@atlaskit/react-select 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cjs/emotion/components/containers.js +111 -0
  3. package/dist/cjs/emotion/components/control.js +110 -0
  4. package/dist/cjs/emotion/components/group.js +71 -0
  5. package/dist/cjs/emotion/components/index.js +52 -0
  6. package/dist/cjs/emotion/components/indicators.js +137 -0
  7. package/dist/cjs/emotion/components/input.js +94 -0
  8. package/dist/cjs/emotion/components/internal/a11y-text.js +36 -0
  9. package/dist/cjs/emotion/components/internal/dummy-input.js +44 -0
  10. package/dist/cjs/emotion/components/internal/index.js +34 -0
  11. package/dist/cjs/emotion/components/internal/notify-open-layer-observer.js +21 -0
  12. package/dist/cjs/emotion/components/internal/required-input.js +43 -0
  13. package/dist/cjs/emotion/components/internal/scroll-manager.js +57 -0
  14. package/dist/cjs/emotion/components/internal/use-scroll-capture.js +132 -0
  15. package/dist/cjs/emotion/components/internal/use-scroll-lock.js +149 -0
  16. package/dist/cjs/emotion/components/live-region.js +182 -0
  17. package/dist/cjs/emotion/components/menu.js +456 -0
  18. package/dist/cjs/emotion/components/multi-value.js +224 -0
  19. package/dist/cjs/emotion/components/option.js +82 -0
  20. package/dist/cjs/emotion/components/placeholder.js +34 -0
  21. package/dist/cjs/emotion/components/single-value.js +40 -0
  22. package/dist/es2019/emotion/components/containers.js +109 -0
  23. package/dist/es2019/emotion/components/control.js +107 -0
  24. package/dist/es2019/emotion/components/group.js +59 -0
  25. package/dist/es2019/emotion/components/index.js +41 -0
  26. package/dist/es2019/emotion/components/indicators.js +128 -0
  27. package/dist/es2019/emotion/components/input.js +86 -0
  28. package/dist/es2019/emotion/components/internal/a11y-text.js +27 -0
  29. package/dist/es2019/emotion/components/internal/dummy-input.js +37 -0
  30. package/dist/es2019/emotion/components/internal/index.js +4 -0
  31. package/dist/es2019/emotion/components/internal/notify-open-layer-observer.js +16 -0
  32. package/dist/es2019/emotion/components/internal/required-input.js +35 -0
  33. package/dist/es2019/emotion/components/internal/scroll-manager.js +49 -0
  34. package/dist/es2019/emotion/components/internal/use-scroll-capture.js +128 -0
  35. package/dist/es2019/emotion/components/internal/use-scroll-lock.js +143 -0
  36. package/dist/es2019/emotion/components/live-region.js +178 -0
  37. package/dist/es2019/emotion/components/menu.js +450 -0
  38. package/dist/es2019/emotion/components/multi-value.js +227 -0
  39. package/dist/es2019/emotion/components/option.js +78 -0
  40. package/dist/es2019/emotion/components/placeholder.js +28 -0
  41. package/dist/es2019/emotion/components/single-value.js +34 -0
  42. package/dist/esm/emotion/components/containers.js +105 -0
  43. package/dist/esm/emotion/components/control.js +103 -0
  44. package/dist/esm/emotion/components/group.js +65 -0
  45. package/dist/esm/emotion/components/index.js +43 -0
  46. package/dist/esm/emotion/components/indicators.js +132 -0
  47. package/dist/esm/emotion/components/input.js +89 -0
  48. package/dist/esm/emotion/components/internal/a11y-text.js +29 -0
  49. package/dist/esm/emotion/components/internal/dummy-input.js +38 -0
  50. package/dist/esm/emotion/components/internal/index.js +4 -0
  51. package/dist/esm/emotion/components/internal/notify-open-layer-observer.js +15 -0
  52. package/dist/esm/emotion/components/internal/required-input.js +36 -0
  53. package/dist/esm/emotion/components/internal/scroll-manager.js +49 -0
  54. package/dist/esm/emotion/components/internal/use-scroll-capture.js +126 -0
  55. package/dist/esm/emotion/components/internal/use-scroll-lock.js +143 -0
  56. package/dist/esm/emotion/components/live-region.js +175 -0
  57. package/dist/esm/emotion/components/menu.js +454 -0
  58. package/dist/esm/emotion/components/multi-value.js +217 -0
  59. package/dist/esm/emotion/components/option.js +75 -0
  60. package/dist/esm/emotion/components/placeholder.js +27 -0
  61. package/dist/esm/emotion/components/single-value.js +33 -0
  62. package/dist/types/emotion/components/containers.d.ts +54 -0
  63. package/dist/types/emotion/components/control.d.ts +42 -0
  64. package/dist/types/emotion/components/group.d.ts +52 -0
  65. package/dist/types/emotion/components/index.d.ts +67 -0
  66. package/dist/types/emotion/components/indicators.d.ts +73 -0
  67. package/dist/types/emotion/components/input.d.ts +37 -0
  68. package/dist/types/emotion/components/internal/a11y-text.d.ts +8 -0
  69. package/dist/types/emotion/components/internal/dummy-input.d.ts +9 -0
  70. package/dist/types/emotion/components/internal/index.d.ts +4 -0
  71. package/dist/types/emotion/components/internal/notify-open-layer-observer.d.ts +11 -0
  72. package/dist/types/emotion/components/internal/required-input.d.ts +10 -0
  73. package/dist/types/emotion/components/internal/scroll-manager.d.ts +17 -0
  74. package/dist/types/emotion/components/internal/use-scroll-capture.d.ts +12 -0
  75. package/dist/types/emotion/components/internal/use-scroll-lock.d.ts +9 -0
  76. package/dist/types/emotion/components/live-region.d.ts +25 -0
  77. package/dist/types/emotion/components/menu.d.ts +116 -0
  78. package/dist/types/emotion/components/multi-value.d.ts +47 -0
  79. package/dist/types/emotion/components/option.d.ts +49 -0
  80. package/dist/types/emotion/components/placeholder.d.ts +22 -0
  81. package/dist/types/emotion/components/single-value.d.ts +28 -0
  82. package/dist/types-ts4.5/emotion/components/containers.d.ts +54 -0
  83. package/dist/types-ts4.5/emotion/components/control.d.ts +42 -0
  84. package/dist/types-ts4.5/emotion/components/group.d.ts +52 -0
  85. package/dist/types-ts4.5/emotion/components/index.d.ts +67 -0
  86. package/dist/types-ts4.5/emotion/components/indicators.d.ts +73 -0
  87. package/dist/types-ts4.5/emotion/components/input.d.ts +37 -0
  88. package/dist/types-ts4.5/emotion/components/internal/a11y-text.d.ts +8 -0
  89. package/dist/types-ts4.5/emotion/components/internal/dummy-input.d.ts +9 -0
  90. package/dist/types-ts4.5/emotion/components/internal/index.d.ts +4 -0
  91. package/dist/types-ts4.5/emotion/components/internal/notify-open-layer-observer.d.ts +11 -0
  92. package/dist/types-ts4.5/emotion/components/internal/required-input.d.ts +10 -0
  93. package/dist/types-ts4.5/emotion/components/internal/scroll-manager.d.ts +17 -0
  94. package/dist/types-ts4.5/emotion/components/internal/use-scroll-capture.d.ts +12 -0
  95. package/dist/types-ts4.5/emotion/components/internal/use-scroll-lock.d.ts +9 -0
  96. package/dist/types-ts4.5/emotion/components/live-region.d.ts +25 -0
  97. package/dist/types-ts4.5/emotion/components/menu.d.ts +116 -0
  98. package/dist/types-ts4.5/emotion/components/multi-value.d.ts +47 -0
  99. package/dist/types-ts4.5/emotion/components/option.d.ts +49 -0
  100. package/dist/types-ts4.5/emotion/components/placeholder.d.ts +22 -0
  101. package/dist/types-ts4.5/emotion/components/single-value.d.ts +28 -0
  102. package/package.json +1 -1
