@dbcdk/react-components 0.0.194 → 0.0.196

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.
Files changed (114) hide show
  1. package/README.md +78 -10
  2. package/dist/client.cjs +486 -614
  3. package/dist/client.d.ts +176 -102
  4. package/dist/client.js +102 -102
  5. package/dist/components/color-scheme-button/ColorSchemeButton.cjs +7 -4
  6. package/dist/components/color-scheme-button/ColorSchemeButton.d.ts +7 -3
  7. package/dist/components/color-scheme-button/ColorSchemeButton.js +7 -4
  8. package/dist/components/forms/text-area/Textarea.cjs +2 -1
  9. package/dist/components/forms/text-area/Textarea.d.ts +1 -0
  10. package/dist/components/forms/text-area/Textarea.js +2 -1
  11. package/dist/components/highlighted-text/HighlightedText.cjs +6 -3
  12. package/dist/components/highlighted-text/HighlightedText.js +7 -4
  13. package/dist/components/json-viewer/JsonNode.cjs +27 -67
  14. package/dist/components/json-viewer/JsonNode.d.ts +10 -0
  15. package/dist/components/json-viewer/JsonNode.js +28 -68
  16. package/dist/components/json-viewer/JsonRow.cjs +85 -0
  17. package/dist/components/json-viewer/JsonRow.d.ts +5 -0
  18. package/dist/components/json-viewer/JsonRow.js +79 -0
  19. package/dist/components/json-viewer/JsonViewer.cjs +36 -256
  20. package/dist/components/json-viewer/JsonViewer.js +37 -253
  21. package/dist/components/json-viewer/JsonViewerShell.cjs +208 -0
  22. package/dist/components/json-viewer/JsonViewerShell.d.ts +25 -0
  23. package/dist/components/json-viewer/JsonViewerShell.js +202 -0
  24. package/dist/components/json-viewer/TanstackJsonViewer.cjs +127 -0
  25. package/dist/components/json-viewer/TanstackJsonViewer.d.ts +17 -0
  26. package/dist/components/json-viewer/TanstackJsonViewer.js +121 -0
  27. package/dist/components/json-viewer/types.d.ts +27 -0
  28. package/dist/components/json-viewer/useJsonViewerState.cjs +111 -0
  29. package/dist/components/json-viewer/useJsonViewerState.d.ts +42 -0
  30. package/dist/components/json-viewer/useJsonViewerState.js +108 -0
  31. package/dist/components/json-viewer/utils.cjs +36 -0
  32. package/dist/components/json-viewer/utils.d.ts +21 -1
  33. package/dist/components/json-viewer/utils.js +35 -1
  34. package/dist/components/lightbox/Lightbox.cjs +2 -2
  35. package/dist/components/lightbox/Lightbox.d.ts +1 -1
  36. package/dist/components/lightbox/Lightbox.js +1 -1
  37. package/dist/components/line-viewer/LineViewer.cjs +2 -3
  38. package/dist/components/line-viewer/LineViewer.js +2 -3
  39. package/dist/components/line-viewer/tokenizeLineFormat.cjs +37 -17
  40. package/dist/components/line-viewer/tokenizeLineFormat.d.ts +5 -4
  41. package/dist/components/line-viewer/tokenizeLineFormat.js +37 -17
  42. package/dist/components/menu/Menu.cjs +3 -23
  43. package/dist/components/menu/Menu.js +3 -23
  44. package/dist/components/menu/Menu.module.css +4 -3
  45. package/dist/components/metric-tile/MetricTile.cjs +3 -2
  46. package/dist/components/metric-tile/MetricTile.js +2 -1
  47. package/dist/components/overlay/tooltip/Tooltip.cjs +7 -2
  48. package/dist/components/overlay/tooltip/Tooltip.d.ts +7 -1
  49. package/dist/components/overlay/tooltip/Tooltip.js +7 -2
  50. package/dist/components/overlay/tooltip/useTooltipTrigger.cjs +7 -1
  51. package/dist/components/overlay/tooltip/useTooltipTrigger.js +7 -1
  52. package/dist/components/page-layout/PageLayout.module.css +1 -1
  53. package/dist/components/table/Table.cjs +45 -16
  54. package/dist/components/table/Table.d.ts +1 -1
  55. package/dist/components/table/Table.js +47 -18
  56. package/dist/components/table/Table.module.css +135 -7
  57. package/dist/components/table/Table.types.d.ts +47 -1
  58. package/dist/components/table/TanstackTable.cjs +30 -2
  59. package/dist/components/table/TanstackTable.js +31 -3
  60. package/dist/components/table/components/TableBody.d.ts +1 -2
  61. package/dist/components/table/components/TableHeader.cjs +6 -4
  62. package/dist/components/table/components/TableHeader.d.ts +2 -1
  63. package/dist/components/table/components/TableHeader.js +6 -4
  64. package/dist/components/table/components/TableHeaderCell.cjs +5 -4
  65. package/dist/components/table/components/TableHeaderCell.d.ts +3 -1
  66. package/dist/components/table/components/TableHeaderCell.js +5 -4
  67. package/dist/components/table/components/TableRow.cjs +1 -1
  68. package/dist/components/table/components/TableRow.d.ts +1 -2
  69. package/dist/components/table/components/TableRow.js +1 -1
  70. package/dist/components/table/components/TableSkeletonBody.cjs +30 -0
  71. package/dist/components/table/components/TableSkeletonBody.d.ts +13 -0
  72. package/dist/components/table/components/TableSkeletonBody.js +24 -0
  73. package/dist/components/table/components/table-settings/TableHeaderSettings.cjs +28 -0
  74. package/dist/components/table/components/table-settings/TableHeaderSettings.d.ts +11 -0
  75. package/dist/components/table/components/table-settings/TableHeaderSettings.js +26 -0
  76. package/dist/components/table/components/table-settings/TableSettings.cjs +82 -32
  77. package/dist/components/table/components/table-settings/TableSettings.d.ts +14 -6
  78. package/dist/components/table/components/table-settings/TableSettings.js +84 -34
  79. package/dist/components/table/table.utils.cjs +2 -0
  80. package/dist/components/table/table.utils.d.ts +6 -0
  81. package/dist/components/table/table.utils.js +2 -1
  82. package/dist/components/table/tableSettings.utils.cjs +29 -0
  83. package/dist/components/table/tableSettings.utils.d.ts +9 -0
  84. package/dist/components/table/tableSettings.utils.js +24 -0
  85. package/dist/components/table/tanstackTable.utils.cjs +18 -0
  86. package/dist/components/table/tanstackTable.utils.js +19 -1
  87. package/dist/components/theme-button/ThemeButton.cjs +9 -4
  88. package/dist/components/theme-button/ThemeButton.d.ts +4 -2
  89. package/dist/components/theme-button/ThemeButton.js +9 -4
  90. package/dist/components/theme-script/ThemeScript.cjs +10 -4
  91. package/dist/components/theme-script/ThemeScript.d.ts +9 -1
  92. package/dist/components/theme-script/ThemeScript.js +10 -4
  93. package/dist/components/xml-viewer/XmlViewer.cjs +2 -3
  94. package/dist/components/xml-viewer/XmlViewer.js +2 -3
  95. package/dist/hooks/useColorScheme.cjs +18 -14
  96. package/dist/hooks/useColorScheme.d.ts +11 -1
  97. package/dist/hooks/useColorScheme.js +19 -15
  98. package/dist/hooks/useGetActiveTheme.cjs +4 -3
  99. package/dist/hooks/useGetActiveTheme.d.ts +7 -1
  100. package/dist/hooks/useGetActiveTheme.js +4 -3
  101. package/dist/hooks/useTableData.cjs +11 -7
  102. package/dist/hooks/useTableData.d.ts +8 -2
  103. package/dist/hooks/useTableData.js +11 -7
  104. package/dist/hooks/useTableSettings.cjs +25 -9
  105. package/dist/hooks/useTableSettings.d.ts +9 -6
  106. package/dist/hooks/useTableSettings.js +25 -9
  107. package/dist/hooks/useTheme.d.ts +6 -0
  108. package/dist/styles/styles.css +7 -3
  109. package/dist/styles/themes/dbc/colors.css +1 -1
  110. package/dist/styles.css +1 -476
  111. package/dist/tanstack-virtual.cjs +12 -0
  112. package/dist/tanstack-virtual.d.ts +1 -0
  113. package/dist/tanstack-virtual.js +1 -0
  114. package/package.json +13 -1
