Skip to content

Commit 5bc75fd

Browse files
authored
Merge pull request #514 from seijikohara/feat/modernize-tooling-and-docs
Modernize tooling and improve documentation
2 parents 315bbb7 + 34a71ea commit 5bc75fd

File tree

16 files changed

+2287
-1499
lines changed

16 files changed

+2287
-1499
lines changed

.eslintrc.cjs

Lines changed: 0 additions & 15 deletions
This file was deleted.

.github/workflows/npm-ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ jobs:
88
runs-on: ubuntu-latest
99
strategy:
1010
matrix:
11-
node-version: [18.x, 20.x, 22.x, 24.x]
11+
node-version: [20.x, 22.x, 24.x]
1212
steps:
13-
- uses: actions/checkout@v4
13+
- uses: actions/checkout@v5
1414
- name: Use Node.js ${{ matrix.node-version }}
15-
uses: actions/setup-node@v4
15+
uses: actions/setup-node@v5
1616
with:
1717
node-version: ${{ matrix.node-version }}
1818
cache: "npm"

.github/workflows/npm-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ jobs:
1111
publish-npm:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v4
15-
- uses: actions/setup-node@v4
14+
- uses: actions/checkout@v5
15+
- uses: actions/setup-node@v5
1616
with:
1717
node-version: 22
1818
registry-url: https://registry.npmjs.org/

.github/workflows/playwright.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,16 @@ on:
77
jobs:
88
test:
99
timeout-minutes: 60
10-
runs-on: ${{ matrix.os }}
10+
runs-on: ubuntu-latest
1111
strategy:
1212
fail-fast: false
1313
matrix:
14-
os: [ubuntu-latest, windows-latest, macos-latest]
1514
browser: [chromium, firefox, webkit]
1615
steps:
17-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v5
1817

1918
- name: Setup Node.js
20-
uses: actions/setup-node@v4
19+
uses: actions/setup-node@v5
2120
with:
2221
node-version: 20
2322
cache: "npm"
@@ -32,10 +31,10 @@ jobs:
3231
run: npx playwright test --project=${{ matrix.browser }}
3332

3433
- name: Upload test results
35-
uses: actions/upload-artifact@v4
34+
uses: actions/upload-artifact@v5
3635
if: ${{ !cancelled() }}
3736
with:
38-
name: playwright-report-${{ matrix.os }}-${{ matrix.browser }}
37+
name: playwright-report-${{ matrix.browser }}
3938
path: playwright-report/
4039
retention-days: 30
4140

README.md

Lines changed: 103 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,123 @@
11
# json-tree-view-vue3
22

