@telus-uds/components-web 2.18.0 → 2.19.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 (51) hide show
  1. package/CHANGELOG.md +11 -2
  2. package/component-docs.json +381 -471
  3. package/lib/NavigationBar/NavigationSubMenu.js +2 -4
  4. package/lib/baseExports.js +12 -0
  5. package/lib/index.js +0 -18
  6. package/lib/utils/useOverlaidPosition.js +2 -2
  7. package/lib-module/NavigationBar/NavigationSubMenu.js +1 -2
  8. package/lib-module/baseExports.js +1 -1
  9. package/lib-module/index.js +0 -2
  10. package/lib-module/utils/useOverlaidPosition.js +2 -2
  11. package/package.json +2 -2
  12. package/src/NavigationBar/NavigationSubMenu.jsx +1 -2
  13. package/src/baseExports.js +2 -0
  14. package/src/index.js +0 -2
  15. package/src/utils/useOverlaidPosition.js +2 -2
  16. package/lib/Autocomplete/Autocomplete.js +0 -430
  17. package/lib/Autocomplete/Loading.js +0 -46
  18. package/lib/Autocomplete/Suggestions.js +0 -81
  19. package/lib/Autocomplete/constants.js +0 -19
  20. package/lib/Autocomplete/dictionary.js +0 -19
  21. package/lib/Autocomplete/index.js +0 -13
  22. package/lib/Listbox/GroupControl.js +0 -110
  23. package/lib/Listbox/Listbox.js +0 -185
  24. package/lib/Listbox/ListboxGroup.js +0 -145
  25. package/lib/Listbox/ListboxItem.js +0 -101
  26. package/lib/Listbox/ListboxOverlay.js +0 -91
  27. package/lib/Listbox/index.js +0 -13
  28. package/lib-module/Autocomplete/Autocomplete.js +0 -406
  29. package/lib-module/Autocomplete/Loading.js +0 -32
  30. package/lib-module/Autocomplete/Suggestions.js +0 -64
  31. package/lib-module/Autocomplete/constants.js +0 -5
  32. package/lib-module/Autocomplete/dictionary.js +0 -12
  33. package/lib-module/Autocomplete/index.js +0 -2
  34. package/lib-module/Listbox/GroupControl.js +0 -96
  35. package/lib-module/Listbox/Listbox.js +0 -164
  36. package/lib-module/Listbox/ListboxGroup.js +0 -122
  37. package/lib-module/Listbox/ListboxItem.js +0 -77
  38. package/lib-module/Listbox/ListboxOverlay.js +0 -69
  39. package/lib-module/Listbox/index.js +0 -2
  40. package/src/Autocomplete/Autocomplete.jsx +0 -375
  41. package/src/Autocomplete/Loading.jsx +0 -15
  42. package/src/Autocomplete/Suggestions.jsx +0 -52
  43. package/src/Autocomplete/constants.js +0 -6
  44. package/src/Autocomplete/dictionary.js +0 -12
  45. package/src/Autocomplete/index.js +0 -3
  46. package/src/Listbox/GroupControl.jsx +0 -82
  47. package/src/Listbox/Listbox.jsx +0 -169
  48. package/src/Listbox/ListboxGroup.jsx +0 -125
  49. package/src/Listbox/ListboxItem.jsx +0 -80
  50. package/src/Listbox/ListboxOverlay.jsx +0 -72
  51. package/src/Listbox/index.js +0 -3
