tailwind-styled-v4 4.0.0 → 5.0.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.
Files changed (77) hide show
  1. package/dist/animate.cjs +754 -235
  2. package/dist/animate.cjs.map +1 -1
  3. package/dist/animate.d.cts +55 -99
  4. package/dist/animate.d.ts +55 -99
  5. package/dist/animate.js +742 -235
  6. package/dist/animate.js.map +1 -1
  7. package/dist/chunk-VZEJV27B.js +11 -0
  8. package/dist/chunk-VZEJV27B.js.map +1 -0
  9. package/dist/chunk-Y5D3E72P.cjs +13 -0
  10. package/dist/chunk-Y5D3E72P.cjs.map +1 -0
  11. package/dist/css.cjs +61 -11
  12. package/dist/css.cjs.map +1 -1
  13. package/dist/css.d.cts +3 -18
  14. package/dist/css.d.ts +3 -18
  15. package/dist/css.js +61 -11
  16. package/dist/css.js.map +1 -1
  17. package/dist/devtools.cjs +200 -88
  18. package/dist/devtools.cjs.map +1 -1
  19. package/dist/devtools.js +200 -88
  20. package/dist/devtools.js.map +1 -1
  21. package/dist/index.cjs +430 -135
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +74 -3
  24. package/dist/index.d.ts +74 -3
  25. package/dist/index.js +415 -132
  26. package/dist/index.js.map +1 -1
  27. package/dist/next.cjs +118 -138
  28. package/dist/next.cjs.map +1 -1
  29. package/dist/next.d.cts +28 -19
  30. package/dist/next.d.ts +28 -19
  31. package/dist/next.js +111 -131
  32. package/dist/next.js.map +1 -1
  33. package/dist/preset.cjs +312 -18
  34. package/dist/preset.cjs.map +1 -1
  35. package/dist/preset.d.cts +29 -2
  36. package/dist/preset.d.ts +29 -2
  37. package/dist/preset.js +311 -19
  38. package/dist/preset.js.map +1 -1
  39. package/dist/turbopackLoader.cjs +24 -2676
  40. package/dist/turbopackLoader.cjs.map +1 -1
  41. package/dist/turbopackLoader.d.cts +3 -13
  42. package/dist/turbopackLoader.d.ts +3 -13
  43. package/dist/turbopackLoader.js +24 -2670
  44. package/dist/turbopackLoader.js.map +1 -1
  45. package/dist/vite.cjs +90 -57
  46. package/dist/vite.cjs.map +1 -1
  47. package/dist/vite.d.cts +35 -6
  48. package/dist/vite.d.ts +35 -6
  49. package/dist/vite.js +90 -58
  50. package/dist/vite.js.map +1 -1
  51. package/dist/webpackLoader.cjs +27 -2646
  52. package/dist/webpackLoader.cjs.map +1 -1
  53. package/dist/webpackLoader.d.cts +3 -10
  54. package/dist/webpackLoader.d.ts +3 -10
  55. package/dist/webpackLoader.js +27 -2640
  56. package/dist/webpackLoader.js.map +1 -1
  57. package/package.json +31 -28
  58. package/dist/astTransform-ua-eapqs.d.cts +0 -41
  59. package/dist/astTransform-ua-eapqs.d.ts +0 -41
  60. package/dist/compiler.cjs +0 -3594
  61. package/dist/compiler.cjs.map +0 -1
  62. package/dist/compiler.d.cts +0 -716
  63. package/dist/compiler.d.ts +0 -716
  64. package/dist/compiler.js +0 -3535
  65. package/dist/compiler.js.map +0 -1
  66. package/dist/plugins.cjs +0 -396
  67. package/dist/plugins.cjs.map +0 -1
  68. package/dist/plugins.d.cts +0 -231
  69. package/dist/plugins.d.ts +0 -231
  70. package/dist/plugins.js +0 -381
  71. package/dist/plugins.js.map +0 -1
  72. package/dist/theme.cjs +0 -154
  73. package/dist/theme.cjs.map +0 -1
  74. package/dist/theme.d.cts +0 -181
  75. package/dist/theme.d.ts +0 -181
  76. package/dist/theme.js +0 -148
  77. package/dist/theme.js.map +0 -1
