tailwind-styled-v4 5.1.12 → 5.1.14

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.
@@ -1,90 +1,2 @@
1
- import React from 'react';
2
-
3
- /**
4
- * Queue a CSS rule for batched injection.
5
- * Multiple rules accumulated during one event loop tick are flushed together
6
- * in one requestAnimationFrame → one style recalculation.
7
- *
8
- * Rules diinjeksi via insertRule() — zero flicker, truly additive.
9
- */
10
- declare function batchedInject(cssRule: string): void;
11
- /**
12
- * Immediately flush all pending CSS rules to the DOM.
13
- * Called automatically by RAF each frame. Can also be called manually
14
- * after synchronous component setup where RAF timing is too late.
15
- *
16
- * Setiap rule diinjeksi secara individual via insertRule() — tidak ada
17
- * window dimana existing rules hilang.
18
- */
19
- declare function flushBatchedCss(): void;
20
- /**
21
- * Synchronous inject — skips batching.
22
- * Use for SSR / critical path where RAF is not available.
23
- *
24
- * Menggunakan insertRule() — tidak ada flicker meskipun dipanggil
25
- * di tengah render cycle.
26
- */
27
- declare function syncInject(cssRule: string): void;
28
- /**
29
- * Check if a rule has already been injected (deduplication check).
30
- */
31
- declare function isInjected(cssRule: string): boolean;
32
- /**
33
- * Clear all injected rules and remove the style element.
34
- * Useful for testing / SSR resets. Not for production use.
35
- */
36
- declare function resetBatchedCss(): void;
37
- /**
38
- * Get stats about the current injection state (for devtools).
39
- */
40
- declare function getBatchedCssStats(): {
41
- totalInjected: number;
42
- pendingCount: number;
43
- hasBatchScheduled: boolean;
44
- };
45
-
46
- /**
47
- * tailwind-styled-v4 — TwCssInjector
48
- *
49
- * React Server Component — inject route-specific CSS ke <head>.
50
- * Zero client JS, no hydration overhead, streaming-friendly.
51
- *
52
- * Pipeline:
53
- * 1. withTailwindStyled webpack plugin emit CSS manifest ke .next/static/css/tw/
54
- * 2. TwCssInjector baca manifest → inject <style> inline per route
55
- *
56
- * Usage:
57
- * // app/layout.tsx
58
- * import { TwCssInjector } from "tailwind-styled-v4/runtime-css"
59
- *
60
- * export default function Layout({ children }) {
61
- * return (
62
- * <html>
63
- * <head><TwCssInjector /></head>
64
- * <body>{children}</body>
65
- * </html>
66
- * )
67
- * }
68
- */
69
-
70
- interface CssInjectorProps {
71
- /** Route spesifik. Default: auto-detect */
72
- route?: string;
73
- /** Inject global CSS juga. Default: true */
74
- includeGlobal?: boolean;
75
- /** Minify inline CSS. Default: true */
76
- minify?: boolean;
77
- /** CSS directory. Default: .next/static/css/tw */
78
- cssDir?: string;
79
- }
80
- /**
81
- * Server Component — inject CSS per route ke <head>.
82
- * Baca dari manifest yang di-emit oleh TwCssManifestPlugin.
83
- */
84
- declare function TwCssInjector(props?: CssInjectorProps): Promise<React.ReactElement>;
85
- /**
86
- * Hook untuk client components — CSS sudah di-handle TwCssInjector di server.
87
- */
88
- declare function useTwClasses(classes: string): string;
89
-
90
- export { TwCssInjector, batchedInject, flushBatchedCss, getBatchedCssStats, isInjected, resetBatchedCss, syncInject, useTwClasses };
1
+ export { batchedInject, flushBatchedCss, getBatchedCssStats, isInjected, resetBatchedCss, syncInject } from '@tailwind-styled/runtime-css/client';
2
+ export { useTwClasses } from '@tailwind-styled/runtime-css/server';
@@ -1,90 +1,2 @@
1
- import React from 'react';
2
-
3
- /**
4
- * Queue a CSS rule for batched injection.
5
- * Multiple rules accumulated during one event loop tick are flushed together
6
- * in one requestAnimationFrame → one style recalculation.
7
- *
8
- * Rules diinjeksi via insertRule() — zero flicker, truly additive.
9
- */
10
- declare function batchedInject(cssRule: string): void;
11
- /**
12
- * Immediately flush all pending CSS rules to the DOM.
13
- * Called automatically by RAF each frame. Can also be called manually
14
- * after synchronous component setup where RAF timing is too late.
15
- *
16
- * Setiap rule diinjeksi secara individual via insertRule() — tidak ada
17
- * window dimana existing rules hilang.
18
- */
19
- declare function flushBatchedCss(): void;
20
- /**
21
- * Synchronous inject — skips batching.
22
- * Use for SSR / critical path where RAF is not available.
23
- *
24
- * Menggunakan insertRule() — tidak ada flicker meskipun dipanggil
25
- * di tengah render cycle.
26
- */
27
- declare function syncInject(cssRule: string): void;
28
- /**
29
- * Check if a rule has already been injected (deduplication check).
30
- */
31
- declare function isInjected(cssRule: string): boolean;
32
- /**
33
- * Clear all injected rules and remove the style element.
34
- * Useful for testing / SSR resets. Not for production use.
35
- */
36
- declare function resetBatchedCss(): void;
37
- /**
38
- * Get stats about the current injection state (for devtools).
39
- */
40
- declare function getBatchedCssStats(): {
41
- totalInjected: number;
42
- pendingCount: number;
43
- hasBatchScheduled: boolean;
44
- };
45
-
46
- /**
47
- * tailwind-styled-v4 — TwCssInjector
48
- *
49
- * React Server Component — inject route-specific CSS ke <head>.
50
- * Zero client JS, no hydration overhead, streaming-friendly.
51
- *
52
- * Pipeline:
53
- * 1. withTailwindStyled webpack plugin emit CSS manifest ke .next/static/css/tw/
54
- * 2. TwCssInjector baca manifest → inject <style> inline per route
55
- *
56
- * Usage:
57
- * // app/layout.tsx
58
- * import { TwCssInjector } from "tailwind-styled-v4/runtime-css"
59
- *
60
- * export default function Layout({ children }) {
61
- * return (
62
- * <html>
63
- * <head><TwCssInjector /></head>
64
- * <body>{children}</body>
65
- * </html>
66
- * )
67
- * }
68
- */
69
-
70
- interface CssInjectorProps {
71
- /** Route spesifik. Default: auto-detect */
72
- route?: string;
73
- /** Inject global CSS juga. Default: true */
74
- includeGlobal?: boolean;
75
- /** Minify inline CSS. Default: true */
76
- minify?: boolean;
77
- /** CSS directory. Default: .next/static/css/tw */
78
- cssDir?: string;
79
- }
80
- /**
81
- * Server Component — inject CSS per route ke <head>.
82
- * Baca dari manifest yang di-emit oleh TwCssManifestPlugin.
83
- */
84
- declare function TwCssInjector(props?: CssInjectorProps): Promise<React.ReactElement>;
85
- /**
86
- * Hook untuk client components — CSS sudah di-handle TwCssInjector di server.
87
- */
88
- declare function useTwClasses(classes: string): string;
89
-
90
- export { TwCssInjector, batchedInject, flushBatchedCss, getBatchedCssStats, isInjected, resetBatchedCss, syncInject, useTwClasses };
1
+ export { batchedInject, flushBatchedCss, getBatchedCssStats, isInjected, resetBatchedCss, syncInject } from '@tailwind-styled/runtime-css/client';
2
+ export { useTwClasses } from '@tailwind-styled/runtime-css/server';
@@ -31,7 +31,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/umbrella/runtime-css.ts
32
32
  var runtime_css_exports = {};
