@redsift/design-system 11.6.0-muiv5-alpha.5 → 11.6.0-muiv5-alpha.7

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 (150) hide show
  1. package/_internal/Alert2.js +182 -39
  2. package/_internal/AppBar.js +240 -29
  3. package/_internal/AppContainer.js +132 -86
  4. package/_internal/AppContent.js +84 -17
  5. package/_internal/Badge2.js +137 -4
  6. package/_internal/BreadcrumbItem.js +85 -3
  7. package/_internal/Breadcrumbs2.js +86 -21
  8. package/_internal/Button2.js +81 -20
  9. package/_internal/ButtonGroup.js +165 -25
  10. package/_internal/ButtonLink.js +74 -18
  11. package/_internal/Card2.js +151 -29
  12. package/_internal/CardActions.js +38 -3
  13. package/_internal/CardBody.js +36 -3
  14. package/_internal/CardHeader.js +77 -3
  15. package/_internal/Checkbox2.js +234 -58
  16. package/_internal/CheckboxGroup.js +182 -4
  17. package/_internal/ConditionalWrapper.js +11 -12
  18. package/_internal/DetailedCard.js +6912 -48
  19. package/_internal/DetailedCardCollapsibleSectionItems.js +58 -3
  20. package/_internal/DetailedCardHeader.js +61 -3
  21. package/_internal/DetailedCardSection.js +166 -3
  22. package/_internal/DetailedCardSectionItem.js +88 -3
  23. package/_internal/Flexbox2.js +85 -22
  24. package/_internal/Grid2.js +87 -24
  25. package/_internal/GridItem.js +34 -3
  26. package/_internal/Heading2.js +107 -3
  27. package/_internal/Icon2.js +206 -5
  28. package/_internal/IconButton.js +71 -3
  29. package/_internal/IconButtonLink.js +65 -18
  30. package/_internal/Item2.js +390 -73
  31. package/_internal/Link2.js +56 -15
  32. package/_internal/LinkButton.js +56 -13
  33. package/_internal/Number2.js +103 -61
  34. package/_internal/NumberField.js +3959 -65
  35. package/_internal/Pill2.js +400 -4
  36. package/_internal/ProgressBar.js +61 -18
  37. package/_internal/Radio2.js +227 -56
  38. package/_internal/RadioGroup.js +170 -4
  39. package/_internal/Shield2.js +220 -4
  40. package/_internal/SideNavigationMenu.js +586 -4
  41. package/_internal/SideNavigationMenuItem.js +299 -4
  42. package/_internal/Skeleton2.js +36 -9
  43. package/_internal/SkeletonCircle.js +52 -3
  44. package/_internal/SkeletonText.js +71 -3
  45. package/_internal/Spinner2.js +319 -29
  46. package/_internal/Switch2.js +310 -56
  47. package/_internal/SwitchGroup.js +182 -4
  48. package/_internal/Text2.js +45 -3
  49. package/_internal/TextArea.js +430 -20
  50. package/_internal/TextField.js +463 -19
  51. package/_internal/alert.js +2 -5
  52. package/_internal/app-bar.js +2 -8
  53. package/_internal/app-container.js +3 -9
  54. package/_internal/app-content.js +2 -5
  55. package/_internal/app-side-panel.js +3 -11
  56. package/_internal/badge.js +2 -6
  57. package/_internal/breadcrumb-item.js +1 -4
  58. package/_internal/breadcrumbs.js +2 -6
  59. package/_internal/button-group.js +2 -5
  60. package/_internal/button-link.js +2 -8
  61. package/_internal/button.js +3 -8
  62. package/_internal/card-actions.js +1 -4
  63. package/_internal/card-body.js +1 -4
  64. package/_internal/card-header.js +1 -8
  65. package/_internal/card.js +2 -11
  66. package/_internal/checkbox-group.js +2 -6
  67. package/_internal/checkbox.js +2 -6
  68. package/_internal/colors.js +87 -91
  69. package/_internal/conditional-wrapper.js +2 -2
  70. package/_internal/detailed-card-collapsible-section-items.js +1 -3
  71. package/_internal/detailed-card-header.js +1 -7
  72. package/_internal/detailed-card-section-item.js +1 -10
  73. package/_internal/detailed-card-section.js +1 -6
  74. package/_internal/detailed-card.js +2 -16
  75. package/_internal/flexbox.js +2 -5
  76. package/_internal/focus-within-group.js +3 -3
  77. package/_internal/fonts.js +4 -6
  78. package/_internal/gradient-border.js +35 -16
  79. package/_internal/grid-item.js +1 -4
  80. package/_internal/grid.js +2 -6
  81. package/_internal/heading.js +2 -6
  82. package/_internal/icon-button-link.js +2 -8
  83. package/_internal/icon-button.js +2 -6
  84. package/_internal/icon.js +2 -6
  85. package/_internal/item.js +2 -8
  86. package/_internal/link-button.js +2 -8
  87. package/_internal/link.js +3 -8
  88. package/_internal/listbox.js +3 -6
  89. package/_internal/number-field.js +2 -9
  90. package/_internal/number.js +2 -7
  91. package/_internal/pill.js +2 -6
  92. package/_internal/progress-bar.js +2 -5
  93. package/_internal/radio-group.js +2 -6
  94. package/_internal/radio.js +2 -6
  95. package/_internal/shared.js +2 -5
  96. package/_internal/shield.js +2 -6
  97. package/_internal/side-navigation-menu-bar.js +3 -9
  98. package/_internal/side-navigation-menu-item.js +2 -8
  99. package/_internal/side-navigation-menu.js +2 -8
  100. package/_internal/skeleton-circle.js +1 -6
  101. package/_internal/skeleton-text.js +2 -6
  102. package/_internal/skeleton.js +1 -7
  103. package/_internal/spinner.js +2 -5
  104. package/_internal/styles.js +235 -17
  105. package/_internal/styles2.js +44 -280
  106. package/_internal/switch-group.js +2 -6
  107. package/_internal/switch.js +2 -6
  108. package/_internal/text-area.js +2 -9
  109. package/_internal/text-field.js +2 -10
  110. package/_internal/text.js +2 -6
  111. package/_internal/theme.js +1 -3
  112. package/_internal/types.js +7 -31
  113. package/_internal/types2.js +18 -29
  114. package/_internal/types3.js +15 -18
  115. package/_internal/useAppSidePanel.js +331 -6
  116. package/_internal/useFocusOnList.js +502 -44
  117. package/_internal/useListboxItem.js +120 -23
  118. package/_internal/useSideNavigationMenuBar.js +371 -7
  119. package/_internal/useTheme.js +10 -8
  120. package/index.d.ts +4667 -0
  121. package/index.js +523 -1674
  122. package/package.json +2 -2
  123. package/_internal/SideNavigationMenuBar.js +0 -9
  124. package/_internal/helpers.js +0 -23
  125. package/_internal/types10.js +0 -20
  126. package/_internal/types11.js +0 -27
  127. package/_internal/types12.js +0 -35
  128. package/_internal/types13.js +0 -143
  129. package/_internal/types14.js +0 -11
  130. package/_internal/types15.js +0 -62
  131. package/_internal/types16.js +0 -56
  132. package/_internal/types17.js +0 -57
  133. package/_internal/types18.js +0 -40
  134. package/_internal/types19.js +0 -101
  135. package/_internal/types20.js +0 -47
  136. package/_internal/types21.js +0 -68
  137. package/_internal/types22.js +0 -52
  138. package/_internal/types23.js +0 -174
  139. package/_internal/types24.js +0 -18
  140. package/_internal/types25.js +0 -12
  141. package/_internal/types26.js +0 -36
  142. package/_internal/types27.js +0 -72
  143. package/_internal/types28.js +0 -73
  144. package/_internal/types29.js +0 -99
  145. package/_internal/types4.js +0 -67
  146. package/_internal/types5.js +0 -11
  147. package/_internal/types6.js +0 -11
  148. package/_internal/types7.js +0 -28
  149. package/_internal/types8.js +0 -72
  150. package/_internal/types9.js +0 -16
