├── .env ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── docs ├── assets │ ├── feather-sprite-BfIm3Xr9.svg │ ├── index-BDoPEOr-.js │ └── index-DbaNkN54.css ├── favicon.ico ├── images │ ├── feather-sprite.svg │ ├── json-editor-app-icon.png │ ├── json-editor-app-icon.webp │ ├── json-editor-banner.webp │ └── json-editor-icon.png └── index.html ├── lib ├── json-editor.css ├── json-editor.d.ts ├── json-editor.js └── json-editor.umd.cjs ├── package.json ├── src ├── dev │ ├── assets │ │ ├── global.scss │ │ └── resource.js │ ├── index.html │ ├── main.js │ ├── main.scss │ └── util.js ├── docs │ ├── app.scss │ ├── app.svelte │ ├── assets │ │ └── scss │ │ │ ├── main.scss │ │ │ ├── mixins.scss │ │ │ └── normalize.scss │ ├── components │ │ ├── about │ │ │ ├── index.scss │ │ │ └── index.svelte │ │ ├── assets │ │ │ ├── button.scss │ │ │ ├── button.svelte │ │ │ ├── icon.svelte │ │ │ ├── logo-label.svelte │ │ │ └── logo-symbol.svelte │ │ ├── data │ │ │ ├── common.scss │ │ │ ├── export.svelte │ │ │ ├── import.svelte │ │ │ └── index.js │ │ ├── editor │ │ │ ├── index.scss │ │ │ └── index.svelte │ │ ├── header │ │ │ ├── index.scss │ │ │ ├── index.svelte │ │ │ ├── menu-item.svelte │ │ │ ├── sub-menu.scss │ │ │ ├── sub-menu.svelte │ │ │ ├── theme.scss │ │ │ └── theme.svelte │ │ ├── modal-window │ │ │ ├── index.scss │ │ │ └── index.svelte │ │ └── preview │ │ │ ├── index.scss │ │ │ └── index.svelte │ ├── index.html │ ├── libs │ │ ├── lang.js │ │ ├── storage.js │ │ └── util.js │ ├── main.js │ ├── public │ │ ├── favicon.ico │ │ └── images │ │ │ ├── feather-sprite.svg │ │ │ ├── json-editor-app-icon.png │ │ │ ├── json-editor-app-icon.webp │ │ │ ├── json-editor-banner.webp │ │ │ └── json-editor-icon.png │ └── store │ │ ├── service.js │ │ └── visible.js └── json-editor │ ├── assets │ ├── context.scss │ ├── icons.js │ ├── main.scss │ ├── mixins.scss │ └── node.scss │ ├── context.js │ ├── exports.js │ ├── index.d.ts │ ├── index.js │ └── libs │ ├── assets.js │ ├── lang.js │ └── util.js └── vite.config ├── dev.js ├── docs.js └── lib.js /.env: -------------------------------------------------------------------------------- 1 | # server 2 | VITE_HOST="0.0.0.0" 3 | VITE_PORT="4000" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # directories 2 | .idea/ 3 | .vscode/ 4 | node_modules/ 5 | dist/ 6 | 7 | # files 8 | .DS_Store 9 | yarn.lock 10 | package-lock.json 11 | bun.lockb 12 | .env.local 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # directories 2 | .idea/ 3 | .vscode/ 4 | node_modules/ 5 | dist/ 6 | 7 | # files 8 | .DS_Store 9 | yarn.lock 10 | package-lock.json 11 | bun.lockb 12 | .env 13 | .env.local 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 redgoose 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSON Editor 2 | 3 | "json-editor"는 웹브라우저에서 json 데이터를 편집하는 에디터입니다. 4 | 텍스트 편집툴을 사용할 수 없거나 json 데이터를 손쉽게 다루기 위하여 만들어진 프로그램 입니다. 5 | 이 에디터는 독립적으로 동작하며 메서드를 실행하여 에디터의 기능을 조작할 수 있습니다. 6 | 7 | 권장되는 사용환경은 다음과 같습니다. 8 | 9 | - 데스크탑 10 | - 큰 화면의 태블릿 11 | 12 | 에디터가 어떻게 사용되는지 데모를 확인해볼 수 있습니다. 데모페이지에서 임시로 에디터로 사용할 수 있습니다. 13 | 14 | > 데모링크: https://redgoose-dev.github.io/json-editor/ 15 | 16 | 17 | ## Using 18 | 19 | javascript와 css를 불러와서 클래스 인스턴스를 만드는 방식으로 시작합니다. 20 | 21 | ```javascript 22 | import JsonEditor from '@redgoose/json-editor' 23 | import '@redgoose/json-editor/css' 24 | 25 | const jsonEditor = new JsonEditor(document.getElementById('target'), { 26 | live: true, 27 | theme: 'system', 28 | edit: 'all', 29 | node: {}, 30 | openDepth: 2, 31 | }) 32 | ``` 33 | 34 | 35 | ## Options 36 | 37 | 컴포넌트를 사용할때에 사용하는 옵션값입니다. 38 | 39 | - `live` / (true,false) 40 | 이 값을 사용하면 데이터가 업데이트 될때마다 `update` 메서드가 호출되면서 업데이트 이벤트를 호출합니다. 41 | - `theme` / (system,light,dark) 42 | 다크모드를 사용하는지에 대한 값입니다. 43 | - `edit` / (all,value,none) 44 | 컨트롤할 수 있는 범위를 정합니다. 45 | - `node` / ({},[]) 46 | 클래스를 초기화할때 사용하는 노드 데이터 값입니다. 47 | - `openDepth` / 0 48 | x번째 뎁스의 노드가 열리는지에 대하여 정합니다. 49 | 50 | 51 | ## Methods 52 | 53 | 인스턴스에서 사용할 수 있는 메서드들이며 필요할때에 적절히 사용할 수 있습니다. (아니면 클래스 프로토타입으로 미리 확장해둘 수 있습니다.) 54 | 사용할 수 있는 공개 메서드들은 다음과 같습니다. 55 | 56 | > ps. 먼저 소스코드는 다음과 같이 정의합니다. 57 | > 58 | > ```javascript 59 | > const jsonEditor = new JsonEditor() 60 | > const node = document.querySelector('.node') // node 61 | > ``` 62 | 63 | ### addNode 64 | 65 | `object`, `array` 노드에서 자식 노드를 추가합니다. 66 | 67 | ```javascript 68 | jsonEditor.addNode(node, data, options, useUpdate, useUpdateCount) 69 | ``` 70 | 71 | - `node`: 데이터를 추가할 노드 엘리먼트 72 | - `data`: 추가할 데이터 73 | - `options`: 추가옵션 74 | - `useUpdate`: 노드를 추가하고 업데이트 메서드를 실행합니다. 75 | - `useUpdateCount`: 부모노드 데이터 갯수를 업데이트합니다. 76 | 77 | 다음과 같이 사용할 수 있습니다. 78 | 79 | ```javascript 80 | jsonEditor.addNode( 81 | node, 82 | { key: '', type: 'string', value: 'metal' }, 83 | options, 84 | true, 85 | true 86 | ) 87 | ``` 88 | 89 | ### removeNode 90 | 91 | 노드를 삭제합니다. 92 | 93 | ```javascript 94 | jsonEditor.removeNode(node, useUpdate) 95 | ``` 96 | 97 | - `node`: 데이터를 추가할 노드 엘리먼트 98 | - `useUpdate`: 노드를 삭제하고 업데이트 메서드를 실행합니다. 99 | 100 | 다음과 같이 사용할 수 있습니다. 101 | 102 | ```javascript 103 | jsonEditor.removeNode(node, true) 104 | ``` 105 | 106 | ### changeType 107 | 108 | 노드의 타입을 변경합니다. 109 | 110 | ```javascript 111 | jsonEditor.changeType(node, type, useUpdate) 112 | ``` 113 | 114 | - `node`: 타입을 변경할 노드 엘리먼트 115 | - `type`: 타입의 이름 (object,array,string,number,boolean,null) 116 | - `useUpdate`: 노드 타입을 변경하고 업데이트 메서드를 실행합니다. 117 | 118 | 다음과 같이 사용할 수 있습니다. 119 | 120 | ```javascript 121 | jsonEditor.changeType(node, 'boolean', true) 122 | ``` 123 | 124 | ### changeKey 125 | 126 | 노드의 `key`를 변경합니다. 127 | 128 | ```javascript 129 | jsonEditor.changeKey(node, keyword) 130 | ``` 131 | 132 | - `node`: 타입을 변경할 노드 엘리먼트 133 | - `keyword`: 키워드 134 | 135 | ### changeValue 136 | 137 | 노드의 `value`를 변경합니다. 138 | 139 | ```javascript 140 | jsonEditor.changeValue(node, value) 141 | ``` 142 | 143 | - `node`: 타입을 변경할 노드 엘리먼트 144 | - `value`: 값 145 | 146 | ### duplicate 147 | 148 | 노드를 복제합니다. 149 | 150 | ```javascript 151 | jsonEditor.duplicate(node, useUpdate) 152 | ``` 153 | 154 | - `node`: 복제할 노드 엘리먼트 155 | - `useUpdate`: 실행하고 업데이트 메서드를 실행합니다. 156 | 157 | 다음과 같이 사용할 수 있습니다. 158 | 159 | ```javascript 160 | jsonEditor.duplicate(node, true) 161 | ``` 162 | 163 | ### fold 164 | 165 | 노드를 접거나 펼칩니다. 166 | 167 | ```javascript 168 | jsonEditor.fold(node, true) 169 | ``` 170 | 171 | ### import 172 | 173 | 데이터를 가져옵니다. 174 | 175 | ```javascript 176 | jsonEditor.import(node, data, useUpdate, useUpdateCount) 177 | ``` 178 | 179 | - `node`: 데이터를 추가할 노드 엘리먼트 180 | - `data`: 가져올 데이터 181 | - `useUpdate`: 노드를 추가하고 업데이트 메서드를 실행합니다. 182 | - `useUpdateCount`: 부모노드 데이터 갯수를 업데이트합니다. 183 | 184 | 다음과 같이 사용할 수 있습니다. 185 | 186 | ```javascript 187 | jsonEditor.import(node, { foo: 'bar' }, true, true) 188 | ``` 189 | 190 | ### replace 191 | 192 | 데이터를 모두 교체합니다. 193 | 194 | ```javascript 195 | jsonEditor.replace(data, options, useUpdate) 196 | ``` 197 | 198 | - `data`: 새로 교체할 데이터 199 | - `options`: 옵션 200 | - `openDepth`: 데이터가 교체될때 노드가 열리는 x번째 뎁스 201 | - `useUpdate`: 노드를 수정하고 업데이트 메서드를 실행합니다. 202 | 203 | 다음과 같이 사용할 수 있습니다. 204 | 205 | ```javascript 206 | jsonEditor.replace({ foo: 'bar' }, { 207 | openDepth: 2, 208 | }, true) 209 | ``` 210 | 211 | ### export 212 | 213 | 에디터의 데이터를 가져옵니다. 214 | 215 | ```javascript 216 | jsonEditor.export(node, json, space) 217 | ``` 218 | 219 | - `node`: 가져올 데이터의 노드 엘리먼트 220 | - `json`: json 형식의 데이터 변환여부 221 | - `space`: json 공백 222 | 223 | 다음과 같이 사용할 수 있습니다. 224 | 225 | ```javascript 226 | const space = 2 // null,2,'\t' 227 | jsonEditor.export(node, true, space) 228 | ``` 229 | 230 | ### clear 231 | 232 | 노드의 내용을 비웁니다. 233 | 234 | ```javascript 235 | jsonEditor.clear() 236 | ``` 237 | 238 | ### destroy 239 | 240 | 만들어진 인스턴스를 파괴합니다. 241 | 242 | ```javascript 243 | jsonEditor.destroy() 244 | ``` 245 | 246 | 247 | ## Events 248 | 249 | 에디터에서 일어난 일들을 외부에서 이벤트리스너로 받아올 수 있습니다. 250 | 251 | > ps. 먼저 소스코드는 다음과 같이 정의합니다. 252 | > 253 | > ```javascript 254 | > const jsonEditor = new JsonEditor() 255 | > const wrap = jsonEditor.el.wrap.get(0) // wrap element 256 | > ``` 257 | 258 | ### update 259 | 260 | 에디터의 내용이 수정된다면 실행되는 이벤트입니다. 261 | 262 | ```javascript 263 | wrap.addEventListener('update', ({ detail }) => { 264 | console.log('updated data', src) 265 | }) 266 | ``` 267 | 268 | - `detail`: 데이터 객체 269 | 270 | ### context 271 | 272 | 컨텍스트 메뉴가 열릴때마다 실행되는 이벤트입니다. 273 | 메뉴를 커스터마이즈 할 수 있으며 제공된 파라메터 값을 이용하여 상황에 맞게 메뉴를 조작할 수 있습니다. 274 | 275 | ```javascript 276 | wrap.addEventListener('context', ({ detail: { body, node, type, isRoot, $ } }) => { 277 | if (!isRoot) return 278 | const $ul = $(body).children() 279 | const $items = $(` 280 |
  • 281 |
  • 282 | `) 283 | $items.find('button').on('click', (e) => { 284 | console.log('click item-key:', $(e.currentTarget).data('key')) 285 | jsonEditor.context.close() 286 | }) 287 | $ul.append($items) 288 | }) 289 | ``` 290 | 291 | - `body`: 열린 컨텍스트 메뉴 영역. 이 엘리먼트에다 항목을 조작하면 됩니다. 292 | - `node`: 선택된 노드 엘리먼트 293 | - `type`: 선택된 노드의 타입 294 | - `isRoot`: 현재 선택된 노드가 루트인지 구분하는 값 295 | - `$`: 컴포넌트 내부에서 사용하는 [Cash](https://github.com/fabiospampinato/cash)를 이용하여 손쉽게 dom을 다룰 수 있습니다. 296 | 297 | 298 | ## Exports guide 299 | 300 | 다음 경로를 참고하여 모듈들을 import 기능을 이용하는데 참고할 수 있습니다. 301 | 302 | - `@redgoose/json-editor`: 코어 라이브러리 303 | - `@redgoose/json-editor/css`: 스타일시트 304 | - `@redgoose/json-editor/lib/umd`: 코어 라이브러리 UMD 305 | 306 | 307 | ## Custom style 308 | 309 | 에디터의 디자인을 수정할 수 있는 요소들을 변수화 시켰습니다. 310 | 다음과 같이 외부 영역에서 에디터 스타일을 커스터마이즈 할 수 있습니다. 311 | 312 | ```css 313 | .editor { 314 | --json-editor-color-base: red; 315 | --json-editor-color-focus: blue; 316 | } 317 | @media (prefers-color-scheme: dark) { 318 | .editor { 319 | --json-editor-color-base: green; 320 | --json-editor-color-focus: yellow; 321 | } 322 | } 323 | ``` 324 | 325 | [main.scss](https://github.com/redgoose-dev/json-editor/blob/main/src/json-editor/assets/main.scss) 파일의 코드를 참고하여 직접 스타일을 편집할 수 있습니다. 326 | 327 | 328 | ## Extention language 329 | 330 | 클래스 메서드를 교체하여 에디터 텍스트를 변경할 수 있습니다. 331 | 332 | ```javascript 333 | JsonEditor.prototype.updateLanguage = function() 334 | { 335 | this.lang = Object.assign(this.lang, { 336 | nodeChangeSort: '노드 순서변경', 337 | nodeContextMenu: '노드메뉴', 338 | nodeFold: '접기/펼치기', 339 | contextChangeType: '타입변경', 340 | contextInsertNode: '노드추가', 341 | contextTypeObject: '객체', 342 | contextTypeArray: '배열', 343 | contextTypeString: '문자', 344 | contextTypeNumber: '번호', 345 | contextTypeBoolean: '부울', 346 | contextTypeNull: '널', 347 | contextDuplicate: '노드복제', 348 | contextRemove: '노드삭제', 349 | }) 350 | } 351 | ``` 352 | 353 | 354 | ## Developing a wrapper 355 | 356 | `JSON Editor` 에디터를 `web component`, `react`, `vue`, `svelte` 같은 환경에서 사용할 수 있도록 컴포넌트를 래핑할 수 있습니다. 357 | 다음 링크를 참고하여 개발할 수 있습니다. 358 | 359 | - [web component](https://github.com/redgoose-dev/json-editor/wiki/json%E2%80%90editor-for-web-component) 360 | - [react](https://github.com/redgoose-dev/json-editor/wiki/json%E2%80%90editor-for-react) 361 | - [vue](https://github.com/redgoose-dev/json-editor/wiki/json%E2%80%90editor-for-vue) 362 | - [svelte](https://github.com/redgoose-dev/json-editor/wiki/json%E2%80%90editor-for-svelte) 363 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redgoose-dev/json-editor/ddf64587751ccadc5b789aca9298edefc0ab3735/docs/favicon.ico -------------------------------------------------------------------------------- /docs/images/json-editor-app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redgoose-dev/json-editor/ddf64587751ccadc5b789aca9298edefc0ab3735/docs/images/json-editor-app-icon.png -------------------------------------------------------------------------------- /docs/images/json-editor-app-icon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redgoose-dev/json-editor/ddf64587751ccadc5b789aca9298edefc0ab3735/docs/images/json-editor-app-icon.webp -------------------------------------------------------------------------------- /docs/images/json-editor-banner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redgoose-dev/json-editor/ddf64587751ccadc5b789aca9298edefc0ab3735/docs/images/json-editor-banner.webp -------------------------------------------------------------------------------- /docs/images/json-editor-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redgoose-dev/json-editor/ddf64587751ccadc5b789aca9298edefc0ab3735/docs/images/json-editor-icon.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JSON Editor 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
    25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/json-editor.css: -------------------------------------------------------------------------------- 1 | .json-editor{--font-base: var(--json-editor-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol");--font-code: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;--color-base: var(--json-editor-color-base, hsl(0 0% 13%));--color-input-empty: var(--json-editor-color-input-empty, hsl(0 0% 78%));--color-input-hover: var(--json-editor-color-input-active, hsla(0 0% 0% / 6%));--color-focus: var(--json-editor-color-focus, hsl(10, 95%, 54%));--color-count: var(--json-editor-color-count, hsl(0 0% 67%));--color-bullet: var(--json-editor-color-bullet, hsl(0 0% 13%));--color-tree: var(--json-editor-color-tree, hsl(0 0% 67%));--color-null: var(--json-editor-color-null, hsl(0 0% 72%));--object: var(--json-editor-object, hsl(168 73% 43%));--array: var(--json-editor-array, hsl(191 75% 53%));--string: var(--json-editor-string, hsl(5 87% 59%));--number: var(--json-editor-number, hsl(33 89% 55%));--boolean: var(--json-editor-boolean, hsl(45 89% 54%));--null: var(--json-editor-null, hsl(0 0% 58%));--color-drag-target-bg: var(--json-editor-color-drag-target-bg, hsla(0 0% 0% / 6%));--color-drag-line: var(--json-editor-color-drag-line, hsl(0 0% 65%));--switch-bg: var(--json-editor-switch-bg, hsla(0 0% 100% / 0%));--switch-outline: var(--json-editor-switch-outline, hsl(0 0% 67%));--switch-outline-active: var(--json-editor-switch-outline-active, hsla(0 0% 67% / 50%));--switch-ball: var(--json-editor-switch-ball, hsl(0 0% 56%));--switch-ball-active: var(--json-editor-switch-ball-active, hsl(0 0% 13%));--context-color-bg: var(--json-editor-context-color-bg, hsl(0 0% 100%));--context-color-inner: var(--json-editor-context-color-inner, hsl(0 0% 88%));--context-color-active: var(--json-editor-context-color-active, hsl(0 0% 92%));--context-color-remove: var(--json-editor-context-color-remove, hsl(0 96% 52%));--context-color-text: var(--json-editor-context-color-text, hsl(0 0% 13%));--context-color-bullet: var(--json-editor-context-color-bullet, hsl(0 0% 13%));--context-shadow: var(--json-editor-context-shadow, 0 4px 36px 0 hsla(0 0% 0% / 12%), 0 2px 12px 0 hsla(0 0% 0% / 20%), 0 0 0 1px hsla(0 0% 0% / 8%));--context-radius: var(--json-editor-radius, 2px);color:var(--color-base);font-size:16px;line-height:1.15}.json-editor,.json-editor button,.json-editor input,.json-editor select{font-family:var(--font-base)}.json-editor>ul{position:relative;margin:-4px 0;padding:0;list-style:none}.json-editor.dragging{cursor:move;-webkit-user-select:none;user-select:none}.json-editor.dragging *{cursor:move!important;-webkit-user-select:none!important;user-select:none!important}.json-editor[data-theme=dark]{--color-base: var(--json-editor-color-base, hsl(0 0% 92%));--color-input-empty: var(--json-editor-color-input-empty, hsl(0 0% 48%));--color-input-hover: var(--json-editor-color-input-active, hsla(0 0% 100% / 12%));--color-count: var(--json-editor-color-count, hsl(0 0% 56%));--color-bullet: var(--json-editor-color-bullet, hsl(0 0% 92%));--color-tree: var(--json-editor-color-tree, hsl(0 0% 42%));--color-null: var(--json-editor-color-null, hsl(0 0% 48%));--color-drag-target-bg: var(--json-editor-color-drag-target-bg, hsla(0 0% 100% / 8%));--color-drag-line: var(--json-editor-color-drag-line, hsl(0 0% 75%));--switch-bg: var(--json-editor-switch-bg, hsla(0 0% 0% / 0%));--switch-outline: var(--json-editor-switch-outline, hsl(0 0% 78%));--switch-outline-active: var(--json-editor-switch-outline-active, hsla(0 0% 62% / 50%));--switch-ball: var(--json-editor-switch-ball, hsl(0 0% 54%));--switch-ball-active: var(--json-editor-switch-ball-active, hsl(0 0% 100%));--context-color-bg: var(--json-editor-context-color-bg, hsl(0 0% 24%));--context-color-inner: var(--json-editor-context-color-inner, hsl(0 0% 16%));--context-color-active: var(--json-editor-context-color-active, hsl(0 0% 36%));--context-color-remove: var(--json-editor-context-color-remove, hsl(0 98% 60%));--context-color-text: var(--json-editor-context-color-text, hsl(0 0% 92%));--context-color-bullet: var(--json-editor-context-color-bullet, hsl(0 0% 92%));--context-shadow: var(--json-editor-context-shadow, 0 4px 36px 0 hsla(0 0% 0% / 32%), 0 2px 8px 0 hsla(0 0% 0% / 52%), 0 0 0 1px hsla(0 0% 0% / 75%))}@media (prefers-color-scheme: dark){.json-editor[data-theme=system],.json-editor:not([data-theme]),.json-editor[data-theme=""]{--color-base: var(--json-editor-color-base, hsl(0 0% 92%));--color-input-empty: var(--json-editor-color-input-empty, hsl(0 0% 48%));--color-input-hover: var(--json-editor-color-input-active, hsla(0 0% 100% / 12%));--color-count: var(--json-editor-color-count, hsl(0 0% 56%));--color-bullet: var(--json-editor-color-bullet, hsl(0 0% 92%));--color-tree: var(--json-editor-color-tree, hsl(0 0% 42%));--color-null: var(--json-editor-color-null, hsl(0 0% 48%));--color-drag-target-bg: var(--json-editor-color-drag-target-bg, hsla(0 0% 100% / 8%));--color-drag-line: var(--json-editor-color-drag-line, hsl(0 0% 75%));--switch-bg: var(--json-editor-switch-bg, hsla(0 0% 0% / 0%));--switch-outline: var(--json-editor-switch-outline, hsl(0 0% 78%));--switch-outline-active: var(--json-editor-switch-outline-active, hsla(0 0% 62% / 50%));--switch-ball: var(--json-editor-switch-ball, hsl(0 0% 54%));--switch-ball-active: var(--json-editor-switch-ball-active, hsl(0 0% 100%));--context-color-bg: var(--json-editor-context-color-bg, hsl(0 0% 24%));--context-color-inner: var(--json-editor-context-color-inner, hsl(0 0% 16%));--context-color-active: var(--json-editor-context-color-active, hsl(0 0% 36%));--context-color-remove: var(--json-editor-context-color-remove, hsl(0 98% 60%));--context-color-text: var(--json-editor-context-color-text, hsl(0 0% 92%));--context-color-bullet: var(--json-editor-context-color-bullet, hsl(0 0% 92%));--context-shadow: var(--json-editor-context-shadow, 0 4px 36px 0 hsla(0 0% 0% / 32%), 0 2px 8px 0 hsla(0 0% 0% / 52%), 0 0 0 1px hsla(0 0% 0% / 75%))}}.json-editor .type-icon{display:grid;width:var(--type-size, 24px);height:var(--type-size, 24px);place-content:center;box-sizing:border-box;border-radius:4px;background:var(--type-icon-color, #aaa)}.json-editor .type-icon svg{display:block;box-sizing:border-box;color:#fff;width:var(--type-icon-width)}.json-editor .type-icon--object{--type-icon-color: var(--object);--type-icon-width: calc(var(--type-icon-size, 10px) + 1px)}.json-editor .type-icon--array{--type-icon-color: var(--array);--type-icon-width: var(--type-icon-size, 10px)}.json-editor .type-icon--string{--type-icon-color: var(--string);--type-icon-width: calc(var(--type-icon-size, 10px) - 2px)}.json-editor .type-icon--number{--type-icon-color: var(--number);--type-icon-width: calc(var(--type-icon-size, 10px) - 1px)}.json-editor .type-icon--boolean{--type-icon-color: var(--boolean);--type-icon-width: calc(var(--type-icon-size, 10px) - 3px)}.json-editor .type-icon--null{--type-icon-color: var(--null);--type-icon-width: calc(var(--type-icon-size, 10px) - 2px)}.json-editor .label-field{margin:-4px 0;padding:4px 6px;min-width:var(--label-min-width, unset);min-height:24px;outline:none;font-size:13px;color:var(--color-base);line-height:1.42;box-sizing:border-box;border-radius:2px;background-color:#0000;box-shadow:0 0 0 .5px #0000;transition:background-color .16s ease-out,box-shadow .2s ease-out;cursor:text;word-break:break-all}@media (hover: hover) and (pointer: fine){.json-editor .label-field:hover{background-color:var(--color-input-hover)}}.json-editor .label-field:focus{outline:2px solid var(--color-focus);outline-offset:-1px}.json-editor .label-field:empty:before{content:attr(data-placeholder);color:var(--color-input-empty)}.json-editor .label-field[type=number]{border:none;width:160px}.json-editor .label-field[type=number]::-webkit-outer-spin-button,.json-editor .label-field[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;-moz-appearance:none;appearance:none}.json-editor .label-null{display:block;padding:0 6px;color:var(--color-null);font-style:normal;letter-spacing:-.5px;-webkit-user-select:none;user-select:none;font-size:13px}.json-editor .label-switch{--switch-width: 36px;--switch-height: 18px;--switch-offset: 3px;--switch-speed: .1s;--switch-unit-size: calc(var(--switch-height) - (var(--switch-offset) * 2));display:block;margin:0 0 0 6px;padding:2px 0;background:none;border:none;font-size:0;cursor:pointer;-webkit-tap-highlight-color:transparent}.json-editor .label-switch span{display:block;position:relative;padding:var(--switch-offset);width:var(--switch-width);height:var(--switch-height);border-radius:calc(var(--switch-height) * .5);box-shadow:inset 0 0 0 1px var(--switch-outline);background-color:var(--switch-bg);transition:box-shadow .16s ease-out;box-sizing:border-box}.json-editor .label-switch i{display:block;width:var(--switch-unit-size);height:var(--switch-unit-size);background-color:var(--switch-unit-color, var(--switch-ball));border-radius:var(--switch-unit-size);pointer-events:none;transform:translate(var(--switch-unit-x));transition:transform var(--switch-speed) ease-out,width var(--switch-speed) ease-out,background-color .24s ease-out}.json-editor .label-switch:active span{box-shadow:inset 0 0 0 1px var(--switch-outline-active)}.json-editor .label-switch:active[data-value=false] i{width:calc(var(--switch-unit-size) + 6px)}.json-editor .label-switch:active[data-value=true] i{width:calc(var(--switch-unit-size) + 6px);transform:translate(calc(var(--switch-width) - var(--switch-offset) * 2 - var(--switch-unit-size) - 6px))}.json-editor .label-switch:focus-visible{outline:none}.json-editor .label-switch:focus-visible span{outline:2px solid var(--color-focus);outline-offset:1px}.json-editor .label-switch[data-value=false]{--switch-unit-x: 0}.json-editor .label-switch[data-value=true]{--switch-unit-x: calc(var(--switch-width) - (var(--switch-offset) * 2) - var(--switch-unit-size));--switch-unit-color: var(--switch-ball-active)}.json-editor .node{position:relative}@supports (-webkit-touch-callout: none){.json-editor .node{-webkit-user-select:none}}.json-editor .node__body{position:relative;display:flex;align-items:center;box-sizing:border-box;padding:4px 0;transition:opacity .12s ease-out}.json-editor .node__body>.sort{display:block;box-sizing:border-box;cursor:move;margin:-4px 4px -4px 0;padding:4px 0;touch-action:none}.json-editor .node__body>.sort svg{display:block;width:24px;color:var(--color-bullet)}.json-editor .node__body>.sort:active{opacity:.5}.json-editor .node__body>.type{position:relative}.json-editor .node__body>.type>button{display:block;margin:-2px;padding:2px;box-sizing:border-box;border:none;background:none;outline:none;cursor:pointer;transition:opacity .12s ease-out;border-radius:6px;-webkit-tap-highlight-color:transparent}.json-editor .node__body>.type>button:active{opacity:.5}.json-editor .node__body>.type>button:focus-visible{outline:2px solid var(--color-focus);outline-offset:-1px}.json-editor .node__body>.type.open>button{opacity:.5}.json-editor .node__body>.fold{display:block;width:28px;height:28px;margin:-8px -8px -8px 0;padding:0;background:none;border:none;box-sizing:border-box;cursor:pointer;-webkit-tap-highlight-color:transparent}.json-editor .node__body>.fold:focus-visible{outline:2px solid var(--color-focus);outline-offset:-6px}.json-editor .node__body>.fold:active{opacity:.5}.json-editor .node__body>.fold svg{display:block;margin:0 auto;width:20px;rotate:0deg;box-sizing:border-box;transition:rotate,.16s ease-out;color:var(--color-bullet)}.json-editor .node__body>.key{margin-left:6px;--label-min-width: 48px}.json-editor .node__body>.count{display:block;margin:0;pointer-events:none;padding:0 0 0 8px;color:var(--color-count);font-style:normal;-webkit-user-select:none;user-select:none;font-size:13px;line-height:normal;font-family:var(--font-code)}.json-editor .node__body>.value{position:relative;flex:1;display:flex;align-items:center;gap:0 6px;font-size:13px;line-height:1.42;--label-min-width: 78px}.json-editor .node__body>.value:before{content:":"}.json-editor .node__children>.tree{position:relative;display:none;margin:0;padding:0 0 0 26px;list-style:none;box-sizing:border-box}.json-editor .node__children>.tree:not(:empty):before{content:"";display:block;position:absolute;left:11px;top:6px;bottom:14px;width:4px;border-width:0 0 0 1px;border-style:dashed;border-color:var(--color-tree)}.json-editor .node__children>.tree:not(:empty):after{content:"";display:block;position:absolute;left:9px;bottom:13px;width:5px;height:5px;background:var(--color-tree);border-radius:50%}.json-editor .node.open>.node__body .fold svg{rotate:90deg}.json-editor .node.open>.node__children>.tree{display:grid}.json-editor .node.open>.node__children>.tree:empty{display:none}.json-editor .node[data-type=object]>.node__body .count:before{content:"{"}.json-editor .node[data-type=object]>.node__body .count:after{content:"}"}.json-editor .node[data-type=object]>.node__body .value{display:none}.json-editor .node[data-type=array]>.node__body .count:before{content:"["}.json-editor .node[data-type=array]>.node__body .count:after{content:"]"}.json-editor .node[data-type=array]>.node__body .value{display:none}.json-editor .node[data-type=array]>.node__children>.tree>.node>.node__body>.key{display:none}.json-editor .node[data-type=string]>.node__body .fold,.json-editor .node[data-type=number]>.node__body .fold,.json-editor .node[data-type=boolean]>.node__body .fold,.json-editor .node[data-type=null]>.node__body .fold{display:none}.json-editor .node[data-type=string]>.node__children>.tree,.json-editor .node[data-type=number]>.node__children>.tree,.json-editor .node[data-type=boolean]>.node__children>.tree,.json-editor .node[data-type=null]>.node__children>.tree{display:none}.json-editor .node:before,.json-editor .node:after{display:none;content:"";position:absolute;left:0;right:0;height:2px;background-color:var(--color-drag-line);border-radius:2px}.json-editor .node:before{top:-1px}.json-editor .node:after{bottom:-1px}.json-editor .node.drag-over-start:before{display:block}.json-editor .node.drag-over-end:after{display:block}.json-editor.dragging .node:not(.root)>.node__body{opacity:.25}.json-editor.dragging .drag-area>.node>.node__body{opacity:unset}.json-editor .drag-select{background-color:var(--color-drag-target-bg)}.json-editor:is([data-edit=none],[data-edit=value]) .node__body>.sort{display:none}.json-editor:is([data-edit=none],[data-edit=value]) .node__body>.type>button{opacity:unset;cursor:default;outline:unset}.json-editor:is([data-edit=none],[data-edit=value]) .node__body>.fold{outline:unset}.json-editor:is([data-edit=none],[data-edit=value]) .node__body>.key .label-field{caret-color:transparent}@media (hover: hover) and (pointer: fine){.json-editor:is([data-edit=none],[data-edit=value]) .node__body>.key .label-field:hover{background-color:unset}}.json-editor:is([data-edit=none],[data-edit=value]) .node__body>.key .label-field:focus{outline:unset}.json-editor[data-edit=none] .node__body>.value .label-field{caret-color:transparent}@media (hover: hover) and (pointer: fine){.json-editor[data-edit=none] .node__body>.value .label-field:hover{background-color:unset}}.json-editor[data-edit=none] .node__body>.value .label-field:focus{outline:unset}.json-editor[data-edit=none] .node__body>.value .label-switch{cursor:default}.json-editor[data-edit=none] .node__body>.value .label-switch span{box-shadow:inset 0 0 0 1px var(--switch-outline)}.json-editor[data-edit=none] .node__body>.value .label-switch i{width:var(--switch-unit-size);transform:translate(var(--switch-unit-x))}.json-editor .context{position:absolute;top:-8px;right:-6px;z-index:2}.json-editor .context.is-root{left:28px}.json-editor .context ol{position:absolute;left:0;margin:0;padding:0;list-style:none;background:var(--context-color-inner);border-radius:var(--context-radius);box-shadow:var(--context-shadow)}.json-editor .context li{position:relative}.json-editor .context li:not(:first-child){margin-top:1px}.json-editor .context li:first-child>button{border-top-left-radius:var(--context-radius);border-top-right-radius:var(--context-radius)}.json-editor .context li:last-child>button{border-bottom-left-radius:var(--context-radius);border-bottom-right-radius:var(--context-radius)}.json-editor .context li.type>button{grid-template-columns:auto 1fr;gap:8px}.json-editor .context li.type>button:disabled>*{opacity:.25}.json-editor .context li.dropdown:hover>button,.json-editor .context li.dropdown:focus-within>button{background-color:var(--context-color-active)}.json-editor .context li.dropdown:hover>.children,.json-editor .context li.dropdown:focus-within>.children{opacity:1;pointer-events:auto}.json-editor .context li.dropdown>button{grid-template-columns:1fr auto}.json-editor .context li.remove .label{color:var(--context-color-remove)}.json-editor .context button{display:grid;align-items:center;margin:0;padding:8px 12px;min-width:150px;text-align:left;box-sizing:border-box;background-color:var(--context-color-bg);border:none;cursor:pointer;border-radius:0;transition:background-color .12s ease-out;font-size:12px;letter-spacing:-.25px;outline:none;color:var(--context-color-text);-webkit-tap-highlight-color:transparent}.json-editor .context button:hover:not(:disabled),.json-editor .context button:active:not(:disabled){background-color:var(--context-color-active)}.json-editor .context button:not(.parent):focus-visible{outline:2px solid var(--color-focus);outline-offset:-2px}.json-editor .context button:disabled{cursor:default}.json-editor .context .label{display:block;font-style:normal;pointer-events:none;-webkit-user-select:none;user-select:none}.json-editor .context .type-icon{--type-size: 16px;--type-icon-size: 8px}.json-editor .context .arrow{display:block;margin:0 -4px 0 0;pointer-events:none}.json-editor .context .arrow svg{display:block;width:16px;color:var(--color-bullet);stroke-width:1.5}.json-editor .context .children{position:absolute;top:-12px;right:4px;z-index:2;pointer-events:none;opacity:0;transition:opacity .24s ease-out}.json-editor .context .children ol{top:0;left:0} 2 | -------------------------------------------------------------------------------- /lib/json-editor.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@redgoose/json-editor' { 2 | 3 | type typeOptions = { 4 | live?: boolean 5 | theme?: 'system' | 'light' | 'dark' 6 | edit?: 'all' | 'value' | 'none' 7 | openDepth?: boolean 8 | node?: object | any[] 9 | } 10 | type typeData = any[] | object 11 | type typeAddNodeOptions = { 12 | open?: boolean 13 | callback?: Function 14 | } 15 | type typeNames = 'object' | 'array' | 'string' | 'number' | 'boolean' | 'null' 16 | 17 | export default class JsonEditor { 18 | // properties 19 | options: typeOptions 20 | context: Context 21 | // class units 22 | constructor(wrap: HTMLElement, options?: typeOptions) 23 | // public methods 24 | addNode(target: HTMLElement, data: typeData, options?: typeAddNodeOptions, useUpdate?: boolean, useUpdateCount?: boolean): void 25 | removeNode(node: HTMLElement, useUpdate?: boolean): void 26 | changeType(node: HTMLElement, type: typeNames, useUpdate?: boolean): void 27 | changeKey(node: HTMLElement, keyword: string): void 28 | changeValue(node: HTMLElement, value: string|number|boolean|null): void 29 | duplicate(target: HTMLElement, useUpdate?: boolean): void 30 | fold(node: HTMLElement, sw?: boolean): void 31 | clear(): void 32 | destroy(): void 33 | replace(data: typeData, options?: object, useUpdate?: boolean): void 34 | import(target: HTMLElement, data: typeData, useUpdate?: boolean): void 35 | export(node: HTMLElement, json?: boolean, space?: number): any[]|object 36 | updateLanguage(): void 37 | } 38 | 39 | export class Context { 40 | constructor(parent: JsonEditor, node: HTMLElement, isRoot: boolean) 41 | close(): void 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /lib/json-editor.umd.cjs: -------------------------------------------------------------------------------- 1 | (function(y,C){typeof exports=="object"&&typeof module<"u"?module.exports=C():typeof define=="function"&&define.amd?define(C):(y=typeof globalThis<"u"?globalThis:y||self,y.JsonEditor=C())})(this,function(){"use strict";var bn=Object.defineProperty;var le=y=>{throw TypeError(y)};var Cn=(y,C,N)=>C in y?bn(y,C,{enumerable:!0,configurable:!0,writable:!0,value:N}):y[C]=N;var j=(y,C,N)=>Cn(y,typeof C!="symbol"?C+"":C,N),Rt=(y,C,N)=>C.has(y)||le("Cannot "+N);var m=(y,C,N)=>(Rt(y,C,"read from private field"),N?N.call(y):C.get(y)),F=(y,C,N)=>C.has(y)?le("Cannot add the same private member more than once"):C instanceof WeakSet?C.add(y):C.set(y,N),U=(y,C,N,O)=>(Rt(y,C,"write to private field"),O?O.call(y,N):C.set(y,N),N),h=(y,C,N)=>(Rt(y,C,"access private method"),N);var Y,Z,B,ue,fe,de,he,b,G,l,pe,At,lt,ge,ye,ut,tt,Lt,A,Ot,et,St,_t,nt,ft,dt,me,be,Ce;const y=document,C=window,N=y.documentElement,O=y.createElement.bind(y),Bt=O("div"),ht=O("table"),we=O("tbody"),$t=O("tr"),{isArray:it,prototype:Mt}=Array,{concat:ve,filter:pt,indexOf:Dt,map:It,push:Ne,slice:Pt,some:gt,splice:xe}=Mt,Ee=/^#(?:[\w-]|\\.|[^\x00-\xa0])*$/,Te=/^\.(?:[\w-]|\\.|[^\x00-\xa0])*$/,ke=/<.+>/,Re=/^\w+$/;function yt(t,e){const n=Ae(e);return!t||!n&&!H(e)&&!E(e)?[]:!n&&Te.test(t)?e.getElementsByClassName(t.slice(1).replace(/\\/g,"")):!n&&Re.test(t)?e.getElementsByTagName(t):e.querySelectorAll(t)}class st{constructor(e,n){if(!e)return;if(mt(e))return e;let i=e;if(k(e)){const s=n||y;if(i=Ee.test(e)&&H(s)?s.getElementById(e.slice(1).replace(/\\/g,"")):ke.test(e)?Ft(e):mt(s)?s.find(e):k(s)?o(s).find(e):yt(e,s),!i)return}else if(V(e))return this.ready(e);(i.nodeType||i===C)&&(i=[i]),this.length=i.length;for(let s=0,r=this.length;s{for(;e.firstChild;)e.removeChild(e.firstChild)})};function rt(...t){const e=Oe(t[0])?t.shift():!1,n=t.shift(),i=t.length;if(!n)return{};if(!i)return rt(e,o,n);for(let s=0;s{E(r)&&T(n,(u,a)=>{i?e?r.classList.add(a):r.classList.remove(a):r.classList.toggle(a)})})},c.addClass=function(t){return this.toggleClass(t,!0)},c.removeAttr=function(t){const e=ot(t);return this.each((n,i)=>{E(i)&&T(e,(s,r)=>{i.removeAttribute(r)})})};function _e(t,e){if(t){if(k(t)){if(arguments.length<2){if(!this[0]||!E(this[0]))return;const n=this[0].getAttribute(t);return X(n)?void 0:n}return R(e)?this:X(e)?this.removeAttr(t):this.each((n,i)=>{E(i)&&i.setAttribute(t,e)})}for(const n in t)this.attr(n,t[n]);return this}}c.attr=_e,c.removeClass=function(t){return arguments.length?this.toggleClass(t,!1):this.attr("class","")},c.hasClass=function(t){return!!t&>.call(this,e=>E(e)&&e.classList.contains(t))},c.get=function(t){return R(t)?Pt.call(this):(t=Number(t),this[t<0?t+this.length:t])},c.eq=function(t){return o(this.get(t))},c.first=function(){return this.eq(0)},c.last=function(){return this.eq(-1)};function Be(t){return R(t)?this.get().map(e=>E(e)||Le(e)?e.textContent:"").join(""):this.each((e,n)=>{E(n)&&(n.textContent=t)})}c.text=Be;function $(t,e,n){if(!E(t))return;const i=C.getComputedStyle(t,null);return n?i.getPropertyValue(e)||void 0:i[e]||t.style[e]}function S(t,e){return parseInt($(t,e),10)||0}function Ut(t,e){return S(t,`border${e?"Left":"Top"}Width`)+S(t,`padding${e?"Left":"Top"}`)+S(t,`padding${e?"Right":"Bottom"}`)+S(t,`border${e?"Right":"Bottom"}Width`)}const Ct={};function $e(t){if(Ct[t])return Ct[t];const e=O(t);y.body.insertBefore(e,null);const n=$(e,"display");return y.body.removeChild(e),Ct[t]=n!=="none"?n:"block"}function Ht(t){return $(t,"display")==="none"}function Vt(t,e){const n=t&&(t.matches||t.webkitMatchesSelector||t.msMatchesSelector);return!!n&&!!e&&n.call(t,e)}function ct(t){return k(t)?(e,n)=>Vt(n,t):V(t)?t:mt(t)?(e,n)=>t.is(n):t?(e,n)=>n===t:()=>!1}c.filter=function(t){const e=ct(t);return o(pt.call(this,(n,i)=>e.call(n,i,n)))};function D(t,e){return e?t.filter(e):t}c.detach=function(t){return D(this,t).each((e,n)=>{n.parentNode&&n.parentNode.removeChild(n)}),this};const Me=/^\s*<(\w+)[^>]*>/,De=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,Yt={"*":Bt,tr:we,td:$t,th:$t,thead:ht,tbody:ht,tfoot:ht};function Ft(t){if(!k(t))return[];if(De.test(t))return[O(RegExp.$1)];const e=Me.test(t)&&RegExp.$1,n=Yt[e]||Yt["*"];return n.innerHTML=t,o(n.childNodes).detach().get()}o.parseHTML=Ft,c.has=function(t){const e=k(t)?(n,i)=>yt(t,i).length:(n,i)=>i.contains(t);return this.filter(e)},c.not=function(t){const e=ct(t);return this.filter((n,i)=>(!k(t)||E(i))&&!e.call(i,n,i))};function M(t,e,n,i){const s=[],r=V(e),u=i&&ct(i);for(let a=0,p=t.length;ae.selected&&!e.disabled&&!e.parentNode.disabled),"value"):t.value||""}function Ie(t){return arguments.length?this.each((e,n)=>{const i=n.multiple&&n.options;if(i||ne.test(n.type)){const s=it(t)?It.call(t,String):X(t)?[]:[String(t)];i?T(n.options,(r,u)=>{u.selected=s.indexOf(u.value)>=0},!0):n.checked=s.indexOf(n.value)>=0}else n.value=R(t)||X(t)?"":t}):this[0]&&Jt(this[0])}c.val=Ie,c.is=function(t){const e=ct(t);return gt.call(this,(n,i)=>e.call(n,i,n))},o.guid=1;function _(t){return t.length>1?pt.call(t,(e,n,i)=>Dt.call(i,e)===n):t}o.unique=_,c.add=function(t,e){return o(_(this.get().concat(o(t,e).get())))},c.children=function(t){return D(o(_(M(this,e=>e.children))),t)},c.parent=function(t){return D(o(_(M(this,"parentNode"))),t)},c.index=function(t){const e=t?o(t)[0]:this[0],n=t?this:o(e).parent().children();return Dt.call(n,e)},c.closest=function(t){const e=this.filter(t);if(e.length)return e;const n=this.parent();return n.length?n.closest(t):e},c.siblings=function(t){return D(o(_(M(this,e=>o(e).parent().children().not(e)))),t)},c.find=function(t){return o(_(M(this,e=>yt(t,e))))};const Pe=/^\s*\s*$/g,je=/^$|^module$|\/(java|ecma)script/i,Ue=["type","src","nonce","noModule"];function He(t,e){const n=o(t);n.filter("script").add(n.find("script")).each((i,s)=>{if(je.test(s.type)&&N.contains(s)){const r=O("script");r.text=s.textContent.replace(Pe,""),T(Ue,(u,a)=>{s[a]&&(r[a]=s[a])}),e.head.insertBefore(r,null),e.head.removeChild(r)}})}function Ve(t,e,n,i,s){i?t.insertBefore(e,n?t.firstChild:null):t.nodeName==="HTML"?t.parentNode.replaceChild(e,t):t.parentNode.insertBefore(e,n?t:t.nextSibling),s&&He(e,t.ownerDocument)}function I(t,e,n,i,s,r,u,a){return T(t,(p,d)=>{T(o(d),(g,x)=>{T(o(e),(L,v)=>{const P=n?x:v,w=n?v:x,q=n?g:L;Ve(P,q?w.cloneNode(!0):w,i,s,!q)},a)},u)},r),e}c.after=function(){return I(arguments,this,!1,!1,!1,!0,!0)},c.append=function(){return I(arguments,this,!1,!1,!0)};function Ye(t){if(!arguments.length)return this[0]&&this[0].innerHTML;if(R(t))return this;const e=/]/.test(t);return this.each((n,i)=>{E(i)&&(e?o(i).empty().append(t):i.innerHTML=t)})}c.html=Ye,c.appendTo=function(t){return I(arguments,this,!0,!1,!0)},c.wrapInner=function(t){return this.each((e,n)=>{const i=o(n),s=i.contents();s.length?s.wrapAll(t):i.append(t)})},c.before=function(){return I(arguments,this,!1,!0)},c.wrapAll=function(t){let e=o(t),n=e[0];for(;n.children.length;)n=n.firstElementChild;return this.first().before(e),this.appendTo(n)},c.wrap=function(t){return this.each((e,n)=>{const i=o(t)[0];o(n).wrapAll(e?i.cloneNode(!0):i)})},c.insertAfter=function(t){return I(arguments,this,!0,!1,!1,!1,!1,!0)},c.insertBefore=function(t){return I(arguments,this,!0,!0)},c.prepend=function(){return I(arguments,this,!1,!0,!0,!0,!0)},c.prependTo=function(t){return I(arguments,this,!0,!0,!0,!1,!1,!0)},c.contents=function(){return o(_(M(this,t=>t.tagName==="IFRAME"?[t.contentDocument]:t.tagName==="TEMPLATE"?t.content.childNodes:t.childNodes)))},c.next=function(t,e,n){return D(o(_(M(this,"nextElementSibling",e,n))),t)},c.nextAll=function(t){return this.next(t,!0)},c.nextUntil=function(t,e){return this.next(e,!0,t)},c.parents=function(t,e){return D(o(_(M(this,"parentElement",!0,e))),t)},c.parentsUntil=function(t,e){return this.parents(e,t)},c.prev=function(t,e,n){return D(o(_(M(this,"previousElementSibling",e,n))),t)},c.prevAll=function(t){return this.prev(t,!0)},c.prevUntil=function(t,e){return this.prev(e,!0,t)},c.map=function(t){return o(ve.apply([],It.call(this,(e,n)=>t.call(e,n,e))))},c.clone=function(){return this.map((t,e)=>e.cloneNode(!0))},c.offsetParent=function(){return this.map((t,e)=>{let n=e.offsetParent;for(;n&&$(n,"position")==="static";)n=n.offsetParent;return n||N})},c.slice=function(t,e){return o(Pt.call(this,t,e))};const Fe=/-([a-z])/g;function wt(t){return t.replace(Fe,(e,n)=>n.toUpperCase())}c.ready=function(t){const e=()=>setTimeout(t,0,o);return y.readyState!=="loading"?e():y.addEventListener("DOMContentLoaded",e),this},c.unwrap=function(){return this.parent().each((t,e)=>{if(e.tagName==="BODY")return;const n=o(e);n.replaceWith(n.children())}),this},c.offset=function(){const t=this[0];if(!t)return;const e=t.getBoundingClientRect();return{top:e.top+C.pageYOffset,left:e.left+C.pageXOffset}},c.position=function(){const t=this[0];if(!t)return;const e=$(t,"position")==="fixed",n=e?t.getBoundingClientRect():this.offset();if(!e){const i=t.ownerDocument;let s=t.offsetParent||i.documentElement;for(;(s===i.body||s===i.documentElement)&&$(s,"position")==="static";)s=s.parentNode;if(s!==t&&E(s)){const r=o(s).offset();n.top-=r.top+S(s,"borderTopWidth"),n.left-=r.left+S(s,"borderLeftWidth")}}return{top:n.top-S(t,"marginTop"),left:n.left-S(t,"marginLeft")}};const Kt={class:"className",contenteditable:"contentEditable",for:"htmlFor",readonly:"readOnly",maxlength:"maxLength",tabindex:"tabIndex",colspan:"colSpan",rowspan:"rowSpan",usemap:"useMap"};c.prop=function(t,e){if(t){if(k(t))return t=Kt[t]||t,arguments.length<2?this[0]&&this[0][t]:this.each((n,i)=>{i[t]=e});for(const n in t)this.prop(n,t[n]);return this}},c.removeProp=function(t){return this.each((e,n)=>{delete n[Kt[t]||t]})};const Je=/^--/;function vt(t){return Je.test(t)}const Nt={},{style:Ke}=Bt,We=["webkit","moz","ms"];function Ze(t,e=vt(t)){if(e)return t;if(!Nt[t]){const n=wt(t),i=`${n[0].toUpperCase()}${n.slice(1)}`,s=`${n} ${We.join(`${i} `)}${i}`.split(" ");T(s,(r,u)=>{if(u in Ke)return Nt[t]=u,!1})}return Nt[t]}const Ge={animationIterationCount:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0};function Wt(t,e,n=vt(t)){return!n&&!Ge[t]&&jt(e)?`${e}px`:e}function qe(t,e){if(k(t)){const n=vt(t);return t=Ze(t,n),arguments.length<2?this[0]&&$(this[0],t,n):t?(e=Wt(t,e,n),this.each((i,s)=>{E(s)&&(n?s.style.setProperty(t,e):s.style[t]=e)})):this}for(const n in t)this.css(n,t[n]);return this}c.css=qe;function Zt(t,e){try{return t(e)}catch{return e}}const ze=/^\s+|\s+$/;function Gt(t,e){const n=t.dataset[e]||t.dataset[wt(e)];return ze.test(n)?n:Zt(JSON.parse,n)}function Xe(t,e,n){n=Zt(JSON.stringify,n),t.dataset[wt(e)]=n}function Qe(t,e){if(!t){if(!this[0])return;const n={};for(const i in this[0].dataset)n[i]=Gt(this[0],i);return n}if(k(t))return arguments.length<2?this[0]&&Gt(this[0],t):R(e)?this:this.each((n,i)=>{Xe(i,t,e)});for(const n in t)this.data(n,t[n]);return this}c.data=Qe;function qt(t,e){const n=t.documentElement;return Math.max(t.body[`scroll${e}`],n[`scroll${e}`],t.body[`offset${e}`],n[`offset${e}`],n[`client${e}`])}T([!0,!1],(t,e)=>{T(["Width","Height"],(n,i)=>{const s=`${e?"outer":"inner"}${i}`;c[s]=function(r){if(this[0])return J(this[0])?e?this[0][`inner${i}`]:this[0].document.documentElement[`client${i}`]:H(this[0])?qt(this[0],i):this[0][`${e?"offset":"client"}${i}`]+(r&&e?S(this[0],`margin${n?"Top":"Left"}`)+S(this[0],`margin${n?"Bottom":"Right"}`):0)}})}),T(["Width","Height"],(t,e)=>{const n=e.toLowerCase();c[n]=function(i){if(!this[0])return R(i)?void 0:this;if(!arguments.length)return J(this[0])?this[0].document.documentElement[`client${e}`]:H(this[0])?qt(this[0],e):this[0].getBoundingClientRect()[n]-Ut(this[0],!t);const s=parseInt(i,10);return this.each((r,u)=>{if(!E(u))return;const a=$(u,"boxSizing");u.style[n]=Wt(n,s+(a==="border-box"?Ut(u,!t):0))})}});const zt="___cd";c.toggle=function(t){return this.each((e,n)=>{if(!E(n))return;const i=Ht(n);(R(t)?i:t)?(n.style.display=n[zt]||"",Ht(n)&&(n.style.display=$e(n.tagName))):i||(n[zt]=$(n,"display"),n.style.display="none")})},c.hide=function(){return this.toggle(!1)},c.show=function(){return this.toggle(!0)};const Xt="___ce",xt=".",Et={focus:"focusin",blur:"focusout"},Qt={mouseenter:"mouseover",mouseleave:"mouseout"},tn=/^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function Tt(t){return Qt[t]||Et[t]||t}function kt(t){const e=t.split(xt);return[e[0],e.slice(1).sort()]}c.trigger=function(t,e){if(k(t)){const[i,s]=kt(t),r=Tt(i);if(!r)return this;const u=tn.test(r)?"MouseEvents":"HTMLEvents";t=y.createEvent(u),t.initEvent(r,!0,!0),t.namespace=s.join(xt),t.___ot=i}t.___td=e;const n=t.___ot in Et;return this.each((i,s)=>{n&&V(s[t.___ot])&&(s[`___i${t.type}`]=!0,s[t.___ot](),s[`___i${t.type}`]=!1),s.dispatchEvent(t)})};function te(t){return t[Xt]=t[Xt]||{}}function en(t,e,n,i,s){const r=te(t);r[e]=r[e]||[],r[e].push([n,i,s]),t.addEventListener(e,s)}function ee(t,e){return!e||!gt.call(e,n=>t.indexOf(n)<0)}function at(t,e,n,i,s){const r=te(t);if(e)r[e]&&(r[e]=r[e].filter(([u,a,p])=>{if(s&&p.guid!==s.guid||!ee(u,n)||i&&i!==a)return!0;t.removeEventListener(e,p)}));else for(e in r)at(t,e,n,i,s)}c.off=function(t,e,n){if(R(t))this.each((i,s)=>{!E(s)&&!H(s)&&!J(s)||at(s)});else if(k(t))V(e)&&(n=e,e=""),T(ot(t),(i,s)=>{const[r,u]=kt(s),a=Tt(r);this.each((p,d)=>{!E(d)&&!H(d)&&!J(d)||at(d,a,u,e,n)})});else for(const i in t)this.off(i,t[i]);return this},c.remove=function(t){return D(this,t).detach().off(),this},c.replaceWith=function(t){return this.before(t).remove()},c.replaceAll=function(t){return o(t).replaceWith(this),this};function nn(t,e,n,i,s){if(!k(t)){for(const r in t)this.on(r,e,n,t[r],s);return this}return k(e)||(R(e)||X(e)?e="":R(n)?(n=e,e=""):(i=n,n=e,e="")),V(i)||(i=n,n=void 0),i?(T(ot(t),(r,u)=>{const[a,p]=kt(u),d=Tt(a),g=a in Qt,x=a in Et;d&&this.each((L,v)=>{if(!E(v)&&!H(v)&&!J(v))return;const P=function(w){if(w.target[`___i${w.type}`])return w.stopImmediatePropagation();if(w.namespace&&!ee(p,w.namespace.split(xt))||!e&&(x&&(w.target!==v||w.___ot===d)||g&&w.relatedTarget&&v.contains(w.relatedTarget)))return;let q=v;if(e){let z=w.target;for(;!Vt(z,e);)if(z===v||(z=z.parentNode,!z))return;q=z}Object.defineProperty(w,"currentTarget",{configurable:!0,get(){return q}}),Object.defineProperty(w,"delegateTarget",{configurable:!0,get(){return v}}),Object.defineProperty(w,"data",{configurable:!0,get(){return n}});const mn=i.call(q,w,w.___td);s&&at(v,d,p,e,P),mn===!1&&(w.preventDefault(),w.stopPropagation())};P.guid=i.guid=i.guid||o.guid++,en(v,d,p,e,P)})}),this):this}c.on=nn;function sn(t,e,n,i){return this.on(t,e,n,i,!0)}c.one=sn;const rn=/\r?\n/g;function on(t,e){return`&${encodeURIComponent(t)}=${encodeURIComponent(e.replace(rn,`\r 2 | `))}`}const cn=/file|reset|submit|button|image/i,ne=/radio|checkbox/i;c.serialize=function(){let t="";return this.each((e,n)=>{T(n.elements||[n],(i,s)=>{if(s.disabled||!s.name||s.tagName==="FIELDSET"||cn.test(s.type)||ne.test(s.type)&&!s.checked)return;const r=Jt(s);if(!R(r)){const u=it(r)?r:[r];T(u,(a,p)=>{t+=on(s.name,p)})}})}),t.slice(1)};const an={live:!1,theme:"system",edit:"all",openDepth:0,node:void 0},ln={open:!0,callback:void 0},f={OBJECT:"object",ARRAY:"array",STRING:"string",NUMBER:"number",BOOLEAN:"boolean",NULL:"null"},K={START:"pointerdown",MOVE:"pointermove",END:"pointerup.json-editor pointercancel.json-editor"},W={CLICK:"click.json-editor-context",KEYUP:"keyup.json-editor-context"},Q={START:"drag-over-start",END:"drag-over-end",ALL:"drag-over-start drag-over-end"},un='',fn='',dn='',ie={object:'',array:'',string:'',number:'',boolean:'',null:''};class hn{constructor(e,n,i=!1){F(this,B);F(this,Y);j(this,"el",{node:void 0,type:void 0,dialog:void 0});F(this,Z);U(this,Y,e),this.el.node=o(n),U(this,Z,String(this.el.node.data("type"))),this.el.type=this.el.node.find("& > .node__body > .type"),this.el.type.addClass("open"),this.el.dialog=h(this,B,fe).call(this,h(this,B,ue).call(this),m(this,Z),i),this.el.dialog.on("click",s=>s.stopPropagation()),this.el.dialog.find("button").on("click",s=>h(this,B,de).call(this,s)),m(this,Y).el.wrap.get(0).dispatchEvent(new CustomEvent("context",{detail:{body:this.el.dialog.get(0),node:this.el.node.get(0),type:m(this,Z),isRoot:i,$:o}})),this.el.type.append(this.el.dialog),o(window).on(W.CLICK,s=>this.close(s)),o(window).on(W.KEYUP,s=>h(this,B,he).call(this,s))}close(){this.el.type.removeClass("open"),this.el.dialog.remove(),o(window).off(W.CLICK),o(window).off(W.KEYUP),delete m(this,Y).context}}Y=new WeakMap,Z=new WeakMap,B=new WeakSet,ue=function(){const{lang:e}=m(this,Y);return[{key:"change-type",label:e.contextChangeType,children:[{key:f.OBJECT,label:e.contextTypeObject},{key:f.ARRAY,label:e.contextTypeArray},{key:f.STRING,label:e.contextTypeString},{key:f.NUMBER,label:e.contextTypeNumber},{key:f.BOOLEAN,label:e.contextTypeBoolean},{key:f.NULL,label:e.contextTypeNull}]},{key:"insert",label:e.contextInsertNode,children:[{key:f.OBJECT,label:e.contextTypeObject},{key:f.ARRAY,label:e.contextTypeArray},{key:f.STRING,label:e.contextTypeString},{key:f.NUMBER,label:e.contextTypeNumber},{key:f.BOOLEAN,label:e.contextTypeBoolean},{key:f.NULL,label:e.contextTypeNull}]},{key:"duplicate",label:e.contextDuplicate},{key:"remove",label:e.contextRemove}]},fe=function(e,n,i=!1){function s(a,p){let d="";const{key:g,label:x,children:L}=a;if(i)switch(g){case f.STRING:case f.NUMBER:case f.BOOLEAN:case f.NULL:if(p==="change-type")return"";break;case"duplicate":case"remove":return""}let v="",P="",w="";switch(g){case"change-type":v=' class="dropdown"',w=" disabled";break;case"insert":if([f.STRING,f.NUMBER,f.BOOLEAN,f.NULL].indexOf(n)>-1)return"";v=' class="dropdown"',w=" disabled";break;case"duplicate":v=' class="duplicate"',w=' data-mode="duplicate"';break;case"remove":v=' class="remove"',w=' data-mode="remove"';break;case f.OBJECT:case f.ARRAY:case f.STRING:case f.NUMBER:case f.BOOLEAN:case f.NULL:v=' class="type"',P=`${ie[g]}`,w=` data-mode="${p}" data-type="${g}"`,p==="change-type"&&g===n&&(w=" disabled");break}return d+=``,d+=`",(L==null?void 0:L.length)>0&&(d+='
    ',d+=r(L,g),d+="
    "),d+="",d}function r(a,p=void 0){let d="
      ";for(let g in a)d+=s(a[g],p);return d+="
    ",d}let u=`",o(u)},de=function(e){const n=o(e.currentTarget),i=n.data("mode");let s=String(n.data("type"));s=s==="undefined"?"":s,this.close(),this.selectItem&&typeof this.selectItem=="function"&&this.selectItem(this.el.node,i,s)},he=function(e){e.code==="Escape"&&this.close()};function se(t){return t==null?"null":Array.isArray(t)?"array":typeof t=="string"?"string":typeof t=="number"?"number":typeof t=="boolean"?"boolean":"object"}function pn(t){try{return typeof t=="string"?JSON.parse(t):Array.isArray(t)?Object.assign([],t):o.isPlainObject(t)?Object.assign({},t):{}}catch(e){console.error("error",e.message)}}function gn(t){return Array.isArray(t)?t.length:o.isPlainObject(t)?Object.keys(t).length:0}function re(t){if(t.ctrlKey||t.metaKey)switch(t.code){case"KeyB":case"KeyI":case"KeyU":return!0}return!1}function oe(t){t.preventDefault();const e=t.currentTarget,n=document.createRange();n.selectNodeContents(e);const i=window.getSelection();i.removeAllRanges(),i.addRange(n)}function ce(t){t.preventDefault();let n=(t.originalEvent||t).clipboardData.getData("text/plain");document.execCommand("insertText",!1,n)}const yn={nodeChangeSort:"Change node sort",nodeContextMenu:"Node context menu",nodeFold:"Collapse/Expand",contextChangeType:"Change type",contextInsertNode:"Insert",contextTypeObject:"Object",contextTypeArray:"Array",contextTypeString:"String",contextTypeNumber:"Number",contextTypeBoolean:"Boolean",contextTypeNull:"Null",contextDuplicate:"Duplicate",contextRemove:"Remove"};class ae{constructor(e,n={}){F(this,l);j(this,"$");j(this,"el",{wrap:null,body:null,tree:null});j(this,"options");j(this,"context");F(this,b);F(this,G,!1);j(this,"lang",yn);this.$=o,this.el.wrap=o(e),this.el.body=o('
    '),this.options=new Proxy(Object.assign({},an,n),{get:(i,s)=>i[s],set:h(this,l,pe).bind(this)}),this.updateLanguage(),this.el.wrap.append(this.el.body),h(this,l,At).call(this,this.options.theme),h(this,l,St).call(this,this.options.edit),this.replace(n.node||{},{},!1),h(this,l,_t).call(this,n.openDepth)}addNode(e,n,i={},s=!0,r=!0){i={...ln,...i};const{open:u,callback:a}=i;e=o(e);const p=n.type===void 0?se(n.value):n.type,d=h(this,l,lt).call(this,p,!1);h(this,l,ut).call(this,d,{...n,open:u,type:p,depth:e.data("depth")+1}),h(this,l,nt).call(this,d),e.find("& > .node__children > ul").append(d),r&&h(this,l,et).call(this,e),(p===f.ARRAY||p===f.OBJECT)&&a&&typeof a=="function"&&a(d.get(0),n.value),s&&h(this,l,A).call(this)}removeNode(e,n=!0){e=o(e);const i=e.parent().closest(".node");e.remove(),h(this,l,et).call(this,i),n&&h(this,l,A).call(this)}changeType(e,n,i=!0){const s=o(e),r={key:s.find("& > .node__body .key").text(),value:h(this,l,Lt).call(this,s),type:n,open:s.hasClass("open"),depth:s.data("depth")},u=s.find("& > .node__children > .tree").html(),a=s.hasClass("root");s.empty(),s.html(h(this,l,lt).call(this,n,a).html()),u&&s.find("& > .node__children > .tree").html(u),h(this,l,ut).call(this,s,r),h(this,l,nt).call(this,s),s.attr("data-type",n),i&&h(this,l,A).call(this)}changeKey(e,n){o(e).find(".key > div").text(n),h(this,l,A).call(this)}changeValue(e,n){o(e).find(".value > div").text(n),h(this,l,A).call(this)}duplicate(e,n=!0){e=o(e);const i=o(e.get(0).outerHTML);h(this,l,nt).call(this,i),e.after(i),h(this,l,et).call(this,e.parent().closest(".node")),n&&h(this,l,A).call(this)}fold(e,n){e=o(e),n===void 0?e.toggleClass("open"):n===!0?e.addClass("open"):e.removeClass("open")}clear(){this.el.tree&&(this.el.body.empty(),this.replace({},{},!1),h(this,l,A).call(this))}destroy(){o(window).off(K.END).off(W.CLICK).off(W.KEYUP),this.el.wrap.empty()}replace(e,n={},i=!0){this.el.body.empty(),e=pn(e);const s=h(this,l,ge).call(this,e);this.import(s,e,!1,!1),i&&h(this,l,A).call(this),n!=null&&n.openDepth&&h(this,l,_t).call(this,n==null?void 0:n.openDepth)}import(e,n,i=!0,s=!0){e=o(e),o.each(n,(r,u)=>{const a={key:r,value:u},p={open:!1,callback:(d,g)=>this.import(d,g,!1,!1)};this.addNode(e,a,p,!1,!1)}),s&&h(this,l,et).call(this,e),i&&h(this,l,A).call(this)}export(e=void 0,n,i=2){let s=h(this,l,Ot).call(this,e);if(n){let r=2;return i===!0?r=" ":typeof i===f.NUMBER&&(r=i),JSON.stringify(s,null,r)}else return s}updateLanguage(){}}return b=new WeakMap,G=new WeakMap,l=new WeakSet,pe=function(e,n,i){switch(e[n]=i,n){case"theme":h(this,l,At).call(this,i);break;case"edit":h(this,l,St).call(this,i);break}return!0},At=function(e){e=["system","light","dark"].indexOf(e)>-1?e:"system",this.el.body.attr("data-theme",e)},lt=function(e,n=!1){const{lang:i}=this;let s=`
  • `;return s+='
    ',n||(s+=`
    ${dn}
    `),s+=`
    `,(e===f.OBJECT||e===f.ARRAY)&&(s+=``),n||(s+='
    '),s+='',n||(s+='
    '),s+="
    ",s+='
      ',s+="
    • ",o(s)},ge=function(e){const n=se(e),i=h(this,l,lt).call(this,n,!0);return h(this,l,ut).call(this,i,{key:void 0,value:e,type:n,open:!0,depth:0}),h(this,l,nt).call(this,i),this.el.tree=o("
        "),this.el.tree.append(i),this.el.body.append(this.el.tree),i},ye=function(e,n,i){switch(n){case"change-type":this.changeType(e,i);break;case"insert":this.fold(e,!0),this.addNode(e,{key:"",value:"",type:i});break;case"duplicate":this.duplicate(e);break;case"remove":this.removeNode(e);break}},ut=function(e,n){const{key:i,value:s,type:r,open:u,depth:a}=n,p=e.hasClass("root"),d=e.children(".node__body");if(d.find(".type > button").html(`${ie[r]}`),(r===f.OBJECT||r===f.ARRAY)&&this.fold(e,u),a!==void 0&&e.attr("data-depth",a),!p){d.find(".key").html(`
        ${i}
        `);const g=d.find(".value");let x;switch(r){case f.STRING:g.html(`
        ${String(s)}
        `);break;case f.NUMBER:x=Number(s),isNaN(x)&&(x=0),g.html(``);break;case f.BOOLEAN:x=s==="false"?!1:!!s,g.html(``);break;case f.NULL:g.html('NULL');break}}if(r===f.OBJECT||r===f.ARRAY){const g=gn(s);isNaN(g)||d.find(".count").text(g)}},tt=function(e){return String(e.data("type"))},Lt=function(e){const n=h(this,l,tt).call(this,e),i=e.find("& > .node__body > .value");switch(n){case f.OBJECT:case f.ARRAY:return"";case f.STRING:return i.children(".type-string").get(0).innerText||"";case f.NUMBER:return Number(i.children(".type-number").val());case f.BOOLEAN:return i.children(".type-boolean").data("value");case f.NULL:return null}},A=function(){this.options.live&&this.el.wrap.get(0).dispatchEvent(new CustomEvent("update",{detail:h(this,l,Ot).call(this)}))},Ot=function(e){const n=(r,u)=>{let a=u===f.ARRAY?[]:{};return r.find("& > .node__children > ul > li").each((d,g)=>{if(!(u===f.ARRAY||u===f.OBJECT))return!0;g=o(g);const x=h(this,l,tt).call(this,g);switch(x){case f.OBJECT:case f.ARRAY:switch(u){case f.ARRAY:a.push(n(g,x));break;case f.OBJECT:const v=g.find("& > .node__body > .key").text();v&&(a[v]=n(g,x));break}break;case f.STRING:case f.NUMBER:case f.BOOLEAN:case f.NULL:const L=h(this,l,Lt).call(this,g);switch(u){case f.ARRAY:a.push(L);break;case f.OBJECT:const v=g.find("& > .node__body > .key").text();v&&(a[v]=L);break}break}}),a};e=o(e);const i=(e==null?void 0:e.length)>0?e:this.el.tree.children(".node"),s=h(this,l,tt).call(this,i);if([f.OBJECT,f.ARRAY].includes(s))return n(i,s)},et=function(e){e=o(e);const n=h(this,l,tt).call(this,e);if(!(n==="object"||n==="array"))return;const i=e.find("& > .node__children > ul > li").length;isNaN(i)||e.find("& > .node__body > .count").text(i)},St=function(e){e==="all"?this.el.body.removeAttr("data-edit"):this.el.body.attr("data-edit",e)},_t=function(e=0){if(!(e>0))return;this.el.body.find(".node:not(.root)").each((i,s)=>{o(s).data("depth") button").on("click",async a=>{if(a.stopPropagation(),this.options.edit!=="all")return;const p=o(a.currentTarget);if(p.parent().hasClass("open"))this.context&&this.context.close();else{this.context&&this.context.close();const d=p.closest(".node").hasClass("root");this.context=new hn(this,p.closest(".node"),d),this.context.selectItem=(g,x,L)=>h(this,l,ye).call(this,g,x,L)}}),e.find(".fold").on("click",a=>{const d=o(a.currentTarget).closest(".node");this.fold(d)});const i=e.find(".key > .label-field");i.length&&(i.on("keydown",a=>{if(this.options.edit==="all"&&(a.code==="Enter"||re(a)))return a.preventDefault()}).on("input",a=>h(this,l,ft).call(this,a)).on("blur",a=>h(this,l,dt).call(this,a)),this.options.edit!=="all"?i.on("dblclick",oe):i.on("paste",ce));const s=e.find(".value > .type-string");s.length&&(s.on("keydown",a=>{if(this.options.edit!=="none"&&re(a))return a.preventDefault()}).on("input",a=>h(this,l,ft).call(this,a)).on("blur",a=>h(this,l,dt).call(this,a)),this.options.edit==="none"?s.on("dblclick",oe):s.on("paste",ce));const r=e.find(".value > .type-number");r.length&&r.on("keydown",a=>{this.options.edit==="none"&&a.preventDefault()}).on("input",a=>h(this,l,ft).call(this,a)).on("blur",a=>h(this,l,dt).call(this,a));const u=e.find(".value > .type-boolean");u.length&&u.on("click",a=>{if(this.options.edit==="none")return;const p=o(a.currentTarget),d=!p.data("value");p.data("value",d).find("i").text(d.toString().toUpperCase()),h(this,l,A).call(this)})},ft=function(){U(this,G,!0)},dt=function(){m(this,G)&&(h(this,l,A).call(this),U(this,G,!1))},me=function(e){if(U(this,b,{}),m(this,b).$node=o(e.currentTarget).closest(".node"),m(this,b).$area=m(this,b).$node.parent(),m(this,b).$nodes=m(this,b).$area.children(".node"),m(this,b).$nodes.length<2){U(this,b,void 0);return}m(this,b).$nodes.on(K.MOVE,h(this,l,be).bind(this)),o(window).on(K.END,h(this,l,Ce).bind(this))},be=function(e){let n;if(e.pointerType==="touch"){const{clientX:a,clientY:p}=e,d=document.elementFromPoint(a,p).closest(".node");if(!m(this,b).$nodes.get().includes(d))return;n=o(d)}else n=o(e.currentTarget);const i=n.children(".node__body");if(!(i.length>0))return;const{y:s,height:r}=i.get(0).getBoundingClientRect(),u=r*.5", 5 | "version": "1.2.2", 6 | "keywords": [ "json", "editor", "library", "tool" ], 7 | "license": "MIT", 8 | "main": "./lib/json-editor.js", 9 | "types": "./lib/json-editor.d.ts", 10 | "files": [ "lib" ], 11 | "exports": { 12 | ".": { 13 | "module": "./lib/json-editor.js", 14 | "default": "./lib/json-editor.js", 15 | "types": "./lib/json-editor.d.ts" 16 | }, 17 | "./css": "./lib/json-editor.css", 18 | "./umd": "./lib/json-editor.umd.cjs" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/redgoose-dev/json-editor.git" 23 | }, 24 | "bugs": { 25 | "url": "https://github.com/redgoose-dev/json-editor/issues" 26 | }, 27 | "homepage": "https://redgoose-dev.github.io/json-editor", 28 | "type": "module", 29 | "scripts": { 30 | "dev": "vite --config vite.config/dev.js", 31 | "docs": "vite --config vite.config/docs.js", 32 | "prebuild": "rm -rf docs && rm -rf lib", 33 | "build": "node vite.config/lib.js" 34 | }, 35 | "browserslist": [ 36 | "> 1%", 37 | "last 2 versions" 38 | ], 39 | "engines": { 40 | "node": ">=20" 41 | }, 42 | "devDependencies": { 43 | "@sveltejs/vite-plugin-svelte": "^3.1.1", 44 | "cash-dom": "^8.1.5", 45 | "feather-icons": "^4.29.2", 46 | "sass": "^1.77.5", 47 | "svelte": "^4.2.18", 48 | "vite": "^5.3.1" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/dev/assets/global.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --dev-color-bg: hsl(200 5% 92%); 3 | --dev-color-base: hsl(0 0% 10%); 4 | --dev-color-key: hsl(175 92% 40%); 5 | --dev-color-white: hsl(0 0% 100%); 6 | --font-base: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; 7 | --font-code: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 8 | color-scheme: light; 9 | } 10 | 11 | html, body { 12 | -webkit-text-size-adjust: none; 13 | box-sizing: border-box; 14 | text-size-adjust: none; 15 | } 16 | html { 17 | touch-action: manipulation; 18 | } 19 | body { 20 | margin: 0; 21 | padding: 0 42px; 22 | background: var(--dev-color-bg); 23 | font-size: 16px; 24 | line-height: 1.62; 25 | color: var(--dev-color-base); 26 | box-sizing: border-box; 27 | } 28 | body, button { 29 | font-family: var(--font-base); 30 | } 31 | a { 32 | color: var(--dev-color-key); 33 | } 34 | ::selection { 35 | background: var(--dev-color-key); 36 | color: hsl(0 0% 100%); 37 | } 38 | -------------------------------------------------------------------------------- /src/dev/assets/resource.js: -------------------------------------------------------------------------------- 1 | export const sampleStudent = { 2 | "id": 12345, 3 | "name": "Alice Kim", 4 | "age": 20, 5 | "major": "Computer Science", 6 | "email": "alice.kim@example.com", 7 | "phone": "010-1234-5678", 8 | "graduatedA": true, 9 | "graduatedB": false 10 | } 11 | 12 | export const sampleMovie = { 13 | "title": "Inception", 14 | "director": "Christopher Nolan", 15 | "releaseYear": 2010, 16 | "genre": "Sci-Fi", 17 | "rating": 8.8, 18 | "duration": 148, 19 | "mainActor": "Leonardo DiCaprio" 20 | } 21 | 22 | export const sampleCompany = { 23 | "name": "TechCorp", 24 | "location": "Seoul", 25 | "established": 2005, 26 | "CEO": "James Lee", 27 | "employees": 500, 28 | "industry": "IT", 29 | "stockPrice": 250.5 30 | } 31 | 32 | export const sampleCats = [ 33 | { 34 | "name": "Mew", 35 | "color": "white", 36 | "age": 3, 37 | "human": true, 38 | "hobbies": ["chasing toys", "sleeping", "purring"] 39 | }, 40 | { 41 | "name": "Whiskers", 42 | "color": "gray", 43 | "age": 5, 44 | "human": false, 45 | "hobbies": ["climbing", "watching birds", "playing with Mew"] 46 | } 47 | ] 48 | 49 | export const sampleBooks = [ 50 | { 51 | "title": "The Tale of Two Kitties", 52 | "author": "Furry Feline", 53 | "publishedYear": 2020, 54 | "genres": ["adventure", "comedy"] 55 | }, 56 | { 57 | "title": "Paws & Whiskers", 58 | "author": "Miaow L. Purr", 59 | "publishedYear": 2019, 60 | "genres": ["drama", "slice of life"] 61 | } 62 | ] 63 | 64 | export const samples = [ 65 | sampleStudent, 66 | sampleMovie, 67 | sampleCompany, 68 | sampleCats, 69 | sampleBooks, 70 | ] 71 | -------------------------------------------------------------------------------- /src/dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @json-editor / development 7 | 8 | 9 | 10 |
        11 |
        12 |

        json-editor / #DEV

        13 | 28 |
        29 |
        30 |
        31 |
        32 |

        Editor

        33 |
        34 |
        35 |
        36 |
        37 |
        38 |

        Preview

        39 |
        40 |
        
        41 |     
        42 |
        43 |
        44 | 45 | 46 | -------------------------------------------------------------------------------- /src/dev/main.js: -------------------------------------------------------------------------------- 1 | import JsonEditor from '../json-editor/exports.js' 2 | import { samples } from './assets/resource.js' 3 | import { randomPickInArray } from './util.js' 4 | 5 | import '../json-editor/assets/main.scss' 6 | import './main.scss' 7 | 8 | let $ 9 | let options = { 10 | theme: 'system', 11 | live: true, 12 | edit: 'all', // all,value,none 13 | } 14 | const lang = {} 15 | const gnb = document.getElementById('gnb') 16 | const container = document.querySelector('.container') 17 | const editor = document.getElementById('editor') 18 | const preview = document.getElementById('preview') 19 | 20 | // set language 21 | JsonEditor.prototype.updateLanguage = function() 22 | { 23 | this.lang = Object.assign(this.lang, { 24 | nodeChangeSort: '노드 순서변경', 25 | nodeContextMenu: '노드메뉴', 26 | nodeFold: '접기/펼치기', 27 | contextChangeType: '타입변경', 28 | contextInsertNode: '노드추가', 29 | contextTypeObject: '객체', 30 | contextTypeArray: '배열', 31 | contextTypeString: '문자', 32 | contextTypeNumber: '번호', 33 | contextTypeBoolean: '부울', 34 | contextTypeNull: '널', 35 | contextDuplicate: '노드복제', 36 | contextRemove: '노드삭제', 37 | }) 38 | } 39 | 40 | // set json-editor 41 | window.jsonEditor = new JsonEditor(editor, { 42 | theme: options.theme, 43 | live: options.live, 44 | edit: options.edit, 45 | openDepth: 3, 46 | node: {}, 47 | }) 48 | $ = window.$ = jsonEditor.$ 49 | initJsonEditor() 50 | 51 | // setup menu 52 | initMenu() 53 | 54 | function onUpdateJsonEditor({ detail }) 55 | { 56 | renderPreview(detail) 57 | } 58 | 59 | function initMenu() 60 | { 61 | // set theme 62 | changeTheme(options.theme) 63 | // set button events 64 | $(gnb).find('button').on('click', onClickMenu) 65 | } 66 | 67 | function initJsonEditor() 68 | { 69 | editor.addEventListener('update', onUpdateJsonEditor) 70 | randomReplaceSampleItem() 71 | } 72 | 73 | function onClickMenu(e) 74 | { 75 | const { action } = e.currentTarget.dataset 76 | switch (action) 77 | { 78 | case 'theme-system': 79 | case 'theme-light': 80 | case 'theme-dark': 81 | changeTheme(action.replace(/^theme-/, '')) 82 | break 83 | case 'clear': 84 | jsonEditor.clear() 85 | break 86 | case 'random-pick': 87 | randomReplaceSampleItem() 88 | break 89 | case 'export': 90 | const result = jsonEditor.export(undefined, false, 2) 91 | console.group('<= EXPORT JSON =>') 92 | console.log(result) 93 | console.groupEnd() 94 | break 95 | case 'preview': 96 | visiblePreview() 97 | break 98 | } 99 | } 100 | 101 | function changeTheme(value) 102 | { 103 | if (!['system', 'light', 'dark'].includes(value)) return 104 | const $themeButtons = $(gnb).find('[data-action^=theme]') 105 | $themeButtons.prop('disabled', false) 106 | $themeButtons.filter(`[data-action^=theme-${value}]`).prop('disabled', true) 107 | jsonEditor.options.theme = value 108 | 109 | editor.parentElement.classList.remove('editor--system', 'editor--light', 'editor--dark') 110 | editor.parentElement.classList.add(`editor--${value}`) 111 | } 112 | 113 | function visiblePreview(sw) 114 | { 115 | if (sw === undefined) 116 | { 117 | container.classList.toggle('hide-preview') 118 | } 119 | else if (sw) 120 | { 121 | container.classList.remove('hide-preview') 122 | } 123 | else 124 | { 125 | container.classList.add('hide-preview') 126 | } 127 | } 128 | 129 | function randomReplaceSampleItem() 130 | { 131 | jsonEditor.replace(randomPickInArray(samples), { 132 | openDepth: 2, 133 | }, true) 134 | } 135 | 136 | function renderPreview(src) 137 | { 138 | preview.innerText = JSON.stringify(src, null, 2) 139 | } 140 | -------------------------------------------------------------------------------- /src/dev/main.scss: -------------------------------------------------------------------------------- 1 | @import './assets/global'; 2 | 3 | .layout { 4 | margin: 0 auto; 5 | max-width: 1400px; 6 | } 7 | 8 | .header { 9 | text-align: center; 10 | padding: 36px 0 0 0; 11 | &__title { 12 | margin: 0; 13 | color: var(--dev-color-base); 14 | font-size: 32px; 15 | letter-spacing: -1px; 16 | text-transform: uppercase; 17 | font-weight: 900; 18 | line-height: 1.05; 19 | user-select: none; 20 | } 21 | &__gnb { 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | gap: 4px 6px; 26 | margin: 12px 0 0; 27 | menu { 28 | margin: 0; 29 | padding: 0; 30 | list-style: none; 31 | display: flex; 32 | align-items: center; 33 | justify-content: center; 34 | gap: 4px 1px; 35 | } 36 | li {} 37 | button { 38 | display: block; 39 | margin: 0; 40 | padding: 0 12px; 41 | height: 28px; 42 | background: var(--dev-color-key); 43 | font-size: 14px; 44 | line-height: 1; 45 | color: var(--dev-color-white); 46 | border: none; 47 | cursor: pointer; 48 | font-weight: 600; 49 | &:active { 50 | opacity: .5; 51 | } 52 | &:disabled { 53 | opacity: .5; 54 | cursor: default; 55 | } 56 | } 57 | } 58 | } 59 | 60 | .container { 61 | display: grid; 62 | grid-template-columns: 1fr 1fr; 63 | margin: 42px 0 0; 64 | gap: 16px; 65 | &.hide-preview { 66 | grid-template-columns: 1fr; 67 | .preview { 68 | display: none; 69 | } 70 | } 71 | } 72 | 73 | .editor { 74 | --dev-editor-color-bg: #fff; 75 | background: var(--dev-editor-color-bg); 76 | @media (prefers-color-scheme: dark) { 77 | --dev-editor-color-bg: #222; 78 | } 79 | &--light { 80 | --dev-editor-color-bg: #fff; 81 | } 82 | &--dark { 83 | --dev-editor-color-bg: #333; 84 | } 85 | &__header { 86 | background: var(--dev-color-key); 87 | } 88 | &__body { 89 | min-height: 120px; 90 | padding: 24px; 91 | box-sizing: border-box; 92 | } 93 | } 94 | 95 | .preview { 96 | background: var(--dev-color-white); 97 | &__header { 98 | background: hsl(0 0% 24%); 99 | } 100 | &__body { 101 | min-height: 120px; 102 | padding: 24px; 103 | box-sizing: border-box; 104 | margin: 0; 105 | font-size: 12px; 106 | font-family: var(--font-code); 107 | line-height: 1.6; 108 | } 109 | } 110 | 111 | .editor, 112 | .preview { 113 | border-radius: 2px; 114 | box-shadow: 115 | 0 4.5px 3.6px rgba(0, 0, 0, 0.042), 116 | 0 12.5px 10px rgba(0, 0, 0, 0.06), 117 | 0 30.1px 24.1px rgba(0, 0, 0, 0.078), 118 | 0 100px 80px rgba(0, 0, 0, 0.12); 119 | } 120 | 121 | .content-header { 122 | margin: 0; 123 | border-top-left-radius: 2px; 124 | border-top-right-radius: 2px; 125 | h1 { 126 | margin: 0; 127 | padding: 4px 0 4px 8px; 128 | font-size: 12px; 129 | font-weight: 700; 130 | color: var(--dev-color-white); 131 | line-height: 1; 132 | user-select: none; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/dev/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * random pick in array 3 | * @param {array} arr 4 | * @return {any} 5 | */ 6 | export function randomPickInArray(arr = []) 7 | { 8 | return arr[Math.floor(Math.random() * arr.length)] 9 | } 10 | -------------------------------------------------------------------------------- /src/docs/app.scss: -------------------------------------------------------------------------------- 1 | @use './assets/scss/mixins'; 2 | 3 | .layout { 4 | display: grid; 5 | grid-template-areas: var(--layout-areas, 'header' 'editor'); 6 | grid-template-columns: var(--layout-columns, 1fr); 7 | grid-template-rows: var(--layout-rows, var(--layout-header-height) 1fr); 8 | box-sizing: border-box; 9 | &__header { 10 | grid-area: header; 11 | position: sticky; 12 | top: 0; 13 | z-index: 10; 14 | } 15 | &__editor { 16 | grid-area: editor; 17 | } 18 | &__preview { 19 | grid-area: preview; 20 | --preview-width: 45vw; 21 | --preview-max-width: 640px; 22 | width: var(--preview-width); 23 | max-width: var(--preview-max-width); 24 | } 25 | &--preview { 26 | --layout-areas: 'header header' 'editor preview'; 27 | --layout-columns: 1fr auto; 28 | .layout { 29 | &__preview {} 30 | } 31 | } 32 | @include mixins.responsive(mobile) { 33 | --layout-areas: 'header' 'editor'; 34 | --layout-columns: 1fr; 35 | --layout-rows: unset; 36 | &__preview { 37 | display: none; 38 | } 39 | } 40 | } 41 | 42 | .modal-data { 43 | --modal-width: 720px; 44 | --modal-height: 540px; 45 | } 46 | .modal-about { 47 | --modal-width: 640px; 48 | --modal-height: 600px; 49 | } 50 | -------------------------------------------------------------------------------- /src/docs/app.svelte: -------------------------------------------------------------------------------- 1 |
        4 |
        5 |
        6 |
        7 |
        8 | 12 |
        13 | {#if $visiblePreview} 14 |
        15 | 16 |
        17 | {/if} 18 |
        19 | 20 | {#if dataImport.visible} 21 | 31 | {/if} 32 | 33 | {#if dataExport.visible} 34 | 43 | {/if} 44 | 45 | {#if $visibleAbout} 46 | 53 | {/if} 54 | 55 | 182 | 183 | 186 | -------------------------------------------------------------------------------- /src/docs/assets/scss/main.scss: -------------------------------------------------------------------------------- 1 | @use 'mixins'; 2 | @import 'normalize'; 3 | 4 | :root { 5 | --color-bg-hsl: 0 0% 100%; 6 | --color-base-hsl: 0 0% 13.5%; 7 | --color-key-hsl: 168 82% 42%; 8 | --color-blur-hsl: 0 0% 52%; 9 | --color-invert-hsl: 0 0% 100%; 10 | --color-bg: hsl(var(--color-bg-hsl)); 11 | --color-base: hsl(var(--color-base-hsl)); 12 | --color-key: hsl(var(--color-key-hsl)); 13 | --color-blur: hsl(var(--color-blur-hsl)); 14 | --color-invert: hsl(var(--color-invert-hsl)); 15 | --font-base: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; 16 | --font-code: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 17 | --layout-header-height: 44px; 18 | --layout-min-width: 640px; 19 | color-scheme: light; 20 | @include mixins.dark-mode('root') { 21 | color-scheme: dark; 22 | --color-bg-hsl: 0 0% 13%; 23 | --color-base-hsl: 0 0% 94%; 24 | --color-key-hsl: 172 92% 40%; 25 | --color-blur-hsl: 0 0% 64%; 26 | --color-invert-hsl: 0 0% 0%; 27 | } 28 | } 29 | 30 | html, body { 31 | -webkit-text-size-adjust: none; 32 | box-sizing: border-box; 33 | text-size-adjust: none; 34 | } 35 | html { 36 | touch-action: manipulation; 37 | &.transition-theme { 38 | * { 39 | transition: background-color 160ms ease-out; 40 | } 41 | } 42 | } 43 | body { 44 | margin: 0; 45 | min-width: var(--layout-min-width); 46 | background: var(--color-bg); 47 | font-size: 16px; 48 | line-height: 1.52; 49 | color: var(--color-base); 50 | box-sizing: border-box; 51 | } 52 | body, button, input, textarea, select { 53 | font-family: var(--font-base); 54 | } 55 | main { 56 | box-sizing: border-box; 57 | } 58 | a { 59 | color: var(--color-key); 60 | } 61 | ::selection { 62 | background: var(--color-key); 63 | color: hsl(0 0% 100%); 64 | } 65 | 66 | .opened-modal { 67 | overflow: hidden; 68 | body { 69 | overflow: hidden; 70 | } 71 | } 72 | 73 | .scroll-area { 74 | overflow: auto; 75 | --scroll-size: 15px; 76 | --scroll-padding: 5px; 77 | --scroll-track: hsl(0 0% 65%); 78 | --scroll-track-hover: hsl(0 0% 45%); 79 | --scroll-bg: hsla(0 0% 100% / 0%); 80 | &::-webkit-scrollbar { 81 | width: var(--scroll-size); 82 | } 83 | &::-webkit-scrollbar-thumb { 84 | border: var(--scroll-padding) solid hsla(0 0% 100% / 0%); 85 | background-clip: padding-box; 86 | border-radius: 9999px; 87 | background-color: var(--scroll-track); 88 | &:hover { 89 | background-color: var(--scroll-track-hover); 90 | } 91 | } 92 | &::-webkit-scrollbar-track { 93 | background: var(--scroll-bg); 94 | } 95 | @include mixins.dark-mode('global') { 96 | --scroll-track: hsl(0 0% 72%); 97 | --scroll-track-hover: hsl(0 0% 52%); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/docs/assets/scss/mixins.scss: -------------------------------------------------------------------------------- 1 | // dark mode 2 | @mixin dark-mode($mode: '') 3 | { 4 | @if ($mode == 'root') 5 | { 6 | &[data-theme=dark] { 7 | @content; 8 | } 9 | &[data-theme=system], 10 | &:not([data-theme]), 11 | &[data-theme=""] { 12 | @media (prefers-color-scheme: dark) { 13 | @content; 14 | } 15 | } 16 | } 17 | @else if ($mode == 'global') 18 | { 19 | html[data-theme=dark] & { 20 | @content; 21 | } 22 | @media (prefers-color-scheme: dark) { 23 | html[data-theme=system] &, 24 | html:not([data-theme]) &, 25 | html[data-theme=""] & { 26 | @content; 27 | } 28 | } 29 | } 30 | @else 31 | { 32 | :global(html[data-theme=dark]) { 33 | & { 34 | @content; 35 | } 36 | } 37 | @media (prefers-color-scheme: dark) { 38 | :global(html[data-theme=system]), 39 | :global(html:not([data-theme])), 40 | :global(html[data-theme=""]) { 41 | & { 42 | @content; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | // background blur 50 | @mixin background-blur($size: 8px) 51 | { 52 | @supports (backdrop-filter: blur(#{$size})) or (-webkit-backdrop-filter: blur(#{$size})) { 53 | backdrop-filter: blur(#{$size}); 54 | -webkit-backdrop-filter: blur(#{$size}); 55 | @content; 56 | } 57 | } 58 | 59 | // hover 60 | @mixin hover() 61 | { 62 | @media (hover: hover) { 63 | &:hover { 64 | @content; 65 | } 66 | } 67 | } 68 | 69 | // responsive 70 | @mixin responsive($range) 71 | { 72 | @if ($range == mobile) { @media (max-width: 768px) { @content; } } 73 | //@else if ($range == desktop) { @media (min-width: 1024px) { @content; } } 74 | //@else if ($range == desktop-large) { @media (min-width: 1440px) { @content; } } 75 | } 76 | -------------------------------------------------------------------------------- /src/docs/assets/scss/normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | overflow: auto; 263 | } 264 | 265 | /** 266 | * 1. Add the correct box sizing in IE 10. 267 | * 2. Remove the padding in IE 10. 268 | */ 269 | 270 | [type="checkbox"], 271 | [type="radio"] { 272 | box-sizing: border-box; /* 1 */ 273 | padding: 0; /* 2 */ 274 | } 275 | 276 | /** 277 | * Correct the cursor style of increment and decrement buttons in Chrome. 278 | */ 279 | 280 | [type="number"]::-webkit-inner-spin-button, 281 | [type="number"]::-webkit-outer-spin-button { 282 | height: auto; 283 | } 284 | 285 | /** 286 | * 1. Correct the odd appearance in Chrome and Safari. 287 | * 2. Correct the outline style in Safari. 288 | */ 289 | 290 | [type="search"] { 291 | -webkit-appearance: textfield; /* 1 */ 292 | outline-offset: -2px; /* 2 */ 293 | } 294 | 295 | /** 296 | * Remove the inner padding in Chrome and Safari on macOS. 297 | */ 298 | 299 | [type="search"]::-webkit-search-decoration { 300 | -webkit-appearance: none; 301 | } 302 | 303 | /** 304 | * 1. Correct the inability to style clickable types in iOS and Safari. 305 | * 2. Change font properties to `inherit` in Safari. 306 | */ 307 | 308 | ::-webkit-file-upload-button { 309 | -webkit-appearance: button; /* 1 */ 310 | font: inherit; /* 2 */ 311 | } 312 | 313 | /* Interactive 314 | ========================================================================== */ 315 | 316 | /* 317 | * Add the correct display in Edge, IE 10+, and Firefox. 318 | */ 319 | 320 | details { 321 | display: block; 322 | } 323 | 324 | /* 325 | * Add the correct display in all browsers. 326 | */ 327 | 328 | summary { 329 | display: list-item; 330 | } 331 | 332 | /* Misc 333 | ========================================================================== */ 334 | 335 | /** 336 | * Add the correct display in IE 10+. 337 | */ 338 | 339 | template { 340 | display: none; 341 | } 342 | 343 | /** 344 | * Add the correct display in IE 10. 345 | */ 346 | 347 | [hidden] { 348 | display: none; 349 | } -------------------------------------------------------------------------------- /src/docs/components/about/index.scss: -------------------------------------------------------------------------------- 1 | @use '../../assets/scss/mixins'; 2 | 3 | .about { 4 | display: grid; 5 | place-content: center; 6 | height: 100%; 7 | &__wrap { 8 | padding: 60px; 9 | box-sizing: border-box; 10 | } 11 | &__logo { 12 | display: grid; 13 | gap: 32px; 14 | place-content: center; 15 | margin: 0; 16 | .symbol { 17 | display: block; 18 | width: 150px; 19 | margin: 0 auto; 20 | --logo-symbol-wdith: 100%; 21 | } 22 | .label { 23 | display: block; 24 | width: 240px; 25 | margin: 0 auto; 26 | --logo-label-wdith: 100%; 27 | } 28 | } 29 | &__description { 30 | margin: 54px 0 0; 31 | font-size: 15px; 32 | line-height: 1.42; 33 | } 34 | &__information {} 35 | @include mixins.responsive(mobile) { 36 | &__wrap { 37 | padding: 32px; 38 | max-width: 540px; 39 | } 40 | &__logo { 41 | gap: 24px; 42 | .symbol { 43 | width: 100px; 44 | } 45 | .label { 46 | width: 180px; 47 | } 48 | } 49 | } 50 | } 51 | 52 | .information { 53 | margin: 30px 0 0; 54 | h2 { 55 | margin: 0; 56 | font-size: 18px; 57 | line-height: 1.15; 58 | } 59 | ul { 60 | display: grid; 61 | gap: 2px; 62 | margin: 12px 0 0; 63 | padding: 0 0 0 16px; 64 | font-size: 13px; 65 | line-height: 1.42; 66 | } 67 | } 68 | @include mixins.dark-mode() { 69 | .information { 70 | ul { 71 | li {} 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/docs/components/about/index.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 | 28 | 29 | 32 | -------------------------------------------------------------------------------- /src/docs/components/assets/button.scss: -------------------------------------------------------------------------------- 1 | @use '../../assets/scss/mixins'; 2 | 3 | .button { 4 | display: flex; 5 | align-items: center; 6 | gap: 4px; 7 | width: auto; 8 | height: 36px; 9 | user-select: none; 10 | white-space: nowrap; 11 | box-sizing: border-box; 12 | font-size: 14px; 13 | line-height: 1.15; 14 | color: hsl(0 0% 100%); 15 | margin: 0; 16 | padding: 0 16px; 17 | border: none; 18 | cursor: pointer; 19 | border-radius: 2px; 20 | background-color: hsl(0 0% 52%); 21 | box-shadow: var(--button-outline), var(--button-focus); 22 | transition: box-shadow 120ms ease-out; 23 | -webkit-tap-highlight-color: transparent; 24 | --button-outline: 0 0 0 0 hsla(var(--color-base-hsl) / 0%); 25 | --button-focus: 0 0 0 0 hsla(var(--color-key-hsl) / 0%); 26 | --icon-size: 16px; 27 | --icon-color: hsl(0 0% 100%); 28 | --icon-margin: 0 0 0 -2px; 29 | @include mixins.hover() { 30 | --button-outline: 0 0 0 1px hsla(var(--color-base-hsl) / 25%); 31 | } 32 | &:active { 33 | --button-outline: 0 0 0 1px hsla(var(--color-base-hsl) / 75%); 34 | } 35 | &:focus-visible { 36 | outline: none; 37 | --button-outline: 0 0 0 1px hsla(var(--color-base-hsl) / 75%); 38 | --button-focus: 0 0 0 5px hsla(var(--color-base-hsl) / 20%); 39 | } 40 | &:disabled { 41 | opacity: .5; 42 | cursor: not-allowed; 43 | @include mixins.hover() { 44 | --button-outline: 0 0 0 0; 45 | } 46 | } 47 | &--color { 48 | &-key { 49 | background-color: var(--color-key); 50 | } 51 | } 52 | } 53 | @include mixins.dark-mode() { 54 | .button { 55 | background-color: hsl(0 0% 52%); 56 | &--color { 57 | &-key { 58 | background-color: var(--color-key); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/docs/components/assets/button.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 23 | 24 | -------------------------------------------------------------------------------- /src/docs/components/assets/icon.svelte: -------------------------------------------------------------------------------- 1 | {#if name} 2 | 12 | 13 | 14 | {/if} 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /src/docs/components/assets/logo-label.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /src/docs/components/assets/logo-symbol.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 29 | -------------------------------------------------------------------------------- /src/docs/components/data/common.scss: -------------------------------------------------------------------------------- 1 | @use '../../assets/scss/mixins'; 2 | 3 | .data { 4 | height: 100%; 5 | &__wrap { 6 | display: grid; 7 | grid-template-rows: auto 1fr; 8 | height: 100%; 9 | padding: 30px; 10 | box-sizing: border-box; 11 | } 12 | &__header { 13 | h1 { 14 | margin: 0; 15 | font-size: 24px; 16 | line-height: 1.15; 17 | letter-spacing: -.5px; 18 | font-weight: 700; 19 | color: var(--color-base); 20 | } 21 | p { 22 | margin: 6px 0 0; 23 | font-size: 13px; 24 | line-height: 1.25; 25 | color: hsl(0 0% 52%); 26 | } 27 | } 28 | } 29 | @include mixins.dark-mode() { 30 | .data { 31 | &__header { 32 | p { 33 | color: hsl(0 0% 64%); 34 | } 35 | } 36 | } 37 | } 38 | 39 | .form { 40 | display: grid; 41 | grid-template-rows: 1fr auto; 42 | margin: 16px 0 0; 43 | } 44 | 45 | .source-input { 46 | display: flex; 47 | flex-direction: column; 48 | border: none; 49 | margin: 0; 50 | padding: 0; 51 | legend { 52 | position: absolute; 53 | font-size: 0; 54 | } 55 | textarea { 56 | flex: 1; 57 | display: block; 58 | width: 100%; 59 | height: 100%; 60 | border-radius: 2px; 61 | background: hsl(0 0% 96%); 62 | border: none; 63 | box-sizing: border-box; 64 | margin: 0; 65 | padding: 16px; 66 | font-size: 14px; 67 | line-height: 1.42; 68 | resize: none; 69 | appearance: none; 70 | box-shadow: 71 | var(--source-code-shadow, (0 4px 12px 0 hsla(0 0% 0% / 15%) inset)), 72 | var(--source-code-border, (0 0 0 1px hsla(0 0% 0% / 25%) inset)), 73 | var(--source-code-focus, (0 0 0 3px hsla(var(--color-key-hsl) / 0%))); 74 | transition: box-shadow 120ms ease-out; 75 | &:focus-visible { 76 | outline: none; 77 | --source-code-focus: 0 0 0 3px hsla(var(--color-key-hsl) / 100%); 78 | } 79 | } 80 | } 81 | @include mixins.dark-mode() { 82 | .source-input { 83 | textarea { 84 | background: hsl(0 0% 12%); 85 | --source-code-border: 0 0 0 1px hsla(0 0% 100% / 12%) inset; 86 | } 87 | } 88 | } 89 | 90 | .help-message { 91 | --color-fill: hsl(0 82% 48%); 92 | display: grid; 93 | grid-template-columns: auto 1fr; 94 | align-items: center; 95 | gap: 6px; 96 | margin: 8px 0 0; 97 | user-select: none; 98 | --icon-size: 16px; 99 | --icon-color: var(--color-fill); 100 | --icon-stroke: 2; 101 | p { 102 | margin: 0; 103 | color: var(--color-fill); 104 | font-size: 12px; 105 | } 106 | } 107 | 108 | .source-result { 109 | margin: 16px 0 0; 110 | border-radius: 2px; 111 | background: hsl(0 0% 100%); 112 | box-shadow: 113 | var(--source-shadow, (0 4px 32px 0 hsla(0 0% 0% / 10%) inset)), 114 | var(--source-focus, (0 0 0 1px hsla(0 0% 0% / 20%) inset)); 115 | box-sizing: border-box; 116 | pre { 117 | margin: 0; 118 | min-height: 100%; 119 | padding: 16px; 120 | font-size: 11px; 121 | font-weight: 400; 122 | line-height: 1.62; 123 | font-family: var(--font-code); 124 | box-sizing: border-box; 125 | word-break: break-all; 126 | white-space: break-spaces; 127 | } 128 | } 129 | @include mixins.dark-mode() { 130 | .source-result { 131 | background: hsl(0 0% 24%); 132 | box-shadow: 133 | var(--source-shadow, (0 4px 32px 0 hsla(0 0% 0% / 30%) inset)), 134 | var(--source-focus, (0 0 0 1px hsla(0 0% 100% / 10%) inset)); 135 | } 136 | } 137 | 138 | .select-code-style { 139 | display: block; 140 | position: relative; 141 | background: hsl(0 0% 96%); 142 | box-shadow: 143 | var(--selct-code-style-border, (0 0 0 1px hsla(0 0% 0% / 25%) inset)), 144 | var(--selct-code-style-shadow, (0 4px 12px 0 hsla(0 0% 0% / 15%) inset)), 145 | var(--selct-code-style-focus, (0 0 0 3px hsla(var(--color-key-hsl) / 0%))); 146 | border-radius: 2px; 147 | transition: box-shadow 120ms ease-out; 148 | &:focus-within { 149 | --selct-code-style-focus: 0 0 0 3px hsla(var(--color-key-hsl) / 100%); 150 | select { 151 | outline: none; 152 | } 153 | } 154 | select { 155 | display: block; 156 | margin: 0; 157 | padding: 0 36px 0 16px; 158 | height: 36px; 159 | appearance: none; 160 | border: none; 161 | background: none; 162 | font-size: 14px; 163 | color: var(--color-base); 164 | } 165 | i { 166 | position: absolute; 167 | right: 12px; 168 | top: 50%; 169 | transform: translateY(-50%); 170 | display: block; 171 | --icon-size: 16px; 172 | pointer-events: none; 173 | } 174 | } 175 | @include mixins.dark-mode() { 176 | .select-code-style { 177 | background: hsl(0 0% 12%); 178 | } 179 | } 180 | 181 | .nav-submit { 182 | display: grid; 183 | grid-template-columns: 1fr auto; 184 | align-items: center; 185 | margin: 16px 0 0; 186 | > div { 187 | display: flex; 188 | align-items: center; 189 | justify-content: flex-start; 190 | gap: 8px; 191 | } 192 | } 193 | 194 | .json-uploader { 195 | &__file { 196 | display: none; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/docs/components/data/export.svelte: -------------------------------------------------------------------------------- 1 |
        2 |
        3 |
        4 |

        {$_language.exportTitle}

        5 |

        {@html $_language.exportDescription}

        6 |
        7 |
        8 |
        {_source}
        9 |
        10 | 38 |
        39 |
        40 | 41 | 80 | 81 | 84 | -------------------------------------------------------------------------------- /src/docs/components/data/import.svelte: -------------------------------------------------------------------------------- 1 |
        2 |
        3 |
        4 |

        {$_language.importTitle}

        5 |

        {@html $_language.importDescription}

        6 |
        7 |
        10 |
        11 | source code field 12 |