@digdir/designsystemet-react 1.13.0 → 1.13.2

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 (97) hide show
  1. package/dist/cjs/components/button/button.js +3 -2
  2. package/dist/cjs/components/dialog/dialog-trigger-context.js +5 -4
  3. package/dist/cjs/components/dialog/dialog-trigger.js +9 -3
  4. package/dist/cjs/components/dialog/dialog.js +6 -7
  5. package/dist/cjs/components/dropdown/dropdown-heading.js +1 -1
  6. package/dist/cjs/components/dropdown/dropdown-item.js +1 -1
  7. package/dist/cjs/components/dropdown/dropdown-list.js +1 -1
  8. package/dist/cjs/components/fieldset/fieldset-description.js +2 -1
  9. package/dist/cjs/components/fieldset/fieldset-legend.js +2 -1
  10. package/dist/cjs/components/fieldset/fieldset.js +2 -1
  11. package/dist/cjs/components/input/input.js +2 -1
  12. package/dist/cjs/components/pagination/pagination-button.js +3 -5
  13. package/dist/cjs/components/select/select.js +2 -1
  14. package/dist/cjs/components/suggestion/suggestion-list.js +2 -2
  15. package/dist/cjs/components/tabs/tabs-tab.js +10 -5
  16. package/dist/cjs/components/tabs/tabs.js +11 -3
  17. package/dist/cjs/components/toggle-group/toggle-group-item.js +2 -14
  18. package/dist/cjs/components/toggle-group/toggle-group.js +2 -1
  19. package/dist/cjs/components/tooltip/tooltip.js +3 -3
  20. package/dist/esm/components/button/button.js +3 -2
  21. package/dist/esm/components/dialog/dialog-trigger-context.js +6 -5
  22. package/dist/esm/components/dialog/dialog-trigger.js +9 -3
  23. package/dist/esm/components/dialog/dialog.js +6 -7
  24. package/dist/esm/components/dropdown/dropdown-heading.js +1 -1
  25. package/dist/esm/components/dropdown/dropdown-item.js +1 -1
  26. package/dist/esm/components/dropdown/dropdown-list.js +1 -1
  27. package/dist/esm/components/fieldset/fieldset-description.js +2 -1
  28. package/dist/esm/components/fieldset/fieldset-legend.js +2 -1
  29. package/dist/esm/components/fieldset/fieldset.js +2 -1
  30. package/dist/esm/components/input/input.js +2 -1
  31. package/dist/esm/components/pagination/pagination-button.js +3 -5
  32. package/dist/esm/components/select/select.js +2 -1
  33. package/dist/esm/components/suggestion/suggestion-list.js +2 -2
  34. package/dist/esm/components/tabs/tabs-tab.js +10 -5
  35. package/dist/esm/components/tabs/tabs.js +11 -3
  36. package/dist/esm/components/toggle-group/toggle-group-item.js +2 -14
  37. package/dist/esm/components/toggle-group/toggle-group.js +2 -1
  38. package/dist/esm/components/tooltip/tooltip.js +3 -3
  39. package/dist/types/components/Combobox/index.d.ts +1 -1
  40. package/dist/types/components/Combobox/index.d.ts.map +1 -1
  41. package/dist/types/components/badge/index.d.ts +1 -1
  42. package/dist/types/components/badge/index.d.ts.map +1 -1
  43. package/dist/types/components/breadcrumbs/index.d.ts +1 -1
  44. package/dist/types/components/button/button.d.ts +24 -2
  45. package/dist/types/components/button/button.d.ts.map +1 -1
  46. package/dist/types/components/card/index.d.ts +1 -1
  47. package/dist/types/components/card/index.d.ts.map +1 -1
  48. package/dist/types/components/chip/index.d.ts +1 -1
  49. package/dist/types/components/chip/index.d.ts.map +1 -1
  50. package/dist/types/components/dialog/dialog-trigger-context.d.ts +1 -8
  51. package/dist/types/components/dialog/dialog-trigger-context.d.ts.map +1 -1
  52. package/dist/types/components/dialog/dialog-trigger.d.ts +4 -1
  53. package/dist/types/components/dialog/dialog-trigger.d.ts.map +1 -1
  54. package/dist/types/components/dialog/dialog.d.ts +1 -1
  55. package/dist/types/components/dialog/index.d.ts +1 -1
  56. package/dist/types/components/dialog/index.d.ts.map +1 -1
  57. package/dist/types/components/dropdown/index.d.ts +1 -1
  58. package/dist/types/components/dropdown/index.d.ts.map +1 -1
  59. package/dist/types/components/error-summary/index.d.ts +1 -1
  60. package/dist/types/components/error-summary/index.d.ts.map +1 -1
  61. package/dist/types/components/field/index.d.ts +1 -1
  62. package/dist/types/components/field/index.d.ts.map +1 -1
  63. package/dist/types/components/fieldset/fieldset-description.d.ts.map +1 -1
  64. package/dist/types/components/fieldset/fieldset-legend.d.ts.map +1 -1
  65. package/dist/types/components/fieldset/fieldset.d.ts.map +1 -1
  66. package/dist/types/components/fieldset/index.d.ts +1 -1
  67. package/dist/types/components/fieldset/index.d.ts.map +1 -1
  68. package/dist/types/components/input/input.d.ts.map +1 -1
  69. package/dist/types/components/list/index.d.ts +1 -1
  70. package/dist/types/components/list/index.d.ts.map +1 -1
  71. package/dist/types/components/pagination/index.d.ts +1 -1
  72. package/dist/types/components/pagination/index.d.ts.map +1 -1
  73. package/dist/types/components/pagination/pagination-button.d.ts +4 -13
  74. package/dist/types/components/pagination/pagination-button.d.ts.map +1 -1
  75. package/dist/types/components/popover/index.d.ts +1 -1
  76. package/dist/types/components/popover/index.d.ts.map +1 -1
  77. package/dist/types/components/search/index.d.ts +1 -1
  78. package/dist/types/components/search/index.d.ts.map +1 -1
  79. package/dist/types/components/search/search-button.d.ts +4 -1
  80. package/dist/types/components/search/search-button.d.ts.map +1 -1
  81. package/dist/types/components/select/index.d.ts +1 -1
  82. package/dist/types/components/select/index.d.ts.map +1 -1
  83. package/dist/types/components/select/select.d.ts.map +1 -1
  84. package/dist/types/components/suggestion/index.d.ts +1 -1
  85. package/dist/types/components/suggestion/index.d.ts.map +1 -1
  86. package/dist/types/components/suggestion/suggestion-list.d.ts.map +1 -1
  87. package/dist/types/components/table/index.d.ts +2 -2
  88. package/dist/types/components/table/index.d.ts.map +1 -1
  89. package/dist/types/components/tabs/index.d.ts +1 -1
  90. package/dist/types/components/tabs/index.d.ts.map +1 -1
  91. package/dist/types/components/tabs/tabs-tab.d.ts.map +1 -1
  92. package/dist/types/components/tabs/tabs.d.ts +2 -2
  93. package/dist/types/components/tabs/tabs.d.ts.map +1 -1
  94. package/dist/types/components/toggle-group/toggle-group-item.d.ts.map +1 -1
  95. package/dist/types/components/toggle-group/toggle-group.d.ts.map +1 -1
  96. package/dist/types/components/tooltip/tooltip.d.ts.map +1 -1
  97. package/package.json +23 -23
