@dbcdk/react-components 0.0.12 → 0.0.13

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 (75) hide show
  1. package/dist/components/accordion/Accordion.d.ts +2 -2
  2. package/dist/components/accordion/Accordion.js +34 -41
  3. package/dist/components/accordion/Accordion.module.css +13 -72
  4. package/dist/components/accordion/components/AccordionRow.d.ts +10 -0
  5. package/dist/components/accordion/components/AccordionRow.js +51 -0
  6. package/dist/components/accordion/components/AccordionRow.module.css +82 -0
  7. package/dist/components/breadcrumbs/Breadcrumbs.module.css +0 -1
  8. package/dist/components/button/Button.module.css +7 -7
  9. package/dist/components/card/Card.d.ts +9 -18
  10. package/dist/components/card/Card.js +34 -23
  11. package/dist/components/card/Card.module.css +22 -87
  12. package/dist/components/card/components/CardMeta.d.ts +15 -0
  13. package/dist/components/card/components/CardMeta.js +20 -0
  14. package/dist/components/card/components/CardMeta.module.css +51 -0
  15. package/dist/components/card-container/CardContainer.js +1 -1
  16. package/dist/components/card-container/CardContainer.module.css +3 -1
  17. package/dist/components/chip/Chip.module.css +7 -2
  18. package/dist/components/datetime-picker/DateTimePicker.d.ts +33 -8
  19. package/dist/components/datetime-picker/DateTimePicker.js +119 -78
  20. package/dist/components/datetime-picker/DateTimePicker.module.css +2 -0
  21. package/dist/components/datetime-picker/dateTimeHelpers.d.ts +15 -3
  22. package/dist/components/datetime-picker/dateTimeHelpers.js +137 -23
  23. package/dist/components/filter-field/FilterField.module.css +5 -5
  24. package/dist/components/forms/form-select/FormSelect.d.ts +35 -0
  25. package/dist/components/forms/form-select/FormSelect.js +86 -0
  26. package/dist/components/forms/form-select/FormSelect.module.css +236 -0
  27. package/dist/components/forms/input/Input.d.ts +0 -3
  28. package/dist/components/forms/input/Input.js +0 -3
  29. package/dist/components/forms/input/Input.module.css +7 -7
  30. package/dist/components/forms/radio-buttons/RadioButtons.module.css +1 -0
  31. package/dist/components/forms/select/Select.js +55 -16
  32. package/dist/components/interval-select/IntervalSelect.d.ts +9 -2
  33. package/dist/components/interval-select/IntervalSelect.js +21 -6
  34. package/dist/components/menu/Menu.d.ts +11 -14
  35. package/dist/components/menu/Menu.js +18 -33
  36. package/dist/components/menu/Menu.module.css +2 -2
  37. package/dist/components/overlay/modal/Modal.module.css +2 -1
  38. package/dist/components/overlay/modal/provider/ModalProvider.js +1 -3
  39. package/dist/components/overlay/side-panel/SidePanel.js +1 -1
  40. package/dist/components/overlay/side-panel/SidePanel.module.css +1 -1
  41. package/dist/components/page-layout/PageLayout.d.ts +16 -4
  42. package/dist/components/page-layout/PageLayout.js +57 -28
  43. package/dist/components/page-layout/PageLayout.module.css +153 -33
  44. package/dist/components/popover/Popover.d.ts +17 -4
  45. package/dist/components/popover/Popover.js +147 -65
  46. package/dist/components/popover/Popover.module.css +5 -0
  47. package/dist/components/split-pane/SplitPane.d.ts +10 -24
  48. package/dist/components/split-pane/SplitPane.js +83 -54
  49. package/dist/components/split-pane/SplitPane.module.css +11 -6
  50. package/dist/components/split-pane/provider/SplitPaneContext.js +5 -11
  51. package/dist/components/sticky-footer-layout/StickyFooterLayout.d.ts +3 -8
  52. package/dist/components/sticky-footer-layout/StickyFooterLayout.js +57 -20
  53. package/dist/components/table/Table.d.ts +3 -8
  54. package/dist/components/table/Table.js +37 -76
  55. package/dist/components/table/Table.module.css +45 -42
  56. package/dist/components/table/{tanstack.d.ts → TanstackTable.d.ts} +5 -12
  57. package/dist/components/table/TanstackTable.js +84 -0
  58. package/dist/components/table/components/column-resizer/ColumnResizer.js +1 -1
  59. package/dist/components/table/components/column-resizer/ColumnResizer.module.css +17 -7
  60. package/dist/components/table/table.utils.d.ts +17 -0
  61. package/dist/components/table/table.utils.js +61 -0
  62. package/dist/components/table/tanstackTable.utils.d.ts +22 -0
  63. package/dist/components/table/tanstackTable.utils.js +104 -0
  64. package/dist/components/tabs/Tabs.d.ts +35 -12
  65. package/dist/components/tabs/Tabs.js +114 -26
  66. package/dist/components/tabs/Tabs.module.css +158 -71
  67. package/dist/index.d.ts +1 -1
  68. package/dist/index.js +1 -1
  69. package/dist/src/styles/styles.css +0 -1
  70. package/dist/styles/styles.css +0 -1
  71. package/dist/styles/themes/dbc/base.css +136 -0
  72. package/dist/styles/themes/dbc/dark.css +39 -202
  73. package/dist/styles/themes/dbc/light.css +17 -174
  74. package/package.json +4 -4
  75. package/dist/components/table/tanstack.js +0 -214
