@telus-uds/components-base 1.20.0 → 1.22.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 (40) hide show
  1. package/CHANGELOG.md +30 -2
  2. package/__tests17__/ThemeProvider/ThemeProvider.test.jsx +1 -0
  3. package/component-docs.json +461 -3
  4. package/lib/Button/ButtonGroup.js +9 -0
  5. package/lib/ExpandCollapse/Control.js +3 -1
  6. package/lib/Feedback/Feedback.js +3 -1
  7. package/lib/Fieldset/Fieldset.js +42 -13
  8. package/lib/Fieldset/FieldsetContainer.js +9 -3
  9. package/lib/QuickLinksFeature/QuickLinksFeature.js +91 -0
  10. package/lib/QuickLinksFeature/QuickLinksFeatureItem.js +157 -0
  11. package/lib/QuickLinksFeature/index.js +16 -0
  12. package/lib/RadioCard/RadioCardGroup.js +2 -0
  13. package/lib/ThemeProvider/ThemeProvider.js +21 -9
  14. package/lib/ThemeProvider/utils/styles.js +3 -1
  15. package/lib/index.js +18 -0
  16. package/lib-module/Button/ButtonGroup.js +9 -0
  17. package/lib-module/ExpandCollapse/Control.js +3 -1
  18. package/lib-module/Feedback/Feedback.js +3 -1
  19. package/lib-module/Fieldset/Fieldset.js +39 -12
  20. package/lib-module/Fieldset/FieldsetContainer.js +9 -3
  21. package/lib-module/QuickLinksFeature/QuickLinksFeature.js +69 -0
  22. package/lib-module/QuickLinksFeature/QuickLinksFeatureItem.js +130 -0
  23. package/lib-module/QuickLinksFeature/index.js +4 -0
  24. package/lib-module/RadioCard/RadioCardGroup.js +2 -0
  25. package/lib-module/ThemeProvider/ThemeProvider.js +21 -9
  26. package/lib-module/ThemeProvider/utils/styles.js +3 -1
  27. package/lib-module/index.js +2 -0
  28. package/package.json +2 -2
  29. package/src/Button/ButtonGroup.jsx +10 -0
  30. package/src/ExpandCollapse/Control.jsx +3 -2
  31. package/src/Feedback/Feedback.jsx +2 -2
  32. package/src/Fieldset/Fieldset.jsx +40 -13
  33. package/src/Fieldset/FieldsetContainer.jsx +29 -12
  34. package/src/QuickLinksFeature/QuickLinksFeature.jsx +65 -0
  35. package/src/QuickLinksFeature/QuickLinksFeatureItem.jsx +114 -0
  36. package/src/QuickLinksFeature/index.js +6 -0
  37. package/src/RadioCard/RadioCardGroup.jsx +2 -0
  38. package/src/ThemeProvider/ThemeProvider.jsx +19 -6
  39. package/src/ThemeProvider/utils/styles.js +3 -1
  40. package/src/index.js +2 -0
@@ -7,17 +7,32 @@ import cssReset from './cssReset'
7
7
  * On Web, wraps children with a HTML `<fieldset>` and sets its attributes as necessary.
8
8
  */
9
9
  const FieldsetContainer = forwardRef(
10
- ({ children, inactive, accessibilityRole, name: fieldsetName }, ref) => (
11
- <fieldset
12
- ref={ref}
13
- disabled={inactive}
14
- style={cssReset}
15
- role={accessibilityRole}
16
- name={fieldsetName}
17
- >
18
- {children}
19
- </fieldset>
20
- )
10
+ (
11
+ {
12
+ children,
13
+ inactive,
14
+ accessibilityRole,
15
+ name: fieldsetName,
16
+ showBorderStyle = false,
17
+ borderStyle
18
+ },
19
+ ref
20
+ ) => {
21
+ // If needs border for error design or reset the component style
22
+ const styleContainer = showBorderStyle ? borderStyle : cssReset
23
+
24
+ return (
25
+ <fieldset
26
+ ref={ref}
27
+ disabled={inactive}
28
+ style={styleContainer}
29
+ role={accessibilityRole}
30
+ name={fieldsetName}
31
+ >
32
+ {children}
33
+ </fieldset>
34
+ )
35
+ }
21
36
  )
