@telus-uds/components-base 1.12.0 → 1.14.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 (132) hide show
  1. package/CHANGELOG.md +41 -2
  2. package/component-docs.json +933 -55
  3. package/lib/BaseProvider/index.js +7 -2
  4. package/lib/Button/ButtonBase.js +52 -19
  5. package/lib/Button/ButtonGroup.js +7 -0
  6. package/lib/Button/propTypes.js +18 -0
  7. package/lib/Carousel/Carousel.js +83 -58
  8. package/lib/Carousel/CarouselContext.js +22 -8
  9. package/lib/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +73 -0
  10. package/lib/Carousel/CarouselStepTracker/CarouselStepTracker.js +56 -0
  11. package/lib/Carousel/CarouselStepTracker/index.js +13 -0
  12. package/lib/Carousel/CarouselTabs/CarouselTabs.js +70 -0
  13. package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +95 -0
  14. package/lib/Carousel/CarouselTabs/CarouselTabsPanelItem.js +148 -0
  15. package/lib/Carousel/CarouselTabs/index.js +13 -0
  16. package/lib/Carousel/CarouselThumbnail.js +99 -0
  17. package/lib/Carousel/CarouselThumbnailNavigation.js +87 -0
  18. package/lib/Carousel/dictionary.js +4 -2
  19. package/lib/Carousel/index.js +10 -1
  20. package/lib/Checkbox/Checkbox.js +7 -3
  21. package/lib/Checkbox/CheckboxGroup.js +8 -1
  22. package/lib/Feedback/Feedback.js +18 -10
  23. package/lib/Icon/IconText.js +6 -1
  24. package/lib/InputLabel/InputLabel.js +11 -5
  25. package/lib/Link/InlinePressable.js +1 -8
  26. package/lib/Link/LinkBase.js +13 -10
  27. package/lib/List/ListItem.js +8 -4
  28. package/lib/Notification/Notification.js +44 -24
  29. package/lib/Pagination/Pagination.js +7 -3
  30. package/lib/Radio/RadioGroup.js +8 -0
  31. package/lib/RadioCard/RadioCard.js +6 -1
  32. package/lib/RadioCard/RadioCardGroup.js +7 -0
  33. package/lib/Select/Select.js +7 -3
  34. package/lib/SkipLink/SkipLink.js +216 -0
  35. package/lib/SkipLink/index.js +13 -0
  36. package/lib/StepTracker/Step.js +8 -4
  37. package/lib/StepTracker/StepTracker.js +7 -3
  38. package/lib/Tabs/TabsItem.js +4 -0
  39. package/lib/TextInput/TextInputBase.js +7 -3
  40. package/lib/ThemeProvider/ThemeProvider.js +25 -3
  41. package/lib/ThemeProvider/utils/styles.js +8 -1
  42. package/lib/ThemeProvider/utils/theme-tokens.js +1 -1
  43. package/lib/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  44. package/lib/Typography/Typography.js +6 -2
  45. package/lib/index.js +9 -0
  46. package/lib-module/BaseProvider/index.js +7 -2
  47. package/lib-module/Button/ButtonBase.js +41 -9
  48. package/lib-module/Button/ButtonGroup.js +7 -0
  49. package/lib-module/Button/propTypes.js +17 -0
  50. package/lib-module/Carousel/Carousel.js +80 -57
  51. package/lib-module/Carousel/CarouselContext.js +21 -8
  52. package/lib-module/Carousel/CarouselFirstFocus/CarouselFirstFocus.js +51 -0
  53. package/lib-module/Carousel/CarouselStepTracker/CarouselStepTracker.js +42 -0
  54. package/lib-module/Carousel/CarouselStepTracker/index.js +2 -0
  55. package/lib-module/Carousel/CarouselTabs/CarouselTabs.js +50 -0
  56. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanel.js +76 -0
  57. package/lib-module/Carousel/CarouselTabs/CarouselTabsPanelItem.js +126 -0
  58. package/lib-module/Carousel/CarouselTabs/index.js +2 -0
  59. package/lib-module/Carousel/CarouselThumbnail.js +85 -0
  60. package/lib-module/Carousel/CarouselThumbnailNavigation.js +66 -0
  61. package/lib-module/Carousel/dictionary.js +4 -2
  62. package/lib-module/Carousel/index.js +2 -1
  63. package/lib-module/Checkbox/Checkbox.js +8 -4
  64. package/lib-module/Checkbox/CheckboxGroup.js +8 -1
  65. package/lib-module/Feedback/Feedback.js +19 -11
  66. package/lib-module/Icon/IconText.js +6 -1
  67. package/lib-module/InputLabel/InputLabel.js +12 -6
  68. package/lib-module/Link/InlinePressable.js +1 -8
  69. package/lib-module/Link/LinkBase.js +14 -11
  70. package/lib-module/List/ListItem.js +9 -5
  71. package/lib-module/Notification/Notification.js +46 -26
  72. package/lib-module/Pagination/Pagination.js +8 -4
  73. package/lib-module/Radio/RadioGroup.js +8 -0
  74. package/lib-module/RadioCard/RadioCard.js +7 -2
  75. package/lib-module/RadioCard/RadioCardGroup.js +7 -0
  76. package/lib-module/Select/Select.js +8 -4
  77. package/lib-module/SkipLink/SkipLink.js +188 -0
  78. package/lib-module/SkipLink/index.js +2 -0
  79. package/lib-module/StepTracker/Step.js +9 -5
  80. package/lib-module/StepTracker/StepTracker.js +8 -4
  81. package/lib-module/Tabs/TabsItem.js +5 -1
  82. package/lib-module/TextInput/TextInputBase.js +8 -4
  83. package/lib-module/ThemeProvider/ThemeProvider.js +24 -3
  84. package/lib-module/ThemeProvider/utils/styles.js +8 -1
  85. package/lib-module/ThemeProvider/utils/theme-tokens.js +1 -1
  86. package/lib-module/ToggleSwitch/ToggleSwitchGroup.js +7 -0
  87. package/lib-module/Typography/Typography.js +7 -3
  88. package/lib-module/index.js +1 -0
  89. package/package.json +46 -47
  90. package/src/BaseProvider/index.jsx +6 -3
  91. package/src/Button/ButtonBase.jsx +36 -12
  92. package/src/Button/ButtonGroup.jsx +6 -0
  93. package/src/Button/propTypes.js +14 -0
  94. package/src/Carousel/Carousel.jsx +91 -64
  95. package/src/Carousel/CarouselContext.jsx +29 -5
  96. package/src/Carousel/CarouselFirstFocus/CarouselFirstFocus.jsx +49 -0
  97. package/src/Carousel/CarouselStepTracker/CarouselStepTracker.jsx +36 -0
  98. package/src/Carousel/CarouselStepTracker/index.js +3 -0
  99. package/src/Carousel/CarouselTabs/CarouselTabs.jsx +37 -0
  100. package/src/Carousel/CarouselTabs/CarouselTabsPanel.jsx +69 -0
  101. package/src/Carousel/CarouselTabs/CarouselTabsPanelItem.jsx +119 -0
  102. package/src/Carousel/CarouselTabs/index.js +3 -0
  103. package/src/Carousel/CarouselThumbnail.jsx +77 -0
  104. package/src/Carousel/CarouselThumbnailNavigation.jsx +53 -0
  105. package/src/Carousel/dictionary.js +4 -2
  106. package/src/Carousel/index.js +1 -0
  107. package/src/Checkbox/Checkbox.jsx +14 -11
  108. package/src/Checkbox/CheckboxGroup.jsx +8 -1
  109. package/src/Feedback/Feedback.jsx +14 -7
  110. package/src/Icon/IconText.jsx +3 -1
  111. package/src/InputLabel/InputLabel.jsx +13 -12
  112. package/src/Link/InlinePressable.jsx +2 -8
  113. package/src/Link/LinkBase.jsx +18 -21
  114. package/src/List/ListItem.jsx +10 -5
  115. package/src/Notification/Notification.jsx +40 -23
  116. package/src/Pagination/Pagination.jsx +6 -4
  117. package/src/Radio/RadioGroup.jsx +7 -0
  118. package/src/RadioCard/RadioCard.jsx +3 -2
  119. package/src/RadioCard/RadioCardGroup.jsx +6 -0
  120. package/src/Select/Select.jsx +12 -3
  121. package/src/SkipLink/SkipLink.jsx +179 -0
  122. package/src/SkipLink/index.js +3 -0
  123. package/src/StepTracker/Step.jsx +12 -4
  124. package/src/StepTracker/StepTracker.jsx +11 -10
  125. package/src/Tabs/TabsItem.jsx +3 -2
  126. package/src/TextInput/TextInputBase.jsx +11 -3
  127. package/src/ThemeProvider/ThemeProvider.jsx +22 -3
  128. package/src/ThemeProvider/utils/styles.js +9 -1
  129. package/src/ThemeProvider/utils/theme-tokens.js +1 -1
  130. package/src/ToggleSwitch/ToggleSwitchGroup.jsx +6 -0
  131. package/src/Typography/Typography.jsx +11 -12
  132. package/src/index.js +1 -0
