@kbach/ui 0.1.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.
@@ -0,0 +1,1346 @@
1
+ /**
2
+ * Unified modifier registry — single source of truth for ALL modifier behavior.
3
+ *
4
+ * Adding a new modifier requires editing ONLY this file:
5
+ * 1. Add an entry to BUILTIN_MODIFIERS with its CSS and JS behavior.
6
+ * 2. Done — parser, resolver, CSS generator, and JSX runtime all derive
7
+ * their behavior from this data automatically.
8
+ *
9
+ * Plugin authors can register custom modifiers via registerModifier().
10
+ */
11
+ interface ModifierDef {
12
+ /**
13
+ * Cascade priority for CSS rule ORDER — NOT specificity. Two rules that
14
+ * differ only by modifier (e.g. `.hover\:bg-blue-6:hover` and
15
+ * `.focus\:bg-red-6:focus`) have equal CSS specificity, so when both
16
+ * conditions are true at once (hovering AND focused), the winner is
17
+ * whichever rule appears LATER in the stylesheet — CSS's normal same-
18
+ * specificity tiebreak. Without a fixed priority, "later" would depend on
19
+ * encounter order (whichever class the app happens to render/scan first),
20
+ * making the winner effectively random and inconsistent across reloads/
21
+ * builds. `order` fixes that: rules are emitted/injected sorted by this
22
+ * value (ascending — higher wins ties), regardless of source order, so
23
+ * e.g. `disabled:` always beats `hover:` on the same element no matter
24
+ * which one was written first in the className or rendered first in the
25
+ * app. Omit for the default (0). See getModifierOrder() below.
26
+ */
27
+ order?: number;
28
+ /** CSS pseudo-class or pseudo-element appended to the selector (e.g. ':hover', '::before') */
29
+ pseudo?: string;
30
+ /** Ancestor selector prefix INCLUDING trailing space (e.g. '.group:hover ', '.peer:focus ~ ') */
31
+ ancestorSelector?: string;
32
+ /** Directionality attribute selector prefix INCLUDING trailing space (e.g. '[dir="rtl"] ') */
33
+ dirSelector?: string;
34
+ /** @media query body WITHOUT the '@media ' prefix (e.g. 'print', '(orientation: landscape)') */
35
+ mediaQuery?: string;
36
+ /** Dark/light mode scheme — triggers the configured darkMode strategy in CSS output */
37
+ darkScheme?: 'dark' | 'light';
38
+ /** True for responsive modifiers — wraps in @media (min-width: theme.screens[name]) */
39
+ isResponsive?: boolean;
40
+ /**
41
+ * Forces !important on all declarations in the generated CSS rule.
42
+ * Applied automatically for structural / ancestor / media modifiers that must
43
+ * win over base inline styles.
44
+ */
45
+ forcesImportant?: boolean;
46
+ /**
47
+ * How the JSX runtime routes this modifier:
48
+ * 'interactive' — managed by InteractiveWrapper (hover, focus, pressed, …)
49
+ * 'mode' — managed by DarkWrapper (dark, light, not-dark, …)
50
+ * 'responsive' — managed by DarkWrapper (sm, md, lg, xl, 2xl)
51
+ * 'css-only' — CSS injection only; matchModifier always returns false
52
+ */
53
+ jsBehavior: 'interactive' | 'mode' | 'responsive' | 'css-only';
54
+ /**
55
+ * Evaluates whether this modifier's condition is met at runtime.
56
+ * Omit for 'css-only' modifiers — they never apply as inline styles.
57
+ */
58
+ jsMatch?: (isDark: boolean, state: Record<string, boolean | undefined>, breakpoints: Set<string>) => boolean;
59
+ }
60
+ declare function registerModifier(name: string, def: ModifierDef): void;
61
+ declare function clearPluginModifiers(): void;
62
+ declare function getModifier(name: string): ModifierDef | undefined;
63
+ declare function isKnownModifier(name: string): boolean;
64
+ /** All known modifier names (built-in + plugin). */
65
+ declare function getAllModifierNames(): Set<string>;
66
+ /** Modifier names routed to InteractiveWrapper. */
67
+ declare function getInteractiveModifiers(): Set<string>;
68
+ /** Modifier names routed to DarkWrapper for mode switching. */
69
+ declare function getModeModifiers(): Set<string>;
70
+ /** Modifier names routed to DarkWrapper for responsive handling. */
71
+ declare function getResponsiveModifiers(): Set<string>;
72
+ /**
73
+ * Evaluates whether a modifier matches the current runtime state.
74
+ * CSS-only modifiers always return false — they have no JS representation.
75
+ */
76
+ declare function matchModifier(name: string, isDark: boolean, state: Record<string, boolean | undefined>, breakpoints: Set<string>): boolean;
77
+
78
+ type Platform = 'web' | 'native';
79
+ type ThemeMode = 'light' | 'dark' | 'system';
80
+ interface StyleValue {
81
+ [key: string]: string | number | undefined | null | StyleValue | StyleValue[];
82
+ }
83
+ interface ParsedClass {
84
+ /** The original class string, e.g. "dark:hover:bg-[#fff]" */
85
+ original: string;
86
+ /** Up to 3 modifier prefixes, e.g. ['dark', 'hover'] */
87
+ modifiers: string[];
88
+ /** Whether a leading `-` was present for negative values */
89
+ negative: boolean;
90
+ /** Whether a leading `!` was present — applies !important to all CSS declarations */
91
+ important: boolean;
92
+ /** The utility name, e.g. 'bg', 'p', 'text' */
93
+ utility: string;
94
+ /** The resolved value, e.g. 'white', '#fff', '4' */
95
+ value: string;
96
+ /** Whether the value was specified with bracket notation [value] */
97
+ isArbitrary: boolean;
98
+ }
99
+ interface ResolvedStyle {
100
+ /** Base styles applied unconditionally */
101
+ base?: StyleValue;
102
+ /** Styles keyed by modifier or modifier combo, e.g. 'dark', 'hover', 'dark:hover' */
103
+ [modifierKey: string]: StyleValue | undefined;
104
+ }
105
+ /**
106
+ * A color value is either a plain string (hex/rgb/alias-to-another-color-name)
107
+ * or a mode-aware pair — resolved to `light` or `dark` per the active theme
108
+ * mode wherever it's actually used (className resolution, useColors()).
109
+ */
110
+ type ColorValue = string | {
111
+ light: string;
112
+ dark: string;
113
+ };
114
+ type ColorShades = Record<string, ColorValue>;
115
+ type ThemeColors = Record<string, ColorValue | ColorShades>;
116
+ type ThemeSpacing = Record<string, number | string>;
117
+ interface ThemeConfig {
118
+ colors: ThemeColors;
119
+ spacing: ThemeSpacing;
120
+ fontSize: Record<string, number | string>;
121
+ fontFamily: Record<string, string | string[]>;
122
+ fontWeight: Record<string, string | number>;
123
+ borderRadius: Record<string, number | string>;
124
+ borderWidth: Record<string, number>;
125
+ opacity: Record<string, number>;
126
+ lineHeight: Record<string, number | string>;
127
+ letterSpacing: Record<string, number | string>;
128
+ zIndex: Record<string, number | string>;
129
+ flex: Record<string, number | string>;
130
+ shadow: Record<string, StyleValue>;
131
+ screens: Record<string, string | number>;
132
+ /**
133
+ * Custom @keyframes, web only. Each key is a keyframe name, its value maps
134
+ * percentage/from/to selectors to a plain CSS declaration object (camelCase
135
+ * properties, same shape as an inline style object):
136
+ * keyframes: { wiggle: { '0%, 100%': { transform: 'rotate(-3deg)' }, '50%': { transform: 'rotate(3deg)' } } }
137
+ * Referenced from `animation` below, or directly via animate-[wiggle_1s_ease-in-out].
138
+ */
139
+ keyframes: Record<string, Record<string, StyleValue>>;
140
+ /**
141
+ * Named animation shorthands built on `keyframes` above, referenced via
142
+ * animate-{name} (e.g. animate-wiggle):
143
+ * animation: { wiggle: 'wiggle 1s ease-in-out infinite' }
144
+ * The first word must match a `keyframes` key so its @keyframes rule can be
145
+ * injected alongside the animation — a name with no matching keyframes entry
146
+ * still sets the `animation` CSS property, it just won't animate anything.
147
+ */
148
+ animation: Record<string, string>;
149
+ [key: string]: unknown;
150
+ }
151
+ /**
152
+ * 'class' — toggles .dark class on <html>
153
+ * 'media' — uses prefers-color-scheme media query
154
+ * 'attribute' — uses data-theme="dark" attribute on <html>
155
+ */
156
+ type DarkMode = 'attribute' | 'class' | 'media';
157
+ interface PluginAPI {
158
+ addUtility(name: string, styles: StyleValue): void;
159
+ /**
160
+ * Register a custom variant.
161
+ *
162
+ * Pass a CSS selector string for simple cases — it is automatically
163
+ * converted into a ModifierDef that generates correct CSS rules:
164
+ * addVariant('hocus', ':hover, :focus') // pseudo
165
+ * addVariant('supports-grid', '@media (display: grid)') // media
166
+ * addVariant('dark-green', '.dark-green') // ancestor selector
167
+ *
168
+ * Pass a full ModifierDef object for advanced control (e.g. JS-trackable
169
+ * interactive variants with custom jsMatch logic).
170
+ */
171
+ addVariant(name: string, selectorOrDef: string | ModifierDef): void;
172
+ theme(path: string, defaultValue?: unknown): unknown;
173
+ e(className: string): string;
174
+ }
175
+ interface FrameworkConfig {
176
+ darkMode?: DarkMode;
177
+ theme?: Partial<ThemeConfig>;
178
+ /** Additive theme extension — accepts either `extend.theme.X` or `extend.X` directly. */
179
+ extend?: {
180
+ theme?: Partial<ThemeConfig>;
181
+ } & Partial<ThemeConfig>;
182
+ plugins?: Array<(api: PluginAPI) => void>;
183
+ content?: string[];
184
+ }
185
+ interface ResolvedConfig {
186
+ darkMode: DarkMode;
187
+ theme: ThemeConfig;
188
+ plugins: Array<(api: PluginAPI) => void>;
189
+ }
190
+
191
+ /**
192
+ * True for a mode-aware color pair (`{ light, dark }`), as opposed to a plain
193
+ * hex/rgb/alias string. Shared by config.ts (alias-chain resolution),
194
+ * resolvers/color.ts (direct lookups), and modeAwareColors.ts (className
195
+ * expansion) so all three agree on exactly one definition. Real shade keys
196
+ * are always numeric strings ('1'–'12'), so this can never collide with one.
197
+ */
198
+ declare function isModeAwareColor(v: unknown): v is {
199
+ light: string;
200
+ dark: string;
201
+ };
202
+
203
+ /**
204
+ * Expand every class referencing a mode-aware color (a kbach.config.js color
205
+ * value shaped `{ light, dark }`) into an explicit base + dark: pair BEFORE
206
+ * normal parsing — e.g. `bg-surface` becomes `bg-[#ffffff] dark:bg-[#111827]`.
207
+ * `bg-surface/50` becomes `bg-[#ffffff]/50 dark:bg-[#111827]/50` (the arbitrary-
208
+ * color-plus-opacity composition already resolveColor() already supports).
209
+ * `hover:bg-surface` becomes `hover:bg-[#ffffff] dark:hover:bg-[#111827]` —
210
+ * every other modifier already present on the token carries through onto
211
+ * both halves of the pair unchanged.
212
+ *
213
+ * A token that ALREADY carries an explicit dark:/light:/not-dark:/not-light:
214
+ * modifier (someone writes `dark:hover:bg-primary` on a `primary` that's
215
+ * already mode-aware, usually out of habit from before it was) isn't split
216
+ * into a pair — that would be redundant on top of an already-explicit
217
+ * choice. Instead the matching side is substituted in place and every
218
+ * modifier, including the dark:/light: itself, is left exactly as written,
219
+ * so `dark:hover:bg-primary` still only applies in dark mode, using the
220
+ * dark side (not the resolveColor()-level fallback's light side, which is
221
+ * only ever reached by a mode-aware pair that skipped this expansion
222
+ * entirely — not a path normal className resolution takes).
223
+ *
224
+ * Runs once, upfront, purely as a string rewrite — everything downstream
225
+ * (CSS generation, native bucketing/flatten(), the existing dark: reactivity
226
+ * machinery: DarkWrapper, bucketMods()) then handles the result exactly like
227
+ * a hand-written dark: pair, with zero further changes needed anywhere else.
228
+ * That also means resolve()'s cache (keyed on the ORIGINAL, unexpanded string
229
+ * — see resolver.ts) stays correct without any changes to its cache key.
230
+ */
231
+ declare function expandModeAwareColorClasses(classString: string, colors: ThemeColors): string;
232
+
233
+ /**
234
+ * Generates the KbachCustomColors/KbachCustomSpacing module-augmentation
235
+ * source for every color/spacing key `extend.theme` added beyond the built-in
236
+ * defaults. Called by both the Vite plugin and the Babel plugin (@kbach/ui/babel-plugin) —
237
+ * kept here, shared, so "which colors count as custom" and "flat string vs.
238
+ * ColorScale" can't drift between the two.
239
+ *
240
+ * Returns '' (nothing to write) when the theme adds no custom colors or
241
+ * spacing keys at all, so callers can skip writing/deleting a file for the
242
+ * common case of a project still on the stock theme.
243
+ */
244
+ declare function generateKbachTypesDts(theme: ThemeConfig): string;
245
+
246
+ declare const defaultColors: {
247
+ transparent: string;
248
+ current: string;
249
+ black: string;
250
+ white: string;
251
+ slate: {
252
+ 1: string;
253
+ 2: string;
254
+ 3: string;
255
+ 4: string;
256
+ 5: string;
257
+ 6: string;
258
+ 7: string;
259
+ 8: string;
260
+ 9: string;
261
+ 10: string;
262
+ 11: string;
263
+ 12: string;
264
+ };
265
+ gray: {
266
+ 1: string;
267
+ 2: string;
268
+ 3: string;
269
+ 4: string;
270
+ 5: string;
271
+ 6: string;
272
+ 7: string;
273
+ 8: string;
274
+ 9: string;
275
+ 10: string;
276
+ 11: string;
277
+ 12: string;
278
+ };
279
+ zinc: {
280
+ 1: string;
281
+ 2: string;
282
+ 3: string;
283
+ 4: string;
284
+ 5: string;
285
+ 6: string;
286
+ 7: string;
287
+ 8: string;
288
+ 9: string;
289
+ 10: string;
290
+ 11: string;
291
+ 12: string;
292
+ };
293
+ neutral: {
294
+ 1: string;
295
+ 2: string;
296
+ 3: string;
297
+ 4: string;
298
+ 5: string;
299
+ 6: string;
300
+ 7: string;
301
+ 8: string;
302
+ 9: string;
303
+ 10: string;
304
+ 11: string;
305
+ 12: string;
306
+ };
307
+ stone: {
308
+ 1: string;
309
+ 2: string;
310
+ 3: string;
311
+ 4: string;
312
+ 5: string;
313
+ 6: string;
314
+ 7: string;
315
+ 8: string;
316
+ 9: string;
317
+ 10: string;
318
+ 11: string;
319
+ 12: string;
320
+ };
321
+ red: {
322
+ 1: string;
323
+ 2: string;
324
+ 3: string;
325
+ 4: string;
326
+ 5: string;
327
+ 6: string;
328
+ 7: string;
329
+ 8: string;
330
+ 9: string;
331
+ 10: string;
332
+ 11: string;
333
+ 12: string;
334
+ };
335
+ orange: {
336
+ 1: string;
337
+ 2: string;
338
+ 3: string;
339
+ 4: string;
340
+ 5: string;
341
+ 6: string;
342
+ 7: string;
343
+ 8: string;
344
+ 9: string;
345
+ 10: string;
346
+ 11: string;
347
+ 12: string;
348
+ };
349
+ amber: {
350
+ 1: string;
351
+ 2: string;
352
+ 3: string;
353
+ 4: string;
354
+ 5: string;
355
+ 6: string;
356
+ 7: string;
357
+ 8: string;
358
+ 9: string;
359
+ 10: string;
360
+ 11: string;
361
+ 12: string;
362
+ };
363
+ yellow: {
364
+ 1: string;
365
+ 2: string;
366
+ 3: string;
367
+ 4: string;
368
+ 5: string;
369
+ 6: string;
370
+ 7: string;
371
+ 8: string;
372
+ 9: string;
373
+ 10: string;
374
+ 11: string;
375
+ 12: string;
376
+ };
377
+ lime: {
378
+ 1: string;
379
+ 2: string;
380
+ 3: string;
381
+ 4: string;
382
+ 5: string;
383
+ 6: string;
384
+ 7: string;
385
+ 8: string;
386
+ 9: string;
387
+ 10: string;
388
+ 11: string;
389
+ 12: string;
390
+ };
391
+ green: {
392
+ 1: string;
393
+ 2: string;
394
+ 3: string;
395
+ 4: string;
396
+ 5: string;
397
+ 6: string;
398
+ 7: string;
399
+ 8: string;
400
+ 9: string;
401
+ 10: string;
402
+ 11: string;
403
+ 12: string;
404
+ };
405
+ emerald: {
406
+ 1: string;
407
+ 2: string;
408
+ 3: string;
409
+ 4: string;
410
+ 5: string;
411
+ 6: string;
412
+ 7: string;
413
+ 8: string;
414
+ 9: string;
415
+ 10: string;
416
+ 11: string;
417
+ 12: string;
418
+ };
419
+ teal: {
420
+ 1: string;
421
+ 2: string;
422
+ 3: string;
423
+ 4: string;
424
+ 5: string;
425
+ 6: string;
426
+ 7: string;
427
+ 8: string;
428
+ 9: string;
429
+ 10: string;
430
+ 11: string;
431
+ 12: string;
432
+ };
433
+ cyan: {
434
+ 1: string;
435
+ 2: string;
436
+ 3: string;
437
+ 4: string;
438
+ 5: string;
439
+ 6: string;
440
+ 7: string;
441
+ 8: string;
442
+ 9: string;
443
+ 10: string;
444
+ 11: string;
445
+ 12: string;
446
+ };
447
+ sky: {
448
+ 1: string;
449
+ 2: string;
450
+ 3: string;
451
+ 4: string;
452
+ 5: string;
453
+ 6: string;
454
+ 7: string;
455
+ 8: string;
456
+ 9: string;
457
+ 10: string;
458
+ 11: string;
459
+ 12: string;
460
+ };
461
+ blue: {
462
+ 1: string;
463
+ 2: string;
464
+ 3: string;
465
+ 4: string;
466
+ 5: string;
467
+ 6: string;
468
+ 7: string;
469
+ 8: string;
470
+ 9: string;
471
+ 10: string;
472
+ 11: string;
473
+ 12: string;
474
+ };
475
+ indigo: {
476
+ 1: string;
477
+ 2: string;
478
+ 3: string;
479
+ 4: string;
480
+ 5: string;
481
+ 6: string;
482
+ 7: string;
483
+ 8: string;
484
+ 9: string;
485
+ 10: string;
486
+ 11: string;
487
+ 12: string;
488
+ };
489
+ violet: {
490
+ 1: string;
491
+ 2: string;
492
+ 3: string;
493
+ 4: string;
494
+ 5: string;
495
+ 6: string;
496
+ 7: string;
497
+ 8: string;
498
+ 9: string;
499
+ 10: string;
500
+ 11: string;
501
+ 12: string;
502
+ };
503
+ purple: {
504
+ 1: string;
505
+ 2: string;
506
+ 3: string;
507
+ 4: string;
508
+ 5: string;
509
+ 6: string;
510
+ 7: string;
511
+ 8: string;
512
+ 9: string;
513
+ 10: string;
514
+ 11: string;
515
+ 12: string;
516
+ };
517
+ fuchsia: {
518
+ 1: string;
519
+ 2: string;
520
+ 3: string;
521
+ 4: string;
522
+ 5: string;
523
+ 6: string;
524
+ 7: string;
525
+ 8: string;
526
+ 9: string;
527
+ 10: string;
528
+ 11: string;
529
+ 12: string;
530
+ };
531
+ pink: {
532
+ 1: string;
533
+ 2: string;
534
+ 3: string;
535
+ 4: string;
536
+ 5: string;
537
+ 6: string;
538
+ 7: string;
539
+ 8: string;
540
+ 9: string;
541
+ 10: string;
542
+ 11: string;
543
+ 12: string;
544
+ };
545
+ rose: {
546
+ 1: string;
547
+ 2: string;
548
+ 3: string;
549
+ 4: string;
550
+ 5: string;
551
+ 6: string;
552
+ 7: string;
553
+ 8: string;
554
+ 9: string;
555
+ 10: string;
556
+ 11: string;
557
+ 12: string;
558
+ };
559
+ };
560
+ declare const defaultTheme: {
561
+ colors: {
562
+ transparent: string;
563
+ current: string;
564
+ black: string;
565
+ white: string;
566
+ slate: {
567
+ 1: string;
568
+ 2: string;
569
+ 3: string;
570
+ 4: string;
571
+ 5: string;
572
+ 6: string;
573
+ 7: string;
574
+ 8: string;
575
+ 9: string;
576
+ 10: string;
577
+ 11: string;
578
+ 12: string;
579
+ };
580
+ gray: {
581
+ 1: string;
582
+ 2: string;
583
+ 3: string;
584
+ 4: string;
585
+ 5: string;
586
+ 6: string;
587
+ 7: string;
588
+ 8: string;
589
+ 9: string;
590
+ 10: string;
591
+ 11: string;
592
+ 12: string;
593
+ };
594
+ zinc: {
595
+ 1: string;
596
+ 2: string;
597
+ 3: string;
598
+ 4: string;
599
+ 5: string;
600
+ 6: string;
601
+ 7: string;
602
+ 8: string;
603
+ 9: string;
604
+ 10: string;
605
+ 11: string;
606
+ 12: string;
607
+ };
608
+ neutral: {
609
+ 1: string;
610
+ 2: string;
611
+ 3: string;
612
+ 4: string;
613
+ 5: string;
614
+ 6: string;
615
+ 7: string;
616
+ 8: string;
617
+ 9: string;
618
+ 10: string;
619
+ 11: string;
620
+ 12: string;
621
+ };
622
+ stone: {
623
+ 1: string;
624
+ 2: string;
625
+ 3: string;
626
+ 4: string;
627
+ 5: string;
628
+ 6: string;
629
+ 7: string;
630
+ 8: string;
631
+ 9: string;
632
+ 10: string;
633
+ 11: string;
634
+ 12: string;
635
+ };
636
+ red: {
637
+ 1: string;
638
+ 2: string;
639
+ 3: string;
640
+ 4: string;
641
+ 5: string;
642
+ 6: string;
643
+ 7: string;
644
+ 8: string;
645
+ 9: string;
646
+ 10: string;
647
+ 11: string;
648
+ 12: string;
649
+ };
650
+ orange: {
651
+ 1: string;
652
+ 2: string;
653
+ 3: string;
654
+ 4: string;
655
+ 5: string;
656
+ 6: string;
657
+ 7: string;
658
+ 8: string;
659
+ 9: string;
660
+ 10: string;
661
+ 11: string;
662
+ 12: string;
663
+ };
664
+ amber: {
665
+ 1: string;
666
+ 2: string;
667
+ 3: string;
668
+ 4: string;
669
+ 5: string;
670
+ 6: string;
671
+ 7: string;
672
+ 8: string;
673
+ 9: string;
674
+ 10: string;
675
+ 11: string;
676
+ 12: string;
677
+ };
678
+ yellow: {
679
+ 1: string;
680
+ 2: string;
681
+ 3: string;
682
+ 4: string;
683
+ 5: string;
684
+ 6: string;
685
+ 7: string;
686
+ 8: string;
687
+ 9: string;
688
+ 10: string;
689
+ 11: string;
690
+ 12: string;
691
+ };
692
+ lime: {
693
+ 1: string;
694
+ 2: string;
695
+ 3: string;
696
+ 4: string;
697
+ 5: string;
698
+ 6: string;
699
+ 7: string;
700
+ 8: string;
701
+ 9: string;
702
+ 10: string;
703
+ 11: string;
704
+ 12: string;
705
+ };
706
+ green: {
707
+ 1: string;
708
+ 2: string;
709
+ 3: string;
710
+ 4: string;
711
+ 5: string;
712
+ 6: string;
713
+ 7: string;
714
+ 8: string;
715
+ 9: string;
716
+ 10: string;
717
+ 11: string;
718
+ 12: string;
719
+ };
720
+ emerald: {
721
+ 1: string;
722
+ 2: string;
723
+ 3: string;
724
+ 4: string;
725
+ 5: string;
726
+ 6: string;
727
+ 7: string;
728
+ 8: string;
729
+ 9: string;
730
+ 10: string;
731
+ 11: string;
732
+ 12: string;
733
+ };
734
+ teal: {
735
+ 1: string;
736
+ 2: string;
737
+ 3: string;
738
+ 4: string;
739
+ 5: string;
740
+ 6: string;
741
+ 7: string;
742
+ 8: string;
743
+ 9: string;
744
+ 10: string;
745
+ 11: string;
746
+ 12: string;
747
+ };
748
+ cyan: {
749
+ 1: string;
750
+ 2: string;
751
+ 3: string;
752
+ 4: string;
753
+ 5: string;
754
+ 6: string;
755
+ 7: string;
756
+ 8: string;
757
+ 9: string;
758
+ 10: string;
759
+ 11: string;
760
+ 12: string;
761
+ };
762
+ sky: {
763
+ 1: string;
764
+ 2: string;
765
+ 3: string;
766
+ 4: string;
767
+ 5: string;
768
+ 6: string;
769
+ 7: string;
770
+ 8: string;
771
+ 9: string;
772
+ 10: string;
773
+ 11: string;
774
+ 12: string;
775
+ };
776
+ blue: {
777
+ 1: string;
778
+ 2: string;
779
+ 3: string;
780
+ 4: string;
781
+ 5: string;
782
+ 6: string;
783
+ 7: string;
784
+ 8: string;
785
+ 9: string;
786
+ 10: string;
787
+ 11: string;
788
+ 12: string;
789
+ };
790
+ indigo: {
791
+ 1: string;
792
+ 2: string;
793
+ 3: string;
794
+ 4: string;
795
+ 5: string;
796
+ 6: string;
797
+ 7: string;
798
+ 8: string;
799
+ 9: string;
800
+ 10: string;
801
+ 11: string;
802
+ 12: string;
803
+ };
804
+ violet: {
805
+ 1: string;
806
+ 2: string;
807
+ 3: string;
808
+ 4: string;
809
+ 5: string;
810
+ 6: string;
811
+ 7: string;
812
+ 8: string;
813
+ 9: string;
814
+ 10: string;
815
+ 11: string;
816
+ 12: string;
817
+ };
818
+ purple: {
819
+ 1: string;
820
+ 2: string;
821
+ 3: string;
822
+ 4: string;
823
+ 5: string;
824
+ 6: string;
825
+ 7: string;
826
+ 8: string;
827
+ 9: string;
828
+ 10: string;
829
+ 11: string;
830
+ 12: string;
831
+ };
832
+ fuchsia: {
833
+ 1: string;
834
+ 2: string;
835
+ 3: string;
836
+ 4: string;
837
+ 5: string;
838
+ 6: string;
839
+ 7: string;
840
+ 8: string;
841
+ 9: string;
842
+ 10: string;
843
+ 11: string;
844
+ 12: string;
845
+ };
846
+ pink: {
847
+ 1: string;
848
+ 2: string;
849
+ 3: string;
850
+ 4: string;
851
+ 5: string;
852
+ 6: string;
853
+ 7: string;
854
+ 8: string;
855
+ 9: string;
856
+ 10: string;
857
+ 11: string;
858
+ 12: string;
859
+ };
860
+ rose: {
861
+ 1: string;
862
+ 2: string;
863
+ 3: string;
864
+ 4: string;
865
+ 5: string;
866
+ 6: string;
867
+ 7: string;
868
+ 8: string;
869
+ 9: string;
870
+ 10: string;
871
+ 11: string;
872
+ 12: string;
873
+ };
874
+ };
875
+ spacing: {
876
+ px: number;
877
+ 0: number;
878
+ '0.5': number;
879
+ 1: number;
880
+ '1.5': number;
881
+ 2: number;
882
+ '2.5': number;
883
+ 3: number;
884
+ '3.5': number;
885
+ 4: number;
886
+ 5: number;
887
+ 6: number;
888
+ 7: number;
889
+ 8: number;
890
+ 9: number;
891
+ 10: number;
892
+ 11: number;
893
+ 12: number;
894
+ 14: number;
895
+ 16: number;
896
+ 20: number;
897
+ 24: number;
898
+ 28: number;
899
+ 32: number;
900
+ 36: number;
901
+ 40: number;
902
+ 44: number;
903
+ 48: number;
904
+ 52: number;
905
+ 56: number;
906
+ 60: number;
907
+ 64: number;
908
+ 72: number;
909
+ 80: number;
910
+ 96: number;
911
+ auto: string;
912
+ full: string;
913
+ '1/2': string;
914
+ '1/3': string;
915
+ '2/3': string;
916
+ '1/4': string;
917
+ '3/4': string;
918
+ screen: string;
919
+ min: string;
920
+ max: string;
921
+ fit: string;
922
+ };
923
+ fontSize: {
924
+ xs: number;
925
+ sm: number;
926
+ base: number;
927
+ lg: number;
928
+ xl: number;
929
+ '2xl': number;
930
+ '3xl': number;
931
+ '4xl': number;
932
+ '5xl': number;
933
+ '6xl': number;
934
+ '7xl': number;
935
+ '8xl': number;
936
+ '9xl': number;
937
+ };
938
+ fontFamily: {
939
+ sans: string;
940
+ mono: string;
941
+ serif: string;
942
+ };
943
+ fontWeight: {
944
+ thin: string;
945
+ extralight: string;
946
+ light: string;
947
+ normal: string;
948
+ medium: string;
949
+ semibold: string;
950
+ bold: string;
951
+ extrabold: string;
952
+ black: string;
953
+ };
954
+ borderRadius: {
955
+ none: number;
956
+ sm: number;
957
+ DEFAULT: number;
958
+ md: number;
959
+ lg: number;
960
+ xl: number;
961
+ '2xl': number;
962
+ '3xl': number;
963
+ full: number;
964
+ };
965
+ borderWidth: {
966
+ DEFAULT: number;
967
+ 0: number;
968
+ 2: number;
969
+ 4: number;
970
+ 8: number;
971
+ };
972
+ opacity: {
973
+ 0: number;
974
+ 5: number;
975
+ 10: number;
976
+ 15: number;
977
+ 20: number;
978
+ 25: number;
979
+ 30: number;
980
+ 40: number;
981
+ 50: number;
982
+ 60: number;
983
+ 70: number;
984
+ 75: number;
985
+ 80: number;
986
+ 90: number;
987
+ 95: number;
988
+ 100: number;
989
+ };
990
+ lineHeight: {
991
+ none: number;
992
+ tight: number;
993
+ snug: number;
994
+ normal: number;
995
+ relaxed: number;
996
+ loose: number;
997
+ 3: string;
998
+ 4: string;
999
+ 5: string;
1000
+ 6: string;
1001
+ 7: string;
1002
+ 8: string;
1003
+ 9: string;
1004
+ 10: string;
1005
+ };
1006
+ letterSpacing: {
1007
+ tighter: number;
1008
+ tight: number;
1009
+ normal: number;
1010
+ wide: number;
1011
+ wider: number;
1012
+ widest: number;
1013
+ };
1014
+ zIndex: {
1015
+ auto: string;
1016
+ 0: number;
1017
+ 10: number;
1018
+ 20: number;
1019
+ 30: number;
1020
+ 40: number;
1021
+ 50: number;
1022
+ };
1023
+ flex: {
1024
+ 1: number;
1025
+ auto: string;
1026
+ initial: string;
1027
+ none: string;
1028
+ };
1029
+ shadow: {
1030
+ sm: {
1031
+ shadowColor: string;
1032
+ shadowOffset: {
1033
+ width: number;
1034
+ height: number;
1035
+ };
1036
+ shadowOpacity: number;
1037
+ shadowRadius: number;
1038
+ elevation: number;
1039
+ };
1040
+ DEFAULT: {
1041
+ shadowColor: string;
1042
+ shadowOffset: {
1043
+ width: number;
1044
+ height: number;
1045
+ };
1046
+ shadowOpacity: number;
1047
+ shadowRadius: number;
1048
+ elevation: number;
1049
+ };
1050
+ md: {
1051
+ shadowColor: string;
1052
+ shadowOffset: {
1053
+ width: number;
1054
+ height: number;
1055
+ };
1056
+ shadowOpacity: number;
1057
+ shadowRadius: number;
1058
+ elevation: number;
1059
+ };
1060
+ lg: {
1061
+ shadowColor: string;
1062
+ shadowOffset: {
1063
+ width: number;
1064
+ height: number;
1065
+ };
1066
+ shadowOpacity: number;
1067
+ shadowRadius: number;
1068
+ elevation: number;
1069
+ };
1070
+ xl: {
1071
+ shadowColor: string;
1072
+ shadowOffset: {
1073
+ width: number;
1074
+ height: number;
1075
+ };
1076
+ shadowOpacity: number;
1077
+ shadowRadius: number;
1078
+ elevation: number;
1079
+ };
1080
+ '2xl': {
1081
+ shadowColor: string;
1082
+ shadowOffset: {
1083
+ width: number;
1084
+ height: number;
1085
+ };
1086
+ shadowOpacity: number;
1087
+ shadowRadius: number;
1088
+ elevation: number;
1089
+ };
1090
+ none: {
1091
+ shadowColor: string;
1092
+ shadowOffset: {
1093
+ width: number;
1094
+ height: number;
1095
+ };
1096
+ shadowOpacity: number;
1097
+ shadowRadius: number;
1098
+ elevation: number;
1099
+ };
1100
+ };
1101
+ screens: {
1102
+ sm: number;
1103
+ md: number;
1104
+ lg: number;
1105
+ xl: number;
1106
+ '2xl': number;
1107
+ };
1108
+ keyframes: {};
1109
+ animation: {};
1110
+ };
1111
+ type DefaultColorName = keyof typeof defaultColors;
1112
+ type DefaultSpacingKey = `${keyof typeof defaultTheme.spacing}`;
1113
+
1114
+ declare const RESET_STYLE_ID = "kbach-reset";
1115
+ declare const BASE_RESET: string;
1116
+
1117
+ /**
1118
+ * Bounded LRU cache using Map's insertion-order iteration.
1119
+ * Map.keys().next() gives the oldest entry for O(1) eviction.
1120
+ * Safe upper bound prevents unbounded growth (no memory leak).
1121
+ */
1122
+ declare class LRUCache<K, V> {
1123
+ private readonly capacity;
1124
+ private readonly cache;
1125
+ private readonly onEvict?;
1126
+ constructor(capacity?: number, onEvict?: (key: K, value: V) => void);
1127
+ get(key: K): V | undefined;
1128
+ set(key: K, value: V): this;
1129
+ has(key: K): boolean;
1130
+ delete(key: K): boolean;
1131
+ clear(): void;
1132
+ get size(): number;
1133
+ }
1134
+
1135
+ /**
1136
+ * Detected at module load time — safe to call repeatedly without perf cost.
1137
+ */
1138
+ declare const isWeb: boolean;
1139
+ declare const isNative: boolean;
1140
+ declare function setResolveTarget(target: 'web' | 'native' | null): void;
1141
+ declare function getEffectiveIsWeb(): boolean;
1142
+ /**
1143
+ * Convert an arbitrary-bracket value to a native-friendly number when possible.
1144
+ * e.g. '10px' → 10, '1rem' → 16, '50%' → '50%' (keep as string), '#fff' → '#fff'
1145
+ */
1146
+ declare function toNativeValue(raw: string): string | number;
1147
+ /**
1148
+ * Escape a class name for use inside a CSS selector.
1149
+ * e.g. 'bg-[#fff]' → 'bg-\\[\\#fff\\]'
1150
+ */
1151
+ declare function escapeCSSSelector(cls: string): string;
1152
+
1153
+ /**
1154
+ * Styled console.warn for browser/runtime code. Uses the `%c` CSS-styling
1155
+ * console format (supported by Chrome, Firefox, Safari, and Edge DevTools)
1156
+ * so Kbach's own warnings are visually distinct from the surrounding noise —
1157
+ * a colored "[kbach]" tag followed by a short, plain message.
1158
+ *
1159
+ * Kept deliberately terse at call sites: one sentence, no walls of text.
1160
+ */
1161
+ declare function kbachWarn(message: string): void;
1162
+
1163
+ declare function parseClass(className: string): ParsedClass | null;
1164
+ /**
1165
+ * Split a class string into tokens. Whitespace at bracket depth > 0 is STRIPPED
1166
+ * (not just skipped) so that arbitrary values like rgb(41, 172, 15) become valid
1167
+ * CSS class name tokens: bg-[rgb(41,172,15)].
1168
+ */
1169
+ declare function splitClassTokens(classString: string): string[];
1170
+ /**
1171
+ * Normalize a full class string so it is safe to use as an HTML className value.
1172
+ * Strips spaces inside brackets: "bg-[rgb(41, 172, 15)] p-4" → "bg-[rgb(41,172,15)] p-4"
1173
+ */
1174
+ declare function normalizeClassString(classString: string): string;
1175
+ /** Parse a space-separated class string into individual ParsedClass objects. */
1176
+ declare function parseClasses(classString: string): ParsedClass[];
1177
+
1178
+ declare function resolveColor(value: string, colors: ThemeColors, isArbitrary: boolean): string | null;
1179
+ /**
1180
+ * Parse a hex color string (#rgb, #rgba, #rrggbb, #rrggbbaa) into an [r, g, b]
1181
+ * tuple. Any alpha nibble/byte is ignored — callers apply their own opacity.
1182
+ * Shared with useColors.ts's applyOpacity() so hex parsing lives in one place.
1183
+ */
1184
+ declare function parseHexRgb(hex: string): [number, number, number] | null;
1185
+
1186
+ declare function resolveSpacing(value: string, negative: boolean, spacing: ThemeConfig['spacing'], isArbitrary: boolean): string | number | null;
1187
+ declare function resolveSizing(value: string, spacing: ThemeConfig['spacing'], isArbitrary: boolean): string | number | null;
1188
+
1189
+ declare function resolveUtility(parsed: ParsedClass, theme: ThemeConfig): StyleValue | null;
1190
+ /**
1191
+ * Returns true if the utility name is known to the framework (built-in or plugin).
1192
+ * Used for dev-mode warnings — resolveUtility returning null could mean either
1193
+ * "intentionally null on this platform" or "completely unknown utility name".
1194
+ * This check covers the second case.
1195
+ */
1196
+ declare function isKnownUtility(utility: string): boolean;
1197
+ /**
1198
+ * Sorted (longest-first) unique list of all built-in + plugin utility prefixes.
1199
+ * Used by parser.ts for greedy prefix matching — replaces the hard-coded
1200
+ * UTILITY_PREFIXES array that had to be kept in sync manually.
1201
+ */
1202
+ declare function getBuiltinUtilityPrefixes(): readonly string[];
1203
+ /**
1204
+ * Set of all built-in + plugin standalone utility names.
1205
+ * Used by parser.ts to recognise no-value tokens — replaces the hard-coded
1206
+ * STANDALONE_UTILITIES set that had to be kept in sync manually.
1207
+ */
1208
+ declare function getBuiltinStandaloneNames(): ReadonlySet<string>;
1209
+
1210
+ declare function setDefaultFontFamily(font: string | undefined): void;
1211
+ declare function getDefaultFontFamily(): string | undefined;
1212
+ declare function disableRuntimeCSS(): void;
1213
+ declare function isRuntimeCSSDisabled(): boolean;
1214
+ declare function generateClassCSS(classString: string, theme: ThemeConfig, darkMode?: 'attribute' | 'class' | 'media', screens?: Record<string, number>): string;
1215
+ /**
1216
+ * Resolve a class string to a ResolvedStyle object.
1217
+ *
1218
+ * Results are cached per (theme, classString, darkMode) — repeated calls with
1219
+ * the same arguments are O(1). Different theme objects each get their own
1220
+ * cache so concurrent ThemeProviders with different configs are always correct.
1221
+ */
1222
+ declare function resolve(classString: string, theme: ThemeConfig, darkMode?: 'attribute' | 'class' | 'media'): ResolvedStyle;
1223
+ /**
1224
+ * Flatten a ResolvedStyle into a single StyleValue for the current runtime state.
1225
+ * Used by useStyles() and styled().
1226
+ *
1227
+ * The sort step is memoized per resolved object reference (#6) — when resolve()
1228
+ * returns a cached object, getSortedEntries() is O(1) on all subsequent calls.
1229
+ */
1230
+ declare function flatten(resolved: ResolvedStyle, isDark: boolean, state?: {
1231
+ hover?: boolean;
1232
+ focus?: boolean;
1233
+ pressed?: boolean;
1234
+ active?: boolean;
1235
+ disabled?: boolean;
1236
+ checked?: boolean;
1237
+ visited?: boolean;
1238
+ placeholder?: boolean;
1239
+ }, breakpoints?: Set<string>): StyleValue;
1240
+ /**
1241
+ * Clear CSS injection state so stale rules are re-injected when the theme changes.
1242
+ *
1243
+ * The per-theme style cache (WeakMap) does not need to be cleared manually:
1244
+ * updateConfig() creates a new theme object, making the old cache entry
1245
+ * automatically unreachable for GC.
1246
+ */
1247
+ declare function clearCache(): void;
1248
+
1249
+ /**
1250
+ * Load, merge, and cache the resolved config.
1251
+ * Call resetConfig() to force a reload (e.g. in tests or after live update).
1252
+ */
1253
+ declare function getConfig(): ResolvedConfig;
1254
+ declare function resetConfig(): void;
1255
+ declare function buildConfig(userConfig: FrameworkConfig): ResolvedConfig;
1256
+ type ConfigListener = (config: ResolvedConfig) => void;
1257
+ declare function onConfigChange(listener: ConfigListener): () => void;
1258
+ declare function updateConfig(userConfig: FrameworkConfig): void;
1259
+ /**
1260
+ * Like updateConfig, but only calls it when the config object reference has
1261
+ * actually changed. Used by the Babel-injected IIFE so that:
1262
+ * - multiple files with kbach classes don't re-run the update on every load
1263
+ * - Fast Refresh DOES re-run when kbach.config.js changes (new module → new object)
1264
+ */
1265
+ declare function initConfig(userConfig: FrameworkConfig): void;
1266
+
1267
+ /**
1268
+ * Module-level dark-mode singleton.
1269
+ *
1270
+ * This intentionally lives outside React so the custom JSX runtime can read it
1271
+ * synchronously during render without needing context. ThemeProvider writes to it;
1272
+ * DarkWrapper / InteractiveWrapper subscribe via useSyncExternalStore.
1273
+ *
1274
+ * Used to be backed by globalThis instead of a plain module-level variable:
1275
+ * tsup used to bundle core/ separately into each of dist/index.js and
1276
+ * dist/jsx-runtime.js (esbuild doesn't support code-splitting CJS output),
1277
+ * so Metro loading each by path got independent copies of this module with
1278
+ * independent top-level state. core/ is now built as its own dist/core/
1279
+ * entry and required externally by both (see packages/ui/tsup.config.ts),
1280
+ * so there's only ever one real instance of this module to begin with — a
1281
+ * plain module-level object is enough.
1282
+ */
1283
+ /**
1284
+ * Silently update isDark without notifying subscribers.
1285
+ * Safe to call during React's render phase — no state side-effects.
1286
+ * ThemeProvider calls this before returning JSX so the JSX runtime and
1287
+ * children that call getGlobalDarkMode() during the same render pass
1288
+ * already see the correct value.
1289
+ */
1290
+ declare function syncGlobalDarkMode(isDark: boolean): void;
1291
+ /**
1292
+ * Update isDark and notify all subscribers.
1293
+ * Called by ThemeProvider in a layout effect (after commit) so DarkWrapper /
1294
+ * InteractiveWrapper consumers re-render with the updated dark-mode value.
1295
+ * Notifications are skipped when the value hasn't changed since the last
1296
+ * broadcast to avoid spurious re-renders — see the notifiedIsDark comment
1297
+ * above for why that comparison can't use `isDark` itself.
1298
+ */
1299
+ declare function setGlobalDarkMode(isDark: boolean): void;
1300
+ /** Read current dark-mode state synchronously (safe in render, no hook needed). */
1301
+ declare function getGlobalDarkMode(): boolean;
1302
+ /**
1303
+ * Subscribe to dark-mode changes.
1304
+ * @returns Cleanup function — call it to unsubscribe (no leak).
1305
+ */
1306
+ declare function subscribeGlobalDarkMode(callback: () => void): () => void;
1307
+
1308
+ /**
1309
+ * Global responsive width store.
1310
+ *
1311
+ * Used to be backed by globalThis so all CJS bundle splits (index.js,
1312
+ * jsx-runtime.js, jsx-dev-runtime.js) shared one instance — tsup used to
1313
+ * bundle core/ separately into each of them (esbuild doesn't support
1314
+ * code-splitting CJS output). core/ is now built as its own dist/core/
1315
+ * entry and required externally by all three (see
1316
+ * packages/ui/tsup.config.ts), so there's only ever one real instance of
1317
+ * this module to begin with — a plain module-level object is enough.
1318
+ */
1319
+ type WidthListener = () => void;
1320
+ /** Synchronous write for use in the render phase. */
1321
+ declare function syncGlobalWidth(width: number): void;
1322
+ /** Update the breakpoint-name → min-width map from the resolved theme config. */
1323
+ declare function syncGlobalScreens(screens: Record<string, number>): void;
1324
+ declare function getGlobalScreens(): Record<string, number>;
1325
+ /**
1326
+ * Async write — fires listeners so subscribers re-render. Skip check uses
1327
+ * notifiedWidth, not width — see the ResponsiveStore.notifiedWidth comment.
1328
+ */
1329
+ declare function setGlobalWidth(width: number): void;
1330
+ declare function getGlobalWidth(): number;
1331
+ declare function subscribeGlobalWidth(listener: WidthListener): () => void;
1332
+ /**
1333
+ * Returns the Set of breakpoint names that are currently active
1334
+ * (i.e. width >= their min-width threshold).
1335
+ *
1336
+ * `screens` defaults to the global store's screens map (the common case —
1337
+ * DarkWrapper/InteractiveWrapper have no per-tree config available). Pass an
1338
+ * explicit map to check against a LOCAL config instead — e.g. useBreakpoint()/
1339
+ * useResponsive() pass the nearest <ThemeProvider>'s own `config.theme.screens`
1340
+ * so they stay correct per-provider rather than silently reading whichever
1341
+ * config the global store happens to hold (see ThemeProvider's per-tree
1342
+ * config-override limitation).
1343
+ */
1344
+ declare function getActiveBreakpoints(width?: number, screens?: Record<string, number>): Set<string>;
1345
+
1346
+ export { BASE_RESET, type ColorShades, type ColorValue, type DarkMode, type DefaultColorName, type DefaultSpacingKey, type FrameworkConfig, LRUCache, type ParsedClass, type Platform, type PluginAPI, RESET_STYLE_ID, type ResolvedConfig, type ResolvedStyle, type StyleValue, type ThemeColors, type ThemeConfig, type ThemeMode, type ThemeSpacing, buildConfig, clearCache, clearPluginModifiers, defaultColors, defaultTheme, disableRuntimeCSS, escapeCSSSelector, expandModeAwareColorClasses, flatten, generateClassCSS, generateKbachTypesDts, getActiveBreakpoints, getAllModifierNames, getBuiltinStandaloneNames, getBuiltinUtilityPrefixes, getConfig, getDefaultFontFamily, getEffectiveIsWeb, getGlobalDarkMode, getGlobalScreens, getGlobalWidth, getInteractiveModifiers, getModeModifiers, getModifier, getResponsiveModifiers, initConfig, isKnownModifier, isKnownUtility, isModeAwareColor, isNative, isRuntimeCSSDisabled, isWeb, kbachWarn, matchModifier, normalizeClassString, onConfigChange, parseClass, parseClasses, parseHexRgb, registerModifier, resetConfig, resolve, resolveColor, resolveSizing, resolveSpacing, resolveUtility, setDefaultFontFamily, setGlobalDarkMode, setGlobalWidth, setResolveTarget, splitClassTokens, subscribeGlobalDarkMode, subscribeGlobalWidth, syncGlobalDarkMode, syncGlobalScreens, syncGlobalWidth, toNativeValue, updateConfig };