typestyles 0.1.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/dist/index.js ADDED
@@ -0,0 +1,326 @@
1
+ import { __export, insertRules, insertRule } from './chunk-PFDN4Y4C.js';
2
+ export { getRegisteredCss } from './chunk-PFDN4Y4C.js';
3
+
4
+ // src/css.ts
5
+ function toKebabCase(prop) {
6
+ if (prop.startsWith("ms")) {
7
+ return "-" + prop.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
8
+ }
9
+ return prop.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
10
+ }
11
+ function serializeValue(prop, value) {
12
+ if (typeof value === "number") {
13
+ if (value === 0) return "0";
14
+ if (unitlessProperties.has(prop)) return String(value);
15
+ return value + "px";
16
+ }
17
+ return value;
18
+ }
19
+ var unitlessProperties = /* @__PURE__ */ new Set([
20
+ "animationIterationCount",
21
+ "borderImageOutset",
22
+ "borderImageSlice",
23
+ "borderImageWidth",
24
+ "columnCount",
25
+ "columns",
26
+ "flex",
27
+ "flexGrow",
28
+ "flexPositive",
29
+ "flexShrink",
30
+ "flexNegative",
31
+ "flexOrder",
32
+ "fontWeight",
33
+ "gridArea",
34
+ "gridColumn",
35
+ "gridColumnEnd",
36
+ "gridColumnSpan",
37
+ "gridColumnStart",
38
+ "gridRow",
39
+ "gridRowEnd",
40
+ "gridRowSpan",
41
+ "gridRowStart",
42
+ "lineClamp",
43
+ "lineHeight",
44
+ "opacity",
45
+ "order",
46
+ "orphans",
47
+ "tabSize",
48
+ "widows",
49
+ "zIndex",
50
+ "zoom",
51
+ "fillOpacity",
52
+ "floodOpacity",
53
+ "stopOpacity",
54
+ "strokeDasharray",
55
+ "strokeDashoffset",
56
+ "strokeMiterlimit",
57
+ "strokeOpacity",
58
+ "strokeWidth"
59
+ ]);
60
+ function serializeStyle(selector, properties) {
61
+ const rules = [];
62
+ const declarations = [];
63
+ for (const [prop, value] of Object.entries(properties)) {
64
+ if (value == null) continue;
65
+ if (prop.startsWith("&")) {
66
+ const nestedSelector = prop.replace(/&/g, selector);
67
+ rules.push(
68
+ ...serializeStyle(nestedSelector, value)
69
+ );
70
+ } else if (prop.startsWith("@")) {
71
+ const innerRules = serializeStyle(selector, value);
72
+ for (const inner of innerRules) {
73
+ rules.push({
74
+ key: `${prop}:${inner.key}`,
75
+ css: `${prop} { ${inner.css} }`
76
+ });
77
+ }
78
+ } else {
79
+ const kebabProp = toKebabCase(prop);
80
+ declarations.push(
81
+ `${kebabProp}: ${serializeValue(prop, value)}`
82
+ );
83
+ }
84
+ }
85
+ if (declarations.length > 0) {
86
+ rules.unshift({
87
+ key: selector,
88
+ css: `${selector} { ${declarations.join("; ")}; }`
89
+ });
90
+ }
91
+ return rules;
92
+ }
93
+
94
+ // src/registry.ts
95
+ var registeredNamespaces = /* @__PURE__ */ new Set();
96
+
97
+ // src/styles.ts
98
+ function createStyles(namespace, definitions) {
99
+ if (process.env.NODE_ENV !== "production") {
100
+ if (registeredNamespaces.has(namespace)) {
101
+ console.warn(
102
+ `[typestyles] styles.create('${namespace}', ...) called more than once. This will cause class name collisions. Each namespace should be unique.`
103
+ );
104
+ }
105
+ }
106
+ registeredNamespaces.add(namespace);
107
+ const rules = [];
108
+ for (const [variant, properties] of Object.entries(definitions)) {
109
+ const className = `${namespace}-${variant}`;
110
+ const selector = `.${className}`;
111
+ const variantRules = serializeStyle(selector, properties);
112
+ rules.push(...variantRules);
113
+ }
114
+ insertRules(rules);
115
+ const selectorFn = (...variants) => {
116
+ return variants.filter(Boolean).map((v) => `${namespace}-${v}`).join(" ");
117
+ };
118
+ return selectorFn;
119
+ }
120
+
121
+ // src/tokens.ts
122
+ var registeredNamespaces2 = /* @__PURE__ */ new Set();
123
+ function createTokenProxy(namespace) {
124
+ return new Proxy({}, {
125
+ get(_target, prop) {
126
+ return `var(--${namespace}-${prop})`;
127
+ }
128
+ });
129
+ }
130
+ function createTokens(namespace, values) {
131
+ registeredNamespaces2.add(namespace);
132
+ const declarations = Object.entries(values).map(([key, value]) => `--${namespace}-${key}: ${value}`).join("; ");
133
+ const css = `:root { ${declarations}; }`;
134
+ insertRule(`tokens:${namespace}`, css);
135
+ return createTokenProxy(namespace);
136
+ }
137
+ function useTokens(namespace) {
138
+ if (process.env.NODE_ENV !== "production" && registeredNamespaces2.size > 0 && !registeredNamespaces2.has(namespace)) {
139
+ console.warn(
140
+ `[typestyles] tokens.use('${namespace}') references a namespace that hasn't been created yet. Make sure tokens.create('${namespace}', ...) is called before using these tokens.`
141
+ );
142
+ }
143
+ return createTokenProxy(namespace);
144
+ }
145
+ function createTheme(name, overrides) {
146
+ const className = `theme-${name}`;
147
+ const declarations = [];
148
+ for (const [namespace, values] of Object.entries(overrides)) {
149
+ for (const [key, value] of Object.entries(values)) {
150
+ if (value != null) {
151
+ declarations.push(`--${namespace}-${key}: ${value}`);
152
+ }
153
+ }
154
+ }
155
+ const css = `.${className} { ${declarations.join("; ")}; }`;
156
+ insertRule(`theme:${name}`, css);
157
+ return className;
158
+ }
159
+
160
+ // src/keyframes.ts
161
+ function serializeDeclarations(properties) {
162
+ const declarations = [];
163
+ for (const [prop, value] of Object.entries(properties)) {
164
+ if (value == null) continue;
165
+ if (prop.startsWith("&") || prop.startsWith("@")) continue;
166
+ const kebabProp = toKebabCase(prop);
167
+ const serialized = typeof value === "number" ? value === 0 ? "0" : value + "px" : value;
168
+ declarations.push(`${kebabProp}: ${serialized}`);
169
+ }
170
+ return declarations.join("; ");
171
+ }
172
+ function createKeyframes(name, stops) {
173
+ const stopsCSS = Object.entries(stops).map(([stop, properties]) => {
174
+ const decls = serializeDeclarations(properties);
175
+ return `${stop} { ${decls}; }`;
176
+ }).join(" ");
177
+ const css = `@keyframes ${name} { ${stopsCSS} }`;
178
+ insertRule(`keyframes:${name}`, css);
179
+ return name;
180
+ }
181
+
182
+ // src/color.ts
183
+ var color_exports = {};
184
+ __export(color_exports, {
185
+ alpha: () => alpha,
186
+ hsl: () => hsl,
187
+ hwb: () => hwb,
188
+ lab: () => lab,
189
+ lch: () => lch,
190
+ lightDark: () => lightDark,
191
+ mix: () => mix,
192
+ oklab: () => oklab,
193
+ oklch: () => oklch,
194
+ rgb: () => rgb
195
+ });
196
+ function rgb(r, g, b, alpha2) {
197
+ if (alpha2 != null) return `rgb(${r} ${g} ${b} / ${alpha2})`;
198
+ return `rgb(${r} ${g} ${b})`;
199
+ }
200
+ function hsl(h, s, l, alpha2) {
201
+ if (alpha2 != null) return `hsl(${h} ${s} ${l} / ${alpha2})`;
202
+ return `hsl(${h} ${s} ${l})`;
203
+ }
204
+ function oklch(l, c, h, alpha2) {
205
+ if (alpha2 != null) return `oklch(${l} ${c} ${h} / ${alpha2})`;
206
+ return `oklch(${l} ${c} ${h})`;
207
+ }
208
+ function oklab(l, a, b, alpha2) {
209
+ if (alpha2 != null) return `oklab(${l} ${a} ${b} / ${alpha2})`;
210
+ return `oklab(${l} ${a} ${b})`;
211
+ }
212
+ function lab(l, a, b, alpha2) {
213
+ if (alpha2 != null) return `lab(${l} ${a} ${b} / ${alpha2})`;
214
+ return `lab(${l} ${a} ${b})`;
215
+ }
216
+ function lch(l, c, h, alpha2) {
217
+ if (alpha2 != null) return `lch(${l} ${c} ${h} / ${alpha2})`;
218
+ return `lch(${l} ${c} ${h})`;
219
+ }
220
+ function hwb(h, w, b, alpha2) {
221
+ if (alpha2 != null) return `hwb(${h} ${w} ${b} / ${alpha2})`;
222
+ return `hwb(${h} ${w} ${b})`;
223
+ }
224
+ function mix(color1, color2, percentage, colorSpace = "srgb") {
225
+ const c1 = percentage != null ? `${color1} ${percentage}%` : color1;
226
+ return `color-mix(in ${colorSpace}, ${c1}, ${color2})`;
227
+ }
228
+ function lightDark(lightColor, darkColor) {
229
+ return `light-dark(${lightColor}, ${darkColor})`;
230
+ }
231
+ function alpha(colorValue, opacity, colorSpace = "srgb") {
232
+ const percentage = Math.round(opacity * 100);
233
+ return `color-mix(in ${colorSpace}, ${colorValue} ${percentage}%, transparent)`;
234
+ }
235
+
236
+ // src/component.ts
237
+ function createComponent(namespace, config) {
238
+ const { base, variants = {}, compoundVariants = [], defaultVariants = {} } = config;
239
+ if (process.env.NODE_ENV !== "production") {
240
+ if (registeredNamespaces.has(namespace)) {
241
+ console.warn(
242
+ `[typestyles] styles.component('${namespace}', ...) called more than once. This will cause class name collisions. Each namespace should be unique.`
243
+ );
244
+ }
245
+ }
246
+ registeredNamespaces.add(namespace);
247
+ const rules = [];
248
+ if (base) {
249
+ rules.push(...serializeStyle(`.${namespace}-base`, base));
250
+ }
251
+ for (const [dimension, options] of Object.entries(variants)) {
252
+ for (const [option, properties] of Object.entries(options)) {
253
+ const className = `.${namespace}-${dimension}-${option}`;
254
+ rules.push(...serializeStyle(className, properties));
255
+ }
256
+ }
257
+ compoundVariants.forEach(
258
+ (cv, index) => {
259
+ const className = `.${namespace}-compound-${index}`;
260
+ rules.push(...serializeStyle(className, cv.style));
261
+ }
262
+ );
263
+ insertRules(rules);
264
+ return ((selections = {}) => {
265
+ const classes = [];
266
+ if (base) classes.push(`${namespace}-base`);
267
+ const resolvedSelections = {};
268
+ for (const dimension of Object.keys(variants)) {
269
+ resolvedSelections[dimension] = selections[dimension] ?? defaultVariants[dimension];
270
+ }
271
+ for (const dimension of Object.keys(variants)) {
272
+ const selected = resolvedSelections[dimension];
273
+ if (selected != null && selected !== false) {
274
+ classes.push(`${namespace}-${dimension}-${String(selected)}`);
275
+ }
276
+ }
277
+ compoundVariants.forEach(
278
+ (cv, index) => {
279
+ const matches = Object.entries(cv.variants).every(
280
+ ([k, v]) => resolvedSelections[k] === v
281
+ );
282
+ if (matches) classes.push(`${namespace}-compound-${index}`);
283
+ }
284
+ );
285
+ return classes.join(" ");
286
+ });
287
+ }
288
+
289
+ // src/global.ts
290
+ function globalStyle(selector, properties) {
291
+ const rules = serializeStyle(selector, properties);
292
+ insertRules(rules);
293
+ }
294
+ function globalFontFace(family, props) {
295
+ const decls = [`font-family: "${family}"`, `src: ${props.src}`];
296
+ if (props.fontWeight != null) decls.push(`font-weight: ${props.fontWeight}`);
297
+ if (props.fontStyle) decls.push(`font-style: ${props.fontStyle}`);
298
+ if (props.fontDisplay) decls.push(`font-display: ${props.fontDisplay}`);
299
+ if (props.fontStretch) decls.push(`font-stretch: ${props.fontStretch}`);
300
+ if (props.unicodeRange) decls.push(`unicode-range: ${props.unicodeRange}`);
301
+ const css = `@font-face { ${decls.join("; ")}; }`;
302
+ insertRule(`font-face:${family}:${props.src}`, css);
303
+ }
304
+
305
+ // src/index.ts
306
+ var styles = {
307
+ create: createStyles,
308
+ component: createComponent
309
+ };
310
+ var global = {
311
+ style: globalStyle,
312
+ fontFace: globalFontFace
313
+ };
314
+ var tokens = {
315
+ create: createTokens,
316
+ use: useTokens,
317
+ createTheme
318
+ };
319
+ var keyframes = {
320
+ create: createKeyframes
321
+ };
322
+ var color = color_exports;
323
+
324
+ export { color, global, keyframes, styles, tokens };
325
+ //# sourceMappingURL=index.js.map
326
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/css.ts","../src/registry.ts","../src/styles.ts","../src/tokens.ts","../src/keyframes.ts","../src/color.ts","../src/component.ts","../src/global.ts","../src/index.ts"],"names":["registeredNamespaces","alpha"],"mappings":"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","file":"index.js","sourcesContent":["import type { CSSProperties } from './types.js';\n\n/**\n * Convert a camelCase CSS property name to kebab-case.\n * Handles vendor prefixes (ms, webkit, moz) correctly.\n */\nexport function toKebabCase(prop: string): string {\n // Handle ms- prefix specially (no leading dash in camelCase)\n if (prop.startsWith('ms')) {\n return '-' + prop.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase());\n }\n return prop.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase());\n}\n\n/**\n * Serialize a single CSS value. Numbers are treated as px for most properties.\n */\nfunction serializeValue(prop: string, value: string | number): string {\n if (typeof value === 'number') {\n if (value === 0) return '0';\n // Unitless properties that shouldn't get 'px'\n if (unitlessProperties.has(prop)) return String(value);\n return value + 'px';\n }\n return value;\n}\n\nconst unitlessProperties = new Set([\n 'animationIterationCount',\n 'borderImageOutset',\n 'borderImageSlice',\n 'borderImageWidth',\n 'columnCount',\n 'columns',\n 'flex',\n 'flexGrow',\n 'flexPositive',\n 'flexShrink',\n 'flexNegative',\n 'flexOrder',\n 'fontWeight',\n 'gridArea',\n 'gridColumn',\n 'gridColumnEnd',\n 'gridColumnSpan',\n 'gridColumnStart',\n 'gridRow',\n 'gridRowEnd',\n 'gridRowSpan',\n 'gridRowStart',\n 'lineClamp',\n 'lineHeight',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'widows',\n 'zIndex',\n 'zoom',\n 'fillOpacity',\n 'floodOpacity',\n 'stopOpacity',\n 'strokeDasharray',\n 'strokeDashoffset',\n 'strokeMiterlimit',\n 'strokeOpacity',\n 'strokeWidth',\n]);\n\n/**\n * Represents a generated CSS rule.\n */\nexport interface CSSRule {\n /** Unique key for deduplication */\n key: string;\n /** The CSS rule string */\n css: string;\n}\n\n/**\n * Serialize a style definition object into CSS rule(s) for a given selector.\n */\nexport function serializeStyle(\n selector: string,\n properties: CSSProperties\n): CSSRule[] {\n const rules: CSSRule[] = [];\n const declarations: string[] = [];\n\n for (const [prop, value] of Object.entries(properties)) {\n if (value == null) continue;\n\n if (prop.startsWith('&')) {\n // Nested selector: replace & with the parent selector\n const nestedSelector = prop.replace(/&/g, selector);\n rules.push(\n ...serializeStyle(nestedSelector, value as CSSProperties)\n );\n } else if (prop.startsWith('@')) {\n // At-rule: wrap the serialized content in the at-rule\n const innerRules = serializeStyle(selector, value as CSSProperties);\n for (const inner of innerRules) {\n rules.push({\n key: `${prop}:${inner.key}`,\n css: `${prop} { ${inner.css} }`,\n });\n }\n } else {\n // Regular CSS property\n const kebabProp = toKebabCase(prop);\n declarations.push(\n `${kebabProp}: ${serializeValue(prop, value as string | number)}`\n );\n }\n }\n\n // Add the base rule with all plain declarations\n if (declarations.length > 0) {\n rules.unshift({\n key: selector,\n css: `${selector} { ${declarations.join('; ')}; }`,\n });\n }\n\n return rules;\n}\n","/**\n * Shared registry for detecting duplicate namespace registrations.\n */\nexport const registeredNamespaces = new Set<string>();\n","import type { CSSProperties, SelectorFunction, StyleDefinitions } from './types.js';\nimport { serializeStyle } from './css.js';\nimport { insertRules } from './sheet.js';\nimport { registeredNamespaces } from './registry.js';\n\n/**\n * Create a style group and return a selector function.\n *\n * The selector function accepts variant names and returns a composed\n * class name string. Class names are deterministic and human-readable:\n * `{namespace}-{variant}`.\n *\n * @example\n * ```ts\n * const button = createStyles('button', {\n * base: { padding: '8px 16px', fontSize: '14px' },\n * primary: { backgroundColor: '#0066ff', color: '#fff' },\n * large: { padding: '12px 24px', fontSize: '16px' },\n * });\n *\n * button('base', 'primary') // \"button-base button-primary\"\n * button('base', isLarge && 'large') // conditional application\n * ```\n */\nexport function createStyles<K extends string>(\n namespace: string,\n definitions: StyleDefinitions & Record<K, CSSProperties>\n): SelectorFunction<K> {\n // Development-mode duplicate detection\n if (process.env.NODE_ENV !== 'production') {\n if (registeredNamespaces.has(namespace)) {\n console.warn(\n `[typestyles] styles.create('${namespace}', ...) called more than once. ` +\n `This will cause class name collisions. Each namespace should be unique.`\n );\n }\n }\n registeredNamespaces.add(namespace);\n\n // Generate and inject CSS for all variants\n const rules: Array<{ key: string; css: string }> = [];\n\n for (const [variant, properties] of Object.entries(definitions)) {\n const className = `${namespace}-${variant}`;\n const selector = `.${className}`;\n const variantRules = serializeStyle(selector, properties as CSSProperties);\n rules.push(...variantRules);\n }\n\n insertRules(rules);\n\n // Return the selector function\n const selectorFn = (...variants: (K | false | null | undefined)[]): string => {\n return variants\n .filter(Boolean)\n .map((v) => `${namespace}-${v as string}`)\n .join(' ');\n };\n\n return selectorFn as SelectorFunction<K>;\n}\n","import type { TokenValues, TokenRef, ThemeOverrides } from './types.js';\nimport { insertRule } from './sheet.js';\n\n/**\n * Registry tracking which token namespaces have been created,\n * so tokens.use() can provide warnings in development.\n */\nconst registeredNamespaces = new Set<string>();\n\n/**\n * Create a proxy-based token reference for a namespace.\n * Property access returns var(--{namespace}-{key}).\n */\nfunction createTokenProxy<T extends TokenValues>(namespace: string): TokenRef<T> {\n return new Proxy({} as TokenRef<T>, {\n get(_target, prop: string) {\n return `var(--${namespace}-${prop})`;\n },\n });\n}\n\n/**\n * Create design tokens as CSS custom properties.\n *\n * Generates a :root rule with the custom properties and returns\n * a typed object where property access yields var() references.\n *\n * @example\n * ```ts\n * const color = createTokens('color', {\n * primary: '#0066ff',\n * secondary: '#6b7280',\n * });\n *\n * color.primary // \"var(--color-primary)\"\n * ```\n */\nexport function createTokens<T extends TokenValues>(\n namespace: string,\n values: T\n): TokenRef<T> {\n registeredNamespaces.add(namespace);\n\n // Generate CSS custom property declarations\n const declarations = Object.entries(values)\n .map(([key, value]) => `--${namespace}-${key}: ${value}`)\n .join('; ');\n\n const css = `:root { ${declarations}; }`;\n insertRule(`tokens:${namespace}`, css);\n\n return createTokenProxy<T>(namespace);\n}\n\n/**\n * Reference tokens defined elsewhere without injecting CSS.\n *\n * Returns a typed proxy that produces var() references.\n * Useful for consuming shared tokens from a different module.\n *\n * @example\n * ```ts\n * const color = useTokens('color');\n * color.primary // \"var(--color-primary)\"\n * ```\n */\nexport function useTokens<T extends TokenValues = TokenValues>(\n namespace: string\n): TokenRef<T> {\n if (\n process.env.NODE_ENV !== 'production' &&\n registeredNamespaces.size > 0 &&\n !registeredNamespaces.has(namespace)\n ) {\n console.warn(\n `[typestyles] tokens.use('${namespace}') references a namespace that hasn't been created yet. ` +\n `Make sure tokens.create('${namespace}', ...) is called before using these tokens.`\n );\n }\n\n return createTokenProxy<T>(namespace);\n}\n\n/**\n * Create a theme class that overrides token values.\n *\n * Returns a class name string. Apply it to any element to override\n * token values for that subtree via CSS custom property cascading.\n *\n * @example\n * ```ts\n * const dark = createTheme('dark', {\n * color: { primary: '#66b3ff', surface: '#1a1a2e' },\n * });\n *\n * <div className={dark}> // class=\"theme-dark\"\n * ```\n */\nexport function createTheme(name: string, overrides: ThemeOverrides): string {\n const className = `theme-${name}`;\n\n const declarations: string[] = [];\n for (const [namespace, values] of Object.entries(overrides)) {\n for (const [key, value] of Object.entries(values)) {\n if (value != null) {\n declarations.push(`--${namespace}-${key}: ${value}`);\n }\n }\n }\n\n const css = `.${className} { ${declarations.join('; ')}; }`;\n insertRule(`theme:${name}`, css);\n\n return className;\n}\n","import type { CSSProperties } from './types.js';\nimport { toKebabCase } from './css.js';\nimport { insertRule } from './sheet.js';\n\n/**\n * A keyframe stop is either 'from', 'to', or a percentage like '50%'.\n */\nexport type KeyframeStops = Record<string, CSSProperties>;\n\n/**\n * Serialize CSS declarations for a single keyframe stop (no nesting/at-rules).\n */\nfunction serializeDeclarations(properties: CSSProperties): string {\n const declarations: string[] = [];\n\n for (const [prop, value] of Object.entries(properties)) {\n if (value == null) continue;\n // Keyframe stops only contain plain properties — skip nested selectors/at-rules\n if (prop.startsWith('&') || prop.startsWith('@')) continue;\n\n const kebabProp = toKebabCase(prop);\n const serialized =\n typeof value === 'number' ? (value === 0 ? '0' : value + 'px') : value;\n declarations.push(`${kebabProp}: ${serialized}`);\n }\n\n return declarations.join('; ');\n}\n\n/**\n * Create a CSS @keyframes animation and return its name.\n *\n * The returned string is the animation name — use it directly in\n * `animation` shorthand or `animationName`.\n *\n * @example\n * ```ts\n * const fadeIn = keyframes.create('fadeIn', {\n * from: { opacity: 0 },\n * to: { opacity: 1 },\n * });\n *\n * const card = styles.create('card', {\n * base: { animation: `${fadeIn} 300ms ease` },\n * });\n * ```\n *\n * @example\n * ```ts\n * const bounce = keyframes.create('bounce', {\n * '0%': { transform: 'translateY(0)' },\n * '50%': { transform: 'translateY(-20px)' },\n * '100%': { transform: 'translateY(0)' },\n * });\n * ```\n */\nexport function createKeyframes(name: string, stops: KeyframeStops): string {\n const stopsCSS = Object.entries(stops)\n .map(([stop, properties]) => {\n const decls = serializeDeclarations(properties as CSSProperties);\n return `${stop} { ${decls}; }`;\n })\n .join(' ');\n\n const css = `@keyframes ${name} { ${stopsCSS} }`;\n insertRule(`keyframes:${name}`, css);\n\n return name;\n}\n","/**\n * Type-safe helpers for CSS color functions.\n *\n * Each function returns a plain CSS string — no runtime color math.\n * Works naturally with token references since tokens are strings too.\n */\n\ntype ColorValue = string | number;\n\n/** Color spaces supported by color-mix(). */\nexport type ColorMixSpace =\n | 'srgb'\n | 'srgb-linear'\n | 'display-p3'\n | 'a98-rgb'\n | 'prophoto-rgb'\n | 'rec2020'\n | 'lab'\n | 'oklab'\n | 'xyz'\n | 'xyz-d50'\n | 'xyz-d65'\n | 'hsl'\n | 'hwb'\n | 'lch'\n | 'oklch';\n\n/**\n * `rgb(r g b)` or `rgb(r g b / a)`\n *\n * @example\n * ```ts\n * color.rgb(0, 102, 255) // \"rgb(0 102 255)\"\n * color.rgb(0, 102, 255, 0.5) // \"rgb(0 102 255 / 0.5)\"\n * ```\n */\nexport function rgb(r: ColorValue, g: ColorValue, b: ColorValue, alpha?: ColorValue): string {\n if (alpha != null) return `rgb(${r} ${g} ${b} / ${alpha})`;\n return `rgb(${r} ${g} ${b})`;\n}\n\n/**\n * `hsl(h s l)` or `hsl(h s l / a)`\n *\n * @example\n * ```ts\n * color.hsl(220, '100%', '50%') // \"hsl(220 100% 50%)\"\n * color.hsl(220, '100%', '50%', 0.8) // \"hsl(220 100% 50% / 0.8)\"\n * ```\n */\nexport function hsl(h: ColorValue, s: ColorValue, l: ColorValue, alpha?: ColorValue): string {\n if (alpha != null) return `hsl(${h} ${s} ${l} / ${alpha})`;\n return `hsl(${h} ${s} ${l})`;\n}\n\n/**\n * `oklch(L C h)` or `oklch(L C h / a)`\n *\n * @example\n * ```ts\n * color.oklch(0.7, 0.15, 250) // \"oklch(0.7 0.15 250)\"\n * color.oklch(0.7, 0.15, 250, 0.5) // \"oklch(0.7 0.15 250 / 0.5)\"\n * ```\n */\nexport function oklch(l: ColorValue, c: ColorValue, h: ColorValue, alpha?: ColorValue): string {\n if (alpha != null) return `oklch(${l} ${c} ${h} / ${alpha})`;\n return `oklch(${l} ${c} ${h})`;\n}\n\n/**\n * `oklab(L a b)` or `oklab(L a b / alpha)`\n *\n * @example\n * ```ts\n * color.oklab(0.7, -0.1, -0.1) // \"oklab(0.7 -0.1 -0.1)\"\n * color.oklab(0.7, -0.1, -0.1, 0.5) // \"oklab(0.7 -0.1 -0.1 / 0.5)\"\n * ```\n */\nexport function oklab(l: ColorValue, a: ColorValue, b: ColorValue, alpha?: ColorValue): string {\n if (alpha != null) return `oklab(${l} ${a} ${b} / ${alpha})`;\n return `oklab(${l} ${a} ${b})`;\n}\n\n/**\n * `lab(L a b)` or `lab(L a b / alpha)`\n *\n * @example\n * ```ts\n * color.lab('50%', 40, -20) // \"lab(50% 40 -20)\"\n * ```\n */\nexport function lab(l: ColorValue, a: ColorValue, b: ColorValue, alpha?: ColorValue): string {\n if (alpha != null) return `lab(${l} ${a} ${b} / ${alpha})`;\n return `lab(${l} ${a} ${b})`;\n}\n\n/**\n * `lch(L C h)` or `lch(L C h / alpha)`\n *\n * @example\n * ```ts\n * color.lch('50%', 80, 250) // \"lch(50% 80 250)\"\n * ```\n */\nexport function lch(l: ColorValue, c: ColorValue, h: ColorValue, alpha?: ColorValue): string {\n if (alpha != null) return `lch(${l} ${c} ${h} / ${alpha})`;\n return `lch(${l} ${c} ${h})`;\n}\n\n/**\n * `hwb(h w b)` or `hwb(h w b / alpha)`\n *\n * @example\n * ```ts\n * color.hwb(220, '10%', '0%') // \"hwb(220 10% 0%)\"\n * ```\n */\nexport function hwb(h: ColorValue, w: ColorValue, b: ColorValue, alpha?: ColorValue): string {\n if (alpha != null) return `hwb(${h} ${w} ${b} / ${alpha})`;\n return `hwb(${h} ${w} ${b})`;\n}\n\n/**\n * `color-mix(in colorspace, color1 p1%, color2 p2%)`\n *\n * Mixes two colors in the given color space. Percentages are optional.\n *\n * @example\n * ```ts\n * color.mix('red', 'blue') // \"color-mix(in srgb, red, blue)\"\n * color.mix('red', 'blue', 30) // \"color-mix(in srgb, red 30%, blue)\"\n * color.mix(theme.primary, 'white', 20) // \"color-mix(in srgb, var(--theme-primary) 20%, white)\"\n * color.mix('red', 'blue', 50, 'oklch') // \"color-mix(in oklch, red 50%, blue)\"\n * ```\n */\nexport function mix(\n color1: string,\n color2: string,\n percentage?: number,\n colorSpace: ColorMixSpace = 'srgb'\n): string {\n const c1 = percentage != null ? `${color1} ${percentage}%` : color1;\n return `color-mix(in ${colorSpace}, ${c1}, ${color2})`;\n}\n\n/**\n * `light-dark(lightColor, darkColor)`\n *\n * Uses the `light-dark()` CSS function that resolves based on\n * the computed `color-scheme` of the element.\n *\n * @example\n * ```ts\n * color.lightDark('#111', '#eee') // \"light-dark(#111, #eee)\"\n * color.lightDark(theme.textLight, theme.textDark) // \"light-dark(var(--theme-textLight), var(--theme-textDark))\"\n * ```\n */\nexport function lightDark(lightColor: string, darkColor: string): string {\n return `light-dark(${lightColor}, ${darkColor})`;\n}\n\n/**\n * Adjust the alpha/opacity of any color using `color-mix()`.\n *\n * This is a common pattern: mixing a color with transparent to change opacity.\n * Works with any color value including token references.\n *\n * @example\n * ```ts\n * color.alpha('red', 0.5) // \"color-mix(in srgb, red 50%, transparent)\"\n * color.alpha(theme.primary, 0.2) // \"color-mix(in srgb, var(--theme-primary) 20%, transparent)\"\n * color.alpha('#0066ff', 0.8, 'oklch') // \"color-mix(in oklch, #0066ff 80%, transparent)\"\n * ```\n */\nexport function alpha(\n colorValue: string,\n opacity: number,\n colorSpace: ColorMixSpace = 'srgb'\n): string {\n const percentage = Math.round(opacity * 100);\n return `color-mix(in ${colorSpace}, ${colorValue} ${percentage}%, transparent)`;\n}\n","import type { CSSProperties, VariantDefinitions, ComponentConfig, ComponentFunction } from './types.js';\nimport { serializeStyle } from './css.js';\nimport { insertRules } from './sheet.js';\nimport { registeredNamespaces } from './registry.js';\n\n/**\n * Create a multi-variant component style and return a selector function.\n *\n * Class naming convention:\n * base → `{namespace}-base`\n * variants.intent.primary → `{namespace}-intent-primary`\n * compoundVariants[0] → `{namespace}-compound-0`\n *\n * @example\n * ```ts\n * const button = styles.component('button', {\n * base: { padding: '8px 16px' },\n * variants: {\n * intent: {\n * primary: { backgroundColor: '#0066ff', color: '#fff' },\n * ghost: { backgroundColor: 'transparent', border: '1px solid currentColor' },\n * },\n * size: {\n * sm: { fontSize: '12px' },\n * lg: { fontSize: '18px' },\n * },\n * },\n * compoundVariants: [\n * { variants: { intent: 'primary', size: 'lg' }, style: { fontWeight: 700 } },\n * ],\n * defaultVariants: { intent: 'primary', size: 'sm' },\n * });\n *\n * button() // \"button-base button-intent-primary button-size-sm\"\n * button({ intent: 'ghost' }) // \"button-base button-intent-ghost button-size-sm\"\n * button({ intent: 'primary', size: 'lg' }) // includes compound class\n * ```\n */\nexport function createComponent<V extends VariantDefinitions>(\n namespace: string,\n config: ComponentConfig<V>\n): ComponentFunction<V> {\n const { base, variants = {} as V, compoundVariants = [], defaultVariants = {} } = config;\n\n // Development-mode duplicate detection\n if (process.env.NODE_ENV !== 'production') {\n if (registeredNamespaces.has(namespace)) {\n console.warn(\n `[typestyles] styles.component('${namespace}', ...) called more than once. ` +\n `This will cause class name collisions. Each namespace should be unique.`\n );\n }\n }\n registeredNamespaces.add(namespace);\n\n const rules: Array<{ key: string; css: string }> = [];\n\n // 1. Inject CSS for base\n if (base) {\n rules.push(...serializeStyle(`.${namespace}-base`, base));\n }\n\n // 2. Inject CSS for each variant option\n for (const [dimension, options] of Object.entries(variants)) {\n for (const [option, properties] of Object.entries(options as Record<string, CSSProperties>)) {\n const className = `.${namespace}-${dimension}-${option}`;\n rules.push(...serializeStyle(className, properties));\n }\n }\n\n // 3. Inject CSS for each compound variant\n (compoundVariants as Array<{ variants: Record<string, unknown>; style: CSSProperties }>).forEach(\n (cv, index) => {\n const className = `.${namespace}-compound-${index}`;\n rules.push(...serializeStyle(className, cv.style));\n }\n );\n\n insertRules(rules);\n\n // 4. Return the selector function\n return ((selections: Record<string, unknown> = {}) => {\n const classes: string[] = [];\n\n if (base) classes.push(`${namespace}-base`);\n\n // Resolve final selections (explicit overrides defaultVariants)\n const resolvedSelections: Record<string, unknown> = {};\n for (const dimension of Object.keys(variants)) {\n resolvedSelections[dimension] =\n selections[dimension] ?? (defaultVariants as Record<string, unknown>)[dimension];\n }\n\n // Apply variant classes\n for (const dimension of Object.keys(variants)) {\n const selected = resolvedSelections[dimension];\n if (selected != null && selected !== false) {\n classes.push(`${namespace}-${dimension}-${String(selected)}`);\n }\n }\n\n // Apply compound variant classes\n (compoundVariants as Array<{ variants: Record<string, unknown>; style: CSSProperties }>).forEach(\n (cv, index) => {\n const matches = Object.entries(cv.variants).every(\n ([k, v]) => resolvedSelections[k] === v\n );\n if (matches) classes.push(`${namespace}-compound-${index}`);\n }\n );\n\n return classes.join(' ');\n }) as ComponentFunction<V>;\n}\n","import type { CSSProperties, FontFaceProps } from './types.js';\nimport { serializeStyle } from './css.js';\nimport { insertRule, insertRules } from './sheet.js';\n\n/**\n * Apply styles to an arbitrary CSS selector.\n *\n * Use for CSS resets, body/root defaults, third-party elements, or any\n * selector that isn't tied to a specific component class.\n *\n * @example\n * ```ts\n * global.style('body', { margin: 0, fontFamily: 'sans-serif' });\n * global.style('a:hover', { textDecoration: 'underline' });\n * global.style('*, *::before, *::after', { boxSizing: 'border-box' });\n * ```\n */\nexport function globalStyle(selector: string, properties: CSSProperties): void {\n const rules = serializeStyle(selector, properties);\n insertRules(rules);\n}\n\n/**\n * Declare a `@font-face` rule to load a custom font.\n *\n * Multiple weights/styles of the same family can be registered by calling\n * this function multiple times with different `src` values — each call is\n * deduplicated by `family + src`.\n *\n * @example\n * ```ts\n * global.fontFace('Inter', {\n * src: \"url('/fonts/Inter-Regular.woff2') format('woff2')\",\n * fontWeight: 400,\n * fontStyle: 'normal',\n * fontDisplay: 'swap',\n * });\n *\n * global.fontFace('Inter', {\n * src: \"url('/fonts/Inter-Bold.woff2') format('woff2')\",\n * fontWeight: 700,\n * fontStyle: 'normal',\n * fontDisplay: 'swap',\n * });\n * ```\n */\nexport function globalFontFace(family: string, props: FontFaceProps): void {\n const decls: string[] = [`font-family: \"${family}\"`, `src: ${props.src}`];\n if (props.fontWeight != null) decls.push(`font-weight: ${props.fontWeight}`);\n if (props.fontStyle) decls.push(`font-style: ${props.fontStyle}`);\n if (props.fontDisplay) decls.push(`font-display: ${props.fontDisplay}`);\n if (props.fontStretch) decls.push(`font-stretch: ${props.fontStretch}`);\n if (props.unicodeRange) decls.push(`unicode-range: ${props.unicodeRange}`);\n const css = `@font-face { ${decls.join('; ')}; }`;\n // Key includes src for uniqueness (multiple weights per family)\n insertRule(`font-face:${family}:${props.src}`, css);\n}\n","import { createStyles } from './styles.js';\nimport { createTokens, useTokens, createTheme } from './tokens.js';\nimport { createKeyframes } from './keyframes.js';\nimport * as colorFns from './color.js';\nimport { getRegisteredCss } from './sheet.js';\nimport { createComponent } from './component.js';\nimport { globalStyle, globalFontFace } from './global.js';\n\nexport type {\n CSSProperties,\n CSSValue,\n StyleDefinitions,\n SelectorFunction,\n TokenValues,\n TokenRef,\n ThemeOverrides,\n KeyframeStops,\n VariantDefinitions,\n ComponentConfig,\n ComponentFunction,\n FontFaceProps,\n} from './types.js';\n\nexport type { ColorMixSpace } from './color.js';\n\n/**\n * Style creation API.\n *\n * @example\n * ```ts\n * const button = styles.create('button', {\n * base: { padding: '8px 16px' },\n * primary: { backgroundColor: '#0066ff' },\n * });\n *\n * <button className={button('base', 'primary')}>\n * ```\n */\nexport const styles = {\n create: createStyles,\n component: createComponent,\n} as const;\n\n/**\n * Global CSS API for arbitrary selectors and font-face declarations.\n *\n * @example\n * ```ts\n * global.style('body', { margin: 0 });\n * global.fontFace('Inter', { src: \"url('/Inter.woff2') format('woff2')\", fontWeight: 400 });\n * ```\n */\nexport const global = {\n style: globalStyle,\n fontFace: globalFontFace,\n} as const;\n\n/**\n * Design token API using CSS custom properties.\n *\n * @example\n * ```ts\n * const color = tokens.create('color', {\n * primary: '#0066ff',\n * });\n *\n * color.primary // \"var(--color-primary)\"\n * ```\n */\nexport const tokens = {\n create: createTokens,\n use: useTokens,\n createTheme,\n} as const;\n\n/**\n * Keyframe animation API.\n *\n * @example\n * ```ts\n * const fadeIn = keyframes.create('fadeIn', {\n * from: { opacity: 0 },\n * to: { opacity: 1 },\n * });\n *\n * const card = styles.create('card', {\n * base: { animation: `${fadeIn} 300ms ease` },\n * });\n * ```\n */\nexport const keyframes = {\n create: createKeyframes,\n} as const;\n\n/**\n * Type-safe CSS color function helpers.\n *\n * Each function returns a plain CSS color string — no runtime color math.\n * Composes naturally with token references.\n *\n * @example\n * ```ts\n * color.rgb(0, 102, 255) // \"rgb(0 102 255)\"\n * color.oklch(0.7, 0.15, 250) // \"oklch(0.7 0.15 250)\"\n * color.mix(theme.primary, 'white', 20) // \"color-mix(in srgb, var(--theme-primary) 20%, white)\"\n * color.alpha(theme.primary, 0.5) // \"color-mix(in srgb, var(--theme-primary) 50%, transparent)\"\n * color.lightDark('#111', '#eee') // \"light-dark(#111, #eee)\"\n * ```\n */\nexport const color = colorFns;\n\n/**\n * Return all registered CSS as a string (for SSR).\n *\n * Returns every CSS rule registered via `styles.create`, `tokens.create`,\n * `keyframes.create`, etc. Use this in your SSR head/meta function to\n * inject styles into the document.\n *\n * This is safe to import on the client — it has no server-specific\n * dependencies and will simply return whatever CSS has been registered.\n *\n * @example\n * ```ts\n * import { getRegisteredCss } from 'typestyles';\n *\n * // In a route's head function (e.g. TanStack Start):\n * export const Route = createRootRoute({\n * head: () => ({\n * styles: [{ id: 'typestyles', children: getRegisteredCss() }],\n * }),\n * });\n * ```\n */\nexport { getRegisteredCss };\n"]}
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ // src/sheet.ts
4
+ var STYLE_ELEMENT_ID = "typestyles";
5
+ var pendingRules = [];
6
+ var allRules = [];
7
+ var styleElement = null;
8
+ var ssrBuffer = null;
9
+ var isBrowser = typeof document !== "undefined" && typeof window !== "undefined";
10
+ function getStyleElement() {
11
+ if (styleElement) return styleElement;
12
+ const existing = document.getElementById(
13
+ STYLE_ELEMENT_ID
14
+ );
15
+ if (existing) {
16
+ styleElement = existing;
17
+ return styleElement;
18
+ }
19
+ styleElement = document.createElement("style");
20
+ styleElement.id = STYLE_ELEMENT_ID;
21
+ document.head.appendChild(styleElement);
22
+ return styleElement;
23
+ }
24
+ function flush() {
25
+ if (pendingRules.length === 0) return;
26
+ const rules = pendingRules;
27
+ pendingRules = [];
28
+ if (ssrBuffer) {
29
+ ssrBuffer.push(...rules);
30
+ return;
31
+ }
32
+ if (!isBrowser) return;
33
+ const el = getStyleElement();
34
+ const sheet = el.sheet;
35
+ if (sheet) {
36
+ for (const rule of rules) {
37
+ try {
38
+ sheet.insertRule(rule, sheet.cssRules.length);
39
+ } catch {
40
+ el.appendChild(document.createTextNode(rule));
41
+ }
42
+ }
43
+ } else {
44
+ el.appendChild(document.createTextNode(rules.join("\n")));
45
+ }
46
+ }
47
+ function startCollection() {
48
+ ssrBuffer = [];
49
+ return () => {
50
+ const css = ssrBuffer ? ssrBuffer.join("\n") : "";
51
+ ssrBuffer = null;
52
+ return css;
53
+ };
54
+ }
55
+ function getRegisteredCss() {
56
+ return allRules.join("\n");
57
+ }
58
+ function flushSync() {
59
+ flush();
60
+ }
61
+
62
+ // src/server.ts
63
+ function collectStyles(renderFn) {
64
+ const endCollection = startCollection();
65
+ const html = renderFn();
66
+ flushSync();
67
+ const css = endCollection();
68
+ return { html, css };
69
+ }
70
+
71
+ exports.collectStyles = collectStyles;
72
+ exports.getRegisteredCss = getRegisteredCss;
73
+ //# sourceMappingURL=server.cjs.map
74
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sheet.ts","../src/server.ts"],"names":[],"mappings":";;;AAAA,IAAM,gBAAA,GAAmB,YAAA;AAUzB,IAAI,eAAyB,EAAC;AAO9B,IAAM,WAAqB,EAAC;AAU5B,IAAI,YAAA,GAAwC,IAAA;AAK5C,IAAI,SAAA,GAA6B,IAAA;AAKjC,IAAM,SAAA,GACJ,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,MAAA,KAAW,WAAA;AAEvD,SAAS,eAAA,GAAoC;AAC3C,EAAA,IAAI,cAAc,OAAO,YAAA;AAGzB,EAAA,MAAM,WAAW,QAAA,CAAS,cAAA;AAAA,IACxB;AAAA,GACF;AACA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,YAAA,GAAe,QAAA;AACf,IAAA,OAAO,YAAA;AAAA,EACT;AAGA,EAAA,YAAA,GAAe,QAAA,CAAS,cAAc,OAAO,CAAA;AAC7C,EAAA,YAAA,CAAa,EAAA,GAAK,gBAAA;AAClB,EAAA,QAAA,CAAS,IAAA,CAAK,YAAY,YAAY,CAAA;AACtC,EAAA,OAAO,YAAA;AACT;AAEA,SAAS,KAAA,GAAc;AAErB,EAAA,IAAI,YAAA,CAAa,WAAW,CAAA,EAAG;AAE/B,EAAA,MAAM,KAAA,GAAQ,YAAA;AACd,EAAA,YAAA,GAAe,EAAC;AAEhB,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,SAAA,CAAU,IAAA,CAAK,GAAG,KAAK,CAAA;AACvB,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,SAAA,EAAW;AAEhB,EAAA,MAAM,KAAK,eAAA,EAAgB;AAC3B,EAAA,MAAM,QAAQ,EAAA,CAAG,KAAA;AAEjB,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAI;AACF,QAAA,KAAA,CAAM,UAAA,CAAW,IAAA,EAAM,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AAAA,MAC9C,CAAA,CAAA,MAAQ;AAEN,QAAA,EAAA,CAAG,WAAA,CAAY,QAAA,CAAS,cAAA,CAAe,IAAI,CAAC,CAAA;AAAA,MAC9C;AAAA,IACF;AAAA,EACF,CAAA,MAAO;AAEL,IAAA,EAAA,CAAG,YAAY,QAAA,CAAS,cAAA,CAAe,MAAM,IAAA,CAAK,IAAI,CAAC,CAAC,CAAA;AAAA,EAC1D;AACF;AAoEO,SAAS,eAAA,GAAgC;AAC9C,EAAA,SAAA,GAAY,EAAC;AACb,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,GAAA,GAAM,SAAA,GAAY,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,GAAI,EAAA;AAC/C,IAAA,SAAA,GAAY,IAAA;AACZ,IAAA,OAAO,GAAA;AAAA,EACT,CAAA;AACF;AAsBO,SAAS,gBAAA,GAA2B;AACzC,EAAA,OAAO,QAAA,CAAS,KAAK,IAAI,CAAA;AAC3B;AAoBO,SAAS,SAAA,GAAkB;AAChC,EAAA,KAAA,EAAM;AACR;;;ACpLO,SAAS,cAAiB,QAAA,EAA6C;AAC5E,EAAA,MAAM,gBAAgB,eAAA,EAAgB;AAEtC,EAAA,MAAM,OAAO,QAAA,EAAS;AACtB,EAAA,SAAA,EAAU;AACV,EAAA,MAAM,MAAM,aAAA,EAAc;AAE1B,EAAA,OAAO,EAAE,MAAM,GAAA,EAAI;AACrB","file":"server.cjs","sourcesContent":["const STYLE_ELEMENT_ID = 'typestyles';\n\n/**\n * Tracks which CSS rules have been inserted to avoid duplicates.\n */\nconst insertedRules = new Set<string>();\n\n/**\n * Buffer of CSS rules waiting to be flushed.\n */\nlet pendingRules: string[] = [];\n\n/**\n * All CSS rules ever registered (for SSR extraction).\n * Unlike pendingRules (which is cleared on flush), this retains every rule\n * so getRegisteredCss() can return the full stylesheet at any point.\n */\nconst allRules: string[] = [];\n\n/**\n * Whether a flush is scheduled.\n */\nlet flushScheduled = false;\n\n/**\n * The managed <style> element, lazily created.\n */\nlet styleElement: HTMLStyleElement | null = null;\n\n/**\n * When in SSR collection mode, CSS is captured here instead of injected.\n */\nlet ssrBuffer: string[] | null = null;\n\n/**\n * Whether we're running in a browser environment.\n */\nconst isBrowser =\n typeof document !== 'undefined' && typeof window !== 'undefined';\n\nfunction getStyleElement(): HTMLStyleElement {\n if (styleElement) return styleElement;\n\n // Check for an existing element (e.g., from SSR)\n const existing = document.getElementById(\n STYLE_ELEMENT_ID\n ) as HTMLStyleElement | null;\n if (existing) {\n styleElement = existing;\n return styleElement;\n }\n\n // Create a new one\n styleElement = document.createElement('style');\n styleElement.id = STYLE_ELEMENT_ID;\n document.head.appendChild(styleElement);\n return styleElement;\n}\n\nfunction flush(): void {\n flushScheduled = false;\n if (pendingRules.length === 0) return;\n\n const rules = pendingRules;\n pendingRules = [];\n\n if (ssrBuffer) {\n ssrBuffer.push(...rules);\n return;\n }\n\n if (!isBrowser) return;\n\n const el = getStyleElement();\n const sheet = el.sheet;\n\n if (sheet) {\n for (const rule of rules) {\n try {\n sheet.insertRule(rule, sheet.cssRules.length);\n } catch {\n // Fallback: append as text (handles edge cases with certain selectors)\n el.appendChild(document.createTextNode(rule));\n }\n }\n } else {\n // Sheet not available yet, append as text\n el.appendChild(document.createTextNode(rules.join('\\n')));\n }\n}\n\nfunction scheduleFlush(): void {\n if (flushScheduled) return;\n flushScheduled = true;\n\n if (ssrBuffer) {\n // In SSR mode, flush synchronously\n flush();\n return;\n }\n\n if (isBrowser) {\n // Use microtask for fast, batched insertion\n queueMicrotask(flush);\n }\n}\n\n/**\n * Insert a CSS rule. Deduplicates by rule key.\n */\nexport function insertRule(key: string, css: string): void {\n if (insertedRules.has(key)) return;\n insertedRules.add(key);\n pendingRules.push(css);\n allRules.push(css);\n scheduleFlush();\n}\n\n/**\n * Insert multiple CSS rules at once.\n */\nexport function insertRules(rules: Array<{ key: string; css: string }>): void {\n let added = false;\n for (const { key, css } of rules) {\n if (insertedRules.has(key)) continue;\n insertedRules.add(key);\n pendingRules.push(css);\n allRules.push(css);\n added = true;\n }\n if (added) scheduleFlush();\n}\n\n/**\n * Replace a CSS rule (used for HMR). Removes the old rule and inserts the new one.\n */\nexport function replaceRule(key: string, css: string): void {\n if (!isBrowser) return;\n\n insertedRules.delete(key);\n\n // Remove existing rule from the sheet if possible\n const el = getStyleElement();\n const sheet = el.sheet;\n if (sheet) {\n for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n // We can't reliably match by key in CSSOM, so for HMR we fall back to\n // clearing and re-inserting. This is fine since HMR is dev-only.\n }\n }\n\n insertRule(key, css);\n}\n\n/**\n * Start collecting CSS for SSR. Returns a function to stop collection and get the CSS.\n */\nexport function startCollection(): () => string {\n ssrBuffer = [];\n return () => {\n const css = ssrBuffer ? ssrBuffer.join('\\n') : '';\n ssrBuffer = null;\n return css;\n };\n}\n\n/**\n * Return all registered CSS as a string.\n *\n * Unlike `collectStyles`, this doesn't require wrapping a render function.\n * It simply returns every CSS rule that has been registered via\n * `styles.create`, `tokens.create`, `keyframes.create`, etc.\n *\n * Ideal for SSR frameworks that need the CSS separately from the render\n * pass (e.g. TanStack Start's `head()`, Next.js metadata, Remix links).\n *\n * @example\n * ```ts\n * import { getRegisteredCss } from 'typestyles/server';\n *\n * // In a route's head/meta function:\n * export const head = () => ({\n * styles: [{ id: 'typestyles', children: getRegisteredCss() }],\n * });\n * ```\n */\nexport function getRegisteredCss(): string {\n return allRules.join('\\n');\n}\n\n/**\n * Reset all state (useful for testing).\n */\nexport function reset(): void {\n insertedRules.clear();\n pendingRules = [];\n allRules.length = 0;\n flushScheduled = false;\n ssrBuffer = null;\n if (isBrowser && styleElement) {\n styleElement.remove();\n styleElement = null;\n }\n}\n\n/**\n * Flush all pending rules synchronously. Used for SSR and testing.\n */\nexport function flushSync(): void {\n flush();\n}\n\n/**\n * Invalidate all dedup keys that start with the given prefix.\n * Also removes matching rules from the live stylesheet.\n * Used for HMR — allows modules to re-register their styles after editing.\n */\nexport function invalidatePrefix(prefix: string): void {\n for (const key of insertedRules) {\n if (key.startsWith(prefix)) {\n insertedRules.delete(key);\n }\n }\n\n if (!isBrowser) return;\n\n const el = styleElement;\n if (!el) return;\n const sheet = el.sheet;\n if (!sheet) return;\n\n for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n const rule = sheet.cssRules[i];\n if (ruleMatchesPrefix(rule, prefix)) {\n sheet.deleteRule(i);\n }\n }\n}\n\n/**\n * Invalidate a list of exact keys or prefixes.\n * Each entry in `keys` is treated as an exact key match.\n * Each entry in `prefixes` is treated as a prefix match.\n * Used for HMR to invalidate all styles from a module at once.\n */\nexport function invalidateKeys(keys: string[], prefixes: string[]): void {\n for (const key of keys) {\n insertedRules.delete(key);\n }\n for (const prefix of prefixes) {\n for (const key of insertedRules) {\n if (key.startsWith(prefix)) {\n insertedRules.delete(key);\n }\n }\n }\n\n if (!isBrowser) return;\n\n const el = styleElement;\n if (!el) return;\n const sheet = el.sheet;\n if (!sheet) return;\n\n const keySet = new Set(keys);\n for (let i = sheet.cssRules.length - 1; i >= 0; i--) {\n const rule = sheet.cssRules[i];\n let shouldRemove = false;\n\n for (const prefix of prefixes) {\n if (ruleMatchesPrefix(rule, prefix)) {\n shouldRemove = true;\n break;\n }\n }\n\n if (!shouldRemove) {\n // Check exact key matches — for tokens/themes/keyframes,\n // we match based on rule content patterns\n const ruleText = rule.cssText;\n for (const key of keySet) {\n if (ruleMatchesKey(ruleText, key)) {\n shouldRemove = true;\n break;\n }\n }\n }\n\n if (shouldRemove) {\n sheet.deleteRule(i);\n }\n }\n}\n\nfunction ruleMatchesPrefix(rule: CSSRule, prefix: string): boolean {\n if (prefix.startsWith('font-face:')) {\n const family = prefix.slice('font-face:'.length).split(':')[0];\n // CSSFontFaceRule has type 5 and cssText contains @font-face\n if (rule.cssText.includes('@font-face')) {\n return (\n rule.cssText.includes(`\"${family}\"`) || rule.cssText.includes(`'${family}'`)\n );\n }\n return false;\n }\n if ('selectorText' in rule) {\n return (rule as CSSStyleRule).selectorText.startsWith(prefix);\n }\n if ('name' in rule && prefix.startsWith('keyframes:')) {\n return (rule as CSSKeyframesRule).name === prefix.slice('keyframes:'.length);\n }\n // For at-rules wrapping style rules, check inner rules\n if ('cssRules' in rule) {\n const innerRules = (rule as CSSGroupingRule).cssRules;\n for (let i = 0; i < innerRules.length; i++) {\n if (ruleMatchesPrefix(innerRules[i], prefix)) return true;\n }\n }\n return false;\n}\n\nfunction ruleMatchesKey(cssText: string, key: string): boolean {\n if (key.startsWith('tokens:')) {\n // tokens:color -> :root rule with --color- custom properties\n const namespace = key.slice('tokens:'.length);\n return cssText.includes(`:root`) && cssText.includes(`--${namespace}-`);\n }\n if (key.startsWith('theme:')) {\n // theme:dark -> .theme-dark selector\n const name = key.slice('theme:'.length);\n return cssText.includes(`.theme-${name}`);\n }\n if (key.startsWith('keyframes:')) {\n const name = key.slice('keyframes:'.length);\n return cssText.includes(`@keyframes ${name}`);\n }\n return false;\n}\n","import { startCollection, flushSync, getRegisteredCss } from './sheet.js';\n\nexport { getRegisteredCss };\n\n/**\n * Collect all CSS generated during a render pass (for SSR).\n *\n * Wraps a synchronous render function and captures all CSS that would\n * normally be injected into the DOM. Returns both the render result\n * and the collected CSS string.\n *\n * For frameworks where you need the CSS separately from the render pass\n * (e.g. TanStack Start's `head()`, Next.js metadata), use the simpler\n * `getRegisteredCss()` instead.\n *\n * @example\n * ```ts\n * import { collectStyles } from 'typestyles/server';\n * import { renderToString } from 'react-dom/server';\n *\n * const { html, css } = collectStyles(() => renderToString(<App />));\n *\n * const fullHtml = `\n * <html>\n * <head><style id=\"typestyles\">${css}</style></head>\n * <body>${html}</body>\n * </html>\n * `;\n * ```\n */\nexport function collectStyles<T>(renderFn: () => T): { html: T; css: string } {\n const endCollection = startCollection();\n\n const html = renderFn();\n flushSync();\n const css = endCollection();\n\n return { html, css };\n}\n"]}
@@ -0,0 +1,34 @@
1
+ export { g as getRegisteredCss } from './hmr-CSDtaPpU.cjs';
2
+
3
+ /**
4
+ * Collect all CSS generated during a render pass (for SSR).
5
+ *
6
+ * Wraps a synchronous render function and captures all CSS that would
7
+ * normally be injected into the DOM. Returns both the render result
8
+ * and the collected CSS string.
9
+ *
10
+ * For frameworks where you need the CSS separately from the render pass
11
+ * (e.g. TanStack Start's `head()`, Next.js metadata), use the simpler
12
+ * `getRegisteredCss()` instead.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { collectStyles } from 'typestyles/server';
17
+ * import { renderToString } from 'react-dom/server';
18
+ *
19
+ * const { html, css } = collectStyles(() => renderToString(<App />));
20
+ *
21
+ * const fullHtml = `
22
+ * <html>
23
+ * <head><style id="typestyles">${css}</style></head>
24
+ * <body>${html}</body>
25
+ * </html>
26
+ * `;
27
+ * ```
28
+ */
29
+ declare function collectStyles<T>(renderFn: () => T): {
30
+ html: T;
31
+ css: string;
32
+ };
33
+
34
+ export { collectStyles };
@@ -0,0 +1,34 @@
1
+ export { g as getRegisteredCss } from './hmr-CSDtaPpU.js';
2
+
3
+ /**
4
+ * Collect all CSS generated during a render pass (for SSR).
5
+ *
6
+ * Wraps a synchronous render function and captures all CSS that would
7
+ * normally be injected into the DOM. Returns both the render result
8
+ * and the collected CSS string.
9
+ *
10
+ * For frameworks where you need the CSS separately from the render pass
11
+ * (e.g. TanStack Start's `head()`, Next.js metadata), use the simpler
12
+ * `getRegisteredCss()` instead.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { collectStyles } from 'typestyles/server';
17
+ * import { renderToString } from 'react-dom/server';
18
+ *
19
+ * const { html, css } = collectStyles(() => renderToString(<App />));
20
+ *
21
+ * const fullHtml = `
22
+ * <html>
23
+ * <head><style id="typestyles">${css}</style></head>
24
+ * <body>${html}</body>
25
+ * </html>
26
+ * `;
27
+ * ```
28
+ */
29
+ declare function collectStyles<T>(renderFn: () => T): {
30
+ html: T;
31
+ css: string;
32
+ };
33
+
34
+ export { collectStyles };
package/dist/server.js ADDED
@@ -0,0 +1,15 @@
1
+ import { startCollection, flushSync } from './chunk-PFDN4Y4C.js';
2
+ export { getRegisteredCss } from './chunk-PFDN4Y4C.js';
3
+
4
+ // src/server.ts
5
+ function collectStyles(renderFn) {
6
+ const endCollection = startCollection();
7
+ const html = renderFn();
8
+ flushSync();
9
+ const css = endCollection();
10
+ return { html, css };
11
+ }
12
+
13
+ export { collectStyles };
14
+ //# sourceMappingURL=server.js.map
15
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";;;;AA8BO,SAAS,cAAiB,QAAA,EAA6C;AAC5E,EAAA,MAAM,gBAAgB,eAAA,EAAgB;AAEtC,EAAA,MAAM,OAAO,QAAA,EAAS;AACtB,EAAA,SAAA,EAAU;AACV,EAAA,MAAM,MAAM,aAAA,EAAc;AAE1B,EAAA,OAAO,EAAE,MAAM,GAAA,EAAI;AACrB","file":"server.js","sourcesContent":["import { startCollection, flushSync, getRegisteredCss } from './sheet.js';\n\nexport { getRegisteredCss };\n\n/**\n * Collect all CSS generated during a render pass (for SSR).\n *\n * Wraps a synchronous render function and captures all CSS that would\n * normally be injected into the DOM. Returns both the render result\n * and the collected CSS string.\n *\n * For frameworks where you need the CSS separately from the render pass\n * (e.g. TanStack Start's `head()`, Next.js metadata), use the simpler\n * `getRegisteredCss()` instead.\n *\n * @example\n * ```ts\n * import { collectStyles } from 'typestyles/server';\n * import { renderToString } from 'react-dom/server';\n *\n * const { html, css } = collectStyles(() => renderToString(<App />));\n *\n * const fullHtml = `\n * <html>\n * <head><style id=\"typestyles\">${css}</style></head>\n * <body>${html}</body>\n * </html>\n * `;\n * ```\n */\nexport function collectStyles<T>(renderFn: () => T): { html: T; css: string } {\n const endCollection = startCollection();\n\n const html = renderFn();\n flushSync();\n const css = endCollection();\n\n return { html, css };\n}\n"]}