@telus-uds/components-base 1.5.0 → 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 (96) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/.turbo/turbo-lint.log +13 -0
  3. package/CHANGELOG.json +98 -1
  4. package/CHANGELOG.md +24 -2
  5. package/__tests__/FlexGrid/Row.test.jsx +100 -25
  6. package/__tests__/utils/containUniqueFields.test.js +25 -0
  7. package/component-docs.json +18 -2
  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/InputLabel/InputLabel.js +27 -25
  17. package/lib/Link/LinkBase.js +19 -6
  18. package/lib/Modal/Modal.js +18 -18
  19. package/lib/Radio/Radio.js +23 -12
  20. package/lib/Radio/RadioGroup.js +12 -3
  21. package/lib/RadioCard/RadioCard.js +1 -1
  22. package/lib/RadioCard/RadioCardGroup.js +11 -2
  23. package/lib/Select/Select.js +2 -3
  24. package/lib/Tags/Tags.js +23 -17
  25. package/lib/TextInput/TextArea.js +2 -2
  26. package/lib/TextInput/TextInput.js +12 -2
  27. package/lib/TextInput/TextInputBase.js +1 -1
  28. package/lib/TextInput/propTypes.js +8 -1
  29. package/lib/ToggleSwitch/ToggleSwitch.js +5 -2
  30. package/lib/ToggleSwitch/ToggleSwitchGroup.js +20 -12
  31. package/lib/utils/containUniqueFields.js +34 -0
  32. package/lib/utils/index.js +10 -1
  33. package/lib/utils/props/handlerProps.js +72 -0
  34. package/lib/utils/props/index.js +14 -0
  35. package/lib/utils/props/inputSupportsProps.js +3 -5
  36. package/lib-module/Button/ButtonBase.js +2 -2
  37. package/lib-module/Button/ButtonGroup.js +15 -6
  38. package/lib-module/Card/PressableCardBase.js +2 -2
  39. package/lib-module/Checkbox/Checkbox.js +28 -17
  40. package/lib-module/Checkbox/CheckboxGroup.js +20 -7
  41. package/lib-module/ExpandCollapse/Panel.js +10 -10
  42. package/lib-module/FlexGrid/Col/Col.js +13 -3
  43. package/lib-module/FlexGrid/Row/Row.js +8 -2
  44. package/lib-module/InputLabel/InputLabel.js +28 -25
  45. package/lib-module/Link/LinkBase.js +19 -6
  46. package/lib-module/Modal/Modal.js +19 -19
  47. package/lib-module/Radio/Radio.js +24 -13
  48. package/lib-module/Radio/RadioGroup.js +13 -4
  49. package/lib-module/RadioCard/RadioCard.js +2 -2
  50. package/lib-module/RadioCard/RadioCardGroup.js +12 -3
  51. package/lib-module/Select/Select.js +2 -3
  52. package/lib-module/Tags/Tags.js +18 -11
  53. package/lib-module/TextInput/TextArea.js +3 -3
  54. package/lib-module/TextInput/TextInput.js +11 -3
  55. package/lib-module/TextInput/TextInputBase.js +2 -2
  56. package/lib-module/TextInput/propTypes.js +7 -1
  57. package/lib-module/ToggleSwitch/ToggleSwitch.js +6 -3
  58. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +15 -6
  59. package/lib-module/utils/containUniqueFields.js +26 -0
  60. package/lib-module/utils/index.js +2 -1
  61. package/lib-module/utils/props/handlerProps.js +59 -0
  62. package/lib-module/utils/props/index.js +1 -0
  63. package/lib-module/utils/props/inputSupportsProps.js +3 -5
  64. package/package.json +5 -5
  65. package/src/Button/ButtonBase.jsx +8 -2
  66. package/src/Button/ButtonGroup.jsx +51 -34
  67. package/src/Card/PressableCardBase.jsx +6 -1
  68. package/src/Checkbox/Checkbox.jsx +35 -23
  69. package/src/Checkbox/CheckboxGroup.jsx +52 -22
  70. package/src/ExpandCollapse/Panel.jsx +9 -9
  71. package/src/FlexGrid/Col/Col.jsx +11 -2
  72. package/src/FlexGrid/Row/Row.jsx +8 -2
  73. package/src/InputLabel/InputLabel.jsx +36 -27
  74. package/src/Link/LinkBase.jsx +20 -4
  75. package/src/Modal/Modal.jsx +30 -26
  76. package/src/Radio/Radio.jsx +26 -14
  77. package/src/Radio/RadioGroup.jsx +39 -21
  78. package/src/RadioCard/RadioCard.jsx +6 -1
  79. package/src/RadioCard/RadioCardGroup.jsx +17 -1
  80. package/src/Select/Select.jsx +2 -2
  81. package/src/Tags/Tags.jsx +23 -9
  82. package/src/TextInput/TextArea.jsx +5 -1
  83. package/src/TextInput/TextInput.jsx +13 -3
  84. package/src/TextInput/TextInputBase.jsx +6 -1
  85. package/src/TextInput/propTypes.js +7 -1
  86. package/src/ToggleSwitch/ToggleSwitch.jsx +11 -2
  87. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +19 -6
  88. package/src/utils/containUniqueFields.js +32 -0
  89. package/src/utils/index.js +1 -0
  90. package/src/utils/props/handlerProps.js +47 -0
  91. package/src/utils/props/index.js +1 -0
  92. package/src/utils/props/inputSupportsProps.js +3 -4
  93. package/stories/InputLabel/InputLabel.stories.jsx +25 -28
  94. package/stories/Modal/Modal.stories.jsx +25 -0
  95. package/stories/Search/Search.stories.jsx +4 -1
  96. package/stories/TextInput/TextInput.stories.jsx +40 -2
