From c0f11ea05a80df12e3b8c53169de79f794d423e6 Mon Sep 17 00:00:00 2001 From: dananji Date: Tue, 14 Nov 2023 18:01:11 -0500 Subject: [PATCH] Make tab labels focusable in the demo site --- demo/app.js | 175 +++++++++++++++++++++++++++++++++----------------- demo/app.scss | 95 ++++++++++++--------------- 2 files changed, 156 insertions(+), 114 deletions(-) diff --git a/demo/app.js b/demo/app.js index 0c665f14..cd8b92da 100644 --- a/demo/app.js +++ b/demo/app.js @@ -14,7 +14,13 @@ import '../dist/ramp.css'; const App = ({ manifestURL }) => { const [userURL, setUserURL] = React.useState(manifestURL); const [manifestUrl, setManifestUrl] = React.useState(manifestURL); - const [activeTab, setActiveTab] = React.useState('Details'); + + const tabValues = [ + { title: 'Details', ref: React.useRef(null) }, + { title: 'Transcripts', ref: React.useRef(null) }, + { title: 'Files', ref: React.useRef(null) }, + { title: 'Markers', ref: React.useRef(null) }, + ]; React.useEffect(() => { setManifestUrl(manifestUrl); @@ -30,10 +36,6 @@ const App = ({ manifestURL }) => { setUserURL(e.target.value); }; - const handleShowTab = (tab) => { - setActiveTab(tab); - }; - return (

Ramp

@@ -76,52 +78,7 @@ const App = ({ manifestURL }) => {
-
- - - - - - - - - - - -
+ @@ -130,19 +87,117 @@ const App = ({ manifestURL }) => { ); }; -const Tab = ({ label, onClick, activeTab, children }) => { - const onClickHandler = () => { - onClick(label); + +/*Reference: https://accessible-react.eevis.codes/components/tabs */ +const Tabs = ({ tabValues, manifestUrl }) => { + const [activeTab, setActiveTab] = React.useState(0); + + let tabs = []; + + const handleClick = (index) => { + setActiveTab(index); + }; + + const handleNextTab = (firstTabInRound, nextTab, lastTabInRound) => { + const tabToSelect = + activeTab === lastTabInRound ? firstTabInRound : nextTab; + setActiveTab(tabToSelect); + tabValues[tabToSelect].ref.current.focus(); + }; + + const handleKeyPress = (event) => { + const tabCount = Object.keys(tabValues).length; + + if (event.key === "ArrowLeft") { + const last = tabCount; + const next = activeTab - 1; + handleNextTab(last, next, 0); + } + if (event.key === "ArrowRight") { + const first = 0; + const next = activeTab + 1; + handleNextTab(first, next, tabCount); + } }; + tabValues.map((t, index) => { + tabs.push( + + ); + }); + return ( -
- - -
- {children} +
+
+
    + {tabs} +
-
+ + + + + + + + + + + + + + ); +}; + +const Tab = ({ id, tabPanelId, index, handleChange, activeTab, title, tabRef }) => { + const handleClick = () => { handleChange(index); }; + return ( +
  • + +
  • + ); +}; + +const TabPanel = ({ id, tabId, activeTab, tabIndex, children }) => { + return ( + ); }; diff --git a/demo/app.scss b/demo/app.scss index 35875287..4e8b0c0e 100644 --- a/demo/app.scss +++ b/demo/app.scss @@ -28,78 +28,65 @@ div.iiif-player-demo { margin-right: 2rem; } - // Reference: https://codepen.io/alvarotrigo/pen/xxXoMJy - .tabs { - flex: 1; - position: relative; + /*Reference: https://accessible-react.eevis.codes/components/tabs */ + .tablist { display: flex; - border-radius: 0.5rem 0.5rem 0 0; + flex-direction: row; } - .tab-nav { - flex: 1; + .tablist>li { + list-style: none; } - .tab-nav>label { - display: block; - box-sizing: border-box; - /* tab content must clear this */ - height: 2.5rem; - - padding: 10px; - text-align: center; - cursor: pointer; - transition: background 0.5s ease; + .tablist>li>button { + padding: 0.5rem; + background-color: transparent; + border: none; color: black; - } + font-size: 1rem; + font-family: inherit; + cursor: pointer; - .tab-nav>label:hover { - background: #d3d3d3; - border-radius: 0.5rem 0.5rem 0 0; + &:hover { + background-color: #d3d3d3; + border-radius: .5rem .5rem 0 0; + } } - .tab-content { - position: absolute; + .tablist>li>[aria-selected="true"] { border: 1px solid #d3d3d3; - height: max-content; - - left: 0; - bottom: 0; - right: 0; - /* clear the tab labels */ - top: 2.5rem; - - border-radius: 0 0 0.5rem 0.5rem; - - transition: - opacity 0.8s ease, - transform 0.8s ease; - - /* show/hide */ - opacity: 0; - transform: scale(0.1); - transform-origin: top left; + border-bottom: none; + border-radius: .5rem .5rem 0 0; } + .tabs-wrapper { + flex: 1; + position: relative; + padding: 1rem; + } - /* MAKE IT WORK ----- */ - .tab-nav [type=radio] { - display: none; + /* From Every Layout (https://every-layout.dev/) */ + .switcher>* { + display: flex; + flex-wrap: wrap; + margin: 0; + padding-left: 0; } - [type=radio]:checked~label { - z-index: 2; - border: 1px solid #d3d3d3; - border-bottom: none; - border-radius: 0.5rem 0.5rem 0 0; + .switcher>*>* { + flex-grow: 1; + flex-basis: auto; + margin: 0; } - [type=radio]:checked~label~.tab-content { - z-index: 1; + .switcher>*> :nth-last-child(n + 5), + .switcher>*> :nth-last-child(n + 5)~* { + flex-basis: 100%; + } - /* show/hide */ - opacity: 1; - transform: scale(1); + .tabpanel { + border: 1px solid #d3d3d3; + border-radius: 0 0 0.5rem 0.5rem; } }