@dbcdk/react-components 0.0.88 → 0.0.89

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 (65) hide show
  1. package/dist/components/accordion/Accordion.d.ts +1 -0
  2. package/dist/components/accordion/components/AccordionRow.js +1 -1
  3. package/dist/components/button/Button.js +8 -1
  4. package/dist/components/button/Button.module.css +2 -1
  5. package/dist/components/card/Card.d.ts +1 -5
  6. package/dist/components/card/Card.js +29 -4
  7. package/dist/components/card/Card.module.css +85 -98
  8. package/dist/components/card-container/CardContainer.d.ts +2 -1
  9. package/dist/components/card-container/CardContainer.js +2 -2
  10. package/dist/components/card-container/CardContainer.module.css +10 -9
  11. package/dist/components/clear-button/ClearButton.d.ts +2 -1
  12. package/dist/components/clear-button/ClearButton.js +6 -2
  13. package/dist/components/clear-button/ClearButton.module.css +6 -0
  14. package/dist/components/divider/Divider.d.ts +5 -0
  15. package/dist/components/divider/Divider.js +12 -0
  16. package/dist/components/forms/input/Input.d.ts +2 -1
  17. package/dist/components/forms/input/Input.js +6 -2
  18. package/dist/components/forms/input/Input.module.css +32 -0
  19. package/dist/components/forms/select/Select.d.ts +2 -1
  20. package/dist/components/forms/select/Select.js +2 -2
  21. package/dist/components/forms/typeahead/Typeahead.d.ts +2 -1
  22. package/dist/components/forms/typeahead/Typeahead.js +180 -118
  23. package/dist/components/forms/typeahead/Typeahead.module.css +4 -0
  24. package/dist/components/grid/Grid.d.ts +21 -0
  25. package/dist/components/grid/Grid.js +21 -0
  26. package/dist/components/grid/Grid.module.css +20 -0
  27. package/dist/components/headline/Headline.d.ts +3 -3
  28. package/dist/components/headline/Headline.js +6 -6
  29. package/dist/components/headline/Headline.module.css +25 -6
  30. package/dist/components/nav-bar/NavBar.module.css +6 -2
  31. package/dist/components/overlay/modal/Modal.d.ts +2 -1
  32. package/dist/components/overlay/modal/Modal.js +5 -3
  33. package/dist/components/overlay/modal/provider/ModalProvider.js +2 -0
  34. package/dist/components/overlay/side-panel/SidePanel.d.ts +2 -1
  35. package/dist/components/overlay/side-panel/SidePanel.js +2 -2
  36. package/dist/components/page/Page.d.ts +5 -1
  37. package/dist/components/page/Page.js +6 -2
  38. package/dist/components/page/Page.module.css +54 -4
  39. package/dist/components/panel/Panel.d.ts +2 -1
  40. package/dist/components/panel/Panel.js +2 -2
  41. package/dist/components/stack/Stack.d.ts +16 -0
  42. package/dist/components/stack/Stack.js +19 -0
  43. package/dist/components/state-page/StatePage.d.ts +2 -1
  44. package/dist/components/state-page/StatePage.js +2 -2
  45. package/dist/components/table/Table.d.ts +1 -1
  46. package/dist/components/table/Table.js +22 -4
  47. package/dist/components/table/Table.module.css +14 -0
  48. package/dist/components/table/Table.types.d.ts +1 -0
  49. package/dist/components/tabs/Tabs.d.ts +3 -1
  50. package/dist/components/tabs/Tabs.js +4 -2
  51. package/dist/components/tabs/Tabs.module.css +4 -0
  52. package/dist/components/theme-button/ThemeButton.d.ts +1 -0
  53. package/dist/components/theme-button/ThemeButton.js +5 -1
  54. package/dist/components/toast/Toast.d.ts +2 -1
  55. package/dist/components/toast/Toast.js +2 -2
  56. package/dist/hooks/useViewportFill.d.ts +2 -6
  57. package/dist/hooks/useViewportFill.js +29 -24
  58. package/dist/index.d.ts +4 -0
  59. package/dist/index.js +4 -0
  60. package/dist/styles/css-helper-classes/flex.css +12 -0
  61. package/dist/styles/css-helper-classes/spacing.css +5 -0
  62. package/dist/styles/styles.css +154 -66
  63. package/dist/styles/themes/dbc/colors.css +10 -0
  64. package/dist/styles.css +154 -66
  65. package/package.json +1 -1
@@ -2,6 +2,7 @@ import type { JSX, ReactNode } from 'react';
2
2
  import type { Severity } from '../../constants/severity.types';
