@dbcdk/react-components 0.0.191 → 0.0.193

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 (44) hide show
  1. package/dist/client.cjs +7 -0
  2. package/dist/client.d.ts +1 -0
  3. package/dist/client.js +1 -0
  4. package/dist/components/forms/input/Input.module.css +93 -0
  5. package/dist/components/json-viewer/JsonViewer.cjs +4 -2
  6. package/dist/components/json-viewer/JsonViewer.d.ts +2 -2
  7. package/dist/components/json-viewer/JsonViewer.js +5 -3
  8. package/dist/components/json-viewer/types.d.ts +2 -0
  9. package/dist/components/line-viewer/LineViewer.cjs +11 -3
  10. package/dist/components/line-viewer/LineViewer.d.ts +6 -1
  11. package/dist/components/line-viewer/LineViewer.js +12 -4
  12. package/dist/components/line-viewer/LineViewer.module.css +15 -2
  13. package/dist/components/popover/Popover.cjs +2 -1
  14. package/dist/components/popover/Popover.d.ts +8 -1
  15. package/dist/components/popover/Popover.js +2 -1
  16. package/dist/components/search-box/SearchBox.cjs +10 -7
  17. package/dist/components/search-box/SearchBox.d.ts +7 -0
  18. package/dist/components/search-box/SearchBox.js +10 -7
  19. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.cjs +2 -1
  20. package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.js +2 -1
  21. package/dist/components/tabs/Tabs.cjs +58 -56
  22. package/dist/components/tabs/Tabs.js +58 -56
  23. package/dist/components/tabs/Tabs.module.css +32 -16
  24. package/dist/components/timeline/Timeline.d.ts +1 -0
  25. package/dist/components/timeline/components/TimelineRow.cjs +1 -1
  26. package/dist/components/timeline/components/TimelineRow.js +1 -1
  27. package/dist/components/timeline/components/TimelineRow.module.css +4 -0
  28. package/dist/components/tree-view/TreeNodeRow.cjs +9 -1
  29. package/dist/components/tree-view/TreeNodeRow.d.ts +2 -1
  30. package/dist/components/tree-view/TreeNodeRow.js +9 -1
  31. package/dist/components/tree-view/TreeView.cjs +2 -0
  32. package/dist/components/tree-view/TreeView.d.ts +1 -1
  33. package/dist/components/tree-view/TreeView.js +2 -0
  34. package/dist/components/tree-view/TreeView.module.css +8 -0
  35. package/dist/components/tree-view/types.d.ts +2 -0
  36. package/dist/components/tree-view/useTreeExpansion.cjs +12 -2
  37. package/dist/components/tree-view/useTreeExpansion.d.ts +1 -0
  38. package/dist/components/tree-view/useTreeExpansion.js +12 -2
  39. package/dist/components/xml-viewer/XmlViewer.cjs +2 -1
  40. package/dist/components/xml-viewer/XmlViewer.js +3 -2
  41. package/dist/hooks/useTreeViewSettings.cjs +87 -0
  42. package/dist/hooks/useTreeViewSettings.d.ts +35 -0
  43. package/dist/hooks/useTreeViewSettings.js +84 -0
  44. package/package.json +1 -1
package/dist/client.cjs CHANGED
@@ -22,6 +22,7 @@ var useColorScheme = require('./hooks/useColorScheme');
22
22
  var useGetActiveTheme = require('./hooks/useGetActiveTheme');
23
23
  var useTheme = require('./hooks/useTheme');
24
24
  var usePersistentState = require('./hooks/usePersistentState');
25
+ var useTreeViewSettings = require('./hooks/useTreeViewSettings');
25
26
  var Chip = require('./components/chip/Chip');
26
27
  var Panel = require('./components/panel/Panel');
27
28
  var Card = require('./components/card/Card');
@@ -231,6 +232,12 @@ Object.keys(usePersistentState).forEach(function (k) {
231
232
  get: function () { return usePersistentState[k]; }
232
233
  });
233
234
  });
