@dbcdk/react-components 0.0.208 → 0.0.210

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 (54) hide show
  1. package/dist/client.cjs +10 -0
  2. package/dist/client.d.ts +4 -0
  3. package/dist/client.js +2 -0
  4. package/dist/components/forms/markdown-editor/MarkdownEditor.cjs +475 -0
  5. package/dist/components/forms/markdown-editor/MarkdownEditor.d.ts +68 -0
  6. package/dist/components/forms/markdown-editor/MarkdownEditor.js +468 -0
  7. package/dist/components/forms/markdown-editor/MarkdownEditor.module.css +202 -0
  8. package/dist/components/forms/markdown-editor/MarkdownViewer.cjs +29 -0
  9. package/dist/components/forms/markdown-editor/MarkdownViewer.d.ts +27 -0
  10. package/dist/components/forms/markdown-editor/MarkdownViewer.js +23 -0
  11. package/dist/components/forms/markdown-editor/MarkdownViewer.module.css +97 -0
  12. package/dist/components/forms/markdown-editor/markdown.utils.cjs +325 -0
  13. package/dist/components/forms/markdown-editor/markdown.utils.d.ts +66 -0
  14. package/dist/components/forms/markdown-editor/markdown.utils.js +310 -0
  15. package/dist/components/listbox/Listbox.cjs +2 -2
  16. package/dist/components/listbox/Listbox.d.ts +2 -2
  17. package/dist/components/listbox/Listbox.js +2 -2
  18. package/dist/components/meta-bar/MetaBar.cjs +2 -2
  19. package/dist/components/meta-bar/MetaBar.d.ts +2 -1
  20. package/dist/components/meta-bar/MetaBar.js +2 -2
  21. package/dist/components/meta-bar/MetaBar.module.css +7 -0
  22. package/dist/components/overlay/side-panel/SidePanel.cjs +80 -2
  23. package/dist/components/overlay/side-panel/SidePanel.js +80 -2
  24. package/dist/components/overlay/tooltip/TooltipProvider.cjs +10 -1
  25. package/dist/components/overlay/tooltip/TooltipProvider.js +11 -2
  26. package/dist/components/overlay/tooltip/useTooltipTrigger.cjs +9 -2
  27. package/dist/components/overlay/tooltip/useTooltipTrigger.js +9 -2
  28. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.cjs +1 -1
  29. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +1 -1
  30. package/dist/components/split-pane/SplitPane.cjs +22 -7
  31. package/dist/components/split-pane/SplitPane.d.ts +5 -2
  32. package/dist/components/split-pane/SplitPane.js +22 -7
  33. package/dist/components/split-pane/SplitPane.module.css +9 -0
  34. package/dist/components/split-pane/provider/SplitPaneContext.cjs +5 -2
  35. package/dist/components/split-pane/provider/SplitPaneContext.d.ts +3 -1
  36. package/dist/components/split-pane/provider/SplitPaneContext.js +5 -2
  37. package/dist/components/tabs/Tabs.cjs +83 -69
  38. package/dist/components/tabs/Tabs.d.ts +5 -1
  39. package/dist/components/tabs/Tabs.js +83 -69
  40. package/dist/components/tabs/Tabs.module.css +39 -0
  41. package/dist/components/tree-view/TreeNodeRow.cjs +70 -30
  42. package/dist/components/tree-view/TreeNodeRow.d.ts +6 -1
  43. package/dist/components/tree-view/TreeNodeRow.js +70 -30
  44. package/dist/components/tree-view/TreeView.cjs +107 -19
  45. package/dist/components/tree-view/TreeView.d.ts +1 -1
  46. package/dist/components/tree-view/TreeView.js +107 -19
  47. package/dist/components/tree-view/TreeView.module.css +47 -3
  48. package/dist/components/tree-view/types.d.ts +6 -0
  49. package/dist/index.cjs +213 -208
  50. package/dist/index.css +2 -0
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.js +1 -0
  53. package/dist/styles/css-helper-classes/typography.css +4 -0
  54. package/package.json +4 -1
