@dbcdk/react-components 0.0.181 → 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.
Files changed (56) hide show
  1. package/dist/client.cjs +21 -0
  2. package/dist/client.d.ts +3 -0
  3. package/dist/client.js +3 -0
  4. package/dist/components/clear-button/ClearButton.cjs +35 -12
  5. package/dist/components/clear-button/ClearButton.d.ts +17 -1
  6. package/dist/components/clear-button/ClearButton.js +35 -12
  7. package/dist/components/clear-button/ClearButton.module.css +12 -0
  8. package/dist/components/forms/multi-select/MultiSelect.cjs +2 -1
  9. package/dist/components/forms/multi-select/MultiSelect.js +2 -1
  10. package/dist/components/forms/select/Select.cjs +3 -1
  11. package/dist/components/forms/select/Select.js +3 -1
  12. package/dist/components/interval-select/IntervalSelect.cjs +2 -1
  13. package/dist/components/interval-select/IntervalSelect.js +2 -1
  14. package/dist/components/json-viewer/JsonViewer.cjs +3 -2
  15. package/dist/components/json-viewer/JsonViewer.d.ts +1 -1
  16. package/dist/components/json-viewer/JsonViewer.js +3 -2
  17. package/dist/components/json-viewer/JsonViewer.module.css +7 -0
  18. package/dist/components/json-viewer/types.d.ts +6 -0
  19. package/dist/components/line-viewer/LineViewer.cjs +174 -0
  20. package/dist/components/line-viewer/LineViewer.d.ts +20 -0
  21. package/dist/components/line-viewer/LineViewer.js +168 -0
  22. package/dist/components/line-viewer/LineViewer.module.css +112 -0
  23. package/dist/components/line-viewer/tokenizeLineFormat.cjs +52 -0
  24. package/dist/components/line-viewer/tokenizeLineFormat.d.ts +14 -0
  25. package/dist/components/line-viewer/tokenizeLineFormat.js +50 -0
  26. package/dist/components/tree-view/TreeNodeRow.cjs +99 -0
  27. package/dist/components/tree-view/TreeNodeRow.d.ts +18 -0
  28. package/dist/components/tree-view/TreeNodeRow.js +93 -0
  29. package/dist/components/tree-view/TreeView.cjs +93 -0
  30. package/dist/components/tree-view/TreeView.d.ts +20 -0
  31. package/dist/components/tree-view/TreeView.js +79 -0
  32. package/dist/components/tree-view/TreeView.module.css +141 -0
  33. package/dist/components/tree-view/types.cjs +2 -0
  34. package/dist/components/tree-view/types.d.ts +44 -0
  35. package/dist/components/tree-view/types.js +1 -0
  36. package/dist/components/tree-view/useTreeExpansion.cjs +47 -0
  37. package/dist/components/tree-view/useTreeExpansion.d.ts +17 -0
  38. package/dist/components/tree-view/useTreeExpansion.js +45 -0
  39. package/dist/components/tree-view/utils.cjs +32 -0
  40. package/dist/components/tree-view/utils.d.ts +16 -0
  41. package/dist/components/tree-view/utils.js +29 -0
  42. package/dist/components/xml-viewer/XmlViewer.cjs +175 -0
  43. package/dist/components/xml-viewer/XmlViewer.d.ts +20 -0
  44. package/dist/components/xml-viewer/XmlViewer.js +169 -0
  45. package/dist/components/xml-viewer/XmlViewer.module.css +109 -0
  46. package/dist/components/xml-viewer/tokenizeXml.cjs +50 -0
  47. package/dist/components/xml-viewer/tokenizeXml.d.ts +12 -0
  48. package/dist/components/xml-viewer/tokenizeXml.js +48 -0
  49. package/dist/index.cjs +7 -0
  50. package/dist/index.css +3 -0
  51. package/dist/index.d.ts +1 -0
  52. package/dist/index.js +1 -0
  53. package/dist/utils/date/formatDate.cjs +29 -17
  54. package/dist/utils/date/formatDate.d.ts +7 -0
  55. package/dist/utils/date/formatDate.js +29 -17
  56. package/package.json +1 -1
