@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.
- package/dist/client.cjs +7 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +1 -0
- package/dist/components/forms/input/Input.module.css +93 -0
- package/dist/components/json-viewer/JsonViewer.cjs +4 -2
- package/dist/components/json-viewer/JsonViewer.d.ts +2 -2
- package/dist/components/json-viewer/JsonViewer.js +5 -3
- package/dist/components/json-viewer/types.d.ts +2 -0
- package/dist/components/line-viewer/LineViewer.cjs +11 -3
- package/dist/components/line-viewer/LineViewer.d.ts +6 -1
- package/dist/components/line-viewer/LineViewer.js +12 -4
- package/dist/components/line-viewer/LineViewer.module.css +15 -2
- package/dist/components/popover/Popover.cjs +2 -1
- package/dist/components/popover/Popover.d.ts +8 -1
- package/dist/components/popover/Popover.js +2 -1
- package/dist/components/search-box/SearchBox.cjs +10 -7
- package/dist/components/search-box/SearchBox.d.ts +7 -0
- package/dist/components/search-box/SearchBox.js +10 -7
- package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.cjs +2 -1
- package/dist/components/sidebar/components/sidenav-filteirng/SidenavFiltering.js +2 -1
- package/dist/components/tabs/Tabs.cjs +58 -56
- package/dist/components/tabs/Tabs.js +58 -56
- package/dist/components/tabs/Tabs.module.css +32 -16
- package/dist/components/timeline/Timeline.d.ts +1 -0
- package/dist/components/timeline/components/TimelineRow.cjs +1 -1
- package/dist/components/timeline/components/TimelineRow.js +1 -1
- package/dist/components/timeline/components/TimelineRow.module.css +4 -0
- package/dist/components/tree-view/TreeNodeRow.cjs +9 -1
- package/dist/components/tree-view/TreeNodeRow.d.ts +2 -1
- package/dist/components/tree-view/TreeNodeRow.js +9 -1
- package/dist/components/tree-view/TreeView.cjs +2 -0
- package/dist/components/tree-view/TreeView.d.ts +1 -1
- package/dist/components/tree-view/TreeView.js +2 -0
- package/dist/components/tree-view/TreeView.module.css +8 -0
- package/dist/components/tree-view/types.d.ts +2 -0
- package/dist/components/tree-view/useTreeExpansion.cjs +12 -2
- package/dist/components/tree-view/useTreeExpansion.d.ts +1 -0
- package/dist/components/tree-view/useTreeExpansion.js +12 -2
- package/dist/components/xml-viewer/XmlViewer.cjs +2 -1
- package/dist/components/xml-viewer/XmlViewer.js +3 -2
- package/dist/hooks/useTreeViewSettings.cjs +87 -0
- package/dist/hooks/useTreeViewSettings.d.ts +35 -0
- package/dist/hooks/useTreeViewSettings.js +84 -0
- 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:
|
|
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.
|
|
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,
|
|
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:
|
|
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(
|
|
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:
|
|
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.
|
|
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: [
|
|
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,
|
|
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:
|
|
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(
|
|
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: [
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|