@@ -43,6 +43,8 @@ function Tabs({
43
43
  subheader,
44
44
  variant,
45
45
  panelStyle = false,
46
+ flushContent = false,
47
+ stackTabListAdditionOnMobile = false,
46
48
  tabs,
47
49
  value,
48
50
  defaultValue,
@@ -142,79 +144,91 @@ function Tabs({
142
144
  children: /* @__PURE__ */ jsx(Headline, { disableMargin: true, size: 2, subheader, addition, children: header })
143
145
  }
144
146
  ) : null,
145
- /* @__PURE__ */ jsxs("div", { className: `${styles.tabs} ${styles[variant]} ${panelStyle ? styles.panelStyle : ""}`, children: [
146
- /* @__PURE__ */ jsxs("div", { className: styles.tabList, children: [
147
- /* @__PURE__ */ jsxs("div", { className: styles.tabStrip, children: [
147
+ /* @__PURE__ */ jsxs(
148
+ "div",
149
+ {
150
+ className: [
151
+ styles.tabs,
152
+ styles[variant],
153
+ panelStyle && styles.panelStyle,
154
+ flushContent && styles.flushContent,
155
+ stackTabListAdditionOnMobile && styles.stackTabListAdditionOnMobile
156
+ ].filter(Boolean).join(" "),
157
+ children: [
158
+ /* @__PURE__ */ jsxs("div", { className: styles.tabList, children: [
159
+ /* @__PURE__ */ jsxs("div", { className: styles.tabStrip, children: [
160
+ /* @__PURE__ */ jsx(
161
+ "div",
162
+ {
163
+ className: onAddTab ? styles.tabButtons : `${styles.tabButtons} ${styles.tabButtonsEnd}`,
164
+ role: "tablist",
165
+ "aria-label": header != null ? header : "Tabs",
166
+ children: visibleTabs.map((tab, index) => {
167
+ const selected = index === activeIndex;
168
+ const tabDomId = `${uid}-tab-${String(tab.id)}`;
169
+ const panelDomId = `${uid}-panel-${String(tab.id)}`;
170
+ return /* @__PURE__ */ jsxs("div", { className: `${styles.tab} ${selected ? styles.active : ""}`, children: [
171
+ /* @__PURE__ */ jsxs(
172
+ "button",
173
+ {
174
+ id: tabDomId,
175
+ type: "button",
176
+ className: styles.tabButton,
177
+ role: "tab",
178
+ "aria-selected": selected,
179
+ "aria-controls": panelDomId,
180
+ tabIndex: selected ? 0 : -1,
181
+ disabled: tab.disabled,
182
+ onClick: () => setValue(tab.id),
183
+ onKeyDown: (e) => onKeyDownTab(e, index),
184
+ children: [
185
+ tab.headerIcon ? /* @__PURE__ */ jsx("span", { className: styles.icon, children: tab.headerIcon }) : null,
186
+ /* @__PURE__ */ jsx("span", { className: styles.label, children: tab.header }),
187
+ tab.badge ? /* @__PURE__ */ jsx("span", { className: styles.badge, children: /* @__PURE__ */ jsx(Chip, { size: "sm", children: tab.badge.toLocaleString("da-DK") }) }) : null
188
+ ]
189
+ }
190
+ ),
191
+ tab.removable && onRemoveTab ? /* @__PURE__ */ jsx(
192
+ "button",
193
+ {
194
+ type: "button",
195
+ className: styles.removeTabButton,
196
+ "aria-label": `Fjern fane ${tab.header}`,
197
+ disabled: tab.disabled,
198
+ onClick: () => onRemoveTab(tab.id, tab, index),
199
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
200
+ }
201
+ ) : null
202
+ ] }, tab.id);
203
+ })
204
+ }
205
+ ),
206
+ onAddTab ? /* @__PURE__ */ jsx(
207
+ "button",
208
+ {
209
+ type: "button",
210
+ className: styles.addTabButton,
211
+ onClick: onAddTab,
212
+ "aria-label": "Tilf\xF8j fane",
213
+ children: /* @__PURE__ */ jsx(Plus, { "aria-hidden": "true" })
214
+ }
215
+ ) : null
216
+ ] }),
217
+ tabListAddition ? /* @__PURE__ */ jsx("div", { className: styles.tabListAddition, children: tabListAddition }) : null
218
+ ] }),
148
219
  /* @__PURE__ */ jsx(
149
220
  "div",
150
221
  {
151
- className: onAddTab ? styles.tabButtons : `${styles.tabButtons} ${styles.tabButtonsEnd}`,
152
- role: "tablist",
153
- "aria-label": header != null ? header : "Tabs",
154
- children: visibleTabs.map((tab, index) => {
155
- const selected = index === activeIndex;
156
- const tabDomId = `${uid}-tab-${String(tab.id)}`;
157
- const panelDomId = `${uid}-panel-${String(tab.id)}`;
158
- return /* @__PURE__ */ jsxs("div", { className: `${styles.tab} ${selected ? styles.active : ""}`, children: [
159
- /* @__PURE__ */ jsxs(
160
- "button",
161
- {
162
- id: tabDomId,
163
- type: "button",
164
- className: styles.tabButton,
165
- role: "tab",
166
- "aria-selected": selected,
167
- "aria-controls": panelDomId,
168
- tabIndex: selected ? 0 : -1,
169
- disabled: tab.disabled,
170
- onClick: () => setValue(tab.id),
171
- onKeyDown: (e) => onKeyDownTab(e, index),
172
- children: [
173
- tab.headerIcon ? /* @__PURE__ */ jsx("span", { className: styles.icon, children: tab.headerIcon }) : null,
174
- /* @__PURE__ */ jsx("span", { className: styles.label, children: tab.header }),
175
- tab.badge ? /* @__PURE__ */ jsx("span", { className: styles.badge, children: /* @__PURE__ */ jsx(Chip, { size: "sm", children: tab.badge.toLocaleString("da-DK") }) }) : null
176
- ]
177
- }
178
- ),
179
- tab.removable && onRemoveTab ? /* @__PURE__ */ jsx(
180
- "button",
181
- {
182
- type: "button",
183
- className: styles.removeTabButton,
184
- "aria-label": `Fjern fane ${tab.header}`,
185
- disabled: tab.disabled,
186
- onClick: () => onRemoveTab(tab.id, tab, index),
187
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
188
- }
189
- ) : null
190
- ] }, tab.id);
191
- })
222
+ id: activeTab ? `${uid}-panel-${String(activeTab.id)}` : void 0,
223
+ role: "tabpanel",
224
+ "aria-labelledby": activeTab ? `${uid}-tab-${String(activeTab.id)}` : void 0,
225
+ className: styles.tabContent,
226
+ children: loading ? /* @__PURE__ */ jsx("div", { className: styles.loadingContent, children: /* @__PURE__ */ jsx(SkeletonLoader, { type: "squares", rows: 1, columns: 1 }) }) : activeTab == null ? void 0 : activeTab.content
192
227
  }
193
- ),
194
- onAddTab ? /* @__PURE__ */ jsx(
195
- "button",
196
- {
197
- type: "button",
198
- className: styles.addTabButton,
199
- onClick: onAddTab,
200
- "aria-label": "Tilf\xF8j fane",
201
- children: /* @__PURE__ */ jsx(Plus, { "aria-hidden": "true" })
202
- }
203
- ) : null
204
- ] }),
205
- tabListAddition ? /* @__PURE__ */ jsx("div", { className: styles.tabListAddition, children: tabListAddition }) : null
206
- ] }),
207
- /* @__PURE__ */ jsx(
208
- "div",
209
- {
210
- id: activeTab ? `${uid}-panel-${String(activeTab.id)}` : void 0,
211
- role: "tabpanel",
212
- "aria-labelledby": activeTab ? `${uid}-tab-${String(activeTab.id)}` : void 0,
213
- className: styles.tabContent,
214
- children: loading ? /* @__PURE__ */ jsx("div", { className: styles.loadingContent, children: /* @__PURE__ */ jsx(SkeletonLoader, { type: "squares", rows: 1, columns: 1 }) }) : activeTab == null ? void 0 : activeTab.content
215
- }
216
- )
217
- ] })
228
+ )
229
+ ]
230
+ }
231
+ )
218
232
  ] });
