@telus-uds/components-base 1.8.5 → 1.11.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.
- package/CHANGELOG.md +47 -2
- package/component-docs.json +666 -27
- package/lib/Card/Card.js +9 -4
- package/lib/Carousel/Carousel.js +672 -0
- package/lib/Carousel/CarouselContext.js +59 -0
- package/lib/Carousel/CarouselItem/CarouselItem.js +92 -0
- package/lib/Carousel/CarouselItem/index.js +13 -0
- package/lib/Carousel/dictionary.js +23 -0
- package/lib/Carousel/index.js +32 -0
- package/lib/ExpandCollapse/Panel.js +10 -1
- package/lib/InputSupports/InputSupports.js +10 -3
- package/lib/InputSupports/useInputSupports.js +3 -2
- package/lib/Modal/Modal.js +4 -0
- package/lib/Skeleton/Skeleton.js +1 -0
- package/lib/StepTracker/StepTracker.js +15 -12
- package/lib/TextInput/TextInput.js +3 -12
- package/lib/TextInput/TextInputBase.js +9 -0
- package/lib/TextInput/propTypes.js +3 -8
- package/lib/index.js +23 -0
- package/lib/utils/props/clickProps.js +2 -2
- package/lib/utils/props/handlerProps.js +77 -31
- package/lib/utils/props/textInputProps.js +8 -1
- package/lib/utils/useScrollBlocking.js +66 -0
- package/lib/utils/useScrollBlocking.native.js +11 -0
- package/lib-module/Card/Card.js +5 -4
- package/lib-module/Carousel/Carousel.js +617 -0
- package/lib-module/Carousel/CarouselContext.js +43 -0
- package/lib-module/Carousel/CarouselItem/CarouselItem.js +75 -0
- package/lib-module/Carousel/CarouselItem/index.js +2 -0
- package/lib-module/Carousel/dictionary.js +16 -0
- package/lib-module/Carousel/index.js +2 -0
- package/lib-module/ExpandCollapse/Panel.js +9 -1
- package/lib-module/InputSupports/InputSupports.js +10 -3
- package/lib-module/InputSupports/useInputSupports.js +3 -2
- package/lib-module/Modal/Modal.js +3 -0
- package/lib-module/Skeleton/Skeleton.js +1 -0
- package/lib-module/StepTracker/StepTracker.js +14 -12
- package/lib-module/TextInput/TextInput.js +3 -9
- package/lib-module/TextInput/TextInputBase.js +10 -1
- package/lib-module/TextInput/propTypes.js +4 -8
- package/lib-module/index.js +2 -0
- package/lib-module/utils/props/clickProps.js +2 -2
- package/lib-module/utils/props/handlerProps.js +78 -31
- package/lib-module/utils/props/textInputProps.js +8 -1
- package/lib-module/utils/useScrollBlocking.js +58 -0
- package/lib-module/utils/useScrollBlocking.native.js +2 -0
- package/package.json +3 -3
- package/src/Card/Card.jsx +6 -4
- package/src/Carousel/Carousel.jsx +649 -0
- package/src/Carousel/CarouselContext.jsx +30 -0
- package/src/Carousel/CarouselItem/CarouselItem.jsx +66 -0
- package/src/Carousel/CarouselItem/index.js +3 -0
- package/src/Carousel/dictionary.js +16 -0
- package/src/Carousel/index.js +2 -0
- package/src/ExpandCollapse/Panel.jsx +8 -1
- package/src/InputSupports/InputSupports.jsx +18 -3
- package/src/InputSupports/useInputSupports.js +2 -2
- package/src/Modal/Modal.jsx +3 -1
- package/src/Skeleton/Skeleton.jsx +1 -0
- package/src/StepTracker/StepTracker.jsx +21 -8
- package/src/TextInput/TextInput.jsx +2 -9
- package/src/TextInput/TextInputBase.jsx +11 -1
- package/src/TextInput/propTypes.js +3 -7
- package/src/index.js +2 -0
- package/src/utils/props/clickProps.js +2 -2
- package/src/utils/props/handlerProps.js +64 -16
- package/src/utils/props/textInputProps.js +7 -1
- package/src/utils/useScrollBlocking.js +57 -0
- package/src/utils/useScrollBlocking.native.js +2 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import View from "react-native-web/dist/exports/View";
|
|
4
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
5
|
+
import { layoutTags, getA11yPropsFromHtmlTag, selectSystemProps, a11yProps, viewProps } from '../../utils';
|
|
6
|
+
import { useCarousel } from '../CarouselContext';
|
|
7
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
9
|
+
/**
|
|
10
|
+
* `Carousel.Item` is used to wrap the content of an individual slide and is suppsoed to be the
|
|
11
|
+
* only top-level component passed to the `Carousel`
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const CarouselItem = _ref => {
|
|
15
|
+
let {
|
|
16
|
+
children,
|
|
17
|
+
elementIndex,
|
|
18
|
+
tag = 'li',
|
|
19
|
+
hidden,
|
|
20
|
+
...rest
|
|
21
|
+
} = _ref;
|
|
22
|
+
const {
|
|
23
|
+
width,
|
|
24
|
+
activeIndex
|
|
25
|
+
} = useCarousel();
|
|
26
|
+
const selectedProps = selectProps({ ...rest,
|
|
27
|
+
...getA11yPropsFromHtmlTag(tag, rest.accessibilityRole)
|
|
28
|
+
});
|
|
29
|
+
const focusabilityProps = activeIndex === elementIndex ? {} : a11yProps.nonFocusableProps;
|
|
30
|
+
const style = {
|
|
31
|
+
width
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
if (hidden && Platform.OS === 'web') {
|
|
35
|
+
// On web, visibility: hidden makes all children non-focusable. It doesn't exist on native.
|
|
36
|
+
style.visibility = 'hidden';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return /*#__PURE__*/_jsx(View, {
|
|
40
|
+
style: style,
|
|
41
|
+
...selectedProps,
|
|
42
|
+
...focusabilityProps,
|
|
43
|
+
children: children
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
CarouselItem.propTypes = { ...selectedSystemPropTypes,
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Index of the current slide
|
|
51
|
+
* Don't pass this prop when using `Carousel.Item` as it is already being passed by `Carousel` top-level component
|
|
52
|
+
*/
|
|
53
|
+
elementIndex: PropTypes.number,
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Provide custom accessibilityLabelledBy for Carousel slide
|
|
57
|
+
*/
|
|
58
|
+
accessibilityLabelledBy: PropTypes.string,
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Content of the slide
|
|
62
|
+
*/
|
|
63
|
+
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Sets the HTML tag of the outer container. By default `'li'` so that assistive technology sees
|
|
67
|
+
* the Carousel as a list of items.
|
|
68
|
+
*
|
|
69
|
+
* Carousel's innermost container defaults to `'ul'` which can be overridden. If the tag of either
|
|
70
|
+
* `Carousel` or `Carousel.Item` is overriden, the other should be too, to avoid producing invalid HTML.
|
|
71
|
+
*/
|
|
72
|
+
tag: PropTypes.oneOf(layoutTags)
|
|
73
|
+
};
|
|
74
|
+
CarouselItem.displayName = 'Carousel.Item';
|
|
75
|
+
export default CarouselItem;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// 'stepLabel' and 'stepTrackerLabel' are passed down to StepTracker
|
|
2
|
+
export default {
|
|
3
|
+
en: {
|
|
4
|
+
carouselLabel: '%{stepCount} items',
|
|
5
|
+
iconButtonLabel: 'Show %{itemLabel} %{targetStep} of %{stepCount}',
|
|
6
|
+
stepLabel: '%{itemLabel} %{stepNumber}',
|
|
7
|
+
stepTrackerLabel: '%{itemLabel} %{stepNumber} of %{stepCount}'
|
|
8
|
+
},
|
|
9
|
+
fr: {
|
|
10
|
+
// TODO: French translations here
|
|
11
|
+
carouselLabel: '(fr) %{stepCount} items',
|
|
12
|
+
iconButtonLabel: '(fr) Show %{itemLabel} %{targetStep} of %{stepCount}',
|
|
13
|
+
stepLabel: '(fr) %{itemLabel} %{stepNumber}',
|
|
14
|
+
stepTrackerLabel: '(fr) %{itemLabel} %{stepNumber} of %{stepCount}'
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -3,6 +3,7 @@ import Animated from "react-native-web/dist/exports/Animated";
|
|
|
3
3
|
import Platform from "react-native-web/dist/exports/Platform";
|
|
4
4
|
import View from "react-native-web/dist/exports/View";
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
|
+
import ABBPropTypes from 'airbnb-prop-types';
|
|
6
7
|
import ExpandCollapseControl from './Control';
|
|
7
8
|
import { useThemeTokens } from '../ThemeProvider';
|
|
8
9
|
import { a11yProps, getTokensPropType, selectSystemProps, useVerticalExpandAnimation, variantProp, viewProps } from '../utils';
|
|
@@ -49,6 +50,7 @@ const ExpandCollapsePanel = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
49
50
|
children,
|
|
50
51
|
tokens,
|
|
51
52
|
variant,
|
|
53
|
+
controlRef,
|
|
52
54
|
...rest
|
|
53
55
|
} = _ref2;
|
|
54
56
|
const [containerHeight, setContainerHeight] = useState(null);
|
|
@@ -91,6 +93,7 @@ const ExpandCollapsePanel = /*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
|
91
93
|
isExpanded: isExpanded,
|
|
92
94
|
tokens: controlTokens,
|
|
93
95
|
onPress: handleControlPress,
|
|
96
|
+
ref: controlRef,
|
|
94
97
|
children: control
|
|
95
98
|
}), /*#__PURE__*/_jsx(Animated.View, {
|
|
96
99
|
ref: animatedRef,
|
|
@@ -146,6 +149,11 @@ ExpandCollapsePanel.propTypes = { ...selectedSystemPropTypes,
|
|
|
146
149
|
/**
|
|
147
150
|
* Optional theme token overrides that may be passed to the ExpandCollapseControl element.
|
|
148
151
|
*/
|
|
149
|
-
controlTokens: getTokensPropType('ExpandCollapseControl')
|
|
152
|
+
controlTokens: getTokensPropType('ExpandCollapseControl'),
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* An optional ref to be attached to the control
|
|
156
|
+
*/
|
|
157
|
+
controlRef: ABBPropTypes.ref()
|
|
150
158
|
};
|
|
151
159
|
export default ExpandCollapsePanel;
|
|
@@ -16,7 +16,8 @@ const InputSupports = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
16
16
|
hintPosition = 'inline',
|
|
17
17
|
feedback,
|
|
18
18
|
tooltip,
|
|
19
|
-
validation
|
|
19
|
+
validation,
|
|
20
|
+
nativeID
|
|
20
21
|
} = _ref;
|
|
21
22
|
const {
|
|
22
23
|
space
|
|
@@ -30,7 +31,8 @@ const InputSupports = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
30
31
|
feedback,
|
|
31
32
|
hint,
|
|
32
33
|
label,
|
|
33
|
-
validation
|
|
34
|
+
validation,
|
|
35
|
+
nativeID
|
|
34
36
|
});
|
|
35
37
|
return /*#__PURE__*/_jsxs(StackView, {
|
|
36
38
|
space: space,
|
|
@@ -91,6 +93,11 @@ InputSupports.propTypes = {
|
|
|
91
93
|
/**
|
|
92
94
|
* Use to visually mark an input as valid or invalid.
|
|
93
95
|
*/
|
|
94
|
-
validation: PropTypes.oneOf(['error', 'success'])
|
|
96
|
+
validation: PropTypes.oneOf(['error', 'success']),
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* ID for DOM element on web
|
|
100
|
+
*/
|
|
101
|
+
nativeID: PropTypes.string
|
|
95
102
|
};
|
|
96
103
|
export default InputSupports;
|
|
@@ -7,7 +7,8 @@ const useInputSupports = _ref => {
|
|
|
7
7
|
label,
|
|
8
8
|
feedback,
|
|
9
9
|
validation,
|
|
10
|
-
hint
|
|
10
|
+
hint,
|
|
11
|
+
nativeID
|
|
11
12
|
} = _ref;
|
|
12
13
|
const hasValidationError = validation === 'error';
|
|
13
14
|
const inputId = useUniqueId('input');
|
|
@@ -22,7 +23,7 @@ const useInputSupports = _ref => {
|
|
|
22
23
|
accessibilityInvalid: hasValidationError
|
|
23
24
|
};
|
|
24
25
|
return {
|
|
25
|
-
inputId,
|
|
26
|
+
inputId: nativeID || inputId,
|
|
26
27
|
hintId,
|
|
27
28
|
feedbackId,
|
|
28
29
|
a11yProps
|
|
@@ -10,6 +10,7 @@ import { a11yProps, copyPropTypes, getTokensPropType, selectSystemProps, useCopy
|
|
|
10
10
|
import { useViewport } from '../ViewportProvider';
|
|
11
11
|
import IconButton from '../IconButton';
|
|
12
12
|
import dictionary from './dictionary';
|
|
13
|
+
import useScrollBlocking from '../utils/useScrollBlocking';
|
|
13
14
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
15
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
15
16
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
|
|
@@ -110,6 +111,7 @@ const Modal = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
110
111
|
viewport,
|
|
111
112
|
maxWidth
|
|
112
113
|
});
|
|
114
|
+
const modalRef = useScrollBlocking(isOpen);
|
|
113
115
|
const {
|
|
114
116
|
closeIcon: CloseIconComponent
|
|
115
117
|
} = themeTokens;
|
|
@@ -140,6 +142,7 @@ const Modal = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
140
142
|
...selectProps(rest),
|
|
141
143
|
children: /*#__PURE__*/_jsxs(View, {
|
|
142
144
|
style: [staticStyles.positioningContainer],
|
|
145
|
+
ref: modalRef,
|
|
143
146
|
children: [/*#__PURE__*/_jsx(View, {
|
|
144
147
|
style: [staticStyles.sizingContainer, selectContainerStyles(themeTokens)],
|
|
145
148
|
pointerEvents: "box-none" // don't capture backdrop press events
|
|
@@ -109,7 +109,10 @@ const StepTracker = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
109
109
|
dictionary,
|
|
110
110
|
copy
|
|
111
111
|
});
|
|
112
|
-
const stepTrackerLabel = getCopy('stepTrackerLabel').replace('%{stepNumber}', current < steps.length ? current + 1 : steps.length).replace('%{stepCount}', steps.length).replace('%{stepLabel}', current < steps.length ? steps[current] : steps[steps.length - 1]);
|
|
112
|
+
const stepTrackerLabel = showStepTrackerLabel ? getCopy('stepTrackerLabel').replace('%{stepNumber}', current < steps.length ? current + 1 : steps.length).replace('%{stepCount}', steps.length).replace('%{stepLabel}', current < steps.length ? steps[current] : steps[steps.length - 1]) : '';
|
|
113
|
+
|
|
114
|
+
const getStepLabel = index => themeTokens.showStepLabel ? getCopy('stepLabel').replace('%{stepNumber}', index + 1) : '';
|
|
115
|
+
|
|
113
116
|
if (!steps.length) return null;
|
|
114
117
|
const selectedProps = selectProps({
|
|
115
118
|
accessibilityLabel: stepTrackerLabel,
|
|
@@ -135,7 +138,7 @@ const StepTracker = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
135
138
|
return /*#__PURE__*/_jsx(Step, {
|
|
136
139
|
status: current,
|
|
137
140
|
label: label,
|
|
138
|
-
name:
|
|
141
|
+
name: getStepLabel(index),
|
|
139
142
|
stepIndex: index,
|
|
140
143
|
stepCount: steps.length,
|
|
141
144
|
tokens: themeTokens
|
|
@@ -151,19 +154,18 @@ const StepTracker = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
151
154
|
})
|
|
152
155
|
});
|
|
153
156
|
});
|
|
154
|
-
StepTracker.displayName = 'StepTracker';
|
|
157
|
+
StepTracker.displayName = 'StepTracker'; // If a language dictionary entry is provided, it must contain every key
|
|
158
|
+
|
|
159
|
+
const dictionaryContentShape = PropTypes.shape({
|
|
160
|
+
stepLabel: PropTypes.string.isRequired,
|
|
161
|
+
stepTrackerLabel: PropTypes.string.isRequired
|
|
162
|
+
});
|
|
155
163
|
StepTracker.propTypes = { ...selectedSystemPropTypes,
|
|
156
164
|
current: PropTypes.number,
|
|
157
|
-
copy: PropTypes.oneOf(['en', 'fr']),
|
|
165
|
+
copy: PropTypes.oneOfType([PropTypes.oneOf(['en', 'fr']), dictionaryContentShape]),
|
|
158
166
|
dictionary: PropTypes.shape({
|
|
159
|
-
en:
|
|
160
|
-
|
|
161
|
-
stepTrackerLabel: PropTypes.string
|
|
162
|
-
}),
|
|
163
|
-
fr: PropTypes.shape({
|
|
164
|
-
stepLabel: PropTypes.string,
|
|
165
|
-
stepTrackerLabel: PropTypes.string
|
|
166
|
-
})
|
|
167
|
+
en: dictionaryContentShape,
|
|
168
|
+
fr: dictionaryContentShape
|
|
167
169
|
}),
|
|
168
170
|
steps: PropTypes.arrayOf(PropTypes.string),
|
|
169
171
|
tokens: getTokensPropType('StepTracker'),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
|
-
import Platform from "react-native-web/dist/exports/Platform";
|
|
3
2
|
import { a11yProps, focusHandlerProps, getTokensPropType, inputSupportsProps, selectSystemProps, textInputHandlerProps, textInputProps, variantProp, viewProps } from '../utils';
|
|
4
3
|
import InputSupports from '../InputSupports';
|
|
5
4
|
import TextInputBase from './TextInputBase';
|
|
@@ -29,15 +28,8 @@ const TextInput = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
29
28
|
let {
|
|
30
29
|
tokens,
|
|
31
30
|
variant = {},
|
|
32
|
-
pattern,
|
|
33
31
|
...rest
|
|
34
32
|
} = _ref;
|
|
35
|
-
React.useEffect(() => {
|
|
36
|
-
if (Platform.OS === 'web' && pattern && ref.current) {
|
|
37
|
-
// eslint-disable-next-line no-param-reassign
|
|
38
|
-
ref.current.pattern = pattern;
|
|
39
|
-
}
|
|
40
|
-
}, [ref, pattern]);
|
|
41
33
|
const {
|
|
42
34
|
supportsProps,
|
|
43
35
|
...selectedProps
|
|
@@ -48,7 +40,9 @@ const TextInput = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
48
40
|
validation: supportsProps.validation
|
|
49
41
|
}
|
|
50
42
|
};
|
|
51
|
-
return /*#__PURE__*/_jsx(InputSupports, {
|
|
43
|
+
return /*#__PURE__*/_jsx(InputSupports, {
|
|
44
|
+
nativeID: selectedProps.nativeID,
|
|
45
|
+
...supportsProps,
|
|
52
46
|
children: _ref2 => {
|
|
53
47
|
let {
|
|
54
48
|
inputId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef, useState } from 'react';
|
|
1
|
+
import React, { forwardRef, useEffect, useState } from 'react';
|
|
2
2
|
import Platform from "react-native-web/dist/exports/Platform";
|
|
3
3
|
import StyleSheet from "react-native-web/dist/exports/StyleSheet";
|
|
4
4
|
import NativeTextInput from "react-native-web/dist/exports/TextInput";
|
|
@@ -133,6 +133,7 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
133
133
|
onBlur,
|
|
134
134
|
onMouseOver,
|
|
135
135
|
onMouseOut,
|
|
136
|
+
pattern,
|
|
136
137
|
tokens,
|
|
137
138
|
variant = {},
|
|
138
139
|
...rest
|
|
@@ -171,6 +172,14 @@ const TextInputBase = /*#__PURE__*/forwardRef((_ref5, ref) => {
|
|
|
171
172
|
onChange,
|
|
172
173
|
readOnly
|
|
173
174
|
});
|
|
175
|
+
const element = ref === null || ref === void 0 ? void 0 : ref.current;
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
if (Platform.OS === 'web' && pattern && element) {
|
|
178
|
+
// React Native Web doesn't support `pattern`, so we have to attach it via a ref,
|
|
179
|
+
// which a `pattern` user must provide anyway to call .checkValidity() on the element.
|
|
180
|
+
element.pattern = pattern;
|
|
181
|
+
}
|
|
182
|
+
}, [element, pattern]);
|
|
174
183
|
|
|
175
184
|
const handleChangeText = event => {
|
|
176
185
|
var _event$nativeEvent, _event$target;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import PropTypes from 'prop-types';
|
|
2
|
-
|
|
1
|
+
import PropTypes from 'prop-types'; // These are prop types specific to UDS TextInput; see also ../utils/props/textInputProps
|
|
2
|
+
// for generic React Native props and HTML input attrs that are passed through.
|
|
3
|
+
|
|
3
4
|
const textInputPropTypes = {
|
|
4
5
|
/**
|
|
5
6
|
* If the input's state is to be controlled by a parent component, use this prop
|
|
@@ -27,11 +28,6 @@ const textInputPropTypes = {
|
|
|
27
28
|
* Use to react upon input's value changes. Required when the `value` prop is set.
|
|
28
29
|
* Will receive the input's value as an argument.
|
|
29
30
|
*/
|
|
30
|
-
onChange: PropTypes.func
|
|
31
|
-
...Platform.select({
|
|
32
|
-
web: {
|
|
33
|
-
pattern: PropTypes.string
|
|
34
|
-
}
|
|
35
|
-
})
|
|
31
|
+
onChange: PropTypes.func
|
|
36
32
|
};
|
|
37
33
|
export default textInputPropTypes;
|
package/lib-module/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { default as ActivityIndicator } from './ActivityIndicator';
|
|
|
3
3
|
export { default as Box } from './Box';
|
|
4
4
|
export * from './Button';
|
|
5
5
|
export { default as Card, PressableCardBase } from './Card';
|
|
6
|
+
export * from './Carousel';
|
|
6
7
|
export { default as Checkbox } from './Checkbox';
|
|
7
8
|
export * from './Checkbox';
|
|
8
9
|
export { default as Divider } from './Divider';
|
|
@@ -16,6 +17,7 @@ export { default as Icon } from './Icon';
|
|
|
16
17
|
export * from './Icon';
|
|
17
18
|
export { default as IconButton } from './IconButton';
|
|
18
19
|
export { default as InputLabel } from './InputLabel';
|
|
20
|
+
export { default as InputSupports } from './InputSupports';
|
|
19
21
|
export * from './Link';
|
|
20
22
|
export { default as List, ListItem, ListBase } from './List';
|
|
21
23
|
export { default as Modal } from './Modal';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
|
-
|
|
2
|
+
import Platform from "react-native-web/dist/exports/Platform";
|
|
3
|
+
import getPropSelector from './getPropSelector';
|
|
4
|
+
const focusHandlerProps = {
|
|
3
5
|
types: {
|
|
4
6
|
/**
|
|
5
7
|
* onBlur handler
|
|
@@ -10,19 +12,10 @@ export const focusHandlerProps = {
|
|
|
10
12
|
* onFocus handler
|
|
11
13
|
*/
|
|
12
14
|
onFocus: PropTypes.func
|
|
13
|
-
},
|
|
14
|
-
select: _ref => {
|
|
15
|
-
let {
|
|
16
|
-
onBlur,
|
|
17
|
-
onFocus
|
|
18
|
-
} = _ref;
|
|
19
|
-
return {
|
|
20
|
-
onBlur,
|
|
21
|
-
onFocus
|
|
22
|
-
};
|
|
23
15
|
}
|
|
24
16
|
};
|
|
25
|
-
|
|
17
|
+
focusHandlerProps.select = getPropSelector(focusHandlerProps.types);
|
|
18
|
+
const textInputHandlerProps = {
|
|
26
19
|
types: {
|
|
27
20
|
/**
|
|
28
21
|
* onChange handler
|
|
@@ -42,24 +35,78 @@ export const textInputHandlerProps = {
|
|
|
42
35
|
/**
|
|
43
36
|
* onSubmitEditing handler
|
|
44
37
|
*/
|
|
45
|
-
onSubmitEditing: PropTypes.func
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
38
|
+
onSubmitEditing: PropTypes.func,
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* onContentSizeChange handler
|
|
42
|
+
*/
|
|
43
|
+
onContentSizeChange: PropTypes.func,
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* onEndEditing handler
|
|
47
|
+
*/
|
|
48
|
+
onEndEditing: PropTypes.func,
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* onScroll handler
|
|
52
|
+
*/
|
|
53
|
+
onScroll: PropTypes.func,
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* onSelectionChange handler
|
|
57
|
+
*/
|
|
58
|
+
onSelectionChange: PropTypes.func,
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* onKeyPress handler
|
|
62
|
+
*/
|
|
63
|
+
onKeyPress: PropTypes.func,
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* onKeyUp handler (only supported on Web)
|
|
67
|
+
*/
|
|
68
|
+
onKeyUp: PropTypes.func,
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* onKeyDown handler (only supported on Web)
|
|
72
|
+
*/
|
|
73
|
+
onKeyDown: PropTypes.func
|
|
60
74
|
}
|
|
61
75
|
};
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
const selectTextInputHandlers = getPropSelector(textInputHandlerProps.types);
|
|
77
|
+
|
|
78
|
+
textInputHandlerProps.select = props => {
|
|
79
|
+
// Support for onKeyPress/onKeyUp/onKeyDown is inconsistent between React Native and React Native Web
|
|
80
|
+
const {
|
|
81
|
+
onKeyPress,
|
|
82
|
+
onKeyUp,
|
|
83
|
+
onKeyDown,
|
|
84
|
+
...resolvedProps
|
|
85
|
+
} = selectTextInputHandlers(props);
|
|
86
|
+
|
|
87
|
+
if (onKeyPress || onKeyUp || onKeyDown) {
|
|
88
|
+
if (Platform.OS !== 'web') {
|
|
89
|
+
// React Native only supports onKeyPress. Call any key handlers supplied in expected order.
|
|
90
|
+
resolvedProps.onKeyPress = event => {
|
|
91
|
+
if (typeof onKeyDown === 'function') onKeyDown(event);
|
|
92
|
+
if (typeof onKeyPress === 'function') onKeyPress(event);
|
|
93
|
+
if (typeof onKeyUp === 'function') onKeyUp(event);
|
|
94
|
+
};
|
|
95
|
+
} else {
|
|
96
|
+
// React Native Web supports onKeyUp the normal way.
|
|
97
|
+
if (onKeyUp) resolvedProps.onKeyUp = onKeyUp; // React Native Web doesn't support the `onKeyDown` prop name, but maps a supplied onKeyPress handler
|
|
98
|
+
// to the onKeyDown event and calls it with a keydown event. Make React Native Web call either or both.
|
|
99
|
+
|
|
100
|
+
if (onKeyPress || onKeyDown) {
|
|
101
|
+
resolvedProps.onKeyPress = event => {
|
|
102
|
+
if (typeof onKeyDown === 'function') onKeyDown(event);
|
|
103
|
+
if (typeof onKeyPress === 'function') onKeyPress(event);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return resolvedProps;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export { focusHandlerProps, textInputHandlerProps };
|
|
@@ -135,7 +135,14 @@ const crossPlatform = { ...textProps,
|
|
|
135
135
|
const webOnly = {
|
|
136
136
|
disabled: PropTypes.bool,
|
|
137
137
|
dir: PropTypes.oneOf(['auto', 'ltr', 'rtl']),
|
|
138
|
-
lang: PropTypes.string
|
|
138
|
+
lang: PropTypes.string,
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Sets the HTML input `pattern` attr. Not supported by React Native Web, but is supported by UDS.
|
|
142
|
+
* Must also pass in a ref and check validity by calling the HTML element's checkValidity method:
|
|
143
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/checkValidity
|
|
144
|
+
*/
|
|
145
|
+
pattern: PropTypes.string
|
|
139
146
|
};
|
|
140
147
|
/**
|
|
141
148
|
* These props are supported in React Native but not React Native Web.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
const addScrollBlocking = (preventScrolling, stopPropagation, ref) => {
|
|
4
|
+
var _ref$current;
|
|
5
|
+
|
|
6
|
+
document.body.addEventListener('touchmove', preventScrolling, {
|
|
7
|
+
passive: false
|
|
8
|
+
});
|
|
9
|
+
(_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.addEventListener('touchmove', stopPropagation);
|
|
10
|
+
document.body.style.overflow = 'hidden';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const removeScrollBlocking = (preventScrolling, stopPropagation, ref) => {
|
|
14
|
+
var _ref$current2;
|
|
15
|
+
|
|
16
|
+
document.body.removeEventListener('touchmove', preventScrolling);
|
|
17
|
+
(_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.removeEventListener('touchmove', stopPropagation);
|
|
18
|
+
document.body.style.overflow = 'inherit';
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Disables scrolling when passed `true` or an array where all items are `true`.
|
|
22
|
+
*
|
|
23
|
+
* Returns an optional callback ref. Pass this to an element if it or its children
|
|
24
|
+
* should allow touch-based scrolling within that element's bounds.
|
|
25
|
+
*
|
|
26
|
+
* @param {boolean | boolean[]} conditionProps
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const useScrollBlocking = conditionProps => {
|
|
32
|
+
// useRef refs are null on first render and don't trigger a re-render when they get their
|
|
33
|
+
// element. Force re-run when ref mounts to ensure the stopPropagation listener is attached.
|
|
34
|
+
const ref = useRef();
|
|
35
|
+
const [refIsMounted, setRefIsMounted] = useState(false);
|
|
36
|
+
const callbackRef = useCallback(element => {
|
|
37
|
+
ref.current = element;
|
|
38
|
+
setRefIsMounted(Boolean(element));
|
|
39
|
+
}, []);
|
|
40
|
+
const conditionsMet = Array.isArray(conditionProps) ? conditionProps.every(condition => condition) : Boolean(conditionProps);
|
|
41
|
+
const preventScrolling = useCallback(event => event.preventDefault(), []);
|
|
42
|
+
const stopPropagation = useCallback(event => event.stopPropagation(), []);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const cleanup = () => removeScrollBlocking(preventScrolling, stopPropagation, ref);
|
|
45
|
+
|
|
46
|
+
if (conditionsMet) {
|
|
47
|
+
addScrollBlocking(preventScrolling, stopPropagation, ref);
|
|
48
|
+
} else {
|
|
49
|
+
cleanup();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return cleanup; // preventScrolling and stopPropagation are stable callbacks with no deps, so this
|
|
53
|
+
// will re-run when conditionsMet or refIsMounted flip between true and false.
|
|
54
|
+
}, [preventScrolling, conditionsMet, stopPropagation, refIsMounted]);
|
|
55
|
+
return callbackRef;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default useScrollBlocking;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telus-uds/components-base",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Base components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"base"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"react": "^17.0.2",
|
|
48
48
|
"react-dom": "^17.0.2",
|
|
49
49
|
"react-native": "*",
|
|
50
|
-
"react-native-web": "
|
|
50
|
+
"react-native-web": "~0.17.5"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@storybook/addon-a11y": "^6.5.6",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"airbnb-prop-types": "^2.16.0",
|
|
68
68
|
"@telus-uds/system-constants": "^1.0.4",
|
|
69
|
-
"@telus-uds/system-theme-tokens": "^2.0
|
|
69
|
+
"@telus-uds/system-theme-tokens": "^2.1.0",
|
|
70
70
|
"lodash.debounce": "^4.0.8",
|
|
71
71
|
"lodash.merge": "^4.6.2",
|
|
72
72
|
"prop-types": "^15.7.2",
|
package/src/Card/Card.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
|
|
4
4
|
import { useThemeTokens } from '../ThemeProvider'
|
|
@@ -57,16 +57,18 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
|
|
|
57
57
|
* you automatically make inaccessible its children, which may or may not be appropriate
|
|
58
58
|
* depending on what you are trying to achieve.
|
|
59
59
|
*/
|
|
60
|
-
const Card = ({ children, tokens, variant, dataSet, ...rest }) => {
|
|
60
|
+
const Card = forwardRef(({ children, tokens, variant, dataSet, ...rest }, ref) => {
|
|
61
61
|
const viewport = useViewport()
|
|
62
62
|
const themeTokens = useThemeTokens('Card', tokens, variant, { viewport })
|
|
63
63
|
|
|
64
64
|
return (
|
|
65
|
-
<CardBase tokens={themeTokens} dataSet={dataSet} {...selectProps(rest)}>
|
|
65
|
+
<CardBase ref={ref} tokens={themeTokens} dataSet={dataSet} {...selectProps(rest)}>
|
|
66
66
|
{children}
|
|
67
67
|
</CardBase>
|
|
68
68
|
)
|
|
69
|
-
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
Card.displayName = 'Card'
|
|
70
72
|
|
|
71
73
|
Card.propTypes = {
|
|
72
74
|
...selectedSystemPropTypes,
|