@primer/components 30.3.0-rc.2010c7d4 → 30.3.0-rc.9dbc85a9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGELOG.md +4 -2
  2. package/dist/browser.esm.js +717 -718
  3. package/dist/browser.esm.js.map +1 -1
  4. package/dist/browser.umd.js +320 -321
  5. package/dist/browser.umd.js.map +1 -1
  6. package/docs/content/Autocomplete.mdx +627 -0
  7. package/docs/content/TextInputTokens.mdx +89 -0
  8. package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +2 -0
  9. package/lib/AnchoredOverlay/AnchoredOverlay.d.ts +2 -1
  10. package/lib/AnchoredOverlay/AnchoredOverlay.js +11 -3
  11. package/lib/Autocomplete/Autocomplete.d.ts +304 -0
  12. package/lib/Autocomplete/Autocomplete.js +145 -0
  13. package/lib/Autocomplete/AutocompleteContext.d.ts +17 -0
  14. package/lib/Autocomplete/AutocompleteContext.js +11 -0
  15. package/lib/Autocomplete/AutocompleteInput.d.ts +292 -0
  16. package/lib/Autocomplete/AutocompleteInput.js +157 -0
  17. package/lib/Autocomplete/AutocompleteMenu.d.ts +72 -0
  18. package/lib/Autocomplete/AutocompleteMenu.js +224 -0
  19. package/lib/Autocomplete/AutocompleteOverlay.d.ts +20 -0
  20. package/lib/Autocomplete/AutocompleteOverlay.js +80 -0
  21. package/lib/Autocomplete/index.d.ts +2 -0
  22. package/lib/Autocomplete/index.js +15 -0
  23. package/lib/FilteredActionList/FilteredActionList.js +5 -31
  24. package/lib/Overlay.d.ts +1 -0
  25. package/lib/Overlay.js +3 -1
  26. package/lib/__tests__/Autocomplete.test.d.ts +1 -0
  27. package/lib/__tests__/Autocomplete.test.js +528 -0
  28. package/lib/__tests__/behaviors/scrollIntoViewingArea.test.d.ts +1 -0
  29. package/lib/__tests__/behaviors/scrollIntoViewingArea.test.js +226 -0
  30. package/lib/behaviors/scrollIntoViewingArea.d.ts +1 -0
  31. package/lib/behaviors/scrollIntoViewingArea.js +39 -0
  32. package/lib/hooks/useOpenAndCloseFocus.d.ts +2 -1
  33. package/lib/hooks/useOpenAndCloseFocus.js +7 -2
  34. package/lib/hooks/useOverlay.d.ts +2 -1
  35. package/lib/hooks/useOverlay.js +4 -2
  36. package/lib/index.d.ts +2 -0
  37. package/lib/index.js +8 -0
  38. package/lib/stories/Autocomplete.stories.js +608 -0
  39. package/lib/utils/types/MandateProps.d.ts +3 -0
  40. package/lib/utils/types/MandateProps.js +1 -0
  41. package/lib/utils/types/index.d.ts +1 -0
  42. package/lib/utils/types/index.js +13 -0
  43. package/lib-esm/AnchoredOverlay/AnchoredOverlay.d.ts +2 -1
  44. package/lib-esm/AnchoredOverlay/AnchoredOverlay.js +11 -3
  45. package/lib-esm/Autocomplete/Autocomplete.d.ts +304 -0
  46. package/lib-esm/Autocomplete/Autocomplete.js +123 -0
  47. package/lib-esm/Autocomplete/AutocompleteContext.d.ts +17 -0
  48. package/lib-esm/Autocomplete/AutocompleteContext.js +2 -0
  49. package/lib-esm/Autocomplete/AutocompleteInput.d.ts +292 -0
  50. package/lib-esm/Autocomplete/AutocompleteInput.js +138 -0
  51. package/lib-esm/Autocomplete/AutocompleteMenu.d.ts +72 -0
  52. package/lib-esm/Autocomplete/AutocompleteMenu.js +205 -0
  53. package/lib-esm/Autocomplete/AutocompleteOverlay.d.ts +20 -0
  54. package/lib-esm/Autocomplete/AutocompleteOverlay.js +62 -0
  55. package/lib-esm/Autocomplete/index.d.ts +2 -0
  56. package/lib-esm/Autocomplete/index.js +1 -0
  57. package/lib-esm/FilteredActionList/FilteredActionList.js +3 -31
  58. package/lib-esm/Overlay.d.ts +1 -0
  59. package/lib-esm/Overlay.js +3 -1
  60. package/lib-esm/__tests__/Autocomplete.test.d.ts +1 -0
  61. package/lib-esm/__tests__/Autocomplete.test.js +494 -0
  62. package/lib-esm/__tests__/behaviors/scrollIntoViewingArea.test.d.ts +1 -0
  63. package/lib-esm/__tests__/behaviors/scrollIntoViewingArea.test.js +224 -0
  64. package/lib-esm/behaviors/scrollIntoViewingArea.d.ts +1 -0
  65. package/lib-esm/behaviors/scrollIntoViewingArea.js +30 -0
  66. package/lib-esm/hooks/useOpenAndCloseFocus.d.ts +2 -1
  67. package/lib-esm/hooks/useOpenAndCloseFocus.js +7 -2
  68. package/lib-esm/hooks/useOverlay.d.ts +2 -1
  69. package/lib-esm/hooks/useOverlay.js +4 -2
  70. package/lib-esm/index.d.ts +2 -0
  71. package/lib-esm/index.js +1 -0
  72. package/lib-esm/stories/Autocomplete.stories.js +549 -0
  73. package/lib-esm/utils/types/MandateProps.d.ts +3 -0
  74. package/lib-esm/utils/types/MandateProps.js +1 -0
  75. package/lib-esm/utils/types/index.d.ts +1 -0
  76. package/lib-esm/utils/types/index.js +2 -1
  77. package/package.json +1 -1
  78. package/src/AnchoredOverlay/AnchoredOverlay.tsx +14 -3
  79. package/src/Autocomplete/Autocomplete.tsx +103 -0
  80. package/src/Autocomplete/AutocompleteContext.tsx +19 -0
  81. package/src/Autocomplete/AutocompleteInput.tsx +179 -0
  82. package/src/Autocomplete/AutocompleteMenu.tsx +341 -0
  83. package/src/Autocomplete/AutocompleteOverlay.tsx +68 -0
  84. package/src/Autocomplete/index.ts +2 -0
  85. package/src/FilteredActionList/FilteredActionList.tsx +10 -25
  86. package/src/Overlay.tsx +4 -1
  87. package/src/__tests__/Autocomplete.test.tsx +444 -0
  88. package/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +3414 -0
  89. package/src/__tests__/behaviors/scrollIntoViewingArea.test.ts +195 -0
  90. package/src/behaviors/scrollIntoViewingArea.ts +27 -0
  91. package/src/hooks/useOpenAndCloseFocus.ts +7 -2
  92. package/src/hooks/useOverlay.tsx +4 -2
  93. package/src/index.ts +2 -0
  94. package/src/stories/Autocomplete.stories.tsx +572 -0
  95. package/src/utils/types/MandateProps.ts +19 -0
  96. package/src/utils/types/index.ts +1 -0
  97. package/stats.html +1 -1
