Tabs: fix misplaced indicator
This commit is contained in:
parent
66b593add8
commit
0eef74f25f
4 changed files with 58 additions and 67 deletions
23
src/material/Tab.css
Normal file
23
src/material/Tab.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
.Tab {
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
height: 100%;
|
||||
max-width: min(calc(100% - 56px), 264px);
|
||||
padding: 10px 24px;
|
||||
font-size: 0.8135rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
transition: color 120ms var(--tutu-anim-curve-std);
|
||||
}
|
||||
|
||||
.MuiToolbar-root .Tab {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&.focus,
|
||||
&.Tabs-focus {
|
||||
color: white;
|
||||
}
|
||||
}
|
|
@ -1,26 +1,18 @@
|
|||
import {
|
||||
Component,
|
||||
createEffect,
|
||||
splitProps,
|
||||
type JSX,
|
||||
type ParentComponent,
|
||||
} from "solid-js";
|
||||
import { css } from "solid-styled";
|
||||
import { useTabListContext } from "./Tabs";
|
||||
import "./Tab.css";
|
||||
|
||||
const Tab: ParentComponent<
|
||||
{
|
||||
focus?: boolean;
|
||||
large?: boolean;
|
||||
} & JSX.ButtonHTMLAttributes<HTMLButtonElement>
|
||||
> = (props) => {
|
||||
const [managed, rest] = splitProps(props, [
|
||||
"focus",
|
||||
"large",
|
||||
"type",
|
||||
"role",
|
||||
"ref",
|
||||
]);
|
||||
const [managed, rest] = splitProps(props, ["focus", "type", "role", "ref"]);
|
||||
let self: HTMLButtonElement;
|
||||
const {
|
||||
focusOn: [, setFocusOn],
|
||||
|
@ -35,32 +27,7 @@ const Tab: ParentComponent<
|
|||
}
|
||||
return managed.focus;
|
||||
});
|
||||
css`
|
||||
.tab {
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
min-width: ${managed.large ? "160px" : "72px"};
|
||||
height: 48px;
|
||||
max-width: min(calc(100% - 56px), 264px);
|
||||
padding: 10px 24px;
|
||||
font-size: 0.8135rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
transition: color 120ms var(--tutu-anim-curve-std);
|
||||
}
|
||||
|
||||
:global(.MuiToolbar-root) .tab {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&.focus,
|
||||
&:global(.tablist-focus) {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
`;
|
||||
return (
|
||||
<button
|
||||
ref={(x) => {
|
||||
|
@ -68,7 +35,7 @@ const Tab: ParentComponent<
|
|||
(managed.ref as (e: HTMLButtonElement) => void)?.(x);
|
||||
}}
|
||||
type={managed.type ?? "button"}
|
||||
classList={{ tab: true, focus: managed.focus }}
|
||||
classList={{ Tab: true, focus: managed.focus }}
|
||||
role={managed.role ?? "tab"}
|
||||
{...rest}
|
||||
>
|
||||
|
|
21
src/material/Tabs.css
Normal file
21
src/material/Tabs.css
Normal file
|
@ -0,0 +1,21 @@
|
|||
.Tabs {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
align-self: stretch;
|
||||
|
||||
&::after {
|
||||
transition:
|
||||
left var(--tabs-indkt-movspeed-offset, 0) var(--tutu-anim-curve-std),
|
||||
width var(--tabs-indkt-movspeed-width, 0) var(--tutu-anim-curve-std);
|
||||
position: absolute;
|
||||
content: "";
|
||||
display: block;
|
||||
background-color: white;
|
||||
height: 2px;
|
||||
width: var(--tabs-indkt-width, 0);
|
||||
left: var(--tabs-indkt-offset, 0);
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
import {
|
||||
ParentComponent,
|
||||
createContext,
|
||||
createEffect,
|
||||
createMemo,
|
||||
createRenderEffect,
|
||||
createSignal,
|
||||
useContext,
|
||||
type Signal,
|
||||
} from "solid-js";
|
||||
import { css } from "solid-styled";
|
||||
import "./Tabs.css"
|
||||
|
||||
const TabListContext = /* @__PURE__ */ createContext<{
|
||||
focusOn: Signal<HTMLElement[]>;
|
||||
|
@ -24,7 +22,7 @@ export function useTabListContext() {
|
|||
|
||||
const ANIM_SPEED = 160 / 110; // 160px/110ms
|
||||
|
||||
const TABLIST_FOCUS_CLASS = "tablist-focus";
|
||||
const TABS_FOCUS_CLASS = "Tabs-focus";
|
||||
|
||||
const Tabs: ParentComponent<{
|
||||
offset?: number;
|
||||
|
@ -37,11 +35,11 @@ const Tabs: ParentComponent<{
|
|||
const current = focusOn();
|
||||
if (lastFocusElement) {
|
||||
for (const e of lastFocusElement) {
|
||||
e.classList.remove(TABLIST_FOCUS_CLASS);
|
||||
e.classList.remove(TABS_FOCUS_CLASS);
|
||||
}
|
||||
}
|
||||
for (const e of current) {
|
||||
e.classList.add("tablist-focus");
|
||||
e.classList.add(TABS_FOCUS_CLASS);
|
||||
}
|
||||
return current;
|
||||
});
|
||||
|
@ -109,7 +107,7 @@ const Tabs: ParentComponent<{
|
|||
return ["0px", "0px", "110ms", "110ms"] as const;
|
||||
}
|
||||
const rect = focusBoundingClientRect();
|
||||
const rootRect = self.getBoundingClientRect();
|
||||
const rootRect = self!.getBoundingClientRect();
|
||||
const left = rect.x - rootRect.x;
|
||||
const width = rect.width;
|
||||
const [prevEl, nextEl] = focusSiblings();
|
||||
|
@ -130,32 +128,14 @@ const Tabs: ParentComponent<{
|
|||
return result;
|
||||
};
|
||||
|
||||
css`
|
||||
.tablist {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
|
||||
&::after {
|
||||
transition:
|
||||
left ${indicator()[2]} var(--tutu-anim-curve-std),
|
||||
width ${indicator()[3]} var(--tutu-anim-curve-std);
|
||||
position: absolute;
|
||||
content: "";
|
||||
display: block;
|
||||
background-color: white;
|
||||
height: 2px;
|
||||
width: ${indicator()[1]};
|
||||
left: ${indicator()[0]};
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<TabListContext.Provider value={{ focusOn: [focusOn, setFocusOn] }}>
|
||||
<div ref={self!} class="tablist" role="tablist">
|
||||
<div ref={self!} class="Tabs" style={{
|
||||
"--tabs-indkt-width": indicator()[1],
|
||||
"--tabs-indkt-offset": indicator()[0],
|
||||
"--tabs-indkt-movspeed-offset": indicator()[2],
|
||||
"--tabs-indkt-movspeed-width": indicator()[3]
|
||||
}} role="tablist">
|
||||
{props.children}
|
||||
</div>
|
||||
</TabListContext.Provider>
|
||||
|
|
Loading…
Add table
Reference in a new issue