@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.
Files changed (105) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/.turbo/turbo-lint.log +13 -0
  3. package/CHANGELOG.json +142 -1
  4. package/CHANGELOG.md +51 -2
  5. package/__tests__/FlexGrid/Row.test.jsx +100 -25
  6. package/__tests__/utils/containUniqueFields.test.js +25 -0
  7. package/component-docs.json +50 -15
  8. package/lib/Button/ButtonBase.js +1 -1
  9. package/lib/Button/ButtonGroup.js +20 -12
  10. package/lib/Card/PressableCardBase.js +1 -1
  11. package/lib/Checkbox/Checkbox.js +27 -16
  12. package/lib/Checkbox/CheckboxGroup.js +19 -5
  13. package/lib/ExpandCollapse/Panel.js +10 -10
  14. package/lib/FlexGrid/Col/Col.js +13 -3
  15. package/lib/FlexGrid/Row/Row.js +8 -2
  16. package/lib/HorizontalScroll/HorizontalScroll.js +0 -1
  17. package/lib/HorizontalScroll/HorizontalScrollButton.js +23 -49
  18. package/lib/InputLabel/InputLabel.js +27 -25
  19. package/lib/Link/LinkBase.js +19 -6
  20. package/lib/Modal/Modal.js +18 -18
  21. package/lib/Notification/Notification.js +5 -6
  22. package/lib/Radio/Radio.js +23 -12
  23. package/lib/Radio/RadioGroup.js +12 -3
  24. package/lib/RadioCard/RadioCard.js +1 -1
  25. package/lib/RadioCard/RadioCardGroup.js +11 -2
  26. package/lib/Select/Select.js +2 -3
  27. package/lib/Tags/Tags.js +23 -17
  28. package/lib/TextInput/TextArea.js +2 -2
  29. package/lib/TextInput/TextInput.js +12 -2
  30. package/lib/TextInput/TextInputBase.js +1 -1
  31. package/lib/TextInput/propTypes.js +8 -1
  32. package/lib/ToggleSwitch/ToggleSwitch.js +5 -2
  33. package/lib/ToggleSwitch/ToggleSwitchGroup.js +20 -12
  34. package/lib/utils/containUniqueFields.js +34 -0
  35. package/lib/utils/index.js +10 -1
  36. package/lib/utils/props/handlerProps.js +72 -0
  37. package/lib/utils/props/index.js +14 -0
  38. package/lib/utils/props/inputSupportsProps.js +3 -5
  39. package/lib-module/Button/ButtonBase.js +2 -2
  40. package/lib-module/Button/ButtonGroup.js +15 -6
  41. package/lib-module/Card/PressableCardBase.js +2 -2
  42. package/lib-module/Checkbox/Checkbox.js +28 -17
  43. package/lib-module/Checkbox/CheckboxGroup.js +20 -7
  44. package/lib-module/ExpandCollapse/Panel.js +10 -10
  45. package/lib-module/FlexGrid/Col/Col.js +13 -3
  46. package/lib-module/FlexGrid/Row/Row.js +8 -2
  47. package/lib-module/HorizontalScroll/HorizontalScroll.js +0 -1
  48. package/lib-module/HorizontalScroll/HorizontalScrollButton.js +24 -49
  49. package/lib-module/InputLabel/InputLabel.js +28 -25
  50. package/lib-module/Link/LinkBase.js +19 -6
  51. package/lib-module/Modal/Modal.js +19 -19
  52. package/lib-module/Notification/Notification.js +6 -6
  53. package/lib-module/Radio/Radio.js +24 -13
  54. package/lib-module/Radio/RadioGroup.js +13 -4
  55. package/lib-module/RadioCard/RadioCard.js +2 -2
  56. package/lib-module/RadioCard/RadioCardGroup.js +12 -3
  57. package/lib-module/Select/Select.js +2 -3
  58. package/lib-module/Tags/Tags.js +18 -11
  59. package/lib-module/TextInput/TextArea.js +3 -3
  60. package/lib-module/TextInput/TextInput.js +11 -3
  61. package/lib-module/TextInput/TextInputBase.js +2 -2
  62. package/lib-module/TextInput/propTypes.js +7 -1
  63. package/lib-module/ToggleSwitch/ToggleSwitch.js +6 -3
  64. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +15 -6
  65. package/lib-module/utils/containUniqueFields.js +26 -0
  66. package/lib-module/utils/index.js +2 -1
  67. package/lib-module/utils/props/handlerProps.js +59 -0
  68. package/lib-module/utils/props/index.js +1 -0
  69. package/lib-module/utils/props/inputSupportsProps.js +3 -5
  70. package/package.json +5 -5
  71. package/src/Button/ButtonBase.jsx +8 -2
  72. package/src/Button/ButtonGroup.jsx +51 -34
  73. package/src/Card/PressableCardBase.jsx +6 -1
  74. package/src/Checkbox/Checkbox.jsx +35 -23
  75. package/src/Checkbox/CheckboxGroup.jsx +52 -22
  76. package/src/ExpandCollapse/Panel.jsx +9 -9
  77. package/src/FlexGrid/Col/Col.jsx +11 -2
  78. package/src/FlexGrid/Row/Row.jsx +8 -2
  79. package/src/HorizontalScroll/HorizontalScroll.jsx +1 -1
  80. package/src/HorizontalScroll/HorizontalScrollButton.jsx +21 -58
  81. package/src/InputLabel/InputLabel.jsx +36 -27
  82. package/src/Link/LinkBase.jsx +20 -4
  83. package/src/Modal/Modal.jsx +30 -26
  84. package/src/Notification/Notification.jsx +7 -4
  85. package/src/Radio/Radio.jsx +26 -14
  86. package/src/Radio/RadioGroup.jsx +39 -21
  87. package/src/RadioCard/RadioCard.jsx +6 -1
  88. package/src/RadioCard/RadioCardGroup.jsx +17 -1
  89. package/src/Select/Select.jsx +2 -2
  90. package/src/Tags/Tags.jsx +23 -9
  91. package/src/TextInput/TextArea.jsx +5 -1
  92. package/src/TextInput/TextInput.jsx +13 -3
  93. package/src/TextInput/TextInputBase.jsx +6 -1
  94. package/src/TextInput/propTypes.js +7 -1
  95. package/src/ToggleSwitch/ToggleSwitch.jsx +11 -2
  96. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +19 -6
  97. package/src/utils/containUniqueFields.js +32 -0
  98. package/src/utils/index.js +1 -0
  99. package/src/utils/props/handlerProps.js +47 -0
  100. package/src/utils/props/index.js +1 -0
  101. package/src/utils/props/inputSupportsProps.js +3 -4
  102. package/stories/InputLabel/InputLabel.stories.jsx +25 -28
  103. package/stories/Modal/Modal.stories.jsx +25 -0
  104. package/stories/Search/Search.stories.jsx +4 -1
  105. 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,
