@telus-uds/components-base 2.4.0 → 2.5.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 (82) hide show
  1. package/CHANGELOG.md +15 -2
  2. package/lib/A11yInfoProvider/index.js +2 -2
  3. package/lib/Autocomplete/Autocomplete.js +22 -32
  4. package/lib/Autocomplete/Suggestions.js +1 -1
  5. package/lib/BaseProvider/HydrationContext.js +1 -2
  6. package/lib/BaseProvider/index.js +1 -2
  7. package/lib/Button/ButtonDropdown.js +1 -1
  8. package/lib/Card/Card.js +12 -13
  9. package/lib/Card/CardBase.js +1 -1
  10. package/lib/Card/PressableCardBase.js +1 -1
  11. package/lib/CardGroup/CardGroup.js +3 -3
  12. package/lib/Carousel/Carousel.js +5 -6
  13. package/lib/Carousel/CarouselStepTracker/CarouselStepTracker.js +3 -0
  14. package/lib/Carousel/CarouselTabs/CarouselTabs.js +1 -2
  15. package/lib/Carousel/CarouselTabs/CarouselTabsPanel.js +1 -1
  16. package/lib/Carousel/CarouselTabs/CarouselTabsPanelItem.js +1 -1
  17. package/lib/Carousel/CarouselThumbnail.js +1 -1
  18. package/lib/Checkbox/Checkbox.js +1 -1
  19. package/lib/ColourToggle/ColourToggle.js +1 -1
  20. package/lib/ExpandCollapseMini/ExpandCollapseMini.js +77 -0
  21. package/lib/ExpandCollapseMini/ExpandCollapseMiniControl.js +126 -0
  22. package/lib/ExpandCollapseMini/index.js +2 -0
  23. package/lib/Footnote/Footnote.js +4 -4
  24. package/lib/HorizontalScroll/HorizontalScroll.js +1 -2
  25. package/lib/Icon/Icon.js +1 -1
  26. package/lib/Icon/IconText.js +2 -3
  27. package/lib/IconButton/IconButton.js +1 -2
  28. package/lib/InputSupports/InputSupports.js +4 -4
  29. package/lib/Link/LinkBase.js +8 -3
  30. package/lib/List/List.js +1 -2
  31. package/lib/List/ListItemContent.js +1 -1
  32. package/lib/Listbox/Listbox.js +5 -8
  33. package/lib/Listbox/PressableItem.js +4 -4
  34. package/lib/Modal/Modal.js +4 -7
  35. package/lib/MultiSelectFilter/MultiSelectFilter.js +1 -1
  36. package/lib/Notification/Notification.js +10 -12
  37. package/lib/OrderedList/OrderedList.js +2 -3
  38. package/lib/Pagination/usePagination.js +1 -2
  39. package/lib/PriceLockup/utils/renderFootnoteContent.js +2 -2
  40. package/lib/PriceLockup/utils/renderFootnoteLinks.js +2 -2
  41. package/lib/PriceLockup/utils/renderPrice.js +2 -2
  42. package/lib/ProductCard/ProductCard.js +2 -3
  43. package/lib/Progress/ProgressBarBackground.js +2 -2
  44. package/lib/QuickLinksFeature/QuickLinksFeature.js +1 -2
  45. package/lib/Radio/Radio.js +1 -1
  46. package/lib/Search/Search.js +2 -3
  47. package/lib/Select/Picker.js +2 -2
  48. package/lib/StackView/StackWrap.js +1 -4
  49. package/lib/StackView/getStackedContent.js +1 -2
  50. package/lib/StepTracker/StepTracker.js +1 -2
  51. package/lib/TabBar/TabBar.js +1 -1
  52. package/lib/Tabs/Tabs.js +1 -1
  53. package/lib/Tabs/TabsItem.js +2 -2
  54. package/lib/TextInput/TextArea.js +1 -1
  55. package/lib/TextInput/TextInput.js +1 -1
  56. package/lib/TextInput/TextInputBase.js +10 -12
  57. package/lib/ThemeProvider/utils/theme-tokens.js +2 -4
  58. package/lib/Timeline/Timeline.js +1 -2
  59. package/lib/Tooltip/Tooltip.native.js +4 -4
  60. package/lib/Typography/Typography.js +4 -5
  61. package/lib/Validator/Validator.js +9 -14
  62. package/lib/ViewportProvider/useViewportListener.js +1 -1
  63. package/lib/index.js +1 -0
  64. package/lib/utils/children.js +2 -6
  65. package/lib/utils/input.js +1 -1
  66. package/lib/utils/props/componentPropType.js +1 -2
  67. package/lib/utils/props/selectSystemProps.js +2 -2
  68. package/lib/utils/ssr-media-query/create-stylesheet/create-stylesheet-mobile.js +1 -1
  69. package/lib/utils/ssr-media-query/create-stylesheet/index.js +2 -3
  70. package/lib/utils/ssr-media-query/utils/inject.js +3 -5
  71. package/lib/utils/useHash.js +1 -4
  72. package/lib/utils/useOverlaidPosition.js +25 -4
  73. package/lib/utils/useScrollBlocking.js +2 -4
  74. package/lib/utils/useSpacingScale.js +2 -2
  75. package/package.json +1 -1
  76. package/src/Carousel/CarouselStepTracker/CarouselStepTracker.jsx +3 -0
  77. package/src/ExpandCollapseMini/ExpandCollapseMini.jsx +76 -0
  78. package/src/ExpandCollapseMini/ExpandCollapseMiniControl.jsx +119 -0
  79. package/src/ExpandCollapseMini/index.js +3 -0
  80. package/src/Link/LinkBase.jsx +8 -3
  81. package/src/index.js +1 -0
  82. package/src/utils/useOverlaidPosition.js +23 -0
