@dbcdk/react-components 0.0.172 → 0.0.174

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 (67) hide show
  1. package/dist/client.cjs +14 -0
  2. package/dist/client.d.ts +2 -0
  3. package/dist/client.js +2 -0
  4. package/dist/components/app-header/AppHeader.module.css +2 -2
  5. package/dist/components/button/Button.d.ts +3 -1
  6. package/dist/components/button/Button.module.css +26 -0
  7. package/dist/components/color-scheme-button/ColorSchemeButton.cjs +78 -0
  8. package/dist/components/color-scheme-button/ColorSchemeButton.d.ts +8 -0
  9. package/dist/components/color-scheme-button/ColorSchemeButton.js +75 -0
  10. package/dist/components/forms/form-select/FormSelect.d.ts +1 -1
  11. package/dist/components/forms/form-select/FormSelect.module.css +19 -0
  12. package/dist/components/forms/input/Input.cjs +1 -1
  13. package/dist/components/forms/input/Input.d.ts +1 -1
  14. package/dist/components/forms/input/Input.js +1 -1
  15. package/dist/components/forms/input/Input.module.css +32 -0
  16. package/dist/components/forms/typeahead/Typeahead.cjs +1 -0
  17. package/dist/components/forms/typeahead/Typeahead.js +1 -0
  18. package/dist/components/grid/Grid.cjs +4 -3
  19. package/dist/components/grid/Grid.d.ts +3 -3
  20. package/dist/components/grid/Grid.js +4 -3
  21. package/dist/components/grid/Grid.module.css +1 -1
  22. package/dist/components/hyperlink/Hyperlink.cjs +2 -1
  23. package/dist/components/hyperlink/Hyperlink.d.ts +2 -1
  24. package/dist/components/hyperlink/Hyperlink.js +2 -1
  25. package/dist/components/hyperlink/Hyperlink.module.css +16 -0
  26. package/dist/components/metric-tile/MetricTile.cjs +77 -8
  27. package/dist/components/metric-tile/MetricTile.d.ts +17 -4
  28. package/dist/components/metric-tile/MetricTile.js +78 -9
  29. package/dist/components/metric-tile/MetricTile.module.css +122 -19
  30. package/dist/components/nav-bar/NavBar.cjs +1 -0
  31. package/dist/components/nav-bar/NavBar.js +1 -0
  32. package/dist/components/nav-bar/NavBar.module.css +10 -10
  33. package/dist/components/page-layout/PageLayout.module.css +1 -1
  34. package/dist/components/popover/Popover.cjs +4 -2
  35. package/dist/components/popover/Popover.d.ts +2 -0
  36. package/dist/components/popover/Popover.js +4 -2
  37. package/dist/components/popover/Popover.module.css +5 -0
  38. package/dist/components/theme-button/ThemeButton.cjs +30 -23
  39. package/dist/components/theme-button/ThemeButton.d.ts +9 -3
  40. package/dist/components/theme-button/ThemeButton.js +31 -24
  41. package/dist/components/theme-script/ThemeScript.cjs +50 -12
  42. package/dist/components/theme-script/ThemeScript.d.ts +35 -12
  43. package/dist/components/theme-script/ThemeScript.js +51 -13
  44. package/dist/hooks/useColorScheme.cjs +74 -0
  45. package/dist/hooks/useColorScheme.d.ts +6 -0
  46. package/dist/hooks/useColorScheme.js +72 -0
  47. package/dist/hooks/useTheme.cjs +116 -50
  48. package/dist/hooks/useTheme.d.ts +17 -5
  49. package/dist/hooks/useTheme.js +117 -51
  50. package/dist/index.cjs +14 -0
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.js +2 -0
  53. package/dist/styles/themes/dbc/colors.css +13 -2
  54. package/dist/styles/themes/filmstriben/theme.css +55 -0
  55. package/dist/styles/themes/types.cjs +8 -0
  56. package/dist/styles/themes/types.d.ts +24 -16
  57. package/dist/styles/themes/types.js +6 -0
  58. package/dist/themes/filmstriben.css +4 -0
  59. package/dist/utils/color-scheme.constants.cjs +11 -0
  60. package/dist/utils/color-scheme.constants.d.ts +4 -0
  61. package/dist/utils/color-scheme.constants.js +7 -0
  62. package/dist/utils/theme.constants.cjs +3 -7
  63. package/dist/utils/theme.constants.d.ts +2 -4
  64. package/dist/utils/theme.constants.js +3 -6
  65. package/package.json +1 -1
  66. package/dist/styles/themes/filmstriben-budget/theme.css +0 -22
  67. package/dist/themes/filmstriben-budget.css +0 -3