@@ -0,0 +1,608 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.InOverlayWithCustomScrollContainerRef = exports.WithCustomOverlayProps = exports.CustomOverlayMenuAnchor = exports.RenderingTheMenuOutsideAnOverlay = exports.AsyncLoadingOfItems = exports.WithCallbackWhenOverlayOpenStateChanges = exports.CustomSortAfterMenuClose = exports.CustomSearchFilter = exports.CustomEmptyStateMessage = exports.MultiSelectAddNewItem = exports.MultiSelectWithTokenInput = exports.MultiSelect = exports.SingleSelect = exports.default = void 0;
7
+
8
+ var _react = _interopRequireWildcard(require("react"));
9
+
10
+ var _ = require("..");
11
+
12
+ var _TextInputWithTokens = _interopRequireDefault(require("../TextInputWithTokens"));
13
+
14
+ var _Autocomplete = _interopRequireDefault(require("../Autocomplete/Autocomplete"));
15
+
16
+ var _AnchoredOverlay = require("../AnchoredOverlay");
17
+
18
+ var _Button = require("../Button");
19
+
20
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
+
22
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
23
+
24
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
25
+
26
+ 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); }
27
+
28
+ const items = [{
29
+ text: 'zero',
30
+ id: 0
31
+ }, {
32
+ text: 'one',
33
+ id: 1
34
+ }, {
35
+ text: 'two',
36
+ id: 2
37
+ }, {
38
+ text: 'three',
39
+ id: 3
40
+ }, {
41
+ text: 'four',
42
+ id: 4
43
+ }, {
44
+ text: 'five',
45
+ id: 5
46
+ }, {
47
+ text: 'six',
48
+ id: 6
49
+ }, {
50
+ text: 'seven',
51
+ id: 7
52
+ }, {
53
+ text: 'twenty',
54
+ id: 20
55
+ }, {
56
+ text: 'twentyone',
57
+ id: 21
58
+ }];
59
+ const mockTokens = [{
60
+ text: 'zero',
61
+ id: 0
62
+ }, {
63
+ text: 'one',
64
+ id: 1
65
+ }, {
66
+ text: 'three',
67
+ id: 3
68
+ }, {
69
+ text: 'four',
70
+ id: 4
71
+ }];
72
+ var _default = {
73
+ title: 'Forms/Autocomplete',
74
+ decorators: [Story => {
75
+ const [lastKey, setLastKey] = (0, _react.useState)('none');
76
+ const reportKey = (0, _react.useCallback)(event => {
77
+ setLastKey(event.key);
78
+ }, []);
79
+ return /*#__PURE__*/_react.default.createElement(_.ThemeProvider, null, /*#__PURE__*/_react.default.createElement(_.BaseStyles, null, /*#__PURE__*/_react.default.createElement(_.Box, {
80
+ onKeyDownCapture: reportKey
81
+ }, /*#__PURE__*/_react.default.createElement(_.Box, {
82
+ position: "absolute",
83
+ right: 5,
84
+ top: 2
85
+ }, "Last key pressed: ", lastKey), /*#__PURE__*/_react.default.createElement(_.Box, {
86
+ paddingTop: 5
87
+ }, /*#__PURE__*/_react.default.createElement(Story, null)))));
88
+ }]
89
+ };
90
+ exports.default = _default;
91
+
92
+ const SingleSelect = () => {
93
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
94
+ as: "label",
95
+ display: "block",
96
+ htmlFor: "autocompleteInput",
97
+ id: "autocompleteLabel"
98
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
99
+ id: "autocompleteInput"
100
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
101
+ items: items,
102
+ selectedItemIds: [],
103
+ "aria-labelledby": "autocompleteLabel"
104
+ }))));
105
+ };
106
+
107
+ exports.SingleSelect = SingleSelect;
108
+
109
+ const MultiSelect = () => {
110
+ const [selectedItemIds, setSelectedItemIds] = (0, _react.useState)([]);
111
+
112
+ const onSelectedChange = newlySelectedItems => {
113
+ if (!Array.isArray(newlySelectedItems)) {
114
+ return;
115
+ }
116
+
117
+ setSelectedItemIds(newlySelectedItems.map(item => item.id));
118
+ };
119
+
120
+ const getItemById = id => items.find(item => item.id === id);
121
+
122
+ return /*#__PURE__*/_react.default.createElement(_.Box, {
123
+ display: "flex",
124
+ sx: {
125
+ gap: '1em'
126
+ }
127
+ }, /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_.Box, {
128
+ as: "label",
129
+ display: "block",
130
+ htmlFor: "autocompleteInput",
131
+ id: "autocompleteLabel"
132
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
133
+ id: "autocompleteInput"
134
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
135
+ items: items,
136
+ selectedItemIds: selectedItemIds,
137
+ "aria-labelledby": "autocompleteLabel",
138
+ onSelectedChange: onSelectedChange,
139
+ selectionVariant: "multiple"
140
+ })))), /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", null, "Selected items:"), /*#__PURE__*/_react.default.createElement(_.Box, {
141
+ as: "ul",
142
+ my: 0
143
+ }, selectedItemIds.map(selectedItemId => {
144
+ var _getItemById;
145
+
146
+ return /*#__PURE__*/_react.default.createElement("li", {
147
+ key: selectedItemId
148
+ }, (_getItemById = getItemById(selectedItemId)) === null || _getItemById === void 0 ? void 0 : _getItemById.text);
149
+ }))));
150
+ };
151
+
152
+ exports.MultiSelect = MultiSelect;
153
+ MultiSelect.displayName = "MultiSelect";
154
+
155
+ const MultiSelectWithTokenInput = () => {
156
+ const [tokens, setTokens] = (0, _react.useState)(mockTokens);
157
+ const selectedTokenIds = tokens.map(token => token.id);
158
+ const [selectedItemIds, setSelectedItemIds] = (0, _react.useState)(selectedTokenIds);
159
+
160
+ const onTokenRemove = tokenId => {
161
+ setTokens(tokens.filter(token => token.id !== tokenId));
162
+ setSelectedItemIds(selectedItemIds.filter(id => id !== tokenId));
163
+ };
164
+
165
+ const onSelectedChange = newlySelectedItems => {
166
+ if (!Array.isArray(newlySelectedItems)) {
167
+ return;
168
+ }
169
+
170
+ setSelectedItemIds(newlySelectedItems.map(item => item.id));
171
+
172
+ if (newlySelectedItems.length < selectedItemIds.length) {
173
+ const newlySelectedItemIds = newlySelectedItems.map(({
174
+ id
175
+ }) => id);
176
+ const removedItemIds = selectedTokenIds.filter(id => !newlySelectedItemIds.includes(id));
177
+
178
+ for (const removedItemId of removedItemIds) {
179
+ onTokenRemove(removedItemId);
180
+ }
181
+
182
+ return;
183
+ }
184
+
185
+ setTokens(newlySelectedItems.map(({
186
+ id,
187
+ text
188
+ }) => ({
189
+ id,
190
+ text
191
+ })));
192
+ };
193
+
194
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
195
+ as: "label",
196
+ display: "block",
197
+ htmlFor: "autocompleteInput",
198
+ id: "autocompleteLabel"
199
+ }, "Pick options"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
200
+ as: _TextInputWithTokens.default,
201
+ tokens: tokens,
202
+ onTokenRemove: onTokenRemove,
203
+ id: "autocompleteInput"
204
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
205
+ items: items,
206
+ selectedItemIds: selectedItemIds,
207
+ onSelectedChange: onSelectedChange,
208
+ selectionVariant: "multiple",
209
+ "aria-labelledby": "autocompleteLabel"
210
+ }))));
211
+ };
212
+
213
+ exports.MultiSelectWithTokenInput = MultiSelectWithTokenInput;
214
+
215
+ const MultiSelectAddNewItem = () => {
216
+ const [localItemsState, setLocalItemsState] = (0, _react.useState)(items);
217
+ const [filterVal, setFilterVal] = (0, _react.useState)('');
218
+ const [tokens, setTokens] = (0, _react.useState)(mockTokens);
219
+ const selectedTokenIds = tokens.map(token => token.id);
220
+ const [selectedItemIds, setSelectedItemIds] = (0, _react.useState)(selectedTokenIds);
221
+
222
+ const onTokenRemove = tokenId => {
223
+ setTokens(tokens.filter(token => token.id !== tokenId));
224
+ setSelectedItemIds(selectedItemIds.filter(id => id !== tokenId));
225
+ };
226
+
227
+ const onSelectedChange = newlySelectedItems => {
228
+ if (!Array.isArray(newlySelectedItems)) {
229
+ return;
230
+ }
231
+
232
+ setSelectedItemIds(newlySelectedItems.map(item => item.id));
233
+
234
+ if (newlySelectedItems.length < selectedItemIds.length) {
235
+ const newlySelectedItemIds = newlySelectedItems.map(({
236
+ id
237
+ }) => id);
238
+ const removedItemIds = selectedTokenIds.filter(id => !newlySelectedItemIds.includes(id));
239
+
240
+ for (const removedItemId of removedItemIds) {
241
+ onTokenRemove(removedItemId);
242
+ }
243
+
244
+ return;
245
+ }
246
+
247
+ setTokens(newlySelectedItems.map(({
248
+ id,
249
+ text
250
+ }) => ({
251
+ id,
252
+ text
253
+ })));
254
+ };
255
+
256
+ const onItemSelect = item => {
257
+ onSelectedChange([...selectedItemIds.map(id => items.find(selectedItem => selectedItem.id === id)), item]);
258
+
259
+ if (!localItemsState.some(localItem => localItem.id === item.id)) {
260
+ setLocalItemsState([...localItemsState, item]);
261
+ }
262
+ };
263
+
264
+ const handleChange = e => {
265
+ setFilterVal(e.currentTarget.value);
266
+ };
267
+
268
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
269
+ as: "label",
270
+ display: "block",
271
+ htmlFor: "autocompleteInput",
272
+ id: "autocompleteLabel"
273
+ }, "Pick options"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
274
+ as: _TextInputWithTokens.default,
275
+ tokens: tokens,
276
+ onTokenRemove: onTokenRemove,
277
+ onChange: handleChange,
278
+ id: "autocompleteInput"
279
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
280
+ addNewItem: filterVal && !localItemsState.map(localItem => localItem.text).includes(filterVal) ? {
281
+ text: `Add '${filterVal}'`,
282
+ handleAddItem: item => {
283
+ onItemSelect({ ...item,
284
+ text: filterVal,
285
+ selected: true
286
+ });
287
+ setFilterVal('');
288
+ }
289
+ } : undefined,
290
+ items: localItemsState,
291
+ selectedItemIds: selectedItemIds,
292
+ onSelectedChange: onSelectedChange,
293
+ selectionVariant: "multiple",
294
+ "aria-labelledby": "autocompleteLabel"
295
+ }))));
296
+ };
297
+
298
+ exports.MultiSelectAddNewItem = MultiSelectAddNewItem;
299
+
300
+ const CustomEmptyStateMessage = () => {
301
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
302
+ as: "label",
303
+ display: "block",
304
+ htmlFor: "autocompleteInput",
305
+ id: "autocompleteLabel"
306
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
307
+ id: "autocompleteInput"
308
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
309
+ items: items,
310
+ selectedItemIds: [],
311
+ "aria-labelledby": "autocompleteLabel",
312
+ emptyStateText: "Sorry, no matches"
313
+ }))));
314
+ };
315
+
316
+ exports.CustomEmptyStateMessage = CustomEmptyStateMessage;
317
+
318
+ const CustomSearchFilter = () => {
319
+ const [filterVal, setFilterVal] = (0, _react.useState)('');
320
+
321
+ const handleChange = e => {
322
+ setFilterVal(e.currentTarget.value);
323
+ };
324
+
325
+ const customFilterFn = item => item.text.includes(filterVal);
326
+
327
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
328
+ as: "label",
329
+ display: "block",
330
+ htmlFor: "autocompleteInput",
331
+ id: "autocompleteLabel"
332
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
333
+ id: "autocompleteInput",
334
+ onChange: handleChange
335
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
336
+ items: items,
337
+ selectedItemIds: [],
338
+ "aria-labelledby": "autocompleteLabel",
339
+ filterFn: customFilterFn
340
+ }))), /*#__PURE__*/_react.default.createElement(_.Text, {
341
+ fontSize: 0,
342
+ display: "block",
343
+ color: "fg.subtle",
344
+ mt: 2
345
+ }, "Items in dropdown are filtered if their text has no part that matches the input value"));
346
+ };
347
+
348
+ exports.CustomSearchFilter = CustomSearchFilter;
349
+
350
+ const CustomSortAfterMenuClose = () => {
351
+ const [selectedItemIds, setSelectedItemIds] = (0, _react.useState)([]);
352
+
353
+ const isItemSelected = itemId => selectedItemIds.includes(itemId);
354
+
355
+ const onSelectedChange = newlySelectedItems => {
356
+ if (!Array.isArray(newlySelectedItems)) {
357
+ return;
358
+ }
359
+
360
+ setSelectedItemIds(newlySelectedItems.map(item => item.id));
361
+ };
362
+
363
+ const customSortFn = (itemIdA, itemIdB) => isItemSelected(itemIdA) === isItemSelected(itemIdB) ? 0 : isItemSelected(itemIdA) ? 1 : -1;
364
+
365
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
366
+ as: "label",
367
+ display: "block",
368
+ htmlFor: "autocompleteInput",
369
+ id: "autocompleteLabel"
370
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
371
+ id: "autocompleteInput"
372
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
373
+ items: items,
374
+ selectedItemIds: selectedItemIds,
375
+ "aria-labelledby": "autocompleteLabel",
376
+ onSelectedChange: onSelectedChange,
377
+ sortOnCloseFn: customSortFn,
378
+ selectionVariant: "multiple"
379
+ }))), /*#__PURE__*/_react.default.createElement(_.Text, {
380
+ fontSize: 0,
381
+ display: "block",
382
+ color: "fg.subtle",
383
+ mt: 2
384
+ }, "When the dropdown closes, selected items are sorted to the end"));
385
+ };
386
+
387
+ exports.CustomSortAfterMenuClose = CustomSortAfterMenuClose;
388
+
389
+ const WithCallbackWhenOverlayOpenStateChanges = () => {
390
+ const [isMenuOpen, setIsMenuOpen] = (0, _react.useState)(false);
391
+
392
+ const onOpenChange = isOpen => {
393
+ setIsMenuOpen(isOpen);
394
+ };
395
+
396
+ return /*#__PURE__*/_react.default.createElement(_.Box, {
397
+ display: "flex",
398
+ sx: {
399
+ gap: '1em'
400
+ }
401
+ }, /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_.Box, {
402
+ as: "label",
403
+ display: "block",
404
+ htmlFor: "autocompleteInput",
405
+ id: "autocompleteLabel"
406
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
407
+ id: "autocompleteInput"
408
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
409
+ items: items,
410
+ selectedItemIds: [],
411
+ "aria-labelledby": "autocompleteLabel",
412
+ onOpenChange: onOpenChange
413
+ })))), /*#__PURE__*/_react.default.createElement("div", null, "The menu is ", /*#__PURE__*/_react.default.createElement("strong", null, isMenuOpen ? 'opened' : 'closed')));
414
+ };
415
+
416
+ exports.WithCallbackWhenOverlayOpenStateChanges = WithCallbackWhenOverlayOpenStateChanges;
417
+ WithCallbackWhenOverlayOpenStateChanges.displayName = "WithCallbackWhenOverlayOpenStateChanges";
418
+
419
+ const AsyncLoadingOfItems = () => {
420
+ const [loadedItems, setLoadedItems] = (0, _react.useState)([]);
421
+
422
+ const onOpenChange = () => {
423
+ setTimeout(() => {
424
+ setLoadedItems(items);
425
+ }, 1500);
426
+ };
427
+
428
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
429
+ as: "label",
430
+ display: "block",
431
+ htmlFor: "autocompleteInput",
432
+ id: "autocompleteLabel"
433
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
434
+ id: "autocompleteInput"
435
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
436
+ items: loadedItems,
437
+ selectedItemIds: [],
438
+ "aria-labelledby": "autocompleteLabel",
439
+ onOpenChange: onOpenChange,
440
+ loading: loadedItems.length === 0
441
+ }))));
442
+ };
443
+
444
+ exports.AsyncLoadingOfItems = AsyncLoadingOfItems;
445
+
446
+ const RenderingTheMenuOutsideAnOverlay = () => {
447
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
448
+ as: "label",
449
+ display: "block",
450
+ htmlFor: "autocompleteInput",
451
+ id: "autocompleteLabel"
452
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
453
+ id: "autocompleteInput"
454
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
455
+ items: items,
456
+ selectedItemIds: [],
457
+ "aria-labelledby": "autocompleteLabel"
458
+ })));
459
+ };
460
+
461
+ exports.RenderingTheMenuOutsideAnOverlay = RenderingTheMenuOutsideAnOverlay;
462
+
463
+ const CustomOverlayMenuAnchor = () => {
464
+ const menuAnchorRef = (0, _react.useRef)(null);
465
+ const anchorWrapperStyles = {
466
+ display: 'flex',
467
+ alignItems: 'center',
468
+ flexGrow: 1,
469
+ flexShrink: 0,
470
+ flexBasis: '25%',
471
+ border: '1px solid black',
472
+ padding: '1em'
473
+ };
474
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
475
+ as: "label",
476
+ htmlFor: "autocompleteInput",
477
+ id: "autocompleteLabel"
478
+ }, "Pick labels"), /*#__PURE__*/_react.default.createElement(_.Box, _extends({}, anchorWrapperStyles, {
479
+ ref: menuAnchorRef
480
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
481
+ as: _.TextInput,
482
+ id: "autocompleteInput",
483
+ sx: {
484
+ border: '0',
485
+ padding: '0',
486
+ boxShadow: 'none',
487
+ ':focus-within': {
488
+ border: '0',
489
+ boxShadow: 'none'
490
+ }
491
+ }
492
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, {
493
+ menuAnchorRef: menuAnchorRef
494
+ }, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
495
+ items: items,
496
+ selectedItemIds: [],
497
+ "aria-labelledby": "autocompleteLabel"
498
+ })))), /*#__PURE__*/_react.default.createElement(_.Text, {
499
+ fontSize: 0,
500
+ display: "block",
501
+ color: "fg.subtle",
502
+ mt: 2
503
+ }, "The overlay menu's position is anchored to the div with the black border instead of to the text input"));
504
+ };
505
+
506
+ exports.CustomOverlayMenuAnchor = CustomOverlayMenuAnchor;
507
+
508
+ const WithCustomOverlayProps = () => {
509
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_.Box, {
510
+ as: "label",
511
+ display: "block",
512
+ htmlFor: "autocompleteInput",
513
+ id: "autocompleteLabel"
514
+ }, "Pick an option"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
515
+ id: "autocompleteInput"
516
+ }), /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Overlay, {
517
+ overlayProps: {
518
+ width: 'large',
519
+ height: 'xsmall'
520
+ }
521
+ }, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
522
+ items: items,
523
+ selectedItemIds: [],
524
+ "aria-labelledby": "autocompleteLabel"
525
+ }))));
526
+ };
527
+
528
+ exports.WithCustomOverlayProps = WithCustomOverlayProps;
529
+
530
+ const InOverlayWithCustomScrollContainerRef = () => {
531
+ const scrollContainerRef = (0, _react.useRef)(null);
532
+ const inputRef = (0, _react.useRef)(null);
533
+ const [isOpen, setIsOpen] = (0, _react.useState)(false);
534
+
535
+ const handleOpen = () => {
536
+ setIsOpen(true);
537
+ inputRef.current && inputRef.current.focus();
538
+ };
539
+
540
+ return /*#__PURE__*/_react.default.createElement(_AnchoredOverlay.AnchoredOverlay, {
541
+ open: isOpen,
542
+ onOpen: handleOpen,
543
+ onClose: () => setIsOpen(false),
544
+ width: "large",
545
+ height: "xsmall",
546
+ focusTrapSettings: {
547
+ initialFocusRef: inputRef
548
+ },
549
+ side: "inside-top",
550
+ renderAnchor: props => /*#__PURE__*/_react.default.createElement(_Button.ButtonInvisible, props, "open overlay")
551
+ }, /*#__PURE__*/_react.default.createElement(_.Box, {
552
+ as: "label",
553
+ display: "block",
554
+ htmlFor: "autocompleteInput",
555
+ id: "autocompleteLabel",
556
+ sx: {
557
+ // visually hides this label for sighted users
558
+ position: 'absolute',
559
+ width: '1px',
560
+ height: '1px',
561
+ padding: '0',
562
+ margin: '-1px',
563
+ overflow: 'hidden',
564
+ clip: 'rect(0, 0, 0, 0)',
565
+ whiteSpace: 'nowrap',
566
+ borderWidth: '0'
567
+ }
568
+ }, "Pick options"), /*#__PURE__*/_react.default.createElement(_Autocomplete.default, null, /*#__PURE__*/_react.default.createElement(_.Box, {
569
+ display: "flex",
570
+ flexDirection: "column",
571
+ height: "100%"
572
+ }, /*#__PURE__*/_react.default.createElement(_.Box, {
573
+ paddingX: "3",
574
+ paddingY: "1",
575
+ borderWidth: 0,
576
+ borderBottomWidth: 1,
577
+ borderColor: "border.default",
578
+ borderStyle: "solid"
579
+ }, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Input, {
580
+ block: true,
581
+ as: _.TextInput,
582
+ ref: inputRef,
583
+ id: "autocompleteInput",
584
+ sx: {
585
+ display: 'flex',
586
+ border: '0',
587
+ padding: '0',
588
+ boxShadow: 'none',
589
+ ':focus-within': {
590
+ border: '0',
591
+ boxShadow: 'none'
592
+ }
593
+ }
594
+ })), /*#__PURE__*/_react.default.createElement(_.Box, {
595
+ overflow: "auto",
596
+ flexGrow: 1,
597
+ ref: scrollContainerRef
598
+ }, /*#__PURE__*/_react.default.createElement(_Autocomplete.default.Menu, {
599
+ items: items,
600
+ selectedItemIds: [] // onSelectedChange={onSelectedChange}
601
+ ,
602
+ customScrollContainerRef: scrollContainerRef,
603
+ "aria-labelledby": "autocompleteLabel"
604
+ })))));
605
+ };
606
+
607
+ exports.InOverlayWithCustomScrollContainerRef = InOverlayWithCustomScrollContainerRef;
608
+ InOverlayWithCustomScrollContainerRef.displayName = "InOverlayWithCustomScrollContainerRef";
@@ -0,0 +1,3 @@
1
+ export declare type MandateProps<T extends unknown, K extends keyof T> = Omit<T, K> & {
2
+ [MK in K]-?: NonNullable<T[MK]>;
3
+ };
@@ -0,0 +1 @@
1
+ "use strict";
@@ -2,3 +2,4 @@ export * from './AriaRole';
2
2
  export * from './ComponentProps';