@@ -0,0 +1,77 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { Pressable, Image } from 'react-native'
4
+ import { useCarousel } from './CarouselContext'
5
+
6
+ /**
7
+ * `Carousel.Thumbnail` is used to wrap the content of an individual slide and is suppsoed to be the
8
+ * only top-level component passed to the `Carousel`
9
+ */
10
+ const CarouselThumbnail = ({ accessibilityLabel, alt, index, src }) => {
11
+ const { activeIndex, itemLabel, totalItems, getCopyWithPlaceholders, goTo, themeTokens } =
12
+ useCarousel()
13
+ const thumbnailTitle =
14
+ alt ??
15
+ getCopyWithPlaceholders('stepTrackerLabel')
16
+ .replace(/%\{itemLabel\}/g, itemLabel)
17
+ .replace(/%\{stepNumber\}/g, index)
18
+ .replace(/%\{stepCount\}/g, totalItems)
19
+ const handlePress = () => goTo(index)
20
+ const handleKeyDown = (event) => {
21
+ // Allow using the spacebar for navigation
22
+ if (event?.key === ' ') goTo(index)
23
+ }
24
+ const {
25
+ thumbnailBorderColor,
26
+ thumbnailBorderRadius,
27
+ thumbnailBorderWidth,
28
+ thumbnailMargin,
29
+ thumbnailPadding,
30
+ thumbnailSelectedBorderColor,
31
+ thumbnailSelectedBorderWidth,
32
+ thumbnailSize
33
+ } = themeTokens
34
+ const styles = {
35
+ pressable: {
36
+ borderColor: thumbnailBorderColor,
37
+ borderRadius: thumbnailBorderRadius,
38
+ borderWidth: thumbnailBorderWidth,
39
+ margin: thumbnailMargin,
40
+ padding: thumbnailPadding
41
+ },
42
+ image: {
43
+ height: thumbnailSize,
44
+ width: thumbnailSize
45
+ },
46
+ selected: {
47
+ borderColor: thumbnailSelectedBorderColor,
48
+ borderWidth: thumbnailSelectedBorderWidth,
49
+ padding: thumbnailPadding - thumbnailSelectedBorderWidth + thumbnailBorderWidth
50
+ }
51
+ }
52
+
53
+ return (
54
+ <Pressable
55
+ key={src}
56
+ onKeyDown={handleKeyDown}
57
+ onPress={handlePress}
58
+ style={[styles.pressable, index === activeIndex && styles.selected]}
59
+ >
60
+ <Image
61
+ accessibilityIgnoresInvertColors
62
+ accessibilityLabel={accessibilityLabel ?? alt}
63
+ source={src}
64
+ style={styles.image}
65
+ title={thumbnailTitle}
66
+ />
67
+ </Pressable>
68
+ )
69
+ }
70
+ CarouselThumbnail.propTypes = {
71
+ accessibilityLabel: PropTypes.string,
72
+ alt: PropTypes.string,
73
+ index: PropTypes.number,
74
+ src: PropTypes.string
75
+ }
76
+
77
+ export default CarouselThumbnail
@@ -0,0 +1,53 @@
1
+ import React, { forwardRef } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { View } from 'react-native'
4
+ import { useCarousel } from './CarouselContext'
5
+ import CarouselThumbnail from './CarouselThumbnail'
6
+ import { StackWrap } from '../StackView'
7
+
8
+ const CarouselThumbnailNavigation = forwardRef(({ thumbnails = [] }, ref) => {
9
+ const { totalItems, themeTokens } = useCarousel()
10
+ if (thumbnails.length !== totalItems) {
11
+ throw new Error('Thumbnail set provided does not match the number of slides in the carousel')
12
+ }
13
+ const { thumbnailContainerPaddingTop, thumbnailMargin } = themeTokens
14
+ const stackWrapTokens = {
15
+ justifyContent: 'flex-start'
16
+ }
17
+ const containerStyles = {
18
+ justifyContent: 'center',
19
+ alignItems: 'center',
20
+ paddingTop: thumbnailContainerPaddingTop - thumbnailMargin
21
+ }
22
+
23
+ return (
24
+ <View style={containerStyles}>
25
+ <StackWrap direction="row" tokens={stackWrapTokens} ref={ref}>
26
+ {thumbnails.map(({ accessibilityLabel, alt, src }, index) => (
27
+ <CarouselThumbnail
28
+ accessibilityLabel={accessibilityLabel}
29
+ alt={alt}
30
+ index={index}
31
+ key={src}
32
+ src={src}
33
+ />
34
+ ))}
35
+ </StackWrap>
36
+ </View>
37
+ )
38
+ })
39
+ CarouselThumbnailNavigation.displayName = 'CarouselThumbnailNavigation'
40
+ CarouselThumbnailNavigation.propTypes = {
41
+ /**
42
+ * An array of objects containing information on the thumbnail images.
43
+ */
44
+ thumbnails: PropTypes.arrayOf(
45
+ PropTypes.shape({
46
+ accessibilityLabel: PropTypes.string,
47
+ alt: PropTypes.string,
48
+ src: PropTypes.string
49
+ })
50
+ ).isRequired
51
+ }
52
+
53
+ export default CarouselThumbnailNavigation
@@ -4,13 +4,15 @@ export default {
4
4
  carouselLabel: '%{stepCount} items',
5
5
  iconButtonLabel: 'Show %{itemLabel} %{targetStep} of %{stepCount}',
6
6
  stepLabel: '%{itemLabel} %{stepNumber}',
7
- stepTrackerLabel: '%{itemLabel} %{stepNumber} of %{stepCount}'
7
+ stepTrackerLabel: '%{itemLabel} %{stepNumber} of %{stepCount}',
8
+ skipLink: 'Skip %{title}'
8
9
  },