@@ -0,0 +1,76 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import ExpandCollapse from '../ExpandCollapse'
4
+ import { getTokensPropType } from '../utils'
5
+ import ExpandCollapseMiniControl from './ExpandCollapseMiniControl'
6
+
7
+ const ExpandCollapseMini = React.forwardRef(
8
+ ({ children, onToggle = () => {}, tokens = {}, nativeID, initialOpen = false, ...rest }, ref) => {
9
+ const expandCollapeMiniPanelId = 'ExpandCollapseMiniPanel'
10
+ const handleChange = (openPanels, event) => {
11
+ if (typeof onToggle === 'function') {
12
+ const isOpen = openPanels.length > 0
13
+ onToggle(event, isOpen)
14
+ }
15
+ }
16
+
17
+ return (
18
+ <ExpandCollapse
19
+ onChange={handleChange}
20
+ tokens={tokens}
21
+ initialOpen={initialOpen ? [expandCollapeMiniPanelId] : []}
22
+ >
23
+ {(expandProps) => (
24
+ <ExpandCollapse.Panel
25
+ {...expandProps}
26
+ panelId={expandCollapeMiniPanelId}
27
+ variant={{ mini: true }}
28
+ controlTokens={{
29
+ // Remove unwanted look and feel from ExpandCollapse(background pressed, focus border and text underline)
30
+ icon: null,
31
+ borderColor: 'transparent',
32
+ textLine: 'none',
33
+ backgroundColor: 'transparent'
34
+ }}
35
+ // TODO refactor
36
+ // eslint-disable-next-line react/no-unstable-nested-components
37
+ control={(pressableState) => (
38
+ <ExpandCollapseMiniControl pressableState={pressableState} {...rest} />
39
+ )}
40
+ controlRef={ref}
41
+ nativeID={nativeID}
42
+ >
43
+ {children}
44
+ </ExpandCollapse.Panel>
45
+ )}
46
+ </ExpandCollapse>
47
+ )
48
+ }
49
+ )
50
+ ExpandCollapseMini.displayName = 'ExpandCollapseMini'
51
+
52
+ ExpandCollapseMini.propTypes = {
53
+ ...ExpandCollapseMiniControl.propTypes,
54
+ /**
55
+ * Function to call on pressing the panel's control, which should open or close the panel.
56
+ */
57
+ onToggle: PropTypes.func,
58
+ /**
59
+ * ID for DOM element on web
60
+ */
61
+ nativeID: PropTypes.string,
62
+ /**
63
+ * Children nodes that can be added
64
+ */
65
+ children: PropTypes.node.isRequired,
66
+ /**
67
+ * Controls if the panel and the content is opened by default on the first load
68
+ */
69
+ initialOpen: PropTypes.bool,
70
+ /**
71
+ * Optional variant object to override the default theme tokens
72
+ */
73
+ tokens: getTokensPropType('ExpandCollapseMini')
74
+ }
75
+
76
+ export default ExpandCollapseMini
@@ -0,0 +1,119 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { Platform } from 'react-native'
4
+ import { Link } from '../Link'
5
+ import { useThemeTokens } from '../ThemeProvider'
6
+ import { htmlAttrs, viewProps, selectSystemProps } from '../utils'
7
+
8
+ const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, viewProps])
9
+
10
+ // The ExpandCollapseControl has all the appropriate role, a11y, press handling etc
11
+ // and a more appropriate press area, defer interaction handling to it.
12
+ const presentationOnly = {
13
+ accessibilityRole: null, // Treat as regular flow content with the Control
14
+ pointerEvents: 'none', // Stop RNW from stopping clicks from bubbling to Control
15
+ focusable: false // Stop RNW from setting tabIndex={0}: focus goes to Control only
16
+ }
17
+
18
+ const selectLinkTokens = ({ color, textLine, lineHeight, fontSize }) => ({
19
+ color,
20
+ textLine,
21
+ blockLineHeight: lineHeight,
22
+ blockFontSize: fontSize
23
+ })
24
+
25
+ const ExpandCollapseMiniControl = React.forwardRef(
26
+ (
27
+ {
28
+ pressableState,
29
+ collapseTitle,
30
+ expandTitle = collapseTitle,
31
+ iconPosition = 'right',
32
+ tokens,
33
+ variant = {},
34
+ ...rest
35
+ },
36
+ ref
37
+ ) => {
38
+ const { expanded, hover, focus } = pressableState || {}
39
+ // we only want focus outline when focusing, if user is pressing we don't want the border.
40
+ const { outerBorderColor } = useThemeTokens(
41
+ 'Link',
42
+ {},
43
+ {},
44
+ { focus: Platform.OS !== 'web' ? expanded : focus }
45
+ )
46
+ const { size, icon, ...themeTokens } = useThemeTokens(
47
+ 'ExpandCollapseMiniControl',
48
+ tokens,
49
+ variant,
50
+ { expanded, focus }
51
+ )
52
+
53
+ // Choose hover styles when any part of Control is hoverred
54
+ const appearance = { ...variant, hover }
55
+
56
+ const getTokens = (linkState) => {
57
+ const { hover: linkHover } = linkState || {}
58
+ const isHovered = hover || linkHover
59
+
60
+ if (Platform.OS !== 'web') {
61
+ return { iconTranslateY: -1 }
62
+ }
63
+
64
+ if (isHovered) {
65
+ // Include vertical icon animation on hover alongside built-in Link theme, the size is size4
66
+ return { iconTranslateY: (expanded ? -1 : 1) * size }
67
+ }
68
+
69
+ return {}
70
+ }
71
+
72
+ return (
73
+ <Link
74
+ variant={appearance}
75
+ icon={icon}
76
+ iconPosition={iconPosition}
77
+ tokens={(linkState) => ({
78
+ ...getTokens(linkState),
79
+ ...selectLinkTokens(themeTokens),
80
+ outerBorderColor
81
+ })}
82
+ ref={ref}
83
+ {...presentationOnly}
84
+ {...selectProps(rest)}
85
+ >
86
+ {expanded ? expandTitle : collapseTitle}
87
+ </Link>
88
+ )
89
+ }
90
+ )
91
+
92
+ ExpandCollapseMiniControl.displayName = 'ExpandCollapseMiniControl'
93
+
94
+ ExpandCollapseMiniControl.propTypes = {
95
+ ...selectedSystemPropTypes,
96
+ ...Link.propTypes,
97
+ /**
98
+ * Optional function to call on pressing the panel's control, in addition to opening or closing the panel
99
+ */
100
+ onPress: PropTypes.func,
101
+ /**
102
+ * ExpandCollapseMiniControl title when expanded
103
+ */
104
+ expandTitle: PropTypes.string.isRequired,
105
+ /**
106
+ * ExpandCollapseMiniControl title when collapsed
107
+ */
108
+ collapseTitle: PropTypes.string.isRequired,
109
+ /**
110
+ * React Native's `Pressable`'s state object
111
+ */
112
+ pressableState: PropTypes.object,
113
+ /**
114
+ * Optional variant object to override the default theme tokens
115
+ */
116
+ variant: PropTypes.object
117
+ }
118
+
119
+ export default ExpandCollapseMiniControl
@@ -0,0 +1,3 @@
1
+ import ExpandCollapseMini from './ExpandCollapseMini'
2
+
3
+ export default ExpandCollapseMini
@@ -81,18 +81,19 @@ const selectDecorationStyles = ({ color, textLine, textLineStyle, alignSelf }) =
81
81
  })