22
37
  FieldsetContainer.displayName = 'FieldsetContainer'
23
38
 
@@ -25,7 +40,9 @@ FieldsetContainer.propTypes = {
25
40
  accessibilityRole: PropTypes.string,
26
41
  children: PropTypes.node,
27
42
  inactive: PropTypes.bool,
28
- name: PropTypes.string
43
+ name: PropTypes.string,
44
+ showBorderStyle: PropTypes.bool,
45
+ borderStyle: PropTypes.object
29
46
  }
30
47
 
31
48
  export default FieldsetContainer
@@ -0,0 +1,65 @@
1
+ import React, { forwardRef, Children, cloneElement } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { StackWrap } from '../StackView'
4
+
5
+ import { useThemeTokens } from '../ThemeProvider'
6
+ import { a11yProps, getTokensPropType, selectSystemProps, variantProp, viewProps } from '../utils'
7
+
8
+ // pass through and type relevant system props - add more sets for interactive components
9
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
10
+
11
+ const isQuickListItem = (element) => {
12
+ const elementName = element?.type?.displayName || element?.type?.name
13
+ return Boolean(elementName.match(/QuickLinksFeatureItem/))
14
+ }
15
+
16
+ /**
17
+ * QuickLinksFeature renders a list of interactive items.
18
+ * - This is the base component that is used as a wrapper and accepts a List of `QuickLinksFeature.Item`
19
+ */
20
+ const QuickLinksFeature = forwardRef(({ tokens, variant, tag = 'ul', children, ...rest }, ref) => {
21
+ const { stackGap, stackJustify, stackSpace } = useThemeTokens(
22
+ 'QuickLinksFeature',
23
+ tokens,
24
+ variant
25
+ )
26
+
27
+ const items = Children.map(children, (child) => {
28
+ if (isQuickListItem(child)) {
29
+ return cloneElement(child, child.props)
30
+ }
31
+
32
+ return null
33
+ })
34
+
35
+ return (
36
+ <StackWrap
37
+ space={stackSpace}
38
+ gap={stackGap}
39
+ tokens={{ justifyContent: stackJustify }}
40
+ tag={tag}
41
+ ref={ref}
42
+ {...selectProps(rest)}
43
+ >
44
+ {items}
45
+ </StackWrap>
46
+ )
47
+ })
48
+
49
+ QuickLinksFeature.displayName = 'QuickLinksFeature'
50
+
51
+ QuickLinksFeature.propTypes = {
52
+ ...selectedSystemPropTypes,
53
+ tokens: getTokensPropType('QuickLinksFeature'),
54
+ variant: variantProp.propType,
55
+ /**
56
+ * Default wrapper tag, by default it's "ul"
57
+ */
58
+ tag: PropTypes.string,
59
+ /**
60
+ * QuickLinksFeature.Item component
61
+ */
62
+ children: PropTypes.node
63
+ }
64
+
65
+ export default QuickLinksFeature
@@ -0,0 +1,114 @@
1
+ import React, { forwardRef, useState } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ import { Image, Platform, Text, View } from 'react-native'
5
+ import {
6
+ getTokensPropType,
7
+ variantProp,
8
+ withLinkRouter,
9
+ a11yProps,
10
+ linkProps,
11
+ selectSystemProps
12
+ } from '../utils'
13
+ import { useViewport } from '../ViewportProvider'
14
+ import { useThemeTokensCallback } from '../ThemeProvider'
15
+ import { Link } from '../Link'
16
+ import { StackWrap } from '../StackView'
17
+
18
+ // pass through and type relevant system props - add more sets for interactive components
19
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps])
20
+
21
+ const selectImageStyle = (imageDimension) => ({
22
+ width: imageDimension,
23
+ height: imageDimension,
24
+ ...Platform.select({
25
+ // TODO: https://github.com/telus/universal-design-system/issues/487
26
+ web: { transition: 'width 200ms, height 200ms' }
27
+ })
28
+ })
29
+
30
+ const selectContainerStyle = ({ contentMaxDimension, textAlign }) => ({
31
+ textAlign,
32
+ width: contentMaxDimension,
33
+ overflow: 'hidden'
34
+ })
35
+
36
+ const selectImageContainerStyle = (contentMaxDimension) => ({
37
+ width: contentMaxDimension,
38
+ height: contentMaxDimension,
39
+ justifyContent: 'center',
40
+ alignItems: 'center'
41
+ })
42
+
43
+ /**
44
+ * Component export along with QuickLinksFeature to be used as children
45
+ *
46
+ * It will receive a image source and a accessibility label and will render a link accordingly with the theme tokens
47
+ */
48
+ const QuickLinksFeatureItem = forwardRef(
49
+ ({ tokens, variant, children, imageAccessibilityLabel, imageSource, ...rest }, ref) => {
50
+ const viewport = useViewport()
51
+ const getTokens = useThemeTokensCallback('QuickLinksFeatureItem', tokens, variant)
52
+ const [hover, setHover] = useState(false)
53
+ const {
54
+ contentDirection,
55
+ contentSpace,
56
+ contentAlignItems,
57
+ contentMaxDimension,
58
+ imageDimension,
59
+ textAlign
60
+ } = getTokens({ viewport, hover })
61
+
62
+ return (
63
+ <Link
64
+ ref={ref}
65
+ tokens={(state) => {
66
+ setHover(state.hover)
67
+ return getTokens(state)
68
+ }}
69
+ {...selectProps(rest)}
70
+ >
71
+ <View style={selectContainerStyle({ contentMaxDimension, textAlign })}>
72
+ <StackWrap
73
+ direction={contentDirection}
74
+ space={contentSpace}
75
+ tokens={{ alignItems: contentAlignItems }}
76
+ >
77
+ <View style={selectImageContainerStyle(contentMaxDimension)}>
78
+ <Image
79
+ accessibilityIgnoresInvertColors
80
+ imageAccessibilityLabel={imageAccessibilityLabel}
81
+ source={imageSource}
82
+ style={selectImageStyle(imageDimension)}
83
+ />
84
+ </View>
85
+ <Text>{children}</Text>
86
+ </StackWrap>
87
+ </View>
88
+ </Link>
89
+ )
90
+ }
91
+ )
92
+
93
+ QuickLinksFeatureItem.displayName = 'QuickLinksFeatureItem'
94
+
95
+ QuickLinksFeatureItem.propTypes = {
96
+ ...withLinkRouter.propTypes,
97
+ ...selectedSystemPropTypes,
98
+ tokens: getTokensPropType('QuickLinksFeatureItem'),
99
+ variant: variantProp.propType,
100
+ /**
101
+ * Text which will be rendered within the Link
102
+ */
103
+ children: PropTypes.node.isRequired,
104
+ /**
105
+ * Image accessibility label
106
+ */
107
+ imageAccessibilityLabel: PropTypes.string.isRequired,
108
+ /**
109
+ * Image node or Image url
110
+ */
111
+ imageSource: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired
112
+ }
113
+
114
+ export default withLinkRouter(QuickLinksFeatureItem)
@@ -0,0 +1,6 @@
1
+ import QuickLinksFeature from './QuickLinksFeature'
2
+ import QuickLinksFeatureItem from './QuickLinksFeatureItem'
3
+
4
+ QuickLinksFeature.Item = QuickLinksFeatureItem
5
+
6
+ export default QuickLinksFeature
@@ -133,6 +133,8 @@ const RadioCardGroup = forwardRef(
133
133
  feedback={feedback}
134
134
  inactive={inactive || readOnly}
135
135
  validation={validation}
136
+ showErrorBorder
137
+ showIcon
136
138
  accessibilityRole="radiogroup"
137
139
  {...selectProps(rest)}
138
140
  >
@@ -8,15 +8,22 @@ export const uninitialisedError = new Error('Theme context used outside of Theme
8
8
  export const ThemeContext = createContext(uninitialisedError)
9
9
  export const ThemeSetterContext = createContext(uninitialisedError)
10
10
 
11
- const ThemeProvider = ({
12
- children,
13
- defaultTheme,
11
+ // These options default to `true` in v1.x to match legacy defaults and avoid breaking changes.
12
+ // This should change in future major releases to become "opt-in" legacy support.
13
+ const defaultThemeOptions = {
14
14
  // TODO: switch `forceAbsoluteFontSizing` to be false by default in the next major version
15
+ forceAbsoluteFontSizing: true,
15
16
  // TODO: switch `forceZIndex` to be false by default in the next major version
16
- themeOptions = { forceAbsoluteFontSizing: true, forceZIndex: true }
17
- }) => {
17
+ forceZIndex: true,
18
+ // TODO: switch `enableHelmetSSR` to be false by default in the next major version
19
+ enableHelmetSSR: true
20
+ }
21
+
22
+ const ThemeProvider = ({ children, defaultTheme, themeOptions = {} }) => {
18
23
  const [theme, setTheme] = useState(defaultTheme)
19
24
 
25
+ const appliedThemeOptions = { ...defaultThemeOptions, ...themeOptions }
26
+
20
27
  // Validate the theme tokens version on every render.
21
28
  // This will intentionally break the application when attempting to use an invalid theme.
22
29
  // This will surface an incompatibility quickly rather than allowing the potential for strange bugs due to missing or incompatible tokens.
@@ -24,7 +31,9 @@ const ThemeProvider = ({
24
31
 
25
32
  return (
26
33
  <ThemeSetterContext.Provider value={setTheme}>
27
- <ThemeContext.Provider value={{ ...theme, themeOptions }}>{children}</ThemeContext.Provider>
34
+ <ThemeContext.Provider value={{ ...theme, themeOptions: appliedThemeOptions }}>
35
+ {children}
36
+ </ThemeContext.Provider>
28
37
  </ThemeSetterContext.Provider>
29
38
  )
30
39
  }
@@ -46,10 +55,14 @@ ThemeProvider.propTypes = {
46
55
  * such as Footnote and Notification to avoid content to stretch width more then the page's width
47
56
  * - `forceZIndex`: available on web only, when set to false, sets zIndex on `View` to be `auto`
48
57
  * and when true, sets zIndex to be `0` (the default from `react-native-web`)
58
+ * - `enableHelmetSSR`: on Web SSR, allows React Helmet to run during server-side rendering. This should be
59
+ * disabled unless a web app has been specifically configured to stop React Helmet accumulating
60
+ * instances (which may cause a memory leak). See React Helmet's docs: https://github.com/nfl/react-helmet
49
61
  */
50
62
  themeOptions: PropTypes.shape({
51
63
  forceAbsoluteFontSizing: PropTypes.bool,
52
64
  forceZIndex: PropTypes.bool,
65
+ enableHelmetSSR: PropTypes.bool,
53
66
  contentMaxWidth: responsiveProps.getTypeOptionallyByViewport(PropTypes.number)
54
67
  })
55
68
  }
@@ -45,7 +45,9 @@ export function applyTextStyles({
45
45
  // Don't set undefined font families. May need some validation here that the font is available.
46
46
  // Android doesn't recognise font weights natively so apply custom font weights via `fontFamily`.
47
47
  styles.fontFamily = `${fontName}${fontWeight}${fontStyle}`
48
- } else if (fontWeight) {
48
+ }
49
+
50
+ if (fontWeight) {
49
51
  // If using system default font, apply the font weight directly.
50
52
  // Font weight support in Android is limited to 'bold' or anything else === 'normal'.
51
53
  styles.fontWeight = Platform.OS === 'android' && Number(fontWeight) > 400 ? 'bold' : fontWeight
package/src/index.js CHANGED
@@ -26,6 +26,7 @@ export { default as Notification } from './Notification'
26
26
  export { default as Pagination } from './Pagination'
27
27
  export { default as Progress } from './Progress'
28
28
  export { default as QuickLinks } from './QuickLinks'
29
+ export { default as QuickLinksFeature } from './QuickLinksFeature'
29
30
  export { default as Radio } from './Radio'
30
31
  export * from './Radio'
31
32
  export { default as RadioCard } from './RadioCard'
@@ -51,6 +52,7 @@ export { default as Typography } from './Typography'
51
52
 
52
53
  export { default as A11yInfoProvider, useA11yInfo } from './A11yInfoProvider'
53
54
  export { default as BaseProvider } from './BaseProvider'
55
+ export { useHydrationContext } from './BaseProvider/HydrationContext'
54
56
  export { default as ViewportProvider, useViewport, ViewportContext } from './ViewportProvider'
55
57
  export {
56
58
  default as ThemeProvider,