stoop 0.3.0 → 0.4.1

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.
Files changed (65) hide show
  1. package/README.md +125 -0
  2. package/dist/api/core-api.d.ts +34 -0
  3. package/dist/api/styled.d.ts +0 -1
  4. package/dist/api/theme-provider.d.ts +41 -0
  5. package/dist/constants.d.ts +11 -1
  6. package/dist/core/compiler.d.ts +11 -0
  7. package/dist/core/theme-manager.d.ts +34 -3
  8. package/dist/create-stoop-internal.d.ts +30 -0
  9. package/dist/create-stoop-ssr.d.ts +10 -0
  10. package/dist/create-stoop-ssr.js +16 -0
  11. package/dist/create-stoop.d.ts +32 -1
  12. package/dist/create-stoop.js +16 -147
  13. package/dist/inject.d.ts +113 -0
  14. package/dist/types/index.d.ts +147 -12
  15. package/dist/types/react-polymorphic-types.d.ts +13 -2
  16. package/dist/utils/auto-preload.d.ts +45 -0
  17. package/dist/utils/helpers.d.ts +64 -0
  18. package/dist/utils/storage.d.ts +148 -0
  19. package/dist/utils/{string.d.ts → theme-utils.d.ts} +20 -3
  20. package/dist/utils/theme.d.ts +14 -2
  21. package/package.json +44 -17
  22. package/dist/api/create-theme.d.ts +0 -13
  23. package/dist/api/create-theme.js +0 -43
  24. package/dist/api/css.d.ts +0 -16
  25. package/dist/api/css.js +0 -20
  26. package/dist/api/global-css.js +0 -89
  27. package/dist/api/keyframes.d.ts +0 -16
  28. package/dist/api/keyframes.js +0 -95
  29. package/dist/api/provider.d.ts +0 -19
  30. package/dist/api/provider.js +0 -109
  31. package/dist/api/styled.js +0 -170
  32. package/dist/api/use-theme.d.ts +0 -13
  33. package/dist/api/use-theme.js +0 -21
  34. package/dist/constants.js +0 -144
  35. package/dist/core/cache.js +0 -68
  36. package/dist/core/compiler.js +0 -198
  37. package/dist/core/theme-manager.js +0 -97
  38. package/dist/core/variants.js +0 -32
  39. package/dist/create-stoop-server.d.ts +0 -33
  40. package/dist/create-stoop-server.js +0 -130
  41. package/dist/index.d.ts +0 -6
  42. package/dist/index.js +0 -5
  43. package/dist/inject/browser.d.ts +0 -58
  44. package/dist/inject/browser.js +0 -149
  45. package/dist/inject/dedup.d.ts +0 -29
  46. package/dist/inject/dedup.js +0 -38
  47. package/dist/inject/index.d.ts +0 -40
  48. package/dist/inject/index.js +0 -75
  49. package/dist/inject/ssr.d.ts +0 -27
  50. package/dist/inject/ssr.js +0 -46
  51. package/dist/ssr.d.ts +0 -21
  52. package/dist/ssr.js +0 -19
  53. package/dist/types/index.js +0 -5
  54. package/dist/utils/environment.d.ts +0 -6
  55. package/dist/utils/environment.js +0 -12
  56. package/dist/utils/string.js +0 -253
  57. package/dist/utils/theme-map.d.ts +0 -22
  58. package/dist/utils/theme-map.js +0 -97
  59. package/dist/utils/theme-validation.d.ts +0 -13
  60. package/dist/utils/theme-validation.js +0 -36
  61. package/dist/utils/theme.js +0 -279
  62. package/dist/utils/type-guards.d.ts +0 -26
  63. package/dist/utils/type-guards.js +0 -38
  64. package/dist/utils/utilities.d.ts +0 -14
  65. package/dist/utils/utilities.js +0 -43
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # stoop
2
+
3
+ A lightweight, type-safe CSS-in-JS library for React with theme support, variants, and SSR capabilities.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install stoop
9
+ # or
10
+ bun add stoop
11
+ # or
12
+ yarn add stoop
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```tsx
18
+ import { createStoop } from "stoop";
19
+
20
+ const { styled, css, Provider, useTheme } = createStoop({
21
+ theme: {
22
+ colors: {
23
+ primary: "#0070f3",
24
+ background: "#ffffff",
25
+ text: "#000000",
26
+ },
27
+ space: {
28
+ small: "8px",
29
+ medium: "16px",
30
+ large: "24px",
31
+ },
32
+ },
33
+ themes: {
34
+ light: {
35
+ /* ... */
36
+ },
37
+ dark: {
38
+ /* ... */
39
+ },
40
+ },
41
+ });
42
+
43
+ const Button = styled("button", {
44
+ padding: "$medium",
45
+ backgroundColor: "$primary",
46
+ color: "$text",
47
+ });
48
+
49
+ <Button>Click me</Button>;
50
+ ```
51
+
52
+ ## Features
53
+
54
+ - **Type-safe theming** with TypeScript inference
55
+ - **CSS variables** for instant theme switching
56
+ - **Variant system** for component variations
57
+ - **SSR support** via `getCssText()`
58
+ - **Multiple themes** with built-in Provider
59
+ - **Utility functions** for custom CSS transformations
60
+ - **Zero runtime overhead** for theme switching
61
+
62
+ ## Documentation
63
+
64
+ - **[GUIDE.md](./docs/GUIDE.md)** - Step-by-step setup and usage guide
65
+ - **[API.md](./docs/API.md)** - Complete API reference
66
+ - **[ARCHITECTURE.md](./docs/ARCHITECTURE.md)** - Internal implementation details
67
+ - **[TESTING.md](./docs/TESTING.md)** - Testing guide and test suite documentation
68
+
69
+ ## API Overview
70
+
71
+ ### `createStoop(config)`
72
+
73
+ Creates a Stoop instance. Returns: `styled`, `css`, `createTheme`, `globalCss`, `keyframes`, `getCssText`, `warmCache`, `preloadTheme`, `theme`, `config`. If `themes` config is provided, also returns `Provider` and `useTheme`.
74
+
75
+ ### Theme Tokens
76
+
77
+ Use `$` prefix for theme tokens. Shorthand `$token` uses property-aware resolution (preferred); explicit `$scale.token` specifies the scale.
78
+
79
+ ```tsx
80
+ {
81
+ color: "$primary", // Shorthand (preferred, property-aware)
82
+ padding: "$medium", // Property-aware → space scale
83
+ fontSize: "$fontSizes.small", // Explicit scale
84
+ }
85
+ ```
86
+
87
+ ### Variants
88
+
89
+ Variants create component variations via props:
90
+
91
+ ```tsx
92
+ const Button = styled(
93
+ "button",
94
+ {},
95
+ {
96
+ variant: {
97
+ primary: { backgroundColor: "$primary" },
98
+ secondary: { backgroundColor: "$secondary" },
99
+ },
100
+ size: {
101
+ small: { padding: "$small" },
102
+ large: { padding: "$large" },
103
+ },
104
+ },
105
+ );
106
+
107
+ <Button variant="primary" size="small" />;
108
+ ```
109
+
110
+ ## Development
111
+
112
+ ```sh
113
+ # Build
114
+ bun run build
115
+
116
+ # Test
117
+ bun run test
118
+
119
+ # Watch mode
120
+ bun run test:watch
121
+ ```
122
+
123
+ ## License
124
+
125
+ MIT
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Core API functions.
3
+ * Consolidates theme creation, CSS class generation, and keyframes animation APIs.
4
+ */
5
+ import type { CSS, Theme, ThemeScale, UtilityFunction } from "../types";
6
+ /**
7
+ * Creates a function that extends a base theme with overrides.
8
+ * The returned function deep merges theme overrides with the base theme.
9
+ *
10
+ * @param baseTheme - Base theme to extend
11
+ * @returns Function that accepts theme overrides and returns a merged theme
12
+ */
13
+ export declare function createTheme(baseTheme: Theme): (themeOverrides?: Partial<Theme>) => Theme;
14
+ /**
15
+ * Creates a CSS function that compiles CSS objects into class names.
16
+ *
17
+ * @param defaultTheme - Default theme for token resolution
18
+ * @param prefix - Optional prefix for generated class names
19
+ * @param media - Optional media query breakpoints
20
+ * @param utils - Optional utility functions
21
+ * @param themeMap - Optional theme scale mappings
22
+ * @returns Function that accepts CSS objects and returns class names
23
+ */
24
+ export declare function createCSSFunction(defaultTheme: Theme, prefix?: string, media?: Record<string, string>, utils?: Record<string, UtilityFunction>, themeMap?: Record<string, ThemeScale>): (styles: CSS) => string;
25
+ /**
26
+ * Creates a keyframes animation function.
27
+ * Generates and injects @keyframes rules with caching to prevent duplicates.
28
+ *
29
+ * @param prefix - Optional prefix for animation names
30
+ * @param theme - Optional theme for token resolution
31
+ * @param themeMap - Optional theme scale mappings
32
+ * @returns Function that accepts keyframes objects and returns animation names
33
+ */
34
+ export declare function createKeyframesFunction(prefix?: string, theme?: Theme, themeMap?: Record<string, ThemeScale>): (keyframes: Record<string, CSS>) => string;
@@ -16,7 +16,6 @@ type CSSWithVariants = {
16
16
  [K in keyof CSS]: CSS[K];
17
17
  } & {
18
18
  variants: Variants;
19
- compoundVariants?: unknown[];
20
19
  };
