@lpdsgn/astro-themes 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -159,7 +159,7 @@ Now use dark-mode classes:
159
159
 
160
160
  ### Integration Options
161
161
 
162
- For centralized configuration without using `ThemeProvider`, configure the integration directly:
162
+ The integration can be configured in your `astro.config.mjs`:
163
163
 
164
164
  ```js frame="code" title="astro.config.mjs"
165
165
  import { defineConfig } from "astro/config";
@@ -168,13 +168,7 @@ import astroThemes from "@lpdsgn/astro-themes";
168
168
  export default defineConfig({
169
169
  integrations: [
170
170
  astroThemes({
171
- injectScript: true, // Auto-inject theme script
172
- defaultProps: {
173
- attribute: "class",
174
- defaultTheme: "system",
175
- themes: ["light", "dark"],
176
- },
177
- devToolbar: true, // Enable Dev Toolbar App
171
+ devToolbar: true, // Enable Dev Toolbar App (default: true)
178
172
  }),
179
173
  ],
180
174
  });
@@ -182,11 +176,7 @@ export default defineConfig({
182
176
 
183
177
  | Option | Type | Default | Description |
184
178
  |--------|------|---------|-------------|
185
- | `injectScript` | `boolean` | `false` | Auto-inject theme script (no `ThemeProvider` needed) |
186
- | `defaultProps` | `object` | `{}` | Default theme configuration (same options as **[ThemeProvider Props](#themeprovider-props)**) |
187
- | `devToolbar` | `boolean` | `true` | Enable the Dev Toolbar App |
188
-
189
- > **Tip:** Use `injectScript: true` for consistent settings across all pages. You can still use `ThemeProvider` with `forcedTheme` on specific pages.
179
+ | `devToolbar` | `boolean` | `true` | Enable the Dev Toolbar App for theme switching during development |
190
180
 
191
181
  ## Examples
192
182
 
@@ -0,0 +1,27 @@
1
+ // Type declarations for Astro components
2
+ import type { ThemeProviderProps } from "../types.js";
3
+
4
+ /**
5
+ * ThemeProvider component for managing themes in Astro applications.
6
+ * Place this component inside the `<head>` tag of your layout.
7
+ *
8
+ * @param {string} [storageKey='theme'] - Key used to store theme setting in localStorage
9
+ * @param {string} [defaultTheme='system'] - Default theme name. If `enableSystem` is false, the default theme is 'light'
10
+ * @param {string} [forcedTheme] - Forced theme name for the current page (does not modify saved theme settings)
11
+ * @param {boolean} [enableSystem=true] - Whether to switch themes based on `prefers-color-scheme`
12
+ * @param {boolean} [enableColorScheme=true] - Whether to indicate color scheme to browsers
13
+ * @param {boolean} [disableTransitionOnChange=false] - Disable CSS transitions when switching themes
14
+ * @param {string[]} [themes=['light', 'dark']] - List of theme names
15
+ * @param {Attribute} [attribute='data-theme'] - HTML attribute to apply the theme. Accepts `class` and `data-*` (meaning any data attribute, `data-mode`, `data-color`, etc.). Can also be an array to set multiple attributes
16
+ * @param {ValueObject} [value] - Map theme names to custom attribute values, eg. `{ dark: 'dark-mode', light: 'light-mode' }`
17
+ * @param {string} [nonce] - Optional nonce passed to the injected `script` tag, used to allow-list the script in your CSP
18
+ * @param {ScriptProps} [scriptProps] - Additional props to pass to the internal script tag
19
+ *
20
+ * @example
21
+ * ```astro
22
+ * <head>
23
+ * <ThemeProvider attribute="class" defaultTheme="system" />
24
+ * </head>
25
+ * ```
26
+ */
27
+ export declare function ThemeProvider(props: ThemeProviderProps): any;
package/dist/index.d.ts CHANGED
@@ -3,18 +3,6 @@ export { AstroThemesConfig, Attribute, ScriptProps, ThemeProviderProps, ThemeSta
3
3
  export { getResolvedTheme, getSystemTheme, getTheme, getThemes, isForcedTheme, onThemeChange, setTheme, toggleTheme } from './client.js';
4
4
 
5
5
  declare const integration: (options?: {
6
- injectScript?: boolean | undefined;
7
- defaultProps?: {
8
- storageKey?: string | undefined;
9
- defaultTheme?: string | undefined;
10
- forcedTheme?: string | undefined;
11
- enableSystem?: boolean | undefined;
12
- enableColorScheme?: boolean | undefined;
13
- disableTransitionOnChange?: boolean | undefined;
14
- value?: Record<string, string> | undefined;
15
- themes?: string[] | undefined;
16
- attribute?: string | string[] | undefined;
17
- } | undefined;
18
6
  devToolbar?: boolean | undefined;
19
7
  } | undefined) => astro.AstroIntegration & {};
20
8
 
package/dist/index.js CHANGED
@@ -1,55 +1,4 @@
1
- import{defineIntegration as c}from"astro-integration-kit";import{z as e}from"astro/zod";function g(r,t,n,o,a,s,m,h){return`
2
- (function() {
3
- var el = document.documentElement;
4
- var attribute = ${JSON.stringify(r)};
5
- var storageKey = ${JSON.stringify(t)};
6
- var defaultTheme = ${JSON.stringify(n)};
7
- var forcedTheme = ${JSON.stringify(o)};
8
- var themes = ${JSON.stringify(a)};
9
- var value = ${JSON.stringify(s)};
10
- var enableSystem = ${JSON.stringify(m)};
11
- var enableColorScheme = ${JSON.stringify(h)};
12
- var systemThemes = ['light', 'dark'];
13
-
14
- function updateDOM(theme) {
15
- var attributes = Array.isArray(attribute) ? attribute : [attribute];
16
- attributes.forEach(function(attr) {
17
- var isClass = attr === 'class';
18
- var classes = isClass && value ? themes.map(function(t) { return value[t] || t; }) : themes;
19
- if (isClass) {
20
- el.classList.remove.apply(el.classList, classes);
21
- el.classList.add(value && value[theme] ? value[theme] : theme);
22
- } else {
23
- el.setAttribute(attr, value && value[theme] ? value[theme] : theme);
24
- }
25
- });
26
- setColorScheme(theme);
27
- }
28
-
29
- function setColorScheme(theme) {
30
- if (enableColorScheme && systemThemes.indexOf(theme) !== -1) {
31
- el.style.colorScheme = theme;
32
- }
33
- }
34
-
35
- function getSystemTheme() {
36
- return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
37
- }
38
-
39
- if (forcedTheme) {
40
- updateDOM(forcedTheme);
41
- } else {
42
- try {
43
- var themeName = localStorage.getItem(storageKey) || defaultTheme;
44
- var isSystem = enableSystem && themeName === 'system';
45
- var theme = isSystem ? getSystemTheme() : themeName;
46
- updateDOM(theme);
47
- } catch (e) {
48
- updateDOM(defaultTheme === 'system' && enableSystem ? getSystemTheme() : defaultTheme);
49
- }
50
- }
51
- })();
52
- `.trim()}function l(r,t,n,o,a,s,m,h){return g(r,t,n,o,a,s,m,h).replace(/\s+/g," ").replace(/\s*{\s*/g,"{").replace(/\s*}\s*/g,"}").replace(/\s*;\s*/g,";").replace(/\s*,\s*/g,",").replace(/\s*\(\s*/g,"(").replace(/\s*\)\s*/g,")").trim()}var f="theme",u="system",p=["light","dark"],T="data-theme",v=e.object({injectScript:e.boolean().default(!1),defaultProps:e.object({storageKey:e.string().default(f),defaultTheme:e.string().default(u),forcedTheme:e.string().optional(),enableSystem:e.boolean().default(!0),enableColorScheme:e.boolean().default(!0),disableTransitionOnChange:e.boolean().default(!1),themes:e.array(e.string()).default(p),attribute:e.union([e.string(),e.array(e.string())]).default(T),value:e.record(e.string()).optional()}).default({}),devToolbar:e.boolean().default(!0)}).default({}),d=c({name:"astro-themes",optionsSchema:v,setup({options:r}){return{hooks:{"astro:config:setup":({logger:t,injectScript:n,addDevToolbarApp:o,command:a})=>{if(t.info("astro-themes initialized"),r.injectScript){let s=r.defaultProps,m=l(s.attribute,s.storageKey,s.defaultTheme,s.forcedTheme,s.themes,s.value,s.enableSystem,s.enableColorScheme);n("head-inline",m),t.info("Flash-prevention script injected via integration")}r.devToolbar&&a==="dev"&&(o({id:"astro-themes-toolbar",name:"Theme Switcher",icon:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>',entrypoint:"@lpdsgn/astro-themes/toolbar"}),t.debug("Dev Toolbar App registered"))},"astro:config:done":({injectTypes:t})=>{t({filename:"types.d.ts",content:`declare global {
1
+ import{defineIntegration as h}from"astro-integration-kit";import{z as n}from"astro/zod";var m=n.object({devToolbar:n.boolean().default(!0)}).default({}),i=h({name:"astro-themes",optionsSchema:m,setup({options:t}){return{hooks:{"astro:config:setup":({logger:e,addDevToolbarApp:r,command:s})=>{e.info("astro-themes initialized"),t.devToolbar&&s==="dev"&&(r({id:"astro-themes-toolbar",name:"Theme Switcher",icon:'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>',entrypoint:"@lpdsgn/astro-themes/toolbar"}),e.debug("Dev Toolbar App registered"))},"astro:config:done":({injectTypes:e})=>{e({filename:"types.d.ts",content:`declare global {
53
2
  interface Window {
54
3
  __ASTRO_THEMES__?: {
55
4
  theme: string;
@@ -61,5 +10,5 @@ import{defineIntegration as c}from"astro-integration-kit";import{z as e}from"ast
61
10
  };
62
11
  }
63
12
  }
64
- export {};`})}}}}});function i(){if(!(typeof window>"u"))return window.__ASTRO_THEMES__}function y(r){let t=i();t&&t.setTheme(r)}function S(){return i()?.resolvedTheme}function b(){return i()?.systemTheme}function E(){return!!i()?.forcedTheme}function w(){return i()?.themes??[]}function x(r){if(typeof window>"u")return()=>{};let t=n=>{r(n.detail)};return window.addEventListener("astro-themes:change",t),()=>{window.removeEventListener("astro-themes:change",t)}}function _(){let r=i();if(!r)return;let t=r.resolvedTheme;r.setTheme(t==="light"?"dark":"light")}var D=d;export{D as default,S as getResolvedTheme,b as getSystemTheme,i as getTheme,w as getThemes,d as integration,E as isForcedTheme,x as onThemeChange,y as setTheme,_ as toggleTheme};
13
+ export {};`})}}}}});function o(){if(!(typeof window>"u"))return window.__ASTRO_THEMES__}function d(t){let e=o();e&&e.setTheme(t)}function a(){return o()?.resolvedTheme}function p(){return o()?.systemTheme}function g(){return!!o()?.forcedTheme}function T(){return o()?.themes??[]}function f(t){if(typeof window>"u")return()=>{};let e=r=>{t(r.detail)};return window.addEventListener("astro-themes:change",e),()=>{window.removeEventListener("astro-themes:change",e)}}function l(){let t=o();if(!t)return;let e=t.resolvedTheme;t.setTheme(e==="light"?"dark":"light")}var y=i;export{y as default,a as getResolvedTheme,p as getSystemTheme,o as getTheme,T as getThemes,i as integration,g as isForcedTheme,f as onThemeChange,d as setTheme,l as toggleTheme};
65
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/integration.ts","../src/script.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["import { defineIntegration } from \"astro-integration-kit\";\nimport { z } from \"astro/zod\";\nimport type { AstroThemesConfig, ThemeProviderProps } from \"./types.js\";\nimport { getMinifiedInlineScript } from \"./script.js\";\n\n// Default configuration values\nconst DEFAULT_STORAGE_KEY = \"theme\";\nconst DEFAULT_THEME = \"system\";\nconst DEFAULT_THEMES = [\"light\", \"dark\"];\nconst DEFAULT_ATTRIBUTE = \"data-theme\";\n\n// Options schema for the integration\nconst optionsSchema = z\n\t.object({\n\t\t/**\n\t\t * Inject the flash-prevention script automatically via integration\n\t\t * When true, you don't need to use ThemeProvider component\n\t\t * @default false\n\t\t */\n\t\tinjectScript: z.boolean().default(false),\n\t\t/**\n\t\t * Default theme configuration used when injectScript is true\n\t\t */\n\t\tdefaultProps: z\n\t\t\t.object({\n\t\t\t\tstorageKey: z.string().default(DEFAULT_STORAGE_KEY),\n\t\t\t\tdefaultTheme: z.string().default(DEFAULT_THEME),\n\t\t\t\tforcedTheme: z.string().optional(),\n\t\t\t\tenableSystem: z.boolean().default(true),\n\t\t\t\tenableColorScheme: z.boolean().default(true),\n\t\t\t\tdisableTransitionOnChange: z.boolean().default(false),\n\t\t\t\tthemes: z.array(z.string()).default(DEFAULT_THEMES),\n\t\t\t\tattribute: z\n\t\t\t\t\t.union([z.string(), z.array(z.string())])\n\t\t\t\t\t.default(DEFAULT_ATTRIBUTE),\n\t\t\t\tvalue: z.record(z.string()).optional(),\n\t\t\t})\n\t\t\t.default({}),\n\t\t/**\n\t\t * Enable the Dev Toolbar App for theme switching during development\n\t\t * @default true\n\t\t */\n\t\tdevToolbar: z.boolean().default(true),\n\t})\n\t.default({});\n\nexport const integration = defineIntegration({\n\tname: \"astro-themes\",\n\toptionsSchema,\n\tsetup({ options }) {\n\t\treturn {\n\t\t\thooks: {\n\t\t\t\t\"astro:config:setup\": ({\n\t\t\t\t\tlogger,\n\t\t\t\t\tinjectScript,\n\t\t\t\t\taddDevToolbarApp,\n\t\t\t\t\tcommand,\n\t\t\t\t}) => {\n\t\t\t\t\tlogger.info(\"astro-themes initialized\");\n\n\t\t\t\t\t// Inject flash-prevention script if enabled\n\t\t\t\t\tif (options.injectScript) {\n\t\t\t\t\t\tconst props = options.defaultProps;\n\t\t\t\t\t\tconst script = getMinifiedInlineScript(\n\t\t\t\t\t\t\tprops.attribute,\n\t\t\t\t\t\t\tprops.storageKey,\n\t\t\t\t\t\t\tprops.defaultTheme,\n\t\t\t\t\t\t\tprops.forcedTheme,\n\t\t\t\t\t\t\tprops.themes,\n\t\t\t\t\t\t\tprops.value,\n\t\t\t\t\t\t\tprops.enableSystem,\n\t\t\t\t\t\t\tprops.enableColorScheme\n\t\t\t\t\t\t);\n\t\t\t\t\t\tinjectScript(\"head-inline\", script);\n\t\t\t\t\t\tlogger.info(\"Flash-prevention script injected via integration\");\n\t\t\t\t\t}\n\n\t\t\t\t\t// Add Dev Toolbar App in dev mode\n\t\t\t\t\tif (options.devToolbar && command === \"dev\") {\n\t\t\t\t\t\taddDevToolbarApp({\n\t\t\t\t\t\t\tid: \"astro-themes-toolbar\",\n\t\t\t\t\t\t\tname: \"Theme Switcher\",\n\t\t\t\t\t\t\ticon: `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"4\"/><path d=\"M12 2v2\"/><path d=\"M12 20v2\"/><path d=\"m4.93 4.93 1.41 1.41\"/><path d=\"m17.66 17.66 1.41 1.41\"/><path d=\"M2 12h2\"/><path d=\"M20 12h2\"/><path d=\"m6.34 17.66-1.41 1.41\"/><path d=\"m19.07 4.93-1.41 1.41\"/></svg>`,\n\t\t\t\t\t\t\tentrypoint: \"@lpdsgn/astro-themes/toolbar\",\n\t\t\t\t\t\t});\n\t\t\t\t\t\tlogger.debug(\"Dev Toolbar App registered\");\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"astro:config:done\": ({ injectTypes }) => {\n\t\t\t\t\t// Inject global types for window.__ASTRO_THEMES__\n\t\t\t\t\tinjectTypes({\n\t\t\t\t\t\tfilename: \"types.d.ts\",\n\t\t\t\t\t\tcontent: `declare global {\n interface Window {\n __ASTRO_THEMES__?: {\n theme: string;\n resolvedTheme: string;\n systemTheme: \"dark\" | \"light\";\n forcedTheme?: string;\n themes: string[];\n setTheme: (theme: string | ((prevTheme: string) => string)) => void;\n };\n }\n}\nexport {};`,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t},\n});\n\nexport type { AstroThemesConfig, ThemeProviderProps };\n","/**\n * Inline script that runs before page render to prevent flash\n * This script is injected into the head and executes immediately\n */\nexport function getInlineScript(\n\tattribute: string | string[],\n\tstorageKey: string,\n\tdefaultTheme: string,\n\tforcedTheme: string | undefined,\n\tthemes: string[],\n\tvalue: Record<string, string> | undefined,\n\tenableSystem: boolean,\n\tenableColorScheme: boolean\n): string {\n\t// The script must be minified and self-contained\n\tconst script = `\n(function() {\n var el = document.documentElement;\n var attribute = ${JSON.stringify(attribute)};\n var storageKey = ${JSON.stringify(storageKey)};\n var defaultTheme = ${JSON.stringify(defaultTheme)};\n var forcedTheme = ${JSON.stringify(forcedTheme)};\n var themes = ${JSON.stringify(themes)};\n var value = ${JSON.stringify(value)};\n var enableSystem = ${JSON.stringify(enableSystem)};\n var enableColorScheme = ${JSON.stringify(enableColorScheme)};\n var systemThemes = ['light', 'dark'];\n\n function updateDOM(theme) {\n var attributes = Array.isArray(attribute) ? attribute : [attribute];\n attributes.forEach(function(attr) {\n var isClass = attr === 'class';\n var classes = isClass && value ? themes.map(function(t) { return value[t] || t; }) : themes;\n if (isClass) {\n el.classList.remove.apply(el.classList, classes);\n el.classList.add(value && value[theme] ? value[theme] : theme);\n } else {\n el.setAttribute(attr, value && value[theme] ? value[theme] : theme);\n }\n });\n setColorScheme(theme);\n }\n\n function setColorScheme(theme) {\n if (enableColorScheme && systemThemes.indexOf(theme) !== -1) {\n el.style.colorScheme = theme;\n }\n }\n\n function getSystemTheme() {\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n if (forcedTheme) {\n updateDOM(forcedTheme);\n } else {\n try {\n var themeName = localStorage.getItem(storageKey) || defaultTheme;\n var isSystem = enableSystem && themeName === 'system';\n var theme = isSystem ? getSystemTheme() : themeName;\n updateDOM(theme);\n } catch (e) {\n updateDOM(defaultTheme === 'system' && enableSystem ? getSystemTheme() : defaultTheme);\n }\n }\n})();\n`.trim();\n\n\treturn script;\n}\n\n/**\n * Returns a minified version of the inline script\n */\nexport function getMinifiedInlineScript(\n\tattribute: string | string[],\n\tstorageKey: string,\n\tdefaultTheme: string,\n\tforcedTheme: string | undefined,\n\tthemes: string[],\n\tvalue: Record<string, string> | undefined,\n\tenableSystem: boolean,\n\tenableColorScheme: boolean\n): string {\n\t// Minified version for production\n\treturn getInlineScript(\n\t\tattribute,\n\t\tstorageKey,\n\t\tdefaultTheme,\n\t\tforcedTheme,\n\t\tthemes,\n\t\tvalue,\n\t\tenableSystem,\n\t\tenableColorScheme\n\t)\n\t\t.replace(/\\s+/g, \" \")\n\t\t.replace(/\\s*{\\s*/g, \"{\")\n\t\t.replace(/\\s*}\\s*/g, \"}\")\n\t\t.replace(/\\s*;\\s*/g, \";\")\n\t\t.replace(/\\s*,\\s*/g, \",\")\n\t\t.replace(/\\s*\\(\\s*/g, \"(\")\n\t\t.replace(/\\s*\\)\\s*/g, \")\")\n\t\t.trim();\n}\n","/**\n * Client-side helpers for interacting with the theme\n * These are meant to be used in client-side scripts\n */\n\nimport type { ThemeState } from \"./types.js\";\n\ndeclare global {\n\tinterface Window {\n\t\t__ASTRO_THEMES__?: ThemeState;\n\t}\n}\n\n/**\n * Get the current theme state\n * Returns undefined if ThemeProvider is not mounted\n */\nexport function getTheme(): ThemeState | undefined {\n\tif (typeof window === \"undefined\") return undefined;\n\treturn window.__ASTRO_THEMES__;\n}\n\n/**\n * Set the theme\n * @param theme - Theme name or function that receives current theme and returns new theme\n */\nexport function setTheme(theme: string | ((prevTheme: string) => string)): void {\n\tconst state = getTheme();\n\tif (state) {\n\t\tstate.setTheme(theme);\n\t}\n}\n\n/**\n * Get the resolved theme (system theme resolved to actual value)\n */\nexport function getResolvedTheme(): string | undefined {\n\treturn getTheme()?.resolvedTheme;\n}\n\n/**\n * Get the system theme preference\n */\nexport function getSystemTheme(): \"dark\" | \"light\" | undefined {\n\treturn getTheme()?.systemTheme;\n}\n\n/**\n * Check if theme is forced for the current page\n */\nexport function isForcedTheme(): boolean {\n\treturn !!getTheme()?.forcedTheme;\n}\n\n/**\n * Get the list of available themes\n */\nexport function getThemes(): string[] {\n\treturn getTheme()?.themes ?? [];\n}\n\n/**\n * Subscribe to theme changes\n * @param callback - Function called when theme changes\n * @returns Cleanup function to unsubscribe\n */\nexport function onThemeChange(\n\tcallback: (detail: { theme: string; resolvedTheme: string }) => void\n): () => void {\n\tif (typeof window === \"undefined\") return () => {};\n\n\tconst handler = (e: CustomEvent<{ theme: string; resolvedTheme: string }>) => {\n\t\tcallback(e.detail);\n\t};\n\n\twindow.addEventListener(\"astro-themes:change\", handler as EventListener);\n\n\treturn () => {\n\t\twindow.removeEventListener(\"astro-themes:change\", handler as EventListener);\n\t};\n}\n\n/**\n * Toggle between light and dark themes\n * If current theme is neither light nor dark, switches to light\n */\nexport function toggleTheme(): void {\n\tconst state = getTheme();\n\tif (!state) return;\n\n\tconst resolved = state.resolvedTheme;\n\tstate.setTheme(resolved === \"light\" ? \"dark\" : \"light\");\n}\n","// Main integration export\nimport { integration } from \"./integration.js\";\n\nexport default integration;\n\n// Re-export integration\nexport { integration };\n\n// Re-export types\nexport type {\n\tAttribute,\n\tValueObject,\n\tScriptProps,\n\tThemeProviderProps,\n\tThemeState,\n\tAstroThemesConfig,\n} from \"./types.js\";\n\n// Re-export client helpers\nexport {\n\tgetTheme,\n\tsetTheme,\n\tgetResolvedTheme,\n\tgetSystemTheme,\n\tisForcedTheme,\n\tgetThemes,\n\tonThemeChange,\n\ttoggleTheme,\n} from \"./client.js\";\n"],"mappings":"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","names":["defineIntegration","z","getInlineScript","attribute","storageKey","defaultTheme","forcedTheme","themes","value","enableSystem","enableColorScheme","getMinifiedInlineScript","DEFAULT_STORAGE_KEY","DEFAULT_THEME","DEFAULT_THEMES","DEFAULT_ATTRIBUTE","optionsSchema","z","integration","defineIntegration","options","logger","injectScript","addDevToolbarApp","command","props","script","getMinifiedInlineScript","injectTypes","getTheme","setTheme","theme","state","getResolvedTheme","getSystemTheme","isForcedTheme","getThemes","onThemeChange","callback","handler","e","toggleTheme","resolved","index_default","integration"]}
1
+ {"version":3,"sources":["../src/integration.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["import { defineIntegration } from \"astro-integration-kit\";\nimport { z } from \"astro/zod\";\nimport type { AstroThemesConfig, ThemeProviderProps } from \"./types.js\";\n\n// Options schema for the integration\nconst optionsSchema = z\n\t.object({\n\t\t/**\n\t\t * Enable the Dev Toolbar App for theme switching during development\n\t\t * @default true\n\t\t */\n\t\tdevToolbar: z.boolean().default(true),\n\t})\n\t.default({});\n\nexport const integration = defineIntegration({\n\tname: \"astro-themes\",\n\toptionsSchema,\n\tsetup({ options }) {\n\t\treturn {\n\t\t\thooks: {\n\t\t\t\t\"astro:config:setup\": ({\n\t\t\t\t\tlogger,\n\t\t\t\t\taddDevToolbarApp,\n\t\t\t\t\tcommand,\n\t\t\t\t}) => {\n\t\t\t\t\tlogger.info(\"astro-themes initialized\");\n\n\t\t\t\t\t// Add Dev Toolbar App in dev mode\n\t\t\t\t\tif (options.devToolbar && command === \"dev\") {\n\t\t\t\t\t\taddDevToolbarApp({\n\t\t\t\t\t\t\tid: \"astro-themes-toolbar\",\n\t\t\t\t\t\t\tname: \"Theme Switcher\",\n\t\t\t\t\t\t\ticon: `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"4\"/><path d=\"M12 2v2\"/><path d=\"M12 20v2\"/><path d=\"m4.93 4.93 1.41 1.41\"/><path d=\"m17.66 17.66 1.41 1.41\"/><path d=\"M2 12h2\"/><path d=\"M20 12h2\"/><path d=\"m6.34 17.66-1.41 1.41\"/><path d=\"m19.07 4.93-1.41 1.41\"/></svg>`,\n\t\t\t\t\t\t\tentrypoint: \"@lpdsgn/astro-themes/toolbar\",\n\t\t\t\t\t\t});\n\t\t\t\t\t\tlogger.debug(\"Dev Toolbar App registered\");\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"astro:config:done\": ({ injectTypes }) => {\n\t\t\t\t\t// Inject global types for window.__ASTRO_THEMES__\n\t\t\t\t\tinjectTypes({\n\t\t\t\t\t\tfilename: \"types.d.ts\",\n\t\t\t\t\t\tcontent: `declare global {\n interface Window {\n __ASTRO_THEMES__?: {\n theme: string;\n resolvedTheme: string;\n systemTheme: \"dark\" | \"light\";\n forcedTheme?: string;\n themes: string[];\n setTheme: (theme: string | ((prevTheme: string) => string)) => void;\n };\n }\n}\nexport {};`,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t},\n});\n\nexport type { AstroThemesConfig, ThemeProviderProps };\n","/**\n * Client-side helpers for interacting with the theme\n * These are meant to be used in client-side scripts\n */\n\nimport type { ThemeState } from \"./types.js\";\n\ndeclare global {\n\tinterface Window {\n\t\t__ASTRO_THEMES__?: ThemeState;\n\t}\n}\n\n/**\n * Get the current theme state\n * Returns undefined if ThemeProvider is not mounted\n */\nexport function getTheme(): ThemeState | undefined {\n\tif (typeof window === \"undefined\") return undefined;\n\treturn window.__ASTRO_THEMES__;\n}\n\n/**\n * Set the theme\n * @param theme - Theme name or function that receives current theme and returns new theme\n */\nexport function setTheme(theme: string | ((prevTheme: string) => string)): void {\n\tconst state = getTheme();\n\tif (state) {\n\t\tstate.setTheme(theme);\n\t}\n}\n\n/**\n * Get the resolved theme (system theme resolved to actual value)\n */\nexport function getResolvedTheme(): string | undefined {\n\treturn getTheme()?.resolvedTheme;\n}\n\n/**\n * Get the system theme preference\n */\nexport function getSystemTheme(): \"dark\" | \"light\" | undefined {\n\treturn getTheme()?.systemTheme;\n}\n\n/**\n * Check if theme is forced for the current page\n */\nexport function isForcedTheme(): boolean {\n\treturn !!getTheme()?.forcedTheme;\n}\n\n/**\n * Get the list of available themes\n */\nexport function getThemes(): string[] {\n\treturn getTheme()?.themes ?? [];\n}\n\n/**\n * Subscribe to theme changes\n * @param callback - Function called when theme changes\n * @returns Cleanup function to unsubscribe\n */\nexport function onThemeChange(\n\tcallback: (detail: { theme: string; resolvedTheme: string }) => void\n): () => void {\n\tif (typeof window === \"undefined\") return () => {};\n\n\tconst handler = (e: CustomEvent<{ theme: string; resolvedTheme: string }>) => {\n\t\tcallback(e.detail);\n\t};\n\n\twindow.addEventListener(\"astro-themes:change\", handler as EventListener);\n\n\treturn () => {\n\t\twindow.removeEventListener(\"astro-themes:change\", handler as EventListener);\n\t};\n}\n\n/**\n * Toggle between light and dark themes\n * If current theme is neither light nor dark, switches to light\n */\nexport function toggleTheme(): void {\n\tconst state = getTheme();\n\tif (!state) return;\n\n\tconst resolved = state.resolvedTheme;\n\tstate.setTheme(resolved === \"light\" ? \"dark\" : \"light\");\n}\n","// Main integration export\nimport { integration } from \"./integration.js\";\n\nexport default integration;\n\n// Re-export integration\nexport { integration };\n\n// Re-export types\nexport type {\n\tAttribute,\n\tValueObject,\n\tScriptProps,\n\tThemeProviderProps,\n\tThemeState,\n\tAstroThemesConfig,\n} from \"./types.js\";\n\n// Re-export client helpers\nexport {\n\tgetTheme,\n\tsetTheme,\n\tgetResolvedTheme,\n\tgetSystemTheme,\n\tisForcedTheme,\n\tgetThemes,\n\tonThemeChange,\n\ttoggleTheme,\n} from \"./client.js\";\n"],"mappings":"AAAA,OAAS,qBAAAA,MAAyB,wBAClC,OAAS,KAAAC,MAAS,YAIlB,IAAMC,EAAgBD,EACpB,OAAO,CAKP,WAAYA,EAAE,QAAQ,EAAE,QAAQ,EAAI,CACrC,CAAC,EACA,QAAQ,CAAC,CAAC,EAECE,EAAcH,EAAkB,CAC5C,KAAM,eACN,cAAAE,EACA,MAAM,CAAE,QAAAE,CAAQ,EAAG,CAClB,MAAO,CACN,MAAO,CACN,qBAAsB,CAAC,CACtB,OAAAC,EACA,iBAAAC,EACA,QAAAC,CACD,IAAM,CACLF,EAAO,KAAK,0BAA0B,EAGlCD,EAAQ,YAAcG,IAAY,QACrCD,EAAiB,CAChB,GAAI,uBACJ,KAAM,iBACN,KAAM,+aACN,WAAY,8BACb,CAAC,EACDD,EAAO,MAAM,4BAA4B,EAE3C,EACA,oBAAqB,CAAC,CAAE,YAAAG,CAAY,IAAM,CAEzCA,EAAY,CACX,SAAU,aACV,QAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAaV,CAAC,CACF,CACD,CACD,CACD,CACD,CAAC,EC5CM,SAASC,GAAmC,CAClD,GAAI,SAAO,OAAW,KACtB,OAAO,OAAO,gBACf,CAMO,SAASC,EAASC,EAAuD,CAC/E,IAAMC,EAAQH,EAAS,EACnBG,GACHA,EAAM,SAASD,CAAK,CAEtB,CAKO,SAASE,GAAuC,CACtD,OAAOJ,EAAS,GAAG,aACpB,CAKO,SAASK,GAA+C,CAC9D,OAAOL,EAAS,GAAG,WACpB,CAKO,SAASM,GAAyB,CACxC,MAAO,CAAC,CAACN,EAAS,GAAG,WACtB,CAKO,SAASO,GAAsB,CACrC,OAAOP,EAAS,GAAG,QAAU,CAAC,CAC/B,CAOO,SAASQ,EACfC,EACa,CACb,GAAI,OAAO,OAAW,IAAa,MAAO,IAAM,CAAC,EAEjD,IAAMC,EAAWC,GAA6D,CAC7EF,EAASE,EAAE,MAAM,CAClB,EAEA,cAAO,iBAAiB,sBAAuBD,CAAwB,EAEhE,IAAM,CACZ,OAAO,oBAAoB,sBAAuBA,CAAwB,CAC3E,CACD,CAMO,SAASE,GAAoB,CACnC,IAAMT,EAAQH,EAAS,EACvB,GAAI,CAACG,EAAO,OAEZ,IAAMU,EAAWV,EAAM,cACvBA,EAAM,SAASU,IAAa,QAAU,OAAS,OAAO,CACvD,CCzFA,IAAOC,EAAQC","names":["defineIntegration","z","optionsSchema","integration","options","logger","addDevToolbarApp","command","injectTypes","getTheme","setTheme","theme","state","getResolvedTheme","getSystemTheme","isForcedTheme","getThemes","onThemeChange","callback","handler","e","toggleTheme","resolved","index_default","integration"]}
package/dist/types.d.ts CHANGED
@@ -39,8 +39,7 @@ interface ThemeProviderProps {
39
39
  */
40
40
  enableSystem?: boolean;
41
41
  /**
42
- * Whether to indicate to browsers which color scheme is used (dark or light)
43
- * for built-in UI like inputs and buttons
42
+ * Whether to indicate to browsers which color scheme is used (dark or light) for built-in UI like inputs and buttons
44
43
  * @default true
45
44
  */
46
45
  enableColorScheme?: boolean;
@@ -97,16 +96,6 @@ interface ThemeState {
97
96
  * Configuration for the astro-themes integration
98
97
  */
99
98
  interface AstroThemesConfig {
100
- /**
101
- * Inject the flash-prevention script automatically via integration
102
- * When true, you don't need to use ThemeProvider component for basic setup
103
- * @default false
104
- */
105
- injectScript?: boolean;
106
- /**
107
- * Default props for the ThemeProvider component or injected script
108
- */
109
- defaultProps?: Partial<ThemeProviderProps>;
110
99
  /**
111
100
  * Enable the Dev Toolbar App for theme switching during development
112
101
  * @default true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lpdsgn/astro-themes",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Perfect dark mode in Astro with no flash. System preference, multiple themes, and sync across tabs.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -9,7 +9,10 @@
9
9
  "types": "./dist/index.d.ts",
10
10
  "default": "./dist/index.js"
11
11
  },
12
- "./components": "./dist/components/index.js",
12
+ "./components": {
13
+ "types": "./dist/components/index.d.ts",
14
+ "default": "./dist/components/index.js"
15
+ },
13
16
  "./components/ThemeProvider.astro": "./dist/components/ThemeProvider.astro",
14
17
  "./client": {
15
18
  "types": "./dist/client.d.ts",
@@ -58,6 +61,6 @@
58
61
  },
59
62
  "scripts": {
60
63
  "dev": "tsup --watch",
61
- "build": "tsup"
64
+ "build": "tsup && node -e \"require('fs').copyFileSync('src/components/index.d.ts', 'dist/components/index.d.ts')\""
62
65
  }
63
66
  }