@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
@@ -14,19 +14,29 @@ var styles__default = /*#__PURE__*/_interopDefault(styles);
14
14
 
15
15
  function TreeView({
16
16
  data,
17
+ size = "sm",
17
18
  loadChildren,
18
19
  defaultExpandedIds,
19
20
  expandedIds,
20
21
  onExpandedIdsChange,
21
22
  selectedId,
23
+ currentId,
22
24
  onSelectNode,
25
+ expandOnSelect = false,
23
26
  renderLabel,
24
27
  wrapLabels = true,
25
28
  emptyMessage = "Intet at vise.",
26
29
  loadErrorMessage = () => "Der skete en fejl under indl\xE6sning.",
27
30
  className,
31
+ "aria-label": ariaLabel,
28
32
  ...rest
29
33
  }) {
34
+ const [focusedId, setFocusedId] = react.useState(
35
+ () => {
36
+ var _a, _b;
37
+ return (_b = currentId != null ? currentId : selectedId) != null ? _b : (_a = data[0]) == null ? void 0 : _a.id;
38
+ }
39
+ );
30
40
  const { isExpanded, toggle, expand } = useTreeExpansion.useTreeExpansion(
31
41
  defaultExpandedIds,
32
42
  expandedIds,
@@ -60,28 +70,106 @@ function TreeView({
60
70
  },
61
71
  [loadChildren, loadingIds, expand, loadErrorMessage]
62
72
  );
73
+ const handleTreeKeyDown = react.useCallback((event) => {
74
+ var _a, _b, _c, _d;
75
+ const target = event.target;
76
+ const focusedLabel = target.closest('[data-tree-focus-target="true"]');
77
+ if (!focusedLabel) return;
78
+ const visibleItems = Array.from(
79
+ event.currentTarget.querySelectorAll('[data-tree-focus-target="true"]')
80
+ );
81
+ const treeItem = focusedLabel.closest('[role="treeitem"]');
82
+ if (!treeItem) return;
83
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
84
+ const index = visibleItems.indexOf(focusedLabel);
85
+ const nextIndex = Math.max(
86
+ 0,
87
+ Math.min(index + (event.key === "ArrowDown" ? 1 : -1), visibleItems.length - 1)
88
+ );
89
+ if (nextIndex !== index) {
90
+ event.preventDefault();
91
+ (_a = visibleItems[nextIndex]) == null ? void 0 : _a.focus();
92
+ }
93
+ return;
94
+ }
95
+ if (event.key === "ArrowRight") {
96
+ const expanded = treeItem.getAttribute("aria-expanded") === "true";
97
+ if (treeItem.getAttribute("aria-expanded") === "false") {
98
+ event.preventDefault();
99
+ (_b = treeItem.querySelector('[data-tree-toggle="true"]')) == null ? void 0 : _b.click();
100
+ } else if (expanded) {
101
+ const firstChild = treeItem.querySelector(
102
+ ':scope > [role="group"] [data-tree-focus-target="true"]'
103
+ );
104
+ if (firstChild) {
105
+ event.preventDefault();
106
+ firstChild.focus();
107
+ }
108
+ }
109
+ return;
110
+ }
111
+ if (event.key === "ArrowLeft") {
112
+ if (treeItem.getAttribute("aria-expanded") === "true") {
113
+ event.preventDefault();
114
+ (_c = treeItem.querySelector('[data-tree-toggle="true"]')) == null ? void 0 : _c.click();
115
+ return;
116
+ }
117
+ const parentTreeItem = (_d = treeItem.parentElement) == null ? void 0 : _d.closest('[role="treeitem"]');
118
+ const parentLabel = parentTreeItem == null ? void 0 : parentTreeItem.querySelector(
119
+ ':scope > [data-tree-row] [data-tree-focus-target="true"]'
120
+ );
121
+ if (parentLabel) {
122
+ event.preventDefault();
123
+ parentLabel.focus();
124
+ }
125
+ }
126
+ }, []);
63
127
  if (data.length === 0) {
64
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: [styles__default.default.emptyState, className].filter(Boolean).join(" "), ...rest, children: emptyMessage });
128
+ return /* @__PURE__ */ jsxRuntime.jsx(
129
+ "div",
130
+ {
131
+ className: [styles__default.default.emptyState, className].filter(Boolean).join(" "),
132
+ "aria-label": ariaLabel,
133
+ ...rest,
134
+ children: emptyMessage
135
+ }
136
+ );
65
137
  }
