json-viewer-element 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +62 -0
- package/README.md +64 -2
- package/dist/json-viewer-element.d.ts +6 -4
- package/dist/json-viewer-element.es.js +14 -6
- package/dist/json-viewer-element.umd.js +1 -1
- package/package.json +2 -2
package/README.en.md
CHANGED
|
@@ -55,6 +55,8 @@ Set value by attribute:
|
|
|
55
55
|
|
|
56
56
|
Use in Vue framework:
|
|
57
57
|
|
|
58
|
+
Vue 2/3 Options API:
|
|
59
|
+
|
|
58
60
|
```vue
|
|
59
61
|
<template>
|
|
60
62
|
<json-viewer :value="JSON.stringify(json)" boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
|
|
@@ -71,6 +73,66 @@ export default {
|
|
|
71
73
|
</script>
|
|
72
74
|
```
|
|
73
75
|
|
|
76
|
+
Vue 3 composition API:
|
|
77
|
+
|
|
78
|
+
```vue
|
|
79
|
+
<script lang="ts" setup>
|
|
80
|
+
import { ref } from 'vue'
|
|
81
|
+
const json = ref({ hello: "world", arr: [1,2,3] })
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<template>
|
|
85
|
+
<json-viewer :value="JSON.stringify(json)" boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
|
|
86
|
+
</template>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
> [!TIP]
|
|
90
|
+
>
|
|
91
|
+
> [Skipping Component Resolution](https://vuejs.org/guide/extras/web-components.html#skipping-component-resolution)
|
|
92
|
+
>
|
|
93
|
+
> To let Vue know that certain elements should be treated as custom elements and skip component resolution, we can specify the [`compilerOptions.isCustomElement` option](https://vuejs.org/api/application.html#app-config-compileroptions).
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
// vite.config.js
|
|
97
|
+
import vue from '@vitejs/plugin-vue'
|
|
98
|
+
import vueJsx from '@vitejs/plugin-vue-jsx'
|
|
99
|
+
|
|
100
|
+
export default {
|
|
101
|
+
plugins: [
|
|
102
|
+
vue({
|
|
103
|
+
template: {
|
|
104
|
+
compilerOptions: {
|
|
105
|
+
// treat all tags with a dash as custom elements
|
|
106
|
+
isCustomElement: tag => tag.includes('-')
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}),
|
|
110
|
+
vueJsx({
|
|
111
|
+
// treat all tags with a dash as custom elements
|
|
112
|
+
isCustomElement: tag => tag.includes('-')
|
|
113
|
+
}),
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
If you're using ESLint with Vue, you may need to configure it to ignore the custom element:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
// eslint.config.js
|
|
122
|
+
export default {
|
|
123
|
+
rules: {
|
|
124
|
+
'vue/component-name-in-template-casing': [
|
|
125
|
+
'warn',
|
|
126
|
+
'PascalCase',
|
|
127
|
+
{
|
|
128
|
+
registeredComponentsOnly: false,
|
|
129
|
+
ignores: ['/^icon-/', 'json-viewer'],
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
74
136
|
## Props
|
|
75
137
|
|
|
76
138
|
> [!TIP]
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
- 🔑 **排序**:支持键排序
|
|
12
12
|
- 🔍 **展开深度**:可控初始展开层级
|
|
13
13
|
- 🧩 **自定义复制按钮**:slot 插槽支持
|
|
14
|
-
- 🧬
|
|
14
|
+
- 🧬 **类型高亮**:多种类型高亮
|
|
15
15
|
- 🛠️ **自定义事件**:支持 copy/toggle 事件监听
|
|
16
16
|
|
|
17
17
|
## 使用方法
|
|
@@ -55,6 +55,8 @@ import 'json-viewer-element'
|
|
|
55
55
|
|
|
56
56
|
在 Vue 框架中使用:
|
|
57
57
|
|
|
58
|
+
Vue 2/3 选项式 API:
|
|
59
|
+
|
|
58
60
|
```vue
|
|
59
61
|
<template>
|
|
60
62
|
<json-viewer :value="JSON.stringify(json)" boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
|
|
@@ -71,10 +73,70 @@ export default {
|
|
|
71
73
|
</script>
|
|
72
74
|
```
|
|
73
75
|
|
|
76
|
+
Vue 3 组合式 API:
|
|
77
|
+
|
|
78
|
+
```vue
|
|
79
|
+
<script lang="ts" setup>
|
|
80
|
+
import { ref } from 'vue'
|
|
81
|
+
const json = ref({ hello: "world", arr: [1,2,3] })
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<template>
|
|
85
|
+
<json-viewer :value="JSON.stringify(json)" boxed copyable sort expand-depth="2" theme="dark"></json-viewer>
|
|
86
|
+
</template>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
> [!TIP]
|
|
90
|
+
>
|
|
91
|
+
> [跳过组件解析](https://cn.vuejs.org/guide/extras/web-components.html#skipping-component-resolution)
|
|
92
|
+
>
|
|
93
|
+
> 为了让 Vue 知道某些元素应被视为自定义元素并跳过组件解析,我们可以指定 [`compilerOptions.isCustomElement` 选项](https://cn.vuejs.org/api/application.html#app-config-compileroptions)。
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
// vite.config.js
|
|
97
|
+
import vue from '@vitejs/plugin-vue'
|
|
98
|
+
import vueJsx from '@vitejs/plugin-vue-jsx'
|
|
99
|
+
|
|
100
|
+
export default {
|
|
101
|
+
plugins: [
|
|
102
|
+
vue({
|
|
103
|
+
template: {
|
|
104
|
+
compilerOptions: {
|
|
105
|
+
// 将所有带短横线的标签名都视为自定义元素
|
|
106
|
+
isCustomElement: tag => tag.includes('-')
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}),
|
|
110
|
+
vueJsx({
|
|
111
|
+
// 将所有带短横线的标签名都视为自定义元素
|
|
112
|
+
isCustomElement: tag => tag.includes('-')
|
|
113
|
+
}),
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
如果你在 Vue 中使用 ESLint,可能需要配置忽略自定义元素:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
// eslint.config.js
|
|
122
|
+
export default {
|
|
123
|
+
rules: {
|
|
124
|
+
'vue/component-name-in-template-casing': [
|
|
125
|
+
'warn',
|
|
126
|
+
'PascalCase',
|
|
127
|
+
{
|
|
128
|
+
registeredComponentsOnly: false,
|
|
129
|
+
ignores: ['/^icon-/', 'json-viewer'],
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
74
136
|
## 属性
|
|
75
137
|
|
|
76
138
|
> [!TIP]
|
|
77
|
-
> 在 Vue 等框架中使用时,value 和 copyable
|
|
139
|
+
> 在 Vue 等框架中使用时,value 和 copyable 属性的值需要转成字符串传入。
|
|
78
140
|
|
|
79
141
|
| 属性 | 类型 | 默认值 | 说明 |
|
|
80
142
|
| :----------- | :----------------------------------------- | :------ | :----------------------------------------- |
|
|
@@ -40,11 +40,13 @@ export declare class JsonViewerElement extends HTMLElement {
|
|
|
40
40
|
attributeChangedCallback(): void;
|
|
41
41
|
set value(v: any);
|
|
42
42
|
get value(): any;
|
|
43
|
+
set sort(v: boolean);
|
|
44
|
+
get sort(): boolean;
|
|
45
|
+
set parse(v: boolean);
|
|
46
|
+
get parse(): boolean;
|
|
47
|
+
set copyable(v: CopyableOptions | false);
|
|
48
|
+
get copyable(): CopyableOptions | false;
|
|
43
49
|
private get expandDepth();
|
|
44
|
-
private get sort();
|
|
45
|
-
private get theme();
|
|
46
|
-
private get parse();
|
|
47
|
-
private get copyable();
|
|
48
50
|
/**
|
|
49
51
|
* Copy text to clipboard. Uses Clipboard API if available, otherwise fallback.
|
|
50
52
|
*/
|
|
@@ -207,7 +207,6 @@ class JsonViewerElement extends HTMLElement {
|
|
|
207
207
|
attributeChangedCallback() {
|
|
208
208
|
this.render();
|
|
209
209
|
}
|
|
210
|
-
// ----- Public property: value -----
|
|
211
210
|
set value(v) {
|
|
212
211
|
if (v === this._value)
|
|
213
212
|
return;
|
|
@@ -217,19 +216,25 @@ class JsonViewerElement extends HTMLElement {
|
|
|
217
216
|
get value() {
|
|
218
217
|
return this._value ?? this.getAttribute("value");
|
|
219
218
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return Number(this.getAttribute("expand-depth") ?? 1);
|
|
219
|
+
set sort(v) {
|
|
220
|
+
this.setAttribute("sort", v ? "true" : "false");
|
|
223
221
|
}
|
|
224
222
|
get sort() {
|
|
225
223
|
return this.hasAttribute("sort");
|
|
226
224
|
}
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
set parse(v) {
|
|
226
|
+
this.setAttribute("parse", v ? "true" : "false");
|
|
229
227
|
}
|
|
230
228
|
get parse() {
|
|
231
229
|
return this.getAttribute("parse") !== "false";
|
|
232
230
|
}
|
|
231
|
+
set copyable(v) {
|
|
232
|
+
if (v === false) {
|
|
233
|
+
this.removeAttribute("copyable");
|
|
234
|
+
} else {
|
|
235
|
+
this.setAttribute("copyable", JSON.stringify(v));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
233
238
|
get copyable() {
|
|
234
239
|
if (!this.hasAttribute("copyable"))
|
|
235
240
|
return false;
|
|
@@ -246,6 +251,9 @@ class JsonViewerElement extends HTMLElement {
|
|
|
246
251
|
return defaultCopyableOptions;
|
|
247
252
|
}
|
|
248
253
|
}
|
|
254
|
+
get expandDepth() {
|
|
255
|
+
return Number(this.getAttribute("expand-depth") ?? 1);
|
|
256
|
+
}
|
|
249
257
|
/**
|
|
250
258
|
* Copy text to clipboard. Uses Clipboard API if available, otherwise fallback.
|
|
251
259
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).JsonViewerElement={})}(this,function(e){"use strict";const t=document.createElement("template");t.innerHTML='\n<style>\n/* Light Theme (default) */\n:host {\n --jv-bg-color: #ffffff;\n --jv-border-color: #ddd;\n --jv-text-color: #111;\n --jv-key-color: #111;\n --jv-string-color: #42b983;\n --jv-number-color: #fc1e70;\n --jv-boolean-color: #fc1e70;\n --jv-null-color: #e08331;\n --jv-undefined-color: #b0b0b0;\n --jv-function-color: #067bca;\n --jv-regexp-color: #fc1e70;\n --jv-copy-bg: #eee;\n --jv-copy-text: #333;\n --jv-ellipsis-color: #999999;\n --jv-ellipsis-bg: #eeeeee;\n --jv-hover-shadow: rgba(0,0,0,0.1);\n}\n\n/* Dark Theme */\n:host([theme="dark"]) {\n --jv-bg-color: #23272f;\n --jv-border-color: #2c313a;\n --jv-text-color: #d4d4d4;\n --jv-key-color: #79c0ff;\n --jv-string-color: #a5d6a7;\n --jv-number-color: #e2b86b;\n --jv-boolean-color: #ff7b72;\n --jv-null-color: #ffab70;\n --jv-undefined-color: #d2a8ff;\n --jv-function-color: #c678dd;\n --jv-regexp-color: #56b6c2;\n --jv-copy-bg: #3a3f4b;\n --jv-copy-text: #fff;\n --jv-ellipsis-color: #6e7681;\n --jv-ellipsis-bg: #2c313a;\n --jv-hover-shadow: rgba(0,0,0,0.4);\n}\n\n:host {\n display: block;\n width: 100%;\n max-width: 100%;\n font-family: Consolas, Menlo, Courier, monospace;\n font-size: 14px;\n padding: 8px;\n overflow-x: auto;\n box-sizing: border-box;\n position: relative;\n background-color: var(--jv-bg-color);\n color: var(--jv-text-color);\n}\n\n:host([boxed]) {\n border: 1px solid var(--jv-border-color);\n border-radius: 4px;\n padding: 16px;\n transition: box-shadow 0.2s ease;\n}\n:host([boxed]:hover) {\n box-shadow: 0 2px 8px var(--jv-hover-shadow);\n}\n#root:has(+.align-left) {\n margin-top: 16px;\n}\n.jv-copy {\n cursor: pointer;\n font-size: 12px;\n background: var(--jv-copy-bg);\n color: var(--jv-copy-text);\n padding: 4px 8px;\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n:host(:hover) .jv-copy {\n opacity: 1;\n}\nslot[name="copy-button"] {\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 10;\n opacity: 0;\n transition: opacity 0.2s ease;\n display: block !important;\n}\nslot[name="copy-button"][hidden] {\n display: none !important;\n}\nslot[name="copy-button"].align-left {\n left: 8px;\n right: auto;\n}\nslot[name="copy-button"].align-right {\n right: 8px;\n left: auto;\n}\n:host(:hover) slot[name="copy-button"] {\n opacity: 1;\n}\n.jv-toggle {\n background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyBoZWlnaHQ9IjE2IiB3aWR0aD0iOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMCAwIDggOC04IDh6IiBmaWxsPSIjNjY2Ii8+PC9zdmc+");\n background-repeat: no-repeat;\n background-size: contain;\n background-position: center center;\n cursor: pointer;\n width: 10px;\n height: 10px;\n margin-right: 2px;\n display: inline-block;\n transition: rotate .1s;\n}\n.jv-toggle.open {\n rotate: 90deg;\n}\n.jv-key {\n color: var(--jv-key-color);\n}\n.jv-string {\n color: var(--jv-string-color);\n}\n.jv-number {\n color: var(--jv-number-color);\n}\n.jv-boolean {\n color: var(--jv-boolean-color);\n}\n.jv-null {\n color: var(--jv-null-color);\n}\n.jv-undefined {\n color: var(--jv-undefined-color);\n}\n.jv-function {\n color: var(--jv-function-color);\n}\n.jv-regexp {\n color: var(--jv-regexp-color);\n}\n.jv-list {\n margin-left: 16px;\n}\n.jv-item:not(:has(.jv-toggle)) .jv-key {\n margin-left: 12px;\n}\n.jv-item:not(:last-child):after {\n content: \',\';\n}\n.jv-node > .jv-ellipsis {\n display: none;\n}\n.jv-node.empty > .jv-list {\n display: inline-block;\n margin-inline: 4px;\n}\n.jv-node.collapsed > .jv-list,\n.jv-node.collapsed.empty > .jv-ellipsis {\n display: none;\n}\n.jv-node.collapsed > .jv-ellipsis {\n color: var(--jv-ellipsis-color);\n background-color: var(--jv-ellipsis-bg);\n display: inline-block;\n line-height: 0.9;\n font-size: 0.85em;\n vertical-align: 2px;\n cursor: pointer;\n user-select: none;\n padding: 2px 4px;\n margin: 0px 4px;\n border-radius: 3px;\n}\n</style>\n<div id="root" part="root"></div>\n<slot name="copy-button" part="copy-button" hidden>\n <span class="jv-copy"></span>\n</slot>\n';class n extends HTMLElement{constructor(){super(),this._value=null,this.root=this.attachShadow({mode:"open"}),this.root.appendChild(t.content.cloneNode(!0)),this.container=this.root.getElementById("root")}static get observedAttributes(){return["value","expand-depth","copyable","sort","boxed","theme","parse"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}set value(e){e!==this._value&&(this._value=e,this.render())}get value(){return this._value??this.getAttribute("value")}
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).JsonViewerElement={})}(this,function(e){"use strict";const t=document.createElement("template");t.innerHTML='\n<style>\n/* Light Theme (default) */\n:host {\n --jv-bg-color: #ffffff;\n --jv-border-color: #ddd;\n --jv-text-color: #111;\n --jv-key-color: #111;\n --jv-string-color: #42b983;\n --jv-number-color: #fc1e70;\n --jv-boolean-color: #fc1e70;\n --jv-null-color: #e08331;\n --jv-undefined-color: #b0b0b0;\n --jv-function-color: #067bca;\n --jv-regexp-color: #fc1e70;\n --jv-copy-bg: #eee;\n --jv-copy-text: #333;\n --jv-ellipsis-color: #999999;\n --jv-ellipsis-bg: #eeeeee;\n --jv-hover-shadow: rgba(0,0,0,0.1);\n}\n\n/* Dark Theme */\n:host([theme="dark"]) {\n --jv-bg-color: #23272f;\n --jv-border-color: #2c313a;\n --jv-text-color: #d4d4d4;\n --jv-key-color: #79c0ff;\n --jv-string-color: #a5d6a7;\n --jv-number-color: #e2b86b;\n --jv-boolean-color: #ff7b72;\n --jv-null-color: #ffab70;\n --jv-undefined-color: #d2a8ff;\n --jv-function-color: #c678dd;\n --jv-regexp-color: #56b6c2;\n --jv-copy-bg: #3a3f4b;\n --jv-copy-text: #fff;\n --jv-ellipsis-color: #6e7681;\n --jv-ellipsis-bg: #2c313a;\n --jv-hover-shadow: rgba(0,0,0,0.4);\n}\n\n:host {\n display: block;\n width: 100%;\n max-width: 100%;\n font-family: Consolas, Menlo, Courier, monospace;\n font-size: 14px;\n padding: 8px;\n overflow-x: auto;\n box-sizing: border-box;\n position: relative;\n background-color: var(--jv-bg-color);\n color: var(--jv-text-color);\n}\n\n:host([boxed]) {\n border: 1px solid var(--jv-border-color);\n border-radius: 4px;\n padding: 16px;\n transition: box-shadow 0.2s ease;\n}\n:host([boxed]:hover) {\n box-shadow: 0 2px 8px var(--jv-hover-shadow);\n}\n#root:has(+.align-left) {\n margin-top: 16px;\n}\n.jv-copy {\n cursor: pointer;\n font-size: 12px;\n background: var(--jv-copy-bg);\n color: var(--jv-copy-text);\n padding: 4px 8px;\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n:host(:hover) .jv-copy {\n opacity: 1;\n}\nslot[name="copy-button"] {\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 10;\n opacity: 0;\n transition: opacity 0.2s ease;\n display: block !important;\n}\nslot[name="copy-button"][hidden] {\n display: none !important;\n}\nslot[name="copy-button"].align-left {\n left: 8px;\n right: auto;\n}\nslot[name="copy-button"].align-right {\n right: 8px;\n left: auto;\n}\n:host(:hover) slot[name="copy-button"] {\n opacity: 1;\n}\n.jv-toggle {\n background-image: url("data:image/svg+xml;charset=utf-8;base64,PHN2ZyBoZWlnaHQ9IjE2IiB3aWR0aD0iOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMCAwIDggOC04IDh6IiBmaWxsPSIjNjY2Ii8+PC9zdmc+");\n background-repeat: no-repeat;\n background-size: contain;\n background-position: center center;\n cursor: pointer;\n width: 10px;\n height: 10px;\n margin-right: 2px;\n display: inline-block;\n transition: rotate .1s;\n}\n.jv-toggle.open {\n rotate: 90deg;\n}\n.jv-key {\n color: var(--jv-key-color);\n}\n.jv-string {\n color: var(--jv-string-color);\n}\n.jv-number {\n color: var(--jv-number-color);\n}\n.jv-boolean {\n color: var(--jv-boolean-color);\n}\n.jv-null {\n color: var(--jv-null-color);\n}\n.jv-undefined {\n color: var(--jv-undefined-color);\n}\n.jv-function {\n color: var(--jv-function-color);\n}\n.jv-regexp {\n color: var(--jv-regexp-color);\n}\n.jv-list {\n margin-left: 16px;\n}\n.jv-item:not(:has(.jv-toggle)) .jv-key {\n margin-left: 12px;\n}\n.jv-item:not(:last-child):after {\n content: \',\';\n}\n.jv-node > .jv-ellipsis {\n display: none;\n}\n.jv-node.empty > .jv-list {\n display: inline-block;\n margin-inline: 4px;\n}\n.jv-node.collapsed > .jv-list,\n.jv-node.collapsed.empty > .jv-ellipsis {\n display: none;\n}\n.jv-node.collapsed > .jv-ellipsis {\n color: var(--jv-ellipsis-color);\n background-color: var(--jv-ellipsis-bg);\n display: inline-block;\n line-height: 0.9;\n font-size: 0.85em;\n vertical-align: 2px;\n cursor: pointer;\n user-select: none;\n padding: 2px 4px;\n margin: 0px 4px;\n border-radius: 3px;\n}\n</style>\n<div id="root" part="root"></div>\n<slot name="copy-button" part="copy-button" hidden>\n <span class="jv-copy"></span>\n</slot>\n';class n extends HTMLElement{constructor(){super(),this._value=null,this.root=this.attachShadow({mode:"open"}),this.root.appendChild(t.content.cloneNode(!0)),this.container=this.root.getElementById("root")}static get observedAttributes(){return["value","expand-depth","copyable","sort","boxed","theme","parse"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}set value(e){e!==this._value&&(this._value=e,this.render())}get value(){return this._value??this.getAttribute("value")}set sort(e){this.setAttribute("sort",e?"true":"false")}get sort(){return this.hasAttribute("sort")}set parse(e){this.setAttribute("parse",e?"true":"false")}get parse(){return"false"!==this.getAttribute("parse")}set copyable(e){!1===e?this.removeAttribute("copyable"):this.setAttribute("copyable",JSON.stringify(e))}get copyable(){if(!this.hasAttribute("copyable"))return!1;const e=this.getAttribute("copyable"),t={copyText:"Copy",copiedText:"Copied",timeout:2e3,align:"right"};if(""===e||null===e)return t;try{return{...t,...JSON.parse(e)}}catch{return t}}get expandDepth(){return Number(this.getAttribute("expand-depth")??1)}copyText(e){return navigator.clipboard?(this.copyText=e=>navigator.clipboard.writeText(e),this.copyText(e)):(this.copyText=e=>new Promise((t,n)=>{const o=document.createElement("input");o.value=e,document.body.appendChild(o),o.select(),document.execCommand("copy")?(document.body.removeChild(o),t()):(document.body.removeChild(o),n(new Error("Copy failed")))}),this.copyText(e))}render(){if("string"==typeof this.value&&this.parse)try{this._value=JSON.parse(this.value)}catch{}this.container.innerHTML="",this.container.appendChild(this.build(this._value,0));const e=this.copyable;if(e){const t=e.align||"right",n=this.root.querySelector('slot[name="copy-button"]'),o=n.assignedElements()[0],r=this.root.querySelector(".jv-copy");if(n.hidden=!1,n.className=`align-${t}`,!o){let t;r.textContent=e.copyText;const n=r.cloneNode(!0);r.replaceWith(n),n.textContent=e.copyText,n.addEventListener("click",()=>{const o=JSON.stringify(this._value,null,2);this.copyText(o).then(()=>{n.textContent=e.copiedText,t=window.setTimeout(()=>{n.textContent=e.copyText,clearTimeout(t)},e.timeout),this.dispatchEvent(new CustomEvent("copy-success",{detail:{text:o,options:e}}))}).catch(()=>{console.warn("Failed to copy text to clipboard"),this.dispatchEvent(new CustomEvent("copy-error",{detail:{text:o,options:e}}))})})}}}build(e,t){if(null===e)return this.leaf("null","jv-null");if(void 0===e)return this.leaf("undefined","jv-undefined");if("boolean"==typeof e)return this.leaf(String(e),"jv-boolean");if("number"==typeof e)return this.leaf(String(e),"jv-number");if("string"==typeof e)return this.leaf(`"${e}"`,"jv-string");if("function"==typeof e)return this.leaf("<function>","jv-function");if(e instanceof RegExp)return this.leaf("<regexp>","jv-regexp");if(e instanceof Date)return this.leaf(`"${e.toLocaleString()}"`,"jv-string");const n=Array.isArray(e),o=document.createElement("span");o.className="jv-node",o.setAttribute("part","node");const r=document.createElement("div");r.className="jv-list",r.setAttribute("part","list");const s=n?this.sort?[...e.keys()].sort((e,t)=>e-t):[...e.keys()]:this.sort?Object.keys(e).sort():Object.keys(e);for(const l of s){const o=document.createElement("div"),s=this.build(e[l],t+1);if(o.className="jv-item",s instanceof Element&&s.classList.contains("jv-node")){const e=s.querySelector(".jv-toggle");e&&(e.remove(),o.append(e))}if(!n){const e=document.createElement("span");e.className="jv-key",e.setAttribute("part","key"),e.textContent=`"${l}": `,o.append(e)}o.append(s),r.append(o)}const i=document.createElement("span");i.className="jv-toggle",i.setAttribute("part","toggle"),o.classList.contains("collapsed")||i.classList.add("open"),i.addEventListener("click",()=>{o.classList.toggle("collapsed"),i.classList.toggle("open"),this.dispatchEvent(new CustomEvent("toggle",{detail:{node:o,data:e,isCollapsed:o.classList.contains("collapsed")}}))});const a=document.createElement("span");return a.className="jv-ellipsis",a.setAttribute("part","ellipsis"),a.textContent=`...${s.length}`,a.addEventListener("click",()=>{o.classList.remove("collapsed"),i.classList.add("open")}),t>=this.expandDepth&&(o.classList.add("collapsed"),i.classList.remove("open")),s.length||o.classList.add("empty"),o.append(i,n?"[":"{",a,r,n?"]":"}"),o}leaf(e,t){const n=document.createElement("span");return n.className=`jv-value ${t}`,n.setAttribute("part",`value ${t.replace("jv-","")}`),n.textContent=e,n}}customElements.define("json-viewer",n),e.JsonViewerElement=n,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-viewer-element",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"packageManager": "pnpm@10.18.2",
|
|
6
6
|
"description": "A custom element for viewing and interacting with JSON data.",
|
|
7
7
|
"author": "Lruihao (https://lruihao.cn)",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"version": "auto-changelog-plus -p && git add CHANGELOG.md"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@antfu/eslint-config": "^
|
|
36
|
+
"@antfu/eslint-config": "^6.2.0",
|
|
37
37
|
"auto-changelog-plus": "^1.2.1",
|
|
38
38
|
"eslint": "^9.36.0",
|
|
39
39
|
"terser": "^5.44.0",
|