From 1273c6a2c550e9acb63e4878c5db1af63eba5c4d Mon Sep 17 00:00:00 2001 From: DeMineArchiver Date: Tue, 5 Nov 2024 22:01:28 +0300 Subject: [PATCH] WIP tabs component (and more) --- apps/docs/package.json | 4 +- apps/docs/src/theme/theme.ts | 9 +- examples/react/package.json | 3 +- examples/react/src/app.tsx | 290 +++++++++++++++++- .../react/src/components/example/index.ts | 0 examples/react/src/main.tsx | 2 +- examples/react/src/theme/theme.ts | 3 +- examples/solid/package.json | 2 +- packages/dom/CHANGELOG.md | 7 + packages/dom/package.json | 4 +- packages/react-utils/CHANGELOG.md | 7 + packages/react-utils/package.json | 4 +- packages/react-utils/src/index.ts | 2 + packages/react-utils/src/is.ts | 33 ++ packages/react/CHANGELOG.md | 10 + packages/react/package.json | 6 +- packages/react/src/avatar/avatar.tsx | 4 +- packages/react/src/button/button.css.ts | 4 +- packages/react/src/button/button.tsx | 24 +- packages/react/src/checkbox/checkbox.css.ts | 3 + packages/react/src/checkbox/checkbox.tsx | 43 +++ packages/react/src/checkbox/index.ts | 1 + packages/react/src/divider/divider.tsx | 4 +- packages/react/src/focus/focus-ring.tsx | 4 +- .../react/src/icon/material-symbol.css.ts | 7 +- packages/react/src/icon/material-symbol.tsx | 2 +- packages/react/src/index.ts | 5 + packages/react/src/list/list-item.tsx | 4 +- packages/react/src/menu/index.ts | 1 + packages/react/src/menu/menu.css.ts | 42 +++ packages/react/src/menu/menu.tsx | 137 +++++++++ packages/react/src/modal/modal.tsx | 12 +- packages/react/src/radio/radio-list-item.tsx | 4 +- packages/react/src/radio/radio.tsx | 4 +- packages/react/src/ripple/ripple.tsx | 12 +- packages/react/src/switch/index.ts | 1 + packages/react/src/tabs/index.ts | 2 + packages/react/src/tabs/tab-bar.css.ts | 23 ++ packages/react/src/tabs/tab-bar.tsx | 183 +++++++++++ packages/react/src/tabs/tab-indicator.css.ts | 21 ++ packages/react/src/tabs/tab-indicator.tsx | 48 +++ packages/react/src/tabs/tab.css.ts | 80 +++++ packages/react/src/tabs/tab.tsx | 86 ++++++ packages/react/src/tooltip/plain-tooltip.tsx | 2 +- packages/solid/CHANGELOG.md | 6 + packages/solid/package.json | 6 +- yarn.lock | 61 ++-- 47 files changed, 1124 insertions(+), 98 deletions(-) create mode 100644 examples/react/src/components/example/index.ts create mode 100644 packages/dom/CHANGELOG.md create mode 100644 packages/react-utils/src/is.ts create mode 100644 packages/react/src/menu/index.ts create mode 100644 packages/react/src/menu/menu.css.ts create mode 100644 packages/react/src/menu/menu.tsx create mode 100644 packages/react/src/tabs/index.ts create mode 100644 packages/react/src/tabs/tab-bar.css.ts create mode 100644 packages/react/src/tabs/tab-bar.tsx create mode 100644 packages/react/src/tabs/tab-indicator.css.ts create mode 100644 packages/react/src/tabs/tab-indicator.tsx create mode 100644 packages/react/src/tabs/tab.css.ts create mode 100644 packages/react/src/tabs/tab.tsx diff --git a/apps/docs/package.json b/apps/docs/package.json index a9929b2..a4edb5e 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -15,7 +15,7 @@ "@fontsource-variable/raleway": "^5.1.0", "@fontsource-variable/roboto-flex": "^5.1.0", "@solidjs/meta": "^0.29.4", - "@solidjs/router": "^0.15.0", + "@solidjs/router": "^0.15.1", "@star4/solid": "workspace:^", "@star4/theme": "workspace:^", "@star4/vanilla-extract": "workspace:^", @@ -26,7 +26,7 @@ }, "devDependencies": { "@star4/config": "workspace:^", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@vanilla-extract/vite-plugin": "^4.0.17", "typescript": "^5.6.3", "vite": "^5.4.10", diff --git a/apps/docs/src/theme/theme.ts b/apps/docs/src/theme/theme.ts index 432828b..1b5d89b 100644 --- a/apps/docs/src/theme/theme.ts +++ b/apps/docs/src/theme/theme.ts @@ -19,10 +19,11 @@ const fontFamily = (...args: FontFamily): string => { const fontSource = (family: string) => [`${family}`, `${family} Variable`]; export const { contract, theme } = createTheme({ - color: { - variant: "expressive", - sourceColor: "#0000ff", - }, + color: {}, + // color: { + // variant: "expressive", + // sourceColor: "#0000ff", + // }, typeface: { plain: fontFamily(fontSource("Roboto Flex"), fontSource("Open Sans"), "Roboto", "system-ui", "Arial", "sans-serif"), brand: fontFamily(fontSource("Raleway"), fontSource("Manrope"), "sans-serif"), diff --git a/examples/react/package.json b/examples/react/package.json index 636133b..8ce5cba 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@fontsource-variable/manrope": "^5.1.0", + "@fontsource-variable/material-symbols-outlined": "^5.1.3", "@fontsource-variable/material-symbols-rounded": "^5.1.3", "@fontsource-variable/material-symbols-sharp": "^5.1.3", "@fontsource-variable/open-sans": "^5.1.0", @@ -27,7 +28,7 @@ }, "devDependencies": { "@star4/config": "workspace:^", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@vanilla-extract/vite-plugin": "^4.0.17", diff --git a/examples/react/src/app.tsx b/examples/react/src/app.tsx index 0b50d1e..9580365 100644 --- a/examples/react/src/app.tsx +++ b/examples/react/src/app.tsx @@ -1,19 +1,289 @@ -import { Dialog, FocusRing, Ripple, Button, Radio, MaterialSymbol, ListItem, Avatar, RadioListItem } from "@star4/react"; -import { forwardRef, useRef, useState, type FC } from "react"; +import { Dialog, FocusRing, Ripple, Button, Radio, MaterialSymbol, ListItem, Avatar, RadioListItem, Menu, usePresence, TabBar, Tab } from "@star4/react"; +import { forwardRef, useRef, useState, type FC, type ReactNode } from "react"; import { THEME } from "~/theme"; -export const App: FC = () => { - const [open, setOpen] = useState(false); +const Example1 = () =>
Hello world!
; + +const MENU_ITEMS = [ + "Apple", + "Apricot", + "Avocado", + "Banana", + "Cucumber", + "Grapes", + "Olive", + "Orange" +]; + + +type ExampleProps = { + headline: ReactNode; + supportingText?: ReactNode; + children?: ReactNode; +} +function Example({ headline, supportingText, children }: ExampleProps) { + return ( +
+
+

+ +

+
+
+
+ ) +} + +function DialogExample() { + const [isOpen, setIsOpen] = useState(false); + return ( + +
+ + ); +} + +function RadioExample() { + return ( + + + + ) +} +function TabsExample() { const [value, setValue] = useState(0); + const [count, setCount] = useState(3); + const [value2, setValue2] = useState(0); + + const tabs: ReactNode[] = []; + for(let i = 0; i < count; i++) { + tabs.push() + } + return ( -
+ + {/* + } + label="Explore" /> + } + label="Travel" /> + } + label="Drums" /> + } + label="Bass" /> + } + label="Saxophone" /> + */} +
+
+ +
+ +{/*
*/} ); } diff --git a/examples/react/src/components/example/index.ts b/examples/react/src/components/example/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/examples/react/src/main.tsx b/examples/react/src/main.tsx index e592062..117a315 100644 --- a/examples/react/src/main.tsx +++ b/examples/react/src/main.tsx @@ -2,7 +2,7 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; -import "@fontsource-variable/material-symbols-rounded/full.css"; +import "@fontsource-variable/material-symbols-outlined/full.css"; import "@fontsource-variable/open-sans"; import "@fontsource-variable/raleway"; diff --git a/examples/react/src/theme/theme.ts b/examples/react/src/theme/theme.ts index a580012..ce3671a 100644 --- a/examples/react/src/theme/theme.ts +++ b/examples/react/src/theme/theme.ts @@ -1,4 +1,3 @@ -import { Hct } from "@star4/theme/material"; import { createTheme } from "@star4/vanilla-extract"; @@ -29,7 +28,7 @@ export const { contract, theme } = createTheme({ }, component: { materialSymbol: { - font: fontFamily("Material Symbols Rounded Variable"), + font: fontFamily("Material Symbols Outlined Variable"), }, } }); diff --git a/examples/solid/package.json b/examples/solid/package.json index 948db86..ff05d53 100644 --- a/examples/solid/package.json +++ b/examples/solid/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@star4/config": "workspace:^", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@vanilla-extract/vite-plugin": "^4.0.17", "typescript": "^5.6.3", "vite": "^5.4.10", diff --git a/packages/dom/CHANGELOG.md b/packages/dom/CHANGELOG.md new file mode 100644 index 0000000..45297bc --- /dev/null +++ b/packages/dom/CHANGELOG.md @@ -0,0 +1,7 @@ +# @star4/dom + +## 0.0.2 + +### Patch Changes + +- Update dependencies diff --git a/packages/dom/package.json b/packages/dom/package.json index 01ae2d1..95cf742 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@star4/dom", - "version": "0.0.1", + "version": "0.0.2", "publishConfig": { "access": "public" }, @@ -39,7 +39,7 @@ }, "devDependencies": { "@star4/config": "workspace:^", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "tsup": "^8.3.5", "typescript": "^5.6.3" }, diff --git a/packages/react-utils/CHANGELOG.md b/packages/react-utils/CHANGELOG.md index c762ec9..bceaea9 100644 --- a/packages/react-utils/CHANGELOG.md +++ b/packages/react-utils/CHANGELOG.md @@ -1,5 +1,12 @@ # @star4/react-utils +## 0.0.5 + +### Patch Changes + +- Implement createIdentifiableElement helper +- Update dependencies + ## 0.0.4 ### Patch Changes diff --git a/packages/react-utils/package.json b/packages/react-utils/package.json index c000a89..53084b9 100644 --- a/packages/react-utils/package.json +++ b/packages/react-utils/package.json @@ -1,6 +1,6 @@ { "name": "@star4/react-utils", - "version": "0.0.4", + "version": "0.0.5", "publishConfig": { "access": "public" }, @@ -39,7 +39,7 @@ }, "devDependencies": { "@star4/config": "workspace:^", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "tsup": "^8.3.5", diff --git a/packages/react-utils/src/index.ts b/packages/react-utils/src/index.ts index cf18157..e605edd 100644 --- a/packages/react-utils/src/index.ts +++ b/packages/react-utils/src/index.ts @@ -4,3 +4,5 @@ export * from "./use-media-query"; export * from "./use-presence"; export type * from "./types"; + +export * from "./is"; diff --git a/packages/react-utils/src/is.ts b/packages/react-utils/src/is.ts new file mode 100644 index 0000000..0bed96b --- /dev/null +++ b/packages/react-utils/src/is.ts @@ -0,0 +1,33 @@ +import { isValidElement, type JSXElementConstructor, type ReactElement, type ReactNode } from "react"; + +export const isFactory = (key: Key, is: (value: Value) => boolean) => { + return (node: ReactNode): node is ReactElement