66
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tree", className: [styles__default.default.tree, className].filter(Boolean).join(" "), ...rest, children: data.map((node) => /* @__PURE__ */ jsxRuntime.jsx(
67
- TreeNodeRow.TreeNodeRow,
138
+ return /* @__PURE__ */ jsxRuntime.jsx(
139
+ "div",
68
140
  {
69
- node,
70
- depth: 0,
71
- wrapLabels,
72
- isExpanded,
73
- toggle,
74
- resolvedChildren,
75
- loadingIds,
76
- errorIds,
77
- requestLoad,
78
- loadChildren,
79
- selectedId,
80
- onSelectNode,
81
- renderLabel
82
- },
83
- node.id
84
- )) });
141
+ role: "tree",
142
+ "data-size": size,
143
+ "aria-label": ariaLabel,
144
+ className: [styles__default.default.tree, className].filter(Boolean).join(" "),
145
+ onKeyDown: handleTreeKeyDown,
146
+ ...rest,
147
+ children: data.map((node) => /* @__PURE__ */ jsxRuntime.jsx(
148
+ TreeNodeRow.TreeNodeRow,
149
+ {
150
+ node,
151
+ depth: 0,
152
+ wrapLabels,
153
+ isExpanded,
154
+ toggle,
155
+ expand,
156
+ expandOnSelect,
157
+ resolvedChildren,
158
+ loadingIds,
159
+ errorIds,
160
+ requestLoad,
161
+ loadChildren,
162
+ selectedId,
163
+ currentId,
164
+ focusedId,
165
+ onFocusNode: setFocusedId,
166
+ onSelectNode,
167
+ renderLabel
168
+ },
169
+ node.id
170
+ ))
171
+ }
172
+ );
85
173
  }
86
174
 
