@ringcentral/spring-base 1.7.0

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 (146) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +61 -0
  3. package/chunks/twMerge.js +409 -0
  4. package/config.js +78 -0
  5. package/contexts.js +71 -0
  6. package/hooks.js +2101 -0
  7. package/index.d.ts +1 -0
  8. package/index.js +16 -0
  9. package/package.json +30 -0
  10. package/src/config.d.ts +40 -0
  11. package/src/contexts/ResponsiveContext/ResponsiveContext.d.ts +7 -0
  12. package/src/contexts/ResponsiveContext/breakpointList.d.ts +3 -0
  13. package/src/contexts/ResponsiveContext/getMatchDetail.d.ts +2 -0
  14. package/src/contexts/ResponsiveContext/index.d.ts +4 -0
  15. package/src/contexts/ResponsiveContext/types.d.ts +24 -0
  16. package/src/contexts/WindowContext.d.ts +9 -0
  17. package/src/contexts/index.d.ts +2 -0
  18. package/src/hooks/index.d.ts +43 -0
  19. package/src/hooks/useA11yKeyEvent/index.d.ts +1 -0
  20. package/src/hooks/useA11yKeyEvent/useA11yKeyEvent.d.ts +23 -0
  21. package/src/hooks/useActive/index.d.ts +1 -0
  22. package/src/hooks/useActive/useActive.d.ts +23 -0
  23. package/src/hooks/useAnnouncer/index.d.ts +1 -0
  24. package/src/hooks/useAnnouncer/useAnnouncer.d.ts +12 -0
  25. package/src/hooks/useAriaHideOutside/index.d.ts +1 -0
  26. package/src/hooks/useAriaHideOutside/useAriaHideOutside.d.ts +12 -0
  27. package/src/hooks/useAudio/index.d.ts +1 -0
  28. package/src/hooks/useAudio/useAudio.d.ts +21 -0
  29. package/src/hooks/useBodyScrollLock/index.d.ts +1 -0
  30. package/src/hooks/useBodyScrollLock/useBodyScrollLock.d.ts +25 -0
  31. package/src/hooks/useChange/index.d.ts +1 -0
  32. package/src/hooks/useChange/useChange.d.ts +12 -0
  33. package/src/hooks/useClickAway/index.d.ts +1 -0
  34. package/src/hooks/useClickAway/useClickAway.d.ts +22 -0
  35. package/src/hooks/useControlled/index.d.ts +1 -0
  36. package/src/hooks/useControlled/useControlled.d.ts +1 -0
  37. package/src/hooks/useDebounce/index.d.ts +1 -0
  38. package/src/hooks/useDebounce/useDebounce.d.ts +8 -0
  39. package/src/hooks/useEventCallback/index.d.ts +1 -0
  40. package/src/hooks/useEventCallback/useEventCallback.d.ts +1 -0
  41. package/src/hooks/useEventListener/index.d.ts +1 -0
  42. package/src/hooks/useEventListener/useEventListener.d.ts +32 -0
  43. package/src/hooks/useEver/index.d.ts +1 -0
  44. package/src/hooks/useEver/useEver.d.ts +13 -0
  45. package/src/hooks/useFocusVisible/index.d.ts +1 -0
  46. package/src/hooks/useFocusVisible/useFocusVisible.d.ts +22 -0
  47. package/src/hooks/useFontLoaded/index.d.ts +1 -0
  48. package/src/hooks/useFontLoaded/useFontLoaded.d.ts +13 -0
  49. package/src/hooks/useForceUpdate/index.d.ts +1 -0
  50. package/src/hooks/useForceUpdate/useForceUpdate.d.ts +5 -0
  51. package/src/hooks/useForkRef/index.d.ts +1 -0
  52. package/src/hooks/useForkRef/useForkRef.d.ts +19 -0
  53. package/src/hooks/useGlobalListener/createGlobalListener.d.ts +55 -0
  54. package/src/hooks/useGlobalListener/index.d.ts +2 -0
  55. package/src/hooks/useGlobalListener/useGlobalListener.d.ts +14 -0
  56. package/src/hooks/useHiddenTabindex/index.d.ts +1 -0
  57. package/src/hooks/useHiddenTabindex/useHiddenTabindex.d.ts +9 -0
  58. package/src/hooks/useHover/index.d.ts +2 -0
  59. package/src/hooks/useHover/useHover.d.ts +17 -0
  60. package/src/hooks/useHover/useHoverDirty.d.ts +8 -0
  61. package/src/hooks/useId/index.d.ts +1 -0
  62. package/src/hooks/useId/useId.d.ts +15 -0
  63. package/src/hooks/useImgLoaded/index.d.ts +1 -0
  64. package/src/hooks/useImgLoaded/useImgLoaded.d.ts +24 -0
  65. package/src/hooks/useInterval/index.d.ts +1 -0
  66. package/src/hooks/useInterval/useInterval.d.ts +43 -0
  67. package/src/hooks/useIsFocusVisible/index.d.ts +2 -0
  68. package/src/hooks/useIsFocusVisible/useIsFocusVisible.d.ts +9 -0
  69. package/src/hooks/useKeyDownOnce/index.d.ts +1 -0
  70. package/src/hooks/useKeyDownOnce/useKeyDownOnce.d.ts +15 -0
  71. package/src/hooks/useKeyboardMoveFocus/index.d.ts +3 -0
  72. package/src/hooks/useKeyboardMoveFocus/moveIndexInTwoDimension.d.ts +18 -0
  73. package/src/hooks/useKeyboardMoveFocus/useKeyboardMoveFocus.d.ts +49 -0
  74. package/src/hooks/useKeyboardMoveFocus/useOnlyOneFocusable.d.ts +17 -0
  75. package/src/hooks/useLongPress/index.d.ts +1 -0
  76. package/src/hooks/useLongPress/useLongPress.d.ts +39 -0
  77. package/src/hooks/useMountState/index.d.ts +1 -0
  78. package/src/hooks/useMountState/useMountState.d.ts +16 -0
  79. package/src/hooks/useOnLayoutReRender/index.d.ts +1 -0
  80. package/src/hooks/useOnLayoutReRender/useOnLayoutReRender.d.ts +5 -0
  81. package/src/hooks/useOnReRender/index.d.ts +1 -0
  82. package/src/hooks/useOnReRender/useOnReRender.d.ts +5 -0
  83. package/src/hooks/useOverflow/index.d.ts +1 -0
  84. package/src/hooks/useOverflow/useOverflow.d.ts +11 -0
  85. package/src/hooks/usePrevious/index.d.ts +1 -0
  86. package/src/hooks/usePrevious/usePrevious.d.ts +7 -0
  87. package/src/hooks/useRefState/index.d.ts +1 -0
  88. package/src/hooks/useRefState/useRefState.d.ts +21 -0
  89. package/src/hooks/useResizeObserver/index.d.ts +1 -0
  90. package/src/hooks/useResizeObserver/useResizeObserver.d.ts +24 -0
  91. package/src/hooks/useResponsiveMatch/index.d.ts +1 -0
  92. package/src/hooks/useResponsiveMatch/useResponsiveMatch.d.ts +7 -0
  93. package/src/hooks/useResultRef/index.d.ts +1 -0
  94. package/src/hooks/useResultRef/useResultRef.d.ts +10 -0
  95. package/src/hooks/useRetry/index.d.ts +1 -0
  96. package/src/hooks/useRetry/useRetry.d.ts +35 -0
  97. package/src/hooks/useSleep/index.d.ts +1 -0
  98. package/src/hooks/useSleep/useSleep.d.ts +22 -0
  99. package/src/hooks/useTabOut/index.d.ts +1 -0
  100. package/src/hooks/useTabOut/useTabOut.d.ts +10 -0
  101. package/src/hooks/useTestRunnerDetection.d.ts +7 -0
  102. package/src/hooks/useThrottle/index.d.ts +1 -0
  103. package/src/hooks/useThrottle/useThrottle.d.ts +8 -0
  104. package/src/hooks/useTimeout/index.d.ts +1 -0
  105. package/src/hooks/useTimeout/useTimeout.d.ts +2 -0
  106. package/src/hooks/useTouchMouseEvent/index.d.ts +1 -0
  107. package/src/hooks/useTouchMouseEvent/useTouchMouseEvent.d.ts +56 -0
  108. package/src/index.d.ts +5 -0
  109. package/src/typings/BaseColor.d.ts +14 -0
  110. package/src/typings/BaseSize.d.ts +15 -0
  111. package/src/typings/ComponentTypes.d.ts +50 -0
  112. package/src/typings/ExtractValue.d.ts +2 -0
  113. package/src/typings/OverridableTypes.d.ts +45 -0
  114. package/src/typings/UnionOmit.d.ts +3 -0
  115. package/src/typings/UnitMap.d.ts +28 -0
  116. package/src/typings/index.d.ts +7 -0
  117. package/src/utils/a11yKeyboardCode.d.ts +8 -0
  118. package/src/utils/ariaHideOutside.d.ts +9 -0
  119. package/src/utils/capitalize.d.ts +1 -0
  120. package/src/utils/checkDefaultPrevented.d.ts +3 -0
  121. package/src/utils/checkElementName.d.ts +2 -0
  122. package/src/utils/checkKeyboardEvent.d.ts +2 -0
  123. package/src/utils/classes/globalStateClasses.d.ts +14 -0
  124. package/src/utils/classes/index.d.ts +2 -0
  125. package/src/utils/classes/useClasses.d.ts +41 -0
  126. package/src/utils/combineProps.d.ts +90 -0
  127. package/src/utils/devlog.d.ts +7 -0
  128. package/src/utils/getRefElement.d.ts +6 -0
  129. package/src/utils/getTitle.d.ts +1 -0
  130. package/src/utils/index.d.ts +25 -0
  131. package/src/utils/isRef.d.ts +2 -0
  132. package/src/utils/isSuiElement.d.ts +1 -0
  133. package/src/utils/isUrl.d.ts +1 -0
  134. package/src/utils/isWebKit154.d.ts +9 -0
  135. package/src/utils/omit.d.ts +2 -0
  136. package/src/utils/outerSize.d.ts +8 -0
  137. package/src/utils/ownerDocument.d.ts +1 -0
  138. package/src/utils/ownerWindow.d.ts +1 -0
  139. package/src/utils/pick.d.ts +2 -0
  140. package/src/utils/preloadImg.d.ts +2 -0
  141. package/src/utils/removeClassName.d.ts +35 -0
  142. package/src/utils/runKeyHandler.d.ts +12 -0
  143. package/src/utils/selectionHandler.d.ts +23 -0
  144. package/src/utils/twMerge.d.ts +4 -0
  145. package/typings.js +1 -0
  146. package/utils.js +333 -0