@@ -31,6 +31,8 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
31
31
 
32
32
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
33
33
 
34
+ const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
35
+ const [selectItemProps, selectedItemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.viewProps]);
34
36
  /**
35
37
  * A group of Checkboxs that behave as a fieldset. Use when users select any number of choices from options.
36
38
  *
@@ -78,6 +80,7 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
78
80
  * />
79
81
  * ```
80
82
  */
83
+
81
84
  const CheckboxGroup = /*#__PURE__*/(0, _react.forwardRef)(({
82
85
  tokens,
83
86
  radioTokens,
@@ -93,7 +96,8 @@ const CheckboxGroup = /*#__PURE__*/(0, _react.forwardRef)(({
93
96
  onChange,
94
97
  readOnly,
95
98
  name: inputGroupName,
96
- inactive
99
+ inactive,
100
+ ...rest
97
101
  }, ref) => {
98
102
  const viewport = (0, _ViewportProvider.useViewport)();
99
103
  const {
@@ -111,11 +115,18 @@ const CheckboxGroup = /*#__PURE__*/(0, _react.forwardRef)(({
111
115
  onChange,
112
116
  readOnly: readOnly || inactive
113
117
  });
118
+ const uniqueFields = ['id', 'label'];
119
+
120
+ if (!(0, _utils.containUniqueFields)(items, uniqueFields)) {
121
+ throw new Error(`CheckboxGroup items must have unique ${uniqueFields.join(', ')}`);
122
+ }
123
+
114
124
  const checkboxes = items.map(({
115
125
  label,
116
126
  id,
117
127
  onChange: itemOnChange,
118
- ref: itemRef
128
+ ref: itemRef,
129
+ ...itemRest
119
130
  }, index) => {
120
131
  const checkboxId = id || `Checkbox[${index}]`;
121
132
 
@@ -133,7 +144,8 @@ const CheckboxGroup = /*#__PURE__*/(0, _react.forwardRef)(({
133
144
  label: label,
134
145
  name: inputGroupName,
135
146
  tokens: radioTokens,
136
- variant: variant
147
+ variant: variant,
148
+ ...selectItemProps(itemRest)
137
149
  }, checkboxId);
138
150
  });
139
151
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Fieldset.default, {
@@ -146,6 +158,7 @@ const CheckboxGroup = /*#__PURE__*/(0, _react.forwardRef)(({
146
158
  feedback: feedback,
147
159
  inactive: inactive,
148
160
  validation: validation,
161
+ ...selectProps(rest),
149
162
  children: (0, _StackView.getStackedContent)(checkboxes, {
150
163
  space,
151
164
  direction: 'column'
@@ -153,7 +166,8 @@ const CheckboxGroup = /*#__PURE__*/(0, _react.forwardRef)(({
153
166
  });
154
167
  });
155
168
  CheckboxGroup.displayName = 'CheckboxGroup';
156
- CheckboxGroup.propTypes = {
169
+ CheckboxGroup.propTypes = { ...selectedSystemPropTypes,
170
+
157
171
  /**
158
172
  * Optional theme token overrides for the outer CheckboxGroup component
159
173
  */
@@ -172,7 +186,7 @@ CheckboxGroup.propTypes = {
172
186
  /**
173
187
  * Array of objects containing specifics for each Checkbox to be rendered in the group.
174
188
  */
175
- items: _propTypes.default.arrayOf(_propTypes.default.exact({
189
+ items: _propTypes.default.arrayOf(_propTypes.default.exact({ ...selectedItemPropTypes,
176
190
  label: _propTypes.default.string,
177
191
  id: _propTypes.default.string,
178
192
  onChange: _propTypes.default.func,
@@ -86,12 +86,13 @@ const ExpandCollapsePanel = /*#__PURE__*/(0, _react.forwardRef)(({
86
86
  };
87
87
 
88
88
  const onContainerLayout = event => {
89
- if (containerHeight === null) {
90
- const {
91
- layout: {
92
- height = 0
93
- } = {}
94
- } = event.nativeEvent;
89
+ const {
90
+ layout: {
91
+ height = 0
92
+ } = {}
93
+ } = event.nativeEvent;
94
+
95
+ if (_Platform.default.OS === 'web' || _Platform.default.OS !== 'web' && containerHeight === null) {
95
96
  setContainerHeight(height);
96
97
  }
97
98
  };
@@ -116,12 +117,11 @@ const ExpandCollapsePanel = /*#__PURE__*/(0, _react.forwardRef)(({
116
117
  tokens: controlTokens,
117
118
  onPress: handleControlPress,
118
119
  children: control
119
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
120
- style: overflowContainerStyles,
120
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Animated.default.View, {
121
+ style: [overflowContainerStyles, animatedStyles, staticStyles.itemsContainer],
121
122
  ...focusabilityProps,
122
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Animated.default.View, {
123
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
123
124
  onLayout: onContainerLayout,
124
- style: [staticStyles.itemsContainer, animatedStyles],
125
125
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
126
126
  style: selectContainerStyles(themeTokens),
127
127
  children: children
@@ -46,6 +46,7 @@ const Col = /*#__PURE__*/(0, _react.forwardRef)(({
46
46
  mdOffset,
47
47
  lgOffset,
48
48
  xlOffset,
49
+ flex,
49
50
  ...viewProps
50
51
  }, ref) => {
51
52
  const gutter = (0, _react.useContext)(_GutterContext.default);
@@ -119,8 +120,11 @@ const Col = /*#__PURE__*/(0, _react.forwardRef)(({
119
120
  paddingLeft: gutter ? 16 : 0,
120
121
  paddingRight: gutter ? 16 : 0
121
122
  };
122
- let hidingStyles = {};
123
- const shown = _Platform.default.OS === 'web' ? 'block' : 'flex';
123
+ let hidingStyles = {}; // TODO: consider setting this to always 'flex' in a major release.
124
+ // `display: block` is invalid in native apps.
125
+ // See https://telusdigital.atlassian.net/browse/UDS1-92
126
+
127
+ const shown = !flex && _Platform.default.OS === 'web' ? 'block' : 'flex';
124
128
 
125
129
  if (viewPort === _systemConstants.viewports.xs) {
126
130
  hidingStyles = {
@@ -286,7 +290,13 @@ Col.propTypes = {
286
290
  *
287
291
  * Accepts a `PropType.string` following the [responsive prop](#/Layout?id=responsive) structure.
288
292
  */
289
- horizontalAlign: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['left', 'center', 'right']))
293
+ horizontalAlign: _utils.responsiveProps.getTypeOptionallyByViewport(_propTypes.default.oneOf(['left', 'center', 'right'])),
294
+
295
+ /**
296
+ * (web only) Stretches the column to fill vertical space using `display: flex`.
297
+ * In native apps, FlexGrid.Col behaves as if this is always true (as do all `View`s).
298
+ */
299
+ flex: _propTypes.default.bool
290
300
  };
291
301
  var _default = Col;
292
302
  exports.default = _default;
@@ -106,25 +106,31 @@ const Row = /*#__PURE__*/(0, _react.forwardRef)(({
106
106
  const viewPort = (0, _ViewportProvider.useViewport)();
107
107
  const reverseLevel = (0, _helpers.default)([xsReverse, smReverse, mdReverse, lgReverse, xlReverse]);
108
108
  let flexDirection = '';
109
+ let flexWrap = '';
109
110
 
110
111
  if (viewPort === _systemConstants.viewports.xs) {
111
112
  flexDirection = reverseLevel[0] ? 'row-reverse' : 'row';
113
+ flexWrap = reverseLevel[0] ? 'wrap-reverse' : 'wrap';
112
114
  }
113
115
 
114
116
  if (viewPort === _systemConstants.viewports.sm) {
115
117
  flexDirection = reverseLevel[1] ? 'row-reverse' : 'row';
118
+ flexWrap = reverseLevel[1] ? 'wrap-reverse' : 'wrap';
116
119
  }
117
120
 
118
121
  if (viewPort === _systemConstants.viewports.md) {
119
122
  flexDirection = reverseLevel[2] ? 'row-reverse' : 'row';
123
+ flexWrap = reverseLevel[2] ? 'wrap-reverse' : 'wrap';
120
124
  }
121
125
 
122
126
  if (viewPort === _systemConstants.viewports.lg) {
123
127
  flexDirection = reverseLevel[3] ? 'row-reverse' : 'row';
128
+ flexWrap = reverseLevel[3] ? 'wrap-reverse' : 'wrap';
124
129
  }
125
130
 
126
131
  if (viewPort === _systemConstants.viewports.xl) {
127
132
  flexDirection = reverseLevel[4] ? 'row-reverse' : 'row';
133
+ flexWrap = reverseLevel[4] ? 'wrap-reverse' : 'wrap';
128
134
  }
129
135
 
130
136
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
@@ -132,6 +138,7 @@ const Row = /*#__PURE__*/(0, _react.forwardRef)(({
132
138
  ...rest,
133
139
  style: [styles.row, {
134
140
  flexDirection,
141
+ flexWrap,
135
142
  ...horizontalAlignStyles(horizontalAlign),
136
143
  ...verticalAlignStyles(verticalAlign),
137
144
  ...distributeStyles(distribute)
@@ -149,8 +156,7 @@ const styles = _StyleSheet.default.create({
149
156
  flexGrow: 0,
150
157
  flexShrink: 1,
151
158
  flexBasis: 'auto',
152
- flexDirection: 'row',
153
- flexWrap: 'wrap'
159
+ flexDirection: 'row'
154
160
  }
155
161
  });
156
162
 
@@ -69,25 +69,29 @@ const InputLabel = /*#__PURE__*/(0, _react.forwardRef)(({
69
69
  const themeTokens = (0, _ThemeProvider.useThemeTokens)('InputLabel', tokens, variant);
70
70
  const hasTooltip = tooltip !== undefined;
71
71
  const isHintInline = hintPosition === 'inline';
72
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
73
- ref: ref,
74
- style: [staticStyles.container, !isHintInline && staticStyles.containerWithHintBelow],
75
- ...selectProps(rest),
76
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
77
- style: [selectLabelStyles(themeTokens), selectGapStyles(themeTokens), staticStyles.label],
78
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_LabelContent.default, {
79
- forId: forId,
80
- children: label
81
- })
82
- }), hint && isHintInline && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
83
- style: [selectHintStyles(themeTokens), hasTooltip && selectGapStyles(themeTokens)],
84
- nativeID: hintId,
85
- children: hint
86
- }), hasTooltip && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
87
- style: staticStyles.tooltipAlign,
88
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
89
- content: tooltip
90
- })
72
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
73
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
74
+ ref: ref,
75
+ style: staticStyles.container,
76
+ ...selectProps(rest),
77
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
78
+ style: [selectLabelStyles(themeTokens), selectGapStyles(themeTokens), staticStyles.label],
79
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_LabelContent.default, {
80
+ forId: forId,
81
+ children: label
82
+ })
83
+ }), hint && isHintInline && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
84
+ style: [selectHintStyles(themeTokens), hasTooltip && selectGapStyles(themeTokens), staticStyles.label],
85
+ nativeID: hintId,
86
+ children: hint
87
+ }), hasTooltip && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
88
+ style: [staticStyles.tooltipAlign, {
89
+ height: themeTokens.fontSize * themeTokens.lineHeight
90
+ }],
91
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
92
+ content: tooltip
93
+ })
94
+ })]
91
95
  }), hint && !isHintInline && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
92
96
  style: [selectHintStyles(themeTokens), staticStyles.hintBelow],
93
97
  nativeID: hintId,
@@ -135,21 +139,19 @@ exports.default = _default;
135
139
 
136
140
  const staticStyles = _StyleSheet.default.create({
137
141
  container: {
138
- display: 'flex',
142
+ flexShrink: 1,
139
143
  flexDirection: 'row',
140
144
  alignItems: 'baseline'
141
145
  },
142
- containerWithHintBelow: {
143
- flexWrap: 'wrap'
144
- },
145
146
  label: {
146
- flexShrink: 0
147
+ flexShrink: 1
147
148
  },
148
149
  hintBelow: {
149
150
  flexBasis: '100%',
150
151
  flexShrink: 0
151
152
  },
152
153
  tooltipAlign: {
153
- alignSelf: 'center'
154
+ alignSelf: 'flex-start',
155
+ justifyContent: 'center'
154
156
  }
155
157
  });
@@ -60,13 +60,9 @@ _Platform.default.OS === 'web' ? {
60
60
  } : {};
61
61
 
62
62
  const selectTextStyles = ({
63
- color,
64
- textLine,
65
- textLineStyle
63
+ color
66
64
  }) => ({
67
65
  color,
68
- textDecorationLine: textLine,
69
- textDecorationStyle: textLineStyle,
70
66
  ..._Platform.default.select({
71
67
  web: {
72
68
  // TODO: https://github.com/telus/universal-design-system/issues/487
@@ -87,6 +83,22 @@ const selectBlockStyles = ({
87
83
  fontName: blockFontName
88
84
  });
89
85
 
86
+ const selectDecorationStyles = ({
87
+ color,
88
+ textLine,
89
+ textLineStyle
90
+ }) => ({
91
+ color,
92
+ textDecorationLine: textLine,
93
+ textDecorationStyle: textLineStyle,
94
+ ..._Platform.default.select({
95
+ web: {
96
+ // TODO: https://github.com/telus/universal-design-system/issues/487
97
+ transition: 'color 200ms'
98
+ }
99
+ })
100
+ });
101
+
90
102
  const selectIconTokens = ({
91
103
  color,
92
104
  iconSize,
@@ -165,8 +177,9 @@ const LinkBase = /*#__PURE__*/(0, _react.forwardRef)(({
165
177
  style: linkState => {
166
178
  const themeTokens = resolveLinkTokens(linkState);
167
179
  const outerBorderStyles = selectOuterBorderStyles(themeTokens);
180
+ const decorationStyles = selectDecorationStyles(themeTokens);
168
181
  const hasIcon = Boolean(icon || themeTokens.icon);
169
- return [outerBorderStyles, blockLeftStyle, hasIcon && staticStyles.rowContainer];
182
+ return [outerBorderStyles, blockLeftStyle, decorationStyles, hasIcon && staticStyles.rowContainer];
170
183
  },
171
184
  children: linkState => {
172
185
  const themeTokens = resolveLinkTokens(linkState);
@@ -25,7 +25,7 @@ var _utils = require("../utils");
25
25
 
26
26
  var _ViewportProvider = require("../ViewportProvider");
27
27
 
28
- var _ButtonBase = _interopRequireDefault(require("../Button/ButtonBase"));
28
+ var _IconButton = _interopRequireDefault(require("../IconButton"));
29
29
 
30
30
  var _dictionary = _interopRequireDefault(require("./dictionary"));
31
31
 
@@ -90,14 +90,6 @@ const selectCloseButtonContainerStyles = ({
90
90
  paddingRight,
91
91
  paddingTop
92
92
  });
93
-
94
- const selectCloseIconProps = ({
95
- closeIconSize,
96
- closeIconColor
97
- }) => ({
98
- size: closeIconSize,
99
- color: closeIconColor
100
- });
101
93
  /**
102
94
  * A modal window is a secondary window that opens on top of the main one.
103
95
  * Users have to interact with it before they can carry out their task and return to the main window.
@@ -122,6 +114,7 @@ const Modal = /*#__PURE__*/(0, _react.forwardRef)(({
122
114
  tokens,
123
115
  variant,
124
116
  copy,
117
+ closeButton,
125
118
  ...rest
126
119
  }, ref) => {
127
120
  const viewport = (0, _ViewportProvider.useViewport)();
@@ -144,12 +137,15 @@ const Modal = /*#__PURE__*/(0, _react.forwardRef)(({
144
137
 
145
138
  const handleKeyUp = event => {
146
139
  if (event.key === 'Escape') onClose();
147
- };
140
+ }; // Show the custom react node passed to `closedButton` or the default close button if `closeButton` is `undefined`.
141
+ // Hide the close button if `closeButton` is `null`.
142
+
143
+
144
+ const showCloseButton = closeButton !== null;
148
145
 
149
146
  if (!isOpen) {
150
147
  return null;
151
- } // TODO: replace the close button with IconButton when implemented (https://github.com/telus/universal-design-system/issues/281)
152
-
148
+ }
153
149
 
154
150
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Modal.default, {
155
151
  transparent: true,
@@ -164,15 +160,14 @@ const Modal = /*#__PURE__*/(0, _react.forwardRef)(({
164
160
  ref: ref,
165
161
  style: [staticStyles.modal, selectModalStyles(themeTokens)],
166
162
  onKeyUp: handleKeyUp,
167
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
163
+ children: [showCloseButton && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
168
164
  style: [staticStyles.closeButtonContainer, selectCloseButtonContainerStyles(themeTokens)],
169
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ButtonBase.default, {
165
+ children: closeButton || /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
170
166
  onPress: handleClose,
167
+ icon: CloseIconComponent,
171
168
  accessibilityRole: "button",
172
169
  accessibilityLabel: closeLabel,
173
- children: // TODO: add close button interactive states after IconButton is done
174
- () => /*#__PURE__*/(0, _jsxRuntime.jsx)(CloseIconComponent, { ...selectCloseIconProps(themeTokens)
175
- })
170
+ tokens: (0, _utils.selectTokens)('IconButton', themeTokens, 'close')
176
171
  })
177
172
  }), children]
178
173
  })
@@ -193,7 +188,12 @@ Modal.propTypes = { ...selectedSystemPropTypes,
193
188
  onClose: _propTypes.default.func,
194
189
  maxWidth: _propTypes.default.bool,
195
190
  tokens: (0, _utils.getTokensPropType)('Modal'),
196
- variant: _utils.variantProp.propType
191
+ variant: _utils.variantProp.propType,
192
+
193
+ /**
194
+ * Pass a react node to override the default close button or pass `null` to hide the close button.
195
+ */
196
+ closeButton: _propTypes.default.node
197
197
  };
198
198
  var _default = Modal;
199
199
  exports.default = _default;
@@ -35,7 +35,7 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
35
35
 
36
36
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
37
37
 
38
- const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
38
+ const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.viewProps]);
39
39
 
40
40
  const selectContainerStyles = ({
41
41
  containerBackgroundColor,
@@ -186,22 +186,29 @@ const Radio = /*#__PURE__*/(0, _react.forwardRef)(({
186
186
  hover,
187
187
  pressed
188
188
  });
189
+ const labelStyles = selectLabelStyles(stateTokens);
190
+ const alignWithLabel = label ? [staticStyles.alignWithLabel, {
191
+ height: labelStyles.lineHeight
192
+ }] : null;
189
193
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_StackView.default, {
190
194
  space: 0,
191
195
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_View.default, {
192
196
  style: [staticStyles.container, selectContainerStyles(stateTokens)],
193
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_RadioButton.default, {
194
- tokens: (0, _RadioButton.selectRadioButtonTokens)(stateTokens),
195
- isControlled: isControlled,
196
- isChecked: isChecked,
197
- inactive: inactive,
198
- defaultChecked: defaultChecked,
199
- inputId: inputId,
200
- handleChange: handleChange,
201
- name: inputName,
202
- value: value
197
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
198
+ style: alignWithLabel,
199
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_RadioButton.default, {
200
+ tokens: (0, _RadioButton.selectRadioButtonTokens)(stateTokens),
201
+ isControlled: isControlled,
202
+ isChecked: isChecked,
203
+ inactive: inactive,
204
+ defaultChecked: defaultChecked,
205
+ inputId: inputId,
206
+ handleChange: handleChange,
207
+ name: inputName,
208
+ value: value
209
+ })
203
210
  }), Boolean(label) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Text.default, {
204
- style: selectLabelStyles(stateTokens),
211
+ style: labelStyles,
205
212
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_LabelContent.default, {
206
213
  forId: inputId,
207
214
  children: label
@@ -285,5 +292,9 @@ const staticStyles = _StyleSheet.default.create({
285
292
  container: {
286
293
  flexDirection: 'row',
287
294
  alignItems: 'center'
295
+ },
296
+ alignWithLabel: {
297
+ alignSelf: 'flex-start',
298
+ justifyContent: 'center'
288
299
  }
289
300
  });
@@ -32,6 +32,7 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
32
32
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
33
33
 
34
34
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
35
+ const [selectItemProps, selectedItemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.viewProps]);
35
36
  /**
36
37
  * A group of Radios that behave as a radio group. Use when users select a single choice from mutually
37
38
  * exclusive options.
@@ -115,11 +116,18 @@ const RadioGroup = /*#__PURE__*/(0, _react.forwardRef)(({
115
116
  onChange,
116
117
  readOnly: readOnly || inactive
117
118
  });
119
+ const uniqueFields = ['id', 'label'];
120
+
121
+ if (!(0, _utils.containUniqueFields)(items, uniqueFields)) {
122
+ throw new Error(`RadioGroup items must have unique ${uniqueFields.join(', ')}`);
123
+ }
124
+
118
125
  const radios = items.map(({
119
126
  label,
120
127
  id,
121
128
  onChange: itemOnChange,
122
- ref: itemRef
129
+ ref: itemRef,
130
+ ...itemRest
123
131
  }, index) => {
124
132
  const radioId = id || `Radio[${index}]`;
125
133
  const isChecked = currentValue === radioId;
@@ -138,7 +146,8 @@ const RadioGroup = /*#__PURE__*/(0, _react.forwardRef)(({
138
146
  label: label,
139
147
  name: inputGroupName,
140
148
  tokens: radioTokens,
141
- variant: variant
149
+ variant: variant,
150
+ ...selectItemProps(itemRest)
142
151
  }, radioId);
143
152
  });
144
153
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Fieldset.default, {
@@ -180,7 +189,7 @@ RadioGroup.propTypes = { ...selectedSystemPropTypes,
180
189
  /**
181
190
  * Array of objects containing specifics for each Radio to be rendered in the group.
182
191
  */
183
- items: _propTypes.default.arrayOf(_propTypes.default.exact({
192
+ items: _propTypes.default.arrayOf(_propTypes.default.exact({ ...selectedItemPropTypes,
184
193
  label: _propTypes.default.string,
185
194
  id: _propTypes.default.string,
186
195
  onChange: _propTypes.default.func,
@@ -33,7 +33,7 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
33
33
 
34
34
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
35
35
 
36
- const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
36
+ const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.viewProps]);
37
37
  /**
38
38
  * A Card that behaves like a radio button. Use when users select a single choice from mutually exclusive options
39
39
  * with need to show additional information for each option. The whole card is interactive as one item.
@@ -30,6 +30,7 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
30
30
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
31
31
 
32
32
  const [selectProps, selectedSystemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.viewProps]);
33
+ const [selectItemProps, selectedItemPropTypes] = (0, _utils.selectSystemProps)([_utils.a11yProps, _utils.focusHandlerProps, _utils.viewProps]);
33
34
  /**
34
35
  * A group of Cards that behave as a radio button group. Use when users select a single choice from mutually
35
36
  * exclusive options with need to show additional information for each option. The whole cards are each
@@ -120,6 +121,12 @@ const RadioCardGroup = /*#__PURE__*/(0, _react.forwardRef)(({
120
121
  // and also needs 'radiogroup' role on fieldset for correct description on focusing the set.
121
122
  // TODO: test this on more web screen readers.
122
123
 
124
+ const uniqueFields = ['id'];
125
+
126
+ if (!(0, _utils.containUniqueFields)(items, uniqueFields)) {
127
+ throw new Error(`RadioCardGroup items must have unique ${uniqueFields.join(', ')}`);
128
+ }
129
+
123
130
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Fieldset.default, {
124
131
  ref: ref,
125
132
  name: inputGroupName,
@@ -139,7 +146,8 @@ const RadioCardGroup = /*#__PURE__*/(0, _react.forwardRef)(({
139
146
  title,
140
147
  content,
141
148
  id,
142
- onChange: itemOnChange
149
+ onChange: itemOnChange,
150
+ ...itemRest
143
151
  }, index) => {
144
152
  const cardId = id || `RadioCard[${index}]`;
145
153
 
@@ -158,6 +166,7 @@ const RadioCardGroup = /*#__PURE__*/(0, _react.forwardRef)(({
158
166
  tokens: radioCardTokens,
159
167
  variant: variant,
160
168
  readOnly: readOnly,
169
+ ...selectItemProps(itemRest),
161
170
  ...props,
162
171
  children: content
163
172
  }, cardId);
@@ -186,7 +195,7 @@ RadioCardGroup.propTypes = { ...selectedSystemPropTypes,
186
195
  /**
187
196
  * Array of objects containing specifics for each RadioCard to be rendered in the group.
188
197
  */
189
- items: _propTypes.default.arrayOf(_propTypes.default.exact({
198
+ items: _propTypes.default.arrayOf(_propTypes.default.exact({ ...selectedItemPropTypes,
190
199
  title: _propTypes.default.string,
191
200
  content: _propTypes.default.node,
192
201
  id: _propTypes.default.string,
@@ -221,7 +221,7 @@ const Select = /*#__PURE__*/(0, _react.forwardRef)(({
221
221
  const handleMouseOut = () => setIsHovered(false);
222
222
 
223
223
  const {
224
- props: supportsProps,
224
+ supportsProps,
225
225
  ...selectedProps
226
226
  } = selectProps(rest);
227
227
  const themeTokens = (0, _ThemeProvider.useThemeTokens)('Select', tokens, variant, {
@@ -262,8 +262,7 @@ const Select = /*#__PURE__*/(0, _react.forwardRef)(({
262
262
  }), ValidationIconComponent && /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
263
263
  pointerEvents: "none",
264
264
  style: [staticStyles.iconContainer, selectValidationIconContainerStyles(themeTokens)],
265
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ValidationIconComponent, {
266
- tokens: selectValidationIconTokens(themeTokens)
265
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ValidationIconComponent, { ...selectValidationIconTokens(themeTokens)
267
266
  })
268
267
  }), IconComponent && _Platform.default.OS !== 'android' &&
269
268
  /*#__PURE__*/