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.
- package/dist/animate.cjs +754 -235
- package/dist/animate.cjs.map +1 -1
- package/dist/animate.d.cts +55 -99
- package/dist/animate.d.ts +55 -99
- package/dist/animate.js +742 -235
- package/dist/animate.js.map +1 -1
- package/dist/chunk-VZEJV27B.js +11 -0
- package/dist/chunk-VZEJV27B.js.map +1 -0
- package/dist/chunk-Y5D3E72P.cjs +13 -0
- package/dist/chunk-Y5D3E72P.cjs.map +1 -0
- package/dist/css.cjs +61 -11
- package/dist/css.cjs.map +1 -1
- package/dist/css.d.cts +3 -18
- package/dist/css.d.ts +3 -18
- package/dist/css.js +61 -11
- package/dist/css.js.map +1 -1
- package/dist/devtools.cjs +200 -88
- package/dist/devtools.cjs.map +1 -1
- package/dist/devtools.js +200 -88
- package/dist/devtools.js.map +1 -1
- package/dist/index.cjs +430 -135
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -3
- package/dist/index.d.ts +74 -3
- package/dist/index.js +415 -132
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +118 -138
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +28 -19
- package/dist/next.d.ts +28 -19
- package/dist/next.js +111 -131
- package/dist/next.js.map +1 -1
- package/dist/preset.cjs +312 -18
- package/dist/preset.cjs.map +1 -1
- package/dist/preset.d.cts +29 -2
- package/dist/preset.d.ts +29 -2
- package/dist/preset.js +311 -19
- package/dist/preset.js.map +1 -1
- package/dist/turbopackLoader.cjs +24 -2676
- package/dist/turbopackLoader.cjs.map +1 -1
- package/dist/turbopackLoader.d.cts +3 -13
- package/dist/turbopackLoader.d.ts +3 -13
- package/dist/turbopackLoader.js +24 -2670
- package/dist/turbopackLoader.js.map +1 -1
- package/dist/vite.cjs +90 -57
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +35 -6
- package/dist/vite.d.ts +35 -6
- package/dist/vite.js +90 -58
- package/dist/vite.js.map +1 -1
- package/dist/webpackLoader.cjs +27 -2646
- package/dist/webpackLoader.cjs.map +1 -1
- package/dist/webpackLoader.d.cts +3 -10
- package/dist/webpackLoader.d.ts +3 -10
- package/dist/webpackLoader.js +27 -2640
- package/dist/webpackLoader.js.map +1 -1
- package/package.json +31 -28
- package/dist/astTransform-ua-eapqs.d.cts +0 -41
- package/dist/astTransform-ua-eapqs.d.ts +0 -41
- package/dist/compiler.cjs +0 -3594
- package/dist/compiler.cjs.map +0 -1
- package/dist/compiler.d.cts +0 -716
- package/dist/compiler.d.ts +0 -716
- package/dist/compiler.js +0 -3535
- package/dist/compiler.js.map +0 -1
- package/dist/plugins.cjs +0 -396
- package/dist/plugins.cjs.map +0 -1
- package/dist/plugins.d.cts +0 -231
- package/dist/plugins.d.ts +0 -231
- package/dist/plugins.js +0 -381
- package/dist/plugins.js.map +0 -1
- package/dist/theme.cjs +0 -154
- package/dist/theme.cjs.map +0 -1
- package/dist/theme.d.cts +0 -181
- package/dist/theme.d.ts +0 -181
- package/dist/theme.js +0 -148
- 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,
|
|
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
|
|
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 (
|
|
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:
|
|
129
|
-
React__default.default.createElement("span", { style:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
254
|
+
{ style: { ...S.row, marginTop: "4px" } },
|
|
274
255
|
React__default.default.createElement(
|
|
275
256
|
"span",
|
|
276
257
|
{
|
|
277
|
-
style:
|
|
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:
|
|
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_(
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
481
|
-
containerCount:
|
|
482
|
-
tokenCount: Object.keys(
|
|
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:
|
|
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
|
-
) :
|
|
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) =>
|
|
696
|
+
setState((s) => ({ ...s, open: !s.open, inspected: null }));
|
|
585
697
|
}
|
|
586
698
|
if (e.key === "Escape")
|
|
587
|
-
setState((s) =>
|
|
588
|
-
if (e.key === "1") setState((s) => s.open ?
|
|
589
|
-
if (e.key === "2") setState((s) => s.open ?
|
|
590
|
-
if (e.key === "3") setState((s) => s.open ?
|
|
591
|
-
if (e.key === "4") setState((s) => s.open ?
|
|
592
|
-
if (e.key === "5") setState((s) => s.open ?
|
|
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) =>
|
|
714
|
+
setState((s) => ({ ...s, inspected: null, position: { x: e.clientX, y: e.clientY } }));
|
|
604
715
|
return;
|
|
605
716
|
}
|
|
606
|
-
const { name, classes } = parseDataTw(
|
|
607
|
-
setState((s) => {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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 (
|
|
633
|
-
setState((s) =>
|
|
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) =>
|
|
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:
|
|
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 ?
|
|
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
|
-
}
|
|
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) =>
|
|
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:
|
|
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) =>
|
|
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}`
|