@dbcdk/react-components 0.0.9 → 0.0.12

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 (113) hide show
  1. package/dist/components/accordion/Accordion.d.ts +27 -0
  2. package/dist/components/accordion/Accordion.js +66 -0
  3. package/dist/components/accordion/Accordion.module.css +87 -0
  4. package/dist/components/button/Button.module.css +1 -0
  5. package/dist/components/card/Card.d.ts +21 -3
  6. package/dist/components/card/Card.js +17 -2
  7. package/dist/components/card/Card.module.css +59 -0
  8. package/dist/components/circle/Circle.d.ts +5 -1
  9. package/dist/components/circle/Circle.js +2 -2
  10. package/dist/components/circle/Circle.module.css +60 -4
  11. package/dist/components/code-block/CodeBlock.js +1 -1
  12. package/dist/components/code-block/CodeBlock.module.css +30 -17
  13. package/dist/components/copy-button/CopyButton.d.ts +1 -0
  14. package/dist/components/copy-button/CopyButton.js +10 -2
  15. package/dist/components/datetime-picker/DateTimePicker.d.ts +4 -8
  16. package/dist/components/datetime-picker/DateTimePicker.js +72 -92
  17. package/dist/components/datetime-picker/dateTimeHelpers.d.ts +14 -12
  18. package/dist/components/datetime-picker/dateTimeHelpers.js +25 -45
  19. package/dist/components/filter-field/FilterField.js +16 -11
  20. package/dist/components/filter-field/FilterField.module.css +133 -12
  21. package/dist/components/forms/checkbox/Checkbox.d.ts +4 -10
  22. package/dist/components/forms/checkbox/Checkbox.js +3 -5
  23. package/dist/components/forms/checkbox-group/CheckboxGroup.js +1 -1
  24. package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +1 -1
  25. package/dist/components/forms/input/Input.d.ts +1 -0
  26. package/dist/components/forms/input/Input.js +2 -4
  27. package/dist/components/forms/input/Input.module.css +10 -11
  28. package/dist/components/forms/input-container/InputContainer.d.ts +2 -1
  29. package/dist/components/forms/input-container/InputContainer.js +3 -3
  30. package/dist/components/forms/input-container/InputContainer.module.css +65 -0
  31. package/dist/components/forms/radio-buttons/RadioButton.d.ts +36 -0
  32. package/dist/components/forms/radio-buttons/RadioButton.js +26 -0
  33. package/dist/components/forms/radio-buttons/RadioButtonGroup.d.ts +25 -0
  34. package/dist/components/forms/radio-buttons/RadioButtonGroup.js +19 -0
  35. package/dist/components/forms/radio-buttons/RadioButtons.module.css +117 -0
  36. package/dist/components/forms/select/Select.d.ts +1 -1
  37. package/dist/components/forms/select/Select.js +3 -3
  38. package/dist/components/forms/text-area/Textarea.js +3 -3
  39. package/dist/components/forms/text-area/Textarea.module.css +8 -1
  40. package/dist/components/headline/Headline.d.ts +2 -7
  41. package/dist/components/headline/Headline.js +5 -2
  42. package/dist/components/headline/Headline.module.css +61 -2
  43. package/dist/components/hyperlink/Hyperlink.d.ts +19 -6
  44. package/dist/components/hyperlink/Hyperlink.js +35 -7
  45. package/dist/components/hyperlink/Hyperlink.module.css +50 -2
  46. package/dist/components/icon/Icon.module.css +1 -0
  47. package/dist/components/interval-select/IntervalSelect.js +1 -1
  48. package/dist/components/menu/Menu.d.ts +32 -0
  49. package/dist/components/menu/Menu.js +73 -13
  50. package/dist/components/menu/Menu.module.css +72 -4
  51. package/dist/components/nav-bar/NavBar.d.ts +24 -6
  52. package/dist/components/overlay/modal/Modal.module.css +2 -2
  53. package/dist/components/overlay/side-panel/SidePanel.d.ts +12 -4
  54. package/dist/components/overlay/side-panel/SidePanel.js +77 -4
  55. package/dist/components/overlay/side-panel/SidePanel.module.css +149 -28
  56. package/dist/components/overlay/side-panel/useSidePanel.d.ts +1 -1
  57. package/dist/components/overlay/side-panel/useSidePanel.js +2 -2
  58. package/dist/components/overlay/tooltip/useTooltipTrigger.js +4 -2
  59. package/dist/components/page-layout/PageLayout.js +0 -2
  60. package/dist/components/popover/Popover.js +1 -1
  61. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +5 -5
  62. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +36 -24
  63. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -3
  64. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -1
  65. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +4 -3
  66. package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +109 -79
  67. package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +16 -3
  68. package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +20 -0
  69. package/dist/components/sidebar/providers/SidebarProvider.d.ts +4 -1
  70. package/dist/components/sidebar/providers/SidebarProvider.js +85 -58
  71. package/dist/components/skeleton-loader/SkeletonLoader.d.ts +1 -1
  72. package/dist/components/skeleton-loader/SkeletonLoader.js +15 -12
  73. package/dist/components/split-button/SplitButton.d.ts +1 -1
  74. package/dist/components/split-button/SplitButton.js +3 -1
  75. package/dist/components/split-button/SplitButton.module.css +4 -4
  76. package/dist/components/state-page/StatePage.d.ts +9 -0
  77. package/dist/components/state-page/StatePage.js +20 -0
  78. package/dist/components/state-page/StatePage.module.css +9 -0
  79. package/dist/components/state-page/empty.d.ts +2 -0
  80. package/dist/components/state-page/empty.js +2 -0
  81. package/dist/components/state-page/error.d.ts +2 -0
  82. package/dist/components/state-page/error.js +2 -0
  83. package/dist/components/state-page/notFound.d.ts +2 -0
  84. package/dist/components/state-page/notFound.js +2 -0
  85. package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +19 -0
  86. package/dist/components/sticky-footer-layout/StickyFooterLayout.js +27 -0
  87. package/dist/components/table/Table.d.ts +9 -4
  88. package/dist/components/table/Table.js +6 -9
  89. package/dist/components/table/Table.module.css +180 -59
  90. package/dist/components/table/components/empty-state/EmptyState.d.ts +1 -1
  91. package/dist/components/table/components/empty-state/EmptyState.js +6 -7
  92. package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -3
  93. package/dist/components/table/components/table-settings/TableSettings.js +55 -4
  94. package/dist/components/table/tanstack.d.ts +12 -1
  95. package/dist/components/table/tanstack.js +75 -23
  96. package/dist/components/toast/Toast.js +5 -1
  97. package/dist/components/toast/Toast.module.css +40 -15
  98. package/dist/components/toast/provider/ToastProvider.js +1 -0
  99. package/dist/hooks/useTableSettings.d.ts +23 -4
  100. package/dist/hooks/useTableSettings.js +64 -17
  101. package/dist/hooks/useTimeDuration.js +9 -3
  102. package/dist/hooks/useViewportFill.js +1 -0
  103. package/dist/index.d.ts +6 -0
  104. package/dist/index.js +6 -1
  105. package/dist/src/styles/styles.css +60 -25
  106. package/dist/styles/animation.d.ts +5 -0
  107. package/dist/styles/animation.js +5 -0
  108. package/dist/styles/styles.css +60 -25
  109. package/dist/styles/themes/dbc/dark.css +1 -1
  110. package/dist/styles/themes/dbc/light.css +2 -1
  111. package/dist/utils/localStorage.utils.d.ts +19 -0
  112. package/dist/utils/localStorage.utils.js +78 -0
  113. package/package.json +1 -1
