@telus-uds/components-base 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,42 @@
1
1
  # Change Log - @telus-uds/components-base
2
2
 
3
- This log was last generated on Wed, 01 Feb 2023 20:54:30 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 10 Feb 2023 17:37:16 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 1.26.0
8
+
9
+ Fri, 10 Feb 2023 17:37:16 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - chore: new modal overlay component for multiselectfilter (mauricio.batresmontejo@telus.com)
14
+
15
+ ### Patches
16
+
17
+ - fixing icon gap to the right side (evander.owusu@telus.com)
18
+ - Fix carousel content not centering when resizing screen (tiagohldb@gmail.com)
19
+ - Fixing carousel StepTracker variant for mobile (tiagohldb@gmail.com)
20
+ - Tooltip implementation is separated into web and native for a fix on smaller screen size (akshay.pandey@telus.com)
21
+
22
+ ## 2.0.0
23
+
24
+ Thu, 09 Feb 2023 23:38:35 GMT
25
+
26
+ ### Major changes
27
+
28
+ - chore: new modal overlay component for multiselectfilter (mauricio.batresmontejo@telus.com)
29
+ - Bump @telus-uds/system-theme-tokens to v2.10.0
30
+
31
+ ### Patches
32
+
33
+ - fixing icon gap to the right side (evander.owusu@telus.com)
34
+ - Fixing carousel StepTracker variant for mobile (tiagohldb@gmail.com)
35
+ - Tooltip implementation is separated into web and native for a fix on smaller screen size (akshay.pandey@telus.com)
36
+
7
37
  ## 1.25.0
8
38
 
9
- Wed, 01 Feb 2023 20:54:30 GMT
39
+ Wed, 01 Feb 2023 20:56:49 GMT
10
40
 
11
41
  ### Minor changes
12
42
 
@@ -58,6 +58,8 @@
58
58
  "shadow": "shadow",
59
59
  "fontSize": "fontSize",
60
60
  "color": "color",
61
+ "dividerColor": "color",
62
+ "subtitleColor": "color",
61
63
  "lineHeight": "lineHeight",
62
64
  "textAlign": "flexJustifyContent",
63
65
  "alignSelf": "flexAlign",
@@ -103,6 +105,7 @@
103
105
  "paddingRight": "size",
104
106
  "paddingTop": "size",
105
107
  "paddingBottom": "size",
108
+ "height": "size",
106
109
  "width": "size",
107
110
  "minWidth": "size",
108
111
  "outerBorderColor": "color",
@@ -5867,6 +5870,13 @@
5867
5870
  "required": true,
5868
5871
  "description": "The text displayed to the user in a ButtonDropdown."
5869
5872
  },