3-
[![npm version](https://badge.fury.io/js/json-tree-view-vue3.svg)](https://www.npmjs.com/package/json-tree-view-vue3) [![TypeScript](https://badges.frapsoft.com/typescript/code/typescript.svg?v=101)](https://github.com/ellerbrock/typescript-badges/) ![npm bundle size](https://img.shields.io/bundlephobia/min/json-tree-view-vue3.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
3+
[![npm version](https://img.shields.io/npm/v/json-tree-view-vue3.svg)](https://www.npmjs.com/package/json-tree-view-vue3)
4+
[![CI](https://img.shields.io/github/actions/workflow/status/seijikohara/json-tree-view-vue3/npm-ci.yml?branch=main&label=CI)](https://github.com/seijikohara/json-tree-view-vue3/actions/workflows/npm-ci.yml)
5+
[![E2E Tests](https://img.shields.io/github/actions/workflow/status/seijikohara/json-tree-view-vue3/playwright.yml?branch=main&label=E2E)](https://github.com/seijikohara/json-tree-view-vue3/actions/workflows/playwright.yml)
6+
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)
7+
[![npm bundle size](https://img.shields.io/bundlephobia/min/json-tree-view-vue3.svg)](https://bundlephobia.com/package/json-tree-view-vue3)
8+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
49

5-
A Vue3 component that displays JSON in a collapsible tree.
6-
Inspired by [vue-json-component](https://www.npmjs.com/package/vue-json-component) and [vue-json-tree-view](https://www.npmjs.com/package/vue-json-tree-view) to work with Vue3 and TypeScript.
10+
A Vue 3 component for rendering JSON data as an interactive, collapsible tree structure.
711

8-
## Example
12+
Inspired by [vue-json-component](https://www.npmjs.com/package/vue-json-component) and [vue-json-tree-view](https://www.npmjs.com/package/vue-json-tree-view), this library provides native Vue 3 and TypeScript support.
13+
14+
## Installation
15+
16+
```bash
17+
npm install json-tree-view-vue3
18+
```
19+
20+
## Usage
921

1022
```vue
1123
<script setup lang="ts">
1224
import { JsonTreeView } from "json-tree-view-vue3";
13-
import 'json-tree-view-vue3/dist/style.css'
25+
import "json-tree-view-vue3/dist/style.css";
1426
15-
const json = `{"string":"text","number":123,"boolean":true,"null":null,"array":["A","B","C"],"object":{"prop1":"value1","nestedObject":{"prop2":"value2"}}}`
27+
const json = `{"string":"text","number":123,"boolean":true,"null":null,"array":["A","B","C"],"object":{"prop1":"value1","nestedObject":{"prop2":"value2"}}}`;
1628
</script>
1729
1830
<template>
1931
<JsonTreeView :json="json" :maxDepth="3" />
2032
</template>
2133
```
2234

23-
<img width="296" alt="image" src="https://github.com/seijikohara/json-tree-view-vue3/assets/9543980/0d4d74bc-367d-4fd1-a47a-edfb857a6478">
35+
### Example Output
36+
37+
<img width="296" alt="JSON tree view example" src="https://github.com/seijikohara/json-tree-view-vue3/assets/9543980/0d4d74bc-367d-4fd1-a47a-edfb857a6478">
38+
39+
## API Reference
40+
41+
### Props
42+
43+
| Property | Type | Required | Default | Description |
44+
|---------------|----------|----------|-----------|------------------------------------------------------------------|
45+
| `json` | `string` | Yes | - | A valid JSON string to be rendered as a tree structure |
46+
| `rootKey` | `string` | No | `"/"` | The label displayed for the root node of the tree |
47+
| `maxDepth` | `number` | No | `1` | The initial depth level to which the tree will be expanded |
48+
| `colorScheme` | `string` | No | `"light"` | Visual theme of the component. Accepts `"light"` or `"dark"` |
49+
50+
### Events
51+
52+
#### `selected`
53+
54+
Emitted when a user selects a value in the tree.
55+
56+
**Payload Type:**
57+
```typescript
58+
{
59+
key: string; // The key of the selected node
60+
value: PrimitiveTypes; // The value of the selected node (string, number, boolean, or null)
61+
path: string; // The full path to the selected node
62+
}
63+
```
64+
65+
## Styling and Customization
66+
67+
The component uses CSS custom properties (variables) for theming, allowing you to customize colors and dimensions to match your application's design system.
68+
69+
### Available CSS Variables
70+
71+
```css
72+
/* Color palette */
73+
--jtv-key-color: oklch(0.55 0.15 240); /* Object/Array key color */
74+
--jtv-valueKey-color: oklch(0.25 0.05 210); /* Primitive value key color */
75+
--jtv-string-color: oklch(0.6 0.12 230); /* String value color */
76+
--jtv-number-color: oklch(0.65 0.1 180); /* Number value color */
77+
--jtv-boolean-color: oklch(0.55 0.15 40); /* Boolean value color */
78+
--jtv-null-color: oklch(0.55 0.12 280); /* Null value color */
79+
80+
/* UI colors */
81+
--jtv-arrow-color: oklch(0.3 0 0); /* Expand/collapse arrow color */
82+
--jtv-hover-color: oklch(0 0 0 / 0.1); /* Hover background color */
83+
84+
/* Dimensions */
85+
--jtv-arrow-size: 6px; /* Size of the expand/collapse arrow */
86+
--jtv-spacing-unit: 4px; /* Base spacing unit */
87+
```
88+
89+
### Custom Styling Example
90+
91+
You can override these variables to customize the appearance:
92+
93+
```vue
94+
<style>
95+
.json-tree-view {
96+
/* Custom color scheme */
97+
--jtv-key-color: #2563eb;
98+
--jtv-valueKey-color: #1e293b;
99+
--jtv-string-color: #059669;
100+
--jtv-number-color: #dc2626;
101+
--jtv-boolean-color: #7c3aed;
102+
--jtv-null-color: #64748b;
103+
104+
/* Custom dimensions */
105+
--jtv-arrow-size: 8px;
106+
--jtv-spacing-unit: 6px;
107+
}
108+
</style>
109+
110+
<template>
111+
<div class="json-tree-view">
112+
<JsonTreeView :json="json" />
113+
</div>
114+
</template>
115+
```
24116

25-
## Props
117+
### Dark Mode
26118

27-
| Props | Required | Param Type | Default value | Description |
28-
|-------------|----------|------------|---------------|-------------------------------------------------------|
29-
| json | true | string | | JSON string to display the tree |
30-
| rootKey | false | string | "/" | Top root-level name |
31-
| maxDepth | false | number | 1 | The depth of the tree that will be open when rendered |
32-
| colorScheme | false | string | "light" | "light" or "dark" can be used. |
119+
The component includes built-in dark mode support through the `colorScheme` prop. Alternatively, you can customize the dark theme by overriding the CSS variables within your own dark mode class.
33120

34-
## Events
121+
## License
35122

36-
- **selected**(event: `{key: string, value: PrimitiveTypes, path: string}`]
123+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

e2e/json-tree-view.spec.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -107,21 +107,18 @@ test.describe('JsonTreeView', () => {
107107
test('should show/hide children on toggle', async ({ page }) => {
108108
const lightTheme = page.locator('.theme-light')
109109
const toggleButton = lightTheme.locator('.data-key').first()
110-
const valueKeys = lightTheme.locator('.value-key')
110+
const firstChild = toggleButton.locator('..').locator('.json-view-item').first()
111111

112112
// Initial state - children visible
113-
const initialCount = await valueKeys.count()
114-
expect.soft(initialCount).toBeGreaterThan(0)
113+
await expect.soft(firstChild).toBeVisible()
115114

116115
// Click to collapse
117116
await toggleButton.click()
118-
const collapsedCount = await valueKeys.count()
119-
expect.soft(collapsedCount).toBeLessThan(initialCount)
117+
await expect.soft(firstChild).toBeHidden()
120118

121119
// Click to expand
122120
await toggleButton.click()
123-
const expandedCount = await valueKeys.count()
124-
expect.soft(expandedCount).toBe(initialCount)
121+
await expect.soft(firstChild).toBeVisible()
125122
})
126123
})
127124

@@ -131,8 +128,8 @@ test.describe('JsonTreeView', () => {
131128
const stringValue = lightTheme.getByText('"text"')
132129

133130
await expect.soft(stringValue).toBeVisible()
134-
// String values should have specific color
135-
await expect.soft(stringValue).toHaveCSS('color', /rgb\(\d+, \d+, \d+\)/)
131+
// String values should have specific color (rgb or oklch format)
132+
await expect.soft(stringValue).toHaveCSS('color', /(rgb\(\d+, \d+, \d+\)|oklch\([^)]+\))/)
136133
})
137134

138135
test('should render number values', async ({ page }) => {
@@ -193,7 +190,7 @@ test.describe('JsonTreeView', () => {
193190
const lightTheme = page.locator('.theme-light')
194191
const items = lightTheme.locator('.json-view-item:not(.root-item)')
195192

196-
if (await items.count() > 0) {
193+
if ((await items.count()) > 0) {
197194
await expect(items.first()).toHaveCSS('margin-left', '15px')
198195
}
199196
})
@@ -220,12 +217,8 @@ test.describe('JsonTreeView', () => {
220217
await expect.soft(lightTheme).toBeVisible()
221218
await expect.soft(darkTheme).toBeVisible()
222219

223-
const lightBg = await lightTheme.evaluate((el) =>
224-
window.getComputedStyle(el).backgroundColor
225-
)
226-
const darkBg = await darkTheme.evaluate((el) =>
227-
window.getComputedStyle(el).backgroundColor
228-
)
220+
const lightBg = await lightTheme.evaluate((el) => window.getComputedStyle(el).backgroundColor)
221+
const darkBg = await darkTheme.evaluate((el) => window.getComputedStyle(el).backgroundColor)
229222

230223
expect.soft(lightBg).not.toBe(darkBg)
231224
})

eslint.config.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pluginVue from 'eslint-plugin-vue'
2+
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
3+
import pluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
4+
5+
export default defineConfigWithVueTs(
6+
{
7+
name: 'app/files-to-ignore',
8+
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**']
9+
},
10+
11+
pluginVue.configs['flat/essential'],
12+
vueTsConfigs.recommended,
13+
14+
pluginPrettierRecommended,
15+
16+
{
17+
name: 'app/custom-rules',
18+
rules: {
19+
'vue/multi-word-component-names': 'warn',
20+
'@typescript-eslint/no-unused-vars': [
21+
'warn',
22+
{
23+
argsIgnorePattern: '^_',
24+
varsIgnorePattern: '^_'
25+
}
26+
]
27+
}
28+
}
29+
)

0 commit comments

Comments
 (0)