@telus-uds/components-base 3.29.1 → 3.31.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 (71) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/lib/cjs/Autocomplete/Autocomplete.js +13 -1
  3. package/lib/cjs/Autocomplete/constants.js +1 -1
  4. package/lib/cjs/Carousel/Carousel.js +6 -1
  5. package/lib/cjs/Carousel/CarouselThumbnail.js +123 -31
  6. package/lib/cjs/Carousel/CarouselThumbnailNavigation.js +8 -1
  7. package/lib/cjs/Footnote/FootnoteLink.js +18 -17
  8. package/lib/cjs/Listbox/ListboxOverlay.js +7 -1
  9. package/lib/cjs/MultiSelectFilter/ModalOverlay.js +7 -1
  10. package/lib/cjs/MultiSelectFilter/MultiSelectFilter.js +2 -28
  11. package/lib/cjs/Progress/Progress.js +30 -5
  12. package/lib/cjs/Scroll/Scroll.js +466 -0
  13. package/lib/cjs/Scroll/ScrollContext.js +55 -0
  14. package/lib/cjs/Scroll/ScrollItem.js +103 -0
  15. package/lib/cjs/Scroll/ScrollProgress.js +99 -0
  16. package/lib/cjs/Scroll/dictionary.js +18 -0
  17. package/lib/cjs/Scroll/index.js +29 -0
  18. package/lib/cjs/TextInput/TextInputBase.js +2 -1
  19. package/lib/cjs/index.js +15 -0
  20. package/lib/cjs/utils/animation/index.js +7 -0
  21. package/lib/cjs/utils/animation/useAnimatedValue.js +46 -0
  22. package/lib/cjs/utils/children.js +2 -1
  23. package/lib/cjs/utils/useOverlaidPosition.js +83 -42
  24. package/lib/esm/Autocomplete/Autocomplete.js +13 -1
  25. package/lib/esm/Autocomplete/constants.js +1 -1
  26. package/lib/esm/Carousel/Carousel.js +6 -1
  27. package/lib/esm/Carousel/CarouselThumbnail.js +124 -32
  28. package/lib/esm/Carousel/CarouselThumbnailNavigation.js +8 -1
  29. package/lib/esm/Footnote/FootnoteLink.js +18 -17
  30. package/lib/esm/Listbox/ListboxOverlay.js +7 -1
  31. package/lib/esm/MultiSelectFilter/ModalOverlay.js +8 -2
  32. package/lib/esm/MultiSelectFilter/MultiSelectFilter.js +2 -28
  33. package/lib/esm/Progress/Progress.js +30 -5
  34. package/lib/esm/Scroll/Scroll.js +459 -0
  35. package/lib/esm/Scroll/ScrollContext.js +47 -0
  36. package/lib/esm/Scroll/ScrollItem.js +96 -0
  37. package/lib/esm/Scroll/ScrollProgress.js +92 -0
  38. package/lib/esm/Scroll/dictionary.js +12 -0
  39. package/lib/esm/Scroll/index.js +4 -0
  40. package/lib/esm/TextInput/TextInputBase.js +2 -1
  41. package/lib/esm/index.js +1 -0
  42. package/lib/esm/utils/animation/index.js +1 -1
  43. package/lib/esm/utils/animation/useAnimatedValue.js +39 -0
  44. package/lib/esm/utils/children.js +2 -1
  45. package/lib/esm/utils/useOverlaidPosition.js +83 -42
  46. package/lib/package.json +2 -2
  47. package/package.json +2 -2
  48. package/src/Autocomplete/Autocomplete.jsx +11 -2
  49. package/src/Autocomplete/constants.js +1 -1
  50. package/src/Carousel/Carousel.jsx +6 -1
  51. package/src/Carousel/CarouselThumbnail.jsx +153 -64
  52. package/src/Carousel/CarouselThumbnailNavigation.jsx +8 -2
  53. package/src/Footnote/FootnoteLink.jsx +17 -12
  54. package/src/Listbox/ListboxOverlay.jsx +6 -2
  55. package/src/MultiSelectFilter/ModalOverlay.jsx +9 -3
  56. package/src/MultiSelectFilter/MultiSelectFilter.jsx +1 -31
  57. package/src/Progress/Progress.jsx +22 -3
  58. package/src/Scroll/Scroll.jsx +488 -0
  59. package/src/Scroll/ScrollContext.jsx +41 -0
  60. package/src/Scroll/ScrollItem.jsx +89 -0
  61. package/src/Scroll/ScrollProgress.jsx +75 -0
  62. package/src/Scroll/dictionary.js +12 -0
  63. package/src/Scroll/index.js +5 -0
  64. package/src/TextInput/TextInputBase.jsx +2 -1
  65. package/src/index.js +1 -0
  66. package/src/utils/animation/index.js +1 -1
  67. package/src/utils/animation/useAnimatedValue.js +37 -0
  68. package/src/utils/children.jsx +4 -1
  69. package/src/utils/useOverlaidPosition.js +84 -34
  70. package/types/Scroll.d.ts +66 -0
  71. package/types/index.d.ts +9 -0
