@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.
- package/dist/components/accordion/Accordion.d.ts +27 -0
- package/dist/components/accordion/Accordion.js +66 -0
- package/dist/components/accordion/Accordion.module.css +87 -0
- package/dist/components/button/Button.module.css +1 -0
- package/dist/components/card/Card.d.ts +21 -3
- package/dist/components/card/Card.js +17 -2
- package/dist/components/card/Card.module.css +59 -0
- package/dist/components/circle/Circle.d.ts +5 -1
- package/dist/components/circle/Circle.js +2 -2
- package/dist/components/circle/Circle.module.css +60 -4
- package/dist/components/code-block/CodeBlock.js +1 -1
- package/dist/components/code-block/CodeBlock.module.css +30 -17
- package/dist/components/copy-button/CopyButton.d.ts +1 -0
- package/dist/components/copy-button/CopyButton.js +10 -2
- package/dist/components/datetime-picker/DateTimePicker.d.ts +4 -8
- package/dist/components/datetime-picker/DateTimePicker.js +72 -92
- package/dist/components/datetime-picker/dateTimeHelpers.d.ts +14 -12
- package/dist/components/datetime-picker/dateTimeHelpers.js +25 -45
- package/dist/components/filter-field/FilterField.js +16 -11
- package/dist/components/filter-field/FilterField.module.css +133 -12
- package/dist/components/forms/checkbox/Checkbox.d.ts +4 -10
- package/dist/components/forms/checkbox/Checkbox.js +3 -5
- package/dist/components/forms/checkbox-group/CheckboxGroup.js +1 -1
- package/dist/components/forms/checkbox-group/CheckboxGroup.module.css +1 -1
- package/dist/components/forms/input/Input.d.ts +1 -0
- package/dist/components/forms/input/Input.js +2 -4
- package/dist/components/forms/input/Input.module.css +10 -11
- package/dist/components/forms/input-container/InputContainer.d.ts +2 -1
- package/dist/components/forms/input-container/InputContainer.js +3 -3
- package/dist/components/forms/input-container/InputContainer.module.css +65 -0
- package/dist/components/forms/radio-buttons/RadioButton.d.ts +36 -0
- package/dist/components/forms/radio-buttons/RadioButton.js +26 -0
- package/dist/components/forms/radio-buttons/RadioButtonGroup.d.ts +25 -0
- package/dist/components/forms/radio-buttons/RadioButtonGroup.js +19 -0
- package/dist/components/forms/radio-buttons/RadioButtons.module.css +117 -0
- package/dist/components/forms/select/Select.d.ts +1 -1
- package/dist/components/forms/select/Select.js +3 -3
- package/dist/components/forms/text-area/Textarea.js +3 -3
- package/dist/components/forms/text-area/Textarea.module.css +8 -1
- package/dist/components/headline/Headline.d.ts +2 -7
- package/dist/components/headline/Headline.js +5 -2
- package/dist/components/headline/Headline.module.css +61 -2
- package/dist/components/hyperlink/Hyperlink.d.ts +19 -6
- package/dist/components/hyperlink/Hyperlink.js +35 -7
- package/dist/components/hyperlink/Hyperlink.module.css +50 -2
- package/dist/components/icon/Icon.module.css +1 -0
- package/dist/components/interval-select/IntervalSelect.js +1 -1
- package/dist/components/menu/Menu.d.ts +32 -0
- package/dist/components/menu/Menu.js +73 -13
- package/dist/components/menu/Menu.module.css +72 -4
- package/dist/components/nav-bar/NavBar.d.ts +24 -6
- package/dist/components/overlay/modal/Modal.module.css +2 -2
- package/dist/components/overlay/side-panel/SidePanel.d.ts +12 -4
- package/dist/components/overlay/side-panel/SidePanel.js +77 -4
- package/dist/components/overlay/side-panel/SidePanel.module.css +149 -28
- package/dist/components/overlay/side-panel/useSidePanel.d.ts +1 -1
- package/dist/components/overlay/side-panel/useSidePanel.js +2 -2
- package/dist/components/overlay/tooltip/useTooltipTrigger.js +4 -2
- package/dist/components/page-layout/PageLayout.js +0 -2
- package/dist/components/popover/Popover.js +1 -1
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.d.ts +5 -5
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +36 -24
- package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +0 -3
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +3 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +4 -3
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +109 -79
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.js +16 -3
- package/dist/components/sidebar/components/sidebar-items/SidebarItems.module.css +20 -0
- package/dist/components/sidebar/providers/SidebarProvider.d.ts +4 -1
- package/dist/components/sidebar/providers/SidebarProvider.js +85 -58
- package/dist/components/skeleton-loader/SkeletonLoader.d.ts +1 -1
- package/dist/components/skeleton-loader/SkeletonLoader.js +15 -12
- package/dist/components/split-button/SplitButton.d.ts +1 -1
- package/dist/components/split-button/SplitButton.js +3 -1
- package/dist/components/split-button/SplitButton.module.css +4 -4
- package/dist/components/state-page/StatePage.d.ts +9 -0
- package/dist/components/state-page/StatePage.js +20 -0
- package/dist/components/state-page/StatePage.module.css +9 -0
- package/dist/components/state-page/empty.d.ts +2 -0
- package/dist/components/state-page/empty.js +2 -0
- package/dist/components/state-page/error.d.ts +2 -0
- package/dist/components/state-page/error.js +2 -0
- package/dist/components/state-page/notFound.d.ts +2 -0
- package/dist/components/state-page/notFound.js +2 -0
- package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +19 -0
- package/dist/components/sticky-footer-layout/StickyFooterLayout.js +27 -0
- package/dist/components/table/Table.d.ts +9 -4
- package/dist/components/table/Table.js +6 -9
- package/dist/components/table/Table.module.css +180 -59
- package/dist/components/table/components/empty-state/EmptyState.d.ts +1 -1
- package/dist/components/table/components/empty-state/EmptyState.js +6 -7
- package/dist/components/table/components/table-settings/TableSettings.d.ts +13 -3
- package/dist/components/table/components/table-settings/TableSettings.js +55 -4
- package/dist/components/table/tanstack.d.ts +12 -1
- package/dist/components/table/tanstack.js +75 -23
- package/dist/components/toast/Toast.js +5 -1
- package/dist/components/toast/Toast.module.css +40 -15
- package/dist/components/toast/provider/ToastProvider.js +1 -0
- package/dist/hooks/useTableSettings.d.ts +23 -4
- package/dist/hooks/useTableSettings.js +64 -17
- package/dist/hooks/useTimeDuration.js +9 -3
- package/dist/hooks/useViewportFill.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -1
- package/dist/src/styles/styles.css +60 -25
- package/dist/styles/animation.d.ts +5 -0
- package/dist/styles/animation.js +5 -0
- package/dist/styles/styles.css +60 -25
- package/dist/styles/themes/dbc/dark.css +1 -1
- package/dist/styles/themes/dbc/light.css +2 -1
- package/dist/utils/localStorage.utils.d.ts +19 -0
- package/dist/utils/localStorage.utils.js +78 -0
- 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
|
+
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
15
|
-
block-size: var(--component-size-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
}
|
|
@@ -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
|
-
|
|
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 {
|
|
3
|
+
import { type UtcIsoString } from './dateTimeHelpers';
|
|
4
4
|
type Mode = 'single' | 'range';
|
|
5
5
|
type WeekStart = 0 | 1;
|
|
6
|
-
export type DateValue =
|
|
7
|
-
start:
|
|
8
|
-
end:
|
|
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;
|