@lumx/react 4.3.2-alpha.10 → 4.3.2-alpha.11
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/Tooltip-sXtC5rw3.d.ts +873 -0
- package/_internal/{BcRzrT9Y.js → BCgo9dYV.js} +332 -7
- package/_internal/BCgo9dYV.js.map +1 -0
- package/index.d.ts +88 -816
- package/index.js +58 -383
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/utils/index.d.ts +35 -1
- package/utils/index.js +2 -2
- package/_internal/BcRzrT9Y.js.map +0 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import React__default, { useContext,
|
|
1
|
+
import React__default, { useContext, useMemo, createContext, useEffect, useRef } from 'react';
|
|
2
2
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import isEmpty from 'lodash/isEmpty';
|
|
4
4
|
import { join, visuallyHidden } from '@lumx/core/js/utils/classNames';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
6
|
import noop from 'lodash/noop';
|
|
7
|
+
import uniqueId from 'lodash/uniqueId';
|
|
7
8
|
import findLast from 'lodash/findLast';
|
|
8
9
|
import find from 'lodash/find';
|
|
9
10
|
import findLastIndex from 'lodash/findLastIndex';
|
|
@@ -34,6 +35,40 @@ function useDisabledStateContext() {
|
|
|
34
35
|
return useContext(DisabledStateContext);
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
/** Context to store the refs of the combobox elements */
|
|
39
|
+
const ComboboxRefsContext = /*#__PURE__*/createContext({
|
|
40
|
+
triggerRef: {
|
|
41
|
+
current: null
|
|
42
|
+
},
|
|
43
|
+
anchorRef: {
|
|
44
|
+
current: null
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
/** Provider to store the required refs for the Combobox */
|
|
48
|
+
const ComboboxRefsProvider = ({
|
|
49
|
+
triggerRef,
|
|
50
|
+
anchorRef,
|
|
51
|
+
children
|
|
52
|
+
}) => {
|
|
53
|
+
const value = useMemo(() => ({
|
|
54
|
+
triggerRef,
|
|
55
|
+
anchorRef
|
|
56
|
+
}), [triggerRef, anchorRef]);
|
|
57
|
+
return /*#__PURE__*/jsx(ComboboxRefsContext.Provider, {
|
|
58
|
+
value: value,
|
|
59
|
+
children: children
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Retrieves the combobox elements references from context */
|
|
64
|
+
const useComboboxRefs = () => {
|
|
65
|
+
const refs = useContext(ComboboxRefsContext);
|
|
66
|
+
if (!refs) {
|
|
67
|
+
throw new Error('The useComboboxRefs hook must be called within a ComboboxRefsProvider');
|
|
68
|
+
}
|
|
69
|
+
return refs;
|
|
70
|
+
};
|
|
71
|
+
|
|
37
72
|
const EVENT_TYPES = ['mousedown', 'touchstart'];
|
|
38
73
|
function isClickAway(targets, refs) {
|
|
39
74
|
// The targets elements are not contained in any of the listed element references.
|
|
@@ -1234,7 +1269,7 @@ const OPTIONS_UPDATED = (state, action) => {
|
|
|
1234
1269
|
};
|
|
1235
1270
|
|
|
1236
1271
|
/** Reducers for each action type: */
|
|
1237
|
-
const REDUCERS = {
|
|
1272
|
+
const REDUCERS$1 = {
|
|
1238
1273
|
REGISTER_TAB_STOP,
|
|
1239
1274
|
UNREGISTER_TAB_STOP,
|
|
1240
1275
|
UPDATE_TAB_STOP,
|
|
@@ -1246,8 +1281,8 @@ const REDUCERS = {
|
|
|
1246
1281
|
};
|
|
1247
1282
|
|
|
1248
1283
|
/** Main reducer */
|
|
1249
|
-
const reducer = (state, action) => {
|
|
1250
|
-
return REDUCERS[action.type]?.(state, action) || state;
|
|
1284
|
+
const reducer$1 = (state, action) => {
|
|
1285
|
+
return REDUCERS$1[action.type]?.(state, action) || state;
|
|
1251
1286
|
};
|
|
1252
1287
|
|
|
1253
1288
|
const MovingFocusContext = /*#__PURE__*/React__default.createContext({
|
|
@@ -1262,7 +1297,7 @@ const MovingFocusProvider = ({
|
|
|
1262
1297
|
children,
|
|
1263
1298
|
options
|
|
1264
1299
|
}) => {
|
|
1265
|
-
const [state, dispatch] = React__default.useReducer(reducer, INITIAL_STATE, st => ({
|
|
1300
|
+
const [state, dispatch] = React__default.useReducer(reducer$1, INITIAL_STATE, st => ({
|
|
1266
1301
|
...st,
|
|
1267
1302
|
...options,
|
|
1268
1303
|
direction: options?.direction || st.direction,
|
|
@@ -1476,5 +1511,295 @@ const useVirtualFocusParent = ref => {
|
|
|
1476
1511
|
return focused;
|
|
1477
1512
|
};
|
|
1478
1513
|
|
|
1479
|
-
|
|
1480
|
-
|
|
1514
|
+
/** Generate the combobox option id from the combobox id and the given id */
|
|
1515
|
+
const generateOptionId = (comboboxId, optionId) => `${comboboxId}-option-${optionId}`;
|
|
1516
|
+
|
|
1517
|
+
/** Verifies that the combobox registered option is an action */
|
|
1518
|
+
const isComboboxAction = option => Boolean(option?.isAction);
|
|
1519
|
+
|
|
1520
|
+
/** Verifies that the combobox registered option is the option's value */
|
|
1521
|
+
const isComboboxValue = option => {
|
|
1522
|
+
return !isComboboxAction(option);
|
|
1523
|
+
};
|
|
1524
|
+
|
|
1525
|
+
const comboboxId = `combobox-${uniqueId()}`;
|
|
1526
|
+
const initialState = {
|
|
1527
|
+
comboboxId,
|
|
1528
|
+
listboxId: `${comboboxId}-popover`,
|
|
1529
|
+
status: 'idle',
|
|
1530
|
+
isOpen: false,
|
|
1531
|
+
inputValue: '',
|
|
1532
|
+
showAll: true,
|
|
1533
|
+
options: {},
|
|
1534
|
+
type: 'listbox',
|
|
1535
|
+
optionsLength: 0
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
/** Actions when the combobox opens. */
|
|
1539
|
+
const OPEN_COMBOBOX = (state, action) => {
|
|
1540
|
+
const {
|
|
1541
|
+
manual
|
|
1542
|
+
} = action.payload || {};
|
|
1543
|
+
// If the combobox was manually opened, show all suggestions
|
|
1544
|
+
return {
|
|
1545
|
+
...state,
|
|
1546
|
+
showAll: Boolean(manual),
|
|
1547
|
+
isOpen: true
|
|
1548
|
+
};
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
/** Actions when the combobox closes */
|
|
1552
|
+
const CLOSE_COMBOBOX = state => {
|
|
1553
|
+
return {
|
|
1554
|
+
...state,
|
|
1555
|
+
showAll: true,
|
|
1556
|
+
isOpen: false
|
|
1557
|
+
};
|
|
1558
|
+
};
|
|
1559
|
+
|
|
1560
|
+
/** Actions on input update. */
|
|
1561
|
+
const SET_INPUT_VALUE = (state, action) => {
|
|
1562
|
+
return {
|
|
1563
|
+
...state,
|
|
1564
|
+
inputValue: action.payload,
|
|
1565
|
+
// When the user is changing the value, show only values that are related to the input value.
|
|
1566
|
+
showAll: false,
|
|
1567
|
+
isOpen: true
|
|
1568
|
+
};
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
/** Register an option to the state */
|
|
1572
|
+
const ADD_OPTION = (state, action) => {
|
|
1573
|
+
const {
|
|
1574
|
+
id,
|
|
1575
|
+
option
|
|
1576
|
+
} = action.payload;
|
|
1577
|
+
const {
|
|
1578
|
+
options
|
|
1579
|
+
} = state;
|
|
1580
|
+
if (options[id]) {
|
|
1581
|
+
// Option already exists, return state unchanged
|
|
1582
|
+
return state;
|
|
1583
|
+
}
|
|
1584
|
+
const newOptions = {
|
|
1585
|
+
...options,
|
|
1586
|
+
[id]: option
|
|
1587
|
+
};
|
|
1588
|
+
let newType = state.type;
|
|
1589
|
+
if (isComboboxAction(option)) {
|
|
1590
|
+
newType = 'grid';
|
|
1591
|
+
}
|
|
1592
|
+
let newOptionsLength = state.optionsLength;
|
|
1593
|
+
if (isComboboxValue(option)) {
|
|
1594
|
+
newOptionsLength += 1;
|
|
1595
|
+
}
|
|
1596
|
+
return {
|
|
1597
|
+
...state,
|
|
1598
|
+
options: newOptions,
|
|
1599
|
+
type: newType,
|
|
1600
|
+
optionsLength: newOptionsLength
|
|
1601
|
+
};
|
|
1602
|
+
};
|
|
1603
|
+
|
|
1604
|
+
/** Remove an option from the state */
|
|
1605
|
+
const REMOVE_OPTION = (state, action) => {
|
|
1606
|
+
const {
|
|
1607
|
+
id
|
|
1608
|
+
} = action.payload;
|
|
1609
|
+
const {
|
|
1610
|
+
options
|
|
1611
|
+
} = state;
|
|
1612
|
+
const option = options[id];
|
|
1613
|
+
if (!options[id]) {
|
|
1614
|
+
// Option doesn't exist, return state unchanged
|
|
1615
|
+
return state;
|
|
1616
|
+
}
|
|
1617
|
+
const newOptions = {
|
|
1618
|
+
...options
|
|
1619
|
+
};
|
|
1620
|
+
delete newOptions[id];
|
|
1621
|
+
let newOptionsLength = state.optionsLength;
|
|
1622
|
+
if (isComboboxValue(option)) {
|
|
1623
|
+
newOptionsLength -= 1;
|
|
1624
|
+
}
|
|
1625
|
+
return {
|
|
1626
|
+
...state,
|
|
1627
|
+
options: newOptions,
|
|
1628
|
+
optionsLength: newOptionsLength
|
|
1629
|
+
};
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1632
|
+
/** Reducers for each action type: */
|
|
1633
|
+
const REDUCERS = {
|
|
1634
|
+
OPEN_COMBOBOX,
|
|
1635
|
+
CLOSE_COMBOBOX,
|
|
1636
|
+
SET_INPUT_VALUE,
|
|
1637
|
+
ADD_OPTION,
|
|
1638
|
+
REMOVE_OPTION
|
|
1639
|
+
};
|
|
1640
|
+
|
|
1641
|
+
/** Main reducer */
|
|
1642
|
+
const reducer = (state, action) => {
|
|
1643
|
+
return REDUCERS[action.type]?.(state, action) || state;
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1646
|
+
/** Dispatch for the combobox component */
|
|
1647
|
+
|
|
1648
|
+
/** Context for the Combobox component */
|
|
1649
|
+
const ComboboxContext = /*#__PURE__*/React__default.createContext({
|
|
1650
|
+
...initialState,
|
|
1651
|
+
openOnFocus: false,
|
|
1652
|
+
openOnClick: false,
|
|
1653
|
+
selectionType: 'single',
|
|
1654
|
+
optionsLength: 0,
|
|
1655
|
+
onSelect: noop,
|
|
1656
|
+
onInputChange: noop,
|
|
1657
|
+
onOpen: noop,
|
|
1658
|
+
dispatch: noop,
|
|
1659
|
+
translations: {
|
|
1660
|
+
clearLabel: '',
|
|
1661
|
+
tryReloadLabel: '',
|
|
1662
|
+
showSuggestionsLabel: '',
|
|
1663
|
+
noResultsForInputLabel: input => input || '',
|
|
1664
|
+
loadingLabel: '',
|
|
1665
|
+
serviceUnavailableLabel: '',
|
|
1666
|
+
nbOptionsLabel: options => `${options}`
|
|
1667
|
+
}
|
|
1668
|
+
});
|
|
1669
|
+
|
|
1670
|
+
/** Context for a combobox section to store its unique id */
|
|
1671
|
+
const SectionContext = /*#__PURE__*/React__default.createContext({
|
|
1672
|
+
sectionId: ''
|
|
1673
|
+
});
|
|
1674
|
+
|
|
1675
|
+
/** Retrieve the current combobox state and actions */
|
|
1676
|
+
const useCombobox = () => {
|
|
1677
|
+
const comboboxContext = React__default.useContext(ComboboxContext);
|
|
1678
|
+
const {
|
|
1679
|
+
dispatch: movingFocusDispatch
|
|
1680
|
+
} = React__default.useContext(MovingFocusContext);
|
|
1681
|
+
const {
|
|
1682
|
+
onSelect,
|
|
1683
|
+
onInputChange,
|
|
1684
|
+
onOpen,
|
|
1685
|
+
dispatch,
|
|
1686
|
+
inputValue,
|
|
1687
|
+
...contextValues
|
|
1688
|
+
} = comboboxContext;
|
|
1689
|
+
const {
|
|
1690
|
+
triggerRef
|
|
1691
|
+
} = useComboboxRefs();
|
|
1692
|
+
|
|
1693
|
+
/** Action triggered when the listBox is closed without selecting any option */
|
|
1694
|
+
const handleClose = React__default.useCallback(() => {
|
|
1695
|
+
dispatch({
|
|
1696
|
+
type: 'CLOSE_COMBOBOX'
|
|
1697
|
+
});
|
|
1698
|
+
// Reset visual focus
|
|
1699
|
+
movingFocusDispatch({
|
|
1700
|
+
type: 'RESET_SELECTED_TAB_STOP'
|
|
1701
|
+
});
|
|
1702
|
+
}, [dispatch, movingFocusDispatch]);
|
|
1703
|
+
|
|
1704
|
+
// Handle callbacks on options mounted
|
|
1705
|
+
const [optionsMountedCallbacks, setOptionsMountedCallback] = React__default.useState();
|
|
1706
|
+
React__default.useEffect(() => {
|
|
1707
|
+
if (comboboxContext.optionsLength > 0 && optionsMountedCallbacks?.length) {
|
|
1708
|
+
const optionsArray = Object.values(comboboxContext.options);
|
|
1709
|
+
// Execute callbacks
|
|
1710
|
+
for (const callback of optionsMountedCallbacks) {
|
|
1711
|
+
callback(optionsArray);
|
|
1712
|
+
}
|
|
1713
|
+
setOptionsMountedCallback(undefined);
|
|
1714
|
+
}
|
|
1715
|
+
}, [comboboxContext.options, comboboxContext.optionsLength, optionsMountedCallbacks]);
|
|
1716
|
+
|
|
1717
|
+
/** Callback for when an option is selected */
|
|
1718
|
+
const handleSelected = React__default.useCallback((option, source) => {
|
|
1719
|
+
if (option?.isDisabled) {
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
if (isComboboxValue(option)) {
|
|
1723
|
+
/**
|
|
1724
|
+
* We only close the list if the selection type is single.
|
|
1725
|
+
* If it is multiple, we want to allow the user to continue
|
|
1726
|
+
* selecting multiple options.
|
|
1727
|
+
*/
|
|
1728
|
+
if (comboboxContext.selectionType !== 'multiple') {
|
|
1729
|
+
handleClose();
|
|
1730
|
+
}
|
|
1731
|
+
/** Call parent onSelect callback */
|
|
1732
|
+
if (onSelect) {
|
|
1733
|
+
onSelect(option);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
/** If the option itself has a custom action, also call it */
|
|
1738
|
+
if (option?.onSelect) {
|
|
1739
|
+
option.onSelect(option, source);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
/** Reset focus on input */
|
|
1743
|
+
if (triggerRef?.current) {
|
|
1744
|
+
triggerRef.current?.focus();
|
|
1745
|
+
}
|
|
1746
|
+
}, [comboboxContext.selectionType, handleClose, onSelect, triggerRef]);
|
|
1747
|
+
|
|
1748
|
+
/** Callback for when the input must be updated */
|
|
1749
|
+
const handleInputChange = React__default.useCallback((value, ...args) => {
|
|
1750
|
+
// Update the local state
|
|
1751
|
+
dispatch({
|
|
1752
|
+
type: 'SET_INPUT_VALUE',
|
|
1753
|
+
payload: value
|
|
1754
|
+
});
|
|
1755
|
+
// If a callback if given, call it with the value
|
|
1756
|
+
if (onInputChange) {
|
|
1757
|
+
onInputChange(value, ...args);
|
|
1758
|
+
}
|
|
1759
|
+
// Reset visual focus
|
|
1760
|
+
movingFocusDispatch({
|
|
1761
|
+
type: 'RESET_SELECTED_TAB_STOP'
|
|
1762
|
+
});
|
|
1763
|
+
}, [dispatch, movingFocusDispatch, onInputChange]);
|
|
1764
|
+
|
|
1765
|
+
/**
|
|
1766
|
+
* Open the popover
|
|
1767
|
+
*
|
|
1768
|
+
* @returns a promise with the updated context once all options are mounted
|
|
1769
|
+
*/
|
|
1770
|
+
const handleOpen = React__default.useCallback(params => {
|
|
1771
|
+
/** update the local state */
|
|
1772
|
+
dispatch({
|
|
1773
|
+
type: 'OPEN_COMBOBOX',
|
|
1774
|
+
payload: params
|
|
1775
|
+
});
|
|
1776
|
+
/** If a parent callback was given, trigger it with state information */
|
|
1777
|
+
if (onOpen) {
|
|
1778
|
+
onOpen({
|
|
1779
|
+
currentValue: inputValue,
|
|
1780
|
+
manual: Boolean(params?.manual)
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
// Promise resolving options on mount
|
|
1785
|
+
return new Promise(resolve => {
|
|
1786
|
+
// Append to the list of callback on options mounted
|
|
1787
|
+
setOptionsMountedCallback((callbacks = []) => {
|
|
1788
|
+
callbacks.push(resolve);
|
|
1789
|
+
return callbacks;
|
|
1790
|
+
});
|
|
1791
|
+
});
|
|
1792
|
+
}, [dispatch, inputValue, onOpen]);
|
|
1793
|
+
return React__default.useMemo(() => ({
|
|
1794
|
+
handleClose,
|
|
1795
|
+
handleOpen,
|
|
1796
|
+
handleInputChange,
|
|
1797
|
+
handleSelected,
|
|
1798
|
+
dispatch,
|
|
1799
|
+
inputValue,
|
|
1800
|
+
...contextValues
|
|
1801
|
+
}), [contextValues, dispatch, handleClose, handleInputChange, handleOpen, handleSelected, inputValue]);
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
export { A11YLiveMessage as A, ComboboxContext as C, DisabledStateProvider as D, MovingFocusContext as M, NAV_KEYS as N, Portal as P, SectionContext as S, useVirtualFocusParent as a, useComboboxRefs as b, useCombobox as c, useVirtualFocus as d, MovingFocusProvider as e, initialState as f, generateOptionId as g, ComboboxRefsProvider as h, isComboboxValue as i, ClickAwayProvider as j, getPointerTypeFromEvent as k, PortalProvider as l, reducer as r, useDisabledStateContext as u };
|
|
1805
|
+
//# sourceMappingURL=BCgo9dYV.js.map
|