mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
refactor(console): improve tabs used in mdx files
This commit is contained in:
parent
def900b3fa
commit
56d610bae9
2 changed files with 61 additions and 27 deletions
32
packages/console/src/mdx-components/Tabs/index.module.scss
Normal file
32
packages/console/src/mdx-components/Tabs/index.module.scss
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
@use '@/scss/underscore' as _;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
border-bottom: 1px solid var(--color-divider);
|
||||||
|
display: flex;
|
||||||
|
margin: _.unit(1) 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
margin-right: _.unit(6);
|
||||||
|
padding-bottom: _.unit(1);
|
||||||
|
font: var(--font-subhead-2);
|
||||||
|
color: var(--color-caption);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
li[aria-selected='true'] {
|
||||||
|
color: var(--color-primary);
|
||||||
|
border-bottom: 2px solid var(--color-primary);
|
||||||
|
margin-bottom: -1px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,9 +6,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Nullable } from '@silverhand/essentials';
|
import { Nullable } from '@silverhand/essentials';
|
||||||
import React, { useState, isValidElement, type ReactElement, cloneElement } from 'react';
|
import React, { useState, isValidElement, type ReactElement, cloneElement, useRef } from 'react';
|
||||||
|
|
||||||
import type { Props as TabItemProps } from '../TabItem';
|
import type { Props as TabItemProps } from '../TabItem';
|
||||||
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -35,20 +36,11 @@ const Tabs = ({ className, children }: Props): JSX.Element => {
|
||||||
label,
|
label,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const [selectedValue, setSelectedValue] = useState<string>();
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||||
const tabReferences: Array<Nullable<HTMLLIElement>> = [];
|
const tabReferences = useRef<Array<Nullable<HTMLLIElement>>>(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
const handleTabChange = (
|
Array.from<null>({ length }).fill(null)
|
||||||
event: React.FocusEvent<HTMLLIElement> | React.MouseEvent<HTMLLIElement>
|
);
|
||||||
) => {
|
|
||||||
const newTab = event.currentTarget;
|
|
||||||
const newTabIndex = tabReferences.indexOf(newTab);
|
|
||||||
const newTabValue = values[newTabIndex]?.value;
|
|
||||||
|
|
||||||
if (newTabValue !== selectedValue) {
|
|
||||||
setSelectedValue(newTabValue);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleKeydown = (event: React.KeyboardEvent<HTMLLIElement>) => {
|
const handleKeydown = (event: React.KeyboardEvent<HTMLLIElement>) => {
|
||||||
// eslint-disable-next-line @silverhand/fp/no-let
|
// eslint-disable-next-line @silverhand/fp/no-let
|
||||||
|
@ -56,17 +48,19 @@ const Tabs = ({ className, children }: Props): JSX.Element => {
|
||||||
|
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'ArrowRight': {
|
case 'ArrowRight': {
|
||||||
const nextTab = tabReferences.indexOf(event.currentTarget) + 1;
|
const nextTab = tabReferences.current.indexOf(event.currentTarget) + 1;
|
||||||
// eslint-disable-next-line @silverhand/fp/no-mutation
|
// eslint-disable-next-line @silverhand/fp/no-mutation
|
||||||
focusElement = tabReferences[nextTab] ?? tabReferences[0] ?? null;
|
focusElement = tabReferences.current[nextTab] ?? tabReferences.current[0] ?? null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'ArrowLeft': {
|
case 'ArrowLeft': {
|
||||||
const previousTab = tabReferences.indexOf(event.currentTarget) - 1;
|
const previousTab = tabReferences.current.indexOf(event.currentTarget) - 1;
|
||||||
// eslint-disable-next-line @silverhand/fp/no-mutation
|
// eslint-disable-next-line @silverhand/fp/no-mutation
|
||||||
focusElement =
|
focusElement =
|
||||||
tabReferences[previousTab] ?? tabReferences[tabReferences.length - 1] ?? null;
|
tabReferences.current[previousTab] ??
|
||||||
|
tabReferences.current[tabReferences.current.length - 1] ??
|
||||||
|
null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -77,27 +71,35 @@ const Tabs = ({ className, children }: Props): JSX.Element => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={styles.container}>
|
||||||
<ul role="tablist" aria-orientation="horizontal" className={className}>
|
<ul role="tablist" aria-orientation="horizontal" className={className}>
|
||||||
{values.map(({ value, label }) => (
|
{values.map(({ value, label }, index) => (
|
||||||
<li
|
<li
|
||||||
key={value}
|
key={value}
|
||||||
ref={(tabControl) => tabReferences.concat(tabControl)}
|
ref={(element) => {
|
||||||
|
// eslint-disable-next-line @silverhand/fp/no-mutation
|
||||||
|
tabReferences.current[index] = element;
|
||||||
|
}}
|
||||||
role="tab"
|
role="tab"
|
||||||
tabIndex={selectedValue === value ? 0 : -1}
|
tabIndex={selectedIndex === index ? 0 : -1}
|
||||||
aria-selected={selectedValue === value}
|
aria-selected={selectedIndex === index}
|
||||||
onKeyDown={handleKeydown}
|
onKeyDown={handleKeydown}
|
||||||
onFocus={handleTabChange}
|
onFocus={() => {
|
||||||
onClick={handleTabChange}
|
setSelectedIndex(index);
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedIndex(index);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{label ?? value}
|
{label ?? value}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<div>
|
<div>
|
||||||
{verifiedChildren.map((tabItem) =>
|
{verifiedChildren.map((tabItem, index) =>
|
||||||
cloneElement(tabItem, {
|
cloneElement(tabItem, {
|
||||||
key: tabItem.props.value,
|
key: tabItem.props.value,
|
||||||
|
className: index === selectedIndex ? undefined : styles.hidden,
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue