@cronus-ui/theme 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cronus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # @cronus-ui/theme
2
+
3
+ The Cronus UI runtime theming engine — a React provider and hook that apply
4
+ [`@cronus-ui/tokens`](../tokens) to your app and let you re-theme any subtree live.
5
+
6
+ Theming happens entirely through CSS custom properties: switching theme, toggling
7
+ light/dark, or overriding a token (radius, primary, border, …) updates the whole
8
+ subtree instantly **without re-rendering the components below it**. This is what
9
+ makes brand portals, per-tenant styling, and visual preview builders cheap.
10
+
11
+ You need this package if you render `@cronus-ui/ui` components and want runtime theme
12
+ control, mode switching, or token overrides. (It is also the only supported way to
13
+ inject the `--cronus-*` variables when running on Tailwind v3.)
14
+
15
+ ## Install
16
+
17
+ > Published on npm under the `@cronus-ui` scope.
18
+
19
+ ```sh
20
+ # npm
21
+ npm i @cronus-ui/theme @cronus-ui/tokens
22
+ # pnpm
23
+ pnpm add @cronus-ui/theme @cronus-ui/tokens
24
+ # bun
25
+ bun add @cronus-ui/theme @cronus-ui/tokens
26
+ ```
27
+
28
+ ### Prerequisites
29
+
30
+ - **React 19** (also works with React 18.3+) — `react` and `react-dom` are peer
31
+ dependencies.
32
+ - [`@cronus-ui/tokens`](../tokens) — the token data this provider applies (installed
33
+ alongside above; on Tailwind v4 also import `@cronus-ui/tokens/styles.css` once).
34
+
35
+ ## Usage
36
+
37
+ Wrap your app at the framework root. Use `asRoot` so the theme/mode attributes
38
+ are written to `<html>` and the whole document is themed.
39
+
40
+ ```tsx
41
+ // app/layout.tsx (Next.js App Router) — or your root component
42
+ import "@cronus-ui/tokens/styles.css";
43
+ import { CronusUIProvider } from "@cronus-ui/theme";
44
+
45
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
46
+ return (
47
+ <html lang="en">
48
+ <body>
49
+ <CronusUIProvider asRoot defaultThemeName="aurora" defaultModeName="dark">
50
+ {children}
51
+ </CronusUIProvider>
52
+ </body>
53
+ </html>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ### Avoiding a flash of the wrong theme
59
+
60
+ When you use `asRoot` with a `storageKey`, the provider restores the saved
61
+ theme/mode from `localStorage` in an effect that runs **after** first paint — so
62
+ a returning visitor whose saved choice differs from the defaults briefly sees the
63
+ default theme before it swaps (a "flash of the wrong theme", or FOUC).
64
+
65
+ Render `<CronusThemeScript>` in your document `<head>` to apply the saved
66
+ theme/mode **before** paint. It emits one tiny inline script that reads the same
67
+ `storageKey` and sets the `data-cronus-theme` / `data-cronus-mode` attributes and
68
+ the `dark` class on `<html>` exactly as the provider does.
69
+
70
+ ```tsx
71
+ // app/layout.tsx (Next.js App Router)
72
+ import { CronusThemeScript, CronusUIProvider } from "@cronus-ui/theme";
73
+
74
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
75
+ return (
76
+ // suppressHydrationWarning: the script mutates <html> before React hydrates.
77
+ <html lang="en" suppressHydrationWarning>
78
+ <head>
79
+ <CronusThemeScript
80
+ storageKey="cronus-ui-theme"
81
+ defaultThemeName="aurora"
82
+ defaultModeName="dark"
83
+ />
84
+ </head>
85
+ <body>
86
+ <CronusUIProvider asRoot storageKey="cronus-ui-theme">
87
+ {children}
88
+ </CronusUIProvider>
89
+ </body>
90
+ </html>
91
+ );
92
+ }
93
+ ```
94
+
95
+ Pass the **same** `storageKey` to both the script and the provider. Add
96
+ `suppressHydrationWarning` to `<html>` because the script changes those
97
+ attributes before hydration; without it React logs a hydration mismatch. For a
98
+ strict CSP, pass a `nonce` to `<CronusThemeScript nonce={nonce} />`.
99
+
100
+ ### `useTheme`
101
+
102
+ Read and control the active theme from anywhere inside the provider.
103
+
104
+ ```tsx
105
+ "use client";
106
+ import { useTheme } from "@cronus-ui/theme";
107
+
108
+ export function ThemeControls() {
109
+ const { theme, mode, setTheme, setMode, toggleMode, setOverrides } = useTheme();
110
+
111
+ return (
112
+ <div>
113
+ <button onClick={toggleMode}>Mode: {mode}</button>
114
+ <button onClick={() => setTheme(theme === "aurora" ? "neutral" : "aurora")}>
115
+ Theme: {theme}
116
+ </button>
117
+ {/* Re-theme the whole subtree at runtime — no component re-render: */}
118
+ <button
119
+ onClick={() =>
120
+ setOverrides({
121
+ radius: "16px",
122
+ primary: "oklch(0.685 0.169 237.3)",
123
+ fontDisplay: "Inter, sans-serif",
124
+ })
125
+ }
126
+ >
127
+ Apply brand theme
128
+ </button>
129
+ </div>
130
+ );
131
+ }
132
+ ```
133
+
134
+ Calling `useTheme()` outside a `<CronusUIProvider>` throws.
135
+
136
+ ## API
137
+
138
+ ### `<CronusUIProvider>`
139
+
140
+ | Prop | Type | Default | Description |
141
+ | ------------------ | ---------------- | ---------- | --------------------------------------------------------------------------- |
142
+ | `defaultThemeName` | `ThemeName` | `"aurora"` | Initial theme (`"aurora"` \| `"neutral"` \| `"midnight"` \| `"sunset"` \| `"emerald"`). |
143
+ | `defaultModeName` | `Mode` | `"dark"` | Initial mode (`"light"` \| `"dark"`). |
144
+ | `overrides` | `ThemeOverrides` | — | Seed per-scope token overrides (initial value only; later use `setOverrides`). |
145
+ | `asRoot` | `boolean` | `false` | Write attributes to `<html>` (whole document) instead of a wrapper `<div>`. |
146
+ | `storageKey` | `string` | — | Persist the theme/mode choice to `localStorage` under this key. |
147
+ | `className` | `string` | — | Extra classes for the wrapper `<div>` (ignored when `asRoot`). |
148
+
149
+ When `asRoot` is `false`, the provider renders a `<div>` that themes only its
150
+ subtree — useful for previews and isolated brand sections.
151
+
152
+ > `overrides` is reactive: change its **content** (e.g. from a controlled
153
+ > parent) and the themed element updates. A re-render that passes a new object of
154
+ > equal content does not loop or reset live overrides. `setOverrides` from
155
+ > `useTheme` still drives uncontrolled changes.
156
+
157
+ ### `<CronusThemeScript>`
158
+
159
+ Inline anti-FOUC head script (see [Avoiding a flash of the wrong
160
+ theme](#avoiding-a-flash-of-the-wrong-theme)).
161
+
162
+ | Prop | Type | Default | Description |
163
+ | ------------------ | ----------- | ---------- | ----------------------------------------------------------------- |
164
+ | `storageKey` | `string` | — | Required. The same key passed to `<CronusUIProvider storageKey>`. |
165
+ | `defaultThemeName` | `ThemeName` | `"aurora"` | Theme applied when storage is empty or unreadable. |
166
+ | `defaultModeName` | `Mode` | `"dark"` | Mode applied when storage is empty or unreadable. |
167
+ | `nonce` | `string` | — | CSP nonce forwarded to the inline `<script>`. |
168
+
169
+ ### `useTheme(): ThemeContextValue`
170
+
171
+ Returns `{ theme, mode, overrides, setTheme, setMode, toggleMode, setOverrides }`.
172
+ `ThemeName`, `Mode`, and `ThemeOverrides` come from [`@cronus-ui/tokens`](../tokens).
173
+
174
+ ## How it works
175
+
176
+ `overrides` are converted to a `{ "--cronus-*": value }` style object
177
+ (via `@cronus-ui/tokens`) and set on the themed element; the `@cronus-ui/tokens` Tailwind
178
+ bridge maps utilities like `bg-primary` and `rounded-lg` onto those variables.
179
+ Because everything resolves through CSS variables, overriding a token restyles the
180
+ subtree with no React re-render of the components it contains.
181
+
182
+ ## Related packages
183
+
184
+ - [`@cronus-ui/tokens`](../tokens) — the token source this provider applies.
185
+ - [`@cronus-ui/ui`](../ui) — the components that render against the applied tokens.
186
+ - See the [docs site](../../apps/www) for the live theme builder.
187
+
188
+ ## License
189
+
190
+ MIT
@@ -0,0 +1,7 @@
1
+ export type { CronusUIProviderProps } from "./provider.js";
2
+ export { CronusUIProvider } from "./provider.js";
3
+ export type { CronusThemeScriptProps } from "./theme-script.js";
4
+ export { CronusThemeScript } from "./theme-script.js";
5
+ export type { ThemeContextValue } from "./use-theme.js";
6
+ export { useOptionalThemeMode, useTheme } from "./use-theme.js";
7
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { CronusUIProvider } from "./provider.js";
2
+ export { CronusThemeScript } from "./theme-script.js";
3
+ export { useOptionalThemeMode, useTheme } from "./use-theme.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,27 @@
1
+ import { type Mode, type ThemeName, type ThemeOverrides } from "@cronus-ui/tokens";
2
+ import { type ReactNode } from "react";
3
+ export interface CronusUIProviderProps {
4
+ children: ReactNode;
5
+ /** Initial theme. @default "aurora" */
6
+ defaultThemeName?: ThemeName;
7
+ /** Initial mode. @default "dark" */
8
+ defaultModeName?: Mode;
9
+ /** Per-scope token overrides (radius, primary, border, ...). */
10
+ overrides?: ThemeOverrides;
11
+ /**
12
+ * When true, attributes are written to <html> so the whole document is
13
+ * themed. When false (default), they are written to a wrapper <div> so a
14
+ * subtree can be themed independently (useful for the ThemeBuilder preview).
15
+ */
16
+ asRoot?: boolean;
17
+ /** Persist theme/mode choice to localStorage under this key. */
18
+ storageKey?: string;
19
+ className?: string;
20
+ }
21
+ /**
22
+ * Themes its subtree purely via CSS custom properties — no per-component
23
+ * re-render, no context churn beyond the controls themselves. Overriding
24
+ * `radius`, `primary`, `border`, etc. updates the entire subtree instantly.
25
+ */
26
+ export declare function CronusUIProvider({ children, defaultThemeName, defaultModeName, overrides, asRoot, storageKey, className, }: CronusUIProviderProps): import("react").JSX.Element;
27
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1,110 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { defaultMode, defaultTheme, tokensToCssVars, } from "@cronus-ui/tokens";
4
+ import { useCallback, useEffect, useMemo, useState } from "react";
5
+ import { ThemeContext } from "./use-theme.js";
6
+ function applyRootAttributes(theme, mode) {
7
+ if (typeof document === "undefined")
8
+ return;
9
+ const el = document.documentElement;
10
+ el.dataset.cronusTheme = theme;
11
+ el.dataset.cronusMode = mode;
12
+ el.classList.toggle("dark", mode === "dark");
13
+ }
14
+ /**
15
+ * Themes its subtree purely via CSS custom properties — no per-component
16
+ * re-render, no context churn beyond the controls themselves. Overriding
17
+ * `radius`, `primary`, `border`, etc. updates the entire subtree instantly.
18
+ */
19
+ export function CronusUIProvider({ children, defaultThemeName = defaultTheme, defaultModeName = defaultMode, overrides, asRoot = false, storageKey, className, }) {
20
+ const [theme, setThemeState] = useState(defaultThemeName);
21
+ const [mode, setModeState] = useState(defaultModeName);
22
+ // `overrides` seeds the initial value; the effect below keeps it in sync when
23
+ // the prop's CONTENT changes (controlled usage), while setScopedOverrides
24
+ // still drives uncontrolled changes via setOverrides() (e.g. the
25
+ // ThemeBuilder). Syncing on a stable serialization — not the object identity —
26
+ // means a re-render with an equal-content new reference neither loops nor
27
+ // resets the live overrides.
28
+ const [scopedOverrides, setScopedOverrides] = useState(() => overrides ?? {});
29
+ // Make the controlled `overrides` prop reactive. Keying on the JSON instead of
30
+ // the object reference avoids the infinite loop an inline `overrides={{...}}`
31
+ // (new reference every render) would otherwise cause.
32
+ const overridesKey = JSON.stringify(overrides ?? {});
33
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `overridesKey` is the stable serialization of `overrides`; depending on the object reference is exactly what we must avoid.
34
+ useEffect(() => {
35
+ setScopedOverrides(overrides ?? {});
36
+ }, [overridesKey]);
37
+ // Hydrate from storage once on mount.
38
+ useEffect(() => {
39
+ if (!storageKey || typeof window === "undefined")
40
+ return;
41
+ try {
42
+ const raw = window.localStorage.getItem(storageKey);
43
+ if (!raw)
44
+ return;
45
+ const saved = JSON.parse(raw);
46
+ if (saved.theme)
47
+ setThemeState(saved.theme);
48
+ if (saved.mode)
49
+ setModeState(saved.mode);
50
+ }
51
+ catch {
52
+ // ignore malformed storage
53
+ }
54
+ }, [storageKey]);
55
+ const persist = useCallback((next) => {
56
+ if (!storageKey || typeof window === "undefined")
57
+ return;
58
+ try {
59
+ window.localStorage.setItem(storageKey, JSON.stringify(next));
60
+ }
61
+ catch {
62
+ // ignore quota / privacy errors
63
+ }
64
+ }, [storageKey]);
65
+ const setTheme = useCallback((next) => {
66
+ setThemeState(next);
67
+ persist({ theme: next, mode });
68
+ }, [mode, persist]);
69
+ const setMode = useCallback((next) => {
70
+ setModeState(next);
71
+ persist({ theme, mode: next });
72
+ }, [theme, persist]);
73
+ const toggleMode = useCallback(() => {
74
+ setModeState((prev) => {
75
+ const next = prev === "dark" ? "light" : "dark";
76
+ persist({ theme, mode: next });
77
+ return next;
78
+ });
79
+ }, [theme, persist]);
80
+ // Sync <html> attributes + overrides when used as the document root.
81
+ useEffect(() => {
82
+ if (!asRoot)
83
+ return;
84
+ applyRootAttributes(theme, mode);
85
+ if (typeof document === "undefined")
86
+ return;
87
+ const el = document.documentElement;
88
+ const vars = tokensToCssVars(scopedOverrides);
89
+ for (const [prop, val] of Object.entries(vars))
90
+ el.style.setProperty(prop, val);
91
+ return () => {
92
+ for (const prop of Object.keys(vars))
93
+ el.style.removeProperty(prop);
94
+ };
95
+ }, [asRoot, theme, mode, scopedOverrides]);
96
+ const value = useMemo(() => ({
97
+ theme,
98
+ mode,
99
+ overrides: scopedOverrides,
100
+ setTheme,
101
+ setMode,
102
+ toggleMode,
103
+ setOverrides: setScopedOverrides,
104
+ }), [theme, mode, scopedOverrides, setTheme, setMode, toggleMode]);
105
+ const style = useMemo(() => tokensToCssVars(scopedOverrides), [scopedOverrides]);
106
+ return (_jsx(ThemeContext.Provider, { value: value, children: asRoot ? (children) : (_jsx("div", { "data-cronus-theme": theme, "data-cronus-mode": mode, className: [mode === "dark" ? "dark" : null, "text-fg", className]
107
+ .filter(Boolean)
108
+ .join(" "), style: style, children: children })) }));
109
+ }
110
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1,34 @@
1
+ import { type Mode, type ThemeName } from "@cronus-ui/tokens";
2
+ export interface CronusThemeScriptProps {
3
+ /**
4
+ * The same `storageKey` passed to `<CronusUIProvider>`. The script reads the
5
+ * persisted `{ theme, mode }` from `localStorage[storageKey]`.
6
+ */
7
+ storageKey: string;
8
+ /** Theme to apply when storage is empty/unreadable. @default "aurora" */
9
+ defaultThemeName?: ThemeName;
10
+ /** Mode to apply when storage is empty/unreadable. @default "dark" */
11
+ defaultModeName?: Mode;
12
+ /** CSP nonce forwarded to the inline `<script nonce>`. */
13
+ nonce?: string;
14
+ }
15
+ /**
16
+ * Inline head script that applies the persisted theme/mode to `<html>` BEFORE
17
+ * first paint, eliminating the flash of the default theme that otherwise occurs
18
+ * while `<CronusUIProvider asRoot storageKey>` hydrates from `localStorage` in a
19
+ * post-paint effect.
20
+ *
21
+ * Place it inside `<head>` (above the app) and add `suppressHydrationWarning` to
22
+ * the `<html>` element, since this mutates `<html>` before React hydrates.
23
+ *
24
+ * ```tsx
25
+ * <html lang="en" suppressHydrationWarning>
26
+ * <head>
27
+ * <CronusThemeScript storageKey="theme" defaultThemeName="aurora" defaultModeName="dark" />
28
+ * </head>
29
+ * ...
30
+ * </html>
31
+ * ```
32
+ */
33
+ export declare function CronusThemeScript({ storageKey, defaultThemeName, defaultModeName, nonce, }: CronusThemeScriptProps): import("react").JSX.Element;
34
+ //# sourceMappingURL=theme-script.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { defaultMode, defaultTheme } from "@cronus-ui/tokens";
3
+ /**
4
+ * Builds the dependency-free IIFE source. The body mirrors the provider's
5
+ * `applyRootAttributes` byte-for-byte (dataset.cronusTheme / dataset.cronusMode /
6
+ * classList.toggle("dark", …)) so the pre-paint state matches what React would
7
+ * compute on hydration. All interpolated values are `JSON.stringify`-encoded so
8
+ * a storage key or default containing quotes can't break out of the script.
9
+ */
10
+ function buildScript(storageKey, defaultThemeName, defaultModeName) {
11
+ // Defaults are applied first and the storage read overrides them, so a quota /
12
+ // malformed-JSON throw still leaves <html> on the SSR default the provider
13
+ // reconciles to on hydration (rather than a bare, attribute-less root).
14
+ return `(function(){var d=document.documentElement,t=${JSON.stringify(defaultThemeName)},m=${JSON.stringify(defaultModeName)};try{var s=localStorage.getItem(${JSON.stringify(storageKey)});if(s){var p=JSON.parse(s);if(p&&p.theme)t=p.theme;if(p&&p.mode)m=p.mode;}}catch(e){}d.dataset.cronusTheme=t;d.dataset.cronusMode=m;d.classList.toggle("dark",m==="dark");})();`;
15
+ }
16
+ /**
17
+ * Inline head script that applies the persisted theme/mode to `<html>` BEFORE
18
+ * first paint, eliminating the flash of the default theme that otherwise occurs
19
+ * while `<CronusUIProvider asRoot storageKey>` hydrates from `localStorage` in a
20
+ * post-paint effect.
21
+ *
22
+ * Place it inside `<head>` (above the app) and add `suppressHydrationWarning` to
23
+ * the `<html>` element, since this mutates `<html>` before React hydrates.
24
+ *
25
+ * ```tsx
26
+ * <html lang="en" suppressHydrationWarning>
27
+ * <head>
28
+ * <CronusThemeScript storageKey="theme" defaultThemeName="aurora" defaultModeName="dark" />
29
+ * </head>
30
+ * ...
31
+ * </html>
32
+ * ```
33
+ */
34
+ export function CronusThemeScript({ storageKey, defaultThemeName = defaultTheme, defaultModeName = defaultMode, nonce, }) {
35
+ return (_jsx("script", {
36
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: required to inline a pre-paint anti-FOUC script; all interpolated values are JSON.stringify-encoded.
37
+ dangerouslySetInnerHTML: {
38
+ __html: buildScript(storageKey, defaultThemeName, defaultModeName),
39
+ }, nonce: nonce }));
40
+ }
41
+ //# sourceMappingURL=theme-script.js.map
@@ -0,0 +1,15 @@
1
+ import type { Mode, ThemeName, ThemeOverrides } from "@cronus-ui/tokens";
2
+ export interface ThemeContextValue {
3
+ theme: ThemeName;
4
+ mode: Mode;
5
+ overrides: ThemeOverrides;
6
+ setTheme: (theme: ThemeName) => void;
7
+ setMode: (mode: Mode) => void;
8
+ toggleMode: () => void;
9
+ setOverrides: (overrides: ThemeOverrides) => void;
10
+ }
11
+ export declare const ThemeContext: import("react").Context<ThemeContextValue | null>;
12
+ export declare function useTheme(): ThemeContextValue;
13
+ /** Mode from the nearest provider, or null outside one. */
14
+ export declare function useOptionalThemeMode(): Mode | null;
15
+ //# sourceMappingURL=use-theme.d.ts.map
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { createContext, useContext } from "react";
3
+ export const ThemeContext = createContext(null);
4
+ export function useTheme() {
5
+ const ctx = useContext(ThemeContext);
6
+ if (!ctx) {
7
+ throw new Error("useTheme must be used within a <CronusUIProvider>");
8
+ }
9
+ return ctx;
10
+ }
11
+ /** Mode from the nearest provider, or null outside one. */
12
+ export function useOptionalThemeMode() {
13
+ return useContext(ThemeContext)?.mode ?? null;
14
+ }
15
+ //# sourceMappingURL=use-theme.js.map
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@cronus-ui/theme",
3
+ "version": "0.6.0",
4
+ "description": "Cronus runtime theming engine — CronusUIProvider + useTheme (CSS-var only, no re-render).",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "sideEffects": false,
15
+ "license": "MIT",
16
+ "author": "Cronus",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/pedrogbraz/cronus-ui.git",
20
+ "directory": "packages/theme"
21
+ },
22
+ "homepage": "https://aicronus.com",
23
+ "bugs": {
24
+ "url": "https://github.com/pedrogbraz/cronus-ui/issues"
25
+ },
26
+ "keywords": [
27
+ "cronus",
28
+ "design-system",
29
+ "react",
30
+ "tailwind",
31
+ "ui",
32
+ "components"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "LICENSE",
40
+ "README.md",
41
+ "!dist/**/*.map"
42
+ ],
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.json",
45
+ "typecheck": "tsc -p tsconfig.json --noEmit",
46
+ "prepublishOnly": "tsc -p tsconfig.json"
47
+ },
48
+ "dependencies": {
49
+ "@cronus-ui/tokens": "0.6.0"
50
+ },
51
+ "peerDependencies": {
52
+ "react": "^18.3.0 || ^19.0.0",
53
+ "react-dom": "^18.3.0 || ^19.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/react": "^19.0.0",
57
+ "@types/react-dom": "^19.0.0",
58
+ "react": "^19.2.0",
59
+ "react-dom": "^19.2.0",
60
+ "typescript": "^6.0.3",
61
+ "vitest": "^4.1.9"
62
+ }
63
+ }