5873
+ "subtitle": {
5874
+ "type": {
5875
+ "name": "string"
5876
+ },
5877
+ "required": false,
5878
+ "description": "The text for the subtitle"
5879
+ },
5870
5880
  "variant": {
5871
5881
  "type": {
5872
5882
  "name": "objectOf",
@@ -5909,6 +5919,8 @@
5909
5919
  "shadow": "shadow",
5910
5920
  "fontSize": "fontSize",
5911
5921
  "color": "color",
5922
+ "dividerColor": "color",
5923
+ "subtitleColor": "color",
5912
5924
  "lineHeight": "lineHeight",
5913
5925
  "textAlign": "flexJustifyContent",
5914
5926
  "alignSelf": "flexAlign",
@@ -10672,7 +10684,7 @@
10672
10684
  },
10673
10685
  "panelNavigation": {
10674
10686
  "defaultValue": {
10675
- "value": "thumbnails ? (\n <CarouselThumbnailNavigation thumbnails={thumbnails} />\n) : (\n <CarouselStepTracker />\n)",
10687
+ "value": "thumbnails ? (\n <CarouselThumbnailNavigation thumbnails={thumbnails} />\n) : (\n <CarouselStepTracker variant={stepTrackerVariant} />\n)",
10676
10688
  "computed": false
10677
10689
  },
10678
10690
  "type": {
@@ -10824,6 +10836,27 @@
10824
10836
  "required": false,
10825
10837
  "description": ""
10826
10838
  },
10839
+ "stepTrackerVariant": {
10840
+ "type": {
10841
+ "name": "objectOf",
10842
+ "value": {
10843
+ "name": "union",
10844
+ "value": [
10845
+ {
10846
+ "name": "string"
10847
+ },
10848
+ {
10849
+ "name": "number"
10850
+ },
10851
+ {
10852
+ "name": "bool"
10853
+ }
10854
+ ]
10855
+ }
10856
+ },
10857
+ "required": false,
10858
+ "description": "Prop related to StepTracker Variants"
10859
+ },
10827
10860
  "children": {
10828
10861
  "type": {
10829
10862
  "name": "union",
@@ -11172,6 +11205,27 @@
11172
11205
  "required": false,
11173
11206
  "description": ""
11174
11207
  },
11208
+ "stepTrackerVariant": {
11209
+ "type": {
11210
+ "name": "objectOf",
11211
+ "value": {
11212
+ "name": "union",
11213
+ "value": [
11214
+ {
11215
+ "name": "string"
11216
+ },
11217
+ {
11218
+ "name": "number"
11219
+ },
11220
+ {
11221
+ "name": "bool"
11222
+ }
11223
+ ]
11224
+ }
11225
+ },
11226
+ "required": false,
11227
+ "description": "Prop related to StepTracker Variants"
11228
+ },
11175
11229
  "children": {
11176
11230
  "type": {
11177
11231
  "name": "union",
@@ -232,7 +232,8 @@ const ButtonBase = /*#__PURE__*/(0, _react.forwardRef)((_ref9, ref) => {
232
232
 
233
233
  const extraButtonState = {
234
234
  inactive,
235
- selected
235
+ selected,
236
+ iconPosition
236
237
  };
237
238
 
238
239
  const resolveButtonTokens = pressableState => (0, _utils.resolvePressableTokens)(tokens, pressableState, extraButtonState);
@@ -17,6 +17,8 @@ var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/expo
17
17
 
18
18
  var _Platform = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Platform"));
19
19
 
20
+ var _Dimensions = _interopRequireDefault(require("react-native-web/dist/cjs/exports/Dimensions"));
21
+
20
22
  var _propTypes = _interopRequireDefault(require("prop-types"));
21
23
 
22
24
  var _ThemeProvider = require("../ThemeProvider");
@@ -165,6 +167,7 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
165
167
  children,
166
168
  itemLabel = 'item',
167
169
  previousNextNavigationPosition = 'inside',
170
+ stepTrackerVariant,
168
171
  previousNextIconSize = 'default',
169
172
  minDistanceToCapture = 5,
170
173
  minDistanceForAction = 0.2,
@@ -179,7 +182,9 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
179
182
  thumbnails = undefined,
180
183
  panelNavigation = thumbnails ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_CarouselThumbnailNavigation.default, {
181
184
  thumbnails: thumbnails
182
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_CarouselStepTracker.default, {}),
185
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_CarouselStepTracker.default, {
186
+ variant: stepTrackerVariant
187
+ }),
183
188
  tag = 'ul',
184
189
  accessibilityRole,
185
190
  accessibilityLabel,
@@ -419,6 +424,14 @@ const Carousel = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
419
424
  };
420
425
  }, [pan.x, pan.y]);
421
426
 
427
+ _react.default.useEffect(() => {
428
+ const subscription = _Dimensions.default.addEventListener('change', () => {
429
+ updateOffset();
430
+ });
431
+
432
+ return () => subscription === null || subscription === void 0 ? void 0 : subscription.remove();
433
+ });
434
+
422
435
  const goToNext = _react.default.useCallback(() => {
423
436
  goToNeighboring();
424
437
  }, [goToNeighboring]);
@@ -562,6 +575,11 @@ Carousel.propTypes = { ...selectedSystemPropTypes,
562
575
  tokens: (0, _utils.getTokensPropType)('Carousel'),
563
576
  variant: _utils.variantProp.propType,
564
577
 
578
+ /**
579
+ * Prop related to StepTracker Variants
580
+ */
581
+ stepTrackerVariant: _utils.variantProp.propType,
582
+
565
583
  /**
566
584
  * Slides to render in Carousel. Wrap individual slides in `Carousel.Item`
567
585
  */
@@ -13,11 +13,16 @@ var _StepTracker = _interopRequireDefault(require("../../StepTracker"));
13
13
 
14
14
  var _StackView = _interopRequireDefault(require("../../StackView"));
15
15
 
16
+ var _utils = require("../../utils");
17
+
16
18
  var _jsxRuntime = require("react/jsx-runtime");
17
19
 
18
20
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
21
 
20
- const CarouselStepTracker = () => {
22
+ const CarouselStepTracker = _ref => {
23
+ let {
24
+ variant
25
+ } = _ref;
21
26
  const {
22
27
  activeIndex,
23
28
  totalItems,
@@ -47,10 +52,14 @@ const CarouselStepTracker = () => {
47
52
  stepLabel: getCopyWithPlaceholders('stepLabel'),
48
53
  stepTrackerLabel: getCopyWithPlaceholders('stepTrackerLabel')
49
54
  },
50
- tokens: stepTrackerTokens
55
+ tokens: stepTrackerTokens,
56
+ variant: variant
51
57
  })
52
58
  });
53
59
  };
54
60
 
61
+ CarouselStepTracker.propTypes = {
62
+ variant: _utils.variantProp.propType
63
+ };
55
64
  var _default = CarouselStepTracker;
56
65
  exports.default = _default;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _react = _interopRequireWildcard(require("react"));
9
+
10
+ var _propTypes = _interopRequireDefault(require("prop-types"));
11
+
12
+ var _View = _interopRequireDefault(require("react-native-web/dist/cjs/exports/View"));
13
+
14
+ var _StyleSheet = _interopRequireDefault(require("react-native-web/dist/cjs/exports/StyleSheet"));
15
+
16
+ var _portal = require("@gorhom/portal");
17
+
18
+ var _utils = require("../utils");
19
+
20
+ var _ViewportProvider = require("../ViewportProvider");
21
+
22
+ var _ThemeProvider = require("../ThemeProvider");
23
+
24
+ var _dictionary = _interopRequireDefault(require("./dictionary"));
25
+
26
+ var _Card = _interopRequireDefault(require("../Card"));
27
+
28
+ var _IconButton = _interopRequireDefault(require("../IconButton"));
29
+
30
+ var _jsxRuntime = require("react/jsx-runtime");
31
+
32
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
+
34
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
35
+
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
+
38
+ const staticStyles = _StyleSheet.default.create({
39
+ positioner: {
40
+ flex: 1,
41
+ // Grow to maxWidth when possible, shrink when not possible
42
+ position: 'absolute',
43
+ height: 330,
44
+ paddingTop: 5,
45
+ zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
46
+
47
+ },
48
+ closeButtonContainer: {
49
+ position: 'absolute',
50
+ top: 0,
51
+ right: 0,
52
+ zIndex: 1
53
+ }
54
+ });
55
+
56
+ const selectCloseButtonContainerStyles = _ref => {
57
+ let {
58
+ paddingRight,
59
+ paddingTop
60
+ } = _ref;
61
+ return {
62
+ paddingRight,
63
+ paddingTop
64
+ };
65
+ };
66
+
67
+ const selectPaddingContainerStyles = _ref2 => {
68
+ let {
69
+ paddingTop,
70
+ paddingLeft,
71
+ paddingRight
72
+ } = _ref2;
73
+ return {
74
+ paddingBottom: 35,
75
+ paddingTop,
76
+ paddingLeft,
77
+ paddingRight
78
+ };
79
+ };
80
+
81
+ const ModalOverlay = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
82
+ let {
83
+ children,
84
+ tokens,
85
+ variant,
86
+ copy,
87
+ onClose
88
+ } = _ref3;
89
+ const viewport = (0, _ViewportProvider.useViewport)();
90
+ const themeTokens = (0, _ThemeProvider.useThemeTokens)('Modal', tokens, variant, {
91
+ viewport,
92
+ maxWidth: false
93
+ });
94
+ const {
95
+ closeIcon: CloseIconComponent,
96
+ maxWidth
97
+ } = themeTokens;
98
+ const getCopy = (0, _utils.useCopy)({
99
+ dictionary: _dictionary.default,
100
+ copy
101
+ });
102
+ const closeLabel = getCopy('closeButton');
103
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
104
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_portal.Portal, {
105
+ ref: ref,
106
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
107
+ style: [{
108
+ minWidth: maxWidth
109
+ }, staticStyles.positioner],
110
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Card.default, {
111
+ tokens: selectPaddingContainerStyles(themeTokens),
112
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_View.default, {
113
+ style: [staticStyles.closeButtonContainer, selectCloseButtonContainerStyles(themeTokens)],
114
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconButton.default, {
115
+ onPress: onClose,
116
+ icon: CloseIconComponent,
117
+ accessibilityRole: "button",
118
+ accessibilityLabel: closeLabel,
119
+ tokens: (0, _utils.selectTokens)('IconButton', themeTokens, 'close')
120
+ })
121
+ }), children]
122
+ })
123
+ })
124
+ })
125
+ });
126
+ });
127
+ ModalOverlay.displayName = 'ModalOverlay';
128
+ ModalOverlay.propTypes = {
129
+ children: _propTypes.default.node.isRequired,
130
+ variant: _utils.variantProp.propType,
131
+ tokens: (0, _utils.getTokensPropType)('Modal'),
132
+ copy: _utils.copyPropTypes,
133
+ onClose: _propTypes.default.func
134
+ };
135
+ var _default = ModalOverlay;
136
+ exports.default = _default;
@@ -25,8 +25,6 @@ var _Divider = _interopRequireDefault(require("../Divider"));
25
25
 