@@ -1,5 +1,5 @@
1
- import type { ReactNode, JSX } from 'react';
2
- import { Severity } from '../../constants/severity.types';
1
+ import type { JSX, ReactNode } from 'react';
2
+ import type { Severity } from '../../constants/severity.types';
3
3
  export interface AccordionItem {
4
4
  header: string;
5
5
  headerIcon?: ReactNode;
@@ -1,42 +1,43 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useId, useMemo, useState } from 'react';
4
4
  import styles from './Accordion.module.css';
5
- import { Headline } from '../headline/Headline';
5
+ import { AccordionRow } from './components/AccordionRow';
6
6
  function uniqSorted(nums) {
7
7
  return Array.from(new Set(nums)).sort((a, b) => a - b);
8
8
  }
9
+ function normalizeMultiple(indexes) {
10
+ return uniqSorted((indexes !== null && indexes !== void 0 ? indexes : []).filter(n => Number.isFinite(n)));
11
+ }
9
12
  export function Accordion({ items, mode = 'single', size = 'md', defaultOpenIndex = null, defaultOpenIndexes = [], openIndex, openIndexes, onOpenIndexChange, onOpenIndexesChange, }) {
10
13
  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);
14
+ const isControlled = mode === 'single' ? openIndex !== undefined : openIndexes !== undefined;
15
+ const [internalSingle, setInternalSingle] = useState(mode === 'single' ? defaultOpenIndex : null);
16
+ const [internalMultiple, setInternalMultiple] = useState(mode === 'multiple' ? normalizeMultiple(defaultOpenIndexes) : []);
17
+ const currentOpenIndexes = useMemo(() => {
18
+ if (mode === 'single') {
19
+ const current = isControlled ? (openIndex !== null && openIndex !== void 0 ? openIndex : null) : internalSingle;
20
+ return current === null ? [] : [current];
32
21
  }
33
- }
34
- function setMultiple(next) {
35
- const normalized = uniqSorted(next);
36
- if (isControlledMultiple)
22
+ return isControlled ? normalizeMultiple(openIndexes) : internalMultiple;
23
+ }, [mode, isControlled, openIndex, openIndexes, internalSingle, internalMultiple]);
24
+ const openSet = useMemo(() => new Set(currentOpenIndexes), [currentOpenIndexes]);
25
+ function commit(nextIndexes) {
26
+ if (mode === 'single') {
27
+ const next = nextIndexes.length ? nextIndexes[0] : null;
28
+ if (isControlled)
29
+ onOpenIndexChange === null || onOpenIndexChange === void 0 ? void 0 : onOpenIndexChange(next);
30
+ else {
31
+ setInternalSingle(next);
32
+ onOpenIndexChange === null || onOpenIndexChange === void 0 ? void 0 : onOpenIndexChange(next);
33
+ }
34
+ return;
35
+ }
36
+ const normalized = uniqSorted(nextIndexes);
37
+ if (isControlled)
37
38
  onOpenIndexesChange === null || onOpenIndexesChange === void 0 ? void 0 : onOpenIndexesChange(normalized);
38
39
  else {
39
- setInternalOpenIndexes(normalized);
40
+ setInternalMultiple(normalized);
40
41
  onOpenIndexesChange === null || onOpenIndexesChange === void 0 ? void 0 : onOpenIndexesChange(normalized);
41
42
  }
42
43
  }