@@ -1,15 +1,28 @@
1
- import type { ReactNode, JSX } from 'react';
1
+ import type { FC, JSX, PropsWithChildren, ReactNode } from 'react';
2
2
  import { Severity } from '../../constants/severity.types';
3
3
  type MetricTileSize = 'sm' | 'md' | 'lg';
4
+ type MetricTileVariant = 'filled' | 'outlined';
4
5
  type SizeValue = number | string;
5
- interface MetricTileProps {
6
+ interface MetricTileSlotProps {
7
+ children: ReactNode;
8
+ }
9
+ interface MetricTileProps extends PropsWithChildren {
6
10
  severity: Severity;
7
11
  label: string;
8
- value: string | number;
12
+ icon?: JSX.Element;
13
+ value?: string | number;
9
14
  tooltip?: ReactNode;
10
15
  size?: MetricTileSize;
16
+ variant?: MetricTileVariant;
11
17
  minWidth?: SizeValue;
12
18
  maxWidth?: SizeValue;
19
+ /** Smaller secondary label shown below the main value, e.g. a second time period. */
20
+ secondaryLabel?: string;
21
+ /** Smaller secondary value shown alongside secondaryLabel. Ignored if secondaryLabel is omitted. */
22
+ secondaryValue?: string | number;
13
23
  }
14
- export declare function MetricTile({ severity, label, value, tooltip, size, minWidth, maxWidth, }: MetricTileProps): JSX.Element;
24
+ export declare const MetricTile: FC<MetricTileProps> & {
25
+ Value: FC<MetricTileSlotProps>;
26
+ Adornment: FC<MetricTileSlotProps>;
27
+ };
15
28
  export {};
@@ -1,27 +1,96 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
1
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
+ import { Children, isValidElement } from 'react';
2
3
  import { Tooltip } from '../../client';
3
4
  import styles from './MetricTile.module.css';
4
5
 
5
6
  function toSize(v) {
6
7
  return typeof v === "number" ? `${v}px` : v;
7
8
  }
8
- function MetricTile({
9
+ function getSlotName(el) {
10
+ var _a;
11
+ const t = el.type;
12
+ return (_a = t.__METRIC_TILE_SLOT__) != null ? _a : null;
13
+ }
14
+ function splitSlots(children) {
15
+ const slots = {};
16
+ const rest = [];
17
+ Children.forEach(children, (child) => {
18
+ if (!isValidElement(child)) {
19
+ if (child != null) rest.push(child);
20
+ return;
21
+ }
22
+ const slot = getSlotName(child);
23
+ if (!slot) {
24
+ rest.push(child);
25
+ return;
26
+ }
27
+ slots[slot] = child;
28
+ });
29
+ return { slots, rest };
30
+ }
31
+ const MetricTileValue = ({
32
+ children
33
+ }) => {
34
+ return /* @__PURE__ */ jsx(Fragment, { children });
35
+ };
36
+ MetricTileValue.__METRIC_TILE_SLOT__ = "Value";
37
+ MetricTileValue.displayName = "MetricTile.Value";
38
+ const MetricTileAdornment = ({ children }) => {
39
+ return /* @__PURE__ */ jsx(Fragment, { children });
40
+ };
41
+ MetricTileAdornment.__METRIC_TILE_SLOT__ = "Adornment";
42
+ MetricTileAdornment.displayName = "MetricTile.Adornment";
43
+ const MetricTileBase = ({
9
44
  severity,
10
45
  label,
46
+ icon,
11
47
  value,
12
48
  tooltip,
13
49
  size = "md",
50
+ variant = "filled",
14
51
  minWidth,
15
- maxWidth
16
- }) {
52
+ maxWidth,
53
+ secondaryLabel,
54
+ secondaryValue,
55
+ children
56
+ }) => {
57
+ var _a, _b, _c;
17
58
  const style = minWidth != null || maxWidth != null ? {
18
59
  ...minWidth != null ? { minWidth: toSize(minWidth) } : {},
19
60
  ...maxWidth != null ? { maxWidth: toSize(maxWidth) } : {}
20
61
  } : void 0;
21
- return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, placement: "bottom", children: /* @__PURE__ */ jsxs("span", { className: styles.tile, "data-severity": severity, "data-size": size, style, children: [
22
- /* @__PURE__ */ jsx("span", { className: styles.label, children: label }),
23
- /* @__PURE__ */ jsx("span", { className: styles.value, children: value })
24
- ] }) });
25
- }
62
+ const { slots } = splitSlots(children);
63
+ const resolvedValue = (_b = (_a = slots.Value) == null ? void 0 : _a.props.children) != null ? _b : value;
64
+ const resolvedAdornment = (_c = slots.Adornment) == null ? void 0 : _c.props.children;
65
+ const showValueRow = resolvedValue != null || resolvedAdornment != null;
66
+ return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, placement: "bottom", children: /* @__PURE__ */ jsxs(
67
+ "span",
68
+ {
69
+ className: styles.tile,
70
+ "data-severity": severity,
71
+ "data-size": size,
72
+ "data-variant": variant,
73
+ style,
74
+ children: [
75
+ /* @__PURE__ */ jsxs("span", { className: styles.labelRow, children: [
76
+ icon != null ? /* @__PURE__ */ jsx("span", { className: styles.icon, children: icon }) : null,
77
+ /* @__PURE__ */ jsx("span", { className: styles.label, children: label })
78
+ ] }),
79
+ showValueRow ? /* @__PURE__ */ jsxs("span", { className: styles.valueRow, children: [
80
+ resolvedValue != null ? /* @__PURE__ */ jsx("span", { className: styles.value, children: resolvedValue }) : null,
81
+ resolvedAdornment != null ? /* @__PURE__ */ jsx("span", { className: styles.adornment, children: resolvedAdornment }) : null
82
+ ] }) : null,
83
+ secondaryLabel != null && /* @__PURE__ */ jsxs("span", { className: styles.secondary, children: [
84
+ /* @__PURE__ */ jsx("span", { className: styles.secondaryLabel, children: secondaryLabel }),
85
+ /* @__PURE__ */ jsx("span", { className: styles.secondaryValue, children: secondaryValue })
86
+ ] })
87
+ ]
88
+ }
89
+ ) });
90
+ };
91
+ const MetricTile = Object.assign(MetricTileBase, {
92
+ Value: MetricTileValue,
93
+ Adornment: MetricTileAdornment
94
+ });
26
95
 