@@ -0,0 +1,175 @@
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 tokenizeXml = require('./tokenizeXml');
11
+ var styles = require('./XmlViewer.module.css');
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
+ tagName: styles__default.default.tagName,
20
+ attrName: styles__default.default.attrName,
21
+ attrValue: styles__default.default.attrValue,
22
+ comment: styles__default.default.comment,
23
+ cdata: styles__default.default.cdata,
24
+ declaration: styles__default.default.declaration,
25
+ doctype: styles__default.default.doctype,
26
+ punctuation: styles__default.default.punctuation,
27
+ text: void 0
28
+ };
29
+ function XmlViewer({
30
+ xml,
31
+ size = "md",
32
+ appearance = "dark",
33
+ storageKey,
34
+ borderless = false
35
+ }) {
36
+ const tokens = react.useMemo(() => tokenizeXml.tokenizeXml(xml), [xml]);
37
+ const codeRef = react.useRef(null);
38
+ const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState.usePersistentState({
39
+ initialValue: appearance,
40
+ storageKey: storageKey ? `${storageKey}:appearance` : void 0,
41
+ validate: (stored) => stored === "dark" || stored === "light"
42
+ });
43
+ const { value: viewMode, setValue: setViewMode } = usePersistentState.usePersistentState({
44
+ initialValue: "highlighted",
45
+ storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
46
+ validate: (stored) => stored === "highlighted" || stored === "raw"
47
+ });
48
+ const { value: wrap, setValue: setWrap } = usePersistentState.usePersistentState({
49
+ initialValue: true,
50
+ storageKey: storageKey ? `${storageKey}:wrap` : void 0,
51
+ validate: (stored) => typeof stored === "boolean"
52
+ });
53
+ const handleCopy = () => {
54
+ var _a;
55
+ (_a = navigator.clipboard) == null ? void 0 : _a.writeText(xml).catch(() => {
56
+ });
57
+ };
58
+ const handleDoubleClick = () => {
59
+ const el = codeRef.current;
60
+ const selection = typeof window !== "undefined" ? window.getSelection() : null;
61
+ if (!el || !selection) return;
62
+ const range = document.createRange();
63
+ range.selectNodeContents(el);
64
+ selection.removeAllRanges();
65
+ selection.addRange(range);
66
+ };
67
+ return /* @__PURE__ */ jsxRuntime.jsxs(
68
+ "section",
69
+ {
70
+ className: [styles__default.default.viewer, borderless ? styles__default.default.borderless : ""].filter(Boolean).join(" "),
71
+ "data-appearance": currentAppearance,
72
+ children: [
73
+ /* @__PURE__ */ jsxRuntime.jsx(
74
+ "div",
75
+ {
76
+ className: styles__default.default.toolbar,
77
+ "data-surface": currentAppearance === "dark" ? "inverse" : void 0,
78
+ children: /* @__PURE__ */ jsxRuntime.jsx(
79
+ Popover.Popover,
80
+ {
81
+ matchTriggerWidth: false,
82
+ minWidth: "200px",
83
+ trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsxRuntime.jsx(
84
+ Button.Button,
85
+ {
86
+ variant: "inline",
87
+ "aria-label": "Flere handlinger",
88
+ "aria-haspopup": "menu",
89
+ "aria-expanded": isOpen ? true : false,
90
+ onClick: toggle,
91
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { "aria-hidden": "true" })
92
+ }
93
+ ),
94
+ children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
95
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
96
+ "button",
97
+ {
98
+ type: "button",
99
+ onClick: () => {
100
+ setWrap((value) => !value);
101
+ close();
102
+ },
103
+ children: [
104
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TextWrap, { "aria-hidden": "true" }),
105
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: wrap ? "Ombryd ikke tekst" : "Ombryd tekst" })
106
+ ]
107
+ }
108
+ ) }),
109
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
110
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
111
+ "button",
112
+ {
113
+ type: "button",
114
+ onClick: () => {
115
+ setViewMode((mode) => mode === "raw" ? "highlighted" : "raw");
116
+ close();
117
+ },
118
+ children: [
119
+ viewMode === "raw" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListTree, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code2, { "aria-hidden": "true" }),
120
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: viewMode === "raw" ? "Vis med farver" : "Vis raw" })
121
+ ]
122
+ }
123
+ ) }),
124
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
125
+ "button",
126
+ {
127
+ type: "button",
128
+ onClick: () => {
129
+ setCurrentAppearance((value) => value === "dark" ? "light" : "dark");
130
+ close();
131
+ },
132
+ children: [
133
+ currentAppearance === "dark" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { "aria-hidden": "true" }),
134
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: currentAppearance === "dark" ? "Lys visning" : "M\xF8rk visning" })
135
+ ]
136
+ }
137
+ ) }),
138
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Separator, {}),
139
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(
140
+ "button",
141
+ {
142
+ type: "button",
143
+ onClick: () => {
144
+ handleCopy();
145
+ close();
146
+ },
147
+ children: [
148
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardCopy, { "aria-hidden": "true" }),
149
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Kopi\xE9r XML" })
150
+ ]
151
+ }
152
+ ) })
153
+ ] })
154
+ }
155
+ )
156
+ }
157
+ ),
158
+ /* @__PURE__ */ jsxRuntime.jsx(
159
+ "pre",
160
+ {
161
+ className: [styles__default.default.codePane, styles__default.default[size], wrap ? styles__default.default.wrap : styles__default.default.noWrap].join(" "),
162
+ tabIndex: 0,
163
+ onDoubleClick: handleDoubleClick,
164
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { ref: codeRef, children: viewMode === "raw" ? xml : tokens.map((token, index) => {
165
+ const tokenClassName = TOKEN_CLASS[token.type];
166
+ return tokenClassName ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: tokenClassName, children: token.value }, index) : token.value;
167
+ }) })
168
+ }
169
+ )
170
+ ]
171
+ }
172
+ );
173
+ }
174
+
175
+ exports.XmlViewer = XmlViewer;
@@ -0,0 +1,20 @@
1
+ import type { JSX } from 'react';
2
+ export type XmlViewerAppearance = 'dark' | 'light';
3
+ export interface XmlViewerProps {
4
+ xml: string;
5
+ size?: 'xs' | 'sm' | 'md' | 'lg';
6
+ /** Initial appearance. The user can toggle it via the kebab menu; defaults to 'dark'. */
7
+ appearance?: XmlViewerAppearance;
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 XmlViewer({ xml, size, appearance, storageKey, borderless, }: XmlViewerProps): JSX.Element;
@@ -0,0 +1,169 @@
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 { tokenizeXml } from './tokenizeXml';
9
+ import styles from './XmlViewer.module.css';
10
+ import { Button } from '../button/Button';
11
+
12
+ const TOKEN_CLASS = {
13
+ tagName: styles.tagName,
14
+ attrName: styles.attrName,
15
+ attrValue: styles.attrValue,
16
+ comment: styles.comment,
17
+ cdata: styles.cdata,
18
+ declaration: styles.declaration,
19
+ doctype: styles.doctype,
20
+ punctuation: styles.punctuation,
21
+ text: void 0
22
+ };
23
+ function XmlViewer({
24
+ xml,
25
+ size = "md",
26
+ appearance = "dark",
27
+ storageKey,
28
+ borderless = false
29
+ }) {
30
+ const tokens = useMemo(() => tokenizeXml(xml), [xml]);
31
+ const codeRef = useRef(null);
32
+ const { value: currentAppearance, setValue: setCurrentAppearance } = usePersistentState({
33
+ initialValue: appearance,
34
+ storageKey: storageKey ? `${storageKey}:appearance` : void 0,
35
+ validate: (stored) => stored === "dark" || stored === "light"
36
+ });
37
+ const { value: viewMode, setValue: setViewMode } = usePersistentState({
38
+ initialValue: "highlighted",
39
+ storageKey: storageKey ? `${storageKey}:viewMode` : void 0,
40
+ validate: (stored) => stored === "highlighted" || stored === "raw"
41
+ });
42
+ const { value: wrap, setValue: setWrap } = usePersistentState({
43
+ initialValue: true,
44
+ storageKey: storageKey ? `${storageKey}:wrap` : void 0,
45
+ validate: (stored) => typeof stored === "boolean"
46
+ });
47
+ const handleCopy = () => {
48
+ var _a;
49
+ (_a = navigator.clipboard) == null ? void 0 : _a.writeText(xml).catch(() => {
50
+ });
51
+ };
52
+ const handleDoubleClick = () => {
53
+ const el = codeRef.current;
54
+ const selection = typeof window !== "undefined" ? window.getSelection() : null;
55
+ if (!el || !selection) return;
56
+ const range = document.createRange();
57
+ range.selectNodeContents(el);
58
+ selection.removeAllRanges();
59
+ selection.addRange(range);
60
+ };
61
+ return /* @__PURE__ */ jsxs(
62
+ "section",
63
+ {
64
+ className: [styles.viewer, borderless ? styles.borderless : ""].filter(Boolean).join(" "),
65
+ "data-appearance": currentAppearance,
66
+ children: [
67
+ /* @__PURE__ */ jsx(
68
+ "div",
69
+ {
70
+ className: styles.toolbar,
71
+ "data-surface": currentAppearance === "dark" ? "inverse" : void 0,
72
+ children: /* @__PURE__ */ jsx(
73
+ Popover,
74
+ {
75
+ matchTriggerWidth: false,
76
+ minWidth: "200px",
77
+ trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsx(
78
+ Button,
79
+ {
80
+ variant: "inline",
81
+ "aria-label": "Flere handlinger",
82
+ "aria-haspopup": "menu",
83
+ "aria-expanded": isOpen ? true : false,
84
+ onClick: toggle,
85
+ children: /* @__PURE__ */ jsx(MoreVertical, { "aria-hidden": "true" })
86
+ }
87
+ ),
88
+ children: (close) => /* @__PURE__ */ jsxs(Menu, { children: [
89
+ /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
90
+ "button",
91
+ {
92
+ type: "button",
93
+ onClick: () => {
94
+ setWrap((value) => !value);
95
+ close();
96
+ },
97
+ children: [
98
+ /* @__PURE__ */ jsx(TextWrap, { "aria-hidden": "true" }),
99
+ /* @__PURE__ */ jsx("span", { children: wrap ? "Ombryd ikke tekst" : "Ombryd tekst" })
100
+ ]
101
+ }
102
+ ) }),
103
+ /* @__PURE__ */ jsx(Menu.Separator, {}),
104
+ /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
105
+ "button",
106
+ {
107
+ type: "button",
108
+ onClick: () => {
109
+ setViewMode((mode) => mode === "raw" ? "highlighted" : "raw");
110
+ close();
111
+ },
112
+ children: [
113
+ viewMode === "raw" ? /* @__PURE__ */ jsx(ListTree, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Code2, { "aria-hidden": "true" }),
114
+ /* @__PURE__ */ jsx("span", { children: viewMode === "raw" ? "Vis med farver" : "Vis raw" })
115
+ ]
116
+ }
117
+ ) }),
118
+ /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
119
+ "button",
120
+ {
121
+ type: "button",
122
+ onClick: () => {
123
+ setCurrentAppearance((value) => value === "dark" ? "light" : "dark");
124
+ close();
125
+ },
126
+ children: [
127
+ currentAppearance === "dark" ? /* @__PURE__ */ jsx(Sun, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Moon, { "aria-hidden": "true" }),
128
+ /* @__PURE__ */ jsx("span", { children: currentAppearance === "dark" ? "Lys visning" : "M\xF8rk visning" })
129
+ ]
130
+ }
131
+ ) }),
132
+ /* @__PURE__ */ jsx(Menu.Separator, {}),
133
+ /* @__PURE__ */ jsx(Menu.Item, { children: /* @__PURE__ */ jsxs(
134
+ "button",
135
+ {
136
+ type: "button",
137
+ onClick: () => {
138
+ handleCopy();
139
+ close();
140
+ },
141
+ children: [
142
+ /* @__PURE__ */ jsx(ClipboardCopy, { "aria-hidden": "true" }),
143
+ /* @__PURE__ */ jsx("span", { children: "Kopi\xE9r XML" })
144
+ ]
145
+ }
146
+ ) })
147
+ ] })
148
+ }
149
+ )
150
+ }
151
+ ),
152
+ /* @__PURE__ */ jsx(
153
+ "pre",
154
+ {
155
+ className: [styles.codePane, styles[size], wrap ? styles.wrap : styles.noWrap].join(" "),
156
+ tabIndex: 0,
157
+ onDoubleClick: handleDoubleClick,
158
+ children: /* @__PURE__ */ jsx("code", { ref: codeRef, children: viewMode === "raw" ? xml : tokens.map((token, index) => {
159
+ const tokenClassName = TOKEN_CLASS[token.type];
160
+ return tokenClassName ? /* @__PURE__ */ jsx("span", { className: tokenClassName, children: token.value }, index) : token.value;
161
+ }) })
162
+ }
163
+ )
164
+ ]
165
+ }
166
+ );
167
+ }
168
+
169
+ export { XmlViewer };
@@ -0,0 +1,109 @@
1
+ .viewer {
2
+ --xml-pane-bg: var(--color-bg-inverse);
3
+ --xml-pane-border: color-mix(in oklab, var(--color-fg-inverse) 12%, transparent);
4
+ --xml-pane-text: var(--color-fg-inverse);
5
+
6
+ --xml-tag: color-mix(in oklab, var(--color-fg-inverse) 66%, var(--color-syntax-accent) 34%);
7
+ --xml-attr-name: color-mix(in oklab, var(--color-fg-inverse) 50%, var(--color-syntax-accent) 50%);
8
+ --xml-attr-value: color-mix(in oklab, var(--color-fg-inverse) 20%, var(--color-syntax-string) 80%);
9
+ --xml-comment: color-mix(in oklab, var(--color-fg-inverse) 46%, transparent);
10
+ --xml-punctuation: color-mix(in oklab, var(--color-fg-inverse) 60%, transparent);
11
+
12
+ position: relative;
13
+ background: var(--xml-pane-bg);
14
+ border: var(--border-width-thin) solid var(--xml-pane-border);
15
+ border-radius: var(--border-radius-default);
16
+ box-shadow: var(--shadow-md);
17
+ font-family: var(--font-family-mono);
18
+ }
19
+
20
+ .viewer[data-appearance='light'] {
21
+ --xml-pane-bg: var(--color-bg-surface);
22
+ --xml-pane-border: var(--color-border-subtle);
23
+ --xml-pane-text: var(--color-fg-default);
24
+
25
+ --xml-tag: var(--color-link);
26
+ --xml-attr-name: color-mix(in oklab, var(--color-fg-default) 55%, var(--color-link) 45%);
27
+ --xml-attr-value: var(--color-status-success-fg);
28
+ --xml-comment: var(--color-fg-muted);
29
+ --xml-punctuation: var(--color-fg-subtle);
30
+
31
+ box-shadow: var(--shadow-xs);
32
+ }
33
+
34
+ .viewer.borderless {
35
+ border: none;
36
+ border-radius: 0;
37
+ box-shadow: none;
38
+ }
39
+
40
+ .toolbar {
41
+ position: absolute;
42
+ top: var(--spacing-xs);
43
+ right: var(--spacing-xs);
44
+ z-index: 1;
45
+ }
46
+
47
+ .codePane {
48
+ margin: 0;
49
+ padding: var(--spacing-sm);
50
+ overflow: auto;
51
+ color: var(--xml-pane-text);
52
+ font-family: inherit;
53
+ line-height: 1.35;
54
+ }
55
+
56
+ .wrap {
57
+ white-space: pre-wrap;
58
+ overflow-wrap: break-word;
59
+ }
60
+
61
+ .noWrap {
62
+ white-space: pre;
63
+ }
64
+
65
+ .xs,
66
+ .sm {
67
+ font-size: var(--font-size-xs);
68
+ }
69
+
70
+ .md {
71
+ font-size: var(--font-size-sm);
72
+ }
73
+
74
+ .lg {
75
+ font-size: var(--font-size-base);
76
+ }
77
+
78
+ .tagName {
79
+ color: var(--xml-tag);
80
+ font-weight: var(--font-weight-medium);
81
+ }
82
+
83
+ .attrName {
84
+ color: var(--xml-attr-name);
85
+ }
86
+
87
+ .attrValue {
88
+ color: var(--xml-attr-value);
89
+ }
90
+
91
+ .comment {
92
+ color: var(--xml-comment);
93
+ font-style: italic;
94
+ }
95
+
96
+ .cdata {
97
+ color: var(--xml-attr-value);
98
+ opacity: 0.85;
99
+ }
100
+
101
+ .declaration,
102
+ .doctype {
103
+ color: var(--xml-comment);
104
+ font-style: italic;
105
+ }
106
+
107
+ .punctuation {
108
+ color: var(--xml-punctuation);
109
+ }
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const CHUNK_PATTERN = /(<!--[\s\S]*?-->)|(<!\[CDATA\[[\s\S]*?\]\]>)|(<!DOCTYPE[\s\S]*?>)|(<\?[\s\S]*?\?>)|(<\/?[a-zA-Z_:][\s\S]*?>)|([^<]+)/g;
4
+ const ATTR_PATTERN = /([^\s=/>]+)(\s*=\s*)("[^"]*"|'[^']*')/g;
5
+ function tokenizeTag(raw) {
6
+ var _a;
7
+ const isClosing = raw.startsWith("</");
8
+ const isSelfClosing = raw.endsWith("/>");
9
+ const openLength = isClosing ? 2 : 1;
10
+ const closeLength = isSelfClosing ? 2 : 1;
11
+ const inner = raw.slice(openLength, raw.length - closeLength);
12
+ const tokens = [{ type: "punctuation", value: raw.slice(0, openLength) }];
13
+ const nameMatch = /^[^\s/>]+/.exec(inner);
14
+ const name = (_a = nameMatch == null ? void 0 : nameMatch[0]) != null ? _a : "";
15
+ if (name) tokens.push({ type: "tagName", value: name });
16
+ let lastIndex = name.length;
17
+ ATTR_PATTERN.lastIndex = lastIndex;
18
+ let match;
19
+ while (match = ATTR_PATTERN.exec(inner)) {
20
+ if (match.index > lastIndex) {
21
+ tokens.push({ type: "punctuation", value: inner.slice(lastIndex, match.index) });
22
+ }
23
+ tokens.push({ type: "attrName", value: match[1] });
24
+ tokens.push({ type: "punctuation", value: match[2] });
25
+ tokens.push({ type: "attrValue", value: match[3] });
26
+ lastIndex = match.index + match[0].length;
27
+ }
28
+ if (lastIndex < inner.length) {
29
+ tokens.push({ type: "punctuation", value: inner.slice(lastIndex) });
30
+ }
31
+ tokens.push({ type: "punctuation", value: raw.slice(raw.length - closeLength) });
32
+ return tokens;
33
+ }
34
+ function tokenizeXml(source) {
35
+ const tokens = [];
36
+ CHUNK_PATTERN.lastIndex = 0;
37
+ let match;
38
+ while (match = CHUNK_PATTERN.exec(source)) {
39
+ const [, comment, cdata, doctype, declaration, tag, text] = match;
40
+ if (comment) tokens.push({ type: "comment", value: comment });
41
+ else if (cdata) tokens.push({ type: "cdata", value: cdata });
42
+ else if (doctype) tokens.push({ type: "doctype", value: doctype });
43
+ else if (declaration) tokens.push({ type: "declaration", value: declaration });
44
+ else if (tag) tokens.push(...tokenizeTag(tag));
45
+ else if (text) tokens.push({ type: "text", value: text });
46
+ }
47
+ return tokens;
48
+ }
49
+
50
+ exports.tokenizeXml = tokenizeXml;
@@ -0,0 +1,12 @@
1
+ export type XmlTokenType = 'tagName' | 'attrName' | 'attrValue' | 'text' | 'comment' | 'cdata' | 'declaration' | 'doctype' | 'punctuation';
2
+ export interface XmlToken {
3
+ type: XmlTokenType;
4
+ value: string;
5
+ }
6
+ /**
7
+ * Tokenizes an XML string for syntax highlighting without parsing it into a
8
+ * DOM. Preserves the source exactly - concatenating every token's `value`
9
+ * reproduces the input - so malformed or partial XML still highlights
10
+ * whatever it recognizes instead of failing outright.
11
+ */
12
+ export declare function tokenizeXml(source: string): XmlToken[];
@@ -0,0 +1,48 @@
1
+ const CHUNK_PATTERN = /(<!--[\s\S]*?-->)|(<!\[CDATA\[[\s\S]*?\]\]>)|(<!DOCTYPE[\s\S]*?>)|(<\?[\s\S]*?\?>)|(<\/?[a-zA-Z_:][\s\S]*?>)|([^<]+)/g;
2
+ const ATTR_PATTERN = /([^\s=/>]+)(\s*=\s*)("[^"]*"|'[^']*')/g;
3
+ function tokenizeTag(raw) {
4
+ var _a;
5
+ const isClosing = raw.startsWith("</");
6
+ const isSelfClosing = raw.endsWith("/>");
7
+ const openLength = isClosing ? 2 : 1;
8
+ const closeLength = isSelfClosing ? 2 : 1;
9
+ const inner = raw.slice(openLength, raw.length - closeLength);
10
+ const tokens = [{ type: "punctuation", value: raw.slice(0, openLength) }];
11
+ const nameMatch = /^[^\s/>]+/.exec(inner);
12
+ const name = (_a = nameMatch == null ? void 0 : nameMatch[0]) != null ? _a : "";
13
+ if (name) tokens.push({ type: "tagName", value: name });
14
+ let lastIndex = name.length;
15
+ ATTR_PATTERN.lastIndex = lastIndex;
16
+ let match;
17
+ while (match = ATTR_PATTERN.exec(inner)) {
18
+ if (match.index > lastIndex) {
19
+ tokens.push({ type: "punctuation", value: inner.slice(lastIndex, match.index) });
20
+ }
21
+ tokens.push({ type: "attrName", value: match[1] });
22
+ tokens.push({ type: "punctuation", value: match[2] });
23
+ tokens.push({ type: "attrValue", value: match[3] });
24
+ lastIndex = match.index + match[0].length;
25
+ }
26
+ if (lastIndex < inner.length) {
27
+ tokens.push({ type: "punctuation", value: inner.slice(lastIndex) });
28
+ }
29
+ tokens.push({ type: "punctuation", value: raw.slice(raw.length - closeLength) });
30
+ return tokens;
31
+ }
32
+ function tokenizeXml(source) {
33
+ const tokens = [];
34
+ CHUNK_PATTERN.lastIndex = 0;
35
+ let match;
36
+ while (match = CHUNK_PATTERN.exec(source)) {
37
+ const [, comment, cdata, doctype, declaration, tag, text] = match;
38
+ if (comment) tokens.push({ type: "comment", value: comment });
39
+ else if (cdata) tokens.push({ type: "cdata", value: cdata });
40
+ else if (doctype) tokens.push({ type: "doctype", value: doctype });
41
+ else if (declaration) tokens.push({ type: "declaration", value: declaration });
42
+ else if (tag) tokens.push(...tokenizeTag(tag));
43
+ else if (text) tokens.push({ type: "text", value: text });
44
+ }
45
+ return tokens;
46
+ }
47
+
48
+ export { tokenizeXml };
package/dist/index.cjs CHANGED
@@ -43,6 +43,7 @@ var MediaCard = require('./components/media-card/MediaCard');
43
43
  var HighlightedText = require('./components/highlighted-text/HighlightedText');