@@ -44,23 +45,15 @@ export function Accordion({ items, mode = 'single', size = 'md', defaultOpenInde
44
45
  const item = items[index];
45
46
  if (!item || item.disabled)
46
47
  return;
48
+ const isOpen = openSet.has(index);
47
49
  if (mode === 'single') {
48
- const isOpen = openSet.has(index);
49
- setSingle(isOpen ? null : index);
50
+ commit(isOpen ? [] : [index]);
50
51
  return;
51
52
  }
52
- // multiple
53
- const isOpen = openSet.has(index);
54
53
  if (isOpen)
55
- setMultiple(currentOpenIndexes.filter(i => i !== index));
54
+ commit(currentOpenIndexes.filter(i => i !== index));
56
55
  else
57
- setMultiple([...currentOpenIndexes, index]);
56
+ commit([...currentOpenIndexes, index]);
58
57
  }
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
- }) }));
58
+ return (_jsx("div", { className: `${styles.container} ${styles[size]}`, children: items.map((item, i) => (_jsx(AccordionRow, { uid: uid, index: i, item: item, isOpen: openSet.has(i), onToggle: toggle }, i))) }));
66
59
  }
@@ -8,80 +8,21 @@
8
8
  gap: var(--spacing-xxs);
9
9
  }
10
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);
11
+ /* Size variables (consumed by AccordionRow) */
12
+ .sm {
13
+ --acc-trigger-py: var(--spacing-sm);
14
+ --acc-trigger-px: var(--spacing-md);
15
+ --acc-content-py: var(--spacing-sm);
79
16
  }
80
17
 