82
82
  })
83
83
 
84
- const selectIconTokens = ({ color, iconSize, blockFontSize, iconTranslateX }) => {
84
+ const selectIconTokens = ({ color, iconSize, blockFontSize, iconTranslateX, iconTranslateY }) => {
85
85
  /**
86
86
  * These calculations were carried out using a set of linear equations to calculate that the
87
87
  * position of the icon "->"" is aligned to the first line of the tooltip text.
88
88
  * The base equation is: X/4 + Y/4 - 4 - |X - Y| = Z
89
89
  * where X = blockFontSize, Y = iconSize and Z = translateY
90
90
  */
91
- const translateY = blockFontSize / 4 + iconSize / 4 - 4 - Math.abs(iconSize - blockFontSize)
91
+ const translateY =
92
+ iconTranslateY ?? blockFontSize / 4 + iconSize / 4 - 4 - Math.abs(iconSize - blockFontSize)
92
93
  return {
93
94
  color,
94
95
  translateX: iconTranslateX,
95
- translateY: translateY < 0 ? 0 : translateY,
96
+ translateY,
96
97
  size: iconSize
97
98
  }
98
99
  }
@@ -274,6 +275,10 @@ const staticStyles = StyleSheet.create({
274
275
  margin: 0,
275
276
  marginHorizontal: 2,
276
277
  padding: 0
278
+ }),
279
+ ...(Platform.OS === 'android' && {
280
+ paddingHorizontal: 2,
281
+ paddingTop: 2
277
282
  })
278
283
  }
