Co-authored-by: gobha <jasafpro@gmail.com> Co-committed-by: gobha <jasafpro@gmail.com>
61 lines
2.3 KiB
JavaScript
61 lines
2.3 KiB
JavaScript
/**
|
|
* Tabs primitive — horizontal tab bar with overflow scroll arrows
|
|
* tabs: [{ label, value, icon?, disabled? }]
|
|
*/
|
|
const { html } = window;
|
|
const { useRef, useEffect, useState, useCallback } = hooks;
|
|
|
|
export function Tabs({ tabs = [], active, onChange }) {
|
|
const scrollRef = useRef(null);
|
|
const [overflow, setOverflow] = useState({ left: false, right: false });
|
|
|
|
const checkOverflow = useCallback(() => {
|
|
const el = scrollRef.current;
|
|
if (!el) return;
|
|
setOverflow({
|
|
left: el.scrollLeft > 0,
|
|
right: el.scrollLeft + el.clientWidth < el.scrollWidth - 1,
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
checkOverflow();
|
|
const el = scrollRef.current;
|
|
if (el) el.addEventListener('scroll', checkOverflow, { passive: true });
|
|
window.addEventListener('resize', checkOverflow);
|
|
return () => {
|
|
if (el) el.removeEventListener('scroll', checkOverflow);
|
|
window.removeEventListener('resize', checkOverflow);
|
|
};
|
|
}, [checkOverflow, tabs]);
|
|
|
|
const scroll = (dir) => {
|
|
const el = scrollRef.current;
|
|
if (el) el.scrollBy({ left: dir * 150, behavior: 'smooth' });
|
|
};
|
|
|
|
return html`
|
|
<div class="sw-tabs">
|
|
${overflow.left && html`
|
|
<button class="sw-tabs__arrow sw-tabs__arrow--left" onClick=${() => scroll(-1)} aria-label="Scroll left">\u2039</button>
|
|
`}
|
|
<div class="sw-tabs__scroll" ref=${scrollRef}>
|
|
${tabs.map(tab => html`
|
|
<button
|
|
class="sw-tabs__tab ${tab.value === active ? 'sw-tabs__tab--active' : ''} ${tab.disabled ? 'sw-tabs__tab--disabled' : ''}"
|
|
disabled=${tab.disabled}
|
|
onClick=${() => !tab.disabled && onChange && onChange(tab.value)}
|
|
role="tab"
|
|
aria-selected=${tab.value === active}>
|
|
${tab.icon && html`<span class="sw-tabs__icon">${tab.icon}</span>`}
|
|
${tab.label}
|
|
</button>
|
|
`)}
|
|
</div>
|
|
${overflow.right && html`
|
|
<button class="sw-tabs__arrow sw-tabs__arrow--right" onClick=${() => scroll(1)} aria-label="Scroll right">\u203a</button>
|
|
`}
|
|
</div>
|
|
`;
|
|
}
|