27
96
  export { MetricTile };
@@ -1,4 +1,7 @@
1
1
  .tile {
2
+ --metric-tile-bg: var(--color-bg-surface);
3
+ --metric-tile-fg: var(--color-fg-default);
4
+ --metric-tile-outline: var(--color-border-default);
2
5
  display: inline-flex;
3
6
  flex-direction: column;
4
7
  align-items: center;
@@ -9,6 +12,9 @@
9
12
  overflow: hidden;
10
13
  box-sizing: border-box;
11
14
  border-radius: var(--border-radius-md);
15
+ border: var(--border-width-thin) solid transparent;
16
+ background-color: var(--metric-tile-bg);
17
+ color: var(--metric-tile-fg);
12
18
  font-family: var(--font-family);
13
19
  cursor: default;
14
20
  }
@@ -20,6 +26,10 @@
20
26
  border-radius: var(--border-radius-sm);
21
27
  }
22
28
 
29
+ .tile[data-size='md'] {
30
+ gap: 8px;
31
+ }
32
+
23
33
  .tile[data-size='lg'] {
24
34
  gap: var(--spacing-2xs);
25
35
  padding: var(--spacing-md) var(--spacing-lg);
@@ -28,55 +38,86 @@
28
38
  }
29
39
 
30
40
  .tile[data-severity='success'] {
31
- background-color: var(--color-status-success-bg-soft);
32
- color: var(--color-status-success-fg-soft);
41
+ --metric-tile-bg: var(--color-status-success-bg-soft);
42
+ --metric-tile-fg: var(--color-status-success-fg-soft);
43
+ --metric-tile-outline: var(--color-status-success-fg-soft);
33
44
  }