@@ -2,23 +2,10 @@
2
2
  'use strict';
3
3
 
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
- var lucideReact = require('lucide-react');
6
- var react = require('react');
7
- var Menu = require('../../components/menu/Menu');
8
- var Popover = require('../../components/popover/Popover');
9
- var usePersistentState = require('../../hooks/usePersistentState');
10
5
  var JsonNode = require('./JsonNode');
11
- var styles = require('./JsonViewer.module.css');
12
- var useClipboardStatus = require('./useClipboardStatus');
13
- var utils = require('./utils');
14
- var Button = require('../button/Button');
15
- var Icon = require('../icon/Icon');
6
+ var JsonViewerShell = require('./JsonViewerShell');
7
+ var useJsonViewerState = require('./useJsonViewerState');
16
8
 
17
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
18
-
19
- var styles__default = /*#__PURE__*/_interopDefault(styles);
20
-
21
- const COPY_ALL_ID = "__json-viewer-copy-all__";
22
9
  function JsonViewer({
23
10
  value,
24
11
  defaultExpandedDepth = 2,
@@ -35,249 +22,42 @@ function JsonViewer({
35
22
  storageKey,
36
23
  borderless = false
37
24
  }) {
38
- const [queryInput, setQueryInput] = react.useState("");
39
- const [query, setQuery] = react.useState("");
40
- const normalizedQuery = utils.normalizeSearch(query);
41
- const inputId = react.useId();
42
- const { copiedId, setCopiedId } = useClipboardStatus.useClipboardStatus();
43
- const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState.usePersistentState({
44
- initialValue: appearance,
45
- storageKey: storageKey ? `${storageKey}:appearance` : void 0,
46
- validate: (stored) => stored === "dark" || stored === "light"
47
- });
48
- const { value: viewMode, setValue: setViewMode } = usePersistentState.usePersistentState({
49
- initialValue: defaultViewMode,
50
- storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
51
- validate: (stored) => stored === "tree" || stored === "raw"
25
+ const state = useJsonViewerState.useJsonViewerState({
26
+ value,
27
+ defaultExpandedDepth,
28
+ expandAll,
29
+ defaultViewMode,
30
+ searchDebounceMs,
31
+ appearance,
32
+ storageKey
52
33
  });
53
- const handleToggleAppearance = () => {
54
- setCurrentAppearance((current) => current === "dark" ? "light" : "dark");
55
- };
56
- react.useEffect(() => {
57
- const timeoutId = window.setTimeout(() => {
58
- setQuery(queryInput);
59
- }, searchDebounceMs);
60
- return () => window.clearTimeout(timeoutId);
61
- }, [queryInput, searchDebounceMs]);
62
- const safeValue = react.useMemo(() => {
63
- if (utils.isJsonValue(value)) return value;
64
- return {
65
- unsupported: {
66
- besked: "Den angivne v\xE6rdi kan ikke vises som JSON",
67
- modtagetType: typeof value
68
- }
69
- };
70
- }, [value]);
71
- const matches = react.useMemo(
72
- () => normalizedQuery ? utils.collectSearchMatches(safeValue, normalizedQuery) : /* @__PURE__ */ new Map(),
73
- [normalizedQuery, safeValue]
74
- );
75
- const allExpandableNodeIds = react.useMemo(() => utils.collectExpandableNodeIds(safeValue), [safeValue]);
76
- const [expandedNodeIds, setExpandedNodeIds] = react.useState(
77
- () => new Set(utils.collectInitiallyExpandedNodeIds(safeValue, defaultExpandedDepth, expandAll))
78
- );
79
- const hasResults = normalizedQuery ? matches.size > 0 : true;
80
- const rawJson = react.useMemo(() => JSON.stringify(safeValue, null, 2), [safeValue]);
81
- const contentClassName = [
82
- viewMode === "raw" ? styles__default.default.rawPane : styles__default.default.treePane,
83
- deleted ? styles__default.default.deleted : ""
84
- ].filter(Boolean).join(" ");
85
- const handleCopy = async (nodeId, rawValue) => {
86
- try {
87
- await navigator.clipboard.writeText(rawValue);
88
- setCopiedId(nodeId);
89
- } catch {
90
- setCopiedId(null);
91
- }
92
- };
93
- const handleCopyAll = () => handleCopy(COPY_ALL_ID, rawJson);
94
- const handleExpandAll = () => {
95
- setExpandedNodeIds(new Set(allExpandableNodeIds));
96
- };
97
- const handleCollapseAll = () => {
98
- setExpandedNodeIds(/* @__PURE__ */ new Set());
99
- };
100
- const handleToggleNode = (nodeId) => {
101
- setExpandedNodeIds((current) => {
102
- const next = new Set(current);
103
- if (next.has(nodeId)) next.delete(nodeId);
104
- else next.add(nodeId);
105
- return next;
106
- });
107
- };
108
- return /* @__PURE__ */ jsxRuntime.jsxs(
109
- "section",
34
+ return /* @__PURE__ */ jsxRuntime.jsx(
35
+ JsonViewerShell.JsonViewerShell,
110
36
  {
111
- className: [styles__default.default.viewer, borderless ? styles__default.default.borderless : "", className].filter(Boolean).join(" "),
112
- "data-appearance": currentAppearance,
113
- children: [
114
- /* @__PURE__ */ jsxRuntime.jsxs(
115
- "div",
116
- {
117
- className: styles__default.default.toolbar,
118
- "data-surface": currentAppearance === "dark" ? "inverse" : void 0,
119
- children: [
120
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.toolbarTop, children: [
121
- viewMode === "tree" ? /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: styles__default.default.searchField, children: [
122
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: styles__default.default.searchIcon, "aria-hidden": "true" }),
123
- /* @__PURE__ */ jsxRuntime.jsx(
124
- "input",
125
- {
126
- id: inputId,
127
- type: "search",
128
- value: queryInput,
129
- onChange: (event) => setQueryInput(event.target.value),
130
- placeholder: searchPlaceholder,
131
- className: styles__default.default.searchInput
132
- }
133
- ),
134
- queryInput ? /* @__PURE__ */ jsxRuntime.jsx(
135
- "button",
136
- {
137
- type: "button",
138
- className: styles__default.default.clearButton,
139
- "aria-label": "Ryd s\xF8gning",
140
- onClick: () => {
141
- setQueryInput("");
142
- setQuery("");
143
- },
144
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": "true" })
145
- }
146
- ) : null
147
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
148
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.actions, children: /* @__PURE__ */ jsxRuntime.jsx(
149
- Popover.Popover,
150
- {
151
- matchTriggerWidth: false,
152
- minWidth: "200px",
153
- trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsxRuntime.jsx(
154
- Button.Button,
155
- {
156
- variant: "inline",
157
- "aria-label": "Flere handlinger",
158
- "aria-haspopup": "menu",
159
- "aria-expanded": isOpen ? true : false,
160
- onClick: toggle,
161
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { customIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, { "aria-hidden": "true" }) })
162
- }
163
- ),
164
- children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
165
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { disabled: viewMode === "raw" || Boolean(normalizedQuery), children: /* @__PURE__ */ jsxRuntime.jsxs(
166
- "button",
167
- {
168
- type: "button",
169
- onClick: () => {
170
- handleExpandAll();
171
- close();
172
- },
173
- children: [
174
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { "aria-hidden": "true" }),
175
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Fold alle ud" })
176
- ]
177
- }
178
- ) }),
179
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { disabled: viewMode === "raw" || Boolean(normalizedQuery), children: /* @__PURE__ */ jsxRuntime.jsxs(
180
- "button",
181
- {
182
- type: "button",
183
- onClick: () => {
184
- handleCollapseAll();
185
- close();
186
- },
187
- children: [
188
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { "aria-hidden": "true" }),
189
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Fold alle sammen" })
190
- ]
191
- }
192
- ) }),
193
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
194
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
195
- "button",
196
- {
197
- type: "button",
198
- onClick: () => {
199
- setViewMode((mode) => mode === "raw" ? "tree" : "raw");
200
- close();
201
- },
202
- children: [
203
- viewMode === "raw" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListTree, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Braces, { "aria-hidden": "true" }),
204
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: viewMode === "raw" ? "Vis tr\xE6" : "Vis raw" })
205
- ]
206
- }
207
- ) }),
208
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
209
- "button",
210
- {
211
- type: "button",
212
- onClick: () => {
213
- handleToggleAppearance();
214
- close();
215
- },
216
- children: [
217
- currentAppearance === "dark" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { "aria-hidden": "true" }),
218
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: currentAppearance === "dark" ? "Lys visning" : "M\xF8rk visning" })
219
- ]
220
- }
221
- ) }),
222
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
223
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
224
- "button",
225
- {
226
- type: "button",
227
- onClick: () => {
228
- handleCopyAll();
229
- close();
230
- },
231
- children: [
232
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardCopy, { "aria-hidden": "true" }),
233
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Kopi\xE9r JSON" })
234
- ]
235
- }
236
- ) })
237
- ] })
238
- }
239
- ) })
240
- ] }),
241
- helperText || viewMode === "tree" && normalizedQuery ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.metaRow, children: [
242
- helperText ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.helperText, children: helperText }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
243
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.statusText, children: viewMode === "tree" && normalizedQuery ? `${matches.size} matchende node${matches.size === 1 ? "" : "r"}` : "" })
244
- ] }) : null
245
- ]
246
- }
247
- ),
248
- viewMode === "raw" ? /* @__PURE__ */ jsxRuntime.jsx(
249
- "pre",
250
- {
251
- className: contentClassName,
252
- style: maxHeight !== void 0 ? { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight } : void 0,
253
- children: rawJson
254
- }
255
- ) : /* @__PURE__ */ jsxRuntime.jsx(
256
- "div",
257
- {
258
- className: contentClassName,
259
- role: "tree",
260
- "aria-label": "JSON-visning",
261
- style: maxHeight !== void 0 ? { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight } : void 0,
262
- children: hasResults ? /* @__PURE__ */ jsxRuntime.jsx(
263
- JsonNode.JsonNode,
264
- {
265
- keyName: void 0,
266
- path: [],
267
- value: safeValue,
268
- depth: 0,
269
- defaultExpandedDepth,
270
- query: normalizedQuery,
271
- matches,
272
- expandedNodeIds,
273
- onToggleNode: handleToggleNode,
274
- copiedId,
275
- onCopy: handleCopy
276
- }
277
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.emptyState, children: emptySearchText })
278
- }
279
- )
280
- ]
37
+ state,
38
+ helperText,
39
+ searchPlaceholder,
40
+ emptySearchText,
41
+ className,
42
+ maxHeight,
43
+ borderless,
44
+ deleted,
45
+ children: /* @__PURE__ */ jsxRuntime.jsx(
46
+ JsonNode.JsonNode,
47
+ {
48
+ keyName: void 0,
49
+ path: [],
50
+ value: state.safeValue,
51
+ depth: 0,
52
+ defaultExpandedDepth,
53
+ query: state.normalizedQuery,
54
+ matches: state.matches,
55
+ expandedNodeIds: state.expandedNodeIds,
56
+ onToggleNode: state.handleToggleNode,
57
+ copiedId: state.copiedId,
58
+ onCopy: state.handleCopy
59
+ }
60
+ )
281
61
  }