219
233
  }
220
234
  Tabs.Item = TabsItem;
@@ -337,6 +337,26 @@
337
337
  gap: var(--spacing-md);
338
338
  }
339
339
 
340
+ .flushContent.tabs {
341
+ gap: 0;
342
+ }
343
+
344
+ .flushContent > .tabList {
345
+ grid-template-rows: auto 0;
346
+ }
347
+
348
+ .flushContent > .tabList > .tabStrip {
349
+ grid-row: 1;
350
+ align-self: stretch;
351
+ }
352
+
353
+ .flushContent.filled > .tabContent {
354
+ border: 0;
355
+ border-radius: 0;
356
+ box-shadow: none;
357
+ padding: 0;
358
+ }
359
+
340
360
  .headerContainerOutlined {
341
361
  padding-block-end: var(--spacing-xs);
342
362
  }
@@ -413,4 +433,23 @@
413
433
  .panelStyle > .tabList {
414
434
  border: 0;
415
435
  }
436
+
437
+ .stackTabListAdditionOnMobile > .tabList {
438
+ grid-template-columns: minmax(0, 1fr);
439
+ grid-template-rows: auto auto;
440
+ }
441
+
442
+ .stackTabListAdditionOnMobile > .tabList > .tabStrip {
443
+ grid-column: 1;
444
+ grid-row: 1;
445
+ }
446
+
447
+ .stackTabListAdditionOnMobile > .tabList > .tabListAddition {
448
+ grid-column: 1;
449
+ grid-row: 2;
450
+ justify-content: flex-start;
451
+ margin-inline-start: 0;
452
+ padding-block: var(--spacing-xs);
453
+ padding-inline: 0;
454
+ }
416
455
  }