87
175
  Object.defineProperty(exports, "collectExpandableIds", {
@@ -17,4 +17,4 @@ export { collectExpandableIds, findAncestorIds } from './utils';
17
17
  * useTreeExpansion), and it can be left uncontrolled or owned by the
18
18
  * caller via `expandedIds`/`onExpandedIdsChange`.
19
19
  */
20
- export declare function TreeView<T = unknown>({ data, loadChildren, defaultExpandedIds, expandedIds, onExpandedIdsChange, selectedId, onSelectNode, renderLabel, wrapLabels, emptyMessage, loadErrorMessage, className, ...rest }: TreeViewProps<T>): JSX.Element;
20
+ export declare function TreeView<T = unknown>({ data, size, loadChildren, defaultExpandedIds, expandedIds, onExpandedIdsChange, selectedId, currentId, onSelectNode, expandOnSelect, renderLabel, wrapLabels, emptyMessage, loadErrorMessage, className, 'aria-label': ariaLabel, ...rest }: TreeViewProps<T>): JSX.Element;
@@ -8,19 +8,29 @@ export { collectExpandableIds, findAncestorIds } from './utils';
8
8
 
9
9
  function TreeView({
10
10
  data,
11
+ size = "sm",
11
12
  loadChildren,
12
13
  defaultExpandedIds,
13
14
  expandedIds,
14
15
  onExpandedIdsChange,
15
16
  selectedId,
17
+ currentId,
16
18
  onSelectNode,
19
+ expandOnSelect = false,
17
20
  renderLabel,
18
21
  wrapLabels = true,
19
22
  emptyMessage = "Intet at vise.",
20
23
  loadErrorMessage = () => "Der skete en fejl under indl\xE6sning.",
21
24
  className,
25
+ "aria-label": ariaLabel,
22
26
  ...rest
23
27
  }) {
28
+ const [focusedId, setFocusedId] = useState(
29
+ () => {
30
+ var _a, _b;
31
+ return (_b = currentId != null ? currentId : selectedId) != null ? _b : (_a = data[0]) == null ? void 0 : _a.id;
32
+ }
33
+ );
24
34
  const { isExpanded, toggle, expand } = useTreeExpansion(
25
35
  defaultExpandedIds,
26
36
  expandedIds,
@@ -54,28 +64,106 @@ function TreeView({
54
64
  },
55
65
  [loadChildren, loadingIds, expand, loadErrorMessage]
56
66
  );
67
+ const handleTreeKeyDown = useCallback((event) => {
68
+ var _a, _b, _c, _d;
69
+ const target = event.target;
70
+ const focusedLabel = target.closest('[data-tree-focus-target="true"]');
71
+ if (!focusedLabel) return;
72
+ const visibleItems = Array.from(
73
+ event.currentTarget.querySelectorAll('[data-tree-focus-target="true"]')
74
+ );
75
+ const treeItem = focusedLabel.closest('[role="treeitem"]');
76
+ if (!treeItem) return;
77
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
78
+ const index = visibleItems.indexOf(focusedLabel);
79
+ const nextIndex = Math.max(
80
+ 0,
81
+ Math.min(index + (event.key === "ArrowDown" ? 1 : -1), visibleItems.length - 1)
82
+ );
83
+ if (nextIndex !== index) {
84
+ event.preventDefault();
85
+ (_a = visibleItems[nextIndex]) == null ? void 0 : _a.focus();
86
+ }
87
+ return;
88
+ }
89
+ if (event.key === "ArrowRight") {
90
+ const expanded = treeItem.getAttribute("aria-expanded") === "true";
91
+ if (treeItem.getAttribute("aria-expanded") === "false") {
92
+ event.preventDefault();
93
+ (_b = treeItem.querySelector('[data-tree-toggle="true"]')) == null ? void 0 : _b.click();
94
+ } else if (expanded) {
95
+ const firstChild = treeItem.querySelector(
96
+ ':scope > [role="group"] [data-tree-focus-target="true"]'
97
+ );
98
+ if (firstChild) {
99
+ event.preventDefault();
100
+ firstChild.focus();
101
+ }
102
+ }
103
+ return;
104
+ }
105
+ if (event.key === "ArrowLeft") {
106
+ if (treeItem.getAttribute("aria-expanded") === "true") {
107
+ event.preventDefault();
108
+ (_c = treeItem.querySelector('[data-tree-toggle="true"]')) == null ? void 0 : _c.click();
109
+ return;
110
+ }
111
+ const parentTreeItem = (_d = treeItem.parentElement) == null ? void 0 : _d.closest('[role="treeitem"]');
112
+ const parentLabel = parentTreeItem == null ? void 0 : parentTreeItem.querySelector(
113
+ ':scope > [data-tree-row] [data-tree-focus-target="true"]'
114
+ );
115
+ if (parentLabel) {
116
+ event.preventDefault();
117
+ parentLabel.focus();
118
+ }
119
+ }
120
+ }, []);
57
121
  if (data.length === 0) {
58
- return /* @__PURE__ */ jsx("div", { className: [styles.emptyState, className].filter(Boolean).join(" "), ...rest, children: emptyMessage });
122
+ return /* @__PURE__ */ jsx(
123
+ "div",
124
+ {
125
+ className: [styles.emptyState, className].filter(Boolean).join(" "),
126
+ "aria-label": ariaLabel,
127
+ ...rest,
128
+ children: emptyMessage
129
+ }
130
+ );
59
131
  }
60
- return /* @__PURE__ */ jsx("div", { role: "tree", className: [styles.tree, className].filter(Boolean).join(" "), ...rest, children: data.map((node) => /* @__PURE__ */ jsx(
61
- TreeNodeRow,
132
+ return /* @__PURE__ */ jsx(
133
+ "div",
62
134
  {
63
- node,
64
- depth: 0,
65
- wrapLabels,
66
- isExpanded,
67
- toggle,
68
- resolvedChildren,
69
- loadingIds,
70
- errorIds,
71
- requestLoad,
72
- loadChildren,
73
- selectedId,
74
- onSelectNode,
75
- renderLabel
76
- },
77
- node.id
78
- )) });
135
+ role: "tree",
136
+ "data-size": size,
137
+ "aria-label": ariaLabel,
138
+ className: [styles.tree, className].filter(Boolean).join(" "),
139
+ onKeyDown: handleTreeKeyDown,
140
+ ...rest,
141
+ children: data.map((node) => /* @__PURE__ */ jsx(
142
+ TreeNodeRow,
143
+ {
144
+ node,
145
+ depth: 0,
146
+ wrapLabels,
147
+ isExpanded,
148
+ toggle,
149
+ expand,
150
+ expandOnSelect,
151
+ resolvedChildren,
152
+ loadingIds,
153
+ errorIds,
154
+ requestLoad,
155
+ loadChildren,
156
+ selectedId,
157
+ currentId,
158
+ focusedId,
159
+ onFocusNode: setFocusedId,
160
+ onSelectNode,
161
+ renderLabel
162
+ },
163
+ node.id
164
+ ))
165
+ }
166
+ );
79
167
  }
80
168
 
81
169
  export { TreeView };
@@ -21,8 +21,44 @@
21
21
  border-radius: var(--border-radius-default);
22
22
  }
23
23
 