@@ -0,0 +1,450 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ /**
3
+ * @jsxRuntime classic
4
+ * @jsx jsx
5
+ */
6
+ import { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';
7
+ import { jsx } from '@emotion/react';
8
+ import { autoUpdate } from '@floating-ui/dom';
9
+ import { createPortal } from 'react-dom';
10
+ import useLayoutEffect from 'use-isomorphic-layout-effect';
11
+ import { fg } from '@atlaskit/platform-feature-flags';
12
+ import { Text } from '@atlaskit/primitives';
13
+ import { animatedScrollTo, getBoundingClientObj, getScrollParent, getScrollTop, getStyleProps, normalizedHeight, scrollTo } from '../../utils';
14
+
15
+ // ==============================
16
+ // Menu
17
+ // ==============================
18
+
19
+ // Get Menu Placement
20
+ // ------------------------------
21
+
22
+ function getMenuPlacement({
23
+ maxHeight: preferredMaxHeight,
24
+ menuEl,
25
+ minHeight,
26
+ placement: preferredPlacement,
27
+ shouldScroll,
28
+ isFixedPosition,
29
+ controlHeight
30
+ }) {
31
+ const scrollParent = getScrollParent(menuEl);
32
+ const defaultState = {
33
+ placement: 'bottom',
34
+ maxHeight: preferredMaxHeight
35
+ };
36
+
37
+ // something went wrong, return default state
38
+ if (!menuEl || !menuEl.offsetParent) {
39
+ return defaultState;
40
+ }
41
+
42
+ // we can't trust `scrollParent.scrollHeight` --> it may increase when
43
+ // the menu is rendered
44
+ const {
45
+ height: scrollHeight,
46
+ top: scrollParentTop
47
+ } = scrollParent.getBoundingClientRect();
48
+ const {
49
+ bottom: menuBottom,
50
+ height: menuHeight,
51
+ top: menuTop
52
+ } = menuEl.getBoundingClientRect();
53
+ const {
54
+ top: containerTop
55
+ } = menuEl.offsetParent.getBoundingClientRect();
56
+ const viewHeight = isFixedPosition ? window.innerHeight : normalizedHeight(scrollParent);
57
+ const scrollTop = getScrollTop(scrollParent);
58
+ // use menuTop - scrollParentTop for the actual top space of menu in the scroll container
59
+ const menuTopFromParent = fg('design-system-select-fix-placement') ? menuTop - scrollParentTop : menuTop;
60
+ const marginBottom = parseInt(getComputedStyle(menuEl).marginBottom, 10);
61
+ const marginTop = parseInt(getComputedStyle(menuEl).marginTop, 10);
62
+ const viewSpaceAbove = containerTop - marginTop;
63
+ const viewSpaceBelow = viewHeight - menuTopFromParent;
64
+ const scrollSpaceAbove = viewSpaceAbove + scrollTop;
65
+ const scrollSpaceBelow = scrollHeight - scrollTop - menuTopFromParent;
66
+ const scrollDown = menuBottom - viewHeight + scrollTop + marginBottom;
67
+ const scrollUp = scrollTop + menuTop - marginTop;
68
+ const scrollDuration = 160;
69
+ switch (preferredPlacement) {
70
+ case 'auto':
71
+ case 'bottom':
72
+ // 1: the menu will fit, do nothing
73
+ if (viewSpaceBelow >= menuHeight) {
74
+ return {
75
+ placement: 'bottom',
76
+ maxHeight: preferredMaxHeight
77
+ };
78
+ }
79
+
80
+ // 2: the menu will fit, if scrolled
81
+ if (scrollSpaceBelow >= menuHeight && !isFixedPosition) {
82
+ if (shouldScroll) {
83
+ animatedScrollTo(scrollParent, scrollDown, scrollDuration);
84
+ }
85
+ return {
86
+ placement: 'bottom',
87
+ maxHeight: preferredMaxHeight
88
+ };
89
+ }
90
+
91
+ // 3: the menu will fit, if constrained
92
+ if (!isFixedPosition && scrollSpaceBelow >= minHeight || isFixedPosition && viewSpaceBelow >= minHeight) {
93
+ if (shouldScroll) {
94
+ animatedScrollTo(scrollParent, scrollDown, scrollDuration);
95
+ }
96
+
97
+ // we want to provide as much of the menu as possible to the user,
98
+ // so give them whatever is available below rather than the minHeight.
99
+ const constrainedHeight = isFixedPosition ? viewSpaceBelow - marginBottom : scrollSpaceBelow - marginBottom;
100
+ return {
101
+ placement: 'bottom',
102
+ maxHeight: constrainedHeight
103
+ };
104
+ }
105
+
106
+ // 4. Forked beviour when there isn't enough space below
107
+
108
+ // AUTO: flip the menu, render above
109
+ if (preferredPlacement === 'auto' || isFixedPosition) {
110
+ // may need to be constrained after flipping
111
+ let constrainedHeight = preferredMaxHeight;
112
+ const spaceAbove = isFixedPosition ? viewSpaceAbove : scrollSpaceAbove;
113
+ if (spaceAbove >= minHeight) {
114
+ constrainedHeight = Math.min(spaceAbove - marginBottom - controlHeight, preferredMaxHeight);
115
+ }
116
+ return {
117
+ placement: 'top',
118
+ maxHeight: constrainedHeight
119
+ };
120
+ }
121
+
122
+ // BOTTOM: allow browser to increase scrollable area and immediately set scroll
123
+ if (preferredPlacement === 'bottom') {
124
+ if (shouldScroll) {
125
+ scrollTo(scrollParent, scrollDown);
126
+ }
127
+ return {
128
+ placement: 'bottom',
129
+ maxHeight: preferredMaxHeight
130
+ };
131
+ }
132
+ break;
133
+ case 'top':
134
+ // 1: the menu will fit, do nothing
135
+ if (viewSpaceAbove >= menuHeight) {
136
+ return {
137
+ placement: 'top',
138
+ maxHeight: preferredMaxHeight
139
+ };
140
+ }
141
+
142
+ // 2: the menu will fit, if scrolled
143
+ if (scrollSpaceAbove >= menuHeight && !isFixedPosition) {
144
+ if (shouldScroll) {
145
+ animatedScrollTo(scrollParent, scrollUp, scrollDuration);
146
+ }
147
+ return {
148
+ placement: 'top',
149
+ maxHeight: preferredMaxHeight
150
+ };
151
+ }
152
+
153
+ // 3: the menu will fit, if constrained
154
+ if (!isFixedPosition && scrollSpaceAbove >= minHeight || isFixedPosition && viewSpaceAbove >= minHeight) {
155
+ let constrainedHeight = preferredMaxHeight;
156
+
157
+ // we want to provide as much of the menu as possible to the user,
158
+ // so give them whatever is available below rather than the minHeight.
159
+ if (!isFixedPosition && scrollSpaceAbove >= minHeight || isFixedPosition && viewSpaceAbove >= minHeight) {
160
+ constrainedHeight = isFixedPosition ? viewSpaceAbove - marginTop : scrollSpaceAbove - marginTop;
161
+ }
162
+ if (shouldScroll) {
163
+ animatedScrollTo(scrollParent, scrollUp, scrollDuration);
164
+ }
165
+ return {
166
+ placement: 'top',
167
+ maxHeight: constrainedHeight
168
+ };
169
+ }
170
+
171
+ // 4. not enough space, the browser WILL NOT increase scrollable area when
172
+ // absolutely positioned element rendered above the viewport (only below).
173
+ // Flip the menu, render below
174
+ return {
175
+ placement: 'bottom',
176
+ maxHeight: preferredMaxHeight
177
+ };
178
+ default:
179
+ throw new Error(`Invalid placement provided "${preferredPlacement}".`);
180
+ }
181
+ return defaultState;
182
+ }
183
+
184
+ // Menu Component
185
+ // ------------------------------
186
+
187
+ function alignToControl(placement) {
188
+ const placementToCSSProp = {
189
+ bottom: 'top',
190
+ top: 'bottom'
191
+ };
192
+ return placement ? placementToCSSProp[placement] : 'bottom';
193
+ }
194
+ const coercePlacement = p => p === 'auto' ? 'bottom' : p;
195
+ export const menuCSS = ({
196
+ placement
197
+ }) => ({
198
+ label: 'menu',
199
+ [alignToControl(placement)]: '100%',
200
+ position: 'absolute',
201
+ width: '100%',
202
+ zIndex: 1,
203
+ borderRadius: "var(--ds-border-radius, 4px)",
204
+ marginBottom: "var(--ds-space-100, 8px)",
205
+ marginTop: "var(--ds-space-100, 8px)",
206
+ backgroundColor: "var(--ds-surface-overlay, white)",
207
+ boxShadow: "var(--ds-shadow-overlay, 0 0 0 1px hsl(0deg 0% 0% / 10%), 0 4px 11px hsl(0deg 0% 0% / 10%))"
208
+ });
209
+ const PortalPlacementContext = /*#__PURE__*/createContext(null);
210
+
211
+ // NOTE: internal only
212
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
213
+ export const MenuPlacer = props => {
214
+ const {
215
+ children,
216
+ minMenuHeight,
217
+ maxMenuHeight,
218
+ menuPlacement,
219
+ menuPosition,
220
+ menuShouldScrollIntoView
221
+ } = props;
222
+ const {
223
+ setPortalPlacement
224
+ } = useContext(PortalPlacementContext) || {};
225
+ const ref = useRef(null);
226
+ const [maxHeight, setMaxHeight] = useState(maxMenuHeight);
227
+ const [placement, setPlacement] = useState(null);
228
+ // The minimum height of the control
229
+ const controlHeight = 38;
230
+ useLayoutEffect(() => {
231
+ const menuEl = ref.current;
232
+ if (!menuEl) {
233
+ return;
234
+ }
235
+
236
+ // DO NOT scroll if position is fixed
237
+ const isFixedPosition = menuPosition === 'fixed';
238
+ const shouldScroll = menuShouldScrollIntoView && !isFixedPosition;
239
+ const state = getMenuPlacement({
240
+ maxHeight: maxMenuHeight,
241
+ menuEl,
242
+ minHeight: minMenuHeight,
243
+ placement: menuPlacement,
244
+ shouldScroll,
245
+ isFixedPosition,
246
+ controlHeight
247
+ });
248
+ setMaxHeight(state.maxHeight);
249
+ setPlacement(state.placement);
250
+ setPortalPlacement === null || setPortalPlacement === void 0 ? void 0 : setPortalPlacement(state.placement);
251
+ }, [maxMenuHeight, menuPlacement, menuPosition, menuShouldScrollIntoView, minMenuHeight, setPortalPlacement, controlHeight]);
252
+ return children({
253
+ ref,
254
+ placerProps: {
255
+ ...props,
256
+ placement: placement || coercePlacement(menuPlacement),
257
+ maxHeight
258
+ }
259
+ });
260
+ };
261
+ const Menu = props => {
262
+ const {
263
+ children,
264
+ innerRef,
265
+ innerProps
266
+ } = props;
267
+ return jsx("div", _extends({}, getStyleProps(props, 'menu', {
268
+ menu: true
269
+ }), {
270
+ ref: innerRef
271
+ }, innerProps), children);
272
+ };
273
+
274
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
275
+ export default Menu;
276
+
277
+ // ==============================
278
+ // Menu List
279
+ // ==============================
280
+
281
+ export const menuListCSS = ({
282
+ maxHeight
283
+ }) => ({
284
+ maxHeight,
285
+ overflowY: 'auto',
286
+ position: 'relative',
287
+ // required for offset[Height, Top] > keyboard scroll
288
+ WebkitOverflowScrolling: 'touch',
289
+ paddingTop: "var(--ds-space-100, 8px)",
290
+ paddingBottom: "var(--ds-space-100, 8px)"
291
+ });
292
+
293
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
294
+ export const MenuList = props => {
295
+ const {
296
+ children,
297
+ innerProps,
298
+ innerRef,
299
+ isMulti
300
+ } = props;
301
+ return jsx("div", _extends({}, getStyleProps(props, 'menuList', {
302
+ 'menu-list': true,
303
+ 'menu-list--is-multi': isMulti
304
+ }), {
305
+ ref: innerRef
306
+ }, innerProps, {
307
+ tabIndex: -1
308
+ }), children);
309
+ };
310
+
311
+ // ==============================
312
+ // Menu Notices
313
+ // ==============================
314
+
315
+ const noticeCSS = ({}) => ({
316
+ textAlign: 'center',
317
+ padding: `${"var(--ds-space-100, 8px)"} ${"var(--ds-space-150, 12px)"}`
318
+ });
319
+ export const noOptionsMessageCSS = noticeCSS;
320
+ export const loadingMessageCSS = noticeCSS;
321
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
322
+ export const NoOptionsMessage = ({
323
+ children = 'No options',
324
+ innerProps,
325
+ ...restProps
326
+ }) => {
327
+ return jsx("div", _extends({}, getStyleProps({
328
+ ...restProps,
329
+ children,
330
+ innerProps
331
+ }, 'noOptionsMessage', {
332
+ 'menu-notice': true,
333
+ 'menu-notice--no-options': true
334
+ }), {
335
+ // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
336
+ role: "option"
337
+ }, innerProps), jsx(Text, {
338
+ color: "color.text.subtle"
339
+ }, children));
340
+ };
341
+
342
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
343
+ export const LoadingMessage = ({
344
+ children = 'Loading...',
345
+ innerProps,
346
+ ...restProps
347
+ }) => {
348
+ return jsx("div", _extends({}, getStyleProps({
349
+ ...restProps,
350
+ children,
351
+ innerProps
352
+ }, 'loadingMessage', {
353
+ 'menu-notice': true,
354
+ 'menu-notice--loading': true
355
+ }), innerProps, {
356
+ // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
357
+ role: "option"
358
+ }), jsx(Text, {
359
+ color: "color.text.subtle"
360
+ }, children));
361
+ };
362
+
363
+ // ==============================
364
+ // Menu Portal
365
+ // ==============================
366
+
367
+ export const menuPortalCSS = ({
368
+ rect,
369
+ offset,
370
+ position
371
+ }) => ({
372
+ left: rect.left,
373
+ position: position,
374
+ top: offset,
375
+ width: rect.width,
376
+ zIndex: 1
377
+ });
378
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
379
+ export const MenuPortal = props => {
380
+ const {
381
+ appendTo,
382
+ children,
383
+ controlElement,
384
+ innerProps,
385
+ menuPlacement,
386
+ menuPosition
387
+ } = props;
388
+ const menuPortalRef = useRef(null);
389
+ const cleanupRef = useRef(null);
390
+ const [placement, setPortalPlacement] = useState(coercePlacement(menuPlacement));
391
+ const portalPlacementContext = useMemo(() => ({
392
+ setPortalPlacement
393
+ }), []);
394
+ const [computedPosition, setComputedPosition] = useState(null);
395
+ const updateComputedPosition = useCallback(() => {
396
+ if (!controlElement) {
397
+ return;
398
+ }
399
+ const rect = getBoundingClientObj(controlElement);
400
+ const scrollDistance = menuPosition === 'fixed' ? 0 : window.pageYOffset;
401
+ const offset = rect[placement] + scrollDistance;
402
+ if (offset !== (computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.offset) || rect.left !== (computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.left) || rect.width !== (computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.width)) {
403
+ setComputedPosition({
404
+ offset,
405
+ rect
406
+ });
407
+ }
408
+ }, [controlElement, menuPosition, placement, computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.offset, computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.left, computedPosition === null || computedPosition === void 0 ? void 0 : computedPosition.rect.width]);
409
+ useLayoutEffect(() => {
410
+ updateComputedPosition();
411
+ }, [updateComputedPosition]);
412
+ const runAutoUpdate = useCallback(() => {
413
+ if (typeof cleanupRef.current === 'function') {
414
+ cleanupRef.current();
415
+ cleanupRef.current = null;
416
+ }
417
+ if (controlElement && menuPortalRef.current) {
418
+ cleanupRef.current = autoUpdate(controlElement, menuPortalRef.current, updateComputedPosition, {
419
+ elementResize: 'ResizeObserver' in window
420
+ });
421
+ }
422
+ }, [controlElement, updateComputedPosition]);
423
+ useLayoutEffect(() => {
424
+ runAutoUpdate();
425
+ }, [runAutoUpdate]);
426
+ const setMenuPortalElement = useCallback(menuPortalElement => {
427
+ menuPortalRef.current = menuPortalElement;
428
+ runAutoUpdate();
429
+ }, [runAutoUpdate]);
430
+
431
+ // bail early if required elements aren't present
432
+ if (!appendTo && menuPosition !== 'fixed' || !computedPosition) {
433
+ return null;
434
+ }
435
+
436
+ // same wrapper element whether fixed or portalled
437
+ const menuWrapper = jsx("div", _extends({
438
+ ref: setMenuPortalElement
439
+ }, getStyleProps({
440
+ ...props,
441
+ offset: computedPosition.offset,
442
+ position: menuPosition,
443
+ rect: computedPosition.rect
444
+ }, 'menuPortal', {
445
+ 'menu-portal': true
446
+ }), innerProps), children);
447
+ return jsx(PortalPlacementContext.Provider, {
448
+ value: portalPlacementContext
449
+ }, appendTo ? /*#__PURE__*/createPortal(menuWrapper, appendTo) : menuWrapper);
450
+ };
@@ -0,0 +1,227 @@
1
+ /**
2
+ * @jsxRuntime classic
3
+ * @jsx jsx
4
+ */
5
+
6
+ import { css, jsx } from '@emotion/react';
7
+ import LegacySelectClearIcon from '@atlaskit/icon/glyph/select-clear';
8
+ import CrossIcon from '@atlaskit/icon/utility/cross';
9
+ import { fg } from '@atlaskit/platform-feature-flags';
10
+ import { Inline, xcss } from '@atlaskit/primitives';
11
+ import { getStyleProps } from '../../utils';
12
+ export const multiValueCSS = ({
13
+ isDisabled,
14
+ isFocused
15
+ }) => {
16
+ let backgroundColor;
17
+ let color;
18
+ if (isDisabled) {
19
+ // Use the basic neutral background so it is slightly separate from the
20
+ // field's background
21
+ backgroundColor = "var(--ds-background-neutral, #091E420F)";
22
+ color = "var(--ds-text-disabled, #091E424F)";
23
+ } else if (isFocused) {
24
+ backgroundColor = "var(--ds-background-selected, #E9F2FF)";
25
+ color = "var(--ds-text-selected, hsl(0, 0%, 20%))";
26
+ } else {
27
+ backgroundColor = fg('platform-component-visual-refresh') ? "var(--ds-background-neutral-subtle-hovered, #091E420F)" : "var(--ds-background-neutral, #091E420F)";
28
+ color = "var(--ds-text, hsl(0, 0%, 20%))";
29
+ }
30
+ return {
31
+ label: 'multiValue',
32
+ display: 'flex',
33
+ minWidth: 0,
34
+ // resolves flex/text-overflow bug
35
+ margin: "var(--ds-space-025, 2px)",
36
+ borderRadius: "var(--ds-border-radius-050, 2px)",
37
+ backgroundColor,
38
+ boxShadow: isFocused ? `0 0 0 2px ${"var(--ds-surface, transparent)"}, 0 0 0 4px ${"var(--ds-border-focused, transparent)"}` : 'none',
39
+ maxWidth: '100%',
40
+ '@media screen and (-ms-high-contrast: active)': {
41
+ border: isFocused ? '1px solid transparent' : 'none'
42
+ },
43
+ color,
44
+ ...(fg('platform-component-visual-refresh') && {
45
+ borderRadius: "var(--ds-border-radius-100, 4px)",
46
+ // Hardcode this color for visual refresh as there is no token color yet
47
+ borderColor: '#B7B9BE',
48
+ borderWidth: "var(--ds-border-width, 1px)",
49
+ borderStyle: 'solid',
50
+ backgroundColor: "var(--ds-background-input, #FFFFFF)"
51
+ })
52
+ };
53
+ };
54
+ export const multiValueLabelCSS = ({
55
+ cropWithEllipsis,
56
+ isDisabled
57
+ }) => ({
58
+ overflow: 'hidden',
59
+ textOverflow: cropWithEllipsis || cropWithEllipsis === undefined ? 'ellipsis' : undefined,
60
+ whiteSpace: 'nowrap',
61
+ borderRadius: "var(--ds-border-radius-050, 2px)",
62
+ // eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
63
+ fontSize: '85%',
64
+ font: "var(--ds-font-body-UNSAFE_small, normal 400 12px/16px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
65
+ padding: "var(--ds-space-025, 2px)",
66
+ color: isDisabled ? "var(--ds-text-disabled, #091E424F)" : 'inherit',
67
+ paddingLeft: "var(--ds-space-075, 6px)",
68
+ ...(fg('platform-component-visual-refresh') && {
69
+ font: "var(--ds-font-body, normal 400 14px/20px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, \"Helvetica Neue\", sans-serif)",
70
+ paddingTop: 0,
71
+ paddingBottom: 0,
72
+ paddingLeft: "var(--ds-space-050, 4px)"
73
+ })
74
+ });
75
+ export const multiValueRemoveCSS = ({
76
+ isFocused
77
+ }) => ({
78
+ alignItems: 'center',
79
+ display: 'flex',
80
+ backgroundColor: isFocused ? "var(--ds-UNSAFE-transparent, transparent)" : undefined,
81
+ fill: isFocused ? "var(--ds-text-selected, #000)" : "var(--ds-text, #000)",
82
+ paddingLeft: "var(--ds-space-025, 2px)",
83
+ paddingRight: "var(--ds-space-025, 2px)",
84
+ borderRadius: '0px 2px 2px 0px',
85
+ // DSP-6470 we should style like Tag once we have the :has selector
86
+ ':hover': {
87
+ backgroundColor: "var(--ds-background-danger-hovered, #FFD5D2)",
88
+ fill: "var(--ds-text-danger, #000)"
89
+ },
90
+ ':active': {
91
+ backgroundColor: "var(--ds-background-danger-pressed, #FD9891)",
92
+ fill: "var(--ds-text-danger, #000)"
93
+ },
94
+ ...(fg('platform-component-visual-refresh') && {
95
+ backgroundColor: "var(--ds-background-neutral-subtle, #00000000)",
96
+ border: 'none',
97
+ alignItems: 'center',
98
+ justifyContent: 'center',
99
+ alignSelf: 'center',
100
+ appearance: 'none',
101
+ borderRadius: "var(--ds-border-radius, 4px)",
102
+ color: "var(--ds-text, #172B4D)",
103
+ padding: "var(--ds-space-025, 2px)",
104
+ marginRight: "var(--ds-space-025, 2px)",
105
+ ':focus-visible': {
106
+ outlineOffset: "var(--ds-space-negative-025, -2px)"
107
+ },
108
+ ':hover': {
109
+ backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
110
+ },
111
+ ':active': {
112
+ backgroundColor: "var(--ds-background-neutral-subtle-pressed, #091E4224)"
113
+ }
114
+ })
115
+ });
116
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
117
+ const MultiValueGeneric = ({
118
+ children,
119
+ innerProps
120
+ }) => jsx("div", innerProps, children);
121
+
122
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
123
+ export const MultiValueContainer = MultiValueGeneric;
124
+
125
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
126
+ export const MultiValueLabel = MultiValueGeneric;
127
+ const disabledStyles = css({
128
+ display: 'none'
129
+ });
130
+ const enabledStyles = css({
131
+ display: 'inherit'
132
+ });
133
+ const iconWrapperStyles = xcss({
134
+ padding: 'space.025'
135
+ });
136
+ const renderIcon = () => {
137
+ // eslint-disable-next-line @atlaskit/platform/ensure-feature-flag-prefix
138
+ if (fg('platform-component-visual-refresh')) {
139
+ return jsx(CrossIcon, {
140
+ label: "",
141
+ color: "currentColor"
142
+ });
143
+ }
144
+
145
+ // eslint-disable-next-line @atlaskit/platform/ensure-feature-flag-prefix
146
+ if (fg('platform-visual-refresh-icons-legacy-facade')) {
147
+ return jsx(Inline, {
148
+ xcss: iconWrapperStyles
149
+ }, jsx(CrossIcon, {
150
+ label: "",
151
+ color: "currentColor"
152
+ }));
153
+ }
154
+ return (
155
+ // eslint-disable-next-line @atlaskit/design-system/no-legacy-icons
156
+ jsx(LegacySelectClearIcon, {
157
+ label: "",
158
+ primaryColor: "transparent",
159
+ size: "small",
160
+ secondaryColor: "inherit"
161
+ })
162
+ );
163
+ };
164
+ export function MultiValueRemove({
165
+ isDisabled,
166
+ innerProps
167
+ }) {
168
+ return (
169
+ // The Remove button is intentionally excluded from the tab order, please avoid assigning a non-negative tabIndex to it. Context: https://hello.atlassian.net/wiki/spaces/A11YKB/pages/3031993460/Clear+Options+on+an+Input+Field
170
+ jsx("div", innerProps, jsx("div", {
171
+ css: isDisabled ? disabledStyles : enabledStyles,
172
+ "data-testid": isDisabled ? 'hide-clear-icon' : 'show-clear-icon'
173
+ }, renderIcon()))
174
+ );
175
+ }
176
+ const MultiValue = props => {
177
+ const {
178
+ children,
179
+ components,
180
+ data,
181
+ innerProps,
182
+ isDisabled,
183
+ removeProps,
184
+ selectProps
185
+ } = props;
186
+ const {
187
+ Container,
188
+ Label,
189
+ Remove
190
+ } = components;
191
+ const ariaLabel = typeof children === 'string' ? children : data.label;
192
+ return jsx(Container, {
193
+ data: data,
194
+ innerProps: {
195
+ ...getStyleProps(props, 'multiValue', {
196
+ 'multi-value': true,
197
+ 'multi-value--is-disabled': isDisabled
198
+ }),
199
+ ...innerProps
200
+ },
201
+ selectProps: selectProps
202
+ }, jsx(Label, {
203
+ data: data,
204
+ innerProps: {
205
+ ...getStyleProps(props, 'multiValueLabel', {
206
+ 'multi-value__label': true
207
+ })
208
+ },
209
+ selectProps: selectProps
210
+ }, children), jsx(Remove, {
211
+ data: data,
212
+ innerProps: {
213
+ ...getStyleProps(props, 'multiValueRemove', {
214
+ 'multi-value__remove': true
215
+ }),
216
+ role: 'button',
217
+ tabIndex: -1,
218
+ 'aria-label': `${ariaLabel || 'option'}, remove`,
219
+ ...removeProps
220
+ },
221
+ isDisabled: isDisabled,
222
+ selectProps: selectProps
223
+ }));
224
+ };
225
+
226
+ // eslint-disable-next-line @repo/internal/react/require-jsdoc
227
+ export default MultiValue;