@@ -1,80 +1,3974 @@
1
- import { FocusEvent, KeyboardEvent, ChangeEvent } from 'react';
2
- import { b as TextFieldProps } from './types29.js';
3
- import { V as ValueOf, C as Comp } from './helpers.js';
1
+ import { _ as _objectSpread2, a as _defineProperty, b as _objectWithoutProperties, d as _classPrivateFieldInitSpec, e as _classPrivateFieldSet, f as _classPrivateFieldGet, c as _extends } from './_rollupPluginBabelHelpers.js';
2
+ import React__default, { useState, useRef, useCallback, useEffect, useMemo, useContext, createContext, forwardRef } from 'react';
3
+ import classNames from 'classnames';
4
+ import { w as warnIfNoAccessibleLabelFound } from './warnIfNoAccessibleLabelFound.js';
5
+ import styled, { css } from 'styled-components';
6
+ import { i as baseStyling } from './styles4.js';
7
+ import { T as Theme } from './colors.js';
8
+ import { mdiMenuUp, mdiMenuDown } from '@redsift/icons';
9
+ import { S as StyledIconButton } from './styles2.js';
10
+ import { a as useSSRSafeId, u as useLocale } from './context2.js';
11
+ import { N as NumberFormatter, u as useNumberFormatter } from './useNumberFormatter.js';
12
+ import { u as useMessageFormatter } from './useMessageFormatter.js';
13
+ import { b as useLayoutEffect, i as isFirefox, c as isMac, d as isWebKit, e as isIPad, f as useEffectEvent, g as isIOS, h as getOwnerDocument, j as isVirtualPointerEvent, k as isVirtualClick, l as getOwnerWindow, m as getInteractionModality, n as useFocus, s as setInteractionModality, a as useFocusWithin, o as isIPhone, p as isAndroid, u as useFocusRing } from './useFocusRing.js';
14
+ import c from 'clsx';
15
+ import { u as useTheme } from './useTheme.js';
16
+ import { a as Icon } from './Icon2.js';
17
+ import { F as Flexbox } from './Flexbox2.js';
18
+
19
+ /* eslint-disable prefer-const */
20
+
21
+ // copied from SSRProvider.tsx to reduce exports, if needed again, consider sharing
22
+ let canUseDOM = Boolean(typeof window !== 'undefined' && window.document && window.document.createElement);
23
+ let idsUpdaterMap = new Map();
24
+
25
+ /**
26
+ * If a default is not provided, generate an id.
27
+ * @param defaultId - Default component id.
28
+ */
29
+ function useId(defaultId) {
30
+ let [value, setValue] = useState(defaultId);
31
+ let nextId = useRef(null);
32
+ let res = useSSRSafeId(value);
33
+ let updateValue = useCallback(val => {
34
+ nextId.current = val;
35
+ }, []);
36
+ if (canUseDOM) {
37
+ idsUpdaterMap.set(res, updateValue);
38
+ }
39
+ useLayoutEffect(() => {
40
+ let r = res;
41
+ return () => {
42
+ idsUpdaterMap.delete(r);
43
+ };
44
+ }, [res]);
45
+
46
+ // This cannot cause an infinite loop because the ref is updated first.
47
+ // eslint-disable-next-line
48
+ useEffect(() => {
49
+ let newId = nextId.current;
50
+ if (newId) {
51
+ nextId.current = null;
52
+ setValue(newId);
53
+ }
54
+ });
55
+ return res;
56
+ }
57
+
58
+ /**
59
+ * Merges two ids.
60
+ * Different ids will trigger a side-effect and re-render components hooked up with `useId`.
61
+ */
62
+ function mergeIds(idA, idB) {
63
+ if (idA === idB) {
64
+ return idA;
65
+ }
66
+ let setIdA = idsUpdaterMap.get(idA);
67
+ if (setIdA) {
68
+ setIdA(idB);
69
+ return idB;
70
+ }
71
+ let setIdB = idsUpdaterMap.get(idB);
72
+ if (setIdB) {
73
+ setIdB(idA);
74
+ return idA;
75
+ }
76
+ return idB;
77
+ }
78
+
79
+ /**
80
+ * Used to generate an id, and after render, check if that id is rendered so we know
81
+ * if we can use it in places such as labelledby.
82
+ * @param depArray - When to recalculate if the id is in the DOM.
83
+ */
84
+ function useSlotId() {
85
+ let depArray = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
86
+ let id = useId();
87
+ let [resolvedId, setResolvedId] = useValueEffect(id);
88
+ let updateId = useCallback(() => {
89
+ setResolvedId(function* () {
90
+ yield id;
91
+ yield document.getElementById(id) ? id : undefined;
92
+ });
93
+ }, [id, setResolvedId]);
94
+ useLayoutEffect(updateId, [id, updateId, ...depArray]);
95
+ return resolvedId;
96
+ }
97
+
98
+ /* eslint-disable prefer-const */
99
+ // @ts-nocheck
100
+
101
+ /*
102
+ * Copyright 2020 Adobe. All rights reserved.
103
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
104
+ * you may not use this file except in compliance with the License. You may obtain a copy
105
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
106
+ *
107
+ * Unless required by applicable law or agreed to in writing, software distributed under
108
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
109
+ * OF ANY KIND, either express or implied. See the License for the specific language
110
+ * governing permissions and limitations under the License.
111
+ */
112
+
113
+ /**
114
+ * Calls all functions in the order they were chained with the same arguments.
115
+ */
116
+ function chain() {
117
+ for (var _len = arguments.length, callbacks = new Array(_len), _key = 0; _key < _len; _key++) {
118
+ callbacks[_key] = arguments[_key];
119
+ }
120
+ return function () {
121
+ for (let callback of callbacks) {
122
+ if (typeof callback === 'function') {
123
+ callback(...arguments);
124
+ }
125
+ }
126
+ };
127
+ }
128
+
129
+ // taken from: https://stackoverflow.com/questions/51603250/typescript-3-parameter-list-intersection-type/51604379#51604379
130
+
131
+ // eslint-disable-next-line no-undef, @typescript-eslint/no-unused-vars
132
+
133
+ /**
134
+ * Merges multiple props objects together. Event handlers are chained,
135
+ * classNames are combined, and ids are deduplicated - different ids
136
+ * will trigger a side-effect and re-render components hooked up with `useId`.
137
+ * For all other props, the last prop object overrides all previous ones.
138
+ * @param args - Multiple sets of props to merge together.
139
+ */
140
+ function mergeProps() {
141
+ // Start with a base clone of the first argument. This is a lot faster than starting
142
+ // with an empty object and adding properties as we go.
143
+ let result = _objectSpread2({}, arguments.length <= 0 ? undefined : arguments[0]);
144
+ for (let i = 1; i < arguments.length; i++) {
145
+ let props = i < 0 || arguments.length <= i ? undefined : arguments[i];
146
+ for (let key in props) {
147
+ let a = result[key];
148
+ let b = props[key];
149
+
150
+ // Chain events
151
+ if (typeof a === 'function' && typeof b === 'function' &&
152
+ // This is a lot faster than a regex.
153
+ key[0] === 'o' && key[1] === 'n' && key.charCodeAt(2) >= /* 'A' */65 && key.charCodeAt(2) <= /* 'Z' */90) {
154
+ result[key] = chain(a, b);
155
+
156
+ // Merge classnames, sometimes classNames are empty string which eval to false, so we just need to do a type check
157
+ } else if ((key === 'className' || key === 'UNSAFE_className') && typeof a === 'string' && typeof b === 'string') {
158
+ result[key] = c(a, b);
159
+ } else if (key === 'id' && a && b) {
160
+ result.id = mergeIds(a, b);
161
+ // Override others
162
+ } else {
163
+ result[key] = b !== undefined ? b : a;
164
+ }
165
+ }
166
+ }
167
+ return result;
168
+ }
169
+
170
+ /* eslint-disable prefer-const */
171
+ // @ts-nocheck
172
+
173
+ /*
174
+ * Copyright 2020 Adobe. All rights reserved.
175
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
176
+ * you may not use this file except in compliance with the License. You may obtain a copy
177
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
178
+ *
179
+ * Unless required by applicable law or agreed to in writing, software distributed under
180
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
181
+ * OF ANY KIND, either express or implied. See the License for the specific language
182
+ * governing permissions and limitations under the License.
183
+ */
184
+
185
+ const DOMPropNames = new Set(['id']);
186
+ const labelablePropNames = new Set(['aria-label', 'aria-labelledby', 'aria-describedby', 'aria-details']);
187
+
188
+ // See LinkDOMProps in dom.d.ts.
189
+ const linkPropNames = new Set(['href', 'hrefLang', 'target', 'rel', 'download', 'ping', 'referrerPolicy']);
190
+ const propRe = /^(data-.*)$/;
191
+
192
+ /**
193
+ * Filters out all props that aren't valid DOM props or defined via override prop obj.
194
+ * @param props - The component props to be filtered.
195
+ * @param opts - Props to override.
196
+ */
197
+ function filterDOMProps(props) {
198
+ let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
199
+ let {
200
+ labelable,
201
+ isLink,
202
+ propNames
203
+ } = opts;
204
+ let filteredProps = {};
205
+ for (const prop in props) {
206
+ if (Object.prototype.hasOwnProperty.call(props, prop) && (DOMPropNames.has(prop) || labelable && labelablePropNames.has(prop) || isLink && linkPropNames.has(prop) || propNames !== null && propNames !== void 0 && propNames.has(prop) || propRe.test(prop))) {
207
+ filteredProps[prop] = props[prop];
208
+ }
209
+ }
210
+ return filteredProps;
211
+ }
212
+
213
+ /* eslint-disable prefer-const */
214
+ // @ts-nocheck
215
+ /*
216
+ * Copyright 2020 Adobe. All rights reserved.
217
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
218
+ * you may not use this file except in compliance with the License. You may obtain a copy
219
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
220
+ *
221
+ * Unless required by applicable law or agreed to in writing, software distributed under
222
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
223
+ * OF ANY KIND, either express or implied. See the License for the specific language
224
+ * governing permissions and limitations under the License.
225
+ */
226
+
227
+ // This is a polyfill for element.focus({preventScroll: true});
228
+ // Currently necessary for Safari and old Edge:
229
+ // https://caniuse.com/#feat=mdn-api_htmlelement_focus_preventscroll_option
230
+ // See https://bugs.webkit.org/show_bug.cgi?id=178583
231
+ //
232
+
233
+ // Original licensing for the following methods can be found in the
234
+ // NOTICE file in the root directory of this source tree.
235
+ // See https://github.com/calvellido/focus-options-polyfill
236
+ function focusWithoutScrolling(element) {
237
+ if (supportsPreventScroll()) {
238
+ element.focus({
239
+ preventScroll: true
240
+ });
241
+ } else {
242
+ let scrollableElements = getScrollableElements(element);
243
+ element.focus();
244
+ restoreScrollPosition(scrollableElements);
245
+ }
246
+ }
247
+ let supportsPreventScrollCached = null;
248
+ function supportsPreventScroll() {
249
+ if (supportsPreventScrollCached == null) {
250
+ supportsPreventScrollCached = false;
251
+ try {
252
+ let focusElem = document.createElement('div');
253
+ focusElem.focus({
254
+ get preventScroll() {
255
+ supportsPreventScrollCached = true;
256
+ return true;
257
+ }
258
+ });
259
+ } catch (e) {
260
+ // Ignore
261
+ }
262
+ }
263
+ return supportsPreventScrollCached;
264
+ }
265
+ function getScrollableElements(element) {
266
+ let parent = element.parentNode;
267
+ let scrollableElements = [];
268
+ let rootScrollingElement = document.scrollingElement || document.documentElement;
269
+ while (parent instanceof HTMLElement && parent !== rootScrollingElement) {
270
+ if (parent.offsetHeight < parent.scrollHeight || parent.offsetWidth < parent.scrollWidth) {
271
+ scrollableElements.push({
272
+ element: parent,
273
+ scrollTop: parent.scrollTop,
274
+ scrollLeft: parent.scrollLeft
275
+ });
276
+ }
277
+ parent = parent.parentNode;
278
+ }
279
+ if (rootScrollingElement instanceof HTMLElement) {
280
+ scrollableElements.push({
281
+ element: rootScrollingElement,
282
+ scrollTop: rootScrollingElement.scrollTop,
283
+ scrollLeft: rootScrollingElement.scrollLeft
284
+ });
285
+ }
286
+ return scrollableElements;
287
+ }
288
+ function restoreScrollPosition(scrollableElements) {
289
+ for (let {
290
+ element,
291
+ scrollTop,
292
+ scrollLeft
293
+ } of scrollableElements) {
294
+ element.scrollTop = scrollTop;
295
+ element.scrollLeft = scrollLeft;
296
+ }
297
+ }
298
+
299
+ /* eslint-disable prefer-const */
300
+ function openLink(target, modifiers) {
301
+ var _window$event, _window$event$type;
302
+ let setOpening = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
303
+ let {
304
+ metaKey,
305
+ ctrlKey,
306
+ altKey,
307
+ shiftKey
308
+ } = modifiers;
309
+
310
+ // Firefox does not recognize keyboard events as a user action by default, and the popup blocker
311
+ // will prevent links with target="_blank" from opening. However, it does allow the event if the
312
+ // Command/Control key is held, which opens the link in a background tab. This seems like the best we can do.
313
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=257870 and https://bugzilla.mozilla.org/show_bug.cgi?id=746640.
314
+ if (isFirefox() && (_window$event = window.event) !== null && _window$event !== void 0 && (_window$event$type = _window$event.type) !== null && _window$event$type !== void 0 && _window$event$type.startsWith('key') && target.target === '_blank') {
315
+ if (isMac()) {
316
+ metaKey = true;
317
+ } else {
318
+ ctrlKey = true;
319
+ }
320
+ }
321
+
322
+ // WebKit does not support firing click events with modifier keys, but does support keyboard events.
323
+ // https://github.com/WebKit/WebKit/blob/c03d0ac6e6db178f90923a0a63080b5ca210d25f/Source/WebCore/html/HTMLAnchorElement.cpp#L184
324
+ let event = isWebKit() && isMac() && !isIPad() && process.env.NODE_ENV !== 'test' ?
325
+ // @ts-ignore - keyIdentifier is a non-standard property, but it's what webkit expects
326
+ new KeyboardEvent('keydown', {
327
+ keyIdentifier: 'Enter',
328
+ metaKey,
329
+ ctrlKey,
330
+ altKey,
331
+ shiftKey
332
+ }) : new MouseEvent('click', {
333
+ metaKey,
334
+ ctrlKey,
335
+ altKey,
336
+ shiftKey,
337
+ bubbles: true,
338
+ cancelable: true
339
+ });
340
+ openLink.isOpening = setOpening;
341
+ focusWithoutScrolling(target);
342
+ target.dispatchEvent(event);
343
+ openLink.isOpening = false;
344
+ }
345
+ // https://github.com/parcel-bundler/parcel/issues/8724
346
+ openLink.isOpening = false;
347
+
348
+ /* eslint-disable prefer-const */
349
+ // @ts-nocheck
350
+ /*
351
+ * Copyright 2020 Adobe. All rights reserved.
352
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
353
+ * you may not use this file except in compliance with the License. You may obtain a copy
354
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
355
+ *
356
+ * Unless required by applicable law or agreed to in writing, software distributed under
357
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
358
+ * OF ANY KIND, either express or implied. See the License for the specific language
359
+ * governing permissions and limitations under the License.
360
+ */
361
+
362
+ // We store a global list of elements that are currently transitioning,
363
+ // mapped to a set of CSS properties that are transitioning for that element.
364
+ // This is necessary rather than a simple count of transitions because of browser
365
+ // bugs, e.g. Chrome sometimes fires both transitionend and transitioncancel rather
366
+ // than one or the other. So we need to track what's actually transitioning so that
367
+ // we can ignore these duplicate events.
368
+ let transitionsByElement = new Map();
369
+
370
+ // A list of callbacks to call once there are no transitioning elements.
371
+ let transitionCallbacks = new Set();
372
+ function setupGlobalEvents() {
373
+ if (typeof window === 'undefined') {
374
+ return;
375
+ }
376
+ function isTransitionEvent(event) {
377
+ return 'propertyName' in event;
378
+ }
379
+ let onTransitionStart = e => {
380
+ if (!isTransitionEvent(e) || !e.target) {
381
+ return;
382
+ }
383
+ // Add the transitioning property to the list for this element.
384
+ let transitions = transitionsByElement.get(e.target);
385
+ if (!transitions) {
386
+ transitions = new Set();
387
+ transitionsByElement.set(e.target, transitions);
388
+
389
+ // The transitioncancel event must be registered on the element itself, rather than as a global
390
+ // event. This enables us to handle when the node is deleted from the document while it is transitioning.
391
+ // In that case, the cancel event would have nowhere to bubble to so we need to handle it directly.
392
+ e.target.addEventListener('transitioncancel', onTransitionEnd, {
393
+ once: true
394
+ });
395
+ }
396
+ transitions.add(e.propertyName);
397
+ };
398
+ let onTransitionEnd = e => {
399
+ if (!isTransitionEvent(e) || !e.target) {
400
+ return;
401
+ }
402
+ // Remove property from list of transitioning properties.
403
+ let properties = transitionsByElement.get(e.target);
404
+ if (!properties) {
405
+ return;
406
+ }
407
+ properties.delete(e.propertyName);
408
+
409
+ // If empty, remove transitioncancel event, and remove the element from the list of transitioning elements.
410
+ if (properties.size === 0) {
411
+ e.target.removeEventListener('transitioncancel', onTransitionEnd);
412
+ transitionsByElement.delete(e.target);
413
+ }
414
+
415
+ // If no transitioning elements, call all of the queued callbacks.
416
+ if (transitionsByElement.size === 0) {
417
+ for (let cb of transitionCallbacks) {
418
+ cb();
419
+ }
420
+ transitionCallbacks.clear();
421
+ }
422
+ };
423
+ document.body.addEventListener('transitionrun', onTransitionStart);
424
+ document.body.addEventListener('transitionend', onTransitionEnd);
425
+ }
426
+ if (typeof document !== 'undefined') {
427
+ if (document.readyState !== 'loading') {
428
+ setupGlobalEvents();
429
+ } else {
430
+ document.addEventListener('DOMContentLoaded', setupGlobalEvents);
431
+ }
432
+ }
433
+ function runAfterTransition(fn) {
434
+ // Wait one frame to see if an animation starts, e.g. a transition on mount.
435
+ requestAnimationFrame(() => {
436
+ // If no transitions are running, call the function immediately.
437
+ // Otherwise, add it to a list of callbacks to run at the end of the animation.
438
+ if (transitionsByElement.size === 0) {
439
+ fn();
440
+ } else {
441
+ transitionCallbacks.add(fn);
442
+ }
443
+ });
444
+ }
445
+
446
+ /* eslint-disable prefer-const */
447
+ function useGlobalListeners() {
448
+ let globalListeners = useRef(new Map());
449
+ let addGlobalListener = useCallback((eventTarget, type, listener, options) => {
450
+ // Make sure we remove the listener after it is called with the `once` option.
451
+ let fn = options !== null && options !== void 0 && options.once ? function () {
452
+ globalListeners.current.delete(listener);
453
+ listener(...arguments);
454
+ } : listener;
455
+ globalListeners.current.set(listener, {
456
+ type,
457
+ eventTarget,
458
+ fn,
459
+ options
460
+ });
461
+ eventTarget.addEventListener(type, listener, options);
462
+ }, []);
463
+ let removeGlobalListener = useCallback((eventTarget, type, listener, options) => {
464
+ var _globalListeners$curr;
465
+ let fn = ((_globalListeners$curr = globalListeners.current.get(listener)) === null || _globalListeners$curr === void 0 ? void 0 : _globalListeners$curr.fn) || listener;
466
+ eventTarget.removeEventListener(type, fn, options);
467
+ globalListeners.current.delete(listener);
468
+ }, []);
469
+ let removeAllGlobalListeners = useCallback(() => {
470
+ globalListeners.current.forEach((value, key) => {
471
+ removeGlobalListener(value.eventTarget, value.type, key, value.options);
472
+ });
473
+ }, [removeGlobalListener]);
474
+
475
+ // eslint-disable-next-line arrow-body-style
476
+ useEffect(() => {
477
+ return removeAllGlobalListeners;
478
+ }, [removeAllGlobalListeners]);
479
+ return {
480
+ addGlobalListener,
481
+ removeGlobalListener,
482
+ removeAllGlobalListeners
483
+ };
484
+ }
485
+
486
+ /* eslint-disable prefer-const */
487
+
488
+ /**
489
+ * Merges aria-label and aria-labelledby into aria-labelledby when both exist.
490
+ * @param props - Aria label props.
491
+ * @param defaultLabel - Default value for aria-label when not present.
492
+ */
493
+ function useLabels(props, defaultLabel) {
494
+ let {
495
+ id,
496
+ 'aria-label': label,
497
+ 'aria-labelledby': labelledBy
498
+ } = props;
499
+
500
+ // If there is both an aria-label and aria-labelledby,
501
+ // combine them by pointing to the element itself.
502
+ id = useId(id);
503
+ if (labelledBy && label) {
504
+ let ids = new Set([id, ...labelledBy.trim().split(/\s+/)]);
505
+ labelledBy = [...ids].join(' ');
506
+ } else if (labelledBy) {
507
+ labelledBy = labelledBy.trim().split(/\s+/).join(' ');
508
+ }
509
+
510
+ // If no labels are provided, use the default
511
+ if (!label && !labelledBy && defaultLabel) {
512
+ label = defaultLabel;
513
+ }
514
+ return {
515
+ id,
516
+ 'aria-label': label,
517
+ 'aria-labelledby': labelledBy
518
+ };
519
+ }
520
+
521
+ /*
522
+ * Copyright 2020 Adobe. All rights reserved.
523
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
524
+ * you may not use this file except in compliance with the License. You may obtain a copy
525
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
526
+ *
527
+ * Unless required by applicable law or agreed to in writing, software distributed under
528
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
529
+ * OF ANY KIND, either express or implied. See the License for the specific language
530
+ * governing permissions and limitations under the License.
531
+ */
532
+ // Syncs ref from context with ref passed to hook
533
+ function useSyncRef(context, ref) {
534
+ useLayoutEffect(() => {
535
+ if (context && context.ref && ref) {
536
+ context.ref.current = ref.current;
537
+ return () => {
538
+ if (context.ref) {
539
+ context.ref.current = null;
540
+ }
541
+ };
542
+ }
543
+ });
544
+ }
545
+
546
+ /* eslint-disable prefer-const */
547
+ function useEvent(ref, event, handler, options) {
548
+ let handleEvent = useEffectEvent(handler);
549
+ let isDisabled = handler == null;
550
+ useEffect(() => {
551
+ if (isDisabled || !ref.current) {
552
+ return;
553
+ }
554
+ let element = ref.current;
555
+ element.addEventListener(event, handleEvent, options);
556
+ return () => {
557
+ element.removeEventListener(event, handleEvent, options);
558
+ };
559
+ }, [ref, event, options, isDisabled, handleEvent]);
560
+ }
561
+
562
+ /* eslint-disable prefer-const */
563
+ // This hook works like `useState`, but when setting the value, you pass a generator function
564
+ // that can yield multiple values. Each yielded value updates the state and waits for the next
565
+ // layout effect, then continues the generator. This allows sequential updates to state to be
566
+ // written linearly.
567
+ function useValueEffect(defaultValue) {
568
+ let [value, setValue] = useState(defaultValue);
569
+ let effect = useRef(null);
570
+
571
+ // Store the function in a ref so we can always access the current version
572
+ // which has the proper `value` in scope.
573
+ let nextRef = useEffectEvent(() => {
574
+ if (!effect.current) {
575
+ return;
576
+ }
577
+ // Run the generator to the next yield.
578
+ let newValue = effect.current.next();
579
+
580
+ // If the generator is done, reset the effect.
581
+ if (newValue.done) {
582
+ effect.current = null;
583
+ return;
584
+ }
585
+
586
+ // If the value is the same as the current value,
587
+ // then continue to the next yield. Otherwise,
588
+ // set the value in state and wait for the next layout effect.
589
+ if (value === newValue.value) {
590
+ nextRef();
591
+ } else {
592
+ setValue(newValue.value);
593
+ }
594
+ });
595
+ useLayoutEffect(() => {
596
+ // If there is an effect currently running, continue to the next yield.
597
+ if (effect.current) {
598
+ nextRef();
599
+ }
600
+ });
601
+ let queue = useEffectEvent(fn => {
602
+ effect.current = fn(value);
603
+ nextRef();
604
+ });
605
+ return [value, queue];
606
+ }
607
+
608
+ /* eslint-disable prefer-const */
609
+ function useControlledState(value, defaultValue, onChange) {
610
+ let [stateValue, setStateValue] = useState(value || defaultValue);
611
+ let isControlledRef = useRef(value !== undefined);
612
+ let isControlled = value !== undefined;
613
+ useEffect(() => {
614
+ let wasControlled = isControlledRef.current;
615
+ if (wasControlled !== isControlled) {
616
+ console.warn(`WARN: A component changed from ${wasControlled ? 'controlled' : 'uncontrolled'} to ${isControlled ? 'controlled' : 'uncontrolled'}.`);
617
+ }
618
+ isControlledRef.current = isControlled;
619
+ }, [isControlled]);
620
+ let currentValue = isControlled ? value : stateValue;
621
+ let setValue = useCallback(function (value) {
622
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
623
+ args[_key - 1] = arguments[_key];
624
+ }
625
+ let onChangeCaller = function (value) {
626
+ if (onChange) {
627
+ if (!Object.is(currentValue, value)) {
628
+ for (var _len2 = arguments.length, onChangeArgs = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
629
+ onChangeArgs[_key2 - 1] = arguments[_key2];
630
+ }
631
+ onChange(value, ...onChangeArgs);
632
+ }
633
+ }
634
+ if (!isControlled) {
635
+ // If uncontrolled, mutate the currentValue local variable so that
636
+ // calling setState multiple times with the same value only emits onChange once.
637
+ // We do not use a ref for this because we specifically _do_ want the value to
638
+ // reset every render, and assigning to a ref in render breaks aborted suspended renders.
639
+ // eslint-disable-next-line react-hooks/exhaustive-deps
640
+ currentValue = value;
641
+ }
642
+ };
643
+ if (typeof value === 'function') {
644
+ console.warn('We can not support a function callback. See Github Issues for details https://github.com/adobe/react-spectrum/issues/2320');
645
+ // this supports functional updates https://reactjs.org/docs/hooks-reference.html#functional-updates
646
+ // when someone using useControlledState calls setControlledState(myFunc)
647
+ // this will call our useState setState with a function as well which invokes myFunc and calls onChange with the value from myFunc
648
+ // if we're in an uncontrolled state, then we also return the value of myFunc which to setState looks as though it was just called with myFunc from the beginning
649
+ // otherwise we just return the controlled value, which won't cause a rerender because React knows to bail out when the value is the same
650
+ let updateFunction = function (oldValue) {
651
+ for (var _len3 = arguments.length, functionArgs = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
652
+ functionArgs[_key3 - 1] = arguments[_key3];
653
+ }
654
+ let interceptedValue = value(isControlled ? currentValue : oldValue, ...functionArgs);
655
+ onChangeCaller(interceptedValue, ...args);
656
+ if (!isControlled) {
657
+ return interceptedValue;
658
+ }
659
+ return oldValue;
660
+ };
661
+ setStateValue(updateFunction);
662
+ } else {
663
+ if (!isControlled) {
664
+ setStateValue(value);
665
+ }
666
+ onChangeCaller(value, ...args);
667
+ }
668
+ }, [isControlled, currentValue, onChange]);
669
+ return [currentValue, setValue];
670
+ }
671
+
672
+ /* eslint-disable prefer-const */
673
+ // @ts-nocheck
674
+ /*
675
+ * Copyright 2020 Adobe. All rights reserved.
676
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
677
+ * you may not use this file except in compliance with the License. You may obtain a copy
678
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
679
+ *
680
+ * Unless required by applicable law or agreed to in writing, software distributed under
681
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
682
+ * OF ANY KIND, either express or implied. See the License for the specific language
683
+ * governing permissions and limitations under the License.
684
+ */
685
+
686
+ /**
687
+ * Takes a value and forces it to the closest min/max if it's outside. Also forces it to the closest valid step.
688
+ */
689
+ function clamp(value) {
690
+ let min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -Infinity;
691
+ let max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Infinity;
692
+ let newValue = Math.min(Math.max(value, min), max);
693
+ return newValue;
694
+ }
695
+ function roundToStepPrecision(value, step) {
696
+ let roundedValue = value;
697
+ let stepString = step.toString();
698
+ let pointIndex = stepString.indexOf('.');
699
+ let precision = pointIndex >= 0 ? stepString.length - pointIndex : 0;
700
+ if (precision > 0) {
701
+ let pow = Math.pow(10, precision);
702
+ roundedValue = Math.round(roundedValue * pow) / pow;
703
+ }
704
+ return roundedValue;
705
+ }
706
+ function snapValueToStep(value, min, max, step) {
707
+ min = Number(min);
708
+ max = Number(max);
709
+ let remainder = (value - (isNaN(min) ? 0 : min)) % step;
710
+ let snappedValue = roundToStepPrecision(Math.abs(remainder) * 2 >= step ? value + Math.sign(remainder) * (step - Math.abs(remainder)) : value - remainder, step);
711
+ if (!isNaN(min)) {
712
+ if (snappedValue < min) {
713
+ snappedValue = min;
714
+ } else if (!isNaN(max) && snappedValue > max) {
715
+ snappedValue = min + Math.floor(roundToStepPrecision((max - min) / step, step)) * step;
716
+ }
717
+ } else if (!isNaN(max) && snappedValue > max) {
718
+ snappedValue = Math.floor(roundToStepPrecision(max / step, step)) * step;
719
+ }
720
+
721
+ // correct floating point behavior by rounding to step precision
722
+ snappedValue = roundToStepPrecision(snappedValue, step);
723
+ return snappedValue;
724
+ }
725
+
726
+ /* eslint-disable prefer-const */
727
+ function useFormReset(ref, initialValue, onReset) {
728
+ let resetValue = useRef(initialValue);
729
+ let handleReset = useEffectEvent(() => {
730
+ if (onReset) {
731
+ onReset(resetValue.current);
732
+ }
733
+ });
734
+ useEffect(() => {
735
+ var _ref$current;
736
+ let form = ref === null || ref === void 0 ? void 0 : (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.form;
737
+ form === null || form === void 0 ? void 0 : form.addEventListener('reset', handleReset);
738
+ return () => {
739
+ form === null || form === void 0 ? void 0 : form.removeEventListener('reset', handleReset);
740
+ };
741
+ }, [ref, handleReset]);
742
+ }
743
+
744
+ const CURRENCY_SIGN_REGEX = new RegExp('^.*\\(.*\\).*$');
745
+ const NUMBERING_SYSTEMS = ['latn', 'arab', 'hanidec'];
746
+
747
+ /**
748
+ * A NumberParser can be used to perform locale-aware parsing of numbers from Unicode strings,
749
+ * as well as validation of partial user input. It automatically detects the numbering system
750
+ * used in the input, and supports parsing decimals, percentages, currency values, and units
751
+ * according to the locale.
752
+ */
753
+ class NumberParser {
754
+ constructor(locale) {
755
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
756
+ _defineProperty(this, "locale", void 0);
757
+ _defineProperty(this, "options", void 0);
758
+ this.locale = locale;
759
+ this.options = options;
760
+ }
761
+
762
+ /**
763
+ * Parses the given string to a number. Returns NaN if a valid number could not be parsed.
764
+ */
765
+ parse(value) {
766
+ return getNumberParserImpl(this.locale, this.options, value).parse(value);
767
+ }
768
+
769
+ /**
770
+ * Returns whether the given string could potentially be a valid number. This should be used to
771
+ * validate user input as the user types. If a `minValue` or `maxValue` is provided, the validity
772
+ * of the minus/plus sign characters can be checked.
773
+ */
774
+ isValidPartialNumber(value, minValue, maxValue) {
775
+ return getNumberParserImpl(this.locale, this.options, value).isValidPartialNumber(value, minValue, maxValue);
776
+ }
777
+
778
+ /**
779
+ * Returns a numbering system for which the given string is valid in the current locale.
780
+ * If no numbering system could be detected, the default numbering system for the current
781
+ * locale is returned.
782
+ */
783
+ getNumberingSystem(value) {
784
+ return getNumberParserImpl(this.locale, this.options, value).options.numberingSystem;
785
+ }
786
+ }
787
+ const numberParserCache = new Map();
788
+ function getNumberParserImpl(locale, options, value) {
789
+ // First try the default numbering system for the provided locale
790
+ let defaultParser = getCachedNumberParser(locale, options);
791
+
792
+ // If that doesn't match, and the locale doesn't include a hard coded numbering system,
793
+ // try each of the other supported numbering systems until we find one that matches.
794
+ if (!locale.includes('-nu-') && !defaultParser.isValidPartialNumber(value)) {
795
+ for (let numberingSystem of NUMBERING_SYSTEMS) {
796
+ if (numberingSystem !== defaultParser.options.numberingSystem) {
797
+ let parser = getCachedNumberParser(locale + (locale.includes('-u-') ? '-nu-' : '-u-nu-') + numberingSystem, options);
798
+ if (parser.isValidPartialNumber(value)) {
799
+ return parser;
800
+ }
801
+ }
802
+ }
803
+ }
804
+ return defaultParser;
805
+ }
806
+ function getCachedNumberParser(locale, options) {
807
+ let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : '');
808
+ let parser = numberParserCache.get(cacheKey);
809
+ if (!parser) {
810
+ parser = new NumberParserImpl(locale, options);
811
+ numberParserCache.set(cacheKey, parser);
812
+ }
813
+ return parser;
814
+ }
815
+
816
+ // The actual number parser implementation. Instances of this class are cached
817
+ // based on the locale, options, and detected numbering system.
818
+ class NumberParserImpl {
819
+ constructor(locale) {
820
+ var _this$options$minimum, _this$options$maximum;
821
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
822
+ _defineProperty(this, "formatter", void 0);
823
+ _defineProperty(this, "options", void 0);
824
+ _defineProperty(this, "symbols", void 0);
825
+ _defineProperty(this, "locale", void 0);
826
+ this.locale = locale;
827
+ this.formatter = new Intl.NumberFormat(locale, options);
828
+ this.options = this.formatter.resolvedOptions();
829
+ this.symbols = getSymbols(locale, this.formatter, this.options, options);
830
+ if (this.options.style === 'percent' && (((_this$options$minimum = this.options.minimumFractionDigits) !== null && _this$options$minimum !== void 0 ? _this$options$minimum : 0) > 18 || ((_this$options$maximum = this.options.maximumFractionDigits) !== null && _this$options$maximum !== void 0 ? _this$options$maximum : 0) > 18)) {
831
+ console.warn('NumberParser cannot handle percentages with greater than 18 decimal places, please reduce the number in your options.');
832
+ }
833
+ }
834
+ parse(value) {
835
+ // to parse the number, we need to remove anything that isn't actually part of the number, for example we want '-10.40' not '-10.40 USD'
836
+ let fullySanitizedValue = this.sanitize(value);
837
+ if (this.symbols.group) {
838
+ // Remove group characters, and replace decimal points and numerals with ASCII values.
839
+ fullySanitizedValue = replaceAll(fullySanitizedValue, this.symbols.group, '');
840
+ }
841
+ if (this.symbols.decimal) {
842
+ fullySanitizedValue = fullySanitizedValue.replace(this.symbols.decimal, '.');
843
+ }
844
+ if (this.symbols.minusSign) {
845
+ fullySanitizedValue = fullySanitizedValue.replace(this.symbols.minusSign, '-');
846
+ }
847
+ fullySanitizedValue = fullySanitizedValue.replace(this.symbols.numeral, this.symbols.index);
848
+ if (this.options.style === 'percent') {
849
+ // javascript is bad at dividing by 100 and maintaining the same significant figures, so perform it on the string before parsing
850
+ let isNegative = fullySanitizedValue.indexOf('-');
851
+ fullySanitizedValue = fullySanitizedValue.replace('-', '');
852
+ let index = fullySanitizedValue.indexOf('.');
853
+ if (index === -1) {
854
+ index = fullySanitizedValue.length;
855
+ }
856
+ fullySanitizedValue = fullySanitizedValue.replace('.', '');
857
+ if (index - 2 === 0) {
858
+ fullySanitizedValue = `0.${fullySanitizedValue}`;
859
+ } else if (index - 2 === -1) {
860
+ fullySanitizedValue = `0.0${fullySanitizedValue}`;
861
+ } else if (index - 2 === -2) {
862
+ fullySanitizedValue = '0.00';
863
+ } else {
864
+ fullySanitizedValue = `${fullySanitizedValue.slice(0, index - 2)}.${fullySanitizedValue.slice(index - 2)}`;
865
+ }
866
+ if (isNegative > -1) {
867
+ fullySanitizedValue = `-${fullySanitizedValue}`;
868
+ }
869
+ }
870
+ let newValue = fullySanitizedValue ? +fullySanitizedValue : NaN;
871
+ if (isNaN(newValue)) {
872
+ return NaN;
873
+ }
874
+ if (this.options.style === 'percent') {
875
+ var _this$options$minimum2, _this$options$maximum2;
876
+ // extra step for rounding percents to what our formatter would output
877
+ let options = _objectSpread2(_objectSpread2({}, this.options), {}, {
878
+ style: 'decimal',
879
+ minimumFractionDigits: Math.min(((_this$options$minimum2 = this.options.minimumFractionDigits) !== null && _this$options$minimum2 !== void 0 ? _this$options$minimum2 : 0) + 2, 20),
880
+ maximumFractionDigits: Math.min(((_this$options$maximum2 = this.options.maximumFractionDigits) !== null && _this$options$maximum2 !== void 0 ? _this$options$maximum2 : 0) + 2, 20)
881
+ });
882
+ return new NumberParser(this.locale, options).parse(new NumberFormatter(this.locale, options).format(newValue));
883
+ }
884
+
885
+ // accounting will always be stripped to a positive number, so if it's accounting and has a () around everything, then we need to make it negative again
886
+ if (this.options.currencySign === 'accounting' && CURRENCY_SIGN_REGEX.test(value)) {
887
+ newValue = -1 * newValue;
888
+ }
889
+ return newValue;
890
+ }
891
+ sanitize(value) {
892
+ // Remove literals and whitespace, which are allowed anywhere in the string
893
+ value = value.replace(this.symbols.literals, '');
894
+
895
+ // Replace the ASCII minus sign with the minus sign used in the current locale
896
+ // so that both are allowed in case the user's keyboard doesn't have the locale's minus sign.
897
+ if (this.symbols.minusSign) {
898
+ value = value.replace('-', this.symbols.minusSign);
899
+ }
900
+
901
+ // In arab numeral system, their decimal character is 1643, but most keyboards don't type that
902
+ // instead they use the , (44) character or apparently the (1548) character.
903
+ if (this.options.numberingSystem === 'arab') {
904
+ if (this.symbols.decimal) {
905
+ value = value.replace(',', this.symbols.decimal);
906
+ value = value.replace(String.fromCharCode(1548), this.symbols.decimal);
907
+ }
908
+ if (this.symbols.group) {
909
+ value = replaceAll(value, '.', this.symbols.group);
910
+ }
911
+ }
912
+
913
+ // fr-FR group character is char code 8239, but that's not a key on the french keyboard,
914
+ // so allow 'period' as a group char and replace it with a space
915
+ if (this.options.locale === 'fr-FR') {
916
+ value = replaceAll(value, '.', String.fromCharCode(8239));
917
+ }
918
+ return value;
919
+ }
920
+ isValidPartialNumber(value) {
921
+ let minValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -Infinity;
922
+ let maxValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Infinity;
923
+ value = this.sanitize(value);
924
+
925
+ // Remove minus or plus sign, which must be at the start of the string.
926
+ if (this.symbols.minusSign && value.startsWith(this.symbols.minusSign) && minValue < 0) {
927
+ value = value.slice(this.symbols.minusSign.length);
928
+ } else if (this.symbols.plusSign && value.startsWith(this.symbols.plusSign) && maxValue > 0) {
929
+ value = value.slice(this.symbols.plusSign.length);
930
+ }
931
+
932
+ // Numbers cannot start with a group separator
933
+ if (this.symbols.group && value.startsWith(this.symbols.group)) {
934
+ return false;
935
+ }
936
+
937
+ // Numbers that can't have any decimal values fail if a decimal character is typed
938
+ if (this.symbols.decimal && value.indexOf(this.symbols.decimal) > -1 && this.options.maximumFractionDigits === 0) {
939
+ return false;
940
+ }
941
+
942
+ // Remove numerals, groups, and decimals
943
+ if (this.symbols.group) {
944
+ value = replaceAll(value, this.symbols.group, '');
945
+ }
946
+ value = value.replace(this.symbols.numeral, '');
947
+ if (this.symbols.decimal) {
948
+ value = value.replace(this.symbols.decimal, '');
949
+ }
950
+
951
+ // The number is valid if there are no remaining characters
952
+ return value.length === 0;
953
+ }
954
+ }
955
+ const nonLiteralParts = new Set(['decimal', 'fraction', 'integer', 'minusSign', 'plusSign', 'group']);
956
+
957
+ // This list is derived from https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html#comparison and includes
958
+ // all unique numbers which we need to check in order to determine all the plural forms for a given locale.
959
+ // See: https://github.com/adobe/react-spectrum/pull/5134/files#r1337037855 for used script
960
+ const pluralNumbers = [0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1];
961
+ function getSymbols(locale, formatter, intlOptions, originalOptions) {
962
+ var _allParts$find$value, _allParts$find, _posAllParts$find, _decimalParts$find, _allParts$find2;
963
+ // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set
964
+ let symbolFormatter = new Intl.NumberFormat(locale, _objectSpread2(_objectSpread2({}, intlOptions), {}, {
965
+ minimumSignificantDigits: 1,
966
+ maximumSignificantDigits: 21
967
+ }));
968
+ // Note: some locale's don't add a group symbol until there is a ten thousands place
969
+ let allParts = symbolFormatter.formatToParts(-10000.111);
970
+ let posAllParts = symbolFormatter.formatToParts(10000.111);
971
+ let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n));
972
+ let minusSign = (_allParts$find$value = (_allParts$find = allParts.find(p => p.type === 'minusSign')) === null || _allParts$find === void 0 ? void 0 : _allParts$find.value) !== null && _allParts$find$value !== void 0 ? _allParts$find$value : '-';
973
+ let plusSign = (_posAllParts$find = posAllParts.find(p => p.type === 'plusSign')) === null || _posAllParts$find === void 0 ? void 0 : _posAllParts$find.value;
974
+
975
+ // Safari does not support the signDisplay option, but our number parser polyfills it.
976
+ // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character.
977
+ // @ts-ignore
978
+ if (!plusSign && ((originalOptions === null || originalOptions === void 0 ? void 0 : originalOptions.signDisplay) === 'exceptZero' || (originalOptions === null || originalOptions === void 0 ? void 0 : originalOptions.signDisplay) === 'always')) {
979
+ plusSign = '+';
980
+ }
981
+
982
+ // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters
983
+ // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal
984
+ let decimalParts = new Intl.NumberFormat(locale, _objectSpread2(_objectSpread2({}, intlOptions), {}, {
985
+ minimumFractionDigits: 2,
986
+ maximumFractionDigits: 2
987
+ })).formatToParts(0.001);
988
+ let decimal = (_decimalParts$find = decimalParts.find(p => p.type === 'decimal')) === null || _decimalParts$find === void 0 ? void 0 : _decimalParts$find.value;
989
+ let group = (_allParts$find2 = allParts.find(p => p.type === 'group')) === null || _allParts$find2 === void 0 ? void 0 : _allParts$find2.value;
990
+
991
+ // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that
992
+ // don't contribute to the numerical value
993
+ let allPartsLiterals = allParts.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value));
994
+ let pluralPartsLiterals = pluralParts.flatMap(p => p.filter(p => !nonLiteralParts.has(p.type)).map(p => escapeRegex(p.value)));
995
+ let sortedLiterals = [...new Set([...allPartsLiterals, ...pluralPartsLiterals])].sort((a, b) => b.length - a.length);
996
+ let literals = sortedLiterals.length === 0 ? new RegExp('[\\p{White_Space}]', 'gu') : new RegExp(`${sortedLiterals.join('|')}|[\\p{White_Space}]`, 'gu');
997
+
998
+ // These are for replacing non-latn characters with the latn equivalent
999
+ let numerals = [...new Intl.NumberFormat(intlOptions.locale, {
1000
+ useGrouping: false
1001
+ }).format(9876543210)].reverse();
1002
+ let indexes = new Map(numerals.map((d, i) => [d, i]));
1003
+ let numeral = new RegExp(`[${numerals.join('')}]`, 'g');
1004
+ let index = d => String(indexes.get(d));
1005
+ return {
1006
+ minusSign,
1007
+ plusSign,
1008
+ decimal,
1009
+ group,
1010
+ literals,
1011
+ numeral,
1012
+ index
1013
+ };
1014
+ }
1015
+ function replaceAll(str, find, replace) {
1016
+ // @ts-ignore
1017
+ if (str.replaceAll) {
1018
+ // @ts-ignore
1019
+ return str.replaceAll(find, replace);
1020
+ }
1021
+ return str.split(find).join(replace);
1022
+ }
1023
+ function escapeRegex(string) {
1024
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1025
+ }
1026
+
1027
+ /* eslint-disable prefer-const */
1028
+
1029
+ // Safari on iOS starts selecting text on long press. The only way to avoid this, it seems,
1030
+ // is to add user-select: none to the entire page. Adding it to the pressable element prevents
1031
+ // that element from being selected, but nearby elements may still receive selection. We add
1032
+ // user-select: none on touch start, and remove it again on touch end to prevent this.
1033
+ // This must be implemented using global state to avoid race conditions between multiple elements.
1034
+
1035
+ // There are three possible states due to the delay before removing user-select: none after
1036
+ // pointer up. The 'default' state always transitions to the 'disabled' state, which transitions
1037
+ // to 'restoring'. The 'restoring' state can either transition back to 'disabled' or 'default'.
1038
+
1039
+ // For non-iOS devices, we apply user-select: none to the pressed element instead to avoid possible
1040
+ // performance issues that arise from applying and removing user-select: none to the entire page
1041
+ // (see https://github.com/adobe/react-spectrum/issues/1609).
1042
+ // Note that state only matters here for iOS. Non-iOS gets user-select: none applied to the target element
1043
+ // rather than at the document level so we just need to apply/remove user-select: none for each pressed element individually
1044
+ let state = 'default';
1045
+ let savedUserSelect = '';
1046
+ let modifiedElementMap = new WeakMap();
1047
+ function disableTextSelection(target) {
1048
+ if (isIOS()) {
1049
+ if (state === 'default') {
1050
+ // eslint-disable-next-line no-restricted-globals
1051
+ const documentObject = getOwnerDocument(target);
1052
+ savedUserSelect = documentObject.documentElement.style.webkitUserSelect;
1053
+ documentObject.documentElement.style.webkitUserSelect = 'none';
1054
+ }
1055
+ state = 'disabled';
1056
+ } else if (target instanceof HTMLElement || target instanceof SVGElement) {
1057
+ // If not iOS, store the target's original user-select and change to user-select: none
1058
+ // Ignore state since it doesn't apply for non iOS
1059
+ modifiedElementMap.set(target, target.style.userSelect);
1060
+ target.style.userSelect = 'none';
1061
+ }
1062
+ }
1063
+ function restoreTextSelection(target) {
1064
+ if (isIOS()) {
1065
+ // If the state is already default, there's nothing to do.
1066
+ // If it is restoring, then there's no need to queue a second restore.
1067
+ if (state !== 'disabled') {
1068
+ return;
1069
+ }
1070
+ state = 'restoring';
1071
+
1072
+ // There appears to be a delay on iOS where selection still might occur
1073
+ // after pointer up, so wait a bit before removing user-select.
1074
+ setTimeout(() => {
1075
+ // Wait for any CSS transitions to complete so we don't recompute style
1076
+ // for the whole page in the middle of the animation and cause jank.
1077
+ runAfterTransition(() => {
1078
+ // Avoid race conditions
1079
+ if (state === 'restoring') {
1080
+ // eslint-disable-next-line no-restricted-globals
1081
+ const documentObject = getOwnerDocument(target);
1082
+ if (documentObject.documentElement.style.webkitUserSelect === 'none') {
1083
+ documentObject.documentElement.style.webkitUserSelect = savedUserSelect || '';
1084
+ }
1085
+ savedUserSelect = '';
1086
+ state = 'default';
1087
+ }
1088
+ });
1089
+ }, 300);
1090
+ } else if (target instanceof HTMLElement || target instanceof SVGElement) {
1091
+ // If not iOS, restore the target's original user-select if any
1092
+ // Ignore state since it doesn't apply for non iOS
1093
+ if (target && modifiedElementMap.has(target)) {
1094
+ let targetOldUserSelect = modifiedElementMap.get(target);
1095
+ if (target.style.userSelect === 'none') {
1096
+ target.style.userSelect = targetOldUserSelect;
1097
+ }
1098
+ if (target.getAttribute('style') === '') {
1099
+ target.removeAttribute('style');
1100
+ }
1101
+ modifiedElementMap.delete(target);
1102
+ }
1103
+ }
1104
+ }
1105
+
1106
+ /*
1107
+ * Copyright 2020 Adobe. All rights reserved.
1108
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
1109
+ * you may not use this file except in compliance with the License. You may obtain a copy
1110
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
1111
+ *
1112
+ * Unless required by applicable law or agreed to in writing, software distributed under
1113
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
1114
+ * OF ANY KIND, either express or implied. See the License for the specific language
1115
+ * governing permissions and limitations under the License.
1116
+ */
1117
+ const PressResponderContext = /*#__PURE__*/React__default.createContext({
1118
+ register: () => {}
1119
+ });
1120
+ PressResponderContext.displayName = 'PressResponderContext';
1121
+
1122
+ const _excluded$4 = ["register"],
1123
+ _excluded2 = ["onPress", "onPressChange", "onPressStart", "onPressEnd", "onPressUp", "isDisabled", "isPressed", "preventFocusOnPress", "shouldCancelOnPointerExit", "allowTextSelectionOnPress", "ref"];
1124
+ function usePressResponderContext(props) {
1125
+ // Consume context from <PressResponder> and merge with props.
1126
+ let context = useContext(PressResponderContext);
1127
+ if (context) {
1128
+ let {
1129
+ register
1130
+ } = context,
1131
+ contextProps = _objectWithoutProperties(context, _excluded$4);
1132
+ props = mergeProps(contextProps, props);
1133
+ register();
1134
+ }
1135
+ useSyncRef(context, props.ref);
1136
+ return props;
1137
+ }
1138
+ var _shouldStopPropagation = /*#__PURE__*/new WeakMap();
1139
+ class PressEvent {
1140
+ constructor(type, pointerType, originalEvent, state) {
1141
+ var _state$target;
1142
+ _defineProperty(this, "type", void 0);
1143
+ _defineProperty(this, "pointerType", void 0);
1144
+ _defineProperty(this, "target", void 0);
1145
+ _defineProperty(this, "shiftKey", void 0);
1146
+ _defineProperty(this, "ctrlKey", void 0);
1147
+ _defineProperty(this, "metaKey", void 0);
1148
+ _defineProperty(this, "altKey", void 0);
1149
+ _defineProperty(this, "x", void 0);
1150
+ _defineProperty(this, "y", void 0);
1151
+ _classPrivateFieldInitSpec(this, _shouldStopPropagation, {
1152
+ writable: true,
1153
+ value: true
1154
+ });
1155
+ let currentTarget = (_state$target = state === null || state === void 0 ? void 0 : state.target) !== null && _state$target !== void 0 ? _state$target : originalEvent.currentTarget;
1156
+ const rect = currentTarget === null || currentTarget === void 0 ? void 0 : currentTarget.getBoundingClientRect();
1157
+ let x,
1158
+ y = 0;
1159
+ let clientX,
1160
+ clientY = null;
1161
+ if (originalEvent.clientX != null && originalEvent.clientY != null) {
1162
+ clientX = originalEvent.clientX;
1163
+ clientY = originalEvent.clientY;
1164
+ }
1165
+ if (rect) {
1166
+ if (clientX != null && clientY != null) {
1167
+ x = clientX - rect.left;
1168
+ y = clientY - rect.top;
1169
+ } else {
1170
+ x = rect.width / 2;
1171
+ y = rect.height / 2;
1172
+ }
1173
+ }
1174
+ this.type = type;
1175
+ this.pointerType = pointerType;
1176
+ this.target = originalEvent.currentTarget;
1177
+ this.shiftKey = originalEvent.shiftKey;
1178
+ this.metaKey = originalEvent.metaKey;
1179
+ this.ctrlKey = originalEvent.ctrlKey;
1180
+ this.altKey = originalEvent.altKey;
1181
+ this.x = x;
1182
+ this.y = y;
1183
+ }
1184
+ continuePropagation() {
1185
+ _classPrivateFieldSet(this, _shouldStopPropagation, false);
1186
+ }
1187
+ get shouldStopPropagation() {
1188
+ return _classPrivateFieldGet(this, _shouldStopPropagation);
1189
+ }
1190
+ }
1191
+ const LINK_CLICKED = Symbol('linkClicked');
1192
+
1193
+ /**
1194
+ * Handles press interactions across mouse, touch, keyboard, and screen readers.
1195
+ * It normalizes behavior across browsers and platforms, and handles many nuances
1196
+ * of dealing with pointer and keyboard events.
1197
+ */
1198
+ function usePress(props) {
1199
+ let _usePressResponderCon = usePressResponderContext(props),
1200
+ {
1201
+ onPress,
1202
+ onPressChange,
1203
+ onPressStart,
1204
+ onPressEnd,
1205
+ onPressUp,
1206
+ isDisabled,
1207
+ isPressed: isPressedProp,
1208
+ preventFocusOnPress,
1209
+ shouldCancelOnPointerExit,
1210
+ allowTextSelectionOnPress,
1211
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1212
+ ref: _ // Removing `ref` from `domProps` because TypeScript is dumb
1213
+ } = _usePressResponderCon,
1214
+ domProps = _objectWithoutProperties(_usePressResponderCon, _excluded2);
1215
+ let [isPressed, setPressed] = useState(false);
1216
+ let ref = useRef({
1217
+ isPressed: false,
1218
+ ignoreEmulatedMouseEvents: false,
1219
+ ignoreClickAfterPress: false,
1220
+ didFirePressStart: false,
1221
+ isTriggeringEvent: false,
1222
+ activePointerId: null,
1223
+ target: null,
1224
+ isOverTarget: false,
1225
+ pointerType: null
1226
+ });
1227
+ let {
1228
+ addGlobalListener,
1229
+ removeAllGlobalListeners
1230
+ } = useGlobalListeners();
1231
+ let triggerPressStart = useEffectEvent((originalEvent, pointerType) => {
1232
+ let state = ref.current;
1233
+ if (isDisabled || state.didFirePressStart) {
1234
+ return false;
1235
+ }
1236
+ let shouldStopPropagation = true;
1237
+ state.isTriggeringEvent = true;
1238
+ if (onPressStart) {
1239
+ let event = new PressEvent('pressstart', pointerType, originalEvent);
1240
+ onPressStart(event);
1241
+ shouldStopPropagation = event.shouldStopPropagation;
1242
+ }
1243
+ if (onPressChange) {
1244
+ onPressChange(true);
1245
+ }
1246
+ state.isTriggeringEvent = false;
1247
+ state.didFirePressStart = true;
1248
+ setPressed(true);
1249
+ return shouldStopPropagation;
1250
+ });
1251
+ let triggerPressEnd = useEffectEvent(function (originalEvent, pointerType) {
1252
+ let wasPressed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1253
+ let state = ref.current;
1254
+ if (!state.didFirePressStart) {
1255
+ return false;
1256
+ }
1257
+ state.ignoreClickAfterPress = true;
1258
+ state.didFirePressStart = false;
1259
+ state.isTriggeringEvent = true;
1260
+ let shouldStopPropagation = true;
1261
+ if (onPressEnd) {
1262
+ let event = new PressEvent('pressend', pointerType, originalEvent);
1263
+ onPressEnd(event);
1264
+ shouldStopPropagation = event.shouldStopPropagation;
1265
+ }
1266
+ if (onPressChange) {
1267
+ onPressChange(false);
1268
+ }
1269
+ setPressed(false);
1270
+ if (onPress && wasPressed && !isDisabled) {
1271
+ let event = new PressEvent('press', pointerType, originalEvent);
1272
+ onPress(event);
1273
+ shouldStopPropagation &&= event.shouldStopPropagation;
1274
+ }
1275
+ state.isTriggeringEvent = false;
1276
+ return shouldStopPropagation;
1277
+ });
1278
+ let triggerPressUp = useEffectEvent((originalEvent, pointerType) => {
1279
+ let state = ref.current;
1280
+ if (isDisabled) {
1281
+ return false;
1282
+ }
1283
+ if (onPressUp) {
1284
+ state.isTriggeringEvent = true;
1285
+ let event = new PressEvent('pressup', pointerType, originalEvent);
1286
+ onPressUp(event);
1287
+ state.isTriggeringEvent = false;
1288
+ return event.shouldStopPropagation;
1289
+ }
1290
+ return true;
1291
+ });
1292
+ let cancel = useEffectEvent(e => {
1293
+ let state = ref.current;
1294
+ if (state.isPressed && state.target) {
1295
+ if (state.isOverTarget && state.pointerType != null) {
1296
+ triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
1297
+ }
1298
+ state.isPressed = false;
1299
+ state.isOverTarget = false;
1300
+ state.activePointerId = null;
1301
+ state.pointerType = null;
1302
+ removeAllGlobalListeners();
1303
+ if (!allowTextSelectionOnPress) {
1304
+ restoreTextSelection(state.target);
1305
+ }
1306
+ }
1307
+ });
1308
+ let cancelOnPointerExit = useEffectEvent(e => {
1309
+ if (shouldCancelOnPointerExit) {
1310
+ cancel(e);
1311
+ }
1312
+ });
1313
+ let pressProps = useMemo(() => {
1314
+ let state = ref.current;
1315
+ let pressProps = {
1316
+ onKeyDown(e) {
1317
+ if (isValidKeyboardEvent(e.nativeEvent, e.currentTarget) && e.currentTarget.contains(e.target)) {
1318
+ if (shouldPreventDefaultKeyboard(e.target, e.key)) {
1319
+ e.preventDefault();
1320
+ }
1321
+
1322
+ // If the event is repeating, it may have started on a different element
1323
+ // after which focus moved to the current element. Ignore these events and
1324
+ // only handle the first key down event.
1325
+ let shouldStopPropagation = true;
1326
+ if (!state.isPressed && !e.repeat) {
1327
+ state.target = e.currentTarget;
1328
+ state.isPressed = true;
1329
+ shouldStopPropagation = triggerPressStart(e, 'keyboard');
1330
+
1331
+ // Focus may move before the key up event, so register the event on the document
1332
+ // instead of the same element where the key down event occurred. Make it capturing so that it will trigger
1333
+ // before stopPropagation from useKeyboard on a child element may happen and thus we can still call triggerPress for the parent element.
1334
+ let originalTarget = e.currentTarget;
1335
+ let pressUp = e => {
1336
+ if (isValidKeyboardEvent(e, originalTarget) && !e.repeat && originalTarget.contains(e.target) && state.target) {
1337
+ triggerPressUp(createEvent(state.target, e), 'keyboard');
1338
+ }
1339
+ };
1340
+ addGlobalListener(getOwnerDocument(e.currentTarget), 'keyup', chain(pressUp, onKeyUp), true);
1341
+ }
1342
+ if (shouldStopPropagation) {
1343
+ e.stopPropagation();
1344
+ }
1345
+
1346
+ // Keep track of the keydown events that occur while the Meta (e.g. Command) key is held.
1347
+ // macOS has a bug where keyup events are not fired while the Meta key is down.
1348
+ // When the Meta key itself is released we will get an event for that, and we'll act as if
1349
+ // all of these other keys were released as well.
1350
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=1393524
1351
+ // https://bugs.webkit.org/show_bug.cgi?id=55291
1352
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553
1353
+ if (e.metaKey && isMac()) {
1354
+ var _state$metaKeyEvents;
1355
+ (_state$metaKeyEvents = state.metaKeyEvents) === null || _state$metaKeyEvents === void 0 ? void 0 : _state$metaKeyEvents.set(e.key, e.nativeEvent);
1356
+ }
1357
+ } else if (e.key === 'Meta') {
1358
+ state.metaKeyEvents = new Map();
1359
+ }
1360
+ },
1361
+ onClick(e) {
1362
+ if (e && !e.currentTarget.contains(e.target)) {
1363
+ return;
1364
+ }
1365
+ if (e && e.button === 0 && !state.isTriggeringEvent && !openLink.isOpening) {
1366
+ let shouldStopPropagation = true;
1367
+ if (isDisabled) {
1368
+ e.preventDefault();
1369
+ }
1370
+
1371
+ // If triggered from a screen reader or by using element.click(),
1372
+ // trigger as if it were a keyboard click.
1373
+ if (!state.ignoreClickAfterPress && !state.ignoreEmulatedMouseEvents && !state.isPressed && (state.pointerType === 'virtual' || isVirtualClick(e.nativeEvent))) {
1374
+ // Ensure the element receives focus (VoiceOver on iOS does not do this)
1375
+ if (!isDisabled && !preventFocusOnPress) {
1376
+ focusWithoutScrolling(e.currentTarget);
1377
+ }
1378
+ let stopPressStart = triggerPressStart(e, 'virtual');
1379
+ let stopPressUp = triggerPressUp(e, 'virtual');
1380
+ let stopPressEnd = triggerPressEnd(e, 'virtual');
1381
+ shouldStopPropagation = stopPressStart && stopPressUp && stopPressEnd;
1382
+ }
1383
+ state.ignoreEmulatedMouseEvents = false;
1384
+ state.ignoreClickAfterPress = false;
1385
+ if (shouldStopPropagation) {
1386
+ e.stopPropagation();
1387
+ }
1388
+ }
1389
+ }
1390
+ };
1391
+ let onKeyUp = e => {
1392
+ var _state$metaKeyEvents3;
1393
+ if (state.isPressed && state.target && isValidKeyboardEvent(e, state.target)) {
1394
+ var _state$metaKeyEvents2;
1395
+ if (shouldPreventDefaultKeyboard(e.target, e.key)) {
1396
+ e.preventDefault();
1397
+ }
1398
+ let target = e.target;
1399
+ triggerPressEnd(createEvent(state.target, e), 'keyboard', state.target.contains(target));
1400
+ removeAllGlobalListeners();
1401
+
1402
+ // If a link was triggered with a key other than Enter, open the URL ourselves.
1403
+ // This means the link has a role override, and the default browser behavior
1404
+ // only applies when using the Enter key.
1405
+ if (e.key !== 'Enter' && isHTMLAnchorLink(state.target) && state.target.contains(target) && !e[LINK_CLICKED]) {
1406
+ // Store a hidden property on the event so we only trigger link click once,
1407
+ // even if there are multiple usePress instances attached to the element.
1408
+ e[LINK_CLICKED] = true;
1409
+ openLink(state.target, e, false);
1410
+ }
1411
+ state.isPressed = false;
1412
+ (_state$metaKeyEvents2 = state.metaKeyEvents) === null || _state$metaKeyEvents2 === void 0 ? void 0 : _state$metaKeyEvents2.delete(e.key);
1413
+ } else if (e.key === 'Meta' && (_state$metaKeyEvents3 = state.metaKeyEvents) !== null && _state$metaKeyEvents3 !== void 0 && _state$metaKeyEvents3.size) {
1414
+ // If we recorded keydown events that occurred while the Meta key was pressed,
1415
+ // and those haven't received keyup events already, fire keyup events ourselves.
1416
+ // See comment above for more info about the macOS bug causing this.
1417
+ let events = state.metaKeyEvents;
1418
+ state.metaKeyEvents = undefined;
1419
+ for (let event of events.values()) {
1420
+ var _state$target2;
1421
+ (_state$target2 = state.target) === null || _state$target2 === void 0 ? void 0 : _state$target2.dispatchEvent(new KeyboardEvent('keyup', event));
1422
+ }
1423
+ }
1424
+ };
1425
+ if (typeof PointerEvent !== 'undefined') {
1426
+ pressProps.onPointerDown = e => {
1427
+ // Only handle left clicks, and ignore events that bubbled through portals.
1428
+ if (e.button !== 0 || !e.currentTarget.contains(e.target)) {
1429
+ return;
1430
+ }
1431
+
1432
+ // iOS safari fires pointer events from VoiceOver with incorrect coordinates/target.
1433
+ // Ignore and let the onClick handler take care of it instead.
1434
+ // https://bugs.webkit.org/show_bug.cgi?id=222627
1435
+ // https://bugs.webkit.org/show_bug.cgi?id=223202
1436
+ if (isVirtualPointerEvent(e.nativeEvent)) {
1437
+ state.pointerType = 'virtual';
1438
+ return;
1439
+ }
1440
+
1441
+ // Due to browser inconsistencies, especially on mobile browsers, we prevent
1442
+ // default on pointer down and handle focusing the pressable element ourselves.
1443
+ if (shouldPreventDefault(e.currentTarget)) {
1444
+ e.preventDefault();
1445
+ }
1446
+ state.pointerType = e.pointerType;
1447
+ let shouldStopPropagation = true;
1448
+ if (!state.isPressed) {
1449
+ state.isPressed = true;
1450
+ state.isOverTarget = true;
1451
+ state.activePointerId = e.pointerId;
1452
+ state.target = e.currentTarget;
1453
+ if (!isDisabled && !preventFocusOnPress) {
1454
+ focusWithoutScrolling(e.currentTarget);
1455
+ }
1456
+ if (!allowTextSelectionOnPress) {
1457
+ disableTextSelection(state.target);
1458
+ }
1459
+ shouldStopPropagation = triggerPressStart(e, state.pointerType);
1460
+ addGlobalListener(getOwnerDocument(e.currentTarget), 'pointermove', onPointerMove, false);
1461
+ addGlobalListener(getOwnerDocument(e.currentTarget), 'pointerup', onPointerUp, false);
1462
+ addGlobalListener(getOwnerDocument(e.currentTarget), 'pointercancel', onPointerCancel, false);
1463
+ }
1464
+ if (shouldStopPropagation) {
1465
+ e.stopPropagation();
1466
+ }
1467
+ };
1468
+ pressProps.onMouseDown = e => {
1469
+ if (!e.currentTarget.contains(e.target)) {
1470
+ return;
1471
+ }
1472
+ if (e.button === 0) {
1473
+ // Chrome and Firefox on touch Windows devices require mouse down events
1474
+ // to be canceled in addition to pointer events, or an extra asynchronous
1475
+ // focus event will be fired.
1476
+ if (shouldPreventDefault(e.currentTarget)) {
1477
+ e.preventDefault();
1478
+ }
1479
+ e.stopPropagation();
1480
+ }
1481
+ };
1482
+ pressProps.onPointerUp = e => {
1483
+ // iOS fires pointerup with zero width and height, so check the pointerType recorded during pointerdown.
1484
+ if (!e.currentTarget.contains(e.target) || state.pointerType === 'virtual') {
1485
+ return;
1486
+ }
1487
+
1488
+ // Only handle left clicks
1489
+ // Safari on iOS sometimes fires pointerup events, even
1490
+ // when the touch isn't over the target, so double check.
1491
+ if (e.button === 0 && isOverTarget(e, e.currentTarget)) {
1492
+ triggerPressUp(e, state.pointerType || e.pointerType);
1493
+ }
1494
+ };
1495
+
1496
+ // Safari on iOS < 13.2 does not implement pointerenter/pointerleave events correctly.
1497
+ // Use pointer move events instead to implement our own hit testing.
1498
+ // See https://bugs.webkit.org/show_bug.cgi?id=199803
1499
+ let onPointerMove = e => {
1500
+ if (e.pointerId !== state.activePointerId) {
1501
+ return;
1502
+ }
1503
+ if (state.target && isOverTarget(e, state.target)) {
1504
+ if (!state.isOverTarget && state.pointerType != null) {
1505
+ state.isOverTarget = true;
1506
+ triggerPressStart(createEvent(state.target, e), state.pointerType);
1507
+ }
1508
+ } else if (state.target && state.isOverTarget && state.pointerType != null) {
1509
+ state.isOverTarget = false;
1510
+ triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
1511
+ cancelOnPointerExit(e);
1512
+ }
1513
+ };
1514
+ let onPointerUp = e => {
1515
+ if (e.pointerId === state.activePointerId && state.isPressed && e.button === 0 && state.target) {
1516
+ if (isOverTarget(e, state.target) && state.pointerType != null) {
1517
+ triggerPressEnd(createEvent(state.target, e), state.pointerType);
1518
+ } else if (state.isOverTarget && state.pointerType != null) {
1519
+ triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
1520
+ }
1521
+ state.isPressed = false;
1522
+ state.isOverTarget = false;
1523
+ state.activePointerId = null;
1524
+ state.pointerType = null;
1525
+ removeAllGlobalListeners();
1526
+ if (!allowTextSelectionOnPress) {
1527
+ restoreTextSelection(state.target);
1528
+ }
1529
+ }
1530
+ };
1531
+ let onPointerCancel = e => {
1532
+ cancel(e);
1533
+ };
1534
+ pressProps.onDragStart = e => {
1535
+ if (!e.currentTarget.contains(e.target)) {
1536
+ return;
1537
+ }
1538
+
1539
+ // Safari does not call onPointerCancel when a drag starts, whereas Chrome and Firefox do.
1540
+ cancel(e);
1541
+ };
1542
+ } else {
1543
+ pressProps.onMouseDown = e => {
1544
+ // Only handle left clicks
1545
+ if (e.button !== 0 || !e.currentTarget.contains(e.target)) {
1546
+ return;
1547
+ }
1548
+
1549
+ // Due to browser inconsistencies, especially on mobile browsers, we prevent
1550
+ // default on mouse down and handle focusing the pressable element ourselves.
1551
+ if (shouldPreventDefault(e.currentTarget)) {
1552
+ e.preventDefault();
1553
+ }
1554
+ if (state.ignoreEmulatedMouseEvents) {
1555
+ e.stopPropagation();
1556
+ return;
1557
+ }
1558
+ state.isPressed = true;
1559
+ state.isOverTarget = true;
1560
+ state.target = e.currentTarget;
1561
+ state.pointerType = isVirtualClick(e.nativeEvent) ? 'virtual' : 'mouse';
1562
+ if (!isDisabled && !preventFocusOnPress) {
1563
+ focusWithoutScrolling(e.currentTarget);
1564
+ }
1565
+ let shouldStopPropagation = triggerPressStart(e, state.pointerType);
1566
+ if (shouldStopPropagation) {
1567
+ e.stopPropagation();
1568
+ }
1569
+ addGlobalListener(getOwnerDocument(e.currentTarget), 'mouseup', onMouseUp, false);
1570
+ };
1571
+ pressProps.onMouseEnter = e => {
1572
+ if (!e.currentTarget.contains(e.target)) {
1573
+ return;
1574
+ }
1575
+ let shouldStopPropagation = true;
1576
+ if (state.isPressed && !state.ignoreEmulatedMouseEvents && state.pointerType != null) {
1577
+ state.isOverTarget = true;
1578
+ shouldStopPropagation = triggerPressStart(e, state.pointerType);
1579
+ }
1580
+ if (shouldStopPropagation) {
1581
+ e.stopPropagation();
1582
+ }
1583
+ };
1584
+ pressProps.onMouseLeave = e => {
1585
+ if (!e.currentTarget.contains(e.target)) {
1586
+ return;
1587
+ }
1588
+ let shouldStopPropagation = true;
1589
+ if (state.isPressed && !state.ignoreEmulatedMouseEvents && state.pointerType != null) {
1590
+ state.isOverTarget = false;
1591
+ shouldStopPropagation = triggerPressEnd(e, state.pointerType, false);
1592
+ cancelOnPointerExit(e);
1593
+ }
1594
+ if (shouldStopPropagation) {
1595
+ e.stopPropagation();
1596
+ }
1597
+ };
1598
+ pressProps.onMouseUp = e => {
1599
+ if (!e.currentTarget.contains(e.target)) {
1600
+ return;
1601
+ }
1602
+ if (!state.ignoreEmulatedMouseEvents && e.button === 0) {
1603
+ triggerPressUp(e, state.pointerType || 'mouse');
1604
+ }
1605
+ };
1606
+ let onMouseUp = e => {
1607
+ // Only handle left clicks
1608
+ if (e.button !== 0) {
1609
+ return;
1610
+ }
1611
+ state.isPressed = false;
1612
+ removeAllGlobalListeners();
1613
+ if (state.ignoreEmulatedMouseEvents) {
1614
+ state.ignoreEmulatedMouseEvents = false;
1615
+ return;
1616
+ }
1617
+ if (state.target && isOverTarget(e, state.target) && state.pointerType != null) {
1618
+ triggerPressEnd(createEvent(state.target, e), state.pointerType);
1619
+ } else if (state.target && state.isOverTarget && state.pointerType != null) {
1620
+ triggerPressEnd(createEvent(state.target, e), state.pointerType, false);
1621
+ }
1622
+ state.isOverTarget = false;
1623
+ };
1624
+ pressProps.onTouchStart = e => {
1625
+ if (!e.currentTarget.contains(e.target)) {
1626
+ return;
1627
+ }
1628
+ let touch = getTouchFromEvent(e.nativeEvent);
1629
+ if (!touch) {
1630
+ return;
1631
+ }
1632
+ state.activePointerId = touch.identifier;
1633
+ state.ignoreEmulatedMouseEvents = true;
1634
+ state.isOverTarget = true;
1635
+ state.isPressed = true;
1636
+ state.target = e.currentTarget;
1637
+ state.pointerType = 'touch';
1638
+
1639
+ // Due to browser inconsistencies, especially on mobile browsers, we prevent default
1640
+ // on the emulated mouse event and handle focusing the pressable element ourselves.
1641
+ if (!isDisabled && !preventFocusOnPress) {
1642
+ focusWithoutScrolling(e.currentTarget);
1643
+ }
1644
+ if (!allowTextSelectionOnPress) {
1645
+ disableTextSelection(state.target);
1646
+ }
1647
+ let shouldStopPropagation = triggerPressStart(createTouchEvent(state.target, e), state.pointerType);
1648
+ if (shouldStopPropagation) {
1649
+ e.stopPropagation();
1650
+ }
1651
+ addGlobalListener(getOwnerWindow(e.currentTarget), 'scroll', onScroll, true);
1652
+ };
1653
+ pressProps.onTouchMove = e => {
1654
+ if (!e.currentTarget.contains(e.target)) {
1655
+ return;
1656
+ }
1657
+ if (!state.isPressed) {
1658
+ e.stopPropagation();
1659
+ return;
1660
+ }
1661
+ let touch = getTouchById(e.nativeEvent, state.activePointerId);
1662
+ let shouldStopPropagation = true;
1663
+ if (touch && isOverTarget(touch, e.currentTarget)) {
1664
+ if (!state.isOverTarget && state.pointerType != null) {
1665
+ state.isOverTarget = true;
1666
+ shouldStopPropagation = triggerPressStart(createTouchEvent(state.target, e), state.pointerType);
1667
+ }
1668
+ } else if (state.isOverTarget && state.pointerType != null) {
1669
+ state.isOverTarget = false;
1670
+ shouldStopPropagation = triggerPressEnd(createTouchEvent(state.target, e), state.pointerType, false);
1671
+ cancelOnPointerExit(createTouchEvent(state.target, e));
1672
+ }
1673
+ if (shouldStopPropagation) {
1674
+ e.stopPropagation();
1675
+ }
1676
+ };
1677
+ pressProps.onTouchEnd = e => {
1678
+ if (!e.currentTarget.contains(e.target)) {
1679
+ return;
1680
+ }
1681
+ if (!state.isPressed) {
1682
+ e.stopPropagation();
1683
+ return;
1684
+ }
1685
+ let touch = getTouchById(e.nativeEvent, state.activePointerId);
1686
+ let shouldStopPropagation = true;
1687
+ if (touch && isOverTarget(touch, e.currentTarget) && state.pointerType != null) {
1688
+ triggerPressUp(createTouchEvent(state.target, e), state.pointerType);
1689
+ shouldStopPropagation = triggerPressEnd(createTouchEvent(state.target, e), state.pointerType);
1690
+ } else if (state.isOverTarget && state.pointerType != null) {
1691
+ shouldStopPropagation = triggerPressEnd(createTouchEvent(state.target, e), state.pointerType, false);
1692
+ }
1693
+ if (shouldStopPropagation) {
1694
+ e.stopPropagation();
1695
+ }
1696
+ state.isPressed = false;
1697
+ state.activePointerId = null;
1698
+ state.isOverTarget = false;
1699
+ state.ignoreEmulatedMouseEvents = true;
1700
+ if (state.target && !allowTextSelectionOnPress) {
1701
+ restoreTextSelection(state.target);
1702
+ }
1703
+ removeAllGlobalListeners();
1704
+ };
1705
+ pressProps.onTouchCancel = e => {
1706
+ if (!e.currentTarget.contains(e.target)) {
1707
+ return;
1708
+ }
1709
+ e.stopPropagation();
1710
+ if (state.isPressed) {
1711
+ cancel(createTouchEvent(state.target, e));
1712
+ }
1713
+ };
1714
+ let onScroll = e => {
1715
+ if (state.isPressed && e.target.contains(state.target)) {
1716
+ cancel({
1717
+ currentTarget: state.target,
1718
+ shiftKey: false,
1719
+ ctrlKey: false,
1720
+ metaKey: false,
1721
+ altKey: false
1722
+ });
1723
+ }
1724
+ };
1725
+ pressProps.onDragStart = e => {
1726
+ if (!e.currentTarget.contains(e.target)) {
1727
+ return;
1728
+ }
1729
+ cancel(e);
1730
+ };
1731
+ }
1732
+ return pressProps;
1733
+ }, [addGlobalListener, isDisabled, preventFocusOnPress, removeAllGlobalListeners, allowTextSelectionOnPress, cancel, cancelOnPointerExit, triggerPressEnd, triggerPressStart, triggerPressUp]);
1734
+
1735
+ // Remove user-select: none in case component unmounts immediately after pressStart
1736
+ // eslint-disable-next-line arrow-body-style
1737
+ useEffect(() => {
1738
+ return () => {
1739
+ if (!allowTextSelectionOnPress) {
1740
+ var _ref$current$target;
1741
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1742
+ restoreTextSelection((_ref$current$target = ref.current.target) !== null && _ref$current$target !== void 0 ? _ref$current$target : undefined);
1743
+ }
1744
+ };
1745
+ }, [allowTextSelectionOnPress]);
1746
+ return {
1747
+ isPressed: isPressedProp || isPressed,
1748
+ pressProps: mergeProps(domProps, pressProps)
1749
+ };
1750
+ }
1751
+ function isHTMLAnchorLink(target) {
1752
+ return target.tagName === 'A' && target.hasAttribute('href');
1753
+ }
1754
+ function isValidKeyboardEvent(event, currentTarget) {
1755
+ const {
1756
+ key,
1757
+ code
1758
+ } = event;
1759
+ const element = currentTarget;
1760
+ const role = element.getAttribute('role');
1761
+ // Accessibility for keyboards. Space and Enter only.
1762
+ // "Spacebar" is for IE 11
1763
+ return (key === 'Enter' || key === ' ' || key === 'Spacebar' || code === 'Space') && !(element instanceof getOwnerWindow(element).HTMLInputElement && !isValidInputKey(element, key) || element instanceof getOwnerWindow(element).HTMLTextAreaElement || element.isContentEditable) &&
1764
+ // Links should only trigger with Enter key
1765
+ !((role === 'link' || !role && isHTMLAnchorLink(element)) && key !== 'Enter');
1766
+ }
1767
+ function getTouchFromEvent(event) {
1768
+ const {
1769
+ targetTouches
1770
+ } = event;
1771
+ if (targetTouches.length > 0) {
1772
+ return targetTouches[0];
1773
+ }
1774
+ return null;
1775
+ }
1776
+ function getTouchById(event, pointerId) {
1777
+ const changedTouches = event.changedTouches;
1778
+ for (let i = 0; i < changedTouches.length; i++) {
1779
+ const touch = changedTouches[i];
1780
+ if (touch.identifier === pointerId) {
1781
+ return touch;
1782
+ }
1783
+ }
1784
+ return null;
1785
+ }
1786
+ function createTouchEvent(target, e) {
1787
+ let clientX = 0;
1788
+ let clientY = 0;
1789
+ if (e.targetTouches && e.targetTouches.length === 1) {
1790
+ clientX = e.targetTouches[0].clientX;
1791
+ clientY = e.targetTouches[0].clientY;
1792
+ }
1793
+ return {
1794
+ currentTarget: target,
1795
+ shiftKey: e.shiftKey,
1796
+ ctrlKey: e.ctrlKey,
1797
+ metaKey: e.metaKey,
1798
+ altKey: e.altKey,
1799
+ clientX,
1800
+ clientY
1801
+ };
1802
+ }
1803
+ function createEvent(target, e) {
1804
+ let clientX = e.clientX;
1805
+ let clientY = e.clientY;
1806
+ return {
1807
+ currentTarget: target,
1808
+ shiftKey: e.shiftKey,
1809
+ ctrlKey: e.ctrlKey,
1810
+ metaKey: e.metaKey,
1811
+ altKey: e.altKey,
1812
+ clientX,
1813
+ clientY
1814
+ };
1815
+ }
1816
+ function getPointClientRect(point) {
1817
+ let offsetX = 0;
1818
+ let offsetY = 0;
1819
+ if (point.width !== undefined) {
1820
+ offsetX = point.width / 2;
1821
+ } else if (point.radiusX !== undefined) {
1822
+ offsetX = point.radiusX;
1823
+ }
1824
+ if (point.height !== undefined) {
1825
+ offsetY = point.height / 2;
1826
+ } else if (point.radiusY !== undefined) {
1827
+ offsetY = point.radiusY;
1828
+ }
1829
+ return {
1830
+ top: point.clientY - offsetY,
1831
+ right: point.clientX + offsetX,
1832
+ bottom: point.clientY + offsetY,
1833
+ left: point.clientX - offsetX
1834
+ };
1835
+ }
1836
+ function areRectanglesOverlapping(a, b) {
1837
+ // check if they cannot overlap on x axis
1838
+ if (a.left > b.right || b.left > a.right) {
1839
+ return false;
1840
+ }
1841
+ // check if they cannot overlap on y axis
1842
+ if (a.top > b.bottom || b.top > a.bottom) {
1843
+ return false;
1844
+ }
1845
+ return true;
1846
+ }
1847
+ function isOverTarget(point, target) {
1848
+ let rect = target.getBoundingClientRect();
1849
+ let pointRect = getPointClientRect(point);
1850
+ return areRectanglesOverlapping(rect, pointRect);
1851
+ }
1852
+ function shouldPreventDefault(target) {
1853
+ // We cannot prevent default if the target is a draggable element.
1854
+ return !(target instanceof HTMLElement) || !target.hasAttribute('draggable');
1855
+ }
1856
+ function shouldPreventDefaultKeyboard(target, key) {
1857
+ if (target instanceof HTMLInputElement) {
1858
+ return !isValidInputKey(target, key);
1859
+ }
1860
+ if (target instanceof HTMLButtonElement) {
1861
+ return target.type !== 'submit' && target.type !== 'reset';
1862
+ }
1863
+ if (isHTMLAnchorLink(target)) {
1864
+ return false;
1865
+ }
1866
+ return true;
1867
+ }
1868
+ const nonTextInputTypes = new Set(['checkbox', 'radio', 'range', 'color', 'file', 'image', 'button', 'submit', 'reset']);
1869
+ function isValidInputKey(target, key) {
1870
+ // Only space should toggle checkboxes and radios, not enter.
1871
+ return target.type === 'checkbox' || target.type === 'radio' ? key === ' ' : nonTextInputTypes.has(target.type);
1872
+ }
1873
+
1874
+ /* eslint-disable prefer-const */
1875
+ // @ts-nocheck
1876
+ /*
1877
+ * Copyright 2020 Adobe. All rights reserved.
1878
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
1879
+ * you may not use this file except in compliance with the License. You may obtain a copy
1880
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
1881
+ *
1882
+ * Unless required by applicable law or agreed to in writing, software distributed under
1883
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
1884
+ * OF ANY KIND, either express or implied. See the License for the specific language
1885
+ * governing permissions and limitations under the License.
1886
+ */
1887
+
1888
+ /**
1889
+ * This function wraps a React event handler to make stopPropagation the default, and support continuePropagation instead.
1890
+ */
1891
+ function createEventHandler(handler) {
1892
+ if (!handler) {
1893
+ return undefined;
1894
+ }
1895
+ let shouldStopPropagation = true;
1896
+ return e => {
1897
+ let event = _objectSpread2(_objectSpread2({}, e), {}, {
1898
+ preventDefault() {
1899
+ e.preventDefault();
1900
+ },
1901
+ isDefaultPrevented() {
1902
+ return e.isDefaultPrevented();
1903
+ },
1904
+ stopPropagation() {
1905
+ console.error('stopPropagation is now the default behavior for events in React Spectrum. You can use continuePropagation() to revert this behavior.');
1906
+ },
1907
+ continuePropagation() {
1908
+ shouldStopPropagation = false;
1909
+ }
1910
+ });
1911
+ handler(event);
1912
+ if (shouldStopPropagation) {
1913
+ e.stopPropagation();
1914
+ }
1915
+ };
1916
+ }
1917
+
1918
+ /*
1919
+ * Copyright 2020 Adobe. All rights reserved.
1920
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
1921
+ * you may not use this file except in compliance with the License. You may obtain a copy
1922
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
1923
+ *
1924
+ * Unless required by applicable law or agreed to in writing, software distributed under
1925
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
1926
+ * OF ANY KIND, either express or implied. See the License for the specific language
1927
+ * governing permissions and limitations under the License.
1928
+ */
1929
+ /**
1930
+ * Handles keyboard interactions for a focusable element.
1931
+ */
1932
+ function useKeyboard(props) {
1933
+ return {
1934
+ keyboardProps: props.isDisabled ? {} : {
1935
+ onKeyDown: createEventHandler(props.onKeyDown),
1936
+ onKeyUp: createEventHandler(props.onKeyUp)
1937
+ }
1938
+ };
1939
+ }
1940
+
1941
+ /* eslint-disable prefer-const */
1942
+ // scroll wheel needs to be added not passively so it's cancelable, small helper hook to remember that
1943
+ function useScrollWheel(props, ref) {
1944
+ let {
1945
+ onScroll,
1946
+ isDisabled
1947
+ } = props;
1948
+ let onScrollHandler = useCallback(e => {
1949
+ // If the ctrlKey is pressed, this is a zoom event, do nothing.
1950
+ if (e.ctrlKey) {
1951
+ return;
1952
+ }
1953
+
1954
+ // stop scrolling the page
1955
+ e.preventDefault();
1956
+ e.stopPropagation();
1957
+ if (onScroll) {
1958
+ onScroll({
1959
+ deltaX: e.deltaX,
1960
+ deltaY: e.deltaY
1961
+ });
1962
+ }
1963
+ }, [onScroll]);
1964
+ useEvent(ref, 'wheel', isDisabled ? undefined : onScrollHandler);
1965
+ }
1966
+
1967
+ /* eslint-disable prefer-const */
1968
+
1969
+ /**
1970
+ * A utility function that focuses an element while avoiding undesired side effects such
1971
+ * as page scrolling and screen reader issues with CSS transitions.
1972
+ */
1973
+ function focusSafely(element) {
1974
+ // If the user is interacting with a virtual cursor, e.g. screen reader, then
1975
+ // wait until after any animated transitions that are currently occurring on
1976
+ // the page before shifting focus. This avoids issues with VoiceOver on iOS
1977
+ // causing the page to scroll when moving focus if the element is transitioning
1978
+ // from off the screen.
1979
+ const ownerDocument = getOwnerDocument(element);
1980
+ if (getInteractionModality() === 'virtual') {
1981
+ let lastFocusedElement = ownerDocument.activeElement;
1982
+ runAfterTransition(() => {
1983
+ // If focus did not move and the element is still in the document, focus it.
1984
+ if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) {
1985
+ focusWithoutScrolling(element);
1986
+ }
1987
+ });
1988
+ } else {
1989
+ focusWithoutScrolling(element);
1990
+ }
1991
+ }
1992
+
1993
+ const _excluded$3 = ["ref"];
1994
+ let FocusableContext = /*#__PURE__*/React__default.createContext(null);
1995
+ function useFocusableContext(ref) {
1996
+ let context = useContext(FocusableContext) || {};
1997
+ useSyncRef(context, ref);
1998
+
1999
+ // eslint-disable-next-line
2000
+ let otherProps = _objectWithoutProperties(context, _excluded$3);
2001
+ return otherProps;
2002
+ }
2003
+ /**
2004
+ * Used to make an element focusable and capable of auto focus.
2005
+ */
2006
+ function useFocusable(props, domRef) {
2007
+ let {
2008
+ focusProps
2009
+ } = useFocus(props);
2010
+ let {
2011
+ keyboardProps
2012
+ } = useKeyboard(props);
2013
+ let interactions = mergeProps(focusProps, keyboardProps);
2014
+ let domProps = useFocusableContext(domRef);
2015
+ let interactionProps = props.isDisabled ? {} : domProps;
2016
+ let autoFocusRef = useRef(props.autoFocus);
2017
+ useEffect(() => {
2018
+ if (autoFocusRef.current && domRef.current) {
2019
+ focusSafely(domRef.current);
2020
+ }
2021
+ autoFocusRef.current = false;
2022
+ }, [domRef]);
2023
+ return {
2024
+ focusableProps: mergeProps(_objectSpread2(_objectSpread2({}, interactions), {}, {
2025
+ tabIndex: props.excludeFromTabOrder && !props.isDisabled ? -1 : undefined
2026
+ }), interactionProps)
2027
+ };
2028
+ }
4
2029
 