24
+ .tree[data-size='md'] .row {
25
+ min-block-size: calc(var(--spacing-md) + var(--spacing-sm));
26
+ padding-inline-start: 0;
27
+ padding-inline-end: calc(var(--spacing-xs) - var(--spacing-2xs));
28
+ }
29
+
30
+ .tree[data-size='md'] .toggle,
31
+ .tree[data-size='md'] .labelButton {
32
+ box-sizing: border-box;
33
+ min-block-size: calc(var(--spacing-md) + var(--spacing-sm));
34
+ }
35
+
36
+ .tree[data-size='md'] .toggle {
37
+ justify-content: center;
38
+ align-self: stretch;
39
+ --tree-indent: calc(
40
+ var(--tree-depth) * (var(--spacing-md) + 2 * var(--spacing-2xs)) + var(--spacing-xs) -
41
+ var(--spacing-2xs)
42
+ );
43
+ inline-size: calc(var(--tree-indent) + var(--spacing-lg) + var(--spacing-sm));
44
+ padding-inline-start: var(--tree-indent);
45
+ padding-inline-end: 0;
46
+ }
47
+
48
+ .tree[data-size='md'] .errorRow {
49
+ padding-inline-start: calc(
50
+ (var(--tree-depth) + 1) * (var(--spacing-md) + 2 * var(--spacing-2xs)) + var(--spacing-xs) -
51
+ var(--spacing-2xs)
52
+ );
53
+ }
54
+
24
55
  .row[data-selected='true'] {
25
- background: color-mix(in oklab, var(--color-brand) 16%, transparent);
56
+ background: var(--color-status-info-bg);
57
+ }
58
+
59
+ .row[data-current='true'] {
60
+ background: var(--color-bg-surface-subtle);
61
+ font-weight: 600;
26
62
  }
27
63
 
28
64
  .toggle,
@@ -82,13 +118,21 @@
82
118
  padding-inline: var(--spacing-xs);
83
119
  }
84
120
 
85
- .row:hover .toggle:not(:disabled),
86
- .row:hover .labelButton,
121
+ .row:hover {
122
+ background: var(--color-bg-hover-subtle);
123
+ }
124
+
87
125
  .toggle:focus-visible,
88
126
  .labelButton:focus-visible {
89
127
  background: var(--color-bg-hover-subtle);
90
128
  }
91
129
 
130
+ .toggle:not(:disabled):hover,
131
+ .toggle:not(:disabled):focus-visible {
132
+ background: var(--color-bg-pressed-subtle);
133
+ color: var(--color-fg-default);
134
+ }
135
+
92
136
  .toggle:focus-visible,
93
137
  .labelButton:focus-visible {
94
138
  outline: none;
@@ -23,6 +23,7 @@ export type TreeNode<T = unknown> = {
23
23
  /** Fetches one node's children. Called once per node, the first time it's expanded (and again on retry after a failed load). Presence of this prop on TreeView is what switches it into lazy mode. */
24
24
  export type LoadTreeChildren<T = unknown> = (node: TreeNode<T>) => Promise<TreeNode<T>[]>;
25
25
  export type TreeViewProps<T = unknown> = {
26
+ size?: 'sm' | 'md';
26
27
  /** Top-level nodes. In eager mode every node's full subtree must already be present via `children`. In lazy mode only the nodes you already know about need to be here - deeper levels arrive via `loadChildren`. */
27
28
  data: TreeNode<T>[];
28
29
  /** Omit for eager mode. Provide for lazy mode. */
@@ -33,7 +34,11 @@ export type TreeViewProps<T = unknown> = {
33
34
  expandedIds?: string[];
34
35
  onExpandedIdsChange?: (ids: string[]) => void;
35
36
  selectedId?: string;
37
+ /** Marks the page's current record independently from the preview selection. */
38
+ currentId?: string;
36
39
  onSelectNode?: (node: TreeNode<T>) => void;
40
+ /** Expand branches when their labels are activated, without collapsing already-open branches. */
41
+ expandOnSelect?: boolean;
37
42
  /** Customize how a node's row content renders; defaults to `node.icon` + `node.label`. */
38
43
  renderLabel?: (node: TreeNode<T>) => ReactNode;
39
44
  /** Allows node labels to wrap onto multiple lines. Set to false to truncate them to one line. */
@@ -42,5 +47,6 @@ export type TreeViewProps<T = unknown> = {
42
47
  /** Formats the error shown under a node whose `loadChildren` call rejected. */
43
48
  loadErrorMessage?: (error: unknown, node: TreeNode<T>) => ReactNode;
44
49
  className?: string;
50
+ 'aria-label'?: string;
45
51
  'data-testid'?: string;
46
52
  };