@digdir/designsystemet-react 1.0.0 → 1.0.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.
- package/README.md +6 -3
- package/dist/cjs/components/MultiSuggestion/MultiSuggestion.js +160 -0
- package/dist/cjs/components/MultiSuggestion/MultiSuggestionChips.js +20 -0
- package/dist/cjs/components/MultiSuggestion/MultiSuggestionClear.js +52 -0
- package/dist/cjs/components/MultiSuggestion/MultiSuggestionEmpty.js +23 -0
- package/dist/cjs/components/MultiSuggestion/MultiSuggestionInput.js +37 -0
- package/dist/cjs/components/MultiSuggestion/MultiSuggestionList.js +30 -0
- package/dist/cjs/components/MultiSuggestion/MultiSuggestionOption.js +12 -0
- package/dist/cjs/components/MultiSuggestion/index.js +34 -0
- package/dist/cjs/index.js +14 -0
- package/dist/cjs/utilities/hooks/useCheckboxGroup/useCheckboxGroup.js +35 -27
- package/dist/cjs/utilities/hooks/useRadioGroup/useRadioGroup.js +22 -19
- package/dist/esm/components/MultiSuggestion/MultiSuggestion.js +157 -0
- package/dist/esm/components/MultiSuggestion/MultiSuggestionChips.js +18 -0
- package/dist/esm/components/MultiSuggestion/MultiSuggestionClear.js +49 -0
- package/dist/esm/components/MultiSuggestion/MultiSuggestionEmpty.js +21 -0
- package/dist/esm/components/MultiSuggestion/MultiSuggestionInput.js +35 -0
- package/dist/esm/components/MultiSuggestion/MultiSuggestionList.js +28 -0
- package/dist/esm/components/MultiSuggestion/MultiSuggestionOption.js +10 -0
- package/dist/esm/components/MultiSuggestion/index.js +26 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/utilities/hooks/useCheckboxGroup/useCheckboxGroup.js +35 -27
- package/dist/esm/utilities/hooks/useRadioGroup/useRadioGroup.js +23 -20
- package/dist/types/components/Combobox/ComboboxIdContext.d.ts.map +1 -1
- package/dist/types/components/Combobox/Option/useComboboxOption.d.ts.map +1 -1
- package/dist/types/components/Combobox/useComboboxKeyboard.d.ts.map +1 -1
- package/dist/types/components/Combobox/useFloatingCombobox.d.ts.map +1 -1
- package/dist/types/components/Combobox/useFormField/useFormField.d.ts.map +1 -1
- package/dist/types/components/Combobox/utilities.d.ts.map +1 -1
- package/dist/types/components/Field/fieldObserver.d.ts.map +1 -1
- package/dist/types/components/MultiSuggestion/MultiSuggestionClear.d.ts.map +1 -1
- package/dist/types/components/Suggestion/SuggestionClear.d.ts.map +1 -1
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/components/index.d.ts.map +1 -1
- package/dist/types/utilities/RovingFocus/useRovingFocus.d.ts.map +1 -1
- package/dist/types/utilities/hooks/useCheckboxGroup/useCheckboxGroup.d.ts.map +1 -1
- package/dist/types/utilities/hooks/usePagination/usePagination.d.ts.map +1 -1
- package/dist/types/utilities/hooks/useRadioGroup/useRadioGroup.d.ts.map +1 -1
- package/dist/types/utilities/omit/omit.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
React implementation of the Designsystemet components
|
|
4
4
|
|
|
5
|
-
- Uses `@digdir/designsystemet-
|
|
6
|
-
-
|
|
5
|
+
- Uses `@digdir/designsystemet-css` for styling.
|
|
6
|
+
- Uses `@digdir/designsystemet-theme` or CSS file generated from `@digdir/designsystemet tokens build` for theming.
|
|
7
|
+
- Build your own theme on https://theme.designsystemet.no/
|
|
8
|
+
- All components support `ref`.
|
|
9
|
+
- All components support SSR.
|
|
10
|
+
- Use full component name, e.g. `CardBlock` instead of `Card.Block`
|
|
7
11
|
- Most components extend and behave as native html-elements.
|
|
8
12
|
- Most components support composition and `asChild` for overriding the underlying html-element.
|
|
9
|
-
- SSR support.
|
|
10
13
|
|
|
11
14
|
Read the Designsystemet [README](https://github.com/digdir/designsystemet) to get started.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
require('@u-elements/u-tags');
|
|
7
|
+
var react$1 = require('@floating-ui/react');
|
|
8
|
+
var uDatalist = require('@u-elements/u-datalist');
|
|
9
|
+
var cl = require('clsx/lite');
|
|
10
|
+
|
|
11
|
+
const MultiSuggestionContext = react.createContext({});
|
|
12
|
+
const MultiSuggestion = react.forwardRef(function MultiSuggestion({ value, defaultValue, onValueChange, name, filter = true, allowCreate = false, className, ...rest }, ref) {
|
|
13
|
+
const [listId, setListId] = react.useState(react.useId());
|
|
14
|
+
const [selectedItems, setSelectedItems] = react.useState({});
|
|
15
|
+
const inputRef = react.useRef(null);
|
|
16
|
+
const uTagsRef = react.useRef(null);
|
|
17
|
+
const mergedRefs = react$1.useMergeRefs([ref, uTagsRef]);
|
|
18
|
+
const isControlled = Boolean(value);
|
|
19
|
+
const [controlledDirty, setControlledDirty] = react.useState(false);
|
|
20
|
+
/**
|
|
21
|
+
* If we have set a default value, set it on initial render
|
|
22
|
+
*/
|
|
23
|
+
react.useEffect(() => {
|
|
24
|
+
if (!defaultValue)
|
|
25
|
+
return;
|
|
26
|
+
if (value) {
|
|
27
|
+
console.warn('defaultValue can not be used in combination with value');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const items = uTagsRef.current?.querySelectorAll('u-option');
|
|
31
|
+
if (!items)
|
|
32
|
+
return;
|
|
33
|
+
const defaultItems = Array.from(items).filter((item) => defaultValue.includes(item.value));
|
|
34
|
+
for (const item of defaultItems) {
|
|
35
|
+
uTagsRef.current?.dispatchEvent(new CustomEvent('add', {
|
|
36
|
+
detail: { item },
|
|
37
|
+
}));
|
|
38
|
+
setSelectedItems((prevItems) => ({
|
|
39
|
+
...prevItems,
|
|
40
|
+
[item.value]: item,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
return () => {
|
|
44
|
+
console.error('Default value changed during render');
|
|
45
|
+
};
|
|
46
|
+
}, [defaultValue]);
|
|
47
|
+
/**
|
|
48
|
+
* Controlled state management
|
|
49
|
+
*/
|
|
50
|
+
react.useEffect(() => {
|
|
51
|
+
if (!value)
|
|
52
|
+
return;
|
|
53
|
+
const items = inputRef.current?.list?.options;
|
|
54
|
+
if (!items)
|
|
55
|
+
return;
|
|
56
|
+
const itemsArray = Array.from(items);
|
|
57
|
+
const itemsArrayValues = itemsArray.map((item) => item.value);
|
|
58
|
+
const selectedArray = Object.keys(selectedItems);
|
|
59
|
+
const validValues = value.filter((val) => itemsArrayValues.includes(val));
|
|
60
|
+
const itemsToAdd = validValues.filter((val) => !selectedArray.includes(val));
|
|
61
|
+
const itemsToRemove = selectedArray.filter((val) => !validValues.includes(val));
|
|
62
|
+
for (const item of itemsArray) {
|
|
63
|
+
if (itemsToAdd.includes(item.value)) {
|
|
64
|
+
uTagsRef.current?.dispatchEvent(new CustomEvent('add', {
|
|
65
|
+
detail: { item },
|
|
66
|
+
}));
|
|
67
|
+
setSelectedItems((prevItems) => ({
|
|
68
|
+
...prevItems,
|
|
69
|
+
[item.value]: item,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
if (itemsToRemove.includes(item.value)) {
|
|
73
|
+
uTagsRef.current?.dispatchEvent(new CustomEvent('remove', {
|
|
74
|
+
detail: { item },
|
|
75
|
+
}));
|
|
76
|
+
setSelectedItems((prevItems) => {
|
|
77
|
+
const { [item.value]: _, ...rest } = prevItems;
|
|
78
|
+
return rest;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, [value]);
|
|
83
|
+
/**
|
|
84
|
+
* Listerners and handling of adding/removing
|
|
85
|
+
*/
|
|
86
|
+
react.useEffect(() => {
|
|
87
|
+
if (!uTagsRef?.current)
|
|
88
|
+
return;
|
|
89
|
+
const handleItemsChange = (e) => {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
const item = e.detail.item;
|
|
92
|
+
if (e.detail.action === 'add') {
|
|
93
|
+
/**
|
|
94
|
+
* If creating is off, check if the value is allowed to be added
|
|
95
|
+
*/
|
|
96
|
+
if (!allowCreate) {
|
|
97
|
+
const optionExists = Array.from(inputRef.current?.list?.options || [], uDatalist.getDatalistValue).includes(item.value);
|
|
98
|
+
if (!optionExists)
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
setSelectedItems((prevItems) => ({
|
|
102
|
+
...prevItems,
|
|
103
|
+
[item.value]: item,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
if (e.detail.action === 'remove') {
|
|
107
|
+
setSelectedItems((prevItems) => {
|
|
108
|
+
const { [item.value]: _, ...rest } = prevItems;
|
|
109
|
+
return rest;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (isControlled)
|
|
113
|
+
setControlledDirty(true);
|
|
114
|
+
};
|
|
115
|
+
uTagsRef.current.addEventListener('tags', handleItemsChange);
|
|
116
|
+
return () => {
|
|
117
|
+
uTagsRef.current?.removeEventListener('tags', handleItemsChange);
|
|
118
|
+
};
|
|
119
|
+
}, [uTagsRef, setSelectedItems]);
|
|
120
|
+
/**
|
|
121
|
+
* When controlled, trigger onValueChange callback for ordinary add/remove
|
|
122
|
+
*/
|
|
123
|
+
react.useEffect(() => {
|
|
124
|
+
if (!controlledDirty)
|
|
125
|
+
return;
|
|
126
|
+
onValueChange?.(Object.keys(selectedItems));
|
|
127
|
+
setControlledDirty(false);
|
|
128
|
+
}, [controlledDirty]);
|
|
129
|
+
const handleFilter = react.useCallback((input) => {
|
|
130
|
+
const list = input?.list;
|
|
131
|
+
// Let <datalist> handle filtering if filter is true
|
|
132
|
+
if (filter === true || !list)
|
|
133
|
+
return;
|
|
134
|
+
// Handle custom filter
|
|
135
|
+
if (filter !== false) {
|
|
136
|
+
let index = 0;
|
|
137
|
+
for (const option of list.getElementsByTagName('u-option')) {
|
|
138
|
+
if (!option.hasAttribute('data-empty'))
|
|
139
|
+
option.disabled = !filter({
|
|
140
|
+
index: index++, // Increment index for each <option>
|
|
141
|
+
input,
|
|
142
|
+
optionElement: option,
|
|
143
|
+
text: option.text,
|
|
144
|
+
value: uDatalist.getDatalistValue(option),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
uDatalist.syncDatalistState(input); // Sync the datalist state if filter is custom or false
|
|
149
|
+
}, [filter]);
|
|
150
|
+
return (jsxRuntime.jsxs(MultiSuggestionContext.Provider, { value: {
|
|
151
|
+
inputRef,
|
|
152
|
+
listId,
|
|
153
|
+
selectedItems,
|
|
154
|
+
setListId,
|
|
155
|
+
handleFilter,
|
|
156
|
+
}, children: [jsxRuntime.jsx("u-tags", { class: cl('ds-multi-suggestion', className), ref: mergedRefs, ...rest }), name && (jsxRuntime.jsx("select", { multiple: true, hidden: true, name: name, children: Object.values(selectedItems).map((item) => (jsxRuntime.jsx("option", { value: item.value }, item.value))) }))] }));
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
exports.MultiSuggestion = MultiSuggestion;
|
|
160
|
+
exports.MultiSuggestionContext = MultiSuggestionContext;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var index = require('../Chip/index.js');
|
|
7
|
+
var MultiSuggestion = require('./MultiSuggestion.js');
|
|
8
|
+
|
|
9
|
+
const MultiSuggestionChips = ({ render = ({ value }) => value, }) => {
|
|
10
|
+
const { selectedItems } = react.useContext(MultiSuggestion.MultiSuggestionContext);
|
|
11
|
+
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: selectedItems &&
|
|
12
|
+
Object.values(selectedItems).map((item) => (jsxRuntime.jsx(index.Chip.Removable, { value: item.value, asChild: true, children: jsxRuntime.jsx("data", { children: render({
|
|
13
|
+
text: item.textContent || item.value,
|
|
14
|
+
value: item.value,
|
|
15
|
+
element: item,
|
|
16
|
+
}) }) }, item.value))) }));
|
|
17
|
+
};
|
|
18
|
+
MultiSuggestionChips.displayName = 'MultiSuggestionChips';
|
|
19
|
+
|
|
20
|
+
exports.MultiSuggestionChips = MultiSuggestionChips;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
var MultiSuggestion = require('./MultiSuggestion.js');
|
|
7
|
+
var Button = require('../Button/Button.js');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Component that provides a clear button for the MultiSuggestion input.
|
|
11
|
+
*
|
|
12
|
+
* Place as a descendant of `MultiSuggestion`
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <MultiSuggestion>
|
|
16
|
+
* <MultiSuggestion.Input />
|
|
17
|
+
* <MultiSuggestion.Clear />
|
|
18
|
+
* <MultiSuggestion.List />
|
|
19
|
+
* </MultiSuggestion>
|
|
20
|
+
*/
|
|
21
|
+
const MultiSuggestionClear = react.forwardRef(function MultiSuggestionClear({ 'aria-label': label = 'Tøm', onClick, ...rest }, ref) {
|
|
22
|
+
const { inputRef } = react.useContext(MultiSuggestion.MultiSuggestionContext); //, handleValueChange
|
|
23
|
+
const handleClear = (event) => {
|
|
24
|
+
if (!inputRef?.current)
|
|
25
|
+
throw new Error('Input is missing');
|
|
26
|
+
/* narrow type to make TS happy */
|
|
27
|
+
if (!(inputRef?.current instanceof HTMLInputElement))
|
|
28
|
+
throw new Error('Input is not an input element');
|
|
29
|
+
event.preventDefault();
|
|
30
|
+
setReactInputValue(inputRef.current, '');
|
|
31
|
+
inputRef.current.focus();
|
|
32
|
+
onClick?.(event);
|
|
33
|
+
};
|
|
34
|
+
return (jsxRuntime.jsx(Button.Button, { ref: ref, variant: 'tertiary', type: 'reset', "aria-label": label, onClick: handleClear, icon: true, ...rest }));
|
|
35
|
+
});
|
|
36
|
+
// Copied from https://github.com/facebook/react/issues/11488#issuecomment-1300987446
|
|
37
|
+
const setReactInputValue = (input, value) => {
|
|
38
|
+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
|
|
39
|
+
if (nativeInputValueSetter) {
|
|
40
|
+
nativeInputValueSetter.call(input, value);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
throw new Error('Unable to find the native input value setter');
|
|
44
|
+
}
|
|
45
|
+
const inputEvent = new Event('input', { bubbles: true });
|
|
46
|
+
const changeEvent = new Event('change', { bubbles: true });
|
|
47
|
+
input.dispatchEvent(inputEvent);
|
|
48
|
+
input.dispatchEvent(changeEvent);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
exports.MultiSuggestionClear = MultiSuggestionClear;
|
|
52
|
+
exports.setReactInputValue = setReactInputValue;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Component that provides an empty MultiSuggestion list.
|
|
9
|
+
*
|
|
10
|
+
* Place as a descendant of `MultiSuggestion.List`
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <MultiSuggestion.List>
|
|
14
|
+
* <MultiSuggestion.Empty>Tomt</MultiSuggestion.Empty>
|
|
15
|
+
* </MultiSuggestion.List>
|
|
16
|
+
*/
|
|
17
|
+
const MultiSuggestionEmpty = react.forwardRef(function MultiSuggestionEmpty(rest, ref) {
|
|
18
|
+
return (
|
|
19
|
+
// biome-ignore lint/a11y/noInteractiveElementToNoninteractiveRole: Empty option shoult not be interactive
|
|
20
|
+
jsxRuntime.jsx("u-option", { "data-empty": true, role: 'none', ref: ref, ...rest }));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
exports.MultiSuggestionEmpty = MultiSuggestionEmpty;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react$1 = require('@floating-ui/react');
|
|
6
|
+
var uDatalist = require('@u-elements/u-datalist');
|
|
7
|
+
var react = require('react');
|
|
8
|
+
var MultiSuggestion = require('./MultiSuggestion.js');
|
|
9
|
+
var Input = require('../Input/Input.js');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Component that provides an input field for the MultiSuggestion list.
|
|
13
|
+
*
|
|
14
|
+
* Place as a descendant of `MultiSuggestion`
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <MultiSuggestion>
|
|
18
|
+
* <MultiSuggestion.Input />
|
|
19
|
+
* <MultiSuggestion.List />
|
|
20
|
+
* </MultiSuggestion>
|
|
21
|
+
*/
|
|
22
|
+
const MultiSuggestionInput = react.forwardRef(function MultiSuggestionList({ value, onInput, ...rest }, ref) {
|
|
23
|
+
const { listId, inputRef, handleFilter } = react.useContext(MultiSuggestion.MultiSuggestionContext);
|
|
24
|
+
const mergedRefs = react$1.useMergeRefs([inputRef, ref]);
|
|
25
|
+
// Update also if controlled value
|
|
26
|
+
react.useEffect(() => {
|
|
27
|
+
handleFilter?.(inputRef?.current);
|
|
28
|
+
}, [value]);
|
|
29
|
+
return (jsxRuntime.jsx(Input.Input, { ref: mergedRefs, list: listId, value: value, onInput: (event) => {
|
|
30
|
+
onInput?.(event); // Should run first
|
|
31
|
+
if (!uDatalist.isDatalistClick(event.nativeEvent))
|
|
32
|
+
handleFilter?.(inputRef?.current);
|
|
33
|
+
}, placeholder: '' // We need an empty placeholder for the clear button to be able to show/hide
|
|
34
|
+
, ...rest }));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
exports.MultiSuggestionInput = MultiSuggestionInput;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
require('@u-elements/u-datalist');
|
|
7
|
+
var MultiSuggestion = require('./MultiSuggestion.js');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Component that provides a MultiSuggestion list.
|
|
11
|
+
*
|
|
12
|
+
* Place as a descendant of `MultiSuggestion`
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <MultiSuggestion>
|
|
16
|
+
* <MultiSuggestion.Input />
|
|
17
|
+
* <MultiSuggestion.List />
|
|
18
|
+
* </MultiSuggestion>
|
|
19
|
+
*/
|
|
20
|
+
const MultiSuggestionList = react.forwardRef(function MultiSuggestionList({ singular = '%d forslag', plural = '%d forslag', className, id, ...rest }, ref) {
|
|
21
|
+
const { inputRef, listId, setListId, handleFilter } = react.useContext(MultiSuggestion.MultiSuggestionContext);
|
|
22
|
+
react.useEffect(() => handleFilter?.(inputRef?.current)); // Must run on every render
|
|
23
|
+
react.useEffect(() => {
|
|
24
|
+
if (id && listId !== id)
|
|
25
|
+
setListId?.(id);
|
|
26
|
+
}, [listId, id, setListId]);
|
|
27
|
+
return (jsxRuntime.jsx("u-datalist", { "data-sr-singular": singular, "data-sr-plural": plural, class: className, id: listId, ref: ref, ...rest }));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
exports.MultiSuggestionList = MultiSuggestionList;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
require('@u-elements/u-datalist');
|
|
7
|
+
|
|
8
|
+
const MultiSuggestionOption = react.forwardRef(function MultiSuggestionOption({ className, ...rest }, ref) {
|
|
9
|
+
return (jsxRuntime.jsx("u-option", { class: className, ref: ref, ...rest }));
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
exports.MultiSuggestionOption = MultiSuggestionOption;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var MultiSuggestion$1 = require('./MultiSuggestion.js');
|
|
5
|
+
var MultiSuggestionChips = require('./MultiSuggestionChips.js');
|
|
6
|
+
var MultiSuggestionClear = require('./MultiSuggestionClear.js');
|
|
7
|
+
var MultiSuggestionEmpty = require('./MultiSuggestionEmpty.js');
|
|
8
|
+
var MultiSuggestionInput = require('./MultiSuggestionInput.js');
|
|
9
|
+
var MultiSuggestionList = require('./MultiSuggestionList.js');
|
|
10
|
+
var MultiSuggestionOption = require('./MultiSuggestionOption.js');
|
|
11
|
+
|
|
12
|
+
const MultiSuggestion = Object.assign(MultiSuggestion$1.MultiSuggestion, {
|
|
13
|
+
Input: MultiSuggestionInput.MultiSuggestionInput,
|
|
14
|
+
List: MultiSuggestionList.MultiSuggestionList,
|
|
15
|
+
Option: MultiSuggestionOption.MultiSuggestionOption,
|
|
16
|
+
Chips: MultiSuggestionChips.MultiSuggestionChips,
|
|
17
|
+
Empty: MultiSuggestionEmpty.MultiSuggestionEmpty,
|
|
18
|
+
Clear: MultiSuggestionClear.MultiSuggestionClear,
|
|
19
|
+
});
|
|
20
|
+
MultiSuggestion.displayName = 'EXPERIMENTRAL_MultiSuggestion';
|
|
21
|
+
MultiSuggestion.Input.displayName = 'EXPERIMENTRAL_MultiSuggestion.Input';
|
|
22
|
+
MultiSuggestion.List.displayName = 'EXPERIMENTRAL_MultiSuggestion.List';
|
|
23
|
+
MultiSuggestion.Option.displayName = 'EXPERIMENTRAL_MultiSuggestion.Option';
|
|
24
|
+
MultiSuggestion.Chips.displayName = 'EXPERIMENTRAL_MultiSuggestion.Chips';
|
|
25
|
+
MultiSuggestion.Empty.displayName = 'EXPERIMENTRAL_MultiSuggestion.Empty';
|
|
26
|
+
MultiSuggestion.Clear.displayName = 'EXPERIMENTRAL_MultiSuggestion.Clear';
|
|
27
|
+
|
|
28
|
+
exports.EXPERIMENTAL_MultiSuggestionChips = MultiSuggestionChips.MultiSuggestionChips;
|
|
29
|
+
exports.EXPERIMENTAL_MultiSuggestionClear = MultiSuggestionClear.MultiSuggestionClear;
|
|
30
|
+
exports.EXPERIMENTAL_MultiSuggestionEmpty = MultiSuggestionEmpty.MultiSuggestionEmpty;
|
|
31
|
+
exports.EXPERIMENTAL_MultiSuggestionInput = MultiSuggestionInput.MultiSuggestionInput;
|
|
32
|
+
exports.EXPERIMENTAL_MultiSuggestionList = MultiSuggestionList.MultiSuggestionList;
|
|
33
|
+
exports.EXPERIMENTAL_MultiSuggestionOption = MultiSuggestionOption.MultiSuggestionOption;
|
|
34
|
+
exports.EXPERIMENTAL_MultiSuggestion = MultiSuggestion;
|
package/dist/cjs/index.js
CHANGED
|
@@ -96,6 +96,13 @@ var SuggestionInput = require('./components/Suggestion/SuggestionInput.js');
|
|
|
96
96
|
var SuggestionEmpty = require('./components/Suggestion/SuggestionEmpty.js');
|
|
97
97
|
var SuggestionOption = require('./components/Suggestion/SuggestionOption.js');
|
|
98
98
|
var SuggestionClear = require('./components/Suggestion/SuggestionClear.js');
|
|
99
|
+
var index$k = require('./components/MultiSuggestion/index.js');
|
|
100
|
+
var MultiSuggestionInput = require('./components/MultiSuggestion/MultiSuggestionInput.js');
|
|
101
|
+
var MultiSuggestionList = require('./components/MultiSuggestion/MultiSuggestionList.js');
|
|
102
|
+
var MultiSuggestionOption = require('./components/MultiSuggestion/MultiSuggestionOption.js');
|
|
103
|
+
var MultiSuggestionChips = require('./components/MultiSuggestion/MultiSuggestionChips.js');
|
|
104
|
+
var MultiSuggestionEmpty = require('./components/MultiSuggestion/MultiSuggestionEmpty.js');
|
|
105
|
+
var MultiSuggestionClear = require('./components/MultiSuggestion/MultiSuggestionClear.js');
|
|
99
106
|
var omit = require('./utilities/omit/omit.js');
|
|
100
107
|
var useCheckboxGroup = require('./utilities/hooks/useCheckboxGroup/useCheckboxGroup.js');
|
|
101
108
|
var useDebounceCallback = require('./utilities/hooks/useDebounceCallback/useDebounceCallback.js');
|
|
@@ -210,6 +217,13 @@ exports.EXPERIMENTAL_SuggestionInput = SuggestionInput.SuggestionInput;
|
|
|
210
217
|
exports.EXPERIMENTAL_SuggestionEmpty = SuggestionEmpty.SuggestionEmpty;
|
|
211
218
|
exports.EXPERIMENTAL_SuggestionOption = SuggestionOption.SuggestionOption;
|
|
212
219
|
exports.EXPERIMENTAL_SuggestionClear = SuggestionClear.SuggestionClear;
|
|
220
|
+
exports.EXPERIMENTAL_MultiSuggestion = index$k.EXPERIMENTAL_MultiSuggestion;
|
|
221
|
+
exports.EXPERIMENTAL_MultiSuggestionInput = MultiSuggestionInput.MultiSuggestionInput;
|
|
222
|
+
exports.EXPERIMENTAL_MultiSuggestionList = MultiSuggestionList.MultiSuggestionList;
|
|
223
|
+
exports.EXPERIMENTAL_MultiSuggestionOption = MultiSuggestionOption.MultiSuggestionOption;
|
|
224
|
+
exports.EXPERIMENTAL_MultiSuggestionChips = MultiSuggestionChips.MultiSuggestionChips;
|
|
225
|
+
exports.EXPERIMENTAL_MultiSuggestionEmpty = MultiSuggestionEmpty.MultiSuggestionEmpty;
|
|
226
|
+
exports.EXPERIMENTAL_MultiSuggestionClear = MultiSuggestionClear.MultiSuggestionClear;
|
|
213
227
|
exports.omit = omit.omit;
|
|
214
228
|
exports.useCheckboxGroup = useCheckboxGroup.useCheckboxGroup;
|
|
215
229
|
exports.useDebounceCallback = useDebounceCallback.useDebounceCallback;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var react$1 = require('@floating-ui/react');
|
|
5
4
|
var react = require('react');
|
|
6
5
|
|
|
7
6
|
const toggleIndeterminate = (getIndeterminateInputs, getInputs) => {
|
|
@@ -20,8 +19,12 @@ function useCheckboxGroup(props) {
|
|
|
20
19
|
const errorId = react.useId();
|
|
21
20
|
const checkboxRefs = react.useRef(new Set());
|
|
22
21
|
const indeterminateRefs = react.useRef(new Set());
|
|
22
|
+
const inputRefs = react.useRef(new Map());
|
|
23
23
|
const getInputs = (checked) => Array.from(checkboxRefs.current.values()).filter((input) => input.checked === checked);
|
|
24
24
|
const getIndeterminateInputs = () => Array.from(indeterminateRefs.current.values());
|
|
25
|
+
react.useEffect(() => {
|
|
26
|
+
toggleIndeterminate(getIndeterminateInputs, getInputs);
|
|
27
|
+
}, [groupValue]);
|
|
25
28
|
return {
|
|
26
29
|
/**
|
|
27
30
|
* Current value of the group.
|
|
@@ -47,44 +50,49 @@ function useCheckboxGroup(props) {
|
|
|
47
50
|
const props = typeof propsOrValue === 'string'
|
|
48
51
|
? { value: propsOrValue }
|
|
49
52
|
: propsOrValue || {};
|
|
50
|
-
const { allowIndeterminate = false, ref = undefined, value = '', ...rest } = props;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
+
const { allowIndeterminate = false, ref: forwardedRef = undefined, value = '', ...rest } = props;
|
|
54
|
+
const handleRef = (element) => {
|
|
55
|
+
if (element) {
|
|
56
|
+
const refs = allowIndeterminate ? indeterminateRefs : checkboxRefs;
|
|
57
|
+
refs.current.add(element);
|
|
58
|
+
inputRefs.current.set(value, element);
|
|
59
|
+
if (getIndeterminateInputs().length) {
|
|
60
|
+
toggleIndeterminate(getIndeterminateInputs, getInputs);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const oldElement = inputRefs.current.get(value);
|
|
65
|
+
if (oldElement) {
|
|
66
|
+
checkboxRefs.current.delete(oldElement);
|
|
67
|
+
indeterminateRefs.current.delete(oldElement);
|
|
68
|
+
inputRefs.current.delete(value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (forwardedRef) {
|
|
72
|
+
if (typeof forwardedRef === 'function') {
|
|
73
|
+
forwardedRef(element);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
forwardedRef.current = element;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
53
80
|
const handleChange = () => {
|
|
54
81
|
const nextGroupValue = Array.from(getInputs(true), ({ value }) => value);
|
|
55
82
|
setGroupValue(nextGroupValue);
|
|
56
83
|
onChange?.(nextGroupValue, groupValue);
|
|
57
84
|
};
|
|
58
85
|
const indeterminateChange = () => {
|
|
59
|
-
|
|
86
|
+
const element = inputRefs.current.get(value);
|
|
87
|
+
if (!element)
|
|
60
88
|
return;
|
|
61
|
-
const checked = !!
|
|
89
|
+
const checked = !!element.checked;
|
|
62
90
|
for (const input of getInputs(!checked)) {
|
|
63
|
-
/* We use click to send both event and change checked state */
|
|
64
91
|
input.click();
|
|
65
92
|
}
|
|
66
93
|
};
|
|
67
|
-
react.useEffect(() => {
|
|
68
|
-
if (!allowIndeterminate)
|
|
69
|
-
return;
|
|
70
|
-
toggleIndeterminate(getIndeterminateInputs, getInputs);
|
|
71
|
-
}, [groupValue]);
|
|
72
|
-
react.useEffect(() => {
|
|
73
|
-
if (!inputRef.current)
|
|
74
|
-
return;
|
|
75
|
-
const input = inputRef.current;
|
|
76
|
-
const refs = allowIndeterminate ? indeterminateRefs : checkboxRefs;
|
|
77
|
-
refs.current.add(input);
|
|
78
|
-
if (getIndeterminateInputs().length)
|
|
79
|
-
toggleIndeterminate(getIndeterminateInputs, getInputs);
|
|
80
|
-
return () => {
|
|
81
|
-
refs.current.delete(input);
|
|
82
|
-
};
|
|
83
|
-
}, [value]);
|
|
84
94
|
return {
|
|
85
|
-
/* Spread anything the user has set first */
|
|
86
95
|
...rest,
|
|
87
|
-
/* Concat ours with the user prop */
|
|
88
96
|
'aria-describedby': `${error ? errorId : ''} ${rest['aria-describedby'] || ''}`.trim() ||
|
|
89
97
|
undefined,
|
|
90
98
|
'aria-invalid': !!error || rest['aria-invalid'],
|
|
@@ -97,7 +105,7 @@ function useCheckboxGroup(props) {
|
|
|
97
105
|
allowIndeterminate && indeterminateChange();
|
|
98
106
|
handleChange();
|
|
99
107
|
},
|
|
100
|
-
ref:
|
|
108
|
+
ref: handleRef,
|
|
101
109
|
value,
|
|
102
110
|
disabled: disabled || rest.disabled,
|
|
103
111
|
readOnly: readOnly || rest.readOnly,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var react$1 = require('@floating-ui/react');
|
|
5
4
|
var react = require('react');
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -43,34 +42,38 @@ function useRadioGroup({ error, readOnly, required, disabled, name, onChange, va
|
|
|
43
42
|
const props = typeof propsOrValue === 'string'
|
|
44
43
|
? { value: propsOrValue }
|
|
45
44
|
: propsOrValue;
|
|
46
|
-
const { ref = undefined, value = '', ...rest } = props;
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
const { ref: forwardedRef = undefined, value = '', ...rest } = props;
|
|
46
|
+
const handleRef = (element) => {
|
|
47
|
+
if (element) {
|
|
48
|
+
// Set initial checked state
|
|
49
|
+
element.checked = value === groupValue;
|
|
50
|
+
}
|
|
51
|
+
// Handle forwarded ref
|
|
52
|
+
if (forwardedRef) {
|
|
53
|
+
if (typeof forwardedRef === 'function') {
|
|
54
|
+
forwardedRef(element);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
forwardedRef.current = element;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const handleChange = (e) => {
|
|
62
|
+
if (e.target.name === radioGroupName) {
|
|
53
63
|
setGroupValue((prevValue) => {
|
|
54
|
-
onChange?.(
|
|
55
|
-
return
|
|
64
|
+
onChange?.(e.target.value, prevValue);
|
|
65
|
+
return e.target.value;
|
|
56
66
|
});
|
|
57
67
|
}
|
|
58
68
|
};
|
|
59
|
-
react.useEffect(() => {
|
|
60
|
-
if (!localRef.current)
|
|
61
|
-
return;
|
|
62
|
-
localRef.current.checked = value === groupValue;
|
|
63
|
-
}, [groupValue, value]);
|
|
64
69
|
return {
|
|
65
|
-
/* Spread anything the user has set first */
|
|
66
70
|
...rest,
|
|
67
|
-
/* Concat ours with the user prop */
|
|
68
71
|
name: radioGroupName,
|
|
69
72
|
'aria-describedby': `${error ? errorId : ''} ${rest['aria-describedby'] || ''}`.trim() ||
|
|
70
73
|
undefined,
|
|
71
74
|
'aria-invalid': !!error || rest['aria-invalid'],
|
|
72
75
|
value,
|
|
73
|
-
ref:
|
|
76
|
+
ref: handleRef,
|
|
74
77
|
required: required || rest.required,
|
|
75
78
|
readOnly: readOnly || rest.readOnly,
|
|
76
79
|
disabled: disabled || rest.disabled,
|
|
@@ -78,7 +81,7 @@ function useRadioGroup({ error, readOnly, required, disabled, name, onChange, va
|
|
|
78
81
|
rest.onChange?.(e);
|
|
79
82
|
if (e.defaultPrevented)
|
|
80
83
|
return;
|
|
81
|
-
handleChange();
|
|
84
|
+
handleChange(e);
|
|
82
85
|
},
|
|
83
86
|
};
|
|
84
87
|
},
|