@telus-uds/components-base 1.19.0 → 1.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/lib/ActivityIndicator/Spinner.js +7 -7
  3. package/lib/ActivityIndicator/Spinner.native.js +2 -2
  4. package/lib/BaseProvider/HydrationContext.js +1 -1
  5. package/lib/BaseProvider/TamaguiProvider.js +30 -0
  6. package/lib/Button/ButtonBase.js +2 -2
  7. package/lib/Button/ButtonDropdown.js +207 -0
  8. package/lib/Button/ButtonGroup.js +1 -1
  9. package/lib/Carousel/Carousel.js +2 -4
  10. package/lib/Carousel/CarouselContext.js +1 -1
  11. package/lib/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +1 -1
  12. package/lib/Carousel/CarouselThumbnail.js +2 -2
  13. package/lib/Checkbox/Checkbox.js +1 -1
  14. package/lib/Checkbox/CheckboxGroup.js +2 -2
  15. package/lib/Divider/Divider.js +2 -2
  16. package/lib/FlexGrid/Col/Col.js +1 -1
  17. package/lib/Icon/Icon.js +1 -1
  18. package/lib/MultiSelectFilter/ModalOverlay.js +136 -0
  19. package/lib/MultiSelectFilter/MultiSelectFilter.js +314 -0
  20. package/lib/MultiSelectFilter/dictionary.js +19 -0
  21. package/lib/MultiSelectFilter/index.js +13 -0
  22. package/lib/Pagination/PageButton.js +2 -2
  23. package/lib/Pagination/Pagination.js +3 -5
  24. package/lib/Pagination/usePagination.js +2 -2
  25. package/lib/Progress/ProgressBar.js +3 -3
  26. package/lib/Progress/ProgressBarBackground.js +3 -3
  27. package/lib/QuickLinksFeature/QuickLinksFeature.js +91 -0
  28. package/lib/QuickLinksFeature/QuickLinksFeatureItem.js +157 -0
  29. package/lib/QuickLinksFeature/index.js +16 -0
  30. package/lib/Radio/Radio.js +2 -2
  31. package/lib/Radio/RadioGroup.js +2 -2
  32. package/lib/RadioCard/RadioCard.js +1 -1
  33. package/lib/RadioCard/RadioCardGroup.js +2 -2
  34. package/lib/Search/Search.js +1 -1
  35. package/lib/Select/constants.js +15 -0
  36. package/lib/SideNav/SideNav.js +2 -2
  37. package/lib/Skeleton/Skeleton.js +1 -1
  38. package/lib/Skeleton/skeletonWebAnimation.js +1 -1
  39. package/lib/StackView/StackWrap.js +1 -3
  40. package/lib/StackView/getStackedContent.js +2 -2
  41. package/lib/Tabs/Tabs.js +2 -4
  42. package/lib/Tags/Tags.js +1 -1
  43. package/lib/TextInput/dictionary.js +19 -0
  44. package/lib/ThemeProvider/utils/styles.js +3 -3
  45. package/lib/ThemeProvider/utils/theme-tokens.js +9 -7
  46. package/lib/Timeline/Timeline.js +1 -1
  47. package/lib/ToggleSwitch/ToggleSwitch.js +1 -1
  48. package/lib/ToggleSwitch/ToggleSwitchGroup.js +1 -1
  49. package/lib/Tooltip/Backdrop.js +10 -2
  50. package/lib/Tooltip/Tooltip.native.js +357 -0
  51. package/lib/Tooltip/shared.js +39 -0
  52. package/lib/Validator/Validator.js +271 -0
  53. package/lib/Validator/index.js +13 -0
  54. package/lib/utils/BaseView/BaseView.js +64 -0
  55. package/lib/utils/BaseView/BaseView.native.js +16 -0
  56. package/lib/utils/BaseView/index.js +13 -0
  57. package/lib/utils/animation/useVerticalExpandAnimation.js +1 -1
  58. package/lib/utils/children.js +2 -2
  59. package/lib/utils/floating-ui/index.js +43 -0
  60. package/lib/utils/floating-ui/index.native.js +43 -0
  61. package/lib/utils/input.js +12 -6
  62. package/lib/utils/props/componentPropType.js +3 -3
  63. package/lib/utils/props/selectSystemProps.js +2 -2
  64. package/lib/utils/props/tokens.js +2 -2
  65. package/lib/utils/useOverlaidPosition.js +243 -0
  66. package/lib/utils/useSpacingScale.js +1 -3
  67. package/lib/utils/useUniqueId.js +1 -1
  68. package/lib-module/ActivityIndicator/Spinner.js +7 -7
  69. package/lib-module/ActivityIndicator/Spinner.native.js +2 -2
  70. package/lib-module/BaseProvider/HydrationContext.js +1 -1
  71. package/lib-module/BaseProvider/TamaguiProvider.js +22 -0
  72. package/lib-module/Button/ButtonBase.js +2 -2
  73. package/lib-module/Button/ButtonDropdown.js +181 -0
  74. package/lib-module/Button/ButtonGroup.js +1 -1
  75. package/lib-module/Carousel/Carousel.js +2 -4
  76. package/lib-module/Carousel/CarouselContext.js +1 -1
  77. package/lib-module/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +1 -1
  78. package/lib-module/Carousel/CarouselThumbnail.js +2 -2
  79. package/lib-module/Checkbox/Checkbox.js +1 -1
  80. package/lib-module/Checkbox/CheckboxGroup.js +2 -2
  81. package/lib-module/Divider/Divider.js +2 -2
  82. package/lib-module/FlexGrid/Col/Col.js +1 -1
  83. package/lib-module/Icon/Icon.js +1 -1
  84. package/lib-module/MultiSelectFilter/ModalOverlay.js +112 -0
  85. package/lib-module/MultiSelectFilter/MultiSelectFilter.js +286 -0
  86. package/lib-module/MultiSelectFilter/dictionary.js +12 -0
  87. package/lib-module/MultiSelectFilter/index.js +2 -0
  88. package/lib-module/Pagination/PageButton.js +2 -2
  89. package/lib-module/Pagination/Pagination.js +3 -5
  90. package/lib-module/Pagination/usePagination.js +2 -2
  91. package/lib-module/Progress/ProgressBar.js +3 -3
  92. package/lib-module/Progress/ProgressBarBackground.js +3 -3
  93. package/lib-module/QuickLinksFeature/QuickLinksFeature.js +69 -0
  94. package/lib-module/QuickLinksFeature/QuickLinksFeatureItem.js +130 -0
  95. package/lib-module/QuickLinksFeature/index.js +4 -0
  96. package/lib-module/Radio/Radio.js +2 -2
  97. package/lib-module/Radio/RadioGroup.js +2 -2
  98. package/lib-module/RadioCard/RadioCard.js +1 -1
  99. package/lib-module/RadioCard/RadioCardGroup.js +2 -2
  100. package/lib-module/Search/Search.js +1 -1
  101. package/lib-module/Select/constants.js +5 -0
  102. package/lib-module/SideNav/SideNav.js +2 -2
  103. package/lib-module/Skeleton/Skeleton.js +1 -1
  104. package/lib-module/Skeleton/skeletonWebAnimation.js +1 -1
  105. package/lib-module/StackView/StackWrap.js +1 -3
  106. package/lib-module/StackView/getStackedContent.js +2 -2
  107. package/lib-module/Tabs/Tabs.js +2 -4
  108. package/lib-module/Tags/Tags.js +1 -1
  109. package/lib-module/TextInput/dictionary.js +12 -0
  110. package/lib-module/ThemeProvider/utils/styles.js +3 -3
  111. package/lib-module/ThemeProvider/utils/theme-tokens.js +9 -7
  112. package/lib-module/Timeline/Timeline.js +1 -1
  113. package/lib-module/ToggleSwitch/ToggleSwitch.js +1 -1
  114. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +1 -1
  115. package/lib-module/Tooltip/Backdrop.js +10 -2
  116. package/lib-module/Tooltip/Tooltip.native.js +326 -0
  117. package/lib-module/Tooltip/shared.js +27 -0
  118. package/lib-module/Validator/Validator.js +245 -0
  119. package/lib-module/Validator/index.js +2 -0
  120. package/lib-module/utils/BaseView/BaseView.js +43 -0
  121. package/lib-module/utils/BaseView/BaseView.native.js +6 -0
  122. package/lib-module/utils/BaseView/index.js +2 -0
  123. package/lib-module/utils/animation/useVerticalExpandAnimation.js +1 -1
  124. package/lib-module/utils/children.js +2 -2
  125. package/lib-module/utils/floating-ui/index.js +1 -0
  126. package/lib-module/utils/floating-ui/index.native.js +1 -0
  127. package/lib-module/utils/input.js +12 -6
  128. package/lib-module/utils/props/componentPropType.js +3 -3
  129. package/lib-module/utils/props/selectSystemProps.js +2 -2
  130. package/lib-module/utils/props/tokens.js +2 -2
  131. package/lib-module/utils/useOverlaidPosition.js +232 -0
  132. package/lib-module/utils/useSpacingScale.js +1 -3
  133. package/lib-module/utils/useUniqueId.js +1 -1
  134. package/package.json +2 -2