@@ -13,15 +13,16 @@ var spinner = require('../spinner/spinner.js');
13
13
  * @example
14
14
  * <Button>Click me</Button>
15
15
  */
16
- const Button = react.forwardRef(function Button({ asChild, className, children, icon = false, loading = false, variant = 'primary', popoverTarget, popovertarget, ...rest }, ref) {
16
+ const Button = react.forwardRef(function Button({ asChild, className, children, icon = false, loading = false, variant = 'primary', popoverTarget, popovertarget, commandfor, commandFor, ...rest }, ref) {
17
17
  const Component = asChild ? reactSlot.Slot : 'button';
18
18
  const popoverVal = popoverTarget ?? popovertarget;
19
19
  const popoverKey = react.version.startsWith('19')
20
20
  ? 'popoverTarget'
21
21
  : 'popovertarget';
22
+ const commandForVal = commandFor ?? commandfor;
22
23
  // Fallbacks to undefined to prevent rendering attribute="false"
23
24
  return (jsxRuntime.jsxs(Component, { suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup etc.
24
- : true, "aria-busy": Boolean(loading) || undefined, "aria-disabled": Boolean(loading) || undefined, className: cl('ds-button', className), "data-icon": icon || undefined, "data-variant": variant, ref: ref,
25
+ : true, "aria-busy": Boolean(loading) || undefined, "aria-disabled": Boolean(loading) || undefined, className: cl('ds-button', className), "data-icon": icon || undefined, commandfor: commandForVal, "data-variant": variant, ref: ref,
25
26
  /* don't set type when we use `asChild` */
26
27
  type: asChild ? undefined : 'button', [popoverKey]: popoverVal, ...rest, children: [loading === true ? (jsxRuntime.jsx(spinner.Spinner, { "aria-hidden": 'true' })) : (loading // Allow custom loading spinner
27
28
  ), jsxRuntime.jsx(reactSlot.Slottable, { children: icon && loading ? null : children })] }));
@@ -4,7 +4,9 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var react = require('react');
6
6
 
7
- const Context = react.createContext({});
7
+ const Context = react.createContext({
8
+ current: null,
9
+ });
8
10
  /**
9
11
  * DialogTriggerContext component, used to provide a context for a dialog trigger.
10
12
  *
@@ -17,9 +19,8 @@ const Context = react.createContext({});
17
19
  * </Dialog.TriggerContext>
18
20
  */
19
21
  const DialogTriggerContext = (rest) => {
20
- const [state, setState] = react.useState({});
21
- const setContext = (next) => setState({ ...state, ...next });
22
- return jsxRuntime.jsx(Context.Provider, { value: { ...state, setContext }, ...rest });
22
+ const contextRef = react.useRef(null);
23
+ return jsxRuntime.jsx(Context.Provider, { value: contextRef, ...rest });
23
24
  };
24
25
  DialogTriggerContext.displayName = 'DialogTriggerContext';
25
26
 
@@ -19,10 +19,16 @@ var dialogTriggerContext = require('./dialog-trigger-context.js');
19
19
  * </Dialog.TriggerContext>
20
20
  */
21
21
  const DialogTrigger = react.forwardRef(function DialogTrigger({ asChild, ...rest }, ref) {
22
- const { id, modal } = react.useContext(dialogTriggerContext.Context);
22
+ const contextRef = react.useContext(dialogTriggerContext.Context); // Using contextRef instead of command as this is instantly available and plays nice with tests
23
23
  const Component = asChild ? reactSlot.Slot : button.Button;
24
- return (jsxRuntime.jsx(Component, { suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup
25
- : true, command: modal ? 'show-modal' : '--show-non-modal', commandfor: id, ref: ref, ...rest }));
24
+ const openDialog = () => {
25
+ /* check if element has `data-modal`, it it has, use `showModal` */
26
+ contextRef.current?.getAttribute('data-modal') === 'true'
27
+ ? contextRef.current?.showModal()
28
+ : contextRef.current?.show();
29
+ };
30
+ return (jsxRuntime.jsx(Component, { "aria-haspopup": 'dialog', onClick: openDialog, ref: ref, suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup
31
+ : true, ...rest }));
26
32
  });
27
33
 
28
34
  exports.DialogTrigger = DialogTrigger;
@@ -34,24 +34,23 @@ var dialogTriggerContext = require('./dialog-trigger-context.js');
34
34
  * </Dialog>
35
35
  */
36
36
  const Dialog = react.forwardRef(function Dialog({ asChild, children, className, closeButton = 'Lukk dialogvindu', id, modal = true, onAnimationEnd, onClick, onClose, open, placement = 'center', ...rest }, ref) {
37
- const { setContext } = react.useContext(dialogTriggerContext.Context);
37
+ const contextRef = react.useContext(dialogTriggerContext.Context);
38
38
  const dialogRef = react.useRef(null); // This local ref is used to make sure the dialog works without a DialogTriggerContext
39
39
  const Component = asChild ? reactSlot.Slot : 'dialog';
40
- const mergedRefs = useMergeRefs.useMergeRefs([ref, dialogRef]);
40
+ const mergedRefs = useMergeRefs.useMergeRefs([contextRef, ref, dialogRef]);
41
41
  const showProp = modal ? 'showModal' : 'show';
42
42
  const autoId = react.useId();
43
43
  const usedId = id ?? autoId;
44
44
  // Toggle open based on prop
45
45
  react.useEffect(() => dialogRef.current?.[open ? showProp : 'close'](), [open]);
46
- // Store context for DialogTrigger to consume, so it can open the dialog when the trigger is clicked
47
- react.useEffect(() => setContext?.({ id: usedId, modal }), [usedId, modal]);
48
- return (jsxRuntime.jsxs(Component, { className: cl('ds-dialog', className), "data-placement": placement, id: usedId, onClose: (event) => onClose?.(event.nativeEvent), onClick: (event) => {
46
+ return (jsxRuntime.jsxs(Component, { className: cl('ds-dialog', className), "data-placement": placement, "data-modal": modal, id: usedId, onClose: (event) => onClose?.(event.nativeEvent), onClick: (event) => {
49
47
  onClick?.(event);
50
48
  const { currentTarget: dialog, target: el, defaultPrevented } = event;
51
49
  const isClose = el?.closest?.('[data-command="close"]');
52
50
  if (!defaultPrevented && isClose) {
53
51
  dialog.close();
54
- console.warn('Designsystemet: data-command="close" is deprecated. Use command="close" and commandfor="DIALOG-ID" instead.');
52
+ if (window.dsWarnings !== false)
53
+ console.log('Designsystemet: data-command="close" is deprecated. Use command="close" and commandfor="DIALOG-ID" instead.');
55
54
  }
56
55
  }, onAnimationEnd: (event) => {
57
56
  const { currentTarget: dialog } = event;
@@ -59,7 +58,7 @@ const Dialog = react.forwardRef(function Dialog({ asChild, children, className,
59
58
  if (document.activeElement !== autofocus)
60
59
  autofocus?.focus(); // Handle autofocus on open
61
60
  onAnimationEnd?.(event);
62
- }, ref: mergedRefs, ...rest, children: [closeButton !== false && (jsxRuntime.jsx(button.Button, { "aria-label": closeButton, "data-color": 'neutral', icon: true, variant: 'tertiary', command: 'close', commandfor: id ?? autoId })), children] }));
61
+ }, ref: mergedRefs, ...rest, children: [closeButton !== false && (jsxRuntime.jsx(button.Button, { "aria-label": closeButton, "data-color": 'neutral', icon: true, variant: 'tertiary', command: 'close', commandfor: usedId })), children] }));
63
62
  });
64
63
 
65
64
  exports.Dialog = Dialog;
@@ -13,7 +13,7 @@ var heading = require('../heading/heading.js');
13
13
  * <DropdownHeading>Heading</DropdownHeading>
14
14
  * </Dropdown>
15
15
  */
16
- const DropdownHeading = react.forwardRef(function DropdownHeading({ className, ...rest }, ref) {
16
+ const DropdownHeading = react.forwardRef(function DropdownHeading(rest, ref) {
17
17
  return jsxRuntime.jsx(heading.Heading, { ref: ref, ...rest });
18
18
  });
19
19
 
@@ -16,7 +16,7 @@ var react = require('react');
16
16
  * </DropdownList>
17
17
  * </Dropdown>
18
18
  */
19
- const DropdownItem = react.forwardRef(function DropdownItem({ className, ...rest }, ref) {
19
+ const DropdownItem = react.forwardRef(function DropdownItem(rest, ref) {
20
20
  return jsxRuntime.jsx("li", { ref: ref, ...rest });
21
21
  });
22
22
 
@@ -16,7 +16,7 @@ var react = require('react');
16
16
  * </DropdownList>
17
17
  * </Dropdown>
18
18
  */
19
- const DropdownList = react.forwardRef(function DropdownList({ className, ...rest }, ref) {
19
+ const DropdownList = react.forwardRef(function DropdownList(rest, ref) {
20
20
  return jsxRuntime.jsx("ul", { ref: ref, ...rest });
21
21
  });
22
22
 
@@ -14,7 +14,8 @@ var paragraph = require('../paragraph/paragraph.js');
14
14
  * </FieldsetDescription>
15
15
  */
16
16
  const FieldsetDescription = react.forwardRef(function FieldsetDescription(rest, ref) {
17
- return jsxRuntime.jsx(paragraph.Paragraph, { ref: ref, ...rest });
17
+ return (jsxRuntime.jsx(paragraph.Paragraph, { suppressHydrationWarning // Since @digdir/designsystemet-web adds attributes
18
+ : true, ref: ref, ...rest }));
18
19
  });
19
20
 
20
21
  exports.FieldsetDescription = FieldsetDescription;
@@ -12,7 +12,8 @@ var label = require('../label/label.js');
12
12
  * <FieldsetLegend>Skriv inn dine svar</FieldsetLegend>
13
13
  */
14
14
  const FieldsetLegend = react.forwardRef(function FieldsetLegend(rest, ref) {
15
- return (jsxRuntime.jsx(label.Label, { asChild: true, children: jsxRuntime.jsx("legend", { ref: ref, ...rest }) }));
15
+ return (jsxRuntime.jsx(label.Label, { asChild: true, children: jsxRuntime.jsx("legend", { suppressHydrationWarning // Since @digdir/designsystemet-web adds attributes
16
+ : true, ref: ref, ...rest }) }));
16
17
  });
17
18
 
18
19
  exports.FieldsetLegend = FieldsetLegend;
@@ -21,7 +21,8 @@ var react = require('react');
21
21
  * </Fieldset>
22
22
  */
23
23
  const Fieldset = react.forwardRef(function Fieldset({ className, ...rest }, ref) {
24
- return (jsxRuntime.jsx("fieldset", { className: cl('ds-fieldset', className), ref: ref, ...rest }));
24
+ return (jsxRuntime.jsx("fieldset", { className: cl('ds-fieldset', className), suppressHydrationWarning // Since @digdir/designsystemet-web adds attributes
25
+ : true, ref: ref, ...rest }));
25
26
  });
26
27
 
27
28
  exports.Fieldset = Fieldset;
@@ -12,7 +12,8 @@ var react = require('react');
12
12
  * <Input />
13
13
  */
14
14
  const Input = react.forwardRef(function Input({ type = 'text', className, onChange, onClick, ...rest }, ref) {
15
- return (jsxRuntime.jsx("input", { className: cl(`ds-input`, className), ref: ref, type: type, onChange: (event) => rest.readOnly || onChange?.(event), onClick: (event) => {
15
+ return (jsxRuntime.jsx("input", { className: cl(`ds-input`, className), ref: ref, type: type, suppressHydrationWarning // Since <ds-field> adds attributes
16
+ : true, onChange: (event) => rest.readOnly || onChange?.(event), onClick: (event) => {
16
17
  if (rest.readOnly)
17
18
  event.preventDefault(); // Make readonly work for checkbox / radio / switch
18
19
  onClick?.(event);
@@ -2,8 +2,8 @@
2
2
  'use strict';
3
3
 
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
- var reactSlot = require('@radix-ui/react-slot');
6
5
  var react = require('react');
6
+ var button = require('../button/button.js');
7
7
 
8
8
  /**
9
9
  * PaginationButton component, use within a Pagination.Item.
@@ -13,10 +13,8 @@ var react = require('react');
13
13
  * <PaginationButton aria-label='Forrige side'>Forrige</PaginationButton>
14
14
  * </PaginationItem>
15
15
  */
16
- const PaginationButton = react.forwardRef(function PaginationButton({ asChild, ...rest }, ref) {
17
- const Component = asChild ? reactSlot.Slot : 'button';
18
- return (jsxRuntime.jsx(Component, { className: 'ds-button', "data-variant": 'tertiary', suppressHydrationWarning // Since <ds-pagination> adds attributes
19
- : true, ref: ref, ...rest }));
16
+ const PaginationButton = react.forwardRef(function PaginationButton(rest, ref) {
17
+ return jsxRuntime.jsx(button.Button, { "data-variant": 'tertiary', ref: ref, ...rest });
20
18
  });
21
19
 
22
20
  exports.PaginationButton = PaginationButton;
@@ -15,7 +15,8 @@ var react = require('react');
15
15
  * </Select>
16
16
  */
17
17
  const Select = react.forwardRef(function Select({ className, onKeyDown, onMouseDown, width, readOnly, ...rest }, ref) {
18
- return (jsxRuntime.jsx("select", { className: cl('ds-input', className), "aria-readonly": rest['aria-readonly'] ?? readOnly, "data-width": width, ref: ref, ...rest }));
18
+ return (jsxRuntime.jsx("select", { className: cl('ds-input', className), "aria-readonly": rest['aria-readonly'] ?? readOnly, suppressHydrationWarning // Since <ds-field> adds attributes
19
+ : true, "data-width": width, ref: ref, ...rest }));
19
20
  });
20
21
 
21
22
  exports.Select = Select;
@@ -20,8 +20,8 @@ var suggestion = require('./suggestion.js');
20
20
  const SuggestionList = react.forwardRef(function SuggestionList({ singular = '%d forslag', plural = '%d forslag', className, id, autoPlacement = true, ...rest }, ref) {
21
21
  const { handleFilter } = react.useContext(suggestion.SuggestionContext);
22
22
  react.useEffect(handleFilter); // Must run on every render
23
- return (jsxRuntime.jsx("u-datalist", { class: className, popover: 'manual' // Is also set by field.ts, but is nice to have in case focus runs before toggle event
24
- , "data-nofilter": true, "data-sr-plural": plural, "data-sr-singular": singular, ref: ref, suppressHydrationWarning // Since <u-datalist> adds attributes
23
+ return (jsxRuntime.jsx("u-datalist", { class: className, "data-nofilter": true, "data-sr-plural": plural, "data-sr-singular": singular, popover: 'manual', ref: ref, role: 'listbox' // Is also set by <ds-suggestion> but nice to have to please tests
24
+ , suppressHydrationWarning // Since <u-datalist> adds attributes
25
25
  : true, ...rest }));
26
26
  });
27
27
 
@@ -12,14 +12,19 @@ var tabs = require('./tabs.js');
12
12
  * @example
13
13
  * <TabsTab value='1'>Tab 1</TabsTab>
14
14
  */
15
- const TabsTab = react.forwardRef(function TabsTab({ value, className, onClick, ...rest }, ref) {
16
- const { onChange, getPrefixedValue } = react.useContext(tabs.Context);
15
+ const TabsTab = react.forwardRef(function TabsTab({ value, className, onClick, onClickCapture, ...rest }, ref) {
16
+ const { onChange, getPrefixedValue, isControlled, currentValue } = react.useContext(tabs.Context);
17
17
  return (
18
18
  // biome-ignore lint/a11y/noStaticElementInteractions: ds-tabs IS interactive
19
19
  jsxRuntime.jsx("ds-tab", { "aria-controls": rest['aria-controls'] ?? getPrefixedValue?.(value), "data-value": value, ref: ref, suppressHydrationWarning // Since <ds-tablist> adds attributes
20
- : true, onClick: (e) => {
21
- if (e.isTrusted)
22
- onChange?.(value); // Only call onChange is user actually clicked, not when programmatically clicked/controlled
20
+ : true, onClickCapture: (e) => {
21
+ onClickCapture?.(e);
22
+ if (isControlled && currentValue !== value) {
23
+ e.preventDefault();
24
+ }
25
+ }, onClick: (e) => {
26
+ if (currentValue !== value)
27
+ onChange?.(value); // Only call onChange when actual value change
23
28
  onClick?.(e);
24
29
  }, class: className, ...rest, children: rest.children }));
25
30
  });
@@ -42,12 +42,20 @@ const Tabs = react.forwardRef(function Tabs({ value, defaultValue, className, on
42
42
  return;
43
43
  tabsRef.current?.tabList?.tabs?.forEach((tab) => {
44
44
  if (tab.getAttribute('data-value') === value)
45
- tab.click();
45
+ tab.setAttribute('aria-selected', 'true');
46
46
  });
47
47
  }, [value, isControlled]);
48
+ react.useEffect(() => {
49
+ if (defaultValue && tabsRef.current) {
50
+ tabsRef.current?.tabList?.tabs?.forEach((tab) => {
51
+ if (tab.getAttribute('data-value') === defaultValue)
52
+ tab.setAttribute('aria-selected', 'true');
53
+ });
54
+ }
55
+ }, []);
48
56
  return (jsxRuntime.jsx(Context.Provider, { value: {
49
- value,
50
- defaultValue,
57
+ isControlled,
58
+ currentValue: value,
51
59
  onChange: onValueChange,
52
60
  getPrefixedValue: (value) => value && `${valuePrefix}-${value}`,
53
61
  }, children: jsxRuntime.jsx("ds-tabs", { suppressHydrationWarning // Since <ds-tablist> adds attributes
@@ -16,20 +16,8 @@ const ToggleGroupItem = react.forwardRef(function ToggleGroupItem({ className, c
16
16
  const toggleGroup$1 = react.useContext(toggleGroup.ToggleGroupContext);
17
17
  const value = rawValue ?? genValue;
18
18
  const active = toggleGroup$1.value === value;
19
- const { form, formAction, formEncType, formMethod, formNoValidate, formTarget, required, disabled, 'aria-disabled': ariaDisabled, ...labelProps } = rest;
20
- /** Add backwards compatibility for `button` props that were previously allowed on `ToggleGroupItem` but are passeable to `input`*/
21
- const inputProps = {
22
- form,
23
- formAction,
24
- formEncType,
25
- formMethod,
26
- formNoValidate,
27
- formTarget,
28
- required,
29
- disabled,
30
- 'aria-disabled': ariaDisabled,
31
- };
32
- return (jsxRuntime.jsxs("label", { ref: ref, ...labelProps, className: cl('ds-button', className), "data-variant": 'tertiary', "aria-disabled": ariaDisabled ?? disabled, children: [jsxRuntime.jsx("input", { ...inputProps, checked: active, name: toggleGroup$1.name, onChange: () => toggleGroup$1.onChange?.(value), type: 'radio', value: value, disabled: disabled, "aria-disabled": ariaDisabled }), children] }));
19
+ const { 'aria-disabled': ariaDisabled, disabled, form, formAction, formEncType, formMethod, formNoValidate, formTarget, required, ...labelProps } = rest;
20
+ return (jsxRuntime.jsxs("label", { ref: ref, ...labelProps, className: cl('ds-button', className), "data-variant": 'tertiary', "aria-disabled": ariaDisabled ?? disabled, children: [jsxRuntime.jsx("input", { "aria-disabled": ariaDisabled, checked: active, disabled: disabled, form: form, formAction: formAction, formEncType: formEncType, formMethod: formMethod, formNoValidate: formNoValidate, formTarget: formTarget, name: toggleGroup$1.name, onChange: () => toggleGroup$1.onChange?.(value), required: required, type: 'radio', value: value }), children] }));
33
21
  });
34
22
 
35
23
  exports.ToggleGroupItem = ToggleGroupItem;
@@ -35,7 +35,8 @@ const ToggleGroup = react.forwardRef(function ToggleGroup({ children, className,
35
35
  value,
36
36
  variant,
37
37
  }, children: jsxRuntime.jsx("fieldset", { className: cl('ds-toggle-group', className), "data-toggle-group": '' // Default to empty string to ensure attribute is present
38
- , "data-variant": variant, ref: ref, ...rest, children: children }) }));
38
+ , "data-variant": variant, suppressHydrationWarning // Since @digdir/designsystemet-web adds attributes
39
+ : true, ref: ref, ...rest, children: children }) }));
39
40
  });
40
41
 
41
42
  exports.ToggleGroup = ToggleGroup;
@@ -19,11 +19,11 @@ var react = require('react');
19
19
  * Hover me
20
20
  * </Tooltip>
21
21
  */
22
- const Tooltip = react.forwardRef(function Tooltip({ content, placement = 'top', autoPlacement = true, ...rest }, _ref) {
22
+ const Tooltip = react.forwardRef(function Tooltip({ content, placement = 'top', autoPlacement = true, ...rest }, ref) {
23
23
  /* check if children is a string */
24
24
  const isString = typeof rest.children === 'string';
25
- return (jsxRuntime.jsx(reactSlot.Slot, { "aria-label": content, "data-tooltip": content, "data-placement": placement, "data-autoplacement": autoPlacement, suppressHydrationWarning // Since data-tooltip adds aria-label/aria-description
26
- : true, ...rest, children: isString ? jsxRuntime.jsx("span", { tabIndex: 0, children: rest.children }) : rest.children }));
25
+ return (jsxRuntime.jsx(reactSlot.Slot, { "aria-label": content || undefined, "data-tooltip": content, "data-placement": placement, "data-autoplacement": autoPlacement, suppressHydrationWarning // Since data-tooltip adds aria-label/aria-description
26
+ : true, ref: ref, ...rest, children: isString ? jsxRuntime.jsx("span", { tabIndex: 0, children: rest.children }) : rest.children }));
27
27
  });
28
28
 
29
29
  exports.Tooltip = Tooltip;
@@ -11,15 +11,16 @@ import { Spinner } from '../spinner/spinner.js';
11
11
  * @example
12
12
  * <Button>Click me</Button>
13
13
  */
14
- const Button = forwardRef(function Button({ asChild, className, children, icon = false, loading = false, variant = 'primary', popoverTarget, popovertarget, ...rest }, ref) {
14
+ const Button = forwardRef(function Button({ asChild, className, children, icon = false, loading = false, variant = 'primary', popoverTarget, popovertarget, commandfor, commandFor, ...rest }, ref) {
15
15
  const Component = asChild ? Slot : 'button';
16
16
  const popoverVal = popoverTarget ?? popovertarget;
17
17
  const popoverKey = version.startsWith('19')
18
18
  ? 'popoverTarget'
19
19
  : 'popovertarget';
20
+ const commandForVal = commandFor ?? commandfor;
20
21
  // Fallbacks to undefined to prevent rendering attribute="false"
21
22
  return (jsxs(Component, { suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup etc.
22
- : true, "aria-busy": Boolean(loading) || undefined, "aria-disabled": Boolean(loading) || undefined, className: cl('ds-button', className), "data-icon": icon || undefined, "data-variant": variant, ref: ref,
23
+ : true, "aria-busy": Boolean(loading) || undefined, "aria-disabled": Boolean(loading) || undefined, className: cl('ds-button', className), "data-icon": icon || undefined, commandfor: commandForVal, "data-variant": variant, ref: ref,
23
24
  /* don't set type when we use `asChild` */
24
25
  type: asChild ? undefined : 'button', [popoverKey]: popoverVal, ...rest, children: [loading === true ? (jsx(Spinner, { "aria-hidden": 'true' })) : (loading // Allow custom loading spinner
25
26
  ), jsx(Slottable, { children: icon && loading ? null : children })] }));
@@ -1,8 +1,10 @@
1
1
  'use client';
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { createContext, useState } from 'react';
3
+ import { createContext, useRef } from 'react';
4
4
 
5
- const Context = createContext({});
5
+ const Context = createContext({
6
+ current: null,
7
+ });
6
8
  /**
7
9
  * DialogTriggerContext component, used to provide a context for a dialog trigger.
8
10
  *
@@ -15,9 +17,8 @@ const Context = createContext({});
15
17
  * </Dialog.TriggerContext>
16
18
  */
17
19
  const DialogTriggerContext = (rest) => {
18
- const [state, setState] = useState({});
19
- const setContext = (next) => setState({ ...state, ...next });
20
- return jsx(Context.Provider, { value: { ...state, setContext }, ...rest });
20
+ const contextRef = useRef(null);
21
+ return jsx(Context.Provider, { value: contextRef, ...rest });
21
22
  };
22
23
  DialogTriggerContext.displayName = 'DialogTriggerContext';
23
24
 
@@ -17,10 +17,16 @@ import { Context } from './dialog-trigger-context.js';
17
17
  * </Dialog.TriggerContext>
18
18
  */
19
19
  const DialogTrigger = forwardRef(function DialogTrigger({ asChild, ...rest }, ref) {
20
- const { id, modal } = useContext(Context);
20
+ const contextRef = useContext(Context); // Using contextRef instead of command as this is instantly available and plays nice with tests
21
21
  const Component = asChild ? Slot : Button;
22
- return (jsx(Component, { suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup
23
- : true, command: modal ? 'show-modal' : '--show-non-modal', commandfor: id, ref: ref, ...rest }));
22
+ const openDialog = () => {
23
+ /* check if element has `data-modal`, it it has, use `showModal` */
24
+ contextRef.current?.getAttribute('data-modal') === 'true'
25
+ ? contextRef.current?.showModal()
26
+ : contextRef.current?.show();
27
+ };
28
+ return (jsx(Component, { "aria-haspopup": 'dialog', onClick: openDialog, ref: ref, suppressHydrationWarning // Might get augmented through designsystemet-web with aria-haspopup
29
+ : true, ...rest }));
24
30
  });
25
31
 
26
32
  export { DialogTrigger };
@@ -32,24 +32,23 @@ import { Context } from './dialog-trigger-context.js';
32
32
  * </Dialog>
33
33
  */
34
34
  const Dialog = forwardRef(function Dialog({ asChild, children, className, closeButton = 'Lukk dialogvindu', id, modal = true, onAnimationEnd, onClick, onClose, open, placement = 'center', ...rest }, ref) {
35
- const { setContext } = useContext(Context);
35
+ const contextRef = useContext(Context);
36
36
  const dialogRef = useRef(null); // This local ref is used to make sure the dialog works without a DialogTriggerContext
37
37
  const Component = asChild ? Slot : 'dialog';
38
- const mergedRefs = useMergeRefs([ref, dialogRef]);
38
+ const mergedRefs = useMergeRefs([contextRef, ref, dialogRef]);
39
39
  const showProp = modal ? 'showModal' : 'show';
40
40
  const autoId = useId();
41
41
  const usedId = id ?? autoId;
42
42
  // Toggle open based on prop
43
43
  useEffect(() => dialogRef.current?.[open ? showProp : 'close'](), [open]);
44
- // Store context for DialogTrigger to consume, so it can open the dialog when the trigger is clicked
45
- useEffect(() => setContext?.({ id: usedId, modal }), [usedId, modal]);
46
- return (jsxs(Component, { className: cl('ds-dialog', className), "data-placement": placement, id: usedId, onClose: (event) => onClose?.(event.nativeEvent), onClick: (event) => {
44
+ return (jsxs(Component, { className: cl('ds-dialog', className), "data-placement": placement, "data-modal": modal, id: usedId, onClose: (event) => onClose?.(event.nativeEvent), onClick: (event) => {
47
45
  onClick?.(event);
48
46
  const { currentTarget: dialog, target: el, defaultPrevented } = event;
49
47
  const isClose = el?.closest?.('[data-command="close"]');
50
48
  if (!defaultPrevented && isClose) {
51
49
  dialog.close();
52
- console.warn('Designsystemet: data-command="close" is deprecated. Use command="close" and commandfor="DIALOG-ID" instead.');
50
+ if (window.dsWarnings !== false)
51
+ console.log('Designsystemet: data-command="close" is deprecated. Use command="close" and commandfor="DIALOG-ID" instead.');
53
52
  }
54
53
  }, onAnimationEnd: (event) => {
55
54
  const { currentTarget: dialog } = event;
@@ -57,7 +56,7 @@ const Dialog = forwardRef(function Dialog({ asChild, children, className, closeB
57
56
  if (document.activeElement !== autofocus)
58
57
  autofocus?.focus(); // Handle autofocus on open
59
58
  onAnimationEnd?.(event);
60
- }, ref: mergedRefs, ...rest, children: [closeButton !== false && (jsx(Button, { "aria-label": closeButton, "data-color": 'neutral', icon: true, variant: 'tertiary', command: 'close', commandfor: id ?? autoId })), children] }));
59
+ }, ref: mergedRefs, ...rest, children: [closeButton !== false && (jsx(Button, { "aria-label": closeButton, "data-color": 'neutral', icon: true, variant: 'tertiary', command: 'close', commandfor: usedId })), children] }));
61
60
  });
62
61
 
63
62
  export { Dialog };
@@ -11,7 +11,7 @@ import { Heading } from '../heading/heading.js';
11
11
  * <DropdownHeading>Heading</DropdownHeading>
12
12
  * </Dropdown>
13
13
  */
14
- const DropdownHeading = forwardRef(function DropdownHeading({ className, ...rest }, ref) {
14
+ const DropdownHeading = forwardRef(function DropdownHeading(rest, ref) {
15
15
  return jsx(Heading, { ref: ref, ...rest });
16
16
  });
17
17
 
@@ -14,7 +14,7 @@ import { forwardRef } from 'react';
14
14
  * </DropdownList>
15
15
  * </Dropdown>
16
16
  */
17
- const DropdownItem = forwardRef(function DropdownItem({ className, ...rest }, ref) {
17
+ const DropdownItem = forwardRef(function DropdownItem(rest, ref) {
18
18
  return jsx("li", { ref: ref, ...rest });
19
19
  });
20
20
 
@@ -14,7 +14,7 @@ import { forwardRef } from 'react';
14
14
  * </DropdownList>
15
15
  * </Dropdown>
16
16
  */
17
- const DropdownList = forwardRef(function DropdownList({ className, ...rest }, ref) {
17
+ const DropdownList = forwardRef(function DropdownList(rest, ref) {
18
18
  return jsx("ul", { ref: ref, ...rest });
19
19
  });
20
20
 
@@ -12,7 +12,8 @@ import { Paragraph } from '../paragraph/paragraph.js';
12
12
  * </FieldsetDescription>
13
13
  */
14
14
  const FieldsetDescription = forwardRef(function FieldsetDescription(rest, ref) {
15
- return jsx(Paragraph, { ref: ref, ...rest });
15
+ return (jsx(Paragraph, { suppressHydrationWarning // Since @digdir/designsystemet-web adds attributes
16
+ : true, ref: ref, ...rest }));
16
17
  });
17
18
 
18
19
  export { FieldsetDescription };
@@ -10,7 +10,8 @@ import { Label } from '../label/label.js';
10
10
  * <FieldsetLegend>Skriv inn dine svar</FieldsetLegend>
11
11
  */
12
12
  const FieldsetLegend = forwardRef(function FieldsetLegend(rest, ref) {
13
- return (jsx(Label, { asChild: true, children: jsx("legend", { ref: ref, ...rest }) }));
13
+ return (jsx(Label, { asChild: true, children: jsx("legend", { suppressHydrationWarning // Since @digdir/designsystemet-web adds attributes
14
+ : true, ref: ref, ...rest }) }));
14
15
  });
15
16
 
16
17
  export { FieldsetLegend };
@@ -19,7 +19,8 @@ import { forwardRef } from 'react';
19
19
  * </Fieldset>
20
20
  */
21
21
  const Fieldset = forwardRef(function Fieldset({ className, ...rest }, ref) {
22
- return (jsx("fieldset", { className: cl('ds-fieldset', className), ref: ref, ...rest }));
22
+ return (jsx("fieldset", { className: cl('ds-fieldset', className), suppressHydrationWarning // Since @digdir/designsystemet-web adds attributes
23
+ : true, ref: ref, ...rest }));
23
24
  });
24
25
 
25
26
  export { Fieldset };
@@ -10,7 +10,8 @@ import { forwardRef } from 'react';
10
10
  * <Input />
11
11
  */
12
12
  const Input = forwardRef(function Input({ type = 'text', className, onChange, onClick, ...rest }, ref) {
13
- return (jsx("input", { className: cl(`ds-input`, className), ref: ref, type: type, onChange: (event) => rest.readOnly || onChange?.(event), onClick: (event) => {
13
+ return (jsx("input", { className: cl(`ds-input`, className), ref: ref, type: type, suppressHydrationWarning // Since <ds-field> adds attributes
14
+ : true, onChange: (event) => rest.readOnly || onChange?.(event), onClick: (event) => {
14
15
  if (rest.readOnly)
15
16
  event.preventDefault(); // Make readonly work for checkbox / radio / switch
16
17
  onClick?.(event);
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx } from 'react/jsx-runtime';
3
- import { Slot } from '@radix-ui/react-slot';
4
3
  import { forwardRef } from 'react';
4
+ import { Button } from '../button/button.js';
5
5
 
6
6
  /**
7
7
  * PaginationButton component, use within a Pagination.Item.
@@ -11,10 +11,8 @@ import { forwardRef } from 'react';
11
11
  * <PaginationButton aria-label='Forrige side'>Forrige</PaginationButton>
12
12
  * </PaginationItem>
13
13
  */
14
- const PaginationButton = forwardRef(function PaginationButton({ asChild, ...rest }, ref) {
15
- const Component = asChild ? Slot : 'button';
16
- return (jsx(Component, { className: 'ds-button', "data-variant": 'tertiary', suppressHydrationWarning // Since <ds-pagination> adds attributes
17
- : true, ref: ref, ...rest }));
14
+ const PaginationButton = forwardRef(function PaginationButton(rest, ref) {
15
+ return jsx(Button, { "data-variant": 'tertiary', ref: ref, ...rest });
18
16
  });
19
17
 
20
18
  export { PaginationButton };
@@ -13,7 +13,8 @@ import { forwardRef } from 'react';
13
13
  * </Select>
14
14
  */
15
15
  const Select = forwardRef(function Select({ className, onKeyDown, onMouseDown, width, readOnly, ...rest }, ref) {
16
- return (jsx("select", { className: cl('ds-input', className), "aria-readonly": rest['aria-readonly'] ?? readOnly, "data-width": width, ref: ref, ...rest }));
16
+ return (jsx("select", { className: cl('ds-input', className), "aria-readonly": rest['aria-readonly'] ?? readOnly, suppressHydrationWarning // Since <ds-field> adds attributes
17
+ : true, "data-width": width, ref: ref, ...rest }));
17
18
  });
18
19
 
19
20
  export { Select };
@@ -18,8 +18,8 @@ import { SuggestionContext } from './suggestion.js';
18
18
  const SuggestionList = forwardRef(function SuggestionList({ singular = '%d forslag', plural = '%d forslag', className, id, autoPlacement = true, ...rest }, ref) {
19
19
  const { handleFilter } = useContext(SuggestionContext);
20
20
  useEffect(handleFilter); // Must run on every render
21
- return (jsx("u-datalist", { class: className, popover: 'manual' // Is also set by field.ts, but is nice to have in case focus runs before toggle event
22
- , "data-nofilter": true, "data-sr-plural": plural, "data-sr-singular": singular, ref: ref, suppressHydrationWarning // Since <u-datalist> adds attributes
21
+ return (jsx("u-datalist", { class: className, "data-nofilter": true, "data-sr-plural": plural, "data-sr-singular": singular, popover: 'manual', ref: ref, role: 'listbox' // Is also set by <ds-suggestion> but nice to have to please tests
22
+ , suppressHydrationWarning // Since <u-datalist> adds attributes
23
23
  : true, ...rest }));
24
24
  });
25
25
 
@@ -10,14 +10,19 @@ import { Context } from './tabs.js';
10
10
  * @example
11
11
  * <TabsTab value='1'>Tab 1</TabsTab>
12
12
  */
13
- const TabsTab = forwardRef(function TabsTab({ value, className, onClick, ...rest }, ref) {
14
- const { onChange, getPrefixedValue } = useContext(Context);
13
+ const TabsTab = forwardRef(function TabsTab({ value, className, onClick, onClickCapture, ...rest }, ref) {
14
+ const { onChange, getPrefixedValue, isControlled, currentValue } = useContext(Context);
15
15
  return (
16
16
  // biome-ignore lint/a11y/noStaticElementInteractions: ds-tabs IS interactive
17
17
  jsx("ds-tab", { "aria-controls": rest['aria-controls'] ?? getPrefixedValue?.(value), "data-value": value, ref: ref, suppressHydrationWarning // Since <ds-tablist> adds attributes
18
- : true, onClick: (e) => {
19
- if (e.isTrusted)
20
- onChange?.(value); // Only call onChange is user actually clicked, not when programmatically clicked/controlled
18
+ : true, onClickCapture: (e) => {
19
+ onClickCapture?.(e);
20
+ if (isControlled && currentValue !== value) {
21
+ e.preventDefault();
22
+ }
23
+ }, onClick: (e) => {
24
+ if (currentValue !== value)
25
+ onChange?.(value); // Only call onChange when actual value change
21
26
  onClick?.(e);
22
27
  }, class: className, ...rest, children: rest.children }));
23
28
  });