282
62
  );
283
63
  }
@@ -1,18 +1,9 @@
1
1
  'use client';
2
- import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { Search, X, ArrowDown, ArrowUp, ListTree, Braces, Sun, Moon, ClipboardCopy, Settings2 } from 'lucide-react';
4
- import { useState, useId, useEffect, useMemo } from 'react';
5
- import { Menu } from '../../components/menu/Menu';
6
- import { Popover } from '../../components/popover/Popover';
7
- import { usePersistentState } from '../../hooks/usePersistentState';
2
+ import { jsx } from 'react/jsx-runtime';
8
3
  import { JsonNode } from './JsonNode';
9
- import styles from './JsonViewer.module.css';
10
- import { useClipboardStatus } from './useClipboardStatus';
11
- import { normalizeSearch, isJsonValue, collectSearchMatches, collectExpandableNodeIds, collectInitiallyExpandedNodeIds } from './utils';
12
- import { Button } from '../button/Button';
13
- import { Icon } from '../icon/Icon';
4
+ import { JsonViewerShell } from './JsonViewerShell';
5
+ import { useJsonViewerState } from './useJsonViewerState';
14
6
 
15
- const COPY_ALL_ID = "__json-viewer-copy-all__";
16
7
  function JsonViewer({
17
8
  value,
18
9
  defaultExpandedDepth = 2,
@@ -29,249 +20,42 @@ function JsonViewer({
29
20
  storageKey,
30
21
  borderless = false
31
22
  }) {
32
- const [queryInput, setQueryInput] = useState("");
33
- const [query, setQuery] = useState("");
34
- const normalizedQuery = normalizeSearch(query);
35
- const inputId = useId();
36
- const { copiedId, setCopiedId } = useClipboardStatus();
37
- const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState({
38
- initialValue: appearance,
39
- storageKey: storageKey ? `${storageKey}:appearance` : void 0,
40
- validate: (stored) => stored === "dark" || stored === "light"
23
+ const state = useJsonViewerState({
24
+ value,
25
+ defaultExpandedDepth,
26
+ expandAll,
27
+ defaultViewMode,
28
+ searchDebounceMs,
29
+ appearance,
30
+ storageKey
41
31
  });
42
- const { value: viewMode, setValue: setViewMode } = usePersistentState({
43
- initialValue: defaultViewMode,
44
- storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
45
- validate: (stored) => stored === "tree" || stored === "raw"
46
- });
47
- const handleToggleAppearance = () => {
48
- setCurrentAppearance((current) => current === "dark" ? "light" : "dark");
49
- };
50
- useEffect(() => {
51
- const timeoutId = window.setTimeout(() => {
52
- setQuery(queryInput);
53
- }, searchDebounceMs);
54
- return () => window.clearTimeout(timeoutId);
55
- }, [queryInput, searchDebounceMs]);
56
- const safeValue = useMemo(() => {
57
- if (isJsonValue(value)) return value;
58
- return {
59
- unsupported: {
60
- besked: "Den angivne v\xE6rdi kan ikke vises som JSON",
61
- modtagetType: typeof value
62
- }
63
- };
64
- }, [value]);
65
- const matches = useMemo(
66
- () => normalizedQuery ? collectSearchMatches(safeValue, normalizedQuery) : /* @__PURE__ */ new Map(),
67
- [normalizedQuery, safeValue]
68
- );
69
- const allExpandableNodeIds = useMemo(() => collectExpandableNodeIds(safeValue), [safeValue]);
70
- const [expandedNodeIds, setExpandedNodeIds] = useState(
71
- () => new Set(collectInitiallyExpandedNodeIds(safeValue, defaultExpandedDepth, expandAll))
72
- );
73
- const hasResults = normalizedQuery ? matches.size > 0 : true;
74
- const rawJson = useMemo(() => JSON.stringify(safeValue, null, 2), [safeValue]);
75
- const contentClassName = [
76
- viewMode === "raw" ? styles.rawPane : styles.treePane,
77
- deleted ? styles.deleted : ""
78
- ].filter(Boolean).join(" ");
79
- const handleCopy = async (nodeId, rawValue) => {
80
- try {
81
- await navigator.clipboard.writeText(rawValue);
82
- setCopiedId(nodeId);
83
- } catch {
84
- setCopiedId(null);
85
- }
86
- };
87
- const handleCopyAll = () => handleCopy(COPY_ALL_ID, rawJson);
88
- const handleExpandAll = () => {
89
- setExpandedNodeIds(new Set(allExpandableNodeIds));
90
- };
91
- const handleCollapseAll = () => {
92
- setExpandedNodeIds(/* @__PURE__ */ new Set());
93
- };
94
- const handleToggleNode = (nodeId) => {
95
- setExpandedNodeIds((current) => {
96
- const next = new Set(current);
97
- if (next.has(nodeId)) next.delete(nodeId);
98
- else next.add(nodeId);
99
- return next;
100
- });
101
- };
102
- return /* @__PURE__ */ jsxs(
103
- "section",
32
+ return /* @__PURE__ */ jsx(
33
+ JsonViewerShell,
104
34
  {
105
- className: [styles.viewer, borderless ? styles.borderless : "", className].filter(Boolean).join(" "),
106
- "data-appearance": currentAppearance,
107
- children: [
108
- /* @__PURE__ */ jsxs(
109
- "div",
110
- {
111
- className: styles.toolbar,
112
- "data-surface": currentAppearance === "dark" ? "inverse" : void 0,
113
- children: [
114
- /* @__PURE__ */ jsxs("div", { className: styles.toolbarTop, children: [
115
- viewMode === "tree" ? /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: styles.searchField, children: [
116
- /* @__PURE__ */ jsx(Search, { className: styles.searchIcon, "aria-hidden": "true" }),
117
- /* @__PURE__ */ jsx(
118
- "input",
119
- {
120
- id: inputId,
121
- type: "search",
122
- value: queryInput,
123
- onChange: (event) => setQueryInput(event.target.value),
124
- placeholder: searchPlaceholder,
125
- className: styles.searchInput
126
- }
127
- ),
128
- queryInput ? /* @__PURE__ */ jsx(
129
- "button",
130
- {
131
- type: "button",
132
- className: styles.clearButton,
133
- "aria-label": "Ryd s\xF8gning",
134
- onClick: () => {
135
- setQueryInput("");
136
- setQuery("");
137
- },
138
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
139
- }
140
- ) : null
141
- ] }) : /* @__PURE__ */ jsx("span", {}),
142
- /* @__PURE__ */ jsx("div", { className: styles.actions, children: /* @__PURE__ */ jsx(
143
- Popover,
144
- {
145
- matchTriggerWidth: false,
146
- minWidth: "200px",
147
- trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsx(
148
- Button,
149
- {
150
- variant: "inline",
151
- "aria-label": "Flere handlinger",
152
- "aria-haspopup": "menu",
153
- "aria-expanded": isOpen ? true : false,
154
- onClick: toggle,
155
- children: /* @__PURE__ */ jsx(Icon, { customIcon: /* @__PURE__ */ jsx(Settings2, { "aria-hidden": "true" }) })
156
- }
157
- ),
158
- children: (close) => /* @__PURE__ */ jsxs(Menu, { children: [
159
- /* @__PURE__ */ jsx(Menu.Item, { disabled: viewMode === "raw" || Boolean(normalizedQuery), children: /* @__PURE__ */ jsxs(
160
- "button",
161
- {
162
- type: "button",
163
- onClick: () => {
164
- handleExpandAll();
165
- close();
166
- },
167
- children: [
168
- /* @__PURE__ */ jsx(ArrowDown, { "aria-hidden": "true" }),
169
- /* @__PURE__ */ jsx("span", { children: "Fold alle ud" })
170
- ]
171
- }
172
- ) }),
173
- /* @__PURE__ */ jsx(Menu.Item, { disabled: viewMode === "raw" || Boolean(normalizedQuery), children: /* @__PURE__ */ jsxs(
174
- "button",
175
- {
176
- type: "button",
177
- onClick: () => {
178
- handleCollapseAll();
179
- close();
180
- },
181
- children: [
182
- /* @__PURE__ */ jsx(ArrowUp, { "aria-hidden": "true" }),
183
- /* @__PURE__ */ jsx("span", { children: "Fold alle sammen" })
184
- ]
185
- }
186
- ) }),
187
- /* @__PURE__ */ jsx(Menu.Separator, {}),
188
- /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
189
- "button",
190
- {
191
- type: "button",
192
- onClick: () => {
193
- setViewMode((mode) => mode === "raw" ? "tree" : "raw");
194
- close();
195
- },
196
- children: [
197
- viewMode === "raw" ? /* @__PURE__ */ jsx(ListTree, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Braces, { "aria-hidden": "true" }),
198
- /* @__PURE__ */ jsx("span", { children: viewMode === "raw" ? "Vis tr\xE6" : "Vis raw" })
199
- ]
200
- }
201
- ) }),
202
- /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
203
- "button",
204
- {
205
- type: "button",
206
- onClick: () => {
207
- handleToggleAppearance();
208
- close();
209
- },
210
- children: [
211
- currentAppearance === "dark" ? /* @__PURE__ */ jsx(Sun, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Moon, { "aria-hidden": "true" }),
212
- /* @__PURE__ */ jsx("span", { children: currentAppearance === "dark" ? "Lys visning" : "M\xF8rk visning" })
213
- ]
214
- }
215
- ) }),
216
- /* @__PURE__ */ jsx(Menu.Separator, {}),
217
- /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
218
- "button",
219
- {
220
- type: "button",
221
- onClick: () => {
222
- handleCopyAll();
223
- close();
224
- },
225
- children: [
226
- /* @__PURE__ */ jsx(ClipboardCopy, { "aria-hidden": "true" }),
227
- /* @__PURE__ */ jsx("span", { children: "Kopi\xE9r JSON" })
228
- ]
229
- }
230
- ) })
231
- ] })
232
- }
233
- ) })
234
- ] }),
235
- helperText || viewMode === "tree" && normalizedQuery ? /* @__PURE__ */ jsxs("div", { className: styles.metaRow, children: [
236
- helperText ? /* @__PURE__ */ jsx("span", { className: styles.helperText, children: helperText }) : /* @__PURE__ */ jsx("span", {}),
237
- /* @__PURE__ */ jsx("span", { className: styles.statusText, children: viewMode === "tree" && normalizedQuery ? `${matches.size} matchende node${matches.size === 1 ? "" : "r"}` : "" })
238
- ] }) : null
239
- ]
240
- }
241
- ),
242
- viewMode === "raw" ? /* @__PURE__ */ jsx(
243
- "pre",
244
- {
245
- className: contentClassName,
246
- style: maxHeight !== void 0 ? { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight } : void 0,
247
- children: rawJson
248
- }
249
- ) : /* @__PURE__ */ jsx(
250
- "div",
251
- {
252
- className: contentClassName,
253
- role: "tree",
254
- "aria-label": "JSON-visning",
255
- style: maxHeight !== void 0 ? { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight } : void 0,
256
- children: hasResults ? /* @__PURE__ */ jsx(
257
- JsonNode,
258
- {
259
- keyName: void 0,
260
- path: [],
261
- value: safeValue,
262
- depth: 0,
263
- defaultExpandedDepth,
264
- query: normalizedQuery,
265
- matches,
266
- expandedNodeIds,
267
- onToggleNode: handleToggleNode,
268
- copiedId,
269
- onCopy: handleCopy
270
- }
271
- ) : /* @__PURE__ */ jsx("div", { className: styles.emptyState, children: emptySearchText })
272
- }
273
- )
274
- ]
35
+ state,
36
+ helperText,
37
+ searchPlaceholder,
38
+ emptySearchText,
39
+ className,
40
+ maxHeight,
41
+ borderless,
42
+ deleted,
43
+ children: /* @__PURE__ */ jsx(
44
+ JsonNode,
45
+ {
46
+ keyName: void 0,
47
+ path: [],
48
+ value: state.safeValue,
49
+ depth: 0,
50
+ defaultExpandedDepth,
51
+ query: state.normalizedQuery,
52
+ matches: state.matches,
53
+ expandedNodeIds: state.expandedNodeIds,
54
+ onToggleNode: state.handleToggleNode,
55
+ copiedId: state.copiedId,
56
+ onCopy: state.handleCopy
57
+ }
58
+ )
275
59
  }
276
60
  );
277
61
  }