Replace remaining React ARIA components with Compound components (#2576)
* Fix issues detected by Knip Including cleaning up some unused code and dependencies, using a React hook that we unintentionally stopped using, and also adding some previously undeclared dependencies. * Replace remaining React ARIA components with Compound components * fix button position * disable scrollbars to resolve overlapping button --------- Co-authored-by: Timo <toger5@hotmail.de>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
Copyright 2024 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,60 +21,16 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.tabList {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 auto 24px auto;
|
||||
gap: 16px;
|
||||
overflow-y: auto;
|
||||
max-width: 100%;
|
||||
|
||||
/*no scrollbars*/
|
||||
scrollbar-width: none; /* Firefox */
|
||||
-ms-overflow-style: none; /* IE 10+ */
|
||||
}
|
||||
|
||||
.tab {
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 8px;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
|
||||
.tab > * {
|
||||
color: var(--cpd-color-text-secondary);
|
||||
margin: 0 8px 0 0;
|
||||
}
|
||||
|
||||
.tab svg * {
|
||||
fill: var(--cpd-color-text-secondary);
|
||||
}
|
||||
|
||||
.tab > :last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.tab.selected {
|
||||
background-color: var(--cpd-color-text-action-accent);
|
||||
}
|
||||
|
||||
.tab.selected * {
|
||||
color: var(--stopgap-color-on-solid-accent);
|
||||
}
|
||||
|
||||
.tab.selected svg * {
|
||||
fill: var(--stopgap-color-on-solid-accent);
|
||||
}
|
||||
|
||||
.tab.disabled {
|
||||
}
|
||||
|
||||
.tabPanel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
.tabList::-webkit-scrollbar {
|
||||
/*no scrollbars*/
|
||||
background: transparent; /* Chrome/Safari/Webkit */
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2022 New Vector Ltd
|
||||
Copyright 2024 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,74 +14,53 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { useRef } from "react";
|
||||
import { useTabList, useTab, useTabPanel } from "@react-aria/tabs";
|
||||
import { Item } from "@react-stately/collections";
|
||||
import { useTabListState, TabListState } from "@react-stately/tabs";
|
||||
import classNames from "classnames";
|
||||
import { AriaTabPanelProps, TabListProps } from "@react-types/tabs";
|
||||
import { Node } from "@react-types/shared";
|
||||
import { Key, ReactNode, useId } from "react";
|
||||
import { NavBar, NavItem } from "@vector-im/compound-web";
|
||||
|
||||
import styles from "./Tabs.module.css";
|
||||
|
||||
interface TabContainerProps<T> extends TabListProps<T> {
|
||||
className?: string;
|
||||
export interface Tab<K extends Key> {
|
||||
key: K;
|
||||
name: string;
|
||||
content: ReactNode;
|
||||
}
|
||||
|
||||
export function TabContainer<T extends object>(
|
||||
props: TabContainerProps<T>,
|
||||
): JSX.Element {
|
||||
const state = useTabListState<T>(props);
|
||||
const ref = useRef<HTMLUListElement>(null);
|
||||
const { tabListProps } = useTabList(props, state, ref);
|
||||
interface Props<K extends Key> {
|
||||
label: string;
|
||||
tab: K;
|
||||
onTabChange: (key: K) => void;
|
||||
tabs: Tab<K>[];
|
||||
}
|
||||
|
||||
export function TabContainer<K extends Key>({
|
||||
label,
|
||||
tab,
|
||||
onTabChange,
|
||||
tabs,
|
||||
}: Props<K>): ReactNode {
|
||||
const idPrefix = useId();
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.tabContainer, props.className)}>
|
||||
<ul {...tabListProps} ref={ref} className={styles.tabList}>
|
||||
{[...state.collection].map((item) => (
|
||||
<Tab item={item} state={state} key={item.key} />
|
||||
<div className={styles.tabContainer}>
|
||||
<NavBar role="tablist" aria-label={label} className={styles.tabList}>
|
||||
{tabs.map(({ key, name }) => (
|
||||
<NavItem
|
||||
aria-controls={`${idPrefix}[${key}]`}
|
||||
onClick={() => onTabChange(key)}
|
||||
active={key === tab}
|
||||
>
|
||||
{name}
|
||||
</NavItem>
|
||||
))}
|
||||
</ul>
|
||||
<TabPanel key={state.selectedItem?.key} state={state} />
|
||||
</NavBar>
|
||||
{tabs.map(({ key, content }) => (
|
||||
<div
|
||||
id={`${idPrefix}[${key}]`}
|
||||
style={{ display: key === tab ? undefined : "none" }}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface TabProps<T> {
|
||||
item: Node<T>;
|
||||
state: TabListState<T>;
|
||||
}
|
||||
|
||||
function Tab<T>({ item, state }: TabProps<T>): JSX.Element {
|
||||
const { key, rendered } = item;
|
||||
const ref = useRef<HTMLLIElement>(null);
|
||||
const { tabProps } = useTab({ key }, state, ref);
|
||||
|
||||
return (
|
||||
<li
|
||||
{...tabProps}
|
||||
ref={ref}
|
||||
className={classNames(styles.tab, {
|
||||
[styles.selected]: state.selectedKey === key,
|
||||
[styles.disabled]: state.disabledKeys.has(key),
|
||||
})}
|
||||
>
|
||||
{rendered}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
interface TabPanelProps<T> extends AriaTabPanelProps {
|
||||
state: TabListState<T>;
|
||||
}
|
||||
|
||||
function TabPanel<T>({ state, ...props }: TabPanelProps<T>): JSX.Element {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const { tabPanelProps } = useTabPanel(props, state, ref);
|
||||
return (
|
||||
<div {...tabPanelProps} ref={ref} className={styles.tabPanel}>
|
||||
{state.selectedItem?.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const TabItem = Item;
|
||||
|
||||
Reference in New Issue
Block a user