@humanspeak/svelte-json-view-lite 0.1.0 → 0.1.2

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
@@ -5,6 +5,18 @@ Fast, tiny JSON tree viewer for Svelte 5 — a port of
5
5
  (MIT © 2024 AnyRoad) with runes, SSR, per-type snippet overrides, and zero
6
6
  runtime dependencies.
7
7
 
8
+ [![NPM version](https://img.shields.io/npm/v/@humanspeak/svelte-json-view-lite.svg)](https://www.npmjs.com/package/@humanspeak/svelte-json-view-lite)
9
+ [![Build Status](https://github.com/humanspeak/svelte-json-view-lite/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/humanspeak/svelte-json-view-lite/actions/workflows/npm-publish.yml)
10
+ [![Coverage Status](https://coveralls.io/repos/github/humanspeak/svelte-json-view-lite/badge.svg?branch=main)](https://coveralls.io/github/humanspeak/svelte-json-view-lite?branch=main)
11
+ [![License](https://img.shields.io/npm/l/@humanspeak/svelte-json-view-lite.svg)](https://github.com/humanspeak/svelte-json-view-lite/blob/main/LICENSE)
12
+ [![Downloads](https://img.shields.io/npm/dm/@humanspeak/svelte-json-view-lite.svg)](https://www.npmjs.com/package/@humanspeak/svelte-json-view-lite)
13
+ [![CodeQL](https://github.com/humanspeak/svelte-json-view-lite/actions/workflows/codeql.yml/badge.svg)](https://github.com/humanspeak/svelte-json-view-lite/actions/workflows/codeql.yml)
14
+ [![Install size](https://packagephobia.com/badge?p=@humanspeak/svelte-json-view-lite)](https://packagephobia.com/result?p=@humanspeak/svelte-json-view-lite)
15
+ [![Code Style: Trunk](https://img.shields.io/badge/code%20style-trunk-blue.svg)](https://trunk.io)
16
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
17
+ [![Types](https://img.shields.io/npm/types/@humanspeak/svelte-json-view-lite.svg)](https://www.npmjs.com/package/@humanspeak/svelte-json-view-lite)
18
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/humanspeak/svelte-json-view-lite/graphs/commit-activity)
19
+
8
20
  ## Features
9
21
 
10
22
  - Svelte 5 runes throughout (`$props`, `$state`, `$derived`, `$effect`).
@@ -83,6 +95,65 @@ Override individual slots by spreading:
83
95
  />
84
96
  ```
85
97
 
98
+ ## Retheme via CSS variables
99
+
100
+ Every color in the built-in themes is declared as a CSS custom property
101
+ on the root container, so you can tweak one or more colors without
102
+ swapping the entire `style` prop or bringing your own classname map.
103
+ The variables all live under the `--sjv-*` namespace:
104
+
105
+ | Variable | Default (light) | Default (dark) | Applies to |
106
+ | ------------------- | ------------------ | -------------------- | ------------------------------------------ |
107
+ | `--sjv-background` | `#eee` | `rgb(0, 43, 54)` | Root container background |
108
+ | `--sjv-label` | `#000000` | `rgb(253, 246, 227)` | Field label text |
109
+ | `--sjv-punctuation` | `#000000` | `rgb(253, 246, 227)` | Brackets, colons, commas |
110
+ | `--sjv-string` | `rgb(42, 63, 60)` | `rgb(203, 75, 22)` | String values |
111
+ | `--sjv-number` | `#0b75f5` | `rgb(211, 54, 130)` | Number & BigInt values |
112
+ | `--sjv-boolean` | `rgb(70, 144, 56)` | `rgb(174, 129, 255)` | Boolean values |
113
+ | `--sjv-null` | `#df113a` | `rgb(129, 181, 172)` | `null` literal |
114
+ | `--sjv-undefined` | `#df113a` | `rgb(129, 181, 172)` | `undefined` literal |
115
+ | `--sjv-other` | `#43413d` | `rgb(38, 139, 210)` | Dates, functions, symbols, etc. |
116
+ | `--sjv-expander` | `#000000` | `rgb(253, 246, 227)` | `▸` / `▾` icons and collapsed `...` marker |
117
+
118
+ **Global override** — applies to every `JsonView` on the page:
119
+
120
+ ```css
121
+ :root {
122
+ --sjv-string: lavender;
123
+ --sjv-number: #ff71ce;
124
+ }
125
+ ```
126
+
127
+ **Scoped override** — target one component (or a subtree):
128
+
129
+ ```svelte
130
+ <div class="vaporwave">
131
+ <JsonView {data} style={defaultStyles} />
132
+ </div>
133
+
134
+ <style>
135
+ .vaporwave :global(div[role='tree']) {
136
+ --sjv-background: #2b1055;
137
+ --sjv-string: #01cdfe;
138
+ --sjv-number: #05ffa1;
139
+ --sjv-boolean: #b967ff;
140
+ }
141
+ </style>
142
+ ```
143
+
144
+ **Per-instance override** — forward inline styles via the root div (ARIA
145
+ attrs and `style` on `<JsonView>` are spread onto the wrapper):
146
+
147
+ ```svelte
148
+ <JsonView {data} style={defaultStyles} style:--sjv-number="tomato" />
149
+ ```
150
+
151
+ All three patterns work with either `defaultStyles` or `darkStyles` —
152
+ the variables are defined on both container classes with theme-specific
153
+ fallback defaults, so one override applies to whichever theme is active.
154
+
155
+ See the `/test/css-variables` playground route for a live example.
156
+
86
157
  ## Snippet overrides
87
158
 
88
159
  Unlike the React lib, `svelte-json-view-lite` exposes typed `Snippet`
@@ -183,5 +254,9 @@ pnpm build # vite build + svelte-package + publint
183
254
 
184
255
  ## License
185
256
 
186
- MIT. Copyright © 2024-2026 Humanspeak, Inc. Original
187
- `react-json-view-lite` © 2024 AnyRoad.
257
+ MIT © [Humanspeak, Inc.](LICENSE) Original `react-json-view-lite`
258
+ © 2024 AnyRoad.
259
+
260
+ ## Credits
261
+
262
+ Made with ❤️ by [Humanspeak](https://humanspeak.com)
@@ -4,9 +4,8 @@
4
4
  import type { JsonRenderProps } from './types.js'
5
5
  import { isArray, isDate, isFunction, isObject } from './utils/dataTypeDetection.js'
6
6
 
7
- // Declared as constants because Svelte markup parses `"{"` as an
8
- // expression opener, and eslint's no-useless-mustaches objects to
9
- // `{'{'}` inline.
7
+ // Svelte parses `"{"` as an expression opener; stashing the braces as
8
+ // constants avoids the parse error and the no-useless-mustaches lint.
10
9
  const OBJECT_OPEN = '{'
11
10
  const OBJECT_CLOSE = '}'
12
11
 
@@ -16,13 +15,26 @@
16
15
  // Array check first — arrays are also objects, so order matters.
17
16
  const isArr = $derived(isArray(value))
18
17
  const isObj = $derived(isObject(value) && !isDate(value) && !isFunction(value))
18
+
19
+ // Derive the children tuple array from `value` so ExpandableObject
20
+ // receives a stable reference while `value` is unchanged — otherwise
21
+ // a fresh array identity on every parent tick invalidates the
22
+ // {#each} key and cascades re-renders down the tree.
23
+ const children = $derived.by<Array<[string | undefined, unknown]>>(() => {
24
+ if (isArr) return (value as unknown[]).map((el) => [undefined, el])
25
+ if (isObj) {
26
+ const obj = value as Record<string, unknown>
27
+ return Object.keys(obj).map((k) => [k, obj[k]])
28
+ }
29
+ return []
30
+ })
19
31
  </script>
20
32
 
21
33
  {#if isArr}
22
34
  <ExpandableObject
23
35
  {...props}
24
36
  value={value as unknown[]}
25
- data={(value as unknown[]).map((el) => [undefined, el])}
37
+ data={children}
26
38
  openBracket="["
27
39
  closeBracket="]"
28
40
  />
@@ -30,7 +42,7 @@
30
42
  <ExpandableObject
31
43
  {...props}
32
44
  value={value as object}
33
- data={Object.keys(value as object).map((k) => [k, (value as Record<string, unknown>)[k]])}
45
+ data={children}
34
46
  openBracket={OBJECT_OPEN}
35
47
  closeBracket={OBJECT_CLOSE}
36
48
  />
@@ -20,16 +20,14 @@
20
20
  snippets
21
21
  }: ExpandableRenderProps = $props()
22
22
 
23
- // Lazy init runs once on mount (react useState(() => ...) equivalent).
23
+ // Initial expand state captured once on mount; the effect below
24
+ // re-runs only when the callback identity changes so level/value/
25
+ // field mutations from ancestor re-renders don't collapse the node.
24
26
  // svelte-ignore state_referenced_locally
25
27
  let expanded = $state(shouldExpandNode(level, value, field))
26
28
 
27
- // React's useRef<boolean>: plain mutable local.
28
29
  let shouldExpandNodeCalled = false
29
30
 
30
- // Match React useEffect(fn, [shouldExpandNode]) — fire only when the
31
- // callback identity changes. We intentionally avoid reading level/value/
32
- // field so an ancestor re-render doesn't trigger a respectful collapse.
33
31
  $effect(() => {
34
32
  const fn = shouldExpandNode
35
33
  if (!shouldExpandNodeCalled) {
@@ -39,10 +37,9 @@
39
37
  expanded = fn(level, value, field)
40
38
  })
41
39
 
42
- // SSR-stable unique id for aria-controls linkage (React.useId equivalent).
40
+ // SSR-stable id for aria-controls linkage.
43
41
  const contentsId = $props.id()
44
42
 
45
- // bind:this target for focus management.
46
43
  let expanderButton = $state<HTMLSpanElement | null>(null)
47
44
 
48
45
  const activeAriaLabels = $derived<AriaLabels>(
@@ -18,80 +18,131 @@
18
18
  const hasField = $derived(field !== undefined)
19
19
  const labelText = $derived(quoteString(field ?? '', style.quotesForFieldNames))
20
20
 
21
+ type ValueKind =
22
+ | 'null'
23
+ | 'undefined'
24
+ | 'string'
25
+ | 'boolean'
26
+ | 'number'
27
+ | 'bigint'
28
+ | 'date'
29
+ | 'function'
30
+ | 'other'
31
+
32
+ // A single predicate walk picks the discriminant; `rendered`, the
33
+ // snippet lookup, and the template all key off `kind` so the 8-way
34
+ // type ladder is evaluated once per render instead of three times.
35
+ const kind = $derived.by<ValueKind>(() => {
36
+ if (value === null) return 'null'
37
+ if (value === undefined) return 'undefined'
38
+ if (isString(value)) return 'string'
39
+ if (isBoolean(value)) return 'boolean'
40
+ if (isNumber(value)) return 'number'
41
+ if (isBigInt(value)) return 'bigint'
42
+ if (isDate(value)) return 'date'
43
+ if (isFunction(value)) return 'function'
44
+ return 'other'
45
+ })
46
+
21
47
  type Rendered = { text: string; valueStyle: string }
22
48
  const rendered = $derived.by<Rendered>(() => {
23
- if (value === null) return { text: 'null', valueStyle: style.nullValue }
24
- if (value === undefined) return { text: 'undefined', valueStyle: style.undefinedValue }
25
- if (isString(value))
26
- return {
27
- text: quoteStringValue(
28
- value,
29
- !style.noQuotesForStringValues,
30
- style.stringifyStringValues
31
- ),
32
- valueStyle: style.stringValue
33
- }
34
- if (isBoolean(value))
35
- return { text: value ? 'true' : 'false', valueStyle: style.booleanValue }
36
- if (isNumber(value)) return { text: value.toString(), valueStyle: style.numberValue }
37
- if (isBigInt(value)) return { text: `${value.toString()}n`, valueStyle: style.numberValue }
38
- if (isDate(value)) return { text: value.toISOString(), valueStyle: style.otherValue }
39
- if (isFunction(value)) return { text: 'function() { }', valueStyle: style.otherValue }
40
- return { text: String(value), valueStyle: style.otherValue }
49
+ switch (kind) {
50
+ case 'null':
51
+ return { text: 'null', valueStyle: style.nullValue }
52
+ case 'undefined':
53
+ return { text: 'undefined', valueStyle: style.undefinedValue }
54
+ case 'string':
55
+ return {
56
+ text: quoteStringValue(
57
+ value as string,
58
+ !style.noQuotesForStringValues,
59
+ style.stringifyStringValues
60
+ ),
61
+ valueStyle: style.stringValue
62
+ }
63
+ case 'boolean':
64
+ return {
65
+ text: (value as boolean) ? 'true' : 'false',
66
+ valueStyle: style.booleanValue
67
+ }
68
+ case 'number':
69
+ return { text: String(value), valueStyle: style.numberValue }
70
+ case 'bigint':
71
+ return {
72
+ text: `${(value as bigint).toString()}n`,
73
+ valueStyle: style.numberValue
74
+ }
75
+ case 'date':
76
+ return { text: (value as Date).toISOString(), valueStyle: style.otherValue }
77
+ case 'function':
78
+ return { text: 'function() { }', valueStyle: style.otherValue }
79
+ default:
80
+ return { text: String(value), valueStyle: style.otherValue }
81
+ }
41
82
  })
42
83
 
43
- const snippetForValue = $derived.by(() => {
44
- if (value === null) return snippets.null
45
- if (value === undefined) return snippets.undefined
46
- if (isString(value)) return snippets.string
47
- if (isBoolean(value)) return snippets.boolean
48
- if (isNumber(value)) return snippets.number
49
- if (isBigInt(value)) return snippets.bigint
50
- if (isDate(value)) return snippets.date
51
- if (isFunction(value)) return snippets.function
52
- return undefined
84
+ const activeSnippet = $derived.by(() => {
85
+ switch (kind) {
86
+ case 'null':
87
+ return snippets.null
88
+ case 'undefined':
89
+ return snippets.undefined
90
+ case 'string':
91
+ return snippets.string
92
+ case 'boolean':
93
+ return snippets.boolean
94
+ case 'number':
95
+ return snippets.number
96
+ case 'bigint':
97
+ return snippets.bigint
98
+ case 'date':
99
+ return snippets.date
100
+ case 'function':
101
+ return snippets.function
102
+ default:
103
+ return undefined
104
+ }
53
105
  })
54
106
  </script>
55
107
 
56
108
  <!--
57
109
  The entire row body lives on a single prettier-ignored line because Svelte
58
- preserves template whitespace between adjacent elements (e.g. between the
59
- label span and the value span, or between the value and the trailing
60
- comma). Those whitespace text nodes render as visible spaces under the
61
- container's `white-space: pre-wrap`. React/JSX strips that whitespace
62
- natively; we have to hand-collapse it. Every margin we need is provided
63
- by the CSS module (e.g. `.label { margin-right: 5px; }`).
110
+ preserves template whitespace between adjacent elements as visible spaces
111
+ under the container's `white-space: pre-wrap`. React/JSX strips that
112
+ whitespace natively; we hand-collapse it. Per-type snippet branches key
113
+ off `kind` rather than re-running predicates.
64
114
  -->
65
115
  <div class={style.basicChildStyle} role="treeitem" aria-selected={false}>
66
116
  <!-- prettier-ignore -->
67
- {#if hasField}{#if snippets.label}{@render snippets.label({ field: field ?? '', level })}{:else}<span class={style.label}>{labelText}:</span>{/if}{/if}{#if snippetForValue && value === null}{@render snippets.null?.(
117
+ {#if hasField}{#if snippets.label}{@render snippets.label({ field: field ?? '', level })}{:else}<span class={style.label}>{labelText}:</span>{/if}{/if}{#if activeSnippet && kind === 'null'}{@render snippets.null?.(
68
118
  { value: null, field, level }
69
- )}{:else if snippetForValue && value === undefined}{@render snippets.undefined?.({
119
+ )}{:else if activeSnippet && kind === 'undefined'}{@render snippets.undefined?.({
70
120
  value: undefined,
71
121
  field,
72
122
  level
73
- })}{:else if snippetForValue && isString(value)}{@render snippets.string?.({
74
- value,
123
+ })}{:else if activeSnippet && kind === 'string'}{@render snippets.string?.({
124
+ value: value as string,
75
125
  field,
76
126
  level
77
- })}{:else if snippetForValue && isBoolean(value)}{@render snippets.boolean?.({
78
- value,
127
+ })}{:else if activeSnippet && kind === 'boolean'}{@render snippets.boolean?.({
128
+ value: value as boolean,
79
129
  field,
80
130
  level
81
- })}{:else if snippetForValue && isNumber(value)}{@render snippets.number?.({
82
- value,
131
+ })}{:else if activeSnippet && kind === 'number'}{@render snippets.number?.({
132
+ value: value as number,
83
133
  field,
84
134
  level
85
- })}{:else if snippetForValue && isBigInt(value)}{@render snippets.bigint?.({
86
- value,
135
+ })}{:else if activeSnippet && kind === 'bigint'}{@render snippets.bigint?.({
136
+ value: value as bigint,
87
137
  field,
88
138
  level
89
- })}{:else if snippetForValue && isDate(value)}{@render snippets.date?.({
90
- value,
139
+ })}{:else if activeSnippet && kind === 'date'}{@render snippets.date?.({
140
+ value: value as Date,
91
141
  field,
92
142
  level
93
- })}{:else if snippetForValue && isFunction(value)}{@render snippets.function?.({
94
- value,
143
+ })}{:else if activeSnippet && kind === 'function'}{@render snippets.function?.({
144
+ // trunk-ignore(eslint/@typescript-eslint/no-unsafe-function-type)
145
+ value: value as Function,
95
146
  field,
96
147
  level
97
148
  })}{:else}<span class={rendered.valueStyle}>{rendered.text}</span
package/dist/index.d.ts CHANGED
@@ -5,9 +5,9 @@ export type { AriaLabels, BigIntSnippetProps, BooleanSnippetProps, DateSnippetPr
5
5
  export { allExpanded, collapseAllNested } from './utils/expandStrategies.js';
6
6
  export { JsonView };
7
7
  /**
8
- * Correctly-spelled default aria labels. Introduced in the Svelte port;
9
- * prefer this over the typoed `StyleProps.ariaLables` shipped by
10
- * `react-json-view-lite`.
8
+ * Correctly-spelled default aria labels (new in the Svelte port; prefer
9
+ * this over the typoed `StyleProps.ariaLables` shipped by
10
+ * `react-json-view-lite`).
11
11
  */
12
12
  export declare const defaultAriaLabels: AriaLabels;
13
13
  export declare const defaultStyles: StyleProps;
package/dist/index.js CHANGED
@@ -3,16 +3,15 @@ import styles from './styles.module.css';
3
3
  export default JsonView;
4
4
  export { allExpanded, collapseAllNested } from './utils/expandStrategies.js';
5
5
  export { JsonView };
6
- const baseAriaLabels = {
6
+ /**
7
+ * Correctly-spelled default aria labels (new in the Svelte port; prefer
8
+ * this over the typoed `StyleProps.ariaLables` shipped by
9
+ * `react-json-view-lite`).
10
+ */
11
+ export const defaultAriaLabels = {
7
12
  collapseJson: 'collapse JSON',
8
13
  expandJson: 'expand JSON'
9
14
  };
10
- /**
11
- * Correctly-spelled default aria labels. Introduced in the Svelte port;
12
- * prefer this over the typoed `StyleProps.ariaLables` shipped by
13
- * `react-json-view-lite`.
14
- */
15
- export const defaultAriaLabels = baseAriaLabels;
16
15
  const buildStyles = (variant) => ({
17
16
  container: styles[`container-${variant}`],
18
17
  basicChildStyle: styles['basic-element-style'],
@@ -31,7 +30,7 @@ const buildStyles = (variant) => ({
31
30
  collapsedContent: styles[`collapsed-content-${variant}`],
32
31
  noQuotesForStringValues: false,
33
32
  quotesForFieldNames: false,
34
- ariaLabels: baseAriaLabels,
33
+ ariaLabels: defaultAriaLabels,
35
34
  stringifyStringValues: false
36
35
  });
37
36
  export const defaultStyles = buildStyles('light');
@@ -1,4 +1,6 @@
1
- /* base styles */
1
+ /*
2
+ * Base styles shared across themes.
3
+ */
2
4
 
3
5
  .container-base {
4
6
  line-height: 1.2;
@@ -47,11 +49,6 @@
47
49
  font-size: 0.8em;
48
50
  }
49
51
 
50
- .container-light {
51
- composes: container-base;
52
- background: #eee;
53
- }
54
-
55
52
  .basic-element-style {
56
53
  margin: 0;
57
54
  padding: 0 10px;
@@ -62,11 +59,35 @@
62
59
  padding: 0;
63
60
  }
64
61
 
65
- /* default light style */
62
+ /*
63
+ * Light theme.
64
+ *
65
+ * Every color is declared as a CSS custom property (`--sjv-*`) on the
66
+ * container so consumers can override individual colors either globally
67
+ * (`:root { --sjv-string: lavender }`) or scoped to one instance
68
+ * (`.my-json-view { --sjv-number: #f0f }`). Descendant selectors read
69
+ * the vars via `var(--sjv-*)` — no fallback is needed because the
70
+ * container always defines the defaults.
71
+ */
72
+ .container-light {
73
+ composes: container-base;
74
+ --sjv-background: #eee;
75
+ --sjv-label: #000000;
76
+ --sjv-punctuation: #000000;
77
+ --sjv-null: #df113a;
78
+ --sjv-undefined: #df113a;
79
+ --sjv-string: rgb(42, 63, 60);
80
+ --sjv-number: #0b75f5;
81
+ --sjv-boolean: rgb(70, 144, 56);
82
+ --sjv-other: #43413d;
83
+ --sjv-expander: #000000;
84
+ background: var(--sjv-background);
85
+ }
86
+
66
87
  .label-light {
67
88
  font-weight: 600;
68
89
  margin-right: 5px;
69
- color: #000000;
90
+ color: var(--sjv-label);
70
91
  }
71
92
 
72
93
  .clickable-label-light {
@@ -76,77 +97,74 @@
76
97
 
77
98
  .punctuation-light {
78
99
  composes: punctuation-base;
79
- color: #000000;
100
+ color: var(--sjv-punctuation);
80
101
  }
81
102
 
82
103
  .value-null-light {
83
- color: #df113a;
104
+ color: var(--sjv-null);
84
105
  }
85
106
 
86
107
  .value-undefined-light {
87
- color: #df113a;
108
+ color: var(--sjv-undefined);
88
109
  }
89
110
 
90
111
  .value-string-light {
91
- color: rgb(42, 63, 60);
112
+ color: var(--sjv-string);
92
113
  }
93
114
 
94
115
  .value-number-light {
95
- color: #0b75f5;
116
+ color: var(--sjv-number);
96
117
  }
97
118
 
98
119
  .value-boolean-light {
99
- color: rgb(70, 144, 56);
120
+ color: var(--sjv-boolean);
100
121
  }
101
122
 
102
123
  .value-other-light {
103
- color: #43413d;
124
+ color: var(--sjv-other);
104
125
  }
105
126
 
106
127
  .collapse-icon-light {
107
128
  composes: expander-base;
108
129
  composes: collapse-icon;
109
- color: #000000;
130
+ color: var(--sjv-expander);
110
131
  }
111
132
 
112
133
  .expand-icon-light {
113
134
  composes: expander-base;
114
135
  composes: expand-icon;
115
- color: #000000;
136
+ color: var(--sjv-expander);
116
137
  }
117
138
 
118
139
  .collapsed-content-light {
119
140
  composes: collapsed-content-base;
120
- color: #000000;
141
+ color: var(--sjv-expander);
121
142
  }
122
143
 
123
- /* default dark style */
144
+ /*
145
+ * Dark theme. Same variable names, different defaults — so a consumer
146
+ * override like `:root { --sjv-string: lavender }` applies identically
147
+ * to light and dark instances.
148
+ */
124
149
  .container-dark {
125
- background: rgb(0, 43, 54);
126
150
  composes: container-base;
127
- }
128
-
129
- .expand-icon-dark {
130
- composes: expander-base;
131
- composes: expand-icon;
132
- color: rgb(253, 246, 227);
133
- }
134
-
135
- .collapse-icon-dark {
136
- composes: expander-base;
137
- composes: collapse-icon;
138
- color: rgb(253, 246, 227);
139
- }
140
-
141
- .collapsed-content-dark {
142
- composes: collapsed-content-base;
143
- color: rgb(253, 246, 227);
151
+ --sjv-background: rgb(0, 43, 54);
152
+ --sjv-label: rgb(253, 246, 227);
153
+ --sjv-punctuation: rgb(253, 246, 227);
154
+ --sjv-null: rgb(129, 181, 172);
155
+ --sjv-undefined: rgb(129, 181, 172);
156
+ --sjv-string: rgb(203, 75, 22);
157
+ --sjv-number: rgb(211, 54, 130);
158
+ --sjv-boolean: rgb(174, 129, 255);
159
+ --sjv-other: rgb(38, 139, 210);
160
+ --sjv-expander: rgb(253, 246, 227);
161
+ background: var(--sjv-background);
144
162
  }
145
163
 
146
164
  .label-dark {
147
165
  font-weight: bolder;
148
166
  margin-right: 5px;
149
- color: rgb(253, 246, 227);
167
+ color: var(--sjv-label);
150
168
  }
151
169
 
152
170
  .clickable-label-dark {
@@ -156,29 +174,46 @@
156
174
 
157
175
  .punctuation-dark {
158
176
  composes: punctuation-base;
159
- color: rgb(253, 246, 227);
177
+ color: var(--sjv-punctuation);
160
178
  }
161
179
 
162
180
  .value-null-dark {
163
- color: rgb(129, 181, 172);
181
+ color: var(--sjv-null);
164
182
  }
165
183
 
166
184
  .value-undefined-dark {
167
- color: rgb(129, 181, 172);
185
+ color: var(--sjv-undefined);
168
186
  }
169
187
 
170
188
  .value-string-dark {
171
- color: rgb(203, 75, 22);
189
+ color: var(--sjv-string);
172
190
  }
173
191
 
174
192
  .value-number-dark {
175
- color: rgb(211, 54, 130);
193
+ color: var(--sjv-number);
176
194
  }
177
195
 
178
196
  .value-boolean-dark {
179
- color: rgb(174, 129, 255);
197
+ color: var(--sjv-boolean);
180
198
  }
181
199
 
182
200
  .value-other-dark {
183
- color: rgb(38, 139, 210);
201
+ color: var(--sjv-other);
202
+ }
203
+
204
+ .expand-icon-dark {
205
+ composes: expander-base;
206
+ composes: expand-icon;
207
+ color: var(--sjv-expander);
208
+ }
209
+
210
+ .collapse-icon-dark {
211
+ composes: expander-base;
212
+ composes: collapse-icon;
213
+ color: var(--sjv-expander);
214
+ }
215
+
216
+ .collapsed-content-dark {
217
+ composes: collapsed-content-base;
218
+ color: var(--sjv-expander);
184
219
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humanspeak/svelte-json-view-lite",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Fast, tiny JSON tree viewer for Svelte 5 — port of react-json-view-lite with runes, SSR, snippet overrides, and zero runtime dependencies",
5
5
  "keywords": [
6
6
  "svelte",
@@ -55,39 +55,39 @@
55
55
  }
56
56
  },
57
57
  "devDependencies": {
58
- "@eslint/compat": "^2.0.5",
58
+ "@eslint/compat": "^2.1.0",
59
59
  "@eslint/js": "^10.0.1",
60
- "@playwright/test": "^1.59.1",
60
+ "@playwright/test": "^1.60.0",
61
61
  "@sveltejs/adapter-auto": "^7.0.1",
62
- "@sveltejs/kit": "^2.57.1",
62
+ "@sveltejs/kit": "^2.61.1",
63
63
  "@sveltejs/package": "^2.5.7",
64
- "@sveltejs/vite-plugin-svelte": "^7.0.0",
64
+ "@sveltejs/vite-plugin-svelte": "^7.1.2",
65
65
  "@testing-library/jest-dom": "^6.9.1",
66
66
  "@testing-library/svelte": "^5.3.1",
67
67
  "@testing-library/user-event": "^14.6.1",
68
- "@types/node": "^25.6.0",
69
- "@typescript-eslint/eslint-plugin": "^8.58.2",
70
- "@typescript-eslint/parser": "^8.58.2",
71
- "@vitest/coverage-v8": "^4.1.4",
72
- "eslint": "^10.2.1",
68
+ "@types/node": "^25.9.1",
69
+ "@typescript-eslint/eslint-plugin": "^8.60.0",
70
+ "@typescript-eslint/parser": "^8.60.0",
71
+ "@vitest/coverage-v8": "^4.1.7",
72
+ "eslint": "^10.4.0",
73
73
  "eslint-config-prettier": "^10.1.8",
74
74
  "eslint-plugin-import": "^2.32.0",
75
- "eslint-plugin-svelte": "^3.17.0",
75
+ "eslint-plugin-svelte": "^3.18.0",
76
76
  "eslint-plugin-unused-imports": "^4.4.1",
77
- "globals": "^17.5.0",
77
+ "globals": "^17.6.0",
78
78
  "husky": "^9.1.7",
79
- "jsdom": "^29.0.2",
80
- "mprocs": "^0.9.2",
79
+ "jsdom": "^29.1.1",
80
+ "mprocs": "^0.9.3",
81
81
  "prettier": "^3.8.3",
82
82
  "prettier-plugin-organize-imports": "^4.3.0",
83
- "prettier-plugin-svelte": "^3.5.1",
84
- "publint": "^0.3.18",
85
- "svelte": "^5.55.4",
86
- "svelte-check": "^4.4.6",
83
+ "prettier-plugin-svelte": "^4.0.1",
84
+ "publint": "^0.3.21",
85
+ "svelte": "^5.55.9",
86
+ "svelte-check": "^4.4.8",
87
87
  "typescript": "^6.0.3",
88
- "typescript-eslint": "^8.58.2",
89
- "vite": "^8.0.8",
90
- "vitest": "^4.1.4"
88
+ "typescript-eslint": "^8.60.0",
89
+ "vite": "^8.0.14",
90
+ "vitest": "^4.1.7"
91
91
  },
92
92
  "peerDependencies": {
93
93
  "svelte": "^5.0.0"
@@ -105,6 +105,7 @@
105
105
  ],
106
106
  "scripts": {
107
107
  "build": "vite build && npm run package",
108
+ "cf-typegen": "pnpm --filter docs cf-typegen",
108
109
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
109
110
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
110
111
  "dev": "vite dev",