json-diff-viewer-component 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,10 +18,10 @@
18
18
 
19
19
  ## Features
20
20
 
21
- - Deep nested JSON comparison
21
+ - Nested JSON comparison
22
22
  - Side-by-side synchronized scrolling
23
23
  - Collapsible nodes (synced between panels)
24
- - Diff indicators bubble up to parent nodes
24
+ - Diff indicators roll up to parent nodes
25
25
  - Stats summary (added/removed/modified)
26
26
  - Show only changed filter toggle
27
27
  - Syntax highlighting
@@ -36,7 +36,7 @@ npm i json-diff-viewer-component
36
36
 
37
37
  ## Usage
38
38
 
39
- ### ES Module
39
+ Import the package to register the `<json-diff-viewer>` custom element, then call `setData()` with both JSON values:
40
40
 
41
41
  ```js
42
42
  import "json-diff-viewer-component";
@@ -45,8 +45,16 @@ const viewer = document.querySelector("json-diff-viewer");
45
45
  viewer.setData(leftObj, rightObj);
46
46
  ```
47
47
 
48
+ For testing or extension, the class is also exported:
49
+
50
+ ```js
51
+ import { JsonDiffViewer } from "json-diff-viewer-component";
52
+ ```
53
+
48
54
  ### HTML Attributes
49
55
 
56
+ Static JSON can be passed as attributes. Values must be valid JSON strings:
57
+
50
58
  ```html
51
59
  <json-diff-viewer
52
60
  left='{"name":"foo"}'
@@ -54,18 +62,28 @@ viewer.setData(leftObj, rightObj);
54
62
  ></json-diff-viewer>
55
63
  ```
56
64
 
65
+ - `JSON.parse` parses attribute values. Invalid JSON throws at parse time.
66
+ - Prefer `setData()` or property setters for dynamic or object data
67
+
57
68
  ### Properties
58
69
 
70
+ Set `left` and `right` as JavaScript values. Set both before the viewer draws a diff:
71
+
59
72
  ```js
60
73
  viewer.left = { name: "foo" };
61
74
  viewer.right = { name: "bar" };
75
+
76
+ viewer.left; // read current left value
77
+ viewer.right; // read current right value
62
78
  ```
63
79
 
64
- ### Method
80
+ ### Built-in Controls
65
81
 
66
- ```js
67
- viewer.setData(leftObj, rightObj);
68
- ```
82
+ The component toolbar includes:
83
+
84
+ - **Show only changed**: filter toggle (default: **on**); hides unchanged nodes
85
+ - **Collapse all** / **Expand all**: bulk expand/collapse
86
+ - **Node toggles**: click any object/array line to expand/collapse (synced across both panels)
69
87
 
70
88
  <details>
71
89
  <summary>Framework Examples</summary>
