@telus-uds/components-base 1.73.0 → 1.75.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 (35) hide show
  1. package/CHANGELOG.md +27 -3
  2. package/lib/ExpandCollapse/Panel.js +1 -1
  3. package/lib/Footnote/Footnote.js +328 -0
  4. package/lib/Footnote/FootnoteLink.js +108 -0
  5. package/lib/Footnote/dictionary.js +19 -0
  6. package/lib/Footnote/index.js +12 -0
  7. package/lib/Notification/Notification.js +213 -35
  8. package/lib/Responsive/Responsive.js +8 -0
  9. package/lib/Responsive/ResponsiveWithMediaQueryStyleSheet.js +6 -3
  10. package/lib/Typography/Typography.js +3 -1
  11. package/lib/index.js +8 -0
  12. package/lib/utils/ssr-media-query/create-stylesheet/index.js +1 -2
  13. package/lib-module/ExpandCollapse/Panel.js +1 -1
  14. package/lib-module/Footnote/Footnote.js +319 -0
  15. package/lib-module/Footnote/FootnoteLink.js +101 -0
  16. package/lib-module/Footnote/dictionary.js +12 -0
  17. package/lib-module/Footnote/index.js +4 -0
  18. package/lib-module/Notification/Notification.js +216 -38
  19. package/lib-module/Responsive/Responsive.js +8 -0
  20. package/lib-module/Responsive/ResponsiveWithMediaQueryStyleSheet.js +6 -3
  21. package/lib-module/Typography/Typography.js +3 -1
  22. package/lib-module/index.js +1 -0
  23. package/lib-module/utils/ssr-media-query/create-stylesheet/index.js +1 -2
  24. package/package.json +2 -2
  25. package/src/ExpandCollapse/Panel.jsx +1 -1
  26. package/src/Footnote/Footnote.jsx +316 -0
  27. package/src/Footnote/FootnoteLink.jsx +95 -0
  28. package/src/Footnote/dictionary.js +12 -0
  29. package/src/Footnote/index.js +6 -0
  30. package/src/Notification/Notification.jsx +213 -34
  31. package/src/Responsive/Responsive.jsx +8 -2
  32. package/src/Responsive/ResponsiveWithMediaQueryStyleSheet.jsx +6 -4
  33. package/src/Typography/Typography.jsx +6 -1
  34. package/src/index.js +1 -0
  35. package/src/utils/ssr-media-query/create-stylesheet/index.js +3 -2
@@ -1,8 +1,13 @@
1
- import React, { forwardRef, useState } from 'react'
2
- import { StyleSheet, View } from 'react-native'
1
+ import React, { forwardRef, useState, useRef } from 'react'
2
+ import { View } from 'react-native'
3
3
 
4
4
  import PropTypes from 'prop-types'