package/utils.js ADDED
@@ -0,0 +1,333 @@
1
+ import { g as getRefElement } from './chunks/twMerge.js';
2
+ export { a as ariaHideOutside, b as combineClasses, c as combineProps, i as isRef, l as logInDev, o as ownerWindow, t as twMerge } from './chunks/twMerge.js';
3
+ import React__default, { isValidElement, useCallback } from 'react';
4
+ import lodashOmit from 'lodash/omit';
5
+ export { unstable_ownerDocument as ownerDocument } from '@mui/utils';
6
+ import lodashPick from 'lodash/pick';
7
+ import 'lodash/isPlainObject';
8
+ import './config.js';
9
+ import 'tailwind-merge';
10
+
11
+ const a11yKeyboard = {
12
+ ArrowLeft: 'ArrowLeft',
13
+ ArrowRight: 'ArrowRight',
14
+ Space: ' ',
15
+ Escape: 'Escape',
16
+ Enter: 'Enter',
17
+ Tab: 'Tab',
18
+ };
19
+
20
+ // It should to be noted that this function isn't equivalent to `text-transform: capitalize`.
21
+ //
22
+ // A strict capitalization should uppercase the first letter of each word in the sentence.
23
+ // We only handle the first word.
24
+ function capitalize(string) {
25
+ if (typeof string !== 'string') {
26
+ throw new Error('SPRING: `capitalize(string)` expects a string argument.');
27
+ }
28
+ return string.charAt(0).toUpperCase() + string.slice(1);
29
+ }
30
+
31
+ /** check is that event preventDefault */
32
+ const checkDefaultPrevented = (fc) => {
33
+ return (e, ...args) => {
34
+ if (e.defaultPrevented)
35
+ return;
36
+ fc(e, ...args);
37
+ };
38
+ };
39
+
40
+ function checkElementName(element, names) {
41
+ return (isValidElement(element) &&
42
+ names.indexOf(element.type?.displayName) !== -1);
43
+ }
44
+
45
+ const isDeleteKeyboardEvent = (keyboardEvent) => {
46
+ return keyboardEvent.key === 'Backspace' || keyboardEvent.key === 'Delete';
47
+ };
48
+
49
+ const globalStateClasses = {
50
+ active: 'sui-active',
51
+ checked: 'sui-checked',
52
+ completed: 'sui-completed',
53
+ disabled: 'sui-disabled',
54
+ expanded: 'sui-expanded',
55
+ focused: 'sui-focused',
56
+ focusVisible: 'sui-focus-visible',
57
+ focusVisibleWithin: 'sui-focus-visible-within',
58
+ required: 'sui-required',
59
+ selected: 'sui-selected',
60
+ dragged: 'sui-dragged',
61
+ };
62
+
63
+ /**
64
+ * simple camel case for better performance, because this is a very open execution function, below is the benchmark of lodash camelCase vs simpleCamelCase and regex camelCase.
65
+ *
66
+ * https://www.measurethat.net/Benchmarks/Show/31672/0/regex-vs-javascript-camelcase-long
67
+ *
68
+ * https://www.measurethat.net/Benchmarks/Show/12906/0/lodash-camelcase-vs-javascript-camelcase-long
69
+ */
70
+ const simpleCamelCase = (str) => str
71
+ .split('-')
72
+ .map((item, index) => index ? item.charAt(0).toUpperCase() + item.slice(1).toLowerCase() : item)
73
+ .join('');
74
+ const DEFAULT_PREFIX = 'sui-';
75
+ /**
76
+ * Custom hook for generating CSS classes based on input parameters.
77
+ *
78
+ * pick class from object with prefix of object like `sui-${prefix}-${key}`
79
+ *
80
+ * `className` will be apply to the `cls('root')` class.
81
+ *
82
+ * camelCase will be used for the key in the inputClasses object.
83
+ *
84
+ * and apply to kebabCase in the class name.
85
+ *
86
+ * ```tsx
87
+ * type BaseButtonClasses =
88
+ * | 'root'
89
+ * | 'content'
90
+ * | 'start-slot';
91
+ *
92
+ * const cls = useClasses<BaseButtonClasses>('button', {
93
+ * root: 'custom-button-root',
94
+ * content: 'custom-button-content',
95
+ * startSlot: 'custom-button-start-slot',
96
+ * }, 'custom-root-class');
97
+ *
98
+ * <button className={cls('root')}>Button</button> // 'sui-button-root custom-button-root custom-root-class'
99
+ * <button className={cls('content')}>Button</button> // 'sui-button-content custom-button-content'
100
+ *
101
+ * <button className={cls('start-slot')}>Button</button> // 'sui-button-start-slot custom-button-start-slot'
102
+ * ```
103
+ */
104
+ const useClasses = (prefix, inputClasses, className) => {
105
+ return useCallback((...classValues) => {
106
+ const classList = [];
107
+ const selectedMap = new Map();
108
+ let isRoot = false;
109
+ const hasCustomClasses = inputClasses && Object.keys(inputClasses).length > 0;
110
+ const applyClass = (classValue) => {
111
+ const isDefaultClasses = globalStateClasses[classValue];
112
+ if (isDefaultClasses) {
113
+ classList.push(isDefaultClasses);
114
+ }
115
+ else {
116
+ classList.push(`${DEFAULT_PREFIX}${prefix}-${classValue}`);
117
+ }
118
+ if (hasCustomClasses) {
119
+ // add selected class to map for use in inputClasses
120
+ selectedMap.set(simpleCamelCase(classValue), 1);
121
+ }
122
+ };
123
+ for (let i = 0; i < classValues.length; i++) {
124
+ const classValue = classValues[i];
125
+ if (!classValue)
126
+ continue;
127
+ if (typeof classValue === 'string') {
128
+ if (classValue === 'root') {
129
+ isRoot = true;
130
+ classList.push(`${DEFAULT_PREFIX}${prefix}`);
131
+ }
132
+ applyClass(classValue);
133
+ }
134
+ else {
135
+ for (const key in classValue) {
136
+ if (classValue[key]) {
137
+ applyClass(key);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ selectedMap.forEach((_, key) => {
143
+ const inputClassValue = inputClasses?.[key];
144
+ if (inputClassValue) {
145
+ classList.push(inputClassValue);
146
+ }
147
+ });
148
+ if (isRoot && className) {
149
+ // add root class and className
150
+ classList.push(className);
151
+ }
152
+ return classList.join(' ');
153
+ }, [className, inputClasses, prefix]);
154
+ };
155
+
156
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
157
+ const getTitle = (text) => {
158
+ return typeof text === 'string' ? text : undefined;
159
+ };
160
+
161
+ const isSuiElement = (element, suiNames) => {
162
+ return (React__default.isValidElement(element) &&
163
+ suiNames.indexOf(element.type.displayName) !== -1);
164
+ };
165
+
166
+ function isUrl(url) {
167
+ // eslint-disable-next-line no-useless-escape
168
+ const exp = /(\b(https?):\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])/gi;
169
+ return url.match(exp);
170
+ }
171
+
172
+ // * this whole file should be remove after webkit154 issue be fixed
173
+ /**
174
+ * Conditionally apply a workaround for the CSS transition bug in Safari 15.4 / WebKit browsers.
175
+ * Remove this workaround once the WebKit bug fix is released.
176
+ *
177
+ * follow up:
178
+ * https://github.com/mui/material-ui/pull/31975/files
179
+ * https://github.com/mui/material-ui/pull/32202/files
180
+ */
181
+ const isWebKit154 = typeof navigator !== 'undefined' &&
182
+ /^((?!chrome|android).)*(safari|mobile)/i.test(navigator.userAgent) &&
183
+ /(os |version\/)15(.|_)[4-9]/i.test(navigator.userAgent);
184
+
185
+ /** enhance lodash type */
186
+ const omit = (classes, keys) => {
187
+ return lodashOmit(classes, keys);
188
+ };
189
+
190
+ /**
191
+ * get that full height and margin with margin
192
+ * that will ignore transform animation
193
+ */
194
+ function outerSize(el) {
195
+ const style = getComputedStyle(el);
196
+ return {
197
+ get height() {
198
+ return (el.offsetHeight +
199
+ parseInt(style.marginTop, 10) +
200
+ parseInt(style.marginBottom, 10));
201
+ },
202
+ get width() {
203
+ return (el.offsetWidth +
204
+ parseInt(style.marginLeft, 10) +
205
+ parseInt(style.marginRight, 10));
206
+ },
207
+ };
208
+ }
209
+
210
+ /** enhance lodash type */
211
+ const pick = (classes, keys) => {
212
+ return lodashPick(classes, keys);
213
+ };
214
+
215
+ /** preload image file */
216
+ function preloadImg(url) {
217
+ return new Promise((resolve, reject) => {
218
+ const img = new Image();
219
+ img.style.display = 'none';
220
+ img.onload = () => {
221
+ document.body.removeChild(img);
222
+ resolve();
223
+ };
224
+ img.onerror = () => {
225
+ document.body.removeChild(img);
226
+ reject();
227
+ };
228
+ img.src = url;
229
+ document.body.appendChild(img);
230
+ });
231
+ }
232
+
233
+ /**
234
+ * remove className from element, default will not scan child nodes, if you want to scan child nodes, set `scanChildren` to `true`.
235
+ *
236
+ * @param target target element reference or element or callback
237
+ * @param removeClass className to remove, default will use class `includes` to check, if you want to use full match, set `fullMatch` to `true`
238
+ *
239
+ * @example
240
+ * ```js
241
+ * elm => <div class="abc bcd efg abc-def"></div>
242
+ *
243
+ * removeClassName(elmRef, 'bcd');
244
+ *
245
+ * elm => <div class="abc efg abc-def"></div>
246
+ *
247
+ * removeClassName(elmRef, 'abc');
248
+ * elm => <div class="efg"></div>
249
+ * ```
250
+ */
251
+ function removeClassName(target, removeClass, { scanChildren = false, fullMatch = false } = {}) {
252
+ const elm = getRefElement(target);
253
+ if (!elm)
254
+ return;
255
+ if (elm.className.includes(removeClass)) {
256
+ elm.className = cleanClass(elm, removeClass, fullMatch);
257
+ }
258
+ if (scanChildren) {
259
+ const nodes = elm.querySelectorAll(`[class*="${removeClass}"]`);
260
+ if (nodes?.length > 0) {
261
+ nodes.forEach((node) => (node.className = cleanClass(node, removeClass, fullMatch)));
262
+ }
263
+ }
264
+ }
265
+ function cleanClass(elm, removeClass, fullMatch) {
266
+ return elm.className
267
+ .trim()
268
+ .split(/\s+/)
269
+ .filter((className) => !(fullMatch
270
+ ? className === removeClass
271
+ : className.includes(removeClass)))
272
+ .join(' ');
273
+ }
274
+
275
+ /**
276
+ * Executes the corresponding key handler function based on the provided keyboard event.
277
+ * If a handler is found for the pressed key, it will be invoked.
278
+ * Additionally, it prevents any side effects caused by the event, such as page scrolling.
279
+ *
280
+ * @param e - The keyboard event.
281
+ * @param keyHandlers - An object containing key-handler mappings.
282
+ */
283
+ const runKeyHandler = (e, keyHandlers) => {
284
+ const handler = keyHandlers[e.key];
285
+ if (handler) {
286
+ handler();
287
+ // if event was handled prevent other side effects (e.g. page scroll)
288
+ e.preventDefault();
289
+ }
290
+ };
291
+
292
+ /**
293
+ * get current input element selection position and is that selectRange state
294
+ */
295
+ function getSelectionPosition(sourceTarget) {
296
+ const input = getRefElement(sourceTarget);
297
+ const currentPosition = input?.selectionStart;
298
+ const currentPositionEnd = input?.selectionEnd;
299
+ const isSelectRange = currentPosition !== currentPositionEnd;
300
+ return {
301
+ isSelectRange,
302
+ position: { start: currentPosition || 0, end: currentPositionEnd || 0 },
303
+ };
304
+ }
305
+ /**
306
+ * set input element selection position position,
307
+ * if you need scroll that into view set `scrollIntoView` as true
308
+ */
309
+ function setSelectionPosition(target, options) {
310
+ const elm = getRefElement(target);
311
+ if (elm && options.start !== null && options.end !== null) {
312
+ // * use blur and refocus to refocus position into view
313
+ if (options.scrollIntoView)
314
+ elm.blur();
315
+ elm.setSelectionRange(options.start, options.end, options.direction);
316
+ if (options.scrollIntoView)
317
+ elm.focus();
318
+ }
319
+ }
320
+ /** clean whole selection */
321
+ function clearWindowSelection() {
322
+ if (window?.getSelection) {
323
+ const selection = window.getSelection();
324
+ if (selection) {
325
+ // Chrome
326
+ selection.empty?.();
327
+ // Firefox
328
+ selection.removeAllRanges?.();
329
+ }
330
+ }
331
+ }
332
+
333
+ export { a11yKeyboard, capitalize, checkDefaultPrevented, checkElementName, clearWindowSelection, getRefElement, getSelectionPosition, getTitle, globalStateClasses, isDeleteKeyboardEvent, isSuiElement, isUrl, isWebKit154, omit, outerSize, pick, preloadImg, removeClassName, runKeyHandler, setSelectionPosition, useClasses };