3
3
  export * from './Flatten';
4
4
  export * from './Merge';
5
+ export * from './MandateProps';
@@ -54,4 +54,17 @@ Object.keys(_Merge).forEach(function (key) {
54
54
  return _Merge[key];
55
55
  }
56
56
  });
57
+ });
58
+
59
+ var _MandateProps = require("./MandateProps");
60
+
61
+ Object.keys(_MandateProps).forEach(function (key) {
62
+ if (key === "default" || key === "__esModule") return;
63
+ if (key in exports && exports[key] === _MandateProps[key]) return;
64
+ Object.defineProperty(exports, key, {
65
+ enumerable: true,
66
+ get: function () {
67
+ return _MandateProps[key];
68
+ }
69
+ });
57
70
  });
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { OverlayProps } from '../Overlay';
3
3
  import { FocusTrapHookSettings } from '../hooks/useFocusTrap';
4
4
  import { FocusZoneHookSettings } from '../hooks/useFocusZone';
5
+ import { PositionSettings } from '../behaviors/anchoredPosition';
5
6
  interface AnchoredOverlayPropsWithAnchor {
6
7
  /**
7
8
  * A custom function component used to render the anchor element.
@@ -52,7 +53,7 @@ interface AnchoredOverlayBaseProps extends Pick<OverlayProps, 'height' | 'width'
52
53
  */
53
54
  focusZoneSettings?: Partial<FocusZoneHookSettings>;
54
55
  }