@@ -0,0 +1,27 @@
1
+ import type { ReactNode, JSX } from 'react';
2
+ import { Severity } from '../../constants/severity.types';
3
+ export interface AccordionItem {
4
+ header: string;
5
+ headerIcon?: ReactNode;
6
+ severity?: Severity;
7
+ children: ReactNode;
8
+ disabled?: boolean;
9
+ }
10
+ type Size = 'sm' | 'md' | 'lg';
11
+ type Mode = 'single' | 'multiple';
12
+ export interface AccordionProps {
13
+ items: AccordionItem[];
14
+ mode?: Mode;
15
+ size?: Size;
16
+ /** Uncontrolled defaults */
17
+ defaultOpenIndex?: number | null;
18
+ defaultOpenIndexes?: number[];
19
+ /** Controlled state */
20
+ openIndex?: number | null;
21
+ openIndexes?: number[];
22
+ /** Change callbacks */
23
+ onOpenIndexChange?: (index: number | null) => void;
24
+ onOpenIndexesChange?: (indexes: number[]) => void;
25
+ }
26
+ export declare function Accordion({ items, mode, size, defaultOpenIndex, defaultOpenIndexes, openIndex, openIndexes, onOpenIndexChange, onOpenIndexesChange, }: AccordionProps): JSX.Element;
27
+ export {};
@@ -0,0 +1,66 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId, useMemo, useState } from 'react';
4
+ import styles from './Accordion.module.css';
5
+ import { Headline } from '../headline/Headline';
6
+ function uniqSorted(nums) {
7
+ return Array.from(new Set(nums)).sort((a, b) => a - b);
8
+ }
9
+ export function Accordion({ items, mode = 'single', size = 'md', defaultOpenIndex = null, defaultOpenIndexes = [], openIndex, openIndexes, onOpenIndexChange, onOpenIndexesChange, }) {
10
+ const uid = useId();
11
+ const isControlledSingle = mode === 'single' && openIndex !== undefined;
12
+ const isControlledMultiple = mode === 'multiple' && openIndexes !== undefined;
13
+ const [internalOpenIndex, setInternalOpenIndex] = useState(mode === 'single' ? defaultOpenIndex : null);
14
+ const [internalOpenIndexes, setInternalOpenIndexes] = useState(mode === 'multiple' ? uniqSorted(defaultOpenIndexes) : []);
15
+ const currentOpenIndex = mode === 'single' ? (isControlledSingle ? openIndex : internalOpenIndex) : null;
16
+ const currentOpenIndexes = useMemo(() => mode === 'multiple'
17
+ ? isControlledMultiple
18
+ ? uniqSorted(openIndexes)
19
+ : internalOpenIndexes
20
+ : [], [mode, isControlledMultiple, openIndexes, internalOpenIndexes]);
21
+ const openSet = useMemo(() => new Set(mode === 'single'
22
+ ? currentOpenIndex !== null
23
+ ? [currentOpenIndex]
24
+ : []
25
+ : currentOpenIndexes), [mode, currentOpenIndex, currentOpenIndexes]);
26
+ function setSingle(next) {
27
+ if (isControlledSingle)
28
+ onOpenIndexChange === null || onOpenIndexChange === void 0 ? void 0 : onOpenIndexChange(next);
29
+ else {
30
+ setInternalOpenIndex(next);
31
+ onOpenIndexChange === null || onOpenIndexChange === void 0 ? void 0 : onOpenIndexChange(next);
32
+ }
33
+ }
34
+ function setMultiple(next) {
35
+ const normalized = uniqSorted(next);
36
+ if (isControlledMultiple)
37
+ onOpenIndexesChange === null || onOpenIndexesChange === void 0 ? void 0 : onOpenIndexesChange(normalized);
38
+ else {
39
+ setInternalOpenIndexes(normalized);
40
+ onOpenIndexesChange === null || onOpenIndexesChange === void 0 ? void 0 : onOpenIndexesChange(normalized);
41
+ }
42
+ }
43
+ function toggle(index) {
44
+ const item = items[index];
45
+ if (!item || item.disabled)
46
+ return;
47
+ if (mode === 'single') {
48
+ const isOpen = openSet.has(index);
49
+ setSingle(isOpen ? null : index);
50
+ return;
51
+ }
52
+ // multiple
53
+ const isOpen = openSet.has(index);
54
+ if (isOpen)
55
+ setMultiple(currentOpenIndexes.filter(i => i !== index));
56
+ else
57
+ setMultiple([...currentOpenIndexes, index]);
58
+ }
59
+ return (_jsx("div", { className: `${styles.container} ${styles[size]}`, children: items.map((item, i) => {
60
+ const isOpen = openSet.has(i);
61
+ const isDisabled = !!item.disabled;
62
+ const buttonId = `${uid}-acc-btn-${i}`;
63
+ const panelId = `${uid}-acc-panel-${i}`;
64
+ return (_jsxs("section", { className: `${styles.item} ${isOpen ? styles.open : ''} ${isDisabled ? styles.disabled : ''}`, children: [_jsxs("button", { type: "button", id: buttonId, className: styles.trigger, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => toggle(i), disabled: isDisabled, children: [_jsx("span", { className: styles.title, children: _jsx(Headline, { disableMargin: true, size: 4, weight: 500, severity: item.severity, allowWrap: isOpen, children: item.header }) }), _jsx("span", { className: styles.chevron, "aria-hidden": "true", children: _jsx("svg", { viewBox: "0 0 20 20", focusable: "false", children: _jsx("path", { d: "M5.5 7.5L10 12l4.5-4.5", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })] }), _jsx("div", { id: panelId, role: "region", "aria-labelledby": buttonId, className: styles.panel, "data-open": isOpen ? 'true' : 'false', children: _jsx("div", { className: styles.content, children: item.children }) })] }, i));
65
+ }) }));
66
+ }
@@ -0,0 +1,87 @@
1
+ .container {
2
+ border-radius: var(--border-radius-default);
3
+ background-color: var(--color-bg-surface);
4
+ box-sizing: border-box;
5
+ display: flex;
6
+ flex-direction: column;
7
+ overflow: hidden;
8
+ gap: var(--spacing-xxs);
9
+ }
10
+
11
+ .trigger {
12
+ all: unset;
13
+ box-sizing: border-box;
14
+ width: 100%;
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: space-between;
18
+ gap: var(--spacing-sm);
19
+ cursor: pointer;
20
+ user-select: none;
21
+ padding: var(--spacing-xs) var(--spacing-md);
22
+ background: var(--color-bg-contextual);
23
+
24
+ /* IMPORTANT: allow flex children to actually shrink */
25
+ min-width: 0;
26
+ }
27
+
28
+ .trigger:focus-visible {
29
+ outline: none;
30
+ box-shadow: var(--focus-ring);
31
+ }
32
+
33
+ .disabled .trigger {
34
+ cursor: not-allowed;
35
+ color: var(--color-disabled-fg);
36
+ }
37
+
38
+ .title {
39
+ /* IMPORTANT: this is the shrinking area that contains Headline */
40
+ display: flex;
41
+ align-items: center;
42
+ min-width: 0;
43
+ flex: 1 1 auto;
44
+
45
+ /* ensures any overflow is clipped so ellipsis can show */
46
+ overflow: hidden;
47
+ }
48
+
49
+ .chevron {
50
+ width: var(--icon-size-md);
51
+ height: var(--icon-size-md);
52
+ flex: 0 0 auto;
53
+ transition: transform var(--transition-normal) var(--ease-standard);
54
+ }
55
+
56
+ .open .chevron {
57
+ transform: rotate(180deg);
58
+ }
59
+
60
+ /* Collapsible panel using max-height */
61
+ .panel {
62
+ overflow: hidden;
63
+ max-height: 0;
64
+ transition: max-height var(--transition-slow) var(--ease-decelerate);
65
+ }
66
+
67
+ .panel[data-open='true'] {
68
+ max-height: 999px;
69
+ }
70
+
71
+ .content {
72
+ padding: var(--spacing-md) 0;
73
+ }
74
+
75
+ /* Sizes */
76
+ .sm .trigger,
77
+ .sm .content {
78
+ padding: var(--spacing-sm) var(--spacing-md);
79
+ }
80
+
81
+ .md .trigger {
82
+ padding: var(--spacing-sm) var(--spacing-md);
83
+ }
84
+
85
+ .lg .trigger {
86
+ padding: var(--spacing-md) var(--spacing-md);
87
+ }
@@ -47,6 +47,7 @@
47
47
  background-color: var(--color-disabled-bg);
48
48
  border-color: transparent;
49
49
  color: var(--color-disabled-fg);
50
+ opacity: 0.5;
50
51
  }
51
52
 
52
53
  /* ==========================================================================
@@ -1,10 +1,10 @@
1
+ import type { ReactNode, JSX, HTMLAttributes } from 'react';
1
2
  import { JSXElementConstructor, ReactElement } from 'react';
2
- import type { ReactNode, JSX } from 'react';
3
3
  import { Severity } from '../../constants/severity.types';
4
4
  type CardVariant = 'default' | 'subtle' | 'strong';
5
5
  type CardSize = 'sm' | 'md' | 'lg';
6
6
  type CardImagePlacement = 'left' | 'right' | 'top';
7
- interface CardProps {
7
+ export interface CardProps {
8
8
  title?: string;
9
9
  loading?: boolean;
10
10
  variant?: CardVariant;
@@ -23,5 +23,23 @@ interface CardProps {
23
23
  link?: ReactElement<any, string | JSXElementConstructor<any>>;
24
24
  width?: 25 | 33 | 50 | 66 | 75 | 100;
25
25
  }
26
- export declare function Card({ title, loading, variant, size, headerMarker, headerIcon, severity, image, imgPlacement, mediaWidth, actions, headerMeta, sectionTitle, showSectionDivider, children, link, width, }: CardProps): JSX.Element;
26
+ type CardMetaProps = {
27
+ columns?: 1 | 2 | 3;
28
+ className?: string;
29
+ children: ReactNode;
30
+ } & Omit<HTMLAttributes<HTMLDListElement>, 'children'>;
31
+ type CardMetaRowProps = {
32
+ label: ReactNode;
33
+ labelWidth?: string;
34
+ value: ReactNode;
35
+ className?: string;
36
+ nowrapValue?: boolean;
37
+ };
38
+ declare function CardMeta({ columns, className, children, ...rest }: CardMetaProps): JSX.Element;
39
+ declare function CardMetaRow({ label, value, className, nowrapValue, labelWidth, }: CardMetaRowProps): JSX.Element;
40
+ type CardComponent = ((props: CardProps) => JSX.Element) & {
41
+ Meta: typeof CardMeta;
42
+ MetaRow: typeof CardMetaRow;
43
+ };
44
+ export declare const Card: CardComponent;
27
45
  export {};
@@ -4,7 +4,7 @@ import styles from './Card.module.css';
4
4
  import { Headline } from '../headline/Headline';
5
5
  import { Hyperlink } from '../hyperlink/Hyperlink';
6
6
  import { SkeletonLoaderItem } from '../skeleton-loader/skeleton-loader-item/SkeletonLoaderItem';
7
- export function Card({ title, loading, variant = 'default', size = 'md', headerMarker = true, headerIcon, severity, image, imgPlacement = 'left', mediaWidth, actions, headerMeta, sectionTitle, showSectionDivider = false, children, link, width, }) {
7
+ function CardImpl({ title, loading, variant = 'default', size = 'md', headerMarker = true, headerIcon, severity, image, imgPlacement = 'left', mediaWidth, actions, headerMeta, sectionTitle, showSectionDivider = false, children, link, width, }) {
8
8
  const outerContainerStyle = width
9
9
  ? { ['--width']: `${width}%` }
10
10
  : undefined;
@@ -17,6 +17,21 @@ export function Card({ title, loading, variant = 'default', size = 'md', headerM
17
17
  ? styles.innerImgRight
18
18
  : styles.innerImgLeft;
19
19
  const inner = (_jsxs("div", { className: `${styles.inner} ${innerPlacementClass}`, children: [image && (_jsx("div", { className: styles.media, style: mediaStyle, children: image })), _jsxs("div", { className: styles.content, children: [(title || headerMeta) && (_jsxs("header", { className: styles.header, children: [title && (_jsx(Headline, { severity: severity, marker: headerMarker, icon: headerIcon, size: 4, weight: 500, disableMargin: true, children: title })), headerMeta && _jsx("div", { className: styles.headerMeta, children: headerMeta })] })), loading && (_jsx("div", { className: styles.loadingList, children: Array.from({ length: 4 }).map((_, index) => (_jsxs("div", { className: styles.loadingRow, children: [_jsx(SkeletonLoaderItem, {}), _jsx(SkeletonLoaderItem, { width: "100%" })] }, index))) })), !loading && (showSectionDivider || sectionTitle) && (_jsxs("div", { className: styles.section, children: [showSectionDivider && _jsx("div", { className: styles.sectionDivider }), sectionTitle && _jsx("div", { className: styles.sectionTitle, children: sectionTitle })] })), !loading && children && _jsx("div", { className: styles.body, children: children }), !loading && actions && _jsx("div", { className: styles.actions, children: actions })] })] }));
20
- const cardWithLink = link ? _jsx(Hyperlink, { component: link }) : inner;
20
+ // keep existing behavior
21
+ const cardWithLink = link ? _jsx(Hyperlink, { children: link }) : inner;
21
22
  return (_jsx("div", { className: `${styles.outerContainer} ${styles[size]}`, style: outerContainerStyle, children: _jsx("div", { className: [styles.container, styles[variant]].filter(Boolean).join(' '), children: cardWithLink }) }));
22
23
  }
24
+ // ---- subcomponents (declared normally) ----
25
+ function CardMeta({ columns = 2, className, children, ...rest }) {
26
+ const colsClass = columns === 1 ? styles.metaCols1 : columns === 2 ? styles.metaCols2 : styles.metaCols3;
27
+ return (_jsx("dl", { ...rest, className: [styles.metaGrid, colsClass, className].filter(Boolean).join(' '), children: children }));
28
+ }
29
+ function CardMetaRow({ label, value, className, nowrapValue, labelWidth, }) {
30
+ return (_jsxs("div", { className: [styles.metaRow, className].filter(Boolean).join(' '), style: { '--label-width': labelWidth }, children: [_jsx("dt", { className: styles.metaLabel, children: label }), _jsx("dd", { className: [styles.metaValue, nowrapValue ? styles.metaNowrap : undefined]
31
+ .filter(Boolean)
32
+ .join(' '), children: value })] }));
33
+ }
34
+ export const Card = Object.assign(CardImpl, {
35
+ Meta: CardMeta,
36
+ MetaRow: CardMetaRow,
37
+ });
@@ -171,3 +171,62 @@
171
171
  justify-content: flex-end; /* right-align buttons */
172
172
  gap: var(--spacing-sm);
173
173
  }
174
+
175
+ /* --- Meta grid primitives (optional) --- */
176
+
177
+ .metaGrid {
178
+ margin: 0;
179
+ display: grid;
180
+ gap: var(--spacing-xs) var(--spacing-lg);
181
+ }
182
+
183
+ .metaCols1 {
184
+ grid-template-columns: 1fr;
185
+ }
186
+
187
+ .metaCols2 {
188
+ grid-template-columns: 1fr;
189
+ }
190
+
191
+ .metaCols3 {
192
+ grid-template-columns: 1fr;
193
+ }
194
+
195
+ @media (min-width: 640px) {
196
+ .metaCols2 {
197
+ grid-template-columns: 1fr 1fr;
198
+ }
199
+ .metaCols3 {
200
+ grid-template-columns: 1fr 1fr 1fr;
201
+ }
202
+ }
203
+
204
+ .metaRow {
205
+ --label-width: 120px;
206
+ display: grid;
207
+ grid-template-columns: var(--label-width, auto) 1fr;
208
+ gap: var(--spacing-xs);
209
+ align-items: baseline;
210
+ min-inline-size: 0;
211
+ }
212
+
213
+ .metaLabel {
214
+ font-size: var(--font-size-xs);
215
+ color: var(--color-fg-subtle);
216
+ letter-spacing: var(--letter-spacing-wide);
217
+ text-transform: uppercase;
218
+ margin: 0;
219
+ }
220
+
221
+ .metaValue {
222
+ margin: 0;
223
+ font-size: var(--font-size-sm);
224
+ color: var(--color-fg-default);
225
+ font-weight: var(--font-weight-medium);
226
+ min-inline-size: 0;
227
+ word-break: break-word;
228
+ }
229
+
230
+ .metaNowrap {
231
+ white-space: nowrap;
232
+ }
@@ -1,9 +1,13 @@
1
1
  import type { ReactNode, JSX } from 'react';
2
2
  import { Severity } from '../../constants/severity.types';
3
+ type CircleSize = 'xs' | 'sm' | 'md' | 'lg';
3
4
  interface CircleProps {
4
5
  severity: Severity;
5
6
  children?: ReactNode;
6
7
  glow?: boolean;
8
+ muted?: boolean;
9
+ pulse?: boolean;
10
+ size?: CircleSize;
7
11
  }
8
- export declare function Circle({ severity, children, glow }: CircleProps): JSX.Element;
12
+ export declare function Circle({ severity, children, glow, muted, pulse, size, }: CircleProps): JSX.Element;
9
13
  export {};
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import styles from './Circle.module.css';
3
- export function Circle({ severity, children, glow }) {
4
- return (_jsxs("span", { className: styles.container, children: [_jsx("span", { "data-glow": glow, className: `${styles.circle} ${styles[severity]}` }), children, ' '] }));
3
+ export function Circle({ severity, children, glow, muted, pulse, size = 'sm', }) {
4
+ return (_jsxs("span", { className: styles.container, children: [_jsx("span", { "data-glow": glow, "data-pulse": pulse, "data-size": size, "data-muted": muted, className: `${styles.circle} ${styles[severity]}` }), children] }));
5
5
  }
@@ -10,15 +10,16 @@
10
10
  }
11
11
 
12
12
  .circle {
13
+ position: relative;
13
14
  display: inline-block;
14
- inline-size: var(--component-size-xs);
15
- block-size: var(--component-size-xs);
15
+ inline-size: var(--component-size-sm);
16
+ block-size: var(--component-size-sm);
16
17
  border-radius: var(--border-radius-round);
17
18
  flex-shrink: 0;
18
-
19
19
  transition:
20
20
  background-color var(--transition-fast) var(--ease-standard),
21
- box-shadow var(--transition-fast) var(--ease-standard);
21
+ box-shadow var(--transition-fast) var(--ease-standard),
22
+ opacity var(--transition-normal) var(--ease-standard);
22
23
  }
23
24
 
24
25
  /* Density modifier (optional) */
@@ -60,3 +61,58 @@
60
61
  .info[data-glow='true'] {
61
62
  box-shadow: 0 0 0 2px var(--color-status-info-bg);
62
63
  }
64
+
65
+ .circle[data-size='xs'] {
66
+ inline-size: var(--component-size-xxs);
67
+ block-size: var(--component-size-xxs);
68
+ }
69
+
70
+ .circle[data-size='sm'] {
71
+ inline-size: 14px;
72
+ block-size: 14px;
73
+ }
74
+
75
+ .circle[data-size='md'] {
76
+ inline-size: 18px;
77
+ block-size: 18px;
78
+ }
79
+
80
+ .circle[data-muted='true'] {
81
+ opacity: 0.4;
82
+ }
83
+
84
+ .circle[data-size='lg'] {
85
+ inline-size: 22px;
86
+ block-size: 22px;
87
+ }
88
+
89
+ .circle[data-pulse='true']::after {
90
+ content: '';
91
+ position: absolute;
92
+ inset: 0;
93
+ border-radius: inherit;
94
+ background-color: inherit;
95
+ animation: circle-pulse 1.6s ease-out infinite;
96
+ pointer-events: none;
97
+ }
98
+
99
+ @keyframes circle-pulse {
100
+ 0% {
101
+ transform: scale(1);
102
+ opacity: 0.6;
103
+ }
104
+ 60% {
105
+ transform: scale(2);
106
+ opacity: 0;
107
+ }
108
+ 100% {
109
+ transform: scale(2);
110
+ opacity: 0;
111
+ }
112
+ }
113
+
114
+ @media (prefers-reduced-motion: reduce) {
115
+ .circle[data-pulse='true']::after {
116
+ animation: none;
117
+ }
118
+ }
@@ -2,5 +2,5 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import styles from './CodeBlock.module.css';
3
3
  import { CopyButton } from '../copy-button/CopyButton';
4
4
  export function CodeBlock({ code, copyButton, size = 'md' }) {
5
- return (_jsxs("pre", { className: `${styles.container} ${styles[size]}`, children: [copyButton && (_jsx("span", { className: styles.copyButton, children: _jsx(CopyButton, { text: code }) })), _jsx("code", { className: styles.code, children: code })] }));
5
+ return (_jsxs("pre", { className: `${styles.container} ${styles[size]}`, tabIndex: 0, children: [copyButton && (_jsx("span", { className: styles.copyButton, children: _jsx(CopyButton, { style: "link", text: code }) })), _jsx("code", { className: styles.code, children: code })] }));
6
6
  }
@@ -1,21 +1,33 @@
1
1
  .container {
2
- background-color: var(--color-bg-contextual);
3
2
  position: relative;
4
- padding: var(--spacing-sm);
5
- border-radius: var(--border-radius-default);
6
- border: var(--border-width-thin) solid var(--color-border-default);
7
3
  margin-block: 0;
8
- font-family: var(--font-family-mono);
9
- white-space: pre-wrap;
10
- overflow-wrap: anywhere;
11
- word-break: break-word;
4
+
5
+ background: var(--color-bg-contextual-subtle);
6
+ border: var(--border-width-thin) solid var(--color-border-default);
7
+ border-radius: var(--border-radius-lg);
8
+ box-shadow: var(--shadow-xs);
9
+
10
+ padding: var(--spacing-sm);
12
11
  padding-inline-end: calc(var(--spacing-sm) + 40px);
12
+
13
+ font-family: var(--font-family-mono);
14
+ line-height: var(--line-height-relaxed);
15
+
16
+ overflow-x: auto;
17
+ overflow-y: hidden;
18
+
19
+ /* Nice: avoids layout shift if/when scrollbars appear (supported in modern browsers) */
20
+ scrollbar-gutter: stable;
21
+ }
22
+
23
+ .container:focus-within {
24
+ border-color: var(--color-border-selected);
25
+ box-shadow: var(--shadow-xs), var(--focus-ring);
13
26
  }
14
27
 
15
28
  .container.sm {
16
29
  padding: var(--spacing-xs);
17
- padding-inline-end: calc(var(--spacing-xxs) + 40px);
18
- min-height: 0;
30
+ padding-inline-end: calc(var(--spacing-xs) + 40px);
19
31
  }
20
32
 
21
33
  .container.sm .code {
@@ -25,6 +37,7 @@
25
37
  .container.md .code {
26
38
  font-size: var(--font-size-sm);
27
39
  }
40
+
28
41
  .container.lg .code {
29
42
  font-size: var(--font-size-base);
30
43
  }
@@ -33,11 +46,15 @@
33
46
  display: block;
34
47
  margin: 0;
35
48
  font-family: var(--font-family-mono);
36
- font-size: var(--font-size-xs);
37
- line-break: anywhere;
38
- word-break: break-all;
49
+ color: var(--color-fg-default);
50
+
51
+ /* ✅ Preserve formatting but avoid ugly breaking */
52
+ white-space: pre-wrap;
53
+ overflow-wrap: anywhere;
54
+ word-break: normal; /* <- not break-all */
39
55
  }
40
56
 
57
+ /* Copy button stays overlayed; does not affect layout */
41
58
  .copyButton {
42
59
  position: absolute;
43
60
  top: var(--spacing-xs);
@@ -54,7 +71,3 @@
54
71
  opacity: 1;
55
72
  pointer-events: auto;
56
73
  }
57
-
58
- .copyButton button {
59
- pointer-events: auto;
60
- }
@@ -5,6 +5,7 @@ interface CopyButtonProps {
5
5
  variant?: ButtonVariant;
6
6
  size?: ButtonSize;
7
7
  children?: ReactNode;
8
+ style?: 'button' | 'link';
8
9
  }
9
10
  export declare function CopyButton(props: CopyButtonProps & ComponentProps<typeof Button>): ReactNode;
10
11
  export {};
@@ -4,8 +4,9 @@ import { Check, Copy } from 'lucide-react';
4
4
  import { useState } from 'react';
5
5
  import styles from './CopyButton.module.css';
6
6
  import { Button } from '../button/Button';
7
+ import { Hyperlink } from '../hyperlink/Hyperlink';
7
8
  export function CopyButton(props) {
8
- var _a;
9
+ var _a, _b;
9
10
  const { text, variant = 'outlined', size = 'sm', children, ...rest } = props;
10
11
  const [copied, setCopied] = useState(false);
11
12
  const handleCopy = async () => {
@@ -18,5 +19,12 @@ export function CopyButton(props) {
18
19
  console.error('Failed to copy: ', err);
19
20
  }
20
21
  };
21
- return (_jsxs(Button, { ...rest, "aria-label": children ? '' : ((_a = rest['aria-label']) !== null && _a !== void 0 ? _a : 'Kopier til udklipsholder'), onClick: handleCopy, variant: variant, size: size, children: [_jsx("span", { className: `${styles.container} ${copied ? styles.copied : ''}`, children: copied ? _jsx(Check, {}) : _jsx(Copy, {}) }), children] }));
22
+ if (props.style === 'link') {
23
+ return (_jsx(Hyperlink, { asChild: true, variant: "secondary", inline: props.variant === 'inline', children: _jsxs("button", { "aria-label": children ? '' : ((_a = rest['aria-label']) !== null && _a !== void 0 ? _a : 'Kopier til udklipsholder'), onClick: e => {
24
+ e.preventDefault();
25
+ e.stopPropagation();
26
+ handleCopy();
27
+ }, className: `${styles.link} ${copied ? styles.copied : ''}`, children: [children, copied ? _jsx(Check, {}) : _jsx(Copy, {})] }) }));
28
+ }
29
+ return (_jsxs(Button, { ...rest, "aria-label": children ? '' : ((_b = rest['aria-label']) !== null && _b !== void 0 ? _b : 'Kopier til udklipsholder'), onClick: handleCopy, variant: variant, size: size, children: [_jsx("span", { className: `${styles.container} ${copied ? styles.copied : ''}`, children: copied ? _jsx(Check, {}) : _jsx(Copy, {}) }), children] }));
22
30
  }
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
2
  import { Input } from '../../components/forms/input/Input';
3
- import { DateOnly } from './dateTimeHelpers';
3
+ import { type UtcIsoString } from './dateTimeHelpers';
4
4
  type Mode = 'single' | 'range';
5
5
  type WeekStart = 0 | 1;
6
- export type DateValue = number | DateOnly | null | {
7
- start: DateOnly | null;
8
- end: DateOnly | null;
6
+ export type DateValue = UtcIsoString | null | {
7
+ start: UtcIsoString | null;
8
+ end: UtcIsoString | null;
9
9
  };
10
10
  type InputProps = React.ComponentProps<typeof Input>;
11
11
  export interface DateTimePickerProps {
@@ -25,10 +25,6 @@ export interface DateTimePickerProps {
25
25
  end: Date;
26
26
  };
27
27
  }[];
28
- /**
29
- * Forwarded to the internal <Input />.
30
- * DateTimePicker controls: value, onInput/onBlur/onKeyDown, icon, onClear.
31
- */
32
28
  inputProps?: Omit<InputProps, 'value' | 'onInput' | 'onBlur' | 'icon' | 'onClear' | 'type'>;
33
29
  formatDate?: (d: Date, opts: {
34
30
  locale: string;