@@ -194,7 +194,7 @@ const Select = forwardRef(
194
194
  const handleMouseOver = () => setIsHovered(true)
195
195
  const handleMouseOut = () => setIsHovered(false)
196
196
 
197
- const { props: supportsProps, ...selectedProps } = selectProps(rest)
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 tokens={selectValidationIconTokens(themeTokens)} />
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/props'
20
- import { useMultipleInputValues } from '../utils/input'
22
+ } from '../utils'
21
23
  import { getPressHandlersWithArgs } from '../utils/pressability'
22
24
 
23
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, pressProps, viewProps])
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, accessibilityLabel, ref: itemRef }, index) => {
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 itemA11y = {
130
+ const itemProps = {
118
131
  accessibilityState: { checked: isSelected },
119
132
  accessibilityRole: itemA11yRole,
120
- accessibilityLabel,
121
- ...a11yProps.getPositionInSet(items.length, index)
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
- {...itemA11y}
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 { props: supportsProps, ...selectedProps } = selectProps(rest)
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
- const { props: supportsProps, ...selectedProps } = selectProps(rest)
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([a11yProps, viewProps])
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([a11yProps, pressProps, viewProps])
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/props'
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
@@ -14,3 +14,4 @@ export * from './useResponsiveProp'
14
14
  export { default as useUniqueId } from './useUniqueId'
15
15
  export { default as withLinkRouter } from './withLinkRouter'
16
16
  export * from './ssr'
17
+ export { default as containUniqueFields } from './containUniqueFields'
@@ -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 }
@@ -1,4 +1,5 @@
1
1
  export * from './tokens'
2
+ export * from './handlerProps'
2
3
  export { default as a11yProps } from './a11yProps'
3
4
  export { default as clickProps } from './clickProps'
4
5
  export { default as copyPropTypes } from './copyPropTypes'
@@ -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, ...rest }) => ({
32
- props: {
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 label="Test label" />
11
+ export const Default = (args) => <InputLabel {...args} />
12
+ Default.args = { label: 'Test label' }
12
13
 
13
- export const HintInline = () => (
14
- <InputLabel label="Test label" hint="Short hint" hintPosition="inline" />
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
- <InputLabel
19
- label="Test label"
20
- hint="Short hint"
21
- hintPosition="inline"
22
- tooltip="This is the tooltip's content"
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
- <InputLabel
28
- label="Test label"
29
- hint="A rather long hint that won't actually fit"
30
- hintPosition="inline"
31
- tooltip="This is the tooltip's content"
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
- <InputLabel
37
- label="Test label"
38
- hint="A rather long hint that won't actually fit"
39
- hintPosition="below"
40
- tooltip="This is the tooltip's content"
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
  }
@@ -4,7 +4,10 @@ import { Search } from '../../src'
4
4
 
5
5
  export default {
6
6
  title: 'Search',
7
- component: Search
7
+ component: Search,
8
+ argTypes: {
9
+ onSubmit: { action: 'submitted' }
10
+ }
8
11
  }
9
12
 
10
13
  const Template = (args) => <Search {...args} />
@@ -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
+ }