55
- export declare type AnchoredOverlayProps = AnchoredOverlayBaseProps & (AnchoredOverlayPropsWithAnchor | AnchoredOverlayPropsWithoutAnchor);
56
+ export declare type AnchoredOverlayProps = AnchoredOverlayBaseProps & (AnchoredOverlayPropsWithAnchor | AnchoredOverlayPropsWithoutAnchor) & Partial<Pick<PositionSettings, 'align' | 'side'>>;
56
57
  /**
57
58
  * An `AnchoredOverlay` provides an anchor that will open a floating overlay positioned relative to the anchor.
58
59
  * The overlay can be opened and navigated using keyboard or mouse.
@@ -22,7 +22,9 @@ export const AnchoredOverlay = ({
22
22
  width,
23
23
  overlayProps,
24
24
  focusTrapSettings,
25
- focusZoneSettings
25
+ focusZoneSettings,
26
+ side,
27
+ align
26
28
  }) => {
27
29
  const anchorRef = useProvidedRefOrCreate(externalAnchorRef);
28
30
  const [overlayRef, updateOverlayRef] = useRenderForcingRef();
@@ -52,7 +54,9 @@ export const AnchoredOverlay = ({
52
54
  position
53
55
  } = useAnchoredPosition({
54
56
  anchorElementRef: anchorRef,
55
- floatingElementRef: overlayRef
57
+ floatingElementRef: overlayRef,
58
+ side,
59
+ align
56
60
  }, [overlayRef.current]);
57
61
  useEffect(() => {
58
62
  // ensure overlay ref gets cleared when closed, so position can reset between closing/re-opening
@@ -93,4 +97,8 @@ export const AnchoredOverlay = ({
93
97
  anchorSide: position === null || position === void 0 ? void 0 : position.anchorSide
94
98
  }, overlayProps), children) : null);
95
99
  };
96
- AnchoredOverlay.displayName = 'AnchoredOverlay';
100
+ AnchoredOverlay.displayName = 'AnchoredOverlay';
101
+ AnchoredOverlay.defaultProps = {
102
+ side: 'outside-bottom',
103
+ align: 'start'
104
+ };