9
10
  fr: {
10
11
  // TODO: French translations here
11
12
  carouselLabel: '(fr) %{stepCount} items',
12
13
  iconButtonLabel: '(fr) Show %{itemLabel} %{targetStep} of %{stepCount}',
13
14
  stepLabel: '(fr) %{itemLabel} %{stepNumber}',
14
- stepTrackerLabel: '(fr) %{itemLabel} %{stepNumber} of %{stepCount}'
15
+ stepTrackerLabel: '(fr) %{itemLabel} %{stepNumber} of %{stepCount}',
16
+ skipLink: '(fr) Skip %{title}'
15
17
  }
16
18
  }
@@ -1,2 +1,3 @@
1
1
  export * from './CarouselContext'
2
2
  export { default as Carousel } from './Carousel'
3
+ export { default as CarouselTabs } from './CarouselTabs'
@@ -6,7 +6,12 @@ import CheckboxInput from './CheckboxInput'
6
6
  import CheckboxLabel from '../InputLabel/LabelContent'
7
7
  import Feedback from '../Feedback'
8
8
  import StackView from '../StackView'
9
- import { applyShadowToken, applyTextStyles, useThemeTokensCallback } from '../ThemeProvider'
9
+ import {
10
+ applyShadowToken,
11
+ applyTextStyles,
12
+ useTheme,
13
+ useThemeTokensCallback
14
+ } from '../ThemeProvider'
10
15
  import {
11
16
  a11yProps,
12
17
  focusHandlerProps,
@@ -54,21 +59,18 @@ const selectInputStyles = (
54
59
  }
55
60
  })
