@digdir/designsystemet-react 0.59.1-alpha.0 → 0.59.1-alpha.1

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 (54) hide show
  1. package/dist/cjs/components/Accordion/Accordion.js +1 -4
  2. package/dist/cjs/components/Accordion/AccordionContent/AccordionContent.js +1 -2
  3. package/dist/cjs/components/Accordion/AccordionHeader/AccordionHeader.js +1 -2
  4. package/dist/cjs/components/Accordion/AccordionItem/AccordionItem.js +1 -4
  5. package/dist/cjs/components/Button/Button.js +2 -2
  6. package/dist/cjs/components/Modal/ModalHeader/ModalHeader.js +1 -1
  7. package/dist/cjs/components/Modal/ModalHeader/ModalHeader.module.css.js +1 -1
  8. package/dist/cjs/components/form/Combobox/Combobox.js +33 -43
  9. package/dist/cjs/components/form/Combobox/Combobox.module.css.js +1 -1
  10. package/dist/cjs/components/form/Combobox/internal/ComboboxChips.js +7 -12
  11. package/dist/cjs/components/form/Combobox/internal/ComboboxClearButton.js +3 -6
  12. package/dist/cjs/components/form/Combobox/internal/ComboboxInput.js +6 -40
  13. package/dist/cjs/components/form/Combobox/useCombobox.js +48 -60
  14. package/dist/cjs/components/form/Combobox/useComboboxKeyboard.js +25 -28
  15. package/dist/cjs/node_modules/clsx/dist/clsx.js +1 -1
  16. package/dist/cjs/node_modules/clsx/dist/lite.js +9 -0
  17. package/dist/cjs/react-css-modules.css +2 -136
  18. package/dist/esm/components/Accordion/Accordion.js +1 -4
  19. package/dist/esm/components/Accordion/AccordionContent/AccordionContent.js +1 -2
  20. package/dist/esm/components/Accordion/AccordionHeader/AccordionHeader.js +1 -2
  21. package/dist/esm/components/Accordion/AccordionItem/AccordionItem.js +1 -4
  22. package/dist/esm/components/Button/Button.js +2 -2
  23. package/dist/esm/components/Modal/ModalHeader/ModalHeader.js +1 -1
  24. package/dist/esm/components/Modal/ModalHeader/ModalHeader.module.css.js +1 -1
  25. package/dist/esm/components/form/Combobox/Combobox.js +33 -43
  26. package/dist/esm/components/form/Combobox/Combobox.module.css.js +1 -1
  27. package/dist/esm/components/form/Combobox/internal/ComboboxChips.js +7 -12
  28. package/dist/esm/components/form/Combobox/internal/ComboboxClearButton.js +3 -6
  29. package/dist/esm/components/form/Combobox/internal/ComboboxInput.js +7 -41
  30. package/dist/esm/components/form/Combobox/useCombobox.js +48 -60
  31. package/dist/esm/components/form/Combobox/useComboboxKeyboard.js +25 -28
  32. package/dist/esm/node_modules/clsx/dist/clsx.js +1 -1
  33. package/dist/esm/node_modules/clsx/dist/lite.js +4 -0
  34. package/dist/esm/react-css-modules.css +2 -136
  35. package/dist/types/components/Accordion/Accordion.d.ts.map +1 -1
  36. package/dist/types/components/Accordion/AccordionContent/AccordionContent.d.ts.map +1 -1
  37. package/dist/types/components/Accordion/AccordionHeader/AccordionHeader.d.ts.map +1 -1
  38. package/dist/types/components/Accordion/AccordionItem/AccordionItem.d.ts.map +1 -1
  39. package/dist/types/components/Modal/ModalHeader/ModalHeader.d.ts.map +1 -1
  40. package/dist/types/components/form/Combobox/Combobox.d.ts +0 -18
  41. package/dist/types/components/form/Combobox/Combobox.d.ts.map +1 -1
  42. package/dist/types/components/form/Combobox/ComboboxContext.d.ts +6 -13
  43. package/dist/types/components/form/Combobox/ComboboxContext.d.ts.map +1 -1
  44. package/dist/types/components/form/Combobox/internal/ComboboxChips.d.ts.map +1 -1
  45. package/dist/types/components/form/Combobox/internal/ComboboxClearButton.d.ts.map +1 -1
  46. package/dist/types/components/form/Combobox/internal/ComboboxInput.d.ts +9 -1
  47. package/dist/types/components/form/Combobox/internal/ComboboxInput.d.ts.map +1 -1
  48. package/dist/types/components/form/Combobox/useCombobox.d.ts +1 -4
  49. package/dist/types/components/form/Combobox/useCombobox.d.ts.map +1 -1
  50. package/dist/types/components/form/Combobox/useComboboxKeyboard.d.ts +3 -4
  51. package/dist/types/components/form/Combobox/useComboboxKeyboard.d.ts.map +1 -1
  52. package/package.json +2 -2
  53. package/dist/cjs/components/Accordion/Accordion.module.css.js +0 -6
  54. package/dist/esm/components/Accordion/Accordion.module.css.js +0 -4
@@ -4,11 +4,8 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var React = require('react');
6
6
  var clsx = require('../../node_modules/clsx/dist/clsx.js');
7
- var Accordion_module = require('./Accordion.module.css.js');
8
7
 