package/dist/css.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../runtime-css/src/CssInjector.tsx"],"names":[],"mappings":";;;;;;AAsCA,eAAsB,aAAA,CAAc;AAAA,EAClC,MAAA;AAAA,EACA,KAAA;AAAA,EACA,aAAA,GAAgB,IAAA;AAAA,EAChB,MAAA,GAAS,IAAA;AAAA,EACT,MAAA,GAAS;AACX,CAAA,EAAkD;AAChD,EAAA,MAAM,WAAA,GAAc,MAAA,IAAA,IAAA,GAAA,MAAA,GAAU,IAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,KAAI,EAAG,OAAA,EAAS,QAAA,EAAU,KAAA,EAAO,IAAI,CAAA;AAErF,EAAA,MAAM,YAAsB,EAAC;AAG7B,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,MAAM,YAAY,WAAA,CAAY,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,aAAa,CAAC,CAAA;AACnE,IAAA,IAAI,SAAA,EAAW,SAAA,CAAU,IAAA,CAAK,SAAS,CAAA;AAAA,EACzC;AAGA,EAAA,MAAM,cAAc,KAAA,IAAA,IAAA,GAAA,KAAA,GAAS,GAAA;AAC7B,EAAA,MAAM,SAAA,GAAY,gBAAgB,WAAW,CAAA;AAC7C,EAAA,MAAM,WAAW,WAAA,CAAY,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,SAAS,CAAC,CAAA;AAC9D,EAAA,IAAI,QAAA,EAAU,SAAA,CAAU,IAAA,CAAK,QAAQ,CAAA;AAErC,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG,OAAO,MAAM,aAAA,CAAc,KAAA,CAAM,UAAU,IAAI,CAAA;AAE3E,EAAA,MAAM,QAAA,GAAW,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,MAAA,GAAS,SAAA,CAAU,QAAQ,CAAA,GAAI,QAAA;AAE7C,EAAA,IAAI,MAAA,EAAQ;AAEV,IAAA,OAAO,KAAA,CAAM,cAAc,MAAA,EAAQ;AAAA,MACjC,GAAA,EAAK,YAAA;AAAA,MACL,IAAA,EAAM,wBAAwB,SAAS,CAAA,CAAA;AAAA,MACvC,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,EACH;AAGA,EAAA,OAAO,KAAA,CAAM,cAAc,OAAA,EAAS;AAAA,IAClC,uBAAA,EAAyB,EAAE,MAAA,EAAQ,KAAA,EAAM;AAAA,IACzC,eAAA,EAAiB;AAAA,GAClB,CAAA;AACH;AAYO,SAAS,aAAa,OAAA,EAAyB;AAGpD,EAAA,OAAO,OAAA;AACT;AAMA,SAAS,YAAY,QAAA,EAAiC;AACpD,EAAA,IAAI;AACF,IAAA,IAAI,EAAA,CAAG,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC3B,MAAA,OAAO,EAAA,CAAG,YAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AAAA,IAC1C;AAAA,EACF,CAAA,CAAA,OAAQ,CAAA,EAAA;AAAA,EAER;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,gBAAgB,KAAA,EAAuB;AAC9C,EAAA,IAAI,KAAA,KAAU,KAAK,OAAO,WAAA;AAC1B,EAAA,IAAI,KAAA,KAAU,YAAY,OAAO,aAAA;AACjC,EAAA,OAAO,CAAA,EAAG,MAAM,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAC,CAAA,IAAA,CAAA;AACxD;AAEA,SAAS,UAAU,GAAA,EAAqB;AACtC,EAAA,OAAO,GAAA,CACJ,QAAQ,iCAAA,EAAmC,EAAE,EAC7C,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,OAAA,CAAQ,YAAY,GAAG,CAAA,CACvB,QAAQ,UAAA,EAAY,GAAG,EACvB,OAAA,CAAQ,UAAA,EAAY,GAAG,CAAA,CACvB,IAAA,EAAK;AACV","file":"css.js","sourcesContent":["/**\n * tailwind-styled-v4 — CSS Injector (React Server Component)\n *\n * Inject CSS yang sudah di-generate per-route langsung ke <head>.\n * Dipakai di Next.js App Router layout atau page.\n *\n * Di server component — inject inline CSS, zero client JS.\n * Streaming friendly — CSS di-emit bersamaan dengan HTML.\n *\n * Usage:\n * // app/layout.tsx\n * import { TwCssInjector } from \"tailwind-styled-v4/css\"\n * export default function Layout({ children }) {\n * return <html><head><TwCssInjector/></head><body>{children}</body></html>\n * }\n */\n\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport React from \"react\"\n\ninterface CssInjectorProps {\n /** Override CSS directory. Default: .next/static/css/tw */\n cssDir?: string\n /** Specific route to inject. Default: auto-detect dari headers */\n route?: string\n /** Inject global CSS juga. Default: true */\n includeGlobal?: boolean\n /** Minify inline CSS. Default: true */\n minify?: boolean\n /** Add <link> tag instead of inline <style> untuk cached CSS */\n asLink?: boolean\n}\n\n/**\n * Server Component — inject route-specific CSS into <head>.\n * No client JS, no hydration overhead.\n */\nexport async function TwCssInjector({\n cssDir,\n route,\n includeGlobal = true,\n minify = true,\n asLink = false,\n}: CssInjectorProps): Promise<React.ReactElement> {\n const resolvedDir = cssDir ?? path.join(process.cwd(), \".next\", \"static\", \"css\", \"tw\")\n\n const cssChunks: string[] = []\n\n // 1. Global CSS (base styles, reset)\n if (includeGlobal) {\n const globalCss = loadCssFile(path.join(resolvedDir, \"_global.css\"))\n if (globalCss) cssChunks.push(globalCss)\n }\n\n // 2. Route-specific CSS\n const targetRoute = route ?? \"/\"\n const routeFile = routeToFilename(targetRoute)\n const routeCss = loadCssFile(path.join(resolvedDir, routeFile))\n if (routeCss) cssChunks.push(routeCss)\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 if (asLink) {\n // Return <link> tag — CSS cached by browser\n return React.createElement(\"link\", {\n rel: \"stylesheet\",\n href: `/_next/static/css/tw/${routeFile}`,\n crossOrigin: \"anonymous\",\n })\n }\n\n // Inline <style> — zero network request, fastest FCP\n return React.createElement(\"style\", {\n dangerouslySetInnerHTML: { __html: final },\n \"data-tw-route\": targetRoute,\n })\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Hook for client components\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Lightweight hook to get current route's CSS classes.\n * Useful for dynamic class injection in client components.\n *\n * Returns empty string on server (SSR) — CSS already injected by TwCssInjector.\n */\nexport function useTwClasses(classes: string): string {\n // In client environment, return classes as-is\n // CSS is already handled by TwCssInjector at server level\n return classes\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction loadCssFile(filepath: string): string | null {\n try {\n if (fs.existsSync(filepath)) {\n return fs.readFileSync(filepath, \"utf-8\")\n }\n } catch {\n // file not found or unreadable\n }\n return null\n}\n\nfunction routeToFilename(route: string): string {\n if (route === \"/\") return \"index.css\"\n if (route === \"__global\") return \"_global.css\"\n return `${route.replace(/^\\//, \"\").replace(/\\//g, \"_\")}.css`\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}\n"]}
1
+ {"version":3,"sources":["../../runtime-css/src/CssInjector.tsx"],"names":[],"mappings":"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","file":"css.js","sourcesContent":["\"use server\"\n\n/**\n * tailwind-styled-v5 — CSS Injector (React Server Component)\n *\n * Inject CSS yang sudah di-generate per-route langsung ke <head>.\n * Dipakai di Next.js App Router layout atau page.\n *\n * Di server component — inject inline CSS, zero client JS.\n * Streaming friendly — CSS di-emit bersamaan dengan HTML.\n *\n * Usage:\n * // app/layout.tsx\n * import { TwCssInjector } from \"tailwind-styled-v4/css\"\n * export default function Layout({ children }) {\n * return <html><head><TwCssInjector/></head><body>{children}</body></html>\n * }\n */\n\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport React from \"react\"\n\ninterface CssInjectorProps {\n /** Override CSS directory. Default: .next/static/css/tw */\n cssDir?: string\n /** Specific route to inject. Default: auto-detect dari headers */\n route?: string\n /** Inject global CSS juga. Default: true */\n includeGlobal?: boolean\n /** Minify inline CSS. Default: true */\n minify?: boolean\n /** Add <link> tag instead of inline <style> untuk cached CSS */\n asLink?: boolean\n /** Override manifest path for dev mode */\n manifestPath?: string\n}\n\nconst defaultProps: CssInjectorProps = {\n cssDir: undefined,\n route: undefined,\n includeGlobal: true,\n minify: true,\n asLink: false,\n manifestPath: undefined,\n}\n\n/**\n * Server Component — inject route-specific CSS into <head>.\n * No client JS, no hydration overhead.\n */\nexport async function TwCssInjector(props?: CssInjectorProps): Promise<React.ReactElement> {\n const { cssDir, route, includeGlobal, minify, asLink, manifestPath } = {\n ...defaultProps,\n ...props,\n }\n const resolvedDir = cssDir ?? path.join(process.cwd(), \".next\", \"static\", \"css\", \"tw\")\n\n const cssChunks: string[] = []\n\n // Try manifest-based loading first (for dev mode)\n if (manifestPath) {\n const manifestCss = loadCssFromManifest(manifestPath, route ?? \"/\")\n if (manifestCss) {\n cssChunks.push(manifestCss)\n }\n } else {\n // Fallback: legacy file-based loading with path detection\n const detectedManifest = detectManifestPath(resolvedDir)\n if (detectedManifest) {\n const manifestCss = loadCssFromManifest(detectedManifest, route ?? \"/\")\n if (manifestCss) {\n cssChunks.push(manifestCss)\n }\n }\n }\n\n // 1. Global CSS (base styles, reset)\n if (includeGlobal) {\n const globalCss = loadCssFile(path.join(resolvedDir, \"_global.css\"))\n if (globalCss) cssChunks.push(globalCss)\n }\n\n // 2. Route-specific CSS\n const targetRoute = route ?? \"/\"\n const routeFile = routeToFilename(targetRoute)\n const routeCss = loadCssFile(path.join(resolvedDir, routeFile))\n if (routeCss) cssChunks.push(routeCss)\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 if (asLink) {\n // Return <link> tag — CSS cached by browser\n return React.createElement(\"link\", {\n rel: \"stylesheet\",\n href: `/_next/static/css/tw/${routeFile}`,\n crossOrigin: \"anonymous\",\n })\n }\n\n // Inline <style> — zero network request, fastest FCP\n return React.createElement(\"style\", {\n dangerouslySetInnerHTML: { __html: final },\n \"data-tw-route\": targetRoute,\n })\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Hook for client components\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Lightweight hook to get current route's CSS classes.\n * Useful for dynamic class injection in client components.\n *\n * Returns empty string on server (SSR) — CSS already injected by TwCssInjector.\n */\nexport function useTwClasses(classes: string): string {\n // In client environment, return classes as-is\n // CSS is already handled by TwCssInjector at server level\n return classes\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction loadCssFile(filepath: string): string | null {\n try {\n if (fs.existsSync(filepath)) {\n return fs.readFileSync(filepath, \"utf-8\")\n }\n } catch {\n // file not found or unreadable\n }\n return null\n}\n\nfunction routeToFilename(route: string): string {\n if (route === \"/\") return \"index.css\"\n if (route === \"__global\") return \"_global.css\"\n return `${route.replace(/^\\//, \"\").replace(/\\//g, \"_\")}.css`\n}\n\nfunction detectManifestPath(cssDir: string): string | null {\n const candidates = [\n path.join(cssDir, \"css-manifest.json\"),\n path.join(process.cwd(), \"public\", \"__tw\", \"css-manifest.json\"),\n path.join(process.cwd(), \"artifacts\", \"route-css\", \"css-manifest.json\"),\n ]\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate\n }\n }\n return null\n}\n\ninterface CssManifest {\n routes?: Record<string, string>\n global?: string\n [key: string]: unknown\n}\n\nfunction loadCssFromManifest(manifestPath: string, route: string): string | null {\n try {\n if (!fs.existsSync(manifestPath)) return null\n\n const content = fs.readFileSync(manifestPath, \"utf-8\")\n const manifest: CssManifest = JSON.parse(content)\n\n // Try route-specific CSS\n if (manifest.routes?.[route]) {\n const routeCssPath = path.join(path.dirname(manifestPath), manifest.routes[route])\n return loadCssFile(routeCssPath)\n }\n\n // Fallback: global CSS\n if (manifest.global) {\n const globalCssPath = path.join(path.dirname(manifestPath), manifest.global)\n return loadCssFile(globalCssPath)\n }\n } catch {\n // manifest not found or invalid\n }\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}\n"]}
package/dist/devtools.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ require('./chunk-Y5D3E72P.cjs');
3
4
  var React = require('react');