81
- .md .trigger {
82
- padding: var(--spacing-sm) var(--spacing-md);
18
+ .md {
19
+ --acc-trigger-py: var(--spacing-sm);
20
+ --acc-trigger-px: var(--spacing-md);
21
+ --acc-content-py: var(--spacing-md);
83
22
  }
84
23
 
85
- .lg .trigger {
86
- padding: var(--spacing-md) var(--spacing-md);
24
+ .lg {
25
+ --acc-trigger-py: var(--spacing-md);
26
+ --acc-trigger-px: var(--spacing-md);
27
+ --acc-content-py: var(--spacing-md);
87
28
  }
@@ -0,0 +1,10 @@
1
+ import type { JSX } from 'react';
2
+ import { AccordionItem } from '../Accordion';
3
+ export type AccordionRowProps = {
4
+ uid: string;
5
+ index: number;
6
+ item: AccordionItem;
7
+ isOpen: boolean;
8
+ onToggle: (index: number) => void;
9
+ };
10
+ export declare function AccordionRow({ uid, index, item, isOpen, onToggle, }: AccordionRowProps): JSX.Element;
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronDown } from 'lucide-react';
3
+ import { useLayoutEffect, useRef, useState } from 'react';
4
+ import { Headline } from '../../../components/headline/Headline';
5
+ import styles from './AccordionRow.module.css';
6
+ function useCollapsibleHeight(isOpen) {
7
+ const innerRef = useRef(null);
8
+ const [height, setHeight] = useState('0px');
9
+ useLayoutEffect(() => {
10
+ var _a, _b;
11
+ const el = innerRef.current;
12
+ if (!el)
13
+ return;
14
+ const prefersReduced = typeof window !== 'undefined' &&
15
+ ((_b = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, '(prefers-reduced-motion: reduce)')) === null || _b === void 0 ? void 0 : _b.matches);
16
+ if (prefersReduced) {
17
+ setHeight(isOpen ? 'auto' : '0px');
18
+ return;
19
+ }
20
+ if (isOpen) {
21
+ // 0 -> scrollHeight
22
+ setHeight('0px');
23
+ requestAnimationFrame(() => {
24
+ setHeight(`${el.scrollHeight}px`);
25
+ });
26
+ }
27
+ else {
28
+ // lock -> 0 (important when currently 'auto')
29
+ setHeight(`${el.scrollHeight}px`);
30
+ requestAnimationFrame(() => {
31
+ setHeight('0px');
32
+ });
33
+ }
34
+ }, [isOpen]);
35
+ function onTransitionEnd(e) {
36
+ if (e.propertyName !== 'height')
37
+ return;
38
+ if (!innerRef.current)
39
+ return;
40
+ if (isOpen)
41
+ setHeight('auto');
42
+ }
43
+ return { innerRef, height, onTransitionEnd };
44
+ }
45
+ export function AccordionRow({ uid, index, item, isOpen, onToggle, }) {
46
+ const isDisabled = !!item.disabled;
47
+ const buttonId = `${uid}-acc-btn-${index}`;
48
+ const panelId = `${uid}-acc-panel-${index}`;
49
+ const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen);
50
+ return (_jsxs("section", { className: `${styles.item} ${isOpen ? styles.open : ''} ${isDisabled ? styles.disabled : ''}`, children: [_jsx("h3", { className: styles.heading, children: _jsxs("button", { type: "button", id: buttonId, className: styles.trigger, "aria-expanded": isOpen, "aria-controls": panelId, onClick: () => onToggle(index), disabled: isDisabled, children: [_jsxs("span", { className: styles.title, children: [item.headerIcon ? _jsx("span", { className: styles.icon, children: item.headerIcon }) : null, _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(ChevronDown, {}) })] }) }), _jsx("div", { id: panelId, role: "region", "aria-labelledby": buttonId, className: styles.panel, style: { height }, onTransitionEnd: onTransitionEnd, children: _jsx("div", { ref: innerRef, className: styles.content, children: item.children }) })] }));
51
+ }
@@ -0,0 +1,82 @@
1
+ .heading {
2
+ margin: 0;
3
+ }
4
+
5
+ .trigger {
6
+ all: unset;
7
+ box-sizing: border-box;
8
+
9
+ width: 100%;
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: space-between;
13
+ gap: var(--spacing-sm);
14
+
15
+ cursor: pointer;
16
+ user-select: none;
17
+
18
+ padding: var(--acc-trigger-py) var(--acc-trigger-px);
19
+ background: var(--color-bg-contextual);
20
+
21
+ min-width: 0;
22
+ }
23
+
24
+ .trigger:focus-visible {
25
+ outline: none;
26
+ box-shadow: var(--focus-ring);
27
+ }
28
+
29
+ .disabled .trigger {
30
+ cursor: not-allowed;
31
+ color: var(--color-disabled-fg);
32
+ }
33
+
34
+ .title {
35
+ display: flex;
36
+ align-items: center;
37
+ gap: var(--spacing-xs);
38
+
39
+ min-width: 0;
40
+ flex: 1 1 auto;
41
+ overflow: hidden;
42
+ }
43
+
44
+ .icon {
45
+ flex: 0 0 auto;
46
+ display: inline-flex;
47
+ align-items: center;
48
+ }
49
+
50
+ .chevron {
51
+ width: var(--icon-size-md);
52
+ height: var(--icon-size-md);
53
+ flex: 0 0 auto;
54
+ transition: transform var(--transition-normal) var(--ease-standard);
55
+ }
56
+
57
+ .chevron svg {
58
+ width: 100%;
59
+ height: 100%;
60
+ display: block;
61
+ }
62
+
63
+ .open .chevron {
64
+ transform: rotate(180deg);
65
+ }
66
+
67
+ .panel {
68
+ overflow: hidden;
69
+ height: 0px;
70
+ transition: height var(--transition-slow) var(--ease-decelerate);
71
+ }
72
+
73
+ /* Padding inside so scrollHeight includes it */
74
+ .content {
75
+ padding: var(--acc-content-py) var(--acc-trigger-px);
76
+ }
77
+
78
+ @media (prefers-reduced-motion: reduce) {
79
+ .panel {
80
+ transition: none;
81
+ }
82
+ }
@@ -1,6 +1,5 @@
1
1
  .breadcrumbs {
2
2
  font-family: var(--font-family);
3
- text-transform: var(--breadcrumb-transform);
4
3
  }