@@ -0,0 +1,245 @@
1
+ import React, { forwardRef, createRef, useRef, useMemo, useEffect, useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import View from "react-native-web/dist/exports/View";
4
+ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
+ import Platform from "react-native-web/dist/exports/Platform";
6
+ import { inputSupportsProps, selectSystemProps } from '../utils';
7
+ import { TextInput } from '../TextInput';
8
+ import StackView from '../StackView';
9
+ import InputSupports from '../InputSupports';
10
+ import { useThemeTokens } from '../ThemeProvider';
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([inputSupportsProps]);
13
+
14
+ const selectCodeTextInputTokens = _ref => {
15
+ let {
16
+ outerBorderColor,
17
+ outerBackgroundColor
18
+ } = _ref;
19
+ return {
20
+ outerBorderColor,
21
+ outerBackgroundColor,
22
+ icon: null
23
+ };
24
+ };
25
+
26
+ const Validator = /*#__PURE__*/forwardRef((_ref2, ref) => {
27
+ let {
28
+ value = '',
29
+ inactive,
30
+ onChange,
31
+ tokens = {},
32
+ variant = {},
33
+ ...rest
34
+ } = _ref2;
35
+ const defaultRef = useRef();
36
+ const codeRef = ref ?? defaultRef;
37
+ const {
38
+ supportsProps
39
+ } = selectProps(rest);
40
+ const strValidation = supportsProps.validation;
41
+ const [individualCodes, setIndividualCodes] = useState({});
42
+ const [text, setText] = useState(value);
43
+ const validatorsLength = 6;
44
+ const prefix = 'code';
45
+ const sufixValidation = 'Validation';
46
+ const [isHover, setIsHover] = useState(false);
47
+
48
+ const handleMouseOver = () => {
49
+ setIsHover(true);
50
+ };
51
+
52
+ const handleMouseOut = () => {
53
+ setIsHover(false);
54
+ };
55
+
56
+ const themeTokens = useThemeTokens('TextInput', tokens, variant, {
57
+ hover: isHover
58
+ });
59
+ const [codeReferences, singleCodes] = useMemo(() => {
60
+ const codes = [];
61
+ const valueCodes = {};
62
+
63
+ for (let i = 0; validatorsLength && i < validatorsLength; i += 1) {
64
+ codes[prefix + i] = /*#__PURE__*/createRef();
65
+ valueCodes[prefix + i] = '';
66
+ valueCodes[prefix + i + sufixValidation] = '';
67
+ }
68
+
69
+ return [codes, valueCodes];
70
+ }, []);
71
+
72
+ const handleSingleCodes = (codeId, val, validation) => {
73
+ singleCodes[codeId] = val;
74
+ singleCodes[codeId + sufixValidation] = validation;
75
+ /* eslint-disable no-unused-expressions */
76
+
77
+ setIndividualCodes({ ...individualCodes,
78
+ [codeId]: val
79
+ });
80
+ };
81
+
82
+ const handleChangeCode = () => {
83
+ let code = '';
84
+
85
+ for (let i = 0; i < validatorsLength; i += 1) code += singleCodes[prefix + i];
86
+
87
+ if (typeof onChange === 'function') onChange(code, singleCodes);
88
+ };
89
+
90
+ const handleChangeCodeValues = (event, codeId, nextIndex) => {
91
+ var _codeReferences$codeI, _event$nativeEvent, _event$target, _codeElement$value, _codeElement$value2;
92
+
93
+ const codeElement = (_codeReferences$codeI = codeReferences[codeId]) === null || _codeReferences$codeI === void 0 ? void 0 : _codeReferences$codeI.current;
94
+ const val = ((_event$nativeEvent = event.nativeEvent) === null || _event$nativeEvent === void 0 ? void 0 : _event$nativeEvent.value) || ((_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.value);
95
+
96
+ if (Number(val).toString() === 'NaN') {
97
+ codeElement.value = singleCodes[codeId] ?? '';
98
+ return;
99
+ }
100
+
101
+ if ((codeElement === null || codeElement === void 0 ? void 0 : (_codeElement$value = codeElement.value) === null || _codeElement$value === void 0 ? void 0 : _codeElement$value.length) > 1) {
102
+ const oldValue = singleCodes[codeId];
103
+ const newValue = codeElement.value.replace(oldValue, '');
104
+ codeElement.value = newValue;
105
+ handleSingleCodes(codeId, codeElement.value, 'success');
106
+ }
107
+
108
+ handleSingleCodes(codeId, (codeElement === null || codeElement === void 0 ? void 0 : codeElement.value) ?? singleCodes[codeId], 'success');
109
+ handleChangeCode();
110
+
111
+ if (nextIndex === validatorsLength) {
112
+ codeElement.blur();
113
+ return;
114
+ }
115
+
116
+ if ((codeElement === null || codeElement === void 0 ? void 0 : (_codeElement$value2 = codeElement.value) === null || _codeElement$value2 === void 0 ? void 0 : _codeElement$value2.length) > 0) codeReferences[prefix + nextIndex].current.focus();
117
+ };
118
+
119
+ const handleKeyPress = (event, currentIndex, previousIndex) => {
120
+ if (!(event.keyCode === 8 || event.code === 'Backspace')) return;
121
+
122
+ if (currentIndex > 0) {
123
+ codeReferences[prefix + currentIndex].current.value = '';
124
+ codeReferences[prefix + previousIndex].current.focus();
125
+ }
126
+
127
+ handleSingleCodes(prefix + currentIndex, '', '');
128
+ handleChangeCode();
129
+ };
130
+
131
+ const getCodeComponents = () => {
132
+ const components = [];
133
+
134
+ for (let i = 0; validatorsLength && i < validatorsLength; i += 1) {
135
+ const codeId = prefix + i;
136
+ const codeInputProps = {
137
+ nativeID: codeId,
138
+ keyboardType: 'numeric',
139
+ ref: codeReferences[codeId] ?? null,
140
+ validation: strValidation || singleCodes[codeId + sufixValidation],
141
+ tokens: selectCodeTextInputTokens(themeTokens),
142
+ onFocus: () => {
143
+ var _codeReferences$codeI2, _codeReferences$codeI3;
144
+
145
+ return ((_codeReferences$codeI2 = codeReferences[codeId]) === null || _codeReferences$codeI2 === void 0 ? void 0 : (_codeReferences$codeI3 = _codeReferences$codeI2.current) === null || _codeReferences$codeI3 === void 0 ? void 0 : _codeReferences$codeI3.select()) ?? null;
146
+ },
147
+ onKeyPress: event => handleKeyPress(event, i, i - 1),
148
+ onMouseOver: handleMouseOver,
149
+ onMouseOut: handleMouseOut,
150
+ inactive
151
+ };
152
+ codeInputProps.validation || delete codeInputProps.validation;
153
+ components.push( /*#__PURE__*/_jsx(View, {
154
+ style: staticStyles.codeInputWidth,
155
+ children: /*#__PURE__*/_jsx(TextInput, { ...codeInputProps
156
+ })
157
+ }, codeId));
158
+ }
159
+
160
+ return components;
161
+ };
162
+
163
+ useEffect(() => {
164
+ /* eslint-disable no-unused-expressions */
165
+ if (Number(value).toString() !== 'NaN') setText(value);
166
+ }, [value]);
167
+ /* eslint-disable react-hooks/exhaustive-deps */
168
+
169
+ useEffect(() => {
170
+ for (let i = 0; i < validatorsLength; i += 1) {
171
+ codeReferences[prefix + i].current.value = text[i] ?? '';
172
+ handleSingleCodes(prefix + i, text[i] ?? '', text[i] ? 'success' : '');
173
+ }
174
+ }, [text]);
175
+ /* eslint-disable react-hooks/exhaustive-deps */
176
+
177
+ useEffect(() => {
178
+ const handlePasteCode = event => {
179
+ setText('');
180
+ const clipBoardText = event.clipboardData.getData('text');
181
+ if (Number(clipBoardText).toString() !== 'NaN') setText(clipBoardText);
182
+ };
183
+
184
+ const handleCopy = event => {
185
+ let clipBoardText = '';
186
+
187
+ for (let i = 0; i < validatorsLength; i += 1) singleCodes[prefix + i] && (clipBoardText += singleCodes[prefix + i]);
188
+
189
+ event.clipboardData.setData('text/plain', clipBoardText);
190
+ event.preventDefault();
191
+ };
192
+
193
+ if (Platform.OS === 'web') {
194
+ for (let i = 0; i < validatorsLength; i += 1) {
195
+ codeReferences[prefix + i].current.addEventListener('paste', handlePasteCode);
196
+ codeReferences[prefix + i].current.addEventListener('copy', handleCopy);
197
+ codeReferences[prefix + i].current.addEventListener('input', event => handleChangeCodeValues(event, prefix + i, i + 1));
198
+ }
199
+ }
200
+
201
+ return () => {
202
+ if (Platform.oldValue === 'web') {
203
+ for (let i = 0; i < validatorsLength; i += 1) {
204
+ var _codeReferences, _codeReferences$curre, _codeReferences2, _codeReferences2$curr, _codeReferences3, _codeReferences3$curr;
205
+
206
+ (_codeReferences = codeReferences[prefix + i]) === null || _codeReferences === void 0 ? void 0 : (_codeReferences$curre = _codeReferences.current) === null || _codeReferences$curre === void 0 ? void 0 : _codeReferences$curre.removeEventListener('paste', handlePasteCode);
207
+ (_codeReferences2 = codeReferences[prefix + i]) === null || _codeReferences2 === void 0 ? void 0 : (_codeReferences2$curr = _codeReferences2.current) === null || _codeReferences2$curr === void 0 ? void 0 : _codeReferences2$curr.removeEventListener('copy', handleCopy);
208
+ (_codeReferences3 = codeReferences[prefix + i]) === null || _codeReferences3 === void 0 ? void 0 : (_codeReferences3$curr = _codeReferences3.current) === null || _codeReferences3$curr === void 0 ? void 0 : _codeReferences3$curr.removeEventListener('input', event => handleChangeCodeValues(event, prefix + i, i + 1));
209
+ }
210
+ }
211
+ };
212
+ }, []);
213
+ return /*#__PURE__*/_jsx(InputSupports, { ...supportsProps,
214
+ children: /*#__PURE__*/_jsx(StackView, {
215
+ space: 2,
216
+ direction: "row",
217
+ ref: codeRef,
218
+ children: getCodeComponents()
219
+ })
220
+ });
221
+ });
222
+ Validator.displayName = 'Validator';
223
+ Validator.propTypes = { ...selectedSystemPropTypes,
224
+
225
+ /**
226
+ * The value is a 6-digit code, may be only numeric characters, non numeric character aren't renderize
227
+ */
228
+ value: PropTypes.string,
229
+
230
+ /**
231
+ * If true, the component is inactive and non editable.
232
+ */
233
+ inactive: PropTypes.bool,
234
+
235
+ /**
236
+ * Use to react upon input's value changes. Required when the `value` prop is set. Will receive the input's value as an argument.
237
+ */
238
+ onChange: PropTypes.func
239
+ };
240
+ export default Validator;
241
+ const staticStyles = StyleSheet.create({
242
+ codeInputWidth: {
243
+ width: 43
244
+ }
245
+ });
@@ -0,0 +1,2 @@
1
+ import Validator from './Validator';
2
+ export default Validator;
@@ -0,0 +1,43 @@
1
+ import React, { forwardRef } from 'react';
2
+ import NativeView from "react-native-web/dist/exports/View";
3
+ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
4
+ import PropTypes from 'prop-types';
5
+ import { useTheme } from '../../ThemeProvider';
6
+ /**
7
+ * Identical to React Native's View and supporting all the same props, but with:
8
+ * - a zIndex: 'auto' style added to prevent unexpectedly causing children to overlap other elements from other stacking contexts
9
+ */
10
+
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ const BaseView = /*#__PURE__*/forwardRef((_ref, ref) => {
13
+ let {
14
+ children,
15
+ style,
16
+ ...rest
17
+ } = _ref;
18
+ const {
19
+ themeOptions
20
+ } = useTheme();
21
+ const styleProp = Array.isArray(style) ? [...style] : [style];
22
+
23
+ if (!themeOptions.forceZIndex) {
24
+ styleProp.unshift(styles.resetZIndex);
25
+ }
26
+
27
+ return /*#__PURE__*/_jsx(NativeView, { ...rest,
28
+ style: styleProp,
29
+ ref: ref,
30
+ children: children
31
+ });
32
+ });
33
+ BaseView.displayName = 'BaseView';
34
+ const styles = StyleSheet.create({
35
+ resetZIndex: {
36
+ zIndex: 'auto'
37
+ }
38
+ });
39
+ BaseView.propTypes = {
40
+ children: PropTypes.node,
41
+ style: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
42
+ };
43
+ export default BaseView;
@@ -0,0 +1,6 @@
1
+ import BaseView from "react-native-web/dist/exports/View";
2
+ /**
3
+ * Android crashes on non-standard style properties like `zIndex` so adding a `BaseView` for native platforms
4
+ */
5
+
6
+ export default BaseView;
@@ -0,0 +1,2 @@
1
+ import BaseView from './BaseView';
2
+ export default BaseView;
@@ -72,7 +72,7 @@ function useVerticalExpandAnimation(_ref) {
72
72
  }
73
73
  } else if (Platform.OS === 'web') {
74
74
  const transitionDuration = isExpanded ? expandDuration : collapseDuration;
75
- containerStyles.transition = "height ".concat(transitionDuration, "ms ease-in-out");
75
+ containerStyles.transition = `height ${transitionDuration}ms ease-in-out`;
76
76
  containerStyles.height = isExpanded ? containerHeight : 0;
77
77
  } else if (Platform.OS === 'ios' && isExpanded && !isAnimating && !expandStateChanged && typeof containerHeight === 'number') {
78
78
  // iOS reflows text while the height animation is in progress. Sometimes, it hits a timing bug where
@@ -55,7 +55,7 @@ const isWrapable = child => {
55
55
  return isStringOrNumber(child) || child.type === A11yText || ((_child$type = child.type) === null || _child$type === void 0 ? void 0 : _child$type.name) === 'FootnoteLink';
56
56
  };
57
57
 
58
- const combineKeys = childrenArray => childrenArray.reduce((newKey, child) => "".concat(newKey).concat(child.key || ''), ''); // Group wrappable children for one `<Text>` parent, merging adjacent text nodes
58
+ const combineKeys = childrenArray => childrenArray.reduce((newKey, child) => `${newKey}${child.key || ''}`, ''); // Group wrappable children for one `<Text>` parent, merging adjacent text nodes
59
59
 
60
60
 
61
61
  const wrapChild = (child, wrappedText) => {
@@ -64,7 +64,7 @@ const wrapChild = (child, wrappedText) => {
64
64
 
65
65
  if (lastIndex >= 0 && isStringOrNumber(child) && isStringOrNumber(wrappedText[lastIndex])) {
66
66
  /* eslint-disable-next-line no-param-reassign */
67
- wrappedText[lastIndex] = "".concat(wrappedText[lastIndex]).concat(child);
67
+ wrappedText[lastIndex] = `${wrappedText[lastIndex]}${child}`;
68
68
  } else {
69
69
  wrappedText.push(child);
70
70
  }
@@ -0,0 +1 @@
1
+ export { useFloating, arrow, offset, shift, flip, autoPlacement } from '@floating-ui/react-dom';
@@ -0,0 +1 @@
1
+ export { useFloating, arrow, offset, shift, flip, autoPlacement } from '@floating-ui/react-native';
@@ -21,23 +21,29 @@ const validateProps = (_ref, _ref2, hookName) => {
21
21
  const usageError = error => {
22
22
  // Errors inside hooks in React Native get incomplete stack traces pointing at parent component only.
23
23
  // Help devs out by telling them exactly which hook threw the error as well as why.
24
- throw new Error("".concat(hookName, " ").concat(error, ".\n\nConsumers of this hook must be one of:\n1. An \"uncontrolled\" component responding directly to user actions, with an optional `initialValue").concat(s, "` but no `value").concat(s, "` prop,\n2. A \"controlled\" component where an always-defined `value").concat(s, "` prop is managed by an `onChange` handler, with no `initialValue").concat(s, "`,\n3. A \"read-only\" component, with `readOnly` prop set as `true`.\n"));
24
+ throw new Error(`${hookName} ${error}.
25
+
26
+ Consumers of this hook must be one of:
27
+ 1. An "uncontrolled" component responding directly to user actions, with an optional \`initialValue${s}\` but no \`value${s}\` prop,
28
+ 2. A "controlled" component where an always-defined \`value${s}\` prop is managed by an \`onChange\` handler, with no \`initialValue${s}\`,
29
+ 3. A "read-only" component, with \`readOnly\` prop set as \`true\`.
30
+ `);
25
31
  };
26
32
 
27
33
  if (value && !onChange && !readOnly) {
28
- usageError("has `value".concat(s, "` prop without `onChange` or `readOnly`"));
34
+ usageError(`has \`value${s}\` prop without \`onChange\` or \`readOnly\``);
29
35
  }
30
36
 
31
37
  if (initialValue && value) {
32
- usageError("has both `initialValue".concat(s, "` and `value").concat(s, "`"));
38
+ usageError(`has both \`initialValue${s}\` and \`value${s}\``);
33
39
  }
34
40
 
35
41
  if (isControlled && !isCurrentlyControlled) {
36
- usageError("stopped receiving `value".concat(s, "` from parent after delegating state management"));
42
+ usageError(`stopped receiving \`value${s}\` from parent after delegating state management`);
37
43
  }
38
44
 
39
45
  if (!isControlled && isCurrentlyControlled) {
40
- usageError("started receiving `value".concat(s, "` from parent after starting managing own state"));
46
+ usageError(`started receiving \`value${s}\` from parent after starting managing own state`);
41
47
  }
42
48
  };
43
49
  /**
@@ -148,7 +154,7 @@ export const useMultipleInputValues = function () {
148
154
  onChange,
149
155
  value: values,
150
156
  // if we're controlling our own state, always start with an array
151
- initialValue: initialValues !== null && initialValues !== void 0 ? initialValues : values === undefined ? [] : undefined
157
+ initialValue: initialValues ?? (values === undefined ? [] : undefined)
152
158
  }, 'useMultipleInputValues');
153
159
  const enforceMaxValues = useCallback(newValues => {
154
160
  if (!maxValues) return newValues;
@@ -26,8 +26,8 @@ export default function componentPropType(passedName) {
26
26
  const nameInProp = ((_props$propName$type = props[propName].type) === null || _props$propName$type === void 0 ? void 0 : _props$propName$type.displayName) || ((_props$propName$type2 = props[propName].type) === null || _props$propName$type2 === void 0 ? void 0 : _props$propName$type2.name);
27
27
 
28
28
  if (!nameInProp || !passedNames.includes(nameInProp)) {
29
- const propDescription = nameInProp ? "Component ".concat(nameInProp) : typeof props[propName];
30
- return new Error("".concat(componentName, ": ").concat(propDescription, " was passed to `").concat(propName, "` prop; should be ").concat(passedNames.join(' or ')));
29
+ const propDescription = nameInProp ? `Component ${nameInProp}` : typeof props[propName];
30
+ return new Error(`${componentName}: ${propDescription} was passed to \`${propName}\` prop; should be ${passedNames.join(' or ')}`);
31
31
  }
32
32
 
33
33
  return undefined;
@@ -35,7 +35,7 @@ export default function componentPropType(passedName) {
35
35
 
36
36
  const checkRequired = (props, propName, componentName) => {
37
37
  if (props[propName] === undefined) {
38
- return new Error("The prop `".concat(propName, "` is marked as required in `").concat(componentName, "`, but its value is ").concat(props[propName], "."));
38
+ return new Error(`The prop \`${propName}\` is marked as required in \`${componentName}\`, but its value is ${props[propName]}.`);
39
39
  }
40
40
 
41
41
  return undefined;
@@ -3,7 +3,7 @@
3
3
  export default function selectSystemProps(systemPropHelpers) {
4
4
  const selectProps = props => systemPropHelpers.reduce((acc, propHelper) => {
5
5
  if (typeof (propHelper === null || propHelper === void 0 ? void 0 : propHelper.select) !== 'function') {
6
- throw new Error("An invalid system prop helper has been passed to 'selectSystemProps': prop selector ('.select') is missing in ".concat(propHelper));
6
+ throw new Error(`An invalid system prop helper has been passed to 'selectSystemProps': prop selector ('.select') is missing in ${propHelper}`);
7
7
  }
8
8
 
9
9
  return { ...acc,
@@ -13,7 +13,7 @@ export default function selectSystemProps(systemPropHelpers) {
13
13
 
14
14
  const selectedPropTypes = systemPropHelpers.reduce((acc, propHelper) => {
15
15
  if (!(propHelper !== null && propHelper !== void 0 && propHelper.types)) {
16
- throw new Error("An invalid system prop helper has been passed to 'selectSystemProps': types selector ('.types') is missing in ".concat(propHelper));
16
+ throw new Error(`An invalid system prop helper has been passed to 'selectSystemProps': types selector ('.types') is missing in ${propHelper}`);
17
17
  }
18
18
 
19
19
  return { ...acc,
@@ -9,7 +9,7 @@ export const getTokenNames = componentName => {
9
9
  const componentTokenSchema = tokenKeys[componentName];
10
10
 
11
11
  if (!componentTokenSchema) {
12
- throw new Error("No \"".concat(componentName, "\" tokenKeys in @telus-uds/system-theme-tokens"));
12
+ throw new Error(`No "${componentName}" tokenKeys in @telus-uds/system-theme-tokens`);
13
13
  }
14
14
 
15
15
  return Object.keys(componentTokenSchema);
@@ -47,7 +47,7 @@ export const getTokenNames = componentName => {
47
47
  export const selectTokens = (specifier, tokens, prefix) => {
48
48
  const tokenNames = typeof specifier === 'string' ? getTokenNames(specifier) : specifier;
49
49
  const filteredTokens = tokenNames.reduce((validTokens, key) => {
50
- const prefixedKey = prefix ? "".concat(prefix).concat(key[0].toUpperCase()).concat(key.slice(1)) : key;
50
+ const prefixedKey = prefix ? `${prefix}${key[0].toUpperCase()}${key.slice(1)}` : key;
51
51
  const token = tokens[prefixedKey];
52
52
  return token !== undefined ? { ...validTokens,
53
53
  [key]: token
@@ -0,0 +1,232 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import Dimensions from "react-native-web/dist/exports/Dimensions";
3
+
4
+ const adjustHorizontalToFit = (initialOffset, windowWidth, sourceWidth) => {
5
+ const offset = Math.max(0, initialOffset);
6
+ const otherEdgeOverflow = Math.max(0, offset + sourceWidth - windowWidth);
7
+ const tooWideBy = Math.max(0, otherEdgeOverflow - offset);
8
+ const adjusted = {
9
+ offset: Math.max(0, offset - otherEdgeOverflow)
10
+ };
11
+ if (tooWideBy) adjusted.width = Math.max(0, sourceWidth - tooWideBy);
12
+ return adjusted;
13
+ };
14
+
15
+ const getPosition = _ref => {
16
+ let {
17
+ edge,
18
+ fromEdge,
19
+ sourceSize
20
+ } = _ref;
21
+
22
+ switch (edge) {
23
+ case 'near':
24
+ return fromEdge;
25
+
26
+ case 'mid':
27
+ return fromEdge + sourceSize / 2;
28
+
29
+ case 'far':
30
+ return fromEdge + sourceSize;
31
+
32
+ default:
33
+ return 0;
34
+ }
35
+ };
36
+
37
+ const getEdgeType = (align, alignSide) => {
38
+ const alignTo = align[alignSide];
39
+ const edge = ['center', 'middle'].includes(alignTo) && 'mid' || (alignSide === alignTo ? 'near' : 'far');
40
+ return edge;
41
+ };
42
+ /**
43
+ * Based on UDS's private getTooltipPosition but generalised.
44
+ *
45
+ * Used for absolute positioning of the tooltip. Since the tooltip is always centered relatively
46
+ * to the source (button) and we have a limited set of positions, an easy and consistent way
47
+ * of positioning it is to check all of the possible positions and pick one that will be rendered
48
+ * within the window bounds. This way we can also rely on the tooltip being actually rendered
49
+ * before it is shown, which makes it account for the width being limiting in styles, custom font
50
+ * rendering, etc.
51
+ */
52
+
53
+
54
+ function getOverlaidPosition(_ref2) {
55
+ let {
56
+ sourceLayout,
57
+ targetDimensions,
58
+ windowDimensions,
59
+ offsets = {},
60
+ align
61
+ } = _ref2;
62
+ // Web-only: this will be difficult to mimic on native because there's no global scroll position.
63
+ // TODO: wire something in e.g. a scroll ref accessible from a provider included in Allium provider
64
+ // that can be passed to the appropriate ScrollView?
65
+ const {
66
+ scrollX = 0,
67
+ scrollY = 0
68
+ } = typeof window === 'object' ? window : {}; // Will have top, bottom, left and/or right offsets depending on `align`
69
+
70
+ const positioning = {};
71
+ if (align.top) positioning.top = getPosition({
72
+ edge: getEdgeType(align, 'top'),
73
+ fromEdge: sourceLayout.y + scrollY + (offsets.vertical ?? 0),
74
+ sourceSize: sourceLayout.height
75
+ });
76
+ if (align.middle) positioning.top = getPosition({
77
+ edge: getEdgeType(align, 'middle'),
78
+ fromEdge: sourceLayout.y + scrollY + (offsets.vertical ?? 0) - targetDimensions.height / 2,
79
+ sourceSize: sourceLayout.height
80
+ });
81
+ if (align.bottom) positioning.bottom = getPosition({
82
+ edge: getEdgeType(align, 'bottom'),
83
+ fromEdge: windowDimensions.height - (sourceLayout.y + scrollY + sourceLayout.height - (offsets.vertical ?? 0)),
84
+ sourceSize: sourceLayout.height
85
+ });
86
+ if (align.left) positioning.left = getPosition({
87
+ edge: getEdgeType(align, 'left'),
88
+ fromEdge: sourceLayout.x + scrollX + (offsets.horizontal ?? 0),
89
+ sourceSize: sourceLayout.width
90
+ });
91
+ if (align.center) positioning.left = getPosition({
92
+ edge: getEdgeType(align, 'center'),
93
+ fromEdge: sourceLayout.x + scrollX + (offsets.horizontal ?? 0) - targetDimensions.width / 2,
94
+ sourceSize: sourceLayout.width
95
+ });
96
+ if (align.right) positioning.right = getPosition({
97
+ edge: getEdgeType(align, 'right'),
98
+ fromEdge: windowDimensions.width - (sourceLayout.x + scrollX + sourceLayout.width - (offsets.horizontal ?? 0)),
99
+ sourceSize: sourceLayout.width
100
+ });
101
+
102
+ if (!(align.left && align.right)) {
103
+ // Check if the position and/or width need adjusting to fit on the screen
104
+ const side = align.right ? 'right' : 'left';
105
+ const adjusted = adjustHorizontalToFit(positioning[side], windowDimensions.width, sourceLayout.width);
106
+ if (typeof adjusted.width === 'number') positioning.width = adjusted.width;
107
+
108
+ if (typeof adjusted.offset === 'number') {
109
+ positioning[side] = adjusted.offset;
110
+ }
111
+ }
112
+
113
+ return positioning;
114
+ }
115
+ /**
116
+ * Positions an element in a modal or portal so that it appears tooltip-like below the
117
+ * target element.
118
+ *
119
+ * @TODO - add support for positioning other than 'below' like UDS's tooltip (this is not
120
+ * a small task because UDS's tooltip logic only really works for short text - it might be
121
+ * better to use a third-party library).
122
+ */
123
+
124
+
125
+ const useOverlaidPosition = _ref3 => {
126
+ let {
127
+ isShown = false,
128
+ offsets,
129
+ // By default, align the overlaid target's `top` to the bottom of the source, and center horizontally.
130
+ align = {
131
+ center: 'center',
132
+ top: 'bottom'
133
+ }
134
+ } = _ref3;
135
+ // Element in main document flow that the targetRef element is positioned around
136
+ const sourceRef = useRef(null);
137
+ const [sourceLayout, setSourceLayout] = useState(null); // Element in a modal or portal overlay positioned to appear adjacent to sourceRef
138
+
139
+ const targetRef = useRef(null);
140
+ const [targetDimensions, setTargetDimensions] = useState(null);
141
+ const [windowDimensions, setWindowDimensions] = useState(null);
142
+ const onTargetLayout = useCallback(_ref4 => {
143
+ let {
144
+ nativeEvent: {
145
+ layout: {
146
+ width,
147
+ height
148
+ }
149
+ }
150
+ } = _ref4;
151
+ // NOTE: UDS's Tooltip logic injects some additional width to allow for antialiasing etc of text,
152
+ // avoiding adding unnecessary line breaks to text that is slightly wider than it thinks it is.
153
+ // That is probably something specific to text tooltips that doesn't belong in a generic hook.
154
+ setTargetDimensions(previousDimensions => {
155
+ // Re-render on first non-zero width / height: avoid infinite loops on changes, or mispositioning
156
+ // if user scrolls while a slidedown animation is changing the height and recalculating position.
157
+ if (!previousDimensions && width && height) {
158
+ return {
159
+ width,
160
+ height
161
+ };
162
+ }
163
+
164
+ return previousDimensions;
165
+ });
166
+ }, []);
167
+ const readyToShow = Boolean(isShown && sourceRef.current);
168
+ useEffect(() => {
169
+ const handleDimensionsChange = _ref5 => {
170
+ var _sourceRef$current;
171
+
172
+ let {
173
+ window
174
+ } = _ref5;
175
+ (_sourceRef$current = sourceRef.current) === null || _sourceRef$current === void 0 ? void 0 : _sourceRef$current.measureInWindow((x, y, width, height) => {
176
+ // Could add a debouncer here if there's too many rerenders during gradual resizes
177
+ setWindowDimensions(window);
178
+ setSourceLayout({
179
+ x,
180
+ y,
181
+ width,
182
+ height
183
+ });
184
+ });
185
+ };
186
+
187
+ let subscription;
188
+
189
+ const unsubscribe = () => {
190
+ var _subscription;
191
+
192
+ if (typeof ((_subscription = subscription) === null || _subscription === void 0 ? void 0 : _subscription.remove) === 'function') {
193
+ // React Native >=0.65.0
194
+ subscription.remove();
195
+ } else if (typeof Dimensions.removeEventListener === 'function') {
196
+ // React Native <0.65.0
197
+ Dimensions.removeEventListener('change', handleDimensionsChange);
198
+ }
199
+
200
+ setSourceLayout(null);
201
+ setTargetDimensions(null);
202
+ };
203
+
204
+ if (readyToShow) {
205
+ subscription = Dimensions.addEventListener('change', handleDimensionsChange);
206
+ handleDimensionsChange({
207
+ window: Dimensions.get('window')
208
+ });
209
+ } else {
210
+ unsubscribe();
211
+ }
212
+
213
+ return unsubscribe;
214
+ }, [readyToShow]);
215
+ const isReady = Boolean(isShown && sourceLayout && windowDimensions && targetDimensions);
216
+ const overlaidPosition = isReady ? getOverlaidPosition({
217
+ sourceLayout,
218
+ targetDimensions,
219
+ windowDimensions,
220
+ offsets,
221
+ align
222
+ }) : {};
223
+ return {
224
+ overlaidPosition,
225
+ sourceRef,
226
+ targetRef,
227
+ onTargetLayout,
228
+ isReady
229
+ };
230
+ };
231
+
232
+ export default useOverlaidPosition;