9
- const Accordion = React.forwardRef(({ border = false, color = 'neutral', className, ...rest }, ref) => (jsxRuntime.jsx("div", { className: clsx.clsx(Accordion_module.accordion, Accordion_module[color], {
10
- [Accordion_module.border]: border,
11
- }, className), ref: ref, ...rest })));
8
+ const Accordion = React.forwardRef(({ border = false, color = 'neutral', className, ...rest }, ref) => (jsxRuntime.jsx("div", { className: clsx.clsx('fds-accordion', border && 'fds-accordion--border', color && `fds-accordion--${color}`, className), ref: ref, ...rest })));
12
9
  Accordion.displayName = 'Accordion';
13
10
 
14
11
  exports.Accordion = Accordion;
@@ -4,7 +4,6 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var clsx = require('../../../node_modules/clsx/dist/clsx.js');
6
6
  var React = require('react');
7
- var Accordion_module = require('../Accordion.module.css.js');
8
7
  var AccordionItem = require('../AccordionItem/AccordionItem.js');
9
8
  var AnimateHeight = require('../../../utilities/AnimateHeight/AnimateHeight.js');
10
9
  var Paragraph = require('../../Typography/Paragraph/Paragraph.js');
@@ -15,7 +14,7 @@ const AccordionContent = React.forwardRef(({ children, className, ...rest }, ref
15
14
  console.error('<Accordion.Content> has to be used within an <Accordion.Item>');
16
15
  return null;
17
16
  }
18
- return (jsxRuntime.jsx(AnimateHeight.AnimateHeight, { id: context.contentId, open: context.open, children: jsxRuntime.jsx(Paragraph.Paragraph, { asChild: true, size: 'small', children: jsxRuntime.jsx("div", { ref: ref, className: clsx.clsx(Accordion_module.content, className), ...rest, children: children }) }) }));
17
+ return (jsxRuntime.jsx(AnimateHeight.AnimateHeight, { id: context.contentId, open: context.open, children: jsxRuntime.jsx(Paragraph.Paragraph, { asChild: true, size: 'small', children: jsxRuntime.jsx("div", { ref: ref, className: clsx.clsx('fds-accordion__content', className), ...rest, children: children }) }) }));
19
18
  });
20
19
  AccordionContent.displayName = 'AccordionContent';
21
20
 
@@ -5,7 +5,6 @@ var jsxRuntime = require('react/jsx-runtime');
5
5
  var akselIcons = require('@navikt/aksel-icons');
6
6
  var clsx = require('../../../node_modules/clsx/dist/clsx.js');
7
7
  var React = require('react');
8
- var Accordion_module = require('../Accordion.module.css.js');
9
8
  var AccordionItem = require('../AccordionItem/AccordionItem.js');
10
9
  var Heading = require('../../Typography/Heading/Heading.js');
11
10
  var Paragraph = require('../../Typography/Paragraph/Paragraph.js');
@@ -20,7 +19,7 @@ const AccordionHeader = React.forwardRef(({ level = 1, children, className, onHe
20
19
  context.toggleOpen();
21
20
  onHeaderClick && onHeaderClick(e);
22
21
  };
23
- return (jsxRuntime.jsx(Heading.Heading, { ref: ref, size: 'xsmall', level: level, className: clsx.clsx(Accordion_module.header, className), ...rest, children: jsxRuntime.jsxs("button", { type: 'button', className: clsx.clsx(Accordion_module.accordionButton, `fds-focus`), onClick: handleClick, "aria-expanded": context.open, "aria-controls": context.contentId, children: [jsxRuntime.jsx(akselIcons.ChevronDownIcon, { "aria-hidden": true, className: Accordion_module.expandIcon, fontSize: '1.5rem' }), jsxRuntime.jsx(Paragraph.Paragraph, { asChild: true, size: 'small', children: jsxRuntime.jsx("span", { children: children }) })] }) }));
22
+ return (jsxRuntime.jsx(Heading.Heading, { ref: ref, size: 'xsmall', level: level, className: clsx.clsx('fds-accordion__header', className), ...rest, children: jsxRuntime.jsxs("button", { type: 'button', className: clsx.clsx('fds-accordion__button', `fds-focus`), onClick: handleClick, "aria-expanded": context.open, "aria-controls": context.contentId, children: [jsxRuntime.jsx(akselIcons.ChevronDownIcon, { "aria-hidden": true, className: 'fds-accordion__expand-icon', fontSize: '1.5rem' }), jsxRuntime.jsx(Paragraph.Paragraph, { asChild: true, size: 'small', children: jsxRuntime.jsx("span", { children: children }) })] }) }));
24
23
  });
25
24
  AccordionHeader.displayName = 'AccordionHeader';
26
25
 
@@ -4,15 +4,12 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var clsx = require('../../../node_modules/clsx/dist/clsx.js');
6
6
  var React = require('react');
7
- var Accordion_module = require('../Accordion.module.css.js');
8
7
 
9
8
  const AccordionItemContext = React.createContext(null);