5
4
 
6
5
  .breadcrumbs ul {
@@ -13,10 +13,10 @@
13
13
  line-height: 1;
14
14
 
15
15
  height: var(--component-size-md);
16
- min-block-size: calc(var(--component-size-md) + var(--density));
16
+ min-block-size: var(--component-size-md);
17
17
 
18
- padding-inline: var(--control-padding-x);
19
- padding-block: calc(var(--control-padding-y) + var(--density));
18
+ padding-inline: var(--spacing-sm);
19
+ padding-block: var(--spacing-xs);
20
20
 
21
21
  border-width: var(--border-width-thin, 1px);
22
22
  border-style: solid;
@@ -86,19 +86,19 @@
86
86
 
87
87
  .button.xs {
88
88
  height: var(--component-size-xs);
89
- min-block-size: calc(var(--component-size-sm) + var(--density));
89
+ min-block-size: var(--component-size-sm);
90
90
  padding-inline: var(--spacing-sm);
91
91
  }
92
92
 
93
93
  .button.sm {
94
94
  height: var(--component-size-sm);
95
- min-block-size: calc(var(--component-size-sm) + var(--density));
95
+ min-block-size: var(--component-size-sm);
96
96
  padding-inline: var(--spacing-sm);
97
97
  }
98
98
 
99
99
  .button.xs {
100
100
  height: var(--component-size-xs);
101
- min-block-size: calc(var(--component-size-xs) + var(--density));
101
+ min-block-size: var(--component-size-xs);
102
102
  padding-inline: var(--spacing-xs);
103
103
  font-size: var(--font-size-xs);
104
104
  }
@@ -110,7 +110,7 @@
110
110
 
111
111
  .button.lg {
112
112
  height: var(--component-size-lg);
113
- min-block-size: calc(var(--component-size-lg) + var(--density));
113
+ min-block-size: var(--component-size-lg);
114
114
  padding-inline: var(--spacing-lg);
115
115
  }
116
116
 
@@ -1,6 +1,6 @@
1
- import type { ReactNode, JSX, HTMLAttributes } from 'react';
2
- import { JSXElementConstructor, ReactElement } from 'react';
3
- import { Severity } from '../../constants/severity.types';
1
+ import type { JSX, ReactNode } from 'react';
2
+ import type { Severity } from '../../constants/severity.types';
3
+ import { CardMeta, CardMetaRow } from './components/CardMeta';
4
4
  type CardVariant = 'default' | 'subtle' | 'strong';
5
5
  type CardSize = 'sm' | 'md' | 'lg';
6
6
  type CardImagePlacement = 'left' | 'right' | 'top';
@@ -20,23 +20,14 @@ export interface CardProps {
20
20
  sectionTitle?: string;
21
21
  showSectionDivider?: boolean;
22
22
  children?: ReactNode;
23
- link?: ReactElement<any, string | JSXElementConstructor<any>>;
23
+ /**
24
+ * Keep current behavior: if provided, Card becomes "linked".
25
+ * NOTE: this assumes your Hyperlink component can render the passed element correctly.
26
+ * If Hyperlink expects an <a>, pass <a href="...">...</a> or whatever your existing pattern is.
27
+ */
28
+ link?: ReactNode;
24
29
  width?: 25 | 33 | 50 | 66 | 75 | 100;
25
30
  }
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
31
  type CardComponent = ((props: CardProps) => JSX.Element) & {
41
32
  Meta: typeof CardMeta;
42
33
  MetaRow: typeof CardMetaRow;
@@ -1,35 +1,46 @@
1
- 'use client';
2
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
2
  import styles from './Card.module.css';
3
+ import { CardMeta, CardMetaRow } from './components/CardMeta';
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
- 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
- const outerContainerStyle = width
9
- ? { ['--width']: `${width}%` }
10
- : undefined;
7
+ function getInnerPlacementClass(imgPlacement, s) {
8
+ switch (imgPlacement) {
9
+ case 'top':
10
+ return s.innerImgTop;
11
+ case 'right':
12
+ return s.innerImgRight;
13
+ case 'left':
14
+ default:
15
+ return s.innerImgLeft;
16
+ }
17
+ }
18
+ function getVariantClass(variant, s) {
19
+ switch (variant) {
20
+ case 'subtle':
21
+ return s.variantSubtle;
22
+ case 'strong':
23
+ return s.variantStrong;
24
+ case 'default':
25
+ default:
26
+ return s.variantDefault;
27
+ }
28
+ }
29
+ function CardImpl({ title, loading = false, variant = 'default', size = 'md', headerMarker = true, headerIcon, severity, image, imgPlacement = 'left', mediaWidth, actions, headerMeta, sectionTitle, showSectionDivider = false, children, link, width, }) {
30
+ const outerStyle = width ? { ['--width']: `${width}%` } : undefined;
11
31
  const mediaStyle = mediaWidth
12
32
  ? { ['--card-media-width']: `${mediaWidth}px` }
13
33
  : undefined;
14
- const innerPlacementClass = imgPlacement === 'top'
15
- ? styles.innerImgTop
16
- : imgPlacement === 'right'
17
- ? styles.innerImgRight
18
- : styles.innerImgLeft;
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 })] })] }));
34
+ const innerPlacementClass = getInnerPlacementClass(imgPlacement, styles);
35
+ const variantClass = getVariantClass(variant, styles);
36
+ const hasHeader = !!title || !!headerMeta;
37
+ const showSection = !loading && (showSectionDivider || !!sectionTitle);
38
+ const showBody = !loading && !!children;
39
+ const showActions = !loading && !!actions;
40
+ const inner = (_jsxs("div", { className: `${styles.inner} ${innerPlacementClass}`, children: [image ? (_jsx("div", { className: styles.media, style: mediaStyle, children: image })) : null, _jsxs("div", { className: styles.content, children: [hasHeader ? (_jsxs("header", { className: styles.header, children: [title ? (_jsx(Headline, { severity: severity, marker: headerMarker, icon: headerIcon, size: 4, weight: 500, disableMargin: true, children: title })) : null, headerMeta ? _jsx("div", { className: styles.headerMeta, children: headerMeta }) : null] })) : null, loading ? (_jsx("div", { className: styles.loadingList, "aria-busy": "true", "aria-live": "polite", children: Array.from({ length: 4 }, (_, index) => (_jsxs("div", { className: styles.loadingRow, children: [_jsx(SkeletonLoaderItem, {}), _jsx(SkeletonLoaderItem, { width: "100%" })] }, index))) })) : null, showSection ? (_jsxs("div", { className: styles.section, children: [showSectionDivider ? _jsx("div", { className: styles.sectionDivider }) : null, sectionTitle ? _jsx("div", { className: styles.sectionTitle, children: sectionTitle }) : null] })) : null, showBody ? _jsx("div", { className: styles.body, children: children }) : null, showActions ? _jsx("div", { className: styles.actions, children: actions }) : null] })] }));
20
41
  // keep existing behavior
21
- const cardWithLink = link ? _jsx(Hyperlink, { children: link }) : inner;
22
- return (_jsx("div", { className: `${styles.outerContainer} ${styles[size]}`, style: outerContainerStyle, children: _jsx("div", { className: [styles.container, styles[variant]].filter(Boolean).join(' '), children: cardWithLink }) }));
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 })] }));
42
+ const cardContent = link ? _jsx(Hyperlink, { children: link }) : inner;
43
+ return (_jsx("div", { className: `${styles.outerContainer} ${styles[size]}`, style: outerStyle, children: _jsx("div", { className: `${styles.container} ${variantClass}`, children: cardContent }) }));
33
44
  }
34
45
  export const Card = Object.assign(CardImpl, {
35
46
  Meta: CardMeta,