@telus-uds/components-web 4.16.0 → 4.17.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.
- package/CHANGELOG.md +14 -1
- package/lib/cjs/NavigationBar/NavigationSubMenu.js +51 -34
- package/lib/cjs/utils/useOverlaidPosition.js +11 -1
- package/lib/esm/NavigationBar/NavigationSubMenu.js +49 -34
- package/lib/esm/utils/useOverlaidPosition.js +11 -1
- package/package.json +2 -2
- package/src/NavigationBar/NavigationSubMenu.jsx +38 -11
- package/src/utils/useOverlaidPosition.js +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
# Change Log - @telus-uds/components-web
|
|
2
2
|
|
|
3
|
-
This log was last generated on Mon,
|
|
3
|
+
This log was last generated on Mon, 19 Jan 2026 20:39:51 GMT and should not be manually modified.
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## 4.17.0
|
|
8
|
+
|
|
9
|
+
Mon, 19 Jan 2026 20:39:51 GMT
|
|
10
|
+
|
|
11
|
+
### Minor changes
|
|
12
|
+
|
|
13
|
+
- `PriceLockup`: Add inverse variant (david.melara1@telus.com)
|
|
14
|
+
- Bump @telus-uds/components-base to v3.26.0
|
|
15
|
+
|
|
16
|
+
### Patches
|
|
17
|
+
|
|
18
|
+
- `NavigationBar`: Fix flickering from overlay overflow (david.melara1@telus.com)
|
|
19
|
+
|
|
7
20
|
## 4.16.0
|
|
8
21
|
|
|
9
22
|
Mon, 12 Jan 2026 14:55:22 GMT
|
|
@@ -12,11 +12,52 @@ var _useOverlaidPosition = _interopRequireDefault(require("../utils/useOverlaidP
|
|
|
12
12
|
var _resolveItemSelection = _interopRequireDefault(require("./resolveItemSelection"));
|
|
13
13
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
14
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
+
const MIN_WIDTH = 192;
|
|
16
|
+
const MAX_WIDTH = 289;
|
|
17
|
+
const DEFAULT_OFFSETS = {
|
|
18
|
+
offsets: {
|
|
19
|
+
vertical: 4
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const XS_ALIGN = {
|
|
23
|
+
top: 'bottom',
|
|
24
|
+
left: 'left'
|
|
25
|
+
};
|
|
26
|
+
const SM_ALIGN = {
|
|
27
|
+
top: 'bottom',
|
|
28
|
+
right: 'right'
|
|
29
|
+
};
|
|
30
|
+
const LG_ALIGN = {
|
|
31
|
+
top: 'bottom',
|
|
32
|
+
center: 'center'
|
|
33
|
+
};
|
|
34
|
+
const getResponsiveBreakpoints = sourceWidth => ({
|
|
35
|
+
xs: {
|
|
36
|
+
...DEFAULT_OFFSETS,
|
|
37
|
+
align: XS_ALIGN,
|
|
38
|
+
minWidth: sourceWidth,
|
|
39
|
+
maxWidth: sourceWidth
|
|
40
|
+
},
|
|
41
|
+
sm: {
|
|
42
|
+
...DEFAULT_OFFSETS,
|
|
43
|
+
align: SM_ALIGN,
|
|
44
|
+
minWidth: sourceWidth,
|
|
45
|
+
maxWidth: sourceWidth
|
|
46
|
+
},
|
|
47
|
+
lg: {
|
|
48
|
+
...DEFAULT_OFFSETS,
|
|
49
|
+
align: LG_ALIGN,
|
|
50
|
+
minWidth: MIN_WIDTH,
|
|
51
|
+
maxWidth: MAX_WIDTH
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
15
55
|
/**
|
|
16
56
|
* A NavigationItem that opens or closes a Listbox of other NavigationItems.
|
|
17
57
|
*
|
|
18
58
|
* This is rendered automatically by `NavigationBar` and isn't intended be used directly.
|
|
19
|
-
*/
|
|
59
|
+
*/
|
|
60
|
+
const NavigationSubMenu = /*#__PURE__*/_react.default.forwardRef((_ref, ref) => {
|
|
20
61
|
let {
|
|
21
62
|
children,
|
|
22
63
|
id,
|
|
@@ -33,42 +74,13 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
33
74
|
itemsContainerRef
|
|
34
75
|
} = _ref;
|
|
35
76
|
const focusTrapRef = _react.default.useRef();
|
|
36
|
-
const
|
|
37
|
-
const defaultOffsets = {
|
|
38
|
-
offsets: {
|
|
39
|
-
vertical: 4
|
|
40
|
-
}
|
|
41
|
-
};
|
|
77
|
+
const [sourceWidth, setSourceWidth] = _react.default.useState(0);
|
|
42
78
|
const {
|
|
43
79
|
align,
|
|
44
80
|
offsets,
|
|
45
|
-
minWidth
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
...defaultOffsets,
|
|
49
|
-
align: {
|
|
50
|
-
top: 'bottom',
|
|
51
|
-
left: 'left'
|
|
52
|
-
},
|
|
53
|
-
minWidth: maxWidth
|
|
54
|
-
},
|
|
55
|
-
sm: {
|
|
56
|
-
...defaultOffsets,
|
|
57
|
-
align: {
|
|
58
|
-
top: 'bottom',
|
|
59
|
-
right: 'right'
|
|
60
|
-
},
|
|
61
|
-
minWidth: maxWidth
|
|
62
|
-
},
|
|
63
|
-
lg: {
|
|
64
|
-
...defaultOffsets,
|
|
65
|
-
align: {
|
|
66
|
-
top: 'bottom',
|
|
67
|
-
center: 'center'
|
|
68
|
-
},
|
|
69
|
-
minWidth: 192
|
|
70
|
-
}
|
|
71
|
-
});
|
|
81
|
+
minWidth,
|
|
82
|
+
maxWidth
|
|
83
|
+
} = (0, _componentsBase.useResponsiveProp)(getResponsiveBreakpoints(sourceWidth));
|
|
72
84
|
const {
|
|
73
85
|
overlaidPosition,
|
|
74
86
|
sourceRef,
|
|
@@ -95,6 +107,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
95
107
|
} = (0, _componentsBase.useThemeTokens)('NavigationBar', tokens, {}, {
|
|
96
108
|
expanded: isOpen
|
|
97
109
|
});
|
|
110
|
+
_react.default.useEffect(() => {
|
|
111
|
+
sourceRef.current?.measureInWindow((_, __, width) => {
|
|
112
|
+
setSourceWidth(width);
|
|
113
|
+
});
|
|
114
|
+
}, [isOpen, sourceRef]);
|
|
98
115
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
99
116
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_NavigationItem.default, {
|
|
100
117
|
ref: sourceRef,
|
|
@@ -111,6 +111,13 @@ function getOverlaidPosition(_ref2) {
|
|
|
111
111
|
positioning[side] = adjusted.offset;
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
+
if (positioning.left) {
|
|
115
|
+
const overflowAmount = positioning.left + targetDimensions.width - windowDimensions.width;
|
|
116
|
+
if (overflowAmount > 0) {
|
|
117
|
+
const spaceToRightEdge = windowDimensions.width - (sourceLayout.x + sourceLayout.width);
|
|
118
|
+
positioning.left = positioning.left - overflowAmount - spaceToRightEdge;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
114
121
|
return positioning;
|
|
115
122
|
}
|
|
116
123
|
|
|
@@ -210,7 +217,10 @@ const useOverlaidPosition = _ref3 => {
|
|
|
210
217
|
windowDimensions,
|
|
211
218
|
offsets,
|
|
212
219
|
align
|
|
213
|
-
}) : {
|
|
220
|
+
}) : {
|
|
221
|
+
top: 0,
|
|
222
|
+
left: 0
|
|
223
|
+
};
|
|
214
224
|
return {
|
|
215
225
|
overlaidPosition,
|
|
216
226
|
sourceRef,
|
|
@@ -4,13 +4,52 @@ import { Icon, useResponsiveProp, useThemeTokens, Listbox, getTokensPropType } f
|
|
|
4
4
|
import NavigationItem from './NavigationItem';
|
|
5
5
|
import useOverlaidPosition from '../utils/useOverlaidPosition';
|
|
6
6
|
import resolveItemSelection from './resolveItemSelection';
|
|
7
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
|
+
const MIN_WIDTH = 192;
|
|
9
|
+
const MAX_WIDTH = 289;
|
|
10
|
+
const DEFAULT_OFFSETS = {
|
|
11
|
+
offsets: {
|
|
12
|
+
vertical: 4
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const XS_ALIGN = {
|
|
16
|
+
top: 'bottom',
|
|
17
|
+
left: 'left'
|
|
18
|
+
};
|
|
19
|
+
const SM_ALIGN = {
|
|
20
|
+
top: 'bottom',
|
|
21
|
+
right: 'right'
|
|
22
|
+
};
|
|
23
|
+
const LG_ALIGN = {
|
|
24
|
+
top: 'bottom',
|
|
25
|
+
center: 'center'
|
|
26
|
+
};
|
|
27
|
+
const getResponsiveBreakpoints = sourceWidth => ({
|
|
28
|
+
xs: {
|
|
29
|
+
...DEFAULT_OFFSETS,
|
|
30
|
+
align: XS_ALIGN,
|
|
31
|
+
minWidth: sourceWidth,
|
|
32
|
+
maxWidth: sourceWidth
|
|
33
|
+
},
|
|
34
|
+
sm: {
|
|
35
|
+
...DEFAULT_OFFSETS,
|
|
36
|
+
align: SM_ALIGN,
|
|
37
|
+
minWidth: sourceWidth,
|
|
38
|
+
maxWidth: sourceWidth
|
|
39
|
+
},
|
|
40
|
+
lg: {
|
|
41
|
+
...DEFAULT_OFFSETS,
|
|
42
|
+
align: LG_ALIGN,
|
|
43
|
+
minWidth: MIN_WIDTH,
|
|
44
|
+
maxWidth: MAX_WIDTH
|
|
45
|
+
}
|
|
46
|
+
});
|
|
7
47
|
|
|
8
48
|
/**
|
|
9
49
|
* A NavigationItem that opens or closes a Listbox of other NavigationItems.
|
|
10
50
|
*
|
|
11
51
|
* This is rendered automatically by `NavigationBar` and isn't intended be used directly.
|
|
12
52
|
*/
|
|
13
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
53
|
const NavigationSubMenu = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
15
54
|
let {
|
|
16
55
|
children,
|
|
@@ -28,42 +67,13 @@ const NavigationSubMenu = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
28
67
|
itemsContainerRef
|
|
29
68
|
} = _ref;
|
|
30
69
|
const focusTrapRef = React.useRef();
|
|
31
|
-
const
|
|
32
|
-
const defaultOffsets = {
|
|
33
|
-
offsets: {
|
|
34
|
-
vertical: 4
|
|
35
|
-
}
|
|
36
|
-
};
|
|
70
|
+
const [sourceWidth, setSourceWidth] = React.useState(0);
|
|
37
71
|
const {
|
|
38
72
|
align,
|
|
39
73
|
offsets,
|
|
40
|
-
minWidth
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
...defaultOffsets,
|
|
44
|
-
align: {
|
|
45
|
-
top: 'bottom',
|
|
46
|
-
left: 'left'
|
|
47
|
-
},
|
|
48
|
-
minWidth: maxWidth
|
|
49
|
-
},
|
|
50
|
-
sm: {
|
|
51
|
-
...defaultOffsets,
|
|
52
|
-
align: {
|
|
53
|
-
top: 'bottom',
|
|
54
|
-
right: 'right'
|
|
55
|
-
},
|
|
56
|
-
minWidth: maxWidth
|
|
57
|
-
},
|
|
58
|
-
lg: {
|
|
59
|
-
...defaultOffsets,
|
|
60
|
-
align: {
|
|
61
|
-
top: 'bottom',
|
|
62
|
-
center: 'center'
|
|
63
|
-
},
|
|
64
|
-
minWidth: 192
|
|
65
|
-
}
|
|
66
|
-
});
|
|
74
|
+
minWidth,
|
|
75
|
+
maxWidth
|
|
76
|
+
} = useResponsiveProp(getResponsiveBreakpoints(sourceWidth));
|
|
67
77
|
const {
|
|
68
78
|
overlaidPosition,
|
|
69
79
|
sourceRef,
|
|
@@ -90,6 +100,11 @@ const NavigationSubMenu = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
90
100
|
} = useThemeTokens('NavigationBar', tokens, {}, {
|
|
91
101
|
expanded: isOpen
|
|
92
102
|
});
|
|
103
|
+
React.useEffect(() => {
|
|
104
|
+
sourceRef.current?.measureInWindow((_, __, width) => {
|
|
105
|
+
setSourceWidth(width);
|
|
106
|
+
});
|
|
107
|
+
}, [isOpen, sourceRef]);
|
|
93
108
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
94
109
|
children: [/*#__PURE__*/_jsx(NavigationItem, {
|
|
95
110
|
ref: sourceRef,
|
|
@@ -103,6 +103,13 @@ function getOverlaidPosition(_ref2) {
|
|
|
103
103
|
positioning[side] = adjusted.offset;
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
+
if (positioning.left) {
|
|
107
|
+
const overflowAmount = positioning.left + targetDimensions.width - windowDimensions.width;
|
|
108
|
+
if (overflowAmount > 0) {
|
|
109
|
+
const spaceToRightEdge = windowDimensions.width - (sourceLayout.x + sourceLayout.width);
|
|
110
|
+
positioning.left = positioning.left - overflowAmount - spaceToRightEdge;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
106
113
|
return positioning;
|
|
107
114
|
}
|
|
108
115
|
|
|
@@ -202,7 +209,10 @@ const useOverlaidPosition = _ref3 => {
|
|
|
202
209
|
windowDimensions,
|
|
203
210
|
offsets,
|
|
204
211
|
align
|
|
205
|
-
}) : {
|
|
212
|
+
}) : {
|
|
213
|
+
top: 0,
|
|
214
|
+
left: 0
|
|
215
|
+
};
|
|
206
216
|
return {
|
|
207
217
|
overlaidPosition,
|
|
208
218
|
sourceRef,
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
],
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@gorhom/portal": "^1.0.14",
|
|
8
|
-
"@telus-uds/components-base": "^3.
|
|
8
|
+
"@telus-uds/components-base": "^3.26.0",
|
|
9
9
|
"@telus-uds/system-constants": "^3.0.0",
|
|
10
10
|
"@telus-uds/system-theme-tokens": "^4.18.0",
|
|
11
11
|
"fscreen": "^1.2.0",
|
|
@@ -82,5 +82,5 @@
|
|
|
82
82
|
"skip": true
|
|
83
83
|
},
|
|
84
84
|
"types": "types/index.d.ts",
|
|
85
|
-
"version": "4.
|
|
85
|
+
"version": "4.17.0"
|
|
86
86
|
}
|
|
@@ -11,6 +11,34 @@ import NavigationItem from './NavigationItem'
|
|
|
11
11
|
import useOverlaidPosition from '../utils/useOverlaidPosition'
|
|
12
12
|
import resolveItemSelection from './resolveItemSelection'
|
|
13
13
|
|
|
14
|
+
const MIN_WIDTH = 192
|
|
15
|
+
const MAX_WIDTH = 289
|
|
16
|
+
const DEFAULT_OFFSETS = { offsets: { vertical: 4 } }
|
|
17
|
+
const XS_ALIGN = { top: 'bottom', left: 'left' }
|
|
18
|
+
const SM_ALIGN = { top: 'bottom', right: 'right' }
|
|
19
|
+
const LG_ALIGN = { top: 'bottom', center: 'center' }
|
|
20
|
+
|
|
21
|
+
const getResponsiveBreakpoints = (sourceWidth) => ({
|
|
22
|
+
xs: {
|
|
23
|
+
...DEFAULT_OFFSETS,
|
|
24
|
+
align: XS_ALIGN,
|
|
25
|
+
minWidth: sourceWidth,
|
|
26
|
+
maxWidth: sourceWidth
|
|
27
|
+
},
|
|
28
|
+
sm: {
|
|
29
|
+
...DEFAULT_OFFSETS,
|
|
30
|
+
align: SM_ALIGN,
|
|
31
|
+
minWidth: sourceWidth,
|
|
32
|
+
maxWidth: sourceWidth
|
|
33
|
+
},
|
|
34
|
+
lg: {
|
|
35
|
+
...DEFAULT_OFFSETS,
|
|
36
|
+
align: LG_ALIGN,
|
|
37
|
+
minWidth: MIN_WIDTH,
|
|
38
|
+
maxWidth: MAX_WIDTH
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
14
42
|
/**
|
|
15
43
|
* A NavigationItem that opens or closes a Listbox of other NavigationItems.
|
|
16
44
|
*
|
|
@@ -36,18 +64,11 @@ const NavigationSubMenu = React.forwardRef(
|
|
|
36
64
|
ref
|
|
37
65
|
) => {
|
|
38
66
|
const focusTrapRef = React.useRef()
|
|
67
|
+
const [sourceWidth, setSourceWidth] = React.useState(0)
|
|
39
68
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
xs: { ...defaultOffsets, align: { top: 'bottom', left: 'left' }, minWidth: maxWidth },
|
|
44
|
-
sm: { ...defaultOffsets, align: { top: 'bottom', right: 'right' }, minWidth: maxWidth },
|
|
45
|
-
lg: {
|
|
46
|
-
...defaultOffsets,
|
|
47
|
-
align: { top: 'bottom', center: 'center' },
|
|
48
|
-
minWidth: 192
|
|
49
|
-
}
|
|
50
|
-
})
|
|
69
|
+
const { align, offsets, minWidth, maxWidth } = useResponsiveProp(
|
|
70
|
+
getResponsiveBreakpoints(sourceWidth)
|
|
71
|
+
)
|
|
51
72
|
|
|
52
73
|
const { overlaidPosition, sourceRef, targetRef, onTargetLayout, isReady } = useOverlaidPosition(
|
|
53
74
|
{
|
|
@@ -64,6 +85,12 @@ const NavigationSubMenu = React.forwardRef(
|
|
|
64
85
|
|
|
65
86
|
const { icoMenu } = useThemeTokens('NavigationBar', tokens, {}, { expanded: isOpen })
|
|
66
87
|
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
sourceRef.current?.measureInWindow((_, __, width) => {
|
|
90
|
+
setSourceWidth(width)
|
|
91
|
+
})
|
|
92
|
+
}, [isOpen, sourceRef])
|
|
93
|
+
|
|
67
94
|
return (
|
|
68
95
|
<>
|
|
69
96
|
<NavigationItem
|
|
@@ -118,6 +118,14 @@ function getOverlaidPosition({
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
if (positioning.left) {
|
|
122
|
+
const overflowAmount = positioning.left + targetDimensions.width - windowDimensions.width
|
|
123
|
+
if (overflowAmount > 0) {
|
|
124
|
+
const spaceToRightEdge = windowDimensions.width - (sourceLayout.x + sourceLayout.width)
|
|
125
|
+
positioning.left = positioning.left - overflowAmount - spaceToRightEdge
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
121
129
|
return positioning
|
|
122
130
|
}
|
|
123
131
|
|
|
@@ -212,7 +220,7 @@ const useOverlaidPosition = ({
|
|
|
212
220
|
offsets,
|
|
213
221
|
align
|
|
214
222
|
})
|
|
215
|
-
: {}
|
|
223
|
+
: { top: 0, left: 0 }
|
|
216
224
|
|
|
217
225
|
return {
|
|
218
226
|
overlaidPosition,
|