21
20
  /**
22
21
  * Creates a styled component factory function.
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Theme Provider component and hook.
3
+ * Manages theme state, localStorage persistence, cookie sync, and centralized theme variable updates.
4
+ * Includes the useTheme hook for accessing theme management context.
5
+ */
6
+ import { type ComponentType, type Context } from "react";
7
+ import type { ProviderProps, Theme, ThemeContextValue, ThemeManagementContextValue } from "../types";
8
+ /**
9
+ * Creates a Provider component for theme management.
10
+ *
11
+ * @param themes - Map of theme names to theme objects
12
+ * @param defaultTheme - Default theme object
13
+ * @param prefix - Optional prefix for CSS variable scoping
14
+ * @param globalCss - Optional global CSS object from config
15
+ * @param globalCssFunction - Optional globalCss function from createStoop
16
+ * @returns Provider component, theme context, and theme management context
17
+ *
18
+ * @remarks
19
+ * To prevent FOUC (Flash of Unstyled Content) when a user has a non-default theme stored,
20
+ * call `preloadTheme()` from your stoop instance in a script tag before React hydrates:
21
+ *
22
+ * ```html
23
+ * <script>
24
+ * // Read theme from storage and preload before React renders
25
+ * const storedTheme = localStorage.getItem('stoop-theme') || 'light';
26
+ * stoopInstance.preloadTheme(storedTheme);
27
+ * </script>
28
+ * ```
29
+ */
30
+ export declare function createProvider(themes: Record<string, Theme>, defaultTheme: Theme, prefix?: string, globalCss?: import("../types").CSS, globalCssFunction?: import("../types").GlobalCSSFunction): {
31
+ Provider: ComponentType<ProviderProps>;
32
+ ThemeContext: Context<ThemeContextValue | null>;
33
+ ThemeManagementContext: Context<ThemeManagementContextValue | null>;
34
+ };
35
+ /**
36
+ * Creates a useTheme hook for a specific theme management context.
37
+ *
38
+ * @param ThemeManagementContext - React context for theme management
39
+ * @returns Hook function that returns theme management context value
40
+ */
41
+ export declare function createUseThemeHook(ThemeManagementContext: Context<ThemeManagementContextValue | null>): () => ThemeManagementContextValue;
@@ -7,13 +7,23 @@ export declare const EMPTY_CSS: CSS;
7
7
  export declare const MAX_CSS_CACHE_SIZE = 10000;