34
45
 
35
46
  .tile[data-severity='error'] {
36
- background-color: var(--color-status-error-bg-soft);
37
- color: var(--color-status-error-fg-soft);
47
+ --metric-tile-bg: var(--color-status-error-bg-soft);
48
+ --metric-tile-fg: var(--color-status-error-fg-soft);
49
+ --metric-tile-outline: var(--color-status-error-fg-soft);
38
50
  }
39
51
 
40
52
  .tile[data-severity='warning'] {
41
- background-color: var(--color-status-warning-bg-soft);
42
- color: var(--color-status-warning-fg-soft);
53
+ --metric-tile-bg: var(--color-status-warning-bg-soft);
54
+ --metric-tile-fg: var(--color-status-warning-fg-soft);
55
+ --metric-tile-outline: var(--color-status-warning-fg-soft);
43
56
  }
44
57
 
45
58
  .tile[data-severity='info'] {
46
- background-color: var(--color-status-info-bg-soft);
47
- color: var(--color-status-info-fg-soft);
59
+ --metric-tile-bg: var(--color-status-info-bg-soft);
60
+ --metric-tile-fg: var(--color-status-info-fg-soft);
61
+ --metric-tile-outline: var(--color-status-info-fg-soft);
48
62
  }
49
63
 
50
64
  .tile[data-severity='neutral'] {
51
- background-color: var(--color-bg-toolbar);
52
- color: var(--color-fg-default);
65
+ --metric-tile-bg: var(--color-bg-toolbar);
66
+ --metric-tile-fg: var(--color-fg-default);
67
+ --metric-tile-outline: var(--color-border-default);
53
68
  }
54
69
 
55
70
  .tile[data-severity='brand'] {
56
- background-color: var(--color-brand);
57
- color: var(--color-fg-on-brand);
71
+ --metric-tile-bg: var(--color-brand);
72
+ --metric-tile-fg: var(--color-fg-on-brand);
73
+ --metric-tile-outline: var(--color-brand);
58
74
  }
59
75
 
60
76
  .tile[data-severity='accent'] {
61
- background-color: var(--color-accent-bg-soft);
62
- color: var(--color-accent-fg-soft);
77
+ --metric-tile-bg: var(--color-accent-bg-soft);
78
+ --metric-tile-fg: var(--color-accent-fg-soft);
79
+ --metric-tile-outline: var(--color-accent-fg-soft);
80
+ }
81
+
82
+ .tile[data-variant='outlined'] {
83
+ background-color: var(--color-bg-surface);
84
+ color: var(--color-fg-default);
85
+ border-color: var(--metric-tile-outline);
86
+ }
87
+
88
+ .labelRow {
89
+ display: inline-flex;
90
+ align-items: center;
91
+ gap: var(--spacing-xxs);
92
+ max-width: 100%;
93
+ min-width: 0;
63
94
  }
64
95
 
