@kbach/ui 0.1.0-beta.6 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1404 +0,0 @@
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
- * Returns a value that's the SAME object across every physical copy of core/
193
- * a bundler might produce for a single running process — not just across
194
- * dist/index.js / dist/jsx-runtime.js / dist/jsx-dev-runtime.js (the CJS
195
- * build, which already shares one real dist/core/index.js via
196
- * externalization — see tsup.config.ts's CORE_EXTERNAL), but ALSO across
197
- * that CJS build and the separate ESM build (dist/index.mjs etc., which
198
- * inlines its own copy of core/ — a deliberate, accepted trade-off for
199
- * Rollup/Vite compatibility, see context.tsx's ThemeContext comment for the
200
- * full story).
201
- *
202
- * Confirmed as a real, live bug (not just theoretical), back when ThemeProvider
203
- * still had a separate native-specific wrapper at the now-removed
204
- * '@kbach/ui/native' subpath (see native/index.ts): a React Native app that
205
- * reached @kbach/ui through more than one physical dist file — e.g.
206
- * `import { ThemeProvider } from '@kbach/ui/native'` in one file and
207
- * `import { useIsDark } from '@kbach/ui'` in another, which Metro can resolve
208
- * to DIFFERENT dist files per call site — got dark:/light: classes silently
209
- * inert from one instance while useIsDark() read a different,
210
- * correctly-updating instance (or vice versa), depending on which module
211
- * each half of the app happened to load through. ThemeProvider now auto-
212
- * detects native itself (no separate wrapper/import path to diverge on), but
213
- * the underlying dual-build split (ESM for Rollup/Vite, CJS for Metro) is
214
- * still real, so darkModeStore/responsiveStore/config/etc. still need this —
215
- * jsx-runtime.tsx, for instance, still reaches core/ as its own call site.
216
- * See RULES.md rule 3: this is exactly the "globalThis-singleton hack" it
217
- * allows when a real fix (one guaranteed physical module) isn't available —
218
- * which it isn't here, short of giving up either Rollup or Metro compatibility
219
- * entirely.
220
- *
221
- * Keyed on Symbol.for() (the well-known global symbol registry, shared
222
- * across realms/module copies by spec) rather than a plain string property,
223
- * so this can never collide with anything else that happens to touch
224
- * globalThis.
225
- */
226
- declare function getGlobalSingleton<T>(key: string, create: () => T): T;
227
-
228
- /**
229
- * True for a mode-aware color pair (`{ light, dark }`), as opposed to a plain
230
- * hex/rgb/alias string. Shared by config.ts (alias-chain resolution),
231
- * resolvers/color.ts (direct lookups), and modeAwareColors.ts (className
232
- * expansion) so all three agree on exactly one definition. Real shade keys
233
- * are always numeric strings ('1'–'12'), so this can never collide with one.
234
- */
235
- declare function isModeAwareColor(v: unknown): v is {
236
- light: string;
237
- dark: string;
238
- };
239
-
240
- /**
241
- * Expand every class referencing a mode-aware color (a kbach.config.js color
242
- * value shaped `{ light, dark }`) into an explicit base + dark: pair BEFORE
243
- * normal parsing — e.g. `bg-surface` becomes `bg-[#ffffff] dark:bg-[#111827]`.
244
- * `bg-surface/50` becomes `bg-[#ffffff]/50 dark:bg-[#111827]/50` (the arbitrary-
245
- * color-plus-opacity composition already resolveColor() already supports).
246
- * `hover:bg-surface` becomes `hover:bg-[#ffffff] dark:hover:bg-[#111827]` —
247
- * every other modifier already present on the token carries through onto
248
- * both halves of the pair unchanged.
249
- *
250
- * A token that ALREADY carries an explicit dark:/light:/not-dark:/not-light:
251
- * modifier (someone writes `dark:hover:bg-primary` on a `primary` that's
252
- * already mode-aware, usually out of habit from before it was) isn't split
253
- * into a pair — that would be redundant on top of an already-explicit
254
- * choice. Instead the matching side is substituted in place and every
255
- * modifier, including the dark:/light: itself, is left exactly as written,
256
- * so `dark:hover:bg-primary` still only applies in dark mode, using the
257
- * dark side (not the resolveColor()-level fallback's light side, which is
258
- * only ever reached by a mode-aware pair that skipped this expansion
259
- * entirely — not a path normal className resolution takes).
260
- *
261
- * Runs once, upfront, purely as a string rewrite — everything downstream
262
- * (CSS generation, native bucketing/flatten(), the existing dark: reactivity
263
- * machinery: DarkWrapper, bucketMods()) then handles the result exactly like
264
- * a hand-written dark: pair, with zero further changes needed anywhere else.
265
- * That also means resolve()'s cache (keyed on the ORIGINAL, unexpanded string
266
- * — see resolver.ts) stays correct without any changes to its cache key.
267
- */
268
- declare function expandModeAwareColorClasses(classString: string, colors: ThemeColors): string;
269
-
270
- /**
271
- * Generates the KbachCustomColors/KbachCustomSpacing module-augmentation
272
- * source for every color/spacing key `extend.theme` added beyond the built-in
273
- * defaults. Called by both the Vite plugin and the Babel plugin (@kbach/ui/babel-plugin) —
274
- * kept here, shared, so "which colors count as custom" and "flat string vs.
275
- * ColorScale" can't drift between the two.
276
- *
277
- * Returns '' (nothing to write) when the theme adds no custom colors or
278
- * spacing keys at all, so callers can skip writing/deleting a file for the
279
- * common case of a project still on the stock theme.
280
- */
281
- declare function generateKbachTypesDts(theme: ThemeConfig): string;
282
-
283
- declare const defaultColors: {
284
- transparent: string;
285
- current: string;
286
- black: string;
287
- white: string;
288
- slate: {
289
- 1: string;
290
- 2: string;
291
- 3: string;
292
- 4: string;
293
- 5: string;
294
- 6: string;
295
- 7: string;
296
- 8: string;
297
- 9: string;
298
- 10: string;
299
- 11: string;
300
- 12: string;
301
- };
302
- gray: {
303
- 1: string;
304
- 2: string;
305
- 3: string;
306
- 4: string;
307
- 5: string;
308
- 6: string;
309
- 7: string;
310
- 8: string;
311
- 9: string;
312
- 10: string;
313
- 11: string;
314
- 12: string;
315
- };
316
- zinc: {
317
- 1: string;
318
- 2: string;
319
- 3: string;
320
- 4: string;
321
- 5: string;
322
- 6: string;
323
- 7: string;
324
- 8: string;
325
- 9: string;
326
- 10: string;
327
- 11: string;
328
- 12: string;
329
- };
330
- neutral: {
331
- 1: string;
332
- 2: string;
333
- 3: string;
334
- 4: string;
335
- 5: string;
336
- 6: string;
337
- 7: string;
338
- 8: string;
339
- 9: string;
340
- 10: string;
341
- 11: string;
342
- 12: string;
343
- };
344
- stone: {
345
- 1: string;
346
- 2: string;
347
- 3: string;
348
- 4: string;
349
- 5: string;
350
- 6: string;
351
- 7: string;
352
- 8: string;
353
- 9: string;
354
- 10: string;
355
- 11: string;
356
- 12: string;
357
- };
358
- red: {
359
- 1: string;
360
- 2: string;
361
- 3: string;
362
- 4: string;
363
- 5: string;
364
- 6: string;
365
- 7: string;
366
- 8: string;
367
- 9: string;
368
- 10: string;
369
- 11: string;
370
- 12: string;
371
- };
372
- orange: {
373
- 1: string;
374
- 2: string;
375
- 3: string;
376
- 4: string;
377
- 5: string;
378
- 6: string;
379
- 7: string;
380
- 8: string;
381
- 9: string;
382
- 10: string;
383
- 11: string;
384
- 12: string;
385
- };
386
- amber: {
387
- 1: string;
388
- 2: string;
389
- 3: string;
390
- 4: string;
391
- 5: string;
392
- 6: string;
393
- 7: string;
394
- 8: string;
395
- 9: string;
396
- 10: string;
397
- 11: string;
398
- 12: string;
399
- };
400
- yellow: {
401
- 1: string;
402
- 2: string;
403
- 3: string;
404
- 4: string;
405
- 5: string;
406
- 6: string;
407
- 7: string;
408
- 8: string;
409
- 9: string;
410
- 10: string;
411
- 11: string;
412
- 12: string;
413
- };
414
- lime: {
415
- 1: string;
416
- 2: string;
417
- 3: string;
418
- 4: string;
419
- 5: string;
420
- 6: string;
421
- 7: string;
422
- 8: string;
423
- 9: string;
424
- 10: string;
425
- 11: string;
426
- 12: string;
427
- };
428
- green: {
429
- 1: string;
430
- 2: string;
431
- 3: string;
432
- 4: string;
433
- 5: string;
434
- 6: string;
435
- 7: string;
436
- 8: string;
437
- 9: string;
438
- 10: string;
439
- 11: string;
440
- 12: string;
441
- };
442
- emerald: {
443
- 1: string;
444
- 2: string;
445
- 3: string;
446
- 4: string;
447
- 5: string;
448
- 6: string;
449
- 7: string;
450
- 8: string;
451
- 9: string;
452
- 10: string;
453
- 11: string;
454
- 12: string;
455
- };
456
- teal: {
457
- 1: string;
458
- 2: string;
459
- 3: string;
460
- 4: string;
461
- 5: string;
462
- 6: string;
463
- 7: string;
464
- 8: string;
465
- 9: string;
466
- 10: string;
467
- 11: string;
468
- 12: string;
469
- };
470
- cyan: {
471
- 1: string;
472
- 2: string;
473
- 3: string;
474
- 4: string;
475
- 5: string;
476
- 6: string;
477
- 7: string;
478
- 8: string;
479
- 9: string;
480
- 10: string;
481
- 11: string;
482
- 12: string;
483
- };
484
- sky: {
485
- 1: string;
486
- 2: string;
487
- 3: string;
488
- 4: string;
489
- 5: string;
490
- 6: string;
491
- 7: string;
492
- 8: string;
493
- 9: string;
494
- 10: string;
495
- 11: string;
496
- 12: string;
497
- };
498
- blue: {
499
- 1: string;
500
- 2: string;
501
- 3: string;
502
- 4: string;
503
- 5: string;
504
- 6: string;
505
- 7: string;
506
- 8: string;
507
- 9: string;
508
- 10: string;
509
- 11: string;
510
- 12: string;
511
- };
512
- indigo: {
513
- 1: string;
514
- 2: string;
515
- 3: string;
516
- 4: string;
517
- 5: string;
518
- 6: string;
519
- 7: string;
520
- 8: string;
521
- 9: string;
522
- 10: string;
523
- 11: string;
524
- 12: string;
525
- };
526
- violet: {
527
- 1: string;
528
- 2: string;
529
- 3: string;
530
- 4: string;
531
- 5: string;
532
- 6: string;
533
- 7: string;
534
- 8: string;
535
- 9: string;
536
- 10: string;
537
- 11: string;
538
- 12: string;
539
- };
540
- purple: {
541
- 1: string;
542
- 2: string;
543
- 3: string;
544
- 4: string;
545
- 5: string;
546
- 6: string;
547
- 7: string;
548
- 8: string;
549
- 9: string;
550
- 10: string;
551
- 11: string;
552
- 12: string;
553
- };
554
- fuchsia: {
555
- 1: string;
556
- 2: string;
557
- 3: string;
558
- 4: string;
559
- 5: string;
560
- 6: string;
561
- 7: string;
562
- 8: string;
563
- 9: string;
564
- 10: string;
565
- 11: string;
566
- 12: string;
567
- };
568
- pink: {
569
- 1: string;
570
- 2: string;
571
- 3: string;
572
- 4: string;
573
- 5: string;
574
- 6: string;
575
- 7: string;
576
- 8: string;
577
- 9: string;
578
- 10: string;
579
- 11: string;
580
- 12: string;
581
- };
582
- rose: {
583
- 1: string;
584
- 2: string;
585
- 3: string;
586
- 4: string;
587
- 5: string;
588
- 6: string;
589
- 7: string;
590
- 8: string;
591
- 9: string;
592
- 10: string;
593
- 11: string;
594
- 12: string;
595
- };
596
- };
597
- declare const defaultTheme: {
598
- colors: {
599
- transparent: string;
600
- current: string;
601
- black: string;
602
- white: string;
603
- slate: {
604
- 1: string;
605
- 2: string;
606
- 3: string;
607
- 4: string;
608
- 5: string;
609
- 6: string;
610
- 7: string;
611
- 8: string;
612
- 9: string;
613
- 10: string;
614
- 11: string;
615
- 12: string;
616
- };
617
- gray: {
618
- 1: string;
619
- 2: string;
620
- 3: string;
621
- 4: string;
622
- 5: string;
623
- 6: string;
624
- 7: string;
625
- 8: string;
626
- 9: string;
627
- 10: string;
628
- 11: string;
629
- 12: string;
630
- };
631
- zinc: {
632
- 1: string;
633
- 2: string;
634
- 3: string;
635
- 4: string;
636
- 5: string;
637
- 6: string;
638
- 7: string;
639
- 8: string;
640
- 9: string;
641
- 10: string;
642
- 11: string;
643
- 12: string;
644
- };
645
- neutral: {
646
- 1: string;
647
- 2: string;
648
- 3: string;
649
- 4: string;
650
- 5: string;
651
- 6: string;
652
- 7: string;
653
- 8: string;
654
- 9: string;
655
- 10: string;
656
- 11: string;
657
- 12: string;
658
- };
659
- stone: {
660
- 1: string;
661
- 2: string;
662
- 3: string;
663
- 4: string;
664
- 5: string;
665
- 6: string;
666
- 7: string;
667
- 8: string;
668
- 9: string;
669
- 10: string;
670
- 11: string;
671
- 12: string;
672
- };
673
- red: {
674
- 1: string;
675
- 2: string;
676
- 3: string;
677
- 4: string;
678
- 5: string;
679
- 6: string;
680
- 7: string;
681
- 8: string;
682
- 9: string;
683
- 10: string;
684
- 11: string;
685
- 12: string;
686
- };
687
- orange: {
688
- 1: string;
689
- 2: string;
690
- 3: string;
691
- 4: string;
692
- 5: string;
693
- 6: string;
694
- 7: string;
695
- 8: string;
696
- 9: string;
697
- 10: string;
698
- 11: string;
699
- 12: string;
700
- };
701
- amber: {
702
- 1: string;
703
- 2: string;
704
- 3: string;
705
- 4: string;
706
- 5: string;
707
- 6: string;
708
- 7: string;
709
- 8: string;
710
- 9: string;
711
- 10: string;
712
- 11: string;
713
- 12: string;
714
- };
715
- yellow: {
716
- 1: string;
717
- 2: string;
718
- 3: string;
719
- 4: string;
720
- 5: string;
721
- 6: string;
722
- 7: string;
723
- 8: string;
724
- 9: string;
725
- 10: string;
726
- 11: string;
727
- 12: string;
728
- };
729
- lime: {
730
- 1: string;
731
- 2: string;
732
- 3: string;
733
- 4: string;
734
- 5: string;
735
- 6: string;
736
- 7: string;
737
- 8: string;
738
- 9: string;
739
- 10: string;
740
- 11: string;
741
- 12: string;
742
- };
743
- green: {
744
- 1: string;
745
- 2: string;
746
- 3: string;
747
- 4: string;
748
- 5: string;
749
- 6: string;
750
- 7: string;
751
- 8: string;
752
- 9: string;
753
- 10: string;
754
- 11: string;
755
- 12: string;
756
- };
757
- emerald: {
758
- 1: string;
759
- 2: string;
760
- 3: string;
761
- 4: string;
762
- 5: string;
763
- 6: string;
764
- 7: string;
765
- 8: string;
766
- 9: string;
767
- 10: string;
768
- 11: string;
769
- 12: string;
770
- };
771
- teal: {
772
- 1: string;
773
- 2: string;
774
- 3: string;
775
- 4: string;
776
- 5: string;
777
- 6: string;
778
- 7: string;
779
- 8: string;
780
- 9: string;
781
- 10: string;
782
- 11: string;
783
- 12: string;
784
- };
785
- cyan: {
786
- 1: string;
787
- 2: string;
788
- 3: string;
789
- 4: string;
790
- 5: string;
791
- 6: string;
792
- 7: string;
793
- 8: string;
794
- 9: string;
795
- 10: string;
796
- 11: string;
797
- 12: string;
798
- };
799
- sky: {
800
- 1: string;
801
- 2: string;
802
- 3: string;
803
- 4: string;
804
- 5: string;
805
- 6: string;
806
- 7: string;
807
- 8: string;
808
- 9: string;
809
- 10: string;
810
- 11: string;
811
- 12: string;
812
- };
813
- blue: {
814
- 1: string;
815
- 2: string;
816
- 3: string;
817
- 4: string;
818
- 5: string;
819
- 6: string;
820
- 7: string;
821
- 8: string;
822
- 9: string;
823
- 10: string;
824
- 11: string;
825
- 12: string;
826
- };
827
- indigo: {
828
- 1: string;
829
- 2: string;
830
- 3: string;
831
- 4: string;
832
- 5: string;
833
- 6: string;
834
- 7: string;
835
- 8: string;
836
- 9: string;
837
- 10: string;
838
- 11: string;
839
- 12: string;
840
- };
841
- violet: {
842
- 1: string;
843
- 2: string;
844
- 3: string;
845
- 4: string;
846
- 5: string;
847
- 6: string;
848
- 7: string;
849
- 8: string;
850
- 9: string;
851
- 10: string;
852
- 11: string;
853
- 12: string;
854
- };
855
- purple: {
856
- 1: string;
857
- 2: string;
858
- 3: string;
859
- 4: string;
860
- 5: string;
861
- 6: string;
862
- 7: string;
863
- 8: string;
864
- 9: string;
865
- 10: string;
866
- 11: string;
867
- 12: string;
868
- };
869
- fuchsia: {
870
- 1: string;
871
- 2: string;
872
- 3: string;
873
- 4: string;
874
- 5: string;
875
- 6: string;
876
- 7: string;
877
- 8: string;
878
- 9: string;
879
- 10: string;
880
- 11: string;
881
- 12: string;
882
- };
883
- pink: {
884
- 1: string;
885
- 2: string;
886
- 3: string;
887
- 4: string;
888
- 5: string;
889
- 6: string;
890
- 7: string;
891
- 8: string;
892
- 9: string;
893
- 10: string;
894
- 11: string;
895
- 12: string;
896
- };
897
- rose: {
898
- 1: string;
899
- 2: string;
900
- 3: string;
901
- 4: string;
902
- 5: string;
903
- 6: string;
904
- 7: string;
905
- 8: string;
906
- 9: string;
907
- 10: string;
908
- 11: string;
909
- 12: string;
910
- };
911
- };
912
- spacing: {
913
- px: number;
914
- 0: number;
915
- '0.5': number;
916
- 1: number;
917
- '1.5': number;
918
- 2: number;
919
- '2.5': number;
920
- 3: number;
921
- '3.5': number;
922
- 4: number;
923
- 5: number;
924
- 6: number;
925
- 7: number;
926
- 8: number;
927
- 9: number;
928
- 10: number;
929
- 11: number;
930
- 12: number;
931
- 14: number;
932
- 16: number;
933
- 20: number;
934
- 24: number;
935
- 28: number;
936
- 32: number;
937
- 36: number;
938
- 40: number;
939
- 44: number;
940
- 48: number;
941
- 52: number;
942
- 56: number;
943
- 60: number;
944
- 64: number;
945
- 72: number;
946
- 80: number;
947
- 96: number;
948
- auto: string;
949
- full: string;
950
- '1/2': string;
951
- '1/3': string;
952
- '2/3': string;
953
- '1/4': string;
954
- '3/4': string;
955
- screen: string;
956
- min: string;
957
- max: string;
958
- fit: string;
959
- };
960
- fontSize: {
961
- xs: number;
962
- sm: number;
963
- base: number;
964
- lg: number;
965
- xl: number;
966
- '2xl': number;
967
- '3xl': number;
968
- '4xl': number;
969
- '5xl': number;
970
- '6xl': number;
971
- '7xl': number;
972
- '8xl': number;
973
- '9xl': number;
974
- };
975
- fontFamily: {
976
- sans: string;
977
- mono: string;
978
- serif: string;
979
- };
980
- fontWeight: {
981
- thin: string;
982
- extralight: string;
983
- light: string;
984
- normal: string;
985
- medium: string;
986
- semibold: string;
987
- bold: string;
988
- extrabold: string;
989
- black: string;
990
- };
991
- borderRadius: {
992
- none: number;
993
- sm: number;
994
- DEFAULT: number;
995
- md: number;
996
- lg: number;
997
- xl: number;
998
- '2xl': number;
999
- '3xl': number;
1000
- full: number;
1001
- };
1002
- borderWidth: {
1003
- DEFAULT: number;
1004
- 0: number;
1005
- 2: number;
1006
- 4: number;
1007
- 8: number;
1008
- };
1009
- opacity: {
1010
- 0: number;
1011
- 5: number;
1012
- 10: number;
1013
- 15: number;
1014
- 20: number;
1015
- 25: number;
1016
- 30: number;
1017
- 40: number;
1018
- 50: number;
1019
- 60: number;
1020
- 70: number;
1021
- 75: number;
1022
- 80: number;
1023
- 90: number;
1024
- 95: number;
1025
- 100: number;
1026
- };
1027
- lineHeight: {
1028
- none: number;
1029
- tight: number;
1030
- snug: number;
1031
- normal: number;
1032
- relaxed: number;
1033
- loose: number;
1034
- 3: string;
1035
- 4: string;
1036
- 5: string;
1037
- 6: string;
1038
- 7: string;
1039
- 8: string;
1040
- 9: string;
1041
- 10: string;
1042
- };
1043
- letterSpacing: {
1044
- tighter: number;
1045
- tight: number;
1046
- normal: number;
1047
- wide: number;
1048
- wider: number;
1049
- widest: number;
1050
- };
1051
- zIndex: {
1052
- auto: string;
1053
- 0: number;
1054
- 10: number;
1055
- 20: number;
1056
- 30: number;
1057
- 40: number;
1058
- 50: number;
1059
- };
1060
- flex: {
1061
- 1: number;
1062
- auto: string;
1063
- initial: string;
1064
- none: string;
1065
- };
1066
- shadow: {
1067
- sm: {
1068
- shadowColor: string;
1069
- shadowOffset: {
1070
- width: number;
1071
- height: number;
1072
- };
1073
- shadowOpacity: number;
1074
- shadowRadius: number;
1075
- elevation: number;
1076
- boxShadow: string;
1077
- };
1078
- DEFAULT: {
1079
- shadowColor: string;
1080
- shadowOffset: {
1081
- width: number;
1082
- height: number;
1083
- };
1084
- shadowOpacity: number;
1085
- shadowRadius: number;
1086
- elevation: number;
1087
- boxShadow: string;
1088
- };
1089
- md: {
1090
- shadowColor: string;
1091
- shadowOffset: {
1092
- width: number;
1093
- height: number;
1094
- };
1095
- shadowOpacity: number;
1096
- shadowRadius: number;
1097
- elevation: number;
1098
- boxShadow: string;
1099
- };
1100
- lg: {
1101
- shadowColor: string;
1102
- shadowOffset: {
1103
- width: number;
1104
- height: number;
1105
- };
1106
- shadowOpacity: number;
1107
- shadowRadius: number;
1108
- elevation: number;
1109
- boxShadow: string;
1110
- };
1111
- xl: {
1112
- shadowColor: string;
1113
- shadowOffset: {
1114
- width: number;
1115
- height: number;
1116
- };
1117
- shadowOpacity: number;
1118
- shadowRadius: number;
1119
- elevation: number;
1120
- boxShadow: string;
1121
- };
1122
- '2xl': {
1123
- shadowColor: string;
1124
- shadowOffset: {
1125
- width: number;
1126
- height: number;
1127
- };
1128
- shadowOpacity: number;
1129
- shadowRadius: number;
1130
- elevation: number;
1131
- boxShadow: string;
1132
- };
1133
- inner: {
1134
- boxShadow: string;
1135
- };
1136
- none: {
1137
- shadowColor: string;
1138
- shadowOffset: {
1139
- width: number;
1140
- height: number;
1141
- };
1142
- shadowOpacity: number;
1143
- shadowRadius: number;
1144
- elevation: number;
1145
- boxShadow: string;
1146
- };
1147
- };
1148
- screens: {
1149
- sm: number;
1150
- md: number;
1151
- lg: number;
1152
- xl: number;
1153
- '2xl': number;
1154
- };
1155
- keyframes: {};
1156
- animation: {};
1157
- };
1158
- type DefaultColorName = keyof typeof defaultColors;
1159
- type DefaultSpacingKey = `${keyof typeof defaultTheme.spacing}`;
1160
-
1161
- declare const RESET_STYLE_ID = "kbach-reset";
1162
- declare const BASE_RESET: string;
1163
-
1164
- /**
1165
- * Bounded LRU cache using Map's insertion-order iteration.
1166
- * Map.keys().next() gives the oldest entry for O(1) eviction.
1167
- * Safe upper bound prevents unbounded growth (no memory leak).
1168
- */
1169
- declare class LRUCache<K, V> {
1170
- private readonly capacity;
1171
- private readonly cache;
1172
- private readonly onEvict?;
1173
- constructor(capacity?: number, onEvict?: (key: K, value: V) => void);
1174
- get(key: K): V | undefined;
1175
- set(key: K, value: V): this;
1176
- has(key: K): boolean;
1177
- delete(key: K): boolean;
1178
- clear(): void;
1179
- get size(): number;
1180
- }
1181
-
1182
- /**
1183
- * Detected at module load time — safe to call repeatedly without perf cost.
1184
- */
1185
- declare const isWeb: boolean;
1186
- declare const isNative: boolean;
1187
- declare function setResolveTarget(target: 'web' | 'native' | null): void;
1188
- declare function getEffectiveIsWeb(): boolean;
1189
- /**
1190
- * Convert an arbitrary-bracket value to a native-friendly number when possible.
1191
- * e.g. '10px' → 10, '1rem' → 16, '50%' → '50%' (keep as string), '#fff' → '#fff'
1192
- */
1193
- declare function toNativeValue(raw: string): string | number;
1194
- /**
1195
- * Escape a class name for use inside a CSS selector.
1196
- * e.g. 'bg-[#fff]' → 'bg-\\[\\#fff\\]'
1197
- *
1198
- * Also escapes a leading digit: a CSS identifier can't start with an
1199
- * unescaped digit — `.2xl\:text-lg { ... }` is invalid CSS and every browser
1200
- * silently fails to match it, which is exactly what happens for a screen/
1201
- * breakpoint literally named "2xl" (or any other numeric-leading class).
1202
- * Escaped per the CSS spec — a backslash plus the character's hex code
1203
- * point, followed by one space to terminate the hex escape (always safe to
1204
- * include, and needed here since "2xl"'s next character "x" isn't itself a
1205
- * hex digit that could otherwise be read as part of the escape by mistake).
1206
- */
1207
- declare function escapeCSSSelector(cls: string): string;
1208
-
1209
- /**
1210
- * Styled console.warn for browser/runtime code. Uses the `%c` CSS-styling
1211
- * console format (supported by Chrome, Firefox, Safari, and Edge DevTools)
1212
- * so Kbach's own warnings are visually distinct from the surrounding noise —
1213
- * a colored "[kbach]" tag followed by a short, plain message.
1214
- *
1215
- * Kept deliberately terse at call sites: one sentence, no walls of text.
1216
- */
1217
- declare function kbachWarn(message: string): void;
1218
-
1219
- declare function parseClass(className: string): ParsedClass | null;
1220
- /**
1221
- * Split a class string into tokens. Whitespace at bracket depth > 0 is STRIPPED
1222
- * (not just skipped) so that arbitrary values like rgb(41, 172, 15) become valid
1223
- * CSS class name tokens: bg-[rgb(41,172,15)].
1224
- */
1225
- declare function splitClassTokens(classString: string): string[];
1226
- /**
1227
- * Normalize a full class string so it is safe to use as an HTML className value.
1228
- * Strips spaces inside brackets: "bg-[rgb(41, 172, 15)] p-4" → "bg-[rgb(41,172,15)] p-4"
1229
- */
1230
- declare function normalizeClassString(classString: string): string;
1231
- /** Parse a space-separated class string into individual ParsedClass objects. */
1232
- declare function parseClasses(classString: string): ParsedClass[];
1233
-
1234
- declare function resolveColor(value: string, colors: ThemeColors, isArbitrary: boolean): string | null;
1235
- /**
1236
- * Parse a hex color string (#rgb, #rgba, #rrggbb, #rrggbbaa) into an [r, g, b]
1237
- * tuple. Any alpha nibble/byte is ignored — callers apply their own opacity.
1238
- * Shared with useColors.ts's applyOpacity() so hex parsing lives in one place.
1239
- */
1240
- declare function parseHexRgb(hex: string): [number, number, number] | null;
1241
-
1242
- declare function resolveSpacing(value: string, negative: boolean, spacing: ThemeConfig['spacing'], isArbitrary: boolean): string | number | null;
1243
- declare function resolveSizing(value: string, spacing: ThemeConfig['spacing'], isArbitrary: boolean): string | number | null;
1244
-
1245
- declare function resolveUtility(parsed: ParsedClass, theme: ThemeConfig): StyleValue | null;
1246
- /**
1247
- * Returns true if the utility name is known to the framework (built-in or plugin).
1248
- * Used for dev-mode warnings — resolveUtility returning null could mean either
1249
- * "intentionally null on this platform" or "completely unknown utility name".
1250
- * This check covers the second case.
1251
- */
1252
- declare function isKnownUtility(utility: string): boolean;
1253
- /**
1254
- * Sorted (longest-first) unique list of all built-in + plugin utility prefixes.
1255
- * Used by parser.ts for greedy prefix matching — replaces the hard-coded
1256
- * UTILITY_PREFIXES array that had to be kept in sync manually.
1257
- */
1258
- declare function getBuiltinUtilityPrefixes(): readonly string[];
1259
- /**
1260
- * Set of all built-in + plugin standalone utility names.
1261
- * Used by parser.ts to recognise no-value tokens — replaces the hard-coded
1262
- * STANDALONE_UTILITIES set that had to be kept in sync manually.
1263
- */
1264
- declare function getBuiltinStandaloneNames(): ReadonlySet<string>;
1265
-
1266
- declare function setDefaultFontFamily(font: string | undefined): void;
1267
- declare function getDefaultFontFamily(): string | undefined;
1268
- declare function disableRuntimeCSS(): void;
1269
- declare function isRuntimeCSSDisabled(): boolean;
1270
- declare function generateClassCSS(classString: string, theme: ThemeConfig, darkMode?: 'attribute' | 'class' | 'media', screens?: Record<string, number>): string;
1271
- /**
1272
- * Resolve a class string to a ResolvedStyle object.
1273
- *
1274
- * Results are cached per (theme, classString, darkMode) — repeated calls with
1275
- * the same arguments are O(1). Different theme objects each get their own
1276
- * cache so concurrent ThemeProviders with different configs are always correct.
1277
- */
1278
- declare function resolve(classString: string, theme: ThemeConfig, darkMode?: 'attribute' | 'class' | 'media'): ResolvedStyle;
1279
- /**
1280
- * Flatten a ResolvedStyle into a single StyleValue for the current runtime state.
1281
- * Used by useStyles() and styled().
1282
- *
1283
- * The sort step is memoized per resolved object reference (#6) — when resolve()
1284
- * returns a cached object, getSortedEntries() is O(1) on all subsequent calls.
1285
- */
1286
- declare function flatten(resolved: ResolvedStyle, isDark: boolean, state?: {
1287
- hover?: boolean;
1288
- focus?: boolean;
1289
- pressed?: boolean;
1290
- active?: boolean;
1291
- disabled?: boolean;
1292
- checked?: boolean;
1293
- visited?: boolean;
1294
- placeholder?: boolean;
1295
- }, breakpoints?: Set<string>): StyleValue;
1296
- /**
1297
- * Clear CSS injection state so stale rules are re-injected when the theme changes.
1298
- *
1299
- * The per-theme style cache (WeakMap) does not need to be cleared manually:
1300
- * updateConfig() creates a new theme object, making the old cache entry
1301
- * automatically unreachable for GC.
1302
- */
1303
- declare function clearCache(): void;
1304
-
1305
- /**
1306
- * Load, merge, and cache the resolved config.
1307
- * Call resetConfig() to force a reload (e.g. in tests or after live update).
1308
- */
1309
- declare function getConfig(): ResolvedConfig;
1310
- declare function resetConfig(): void;
1311
- declare function buildConfig(userConfig: FrameworkConfig): ResolvedConfig;
1312
- type ConfigListener = (config: ResolvedConfig) => void;
1313
- declare function onConfigChange(listener: ConfigListener): () => void;
1314
- declare function updateConfig(userConfig: FrameworkConfig): void;
1315
- /**
1316
- * Like updateConfig, but only calls it when the config object reference has
1317
- * actually changed. Used by the Babel-injected IIFE so that:
1318
- * - multiple files with kbach classes don't re-run the update on every load
1319
- * - Fast Refresh DOES re-run when kbach.config.js changes (new module → new object)
1320
- */
1321
- declare function initConfig(userConfig: FrameworkConfig): void;
1322
-
1323
- /**
1324
- * Module-level dark-mode singleton.
1325
- *
1326
- * This intentionally lives outside React so the custom JSX runtime can read it
1327
- * synchronously during render without needing context. ThemeProvider writes to it;
1328
- * DarkWrapper / InteractiveWrapper subscribe via useSyncExternalStore.
1329
- *
1330
- * Backed by getGlobalSingleton() (globalThis-keyed), not a plain module-level
1331
- * variable — core/ being built as its own shared dist/core/ entry (see
1332
- * tsup.config.ts's CORE_EXTERNAL) only guarantees one instance across the CJS
1333
- * build (dist/index.js, dist/jsx-runtime.js, dist/jsx-dev-runtime.js). The
1334
- * separate ESM build (dist/index.mjs etc., required for Rollup/Vite — see
1335
- * context.tsx's ThemeContext comment) inlines its own copy, and Metro can
1336
- * route different call sites in the same app through either one. Confirmed
1337
- * as a real bug this way: dark:/light: classes went completely inert (while
1338
- * useIsDark() kept reading correctly) in an app mixing
1339
- * `import ... from '@kbach/ui/native'` and `import ... from '@kbach/ui'`
1340
- * — the two ended up on different physical copies of this store.
1341
- */
1342
- /**
1343
- * Silently update isDark without notifying subscribers.
1344
- * Safe to call during React's render phase — no state side-effects.
1345
- * ThemeProvider calls this before returning JSX so the JSX runtime and
1346
- * children that call getGlobalDarkMode() during the same render pass
1347
- * already see the correct value.
1348
- */
1349
- declare function syncGlobalDarkMode(isDark: boolean): void;
1350
- /**
1351
- * Update isDark and notify all subscribers.
1352
- * Called by ThemeProvider in a layout effect (after commit) so DarkWrapper /
1353
- * InteractiveWrapper consumers re-render with the updated dark-mode value.
1354
- * Notifications are skipped when the value hasn't changed since the last
1355
- * broadcast to avoid spurious re-renders — see the notifiedIsDark comment
1356
- * above for why that comparison can't use `isDark` itself.
1357
- */
1358
- declare function setGlobalDarkMode(isDark: boolean): void;
1359
- /** Read current dark-mode state synchronously (safe in render, no hook needed). */
1360
- declare function getGlobalDarkMode(): boolean;
1361
- /**
1362
- * Subscribe to dark-mode changes.
1363
- * @returns Cleanup function — call it to unsubscribe (no leak).
1364
- */
1365
- declare function subscribeGlobalDarkMode(callback: () => void): () => void;
1366
-
1367
- /**
1368
- * Global responsive width store.
1369
- *
1370
- * Backed by getGlobalSingleton() (globalThis-keyed) — see
1371
- * darkModeStore.ts's header comment for why a plain module-level object
1372
- * isn't enough: core/ being its own shared dist/core/ entry only covers the
1373
- * CJS build (dist/index.js, dist/jsx-runtime.js, dist/jsx-dev-runtime.js);
1374
- * the separate ESM build inlines its own copy, and Metro can route
1375
- * different call sites in the same app through either one.
1376
- */
1377
- type WidthListener = () => void;
1378
- /** Synchronous write for use in the render phase. */
1379
- declare function syncGlobalWidth(width: number): void;
1380
- /** Update the breakpoint-name → min-width map from the resolved theme config. */
1381
- declare function syncGlobalScreens(screens: Record<string, number>): void;
1382
- declare function getGlobalScreens(): Record<string, number>;
1383
- /**
1384
- * Async write — fires listeners so subscribers re-render. Skip check uses
1385
- * notifiedWidth, not width — see the ResponsiveStore.notifiedWidth comment.
1386
- */
1387
- declare function setGlobalWidth(width: number): void;
1388
- declare function getGlobalWidth(): number;
1389
- declare function subscribeGlobalWidth(listener: WidthListener): () => void;
1390
- /**
1391
- * Returns the Set of breakpoint names that are currently active
1392
- * (i.e. width >= their min-width threshold).
1393
- *
1394
- * `screens` defaults to the global store's screens map (the common case —
1395
- * DarkWrapper/InteractiveWrapper have no per-tree config available). Pass an
1396
- * explicit map to check against a LOCAL config instead — e.g. useBreakpoint()/
1397
- * useResponsive() pass the nearest <ThemeProvider>'s own `config.theme.screens`
1398
- * so they stay correct per-provider rather than silently reading whichever
1399
- * config the global store happens to hold (see ThemeProvider's per-tree
1400
- * config-override limitation).
1401
- */
1402
- declare function getActiveBreakpoints(width?: number, screens?: Record<string, number>): Set<string>;
1403
-
1404
- 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, getGlobalSingleton, 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 };