@kbach/react 0.6.51 → 1.0.0-beta.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/README.md +90 -418
- package/dist/chunk-AFY36PRX.mjs +414 -0
- package/dist/chunk-G3RJJNSY.mjs +100 -0
- package/dist/chunk-VBPQAIZL.mjs +32 -0
- package/dist/index.d.mts +117 -0
- package/dist/index.d.ts +84 -295
- package/dist/index.js +618 -1101
- package/dist/index.mjs +143 -550
- package/dist/jsx-dev-runtime.d.mts +22 -0
- package/dist/jsx-dev-runtime.d.ts +6 -5
- package/dist/jsx-dev-runtime.js +453 -695
- package/dist/jsx-dev-runtime.mjs +3 -3
- package/dist/jsx-runtime.d.mts +22 -0
- package/dist/jsx-runtime.d.ts +11 -6
- package/dist/jsx-runtime.js +455 -706
- package/dist/jsx-runtime.mjs +4 -9
- package/dist/theme-BKAb78KP.d.mts +20 -0
- package/dist/theme-BKAb78KP.d.ts +20 -0
- package/dist/vite-plugin.d.mts +20 -147
- package/dist/vite-plugin.d.ts +20 -147
- package/dist/vite-plugin.js +1380 -3722
- package/dist/vite-plugin.mjs +994 -3713
- package/package.json +20 -46
- package/KBACH.md +0 -1044
- package/dist/chunk-KRRGLJLA.mjs +0 -4187
- package/dist/chunk-LIUJPOTS.mjs +0 -208
- package/dist/core/index.d.ts +0 -1346
- package/dist/core/index.js +0 -3712
- package/dist/native.d.ts +0 -314
- package/dist/native.js +0 -99
- package/dist/web-substitute-CfpYFnE7.d.ts +0 -22
- package/jsx-dev-runtime.js +0 -3
- package/jsx-runtime.js +0 -3
- package/kbach-react.md +0 -889
- package/scripts/postinstall.js +0 -28
- package/src/native/babel/index.js +0 -30
- package/src/native/babel-plugin/index.js +0 -605
- package/src/native/babel-plugin/index.test.ts +0 -86
- package/types.d.ts +0 -1
package/dist/vite-plugin.mjs
CHANGED
|
@@ -1,3363 +1,150 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
buildResetCSS,
|
|
3
|
+
defaultTheme
|
|
4
|
+
} from "./chunk-AFY36PRX.mjs";
|
|
5
5
|
|
|
6
|
-
// src/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var _resolveTargetOverride = null;
|
|
10
|
-
function setCSSGenMode(on) {
|
|
11
|
-
_resolveTargetOverride = on ? "web" : null;
|
|
12
|
-
}
|
|
13
|
-
function getEffectiveIsWeb() {
|
|
14
|
-
if (_resolveTargetOverride) return _resolveTargetOverride === "web";
|
|
15
|
-
return isWeb || !isNative;
|
|
16
|
-
}
|
|
17
|
-
function toNativeValue(raw) {
|
|
18
|
-
if (/^-?\d+(\.\d+)?px$/.test(raw)) return parseFloat(raw);
|
|
19
|
-
if (/^-?\d+(\.\d+)?rem$/.test(raw)) return parseFloat(raw) * 16;
|
|
20
|
-
if (/^-?\d+(\.\d+)?em$/.test(raw)) return parseFloat(raw) * 16;
|
|
21
|
-
if (/^-?\d+(\.\d+)?$/.test(raw)) return parseFloat(raw);
|
|
22
|
-
return raw;
|
|
23
|
-
}
|
|
24
|
-
function escapeCSSSelector(cls) {
|
|
25
|
-
return cls.replace(/[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// src/core/reset.ts
|
|
29
|
-
var RESET_STYLE_ID = "kbach-reset";
|
|
30
|
-
var BASE_RESET = [
|
|
31
|
-
// border-style: solid means border-N utilities show a visible border without an extra border-solid class.
|
|
32
|
-
// border-width: 0 keeps all elements borderless by default.
|
|
33
|
-
"*, *::before, *::after { box-sizing: border-box; border-width: 0; border-style: solid; border-color: currentColor; }",
|
|
34
|
-
"body { margin: 0; padding: 0; }",
|
|
35
|
-
"h1, h2, h3, h4, h5, h6 { margin: 0; font-size: inherit; font-weight: inherit; }",
|
|
36
|
-
"p { margin: 0; }",
|
|
37
|
-
"a { color: inherit; text-decoration: none; }",
|
|
38
|
-
"ul, ol { margin: 0; padding: 0; list-style: none; }",
|
|
39
|
-
"img, video, svg { display: block; max-width: 100%; }",
|
|
40
|
-
// appearance: none is deliberately NOT applied to checkbox/radio/select below —
|
|
41
|
-
// stripping it hides their native checkmark/arrow with nothing rendered in its
|
|
42
|
-
// place, leaving an invisible checkbox or an arrow-less <select> that looks like
|
|
43
|
-
// plain text. Text-like inputs, textarea, and button don't have that problem
|
|
44
|
-
// (their native chrome is just a skin around content utilities can fully
|
|
45
|
-
// restyle), so they keep the blank-canvas treatment.
|
|
46
|
-
// :where() wraps the :not() exclusions so they contribute ZERO specificity
|
|
47
|
-
// (unlike a bare `input:not([type='checkbox']):not([type='radio'])`, whose
|
|
48
|
-
// two :not([attr]) clauses each add a class-level specificity point — (0,2,1)
|
|
49
|
-
// total, MORE than any single utility class (0,1,0)). Without :where(), this
|
|
50
|
-
// reset's `color: inherit` always won the cascade over a text-* color
|
|
51
|
-
// utility applied directly to a <input>/<textarea> regardless of source
|
|
52
|
-
// order, since author rules only override on a tie or higher specificity —
|
|
53
|
-
// confirmed on a real app: a TextInput's own text color utility resolved
|
|
54
|
-
// and injected correctly, class and all, but silently never painted.
|
|
55
|
-
"input:where(:not([type='checkbox']):not([type='radio'])), textarea { appearance: none; -webkit-appearance: none; background: transparent; padding: 0; margin: 0; font: inherit; color: inherit; line-height: inherit; }",
|
|
56
|
-
// Native checkbox/radio/range still get typography + spacing normalized, and
|
|
57
|
-
// accent-color re-themes their native indicator to the current text color
|
|
58
|
-
// instead of the browser/OS default blue, so they stay on-brand without
|
|
59
|
-
// needing to be rebuilt from scratch.
|
|
60
|
-
"input[type='checkbox'], input[type='radio'], input[type='range'] { margin: 0; font: inherit; accent-color: currentColor; }",
|
|
61
|
-
// select keeps its native chrome (border/background/arrow are all part of the
|
|
62
|
-
// same OS-drawn widget that appearance: none would blank out) — only typography
|
|
63
|
-
// and spacing are normalized so it still matches surrounding text.
|
|
64
|
-
"select { margin: 0; font: inherit; color: inherit; line-height: inherit; }",
|
|
65
|
-
"button { appearance: none; -webkit-appearance: none; background: transparent; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer; line-height: inherit; text-align: inherit; }",
|
|
66
|
-
"button, [role='button'] { cursor: pointer; }",
|
|
67
|
-
":disabled { cursor: default; }",
|
|
68
|
-
"textarea { resize: vertical; }",
|
|
69
|
-
// Firefox renders placeholders at ~54% opacity by default; every other browser uses 1 —
|
|
70
|
-
// normalize to 1 so placeholder color is consistent and fully controlled by the placeholder: modifier.
|
|
71
|
-
"::placeholder { opacity: 1; }",
|
|
72
|
-
"input[type='number']::-webkit-inner-spin-button, input[type='number']::-webkit-outer-spin-button { margin: 0; }",
|
|
73
|
-
"input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-search-cancel-button { -webkit-appearance: none; }",
|
|
74
|
-
"fieldset { padding: 0; margin: 0; }",
|
|
75
|
-
"table { border-collapse: collapse; border-spacing: 0; }"
|
|
76
|
-
].join("\n");
|
|
77
|
-
|
|
78
|
-
// src/core/theme.ts
|
|
79
|
-
var defaultColors = {
|
|
80
|
-
transparent: "transparent",
|
|
81
|
-
current: "currentColor",
|
|
82
|
-
black: "#000000",
|
|
83
|
-
white: "#ffffff",
|
|
84
|
-
slate: {
|
|
85
|
-
1: "#f8fafc",
|
|
86
|
-
2: "#f1f5f9",
|
|
87
|
-
3: "#e2e8f0",
|
|
88
|
-
4: "#cbd5e1",
|
|
89
|
-
5: "#94a3b8",
|
|
90
|
-
6: "#64748b",
|
|
91
|
-
7: "#475569",
|
|
92
|
-
8: "#334155",
|
|
93
|
-
9: "#1e293b",
|
|
94
|
-
10: "#0f172a",
|
|
95
|
-
11: "#020617",
|
|
96
|
-
12: "#01020a"
|
|
97
|
-
},
|
|
98
|
-
gray: {
|
|
99
|
-
1: "#f9fafb",
|
|
100
|
-
2: "#f3f4f6",
|
|
101
|
-
3: "#e5e7eb",
|
|
102
|
-
4: "#d1d5db",
|
|
103
|
-
5: "#9ca3af",
|
|
104
|
-
6: "#6b7280",
|
|
105
|
-
7: "#4b5563",
|
|
106
|
-
8: "#374151",
|
|
107
|
-
9: "#1f2937",
|
|
108
|
-
10: "#111827",
|
|
109
|
-
11: "#030712",
|
|
110
|
-
12: "#020409"
|
|
111
|
-
},
|
|
112
|
-
zinc: {
|
|
113
|
-
1: "#fafafa",
|
|
114
|
-
2: "#f4f4f5",
|
|
115
|
-
3: "#e4e4e7",
|
|
116
|
-
4: "#d4d4d8",
|
|
117
|
-
5: "#a1a1aa",
|
|
118
|
-
6: "#71717a",
|
|
119
|
-
7: "#52525b",
|
|
120
|
-
8: "#3f3f46",
|
|
121
|
-
9: "#27272a",
|
|
122
|
-
10: "#18181b",
|
|
123
|
-
11: "#09090b",
|
|
124
|
-
12: "#050506"
|
|
125
|
-
},
|
|
126
|
-
neutral: {
|
|
127
|
-
1: "#fafafa",
|
|
128
|
-
2: "#f5f5f5",
|
|
129
|
-
3: "#e5e5e5",
|
|
130
|
-
4: "#d4d4d4",
|
|
131
|
-
5: "#a3a3a3",
|
|
132
|
-
6: "#737373",
|
|
133
|
-
7: "#525252",
|
|
134
|
-
8: "#404040",
|
|
135
|
-
9: "#262626",
|
|
136
|
-
10: "#171717",
|
|
137
|
-
11: "#0a0a0a",
|
|
138
|
-
12: "#050505"
|
|
139
|
-
},
|
|
140
|
-
stone: {
|
|
141
|
-
1: "#fafaf9",
|
|
142
|
-
2: "#f5f5f4",
|
|
143
|
-
3: "#e7e5e4",
|
|
144
|
-
4: "#d6d3d1",
|
|
145
|
-
5: "#a8a29e",
|
|
146
|
-
6: "#78716c",
|
|
147
|
-
7: "#57534e",
|
|
148
|
-
8: "#44403c",
|
|
149
|
-
9: "#292524",
|
|
150
|
-
10: "#1c1917",
|
|
151
|
-
11: "#0c0a09",
|
|
152
|
-
12: "#070605"
|
|
153
|
-
},
|
|
154
|
-
red: {
|
|
155
|
-
1: "#fef2f2",
|
|
156
|
-
2: "#fee2e2",
|
|
157
|
-
3: "#fecaca",
|
|
158
|
-
4: "#fca5a5",
|
|
159
|
-
5: "#f87171",
|
|
160
|
-
6: "#ef4444",
|
|
161
|
-
7: "#dc2626",
|
|
162
|
-
8: "#b91c1c",
|
|
163
|
-
9: "#991b1b",
|
|
164
|
-
10: "#7f1d1d",
|
|
165
|
-
11: "#450a0a",
|
|
166
|
-
12: "#280606"
|
|
167
|
-
},
|
|
168
|
-
orange: {
|
|
169
|
-
1: "#fff7ed",
|
|
170
|
-
2: "#ffedd5",
|
|
171
|
-
3: "#fed7aa",
|
|
172
|
-
4: "#fdba74",
|
|
173
|
-
5: "#fb923c",
|
|
174
|
-
6: "#f97316",
|
|
175
|
-
7: "#ea580c",
|
|
176
|
-
8: "#c2410c",
|
|
177
|
-
9: "#9a3412",
|
|
178
|
-
10: "#7c2d12",
|
|
179
|
-
11: "#431407",
|
|
180
|
-
12: "#270c04"
|
|
181
|
-
},
|
|
182
|
-
amber: {
|
|
183
|
-
1: "#fffbeb",
|
|
184
|
-
2: "#fef3c7",
|
|
185
|
-
3: "#fde68a",
|
|
186
|
-
4: "#fcd34d",
|
|
187
|
-
5: "#fbbf24",
|
|
188
|
-
6: "#f59e0b",
|
|
189
|
-
7: "#d97706",
|
|
190
|
-
8: "#b45309",
|
|
191
|
-
9: "#92400e",
|
|
192
|
-
10: "#78350f",
|
|
193
|
-
11: "#451a03",
|
|
194
|
-
12: "#291002"
|
|
195
|
-
},
|
|
196
|
-
yellow: {
|
|
197
|
-
1: "#fefce8",
|
|
198
|
-
2: "#fef9c3",
|
|
199
|
-
3: "#fef08a",
|
|
200
|
-
4: "#fde047",
|
|
201
|
-
5: "#facc15",
|
|
202
|
-
6: "#eab308",
|
|
203
|
-
7: "#ca8a04",
|
|
204
|
-
8: "#a16207",
|
|
205
|
-
9: "#854d0e",
|
|
206
|
-
10: "#713f12",
|
|
207
|
-
11: "#422006",
|
|
208
|
-
12: "#271304"
|
|
209
|
-
},
|
|
210
|
-
lime: {
|
|
211
|
-
1: "#f7fee7",
|
|
212
|
-
2: "#ecfccb",
|
|
213
|
-
3: "#d9f99d",
|
|
214
|
-
4: "#bef264",
|
|
215
|
-
5: "#a3e635",
|
|
216
|
-
6: "#84cc16",
|
|
217
|
-
7: "#65a30d",
|
|
218
|
-
8: "#4d7c0f",
|
|
219
|
-
9: "#3f6212",
|
|
220
|
-
10: "#365314",
|
|
221
|
-
11: "#1a2e05",
|
|
222
|
-
12: "#0f1b03"
|
|
223
|
-
},
|
|
224
|
-
green: {
|
|
225
|
-
1: "#f0fdf4",
|
|
226
|
-
2: "#dcfce7",
|
|
227
|
-
3: "#bbf7d0",
|
|
228
|
-
4: "#86efac",
|
|
229
|
-
5: "#4ade80",
|
|
230
|
-
6: "#22c55e",
|
|
231
|
-
7: "#16a34a",
|
|
232
|
-
8: "#15803d",
|
|
233
|
-
9: "#166534",
|
|
234
|
-
10: "#14532d",
|
|
235
|
-
11: "#052e16",
|
|
236
|
-
12: "#031b0d"
|
|
237
|
-
},
|
|
238
|
-
emerald: {
|
|
239
|
-
1: "#ecfdf5",
|
|
240
|
-
2: "#d1fae5",
|
|
241
|
-
3: "#a7f3d0",
|
|
242
|
-
4: "#6ee7b7",
|
|
243
|
-
5: "#34d399",
|
|
244
|
-
6: "#10b981",
|
|
245
|
-
7: "#059669",
|
|
246
|
-
8: "#047857",
|
|
247
|
-
9: "#065f46",
|
|
248
|
-
10: "#064e3b",
|
|
249
|
-
11: "#022c22",
|
|
250
|
-
12: "#011a14"
|
|
251
|
-
},
|
|
252
|
-
teal: {
|
|
253
|
-
1: "#f0fdfa",
|
|
254
|
-
2: "#ccfbf1",
|
|
255
|
-
3: "#99f6e4",
|
|
256
|
-
4: "#5eead4",
|
|
257
|
-
5: "#2dd4bf",
|
|
258
|
-
6: "#14b8a6",
|
|
259
|
-
7: "#0d9488",
|
|
260
|
-
8: "#0f766e",
|
|
261
|
-
9: "#115e59",
|
|
262
|
-
10: "#134e4a",
|
|
263
|
-
11: "#042f2e",
|
|
264
|
-
12: "#021c1b"
|
|
265
|
-
},
|
|
266
|
-
cyan: {
|
|
267
|
-
1: "#ecfeff",
|
|
268
|
-
2: "#cffafe",
|
|
269
|
-
3: "#a5f3fc",
|
|
270
|
-
4: "#67e8f9",
|
|
271
|
-
5: "#22d3ee",
|
|
272
|
-
6: "#06b6d4",
|
|
273
|
-
7: "#0891b2",
|
|
274
|
-
8: "#0e7490",
|
|
275
|
-
9: "#155e75",
|
|
276
|
-
10: "#164e63",
|
|
277
|
-
11: "#083344",
|
|
278
|
-
12: "#041e28"
|
|
279
|
-
},
|
|
280
|
-
sky: {
|
|
281
|
-
1: "#f0f9ff",
|
|
282
|
-
2: "#e0f2fe",
|
|
283
|
-
3: "#bae6fd",
|
|
284
|
-
4: "#7dd3fc",
|
|
285
|
-
5: "#38bdf8",
|
|
286
|
-
6: "#0ea5e9",
|
|
287
|
-
7: "#0284c7",
|
|
288
|
-
8: "#0369a1",
|
|
289
|
-
9: "#075985",
|
|
290
|
-
10: "#0c4a6e",
|
|
291
|
-
11: "#082f49",
|
|
292
|
-
12: "#041b2b"
|
|
293
|
-
},
|
|
294
|
-
blue: {
|
|
295
|
-
1: "#eff6ff",
|
|
296
|
-
2: "#dbeafe",
|
|
297
|
-
3: "#bfdbfe",
|
|
298
|
-
4: "#93c5fd",
|
|
299
|
-
5: "#60a5fa",
|
|
300
|
-
6: "#3b82f6",
|
|
301
|
-
7: "#2563eb",
|
|
302
|
-
8: "#1d4ed8",
|
|
303
|
-
9: "#1e40af",
|
|
304
|
-
10: "#1e3a8a",
|
|
305
|
-
11: "#172554",
|
|
306
|
-
12: "#0d1633"
|
|
307
|
-
},
|
|
308
|
-
indigo: {
|
|
309
|
-
1: "#eef2ff",
|
|
310
|
-
2: "#e0e7ff",
|
|
311
|
-
3: "#c7d2fe",
|
|
312
|
-
4: "#a5b4fc",
|
|
313
|
-
5: "#818cf8",
|
|
314
|
-
6: "#6366f1",
|
|
315
|
-
7: "#4f46e5",
|
|
316
|
-
8: "#4338ca",
|
|
317
|
-
9: "#3730a3",
|
|
318
|
-
10: "#312e81",
|
|
319
|
-
11: "#1e1b4b",
|
|
320
|
-
12: "#12102d"
|
|
321
|
-
},
|
|
322
|
-
violet: {
|
|
323
|
-
1: "#f5f3ff",
|
|
324
|
-
2: "#ede9fe",
|
|
325
|
-
3: "#ddd6fe",
|
|
326
|
-
4: "#c4b5fd",
|
|
327
|
-
5: "#a78bfa",
|
|
328
|
-
6: "#8b5cf6",
|
|
329
|
-
7: "#7c3aed",
|
|
330
|
-
8: "#6d28d9",
|
|
331
|
-
9: "#5b21b6",
|
|
332
|
-
10: "#4c1d95",
|
|
333
|
-
11: "#2e1065",
|
|
334
|
-
12: "#1c0a3d"
|
|
335
|
-
},
|
|
336
|
-
purple: {
|
|
337
|
-
1: "#faf5ff",
|
|
338
|
-
2: "#f3e8ff",
|
|
339
|
-
3: "#e9d5ff",
|
|
340
|
-
4: "#d8b4fe",
|
|
341
|
-
5: "#c084fc",
|
|
342
|
-
6: "#a855f7",
|
|
343
|
-
7: "#9333ea",
|
|
344
|
-
8: "#7e22ce",
|
|
345
|
-
9: "#6b21a8",
|
|
346
|
-
10: "#581c87",
|
|
347
|
-
11: "#3b0764",
|
|
348
|
-
12: "#23043c"
|
|
349
|
-
},
|
|
350
|
-
fuchsia: {
|
|
351
|
-
1: "#fdf4ff",
|
|
352
|
-
2: "#fae8ff",
|
|
353
|
-
3: "#f5d0fe",
|
|
354
|
-
4: "#f0abfc",
|
|
355
|
-
5: "#e879f9",
|
|
356
|
-
6: "#d946ef",
|
|
357
|
-
7: "#c026d3",
|
|
358
|
-
8: "#a21caf",
|
|
359
|
-
9: "#86198f",
|
|
360
|
-
10: "#701a75",
|
|
361
|
-
11: "#4a044e",
|
|
362
|
-
12: "#2d022f"
|
|
363
|
-
},
|
|
364
|
-
pink: {
|
|
365
|
-
1: "#fdf2f8",
|
|
366
|
-
2: "#fce7f3",
|
|
367
|
-
3: "#fbcfe8",
|
|
368
|
-
4: "#f9a8d4",
|
|
369
|
-
5: "#f472b6",
|
|
370
|
-
6: "#ec4899",
|
|
371
|
-
7: "#db2777",
|
|
372
|
-
8: "#be185d",
|
|
373
|
-
9: "#9d174d",
|
|
374
|
-
10: "#831843",
|
|
375
|
-
11: "#500724",
|
|
376
|
-
12: "#300415"
|
|
377
|
-
},
|
|
378
|
-
rose: {
|
|
379
|
-
1: "#fff1f2",
|
|
380
|
-
2: "#ffe4e6",
|
|
381
|
-
3: "#fecdd3",
|
|
382
|
-
4: "#fda4af",
|
|
383
|
-
5: "#fb7185",
|
|
384
|
-
6: "#f43f5e",
|
|
385
|
-
7: "#e11d48",
|
|
386
|
-
8: "#be123c",
|
|
387
|
-
9: "#9f1239",
|
|
388
|
-
10: "#881337",
|
|
389
|
-
11: "#4c0519",
|
|
390
|
-
12: "#2d030e"
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
var defaultTheme = {
|
|
394
|
-
colors: defaultColors,
|
|
395
|
-
// 1 unit = 4px
|
|
396
|
-
spacing: {
|
|
397
|
-
px: 1,
|
|
398
|
-
0: 0,
|
|
399
|
-
"0.5": 2,
|
|
400
|
-
1: 4,
|
|
401
|
-
"1.5": 6,
|
|
402
|
-
2: 8,
|
|
403
|
-
"2.5": 10,
|
|
404
|
-
3: 12,
|
|
405
|
-
"3.5": 14,
|
|
406
|
-
4: 16,
|
|
407
|
-
5: 20,
|
|
408
|
-
6: 24,
|
|
409
|
-
7: 28,
|
|
410
|
-
8: 32,
|
|
411
|
-
9: 36,
|
|
412
|
-
10: 40,
|
|
413
|
-
11: 44,
|
|
414
|
-
12: 48,
|
|
415
|
-
14: 56,
|
|
416
|
-
16: 64,
|
|
417
|
-
20: 80,
|
|
418
|
-
24: 96,
|
|
419
|
-
28: 112,
|
|
420
|
-
32: 128,
|
|
421
|
-
36: 144,
|
|
422
|
-
40: 160,
|
|
423
|
-
44: 176,
|
|
424
|
-
48: 192,
|
|
425
|
-
52: 208,
|
|
426
|
-
56: 224,
|
|
427
|
-
60: 240,
|
|
428
|
-
64: 256,
|
|
429
|
-
72: 288,
|
|
430
|
-
80: 320,
|
|
431
|
-
96: 384,
|
|
432
|
-
auto: "auto",
|
|
433
|
-
full: "100%",
|
|
434
|
-
"1/2": "50%",
|
|
435
|
-
"1/3": "33.333333%",
|
|
436
|
-
"2/3": "66.666667%",
|
|
437
|
-
"1/4": "25%",
|
|
438
|
-
"3/4": "75%",
|
|
439
|
-
// Dynamic viewport unit — see the comment on the 'screen' standalone utilities
|
|
440
|
-
// in utilities.ts for why dvh beats vh on mobile. Used by h-screen (w-screen
|
|
441
|
-
// has its own standalone entry so it never reaches this spacing lookup).
|
|
442
|
-
screen: "100dvh",
|
|
443
|
-
min: "min-content",
|
|
444
|
-
max: "max-content",
|
|
445
|
-
fit: "fit-content"
|
|
446
|
-
},
|
|
447
|
-
fontSize: {
|
|
448
|
-
xs: 12,
|
|
449
|
-
sm: 14,
|
|
450
|
-
base: 16,
|
|
451
|
-
lg: 18,
|
|
452
|
-
xl: 20,
|
|
453
|
-
"2xl": 24,
|
|
454
|
-
"3xl": 30,
|
|
455
|
-
"4xl": 36,
|
|
456
|
-
"5xl": 48,
|
|
457
|
-
"6xl": 60,
|
|
458
|
-
"7xl": 72,
|
|
459
|
-
"8xl": 96,
|
|
460
|
-
"9xl": 128
|
|
461
|
-
},
|
|
462
|
-
fontFamily: {
|
|
463
|
-
sans: "System",
|
|
464
|
-
mono: "Courier New",
|
|
465
|
-
serif: "Georgia"
|
|
466
|
-
},
|
|
467
|
-
fontWeight: {
|
|
468
|
-
thin: "100",
|
|
469
|
-
extralight: "200",
|
|
470
|
-
light: "300",
|
|
471
|
-
normal: "400",
|
|
472
|
-
medium: "500",
|
|
473
|
-
semibold: "600",
|
|
474
|
-
bold: "700",
|
|
475
|
-
extrabold: "800",
|
|
476
|
-
black: "900"
|
|
477
|
-
},
|
|
478
|
-
borderRadius: {
|
|
479
|
-
none: 0,
|
|
480
|
-
sm: 2,
|
|
481
|
-
DEFAULT: 4,
|
|
482
|
-
md: 6,
|
|
483
|
-
lg: 8,
|
|
484
|
-
xl: 12,
|
|
485
|
-
"2xl": 16,
|
|
486
|
-
"3xl": 24,
|
|
487
|
-
full: 9999
|
|
488
|
-
},
|
|
489
|
-
borderWidth: {
|
|
490
|
-
DEFAULT: 1,
|
|
491
|
-
0: 0,
|
|
492
|
-
2: 2,
|
|
493
|
-
4: 4,
|
|
494
|
-
8: 8
|
|
495
|
-
},
|
|
496
|
-
opacity: {
|
|
497
|
-
0: 0,
|
|
498
|
-
5: 0.05,
|
|
499
|
-
10: 0.1,
|
|
500
|
-
15: 0.15,
|
|
501
|
-
20: 0.2,
|
|
502
|
-
25: 0.25,
|
|
503
|
-
30: 0.3,
|
|
504
|
-
40: 0.4,
|
|
505
|
-
50: 0.5,
|
|
506
|
-
60: 0.6,
|
|
507
|
-
70: 0.7,
|
|
508
|
-
75: 0.75,
|
|
509
|
-
80: 0.8,
|
|
510
|
-
90: 0.9,
|
|
511
|
-
95: 0.95,
|
|
512
|
-
100: 1
|
|
513
|
-
},
|
|
514
|
-
lineHeight: {
|
|
515
|
-
none: 1,
|
|
516
|
-
tight: 1.25,
|
|
517
|
-
snug: 1.375,
|
|
518
|
-
normal: 1.5,
|
|
519
|
-
relaxed: 1.625,
|
|
520
|
-
loose: 2,
|
|
521
|
-
// Pixel values stored as strings; styleValueToCSS passes them through, toNativeValue strips the unit
|
|
522
|
-
3: "12px",
|
|
523
|
-
4: "16px",
|
|
524
|
-
5: "20px",
|
|
525
|
-
6: "24px",
|
|
526
|
-
7: "28px",
|
|
527
|
-
8: "32px",
|
|
528
|
-
9: "36px",
|
|
529
|
-
10: "40px"
|
|
530
|
-
},
|
|
531
|
-
letterSpacing: {
|
|
532
|
-
tighter: -0.8,
|
|
533
|
-
tight: -0.4,
|
|
534
|
-
normal: 0,
|
|
535
|
-
wide: 0.4,
|
|
536
|
-
wider: 0.8,
|
|
537
|
-
widest: 1.6
|
|
538
|
-
},
|
|
539
|
-
zIndex: {
|
|
540
|
-
auto: "auto",
|
|
541
|
-
0: 0,
|
|
542
|
-
10: 10,
|
|
543
|
-
20: 20,
|
|
544
|
-
30: 30,
|
|
545
|
-
40: 40,
|
|
546
|
-
50: 50
|
|
547
|
-
},
|
|
548
|
-
flex: {
|
|
549
|
-
1: 1,
|
|
550
|
-
auto: "auto",
|
|
551
|
-
// CSS: flex: auto = 1 1 auto; native: mapped to 1 in resolver
|
|
552
|
-
initial: "initial",
|
|
553
|
-
// CSS: flex: initial = 0 1 auto; native: mapped to 1
|
|
554
|
-
none: "none"
|
|
555
|
-
// CSS: flex: none = 0 0 auto; native: mapped to 0
|
|
556
|
-
},
|
|
557
|
-
shadow: {
|
|
558
|
-
sm: {
|
|
559
|
-
shadowColor: "#000",
|
|
560
|
-
shadowOffset: { width: 0, height: 1 },
|
|
561
|
-
shadowOpacity: 0.05,
|
|
562
|
-
shadowRadius: 2,
|
|
563
|
-
elevation: 1
|
|
564
|
-
},
|
|
565
|
-
DEFAULT: {
|
|
566
|
-
shadowColor: "#000",
|
|
567
|
-
shadowOffset: { width: 0, height: 2 },
|
|
568
|
-
shadowOpacity: 0.1,
|
|
569
|
-
shadowRadius: 4,
|
|
570
|
-
elevation: 2
|
|
571
|
-
},
|
|
572
|
-
md: {
|
|
573
|
-
shadowColor: "#000",
|
|
574
|
-
shadowOffset: { width: 0, height: 4 },
|
|
575
|
-
shadowOpacity: 0.1,
|
|
576
|
-
shadowRadius: 8,
|
|
577
|
-
elevation: 3
|
|
578
|
-
},
|
|
579
|
-
lg: {
|
|
580
|
-
shadowColor: "#000",
|
|
581
|
-
shadowOffset: { width: 0, height: 8 },
|
|
582
|
-
shadowOpacity: 0.1,
|
|
583
|
-
shadowRadius: 15,
|
|
584
|
-
elevation: 4
|
|
585
|
-
},
|
|
586
|
-
xl: {
|
|
587
|
-
shadowColor: "#000",
|
|
588
|
-
shadowOffset: { width: 0, height: 16 },
|
|
589
|
-
shadowOpacity: 0.1,
|
|
590
|
-
shadowRadius: 24,
|
|
591
|
-
elevation: 6
|
|
592
|
-
},
|
|
593
|
-
"2xl": {
|
|
594
|
-
shadowColor: "#000",
|
|
595
|
-
shadowOffset: { width: 0, height: 24 },
|
|
596
|
-
shadowOpacity: 0.25,
|
|
597
|
-
shadowRadius: 48,
|
|
598
|
-
elevation: 8
|
|
599
|
-
},
|
|
600
|
-
none: {
|
|
601
|
-
shadowColor: "transparent",
|
|
602
|
-
shadowOffset: { width: 0, height: 0 },
|
|
603
|
-
shadowOpacity: 0,
|
|
604
|
-
shadowRadius: 0,
|
|
605
|
-
elevation: 0
|
|
606
|
-
}
|
|
607
|
-
},
|
|
608
|
-
screens: {
|
|
609
|
-
sm: 576,
|
|
610
|
-
// small tablets / large phones (landscape)
|
|
611
|
-
md: 768,
|
|
612
|
-
// tablets (iPad and up)
|
|
613
|
-
lg: 1024,
|
|
614
|
-
// large tablets (iPad Pro)
|
|
615
|
-
xl: 1280,
|
|
616
|
-
// desktop
|
|
617
|
-
"2xl": 1536
|
|
618
|
-
},
|
|
619
|
-
// Empty by default — the 4 built-in presets (spin/ping/pulse/bounce) are handled
|
|
620
|
-
// directly in the `animate` resolver, not through this theme table. This exists so
|
|
621
|
-
// user-defined ones (kbach.config.js theme.extend.keyframes/animation) merge in
|
|
622
|
-
// alongside them without needing to redeclare the built-ins.
|
|
623
|
-
keyframes: {},
|
|
624
|
-
animation: {}
|
|
625
|
-
};
|
|
626
|
-
|
|
627
|
-
// src/core/colorValue.ts
|
|
628
|
-
function isModeAwareColor(v) {
|
|
629
|
-
return typeof v === "object" && v !== null && "light" in v && "dark" in v;
|
|
630
|
-
}
|
|
631
|
-
function splitColorShadeRef(ref) {
|
|
632
|
-
const lastDash = ref.lastIndexOf("-");
|
|
633
|
-
if (lastDash <= 0) return null;
|
|
634
|
-
return { name: ref.slice(0, lastDash), shade: ref.slice(lastDash + 1) };
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
// src/core/resolvers/color.ts
|
|
638
|
-
function pickModeAwareFallback(v) {
|
|
639
|
-
return isModeAwareColor(v) ? v.light : v;
|
|
640
|
-
}
|
|
641
|
-
function resolveColor(value, colors, isArbitrary) {
|
|
642
|
-
if (isArbitrary) return value;
|
|
643
|
-
const slashIdx = value.indexOf("/");
|
|
644
|
-
const colorPart = slashIdx > 0 ? value.slice(0, slashIdx) : value;
|
|
645
|
-
const opacityPart = slashIdx > 0 ? value.slice(slashIdx + 1) : null;
|
|
646
|
-
let hex = null;
|
|
647
|
-
if (colorPart.startsWith("[") && colorPart.endsWith("]")) {
|
|
648
|
-
hex = colorPart.slice(1, -1);
|
|
649
|
-
} else if (colorPart in colors) {
|
|
650
|
-
const entry = colors[colorPart];
|
|
651
|
-
if (typeof entry === "string") hex = entry;
|
|
652
|
-
else if (isModeAwareColor(entry)) hex = pickModeAwareFallback(entry);
|
|
653
|
-
else if (typeof entry === "object" && "6" in entry) hex = pickModeAwareFallback(entry["6"]);
|
|
654
|
-
} else {
|
|
655
|
-
const split = splitColorShadeRef(colorPart);
|
|
656
|
-
if (split) {
|
|
657
|
-
const scale = colors[split.name];
|
|
658
|
-
if (scale && typeof scale === "object" && !isModeAwareColor(scale) && split.shade in scale) {
|
|
659
|
-
const shadeVal = scale[split.shade];
|
|
660
|
-
hex = shadeVal !== void 0 ? pickModeAwareFallback(shadeVal) : null;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
if (!hex) return null;
|
|
665
|
-
if (!opacityPart) {
|
|
666
|
-
if (!getEffectiveIsWeb() && hex.startsWith("#") && hex.length === 9) {
|
|
667
|
-
return hexToRgba(hex, Math.round(parseInt(hex.slice(7, 9), 16) / 255 * 1e3) / 1e3);
|
|
668
|
-
}
|
|
669
|
-
return hex;
|
|
670
|
-
}
|
|
671
|
-
let alpha;
|
|
672
|
-
if (opacityPart.startsWith("[") && opacityPart.endsWith("]")) {
|
|
673
|
-
const v = parseFloat(opacityPart.slice(1, -1));
|
|
674
|
-
alpha = v > 1 ? v / 100 : v;
|
|
675
|
-
} else {
|
|
676
|
-
alpha = parseFloat(opacityPart) / 100;
|
|
677
|
-
}
|
|
678
|
-
if (isNaN(alpha)) return hex;
|
|
679
|
-
if (alpha < 0) alpha = 0;
|
|
680
|
-
else if (alpha > 1) alpha = 1;
|
|
681
|
-
return hexToRgba(hex, alpha);
|
|
682
|
-
}
|
|
683
|
-
function parseHexRgb(hex) {
|
|
684
|
-
const h = hex.replace("#", "");
|
|
685
|
-
if (h.length === 3 || h.length === 4) {
|
|
686
|
-
return [
|
|
687
|
-
parseInt(h[0] + h[0], 16),
|
|
688
|
-
parseInt(h[1] + h[1], 16),
|
|
689
|
-
parseInt(h[2] + h[2], 16)
|
|
690
|
-
];
|
|
691
|
-
}
|
|
692
|
-
if (h.length === 6 || h.length === 8) {
|
|
693
|
-
return [
|
|
694
|
-
parseInt(h.slice(0, 2), 16),
|
|
695
|
-
parseInt(h.slice(2, 4), 16),
|
|
696
|
-
parseInt(h.slice(4, 6), 16)
|
|
697
|
-
];
|
|
698
|
-
}
|
|
699
|
-
return null;
|
|
700
|
-
}
|
|
701
|
-
function hexToRgba(hex, alpha) {
|
|
702
|
-
const rgb = parseHexRgb(hex);
|
|
703
|
-
if (!rgb) return hex;
|
|
704
|
-
const [r, g, b] = rgb;
|
|
705
|
-
return `rgba(${r},${g},${b},${alpha})`;
|
|
706
|
-
}
|
|
707
|
-
function withOpacityVar(color, varName) {
|
|
708
|
-
if (!color.startsWith("#")) return color;
|
|
709
|
-
const rgb = parseHexRgb(color);
|
|
710
|
-
if (!rgb) return color;
|
|
711
|
-
const [r, g, b] = rgb;
|
|
712
|
-
return `rgba(${r},${g},${b},var(${varName},1))`;
|
|
713
|
-
}
|
|
714
|
-
var colorResolvers = {
|
|
715
|
-
// ── Background ─────────────────────────────────────────────────────────────
|
|
716
|
-
bg: ({ value, isArbitrary }, { colors }) => {
|
|
717
|
-
const color = resolveColor(value, colors, isArbitrary);
|
|
718
|
-
if (!color) return null;
|
|
719
|
-
return { backgroundColor: getEffectiveIsWeb() ? withOpacityVar(color, "--bg-opacity") : color };
|
|
720
|
-
},
|
|
721
|
-
"bg-opacity": ({ value, isArbitrary }, _) => {
|
|
722
|
-
if (!getEffectiveIsWeb()) return null;
|
|
723
|
-
const n = parseFloat(value);
|
|
724
|
-
if (isNaN(n)) return null;
|
|
725
|
-
const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
|
|
726
|
-
return { "--bg-opacity": v };
|
|
727
|
-
},
|
|
728
|
-
// ── Background gradient (CSS variable gradient stops, web-only) ──────────
|
|
729
|
-
"bg-gradient-to": ({ value }) => {
|
|
730
|
-
if (!getEffectiveIsWeb()) return null;
|
|
731
|
-
const directions = {
|
|
732
|
-
t: "to top",
|
|
733
|
-
tr: "to top right",
|
|
734
|
-
r: "to right",
|
|
735
|
-
br: "to bottom right",
|
|
736
|
-
b: "to bottom",
|
|
737
|
-
bl: "to bottom left",
|
|
738
|
-
l: "to left",
|
|
739
|
-
tl: "to top left"
|
|
740
|
-
};
|
|
741
|
-
const dir = directions[value];
|
|
742
|
-
if (!dir) return null;
|
|
743
|
-
return {
|
|
744
|
-
backgroundImage: `linear-gradient(${dir}, var(--kb-gradient-from, transparent), var(--kb-gradient-stops, transparent))`
|
|
745
|
-
};
|
|
746
|
-
},
|
|
747
|
-
from: ({ value, isArbitrary }, { colors }) => {
|
|
748
|
-
if (!getEffectiveIsWeb()) return null;
|
|
749
|
-
const color = resolveColor(value, colors, isArbitrary);
|
|
750
|
-
if (!color) return null;
|
|
751
|
-
return {
|
|
752
|
-
"--kb-gradient-from": color,
|
|
753
|
-
"--kb-gradient-stops": `var(--kb-gradient-from), var(--kb-gradient-to, transparent)`
|
|
754
|
-
};
|
|
755
|
-
},
|
|
756
|
-
via: ({ value, isArbitrary }, { colors }) => {
|
|
757
|
-
if (!getEffectiveIsWeb()) return null;
|
|
758
|
-
const color = resolveColor(value, colors, isArbitrary);
|
|
759
|
-
if (!color) return null;
|
|
760
|
-
return {
|
|
761
|
-
"--kb-gradient-via": color,
|
|
762
|
-
"--kb-gradient-stops": `var(--kb-gradient-from), var(--kb-gradient-via), var(--kb-gradient-to, transparent)`
|
|
763
|
-
};
|
|
764
|
-
},
|
|
765
|
-
to: ({ value, isArbitrary }, { colors }) => {
|
|
766
|
-
if (!getEffectiveIsWeb()) return null;
|
|
767
|
-
const color = resolveColor(value, colors, isArbitrary);
|
|
768
|
-
if (!color) return null;
|
|
769
|
-
return { "--kb-gradient-to": color };
|
|
770
|
-
},
|
|
771
|
-
// ── Tint color (native-only, for Image and icon components) ──────────────
|
|
772
|
-
tint: ({ value, isArbitrary }, { colors }) => {
|
|
773
|
-
if (getEffectiveIsWeb()) return null;
|
|
774
|
-
const color = resolveColor(value, colors, isArbitrary);
|
|
775
|
-
return color ? { tintColor: color } : null;
|
|
776
|
-
},
|
|
777
|
-
// ── Caret color (web-only) ────────────────────────────────────────────────
|
|
778
|
-
caret: ({ value, isArbitrary }, { colors }) => {
|
|
779
|
-
if (!getEffectiveIsWeb()) return null;
|
|
780
|
-
if (value === "auto" || value === "transparent") return { caretColor: value };
|
|
781
|
-
const color = resolveColor(value, colors, isArbitrary);
|
|
782
|
-
return color ? { caretColor: color } : null;
|
|
783
|
-
},
|
|
784
|
-
// ── Accent color (web-only) ───────────────────────────────────────────────
|
|
785
|
-
accent: ({ value, isArbitrary }, { colors }) => {
|
|
786
|
-
if (!getEffectiveIsWeb()) return null;
|
|
787
|
-
if (value === "auto") return { accentColor: "auto" };
|
|
788
|
-
const color = resolveColor(value, colors, isArbitrary);
|
|
789
|
-
return color ? { accentColor: color } : null;
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
|
|
793
|
-
// src/core/resolvers/spacing.ts
|
|
794
|
-
function resolveSpacing(value, negative, spacing, isArbitrary) {
|
|
795
|
-
if (isArbitrary) {
|
|
796
|
-
const resolved = getEffectiveIsWeb() ? value : toNativeValue(value);
|
|
797
|
-
if (negative) {
|
|
798
|
-
if (typeof resolved === "number") return -resolved;
|
|
799
|
-
if (typeof resolved === "string") {
|
|
800
|
-
if (resolved.startsWith("-")) return resolved.slice(1);
|
|
801
|
-
if (/^\d/.test(resolved)) return `-${resolved}`;
|
|
802
|
-
if (/^(calc|var|min|max|clamp|env)\s*\(/.test(resolved)) return `calc(-1 * (${resolved}))`;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
return resolved;
|
|
806
|
-
}
|
|
807
|
-
const raw = spacing[value];
|
|
808
|
-
if (raw === void 0) return null;
|
|
809
|
-
if (typeof raw === "number") return negative ? -raw : raw;
|
|
810
|
-
if (raw === "auto") return "auto";
|
|
811
|
-
if (negative && typeof raw === "string" && raw.endsWith("%")) {
|
|
812
|
-
return `-${raw}`;
|
|
813
|
-
}
|
|
814
|
-
return raw;
|
|
815
|
-
}
|
|
816
|
-
function resolveSizing(value, spacing, isArbitrary) {
|
|
817
|
-
if (isArbitrary) return getEffectiveIsWeb() ? value : toNativeValue(value);
|
|
818
|
-
const raw = spacing[value];
|
|
819
|
-
if (raw !== void 0) return raw;
|
|
820
|
-
if (/^\d+\/\d+$/.test(value)) {
|
|
821
|
-
const [num, den] = value.split("/").map(Number);
|
|
822
|
-
if (!den) return null;
|
|
823
|
-
return `${(num / den * 100).toFixed(6)}%`;
|
|
824
|
-
}
|
|
825
|
-
return null;
|
|
826
|
-
}
|
|
827
|
-
function makeSpacingResolver(prop) {
|
|
828
|
-
return ({ value, negative, isArbitrary }, { spacing }) => {
|
|
829
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
830
|
-
return v !== null ? { [prop]: v } : null;
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
var PADDING_MARGIN_PROPS = {
|
|
834
|
-
p: "padding",
|
|
835
|
-
px: "paddingHorizontal",
|
|
836
|
-
py: "paddingVertical",
|
|
837
|
-
pt: "paddingTop",
|
|
838
|
-
pr: "paddingRight",
|
|
839
|
-
pb: "paddingBottom",
|
|
840
|
-
pl: "paddingLeft",
|
|
841
|
-
m: "margin",
|
|
842
|
-
mx: "marginHorizontal",
|
|
843
|
-
my: "marginVertical",
|
|
844
|
-
mt: "marginTop",
|
|
845
|
-
mr: "marginRight",
|
|
846
|
-
mb: "marginBottom",
|
|
847
|
-
ml: "marginLeft"
|
|
848
|
-
};
|
|
849
|
-
var spacingResolvers = {
|
|
850
|
-
// ── Sizing ─────────────────────────────────────────────────────────────────
|
|
851
|
-
w: ({ value, isArbitrary }, { spacing }) => {
|
|
852
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
853
|
-
return v !== null ? { width: v } : null;
|
|
854
|
-
},
|
|
855
|
-
h: ({ value, isArbitrary }, { spacing }) => {
|
|
856
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
857
|
-
return v !== null ? { height: v } : null;
|
|
858
|
-
},
|
|
859
|
-
"min-w": ({ value, isArbitrary }, { spacing }) => {
|
|
860
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
861
|
-
return v !== null ? { minWidth: v } : null;
|
|
862
|
-
},
|
|
863
|
-
"min-h": ({ value, isArbitrary }, { spacing }) => {
|
|
864
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
865
|
-
return v !== null ? { minHeight: v } : null;
|
|
866
|
-
},
|
|
867
|
-
"max-w": ({ value, isArbitrary }, { spacing }) => {
|
|
868
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
869
|
-
return v !== null ? { maxWidth: v } : null;
|
|
870
|
-
},
|
|
871
|
-
"max-h": ({ value, isArbitrary }, { spacing }) => {
|
|
872
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
873
|
-
return v !== null ? { maxHeight: v } : null;
|
|
874
|
-
},
|
|
875
|
-
// ── Size shorthand (sets width AND height in one utility) ────────────────
|
|
876
|
-
size: ({ value, isArbitrary }, { spacing }) => {
|
|
877
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
878
|
-
return v !== null ? { width: v, height: v } : null;
|
|
879
|
-
},
|
|
880
|
-
// ── Flex basis ─────────────────────────────────────────────────────────────
|
|
881
|
-
basis: ({ value, isArbitrary }, { spacing }) => {
|
|
882
|
-
const v = resolveSizing(value, spacing, isArbitrary);
|
|
883
|
-
return v !== null ? { flexBasis: v } : null;
|
|
884
|
-
},
|
|
885
|
-
// ── Gap ────────────────────────────────────────────────────────────────────
|
|
886
|
-
gap: ({ value, negative, isArbitrary }, { spacing }) => {
|
|
887
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
888
|
-
return v !== null ? { gap: v } : null;
|
|
889
|
-
},
|
|
890
|
-
"gap-x": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
891
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
892
|
-
return v !== null ? { columnGap: v } : null;
|
|
893
|
-
},
|
|
894
|
-
"gap-y": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
895
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
896
|
-
return v !== null ? { rowGap: v } : null;
|
|
897
|
-
},
|
|
898
|
-
// ── Position ───────────────────────────────────────────────────────────────
|
|
899
|
-
top: ({ value, negative, isArbitrary }, { spacing }) => {
|
|
900
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
901
|
-
return v !== null ? { top: v } : null;
|
|
902
|
-
},
|
|
903
|
-
right: ({ value, negative, isArbitrary }, { spacing }) => {
|
|
904
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
905
|
-
return v !== null ? { right: v } : null;
|
|
906
|
-
},
|
|
907
|
-
bottom: ({ value, negative, isArbitrary }, { spacing }) => {
|
|
908
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
909
|
-
return v !== null ? { bottom: v } : null;
|
|
910
|
-
},
|
|
911
|
-
left: ({ value, negative, isArbitrary }, { spacing }) => {
|
|
912
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
913
|
-
return v !== null ? { left: v } : null;
|
|
914
|
-
},
|
|
915
|
-
inset: ({ value, negative, isArbitrary }, { spacing }) => {
|
|
916
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
917
|
-
return v !== null ? { top: v, right: v, bottom: v, left: v } : null;
|
|
918
|
-
},
|
|
919
|
-
"inset-x": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
920
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
921
|
-
return v !== null ? { left: v, right: v } : null;
|
|
922
|
-
},
|
|
923
|
-
"inset-y": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
924
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
925
|
-
return v !== null ? { top: v, bottom: v } : null;
|
|
926
|
-
},
|
|
927
|
-
// ── Translate ──────────────────────────────────────────────────────────────
|
|
928
|
-
"translate-x": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
929
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
930
|
-
if (v === null) return null;
|
|
931
|
-
if (getEffectiveIsWeb()) return { transform: `translateX(${typeof v === "number" ? `${v}px` : v})` };
|
|
932
|
-
if (typeof v === "string") {
|
|
933
|
-
const n = parseFloat(v);
|
|
934
|
-
return isNaN(n) ? null : { transform: [{ translateX: n }] };
|
|
935
|
-
}
|
|
936
|
-
return { transform: [{ translateX: v }] };
|
|
937
|
-
},
|
|
938
|
-
"translate-y": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
939
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
940
|
-
if (v === null) return null;
|
|
941
|
-
if (getEffectiveIsWeb()) return { transform: `translateY(${typeof v === "number" ? `${v}px` : v})` };
|
|
942
|
-
if (typeof v === "string") {
|
|
943
|
-
const n = parseFloat(v);
|
|
944
|
-
return isNaN(n) ? null : { transform: [{ translateY: n }] };
|
|
945
|
-
}
|
|
946
|
-
return { transform: [{ translateY: v }] };
|
|
947
|
-
},
|
|
948
|
-
// ── Space between ─────────────────────────────────────────────────────────
|
|
949
|
-
// On web: emits __spaceX/__spaceY markers → resolver generates > * + * CSS rules.
|
|
950
|
-
// On native (RN 0.71+): uses columnGap/rowGap directly.
|
|
951
|
-
"space-x": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
952
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
953
|
-
if (v === null) return null;
|
|
954
|
-
if (getEffectiveIsWeb()) return { __spaceX: v };
|
|
955
|
-
return { columnGap: v };
|
|
956
|
-
},
|
|
957
|
-
"space-y": ({ value, negative, isArbitrary }, { spacing }) => {
|
|
958
|
-
const v = resolveSpacing(value, negative, spacing, isArbitrary);
|
|
959
|
-
if (v === null) return null;
|
|
960
|
-
if (getEffectiveIsWeb()) return { __spaceY: v };
|
|
961
|
-
return { rowGap: v };
|
|
962
|
-
}
|
|
963
|
-
};
|
|
964
|
-
for (const [utility, prop] of Object.entries(PADDING_MARGIN_PROPS)) {
|
|
965
|
-
spacingResolvers[utility] = makeSpacingResolver(prop);
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// src/core/resolvers/border.ts
|
|
969
|
-
function resolveRadius(value, radii, isArbitrary) {
|
|
970
|
-
if (isArbitrary) return getEffectiveIsWeb() ? value : toNativeValue(value);
|
|
971
|
-
const key = value === "" ? "DEFAULT" : value;
|
|
972
|
-
return radii[key] ?? null;
|
|
973
|
-
}
|
|
974
|
-
function makeBorderSideResolver(widthProp, colorProp) {
|
|
975
|
-
return ({ value, isArbitrary }, { colors, borderWidth }) => {
|
|
976
|
-
if (!value) return { [widthProp]: 1 };
|
|
977
|
-
if (isArbitrary) {
|
|
978
|
-
const w2 = toNativeValue(value);
|
|
979
|
-
if (typeof w2 === "number") return { [widthProp]: getEffectiveIsWeb() ? value : w2 };
|
|
980
|
-
return { [colorProp]: value };
|
|
981
|
-
}
|
|
982
|
-
const color = resolveColor(value, colors, false);
|
|
983
|
-
if (color) return { [colorProp]: color };
|
|
984
|
-
const w = borderWidth[value];
|
|
985
|
-
return w !== void 0 ? { [widthProp]: w } : null;
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
var BORDER_SIDE_PROPS = {
|
|
989
|
-
"border-t": ["borderTopWidth", "borderTopColor"],
|
|
990
|
-
"border-r": ["borderRightWidth", "borderRightColor"],
|
|
991
|
-
"border-b": ["borderBottomWidth", "borderBottomColor"],
|
|
992
|
-
"border-l": ["borderLeftWidth", "borderLeftColor"]
|
|
993
|
-
};
|
|
994
|
-
var borderResolvers = {
|
|
995
|
-
// ── Border width ───────────────────────────────────────────────────────────
|
|
996
|
-
border: ({ value, isArbitrary }, { colors, borderWidth, spacing }) => {
|
|
997
|
-
if (!value) return { borderWidth: borderWidth["DEFAULT"] ?? 1 };
|
|
998
|
-
if (isArbitrary) {
|
|
999
|
-
const w2 = toNativeValue(value);
|
|
1000
|
-
if (typeof w2 === "number") return { borderWidth: getEffectiveIsWeb() ? value : w2 };
|
|
1001
|
-
return { borderColor: value };
|
|
1002
|
-
}
|
|
1003
|
-
const color = resolveColor(value, colors, false);
|
|
1004
|
-
if (color) return { borderColor: color };
|
|
1005
|
-
const w = borderWidth[value] ?? spacing[value];
|
|
1006
|
-
if (w !== void 0) {
|
|
1007
|
-
const numW = typeof w === "number" ? w : parseFloat(String(w));
|
|
1008
|
-
if (isNaN(numW)) return null;
|
|
1009
|
-
return { borderWidth: numW };
|
|
1010
|
-
}
|
|
1011
|
-
return null;
|
|
1012
|
-
},
|
|
1013
|
-
// border-t/-r/-b/-l generated below via makeBorderSideResolver() — see BORDER_SIDE_PROPS.
|
|
1014
|
-
// ── Border radius ──────────────────────────────────────────────────────────
|
|
1015
|
-
rounded: ({ value, isArbitrary }, { borderRadius }) => {
|
|
1016
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1017
|
-
return r !== null ? { borderRadius: r } : null;
|
|
1018
|
-
},
|
|
1019
|
-
"rounded-t": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1020
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1021
|
-
return r !== null ? { borderTopLeftRadius: r, borderTopRightRadius: r } : null;
|
|
1022
|
-
},
|
|
1023
|
-
"rounded-r": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1024
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1025
|
-
return r !== null ? { borderTopRightRadius: r, borderBottomRightRadius: r } : null;
|
|
1026
|
-
},
|
|
1027
|
-
"rounded-b": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1028
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1029
|
-
return r !== null ? { borderBottomLeftRadius: r, borderBottomRightRadius: r } : null;
|
|
1030
|
-
},
|
|
1031
|
-
"rounded-l": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1032
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1033
|
-
return r !== null ? { borderTopLeftRadius: r, borderBottomLeftRadius: r } : null;
|
|
1034
|
-
},
|
|
1035
|
-
"rounded-tl": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1036
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1037
|
-
return r !== null ? { borderTopLeftRadius: r } : null;
|
|
1038
|
-
},
|
|
1039
|
-
"rounded-tr": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1040
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1041
|
-
return r !== null ? { borderTopRightRadius: r } : null;
|
|
1042
|
-
},
|
|
1043
|
-
"rounded-bl": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1044
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1045
|
-
return r !== null ? { borderBottomLeftRadius: r } : null;
|
|
1046
|
-
},
|
|
1047
|
-
"rounded-br": ({ value, isArbitrary }, { borderRadius }) => {
|
|
1048
|
-
const r = resolveRadius(value, borderRadius, isArbitrary);
|
|
1049
|
-
return r !== null ? { borderBottomRightRadius: r } : null;
|
|
1050
|
-
},
|
|
1051
|
-
// ── Outline extended (web-only) ───────────────────────────────────────────
|
|
1052
|
-
outline: ({ value, isArbitrary }, { colors }) => {
|
|
1053
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1054
|
-
if (!value) return { outline: "2px solid transparent", outlineOffset: "2px" };
|
|
1055
|
-
if (value === "none") return { outline: "none", outlineOffset: "0" };
|
|
1056
|
-
if (isArbitrary) {
|
|
1057
|
-
if (/^\d/.test(value) || value.startsWith("calc(")) return { outlineWidth: value };
|
|
1058
|
-
return { outlineColor: value };
|
|
1059
|
-
}
|
|
1060
|
-
const widths = { "0": "0px", "1": "1px", "2": "2px", "4": "4px", "8": "8px" };
|
|
1061
|
-
if (value in widths) return { outlineWidth: widths[value] };
|
|
1062
|
-
const color = resolveColor(value, colors, false);
|
|
1063
|
-
return color ? { outlineColor: color } : null;
|
|
1064
|
-
},
|
|
1065
|
-
"outline-offset": ({ value, isArbitrary }) => {
|
|
1066
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1067
|
-
if (isArbitrary) return { outlineOffset: value };
|
|
1068
|
-
const offsets = { "0": "0px", "1": "1px", "2": "2px", "4": "4px", "8": "8px" };
|
|
1069
|
-
return offsets[value] ? { outlineOffset: offsets[value] } : null;
|
|
1070
|
-
},
|
|
1071
|
-
// ── Divide (child combinator CSS, web-only) ───────────────────────────────
|
|
1072
|
-
// These return special __divide* markers that resolver.ts converts to
|
|
1073
|
-
// .cls > * + * { border-... } CSS rules. No inline style is applied.
|
|
1074
|
-
"divide-x": ({ value, isArbitrary }) => {
|
|
1075
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1076
|
-
if (value === "reverse") return null;
|
|
1077
|
-
if (!value) return { __divideX: 1 };
|
|
1078
|
-
const n = parseFloat(value);
|
|
1079
|
-
return isNaN(n) ? null : { __divideX: n };
|
|
1080
|
-
},
|
|
1081
|
-
"divide-y": ({ value, isArbitrary }) => {
|
|
1082
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1083
|
-
if (value === "reverse") return null;
|
|
1084
|
-
if (!value) return { __divideY: 1 };
|
|
1085
|
-
const n = parseFloat(value);
|
|
1086
|
-
return isNaN(n) ? null : { __divideY: n };
|
|
1087
|
-
},
|
|
1088
|
-
divide: ({ value, isArbitrary }, { colors }) => {
|
|
1089
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1090
|
-
if (isArbitrary) return { __divideColor: value };
|
|
1091
|
-
const styleTokens = {
|
|
1092
|
-
solid: "solid",
|
|
1093
|
-
dashed: "dashed",
|
|
1094
|
-
dotted: "dotted",
|
|
1095
|
-
double: "double",
|
|
1096
|
-
none: "none"
|
|
1097
|
-
};
|
|
1098
|
-
if (value in styleTokens) return { __divideStyle: styleTokens[value] };
|
|
1099
|
-
const color = resolveColor(value, colors, false);
|
|
1100
|
-
return color ? { __divideColor: color } : null;
|
|
1101
|
-
},
|
|
1102
|
-
// ── Ring ───────────────────────────────────────────────────────────────────
|
|
1103
|
-
// Web: box-shadow outline ring (doesn't affect layout).
|
|
1104
|
-
// Native: React Native has no box-shadow, so this falls back to borderWidth/
|
|
1105
|
-
// borderColor — the closest visual approximation (used by other RN Tailwind-
|
|
1106
|
-
// likes for the same reason). Unlike the web ring, this DOES affect layout,
|
|
1107
|
-
// and it shares its properties with the `border` utility — combining
|
|
1108
|
-
// `border-*` and `ring-*` on the same native element means whichever class
|
|
1109
|
-
// comes later wins, since both ultimately set borderWidth/borderColor.
|
|
1110
|
-
ring: ({ value, isArbitrary }, { colors }) => {
|
|
1111
|
-
const onWeb = getEffectiveIsWeb();
|
|
1112
|
-
const DEFAULT_COLOR = "rgba(59, 130, 246, 0.5)";
|
|
1113
|
-
const DEFAULT_WIDTH = 3;
|
|
1114
|
-
const asNative = (w, color2) => w === 0 ? { borderWidth: 0 } : { borderWidth: w, borderColor: color2 };
|
|
1115
|
-
if (!value) {
|
|
1116
|
-
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
1117
|
-
}
|
|
1118
|
-
if (value === "inset") {
|
|
1119
|
-
return onWeb ? { boxShadow: `inset 0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
1120
|
-
}
|
|
1121
|
-
const widthTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
|
|
1122
|
-
if (!isArbitrary && value in widthTokens) {
|
|
1123
|
-
const w = widthTokens[value];
|
|
1124
|
-
return onWeb ? { boxShadow: w === 0 ? "none" : `0 0 0 ${w}px ${DEFAULT_COLOR}` } : asNative(w, DEFAULT_COLOR);
|
|
1125
|
-
}
|
|
1126
|
-
if (isArbitrary) {
|
|
1127
|
-
const numMatch = /^(\d+(?:\.\d+)?)(px|rem|em|vw|vh)?$/.exec(value);
|
|
1128
|
-
if (numMatch) {
|
|
1129
|
-
const unit = numMatch[2] ?? "px";
|
|
1130
|
-
if (onWeb) return { boxShadow: `0 0 0 ${numMatch[1]}${unit} ${DEFAULT_COLOR}` };
|
|
1131
|
-
return unit === "px" ? asNative(parseFloat(numMatch[1]), DEFAULT_COLOR) : null;
|
|
1132
|
-
}
|
|
1133
|
-
return onWeb ? { boxShadow: value.replace(/_/g, " ") } : null;
|
|
1134
|
-
}
|
|
1135
|
-
const color = resolveColor(value, colors, false);
|
|
1136
|
-
if (color) {
|
|
1137
|
-
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${color}` } : asNative(DEFAULT_WIDTH, color);
|
|
1138
|
-
}
|
|
1139
|
-
return null;
|
|
1140
|
-
},
|
|
1141
|
-
// Web-only, unlike `ring` above: this stacks a second box-shadow layer to
|
|
1142
|
-
// create a gap between the element and the ring. There's no native
|
|
1143
|
-
// equivalent to approximate that with (a border can't create a gap outside
|
|
1144
|
-
// its own element without an extra wrapper view), so this stays a no-op
|
|
1145
|
-
// on native rather than rendering a misleading half-translation.
|
|
1146
|
-
"ring-offset": ({ value, isArbitrary }, _theme) => {
|
|
1147
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1148
|
-
const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
|
|
1149
|
-
const DEFAULT_RING_WIDTH = 3;
|
|
1150
|
-
const offsetTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
|
|
1151
|
-
let offsetWidth;
|
|
1152
|
-
if (!isArbitrary) {
|
|
1153
|
-
offsetWidth = value in offsetTokens ? offsetTokens[value] : null;
|
|
1154
|
-
} else {
|
|
1155
|
-
offsetWidth = /^-?\d+(\.\d+)?$/.test(value) ? parseFloat(value) : value;
|
|
1156
|
-
}
|
|
1157
|
-
if (offsetWidth === null || typeof offsetWidth === "number" && isNaN(offsetWidth)) return null;
|
|
1158
|
-
const isZero = offsetWidth === 0 || offsetWidth === "0";
|
|
1159
|
-
const offsetCss = typeof offsetWidth === "number" ? `${offsetWidth}px` : offsetWidth;
|
|
1160
|
-
return {
|
|
1161
|
-
boxShadow: isZero ? `0 0 0 ${DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}` : `0 0 0 ${offsetCss} #fff, 0 0 0 calc(${offsetCss} + ${DEFAULT_RING_WIDTH}px) ${DEFAULT_RING_COLOR}`
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
};
|
|
1165
|
-
for (const [utility, [widthProp, colorProp]] of Object.entries(BORDER_SIDE_PROPS)) {
|
|
1166
|
-
borderResolvers[utility] = makeBorderSideResolver(widthProp, colorProp);
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
// src/core/resolvers/filters.ts
|
|
1170
|
-
var FILTER_COMPOSE = "var(--kb-blur,) var(--kb-brightness,) var(--kb-contrast,) var(--kb-grayscale,) var(--kb-hue-rotate,) var(--kb-invert,) var(--kb-saturate,) var(--kb-sepia,) var(--kb-drop-shadow,)";
|
|
1171
|
-
var BACKDROP_FILTER_COMPOSE = "var(--kb-backdrop-blur,) var(--kb-backdrop-brightness,) var(--kb-backdrop-contrast,) var(--kb-backdrop-grayscale,) var(--kb-backdrop-hue-rotate,) var(--kb-backdrop-invert,) var(--kb-backdrop-opacity,) var(--kb-backdrop-saturate,) var(--kb-backdrop-sepia,)";
|
|
1172
|
-
var filterResolvers = {
|
|
1173
|
-
// ── CSS Filters (composable via CSS variables, web-only) ─────────────────
|
|
1174
|
-
blur: ({ value, isArbitrary }) => {
|
|
1175
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1176
|
-
const sizes = {
|
|
1177
|
-
"": "blur(8px)",
|
|
1178
|
-
sm: "blur(4px)",
|
|
1179
|
-
md: "blur(12px)",
|
|
1180
|
-
lg: "blur(16px)",
|
|
1181
|
-
xl: "blur(24px)",
|
|
1182
|
-
"2xl": "blur(40px)",
|
|
1183
|
-
"3xl": "blur(64px)"
|
|
1184
|
-
};
|
|
1185
|
-
if (value === "none") return { "--kb-blur": "", filter: FILTER_COMPOSE };
|
|
1186
|
-
const v = isArbitrary ? `blur(${value})` : sizes[value];
|
|
1187
|
-
return v !== void 0 ? { "--kb-blur": v, filter: FILTER_COMPOSE } : null;
|
|
1188
|
-
},
|
|
1189
|
-
brightness: ({ value, isArbitrary }) => {
|
|
1190
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1191
|
-
const v = isArbitrary ? `brightness(${value})` : `brightness(${parseFloat(value) / 100})`;
|
|
1192
|
-
return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-brightness": v, filter: FILTER_COMPOSE };
|
|
1193
|
-
},
|
|
1194
|
-
contrast: ({ value, isArbitrary }) => {
|
|
1195
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1196
|
-
const v = isArbitrary ? `contrast(${value})` : `contrast(${parseFloat(value) / 100})`;
|
|
1197
|
-
return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-contrast": v, filter: FILTER_COMPOSE };
|
|
1198
|
-
},
|
|
1199
|
-
grayscale: ({ value, isArbitrary }) => {
|
|
1200
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1201
|
-
const v = isArbitrary ? `grayscale(${value})` : value === "0" ? "grayscale(0)" : "grayscale(100%)";
|
|
1202
|
-
return { "--kb-grayscale": v, filter: FILTER_COMPOSE };
|
|
1203
|
-
},
|
|
1204
|
-
"hue-rotate": ({ value, negative, isArbitrary }) => {
|
|
1205
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1206
|
-
const deg = isArbitrary ? value : `${(negative ? -1 : 1) * parseFloat(value)}deg`;
|
|
1207
|
-
if (isNaN(parseFloat(deg)) && !isArbitrary) return null;
|
|
1208
|
-
return { "--kb-hue-rotate": `hue-rotate(${deg})`, filter: FILTER_COMPOSE };
|
|
1209
|
-
},
|
|
1210
|
-
invert: ({ value, isArbitrary }) => {
|
|
1211
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1212
|
-
const v = isArbitrary ? `invert(${value})` : value === "0" ? "invert(0)" : "invert(100%)";
|
|
1213
|
-
return { "--kb-invert": v, filter: FILTER_COMPOSE };
|
|
1214
|
-
},
|
|
1215
|
-
saturate: ({ value, isArbitrary }) => {
|
|
1216
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1217
|
-
const v = isArbitrary ? `saturate(${value})` : `saturate(${parseFloat(value) / 100})`;
|
|
1218
|
-
return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-saturate": v, filter: FILTER_COMPOSE };
|
|
1219
|
-
},
|
|
1220
|
-
sepia: ({ value, isArbitrary }) => {
|
|
1221
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1222
|
-
const v = isArbitrary ? `sepia(${value})` : value === "0" ? "sepia(0)" : "sepia(100%)";
|
|
1223
|
-
return { "--kb-sepia": v, filter: FILTER_COMPOSE };
|
|
1224
|
-
},
|
|
1225
|
-
"drop-shadow": ({ value, isArbitrary }) => {
|
|
1226
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1227
|
-
if (isArbitrary) return { "--kb-drop-shadow": `drop-shadow(${value.replace(/_/g, " ")})`, filter: FILTER_COMPOSE };
|
|
1228
|
-
const presets = {
|
|
1229
|
-
"": "drop-shadow(0 1px 2px rgb(0 0 0/0.1)) drop-shadow(0 1px 1px rgb(0 0 0/0.06))",
|
|
1230
|
-
sm: "drop-shadow(0 1px 1px rgb(0 0 0/0.05))",
|
|
1231
|
-
md: "drop-shadow(0 4px 3px rgb(0 0 0/0.07)) drop-shadow(0 2px 2px rgb(0 0 0/0.06))",
|
|
1232
|
-
lg: "drop-shadow(0 10px 8px rgb(0 0 0/0.04)) drop-shadow(0 4px 3px rgb(0 0 0/0.1))",
|
|
1233
|
-
xl: "drop-shadow(0 20px 13px rgb(0 0 0/0.03)) drop-shadow(0 8px 5px rgb(0 0 0/0.08))",
|
|
1234
|
-
"2xl": "drop-shadow(0 25px 25px rgb(0 0 0/0.15))",
|
|
1235
|
-
none: "drop-shadow(0 0 #0000)"
|
|
1236
|
-
};
|
|
1237
|
-
const v = presets[value];
|
|
1238
|
-
return v !== void 0 ? { "--kb-drop-shadow": v, filter: FILTER_COMPOSE } : null;
|
|
1239
|
-
},
|
|
1240
|
-
// Arbitrary full filter string: filter-[blur(4px)_grayscale(1)]
|
|
1241
|
-
filter: ({ value, isArbitrary }) => {
|
|
1242
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1243
|
-
if (isArbitrary) return { filter: value.replace(/_/g, " ") };
|
|
1244
|
-
if (value === "none") return { filter: "none" };
|
|
1245
|
-
return null;
|
|
1246
|
-
},
|
|
1247
|
-
// ── Backdrop Filters (composable via CSS variables, web-only) ────────────
|
|
1248
|
-
"backdrop-blur": ({ value, isArbitrary }) => {
|
|
1249
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1250
|
-
const sizes = {
|
|
1251
|
-
"": "blur(8px)",
|
|
1252
|
-
sm: "blur(4px)",
|
|
1253
|
-
md: "blur(12px)",
|
|
1254
|
-
lg: "blur(16px)",
|
|
1255
|
-
xl: "blur(24px)",
|
|
1256
|
-
"2xl": "blur(40px)",
|
|
1257
|
-
"3xl": "blur(64px)"
|
|
1258
|
-
};
|
|
1259
|
-
if (value === "none") return { "--kb-backdrop-blur": "", backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1260
|
-
const v = isArbitrary ? `blur(${value})` : sizes[value];
|
|
1261
|
-
return v !== void 0 ? { "--kb-backdrop-blur": v, backdropFilter: BACKDROP_FILTER_COMPOSE } : null;
|
|
1262
|
-
},
|
|
1263
|
-
"backdrop-brightness": ({ value, isArbitrary }) => {
|
|
1264
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1265
|
-
const v = isArbitrary ? `brightness(${value})` : `brightness(${parseFloat(value) / 100})`;
|
|
1266
|
-
return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-backdrop-brightness": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1267
|
-
},
|
|
1268
|
-
"backdrop-contrast": ({ value, isArbitrary }) => {
|
|
1269
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1270
|
-
const v = isArbitrary ? `contrast(${value})` : `contrast(${parseFloat(value) / 100})`;
|
|
1271
|
-
return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-backdrop-contrast": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1272
|
-
},
|
|
1273
|
-
"backdrop-grayscale": ({ value, isArbitrary }) => {
|
|
1274
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1275
|
-
const v = isArbitrary ? `grayscale(${value})` : value === "0" ? "grayscale(0)" : "grayscale(100%)";
|
|
1276
|
-
return { "--kb-backdrop-grayscale": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1277
|
-
},
|
|
1278
|
-
"backdrop-hue-rotate": ({ value, negative, isArbitrary }) => {
|
|
1279
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1280
|
-
const deg = isArbitrary ? value : `${(negative ? -1 : 1) * parseFloat(value)}deg`;
|
|
1281
|
-
if (isNaN(parseFloat(deg)) && !isArbitrary) return null;
|
|
1282
|
-
return { "--kb-backdrop-hue-rotate": `hue-rotate(${deg})`, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1283
|
-
},
|
|
1284
|
-
"backdrop-invert": ({ value, isArbitrary }) => {
|
|
1285
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1286
|
-
const v = isArbitrary ? `invert(${value})` : value === "0" ? "invert(0)" : "invert(100%)";
|
|
1287
|
-
return { "--kb-backdrop-invert": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1288
|
-
},
|
|
1289
|
-
"backdrop-opacity": ({ value, isArbitrary }) => {
|
|
1290
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1291
|
-
const v = isArbitrary ? `opacity(${value})` : `opacity(${parseFloat(value) / 100})`;
|
|
1292
|
-
return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-backdrop-opacity": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1293
|
-
},
|
|
1294
|
-
"backdrop-saturate": ({ value, isArbitrary }) => {
|
|
1295
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1296
|
-
const v = isArbitrary ? `saturate(${value})` : `saturate(${parseFloat(value) / 100})`;
|
|
1297
|
-
return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-backdrop-saturate": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1298
|
-
},
|
|
1299
|
-
"backdrop-sepia": ({ value, isArbitrary }) => {
|
|
1300
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1301
|
-
const v = isArbitrary ? `sepia(${value})` : value === "0" ? "sepia(0)" : "sepia(100%)";
|
|
1302
|
-
return { "--kb-backdrop-sepia": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
|
|
1303
|
-
},
|
|
1304
|
-
"backdrop-filter": ({ value, isArbitrary }) => {
|
|
1305
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1306
|
-
if (isArbitrary) return { backdropFilter: value.replace(/_/g, " ") };
|
|
1307
|
-
if (value === "none") return { backdropFilter: "none" };
|
|
1308
|
-
return null;
|
|
1309
|
-
},
|
|
1310
|
-
// ── Mix / background blend mode (web-only) ───────────────────────────────
|
|
1311
|
-
"mix-blend": ({ value }) => {
|
|
1312
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1313
|
-
const modes = [
|
|
1314
|
-
"normal",
|
|
1315
|
-
"multiply",
|
|
1316
|
-
"screen",
|
|
1317
|
-
"overlay",
|
|
1318
|
-
"darken",
|
|
1319
|
-
"lighten",
|
|
1320
|
-
"color-dodge",
|
|
1321
|
-
"color-burn",
|
|
1322
|
-
"hard-light",
|
|
1323
|
-
"soft-light",
|
|
1324
|
-
"difference",
|
|
1325
|
-
"exclusion",
|
|
1326
|
-
"hue",
|
|
1327
|
-
"saturation",
|
|
1328
|
-
"color",
|
|
1329
|
-
"luminosity",
|
|
1330
|
-
"plus-lighter"
|
|
1331
|
-
];
|
|
1332
|
-
return modes.includes(value) ? { mixBlendMode: value } : null;
|
|
1333
|
-
},
|
|
1334
|
-
"bg-blend": ({ value }) => {
|
|
1335
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1336
|
-
const modes = [
|
|
1337
|
-
"normal",
|
|
1338
|
-
"multiply",
|
|
1339
|
-
"screen",
|
|
1340
|
-
"overlay",
|
|
1341
|
-
"darken",
|
|
1342
|
-
"lighten",
|
|
1343
|
-
"color-dodge",
|
|
1344
|
-
"color-burn",
|
|
1345
|
-
"hard-light",
|
|
1346
|
-
"soft-light",
|
|
1347
|
-
"difference",
|
|
1348
|
-
"exclusion",
|
|
1349
|
-
"hue",
|
|
1350
|
-
"saturation",
|
|
1351
|
-
"color",
|
|
1352
|
-
"luminosity"
|
|
1353
|
-
];
|
|
1354
|
-
return modes.includes(value) ? { backgroundBlendMode: value } : null;
|
|
1355
|
-
},
|
|
1356
|
-
// ── Will-change (web-only) ─────────────────────────────────────────────────
|
|
1357
|
-
"will-change": ({ value, isArbitrary }) => {
|
|
1358
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1359
|
-
if (isArbitrary) return { willChange: value.replace(/_/g, ", ") };
|
|
1360
|
-
const presets = {
|
|
1361
|
-
auto: "auto",
|
|
1362
|
-
scroll: "scroll-position",
|
|
1363
|
-
contents: "contents",
|
|
1364
|
-
transform: "transform"
|
|
1365
|
-
};
|
|
1366
|
-
return presets[value] ? { willChange: presets[value] } : null;
|
|
1367
|
-
}
|
|
1368
|
-
};
|
|
1369
|
-
|
|
1370
|
-
// src/core/resolvers/layout.ts
|
|
1371
|
-
var _standalone = null;
|
|
1372
|
-
var _standaloneWeb = null;
|
|
1373
|
-
function buildStandalone(web) {
|
|
1374
|
-
return {
|
|
1375
|
-
// Display
|
|
1376
|
-
// React Native only supports display:'flex'|'none'. Setting 'flex' explicitly is
|
|
1377
|
-
// a no-op normally, but is needed to re-show an element that was hidden via `hidden`.
|
|
1378
|
-
// `grid`, `contents`, `flow-root` have no native equivalent and stay null there.
|
|
1379
|
-
// The inline-* family (inline, inline-block, inline-flex, inline-grid) falls back
|
|
1380
|
-
// to 'flex' on native instead — like plain `flex`, this is a no-op most of the
|
|
1381
|
-
// time, but without it these utilities couldn't re-show a `hidden` element on
|
|
1382
|
-
// native either (null → no style applied → still display:'none').
|
|
1383
|
-
flex: { display: "flex" },
|
|
1384
|
-
block: web ? { display: "block" } : null,
|
|
1385
|
-
"inline-block": { display: web ? "inline-block" : "flex" },
|
|
1386
|
-
inline: { display: web ? "inline" : "flex" },
|
|
1387
|
-
grid: web ? { display: "grid" } : null,
|
|
1388
|
-
"inline-flex": { display: web ? "inline-flex" : "flex" },
|
|
1389
|
-
"inline-grid": { display: web ? "inline-grid" : "flex" },
|
|
1390
|
-
hidden: { display: "none" },
|
|
1391
|
-
contents: web ? { display: "contents" } : null,
|
|
1392
|
-
"flow-root": web ? { display: "flow-root" } : null,
|
|
1393
|
-
// Flex direction, wrap, grow/shrink, and alignment (both web and native) —
|
|
1394
|
-
// every one of these is meaningless without the element also being a flex
|
|
1395
|
-
// container. React Native Views are ALWAYS flex containers by default, so
|
|
1396
|
-
// on native this was already true for free; on web a plain <div> defaults
|
|
1397
|
-
// to display:block, so e.g. `items-center` alone silently did nothing.
|
|
1398
|
-
// Folding `display: 'flex'` into these on web closes that native/web gap —
|
|
1399
|
-
// `flex-1 items-center justify-center` now behaves the same on both,
|
|
1400
|
-
// without also needing a separate `flex` class.
|
|
1401
|
-
"flex-row": { flexDirection: "row", ...web ? { display: "flex" } : {} },
|
|
1402
|
-
"flex-col": { flexDirection: "column", ...web ? { display: "flex" } : {} },
|
|
1403
|
-
"flex-row-reverse": { flexDirection: "row-reverse", ...web ? { display: "flex" } : {} },
|
|
1404
|
-
"flex-col-reverse": { flexDirection: "column-reverse", ...web ? { display: "flex" } : {} },
|
|
1405
|
-
// Flex wrap (both)
|
|
1406
|
-
"flex-wrap": { flexWrap: "wrap", ...web ? { display: "flex" } : {} },
|
|
1407
|
-
"flex-wrap-reverse": { flexWrap: "wrap-reverse", ...web ? { display: "flex" } : {} },
|
|
1408
|
-
"flex-nowrap": { flexWrap: "nowrap", ...web ? { display: "flex" } : {} },
|
|
1409
|
-
// Flex grow / shrink (both) — deliberately NOT folding in display:flex
|
|
1410
|
-
// like the container-level properties above. flex-grow/flex-shrink are
|
|
1411
|
-
// item-level: they already take effect purely via the PARENT already
|
|
1412
|
-
// being a flex container, with zero dependency on this element's own
|
|
1413
|
-
// display. Forcing display:flex here would instead be an unrelated side
|
|
1414
|
-
// effect on THIS element's own children (turning what may be an ordinary
|
|
1415
|
-
// block stack into a flex row) — exactly the kind of surprise the
|
|
1416
|
-
// container-level properties above can never cause, since those are
|
|
1417
|
-
// no-ops without display:flex to begin with.
|
|
1418
|
-
"flex-grow": { flexGrow: 1 },
|
|
1419
|
-
"flex-grow-0": { flexGrow: 0 },
|
|
1420
|
-
"flex-shrink": { flexShrink: 1 },
|
|
1421
|
-
"flex-shrink-0": { flexShrink: 0 },
|
|
1422
|
-
// Align items (both)
|
|
1423
|
-
"items-start": { alignItems: "flex-start", ...web ? { display: "flex" } : {} },
|
|
1424
|
-
"items-end": { alignItems: "flex-end", ...web ? { display: "flex" } : {} },
|
|
1425
|
-
"items-center": { alignItems: "center", ...web ? { display: "flex" } : {} },
|
|
1426
|
-
"items-baseline": { alignItems: "baseline", ...web ? { display: "flex" } : {} },
|
|
1427
|
-
"items-stretch": { alignItems: "stretch", ...web ? { display: "flex" } : {} },
|
|
1428
|
-
// Justify content (both)
|
|
1429
|
-
"justify-start": { justifyContent: "flex-start", ...web ? { display: "flex" } : {} },
|
|
1430
|
-
"justify-end": { justifyContent: "flex-end", ...web ? { display: "flex" } : {} },
|
|
1431
|
-
"justify-center": { justifyContent: "center", ...web ? { display: "flex" } : {} },
|
|
1432
|
-
"justify-between": { justifyContent: "space-between", ...web ? { display: "flex" } : {} },
|
|
1433
|
-
"justify-around": { justifyContent: "space-around", ...web ? { display: "flex" } : {} },
|
|
1434
|
-
"justify-evenly": { justifyContent: "space-evenly", ...web ? { display: "flex" } : {} },
|
|
1435
|
-
// Align content (both)
|
|
1436
|
-
"content-start": { alignContent: "flex-start", ...web ? { display: "flex" } : {} },
|
|
1437
|
-
"content-end": { alignContent: "flex-end", ...web ? { display: "flex" } : {} },
|
|
1438
|
-
"content-center": { alignContent: "center", ...web ? { display: "flex" } : {} },
|
|
1439
|
-
"content-between": { alignContent: "space-between", ...web ? { display: "flex" } : {} },
|
|
1440
|
-
"content-around": { alignContent: "space-around", ...web ? { display: "flex" } : {} },
|
|
1441
|
-
"content-evenly": { alignContent: "space-evenly", ...web ? { display: "flex" } : {} },
|
|
1442
|
-
"content-stretch": { alignContent: "stretch", ...web ? { display: "flex" } : {} },
|
|
1443
|
-
// Align self (both)
|
|
1444
|
-
"self-auto": { alignSelf: "auto" },
|
|
1445
|
-
"self-start": { alignSelf: "flex-start" },
|
|
1446
|
-
"self-end": { alignSelf: "flex-end" },
|
|
1447
|
-
"self-center": { alignSelf: "center" },
|
|
1448
|
-
"self-stretch": { alignSelf: "stretch" },
|
|
1449
|
-
"self-baseline": { alignSelf: "baseline" },
|
|
1450
|
-
// Text align (both)
|
|
1451
|
-
"text-left": { textAlign: "left" },
|
|
1452
|
-
"text-right": { textAlign: "right" },
|
|
1453
|
-
"text-center": { textAlign: "center" },
|
|
1454
|
-
"text-justify": { textAlign: "justify" },
|
|
1455
|
-
// Font weight shortcuts (both)
|
|
1456
|
-
"font-thin": { fontWeight: "100" },
|
|
1457
|
-
"font-extralight": { fontWeight: "200" },
|
|
1458
|
-
"font-light": { fontWeight: "300" },
|
|
1459
|
-
"font-normal": { fontWeight: "400" },
|
|
1460
|
-
"font-medium": { fontWeight: "500" },
|
|
1461
|
-
"font-semibold": { fontWeight: "600" },
|
|
1462
|
-
"font-bold": { fontWeight: "700" },
|
|
1463
|
-
"font-extrabold": { fontWeight: "800" },
|
|
1464
|
-
"font-black": { fontWeight: "900" },
|
|
1465
|
-
// Text decoration (overline is web-only)
|
|
1466
|
-
underline: { textDecorationLine: "underline" },
|
|
1467
|
-
overline: web ? { textDecorationLine: "overline" } : null,
|
|
1468
|
-
"line-through": { textDecorationLine: "line-through" },
|
|
1469
|
-
"no-underline": { textDecorationLine: "none" },
|
|
1470
|
-
// Text transform (both)
|
|
1471
|
-
uppercase: { textTransform: "uppercase" },
|
|
1472
|
-
lowercase: { textTransform: "lowercase" },
|
|
1473
|
-
capitalize: { textTransform: "capitalize" },
|
|
1474
|
-
"normal-case": { textTransform: "none" },
|
|
1475
|
-
// Font style (both)
|
|
1476
|
-
italic: { fontStyle: "italic" },
|
|
1477
|
-
"non-italic": { fontStyle: "normal" },
|
|
1478
|
-
// Position (fixed/sticky/static are web-only; RN only supports relative/absolute)
|
|
1479
|
-
relative: { position: "relative" },
|
|
1480
|
-
absolute: { position: "absolute" },
|
|
1481
|
-
fixed: web ? { position: "fixed" } : null,
|
|
1482
|
-
sticky: web ? { position: "sticky" } : null,
|
|
1483
|
-
static: web ? { position: "static" } : null,
|
|
1484
|
-
// Visibility (no `visibility` prop on native; use opacity instead)
|
|
1485
|
-
visible: web ? { visibility: "visible" } : null,
|
|
1486
|
-
invisible: web ? { visibility: "hidden" } : { opacity: 0 },
|
|
1487
|
-
// Overflow (RN supports 'hidden' | 'visible' | 'scroll'; not 'auto')
|
|
1488
|
-
"overflow-hidden": { overflow: "hidden" },
|
|
1489
|
-
"overflow-visible": { overflow: "visible" },
|
|
1490
|
-
"overflow-scroll": { overflow: "scroll" },
|
|
1491
|
-
"overflow-auto": web ? { overflow: "auto" } : { overflow: "scroll" },
|
|
1492
|
-
// overflowX / overflowY are web-only
|
|
1493
|
-
"overflow-x-hidden": web ? { overflowX: "hidden" } : null,
|
|
1494
|
-
"overflow-x-scroll": web ? { overflowX: "scroll" } : null,
|
|
1495
|
-
"overflow-x-auto": web ? { overflowX: "auto" } : null,
|
|
1496
|
-
"overflow-y-hidden": web ? { overflowY: "hidden" } : null,
|
|
1497
|
-
"overflow-y-scroll": web ? { overflowY: "scroll" } : null,
|
|
1498
|
-
"overflow-y-auto": web ? { overflowY: "auto" } : null,
|
|
1499
|
-
// Object fit (web-only; use resizeMode prop on RN Image)
|
|
1500
|
-
"object-contain": web ? { objectFit: "contain" } : null,
|
|
1501
|
-
"object-cover": web ? { objectFit: "cover" } : null,
|
|
1502
|
-
"object-fill": web ? { objectFit: "fill" } : null,
|
|
1503
|
-
"object-none": web ? { objectFit: "none" } : null,
|
|
1504
|
-
"object-scale-down": web ? { objectFit: "scale-down" } : null,
|
|
1505
|
-
// Border style (both)
|
|
1506
|
-
"border-solid": { borderStyle: "solid" },
|
|
1507
|
-
"border-dashed": { borderStyle: "dashed" },
|
|
1508
|
-
"border-dotted": { borderStyle: "dotted" },
|
|
1509
|
-
"border-none": { borderWidth: 0 },
|
|
1510
|
-
// Border sides default width (both)
|
|
1511
|
-
"border-t": { borderTopWidth: 1 },
|
|
1512
|
-
"border-r": { borderRightWidth: 1 },
|
|
1513
|
-
"border-b": { borderBottomWidth: 1 },
|
|
1514
|
-
"border-l": { borderLeftWidth: 1 },
|
|
1515
|
-
// Cursor (web-only)
|
|
1516
|
-
"cursor-auto": web ? { cursor: "auto" } : null,
|
|
1517
|
-
"cursor-default": web ? { cursor: "default" } : null,
|
|
1518
|
-
"cursor-pointer": web ? { cursor: "pointer" } : null,
|
|
1519
|
-
"cursor-wait": web ? { cursor: "wait" } : null,
|
|
1520
|
-
"cursor-text": web ? { cursor: "text" } : null,
|
|
1521
|
-
"cursor-move": web ? { cursor: "move" } : null,
|
|
1522
|
-
"cursor-not-allowed": web ? { cursor: "not-allowed" } : null,
|
|
1523
|
-
// User select (web-only)
|
|
1524
|
-
"select-none": web ? { userSelect: "none" } : null,
|
|
1525
|
-
"select-text": web ? { userSelect: "text" } : null,
|
|
1526
|
-
"select-all": web ? { userSelect: "all" } : null,
|
|
1527
|
-
"select-auto": web ? { userSelect: "auto" } : null,
|
|
1528
|
-
// Pointer events (both)
|
|
1529
|
-
"pointer-events-none": { pointerEvents: "none" },
|
|
1530
|
-
"pointer-events-auto": { pointerEvents: "auto" },
|
|
1531
|
-
// Whitespace (web-only; RN Text uses numberOfLines prop instead)
|
|
1532
|
-
"whitespace-normal": web ? { whiteSpace: "normal" } : null,
|
|
1533
|
-
"whitespace-nowrap": web ? { whiteSpace: "nowrap" } : null,
|
|
1534
|
-
"whitespace-pre": web ? { whiteSpace: "pre" } : null,
|
|
1535
|
-
"whitespace-pre-wrap": web ? { whiteSpace: "pre-wrap" } : null,
|
|
1536
|
-
"whitespace-pre-line": web ? { whiteSpace: "pre-line" } : null,
|
|
1537
|
-
// Word break (web-only)
|
|
1538
|
-
"break-normal": web ? { overflowWrap: "normal", wordBreak: "normal" } : null,
|
|
1539
|
-
"break-words": web ? { overflowWrap: "break-word" } : null,
|
|
1540
|
-
"break-all": web ? { wordBreak: "break-all" } : null,
|
|
1541
|
-
// Misc web-only
|
|
1542
|
-
truncate: web ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } : null,
|
|
1543
|
-
"box-border": web ? { boxSizing: "border-box" } : null,
|
|
1544
|
-
"box-content": web ? { boxSizing: "content-box" } : null,
|
|
1545
|
-
"appearance-none": web ? { appearance: "none" } : null,
|
|
1546
|
-
"outline-none": web ? { outline: "none", outlineOffset: "0" } : null,
|
|
1547
|
-
outline: web ? { outline: "2px solid transparent", outlineOffset: "2px" } : null,
|
|
1548
|
-
resize: web ? { resize: "both" } : null,
|
|
1549
|
-
"resize-none": web ? { resize: "none" } : null,
|
|
1550
|
-
"resize-y": web ? { resize: "vertical" } : null,
|
|
1551
|
-
"resize-x": web ? { resize: "horizontal" } : null,
|
|
1552
|
-
antialiased: web ? { WebkitFontSmoothing: "antialiased", MozOsxFontSmoothing: "grayscale" } : null,
|
|
1553
|
-
"subpixel-antialiased": web ? { WebkitFontSmoothing: "subpixel-antialiased", MozOsxFontSmoothing: "auto" } : null,
|
|
1554
|
-
"overflow-ellipsis": web ? { textOverflow: "ellipsis" } : null,
|
|
1555
|
-
"sr-only": web ? {
|
|
1556
|
-
position: "absolute",
|
|
1557
|
-
width: 1,
|
|
1558
|
-
height: 1,
|
|
1559
|
-
padding: 0,
|
|
1560
|
-
margin: -1,
|
|
1561
|
-
overflow: "hidden",
|
|
1562
|
-
clip: "rect(0,0,0,0)",
|
|
1563
|
-
whiteSpace: "nowrap",
|
|
1564
|
-
border: 0
|
|
1565
|
-
} : null,
|
|
1566
|
-
"not-sr-only": web ? {
|
|
1567
|
-
position: "static",
|
|
1568
|
-
width: "auto",
|
|
1569
|
-
height: "auto",
|
|
1570
|
-
padding: 0,
|
|
1571
|
-
margin: 0,
|
|
1572
|
-
overflow: "visible",
|
|
1573
|
-
clip: "auto",
|
|
1574
|
-
whiteSpace: "normal"
|
|
1575
|
-
} : null,
|
|
1576
|
-
// Lists (web-only)
|
|
1577
|
-
"list-none": web ? { listStyleType: "none" } : null,
|
|
1578
|
-
"list-disc": web ? { listStyleType: "disc" } : null,
|
|
1579
|
-
"list-decimal": web ? { listStyleType: "decimal" } : null,
|
|
1580
|
-
// Background clip (web-only)
|
|
1581
|
-
"bg-clip-border": web ? { backgroundClip: "border-box" } : null,
|
|
1582
|
-
"bg-clip-padding": web ? { backgroundClip: "padding-box" } : null,
|
|
1583
|
-
"bg-clip-content": web ? { backgroundClip: "content-box" } : null,
|
|
1584
|
-
"bg-clip-text": web ? { backgroundClip: "text", WebkitBackgroundClip: "text" } : null,
|
|
1585
|
-
// Background image
|
|
1586
|
-
"bg-none": web ? { backgroundImage: "none" } : null,
|
|
1587
|
-
// Background size (web-only)
|
|
1588
|
-
"bg-auto": web ? { backgroundSize: "auto" } : null,
|
|
1589
|
-
"bg-cover": web ? { backgroundSize: "cover" } : null,
|
|
1590
|
-
"bg-contain": web ? { backgroundSize: "contain" } : null,
|
|
1591
|
-
// Background position (web-only)
|
|
1592
|
-
"bg-center": web ? { backgroundPosition: "center" } : null,
|
|
1593
|
-
"bg-top": web ? { backgroundPosition: "top" } : null,
|
|
1594
|
-
"bg-bottom": web ? { backgroundPosition: "bottom" } : null,
|
|
1595
|
-
"bg-left": web ? { backgroundPosition: "left" } : null,
|
|
1596
|
-
"bg-right": web ? { backgroundPosition: "right" } : null,
|
|
1597
|
-
"bg-left-top": web ? { backgroundPosition: "left top" } : null,
|
|
1598
|
-
"bg-left-bottom": web ? { backgroundPosition: "left bottom" } : null,
|
|
1599
|
-
"bg-right-top": web ? { backgroundPosition: "right top" } : null,
|
|
1600
|
-
"bg-right-bottom": web ? { backgroundPosition: "right bottom" } : null,
|
|
1601
|
-
// Background repeat (web-only)
|
|
1602
|
-
"bg-repeat": web ? { backgroundRepeat: "repeat" } : null,
|
|
1603
|
-
"bg-no-repeat": web ? { backgroundRepeat: "no-repeat" } : null,
|
|
1604
|
-
"bg-repeat-x": web ? { backgroundRepeat: "repeat-x" } : null,
|
|
1605
|
-
"bg-repeat-y": web ? { backgroundRepeat: "repeat-y" } : null,
|
|
1606
|
-
"bg-repeat-round": web ? { backgroundRepeat: "round" } : null,
|
|
1607
|
-
"bg-repeat-space": web ? { backgroundRepeat: "space" } : null,
|
|
1608
|
-
// Background attachment (web-only)
|
|
1609
|
-
"bg-fixed": web ? { backgroundAttachment: "fixed" } : null,
|
|
1610
|
-
"bg-local": web ? { backgroundAttachment: "local" } : null,
|
|
1611
|
-
"bg-scroll": web ? { backgroundAttachment: "scroll" } : null,
|
|
1612
|
-
// Object position (web-only)
|
|
1613
|
-
"object-center": web ? { objectPosition: "center" } : null,
|
|
1614
|
-
"object-top": web ? { objectPosition: "top" } : null,
|
|
1615
|
-
"object-bottom": web ? { objectPosition: "bottom" } : null,
|
|
1616
|
-
"object-left": web ? { objectPosition: "left" } : null,
|
|
1617
|
-
"object-right": web ? { objectPosition: "right" } : null,
|
|
1618
|
-
"object-left-top": web ? { objectPosition: "left top" } : null,
|
|
1619
|
-
"object-left-bottom": web ? { objectPosition: "left bottom" } : null,
|
|
1620
|
-
"object-right-top": web ? { objectPosition: "right top" } : null,
|
|
1621
|
-
"object-right-bottom": web ? { objectPosition: "right bottom" } : null,
|
|
1622
|
-
// Table (web-only)
|
|
1623
|
-
table: web ? { display: "table" } : null,
|
|
1624
|
-
"table-auto": web ? { tableLayout: "auto" } : null,
|
|
1625
|
-
"table-fixed": web ? { tableLayout: "fixed" } : null,
|
|
1626
|
-
"caption-top": web ? { captionSide: "top" } : null,
|
|
1627
|
-
"caption-bottom": web ? { captionSide: "bottom" } : null,
|
|
1628
|
-
"border-collapse": web ? { borderCollapse: "collapse" } : null,
|
|
1629
|
-
"border-separate": web ? { borderCollapse: "separate" } : null,
|
|
1630
|
-
// List style position (web-only)
|
|
1631
|
-
"list-inside": web ? { listStylePosition: "inside" } : null,
|
|
1632
|
-
"list-outside": web ? { listStylePosition: "outside" } : null,
|
|
1633
|
-
// Font variant numeric (web-only)
|
|
1634
|
-
"normal-nums": web ? { fontVariantNumeric: "normal" } : null,
|
|
1635
|
-
ordinal: web ? { fontVariantNumeric: "ordinal" } : null,
|
|
1636
|
-
"slashed-zero": web ? { fontVariantNumeric: "slashed-zero" } : null,
|
|
1637
|
-
"lining-nums": web ? { fontVariantNumeric: "lining-nums" } : null,
|
|
1638
|
-
"oldstyle-nums": web ? { fontVariantNumeric: "oldstyle-nums" } : null,
|
|
1639
|
-
"proportional-nums": web ? { fontVariantNumeric: "proportional-nums" } : null,
|
|
1640
|
-
"tabular-nums": web ? { fontVariantNumeric: "tabular-nums" } : null,
|
|
1641
|
-
"diagonal-fractions": web ? { fontVariantNumeric: "diagonal-fractions" } : null,
|
|
1642
|
-
"stacked-fractions": web ? { fontVariantNumeric: "stacked-fractions" } : null,
|
|
1643
|
-
// Isolation (web-only)
|
|
1644
|
-
isolate: web ? { isolation: "isolate" } : null,
|
|
1645
|
-
"isolation-auto": web ? { isolation: "auto" } : null,
|
|
1646
|
-
// Backface visibility (both iOS and Android)
|
|
1647
|
-
"backface-visible": { backfaceVisibility: "visible" },
|
|
1648
|
-
"backface-hidden": { backfaceVisibility: "hidden" },
|
|
1649
|
-
// CSS filters — standalone = default/full effect (web-only)
|
|
1650
|
-
grayscale: web ? { "--kb-grayscale": "grayscale(100%)", filter: FILTER_COMPOSE } : null,
|
|
1651
|
-
invert: web ? { "--kb-invert": "invert(100%)", filter: FILTER_COMPOSE } : null,
|
|
1652
|
-
sepia: web ? { "--kb-sepia": "sepia(100%)", filter: FILTER_COMPOSE } : null,
|
|
1653
|
-
// Divide none
|
|
1654
|
-
"divide-none": web ? { __divideX: 0, __divideY: 0 } : null,
|
|
1655
|
-
// Group / peer markers (no-op: no style emitted; just ensures isKnownUtility returns true)
|
|
1656
|
-
group: web ? {} : null,
|
|
1657
|
-
peer: web ? {} : null,
|
|
1658
|
-
// Text-wrap (web-only)
|
|
1659
|
-
"text-wrap": web ? { textWrap: "wrap" } : null,
|
|
1660
|
-
"text-nowrap": web ? { textWrap: "nowrap" } : null,
|
|
1661
|
-
"text-balance": web ? { textWrap: "balance" } : null,
|
|
1662
|
-
"text-pretty": web ? { textWrap: "pretty" } : null,
|
|
1663
|
-
// Screen sizing — dvw/dvh (dynamic viewport units) instead of vw/vh: on mobile
|
|
1664
|
-
// browsers, vh/vw are pinned to the LARGEST viewport size (address bar hidden),
|
|
1665
|
-
// so `h-screen` overflows behind the address bar when it's shown. dvh/dvw track
|
|
1666
|
-
// the actual visible viewport as browser chrome shows/hides. Desktop behavior
|
|
1667
|
-
// is unchanged since there's no dynamic chrome to account for.
|
|
1668
|
-
// (vw/dvw values are web-only; vh/dvh values work cross-platform via spacing scale for h-*)
|
|
1669
|
-
"w-screen": web ? { width: "100dvw" } : null,
|
|
1670
|
-
"min-h-screen": { minHeight: "100dvh" },
|
|
1671
|
-
"max-h-screen": { maxHeight: "100dvh" },
|
|
1672
|
-
"min-w-screen": web ? { minWidth: "100dvw" } : null,
|
|
1673
|
-
"max-w-screen": web ? { maxWidth: "100dvw" } : null,
|
|
1674
|
-
// max-w named container sizes (mirrors Tailwind's container scale)
|
|
1675
|
-
"max-w-none": { maxWidth: "none" },
|
|
1676
|
-
"max-w-xs": { maxWidth: 320 },
|
|
1677
|
-
"max-w-sm": { maxWidth: 384 },
|
|
1678
|
-
"max-w-md": { maxWidth: 448 },
|
|
1679
|
-
"max-w-lg": { maxWidth: 512 },
|
|
1680
|
-
"max-w-xl": { maxWidth: 576 },
|
|
1681
|
-
"max-w-2xl": { maxWidth: 672 },
|
|
1682
|
-
"max-w-3xl": { maxWidth: 768 },
|
|
1683
|
-
"max-w-4xl": { maxWidth: 896 },
|
|
1684
|
-
"max-w-5xl": { maxWidth: 1024 },
|
|
1685
|
-
"max-w-6xl": { maxWidth: 1152 },
|
|
1686
|
-
"max-w-7xl": { maxWidth: 1280 },
|
|
1687
|
-
"max-w-prose": web ? { maxWidth: "65ch" } : null,
|
|
1688
|
-
// Extended cursors (web-only)
|
|
1689
|
-
"cursor-grab": web ? { cursor: "grab" } : null,
|
|
1690
|
-
"cursor-grabbing": web ? { cursor: "grabbing" } : null,
|
|
1691
|
-
"cursor-zoom-in": web ? { cursor: "zoom-in" } : null,
|
|
1692
|
-
"cursor-zoom-out": web ? { cursor: "zoom-out" } : null,
|
|
1693
|
-
"cursor-crosshair": web ? { cursor: "crosshair" } : null,
|
|
1694
|
-
"cursor-help": web ? { cursor: "help" } : null,
|
|
1695
|
-
"cursor-none": web ? { cursor: "none" } : null,
|
|
1696
|
-
// Overflow clip (web-only)
|
|
1697
|
-
"overflow-clip": web ? { overflow: "clip" } : null,
|
|
1698
|
-
"overflow-x-clip": web ? { overflowX: "clip" } : null,
|
|
1699
|
-
"overflow-y-clip": web ? { overflowY: "clip" } : null,
|
|
1700
|
-
// Scroll behavior (web-only)
|
|
1701
|
-
"scroll-smooth": web ? { scrollBehavior: "smooth" } : null,
|
|
1702
|
-
"scroll-auto": web ? { scrollBehavior: "auto" } : null,
|
|
1703
|
-
// Float (web-only)
|
|
1704
|
-
"float-left": web ? { float: "left" } : null,
|
|
1705
|
-
"float-right": web ? { float: "right" } : null,
|
|
1706
|
-
"float-start": web ? { float: "inline-start" } : null,
|
|
1707
|
-
"float-end": web ? { float: "inline-end" } : null,
|
|
1708
|
-
"float-none": web ? { float: "none" } : null,
|
|
1709
|
-
// Clear (web-only)
|
|
1710
|
-
"clear-left": web ? { clear: "left" } : null,
|
|
1711
|
-
"clear-right": web ? { clear: "right" } : null,
|
|
1712
|
-
"clear-both": web ? { clear: "both" } : null,
|
|
1713
|
-
"clear-start": web ? { clear: "inline-start" } : null,
|
|
1714
|
-
"clear-end": web ? { clear: "inline-end" } : null,
|
|
1715
|
-
"clear-none": web ? { clear: "none" } : null,
|
|
1716
|
-
// Vertical align (web-only)
|
|
1717
|
-
"align-baseline": web ? { verticalAlign: "baseline" } : null,
|
|
1718
|
-
"align-top": web ? { verticalAlign: "top" } : null,
|
|
1719
|
-
"align-middle": web ? { verticalAlign: "middle" } : null,
|
|
1720
|
-
"align-bottom": web ? { verticalAlign: "bottom" } : null,
|
|
1721
|
-
"align-text-top": web ? { verticalAlign: "text-top" } : null,
|
|
1722
|
-
"align-text-bottom": web ? { verticalAlign: "text-bottom" } : null,
|
|
1723
|
-
"align-sub": web ? { verticalAlign: "sub" } : null,
|
|
1724
|
-
"align-super": web ? { verticalAlign: "super" } : null,
|
|
1725
|
-
// Touch action (web-only)
|
|
1726
|
-
"touch-auto": web ? { touchAction: "auto" } : null,
|
|
1727
|
-
"touch-none": web ? { touchAction: "none" } : null,
|
|
1728
|
-
"touch-pan-x": web ? { touchAction: "pan-x" } : null,
|
|
1729
|
-
"touch-pan-y": web ? { touchAction: "pan-y" } : null,
|
|
1730
|
-
"touch-pan-left": web ? { touchAction: "pan-left" } : null,
|
|
1731
|
-
"touch-pan-right": web ? { touchAction: "pan-right" } : null,
|
|
1732
|
-
"touch-pan-up": web ? { touchAction: "pan-up" } : null,
|
|
1733
|
-
"touch-pan-down": web ? { touchAction: "pan-down" } : null,
|
|
1734
|
-
"touch-pinch-zoom": web ? { touchAction: "pinch-zoom" } : null,
|
|
1735
|
-
"touch-manipulation": web ? { touchAction: "manipulation" } : null
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
function getStandalone() {
|
|
1739
|
-
const web = getEffectiveIsWeb();
|
|
1740
|
-
if (!_standalone || _standaloneWeb !== web) {
|
|
1741
|
-
_standalone = buildStandalone(web);
|
|
1742
|
-
_standaloneWeb = web;
|
|
1743
|
-
}
|
|
1744
|
-
return _standalone;
|
|
1745
|
-
}
|
|
1746
|
-
var layoutResolvers = {
|
|
1747
|
-
// ── Grid (responsive column count: grid-1 … grid-12, or arbitrary) ───────
|
|
1748
|
-
grid: ({ value, isArbitrary }) => {
|
|
1749
|
-
if (!value) return null;
|
|
1750
|
-
if (isArbitrary) return { display: "grid", gridTemplateColumns: value };
|
|
1751
|
-
const n = parseInt(value, 10);
|
|
1752
|
-
if (isNaN(n) || n < 1 || n > 12) return null;
|
|
1753
|
-
return { display: "grid", gridTemplateColumns: `repeat(${n}, minmax(0, 1fr))` };
|
|
1754
|
-
},
|
|
1755
|
-
// ── Grid template columns/rows (Tailwind-style aliases, web-only) ──────────
|
|
1756
|
-
"grid-cols": ({ value, isArbitrary }) => {
|
|
1757
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1758
|
-
if (!value) return null;
|
|
1759
|
-
if (isArbitrary) return { display: "grid", gridTemplateColumns: value };
|
|
1760
|
-
if (value === "none") return { display: "grid", gridTemplateColumns: "none" };
|
|
1761
|
-
const n = parseInt(value, 10);
|
|
1762
|
-
if (isNaN(n) || n < 1 || n > 12) return null;
|
|
1763
|
-
return { display: "grid", gridTemplateColumns: `repeat(${n}, minmax(0, 1fr))` };
|
|
1764
|
-
},
|
|
1765
|
-
"grid-rows": ({ value, isArbitrary }) => {
|
|
1766
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1767
|
-
if (!value) return null;
|
|
1768
|
-
if (isArbitrary) return { gridTemplateRows: value };
|
|
1769
|
-
if (value === "none") return { gridTemplateRows: "none" };
|
|
1770
|
-
const n = parseInt(value, 10);
|
|
1771
|
-
if (isNaN(n) || n < 1) return null;
|
|
1772
|
-
return { gridTemplateRows: `repeat(${n}, minmax(0, 1fr))` };
|
|
1773
|
-
},
|
|
1774
|
-
// ── Grid auto flow (web-only) ─────────────────────────────────────────────
|
|
1775
|
-
"grid-flow": ({ value }) => {
|
|
1776
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1777
|
-
const flows = {
|
|
1778
|
-
row: "row",
|
|
1779
|
-
col: "column",
|
|
1780
|
-
dense: "dense",
|
|
1781
|
-
"row-dense": "row dense",
|
|
1782
|
-
"col-dense": "column dense"
|
|
1783
|
-
};
|
|
1784
|
-
const flow = flows[value];
|
|
1785
|
-
return flow ? { gridAutoFlow: flow } : null;
|
|
1786
|
-
},
|
|
1787
|
-
// ── Grid auto sizing (web-only) ───────────────────────────────────────────
|
|
1788
|
-
"auto-cols": ({ value, isArbitrary }) => {
|
|
1789
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1790
|
-
if (isArbitrary) return { gridAutoColumns: value };
|
|
1791
|
-
const presets = {
|
|
1792
|
-
auto: "auto",
|
|
1793
|
-
min: "min-content",
|
|
1794
|
-
max: "max-content",
|
|
1795
|
-
fr: "minmax(0, 1fr)"
|
|
1796
|
-
};
|
|
1797
|
-
const v = presets[value];
|
|
1798
|
-
return v ? { gridAutoColumns: v } : null;
|
|
1799
|
-
},
|
|
1800
|
-
"auto-rows": ({ value, isArbitrary }) => {
|
|
1801
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1802
|
-
if (isArbitrary) return { gridAutoRows: value };
|
|
1803
|
-
const presets = {
|
|
1804
|
-
auto: "auto",
|
|
1805
|
-
min: "min-content",
|
|
1806
|
-
max: "max-content",
|
|
1807
|
-
fr: "minmax(0, 1fr)"
|
|
1808
|
-
};
|
|
1809
|
-
const v = presets[value];
|
|
1810
|
-
return v ? { gridAutoRows: v } : null;
|
|
1811
|
-
},
|
|
1812
|
-
// ── Grid column placement (web-only) ──────────────────────────────────────
|
|
1813
|
-
"col-span": ({ value }) => {
|
|
1814
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1815
|
-
if (value === "full") return { gridColumn: "1 / -1" };
|
|
1816
|
-
const n = parseInt(value, 10);
|
|
1817
|
-
return isNaN(n) ? null : { gridColumn: `span ${n} / span ${n}` };
|
|
1818
|
-
},
|
|
1819
|
-
"col-start": ({ value, isArbitrary }) => {
|
|
1820
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1821
|
-
if (value === "auto") return { gridColumnStart: "auto" };
|
|
1822
|
-
if (isArbitrary) return { gridColumnStart: value };
|
|
1823
|
-
const n = parseInt(value, 10);
|
|
1824
|
-
return isNaN(n) ? null : { gridColumnStart: n };
|
|
1825
|
-
},
|
|
1826
|
-
"col-end": ({ value, isArbitrary }) => {
|
|
1827
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1828
|
-
if (value === "auto") return { gridColumnEnd: "auto" };
|
|
1829
|
-
if (isArbitrary) return { gridColumnEnd: value };
|
|
1830
|
-
const n = parseInt(value, 10);
|
|
1831
|
-
return isNaN(n) ? null : { gridColumnEnd: n };
|
|
1832
|
-
},
|
|
1833
|
-
col: ({ value, isArbitrary }) => {
|
|
1834
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1835
|
-
if (!value || value === "auto") return { gridColumn: "auto" };
|
|
1836
|
-
if (isArbitrary) return { gridColumn: value };
|
|
1837
|
-
return null;
|
|
1838
|
-
},
|
|
1839
|
-
// ── Grid row placement (web-only) ─────────────────────────────────────────
|
|
1840
|
-
"row-span": ({ value }) => {
|
|
1841
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1842
|
-
if (value === "full") return { gridRow: "1 / -1" };
|
|
1843
|
-
const n = parseInt(value, 10);
|
|
1844
|
-
return isNaN(n) ? null : { gridRow: `span ${n} / span ${n}` };
|
|
1845
|
-
},
|
|
1846
|
-
"row-start": ({ value, isArbitrary }) => {
|
|
1847
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1848
|
-
if (value === "auto") return { gridRowStart: "auto" };
|
|
1849
|
-
if (isArbitrary) return { gridRowStart: value };
|
|
1850
|
-
const n = parseInt(value, 10);
|
|
1851
|
-
return isNaN(n) ? null : { gridRowStart: n };
|
|
1852
|
-
},
|
|
1853
|
-
"row-end": ({ value, isArbitrary }) => {
|
|
1854
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1855
|
-
if (value === "auto") return { gridRowEnd: "auto" };
|
|
1856
|
-
if (isArbitrary) return { gridRowEnd: value };
|
|
1857
|
-
const n = parseInt(value, 10);
|
|
1858
|
-
return isNaN(n) ? null : { gridRowEnd: n };
|
|
1859
|
-
},
|
|
1860
|
-
row: ({ value, isArbitrary }) => {
|
|
1861
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1862
|
-
if (!value || value === "auto") return { gridRow: "auto" };
|
|
1863
|
-
if (isArbitrary) return { gridRow: value };
|
|
1864
|
-
return null;
|
|
1865
|
-
},
|
|
1866
|
-
// ── Grid alignment (web-only) ──────────────────────────────────────────────
|
|
1867
|
-
// place-items is shorthand for align-items + justify-items on a grid container
|
|
1868
|
-
"place-items": ({ value }) => {
|
|
1869
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1870
|
-
const map = {
|
|
1871
|
-
start: "start",
|
|
1872
|
-
end: "end",
|
|
1873
|
-
center: "center",
|
|
1874
|
-
stretch: "stretch",
|
|
1875
|
-
baseline: "baseline"
|
|
1876
|
-
};
|
|
1877
|
-
return map[value] ? { placeItems: map[value] } : null;
|
|
1878
|
-
},
|
|
1879
|
-
// place-content is shorthand for align-content + justify-content on a grid container
|
|
1880
|
-
"place-content": ({ value }) => {
|
|
1881
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1882
|
-
const map = {
|
|
1883
|
-
start: "start",
|
|
1884
|
-
end: "end",
|
|
1885
|
-
center: "center",
|
|
1886
|
-
stretch: "stretch",
|
|
1887
|
-
between: "space-between",
|
|
1888
|
-
around: "space-around",
|
|
1889
|
-
evenly: "space-evenly",
|
|
1890
|
-
baseline: "baseline"
|
|
1891
|
-
};
|
|
1892
|
-
return map[value] ? { placeContent: map[value] } : null;
|
|
1893
|
-
},
|
|
1894
|
-
// justify-items controls inline-axis alignment of grid items within their cells
|
|
1895
|
-
"justify-items": ({ value }) => {
|
|
1896
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1897
|
-
const map = {
|
|
1898
|
-
start: "start",
|
|
1899
|
-
end: "end",
|
|
1900
|
-
center: "center",
|
|
1901
|
-
stretch: "stretch"
|
|
1902
|
-
};
|
|
1903
|
-
return map[value] ? { justifyItems: map[value] } : null;
|
|
1904
|
-
},
|
|
1905
|
-
// place-self is shorthand for align-self + justify-self on a grid item
|
|
1906
|
-
"place-self": ({ value }) => {
|
|
1907
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1908
|
-
const map = {
|
|
1909
|
-
auto: "auto",
|
|
1910
|
-
start: "start",
|
|
1911
|
-
end: "end",
|
|
1912
|
-
center: "center",
|
|
1913
|
-
stretch: "stretch"
|
|
1914
|
-
};
|
|
1915
|
-
return map[value] ? { placeSelf: map[value] } : null;
|
|
1916
|
-
},
|
|
1917
|
-
// justify-self controls inline-axis self-alignment of a grid item
|
|
1918
|
-
"justify-self": ({ value }) => {
|
|
1919
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1920
|
-
const map = {
|
|
1921
|
-
auto: "auto",
|
|
1922
|
-
start: "start",
|
|
1923
|
-
end: "end",
|
|
1924
|
-
center: "center",
|
|
1925
|
-
stretch: "stretch"
|
|
1926
|
-
};
|
|
1927
|
-
return map[value] ? { justifySelf: map[value] } : null;
|
|
1928
|
-
},
|
|
1929
|
-
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
1930
|
-
// flex-1/flex-auto/flex-none/grow/shrink are item-level sizing properties —
|
|
1931
|
-
// deliberately NOT implying display:flex here. See the "Flex grow / shrink"
|
|
1932
|
-
// comment in the standalone table above for why: these already work via the
|
|
1933
|
-
// PARENT's flex context regardless of this element's own display, so
|
|
1934
|
-
// forcing display:flex here would only be a surprising, unrelated side
|
|
1935
|
-
// effect on this element's OWN children.
|
|
1936
|
-
flex: ({ value, isArbitrary }, { flex }) => {
|
|
1937
|
-
if (!value) return { display: "flex" };
|
|
1938
|
-
if (isArbitrary) {
|
|
1939
|
-
const v = parseFloat(value);
|
|
1940
|
-
return isNaN(v) ? null : { flex: v };
|
|
1941
|
-
}
|
|
1942
|
-
if (value in flex) {
|
|
1943
|
-
const v = flex[value];
|
|
1944
|
-
if (typeof v === "string" && !getEffectiveIsWeb()) {
|
|
1945
|
-
if (v === "auto" || v === "initial") return { flex: 1 };
|
|
1946
|
-
if (v === "none") return { flex: 0 };
|
|
1947
|
-
return null;
|
|
1948
|
-
}
|
|
1949
|
-
return { flex: v };
|
|
1950
|
-
}
|
|
1951
|
-
const n = parseFloat(value);
|
|
1952
|
-
return isNaN(n) ? null : { flex: n };
|
|
1953
|
-
},
|
|
1954
|
-
grow: ({ value }, _) => {
|
|
1955
|
-
if (!value) return { flexGrow: 1 };
|
|
1956
|
-
const n = parseFloat(value);
|
|
1957
|
-
return { flexGrow: isNaN(n) ? 1 : n };
|
|
1958
|
-
},
|
|
1959
|
-
shrink: ({ value }, _) => {
|
|
1960
|
-
if (!value) return { flexShrink: 1 };
|
|
1961
|
-
const n = parseFloat(value);
|
|
1962
|
-
return { flexShrink: isNaN(n) ? 1 : n };
|
|
1963
|
-
},
|
|
1964
|
-
order: ({ value, negative }, _) => {
|
|
1965
|
-
const n = parseInt(value, 10);
|
|
1966
|
-
return isNaN(n) ? null : { order: negative ? -n : n };
|
|
1967
|
-
},
|
|
1968
|
-
// ── Z-index ────────────────────────────────────────────────────────────────
|
|
1969
|
-
z: ({ value, isArbitrary }, { zIndex }) => {
|
|
1970
|
-
if (isArbitrary) {
|
|
1971
|
-
const n2 = parseInt(value);
|
|
1972
|
-
return isNaN(n2) ? null : { zIndex: n2 };
|
|
1973
|
-
}
|
|
1974
|
-
const v = zIndex[value];
|
|
1975
|
-
if (v !== void 0) {
|
|
1976
|
-
if (v === "auto") return getEffectiveIsWeb() ? { zIndex: "auto" } : null;
|
|
1977
|
-
return { zIndex: v };
|
|
1978
|
-
}
|
|
1979
|
-
const n = parseInt(value);
|
|
1980
|
-
return isNaN(n) ? null : { zIndex: n };
|
|
1981
|
-
},
|
|
1982
|
-
// ── Aspect ratio ───────────────────────────────────────────────────────────
|
|
1983
|
-
aspect: ({ value, isArbitrary }) => {
|
|
1984
|
-
if (isArbitrary) return { aspectRatio: value };
|
|
1985
|
-
const presets = { auto: "auto", square: 1, video: 16 / 9 };
|
|
1986
|
-
if (!(value in presets)) return null;
|
|
1987
|
-
const v = presets[value];
|
|
1988
|
-
if (v === "auto") return getEffectiveIsWeb() ? { aspectRatio: "auto" } : null;
|
|
1989
|
-
return { aspectRatio: v };
|
|
1990
|
-
},
|
|
1991
|
-
// ── Columns (web-only) ─────────────────────────────────────────────────────
|
|
1992
|
-
columns: ({ value, isArbitrary }) => {
|
|
1993
|
-
if (!getEffectiveIsWeb()) return null;
|
|
1994
|
-
if (isArbitrary) return { columnCount: value };
|
|
1995
|
-
if (value === "auto") return { columnCount: "auto" };
|
|
1996
|
-
const n = parseInt(value, 10);
|
|
1997
|
-
if (!isNaN(n)) return { columnCount: n };
|
|
1998
|
-
const widths = {
|
|
1999
|
-
"3xs": "16rem",
|
|
2000
|
-
"2xs": "18rem",
|
|
2001
|
-
xs: "20rem",
|
|
2002
|
-
sm: "24rem",
|
|
2003
|
-
md: "28rem",
|
|
2004
|
-
lg: "32rem",
|
|
2005
|
-
xl: "36rem",
|
|
2006
|
-
"2xl": "42rem",
|
|
2007
|
-
"3xl": "48rem",
|
|
2008
|
-
"4xl": "56rem",
|
|
2009
|
-
"5xl": "64rem",
|
|
2010
|
-
"6xl": "72rem",
|
|
2011
|
-
"7xl": "80rem"
|
|
2012
|
-
};
|
|
2013
|
-
return widths[value] ? { columnWidth: widths[value] } : null;
|
|
2014
|
-
}
|
|
2015
|
-
};
|
|
2016
|
-
|
|
2017
|
-
// src/core/resolvers/typography.ts
|
|
2018
|
-
function resolveFontSize(value, fontSizes, isArbitrary) {
|
|
2019
|
-
if (isArbitrary) return getEffectiveIsWeb() ? value : toNativeValue(value);
|
|
2020
|
-
return fontSizes[value] ?? null;
|
|
2021
|
-
}
|
|
2022
|
-
var typographyResolvers = {
|
|
2023
|
-
// ── Text ───────────────────────────────────────────────────────────────────
|
|
2024
|
-
text: ({ value, isArbitrary }, { colors, fontSize }) => {
|
|
2025
|
-
const size = resolveFontSize(value, fontSize, false);
|
|
2026
|
-
if (!isArbitrary && size !== null) return { fontSize: size };
|
|
2027
|
-
if (isArbitrary) {
|
|
2028
|
-
if (/^\d/.test(value) || /^(calc|min|max|clamp)/.test(value)) {
|
|
2029
|
-
return { fontSize: getEffectiveIsWeb() ? value : toNativeValue(value) };
|
|
2030
|
-
}
|
|
2031
|
-
return { color: getEffectiveIsWeb() ? withOpacityVar(value, "--text-opacity") : value };
|
|
2032
|
-
}
|
|
2033
|
-
const color = resolveColor(value, colors, false);
|
|
2034
|
-
if (!color) return null;
|
|
2035
|
-
return { color: getEffectiveIsWeb() ? withOpacityVar(color, "--text-opacity") : color };
|
|
2036
|
-
},
|
|
2037
|
-
"text-opacity": ({ value, isArbitrary }, _) => {
|
|
2038
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2039
|
-
const n = parseFloat(value);
|
|
2040
|
-
if (isNaN(n)) return null;
|
|
2041
|
-
const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
|
|
2042
|
-
return { "--text-opacity": v };
|
|
2043
|
-
},
|
|
2044
|
-
// ── Text decoration advanced (web-only) ───────────────────────────────────
|
|
2045
|
-
decoration: ({ value, isArbitrary }, { colors }) => {
|
|
2046
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2047
|
-
if (isArbitrary) {
|
|
2048
|
-
if (/^\d/.test(value) || value.startsWith("calc(")) return { textDecorationThickness: value };
|
|
2049
|
-
return { textDecorationColor: value };
|
|
2050
|
-
}
|
|
2051
|
-
const thickTokens = {
|
|
2052
|
-
auto: "auto",
|
|
2053
|
-
"from-font": "from-font",
|
|
2054
|
-
"0": "0px",
|
|
2055
|
-
"1": "1px",
|
|
2056
|
-
"2": "2px",
|
|
2057
|
-
"4": "4px",
|
|
2058
|
-
"8": "8px"
|
|
2059
|
-
};
|
|
2060
|
-
if (value in thickTokens) return { textDecorationThickness: thickTokens[value] };
|
|
2061
|
-
const styleTokens = {
|
|
2062
|
-
solid: "solid",
|
|
2063
|
-
dashed: "dashed",
|
|
2064
|
-
dotted: "dotted",
|
|
2065
|
-
double: "double",
|
|
2066
|
-
wavy: "wavy"
|
|
2067
|
-
};
|
|
2068
|
-
if (value in styleTokens) return { textDecorationStyle: styleTokens[value] };
|
|
2069
|
-
const color = resolveColor(value, colors, false);
|
|
2070
|
-
return color ? { textDecorationColor: color } : null;
|
|
2071
|
-
},
|
|
2072
|
-
"underline-offset": ({ value, isArbitrary }) => {
|
|
2073
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2074
|
-
if (isArbitrary) return { textUnderlineOffset: value };
|
|
2075
|
-
const offsets = {
|
|
2076
|
-
auto: "auto",
|
|
2077
|
-
"0": "0px",
|
|
2078
|
-
"1": "1px",
|
|
2079
|
-
"2": "2px",
|
|
2080
|
-
"4": "4px",
|
|
2081
|
-
"8": "8px"
|
|
2082
|
-
};
|
|
2083
|
-
return offsets[value] ? { textUnderlineOffset: offsets[value] } : null;
|
|
2084
|
-
},
|
|
2085
|
-
// ── Content (web-only — for before:/after: pseudo-elements, which don't exist on native) ──
|
|
2086
|
-
// Arbitrary value carries its own quotes from the bracket syntax (content-['*'] parses to
|
|
2087
|
-
// the literal string 'you can see it' quotes included), so it passes straight through as a
|
|
2088
|
-
// valid `content: '*'` CSS value with no extra wrapping needed.
|
|
2089
|
-
content: ({ value, isArbitrary }) => {
|
|
2090
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2091
|
-
if (isArbitrary) return { content: value };
|
|
2092
|
-
const presets = { none: "none" };
|
|
2093
|
-
return value in presets ? { content: presets[value] } : null;
|
|
2094
|
-
},
|
|
2095
|
-
// ── Font ───────────────────────────────────────────────────────────────────
|
|
2096
|
-
font: ({ value, isArbitrary }, { fontFamily, fontWeight }) => {
|
|
2097
|
-
if (isArbitrary) return { fontFamily: value };
|
|
2098
|
-
if (value in fontFamily) {
|
|
2099
|
-
const ff = fontFamily[value];
|
|
2100
|
-
return { fontFamily: Array.isArray(ff) ? ff.join(", ") : ff };
|
|
2101
|
-
}
|
|
2102
|
-
if (value in fontWeight) return { fontWeight: String(fontWeight[value]) };
|
|
2103
|
-
return null;
|
|
2104
|
-
},
|
|
2105
|
-
// ── Line height ────────────────────────────────────────────────────────────
|
|
2106
|
-
leading: ({ value, isArbitrary }, { lineHeight }) => {
|
|
2107
|
-
if (isArbitrary) return { lineHeight: getEffectiveIsWeb() ? value : toNativeValue(value) };
|
|
2108
|
-
const v = lineHeight[value];
|
|
2109
|
-
if (v === void 0) return null;
|
|
2110
|
-
if (typeof v === "string" && !getEffectiveIsWeb()) return { lineHeight: toNativeValue(v) };
|
|
2111
|
-
return { lineHeight: v };
|
|
2112
|
-
},
|
|
2113
|
-
// ── Letter spacing ─────────────────────────────────────────────────────────
|
|
2114
|
-
tracking: ({ value, isArbitrary }, { letterSpacing }) => {
|
|
2115
|
-
if (isArbitrary) return { letterSpacing: getEffectiveIsWeb() ? value : toNativeValue(value) };
|
|
2116
|
-
const v = letterSpacing[value];
|
|
2117
|
-
return v !== void 0 ? { letterSpacing: v } : null;
|
|
2118
|
-
},
|
|
2119
|
-
// ── Line-clamp (web-only) ─────────────────────────────────────────────────
|
|
2120
|
-
"line-clamp": ({ value }) => {
|
|
2121
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2122
|
-
if (value === "none") return { overflow: "visible", display: "block", WebkitLineClamp: "unset" };
|
|
2123
|
-
const n = parseInt(value, 10);
|
|
2124
|
-
if (isNaN(n) || n < 1) return null;
|
|
2125
|
-
return {
|
|
2126
|
-
overflow: "hidden",
|
|
2127
|
-
display: "-webkit-box",
|
|
2128
|
-
WebkitBoxOrient: "vertical",
|
|
2129
|
-
WebkitLineClamp: n
|
|
2130
|
-
};
|
|
2131
|
-
}
|
|
2132
|
-
};
|
|
2133
|
-
|
|
2134
|
-
// src/core/resolvers/transform.ts
|
|
2135
|
-
var transformResolvers = {
|
|
2136
|
-
// ── Transform extras (web-only) ───────────────────────────────────────────
|
|
2137
|
-
"skew-x": ({ value, negative, isArbitrary }) => {
|
|
2138
|
-
const deg = isArbitrary ? value : `${(negative ? -1 : 1) * parseFloat(value)}deg`;
|
|
2139
|
-
if (!isArbitrary && isNaN(parseFloat(value))) return null;
|
|
2140
|
-
return getEffectiveIsWeb() ? { transform: `skewX(${deg})` } : { transform: [{ skewX: deg }] };
|
|
2141
|
-
},
|
|
2142
|
-
"skew-y": ({ value, negative, isArbitrary }) => {
|
|
2143
|
-
const deg = isArbitrary ? value : `${(negative ? -1 : 1) * parseFloat(value)}deg`;
|
|
2144
|
-
if (!isArbitrary && isNaN(parseFloat(value))) return null;
|
|
2145
|
-
return getEffectiveIsWeb() ? { transform: `skewY(${deg})` } : { transform: [{ skewY: deg }] };
|
|
2146
|
-
},
|
|
2147
|
-
// Arbitrary full transform string: transform-[rotate(45deg)_scale(1.5)]
|
|
2148
|
-
transform: ({ value, isArbitrary }) => {
|
|
2149
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2150
|
-
if (isArbitrary) return { transform: value.replace(/_/g, " ") };
|
|
2151
|
-
if (value === "none") return { transform: "none" };
|
|
2152
|
-
return null;
|
|
2153
|
-
},
|
|
2154
|
-
// Transform origin
|
|
2155
|
-
origin: ({ value, isArbitrary }) => {
|
|
2156
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2157
|
-
if (isArbitrary) return { transformOrigin: value.replace(/_/g, " ") };
|
|
2158
|
-
const origins = {
|
|
2159
|
-
center: "center",
|
|
2160
|
-
top: "top",
|
|
2161
|
-
"top-right": "top right",
|
|
2162
|
-
right: "right",
|
|
2163
|
-
"bottom-right": "bottom right",
|
|
2164
|
-
bottom: "bottom",
|
|
2165
|
-
"bottom-left": "bottom left",
|
|
2166
|
-
left: "left",
|
|
2167
|
-
"top-left": "top left"
|
|
2168
|
-
};
|
|
2169
|
-
return origins[value] ? { transformOrigin: origins[value] } : null;
|
|
2170
|
-
},
|
|
2171
|
-
// ── Scale ──────────────────────────────────────────────────────────────────
|
|
2172
|
-
// Non-arbitrary: scale-150 → value='150' → 150/100 = 1.5
|
|
2173
|
-
// Arbitrary: scale-[1.5] → value='1.5' → used as-is (already the factor)
|
|
2174
|
-
scale: ({ value, isArbitrary }) => {
|
|
2175
|
-
const n = isArbitrary ? parseFloat(value) : parseFloat(value) / 100;
|
|
2176
|
-
if (isNaN(n)) return null;
|
|
2177
|
-
return getEffectiveIsWeb() ? { transform: `scale(${n})` } : { transform: [{ scale: n }] };
|
|
2178
|
-
},
|
|
2179
|
-
"scale-x": ({ value, isArbitrary }) => {
|
|
2180
|
-
const n = isArbitrary ? parseFloat(value) : parseFloat(value) / 100;
|
|
2181
|
-
if (isNaN(n)) return null;
|
|
2182
|
-
return getEffectiveIsWeb() ? { transform: `scaleX(${n})` } : { transform: [{ scaleX: n }] };
|
|
2183
|
-
},
|
|
2184
|
-
"scale-y": ({ value, isArbitrary }) => {
|
|
2185
|
-
const n = isArbitrary ? parseFloat(value) : parseFloat(value) / 100;
|
|
2186
|
-
if (isNaN(n)) return null;
|
|
2187
|
-
return getEffectiveIsWeb() ? { transform: `scaleY(${n})` } : { transform: [{ scaleY: n }] };
|
|
2188
|
-
},
|
|
2189
|
-
// ── Rotate ─────────────────────────────────────────────────────────────────
|
|
2190
|
-
rotate: ({ value, negative, isArbitrary }) => {
|
|
2191
|
-
if (isArbitrary) {
|
|
2192
|
-
const finalValue = negative ? `-${value}` : value;
|
|
2193
|
-
return getEffectiveIsWeb() ? { transform: `rotate(${finalValue})` } : { transform: [{ rotate: finalValue }] };
|
|
2194
|
-
}
|
|
2195
|
-
const deg = parseFloat(value);
|
|
2196
|
-
if (isNaN(deg)) return null;
|
|
2197
|
-
const finalDeg = negative ? -deg : deg;
|
|
2198
|
-
return getEffectiveIsWeb() ? { transform: `rotate(${finalDeg}deg)` } : { transform: [{ rotate: `${finalDeg}deg` }] };
|
|
2199
|
-
},
|
|
2200
|
-
// ── Perspective transform (cross-platform: iOS, Android, web) ────────────
|
|
2201
|
-
perspective: ({ value, isArbitrary }) => {
|
|
2202
|
-
if (isArbitrary) {
|
|
2203
|
-
const numPx = parseFloat(value);
|
|
2204
|
-
if (getEffectiveIsWeb()) return { transform: `perspective(${value})` };
|
|
2205
|
-
return isNaN(numPx) ? null : { transform: [{ perspective: numPx }] };
|
|
2206
|
-
}
|
|
2207
|
-
if (value === "none") return getEffectiveIsWeb() ? { transform: "none" } : null;
|
|
2208
|
-
const n = parseFloat(value);
|
|
2209
|
-
if (isNaN(n)) return null;
|
|
2210
|
-
return getEffectiveIsWeb() ? { transform: `perspective(${n}px)` } : { transform: [{ perspective: n }] };
|
|
2211
|
-
}
|
|
2212
|
-
};
|
|
2213
|
-
|
|
2214
|
-
// src/core/resolvers/effects.ts
|
|
2215
|
-
function keyframeDeclToCSS(decl) {
|
|
2216
|
-
return Object.entries(decl).map(([prop, val]) => `${prop.replace(/([A-Z])/g, "-$1").toLowerCase()}: ${val}`).join("; ");
|
|
2217
|
-
}
|
|
2218
|
-
function buildKeyframeCSS(name, steps) {
|
|
2219
|
-
const body = Object.entries(steps).map(([selector, decl]) => `${selector} { ${keyframeDeclToCSS(decl)} }`).join(" ");
|
|
2220
|
-
return `@keyframes ${name} { ${body} }`;
|
|
2221
|
-
}
|
|
2222
|
-
var BUILTIN_ANIMATIONS = {
|
|
2223
|
-
none: { animation: "none" },
|
|
2224
|
-
spin: {
|
|
2225
|
-
animation: "kb-spin 1s linear infinite",
|
|
2226
|
-
__keyframe: "@keyframes kb-spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } }"
|
|
2227
|
-
},
|
|
2228
|
-
ping: {
|
|
2229
|
-
animation: "kb-ping 1s cubic-bezier(0,0,0.2,1) infinite",
|
|
2230
|
-
__keyframe: "@keyframes kb-ping { 75%, 100% { transform: scale(2); opacity: 0 } }"
|
|
2231
|
-
},
|
|
2232
|
-
pulse: {
|
|
2233
|
-
animation: "kb-pulse 2s cubic-bezier(0.4,0,0.6,1) infinite",
|
|
2234
|
-
__keyframe: "@keyframes kb-pulse { 0%, 100% { opacity: 1 } 50% { opacity: .5 } }"
|
|
2235
|
-
},
|
|
2236
|
-
bounce: {
|
|
2237
|
-
animation: "kb-bounce 1s infinite",
|
|
2238
|
-
__keyframe: "@keyframes kb-bounce { 0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8,0,1,1) } 50% { transform: none; animation-timing-function: cubic-bezier(0,0,0.2,1) } }"
|
|
2239
|
-
}
|
|
2240
|
-
};
|
|
2241
|
-
function buildAnimationValue(animation, keyframes) {
|
|
2242
|
-
const words = animation.trim().split(/\s+/);
|
|
2243
|
-
const name = words[0];
|
|
2244
|
-
if (!name) return { animation };
|
|
2245
|
-
const builtin = BUILTIN_ANIMATIONS[name];
|
|
2246
|
-
if (builtin?.__keyframe) {
|
|
2247
|
-
const kbName = builtin.animation.split(/\s+/, 1)[0];
|
|
2248
|
-
return { animation: [kbName, ...words.slice(1)].join(" "), __keyframe: builtin.__keyframe };
|
|
2249
|
-
}
|
|
2250
|
-
const steps = keyframes?.[name];
|
|
2251
|
-
return steps ? { animation, __keyframe: buildKeyframeCSS(name, steps) } : { animation };
|
|
2252
|
-
}
|
|
2253
|
-
var effectResolvers = {
|
|
2254
|
-
// ── Opacity ────────────────────────────────────────────────────────────────
|
|
2255
|
-
opacity: ({ value, isArbitrary }, { opacity }) => {
|
|
2256
|
-
if (isArbitrary) {
|
|
2257
|
-
const v2 = parseFloat(value);
|
|
2258
|
-
return isNaN(v2) ? null : { opacity: v2 > 1 ? v2 / 100 : v2 };
|
|
2259
|
-
}
|
|
2260
|
-
const v = opacity[value];
|
|
2261
|
-
if (v !== void 0) return { opacity: v };
|
|
2262
|
-
const n = parseFloat(value);
|
|
2263
|
-
return isNaN(n) ? null : { opacity: n > 1 ? n / 100 : n };
|
|
2264
|
-
},
|
|
2265
|
-
// ── Shadow ─────────────────────────────────────────────────────────────────
|
|
2266
|
-
shadow: ({ value }, { shadow }) => {
|
|
2267
|
-
const key = value === "" ? "DEFAULT" : value;
|
|
2268
|
-
return shadow[key] ?? null;
|
|
2269
|
-
},
|
|
2270
|
-
// ── Animations (CSS keyframe animations, web-only) ────────────────────────
|
|
2271
|
-
// Each variant injects a @keyframes rule once via the __keyframe marker.
|
|
2272
|
-
// resolver.ts detects __keyframe, injects the rule, then strips the marker
|
|
2273
|
-
// so it never reaches element inline styles.
|
|
2274
|
-
animate: ({ value, isArbitrary }, theme) => {
|
|
2275
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2276
|
-
if (isArbitrary) return buildAnimationValue(value.replace(/_/g, " "), theme.keyframes);
|
|
2277
|
-
if (value in BUILTIN_ANIMATIONS) return BUILTIN_ANIMATIONS[value];
|
|
2278
|
-
const custom = theme.animation?.[value];
|
|
2279
|
-
return custom ? buildAnimationValue(custom, theme.keyframes) : null;
|
|
2280
|
-
},
|
|
2281
|
-
// ── Transition (web-only; use Animated API on native) ─────────────────────
|
|
2282
|
-
transition: ({ value }) => {
|
|
2283
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2284
|
-
const presets = {
|
|
2285
|
-
"": "color 150ms, background-color 150ms, border-color 150ms, text-decoration-color 150ms, fill 150ms, stroke 150ms, opacity 150ms, box-shadow 150ms, transform 150ms, filter 150ms, backdrop-filter 150ms",
|
|
2286
|
-
all: "all 150ms",
|
|
2287
|
-
none: "none",
|
|
2288
|
-
colors: "color 150ms, background-color 150ms, border-color 150ms",
|
|
2289
|
-
opacity: "opacity 150ms",
|
|
2290
|
-
shadow: "box-shadow 150ms",
|
|
2291
|
-
transform: "transform 150ms"
|
|
2292
|
-
};
|
|
2293
|
-
const v = presets[value];
|
|
2294
|
-
return v !== void 0 ? { transition: v } : null;
|
|
2295
|
-
},
|
|
2296
|
-
duration: ({ value, isArbitrary }) => {
|
|
2297
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2298
|
-
if (!isArbitrary && isNaN(parseFloat(value))) return null;
|
|
2299
|
-
const ms = isArbitrary ? value : `${value}ms`;
|
|
2300
|
-
return { transitionDuration: ms };
|
|
2301
|
-
},
|
|
2302
|
-
delay: ({ value, isArbitrary }) => {
|
|
2303
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2304
|
-
if (!isArbitrary && isNaN(parseFloat(value))) return null;
|
|
2305
|
-
const ms = isArbitrary ? value : `${value}ms`;
|
|
2306
|
-
return { transitionDelay: ms };
|
|
2307
|
-
},
|
|
2308
|
-
ease: ({ value, isArbitrary }) => {
|
|
2309
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2310
|
-
if (isArbitrary) return { transitionTimingFunction: value };
|
|
2311
|
-
const presets = {
|
|
2312
|
-
linear: "linear",
|
|
2313
|
-
in: "cubic-bezier(0.4, 0, 1, 1)",
|
|
2314
|
-
out: "cubic-bezier(0, 0, 0.2, 1)",
|
|
2315
|
-
"in-out": "cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2316
|
-
};
|
|
2317
|
-
const v = presets[value];
|
|
2318
|
-
return v !== void 0 ? { transitionTimingFunction: v } : null;
|
|
2319
|
-
}
|
|
2320
|
-
};
|
|
2321
|
-
|
|
2322
|
-
// src/core/resolvers/misc.ts
|
|
2323
|
-
var miscResolvers = {
|
|
2324
|
-
// ── Arbitrary CSS property (web-only): [property:value] with no utility prefix ──
|
|
2325
|
-
// e.g. [mask-type:luminance], [--my-var:10px]. parser.ts already isolates this case
|
|
2326
|
-
// as utility: '' — it's ALSO how a stray, prefix-less negative bracket ("-[10px]",
|
|
2327
|
-
// presumably a typo) parses, which is why this only fires when the arbitrary value
|
|
2328
|
-
// itself contains a "property:value" pair; anything else (no colon) still resolves
|
|
2329
|
-
// to null exactly as before this resolver existed, rather than guessing a property.
|
|
2330
|
-
//
|
|
2331
|
-
// Only the FIRST colon splits property from value — the value itself may contain
|
|
2332
|
-
// more colons (a URL's "http://…") and must stay intact: [background:url(http://x/a.png)].
|
|
2333
|
-
// camelToKebab() in resolver.ts is a no-op on an already-kebab-case (or "--"-prefixed
|
|
2334
|
-
// custom property) key, so it can be used as the style object key as-written with no
|
|
2335
|
-
// extra case conversion — it only needs to look like a plausible CSS property name.
|
|
2336
|
-
"": ({ value, isArbitrary, negative }) => {
|
|
2337
|
-
if (!getEffectiveIsWeb() || !isArbitrary || !value) return null;
|
|
2338
|
-
if (negative) return null;
|
|
2339
|
-
const colonIdx = value.indexOf(":");
|
|
2340
|
-
if (colonIdx <= 0) return null;
|
|
2341
|
-
const prop = value.slice(0, colonIdx).trim();
|
|
2342
|
-
const cssValue = value.slice(colonIdx + 1).trim();
|
|
2343
|
-
if (!cssValue || !/^(--[\w-]+|[a-zA-Z-]+)$/.test(prop)) return null;
|
|
2344
|
-
return { [prop]: cssValue };
|
|
2345
|
-
},
|
|
2346
|
-
// ── SVG stroke/fill (web-only) ────────────────────────────────────────────
|
|
2347
|
-
// Native is intentionally excluded: react-native-svg's <Path>/<Circle>/etc.
|
|
2348
|
-
// take stroke/fill as component PROPS, not style entries, so there's no
|
|
2349
|
-
// reliable way to apply a resolved color through the `style` prop there.
|
|
2350
|
-
// `stroke-{n}` sets strokeWidth (a plain number, unlike a color) — same
|
|
2351
|
-
// color-first-then-numeric-fallback disambiguation `border` uses above.
|
|
2352
|
-
stroke: ({ value, isArbitrary }, { colors }) => {
|
|
2353
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2354
|
-
if (!value) return null;
|
|
2355
|
-
if (value === "none") return { stroke: "none" };
|
|
2356
|
-
if (isArbitrary) {
|
|
2357
|
-
const w = toNativeValue(value);
|
|
2358
|
-
return typeof w === "number" ? { strokeWidth: w } : { stroke: value };
|
|
2359
|
-
}
|
|
2360
|
-
const color = resolveColor(value, colors, false);
|
|
2361
|
-
if (color) return { stroke: color };
|
|
2362
|
-
const n = parseFloat(value);
|
|
2363
|
-
return isNaN(n) ? null : { strokeWidth: n };
|
|
2364
|
-
},
|
|
2365
|
-
fill: ({ value, isArbitrary }, { colors }) => {
|
|
2366
|
-
if (!getEffectiveIsWeb()) return null;
|
|
2367
|
-
if (!value) return null;
|
|
2368
|
-
if (value === "none") return { fill: "none" };
|
|
2369
|
-
if (isArbitrary) return { fill: value };
|
|
2370
|
-
const color = resolveColor(value, colors, false);
|
|
2371
|
-
return color ? { fill: color } : null;
|
|
2372
|
-
},
|
|
2373
|
-
// ── Text shadow (cross-platform: iOS, Android, web) ─────────────────────
|
|
2374
|
-
// Named presets give cross-platform shadow; arbitrary is web-only.
|
|
2375
|
-
"text-shadow": ({ value, isArbitrary }, { colors }) => {
|
|
2376
|
-
if (value === "none") {
|
|
2377
|
-
return getEffectiveIsWeb() ? { textShadow: "none" } : { textShadowColor: "transparent", textShadowOffset: { width: 0, height: 0 }, textShadowRadius: 0 };
|
|
2378
|
-
}
|
|
2379
|
-
const webPresets = {
|
|
2380
|
-
"": "0 2px 4px rgba(0,0,0,0.3)",
|
|
2381
|
-
sm: "0 1px 2px rgba(0,0,0,0.3)",
|
|
2382
|
-
md: "0 4px 6px rgba(0,0,0,0.3)",
|
|
2383
|
-
lg: "0 8px 16px rgba(0,0,0,0.5)",
|
|
2384
|
-
xl: "0 16px 32px rgba(0,0,0,0.5)"
|
|
2385
|
-
};
|
|
2386
|
-
const nativePresets = {
|
|
2387
|
-
"": { textShadowColor: "rgba(0,0,0,0.3)", textShadowOffset: { width: 0, height: 2 }, textShadowRadius: 4 },
|
|
2388
|
-
sm: { textShadowColor: "rgba(0,0,0,0.3)", textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 2 },
|
|
2389
|
-
md: { textShadowColor: "rgba(0,0,0,0.3)", textShadowOffset: { width: 0, height: 4 }, textShadowRadius: 6 },
|
|
2390
|
-
lg: { textShadowColor: "rgba(0,0,0,0.5)", textShadowOffset: { width: 0, height: 8 }, textShadowRadius: 16 },
|
|
2391
|
-
xl: { textShadowColor: "rgba(0,0,0,0.5)", textShadowOffset: { width: 0, height: 16 }, textShadowRadius: 32 }
|
|
2392
|
-
};
|
|
2393
|
-
if (value in webPresets) {
|
|
2394
|
-
if (getEffectiveIsWeb()) return { textShadow: webPresets[value] };
|
|
2395
|
-
return nativePresets[value] ?? null;
|
|
2396
|
-
}
|
|
2397
|
-
if (isArbitrary) {
|
|
2398
|
-
return getEffectiveIsWeb() ? { textShadow: value.replace(/_/g, " ") } : null;
|
|
2399
|
-
}
|
|
2400
|
-
const color = resolveColor(value, colors, false);
|
|
2401
|
-
if (color) {
|
|
2402
|
-
return getEffectiveIsWeb() ? { textShadow: `0 2px 4px ${color}` } : { textShadowColor: color };
|
|
2403
|
-
}
|
|
2404
|
-
return null;
|
|
2405
|
-
}
|
|
2406
|
-
};
|
|
2407
|
-
|
|
2408
|
-
// src/core/utilities.ts
|
|
2409
|
-
var RESOLVERS = {
|
|
2410
|
-
...colorResolvers,
|
|
2411
|
-
...spacingResolvers,
|
|
2412
|
-
...borderResolvers,
|
|
2413
|
-
...layoutResolvers,
|
|
2414
|
-
...typographyResolvers,
|
|
2415
|
-
...filterResolvers,
|
|
2416
|
-
...transformResolvers,
|
|
2417
|
-
...effectResolvers,
|
|
2418
|
-
...miscResolvers
|
|
2419
|
-
};
|
|
2420
|
-
var NAMED_GROUP_PEER_MARKER_RE = /^(group|peer)\/.+$/;
|
|
2421
|
-
function resolveUtility(parsed, theme) {
|
|
2422
|
-
if (!parsed.value) {
|
|
2423
|
-
if (parsed.utility in PLUGIN_STANDALONE) return PLUGIN_STANDALONE[parsed.utility] ?? null;
|
|
2424
|
-
if (parsed.utility in getStandalone()) return getStandalone()[parsed.utility] ?? null;
|
|
2425
|
-
if (NAMED_GROUP_PEER_MARKER_RE.test(parsed.utility)) return getEffectiveIsWeb() ? {} : null;
|
|
2426
|
-
}
|
|
2427
|
-
const resolver = PLUGIN_RESOLVERS[parsed.utility] ?? RESOLVERS[parsed.utility];
|
|
2428
|
-
if (resolver) return resolver(parsed, theme);
|
|
2429
|
-
return null;
|
|
2430
|
-
}
|
|
2431
|
-
var PLUGIN_STANDALONE = {};
|
|
2432
|
-
var PLUGIN_RESOLVERS = {};
|
|
2433
|
-
function clearPluginUtilities() {
|
|
2434
|
-
for (const key of Object.keys(PLUGIN_STANDALONE)) delete PLUGIN_STANDALONE[key];
|
|
2435
|
-
for (const key of Object.keys(PLUGIN_RESOLVERS)) delete PLUGIN_RESOLVERS[key];
|
|
2436
|
-
_sortedPrefixes = null;
|
|
2437
|
-
_standaloneNames = null;
|
|
2438
|
-
}
|
|
2439
|
-
function getPluginStandaloneMap() {
|
|
2440
|
-
return PLUGIN_STANDALONE;
|
|
2441
|
-
}
|
|
2442
|
-
var _sortedPrefixes = null;
|
|
2443
|
-
var _standaloneNames = null;
|
|
2444
|
-
function getBuiltinUtilityPrefixes() {
|
|
2445
|
-
if (!_sortedPrefixes) {
|
|
2446
|
-
const all = [.../* @__PURE__ */ new Set([...Object.keys(RESOLVERS), ...Object.keys(PLUGIN_RESOLVERS)])];
|
|
2447
|
-
_sortedPrefixes = all.sort((a, b) => b.length - a.length);
|
|
2448
|
-
}
|
|
2449
|
-
return _sortedPrefixes;
|
|
2450
|
-
}
|
|
2451
|
-
function getBuiltinStandaloneNames() {
|
|
2452
|
-
if (!_standaloneNames) {
|
|
2453
|
-
_standaloneNames = /* @__PURE__ */ new Set([...Object.keys(getStandalone()), ...Object.keys(PLUGIN_STANDALONE)]);
|
|
2454
|
-
}
|
|
2455
|
-
return _standaloneNames;
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2458
|
-
// src/core/devWarn.ts
|
|
2459
|
-
function kbachWarn(message) {
|
|
2460
|
-
console.warn(
|
|
2461
|
-
"%c[kbach]%c " + message,
|
|
2462
|
-
"color:#8b5cf6;font-weight:700",
|
|
2463
|
-
"color:inherit;font-weight:400"
|
|
2464
|
-
);
|
|
2465
|
-
}
|
|
2466
|
-
|
|
2467
|
-
// src/core/cache.ts
|
|
2468
|
-
var LRUCache = class {
|
|
2469
|
-
constructor(capacity = 1e4, onEvict) {
|
|
2470
|
-
this.capacity = capacity;
|
|
2471
|
-
if (capacity <= 0) throw new Error("LRUCache: capacity must be a positive integer");
|
|
2472
|
-
this.cache = /* @__PURE__ */ new Map();
|
|
2473
|
-
this.onEvict = onEvict;
|
|
2474
|
-
}
|
|
2475
|
-
get(key) {
|
|
2476
|
-
if (!this.cache.has(key)) return void 0;
|
|
2477
|
-
const value = this.cache.get(key);
|
|
2478
|
-
this.cache.delete(key);
|
|
2479
|
-
this.cache.set(key, value);
|
|
2480
|
-
return value;
|
|
2481
|
-
}
|
|
2482
|
-
set(key, value) {
|
|
2483
|
-
if (this.cache.has(key)) {
|
|
2484
|
-
this.cache.delete(key);
|
|
2485
|
-
} else if (this.cache.size >= this.capacity) {
|
|
2486
|
-
const oldestKey = this.cache.keys().next().value;
|
|
2487
|
-
const oldestValue = this.cache.get(oldestKey);
|
|
2488
|
-
this.cache.delete(oldestKey);
|
|
2489
|
-
this.onEvict?.(oldestKey, oldestValue);
|
|
2490
|
-
}
|
|
2491
|
-
this.cache.set(key, value);
|
|
2492
|
-
return this;
|
|
2493
|
-
}
|
|
2494
|
-
has(key) {
|
|
2495
|
-
return this.cache.has(key);
|
|
2496
|
-
}
|
|
2497
|
-
delete(key) {
|
|
2498
|
-
return this.cache.delete(key);
|
|
2499
|
-
}
|
|
2500
|
-
clear() {
|
|
2501
|
-
this.cache.clear();
|
|
2502
|
-
}
|
|
2503
|
-
get size() {
|
|
2504
|
-
return this.cache.size;
|
|
2505
|
-
}
|
|
2506
|
-
};
|
|
2507
|
-
|
|
2508
|
-
// src/core/registry.ts
|
|
2509
|
-
var BUILTIN_MODIFIERS = {
|
|
2510
|
-
// ── Mode ─────────────────────────────────────────────────────────────────
|
|
2511
|
-
dark: { order: 60, darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
|
|
2512
|
-
"not-light": { order: 60, darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
|
|
2513
|
-
light: { order: 60, darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
|
|
2514
|
-
"not-dark": { order: 60, darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
|
|
2515
|
-
// ── Interactive — JS state + CSS pseudo ───────────────────────────────────
|
|
2516
|
-
hover: { order: 10, pseudo: ":hover", jsBehavior: "interactive", jsMatch: (_, s) => !!s.hover },
|
|
2517
|
-
"not-hover": { order: 10, pseudo: ":not(:hover)", jsBehavior: "interactive", jsMatch: (_, s) => !s.hover },
|
|
2518
|
-
focus: { order: 20, pseudo: ":focus", jsBehavior: "interactive", jsMatch: (_, s) => !!s.focus },
|
|
2519
|
-
"not-focus": { order: 20, pseudo: ":not(:focus)", jsBehavior: "interactive", jsMatch: (_, s) => !s.focus },
|
|
2520
|
-
active: { order: 30, pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.active || !!s.pressed },
|
|
2521
|
-
"not-active": { order: 30, pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.active && !s.pressed },
|
|
2522
|
-
pressed: { order: 30, pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.pressed || !!s.active },
|
|
2523
|
-
"not-pressed": { order: 30, pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.pressed && !s.active },
|
|
2524
|
-
disabled: { order: 40, pseudo: ":disabled", jsBehavior: "interactive", jsMatch: (_, s) => !!s.disabled },
|
|
2525
|
-
"not-disabled": { order: 40, pseudo: ":not(:disabled)", jsBehavior: "interactive", jsMatch: (_, s) => !s.disabled },
|
|
2526
|
-
checked: { order: 35, pseudo: ":checked", jsBehavior: "interactive", jsMatch: (_, s) => !!s.checked },
|
|
2527
|
-
"not-checked": { order: 35, pseudo: ":not(:checked)", jsBehavior: "interactive", jsMatch: (_, s) => !s.checked },
|
|
2528
|
-
visited: { order: 5, pseudo: ":visited", jsBehavior: "interactive", jsMatch: (_, s) => !!s.visited },
|
|
2529
|
-
"not-visited": { order: 5, pseudo: ":not(:visited)", jsBehavior: "interactive", jsMatch: (_, s) => !s.visited },
|
|
2530
|
-
placeholder: { order: 0, pseudo: "::placeholder", jsBehavior: "interactive", jsMatch: (_, s) => !!s.placeholder },
|
|
2531
|
-
// ── CSS-only pseudo-classes (structural) ──────────────────────────────────
|
|
2532
|
-
first: { order: 0, pseudo: ":first-child", jsBehavior: "css-only", forcesImportant: true },
|
|
2533
|
-
last: { order: 0, pseudo: ":last-child", jsBehavior: "css-only", forcesImportant: true },
|
|
2534
|
-
odd: { order: 0, pseudo: ":nth-child(odd)", jsBehavior: "css-only", forcesImportant: true },
|
|
2535
|
-
even: { order: 0, pseudo: ":nth-child(even)", jsBehavior: "css-only", forcesImportant: true },
|
|
2536
|
-
only: { order: 0, pseudo: ":only-child", jsBehavior: "css-only", forcesImportant: true },
|
|
2537
|
-
"focus-within": { order: 15, pseudo: ":focus-within", jsBehavior: "css-only", forcesImportant: true },
|
|
2538
|
-
"focus-visible": { order: 25, pseudo: ":focus-visible", jsBehavior: "css-only", forcesImportant: true },
|
|
2539
|
-
// ── CSS-only pseudo-elements ───────────────────────────────────────────────
|
|
2540
|
-
before: { order: 0, pseudo: "::before", jsBehavior: "css-only" },
|
|
2541
|
-
after: { order: 0, pseudo: "::after", jsBehavior: "css-only" },
|
|
2542
|
-
selection: { order: 0, pseudo: "::selection", jsBehavior: "css-only" },
|
|
2543
|
-
"first-letter": { order: 0, pseudo: "::first-letter", jsBehavior: "css-only" },
|
|
2544
|
-
"first-line": { order: 0, pseudo: "::first-line", jsBehavior: "css-only" },
|
|
2545
|
-
marker: { order: 0, pseudo: "::marker", jsBehavior: "css-only" },
|
|
2546
|
-
// ── Group / peer ancestor selectors (CSS-only) ─────────────────────────────
|
|
2547
|
-
"group-hover": { order: 10, ancestorSelector: ".group:hover ", jsBehavior: "css-only", forcesImportant: true },
|
|
2548
|
-
"group-focus": { order: 20, ancestorSelector: ".group:focus ", jsBehavior: "css-only", forcesImportant: true },
|
|
2549
|
-
"peer-hover": { order: 10, ancestorSelector: ".peer:hover ~ ", jsBehavior: "css-only", forcesImportant: true },
|
|
2550
|
-
"peer-focus": { order: 20, ancestorSelector: ".peer:focus ~ ", jsBehavior: "css-only", forcesImportant: true },
|
|
2551
|
-
// ── Responsive — both CSS (@media min-width) and JS (breakpoints set) ──────
|
|
2552
|
-
sm: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("sm") },
|
|
2553
|
-
md: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("md") },
|
|
2554
|
-
lg: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("lg") },
|
|
2555
|
-
xl: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("xl") },
|
|
2556
|
-
"2xl": { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("2xl") },
|
|
2557
|
-
// ── Print media (CSS-only) ─────────────────────────────────────────────────
|
|
2558
|
-
print: { order: 70, mediaQuery: "print", jsBehavior: "css-only", forcesImportant: true },
|
|
2559
|
-
// ── Orientation / accessibility media (CSS-only) ───────────────────────────
|
|
2560
|
-
landscape: { order: 70, mediaQuery: "(orientation: landscape)", jsBehavior: "css-only", forcesImportant: true },
|
|
2561
|
-
portrait: { order: 70, mediaQuery: "(orientation: portrait)", jsBehavior: "css-only", forcesImportant: true },
|
|
2562
|
-
"motion-reduce": { order: 70, mediaQuery: "(prefers-reduced-motion: reduce)", jsBehavior: "css-only", forcesImportant: true },
|
|
2563
|
-
"motion-safe": { order: 70, mediaQuery: "(prefers-reduced-motion: no-preference)", jsBehavior: "css-only", forcesImportant: true },
|
|
2564
|
-
"contrast-more": { order: 70, mediaQuery: "(prefers-contrast: more)", jsBehavior: "css-only", forcesImportant: true },
|
|
2565
|
-
"contrast-less": { order: 70, mediaQuery: "(prefers-contrast: less)", jsBehavior: "css-only", forcesImportant: true },
|
|
2566
|
-
// ── Directionality (CSS-only) ──────────────────────────────────────────────
|
|
2567
|
-
rtl: { order: 80, dirSelector: '[dir="rtl"] ', jsBehavior: "css-only", forcesImportant: true },
|
|
2568
|
-
ltr: { order: 80, dirSelector: '[dir="ltr"] ', jsBehavior: "css-only", forcesImportant: true }
|
|
2569
|
-
};
|
|
2570
|
-
var _pluginModifiers = {};
|
|
2571
|
-
var _allNames = null;
|
|
2572
|
-
var _interactiveNames = null;
|
|
2573
|
-
var _modeNames = null;
|
|
2574
|
-
var _responsiveNames = null;
|
|
2575
|
-
function _invalidate() {
|
|
2576
|
-
_allNames = null;
|
|
2577
|
-
_interactiveNames = null;
|
|
2578
|
-
_modeNames = null;
|
|
2579
|
-
_responsiveNames = null;
|
|
2580
|
-
}
|
|
2581
|
-
function registerModifier(name, def) {
|
|
2582
|
-
if (process.env.NODE_ENV !== "production" && name in BUILTIN_MODIFIERS) {
|
|
2583
|
-
kbachWarn(`"${name}" is built-in \u2014 pick another modifier name`);
|
|
2584
|
-
return;
|
|
2585
|
-
}
|
|
2586
|
-
_pluginModifiers[name] = def;
|
|
2587
|
-
_invalidate();
|
|
2588
|
-
}
|
|
2589
|
-
function clearPluginModifiers() {
|
|
2590
|
-
for (const k of Object.keys(_pluginModifiers)) delete _pluginModifiers[k];
|
|
2591
|
-
_invalidate();
|
|
2592
|
-
}
|
|
2593
|
-
var NAMED_GROUP_PEER_RE = /^(group|peer)-(hover|focus)\/(.+)$/;
|
|
2594
|
-
var _namedModifierCache = new LRUCache(1e4);
|
|
2595
|
-
function getNamedGroupPeerModifier(name) {
|
|
2596
|
-
const cached = _namedModifierCache.get(name);
|
|
2597
|
-
if (cached) return cached;
|
|
2598
|
-
const m = NAMED_GROUP_PEER_RE.exec(name);
|
|
2599
|
-
if (!m) return void 0;
|
|
2600
|
-
const [, kind, trigger, groupName] = m;
|
|
2601
|
-
const escapedName = escapeCSSSelector(groupName);
|
|
2602
|
-
const pseudo = trigger === "hover" ? ":hover" : ":focus";
|
|
2603
|
-
const combinator = kind === "group" ? " " : " ~ ";
|
|
2604
|
-
const def = {
|
|
2605
|
-
// Matches the plain group-hover/group-focus/peer-hover/peer-focus order below.
|
|
2606
|
-
order: trigger === "hover" ? 10 : 20,
|
|
2607
|
-
ancestorSelector: `.${kind}\\/${escapedName}${pseudo}${combinator}`,
|
|
2608
|
-
jsBehavior: "css-only",
|
|
2609
|
-
forcesImportant: true
|
|
2610
|
-
};
|
|
2611
|
-
_namedModifierCache.set(name, def);
|
|
2612
|
-
return def;
|
|
2613
|
-
}
|
|
2614
|
-
function getModifier(name) {
|
|
2615
|
-
return BUILTIN_MODIFIERS[name] ?? _pluginModifiers[name] ?? getNamedGroupPeerModifier(name);
|
|
2616
|
-
}
|
|
2617
|
-
function isKnownModifier(name) {
|
|
2618
|
-
return name in BUILTIN_MODIFIERS || name in _pluginModifiers || NAMED_GROUP_PEER_RE.test(name);
|
|
2619
|
-
}
|
|
2620
|
-
function getModifierOrder(bucketKey) {
|
|
2621
|
-
if (bucketKey === "base") return -1;
|
|
2622
|
-
let max = 0;
|
|
2623
|
-
for (const mod of bucketKey.split(":")) {
|
|
2624
|
-
const order = getModifier(mod)?.order ?? 0;
|
|
2625
|
-
if (order > max) max = order;
|
|
2626
|
-
}
|
|
2627
|
-
return max;
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
// src/core/parser.ts
|
|
2631
|
-
var UNSAFE_ARBITRARY_VALUE = /[{};\\]|\/\*|\*\//;
|
|
2632
|
-
function isSafeArbitraryValue(value) {
|
|
2633
|
-
if (!UNSAFE_ARBITRARY_VALUE.test(value)) return true;
|
|
2634
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2635
|
-
kbachWarn(`Unsafe arbitrary value rejected: "${value}"`);
|
|
2636
|
-
}
|
|
2637
|
-
return false;
|
|
2638
|
-
}
|
|
2639
|
-
function parseClass(className) {
|
|
2640
|
-
const trimmed = className.trim();
|
|
2641
|
-
if (!trimmed) return null;
|
|
2642
|
-
const modifiers = [];
|
|
2643
|
-
let remaining = trimmed;
|
|
2644
|
-
while (true) {
|
|
2645
|
-
const colonIdx = findOuterColon(remaining);
|
|
2646
|
-
if (colonIdx === -1) break;
|
|
2647
|
-
const candidate = remaining.slice(0, colonIdx);
|
|
2648
|
-
if (!isKnownModifier(candidate)) break;
|
|
2649
|
-
modifiers.push(candidate);
|
|
2650
|
-
remaining = remaining.slice(colonIdx + 1);
|
|
2651
|
-
}
|
|
2652
|
-
let important = false;
|
|
2653
|
-
if (remaining.startsWith("!") && remaining.length > 1) {
|
|
2654
|
-
important = true;
|
|
2655
|
-
remaining = remaining.slice(1);
|
|
2656
|
-
}
|
|
2657
|
-
let negative = false;
|
|
2658
|
-
if (remaining.startsWith("-") && remaining.length > 1 && remaining[1] !== "-") {
|
|
2659
|
-
negative = true;
|
|
2660
|
-
remaining = remaining.slice(1);
|
|
2661
|
-
}
|
|
2662
|
-
let bracketDepth = 0;
|
|
2663
|
-
let bracketStart = -1;
|
|
2664
|
-
for (let i = remaining.length - 1; i >= 0; i--) {
|
|
2665
|
-
if (remaining[i] === "]") bracketDepth++;
|
|
2666
|
-
else if (remaining[i] === "[") {
|
|
2667
|
-
bracketDepth--;
|
|
2668
|
-
if (bracketDepth === 0) {
|
|
2669
|
-
bracketStart = i;
|
|
2670
|
-
break;
|
|
2671
|
-
}
|
|
2672
|
-
}
|
|
2673
|
-
}
|
|
2674
|
-
if (bracketStart > 0 && remaining[bracketStart - 1] === "-" && remaining.endsWith("]")) {
|
|
2675
|
-
const utility = remaining.slice(0, bracketStart - 1);
|
|
2676
|
-
const value = remaining.slice(bracketStart + 1, -1).replace(/_/g, " ");
|
|
2677
|
-
if (!isSafeArbitraryValue(value)) return null;
|
|
2678
|
-
return { original: trimmed, modifiers, negative, important, utility, value, isArbitrary: true };
|
|
2679
|
-
}
|
|
2680
|
-
if (remaining.endsWith("]") && bracketStart === -1) {
|
|
2681
|
-
if (process.env.NODE_ENV !== "production") {
|
|
2682
|
-
kbachWarn(`Unbalanced brackets: "${trimmed}"`);
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
if (remaining.startsWith("[") && remaining.endsWith("]")) {
|
|
2686
|
-
const value = remaining.slice(1, -1).replace(/_/g, " ");
|
|
2687
|
-
if (!isSafeArbitraryValue(value)) return null;
|
|
2688
|
-
return { original: trimmed, modifiers, negative, important, utility: "", value, isArbitrary: true };
|
|
2689
|
-
}
|
|
2690
|
-
if (getBuiltinStandaloneNames().has(remaining)) {
|
|
2691
|
-
return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
|
|
2692
|
-
}
|
|
2693
|
-
for (const prefix of getBuiltinUtilityPrefixes()) {
|
|
2694
|
-
if (remaining === prefix) {
|
|
2695
|
-
return { original: trimmed, modifiers, negative, important, utility: prefix, value: "", isArbitrary: false };
|
|
2696
|
-
}
|
|
2697
|
-
if (remaining.startsWith(prefix + "-")) {
|
|
2698
|
-
const value = remaining.slice(prefix.length + 1);
|
|
2699
|
-
return { original: trimmed, modifiers, negative, important, utility: prefix, value, isArbitrary: false };
|
|
2700
|
-
}
|
|
2701
|
-
}
|
|
2702
|
-
const firstDash = remaining.indexOf("-");
|
|
2703
|
-
if (firstDash > 0) {
|
|
2704
|
-
return {
|
|
2705
|
-
original: trimmed,
|
|
2706
|
-
modifiers,
|
|
2707
|
-
negative,
|
|
2708
|
-
important,
|
|
2709
|
-
utility: remaining.slice(0, firstDash),
|
|
2710
|
-
value: remaining.slice(firstDash + 1),
|
|
2711
|
-
isArbitrary: false
|
|
2712
|
-
};
|
|
2713
|
-
}
|
|
2714
|
-
return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
|
|
2715
|
-
}
|
|
2716
|
-
function splitClassTokens(classString) {
|
|
2717
|
-
const tokens = [];
|
|
2718
|
-
let current = "";
|
|
2719
|
-
let depth = 0;
|
|
2720
|
-
let parenDepth = 0;
|
|
2721
|
-
for (let i = 0; i < classString.length; i++) {
|
|
2722
|
-
const ch = classString[i];
|
|
2723
|
-
if (ch === "[") {
|
|
2724
|
-
depth++;
|
|
2725
|
-
current += ch;
|
|
2726
|
-
continue;
|
|
2727
|
-
}
|
|
2728
|
-
if (ch === "]") {
|
|
2729
|
-
depth--;
|
|
2730
|
-
current += ch;
|
|
2731
|
-
continue;
|
|
2732
|
-
}
|
|
2733
|
-
if (ch === "(") {
|
|
2734
|
-
parenDepth++;
|
|
2735
|
-
current += ch;
|
|
2736
|
-
continue;
|
|
2737
|
-
}
|
|
2738
|
-
if (ch === ")") {
|
|
2739
|
-
parenDepth--;
|
|
2740
|
-
current += ch;
|
|
2741
|
-
continue;
|
|
2742
|
-
}
|
|
2743
|
-
if (/\s/.test(ch)) {
|
|
2744
|
-
if (depth === 0 && parenDepth === 0) {
|
|
2745
|
-
if (current) {
|
|
2746
|
-
tokens.push(current);
|
|
2747
|
-
current = "";
|
|
2748
|
-
}
|
|
2749
|
-
}
|
|
2750
|
-
} else {
|
|
2751
|
-
current += ch;
|
|
2752
|
-
}
|
|
2753
|
-
}
|
|
2754
|
-
if (current) tokens.push(current);
|
|
2755
|
-
return tokens;
|
|
2756
|
-
}
|
|
2757
|
-
function parseClasses(classString) {
|
|
2758
|
-
const results = [];
|
|
2759
|
-
for (const token of splitClassTokens(classString)) {
|
|
2760
|
-
const parsed = parseClass(token);
|
|
2761
|
-
if (parsed) results.push(parsed);
|
|
2762
|
-
}
|
|
2763
|
-
return results;
|
|
2764
|
-
}
|
|
2765
|
-
function findOuterColon(s) {
|
|
2766
|
-
let depth = 0;
|
|
2767
|
-
for (let i = 0; i < s.length; i++) {
|
|
2768
|
-
const ch = s[i];
|
|
2769
|
-
if (ch === "[") depth++;
|
|
2770
|
-
else if (ch === "]") depth--;
|
|
2771
|
-
else if (ch === ":" && depth === 0) return i;
|
|
2772
|
-
}
|
|
2773
|
-
return -1;
|
|
2774
|
-
}
|
|
6
|
+
// src/vite-plugin/index.ts
|
|
7
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
8
|
+
import { join as join3, dirname } from "path";
|
|
2775
9
|
|
|
2776
|
-
// src/
|
|
2777
|
-
|
|
2778
|
-
function
|
|
2779
|
-
|
|
2780
|
-
for (const [name, entry] of Object.entries(colors)) {
|
|
2781
|
-
if (isModeAwareColor(entry)) {
|
|
2782
|
-
map.set(name, entry);
|
|
2783
|
-
} else if (entry && typeof entry === "object") {
|
|
2784
|
-
for (const [shade, val] of Object.entries(entry)) {
|
|
2785
|
-
if (isModeAwareColor(val)) map.set(`${name}-${shade}`, val);
|
|
2786
|
-
}
|
|
2787
|
-
}
|
|
2788
|
-
}
|
|
2789
|
-
return map;
|
|
2790
|
-
}
|
|
2791
|
-
function getModeAwareMap(colors) {
|
|
2792
|
-
let map = _modeAwareMapCache.get(colors);
|
|
2793
|
-
if (!map) {
|
|
2794
|
-
map = buildModeAwareMap(colors);
|
|
2795
|
-
_modeAwareMapCache.set(colors, map);
|
|
2796
|
-
}
|
|
2797
|
-
return map;
|
|
2798
|
-
}
|
|
2799
|
-
function expandModeAwareColorClasses(classString, colors) {
|
|
2800
|
-
const map = getModeAwareMap(colors);
|
|
2801
|
-
if (map.size === 0) return classString;
|
|
2802
|
-
const tokens = splitClassTokens(classString);
|
|
2803
|
-
let changed = false;
|
|
2804
|
-
const out = [];
|
|
2805
|
-
for (const token of tokens) {
|
|
2806
|
-
const parsed = parseClass(token);
|
|
2807
|
-
if (!parsed || parsed.isArbitrary) {
|
|
2808
|
-
out.push(token);
|
|
2809
|
-
continue;
|
|
2810
|
-
}
|
|
2811
|
-
const slashIdx = parsed.value.indexOf("/");
|
|
2812
|
-
const colorPart = slashIdx > 0 ? parsed.value.slice(0, slashIdx) : parsed.value;
|
|
2813
|
-
const opacitySuffix = slashIdx > 0 ? parsed.value.slice(slashIdx) : "";
|
|
2814
|
-
const pair = map.get(colorPart);
|
|
2815
|
-
if (!pair) {
|
|
2816
|
-
out.push(token);
|
|
2817
|
-
continue;
|
|
2818
|
-
}
|
|
2819
|
-
changed = true;
|
|
2820
|
-
const bang = parsed.important ? "!" : "";
|
|
2821
|
-
const modPrefix = parsed.modifiers.map((m) => `${m}:`).join("");
|
|
2822
|
-
const explicitScheme = parsed.modifiers.map((m) => getModifier(m)?.darkScheme).find((s) => s);
|
|
2823
|
-
if (explicitScheme) {
|
|
2824
|
-
const side = explicitScheme === "dark" ? pair.dark : pair.light;
|
|
2825
|
-
out.push(`${bang}${modPrefix}${parsed.utility}-[${side}]${opacitySuffix}`);
|
|
2826
|
-
continue;
|
|
2827
|
-
}
|
|
2828
|
-
out.push(`${bang}${modPrefix}${parsed.utility}-[${pair.light}]${opacitySuffix}`);
|
|
2829
|
-
out.push(`${bang}dark:${modPrefix}${parsed.utility}-[${pair.dark}]${opacitySuffix}`);
|
|
2830
|
-
}
|
|
2831
|
-
return changed ? out.join(" ") : classString;
|
|
10
|
+
// src/vite-plugin/wasmNode.ts
|
|
11
|
+
import { generate_css } from "@kbach/core-engine/node";
|
|
12
|
+
function generateCssForToken(token, themeJson) {
|
|
13
|
+
return JSON.parse(generate_css(token, themeJson));
|
|
2832
14
|
}
|
|
2833
15
|
|
|
2834
|
-
// src/
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
var _styleEl = null;
|
|
2840
|
-
var _ruleIndexByKey = /* @__PURE__ */ new Map();
|
|
2841
|
-
var _sheetKeys = [];
|
|
2842
|
-
var _ruleOrderByKey = /* @__PURE__ */ new Map();
|
|
2843
|
-
function evictInjectedRule(rule) {
|
|
2844
|
-
const idx = _ruleIndexByKey.get(rule);
|
|
2845
|
-
_ruleIndexByKey.delete(rule);
|
|
2846
|
-
_ruleOrderByKey.delete(rule);
|
|
2847
|
-
if (idx === void 0) return;
|
|
2848
|
-
const sheet = _styleEl?.sheet;
|
|
2849
|
-
if (!sheet) return;
|
|
2850
|
-
try {
|
|
2851
|
-
sheet.deleteRule(idx);
|
|
2852
|
-
} catch {
|
|
2853
|
-
return;
|
|
2854
|
-
}
|
|
2855
|
-
_sheetKeys.splice(idx, 1);
|
|
2856
|
-
for (const [key, i] of _ruleIndexByKey) {
|
|
2857
|
-
if (i > idx) _ruleIndexByKey.set(key, i - 1);
|
|
2858
|
-
}
|
|
2859
|
-
}
|
|
2860
|
-
var _injectedRules = new LRUCache(5e4, evictInjectedRule);
|
|
2861
|
-
var _runtimeCSSDisabled = false;
|
|
2862
|
-
function isRuntimeCSSDisabled() {
|
|
2863
|
-
return _runtimeCSSDisabled;
|
|
2864
|
-
}
|
|
2865
|
-
function getStyleEl() {
|
|
2866
|
-
if (_styleEl) return _styleEl;
|
|
2867
|
-
_styleEl = document.createElement("style");
|
|
2868
|
-
_styleEl.setAttribute("data-kbach", "");
|
|
2869
|
-
document.head.appendChild(_styleEl);
|
|
2870
|
-
return _styleEl;
|
|
2871
|
-
}
|
|
2872
|
-
var _globalStyleEl = null;
|
|
2873
|
-
function getGlobalStyleEl() {
|
|
2874
|
-
if (_globalStyleEl) return _globalStyleEl;
|
|
2875
|
-
_globalStyleEl = document.createElement("style");
|
|
2876
|
-
_globalStyleEl.setAttribute("data-kbach-global", "");
|
|
2877
|
-
document.head.insertBefore(_globalStyleEl, getStyleEl());
|
|
2878
|
-
return _globalStyleEl;
|
|
2879
|
-
}
|
|
2880
|
-
function injectGlobalStyles(theme) {
|
|
2881
|
-
if (typeof document === "undefined" || isRuntimeCSSDisabled()) return;
|
|
2882
|
-
const rules = document.getElementById(RESET_STYLE_ID) ? [] : [BASE_RESET];
|
|
2883
|
-
const ff = theme.fontFamily;
|
|
2884
|
-
if (ff?.sans && ff.sans !== "System") {
|
|
2885
|
-
const family = Array.isArray(ff.sans) ? ff.sans.join(", ") : ff.sans;
|
|
2886
|
-
rules.push(`body { font-family: ${family}; }`);
|
|
2887
|
-
}
|
|
2888
|
-
getGlobalStyleEl().textContent = rules.join("\n");
|
|
2889
|
-
}
|
|
2890
|
-
function buildDivideDecls(styles, forceImportant) {
|
|
2891
|
-
const imp = forceImportant ? " !important" : "";
|
|
2892
|
-
const parts = [];
|
|
2893
|
-
if ("__divideX" in styles) {
|
|
2894
|
-
const w = Number(styles.__divideX);
|
|
2895
|
-
parts.push(`border-left-width: ${w}px${imp}`, `border-right-width: 0px${imp}`);
|
|
2896
|
-
}
|
|
2897
|
-
if ("__divideY" in styles) {
|
|
2898
|
-
const w = Number(styles.__divideY);
|
|
2899
|
-
parts.push(`border-top-width: ${w}px${imp}`, `border-bottom-width: 0px${imp}`);
|
|
2900
|
-
}
|
|
2901
|
-
if ("__divideColor" in styles) parts.push(`border-color: ${String(styles.__divideColor)}${imp}`);
|
|
2902
|
-
if ("__divideStyle" in styles) parts.push(`border-style: ${String(styles.__divideStyle)}${imp}`);
|
|
2903
|
-
return parts.join("; ");
|
|
16
|
+
// src/vite-plugin/scan.ts
|
|
17
|
+
import { readdirSync, readFileSync, statSync } from "fs";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
function splitClassTokens(str) {
|
|
20
|
+
return str.split(/\s+/).filter(Boolean);
|
|
2904
21
|
}
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
const
|
|
2908
|
-
|
|
2909
|
-
const v = styles.__spaceX;
|
|
2910
|
-
const val = typeof v === "number" ? `${v}px` : String(v);
|
|
2911
|
-
parts.push(`margin-left: ${val}${imp}`);
|
|
2912
|
-
}
|
|
2913
|
-
if ("__spaceY" in styles) {
|
|
2914
|
-
const v = styles.__spaceY;
|
|
2915
|
-
const val = typeof v === "number" ? `${v}px` : String(v);
|
|
2916
|
-
parts.push(`margin-top: ${val}${imp}`);
|
|
2917
|
-
}
|
|
2918
|
-
return parts.join("; ");
|
|
2919
|
-
}
|
|
2920
|
-
var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
|
|
2921
|
-
"shadowColor",
|
|
2922
|
-
"shadowOffset",
|
|
2923
|
-
"shadowOpacity",
|
|
2924
|
-
"shadowRadius",
|
|
2925
|
-
"elevation",
|
|
2926
|
-
"includeFontPadding",
|
|
2927
|
-
"textAlignVertical",
|
|
2928
|
-
"writingDirection",
|
|
2929
|
-
"textShadowColor",
|
|
2930
|
-
"textShadowOffset",
|
|
2931
|
-
"textShadowRadius",
|
|
2932
|
-
"tintColor",
|
|
2933
|
-
"__divideX",
|
|
2934
|
-
"__divideY",
|
|
2935
|
-
"__divideColor",
|
|
2936
|
-
"__divideStyle",
|
|
2937
|
-
"__keyframe",
|
|
2938
|
-
"__spaceX",
|
|
2939
|
-
"__spaceY"
|
|
2940
|
-
]);
|
|
2941
|
-
var CSS_UNITLESS = /* @__PURE__ */ new Set([
|
|
2942
|
-
"opacity",
|
|
2943
|
-
"fontWeight",
|
|
2944
|
-
"flex",
|
|
2945
|
-
"flexGrow",
|
|
2946
|
-
"flexShrink",
|
|
2947
|
-
"order",
|
|
2948
|
-
"zIndex",
|
|
2949
|
-
"aspectRatio",
|
|
2950
|
-
"columnCount",
|
|
2951
|
-
"lineHeight",
|
|
2952
|
-
"gridColumnStart",
|
|
2953
|
-
"gridColumnEnd",
|
|
2954
|
-
"gridRowStart",
|
|
2955
|
-
"gridRowEnd"
|
|
2956
|
-
]);
|
|
2957
|
-
var RN_SHORTHAND_EXPAND = {
|
|
2958
|
-
marginHorizontal: ["margin-left", "margin-right"],
|
|
2959
|
-
marginVertical: ["margin-top", "margin-bottom"],
|
|
2960
|
-
paddingHorizontal: ["padding-left", "padding-right"],
|
|
2961
|
-
paddingVertical: ["padding-top", "padding-bottom"]
|
|
2962
|
-
};
|
|
2963
|
-
function styleValueToCSS(styles, forceImportant = false) {
|
|
2964
|
-
const parts = [];
|
|
2965
|
-
for (const [prop, val] of Object.entries(styles)) {
|
|
2966
|
-
if (val === void 0 || val === null || typeof val === "object" || RN_ONLY_PROPS.has(prop)) continue;
|
|
2967
|
-
let cssVal;
|
|
2968
|
-
if (typeof val === "number") {
|
|
2969
|
-
const isCustomProp = prop.startsWith("--");
|
|
2970
|
-
cssVal = val === 0 || isCustomProp || CSS_UNITLESS.has(prop) ? String(val) : `${val}px`;
|
|
2971
|
-
} else {
|
|
2972
|
-
cssVal = String(val);
|
|
2973
|
-
}
|
|
2974
|
-
const imp = forceImportant || prop === "display" && (cssVal === "grid" || cssVal === "inline-grid") || prop === "position" && (cssVal === "sticky" || cssVal === "fixed" || cssVal === "static") ? " !important" : "";
|
|
2975
|
-
if (prop in RN_SHORTHAND_EXPAND) {
|
|
2976
|
-
const [p1, p2] = RN_SHORTHAND_EXPAND[prop];
|
|
2977
|
-
parts.push(`${p1}: ${cssVal}${imp}`, `${p2}: ${cssVal}${imp}`);
|
|
2978
|
-
continue;
|
|
2979
|
-
}
|
|
2980
|
-
parts.push(`${camelToKebab(prop)}: ${cssVal}${imp}`);
|
|
2981
|
-
}
|
|
2982
|
-
return parts.join("; ");
|
|
2983
|
-
}
|
|
2984
|
-
function camelToKebab(str) {
|
|
2985
|
-
return str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
2986
|
-
}
|
|
2987
|
-
function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens) {
|
|
2988
|
-
const rules = [];
|
|
2989
|
-
if ("__keyframe" in styles && typeof styles.__keyframe === "string") {
|
|
2990
|
-
rules.push(styles.__keyframe);
|
|
2991
|
-
}
|
|
2992
|
-
const isDivide = "__divideX" in styles || "__divideY" in styles || "__divideColor" in styles || "__divideStyle" in styles;
|
|
2993
|
-
const isSpace = "__spaceX" in styles || "__spaceY" in styles;
|
|
2994
|
-
const isChildCombinator = isDivide || isSpace;
|
|
2995
|
-
const escaped = escapeCSSSelector(cls);
|
|
2996
|
-
const childSuffix = isChildCombinator ? " > * + *" : "";
|
|
2997
|
-
if (bucketKey === "base") {
|
|
2998
|
-
const decls2 = isDivide ? buildDivideDecls(styles, important) : isSpace ? buildSpaceDecls(styles, important) : styleValueToCSS(styles, important);
|
|
2999
|
-
if (!decls2) return rules;
|
|
3000
|
-
rules.push(`.${escaped}${childSuffix} { ${decls2} }`);
|
|
3001
|
-
return rules;
|
|
3002
|
-
}
|
|
3003
|
-
const mods = bucketKey.split(":");
|
|
3004
|
-
let darkScheme;
|
|
3005
|
-
let needsImportant = important;
|
|
3006
|
-
const pseudoParts = [];
|
|
3007
|
-
const ancestorParts = [];
|
|
3008
|
-
const dirParts = [];
|
|
3009
|
-
const mediaWrappers = [];
|
|
3010
|
-
let minWidth = 0;
|
|
3011
|
-
for (const mod of mods) {
|
|
3012
|
-
const def = getModifier(mod);
|
|
3013
|
-
if (!def) continue;
|
|
3014
|
-
if (def.darkScheme) darkScheme = def.darkScheme;
|
|
3015
|
-
if (def.pseudo) pseudoParts.push(def.pseudo);
|
|
3016
|
-
if (def.ancestorSelector) {
|
|
3017
|
-
ancestorParts.push(def.ancestorSelector);
|
|
3018
|
-
needsImportant = true;
|
|
3019
|
-
}
|
|
3020
|
-
if (def.dirSelector) {
|
|
3021
|
-
dirParts.push(def.dirSelector);
|
|
3022
|
-
needsImportant = true;
|
|
3023
|
-
}
|
|
3024
|
-
if (def.mediaQuery) {
|
|
3025
|
-
mediaWrappers.push(`@media ${def.mediaQuery}`);
|
|
3026
|
-
needsImportant = true;
|
|
3027
|
-
}
|
|
3028
|
-
if (def.isResponsive) {
|
|
3029
|
-
const w = screens[mod] ?? 0;
|
|
3030
|
-
if (w > minWidth) minWidth = w;
|
|
3031
|
-
}
|
|
3032
|
-
if (def.forcesImportant) needsImportant = true;
|
|
3033
|
-
}
|
|
3034
|
-
const pseudoSuffix = pseudoParts.join("");
|
|
3035
|
-
const elementSelector = `.${escaped}${pseudoSuffix}${childSuffix}`;
|
|
3036
|
-
const ancestorPrefix = ancestorParts.join("");
|
|
3037
|
-
const dirPrefix = dirParts.join("");
|
|
3038
|
-
const selector = `${dirPrefix}${ancestorPrefix}${elementSelector}`;
|
|
3039
|
-
const decls = isDivide ? buildDivideDecls(styles, needsImportant) : isSpace ? buildSpaceDecls(styles, needsImportant) : styleValueToCSS(styles, needsImportant);
|
|
3040
|
-
if (!decls) return rules;
|
|
3041
|
-
let rule;
|
|
3042
|
-
if (darkScheme === "dark") {
|
|
3043
|
-
if (darkMode === "media") rule = `@media (prefers-color-scheme: dark) { ${selector} { ${decls} } }`;
|
|
3044
|
-
else if (darkMode === "class") rule = `.dark ${selector} { ${decls} }`;
|
|
3045
|
-
else rule = `[data-theme="dark"] ${selector} { ${decls} }`;
|
|
3046
|
-
} else if (darkScheme === "light") {
|
|
3047
|
-
if (darkMode === "media") rule = `@media (prefers-color-scheme: light) { ${selector} { ${decls} } }`;
|
|
3048
|
-
else if (darkMode === "class") rule = `.light ${selector} { ${decls} }`;
|
|
3049
|
-
else rule = `[data-theme="light"] ${selector} { ${decls} }`;
|
|
3050
|
-
} else {
|
|
3051
|
-
rule = `${selector} { ${decls} }`;
|
|
22
|
+
var NOT_A_CLASS_NAME_RE = /[${}]|-$|^[?:&|!"'=<>]+$/;
|
|
23
|
+
function pushTokens(str, into) {
|
|
24
|
+
for (const tok of splitClassTokens(str)) {
|
|
25
|
+
if (tok && !NOT_A_CLASS_NAME_RE.test(tok)) into.add(tok);
|
|
3052
26
|
}
|
|
3053
|
-
for (const mw of mediaWrappers) rule = `${mw} { ${rule} }`;
|
|
3054
|
-
if (minWidth > 0) rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
|
|
3055
|
-
rules.push(rule);
|
|
3056
|
-
return rules;
|
|
3057
27
|
}
|
|
3058
|
-
function
|
|
3059
|
-
const
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
const bucketKey = parsed.modifiers.length === 0 ? "base" : parsed.modifiers.join(":");
|
|
3064
|
-
rules.push(...buildClassCSSRules(parsed.original, bucketKey, styles, darkMode, parsed.important, screens));
|
|
28
|
+
function pushTemplateLiteralBody(body, into) {
|
|
29
|
+
const interpolationRe = /\$\{(?:[^{}]|\{[^{}]*\})*\}/g;
|
|
30
|
+
let im;
|
|
31
|
+
while ((im = interpolationRe.exec(body)) !== null) {
|
|
32
|
+
pushClassLikeStrings(im[0], into);
|
|
3065
33
|
}
|
|
3066
|
-
|
|
34
|
+
pushTokens(body.replace(/\$\{(?:[^{}]|\{[^{}]*\})*\}/g, () => "$"), into);
|
|
3067
35
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overVal !== null && typeof overVal === "object" && !Array.isArray(overVal)) {
|
|
3076
|
-
result[key] = deepMerge(
|
|
3077
|
-
baseVal,
|
|
3078
|
-
overVal
|
|
3079
|
-
);
|
|
3080
|
-
} else if (overVal !== void 0) {
|
|
3081
|
-
result[key] = overVal;
|
|
3082
|
-
}
|
|
36
|
+
function pushClassLikeStrings(text, into) {
|
|
37
|
+
const quotedStringRe = /(["'`])((?:(?!\1).)*)\1/g;
|
|
38
|
+
let qm;
|
|
39
|
+
while ((qm = quotedStringRe.exec(text)) !== null) {
|
|
40
|
+
const [, quote, content] = qm;
|
|
41
|
+
if (quote === "`") pushTemplateLiteralBody(content, into);
|
|
42
|
+
else pushTokens(content, into);
|
|
3083
43
|
}
|
|
3084
|
-
return result;
|
|
3085
44
|
}
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
current = next;
|
|
3094
|
-
}
|
|
3095
|
-
return current;
|
|
3096
|
-
}
|
|
3097
|
-
function resolveOneRef(ref, side) {
|
|
3098
|
-
const slashIdx = ref.indexOf("/");
|
|
3099
|
-
if (slashIdx > 0) {
|
|
3100
|
-
const baseName = ref.slice(0, slashIdx);
|
|
3101
|
-
const opacity = Number(ref.slice(slashIdx + 1));
|
|
3102
|
-
if (!Number.isFinite(opacity)) return null;
|
|
3103
|
-
let baseRef;
|
|
3104
|
-
const entry2 = colors[baseName];
|
|
3105
|
-
if (typeof entry2 === "string") {
|
|
3106
|
-
baseRef = entry2;
|
|
3107
|
-
} else if (isModeAwareColor(entry2)) {
|
|
3108
|
-
if (!side) return null;
|
|
3109
|
-
baseRef = entry2[side];
|
|
3110
|
-
} else if (entry2 && typeof entry2 === "object" && "6" in entry2) {
|
|
3111
|
-
const v = entry2["6"];
|
|
3112
|
-
baseRef = typeof v === "string" ? v : void 0;
|
|
3113
|
-
}
|
|
3114
|
-
if (baseRef === void 0) return null;
|
|
3115
|
-
const baseHex = resolveChain(baseRef, side);
|
|
3116
|
-
const a = opacity > 1 ? opacity / 100 : opacity;
|
|
3117
|
-
return hexToRgba(baseHex, a);
|
|
3118
|
-
}
|
|
3119
|
-
const split = splitColorShadeRef(ref);
|
|
3120
|
-
if (!split) return null;
|
|
3121
|
-
const { name, shade } = split;
|
|
3122
|
-
if (!/^\d+$/.test(shade)) return null;
|
|
3123
|
-
const entry = colors[name];
|
|
3124
|
-
if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
|
|
3125
|
-
const target = entry[shade];
|
|
3126
|
-
return typeof target === "string" ? target : null;
|
|
3127
|
-
}
|
|
3128
|
-
function resolveValue(val) {
|
|
3129
|
-
return typeof val === "string" ? resolveChain(val, null) : { light: resolveChain(val.light, "light"), dark: resolveChain(val.dark, "dark") };
|
|
3130
|
-
}
|
|
3131
|
-
const out = {};
|
|
3132
|
-
for (const [key, val] of Object.entries(colors)) {
|
|
3133
|
-
if (typeof val === "string" || isModeAwareColor(val)) {
|
|
3134
|
-
out[key] = resolveValue(val);
|
|
3135
|
-
} else {
|
|
3136
|
-
const shades = {};
|
|
3137
|
-
for (const [shade, v] of Object.entries(val)) {
|
|
3138
|
-
shades[shade] = resolveValue(v);
|
|
3139
|
-
}
|
|
3140
|
-
out[key] = shades;
|
|
3141
|
-
}
|
|
3142
|
-
}
|
|
3143
|
-
return out;
|
|
45
|
+
var JSX_TAG_RE = /<([a-z][a-zA-Z0-9]*)[\s/>]/g;
|
|
46
|
+
function scanUsedTags(code) {
|
|
47
|
+
const tags = /* @__PURE__ */ new Set();
|
|
48
|
+
let m;
|
|
49
|
+
JSX_TAG_RE.lastIndex = 0;
|
|
50
|
+
while ((m = JSX_TAG_RE.exec(code)) !== null) tags.add(m[1]);
|
|
51
|
+
return tags;
|
|
3144
52
|
}
|
|
3145
|
-
function
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
kbachWarn(`extend.${key} should be an object, got ${typeof value} \u2014 skipped`);
|
|
3161
|
-
}
|
|
3162
|
-
continue;
|
|
3163
|
-
}
|
|
3164
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
3165
|
-
theme[key] = deepMerge(
|
|
3166
|
-
theme[key] ?? {},
|
|
3167
|
-
value
|
|
3168
|
-
);
|
|
3169
|
-
}
|
|
53
|
+
function extractClassStrings(code) {
|
|
54
|
+
const found = /* @__PURE__ */ new Set();
|
|
55
|
+
const simpleRe = /(?:className|kb)=(["'])((?:(?!\1).)*)\1/g;
|
|
56
|
+
let m;
|
|
57
|
+
while ((m = simpleRe.exec(code)) !== null) pushTokens(m[2], found);
|
|
58
|
+
const jsxExprRe = /(?:className|kb)=\{/g;
|
|
59
|
+
while ((m = jsxExprRe.exec(code)) !== null) {
|
|
60
|
+
let depth = 1;
|
|
61
|
+
let i = m.index + m[0].length;
|
|
62
|
+
let block = "";
|
|
63
|
+
while (i < code.length && depth > 0) {
|
|
64
|
+
const ch = code[i];
|
|
65
|
+
if (ch === "{") depth++;
|
|
66
|
+
else if (ch === "}") {
|
|
67
|
+
if (--depth === 0) break;
|
|
3170
68
|
}
|
|
69
|
+
block += ch;
|
|
70
|
+
i++;
|
|
3171
71
|
}
|
|
72
|
+
jsxExprRe.lastIndex = i + 1;
|
|
73
|
+
pushClassLikeStrings(block, found);
|
|
3172
74
|
}
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
const pluginAPI = makePluginAPI(resolved.theme);
|
|
3184
|
-
for (const plugin of resolved.plugins) {
|
|
3185
|
-
plugin(pluginAPI);
|
|
3186
|
-
}
|
|
3187
|
-
const rawSans = theme.fontFamily?.sans;
|
|
3188
|
-
const sansFontValue = Array.isArray(rawSans) ? rawSans[0] : rawSans;
|
|
3189
|
-
const nativeSansFont = sansFontValue?.split(",")[0]?.trim().replace(/^['"]|['"]$/g, "");
|
|
3190
|
-
setDefaultFontFamily(nativeSansFont && nativeSansFont !== "System" ? nativeSansFont : void 0);
|
|
3191
|
-
injectGlobalStyles(resolved.theme);
|
|
3192
|
-
return resolved;
|
|
3193
|
-
}
|
|
3194
|
-
function _selectorToModifierDef(selector) {
|
|
3195
|
-
const s = selector.trim();
|
|
3196
|
-
if (s.startsWith("@media ")) {
|
|
3197
|
-
return { mediaQuery: s.slice(7), jsBehavior: "css-only", forcesImportant: true };
|
|
3198
|
-
}
|
|
3199
|
-
if (s.startsWith("::") || s.startsWith(":") && !s.includes(" ") && !s.includes("&") && !s.includes("(")) {
|
|
3200
|
-
return { pseudo: s, jsBehavior: "css-only", forcesImportant: true };
|
|
3201
|
-
}
|
|
3202
|
-
return { ancestorSelector: s.endsWith(" ") ? s : `${s} `, jsBehavior: "css-only", forcesImportant: true };
|
|
3203
|
-
}
|
|
3204
|
-
function makePluginAPI(theme) {
|
|
3205
|
-
const standalone = getPluginStandaloneMap();
|
|
3206
|
-
return {
|
|
3207
|
-
addUtility(name, styles) {
|
|
3208
|
-
standalone[name] = styles;
|
|
3209
|
-
},
|
|
3210
|
-
addVariant(name, selectorOrDef) {
|
|
3211
|
-
const def = typeof selectorOrDef === "string" ? _selectorToModifierDef(selectorOrDef) : selectorOrDef;
|
|
3212
|
-
registerModifier(name, def);
|
|
3213
|
-
},
|
|
3214
|
-
theme(path, defaultValue) {
|
|
3215
|
-
const parts = path.replace(/\[([^\]]+)\]/g, ".$1").split(".");
|
|
3216
|
-
let current = theme;
|
|
3217
|
-
for (const part of parts) {
|
|
3218
|
-
if (current === null || typeof current !== "object") return defaultValue;
|
|
3219
|
-
current = current[part];
|
|
75
|
+
const classComposerCallRe = /(?:clsx|cn|classnames|cx|kb)\(/g;
|
|
76
|
+
while ((m = classComposerCallRe.exec(code)) !== null) {
|
|
77
|
+
let depth = 1;
|
|
78
|
+
let i = m.index + m[0].length;
|
|
79
|
+
let block = "";
|
|
80
|
+
while (i < code.length && depth > 0) {
|
|
81
|
+
const ch = code[i];
|
|
82
|
+
if (ch === "(") depth++;
|
|
83
|
+
else if (ch === ")") {
|
|
84
|
+
if (--depth === 0) break;
|
|
3220
85
|
}
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
e(className) {
|
|
3224
|
-
return className.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
|
|
86
|
+
block += ch;
|
|
87
|
+
i++;
|
|
3225
88
|
}
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
// src/core/generateTypesDts.ts
|
|
3230
|
-
var HEADER = `// AUTO-GENERATED by Kbach from your kbach.config.js \u2014 do not edit by hand.
|
|
3231
|
-
// Regenerated automatically every time your dev server / Metro picks up a
|
|
3232
|
-
// change to that file. Safe (and recommended) to add to .gitignore.
|
|
3233
|
-
//
|
|
3234
|
-
// Gives useColors()/useSpacing() full autocomplete and typo-catching for your
|
|
3235
|
-
// custom colors/spacing keys with zero manual setup \u2014 see KbachCustomColors'
|
|
3236
|
-
// doc comment in @kbach/react if you'd rather hand-author this instead.
|
|
3237
|
-
import '@kbach/react';
|
|
3238
|
-
`;
|
|
3239
|
-
var IDENT_RE = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
3240
|
-
function propKey(name) {
|
|
3241
|
-
return IDENT_RE.test(name) ? name : JSON.stringify(name);
|
|
3242
|
-
}
|
|
3243
|
-
function generateKbachTypesDts(theme) {
|
|
3244
|
-
const colorLines = [];
|
|
3245
|
-
for (const [name, value] of Object.entries(theme.colors)) {
|
|
3246
|
-
if (name in defaultColors) continue;
|
|
3247
|
-
const isFlat = typeof value === "string" || isModeAwareColor(value);
|
|
3248
|
-
colorLines.push(` ${propKey(name)}: ${isFlat ? "string" : "ColorScale"};`);
|
|
3249
|
-
}
|
|
3250
|
-
const spacingLines = [];
|
|
3251
|
-
for (const key of Object.keys(theme.spacing)) {
|
|
3252
|
-
if (key in defaultTheme.spacing) continue;
|
|
3253
|
-
spacingLines.push(` ${propKey(key)}: true;`);
|
|
89
|
+
classComposerCallRe.lastIndex = i + 1;
|
|
90
|
+
pushClassLikeStrings(block, found);
|
|
3254
91
|
}
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
${colorLines.join("\n")}
|
|
3259
|
-
}` : null,
|
|
3260
|
-
spacingLines.length > 0 ? ` interface KbachCustomSpacing {
|
|
3261
|
-
${spacingLines.join("\n")}
|
|
3262
|
-
}` : null
|
|
3263
|
-
].filter((s) => s !== null).join("\n\n");
|
|
3264
|
-
return `${HEADER}
|
|
3265
|
-
declare module '@kbach/react' {
|
|
3266
|
-
${body}
|
|
3267
|
-
}
|
|
3268
|
-
`;
|
|
3269
|
-
}
|
|
3270
|
-
|
|
3271
|
-
// src/vite-plugin.ts
|
|
3272
|
-
var process2 = processImport;
|
|
3273
|
-
function normPath(p) {
|
|
3274
|
-
const fwd = p.replace(/\\/g, "/");
|
|
3275
|
-
return process2.platform === "win32" ? fwd.toLowerCase() : fwd;
|
|
3276
|
-
}
|
|
3277
|
-
setCSSGenMode(true);
|
|
3278
|
-
var useColor = !!process2.stdout?.isTTY && !process2.env.NO_COLOR;
|
|
3279
|
-
var paint = (code, s) => useColor ? `\x1B[${code}m${s}\x1B[0m` : s;
|
|
3280
|
-
var purple = (s) => paint("35", s);
|
|
3281
|
-
var yellow = (s) => paint("33", s);
|
|
3282
|
-
var dim = (s) => paint("2", s);
|
|
3283
|
-
var bold = (s) => paint("1", s);
|
|
3284
|
-
var TAG = () => `${bold(purple("[kbach]"))}`;
|
|
3285
|
-
function warn(message) {
|
|
3286
|
-
console.warn(`${TAG()} ${yellow(message)}`);
|
|
3287
|
-
}
|
|
3288
|
-
function warnBlock(header, ...lines) {
|
|
3289
|
-
console.warn([`${TAG()} ${yellow(header)}`, ...lines].join("\n"));
|
|
3290
|
-
}
|
|
3291
|
-
function log(message) {
|
|
3292
|
-
console.log(`${TAG()} ${message}`);
|
|
92
|
+
const templateRe = /`([^`]{1,2000})`/g;
|
|
93
|
+
while ((m = templateRe.exec(code)) !== null) pushTemplateLiteralBody(m[1], found);
|
|
94
|
+
return [...found];
|
|
3293
95
|
}
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
96
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "out", ".next", ".output", ".git", ".svn", ".cache", "coverage"]);
|
|
97
|
+
var MAX_SCAN_DEPTH = 10;
|
|
98
|
+
var DEFAULT_FILE_MATCH = /\.(tsx?|jsx?)$/;
|
|
99
|
+
function scanDir(dir, onFile, depth = 0, fileMatch = DEFAULT_FILE_MATCH) {
|
|
100
|
+
if (depth > MAX_SCAN_DEPTH) return;
|
|
101
|
+
let entries;
|
|
102
|
+
try {
|
|
103
|
+
entries = readdirSync(dir);
|
|
104
|
+
} catch {
|
|
105
|
+
return;
|
|
3304
106
|
}
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
}
|
|
3314
|
-
var KBACH_START = "/* kbach:start */";
|
|
3315
|
-
var KBACH_END = "/* kbach:end */";
|
|
3316
|
-
var GROUPS = [
|
|
3317
|
-
["Layout", /^(flex(?!-\d|-auto|-none|-initial|-1)|flex-(col|row|wrap|nowrap)|grid|block|inline|hidden|table|contents|overflow|items-|justify-|self-|place-|grow|shrink|float-|clear-|static|fixed|absolute|relative|sticky|z-|top-|right-|bottom-|left-|inset|aspect)/],
|
|
3318
|
-
["Sizing", /^(w-|h-|min-w-|max-w-|min-h-|max-h-|size-|flex-1|flex-auto|flex-none|flex-initial|basis-)/],
|
|
3319
|
-
["Spacing", /^(p-|px-|py-|pt-|pb-|pl-|pr-|m-|mx-|my-|mt-|mb-|ml-|mr-|gap-|space-)/],
|
|
3320
|
-
["Typography", /^(text-(xs|sm|base|lg|\dxl)|font-|leading-|tracking-|uppercase|lowercase|capitalize|normal-case|italic|not-italic|underline|overline|line-through|no-underline|truncate|whitespace-|text-(left|center|right|justify|start|end)|list-|align-|line-clamp)/],
|
|
3321
|
-
["Colors", /^(bg-|text-|color-|fill-|stroke-|caret-|accent-)/],
|
|
3322
|
-
["Borders", /^(border|rounded|ring|outline|divide)/],
|
|
3323
|
-
["Effects", /^(shadow|opacity|blur|brightness|contrast|grayscale|transition|duration|ease|delay|animate|scale|rotate|translate|transform|cursor|pointer|select-)/]
|
|
3324
|
-
];
|
|
3325
|
-
var GROUP_ORDER = ["Layout", "Sizing", "Spacing", "Typography", "Colors", "Borders", "Effects", "Utilities", "Dark Mode", "Responsive"];
|
|
3326
|
-
function classifyToken(token, responsiveRe) {
|
|
3327
|
-
if (/^dark:/.test(token)) return "Dark Mode";
|
|
3328
|
-
if (responsiveRe.test(token)) return "Responsive";
|
|
3329
|
-
const parsed = parseClass(token);
|
|
3330
|
-
const base = parsed ? parsed.value ? `${parsed.utility}-${parsed.value}` : parsed.utility : token;
|
|
3331
|
-
for (const [label, re] of GROUPS) {
|
|
3332
|
-
if (re.test(base)) return label;
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
if (entry.startsWith(".") || SKIP_DIRS.has(entry)) continue;
|
|
109
|
+
const full = join(dir, entry);
|
|
110
|
+
try {
|
|
111
|
+
const st = statSync(full);
|
|
112
|
+
if (st.isDirectory()) scanDir(full, onFile, depth + 1, fileMatch);
|
|
113
|
+
else if (fileMatch.test(entry)) onFile(full, readFileSync(full, "utf-8"));
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
3333
116
|
}
|
|
3334
|
-
return "Utilities";
|
|
3335
117
|
}
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
118
|
+
|
|
119
|
+
// src/vite-plugin/cssVars.ts
|
|
120
|
+
function hexToRgbTriplet(hex) {
|
|
121
|
+
const h = hex.replace("#", "");
|
|
122
|
+
const expand = (s) => s.length === 3 ? s.split("").map((c) => c + c).join("") : s;
|
|
123
|
+
const full = expand(h);
|
|
124
|
+
if (full.length !== 6) return null;
|
|
125
|
+
const r = parseInt(full.slice(0, 2), 16);
|
|
126
|
+
const g = parseInt(full.slice(2, 4), 16);
|
|
127
|
+
const b = parseInt(full.slice(4, 6), 16);
|
|
128
|
+
if ([r, g, b].some((n) => Number.isNaN(n))) return null;
|
|
129
|
+
return `${r},${g},${b}`;
|
|
130
|
+
}
|
|
131
|
+
function buildColorVarMap(theme, cssText) {
|
|
3341
132
|
const replacements = /* @__PURE__ */ new Map();
|
|
3342
133
|
const declarations = /* @__PURE__ */ new Map();
|
|
3343
|
-
for (const [name,
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
const
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
const rgbVarName = `--color-${fullName}-rgb`;
|
|
3358
|
-
replacements.set(rgbaPrefix, `rgba(var(${rgbVarName}),`);
|
|
3359
|
-
declarations.set(rgbVarName, triplet);
|
|
3360
|
-
}
|
|
134
|
+
for (const [name, value] of Object.entries(theme.colors)) {
|
|
135
|
+
if (typeof value !== "string") continue;
|
|
136
|
+
const varName = `--color-${name}`;
|
|
137
|
+
if (cssText.includes(value)) {
|
|
138
|
+
replacements.set(value, `var(${varName})`);
|
|
139
|
+
declarations.set(varName, value);
|
|
140
|
+
}
|
|
141
|
+
const triplet = hexToRgbTriplet(value);
|
|
142
|
+
if (!triplet) continue;
|
|
143
|
+
const rgbaPrefix = `rgba(${triplet},`;
|
|
144
|
+
if (cssText.includes(rgbaPrefix)) {
|
|
145
|
+
const rgbVarName = `--color-${name}-rgb`;
|
|
146
|
+
replacements.set(rgbaPrefix, `rgba(var(${rgbVarName}),`);
|
|
147
|
+
declarations.set(rgbVarName, triplet);
|
|
3361
148
|
}
|
|
3362
149
|
}
|
|
3363
150
|
return { replacements, declarations };
|
|
@@ -3385,20 +172,19 @@ var SPACING_PROPS = /* @__PURE__ */ new Set([
|
|
|
3385
172
|
"top",
|
|
3386
173
|
"right",
|
|
3387
174
|
"bottom",
|
|
3388
|
-
"left"
|
|
3389
|
-
"flex-basis"
|
|
175
|
+
"left"
|
|
3390
176
|
]);
|
|
3391
|
-
function buildSpacingVarMap(theme,
|
|
3392
|
-
const pxToKey = /* @__PURE__ */ new Map();
|
|
3393
|
-
for (const [key, val] of Object.entries(theme.spacing ?? {})) {
|
|
3394
|
-
if (typeof val === "number" && !pxToKey.has(val)) pxToKey.set(val, key);
|
|
3395
|
-
}
|
|
177
|
+
function buildSpacingVarMap(theme, cssText) {
|
|
3396
178
|
const replacements = /* @__PURE__ */ new Map();
|
|
3397
179
|
const declarations = /* @__PURE__ */ new Map();
|
|
180
|
+
const pxToKey = /* @__PURE__ */ new Map();
|
|
181
|
+
for (const [key, val] of Object.entries(theme.spacing)) {
|
|
182
|
+
if (!pxToKey.has(val)) pxToKey.set(val, key);
|
|
183
|
+
}
|
|
3398
184
|
const varNameFor = (key) => `--spacing-${key.replace(/\./g, "_")}`;
|
|
3399
185
|
const declRe = /([a-z-]+): (\d+(?:\.\d+)?)px/g;
|
|
3400
186
|
let m;
|
|
3401
|
-
while ((m = declRe.exec(
|
|
187
|
+
while ((m = declRe.exec(cssText)) !== null) {
|
|
3402
188
|
const [, prop, numStr] = m;
|
|
3403
189
|
if (!SPACING_PROPS.has(prop)) continue;
|
|
3404
190
|
const key = pxToKey.get(parseFloat(numStr));
|
|
@@ -3407,17 +193,53 @@ function buildSpacingVarMap(theme, usedCSS) {
|
|
|
3407
193
|
replacements.set(`${prop}: ${numStr}px`, `${prop}: var(${varName})`);
|
|
3408
194
|
declarations.set(varName, `${numStr}px`);
|
|
3409
195
|
}
|
|
3410
|
-
const transformRe = /(translateX|translateY)\((\d+(?:\.\d+)?)px\)/g;
|
|
3411
|
-
while ((m = transformRe.exec(usedCSS)) !== null) {
|
|
3412
|
-
const [, fn, numStr] = m;
|
|
3413
|
-
const key = pxToKey.get(parseFloat(numStr));
|
|
3414
|
-
if (key === void 0) continue;
|
|
3415
|
-
const varName = varNameFor(key);
|
|
3416
|
-
replacements.set(`${fn}(${numStr}px)`, `${fn}(var(${varName}))`);
|
|
3417
|
-
declarations.set(varName, `${numStr}px`);
|
|
3418
|
-
}
|
|
3419
196
|
return { replacements, declarations };
|
|
3420
197
|
}
|
|
198
|
+
function applyVarMap(cssText, ...maps) {
|
|
199
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
200
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
201
|
+
for (const map of maps) {
|
|
202
|
+
for (const [k, v] of map.replacements) replacements.set(k, v);
|
|
203
|
+
for (const [k, v] of map.declarations) declarations.set(k, v);
|
|
204
|
+
}
|
|
205
|
+
const sorted = [...replacements].sort(([a], [b]) => b.length - a.length);
|
|
206
|
+
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
207
|
+
const patterns = sorted.map(([pattern, replacement]) => [new RegExp(escapeRegex(pattern), "g"), replacement]);
|
|
208
|
+
const text = cssText.replace(/\{([^{}]*)\}/g, (_whole, inner) => {
|
|
209
|
+
let replaced = inner;
|
|
210
|
+
for (const [re, replacement] of patterns) {
|
|
211
|
+
replaced = replaced.replace(re, () => replacement);
|
|
212
|
+
}
|
|
213
|
+
return `{${replaced}}`;
|
|
214
|
+
});
|
|
215
|
+
return { text, declarations };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/vite-plugin/mediaMerge.ts
|
|
219
|
+
var RESPONSIVE_MEDIA_RE = /^@media \(min-width: (\d+)px\) \{ (.+) \}$/;
|
|
220
|
+
function mergeResponsiveMediaBlocks(rules) {
|
|
221
|
+
const byWidth = /* @__PURE__ */ new Map();
|
|
222
|
+
const widthOrder = [];
|
|
223
|
+
const unwrapped = [];
|
|
224
|
+
for (const rule of rules) {
|
|
225
|
+
const m = RESPONSIVE_MEDIA_RE.exec(rule);
|
|
226
|
+
if (!m) {
|
|
227
|
+
unwrapped.push(rule);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const width = Number(m[1]);
|
|
231
|
+
if (!byWidth.has(width)) {
|
|
232
|
+
byWidth.set(width, []);
|
|
233
|
+
widthOrder.push(width);
|
|
234
|
+
}
|
|
235
|
+
byWidth.get(width).push(m[2]);
|
|
236
|
+
}
|
|
237
|
+
widthOrder.sort((a, b) => a - b);
|
|
238
|
+
const merged = widthOrder.map((w) => `@media (min-width: ${w}px) { ${byWidth.get(w).join(" ")} }`);
|
|
239
|
+
return [...unwrapped, ...merged];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/vite-plugin/prettify.ts
|
|
3421
243
|
function prettifyCSS(css) {
|
|
3422
244
|
const out = [];
|
|
3423
245
|
let depth = 0;
|
|
@@ -3446,106 +268,35 @@ function prettifyCSS(css) {
|
|
|
3446
268
|
if (trailing) out.push(trailing);
|
|
3447
269
|
return out.join("\n");
|
|
3448
270
|
}
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
const
|
|
3455
|
-
const
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
const
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
const parsedToken = parseClass(token);
|
|
3467
|
-
const bucketKey = parsedToken && parsedToken.modifiers.length > 0 ? parsedToken.modifiers.join(":") : "base";
|
|
3468
|
-
groups.get(label).push({ order: getModifierOrder(bucketKey), css: prettifyCSS(applyVars(css)) });
|
|
3469
|
-
}
|
|
3470
|
-
const out = ["/* Generated by Kbach \u2014 do not edit */"];
|
|
271
|
+
|
|
272
|
+
// src/vite-plugin/format.ts
|
|
273
|
+
var KBACH_START = "/* kbach:start */";
|
|
274
|
+
var KBACH_END = "/* kbach:end */";
|
|
275
|
+
function formatKbachCSS(tokenRules, theme, usedTags) {
|
|
276
|
+
const allEntries = [];
|
|
277
|
+
for (const rules of tokenRules.values()) {
|
|
278
|
+
for (const entry of rules) allEntries.push(entry);
|
|
279
|
+
}
|
|
280
|
+
allEntries.sort((a, b) => a.order - b.order);
|
|
281
|
+
const allRules = allEntries.map((e) => e.rule);
|
|
282
|
+
const merged = mergeResponsiveMediaBlocks(allRules);
|
|
283
|
+
const compact = merged.join("\n");
|
|
284
|
+
const colorMap = buildColorVarMap(theme, compact);
|
|
285
|
+
const spacingMap = buildSpacingVarMap(theme, compact);
|
|
286
|
+
const { text, declarations } = applyVarMap(compact, colorMap, spacingMap);
|
|
287
|
+
const lines = ["/* Generated by Kbach \u2014 do not edit */", "", buildResetCSS(usedTags)];
|
|
3471
288
|
if (declarations.size > 0) {
|
|
3472
|
-
|
|
3473
|
-
for (const [varName, val] of declarations)
|
|
3474
|
-
|
|
3475
|
-
}
|
|
3476
|
-
const globalCSS = buildThemeGlobal(theme);
|
|
3477
|
-
if (globalCSS) out.push(`
|
|
3478
|
-
/* Global */
|
|
3479
|
-
${prettifyCSS(globalCSS)}`);
|
|
3480
|
-
for (const label of GROUP_ORDER) {
|
|
3481
|
-
const items = groups.get(label) ?? [];
|
|
3482
|
-
if (!items.length) continue;
|
|
3483
|
-
const sorted = [...items].sort((a, b) => a.order - b.order);
|
|
3484
|
-
out.push(`
|
|
3485
|
-
/* ${label} */`);
|
|
3486
|
-
out.push(sorted.map((it) => it.css).join("\n\n"));
|
|
3487
|
-
}
|
|
3488
|
-
return out.join("\n");
|
|
3489
|
-
}
|
|
3490
|
-
function buildThemeGlobal(theme) {
|
|
3491
|
-
const lines = [BASE_RESET];
|
|
3492
|
-
const ff = theme.fontFamily;
|
|
3493
|
-
if (ff?.sans && ff.sans !== "System") {
|
|
3494
|
-
const family = Array.isArray(ff.sans) ? ff.sans.join(", ") : ff.sans;
|
|
3495
|
-
lines.push(`body { font-family: ${family}; }`);
|
|
289
|
+
lines.push("", ":root {");
|
|
290
|
+
for (const [varName, val] of declarations) lines.push(` ${varName}: ${val};`);
|
|
291
|
+
lines.push("}");
|
|
3496
292
|
}
|
|
293
|
+
lines.push("", prettifyCSS(text));
|
|
3497
294
|
return lines.join("\n");
|
|
3498
295
|
}
|
|
3499
|
-
|
|
3500
|
-
"node_modules",
|
|
3501
|
-
"dist",
|
|
3502
|
-
"build",
|
|
3503
|
-
"out",
|
|
3504
|
-
".next",
|
|
3505
|
-
".nuxt",
|
|
3506
|
-
".output",
|
|
3507
|
-
".git",
|
|
3508
|
-
".svn",
|
|
3509
|
-
".cache",
|
|
3510
|
-
"coverage",
|
|
3511
|
-
"__pycache__"
|
|
3512
|
-
]);
|
|
3513
|
-
function findKbachCSS(root) {
|
|
3514
|
-
const found = [];
|
|
3515
|
-
function scan(dir, depth) {
|
|
3516
|
-
if (depth > 10) return;
|
|
3517
|
-
let entries;
|
|
3518
|
-
try {
|
|
3519
|
-
entries = readdirSync(dir);
|
|
3520
|
-
} catch {
|
|
3521
|
-
return;
|
|
3522
|
-
}
|
|
3523
|
-
for (const entry of entries) {
|
|
3524
|
-
if (entry.startsWith(".") || SKIP_DIRS.has(entry)) continue;
|
|
3525
|
-
const full = join(dir, entry);
|
|
3526
|
-
try {
|
|
3527
|
-
const st = statSync(full);
|
|
3528
|
-
if (st.isDirectory()) scan(full, depth + 1);
|
|
3529
|
-
else if (entry === "kbach.css") found.push(full);
|
|
3530
|
-
} catch {
|
|
3531
|
-
}
|
|
3532
|
-
}
|
|
3533
|
-
}
|
|
3534
|
-
scan(root, 0);
|
|
3535
|
-
if (found.length === 0) return null;
|
|
3536
|
-
found.sort((a, b) => a.split(/[\\/]/g).length - b.split(/[\\/]/g).length);
|
|
3537
|
-
if (found.length > 1) {
|
|
3538
|
-
warnBlock(
|
|
3539
|
-
`Multiple kbach.css found, using the shallowest \u2014 remove the rest:`,
|
|
3540
|
-
...found.map((f) => dim(` ${f}`))
|
|
3541
|
-
);
|
|
3542
|
-
}
|
|
3543
|
-
return found[0];
|
|
3544
|
-
}
|
|
3545
|
-
function writeKbachToFile(filePath, css) {
|
|
296
|
+
function writeKbachToFile(filePath, css, readFile2, writeFile2) {
|
|
3546
297
|
let existing = "";
|
|
3547
298
|
try {
|
|
3548
|
-
existing =
|
|
299
|
+
existing = readFile2(filePath);
|
|
3549
300
|
} catch {
|
|
3550
301
|
}
|
|
3551
302
|
const block = `${KBACH_START}
|
|
@@ -3557,322 +308,857 @@ ${KBACH_END}`;
|
|
|
3557
308
|
|
|
3558
309
|
${block}` : block;
|
|
3559
310
|
if (next === existing) return false;
|
|
3560
|
-
|
|
311
|
+
writeFile2(filePath, next);
|
|
3561
312
|
return true;
|
|
3562
313
|
}
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
314
|
+
|
|
315
|
+
// src/vite-plugin/unknownClassWarnings.ts
|
|
316
|
+
import { join as join2 } from "path";
|
|
317
|
+
var CSS_CLASS_SELECTOR_RE = /\.(-?[a-zA-Z_][a-zA-Z0-9_-]*)/g;
|
|
318
|
+
var CSS_FILE_RE = /\.(css|scss|sass|less)$/;
|
|
319
|
+
var useColor = !!process.stdout?.isTTY && !process.env.NO_COLOR;
|
|
320
|
+
var paint = (code, s) => useColor ? `\x1B[${code}m${s}\x1B[0m` : s;
|
|
321
|
+
var green = (s) => paint("32", s);
|
|
322
|
+
var blue = (s) => paint("34", s);
|
|
323
|
+
var white = (s) => paint("97", s);
|
|
324
|
+
var gray = (s) => paint("90", s);
|
|
325
|
+
var bold = (s) => paint("1", s);
|
|
326
|
+
var ARROW = () => green("\u2192");
|
|
327
|
+
var TAG = () => bold(green("[kbach]"));
|
|
328
|
+
var highlight = (s) => bold(white(s));
|
|
329
|
+
function findLineCol(code, needle) {
|
|
330
|
+
const index = code.indexOf(needle);
|
|
331
|
+
if (index === -1) return null;
|
|
332
|
+
let line = 1;
|
|
333
|
+
let lastNewline = -1;
|
|
334
|
+
for (let i = 0; i < index; i++) {
|
|
335
|
+
if (code.charCodeAt(i) === 10) {
|
|
336
|
+
line++;
|
|
337
|
+
lastNewline = i;
|
|
3581
338
|
}
|
|
3582
|
-
} catch {
|
|
3583
339
|
}
|
|
340
|
+
return { line, column: index - lastNewline };
|
|
3584
341
|
}
|
|
3585
|
-
function
|
|
3586
|
-
const
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
}
|
|
3590
|
-
return out;
|
|
342
|
+
function scanCssFileInto(code, into) {
|
|
343
|
+
const re = new RegExp(CSS_CLASS_SELECTOR_RE.source, "g");
|
|
344
|
+
let m;
|
|
345
|
+
while ((m = re.exec(code)) !== null) into.add(m[1]);
|
|
3591
346
|
}
|
|
3592
|
-
function
|
|
3593
|
-
const
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
pushClassLikeStrings(im[0], into);
|
|
347
|
+
function scanProjectCssSelectors(root, includeDirs) {
|
|
348
|
+
const projectCssClasses = /* @__PURE__ */ new Set();
|
|
349
|
+
for (const dir of includeDirs) {
|
|
350
|
+
scanDir(join2(root, dir), (_filePath, code) => scanCssFileInto(code, projectCssClasses), 0, CSS_FILE_RE);
|
|
3597
351
|
}
|
|
3598
|
-
|
|
352
|
+
return projectCssClasses;
|
|
3599
353
|
}
|
|
3600
|
-
function
|
|
3601
|
-
|
|
3602
|
-
let qm;
|
|
3603
|
-
while ((qm = quotedStringRe.exec(text)) !== null) {
|
|
3604
|
-
const [, quote, content] = qm;
|
|
3605
|
-
if (quote === "`") pushTemplateLiteralBody(content, into);
|
|
3606
|
-
else pushTokens(content, into);
|
|
3607
|
-
}
|
|
354
|
+
function stripModifierPrefix(token) {
|
|
355
|
+
return token.replace(/^(?:[a-zA-Z0-9_/-]+:)+/, "");
|
|
3608
356
|
}
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
if (ch === "{") depth++;
|
|
3622
|
-
else if (ch === "}") {
|
|
3623
|
-
if (--depth === 0) break;
|
|
3624
|
-
}
|
|
3625
|
-
block += ch;
|
|
3626
|
-
i++;
|
|
3627
|
-
}
|
|
3628
|
-
jsxExprRe.lastIndex = i + 1;
|
|
3629
|
-
pushClassLikeStrings(block, found);
|
|
3630
|
-
}
|
|
3631
|
-
const clsxCallRe = /(?:clsx|cn|classnames|cx)\(/g;
|
|
3632
|
-
while ((m = clsxCallRe.exec(code)) !== null) {
|
|
3633
|
-
let depth = 1;
|
|
3634
|
-
let i = m.index + m[0].length;
|
|
3635
|
-
let block = "";
|
|
3636
|
-
while (i < code.length && depth > 0) {
|
|
3637
|
-
const ch = code[i];
|
|
3638
|
-
if (ch === "(") depth++;
|
|
3639
|
-
else if (ch === ")") {
|
|
3640
|
-
if (--depth === 0) break;
|
|
3641
|
-
}
|
|
3642
|
-
block += ch;
|
|
3643
|
-
i++;
|
|
3644
|
-
}
|
|
3645
|
-
clsxCallRe.lastIndex = i + 1;
|
|
3646
|
-
pushClassLikeStrings(block, found);
|
|
3647
|
-
}
|
|
3648
|
-
const templateRe = /`([^`]{1,2000})`/g;
|
|
3649
|
-
while ((m = templateRe.exec(code)) !== null) pushTemplateLiteralBody(m[1], found);
|
|
3650
|
-
return [...found];
|
|
357
|
+
var MARKER_CLASSES = /* @__PURE__ */ new Set(["group", "peer"]);
|
|
358
|
+
function warnIfUnknownClass(token, filePath, code, isResolvable, projectCssClasses, warnedTokens) {
|
|
359
|
+
if (isResolvable || warnedTokens.has(token)) return;
|
|
360
|
+
const base = stripModifierPrefix(token);
|
|
361
|
+
if (!base || projectCssClasses.has(base) || MARKER_CLASSES.has(base)) return;
|
|
362
|
+
warnedTokens.add(token);
|
|
363
|
+
const pos = findLineCol(code, token);
|
|
364
|
+
const location = pos ? `${blue(filePath)}${green(`:${pos.line}:${pos.column}`)}` : blue(filePath);
|
|
365
|
+
console.warn(
|
|
366
|
+
`${ARROW()} ${TAG()} ${gray("Unknown class")} ${highlight(token)} ${gray("\u2014 no Kbach utility or project CSS rule matches it. Typo?")}
|
|
367
|
+
${bold("at")} ${location}`
|
|
368
|
+
);
|
|
3651
369
|
}
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
370
|
+
|
|
371
|
+
// src/vite-plugin/classNameHints.ts
|
|
372
|
+
var STRUCTURAL_TOKENS = [
|
|
373
|
+
// layout.rs
|
|
374
|
+
"flex",
|
|
375
|
+
"flex-row",
|
|
376
|
+
"flex-col",
|
|
377
|
+
"flex-row-reverse",
|
|
378
|
+
"flex-col-reverse",
|
|
379
|
+
"flex-wrap",
|
|
380
|
+
"flex-wrap-reverse",
|
|
381
|
+
"flex-nowrap",
|
|
382
|
+
"flex-1",
|
|
383
|
+
"flex-auto",
|
|
384
|
+
"flex-initial",
|
|
385
|
+
"flex-none",
|
|
386
|
+
"flex-grow",
|
|
387
|
+
"flex-grow-0",
|
|
388
|
+
"flex-shrink",
|
|
389
|
+
"flex-shrink-0",
|
|
390
|
+
"grow",
|
|
391
|
+
"grow-0",
|
|
392
|
+
"shrink",
|
|
393
|
+
"shrink-0",
|
|
394
|
+
"grid",
|
|
395
|
+
"block",
|
|
396
|
+
"inline-block",
|
|
397
|
+
"inline",
|
|
398
|
+
"inline-flex",
|
|
399
|
+
"inline-grid",
|
|
400
|
+
"contents",
|
|
401
|
+
"flow-root",
|
|
402
|
+
"hidden",
|
|
403
|
+
"items-center",
|
|
404
|
+
"items-start",
|
|
405
|
+
"items-end",
|
|
406
|
+
"items-baseline",
|
|
407
|
+
"items-stretch",
|
|
408
|
+
"justify-center",
|
|
409
|
+
"justify-start",
|
|
410
|
+
"justify-end",
|
|
411
|
+
"justify-between",
|
|
412
|
+
"justify-around",
|
|
413
|
+
"justify-evenly",
|
|
414
|
+
"content-start",
|
|
415
|
+
"content-end",
|
|
416
|
+
"content-center",
|
|
417
|
+
"content-between",
|
|
418
|
+
"content-around",
|
|
419
|
+
"content-evenly",
|
|
420
|
+
"content-stretch",
|
|
421
|
+
"self-auto",
|
|
422
|
+
"self-center",
|
|
423
|
+
"self-start",
|
|
424
|
+
"self-end",
|
|
425
|
+
"self-stretch",
|
|
426
|
+
"self-baseline",
|
|
427
|
+
"overflow-hidden",
|
|
428
|
+
"overflow-auto",
|
|
429
|
+
"overflow-scroll",
|
|
430
|
+
"overflow-visible",
|
|
431
|
+
"static",
|
|
432
|
+
"relative",
|
|
433
|
+
"absolute",
|
|
434
|
+
"fixed",
|
|
435
|
+
"sticky",
|
|
436
|
+
"aspect-square",
|
|
437
|
+
"aspect-video",
|
|
438
|
+
"w-full",
|
|
439
|
+
"h-full",
|
|
440
|
+
"min-w-full",
|
|
441
|
+
"max-w-full",
|
|
442
|
+
"min-h-full",
|
|
443
|
+
"max-h-full",
|
|
444
|
+
"w-screen",
|
|
445
|
+
"h-screen",
|
|
446
|
+
"min-w-screen",
|
|
447
|
+
"max-w-screen",
|
|
448
|
+
"min-h-screen",
|
|
449
|
+
"max-h-screen",
|
|
450
|
+
"w-auto",
|
|
451
|
+
"h-auto",
|
|
452
|
+
"m-auto",
|
|
453
|
+
"mx-auto",
|
|
454
|
+
"my-auto",
|
|
455
|
+
// grid.rs — web-only (see the module's own doc comment for why)
|
|
456
|
+
"grid-cols-none",
|
|
457
|
+
"grid-rows-none",
|
|
458
|
+
"grid-flow-row",
|
|
459
|
+
"grid-flow-col",
|
|
460
|
+
"grid-flow-dense",
|
|
461
|
+
"grid-flow-row-dense",
|
|
462
|
+
"grid-flow-col-dense",
|
|
463
|
+
"auto-cols-auto",
|
|
464
|
+
"auto-cols-min",
|
|
465
|
+
"auto-cols-max",
|
|
466
|
+
"auto-cols-fr",
|
|
467
|
+
"auto-rows-auto",
|
|
468
|
+
"auto-rows-min",
|
|
469
|
+
"auto-rows-max",
|
|
470
|
+
"auto-rows-fr",
|
|
471
|
+
"col-span-full",
|
|
472
|
+
"row-span-full",
|
|
473
|
+
"col-start-auto",
|
|
474
|
+
"col-end-auto",
|
|
475
|
+
"row-start-auto",
|
|
476
|
+
"row-end-auto",
|
|
477
|
+
"col",
|
|
478
|
+
"col-auto",
|
|
479
|
+
"row",
|
|
480
|
+
"row-auto",
|
|
481
|
+
"place-items-start",
|
|
482
|
+
"place-items-end",
|
|
483
|
+
"place-items-center",
|
|
484
|
+
"place-items-stretch",
|
|
485
|
+
"place-items-baseline",
|
|
486
|
+
"place-content-start",
|
|
487
|
+
"place-content-end",
|
|
488
|
+
"place-content-center",
|
|
489
|
+
"place-content-stretch",
|
|
490
|
+
"place-content-between",
|
|
491
|
+
"place-content-around",
|
|
492
|
+
"place-content-evenly",
|
|
493
|
+
"place-content-baseline",
|
|
494
|
+
"place-self-auto",
|
|
495
|
+
"place-self-start",
|
|
496
|
+
"place-self-end",
|
|
497
|
+
"place-self-center",
|
|
498
|
+
"place-self-stretch",
|
|
499
|
+
"justify-items-start",
|
|
500
|
+
"justify-items-end",
|
|
501
|
+
"justify-items-center",
|
|
502
|
+
"justify-items-stretch",
|
|
503
|
+
"justify-self-auto",
|
|
504
|
+
"justify-self-start",
|
|
505
|
+
"justify-self-end",
|
|
506
|
+
"justify-self-center",
|
|
507
|
+
"justify-self-stretch",
|
|
508
|
+
// transform.rs — web-only (see the module's own doc comment for why)
|
|
509
|
+
"transform-none",
|
|
510
|
+
"origin-center",
|
|
511
|
+
"origin-top",
|
|
512
|
+
"origin-top-right",
|
|
513
|
+
"origin-right",
|
|
514
|
+
"origin-bottom-right",
|
|
515
|
+
"origin-bottom",
|
|
516
|
+
"origin-bottom-left",
|
|
517
|
+
"origin-left",
|
|
518
|
+
"origin-top-left",
|
|
519
|
+
// filters.rs — web-only (see the module's own doc comment for why)
|
|
520
|
+
"blur",
|
|
521
|
+
"blur-sm",
|
|
522
|
+
"blur-md",
|
|
523
|
+
"blur-lg",
|
|
524
|
+
"blur-xl",
|
|
525
|
+
"blur-2xl",
|
|
526
|
+
"blur-3xl",
|
|
527
|
+
"blur-none",
|
|
528
|
+
"grayscale",
|
|
529
|
+
"grayscale-0",
|
|
530
|
+
"invert",
|
|
531
|
+
"invert-0",
|
|
532
|
+
"sepia",
|
|
533
|
+
"sepia-0",
|
|
534
|
+
"drop-shadow",
|
|
535
|
+
"drop-shadow-sm",
|
|
536
|
+
"drop-shadow-md",
|
|
537
|
+
"drop-shadow-lg",
|
|
538
|
+
"drop-shadow-xl",
|
|
539
|
+
"drop-shadow-2xl",
|
|
540
|
+
"drop-shadow-none",
|
|
541
|
+
"filter-none",
|
|
542
|
+
"backdrop-filter-none",
|
|
543
|
+
"backdrop-blur",
|
|
544
|
+
"backdrop-blur-sm",
|
|
545
|
+
"backdrop-blur-md",
|
|
546
|
+
"backdrop-blur-lg",
|
|
547
|
+
"backdrop-blur-xl",
|
|
548
|
+
"backdrop-blur-2xl",
|
|
549
|
+
"backdrop-blur-3xl",
|
|
550
|
+
"backdrop-blur-none",
|
|
551
|
+
"backdrop-grayscale",
|
|
552
|
+
"backdrop-grayscale-0",
|
|
553
|
+
"backdrop-invert",
|
|
554
|
+
"backdrop-invert-0",
|
|
555
|
+
"backdrop-sepia",
|
|
556
|
+
"backdrop-sepia-0",
|
|
557
|
+
// border.rs
|
|
558
|
+
"border",
|
|
559
|
+
"border-t",
|
|
560
|
+
"border-r",
|
|
561
|
+
"border-b",
|
|
562
|
+
"border-l",
|
|
563
|
+
"rounded",
|
|
564
|
+
"rounded-none",
|
|
565
|
+
"rounded-sm",
|
|
566
|
+
"rounded-md",
|
|
567
|
+
"rounded-lg",
|
|
568
|
+
"rounded-xl",
|
|
569
|
+
"rounded-2xl",
|
|
570
|
+
"rounded-3xl",
|
|
571
|
+
"rounded-full",
|
|
572
|
+
"ring",
|
|
573
|
+
"ring-0",
|
|
574
|
+
"ring-1",
|
|
575
|
+
"ring-2",
|
|
576
|
+
"ring-4",
|
|
577
|
+
"ring-8",
|
|
578
|
+
"ring-inset",
|
|
579
|
+
"ring-offset-0",
|
|
580
|
+
"ring-offset-1",
|
|
581
|
+
"ring-offset-2",
|
|
582
|
+
"ring-offset-4",
|
|
583
|
+
"ring-offset-8",
|
|
584
|
+
"outline",
|
|
585
|
+
"outline-none",
|
|
586
|
+
"border-solid",
|
|
587
|
+
"border-dashed",
|
|
588
|
+
"border-dotted",
|
|
589
|
+
"border-none",
|
|
590
|
+
// typography.rs
|
|
591
|
+
"font-thin",
|
|
592
|
+
"font-normal",
|
|
593
|
+
"font-medium",
|
|
594
|
+
"font-semibold",
|
|
595
|
+
"font-bold",
|
|
596
|
+
"font-extrabold",
|
|
597
|
+
"uppercase",
|
|
598
|
+
"lowercase",
|
|
599
|
+
"capitalize",
|
|
600
|
+
"underline",
|
|
601
|
+
"line-through",
|
|
602
|
+
"no-underline",
|
|
603
|
+
"truncate",
|
|
604
|
+
"text-xs",
|
|
605
|
+
"text-sm",
|
|
606
|
+
"text-base",
|
|
607
|
+
"text-lg",
|
|
608
|
+
"text-xl",
|
|
609
|
+
"text-2xl",
|
|
610
|
+
"text-3xl",
|
|
611
|
+
"text-4xl",
|
|
612
|
+
"text-left",
|
|
613
|
+
"text-center",
|
|
614
|
+
"text-right",
|
|
615
|
+
"text-justify",
|
|
616
|
+
// typography.rs — Phase 20 (typography completeness)
|
|
617
|
+
"italic",
|
|
618
|
+
"not-italic",
|
|
619
|
+
"leading-none",
|
|
620
|
+
"leading-tight",
|
|
621
|
+
"leading-snug",
|
|
622
|
+
"leading-normal",
|
|
623
|
+
"leading-relaxed",
|
|
624
|
+
"leading-loose",
|
|
625
|
+
"tracking-tighter",
|
|
626
|
+
"tracking-tight",
|
|
627
|
+
"tracking-normal",
|
|
628
|
+
"tracking-wide",
|
|
629
|
+
"tracking-wider",
|
|
630
|
+
"tracking-widest",
|
|
631
|
+
"decoration-auto",
|
|
632
|
+
"decoration-from-font",
|
|
633
|
+
"decoration-solid",
|
|
634
|
+
"decoration-dashed",
|
|
635
|
+
"decoration-dotted",
|
|
636
|
+
"decoration-double",
|
|
637
|
+
"decoration-wavy",
|
|
638
|
+
"underline-offset-auto",
|
|
639
|
+
"underline-offset-0",
|
|
640
|
+
"underline-offset-1",
|
|
641
|
+
"underline-offset-2",
|
|
642
|
+
"underline-offset-4",
|
|
643
|
+
"underline-offset-8",
|
|
644
|
+
"text-wrap",
|
|
645
|
+
"text-nowrap",
|
|
646
|
+
"text-balance",
|
|
647
|
+
"text-pretty",
|
|
648
|
+
"whitespace-normal",
|
|
649
|
+
"whitespace-nowrap",
|
|
650
|
+
"whitespace-pre",
|
|
651
|
+
"whitespace-pre-wrap",
|
|
652
|
+
"whitespace-pre-line",
|
|
653
|
+
"break-normal",
|
|
654
|
+
"break-words",
|
|
655
|
+
"break-all",
|
|
656
|
+
"align-baseline",
|
|
657
|
+
"align-top",
|
|
658
|
+
"align-middle",
|
|
659
|
+
"align-bottom",
|
|
660
|
+
"align-text-top",
|
|
661
|
+
"align-text-bottom",
|
|
662
|
+
"align-sub",
|
|
663
|
+
"align-super",
|
|
664
|
+
"list-none",
|
|
665
|
+
"list-disc",
|
|
666
|
+
"list-decimal",
|
|
667
|
+
"list-inside",
|
|
668
|
+
"list-outside",
|
|
669
|
+
"hyphens-none",
|
|
670
|
+
"hyphens-manual",
|
|
671
|
+
"hyphens-auto",
|
|
672
|
+
// effects.rs
|
|
673
|
+
"shadow",
|
|
674
|
+
"shadow-sm",
|
|
675
|
+
"shadow-md",
|
|
676
|
+
"shadow-lg",
|
|
677
|
+
"shadow-xl",
|
|
678
|
+
"shadow-2xl",
|
|
679
|
+
"shadow-inner",
|
|
680
|
+
"shadow-none",
|
|
681
|
+
"transition",
|
|
682
|
+
"transition-none",
|
|
683
|
+
"ease-linear",
|
|
684
|
+
"ease-in",
|
|
685
|
+
"ease-out",
|
|
686
|
+
"ease-in-out",
|
|
687
|
+
"cursor-pointer",
|
|
688
|
+
"cursor-default",
|
|
689
|
+
"cursor-not-allowed",
|
|
690
|
+
"cursor-wait",
|
|
691
|
+
"select-none",
|
|
692
|
+
"select-text",
|
|
693
|
+
"select-all",
|
|
694
|
+
"pointer-events-none",
|
|
695
|
+
"pointer-events-auto",
|
|
696
|
+
// effects.rs — Phase 22 (effects completeness)
|
|
697
|
+
"text-shadow",
|
|
698
|
+
"text-shadow-sm",
|
|
699
|
+
"text-shadow-lg",
|
|
700
|
+
"text-shadow-none",
|
|
701
|
+
"mix-blend-normal",
|
|
702
|
+
"mix-blend-multiply",
|
|
703
|
+
"mix-blend-screen",
|
|
704
|
+
"mix-blend-overlay",
|
|
705
|
+
"mix-blend-darken",
|
|
706
|
+
"mix-blend-lighten",
|
|
707
|
+
"mix-blend-color-dodge",
|
|
708
|
+
"mix-blend-color-burn",
|
|
709
|
+
"mix-blend-hard-light",
|
|
710
|
+
"mix-blend-soft-light",
|
|
711
|
+
"mix-blend-difference",
|
|
712
|
+
"mix-blend-exclusion",
|
|
713
|
+
"mix-blend-hue",
|
|
714
|
+
"mix-blend-saturation",
|
|
715
|
+
"mix-blend-color",
|
|
716
|
+
"mix-blend-luminosity",
|
|
717
|
+
"mix-blend-plus-lighter",
|
|
718
|
+
"bg-blend-normal",
|
|
719
|
+
"bg-blend-multiply",
|
|
720
|
+
"bg-blend-screen",
|
|
721
|
+
"bg-blend-overlay",
|
|
722
|
+
"bg-blend-darken",
|
|
723
|
+
"bg-blend-lighten",
|
|
724
|
+
"bg-blend-color-dodge",
|
|
725
|
+
"bg-blend-color-burn",
|
|
726
|
+
"bg-blend-hard-light",
|
|
727
|
+
"bg-blend-soft-light",
|
|
728
|
+
"bg-blend-difference",
|
|
729
|
+
"bg-blend-exclusion",
|
|
730
|
+
"bg-blend-hue",
|
|
731
|
+
"bg-blend-saturation",
|
|
732
|
+
"bg-blend-color",
|
|
733
|
+
"bg-blend-luminosity",
|
|
734
|
+
"bg-blend-plus-lighter",
|
|
735
|
+
"animate-spin",
|
|
736
|
+
"animate-ping",
|
|
737
|
+
"animate-pulse",
|
|
738
|
+
"animate-bounce",
|
|
739
|
+
"animate-none",
|
|
740
|
+
// interactivity.rs — Phase 23 (interactivity & sizing rest)
|
|
741
|
+
"resize",
|
|
742
|
+
"resize-none",
|
|
743
|
+
"resize-y",
|
|
744
|
+
"resize-x",
|
|
745
|
+
"touch-auto",
|
|
746
|
+
"touch-none",
|
|
747
|
+
"touch-pan-x",
|
|
748
|
+
"touch-pan-left",
|
|
749
|
+
"touch-pan-right",
|
|
750
|
+
"touch-pan-y",
|
|
751
|
+
"touch-pan-up",
|
|
752
|
+
"touch-pan-down",
|
|
753
|
+
"touch-pinch-zoom",
|
|
754
|
+
"touch-manipulation",
|
|
755
|
+
"will-change-auto",
|
|
756
|
+
"will-change-scroll",
|
|
757
|
+
"will-change-contents",
|
|
758
|
+
"will-change-transform",
|
|
759
|
+
"sr-only",
|
|
760
|
+
"not-sr-only",
|
|
761
|
+
"border-collapse",
|
|
762
|
+
"border-separate",
|
|
763
|
+
"table-auto",
|
|
764
|
+
"table-fixed",
|
|
765
|
+
"caption-top",
|
|
766
|
+
"caption-bottom",
|
|
767
|
+
"stroke-width-0",
|
|
768
|
+
"stroke-width-1",
|
|
769
|
+
"stroke-width-2",
|
|
770
|
+
// spacing.rs — Phase 23 (size-* shorthand + fraction-based width/height)
|
|
771
|
+
"size-full",
|
|
772
|
+
"size-auto",
|
|
773
|
+
"size-px",
|
|
774
|
+
"w-1/2",
|
|
775
|
+
"w-1/3",
|
|
776
|
+
"w-2/3",
|
|
777
|
+
"w-1/4",
|
|
778
|
+
"w-2/4",
|
|
779
|
+
"w-3/4",
|
|
780
|
+
"w-1/5",
|
|
781
|
+
"w-2/5",
|
|
782
|
+
"w-3/5",
|
|
783
|
+
"w-4/5",
|
|
784
|
+
"w-1/6",
|
|
785
|
+
"w-5/6",
|
|
786
|
+
"w-1/12",
|
|
787
|
+
"w-5/12",
|
|
788
|
+
"w-7/12",
|
|
789
|
+
"w-11/12",
|
|
790
|
+
"h-1/2",
|
|
791
|
+
"h-1/3",
|
|
792
|
+
"h-2/3",
|
|
793
|
+
"h-1/4",
|
|
794
|
+
"h-2/4",
|
|
795
|
+
"h-3/4",
|
|
796
|
+
"h-1/5",
|
|
797
|
+
"h-2/5",
|
|
798
|
+
"h-3/5",
|
|
799
|
+
"h-4/5",
|
|
800
|
+
"h-1/6",
|
|
801
|
+
"h-5/6",
|
|
802
|
+
// scroll.rs — Phase 23 (scroll-behavior/-margin/-padding, scroll-snap)
|
|
803
|
+
"scroll-auto",
|
|
804
|
+
"scroll-smooth",
|
|
805
|
+
"snap-start",
|
|
806
|
+
"snap-end",
|
|
807
|
+
"snap-center",
|
|
808
|
+
"snap-align-none",
|
|
809
|
+
"snap-normal",
|
|
810
|
+
"snap-always",
|
|
811
|
+
"snap-none",
|
|
812
|
+
"snap-x",
|
|
813
|
+
"snap-y",
|
|
814
|
+
"snap-both",
|
|
815
|
+
"snap-mandatory",
|
|
816
|
+
"snap-proximity",
|
|
817
|
+
// divide.rs
|
|
818
|
+
"divide-x",
|
|
819
|
+
"divide-y",
|
|
820
|
+
// background.rs — web-only (see the module's own doc comment for why)
|
|
821
|
+
"bg-top",
|
|
822
|
+
"bg-bottom",
|
|
823
|
+
"bg-left",
|
|
824
|
+
"bg-right",
|
|
825
|
+
"bg-center",
|
|
826
|
+
"bg-left-top",
|
|
827
|
+
"bg-left-bottom",
|
|
828
|
+
"bg-right-top",
|
|
829
|
+
"bg-right-bottom",
|
|
830
|
+
"bg-auto",
|
|
831
|
+
"bg-cover",
|
|
832
|
+
"bg-contain",
|
|
833
|
+
"bg-repeat",
|
|
834
|
+
"bg-no-repeat",
|
|
835
|
+
"bg-repeat-x",
|
|
836
|
+
"bg-repeat-y",
|
|
837
|
+
"bg-repeat-round",
|
|
838
|
+
"bg-repeat-space",
|
|
839
|
+
"bg-fixed",
|
|
840
|
+
"bg-local",
|
|
841
|
+
"bg-scroll",
|
|
842
|
+
"bg-clip-border",
|
|
843
|
+
"bg-clip-padding",
|
|
844
|
+
"bg-clip-content",
|
|
845
|
+
"bg-clip-text",
|
|
846
|
+
"bg-origin-border",
|
|
847
|
+
"bg-origin-padding",
|
|
848
|
+
"bg-origin-content",
|
|
849
|
+
"bg-none",
|
|
850
|
+
"bg-linear-to-t",
|
|
851
|
+
"bg-linear-to-tr",
|
|
852
|
+
"bg-linear-to-r",
|
|
853
|
+
"bg-linear-to-br",
|
|
854
|
+
"bg-linear-to-b",
|
|
855
|
+
"bg-linear-to-bl",
|
|
856
|
+
"bg-linear-to-l",
|
|
857
|
+
"bg-linear-to-tl",
|
|
858
|
+
"bg-radial",
|
|
859
|
+
"bg-conic",
|
|
860
|
+
// Ancestor/sibling-state marker classes — carry no styles of their own,
|
|
861
|
+
// just a selector target for group-hover:/peer-hover:/etc. below (see
|
|
862
|
+
// unknownClassWarnings.ts's MARKER_CLASSES for why they need special
|
|
863
|
+
// handling there too).
|
|
864
|
+
"group",
|
|
865
|
+
"peer",
|
|
866
|
+
// registry.rs modifiers — bare tokens only, not composed with a
|
|
867
|
+
// following utility (see this module's doc header / the Phase 15 plan).
|
|
868
|
+
"hover:",
|
|
869
|
+
"focus:",
|
|
870
|
+
"focus-visible:",
|
|
871
|
+
"focus-within:",
|
|
872
|
+
"active:",
|
|
873
|
+
"visited:",
|
|
874
|
+
"disabled:",
|
|
875
|
+
"checked:",
|
|
876
|
+
"group-hover:",
|
|
877
|
+
"group-focus:",
|
|
878
|
+
"peer-hover:",
|
|
879
|
+
"peer-focus:",
|
|
880
|
+
"peer-checked:",
|
|
881
|
+
"dark:",
|
|
882
|
+
"motion-safe:",
|
|
883
|
+
"motion-reduce:",
|
|
884
|
+
"print:",
|
|
885
|
+
"sm:",
|
|
886
|
+
"md:",
|
|
887
|
+
"lg:",
|
|
888
|
+
"xl:",
|
|
889
|
+
"2xl:",
|
|
890
|
+
// registry.rs modifiers — Phase 24 (expanded variant system), the
|
|
891
|
+
// FIXED/static additions only. Deliberately excluded: every genuinely
|
|
892
|
+
// parameterized modifier (has-[...]/group-has-[...]/peer-has-[...]/
|
|
893
|
+
// data-[...]/aria-[...]/not-[...]/min-[...]/max-[...], and the
|
|
894
|
+
// generalized group-<pseudo>/peer-<pseudo> beyond the five hardcoded
|
|
895
|
+
// combos above) — these have no finite enumerable set (their whole point
|
|
896
|
+
// is arbitrary user-supplied content), so there's nothing meaningful to
|
|
897
|
+
// suggest beyond the bare prefix, same reasoning as every other
|
|
898
|
+
// arbitrary-value exclusion in this file. `not-hover:`/`not-disabled:`/
|
|
899
|
+
// etc. (wrapping a KNOWN static modifier) are excluded for the same
|
|
900
|
+
// reason — enumerable in principle, but a full cross-product with every
|
|
901
|
+
// modifier above would be more noise than signal for an editor hint list.
|
|
902
|
+
"first:",
|
|
903
|
+
"last:",
|
|
904
|
+
"only:",
|
|
905
|
+
"odd:",
|
|
906
|
+
"even:",
|
|
907
|
+
"open:",
|
|
908
|
+
"inert:",
|
|
909
|
+
"aria-checked:",
|
|
910
|
+
"aria-disabled:",
|
|
911
|
+
"aria-expanded:",
|
|
912
|
+
"aria-hidden:",
|
|
913
|
+
"aria-pressed:",
|
|
914
|
+
"aria-readonly:",
|
|
915
|
+
"aria-required:",
|
|
916
|
+
"aria-selected:",
|
|
917
|
+
"aria-busy:",
|
|
918
|
+
// Phase 25 (container queries & arbitrary properties). "@container" is a
|
|
919
|
+
// real UTILITY (container-type: inline-size), not a modifier — included
|
|
920
|
+
// as a bare token like "flex"/"hidden" above, not with the trailing ":"
|
|
921
|
+
// the modifier tokens below get. "@sm:"/"@md:"/"@lg:"/"@xl:"/"@2xl:" are
|
|
922
|
+
// container-responsive modifiers (registry.rs's `is_container_responsive`),
|
|
923
|
+
// and "starting:" wraps in @starting-style. Deliberately excluded, same
|
|
924
|
+
// "no finite enumerable set" reasoning as Phase 24's exclusions:
|
|
925
|
+
// "@min-[...]:"/"@max-[...]:" (arbitrary container breakpoints) and every
|
|
926
|
+
// `[property:value]` arbitrary property — both are open-ended by design.
|
|
927
|
+
"@container",
|
|
928
|
+
"@sm:",
|
|
929
|
+
"@md:",
|
|
930
|
+
"@lg:",
|
|
931
|
+
"@xl:",
|
|
932
|
+
"@2xl:",
|
|
933
|
+
"starting:"
|
|
934
|
+
];
|
|
935
|
+
var COLOR_PREFIXES = [
|
|
936
|
+
"bg-",
|
|
937
|
+
"text-",
|
|
938
|
+
"border-",
|
|
939
|
+
"divide-",
|
|
940
|
+
"decoration-",
|
|
941
|
+
"from-",
|
|
942
|
+
"via-",
|
|
943
|
+
"to-",
|
|
944
|
+
"text-shadow-",
|
|
945
|
+
"ring-",
|
|
946
|
+
"ring-offset-",
|
|
947
|
+
"caret-",
|
|
948
|
+
"accent-",
|
|
949
|
+
"fill-",
|
|
950
|
+
"stroke-"
|
|
951
|
+
];
|
|
952
|
+
var SPACING_PREFIXES = [
|
|
953
|
+
"p-",
|
|
954
|
+
"px-",
|
|
955
|
+
"py-",
|
|
956
|
+
"pt-",
|
|
957
|
+
"pr-",
|
|
958
|
+
"pb-",
|
|
959
|
+
"pl-",
|
|
960
|
+
"m-",
|
|
961
|
+
"mx-",
|
|
962
|
+
"my-",
|
|
963
|
+
"mt-",
|
|
964
|
+
"mr-",
|
|
965
|
+
"mb-",
|
|
966
|
+
"ml-",
|
|
967
|
+
"gap-",
|
|
968
|
+
"gap-x-",
|
|
969
|
+
"gap-y-",
|
|
970
|
+
"w-",
|
|
971
|
+
"h-",
|
|
972
|
+
"min-w-",
|
|
973
|
+
"max-w-",
|
|
974
|
+
"min-h-",
|
|
975
|
+
"max-h-",
|
|
976
|
+
"size-",
|
|
977
|
+
"top-",
|
|
978
|
+
"right-",
|
|
979
|
+
"bottom-",
|
|
980
|
+
"left-",
|
|
981
|
+
"inset-",
|
|
982
|
+
"space-x-",
|
|
983
|
+
"space-y-",
|
|
984
|
+
"indent-",
|
|
985
|
+
"scroll-m-",
|
|
986
|
+
"scroll-mx-",
|
|
987
|
+
"scroll-my-",
|
|
988
|
+
"scroll-mt-",
|
|
989
|
+
"scroll-mr-",
|
|
990
|
+
"scroll-mb-",
|
|
991
|
+
"scroll-ml-",
|
|
992
|
+
"scroll-p-",
|
|
993
|
+
"scroll-px-",
|
|
994
|
+
"scroll-py-",
|
|
995
|
+
"scroll-pt-",
|
|
996
|
+
"scroll-pr-",
|
|
997
|
+
"scroll-pb-",
|
|
998
|
+
"scroll-pl-"
|
|
999
|
+
];
|
|
1000
|
+
var SIZE_PREFIXES = ["w-", "h-", "min-w-", "max-w-", "min-h-", "max-h-", "size-"];
|
|
1001
|
+
var NAMED_SIZES = ["sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl", "8xl", "9xl"];
|
|
1002
|
+
function buildClassTokens(theme) {
|
|
1003
|
+
const tokens = new Set(STRUCTURAL_TOKENS);
|
|
1004
|
+
for (const colorKey of Object.keys(theme.colors)) {
|
|
1005
|
+
for (const prefix of COLOR_PREFIXES) tokens.add(`${prefix}${colorKey}`);
|
|
1006
|
+
}
|
|
1007
|
+
for (const spacingKey of Object.keys(theme.spacing)) {
|
|
1008
|
+
for (const prefix of SPACING_PREFIXES) tokens.add(`${prefix}${spacingKey}`);
|
|
1009
|
+
}
|
|
1010
|
+
for (const size of NAMED_SIZES) {
|
|
1011
|
+
for (const prefix of SIZE_PREFIXES) tokens.add(`${prefix}${size}`);
|
|
1012
|
+
}
|
|
1013
|
+
return Array.from(tokens).sort();
|
|
1014
|
+
}
|
|
1015
|
+
function buildClassNameHintsDts(tokens) {
|
|
1016
|
+
const literals = tokens.map((t) => ` | '${t}'`).join("\n");
|
|
1017
|
+
return [
|
|
1018
|
+
"// Generated by Kbach \u2014 do not edit",
|
|
1019
|
+
"// Editor autocomplete for className \u2014 see packages/react/src/vite-plugin/classNameHints.ts",
|
|
1020
|
+
"",
|
|
1021
|
+
"type KbachClassToken =",
|
|
1022
|
+
literals,
|
|
1023
|
+
";",
|
|
1024
|
+
"",
|
|
1025
|
+
"export type KbachClassName = KbachClassToken | `${string} ${KbachClassToken}` | (string & {});",
|
|
1026
|
+
"",
|
|
1027
|
+
"declare module 'react' {",
|
|
1028
|
+
" interface HTMLAttributes<T> {",
|
|
1029
|
+
" className?: KbachClassName | undefined;",
|
|
1030
|
+
" }",
|
|
1031
|
+
" interface SVGAttributes<T> {",
|
|
1032
|
+
" className?: KbachClassName | undefined;",
|
|
1033
|
+
" }",
|
|
1034
|
+
"}",
|
|
1035
|
+
""
|
|
1036
|
+
].join("\n");
|
|
3657
1037
|
}
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
} catch (err) {
|
|
3665
|
-
if (err.code !== "ENOENT") {
|
|
3666
|
-
warn(`Can't read ${dir}: ${err.message}`);
|
|
3667
|
-
}
|
|
3668
|
-
return;
|
|
3669
|
-
}
|
|
3670
|
-
for (const entry of entries) {
|
|
3671
|
-
if (entry.startsWith(".") || entry === "node_modules") continue;
|
|
3672
|
-
const full = join(dir, entry);
|
|
3673
|
-
try {
|
|
3674
|
-
const st = statSync(full);
|
|
3675
|
-
if (st.isDirectory()) scanDir(full, onFile, depth + 1);
|
|
3676
|
-
else if (/\.(tsx?|jsx?)$/.test(entry)) onFile(full, readFileSync(full, "utf-8"));
|
|
3677
|
-
} catch (err) {
|
|
3678
|
-
warn(`Can't process ${full}: ${err.message}`);
|
|
3679
|
-
}
|
|
3680
|
-
}
|
|
1038
|
+
|
|
1039
|
+
// src/vite-plugin/index.ts
|
|
1040
|
+
var DEFAULT_SCAN_DIRS = ["src", "app", "pages", "components"];
|
|
1041
|
+
function normPath(p) {
|
|
1042
|
+
const fwd = p.replace(/\\/g, "/");
|
|
1043
|
+
return process.platform === "win32" ? fwd.toLowerCase() : fwd;
|
|
3681
1044
|
}
|
|
3682
|
-
var
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
try {
|
|
3686
|
-
const text = readFileSync(filePath, "utf-8");
|
|
3687
|
-
let m;
|
|
3688
|
-
CSS_CLASS_SELECTOR_RE.lastIndex = 0;
|
|
3689
|
-
while ((m = CSS_CLASS_SELECTOR_RE.exec(text)) !== null) into.add(m[1]);
|
|
3690
|
-
} catch {
|
|
3691
|
-
}
|
|
1045
|
+
var SAFELIST_KEY = "\0kbach-safelist";
|
|
1046
|
+
function readFile(path) {
|
|
1047
|
+
return readFileSync2(path, "utf-8");
|
|
3692
1048
|
}
|
|
3693
|
-
function
|
|
3694
|
-
|
|
3695
|
-
let entries;
|
|
3696
|
-
try {
|
|
3697
|
-
entries = readdirSync(dir);
|
|
3698
|
-
} catch {
|
|
3699
|
-
return;
|
|
3700
|
-
}
|
|
3701
|
-
for (const entry of entries) {
|
|
3702
|
-
if (entry.startsWith(".") || entry === "node_modules") continue;
|
|
3703
|
-
const full = join(dir, entry);
|
|
3704
|
-
try {
|
|
3705
|
-
const st = statSync(full);
|
|
3706
|
-
if (st.isDirectory()) scanCssSelectorsInto(full, into, depth + 1);
|
|
3707
|
-
else if (CSS_FILE_RE.test(entry)) scanCssFileInto(full, into);
|
|
3708
|
-
} catch {
|
|
3709
|
-
}
|
|
3710
|
-
}
|
|
1049
|
+
function writeFile(path, content) {
|
|
1050
|
+
writeFileSync(path, content, "utf-8");
|
|
3711
1051
|
}
|
|
3712
|
-
function
|
|
3713
|
-
|
|
1052
|
+
function writeFileEnsuringDir(path, content) {
|
|
1053
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
1054
|
+
writeFileSync(path, content, "utf-8");
|
|
3714
1055
|
}
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
const
|
|
3718
|
-
const
|
|
3719
|
-
const
|
|
3720
|
-
|
|
3721
|
-
const screens = toNumericScreens(cfg.theme.screens ?? {});
|
|
3722
|
-
const screenKeys = Object.keys(cfg.theme.screens ?? {});
|
|
3723
|
-
const responsivePattern = screenKeys.length ? screenKeys.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|") : "sm|md|lg|xl|2xl";
|
|
3724
|
-
const responsiveRe = new RegExp(`^(${responsivePattern}):`);
|
|
3725
|
-
let root = process2.cwd();
|
|
3726
|
-
let mainCSSFile = null;
|
|
1056
|
+
function kbach(options = {}) {
|
|
1057
|
+
const theme = options.theme ?? defaultTheme;
|
|
1058
|
+
const themeJson = JSON.stringify(theme);
|
|
1059
|
+
const includeDirs = options.include ?? DEFAULT_SCAN_DIRS;
|
|
1060
|
+
const safelist = options.safelist ?? [];
|
|
1061
|
+
let root = process.cwd();
|
|
3727
1062
|
const fileTokens = /* @__PURE__ */ new Map();
|
|
3728
|
-
const
|
|
3729
|
-
const
|
|
1063
|
+
const tokenRules = /* @__PURE__ */ new Map();
|
|
1064
|
+
const fileTags = /* @__PURE__ */ new Map();
|
|
1065
|
+
let projectCssClasses = /* @__PURE__ */ new Set();
|
|
3730
1066
|
const warnedTokens = /* @__PURE__ */ new Set();
|
|
3731
|
-
function
|
|
3732
|
-
if (
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
if (!base || projectCssClasses.has(base)) return;
|
|
3737
|
-
warnedTokens.add(tok);
|
|
3738
|
-
warnAt(`Unknown class "${tok}" \u2014 no Kbach utility or project CSS rule matches it. Typo?`, root, filePath, code, tok);
|
|
1067
|
+
function resolveToken(tok) {
|
|
1068
|
+
if (!tokenRules.has(tok)) {
|
|
1069
|
+
tokenRules.set(tok, generateCssForToken(tok, themeJson).rules);
|
|
1070
|
+
}
|
|
1071
|
+
return tokenRules.get(tok);
|
|
3739
1072
|
}
|
|
3740
1073
|
function processFile(filePath, code) {
|
|
3741
|
-
const key = normPath(filePath);
|
|
3742
1074
|
const tokens = /* @__PURE__ */ new Set();
|
|
3743
1075
|
for (const tok of extractClassStrings(code)) {
|
|
3744
1076
|
tokens.add(tok);
|
|
3745
|
-
|
|
3746
|
-
|
|
1077
|
+
const rules = resolveToken(tok);
|
|
1078
|
+
if (process.env.NODE_ENV !== "production") {
|
|
1079
|
+
warnIfUnknownClass(tok, filePath, code, rules.length > 0, projectCssClasses, warnedTokens);
|
|
3747
1080
|
}
|
|
3748
|
-
checkUnknownToken(tok, filePath, code);
|
|
3749
1081
|
}
|
|
3750
|
-
fileTokens.set(
|
|
3751
|
-
|
|
3752
|
-
function scanProjectCssSelectors() {
|
|
3753
|
-
for (const dir of includeDirs) scanCssSelectorsInto(join(root, dir), projectCssClasses);
|
|
1082
|
+
fileTokens.set(normPath(filePath), tokens);
|
|
1083
|
+
fileTags.set(normPath(filePath), scanUsedTags(code));
|
|
3754
1084
|
}
|
|
3755
|
-
function
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
});
|
|
1085
|
+
function processSafelist() {
|
|
1086
|
+
if (safelist.length === 0) return;
|
|
1087
|
+
const tokens = new Set(safelist);
|
|
1088
|
+
for (const tok of tokens) resolveToken(tok);
|
|
1089
|
+
fileTokens.set(SAFELIST_KEY, tokens);
|
|
3761
1090
|
}
|
|
3762
|
-
function
|
|
1091
|
+
function activeTokens() {
|
|
3763
1092
|
const active = /* @__PURE__ */ new Set();
|
|
3764
1093
|
for (const tokens of fileTokens.values()) for (const t of tokens) active.add(t);
|
|
1094
|
+
return active;
|
|
1095
|
+
}
|
|
1096
|
+
function activeTags() {
|
|
1097
|
+
const active = /* @__PURE__ */ new Set();
|
|
1098
|
+
for (const tags of fileTags.values()) for (const t of tags) active.add(t);
|
|
1099
|
+
return active;
|
|
1100
|
+
}
|
|
1101
|
+
function generateCSS() {
|
|
1102
|
+
const active = activeTokens();
|
|
3765
1103
|
const view = /* @__PURE__ */ new Map();
|
|
3766
1104
|
for (const tok of active) {
|
|
3767
|
-
const
|
|
3768
|
-
if (
|
|
1105
|
+
const rules = tokenRules.get(tok);
|
|
1106
|
+
if (rules) view.set(tok, rules);
|
|
3769
1107
|
}
|
|
3770
|
-
return view;
|
|
1108
|
+
return formatKbachCSS(view, theme, activeTags());
|
|
3771
1109
|
}
|
|
3772
|
-
function
|
|
3773
|
-
|
|
3774
|
-
scanDir(join(root, dir), processFile);
|
|
3775
|
-
}
|
|
1110
|
+
function mainCSSFile() {
|
|
1111
|
+
return join3(root, "src", "kbach.css");
|
|
3776
1112
|
}
|
|
3777
|
-
function
|
|
3778
|
-
return
|
|
1113
|
+
function classNameHintsFile() {
|
|
1114
|
+
return join3(root, ".kbach", "kbach-classnames.d.ts");
|
|
1115
|
+
}
|
|
1116
|
+
function writeClassNameHints() {
|
|
1117
|
+
const dts = buildClassNameHintsDts(buildClassTokens(theme));
|
|
1118
|
+
writeFileEnsuringDir(classNameHintsFile(), dts);
|
|
3779
1119
|
}
|
|
3780
1120
|
function syncMainCSSFile(server) {
|
|
3781
|
-
const active =
|
|
3782
|
-
for (const
|
|
3783
|
-
|
|
3784
|
-
if (!active.has(tok)) tokenCSS.delete(tok);
|
|
1121
|
+
const active = activeTokens();
|
|
1122
|
+
for (const tok of tokenRules.keys()) {
|
|
1123
|
+
if (!active.has(tok)) tokenRules.delete(tok);
|
|
3785
1124
|
}
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
1125
|
+
const changed = writeKbachToFile(mainCSSFile(), generateCSS(), readFile, writeFile);
|
|
1126
|
+
if (changed && server) server.watcher.emit("change", mainCSSFile());
|
|
1127
|
+
}
|
|
1128
|
+
function initialScan() {
|
|
1129
|
+
for (const dir of includeDirs) {
|
|
1130
|
+
scanDir(join3(root, dir), processFile);
|
|
3789
1131
|
}
|
|
3790
1132
|
}
|
|
3791
1133
|
return {
|
|
3792
1134
|
name: "kbach",
|
|
3793
1135
|
enforce: "pre",
|
|
3794
|
-
// Without this, Vite only discovers @kbach/react needs pre-bundling once it
|
|
3795
|
-
// actually crawls into an import of it — typically the FIRST page load — and
|
|
3796
|
-
// has to stop, optimize it, and force a full reload mid-render. That reload
|
|
3797
|
-
// can land in the middle of a render pass (React hooks resolving against a
|
|
3798
|
-
// module graph that's being swapped out from under it), which is what an
|
|
3799
|
-
// "Invalid hook call" / hook-related crash on first load only usually is.
|
|
3800
|
-
// Declaring it here upfront means Vite pre-bundles it during its initial
|
|
3801
|
-
// dependency scan, before any page ever requests it — no mid-render reload.
|
|
3802
|
-
config() {
|
|
3803
|
-
return {
|
|
3804
|
-
optimizeDeps: {
|
|
3805
|
-
include: ["@kbach/react", "@kbach/react/jsx-runtime", "@kbach/react/jsx-dev-runtime"]
|
|
3806
|
-
}
|
|
3807
|
-
};
|
|
3808
|
-
},
|
|
3809
1136
|
configResolved(resolved) {
|
|
3810
1137
|
root = resolved.root;
|
|
3811
|
-
writeKbachTypesDts(root, cfg.theme);
|
|
3812
|
-
const names = new Set(resolved.plugins.map((p) => p.name));
|
|
3813
|
-
if (names.has("react-router") && names.has("vite:react-refresh")) {
|
|
3814
|
-
warnBlock(
|
|
3815
|
-
"@vitejs/plugin-react + reactRouter() conflict \u2014 page will crash before styles apply.",
|
|
3816
|
-
dim(' Both inject Fast Refresh ("RefreshRuntime already declared").'),
|
|
3817
|
-
dim(" Fix: remove react() from vite.config.ts \u2014 tsconfig jsxImportSource is enough.")
|
|
3818
|
-
);
|
|
3819
|
-
}
|
|
3820
|
-
},
|
|
3821
|
-
// When any JS/TS file imports kbach.css, prepend a disableRuntimeCSS() call
|
|
3822
|
-
// so styles come solely from the static stylesheet — no duplicate injection.
|
|
3823
|
-
//
|
|
3824
|
-
// Anchored to the START of a source line (^\s*, with the m flag) rather than a
|
|
3825
|
-
// bare \bimport\b anywhere in the file — disableRuntimeCSS() sets a globalThis
|
|
3826
|
-
// flag with no way to re-enable it, so a false match here doesn't just misfire
|
|
3827
|
-
// once, it silently kills ALL runtime CSS injection for the rest of that page's
|
|
3828
|
-
// JS lifetime, including on completely unrelated components. A real import
|
|
3829
|
-
// statement is always the first token on its line (give or take whitespace);
|
|
3830
|
-
// this same text appearing as part of a STRING — e.g. a docs site's own code
|
|
3831
|
-
// sample literally showing `import "./kbach.css";` as example text, which is
|
|
3832
|
-
// exactly what happened here — is never positioned that way, since something
|
|
3833
|
-
// always precedes it syntactically (a quote, JSX braces, an array bracket, …).
|
|
3834
|
-
transform(code, id) {
|
|
3835
|
-
if (!/\.(tsx?|jsx?|mjs?)$/.test(id)) return;
|
|
3836
|
-
if (!/^\s*import\b[^;]*['"][^'"]*kbach\.css['"]/im.test(code)) return;
|
|
3837
|
-
warn(`disableRuntimeCSS() auto-triggered by an import in ${id.replace(/\\/g, "/")}`);
|
|
3838
|
-
return {
|
|
3839
|
-
code: `import { disableRuntimeCSS } from '@kbach/react';
|
|
3840
|
-
disableRuntimeCSS();
|
|
3841
|
-
${code}`,
|
|
3842
|
-
map: null
|
|
3843
|
-
};
|
|
3844
1138
|
},
|
|
3845
1139
|
buildStart() {
|
|
3846
|
-
|
|
3847
|
-
scanProjectCssSelectors();
|
|
1140
|
+
projectCssClasses = scanProjectCssSelectors(root, includeDirs);
|
|
3848
1141
|
initialScan();
|
|
3849
|
-
|
|
1142
|
+
processSafelist();
|
|
1143
|
+
writeKbachToFile(mainCSSFile(), generateCSS(), readFile, writeFile);
|
|
1144
|
+
writeClassNameHints();
|
|
3850
1145
|
},
|
|
3851
|
-
//
|
|
3852
|
-
//
|
|
3853
|
-
//
|
|
3854
|
-
// vite's own onHMRUpdate/handleHMRUpdate: the hook loop is gated on
|
|
3855
|
-
// `type === "update"`). Without also listening on those two events here,
|
|
3856
|
-
// creating a new file with new Kbach classes never adds them to
|
|
3857
|
-
// kbach.css, and deleting a file never removes its classes, until a full
|
|
3858
|
-
// dev-server restart. configureServer gives access to the raw watcher so
|
|
3859
|
-
// both cases can share the same sync logic as a plain edit.
|
|
1146
|
+
// handleHotUpdate covers edits; add/unlink (create/delete) land on the
|
|
1147
|
+
// raw watcher instead — Vite's handleHotUpdate hook only fires for
|
|
1148
|
+
// type === "update".
|
|
3860
1149
|
configureServer(server) {
|
|
3861
1150
|
const onAddOrUnlink = (file, isUnlink) => {
|
|
3862
1151
|
if (file.includes("node_modules")) return;
|
|
3863
|
-
if (!isWithinIncludeDirs(file)) return;
|
|
3864
|
-
if (CSS_FILE_RE.test(file)) {
|
|
3865
|
-
if (!isUnlink) scanCssFileInto(file, projectCssClasses);
|
|
3866
|
-
return;
|
|
3867
|
-
}
|
|
3868
1152
|
if (!/\.(tsx?|jsx?)$/.test(file)) return;
|
|
3869
1153
|
if (isUnlink) {
|
|
3870
1154
|
fileTokens.delete(normPath(file));
|
|
1155
|
+
fileTags.delete(normPath(file));
|
|
3871
1156
|
} else {
|
|
3872
1157
|
try {
|
|
3873
|
-
processFile(file,
|
|
1158
|
+
processFile(file, readFile(file));
|
|
3874
1159
|
} catch {
|
|
3875
1160
|
fileTokens.delete(normPath(file));
|
|
1161
|
+
fileTags.delete(normPath(file));
|
|
3876
1162
|
}
|
|
3877
1163
|
}
|
|
3878
1164
|
syncMainCSSFile(server);
|
|
@@ -3882,22 +1168,17 @@ ${code}`,
|
|
|
3882
1168
|
},
|
|
3883
1169
|
handleHotUpdate({ file, server }) {
|
|
3884
1170
|
if (file.includes("node_modules")) return;
|
|
3885
|
-
if (!isWithinIncludeDirs(file)) return;
|
|
3886
|
-
if (CSS_FILE_RE.test(file)) {
|
|
3887
|
-
scanCssFileInto(file, projectCssClasses);
|
|
3888
|
-
return;
|
|
3889
|
-
}
|
|
3890
1171
|
if (!/\.(tsx?|jsx?)$/.test(file)) return;
|
|
3891
1172
|
try {
|
|
3892
|
-
processFile(file,
|
|
1173
|
+
processFile(file, readFile(file));
|
|
3893
1174
|
} catch {
|
|
3894
1175
|
fileTokens.delete(normPath(file));
|
|
1176
|
+
fileTags.delete(normPath(file));
|
|
3895
1177
|
}
|
|
3896
1178
|
syncMainCSSFile(server);
|
|
3897
1179
|
}
|
|
3898
1180
|
};
|
|
3899
1181
|
}
|
|
3900
1182
|
export {
|
|
3901
|
-
formatKbachCSS,
|
|
3902
1183
|
kbach
|
|
3903
1184
|
};
|