56
61
  })
57
- const selectLabelStyles = ({
58
- labelColor,
59
- labelFontName,
60
- labelFontSize,
61
- labelFontWeight,
62
- labelMarginLeft,
63
- labelLineHeight
64
- }) => ({
62
+ const selectLabelStyles = (
63
+ { labelColor, labelFontName, labelFontSize, labelFontWeight, labelMarginLeft, labelLineHeight },
64
+ themeOptions
65
+ ) => ({
65
66
  marginLeft: labelMarginLeft,
66
67
  ...applyTextStyles({
67
68
  color: labelColor,
68
69
  fontName: labelFontName,
69
70
  fontWeight: labelFontWeight,
70
71
  fontSize: labelFontSize,
71
- lineHeight: labelLineHeight
72
+ lineHeight: labelLineHeight,
73
+ themeOptions
72
74
  })
73
75
  })
74
76
  const selectIconTokens = ({ icon, iconColor, iconSize }) => ({
@@ -172,6 +174,7 @@ const Checkbox = forwardRef(
172
174
  }
173
175
  const uniqueId = useUniqueId('checkbox')
174
176
  const inputId = id ?? uniqueId
177
+ const { themeOptions } = useTheme()
175
178
 
176
179
  return (
177
180
  <View style={staticStyles.wrapper} ref={ref}>
@@ -187,7 +190,7 @@ const Checkbox = forwardRef(
187
190
  {({ focused: focus, hovered: hover, pressed }) => {
188
191
  const { icon: IconComponent, ...stateTokens } = getTokens({ focus, hover, pressed })
189
192
  const iconTokens = selectIconTokens(stateTokens)
190
- const labelStyles = selectLabelStyles(stateTokens)
193
+ const labelStyles = selectLabelStyles(stateTokens, themeOptions)
191
194
  const alignWithLabel = label
192
195
  ? [staticStyles.alignWithLabel, { height: labelStyles.lineHeight }]
193
196
  : null
@@ -61,7 +61,7 @@ const [selectItemProps, selectedItemPropTypes] = selectSystemProps([
61
61
  * @example
62
62
  * ```jsx
63
63
  * <CheckboxGroup
64
- * initialCheckedId="check1"
64
+ * initialCheckedIds="check1"
65
65
  * items={[
66
66
  * { label: 'Checkbox 1', id: 'check1' },
67
67
  * { label: 'Checkbox 2', id: 'check2' },
@@ -82,6 +82,8 @@ const CheckboxGroup = forwardRef(
82
82
  legend,
83
83
  tooltip,
84
84
  hint,
85
+ hintPosition = 'inline',
86
+
85
87
  validation,
86
88
  feedback,
87
89
  initialCheckedIds,
@@ -145,6 +147,7 @@ const CheckboxGroup = forwardRef(
145
147
  legend={legend}
146
148
  tooltip={tooltip}
147
149
  hint={hint}
150
+ hintPosition={hintPosition}
148
151
  space={fieldSpace}
149
152
  feedback={feedback}
150
153
  inactive={inactive}
@@ -192,6 +195,10 @@ CheckboxGroup.propTypes = {
192
195
  * Optional additional text giving more detail to help a user make a choice.
193
196
  */
194
197
  hint: PropTypes.string,
198
+ /**
199
+ * Position of the hint relative to label. Use `below` to display a larger hint below the label.
200
+ */
201
+ hintPosition: PropTypes.oneOf(['inline', 'below']),
195
202
  /**
196
203
  * Optional tooltip text content to include alongside the legend and hint.
197
204
  */
@@ -2,7 +2,7 @@ import React, { forwardRef } from 'react'
2
2
  import { StyleSheet, Text, View } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
 
5
- import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
5
+ import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider'
6
6
  import {
7
7
  a11yProps,
8
8
  getTokensPropType,
@@ -17,10 +17,16 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
17
17
 
18
18
  const selectStyles = (tokens) => selectTokens('Feedback', tokens)
19
19
 
20
- const selectTitleTextStyles = ({ titleFontSize, ...tokens }) =>
21
- applyTextStyles(selectTokens('Typography', { ...tokens, fontSize: titleFontSize }))
22
- const selectContentTextStyles = ({ contentFontSize, ...tokens }) =>
23
- applyTextStyles(selectTokens('Typography', { ...tokens, fontSize: contentFontSize }))
20
+ const selectTitleTextStyles = ({ titleFontSize, ...tokens }, themeOptions) =>
21
+ applyTextStyles({
22
+ ...selectTokens('Typography', { ...tokens, fontSize: titleFontSize, themeOptions }),
23
+ themeOptions
24
+ })
25
+ const selectContentTextStyles = ({ contentFontSize, ...tokens }, themeOptions) =>
26
+ applyTextStyles({
27
+ ...selectTokens('Typography', { ...tokens, fontSize: contentFontSize }),
28
+ themeOptions
29
+ })
24
30
 
25
31
  const selectIconTokens = ({ iconSize, iconColor }) => ({
26
32
  size: iconSize,
@@ -56,8 +62,9 @@ const Feedback = forwardRef(
56
62
 
57
63
  const { icon: IconComponent } = themeTokens
58
64
 
59
- const titleTextStyles = selectTitleTextStyles(themeTokens)
60
- const contentTextStyles = selectContentTextStyles(themeTokens)
65
+ const { themeOptions } = useTheme()
66
+ const titleTextStyles = selectTitleTextStyles(themeTokens, themeOptions)
67
+ const contentTextStyles = selectContentTextStyles(themeTokens, themeOptions)
61
68
 
62
69
  const content =
63
70
  typeof children === 'string' ? <Text style={contentTextStyles}>{children}</Text> : children
@@ -39,6 +39,7 @@ const IconText = forwardRef(
39
39
  IconText.displayName = 'IconText'
40
40
 
41
41
  IconText.propTypes = {
42
+ /* eslint-disable react/no-unused-prop-types */ // eslint is having hard time seeing these props through forwardRef
42
43
  /**
43
44
  * Amount of space to separate the text content and icon. Uses the themes's spacing scale
44
45
  * (see useSpacingScale for more info).
@@ -51,7 +52,7 @@ IconText.propTypes = {
51
52
  /**
52
53
  * A valid UDS icon component imported from a UDS palette.
53
54
  */
54
- icon: PropTypes.func,
55
+ icon: PropTypes.elementType,
55
56
  /**
56
57
  * Props that will be passed to the icon component. By default the icon's `scalesWithText`
57
58
  * prop will be set as "true" so that the icon continues to match the size of the text
@@ -63,6 +64,7 @@ IconText.propTypes = {
63
64
  * `<Typography>` component, or a component that renders `<Text>`.
64
65
  */
65
66
  children: PropTypes.node
67
+ /* eslint-enable react/no-unused-prop-types */
66
68
  }
67
69
 
68
70
  export default IconText
@@ -2,7 +2,7 @@ import React, { forwardRef } from 'react'
2
2
  import { StyleSheet, Text, View } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
4
 
5
- import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
5
+ import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider'
6
6
  import {
7
7
  a11yProps,
8
8
  getTokensPropType,
@@ -17,21 +17,20 @@ import Tooltip from '../Tooltip'
17
17
 
18
18
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
19
19
 
20
- const selectLabelStyles = (tokens) => applyTextStyles(selectTokens('Typography', tokens))
20
+ const selectLabelStyles = (tokens, themeOptions) =>
21
+ applyTextStyles({ ...selectTokens('Typography', tokens), themeOptions })
21
22
 
22
- const selectHintStyles = ({
23
- hintColor,
24
- hintFontName,
25
- hintFontSize,
26
- hintFontWeight,
27
- hintLineHeight
28
- }) =>
23
+ const selectHintStyles = (
24
+ { hintColor, hintFontName, hintFontSize, hintFontWeight, hintLineHeight },
25
+ themeOptions
26
+ ) =>
29
27
  applyTextStyles({
30
28
  color: hintColor,
31
29
  fontName: hintFontName,
32
30
  fontSize: hintFontSize,
33
31
  fontWeight: hintFontWeight,
34
- lineHeight: hintLineHeight
32
+ lineHeight: hintLineHeight,
33
+ themeOptions
35
34
  })
36
35
 
37
36
  const selectGapStyles = ({ gap }) => ({ marginRight: gap })
@@ -57,12 +56,14 @@ const InputLabel = forwardRef(
57
56
  const hasTooltip = tooltip !== undefined
58
57
  const isHintInline = hintPosition === 'inline'
59
58
 
59
+ const { themeOptions } = useTheme()
60
+
60
61
  return (
61
62
  <>
62
63
  <View ref={ref} style={staticStyles.container} {...selectProps(rest)}>
63
64
  <Text
64
65
  style={[
65
- selectLabelStyles(themeTokens),
66
+ selectLabelStyles(themeTokens, themeOptions),
66
67
  selectGapStyles(themeTokens),
67
68
  staticStyles.label
68
69
  ]}
@@ -72,7 +73,7 @@ const InputLabel = forwardRef(
72
73
  {hint && isHintInline && (
73
74
  <Text
74
75
  style={[
75
- selectHintStyles(themeTokens),
76
+ selectHintStyles(themeTokens, themeOptions),
76
77
  hasTooltip && selectGapStyles(themeTokens),
77
78
  staticStyles.label
78
79
  ]}
@@ -9,17 +9,15 @@ import { Pressable, StyleSheet } from 'react-native'
9
9
  * InlinePressable is an alternative to React Native's Pressable that works better when nested
10
10
  * inline inside Text. It accepts the same props as React Native's Pressable.
11
11
  *
12
- * On Web it simply passes its props to Pressable and defaults to `inline-flex` instead of `flex`.
13
- *
14
12
  * @param {PressableProps} PressableProps
15
13
  */
16
14
  // React Native exports prop Types but not propTypes, use JSDoc types here rather than duplicate RN
17
15
  // eslint-disable-next-line react/prop-types
18
- const InlinePressable = forwardRef(({ children, style, inline = false, ...props }, ref) => (
16
+ const InlinePressable = forwardRef(({ children, style, ...props }, ref) => (
19
17
  <Pressable
20
18
  ref={ref}
21
19
  style={(pressState) => [
22
- staticStyles[inline ? 'inline' : 'inlineFlex'],
20
+ staticStyles.inline,
23
21
  typeof style === 'function' ? style(pressState) : style
24
22
  ]}
25
23
  {...props}
@@ -31,11 +29,7 @@ InlinePressable.displayName = 'InlinePressable'
31
29
 
32
30
  const staticStyles = StyleSheet.create({
33
31
  inline: {
34
- // Stop Pressable defaulting to (block) flex
35
32
  display: 'inline'
36
- },
37
- inlineFlex: {
38
- display: 'inline-flex'
39
33
  }
40
34
  })
41
35
 
@@ -15,18 +15,15 @@ import { resolvePressableTokens } from '../utils/pressability'
15
15
  import { withLinkRouter } from '../utils'
16
16
 
17
17
  import InlinePressable from './InlinePressable'
18
- import { applyTextStyles, applyOuterBorder } from '../ThemeProvider'
18
+ import { applyTextStyles, applyOuterBorder, useTheme } from '../ThemeProvider'
19
19
  import { IconText, iconComponentPropTypes } from '../Icon'
20
20
 
21
21
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps, viewProps])
22
22
 
23
- const selectOuterBorderStyles = ({
24
- outerBorderColor,
25
- outerBorderWidth,
26
- outerBorderGap,
27
- borderRadius,
28
- outerBorderOutline
29
- }) =>
23
+ const selectOuterBorderStyles = (
24
+ { outerBorderColor, outerBorderWidth, outerBorderGap, borderRadius, outerBorderOutline },
25
+ hasIcon
26
+ ) =>
30
27
  // A view wrapper with a border on native messes up inline text alignment
31
28
  // so for now make focus styles strictly web-only
32
29
  Platform.OS === 'web'
@@ -41,7 +38,7 @@ const selectOuterBorderStyles = ({
41
38
  }),
42
39
  // Stops focus ring stretching horizontally if parent has display: block
43
40
  // width: fit-content isn't supported on Firefox; can't cascade props like CSS `width: fit-content; width: --moz-fit-content;`
44
- display: 'inline-flex'
41
+ display: hasIcon ? 'inline-flex' : 'inline' // Stop Pressable defaulting to (block) flex
45
42
  }
46
43
  : {}
47
44
 
@@ -55,12 +52,16 @@ const selectTextStyles = ({ color }) => ({
55
52
  })
56
53
  })
57
54
 
58
- const selectBlockStyles = ({ blockFontWeight, blockFontSize, blockLineHeight, blockFontName }) =>
55
+ const selectBlockStyles = (
56
+ { blockFontWeight, blockFontSize, blockLineHeight, blockFontName },
57
+ themeOptions
58
+ ) =>
59
59
  applyTextStyles({
60
60
  fontWeight: blockFontWeight,
61
61
  fontSize: blockFontSize,
62
62
  lineHeight: blockLineHeight,
63
- fontName: blockFontName
63
+ fontName: blockFontName,
64
+ themeOptions
64
65
  })
65
66
 
66
67
  const selectDecorationStyles = ({ color, textLine, textLineStyle }) => ({
@@ -138,21 +139,17 @@ const LinkBase = forwardRef(
138
139
  // On web, this makes focus rings wrap only the link, not the entire block
139
140
  const blockLeftStyle = Platform.OS === 'web' && staticStyles.blockLeft
140
141
 
142
+ const { themeOptions } = useTheme()
143
+
141
144
  return (
142
145
  <InlinePressable
143
146
  {...selectedProps}
144
- inline={hasIcon} // assuming links without icons should be inline (even if they are long)
145
147
  ref={ref}
146
148
  style={(linkState) => {
147
149
  const themeTokens = resolveLinkTokens(linkState)
148
- const outerBorderStyles = selectOuterBorderStyles(themeTokens)
150
+ const outerBorderStyles = selectOuterBorderStyles(themeTokens, hasIcon)
149
151
  const decorationStyles = selectDecorationStyles(themeTokens)
150
- return [
151
- outerBorderStyles,
152
- blockLeftStyle,
153
- decorationStyles,
154
- hasIcon && staticStyles.rowContainer
155
- ]
152
+ return [outerBorderStyles, blockLeftStyle, decorationStyles, staticStyles.rowContainer]
156
153
  }}
157
154
  >
158
155
  {(linkState) => {
@@ -162,7 +159,7 @@ const LinkBase = forwardRef(
162
159
 
163
160
  // TODO: may need to apply some smarter text inheritance here if inline to avoid native
164
161
  // issues like double-application of line heights breaking align-items: baseline
165
- const blockTextStyles = selectBlockStyles(themeTokens)
162
+ const blockTextStyles = selectBlockStyles(themeTokens, themeOptions)
166
163
 
167
164
  const IconComponent = icon || themeTokens.icon
168
165
  const { iconSpace } = themeTokens
@@ -196,7 +193,7 @@ LinkBase.propTypes = {
196
193
  * A function component for an SVG icon to render inside the link. Inherits size and color from
197
194
  * the link and any Typography the link is nested inside.
198
195
  */
199
- icon: PropTypes.func,
196
+ icon: PropTypes.elementType,
200
197
  /**
201
198
  * When `icon` is provided, use `iconPosition` to place the Icon to the left or right side of Link.
202
199
  */
@@ -1,7 +1,7 @@
1
1
  import React, { forwardRef } from 'react'
2
2
  import { View, Platform, StyleSheet } from 'react-native'
3
3
  import PropTypes from 'prop-types'
4
- import { useThemeTokens, applyTextStyles } from '../ThemeProvider'
4
+ import { useTheme, useThemeTokens, applyTextStyles } from '../ThemeProvider'
5
5
  import {
6
6
  a11yProps,
7
7
  getTokensPropType,
@@ -41,12 +41,16 @@ const selectBulletPositioningStyles = ({ itemIconSize }) => ({
41
41
  height: itemIconSize
42
42
  })
43
43
 
44
- const selectItemStyles = ({ itemFontWeight, itemFontSize, itemLineHeight, itemFontName }) =>
44
+ const selectItemStyles = (
45
+ { itemFontWeight, itemFontSize, itemLineHeight, itemFontName },
46
+ themeOptions
47
+ ) =>
45
48
  applyTextStyles({
46
49
  fontWeight: itemFontWeight,
47
50
  fontSize: itemFontSize,
48
51
  lineHeight: itemLineHeight,
49
- fontName: itemFontName
52
+ fontName: itemFontName,
53
+ themeOptions
50
54
  })
51
55
 
52
56
  const selectItemBlockStyles = ({ interItemMargin }) => ({
@@ -80,8 +84,9 @@ const ListItem = forwardRef(
80
84
  ref
81
85
  ) => {
82
86
  const themeTokens = useThemeTokens('List', tokens, variant)
87
+ const { themeOptions } = useTheme()
83
88
 
84
- const itemStyles = selectItemStyles(themeTokens)
89
+ const itemStyles = selectItemStyles(themeTokens, themeOptions)
85
90
  const itemBlockStyles = selectItemBlockStyles(themeTokens)
86
91
  const dividerStyles = selectDividerStyles(themeTokens)
87
92
  const itemBulletContainerStyles = selectBulletContainerStyles(themeTokens)
@@ -175,7 +180,7 @@ ListItem.propTypes = {
175
180
  /**
176
181
  * Renders side item icon
177
182
  */
178
- icon: PropTypes.func,
183
+ icon: PropTypes.elementType,
179
184
  /**
180
185
  * Will set display icon color
181
186
  */
@@ -2,7 +2,7 @@ import React, { forwardRef, useState } from 'react'
2
2
  import { StyleSheet, View } from 'react-native'
3
3
 
4
4
  import PropTypes from 'prop-types'
5
- import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
5
+ import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider'
6
6
  import {
7
7
  a11yProps,
8
8
  getTokensPropType,
@@ -10,7 +10,8 @@ import {
10
10
  selectTokens,
11
11
  variantProp,
12
12
  viewProps,
13
- wrapStringsInText
13
+ wrapStringsInText,
14
+ useResponsiveProp
14
15
  } from '../utils'
15
16
  import ButtonBase from '../Button/ButtonBase'
16
17
  import useCopy from '../utils/useCopy'
@@ -20,7 +21,8 @@ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, vie
20
21
 
21
22
  const selectContainerStyles = (tokens) => ({ ...tokens })
22
23
 
23
- const selectTextStyles = (tokens) => applyTextStyles(selectTokens('Typography', tokens))
24
+ const selectTextStyles = (tokens, themeOptions) =>
25
+ applyTextStyles({ ...selectTokens('Typography', tokens), themeOptions })
24
26
 
25
27
  const selectIconProps = ({ iconSize, iconColor }) => ({
26
28
  size: iconSize,
@@ -40,6 +42,10 @@ const selectDismissButtonContainerStyles = ({ dismissButtonGap }) => ({
40
42
  paddingLeft: dismissButtonGap
41
43
  })
42
44
 
45
+ const selectContentContainerStyle = (maxWidth) => ({
46
+ width: maxWidth || '100%'
47
+ })
48
+
43
49
  /**
44
50
  * A banner that highlights important messages:
45
51
  * - Status message to show there is an error or outage of services
@@ -96,12 +102,14 @@ const Notification = forwardRef(
96
102
  const [isDismissed, setIsDismissed] = useState(false)
97
103
  const themeTokens = useThemeTokens('Notification', tokens, variant, { system })
98
104
  const getCopy = useCopy({ dictionary, copy })
105
+ const { themeOptions } = useTheme()
106
+ const contentMaxWidth = useResponsiveProp(themeOptions?.contentMaxWidth)
99
107
 
100
108
  if (isDismissed) {
101
109
  return null
102
110
  }
103
111
 
104
- const textStyles = selectTextStyles(themeTokens)
112
+ const textStyles = selectTextStyles(themeTokens, themeOptions)
105
113
 
106
114
  const content = wrapStringsInText(
107
115
  typeof children === 'function' ? children({ textStyles }) : children,
@@ -119,25 +127,27 @@ const Notification = forwardRef(
119
127
  style={[staticStyles.container, selectContainerStyles(themeTokens)]}
120
128
  {...selectProps(rest)}
121
129
  >
122
- {IconComponent && (
123
- <View style={selectIconContainerStyles(themeTokens)}>
124
- <IconComponent {...selectIconProps(themeTokens)} />
130
+ <View style={[staticStyles.content, selectContentContainerStyle(contentMaxWidth)]}>
131
+ <View style={staticStyles.contentContainer}>
132
+ {IconComponent && (
133
+ <View style={selectIconContainerStyles(themeTokens)}>
134
+ <IconComponent {...selectIconProps(themeTokens)} />
135
+ </View>
136
+ )}
137
+ {content && typeof content === 'function' ? content({ textStyles, variant }) : content}
125
138
  </View>
126
- )}
127
- <View style={staticStyles.contentContainer}>
128
- {content && typeof content === 'function' ? content({ textStyles, variant }) : content}
139
+ {dismissible && DismissIconComponent && (
140
+ <View style={selectDismissButtonContainerStyles(themeTokens)}>
141
+ <ButtonBase
142
+ onPress={onDismissPress}
143
+ accessibilityRole="button"
144
+ accessibilityLabel={getCopy('dismiss')}
145
+ >
146
+ {() => <DismissIconComponent {...selectDismissIconProps(themeTokens)} />}
147
+ </ButtonBase>
148
+ </View>
149
+ )}
129
150
  </View>
130
- {dismissible && DismissIconComponent && (
131
- <View style={selectDismissButtonContainerStyles(themeTokens)}>
132
- <ButtonBase
133
- onPress={onDismissPress}
134
- accessibilityRole="button"
135
- accessibilityLabel={getCopy('dismiss')}
136
- >
137
- {() => <DismissIconComponent {...selectDismissIconProps(themeTokens)} />}
138
- </ButtonBase>
139
- </View>
140
- )}
141
151
  </View>
142
152
  )
143
153
  }
@@ -173,9 +183,16 @@ export default Notification
173
183
 
174
184
  const staticStyles = StyleSheet.create({
175
185
  container: {
176
- flexDirection: 'row'
186
+ flexDirection: 'row',
187
+ justifyContent: 'center'
177
188
  },
178
189
  contentContainer: {
179
- flex: 1
190
+ flexDirection: 'row',
191
+ flexShrink: 1
192
+ },
193
+ content: {
194
+ flexDirection: 'row',
195
+ flexShrink: 1,
196
+ justifyContent: 'space-between'
180
197
  }
181
198
  })