@@ -1,169 +0,0 @@
1
- import React, { useCallback, useEffect, useRef, useState } from 'react'
2
- import PropTypes from 'prop-types'
3
- import styled from 'styled-components'
4
- import {
5
- ExpandCollapse,
6
- useThemeTokens,
7
- withLinkRouter,
8
- ListboxContext,
9
- getTokensPropType
10
- } from '@telus-uds/components-base'
11
- import ListboxGroup from './ListboxGroup'
12
- import ListboxItem from './ListboxItem'
13
- import DropdownOverlay from './ListboxOverlay'
14
-
15
- const StyledList = styled.ul({
16
- margin: 0,
17
- padding: 0,
18
- listStyle: 'none'
19
- })
20
-
21
- const getInitialOpen = (items, selectedId) =>
22
- items
23
- .filter(
24
- (item) =>
25
- item.items &&
26
- item.items.some((nestedItem) => (nestedItem.id ?? nestedItem.label) === selectedId)
27
- )
28
- .map((item) => item.id ?? item.label)
29
-
30
- const Listbox = ({
31
- items = [],
32
- firstItemRef = null, // focus will be moved to this one once within the menu
33
- parentRef = null, // to return focus to after leaving the last menu item
34
- selectedId: defaultSelectedId,
35
- LinkRouter,
36
- itemRouterProps,
37
- onClose,
38
- variant,
39
- tokens
40
- }) => {
41
- const initialOpen = getInitialOpen(items, defaultSelectedId)
42
-
43
- const [selectedId, setSelectedId] = useState(defaultSelectedId)
44
-
45
- const { minHeight, minWidth } = useThemeTokens('Listbox', variant, tokens)
46
-
47
- // We need to keep track of each item's ref in order to be able to
48
- // focus on a specific item via keyboard navigation
49
- const itemRefs = useRef([])
50
- if (firstItemRef?.current) itemRefs.current[0] = firstItemRef.current
51
- const [focusedIndex, setFocusedIndex] = useState(0)
52
- const handleKeydown = useCallback(
53
- (event) => {
54
- const nextItemRef = itemRefs.current[focusedIndex + 1]
55
- const prevItemRef = itemRefs.current[focusedIndex - 1]
56
- if (event.key === 'ArrowUp' || (event.shiftKey && event.key === 'Tab')) {
57
- // Move the focus to the previous item or to the parent one if on the first
58
- if (prevItemRef) {
59
- event.preventDefault()
60
- prevItemRef.focus()
61
- } else if (parentRef) parentRef.current?.focus()
62
- setFocusedIndex(focusedIndex - 1)
63
- } else if ((event.key === 'ArrowDown' || event.key === 'Tab') && nextItemRef) {
64
- event.preventDefault()
65
- setFocusedIndex(focusedIndex + 1)
66
- nextItemRef.focus()
67
- } else if (event.key === 'Escape') {
68
- // Close the dropdown
69
- parentRef?.current?.click()
70
- // Return focus to the dropdown control after leaving the last item
71
- parentRef?.current?.focus()
72
- if (onClose) onClose(event)
73
- }
74
- },
75
- [focusedIndex, onClose, parentRef]
76
- )
77
-
78
- // Add listeners for mouse clicks outside and for key presses
79
- useEffect(() => {
80
- window.addEventListener('click', onClose)
81
- window.addEventListener('keydown', handleKeydown)
82
- window.addEventListener('touchstart', onClose)
83
-
84
- return () => {
85
- window.removeEventListener('click', onClose)
86
- window.removeEventListener('keydown', handleKeydown)
87
- window.removeEventListener('touchstart', onClose)
88
- }
89
- }, [onClose, handleKeydown])
90
-
91
- return (
92
- <ListboxContext.Provider value={{ selectedId, setSelectedId }}>
93
- <ExpandCollapse initialOpen={initialOpen} maxOpen={1}>
94
- {(expandProps) => (
95
- <StyledList role="listbox" style={{ minHeight, minWidth }}>
96
- {items.map((item, index) => {
97
- const { id, label, items: nestedItems } = item
98
- const itemId = id ?? label
99
-
100
- // Give `firstItemRef` to the first focusable item
101
- const itemRef =
102
- (index === 0 && !itemId !== selectedId) ||
103
- (index === 1 && items[0].id === selectedId)
104
- ? firstItemRef
105
- : (ref) => {
106
- itemRefs.current[index] = ref
107
- return ref
108
- }
109
-
110
- return nestedItems ? (
111
- <ListboxGroup
112
- {...item}
113
- expandProps={expandProps}
114
- LinkRouter={LinkRouter}
115
- itemRouterProps={itemRouterProps}
116
- prevItemRef={itemRefs.current[index - 1] ?? null}
117
- nextItemRef={itemRefs.current[index + 1] ?? null}
118
- ref={itemRef}
119
- key={itemId}
120
- />
121
- ) : (
122
- <ListboxItem
123
- {...item}
124
- key={itemId}
125
- id={itemId}
126
- LinkRouter={LinkRouter}
127
- itemRouterProps={itemRouterProps}
128
- prevItemRef={itemRefs.current[index - 1] ?? null}
129
- nextItemRef={itemRefs.current[index + 1] ?? null}
130
- ref={itemRef}
131
- />
132
- )
133
- })}
134
- </StyledList>
135
- )}
136
- </ExpandCollapse>
137
- </ListboxContext.Provider>
138
- )
139
- }
140
-
141
- Listbox.propTypes = {
142
- ...withLinkRouter.propTypes,
143
- /**
144
- * Focus will be moved to the item with this ref once within the menu.
145
- */
146
- firstItemRef: PropTypes.object,
147
- /**
148
- * Focus will be returned to the dropdown control with this ref after leaving
149
- * the last menu item.
150
- */
151
- parentRef: PropTypes.object,
152
- /**
153
- * `Listbox` items
154
- */
155
- items: PropTypes.array,
156
- /**
157
- * To select an item by default
158
- */
159
- selectedId: PropTypes.string,
160
- /**
161
- * onClose event
162
- */
163
- onClose: PropTypes.func,
164
- tokens: getTokensPropType('Listbox')
165
- }
166
-
167
- Listbox.Overlay = DropdownOverlay
168
-
169
- export default Listbox
@@ -1,125 +0,0 @@
1
- /* eslint-disable react/require-default-props */
2
- import React, { forwardRef } from 'react'
3
- import PropTypes from 'prop-types'
4
- import { ExpandCollapse, withLinkRouter, useListboxContext } from '@telus-uds/components-base'
5
- import styled from 'styled-components'
6
- import ListboxItem from './ListboxItem'
7
- import GroupControl from './GroupControl'
8
-
9
- const StyledGroupWrapper = styled.li({
10
- margin: 'none',
11
- padding: 'none',
12
- display: 'block',
13
- overflowY: 'hidden',
14
-
15
- // Currently the default expand collapse control does not have a focus state and so the browser default is applied.
16
- // This hides the outline so that it does not clash with the custom control we provide.
17
- '& div[role=button]': {
18
- outline: 'none'
19
- }
20
- })
21
-
22
- const StyledList = styled.ul({
23
- margin: 0,
24
- padding: 0,
25
- listStyle: 'none'
26
- })
27
-
28
- const ListboxGroup = forwardRef(
29
- (
30
- {
31
- id,
32
- label,
33
- items,
34
- LinkRouter,
35
- linkRouterProps,
36
- expandProps,
37
- onLastItemBlur,
38
- nextItemRef,
39
- prevItemRef
40
- },
41
- ref
42
- ) => {
43
- const { selectedId } = useListboxContext()
44
-
45
- // TODO: implement keyboard navigation via refs for grouped items separately here
46
- return (
47
- <StyledGroupWrapper role="option">
48
- <ExpandCollapse.Panel
49
- panelId={id ?? label}
50
- controlTokens={{
51
- icon: null,
52
- paddingLeft: 'none',
53
- paddingRight: 'none',
54
- paddingTop: 'none',
55
- paddingBottom: 'none',
56
- backgroundColor: 'transparent',
57
- borderColor: 'transparent',
58
- textLine: 'none',
59
- borderWidth: 0
60
- }}
61
- // TODO refactor
62
- // eslint-disable-next-line react/no-unstable-nested-components
63
- control={(controlProps) => (
64
- <GroupControl id={id ?? label} {...controlProps} label={label} />
65
- )}
66
- {...expandProps}
67
- tokens={{
68
- contentPaddingLeft: 'none',
69
- contentPaddingRight: 'none',
70
- contentPaddingTop: 'none',
71
- contentPaddingBottom: 'none',
72
- borderColor: 'transparent',
73
- borderRadius: 0,
74
- borderWidth: 0,
75
- marginBottom: 0
76
- }}
77
- controlRef={ref}
78
- >
79
- <StyledList>
80
- {items.map((item, index) => {
81
- return (
82
- <ListboxItem
83
- key={item.label}
84
- id={item.id ?? item.label}
85
- {...item}
86
- selected={
87
- (item.id && item.id === selectedId) || (item.label && item.label === selectedId)
88
- }
89
- isChild
90
- LinkRouter={LinkRouter}
91
- linkRouterProps={linkRouterProps}
92
- {...(index === 0 && { prevItemRef })}
93
- {...(index === items.length - 1 && { nextItemRef })}
94
- {...(index === items.length - 1 && { onBlur: onLastItemBlur })}
95
- />
96
- )
97
- })}
98
- </StyledList>
99
- </ExpandCollapse.Panel>
100
- </StyledGroupWrapper>
101
- )
102
- }
103
- )
104
- ListboxGroup.displayName = 'ListboxGroup'
105
-
106
- ListboxGroup.propTypes = {
107
- ...withLinkRouter.propTypes,
108
- label: PropTypes.string,
109
- items: PropTypes.arrayOf(
110
- PropTypes.shape({
111
- href: PropTypes.string,
112
- label: PropTypes.string,
113
- current: PropTypes.bool
114
- })
115
- ),
116
- expandProps: PropTypes.object,
117
- nextItemRef: PropTypes.object,
118
- prevItemRef: PropTypes.object,
119
- /**
120
- * Use this callback to redirect the focus after it leaves the last item of the group.
121
- */
122
- onLastItemBlur: PropTypes.func
123
- }
124
-
125
- export default ListboxGroup
@@ -1,80 +0,0 @@
1
- /* eslint-disable react/require-default-props */
2
- import React, { forwardRef } from 'react'
3
- import PropTypes from 'prop-types'
4
- import styled from 'styled-components'
5
- import {
6
- selectSystemProps,
7
- withLinkRouter,
8
- useThemeTokensCallback,
9
- PressableItem
10
- } from '@telus-uds/components-base'
11
- import { htmlAttrs } from '../utils'
12
-
13
- const [selectProps, selectedSystemPropTypes] = selectSystemProps([htmlAttrs])
14
-
15
- const StyledItemContainer = styled.li({
16
- display: 'flex',
17
- paddingLeft: ({ isChild }) => (isChild ? '16px' : '0px'),
18
- '&&&': {
19
- // Docusaurus applies aggressively high-specificity margin on `li`
20
- margin: 0
21
- }
22
- })
23
-
24
- const ListboxItem = forwardRef(
25
- (
26
- {
27
- href,
28
- label,
29
- isChild = false,
30
- onBlur,
31
- nextItemRef,
32
- prevItemRef,
33
- tokens,
34
- variant = {},
35
- LinkRouter,
36
- linkRouterProps,
37
- id,
38
- onPress = () => {},
39
-
40
- ...rest
41
- },
42
- ref
43
- ) => {
44
- const selectedProps = selectProps({ href, ...rest })
45
-
46
- const getTokens = useThemeTokensCallback('Listbox', tokens, variant, { isChild })
47
- return (
48
- <StyledItemContainer isChild={isChild} {...selectedProps} role="option">
49
- <PressableItem
50
- href={href}
51
- isChild={isChild}
52
- onPress={onPress}
53
- onBlur={onBlur}
54
- nextItemRef={nextItemRef}
55
- prevItemRef={prevItemRef}
56
- ref={ref}
57
- tokens={getTokens}
58
- selectedProps={selectedProps}
59
- id={id}
60
- >
61
- {label}
62
- </PressableItem>
63
- </StyledItemContainer>
64
- )
65
- }
66
- )
67
- ListboxItem.displayName = 'ListboxItem'
68
-
69
- ListboxItem.propTypes = {
70
- ...selectedSystemPropTypes,
71
- ...withLinkRouter.propTypes,
72
- href: PropTypes.string,
73
- isChild: PropTypes.bool,
74
- label: PropTypes.node.isRequired,
75
- nextItemRef: PropTypes.object,
76
- prevItemRef: PropTypes.object,
77
- onPress: PropTypes.func
78
- }
79
-
80
- export default withLinkRouter(ListboxItem)
@@ -1,72 +0,0 @@
1
- /* eslint-disable react/require-default-props */
2
- import React, { forwardRef } from 'react'
3
- import { Card, useThemeTokens } from '@telus-uds/components-base'
4
- import PropTypes from 'prop-types'
5
- import { View, StyleSheet } from 'react-native-web'
6
- import WebPortal from '../WebPortal'
7
-
8
- const staticStyles = StyleSheet.create({
9
- positioner: {
10
- flex: 1, // Grow to maxWidth when possible, shrink when not possible
11
- position: 'absolute',
12
- zIndex: 10000 // Position on top of all the other overlays, including backdrops and modals
13
- },
14
- hidden: {
15
- // Use opacity not visibility to hide the dropdown during positioning
16
- // so on web, children may be focused from the first render
17
- opacity: 0
18
- }
19
- })
20
-
21
- const paddingVertical = 0
22
- const paddingHorizontal = 0
23
-
24
- const DropdownOverlay = forwardRef(
25
- ({ children, isReady = false, overlaidPosition, maxWidth, minWidth, onLayout }, ref) => {
26
- const systemTokens = useThemeTokens('Listbox', {}, {})
27
-
28
- return (
29
- <WebPortal>
30
- <View
31
- ref={ref}
32
- onLayout={onLayout}
33
- style={[
34
- overlaidPosition,
35
- { maxWidth, minWidth },
36
- staticStyles.positioner,
37
- !isReady && staticStyles.hidden
38
- ]}
39
- >
40
- <Card
41
- tokens={{
42
- shadow: systemTokens.shadow,
43
- paddingBottom: paddingVertical,
44
- paddingTop: paddingVertical,
45
- paddingLeft: paddingHorizontal,
46
- paddingRight: paddingHorizontal
47
- }}
48
- >
49
- {children}
50
- </Card>
51
- </View>
52
- </WebPortal>
53
- )
54
- }
55
- )
56
-
57
- DropdownOverlay.displayName = 'DropdownOverlay'
58
-
59
- DropdownOverlay.propTypes = {
60
- children: PropTypes.node.isRequired,
61
- isReady: PropTypes.bool,
62
- overlaidPosition: PropTypes.shape({
63
- top: PropTypes.number,
64
- left: PropTypes.number,
65
- width: PropTypes.number
66
- }),
67
- maxWidth: PropTypes.number,
68
- minWidth: PropTypes.number,
69
- onLayout: PropTypes.func
70
- }
71
-
72
- export default DropdownOverlay
@@ -1,3 +0,0 @@
1
- import Listbox from './Listbox'
2
-
3
- export default Listbox