Skip to content

Commit 82df5c1

Browse files
committed
fix(many): fix "not a valid selector" exception when an option ID contains quotes
The issue is that we are letting users choose any string as an ID, and the querySelector method only accepts CSS safe IDs. Luckily there is a built in method to escape stuff that it does not like Fixes INSTUI-4570
1 parent 1a03763 commit 82df5c1

File tree

4 files changed

+25
-22
lines changed

4 files changed

+25
-22
lines changed

packages/ui-drilldown/src/Drilldown/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1516,7 +1516,9 @@ class Drilldown extends Component<DrilldownProps, DrilldownState> {
15161516
: this.currentPage.children[0]?.props.id
15171517

15181518
if (!targetId) return null
1519-
return this._popover?._contentElement?.querySelector(`#${targetId}`)
1519+
return this._popover?._contentElement?.querySelector(
1520+
`#${CSS.escape(targetId)}`
1521+
)
15201522
}}
15211523
elementRef={(element) => {
15221524
// setting ref for "Popover" version, the popover root

packages/ui-select/src/Select/index.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -291,22 +291,21 @@ class Select extends Component<SelectProps> {
291291
}
292292

293293
scrollToOption(id?: string) {
294-
if (this._listView) {
295-
const option = this._listView.querySelector(`[id="${id}"]`)
296-
if (!option) return
297-
298-
const listItem = option.parentNode
299-
const parentTop = getBoundingClientRect(this._listView).top
300-
const elemTop = getBoundingClientRect(listItem).top
301-
const parentBottom = parentTop + this._listView.clientHeight
302-
const elemBottom =
303-
elemTop + (listItem ? (listItem as Element).clientHeight : 0)
304-
305-
if (elemBottom > parentBottom) {
306-
this._listView.scrollTop += elemBottom - parentBottom
307-
} else if (elemTop < parentTop) {
308-
this._listView.scrollTop -= parentTop - elemTop
309-
}
294+
if (!this._listView || !id) return
295+
const option = this._listView.querySelector(`[id="${CSS.escape(id)}"]`)
296+
if (!option) return
297+
298+
const listItem = option.parentNode
299+
const parentTop = getBoundingClientRect(this._listView).top
300+
const elemTop = getBoundingClientRect(listItem).top
301+
const parentBottom = parentTop + this._listView.clientHeight
302+
const elemBottom =
303+
elemTop + (listItem ? (listItem as Element).clientHeight : 0)
304+
305+
if (elemBottom > parentBottom) {
306+
this._listView.scrollTop += elemBottom - parentBottom
307+
} else if (elemTop < parentTop) {
308+
this._listView.scrollTop -= parentTop - elemTop
310309
}
311310
}
312311

packages/ui-tabs/src/Tabs/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,10 +331,12 @@ class Tabs extends Component<TabsProps, TabsState> {
331331
// this is needed because keypress cancels scrolling. So we have to trigger the scrolling
332332
// one "tick" later than the keypress
333333
setTimeout(() => {
334-
this.state.withTabListOverflow &&
335-
this.showActiveTabIfOverlayed(
336-
this._tabList!.querySelector(`#tab-${id}`)
337-
)
334+
if (this.state.withTabListOverflow) {
335+
const tab = id
336+
? this._tabList!.querySelector(`#tab-${CSS.escape(id)}`)
337+
: null
338+
this.showActiveTabIfOverlayed(tab)
339+
}
338340
}, 0)
339341
}
340342

packages/ui-top-nav-bar/src/TopNavBar/TopNavBarLayout/SmallViewportLayout/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ class TopNavBarSmallViewportLayout extends Component<
310310
setTimeout(() => {
311311
const container = document.getElementById(this._trayContainerId)
312312
const firstOption = container?.querySelector(
313-
`[id="${targetId}"]`
313+
`[id="${CSS.escape(targetId)}"]`
314314
) as HTMLSpanElement
315315
firstOption?.focus()
316316
if (this._drilldownRef) {

0 commit comments

Comments
 (0)