@telus-uds/components-base 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/.turbo/turbo-lint.log +13 -0
  3. package/CHANGELOG.json +154 -1
  4. package/CHANGELOG.md +47 -2
  5. package/__tests__/FlexGrid/Row.test.jsx +100 -25
  6. package/__tests__/utils/containUniqueFields.test.js +25 -0
  7. package/component-docs.json +78 -26
  8. package/generate-component-docs.js +20 -7
  9. package/lib/Button/ButtonBase.js +1 -1
  10. package/lib/Button/ButtonGroup.js +20 -12
  11. package/lib/Card/PressableCardBase.js +1 -1
  12. package/lib/Checkbox/Checkbox.js +27 -16
  13. package/lib/Checkbox/CheckboxGroup.js +19 -5
  14. package/lib/ExpandCollapse/Panel.js +10 -10
  15. package/lib/FlexGrid/Col/Col.js +13 -3
  16. package/lib/FlexGrid/Row/Row.js +8 -2
  17. package/lib/InputLabel/InputLabel.js +27 -25
  18. package/lib/Link/LinkBase.js +19 -6
  19. package/lib/Link/TextButton.js +1 -10
  20. package/lib/List/ListItem.js +22 -12
  21. package/lib/Modal/Modal.js +18 -18
  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/Search/Search.js +27 -19
  27. package/lib/Select/Select.js +2 -3
  28. package/lib/Tags/Tags.js +23 -17
  29. package/lib/TextInput/TextArea.js +2 -2
  30. package/lib/TextInput/TextInput.js +12 -2
  31. package/lib/TextInput/TextInputBase.js +1 -1
  32. package/lib/TextInput/propTypes.js +8 -1
  33. package/lib/ToggleSwitch/ToggleSwitch.js +5 -2
  34. package/lib/ToggleSwitch/ToggleSwitchGroup.js +20 -12
  35. package/lib/Typography/Typography.js +12 -10
  36. package/lib/index.js +22 -1
  37. package/lib/utils/containUniqueFields.js +34 -0
  38. package/lib/utils/index.js +10 -1
  39. package/lib/utils/input.js +5 -6
  40. package/lib/utils/props/handlerProps.js +72 -0
  41. package/lib/utils/props/index.js +32 -0
  42. package/lib/utils/props/inputSupportsProps.js +3 -5
  43. package/lib/utils/props/linkProps.js +3 -7
  44. package/lib/utils/props/textInputProps.js +206 -0
  45. package/lib/utils/props/textProps.js +72 -0
  46. package/lib-module/Button/ButtonBase.js +2 -2
  47. package/lib-module/Button/ButtonGroup.js +15 -6
  48. package/lib-module/Card/PressableCardBase.js +2 -2
  49. package/lib-module/Checkbox/Checkbox.js +28 -17
  50. package/lib-module/Checkbox/CheckboxGroup.js +20 -7
  51. package/lib-module/ExpandCollapse/Panel.js +10 -10
  52. package/lib-module/FlexGrid/Col/Col.js +13 -3
  53. package/lib-module/FlexGrid/Row/Row.js +8 -2
  54. package/lib-module/InputLabel/InputLabel.js +28 -25
  55. package/lib-module/Link/LinkBase.js +19 -6
  56. package/lib-module/Link/TextButton.js +1 -10
  57. package/lib-module/List/ListItem.js +22 -12
  58. package/lib-module/Modal/Modal.js +19 -19
  59. package/lib-module/Radio/Radio.js +24 -13
  60. package/lib-module/Radio/RadioGroup.js +13 -4
  61. package/lib-module/RadioCard/RadioCard.js +2 -2
  62. package/lib-module/RadioCard/RadioCardGroup.js +12 -3
  63. package/lib-module/Search/Search.js +29 -21
  64. package/lib-module/Select/Select.js +2 -3
  65. package/lib-module/Tags/Tags.js +18 -11
  66. package/lib-module/TextInput/TextArea.js +3 -3
  67. package/lib-module/TextInput/TextInput.js +11 -3
  68. package/lib-module/TextInput/TextInputBase.js +2 -2
  69. package/lib-module/TextInput/propTypes.js +7 -1
  70. package/lib-module/ToggleSwitch/ToggleSwitch.js +6 -3
  71. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +15 -6
  72. package/lib-module/Typography/Typography.js +13 -11
  73. package/lib-module/index.js +1 -1
  74. package/lib-module/utils/containUniqueFields.js +26 -0
  75. package/lib-module/utils/index.js +2 -1
  76. package/lib-module/utils/input.js +6 -6
  77. package/lib-module/utils/props/handlerProps.js +59 -0
  78. package/lib-module/utils/props/index.js +3 -0
  79. package/lib-module/utils/props/inputSupportsProps.js +3 -5
  80. package/lib-module/utils/props/linkProps.js +3 -7
  81. package/lib-module/utils/props/textInputProps.js +193 -0
  82. package/lib-module/utils/props/textProps.js +59 -0
  83. package/package.json +5 -5
  84. package/src/Button/ButtonBase.jsx +8 -2
  85. package/src/Button/ButtonGroup.jsx +51 -34
  86. package/src/Card/PressableCardBase.jsx +6 -1
  87. package/src/Checkbox/Checkbox.jsx +35 -23
  88. package/src/Checkbox/CheckboxGroup.jsx +52 -22
  89. package/src/ExpandCollapse/Panel.jsx +9 -9
  90. package/src/FlexGrid/Col/Col.jsx +11 -2
  91. package/src/FlexGrid/Row/Row.jsx +8 -2
  92. package/src/InputLabel/InputLabel.jsx +36 -27
  93. package/src/Link/LinkBase.jsx +20 -4
  94. package/src/Link/TextButton.jsx +1 -19
  95. package/src/List/ListItem.jsx +17 -9
  96. package/src/Modal/Modal.jsx +30 -26
  97. package/src/Radio/Radio.jsx +26 -14
  98. package/src/Radio/RadioGroup.jsx +39 -21
  99. package/src/RadioCard/RadioCard.jsx +6 -1
  100. package/src/RadioCard/RadioCardGroup.jsx +17 -1
  101. package/src/Search/Search.jsx +33 -21
  102. package/src/Select/Select.jsx +2 -2
  103. package/src/Tags/Tags.jsx +23 -9
  104. package/src/TextInput/TextArea.jsx +7 -1
  105. package/src/TextInput/TextInput.jsx +15 -3
  106. package/src/TextInput/TextInputBase.jsx +8 -1
  107. package/src/TextInput/propTypes.js +7 -1
  108. package/src/ToggleSwitch/ToggleSwitch.jsx +11 -2
  109. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +19 -6
  110. package/src/Typography/Typography.jsx +13 -9
  111. package/src/index.js +4 -1
  112. package/src/utils/containUniqueFields.js +32 -0
  113. package/src/utils/index.js +1 -0
  114. package/src/utils/input.js +5 -7
  115. package/src/utils/props/handlerProps.js +47 -0
  116. package/src/utils/props/index.js +3 -0
  117. package/src/utils/props/inputSupportsProps.js +3 -4
  118. package/src/utils/props/linkProps.js +3 -6
  119. package/src/utils/props/textInputProps.js +177 -0
  120. package/src/utils/props/textProps.js +58 -0
  121. package/stories/InputLabel/InputLabel.stories.jsx +25 -28
  122. package/stories/Modal/Modal.stories.jsx +25 -0
  123. package/stories/Search/Search.stories.jsx +53 -3
  124. package/stories/TextInput/TextInput.stories.jsx +40 -2
  125. package/__tests__/Link/LinkBase.test.jsx +0 -22