26
26
  var _FlexGrid = _interopRequireDefault(require("../FlexGrid"));
27
27
 
28
- var _Modal = _interopRequireDefault(require("../Modal"));
29
-
30
28
  var _Spacer = _interopRequireDefault(require("../Spacer"));
31
29
 
32
30
  var _StackView = _interopRequireDefault(require("../StackView"));
@@ -35,6 +33,8 @@ var _Typography = _interopRequireDefault(require("../Typography"));
35
33
 
36
34
  var _Link = require("../Link");
37
35
 
36
+ var _ModalOverlay = _interopRequireDefault(require("./ModalOverlay"));
37
+
38
38
  var _jsxRuntime = require("react/jsx-runtime");
39
39
 
40
40
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -47,9 +47,35 @@ const {
47
47
  Col,
48
48
  Row
49
49
  } = _FlexGrid.default;
50
- const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
50
+
51
+ const selectSubTitleTokens = _ref => {
52
+ let {
53
+ subtitleColor
54
+ } = _ref;
55
+ return {
56
+ color: subtitleColor
57
+ };
58
+ };
59
+
60
+ const selectDividerToknes = _ref2 => {
61
+ let {
62
+ dividerColor,
63
+ width,
64
+ decorative = true,
65
+ weight = 'thin'
66
+ } = _ref2;
67
+ return {
68
+ color: dividerColor,
69
+ width,
70
+ decorative,
71
+ weight
72
+ };
73
+ };
74
+
75
+ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref3, ref) => {
51
76
  let {
52
77
  label,
78
+ subtitle,
53
79
  id = label,
54
80
  variant,
55
81
  tokens,
@@ -63,7 +89,7 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
63
89
  inactive = false,
64
90
  rowLimit = 12,
65
91
  ...rest
66
- } = _ref;
92
+ } = _ref3;
67
93
  const {
68
94
  currentValues,
69
95
  setValues
@@ -74,6 +100,7 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
74
100
  onChange,
75
101
  readOnly
76
102
  });
103
+ const themeTokens = (0, _ThemeProvider.useThemeTokens)('ButtonDropdown', tokens, variant);
77
104
  const getItemTokens = (0, _ThemeProvider.useThemeTokensCallback)('ButtonDropdown', tokens, variant);
78
105
 
79
106
  const getButtonTokens = buttonState => (0, _utils.selectTokens)('Button', getItemTokens(buttonState));
@@ -101,7 +128,7 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
101
128
 
102
129
  const handleChange = event => {
103
130
  if (pressHandlers.onPress) pressHandlers === null || pressHandlers === void 0 ? void 0 : pressHandlers.onPress(event);
104
- setIsOpen(true);
131
+ setIsOpen(!isOpen);
105
132
  };
106
133
 
107
134
  const onApply = e => {
@@ -110,12 +137,20 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
110
137
  };
111
138
 
112
139
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
113
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_Modal.default, {
114
- isOpen: isOpen,
115
- onClose: () => setIsOpen(false),
140
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.ButtonDropdown, {
141
+ ref: ref,
142
+ ...pressHandlers,
143
+ value: isOpen,
144
+ selected: isSelected,
145
+ label: label,
146
+ onChange: handleChange,
147
+ tokens: getButtonTokens,
148
+ inactive: inactive
149
+ }, id), isOpen && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_ModalOverlay.default, {
116
150
  variant: {
117
151
  width: colSize > 1 ? 'size576' : 's'
118
152
  },
153
+ onClose: () => setIsOpen(false),
119
154
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
120
155
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
121
156
  variant: {
@@ -123,10 +158,20 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
123
158
  },
124
159
  children: getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())
125
160
  })
161
+ }), subtitle && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
162
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Spacer.default, {
163
+ space: 5
164
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
165
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Typography.default, {
166
+ variant: {
167
+ size: 'h5'
168
+ },
169
+ tokens: selectSubTitleTokens(themeTokens),
170
+ children: subtitle
171
+ })
172
+ })]
126
173
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Spacer.default, {
127
174
  space: 4
128
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Spacer.default, {
129
- space: 1
130
175
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Box.default, {
131
176
  scroll: true,
132
177
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
@@ -143,12 +188,9 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
143
188
  }, i))
144
189
  })
145
190
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Divider.default, {
146
- variant: {
147
- width: 'full',
148
- color: 'E3E6E8',
149
- decorative: true,
150
- weight: 'thin'
151
- },
191
+ variant: selectDividerToknes({ ...themeTokens,
192
+ width: 'full'
193
+ }),
152
194
  space: 4
153
195
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Row, {
154
196
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_StackView.default, {
@@ -172,16 +214,7 @@ const MultiSelectFilter = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
172
214
  })]
173
215
  })
174
216
  })]