3
3
  export interface AccordionItem {
4
4
  header: string;
5
+ subheader?: ReactNode;
5
6
  headerAddition?: ReactNode;
6
7
  headerIcon?: ReactNode;
7
8
  severity?: Severity;
@@ -49,5 +49,5 @@ export function AccordionRow({ uid, index, item, isOpen, onToggle, shouldAnimate
49
49
  const buttonId = `${uid}-acc-btn-${index}`;
50
50
  const panelId = `${uid}-acc-panel-${index}`;
51
51
  const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen, shouldAnimate);
52
- return (_jsxs("section", { className: `${styles.item} ${isOpen ? styles.open : ''} ${isDisabled ? styles.disabled : ''}`, children: [_jsx("div", { 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 }), item.headerAddition] }), _jsx("span", { className: styles.chevron, "aria-hidden": "true", children: _jsx(ChevronDown, {}) })] }) }), _jsx("div", { id: panelId, role: "region", "aria-labelledby": buttonId, className: `${styles.panel} ${shouldAnimate ? styles.animate : styles.noAnimate}`, style: { height }, onTransitionEnd: onTransitionEnd, children: _jsx("div", { ref: innerRef, className: styles.content, children: item.children }) })] }));
52
+ return (_jsxs("section", { className: `${styles.item} ${isOpen ? styles.open : ''} ${isDisabled ? styles.disabled : ''}`, children: [_jsx("div", { 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, subheader: item.subheader, allowWrap: isOpen, children: item.header }), item.headerAddition] }), _jsx("span", { className: styles.chevron, "aria-hidden": "true", children: _jsx(ChevronDown, {}) })] }) }), _jsx("div", { id: panelId, role: "region", "aria-labelledby": buttonId, className: `${styles.panel} ${shouldAnimate ? styles.animate : styles.noAnimate}`, style: { height }, onTransitionEnd: onTransitionEnd, children: _jsx("div", { ref: innerRef, className: styles.content, children: item.children }) })] }));
53
53
  }
@@ -67,7 +67,14 @@ export const Button = React.forwardRef(function Button({ variant = 'outlined', s
67
67
  });
68
68
  }
69
69
  else {
70
- buttonEl = (_jsx("button", { className: computedClassName, type: type, ...buttonProps, ...(tooltipEnabled ? triggerProps : {}), "aria-describedby": describedBy, children: content }));
70
+ const isDisabled = Boolean(buttonProps.disabled);
71
+ buttonEl = (_jsx("button", { className: computedClassName, type: type, ...buttonProps, ...(tooltipEnabled && !isDisabled ? triggerProps : {}), "aria-describedby": describedBy, children: content }));
72
+ if (tooltipEnabled && isDisabled) {
73
+ buttonEl = (_jsx("span", { ref: triggerProps.ref, onPointerEnter: triggerProps.onPointerEnter, onPointerLeave: triggerProps.onPointerLeave, style: {
74
+ display: fullWidth ? 'flex' : 'inline-flex',
75
+ cursor: 'not-allowed',
76
+ }, children: buttonEl }));
77
+ }
71
78
  }
72
79
  return buttonEl;
73
80
  });
@@ -2,7 +2,7 @@
2
2
  display: inline-flex;
3
3
  align-items: center;
4
4
  justify-content: center;
5
- gap: var(--spacing-xxs);
5
+ gap: var(--spacing-xs);
6
6
 
7
7
  font-family: var(--font-family);
8
8
  font-size: var(--font-size-sm);
@@ -117,6 +117,7 @@
117
117
 
118
118
  .button.lg {
119
119
  height: var(--component-size-lg);
120
+ font-size: var(--font-size-md);
120
121
  min-block-size: var(--component-size-lg);
121
122
  padding-inline: var(--spacing-lg);
122
123
  }
@@ -6,6 +6,7 @@ type CardSize = 'sm' | 'md' | 'lg';
6
6
  type CardImagePlacement = 'left' | 'right' | 'top';