279
284
  })
package/src/index.js CHANGED
@@ -18,6 +18,7 @@ export { default as ColourToggle } from './ColourToggle'
18
18
  export { default as DownloadApp } from './DownloadApp'
19
19
  export { default as Divider } from './Divider'
20
20
  export { default as ExpandCollapse, Accordion } from './ExpandCollapse'
21
+ export { default as ExpandCollapseMini } from './ExpandCollapseMini'
21
22
  export { default as Feedback } from './Feedback'
22
23
  export { default as Fieldset } from './Fieldset'
23
24
  export { default as FlexGrid } from './FlexGrid'
@@ -1,5 +1,8 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react'
2
2
  import { Dimensions, Platform } from 'react-native'
3
+ import debounce from 'lodash.debounce'
4
+
5
+ const DEBOUNCE_DELAY = 100
3
6
 
4
7
  const adjustHorizontalToFit = (initialOffset, windowWidth, sourceWidth) => {
5
8
  const offset = Math.max(0, initialOffset)
@@ -200,6 +203,26 @@ const useOverlaidPosition = ({
200
203
  return unsubscribe
201
204
  }, [readyToShow])
202
205
 
206
+ useEffect(() => {
207
+ if (Platform.OS !== 'web') {
208
+ return undefined
209
+ }
210
+
211
+ const handleScroll = debounce(() => {
212
+ sourceRef.current?.measureInWindow((x, y, width, height) => {
213
+ setWindowDimensions(window)
214
+ setSourceLayout({ x, y, width, height })
215
+ })
216
+ }, DEBOUNCE_DELAY)
217
+
218
+ window.addEventListener('scroll', handleScroll)
219
+
220
+ return () => {
221
+ window.removeEventListener('scroll', handleScroll)
222
+ handleScroll.cancel()
223
+ }
224
+ }, [sourceRef])
225
+
203
226
  const isReady = Boolean(isShown && sourceLayout && windowDimensions && targetDimensions)
204
227
 
205
228
  const overlaidPosition = isReady