@telus-uds/components-base 1.3.1 → 1.6.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/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-lint.log +13 -0
- package/CHANGELOG.json +142 -1
- package/CHANGELOG.md +51 -2
- package/__tests__/FlexGrid/Row.test.jsx +100 -25
- package/__tests__/utils/containUniqueFields.test.js +25 -0
- package/component-docs.json +50 -15
- package/lib/Button/ButtonBase.js +1 -1
- package/lib/Button/ButtonGroup.js +20 -12
- package/lib/Card/PressableCardBase.js +1 -1
- package/lib/Checkbox/Checkbox.js +27 -16
- package/lib/Checkbox/CheckboxGroup.js +19 -5
- package/lib/ExpandCollapse/Panel.js +10 -10
- package/lib/FlexGrid/Col/Col.js +13 -3
- package/lib/FlexGrid/Row/Row.js +8 -2
- package/lib/HorizontalScroll/HorizontalScroll.js +0 -1
- package/lib/HorizontalScroll/HorizontalScrollButton.js +23 -49
- package/lib/InputLabel/InputLabel.js +27 -25
- package/lib/Link/LinkBase.js +19 -6
- package/lib/Modal/Modal.js +18 -18
- package/lib/Notification/Notification.js +5 -6
- package/lib/Radio/Radio.js +23 -12
- package/lib/Radio/RadioGroup.js +12 -3
- package/lib/RadioCard/RadioCard.js +1 -1
- package/lib/RadioCard/RadioCardGroup.js +11 -2
- package/lib/Select/Select.js +2 -3
- package/lib/Tags/Tags.js +23 -17
- package/lib/TextInput/TextArea.js +2 -2
- package/lib/TextInput/TextInput.js +12 -2
- package/lib/TextInput/TextInputBase.js +1 -1
- package/lib/TextInput/propTypes.js +8 -1
- package/lib/ToggleSwitch/ToggleSwitch.js +5 -2
- package/lib/ToggleSwitch/ToggleSwitchGroup.js +20 -12
- package/lib/utils/containUniqueFields.js +34 -0
- package/lib/utils/index.js +10 -1
- package/lib/utils/props/handlerProps.js +72 -0
- package/lib/utils/props/index.js +14 -0
- package/lib/utils/props/inputSupportsProps.js +3 -5
- package/lib-module/Button/ButtonBase.js +2 -2
- package/lib-module/Button/ButtonGroup.js +15 -6
- package/lib-module/Card/PressableCardBase.js +2 -2
- package/lib-module/Checkbox/Checkbox.js +28 -17
- package/lib-module/Checkbox/CheckboxGroup.js +20 -7
- package/lib-module/ExpandCollapse/Panel.js +10 -10
- package/lib-module/FlexGrid/Col/Col.js +13 -3
- package/lib-module/FlexGrid/Row/Row.js +8 -2
- package/lib-module/HorizontalScroll/HorizontalScroll.js +0 -1
- package/lib-module/HorizontalScroll/HorizontalScrollButton.js +24 -49
- package/lib-module/InputLabel/InputLabel.js +28 -25
- package/lib-module/Link/LinkBase.js +19 -6
- package/lib-module/Modal/Modal.js +19 -19
- package/lib-module/Notification/Notification.js +6 -6
- package/lib-module/Radio/Radio.js +24 -13
- package/lib-module/Radio/RadioGroup.js +13 -4
- package/lib-module/RadioCard/RadioCard.js +2 -2
- package/lib-module/RadioCard/RadioCardGroup.js +12 -3
- package/lib-module/Select/Select.js +2 -3
- package/lib-module/Tags/Tags.js +18 -11
- package/lib-module/TextInput/TextArea.js +3 -3
- package/lib-module/TextInput/TextInput.js +11 -3
- package/lib-module/TextInput/TextInputBase.js +2 -2
- package/lib-module/TextInput/propTypes.js +7 -1
- package/lib-module/ToggleSwitch/ToggleSwitch.js +6 -3
- package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +15 -6
- package/lib-module/utils/containUniqueFields.js +26 -0
- package/lib-module/utils/index.js +2 -1
- package/lib-module/utils/props/handlerProps.js +59 -0
- package/lib-module/utils/props/index.js +1 -0
- package/lib-module/utils/props/inputSupportsProps.js +3 -5
- package/package.json +5 -5
- package/src/Button/ButtonBase.jsx +8 -2
- package/src/Button/ButtonGroup.jsx +51 -34
- package/src/Card/PressableCardBase.jsx +6 -1
- package/src/Checkbox/Checkbox.jsx +35 -23
- package/src/Checkbox/CheckboxGroup.jsx +52 -22
- package/src/ExpandCollapse/Panel.jsx +9 -9
- package/src/FlexGrid/Col/Col.jsx +11 -2
- package/src/FlexGrid/Row/Row.jsx +8 -2
- package/src/HorizontalScroll/HorizontalScroll.jsx +1 -1
- package/src/HorizontalScroll/HorizontalScrollButton.jsx +21 -58
- package/src/InputLabel/InputLabel.jsx +36 -27
- package/src/Link/LinkBase.jsx +20 -4
- package/src/Modal/Modal.jsx +30 -26
- package/src/Notification/Notification.jsx +7 -4
- package/src/Radio/Radio.jsx +26 -14
- package/src/Radio/RadioGroup.jsx +39 -21
- package/src/RadioCard/RadioCard.jsx +6 -1
- package/src/RadioCard/RadioCardGroup.jsx +17 -1
- package/src/Select/Select.jsx +2 -2
- package/src/Tags/Tags.jsx +23 -9
- package/src/TextInput/TextArea.jsx +5 -1
- package/src/TextInput/TextInput.jsx +13 -3
- package/src/TextInput/TextInputBase.jsx +6 -1
- package/src/TextInput/propTypes.js +7 -1
- package/src/ToggleSwitch/ToggleSwitch.jsx +11 -2
- package/src/ToggleSwitch/ToggleSwitchGroup.jsx +19 -6
- package/src/utils/containUniqueFields.js +32 -0
- package/src/utils/index.js +1 -0
- package/src/utils/props/handlerProps.js +47 -0
- package/src/utils/props/index.js +1 -0
- package/src/utils/props/inputSupportsProps.js +3 -4
- package/stories/InputLabel/InputLabel.stories.jsx +25 -28
- package/stories/Modal/Modal.stories.jsx +25 -0
- package/stories/Search/Search.stories.jsx +4 -1
- package/stories/TextInput/TextInput.stories.jsx +40 -2
|
@@ -5,6 +5,8 @@ import { useViewport } from '../ViewportProvider'
|
|
|
5
5
|
import { useThemeTokens } from '../ThemeProvider'
|
|
6
6
|
import {
|
|
7
7
|
a11yProps,
|
|
8
|
+
containUniqueFields,
|
|
9
|
+
focusHandlerProps,
|
|
8
10
|
getTokensPropType,
|
|
9
11
|
selectSystemProps,
|
|
10
12
|
useInputValue,
|
|
@@ -16,6 +18,11 @@ import RadioCard from './RadioCard'
|
|
|
16
18
|
import Fieldset from '../Fieldset'
|
|
17
19
|
|
|
18
20
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
21
|
+
const [selectItemProps, selectedItemPropTypes] = selectSystemProps([
|
|
22
|
+
a11yProps,
|
|
23
|
+
focusHandlerProps,
|
|
24
|
+
viewProps
|
|
25
|
+
])
|
|
19
26
|
|
|
20
27
|
/**
|
|
21
28
|
* A group of Cards that behave as a radio button group. Use when users select a single choice from mutually
|
|
@@ -105,6 +112,12 @@ const RadioCardGroup = forwardRef(
|
|
|
105
112
|
// Needs 'radiogroup' role on direct parent of radios for MacOS Voiceover's numbering to work,
|
|
106
113
|
// and also needs 'radiogroup' role on fieldset for correct description on focusing the set.
|
|
107
114
|
// TODO: test this on more web screen readers.
|
|
115
|
+
|
|
116
|
+
const uniqueFields = ['id']
|
|
117
|
+
if (!containUniqueFields(items, uniqueFields)) {
|
|
118
|
+
throw new Error(`RadioCardGroup items must have unique ${uniqueFields.join(', ')}`)
|
|
119
|
+
}
|
|
120
|
+
|
|
108
121
|
return (
|
|
109
122
|
<Fieldset
|
|
110
123
|
ref={ref}
|
|
@@ -121,12 +134,13 @@ const RadioCardGroup = forwardRef(
|
|
|
121
134
|
>
|
|
122
135
|
{(props) => (
|
|
123
136
|
<StackContainer space={space} accessibilityRole="radiogroup">
|
|
124
|
-
{items.map(({ title, content, id, onChange: itemOnChange }, index) => {
|
|
137
|
+
{items.map(({ title, content, id, onChange: itemOnChange, ...itemRest }, index) => {
|
|
125
138
|
const cardId = id || `RadioCard[${index}]`
|
|
126
139
|
const handleChange = (newCheckedState, event) => {
|
|
127
140
|
if (typeof itemOnChange === 'function') itemOnChange(newCheckedState, event)
|
|
128
141
|
if (newCheckedState) setValue(cardId, event)
|
|
129
142
|
}
|
|
143
|
+
|
|
130
144
|
return (
|
|
131
145
|
<RadioCard
|
|
132
146
|
key={cardId}
|
|
@@ -139,6 +153,7 @@ const RadioCardGroup = forwardRef(
|
|
|
139
153
|
tokens={radioCardTokens}
|
|
140
154
|
variant={variant}
|
|
141
155
|
readOnly={readOnly}
|
|
156
|
+
{...selectItemProps(itemRest)}
|
|
142
157
|
{...props}
|
|
143
158
|
>
|
|
144
159
|
{content}
|
|
@@ -172,6 +187,7 @@ RadioCardGroup.propTypes = {
|
|
|
172
187
|
*/
|
|
173
188
|
items: PropTypes.arrayOf(
|
|
174
189
|
PropTypes.exact({
|
|
190
|
+
...selectedItemPropTypes,
|
|
175
191
|
title: PropTypes.string,
|
|
176
192
|
content: PropTypes.node,
|
|
177
193
|
id: PropTypes.string,
|
package/src/Select/Select.jsx
CHANGED
|
@@ -194,7 +194,7 @@ const Select = forwardRef(
|
|
|
194
194
|
const handleMouseOver = () => setIsHovered(true)
|
|
195
195
|
const handleMouseOut = () => setIsHovered(false)
|
|
196
196
|
|
|
197
|
-
const {
|
|
197
|
+
const { supportsProps, ...selectedProps } = selectProps(rest)
|
|
198
198
|
|
|
199
199
|
const themeTokens = useThemeTokens('Select', tokens, variant, {
|
|
200
200
|
focus: isFocused,
|
|
@@ -236,7 +236,7 @@ const Select = forwardRef(
|
|
|
236
236
|
selectValidationIconContainerStyles(themeTokens)
|
|
237
237
|
]}
|
|
238
238
|
>
|
|
239
|
-
<ValidationIconComponent
|
|
239
|
+
<ValidationIconComponent {...selectValidationIconTokens(themeTokens)} />
|
|
240
240
|
</View>
|
|
241
241
|
)}
|
|
242
242
|
{IconComponent &&
|
package/src/Tags/Tags.jsx
CHANGED
|
@@ -10,17 +10,25 @@ import { useViewport } from '../ViewportProvider'
|
|
|
10
10
|
import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider'
|
|
11
11
|
import {
|
|
12
12
|
a11yProps,
|
|
13
|
+
containUniqueFields,
|
|
14
|
+
focusHandlerProps,
|
|
13
15
|
getTokensPropType,
|
|
14
16
|
pressProps,
|
|
15
17
|
selectSystemProps,
|
|
16
18
|
selectTokens,
|
|
19
|
+
useMultipleInputValues,
|
|
17
20
|
variantProp,
|
|
18
21
|
viewProps
|
|
19
|
-
} from '../utils
|
|
20
|
-
import { useMultipleInputValues } from '../utils/input'
|
|
22
|
+
} from '../utils'
|
|
21
23
|
import { getPressHandlersWithArgs } from '../utils/pressability'
|
|
22
24
|
|
|
23
|
-
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps,
|
|
25
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
26
|
+
const [selectItemProps, selectedItemPropTypes] = selectSystemProps([
|
|
27
|
+
a11yProps,
|
|
28
|
+
focusHandlerProps,
|
|
29
|
+
pressProps,
|
|
30
|
+
viewProps
|
|
31
|
+
])
|
|
24
32
|
|
|
25
33
|
const selectIconTextTokens = ({
|
|
26
34
|
icon,
|
|
@@ -95,6 +103,11 @@ const Tags = forwardRef(
|
|
|
95
103
|
})
|
|
96
104
|
const itemA11yRole = 'checkbox'
|
|
97
105
|
|
|
106
|
+
const uniqueFields = ['id', 'label']
|
|
107
|
+
if (!containUniqueFields(items, uniqueFields)) {
|
|
108
|
+
throw new Error(`Tags items must have unique ${uniqueFields.join(', ')}`)
|
|
109
|
+
}
|
|
110
|
+
|
|
98
111
|
return (
|
|
99
112
|
<StackWrap
|
|
100
113
|
ref={ref}
|
|
@@ -103,22 +116,22 @@ const Tags = forwardRef(
|
|
|
103
116
|
direction={direction}
|
|
104
117
|
tokens={stackTokens}
|
|
105
118
|
>
|
|
106
|
-
{items.map(({ label, id = label,
|
|
119
|
+
{items.map(({ label, id = label, ref: itemRef, ...itemRest }, index) => {
|
|
107
120
|
const isSelected = currentValues.includes(id)
|
|
108
121
|
|
|
109
122
|
// Pass an object of relevant component state as first argument for any passed-in press handlers
|
|
110
123
|
const pressHandlers = getPressHandlersWithArgs(rest, [{ id, label, currentValues }])
|
|
111
124
|
|
|
112
125
|
const handlePress = (event) => {
|
|
113
|
-
if (pressHandlers.onPress) pressHandlers.onPress()
|
|
126
|
+
if (pressHandlers.onPress) pressHandlers.onPress(event)
|
|
114
127
|
toggleOneValue(id, event)
|
|
115
128
|
}
|
|
116
129
|
|
|
117
|
-
const
|
|
130
|
+
const itemProps = {
|
|
118
131
|
accessibilityState: { checked: isSelected },
|
|
119
132
|
accessibilityRole: itemA11yRole,
|
|
120
|
-
|
|
121
|
-
...
|
|
133
|
+
...a11yProps.getPositionInSet(items.length, index),
|
|
134
|
+
...selectItemProps(itemRest)
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
return (
|
|
@@ -130,7 +143,7 @@ const Tags = forwardRef(
|
|
|
130
143
|
tokens={getButtonTokens}
|
|
131
144
|
selected={isSelected}
|
|
132
145
|
inactive={inactive}
|
|
133
|
-
{...
|
|
146
|
+
{...itemProps}
|
|
134
147
|
>
|
|
135
148
|
{({ textStyles, ...buttonState }) => {
|
|
136
149
|
// TODO: once Icon/IconButton designs are stable, see if this sort of styling around
|
|
@@ -183,6 +196,7 @@ Tags.propTypes = {
|
|
|
183
196
|
*/
|
|
184
197
|
items: PropTypes.arrayOf(
|
|
185
198
|
PropTypes.shape({
|
|
199
|
+
...selectedItemPropTypes,
|
|
186
200
|
/**
|
|
187
201
|
* The text displayed to the user in the button, describing this option,
|
|
188
202
|
* passed to the button as its child.
|
|
@@ -3,9 +3,11 @@ import React, { forwardRef, useState } from 'react'
|
|
|
3
3
|
import { Platform } from 'react-native'
|
|
4
4
|
import {
|
|
5
5
|
a11yProps,
|
|
6
|
+
focusHandlerProps,
|
|
6
7
|
getTokensPropType,
|
|
7
8
|
inputSupportsProps,
|
|
8
9
|
selectSystemProps,
|
|
10
|
+
textInputHandlerProps,
|
|
9
11
|
variantProp,
|
|
10
12
|
viewProps
|
|
11
13
|
} from '../utils'
|
|
@@ -16,7 +18,9 @@ import textInputPropTypes from './propTypes'
|
|
|
16
18
|
|
|
17
19
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
18
20
|
a11yProps,
|
|
21
|
+
focusHandlerProps,
|
|
19
22
|
inputSupportsProps,
|
|
23
|
+
textInputHandlerProps,
|
|
20
24
|
viewProps
|
|
21
25
|
])
|
|
22
26
|
|
|
@@ -60,7 +64,7 @@ const TextArea = forwardRef(({ tokens, variant = {}, ...rest }, ref) => {
|
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
const {
|
|
67
|
+
const { supportsProps, ...selectedProps } = selectProps(rest)
|
|
64
68
|
|
|
65
69
|
const inputProps = {
|
|
66
70
|
...selectedProps,
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react'
|
|
2
|
-
|
|
2
|
+
import { Platform } from 'react-native'
|
|
3
3
|
import {
|
|
4
4
|
a11yProps,
|
|
5
|
+
focusHandlerProps,
|
|
5
6
|
getTokensPropType,
|
|
6
7
|
inputSupportsProps,
|
|
7
8
|
selectSystemProps,
|
|
9
|
+
textInputHandlerProps,
|
|
8
10
|
variantProp,
|
|
9
11
|
viewProps
|
|
10
12
|
} from '../utils'
|
|
@@ -14,7 +16,9 @@ import textInputPropTypes from './propTypes'
|
|
|
14
16
|
|
|
15
17
|
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
16
18
|
a11yProps,
|
|
19
|
+
focusHandlerProps,
|
|
17
20
|
inputSupportsProps,
|
|
21
|
+
textInputHandlerProps,
|
|
18
22
|
viewProps
|
|
19
23
|
])
|
|
20
24
|
|
|
@@ -36,8 +40,14 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
|
36
40
|
* supported props and <a href="https://reactnative.dev/docs/textinput" target="_blank">React Native Web documentation</a> for
|
|
37
41
|
* their implementation on the web.
|
|
38
42
|
*/
|
|
39
|
-
const TextInput = forwardRef(({ tokens, variant = {}, ...rest }, ref) => {
|
|
40
|
-
|
|
43
|
+
const TextInput = forwardRef(({ tokens, variant = {}, pattern, ...rest }, ref) => {
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
if (Platform.OS === 'web' && pattern && ref.current) {
|
|
46
|
+
// eslint-disable-next-line no-param-reassign
|
|
47
|
+
ref.current.pattern = pattern
|
|
48
|
+
}
|
|
49
|
+
}, [ref, pattern])
|
|
50
|
+
const { supportsProps, ...selectedProps } = selectProps(rest)
|
|
41
51
|
|
|
42
52
|
const inputProps = {
|
|
43
53
|
...selectedProps,
|
|
@@ -7,12 +7,17 @@ import {
|
|
|
7
7
|
a11yProps,
|
|
8
8
|
getTokensPropType,
|
|
9
9
|
selectSystemProps,
|
|
10
|
+
textInputHandlerProps,
|
|
10
11
|
useInputValue,
|
|
11
12
|
variantProp,
|
|
12
13
|
viewProps
|
|
13
14
|
} from '../utils'
|
|
14
15
|
|
|
15
|
-
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
16
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
17
|
+
a11yProps,
|
|
18
|
+
textInputHandlerProps,
|
|
19
|
+
viewProps
|
|
20
|
+
])
|
|
16
21
|
|
|
17
22
|
const selectInputStyles = (
|
|
18
23
|
{
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
|
+
import { Platform } from 'react-native'
|
|
2
3
|
|
|
3
4
|
const textInputPropTypes = {
|
|
4
5
|
/**
|
|
@@ -23,7 +24,12 @@ const textInputPropTypes = {
|
|
|
23
24
|
* Use to react upon input's value changes. Required when the `value` prop is set.
|
|
24
25
|
* Will receive the input's value as an argument.
|
|
25
26
|
*/
|
|
26
|
-
onChange: PropTypes.func
|
|
27
|
+
onChange: PropTypes.func,
|
|
28
|
+
...Platform.select({
|
|
29
|
+
web: {
|
|
30
|
+
pattern: PropTypes.string
|
|
31
|
+
}
|
|
32
|
+
})
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
export default textInputPropTypes
|
|
@@ -8,6 +8,7 @@ import StackView from '../StackView'
|
|
|
8
8
|
import { useThemeTokensCallback, applyShadowToken } from '../ThemeProvider'
|
|
9
9
|
import {
|
|
10
10
|
a11yProps,
|
|
11
|
+
focusHandlerProps,
|
|
11
12
|
getTokensPropType,
|
|
12
13
|
selectTokens,
|
|
13
14
|
pressProps,
|
|
@@ -18,7 +19,12 @@ import {
|
|
|
18
19
|
} from '../utils'
|
|
19
20
|
import { useInputValue } from '../utils/input'
|
|
20
21
|
|
|
21
|
-
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
22
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([
|
|
23
|
+
a11yProps,
|
|
24
|
+
focusHandlerProps,
|
|
25
|
+
pressProps,
|
|
26
|
+
viewProps
|
|
27
|
+
])
|
|
22
28
|
|
|
23
29
|
const selectButtonTokens = (tokens) =>
|
|
24
30
|
selectTokens('Button', {
|
|
@@ -111,7 +117,7 @@ const ToggleSwitch = forwardRef(
|
|
|
111
117
|
return (
|
|
112
118
|
<StackView space={2} direction="row">
|
|
113
119
|
{Boolean(label) && (
|
|
114
|
-
<View style={selectLabelStyles(themeTokens)}>
|
|
120
|
+
<View style={[selectLabelStyles(themeTokens), staticStyles.containText]}>
|
|
115
121
|
<InputLabel
|
|
116
122
|
forId={inputId}
|
|
117
123
|
label={label}
|
|
@@ -210,6 +216,9 @@ const staticStyles = StyleSheet.create({
|
|
|
210
216
|
switch: {
|
|
211
217
|
alignItems: 'center',
|
|
212
218
|
justifyContent: 'center'
|
|
219
|
+
},
|
|
220
|
+
containText: {
|
|
221
|
+
flexShrink: 1
|
|
213
222
|
}
|
|
214
223
|
})
|
|
215
224
|
|
|
@@ -10,16 +10,21 @@ import { useViewport } from '../ViewportProvider'
|
|
|
10
10
|
import { useThemeTokens } from '../ThemeProvider'
|
|
11
11
|
import {
|
|
12
12
|
a11yProps,
|
|
13
|
+
containUniqueFields,
|
|
14
|
+
focusHandlerProps,
|
|
13
15
|
getTokensPropType,
|
|
14
|
-
pressProps,
|
|
15
16
|
selectSystemProps,
|
|
17
|
+
useMultipleInputValues,
|
|
16
18
|
variantProp,
|
|
17
19
|
viewProps
|
|
18
|
-
} from '../utils
|
|
19
|
-
import { useMultipleInputValues } from '../utils/input'
|
|
20
|
-
|
|
21
|
-
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, pressProps, viewProps])
|
|
20
|
+
} from '../utils'
|
|
22
21
|
|
|
22
|
+
const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
|
|
23
|
+
const [selectItemProps, selectedItemPropTypes] = selectSystemProps([
|
|
24
|
+
a11yProps,
|
|
25
|
+
focusHandlerProps,
|
|
26
|
+
viewProps
|
|
27
|
+
])
|
|
23
28
|
const ToggleSwitchGroup = forwardRef(
|
|
24
29
|
(
|
|
25
30
|
{
|
|
@@ -66,6 +71,11 @@ const ToggleSwitchGroup = forwardRef(
|
|
|
66
71
|
})
|
|
67
72
|
const itemA11yRole = selectedProps.accessibilityRole === 'radiogroup' ? 'radio' : 'switch'
|
|
68
73
|
|
|
74
|
+
const uniqueFields = ['id', 'label']
|
|
75
|
+
if (!containUniqueFields(items, uniqueFields)) {
|
|
76
|
+
throw new Error(`ToggleSwitchGroup items must have unique ${uniqueFields.join(', ')}`)
|
|
77
|
+
}
|
|
78
|
+
|
|
69
79
|
const toggleSwitches = items.map(
|
|
70
80
|
(
|
|
71
81
|
{
|
|
@@ -74,7 +84,8 @@ const ToggleSwitchGroup = forwardRef(
|
|
|
74
84
|
accessibilityLabel = label,
|
|
75
85
|
onChange: itemOnChange,
|
|
76
86
|
ref: itemRef,
|
|
77
|
-
tooltip: itemTooltip
|
|
87
|
+
tooltip: itemTooltip,
|
|
88
|
+
...itemRest
|
|
78
89
|
},
|
|
79
90
|
index
|
|
80
91
|
) => {
|
|
@@ -104,6 +115,7 @@ const ToggleSwitchGroup = forwardRef(
|
|
|
104
115
|
label={label}
|
|
105
116
|
tooltip={itemTooltip}
|
|
106
117
|
{...itemA11y}
|
|
118
|
+
{...selectItemProps(itemRest)}
|
|
107
119
|
/>
|
|
108
120
|
)
|
|
109
121
|
}
|
|
@@ -143,6 +155,7 @@ ToggleSwitchGroup.propTypes = {
|
|
|
143
155
|
*/
|
|
144
156
|
items: PropTypes.arrayOf(
|
|
145
157
|
PropTypes.shape({
|
|
158
|
+
...selectedItemPropTypes,
|
|
146
159
|
/**
|
|
147
160
|
* The text displayed to the user on the label.
|
|
148
161
|
*/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Returns true if there are no duplicate values of the fields listed
|
|
2
|
+
// in the `fields` array across the objects in the `items` array, false
|
|
3
|
+
// otherwise.
|
|
4
|
+
// Note that if a value of a field in an item is not set, it will be
|
|
5
|
+
// excluded from comparison.
|
|
6
|
+
const containUniqueFields = (items, fields) => {
|
|
7
|
+
const map = []
|
|
8
|
+
|
|
9
|
+
const itemsHaveDuplicateFields = items.some((item) =>
|
|
10
|
+
fields.some((field) => {
|
|
11
|
+
if (!map[field]) {
|
|
12
|
+
map[field] = []
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!item[field]) {
|
|
16
|
+
// We exclude empty values from comparison
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Duplicate found!
|
|
21
|
+
if (map[field][item[field]]) return true
|
|
22
|
+
|
|
23
|
+
map[field][item[field]] = true
|
|
24
|
+
|
|
25
|
+
return false
|
|
26
|
+
})
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
return !itemsHaveDuplicateFields
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default containUniqueFields
|
package/src/utils/index.js
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
|
|
3
|
+
export const focusHandlerProps = {
|
|
4
|
+
types: {
|
|
5
|
+
/**
|
|
6
|
+
* onBlur handler
|
|
7
|
+
*/
|
|
8
|
+
onBlur: PropTypes.func,
|
|
9
|
+
/**
|
|
10
|
+
* onFocus handler
|
|
11
|
+
*/
|
|
12
|
+
onFocus: PropTypes.func
|
|
13
|
+
},
|
|
14
|
+
select: ({ onBlur, onFocus }) => ({
|
|
15
|
+
onBlur,
|
|
16
|
+
onFocus
|
|
17
|
+
})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const textInputHandlerProps = {
|
|
21
|
+
types: {
|
|
22
|
+
/**
|
|
23
|
+
* onChange handler
|
|
24
|
+
*/
|
|
25
|
+
onChange: PropTypes.func,
|
|
26
|
+
/**
|
|
27
|
+
* onChangeText handler
|
|
28
|
+
*/
|
|
29
|
+
onChangeText: PropTypes.func,
|
|
30
|
+
/**
|
|
31
|
+
* onSubmit handler
|
|
32
|
+
*/
|
|
33
|
+
onSubmit: PropTypes.func,
|
|
34
|
+
/**
|
|
35
|
+
* onSubmitEditing handler
|
|
36
|
+
*/
|
|
37
|
+
onSubmitEditing: PropTypes.func
|
|
38
|
+
},
|
|
39
|
+
select: ({ onChange, onChangeText, onSubmit, onSubmitEditing }) => ({
|
|
40
|
+
onChange,
|
|
41
|
+
onChangeText,
|
|
42
|
+
onSubmit,
|
|
43
|
+
onSubmitEditing
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default { focusHandlerProps, textInputHandlerProps }
|
package/src/utils/props/index.js
CHANGED
|
@@ -28,15 +28,14 @@ export default {
|
|
|
28
28
|
*/
|
|
29
29
|
validation: PropTypes.oneOf(['error', 'success'])
|
|
30
30
|
},
|
|
31
|
-
select: ({ label, hint, hintPosition, feedback, tooltip, validation
|
|
32
|
-
|
|
31
|
+
select: ({ label, hint, hintPosition, feedback, tooltip, validation }) => ({
|
|
32
|
+
supportsProps: {
|
|
33
33
|
label,
|
|
34
34
|
hint,
|
|
35
35
|
hintPosition,
|
|
36
36
|
feedback,
|
|
37
37
|
tooltip,
|
|
38
38
|
validation
|
|
39
|
-
}
|
|
40
|
-
...rest
|
|
39
|
+
}
|
|
41
40
|
})
|
|
42
41
|
}
|
|
@@ -8,35 +8,32 @@ export default {
|
|
|
8
8
|
component: InputLabel
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const Default = () => <InputLabel
|
|
11
|
+
export const Default = (args) => <InputLabel {...args} />
|
|
12
|
+
Default.args = { label: 'Test label' }
|
|
12
13
|
|
|
13
|
-
export const HintInline = () =>
|
|
14
|
-
|
|
15
|
-
)
|
|
14
|
+
export const HintInline = (args) => <InputLabel {...args} />
|
|
15
|
+
HintInline.args = { label: 'Test label', hint: 'Short hint', hintPosition: 'inline' }
|
|
16
16
|
|
|
17
|
-
export const HintAndTooltip = () =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
)
|
|
17
|
+
export const HintAndTooltip = (args) => <InputLabel {...args} />
|
|
18
|
+
HintAndTooltip.args = {
|
|
19
|
+
label: 'Test label',
|
|
20
|
+
hint: 'Short hint',
|
|
21
|
+
hintPosition: 'inline',
|
|
22
|
+
tooltip: "This is the tooltip's content"
|
|
23
|
+
}
|
|
25
24
|
|
|
26
|
-
export const HintInlineLong = () =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
25
|
+
export const HintInlineLong = (args) => <InputLabel {...args} />
|
|
26
|
+
HintInlineLong.args = {
|
|
27
|
+
label: 'Test label',
|
|
28
|
+
hint: "A rather long hint that won't actually fit",
|
|
29
|
+
hintPosition: 'inline',
|
|
30
|
+
tooltip: "This is the tooltip's content"
|
|
31
|
+
}
|
|
34
32
|
|
|
35
|
-
export const HintBelow = () =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)
|
|
33
|
+
export const HintBelow = (args) => <InputLabel {...args} />
|
|
34
|
+
HintBelow.args = {
|
|
35
|
+
label: 'Test label',
|
|
36
|
+
hint: "A rather long hint that won't actually fit",
|
|
37
|
+
hintPosition: 'below',
|
|
38
|
+
tooltip: "This is the tooltip's content"
|
|
39
|
+
}
|
|
@@ -10,6 +10,8 @@ export default {
|
|
|
10
10
|
export const Default = (args) => {
|
|
11
11
|
const [isOpen, setIsOpen] = useState(false)
|
|
12
12
|
const [isMaxWidthOpen, setIsMaxWidthOpen] = useState(false)
|
|
13
|
+
const [isCustomCloseOpen, setIsCustomCloseOpen] = useState(false)
|
|
14
|
+
const [isNoCloseOpen, setIsNoCloseOpen] = useState(false)
|
|
13
15
|
|
|
14
16
|
return (
|
|
15
17
|
<>
|
|
@@ -23,6 +25,29 @@ export const Default = (args) => {
|
|
|
23
25
|
<Typography variant={{ size: 'h2' }}>Test heading</Typography>
|
|
24
26
|
<Typography>Test content</Typography>
|
|
25
27
|
</Modal>
|
|
28
|
+
<Spacer space={3} />
|
|
29
|
+
<Button onPress={() => setIsCustomCloseOpen(true)}>Open custom close button modal</Button>
|
|
30
|
+
<Modal
|
|
31
|
+
{...args}
|
|
32
|
+
isOpen={isCustomCloseOpen}
|
|
33
|
+
onClose={() => setIsCustomCloseOpen(false)}
|
|
34
|
+
closeButton={<Button onPress={() => setIsCustomCloseOpen(false)}>Close</Button>}
|
|
35
|
+
>
|
|
36
|
+
<Typography variant={{ size: 'h2' }}>Test heading</Typography>
|
|
37
|
+
<Typography>Test content</Typography>
|
|
38
|
+
</Modal>
|
|
39
|
+
<Spacer space={3} />
|
|
40
|
+
<Button onPress={() => setIsNoCloseOpen(true)}>Open modal without close button</Button>
|
|
41
|
+
<Modal
|
|
42
|
+
{...args}
|
|
43
|
+
isOpen={isNoCloseOpen}
|
|
44
|
+
onClose={() => setIsNoCloseOpen(false)}
|
|
45
|
+
closeButton={null}
|
|
46
|
+
>
|
|
47
|
+
<Typography variant={{ size: 'h2' }}>Test heading</Typography>
|
|
48
|
+
<Typography>A custom close button is added in the modal content.</Typography>
|
|
49
|
+
<Button onPress={() => setIsNoCloseOpen(false)}>Close</Button>
|
|
50
|
+
</Modal>
|
|
26
51
|
</>
|
|
27
52
|
)
|
|
28
53
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
1
|
+
import React, { useEffect, useState, useRef } from 'react'
|
|
2
|
+
import { Platform } from 'react-native'
|
|
2
3
|
|
|
3
|
-
import { TextInput } from '../../src'
|
|
4
|
+
import { TextInput, Typography } from '../../src'
|
|
4
5
|
import { Container } from '../supports'
|
|
5
6
|
|
|
6
7
|
export default {
|
|
@@ -101,3 +102,40 @@ export const Controlled = () => {
|
|
|
101
102
|
</>
|
|
102
103
|
)
|
|
103
104
|
}
|
|
105
|
+
|
|
106
|
+
export const WithPattern = (args) => {
|
|
107
|
+
const [value, setValue] = useState('')
|
|
108
|
+
const inputRef = useRef(null)
|
|
109
|
+
const isEmpty = value === ''
|
|
110
|
+
const isSuccess = !isEmpty && inputRef.current.checkValidity()
|
|
111
|
+
// eslint-disable-next-line no-nested-ternary
|
|
112
|
+
const validation = isEmpty ? undefined : isSuccess ? 'success' : 'error'
|
|
113
|
+
const { pattern } = args
|
|
114
|
+
// eslint-disable-next-line no-nested-ternary
|
|
115
|
+
const feedback = isEmpty
|
|
116
|
+
? `Enter value matching pattern: ${pattern}`
|
|
117
|
+
: isSuccess
|
|
118
|
+
? `Success! Value matches pattern: ${pattern}`
|
|
119
|
+
: `Error! Value must match pattern: ${pattern}`
|
|
120
|
+
if (Platform.OS !== 'web') {
|
|
121
|
+
return <Typography>Pattern prop is only supported on web</Typography>
|
|
122
|
+
}
|
|
123
|
+
return (
|
|
124
|
+
<>
|
|
125
|
+
<Container>
|
|
126
|
+
<TextInput
|
|
127
|
+
{...args}
|
|
128
|
+
ref={inputRef}
|
|
129
|
+
label="Pattern"
|
|
130
|
+
validation={validation}
|
|
131
|
+
feedback={feedback}
|
|
132
|
+
value={value}
|
|
133
|
+
onChange={setValue}
|
|
134
|
+
/>
|
|
135
|
+
</Container>
|
|
136
|
+
</>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
WithPattern.args = {
|
|
140
|
+
pattern: '[1-9]{2}'
|
|
141
|
+
}
|