@@ -14,22 +14,26 @@ import { applyTextStyles, useThemeTokens } from '../ThemeProvider'
14
14
 
15
15
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs, viewProps])
16
16
 
17
- // The top property varies between devices due to how devices render the viewport.
18
- const selectTextStyle = ({ fontSize, lineHeight }) => ({
19
- fontSize,
20
- lineHeight: lineHeight !== 1 ? lineHeight : fontSize * 2,
21
- ...Platform.select({
22
- ios: {
23
- top: -fontSize / 2
24
- },
25
- android: {
26
- top: fontSize / 4
17
+ const HALF_FONT_SIZE = 2
18
+ const QUARTER_FONT_SIZE = 4
19
+ const DEFAULT_LINE_HEIGHT = 1
20
+ const LINE_HEIGHT_MULTIPLIER = 2
21
+
22
+ const selectTextStyle = ({ fontSize, lineHeight }) =>
23
+ Platform.select({
24
+ native: {
25
+ fontSize: fontSize / HALF_FONT_SIZE,
26
+ lineHeight: fontSize,
27
+ position: 'relative',
28
+ top: -(fontSize * lineHeight) / HALF_FONT_SIZE
27
29
  },
28
30
  web: {
29
- top: -fontSize / 2.8
31
+ fontSize,
32
+ lineHeight:
33
+ lineHeight !== DEFAULT_LINE_HEIGHT ? lineHeight : fontSize * LINE_HEIGHT_MULTIPLIER,
34
+ top: -fontSize / QUARTER_FONT_SIZE
30
35
  }
31
36
  })
32
- })
33
37
 
34
38
  const FootnoteLink = React.forwardRef(
35
39
  ({ copy = 'en', content = [], onClick, tokens, variant = {}, ...rest }, ref) => {
@@ -70,6 +74,7 @@ const FootnoteLink = React.forwardRef(
70
74
  )
71
75
 
72
76
  FootnoteLink.displayName = 'FootnoteLink'
77
+ FootnoteLink.__UDS_COMPONENT_NAME__ = 'FootnoteLink'
73
78
 
74
79
  const copyShape = PropTypes.shape({ a11yLabel: PropTypes.string.isRequired })
75
80
 
@@ -1,6 +1,6 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { View, StyleSheet, Platform } from 'react-native'
3
+ import { View, StyleSheet, Platform, ScrollView } from 'react-native'
4
4
  import Portal from '../Portal'
5
5
  import { useThemeTokens } from '../ThemeProvider'
6
6
  import Card from '../Card'
@@ -69,7 +69,11 @@ const DropdownOverlay = React.forwardRef(
69
69
  paddingRight: paddingHorizontal
70
70
  }}
71
71
  >
72
- {children}
72
+ {Platform.OS !== 'web' ? (
73
+ <ScrollView style={{ maxHeight }}>{children}</ScrollView>
74
+ ) : (
75
+ children
76
+ )}
73
77
  </Card>
74
78
  </View>
75
79
  )
@@ -1,7 +1,8 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { View, StyleSheet, Platform } from 'react-native'
4
- import { Portal } from '@gorhom/portal'
4
+ import { Portal as GorhomPortal } from '@gorhom/portal'
5
+ import LocalPortal from '../Portal/Portal'
5
6
  import { useCopy, copyPropTypes, getTokensPropType, variantProp } from '../utils'
6
7
  import { useViewport } from '../ViewportProvider'
7
8
  import { useThemeTokens } from '../ThemeProvider'
@@ -105,8 +106,13 @@ const ModalOverlay = React.forwardRef(
105
106
  const getCopy = useCopy({ dictionary, copy })
106
107
  const closeLabel = getCopy('closeButton')
107
108
 
109
+ // On web, use the local Portal (always appends to document.body) to ensure correct
110
+ // absolute positioning in MFE/iframe contexts. @gorhom/portal may render its host
111
+ // outside the iframe's document, causing coordinate mismatches when scrolled.
112
+ const PortalComponent = Platform.OS === 'web' ? LocalPortal : GorhomPortal
113
+
108
114
  return (
109
- <Portal>
115
+ <PortalComponent>
110
116
  <View
111
117
  ref={containerRef}
112
118
  onLayout={onLayout}
@@ -135,7 +141,7 @@ const ModalOverlay = React.forwardRef(
135
141
  {children}
136
142
  </Card>
137
143
  </View>
138
- </Portal>
144
+ </PortalComponent>
139
145
  )
140
146
  }
141
147
  )
@@ -1,6 +1,5 @@
1
1
  import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import { Portal } from '@gorhom/portal'
4
3
  import { View, StyleSheet, Dimensions, SafeAreaView, Platform, ScrollView } from 'react-native'
5
4
  import { useThemeTokens, useThemeTokensCallback, applyTextStyles } from '../ThemeProvider'
6
5
  import {
@@ -221,27 +220,11 @@ const MultiSelectFilter = React.forwardRef(
221
220
  onCancel()
222
221
  }
223
222
 
224
- const appRootRef = React.useRef(null)
225
- const [rootOffsets, setRootOffsets] = React.useState(null)
226
-
227
- React.useEffect(() => {
228
- if (rootOffsets) return
229
- appRootRef.current?.measureInWindow((x, y) => {
230
- // Only set offsets if they are positive
231
- // this is because we want to avoid negative offsets that could cause
232
- // the dropdown to be positioned incorrectly in some situations
233
- if (y > 0) setRootOffsets({ horizontal: x, vertical: y })
234
- })
235
- }, [isOpen, rootOffsets])
236
-
237
223
  const { align, offsets } = useResponsiveProp({
238
224
  xs: { align: { top: 'top', left: 'left' } },
239
225
  sm: {
240
226
  align: { top: 'bottom', left: 'left' },
241
- offsets: {
242
- vertical: 4 - (rootOffsets?.vertical || 0),
243
- horizontal: -rootOffsets?.horizontal || 0
244
- }
227
+ offsets: { vertical: 4 }
245
228
  }
246
229
  })
247
230
 
@@ -367,14 +350,6 @@ const MultiSelectFilter = React.forwardRef(
367
350
 
368
351
  return (
369
352
  <>
370
- {/*
371
- This View is rendered inside a Portal to determine the application's root position.
372
- Capturing it is crucial to determine offsets to position the Modal correctly, preventing
373
- misalignment that can occur when the Portal does not render the Modal at the body level.
374
- */}
375
- <Portal>
376
- <View ref={appRootRef} style={styles.appRootRef} />
377
- </Portal>
378
353
  <ButtonDropdown
379
354
  ref={sourceRef}
380
355
  key={id}
@@ -464,11 +439,6 @@ const styles = StyleSheet.create({
464
439
  },
465
440
  scrollContainer: {
466
441
  padding: 1
467
- },
468
- appRootRef: {
469
- position: 'absolute',
470
- top: 0,
471
- left: 0
472
442
  }
473
443
  })
474
444
 
@@ -8,6 +8,9 @@ import ProgressContext from './ProgressContext'
8
8
 
9
9
  const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])
10
10
 
11
+ const BORDER_SIDES = 2
12
+ const CENTER_DIVISOR = 2
13
+
11
14
  const selectProgressStyles = ({
12
15
  backgroundColor,
13
16
  borderWidth,
@@ -24,6 +27,14 @@ const selectProgressStyles = ({
24
27
  ...applyShadowToken(shadow)
25
28
  })
26
29
 
30
+ const selectBarWrapperStyles = ({ barHeight, borderRadius, borderWidth, height }) => ({
31
+ height: barHeight,
32
+ width: '100%',
33
+ position: 'absolute',
34
+ top: (height - borderWidth * BORDER_SIDES - barHeight) / CENTER_DIVISOR,
35
+ borderRadius
36
+ })
37
+
27
38
  /**
28
39
  * The `Progress` is a container for displaying one or several `ProgressBar`s.
29
40
  *
@@ -36,10 +47,11 @@ const selectProgressStyles = ({
36
47
  *
37
48
  * - Use the following tokens to customize the appearance:
38
49
  * - `backgroundColor` for the background color of the progress container,
50
+ * - `barHeight` to control the height of the progress bars displayed within the container,
39
51
  * - `borderColor` to control the color of the border,
40
52
  * - `borderRadius` for the rounded corners,
41
53
  * - `borderWidth` to change the border width.
42
- * - `height` to control the height of the progress bars displayed within the progress bar container.
54
+ * - `height` to control the height of the progress bar container.
43
55
  * - `shadow` to apply a box shadow to the progress bar container.
44
56
  *
45
57
  * ## Variants
@@ -62,8 +74,15 @@ const selectProgressStyles = ({
62
74
  */
63
75
  const Progress = React.forwardRef(({ children, tokens, variant, ...rest }, ref) => {
64
76
  const themeTokens = useThemeTokens('Progress', tokens, variant)
65
- // Default to false (vertical layout) to preserve existing behavior and avoid breaking changes
66
77
  const layers = variant?.layers ?? false
78
+ const { barHeight, height } = themeTokens
79
+
80
+ const content =
81
+ barHeight && barHeight !== height ? (
82
+ <View style={selectBarWrapperStyles(themeTokens)}>{children}</View>
83
+ ) : (
84
+ children
85
+ )
67
86
 
68
87
  return (
69
88
  <ProgressContext.Provider value={{ layers }}>
@@ -72,7 +91,7 @@ const Progress = React.forwardRef(({ children, tokens, variant, ...rest }, ref)
72
91
  style={[staticStyles.progressContainer, selectProgressStyles(themeTokens)]}
73
92
  {...selectProps(rest)}
74
93
  >
75
- {children}
94
+ {content}
76
95
  </View>
77
96
  </ProgressContext.Provider>
78
97
  )