4
5
 
5
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -7,25 +8,6 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
8
  var React__default = /*#__PURE__*/_interopDefault(React);
8
9
 
9
10
  /* tailwind-styled-v4 v4 | MIT | https://github.com/dictionar32/tailwind-styled-v4 */
10
- var __defProp = Object.defineProperty;
11
- var __defProps = Object.defineProperties;
12
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
13
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
14
- var __hasOwnProp = Object.prototype.hasOwnProperty;
15
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
16
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
17
- var __spreadValues = (a, b) => {
18
- for (var prop in b || (b = {}))
19
- if (__hasOwnProp.call(b, prop))
20
- __defNormalProp(a, prop, b[prop]);
21
- if (__getOwnPropSymbols)
22
- for (var prop of __getOwnPropSymbols(b)) {
23
- if (__propIsEnum.call(b, prop))
24
- __defNormalProp(a, prop, b[prop]);
25
- }
26
- return a;
27
- };
28
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
29
11
  function parseDataTw(dataTw) {
30
12
  if (!dataTw) return { name: "Unknown", classes: [] };
31
13
  const colonIdx = dataTw.indexOf(":");
@@ -38,15 +20,14 @@ function parseVariantAttr(v) {
38
20
  if (!v) return {};
39
21
  try {
40
22
  return JSON.parse(v);
41
- } catch (e) {
23
+ } catch {
42
24
  return {};
43
25
  }
44
26
  }
45
27
  function findNearestTwElement(el) {
46
- var _a;
47
28
  let cur = el;
48
29
  while (cur) {
49
- if ((_a = cur.dataset) == null ? void 0 : _a.tw) return cur;
30
+ if (cur.dataset?.tw) return cur;
50
31
  cur = cur.parentElement;
51
32
  }
52
33
  return null;
@@ -125,8 +106,8 @@ function InspectorPanel({
125
106
  ([k, v]) => React__default.default.createElement(
126
107
  "div",
127
108
  { key: k, style: S.row },
128
- React__default.default.createElement("code", { style: __spreadProps(__spreadValues({}, S.varKey), { color: "#f59e0b" }) }, `data-${k}`),
129
- React__default.default.createElement("span", { style: __spreadProps(__spreadValues({}, S.varValue), { color: "#34d399" }) }, `"${v}"`)
109
+ React__default.default.createElement("code", { style: { ...S.varKey, color: "#f59e0b" } }, `data-${k}`),
110
+ React__default.default.createElement("span", { style: { ...S.varValue, color: "#34d399" } }, `"${v}"`)
130
111
  )
131
112
  )
132
113
  ),
@@ -143,10 +124,11 @@ function InspectorPanel({
143
124
  "code",
144
125
  {
145
126
  key: s,
146
- style: __spreadProps(__spreadValues({}, S.classChip), {
127
+ style: {
128
+ ...S.classChip,
147
129
  background: inspected.activeStates[s] === "true" ? "#065f46" : "#18181b",
148
130
  borderColor: inspected.activeStates[s] === "true" ? "#34d399" : "#27272a"
149
- })
131
+ }
150
132
  },
151
133
  s
152
134
  )
@@ -164,7 +146,7 @@ function InspectorPanel({
164
146
  inspected.containerBps.map(
165
147
  (bp) => React__default.default.createElement(
166
148
  "code",
167
- { key: bp, style: __spreadProps(__spreadValues({}, S.classChip), { color: "#818cf8" }) },
149
+ { key: bp, style: { ...S.classChip, color: "#818cf8" } },
168
150
  bp
169
151
  )
170
152
  )
@@ -193,8 +175,7 @@ function InspectorPanel({
193
175
  {
194
176
  style: S.copyBtn,
195
177
  onClick: () => {
196
- var _a;
197
- (_a = navigator.clipboard) == null ? void 0 : _a.writeText(
178
+ navigator.clipboard?.writeText(
198
179
  JSON.stringify(
199
180
  {
200
181
  component: inspected.componentName,
@@ -263,21 +244,22 @@ function StatePanel() {
263
244
  entry.states.map(
264
245
  (s) => React__default.default.createElement(
265
246
  "code",
266
- { key: s, style: __spreadProps(__spreadValues({}, S.classChip), { color: "#f59e0b" }) },
247
+ { key: s, style: { ...S.classChip, color: "#f59e0b" } },
267
248
  `data-${s}`
268
249
  )
269
250
  )
270
251
  ),
271
252
  React__default.default.createElement(
272
253
  "div",
273
- { style: __spreadProps(__spreadValues({}, S.row), { marginTop: "4px" }) },
254
+ { style: { ...S.row, marginTop: "4px" } },
274
255
  React__default.default.createElement(
275
256
  "span",
276
257
  {
277
- style: __spreadProps(__spreadValues({}, S.sectionTitle), {
258
+ style: {
259
+ ...S.sectionTitle,
278
260
  marginBottom: 0,
279
261
  color: entry.cssInjected ? "#34d399" : "#ef4444"
280
- })
262
+ }
281
263
  },
282
264
  entry.cssInjected ? "\u25CF CSS injected" : "\u25CB CSS pending"
283
265
  )
@@ -342,7 +324,7 @@ function ContainerPanel() {
342
324
  entry.breakpoints.map(
343
325
  (bp, i) => React__default.default.createElement(
344
326
  "div",
345
- { key: i, style: __spreadProps(__spreadValues({}, S.row), { marginBottom: "2px" }) },
327
+ { key: i, style: { ...S.row, marginBottom: "2px" } },
346
328
  React__default.default.createElement(
347
329
  "code",
348
330
  { style: { color: "#818cf8", fontSize: "11px" } },
@@ -366,7 +348,7 @@ function TokensPanel() {
366
348
  const engine = window.__TW_TOKEN_ENGINE__;
367
349
  if (!engine) return;
368
350
  setTokens_(engine.getTokens());
369
- const unsub = engine.subscribe((t) => setTokens_(__spreadValues({}, t)));
351
+ const unsub = engine.subscribe((t) => setTokens_({ ...t }));
370
352
  return unsub;
371
353
  }, []);
372
354
  const entries = Object.entries(tokens);
@@ -388,14 +370,14 @@ function TokensPanel() {
388
370
  { style: S.scrollArea },
389
371
  React__default.default.createElement(
390
372
  "div",
391
- { style: __spreadProps(__spreadValues({}, S.sectionTitle), { padding: "8px 12px 4px", color: "#52525b" }) },
373
+ { style: { ...S.sectionTitle, padding: "8px 12px 4px", color: "#52525b" } },
392
374
  "Click color to edit \xB7 Changes apply instantly"
393
375
  ),
394
376
  entries.map(([name, value]) => {
395
377
  const isColor = value.startsWith("#") || value.startsWith("rgb") || value.startsWith("hsl");
396
378
  return React__default.default.createElement(
397
379
  "div",
398
- { key: name, style: __spreadProps(__spreadValues({}, S.row), { padding: "6px 12px", borderBottom: "1px solid #18181b" }) },
380
+ { key: name, style: { ...S.row, padding: "6px 12px", borderBottom: "1px solid #18181b" } },
399
381
  React__default.default.createElement(
400
382
  "div",
401
383
  { style: { display: "flex", alignItems: "center", gap: "8px" } },
@@ -450,16 +432,35 @@ function TokensPanel() {
450
432
  function AnalyzerPanel() {
451
433
  const [scanning, setScanning] = React.useState(false);
452
434
  const [results, setResults] = React.useState(null);
435
+ const [engineMetrics, setEngineMetrics] = React.useState(null);
436
+ const [metricsFetching, setMetricsFetching] = React.useState(false);
437
+ const [metricsError, setMetricsError] = React.useState(null);
438
+ const loadEngineMetrics = React.useCallback(async () => {
439
+ setMetricsFetching(true);
440
+ setMetricsError(null);
441
+ try {
442
+ const res = await fetch("http://localhost:3000/metrics", { signal: AbortSignal.timeout(2e3) });
443
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
444
+ const data = await res.json();
445
+ setEngineMetrics(data);
446
+ } catch (e) {
447
+ const msg = e instanceof Error ? e.message : String(e);
448
+ setMetricsError(
449
+ msg.includes("Failed to fetch") || msg.includes("NetworkError") ? "Dashboard tidak berjalan. Jalankan: tw dashboard" : msg
450
+ );
451
+ setEngineMetrics(null);
452
+ } finally {
453
+ setMetricsFetching(false);
454
+ }
455
+ }, []);
453
456
  const runScan = React.useCallback(() => {
454
457
  setScanning(true);
455
458
  setTimeout(() => {
456
- var _a, _b, _c, _d;
457
459
  const twEls = document.querySelectorAll("[data-tw]");
458
460
  const classMap = /* @__PURE__ */ new Map();
459
461
  for (const el of twEls) {
460
462
  const { name, classes } = (() => {
461
- var _a2;
462
- const dTw = (_a2 = el.dataset.tw) != null ? _a2 : null;
463
+ const dTw = el.dataset.tw ?? null;
463
464
  if (!dTw) return { name: "?", classes: [] };
464
465
  const ci = dTw.indexOf(":");
465
466
  return {
@@ -477,9 +478,9 @@ function AnalyzerPanel() {
477
478
  const tokenEngine = window.__TW_TOKEN_ENGINE__;
478
479
  setResults({
479
480
  duplicates,
480
- stateCount: (_a = stateReg == null ? void 0 : stateReg.size) != null ? _a : 0,
481
- containerCount: (_b = containerReg == null ? void 0 : containerReg.size) != null ? _b : 0,
482
- tokenCount: Object.keys((_d = (_c = tokenEngine == null ? void 0 : tokenEngine.getTokens) == null ? void 0 : _c.call(tokenEngine)) != null ? _d : {}).length
481
+ stateCount: stateReg?.size ?? 0,
482
+ containerCount: containerReg?.size ?? 0,
483
+ tokenCount: Object.keys(tokenEngine?.getTokens?.() ?? {}).length
483
484
  });
484
485
  setScanning(false);
485
486
  }, 100);
@@ -490,19 +491,131 @@ function AnalyzerPanel() {
490
491
  React__default.default.createElement(
491
492
  "div",
492
493
  { style: { padding: "10px 12px" } },
494
+ // ── DOM Scan ──────────────────────────────────────────────────────────
493
495
  React__default.default.createElement(
494
496
  "button",
495
497
  {
496
- style: __spreadProps(__spreadValues({}, S.copyBtn), { borderTop: "none", color: "#60a5fa", fontWeight: "600" }),
498
+ style: { ...S.copyBtn, borderTop: "none", color: "#60a5fa", fontWeight: "600" },
497
499
  onClick: runScan,
498
500
  disabled: scanning
499
501
  },
500
502
  scanning ? "Scanning DOM..." : "\u25B6 Run DOM Scan"
501
503
  ),
504
+ // ── Engine Metrics (dari dashboard) ───────────────────────────────────
505
+ React__default.default.createElement(
506
+ "div",
507
+ { style: { ...S.section, marginTop: "8px" } },
508
+ React__default.default.createElement(
509
+ "div",
510
+ { style: { ...S.sectionTitle, marginBottom: "6px" } },
511
+ "\u26A1 Engine Metrics"
512
+ ),
513
+ engineMetrics ? React__default.default.createElement(
514
+ "div",
515
+ null,
516
+ React__default.default.createElement(
517
+ "div",
518
+ { style: S.row },
519
+ React__default.default.createElement("span", { style: S.varKey }, "Build"),
520
+ React__default.default.createElement(
521
+ "span",
522
+ { style: { ...S.varValue, color: "#34d399" } },
523
+ engineMetrics.buildMs != null ? `${engineMetrics.buildMs}ms` : "\u2014"
524
+ )
525
+ ),
526
+ React__default.default.createElement(
527
+ "div",
528
+ { style: S.row },
529
+ React__default.default.createElement("span", { style: S.varKey }, "Classes"),
530
+ React__default.default.createElement(
531
+ "span",
532
+ { style: { ...S.varValue, color: "#34d399" } },
533
+ String(engineMetrics.classCount ?? "\u2014")
534
+ )
535
+ ),
536
+ React__default.default.createElement(
537
+ "div",
538
+ { style: S.row },
539
+ React__default.default.createElement("span", { style: S.varKey }, "Files"),
540
+ React__default.default.createElement(
541
+ "span",
542
+ { style: { ...S.varValue, color: "#34d399" } },
543
+ String(engineMetrics.fileCount ?? "\u2014")
544
+ )
545
+ ),
546
+ React__default.default.createElement(
547
+ "div",
548
+ { style: S.row },
549
+ React__default.default.createElement("span", { style: S.varKey }, "Mode"),
550
+ React__default.default.createElement(
551
+ "span",
552
+ { style: { color: "#a1a1aa", fontSize: "11px" } },
553
+ String(engineMetrics.mode ?? "\u2014")
554
+ )
555
+ ),
556
+ React__default.default.createElement(
557
+ "button",
558
+ {
559
+ style: {
560
+ ...S.copyBtn,
561
+ borderTop: "none",
562
+ color: "#52525b",
563
+ fontSize: "10px",
564
+ padding: "4px 0"
565
+ },
566
+ onClick: loadEngineMetrics,
567
+ disabled: metricsFetching
568
+ },
569
+ "\u21BB Refresh"
570
+ )
571
+ ) : metricsError ? React__default.default.createElement(
572
+ "div",
573
+ null,
574
+ React__default.default.createElement(
575
+ "div",
576
+ { style: { color: "#f87171", fontSize: "11px", marginBottom: "6px" } },
577
+ metricsError
578
+ ),
579
+ React__default.default.createElement(
580
+ "button",
581
+ {
582
+ style: { ...S.copyBtn, borderTop: "none", color: "#34d399", fontWeight: "600" },
583
+ onClick: loadEngineMetrics,
584
+ disabled: metricsFetching
585
+ },
586
+ metricsFetching ? "Connecting..." : "\u21BB Retry"
587
+ )
588
+ ) : React__default.default.createElement(
589
+ "div",
590
+ null,
591
+ React__default.default.createElement(
592
+ "div",
593
+ {
594
+ style: { color: "#71717a", fontSize: "11px", lineHeight: 1.6, marginBottom: "6px" }
595
+ },
596
+ "Rust analyzer hanya tersedia via CLI atau dashboard.",
597
+ React__default.default.createElement("br", null),
598
+ React__default.default.createElement(
599
+ "code",
600
+ { style: { color: "#52525b", fontSize: "10px" } },
601
+ "tw analyze . | tw dashboard"
602
+ )
603
+ ),
604
+ React__default.default.createElement(
605
+ "button",
606
+ {
607
+ style: { ...S.copyBtn, borderTop: "none", color: "#34d399", fontWeight: "600" },
608
+ onClick: loadEngineMetrics,
609
+ disabled: metricsFetching
610
+ },
611
+ metricsFetching ? "Connecting..." : "\u26A1 Load from Dashboard"
612
+ )
613
+ )
614
+ ),
615
+ // ── DOM Scan Results ──────────────────────────────────────────────────
502
616
  results && React__default.default.createElement(
503
617
  "div",
504
618
  null,
505
- // Summary
506
619
  React__default.default.createElement(
507
620
  "div",
508
621
  { style: S.section },
@@ -526,7 +639,6 @@ function AnalyzerPanel() {
526
639
  React__default.default.createElement("span", { style: S.varValue }, String(results.tokenCount))
527
640
  )
528
641
  ),
529
- // Duplicates
530
642
  results.duplicates.length > 0 ? React__default.default.createElement(
531
643
  "div",
532
644
  { style: S.section },
@@ -553,7 +665,7 @@ function AnalyzerPanel() {
553
665
  )
554
666
  )
555
667
  )
556
- ) : results && React__default.default.createElement(
668
+ ) : React__default.default.createElement(
557
669
  "div",
558
670
  { style: S.section },
559
671
  React__default.default.createElement(
@@ -581,56 +693,52 @@ function TwDevTools() {
581
693
  const onKey = (e) => {
582
694
  if (e.ctrlKey && e.shiftKey && e.key === "D") {
583
695
  e.preventDefault();
584
- setState((s) => __spreadProps(__spreadValues({}, s), { open: !s.open, inspected: null }));
696
+ setState((s) => ({ ...s, open: !s.open, inspected: null }));
585
697
  }
586
698
  if (e.key === "Escape")
587
- setState((s) => __spreadProps(__spreadValues({}, s), { open: false, pinned: false, inspected: null }));
588
- if (e.key === "1") setState((s) => s.open ? __spreadProps(__spreadValues({}, s), { panel: "inspector" }) : s);
589
- if (e.key === "2") setState((s) => s.open ? __spreadProps(__spreadValues({}, s), { panel: "state" }) : s);
590
- if (e.key === "3") setState((s) => s.open ? __spreadProps(__spreadValues({}, s), { panel: "container" }) : s);
591
- if (e.key === "4") setState((s) => s.open ? __spreadProps(__spreadValues({}, s), { panel: "tokens" }) : s);
592
- if (e.key === "5") setState((s) => s.open ? __spreadProps(__spreadValues({}, s), { panel: "analyzer" }) : s);
699
+ setState((s) => ({ ...s, open: false, pinned: false, inspected: null }));
700
+ if (e.key === "1") setState((s) => s.open ? { ...s, panel: "inspector" } : s);
701
+ if (e.key === "2") setState((s) => s.open ? { ...s, panel: "state" } : s);
702
+ if (e.key === "3") setState((s) => s.open ? { ...s, panel: "container" } : s);
703
+ if (e.key === "4") setState((s) => s.open ? { ...s, panel: "tokens" } : s);
704
+ if (e.key === "5") setState((s) => s.open ? { ...s, panel: "analyzer" } : s);
593
705
  };
594
706
  window.addEventListener("keydown", onKey);
595
707
  return () => window.removeEventListener("keydown", onKey);
596
708
  }, []);
597
709
  const onMouseMove = React.useCallback(
598
710
  (e) => {
599
- var _a;
600
711
  if (!isInspecting || state.pinned) return;
601
712
  const twEl = findNearestTwElement(e.target);
602
713
  if (!twEl) {
603
- setState((s) => __spreadProps(__spreadValues({}, s), { inspected: null, position: { x: e.clientX, y: e.clientY } }));
714
+ setState((s) => ({ ...s, inspected: null, position: { x: e.clientX, y: e.clientY } }));
604
715
  return;
605
716
  }
606
- const { name, classes } = parseDataTw((_a = twEl.dataset.tw) != null ? _a : null);
607
- setState((s) => {
608
- var _a2;
609
- return __spreadProps(__spreadValues({}, s), {
610
- position: { x: e.clientX, y: e.clientY },
611
- inspected: {
612
- componentName: name,
613
- element: twEl,
614
- rect: twEl.getBoundingClientRect(),
615
- twClasses: classes,
616
- variantProps: parseVariantAttr((_a2 = twEl.dataset.twVariants) != null ? _a2 : null),
617
- atomicMap: getAtomicMap(classes),
618
- rawClassName: twEl.className,
619
- stateNames: getStateNames(twEl),
620
- activeStates: getActiveStates(twEl),
621
- containerBps: getContainerBps(twEl)
622
- }
623
- });
624
- });
717
+ const { name, classes } = parseDataTw(twEl.dataset.tw ?? null);
718
+ setState((s) => ({
719
+ ...s,
720
+ position: { x: e.clientX, y: e.clientY },
721
+ inspected: {
722
+ componentName: name,
723
+ element: twEl,
724
+ rect: twEl.getBoundingClientRect(),
725
+ twClasses: classes,
726
+ variantProps: parseVariantAttr(twEl.dataset.twVariants ?? null),
727
+ atomicMap: getAtomicMap(classes),
728
+ rawClassName: twEl.className,
729
+ stateNames: getStateNames(twEl),
730
+ activeStates: getActiveStates(twEl),
731
+ containerBps: getContainerBps(twEl)
732
+ }
733
+ }));
625
734
  },
626
735
  [isInspecting, state.pinned]
627
736
  );
628
737
  const onClick = React.useCallback(
629
738
  (e) => {
630
- var _a;
631
739
  if (!isInspecting) return;
632
- if ((_a = overlayRef.current) == null ? void 0 : _a.contains(e.target)) return;
633
- setState((s) => __spreadProps(__spreadValues({}, s), { pinned: !s.pinned && !!s.inspected }));
740
+ if (overlayRef.current?.contains(e.target)) return;
741
+ setState((s) => ({ ...s, pinned: !s.pinned && !!s.inspected }));
634
742
  },
635
743
  [isInspecting]
636
744
  );
@@ -647,7 +755,7 @@ function TwDevTools() {
647
755
  return React__default.default.createElement(
648
756
  "button",
649
757
  {
650
- onClick: () => setState((s) => __spreadProps(__spreadValues({}, s), { open: true })),
758
+ onClick: () => setState((s) => ({ ...s, open: true })),
651
759
  style: S.toggleBtn,
652
760
  title: "tailwind-styled-v4 DevTools (Ctrl+Shift+D)"
653
761
  },
@@ -666,12 +774,13 @@ function TwDevTools() {
666
774
  { style: S.root },
667
775
  // ── Element highlight (inspector only) ──────────────────────────────
668
776
  isInspecting && state.inspected && React__default.default.createElement("div", {
669
- style: __spreadProps(__spreadValues({}, S.highlight), {
777
+ style: {
778
+ ...S.highlight,
670
779
  top: state.inspected.rect.top + window.scrollY,
671
780
  left: state.inspected.rect.left + window.scrollX,
672
781
  width: state.inspected.rect.width,
673
782
  height: state.inspected.rect.height
674
- })
783
+ }
675
784
  }),
676
785
  // ── Component name label ────────────────────────────────────────────
677
786
  isInspecting && state.inspected && React__default.default.createElement(
@@ -698,15 +807,17 @@ function TwDevTools() {
698
807
  "div",
699
808
  {
700
809
  ref: overlayRef,
701
- style: state.panel === "inspector" && state.inspected ? __spreadProps(__spreadValues({}, S.panel), {
810
+ style: state.panel === "inspector" && state.inspected ? {
811
+ ...S.panel,
702
812
  top: Math.min(state.position.y + 16, window.innerHeight - 460),
703
813
  left: Math.min(state.position.x + 16, window.innerWidth - 320)
704
- }) : __spreadProps(__spreadValues({}, S.panel), {
814
+ } : {
815
+ ...S.panel,
705
816
  top: "auto",
706
817
  bottom: "40px",
707
818
  right: "12px",
708
819
  left: "auto"
709
- })
820
+ }
710
821
  },
711
822
  // Header
712
823
  React__default.default.createElement(
@@ -725,7 +836,7 @@ function TwDevTools() {
725
836
  "button",
726
837
  {
727
838
  style: S.closeBtn,
728
- onClick: () => setState((s) => __spreadProps(__spreadValues({}, s), { open: false, pinned: false, inspected: null }))
839
+ onClick: () => setState((s) => ({ ...s, open: false, pinned: false, inspected: null }))
729
840
  },
730
841
  "\u2715"
731
842
  )
@@ -740,12 +851,13 @@ function TwDevTools() {
740
851
  "button",
741
852
  {
742
853
  key: p.id,
743
- style: __spreadProps(__spreadValues({}, S.tab), {
854
+ style: {
855
+ ...S.tab,
744
856
  background: state.panel === p.id ? "#18181b" : "none",
745
857
  color: state.panel === p.id ? "#e4e4e7" : "#52525b",
746
858
  borderBottom: state.panel === p.id ? "2px solid #3b82f6" : "2px solid transparent"
747
- }),
748
- onClick: () => setState((s) => __spreadProps(__spreadValues({}, s), { panel: p.id })),
859
+ },
860
+ onClick: () => setState((s) => ({ ...s, panel: p.id })),
749
861
  title: `${p.label} (${PANELS.findIndex((x) => x.id === p.id) + 1})`
750
862
  },
751
863
  `${p.icon} ${p.label}`