@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
@@ -86,14 +86,15 @@ function measureFitContentWidth(input, text, minWidth) {
86
86
  endAdornmentWidth);
87
87
  return Math.max(parseLengthToPx(minWidth, inputFontSize) || 120, nextWidth);
88
88
  }
89
- export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'chips', multiSelectedValuesDisplayMode = 'hidden', multiSelectedValueChipContent = 'label', selectedValue = null, onChange, placeholder, variant = 'outlined', disabled = false, fullWidth = false, onClear, emptyMessage = 'Ingen resultater', filterOptions, inputProps, inputSize, width, minWidth, popoverWidth, autoComplete, autoCorrect, autoCapitalize, spellCheck, popoverAnchorRef, fitContent = false, }) {
89
+ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'chips', multiSelectedValuesDisplayMode = 'hidden', multiSelectedValueChipContent = 'label', selectedValue = null, onChange, placeholder, variant = 'outlined', disabled = false, fullWidth = false, onClear, emptyMessage = 'Ingen resultater', filterOptions, inputProps, inputSize, width, minWidth, popoverWidth, autoComplete, autoCorrect, autoCapitalize, spellCheck, popoverAnchorRef, fitContent = false, enableHotkey = false, }) {
90
90
  var _a, _b;
91
91
  const rootRef = useRef(null);
92
+ const triggerWrapperRef = useRef(null);
92
93
  const inputRef = useRef(null);
93
- const listboxRef = useRef(null);
94
94
  const popoverContentRef = useRef(null);
95
- const optionRefs = useRef([]);
96
95
  const interactingWithOptionsRef = useRef(false);
96
+ const justClearedRef = useRef(false);
97
+ const locallyClearedRef = useRef(false);
97
98
  const listboxId = useId();
98
99
  const { onFocus: inputPropsOnFocus, onBlur: inputPropsOnBlur, onKeyDown: inputPropsOnKeyDown, onMouseDown: inputPropsOnMouseDown, onClear: inputPropsOnClear, startAdornment: inputPropsStartAdornment, endAdornment: inputPropsEndAdornment, ...passthroughInputProps } = inputProps !== null && inputProps !== void 0 ? inputProps : {};
99
100
  const selectedOption = useMemo(() => {
@@ -111,6 +112,12 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
111
112
  const [inputValue, setInputValue] = useState(mode === 'multi' ? '' : ((_a = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) !== null && _a !== void 0 ? _a : ''));
112
113
  const [query, setQuery] = useState('');
113
114
  const [activeIndex, setActiveIndex] = useState(-1);
115
+ const [hideSelectedHighlight, setHideSelectedHighlight] = useState(false);
116
+ const clearJustClearedAfterEventCycle = React.useCallback(() => {
117
+ requestAnimationFrame(() => {
118
+ justClearedRef.current = false;
119
+ });
120
+ }, []);
114
121
  const getSelectedValueChipLabel = React.useCallback((option) => {
115
122
  switch (multiSelectedValueChipContent) {
116
123
  case 'value':
@@ -122,6 +129,48 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
122
129
  return option.label;
123
130
  }
124
131
  }, [multiSelectedValueChipContent]);
132
+ let filteredOptions;
133
+ if (filterOptions) {
134
+ filteredOptions = filterOptions(options, query);
135
+ }
136
+ else {
137
+ const normalizedQuery = query.trim().toLocaleLowerCase();
138
+ if (!normalizedQuery) {
139
+ filteredOptions = options;
140
+ }
141
+ else {
142
+ filteredOptions = options.filter(option => option.label.toLocaleLowerCase().includes(normalizedQuery));
143
+ }
144
+ }
145
+ const commitSelection = React.useCallback((option) => {
146
+ var _a, _b;
147
+ locallyClearedRef.current = false;
148
+ setHideSelectedHighlight(false);
149
+ if (mode === 'multi') {
150
+ if (!option)
151
+ return;
152
+ const nextValues = Array.isArray(selectedValue) ? [...selectedValue] : [];
153
+ const idx = nextValues.indexOf(option.value);
154
+ if (idx > -1) {
155
+ nextValues.splice(idx, 1);
156
+ }
157
+ else {
158
+ nextValues.push(option.value);
159
+ }
160
+ onChange(nextValues);
161
+ if (filteredOptions.length > 1) {
162
+ return;
163
+ }
164
+ setInputValue('');
165
+ setQuery('');
166
+ return;
167
+ }
168
+ onChange((_a = option === null || option === void 0 ? void 0 : option.value) !== null && _a !== void 0 ? _a : null);
169
+ setInputValue((_b = option === null || option === void 0 ? void 0 : option.label) !== null && _b !== void 0 ? _b : '');
170
+ setQuery('');
171
+ setOpen(false);
172
+ setActiveIndex(-1);
173
+ }, [mode, selectedValue, onChange, filteredOptions.length]);
125
174
  const multiSelectionAdornment = mode === 'multi' && selectedOptions.length > 0 ? (multiValueDisplayMode === 'count' ? (_jsxs("span", { className: `dbc-muted-text dbc-sm-text ${styles.countAdornment}`, children: ["(", selectedOptions.length, ")"] })) : ((() => {
126
175
  const MAX_CHIPS = 2;
127
176
  const chipsToShow = selectedOptions.slice(0, MAX_CHIPS);
@@ -130,7 +179,7 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
130
179
  })())) : undefined;
131
180
  const usesCountAdornment = mode === 'multi' && multiValueDisplayMode === 'count' && selectedOptions.length > 0;
132
181
  const resolvedInputSize = (_b = inputSize !== null && inputSize !== void 0 ? inputSize : inputProps === null || inputProps === void 0 ? void 0 : inputProps.inputSize) !== null && _b !== void 0 ? _b : 'md';
133
- const shouldFitContent = fitContent && mode === 'single' && !fullWidth;
182
+ const shouldFitContent = fitContent && mode === 'single';
134
183
  const [fittedWidthPx, setFittedWidthPx] = useState(null);
135
184
  const visibleSingleValueText = useMemo(() => {
136
185
  if (!shouldFitContent)
@@ -144,7 +193,7 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
144
193
  if (!input)
145
194
  return;
146
195
  let cancelled = false;
147
- let frameId = requestAnimationFrame(() => {
196
+ const frameId = requestAnimationFrame(() => {
148
197
  const nextWidth = measureFitContentWidth(input, visibleSingleValueText, minWidth);
149
198
  if (!cancelled && nextWidth != null) {
150
199
  setFittedWidthPx(current => (current !== nextWidth ? nextWidth : current));
@@ -183,28 +232,36 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
183
232
  return `${fittedWidthPx}px`;
184
233
  }, [shouldFitContent, fittedWidthPx, minWidth]);
185
234
  const shouldStretchInput = fullWidth || shouldFitContent;
235
+ useEffect(() => {
236
+ if (!enableHotkey)
237
+ return;
238
+ function handleKeyDown(event) {
239
+ var _a;
240
+ if (event.key === 'k' && (event.metaKey || event.ctrlKey)) {
241
+ event.preventDefault();
242
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
243
+ }
244
+ }
245
+ window.addEventListener('keydown', handleKeyDown);
246
+ return () => window.removeEventListener('keydown', handleKeyDown);
247
+ }, [enableHotkey]);
186
248
  useEffect(() => {
187
249
  var _a;
250
+ if (justClearedRef.current || locallyClearedRef.current)
251
+ return;
188
252
  if (mode === 'multi') {
189
253
  setInputValue('');
190
254
  setQuery('');
191
255
  }
192
256
  else {
193
- const nextLabel = (_a = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) !== null && _a !== void 0 ? _a : '';
194
- setInputValue(nextLabel);
257
+ setInputValue((_a = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) !== null && _a !== void 0 ? _a : '');
195
258
  }
196
259
  }, [selectedOption, mode]);
197
- const filteredOptions = useMemo(() => {
198
- if (filterOptions)
199
- return filterOptions(options, query);
200
- const normalizedQuery = query.trim().toLocaleLowerCase();
201
- if (!normalizedQuery)
202
- return options;
203
- return options.filter(option => option.label.toLocaleLowerCase().includes(normalizedQuery));
204
- }, [filterOptions, query, options]);
205
260
  const getSelectedIndex = React.useCallback((items) => {
206
261
  if (items.length === 0)
207
262
  return -1;
263
+ if (locallyClearedRef.current)
264
+ return 0;
208
265
  if (mode === 'multi') {
209
266
  if (!Array.isArray(selectedValue) || selectedValue.length === 0)
210
267
  return 0;
@@ -218,18 +275,21 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
218
275
  setActiveIndex(current => {
219
276
  if (filteredOptions.length === 0)
220
277
  return -1;
278
+ if (locallyClearedRef.current)
279
+ return 0;
221
280
  if (current < 0)
222
281
  return getSelectedIndex(filteredOptions);
223
282
  return Math.min(current, filteredOptions.length - 1);
224
283
  });
225
284
  }, [filteredOptions, getSelectedIndex]);
226
285
  useEffect(() => {
227
- var _a;
286
+ var _a, _b;
228
287
  if (!open || activeIndex < 0)
229
288
  return;
230
- const activeEl = optionRefs.current[activeIndex];
231
- (_a = activeEl === null || activeEl === void 0 ? void 0 : activeEl.scrollIntoView) === null || _a === void 0 ? void 0 : _a.call(activeEl, { block: 'nearest' });
232
- }, [open, activeIndex, filteredOptions]);
289
+ const activeEl = (_a = document
290
+ .getElementById(listboxId)) === null || _a === void 0 ? void 0 : _a.querySelector(`#${CSS.escape(`${listboxId}-option-${activeIndex}`)}`);
291
+ (_b = activeEl === null || activeEl === void 0 ? void 0 : activeEl.scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(activeEl, { block: 'nearest' });
292
+ }, [open, activeIndex, filteredOptions, listboxId]);
233
293
  const getFocusableElements = React.useCallback(() => {
234
294
  const selector = [
235
295
  'a[href]',
@@ -279,8 +339,6 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
279
339
  ? eventTarget
280
340
  : ((_a = document.activeElement) !== null && _a !== void 0 ? _a : null);
281
341
  const activeIndexInScope = activeElement ? focusables.indexOf(activeElement) : -1;
282
- const boundaryIndex = event.shiftKey ? 0 : focusables.length - 1;
283
- const boundaryElement = focusables[boundaryIndex];
284
342
  if (mode === 'multi') {
285
343
  if (activeIndexInScope === -1) {
286
344
  event.preventDefault();
@@ -294,38 +352,14 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
294
352
  (_c = focusables[nextIndex]) === null || _c === void 0 ? void 0 : _c.focus();
295
353
  return;
296
354
  }
297
- // single mode: Tab always closes the dropdown and lets focus move naturally
298
355
  setOpen(false);
299
356
  setActiveIndex(-1);
300
357
  }, [open, getFocusableElements, mode]);
301
- const commitSelection = (option) => {
302
- var _a, _b;
303
- if (mode === 'multi') {
304
- if (!option)
305
- return;
306
- const nextValues = Array.isArray(selectedValue) ? [...selectedValue] : [];
307
- const idx = nextValues.indexOf(option.value);
308
- if (idx > -1) {
309
- nextValues.splice(idx, 1);
310
- }
311
- else {
312
- nextValues.push(option.value);
313
- }
314
- onChange(nextValues);
315
- if (filteredOptions.length > 1) {
316
- return;
317
- }
318
- setInputValue('');
319
- setQuery('');
320
- return;
321
- }
322
- onChange((_a = option === null || option === void 0 ? void 0 : option.value) !== null && _a !== void 0 ? _a : null);
323
- setInputValue((_b = option === null || option === void 0 ? void 0 : option.label) !== null && _b !== void 0 ? _b : '');
324
- setQuery('');
325
- setOpen(false);
326
- setActiveIndex(-1);
327
- };
328
358
  const handleInputChange = (nextValue) => {
359
+ if (justClearedRef.current)
360
+ return;
361
+ locallyClearedRef.current = false;
362
+ setHideSelectedHighlight(false);
329
363
  setInputValue(nextValue);
330
364
  setQuery(nextValue);
331
365
  if (!open)
@@ -338,6 +372,13 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
338
372
  }
339
373
  };
340
374
  const handleBlur = (nextFocusedTarget) => {
375
+ if (justClearedRef.current || locallyClearedRef.current) {
376
+ setInputValue('');
377
+ setQuery('');
378
+ setOpen(false);
379
+ setActiveIndex(-1);
380
+ return;
381
+ }
341
382
  if (isFocusWithinTypeahead(nextFocusedTarget))
342
383
  return;
343
384
  if (mode === 'multi') {
@@ -369,22 +410,28 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
369
410
  setActiveIndex(-1);
370
411
  };
371
412
  const openWithAllOptions = React.useCallback(() => {
413
+ if (justClearedRef.current)
414
+ return;
372
415
  setQuery('');
373
416
  setOpen(true);
374
417
  setActiveIndex(getSelectedIndex(options));
375
418
  }, [getSelectedIndex, options]);
376
419
  const openWithCurrentFilter = React.useCallback(() => {
420
+ if (justClearedRef.current)
421
+ return;
377
422
  setOpen(true);
378
423
  setActiveIndex(getSelectedIndex(filteredOptions));
379
424
  }, [getSelectedIndex, filteredOptions]);
380
425
  const prepareSingleSearchInput = React.useCallback(() => {
381
- if (mode !== 'single' || !selectedOption)
426
+ if (mode !== 'single' || !selectedOption || justClearedRef.current)
382
427
  return;
383
428
  setInputValue('');
384
429
  setQuery('');
385
430
  }, [mode, selectedOption]);
386
431
  const handleOpen = React.useCallback(() => {
387
- if (mode === 'single' && selectedOption) {
432
+ if (justClearedRef.current)
433
+ return;
434
+ if (mode === 'single' && selectedOption && !locallyClearedRef.current) {
388
435
  prepareSingleSearchInput();
389
436
  openWithAllOptions();
390
437
  return;
@@ -396,22 +443,21 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
396
443
  inputPropsOnMouseDown === null || inputPropsOnMouseDown === void 0 ? void 0 : inputPropsOnMouseDown(e);
397
444
  if (e.defaultPrevented)
398
445
  return;
446
+ if (justClearedRef.current) {
447
+ e.preventDefault();
448
+ e.stopPropagation();
449
+ return;
450
+ }
399
451
  const isAlreadyFocused = document.activeElement === inputRef.current;
400
452
  if (isAlreadyFocused && open) {
401
453
  e.preventDefault();
402
454
  setOpen(false);
403
455
  setActiveIndex(-1);
404
- if (mode === 'single') {
405
- setQuery('');
406
- setInputValue((_a = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) !== null && _a !== void 0 ? _a : '');
407
- }
408
- else {
409
- setQuery('');
410
- setInputValue('');
411
- }
456
+ setQuery('');
457
+ setInputValue(mode === 'single' && !locallyClearedRef.current ? ((_a = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) !== null && _a !== void 0 ? _a : '') : '');
412
458
  return;
413
459
  }
414
- if (isAlreadyFocused && mode === 'single' && selectedOption) {
460
+ if (isAlreadyFocused && mode === 'single' && selectedOption && !locallyClearedRef.current) {
415
461
  prepareSingleSearchInput();
416
462
  setOpen(true);
417
463
  setActiveIndex(getSelectedIndex(options));
@@ -434,18 +480,14 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
434
480
  var _a, _b;
435
481
  e.preventDefault();
436
482
  e.stopPropagation();
483
+ if (justClearedRef.current)
484
+ return;
437
485
  (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
438
486
  if (open) {
439
487
  setOpen(false);
440
488
  setActiveIndex(-1);
441
- if (mode === 'single') {
442
- setQuery('');
443
- setInputValue((_b = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) !== null && _b !== void 0 ? _b : '');
444
- }
445
- else {
446
- setQuery('');
447
- setInputValue('');
448
- }
489
+ setQuery('');
490
+ setInputValue(mode === 'single' && !locallyClearedRef.current ? ((_b = selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.label) !== null && _b !== void 0 ? _b : '') : '');
449
491
  return;
450
492
  }
451
493
  handleOpen();
@@ -506,12 +548,9 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
506
548
  setOpen(false);
507
549
  setActiveIndex(-1);
508
550
  setQuery('');
509
- if (mode === 'single' && selectedOption) {
510
- setInputValue(selectedOption.label);
511
- }
512
- else {
513
- setInputValue('');
514
- }
551
+ setInputValue(mode === 'single' && selectedOption && !locallyClearedRef.current
552
+ ? selectedOption.label
553
+ : '');
515
554
  return;
516
555
  }
517
556
  };
@@ -523,14 +562,19 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
523
562
  selectedOptions.length > 0
524
563
  ? 8
525
564
  : 0,
526
- width: shouldFitContent ? measuredRootWidth : fullWidth ? '100%' : undefined,
565
+ width: fullWidth ? '100%' : shouldFitContent ? measuredRootWidth : undefined,
527
566
  flex: fullWidth || shouldFitContent ? '1 1 auto' : undefined,
528
- minWidth: 0,
567
+ minWidth: shouldFitContent ? measuredRootWidth : 0,
529
568
  maxWidth: shouldFitContent ? '100%' : undefined,
530
- }, children: [_jsx(Popover, { open: open, minWidth: popoverWidth !== null && popoverWidth !== void 0 ? popoverWidth : minWidth, matchTriggerWidth: true, fillTrigger: true, anchorRef: popoverAnchorRef, onOpenChange: nextOpen => {
569
+ }, children: [_jsx(Popover, { open: open, minWidth: popoverWidth !== null && popoverWidth !== void 0 ? popoverWidth : minWidth, matchTriggerWidth: true, fillTrigger: true, anchorRef: popoverAnchorRef !== null && popoverAnchorRef !== void 0 ? popoverAnchorRef : triggerWrapperRef, onOpenChange: nextOpen => {
570
+ if (justClearedRef.current) {
571
+ setOpen(false);
572
+ setActiveIndex(-1);
573
+ return;
574
+ }
531
575
  setOpen(nextOpen);
532
576
  if (nextOpen) {
533
- if (mode === 'single' && selectedOption) {
577
+ if (mode === 'single' && selectedOption && !locallyClearedRef.current) {
534
578
  setQuery('');
535
579
  setActiveIndex(getSelectedIndex(options));
536
580
  }
@@ -543,50 +587,70 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
543
587
  }
544
588
  }, fullWidth: fullWidth, autoFocusContent: false, returnFocus: false, overlayRef: popoverContentRef, trigger: (openPopover, icon) => {
545
589
  var _a, _b, _c, _d;
546
- return (_jsx(Input, { ...passthroughInputProps, ref: inputRef, value: inputValue, startAdornment: multiSelectionAdornment || inputPropsStartAdornment ? (_jsxs(_Fragment, { children: [multiSelectionAdornment, inputPropsStartAdornment] })) : undefined, endAdornment: inputPropsEndAdornment || icon ? (_jsxs(_Fragment, { children: [inputPropsEndAdornment, icon ? (_jsx("span", { className: styles.chevronButton, onMouseDown: handleChevronMouseDown, children: icon })) : null] })) : undefined, onFocus: e => {
547
- inputPropsOnFocus === null || inputPropsOnFocus === void 0 ? void 0 : inputPropsOnFocus(e);
548
- if (e.defaultPrevented)
549
- return;
550
- handleOpen();
551
- openPopover(e);
552
- }, onMouseDown: handleTriggerMouseDown, onChange: e => handleInputChange(e.currentTarget.value), onBlur: e => {
553
- inputPropsOnBlur === null || inputPropsOnBlur === void 0 ? void 0 : inputPropsOnBlur(e);
554
- if (e.defaultPrevented)
555
- return;
556
- handleBlur(e.relatedTarget);
557
- }, onKeyDown: e => {
558
- inputPropsOnKeyDown === null || inputPropsOnKeyDown === void 0 ? void 0 : inputPropsOnKeyDown(e);
559
- if (e.defaultPrevented)
590
+ return (_jsx("div", { ref: triggerWrapperRef, onMouseDown: e => {
591
+ const target = e.target;
592
+ if (justClearedRef.current) {
593
+ e.preventDefault();
594
+ e.stopPropagation();
560
595
  return;
561
- handleTabKeyDown(e);
562
- if (e.defaultPrevented)
596
+ }
597
+ if (target.closest('input, button, [data-input-role="clear"]'))
563
598
  return;
564
- handleKeyDown(e);
565
- }, placeholder: placeholder, variant: variant, inputSize: resolvedInputSize, width: shouldFitContent ? undefined : (width !== null && width !== void 0 ? width : inputProps === null || inputProps === void 0 ? void 0 : inputProps.width), autoComplete: (_a = autoComplete !== null && autoComplete !== void 0 ? autoComplete : inputProps === null || inputProps === void 0 ? void 0 : inputProps.autoComplete) !== null && _a !== void 0 ? _a : 'off', autoCorrect: (_b = autoCorrect !== null && autoCorrect !== void 0 ? autoCorrect : inputProps === null || inputProps === void 0 ? void 0 : inputProps.autoCorrect) !== null && _b !== void 0 ? _b : 'off', autoCapitalize: (_c = autoCapitalize !== null && autoCapitalize !== void 0 ? autoCapitalize : inputProps === null || inputProps === void 0 ? void 0 : inputProps.autoCapitalize) !== null && _c !== void 0 ? _c : 'none', spellCheck: (_d = spellCheck !== null && spellCheck !== void 0 ? spellCheck : inputProps === null || inputProps === void 0 ? void 0 : inputProps.spellCheck) !== null && _d !== void 0 ? _d : false, disabled: disabled, fullWidth: shouldStretchInput, inputClassName: [
566
- inputProps === null || inputProps === void 0 ? void 0 : inputProps.inputClassName,
567
- usesCountAdornment ? styles.inputWithoutStartPadding : '',
568
- ]
569
- .filter(Boolean)
570
- .join(' '), onClear: () => {
571
- setInputValue('');
572
- setQuery('');
573
- setActiveIndex(-1);
574
- onChange(mode === 'multi' ? [] : null);
575
- inputPropsOnClear === null || inputPropsOnClear === void 0 ? void 0 : inputPropsOnClear();
576
- onClear === null || onClear === void 0 ? void 0 : onClear();
577
- if (open) {
599
+ handleChevronMouseDown(e);
600
+ }, children: _jsx(Input, { ...passthroughInputProps, ref: inputRef, value: inputValue, startAdornment: multiSelectionAdornment || inputPropsStartAdornment ? (_jsxs(_Fragment, { children: [multiSelectionAdornment, inputPropsStartAdornment] })) : undefined, endAdornment: inputPropsEndAdornment || icon ? (_jsxs(_Fragment, { children: [inputPropsEndAdornment, icon ? (_jsx("span", { className: styles.chevronButton, onMouseDown: handleChevronMouseDown, children: icon })) : null] })) : undefined, onFocus: e => {
601
+ inputPropsOnFocus === null || inputPropsOnFocus === void 0 ? void 0 : inputPropsOnFocus(e);
602
+ if (e.defaultPrevented)
603
+ return;
604
+ if (justClearedRef.current)
605
+ return;
606
+ handleOpen();
607
+ openPopover(e);
608
+ }, onMouseDown: handleTriggerMouseDown, onChange: e => handleInputChange(e.currentTarget.value), onBlur: e => {
609
+ inputPropsOnBlur === null || inputPropsOnBlur === void 0 ? void 0 : inputPropsOnBlur(e);
610
+ if (e.defaultPrevented)
611
+ return;
612
+ handleBlur(e.relatedTarget);
613
+ }, onKeyDown: e => {
614
+ inputPropsOnKeyDown === null || inputPropsOnKeyDown === void 0 ? void 0 : inputPropsOnKeyDown(e);
615
+ if (e.defaultPrevented)
616
+ return;
617
+ handleTabKeyDown(e);
618
+ if (e.defaultPrevented)
619
+ return;
620
+ handleKeyDown(e);
621
+ }, placeholder: placeholder, variant: variant, inputSize: resolvedInputSize, width: shouldFitContent ? undefined : (width !== null && width !== void 0 ? width : inputProps === null || inputProps === void 0 ? void 0 : inputProps.width), autoComplete: (_a = autoComplete !== null && autoComplete !== void 0 ? autoComplete : inputProps === null || inputProps === void 0 ? void 0 : inputProps.autoComplete) !== null && _a !== void 0 ? _a : 'off', autoCorrect: (_b = autoCorrect !== null && autoCorrect !== void 0 ? autoCorrect : inputProps === null || inputProps === void 0 ? void 0 : inputProps.autoCorrect) !== null && _b !== void 0 ? _b : 'off', autoCapitalize: (_c = autoCapitalize !== null && autoCapitalize !== void 0 ? autoCapitalize : inputProps === null || inputProps === void 0 ? void 0 : inputProps.autoCapitalize) !== null && _c !== void 0 ? _c : 'none', spellCheck: (_d = spellCheck !== null && spellCheck !== void 0 ? spellCheck : inputProps === null || inputProps === void 0 ? void 0 : inputProps.spellCheck) !== null && _d !== void 0 ? _d : false, disabled: disabled, fullWidth: shouldStretchInput, inputClassName: [
622
+ inputProps === null || inputProps === void 0 ? void 0 : inputProps.inputClassName,
623
+ styles.typeaheadInput,
624
+ usesCountAdornment ? styles.inputWithoutStartPadding : '',
625
+ ]
626
+ .filter(Boolean)
627
+ .join(' '), onClear: (event) => {
628
+ var _a, _b;
629
+ (_a = event === null || event === void 0 ? void 0 : event.preventDefault) === null || _a === void 0 ? void 0 : _a.call(event);
630
+ (_b = event === null || event === void 0 ? void 0 : event.stopPropagation) === null || _b === void 0 ? void 0 : _b.call(event);
631
+ justClearedRef.current = true;
632
+ locallyClearedRef.current = true;
633
+ setHideSelectedHighlight(true);
578
634
  setOpen(false);
579
- }
580
- }, role: "combobox", "aria-expanded": open, "aria-controls": listboxId, "aria-autocomplete": "list", "aria-activedescendant": open && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined }));
581
- }, children: _jsx(Menu, { role: "listbox", id: listboxId, ref: listboxRef, children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => {
635
+ setInputValue('');
636
+ setQuery('');
637
+ setActiveIndex(-1);
638
+ inputPropsOnClear === null || inputPropsOnClear === void 0 ? void 0 : inputPropsOnClear();
639
+ if (onClear) {
640
+ onClear();
641
+ }
642
+ else {
643
+ onChange(mode === 'multi' ? [] : null);
644
+ }
645
+ clearJustClearedAfterEventCycle();
646
+ }, role: "combobox", "aria-expanded": open, "aria-controls": listboxId, "aria-autocomplete": "list", "aria-activedescendant": open && activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined }) }));
647
+ }, children: _jsx(Menu, { role: "listbox", id: listboxId, children: filteredOptions.length > 0 ? (filteredOptions.map((option, index) => {
582
648
  const isActive = index === activeIndex;
583
649
  const isSelected = mode === 'multi'
584
650
  ? Array.isArray(selectedValue) && selectedValue.includes(option.value)
585
- : option.value === selectedValue;
651
+ : option.value === selectedValue && !hideSelectedHighlight;
586
652
  const optionId = `${listboxId}-option-${index}`;
587
- return mode === 'multi' ? (_jsx(Menu.CheckItem, { checked: isSelected, active: isActive, interactiveRef: node => {
588
- optionRefs.current[index] = node;
589
- }, interactiveProps: {
653
+ return mode === 'multi' ? (_jsx(Menu.CheckItem, { checked: isSelected, active: isActive, interactiveProps: {
590
654
  id: optionId,
591
655
  role: 'option',
592
656
  onMouseEnter: () => setActiveIndex(index),
@@ -595,9 +659,7 @@ export function Typeahead({ options, mode = 'single', multiValueDisplayMode = 'c
595
659
  e.preventDefault();
596
660
  },
597
661
  onKeyDown: e => handleTabKeyDown(e),
598
- }, label: _jsx("span", { children: option.label }), onCheckedChange: () => commitSelection(option) }, option.value)) : (_jsx(Menu.Item, { active: isActive, selected: isSelected, children: _jsx("button", { ref: node => {
599
- optionRefs.current[index] = node;
600
- }, id: optionId, type: "button", role: "option", "aria-selected": isSelected, onMouseEnter: () => setActiveIndex(index), onMouseDown: e => {
662
+ }, label: _jsx("span", { children: option.label }), onCheckedChange: () => commitSelection(option) }, option.value)) : (_jsx(Menu.Item, { active: isActive, selected: isSelected, children: _jsx("button", { id: optionId, type: "button", role: "option", "aria-selected": isSelected, onMouseEnter: () => setActiveIndex(index), onMouseDown: e => {
601
663
  e.preventDefault();
602
664
  }, onKeyDown: e => handleTabKeyDown(e), onClick: () => commitSelection(option), children: _jsx("span", { children: option.label }) }) }, option.value));
603
665
  })) : (_jsx(Menu.Item, { disabled: true, children: emptyMessage })) }) }), mode === 'multi' &&
@@ -32,3 +32,7 @@
32
32
  .inputWithoutStartPadding {
33
33
  padding-inline-start: 0;
34
34
  }
35
+
36
+ .typeaheadInput {
37
+ cursor: pointer;
38
+ }
@@ -0,0 +1,21 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ export type GridGap = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
3
+ export interface GridProps {
4
+ children?: ReactNode;
5
+ gap?: GridGap;
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ export declare function Grid({ children, gap, className, style }: GridProps): import("react/jsx-runtime").JSX.Element;
10
+ export interface GridItemProps {
11
+ children?: ReactNode;
12
+ /** Default span (mobile-first, 1–12) */
13
+ base?: number;
14
+ /** Override at ≥768px */
15
+ md?: number;
16
+ /** Override at ≥1024px */
17
+ lg?: number;
18
+ className?: string;
19
+ style?: CSSProperties;
20
+ }
21
+ export declare function GridItem({ children, base, md, lg, className, style }: GridItemProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import styles from './Grid.module.css';
3
+ const GAP_TOKEN = {
4
+ none: '0',
5
+ xs: 'var(--spacing-xs)',
6
+ sm: 'var(--spacing-sm)',
7
+ md: 'var(--spacing-md)',
8
+ lg: 'var(--spacing-lg)',
9
+ xl: 'var(--spacing-xl)',
10
+ };
11
+ export function Grid({ children, gap = 'md', className, style }) {
12
+ return (_jsx("div", { className: [styles.grid, className].filter(Boolean).join(' '), style: { gap: GAP_TOKEN[gap], ...style }, children: children }));
13
+ }
14
+ export function GridItem({ children, base = 12, md, lg, className, style }) {
15
+ return (_jsx("div", { className: [styles.item, className].filter(Boolean).join(' '), style: {
16
+ '--span-base': base,
17
+ ...(md != null ? { '--span-md': md } : {}),
18
+ ...(lg != null ? { '--span-lg': lg } : {}),
19
+ ...style,
20
+ }, children: children }));
21
+ }
@@ -0,0 +1,20 @@
1
+ .grid {
2
+ display: grid;
3
+ grid-template-columns: repeat(12, minmax(0, 1fr));
4
+ }
5
+
6
+ .item {
7
+ grid-column: span var(--span-base, 12);
8
+ }
9
+
10
+ @media (min-width: 768px) {
11
+ .item {
12
+ grid-column: span var(--span-md, var(--span-base, 12));
13
+ }
14
+ }
15
+
16
+ @media (min-width: 1024px) {
17
+ .item {
18
+ grid-column: span var(--span-lg, var(--span-md, var(--span-base, 12)));
19
+ }
20
+ }
@@ -1,4 +1,4 @@
1
- import React, { JSX, PropsWithChildren } from 'react';
1
+ import React, { PropsWithChildren } from 'react';
2
2
  import { Severity } from '../../constants/severity.types';
3
3
  type HeadlineTone = 'dark' | 'light';
4
4
  interface HeadlineProps extends React.AriaAttributes {
@@ -7,11 +7,11 @@ interface HeadlineProps extends React.AriaAttributes {
7
7
  disableMargin?: boolean;
8
8
  severity?: Severity;
9
9
  weight?: 500 | 600 | 700;
10
- subHeadline?: string | JSX.Element;
10
+ subheader?: React.ReactNode;
11
11
  addition?: React.ReactNode;
12
12
  icon?: React.ReactNode;
13
13
  allowWrap?: boolean;
14
14
  tone?: HeadlineTone;
15
15
  }
16
- export declare function Headline({ size, marker, disableMargin, children, severity, weight, subHeadline, addition, icon, tone, allowWrap, }: PropsWithChildren<HeadlineProps>): React.ReactNode;
16
+ export declare function Headline({ size, marker, disableMargin, children, severity, weight, subheader, addition, icon, tone, allowWrap, }: PropsWithChildren<HeadlineProps>): React.JSX.Element;
17
17
  export {};
@@ -1,9 +1,9 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import styles from './Headline.module.css';
4
4
  import { SeverityBgColor } from '../../constants/severity';
5
5
  import { Icon } from '../icon/Icon';
6
- export function Headline({ size = 2, marker, disableMargin, children, severity, weight = 600, subHeadline, addition, icon, tone, allowWrap = true, }) {
6
+ export function Headline({ size = 2, marker, disableMargin, children, severity, weight = 600, subheader, addition, icon, tone, allowWrap = true, }) {
7
7
  const Tag = `h${size}`;
8
8
  const containerClassName = [styles.headlineContainer, tone ? styles[`tone-${tone}`] : '']
9
9
  .filter(Boolean)
@@ -18,8 +18,8 @@ export function Headline({ size = 2, marker, disableMargin, children, severity,
18
18
  const textClassName = [styles.text, allowWrap ? styles.wrap : styles.truncate]
19
19
  .filter(Boolean)
20
20
  .join(' ');
21
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: containerClassName, children: [_jsxs(Tag, { style: {
22
- '--font-weight': weight,
23
- '--marker-color': severity ? SeverityBgColor[severity] : undefined,
24
- }, className: headlineClassName, children: [icon || (severity && !marker) ? (_jsx("span", { className: styles.icon, children: _jsx(Icon, { customIcon: icon, severity: severity }) })) : null, _jsx("span", { className: textClassName, children: children })] }), addition] }), subHeadline && _jsx("div", { className: styles.subHeadline, children: subHeadline })] }));
21
+ return (_jsx("div", { className: containerClassName, children: _jsxs("div", { className: styles.headlineBlock, children: [_jsxs("div", { className: styles.headlineRow, children: [_jsxs(Tag, { style: {
22
+ '--font-weight': weight,
23
+ '--marker-color': severity ? SeverityBgColor[severity] : undefined,
24
+ }, className: headlineClassName, children: [icon || (severity && !marker) ? (_jsx("span", { className: styles.icon, children: _jsx(Icon, { customIcon: icon, severity: severity }) })) : null, _jsx("span", { className: textClassName, children: children })] }), addition ? _jsx("div", { className: styles.addition, children: addition }) : null] }), subheader ? _jsx("div", { className: styles.subheader, children: subheader }) : null] }) }));
25
25
  }