8
8
  export declare const MAX_CLASS_NAME_CACHE_SIZE = 5000;
9
9
  export declare const MAX_CSS_NESTING_DEPTH = 10;
10
+ /**
11
+ * Cache size limits for various LRU caches.
12
+ */
13
+ export declare const KEYFRAME_CACHE_LIMIT = 500;
14
+ export declare const SANITIZE_CACHE_SIZE_LIMIT = 1000;
15
+ /**
16
+ * Cookie defaults.
17
+ */
18
+ export declare const DEFAULT_COOKIE_MAX_AGE = 31536000;
19
+ export declare const DEFAULT_COOKIE_PATH = "/";
10
20
  /**
11
21
  * Approved theme scales - only these scales are allowed in theme objects.
12
22
  */
13
23
  export declare const APPROVED_THEME_SCALES: ReadonlyArray<ThemeScale>;
14
24
  /**
15
25
  * Default themeMap mapping CSS properties to theme scales.
16
- * Covers 150+ common CSS properties for zero-config experience.
26
+ * Covers common CSS properties for zero-config experience.
17
27
  * Missing properties gracefully fallback to pattern-based auto-detection.
18
28
  */
19
29
  export declare const DEFAULT_THEME_MAP: Record<string, ThemeScale>;
@@ -4,6 +4,17 @@
4
4
  * Handles nested selectors, media queries, styled component targeting, and theme tokens.
5
5
  */
6
6
  import type { CSS, Theme, ThemeScale, UtilityFunction } from "../types";
7
+ /**
8
+ * Converts a CSS object to a CSS string with proper nesting and selectors.
9
+ * Handles pseudo-selectors, media queries, combinators, and styled component targeting.
10
+ *
11
+ * @param obj - CSS object to convert
12
+ * @param selector - Current selector context
13
+ * @param depth - Current nesting depth
14
+ * @param media - Media query breakpoints
15
+ * @returns CSS string
16
+ */
17
+ export declare function cssObjectToString(obj: CSS, selector?: string, depth?: number, media?: Record<string, string>): string;
7
18
  /**
8
19
  * Compiles CSS objects into CSS strings and generates unique class names.
9
20
  * Handles nested selectors, media queries, styled component targeting, and theme tokens.
@@ -14,9 +14,40 @@ import type { Theme } from "../types";
14
14
  */
15
15
  export declare function registerDefaultTheme(theme: Theme, prefix?: string): void;
16
16
  /**
17
- * Updates CSS custom properties when theme changes.
17
+ * Gets the default theme for a given prefix.
18
+ *
19
+ * @param prefix - Optional prefix for theme scoping
20
+ * @returns Default theme or null if not registered
21
+ */
22
+ export declare function getDefaultTheme(prefix?: string): Theme | null;
23
+ /**
24
+ * Core theme merging logic.
25
+ * Merges source theme into target theme, handling nested objects.
26
+ * Shared implementation used by both mergeWithDefaultTheme and createTheme.
27
+ *
28
+ * @param target - Target theme to merge into
29
+ * @param source - Source theme to merge from
30
+ * @returns Merged theme
31
+ */
32
+ export declare function mergeThemes(target: Theme, source: Theme | Partial<Theme>): Theme;
33
+ /**
34
+ * Merges a theme with the default theme if it's not already the default theme.
35
+ * This ensures all themes extend the default theme, keeping all original properties.
36
+ * Uses caching to avoid repeated merging of the same theme objects.
37
+ *
38
+ * @param theme - Theme to merge
39
+ * @param prefix - Optional prefix for theme scoping
40
+ * @returns Merged theme (or original if it's the default theme)
41
+ */
42
+ export declare function mergeWithDefaultTheme(theme: Theme, prefix?: string): Theme;
43
+ /**
44
+ * Injects CSS variables for all themes using attribute selectors.
45
+ * This allows all themes to be available simultaneously, with theme switching
46
+ * handled by changing the data-theme attribute. This prevents layout shifts
47
+ * and eliminates the need to replace CSS variables on theme change.
18
48
  *
19
- * @param theme - Theme object to generate CSS variables from
49
+ * @param themes - Map of theme names to theme objects
20
50
  * @param prefix - Optional prefix for CSS variable names
51
+ * @param attribute - Attribute name for theme selection (defaults to 'data-theme')
21
52
  */