44
44
  var ButtonSelect = require('./components/button-select/ButtonSelect');
45
45
  var Sidebar = require('./components/sidebar/Sidebar');
46
+ var TreeView = require('./components/tree-view/TreeView');
46
47
  var SplitButton = require('./components/split-button/SplitButton');
47
48
  var ChipMultiToggle = require('./components/filtering/chip-multi-toggle/ChipMultiToggle');
48
49
  var CheckboxGroup = require('./components/forms/checkbox-group/CheckboxGroup');
@@ -307,6 +308,12 @@ Object.keys(Sidebar).forEach(function (k) {
307
308
  get: function () { return Sidebar[k]; }
308
309
  });
309
310
  });
311
+ Object.keys(TreeView).forEach(function (k) {
312
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
313
+ enumerable: true,
314
+ get: function () { return TreeView[k]; }
315
+ });
316
+ });
310
317
  Object.keys(SplitButton).forEach(function (k) {
311
318
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
312
319
  enumerable: true,
package/dist/index.css CHANGED
@@ -39,6 +39,7 @@
39
39
  @import './components/inline-status/InlineStatus.module.css';
40
40
  @import './components/json-viewer/JsonViewer.module.css';
41
41
  @import './components/lightbox/Lightbox.module.css';
42
+ @import './components/line-viewer/LineViewer.module.css';
42
43
  @import './components/media-card/MediaCard.module.css';
43
44
  @import './components/menu/Menu.module.css';
44
45
  @import './components/meta-bar/MetaBar.module.css';
@@ -72,4 +73,6 @@
72
73
  @import './components/table/components/empty-state/EmptyState.module.css';
73
74
  @import './components/tabs/Tabs.module.css';
74
75
  @import './components/toast/Toast.module.css';
76
+ @import './components/tree-view/TreeView.module.css';
75
77
  @import './components/user-display/UserDisplay.module.css';
78
+ @import './components/xml-viewer/XmlViewer.module.css';
package/dist/index.d.ts CHANGED
@@ -42,6 +42,7 @@ export * from './components/media-card/MediaCard';
42
42
  export * from './components/highlighted-text/HighlightedText';
43
43
  export * from './components/button-select/ButtonSelect';
44
44
  export * from './components/sidebar/Sidebar';
45
+ export * from './components/tree-view/TreeView';
45
46
  export * from './components/split-button/SplitButton';
46
47
  export * from './components/filtering/chip-multi-toggle/ChipMultiToggle';
47
48
  export * from './components/forms/checkbox-group/CheckboxGroup';
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ export * from './components/media-card/MediaCard';
41
41
  export * from './components/highlighted-text/HighlightedText';
42
42
  export * from './components/button-select/ButtonSelect';
43
43
  export * from './components/sidebar/Sidebar';
44
+ export * from './components/tree-view/TreeView';
44
45
  export * from './components/split-button/SplitButton';
45
46
  export * from './components/filtering/chip-multi-toggle/ChipMultiToggle';
46
47
  export * from './components/forms/checkbox-group/CheckboxGroup';