diff --git a/.changeset/provider-wonju.md b/.changeset/provider-wonju.md
new file mode 100644
index 00000000..db4bcd72
--- /dev/null
+++ b/.changeset/provider-wonju.md
@@ -0,0 +1,13 @@
+---
+"@sipe-team/theme": major
+"@sipe-team/tokens": minor
+---
+
+Replace brand-color ThemeProvider with light/dark mode toggle and align design tokens with SSOT.
+
+- `ThemeProvider` now applies themes via `data-theme` attribute instead of `assignInlineVars`
+- `theme` prop changed from brand-color objects to `'light' | 'dark'` string union
+- `ThemeMode` type is now exported from `@sipe-team/tokens`
+- VE contract structure for `color`, `spacing`, and `radius` reorganized into semantic token hierarchy
+- Token values in `themes.css.ts` now reference Style Dictionary CSS variables instead of hardcoded JS constants
+- Removed `@vanilla-extract/dynamic` dependency from `@sipe-team/theme`
diff --git a/.claude/settings.json b/.claude/settings.json
index f008a202..55a8b1fc 100644
--- a/.claude/settings.json
+++ b/.claude/settings.json
@@ -12,12 +12,12 @@
"Bash(ls*)",
"Edit",
"Write",
- "Read"
+ "Read",
+ "Read(./packages/tokens/dist/**)"
],
"ask": ["Bash(git push*)", "Bash(git commit*)", "Bash(git reset*)", "Bash(rm *)"],
"deny": [
"Read(./node_modules/)",
- "Read(./dist/)",
"Read(./storybook-static/)",
"Read(./www/build/)",
"Read(./www/.docusaurus/)",
diff --git a/packages/theme/package.json b/packages/theme/package.json
index 7b3a13ee..09c2d896 100644
--- a/packages/theme/package.json
+++ b/packages/theme/package.json
@@ -35,7 +35,6 @@
"vitest": "catalog:"
},
"dependencies": {
- "@vanilla-extract/dynamic": "catalog:",
"@sipe-team/tokens": "workspace:*"
},
"publishConfig": {
diff --git a/packages/theme/src/ThemeProvider.stories.tsx b/packages/theme/src/ThemeProvider.stories.tsx
deleted file mode 100644
index 3a8f9057..00000000
--- a/packages/theme/src/ThemeProvider.stories.tsx
+++ /dev/null
@@ -1,461 +0,0 @@
-import { type ThemeColor, themeColor } from '@sipe-team/tokens';
-
-import type { Meta, StoryObj } from '@storybook/react';
-
-import { ThemeProvider, useTheme } from './ThemeProvider';
-
-const meta = {
- title: 'Components/ThemeProvider',
- component: ThemeProvider,
- parameters: {
- layout: 'centered',
- },
- argTypes: {
- theme: {
- control: { type: 'select' },
- options: ['1st', '2nd', '3rd', '4th'],
- description: 'Select theme variant',
- mapping: {
- '1st': themeColor['1st'],
- '2nd': themeColor['2nd'],
- '3rd': themeColor['3rd'],
- '4th': themeColor['4th'],
- },
- },
- },
- decorators: [
- (Story) => (
-
-
-
- ),
- ],
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-const ThemeDisplay = () => {
- const { theme: currentTheme } = useTheme();
-
- return (
-
-
-
Current Theme: {currentTheme.primary}
-
-
-
Theme Preview
-
-
- This is regular text using the theme's text color and medium font size.
-
-
- This is primary-colored text with large font size and bold weight.
-
-
- This is a primary background container
-
-
- This is a secondary background container
-
-
- This is a gradient background container
-
-
-
-
-
- );
-};
-
-export const Default: Story = {
- args: {
- theme: themeColor['4th'],
- children: ,
- },
- render: (args) => {
- return (
-
-
-
- );
- },
-};
-
-const NestedThemeExample = () => {
- return (
-
-
Nested Theme Override Example
-
- {/* Parent Theme Container */}
-
-
-
Parent Component (Theme 1st)
-
This is the parent component using the 1st theme.
-
-
- Parent theme primary color container
-
-
- {/* Nested Child Theme Container */}
-
-
-
- Child Component (Theme 3rd - Overridden)
-
-
- This child component overrides the parent theme with the 3rd theme.
-
-
-
- Child theme secondary color container
-
-
- {/* Deeply Nested Component */}
-
-
-
- Grandchild Component (Theme 4th)
-
-
- This deeply nested component uses the 4th theme.
-
-
-
- Grandchild primary container
-
-
-
-
-
-
-
-
- );
-};
-
-export const NestedThemeOverride: Story = {
- args: {
- theme: themeColor['4th'],
- children: ,
- },
- render: () => ,
- parameters: {
- docs: {
- description: {
- story:
- 'This example demonstrates how themes can be overridden in nested components. Each ThemeProvider creates a new theme context that overrides its parent.',
- },
- },
- },
-};
-
-const CustomThemeExample = () => {
- // Custom theme object
- const customTheme: ThemeColor = {
- primary: '#ff6b6b',
- secondary: '#4ecdc4',
- background: '#f8f9fa',
- text: '#343a40',
- gradient: 'linear-gradient(135deg, #ff6b6b 0%, #4ecdc4 100%)',
- };
-
- return (
-
-
Custom Theme Injection Example
-
- {/* Custom Theme Container */}
-
-
-
Custom Theme Component
-
- This component uses a completely custom theme with custom colors:
-
-
-
-
- Primary: #ff6b6b
-
-
- Secondary: #4ecdc4
-
-
-
-
- Custom Gradient Background
-
-
- {/* Nested with predefined theme */}
-
-
-
- Nested Predefined Theme (2nd)
-
-
- This shows how you can nest predefined themes within custom themes.
-
-
-
- Predefined theme container
-
-
-
-
-
-
- {/* Multiple Custom Themes Side by Side */}
-
-
-
-
Purple Theme
-
- Custom Purple
-
-
-
-
-
-
-
Green Theme
-
- Custom Green
-
-
-
-
-
- );
-};
-
-export const CustomThemeInjection: Story = {
- args: {
- theme: themeColor['4th'],
- children: ,
- },
- render: () => ,
- parameters: {
- docs: {
- description: {
- story:
- 'This example demonstrates how to inject completely custom theme objects. You can create custom themes with any color values and use them alongside predefined themes.',
- },
- },
- },
-};
diff --git a/packages/theme/src/ThemeProvider.test.tsx b/packages/theme/src/ThemeProvider.test.tsx
index c187458c..4e5fb98b 100644
--- a/packages/theme/src/ThemeProvider.test.tsx
+++ b/packages/theme/src/ThemeProvider.test.tsx
@@ -1,7 +1,5 @@
-import { type ThemeColor, themeColor } from '@sipe-team/tokens';
-
import { act, render, screen } from '@testing-library/react';
-import { describe, expect, it, test } from 'vitest';
+import { describe, expect, test } from 'vitest';
import { ThemeProvider, useTheme } from './ThemeProvider';
@@ -10,18 +8,12 @@ const TestComponent = () => {
return (
- {theme.primary}
-
-
-
);
@@ -29,49 +21,35 @@ const TestComponent = () => {
const ComponentWithoutProvider = () => {
const { theme } = useTheme();
- return {theme.primary}
;
+ return {theme}
;
};
describe('ThemeProvider', () => {
- test('sets 4th generation theme as default', () => {
- render(
+ test('defaults to dark mode', () => {
+ const { container } = render(
,
);
- expect(screen.getByTestId('current-theme')).toHaveTextContent(themeColor['4th'].primary);
- });
-
- test('sets the theme to the provided initial theme prop', () => {
- render(
-
-
- ,
- );
-
- expect(screen.getByTestId('current-theme')).toHaveTextContent(themeColor['2nd'].primary);
+ const themeDiv = container.firstChild as HTMLElement;
+ expect(themeDiv).toHaveAttribute('data-theme', 'dark');
+ expect(screen.getByTestId('current-theme')).toHaveTextContent('dark');
});
- test('accepts custom theme color objects', () => {
- const customTheme: ThemeColor = {
- primary: '#ff0000',
- secondary: '#00ff00',
- background: '#0000ff',
- text: '#ffffff',
- gradient: 'linear-gradient(45deg, #ff0000 0%, #00ff00 100%)',
- };
-
- render(
-
+ test('applies provided initial theme', () => {
+ const { container } = render(
+
,
);
- expect(screen.getByTestId('current-theme')).toHaveTextContent(customTheme.primary);
+ const themeDiv = container.firstChild as HTMLElement;
+ expect(themeDiv).toHaveAttribute('data-theme', 'light');
+ expect(screen.getByTestId('current-theme')).toHaveTextContent('light');
});
- test('container div has display: contents style', () => {
+ test('container has display: contents style', () => {
const { container } = render(
@@ -82,96 +60,41 @@ describe('ThemeProvider', () => {
expect(themeContainer).toHaveStyle({ display: 'contents' });
});
- test('can change theme through setTheme', async () => {
- render(
+ test('setTheme updates data-theme attribute', async () => {
+ const { container } = render(
,
);
- const currentTheme = screen.getByTestId('current-theme');
- const set2ndButton = screen.getByTestId('set-2nd');
-
- expect(currentTheme).toHaveTextContent(themeColor['4th'].primary);
+ const themeDiv = container.firstChild as HTMLElement;
+ expect(themeDiv).toHaveAttribute('data-theme', 'dark');
await act(async () => {
- set2ndButton.click();
+ screen.getByTestId('set-light').click();
});
- expect(currentTheme).toHaveTextContent(themeColor['2nd'].primary);
+ expect(themeDiv).toHaveAttribute('data-theme', 'light');
+ expect(screen.getByTestId('current-theme')).toHaveTextContent('light');
});
- test('theme updates when initial theme changes', () => {
- const { rerender } = render(
-
+ test('theme prop change updates data-theme attribute', () => {
+ const { rerender, container } = render(
+
,
);
- expect(screen.getByTestId('current-theme')).toHaveTextContent(themeColor['1st'].primary);
+ const themeDiv = container.firstChild as HTMLElement;
+ expect(themeDiv).toHaveAttribute('data-theme', 'dark');
rerender(
-
+
,
);
- expect(screen.getByTestId('current-theme')).toHaveTextContent(themeColor['3rd'].primary);
- });
-
- describe('all theme types are set correctly', () => {
- const themes = [
- { name: '1st', theme: themeColor['1st'] },
- { name: '2nd', theme: themeColor['2nd'] },
- { name: '3rd', theme: themeColor['3rd'] },
- { name: '4th', theme: themeColor['4th'] },
- ];
-
- it.each(themes)('theme "$name" is set correctly', ({ theme }) => {
- render(
-
-
- ,
- );
-
- const currentTheme = screen.getByTestId('current-theme');
- expect(currentTheme).toHaveTextContent(theme.primary);
- });
- });
-
- describe('theme change functionality tests', () => {
- const themeChangeTests = [
- { from: themeColor['4th'], to: themeColor['1st'], buttonTestId: 'set-1st' },
- { from: themeColor['1st'], to: themeColor['2nd'], buttonTestId: 'set-2nd' },
- { from: themeColor['2nd'], to: themeColor['3rd'], buttonTestId: 'set-3rd' },
- { from: themeColor['3rd'], to: themeColor['4th'], buttonTestId: 'set-4th' },
- ];
-
- it.each(themeChangeTests)('can change theme from $from.primary to $to.primary', async ({
- from,
- to,
- buttonTestId,
- }) => {
- render(
-
-
- ,
- );
-
- const currentTheme = screen.getByTestId('current-theme');
- const changeButton = screen.getByTestId(buttonTestId);
-
- // Check initial state
- expect(currentTheme).toHaveTextContent(from.primary);
-
- // Change theme
- await act(async () => {
- changeButton.click();
- });
-
- // Check changed state
- expect(currentTheme).toHaveTextContent(to.primary);
- });
+ expect(themeDiv).toHaveAttribute('data-theme', 'light');
});
test('children are rendered correctly', () => {
@@ -187,8 +110,7 @@ describe('ThemeProvider', () => {
});
describe('useTheme hook', () => {
- test('throws an error when used outside of ThemeProvider', () => {
- // Mock console.error to hide console errors
+ test('throws when used outside ThemeProvider', () => {
const originalError = console.error;
console.error = () => {};
@@ -196,21 +118,18 @@ describe('useTheme hook', () => {
render();
}).toThrow('useTheme must be used within a ThemeProvider');
- // Restore console.error
console.error = originalError;
});
- test('returns correct context values when used inside ThemeProvider', () => {
+ test('returns correct theme and setTheme', () => {
render(
-
+
,
);
- expect(screen.getByTestId('current-theme')).toHaveTextContent(themeColor['2nd'].primary);
- expect(screen.getByTestId('set-1st')).toBeInTheDocument();
- expect(screen.getByTestId('set-2nd')).toBeInTheDocument();
- expect(screen.getByTestId('set-3rd')).toBeInTheDocument();
- expect(screen.getByTestId('set-4th')).toBeInTheDocument();
+ expect(screen.getByTestId('current-theme')).toHaveTextContent('dark');
+ expect(screen.getByTestId('set-light')).toBeInTheDocument();
+ expect(screen.getByTestId('set-dark')).toBeInTheDocument();
});
});
diff --git a/packages/theme/src/ThemeProvider.tsx b/packages/theme/src/ThemeProvider.tsx
index bd844775..97f2e925 100644
--- a/packages/theme/src/ThemeProvider.tsx
+++ b/packages/theme/src/ThemeProvider.tsx
@@ -1,13 +1,11 @@
import type React from 'react';
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
-import { type ThemeColor, themeColor, vars } from '@sipe-team/tokens';
-
-import { assignInlineVars } from '@vanilla-extract/dynamic';
+import { type ThemeMode, vars } from '@sipe-team/tokens';
interface ThemeContextType {
- theme: ThemeColor;
- setTheme: (theme: ThemeColor) => void;
+ theme: ThemeMode;
+ setTheme: (theme: ThemeMode) => void;
}
const ThemeContext = createContext(undefined);
@@ -22,11 +20,11 @@ export const useTheme = (): ThemeContextType => {
interface ThemeProviderProps {
children: React.ReactNode;
- theme?: ThemeColor;
+ theme?: ThemeMode;
}
-export const ThemeProvider: React.FC = ({ children, theme: initialTheme = themeColor['4th'] }) => {
- const [theme, setTheme] = useState(initialTheme);
+export const ThemeProvider: React.FC = ({ children, theme: initialTheme = 'dark' }) => {
+ const [theme, setTheme] = useState(initialTheme);
useEffect(() => {
setTheme(initialTheme);
@@ -40,15 +38,11 @@ export const ThemeProvider: React.FC = ({ children, theme: i
[theme],
);
- const themeVars = assignInlineVars(vars.color.accent, {
- default: theme.primary,
- hover: theme.secondary,
- subtle: theme.background,
- });
-
return (
- {children}
+
+ {children}
+
);
};
diff --git a/packages/tokens/src/colors/index.ts b/packages/tokens/src/colors/index.ts
index 1bae1c0e..269a9424 100644
--- a/packages/tokens/src/colors/index.ts
+++ b/packages/tokens/src/colors/index.ts
@@ -1 +1,2 @@
+// TODO: colors.ts is superseded by tokens/tokens.json (SD SSOT). Remove in a follow-up PR.
export * from './colors';
diff --git a/packages/tokens/src/theme/contract.css.ts b/packages/tokens/src/theme/contract.css.ts
index e63e7caa..403fac7b 100644
--- a/packages/tokens/src/theme/contract.css.ts
+++ b/packages/tokens/src/theme/contract.css.ts
@@ -1,5 +1,8 @@
import { createGlobalThemeContract, globalLayer } from '@vanilla-extract/css';
+// TODO: dark is the default mode; light mode will be added later.
+export type ThemeMode = 'light' | 'dark';
+
export const themeLayer = globalLayer('theme');
export const vars = createGlobalThemeContract(
@@ -111,8 +114,6 @@ export const vars = createGlobalThemeContract(
xl: 'shadow-xl',
'2xl': 'shadow-2xl',
},
- mode: 'theme-mode',
- theme: 'theme-name',
},
(value) => `side-${value}`,
);
diff --git a/packages/tokens/src/theme/themes.css.ts b/packages/tokens/src/theme/themes.css.ts
index a0622c39..b994809b 100644
--- a/packages/tokens/src/theme/themes.css.ts
+++ b/packages/tokens/src/theme/themes.css.ts
@@ -1,52 +1,36 @@
import { createGlobalTheme } from '@vanilla-extract/css';
-import { brandColor, color, themeColor } from '../colors/colors';
-import { radius } from '../effects/radius';
import { shadows } from '../effects/shadows';
-import { spacing } from '../layout/spacing';
-import { fontSize, fontWeight, lineHeight } from '../typography/fonts';
import { themeLayer, vars } from './contract.css';
+import { cssVar, mapVars } from './utils';
const baseTheme = {
'@layer': themeLayer,
- spacing: {
- component: {
- xs: `${spacing[1]}px`,
- sm: `${spacing[2]}px`,
- md: `${spacing[3]}px`,
- lg: `${spacing[4]}px`,
- xl: `${spacing[6]}px`,
- },
- layout: {
- sm: `${spacing[8]}px`,
- md: `${spacing[10]}px`,
- lg: `${spacing[12]}px`,
- xl: `${spacing[16]}px`,
- },
- },
+ spacing: mapVars(vars.spacing),
typography: {
- fontFamily: 'Pretendard, system-ui, sans-serif',
+ // typography contract values don't align with SD path-based naming — referenced manually
+ fontFamily: cssVar('typography-font-family-base'),
fontSize: {
- '050': `${fontSize[12]}px`,
- '100': `${fontSize[14]}px`,
- '200': `${fontSize[16]}px`,
- '300': `${fontSize[18]}px`,
- '400': `${fontSize[20]}px`,
- '500': `${fontSize[24]}px`,
- '600': `${fontSize[28]}px`,
- '700': `${fontSize[32]}px`,
- '800': `${fontSize[36]}px`,
- '900': `${fontSize[48]}px`,
+ '050': cssVar('typography-font-size-12'),
+ '100': cssVar('typography-font-size-14'),
+ '200': cssVar('typography-font-size-16'),
+ '300': cssVar('typography-font-size-18'),
+ '400': cssVar('typography-font-size-20'),
+ '500': cssVar('typography-font-size-24'),
+ '600': cssVar('typography-font-size-28'),
+ '700': cssVar('typography-font-size-32'),
+ '800': cssVar('typography-font-size-36'),
+ '900': cssVar('typography-font-size-48'),
},
lineHeight: {
- regular: `${lineHeight.regular}`,
- compact: `${lineHeight.compact}`,
+ regular: cssVar('typography-line-height-regular'),
+ compact: cssVar('typography-line-height-compact'),
},
fontWeight: {
- regular: `${fontWeight.regular}`,
- medium: `${fontWeight.medium}`,
- semiBold: `${fontWeight.semiBold}`,
- bold: `${fontWeight.bold}`,
+ regular: cssVar('typography-font-weight-regular'),
+ medium: cssVar('typography-font-weight-medium'),
+ semiBold: cssVar('typography-font-weight-semi-bold'),
+ bold: cssVar('typography-font-weight-bold'),
},
},
shadows: {
@@ -57,113 +41,21 @@ const baseTheme = {
xl: shadows.xl,
'2xl': shadows['2xl'],
},
- radius: {
- component: {
- sm: radius.sm,
- md: radius.md,
- lg: radius.lg,
- xl: radius.xl,
- full: radius.full,
- },
- layout: {
- sm: radius.md,
- md: radius.lg,
- lg: radius.xl,
- },
- },
+ radius: mapVars(vars.radius),
};
-const darkBaseColor = {
- background: {
- base: color.gray950,
- subtle: color.gray900,
- muted: color.gray800,
- },
- foreground: {
- default: color.white,
- subtle: color.gray400,
- muted: color.gray500,
- onAccent: color.white,
- },
- border: {
- default: color.gray700,
- strong: color.gray500,
- focus: color.blue400,
- },
- status: {
- success: { foreground: color.green400, background: color.green900, border: color.green700 },
- warning: { foreground: color.orange400, background: color.orange900, border: color.orange700 },
- danger: { foreground: color.red400, background: color.red900, border: color.red700 },
- info: { foreground: color.blue400, background: color.blue900, border: color.blue700 },
- },
-};
+const darkColor = mapVars(vars.color);
+// :root — global dark fallback for contexts without an explicit data-theme attribute
createGlobalTheme(':root', vars, {
...baseTheme,
- color: {
- ...darkBaseColor,
- accent: {
- default: brandColor.default,
- hover: brandColor.hover,
- subtle: brandColor.subtle,
- },
- },
- mode: 'dark',
- theme: 'default',
+ color: darkColor,
});
-createGlobalTheme('[data-theme="1st"]', vars, {
+// [data-theme="dark"] — allows a dark sub-region inside a future light-mode root
+createGlobalTheme('[data-theme="dark"]', vars, {
...baseTheme,
- color: {
- ...darkBaseColor,
- accent: {
- default: themeColor['1st'].primary,
- hover: themeColor['1st'].secondary,
- subtle: color.green900,
- },
- },
- mode: 'dark',
- theme: '1st',
+ color: darkColor,
});
-createGlobalTheme('[data-theme="2nd"]', vars, {
- ...baseTheme,
- color: {
- ...darkBaseColor,
- accent: {
- default: themeColor['2nd'].primary,
- hover: themeColor['2nd'].secondary,
- subtle: color.teal900,
- },
- },
- mode: 'dark',
- theme: '2nd',
-});
-
-createGlobalTheme('[data-theme="3rd"]', vars, {
- ...baseTheme,
- color: {
- ...darkBaseColor,
- accent: {
- default: themeColor['3rd'].primary,
- hover: themeColor['3rd'].secondary,
- subtle: color.cyan900,
- },
- },
- mode: 'dark',
- theme: '3rd',
-});
-
-createGlobalTheme('[data-theme="4th"]', vars, {
- ...baseTheme,
- color: {
- ...darkBaseColor,
- accent: {
- default: themeColor['4th'].primary,
- hover: themeColor['4th'].secondary,
- subtle: color.pink900,
- },
- },
- mode: 'dark',
- theme: '4th',
-});
+// TODO: dark is the default mode; light mode will be added later.
diff --git a/packages/tokens/src/theme/utils.test.ts b/packages/tokens/src/theme/utils.test.ts
new file mode 100644
index 00000000..99416780
--- /dev/null
+++ b/packages/tokens/src/theme/utils.test.ts
@@ -0,0 +1,35 @@
+import { describe, expect, it } from 'vitest';
+
+import { mapVars } from './utils';
+
+describe('mapVars', () => {
+ it('strips side- prefix from a leaf string', () => {
+ expect(mapVars('var(--side-spacing-component-xs)')).toBe('var(--spacing-component-xs)');
+ });
+
+ it('recursively transforms all leaves in a nested object', () => {
+ const input = {
+ component: {
+ xs: 'var(--side-spacing-component-xs)',
+ sm: 'var(--side-spacing-component-sm)',
+ },
+ layout: {
+ md: 'var(--side-spacing-layout-md)',
+ },
+ };
+
+ expect(mapVars(input)).toEqual({
+ component: {
+ xs: 'var(--spacing-component-xs)',
+ sm: 'var(--spacing-component-sm)',
+ },
+ layout: {
+ md: 'var(--spacing-layout-md)',
+ },
+ });
+ });
+
+ it('leaves strings without side- prefix unchanged', () => {
+ expect(mapVars('var(--color-background-base)')).toBe('var(--color-background-base)');
+ });
+});
diff --git a/packages/tokens/src/theme/utils.ts b/packages/tokens/src/theme/utils.ts
new file mode 100644
index 00000000..a1744f8f
--- /dev/null
+++ b/packages/tokens/src/theme/utils.ts
@@ -0,0 +1,15 @@
+export type MapLeaves = T extends string ? string : { [K in keyof T]: MapLeaves };
+
+export const cssVar = (token: string) => `var(--${token})`;
+
+/**
+ * Strips the `side-` prefix from every leaf value in a vars subtree,
+ * converting `'var(--side-*)'` references into SD CSS variable references (`'var(--*)'`).
+ *
+ * When the VE contract key and the SD token path don't match (e.g. typography),
+ * use cssVar() directly instead.
+ */
+export function mapVars(obj: T): MapLeaves {
+ if (typeof obj === 'string') return obj.replace('var(--side-', 'var(--') as MapLeaves;
+ return Object.fromEntries(Object.entries(obj as object).map(([k, v]) => [k, mapVars(v)])) as MapLeaves;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e702083f..f7619806 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1000,9 +1000,6 @@ importers:
'@sipe-team/tokens':
specifier: workspace:*
version: link:../tokens
- '@vanilla-extract/dynamic':
- specifier: 'catalog:'
- version: 2.1.5
devDependencies:
'@testing-library/jest-dom':
specifier: 'catalog:'