22
- export declare function updateThemeVariables(theme: Theme, prefix?: string): void;
53
+ export declare function injectAllThemes(themes: Record<string, Theme>, prefix?: string, attribute?: string): void;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Internal implementation for creating Stoop instances.
3
+ * This file is used by the SSR entry point and does NOT import React types at module level.
4
+ * React types are only imported conditionally when creating client instances.
5
+ */
6
+ import type { CSS, StoopConfig, Theme, ThemeScale } from "./types";
7
+ import { createCSSFunction, createKeyframesFunction } from "./api/core-api";
8
+ import { createGlobalCSSFunction } from "./api/global-css";
9
+ /**
10
+ * Shared implementation for creating Stoop instances.
11
+ * Handles common setup logic for both client and server instances.
12
+ * Exported for use in SSR entry point.
13
+ */
14
+ export declare function createStoopBase(config: StoopConfig): {
15
+ config: StoopConfig;
16
+ createTheme: (overrides?: Partial<Theme>) => Theme;
17
+ css: ReturnType<typeof createCSSFunction>;
18
+ getCssText: (theme?: string | Theme) => string;
19
+ globalCss: ReturnType<typeof createGlobalCSSFunction>;
20
+ globalCssConfig: StoopConfig["globalCss"];
21
+ keyframes: ReturnType<typeof createKeyframesFunction>;
22
+ media: StoopConfig["media"];
23
+ mergedThemeMap: Record<string, ThemeScale>;
24
+ preloadTheme: (theme: string | Theme) => void;
25
+ sanitizedPrefix: string;
26
+ theme: Theme;
27
+ utils: StoopConfig["utils"];
28
+ validatedTheme: Theme;
29
+ warmCache: (styles: CSS[]) => void;
30
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * SSR-safe entry point for Stoop.
3
+ * Exports only server-safe APIs that don't require React.
4
+ * Use this import in Server Components: import { createStoop } from "stoop/ssr"
5
+ *
6
+ * This file does NOT import React types or create React components.
7
+ */
8
+ import type { StoopConfig, StoopServerInstance } from "./types";
9
+ export type { CSS, Theme, StoopConfig, StoopServerInstance, UtilityFunction, ThemeScale, DefaultTheme, } from "./types";
10
+ export declare function createStoop(config: StoopConfig): StoopServerInstance;
@@ -0,0 +1,16 @@
1
+ var J0=Object.freeze({}),j=1e4,GJ=5000,QJ=10,FJ=500,P=1000;var c=["colors","opacities","space","radii","sizes","fonts","fontWeights","fontSizes","lineHeights","letterSpacings","shadows","zIndices","transitions"],N={accentColor:"colors",animation:"transitions",animationDelay:"transitions",animationDuration:"transitions",animationTimingFunction:"transitions",backdropFilter:"shadows",background:"colors",backgroundColor:"colors",blockSize:"sizes",border:"colors",borderBlockColor:"colors",borderBlockEndColor:"colors",borderBlockStartColor:"colors",borderBottomColor:"colors",borderBottomLeftRadius:"radii",borderBottomRightRadius:"radii",borderColor:"colors",borderEndEndRadius:"radii",borderEndStartRadius:"radii",borderInlineColor:"colors",borderInlineEndColor:"colors",borderInlineStartColor:"colors",borderLeftColor:"colors",borderRadius:"radii",borderRightColor:"colors",borderStartEndRadius:"radii",borderStartStartRadius:"radii",borderTopColor:"colors",borderTopLeftRadius:"radii",borderTopRightRadius:"radii",bottom:"space",boxShadow:"shadows",caretColor:"colors",color:"colors",columnGap:"space",columnRuleColor:"colors",fill:"colors",filter:"shadows",flexBasis:"sizes",floodColor:"colors",font:"fontSizes",fontFamily:"fonts",fontSize:"fontSizes",fontWeight:"fontWeights",gap:"space",gridColumnGap:"space",gridGap:"space",gridRowGap:"space",height:"sizes",inlineSize:"sizes",inset:"space",insetBlock:"space",insetBlockEnd:"space",insetBlockStart:"space",insetInline:"space",insetInlineEnd:"space",insetInlineStart:"space",left:"space",letterSpacing:"letterSpacings",lightingColor:"colors",lineHeight:"lineHeights",margin:"space",marginBlock:"space",marginBlockEnd:"space",marginBlockStart:"space",marginBottom:"space",marginInline:"space",marginInlineEnd:"space",marginInlineStart:"space",marginLeft:"space",marginRight:"space",marginTop:"space",maxBlockSize:"sizes",maxHeight:"sizes",maxInlineSize:"sizes",maxWidth:"sizes",minBlockSize:"sizes",minHeight:"sizes",minInlineSize:"sizes",minWidth:"sizes",opacity:"opacities",outline:"colors",outlineColor:"colors",padding:"space",paddingBlock:"space",paddingBlockEnd:"space",paddingBlockStart:"space",paddingBottom:"space",paddingInline:"space",paddingInlineEnd:"space",paddingInlineStart:"space",paddingLeft:"space",paddingRight:"space",paddingTop:"space",right:"space",rowGap:"space",size:"sizes",stopColor:"colors",stroke:"colors",textDecorationColor:"colors",textEmphasisColor:"colors",textShadow:"shadows",top:"space",transition:"transitions",transitionDelay:"transitions",transitionDuration:"transitions",transitionProperty:"transitions",transitionTimingFunction:"transitions",width:"sizes",zIndex:"zIndices"},ZJ=Symbol.for("stoop.component");class L extends Map{maxSize;constructor(J){super();this.maxSize=J}get(J){let $=super.get(J);if($!==void 0)super.delete(J),super.set(J,$);return $}set(J,$){if(super.has(J))super.delete(J);else if(this.size>=this.maxSize){let Y=this.keys().next().value;if(Y!==void 0)super.delete(Y)}return super.set(J,$),this}}var WJ=new L(GJ),n=new L(j);function K(){return typeof window!=="undefined"&&typeof document!=="undefined"&&typeof window.document==="object"&&typeof document.createElement==="function"}function g(){return typeof process!=="undefined"&&process.env?.NODE_ENV==="production"}function v(J){return typeof J==="object"&&J!==null}function p(J){return typeof J==="object"&&J!==null&&"__isStoopStyled"in J&&"__stoopClassName"in J&&J.__isStoopStyled===!0}function m(J){return v(J)&&!p(J)}function o(J){return typeof J==="object"&&J!==null&&!Array.isArray(J)}function x(J){if(!J||typeof J!=="object"||Array.isArray(J))throw new Error("[Stoop] Theme must be a non-null object");if(g())return J;let $=J,Y=[];for(let q in $){if(q==="media")continue;if(!c.includes(q))Y.push(q)}if(Y.length>0){let q=`[Stoop] Theme contains invalid scales: ${Y.join(", ")}. Only these scales are allowed: ${c.join(", ")}`;throw new Error(q)}return J}function z(J,$){if(!$||!J||typeof J!=="object")return J;let Y={},q=Object.keys($);for(let X in J){let F=J[X];if(q.includes(X)&&$[X])try{let Q=$[X](F);if(Q&&typeof Q==="object")for(let Z in Q)Y[Z]=Q[Z]}catch{Y[X]=F}else if(v(F))Y[X]=z(F,$);else Y[X]=F}return Y}var l=null,DJ=new L(P),wJ=new L(P),Z0=new L(P),HJ=new L(P);function b(J){let q=2166136261;for(let X=0;X<J.length;X++)q^=J.charCodeAt(X),q=Math.imul(q,16777619);return q^=J.length,(q>>>0).toString(36)}function T(J){try{return b(JSON.stringify(J))}catch{return b(String(J))}}function cJ(J){return J.replace(/([A-Z])/g,"-$1").toLowerCase()}function UJ(J,$=!1){let q=String(J).replace(/\\/g,"\\\\").replace(/"/g,"\\\"").replace(/'/g,"\\'").replace(/;/g,"\\;").replace(/\n/g,"\\A ").replace(/\r/g,"").replace(/\f/g,"\\C ");if($)q=q.replace(/\{/g,"\\7B ").replace(/\}/g,"\\7D ");return q}function BJ(J){return UJ(J,!1)}function I(J){let $=DJ.get(J);if($!==void 0)return $;let Y=J.replace(/[^a-zA-Z0-9\s\-_>+~:.#[\]&@()]/g,""),q=!Y.trim()||/^[>+~:.#[\]&@()\s]+$/.test(Y)?"":Y;return DJ.set(J,q),q}function R(J){let $=HJ.get(J);if($!==void 0)return $;let X=J.replace(/[^a-zA-Z0-9-_]/g,"-").replace(/^[\d-]+/,"").replace(/^-+/,"")||"invalid";return HJ.set(J,X),X}function LJ(J){return UJ(J,!0)}function B(J){if(!J)return"stoop";return J.replace(/[^a-zA-Z0-9-_]/g,"").replace(/^[\d-]+/,"").replace(/^-+/,"")||"stoop"}function _J(J){if(!J||typeof J!=="string")return"";let $=J.replace(/[^a-zA-Z0-9\s():,<>=\-@]/g,"");if(!$.trim()||!/[a-zA-Z]/.test($))return"";return $}function C(J){if(!J||typeof J!=="string")return"";let $=wJ.get(J);if($!==void 0)return $;let X=cJ(J).replace(/[^a-zA-Z0-9-]/g,"").replace(/^-+|-+$/g,"").replace(/^\d+/,"")||"";return wJ.set(J,X),X}function AJ(J){if(!J||typeof J!=="string")return!1;if(J==="from"||J==="to")return!0;if(/^\d+(\.\d+)?%$/.test(J)){let Y=parseFloat(J);return Y>=0&&Y<=100}return!1}function KJ(J=""){if(!l){let Y=":root".replace(/[.*+?^${}()|[\]\\]/g,"\\$&");l=new RegExp(`${Y}\\s*\\{[\\s\\S]*\\}`)}return l}function nJ(J){if(J.includes("Color")||J==="fill"||J==="stroke"||J==="accentColor"||J==="caretColor"||J==="border"||J==="outline"||J.includes("background")&&!J.includes("Size")&&!J.includes("Image"))return"colors";if(/^(margin|padding|gap|inset|top|right|bottom|left|rowGap|columnGap|gridGap|gridRowGap|gridColumnGap)/.test(J)||J.includes("Block")||J.includes("Inline"))return"space";if(/(width|height|size|basis)$/i.test(J)||J.includes("BlockSize")||J.includes("InlineSize"))return"sizes";if(J==="fontSize"||J==="font"&&!J.includes("Family"))return"fontSizes";if(J==="fontFamily"||J.includes("FontFamily"))return"fonts";if(J==="fontWeight"||J.includes("FontWeight"))return"fontWeights";if(J==="letterSpacing"||J.includes("LetterSpacing"))return"letterSpacings";if(J.includes("Radius")||J.includes("radius"))return"radii";if(J.includes("Shadow")||J.includes("shadow")||J==="filter"||J==="backdropFilter")return"shadows";if(J==="zIndex"||J.includes("ZIndex")||J.includes("z-index"))return"zIndices";if(J==="opacity"||J.includes("Opacity"))return"opacities";if(J.startsWith("transition")||J.startsWith("animation")||J.includes("Transition")||J.includes("Animation"))return"transitions";return}function OJ(J,$){if($&&J in $)return $[J];if(J in N)return N[J];return nJ(J)}var r=new Map;function S(J){return r.has(J)}function f(J,$){r.set(J,$)}var i=new L(j);function MJ(J){if(!i.has(J))i.set(J,!0)}function IJ(){return Array.from(i.keys()).join(`
2
+ `)}var k=new Map;var RJ=new Map;function EJ(J="stoop"){if(!K())throw new Error("Cannot access document in SSR context");let $=B(J),Y=k.get($);if(!Y||!Y.parentNode){let q=document.getElementById("stoop-ssr");if(q){let X=q.getAttribute("data-stoop");if(!X||X===$)return Y=q,Y.setAttribute("data-stoop",$),k.set($,Y),Y}Y=document.createElement("style"),Y.setAttribute("data-stoop",$),Y.setAttribute("id",`stoop-${$}`),document.head.appendChild(Y),k.set($,Y)}return Y}function a(J){let $=J,Y=KJ("");$=$.replace(Y,"").trim();let q=$.indexOf("[data-theme=");while(q!==-1){let X=$.indexOf("{",q);if(X===-1)break;let F=1,Q=X+1;while(Q<$.length&&F>0){if($[Q]==="{")F++;else if($[Q]==="}")F--;Q++}if(F===0){let Z=$.substring(0,q).trim(),G=$.substring(Q).trim();$=(Z+`
3
+ `+G).trim()}else break;q=$.indexOf("[data-theme=")}return $.trim()}function VJ(J,$="stoop"){if(!J)return;let Y=B($),q=`__all_theme_vars_${Y}`;if((RJ.get(q)??null)===J)return;if(RJ.set(q,J),!K()){MJ(J);return}let F=EJ(Y),Q=F.textContent||"",Z=Q.includes(":root")||Q.includes("[data-theme=");if(S(q)||Z){let G=a(Q);F.textContent=J+(G?`
4
+
5
+ `+G:""),f(q,J)}else F.textContent=J+(Q?`
6
+
7
+ `+Q:""),f(q,J)}function pJ(J,$,Y="stoop"){if(!K())return;let q=B(Y);if(S($))return;let X=EJ(q),F=X.textContent||"";X.textContent=F+(F?`
8
+ `:"")+J,f($,J)}function mJ(J,$,Y="stoop"){if(S($))return;let q=B(Y);pJ(J,$,q)}function oJ(J="stoop"){let $=B(J);return k.get($)||null}function lJ(){return new Map(r)}function M(J,$="stoop",Y){let q=Y||J;if(!K()){if(!S(q))f(q,J);MJ(J);return}mJ(J,q,$)}function PJ(J="stoop"){if(K()){let $=B(J),Y=oJ($);if(Y&&Y.parentNode){let q=Y.textContent||"";if(!q&&lJ().size>0)return IJ();return q}}return IJ()}var iJ=/(-?\$[a-zA-Z][a-zA-Z0-9]*(?:\$[a-zA-Z][a-zA-Z0-9]*)?(?:\.[a-zA-Z][a-zA-Z0-9]*)?)/g;function t(J){let $=new Map;function Y(q,X=[]){let F=Object.keys(q);for(let Q of F){let Z=q[Q],G=[...X,Q];if(o(Z))Y(Z,G);else{let D=$.get(Q);if(D)D.push(G);else $.set(Q,[G])}}}Y(J);for(let[,q]of $.entries())if(q.length>1)q.sort((X,F)=>{let Q=X.length-F.length;if(Q!==0)return Q;let Z=X.join("."),G=F.join(".");return Z.localeCompare(G)});return $}function rJ(J,$){let Y=Object.keys(J).filter((X)=>X!=="media"),q=Object.keys($).filter((X)=>X!=="media");if(Y.length!==q.length)return!1;for(let X of Y)if(!(X in $))return!1;return!0}function zJ(J,$){if(J===$)return!0;if(!J||!$)return!1;if(!rJ(J,$))return!1;let Y={...J},q={...$};return delete Y.media,delete q.media,JSON.stringify(Y)===JSON.stringify(q)}function s(J,$,Y){if(Y&&Y in J){let F=J[Y];if(F&&typeof F==="object"&&!Array.isArray(F)&&$ in F)return[Y,$]}let X=t(J).get($);if(!X||X.length===0)return null;return X[0]}function NJ(J,$,Y,q){if(!J.startsWith("$"))return J;let X=J.slice(1);if(X.includes("$")||X.includes("."))return`var(${`--${(X.includes("$")?X.split("$"):X.split(".")).map((W)=>R(W)).join("-")}`})`;if($&&Y){let Z=OJ(Y,q);if(Z){let w=s($,X,Z);if(w)return`var(${`--${w.map((A)=>R(A)).join("-")}`})`}let D=t($).get(X);if(D&&D.length>1){if(!g()){let w=Z?`Property "${Y}" maps to "${Z}" scale, but token not found there. `:`No scale mapping found for property "${Y}". `;console.warn(`[Stoop] Ambiguous token "$${X}" found in multiple categories: ${D.map((H)=>H.join(".")).join(", ")}. ${w}Using "${D[0].join(".")}" (deterministic: shorter paths first, then alphabetical). Use full path "$${D[0].join(".")}" to be explicit.`)}}let W=s($,X);if(W)return`var(${`--${W.map((U)=>R(U)).join("-")}`})`}else if($){let G=t($).get(X);if(G&&G.length>1){if(!g())console.warn(`[Stoop] Ambiguous token "$${X}" found in multiple categories: ${G.map((W)=>W.join(".")).join(", ")}. Using "${G[0].join(".")}" (deterministic: shorter paths first, then alphabetical). Use full path "$${G[0].join(".")}" to be explicit, or use with a CSS property for automatic resolution.`)}let D=s($,X);if(D)return`var(${`--${D.map((H)=>R(H)).join("-")}`})`}return`var(${`--${R(X)}`})`}function e(J,$="stoop",Y){let q=Y||":root",X=[];function F(Q,Z=[]){let G=Object.keys(Q).sort();for(let D of G){if(D==="media")continue;let W=Q[D],w=[...Z,D];if(o(W))F(W,w);else{let U=`--${w.map((y)=>R(y)).join("-")}`,A=typeof W==="string"||typeof W==="number"?LJ(W):String(W);X.push(` ${U}: ${A};`)}}}if(F(J),X.length===0)return"";return`${q} {
9
+ ${X.join(`
10
+ `)}
11
+ }`}function d(J,$="stoop",Y="data-theme"){let q=[];for(let[X,F]of Object.entries(J)){let Q=`[${Y}="${X}"]`,Z=e(F,$,Q);if(Z)q.push(Z)}return q.join(`
12
+
13
+ `)}function E(J,$,Y,q){if(!J||typeof J!=="object")return J;let X={},F=!1,Q=Object.keys(J).sort();for(let Z of Q){let G=J[Z];if(v(G)){let D=E(G,$,Y,void 0);if(X[Z]=D,D!==G)F=!0}else if(typeof G==="string"&&G.includes("$")){F=!0;let D=q||Z;X[Z]=G.replace(iJ,(W)=>{if(W.startsWith("-$")){let w=W.slice(1);return`calc(-1 * ${NJ(w,$,D,Y)})`}return NJ(W,$,D,Y)})}else X[Z]=G}if(!F)return J;return X}function aJ(J,$){if(typeof J==="symbol"&&J===ZJ)return!0;if(p($))return!0;if(typeof J==="string"&&J.startsWith("__STOOP_COMPONENT_"))return!0;return!1}function sJ(J,$){if(typeof $==="object"&&$!==null&&"__stoopClassName"in $&&typeof $.__stoopClassName==="string")return $.__stoopClassName;if(typeof J==="string"&&J.startsWith("__STOOP_COMPONENT_"))return J.replace("__STOOP_COMPONENT_","");return""}function _(J,$="",Y=0,q){if(!J||typeof J!=="object")return"";if(Y>QJ)return"";let X=[],F=[],Q=Object.keys(J).sort();for(let G of Q){let D=J[G];if(aJ(G,D)){let W=sJ(G,D);if(!W)continue;let w=I(W);if(!w)continue;let H=$?`${$} .${w}`:`.${w}`,U=m(D)?_(D,H,Y+1,q):"";if(U)F.push(U);continue}if(m(D))if(q&&G in q){let W=_J(q[G]);if(W){let w=_(D,$,Y+1,q);if(w)F.push(`${W} { ${w} }`)}}else if(G.startsWith("@")){let W=I(G);if(W){let w=_(D,$,Y+1,q);if(w)F.push(`${W} { ${w} }`)}}else if(G.includes("&")){let W=I(G);if(W){let H=W.split("&").join($),U=_(D,H,Y+1,q);if(U)F.push(U)}}else if(G.startsWith(":")){let W=I(G);if(W){let w=`${$}${W}`,H=_(D,w,Y+1,q);if(H)F.push(H)}}else if(G.includes(" ")||G.includes(">")||G.includes("+")||G.includes("~")){let W=I(G);if(W){let H=/^[\s>+~]/.test(W.trim())?`${$}${W}`:`${$} ${W}`,U=_(D,H,Y+1,q);if(U)F.push(U)}}else{let W=I(G);if(W){let w=$?`${$} ${W}`:W,H=_(D,w,Y+1,q);if(H)F.push(H)}}else if(D!==void 0){let W=C(G);if(W&&(typeof D==="string"||typeof D==="number")){let w=BJ(D);X.push(`${W}: ${w};`)}}}let Z=[];if(X.length>0)Z.push(`${$} { ${X.join(" ")} }`);return Z.push(...F),Z.join("")}function u(J,$,Y="stoop",q,X,F){let Q=B(Y),Z=z(J,X),G=E(Z,$,F),D=_(G,"",0,q),W=b(D),w=Q?`${Q}-${W}`:`css-${W}`,H=`${Q}:${w}`,U=n.get(H);if(U)return M(U,Q,H),w;let A=_(G,`.${w}`,0,q);return n.set(H,A),WJ.set(H,w),M(A,Q,H),w}var jJ=new Map;function gJ(J,$="stoop"){let Y=$||"";jJ.set(Y,J)}function tJ(J="stoop"){let $=J||"";return jJ.get($)||null}function JJ(J,$){let Y={...J},q=Object.keys($);for(let X of q){if(X==="media")continue;let F=$[X],Q=J[X];if(F&&typeof F==="object"&&!Array.isArray(F)&&Q&&typeof Q==="object"&&!Array.isArray(Q))Y[X]={...Q,...F};else if(F!==void 0)Y[X]=F}return Y}function $J(J,$="stoop"){let Y=tJ($);if(!Y)return J;if(zJ(J,Y))return J;return JJ(Y,J)}function vJ(J,$="stoop",Y="data-theme"){if(!K())return;let q={};for(let[F,Q]of Object.entries(J))q[F]=$J(Q,$);let X=d(q,$,Y);VJ(X,$)}function xJ(J){return function $(Y={}){let q=x(Y);return JJ(J,q)}}function bJ(J,$="stoop",Y,q,X){return function F(Q){return u(Q,J,$,Y,q,X)}}function eJ(J,$,Y,q){let X=`@keyframes ${$} {`,F=Object.keys(J).sort((Q,Z)=>{let G=parseFloat(Q.replace("%","")),D=parseFloat(Z.replace("%",""));if(Q==="from")return-1;if(Z==="from")return 1;if(Q==="to")return 1;if(Z==="to")return-1;return G-D});for(let Q of F){if(!AJ(Q))continue;let Z=J[Q];if(!Z||typeof Z!=="object")continue;X+=` ${Q} {`;let G=E(Z,Y,q),D=Object.keys(G).sort();for(let W of D){let w=G[W];if(w!==void 0&&(typeof w==="string"||typeof w==="number")){let H=C(W);if(H){let U=String(w);X+=` ${H}: ${U};`}}}X+=" }"}return X+=" }",X}function TJ(J="stoop",$,Y){let q=B(J),X=new L(FJ);return function F(Q){let Z=T(Q),G=X.get(Z);if(G)return G;let D=Z.slice(0,8),W=q?`${q}-${D}`:`stoop-${D}`,w=eJ(Q,W,$,Y),H=`__keyframes_${W}`;return M(w,q,H),X.set(Z,W),W}}var YJ=new Set;function CJ(J,$="stoop",Y,q,X){return function F(Q){let Z=T(Q);if(YJ.has(Z))return()=>{};YJ.add(Z);let G=B($),D=z(Q,q),W=E(D,J,X),w=_(W,"",0,Y);return M(w,G,`__global_${Z}`),()=>{YJ.delete(Z)}}}function kJ(J){let{globalCss:$,media:Y,prefix:q="stoop",theme:X,themeMap:F,utils:Q}=J,Z=B(q),G=x(X),D=G.media||Y,W={...N,...F};gJ(G,Z);let w=bJ(G,Z,D,Q,W),H=xJ(G),U=CJ(G,Z,D,Q,W),A=TJ(Z,G,W),y=Object.freeze({...G});function fJ(h){for(let O of h)try{u(O,G,Z,D,Q,W)}catch{}}function SJ(h){if(!J.themes||Object.keys(J.themes).length===0)return;vJ(J.themes,Z)}function dJ(h){let O="";if(J.themes&&Object.keys(J.themes).length>0){let V={};for(let[yJ,hJ]of Object.entries(J.themes))V[yJ]=$J(hJ,Z);let XJ=d(V,Z,"data-theme");if(XJ)O+=XJ+`
14
+ `}else{let V=e(G,Z);if(V)O+=V+`
15
+ `}let uJ=PJ(),qJ=a(uJ).trim();if(qJ)O+=(O?`
16
+ `:"")+qJ;return O}return{config:{...J,prefix:Z},createTheme:H,css:w,getCssText:dJ,globalCss:U,globalCssConfig:$,keyframes:A,media:D,mergedThemeMap:W,preloadTheme:SJ,sanitizedPrefix:Z,theme:y,utils:Q,validatedTheme:G,warmCache:fJ}}function Y1(J){let $=kJ(J);return{config:{...$.config,prefix:$.sanitizedPrefix},createTheme:$.createTheme,css:$.css,getCssText:$.getCssText,globalCss:$.globalCss,keyframes:$.keyframes,preloadTheme:$.preloadTheme,theme:$.theme,warmCache:$.warmCache}}export{Y1 as createStoop};
@@ -1,9 +1,40 @@
1
- import type { StoopConfig, StoopInstance } from "./types";
1
+ /**
2
+ * Factory function that creates a Stoop instance.
3
+ * Supports both client-side (with React APIs) and server-side (without React) usage.
4
+ * Automatically detects environment and includes appropriate APIs.
5
+ */
6
+ import type { CSS, StoopConfig, StoopInstance, Theme, ThemeScale } from "./types";
7
+ import { createCSSFunction, createKeyframesFunction } from "./api/core-api";
8
+ import { createGlobalCSSFunction } from "./api/global-css";
9
+ /**
10
+ * Shared implementation for creating Stoop instances.
11
+ * Handles common setup logic for both client and server instances.
12
+ * Exported for use in SSR entry point.
13
+ */
14
+ export declare function createStoopBase(config: StoopConfig): {
15
+ config: StoopConfig;
16
+ createTheme: (overrides?: Partial<Theme>) => Theme;
17
+ css: ReturnType<typeof createCSSFunction>;
18
+ getCssText: (theme?: string | Theme) => string;
19
+ globalCss: ReturnType<typeof createGlobalCSSFunction>;
20
+ globalCssConfig: StoopConfig["globalCss"];
21
+ keyframes: ReturnType<typeof createKeyframesFunction>;
22
+ media: StoopConfig["media"];
23
+ mergedThemeMap: Record<string, ThemeScale>;
24
+ preloadTheme: (theme: string | Theme) => void;
25
+ sanitizedPrefix: string;
26
+ theme: Theme;
27
+ utils: StoopConfig["utils"];
28
+ validatedTheme: Theme;
29
+ warmCache: (styles: CSS[]) => void;
30
+ };
2
31
  /**
3
32
  * Creates a Stoop instance with the provided configuration.
4
33
  * Includes all APIs: styled, Provider, useTheme, etc.
34
+ * In server contexts without React, React APIs will be undefined.
5
35
  *
6
36
  * @param config - Configuration object containing theme, media queries, utilities, and optional prefix/themeMap
7
37
  * @returns StoopInstance with all API functions
8
38
  */
39
+ export type { CSS, Theme, StoopConfig, StoopInstance, UtilityFunction, ThemeScale, DefaultTheme, } from "./types";
9
40
  export declare function createStoop(config: StoopConfig): StoopInstance;