10
9
  const AccordionItem = React.forwardRef(({ children, className, open, defaultOpen = false, ...rest }, ref) => {
11
10
  const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
12
11
  const contentId = React.useId();
13
- return (jsxRuntime.jsx("div", { className: clsx.clsx(Accordion_module.item, {
14
- [Accordion_module.open]: open ?? internalOpen,
15
- }, className), ref: ref, ...rest, children: jsxRuntime.jsx(AccordionItemContext.Provider, { value: {
12
+ return (jsxRuntime.jsx("div", { className: clsx.clsx('fds-accordion__item', (open ?? internalOpen) && 'fds-accordion__item--open', className), ref: ref, ...rest, children: jsxRuntime.jsx(AccordionItemContext.Provider, { value: {
16
13
  open: open ?? internalOpen,
17
14
  toggleOpen: () => {
18
15
  if (open === undefined) {
@@ -3,7 +3,7 @@
3
3
 
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var React = require('react');
6
- var clsx = require('../../node_modules/clsx/dist/clsx.js');
6
+ var lite = require('../../node_modules/clsx/dist/lite.js');
7
7
  var index = require('../../node_modules/@radix-ui/react-slot/dist/index.js');
8
8
 
9
9
  /**
@@ -11,7 +11,7 @@ var index = require('../../node_modules/@radix-ui/react-slot/dist/index.js');
11
11
  */
12
12
  const Button = React.forwardRef(({ children, color = 'first', variant = 'primary', size = 'medium', fullWidth = false, icon = false, type = 'button', className, as = 'button', asChild, ...rest }, ref) => {
13
13
  const Component = asChild ? index.Slot : as;
14
- return (jsxRuntime.jsx(Component, { ref: ref, type: type, className: clsx.clsx('fds-btn', `fds-focus`, `fds-btn--${size}`, `fds-btn--${variant}`, `fds-btn--${color}`, { 'fds-btn--full-width': fullWidth }, { 'fds-btn--icon-only': icon }, className), ...rest, children: children }));
14
+ return (jsxRuntime.jsx(Component, { ref: ref, type: type, className: lite.clsx('fds-btn', `fds-focus`, `fds-btn--${size}`, `fds-btn--${variant}`, `fds-btn--${color}`, fullWidth && 'fds-btn--full-width', icon && 'fds-btn--icon-only', className), ...rest, children: children }));
15
15
  });
16
16
  Button.displayName = 'Button';
17
17
 
@@ -15,7 +15,7 @@ var Heading = require('../../Typography/Heading/Heading.js');
15
15
  const ModalHeader = React.forwardRef(({ closeButton = true, children, subtitle, asChild, className, ...rest }, ref) => {
16
16
  const Component = asChild ? index.Slot : 'div';
17
17
  const context = React.useContext(ModalRoot.ModalContext);
18
- return (jsxRuntime.jsxs(Component, { ref: ref, className: clsx.clsx(ModalHeader_module.modalHeader, !closeButton && ModalHeader_module.noCloseButton, className), ...rest, children: [subtitle && (jsxRuntime.jsx(Paragraph.Paragraph, { size: 'small', variant: 'short', children: subtitle })), jsxRuntime.jsx(Heading.Heading, { level: 2, size: 'xsmall', children: children }), closeButton && (jsxRuntime.jsx(Button.Button, { name: 'close', variant: 'tertiary', color: 'second', size: 'medium', onClick: context?.closeModal, autoFocus: true, icon: true, children: jsxRuntime.jsx(akselIcons.XMarkIcon, { title: 'close modal', fontSize: '1.5em' }) }))] }));
18
+ return (jsxRuntime.jsxs(Component, { ref: ref, className: clsx.clsx(ModalHeader_module.modalHeader, !closeButton && ModalHeader_module.noCloseButton, className), ...rest, children: [subtitle && (jsxRuntime.jsx(Paragraph.Paragraph, { size: 'small', variant: 'short', children: subtitle })), jsxRuntime.jsx(Heading.Heading, { level: 2, size: 'xsmall', children: children }), closeButton && (jsxRuntime.jsx(Button.Button, { name: 'close', variant: 'tertiary', color: 'second', size: 'medium', onClick: context?.closeModal, autoFocus: true, icon: true, className: ModalHeader_module.modalHeaderButton, children: jsxRuntime.jsx(akselIcons.XMarkIcon, { title: 'close modal', fontSize: '1.5em' }) }))] }));
19
19
  });
20
20
  ModalHeader.displayName = 'ModalHeader';
21
21
 
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var classes = {"modalHeader":"fds-modalheader-modalHeader-47e4ee5b","noCloseButton":"fds-modalheader-noCloseButton-47e4ee5b"};
4
+ var classes = {"modalHeader":"fds-modalheader-modalHeader-47e4ee5b","modalHeaderButton":"fds-modalheader-modalHeaderButton-47e4ee5b","noCloseButton":"fds-modalheader-noCloseButton-47e4ee5b"};
5
5
 
6
6
  module.exports = classes;
@@ -23,14 +23,13 @@ var Box = require('../../Box/Box.js');
23
23
  var Spinner = require('../../Spinner/Spinner.js');
24
24
  var objectUtils = require('../../../utilities/objectUtils.js');
25
25
 
26
- const ComboboxComponent = React.forwardRef(({ value, initialValue = [], onValueChange, label, hideLabel = false, description, multiple = false, size = 'medium', disabled = false, readOnly = false, hideChips = false, cleanButtonLabel = 'Fjern alt', clearButtonLabel = 'Fjern alt', hideClearButton = false, error, errorId, id, name, portal = true, htmlSize = 0, virtual = false, children, style, loading, loadingLabel = 'Laster...', filter, chipSrLabel = (option) => 'Slett ' + option.label, className, ...rest }, forwareddRef) => {
26
+ const ComboboxComponent = React.forwardRef(({ value, initialValue = [], onValueChange, label, hideLabel = false, description, multiple = false, size = 'medium', disabled = false, readOnly = false, hideChips = false, clearButtonLabel = 'Fjern alt', hideClearButton = false, error, errorId, id, name, portal = true, htmlSize = 0, virtual = false, children, style, loading, loadingLabel = 'Laster...', filter, chipSrLabel = (option) => 'Slett ' + option.label, className, ...rest }, forwareddRef) => {
27
27
  const inputRef = React.useRef(null);
28
28
  const portalRef = React.useRef(null);
29
29
  const listRef = React.useRef([]);
30
30
  const listId = React.useId();
31
31
  const [inputValue, setInputValue] = React.useState(rest.inputValue || '');
32
- /* const idDispatch = useComboboxIdDispatch(); */
33
- const { selectedOptions, options, restChildren, interactiveChildren, optionValues, customIds, filteredOptionsChildren, filteredOptions, prevSelectedHash, setSelectedOptions, setPrevSelectedHash, } = useCombobox.default({
32
+ const { selectedOptions, options, restChildren, interactiveChildren, customIds, filteredOptionsChildren, filteredOptions, setSelectedOptions, } = useCombobox.default({
34
33
  children,
35
34
  inputValue,
36
35
  filter,
@@ -51,20 +50,11 @@ const ComboboxComponent = React.forwardRef(({ value, initialValue = [], onValueC
51
50
  }, 'combobox');
52
51
  // if value is set, set input value to the label of the value
53
52
  React.useEffect(() => {
54
- if (value && value.length >= 0 && !multiple) {
53
+ if (value && value.length > 0 && !multiple) {
55
54
  const option = options[value[0]];
56
55
  setInputValue(option?.label || '');
57
56
  }
58
57
  }, [multiple, value, options]);
59
- // Send new value if option was clicked
60
- React.useEffect(() => {
61
- const selectedHash = JSON.stringify(selectedOptions);
62
- if (prevSelectedHash === selectedHash)
63
- return;
64
- const values = Object.keys(selectedOptions);
65
- onValueChange?.(values);
66
- setPrevSelectedHash(selectedHash);
67
- }, [onValueChange, selectedOptions, prevSelectedHash, setPrevSelectedHash]);
68
58
  React.useEffect(() => {
69
59
  if (value && Object.keys(options).length >= 0) {
70
60
  const updatedSelectedOptions = value.map((option) => {
@@ -76,38 +66,47 @@ const ComboboxComponent = React.forwardRef(({ value, initialValue = [], onValueC
76
66
  return acc;
77
67
  }, {}));
78
68
  }
79
- }, [multiple, prevSelectedHash, value, options, setSelectedOptions]);
69
+ }, [multiple, value, options, setSelectedOptions]);
80
70
  // handle click on option, either select or deselect - Handles single or multiple
81
- const handleSelectOption = (option) => {
82
- // if option is already selected, remove it
83
- if (value && value.includes(option.value)) {
84
- setSelectedOptions((prev) => {
85
- const updated = { ...prev };
86
- delete updated[option.value];
87
- return updated;
88
- });
71
+ const handleSelectOption = (args) => {
72
+ const { option, clear, remove } = args;
73
+ if (clear) {
74
+ setSelectedOptions({});
75
+ setInputValue('');
76
+ onValueChange?.([]);
89
77
  return;
90
78
  }
79
+ if (!option)
80
+ return;
81
+ if (remove) {
82
+ const newSelectedOptions = { ...selectedOptions };
83
+ delete newSelectedOptions[option.value];
84
+ setSelectedOptions(newSelectedOptions);
85
+ onValueChange?.(Object.keys(newSelectedOptions));
86
+ return;
87
+ }
88
+ const newSelectedOptions = { ...selectedOptions };
91
89
  if (multiple) {
92
- /* setSelectedOptions([...selectedOptions, option]); */
93
- setSelectedOptions((prev) => {
94
- const updated = { ...prev };
95
- updated[option.value] = option;
96
- return updated;
97
- });
90
+ if (newSelectedOptions[option.value]) {
91
+ delete newSelectedOptions[option.value];
92
+ }
93
+ else {
94
+ newSelectedOptions[option.value] = option;
95
+ }
98
96
  setInputValue('');
99
97
  inputRef.current?.focus();
100
98
  }
101
99
  else {
102
- setSelectedOptions({
103
- [option.value]: option,
104
- });
100
+ newSelectedOptions[option.value] = option;
105
101
  setInputValue(option?.label || '');
106
102
  // move cursor to the end of the input
107
103
  setTimeout(() => {
108
104
  inputRef.current?.setSelectionRange(option?.label?.length || 0, option?.label?.length || 0);
109
105
  }, 0);
110
106
  }
107
+ setSelectedOptions(newSelectedOptions);
108
+ console.log('calling new value with: ', Object.keys(newSelectedOptions));
109
+ onValueChange?.(Object.keys(newSelectedOptions));
111
110
  !multiple && setOpen(false);
112
111
  refs.domReference.current?.focus();
113
112
  };
@@ -124,7 +123,6 @@ const ComboboxComponent = React.forwardRef(({ value, initialValue = [], onValueC
124
123
  interactiveChildren,
125
124
  setOpen,
126
125
  setInputValue,
127
- setSelectedOptions,
128
126
  handleSelectOption: debouncedHandleSelectOption,
129
127
  });
130
128
  const rowVirtualizer = index.useVirtualizer({
@@ -147,23 +145,15 @@ const ComboboxComponent = React.forwardRef(({ value, initialValue = [], onValueC
147
145
  inputRef,
148
146
  refs,
149
147
  inputValue,
150
- error,
151
148
  formFieldProps,
152
- name,
153
149
  htmlSize,
154
- optionValues,
155
- hideChips,
156
- clearButtonLabel: cleanButtonLabel || clearButtonLabel,
157
- hideClearButton,
158
- listId,
150
+ clearButtonLabel,
159
151
  customIds,
160
152
  filteredOptions,
161
153
  setInputValue,
162
- handleKeyDown,
163
154
  setOpen,
164
155
  getReferenceProps,
165
156
  getItemProps,
166
- setSelectedOptions,
167
157
  /* Recieves the value of the option, and searches for it in our values lookup */
168
158
  onOptionClick: (value) => {
169
159
  if (readOnly)
@@ -171,13 +161,13 @@ const ComboboxComponent = React.forwardRef(({ value, initialValue = [], onValueC
171
161
  if (disabled)
172
162
  return;
173
163
  const option = options[value];
174
- debouncedHandleSelectOption(option);
164
+ debouncedHandleSelectOption({ option: option });
175
165
  },
176
166
  handleSelectOption: debouncedHandleSelectOption,
177
167
  chipSrLabel,
178
168
  listRef,
179
169
  forwareddRef,
180
- }, children: [jsxRuntime.jsxs(Box.Box, { className: clsx.clsx(Combobox_module.combobox, disabled && Combobox_module.disabled, className), style: style, ref: portalRef, children: [name && (jsxRuntime.jsx(ComboboxNative.default, { name: name, selectedOptions: selectedOptions, multiple: multiple })), jsxRuntime.jsx(ComboboxLabel.default, { label: label, description: description, size: size, readOnly: readOnly, hideLabel: hideLabel, formFieldProps: formFieldProps }), jsxRuntime.jsx(ComboboxInput.default, { ...objectUtils.omit(['inputValue'], rest), "aria-busy": loading }), jsxRuntime.jsx(ComboboxError.default, { size: size, error: error, formFieldProps: formFieldProps })] }), open && (jsxRuntime.jsx(floatingUi_react.FloatingPortal, { root: portal ? null : portalRef, children: jsxRuntime.jsx(floatingUi_react.FloatingFocusManager, { context: context, initialFocus: -1, visuallyHiddenDismiss: true, children: jsxRuntime.jsxs(Box.Box, { id: listId, shadow: 'medium', borderRadius: 'medium', borderColor: 'default', "aria-labelledby": formFieldProps.inputProps.id, "aria-autocomplete": 'list', tabIndex: -1, ...getFloatingProps({
170
+ }, children: [jsxRuntime.jsxs(Box.Box, { className: clsx.clsx(Combobox_module.combobox, disabled && Combobox_module.disabled, className), style: style, ref: portalRef, children: [name && (jsxRuntime.jsx(ComboboxNative.default, { name: name, selectedOptions: selectedOptions, multiple: multiple })), jsxRuntime.jsx(ComboboxLabel.default, { label: label, description: description, size: size, readOnly: readOnly, hideLabel: hideLabel, formFieldProps: formFieldProps }), jsxRuntime.jsx(ComboboxInput.default, { ...objectUtils.omit(['inputValue'], rest), hideClearButton: hideClearButton, listId: listId, error: error, hideChips: hideChips, handleKeyDown: handleKeyDown, "aria-busy": loading }), jsxRuntime.jsx(ComboboxError.default, { size: size, error: error, formFieldProps: formFieldProps })] }), open && (jsxRuntime.jsx(floatingUi_react.FloatingPortal, { root: portal ? null : portalRef, children: jsxRuntime.jsx(floatingUi_react.FloatingFocusManager, { context: context, initialFocus: -1, visuallyHiddenDismiss: true, children: jsxRuntime.jsxs(Box.Box, { id: listId, shadow: 'medium', borderRadius: 'medium', borderColor: 'default', "aria-labelledby": formFieldProps.inputProps.id, "aria-autocomplete": 'list', tabIndex: -1, ...getFloatingProps({
181
171
  ref: refs.setFloating,
182
172
  style: {
183
173
  ...floatingStyles,
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var classes = {"combobox":"fds-combobox-combobox-249a725c","optionsWrapper":"fds-combobox-optionsWrapper-249a725c","readOnly":"fds-combobox-readOnly-249a725c","inputWrapper":"fds-combobox-inputWrapper-249a725c","small":"fds-combobox-small-249a725c","medium":"fds-combobox-medium-249a725c","large":"fds-combobox-large-249a725c","error":"fds-combobox-error-249a725c","chipAndInput":"fds-combobox-chipAndInput-249a725c","chips":"fds-combobox-chips-249a725c","arrow":"fds-combobox-arrow-249a725c","readonly":"fds-combobox-readonly-249a725c","label":"fds-combobox-label-249a725c","description":"fds-combobox-description-249a725c","clearButton":"fds-combobox-clearButton-249a725c","disabled":"fds-combobox-disabled-249a725c","padlock":"fds-combobox-padlock-249a725c","errorMessage":"fds-combobox-errorMessage-249a725c","loading":"fds-combobox-loading-249a725c","inFocus":"fds-combobox-inFocus-249a725c","showChecked":"fds-combobox-showChecked-249a725c"};
4
+ var classes = {"combobox":"fds-combobox-combobox-249a725c","optionsWrapper":"fds-combobox-optionsWrapper-249a725c","readOnly":"fds-combobox-readOnly-249a725c","inputWrapper":"fds-combobox-inputWrapper-249a725c","small":"fds-combobox-small-249a725c","medium":"fds-combobox-medium-249a725c","large":"fds-combobox-large-249a725c","error":"fds-combobox-error-249a725c","chipAndInput":"fds-combobox-chipAndInput-249a725c","chips":"fds-combobox-chips-249a725c","arrow":"fds-combobox-arrow-249a725c","readonly":"fds-combobox-readonly-249a725c","label":"fds-combobox-label-249a725c","description":"fds-combobox-description-249a725c","clearButton":"fds-combobox-clearButton-249a725c","disabled":"fds-combobox-disabled-249a725c","padlock":"fds-combobox-padlock-249a725c","errorMessage":"fds-combobox-errorMessage-249a725c","loading":"fds-combobox-loading-249a725c","showChecked":"fds-combobox-showChecked-249a725c"};
5
5
 
6
6
  module.exports = classes;
@@ -14,7 +14,7 @@ const ComboboxChips = () => {
14
14
  if (!context) {
15
15
  throw new Error('ComboboxContext is missing');
16
16
  }
17
- const { size, readOnly, disabled, selectedOptions, setSelectedOptions, chipSrLabel, inputRef, } = context;
17
+ const { size, readOnly, disabled, selectedOptions, chipSrLabel, handleSelectOption, inputRef, } = context;
18
18
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Object.keys(selectedOptions).map((value) => {
19
19
  return (jsxRuntime.jsx(Removable.RemovableChip, { size: size, disabled: disabled, onKeyDown: (e) => {
20
20
  if (readOnly)
@@ -23,10 +23,9 @@ const ComboboxChips = () => {
23
23
  return;
24
24
  if (e.key === 'Enter') {
25
25
  e.stopPropagation();
26
- setSelectedOptions((prev) => {
27
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
28
- const { [value]: _, ...rest } = prev;
29
- return rest;
26
+ handleSelectOption({
27
+ option: selectedOptions[value],
28
+ remove: true,
30
29
  });
31
30
  inputRef.current?.focus();
32
31
  }
@@ -36,14 +35,10 @@ const ComboboxChips = () => {
36
35
  if (disabled)
37
36
  return;
38
37
  /* If we click a chip, filter the active values and remove the one we clicked */
39
- setSelectedOptions((prev) => {
40
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
41
- const { [value]: _, ...rest } = prev;
42
- return rest;
38
+ handleSelectOption({
39
+ option: selectedOptions[value],
40
+ remove: true,
43
41
  });
44
- }, style: {
45
- /* We already set the opacity on Combobox */
46
- opacity: 1,
47
42
  }, "aria-label": chipSrLabel(selectedOptions[value]), children: selectedOptions[value].label }, value));
48
43
  }) }));
49
44
  };
@@ -15,14 +15,13 @@ const ComboboxClearButton = () => {
15
15
  if (!context) {
16
16
  throw new Error('ComboboxContext is missing');
17
17
  }
18
- const { size, readOnly, disabled, clearButtonLabel, inputRef, setSelectedOptions, setInputValue, } = context;
18
+ const { size, readOnly, disabled, clearButtonLabel, handleSelectOption } = context;
19
19
  return (jsxRuntime.jsx("button", { disabled: disabled, className: clsx.clsx(Combobox_module.clearButton, Combobox_module[size], `fds-focus`), onClick: () => {
20
20
  if (readOnly)
21
21
  return;
22
22
  if (disabled)
23
23
  return;
24
- setSelectedOptions({});
25
- setInputValue('');
24
+ handleSelectOption({ option: null, clear: true });
26
25
  }, onKeyDown: (e) => {
27
26
  if (readOnly)
28
27
  return;
@@ -30,9 +29,7 @@ const ComboboxClearButton = () => {
30
29
  return;
31
30
  if (e.key === 'Enter') {
32
31
  e.stopPropagation();
33
- setSelectedOptions({});
34
- setInputValue('');
35
- inputRef.current?.focus();
32
+ handleSelectOption({ option: null, clear: true });
36
33
  }
37
34
  }, type: 'button', "aria-label": clearButtonLabel, children: jsxRuntime.jsx(akselIcons.XMarkIcon, { fontSize: '1.5em', title: 'Clear selection' }) }));
38
35
  };
@@ -17,7 +17,7 @@ var ComboboxClearButton = require('./ComboboxClearButton.js');
17
17
  var Box = require('../../../Box/Box.js');
18
18
  var objectUtils = require('../../../../utilities/objectUtils.js');
19
19
 
20
- const ComboboxInput = ({ ...rest }) => {
20
+ const ComboboxInput = ({ hideClearButton, listId, error, hideChips, handleKeyDown, ...rest }) => {
21
21
  const context = React.useContext(ComboboxContext.ComboboxContext);
22
22
  const idDispatch = ComboboxIdContext.useComboboxIdDispatch();
23
23
  if (!context) {
@@ -26,52 +26,20 @@ const ComboboxInput = ({ ...rest }) => {
26
26
  const setActiveIndex = (id) => {
27
27
  idDispatch?.({ type: 'SET_ACTIVE_INDEX', payload: id });
28
28
  };
29
- const { forwareddRef, listId, size, readOnly, disabled, open, inputRef, refs, inputValue, error, multiple, selectedOptions, formFieldProps, htmlSize, options, hideChips, hideClearButton, setOpen, handleKeyDown, getReferenceProps, setInputValue, handleSelectOption, } = context;
29
+ const { forwareddRef, size, readOnly, disabled, open, inputRef, refs, inputValue, multiple, selectedOptions, formFieldProps, htmlSize, options, setOpen, getReferenceProps, setInputValue, handleSelectOption, } = context;
30
30
  const mergedRefs = floatingUi_react.useMergeRefs([forwareddRef, inputRef]);
31
- // we need to check if input is in focus, to add focus styles to the wrapper
32
- const [inputInFocus, setInputInFocus] = React.useState(false);
33
- React.useEffect(() => {
34
- const input = inputRef.current;
35
- const onFocus = () => {
36
- setInputInFocus(true);
37
- };
38
- const onBlur = () => {
39
- setInputInFocus(false);
40
- };
41
- input?.addEventListener('focus', onFocus);
42
- input?.addEventListener('blur', onBlur);
43
- return () => {
44
- input?.removeEventListener('focus', onFocus);
45
- input?.removeEventListener('blur', onBlur);
46
- };
47
- }, [inputRef]);
48
31
  // onChange function for the input
49
32
  const onChange = (event) => {
50
33
  const value = event.target.value;
51
34
  setInputValue(value);
52
35
  setActiveIndex(0);
53
- if (typeof value === 'string') {
54
- setOpen(true);
55
- }
56
- else {
57
- setOpen(false);
58
- }
59
36
  // check if input value is the same as a label, if so, select it
60
- const option = options[value];
37
+ const option = options[value.toLowerCase()];
61
38
  if (!option)
62
39
  return;
63
40
  if (selectedOptions[option.value])
64
41
  return;
65
- handleSelectOption(option);
66
- if (multiple) {
67
- inputRef.current?.focus();
68
- }
69
- else {
70
- // move cursor to the end of the input
71
- setTimeout(() => {
72
- inputRef.current?.setSelectionRange(option?.label?.length || 0, option?.label?.length || 0);
73
- }, 0);
74
- }
42
+ handleSelectOption({ option: option });
75
43
  };
76
44
  const showClearButton = multiple && !hideClearButton && Object.keys(selectedOptions).length > 0;
77
45
  /* Props from floating-ui */
@@ -92,9 +60,7 @@ const ComboboxInput = ({ ...rest }) => {
92
60
  inputRef.current?.focus();
93
61
  },
94
62
  /* Handles list navigation */
95
- onKeyDown(event) {
96
- handleKeyDown(event);
97
- },
63
+ onKeyDown: handleKeyDown,
98
64
  // preventDefault on keydown to avoid sending in form
99
65
  onKeyPress(event) {
100
66
  if (event.key === 'Enter') {
@@ -102,7 +68,7 @@ const ComboboxInput = ({ ...rest }) => {
102
68
  }
103
69
  },
104
70
  });
105
- return (jsxRuntime.jsxs(Box.Box, { ...props, "aria-disabled": disabled, className: clsx.clsx(Textfield_module.input, Combobox_module.inputWrapper, Combobox_module[size], inputInFocus && Combobox_module.inFocus, readOnly && Combobox_module.readonly, error && Combobox_module.error), children: [jsxRuntime.jsxs("div", { className: Combobox_module.chipAndInput, children: [multiple && !hideChips && jsxRuntime.jsx(ComboboxChips.default, {}), jsxRuntime.jsx("input", { ref: mergedRefs, "aria-activedescendant": props['aria-activedescendant'], readOnly: readOnly, "aria-autocomplete": 'list', role: 'combobox', "aria-expanded": open, "aria-controls": listId, autoComplete: 'off', size: htmlSize, value: inputValue, ...objectUtils.omit(['style', 'className'], rest), ...formFieldProps.inputProps, onChange: (e) => {
71
+ return (jsxRuntime.jsxs(Box.Box, { ...props, "aria-disabled": disabled, className: clsx.clsx(Textfield_module.input, Combobox_module.inputWrapper, Combobox_module[size], readOnly && Combobox_module.readonly, error && Combobox_module.error), children: [jsxRuntime.jsxs("div", { className: Combobox_module.chipAndInput, children: [multiple && !hideChips && jsxRuntime.jsx(ComboboxChips.default, {}), jsxRuntime.jsx("input", { ref: mergedRefs, "aria-activedescendant": props['aria-activedescendant'], readOnly: readOnly, "aria-autocomplete": 'list', role: 'combobox', "aria-expanded": open, "aria-controls": listId, autoComplete: 'off', size: htmlSize, value: inputValue, ...objectUtils.omit(['style', 'className'], rest), ...formFieldProps.inputProps, onChange: (e) => {
106
72
  onChange(e);
107
73
  rest.onChange && rest.onChange(e);
108
74
  } })] }), showClearButton && jsxRuntime.jsx(ComboboxClearButton.default, {}), jsxRuntime.jsx("div", { className: Combobox_module.arrow, children: open ? (jsxRuntime.jsx(akselIcons.ChevronUpIcon, { title: 'arrow up', fontSize: '1.5em' })) : (jsxRuntime.jsx(akselIcons.ChevronDownIcon, { title: 'arrow down', fontSize: '1.5em' })) })] }));
@@ -20,35 +20,59 @@ function isInteractiveComboboxCustom(child) {
20
20
  function useCombobox({ children, inputValue, multiple, filter = (inputValue, option) => {
21
21
  return option.label.toLowerCase().startsWith(inputValue.toLowerCase());
22
22
  }, initialValue, }) {
23
- const options = React.useMemo(() => {
24
- const allOptions = {};
25
- React.Children.forEach(children, (child) => {
23
+ const { optionsChildren, customIds, restChildren, interactiveChildren } = React.useMemo(() => {
24
+ const allChildren = React.Children.toArray(children);
25
+ const result = allChildren.reduce((acc, child) => {
26
26
  if (isComboboxOption(child)) {
27
- const props = child.props;
28
- let label = props.displayValue || '';
29
- if (!props.displayValue) {
30
- let childrenLabel = '';
31
- // go over children and find all strings
32
- React.Children.forEach(props.children, (child) => {
33
- if (typeof child === 'string') {
34
- childrenLabel += child;
35
- }
36
- else {
37
- throw new Error('If ComboboxOption is not a string, it must have a displayValue prop');
38
- }
39
- });
40
- label = childrenLabel;
27
+ acc.optionsChildren.push(child);
28
+ }
29
+ else {
30
+ acc.restChildren.push(child);
31
+ if (isInteractiveComboboxCustom(child)) {
32
+ const childElement = child;
33
+ acc.interactiveChildren.push(childElement);
34
+ if (!childElement.props.id) {
35
+ throw new Error('If ComboboxCustom is interactive, it must have an id');
36
+ }
37
+ acc.customIds.push(childElement.props.id);
41
38
  }
42
- allOptions[props.value] = {
43
- value: props.value,
44
- label,
45
- displayValue: props.displayValue,
46
- description: props.description,
47
- };
48
39
  }
40
+ return acc;
41
+ }, {
42
+ optionsChildren: [],
43
+ customIds: [],
44
+ restChildren: [],
45
+ interactiveChildren: [],
49
46
  });
50
- return allOptions;
47
+ return result;
51
48
  }, [children]);
49
+ const options = React.useMemo(() => {
50
+ const allOptions = {};
51
+ optionsChildren.map((child) => {
52
+ const props = child.props;
53
+ let label = props.displayValue || '';
54
+ if (!props.displayValue) {
55
+ let childrenLabel = '';
56
+ // go over children and find all strings
57
+ React.Children.forEach(props.children, (child) => {
58
+ if (typeof child === 'string') {
59
+ childrenLabel += child;
60
+ }
61
+ else {
62
+ throw new Error('If ComboboxOption is not a string, it must have a displayValue prop');
63
+ }
64
+ });
65
+ label = childrenLabel;
66
+ }
67
+ allOptions[props.value] = {
68
+ value: props.value,
69
+ label,
70
+ displayValue: props.displayValue,
71
+ description: props.description,
72
+ };
73
+ });
74
+ return allOptions;
75
+ }, [optionsChildren]);
52
76
  const preSelectedOptions = React.useMemo(() => (initialValue || []).reduce((acc, value) => {
53
77
  const option = options[value];
54
78
  if (isOption(option)) {
@@ -57,22 +81,6 @@ function useCombobox({ children, inputValue, multiple, filter = (inputValue, opt
57
81
  return acc;
58
82
  }, {}), [initialValue, options]);
59
83
  const [selectedOptions, setSelectedOptions] = React.useState(preSelectedOptions);
60
- const [prevSelectedHash, setPrevSelectedHash] = React.useState(JSON.stringify(selectedOptions));
61
- const { optionsChildren, customIds } = React.useMemo(() => {
62
- const allChildren = React.Children.toArray(children);
63
- const optionsChildren = allChildren.filter((child) => isComboboxOption(child));
64
- // find all custom components with `interactive=true` and generate random values for them
65
- const customChildren = allChildren.filter((child) => {
66
- return isInteractiveComboboxCustom(child);
67
- });
68
- // return all ids
69
- const customIds = customChildren.map((child) => {
70
- if (!child.props.id)
71
- throw new Error('If ComboboxCustom is interactive, it must have an id');
72
- return child.props.id;
73
- });
74
- return { optionsChildren, customIds };
75
- }, [children]);
76
84
  const { filteredOptions, filteredOptionsChildren } = React.useMemo(() => {
77
85
  const filteredOptions = [];
78
86
  const filteredOptionsChildren = Object.keys(options)
@@ -90,35 +98,15 @@ function useCombobox({ children, inputValue, multiple, filter = (inputValue, opt
90
98
  return { filteredOptions, filteredOptionsChildren };
91
99
  // eslint-disable-next-line react-hooks/exhaustive-deps
92
100
  }, [inputValue, multiple, options, optionsChildren, selectedOptions]);
93
- const optionValues = React.useMemo(() => {
94
- // create an index map of values from optionsChildren
95
- const options = optionsChildren.map((child) => {
96
- const { value } = child.props;
97
- return value;
98
- });
99
- return [...customIds, ...options];
100
- }, [customIds, optionsChildren]);
101
- const { restChildren, interactiveChildren } = React.useMemo(() => {
102
- const restChildren = React.Children.toArray(children).filter((child) => {
103
- return !isComboboxOption(child);
104
- });
105
- const interactiveChildren = restChildren.filter((child) => {
106
- return isInteractiveComboboxCustom(child);
107
- });
108
- return { restChildren, interactiveChildren };
109
- }, [children]);
110
101
  return {
111
102
  filteredOptionsChildren,
112
103
  filteredOptions,
113
- optionValues,
114
104
  restChildren,
115
105
  options,
116
106
  customIds,
117
107
  selectedOptions,
118
- prevSelectedHash,
119
108
  interactiveChildren,
120
109
  setSelectedOptions,
121
- setPrevSelectedHash,
122
110
  };
123
111
  }
124
112