@@ -7,11 +7,11 @@ import InputLabel from '../InputLabel';
7
7
  import ButtonBase from '../Button/ButtonBase';
8
8
  import StackView from '../StackView';
9
9
  import { useThemeTokensCallback, applyShadowToken } from '../ThemeProvider';
10
- import { a11yProps, getTokensPropType, selectTokens, pressProps, selectSystemProps, useUniqueId, variantProp, viewProps } from '../utils';
10
+ import { a11yProps, focusHandlerProps, getTokensPropType, selectTokens, pressProps, selectSystemProps, useUniqueId, variantProp, viewProps } from '../utils';
11
11
  import { useInputValue } from '../utils/input';
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { jsxs as _jsxs } from "react/jsx-runtime";
14
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, pressProps, viewProps]);
14
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, pressProps, viewProps]);
15
15
 
16
16
  const selectButtonTokens = tokens => selectTokens('Button', { ...tokens,
17
17
  // Width tokens are applied to our inner track. Disable Button width token so it wraps our track width.
@@ -117,7 +117,7 @@ const ToggleSwitch = /*#__PURE__*/forwardRef(({
117
117
  space: 2,
118
118
  direction: "row",
119
119
  children: [Boolean(label) && /*#__PURE__*/_jsx(View, {
120
- style: selectLabelStyles(themeTokens),
120
+ style: [selectLabelStyles(themeTokens), staticStyles.containText],
121
121
  children: /*#__PURE__*/_jsx(InputLabel, {
122
122
  forId: inputId,
123
123
  label: label,
@@ -219,6 +219,9 @@ const staticStyles = StyleSheet.create({
219
219
  switch: {
220
220
  alignItems: 'center',
221
221
  justifyContent: 'center'
222
+ },
223
+ containText: {
224
+ flexShrink: 1
222
225
  }
223
226
  });
224
227
  export default ToggleSwitch;
@@ -7,10 +7,10 @@ import Fieldset from '../Fieldset';
7
7
  import { getStackedContent } from '../StackView';
8
8
  import { useViewport } from '../ViewportProvider';
9
9
  import { useThemeTokens } from '../ThemeProvider';
10
- import { a11yProps, getTokensPropType, pressProps, selectSystemProps, variantProp, viewProps } from '../utils/props';
11
- import { useMultipleInputValues } from '../utils/input';
10
+ import { a11yProps, containUniqueFields, focusHandlerProps, getTokensPropType, selectSystemProps, useMultipleInputValues, variantProp, viewProps } from '../utils';
12
11
  import { jsx as _jsx } from "react/jsx-runtime";
13
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, pressProps, viewProps]);
12
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
13
+ const [selectItemProps, selectedItemPropTypes] = selectSystemProps([a11yProps, focusHandlerProps, viewProps]);
14
14
  const ToggleSwitchGroup = /*#__PURE__*/forwardRef(({
15
15
  variant,
16
16
  tokens,
@@ -57,13 +57,20 @@ const ToggleSwitchGroup = /*#__PURE__*/forwardRef(({
57
57
  ...rest
58
58
  });
59
59
  const itemA11yRole = selectedProps.accessibilityRole === 'radiogroup' ? 'radio' : 'switch';
60
+ const uniqueFields = ['id', 'label'];
61
+
62
+ if (!containUniqueFields(items, uniqueFields)) {
63
+ throw new Error(`ToggleSwitchGroup items must have unique ${uniqueFields.join(', ')}`);
64
+ }
65
+
60
66
  const toggleSwitches = items.map(({
61
67
  label,
62
68
  id = label,
63
69
  accessibilityLabel = label,
64
70
  onChange: itemOnChange,
65
71
  ref: itemRef,
66
- tooltip: itemTooltip
72
+ tooltip: itemTooltip,
73
+ ...itemRest
67
74
  }, index) => {
68
75
  const isSelected = currentValues.includes(id);
69
76
 
@@ -89,7 +96,8 @@ const ToggleSwitchGroup = /*#__PURE__*/forwardRef(({
89
96
  inactive: inactive,
90
97
  label: label,
91
98
  tooltip: itemTooltip,
92
- ...itemA11y
99
+ ...itemA11y,
100
+ ...selectItemProps(itemRest)
93
101
  }, id);
94
102
  });
95
103
  return /*#__PURE__*/_jsx(Fieldset, {
@@ -123,7 +131,8 @@ ToggleSwitchGroup.propTypes = { ...selectedSystemPropTypes,
123
131
  /**
124
132
  * The options a user may select
125
133
  */
126
- items: PropTypes.arrayOf(PropTypes.shape({
134
+ items: PropTypes.arrayOf(PropTypes.shape({ ...selectedItemPropTypes,
135
+
127
136
  /**
128
137
  * The text displayed to the user on the label.
129
138
  */
@@ -5,13 +5,14 @@ import View from "react-native-web/dist/exports/View";
5
5
  import { useThemeTokens } from '../ThemeProvider';
6
6
  import { useViewport } from '../ViewportProvider';
7
7
  import { applyTextStyles } from '../ThemeProvider/utils';
8
- import { a11yProps, variantProp, getTokensPropType, getMaxFontMultiplier, headingTags, selectSystemProps, textTags, viewProps, getA11yPropsFromHtmlTag } from '../utils';
8
+ import { a11yProps, variantProp, getTokensPropType, getMaxFontMultiplier, headingTags, selectSystemProps, textTags, textProps, viewProps, getA11yPropsFromHtmlTag } from '../utils';
9
9
  /**
10
10
  * @typedef {import('../utils/a11y/semantics').TextTag} TextTag
11
11
  */
12
12
 
13
13
  import { jsx as _jsx } from "react/jsx-runtime";
14
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps]);
14
+ const [selectContainerProps, selectedContainerPropTypes] = selectSystemProps([a11yProps, viewProps]);
15
+ const [selectTextProps, selectedTextPropTypes] = selectSystemProps([textProps]);
15
16
 
16
17
  const selectTextStyles = ({
17
18
  fontWeight,
@@ -50,31 +51,32 @@ const Typography = /*#__PURE__*/forwardRef(({
50
51
  const themeTokens = useThemeTokens('Typography', tokens, variant, {
51
52
  viewport
52
53
  });
53
- const textProps = {
54
+ const resolvedTextProps = { ...selectTextProps(rest),
54
55
  style: selectTextStyles(align ? { ...themeTokens,
55
56
  textAlign: align
56
57
  } : themeTokens),
57
58
  dataSet,
58
59
  maxFontSizeMultiplier: getMaxFontMultiplier(themeTokens)
59
60
  };
60
- const selectedProps = selectProps({ ...getA11yPropsFromHtmlTag(tag, accessibilityRole),
61
- ...rest
62
- });
61
+ const containerProps = { ...getA11yPropsFromHtmlTag(tag, accessibilityRole),
62
+ ...selectContainerProps(rest)
63
+ };
63
64
  return block ? /*#__PURE__*/_jsx(View, {
64
65
  ref: ref,
65
- ...selectedProps,
66
- children: /*#__PURE__*/_jsx(Text, { ...textProps,
66
+ ...containerProps,
67
+ children: /*#__PURE__*/_jsx(Text, { ...resolvedTextProps,
67
68
  children: children
68
69
  })
69
70
  }) : /*#__PURE__*/_jsx(Text, {
70
71
  ref: ref,
71
- ...textProps,
72
- ...selectedProps,
72
+ ...containerProps,
73
+ ...resolvedTextProps,
73
74
  children: children
74
75
  });
75
76
  });
76
77
  Typography.displayName = 'Typography';
77
- Typography.propTypes = { ...selectedSystemPropTypes,
78
+ Typography.propTypes = { ...selectedContainerPropTypes,
79
+ ...selectedTextPropTypes,
78
80
  tokens: getTokensPropType('Typography'),
79
81
  variant: variantProp.propType,
80
82
 
@@ -44,5 +44,5 @@ export { default as Typography } from './Typography';
44
44
  export { default as A11yInfoProvider, useA11yInfo } from './A11yInfoProvider';
45
45
  export { default as BaseProvider } from './BaseProvider';
46
46
  export { default as ViewportProvider, useViewport, ViewportContext } from './ViewportProvider';
47
- export { default as ThemeProvider, useTheme, useSetTheme, useThemeTokens, getThemeTokens } from './ThemeProvider';
47
+ export { default as ThemeProvider, useTheme, useSetTheme, useThemeTokens, getThemeTokens, applyOuterBorder, applyTextStyles, applyShadowToken } from './ThemeProvider';
48
48
  export * from './utils';
@@ -0,0 +1,26 @@
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
+ const itemsHaveDuplicateFields = items.some(item => fields.some(field => {
9
+ if (!map[field]) {
10
+ map[field] = [];
11
+ }
12
+
13
+ if (!item[field]) {
14
+ // We exclude empty values from comparison
15
+ return false;
16
+ } // Duplicate found!
17
+
18
+
19
+ if (map[field][item[field]]) return true;
20
+ map[field][item[field]] = true;
21
+ return false;
22
+ }));
23
+ return !itemsHaveDuplicateFields;
24
+ };
25
+
26
+ export default containUniqueFields;
@@ -12,4 +12,5 @@ export { default as useResponsiveProp } from './useResponsiveProp';
12
12
  export * from './useResponsiveProp';
13
13
  export { default as useUniqueId } from './useUniqueId';
14
14
  export { default as withLinkRouter } from './withLinkRouter';
15
- export * from './ssr';
15
+ export * from './ssr';
16
+ export { default as containUniqueFields } from './containUniqueFields';
@@ -1,4 +1,8 @@
1
1
  import { useCallback, useRef, useState } from 'react';
2
+ /**
3
+ * @typedef {import('react').SyntheticEvent} Event
4
+ */
5
+
2
6
  const pluralHooks = ['useMultipleInputValues'];
3
7
 
4
8
  const validateProps = ({
@@ -56,11 +60,9 @@ Consumers of this hook must be one of:
56
60
  *
57
61
  * @param {string} hookName - optional, used for tailoring error messages
58
62
  *
59
- * @typedef {(oldValue: string|number|null) => string|number|null} UpdaterFunction - `setValue` takes a value or
60
- * a function returning a new value from the old value
61
63
  * @returns {{
62
64
  * currentValue: string|number|null
63
- * setValue: (newValue: string|number|null|UpdaterFunction) => void
65
+ * setValue: (newValue: string|number|null|(oldValue: string|number) => string|number, event: Event) => void
64
66
  * resetValue: () => void
65
67
  * isControlled: bool
66
68
  * }}
@@ -122,12 +124,10 @@ export const useInputValue = (props = {}, hookName = 'useInputValue') => {
122
124
  *
123
125
  * @param {string} componentName - optional, used in error messages
124
126
  *
125
- * @typedef {(oldValues: string[]|number[]) => string[]|number[]} UpdaterFunction - `setValues` takes values or
126
- * a function returning new values from old values
127
127
  * @returns {{
128
128
  * currentValues: any
129
129
  * resetValues: () => void
130
- * setValues: (newValues: string[]|number[]|UpdaterFunction) => void
130
+ * setValues: (newValues: string[]|number[]|(oldValues: string[]|number[]) => string[]|number[], event: Event) => void
131
131
  * toggleOneValue: (value: string|number) => void
132
132
  * unsetValues: () => void
133
133
  * }}
@@ -0,0 +1,59 @@
1
+ import PropTypes from 'prop-types';
2
+ export const focusHandlerProps = {
3
+ types: {
4
+ /**
5
+ * onBlur handler
6
+ */
7
+ onBlur: PropTypes.func,
8
+
9
+ /**
10
+ * onFocus handler
11
+ */
12
+ onFocus: PropTypes.func
13
+ },
14
+ select: ({
15
+ onBlur,
16
+ onFocus
17
+ }) => ({
18
+ onBlur,
19
+ onFocus
20
+ })
21
+ };
22
+ export const textInputHandlerProps = {
23
+ types: {
24
+ /**
25
+ * onChange handler
26
+ */
27
+ onChange: PropTypes.func,
28
+
29
+ /**
30
+ * onChangeText handler
31
+ */
32
+ onChangeText: PropTypes.func,
33
+
34
+ /**
35
+ * onSubmit handler
36
+ */
37
+ onSubmit: PropTypes.func,
38
+
39
+ /**
40
+ * onSubmitEditing handler
41
+ */
42
+ onSubmitEditing: PropTypes.func
43
+ },
44
+ select: ({
45
+ onChange,
46
+ onChangeText,
47
+ onSubmit,
48
+ onSubmitEditing
49
+ }) => ({
50
+ onChange,
51
+ onChangeText,
52
+ onSubmit,
53
+ onSubmitEditing
54
+ })
55
+ };
56
+ export default {
57
+ focusHandlerProps,
58
+ textInputHandlerProps
59
+ };
@@ -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';
@@ -12,5 +13,7 @@ export { default as rectProp } from './rectProp';
12
13
  export { default as responsiveProps } from './responsiveProps';
13
14
  export { default as spacingProps } from './spacingProps';
14
15
  export { default as selectSystemProps } from './selectSystemProps';
16
+ export { default as textInputProps } from './textInputProps';
17
+ export { default as textProps } from './textProps';
15
18
  export { default as variantProp } from './variantProp';
16
19
  export { default as viewProps } from './viewProps';
@@ -38,17 +38,15 @@ export default {
38
38
  hintPosition,
39
39
  feedback,
40
40
  tooltip,
41
- validation,
42
- ...rest
41
+ validation
43
42
  }) => ({
44
- props: {
43
+ supportsProps: {
45
44
  label,
46
45
  hint,
47
46
  hintPosition,
48
47
  feedback,
49
48
  tooltip,
50
49
  validation
51
- },
52
- ...rest
50
+ }
53
51
  })
54
52
  };
@@ -22,20 +22,16 @@ export default {
22
22
  select: getPropSelector(linkPropTypes),
23
23
 
24
24
  /**
25
- * Turn hrefs into press handlers on Native and throw if not given `onPress` or `href`.
25
+ * Turn hrefs into press handlers that open links on Native.
26
26
  *
27
27
  * @param {({ onPress?: () => void, href?: string })}
28
- * @returns {(() => void)|undefined} Returns a press handler, or undefined on web if href
29
- * string is provided. Expects calling component to use href string on web (e.g. in `<a>`).
28
+ * @returns {(() => void)|undefined} Returns a press handler, or undefined on web if no press
29
+ * handler is provided (expects calling component to render as `<a href={href}>` on web).
30
30
  */
31
31
  handleHref: ({
32
32
  onPress,
33
33
  href
34
34
  }) => {
35
- if (!href && !onPress) {
36
- throw new Error('handleHref requires either href or onPress');
37
- }
38
-
39
35
  return Platform.select({
40
36
  web: onPress,
41
37
  default: (...args) => {
@@ -0,0 +1,193 @@
1
+ import PropTypes from 'prop-types';
2
+ import Platform from "react-native-web/dist/exports/Platform";
3
+ import getPropSelector from './getPropSelector'; // This file contains common props for components that render a React Native TextInput
4
+ // It excludes interaction handler functions which are in `./handlerProps.js`
5
+
6
+ /**
7
+ * TextInput (web and native) supports some common React Native props
8
+ * shared with React Native's Text component.
9
+ */
10
+
11
+ const textProps = {
12
+ maxFontSizeMultiplier: PropTypes.number,
13
+ nativeId: PropTypes.string,
14
+ onLayout: PropTypes.func
15
+ };
16
+ /**
17
+ * UDS text inputs accept props related to UDS's useInputValue hook
18
+ */
19
+
20
+ const inputValueProps = {
21
+ value: PropTypes.string,
22
+ initialValue: PropTypes.string,
23
+ readOnly: PropTypes.bool
24
+ };
25
+ /**
26
+ * This collection adds props that can be passed through to both React Native's
27
+ * and React Native Web's implementations of the React Native TextInput component.
28
+ */
29
+
30
+ const crossPlatform = { ...textProps,
31
+ ...inputValueProps,
32
+
33
+ /**
34
+ * Web and Android; 'off' disables device autocomplete, other strings are platform-specific.
35
+ * Valid values on Native: https://reactnative.dev/docs/textinput#autocomplete-android
36
+ * Valid values on Web: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
37
+ */
38
+ autoComplete: PropTypes.string,
39
+
40
+ /**
41
+ * On Native, default is `true`, passing `false` disables autoCorrect.
42
+ * On web, only supported by Safari and expects "on" or "off" strings.
43
+ */
44
+ autoCorrect: PropTypes.oneOf([true, false, 'on', 'off']),
45
+
46
+ /**
47
+ * Focuses the element on mount. On Web, only the first form element with autoFocus is focussed.
48
+ */
49
+ autoFocus: PropTypes.bool,
50
+
51
+ /**
52
+ * Default is `true` for single line, `false` for multi-line
53
+ */
54
+ blurOnSubmit: PropTypes.bool,
55
+
56
+ /**
57
+ * iOS and Web only, no effect on Android
58
+ */
59
+ clearTextOnFocus: PropTypes.bool,
60
+
61
+ /**
62
+ * Default is `true`. On web, this works by mapping to input's `readonly` attribute
63
+ */
64
+ editable: PropTypes.bool,
65
+
66
+ /**
67
+ * See documentation for allowed values (varies between Web, Android and iOS) and important notes:
68
+ * - Native: https://reactnative.dev/docs/textinput#keyboardtype
69
+ * - Web: equivalent to `inputmode` but see https://necolas.github.io/react-native-web/docs/text-input/
70
+ */
71
+ keyboardType: PropTypes.string,
72
+
73
+ /**
74
+ * Uses native tools (no flicker) to cap the maximum number of characters.
75
+ * On Web, works via `maxlength` attr.
76
+ */
77
+ maxLength: PropTypes.number,
78
+
79
+ /**
80
+ * If passed as true, the text input can be multiple lines.
81
+ *
82
+ * > It is important to note that this aligns the text to the top on iOS, and centers it on Android.
83
+ * > Use with textAlignVertical set to top for the same behavior in both platforms.
84
+ */
85
+ multiline: PropTypes.bool,
86
+
87
+ /**
88
+ * Web and Android only, requires `multiline` to be `true`.
89
+ */
90
+ numberOfLines: PropTypes.number,
91
+
92
+ /**
93
+ * Text to display when no value set.
94
+ * Accesibility guidelines recommend using labels to describe the input and using
95
+ * placeholders rarely and sparingly to prompt a particular format.
96
+ */
97
+ placeholder: PropTypes.string,
98
+
99
+ /**
100
+ * Sets placeholder colour. On Web, uses `::placeholder { color: ... }` selector.
101
+ */
102
+ placeholderTextColor: PropTypes.string,
103
+
104
+ /**
105
+ * One of a subset of platform-specific options that controls labelling and presentation
106
+ * in on-screen keyboards and accessibility tools. Uses `enterkeyhint` attr on Web.
107
+ *
108
+ * 'done', 'go', 'next', 'search', and 'send' are available for Web, Android and iOS.
109
+ */
110
+ returnKeyType: PropTypes.string,
111
+
112
+ /**
113
+ * Obscures passwords and similar. Equivalent to type="password" on Web.
114
+ * Does not work if multiline is true.
115
+ */
116
+ secureTextEntry: PropTypes.bool,
117
+
118
+ /**
119
+ * If true, all text will automatically be selected on focus.
120
+ */
121
+ selectTextOnFocus: PropTypes.bool,
122
+
123
+ /**
124
+ * Web and iOS. On iOS, default inherits from `autoCorrect`.
125
+ * On Web, equivalent to `spellcheck` attr.
126
+ */
127
+ spellCheck: PropTypes.bool
128
+ };
129
+ /**
130
+ * These web-only props all control HTML `input` attributes of the same name.
131
+ * Refer to general HTML documentation for more details.
132
+ */
133
+
134
+ const webOnly = {
135
+ disabled: PropTypes.bool,
136
+ dir: PropTypes.oneOf(['auto', 'ltr', 'rtl']),
137
+ lang: PropTypes.string
138
+ };
139
+ /**
140
+ * These props are supported in React Native but not React Native Web.
141
+ *
142
+ * React Native text inputs can be quirky, so a full set of props should be allowed to handle edge cases.
143
+ * Refer to React Native documentation for details, allowed values, and Android/iOS support and versions:
144
+ * https://reactnative.dev/docs/textinput
145
+ *
146
+ * Beware that many React Native text input props apply via complicated logic that chooses a built-in
147
+ * native component based on the values of multiple boolean flags, and may sometimes appear to pick an
148
+ * option that is inappropriate for one flag based on the values of one or more other other flags.
149
+ */
150
+
151
+ const nativeOnly = {
152
+ caretHidden: PropTypes.bool,
153
+ clearButtonMode: PropTypes.string,
154
+ contextMenuHidden: PropTypes.bool,
155
+ dataDetectorTypes: PropTypes.string,
156
+ disableFullscreenUI: PropTypes.bool,
157
+ enablesReturnKeyAutomatically: PropTypes.bool,
158
+ importantForAutofill: PropTypes.string,
159
+ inlineImageLeft: PropTypes.string,
160
+ keyboardAppearance: PropTypes.string,
161
+ returnKeyLabel: PropTypes.string,
162
+ rejectResponderTermination: PropTypes.bool,
163
+ scrollEnabled: PropTypes.bool,
164
+ selection: PropTypes.object,
165
+ selectionColor: PropTypes.string,
166
+ showSoftInputOnFocus: PropTypes.bool,
167
+ textAlign: PropTypes.string,
168
+ textContentType: PropTypes.string,
169
+ passwordRules: PropTypes.string,
170
+ textBreakStrategy: PropTypes.string,
171
+ underlineColorAndroid: PropTypes.string
172
+ };
173
+ export default {
174
+ /**
175
+ * Subset of proptypes that can be passed down to a React Native or React Native Web
176
+ * `TextInput` component. Allow regardless of platform, so cross-platform apps don't warn.
177
+ */
178
+ types: { ...crossPlatform,
179
+ ...webOnly,
180
+ ...nativeOnly
181
+ },
182
+
183
+ /**
184
+ * Filters a props object. Return only platform-appropriate TextInput props, native inputs
185
+ * may throw errors on receiving unknown props.
186
+ */
187
+ select: getPropSelector({ ...crossPlatform,
188
+ ...Platform.select({
189
+ web: webOnly,
190
+ default: nativeOnly
191
+ })
192
+ })
193
+ };
@@ -0,0 +1,59 @@
1
+ import PropTypes from 'prop-types';
2
+ import Platform from "react-native-web/dist/exports/Platform";
3
+ import getPropSelector from './getPropSelector'; // These are the props accepted specifically on React Native (Web) `Text` elements.
4
+ // They are generally concerned with the behaviour of multiline text.
5
+
6
+ const crossPlatform = {
7
+ /**
8
+ * Truncates text after this many lines with an ellipsis at the end.
9
+ * On native, ellipsis behaviour may be changed with `ellipsizeMode` prop.
10
+ */
11
+ numberOfLines: PropTypes.number,
12
+
13
+ /**
14
+ * Default is true on web and false on native
15
+ */
16
+ selectable: PropTypes.bool
17
+ };
18
+ /**
19
+ * See React Native docs for latest details on these.
20
+ * https://reactnative.dev/docs/text
21
+ */
22
+
23
+ const nativeOnly = {
24
+ ellipsizeMode: PropTypes.string,
25
+ maxFontSizeMultiplier: PropTypes.number,
26
+ minimumFontScale: PropTypes.number,
27
+ onTextLayout: PropTypes.func,
28
+ suppressHighlighting: PropTypes.bool,
29
+ textBreakStrategy: PropTypes.string
30
+ };
31
+ /**
32
+ * These set HTML attributes of the same name.
33
+ */
34
+
35
+ const webOnly = {
36
+ dir: PropTypes.oneOf(['auto', 'ltr', 'rtl']),
37
+ lang: PropTypes.string
38
+ };
39
+ export default {
40
+ /**
41
+ * Set of prop types specific to React Native and React Native Web `Text`,
42
+ * which largely revolve around the behaviour of multiline non-pressable text.
43
+ */
44
+ types: { ...crossPlatform,
45
+ ...webOnly,
46
+ ...nativeOnly
47
+ },
48
+
49
+ /**
50
+ * Filters a props object, returning only props specific to `Text` elements
51
+ * on the current platform. Does not include props applicable to `Text` and `View`.
52
+ */
53
+ select: getPropSelector({ ...crossPlatform,
54
+ ...Platform.select({
55
+ web: webOnly,
56
+ default: nativeOnly
57
+ })
58
+ })
59
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telus-uds/components-base",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "Base components",
5
5
  "keywords": [
6
6
  "base"
@@ -22,14 +22,14 @@
22
22
  },
23
23
  "scripts": {
24
24
  "test": "jest",
25
- "lint": "telus-standard",
26
- "lint:fix": "telus-standard --fix",
25
+ "lint": "yarn --cwd ../.. lint:path --color packages/components-base",
26
+ "lint:fix": "yarn --cwd ../.. lint:path --fix packages/components-base",
27
27
  "format": "prettier --write .",
28
28
  "build": "yarn build:code && yarn build:docs",
29
29
  "build:main": "babel src -d lib",
30
30
  "build:module": "babel src -d lib-module --env-name module",
31
31
  "build:code": "yarn build:main && yarn build:module",
32
- "build:docs": "babel-node --plugins=react-docgen-alpha generate-component-docs.js",
32
+ "build:docs": "babel-node --plugins=@nearform/babel-plugin-react-docgen generate-component-docs.js",
33
33
  "storybook": "start-storybook",
34
34
  "dev": "yarn build:code --watch",
35
35
  "release": "standard-version"
@@ -59,7 +59,7 @@
59
59
  "dependencies": {
60
60
  "airbnb-prop-types": "^2.16.0",
61
61
  "@telus-uds/system-constants": "^1.0.2",
62
- "@telus-uds/system-theme-tokens": "^1.4.0",
62
+ "@telus-uds/system-theme-tokens": "^1.5.0",
63
63
  "lodash.debounce": "^4.0.8",
64
64
  "lodash.merge": "^4.6.2",
65
65
  "prop-types": "^15.7.2",
@@ -6,8 +6,9 @@ import { applyTextStyles, applyShadowToken, applyOuterBorder } from '../ThemePro
6
6
  import buttonPropTypes from './propTypes'
7
7
  import {
8
8
  a11yProps,
9
- getCursorStyle,
10
9
  clickProps,
10
+ focusHandlerProps,
11
+ getCursorStyle,
11
12
  linkProps,
12
13
  resolvePressableState,
13
14
  resolvePressableTokens,
@@ -17,7 +18,12 @@ import {
17
18
  withLinkRouter
18
19
  } from '../utils'
19
20
 
20
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps])
21
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([
22
+ a11yProps,
23
+ focusHandlerProps,
24
+ linkProps,
25
+ viewProps
26
+ ])
21
27
 
22
28
  const getOuterBorderOffset = ({ outerBorderGap = 0, outerBorderWidth = 0 }) =>
23
29
  outerBorderGap + outerBorderWidth