5
2030
  /**
6
2031
  * Component variant.
7
2032
  */
8
- declare const NumberFieldVariant: {
9
- readonly default: "default";
10
- readonly underline: "underline";
2033
+ const NumberFieldVariant = {
2034
+ default: 'default',
2035
+ underline: 'underline'
11
2036
  };
12
- type NumberFieldVariant = ValueOf<typeof NumberFieldVariant>;
2037
+
13
2038
  /**
14
2039
  * Component props.
15
2040
  */
16
- interface NumberFieldProps extends Omit<TextFieldProps, 'defaultValue' | 'onChange' | 'value' | 'onBlur' | 'onFocus' | 'onKeyDown' | 'onKeyUp' | 'after' | 'internal' | 'pills' | 'placeholder'> {
17
- /** Handler that is called when the element receives focus. */
18
- onFocus?: (e: FocusEvent<Element>) => void;
19
- /** Handler that is called when the element loses focus. */
20
- onBlur?: (e: FocusEvent<Element>) => void;
21
- /** Handler that is called when the element's focus status changes. */
22
- onFocusChange?: (isFocused: boolean) => void;
23
- /** Handler that is called when a key is pressed. */
24
- onKeyDown?: (e: KeyboardEvent<HTMLElement>) => void;
25
- /** Handler that is called when a key is released. */
26
- onKeyUp?: (e: KeyboardEvent<HTMLElement>) => void;
27
- /**
28
- * Default value.
29
- * Used for uncontrolled version.
30
- */
31
- defaultValue?: number;
32
- /** Method to handle component change. */
33
- onChange?(value?: number, name?: string, event?: ChangeEvent<HTMLInputElement>): void;
34
- /**
35
- * Input value.
36
- * Used for controlled version.
37
- */
38
- value?: number;
39
- /** Placeholder. */
40
- placeholder?: number;
41
- /** A custom aria-label for the decrement button. If not provided, the localized string "Decrement" is used. */
42
- decrementAriaLabel?: string;
43
- /** A custom aria-label for the increment button. If not provided, the localized string "Increment" is used. */
44
- incrementAriaLabel?: string;
45
- /**
46
- * Enables or disables changing the value with scroll.
47
- */
48
- isWheelDisabled?: boolean;
49
- /**
50
- * Formatting options for the value displayed in the number field.
51
- * This also affects what characters are allowed to be typed by the user.
52
- */
53
- formatOptions?: Intl.NumberFormatOptions;
54
- /** The smallest value allowed for the input. */
55
- minValue?: number;
56
- /** The largest value allowed for the input. */
57
- maxValue?: number;
58
- /** The amount that the input value changes with each increment or decrement "tick". */
59
- step?: number;
60
- }
61
- type StyledNumberFieldProps = Omit<NumberFieldProps, 'color' | 'isColored' | 'isDisabled' | 'isInvalid' | 'isRequired' | 'onChange' | 'onBlur' | 'onFocus'> & {
62
- $hasLeftIcon: boolean;
63
- $hasContent: boolean;
64
- $isColored: NumberFieldProps['isColored'];
65
- $isDisabled: NumberFieldProps['isDisabled'];
66
- $isInvalid: NumberFieldProps['isInvalid'];
67
- $isFocused: boolean;
68
- $isFocusVisible: boolean;
69
- $isRequired: NumberFieldProps['isRequired'];
70
- $theme: NumberFieldProps['theme'];
71
- $variant: NumberFieldProps['variant'];
2041
+
2042
+ const VALID_VALIDITY_STATE = {
2043
+ badInput: false,
2044
+ customError: false,
2045
+ patternMismatch: false,
2046
+ rangeOverflow: false,
2047
+ rangeUnderflow: false,
2048
+ stepMismatch: false,
2049
+ tooLong: false,
2050
+ tooShort: false,
2051
+ typeMismatch: false,
2052
+ valueMissing: false,
2053
+ valid: true
2054
+ };
2055
+ const CUSTOM_VALIDITY_STATE = _objectSpread2(_objectSpread2({}, VALID_VALIDITY_STATE), {}, {
2056
+ customError: true,
2057
+ valid: false
2058
+ });
2059
+ const DEFAULT_VALIDATION_RESULT = {
2060
+ isInvalid: false,
2061
+ validationDetails: VALID_VALIDITY_STATE,
2062
+ validationErrors: []
72
2063
  };
2064
+ const FormValidationContext = /*#__PURE__*/createContext({});
2065
+ const privateValidationStateProp = '__formValidationState' + Date.now();
2066
+ function useFormValidationState(props) {
2067
+ // Private prop for parent components to pass state to children.
2068
+ if (props[privateValidationStateProp]) {
2069
+ let {
2070
+ realtimeValidation,
2071
+ displayValidation,
2072
+ updateValidation,
2073
+ resetValidation,
2074
+ commitValidation
2075
+ } = props[privateValidationStateProp];
2076
+ return {
2077
+ realtimeValidation,
2078
+ displayValidation,
2079
+ updateValidation,
2080
+ resetValidation,
2081
+ commitValidation
2082
+ };
2083
+ }
2084
+
2085
+ // eslint-disable-next-line react-hooks/rules-of-hooks
2086
+ return useFormValidationStateImpl(props);
2087
+ }
2088
+ function useFormValidationStateImpl(props) {
2089
+ var _builtinValidation;
2090
+ let {
2091
+ isInvalid,
2092
+ validationState,
2093
+ name,
2094
+ value,
2095
+ builtinValidation,
2096
+ validate,
2097
+ validationBehavior = 'aria'
2098
+ } = props;
2099
+
2100
+ // backward compatibility.
2101
+ if (validationState) {
2102
+ isInvalid ||= validationState === 'invalid';
2103
+ }
2104
+
2105
+ // If the isInvalid prop is controlled, update validation result in realtime.
2106
+ let controlledError = isInvalid !== undefined ? {
2107
+ isInvalid,
2108
+ validationErrors: [],
2109
+ validationDetails: CUSTOM_VALIDITY_STATE
2110
+ } : null;
2111
+
2112
+ // Perform custom client side validation.
2113
+ let clientError = useMemo(() => getValidationResult(runValidate(validate, value)), [validate, value]);
2114
+ if ((_builtinValidation = builtinValidation) !== null && _builtinValidation !== void 0 && _builtinValidation.validationDetails.valid) {
2115
+ builtinValidation = null;
2116
+ }
2117
+
2118
+ // Get relevant server errors from the form.
2119
+ let serverErrors = useContext(FormValidationContext);
2120
+ let serverErrorMessages = useMemo(() => {
2121
+ if (name) {
2122
+ return Array.isArray(name) ? name.flatMap(name => asArray(serverErrors[name])) : asArray(serverErrors[name]);
2123
+ }
2124
+ return [];
2125
+ }, [serverErrors, name]);
2126
+
2127
+ // Show server errors when the form gets a new value, and clear when the user changes the value.
2128
+ let [lastServerErrors, setLastServerErrors] = useState(serverErrors);
2129
+ let [isServerErrorCleared, setServerErrorCleared] = useState(false);
2130
+ if (serverErrors !== lastServerErrors) {
2131
+ setLastServerErrors(serverErrors);
2132
+ setServerErrorCleared(false);
2133
+ }
2134
+ let serverError = useMemo(() => getValidationResult(isServerErrorCleared ? [] : serverErrorMessages), [isServerErrorCleared, serverErrorMessages]);
2135
+
2136
+ // Track the next validation state in a ref until commitValidation is called.
2137
+ let nextValidation = useRef(DEFAULT_VALIDATION_RESULT);
2138
+ let [currentValidity, setCurrentValidity] = useState(DEFAULT_VALIDATION_RESULT);
2139
+ let lastError = useRef(DEFAULT_VALIDATION_RESULT);
2140
+ let commitValidation = () => {
2141
+ if (!commitQueued) {
2142
+ return;
2143
+ }
2144
+ setCommitQueued(false);
2145
+ let error = clientError || builtinValidation || nextValidation.current;
2146
+ if (!isEqualValidation(error, lastError.current)) {
2147
+ lastError.current = error;
2148
+ setCurrentValidity(error);
2149
+ }
2150
+ };
2151
+ let [commitQueued, setCommitQueued] = useState(false);
2152
+ useEffect(commitValidation);
2153
+
2154
+ // realtimeValidation is used to update the native input element's state based on custom validation logic.
2155
+ // displayValidation is the currently displayed validation state that the user sees (e.g. on input change/form submit).
2156
+ // With validationBehavior="aria", all errors are displayed in realtime rather than on submit.
2157
+ let realtimeValidation = controlledError || serverError || clientError || builtinValidation || DEFAULT_VALIDATION_RESULT;
2158
+ let displayValidation = validationBehavior === 'native' ? controlledError || serverError || currentValidity : controlledError || serverError || clientError || builtinValidation || currentValidity;
2159
+ return {
2160
+ realtimeValidation,
2161
+ displayValidation,
2162
+ updateValidation(value) {
2163
+ // If validationBehavior is 'aria', update in realtime. Otherwise, store in a ref until commit.
2164
+ if (validationBehavior === 'aria' && !isEqualValidation(currentValidity, value)) {
2165
+ setCurrentValidity(value);
2166
+ } else {
2167
+ nextValidation.current = value;
2168
+ }
2169
+ },
2170
+ resetValidation() {
2171
+ // Update the currently displayed validation state to valid on form reset,
2172
+ // even if the native validity says it isn't. It'll show again on the next form submit.
2173
+ let error = DEFAULT_VALIDATION_RESULT;
2174
+ if (!isEqualValidation(error, lastError.current)) {
2175
+ lastError.current = error;
2176
+ setCurrentValidity(error);
2177
+ }
2178
+
2179
+ // Do not commit validation after the next render. This avoids a condition where
2180
+ // useSelect calls commitValidation inside an onReset handler.
2181
+ if (validationBehavior === 'native') {
2182
+ setCommitQueued(false);
2183
+ }
2184
+ setServerErrorCleared(true);
2185
+ },
2186
+ commitValidation() {
2187
+ // Commit validation state so the user sees it on blur/change/submit. Also clear any server errors.
2188
+ // Wait until after the next render to commit so that the latest value has been validated.
2189
+ if (validationBehavior === 'native') {
2190
+ setCommitQueued(true);
2191
+ }
2192
+ setServerErrorCleared(true);
2193
+ }
2194
+ };
2195
+ }
2196
+ function asArray(v) {
2197
+ if (!v) {
2198
+ return [];
2199
+ }
2200
+ return Array.isArray(v) ? v : [v];
2201
+ }
2202
+ function runValidate(validate, value) {
2203
+ if (typeof validate === 'function') {
2204
+ let e = validate(value);
2205
+ if (e && typeof e !== 'boolean') {
2206
+ return asArray(e);
2207
+ }
2208
+ }
2209
+ return [];
2210
+ }
2211
+ function getValidationResult(errors) {
2212
+ return errors.length ? {
2213
+ isInvalid: true,
2214
+ validationErrors: errors,
2215
+ validationDetails: CUSTOM_VALIDITY_STATE
2216
+ } : null;
2217
+ }
2218
+ function isEqualValidation(a, b) {
2219
+ if (a === b) {
2220
+ return true;
2221
+ }
2222
+ return a && b && a.isInvalid === b.isInvalid && a.validationErrors.length === b.validationErrors.length && a.validationErrors.every((a, i) => a === b.validationErrors[i]) && Object.entries(a.validationDetails).every(_ref => {
2223
+ let [k, v] = _ref;
2224
+ return b.validationDetails[k] === v;
2225
+ });
2226
+ }
2227
+
2228
+ /**
2229
+ * Provides state management for a number field component. Number fields allow users to enter a number,
2230
+ * and increment or decrement the value using stepper buttons.
2231
+ */
2232
+ function useNumberFieldState(props) {
2233
+ let {
2234
+ minValue,
2235
+ maxValue,
2236
+ step,
2237
+ formatOptions,
2238
+ value,
2239
+ defaultValue = NaN,
2240
+ onChange,
2241
+ locale,
2242
+ isDisabled,
2243
+ isReadOnly
2244
+ } = props;
2245
+ if (value === null) {
2246
+ value = NaN;
2247
+ }
2248
+ if (value !== undefined && !isNaN(value)) {
2249
+ if (step !== undefined && !isNaN(step)) {
2250
+ value = snapValueToStep(value, minValue, maxValue, step);
2251
+ } else {
2252
+ value = clamp(value, minValue, maxValue);
2253
+ }
2254
+ }
2255
+ if (!isNaN(defaultValue)) {
2256
+ if (step !== undefined && !isNaN(step)) {
2257
+ defaultValue = snapValueToStep(defaultValue, minValue, maxValue, step);
2258
+ } else {
2259
+ defaultValue = clamp(defaultValue, minValue, maxValue);
2260
+ }
2261
+ }
2262
+ let [numberValue, setNumberValue] = useControlledState(value, isNaN(defaultValue) ? NaN : defaultValue, onChange);
2263
+ let [inputValue, setInputValue] = useState(() => isNaN(numberValue) ? '' : new NumberFormatter(locale, formatOptions).format(numberValue));
2264
+ let numberParser = useMemo(() => new NumberParser(locale, formatOptions), [locale, formatOptions]);
2265
+ let numberingSystem = useMemo(() => numberParser.getNumberingSystem(inputValue), [numberParser, inputValue]);
2266
+ let formatter = useMemo(() => new NumberFormatter(locale, _objectSpread2(_objectSpread2({}, formatOptions), {}, {
2267
+ numberingSystem
2268
+ })), [locale, formatOptions, numberingSystem]);
2269
+ let intlOptions = useMemo(() => formatter.resolvedOptions(), [formatter]);
2270
+ let format = useCallback(value => isNaN(value) || value === null ? '' : formatter.format(value), [formatter]);
2271
+ let validation = useFormValidationState(_objectSpread2(_objectSpread2({}, props), {}, {
2272
+ value: numberValue
2273
+ }));
2274
+ let clampStep = step !== undefined && !isNaN(step) ? step : 1;
2275
+ if (intlOptions.style === 'percent' && (step === undefined || isNaN(step))) {
2276
+ clampStep = 0.01;
2277
+ }
2278
+
2279
+ // Update the input value when the number value or format options change. This is done
2280
+ // in a useEffect so that the controlled behavior is correct and we only update the
2281
+ // textfield after prop changes.
2282
+ let [prevValue, setPrevValue] = useState(numberValue);
2283
+ let [prevLocale, setPrevLocale] = useState(locale);
2284
+ let [prevFormatOptions, setPrevFormatOptions] = useState(formatOptions);
2285
+ if (!Object.is(numberValue, prevValue) || locale !== prevLocale || formatOptions !== prevFormatOptions) {
2286
+ setInputValue(format(numberValue));
2287
+ setPrevValue(numberValue);
2288
+ setPrevLocale(locale);
2289
+ setPrevFormatOptions(formatOptions);
2290
+ }
2291
+ let parsedValue = useMemo(() => numberParser.parse(inputValue), [numberParser, inputValue]);
2292
+ let commit = () => {
2293
+ // Set to empty state if input value is empty
2294
+ if (!inputValue.length) {
2295
+ setNumberValue(NaN);
2296
+ setInputValue(value === undefined ? '' : format(numberValue));
2297
+ return;
2298
+ }
2299
+
2300
+ // if it failed to parse, then reset input to formatted version of current number
2301
+ if (isNaN(parsedValue)) {
2302
+ setInputValue(format(numberValue));
2303
+ return;
2304
+ }
2305
+
2306
+ // Clamp to min and max, round to the nearest step, and round to specified number of digits
2307
+ let clampedValue;
2308
+ if (step === undefined || isNaN(step)) {
2309
+ clampedValue = clamp(parsedValue, minValue, maxValue);
2310
+ } else {
2311
+ clampedValue = snapValueToStep(parsedValue, minValue, maxValue, step);
2312
+ }
2313
+ clampedValue = numberParser.parse(format(clampedValue));
2314
+ setNumberValue(clampedValue);
2315
+
2316
+ // in a controlled state, the numberValue won't change, so we won't go back to our old input without help
2317
+ setInputValue(format(value === undefined ? clampedValue : numberValue));
2318
+ };
2319
+ let safeNextStep = function (operation) {
2320
+ let minMax = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
2321
+ let prev = parsedValue;
2322
+ if (isNaN(prev)) {
2323
+ // if the input is empty, start from the min/max value when incrementing/decrementing,
2324
+ // or zero if there is no min/max value defined.
2325
+ let newValue = isNaN(minMax) ? 0 : minMax;
2326
+ return snapValueToStep(newValue, minValue, maxValue, clampStep);
2327
+ } else {
2328
+ // otherwise, first snap the current value to the nearest step. if it moves in the direction
2329
+ // we're going, use that value, otherwise add the step and snap that value.
2330
+ let newValue = snapValueToStep(prev, minValue, maxValue, clampStep);
2331
+ if (operation === '+' && newValue > prev || operation === '-' && newValue < prev) {
2332
+ return newValue;
2333
+ }
2334
+ return snapValueToStep(handleDecimalOperation(operation, prev, clampStep), minValue, maxValue, clampStep);
2335
+ }
2336
+ };
2337
+ let increment = () => {
2338
+ let newValue = safeNextStep('+', minValue);
2339
+
2340
+ // if we've arrived at the same value that was previously in the state, the
2341
+ // input value should be updated to match
2342
+ // ex type 4, press increment, highlight the number in the input, type 4 again, press increment
2343
+ // you'd be at 5, then incrementing to 5 again, so no re-render would happen and 4 would be left in the input
2344
+ if (newValue === numberValue) {
2345
+ setInputValue(format(newValue));
2346
+ }
2347
+ setNumberValue(newValue);
2348
+ validation.commitValidation();
2349
+ };
2350
+ let decrement = () => {
2351
+ let newValue = safeNextStep('-', maxValue);
2352
+ if (newValue === numberValue) {
2353
+ setInputValue(format(newValue));
2354
+ }
2355
+ setNumberValue(newValue);
2356
+ validation.commitValidation();
2357
+ };
2358
+ let incrementToMax = () => {
2359
+ if (maxValue != null) {
2360
+ setNumberValue(snapValueToStep(maxValue, minValue, maxValue, clampStep));
2361
+ validation.commitValidation();
2362
+ }
2363
+ };
2364
+ let decrementToMin = () => {
2365
+ if (minValue != null) {
2366
+ setNumberValue(minValue);
2367
+ validation.commitValidation();
2368
+ }
2369
+ };
2370
+ let canIncrement = useMemo(() => !isDisabled && !isReadOnly && (isNaN(parsedValue) || maxValue === undefined || isNaN(maxValue) || snapValueToStep(parsedValue, minValue, maxValue, clampStep) > parsedValue || handleDecimalOperation('+', parsedValue, clampStep) <= maxValue), [isDisabled, isReadOnly, minValue, maxValue, clampStep, parsedValue]);
2371
+ let canDecrement = useMemo(() => !isDisabled && !isReadOnly && (isNaN(parsedValue) || minValue === undefined || isNaN(minValue) || snapValueToStep(parsedValue, minValue, maxValue, clampStep) < parsedValue || handleDecimalOperation('-', parsedValue, clampStep) >= minValue), [isDisabled, isReadOnly, minValue, maxValue, clampStep, parsedValue]);
2372
+ let validate = value => numberParser.isValidPartialNumber(value, minValue, maxValue);
2373
+ return _objectSpread2(_objectSpread2({}, validation), {}, {
2374
+ validate,
2375
+ increment,
2376
+ incrementToMax,
2377
+ decrement,
2378
+ decrementToMin,
2379
+ canIncrement,
2380
+ canDecrement,
2381
+ minValue,
2382
+ maxValue,
2383
+ numberValue: parsedValue,
2384
+ setNumberValue,
2385
+ setInputValue,
2386
+ inputValue,
2387
+ commit
2388
+ });
2389
+ }
2390
+ function handleDecimalOperation(operator, value1, value2) {
2391
+ let result = operator === '+' ? value1 + value2 : value1 - value2;
2392
+
2393
+ // Check if we have decimals
2394
+ if (value1 % 1 !== 0 || value2 % 1 !== 0) {
2395
+ const value1Decimal = value1.toString().split('.');
2396
+ const value2Decimal = value2.toString().split('.');
2397
+ const value1DecimalLength = value1Decimal[1] && value1Decimal[1].length || 0;
2398
+ const value2DecimalLength = value2Decimal[1] && value2Decimal[1].length || 0;
2399
+ const multiplier = Math.pow(10, Math.max(value1DecimalLength, value2DecimalLength));
2400
+
2401
+ // Transform the decimals to integers based on the precision
2402
+ value1 = Math.round(value1 * multiplier);
2403
+ value2 = Math.round(value2 * multiplier);
2404
+
2405
+ // Perform the operation on integers values to make sure we don't get a fancy decimal value
2406
+ result = operator === '+' ? value1 + value2 : value1 - value2;
2407
+
2408
+ // Transform the integer result back to decimal
2409
+ result /= multiplier;
2410
+ }
2411
+ return result;
2412
+ }
2413
+
2414
+ var decrease$1 = "Decrease {fieldLabel}";
2415
+ var increase$1 = "Increase {fieldLabel}";
2416
+ var numberField$1 = "Number field";
2417
+ var enUS$1 = {
2418
+ decrease: decrease$1,
2419
+ increase: increase$1,
2420
+ numberField: numberField$1
2421
+ };
2422
+
2423
+ var decrease = "Diminuer {fieldLabel}";
2424
+ var increase = "Augmenter {fieldLabel}";
2425
+ var numberField = "Champ de nombre";
2426
+ var frFR$1 = {
2427
+ decrease: decrease,
2428
+ increase: increase,
2429
+ numberField: numberField
2430
+ };
2431
+
2432
+ var intlMessages$1 = {
2433
+ 'en-US': enUS$1,
2434
+ 'fr-FR': frFR$1
2435
+ };
2436
+
2437
+ /* eslint-disable prefer-const */
2438
+ /**
2439
+ * Provides the accessibility implementation for labels and their associated elements.
2440
+ * Labels provide context for user inputs.
2441
+ * @param props - The props for labels and fields.
2442
+ */
2443
+ function useLabel(props) {
2444
+ let {
2445
+ id,
2446
+ label,
2447
+ 'aria-labelledby': ariaLabelledby,
2448
+ 'aria-label': ariaLabel,
2449
+ labelElementType = 'label'
2450
+ } = props;
2451
+ id = useId(id);
2452
+ let labelId = useId();
2453
+ let labelProps = {};
2454
+ if (label) {
2455
+ ariaLabelledby = ariaLabelledby ? `${labelId} ${ariaLabelledby}` : labelId;
2456
+ labelProps = {
2457
+ id: labelId,
2458
+ htmlFor: labelElementType === 'label' ? id : undefined
2459
+ };
2460
+ } else if (!ariaLabelledby && !ariaLabel) {
2461
+ console.warn('If you do not provide a visible label, you must specify an aria-label or aria-labelledby attribute for accessibility');
2462
+ }
2463
+ let fieldProps = useLabels({
2464
+ id,
2465
+ 'aria-label': ariaLabel,
2466
+ 'aria-labelledby': ariaLabelledby
2467
+ });
2468
+ return {
2469
+ labelProps,
2470
+ fieldProps
2471
+ };
2472
+ }
2473
+
2474
+ /* eslint-disable prefer-const */
2475
+ /**
2476
+ * Provides the accessibility implementation for input fields.
2477
+ * Fields accept user input, gain context from their label, and may display a description or error message.
2478
+ * @param props - Props for the Field.
2479
+ */
2480
+ function useField(props) {
2481
+ let {
2482
+ description,
2483
+ errorMessage,
2484
+ isInvalid,
2485
+ validationState
2486
+ } = props;
2487
+ let {
2488
+ labelProps,
2489
+ fieldProps
2490
+ } = useLabel(props);
2491
+ let descriptionId = useSlotId([Boolean(description), Boolean(errorMessage), isInvalid, validationState]);
2492
+ let errorMessageId = useSlotId([Boolean(description), Boolean(errorMessage), isInvalid, validationState]);
2493
+ fieldProps = mergeProps(fieldProps, {
2494
+ 'aria-describedby': [descriptionId,
2495
+ // Use aria-describedby for error message because aria-errormessage is unsupported using VoiceOver or NVDA. See https://github.com/adobe/react-spectrum/issues/1346#issuecomment-740136268
2496
+ errorMessageId, props['aria-describedby']].filter(Boolean).join(' ') || undefined
2497
+ });
2498
+ return {
2499
+ labelProps,
2500
+ fieldProps,
2501
+ descriptionProps: {
2502
+ id: descriptionId
2503
+ },
2504
+ errorMessageProps: {
2505
+ id: errorMessageId
2506
+ }
2507
+ };
2508
+ }
2509
+
2510
+ /* eslint-disable prefer-const */
2511
+ function useFormValidation(props, state, ref) {
2512
+ let {
2513
+ validationBehavior,
2514
+ focus
2515
+ } = props;
2516
+
2517
+ // This is a useLayoutEffect so that it runs before the useEffect in useFormValidationState, which commits the validation change.
2518
+ useLayoutEffect(() => {
2519
+ if (validationBehavior === 'native' && ref !== null && ref !== void 0 && ref.current) {
2520
+ let errorMessage = state.realtimeValidation.isInvalid ? state.realtimeValidation.validationErrors.join(' ') || 'Invalid value.' : '';
2521
+ ref.current.setCustomValidity(errorMessage);
2522
+
2523
+ // Prevent default tooltip for validation message.
2524
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=605277
2525
+ if (!ref.current.hasAttribute('title')) {
2526
+ ref.current.title = '';
2527
+ }
2528
+ if (!state.realtimeValidation.isInvalid) {
2529
+ state.updateValidation(getNativeValidity(ref.current));
2530
+ }
2531
+ }
2532
+ });
2533
+ let onReset = useEffectEvent(() => {
2534
+ state.resetValidation();
2535
+ });
2536
+ let onInvalid = useEffectEvent(e => {
2537
+ var _ref$current;
2538
+ // Only commit validation if we are not already displaying one.
2539
+ // This avoids clearing server errors that the user didn't actually fix.
2540
+ if (!state.displayValidation.isInvalid) {
2541
+ state.commitValidation();
2542
+ }
2543
+
2544
+ // Auto focus the first invalid input in a form, unless the error already had its default prevented.
2545
+ let form = ref === null || ref === void 0 ? void 0 : (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.form;
2546
+ if (!e.defaultPrevented && ref && form && getFirstInvalidInput(form) === ref.current) {
2547
+ if (focus) {
2548
+ focus();
2549
+ } else {
2550
+ var _ref$current2;
2551
+ (_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.focus();
2552
+ }
2553
+
2554
+ // Always show focus ring.
2555
+ setInteractionModality('keyboard');
2556
+ }
2557
+
2558
+ // Prevent default browser error UI from appearing.
2559
+ e.preventDefault();
2560
+ });
2561
+ let onChange = useEffectEvent(() => {
2562
+ state.commitValidation();
2563
+ });
2564
+ useEffect(() => {
2565
+ let input = ref === null || ref === void 0 ? void 0 : ref.current;
2566
+ if (!input) {
2567
+ return;
2568
+ }
2569
+ let form = input.form;
2570
+ input.addEventListener('invalid', onInvalid);
2571
+ input.addEventListener('change', onChange);
2572
+ form === null || form === void 0 ? void 0 : form.addEventListener('reset', onReset);
2573
+ return () => {
2574
+ input.removeEventListener('invalid', onInvalid);
2575
+ input.removeEventListener('change', onChange);
2576
+ form === null || form === void 0 ? void 0 : form.removeEventListener('reset', onReset);
2577
+ };
2578
+ }, [ref, onInvalid, onChange, onReset, validationBehavior]);
2579
+ }
2580
+ function getValidity(input) {
2581
+ // The native ValidityState object is live, meaning each property is a getter that returns the current state.
2582
+ // We need to create a snapshot of the validity state at the time this function is called to avoid unpredictable React renders.
2583
+ let validity = input.validity;
2584
+ return {
2585
+ badInput: validity.badInput,
2586
+ customError: validity.customError,
2587
+ patternMismatch: validity.patternMismatch,
2588
+ rangeOverflow: validity.rangeOverflow,
2589
+ rangeUnderflow: validity.rangeUnderflow,
2590
+ stepMismatch: validity.stepMismatch,
2591
+ tooLong: validity.tooLong,
2592
+ tooShort: validity.tooShort,
2593
+ typeMismatch: validity.typeMismatch,
2594
+ valueMissing: validity.valueMissing,
2595
+ valid: validity.valid
2596
+ };
2597
+ }
2598
+ function getNativeValidity(input) {
2599
+ return {
2600
+ isInvalid: !input.validity.valid,
2601
+ validationDetails: getValidity(input),
2602
+ validationErrors: input.validationMessage ? [input.validationMessage] : []
2603
+ };
2604
+ }
2605
+ function getFirstInvalidInput(form) {
2606
+ for (let i = 0; i < form.elements.length; i++) {
2607
+ let element = form.elements[i];
2608
+ if (!element.validity.valid) {
2609
+ return element;
2610
+ }
2611
+ }
2612
+ return null;
2613
+ }
2614
+
2615
+ /**
2616
+ * A map of HTML element names and their interface types.
2617
+ * For example `'a'` -> `HTMLAnchorElement`.
2618
+ */
2619
+
2620
+ /**
2621
+ * A map of HTML element names and their attribute interface types.
2622
+ * For example `'a'` -> `AnchorHTMLAttributes<HTMLAnchorElement>`.
2623
+ */
2624
+
2625
+ /**
2626
+ * The intrinsic HTML element names that `useTextField` supports; e.g. `input`,
2627
+ * `textarea`.
2628
+ */
2629
+
2630
+ /**
2631
+ * The HTML element interfaces that `useTextField` supports based on what is
2632
+ * defined for `TextFieldIntrinsicElements`; e.g. `HTMLInputElement`,
2633
+ * `HTMLTextAreaElement`.
2634
+ */
2635
+
2636
+ /**
2637
+ * The HTML attributes interfaces that `useTextField` supports based on what
2638
+ * is defined for `TextFieldIntrinsicElements`; e.g. `InputHTMLAttributes`,
2639
+ * `TextareaHTMLAttributes`.
2640
+ */
2641
+
2642
+ /**
2643
+ * The type of `inputProps` returned by `useTextField`; e.g. `InputHTMLAttributes`,
2644
+ * `TextareaHTMLAttributes`.
2645
+ */
2646
+
2647
+ /**
2648
+ * The type of `ref` object that can be passed to `useTextField` based on the given
2649
+ * intrinsic HTML element name; e.g.`RefObject<HTMLInputElement>`,
2650
+ * `RefObject<HTMLTextAreaElement>`.
2651
+ */
2652
+
2653
+ /**
2654
+ * Provides the behavior and accessibility implementation for a text field.
2655
+ * @param props - Props for the text field.
2656
+ * @param ref - Ref to the HTML input or textarea element.
2657
+ */
2658
+ function useTextField(props, ref) {
2659
+ let {
2660
+ inputElementType = 'input',
2661
+ isDisabled = false,
2662
+ isRequired = false,
2663
+ isReadOnly = false,
2664
+ type = 'text',
2665
+ validationBehavior = 'aria'
2666
+ } = props;
2667
+ let [value, setValue] = useControlledState(props.value, props.defaultValue || '', props.onChange);
2668
+ let {
2669
+ focusableProps
2670
+ } = useFocusable(props, ref);
2671
+ let validationState = useFormValidationState(_objectSpread2(_objectSpread2({}, props), {}, {
2672
+ value
2673
+ }));
2674
+ let {
2675
+ isInvalid,
2676
+ validationErrors,
2677
+ validationDetails
2678
+ } = validationState.displayValidation;
2679
+ let {
2680
+ labelProps,
2681
+ fieldProps,
2682
+ descriptionProps,
2683
+ errorMessageProps
2684
+ } = useField(_objectSpread2(_objectSpread2({}, props), {}, {
2685
+ isInvalid,
2686
+ errorMessage: props.errorMessage || validationErrors
2687
+ }));
2688
+ let domProps = filterDOMProps(props, {
2689
+ labelable: true
2690
+ });
2691
+ const inputOnlyProps = {
2692
+ type,
2693
+ pattern: props.pattern
2694
+ };
2695
+ useFormReset(ref, value, setValue);
2696
+ useFormValidation(props, validationState, ref);
2697
+ useEffect(() => {
2698
+ // This works around a React/Chrome bug that prevents textarea elements from validating when controlled.
2699
+ // We prevent React from updating defaultValue (i.e. children) of textarea when `value` changes,
2700
+ // which causes Chrome to skip validation. Only updating `value` is ok in our case since our
2701
+ // textareas are always controlled. React is planning on removing this synchronization in a
2702
+ // future major version.
2703
+ // https://github.com/facebook/react/issues/19474
2704
+ // https://github.com/facebook/react/issues/11896
2705
+ if (ref.current instanceof getOwnerWindow(ref.current).HTMLTextAreaElement) {
2706
+ let input = ref.current;
2707
+ Object.defineProperty(input, 'defaultValue', {
2708
+ get: () => input.value,
2709
+ set: () => {},
2710
+ configurable: true
2711
+ });
2712
+ }
2713
+ }, [ref]);
2714
+ return {
2715
+ labelProps,
2716
+ inputProps: mergeProps(domProps, inputElementType === 'input' ? inputOnlyProps : undefined, _objectSpread2(_objectSpread2({
2717
+ disabled: isDisabled,
2718
+ readOnly: isReadOnly,
2719
+ required: isRequired && validationBehavior === 'native',
2720
+ 'aria-required': isRequired && validationBehavior === 'aria' || undefined,
2721
+ 'aria-invalid': isInvalid || undefined,
2722
+ 'aria-errormessage': props['aria-errormessage'],
2723
+ 'aria-activedescendant': props['aria-activedescendant'],
2724
+ 'aria-autocomplete': props['aria-autocomplete'],
2725
+ 'aria-haspopup': props['aria-haspopup'],
2726
+ value,
2727
+ onChange: e => setValue(e.target.value),
2728
+ autoComplete: props.autoComplete,
2729
+ autoCapitalize: props.autoCapitalize,
2730
+ maxLength: props.maxLength,
2731
+ minLength: props.minLength,
2732
+ name: props.name,
2733
+ placeholder: props.placeholder,
2734
+ inputMode: props.inputMode,
2735
+ // Clipboard events
2736
+ onCopy: props.onCopy,
2737
+ onCut: props.onCut,
2738
+ onPaste: props.onPaste,
2739
+ // Composition events
2740
+ onCompositionEnd: props.onCompositionEnd,
2741
+ onCompositionStart: props.onCompositionStart,
2742
+ onCompositionUpdate: props.onCompositionUpdate,
2743
+ // Selection events
2744
+ onSelect: props.onSelect,
2745
+ // Input events
2746
+ onBeforeInput: props.onBeforeInput,
2747
+ onInput: props.onInput
2748
+ }, focusableProps), fieldProps)),
2749
+ descriptionProps,
2750
+ errorMessageProps,
2751
+ isInvalid,
2752
+ validationErrors,
2753
+ validationDetails
2754
+ };
2755
+ }
2756
+
2757
+ const _excluded$2 = ["labelProps", "inputProps", "descriptionProps", "errorMessageProps"];
2758
+ function supportsNativeBeforeInputEvent() {
2759
+ return typeof window !== 'undefined' && window.InputEvent &&
2760
+ // @ts-ignore
2761
+ typeof InputEvent.prototype.getTargetRanges === 'function';
2762
+ }
2763
+ function useFormattedTextField(props, state, inputRef) {
2764
+ // All browsers implement the 'beforeinput' event natively except Firefox
2765
+ // (currently behind a flag as of Firefox 84). React's polyfill does not
2766
+ // run in all cases that the native event fires, e.g. when deleting text.
2767
+ // Use the native event if available so that we can prevent invalid deletions.
2768
+ // We do not attempt to polyfill this in Firefox since it would be very complicated,
2769
+ // the benefit of doing so is fairly minor, and it's going to be natively supported soon.
2770
+ let onBeforeInputFallback = useEffectEvent(e => {
2771
+ let input = inputRef.current;
2772
+
2773
+ // Compute the next value of the input if the event is allowed to proceed.
2774
+ // See https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes for a full list of input types.
2775
+ let nextValue;
2776
+ switch (e.inputType) {
2777
+ case 'historyUndo':
2778
+ case 'historyRedo':
2779
+ // Explicitly allow undo/redo. e.data is null in this case, but there's no need to validate,
2780
+ // because presumably the input would have already been validated previously.
2781
+ return;
2782
+ case 'insertLineBreak':
2783
+ // Explicitly allow "insertLineBreak" event, to allow onSubmit for "enter" key. e.data is null in this case.
2784
+ return;
2785
+ case 'deleteContent':
2786
+ case 'deleteByCut':
2787
+ case 'deleteByDrag':
2788
+ nextValue = input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
2789
+ break;
2790
+ case 'deleteContentForward':
2791
+ // This is potentially incorrect, since the browser may actually delete more than a single UTF-16
2792
+ // character. In reality, a full Unicode grapheme cluster consisting of multiple UTF-16 characters
2793
+ // or code points may be deleted. However, in our currently supported locales, there are no such cases.
2794
+ // If we support additional locales in the future, this may need to change.
2795
+ nextValue = input.selectionEnd === input.selectionStart ? input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd + 1) : input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
2796
+ break;
2797
+ case 'deleteContentBackward':
2798
+ nextValue = input.selectionEnd === input.selectionStart ? input.value.slice(0, input.selectionStart - 1) + input.value.slice(input.selectionStart) : input.value.slice(0, input.selectionStart) + input.value.slice(input.selectionEnd);
2799
+ break;
2800
+ case 'deleteSoftLineBackward':
2801
+ case 'deleteHardLineBackward':
2802
+ nextValue = input.value.slice(input.selectionStart);
2803
+ break;
2804
+ default:
2805
+ if (e.data != null) {
2806
+ nextValue = input.value.slice(0, input.selectionStart) + e.data + input.value.slice(input.selectionEnd);
2807
+ }
2808
+ break;
2809
+ }
2810
+
2811
+ // If we did not compute a value, or the new value is invalid, prevent the event
2812
+ // so that the browser does not update the input text, move the selection, or add to
2813
+ // the undo/redo stack.
2814
+ if (nextValue == null || !state.validate(nextValue)) {
2815
+ e.preventDefault();
2816
+ }
2817
+ });
2818
+ useEffect(() => {
2819
+ if (!supportsNativeBeforeInputEvent()) {
2820
+ return;
2821
+ }
2822
+ let input = inputRef.current;
2823
+ input.addEventListener('beforeinput', onBeforeInputFallback, false);
2824
+ return () => {
2825
+ input.removeEventListener('beforeinput', onBeforeInputFallback, false);
2826
+ };
2827
+ }, [inputRef, onBeforeInputFallback]);
2828
+ let onBeforeInput = !supportsNativeBeforeInputEvent() ? e => {
2829
+ let nextValue = e.target.value.slice(0, e.target.selectionStart) + e.data + e.target.value.slice(e.target.selectionEnd);
2830
+ if (!state.validate(nextValue)) {
2831
+ e.preventDefault();
2832
+ }
2833
+ } : null;
2834
+ let _useTextField = useTextField(props, inputRef),
2835
+ {
2836
+ labelProps,
2837
+ inputProps: textFieldProps,
2838
+ descriptionProps,
2839
+ errorMessageProps
2840
+ } = _useTextField,
2841
+ validation = _objectWithoutProperties(_useTextField, _excluded$2);
2842
+ let compositionStartState = useRef(null);
2843
+ return _objectSpread2({
2844
+ inputProps: mergeProps(textFieldProps, {
2845
+ onBeforeInput,
2846
+ onCompositionStart() {
2847
+ // Chrome does not implement Input Events Level 2, which specifies the insertFromComposition
2848
+ // and deleteByComposition inputType values for the beforeinput event. These are meant to occur
2849
+ // at the end of a composition (e.g. Pinyin IME, Android auto correct, etc.), and crucially, are
2850
+ // cancelable. The insertCompositionText and deleteCompositionText input types are not cancelable,
2851
+ // nor would we want to cancel them because the input from the user is incomplete at that point.
2852
+ // In Safari, insertFromComposition/deleteFromComposition will fire, however, allowing us to cancel
2853
+ // the final composition result if it is invalid. As a fallback for Chrome and Firefox, which either
2854
+ // don't support Input Events Level 2, or beforeinput at all, we store the state of the input when
2855
+ // the compositionstart event fires, and undo the changes in compositionend (below) if it is invalid.
2856
+ // Unfortunately, this messes up the undo/redo stack, but until insertFromComposition/deleteByComposition
2857
+ // are implemented, there is no other way to prevent composed input.
2858
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=1022204
2859
+ let {
2860
+ value,
2861
+ selectionStart,
2862
+ selectionEnd
2863
+ } = inputRef.current;
2864
+ compositionStartState.current = {
2865
+ value,
2866
+ selectionStart,
2867
+ selectionEnd
2868
+ };
2869
+ },
2870
+ onCompositionEnd() {
2871
+ if (!state.validate(inputRef.current.value)) {
2872
+ // Restore the input value in the DOM immediately so we can synchronously update the selection position.
2873
+ // But also update the value in React state as well so it is correct for future updates.
2874
+ let {
2875
+ value,
2876
+ selectionStart,
2877
+ selectionEnd
2878
+ } = compositionStartState.current;
2879
+ inputRef.current.value = value;
2880
+ inputRef.current.setSelectionRange(selectionStart, selectionEnd);
2881
+ state.setInputValue(value);
2882
+ }
2883
+ }
2884
+ }),
2885
+ labelProps,
2886
+ descriptionProps,
2887
+ errorMessageProps
2888
+ }, validation);
2889
+ }
2890
+
2891
+ /* eslint-disable prefer-const */
2892
+ // @ts-nocheck
2893
+ /*
2894
+ * Copyright 2020 Adobe. All rights reserved.
2895
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
2896
+ * you may not use this file except in compliance with the License. You may obtain a copy
2897
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
2898
+ *
2899
+ * Unless required by applicable law or agreed to in writing, software distributed under
2900
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
2901
+ * OF ANY KIND, either express or implied. See the License for the specific language
2902
+ * governing permissions and limitations under the License.
2903
+ */
2904
+
2905
+ /* Inspired by https://github.com/AlmeroSteyn/react-aria-live */
2906
+ const LIVEREGION_TIMEOUT_DELAY = 7000;
2907
+ let liveAnnouncer = null;
2908
+
2909
+ /**
2910
+ * Announces the message using screen reader technology.
2911
+ */
2912
+ function announce(message) {
2913
+ let assertiveness = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'assertive';
2914
+ let timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : LIVEREGION_TIMEOUT_DELAY;
2915
+ if (!liveAnnouncer) {
2916
+ liveAnnouncer = new LiveAnnouncer();
2917
+ }
2918
+ liveAnnouncer.announce(message, assertiveness, timeout);
2919
+ }
2920
+
2921
+ /**
2922
+ * Stops all queued announcements.
2923
+ */
2924
+ function clearAnnouncer(assertiveness) {
2925
+ if (liveAnnouncer) {
2926
+ liveAnnouncer.clear(assertiveness);
2927
+ }
2928
+ }
2929
+
2930
+ // LiveAnnouncer is implemented using vanilla DOM, not React. That's because as of React 18
2931
+ // ReactDOM.render is deprecated, and the replacement, ReactDOM.createRoot is moved into a
2932
+ // subpath import `react-dom/client`. That makes it hard for us to support multiple React versions.
2933
+ // As a global API, we can't use portals without introducing a breaking API change. LiveAnnouncer
2934
+ // is simple enough to implement without React, so that's what we do here.
2935
+ // See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638
2936
+ class LiveAnnouncer {
2937
+ constructor() {
2938
+ _defineProperty(this, "node", void 0);
2939
+ _defineProperty(this, "assertiveLog", void 0);
2940
+ _defineProperty(this, "politeLog", void 0);
2941
+ this.node = document.createElement('div');
2942
+ this.node.dataset.liveAnnouncer = 'true';
2943
+ // copied from VisuallyHidden
2944
+ Object.assign(this.node.style, {
2945
+ border: 0,
2946
+ clip: 'rect(0 0 0 0)',
2947
+ clipPath: 'inset(50%)',
2948
+ height: '1px',
2949
+ margin: '-1px',
2950
+ overflow: 'hidden',
2951
+ padding: 0,
2952
+ position: 'absolute',
2953
+ width: '1px',
2954
+ whiteSpace: 'nowrap'
2955
+ });
2956
+ this.assertiveLog = this.createLog('assertive');
2957
+ this.node.appendChild(this.assertiveLog);
2958
+ this.politeLog = this.createLog('polite');
2959
+ this.node.appendChild(this.politeLog);
2960
+ document.body.prepend(this.node);
2961
+ }
2962
+ createLog(ariaLive) {
2963
+ let node = document.createElement('div');
2964
+ node.setAttribute('role', 'log');
2965
+ node.setAttribute('aria-live', ariaLive);
2966
+ node.setAttribute('aria-relevant', 'additions');
2967
+ return node;
2968
+ }
2969
+ destroy() {
2970
+ if (!this.node) {
2971
+ return;
2972
+ }
2973
+ document.body.removeChild(this.node);
2974
+ this.node = null;
2975
+ }
2976
+ announce(message) {
2977
+ let assertiveness = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'assertive';
2978
+ let timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : LIVEREGION_TIMEOUT_DELAY;
2979
+ if (!this.node) {
2980
+ return;
2981
+ }
2982
+ let node = document.createElement('div');
2983
+ node.textContent = message;
2984
+ if (assertiveness === 'assertive') {
2985
+ this.assertiveLog.appendChild(node);
2986
+ } else {
2987
+ this.politeLog.appendChild(node);
2988
+ }
2989
+ if (message !== '') {
2990
+ setTimeout(() => {
2991
+ node.remove();
2992
+ }, timeout);
2993
+ }
2994
+ }
2995
+ clear(assertiveness) {
2996
+ if (!this.node) {
2997
+ return;
2998
+ }
2999
+ if (!assertiveness || assertiveness === 'assertive') {
3000
+ this.assertiveLog.innerHTML = '';
3001
+ }
3002
+ if (!assertiveness || assertiveness === 'polite') {
3003
+ this.politeLog.innerHTML = '';
3004
+ }
3005
+ }
3006
+ }
3007
+
3008
+ var Empty$1 = "Empty";
3009
+ var enUS = {
3010
+ Empty: Empty$1
3011
+ };
3012
+
3013
+ var Empty = "Vide";
3014
+ var frFR = {
3015
+ Empty: Empty
3016
+ };
3017
+
3018
+ var intlMessages = {
3019
+ 'en-US': enUS,
3020
+ 'fr-FR': frFR
3021
+ };
3022
+
3023
+ /* eslint-disable prefer-const */
3024
+ function useSpinButton(props) {
3025
+ const _async = useRef();
3026
+ let {
3027
+ value,
3028
+ textValue,
3029
+ minValue,
3030
+ maxValue,
3031
+ isDisabled,
3032
+ isReadOnly,
3033
+ isRequired,
3034
+ onIncrement,
3035
+ onIncrementPage,
3036
+ onDecrement,
3037
+ onDecrementPage,
3038
+ onDecrementToMin,
3039
+ onIncrementToMax
3040
+ } = props;
3041
+ const format = useMessageFormatter(intlMessages);
3042
+ const clearAsync = () => clearTimeout(_async.current);
3043
+
3044
+ // eslint-disable-next-line arrow-body-style
3045
+ useEffect(() => {
3046
+ return () => clearAsync();
3047
+ }, []);
3048
+ let onKeyDown = e => {
3049
+ if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey || isReadOnly) {
3050
+ return;
3051
+ }
3052
+ switch (e.key) {
3053
+ case 'PageUp':
3054
+ if (onIncrementPage) {
3055
+ e.preventDefault();
3056
+ onIncrementPage === null || onIncrementPage === void 0 ? void 0 : onIncrementPage();
3057
+ break;
3058
+ }
3059
+ // fallthrough!
3060
+ case 'ArrowUp':
3061
+ case 'Up':
3062
+ if (onIncrement) {
3063
+ e.preventDefault();
3064
+ onIncrement === null || onIncrement === void 0 ? void 0 : onIncrement();
3065
+ }
3066
+ break;
3067
+ case 'PageDown':
3068
+ if (onDecrementPage) {
3069
+ e.preventDefault();
3070
+ onDecrementPage === null || onDecrementPage === void 0 ? void 0 : onDecrementPage();
3071
+ break;
3072
+ }
3073
+ // fallthrough
3074
+ case 'ArrowDown':
3075
+ case 'Down':
3076
+ if (onDecrement) {
3077
+ e.preventDefault();
3078
+ onDecrement === null || onDecrement === void 0 ? void 0 : onDecrement();
3079
+ }
3080
+ break;
3081
+ case 'Home':
3082
+ if (onDecrementToMin) {
3083
+ e.preventDefault();
3084
+ onDecrementToMin === null || onDecrementToMin === void 0 ? void 0 : onDecrementToMin();
3085
+ }
3086
+ break;
3087
+ case 'End':
3088
+ if (onIncrementToMax) {
3089
+ e.preventDefault();
3090
+ onIncrementToMax === null || onIncrementToMax === void 0 ? void 0 : onIncrementToMax();
3091
+ }
3092
+ break;
3093
+ }
3094
+ };
3095
+ let isFocused = useRef(false);
3096
+ let onFocus = () => {
3097
+ isFocused.current = true;
3098
+ };
3099
+ let onBlur = () => {
3100
+ isFocused.current = false;
3101
+ };
3102
+
3103
+ // Replace Unicode hyphen-minus (U+002D) with minus sign (U+2212).
3104
+ // This ensures that macOS VoiceOver announces it as "minus" even with other characters between the minus sign
3105
+ // and the number (e.g. currency symbol). Otherwise it announces nothing because it assumes the character is a hyphen.
3106
+ // In addition, replace the empty string with the word "Empty" so that iOS VoiceOver does not read "50%" for an empty field.
3107
+ let ariaTextValue = textValue === '' ? format('Empty') : (textValue || `${value}`).replace('-', '\u2212');
3108
+ useEffect(() => {
3109
+ if (isFocused.current) {
3110
+ clearAnnouncer('assertive');
3111
+ announce(ariaTextValue, 'assertive');
3112
+ }
3113
+ }, [ariaTextValue]);
3114
+ const onIncrementPressStart = useEffectEvent(initialStepDelay => {
3115
+ clearAsync();
3116
+ onIncrement === null || onIncrement === void 0 ? void 0 : onIncrement();
3117
+ // Start spinning after initial delay
3118
+ _async.current = window.setTimeout(() => {
3119
+ if (maxValue === undefined || isNaN(maxValue) || value === undefined || isNaN(value) || value < maxValue) {
3120
+ onIncrementPressStart(60);
3121
+ }
3122
+ }, initialStepDelay);
3123
+ });
3124
+ const onDecrementPressStart = useEffectEvent(initialStepDelay => {
3125
+ clearAsync();
3126
+ onDecrement === null || onDecrement === void 0 ? void 0 : onDecrement();
3127
+ // Start spinning after initial delay
3128
+ _async.current = window.setTimeout(() => {
3129
+ if (minValue === undefined || isNaN(minValue) || value === undefined || isNaN(value) || value > minValue) {
3130
+ onDecrementPressStart(60);
3131
+ }
3132
+ }, initialStepDelay);
3133
+ });
3134
+ let cancelContextMenu = e => {
3135
+ e.preventDefault();
3136
+ };
3137
+ let {
3138
+ addGlobalListener,
3139
+ removeAllGlobalListeners
3140
+ } = useGlobalListeners();
3141
+ return {
3142
+ spinButtonProps: {
3143
+ role: 'spinbutton',
3144
+ 'aria-valuenow': value !== undefined && !isNaN(value) ? value : undefined,
3145
+ 'aria-valuetext': ariaTextValue,
3146
+ 'aria-valuemin': minValue,
3147
+ 'aria-valuemax': maxValue,
3148
+ 'aria-disabled': isDisabled || undefined,
3149
+ 'aria-readonly': isReadOnly || undefined,
3150
+ 'aria-required': isRequired || undefined,
3151
+ onKeyDown,
3152
+ onFocus,
3153
+ onBlur
3154
+ },
3155
+ incrementButtonProps: {
3156
+ onPressStart: () => {
3157
+ onIncrementPressStart(400);
3158
+ addGlobalListener(window, 'contextmenu', cancelContextMenu);
3159
+ },
3160
+ onPressEnd: () => {
3161
+ clearAsync();
3162
+ removeAllGlobalListeners();
3163
+ },
3164
+ onFocus,
3165
+ onBlur
3166
+ },
3167
+ decrementButtonProps: {
3168
+ onPressStart: () => {
3169
+ onDecrementPressStart(400);
3170
+ addGlobalListener(window, 'contextmenu', cancelContextMenu);
3171
+ },
3172
+ onPressEnd: () => {
3173
+ clearAsync();
3174
+ removeAllGlobalListeners();
3175
+ },
3176
+ onFocus,
3177
+ onBlur
3178
+ }
3179
+ };
3180
+ }
3181
+
3182
+ const _excluded$1 = ["id", "decrementAriaLabel", "incrementAriaLabel", "isDisabled", "isReadOnly", "isRequired", "minValue", "maxValue", "autoFocus", "label", "formatOptions", "onBlur", "onFocus", "onFocusChange", "onKeyDown", "onKeyUp", "description", "errorMessage", "isWheelDisabled"];
3183
+ /**
3184
+ * Provides the behavior and accessibility implementation for a number field component.
3185
+ * Number fields allow users to enter a number, and increment or decrement the value using stepper buttons.
3186
+ */
3187
+ function useNumberField(props, state, inputRef) {
3188
+ let {
3189
+ id,
3190
+ decrementAriaLabel,
3191
+ incrementAriaLabel,
3192
+ isDisabled,
3193
+ isReadOnly,
3194
+ isRequired,
3195
+ minValue,
3196
+ maxValue,
3197
+ autoFocus,
3198
+ label,
3199
+ formatOptions,
3200
+ onBlur = () => {},
3201
+ onFocus,
3202
+ onFocusChange,
3203
+ onKeyDown,
3204
+ onKeyUp,
3205
+ description,
3206
+ errorMessage,
3207
+ isWheelDisabled
3208
+ } = props,
3209
+ otherProps = _objectWithoutProperties(props, _excluded$1);
3210
+ let {
3211
+ increment,
3212
+ incrementToMax,
3213
+ decrement,
3214
+ decrementToMin,
3215
+ numberValue,
3216
+ inputValue,
3217
+ commit,
3218
+ commitValidation
3219
+ } = state;
3220
+ const format = useMessageFormatter(intlMessages$1);
3221
+ let inputId = useId(id);
3222
+ let {
3223
+ focusProps
3224
+ } = useFocus({
3225
+ onBlur() {
3226
+ // Set input value to normalized valid value
3227
+ commit();
3228
+ }
3229
+ });
3230
+ let numberFormatter = useNumberFormatter(formatOptions);
3231
+ let intlOptions = useMemo(() => numberFormatter.resolvedOptions(), [numberFormatter]);
3232
+
3233
+ // Replace negative textValue formatted using currencySign: 'accounting'
3234
+ // with a textValue that can be announced using a minus sign.
3235
+ let textValueFormatter = useNumberFormatter(_objectSpread2(_objectSpread2({}, formatOptions), {}, {
3236
+ currencySign: undefined
3237
+ }));
3238
+ let textValue = useMemo(() => isNaN(numberValue) ? '' : textValueFormatter.format(numberValue), [textValueFormatter, numberValue]);
3239
+ let {
3240
+ spinButtonProps,
3241
+ incrementButtonProps: incButtonProps,
3242
+ decrementButtonProps: decButtonProps
3243
+ } = useSpinButton({
3244
+ isDisabled,
3245
+ isReadOnly,
3246
+ isRequired,
3247
+ maxValue,
3248
+ minValue,
3249
+ onIncrement: increment,
3250
+ onIncrementToMax: incrementToMax,
3251
+ onDecrement: decrement,
3252
+ onDecrementToMin: decrementToMin,
3253
+ value: numberValue,
3254
+ textValue
3255
+ });
3256
+ let [focusWithin, setFocusWithin] = useState(false);
3257
+ let {
3258
+ focusWithinProps
3259
+ } = useFocusWithin({
3260
+ isDisabled,
3261
+ onFocusWithinChange: setFocusWithin
3262
+ });
3263
+ let onWheel = useCallback(e => {
3264
+ // if on a trackpad, users can scroll in both X and Y at once, check the magnitude of the change
3265
+ // if it's mostly in the X direction, then just return, the user probably doesn't mean to inc/dec
3266
+ // this isn't perfect, events come in fast with small deltas and a part of the scroll may give a false indication
3267
+ // especially if the user is scrolling near 45deg
3268
+ if (Math.abs(e.deltaY) <= Math.abs(e.deltaX)) {
3269
+ return;
3270
+ }
3271
+ if (e.deltaY > 0) {
3272
+ increment();
3273
+ } else if (e.deltaY < 0) {
3274
+ decrement();
3275
+ }
3276
+ }, [decrement, increment]);
3277
+ // If the input isn't supposed to receive input, disable scrolling.
3278
+ let scrollingDisabled = isWheelDisabled || isDisabled || isReadOnly || !focusWithin;
3279
+ useScrollWheel({
3280
+ onScroll: onWheel,
3281
+ isDisabled: scrollingDisabled
3282
+ }, inputRef);
3283
+
3284
+ // The inputMode attribute influences the software keyboard that is shown on touch devices.
3285
+ // Browsers and operating systems are quite inconsistent about what keys are available, however.
3286
+ // We choose between numeric and decimal based on whether we allow negative and fractional numbers,
3287
+ // and based on testing on various devices to determine what keys are available in each inputMode.
3288
+ let hasDecimals = intlOptions.maximumFractionDigits > 0;
3289
+ let hasNegative = state.minValue === undefined || isNaN(state.minValue) || state.minValue < 0;
3290
+ let inputMode = 'numeric';
3291
+ if (isIPhone()) {
3292
+ // iPhone doesn't have a minus sign in either numeric or decimal.
3293
+ // Note this is only for iPhone, not iPad, which always has both
3294
+ // minus and decimal in numeric.
3295
+ if (hasNegative) {
3296
+ inputMode = 'text';
3297
+ } else if (hasDecimals) {
3298
+ inputMode = 'decimal';
3299
+ }
3300
+ } else if (isAndroid()) {
3301
+ // Android numeric has both a decimal point and minus key.
3302
+ // decimal does not have a minus key.
3303
+ if (hasNegative) {
3304
+ inputMode = 'numeric';
3305
+ } else if (hasDecimals) {
3306
+ inputMode = 'decimal';
3307
+ }
3308
+ }
3309
+ let onChange = value => {
3310
+ if (state.validate(value)) {
3311
+ state.setInputValue(value);
3312
+ }
3313
+ };
3314
+ let domProps = filterDOMProps(props);
3315
+ let onKeyDownEnter = useCallback(e => {
3316
+ if (e.key === 'Enter') {
3317
+ commit();
3318
+ commitValidation();
3319
+ } else {
3320
+ e.continuePropagation();
3321
+ }
3322
+ }, [commit, commitValidation]);
3323
+ let {
3324
+ isInvalid,
3325
+ validationErrors,
3326
+ validationDetails
3327
+ } = state.displayValidation;
3328
+ let {
3329
+ labelProps,
3330
+ inputProps: textFieldProps,
3331
+ descriptionProps,
3332
+ errorMessageProps
3333
+ } = useFormattedTextField(_objectSpread2(_objectSpread2(_objectSpread2({}, otherProps), domProps), {}, {
3334
+ name: undefined,
3335
+ label,
3336
+ autoFocus,
3337
+ isDisabled,
3338
+ isReadOnly,
3339
+ isRequired,
3340
+ validate: undefined,
3341
+ [privateValidationStateProp]: state,
3342
+ value: inputValue,
3343
+ defaultValue: undefined,
3344
+ // defaultValue already used to populate state.inputValue, unneeded here
3345
+ autoComplete: 'off',
3346
+ 'aria-label': props['aria-label'] || undefined,
3347
+ 'aria-labelledby': props['aria-labelledby'] || undefined,
3348
+ id: inputId,
3349
+ type: 'text',
3350
+ // Can't use type="number" because then we can't have things like $ in the field.
3351
+ inputMode,
3352
+ onChange,
3353
+ onBlur,
3354
+ onFocus,
3355
+ onFocusChange,
3356
+ onKeyDown: useMemo(() => chain(onKeyDownEnter, onKeyDown), [onKeyDownEnter, onKeyDown]),
3357
+ onKeyUp,
3358
+ description,
3359
+ errorMessage
3360
+ }), state, inputRef);
3361
+ useFormReset(inputRef, state.numberValue, state.setNumberValue);
3362
+ let inputProps = mergeProps(spinButtonProps, focusProps, textFieldProps, {
3363
+ // override the spinbutton role, we can't focus a spin button with VO
3364
+ role: null,
3365
+ // ignore aria-roledescription on iOS so that required state will announce when it is present
3366
+ 'aria-roledescription': !isIOS() ? format('numberField') : null,
3367
+ 'aria-valuemax': null,
3368
+ 'aria-valuemin': null,
3369
+ 'aria-valuenow': null,
3370
+ 'aria-valuetext': null,
3371
+ autoCorrect: 'off',
3372
+ spellCheck: 'false'
3373
+ });
3374
+ if (props.validationBehavior === 'native') {
3375
+ inputProps['aria-required'] = undefined;
3376
+ }
3377
+ let onButtonPressStart = e => {
3378
+ // If focus is already on the input, keep it there so we don't hide the
3379
+ // software keyboard when tapping the increment/decrement buttons.
3380
+ if (document.activeElement === inputRef.current) {
3381
+ return;
3382
+ }
3383
+
3384
+ // Otherwise, when using a mouse, move focus to the input.
3385
+ // On touch, or with a screen reader, focus the button so that the software
3386
+ // keyboard does not appear and the screen reader cursor is not moved off the button.
3387
+ if (e.pointerType === 'mouse') {
3388
+ var _inputRef$current;
3389
+ (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
3390
+ } else {
3391
+ e.target.focus();
3392
+ }
3393
+ };
3394
+
3395
+ // Determine the label for the increment and decrement buttons. There are 4 cases:
3396
+ //
3397
+ // 1. With a visible label that is a string: aria-label: `Increase ${props.label}`
3398
+ // 2. With a visible label that is JSX: aria-label: 'Increase', aria-labelledby: '${incrementId} ${labelId}'
3399
+ // 3. With an aria-label: aria-label: `Increase ${props['aria-label']}`
3400
+ // 4. With an aria-labelledby: aria-label: 'Increase', aria-labelledby: `${incrementId} ${props['aria-labelledby']}`
3401
+ //
3402
+ // (1) and (2) could possibly be combined and both use aria-labelledby. However, placing the label in
3403
+ // the aria-label string rather than using aria-labelledby gives more flexibility to translators to change
3404
+ // the order or add additional words around the label if needed.
3405
+ let fieldLabel = props['aria-label'] || (typeof props.label === 'string' ? props.label : '');
3406
+ let ariaLabelledby;
3407
+ if (!fieldLabel) {
3408
+ ariaLabelledby = props.label != null ? labelProps.id : props['aria-labelledby'];
3409
+ }
3410
+ let incrementId = useId();
3411
+ let decrementId = useId();
3412
+ let incrementButtonProps = mergeProps(incButtonProps, {
3413
+ 'aria-label': incrementAriaLabel || format('increase', {
3414
+ fieldLabel
3415
+ }).trim(),
3416
+ id: ariaLabelledby && !incrementAriaLabel ? incrementId : null,
3417
+ 'aria-labelledby': ariaLabelledby && !incrementAriaLabel ? `${incrementId} ${ariaLabelledby}` : null,
3418
+ 'aria-controls': inputId,
3419
+ excludeFromTabOrder: true,
3420
+ preventFocusOnPress: true,
3421
+ allowFocusWhenDisabled: true,
3422
+ isDisabled: !state.canIncrement,
3423
+ onPressStart: onButtonPressStart
3424
+ });
3425
+ let decrementButtonProps = mergeProps(decButtonProps, {
3426
+ 'aria-label': decrementAriaLabel || format('decrease', {
3427
+ fieldLabel
3428
+ }).trim(),
3429
+ id: ariaLabelledby && !decrementAriaLabel ? decrementId : null,
3430
+ 'aria-labelledby': ariaLabelledby && !decrementAriaLabel ? `${decrementId} ${ariaLabelledby}` : null,
3431
+ 'aria-controls': inputId,
3432
+ excludeFromTabOrder: true,
3433
+ preventFocusOnPress: true,
3434
+ allowFocusWhenDisabled: true,
3435
+ isDisabled: !state.canDecrement,
3436
+ onPressStart: onButtonPressStart
3437
+ });
3438
+ return {
3439
+ groupProps: _objectSpread2(_objectSpread2({}, focusWithinProps), {}, {
3440
+ role: 'group',
3441
+ 'aria-disabled': isDisabled,
3442
+ 'aria-invalid': isInvalid ? 'true' : undefined
3443
+ }),
3444
+ labelProps,
3445
+ inputProps,
3446
+ incrementButtonProps,
3447
+ decrementButtonProps,
3448
+ errorMessageProps,
3449
+ descriptionProps,
3450
+ isInvalid,
3451
+ validationErrors,
3452
+ validationDetails
3453
+ };
3454
+ }
3455
+
3456
+ /* eslint-disable prefer-const */
3457
+
3458
+ // Order with overrides is important: 'button' should be default
3459
+
3460
+ /**
3461
+ * Provides the behavior and accessibility implementation for a button component. Handles mouse, keyboard, and touch interactions,
3462
+ * focus behavior, and ARIA props for both native button elements and custom element types.
3463
+ * @param props - Props to be applied to the button.
3464
+ * @param ref - A ref to a DOM element for the button.
3465
+ */
3466
+ function useButton(props, ref) {
3467
+ let {
3468
+ elementType = 'button',
3469
+ isDisabled,
3470
+ onPress,
3471
+ onPressStart,
3472
+ onPressEnd,
3473
+ onPressUp,
3474
+ onPressChange,
3475
+ // @ts-ignore - undocumented
3476
+ preventFocusOnPress,
3477
+ // @ts-ignore - undocumented
3478
+ allowFocusWhenDisabled,
3479
+ // @ts-ignore
3480
+ onClick: deprecatedOnClick,
3481
+ href,
3482
+ target,
3483
+ rel,
3484
+ type = 'button'
3485
+ } = props;
3486
+ let additionalProps;
3487
+ if (elementType === 'button') {
3488
+ additionalProps = {
3489
+ type,
3490
+ disabled: isDisabled
3491
+ };
3492
+ } else {
3493
+ additionalProps = {
3494
+ role: 'button',
3495
+ tabIndex: isDisabled ? undefined : 0,
3496
+ href: elementType === 'a' && isDisabled ? undefined : href,
3497
+ target: elementType === 'a' ? target : undefined,
3498
+ type: elementType === 'input' ? type : undefined,
3499
+ disabled: elementType === 'input' ? isDisabled : undefined,
3500
+ 'aria-disabled': !isDisabled || elementType === 'input' ? undefined : isDisabled,
3501
+ rel: elementType === 'a' ? rel : undefined
3502
+ };
3503
+ }
3504
+ let {
3505
+ pressProps,
3506
+ isPressed
3507
+ } = usePress({
3508
+ onPressStart,
3509
+ onPressEnd,
3510
+ onPressChange,
3511
+ onPress,
3512
+ onPressUp,
3513
+ isDisabled,
3514
+ preventFocusOnPress,
3515
+ ref
3516
+ });
3517
+ let {
3518
+ focusableProps
3519
+ } = useFocusable(props, ref);
3520
+ if (allowFocusWhenDisabled) {
3521
+ focusableProps.tabIndex = isDisabled ? -1 : focusableProps.tabIndex;
3522
+ }
3523
+ let buttonProps = mergeProps(focusableProps, pressProps, filterDOMProps(props, {
3524
+ labelable: true
3525
+ }));
3526
+ return {
3527
+ isPressed,
3528
+ // Used to indicate press state for visual
3529
+ buttonProps: mergeProps(additionalProps, buttonProps, {
3530
+ 'aria-haspopup': props['aria-haspopup'],
3531
+ 'aria-expanded': props['aria-expanded'],
3532
+ 'aria-controls': props['aria-controls'],
3533
+ 'aria-pressed': props['aria-pressed'],
3534
+ onClick: e => {
3535
+ if (deprecatedOnClick) {
3536
+ deprecatedOnClick(e);
3537
+ console.warn('onClick is deprecated, please use onPress');
3538
+ }
3539
+ }
3540
+ })
3541
+ };
3542
+ }
3543
+
3544
+ /**
3545
+ * Component style.
3546
+ */
3547
+ const StyledNumberField = styled.div`
3548
+ height: fit-content;
3549
+ position: relative;
3550
+ width: fit-content;
3551
+ margin: 0;
3552
+ min-width: 0;
3553
+ padding: 0;
3554
+ ${baseStyling}
3555
+
3556
+ border: 0;
3557
+ display: inline-flex;
3558
+ flex-direction: column;
3559
+ vertical-align: top;
3560
+
3561
+ ${_ref => {
3562
+ let {
3563
+ $hasLeftIcon,
3564
+ $hasContent,
3565
+ $isFocused,
3566
+ $isDisabled,
3567
+ $isInvalid,
3568
+ $isColored,
3569
+ $theme,
3570
+ $variant
3571
+ } = _ref;
3572
+ return css`
3573
+ ${$isDisabled ? css`
3574
+ pointer-events: none;
3575
+ ` : ''}
3576
+
3577
+ .redsift-number-field__label {
3578
+ font-family: var(--redsift-typography-input-text-font-family);
3579
+ font-size: var(--redsift-typography-input-text-font-size);
3580
+ font-weight: var(--redsift-typography-input-text-font-weight);
3581
+ line-height: var(--redsift-typography-input-text-line-height);
3582
+ left: ${$hasLeftIcon && !$hasContent ? '32px' : '0'};
3583
+ overflow: hidden;
3584
+ pointer-events: none;
3585
+ position: absolute;
3586
+ text-overflow: ellipsis;
3587
+ top: ${$hasContent ? '-8px' : '-5px'};
3588
+ transform-origin: top left;
3589
+ transition: color 200ms cubic-bezier(0, 0, 0.2, 1) 0ms, transform 200ms cubic-bezier(0, 0, 0.2, 1) 0ms,
3590
+ max-width 200ms cubic-bezier(0, 0, 0.2, 1) 0ms;
3591
+ white-space: nowrap;
3592
+ z-index: 1;
3593
+
3594
+ ${!$hasContent ? css`
3595
+ max-width: calc(100% - 24px - 42px - ${$variant === NumberFieldVariant.underline ? '0px' : '14px'});
3596
+ transform: translate(${$variant === NumberFieldVariant.underline ? '0px' : '14px'}, 16px) scale(1);
3597
+ ` : css`
3598
+ max-width: calc(133% - 32px - 42px - ${$variant === NumberFieldVariant.underline ? '0px' : '14px'});
3599
+ transform: translate(${$variant === NumberFieldVariant.underline ? '0px' : '14px'}, 1px) scale(0.733);
3600
+ `}
3601
+
3602
+ ${$isDisabled ? css`
3603
+ color: var(--redsift-color-neutral-light-grey);
3604
+ ` : $isInvalid ? css`
3605
+ color: var(--redsift-color-notifications-error-primary);
3606
+ ` : $isFocused ? css`
3607
+ color: ${$isColored ? 'var(--redsift-color-primary-n)' : 'var(--redsift-color-notifications-question-primary)'};
3608
+ ` : css`
3609
+ color: var(--redsift-color-neutral-${$theme === Theme.light ? 'x-dark-grey' : 'light-grey'});
3610
+ `}
3611
+ }
3612
+
3613
+ .redsift-number-field__input-wrapper {
3614
+ align-items: flex-start;
3615
+ box-sizing: border-box;
3616
+ cursor: text;
3617
+ display: inline-flex;
3618
+ min-height: 42px;
3619
+ position: relative;
3620
+ width: 100%;
3621
+ }
3622
+
3623
+ .redsift-number-field-input-wrapper__input {
3624
+ background: none;
3625
+ border: 0;
3626
+ box-sizing: content-box;
3627
+ display: flex;
3628
+ flex: 1 1 auto;
3629
+ font-family: var(--redsift-typography-input-text-font-family);
3630
+ font-size: var(--redsift-typography-input-text-font-size);
3631
+ font-weight: var(--redsift-typography-input-text-font-weight);
3632
+ line-height: var(--redsift-typography-input-text-line-height);
3633
+ min-width: 0;
3634
+ min-width: 100px;
3635
+ padding: 2px 0;
3636
+ width: auto;
3637
+ padding-bottom: 6px;
3638
+ ${$variant !== NumberFieldVariant.underline && !$hasLeftIcon ? css`
3639
+ padding-left: 16px;
3640
+ ` : ''}
3641
+ padding-top: 10px;
3642
+
3643
+ ${$isDisabled ? css`
3644
+ color: var(--redsift-color-neutral-light-grey);
3645
+ ` : css`
3646
+ color: var(--redsift-color-neutral-${$theme === Theme.dark ? 'white' : 'x-dark-grey'});
3647
+ `}
3648
+ }
3649
+
3650
+ .redsift-number-field-input-wrapper__input::placeholder {
3651
+ color: var(--redsift-color-neutral-mid-grey);
3652
+ }
3653
+
3654
+ .redsift-number-field-input-wrapper__input:focus {
3655
+ outline: 0;
3656
+ }
3657
+
3658
+ .redsift-number-field-input-wrapper__fieldset {
3659
+ border-style: solid;
3660
+ bottom: 0;
3661
+ left: 1px;
3662
+ margin: 0;
3663
+ min-width: 0%;
3664
+ overflow: hidden;
3665
+ padding: 0 8px;
3666
+ pointer-events: none;
3667
+ position: absolute;
3668
+ right: 0;
3669
+ text-align: left;
3670
+ top: -5px;
3671
+
3672
+ ${$variant === NumberFieldVariant.underline ? css`
3673
+ border-bottom-width: 2px;
3674
+ ` : css`
3675
+ border-radius: 4px;
3676
+ border-width: 2px;
3677
+ `}
3678
+
3679
+ ${$isDisabled ? css`
3680
+ border-color: var(--redsift-color-neutral-light-grey);
3681
+ ` : $isInvalid ? css`
3682
+ border-color: var(--redsift-color-notifications-error-primary);
3683
+ ` : $isFocused ? css`
3684
+ border-color: ${$isColored ? 'var(--redsift-color-primary-n)' : 'var(--redsift-color-notifications-question-primary)'};
3685
+ ` : css`
3686
+ border-color: var(--redsift-color-neutral-mid-grey);
3687
+ `}
3688
+ }
3689
+
3690
+ .redsift-number-field-input-wrapper-fieldset__legend {
3691
+ display: block;
3692
+ float: unset;
3693
+ font-size: 11px;
3694
+ height: 11px;
3695
+ overflow: hidden;
3696
+ padding: 0;
3697
+ visibility: hidden;
3698
+ white-space: nowrap;
3699
+ width: auto;
3700
+
3701
+ ${!$hasContent ? css`
3702
+ max-width: 0.01px;
3703
+ transition: max-width 50ms cubic-bezier(0, 0, 0.2, 1) 0ms;
3704
+ ` : css`
3705
+ max-width: calc(100% - 42px);
3706
+ transition: max-width 100ms cubic-bezier(0, 0, 0.2, 1) 50ms;
3707
+ `}
3708
+ }
3709
+
3710
+ .redsift-number-field-input-wrapper-fieldset__legend > span {
3711
+ display: inline-block;
3712
+ opacity: 0;
3713
+ padding-left: 5px;
3714
+ padding-right: 5px;
3715
+ visibility: visible;
3716
+ }
3717
+
3718
+ .redsift-icon-button {
3719
+ padding: 2px;
3720
+ }
3721
+
3722
+ .redsift-number-field-input-wrapper__toolbar {
3723
+ > button {
3724
+ height: 21px;
3725
+ width: 42px;
3726
+ ${$isDisabled ? css`
3727
+ border-color: var(--redsift-color-neutral-light-grey);
3728
+ ` : $isInvalid ? css`
3729
+ border-color: var(--redsift-color-notifications-error-primary);
3730
+ ` : $isFocused ? css`
3731
+ border-color: ${$isColored ? 'var(--redsift-color-primary-n)' : 'var(--redsift-color-notifications-question-primary)'};
3732
+ ` : css`
3733
+ border-color: var(--redsift-color-neutral-mid-grey);
3734
+ `}
3735
+ }
3736
+
3737
+ .redsift-number-field-input-wrapper-toolbar__increment-button {
3738
+ border-top-width: 0;
3739
+ border-right-width: 0;
3740
+ border-bottom-width: 1px;
3741
+ border-left-width: 2px;
3742
+ border-top-left-radius: 0;
3743
+ border-top-right-radius: 4px;
3744
+ border-bottom-right-radius: 0;
3745
+ border-bottom-left-radius: 0;
3746
+ }
3747
+
3748
+ .redsift-number-field-input-wrapper-toolbar__decrement-button {
3749
+ border-top-width: 1px;
3750
+ border-right-width: 0;
3751
+ border-bottom-width: 0;
3752
+ border-left-width: 2px;
3753
+ border-top-left-radius: 0;
3754
+ border-top-right-radius: 0;
3755
+ border-bottom-right-radius: 4px;
3756
+ border-bottom-left-radius: 0;
3757
+ }
3758
+ }
3759
+
3760
+ ${$variant !== NumberFieldVariant.underline ? css`
3761
+ .redsift-icon.left {
3762
+ padding-left: 12px;
3763
+ padding-right: 8px;
3764
+ line-height: 28px;
3765
+ top: 10px;
3766
+ }
3767
+ ` : css`
3768
+ .redsift-icon.left {
3769
+ padding-right: 8px;
3770
+ top: 10px;
3771
+ }
3772
+ `}
3773
+ `;
3774
+ }}
3775
+ `;
3776
+
3777
+ const _excluded = ["autoFocus", "className", "decrementAriaLabel", "defaultValue", "formatOptions", "id", "incrementAriaLabel", "inputProps", "inputRef", "isColored", "isDisabled", "isInvalid", "isReadOnly", "isRequired", "isWheelDisabled", "label", "leftIcon", "maxValue", "minValue", "onBlur", "onChange", "onFocus", "onFocusChange", "onKeyDown", "onKeyUp", "placeholder", "step", "theme", "value", "variant"];
3778
+ const COMPONENT_NAME = 'NumberField';
3779
+ const CLASSNAME = 'redsift-number-field';
73
3780
 
74
3781
  /**
75
3782
  * The NumberField component.
76
3783
  * Can be used as controlled or uncontrolled.
77
3784
  */
78
- declare const NumberField: Comp<NumberFieldProps, HTMLDivElement>;
3785
+ const NumberField = /*#__PURE__*/forwardRef((props, ref) => {
3786
+ const {
3787
+ autoFocus,
3788
+ className,
3789
+ decrementAriaLabel,
3790
+ defaultValue,
3791
+ formatOptions,
3792
+ id,
3793
+ incrementAriaLabel,
3794
+ inputProps: propsInputProps,
3795
+ inputRef: propsInputRef,
3796
+ isColored = true,
3797
+ isDisabled,
3798
+ isInvalid,
3799
+ isReadOnly,
3800
+ isRequired,
3801
+ isWheelDisabled,
3802
+ label,
3803
+ leftIcon,
3804
+ maxValue,
3805
+ minValue,
3806
+ onBlur: onBlurProps,
3807
+ onChange: propsOnChange,
3808
+ onFocus: onFocusProps,
3809
+ onFocusChange,
3810
+ onKeyDown,
3811
+ onKeyUp,
3812
+ placeholder,
3813
+ step,
3814
+ theme: propsTheme,
3815
+ value,
3816
+ variant = NumberFieldVariant.default
3817
+ } = props,
3818
+ forwardedProps = _objectWithoutProperties(props, _excluded);
3819
+ const numberFieldProps = {
3820
+ id,
3821
+ isDisabled,
3822
+ isReadOnly,
3823
+ isRequired,
3824
+ minValue,
3825
+ maxValue,
3826
+ step,
3827
+ autoFocus,
3828
+ label,
3829
+ formatOptions,
3830
+ onBlur: onBlurProps,
3831
+ onFocus: onFocusProps,
3832
+ onFocusChange,
3833
+ onKeyDown,
3834
+ onKeyUp,
3835
+ value,
3836
+ defaultValue,
3837
+ onChange: propsOnChange
3838
+ };
3839
+ const theme = useTheme(propsTheme);
3840
+ const {
3841
+ locale
3842
+ } = useLocale();
3843
+ const state = useNumberFieldState(_objectSpread2({
3844
+ locale
3845
+ }, numberFieldProps));
3846
+ const _inputRef = React__default.useRef(null);
3847
+ const inputRef = propsInputRef !== null && propsInputRef !== void 0 ? propsInputRef : _inputRef;
3848
+ const {
3849
+ labelProps,
3850
+ groupProps,
3851
+ inputProps,
3852
+ incrementButtonProps,
3853
+ decrementButtonProps
3854
+ } = useNumberField(_objectSpread2({
3855
+ decrementAriaLabel,
3856
+ incrementAriaLabel,
3857
+ isWheelDisabled
3858
+ }, numberFieldProps), state, inputRef);
3859
+ const incrementButtonRef = useRef(null);
3860
+ const {
3861
+ buttonProps: incrementButtonForwardedProps
3862
+ } = useButton(incrementButtonProps, incrementButtonRef);
3863
+ const decrementButtonRef = useRef(null);
3864
+ const {
3865
+ buttonProps: decrementButtonForwardedProps
3866
+ } = useButton(decrementButtonProps, decrementButtonRef);
3867
+ const {
3868
+ isFocusVisible,
3869
+ isFocused,
3870
+ focusProps: {
3871
+ onFocus,
3872
+ onBlur
3873
+ }
3874
+ } = useFocusRing({
3875
+ autoFocus
3876
+ });
3877
+ const [isFocusWithin, setFocusWithin] = useState(Boolean(autoFocus));
3878
+ const {
3879
+ focusWithinProps
3880
+ } = useFocusWithin({
3881
+ onFocusWithinChange: isFocusWithin => setFocusWithin(isFocusWithin)
3882
+ });
3883
+ warnIfNoAccessibleLabelFound(props, [label], 'NumberField');
3884
+ return /*#__PURE__*/React__default.createElement(StyledNumberField, _extends({}, forwardedProps, focusWithinProps, {
3885
+ $hasContent: isFocusWithin || Boolean(inputProps.value !== undefined && inputProps.value !== '') || Boolean(placeholder),
3886
+ $hasLeftIcon: Boolean(leftIcon),
3887
+ $isColored: isColored,
3888
+ $isDisabled: isDisabled,
3889
+ $isFocusVisible: isFocusVisible,
3890
+ $isInvalid: isInvalid || isRequired && !(inputProps.value !== undefined),
3891
+ $isRequired: isRequired,
3892
+ $isFocused: isFocused,
3893
+ $theme: theme,
3894
+ $variant: variant,
3895
+ className: classNames(NumberField.className, className),
3896
+ ref: ref
3897
+ }), label ? /*#__PURE__*/React__default.createElement("label", _extends({}, labelProps, {
3898
+ className: `${NumberField.className}__label`
3899
+ }), /*#__PURE__*/React__default.createElement("span", null, label)) : null, /*#__PURE__*/React__default.createElement("div", {
3900
+ className: `${NumberField.className}__input-wrapper`
3901
+ }, leftIcon ? /*#__PURE__*/React__default.createElement(Icon, _extends({
3902
+ color: isDisabled ? 'question' : 'black'
3903
+ }, leftIcon, {
3904
+ "aria-hidden": "true",
3905
+ className: "left"
3906
+ })) : null, /*#__PURE__*/React__default.createElement(Flexbox, _extends({}, groupProps, {
3907
+ flexDirection: "row",
3908
+ gap: "0",
3909
+ width: "100%"
3910
+ }), /*#__PURE__*/React__default.createElement("input", _extends({}, propsInputProps, inputProps, {
3911
+ onChange: event => {
3912
+ if (propsOnChange) {
3913
+ propsOnChange(Number(event.target.value));
3914
+ } else {
3915
+ var _inputProps$onChange;
3916
+ (_inputProps$onChange = inputProps.onChange) === null || _inputProps$onChange === void 0 ? void 0 : _inputProps$onChange.call(inputProps, event);
3917
+ }
3918
+ },
3919
+ onBlur: event => {
3920
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
3921
+ onBlurProps === null || onBlurProps === void 0 ? void 0 : onBlurProps(event);
3922
+ },
3923
+ onFocus: event => {
3924
+ onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
3925
+ onFocusProps === null || onFocusProps === void 0 ? void 0 : onFocusProps(event);
3926
+ },
3927
+ placeholder: placeholder ? `${placeholder}` : undefined,
3928
+ className: `${NumberField.className}-input-wrapper__input`,
3929
+ ref: inputRef,
3930
+ width: "100%"
3931
+ })), /*#__PURE__*/React__default.createElement(Flexbox, {
3932
+ className: `${NumberField.className}-input-wrapper__toolbar`,
3933
+ flexDirection: "column",
3934
+ gap: "0"
3935
+ }, /*#__PURE__*/React__default.createElement(StyledIconButton, _extends({
3936
+ $color: "grey",
3937
+ $isActive: false,
3938
+ $isDisabled: isDisabled,
3939
+ $isGradient: false,
3940
+ $isHovered: false,
3941
+ $isLoading: false,
3942
+ $variant: variant === NumberFieldVariant.underline ? 'unstyled' : 'secondary',
3943
+ $theme: theme
3944
+ }, incrementButtonForwardedProps, {
3945
+ className: `${NumberField.className}-input-wrapper-toolbar__increment-button`
3946
+ }), /*#__PURE__*/React__default.createElement(Icon, {
3947
+ icon: mdiMenuUp,
3948
+ color: isDisabled ? undefined : 'grey'
3949
+ })), /*#__PURE__*/React__default.createElement(StyledIconButton, _extends({
3950
+ $color: "grey",
3951
+ $isActive: false,
3952
+ $isDisabled: isDisabled,
3953
+ $isGradient: false,
3954
+ $isHovered: false,
3955
+ $isLoading: false,
3956
+ $variant: variant === NumberFieldVariant.underline ? 'unstyled' : 'secondary',
3957
+ $theme: theme
3958
+ }, decrementButtonForwardedProps, {
3959
+ className: `${NumberField.className}-input-wrapper-toolbar__decrement-button`
3960
+ }), /*#__PURE__*/React__default.createElement(Icon, {
3961
+ icon: mdiMenuDown,
3962
+ color: isDisabled ? undefined : 'grey'
3963
+ })))), /*#__PURE__*/React__default.createElement("fieldset", {
3964
+ "aria-hidden": "true",
3965
+ className: `${NumberField.className}-input-wrapper__fieldset`
3966
+ }, /*#__PURE__*/React__default.createElement("legend", {
3967
+ className: `${NumberField.className}-input-wrapper-fieldset__legend`
3968
+ }, label ? /*#__PURE__*/React__default.createElement("span", null, label) : null))));
3969
+ });
3970
+ NumberField.className = CLASSNAME;
3971
+ NumberField.displayName = COMPONENT_NAME;
79
3972
 
80
- export { NumberFieldVariant as N, StyledNumberFieldProps as S, NumberFieldProps as a, NumberField as b };
3973
+ export { NumberFieldVariant as N, NumberField as a };
3974
+ //# sourceMappingURL=NumberField.js.map