@dbcdk/react-components 0.0.195 → 0.0.197

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