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 (
- }>
+ } size="md">
+ Button
+
+ } size="lg">
+ Button
+
+ } size="xl">
+ Button
+
+
+
+ {" "}
+ {" "}
+
+ {" "}
+ {" "}
+
+
+
+ {" "}
+ {" "}
+
+ {" "}
+ {" "}
+
+
+
+
+ {" "}
+ {" "}
+
-
-
);
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);