@telus-uds/components-base 2.3.0 → 2.4.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.
@@ -61,10 +61,6 @@ const TextArea = /*#__PURE__*/React.forwardRef((_ref, ref) => {
61
61
  } = selectProps(rest);
62
62
  const inputProps = {
63
63
  ...selectedProps,
64
- variant: {
65
- ...variant,
66
- validation: supportsProps.validation
67
- },
68
64
  multiline: true,
69
65
  onContentSizeChange: onHeightChange,
70
66
  height: inputHeight,
@@ -72,6 +68,7 @@ const TextArea = /*#__PURE__*/React.forwardRef((_ref, ref) => {
72
68
  };
73
69
  return /*#__PURE__*/_jsx(InputSupports, {
74
70
  ...supportsProps,
71
+ inputValue: selectedProps === null || selectedProps === void 0 ? void 0 : selectedProps.value,
75
72
  children: _ref3 => {
76
73
  let {
77
74
  inputId,
@@ -79,9 +76,13 @@ const TextArea = /*#__PURE__*/React.forwardRef((_ref, ref) => {
79
76
  } = _ref3;
80
77
  return /*#__PURE__*/_jsx(TextInputBase, {
81
78
  ref: ref,
82
- ...inputProps,
83
79
  nativeID: inputId,
84
- ...props
80
+ ...props,
81
+ ...inputProps,
82
+ variant: {
83
+ ...variant,
84
+ validation: props.validation
85
+ }
85
86
  });
86
87
  }
87
88
  });
@@ -38,16 +38,13 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
38
38
  } = selectProps(rest);
39
39
  const inputProps = {
40
40
  ...selectedProps,
41
- tokens,
42
- variant: {
43
- ...variant,
44
- validation: supportsProps.validation
45
- }
41
+ tokens
46
42
  };
47
43
  return /*#__PURE__*/_jsxs(_Fragment, {
48
44
  children: [/*#__PURE__*/_jsx(InputSupports, {
49
45
  nativeID: nativeID,
50
46
  ...supportsProps,
47
+ inputValue: selectedProps === null || selectedProps === void 0 ? void 0 : selectedProps.value,
51
48
  children: _ref2 => {
52
49
  let {
53
50
  inputId,
@@ -57,7 +54,11 @@ const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
57
54
  ref: ref,
58
55
  nativeID: inputId,
59
56
  ...propsFromInputSupports,
60
- ...inputProps
57
+ ...inputProps,
58
+ variant: {
59
+ ...variant,
60
+ validation: propsFromInputSupports.validation
61
+ }
61
62
  });
62
63
  }
63
64
  }), rest.children]
@@ -37,6 +37,9 @@ const selectInputStyles = function (_ref, themeOptions, inactive, type) {
37
37
  let buttonSize = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
38
38
  let buttonsGapSize = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 0;
39
39
  let isPassword = arguments.length > 7 ? arguments[7] : undefined;
40
+ let iconLeftWidth = arguments.length > 8 ? arguments[8] : undefined;
41
+ let iconLeftGap = arguments.length > 9 ? arguments[9] : undefined;
42
+ let direction = arguments.length > 10 ? arguments[10] : undefined;
40
43
  // Subtract border width from padding so overall input width/height doesn't
41
44
  // jump around if the border width changes (avoiding NaN and negative padding)
42
45
  const offsetBorder = value => typeof value === 'number' ? Math.max(0, value - borderWidth) : value;
@@ -63,6 +66,15 @@ const selectInputStyles = function (_ref, themeOptions, inactive, type) {
63
66
  resize: minHeight !== maxHeight ? 'vertical' : 'none' // does nothing for an input, only needed for textarea
64
67
  }
65
68
  });
69
+ const getPaddingLeft = () => {
70
+ if (type === 'card') {
71
+ return offsetBorder(paddingLeft + 34);
72
+ }
73
+ if (direction === 'left') {
74
+ return offsetBorder(iconLeftWidth + iconLeftGap + staticStyles.iconLeftContainer.paddingLeft);
75
+ }
76
+ return offsetBorder(paddingLeft);
77
+ };
66
78
  const buttonSpacing = isPassword ? buttonsGapSize : -buttonsGapSize;
67
79
  const adjustedPaddingRight = paddingRight + (buttonCount ? 1 : 0) * (buttonSize + buttonSpacing);
68
80
  const adjustedPaddingWithButtons = buttonCount > 1 ? paddingRight : adjustedPaddingRight;
@@ -73,7 +85,7 @@ const selectInputStyles = function (_ref, themeOptions, inactive, type) {
73
85
  borderWidth,
74
86
  borderColor,
75
87
  borderRadius,
76
- paddingLeft: type === 'card' ? offsetBorder(paddingLeft + 34) : offsetBorder(paddingLeft),
88
+ paddingLeft: getPaddingLeft(),
77
89
  paddingRight: icon ? offsetBorder(paddingWithIcon) : offsetBorder(adjustedPaddingWithButtons),
78
90
  paddingTop: offsetBorder(paddingTop),
79
91
  paddingBottom: offsetBorder(paddingBottom),
@@ -123,20 +135,26 @@ const selectIconContainerStyles = (_ref4, buttonCount) => {
123
135
  paddingBottom
124
136
  };
125
137
  };
126
- const selectLeftIconContainerStyles = _ref5 => {
138
+ const selectIconCardLeftContainerStyles = _ref5 => {
127
139
  let {
128
140
  leftIconPaddingBottom
129
141
  } = _ref5;
130
142
  return {
131
- // not tokenizing paddingLeft as it remains same across brands for now
132
- paddingLeft: 10,
133
143
  paddingBottom: leftIconPaddingBottom
134
144
  };
135
145
  };
136
- const selectButtonsContainerStyle = _ref6 => {
146
+ const selectIconLeftContainerStyles = _ref6 => {
137
147
  let {
138
- buttonsPaddingRight
148
+ iconLeftPaddingBottom
139
149
  } = _ref6;
150
+ return {
151
+ paddingBottom: iconLeftPaddingBottom
152
+ };
153
+ };
154
+ const selectButtonsContainerStyle = _ref7 => {
155
+ let {
156
+ buttonsPaddingRight
157
+ } = _ref7;
140
158
  return {
141
159
  paddingRight: buttonsPaddingRight
142
160
  };
@@ -180,7 +198,7 @@ const getIcon = function () {
180
198
  testID: selectedIcon.testID
181
199
  });
182
200
  };
183
- const TextInputBase = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
201
+ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref8, ref) => {
184
202
  let {
185
203
  buttons = [],
186
204
  copy = 'en',
@@ -201,8 +219,9 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
201
219
  variant = {},
202
220
  type,
203
221
  onKeyPress,
222
+ direction,
204
223
  ...rest
205
- } = _ref7;
224
+ } = _ref8;
206
225
  const [isFocused, setIsFocused] = React.useState(false);
207
226
  const [showPassword, setShowPassword] = React.useState(false);
208
227
  const handleFocus = event => {
@@ -288,14 +307,16 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
288
307
  defaultCreditIcon,
289
308
  amexIcon,
290
309
  visaIcon,
291
- masterCardIcon
310
+ masterCardIcon,
311
+ iconLeftGap
292
312
  } = themeTokens;
293
313
  const buttonsGapSize = useSpacingScale(buttonsGap);
294
314
  const getCopy = useCopy({
295
315
  dictionary,
296
316
  copy
297
317
  });
298
- const textInputButtons = buttons;
318
+ const textInputButtons = direction === 'left' ? buttons.filter(button => button && button.key !== 'submitIcon') : buttons;
319
+ const submitIcon = direction === 'left' ? buttons.find(button => button && button.key === 'submitIcon') : null;
299
320
  if (onClear && isDirty) {
300
321
  textInputButtons === null || textInputButtons === void 0 || textInputButtons.unshift(/*#__PURE__*/_jsx(IconButton, {
301
322
  accessibilityLabel: getCopy('clearButtonAccessibilityLabel'),
@@ -339,15 +360,20 @@ const TextInputBase = /*#__PURE__*/React.forwardRef((_ref7, ref) => {
339
360
  const {
340
361
  themeOptions
341
362
  } = useTheme();
363
+ const iconLeftWidth = submitIcon ? submitIcon.props.tokens.size ?? 0 : 0;
342
364
  const nativeInputStyle = selectInputStyles({
343
365
  ...themeTokens,
344
366
  height
345
- }, themeOptions, inactive, type, buttons === null || buttons === void 0 ? void 0 : buttons.length, themeTokens.buttonSize, buttonsGapSize, isPassword);
367
+ }, themeOptions, inactive, type, buttons === null || buttons === void 0 ? void 0 : buttons.length, themeTokens.buttonSize, buttonsGapSize, isPassword, iconLeftWidth, iconLeftGap, direction);
368
+ const shouldShowSubmitIcon = submitIcon && direction === 'left' && !inactive;
346
369
  return /*#__PURE__*/_jsxs(View, {
347
370
  style: selectOuterBorderStyles(themeTokens),
348
- children: [type === 'card' && /*#__PURE__*/_jsx(View, {
371
+ children: [shouldShowSubmitIcon && /*#__PURE__*/_jsx(View, {
372
+ style: [staticStyles.iconLeftContainer, selectIconLeftContainerStyles(themeTokens)],
373
+ children: submitIcon
374
+ }), type === 'card' && /*#__PURE__*/_jsx(View, {
349
375
  pointerEvents: "none",
350
- style: [staticStyles.leftIconContainer, selectLeftIconContainerStyles(themeTokens)],
376
+ style: [staticStyles.iconCardLeftContainer, selectIconCardLeftContainerStyles(themeTokens)],
351
377
  children: getIcon(currentValue, {
352
378
  defaultCreditIcon,
353
379
  amexIcon,
@@ -425,7 +451,15 @@ const staticStyles = StyleSheet.create({
425
451
  right: 0,
426
452
  bottom: 0
427
453
  },
428
- leftIconContainer: {
454
+ iconCardLeftContainer: {
455
+ paddingLeft: 10,
456
+ position: 'absolute',
457
+ left: 0,
458
+ bottom: 0,
459
+ zIndex: 1
460
+ },
461
+ iconLeftContainer: {
462
+ paddingLeft: 10,
429
463
  position: 'absolute',
430
464
  left: 0,
431
465
  bottom: 0,
@@ -37,7 +37,15 @@ export default {
37
37
  /**
38
38
  * Use to visually mark an input as valid or invalid.
39
39
  */
40
- validation: PropTypes.oneOf(['error', 'success'])
40
+ validation: PropTypes.oneOf(['error', 'success']),
41
+ /**
42
+ * The text value from an input field.
43
+ */
44
+ inputValue: PropTypes.string,
45
+ /**
46
+ * Max number of characters allowed id an input text.
47
+ */
48
+ maxCharacterAllowed: PropTypes.number
41
49
  },
42
50
  select: _ref => {
43
51
  let {
@@ -49,7 +57,9 @@ export default {
49
57
  feedbackTokens,
50
58
  feedbackProps,
51
59
  tooltip,
52
- validation
60
+ validation,
61
+ inputValue,
62
+ maxCharacterAllowed
53
63
  } = _ref;
54
64
  return {
55
65
  supportsProps: {
@@ -61,7 +71,9 @@ export default {
61
71
  feedbackTokens,
62
72
  feedbackProps,
63
73
  tooltip,
64
- validation
74
+ validation,
75
+ inputValue,
76
+ maxCharacterAllowed
65
77
  }
66
78
  };
67
79
  }
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "@gorhom/portal": "^1.0.14",
14
14
  "@react-native-picker/picker": "^2.9.0",
15
15
  "@telus-uds/system-constants": "^2.0.0",
16
- "@telus-uds/system-theme-tokens": "^3.2.0",
16
+ "@telus-uds/system-theme-tokens": "^3.3.0",
17
17
  "airbnb-prop-types": "^2.16.0",
18
18
  "css-mediaquery": "^0.1.2",
19
19
  "expo-document-picker": "^13.0.1",
@@ -81,6 +81,6 @@
81
81
  "standard-engine": {
82
82
  "skip": true
83
83
  },
84
- "version": "2.3.0",
84
+ "version": "2.4.0",
85
85
  "types": "types/index.d.ts"
86
86
  }
@@ -47,6 +47,8 @@ const InputLabel = React.forwardRef(
47
47
  tooltip,
48
48
  tokens,
49
49
  variant,
50
+ characterCount,
51
+ maxCharacterAllowed,
50
52
  ...rest
51
53
  },
52
54
  ref
@@ -95,12 +97,30 @@ const InputLabel = React.forwardRef(
95
97
  <Tooltip content={tooltip} copy={copy} />
96
98
  </View>
97
99
  )}
100
+ {maxCharacterAllowed && isHintInline && (
101
+ <Text style={[selectHintStyles({ ...themeTokens }), staticStyles.characterCountlabel]}>
102
+ {characterCount}/{maxCharacterAllowed}
103
+ </Text>
104
+ )}
98
105
  </View>
99
- {hint && !isHintInline && (
106
+ {hint && !maxCharacterAllowed && !isHintInline && (
100
107
  <Text style={[selectHintStyles(themeTokens), staticStyles.hintBelow]} nativeID={hintId}>
101
108
  {hint}
102
109
  </Text>
103
110
  )}
111
+ {hint && maxCharacterAllowed && !isHintInline && (
112
+ <View style={staticStyles.container}>
113
+ <Text
114
+ style={[selectHintStyles(themeTokens), staticStyles.flexHintBelow]}
115
+ nativeID={hintId}
116
+ >
117
+ {hint}
118
+ </Text>
119
+ <Text style={[selectHintStyles(themeTokens), staticStyles.characterCountlabel]}>
120
+ {characterCount}/{maxCharacterAllowed}
121
+ </Text>
122
+ </View>
123
+ )}
104
124
  </>
105
125
  )
106
126
  }
@@ -137,6 +157,14 @@ InputLabel.propTypes = {
137
157
  * Content of an optional `Tooltip`. If set, a tooltip button will be shown next to the label.
138
158
  */
139
159
  tooltip: PropTypes.string,
160
+ /**
161
+ * Current number of characterts of an input text.
162
+ */
163
+ characterCount: PropTypes.number,
164
+ /**
165
+ * Max number of characters that allows an input text.
166
+ */
167
+ maxCharacterAllowed: PropTypes.number,
140
168
  tokens: getTokensPropType('InputLabel'),
141
169
  variant: variantProp.propType
142
170
  }
@@ -148,13 +176,22 @@ const staticStyles = StyleSheet.create({
148
176
  flexShrink: 1,
149
177
  flexDirection: 'row'
150
178
  },
179
+ characterCountlabel: {
180
+ marginLeft: 'auto',
181
+ marginTop: 'auto'
182
+ },
151
183
  label: {
152
- flexShrink: 1
184
+ flexShrink: 1,
185
+ alignSelf: 'center'
153
186
  },
154
187
  hintBelow: {
155
188
  flexBasis: '100%',
156
189
  flexShrink: 0
157
190
  },
191
+ flexHintBelow: {
192
+ flexBasis: '100%',
193
+ flexShrink: 1
194
+ },
158
195
  tooltipAlign: {
159
196
  alignSelf: 'center',
160
197
  justifyContent: 'center'
@@ -6,7 +6,8 @@ import Feedback from '../Feedback'
6
6
  import StackView from '../StackView'
7
7
  import { useThemeTokens } from '../ThemeProvider'
8
8
  import useInputSupports from './useInputSupports'
9
- import { getTokensPropType } from '../utils'
9
+ import { getTokensPropType, useCopy } from '../utils'
10
+ import dictionary from './dictionary'
10
11
 
11
12
  const InputSupports = React.forwardRef(
12
13
  (
@@ -21,18 +22,31 @@ const InputSupports = React.forwardRef(
21
22
  feedbackProps = {},
22
23
  tooltip,
23
24
  validation,
25
+ maxCharacterAllowed,
26
+ inputValue,
24
27
  nativeID
25
28
  },
26
29
  ref
27
30
  ) => {
28
31
  const { space } = useThemeTokens('InputSupports')
32
+ const getCopy = useCopy({ dictionary, copy })
33
+
34
+ const maxCharsReachedErrorMessage =
35
+ inputValue?.length > maxCharacterAllowed
36
+ ? getCopy('maxCharsMessage').replace(/%\{charCount\}/g, maxCharacterAllowed)
37
+ : ''
38
+
39
+ const feedbackValidation = inputValue?.length > maxCharacterAllowed ? 'error' : validation
29
40
 
30
41
  const { inputId, hintId, feedbackId, a11yProps } = useInputSupports({
31
42
  feedback,
32
43
  hint,
33
44
  label,
34
45
  validation,
35
- nativeID
46
+ nativeID,
47
+ copy,
48
+ maxCharacterAllowed,
49
+ charactersCount: maxCharacterAllowed - inputValue?.length
36
50
  })
37
51
 
38
52
  return (
@@ -46,14 +60,18 @@ const InputSupports = React.forwardRef(
46
60
  hintId={hintId}
47
61
  tooltip={tooltip}
48
62
  forId={inputId}
63
+ characterCount={inputValue?.length}
64
+ maxCharacterAllowed={maxCharacterAllowed}
49
65
  />
50
66
  )}
51
- {typeof children === 'function' ? children({ inputId, ...a11yProps }) : children}
52
- {feedback ? (
67
+ {typeof children === 'function'
68
+ ? children({ inputId, ...a11yProps, validation: feedbackValidation })
69
+ : children}
70
+ {feedback || maxCharsReachedErrorMessage ? (
53
71
  <Feedback
54
72
  id={feedbackId}
55
- title={feedback}
56
- validation={validation}
73
+ title={feedback || maxCharsReachedErrorMessage}
74
+ validation={feedbackValidation}
57
75
  tokens={feedbackTokens}
58
76
  variant={{ icon: feedbackProps.showFeedbackIcon }}
59
77
  {...feedbackProps}
@@ -107,7 +125,15 @@ InputSupports.propTypes = {
107
125
  /**
108
126
  * ID for DOM element on web
109
127
  */
110
- nativeID: PropTypes.string
128
+ nativeID: PropTypes.string,
129
+ /**
130
+ * The text value of a TextArea or TextInput
131
+ */
132
+ inputValue: PropTypes.string,
133
+ /**
134
+ * Max number of characters that allows an input text.
135
+ */
136
+ maxCharacterAllowed: PropTypes.number
111
137
  }
112
138
 
113
139
  export default InputSupports
@@ -0,0 +1,12 @@
1
+ export default {
2
+ en: {
3
+ maxCharacters: 'Maximum %{charCount} characters',
4
+ charactersRemaining: '%{charCount} characters remaining',
5
+ maxCharsMessage: 'Must not exceed %{charCount} characters'
6
+ },
7
+ fr: {
8
+ maxCharacters: '%{charCount} caractères maximum',
9
+ charactersRemaining: '%{charCount} caractères restants',
10
+ maxCharsMessage: 'Ne doit pas dépasser %{charCount} caractères'
11
+ }
12
+ }
@@ -1,8 +1,20 @@
1
1
  import useUniqueId from '../utils/useUniqueId'
2
+ import { useCopy } from '../utils'
3
+ import dictionary from './dictionary'
2
4
 
3
5
  const joinDefined = (array) => array.filter((item) => item !== undefined).join(' ')
4
6
 
5
- const useInputSupports = ({ label, feedback, validation, hint, nativeID }) => {
7
+ const useInputSupports = ({
8
+ label,
9
+ feedback,
10
+ validation,
11
+ hint,
12
+ nativeID,
13
+ copy,
14
+ maxCharacterAllowed,
15
+ charactersCount
16
+ }) => {
17
+ const getCopy = useCopy({ dictionary, copy })
6
18
  const hasValidationError = validation === 'error'
7
19
 
8
20
  const inputId = useUniqueId('input')
@@ -11,10 +23,19 @@ const useInputSupports = ({ label, feedback, validation, hint, nativeID }) => {
11
23
 
12
24
  const a11yProps = {
13
25
  accessibilityLabel: label,
14
- accessibilityHint: joinDefined([!hasValidationError && feedback, hint]), // native only -> replaced with describedBy on web
26
+ accessibilityHint: joinDefined([
27
+ !hasValidationError && feedback,
28
+ hint,
29
+ maxCharacterAllowed
30
+ ? getCopy('maxCharacters').replace(/%\{charCount\}/g, maxCharacterAllowed)
31
+ : undefined
32
+ ]), // native only -> replaced with describedBy on web
15
33
  accessibilityDescribedBy: joinDefined([
16
34
  !hasValidationError && feedback && feedbackId, // feedback receives a11yRole=alert on error, so there's no need to include it here
17
- hint && hintId
35
+ hint && hintId,
36
+ charactersCount
37
+ ? getCopy('charactersRemaining').replace(/%\{charCount\}/g, charactersCount)
38
+ : undefined
18
39
  ]),
19
40
  accessibilityInvalid: hasValidationError
20
41
  }
@@ -32,21 +32,15 @@ const selectOuterBorderStyles = ({
32
32
  outerBorderGap,
33
33
  borderRadius,
34
34
  outerBorderOutline
35
- }) =>
36
- // A view wrapper with a border on native messes up inline text alignment
37
- // so for now make focus styles strictly web-only
38
- Platform.OS === 'web'
39
- ? {
40
- // Allow theme to define outline, or, turn off outline and use border if rounded corners required
41
- outline: outerBorderOutline,
42
- ...applyOuterBorder({
43
- outerBorderColor,
44
- outerBorderWidth,
45
- outerBorderGap
46
- }),
47
- borderRadius
48
- }
49
- : {}
35
+ }) => ({
36
+ outline: outerBorderOutline,
37
+ ...applyOuterBorder({
38
+ outerBorderColor,
39
+ outerBorderWidth,
40
+ outerBorderGap
41
+ }),
42
+ borderRadius
43
+ })
50
44
 
51
45
  const selectTextStyles = ({ color, blockFontSize }) => {
52
46
  return {
@@ -174,6 +168,7 @@ const LinkBase = React.forwardRef(
174
168
  const decorationStyles = selectDecorationStyles(themeTokens)
175
169
  return [
176
170
  outerBorderStyles,
171
+ staticStyles.outerBorderStyles,
177
172
  blockLeftStyle,
178
173
  decorationStyles,
179
174
  hasIcon && staticStyles.rowContainer
@@ -273,6 +268,13 @@ const staticStyles = StyleSheet.create({
273
268
  pointerEvents: 'none'
274
269
  }
275
270
  })
271
+ },
272
+ outerBorderStyles: {
273
+ ...(Platform.OS !== 'web' && {
274
+ margin: 0,
275
+ marginHorizontal: 2,
276
+ padding: 0
277
+ })
276
278
  }
277
279
  })
278
280
 
@@ -149,7 +149,7 @@ const Modal = React.forwardRef(
149
149
  a[href], button, textarea, input, select,
150
150
  [tabindex]:not([tabindex="-1"]),
151
151
  [contenteditable="true"]
152
- `)
152
+ `) || []
153
153
  )
154
154
 
155
155
  const firstElement = focusableElements[0]
@@ -30,14 +30,6 @@ import ModalOverlay from './ModalOverlay'
30
30
 
31
31
  const { Col, Row } = FlexGrid
32
32
 
33
- const selectSubTitleTokens = ({ subtitleColor }) => ({
34
- color: subtitleColor
35
- })
36
-
37
- const selectDividerTokens = ({ dividerColor }) => ({
38
- color: dividerColor
39
- })
40
-
41
33
  const selectHeaderTokens = ({
42
34
  contentMarginLeft,
43
35
  contentMarginRight,
@@ -113,23 +105,6 @@ const MultiSelectFilter = React.forwardRef(
113
105
  const [checkedIds, setCheckedIds] = React.useState(currentValues ?? [])
114
106
  const [maxWidth, setMaxWidth] = React.useState(false)
115
107
 
116
- const themeTokens = useThemeTokens('ButtonDropdown', tokens, variant)
117
- const getItemTokens = useThemeTokensCallback('ButtonDropdown', tokens, variant)
118
- const getButtonTokens = (buttonState) => selectTokens('Button', getItemTokens(buttonState))
119
- const getCopy = useCopy({ dictionary, copy })
120
- const colSizeNotMobile = items.length > rowLimit ? 2 : 1
121
- const colSize = viewport !== 'xs' ? colSizeNotMobile : 1
122
- const itemsLengthNotMobile = items.length > 24 ? items.length / 2 : rowLimit
123
- const isSelected = currentValues.length > 0
124
- const rowLength = viewport !== 'xs' ? itemsLengthNotMobile : items.length
125
-
126
- React.useEffect(() => {
127
- if (colSize === 1) return setMaxWidth(false)
128
- return colSize === 2 && setMaxWidth(true)
129
- }, [colSize])
130
-
131
- React.useEffect(() => setCheckedIds(currentValues ?? []), [currentValues])
132
-
133
108
  const {
134
109
  headerFontColor,
135
110
  headerFontSize,
@@ -143,6 +118,20 @@ const MultiSelectFilter = React.forwardRef(
143
118
  subHeaderLineHeight,
144
119
  minHeight,
145
120
  minWidth,
121
+ labelFontName,
122
+ labelFontSize,
123
+ labelFontWeight,
124
+ labelColor,
125
+ labelLineHeight,
126
+ labelPaddingTop,
127
+ labelPaddingBottom,
128
+ labelPaddingLeft,
129
+ labelPaddingRight,
130
+ buttonBorderColor,
131
+ buttonIconSize,
132
+ buttonIconPadding,
133
+ subtitleColor,
134
+ dividerColor,
146
135
  ...restTokens
147
136
  } = useThemeTokens(
148
137
  'MultiSelectFilter',
@@ -150,6 +139,40 @@ const MultiSelectFilter = React.forwardRef(
150
139
  { ...variant, maxHeight, maxWidth },
151
140
  { viewport }
152
141
  )
142
+ const dropdownTokens = {
143
+ borderColor: buttonBorderColor,
144
+ iconSize: buttonIconSize,
145
+ iconPadding: buttonIconPadding,
146
+ lineHeight: labelLineHeight,
147
+ fontName: labelFontName,
148
+ fontSize: labelFontSize,
149
+ fontWeight: labelFontWeight,
150
+ color: labelColor,
151
+ paddingTop: labelPaddingTop,
152
+ paddingBottom: labelPaddingBottom,
153
+ paddingLeft: labelPaddingLeft,
154
+ paddingRight: labelPaddingRight
155
+ }
156
+ const getButtonDropdownTokens = useThemeTokensCallback(
157
+ 'ButtonDropdown',
158
+ dropdownTokens,
159
+ variant
160
+ )
161
+ const getButtonTokens = (buttonState) =>
162
+ selectTokens('ButtonDropdown', getButtonDropdownTokens(buttonState))
163
+ const getCopy = useCopy({ dictionary, copy })
164
+ const colSizeNotMobile = items.length > rowLimit ? 2 : 1
165
+ const colSize = viewport !== 'xs' ? colSizeNotMobile : 1
166
+ const itemsLengthNotMobile = items.length > 24 ? items.length / 2 : rowLimit
167
+ const isSelected = currentValues.length > 0
168
+ const rowLength = viewport !== 'xs' ? itemsLengthNotMobile : items.length
169
+
170
+ React.useEffect(() => {
171
+ if (colSize === 1) return setMaxWidth(false)
172
+ return colSize === 2 && setMaxWidth(true)
173
+ }, [colSize])
174
+
175
+ React.useEffect(() => setCheckedIds(currentValues ?? []), [currentValues])
153
176
 
154
177
  const uniqueFields = ['id', 'label']
155
178
  if (!containUniqueFields(items, uniqueFields)) {
@@ -199,7 +222,7 @@ const MultiSelectFilter = React.forwardRef(
199
222
  const subeHeaderStyles = applyTextStyles({
200
223
  fontSize: subHeaderFontSize,
201
224
  fontWeight: subHeaderFontWeight,
202
- fontColor: selectSubTitleTokens(themeTokens)
225
+ fontColor: subtitleColor
203
226
  })
204
227
 
205
228
  const { overlaidPosition, onTargetLayout, isReady, sourceRef } = useOverlaidPosition({
@@ -275,7 +298,12 @@ const MultiSelectFilter = React.forwardRef(
275
298
  const controlsContent = (
276
299
  <>
277
300
  {isScrolling ? (
278
- <Divider tokens={selectDividerTokens(themeTokens)} space={4} />
301
+ <Divider
302
+ tokens={{
303
+ color: dividerColor
304
+ }}
305
+ space={4}
306
+ />
279
307
  ) : (
280
308
  <Spacer space={4} />
281
309
  )}