65
96
  .label {
66
97
  font-size: var(--font-size-xs);
67
- font-weight: var(--font-weight-semibold, 600);
68
- text-transform: uppercase;
69
- letter-spacing: var(--letter-spacing-wide);
98
+ font-weight: 400;
99
+ color: var(--color-fg-subtle);
70
100
  line-height: 1;
71
- opacity: 0.85;
72
101
  max-width: 100%;
73
102
  overflow: hidden;
74
103
  white-space: nowrap;
75
104
  text-overflow: ellipsis;
76
105
  }
77
106
 
107
+ .icon {
108
+ display: inline-flex;
109
+ align-items: center;
110
+ flex: 0 0 auto;
111
+ }
112
+
113
+ .icon :global(svg) {
114
+ width: 0.9em;
115
+ height: 0.9em;
116
+ }
117
+
78
118
  .value {
79
119
  font-size: var(--font-size-md);
120
+ font-weight: 500;
80
121
  line-height: 1;
81
122
  font-variant-numeric: tabular-nums;
82
123
  max-width: 100%;
@@ -85,15 +126,51 @@
85
126
  text-overflow: ellipsis;
86
127
  }
87
128
 
129
+ .valueRow {
130
+ display: inline-flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ gap: var(--spacing-xxs);
134
+ max-width: 100%;
135
+ min-width: 0;
136
+ }
137
+
138
+ .adornment {
139
+ display: inline-flex;
140
+ align-items: center;
141
+ gap: var(--spacing-xxs);
142
+ flex: 0 0 auto;
143
+ font-size: var(--font-size-xs);
144
+ line-height: 1;
145
+ opacity: 0.9;
146
+ }
147
+
148
+ .adornment :global(svg) {
149
+ width: 0.9em;
150
+ height: 0.9em;
151
+ }
152
+
88
153
  .tile[data-size='sm'] .label {
89
154
  font-size: var(--font-size-xs);
90
- letter-spacing: normal;
155
+ }
156
+
157
+ .tile[data-size='sm'] .labelRow {
158
+ gap: 2px;
91
159
  }
92
160
 
93
161
  .tile[data-size='sm'] .value {
94
162
  font-size: var(--font-size-xs);
95
163
  }
96
164
 
165
+ .tile[data-size='sm'] .valueRow {
166
+ gap: 2px;
167
+ }
168
+
169
+ .tile[data-size='sm'] .adornment {
170
+ gap: 2px;
171
+ font-size: 10px;
172
+ }
173
+
97
174
  .tile[data-size='lg'] .label {
98
175
  font-size: var(--font-size-sm);
99
176
  }
@@ -101,3 +178,29 @@
101
178
  .tile[data-size='lg'] .value {
102
179
  font-size: var(--font-size-xl);
103
180
  }