235
+ Object.keys(useTreeViewSettings).forEach(function (k) {
236
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
237
+ enumerable: true,
238
+ get: function () { return useTreeViewSettings[k]; }
239
+ });
240
+ });
234
241
  Object.keys(Chip).forEach(function (k) {
235
242
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
236
243
  enumerable: true,
package/dist/client.d.ts CHANGED
@@ -19,6 +19,7 @@ export * from './hooks/useColorScheme';
19
19
  export * from './hooks/useGetActiveTheme';
20
20
  export * from './hooks/useTheme';
21
21
  export * from './hooks/usePersistentState';
22
+ export * from './hooks/useTreeViewSettings';
22
23
  export * from './components/chip/Chip';
23
24
  export * from './components/panel/Panel';
24
25
  export * from './components/card/Card';
package/dist/client.js CHANGED
@@ -20,6 +20,7 @@ export * from './hooks/useColorScheme';
20
20
  export * from './hooks/useGetActiveTheme';
21
21
  export * from './hooks/useTheme';
22
22
  export * from './hooks/usePersistentState';
23
+ export * from './hooks/useTreeViewSettings';
23
24
  export * from './components/chip/Chip';
24
25
  export * from './components/panel/Panel';
25
26
  export * from './components/card/Card';
@@ -41,7 +41,12 @@
41
41
  flex: 1 1 auto;
42
42
  min-inline-size: 0;
43
43
  inline-size: 100%;
44
+ /* Size classes also apply to the field; keep the input inside its border. */
45
+ max-block-size: 100%;
44
46
  box-sizing: border-box;
47
+ /* Matches `.field`'s radius so the autofill box-shadow below (which paints
48
+ within this element's own box) doesn't show sharp corners under it. */
49
+ border-radius: inherit;
45
50
  text-overflow: ellipsis;
46
51
  color: var(--color-fg-default);
47
52
  background: transparent;
@@ -59,6 +64,94 @@
59
64
  color: var(--color-fg-subtle) !important;
60
65
  }
61
66
 
67
+ /* Match the design system's selection color instead of the browser default. */
68
+ .input::selection {
69
+ background-color: var(--color-bg-selected);
70
+ color: var(--color-fg-default);
71
+ }
72
+
73
+ .input::-moz-selection {
74
+ background-color: var(--color-bg-selected);
75
+ color: var(--color-fg-default);
76
+ }
77
+
78
+ /* Neutralize the browser's native autofill tint (Chrome's light-blue fill,
79
+ applied via this pseudo-class) so a filled field keeps the field's normal
80
+ background instead of the browser's own color - this also fires for
81
+ Chrome's "previous values typed in this field" history dropdown, which
82
+ uses the same autofill styling even though it's not real autofill data.
83
+ The huge transition delay is the standard trick to stop Chrome animating
84
+ its own background/text color in on top of this.
85
+
86
+ The field overlay below keeps the focus ring above this opaque fill. */
87
+ .input:-webkit-autofill,
88
+ .input:-webkit-autofill:hover {
89
+ -webkit-text-fill-color: var(--color-fg-default);
90
+ -webkit-box-shadow: 0 0 0 1000px var(--color-bg-surface) inset;
91
+ box-shadow: 0 0 0 1000px var(--color-bg-surface) inset;
92
+ transition:
93
+ background-color 600000s 0s,
94
+ color 600000s 0s;
95
+ }
96
+
97
+ .subtle .input:-webkit-autofill,
98
+ .subtle .input:-webkit-autofill:hover {
99
+ -webkit-box-shadow: 0 0 0 1000px var(--color-bg-toolbar) inset;
100
+ box-shadow: 0 0 0 1000px var(--color-bg-toolbar) inset;
101
+ }
102
+
103
+ .embedded .input:-webkit-autofill,
104
+ .embedded .input:-webkit-autofill:hover,
105
+ .embedded .input:-webkit-autofill:focus {
106
+ -webkit-box-shadow: 0 0 0 1000px transparent inset;
107
+ box-shadow: 0 0 0 1000px transparent inset;
108
+ }
109
+
110
+ .header .input:-webkit-autofill,
111
+ .header .input:-webkit-autofill:hover {
112
+ -webkit-box-shadow: 0 0 0 1000px transparent inset;
113
+ box-shadow: 0 0 0 1000px transparent inset;
114
+ }
115
+
116
+ .header .input:-webkit-autofill {
117
+ -webkit-text-fill-color: var(--color-navbar-fg);
118
+ }
119
+
120
+ /* Paint over the autofill fill using the whole field's geometry, including
121
+ adornments. A ring on the input itself creates an extra inner rectangle.
122
+ Keep this overlay non-interactive so clear buttons remain clickable. */
123
+ .field:has(.input:-webkit-autofill)::after {
124
+ content: '';
125
+ position: absolute;
126
+ inset: 0;
127
+ border-radius: inherit;
128
+ pointer-events: none;
129
+ box-shadow: inset 0 0 0 var(--border-width-thin)
130
+ var(--input-autofill-ring, var(--color-field-focus));
131
+ opacity: 0;
132
+ transition: opacity var(--transition-fast) var(--ease-standard);
133
+ }
134
+
135
+ .field:has(.input:-webkit-autofill):focus-within:not([aria-disabled='true'])::after {
136
+ opacity: 1;
137
+ }
138
+
139
+ .header {
140
+ --input-autofill-ring: var(--color-navbar-fg);
141
+ }
142
+
143
+ .modified {
144
+ --input-autofill-ring: color-mix(
145
+ in srgb,
146
+ var(--color-status-warning-border) 55%,
147
+ var(--color-border-default)
148
+ );
149
+ }
150
+
151
+ .embedded:has(.input:-webkit-autofill)::after {
152
+ content: none;
153
+ }
154
+
62
155
  .input:disabled {
63
156
  background-color: transparent;
64
157
  color: var(--color-disabled-fg);
@@ -12,6 +12,7 @@ var styles = require('./JsonViewer.module.css');
12
12
  var useClipboardStatus = require('./useClipboardStatus');
13
13
  var utils = require('./utils');
14
14
  var Button = require('../button/Button');
15
+ var Icon = require('../icon/Icon');
15
16
 
16
17
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
17
18
 
@@ -22,6 +23,7 @@ function JsonViewer({
22
23
  value,
23
24
  defaultExpandedDepth = 2,
24
25
  expandAll = false,
26
+ defaultViewMode = "tree",
25
27
  searchDebounceMs = 800,
26
28
  helperText,
27
29
  searchPlaceholder = "S\xF8g i n\xF8gler, stier og v\xE6rdier",
@@ -43,7 +45,7 @@ function JsonViewer({
43
45
  validate: (stored) => stored === "dark" || stored === "light"
44
46
  });
45
47
  const { value: viewMode, setValue: setViewMode } = usePersistentState.usePersistentState({
46
- initialValue: "tree",
48
+ initialValue: defaultViewMode,
47
49
  storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
48
50
  validate: (stored) => stored === "tree" || stored === "raw"
49
51
  });
@@ -151,7 +153,7 @@ function JsonViewer({
151
153
  "aria-haspopup": "menu",
152
154
  "aria-expanded": isOpen ? true : false,
153
155
  onClick: toggle,
154
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { "aria-hidden": "true" })
156
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { customIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, { "aria-hidden": "true" }) })
155
157
  }
156
158
  ),
157
159
  children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
@@ -1,4 +1,4 @@
1
1
  import type { JSX } from 'react';
2
2
  import type { JsonViewerProps } from './types';
3
- export type { JsonViewerProps } from './types';
4
- export declare function JsonViewer({ value, defaultExpandedDepth, expandAll, searchDebounceMs, helperText, searchPlaceholder, emptySearchText, className, maxHeight, appearance, storageKey, borderless, }: JsonViewerProps): JSX.Element;
3
+ export type { JsonViewerProps, JsonViewerViewMode } from './types';
4
+ export declare function JsonViewer({ value, defaultExpandedDepth, expandAll, defaultViewMode, searchDebounceMs, helperText, searchPlaceholder, emptySearchText, className, maxHeight, appearance, storageKey, borderless, }: JsonViewerProps): JSX.Element;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { Search, X, ArrowDown, ArrowUp, ListTree, Braces, Sun, Moon, ClipboardCopy, MoreVertical } from 'lucide-react';
3
+ import { Search, X, ArrowDown, ArrowUp, ListTree, Braces, Sun, Moon, ClipboardCopy, Settings2 } from 'lucide-react';
4
4
  import { useState, useId, useEffect, useMemo } from 'react';
5
5
  import { Menu } from '../../components/menu/Menu';
6
6
  import { Popover } from '../../components/popover/Popover';
@@ -10,12 +10,14 @@ import styles from './JsonViewer.module.css';
10
10
  import { useClipboardStatus } from './useClipboardStatus';
11
11
  import { normalizeSearch, isJsonValue, collectSearchMatches, collectExpandableNodeIds, collectInitiallyExpandedNodeIds } from './utils';
12
12
  import { Button } from '../button/Button';
13
+ import { Icon } from '../icon/Icon';
13
14
 
14
15
  const COPY_ALL_ID = "__json-viewer-copy-all__";
15
16
  function JsonViewer({
16
17
  value,
17
18
  defaultExpandedDepth = 2,
18
19
  expandAll = false,
20
+ defaultViewMode = "tree",
19
21
  searchDebounceMs = 800,
20
22
  helperText,
21
23
  searchPlaceholder = "S\xF8g i n\xF8gler, stier og v\xE6rdier",
@@ -37,7 +39,7 @@ function JsonViewer({
37
39
  validate: (stored) => stored === "dark" || stored === "light"
38
40
  });
39
41
  const { value: viewMode, setValue: setViewMode } = usePersistentState({
40
- initialValue: "tree",
42
+ initialValue: defaultViewMode,
41
43
  storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
42
44
  validate: (stored) => stored === "tree" || stored === "raw"
43
45
  });
@@ -145,7 +147,7 @@ function JsonViewer({
145
147
  "aria-haspopup": "menu",
146
148
  "aria-expanded": isOpen ? true : false,
147
149
  onClick: toggle,
148
- children: /* @__PURE__ */ jsx(MoreVertical, { "aria-hidden": "true" })
150
+ children: /* @__PURE__ */ jsx(Icon, { customIcon: /* @__PURE__ */ jsx(Settings2, { "aria-hidden": "true" }) })
149
151
  }
150
152
  ),
151
153
  children: (close) => /* @__PURE__ */ jsxs(Menu, { children: [
@@ -8,10 +8,12 @@ export type SearchMatch = {
8
8
  descendant: boolean;
9
9
  };
10
10
  export type JsonViewerAppearance = 'dark' | 'light';
11
+ export type JsonViewerViewMode = 'tree' | 'raw';
11
12
  export interface JsonViewerProps {
12
13
  value: unknown;
13
14
  defaultExpandedDepth?: number;
14
15
  expandAll?: boolean;
16
+ defaultViewMode?: JsonViewerViewMode;
15
17
  searchDebounceMs?: number;
16
18
  helperText?: string;
17
19
  searchPlaceholder?: string;
@@ -10,6 +10,7 @@ var usePersistentState = require('../../hooks/usePersistentState');
10
10
  var styles = require('./LineViewer.module.css');
11
11
  var tokenizeLineFormat = require('./tokenizeLineFormat');
12
12
  var Button = require('../button/Button');
13
+ var Icon = require('../icon/Icon');
13
14
 
14
15
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
16
 
@@ -29,6 +30,8 @@ function LineViewer({
29
30
  lines,
30
31
  size = "md",
31
32
  appearance = "dark",
33
+ defaultViewMode = "highlighted",
34
+ deleted = false,
32
35
  storageKey,
33
36
  borderless = false
34
37
  }) {
@@ -40,7 +43,7 @@ function LineViewer({
40
43
  validate: (stored) => stored === "dark" || stored === "light"
41
44
  });
42
45
  const { value: viewMode, setValue: setViewMode } = usePersistentState.usePersistentState({
43
- initialValue: "highlighted",
46
+ initialValue: defaultViewMode,
44
47
  storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
45
48
  validate: (stored) => stored === "highlighted" || stored === "raw"
46
49
  });
@@ -87,7 +90,7 @@ function LineViewer({
87
90
  "aria-haspopup": "menu",
88
91
  "aria-expanded": isOpen ? true : false,
89
92
  onClick: toggle,
90
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { "aria-hidden": "true" })
93
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { customIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, { "aria-hidden": "true" }) })
91
94
  }
92
95
  ),
93
96
  children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
@@ -157,7 +160,12 @@ function LineViewer({
157
160
  /* @__PURE__ */ jsxRuntime.jsx(
158
161
  "pre",
159
162
  {
160
- className: [styles__default.default.codePane, styles__default.default[size], wrap ? styles__default.default.wrap : styles__default.default.noWrap].join(" "),
163
+ className: [
164
+ styles__default.default.codePane,
165
+ styles__default.default[size],
166
+ wrap ? styles__default.default.wrap : styles__default.default.noWrap,
167
+ deleted ? styles__default.default.deleted : ""
168
+ ].filter(Boolean).join(" "),
161
169
  tabIndex: 0,
162
170
  onDoubleClick: handleDoubleClick,
163
171
  children: /* @__PURE__ */ jsxRuntime.jsx("code", { ref: codeRef, children: viewMode === "raw" ? lines : tokens.map((token, index) => {
@@ -1,10 +1,15 @@
1
1
  import type { JSX } from 'react';
2
2
  export type LineViewerAppearance = 'dark' | 'light';
3
+ export type LineViewerViewMode = 'highlighted' | 'raw';
3
4
  export interface LineViewerProps {
4
5
  lines: string;
5
6
  size?: 'xs' | 'sm' | 'md' | 'lg';
6
7
  /** Initial appearance. The user can toggle it via the kebab menu; defaults to 'dark'. */
7
8
  appearance?: LineViewerAppearance;
9
+ /** Initial view mode. The user can toggle it via the kebab menu; defaults to 'highlighted'. */
10
+ defaultViewMode?: LineViewerViewMode;
11
+ /** Displays all line text in the theme's error color, for deleted or invalid content. */
12
+ deleted?: boolean;
8
13
  /**
9
14
  * When set, the user's appearance/view-mode/wrap choices are persisted to
10
15
  * localStorage under `${storageKey}:appearance` etc.
@@ -17,4 +22,4 @@ export interface LineViewerProps {
17
22
  */
18
23
  borderless?: boolean;
19
24
  }
20
- export declare function LineViewer({ lines, size, appearance, storageKey, borderless, }: LineViewerProps): JSX.Element;
25
+ export declare function LineViewer({ lines, size, appearance, defaultViewMode, deleted, storageKey, borderless, }: LineViewerProps): JSX.Element;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { TextWrap, ListTree, Code2, Sun, Moon, ClipboardCopy, MoreVertical } from 'lucide-react';
3
+ import { TextWrap, ListTree, Code2, Sun, Moon, ClipboardCopy, Settings2 } from 'lucide-react';
4
4
  import { useMemo, useRef } from 'react';
5
5
  import { Menu } from '../../components/menu/Menu';
6
6
  import { Popover } from '../../components/popover/Popover';
@@ -8,6 +8,7 @@ import { usePersistentState } from '../../hooks/usePersistentState';
8
8
  import styles from './LineViewer.module.css';
9
9
  import { tokenizeLineFormat } from './tokenizeLineFormat';
10
10
  import { Button } from '../button/Button';
11
+ import { Icon } from '../icon/Icon';
11
12
 
12
13
  const TOKEN_CLASS = {
13
14
  tag: styles.tag,
@@ -23,6 +24,8 @@ function LineViewer({
23
24
  lines,
24
25
  size = "md",
25
26
  appearance = "dark",
27
+ defaultViewMode = "highlighted",
28
+ deleted = false,
26
29
  storageKey,
27
30
  borderless = false
28
31
  }) {
@@ -34,7 +37,7 @@ function LineViewer({
34
37
  validate: (stored) => stored === "dark" || stored === "light"
35
38
  });
36
39
  const { value: viewMode, setValue: setViewMode } = usePersistentState({
37
- initialValue: "highlighted",
40
+ initialValue: defaultViewMode,
38
41
  storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
39
42
  validate: (stored) => stored === "highlighted" || stored === "raw"
40
43
  });
@@ -81,7 +84,7 @@ function LineViewer({
81
84
  "aria-haspopup": "menu",
82
85
  "aria-expanded": isOpen ? true : false,
83
86
  onClick: toggle,
84
- children: /* @__PURE__ */ jsx(MoreVertical, { "aria-hidden": "true" })
87
+ children: /* @__PURE__ */ jsx(Icon, { customIcon: /* @__PURE__ */ jsx(Settings2, { "aria-hidden": "true" }) })
85
88
  }
86
89
  ),
87
90
  children: (close) => /* @__PURE__ */ jsxs(Menu, { children: [
@@ -151,7 +154,12 @@ function LineViewer({
151
154
  /* @__PURE__ */ jsx(
152
155
  "pre",
153
156
  {
154
- className: [styles.codePane, styles[size], wrap ? styles.wrap : styles.noWrap].join(" "),
157
+ className: [
158
+ styles.codePane,
159
+ styles[size],
160
+ wrap ? styles.wrap : styles.noWrap,
161
+ deleted ? styles.deleted : ""
162
+ ].filter(Boolean).join(" "),
155
163
  tabIndex: 0,
156
164
  onDoubleClick: handleDoubleClick,
157
165
  children: /* @__PURE__ */ jsx("code", { ref: codeRef, children: viewMode === "raw" ? lines : tokens.map((token, index) => {
@@ -5,9 +5,17 @@
5
5
 
6
6
  --line-tag: color-mix(in oklab, var(--color-fg-inverse) 66%, var(--color-syntax-accent) 34%);
7
7
  --line-indicator: color-mix(in oklab, var(--color-fg-inverse) 46%, transparent);
8
- --line-subfield-code: color-mix(in oklab, var(--color-fg-inverse) 30%, var(--color-syntax-number) 70%);
8
+ --line-subfield-code: color-mix(
9
+ in oklab,
10
+ var(--color-fg-inverse) 30%,
11
+ var(--color-syntax-number) 70%
12
+ );
9
13
  --line-value: color-mix(in oklab, var(--color-fg-inverse) 20%, var(--color-syntax-string) 80%);
10
- --line-terminator: color-mix(in oklab, var(--color-fg-inverse) 30%, var(--color-syntax-boolean) 70%);
14
+ --line-terminator: color-mix(
15
+ in oklab,
16
+ var(--color-fg-inverse) 30%,
17
+ var(--color-syntax-boolean) 70%
18
+ );
11
19
  --line-punctuation: color-mix(in oklab, var(--color-fg-inverse) 60%, transparent);
12
20
  --line-continuation: color-mix(in oklab, var(--color-fg-inverse) 46%, transparent);
13
21
 
@@ -57,6 +65,11 @@
57
65
  line-height: 1.35;
58
66
  }
59
67
 
68
+ .deleted code,
69
+ .deleted code * {
70
+ color: var(--color-status-error);
71
+ }
72
+
60
73
  .wrap {
61
74
  white-space: pre-wrap;
62
75
  overflow-wrap: break-word;
@@ -145,7 +145,7 @@ const Popover = React.forwardRef(function Popover2({
145
145
  React.useImperativeHandle(
146
146
  ref,
147
147
  () => ({
148
- close: () => closePopover("api"),
148
+ close: (opts) => closePopover((opts == null ? void 0 : opts.returnFocus) === false ? "dismiss" : "api"),
149
149
  open: openPopover,
150
150
  isOpen: () => isOpen
151
151
  }),
@@ -265,6 +265,7 @@ const Popover = React.forwardRef(function Popover2({
265
265
  if (isOpen) return;
266
266
  if (!returnFocus) return;
267
267
  if (lastCloseReasonRef.current === "outside") return;
268
+ if (lastCloseReasonRef.current === "dismiss") return;
268
269
  (_b = (_a = triggerElRef.current) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
269
270
  }, [isOpen, returnFocus]);
270
271
  const chevronClassName = variant === "header" ? styles__default.default.chevronHeader : void 0;
@@ -22,7 +22,14 @@ export interface PopoverProps {
22
22
  variant?: 'default' | 'header';
23
23
  }
24
24
  export interface PopoverHandle {
25
- close: () => void;
25
+ /**
26
+ * Pass `{ returnFocus: false }` to close without focus returning to the
27
+ * trigger afterward - e.g. when the caller is about to navigate away or
28
+ * move focus itself, so the trigger shouldn't reclaim it back.
29
+ */
30
+ close: (opts?: {
31
+ returnFocus?: boolean;
32
+ }) => void;
26
33
  open: () => void;
27
34
  isOpen: () => boolean;
28
35
  }
@@ -121,7 +121,7 @@ const Popover = forwardRef(function Popover2({
121
121
  useImperativeHandle(
122
122
  ref,
123
123
  () => ({
124
- close: () => closePopover("api"),
124
+ close: (opts) => closePopover((opts == null ? void 0 : opts.returnFocus) === false ? "dismiss" : "api"),
125
125
  open: openPopover,
126
126
  isOpen: () => isOpen
127
127
  }),
@@ -241,6 +241,7 @@ const Popover = forwardRef(function Popover2({
241
241
  if (isOpen) return;
242
242
  if (!returnFocus) return;
243
243
  if (lastCloseReasonRef.current === "outside") return;
244
+ if (lastCloseReasonRef.current === "dismiss") return;
244
245
  (_b = (_a = triggerElRef.current) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
245
246
  }, [isOpen, returnFocus]);
246
247
  const chevronClassName = variant === "header" ? styles.chevronHeader : void 0;
@@ -27,6 +27,7 @@ const SearchBox = react.forwardRef(function SearchBoxInner({
27
27
  resultKeys,
28
28
  resultTemplate,
29
29
  initialTemplate,
30
+ initialTemplateOnly = false,
30
31
  popoverMinWidth = "500px",
31
32
  noResultText = "Ingen resultater",
32
33
  loading,
@@ -99,34 +100,36 @@ const SearchBox = react.forwardRef(function SearchBoxInner({
99
100
  }, [enableHotkey]);
100
101
  const hasInitialTemplate = initialTemplate !== void 0 && initialTemplate !== null;
101
102
  const hasQuery = draft.trim().length > 0;
102
- const canShowPopover = hasQuery || hasInitialTemplate;
103
+ const canShowPopover = initialTemplateOnly ? !hasQuery && hasInitialTemplate : hasQuery || hasInitialTemplate;
103
104
  const handleChange = react.useCallback(
104
105
  (e) => {
105
106
  var _a2, _b, _c;
106
107
  const nextDraft = e.target.value;
107
108
  const nextHasQuery = nextDraft.trim().length > 0;
108
109
  setDraft(nextDraft);
109
- if (nextHasQuery || hasInitialTemplate) {
110
+ const nextCanShow = initialTemplateOnly ? !nextHasQuery && hasInitialTemplate : nextHasQuery || hasInitialTemplate;
111
+ if (nextCanShow) {
110
112
  if (!((_a2 = popoverRef.current) == null ? void 0 : _a2.isOpen())) (_b = popoverRef.current) == null ? void 0 : _b.open();
111
113
  } else {
112
114
  (_c = popoverRef.current) == null ? void 0 : _c.close();
113
115
  }
114
116
  onChange == null ? void 0 : onChange(e);
115
117
  },
116
- [hasInitialTemplate, onChange]
118
+ [hasInitialTemplate, initialTemplateOnly, onChange]
117
119
  );
118
120
  const handleSelect = react.useCallback(
119
121
  (item) => {
120
122
  onSelect == null ? void 0 : onSelect(item);
121
- reset();
123
+ reset({ returnFocus: false });
124
+ onSearch == null ? void 0 : onSearch("");
122
125
  },
123
- [onSelect]
126
+ [onSelect, onSearch]
124
127
  );
125
- function reset() {
128
+ function reset(opts) {
126
129
  var _a2;
127
130
  setDraft("");
128
131
  setActiveIndex(null);
129
- (_a2 = popoverRef.current) == null ? void 0 : _a2.close();
132
+ (_a2 = popoverRef.current) == null ? void 0 : _a2.close(opts);
130
133
  }
131
134
  const handleClear = react.useCallback(() => {
132
135
  var _a2;
@@ -15,6 +15,13 @@ export type SearchBoxProps<T extends Record<string, unknown>> = Omit<InputProps,
15
15
  onSelect?: (item: T) => void;
16
16
  displayPopover?: boolean;
17
17
  initialTemplate?: React.ReactNode;
18
+ /**
19
+ * When true, the popover only ever shows `initialTemplate` (on an empty
20
+ * field) and never opens once there's a query - for a box with no live
21
+ * results/resultTemplate of its own (e.g. one that just navigates via a
22
+ * URL param), so it doesn't pop open an empty dropdown while typing.
23
+ */
24
+ initialTemplateOnly?: boolean;
18
25
  noResultText?: string;
19
26
  popoverMinWidth?: string;
20
27
  loading?: boolean;
@@ -21,6 +21,7 @@ const SearchBox = forwardRef(function SearchBoxInner({
21
21
  resultKeys,
22
22
  resultTemplate,
23
23
  initialTemplate,
24
+ initialTemplateOnly = false,
24
25
  popoverMinWidth = "500px",
25
26
  noResultText = "Ingen resultater",
26
27
  loading,
@@ -93,34 +94,36 @@ const SearchBox = forwardRef(function SearchBoxInner({
93
94
  }, [enableHotkey]);
94
95
  const hasInitialTemplate = initialTemplate !== void 0 && initialTemplate !== null;
95
96
  const hasQuery = draft.trim().length > 0;
96
- const canShowPopover = hasQuery || hasInitialTemplate;
97
+ const canShowPopover = initialTemplateOnly ? !hasQuery && hasInitialTemplate : hasQuery || hasInitialTemplate;
97
98
  const handleChange = useCallback(
98
99
  (e) => {
99
100
  var _a2, _b, _c;
100
101
  const nextDraft = e.target.value;
101
102
  const nextHasQuery = nextDraft.trim().length > 0;
102
103
  setDraft(nextDraft);
103
- if (nextHasQuery || hasInitialTemplate) {
104
+ const nextCanShow = initialTemplateOnly ? !nextHasQuery && hasInitialTemplate : nextHasQuery || hasInitialTemplate;
105
+ if (nextCanShow) {
104
106
  if (!((_a2 = popoverRef.current) == null ? void 0 : _a2.isOpen())) (_b = popoverRef.current) == null ? void 0 : _b.open();
105
107
  } else {
106
108
  (_c = popoverRef.current) == null ? void 0 : _c.close();
107
109
  }
108
110
  onChange == null ? void 0 : onChange(e);
109
111
  },
110
- [hasInitialTemplate, onChange]
112
+ [hasInitialTemplate, initialTemplateOnly, onChange]
111
113
  );
112
114
  const handleSelect = useCallback(
113
115
  (item) => {
114
116
  onSelect == null ? void 0 : onSelect(item);
115
- reset();
117
+ reset({ returnFocus: false });
118
+ onSearch == null ? void 0 : onSearch("");
116
119
  },
117
- [onSelect]
120
+ [onSelect, onSearch]
118
121
  );
119
- function reset() {
122
+ function reset(opts) {
120
123
  var _a2;
121
124
  setDraft("");
122
125
  setActiveIndex(null);
123
- (_a2 = popoverRef.current) == null ? void 0 : _a2.close();
126
+ (_a2 = popoverRef.current) == null ? void 0 : _a2.close(opts);
124
127
  }
125
128
  const handleClear = useCallback(() => {
126
129
  var _a2;
@@ -4,6 +4,7 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var lucideReact = require('lucide-react');
6
6
  var React = require('react');
7
+ var Icon = require('../../../../components/icon/Icon');
7
8
  var Button = require('../../../button/Button');
8
9
  var Menu = require('../../../menu/Menu');
9
10
  var Popover = require('../../../popover/Popover');
@@ -73,7 +74,7 @@ const SidenavFiltering = ({
73
74
  variant: "outlined",
74
75
  "aria-label": "\xC5bn indstillinger for sidemenu",
75
76
  onClick: toggle,
76
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, {})
77
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { customIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, { "aria-hidden": "true" }) })
77
78
  }
78
79
  ),
79
80
  children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu, { children: /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { active: wrapItemText, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2,6 +2,7 @@
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { Search, Settings2 } from 'lucide-react';
4
4
  import React from 'react';
5
+ import { Icon } from '../../../../components/icon/Icon';
5
6
  import { Button } from '../../../button/Button';
6
7
  import { Menu } from '../../../menu/Menu';
7
8
  import { Popover } from '../../../popover/Popover';
@@ -67,7 +68,7 @@ const SidenavFiltering = ({
67
68
  variant: "outlined",
68
69
  "aria-label": "\xC5bn indstillinger for sidemenu",
69
70
  onClick: toggle,
70
- icon: /* @__PURE__ */ jsx(Settings2, {})
71
+ icon: /* @__PURE__ */ jsx(Icon, { customIcon: /* @__PURE__ */ jsx(Settings2, { "aria-hidden": "true" }) })
71
72
  }
72
73
  ),
73
74
  children: (close) => /* @__PURE__ */ jsx(Menu, { children: /* @__PURE__ */ jsx(Menu.Item, { active: wrapItemText, children: /* @__PURE__ */ jsx(