@dbcdk/react-components 0.0.182 → 0.0.183
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 +21 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +3 -0
- package/dist/components/clear-button/ClearButton.cjs +7 -2
- package/dist/components/clear-button/ClearButton.d.ts +8 -1
- package/dist/components/clear-button/ClearButton.js +7 -2
- package/dist/components/clear-button/ClearButton.module.css +12 -0
- package/dist/components/forms/select/Select.cjs +2 -1
- package/dist/components/forms/select/Select.js +2 -1
- package/dist/components/json-viewer/JsonViewer.cjs +3 -2
- package/dist/components/json-viewer/JsonViewer.d.ts +1 -1
- package/dist/components/json-viewer/JsonViewer.js +3 -2
- package/dist/components/json-viewer/JsonViewer.module.css +7 -0
- package/dist/components/json-viewer/types.d.ts +6 -0
- package/dist/components/line-viewer/LineViewer.cjs +174 -0
- package/dist/components/line-viewer/LineViewer.d.ts +20 -0
- package/dist/components/line-viewer/LineViewer.js +168 -0
- package/dist/components/line-viewer/LineViewer.module.css +112 -0
- package/dist/components/line-viewer/tokenizeLineFormat.cjs +52 -0
- package/dist/components/line-viewer/tokenizeLineFormat.d.ts +14 -0
- package/dist/components/line-viewer/tokenizeLineFormat.js +50 -0
- package/dist/components/tree-view/TreeNodeRow.cjs +99 -0
- package/dist/components/tree-view/TreeNodeRow.d.ts +18 -0
- package/dist/components/tree-view/TreeNodeRow.js +93 -0
- package/dist/components/tree-view/TreeView.cjs +93 -0
- package/dist/components/tree-view/TreeView.d.ts +20 -0
- package/dist/components/tree-view/TreeView.js +79 -0
- package/dist/components/tree-view/TreeView.module.css +141 -0
- package/dist/components/tree-view/types.cjs +2 -0
- package/dist/components/tree-view/types.d.ts +44 -0
- package/dist/components/tree-view/types.js +1 -0
- package/dist/components/tree-view/useTreeExpansion.cjs +47 -0
- package/dist/components/tree-view/useTreeExpansion.d.ts +17 -0
- package/dist/components/tree-view/useTreeExpansion.js +45 -0
- package/dist/components/tree-view/utils.cjs +32 -0
- package/dist/components/tree-view/utils.d.ts +16 -0
- package/dist/components/tree-view/utils.js +29 -0
- package/dist/components/xml-viewer/XmlViewer.cjs +175 -0
- package/dist/components/xml-viewer/XmlViewer.d.ts +20 -0
- package/dist/components/xml-viewer/XmlViewer.js +169 -0
- package/dist/components/xml-viewer/XmlViewer.module.css +109 -0
- package/dist/components/xml-viewer/tokenizeXml.cjs +50 -0
- package/dist/components/xml-viewer/tokenizeXml.d.ts +12 -0
- package/dist/components/xml-viewer/tokenizeXml.js +48 -0
- package/dist/index.cjs +7 -0
- package/dist/index.css +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/date/formatDate.cjs +29 -17
- package/dist/utils/date/formatDate.d.ts +7 -0
- package/dist/utils/date/formatDate.js +29 -17
- package/package.json +1 -1
package/dist/client.cjs
CHANGED
|
@@ -40,6 +40,7 @@ var severity_types = require('./constants/severity.types');
|
|
|
40
40
|
var Textarea = require('./components/forms/text-area/Textarea');
|
|
41
41
|
var AppHeader = require('./components/app-header/AppHeader');
|
|
42
42
|
var Sidebar = require('./components/sidebar/Sidebar');
|
|
43
|
+
var TreeView = require('./components/tree-view/TreeView');
|
|
43
44
|
var nestedFiltering = require('./utils/arrays/nested-filtering');
|
|
44
45
|
var MultiSelect = require('./components/forms/multi-select/MultiSelect');
|
|
45
46
|
var useViewportFill = require('./hooks/useViewportFill');
|
|
@@ -59,6 +60,8 @@ var Pagination = require('./components/pagination/Pagination');
|
|
|
59
60
|
var MetaBar = require('./components/meta-bar/MetaBar');
|
|
60
61
|
var CodeBlock = require('./components/code-block/CodeBlock');
|
|
61
62
|
var JsonViewer = require('./components/json-viewer/JsonViewer');
|
|
63
|
+
var XmlViewer = require('./components/xml-viewer/XmlViewer');
|
|
64
|
+
var LineViewer = require('./components/line-viewer/LineViewer');
|
|
62
65
|
var useTimeDuration = require('./hooks/useTimeDuration');
|
|
63
66
|
var useSorting = require('./hooks/useSorting');
|
|
64
67
|
var usePagination = require('./hooks/usePagination');
|
|
@@ -330,6 +333,12 @@ Object.keys(Sidebar).forEach(function (k) {
|
|
|
330
333
|
get: function () { return Sidebar[k]; }
|
|
331
334
|
});
|
|
332
335
|
});
|
|
336
|
+
Object.keys(TreeView).forEach(function (k) {
|
|
337
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
338
|
+
enumerable: true,
|
|
339
|
+
get: function () { return TreeView[k]; }
|
|
340
|
+
});
|
|
341
|
+
});
|
|
333
342
|
Object.keys(nestedFiltering).forEach(function (k) {
|
|
334
343
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
335
344
|
enumerable: true,
|
|
@@ -444,6 +453,18 @@ Object.keys(JsonViewer).forEach(function (k) {
|
|
|
444
453
|
get: function () { return JsonViewer[k]; }
|
|
445
454
|
});
|
|
446
455
|
});
|
|
456
|
+
Object.keys(XmlViewer).forEach(function (k) {
|
|
457
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
458
|
+
enumerable: true,
|
|
459
|
+
get: function () { return XmlViewer[k]; }
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
Object.keys(LineViewer).forEach(function (k) {
|
|
463
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
464
|
+
enumerable: true,
|
|
465
|
+
get: function () { return LineViewer[k]; }
|
|
466
|
+
});
|
|
467
|
+
});
|
|
447
468
|
Object.keys(useTimeDuration).forEach(function (k) {
|
|
448
469
|
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
449
470
|
enumerable: true,
|
package/dist/client.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export * from './constants/severity.types';
|
|
|
37
37
|
export * from './components/forms/text-area/Textarea';
|
|
38
38
|
export * from './components/app-header/AppHeader';
|
|
39
39
|
export * from './components/sidebar/Sidebar';
|
|
40
|
+
export * from './components/tree-view/TreeView';
|
|
40
41
|
export * from './utils/arrays/nested-filtering';
|
|
41
42
|
export * from './components/forms/multi-select/MultiSelect';
|
|
42
43
|
export * from './hooks/useViewportFill';
|
|
@@ -56,6 +57,8 @@ export * from './components/pagination/Pagination';
|
|
|
56
57
|
export * from './components/meta-bar/MetaBar';
|
|
57
58
|
export * from './components/code-block/CodeBlock';
|
|
58
59
|
export * from './components/json-viewer/JsonViewer';
|
|
60
|
+
export * from './components/xml-viewer/XmlViewer';
|
|
61
|
+
export * from './components/line-viewer/LineViewer';
|
|
59
62
|
export * from './hooks/useTimeDuration';
|
|
60
63
|
export * from './hooks/useSorting';
|
|
61
64
|
export * from './hooks/usePagination';
|
package/dist/client.js
CHANGED
|
@@ -38,6 +38,7 @@ export * from './constants/severity.types';
|
|
|
38
38
|
export * from './components/forms/text-area/Textarea';
|
|
39
39
|
export * from './components/app-header/AppHeader';
|
|
40
40
|
export * from './components/sidebar/Sidebar';
|
|
41
|
+
export * from './components/tree-view/TreeView';
|
|
41
42
|
export * from './utils/arrays/nested-filtering';
|
|
42
43
|
export * from './components/forms/multi-select/MultiSelect';
|
|
43
44
|
export * from './hooks/useViewportFill';
|
|
@@ -57,6 +58,8 @@ export * from './components/pagination/Pagination';
|
|
|
57
58
|
export * from './components/meta-bar/MetaBar';
|
|
58
59
|
export * from './components/code-block/CodeBlock';
|
|
59
60
|
export * from './components/json-viewer/JsonViewer';
|
|
61
|
+
export * from './components/xml-viewer/XmlViewer';
|
|
62
|
+
export * from './components/line-viewer/LineViewer';
|
|
60
63
|
export * from './hooks/useTimeDuration';
|
|
61
64
|
export * from './hooks/useSorting';
|
|
62
65
|
export * from './hooks/usePagination';
|
|
@@ -12,9 +12,14 @@ function ClearButton({
|
|
|
12
12
|
onClick,
|
|
13
13
|
ariaLabel = "Ryd",
|
|
14
14
|
variant = "default",
|
|
15
|
-
as = "button"
|
|
15
|
+
as = "button",
|
|
16
|
+
revealOnHover = false
|
|
16
17
|
}) {
|
|
17
|
-
const wrapperClassName = [
|
|
18
|
+
const wrapperClassName = [
|
|
19
|
+
styles__default.default.clearButton,
|
|
20
|
+
variant === "header" ? styles__default.default.header : "",
|
|
21
|
+
revealOnHover ? styles__default.default.revealOnHover : ""
|
|
22
|
+
].filter(Boolean).join(" ");
|
|
18
23
|
const handleMouseDown = (e) => {
|
|
19
24
|
e.preventDefault();
|
|
20
25
|
e.stopPropagation();
|
|
@@ -14,6 +14,13 @@ interface ClearButtonProps {
|
|
|
14
14
|
* activation so it stays keyboard-operable without the invalid nesting.
|
|
15
15
|
*/
|
|
16
16
|
as?: 'button' | 'span';
|
|
17
|
+
/**
|
|
18
|
+
* When true, the button is hidden until the nearest ancestor <button>
|
|
19
|
+
* (e.g. a Select/MultiSelect/IntervalSelect trigger) is hovered or
|
|
20
|
+
* contains focus, instead of always being visible whenever there's a
|
|
21
|
+
* value to clear.
|
|
22
|
+
*/
|
|
23
|
+
revealOnHover?: boolean;
|
|
17
24
|
}
|
|
18
|
-
export declare function ClearButton({ onClick, ariaLabel, variant, as, }: ClearButtonProps): ReactNode;
|
|
25
|
+
export declare function ClearButton({ onClick, ariaLabel, variant, as, revealOnHover, }: ClearButtonProps): ReactNode;
|
|
19
26
|
export {};
|
|
@@ -6,9 +6,14 @@ function ClearButton({
|
|
|
6
6
|
onClick,
|
|
7
7
|
ariaLabel = "Ryd",
|
|
8
8
|
variant = "default",
|
|
9
|
-
as = "button"
|
|
9
|
+
as = "button",
|
|
10
|
+
revealOnHover = false
|
|
10
11
|
}) {
|
|
11
|
-
const wrapperClassName = [
|
|
12
|
+
const wrapperClassName = [
|
|
13
|
+
styles.clearButton,
|
|
14
|
+
variant === "header" ? styles.header : "",
|
|
15
|
+
revealOnHover ? styles.revealOnHover : ""
|
|
16
|
+
].filter(Boolean).join(" ");
|
|
12
17
|
const handleMouseDown = (e) => {
|
|
13
18
|
e.preventDefault();
|
|
14
19
|
e.stopPropagation();
|
|
@@ -33,3 +33,15 @@
|
|
|
33
33
|
background-color: color-mix(in srgb, var(--color-navbar-fg) 12%, transparent);
|
|
34
34
|
color: var(--color-navbar-fg);
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
.clearButton.revealOnHover {
|
|
38
|
+
opacity: 0;
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
transition: opacity var(--transition-fast) var(--ease-standard);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
button:hover .clearButton.revealOnHover,
|
|
44
|
+
button:focus-within .clearButton.revealOnHover {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
pointer-events: auto;
|
|
47
|
+
}
|
|
@@ -235,7 +235,8 @@ function Select({
|
|
|
235
235
|
{
|
|
236
236
|
onClick: onClear,
|
|
237
237
|
variant: variant === "header" ? "header" : "default",
|
|
238
|
-
as: "span"
|
|
238
|
+
as: "span",
|
|
239
|
+
revealOnHover: true
|
|
239
240
|
}
|
|
240
241
|
),
|
|
241
242
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--color-fg-subtle)", display: "inline-flex" }, children: icon })
|
|
@@ -229,7 +229,8 @@ function Select({
|
|
|
229
229
|
{
|
|
230
230
|
onClick: onClear,
|
|
231
231
|
variant: variant === "header" ? "header" : "default",
|
|
232
|
-
as: "span"
|
|
232
|
+
as: "span",
|
|
233
|
+
revealOnHover: true
|
|
233
234
|
}
|
|
234
235
|
),
|
|
235
236
|
/* @__PURE__ */ jsx("span", { style: { color: "var(--color-fg-subtle)", display: "inline-flex" }, children: icon })
|
|
@@ -29,7 +29,8 @@ function JsonViewer({
|
|
|
29
29
|
className,
|
|
30
30
|
maxHeight,
|
|
31
31
|
appearance = "dark",
|
|
32
|
-
storageKey
|
|
32
|
+
storageKey,
|
|
33
|
+
borderless = false
|
|
33
34
|
}) {
|
|
34
35
|
const [queryInput, setQueryInput] = react.useState("");
|
|
35
36
|
const [query, setQuery] = react.useState("");
|
|
@@ -100,7 +101,7 @@ function JsonViewer({
|
|
|
100
101
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
101
102
|
"section",
|
|
102
103
|
{
|
|
103
|
-
className: [styles__default.default.viewer, className].filter(Boolean).join(" "),
|
|
104
|
+
className: [styles__default.default.viewer, borderless ? styles__default.default.borderless : "", className].filter(Boolean).join(" "),
|
|
104
105
|
"data-appearance": currentAppearance,
|
|
105
106
|
children: [
|
|
106
107
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { JSX } from 'react';
|
|
2
2
|
import type { JsonViewerProps } from './types';
|
|
3
3
|
export type { JsonViewerProps } from './types';
|
|
4
|
-
export declare function JsonViewer({ value, defaultExpandedDepth, expandAll, searchDebounceMs, helperText, searchPlaceholder, emptySearchText, className, maxHeight, appearance, storageKey, }: JsonViewerProps): JSX.Element;
|
|
4
|
+
export declare function JsonViewer({ value, defaultExpandedDepth, expandAll, searchDebounceMs, helperText, searchPlaceholder, emptySearchText, className, maxHeight, appearance, storageKey, borderless, }: JsonViewerProps): JSX.Element;
|
|
@@ -23,7 +23,8 @@ function JsonViewer({
|
|
|
23
23
|
className,
|
|
24
24
|
maxHeight,
|
|
25
25
|
appearance = "dark",
|
|
26
|
-
storageKey
|
|
26
|
+
storageKey,
|
|
27
|
+
borderless = false
|
|
27
28
|
}) {
|
|
28
29
|
const [queryInput, setQueryInput] = useState("");
|
|
29
30
|
const [query, setQuery] = useState("");
|
|
@@ -94,7 +95,7 @@ function JsonViewer({
|
|
|
94
95
|
return /* @__PURE__ */ jsxs(
|
|
95
96
|
"section",
|
|
96
97
|
{
|
|
97
|
-
className: [styles.viewer, className].filter(Boolean).join(" "),
|
|
98
|
+
className: [styles.viewer, borderless ? styles.borderless : "", className].filter(Boolean).join(" "),
|
|
98
99
|
"data-appearance": currentAppearance,
|
|
99
100
|
children: [
|
|
100
101
|
/* @__PURE__ */ jsxs(
|
|
@@ -25,6 +25,12 @@ export interface JsonViewerProps {
|
|
|
25
25
|
* under `${storageKey}:appearance`.
|
|
26
26
|
*/
|
|
27
27
|
storageKey?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Removes the outer border, shadow, corner radius and padding, so the
|
|
30
|
+
* viewer sits flush in a container that already provides its own framing
|
|
31
|
+
* (e.g. a modal).
|
|
32
|
+
*/
|
|
33
|
+
borderless?: boolean;
|
|
28
34
|
}
|
|
29
35
|
export type JsonNodeProps = {
|
|
30
36
|
keyName?: string;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var lucideReact = require('lucide-react');
|
|
6
|
+
var react = require('react');
|
|
7
|
+
var Menu = require('../../components/menu/Menu');
|
|
8
|
+
var Popover = require('../../components/popover/Popover');
|
|
9
|
+
var usePersistentState = require('../../hooks/usePersistentState');
|
|
10
|
+
var styles = require('./LineViewer.module.css');
|
|
11
|
+
var tokenizeLineFormat = require('./tokenizeLineFormat');
|
|
12
|
+
var Button = require('../button/Button');
|
|
13
|
+
|
|
14
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
+
|
|
16
|
+
var styles__default = /*#__PURE__*/_interopDefault(styles);
|
|
17
|
+
|
|
18
|
+
const TOKEN_CLASS = {
|
|
19
|
+
tag: styles__default.default.tag,
|
|
20
|
+
indicator: styles__default.default.indicator,
|
|
21
|
+
subfieldMarker: styles__default.default.subfieldMarker,
|
|
22
|
+
subfieldCode: styles__default.default.subfieldCode,
|
|
23
|
+
value: styles__default.default.value,
|
|
24
|
+
terminator: styles__default.default.terminator,
|
|
25
|
+
text: styles__default.default.text,
|
|
26
|
+
whitespace: void 0
|
|
27
|
+
};
|
|
28
|
+
function LineViewer({
|
|
29
|
+
lines,
|
|
30
|
+
size = "md",
|
|
31
|
+
appearance = "dark",
|
|
32
|
+
storageKey,
|
|
33
|
+
borderless = false
|
|
34
|
+
}) {
|
|
35
|
+
const tokens = react.useMemo(() => tokenizeLineFormat.tokenizeLineFormat(lines), [lines]);
|
|
36
|
+
const codeRef = react.useRef(null);
|
|
37
|
+
const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState.usePersistentState({
|
|
38
|
+
initialValue: appearance,
|
|
39
|
+
storageKey: storageKey ? `${storageKey}:appearance` : void 0,
|
|
40
|
+
validate: (stored) => stored === "dark" || stored === "light"
|
|
41
|
+
});
|
|
42
|
+
const { value: viewMode, setValue: setViewMode } = usePersistentState.usePersistentState({
|
|
43
|
+
initialValue: "highlighted",
|
|
44
|
+
storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
|
|
45
|
+
validate: (stored) => stored === "highlighted" || stored === "raw"
|
|
46
|
+
});
|
|
47
|
+
const { value: wrap, setValue: setWrap } = usePersistentState.usePersistentState({
|
|
48
|
+
initialValue: true,
|
|
49
|
+
storageKey: storageKey ? `${storageKey}:wrap` : void 0,
|
|
50
|
+
validate: (stored) => typeof stored === "boolean"
|
|
51
|
+
});
|
|
52
|
+
const handleCopy = () => {
|
|
53
|
+
var _a;
|
|
54
|
+
(_a = navigator.clipboard) == null ? void 0 : _a.writeText(lines).catch(() => {
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const handleDoubleClick = () => {
|
|
58
|
+
const el = codeRef.current;
|
|
59
|
+
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
60
|
+
if (!el || !selection) return;
|
|
61
|
+
const range = document.createRange();
|
|
62
|
+
range.selectNodeContents(el);
|
|
63
|
+
selection.removeAllRanges();
|
|
64
|
+
selection.addRange(range);
|
|
65
|
+
};
|
|
66
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
67
|
+
"section",
|
|
68
|
+
{
|
|
69
|
+
className: [styles__default.default.viewer, borderless ? styles__default.default.borderless : ""].filter(Boolean).join(" "),
|
|
70
|
+
"data-appearance": currentAppearance,
|
|
71
|
+
children: [
|
|
72
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
73
|
+
"div",
|
|
74
|
+
{
|
|
75
|
+
className: styles__default.default.toolbar,
|
|
76
|
+
"data-surface": currentAppearance === "dark" ? "inverse" : void 0,
|
|
77
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
78
|
+
Popover.Popover,
|
|
79
|
+
{
|
|
80
|
+
matchTriggerWidth: false,
|
|
81
|
+
minWidth: "200px",
|
|
82
|
+
trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
83
|
+
Button.Button,
|
|
84
|
+
{
|
|
85
|
+
variant: "inline",
|
|
86
|
+
"aria-label": "Flere handlinger",
|
|
87
|
+
"aria-haspopup": "menu",
|
|
88
|
+
"aria-expanded": isOpen ? true : false,
|
|
89
|
+
onClick: toggle,
|
|
90
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { "aria-hidden": "true" })
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
95
|
+
"button",
|
|
96
|
+
{
|
|
97
|
+
type: "button",
|
|
98
|
+
onClick: () => {
|
|
99
|
+
setWrap((value) => !value);
|
|
100
|
+
close();
|
|
101
|
+
},
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.TextWrap, { "aria-hidden": "true" }),
|
|
104
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: wrap ? "Ombryd ikke tekst" : "Ombryd tekst" })
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
) }),
|
|
108
|
+
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
|
|
109
|
+
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
110
|
+
"button",
|
|
111
|
+
{
|
|
112
|
+
type: "button",
|
|
113
|
+
onClick: () => {
|
|
114
|
+
setViewMode((mode) => mode === "raw" ? "highlighted" : "raw");
|
|
115
|
+
close();
|
|
116
|
+
},
|
|
117
|
+
children: [
|
|
118
|
+
viewMode === "raw" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListTree, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code2, { "aria-hidden": "true" }),
|
|
119
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: viewMode === "raw" ? "Vis med farver" : "Vis raw" })
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
) }),
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
124
|
+
"button",
|
|
125
|
+
{
|
|
126
|
+
type: "button",
|
|
127
|
+
onClick: () => {
|
|
128
|
+
setCurrentAppearance((value) => value === "dark" ? "light" : "dark");
|
|
129
|
+
close();
|
|
130
|
+
},
|
|
131
|
+
children: [
|
|
132
|
+
currentAppearance === "dark" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { "aria-hidden": "true" }),
|
|
133
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: currentAppearance === "dark" ? "Lys visning" : "M\xF8rk visning" })
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
) }),
|
|
137
|
+
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
|
|
138
|
+
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
139
|
+
"button",
|
|
140
|
+
{
|
|
141
|
+
type: "button",
|
|
142
|
+
onClick: () => {
|
|
143
|
+
handleCopy();
|
|
144
|
+
close();
|
|
145
|
+
},
|
|
146
|
+
children: [
|
|
147
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardCopy, { "aria-hidden": "true" }),
|
|
148
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Kopi\xE9r" })
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
) })
|
|
152
|
+
] })
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
),
|
|
157
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
158
|
+
"pre",
|
|
159
|
+
{
|
|
160
|
+
className: [styles__default.default.codePane, styles__default.default[size], wrap ? styles__default.default.wrap : styles__default.default.noWrap].join(" "),
|
|
161
|
+
tabIndex: 0,
|
|
162
|
+
onDoubleClick: handleDoubleClick,
|
|
163
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("code", { ref: codeRef, children: viewMode === "raw" ? lines : tokens.map((token, index) => {
|
|
164
|
+
const tokenClassName = TOKEN_CLASS[token.type];
|
|
165
|
+
return tokenClassName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: tokenClassName, children: token.value }, index) : token.value;
|
|
166
|
+
}) })
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
exports.LineViewer = LineViewer;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
2
|
+
export type LineViewerAppearance = 'dark' | 'light';
|
|
3
|
+
export interface LineViewerProps {
|
|
4
|
+
lines: string;
|
|
5
|
+
size?: 'xs' | 'sm' | 'md' | 'lg';
|
|
6
|
+
/** Initial appearance. The user can toggle it via the kebab menu; defaults to 'dark'. */
|
|
7
|
+
appearance?: LineViewerAppearance;
|
|
8
|
+
/**
|
|
9
|
+
* When set, the user's appearance/view-mode/wrap choices are persisted to
|
|
10
|
+
* localStorage under `${storageKey}:appearance` etc.
|
|
11
|
+
*/
|
|
12
|
+
storageKey?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Removes the outer border, shadow and corner radius, so the viewer sits
|
|
15
|
+
* flush in a container that already provides its own framing (e.g. a
|
|
16
|
+
* modal).
|
|
17
|
+
*/
|
|
18
|
+
borderless?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function LineViewer({ lines, size, appearance, storageKey, borderless, }: LineViewerProps): JSX.Element;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { TextWrap, ListTree, Code2, Sun, Moon, ClipboardCopy, MoreVertical } from 'lucide-react';
|
|
4
|
+
import { useMemo, useRef } from 'react';
|
|
5
|
+
import { Menu } from '../../components/menu/Menu';
|
|
6
|
+
import { Popover } from '../../components/popover/Popover';
|
|
7
|
+
import { usePersistentState } from '../../hooks/usePersistentState';
|
|
8
|
+
import styles from './LineViewer.module.css';
|
|
9
|
+
import { tokenizeLineFormat } from './tokenizeLineFormat';
|
|
10
|
+
import { Button } from '../button/Button';
|
|
11
|
+
|
|
12
|
+
const TOKEN_CLASS = {
|
|
13
|
+
tag: styles.tag,
|
|
14
|
+
indicator: styles.indicator,
|
|
15
|
+
subfieldMarker: styles.subfieldMarker,
|
|
16
|
+
subfieldCode: styles.subfieldCode,
|
|
17
|
+
value: styles.value,
|
|
18
|
+
terminator: styles.terminator,
|
|
19
|
+
text: styles.text,
|
|
20
|
+
whitespace: void 0
|
|
21
|
+
};
|
|
22
|
+
function LineViewer({
|
|
23
|
+
lines,
|
|
24
|
+
size = "md",
|
|
25
|
+
appearance = "dark",
|
|
26
|
+
storageKey,
|
|
27
|
+
borderless = false
|
|
28
|
+
}) {
|
|
29
|
+
const tokens = useMemo(() => tokenizeLineFormat(lines), [lines]);
|
|
30
|
+
const codeRef = useRef(null);
|
|
31
|
+
const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState({
|
|
32
|
+
initialValue: appearance,
|
|
33
|
+
storageKey: storageKey ? `${storageKey}:appearance` : void 0,
|
|
34
|
+
validate: (stored) => stored === "dark" || stored === "light"
|
|
35
|
+
});
|
|
36
|
+
const { value: viewMode, setValue: setViewMode } = usePersistentState({
|
|
37
|
+
initialValue: "highlighted",
|
|
38
|
+
storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
|
|
39
|
+
validate: (stored) => stored === "highlighted" || stored === "raw"
|
|
40
|
+
});
|
|
41
|
+
const { value: wrap, setValue: setWrap } = usePersistentState({
|
|
42
|
+
initialValue: true,
|
|
43
|
+
storageKey: storageKey ? `${storageKey}:wrap` : void 0,
|
|
44
|
+
validate: (stored) => typeof stored === "boolean"
|
|
45
|
+
});
|
|
46
|
+
const handleCopy = () => {
|
|
47
|
+
var _a;
|
|
48
|
+
(_a = navigator.clipboard) == null ? void 0 : _a.writeText(lines).catch(() => {
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
const handleDoubleClick = () => {
|
|
52
|
+
const el = codeRef.current;
|
|
53
|
+
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
54
|
+
if (!el || !selection) return;
|
|
55
|
+
const range = document.createRange();
|
|
56
|
+
range.selectNodeContents(el);
|
|
57
|
+
selection.removeAllRanges();
|
|
58
|
+
selection.addRange(range);
|
|
59
|
+
};
|
|
60
|
+
return /* @__PURE__ */ jsxs(
|
|
61
|
+
"section",
|
|
62
|
+
{
|
|
63
|
+
className: [styles.viewer, borderless ? styles.borderless : ""].filter(Boolean).join(" "),
|
|
64
|
+
"data-appearance": currentAppearance,
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsx(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
className: styles.toolbar,
|
|
70
|
+
"data-surface": currentAppearance === "dark" ? "inverse" : void 0,
|
|
71
|
+
children: /* @__PURE__ */ jsx(
|
|
72
|
+
Popover,
|
|
73
|
+
{
|
|
74
|
+
matchTriggerWidth: false,
|
|
75
|
+
minWidth: "200px",
|
|
76
|
+
trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsx(
|
|
77
|
+
Button,
|
|
78
|
+
{
|
|
79
|
+
variant: "inline",
|
|
80
|
+
"aria-label": "Flere handlinger",
|
|
81
|
+
"aria-haspopup": "menu",
|
|
82
|
+
"aria-expanded": isOpen ? true : false,
|
|
83
|
+
onClick: toggle,
|
|
84
|
+
children: /* @__PURE__ */ jsx(MoreVertical, { "aria-hidden": "true" })
|
|
85
|
+
}
|
|
86
|
+
),
|
|
87
|
+
children: (close) => /* @__PURE__ */ jsxs(Menu, { children: [
|
|
88
|
+
/* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
|
|
89
|
+
"button",
|
|
90
|
+
{
|
|
91
|
+
type: "button",
|
|
92
|
+
onClick: () => {
|
|
93
|
+
setWrap((value) => !value);
|
|
94
|
+
close();
|
|
95
|
+
},
|
|
96
|
+
children: [
|
|
97
|
+
/* @__PURE__ */ jsx(TextWrap, { "aria-hidden": "true" }),
|
|
98
|
+
/* @__PURE__ */ jsx("span", { children: wrap ? "Ombryd ikke tekst" : "Ombryd tekst" })
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
) }),
|
|
102
|
+
/* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
103
|
+
/* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
|
|
104
|
+
"button",
|
|
105
|
+
{
|
|
106
|
+
type: "button",
|
|
107
|
+
onClick: () => {
|
|
108
|
+
setViewMode((mode) => mode === "raw" ? "highlighted" : "raw");
|
|
109
|
+
close();
|
|
110
|
+
},
|
|
111
|
+
children: [
|
|
112
|
+
viewMode === "raw" ? /* @__PURE__ */ jsx(ListTree, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Code2, { "aria-hidden": "true" }),
|
|
113
|
+
/* @__PURE__ */ jsx("span", { children: viewMode === "raw" ? "Vis med farver" : "Vis raw" })
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
) }),
|
|
117
|
+
/* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
|
|
118
|
+
"button",
|
|
119
|
+
{
|
|
120
|
+
type: "button",
|
|
121
|
+
onClick: () => {
|
|
122
|
+
setCurrentAppearance((value) => value === "dark" ? "light" : "dark");
|
|
123
|
+
close();
|
|
124
|
+
},
|
|
125
|
+
children: [
|
|
126
|
+
currentAppearance === "dark" ? /* @__PURE__ */ jsx(Sun, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Moon, { "aria-hidden": "true" }),
|
|
127
|
+
/* @__PURE__ */ jsx("span", { children: currentAppearance === "dark" ? "Lys visning" : "M\xF8rk visning" })
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
) }),
|
|
131
|
+
/* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
132
|
+
/* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
|
|
133
|
+
"button",
|
|
134
|
+
{
|
|
135
|
+
type: "button",
|
|
136
|
+
onClick: () => {
|
|
137
|
+
handleCopy();
|
|
138
|
+
close();
|
|
139
|
+
},
|
|
140
|
+
children: [
|
|
141
|
+
/* @__PURE__ */ jsx(ClipboardCopy, { "aria-hidden": "true" }),
|
|
142
|
+
/* @__PURE__ */ jsx("span", { children: "Kopi\xE9r" })
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
) })
|
|
146
|
+
] })
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
),
|
|
151
|
+
/* @__PURE__ */ jsx(
|
|
152
|
+
"pre",
|
|
153
|
+
{
|
|
154
|
+
className: [styles.codePane, styles[size], wrap ? styles.wrap : styles.noWrap].join(" "),
|
|
155
|
+
tabIndex: 0,
|
|
156
|
+
onDoubleClick: handleDoubleClick,
|
|
157
|
+
children: /* @__PURE__ */ jsx("code", { ref: codeRef, children: viewMode === "raw" ? lines : tokens.map((token, index) => {
|
|
158
|
+
const tokenClassName = TOKEN_CLASS[token.type];
|
|
159
|
+
return tokenClassName ? /* @__PURE__ */ jsx("span", { className: tokenClassName, children: token.value }, index) : token.value;
|
|
160
|
+
}) })
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export { LineViewer };
|