From 119d51d989b0d33c66e950e732a6113ea221b77b Mon Sep 17 00:00:00 2001 From: Amr Mohammed El-Sheraey <141947355+AmrMsCLL@users.noreply.github.com> Date: Tue, 20 Oct 2026 23:11:02 +0300 Subject: [PATCH] feat: motion across the shell, overlays and controls (1.2.0) --- package-lock.json | 8 +- package.json | 6 +- src/components/AppShell.tsx | 8 +- src/components/Choice.tsx | 9 +- src/components/PageTransition.tsx | 9 ++ src/components/Sidebar.tsx | 14 ++- src/components/Snackbar.tsx | 6 +- src/components/Tabs.tsx | 2 +- src/index.ts | 1 + src/theme.css | 164 +++++++++++++++++++++++++++++- src/theme.ts | 18 +++- 11 files changed, 223 insertions(+), 22 deletions(-) create mode 100644 src/components/PageTransition.tsx diff --git a/package-lock.json b/package-lock.json index ae7edbc..08905c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@project-graphite/ui", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@project-graphite/ui", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "devDependencies": { "@emotion/cache": "11.14.0", @@ -30,8 +30,8 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^9.5.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "react": "^19.3.0", + "react-dom": "^19.3.0" } }, "node_modules/@babel/code-frame": { diff --git a/package.json b/package.json index 91264bb..5f7e453 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@project-graphite/ui", - "version": "1.1.1", + "version": "1.2.0", "description": "Project Graphite design tokens, theme and React components.", "license": "MIT", "repository": { @@ -32,8 +32,8 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^9.5.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "react": "^19.3.0", + "react-dom": "^19.3.0" }, "devDependencies": { "@emotion/cache": "11.14.0", diff --git a/src/components/AppShell.tsx b/src/components/AppShell.tsx index 5c18879..f93f814 100644 --- a/src/components/AppShell.tsx +++ b/src/components/AppShell.tsx @@ -62,6 +62,7 @@ export function AppShell({ }) { const Link = useLink(); const [collapsed, setCollapsed] = useState(storedCollapsed); + const activeTab = tabs.findIndex((tab) => tab.active); const toggle = () => { setCollapsed(!collapsed); storeCollapsed(!collapsed); @@ -73,7 +74,7 @@ export function AppShell({ Skip to content -
+
{sidebar && ( = 0} showLabels - style={{ '--tab-count': tabs.length } as CSSProperties} - value={tabs.find((tab) => tab.active)?.href ?? null} + style={{ '--tab-count': tabs.length, '--tab-index': activeTab } as CSSProperties} + value={tabs[activeTab]?.href ?? null} > {tabs.map((tab) => tab.loading ? ( diff --git a/src/components/Choice.tsx b/src/components/Choice.tsx index 1dde5d0..d36c4e9 100644 --- a/src/components/Choice.tsx +++ b/src/components/Choice.tsx @@ -1,7 +1,7 @@ import MuiCheckbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; import MuiRadio from '@mui/material/Radio'; -import type { InputHTMLAttributes, ReactNode } from 'react'; +import { useState, type InputHTMLAttributes, type ReactNode } from 'react'; type ChoiceProps = Omit, 'size' | 'type'> & { label?: ReactNode }; @@ -18,14 +18,19 @@ function Choice({ ...input }: ChoiceProps & { kind: 'checkbox' | 'radio' }) { const Control = kind === 'checkbox' ? MuiCheckbox : MuiRadio; + const [pressed, setPressed] = useState(false); const control = ( { + setPressed(true); + onChange?.(event); + }} size="small" slotProps={{ input }} value={value} diff --git a/src/components/PageTransition.tsx b/src/components/PageTransition.tsx new file mode 100644 index 0000000..bb2322a --- /dev/null +++ b/src/components/PageTransition.tsx @@ -0,0 +1,9 @@ +import { ViewTransition, type ReactNode } from 'react'; + +export function PageTransition({ children, page }: { children: ReactNode; page: string }) { + return ( + + {children} + + ); +} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 43c79dc..15ad469 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,5 +1,5 @@ import ListItemButton from '@mui/material/ListItemButton'; -import type { ReactNode } from 'react'; +import { useLayoutEffect, useRef, useState, type ReactNode } from 'react'; import { useLink } from '../UiProvider.js'; import { useShell } from './AppShell.js'; import { Icon, type IconName } from './Icon.js'; @@ -36,8 +36,18 @@ export function Sidebar({ }) { const Link = useLink(); const { collapsed } = useShell(); + const nav = useRef(null); + const [current, setCurrent] = useState<{ height: number; top: number }>(); + + useLayoutEffect(() => { + const item = nav.current?.querySelector('.sidebar-item[aria-current="page"]'); + const next = item ? { height: item.offsetHeight, top: item.offsetTop } : undefined; + setCurrent((shown) => (shown && next && shown.top === next.top && shown.height === next.height ? shown : next)); + }, [collapsed, loading, sections]); + return ( -