5
- import { applyTextStyles, useTheme, useThemeTokens } from '../ThemeProvider'
5
+ import {
6
+ applyTextStyles,
7
+ useTheme,
8
+ useThemeTokens,
9
+ useResponsiveThemeTokens
10
+ } from '../ThemeProvider'
6
11
  import {
7
12
  a11yProps,
8
13
  getTokensPropType,
@@ -11,7 +16,9 @@ import {
11
16
  variantProp,
12
17
  viewProps,
13
18
  wrapStringsInText,
14
- useResponsiveProp
19
+ useResponsiveProp,
20
+ createMediaQueryStyles,
21
+ StyleSheet
15
22
  } from '../utils'
16
23
  import IconButton from '../IconButton'
17
24
  import useCopy from '../utils/useCopy'
@@ -61,6 +68,110 @@ const selectContentContainerStyle = (maxWidth) => ({
61
68
  width: maxWidth || '100%'
62
69
  })
63
70
 
71
+ const getMediaQueryStyles = (themeTokens, themeOptions, viewport, mediaIdsRef, dismissible) => {
72
+ const transformedSelectContainerStyles = Object.entries(themeTokens).reduce(
73
+ (acc, [vp, viewportTokens]) => {
74
+ acc[vp] = selectContainerStyles({ ...viewportTokens })
75
+ return acc
76
+ },
77
+ {}
78
+ )
79
+
80
+ const selectContainerMediaQueryStyles = createMediaQueryStyles(transformedSelectContainerStyles)
81
+
82
+ const { ids: containerIds, styles: containerStyles } = StyleSheet.create({
83
+ container: { flexDirection: 'row', ...selectContainerMediaQueryStyles }
84
+ })
85
+
86
+ const { ids: contentContainerIds, styles: contentContainerStyles } = StyleSheet.create({
87
+ contentContainer: {
88
+ flexDirection: 'row',
89
+ flexShrink: 1,
90
+ justifyContent: 'space-between',
91
+ ...createMediaQueryStyles({
92
+ xs: { width: themeOptions?.contentMaxWidth.xs || '100%' },
93
+ md: { width: themeOptions?.contentMaxWidth.md || '100%' },
94
+ lg: { width: themeOptions?.contentMaxWidth.lg || '100%' },
95
+ sm: { width: themeOptions?.contentMaxWidth.sm || '100%' },
96
+ xl: { width: themeOptions?.contentMaxWidth.xl || '100%' }
97
+ })
98
+ }
99
+ })
100
+
101
+ const { ids: staticContentContainerIds, styles: staticContentContainerStyles } =
102
+ StyleSheet.create({
103
+ staticContentContainer: { flexDirection: 'row', flexShrink: 1 }
104
+ })
105
+
106
+ const { ids: iconContainerIds, styles: iconContainerStyles } = StyleSheet.create({
107
+ iconContainer: selectIconContainerStyles(themeTokens[viewport])
108
+ })
109
+
110
+ const { ids: dismissButtonContainerIds, styles: dismissButtonContainerStyles } =
111
+ StyleSheet.create({
112
+ dismissButtonContainer: selectDismissButtonContainerStyles(themeTokens[viewport])
113
+ })
114
+
115
+ const { ids: textIds, styles: textStyles } = StyleSheet.create({
116
+ text: selectTextStyles(themeTokens[viewport], themeOptions, dismissible)
117
+ })
118
+
119
+ const { styles: selectIconPropsStyles } = StyleSheet.create({
120
+ selectIconProps: selectIconProps(themeTokens[viewport])
121
+ })
122
+
123
+ const { styles: selectDismissIconPropsStyles } = StyleSheet.create({
124
+ selectDismissIconProps: selectDismissIconProps(themeTokens[viewport])
125
+ })
126
+
127
+ // eslint-disable-next-line no-param-reassign
128
+ mediaIdsRef.current = {
129
+ containerIds,
130
+ contentContainerIds,
131
+ staticContentContainerIds,
132
+ iconContainerIds,
133
+ dismissButtonContainerIds,
134
+ textIds
135
+ }
136
+
137
+ return {
138
+ containerStyles,
139
+ contentContainerStyles,
140
+ staticContentContainerStyles,
141
+ iconContainerStyles,
142
+ dismissButtonContainerStyles,
143
+ textStyles,
144
+ selectIconPropsStyles,
145
+ selectDismissIconPropsStyles
146
+ }
147
+ }
148
+
149
+ const getDefaultStyles = (themeTokens, themeOptions, maxWidth, dismissible) => ({
150
+ containerStyles: {
151
+ container: { flexDirection: 'row', ...selectContainerStyles(themeTokens) }
152
+ },
153
+ contentContainerStyles: {
154
+ contentContainer: {
155
+ flexDirection: 'row',
156
+ flexShrink: 1,
157
+ justifyContent: 'space-between',
158
+ ...selectContentContainerStyle(maxWidth)
159
+ }
160
+ },
161
+ staticContentContainerStyles: {
162
+ staticContentContainer: { flexDirection: 'row', flexShrink: 1 }
163
+ },
164
+ iconContainerStyles: { iconContainer: { ...selectIconContainerStyles(themeTokens) } },
165
+ dismissButtonContainerStyles: {
166
+ dismissButtonContainer: { ...selectDismissButtonContainerStyles(themeTokens) }
167
+ },
168
+ textStyles: { text: { ...selectTextStyles(themeTokens, themeOptions, dismissible) } },
169
+ selectIconPropsStyles: { selectIconProps: { ...selectIconProps(themeTokens) } },
170
+ selectDismissIconPropsStyles: {
171
+ selectDismissIconProps: { ...selectDismissIconProps(themeTokens) }
172
+ }
173
+ })
174
+
64
175
  /**
65
176
  * A banner that highlights important messages:
66
177
  * - Status message to show there is an error or outage of services
@@ -116,43 +227,121 @@ const Notification = forwardRef(
116
227
  ({ children, system, dismissible, copy = 'en', tokens, variant, ...rest }, ref) => {
117
228
  const [isDismissed, setIsDismissed] = useState(false)
118
229
  const viewport = useViewport()
119
- const themeTokens = useThemeTokens('Notification', tokens, variant, { system, viewport })
120
230
  const getCopy = useCopy({ dictionary, copy })
231
+
121
232
  const { themeOptions } = useTheme()
122
- const contentMaxWidth = useResponsiveProp(themeOptions?.contentMaxWidth)
233
+ const { enableMediaQueryStyleSheet } = themeOptions
234
+ const useTokens = enableMediaQueryStyleSheet ? useResponsiveThemeTokens : useThemeTokens
235
+ const themeTokens = useTokens('Notification', tokens, variant, { system, viewport })
236
+ const maxWidth = useResponsiveProp(themeOptions?.contentMaxWidth)
237
+
238
+ const notificationComponentRef = useRef({
239
+ containerStyles: {},
240
+ contentContainerStyles: {},
241
+ staticContentContainerStyles: {},
242
+ iconContainerStyles: {},
243
+ dismissButtonContainerStyles: {},
244
+ textStyles: {},
245
+ selectIconPropsStyles: {},
246
+ selectDismissIconPropsStyles: {}
247
+ })
248
+ const mediaIdsRef = useRef({
249
+ containerIds: {},
250
+ contentContainerIds: {},
251
+ staticContentContainerIds: {},
252
+ iconContainerIds: {},
253
+ dismissButtonContainerIds: {},
254
+ textIds: {},
255
+ selectIconPropsIds: {},
256
+ selectDismissIconPropsIds: {}
257
+ })
258
+
259
+ if (enableMediaQueryStyleSheet) {
260
+ notificationComponentRef.current = getMediaQueryStyles(
261
+ themeTokens,
262
+ themeOptions,
263
+ viewport,
264
+ mediaIdsRef,
265
+ dismissible
266
+ )
267
+ } else {
268
+ notificationComponentRef.current = getDefaultStyles(
269
+ themeTokens,
270
+ themeOptions,
271
+ maxWidth,
272
+ dismissible
273
+ )
274
+ }
123
275
 
124
276
  if (isDismissed) {
125
277
  return null
126
278
  }
127
279
 
128
- const textStyles = selectTextStyles(themeTokens, themeOptions, dismissible)
129
-
130
280
  const content = wrapStringsInText(
131
- typeof children === 'function' ? children({ textStyles, variant }) : children,
132
- { style: textStyles }
281
+ typeof children === 'function'
282
+ ? children({ textStyles: notificationComponentRef.current.textStyles.text, variant })
283
+ : children,
284
+ { style: notificationComponentRef.current.textStyles.text }
133
285
  )
134
286
 
135
- const { icon: IconComponent, dismissIcon: DismissIconComponent, dismissIconColor } = themeTokens
287
+ const {
288
+ icon: IconComponent,
289
+ dismissIcon: DismissIconComponent,
290
+ dismissIconColor
291
+ } = enableMediaQueryStyleSheet === false ? themeTokens : themeTokens[viewport]
136
292
 
137
293
  const onDismissPress = () => setIsDismissed(true)
138
294
 
139
295
  return (
140
296
  <View
141
297
  ref={ref}
142
- style={[staticStyles.container, selectContainerStyles(themeTokens)]}
298
+ style={notificationComponentRef.current.containerStyles.container}
299
+ dataSet={mediaIdsRef && { media: mediaIdsRef.current.containerIds.container }}
143
300
  {...selectProps(rest)}
144
301
  >
145
- <View style={[staticStyles.content, selectContentContainerStyle(contentMaxWidth)]}>
146
- <View style={staticStyles.contentContainer}>
302
+ <View
303
+ style={notificationComponentRef.current.contentContainerStyles.contentContainer}
304
+ dataSet={
305
+ mediaIdsRef && { media: mediaIdsRef.current.contentContainerIds.contentContainer }
306
+ }
307
+ >
308
+ <View
309
+ style={
310
+ notificationComponentRef.current.staticContentContainerStyles.staticContentContainer
311
+ }
312
+ dataSet={
313
+ mediaIdsRef && {
314
+ media: mediaIdsRef.current.staticContentContainerIds.staticContentContainer
315
+ }
316
+ }
317
+ >
147
318
  {IconComponent && (
148
- <View style={selectIconContainerStyles(themeTokens)}>
149
- <IconComponent {...selectIconProps(themeTokens)} />
319
+ <View
320
+ style={notificationComponentRef.current.iconContainerStyles.iconContainer}
321
+ dataSet={
322
+ mediaIdsRef && { media: mediaIdsRef.current.iconContainerIds.iconContainer }
323
+ }
324
+ >
325
+ <IconComponent
326
+ {...notificationComponentRef.current.selectIconPropsStyles.selectIconProps}
327
+ />
150
328
  </View>
151
329
  )}
152
- {content && typeof content === 'function' ? content({ textStyles, variant }) : content}
330
+ {content && typeof content === 'function'
331
+ ? content({ textStyles: notificationComponentRef.current.textStyles.text, variant })
332
+ : content}
153
333
  </View>
154
334
  {dismissible && DismissIconComponent && (
155
- <View style={selectDismissButtonContainerStyles(themeTokens)}>
335
+ <View
336
+ style={
337
+ notificationComponentRef.current.dismissButtonContainerStyles.dismissButtonContainer
338
+ }
339
+ dataSet={
340
+ mediaIdsRef && {
341
+ media: mediaIdsRef.current.dismissButtonContainerIds.dismissButtonContainer
342
+ }
343
+ }
344
+ >
156
345
  <IconButton
157
346
  action="close"
158
347
  onPress={onDismissPress}
@@ -161,7 +350,12 @@ const Notification = forwardRef(
161
350
  accessibilityLabel={getCopy('dismiss')}
162
351
  variant={{ inverse: dismissIconColor === '#ffffff', size: 'small' }}
163
352
  >
164
- {() => <DismissIconComponent {...selectDismissIconProps(themeTokens)} />}
353
+ {() => (
354
+ <DismissIconComponent
355
+ {...notificationComponentRef.current.selectDismissIconPropsStyles
356
+ .selectDismissIconProps}
357
+ />
358
+ )}
165
359
  </IconButton>
166
360
  </View>
167
361
  )}
@@ -198,18 +392,3 @@ Notification.propTypes = {
198
392
  }
199
393
 
200
394
  export default Notification
201
-
202
- const staticStyles = StyleSheet.create({
203
- container: {
204
- flexDirection: 'row'
205
- },
206
- contentContainer: {
207
- flexDirection: 'row',
208
- flexShrink: 1
209
- },
210
- content: {
211
- flexDirection: 'row',
212
- flexShrink: 1,
213
- justifyContent: 'space-between'
214
- }
215
- })
@@ -17,13 +17,13 @@ import ResponsiveWithMediaQueryStyleSheet from './ResponsiveWithMediaQueryStyleS
17
17
  * is used to hide and show children of `Responsive` within a View.
18
18
  */
19
19
 
20
- const Responsive = ({ min = 'xs', max, children }) => {
20
+ const Responsive = ({ min = 'xs', max, inheritedStyles = [], children }) => {
21
21
  const {
22
22
  themeOptions: { enableMediaQueryStyleSheet }
23
23
  } = useTheme()
24
24
  if (enableMediaQueryStyleSheet) {
25
25
  return (
26
- <ResponsiveWithMediaQueryStyleSheet min={min} max={max}>
26
+ <ResponsiveWithMediaQueryStyleSheet inheritedStyles={inheritedStyles} min={min} max={max}>
27
27
  {children}
28
28
  </ResponsiveWithMediaQueryStyleSheet>
29
29
  )
@@ -46,6 +46,12 @@ Responsive.propTypes = {
46
46
  * To hide children of `Responsive` if the current viewport is larger than `max`
47
47
  */
48
48
  max: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
49
+ /**
50
+ * Styles to be inherited by `Responsive`.
51
+ * It should be an array of style property names.
52
+ * Note: This prop is only applicable when `enableMediaQueryStylesheet` is set to true in the `ThemeProvider`.
53
+ */
54
+ inheritedStyles: PropTypes.arrayOf(PropTypes.string),
49
55
  children: PropTypes.node.isRequired
50
56
  }
51
57
 
@@ -25,12 +25,13 @@ function generateResponsiveStyles(min, max) {
25
25
  })
26
26
  return createMediaQueryStyles(styles, false)
27
27
  }
28
- const ResponsiveWithMediaQueryStyleSheet = ({ min, max, children }) => {
28
+ const ResponsiveWithMediaQueryStyleSheet = ({ min, max, inheritedStyles = [], children }) => {
29
29
  const { ids, styles } = StyleSheet.create({
30
30
  responsive: {
31
- flexDirection: 'inherit',
32
- alignItems: 'inherit',
33
- justifyContent: 'inherit',
31
+ ...inheritedStyles.reduce((acc, prop) => {
32
+ acc[prop] = 'inherit'
33
+ return acc
34
+ }, {}),
34
35
  ...generateResponsiveStyles(min, max)
35
36
  }
36
37
  })
@@ -52,6 +53,7 @@ ResponsiveWithMediaQueryStyleSheet.propTypes = {
52
53
  * To hide children of `Responsive` if the current viewport is larger than `max`
53
54
  */
54
55
  max: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
56
+ inheritedStyles: PropTypes.arrayOf(PropTypes.string),
55
57
  children: PropTypes.node.isRequired
56
58
  }
57
59
 
@@ -76,7 +76,12 @@ const Typography = forwardRef(
76
76
  const { enableMediaQueryStyleSheet } = themeOptions
77
77
 
78
78
  const useTokens = enableMediaQueryStyleSheet ? useResponsiveThemeTokens : useThemeTokens
79
- const themeTokens = useTokens('Typography', tokens, variant)
79
+ const themeTokens = useTokens(
80
+ 'Typography',
81
+ tokens,
82
+ variant,
83
+ !enableMediaQueryStyleSheet && { viewport }
84
+ )
80
85
  const maxFontSizeMultiplier = enableMediaQueryStyleSheet
81
86
  ? getMaxFontMultiplier(themeTokens[viewport])
82
87
  : getMaxFontMultiplier(themeTokens)
package/src/index.js CHANGED
@@ -17,6 +17,7 @@ export { default as ExpandCollapse, Accordion } from './ExpandCollapse'
17
17
  export { default as Feedback } from './Feedback'
18
18
  export { default as Fieldset } from './Fieldset'
19
19
  export { default as FlexGrid } from './FlexGrid'
20
+ export { default as Footnote } from './Footnote'
20
21
  export { default as HorizontalScroll } from './HorizontalScroll'
21
22
  export * from './HorizontalScroll'
22
23
  export { default as Icon } from './Icon'
@@ -5,13 +5,14 @@ import { isMediaOrPseudo, deepClone, createCssRule } from '../utils/common'
5
5
 
6
6
  const createStyleSheet = (stylesWithQuery) => {
7
7
  if (!stylesWithQuery) return { ids: {}, styles: {}, fullStyles: {} }
8
- let cleanStyles
8
+
9
9
  let ids = {}
10
+ const cleanStyles = deepClone(stylesWithQuery)
11
+
10
12
  Object.keys(stylesWithQuery).forEach((key) => {
11
13
  if (!stylesWithQuery?.[key]) return
12
14
 
13
15
  const mediaQueriesAndPseudoClasses = Object.keys(stylesWithQuery[key]).filter(isMediaOrPseudo)
14
- cleanStyles = deepClone(stylesWithQuery)
15
16
  mediaQueriesAndPseudoClasses.forEach((query) => {
16
17
  const css = createDeclarationBlock(stylesWithQuery[key][query])
17
18
  const stringHash = `rnmq-${hash(`${key}${query}${css}`)}`