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
		Add a link
		
	
		Reference in a new issue