@primer/components 0.0.0-20219151326 → 0.0.0-2021915134443
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/CHANGELOG.md +27 -3
- package/codemods/deprecateUtilityComponents.js +1 -1
- package/dist/browser.esm.js +872 -767
- package/dist/browser.esm.js.map +1 -1
- package/dist/browser.umd.js +877 -772
- package/dist/browser.umd.js.map +1 -1
- package/lib/ActionList/Item.js +1 -1
- package/lib/ActionList/List.d.ts +2 -1
- package/lib/ActionList2/Item.d.ts +1 -0
- package/lib/ActionList2/Item.js +2 -2
- package/lib/AnchoredOverlay/AnchoredOverlay.d.ts +2 -1
- package/lib/AnchoredOverlay/AnchoredOverlay.js +11 -3
- package/lib/Autocomplete/Autocomplete.d.ts +304 -0
- package/lib/Autocomplete/Autocomplete.js +145 -0
- package/lib/Autocomplete/AutocompleteContext.d.ts +17 -0
- package/lib/Autocomplete/AutocompleteContext.js +11 -0
- package/lib/Autocomplete/AutocompleteInput.d.ts +292 -0
- package/lib/Autocomplete/AutocompleteInput.js +157 -0
- package/lib/Autocomplete/AutocompleteMenu.d.ts +72 -0
- package/lib/Autocomplete/AutocompleteMenu.js +224 -0
- package/lib/Autocomplete/AutocompleteOverlay.d.ts +20 -0
- package/lib/Autocomplete/AutocompleteOverlay.js +80 -0
- package/lib/Autocomplete/index.d.ts +2 -0
- package/lib/Autocomplete/index.js +15 -0
- package/lib/BaseStyles.js +1 -1
- package/lib/BorderBox.js +1 -1
- package/lib/Caret.js +2 -2
- package/lib/Dialog.js +1 -1
- package/lib/FilteredActionList/FilteredActionList.d.ts +3 -2
- package/lib/FilteredActionList/FilteredActionList.js +8 -32
- package/lib/Flash.js +16 -16
- package/lib/Label.js +1 -1
- package/lib/Overlay.d.ts +1 -0
- package/lib/Overlay.js +3 -1
- package/lib/ProgressBar.js +1 -1
- package/lib/SelectMenu/SelectMenu.d.ts +10 -10
- package/lib/SelectPanel/SelectPanel.d.ts +1 -1
- package/lib/SelectPanel/SelectPanel.js +9 -11
- package/lib/StateLabel.js +13 -19
- package/lib/TextInput.d.ts +5 -13
- package/lib/TextInput.js +4 -46
- package/lib/TextInputWithTokens.d.ts +323 -0
- package/lib/TextInputWithTokens.js +245 -0
- package/lib/Token/AvatarToken.d.ts +7 -0
- package/lib/Token/AvatarToken.js +64 -0
- package/lib/Token/IssueLabelToken.d.ts +14 -0
- package/lib/Token/IssueLabelToken.js +144 -0
- package/lib/Token/Token.d.ts +15 -0
- package/lib/Token/Token.js +94 -0
- package/lib/Token/TokenBase.d.ts +31 -0
- package/lib/Token/TokenBase.js +108 -0
- package/lib/Token/_RemoveTokenButton.d.ts +12 -0
- package/lib/Token/_RemoveTokenButton.js +77 -0
- package/lib/Token/_TokenTextContainer.d.ts +3 -0
- package/lib/Token/_TokenTextContainer.js +17 -0
- package/lib/Token/index.d.ts +3 -0
- package/lib/Token/index.js +31 -0
- package/lib/_TextInputWrapper.d.ts +10 -0
- package/lib/_TextInputWrapper.js +51 -0
- package/lib/_UnstyledTextInput.d.ts +2 -0
- package/lib/_UnstyledTextInput.js +20 -0
- package/lib/behaviors/scrollIntoViewingArea.d.ts +1 -0
- package/lib/behaviors/scrollIntoViewingArea.js +39 -0
- package/lib/hooks/useOpenAndCloseFocus.d.ts +2 -1
- package/lib/hooks/useOpenAndCloseFocus.js +7 -2
- package/lib/hooks/useOverlay.d.ts +2 -1
- package/lib/hooks/useOverlay.js +4 -2
- package/lib/index.d.ts +6 -0
- package/lib/index.js +44 -0
- package/lib/theme-preval.js +370 -3100
- package/lib/utils/testing.d.ts +50 -493
- package/lib/utils/{types.d.ts → types/AriaRole.d.ts} +0 -13
- package/lib/utils/{types.js → types/AriaRole.js} +0 -0
- package/lib/utils/types/ComponentProps.d.ts +9 -0
- package/lib/utils/types/ComponentProps.js +1 -0
- package/lib/utils/types/Flatten.d.ts +4 -0
- package/lib/utils/types/Flatten.js +1 -0
- package/lib/utils/types/MandateProps.d.ts +3 -0
- package/lib/utils/types/MandateProps.js +1 -0
- package/lib/utils/types/Merge.d.ts +19 -0
- package/lib/utils/types/Merge.js +1 -0
- package/lib/utils/types/index.d.ts +5 -0
- package/lib/utils/types/index.js +70 -0
- package/lib-esm/ActionList/Item.js +1 -1
- package/lib-esm/ActionList/List.d.ts +2 -1
- package/lib-esm/ActionList2/Item.d.ts +1 -0
- package/lib-esm/ActionList2/Item.js +3 -2
- package/lib-esm/AnchoredOverlay/AnchoredOverlay.d.ts +2 -1
- package/lib-esm/AnchoredOverlay/AnchoredOverlay.js +11 -3
- package/lib-esm/Autocomplete/Autocomplete.d.ts +304 -0
- package/lib-esm/Autocomplete/Autocomplete.js +123 -0
- package/lib-esm/Autocomplete/AutocompleteContext.d.ts +17 -0
- package/lib-esm/Autocomplete/AutocompleteContext.js +2 -0
- package/lib-esm/Autocomplete/AutocompleteInput.d.ts +292 -0
- package/lib-esm/Autocomplete/AutocompleteInput.js +138 -0
- package/lib-esm/Autocomplete/AutocompleteMenu.d.ts +72 -0
- package/lib-esm/Autocomplete/AutocompleteMenu.js +205 -0
- package/lib-esm/Autocomplete/AutocompleteOverlay.d.ts +20 -0
- package/lib-esm/Autocomplete/AutocompleteOverlay.js +62 -0
- package/lib-esm/Autocomplete/index.d.ts +2 -0
- package/lib-esm/Autocomplete/index.js +1 -0
- package/lib-esm/BaseStyles.js +1 -1
- package/lib-esm/BorderBox.js +1 -1
- package/lib-esm/Caret.js +2 -2
- package/lib-esm/Dialog.js +1 -1
- package/lib-esm/FilteredActionList/FilteredActionList.d.ts +3 -2
- package/lib-esm/FilteredActionList/FilteredActionList.js +6 -32
- package/lib-esm/Flash.js +16 -16
- package/lib-esm/Label.js +1 -1
- package/lib-esm/Overlay.d.ts +1 -0
- package/lib-esm/Overlay.js +3 -1
- package/lib-esm/ProgressBar.js +1 -1
- package/lib-esm/SelectMenu/SelectMenu.d.ts +10 -10
- package/lib-esm/SelectPanel/SelectPanel.d.ts +1 -1
- package/lib-esm/SelectPanel/SelectPanel.js +9 -8
- package/lib-esm/StateLabel.js +13 -19
- package/lib-esm/TextInput.d.ts +5 -13
- package/lib-esm/TextInput.js +4 -37
- package/lib-esm/TextInputWithTokens.d.ts +323 -0
- package/lib-esm/TextInputWithTokens.js +220 -0
- package/lib-esm/Token/AvatarToken.d.ts +7 -0
- package/lib-esm/Token/AvatarToken.js +43 -0
- package/lib-esm/Token/IssueLabelToken.d.ts +14 -0
- package/lib-esm/Token/IssueLabelToken.js +124 -0
- package/lib-esm/Token/Token.d.ts +15 -0
- package/lib-esm/Token/Token.js +73 -0
- package/lib-esm/Token/TokenBase.d.ts +31 -0
- package/lib-esm/Token/TokenBase.js +87 -0
- package/lib-esm/Token/_RemoveTokenButton.d.ts +12 -0
- package/lib-esm/Token/_RemoveTokenButton.js +60 -0
- package/lib-esm/Token/_TokenTextContainer.d.ts +3 -0
- package/lib-esm/Token/_TokenTextContainer.js +6 -0
- package/lib-esm/Token/index.d.ts +3 -0
- package/lib-esm/Token/index.js +3 -0
- package/lib-esm/_TextInputWrapper.d.ts +10 -0
- package/lib-esm/_TextInputWrapper.js +31 -0
- package/lib-esm/_UnstyledTextInput.d.ts +2 -0
- package/lib-esm/_UnstyledTextInput.js +7 -0
- package/lib-esm/behaviors/scrollIntoViewingArea.d.ts +1 -0
- package/lib-esm/behaviors/scrollIntoViewingArea.js +30 -0
- package/lib-esm/hooks/useOpenAndCloseFocus.d.ts +2 -1
- package/lib-esm/hooks/useOpenAndCloseFocus.js +7 -2
- package/lib-esm/hooks/useOverlay.d.ts +2 -1
- package/lib-esm/hooks/useOverlay.js +4 -2
- package/lib-esm/index.d.ts +6 -0
- package/lib-esm/index.js +4 -0
- package/lib-esm/theme-preval.js +370 -3100
- package/lib-esm/utils/testing.d.ts +50 -493
- package/lib-esm/utils/{types.d.ts → types/AriaRole.d.ts} +0 -13
- package/lib-esm/utils/{types.js → types/AriaRole.js} +0 -0
- package/lib-esm/utils/types/ComponentProps.d.ts +9 -0
- package/lib-esm/utils/types/ComponentProps.js +1 -0
- package/lib-esm/utils/types/Flatten.d.ts +4 -0
- package/lib-esm/utils/types/Flatten.js +1 -0
- package/lib-esm/utils/types/MandateProps.d.ts +3 -0
- package/lib-esm/utils/types/MandateProps.js +1 -0
- package/lib-esm/utils/types/Merge.d.ts +19 -0
- package/lib-esm/utils/types/Merge.js +1 -0
- package/lib-esm/utils/types/index.d.ts +5 -0
- package/lib-esm/utils/types/index.js +5 -0
- package/package.json +4 -3
@@ -0,0 +1,205 @@
|
|
1
|
+
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
2
|
+
import { ActionList } from '../ActionList';
|
3
|
+
import { useFocusZone } from '../hooks/useFocusZone';
|
4
|
+
import { Box, Spinner } from '../';
|
5
|
+
import { AutocompleteContext } from './AutocompleteContext';
|
6
|
+
import { PlusIcon } from '@primer/octicons-react';
|
7
|
+
import { uniqueId } from '../utils/uniqueId';
|
8
|
+
import { scrollIntoViewingArea } from '../behaviors/scrollIntoViewingArea';
|
9
|
+
|
10
|
+
const getDefaultSortFn = isItemSelectedFn => (itemIdA, itemIdB) => isItemSelectedFn(itemIdA) === isItemSelectedFn(itemIdB) ? 0 : isItemSelectedFn(itemIdA) ? -1 : 1;
|
11
|
+
|
12
|
+
function getDefaultItemFilter(filterValue) {
|
13
|
+
return function (item, _i) {
|
14
|
+
var _item$text;
|
15
|
+
|
16
|
+
return Boolean((_item$text = item.text) === null || _item$text === void 0 ? void 0 : _item$text.toLowerCase().startsWith(filterValue.toLowerCase()));
|
17
|
+
};
|
18
|
+
}
|
19
|
+
|
20
|
+
function getDefaultOnSelectionChange(setInputValueFn) {
|
21
|
+
return function (itemOrItems) {
|
22
|
+
const {
|
23
|
+
text = ''
|
24
|
+
} = Array.isArray(itemOrItems) ? itemOrItems.slice(-1)[0] : itemOrItems;
|
25
|
+
setInputValueFn(text);
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
const isItemSelected = (itemId, selectedItemIds) => selectedItemIds.includes(itemId);
|
30
|
+
|
31
|
+
function getItemById(itemId, items) {
|
32
|
+
return items.find(item => item.id === itemId);
|
33
|
+
} // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
34
|
+
|
35
|
+
|
36
|
+
function AutocompleteMenu(props) {
|
37
|
+
const autocompleteContext = useContext(AutocompleteContext);
|
38
|
+
|
39
|
+
if (autocompleteContext === null) {
|
40
|
+
throw new Error('AutocompleteContext returned null values');
|
41
|
+
}
|
42
|
+
|
43
|
+
const {
|
44
|
+
activeDescendantRef,
|
45
|
+
id,
|
46
|
+
inputRef,
|
47
|
+
inputValue = '',
|
48
|
+
scrollContainerRef,
|
49
|
+
setAutocompleteSuggestion,
|
50
|
+
setShowMenu,
|
51
|
+
setInputValue,
|
52
|
+
setIsMenuDirectlyActivated,
|
53
|
+
setSelectedItemLength,
|
54
|
+
showMenu
|
55
|
+
} = autocompleteContext;
|
56
|
+
const {
|
57
|
+
items,
|
58
|
+
selectedItemIds,
|
59
|
+
sortOnCloseFn,
|
60
|
+
emptyStateText,
|
61
|
+
addNewItem,
|
62
|
+
loading,
|
63
|
+
selectionVariant,
|
64
|
+
filterFn,
|
65
|
+
'aria-labelledby': ariaLabelledBy,
|
66
|
+
onOpenChange,
|
67
|
+
onSelectedChange,
|
68
|
+
customScrollContainerRef
|
69
|
+
} = props;
|
70
|
+
const listContainerRef = useRef(null);
|
71
|
+
const [highlightedItem, setHighlightedItem] = useState();
|
72
|
+
const [sortedItemIds, setSortedItemIds] = useState(items.map(({
|
73
|
+
id: itemId
|
74
|
+
}) => itemId));
|
75
|
+
const selectableItems = useMemo(() => items.map(selectableItem => {
|
76
|
+
return { ...selectableItem,
|
77
|
+
role: 'option',
|
78
|
+
id: selectableItem.id,
|
79
|
+
selected: selectionVariant === 'multiple' ? selectedItemIds.includes(selectableItem.id) : undefined,
|
80
|
+
onAction: item => {
|
81
|
+
const otherSelectedItemIds = selectedItemIds.filter(selectedItemId => selectedItemId !== item.id);
|
82
|
+
const newSelectedItemIds = selectedItemIds.includes(item.id) ? otherSelectedItemIds : [...otherSelectedItemIds, item.id];
|
83
|
+
const onSelectedChangeFn = onSelectedChange ? onSelectedChange : getDefaultOnSelectionChange(setInputValue);
|
84
|
+
onSelectedChangeFn(newSelectedItemIds.map(newSelectedItemId => getItemById(newSelectedItemId, items)));
|
85
|
+
|
86
|
+
if (selectionVariant === 'multiple') {
|
87
|
+
setInputValue('');
|
88
|
+
setAutocompleteSuggestion('');
|
89
|
+
} else {
|
90
|
+
var _inputRef$current;
|
91
|
+
|
92
|
+
setShowMenu(false);
|
93
|
+
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.setSelectionRange(inputRef.current.value.length, inputRef.current.value.length);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
};
|
97
|
+
}), [items, selectedItemIds, inputRef, onSelectedChange, selectionVariant, setAutocompleteSuggestion, setInputValue, setShowMenu]);
|
98
|
+
const itemSortOrderData = useMemo(() => sortedItemIds.reduce((acc, curr, i) => {
|
99
|
+
acc[curr] = i;
|
100
|
+
return acc;
|
101
|
+
}, {}), [sortedItemIds]);
|
102
|
+
const sortedAndFilteredItemsToRender = useMemo(() => selectableItems.filter(filterFn ? filterFn : getDefaultItemFilter(inputValue)).sort((a, b) => itemSortOrderData[a.id] - itemSortOrderData[b.id]), [selectableItems, itemSortOrderData, filterFn, inputValue]);
|
103
|
+
const allItemsToRender = useMemo(() => [// sorted and filtered selectable items
|
104
|
+
...sortedAndFilteredItemsToRender, // menu item used for creating a token from whatever is in the text input
|
105
|
+
...(addNewItem ? [{ ...addNewItem,
|
106
|
+
leadingVisual: () => /*#__PURE__*/React.createElement(PlusIcon, null),
|
107
|
+
onAction: item => {
|
108
|
+
// TODO: make it possible to pass a leadingVisual when using `addNewItem`
|
109
|
+
addNewItem.handleAddItem({ ...item,
|
110
|
+
id: item.id || uniqueId(),
|
111
|
+
leadingVisual: undefined
|
112
|
+
});
|
113
|
+
|
114
|
+
if (selectionVariant === 'multiple') {
|
115
|
+
setInputValue('');
|
116
|
+
setAutocompleteSuggestion('');
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}] : [])], [sortedAndFilteredItemsToRender, addNewItem, setAutocompleteSuggestion, selectionVariant, setInputValue]);
|
120
|
+
useFocusZone({
|
121
|
+
containerRef: listContainerRef,
|
122
|
+
focusOutBehavior: 'wrap',
|
123
|
+
focusableElementFilter: element => {
|
124
|
+
return !(element instanceof HTMLInputElement);
|
125
|
+
},
|
126
|
+
activeDescendantFocus: inputRef,
|
127
|
+
onActiveDescendantChanged: (current, _previous, directlyActivated) => {
|
128
|
+
activeDescendantRef.current = current || null;
|
129
|
+
|
130
|
+
if (current) {
|
131
|
+
const selectedItem = selectableItems.find(item => item.id.toString() === current.getAttribute('data-id'));
|
132
|
+
setHighlightedItem(selectedItem);
|
133
|
+
setIsMenuDirectlyActivated(directlyActivated);
|
134
|
+
}
|
135
|
+
|
136
|
+
if (current && customScrollContainerRef && customScrollContainerRef.current && directlyActivated) {
|
137
|
+
scrollIntoViewingArea(current, customScrollContainerRef.current);
|
138
|
+
} else if (current && scrollContainerRef.current && directlyActivated) {
|
139
|
+
scrollIntoViewingArea(current, scrollContainerRef.current);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}, [loading]);
|
143
|
+
useEffect(() => {
|
144
|
+
var _highlightedItem$text;
|
145
|
+
|
146
|
+
if (highlightedItem !== null && highlightedItem !== void 0 && (_highlightedItem$text = highlightedItem.text) !== null && _highlightedItem$text !== void 0 && _highlightedItem$text.startsWith(inputValue) && !selectedItemIds.includes(highlightedItem.id)) {
|
147
|
+
setAutocompleteSuggestion(highlightedItem.text);
|
148
|
+
} else {
|
149
|
+
setAutocompleteSuggestion('');
|
150
|
+
}
|
151
|
+
}, [highlightedItem, inputValue, selectedItemIds, setAutocompleteSuggestion]);
|
152
|
+
useEffect(() => {
|
153
|
+
const itemIdSortResult = [...sortedItemIds].sort(sortOnCloseFn ? sortOnCloseFn : getDefaultSortFn(itemId => isItemSelected(itemId, selectedItemIds)));
|
154
|
+
const sortResultMatchesState = itemIdSortResult.length === sortedItemIds.length && itemIdSortResult.every((element, index) => element === sortedItemIds[index]);
|
155
|
+
|
156
|
+
if (showMenu === false && !sortResultMatchesState) {
|
157
|
+
setSortedItemIds(itemIdSortResult);
|
158
|
+
}
|
159
|
+
|
160
|
+
onOpenChange && onOpenChange(Boolean(showMenu));
|
161
|
+
}, [showMenu, onOpenChange, selectedItemIds, sortOnCloseFn, sortedItemIds]);
|
162
|
+
useEffect(() => {
|
163
|
+
if (selectedItemIds.length) {
|
164
|
+
setSelectedItemLength(selectedItemIds.length);
|
165
|
+
}
|
166
|
+
}, [selectedItemIds, setSelectedItemLength]);
|
167
|
+
return /*#__PURE__*/React.createElement(Box, {
|
168
|
+
sx: !showMenu ? {
|
169
|
+
// visually hides this label for sighted users
|
170
|
+
position: 'absolute',
|
171
|
+
width: '1px',
|
172
|
+
height: '1px',
|
173
|
+
padding: '0',
|
174
|
+
margin: '-1px',
|
175
|
+
overflow: 'hidden',
|
176
|
+
clip: 'rect(0, 0, 0, 0)',
|
177
|
+
whiteSpace: 'nowrap',
|
178
|
+
borderWidth: '0'
|
179
|
+
} : {}
|
180
|
+
}, loading ? /*#__PURE__*/React.createElement(Box, {
|
181
|
+
p: 3,
|
182
|
+
display: "flex",
|
183
|
+
justifyContent: "center"
|
184
|
+
}, /*#__PURE__*/React.createElement(Spinner, null)) : /*#__PURE__*/React.createElement("div", {
|
185
|
+
ref: listContainerRef
|
186
|
+
}, allItemsToRender.length ? /*#__PURE__*/React.createElement(ActionList, {
|
187
|
+
selectionVariant: "multiple" // have to typecast to `ItemProps` because we have an extra property
|
188
|
+
// on `items` for Autocomplete: `metadata`
|
189
|
+
,
|
190
|
+
items: allItemsToRender,
|
191
|
+
role: "listbox",
|
192
|
+
id: `${id}-listbox`,
|
193
|
+
"aria-labelledby": ariaLabelledBy
|
194
|
+
}) : /*#__PURE__*/React.createElement(Box, {
|
195
|
+
p: 3
|
196
|
+
}, emptyStateText)));
|
197
|
+
}
|
198
|
+
|
199
|
+
AutocompleteMenu.displayName = "AutocompleteMenu";
|
200
|
+
AutocompleteMenu.defaultProps = {
|
201
|
+
emptyStateText: 'No selectable options',
|
202
|
+
selectionVariant: 'single'
|
203
|
+
};
|
204
|
+
AutocompleteMenu.displayName = 'AutocompleteMenu';
|
205
|
+
export default AutocompleteMenu;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { OverlayProps } from '../Overlay';
|
3
|
+
import { ComponentProps } from '../utils/types';
|
4
|
+
declare type AutocompleteOverlayInternalProps = {
|
5
|
+
/**
|
6
|
+
* The ref of the element that the position of the menu is based on. By default, the menu is positioned based on the text input
|
7
|
+
*/
|
8
|
+
menuAnchorRef?: React.RefObject<HTMLElement>;
|
9
|
+
/**
|
10
|
+
* Props to be spread on the internal `Overlay` component.
|
11
|
+
*/
|
12
|
+
overlayProps?: Partial<OverlayProps>;
|
13
|
+
children?: React.ReactNode;
|
14
|
+
} & Pick<React.AriaAttributes, 'aria-labelledby'>;
|
15
|
+
declare function AutocompleteOverlay({ menuAnchorRef, overlayProps, children }: AutocompleteOverlayInternalProps): JSX.Element | null;
|
16
|
+
declare namespace AutocompleteOverlay {
|
17
|
+
var displayName: string;
|
18
|
+
}
|
19
|
+
export declare type AutocompleteOverlayProps = ComponentProps<typeof AutocompleteOverlay>;
|
20
|
+
export default AutocompleteOverlay;
|
@@ -0,0 +1,62 @@
|
|
1
|
+
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
2
|
+
|
3
|
+
import React, { useCallback, useContext } from 'react';
|
4
|
+
import { useAnchoredPosition } from '../hooks';
|
5
|
+
import Overlay from '../Overlay';
|
6
|
+
import { AutocompleteContext } from './AutocompleteContext';
|
7
|
+
import { useCombinedRefs } from '../hooks/useCombinedRefs';
|
8
|
+
|
9
|
+
// TODO: consider making 'aria-labelledby' required
|
10
|
+
function AutocompleteOverlay({
|
11
|
+
menuAnchorRef,
|
12
|
+
overlayProps,
|
13
|
+
children
|
14
|
+
}) {
|
15
|
+
const autocompleteContext = useContext(AutocompleteContext);
|
16
|
+
|
17
|
+
if (autocompleteContext === null) {
|
18
|
+
throw new Error('AutocompleteContext returned null values');
|
19
|
+
}
|
20
|
+
|
21
|
+
const {
|
22
|
+
inputRef,
|
23
|
+
scrollContainerRef,
|
24
|
+
selectedItemLength,
|
25
|
+
setShowMenu,
|
26
|
+
showMenu = false
|
27
|
+
} = autocompleteContext;
|
28
|
+
const {
|
29
|
+
floatingElementRef,
|
30
|
+
position
|
31
|
+
} = useAnchoredPosition({
|
32
|
+
side: 'outside-bottom',
|
33
|
+
align: 'start',
|
34
|
+
anchorElementRef: menuAnchorRef ? menuAnchorRef : inputRef
|
35
|
+
}, [showMenu, selectedItemLength]);
|
36
|
+
const combinedOverlayRef = useCombinedRefs(scrollContainerRef, floatingElementRef);
|
37
|
+
const closeOptionList = useCallback(() => {
|
38
|
+
setShowMenu(false);
|
39
|
+
}, [setShowMenu]);
|
40
|
+
|
41
|
+
if (typeof window === 'undefined') {
|
42
|
+
return null;
|
43
|
+
}
|
44
|
+
|
45
|
+
return /*#__PURE__*/React.createElement(Overlay, _extends({
|
46
|
+
returnFocusRef: inputRef,
|
47
|
+
preventFocusOnOpen: true,
|
48
|
+
onClickOutside: closeOptionList,
|
49
|
+
onEscape: closeOptionList,
|
50
|
+
ref: combinedOverlayRef,
|
51
|
+
top: position === null || position === void 0 ? void 0 : position.top,
|
52
|
+
left: position === null || position === void 0 ? void 0 : position.left,
|
53
|
+
visibility: showMenu ? 'visible' : 'hidden',
|
54
|
+
sx: {
|
55
|
+
overflow: 'auto'
|
56
|
+
}
|
57
|
+
}, overlayProps), children);
|
58
|
+
}
|
59
|
+
|
60
|
+
AutocompleteOverlay.displayName = "AutocompleteOverlay";
|
61
|
+
AutocompleteOverlay.displayName = 'AutocompleteOverlay';
|
62
|
+
export default AutocompleteOverlay;
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default } from './Autocomplete';
|
package/lib-esm/BaseStyles.js
CHANGED
package/lib-esm/BorderBox.js
CHANGED
package/lib-esm/Caret.js
CHANGED
@@ -106,8 +106,8 @@ function Caret(props) {
|
|
106
106
|
Caret.displayName = "Caret";
|
107
107
|
Caret.locations = ['top', 'top-left', 'top-right', 'right', 'right-top', 'right-bottom', 'bottom', 'bottom-left', 'bottom-right', 'left', 'left-top', 'left-bottom'];
|
108
108
|
Caret.defaultProps = {
|
109
|
-
bg: '
|
110
|
-
borderColor: 'border.
|
109
|
+
bg: 'canvas.default',
|
110
|
+
borderColor: 'border.default',
|
111
111
|
borderWidth: 1
|
112
112
|
};
|
113
113
|
export default Caret;
|
package/lib-esm/Dialog.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { GroupedListProps, ListPropsBase } from '../ActionList/List';
|
3
3
|
import { TextInputProps } from '../TextInput';
|
4
|
-
|
4
|
+
import { SxProp } from '../sx';
|
5
|
+
export interface FilteredActionListProps extends Partial<Omit<GroupedListProps, keyof ListPropsBase>>, ListPropsBase, SxProp {
|
5
6
|
loading?: boolean;
|
6
7
|
placeholderText: string;
|
7
8
|
filterValue?: string;
|
@@ -9,7 +10,7 @@ export interface FilteredActionListProps extends Partial<Omit<GroupedListProps,
|
|
9
10
|
textInputProps?: Partial<Omit<TextInputProps, 'onChange'>>;
|
10
11
|
inputRef?: React.RefObject<HTMLInputElement>;
|
11
12
|
}
|
12
|
-
export declare function FilteredActionList({ loading, placeholderText, filterValue: externalFilterValue, onFilterChange, items, textInputProps, inputRef: providedInputRef, ...listProps }: FilteredActionListProps): JSX.Element;
|
13
|
+
export declare function FilteredActionList({ loading, placeholderText, filterValue: externalFilterValue, onFilterChange, items, textInputProps, inputRef: providedInputRef, sx, ...listProps }: FilteredActionListProps): JSX.Element;
|
13
14
|
export declare namespace FilteredActionList {
|
14
15
|
var displayName: string;
|
15
16
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
2
2
|
|
3
3
|
import React, { useCallback, useEffect, useRef } from 'react';
|
4
|
+
import { useSSRSafeId } from '@react-aria/ssr';
|
4
5
|
import TextInput from '../TextInput';
|
5
6
|
import Box from '../Box';
|
6
7
|
import { ActionList } from '../ActionList';
|
@@ -11,36 +12,7 @@ import styled from 'styled-components';
|
|
11
12
|
import { get } from '../constants';
|
12
13
|
import { useProvidedRefOrCreate } from '../hooks/useProvidedRefOrCreate';
|
13
14
|
import useScrollFlash from '../hooks/useScrollFlash';
|
14
|
-
import {
|
15
|
-
|
16
|
-
function scrollIntoViewingArea(child, container, margin = 8, behavior = 'smooth') {
|
17
|
-
const {
|
18
|
-
top: childTop,
|
19
|
-
bottom: childBottom
|
20
|
-
} = child.getBoundingClientRect();
|
21
|
-
const {
|
22
|
-
top: containerTop,
|
23
|
-
bottom: containerBottom
|
24
|
-
} = container.getBoundingClientRect();
|
25
|
-
const isChildTopAboveViewingArea = childTop < containerTop + margin;
|
26
|
-
const isChildBottomBelowViewingArea = childBottom > containerBottom - margin;
|
27
|
-
|
28
|
-
if (isChildTopAboveViewingArea) {
|
29
|
-
const scrollHeightToChildTop = childTop - containerTop + container.scrollTop;
|
30
|
-
container.scrollTo({
|
31
|
-
behavior,
|
32
|
-
top: scrollHeightToChildTop - margin
|
33
|
-
});
|
34
|
-
} else if (isChildBottomBelowViewingArea) {
|
35
|
-
const scrollHeightToChildBottom = childBottom - containerBottom + container.scrollTop;
|
36
|
-
container.scrollTo({
|
37
|
-
behavior,
|
38
|
-
top: scrollHeightToChildBottom + margin
|
39
|
-
});
|
40
|
-
} // either completely in view or outside viewing area on both ends, don't scroll
|
41
|
-
|
42
|
-
}
|
43
|
-
|
15
|
+
import { scrollIntoViewingArea } from '../behaviors/scrollIntoViewingArea';
|
44
16
|
const StyledHeader = styled.div.withConfig({
|
45
17
|
displayName: "FilteredActionList__StyledHeader",
|
46
18
|
componentId: "yg3jkv-0"
|
@@ -53,6 +25,7 @@ export function FilteredActionList({
|
|
53
25
|
items,
|
54
26
|
textInputProps,
|
55
27
|
inputRef: providedInputRef,
|
28
|
+
sx,
|
56
29
|
...listProps
|
57
30
|
}) {
|
58
31
|
const [filterValue, setInternalFilterValue] = useProvidedStateOrCreate(externalFilterValue, undefined, '');
|
@@ -94,14 +67,15 @@ export function FilteredActionList({
|
|
94
67
|
useEffect(() => {
|
95
68
|
// if items changed, we want to instantly move active descendant into view
|
96
69
|
if (activeDescendantRef.current && scrollContainerRef.current) {
|
97
|
-
scrollIntoViewingArea(activeDescendantRef.current, scrollContainerRef.current, undefined, 'auto');
|
70
|
+
scrollIntoViewingArea(activeDescendantRef.current, scrollContainerRef.current, 'vertical', undefined, undefined, 'auto');
|
98
71
|
}
|
99
72
|
}, [items]);
|
100
73
|
useScrollFlash(scrollContainerRef);
|
101
74
|
return /*#__PURE__*/React.createElement(Box, {
|
102
75
|
display: "flex",
|
103
76
|
flexDirection: "column",
|
104
|
-
overflow: "hidden"
|
77
|
+
overflow: "hidden",
|
78
|
+
sx: sx
|
105
79
|
}, /*#__PURE__*/React.createElement(StyledHeader, null, /*#__PURE__*/React.createElement(TextInput, _extends({
|
106
80
|
ref: inputRef,
|
107
81
|
block: true,
|
package/lib-esm/Flash.js
CHANGED
@@ -5,35 +5,35 @@ import sx from './sx';
|
|
5
5
|
const variants = variant({
|
6
6
|
variants: {
|
7
7
|
default: {
|
8
|
-
color: '
|
9
|
-
backgroundColor: '
|
10
|
-
borderColor: '
|
8
|
+
color: 'fg.default',
|
9
|
+
backgroundColor: 'accent.subtle',
|
10
|
+
borderColor: 'accent.muted',
|
11
11
|
svg: {
|
12
|
-
color: '
|
12
|
+
color: 'accent.fg'
|
13
13
|
}
|
14
14
|
},
|
15
15
|
success: {
|
16
|
-
color: '
|
17
|
-
backgroundColor: '
|
18
|
-
borderColor: '
|
16
|
+
color: 'fg.default',
|
17
|
+
backgroundColor: 'success.subtle',
|
18
|
+
borderColor: 'success.muted',
|
19
19
|
svg: {
|
20
|
-
color: '
|
20
|
+
color: 'success.fg'
|
21
21
|
}
|
22
22
|
},
|
23
23
|
danger: {
|
24
|
-
color: '
|
25
|
-
backgroundColor: '
|
26
|
-
borderColor: '
|
24
|
+
color: 'fg.default',
|
25
|
+
backgroundColor: 'danger.subtle',
|
26
|
+
borderColor: 'danger.muted',
|
27
27
|
svg: {
|
28
|
-
color: '
|
28
|
+
color: 'danger.fg'
|
29
29
|
}
|
30
30
|
},
|
31
31
|
warning: {
|
32
|
-
color: '
|
33
|
-
backgroundColor: '
|
34
|
-
borderColor: '
|
32
|
+
color: 'fg.default',
|
33
|
+
backgroundColor: 'attention.subtle',
|
34
|
+
borderColor: 'attention.muted',
|
35
35
|
svg: {
|
36
|
-
color: '
|
36
|
+
color: 'attention.fg'
|
37
37
|
}
|
38
38
|
}
|
39
39
|
}
|
package/lib-esm/Label.js
CHANGED
@@ -33,7 +33,7 @@ const Label = styled.span.withConfig({
|
|
33
33
|
componentId: "sc-1t3ykp0-0"
|
34
34
|
})(["display:inline-block;font-weight:", ";color:", ";border-radius:", ";&:hover{text-decoration:none;}", " ", " ", " ", " ", ""], get('fontWeights.semibold'), get('colors.fg.onEmphasis'), get('radii.3'), sizeVariant, COMMON, props => props.dropshadow ? 'box-shadow: inset 0 -1px 0 rgba(27, 31, 35, 0.12)' : '', props => props.outline ? outlineStyles : '', sx);
|
35
35
|
Label.defaultProps = {
|
36
|
-
bg: '
|
36
|
+
bg: 'neutral.emphasis',
|
37
37
|
variant: 'medium'
|
38
38
|
};
|
39
39
|
export default Label;
|
package/lib-esm/Overlay.d.ts
CHANGED
@@ -40,6 +40,7 @@ export declare type OverlayProps = {
|
|
40
40
|
top: number;
|
41
41
|
left: number;
|
42
42
|
portalContainerName?: string;
|
43
|
+
preventFocusOnOpen?: boolean;
|
43
44
|
} & Omit<ComponentProps<typeof StyledOverlay>, 'visibility' | keyof SystemPositionProps>;
|
44
45
|
/**
|
45
46
|
* An `Overlay` is a flexible floating surface, used to display transient content such as menus,
|
package/lib-esm/Overlay.js
CHANGED
@@ -92,6 +92,7 @@ const Overlay = /*#__PURE__*/React.forwardRef(({
|
|
92
92
|
left,
|
93
93
|
anchorSide,
|
94
94
|
portalContainerName,
|
95
|
+
preventFocusOnOpen,
|
95
96
|
...rest
|
96
97
|
}, forwardedRef) => {
|
97
98
|
const overlayRef = useRef(null);
|
@@ -107,7 +108,8 @@ const Overlay = /*#__PURE__*/React.forwardRef(({
|
|
107
108
|
onEscape,
|
108
109
|
ignoreClickRefs,
|
109
110
|
onClickOutside,
|
110
|
-
initialFocusRef
|
111
|
+
initialFocusRef,
|
112
|
+
preventFocusOnOpen
|
111
113
|
});
|
112
114
|
useEffect(() => {
|
113
115
|
var _combinedRef$current;
|
package/lib-esm/ProgressBar.js
CHANGED
@@ -32,7 +32,15 @@ declare const _default: React.ForwardRefExoticComponent<Pick<SelectMenuInternalP
|
|
32
32
|
Divider: import("styled-components").StyledComponent<"div", any, SystemCommonProps & SxProp, never>;
|
33
33
|
Filter: React.ForwardRefExoticComponent<Pick<{
|
34
34
|
value?: string | undefined;
|
35
|
-
} & Pick<{
|
35
|
+
} & Pick<Omit<Pick<{
|
36
|
+
[x: string]: any;
|
37
|
+
[x: number]: any;
|
38
|
+
} & {
|
39
|
+
theme?: any;
|
40
|
+
} & {
|
41
|
+
as?: string | React.ComponentType<any> | undefined;
|
42
|
+
forwardedAs?: string | React.ComponentType<any> | undefined;
|
43
|
+
}, string | number | symbol>, "maxWidth" | "minWidth" | "width" | "theme" | "className" | "block" | "icon" | "sx" | "disabled" | "variant" | "contrast"> & {
|
36
44
|
className?: string | undefined;
|
37
45
|
icon?: React.ComponentType<{
|
38
46
|
className?: string | undefined;
|
@@ -307,15 +315,7 @@ declare const _default: React.ForwardRefExoticComponent<Pick<SelectMenuInternalP
|
|
307
315
|
contrast?: boolean | undefined;
|
308
316
|
} & {
|
309
317
|
theme?: any;
|
310
|
-
}, "maxWidth" | "minWidth" | "width" | "theme" | "block" | "sx" | "disabled" | "variant" | "contrast"> &
|
311
|
-
[x: string]: any;
|
312
|
-
[x: number]: any;
|
313
|
-
} & {
|
314
|
-
theme?: any;
|
315
|
-
} & {
|
316
|
-
as?: string | React.ComponentType<any> | undefined;
|
317
|
-
forwardedAs?: string | React.ComponentType<any> | undefined;
|
318
|
-
}, string | number | symbol>, "maxWidth" | "minWidth" | "width" | "theme" | "className" | "block" | "icon" | "sx" | "disabled" | "variant" | "contrast">, string | number | symbol> & React.RefAttributes<HTMLInputElement>, string | number | symbol> & React.RefAttributes<HTMLInputElement>>;
|
318
|
+
}, "maxWidth" | "minWidth" | "width" | "theme" | "block" | "sx" | "disabled" | "variant" | "contrast">, string | number | symbol> & React.RefAttributes<HTMLInputElement>, string | number | symbol> & React.RefAttributes<HTMLInputElement>>;
|
319
319
|
Footer: import("styled-components").StyledComponent<"footer", any, SystemCommonProps & SxProp, never>;
|
320
320
|
Item: React.ForwardRefExoticComponent<Pick<{
|
321
321
|
as?: React.ElementType<any> | undefined;
|
@@ -18,7 +18,7 @@ interface SelectPanelBaseProps {
|
|
18
18
|
overlayProps?: Partial<OverlayProps>;
|
19
19
|
}
|
20
20
|
export declare type SelectPanelProps = SelectPanelBaseProps & Omit<FilteredActionListProps, 'selectionVariant'> & Pick<AnchoredOverlayProps, 'open'> & AnchoredOverlayWrapperAnchorProps & (SelectPanelSingleSelection | SelectPanelMultiSelection);
|
21
|
-
export declare function SelectPanel({ open, onOpenChange, renderAnchor, anchorRef: externalAnchorRef, placeholder, selected, onSelectedChange, filterValue: externalFilterValue, onFilterChange: externalOnFilterChange, items, textInputProps, overlayProps, ...listProps }: SelectPanelProps): JSX.Element;
|
21
|
+
export declare function SelectPanel({ open, onOpenChange, renderAnchor, anchorRef: externalAnchorRef, placeholder, selected, onSelectedChange, filterValue: externalFilterValue, onFilterChange: externalOnFilterChange, items, textInputProps, overlayProps, sx, ...listProps }: SelectPanelProps): JSX.Element;
|
22
22
|
export declare namespace SelectPanel {
|
23
23
|
var displayName: string;
|
24
24
|
}
|
@@ -4,7 +4,6 @@ import React, { useCallback, useMemo } from 'react';
|
|
4
4
|
import { FilteredActionList } from '../FilteredActionList';
|
5
5
|
import { DropdownButton } from '../DropdownMenu';
|
6
6
|
import { AnchoredOverlay } from '../AnchoredOverlay';
|
7
|
-
import Box from '../Box';
|
8
7
|
import { useProvidedStateOrCreate } from '../hooks/useProvidedStateOrCreate';
|
9
8
|
import { useProvidedRefOrCreate } from '../hooks';
|
10
9
|
|
@@ -29,6 +28,7 @@ export function SelectPanel({
|
|
29
28
|
items,
|
30
29
|
textInputProps,
|
31
30
|
overlayProps,
|
31
|
+
sx,
|
32
32
|
...listProps
|
33
33
|
}) {
|
34
34
|
const [filterValue, setInternalFilterValue] = useProvidedStateOrCreate(externalFilterValue, undefined, '');
|
@@ -106,11 +106,6 @@ export function SelectPanel({
|
|
106
106
|
overlayProps: overlayProps,
|
107
107
|
focusTrapSettings: focusTrapSettings,
|
108
108
|
focusZoneSettings: focusZoneSettings
|
109
|
-
}, /*#__PURE__*/React.createElement(Box, {
|
110
|
-
display: "flex",
|
111
|
-
flexDirection: "column",
|
112
|
-
width: "100%",
|
113
|
-
height: "100%"
|
114
109
|
}, /*#__PURE__*/React.createElement(FilteredActionList, _extends({
|
115
110
|
filterValue: filterValue,
|
116
111
|
onFilterChange: onFilterChange
|
@@ -119,8 +114,14 @@ export function SelectPanel({
|
|
119
114
|
items: itemsToRender,
|
120
115
|
selectionVariant: isMultiSelectVariant(selected) ? 'multiple' : 'single',
|
121
116
|
textInputProps: extendedTextInputProps,
|
122
|
-
inputRef: inputRef
|
123
|
-
|
117
|
+
inputRef: inputRef // inheriting height and maxHeight ensures that the FilteredActionList is never taller
|
118
|
+
// than the Overlay (which would break scrolling the items)
|
119
|
+
,
|
120
|
+
sx: { ...sx,
|
121
|
+
height: 'inherit',
|
122
|
+
maxHeight: 'inherit'
|
123
|
+
}
|
124
|
+
})));
|
124
125
|
}
|
125
126
|
SelectPanel.displayName = "SelectPanel";
|
126
127
|
SelectPanel.displayName = 'SelectPanel';
|