@instructure/ui-drilldown 10.18.2-snapshot-1 → 10.18.2-snapshot-3
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 +5 -2
- package/es/Drilldown/__new-tests__/Drilldown.test.js +22 -0
- package/es/Drilldown/index.js +3 -3
- package/lib/Drilldown/__new-tests__/Drilldown.test.js +22 -0
- package/lib/Drilldown/index.js +3 -3
- package/package.json +21 -21
- package/src/Drilldown/__new-tests__/Drilldown.test.tsx +27 -0
- package/src/Drilldown/index.tsx +5 -4
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Drilldown/index.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
## [10.18.2-snapshot-
|
|
6
|
+
## [10.18.2-snapshot-3](https://github.com/instructure/instructure-ui/compare/v10.18.1...v10.18.2-snapshot-3) (2025-06-03)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **many:** fix "not a valid selector" exception when an option ID contains quotes ([78e0b96](https://github.com/instructure/instructure-ui/commit/78e0b96edf29f3d476ba30b03134f1726bbdd0f4))
|
|
9
12
|
|
|
10
13
|
|
|
11
14
|
|
|
@@ -95,6 +95,28 @@ describe('<Drilldown />', () => {
|
|
|
95
95
|
expect(options.length).toBe(0);
|
|
96
96
|
expect(notAllowedChild).not.toBeInTheDocument();
|
|
97
97
|
});
|
|
98
|
+
it('should not crash for weird option ids', async () => {
|
|
99
|
+
const onSelect = vi.fn();
|
|
100
|
+
const weirdID = 'some"_weird!@#$%^&*()\\|`id';
|
|
101
|
+
render(_jsx(Drilldown, {
|
|
102
|
+
rootPageId: "page0",
|
|
103
|
+
onSelect: onSelect,
|
|
104
|
+
children: _jsx(Drilldown.Page, {
|
|
105
|
+
id: "page0",
|
|
106
|
+
children: data.map(option => _jsx(Drilldown.Option, {
|
|
107
|
+
id: weirdID + option.id,
|
|
108
|
+
value: weirdID + option.id,
|
|
109
|
+
"data-testid": weirdID + option.id,
|
|
110
|
+
children: option.label
|
|
111
|
+
}, weirdID + option.id))
|
|
112
|
+
})
|
|
113
|
+
}));
|
|
114
|
+
const option_1 = screen.getByTestId(weirdID + 'opt_1');
|
|
115
|
+
await userEvent.click(option_1);
|
|
116
|
+
await waitFor(() => {
|
|
117
|
+
expect(onSelect).toHaveBeenCalled();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
98
120
|
});
|
|
99
121
|
describe('id prop', () => {
|
|
100
122
|
it('should put id attr on the drilldown', async () => {
|
package/es/Drilldown/index.js
CHANGED
|
@@ -259,7 +259,7 @@ let Drilldown = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle,
|
|
|
259
259
|
}
|
|
260
260
|
if (event.type === 'keydown' && href) {
|
|
261
261
|
var _this$_drilldownRef;
|
|
262
|
-
const optionEl = (_this$_drilldownRef = this._drilldownRef) === null || _this$_drilldownRef === void 0 ? void 0 : _this$_drilldownRef.querySelector(`#${id}`);
|
|
262
|
+
const optionEl = (_this$_drilldownRef = this._drilldownRef) === null || _this$_drilldownRef === void 0 ? void 0 : _this$_drilldownRef.querySelector(`#${CSS.escape(id)}`);
|
|
263
263
|
const isLink = optionEl.tagName.toLowerCase() === 'a';
|
|
264
264
|
|
|
265
265
|
// we need this check because in some cases
|
|
@@ -659,7 +659,7 @@ let Drilldown = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle,
|
|
|
659
659
|
}
|
|
660
660
|
focusOption(id) {
|
|
661
661
|
const container = this._containerElement;
|
|
662
|
-
const optionElement = container === null || container === void 0 ? void 0 : container.querySelector(`[id="${id}"]`);
|
|
662
|
+
const optionElement = container === null || container === void 0 ? void 0 : container.querySelector(`[id="${CSS.escape(id)}"]`);
|
|
663
663
|
optionElement === null || optionElement === void 0 ? void 0 : optionElement.focus();
|
|
664
664
|
}
|
|
665
665
|
handleGroupOptionSelected(event, selectedOption) {
|
|
@@ -1190,7 +1190,7 @@ let Drilldown = (_dec = withDeterministicId(), _dec2 = withStyle(generateStyle,
|
|
|
1190
1190
|
// Use action ID if exists, otherwise first non-action option's ID
|
|
1191
1191
|
const targetId = actionLabel ? this._headerActionId : (_this$currentPage$chi2 = this.currentPage.children[0]) === null || _this$currentPage$chi2 === void 0 ? void 0 : _this$currentPage$chi2.props.id;
|
|
1192
1192
|
if (!targetId) return null;
|
|
1193
|
-
return (_this$_popover2 = this._popover) === null || _this$_popover2 === void 0 ? void 0 : (_this$_popover2$_cont = _this$_popover2._contentElement) === null || _this$_popover2$_cont === void 0 ? void 0 : _this$_popover2$_cont.querySelector(`#${targetId}`);
|
|
1193
|
+
return (_this$_popover2 = this._popover) === null || _this$_popover2 === void 0 ? void 0 : (_this$_popover2$_cont = _this$_popover2._contentElement) === null || _this$_popover2$_cont === void 0 ? void 0 : _this$_popover2$_cont.querySelector(`#${CSS.escape(targetId)}`);
|
|
1194
1194
|
},
|
|
1195
1195
|
elementRef: element => {
|
|
1196
1196
|
// setting ref for "Popover" version, the popover root
|
|
@@ -96,6 +96,28 @@ describe('<Drilldown />', () => {
|
|
|
96
96
|
expect(options.length).toBe(0);
|
|
97
97
|
expect(notAllowedChild).not.toBeInTheDocument();
|
|
98
98
|
});
|
|
99
|
+
it('should not crash for weird option ids', async () => {
|
|
100
|
+
const onSelect = _vitest.vi.fn();
|
|
101
|
+
const weirdID = 'some"_weird!@#$%^&*()\\|`id';
|
|
102
|
+
(0, _react.render)((0, _jsxRuntime.jsx)(_index.Drilldown, {
|
|
103
|
+
rootPageId: "page0",
|
|
104
|
+
onSelect: onSelect,
|
|
105
|
+
children: (0, _jsxRuntime.jsx)(_index.Drilldown.Page, {
|
|
106
|
+
id: "page0",
|
|
107
|
+
children: data.map(option => (0, _jsxRuntime.jsx)(_index.Drilldown.Option, {
|
|
108
|
+
id: weirdID + option.id,
|
|
109
|
+
value: weirdID + option.id,
|
|
110
|
+
"data-testid": weirdID + option.id,
|
|
111
|
+
children: option.label
|
|
112
|
+
}, weirdID + option.id))
|
|
113
|
+
})
|
|
114
|
+
}));
|
|
115
|
+
const option_1 = _react.screen.getByTestId(weirdID + 'opt_1');
|
|
116
|
+
await _userEvent.default.click(option_1);
|
|
117
|
+
await (0, _react.waitFor)(() => {
|
|
118
|
+
expect(onSelect).toHaveBeenCalled();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
99
121
|
});
|
|
100
122
|
describe('id prop', () => {
|
|
101
123
|
it('should put id attr on the drilldown', async () => {
|
package/lib/Drilldown/index.js
CHANGED
|
@@ -268,7 +268,7 @@ let Drilldown = exports.Drilldown = (_dec = (0, _withDeterministicId.withDetermi
|
|
|
268
268
|
}
|
|
269
269
|
if (event.type === 'keydown' && href) {
|
|
270
270
|
var _this$_drilldownRef;
|
|
271
|
-
const optionEl = (_this$_drilldownRef = this._drilldownRef) === null || _this$_drilldownRef === void 0 ? void 0 : _this$_drilldownRef.querySelector(`#${id}`);
|
|
271
|
+
const optionEl = (_this$_drilldownRef = this._drilldownRef) === null || _this$_drilldownRef === void 0 ? void 0 : _this$_drilldownRef.querySelector(`#${CSS.escape(id)}`);
|
|
272
272
|
const isLink = optionEl.tagName.toLowerCase() === 'a';
|
|
273
273
|
|
|
274
274
|
// we need this check because in some cases
|
|
@@ -668,7 +668,7 @@ let Drilldown = exports.Drilldown = (_dec = (0, _withDeterministicId.withDetermi
|
|
|
668
668
|
}
|
|
669
669
|
focusOption(id) {
|
|
670
670
|
const container = this._containerElement;
|
|
671
|
-
const optionElement = container === null || container === void 0 ? void 0 : container.querySelector(`[id="${id}"]`);
|
|
671
|
+
const optionElement = container === null || container === void 0 ? void 0 : container.querySelector(`[id="${CSS.escape(id)}"]`);
|
|
672
672
|
optionElement === null || optionElement === void 0 ? void 0 : optionElement.focus();
|
|
673
673
|
}
|
|
674
674
|
handleGroupOptionSelected(event, selectedOption) {
|
|
@@ -1199,7 +1199,7 @@ let Drilldown = exports.Drilldown = (_dec = (0, _withDeterministicId.withDetermi
|
|
|
1199
1199
|
// Use action ID if exists, otherwise first non-action option's ID
|
|
1200
1200
|
const targetId = actionLabel ? this._headerActionId : (_this$currentPage$chi2 = this.currentPage.children[0]) === null || _this$currentPage$chi2 === void 0 ? void 0 : _this$currentPage$chi2.props.id;
|
|
1201
1201
|
if (!targetId) return null;
|
|
1202
|
-
return (_this$_popover2 = this._popover) === null || _this$_popover2 === void 0 ? void 0 : (_this$_popover2$_cont = _this$_popover2._contentElement) === null || _this$_popover2$_cont === void 0 ? void 0 : _this$_popover2$_cont.querySelector(`#${targetId}`);
|
|
1202
|
+
return (_this$_popover2 = this._popover) === null || _this$_popover2 === void 0 ? void 0 : (_this$_popover2$_cont = _this$_popover2._contentElement) === null || _this$_popover2$_cont === void 0 ? void 0 : _this$_popover2$_cont.querySelector(`#${CSS.escape(targetId)}`);
|
|
1203
1203
|
},
|
|
1204
1204
|
elementRef: element => {
|
|
1205
1205
|
// setting ref for "Popover" version, the popover root
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instructure/ui-drilldown",
|
|
3
|
-
"version": "10.18.2-snapshot-
|
|
3
|
+
"version": "10.18.2-snapshot-3",
|
|
4
4
|
"description": "A drilldown menu component",
|
|
5
5
|
"author": "Instructure, Inc. Engineering and Product Design",
|
|
6
6
|
"module": "./es/index.js",
|
|
@@ -24,29 +24,29 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@babel/runtime": "^7.26.0",
|
|
27
|
-
"@instructure/console": "10.18.2-snapshot-
|
|
28
|
-
"@instructure/emotion": "10.18.2-snapshot-
|
|
29
|
-
"@instructure/shared-types": "10.18.2-snapshot-
|
|
30
|
-
"@instructure/ui-dom-utils": "10.18.2-snapshot-
|
|
31
|
-
"@instructure/ui-icons": "10.18.2-snapshot-
|
|
32
|
-
"@instructure/ui-options": "10.18.2-snapshot-
|
|
33
|
-
"@instructure/ui-popover": "10.18.2-snapshot-
|
|
34
|
-
"@instructure/ui-position": "10.18.2-snapshot-
|
|
35
|
-
"@instructure/ui-prop-types": "10.18.2-snapshot-
|
|
36
|
-
"@instructure/ui-react-utils": "10.18.2-snapshot-
|
|
37
|
-
"@instructure/ui-selectable": "10.18.2-snapshot-
|
|
38
|
-
"@instructure/ui-testable": "10.18.2-snapshot-
|
|
39
|
-
"@instructure/ui-utils": "10.18.2-snapshot-
|
|
40
|
-
"@instructure/ui-view": "10.18.2-snapshot-
|
|
27
|
+
"@instructure/console": "10.18.2-snapshot-3",
|
|
28
|
+
"@instructure/emotion": "10.18.2-snapshot-3",
|
|
29
|
+
"@instructure/shared-types": "10.18.2-snapshot-3",
|
|
30
|
+
"@instructure/ui-dom-utils": "10.18.2-snapshot-3",
|
|
31
|
+
"@instructure/ui-icons": "10.18.2-snapshot-3",
|
|
32
|
+
"@instructure/ui-options": "10.18.2-snapshot-3",
|
|
33
|
+
"@instructure/ui-popover": "10.18.2-snapshot-3",
|
|
34
|
+
"@instructure/ui-position": "10.18.2-snapshot-3",
|
|
35
|
+
"@instructure/ui-prop-types": "10.18.2-snapshot-3",
|
|
36
|
+
"@instructure/ui-react-utils": "10.18.2-snapshot-3",
|
|
37
|
+
"@instructure/ui-selectable": "10.18.2-snapshot-3",
|
|
38
|
+
"@instructure/ui-testable": "10.18.2-snapshot-3",
|
|
39
|
+
"@instructure/ui-utils": "10.18.2-snapshot-3",
|
|
40
|
+
"@instructure/ui-view": "10.18.2-snapshot-3",
|
|
41
41
|
"prop-types": "^15.8.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@instructure/ui-axe-check": "10.18.2-snapshot-
|
|
45
|
-
"@instructure/ui-babel-preset": "10.18.2-snapshot-
|
|
46
|
-
"@instructure/ui-color-utils": "10.18.2-snapshot-
|
|
47
|
-
"@instructure/ui-scripts": "10.18.2-snapshot-
|
|
48
|
-
"@instructure/ui-test-utils": "10.18.2-snapshot-
|
|
49
|
-
"@instructure/ui-themes": "10.18.2-snapshot-
|
|
44
|
+
"@instructure/ui-axe-check": "10.18.2-snapshot-3",
|
|
45
|
+
"@instructure/ui-babel-preset": "10.18.2-snapshot-3",
|
|
46
|
+
"@instructure/ui-color-utils": "10.18.2-snapshot-3",
|
|
47
|
+
"@instructure/ui-scripts": "10.18.2-snapshot-3",
|
|
48
|
+
"@instructure/ui-test-utils": "10.18.2-snapshot-3",
|
|
49
|
+
"@instructure/ui-themes": "10.18.2-snapshot-3",
|
|
50
50
|
"@testing-library/jest-dom": "^6.6.3",
|
|
51
51
|
"@testing-library/react": "^16.0.1",
|
|
52
52
|
"@testing-library/user-event": "^14.5.2",
|
|
@@ -104,6 +104,33 @@ describe('<Drilldown />', () => {
|
|
|
104
104
|
expect(options.length).toBe(0)
|
|
105
105
|
expect(notAllowedChild).not.toBeInTheDocument()
|
|
106
106
|
})
|
|
107
|
+
|
|
108
|
+
it('should not crash for weird option ids', async () => {
|
|
109
|
+
const onSelect = vi.fn()
|
|
110
|
+
const weirdID = 'some"_weird!@#$%^&*()\\|`id'
|
|
111
|
+
render(
|
|
112
|
+
<Drilldown rootPageId="page0" onSelect={onSelect}>
|
|
113
|
+
<Drilldown.Page id="page0">
|
|
114
|
+
{data.map((option) => (
|
|
115
|
+
<Drilldown.Option
|
|
116
|
+
id={weirdID + option.id}
|
|
117
|
+
value={weirdID + option.id}
|
|
118
|
+
key={weirdID + option.id}
|
|
119
|
+
data-testid={weirdID + option.id}
|
|
120
|
+
>
|
|
121
|
+
{option.label}
|
|
122
|
+
</Drilldown.Option>
|
|
123
|
+
))}
|
|
124
|
+
</Drilldown.Page>
|
|
125
|
+
</Drilldown>
|
|
126
|
+
)
|
|
127
|
+
const option_1 = screen.getByTestId(weirdID + 'opt_1')
|
|
128
|
+
await userEvent.click(option_1)
|
|
129
|
+
|
|
130
|
+
await waitFor(() => {
|
|
131
|
+
expect(onSelect).toHaveBeenCalled()
|
|
132
|
+
})
|
|
133
|
+
})
|
|
107
134
|
})
|
|
108
135
|
|
|
109
136
|
describe('id prop', () => {
|
package/src/Drilldown/index.tsx
CHANGED
|
@@ -585,9 +585,8 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
|
|
|
585
585
|
|
|
586
586
|
focusOption(id: string) {
|
|
587
587
|
const container = this._containerElement
|
|
588
|
-
|
|
589
588
|
const optionElement = container?.querySelector(
|
|
590
|
-
`[id="${id}"]`
|
|
589
|
+
`[id="${CSS.escape(id)}"]`
|
|
591
590
|
) as HTMLSpanElement
|
|
592
591
|
|
|
593
592
|
optionElement?.focus()
|
|
@@ -816,7 +815,7 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
|
|
|
816
815
|
|
|
817
816
|
if (event.type === 'keydown' && href) {
|
|
818
817
|
const optionEl = this._drilldownRef?.querySelector(
|
|
819
|
-
`#${id}`
|
|
818
|
+
`#${CSS.escape(id)}`
|
|
820
819
|
) as HTMLLinkElement
|
|
821
820
|
const isLink = optionEl.tagName.toLowerCase() === 'a'
|
|
822
821
|
|
|
@@ -1516,7 +1515,9 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
|
|
|
1516
1515
|
: this.currentPage.children[0]?.props.id
|
|
1517
1516
|
|
|
1518
1517
|
if (!targetId) return null
|
|
1519
|
-
return this._popover?._contentElement?.querySelector(
|
|
1518
|
+
return this._popover?._contentElement?.querySelector(
|
|
1519
|
+
`#${CSS.escape(targetId)}`
|
|
1520
|
+
)
|
|
1520
1521
|
}}
|
|
1521
1522
|
elementRef={(element) => {
|
|
1522
1523
|
// setting ref for "Popover" version, the popover root
|