=> { + if(!isValidElement(node)) return false; + const type = node.type; + return typeof type !== "string" && + key in type && + is((type as JSXElementConstructor & { [K in Key]: Value })[key]); + }; +} + +const IS_FALLBACK: unique symbol = Symbol("IS_FALLBACK"); + +export type IdentifiableComponent

= { + is: (node: ReactNode) => node is ReactElement

; +} + +export const createIdentifiableElement =

( + description?: string | number, +): IdentifiableComponent

=> { + const IS = Symbol(description); + return { + [IS]: true, + is: (node: ReactNode): node is ReactElement

=> { + if(!isValidElement(node)) return false; + const type = node.type; + return typeof type !== "string" && + IS in type && + type[IS] === true; + }, + } as IdentifiableComponent

; +} diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 2578a77..5411973 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,15 @@ # @star4/react +## 0.0.17 + +### Patch Changes + +- WIP tabs component +- Update dependencies +- Updated dependencies +- Updated dependencies + - @star4/react-utils@0.0.5 + ## 0.0.16 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index a8ce50c..0799c04 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@star4/react", - "version": "0.0.16", + "version": "0.0.17", "publishConfig": { "access": "public" }, @@ -39,7 +39,7 @@ }, "devDependencies": { "@star4/config": "workspace:^", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "tsup": "^8.3.5", @@ -54,7 +54,7 @@ "@vanilla-extract/dynamic": "^2.1.2", "@vanilla-extract/recipes": "^0.5.5", "clsx": "^2.1.1", - "lenis": "^1.1.14", + "lenis": "^1.1.15", "react": "^18.3.1", "react-dom": "^18.3.1" } diff --git a/packages/react/src/avatar/avatar.tsx b/packages/react/src/avatar/avatar.tsx index 3e599d9..0b1e9d0 100644 --- a/packages/react/src/avatar/avatar.tsx +++ b/packages/react/src/avatar/avatar.tsx @@ -54,7 +54,7 @@ export namespace Avatar { * ``` */ export const Avatar = forwardRef( - ( + function Avatar( { type, className, @@ -62,7 +62,7 @@ export const Avatar = forwardRef( ...rest }, forwardedRef, - ) => { + ) { const ref = useRef(null); useImperativeHandle( forwardedRef, diff --git a/packages/react/src/button/button.css.ts b/packages/react/src/button/button.css.ts index 0bd075d..aace39d 100644 --- a/packages/react/src/button/button.css.ts +++ b/packages/react/src/button/button.css.ts @@ -210,7 +210,9 @@ const outline = recipe({ }, variants: { disabled: { - borderColor: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 12%)`, + true: { + borderColor: `color-mix(in srgb, transparent, ${THEME.color.onSurface} 12%)`, + } }, }, }); diff --git a/packages/react/src/button/button.tsx b/packages/react/src/button/button.tsx index ca0907b..4491104 100644 --- a/packages/react/src/button/button.tsx +++ b/packages/react/src/button/button.tsx @@ -1,8 +1,11 @@ -import { forwardRef, useImperativeHandle, useRef, type ButtonHTMLAttributes, type ReactNode } from "react"; +import { forwardRef, isValidElement, useImperativeHandle, useRef, type ButtonHTMLAttributes, type ReactElement, type ReactNode } from "react"; import { FocusRing } from "../focus"; import { Ripple } from "../ripple"; import clsx from "clsx"; import { styles } from "./button.css"; +import { createIdentifiableElement } from "@star4/react-utils"; + +export const IS_BUTTON = Symbol("button"); export namespace Button { export type Variant = "elevated" | "filled" | "filledTonal" | "outlined" | "text"; @@ -19,8 +22,8 @@ export namespace Button { export interface Element extends HTMLButtonElement {} } -export const Button = forwardRef( - ( +const Component = forwardRef( + function Button( { className, disabled, @@ -30,7 +33,7 @@ export const Button = forwardRef( ...rest }, forwardedRef, - ) => { + ) { const ref = useRef(null); useImperativeHandle( forwardedRef, @@ -54,16 +57,17 @@ export const Button = forwardRef( {variant === "outlined" && (

)} - {icon && ( -
- {icon} -
- )} + {icon} {label} ) }, ); + +export const Button = Object.assign( + Component, + createIdentifiableElement("IS_BUTTON"), +); diff --git a/packages/react/src/checkbox/checkbox.css.ts b/packages/react/src/checkbox/checkbox.css.ts index e69de29..4e2d5cb 100644 --- a/packages/react/src/checkbox/checkbox.css.ts +++ b/packages/react/src/checkbox/checkbox.css.ts @@ -0,0 +1,3 @@ +export const styles = { + +} as const; diff --git a/packages/react/src/checkbox/checkbox.tsx b/packages/react/src/checkbox/checkbox.tsx index e69de29..c797d90 100644 --- a/packages/react/src/checkbox/checkbox.tsx +++ b/packages/react/src/checkbox/checkbox.tsx @@ -0,0 +1,43 @@ +import { forwardRef, useEffect, useRef, type ChangeEventHandler, type FormEventHandler, type HTMLAttributes } from "react"; + +export namespace Checkbox { + export type Props = + & Omit< + HTMLAttributes, + "children" + > + & { + checked?: boolean; + required?: boolean; + onChange?: ChangeEventHandler; + onInput?: FormEventHandler; + } + + export interface Element extends HTMLElement {} +} + +export const Checkbox = forwardRef( + ( + { + checked = false, + }, + forwardedRef, + ) => { + const inputRef = useRef(null); + + useEffect(() => { + const input = inputRef.current; + if(!input) return; + input.checked = checked; + }, [checked]); + + return ( +
+ +
+ ); + }, +); diff --git a/packages/react/src/checkbox/index.ts b/packages/react/src/checkbox/index.ts index e69de29..057f167 100644 --- a/packages/react/src/checkbox/index.ts +++ b/packages/react/src/checkbox/index.ts @@ -0,0 +1 @@ +export * from "./checkbox"; diff --git a/packages/react/src/divider/divider.tsx b/packages/react/src/divider/divider.tsx index 91f71f6..f625943 100644 --- a/packages/react/src/divider/divider.tsx +++ b/packages/react/src/divider/divider.tsx @@ -15,13 +15,13 @@ export namespace Divider { } export const Divider = forwardRef( - ( + function Divider( { className, ...rest }, forwardedRef, - ) => { + ) { return (
} diff --git a/packages/react/src/focus/focus-ring.tsx b/packages/react/src/focus/focus-ring.tsx index afe79d9..7f1318b 100644 --- a/packages/react/src/focus/focus-ring.tsx +++ b/packages/react/src/focus/focus-ring.tsx @@ -26,14 +26,14 @@ export namespace FocusRing { } export const FocusRing = forwardRef( - ( + function FocusRing( { for: target, className, ...rest }, forwardedRef, - ) => { + ) { const visible = useFocusVisible(target); return ( diff --git a/packages/react/src/icon/material-symbol.css.ts b/packages/react/src/icon/material-symbol.css.ts index f0c5ccf..f58e893 100644 --- a/packages/react/src/icon/material-symbol.css.ts +++ b/packages/react/src/icon/material-symbol.css.ts @@ -8,8 +8,11 @@ const fontVariationSettings = (values: Record) => { } const icon = style({ - fontFamily: fallbackVar(THEME.component.materialSymbol.font, `"Material Symbols Outlined"`), fontSize: fallbackVar(THEME.component.icon.size, "24px"), + inlineSize: fallbackVar(THEME.component.icon.size, "24px"), + blockSize: fallbackVar(THEME.component.icon.size, "24px"), + + fontFamily: fallbackVar(THEME.component.materialSymbol.font, `"Material Symbols Outlined"`), fontWeight: "normal", fontStyle: "normal", @@ -27,8 +30,6 @@ const icon = style({ color: "currentcolor", - inlineSize: fallbackVar(THEME.component.icon.size, "24px"), - blockSize: fallbackVar(THEME.component.icon.size, "24px"), userSelect: "none", transitionProperty: "font-variation-settings", diff --git a/packages/react/src/icon/material-symbol.tsx b/packages/react/src/icon/material-symbol.tsx index 51ae599..b04679f 100644 --- a/packages/react/src/icon/material-symbol.tsx +++ b/packages/react/src/icon/material-symbol.tsx @@ -26,7 +26,7 @@ export namespace MaterialSymbol { * @see {@link https://m3.material.io/styles/icons/overview|Icons - Material Design 3} */ export const MaterialSymbol = forwardRef( - ({ name, className, "aria-hidden": ariaHidden, ...rest }, forwardedRef) => { + function MaterialSymbol({ name, className, "aria-hidden": ariaHidden, ...rest }, forwardedRef) { return ( ( - ( + function ListItem( { selected = false, multiline, @@ -63,7 +63,7 @@ export const ListItem = forwardRef( ...rest }, forwardedRef, - ) => { + ) { const ref = useRef(null); useImperativeHandle( forwardedRef, diff --git a/packages/react/src/menu/index.ts b/packages/react/src/menu/index.ts new file mode 100644 index 0000000..4fbc74d --- /dev/null +++ b/packages/react/src/menu/index.ts @@ -0,0 +1 @@ +export * from "./menu"; diff --git a/packages/react/src/menu/menu.css.ts b/packages/react/src/menu/menu.css.ts new file mode 100644 index 0000000..f796825 --- /dev/null +++ b/packages/react/src/menu/menu.css.ts @@ -0,0 +1,42 @@ +import { THEME } from "@star4/vanilla-extract"; +import { recipe } from "@vanilla-extract/recipes"; + +const container = recipe({ + base: { + position: "relative", + minWidth: 112, + width: "fit-content", + maxWidth: 280, + + backgroundColor: THEME.color.surfaceContainer, + borderRadius: THEME.shape.corner.medium, + }, + variants: { + entering: { + true: { + + }, + }, + exiting: { + true: { + height: 0, + }, + }, + }, +}); + +const items = recipe({ + base: { + display: "flex", + flexDirection: "column", + alignItems: "stretch", + + borderRadius: "inherit", + overflow: "hidden", + } +}); + +export const styles = { + container, + items, +} as const; diff --git a/packages/react/src/menu/menu.tsx b/packages/react/src/menu/menu.tsx new file mode 100644 index 0000000..4aa2298 --- /dev/null +++ b/packages/react/src/menu/menu.tsx @@ -0,0 +1,137 @@ +import { Children, createContext, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, type ReactNode } from "react"; +import { Button, IS_BUTTON } from "../button"; +import { createIdentifiableElement, usePresence } from "@star4/react-utils"; +import { Ripple } from "../ripple"; +import { FocusRing } from "../focus"; +import { styles } from "./menu.css"; + +export namespace Menu { + export type Props = { + open?: boolean; + children: ReactNode; + } + + export interface Element extends HTMLElement {} +} + +type InternalMenuData = { + +} + +const InternalMenuContext = createContext(undefined); +const MenuComponent = forwardRef( + function Menu( + { + open = false, + children + }, + forwardedRef, + ) { + const items = Children.toArray(children) + .filter((node, index) => { + const is = MenuItem.is(node); + if(!is) { + console.warn( + "Invalid JSX Element passed to token resolver:", + node, + ); + } + return is; + }); + const ref = useRef(null); + const listRef = useRef(null); + + const {} = usePresence({ + source: open, + transitionDuration: [500, 150], + }); + + const [height, setHeight] = useState(); + + const resizeObserver = new ResizeObserver( + (entries) => { + const entry = entries[0]; + const element = entry.target as HTMLElement; + const height = element.offsetHeight; + setHeight(height); + } + ); + + useEffect( + () => { + const element = listRef.current; + if(!element) return; + + resizeObserver.observe(element); + return () => { + resizeObserver.unobserve(element); + }; + }, + [], + ); + + return ( +
+
+ + {items} + +
+
+ ) + }, +); + + +export namespace Menu { + export namespace Item { + export type Props = { + headline: ReactNode; + } + export interface Element extends HTMLElement {} + } +} + +const MenuItemComponent = forwardRef( + function MenuItem( + { headline }, + forwardedRef, + ) { + const context = useContext(InternalMenuContext); + if(!context) { + console.warn( + "[star4]: Menu context not found. Make sure to wrap Menu components in . This component will not render." + ); + return; + } + const {} = context; + + const ref = useRef(null); + useImperativeHandle( + forwardedRef, + () => ref.current!, + [], + ); + + return ( + + ) + }, +); + +const MenuItem = Object.assign( + MenuItemComponent, + createIdentifiableElement("IS_MENU_ITEM"), +); + +export const Menu = Object.assign( + MenuComponent, + { + Item: MenuItem, + ...createIdentifiableElement("IS_MENU"), + }, +); diff --git a/packages/react/src/modal/modal.tsx b/packages/react/src/modal/modal.tsx index 7b7c67a..c878558 100644 --- a/packages/react/src/modal/modal.tsx +++ b/packages/react/src/modal/modal.tsx @@ -27,7 +27,7 @@ const InternalModalContext = createContext const useInternalModalContext = () => useContext(InternalModalContext); const NativeModal = forwardRef( - ( + function Modal( { className, open = false, @@ -36,7 +36,7 @@ const NativeModal = forwardRef( ...rest }, forwardedRef, - ) => { + ) { const ref = useRef(null); useImperativeHandle( forwardedRef, @@ -82,7 +82,7 @@ const NativeModal = forwardRef( ); const PortalModal = forwardRef( - ( + function Modal( { className, open = false, @@ -91,7 +91,7 @@ const PortalModal = forwardRef( ...rest }, forwardedRef - ) => { + ) { const ref = useRef(null); useImperativeHandle( forwardedRef, @@ -137,13 +137,13 @@ export namespace Modal { } const Backdrop = forwardRef( - ( + function ModalBackdrop( { className, ...rest }, forwardedRef, - ) => { + ) { const { isOpen, close } = useInternalModalContext()!; return ( diff --git a/packages/react/src/radio/radio-list-item.tsx b/packages/react/src/radio/radio-list-item.tsx index b1c8f1b..08b8cd4 100644 --- a/packages/react/src/radio/radio-list-item.tsx +++ b/packages/react/src/radio/radio-list-item.tsx @@ -16,7 +16,7 @@ export namespace RadioListItem { } export const RadioListItem = forwardRef>( - ( + function RadioListItem( { checked, groupValue, @@ -28,7 +28,7 @@ export const RadioListItem = forwardRef { + ) { const id = useId(); const manual = useMemo(() => checked !== undefined, [checked]); const isChecked = useMemo(() => manual ? checked : value === groupValue, [manual, checked, value, groupValue]); diff --git a/packages/react/src/radio/radio.tsx b/packages/react/src/radio/radio.tsx index 2396755..c290815 100644 --- a/packages/react/src/radio/radio.tsx +++ b/packages/react/src/radio/radio.tsx @@ -136,7 +136,7 @@ export namespace Radio { * ``` */ export const Radio = forwardRef>( - ( + function Radio( { className, checked, @@ -147,7 +147,7 @@ export const Radio = forwardRef>( ...rest }, forwardedRef, - ) => { + ) { const ref = useRef(null); useImperativeHandle( forwardedRef, diff --git a/packages/react/src/ripple/ripple.tsx b/packages/react/src/ripple/ripple.tsx index 073ab2e..bccbb19 100644 --- a/packages/react/src/ripple/ripple.tsx +++ b/packages/react/src/ripple/ripple.tsx @@ -35,7 +35,7 @@ export namespace Ripple { } export const Ripple = forwardRef( - ( + function Ripple( { for: target, className, @@ -43,7 +43,7 @@ export const Ripple = forwardRef( ...rest }, forwardedRef, - ) => { + ) { const ref = useRef(null); const surfaceRef = useRef(null); @@ -286,7 +286,11 @@ export const Ripple = forwardRef( useEffect( () => { - if(!target.current || forcedColors) return; + if(!target.current || disabled || forcedColors) { + setHovered(false); + setPressed(false); + return; + } const element = target.current; @@ -308,7 +312,7 @@ export const Ripple = forwardRef( element.removeEventListener("contextmenu", onContextmenu); }; }, - [target, forcedColors], + [target, disabled, forcedColors], ); return ( diff --git a/packages/react/src/switch/index.ts b/packages/react/src/switch/index.ts index e69de29..7c69fd9 100644 --- a/packages/react/src/switch/index.ts +++ b/packages/react/src/switch/index.ts @@ -0,0 +1 @@ +export * from "./switch"; diff --git a/packages/react/src/tabs/index.ts b/packages/react/src/tabs/index.ts new file mode 100644 index 0000000..3878973 --- /dev/null +++ b/packages/react/src/tabs/index.ts @@ -0,0 +1,2 @@ +export { TabBar } from "./tab-bar"; +export { Tab } from "./tab"; diff --git a/packages/react/src/tabs/tab-bar.css.ts b/packages/react/src/tabs/tab-bar.css.ts new file mode 100644 index 0000000..be72384 --- /dev/null +++ b/packages/react/src/tabs/tab-bar.css.ts @@ -0,0 +1,23 @@ +import { THEME } from "@star4/vanilla-extract"; +import { recipe } from "@vanilla-extract/recipes"; + +const container = recipe({ + base: { + position: "relative", + height: 48, + + display: "grid", + gridAutoFlow: "column", + gridAutoColumns: "1fr", + + backgroundColor: THEME.color.secondaryContainer, + borderRadius: THEME.shape.corner.full, + isolation: "isolate", + + userSelect: "none", + } +}); + +export const styles = { + container, +} as const; diff --git a/packages/react/src/tabs/tab-bar.tsx b/packages/react/src/tabs/tab-bar.tsx new file mode 100644 index 0000000..3b883fb --- /dev/null +++ b/packages/react/src/tabs/tab-bar.tsx @@ -0,0 +1,183 @@ +import { createIdentifiableElement, type ComposableForwardRefExoticComponent, type ForwardRefExoticComponentProps } from "@star4/react-utils"; +import { Children, cloneElement, createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState, type HTMLAttributes, type ReactNode } from "react"; +import { Tab } from "./tab"; +import { styles } from "./tab-bar.css"; + +import clsx from "clsx/lite"; +import { TabIndicator } from "./tab-indicator"; + +export namespace TabBar { + export type Props = + & Omit< + HTMLAttributes, + "role" | "children" + > + & { + value: T; + onValueChange?: (value: T) => void; + children: ReactNode; + }; + + export type Value = string | number | symbol; + + export interface Element extends HTMLElement {} +} + +type InternalTabBarContext = { + index: number; + isSelected: (value: TabBar.Value) => boolean; + setSelected: (value: TabBar.Value) => void; +} + +const InternalTabBarContext = createContext(undefined); +export const useInternalTabBarContext = () => { + const context = useContext(InternalTabBarContext); + if(!context) { + throw new Error( + "[star4]: TabBar context not found. Make sure to wrap Tab components in ." + ); + } + return context; +} + +const TabBarComponent = forwardRef>( + function TabBar( + { + className, + value, + onValueChange, + children, + ...rest + }, + forwardedRef, + ) { + const indicatorRef = useRef(null); + // const refs = useRef([]); + // const [refs, setRefs] = useState<(Tab.Element | undefined)[]>([]); + // const [refs, setRefs] = useState(new Map()); + // const [refs, setRefs] = useState(new Map()); + // const onTabChange = useCallback( + // (newElement: Tab.Element | null, index: number) => { + // setRefs(refs => { + // if(newElement == null) refs.delete(index); + // else refs.set(index, newElement); + // return new Map(refs); + // }); + // }, + // [] + // ); + const tabs = useMemo( + () => Children.toArray(children) + .filter(node => { + const is = Tab.is(node); + if(!is) { + console.warn( + "Invalid JSX Element passed to token resolver:", + node, + ); + } + return is; + }) + .map((tab, index) => cloneElement>( + tab, + { + // ref: (newElement) => { + // //* Map version + // // onTabChange(newElement, index); + + // //* useRef version + // // const elements = refs.current; + // // if(!elements) return; + // // if(newElement == null) { // Delete ref if it is gone + // // delete elements[index]; + // // } else { // Update ref + // // elements[index] = newElement; + // // } + + // //* useState version + // // setRefs( + // // elements => elements + // // .map((element, i) => { + // // if(i === index) { + // // return newElement == null ? undefined : newElement; + // // } else return element; + // // }) + // // ); + // }, + }, + )) + .map( + (children, index) => ( + value === other, + setSelected: (value) => onValueChange?.(value), + }} + children={children} /> + ) + ), + [children] + ); + + // const selectedIndex = useMemo( + // () => { + // return refs.entries().find( + // ([index, element]) => element.value = "" + // ) + // } + // ); + + const [rects, setRects] = useState([]); + const resizeObserver = new ResizeObserver( + (entries) => { + const rects = entries.map(entry => entry.target.getBoundingClientRect()); + setRects(rects); + }, + ); + + useEffect( + () => { + // const selected = refs.get(); + // if(!selected) return; + // resizeObserver.observe() + }, + [], + ); + + const context = useMemo( + () => ({ + index: 0, + isSelected: (other) => value === other, + setSelected: (value) => onValueChange?.(value), + }), + [value], + ); + + return ( +
+ + + {tabs} + +
+ ); + }, +) as ComposableForwardRefExoticComponent< + ExoticProps, + (props: ExoticProps) => ReactNode +>; + +type ExoticProps = ForwardRefExoticComponentProps>; + +export const TabBar = Object.assign( + TabBarComponent, + createIdentifiableElement>("IS_TAB_BAR"), +); diff --git a/packages/react/src/tabs/tab-indicator.css.ts b/packages/react/src/tabs/tab-indicator.css.ts new file mode 100644 index 0000000..3e2919f --- /dev/null +++ b/packages/react/src/tabs/tab-indicator.css.ts @@ -0,0 +1,21 @@ +import { THEME } from "@star4/vanilla-extract"; +import { style } from "@vanilla-extract/css"; + +const container = style({ + position: "absolute", + inset: 0, + zIndex: -1, +}); + +const indicator = style({ + position: "absolute", + inset: 4, + + borderRadius: THEME.shape.corner.full, + backgroundColor: THEME.color.onSecondaryContainer, +}); + +export const styles = { + container, + indicator, +} as const; diff --git a/packages/react/src/tabs/tab-indicator.tsx b/packages/react/src/tabs/tab-indicator.tsx new file mode 100644 index 0000000..2df2532 --- /dev/null +++ b/packages/react/src/tabs/tab-indicator.tsx @@ -0,0 +1,48 @@ +import { splitProps, type Component, type JSX, type Ref } from "solid-js"; +import clsx from "clsx/lite"; +import { styles } from "./tab-indicator.css"; +import { forwardRef, type ForwardedRef, type HTMLAttributes } from "react"; + +export namespace TabIndicator { + export type Props = + & Omit< + HTMLAttributes, + "children" + >; + + export interface Element extends HTMLElement {} +} + +export const TabIndicator = forwardRef( + function TabIndicator({ className, ...rest }, forwardedRef) { + return ( +
} + className={clsx( + styles.container, + className, + )} + {...rest}> +
+
+ ); + } +); + +// export const TabIndicator: Component = (props) => { +// const [local, others] = splitProps( +// props, +// ["ref", "class"] +// ) +// return ( +//
+//
+//
+// ); +// } diff --git a/packages/react/src/tabs/tab.css.ts b/packages/react/src/tabs/tab.css.ts new file mode 100644 index 0000000..f6b60a2 --- /dev/null +++ b/packages/react/src/tabs/tab.css.ts @@ -0,0 +1,80 @@ +import { THEME } from "@star4/vanilla-extract"; +import { style } from "@vanilla-extract/css"; +import { recipe } from "@vanilla-extract/recipes"; + +const container = recipe({ + base: { + WebkitTapHighlightColor: "transparent", + background: "transparent", + outline: "none", + border: "none", + + position: "relative", + + minWidth: "fit-content", + display: "flex", + alignItems: "center", + justifyContent: "center", + paddingInline: 24, + + borderRadius: THEME.shape.corner.full, + }, + variants: { + selected: { + false: { + cursor: "pointer", + }, + true: { + pointerEvents: "none", + }, + } + }, + defaultVariants: { + selected: false, + }, +}); + +const content = recipe({ + base: { + display: "flex", + alignItems: "center", + justifyContent: "center", + gap: 8, + ...THEME.typescale.title.small, + + textWrap: "nowrap", + + transitionProperty: "color, font-variation-settings", + transitionDuration: THEME.motion.duration.long2, + transitionTimingFunction: THEME.motion.easing.emphasized, + }, + variants: { + selected: { + false: { + color: THEME.color.onSecondaryContainer, + vars: { + [THEME.component.materialSymbol.fill]: "0", + }, + }, + true: { + color: THEME.color.secondaryContainer, + + vars: { + [THEME.component.materialSymbol.fill]: "1", + }, + }, + } + }, +}); +const stateLayer = style({ + inset: 4, + vars: { + [THEME.component.ripple.hoverColor]: THEME.color.onSecondaryContainer, + [THEME.component.ripple.pressedColor]: THEME.color.onSecondaryContainer, + }, +}); +export const styles = { + container, + content, + stateLayer, +} as const; diff --git a/packages/react/src/tabs/tab.tsx b/packages/react/src/tabs/tab.tsx new file mode 100644 index 0000000..45880b3 --- /dev/null +++ b/packages/react/src/tabs/tab.tsx @@ -0,0 +1,86 @@ +import { createIdentifiableElement, type ComposableForwardRefExoticComponent, type ForwardRefExoticComponentProps } from "@star4/react-utils"; +import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, type ButtonHTMLAttributes, type ReactNode } from "react"; +import clsx from "clsx/lite"; +import { Ripple } from "../ripple"; +import { FocusRing } from "../focus"; +import { useInternalTabBarContext, type TabBar } from "./tab-bar"; +import { styles } from "./tab.css"; + +export namespace Tab { + export type Props = + & Omit< + ButtonHTMLAttributes, + "role" | "children" + > + & { + value: T; + icon?: ReactNode; + label: ReactNode; + }; + export type PropsWithRef = ForwardRefExoticComponentProps>; + export type Value = TabBar.Value; + export interface Element extends HTMLButtonElement {} +} +const TabComponent = forwardRef>( + function Tab( + { + className, + onClick, + value, + icon, + label, + ...rest + }, + forwardedRef, + ) { + const { isSelected, setSelected } = useInternalTabBarContext(); + + + const ref = useRef(null); + useImperativeHandle( + forwardedRef, + () => ref.current!, + [], + ); + + const selected = useMemo(() => isSelected(value), [value, isSelected]); + + + useEffect( + () => { + + }, + [], + ); + + return ( + + ) + }, +) as ComposableForwardRefExoticComponent< + Tab.PropsWithRef, + (props: Tab.PropsWithRef) => ReactNode +>; + +export const Tab = Object.assign( + TabComponent, + createIdentifiableElement>("IS_TAB"), +); diff --git a/packages/react/src/tooltip/plain-tooltip.tsx b/packages/react/src/tooltip/plain-tooltip.tsx index a1b1c31..6e1aa20 100644 --- a/packages/react/src/tooltip/plain-tooltip.tsx +++ b/packages/react/src/tooltip/plain-tooltip.tsx @@ -43,7 +43,7 @@ export const PlainTooltip = forwardRef< PlainTooltip.Element, PlainTooltip.Props >( - ({}, forwardedRef) => { + function PlainTooltip({}, forwardedRef) { const [isOpen, setIsOpen] = useState(false); const { isMounted, isVisible } = usePresence({ source: isOpen, diff --git a/packages/solid/CHANGELOG.md b/packages/solid/CHANGELOG.md index c775f53..939c5a1 100644 --- a/packages/solid/CHANGELOG.md +++ b/packages/solid/CHANGELOG.md @@ -1,5 +1,11 @@ # @star4/solid +## 0.0.11 + +### Patch Changes + +- Update dependencies + ## 0.0.10 ### Patch Changes diff --git a/packages/solid/package.json b/packages/solid/package.json index 9464dd0..f00dfa6 100644 --- a/packages/solid/package.json +++ b/packages/solid/package.json @@ -1,6 +1,6 @@ { "name": "@star4/solid", - "version": "0.0.10", + "version": "0.0.11", "publishConfig": { "access": "public" }, @@ -39,7 +39,7 @@ }, "devDependencies": { "@star4/config": "workspace:^", - "@types/node": "^22.8.6", + "@types/node": "^22.9.0", "esbuild-plugin-solid": "^0.6.0", "tsup": "^8.3.5", "typescript": "^5.6.3" @@ -66,7 +66,7 @@ "@vanilla-extract/dynamic": "^2.1.2", "@vanilla-extract/recipes": "^0.5.5", "clsx": "^2.1.1", - "lenis": "^1.1.14", + "lenis": "^1.1.15", "solid-js": "^1.9.3" } } diff --git a/yarn.lock b/yarn.lock index a397ffe..6c7d2ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -605,13 +605,6 @@ __metadata: languageName: node linkType: hard -"@darkroom.engineering/tempus@npm:^0.0.46": - version: 0.0.46 - resolution: "@darkroom.engineering/tempus@npm:0.0.46" - checksum: 10c0/20c48ff5b6a1a0dc1b9af253de3b06ac7d66c6ffefa86a0b2efe06f2a9a96135fd1e7b7ac72e8d347489564521e8ac7aa12e13cb60a1ffd0908cca78b764c584 - languageName: node - linkType: hard - "@emotion/hash@npm:^0.9.0": version: 0.9.2 resolution: "@emotion/hash@npm:0.9.2" @@ -1175,6 +1168,13 @@ __metadata: languageName: node linkType: hard +"@fontsource-variable/material-symbols-outlined@npm:^5.1.3": + version: 5.1.3 + resolution: "@fontsource-variable/material-symbols-outlined@npm:5.1.3" + checksum: 10c0/728f3b2f0a88640ab467b406fc78a06b61dbae0811c8fa8645a65f1a4480d0a2b2cf3d769486187af114fab9ef78ae65ed501a85fa939df8e95e8edec4433685 + languageName: node + linkType: hard + "@fontsource-variable/material-symbols-rounded@npm:^5.1.3": version: 5.1.3 resolution: "@fontsource-variable/material-symbols-rounded@npm:5.1.3" @@ -1654,12 +1654,12 @@ __metadata: languageName: node linkType: hard -"@solidjs/router@npm:^0.15.0": - version: 0.15.0 - resolution: "@solidjs/router@npm:0.15.0" +"@solidjs/router@npm:^0.15.1": + version: 0.15.1 + resolution: "@solidjs/router@npm:0.15.1" peerDependencies: solid-js: ^1.8.6 - checksum: 10c0/1d1b92c89823aeb1ab9075a66ede739c0e17e29457446122897788691398e070e9e8f00c033b15d7ea346b11af1951451cc29c63d94c8184750757eb959c0a1d + checksum: 10c0/0170e58f70c4157b48935de85c766ed4033e907887022954b1eaf0ab5b2fb7b02e0bd68e2e92341810216a40952de66350d05a641a862c3dc157747a2304c466 languageName: node linkType: hard @@ -1683,12 +1683,12 @@ __metadata: "@fontsource-variable/raleway": "npm:^5.1.0" "@fontsource-variable/roboto-flex": "npm:^5.1.0" "@solidjs/meta": "npm:^0.29.4" - "@solidjs/router": "npm:^0.15.0" + "@solidjs/router": "npm:^0.15.1" "@star4/config": "workspace:^" "@star4/solid": "workspace:^" "@star4/theme": "workspace:^" "@star4/vanilla-extract": "workspace:^" - "@types/node": "npm:^22.8.6" + "@types/node": "npm:^22.9.0" "@vanilla-extract/css": "npm:^1.16.0" "@vanilla-extract/dynamic": "npm:^2.1.2" "@vanilla-extract/recipes": "npm:^0.5.5" @@ -1706,7 +1706,7 @@ __metadata: dependencies: "@floating-ui/dom": "npm:^1.6.12" "@star4/config": "workspace:^" - "@types/node": "npm:^22.8.6" + "@types/node": "npm:^22.9.0" clsx: "npm:^2.1.1" tsup: "npm:^8.3.5" typescript: "npm:^5.6.3" @@ -1718,6 +1718,7 @@ __metadata: resolution: "@star4/example-react@workspace:examples/react" dependencies: "@fontsource-variable/manrope": "npm:^5.1.0" + "@fontsource-variable/material-symbols-outlined": "npm:^5.1.3" "@fontsource-variable/material-symbols-rounded": "npm:^5.1.3" "@fontsource-variable/material-symbols-sharp": "npm:^5.1.3" "@fontsource-variable/open-sans": "npm:^5.1.0" @@ -1727,7 +1728,7 @@ __metadata: "@star4/react": "workspace:^" "@star4/theme": "workspace:^" "@star4/vanilla-extract": "workspace:^" - "@types/node": "npm:^22.8.6" + "@types/node": "npm:^22.9.0" "@types/react": "npm:^18.3.12" "@types/react-dom": "npm:^18.3.1" "@vanilla-extract/css": "npm:^1.16.0" @@ -1756,7 +1757,7 @@ __metadata: "@star4/solid": "workspace:^" "@star4/theme": "workspace:^" "@star4/vanilla-extract": "workspace:^" - "@types/node": "npm:^22.8.6" + "@types/node": "npm:^22.9.0" "@vanilla-extract/css": "npm:^1.16.0" "@vanilla-extract/dynamic": "npm:^2.1.2" "@vanilla-extract/recipes": "npm:^0.5.5" @@ -1785,7 +1786,7 @@ __metadata: "@floating-ui/dom": "npm:^1.6.12" "@star4/config": "workspace:^" "@star4/vanilla-extract": "workspace:^" - "@types/node": "npm:^22.8.6" + "@types/node": "npm:^22.9.0" "@types/react": "npm:^18.3.12" "@types/react-dom": "npm:^18.3.1" clsx: "npm:^2.1.1" @@ -1805,14 +1806,14 @@ __metadata: "@star4/config": "workspace:^" "@star4/react-utils": "workspace:^" "@star4/vanilla-extract": "workspace:^" - "@types/node": "npm:^22.8.6" + "@types/node": "npm:^22.9.0" "@types/react": "npm:^18.3.12" "@types/react-dom": "npm:^18.3.1" "@vanilla-extract/css": "npm:^1.16.0" "@vanilla-extract/dynamic": "npm:^2.1.2" "@vanilla-extract/recipes": "npm:^0.5.5" clsx: "npm:^2.1.1" - lenis: "npm:^1.1.14" + lenis: "npm:^1.1.15" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" tsup: "npm:^8.3.5" @@ -1842,13 +1843,13 @@ __metadata: "@solid-primitives/utils": "npm:^6.2.3" "@star4/config": "workspace:^" "@star4/vanilla-extract": "workspace:^" - "@types/node": "npm:^22.8.6" + "@types/node": "npm:^22.9.0" "@vanilla-extract/css": "npm:^1.16.0" "@vanilla-extract/dynamic": "npm:^2.1.2" "@vanilla-extract/recipes": "npm:^0.5.5" clsx: "npm:^2.1.1" esbuild-plugin-solid: "npm:^0.6.0" - lenis: "npm:^1.1.14" + lenis: "npm:^1.1.15" solid-js: "npm:^1.9.3" tsup: "npm:^8.3.5" typescript: "npm:^5.6.3" @@ -2075,12 +2076,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^22.8.6": - version: 22.8.6 - resolution: "@types/node@npm:22.8.6" +"@types/node@npm:^22.9.0": + version: 22.9.0 + resolution: "@types/node@npm:22.9.0" dependencies: undici-types: "npm:~6.19.8" - checksum: 10c0/d3a11f2549234a91a4c5d0ff35ab4bdcb7ba34db4d3f1d189be39b8bd41c19aac98d117150a95a9c5a9d45b1014135477ea240b2b8317c86ae3d3cf1c3b3f8f4 + checksum: 10c0/3f46cbe0a49bab4ba30494025e4c8a6e699b98ac922857aa1f0209ce11a1313ee46e6808b8f13fe5b8b960a9d7796b77c8d542ad4e9810e85ef897d5593b5d51 languageName: node linkType: hard @@ -3477,11 +3478,9 @@ __metadata: languageName: node linkType: hard -"lenis@npm:^1.1.14": - version: 1.1.14 - resolution: "lenis@npm:1.1.14" - dependencies: - "@darkroom.engineering/tempus": "npm:^0.0.46" +"lenis@npm:^1.1.15": + version: 1.1.15 + resolution: "lenis@npm:1.1.15" peerDependencies: react: ">=17.0.0" vue: ">=3.0.0" @@ -3490,7 +3489,7 @@ __metadata: optional: true vue: optional: true - checksum: 10c0/426cee9d1cf1d816ad5d7dd051698c17ab1e3b276e3248d602e9314794114a9322b051fc3c8cd27e5f4cab94cabb7aa21445d4f84bccf3518304cd730ef792b0 + checksum: 10c0/5219cbfa6369548629d3378dc92e9db2b923dc66c447a924a1684685b6b690523c9ae4dc0ac982c4c080d8fd78919b17a6516ab68388a1b42c39b2e6995fbc52 languageName: node linkType: hard