175
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.ButtonDropdown, {
176
- ref: ref,
177
- ...pressHandlers,
178
- value: isOpen,
179
- selected: isSelected,
180
- label: label,
181
- onChange: handleChange,
182
- tokens: getButtonTokens,
183
- inactive: inactive
184
- }, id)]
217
+ })]
185
218
  });
186
219
  });
187
220
  MultiSelectFilter.displayName = 'MultiSelectFilter';
@@ -191,6 +224,11 @@ MultiSelectFilter.propTypes = {
191
224
  */
192
225
  label: _propTypes.default.string.isRequired,
193
226
 
227
+ /**
228
+ * The text for the subtitle
229
+ */
230
+ subtitle: _propTypes.default.string,
231
+
194
232
  /**
195
233
  * An optional unique string may be provided to identify the ButtonDropdown.
196
234
  * If not provided, the label is used.
@@ -206,7 +206,8 @@ const ButtonBase = /*#__PURE__*/forwardRef((_ref9, ref) => {
206
206
  } = clickProps.toPressProps(rawRest);
207
207
  const extraButtonState = {
208
208
  inactive,
209
- selected
209
+ selected,
210
+ iconPosition
210
211
  };
211
212
 
212
213
  const resolveButtonTokens = pressableState => resolvePressableTokens(tokens, pressableState, extraButtonState);
@@ -4,6 +4,7 @@ import Animated from "react-native-web/dist/exports/Animated";
4
4
  import PanResponder from "react-native-web/dist/exports/PanResponder";
5
5
  import StyleSheet from "react-native-web/dist/exports/StyleSheet";
6
6
  import Platform from "react-native-web/dist/exports/Platform";
7
+ import Dimensions from "react-native-web/dist/exports/Dimensions";
7
8
  import PropTypes from 'prop-types';
8
9
  import { useThemeTokens } from '../ThemeProvider';
9
10
  import { useViewport } from '../ViewportProvider';
@@ -135,6 +136,7 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
135
136
  children,
136
137
  itemLabel = 'item',
137
138
  previousNextNavigationPosition = 'inside',
139
+ stepTrackerVariant,
138
140
  previousNextIconSize = 'default',
139
141
  minDistanceToCapture = 5,
140
142
  minDistanceForAction = 0.2,
@@ -149,7 +151,9 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
149
151
  thumbnails = undefined,
150
152
  panelNavigation = thumbnails ? /*#__PURE__*/_jsx(CarouselThumbnailNavigation, {
151
153
  thumbnails: thumbnails
152
- }) : /*#__PURE__*/_jsx(CarouselStepTracker, {}),
154
+ }) : /*#__PURE__*/_jsx(CarouselStepTracker, {
155
+ variant: stepTrackerVariant
156
+ }),
153
157
  tag = 'ul',
154
158
  accessibilityRole,
155
159
  accessibilityLabel,
@@ -369,6 +373,12 @@ const Carousel = /*#__PURE__*/React.forwardRef((_ref, ref) => {
369
373
  pan.y.removeAllListeners();
370
374
  };
371
375
  }, [pan.x, pan.y]);
376
+ React.useEffect(() => {
377
+ const subscription = Dimensions.addEventListener('change', () => {
378
+ updateOffset();
379
+ });
380
+ return () => subscription === null || subscription === void 0 ? void 0 : subscription.remove();
381
+ });
372
382
  const goToNext = React.useCallback(() => {
373
383
  goToNeighboring();
374
384
  }, [goToNeighboring]);
@@ -504,6 +514,11 @@ Carousel.propTypes = { ...selectedSystemPropTypes,
504
514
  tokens: getTokensPropType('Carousel'),
505
515
  variant: variantProp.propType,
506
516
 
517
+ /**
518
+ * Prop related to StepTracker Variants
519
+ */
520
+ stepTrackerVariant: variantProp.propType,
521
+
507
522
  /**
508
523
  * Slides to render in Carousel. Wrap individual slides in `Carousel.Item`
509
524
  */
@@ -2,9 +2,13 @@ import React from 'react';
2
2
  import { useCarousel } from '../CarouselContext';
3
3
  import StepTracker from '../../StepTracker';
4
4
  import StackView from '../../StackView';
5
+ import { variantProp } from '../../utils';
5
6
  import { jsx as _jsx } from "react/jsx-runtime";
6
7
 
7
- const CarouselStepTracker = () => {
8
+ const CarouselStepTracker = _ref => {
9
+ let {
10
+ variant
11
+ } = _ref;
8
12
  const {
9
13
  activeIndex,
10
14
  totalItems,
@@ -34,9 +38,13 @@ const CarouselStepTracker = () => {
34
38
  stepLabel: getCopyWithPlaceholders('stepLabel'),
35
39
  stepTrackerLabel: getCopyWithPlaceholders('stepTrackerLabel')
36
40
  },
37
- tokens: stepTrackerTokens
41
+ tokens: stepTrackerTokens,
42
+ variant: variant
38
43
  })
39
44
  });
40
45
  };
41
46
 
47
+ CarouselStepTracker.propTypes = {
48
+ variant: variantProp.propType
49
+ };
42
50
  export default CarouselStepTracker;
