diff --git a/.turbo/cookies/1.cookie b/.turbo/cookies/1.cookie deleted file mode 100644 index e69de29..0000000 diff --git a/.turbo/daemon/934a1a5ec62dbadc-turbo.log.2026-03-23 b/.turbo/daemon/934a1a5ec62dbadc-turbo.log.2026-03-23 new file mode 100644 index 0000000..9caed3d --- /dev/null +++ b/.turbo/daemon/934a1a5ec62dbadc-turbo.log.2026-03-23 @@ -0,0 +1 @@ +2026-03-23T18:36:13.907353Z WARN daemon_server: turborepo_lib::commands::daemon: daemon already running diff --git a/apps/ui-site/src/App.tsx b/apps/ui-site/src/App.tsx index 7340ec4..1b97789 100644 --- a/apps/ui-site/src/App.tsx +++ b/apps/ui-site/src/App.tsx @@ -1,11 +1,11 @@ -import { ThemeProvider } from "@defgov/ui"; +import { Skin } from "@defgov/ui"; import { ButtonGallery } from "./gallery/ButtonGallery"; const App = () => { return ( - + - + ); }; diff --git a/apps/ui-site/src/gallery/ButtonGallery.tsx b/apps/ui-site/src/gallery/ButtonGallery.tsx index 54f5127..68c82f9 100644 --- a/apps/ui-site/src/gallery/ButtonGallery.tsx +++ b/apps/ui-site/src/gallery/ButtonGallery.tsx @@ -6,11 +6,67 @@ export const ButtonGallery = () => { return ( - + + + + + {" "} + {" "} + + {" "} + {" "} + + + + {" "} + {" "} + + {" "} + {" "} + + + + + {" "} + {" "} + - - ); diff --git a/packages/ui/src/common/Box.tsx b/packages/ui/src/common/Box.tsx index 35fb579..90a3bbe 100644 --- a/packages/ui/src/common/Box.tsx +++ b/packages/ui/src/common/Box.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { useThemeContext } from "./ThemeProvider/useThemeContext"; import { cn } from "tailwind-variants"; import type { CommonProps } from "@/common/CommonProps"; @@ -23,12 +22,8 @@ const Box = ( ) => { const { as: Component = "div", children, className, ...rest } = props; - const { themeClass } = useThemeContext(); - if (!themeClass) { - throw new Error("Box must be used within a ThemeProvider"); - } - const boxRootClass = cn(themeClass, className); + const boxRootClass = cn( className); return ( diff --git a/packages/ui/src/common/Skin.tsx b/packages/ui/src/common/Skin.tsx new file mode 100644 index 0000000..39481f1 --- /dev/null +++ b/packages/ui/src/common/Skin.tsx @@ -0,0 +1,10 @@ +import type { CommonProps } from "./CommonProps"; + +type SkinProps = CommonProps & { + theme?: "light" | "dark"; +}; + +export const Skin = (props: SkinProps) => { + const { theme = "light", children } = props; + return
{children}
; +}; diff --git a/packages/ui/src/common/ThemeProvider/ThemeContext.ts b/packages/ui/src/common/ThemeProvider/ThemeContext.ts deleted file mode 100644 index 580007c..0000000 --- a/packages/ui/src/common/ThemeProvider/ThemeContext.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createContext } from "react"; - -export type Theme = "light" | "dark"; - -export const ThemeContext = createContext<{ - theme?: Theme; - toggleTheme?: () => void; - themeClass?: string; -} | null>(null); diff --git a/packages/ui/src/common/ThemeProvider/ThemeProvider.tsx b/packages/ui/src/common/ThemeProvider/ThemeProvider.tsx deleted file mode 100644 index e3ceb29..0000000 --- a/packages/ui/src/common/ThemeProvider/ThemeProvider.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useState, type ReactNode } from "react"; -import { type Theme, ThemeContext } from "./ThemeContext"; -import { cn } from "tailwind-variants"; - -type ThemeProviderProps = { - children?: ReactNode; - defaultTheme?: Theme; -}; - -export const ThemeProvider = ({ - children, - defaultTheme, -}: ThemeProviderProps) => { - const [theme, setTheme] = useState(defaultTheme || "light"); - const toggleTheme = () => setTheme(theme === "light" ? "dark" : "light"); - - const frameworkClass = "dg"; - const themeClass = cn(frameworkClass, theme); - - return ( - -
- {children} -
-
- ); -}; diff --git a/packages/ui/src/common/ThemeProvider/useThemeContext.ts b/packages/ui/src/common/ThemeProvider/useThemeContext.ts deleted file mode 100644 index a3b65ab..0000000 --- a/packages/ui/src/common/ThemeProvider/useThemeContext.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useContext } from "react"; -import { ThemeContext } from "./ThemeContext"; - -export function useThemeContext() { - const context = useContext(ThemeContext); - if (!context) throw new Error("useTheme must be used within ThemeProvider"); - return context; -} diff --git a/packages/ui/src/component/button/Button.tsx b/packages/ui/src/component/button/Button.tsx index 86ee46f..ceb99d4 100644 --- a/packages/ui/src/component/button/Button.tsx +++ b/packages/ui/src/component/button/Button.tsx @@ -2,15 +2,17 @@ import * as BUI from "@base-ui/react/button"; import { cn } from "tailwind-variants"; import type { CommonProps } from "@/common/CommonProps"; -import { itemRootRecipe } from "@/styles/recipe/ItemRoot.recipe"; +import { itemSizeRecipe } from "@/styles/recipe/ItemSize.recipe"; import { variantRecipe } from "@/styles/recipe/variant.recipe"; import type { ReactNode } from "react"; -import { inlineRootRecipe } from "@/styles/recipe/IinlineRoot.recipe"; +import { inlineSizeRecipe } from "@/styles/recipe/IinlineSize.recipe"; import { Slot } from "@/common/Slot"; type ButtonProps = CommonProps & { size?: "md" | "lg" | "xl"; variant?: "filled" | "outline" | "subtle"; + shape?: "rounded" | "square" | "circle"; + brand?: "success" | "danger" | "info" | "warning" | "default"; loading?: boolean; icon?: ReactNode; iconOnly?: boolean; @@ -23,6 +25,8 @@ export const Button = (props: ButtonProps) => { children, size = "md", variant = "filled", + shape = "rounded", + brand, loading, disabled, icon, @@ -30,13 +34,16 @@ export const Button = (props: ButtonProps) => { hideIcon = false, } = props; + const currentBrand = + brand == undefined ? (variant == "filled" ? "info" : "default") : brand; + const buttonCls = cn( - itemRootRecipe({ size }), + itemSizeRecipe({ size, brand: currentBrand, shape }), variantRecipe({ variant, disabled: loading || disabled }), className, ); - const iconCls = cn(inlineRootRecipe({ size, iconOnly })); + const iconCls = cn(inlineSizeRecipe({ size, iconOnly: true })); return ( diff --git a/packages/ui/src/index.css b/packages/ui/src/index.css index 27ec86c..8e17400 100644 --- a/packages/ui/src/index.css +++ b/packages/ui/src/index.css @@ -1,6 +1,5 @@ @import "tailwindcss"; -@import './styles/theme/theme-base.css'; -@import './styles/theme/theme-variant.css'; +@import './styles/theme/global.css'; @import './styles/utility/brand.css'; @import './styles/utility/gap.css'; @import './styles/utility/height.css'; diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index b66efb6..6e91a74 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -24,11 +24,9 @@ export * from './assets/svg/VolumeMediumSvg'; export * from './assets/svg/VolumeMuteSvg'; export * from './common/Box'; export * from './common/CommonProps'; +export * from './common/Skin'; export * from './common/Slot'; -export * from './common/ThemeProvider/ThemeContext'; -export * from './common/ThemeProvider/ThemeProvider'; -export * from './common/ThemeProvider/useThemeContext'; export * from './component/button/Button'; -export * from './styles/recipe/IinlineRoot.recipe'; -export * from './styles/recipe/ItemRoot.recipe'; +export * from './styles/recipe/IinlineSize.recipe'; +export * from './styles/recipe/ItemSize.recipe'; export * from './styles/recipe/variant.recipe'; diff --git a/packages/ui/src/styles/recipe/IinlineRoot.recipe.ts b/packages/ui/src/styles/recipe/IinlineSize.recipe.ts similarity index 98% rename from packages/ui/src/styles/recipe/IinlineRoot.recipe.ts rename to packages/ui/src/styles/recipe/IinlineSize.recipe.ts index 24372e9..bc44fae 100644 --- a/packages/ui/src/styles/recipe/IinlineRoot.recipe.ts +++ b/packages/ui/src/styles/recipe/IinlineSize.recipe.ts @@ -1,6 +1,6 @@ import { tv } from "tailwind-variants"; -export const inlineRootRecipe = tv({ +export const inlineSizeRecipe = tv({ base: "relative overflow-hidden flex flex-nowrap", variants: { size: { diff --git a/packages/ui/src/styles/recipe/ItemRoot.recipe.ts b/packages/ui/src/styles/recipe/ItemSize.recipe.ts similarity index 91% rename from packages/ui/src/styles/recipe/ItemRoot.recipe.ts rename to packages/ui/src/styles/recipe/ItemSize.recipe.ts index a0310bc..8e10932 100644 --- a/packages/ui/src/styles/recipe/ItemRoot.recipe.ts +++ b/packages/ui/src/styles/recipe/ItemSize.recipe.ts @@ -1,7 +1,7 @@ import { tv } from "tailwind-variants"; -export const itemRootRecipe = tv({ - base: "relative select-none overflow-hidden flex flex-nowrap", +export const itemSizeRecipe = tv({ + base: "relative select-none overflow-hidden flex flex-nowrap justify-center items-center", variants: { size: { xs: "text-xs h-xs px-xs gap-xs", @@ -21,7 +21,7 @@ export const itemRootRecipe = tv({ danger: "brand-danger", info: "brand-info", warning: "brand-warning", - emphasis: "brand-emphasis", + default: "brand-default", }, iconOnly: { true: "", diff --git a/packages/ui/src/styles/theme/global.css b/packages/ui/src/styles/theme/global.css new file mode 100644 index 0000000..e28f480 --- /dev/null +++ b/packages/ui/src/styles/theme/global.css @@ -0,0 +1,32 @@ +@theme { + --color-transparent: transparent; + --danger-bg: var(--color-red-600); + --danger-bg-high-hover: var(--color-red-500); + --danger-bg-high-active: var(--color-red-400); + --danger-bg-low-hover: var(--color-red-100); + --danger-bg-low-active: var(--color-red-200); + + --success-bg: var(--color-emerald-600); + --success-bg-high-hover: var(--color-emerald-500); + --success-bg-high-active: var(--color-emerald-400); + --success-bg-low-hover: var(--color-emerald-100); + --success-bg-low-active: var(--color-emerald-200); + + --info-bg: var(--color-sky-600); + --info-bg-high-hover: var(--color-sky-500); + --info-bg-high-active: var(--color-sky-400); + --info-bg-low-hover: var(--color-sky-100); + --info-bg-low-active: var(--color-sky-200); + + --warning-bg: var(--color-yellow-600); + --warning-bg-high-hover: var(--color-yellow-500); + --warning-bg-high-active: var(--color-yellow-400); + --warning-bg-low-hover: var(--color-yellow-100); + --warning-bg-low-active: var(--color-yellow-200); + + --default-bg: var(--color-neutral-800); + --default-bg-high-hover: var(--color-neutral-700); + --default-bg-high-active: var(--color-neutral-600); + --default-bg-low-hover: var(--color-neutral-100); + --default-bg-low-active: var(--color-neutral-200); +} diff --git a/packages/ui/src/styles/theme/theme-base.css b/packages/ui/src/styles/theme/theme-base.css deleted file mode 100644 index 95db713..0000000 --- a/packages/ui/src/styles/theme/theme-base.css +++ /dev/null @@ -1,33 +0,0 @@ -@theme { - --color-transparent: transparent; - --danger-fg: var(--base-fg); - --danger-bg-low-hover: var(--color-red-100); - --danger-bg-low-active: var(--color-red-200); - --danger-bg: var(--color-red-600); - --danger-bg-high-hover: var(--color-red-700); - --danger-bg-high-active: var(--color-red-800); - --success-fg: var(--base-fg); - --success-bg-low-hover: var(--color-green-100); - --success-bg-low-active: var(--color-green-200); - --success-bg: var(--color-green-600); - --success-bg-high-hover: var(--color-green-700); - --success-bg-high-active: var(--color-green-800); - --info-fg: var(--base-fg); - --info-bg-low-hover: var(--color-sky-100); - --info-bg-low-active: var(--color-sky-200); - --info-bg: var(--color-sky-600); - --info-bg-high-hover: var(--color-sky-700); - --info-bg-high-active: var(--color-sky-800); - --warning-fg: var(--base-fg); - --warning-bg-low-hover: var(--color-amber-100); - --warning-bg-low-active: var(--color-amber-200); - --warning-bg: var(--color-amber-600); - --warning-bg-high-hover: var(--color-amber-700); - --warning-bg-high-active: var(--color-amber-800); - --default-fg: var(--base-fg); - --default-bg-low-hover: var(--color-gray-100); - --default-bg-low-active: var(--color-gray-200); - --default-bg: var(--color-gray-600); - --default-bgr-high-hover: var(--color-gray-700); - --default-bg-high-active: var(--color-gray-800); -} diff --git a/packages/ui/src/styles/theme/theme-variant.css b/packages/ui/src/styles/theme/theme-variant.css deleted file mode 100644 index ee45fb2..0000000 --- a/packages/ui/src/styles/theme/theme-variant.css +++ /dev/null @@ -1,25 +0,0 @@ -@theme { - --filled-fg: var(--color-white); - --filled-fg-hover: var(--color-white); - --filled-fg-active: var(--color-white); - --filled-bg: var(--brand-bg); - --filled-bg-hover: var(--brand-bg-high-hover); - --filled-bg-active: var(--brand-bg-high-active); - --filled-border-color: var(--color-transparent); - - --outline-fg: var(--base-fg); - --outline-fg-hover: var(--brand-bg); - --outline-fg-active: var(--brand-bg); - --outline-bg: var(--color-transparent); - --outline-bg-hover: var(--brand-bg-low-hover); - --outline-bg-active: var(--brand-bg-low-active); - --outline-border-color: var(--brand-bg); - - --subtle-fg: var(--base-fg); - --subtle-fg-hover: var(--brand-bg); - --subtle-fg-active: var(--brand-bg); - --subtle-bg: var(--color-transparent); - --subtle-bg-hover: var(--brand-bg-low-hover); - --subtle-bg-active: var(--brand-bg-low-active); - --subtle-border-color: var(--color-transparent); -} diff --git a/packages/ui/src/styles/utility/brand.css b/packages/ui/src/styles/utility/brand.css index 81293a0..5896618 100644 --- a/packages/ui/src/styles/utility/brand.css +++ b/packages/ui/src/styles/utility/brand.css @@ -1,35 +1,35 @@ @utility brand-info { - --brand-bg-low-hover: var(--info-bg-low-hover); - --brand-bg-low-active: var(--info-bg-low-active); --brand-bg: var(--info-bg); --brand-bg-high-hover: var(--info-bg-high-hover); --brand-bg-high-active: var(--info-bg-high-active); + --brand-bg-low-hover: var(--info-bg-low-hover); + --brand-bg-low-active: var(--info-bg-low-active); } @utility brand-danger { - --brand-bg-low-hover: var(--danger-bg-low-hover); - --brand-bg-low-active: var(--danger-bg-low-active); --brand-bg: var(--danger-bg); --brand-bg-high-hover: var(--danger-bg-high-hover); --brand-bg-high-active: var(--danger-bg-high-active); + --brand-bg-low-hover: var(--danger-bg-low-hover); + --brand-bg-low-active: var(--danger-bg-low-active); } @utility brand-success { - --brand-bg-low-hover: var(--success-bg-low-hover); - --brand-bg-low-active: var(--success-bg-low-active); --brand-bg: var(--success-bg); --brand-bg-high-hover: var(--success-bg-high-hover); --brand-bg-high-active: var(--success-bg-high-active); + --brand-bg-low-hover: var(--success-bg-low-hover); + --brand-bg-low-active: var(--success-bg-low-active); } @utility brand-warning { - --brand-bg-low-hover: var(--warning-bg-low-hover); - --brand-bg-low-active: var(--warning-bg-low-active); --brand-bg: var(--warning-bg); --brand-bg-high-hover: var(--warning-bg-high-hover); --brand-bg-high-active: var(--warning-bg-high-active); + --brand-bg-low-hover: var(--warning-bg-low-hover); + --brand-bg-low-active: var(--warning-bg-low-active); } @utility brand-default { - --brand-bg-low-hover: var(--default-bg-low-hover); - --brand-bg-low-active: var(--default-bg-low-active); --brand-bg: var(--default-bg); --brand-bg-high-hover: var(--default-bg-high-hover); --brand-bg-high-active: var(--default-bg-high-active); + --brand-bg-low-hover: var(--default-bg-low-hover); + --brand-bg-low-active: var(--default-bg-low-active); } diff --git a/packages/ui/src/styles/utility/variant.css b/packages/ui/src/styles/utility/variant.css index c944bf9..f7dfd37 100644 --- a/packages/ui/src/styles/utility/variant.css +++ b/packages/ui/src/styles/utility/variant.css @@ -1,27 +1,44 @@ @utility variant-filled { + --filled-fg: var(--color-white); + --filled-fg-hover: var(--color-white); + --filled-fg-active: var(--color-white); + --filled-bg: var(--brand-bg); + --filled-bg-hover: var(--brand-bg-high-hover); + --filled-bg-active: var(--brand-bg-high-active); + --filled-border-color: var(--color-transparent); + color: var(--filled-fg); background-color: var(--filled-bg); border-color: var(--filled-border-color); &:hover { background-color: var(--filled-bg-hover); - color: var(--filid-fg-hover); + color: var(--filled-fg-hover); } &:active { background-color: var(--filled-bg-active); - color: var(--filid-fg-active); + color: var(--filled-fg-active); } &:focus-visible { background-color: var(--filled-bg-hover); - color: var(--filid-fg-hover); + color: var(--filled-fg-hover); } } @utility variant-outline { + --outline-fg: var(--brand-bg); + --outline-fg-hover: var(--brand-bg); + --outline-fg-active: var(--brand-bg); + --outline-bg: var(--color-transparent); + --outline-bg-hover: var(--brand-bg-low-hover); + --outline-bg-active: var(--brand-bg-low-active); + --outline-border-color: var(--brand-bg); + color: var(--outline-fg); background-color: var(--outline-bg); + border: solid 1px; border-color: var(--outline-border-color); &:hover { @@ -41,6 +58,14 @@ } @utility variant-subtle { + --subtle-fg: var(--brand-bg); + --subtle-fg-hover: var(--brand-bg); + --subtle-fg-active: var(--brand-bg); + --subtle-bg: var(--color-transparent); + --subtle-bg-hover: var(--brand-bg-low-hover); + --subtle-bg-active: var(--brand-bg-low-active); + --subtle-border-color: var(--color-transparent); + color: var(--subtle-fg); background-color: var(--subtle-bg); border-color: var(--subtle-border-color);