@@ -131,7 +149,7 @@ watch(
131
149
 
132
150
  ## Styling
133
151
 
134
- Customize the component by overriding CSS custom properties (design tokens) on the `json-diff-viewer` element. All tokens are defined on `:host` and can be overridden from outside the shadow DOM.
152
+ Override CSS custom properties (design tokens) on `json-diff-viewer`. Tokens live on `:host`; you set them from outside the shadow DOM.
135
153
 
136
154
  ### Design Tokens
137
155
 
@@ -170,21 +188,27 @@ Create your own theme by overriding these tokens. For example, a light theme:
170
188
 
171
189
  ```css
172
190
  json-diff-viewer {
173
- --bg: #fafafa;
174
- --bg2: #ffffff;
175
- --bdr: #e4e4e7;
176
- --txt: #18181b;
177
- --dim: #71717a;
178
- --key: #0284c7;
179
- --str: #7c3aed;
180
- --num: #059669;
181
- /* ... override other tokens as needed */
191
+ --add: #15803d;
192
+ --rem: #b91c1c;
193
+ --mod: #ca8a04;
194
+ --bg: #f4f4f4;
195
+ --bg2: #f9fafb;
196
+ --bdr: #d1d5db;
197
+ --txt: #030712;
198
+ --dim: #4b5563;
199
+ --slider: #d1d5db;
200
+ --key: #075985;
201
+ --str: #6d28d9;
202
+ --num: #047857;
203
+ --bool: #b45309;
204
+ --nul: #a21caf;
205
+ --br: #6b7280;
182
206
  }
183
207
  ```
184
208
 
185
209
  ### Sizing
186
210
 
187
- The component requires a defined height to enable scrolling. Without a height, the component will expand to fit all content.
211
+ Set a height to get scrolling. Without one, the viewer grows to fit all content. Default border-radius is `12px`.
188
212
 
189
213
  ```css
190
214
  json-diff-viewer {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-diff-viewer-component",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "type": "module",
5
5
  "description": "Vanilla JS web component for side-by-side JSON diff visualization",
6
6
  "bugs": "https://github.com/metaory/json-diff-viewer-component/issues",
@@ -30,6 +30,6 @@
30
30
  },
31
31
  "devDependencies": {
32
32
  "@fontsource/bungee": "^5.2.7",
33
- "vite": "^7.2.4"
33
+ "vite": "^8.0.16"
34
34
  }
35
35
  }
package/src/lib/viewer.js CHANGED
@@ -2,6 +2,8 @@ import { diff, TYPE } from "./diff.js";
2
2
  import styles from "./styles.js";
3
3
 
4
4
  const STAT_TYPES = ["added", "removed", "modified"];
5
+ const ENTITIES = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
6
+ const escapeHtml = (value) => String(value).replace(/[&<>"']/g, (char) => ENTITIES[char]);
5
7
 
6
8
  const format = (val) => {
7
9
  if (val === null) return ["null", "null"];
@@ -20,7 +22,7 @@ const filterChildren = (children, showOnlyChanged) =>
20
22
  const isExpanded = (proxy, path) => proxy[path] !== false;
21
23
 
22
24
  const buildKeyHtml = (key, root, hidden = false) =>
23
- root ? "" : `<span class="key"${hidden ? ' style="visibility: hidden;"' : ""}>${key}</span><span class="colon"${hidden ? ' style="visibility: hidden;"' : ""}>:</span>`;
25
+ root ? "" : `<span class="key"${hidden ? ' style="visibility: hidden;"' : ""}>${escapeHtml(key)}</span><span class="colon"${hidden ? ' style="visibility: hidden;"' : ""}>:</span>`;
24
26
 
25
27
  const buildRootClass = (root) => root ? " root" : "";
26
28
 
@@ -100,7 +102,7 @@ class JsonDiffViewer extends HTMLElement {
100
102
  }
101
103
 
102
104
  #compute() {
103
- if (!this.#left || !this.#right) return;
105
+ if (this.#left == null || this.#right == null) return;
104
106
  this.#tree = diff(this.#left, this.#right);
105
107
  this.#stats = collectStats(this.#tree);
106
108
  Object.keys(this.#exp).forEach((k) => {
@@ -182,18 +184,18 @@ class JsonDiffViewer extends HTMLElement {
182
184
  const otherValue = side === 'left' ? node.right : node.left;
183
185
  const [val, type] = format(otherValue);
184
186
  const hiddenKey = buildKeyHtml(node.key, root, true);
185
- return `<div class="node${rootClass}"><div class="line placeholder">${hiddenKey}<span class="val-${type}" style="visibility: hidden;">${val}</span></div></div>`;
187
+ return `<div class="node${rootClass}"><div class="line placeholder">${hiddenKey}<span class="val-${type}" style="visibility: hidden;">${escapeHtml(val)}</span></div></div>`;
186
188
  }
187
189
 
188
190
  if (value !== undefined && !node.isArray && !node.isObject) {
189
191
  const [val, type] = format(value);
190
192
  if (placeholder) {
191
- return `<div class="node${rootClass}"><div class="line placeholder">${keyHtml}<span class="val-${type}"${hidden}>${val}</span></div></div>`;
193
+ return `<div class="node${rootClass}"><div class="line placeholder">${keyHtml}<span class="val-${type}"${hidden}>${escapeHtml(val)}</span></div></div>`;
192
194
  }
193
195
  const hasDiff = node.hasDiff && node.type !== TYPE.UNCHANGED;
194
196
  const diffClass = hasDiff ? `diff-${node.type}` : "";
195
197
  const nodeDiffClass = hasDiff ? ` ${diffClass}` : "";
196
- return `<div class="node${rootClass}${nodeDiffClass}"><div class="line"><span class="tog"></span>${keyHtml}<span class="val-${type}">${val}</span></div></div>`;
198
+ return `<div class="node${rootClass}${nodeDiffClass}"><div class="line"><span class="tog"></span>${keyHtml}<span class="val-${type}">${escapeHtml(val)}</span></div></div>`;
197
199
  }
198
200
 
199
201
  const [open, close] = getBrackets(node.isArray);
@@ -219,7 +221,7 @@ class JsonDiffViewer extends HTMLElement {
219
221
  const dot = hasChildDiff ? `<span class="dot dot-${dotType}"></span>` : "";
220
222
  const nodeDiffClass = hasDiff && !hasChildDiff ? ` ${diffClass}` : "";
221
223
  const toggle = expanded ? "▼" : "▶";
222
- const dataPath = ` data-p="${currentPath}"`;
224
+ const dataPath = ` data-p="${escapeHtml(currentPath)}"`;
223
225
 
224
226
  if (!expanded) {
225
227
  return `<div class="node${rootClass}${nodeDiffClass}"><div class="line"${dataPath}><span class="tog">${toggle}</span>${dot}${keyHtml}<span class="br">${open}</span><span class="preview">${preview}</span><span class="br">${close}</span></div></div>`;