@@ -0,0 +1,112 @@
1
+ import React, { forwardRef } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import View from "react-native-web/dist/exports/View";
4
+ import StyleSheet from "react-native-web/dist/exports/StyleSheet";
5
+ import { Portal } from '@gorhom/portal';
6
+ import { copyPropTypes, getTokensPropType, selectTokens, useCopy, variantProp } from '../utils';
7
+ import { useViewport } from '../ViewportProvider';
8
+ import { useThemeTokens } from '../ThemeProvider';
9
+ import dictionary from './dictionary';
10
+ import Card from '../Card';
11
+ import IconButton from '../IconButton';
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import { jsxs as _jsxs } from "react/jsx-runtime";
14
+ import { Fragment as _Fragment } from "react/jsx-runtime";
15
+ const staticStyles = StyleSheet.create({
16
+ positioner: {
17
+ flex: 1,
18
+ // Grow to maxWidth when possible, shrink when not possible
19
+ position: 'absolute',
20
+ height: 330,
21
+ paddingTop: 5,
22
+ zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
23
+
24
+ },
25
+ closeButtonContainer: {
26
+ position: 'absolute',
27
+ top: 0,
28
+ right: 0,
29
+ zIndex: 1
30
+ }
31
+ });
32
+
33
+ const selectCloseButtonContainerStyles = _ref => {
34
+ let {
35
+ paddingRight,
36
+ paddingTop
37
+ } = _ref;
38
+ return {
39
+ paddingRight,
40
+ paddingTop
41
+ };
42
+ };
43
+
44
+ const selectPaddingContainerStyles = _ref2 => {
45
+ let {
46
+ paddingTop,
47
+ paddingLeft,
48
+ paddingRight
49
+ } = _ref2;
50
+ return {
51
+ paddingBottom: 35,
52
+ paddingTop,
53
+ paddingLeft,
54
+ paddingRight
55
+ };
56
+ };
57
+
58
+ const ModalOverlay = /*#__PURE__*/forwardRef((_ref3, ref) => {
59
+ let {
60
+ children,
61
+ tokens,
62
+ variant,
63
+ copy,
64
+ onClose
65
+ } = _ref3;
66
+ const viewport = useViewport();
67
+ const themeTokens = useThemeTokens('Modal', tokens, variant, {
68
+ viewport,
69
+ maxWidth: false
70
+ });
71
+ const {
72
+ closeIcon: CloseIconComponent,
73
+ maxWidth
74
+ } = themeTokens;
75
+ const getCopy = useCopy({
76
+ dictionary,
77
+ copy
78
+ });
79
+ const closeLabel = getCopy('closeButton');
80
+ return /*#__PURE__*/_jsx(_Fragment, {
81
+ children: /*#__PURE__*/_jsx(Portal, {
82
+ ref: ref,
83
+ children: /*#__PURE__*/_jsx(View, {
84
+ style: [{
85
+ minWidth: maxWidth
86
+ }, staticStyles.positioner],
87
+ children: /*#__PURE__*/_jsxs(Card, {
88
+ tokens: selectPaddingContainerStyles(themeTokens),
89
+ children: [/*#__PURE__*/_jsx(View, {
90
+ style: [staticStyles.closeButtonContainer, selectCloseButtonContainerStyles(themeTokens)],
91
+ children: /*#__PURE__*/_jsx(IconButton, {
92
+ onPress: onClose,
93
+ icon: CloseIconComponent,
94
+ accessibilityRole: "button",
95
+ accessibilityLabel: closeLabel,
96
+ tokens: selectTokens('IconButton', themeTokens, 'close')
97
+ })
98
+ }), children]
99
+ })
100
+ })
101
+ })
102
+ });
103
+ });
104
+ ModalOverlay.displayName = 'ModalOverlay';
105
+ ModalOverlay.propTypes = {
106
+ children: PropTypes.node.isRequired,
107
+ variant: variantProp.propType,
108
+ tokens: getTokensPropType('Modal'),
109
+ copy: copyPropTypes,
110
+ onClose: PropTypes.func
111
+ };
112
+ export default ModalOverlay;
@@ -1,6 +1,6 @@
1
1
  import React, { forwardRef, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { useThemeTokensCallback } from '../ThemeProvider';
3
+ import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider';
4
4
  import { containUniqueFields, getTokensPropType, getPressHandlersWithArgs, selectTokens, useCopy, useMultipleInputValues, variantProp } from '../utils';
5
5
  import dictionary from './dictionary';
6
6
  import Box from '../Box';
@@ -8,21 +8,47 @@ import { Button, ButtonDropdown } from '../Button';
8
8
  import { CheckboxGroup } from '../Checkbox';
9
9
  import Divider from '../Divider';
10
10
  import FlexGrid from '../FlexGrid';
11
- import Modal from '../Modal';
12
11
  import Spacer from '../Spacer';
13
12
  import StackView from '../StackView';
14
13
  import Typography from '../Typography';
15
14
  import { TextButton } from '../Link';
15
+ import ModalOverlay from './ModalOverlay';
16
16
  import { jsx as _jsx } from "react/jsx-runtime";
17
- import { jsxs as _jsxs } from "react/jsx-runtime";
18
17
  import { Fragment as _Fragment } from "react/jsx-runtime";
18
+ import { jsxs as _jsxs } from "react/jsx-runtime";
19
19
  const {
20
20
  Col,
21
21
  Row
22
22
  } = FlexGrid;
23
- const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
23
+
24
+ const selectSubTitleTokens = _ref => {
25
+ let {
26
+ subtitleColor
27
+ } = _ref;
28
+ return {
29
+ color: subtitleColor
30
+ };
31
+ };
32
+
33
+ const selectDividerToknes = _ref2 => {
34
+ let {
35
+ dividerColor,
36
+ width,
37
+ decorative = true,
38
+ weight = 'thin'
39
+ } = _ref2;
40
+ return {
41
+ color: dividerColor,
42
+ width,
43
+ decorative,
44
+ weight
45
+ };
46
+ };
47
+
48
+ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref3, ref) => {
24
49
  let {
25
50
  label,
51
+ subtitle,
26
52
  id = label,
27
53
  variant,
28
54
  tokens,
@@ -36,7 +62,7 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
36
62
  inactive = false,
37
63
  rowLimit = 12,
38
64
  ...rest
39
- } = _ref;
65
+ } = _ref3;
40
66
  const {
41
67
  currentValues,
42
68
  setValues
@@ -47,6 +73,7 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
47
73
  onChange,
48
74
  readOnly
49
75
  });
76
+ const themeTokens = useThemeTokens('ButtonDropdown', tokens, variant);
50
77
  const getItemTokens = useThemeTokensCallback('ButtonDropdown', tokens, variant);
51
78
 
52
79
  const getButtonTokens = buttonState => selectTokens('Button', getItemTokens(buttonState));
@@ -74,7 +101,7 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
74
101
 
75
102
  const handleChange = event => {
76
103
  if (pressHandlers.onPress) pressHandlers === null || pressHandlers === void 0 ? void 0 : pressHandlers.onPress(event);
77
- setIsOpen(true);
104
+ setIsOpen(!isOpen);
78
105
  };
79
106
 
80
107
  const onApply = e => {
@@ -83,12 +110,20 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
83
110
  };
84
111
 