181
+
182
+ .secondary {
183
+ display: flex;
184
+ align-items: baseline;
185
+ gap: var(--spacing-2xs, 4px);
186
+ font-size: var(--font-size-xs);
187
+ opacity: 0.75;
188
+ max-width: 100%;
189
+ overflow: hidden;
190
+ white-space: nowrap;
191
+ }
192
+
193
+ .secondaryLabel {
194
+ text-transform: none;
195
+ letter-spacing: normal;
196
+ }
197
+
198
+ .secondaryValue {
199
+ font-variant-numeric: tabular-nums;
200
+ overflow: hidden;
201
+ text-overflow: ellipsis;
202
+ }
203
+
204
+ .tile[data-size='sm'] .secondary {
205
+ font-size: 10px;
206
+ }
@@ -82,6 +82,7 @@ function NavBar({
82
82
  fullWidth: false,
83
83
  autoFocusContent: true,
84
84
  anchorRef: navRef,
85
+ variant: "header",
85
86
  trigger: (toggle, _icon, open) => /* @__PURE__ */ jsxRuntime.jsx(
86
87
  "button",
87
88
  {
@@ -76,6 +76,7 @@ function NavBar({
76
76
  fullWidth: false,
77
77
  autoFocusContent: true,
78
78
  anchorRef: navRef,
79
+ variant: "header",
79
80
  trigger: (toggle, _icon, open) => /* @__PURE__ */ jsx(
80
81
  "button",
81
82
  {
@@ -1,7 +1,7 @@
1
1
  .container {
2
2
  display: flex;
3
3
  align-items: center;
4
- gap: var(--spacing-xl);
4
+ gap: var(--spacing-2xl);
5
5
  inline-size: 100%;
6
6
  box-sizing: border-box;
7
7
  flex-grow: 1;
@@ -40,7 +40,7 @@
40
40
  block-size: var(--component-size-md);
41
41
  border: none;
42
42
  background: transparent;
43
- color: var(--color-fg-default);
43
+ color: var(--color-navbar-fg);
44
44
  border-radius: var(--border-radius-default);
45
45
  cursor: pointer;
46
46
  padding: 0;
@@ -48,12 +48,12 @@
48
48
  }
49
49
 
50
50
  .burgerButton:hover {
51
- background-color: var(--color-bg-hover-subtle);
51
+ background-color: color-mix(in srgb, var(--color-navbar-fg) 12%, transparent);
52
52
  }
53
53
 
54
54
  .burgerButton:focus-visible {
55
55
  outline: none;
56
- box-shadow: var(--focus-ring);
56
+ box-shadow: inset 0 0 0 1px var(--color-navbar-fg);
57
57
  }
58
58
 
59
59
  /* Mobile dropdown content */
@@ -170,7 +170,7 @@
170
170
  display: inline-flex;
171
171
  align-items: center;
172
172
  gap: var(--spacing-xs);
173
- color: var(--color-fg-muted);
173
+ color: var(--color-navbar-fg-muted);
174
174
  font-family: var(--font-family);
175
175
  font-size: var(--font-size-sm);
176
176
  text-decoration: none;
@@ -185,17 +185,17 @@
185
185
 
186
186
  /* Hover + focus */
187
187
  .link:hover {
188
- color: var(--color-fg-default);
188
+ color: var(--color-navbar-fg);
189
189
  }
190
190
  .link:focus-visible {
191
191
  outline: none;
192
- box-shadow: var(--focus-ring);
192
+ box-shadow: inset 0 0 0 1px var(--color-navbar-fg);
193
193
  }
194
194
 
195
195
  /* Active underline */
196
196
  .link.active,
197
197
  .link[aria-current='page'] {
198
- color: var(--color-brand);
198
+ color: var(--color-navbar-brand);
199
199
  box-shadow: none;
200
200
  }
201
201
 
@@ -206,7 +206,7 @@
206
206
  inset-block-end: 0;
207
207
  inline-size: 0;
208
208
  block-size: 2px;
209
- background-color: var(--color-border-strong);
209
+ background-color: var(--color-navbar-fg);
210
210
  transition: inline-size var(--transition-fast) var(--ease-standard);
211
211
  }
212
212
 
@@ -217,7 +217,7 @@
217
217
  .link.active::after,
218
218
  .link[aria-current='page']::after {
219
219
  inline-size: 100%;
220
- background-color: var(--color-brand);
220
+ background-color: var(--color-navbar-brand);
221
221
  }
222
222
 
223
223
  /* Icons/images inside links */
@@ -161,7 +161,7 @@
161
161
  /* Regions */
162
162
  .header {
163
163
  min-width: 0;
164
- background: var(--color-bg-surface);
164
+ background: var(--color-navbar-bg);
165
165
  border-bottom: var(--border-width-thin) solid var(--color-border-default);
166
166
  flex: 0 0 auto;
167
167
  }
@@ -96,7 +96,8 @@ const Popover = React.forwardRef(function Popover2({
96
96
  autoFocusContent = false,
97
97
  returnFocus = true,
98
98
  anchorRef,
99
- overlayRef
99
+ overlayRef,
100
+ variant = "default"
100
101
  }, ref) {
101
102
  const internalId = React.useId();
102
103
  const resolvedContentId = contentId != null ? contentId : `popover-${internalId}`;
@@ -266,7 +267,8 @@ const Popover = React.forwardRef(function Popover2({
266
267
  if (lastCloseReasonRef.current === "outside") return;
267
268
  (_b = (_a = triggerElRef.current) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
268
269
  }, [isOpen, returnFocus]);
269
- const icon = isOpen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "dbc-muted-text", size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "dbc-muted-text", size: 20 });
270
+ const chevronClassName = variant === "header" ? styles__default.default.chevronHeader : "dbc-muted-text";
271
+ const icon = isOpen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: chevronClassName, size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: chevronClassName, size: 20 });
270
272
  const setOverlayRef = React__namespace.useCallback(
271
273
  (node) => {
272
274
  assignRef(overlayRef, node);
@@ -18,6 +18,8 @@ export interface PopoverProps {
18
18
  returnFocus?: boolean;
19
19
  anchorRef?: React.RefObject<HTMLElement | null>;
20
20
  overlayRef?: React.Ref<HTMLDivElement>;
21
+ /** 'header' colors the built-in chevron icon with --color-navbar-fg tokens — only meaningful inside/near AppHeader */
22
+ variant?: 'default' | 'header';
21
23
  }
22
24
  export interface PopoverHandle {
23
25
  close: () => void;
@@ -72,7 +72,8 @@ const Popover = forwardRef(function Popover2({
72
72
  autoFocusContent = false,
73
73
  returnFocus = true,
74
74
  anchorRef,
75
- overlayRef
75
+ overlayRef,
76
+ variant = "default"
76
77
  }, ref) {
77
78
  const internalId = useId();
78
79
  const resolvedContentId = contentId != null ? contentId : `popover-${internalId}`;
@@ -242,7 +243,8 @@ const Popover = forwardRef(function Popover2({
242
243
  if (lastCloseReasonRef.current === "outside") return;
243
244
  (_b = (_a = triggerElRef.current) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
244
245
  }, [isOpen, returnFocus]);
245
- const icon = isOpen ? /* @__PURE__ */ jsx(ChevronUp, { className: "dbc-muted-text", size: 20 }) : /* @__PURE__ */ jsx(ChevronDown, { className: "dbc-muted-text", size: 20 });
246
+ const chevronClassName = variant === "header" ? styles.chevronHeader : "dbc-muted-text";
247
+ const icon = isOpen ? /* @__PURE__ */ jsx(ChevronUp, { className: chevronClassName, size: 20 }) : /* @__PURE__ */ jsx(ChevronDown, { className: chevronClassName, size: 20 });
246
248
  const setOverlayRef = React.useCallback(
247
249
  (node) => {
248
250
  assignRef(overlayRef, node);
@@ -40,6 +40,7 @@
40
40
  position: fixed;
41
41
  border: 1px solid var(--color-border-subtle);
42
42
  background-color: var(--color-bg-surface);
43
+ color: var(--color-fg-default);
43
44
  border-radius: var(--border-radius-lg);
44
45
  padding: var(--spacing-xxs);
45
46
  z-index: var(--z-popover);
@@ -50,3 +51,7 @@
50
51
  .content[hidden] {
51
52
  display: none;
52
53
  }
54
+
55
+ .chevronHeader {
56
+ color: var(--color-navbar-fg-muted);
57
+ }
@@ -7,36 +7,43 @@ var Button = require('../../components/button/Button');
7
7
  var Menu = require('../../components/menu/Menu');
8
8
  var Popover = require('../../components/popover/Popover');
9
9
  var useTheme = require('../../hooks/useTheme');
10
+ var types = require('../../styles/themes/types');
10
11
 
11
- const THEME_OPTIONS = [
12
- { value: "system", label: "System", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Monitor, { size: 16 }) },
13
- { value: "light", label: "Lyst", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { size: 16 }) },
14
- { value: "dark", label: "M\xF8rkt", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { size: 16 }) }
15
- ];
16
- function ThemeMenuSection() {
17
- const { theme, switchTheme } = useTheme.useTheme();
12
+ function ThemeMenuSection({ themes, hrefs }) {
13
+ const { theme, switchTheme } = useTheme.useTheme({
14
+ defaultTheme: themes[0],
15
+ hrefs
16
+ });
18
17
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Header, { children: "Udseende" }),
20
- THEME_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
18
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Header, { children: "Tema" }),
19
+ themes.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
21
20
  Menu.Menu.RadioItem,
22
21
  {
23
22
  name: "theme",
24
- value: option.value,
25
- checked: theme === option.value,
26
- label: option.label,
27
- onValueChange: (value) => switchTheme(value)
23
+ value: id,
24
+ checked: theme === id,
25
+ label: types.THEME_LABELS[id],
26
+ onValueChange: () => switchTheme(id)
28
27
  },
29
- option.value
28
+ id
30
29
  ))
31
30
  ] });
32
31
  }
33
- function ThemeButton({ size, variant = "outlined" }) {
34
- const { theme, switchTheme } = useTheme.useTheme();
32
+ function ThemeButton({
33
+ themes,
34
+ hrefs,
35
+ size,
36
+ variant = "outlined"
37
+ }) {
38
+ const { theme, switchTheme } = useTheme.useTheme({
39
+ defaultTheme: themes[0],
40
+ hrefs
41
+ });
35
42
  return /* @__PURE__ */ jsxRuntime.jsx(
36
43
  Popover.Popover,
37
44
  {
38
45
  matchTriggerWidth: false,
39
- minWidth: "140px",
46
+ minWidth: "160px",
40
47
  trigger: (handleClick, chevron) => /* @__PURE__ */ jsxRuntime.jsxs(
41
48
  Button.Button,
42
49
  {
@@ -52,20 +59,20 @@ function ThemeButton({ size, variant = "outlined" }) {
52
59
  }
53
60
  ),
54
61
  children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
55
- /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Header, { children: "Udseende" }),
56
- THEME_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { active: theme === option.value, children: /* @__PURE__ */ jsxRuntime.jsxs(
62
+ /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Header, { children: "Tema" }),
63
+ themes.map((id) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { active: theme === id, children: /* @__PURE__ */ jsxRuntime.jsxs(
57
64
  "button",
58
65
  {
59
66
  onClick: () => {
60
- switchTheme(option.value);
67
+ switchTheme(id);
61
68
  close();
62
69
  },
63
70
  children: [
64
- option.icon,
65
- option.label
71
+ types.THEME_LABELS[id],
72
+ theme === id && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { size: 16 })
66
73
  ]
67
74
  }
68
- ) }, option.value))
75
+ ) }, id))
69
76
  ] })
70
77
  }
71
78
  );
@@ -1,8 +1,14 @@
1
1
  import type { JSX } from 'react';
2
2
  import type { ButtonSize, ButtonVariant } from '../../components/button/Button';
3
- export interface ThemeButtonProps {
3
+ import type { ThemeHrefs, ThemeId } from '../../hooks/useTheme';
4
+ export interface ThemeMenuSectionProps {
5
+ /** Every theme to offer as an option. The first entry is treated as the default. */
6
+ themes: readonly ThemeId[];
7
+ hrefs?: ThemeHrefs;
8
+ }
9
+ export interface ThemeButtonProps extends ThemeMenuSectionProps {
4
10
  size?: ButtonSize;
5
11
  variant?: ButtonVariant;
6
12
  }
7
- export declare function ThemeMenuSection(): JSX.Element;
8
- export declare function ThemeButton({ size, variant }: ThemeButtonProps): JSX.Element;
13
+ export declare function ThemeMenuSection({ themes, hrefs }: ThemeMenuSectionProps): JSX.Element;
14
+ export declare function ThemeButton({ themes, hrefs, size, variant, }: ThemeButtonProps): JSX.Element;