33
33
  __export(runtime_css_exports, {
34
- TwCssInjector: () => TwCssInjector,
35
34
  batchedInject: () => batchedInject,
36
35
  flushBatchedCss: () => flushBatchedCss,
37
36
  getBatchedCssStats: () => getBatchedCssStats,
@@ -42,7 +41,7 @@ __export(runtime_css_exports, {
42
41
  });
43
42
  module.exports = __toCommonJS(runtime_css_exports);
44
43
 
45
- // packages/domain/runtime-css/src/batchedInjector.ts
44
+ // packages/domain/runtime-css/dist/batchedInjector.js
46
45
  var injected = /* @__PURE__ */ new Set();
47
46
  var pending = [];
48
47
  var _state = {
@@ -123,65 +122,13 @@ function getBatchedCssStats() {
123
122
  };
124
123
  }
125
124
 
126
- // packages/domain/runtime-css/src/CssInjector.tsx
125
+ // packages/domain/runtime-css/dist/CssInjector.js
127
126
  var import_react = __toESM(require("react"), 1);
128
- async function TwCssInjector(props = {}) {
129
- const { route, includeGlobal = true, minify = true, cssDir } = props;
130
- let fs = null;
131
- let path = null;
132
- try {
133
- fs = await import("fs");
134
- path = await import("path");
135
- } catch {
136
- return import_react.default.createElement(import_react.default.Fragment, null);
137
- }
138
- const resolvedDir = cssDir ?? path.join(process.cwd(), ".next", "static", "css", "tw");
139
- const manifestPath = path.join(resolvedDir, "css-manifest.json");
140
- let manifest = {};
141
- try {
142
- if (fs.existsSync(manifestPath)) {
143
- manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
144
- }
145
- } catch {
146
- return import_react.default.createElement(import_react.default.Fragment, null);
147
- }
148
- const cssChunks = [];
149
- if (includeGlobal && manifest.routes?.["__global"]) {
150
- const globalPath = path.join(resolvedDir, manifest.routes["__global"]);
151
- const css = readFile(fs, globalPath);
152
- if (css) cssChunks.push(css);
153
- }
154
- const targetRoute = route ?? "/";
155
- if (manifest.routes?.[targetRoute]) {
156
- const routePath = path.join(resolvedDir, manifest.routes[targetRoute]);
157
- const css = readFile(fs, routePath);
158
- if (css) cssChunks.push(css);
159
- }
160
- if (cssChunks.length === 0) return import_react.default.createElement(import_react.default.Fragment, null);
161
- const combined = cssChunks.join("\n");
162
- const final = minify ? minifyCss(combined) : combined;
163
- return import_react.default.createElement("style", {
164
- dangerouslySetInnerHTML: { __html: final },
165
- "data-tw-route": targetRoute,
166
- "data-tw-injector": "true"
167
- });
168
- }
169
127
  function useTwClasses(classes) {
170
128
  return classes;
171
129
  }
172
- function readFile(fs, filepath) {
173
- try {
174
- if (fs.existsSync(filepath)) return fs.readFileSync(filepath, "utf-8");
175
- } catch {
176
- }
177
- return null;
178
- }
179
- function minifyCss(css) {
180
- return css.replace(/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g, "").replace(/\s+/g, " ").replace(/\s*{\s*/g, "{").replace(/\s*}\s*/g, "}").replace(/\s*;\s*/g, ";").trim();
181
- }
182
130
  // Annotate the CommonJS export names for ESM import in node:
183
131
  0 && (module.exports = {
184
- TwCssInjector,
185
132
  batchedInject,
186
133
  flushBatchedCss,
187
134
  getBatchedCssStats,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/umbrella/runtime-css.ts","../packages/domain/runtime-css/src/batchedInjector.ts","../packages/domain/runtime-css/src/CssInjector.tsx"],"sourcesContent":["export * from \"@tailwind-styled/runtime-css\"\n","\"use client\"\n\n/**\n * tailwind-styled-v5 — Batched CSS Injector (Client Runtime)\n *\n * Menggantikan pattern inject-per-komponen yang menyebabkan banyak\n * style recalculation saat banyak komponen mount bersamaan.\n *\n * Cara kerja:\n * - Semua CSS rules dari render cycle yang sama dikumpulkan\n * - Satu requestAnimationFrame = satu DOM style update\n * - Deduplication via Set<string> — rule yang sama tidak diinjeksi dua kali\n * - Injection via CSSStyleSheet.insertRule() — TIDAK menghapus rules yang ada\n * - Fallback ke textContent += jika CSSOM API tidak tersedia\n *\n * PENTING — Kenapa insertRule() bukan textContent +=:\n * `el.textContent += css` terlihat additive tapi sebenarnya:\n * 1. Browser baca semua textContent yang ada\n * 2. HAPUS semua rules dari stylesheet\n * 3. Concat string baru\n * 4. Parse ulang dan re-add semua rules\n * Di step 2-3, ada window singkat dimana SEMUA styles hilang → FLICKER.\n *\n * `sheet.insertRule()` benar-benar additive — hanya menambah rule baru\n * tanpa menyentuh rules yang sudah ada. Zero flicker.\n *\n * Usage (internal, dipakai oleh stateEngine dan containerQuery):\n * import { batchedInject, flushBatchedCss } from \"./batchedInjector\"\n *\n * // Queue a rule\n * batchedInject(\".tw-s-abc123[data-active=\\\"true\\\"]{opacity:0.5}\")\n *\n * // Force flush (biasanya tidak perlu — RAF melakukan ini otomatis)\n * flushBatchedCss()\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Singleton state\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** All injected rules (deduplication registry) */\nconst injected = new Set<string>()\n\n/** Pending rules for current RAF batch */\nconst pending: string[] = []\n\n/** RAF handle and style element state */\nconst _state = {\n rafHandle: null as ReturnType<typeof requestAnimationFrame> | null,\n styleEl: null as HTMLStyleElement | null,\n}\n\nfunction getStyleElement(): HTMLStyleElement {\n if (_state.styleEl && document.head.contains(_state.styleEl)) return _state.styleEl\n\n _state.styleEl = document.createElement(\"style\")\n _state.styleEl.id = \"__tw-runtime-css\"\n _state.styleEl.setAttribute(\"data-tw-batched\", \"true\")\n // Harus diappend ke DOM sebelum .sheet bisa diakses\n document.head.appendChild(_state.styleEl)\n return _state.styleEl\n}\n\n/**\n * Inject satu CSS rule via CSSStyleSheet.insertRule().\n *\n * Ini benar-benar additive — tidak menyentuh rules yang sudah ada.\n * Fallback ke textContent append jika sheet belum siap (edge case).\n *\n * @internal\n */\nfunction insertRuleToSheet(cssRule: string): void {\n const trimmed = cssRule.trim()\n if (!trimmed) return\n\n const el = getStyleElement()\n const sheet = el.sheet\n\n if (sheet) {\n try {\n // insertRule() di akhir — urutan tidak kritis untuk utility CSS\n sheet.insertRule(trimmed, sheet.cssRules.length)\n return\n } catch {\n // insertRule() bisa throw jika:\n // 1. Rule syntax tidak valid\n // 2. Multi-rule string (insertRule() hanya terima satu rule)\n // Fallback ke textContent append untuk kasus ini.\n if (process.env.NODE_ENV === \"development\") {\n console.warn(\"[tw] insertRule failed, falling back to textContent append for rule:\", trimmed.slice(0, 80))\n }\n }\n }\n\n // Fallback: textContent append.\n // Lebih jarang terjadi sekarang karena stateEngine sudah loop per-rule,\n // tapi tetap perlu sebagai safety net.\n el.textContent = (el.textContent ?? \"\") + `\\n${trimmed}`\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Core API\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Queue a CSS rule for batched injection.\n * Multiple rules accumulated during one event loop tick are flushed together\n * in one requestAnimationFrame → one style recalculation.\n *\n * Rules diinjeksi via insertRule() — zero flicker, truly additive.\n */\nexport function batchedInject(cssRule: string): void {\n if (typeof window === \"undefined\") return // SSR — no-op\n if (!cssRule || injected.has(cssRule)) return\n\n injected.add(cssRule)\n pending.push(cssRule)\n\n if (_state.rafHandle === null) {\n _state.rafHandle = requestAnimationFrame(flushBatchedCss)\n }\n}\n\n/**\n * Immediately flush all pending CSS rules to the DOM.\n * Called automatically by RAF each frame. Can also be called manually\n * after synchronous component setup where RAF timing is too late.\n *\n * Setiap rule diinjeksi secara individual via insertRule() — tidak ada\n * window dimana existing rules hilang.\n */\nexport function flushBatchedCss(): void {\n _state.rafHandle = null\n\n if (pending.length === 0 || typeof document === \"undefined\") return\n\n // Flush semua rules sekaligus — satu per satu via insertRule()\n // insertRule() atomic per-rule: rule lama tidak pernah dihapus\n const rules = pending.splice(0)\n for (const rule of rules) {\n insertRuleToSheet(rule)\n }\n}\n\n/**\n * Synchronous inject — skips batching.\n * Use for SSR / critical path where RAF is not available.\n *\n * Menggunakan insertRule() — tidak ada flicker meskipun dipanggil\n * di tengah render cycle.\n */\nexport function syncInject(cssRule: string): void {\n if (typeof document === \"undefined\") return\n if (!cssRule || injected.has(cssRule)) return\n\n injected.add(cssRule)\n insertRuleToSheet(cssRule)\n}\n\n/**\n * Check if a rule has already been injected (deduplication check).\n */\nexport function isInjected(cssRule: string): boolean {\n return injected.has(cssRule)\n}\n\n/**\n * Clear all injected rules and remove the style element.\n * Useful for testing / SSR resets. Not for production use.\n */\nexport function resetBatchedCss(): void {\n injected.clear()\n pending.length = 0\n\n if (_state.rafHandle !== null) {\n cancelAnimationFrame(_state.rafHandle)\n _state.rafHandle = null\n }\n\n // Guard: document tidak tersedia di SSR / Node test environment\n if (typeof document !== \"undefined\" && _state.styleEl && document.head.contains(_state.styleEl)) {\n document.head.removeChild(_state.styleEl)\n _state.styleEl = null\n } else {\n _state.styleEl = null\n }\n}\n\n/**\n * Get stats about the current injection state (for devtools).\n */\nexport function getBatchedCssStats(): {\n totalInjected: number\n pendingCount: number\n hasBatchScheduled: boolean\n} {\n return {\n totalInjected: injected.size,\n pendingCount: pending.length,\n hasBatchScheduled: _state.rafHandle !== null,\n }\n}","/**\n * tailwind-styled-v4 — TwCssInjector\n *\n * React Server Component — inject route-specific CSS ke <head>.\n * Zero client JS, no hydration overhead, streaming-friendly.\n *\n * Pipeline:\n * 1. withTailwindStyled webpack plugin emit CSS manifest ke .next/static/css/tw/\n * 2. TwCssInjector baca manifest → inject <style> inline per route\n *\n * Usage:\n * // app/layout.tsx\n * import { TwCssInjector } from \"tailwind-styled-v4/runtime-css\"\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <head><TwCssInjector /></head>\n * <body>{children}</body>\n * </html>\n * )\n * }\n */\n\nimport React from \"react\"\n\ninterface CssInjectorProps {\n /** Route spesifik. Default: auto-detect */\n route?: string\n /** Inject global CSS juga. Default: true */\n includeGlobal?: boolean\n /** Minify inline CSS. Default: true */\n minify?: boolean\n /** CSS directory. Default: .next/static/css/tw */\n cssDir?: string\n}\n\n/**\n * Server Component — inject CSS per route ke <head>.\n * Baca dari manifest yang di-emit oleh TwCssManifestPlugin.\n */\nexport async function TwCssInjector(props: CssInjectorProps = {}): Promise<React.ReactElement> {\n const { route, includeGlobal = true, minify = true, cssDir } = props\n\n // Dynamic import fs — hanya jalan di server\n let fs: typeof import(\"node:fs\") | null = null\n let path: typeof import(\"node:path\") | null = null\n try {\n fs = await import(\"node:fs\")\n path = await import(\"node:path\")\n } catch {\n return React.createElement(React.Fragment, null)\n }\n\n const resolvedDir = cssDir\n ?? path.join(process.cwd(), \".next\", \"static\", \"css\", \"tw\")\n\n const manifestPath = path.join(resolvedDir, \"css-manifest.json\")\n\n // Baca manifest\n let manifest: { routes?: Record<string, string> } = {}\n try {\n if (fs.existsSync(manifestPath)) {\n manifest = JSON.parse(fs.readFileSync(manifestPath, \"utf-8\"))\n }\n } catch {\n // Manifest tidak ada — mungkin belum build atau native binding belum ready\n return React.createElement(React.Fragment, null)\n }\n\n const cssChunks: string[] = []\n\n // Global CSS (_global.css)\n if (includeGlobal && manifest.routes?.[\"__global\"]) {\n const globalPath = path.join(resolvedDir, manifest.routes[\"__global\"])\n const css = readFile(fs, globalPath)\n if (css) cssChunks.push(css)\n }\n\n // Route-specific CSS\n const targetRoute = route ?? \"/\"\n if (manifest.routes?.[targetRoute]) {\n const routePath = path.join(resolvedDir, manifest.routes[targetRoute])\n const css = readFile(fs, routePath)\n if (css) cssChunks.push(css)\n }\n\n if (cssChunks.length === 0) return React.createElement(React.Fragment, null)\n\n const combined = cssChunks.join(\"\\n\")\n const final = minify ? minifyCss(combined) : combined\n\n return React.createElement(\"style\", {\n dangerouslySetInnerHTML: { __html: final },\n \"data-tw-route\": targetRoute,\n \"data-tw-injector\": \"true\",\n })\n}\n\n/**\n * Hook untuk client components — CSS sudah di-handle TwCssInjector di server.\n */\nexport function useTwClasses(classes: string): string {\n return classes\n}\n\n// Helpers\nfunction readFile(fs: typeof import(\"node:fs\"), filepath: string): string | null {\n try {\n if (fs.existsSync(filepath)) return fs.readFileSync(filepath, \"utf-8\")\n } catch {}\n return null\n}\n\nfunction minifyCss(css: string): string {\n return css\n .replace(/\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//g, \"\")\n .replace(/\\s+/g, \" \")\n .replace(/\\s*{\\s*/g, \"{\")\n .replace(/\\s*}\\s*/g, \"}\")\n .replace(/\\s*;\\s*/g, \";\")\n .trim()\n}"],"mappings":"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","names":["React"]}
1
+ {"version":3,"sources":["../src/umbrella/runtime-css.ts","../packages/domain/runtime-css/dist/batchedInjector.js","../packages/domain/runtime-css/dist/CssInjector.js"],"sourcesContent":["// runtime-css client utilities (batchedInjector) — safe to bundle with \"use client\"\n// TwCssInjector (Server Component) is intentionally NOT re-exported here because\n// it is an async RSC and must NOT be in a \"use client\" bundle.\n// Import it directly: import { TwCssInjector } from \"tailwind-styled-v4/runtime-css/server\"\nexport {\n batchedInject,\n flushBatchedCss,\n getBatchedCssStats,\n isInjected,\n resetBatchedCss,\n syncInject,\n} from \"@tailwind-styled/runtime-css/client\"\nexport { useTwClasses } from \"@tailwind-styled/runtime-css/server\"\n","\"use client\";\nconst injected = /* @__PURE__ */ new Set();\nconst pending = [];\nconst _state = {\n rafHandle: null,\n styleEl: null\n};\nfunction getStyleElement() {\n if (_state.styleEl && document.head.contains(_state.styleEl)) return _state.styleEl;\n _state.styleEl = document.createElement(\"style\");\n _state.styleEl.id = \"__tw-runtime-css\";\n _state.styleEl.setAttribute(\"data-tw-batched\", \"true\");\n document.head.appendChild(_state.styleEl);\n return _state.styleEl;\n}\nfunction insertRuleToSheet(cssRule) {\n const trimmed = cssRule.trim();\n if (!trimmed) return;\n const el = getStyleElement();\n const sheet = el.sheet;\n if (sheet) {\n try {\n sheet.insertRule(trimmed, sheet.cssRules.length);\n return;\n } catch {\n if (process.env.NODE_ENV === \"development\") {\n console.warn(\"[tw] insertRule failed, falling back to textContent append for rule:\", trimmed.slice(0, 80));\n }\n }\n }\n el.textContent = (el.textContent ?? \"\") + `\n${trimmed}`;\n}\nfunction batchedInject(cssRule) {\n if (typeof window === \"undefined\") return;\n if (!cssRule || injected.has(cssRule)) return;\n injected.add(cssRule);\n pending.push(cssRule);\n if (_state.rafHandle === null) {\n _state.rafHandle = requestAnimationFrame(flushBatchedCss);\n }\n}\nfunction flushBatchedCss() {\n _state.rafHandle = null;\n if (pending.length === 0 || typeof document === \"undefined\") return;\n const rules = pending.splice(0);\n for (const rule of rules) {\n insertRuleToSheet(rule);\n }\n}\nfunction syncInject(cssRule) {\n if (typeof document === \"undefined\") return;\n if (!cssRule || injected.has(cssRule)) return;\n injected.add(cssRule);\n insertRuleToSheet(cssRule);\n}\nfunction isInjected(cssRule) {\n return injected.has(cssRule);\n}\nfunction resetBatchedCss() {\n injected.clear();\n pending.length = 0;\n if (_state.rafHandle !== null) {\n cancelAnimationFrame(_state.rafHandle);\n _state.rafHandle = null;\n }\n if (typeof document !== \"undefined\" && _state.styleEl && document.head.contains(_state.styleEl)) {\n document.head.removeChild(_state.styleEl);\n _state.styleEl = null;\n } else {\n _state.styleEl = null;\n }\n}\nfunction getBatchedCssStats() {\n return {\n totalInjected: injected.size,\n pendingCount: pending.length,\n hasBatchScheduled: _state.rafHandle !== null\n };\n}\nexport {\n batchedInject,\n flushBatchedCss,\n getBatchedCssStats,\n isInjected,\n resetBatchedCss,\n syncInject\n};\n","import React from \"react\";\nasync function TwCssInjector(props = {}) {\n const { route, includeGlobal = true, minify = true, cssDir } = props;\n let fs = null;\n let path = null;\n try {\n fs = await import(\"node:fs\");\n path = await import(\"node:path\");\n } catch {\n return React.createElement(React.Fragment, null);\n }\n const resolvedDir = cssDir ?? path.join(process.cwd(), \".next\", \"static\", \"css\", \"tw\");\n const manifestPath = path.join(resolvedDir, \"css-manifest.json\");\n let manifest = {};\n try {\n if (fs.existsSync(manifestPath)) {\n manifest = JSON.parse(fs.readFileSync(manifestPath, \"utf-8\"));\n }\n } catch {\n return React.createElement(React.Fragment, null);\n }\n const cssChunks = [];\n if (includeGlobal && manifest.routes?.[\"__global\"]) {\n const globalPath = path.join(resolvedDir, manifest.routes[\"__global\"]);\n const css = readFile(fs, globalPath);\n if (css) cssChunks.push(css);\n }\n const targetRoute = route ?? \"/\";\n if (manifest.routes?.[targetRoute]) {\n const routePath = path.join(resolvedDir, manifest.routes[targetRoute]);\n const css = readFile(fs, routePath);\n if (css) cssChunks.push(css);\n }\n if (cssChunks.length === 0) return React.createElement(React.Fragment, null);\n const combined = cssChunks.join(\"\\n\");\n const final = minify ? minifyCss(combined) : combined;\n return React.createElement(\"style\", {\n dangerouslySetInnerHTML: { __html: final },\n \"data-tw-route\": targetRoute,\n \"data-tw-injector\": \"true\"\n });\n}\nfunction useTwClasses(classes) {\n return classes;\n}\nfunction readFile(fs, filepath) {\n try {\n if (fs.existsSync(filepath)) return fs.readFileSync(filepath, \"utf-8\");\n } catch {\n }\n return null;\n}\nfunction minifyCss(css) {\n return css.replace(/\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//g, \"\").replace(/\\s+/g, \" \").replace(/\\s*{\\s*/g, \"{\").replace(/\\s*}\\s*/g, \"}\").replace(/\\s*;\\s*/g, \";\").trim();\n}\nexport {\n TwCssInjector,\n useTwClasses\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,IAAM,WAA2B,oBAAI,IAAI;AACzC,IAAM,UAAU,CAAC;AACjB,IAAM,SAAS;AAAA,EACb,WAAW;AAAA,EACX,SAAS;AACX;AACA,SAAS,kBAAkB;AACzB,MAAI,OAAO,WAAW,SAAS,KAAK,SAAS,OAAO,OAAO,EAAG,QAAO,OAAO;AAC5E,SAAO,UAAU,SAAS,cAAc,OAAO;AAC/C,SAAO,QAAQ,KAAK;AACpB,SAAO,QAAQ,aAAa,mBAAmB,MAAM;AACrD,WAAS,KAAK,YAAY,OAAO,OAAO;AACxC,SAAO,OAAO;AAChB;AACA,SAAS,kBAAkB,SAAS;AAClC,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI,CAAC,QAAS;AACd,QAAM,KAAK,gBAAgB;AAC3B,QAAM,QAAQ,GAAG;AACjB,MAAI,OAAO;AACT,QAAI;AACF,YAAM,WAAW,SAAS,MAAM,SAAS,MAAM;AAC/C;AAAA,IACF,QAAQ;AACN,UAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,gBAAQ,KAAK,wEAAwE,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,MAC3G;AAAA,IACF;AAAA,EACF;AACA,KAAG,eAAe,GAAG,eAAe,MAAM;AAAA,EAC1C,OAAO;AACT;AACA,SAAS,cAAc,SAAS;AAC9B,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI,CAAC,WAAW,SAAS,IAAI,OAAO,EAAG;AACvC,WAAS,IAAI,OAAO;AACpB,UAAQ,KAAK,OAAO;AACpB,MAAI,OAAO,cAAc,MAAM;AAC7B,WAAO,YAAY,sBAAsB,eAAe;AAAA,EAC1D;AACF;AACA,SAAS,kBAAkB;AACzB,SAAO,YAAY;AACnB,MAAI,QAAQ,WAAW,KAAK,OAAO,aAAa,YAAa;AAC7D,QAAM,QAAQ,QAAQ,OAAO,CAAC;AAC9B,aAAW,QAAQ,OAAO;AACxB,sBAAkB,IAAI;AAAA,EACxB;AACF;AACA,SAAS,WAAW,SAAS;AAC3B,MAAI,OAAO,aAAa,YAAa;AACrC,MAAI,CAAC,WAAW,SAAS,IAAI,OAAO,EAAG;AACvC,WAAS,IAAI,OAAO;AACpB,oBAAkB,OAAO;AAC3B;AACA,SAAS,WAAW,SAAS;AAC3B,SAAO,SAAS,IAAI,OAAO;AAC7B;AACA,SAAS,kBAAkB;AACzB,WAAS,MAAM;AACf,UAAQ,SAAS;AACjB,MAAI,OAAO,cAAc,MAAM;AAC7B,yBAAqB,OAAO,SAAS;AACrC,WAAO,YAAY;AAAA,EACrB;AACA,MAAI,OAAO,aAAa,eAAe,OAAO,WAAW,SAAS,KAAK,SAAS,OAAO,OAAO,GAAG;AAC/F,aAAS,KAAK,YAAY,OAAO,OAAO;AACxC,WAAO,UAAU;AAAA,EACnB,OAAO;AACL,WAAO,UAAU;AAAA,EACnB;AACF;AACA,SAAS,qBAAqB;AAC5B,SAAO;AAAA,IACL,eAAe,SAAS;AAAA,IACxB,cAAc,QAAQ;AAAA,IACtB,mBAAmB,OAAO,cAAc;AAAA,EAC1C;AACF;;;AC/EA,mBAAkB;AA0ClB,SAAS,aAAa,SAAS;AAC7B,SAAO;AACT;","names":[]}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- // packages/domain/runtime-css/src/batchedInjector.ts
2
+ // packages/domain/runtime-css/dist/batchedInjector.js
3
3
  var injected = /* @__PURE__ */ new Set();
4
4
  var pending = [];
5
5
  var _state = {
@@ -80,64 +80,12 @@ function getBatchedCssStats() {
80
80
  };
81
81
  }
82
82
 
83
- // packages/domain/runtime-css/src/CssInjector.tsx
83
+ // packages/domain/runtime-css/dist/CssInjector.js
84
84
  import React from "react";
85
- async function TwCssInjector(props = {}) {
86
- const { route, includeGlobal = true, minify = true, cssDir } = props;
87
- let fs = null;
88
- let path = null;
89
- try {
90
- fs = await import("fs");
91
- path = await import("path");
92
- } catch {
93
- return React.createElement(React.Fragment, null);
94
- }
95
- const resolvedDir = cssDir ?? path.join(process.cwd(), ".next", "static", "css", "tw");
96
- const manifestPath = path.join(resolvedDir, "css-manifest.json");
97
- let manifest = {};
98
- try {
99
- if (fs.existsSync(manifestPath)) {
100
- manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
101
- }
102
- } catch {
103
- return React.createElement(React.Fragment, null);
104
- }
105
- const cssChunks = [];
106
- if (includeGlobal && manifest.routes?.["__global"]) {
107
- const globalPath = path.join(resolvedDir, manifest.routes["__global"]);
108
- const css = readFile(fs, globalPath);
109
- if (css) cssChunks.push(css);
110
- }
111
- const targetRoute = route ?? "/";
112
- if (manifest.routes?.[targetRoute]) {
113
- const routePath = path.join(resolvedDir, manifest.routes[targetRoute]);
114
- const css = readFile(fs, routePath);
115
- if (css) cssChunks.push(css);
116
- }
117
- if (cssChunks.length === 0) return React.createElement(React.Fragment, null);
118
- const combined = cssChunks.join("\n");
119
- const final = minify ? minifyCss(combined) : combined;
120
- return React.createElement("style", {
121
- dangerouslySetInnerHTML: { __html: final },
122
- "data-tw-route": targetRoute,
123
- "data-tw-injector": "true"
124
- });
125
- }
126
85
  function useTwClasses(classes) {
127
86
  return classes;
128
87
  }
129
- function readFile(fs, filepath) {
130
- try {
131
- if (fs.existsSync(filepath)) return fs.readFileSync(filepath, "utf-8");
132
- } catch {
133
- }
134
- return null;
135
- }
136
- function minifyCss(css) {
137
- return css.replace(/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g, "").replace(/\s+/g, " ").replace(/\s*{\s*/g, "{").replace(/\s*}\s*/g, "}").replace(/\s*;\s*/g, ";").trim();
138
- }
139
88
  export {
140
- TwCssInjector,
141
89
  batchedInject,
142
90
  flushBatchedCss,
143
91
  getBatchedCssStats,
@@ -1 +1 @@
1
- {"version":3,"sources":["../packages/domain/runtime-css/src/batchedInjector.ts","../packages/domain/runtime-css/src/CssInjector.tsx"],"sourcesContent":["\"use client\"\n\n/**\n * tailwind-styled-v5 — Batched CSS Injector (Client Runtime)\n *\n * Menggantikan pattern inject-per-komponen yang menyebabkan banyak\n * style recalculation saat banyak komponen mount bersamaan.\n *\n * Cara kerja:\n * - Semua CSS rules dari render cycle yang sama dikumpulkan\n * - Satu requestAnimationFrame = satu DOM style update\n * - Deduplication via Set<string> — rule yang sama tidak diinjeksi dua kali\n * - Injection via CSSStyleSheet.insertRule() — TIDAK menghapus rules yang ada\n * - Fallback ke textContent += jika CSSOM API tidak tersedia\n *\n * PENTING — Kenapa insertRule() bukan textContent +=:\n * `el.textContent += css` terlihat additive tapi sebenarnya:\n * 1. Browser baca semua textContent yang ada\n * 2. HAPUS semua rules dari stylesheet\n * 3. Concat string baru\n * 4. Parse ulang dan re-add semua rules\n * Di step 2-3, ada window singkat dimana SEMUA styles hilang → FLICKER.\n *\n * `sheet.insertRule()` benar-benar additive — hanya menambah rule baru\n * tanpa menyentuh rules yang sudah ada. Zero flicker.\n *\n * Usage (internal, dipakai oleh stateEngine dan containerQuery):\n * import { batchedInject, flushBatchedCss } from \"./batchedInjector\"\n *\n * // Queue a rule\n * batchedInject(\".tw-s-abc123[data-active=\\\"true\\\"]{opacity:0.5}\")\n *\n * // Force flush (biasanya tidak perlu — RAF melakukan ini otomatis)\n * flushBatchedCss()\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Singleton state\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** All injected rules (deduplication registry) */\nconst injected = new Set<string>()\n\n/** Pending rules for current RAF batch */\nconst pending: string[] = []\n\n/** RAF handle and style element state */\nconst _state = {\n rafHandle: null as ReturnType<typeof requestAnimationFrame> | null,\n styleEl: null as HTMLStyleElement | null,\n}\n\nfunction getStyleElement(): HTMLStyleElement {\n if (_state.styleEl && document.head.contains(_state.styleEl)) return _state.styleEl\n\n _state.styleEl = document.createElement(\"style\")\n _state.styleEl.id = \"__tw-runtime-css\"\n _state.styleEl.setAttribute(\"data-tw-batched\", \"true\")\n // Harus diappend ke DOM sebelum .sheet bisa diakses\n document.head.appendChild(_state.styleEl)\n return _state.styleEl\n}\n\n/**\n * Inject satu CSS rule via CSSStyleSheet.insertRule().\n *\n * Ini benar-benar additive — tidak menyentuh rules yang sudah ada.\n * Fallback ke textContent append jika sheet belum siap (edge case).\n *\n * @internal\n */\nfunction insertRuleToSheet(cssRule: string): void {\n const trimmed = cssRule.trim()\n if (!trimmed) return\n\n const el = getStyleElement()\n const sheet = el.sheet\n\n if (sheet) {\n try {\n // insertRule() di akhir — urutan tidak kritis untuk utility CSS\n sheet.insertRule(trimmed, sheet.cssRules.length)\n return\n } catch {\n // insertRule() bisa throw jika:\n // 1. Rule syntax tidak valid\n // 2. Multi-rule string (insertRule() hanya terima satu rule)\n // Fallback ke textContent append untuk kasus ini.\n if (process.env.NODE_ENV === \"development\") {\n console.warn(\"[tw] insertRule failed, falling back to textContent append for rule:\", trimmed.slice(0, 80))\n }\n }\n }\n\n // Fallback: textContent append.\n // Lebih jarang terjadi sekarang karena stateEngine sudah loop per-rule,\n // tapi tetap perlu sebagai safety net.\n el.textContent = (el.textContent ?? \"\") + `\\n${trimmed}`\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Core API\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Queue a CSS rule for batched injection.\n * Multiple rules accumulated during one event loop tick are flushed together\n * in one requestAnimationFrame → one style recalculation.\n *\n * Rules diinjeksi via insertRule() — zero flicker, truly additive.\n */\nexport function batchedInject(cssRule: string): void {\n if (typeof window === \"undefined\") return // SSR — no-op\n if (!cssRule || injected.has(cssRule)) return\n\n injected.add(cssRule)\n pending.push(cssRule)\n\n if (_state.rafHandle === null) {\n _state.rafHandle = requestAnimationFrame(flushBatchedCss)\n }\n}\n\n/**\n * Immediately flush all pending CSS rules to the DOM.\n * Called automatically by RAF each frame. Can also be called manually\n * after synchronous component setup where RAF timing is too late.\n *\n * Setiap rule diinjeksi secara individual via insertRule() — tidak ada\n * window dimana existing rules hilang.\n */\nexport function flushBatchedCss(): void {\n _state.rafHandle = null\n\n if (pending.length === 0 || typeof document === \"undefined\") return\n\n // Flush semua rules sekaligus — satu per satu via insertRule()\n // insertRule() atomic per-rule: rule lama tidak pernah dihapus\n const rules = pending.splice(0)\n for (const rule of rules) {\n insertRuleToSheet(rule)\n }\n}\n\n/**\n * Synchronous inject — skips batching.\n * Use for SSR / critical path where RAF is not available.\n *\n * Menggunakan insertRule() — tidak ada flicker meskipun dipanggil\n * di tengah render cycle.\n */\nexport function syncInject(cssRule: string): void {\n if (typeof document === \"undefined\") return\n if (!cssRule || injected.has(cssRule)) return\n\n injected.add(cssRule)\n insertRuleToSheet(cssRule)\n}\n\n/**\n * Check if a rule has already been injected (deduplication check).\n */\nexport function isInjected(cssRule: string): boolean {\n return injected.has(cssRule)\n}\n\n/**\n * Clear all injected rules and remove the style element.\n * Useful for testing / SSR resets. Not for production use.\n */\nexport function resetBatchedCss(): void {\n injected.clear()\n pending.length = 0\n\n if (_state.rafHandle !== null) {\n cancelAnimationFrame(_state.rafHandle)\n _state.rafHandle = null\n }\n\n // Guard: document tidak tersedia di SSR / Node test environment\n if (typeof document !== \"undefined\" && _state.styleEl && document.head.contains(_state.styleEl)) {\n document.head.removeChild(_state.styleEl)\n _state.styleEl = null\n } else {\n _state.styleEl = null\n }\n}\n\n/**\n * Get stats about the current injection state (for devtools).\n */\nexport function getBatchedCssStats(): {\n totalInjected: number\n pendingCount: number\n hasBatchScheduled: boolean\n} {\n return {\n totalInjected: injected.size,\n pendingCount: pending.length,\n hasBatchScheduled: _state.rafHandle !== null,\n }\n}","/**\n * tailwind-styled-v4 — TwCssInjector\n *\n * React Server Component — inject route-specific CSS ke <head>.\n * Zero client JS, no hydration overhead, streaming-friendly.\n *\n * Pipeline:\n * 1. withTailwindStyled webpack plugin emit CSS manifest ke .next/static/css/tw/\n * 2. TwCssInjector baca manifest → inject <style> inline per route\n *\n * Usage:\n * // app/layout.tsx\n * import { TwCssInjector } from \"tailwind-styled-v4/runtime-css\"\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <head><TwCssInjector /></head>\n * <body>{children}</body>\n * </html>\n * )\n * }\n */\n\nimport React from \"react\"\n\ninterface CssInjectorProps {\n /** Route spesifik. Default: auto-detect */\n route?: string\n /** Inject global CSS juga. Default: true */\n includeGlobal?: boolean\n /** Minify inline CSS. Default: true */\n minify?: boolean\n /** CSS directory. Default: .next/static/css/tw */\n cssDir?: string\n}\n\n/**\n * Server Component — inject CSS per route ke <head>.\n * Baca dari manifest yang di-emit oleh TwCssManifestPlugin.\n */\nexport async function TwCssInjector(props: CssInjectorProps = {}): Promise<React.ReactElement> {\n const { route, includeGlobal = true, minify = true, cssDir } = props\n\n // Dynamic import fs — hanya jalan di server\n let fs: typeof import(\"node:fs\") | null = null\n let path: typeof import(\"node:path\") | null = null\n try {\n fs = await import(\"node:fs\")\n path = await import(\"node:path\")\n } catch {\n return React.createElement(React.Fragment, null)\n }\n\n const resolvedDir = cssDir\n ?? path.join(process.cwd(), \".next\", \"static\", \"css\", \"tw\")\n\n const manifestPath = path.join(resolvedDir, \"css-manifest.json\")\n\n // Baca manifest\n let manifest: { routes?: Record<string, string> } = {}\n try {\n if (fs.existsSync(manifestPath)) {\n manifest = JSON.parse(fs.readFileSync(manifestPath, \"utf-8\"))\n }\n } catch {\n // Manifest tidak ada — mungkin belum build atau native binding belum ready\n return React.createElement(React.Fragment, null)\n }\n\n const cssChunks: string[] = []\n\n // Global CSS (_global.css)\n if (includeGlobal && manifest.routes?.[\"__global\"]) {\n const globalPath = path.join(resolvedDir, manifest.routes[\"__global\"])\n const css = readFile(fs, globalPath)\n if (css) cssChunks.push(css)\n }\n\n // Route-specific CSS\n const targetRoute = route ?? \"/\"\n if (manifest.routes?.[targetRoute]) {\n const routePath = path.join(resolvedDir, manifest.routes[targetRoute])\n const css = readFile(fs, routePath)\n if (css) cssChunks.push(css)\n }\n\n if (cssChunks.length === 0) return React.createElement(React.Fragment, null)\n\n const combined = cssChunks.join(\"\\n\")\n const final = minify ? minifyCss(combined) : combined\n\n return React.createElement(\"style\", {\n dangerouslySetInnerHTML: { __html: final },\n \"data-tw-route\": targetRoute,\n \"data-tw-injector\": \"true\",\n })\n}\n\n/**\n * Hook untuk client components — CSS sudah di-handle TwCssInjector di server.\n */\nexport function useTwClasses(classes: string): string {\n return classes\n}\n\n// Helpers\nfunction readFile(fs: typeof import(\"node:fs\"), filepath: string): string | null {\n try {\n if (fs.existsSync(filepath)) return fs.readFileSync(filepath, \"utf-8\")\n } catch {}\n return null\n}\n\nfunction minifyCss(css: string): string {\n return css\n .replace(/\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//g, \"\")\n .replace(/\\s+/g, \" \")\n .replace(/\\s*{\\s*/g, \"{\")\n .replace(/\\s*}\\s*/g, \"}\")\n .replace(/\\s*;\\s*/g, \";\")\n .trim()\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../packages/domain/runtime-css/dist/batchedInjector.js","../packages/domain/runtime-css/dist/CssInjector.js"],"sourcesContent":["\"use client\";\nconst injected = /* @__PURE__ */ new Set();\nconst pending = [];\nconst _state = {\n rafHandle: null,\n styleEl: null\n};\nfunction getStyleElement() {\n if (_state.styleEl && document.head.contains(_state.styleEl)) return _state.styleEl;\n _state.styleEl = document.createElement(\"style\");\n _state.styleEl.id = \"__tw-runtime-css\";\n _state.styleEl.setAttribute(\"data-tw-batched\", \"true\");\n document.head.appendChild(_state.styleEl);\n return _state.styleEl;\n}\nfunction insertRuleToSheet(cssRule) {\n const trimmed = cssRule.trim();\n if (!trimmed) return;\n const el = getStyleElement();\n const sheet = el.sheet;\n if (sheet) {\n try {\n sheet.insertRule(trimmed, sheet.cssRules.length);\n return;\n } catch {\n if (process.env.NODE_ENV === \"development\") {\n console.warn(\"[tw] insertRule failed, falling back to textContent append for rule:\", trimmed.slice(0, 80));\n }\n }\n }\n el.textContent = (el.textContent ?? \"\") + `\n${trimmed}`;\n}\nfunction batchedInject(cssRule) {\n if (typeof window === \"undefined\") return;\n if (!cssRule || injected.has(cssRule)) return;\n injected.add(cssRule);\n pending.push(cssRule);\n if (_state.rafHandle === null) {\n _state.rafHandle = requestAnimationFrame(flushBatchedCss);\n }\n}\nfunction flushBatchedCss() {\n _state.rafHandle = null;\n if (pending.length === 0 || typeof document === \"undefined\") return;\n const rules = pending.splice(0);\n for (const rule of rules) {\n insertRuleToSheet(rule);\n }\n}\nfunction syncInject(cssRule) {\n if (typeof document === \"undefined\") return;\n if (!cssRule || injected.has(cssRule)) return;\n injected.add(cssRule);\n insertRuleToSheet(cssRule);\n}\nfunction isInjected(cssRule) {\n return injected.has(cssRule);\n}\nfunction resetBatchedCss() {\n injected.clear();\n pending.length = 0;\n if (_state.rafHandle !== null) {\n cancelAnimationFrame(_state.rafHandle);\n _state.rafHandle = null;\n }\n if (typeof document !== \"undefined\" && _state.styleEl && document.head.contains(_state.styleEl)) {\n document.head.removeChild(_state.styleEl);\n _state.styleEl = null;\n } else {\n _state.styleEl = null;\n }\n}\nfunction getBatchedCssStats() {\n return {\n totalInjected: injected.size,\n pendingCount: pending.length,\n hasBatchScheduled: _state.rafHandle !== null\n };\n}\nexport {\n batchedInject,\n flushBatchedCss,\n getBatchedCssStats,\n isInjected,\n resetBatchedCss,\n syncInject\n};\n","import React from \"react\";\nasync function TwCssInjector(props = {}) {\n const { route, includeGlobal = true, minify = true, cssDir } = props;\n let fs = null;\n let path = null;\n try {\n fs = await import(\"node:fs\");\n path = await import(\"node:path\");\n } catch {\n return React.createElement(React.Fragment, null);\n }\n const resolvedDir = cssDir ?? path.join(process.cwd(), \".next\", \"static\", \"css\", \"tw\");\n const manifestPath = path.join(resolvedDir, \"css-manifest.json\");\n let manifest = {};\n try {\n if (fs.existsSync(manifestPath)) {\n manifest = JSON.parse(fs.readFileSync(manifestPath, \"utf-8\"));\n }\n } catch {\n return React.createElement(React.Fragment, null);\n }\n const cssChunks = [];\n if (includeGlobal && manifest.routes?.[\"__global\"]) {\n const globalPath = path.join(resolvedDir, manifest.routes[\"__global\"]);\n const css = readFile(fs, globalPath);\n if (css) cssChunks.push(css);\n }\n const targetRoute = route ?? \"/\";\n if (manifest.routes?.[targetRoute]) {\n const routePath = path.join(resolvedDir, manifest.routes[targetRoute]);\n const css = readFile(fs, routePath);\n if (css) cssChunks.push(css);\n }\n if (cssChunks.length === 0) return React.createElement(React.Fragment, null);\n const combined = cssChunks.join(\"\\n\");\n const final = minify ? minifyCss(combined) : combined;\n return React.createElement(\"style\", {\n dangerouslySetInnerHTML: { __html: final },\n \"data-tw-route\": targetRoute,\n \"data-tw-injector\": \"true\"\n });\n}\nfunction useTwClasses(classes) {\n return classes;\n}\nfunction readFile(fs, filepath) {\n try {\n if (fs.existsSync(filepath)) return fs.readFileSync(filepath, \"utf-8\");\n } catch {\n }\n return null;\n}\nfunction minifyCss(css) {\n return css.replace(/\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//g, \"\").replace(/\\s+/g, \" \").replace(/\\s*{\\s*/g, \"{\").replace(/\\s*}\\s*/g, \"}\").replace(/\\s*;\\s*/g, \";\").trim();\n}\nexport {\n TwCssInjector,\n useTwClasses\n};\n"],"mappings":";AACA,IAAM,WAA2B,oBAAI,IAAI;AACzC,IAAM,UAAU,CAAC;AACjB,IAAM,SAAS;AAAA,EACb,WAAW;AAAA,EACX,SAAS;AACX;AACA,SAAS,kBAAkB;AACzB,MAAI,OAAO,WAAW,SAAS,KAAK,SAAS,OAAO,OAAO,EAAG,QAAO,OAAO;AAC5E,SAAO,UAAU,SAAS,cAAc,OAAO;AAC/C,SAAO,QAAQ,KAAK;AACpB,SAAO,QAAQ,aAAa,mBAAmB,MAAM;AACrD,WAAS,KAAK,YAAY,OAAO,OAAO;AACxC,SAAO,OAAO;AAChB;AACA,SAAS,kBAAkB,SAAS;AAClC,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI,CAAC,QAAS;AACd,QAAM,KAAK,gBAAgB;AAC3B,QAAM,QAAQ,GAAG;AACjB,MAAI,OAAO;AACT,QAAI;AACF,YAAM,WAAW,SAAS,MAAM,SAAS,MAAM;AAC/C;AAAA,IACF,QAAQ;AACN,UAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,gBAAQ,KAAK,wEAAwE,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,MAC3G;AAAA,IACF;AAAA,EACF;AACA,KAAG,eAAe,GAAG,eAAe,MAAM;AAAA,EAC1C,OAAO;AACT;AACA,SAAS,cAAc,SAAS;AAC9B,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI,CAAC,WAAW,SAAS,IAAI,OAAO,EAAG;AACvC,WAAS,IAAI,OAAO;AACpB,UAAQ,KAAK,OAAO;AACpB,MAAI,OAAO,cAAc,MAAM;AAC7B,WAAO,YAAY,sBAAsB,eAAe;AAAA,EAC1D;AACF;AACA,SAAS,kBAAkB;AACzB,SAAO,YAAY;AACnB,MAAI,QAAQ,WAAW,KAAK,OAAO,aAAa,YAAa;AAC7D,QAAM,QAAQ,QAAQ,OAAO,CAAC;AAC9B,aAAW,QAAQ,OAAO;AACxB,sBAAkB,IAAI;AAAA,EACxB;AACF;AACA,SAAS,WAAW,SAAS;AAC3B,MAAI,OAAO,aAAa,YAAa;AACrC,MAAI,CAAC,WAAW,SAAS,IAAI,OAAO,EAAG;AACvC,WAAS,IAAI,OAAO;AACpB,oBAAkB,OAAO;AAC3B;AACA,SAAS,WAAW,SAAS;AAC3B,SAAO,SAAS,IAAI,OAAO;AAC7B;AACA,SAAS,kBAAkB;AACzB,WAAS,MAAM;AACf,UAAQ,SAAS;AACjB,MAAI,OAAO,cAAc,MAAM;AAC7B,yBAAqB,OAAO,SAAS;AACrC,WAAO,YAAY;AAAA,EACrB;AACA,MAAI,OAAO,aAAa,eAAe,OAAO,WAAW,SAAS,KAAK,SAAS,OAAO,OAAO,GAAG;AAC/F,aAAS,KAAK,YAAY,OAAO,OAAO;AACxC,WAAO,UAAU;AAAA,EACnB,OAAO;AACL,WAAO,UAAU;AAAA,EACnB;AACF;AACA,SAAS,qBAAqB;AAC5B,SAAO;AAAA,IACL,eAAe,SAAS;AAAA,IACxB,cAAc,QAAQ;AAAA,IACtB,mBAAmB,OAAO,cAAc;AAAA,EAC1C;AACF;;;AC/EA,OAAO,WAAW;AA0ClB,SAAS,aAAa,SAAS;AAC7B,SAAO;AACT;","names":[]}