7
7
  export interface CardProps {
8
8
  title?: string;
9
+ subheader?: ReactNode;
9
10
  loading?: boolean;
10
11
  variant?: CardVariant;
11
12
  size?: CardSize;
@@ -21,11 +22,6 @@ export interface CardProps {
21
22
  sectionTitle?: string;
22
23
  showSectionDivider?: boolean;
23
24
  children?: ReactNode;
24
- /**
25
- * Keep current behavior: if provided, Card becomes "linked".
26
- * NOTE: this assumes your Hyperlink component can render the passed element correctly.
27
- * If Hyperlink expects an <a>, pass <a href="...">...</a> or whatever your existing pattern is.
28
- */
29
25
  link?: ReactNode;
30
26
  width?: 25 | 33 | 50 | 66 | 75 | 100;
31
27
  headlineSize?: 1 | 2 | 3 | 4 | 5 | 6;
@@ -4,6 +4,27 @@ 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
+ /**
8
+ * Fix for flex gap issue:
9
+ * Distributes gap proportionally across cards
10
+ */
11
+ function getGapShare(width) {
12
+ switch (width) {
13
+ case 25:
14
+ return 'calc(var(--card-container-gap, var(--spacing-md)) * 3 / 4)';
15
+ case 33:
16
+ return 'calc(var(--card-container-gap, var(--spacing-md)) * 2 / 3)';
17
+ case 50:
18
+ return 'calc(var(--card-container-gap, var(--spacing-md)) / 2)';
19
+ case 66:
20
+ return 'calc(var(--card-container-gap, var(--spacing-md)) * 2 / 3)';
21
+ case 75:
22
+ return 'calc(var(--card-container-gap, var(--spacing-md)) * 3 / 4)';
23
+ case 100:
24
+ default:
25
+ return '0px';
26
+ }
27
+ }
7
28
  function getInnerPlacementClass(imgPlacement, s) {
8
29
  switch (imgPlacement) {
9
30
  case 'top':
@@ -24,8 +45,13 @@ function getVariantClass(variant, s) {
24
45
  return s.variantDefault;
25
46
  }
26
47
  }
27
- function CardImpl({ title, loading = false, variant = 'default', size = 'md', headerMarker = true, headerIcon, headerAddition, severity, image, imgPlacement = 'left', mediaWidth, actions, headerMeta, sectionTitle, showSectionDivider = false, children, link, width, headlineSize = 4, }) {
28
- const outerStyle = width ? { ['--width']: `${width}%` } : undefined;
48
+ function CardImpl({ title, subheader, loading = false, variant = 'default', size = 'md', headerMarker = true, headerIcon, headerAddition, severity, image, imgPlacement = 'left', mediaWidth, actions, headerMeta, sectionTitle, showSectionDivider = false, children, link, width, headlineSize = 4, }) {
49
+ const outerStyle = width
50
+ ? {
51
+ ['--width']: `${width}%`,
52
+ ['--gap-share']: getGapShare(width),
53
+ }
54
+ : undefined;
29
55
  const mediaStyle = mediaWidth
30
56
  ? { ['--card-media-width']: `${mediaWidth}px` }
31
57
  : undefined;
@@ -35,8 +61,7 @@ function CardImpl({ title, loading = false, variant = 'default', size = 'md', he
35
61
  const showSection = !loading && (showSectionDivider || !!sectionTitle);
36
62
  const showBody = !loading && !!children;
37
63
  const showActions = !loading && !!actions;
38
- 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, addition: headerAddition, size: headlineSize, 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] })] }));
39
- // keep existing behavior
64
+ 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, addition: headerAddition, subheader: subheader, size: headlineSize, 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] })] }));
40
65
  const cardContent = link ? _jsx(Hyperlink, { children: link }) : inner;
41
66
  return (_jsx("div", { className: `${styles.outerContainer} ${styles[size]}`, style: outerStyle, children: _jsx("div", { className: `${styles.container} ${variantClass}`, children: cardContent }) }));
42
67
  }
@@ -1,62 +1,53 @@
1
- /* OUTER WRAPPER (optional width control) */
2
1
  .outerContainer {
3
- inline-size: var(--width, 100%);
2
+ --width: 100%;
3
+ --gap-share: 0px;
4
+
5
+ flex: 0 1 calc(var(--width) - var(--gap-share));
6
+ min-width: 0;
7
+ box-sizing: border-box;
4
8
  }
5
9
 
6
- /* CARD CONTAINER */
10
+ /* Card surface */
7
11
  .container {
8
- inline-size: 100%;
9
- position: relative;
10
- color: var(--card-fg-default, var(--color-fg-default));
11
- background-color: var(--card-bg-default, var(--color-bg-surface));
12
- border-radius: var(--border-radius-md);
13
- border: var(--border-width-thin) solid var(--color-border-subtle);
14
- box-shadow: var(--shadow-xs);
15
- transition:
16
- color var(--transition-fast) var(--ease-standard),
17
- box-shadow var(--transition-fast) var(--ease-standard),
18
- transform var(--transition-fast) var(--ease-standard);
19
- }
12
+ height: 100%;
13
+ border-radius: var(--border-radius-sm);
14
+ box-sizing: border-box;
20
15
 
21
- .container:hover {
22
- box-shadow: var(--shadow-sm);
16
+ /* ✅ Restore border */
17
+ border: 1px solid var(--color-border-subtle);
18
+
19
+ /* Optional: ensure background sits under border */
20
+ background-clip: padding-box;
23
21
  }
24
22
 
25
- /* BACKGROUND VARIANTS */
23
+ /* Variants */
26
24
  .variantDefault {
27
- background-color: var(--card-bg-default, var(--color-bg-surface));
25
+ background-color: var(--card-bg-default, var(--color-bg-surface, var(--color-bg-surface-subtle)));
28
26
  }
29
27
 
30
28
  .variantSubtle {
31
- background-color: var(--card-bg-subtle, var(--color-bg-contextual-subtle));
29
+ background-color: var(--card-bg-subtle, var(--color-bg-surface-subtle, var(--color-bg-surface)));
32
30
  }
33
31
 