85
112
  return /*#__PURE__*/_jsxs(_Fragment, {
86
- children: [/*#__PURE__*/_jsxs(Modal, {
87
- isOpen: isOpen,
88
- onClose: () => setIsOpen(false),
113
+ children: [/*#__PURE__*/_jsx(ButtonDropdown, {
114
+ ref: ref,
115
+ ...pressHandlers,
116
+ value: isOpen,
117
+ selected: isSelected,
118
+ label: label,
119
+ onChange: handleChange,
120
+ tokens: getButtonTokens,
121
+ inactive: inactive
122
+ }, id), isOpen && /*#__PURE__*/_jsxs(ModalOverlay, {
89
123
  variant: {
90
124
  width: colSize > 1 ? 'size576' : 's'
91
125
  },
126
+ onClose: () => setIsOpen(false),
92
127
  children: [/*#__PURE__*/_jsx(Row, {
93
128
  children: /*#__PURE__*/_jsx(Typography, {
94
129
  variant: {
@@ -96,10 +131,20 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
96
131
  },
97
132
  children: getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())
98
133
  })
134
+ }), subtitle && /*#__PURE__*/_jsxs(_Fragment, {
135
+ children: [/*#__PURE__*/_jsx(Spacer, {
136
+ space: 5
137
+ }), /*#__PURE__*/_jsx(Row, {
138
+ children: /*#__PURE__*/_jsx(Typography, {
139
+ variant: {
140
+ size: 'h5'
141
+ },
142
+ tokens: selectSubTitleTokens(themeTokens),
143
+ children: subtitle
144
+ })
145
+ })]
99
146
  }), /*#__PURE__*/_jsx(Spacer, {
100
147
  space: 4
101
- }), /*#__PURE__*/_jsx(Spacer, {
102
- space: 1
103
148
  }), /*#__PURE__*/_jsx(Box, {
104
149
  scroll: true,
105
150
  children: /*#__PURE__*/_jsx(Row, {
@@ -116,12 +161,9 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
116
161
  }, i))
117
162
  })
118
163
  }), /*#__PURE__*/_jsx(Divider, {
119
- variant: {
120
- width: 'full',
121
- color: 'E3E6E8',
122
- decorative: true,
123
- weight: 'thin'
124
- },
164
+ variant: selectDividerToknes({ ...themeTokens,
165
+ width: 'full'
166
+ }),
125
167
  space: 4
126
168
  }), /*#__PURE__*/_jsx(Row, {
127
169
  children: /*#__PURE__*/_jsxs(StackView, {
@@ -145,16 +187,7 @@ const MultiSelectFilter = /*#__PURE__*/forwardRef((_ref, ref) => {
145
187
  })]
146
188
  })
147
189
  })]
148
- }), /*#__PURE__*/_jsx(ButtonDropdown, {
149
- ref: ref,
150
- ...pressHandlers,
151
- value: isOpen,
152
- selected: isSelected,
153
- label: label,
154
- onChange: handleChange,
155
- tokens: getButtonTokens,
156
- inactive: inactive
157
- }, id)]
190
+ })]
158
191
  });
159
192
  });
160
193
  MultiSelectFilter.displayName = 'MultiSelectFilter';
