diff --git a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-body.js b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-body.js
index c4f47e325d..3f9eb7fc5f 100644
--- a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-body.js
+++ b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-body.js
@@ -1,4 +1,3 @@
-import { TabPanels, TabPanel } from '@reach/tabs'
import { useTranslation } from 'react-i18next'
import PropTypes from 'prop-types'
import SymbolPaletteItems from './symbol-palette-items'
@@ -9,6 +8,7 @@ export default function SymbolPaletteBody({
filteredSymbols,
handleSelect,
focusInput,
+ activeCategoryId,
}) {
const { t } = useTranslation()
@@ -17,7 +17,7 @@ export default function SymbolPaletteBody({
// note: include empty tab panels so that aria-controls on tabs can still reference the panel ids
if (filteredSymbols) {
return (
- <>
+
{filteredSymbols.length ? (
{t('no_symbols_found')}
)}
-
- {categories.map(category => (
-
- ))}
-
- >
+ {categories.map(category => (
+
+ ))}
+
)
}
// not searching: show the symbols grouped by category
return (
-
- {categories.map(category => (
-
+
+ {categories.map((category) => (
+
-
+
))}
-
+
)
+
+
}
SymbolPaletteBody.propTypes = {
categories: PropTypes.arrayOf(PropTypes.object).isRequired,
@@ -58,4 +72,5 @@ SymbolPaletteBody.propTypes = {
filteredSymbols: PropTypes.arrayOf(PropTypes.object),
handleSelect: PropTypes.func.isRequired,
focusInput: PropTypes.func.isRequired,
+ activeCategoryId: PropTypes.string.isRequired,
}
diff --git a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-close-button.js b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-close-button.js
index 839b5d1cd5..dbde7ca775 100644
--- a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-close-button.js
+++ b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-close-button.js
@@ -11,7 +11,7 @@ export default function SymbolPaletteCloseButton() {
type="button"
className="btn-close symbol-palette-close-button"
onClick={toggleSymbolPalette}
- aria-label={t('clear_search')}
+ aria-label={t('close')}
>
diff --git a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-content.js b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-content.js
index cb5a9e3029..b395cac53d 100644
--- a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-content.js
+++ b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-content.js
@@ -1,4 +1,3 @@
-import { Tabs } from '@reach/tabs'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import PropTypes from 'prop-types'
@@ -10,8 +9,6 @@ import SymbolPaletteBody from './symbol-palette-body'
import SymbolPaletteTabs from './symbol-palette-tabs'
import SymbolPaletteCloseButton from './symbol-palette-close-button'
-import '@reach/tabs/styles.css'
-
export default function SymbolPaletteContent({ handleSelect }) {
const [input, setInput] = useState('')
@@ -19,6 +16,7 @@ export default function SymbolPaletteContent({ handleSelect }) {
// build the list of categories with translated labels
const categories = useMemo(() => createCategories(t), [t])
+ const [activeCategoryId, setActiveCategoryId] = useState(categories[0]?.id)
// group the symbols by category
const categorisedSymbols = useMemo(
@@ -59,18 +57,23 @@ export default function SymbolPaletteContent({ handleSelect }) {
inputRef.current.focus()
}
}, [])
-
return (
-
+
)
}
SymbolPaletteContent.propTypes = {
diff --git a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-search.js b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-search.js
index 7d52a82874..75d01f0119 100644
--- a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-search.js
+++ b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-search.js
@@ -42,4 +42,4 @@ export default function SymbolPaletteSearch({ setInput, inputRef }) {
SymbolPaletteSearch.propTypes = {
setInput: PropTypes.func.isRequired,
inputRef: PropTypes.object.isRequired,
-};
+}
diff --git a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-tabs.js b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-tabs.js
index d53cd93ac0..80f0421f27 100644
--- a/services/web/frontend/js/features/symbol-palette/components/symbol-palette-tabs.js
+++ b/services/web/frontend/js/features/symbol-palette/components/symbol-palette-tabs.js
@@ -1,22 +1,76 @@
-import { TabList, Tab } from '@reach/tabs'
import PropTypes from 'prop-types'
+import { useState, useRef } from 'react'
+
+
+export default function SymbolPaletteTabs({
+ categories,
+ activeCategoryId,
+ setActiveCategoryId,
+}) {
+
+ const buttonRefs = useRef([])
+ const focusTab = (index) => {
+ setActiveCategoryId(categories[index].id)
+ buttonRefs.current[index]?.focus()
+ }
+
+ const handleKeyDown = (e, index) => {
+ switch (e.key) {
+ case 'ArrowRight':
+ focusTab((index + 1) % categories.length)
+ break
+ case 'ArrowLeft':
+ focusTab((index - 1 + categories.length) % categories.length)
+ break
+ case 'Home':
+ case 'PageUp':
+ focusTab(0)
+ break
+ case 'End':
+ case 'PageDown':
+ focusTab(categories.length - 1)
+ break
+ default:
+ break
+ }
+ }
-export default function SymbolPaletteTabs({ categories }) {
return (
-
- {categories.map(category => (
-
- {category.label}
-
- ))}
-
+
+ {categories.map((category, index) => {
+ const selected = activeCategoryId === category.id
+ return (
+
+ )
+ })}
+
)
}
+
SymbolPaletteTabs.propTypes = {
- categories: PropTypes.arrayOf(
- PropTypes.shape({
- id: PropTypes.string.isRequired,
- label: PropTypes.string.isRequired,
- })
- ).isRequired,
+ categories: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+ })).isRequired,
+ activeCategoryId: PropTypes.string.isRequired,
+ setActiveCategoryId: PropTypes.func.isRequired,
}
diff --git a/services/web/frontend/stylesheets/modules/symbol-palette.scss b/services/web/frontend/stylesheets/modules/symbol-palette.scss
index 2841b374e1..41d2c7de70 100644
--- a/services/web/frontend/stylesheets/modules/symbol-palette.scss
+++ b/services/web/frontend/stylesheets/modules/symbol-palette.scss
@@ -155,7 +155,7 @@
.symbol-palette-close-button-outer {
display: flex;
align-items: center;
- margin-right: var(--spacing-01);
+ margin-right: var(--spacing-05);
}
.symbol-palette-close-button {
diff --git a/services/web/package.json b/services/web/package.json
index 2868ff76d3..6d6f1c939f 100644
--- a/services/web/package.json
+++ b/services/web/package.json
@@ -232,7 +232,6 @@
"@pollyjs/core": "^6.0.6",
"@pollyjs/persister-fs": "^6.0.6",
"@prettier/plugin-pug": "^3.4.0",
- "@reach/tabs": "0.18.0",
"@replit/codemirror-emacs": "overleaf/codemirror-emacs#4394c03858f27053f8768258e9493866e06e938e",
"@replit/codemirror-indentation-markers": "overleaf/codemirror-indentation-markers#371ce3b56f453a392eb0d3b85ab019c185c68e1f",
"@replit/codemirror-vim": "overleaf/codemirror-vim#1bef138382d948018f3f9b8a4d7a70ab61774e4b",