@canonical/react-components 0.47.3 → 0.48.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/README.md
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
# React components for Vanilla Framework
|
|
2
|
+

|
|
2
3
|
|
|
3
4
|
This is a collection of components designed to be the way to consume [Vanilla Framework](http://vanillaframework.io) when using React.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
See the [component docs](https://canonical.github.io/react-components/) for usage instructions.
|
|
6
|
+
**[Storybook](https://canonical.github.io/react-components/)** contains component docs with usage instructions.
|
|
8
7
|
|
|
9
|
-

|
|
10
|
-

|
|
11
8
|
|
|
12
9
|
## Requirements
|
|
13
10
|
|
|
@@ -30,7 +30,7 @@ let Label = exports.Label = /*#__PURE__*/function (Label) {
|
|
|
30
30
|
* @param positionCoords - The coordinates of the position node.
|
|
31
31
|
* @param constrainPanelWidth - Whether the menu width should be constrained to the position width.
|
|
32
32
|
*/
|
|
33
|
-
const getPositionStyle = (position, positionCoords, constrainPanelWidth) => {
|
|
33
|
+
const getPositionStyle = (position, verticalPosition, positionCoords, constrainPanelWidth) => {
|
|
34
34
|
if (!positionCoords) {
|
|
35
35
|
return null;
|
|
36
36
|
}
|
|
@@ -40,7 +40,7 @@ const getPositionStyle = (position, positionCoords, constrainPanelWidth) => {
|
|
|
40
40
|
top,
|
|
41
41
|
width
|
|
42
42
|
} = positionCoords;
|
|
43
|
-
const topPos = top + height + (window.scrollY || 0);
|
|
43
|
+
const topPos = verticalPosition === "bottom" ? top + height + (window.scrollY || 0) : top + (window.scrollY || 0);
|
|
44
44
|
let leftPos = left;
|
|
45
45
|
switch (position) {
|
|
46
46
|
case "left":
|
|
@@ -120,6 +120,20 @@ const generateLink = (link, key, handleClose) => {
|
|
|
120
120
|
} : null
|
|
121
121
|
}, props), children);
|
|
122
122
|
};
|
|
123
|
+
const getClosestScrollableParent = node => {
|
|
124
|
+
let currentNode = node;
|
|
125
|
+
while (currentNode && currentNode !== document.body) {
|
|
126
|
+
const {
|
|
127
|
+
overflowY,
|
|
128
|
+
overflowX
|
|
129
|
+
} = window.getComputedStyle(currentNode);
|
|
130
|
+
if (["auto", "scroll", "overlay"].includes(overflowY) && ["auto", "scroll", "overlay"].includes(overflowX)) {
|
|
131
|
+
return currentNode;
|
|
132
|
+
}
|
|
133
|
+
currentNode = currentNode.parentElement;
|
|
134
|
+
}
|
|
135
|
+
return document.body;
|
|
136
|
+
};
|
|
123
137
|
const ContextualMenuDropdown = _ref => {
|
|
124
138
|
let {
|
|
125
139
|
adjustedPosition,
|
|
@@ -140,23 +154,46 @@ const ContextualMenuDropdown = _ref => {
|
|
|
140
154
|
...props
|
|
141
155
|
} = _ref;
|
|
142
156
|
const dropdown = (0, _react.useRef)();
|
|
143
|
-
const [
|
|
157
|
+
const [verticalPosition, setVerticalPosition] = (0, _react.useState)("bottom");
|
|
158
|
+
const [positionStyle, setPositionStyle] = (0, _react.useState)(getPositionStyle(adjustedPosition, verticalPosition, positionCoords, constrainPanelWidth));
|
|
144
159
|
const [maxHeight, setMaxHeight] = (0, _react.useState)();
|
|
145
|
-
|
|
146
160
|
// Update the styles to position the menu.
|
|
147
161
|
const updatePositionStyle = (0, _react.useCallback)(() => {
|
|
148
|
-
setPositionStyle(getPositionStyle(adjustedPosition, positionCoords, constrainPanelWidth));
|
|
149
|
-
}, [adjustedPosition, positionCoords, constrainPanelWidth]);
|
|
162
|
+
setPositionStyle(getPositionStyle(adjustedPosition, verticalPosition, positionCoords, constrainPanelWidth));
|
|
163
|
+
}, [adjustedPosition, positionCoords, verticalPosition, constrainPanelWidth]);
|
|
164
|
+
const updateVerticalPosition = (0, _react.useCallback)(() => {
|
|
165
|
+
if (!positionNode) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const scrollableParent = getClosestScrollableParent(positionNode);
|
|
169
|
+
if (!scrollableParent) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
const scrollableParentRect = scrollableParent.getBoundingClientRect();
|
|
173
|
+
const rect = positionNode.getBoundingClientRect();
|
|
174
|
+
|
|
175
|
+
// Calculate the rect in relation to the scrollableParent
|
|
176
|
+
const relativeRect = {
|
|
177
|
+
top: rect.top - scrollableParentRect.top,
|
|
178
|
+
bottom: rect.bottom - scrollableParentRect.top,
|
|
179
|
+
height: rect.height
|
|
180
|
+
};
|
|
181
|
+
const spaceBelow = scrollableParentRect.height - relativeRect.bottom;
|
|
182
|
+
const spaceAbove = relativeRect.top;
|
|
183
|
+
const dropdownHeight = relativeRect.height;
|
|
184
|
+
setVerticalPosition(spaceBelow >= dropdownHeight || spaceBelow > spaceAbove ? "bottom" : "top");
|
|
185
|
+
}, [positionNode]);
|
|
150
186
|
|
|
151
187
|
// Update the position when the window fitment info changes.
|
|
152
188
|
const onUpdateWindowFitment = (0, _react.useCallback)(fitsWindow => {
|
|
153
189
|
if (autoAdjust) {
|
|
154
190
|
setAdjustedPosition(adjustForWindow(position, fitsWindow));
|
|
191
|
+
updateVerticalPosition();
|
|
155
192
|
}
|
|
156
193
|
if (scrollOverflow) {
|
|
157
194
|
setMaxHeight(fitsWindow.fromBottom.spaceBelow - 16);
|
|
158
195
|
}
|
|
159
|
-
}, [autoAdjust, position, scrollOverflow, setAdjustedPosition]);
|
|
196
|
+
}, [autoAdjust, position, scrollOverflow, setAdjustedPosition, updateVerticalPosition]);
|
|
160
197
|
|
|
161
198
|
// Handle adjusting the horizontal position and scrolling of the dropdown so that it remains on screen.
|
|
162
199
|
(0, _hooks.useWindowFitment)(dropdown.current, positionNode, onUpdateWindowFitment, 0, isOpen && (autoAdjust || scrollOverflow));
|
|
@@ -165,6 +202,9 @@ const ContextualMenuDropdown = _ref => {
|
|
|
165
202
|
(0, _react.useEffect)(() => {
|
|
166
203
|
updatePositionStyle();
|
|
167
204
|
}, [adjustedPosition, updatePositionStyle]);
|
|
205
|
+
(0, _react.useEffect)(() => {
|
|
206
|
+
updateVerticalPosition();
|
|
207
|
+
}, [updateVerticalPosition]);
|
|
168
208
|
return (
|
|
169
209
|
/*#__PURE__*/
|
|
170
210
|
// Vanilla Framework uses .p-contextual-menu parent modifier classnames to determine the correct position of the .p-contextual-menu__dropdown dropdown (left, center, right).
|
|
@@ -188,6 +228,9 @@ const ContextualMenuDropdown = _ref => {
|
|
|
188
228
|
maxHeight,
|
|
189
229
|
minHeight: "2rem",
|
|
190
230
|
overflowX: "auto"
|
|
231
|
+
} : {}),
|
|
232
|
+
...(verticalPosition === "top" ? {
|
|
233
|
+
bottom: "0"
|
|
191
234
|
} : {})
|
|
192
235
|
}
|
|
193
236
|
}, props), dropdownContent ? typeof dropdownContent === "function" ? dropdownContent(handleClose) : dropdownContent : links.map((item, i) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonical/react-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"author": "Huw Wilkins <huw.wilkins@canonical.com>",
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
"@babel/eslint-parser": "7.23.3",
|
|
27
27
|
"@babel/preset-typescript": "7.23.3",
|
|
28
28
|
"@percy/cli": "1.27.6",
|
|
29
|
-
"@percy/storybook": "
|
|
29
|
+
"@percy/storybook": "5.0.1",
|
|
30
|
+
"@semantic-release/changelog": "6.0.3",
|
|
31
|
+
"@semantic-release/git": "10.0.1",
|
|
30
32
|
"@storybook/addon-a11y": "7.6.7",
|
|
31
33
|
"@storybook/addon-essentials": "7.6.7",
|
|
32
34
|
"@storybook/addon-interactions": "7.6.7",
|
|
@@ -36,63 +38,65 @@
|
|
|
36
38
|
"@storybook/blocks": "7.6.7",
|
|
37
39
|
"@storybook/react": "7.6.7",
|
|
38
40
|
"@storybook/react-webpack5": "7.6.7",
|
|
39
|
-
"@testing-library/cypress": "
|
|
41
|
+
"@testing-library/cypress": "10.0.1",
|
|
40
42
|
"@testing-library/dom": "9.3.3",
|
|
41
|
-
"@testing-library/jest-dom": "
|
|
43
|
+
"@testing-library/jest-dom": "6.2.1",
|
|
42
44
|
"@testing-library/react": "14.1.2",
|
|
43
45
|
"@testing-library/user-event": "14.5.2",
|
|
44
|
-
"@typescript-eslint/eslint-plugin": "
|
|
45
|
-
"@typescript-eslint/parser": "
|
|
46
|
-
"babel-jest": "
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "6.19.1",
|
|
47
|
+
"@typescript-eslint/parser": "6.19.1",
|
|
48
|
+
"babel-jest": "29.7.0",
|
|
47
49
|
"babel-loader": "9.1.3",
|
|
48
50
|
"babel-plugin-module-resolver": "5.0.0",
|
|
49
51
|
"babel-plugin-typescript-to-proptypes": "2.1.0",
|
|
50
52
|
"concurrently": "8.2.2",
|
|
51
53
|
"css-loader": "6.8.1",
|
|
52
|
-
"cypress": "
|
|
54
|
+
"cypress": "13.6.3",
|
|
53
55
|
"deepmerge": "4.3.1",
|
|
54
56
|
"eslint": "8.56.0",
|
|
55
|
-
"eslint-config-prettier": "
|
|
57
|
+
"eslint-config-prettier": "9.1.0",
|
|
56
58
|
"eslint-config-react-app": "7.0.1",
|
|
57
59
|
"eslint-plugin-cypress": "2.15.1",
|
|
58
60
|
"eslint-plugin-flowtype": "8.0.3",
|
|
59
61
|
"eslint-plugin-import": "2.29.1",
|
|
60
62
|
"eslint-plugin-jsx-a11y": "6.8.0",
|
|
61
|
-
"eslint-plugin-prettier": "
|
|
63
|
+
"eslint-plugin-prettier": "5.1.3",
|
|
62
64
|
"eslint-plugin-react": "7.33.2",
|
|
63
65
|
"eslint-plugin-react-hooks": "4.6.0",
|
|
64
66
|
"eslint-plugin-storybook": "0.6.15",
|
|
65
|
-
"eslint-plugin-testing-library": "
|
|
66
|
-
"jest": "
|
|
67
|
-
"npm-package-json-lint": "
|
|
68
|
-
"prettier": "2.
|
|
67
|
+
"eslint-plugin-testing-library": "6.2.0",
|
|
68
|
+
"jest": "29.7.0",
|
|
69
|
+
"npm-package-json-lint": "7.1.0",
|
|
70
|
+
"prettier": "3.2.4",
|
|
69
71
|
"react": "18.2.0",
|
|
70
72
|
"react-docgen-typescript-loader": "3.7.2",
|
|
71
73
|
"react-dom": "18.2.0",
|
|
72
74
|
"sass": "1.69.7",
|
|
73
|
-
"sass-loader": "
|
|
75
|
+
"sass-loader": "14.0.0",
|
|
76
|
+
"semantic-release": "23.0.0",
|
|
74
77
|
"storybook": "7.6.7",
|
|
75
78
|
"style-loader": "3.3.3",
|
|
76
|
-
"stylelint": "
|
|
79
|
+
"stylelint": "16.2.0",
|
|
77
80
|
"stylelint-config-prettier": "9.0.5",
|
|
78
|
-
"stylelint-config-recommended-scss": "
|
|
79
|
-
"stylelint-order": "
|
|
80
|
-
"stylelint-prettier": "
|
|
81
|
-
"ts-jest": "
|
|
81
|
+
"stylelint-config-recommended-scss": "14.0.0",
|
|
82
|
+
"stylelint-order": "6.0.4",
|
|
83
|
+
"stylelint-prettier": "5.0.0",
|
|
84
|
+
"ts-jest": "29.1.2",
|
|
82
85
|
"tsc-alias": "1.8.8",
|
|
83
|
-
"typescript": "
|
|
86
|
+
"typescript": "5.3.3",
|
|
84
87
|
"vanilla-framework": "4.6.0",
|
|
85
|
-
"wait-on": "
|
|
88
|
+
"wait-on": "7.2.0",
|
|
86
89
|
"webpack": "5.89.0"
|
|
87
90
|
},
|
|
88
91
|
"dependencies": {
|
|
89
|
-
"@types/jest": "
|
|
92
|
+
"@types/jest": "29.5.11",
|
|
90
93
|
"@types/node": "18.19.4",
|
|
91
94
|
"@types/react": "18.2.46",
|
|
92
95
|
"@types/react-dom": "18.2.18",
|
|
93
96
|
"@types/react-table": "7.7.19",
|
|
94
97
|
"classnames": "2.5.1",
|
|
95
|
-
"
|
|
98
|
+
"jest-environment-jsdom": "29.7.0",
|
|
99
|
+
"nanoid": "5.0.4",
|
|
96
100
|
"prop-types": "15.8.1",
|
|
97
101
|
"react-table": "7.8.0",
|
|
98
102
|
"react-useportal": "1.0.19"
|
|
@@ -101,10 +105,7 @@
|
|
|
101
105
|
"@types/react": "18.2.46",
|
|
102
106
|
"@types/react-dom": "18.2.18",
|
|
103
107
|
"postcss": "^8.3.11",
|
|
104
|
-
"
|
|
105
|
-
"jackspeak": "^2",
|
|
106
|
-
"strip-ansi": "^6.0.0",
|
|
107
|
-
"strip-ansi-cjs": "^8.0.0"
|
|
108
|
+
"jackspeak": "2.1.1"
|
|
108
109
|
},
|
|
109
110
|
"peerDependencies": {
|
|
110
111
|
"@types/react": "^17.0.2 || ^18.0.0",
|
|
@@ -127,7 +128,6 @@
|
|
|
127
128
|
"lint-package-json": "npmPkgJsonLint .",
|
|
128
129
|
"lint": "yarn lint-package-json && yarn lint-js && yarn lint-style",
|
|
129
130
|
"percy": "yarn build-docs && percy storybook ./docs",
|
|
130
|
-
"prepublishOnly": "yarn clean && yarn install && yarn build",
|
|
131
131
|
"serve": "yarn docs",
|
|
132
132
|
"start": "yarn docs",
|
|
133
133
|
"test": "jest",
|
|
@@ -135,7 +135,9 @@
|
|
|
135
135
|
"unlink-packages": "yarn unlink && cd node_modules/react && yarn unlink && cd ../react-dom && yarn unlink",
|
|
136
136
|
"cypress:test": "wait-on http://localhost:${PORT:-9009} && cypress run --env port=${PORT:-9009}",
|
|
137
137
|
"cypress:run": "cypress run --env port=${PORT:-9009}",
|
|
138
|
-
"cypress:open": "cypress open --env port=${PORT:-9009}"
|
|
138
|
+
"cypress:open": "cypress open --env port=${PORT:-9009}",
|
|
139
|
+
"semantic-release": "semantic-release",
|
|
140
|
+
"semantic-release-dry-run": "semantic-release --dry-run --no-ci"
|
|
139
141
|
},
|
|
140
142
|
"eslintConfig": {
|
|
141
143
|
"extends": "react-app"
|