@@ -164,6 +197,11 @@ MultiSelectFilter.propTypes = {
164
197
  */
165
198
  label: PropTypes.string.isRequired,
166
199
 
200
+ /**
201
+ * The text for the subtitle
202
+ */
203
+ subtitle: PropTypes.string,
204
+
167
205
  /**
168
206
  * An optional unique string may be provided to identify the ButtonDropdown.
169
207
  * If not provided, the label is used.
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "@floating-ui/react-native": "^0.8.1",
12
12
  "@gorhom/portal": "^1.0.14",
13
13
  "@telus-uds/system-constants": "^1.2.0",
14
- "@telus-uds/system-theme-tokens": "^2.9.0",
14
+ "@telus-uds/system-theme-tokens": "^2.10.0",
15
15
  "airbnb-prop-types": "^2.16.0",
16
16
  "lodash.debounce": "^4.0.8",
17
17
  "lodash.merge": "^4.6.2",
@@ -72,5 +72,5 @@
72
72
  "standard-engine": {
73
73
  "skip": true
74
74
  },
75
- "version": "1.25.0"
75
+ "version": "1.26.0"
76
76
  }
@@ -174,7 +174,7 @@ const ButtonBase = forwardRef(
174
174
  ref
175
175
  ) => {
176
176
  const { onPress, ...rest } = clickProps.toPressProps(rawRest)
177
- const extraButtonState = { inactive, selected }
177
+ const extraButtonState = { inactive, selected, iconPosition }
178
178
  const resolveButtonTokens = (pressableState) =>
179
179
  resolvePressableTokens(tokens, pressableState, extraButtonState)
180
180
 
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { View, Animated, PanResponder, StyleSheet, Platform } from 'react-native'
2
+ import { View, Animated, PanResponder, StyleSheet, Platform, Dimensions } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
  import { useThemeTokens } from '../ThemeProvider'
5
5
  import { useViewport } from '../ViewportProvider'
@@ -145,6 +145,7 @@ const Carousel = React.forwardRef(
145
145
  children,
146
146
  itemLabel = 'item',
147
147
  previousNextNavigationPosition = 'inside',
148
+ stepTrackerVariant,
148
149
  previousNextIconSize = 'default',
149
150
  minDistanceToCapture = 5,
150
151
  minDistanceForAction = 0.2,
@@ -160,7 +161,7 @@ const Carousel = React.forwardRef(
160
161
  panelNavigation = thumbnails ? (
161
162
  <CarouselThumbnailNavigation thumbnails={thumbnails} />
162
163
  ) : (
163
- <CarouselStepTracker />
164
+ <CarouselStepTracker variant={stepTrackerVariant} />
164
165
  ),
165
166
  tag = 'ul',
166
167
  accessibilityRole,
@@ -220,6 +221,7 @@ const Carousel = React.forwardRef(
220
221
  y: 0,
221
222
  width: 0
222
223
  })
224
+
223
225
  const [previousNextNavigationButtonWidth, setPreviousNextNavigationButtonWidth] =
224
226
  React.useState(0)
225
227
  const firstFocusRef = React.useRef(null)
@@ -382,6 +384,14 @@ const Carousel = React.forwardRef(
382
384
  }
383
385
  }, [pan.x, pan.y])
384
386
 
387
+ React.useEffect(() => {
388
+ const subscription = Dimensions.addEventListener('change', () => {
389
+ updateOffset()
390
+ })
391
+
392
+ return () => subscription?.remove()
393
+ })
394
+
385
395
  const goToNext = React.useCallback(() => {
386
396
  goToNeighboring()
387
397
  }, [goToNeighboring])
@@ -563,6 +573,10 @@ Carousel.propTypes = {
563
573
  ...selectedSystemPropTypes,
564
574
  tokens: getTokensPropType('Carousel'),
565
575
  variant: variantProp.propType,
576
+ /**
577
+ * Prop related to StepTracker Variants
578
+ */
579
+ stepTrackerVariant: variantProp.propType,
566
580
  /**
567
581
  * Slides to render in Carousel. Wrap individual slides in `Carousel.Item`
568
582
  */
@@ -2,8 +2,9 @@ import React from 'react'
2
2
  import { useCarousel } from '../CarouselContext'
3
3
  import StepTracker from '../../StepTracker'
4
4
  import StackView from '../../StackView'
5
+ import { variantProp } from '../../utils'
5
6
 
6
- const CarouselStepTracker = () => {
7
+ const CarouselStepTracker = ({ variant }) => {
7
8
  const { activeIndex, totalItems, getCopyWithPlaceholders, themeTokens } = useCarousel()
8
9
  const stackViewTokens = {
9
10
  justifyContent: 'center'
@@ -28,9 +29,14 @@ const CarouselStepTracker = () => {
28
29
  stepTrackerLabel: getCopyWithPlaceholders('stepTrackerLabel')
29
30
  }}
30
31
  tokens={stepTrackerTokens}
32
+ variant={variant}
31
33
  />
32
34
  </StackView>
33
35
  )
34
36
  }
35
37
 
38
+ CarouselStepTracker.propTypes = {
39
+ variant: variantProp.propType
40
+ }
41
+
36
42
  export default CarouselStepTracker
@@ -0,0 +1,86 @@
1
+ import React, { forwardRef } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { View, StyleSheet } from 'react-native-web'
4
+ import { Portal } from '@gorhom/portal'
5
+ import { copyPropTypes, getTokensPropType, selectTokens, useCopy, variantProp } from '../utils'
6
+ import { useViewport } from '../ViewportProvider'
7
+ import { useThemeTokens } from '../ThemeProvider'
8
+ import dictionary from './dictionary'
9
+
10
+ import Card from '../Card'
11
+ import IconButton from '../IconButton'
12
+
13
+ const staticStyles = StyleSheet.create({
14
+ positioner: {
15
+ flex: 1, // Grow to maxWidth when possible, shrink when not possible
16
+ position: 'absolute',
17
+ height: 330,
18
+ paddingTop: 5,
19
+ zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
20
+ },
21
+ closeButtonContainer: {
22
+ position: 'absolute',
23
+ top: 0,
24
+ right: 0,
25
+ zIndex: 1
26
+ }
27
+ })
28
+
29
+ const selectCloseButtonContainerStyles = ({ paddingRight, paddingTop }) => ({
30
+ paddingRight,
31
+ paddingTop
32
+ })
33
+
34
+ const selectPaddingContainerStyles = ({ paddingTop, paddingLeft, paddingRight }) => ({
35
+ paddingBottom: 35,
36
+ paddingTop,
37
+ paddingLeft,
38
+ paddingRight
39
+ })
40
+
41
+ const ModalOverlay = forwardRef(({ children, tokens, variant, copy, onClose }, ref) => {
42
+ const viewport = useViewport()
43
+ const themeTokens = useThemeTokens('Modal', tokens, variant, { viewport, maxWidth: false })
44
+
45
+ const { closeIcon: CloseIconComponent, maxWidth } = themeTokens
46
+
47
+ const getCopy = useCopy({ dictionary, copy })
48
+ const closeLabel = getCopy('closeButton')
49
+
50
+ return (
51
+ <>
52
+ <Portal ref={ref}>
53
+ <View style={[{ minWidth: maxWidth }, staticStyles.positioner]}>
54
+ <Card tokens={selectPaddingContainerStyles(themeTokens)}>
55
+ <View
56
+ style={[
57
+ staticStyles.closeButtonContainer,
58
+ selectCloseButtonContainerStyles(themeTokens)
59
+ ]}
60
+ >
61
+ <IconButton
62
+ onPress={onClose}
63
+ icon={CloseIconComponent}
64
+ accessibilityRole="button"
65
+ accessibilityLabel={closeLabel}
66
+ tokens={selectTokens('IconButton', themeTokens, 'close')}
67
+ />
68
+ </View>
69
+ {children}
70
+ </Card>
71
+ </View>
72
+ </Portal>
73
+ </>
74
+ )
75
+ })
76
+ ModalOverlay.displayName = 'ModalOverlay'
77
+
78
+ ModalOverlay.propTypes = {
79
+ children: PropTypes.node.isRequired,
80
+ variant: variantProp.propType,
81
+ tokens: getTokensPropType('Modal'),
82
+ copy: copyPropTypes,
83
+ onClose: PropTypes.func
84
+ }
85
+
86
+ export default ModalOverlay
@@ -1,7 +1,7 @@
1
1
  import React, { forwardRef, useState } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
- import { useThemeTokensCallback } from '../ThemeProvider'
4
+ import { useThemeTokens, useThemeTokensCallback } from '../ThemeProvider'
5
5
  import {
6
6
  containUniqueFields,
7
7
  getTokensPropType,
@@ -18,18 +18,30 @@ import { Button, ButtonDropdown } from '../Button'
18
18
  import { CheckboxGroup } from '../Checkbox'
19
19
  import Divider from '../Divider'
20
20
  import FlexGrid from '../FlexGrid'
21
- import Modal from '../Modal'
22
21
  import Spacer from '../Spacer'
23
22
  import StackView from '../StackView'
24
23
  import Typography from '../Typography'
25
24
  import { TextButton } from '../Link'
25
+ import ModalOverlay from './ModalOverlay'
26
26
 
27
27
  const { Col, Row } = FlexGrid
28
28
 
29
+ const selectSubTitleTokens = ({ subtitleColor }) => ({
30
+ color: subtitleColor
31
+ })
32
+
33
+ const selectDividerToknes = ({ dividerColor, width, decorative = true, weight = 'thin' }) => ({
34
+ color: dividerColor,
35
+ width,
36
+ decorative,
37
+ weight
38
+ })
39
+
29
40
  const MultiSelectFilter = forwardRef(
30
41
  (
31
42
  {
32
43
  label,
44
+ subtitle,
33
45
  id = label,
34
46
  variant,
35
47
  tokens,
@@ -54,6 +66,7 @@ const MultiSelectFilter = forwardRef(
54
66
  readOnly
55
67
  })
56
68
 
69
+ const themeTokens = useThemeTokens('ButtonDropdown', tokens, variant)
57
70
  const getItemTokens = useThemeTokensCallback('ButtonDropdown', tokens, variant)
58
71
  const getButtonTokens = (buttonState) => selectTokens('Button', getItemTokens(buttonState))
59
72
  const getCopy = useCopy({ dictionary, copy })
@@ -74,7 +87,7 @@ const MultiSelectFilter = forwardRef(
74
87
 
75
88
  const handleChange = (event) => {
76
89
  if (pressHandlers.onPress) pressHandlers?.onPress(event)
77
- setIsOpen(true)
90
+ setIsOpen(!isOpen)
78
91
  }
79
92
 
80
93
  const onApply = (e) => {
@@ -84,52 +97,6 @@ const MultiSelectFilter = forwardRef(
84
97
 
85
98
  return (
86
99
  <>
87
- <Modal
88
- isOpen={isOpen}
89
- onClose={() => setIsOpen(false)}
90
- variant={{ width: colSize > 1 ? 'size576' : 's' }}
91
- >
92
- <Row>
93
- <Typography variant={{ size: 'h4' }}>
94
- {getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())}
95
- </Typography>
96
- </Row>
97
- <Spacer space={4} />
98
- <Spacer space={1} />
99
- <Box scroll={true}>
100
- <Row distribute="between">
101
- {[...Array(colSize).keys()].map((i) => (
102
- <Col xs={12 / colSize} key={i}>
103
- <CheckboxGroup
104
- items={items.slice(i * rowLimit, (i + 1) * rowLimit)}
105
- checkedIds={checkedIds}
106
- onChange={(e) => setCheckedIds(e, i)}
107
- />
108
- <Spacer size={4} />
109
- </Col>
110
- ))}
111
- </Row>
112
- </Box>
113
- <Divider
114
- variant={{ width: 'full', color: 'E3E6E8', decorative: true, weight: 'thin' }}
115
- space={4}
116
- />
117
- <Row>
118
- <StackView direction="row" space={3} tokens={{ alignItems: 'center' }}>
119
- <Button
120
- onPress={() => onApply(checkedIds)}
121
- variant={{ size: 'small', priority: 'high' }}
122
- >
123
- {getCopy('applyButtonLabel')}
124
- </Button>
125
- <Box>
126
- <TextButton onPress={() => setCheckedIds([])}>
127
- {getCopy('clearButtonLabel')}
128
- </TextButton>
129
- </Box>
130
- </StackView>
131
- </Row>
132
- </Modal>
133
100
  <ButtonDropdown
134
101
  ref={ref}
135
102
  key={id}
@@ -141,6 +108,59 @@ const MultiSelectFilter = forwardRef(
141
108
  tokens={getButtonTokens}
142
109
  inactive={inactive}
143
110
  />
111
+ {isOpen && (
112
+ <ModalOverlay
113
+ variant={{ width: colSize > 1 ? 'size576' : 's' }}
114
+ onClose={() => setIsOpen(false)}
115
+ >
116
+ <Row>
117
+ <Typography variant={{ size: 'h4' }}>
118
+ {getCopy('filterByLabel').replace(/%\{filterCategory\}/g, label.toLowerCase())}
119
+ </Typography>
120
+ </Row>
121
+ {subtitle && (
122
+ <>
123
+ <Spacer space={5} />
124
+ <Row>
125
+ <Typography variant={{ size: 'h5' }} tokens={selectSubTitleTokens(themeTokens)}>
126
+ {subtitle}
127
+ </Typography>
128
+ </Row>
129
+ </>
130
+ )}
131
+ <Spacer space={4} />
132
+ <Box scroll={true}>
133
+ <Row distribute="between">
134
+ {[...Array(colSize).keys()].map((i) => (
135
+ <Col xs={12 / colSize} key={i}>
136
+ <CheckboxGroup
137
+ items={items.slice(i * rowLimit, (i + 1) * rowLimit)}
138
+ checkedIds={checkedIds}
139
+ onChange={(e) => setCheckedIds(e, i)}
140
+ />
141
+ <Spacer size={4} />
142
+ </Col>
143
+ ))}
144
+ </Row>
145
+ </Box>
146
+ <Divider variant={selectDividerToknes({ ...themeTokens, width: 'full' })} space={4} />
147
+ <Row>
148
+ <StackView direction="row" space={3} tokens={{ alignItems: 'center' }}>
149
+ <Button
150
+ onPress={() => onApply(checkedIds)}
151
+ variant={{ size: 'small', priority: 'high' }}
152
+ >
153
+ {getCopy('applyButtonLabel')}
154
+ </Button>
155
+ <Box>
156
+ <TextButton onPress={() => setCheckedIds([])}>
157
+ {getCopy('clearButtonLabel')}
158
+ </TextButton>
159
+ </Box>
160
+ </StackView>
161
+ </Row>
162
+ </ModalOverlay>
163
+ )}
144
164
  </>
145
165
  )
146
166
  }
@@ -152,6 +172,10 @@ MultiSelectFilter.propTypes = {
152
172
  * The text displayed to the user in a ButtonDropdown.
153
173
  */
154
174
  label: PropTypes.string.isRequired,
175
+ /**
176
+ * The text for the subtitle
177
+ */
178
+ subtitle: PropTypes.string,
155
179
  /**
156
180
  * An optional unique string may be provided to identify the ButtonDropdown.
157
181
  * If not provided, the label is used.