34
- /* SIZE VARIANTS (define vars once; inner uses them) */
35
- .sm {
36
- --card-pad: var(--spacing-md);
37
- --card-gap: var(--spacing-md);
32
+ /* Sizes */
33
+ .sm .container {
34
+ padding: var(--spacing-md);
38
35
  }
39
- .md {
40
- --card-pad: var(--spacing-lg);
41
- --card-gap: var(--spacing-lg);
36
+
37
+ .md .container {
38
+ padding: var(--spacing-lg);
42
39
  }
43
- .lg {
44
- --card-pad: var(--spacing-xl);
45
- --card-gap: var(--spacing-xl);
40
+
41
+ .lg .container {
42
+ padding: var(--spacing-xl);
46
43
  }
47
44
 
48
- /* INNER LAYOUT */
45
+ /* Layout */
49
46
  .inner {
50
- margin-inline: auto;
51
47
  display: flex;
52
- align-items: flex-start;
53
- padding: var(--card-pad);
54
- gap: var(--card-gap);
55
- }
56
-
57
- /* Media placement */
58
- .innerImgTop {
59
- flex-direction: column;
48
+ gap: var(--spacing-lg);
49
+ height: 100%;
50
+ min-width: 0;
60
51
  }
61
52
 
62
53
  .innerImgLeft {
@@ -67,101 +58,97 @@
67
58
  flex-direction: row-reverse;
68
59
  }
69
60
 
70
- /* MEDIA */
71
- .media {
72
- flex: 0 0 auto;
73
- display: flex;
74
- align-items: flex-start;
75
- justify-content: center;
76
- }
77
-
78
- .innerImgLeft .media,
79
- .innerImgRight .media {
80
- inline-size: var(--card-media-width, 56px);
81
- max-inline-size: 25%;
82
- }
83
-
84
- .innerImgTop .media {
85
- inline-size: 100%;
86
- max-inline-size: 100%;
61
+ .innerImgTop {
62
+ flex-direction: column;
87
63
  }
88
64
 
89
- .media img,
90
- .media picture,
91
- .media video,
92
- .media svg {
93
- display: block;
94
- inline-size: 100%;
95
- block-size: auto;
65
+ .media {
66
+ flex: 0 0 var(--card-media-width, auto);
67
+ min-width: 0;
96
68
  }
97
69
 
98
- /* CONTENT */
99
70
  .content {
100
- flex: 1 1 auto;
101
- min-inline-size: 0;
102
71
  display: flex;
72
+ flex: 1 1 auto;
103
73
  flex-direction: column;
104
74
  gap: var(--spacing-md);
75
+ min-width: 0;
105
76
  }
106
77
 
107
- /* HEADER */
78
+ /* Header */
108
79
  .header {
109
80
  display: flex;
110
81
  align-items: flex-start;
111
82
  justify-content: space-between;
112
- gap: var(--spacing-sm);
113
- }
114
-
115
- .header > :first-child {
116
- flex: 1 1 auto;
117
- min-inline-size: 0;
83
+ gap: var(--spacing-md);
84
+ min-width: 0;
118
85
  }
119
86
 
120
87
  .headerMeta {
121
- display: flex;
122
- align-items: center;
123
- gap: var(--spacing-xs);
88
+ flex: 0 0 auto;
124
89
  }
125
90
 
126
- /* LOADING */
127
- .loadingList {
128
- display: grid;
129
- gap: var(--spacing-sm);
91
+ /* Body */
92
+ .body {
93
+ min-width: 0;
130
94
  }
131
95
 
132
- .loadingRow {
133
- display: grid;
134
- grid-template-columns: auto 1fr;
96
+ /* Actions */
97
+ .actions {
98
+ display: flex;
99
+ flex-wrap: wrap;
135
100
  gap: var(--spacing-sm);
136
- align-items: center;
101
+ margin-top: auto;
137
102
  }
138
103
 
139
- /* SECTION */
104
+ /* Section */
140
105
  .section {
141
106
  display: flex;
142
107
  flex-direction: column;
143
- gap: var(--spacing-md);
108
+ gap: var(--spacing-sm);
144
109
  }
145
110
 
146
111
  .sectionDivider {
147
- inline-size: 100%;
148
- block-size: var(--border-width-thin);
149
- background: var(--color-border-subtle);
112
+ width: 100%;
113
+ height: 1px;
114
+ background-color: var(--color-border-subtle);
150
115
  }
151
116
 
152
117
  .sectionTitle {
153
- font-weight: var(--font-weight-semibold);
118
+ font-weight: 500;
154
119
  }
155
120
 
156
- /* BODY */
157
- .body {
158
- /* neutral container */
121
+ /* Loading */
122
+ .loadingList {
123
+ display: flex;
124
+ flex-direction: column;
125
+ gap: var(--spacing-md);
159
126
  }
160
127
 
161
- /* ACTIONS */
162
- .actions {
163
- margin-top: auto;
128
+ .loadingRow {
164
129
  display: flex;
165
- justify-content: flex-end;
130
+ flex-direction: column;
166
131
  gap: var(--spacing-sm);
167
132
  }
133
+
134
+ /* Responsive */
135
+ @media screen and (max-width: 767px) {
136
+ .outerContainer {
137
+ --width: 100%;
138
+ --gap-share: 0px;
139
+
140
+ flex-basis: 100%;
141
+ max-width: 100%;
142
+ }
143
+
144
+ .inner,
145
+ .innerImgLeft,
146
+ .innerImgRight,
147
+ .innerImgTop {
148
+ flex-direction: column;
149
+ }
150
+
151
+ .header {
152
+ flex-direction: column;
153
+ }
154
+ }
@@ -2,10 +2,11 @@ import type { JSX, ReactNode } from 'react';
2
2
  import { Severity } from '../../constants/severity.types';
3
3
  interface CardContainerProps {
4
4
  headline?: string;
5
+ subheader?: ReactNode;
5
6
  children?: ReactNode[];
6
7
  expand?: boolean;
7
8
  severity?: Severity;
8
9
  displayHeaderMarker?: boolean;
9
10
  }
10
- export declare function CardContainer({ children, headline, expand, severity, displayHeaderMarker, }: CardContainerProps): JSX.Element;
11
+ export declare function CardContainer({ children, headline, subheader, expand, severity, displayHeaderMarker, }: CardContainerProps): JSX.Element;
11
12
  export {};
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Headline } from '../../components/headline/Headline';
3
3
  import styles from './CardContainer.module.css';
4
- export function CardContainer({ children, headline, expand, severity, displayHeaderMarker, }) {
5
- return (_jsxs("div", { className: styles.wrapper, children: [headline && (_jsx(Headline, { marker: displayHeaderMarker, severity: severity, disableMargin: true, children: headline })), _jsx("div", { className: styles.container, style: { ['--expand']: expand ? '1' : '0' }, children: children })] }));
4
+ export function CardContainer({ children, headline, subheader, expand, severity, displayHeaderMarker, }) {
5
+ return (_jsxs("div", { className: styles.wrapper, children: [headline && (_jsx(Headline, { marker: displayHeaderMarker, severity: severity, disableMargin: true, subheader: subheader, children: headline })), _jsx("div", { className: styles.container, style: { ['--expand']: expand ? '1' : '0' }, children: children })] }));
6
6
  }
@@ -8,8 +8,8 @@
8
8
  display: flex;
9
9
  flex-wrap: wrap;
10
10
  gap: var(--spacing-md);
11
+ --card-container-gap: var(--spacing-md);
11
12
  border-radius: var(--border-radius-sm);
12
- --width: 100%;
13
13
  }
14
14
 
15
15
  .container.default {
@@ -47,14 +47,15 @@
47
47
  padding: var(--spacing-lg);
48
48
  }
49
49
 
50
- @media screen and (min-width: 768px) {
51
- .container {
52
- --width: 33.333%;
53
- }
54
- }
55
-
56
50
  .container > * {
57
- flex-grow: var(--expand);
58
- flex-shrink: 1;
51
+ min-width: 0;
59
52
  box-sizing: border-box;
60
53
  }
54
+
55
+ /* Mobile: stack */
56
+ @media screen and (max-width: 767px) {
57
+ .container > * {
58
+ flex-basis: 100% !important;
59
+ max-width: 100%;
60
+ }
61
+ }
@@ -1,6 +1,7 @@
1
1
  import type { ReactNode } from 'react';
2
+ import * as React from 'react';
2
3
  interface ClearButtonProps {
3
- onClick: () => void;
4
+ onClick?: (event?: React.MouseEvent | React.KeyboardEvent) => void;
4
5
  absolute?: boolean;
5
6
  }
6
7
  export declare function ClearButton({ onClick, absolute }: ClearButtonProps): ReactNode;
@@ -2,8 +2,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { X } from 'lucide-react';
3
3
  import styles from './ClearButton.module.css';
4
4
  export function ClearButton({ onClick, absolute }) {
5
- return (_jsx("span", { className: `${styles.clearButton} ${absolute ? styles.absolute : ''}`, children: _jsx("span", { className: styles.button, role: "button", onClick: e => {
5
+ return (_jsx("span", { className: `${styles.clearButton} ${absolute ? styles.absolute : ''}`, children: _jsx("button", { className: styles.button, type: "button", "data-input-role": "clear", onMouseDown: e => {
6
+ e.preventDefault();
6
7
  e.stopPropagation();
7
- onClick();
8
+ }, onClick: e => {
9
+ e.preventDefault();
10
+ e.stopPropagation();
11
+ onClick === null || onClick === void 0 ? void 0 : onClick(e);
8
12
  }, children: _jsx(X, { size: 16 }) }) }));
9
13
  }
@@ -1,8 +1,14 @@
1
1
  .clearButton .button {
2
+ appearance: none;
2
3
  display: flex;
3
4
  align-items: center;
4
5
  justify-content: center;
6
+ margin: 0;
7
+ border: 0;
8
+ background: transparent;
5
9
  color: var(--color-fg-subtle);
10
+ font: inherit;
11
+ line-height: 0;
6
12
  padding: var(--spacing-xxs);
7
13
  cursor: pointer;
8
14
  border-radius: 100%;
@@ -0,0 +1,5 @@
1
+ type DividerProps = {
2
+ spacing?: 'sm' | 'md' | 'lg';
3
+ };
4
+ export declare const Divider: ({ spacing }: DividerProps) => import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ const spacingMap = {
3
+ sm: 'var(--spacing-sm)',
4
+ md: 'var(--spacing-md)',
5
+ lg: 'var(--spacing-lg)',
6
+ };
7
+ export const Divider = ({ spacing = 'md' }) => {
8
+ return (_jsx("div", { style: {
9
+ borderTop: '1px solid var(--color-border-subtle)',
10
+ marginBlock: spacingMap[spacing],
11
+ } }));
12
+ };
@@ -10,10 +10,11 @@ export type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size
10
10
  maxWidth?: string | number;
11
11
  inputSize?: Exclude<Size, 'xl'>;
12
12
  variant?: InputVariant;
13
- onClear?: () => void;
13
+ onClear?: (event?: React.MouseEvent | React.KeyboardEvent) => void;
14
14
  onButtonClick?: () => void;
15
15
  buttonLabel?: string;
16
16
  buttonIcon?: React.ReactNode;
17
+ trailingLabel?: string;
17
18
  tooltip?: React.ReactNode;
18
19
  tooltipPlacement?: 'top' | 'right' | 'bottom' | 'left';
19
20
  tooltipOpenOnFocus?: boolean;
@@ -18,7 +18,7 @@ function mergeRefs(...refs) {
18
18
  }
19
19
  };
20
20
  }
21
- export const Input = forwardRef(function Input({ label, error, helpText, orientation = 'vertical', labelWidth = '160px', fullWidth = false, required, tooltip, tooltipPlacement = 'right', modified = false, icon, autoFocus, minWidth, width, maxWidth, inputSize = 'md', variant = 'outlined', onClear, onButtonClick, buttonLabel, buttonIcon, id, tooltipOpenOnFocus = true, style, className, fieldClassName, inputClassName, startAdornment, endAdornment, ...inputProps }, ref) {
21
+ export const Input = forwardRef(function Input({ label, error, helpText, orientation = 'vertical', labelWidth = '160px', fullWidth = false, required, tooltip, tooltipPlacement = 'right', modified = false, icon, autoFocus, minWidth, width, maxWidth, inputSize = 'md', variant = 'outlined', onClear, onButtonClick, buttonLabel, buttonIcon, trailingLabel, id, tooltipOpenOnFocus = true, style, className, fieldClassName, inputClassName, startAdornment, endAdornment, ...inputProps }, ref) {
22
22
  const inputRef = useRef(null);
23
23
  const reactId = useId();
24
24
  const inputId = id !== null && id !== void 0 ? id : `input-${reactId}`;
@@ -28,6 +28,7 @@ export const Input = forwardRef(function Input({ label, error, helpText, orienta
28
28
  (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
29
29
  }, [autoFocus]);
30
30
  const hasButton = Boolean(onButtonClick || buttonLabel || buttonIcon);
31
+ const hasTrailingLabel = Boolean(trailingLabel);
31
32
  const hasValue = Boolean(inputProps.value);
32
33
  const hasVisibleClear = Boolean(onClear && hasValue);
33
34
  const hasEndAdornment = Boolean(endAdornment);
@@ -54,6 +55,7 @@ export const Input = forwardRef(function Input({ label, error, helpText, orienta
54
55
  onClear ? styles.withClear : '',
55
56
  hasInlineClear ? styles.withInlineClear : '',
56
57
  hasButton ? styles.withButton : '',
58
+ hasTrailingLabel ? styles.withTrailingLabel : '',
57
59
  className !== null && className !== void 0 ? className : '',
58
60
  ]
59
61
  .filter(Boolean)
@@ -68,6 +70,8 @@ export const Input = forwardRef(function Input({ label, error, helpText, orienta
68
70
  .filter(Boolean)
69
71
  .join(' '), "data-forminput": "field", "data-modified": modified ? 'true' : undefined, "aria-disabled": inputProps.disabled ? 'true' : undefined, ...(tooltip ? triggerProps : {}), children: [icon && (_jsx("span", { className: styles.icon, "data-input-role": "icon", children: icon })), startAdornment && (_jsx("span", { className: styles.startAdornment, "data-input-role": "start-adornment", children: startAdornment })), _jsx("input", { ...inputProps, id: inputId, ref: mergeRefs(inputRef, ref), className: [styles.input, inputSize ? styles[inputSize] : '', inputClassName !== null && inputClassName !== void 0 ? inputClassName : '']
70
72
  .filter(Boolean)
71
- .join(' ') }), (reservesInlineClearSlot || hasEndAdornment) && (_jsxs("span", { className: styles.endAdornment, "data-input-role": "end-adornment", children: [reservesInlineClearSlot ? (_jsx("span", { className: styles.clearSlot, "aria-hidden": hasVisibleClear ? undefined : 'true', children: hasVisibleClear && onClear ? _jsx(ClearButton, { onClick: onClear }) : null })) : null, endAdornment] })), hasVisibleClear && !hasEndAdornment && onClear ? (_jsx(ClearButton, { onClick: onClear, absolute: true })) : null] }), hasButton && (_jsxs(Button, { onClick: onButtonClick, className: styles.trailingButton, type: "button", variant: trailingButtonVariant, size: inputSize, children: [buttonIcon !== null && buttonIcon !== void 0 ? buttonIcon : null, buttonLabel !== null && buttonLabel !== void 0 ? buttonLabel : null] }))] }) }));
73
+ .join(' ') }), (reservesInlineClearSlot || hasEndAdornment) && (_jsxs("span", { className: styles.endAdornment, "data-input-role": "end-adornment", children: [reservesInlineClearSlot ? (_jsx("span", { className: styles.clearSlot, "aria-hidden": hasVisibleClear ? undefined : 'true', children: hasVisibleClear && onClear ? _jsx(ClearButton, { onClick: onClear }) : null })) : null, endAdornment] })), hasVisibleClear && !hasEndAdornment && onClear ? (_jsx(ClearButton, { onClick: onClear, absolute: true })) : null] }), hasTrailingLabel && (_jsx("span", { className: [styles.trailingLabel, inputSize ? styles[inputSize] : '']
74
+ .filter(Boolean)
75
+ .join(' '), children: trailingLabel })), hasButton && (_jsxs(Button, { onClick: onButtonClick, className: styles.trailingButton, type: "button", variant: trailingButtonVariant, size: inputSize, children: [buttonIcon !== null && buttonIcon !== void 0 ? buttonIcon : null, buttonLabel !== null && buttonLabel !== void 0 ? buttonLabel : null] }))] }) }));
72
76
  });
73
77
  Input.displayName = 'Input';
@@ -375,6 +375,38 @@
375
375
  block-size: var(--icon-size-md);
376
376
  }
377
377
 
378
+ /* Trailing label (unit, currency, etc.) */
379
+ .withTrailingLabel .field {
380
+ border-top-right-radius: 0;
381
+ border-bottom-right-radius: 0;
382
+ }
383
+
384
+ .trailingLabel {
385
+ display: flex;
386
+ align-items: center;
387
+ flex: 0 0 auto;
388
+ padding-inline: var(--spacing-sm);
389
+ font-family: var(--font-family);
390
+ font-size: var(--font-size-sm);
391
+ color: var(--color-fg-muted);
392
+ background: var(--color-bg-toolbar);
393
+ border: var(--border-width-thin) solid var(--color-border-default);
394
+ margin-left: calc(-1 * var(--border-width-thin));
395
+ border-top-right-radius: var(--border-radius-default);
396
+ border-bottom-right-radius: var(--border-radius-default);
397
+ white-space: nowrap;
398
+ user-select: none;
399
+ box-sizing: border-box;
400
+ }
401
+
402
+ .withTrailingLabel:has(.standalone) .trailingLabel {
403
+ border-top-right-radius: var(--border-radius-rounded);
404
+ border-bottom-right-radius: var(--border-radius-rounded);
405
+ border-color: var(--color-border-subtle);
406
+ background-color: var(--color-bg-surface);
407
+ box-shadow: var(--shadow-xs), var(--shadow-sm);
408
+ }
409
+
378
410
  /* Trailing action button (outside field) */
379
411
  .trailingButton {
380
412
  flex: 0 0 auto;
@@ -15,8 +15,9 @@ export type SelectProps<T> = Omit<InputContainerProps, 'children' | 'htmlFor' |
15
15
  datakey?: string;
16
16
  dataCy?: string;
17
17
  disabled?: boolean;
18
+ minWidth?: string | number;
18
19
  tooltip?: React.ReactNode;
19
20
  tooltipPlacement?: 'top' | 'right' | 'bottom' | 'left';
20
21
  };
21
- export declare function Select<T extends string | number | Record<string, any>>({ label, error, helpText, orientation, labelWidth, fullWidth, required, tooltip, tooltipPlacement, modified, id, options, selectedValue, onChange, placeholder, size, variant, onClear, datakey, dataCy, disabled, }: SelectProps<T>): React.ReactNode;
22
+ export declare function Select<T extends string | number | Record<string, any>>({ label, error, helpText, orientation, labelWidth, fullWidth, required, tooltip, tooltipPlacement, modified, id, options, selectedValue, onChange, placeholder, size, variant, onClear, datakey, dataCy, disabled, minWidth, }: SelectProps<T>): React.ReactNode;
22
23
  export {};
@@ -9,7 +9,7 @@ import { ClearButton } from '../../clear-button/ClearButton';
9
9
  import { Menu } from '../../menu/Menu';
10
10
  import { Popover } from '../../popover/Popover';
11
11
  import { InputContainer } from '../input-container/InputContainer';
12
- export function Select({ label, error, helpText, orientation = 'vertical', labelWidth = '160px', fullWidth = true, required, tooltip, tooltipPlacement = 'right', modified = false, id, options, selectedValue, onChange, placeholder = 'Vælg', size, variant = 'outlined', onClear, datakey, dataCy, disabled, }) {
12
+ export function Select({ label, error, helpText, orientation = 'vertical', labelWidth = '160px', fullWidth = true, required, tooltip, tooltipPlacement = 'right', modified = false, id, options, selectedValue, onChange, placeholder = 'Vælg', size, variant = 'outlined', onClear, datakey, dataCy, disabled, minWidth, }) {
13
13
  const generatedId = useId();
14
14
  const controlId = id !== null && id !== void 0 ? id : `select-${generatedId}`;
15
15
  const describedById = `${controlId}-desc`;
@@ -169,7 +169,7 @@ export function Select({ label, error, helpText, orientation = 'vertical', label
169
169
  returnFocus: true, trigger: (toggle, icon, isOpen) => (_jsx(Button, { disabled: disabled, ...(tooltipEnabled ? triggerProps : {}), id: controlId, "data-cy": dataCy !== null && dataCy !== void 0 ? dataCy : 'select-button', onKeyDown: handleKeyDown, fullWidth: fullWidth, variant: variant, onClick: e => {
170
170
  resetActiveToSelected();
171
171
  toggle(e);
172
- }, size: size, type: "button", "data-forminput": true, "aria-haspopup": "listbox", "aria-expanded": !!isOpen, "aria-controls": listboxId, "aria-invalid": Boolean(error) || undefined, "aria-describedby": describedBy, className: modified ? styles.triggerModified : undefined, children: _jsxs("span", { className: "dbc-flex dbc-justify-between dbc-items-center dbc-gap-xxs", style: { width: '100%' }, children: [_jsx("span", { children: selected ? selected.label : _jsx("span", { className: "dbc-muted-text", children: placeholder }) }), _jsxs("span", { className: "dbc-flex dbc-items-center dbc-gap-xxs", children: [onClear && selected && _jsx(ClearButton, { onClick: onClear }), _jsx("span", { style: { color: 'var(--color-fg-subtle)', display: 'inline-flex' }, children: icon })] })] }) })), children: _jsx(Menu, { onKeyDown: handleKeyDown, role: "listbox", children: options.map((opt, index) => {
172
+ }, size: size, style: minWidth != null ? { minWidth } : undefined, type: "button", "data-forminput": true, "aria-haspopup": "listbox", "aria-expanded": !!isOpen, "aria-controls": listboxId, "aria-invalid": Boolean(error) || undefined, "aria-describedby": describedBy, className: modified ? styles.triggerModified : undefined, children: _jsxs("span", { className: "dbc-flex dbc-justify-between dbc-items-center dbc-gap-xxs", style: { width: '100%' }, children: [_jsx("span", { children: selected ? selected.label : _jsx("span", { className: "dbc-muted-text", children: placeholder }) }), _jsxs("span", { className: "dbc-flex dbc-items-center dbc-gap-xxs", children: [onClear && selected && _jsx(ClearButton, { onClick: onClear }), _jsx("span", { style: { color: 'var(--color-fg-subtle)', display: 'inline-flex' }, children: icon })] })] }) })), children: _jsx(Menu, { onKeyDown: handleKeyDown, role: "listbox", children: options.map((opt, index) => {
173
173
  const isSelected = typeof opt.value === 'object' && typeof selectedValue === 'object' && datakey
174
174
  ? (selectedValue === null || selectedValue === void 0 ? void 0 : selectedValue[datakey]) === opt.value[datakey]
175
175
  : opt.value === selectedValue;
@@ -33,6 +33,7 @@ interface TypeaheadProps<T> {
33
33
  spellCheck?: InputProps['spellCheck'];
34
34
  popoverAnchorRef?: React.RefObject<HTMLElement | null>;
35
35
  fitContent?: boolean;
36
+ enableHotkey?: boolean;
36
37
  }
37
- export declare function Typeahead<T extends string | number>({ options, mode, multiValueDisplayMode, multiSelectedValuesDisplayMode, multiSelectedValueChipContent, selectedValue, onChange, placeholder, variant, disabled, fullWidth, onClear, emptyMessage, filterOptions, inputProps, inputSize, width, minWidth, popoverWidth, autoComplete, autoCorrect, autoCapitalize, spellCheck, popoverAnchorRef, fitContent, }: TypeaheadProps<T>): React.ReactElement;
38
+ export declare function Typeahead<T extends string | number>({ options, mode, multiValueDisplayMode, multiSelectedValuesDisplayMode, multiSelectedValueChipContent, selectedValue, onChange, placeholder, variant, disabled, fullWidth, onClear, emptyMessage, filterOptions, inputProps, inputSize, width, minWidth, popoverWidth, autoComplete, autoCorrect, autoCapitalize, spellCheck, popoverAnchorRef, fitContent, enableHotkey, }: TypeaheadProps<T>): React.ReactElement;
38
39
  export {};