@@ -16,12 +16,17 @@ function TreeNodeRow({
16
16
  wrapLabels,
17
17
  isExpanded,
18
18
  toggle,
19
+ expand,
20
+ expandOnSelect,
19
21
  resolvedChildren,
20
22
  loadingIds,
21
23
  errorIds,
22
24
  requestLoad,
23
25
  loadChildren,
24
26
  selectedId,
27
+ currentId,
28
+ focusedId,
29
+ onFocusNode,
25
30
  onSelectNode,
26
31
  renderLabel
27
32
  }) {
@@ -33,6 +38,7 @@ function TreeNodeRow({
33
38
  const loading = loadingIds.has(node.id);
34
39
  const error = errorIds[node.id];
35
40
  const selected = selectedId !== void 0 && selectedId === node.id;
41
+ const current = currentId !== void 0 && currentId === node.id;
36
42
  react.useEffect(() => {
37
43
  if (expanded && children === void 0 && !loading && !error && loadChildren) {
38
44
  requestLoad(node);
@@ -44,38 +50,67 @@ function TreeNodeRow({
44
50
  role: "treeitem",
45
51
  "aria-expanded": expandable ? expanded : void 0,
46
52
  "aria-selected": selected,
53
+ "aria-current": current ? "page" : void 0,
54
+ "aria-level": depth + 1,
55
+ "data-tree-node-id": node.id,
47
56
  style: { ["--tree-depth"]: depth },
48
57
  children: [
49
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.row, "data-selected": selected || void 0, children: [
50
- /* @__PURE__ */ jsxRuntime.jsx(
51
- "button",
52
- {
53
- type: "button",
54
- className: styles__default.default.toggle,
55
- onClick: () => expandable && toggle(node.id),
56
- disabled: !expandable,
57
- "aria-hidden": !expandable,
58
- tabIndex: expandable ? 0 : -1,
59
- children: loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: `spin ${styles__default.default.spinner}`, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LoaderCircle, { "aria-hidden": "true" }) }) : expandable ? (
60
- // A resolved node's chevron means "this has children"; an
61
- // unresolved lazy node's dimmer chevron means "might have
62
- // children, click to check" - we genuinely don't know yet,
63
- // and shouldn't visually assert otherwise.
64
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: isResolved ? void 0 : styles__default.default.toggleUnresolved, children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true" }) })
65
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.leafSpacer, "aria-hidden": "true" })
66
- }
67
- ),
68
- /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: styles__default.default.labelButton, onClick: () => onSelectNode == null ? void 0 : onSelectNode(node), children: [
69
- node.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.icon, "aria-hidden": "true", children: node.icon }) : null,
70
- /* @__PURE__ */ jsxRuntime.jsx(
71
- "span",
72
- {
73
- className: [styles__default.default.label, wrapLabels ? styles__default.default.labelWrap : styles__default.default.labelTruncate].filter(Boolean).join(" "),
74
- children: renderLabel ? renderLabel(node) : node.label
75
- }
76
- )
77
- ] })
78
- ] }),
58
+ /* @__PURE__ */ jsxRuntime.jsxs(
59
+ "div",
60
+ {
61
+ className: styles__default.default.row,
62
+ "data-tree-row": "true",
63
+ "data-selected": selected || void 0,
64
+ "data-current": current || void 0,
65
+ children: [
66
+ /* @__PURE__ */ jsxRuntime.jsx(
67
+ "button",
68
+ {
69
+ type: "button",
70
+ className: styles__default.default.toggle,
71
+ "data-tree-toggle": "true",
72
+ onClick: () => expandable && toggle(node.id),
73
+ disabled: !expandable,
74
+ "aria-hidden": !expandable,
75
+ tabIndex: -1,
76
+ "aria-label": expanded ? "Luk relationer" : "Vis relationer",
77
+ children: loading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: `spin ${styles__default.default.spinner}`, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LoaderCircle, { "aria-hidden": "true" }) }) : expandable ? (
78
+ // A resolved node's chevron means "this has children"; an
79
+ // unresolved lazy node's dimmer chevron means "might have
80
+ // children, click to check" - we genuinely don't know yet,
81
+ // and shouldn't visually assert otherwise.
82
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: isResolved ? void 0 : styles__default.default.toggleUnresolved, children: expanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": "true" }) })
83
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.leafSpacer, "aria-hidden": "true" })
84
+ }
85
+ ),
86
+ /* @__PURE__ */ jsxRuntime.jsxs(
87
+ "button",
88
+ {
89
+ type: "button",
90
+ className: styles__default.default.labelButton,
91
+ "data-tree-focus-target": "true",
92
+ "data-tree-focus-node-id": node.id,
93
+ tabIndex: focusedId === node.id ? 0 : -1,
94
+ onFocus: () => onFocusNode(node.id),
95
+ onClick: () => {
96
+ if (expandOnSelect && expandable) expand(node.id);
97
+ onSelectNode == null ? void 0 : onSelectNode(node);
98
+ },
99
+ children: [
100
+ node.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.icon, "aria-hidden": "true", children: node.icon }) : null,
101
+ /* @__PURE__ */ jsxRuntime.jsx(
102
+ "span",
103
+ {
104
+ className: [styles__default.default.label, wrapLabels ? styles__default.default.labelWrap : styles__default.default.labelTruncate].filter(Boolean).join(" "),
105
+ children: renderLabel ? renderLabel(node) : node.label
106
+ }
107
+ )
108
+ ]
109
+ }
110
+ )
111
+ ]
112
+ }
113
+ ),
79
114
  error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.errorRow, children: [
80
115
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: error }),
81
116
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: styles__default.default.retryButton, onClick: () => requestLoad(node), children: "Pr\xF8v igen" })
@@ -88,12 +123,17 @@ function TreeNodeRow({
88
123
  wrapLabels,
89
124
  isExpanded,
90
125
  toggle,
126
+ expand,
127
+ expandOnSelect,
91
128
  resolvedChildren,
92
129
  loadingIds,
93
130
  errorIds,
94
131
  requestLoad,
95
132
  loadChildren,
96
133
  selectedId,
134
+ currentId,
135
+ focusedId,
136
+ onFocusNode,
97
137
  onSelectNode,
98
138
  renderLabel
99
139
  },
@@ -6,14 +6,19 @@ type TreeNodeRowProps<T> = {
6
6
  wrapLabels: boolean;
7
7
  isExpanded: (id: string) => boolean;
8
8
  toggle: (id: string) => void;
9
+ expand: (id: string) => void;
10
+ expandOnSelect: boolean;
9
11
  resolvedChildren: Record<string, TreeNode<T>[]>;
10
12
  loadingIds: Set<string>;
11
13
  errorIds: Record<string, ReactNode>;
12
14
  requestLoad: (node: TreeNode<T>) => void;
13
15
  loadChildren?: LoadTreeChildren<T>;
14
16
  selectedId?: string;
17
+ currentId?: string;
18
+ focusedId?: string;
19
+ onFocusNode: (id: string) => void;
15
20
  onSelectNode?: (node: TreeNode<T>) => void;
16
21
  renderLabel?: (node: TreeNode<T>) => ReactNode;
17
22
  };
18
- export declare function TreeNodeRow<T>({ node, depth, wrapLabels, isExpanded, toggle, resolvedChildren, loadingIds, errorIds, requestLoad, loadChildren, selectedId, onSelectNode, renderLabel, }: TreeNodeRowProps<T>): JSX.Element;
23
+ export declare function TreeNodeRow<T>({ node, depth, wrapLabels, isExpanded, toggle, expand, expandOnSelect, resolvedChildren, loadingIds, errorIds, requestLoad, loadChildren, selectedId, currentId, focusedId, onFocusNode, onSelectNode, renderLabel, }: TreeNodeRowProps<T>): JSX.Element;
19
24
  export {};
@@ -10,12 +10,17 @@ function TreeNodeRow({
10
10
  wrapLabels,
11
11
  isExpanded,
12
12
  toggle,
13
+ expand,
14
+ expandOnSelect,
13
15
  resolvedChildren,
14
16
  loadingIds,
15
17
  errorIds,
16
18
  requestLoad,
17
19
  loadChildren,
18
20
  selectedId,
21
+ currentId,
22
+ focusedId,
23
+ onFocusNode,
19
24
  onSelectNode,
20
25
  renderLabel
21
26
  }) {
@@ -27,6 +32,7 @@ function TreeNodeRow({
27
32
  const loading = loadingIds.has(node.id);
28
33
  const error = errorIds[node.id];
29
34
  const selected = selectedId !== void 0 && selectedId === node.id;
35
+ const current = currentId !== void 0 && currentId === node.id;
30
36
  useEffect(() => {
31
37
  if (expanded && children === void 0 && !loading && !error && loadChildren) {
32
38
  requestLoad(node);
@@ -38,38 +44,67 @@ function TreeNodeRow({
38
44
  role: "treeitem",
39
45
  "aria-expanded": expandable ? expanded : void 0,
40
46
  "aria-selected": selected,
47
+ "aria-current": current ? "page" : void 0,
48
+ "aria-level": depth + 1,
49
+ "data-tree-node-id": node.id,
41
50
  style: { ["--tree-depth"]: depth },
42
51
  children: [
43
- /* @__PURE__ */ jsxs("div", { className: styles.row, "data-selected": selected || void 0, children: [
44
- /* @__PURE__ */ jsx(
45
- "button",
46
- {
47
- type: "button",
48
- className: styles.toggle,
49
- onClick: () => expandable && toggle(node.id),
50
- disabled: !expandable,
51
- "aria-hidden": !expandable,
52
- tabIndex: expandable ? 0 : -1,
53
- children: loading ? /* @__PURE__ */ jsx("span", { className: `spin ${styles.spinner}`, children: /* @__PURE__ */ jsx(LoaderCircle, { "aria-hidden": "true" }) }) : expandable ? (
54
- // A resolved node's chevron means "this has children"; an
55
- // unresolved lazy node's dimmer chevron means "might have
56
- // children, click to check" - we genuinely don't know yet,
57
- // and shouldn't visually assert otherwise.
58
- /* @__PURE__ */ jsx("span", { className: isResolved ? void 0 : styles.toggleUnresolved, children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }) })
59
- ) : /* @__PURE__ */ jsx("span", { className: styles.leafSpacer, "aria-hidden": "true" })
60
- }
61
- ),
62
- /* @__PURE__ */ jsxs("button", { type: "button", className: styles.labelButton, onClick: () => onSelectNode == null ? void 0 : onSelectNode(node), children: [
63
- node.icon ? /* @__PURE__ */ jsx("span", { className: styles.icon, "aria-hidden": "true", children: node.icon }) : null,
64
- /* @__PURE__ */ jsx(
65
- "span",
66
- {
67
- className: [styles.label, wrapLabels ? styles.labelWrap : styles.labelTruncate].filter(Boolean).join(" "),
68
- children: renderLabel ? renderLabel(node) : node.label
69
- }
70
- )
71
- ] })
72
- ] }),
52
+ /* @__PURE__ */ jsxs(
53
+ "div",
54
+ {
55
+ className: styles.row,
56
+ "data-tree-row": "true",
57
+ "data-selected": selected || void 0,
58
+ "data-current": current || void 0,
59
+ children: [
60
+ /* @__PURE__ */ jsx(
61
+ "button",
62
+ {
63
+ type: "button",
64
+ className: styles.toggle,
65
+ "data-tree-toggle": "true",
66
+ onClick: () => expandable && toggle(node.id),
67
+ disabled: !expandable,
68
+ "aria-hidden": !expandable,
69
+ tabIndex: -1,
70
+ "aria-label": expanded ? "Luk relationer" : "Vis relationer",
71
+ children: loading ? /* @__PURE__ */ jsx("span", { className: `spin ${styles.spinner}`, children: /* @__PURE__ */ jsx(LoaderCircle, { "aria-hidden": "true" }) }) : expandable ? (
72
+ // A resolved node's chevron means "this has children"; an
73
+ // unresolved lazy node's dimmer chevron means "might have
74
+ // children, click to check" - we genuinely don't know yet,
75
+ // and shouldn't visually assert otherwise.
76
+ /* @__PURE__ */ jsx("span", { className: isResolved ? void 0 : styles.toggleUnresolved, children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }) })
77
+ ) : /* @__PURE__ */ jsx("span", { className: styles.leafSpacer, "aria-hidden": "true" })
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsxs(
81
+ "button",
82
+ {
83
+ type: "button",
84
+ className: styles.labelButton,
85
+ "data-tree-focus-target": "true",
86
+ "data-tree-focus-node-id": node.id,
87
+ tabIndex: focusedId === node.id ? 0 : -1,
88
+ onFocus: () => onFocusNode(node.id),
89
+ onClick: () => {
90
+ if (expandOnSelect && expandable) expand(node.id);
91
+ onSelectNode == null ? void 0 : onSelectNode(node);
92
+ },
93
+ children: [
94
+ node.icon ? /* @__PURE__ */ jsx("span", { className: styles.icon, "aria-hidden": "true", children: node.icon }) : null,
95
+ /* @__PURE__ */ jsx(
96
+ "span",
97
+ {
98
+ className: [styles.label, wrapLabels ? styles.labelWrap : styles.labelTruncate].filter(Boolean).join(" "),
99
+ children: renderLabel ? renderLabel(node) : node.label
100
+ }
101
+ )
102
+ ]
103
+ }
104
+ )
105
+ ]
106
+ }
107
+ ),
73
108
  error ? /* @__PURE__ */ jsxs("div", { className: styles.errorRow, children: [
74
109
  /* @__PURE__ */ jsx("span", { children: error }),
75
110
  /* @__PURE__ */ jsx("button", { type: "button", className: styles.retryButton, onClick: () => requestLoad(node), children: "Pr\xF8v igen" })
@@ -82,12 +117,17 @@ function TreeNodeRow({
82
117
  wrapLabels,
83
118
  isExpanded,
84
119
  toggle,
120
+ expand,
121
+ expandOnSelect,
85
122
  resolvedChildren,
86
123
  loadingIds,
87
124
  errorIds,
88
125
  requestLoad,
89
126
  loadChildren,
90
127
  selectedId,
128
+ currentId,
129
+ focusedId,
130
+ onFocusNode,
91
131
  onSelectNode,
92
132
  renderLabel
93
133
  },