@kbach/react 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-6ZORO3BP.mjs → chunk-4A24NQ5X.mjs} +10 -11
- package/dist/{chunk-MPHPB357.mjs → chunk-ZZWJK33J.mjs} +565 -38
- package/dist/index.d.mts +131 -3
- package/dist/index.d.ts +131 -3
- package/dist/index.js +48 -19
- package/dist/index.mjs +15 -16
- package/dist/jsx-dev-runtime.js +48 -19
- package/dist/jsx-dev-runtime.mjs +3 -3
- package/dist/jsx-runtime.js +48 -19
- package/dist/jsx-runtime.mjs +3 -3
- package/dist/vite-plugin.d.mts +102 -1
- package/dist/vite-plugin.d.ts +102 -1
- package/dist/vite-plugin.js +47 -19
- package/dist/vite-plugin.mjs +2909 -11
- package/jsx-dev-runtime.js +1 -0
- package/jsx-runtime.js +1 -0
- package/kbach-react.md +11 -12
- package/package.json +3 -3
- package/dist/chunk-36QRQNPL.mjs +0 -528
- package/dist/types-BESBQANS.d.mts +0 -131
- package/dist/types-BESBQANS.d.ts +0 -131
package/dist/jsx-runtime.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
"use strict";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
@@ -401,7 +402,10 @@ var defaultTheme = {
|
|
|
401
402
|
"2/3": "66.666667%",
|
|
402
403
|
"1/4": "25%",
|
|
403
404
|
"3/4": "75%",
|
|
404
|
-
screen
|
|
405
|
+
// Dynamic viewport unit — see the comment on the 'screen' standalone utilities
|
|
406
|
+
// in utilities.ts for why dvh beats vh on mobile. Used by h-screen (w-screen
|
|
407
|
+
// has its own standalone entry so it never reaches this spacing lookup).
|
|
408
|
+
screen: "100dvh",
|
|
405
409
|
min: "min-content",
|
|
406
410
|
max: "max-content",
|
|
407
411
|
fit: "fit-content"
|
|
@@ -888,15 +892,19 @@ function buildStandalone() {
|
|
|
888
892
|
// Display
|
|
889
893
|
// React Native only supports display:'flex'|'none'. Setting 'flex' explicitly is
|
|
890
894
|
// a no-op normally, but is needed to re-show an element that was hidden via `hidden`.
|
|
891
|
-
// `grid`, `
|
|
895
|
+
// `grid`, `contents`, `flow-root` have no native equivalent and stay null there.
|
|
896
|
+
// The inline-* family (inline, inline-block, inline-flex, inline-grid) falls back
|
|
897
|
+
// to 'flex' on native instead — like plain `flex`, this is a no-op most of the
|
|
898
|
+
// time, but without it these utilities couldn't re-show a `hidden` element on
|
|
899
|
+
// native either (null → no style applied → still display:'none').
|
|
892
900
|
flex: { display: "flex" },
|
|
893
901
|
block: web ? { display: "block" } : null,
|
|
894
|
-
"inline-block":
|
|
895
|
-
inline: web ?
|
|
902
|
+
"inline-block": { display: web ? "inline-block" : "flex" },
|
|
903
|
+
inline: { display: web ? "inline" : "flex" },
|
|
896
904
|
grid: web ? { display: "grid" } : null,
|
|
897
905
|
grd: web ? { display: "grid" } : null,
|
|
898
906
|
"inline-flex": { display: web ? "inline-flex" : "flex" },
|
|
899
|
-
"inline-grid":
|
|
907
|
+
"inline-grid": { display: web ? "inline-grid" : "flex" },
|
|
900
908
|
hidden: { display: "none" },
|
|
901
909
|
contents: web ? { display: "contents" } : null,
|
|
902
910
|
"flow-root": web ? { display: "flow-root" } : null,
|
|
@@ -1155,12 +1163,17 @@ function buildStandalone() {
|
|
|
1155
1163
|
"text-nowrap": web ? { textWrap: "nowrap" } : null,
|
|
1156
1164
|
"text-balance": web ? { textWrap: "balance" } : null,
|
|
1157
1165
|
"text-pretty": web ? { textWrap: "pretty" } : null,
|
|
1158
|
-
// Screen sizing
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1166
|
+
// Screen sizing — dvw/dvh (dynamic viewport units) instead of vw/vh: on mobile
|
|
1167
|
+
// browsers, vh/vw are pinned to the LARGEST viewport size (address bar hidden),
|
|
1168
|
+
// so `h-screen` overflows behind the address bar when it's shown. dvh/dvw track
|
|
1169
|
+
// the actual visible viewport as browser chrome shows/hides. Desktop behavior
|
|
1170
|
+
// is unchanged since there's no dynamic chrome to account for.
|
|
1171
|
+
// (vw/dvw values are web-only; vh/dvh values work cross-platform via spacing scale for h-*)
|
|
1172
|
+
"w-screen": web ? { width: "100dvw" } : null,
|
|
1173
|
+
"min-h-screen": { minHeight: "100dvh" },
|
|
1174
|
+
"max-h-screen": { maxHeight: "100dvh" },
|
|
1175
|
+
"min-w-screen": web ? { minWidth: "100dvw" } : null,
|
|
1176
|
+
"max-w-screen": web ? { maxWidth: "100dvw" } : null,
|
|
1164
1177
|
// max-w named container sizes (mirrors Tailwind's container scale)
|
|
1165
1178
|
"max-w-none": { maxWidth: "none" },
|
|
1166
1179
|
"max-w-xs": { maxWidth: 320 },
|
|
@@ -2286,34 +2299,50 @@ var RESOLVERS = {
|
|
|
2286
2299
|
const ms = isArbitrary ? value : `${value}ms`;
|
|
2287
2300
|
return { transitionDelay: ms };
|
|
2288
2301
|
},
|
|
2289
|
-
// ── Ring
|
|
2302
|
+
// ── Ring ───────────────────────────────────────────────────────────────────
|
|
2303
|
+
// Web: box-shadow outline ring (doesn't affect layout).
|
|
2304
|
+
// Native: React Native has no box-shadow, so this falls back to borderWidth/
|
|
2305
|
+
// borderColor — the closest visual approximation (used by other RN Tailwind-
|
|
2306
|
+
// likes for the same reason). Unlike the web ring, this DOES affect layout,
|
|
2307
|
+
// and it shares its properties with the `border` utility — combining
|
|
2308
|
+
// `border-*` and `ring-*` on the same native element means whichever class
|
|
2309
|
+
// comes later wins, since both ultimately set borderWidth/borderColor.
|
|
2290
2310
|
ring: ({ value, isArbitrary }, { colors }) => {
|
|
2291
|
-
|
|
2311
|
+
const onWeb = getEffectiveIsWeb();
|
|
2292
2312
|
const DEFAULT_COLOR = "rgba(59, 130, 246, 0.5)";
|
|
2293
2313
|
const DEFAULT_WIDTH = 3;
|
|
2314
|
+
const asNative = (w, color2) => w === 0 ? { borderWidth: 0 } : { borderWidth: w, borderColor: color2 };
|
|
2294
2315
|
if (!value) {
|
|
2295
|
-
return { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` };
|
|
2316
|
+
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
2296
2317
|
}
|
|
2297
2318
|
if (value === "inset") {
|
|
2298
|
-
return { boxShadow: `inset 0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` };
|
|
2319
|
+
return onWeb ? { boxShadow: `inset 0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
2299
2320
|
}
|
|
2300
2321
|
const widthTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
|
|
2301
2322
|
if (!isArbitrary && value in widthTokens) {
|
|
2302
2323
|
const w = widthTokens[value];
|
|
2303
|
-
return { boxShadow: w === 0 ? "none" : `0 0 0 ${w}px ${DEFAULT_COLOR}` };
|
|
2324
|
+
return onWeb ? { boxShadow: w === 0 ? "none" : `0 0 0 ${w}px ${DEFAULT_COLOR}` } : asNative(w, DEFAULT_COLOR);
|
|
2304
2325
|
}
|
|
2305
2326
|
if (isArbitrary) {
|
|
2306
2327
|
const numMatch = /^(\d+(?:\.\d+)?)(px|rem|em|vw|vh)?$/.exec(value);
|
|
2307
2328
|
if (numMatch) {
|
|
2308
2329
|
const unit = numMatch[2] ?? "px";
|
|
2309
|
-
return { boxShadow: `0 0 0 ${numMatch[1]}${unit} ${DEFAULT_COLOR}` };
|
|
2330
|
+
if (onWeb) return { boxShadow: `0 0 0 ${numMatch[1]}${unit} ${DEFAULT_COLOR}` };
|
|
2331
|
+
return unit === "px" ? asNative(parseFloat(numMatch[1]), DEFAULT_COLOR) : null;
|
|
2310
2332
|
}
|
|
2311
|
-
return { boxShadow: value.replace(/_/g, " ") };
|
|
2333
|
+
return onWeb ? { boxShadow: value.replace(/_/g, " ") } : null;
|
|
2312
2334
|
}
|
|
2313
2335
|
const color = resolveColor(value, colors, false);
|
|
2314
|
-
if (color)
|
|
2336
|
+
if (color) {
|
|
2337
|
+
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${color}` } : asNative(DEFAULT_WIDTH, color);
|
|
2338
|
+
}
|
|
2315
2339
|
return null;
|
|
2316
2340
|
},
|
|
2341
|
+
// Web-only, unlike `ring` above: this stacks a second box-shadow layer to
|
|
2342
|
+
// create a gap between the element and the ring. There's no native
|
|
2343
|
+
// equivalent to approximate that with (a border can't create a gap outside
|
|
2344
|
+
// its own element without an extra wrapper view), so this stays a no-op
|
|
2345
|
+
// on native rather than rendering a misleading half-translation.
|
|
2317
2346
|
"ring-offset": ({ value, isArbitrary }, _theme) => {
|
|
2318
2347
|
if (!getEffectiveIsWeb()) return null;
|
|
2319
2348
|
const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
|
package/dist/jsx-runtime.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import {
|
|
2
3
|
Fragment,
|
|
3
4
|
_invalidateDefaultFontCache,
|
|
4
5
|
jsx,
|
|
5
6
|
jsxs
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4A24NQ5X.mjs";
|
|
7
8
|
import {
|
|
8
9
|
registerWebElement
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-MPHPB357.mjs";
|
|
10
|
+
} from "./chunk-ZZWJK33J.mjs";
|
|
11
11
|
export {
|
|
12
12
|
Fragment,
|
|
13
13
|
_invalidateDefaultFontCache,
|
package/dist/vite-plugin.d.mts
CHANGED
|
@@ -1,5 +1,106 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Unified modifier registry — single source of truth for ALL modifier behavior.
|
|
5
|
+
*
|
|
6
|
+
* Adding a new modifier requires editing ONLY this file:
|
|
7
|
+
* 1. Add an entry to BUILTIN_MODIFIERS with its CSS and JS behavior.
|
|
8
|
+
* 2. Done — parser, resolver, CSS generator, and JSX runtime all derive
|
|
9
|
+
* their behavior from this data automatically.
|
|
10
|
+
*
|
|
11
|
+
* Plugin authors can register custom modifiers via registerModifier().
|
|
12
|
+
*/
|
|
13
|
+
interface ModifierDef {
|
|
14
|
+
/** CSS pseudo-class or pseudo-element appended to the selector (e.g. ':hover', '::before') */
|
|
15
|
+
pseudo?: string;
|
|
16
|
+
/** Ancestor selector prefix INCLUDING trailing space (e.g. '.group:hover ', '.peer:focus ~ ') */
|
|
17
|
+
ancestorSelector?: string;
|
|
18
|
+
/** Directionality attribute selector prefix INCLUDING trailing space (e.g. '[dir="rtl"] ') */
|
|
19
|
+
dirSelector?: string;
|
|
20
|
+
/** @media query body WITHOUT the '@media ' prefix (e.g. 'print', '(orientation: landscape)') */
|
|
21
|
+
mediaQuery?: string;
|
|
22
|
+
/** Dark/light mode scheme — triggers the configured darkMode strategy in CSS output */
|
|
23
|
+
darkScheme?: 'dark' | 'light';
|
|
24
|
+
/** True for responsive modifiers — wraps in @media (min-width: theme.screens[name]) */
|
|
25
|
+
isResponsive?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Forces !important on all declarations in the generated CSS rule.
|
|
28
|
+
* Applied automatically for structural / ancestor / media modifiers that must
|
|
29
|
+
* win over base inline styles.
|
|
30
|
+
*/
|
|
31
|
+
forcesImportant?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* How the JSX runtime routes this modifier:
|
|
34
|
+
* 'interactive' — managed by InteractiveWrapper (hover, focus, pressed, …)
|
|
35
|
+
* 'mode' — managed by DarkWrapper (dark, light, not-dark, …)
|
|
36
|
+
* 'responsive' — managed by DarkWrapper (sm, md, lg, xl, 2xl)
|
|
37
|
+
* 'css-only' — CSS injection only; matchModifier always returns false
|
|
38
|
+
*/
|
|
39
|
+
jsBehavior: 'interactive' | 'mode' | 'responsive' | 'css-only';
|
|
40
|
+
/**
|
|
41
|
+
* Evaluates whether this modifier's condition is met at runtime.
|
|
42
|
+
* Omit for 'css-only' modifiers — they never apply as inline styles.
|
|
43
|
+
*/
|
|
44
|
+
jsMatch?: (isDark: boolean, state: Record<string, boolean | undefined>, breakpoints: Set<string>) => boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface StyleValue {
|
|
48
|
+
[key: string]: string | number | undefined | null | StyleValue | StyleValue[];
|
|
49
|
+
}
|
|
50
|
+
type ColorShades = Record<string, string>;
|
|
51
|
+
type ThemeColors = Record<string, string | ColorShades>;
|
|
52
|
+
type ThemeSpacing = Record<string, number | string>;
|
|
53
|
+
interface ThemeConfig {
|
|
54
|
+
colors: ThemeColors;
|
|
55
|
+
spacing: ThemeSpacing;
|
|
56
|
+
fontSize: Record<string, number | string>;
|
|
57
|
+
fontFamily: Record<string, string | string[]>;
|
|
58
|
+
fontWeight: Record<string, string | number>;
|
|
59
|
+
borderRadius: Record<string, number | string>;
|
|
60
|
+
borderWidth: Record<string, number>;
|
|
61
|
+
opacity: Record<string, number>;
|
|
62
|
+
lineHeight: Record<string, number | string>;
|
|
63
|
+
letterSpacing: Record<string, number | string>;
|
|
64
|
+
zIndex: Record<string, number | string>;
|
|
65
|
+
flex: Record<string, number | string>;
|
|
66
|
+
shadow: Record<string, StyleValue>;
|
|
67
|
+
screens: Record<string, string | number>;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 'class' — toggles .dark class on <html>
|
|
72
|
+
* 'media' — uses prefers-color-scheme media query
|
|
73
|
+
* 'attribute' — uses data-theme="dark" attribute on <html>
|
|
74
|
+
*/
|
|
75
|
+
type DarkMode = 'attribute' | 'class' | 'media';
|
|
76
|
+
interface PluginAPI {
|
|
77
|
+
addUtility(name: string, styles: StyleValue): void;
|
|
78
|
+
/**
|
|
79
|
+
* Register a custom variant.
|
|
80
|
+
*
|
|
81
|
+
* Pass a CSS selector string for simple cases — it is automatically
|
|
82
|
+
* converted into a ModifierDef that generates correct CSS rules:
|
|
83
|
+
* addVariant('hocus', ':hover, :focus') // pseudo
|
|
84
|
+
* addVariant('supports-grid', '@media (display: grid)') // media
|
|
85
|
+
* addVariant('dark-green', '.dark-green') // ancestor selector
|
|
86
|
+
*
|
|
87
|
+
* Pass a full ModifierDef object for advanced control (e.g. JS-trackable
|
|
88
|
+
* interactive variants with custom jsMatch logic).
|
|
89
|
+
*/
|
|
90
|
+
addVariant(name: string, selectorOrDef: string | ModifierDef): void;
|
|
91
|
+
theme(path: string, defaultValue?: unknown): unknown;
|
|
92
|
+
e(className: string): string;
|
|
93
|
+
}
|
|
94
|
+
interface FrameworkConfig {
|
|
95
|
+
darkMode?: DarkMode;
|
|
96
|
+
theme?: Partial<ThemeConfig>;
|
|
97
|
+
/** Additive theme extension — accepts either `extend.theme.X` or `extend.X` directly. */
|
|
98
|
+
extend?: {
|
|
99
|
+
theme?: Partial<ThemeConfig>;
|
|
100
|
+
} & Partial<ThemeConfig>;
|
|
101
|
+
plugins?: Array<(api: PluginAPI) => void>;
|
|
102
|
+
content?: string[];
|
|
103
|
+
}
|
|
3
104
|
|
|
4
105
|
interface KbachPluginOptions {
|
|
5
106
|
framework?: FrameworkConfig;
|
package/dist/vite-plugin.d.ts
CHANGED
|
@@ -1,5 +1,106 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Unified modifier registry — single source of truth for ALL modifier behavior.
|
|
5
|
+
*
|
|
6
|
+
* Adding a new modifier requires editing ONLY this file:
|
|
7
|
+
* 1. Add an entry to BUILTIN_MODIFIERS with its CSS and JS behavior.
|
|
8
|
+
* 2. Done — parser, resolver, CSS generator, and JSX runtime all derive
|
|
9
|
+
* their behavior from this data automatically.
|
|
10
|
+
*
|
|
11
|
+
* Plugin authors can register custom modifiers via registerModifier().
|
|
12
|
+
*/
|
|
13
|
+
interface ModifierDef {
|
|
14
|
+
/** CSS pseudo-class or pseudo-element appended to the selector (e.g. ':hover', '::before') */
|
|
15
|
+
pseudo?: string;
|
|
16
|
+
/** Ancestor selector prefix INCLUDING trailing space (e.g. '.group:hover ', '.peer:focus ~ ') */
|
|
17
|
+
ancestorSelector?: string;
|
|
18
|
+
/** Directionality attribute selector prefix INCLUDING trailing space (e.g. '[dir="rtl"] ') */
|
|
19
|
+
dirSelector?: string;
|
|
20
|
+
/** @media query body WITHOUT the '@media ' prefix (e.g. 'print', '(orientation: landscape)') */
|
|
21
|
+
mediaQuery?: string;
|
|
22
|
+
/** Dark/light mode scheme — triggers the configured darkMode strategy in CSS output */
|
|
23
|
+
darkScheme?: 'dark' | 'light';
|
|
24
|
+
/** True for responsive modifiers — wraps in @media (min-width: theme.screens[name]) */
|
|
25
|
+
isResponsive?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Forces !important on all declarations in the generated CSS rule.
|
|
28
|
+
* Applied automatically for structural / ancestor / media modifiers that must
|
|
29
|
+
* win over base inline styles.
|
|
30
|
+
*/
|
|
31
|
+
forcesImportant?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* How the JSX runtime routes this modifier:
|
|
34
|
+
* 'interactive' — managed by InteractiveWrapper (hover, focus, pressed, …)
|
|
35
|
+
* 'mode' — managed by DarkWrapper (dark, light, not-dark, …)
|
|
36
|
+
* 'responsive' — managed by DarkWrapper (sm, md, lg, xl, 2xl)
|
|
37
|
+
* 'css-only' — CSS injection only; matchModifier always returns false
|
|
38
|
+
*/
|
|
39
|
+
jsBehavior: 'interactive' | 'mode' | 'responsive' | 'css-only';
|
|
40
|
+
/**
|
|
41
|
+
* Evaluates whether this modifier's condition is met at runtime.
|
|
42
|
+
* Omit for 'css-only' modifiers — they never apply as inline styles.
|
|
43
|
+
*/
|
|
44
|
+
jsMatch?: (isDark: boolean, state: Record<string, boolean | undefined>, breakpoints: Set<string>) => boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface StyleValue {
|
|
48
|
+
[key: string]: string | number | undefined | null | StyleValue | StyleValue[];
|
|
49
|
+
}
|
|
50
|
+
type ColorShades = Record<string, string>;
|
|
51
|
+
type ThemeColors = Record<string, string | ColorShades>;
|
|
52
|
+
type ThemeSpacing = Record<string, number | string>;
|
|
53
|
+
interface ThemeConfig {
|
|
54
|
+
colors: ThemeColors;
|
|
55
|
+
spacing: ThemeSpacing;
|
|
56
|
+
fontSize: Record<string, number | string>;
|
|
57
|
+
fontFamily: Record<string, string | string[]>;
|
|
58
|
+
fontWeight: Record<string, string | number>;
|
|
59
|
+
borderRadius: Record<string, number | string>;
|
|
60
|
+
borderWidth: Record<string, number>;
|
|
61
|
+
opacity: Record<string, number>;
|
|
62
|
+
lineHeight: Record<string, number | string>;
|
|
63
|
+
letterSpacing: Record<string, number | string>;
|
|
64
|
+
zIndex: Record<string, number | string>;
|
|
65
|
+
flex: Record<string, number | string>;
|
|
66
|
+
shadow: Record<string, StyleValue>;
|
|
67
|
+
screens: Record<string, string | number>;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 'class' — toggles .dark class on <html>
|
|
72
|
+
* 'media' — uses prefers-color-scheme media query
|
|
73
|
+
* 'attribute' — uses data-theme="dark" attribute on <html>
|
|
74
|
+
*/
|
|
75
|
+
type DarkMode = 'attribute' | 'class' | 'media';
|
|
76
|
+
interface PluginAPI {
|
|
77
|
+
addUtility(name: string, styles: StyleValue): void;
|
|
78
|
+
/**
|
|
79
|
+
* Register a custom variant.
|
|
80
|
+
*
|
|
81
|
+
* Pass a CSS selector string for simple cases — it is automatically
|
|
82
|
+
* converted into a ModifierDef that generates correct CSS rules:
|
|
83
|
+
* addVariant('hocus', ':hover, :focus') // pseudo
|
|
84
|
+
* addVariant('supports-grid', '@media (display: grid)') // media
|
|
85
|
+
* addVariant('dark-green', '.dark-green') // ancestor selector
|
|
86
|
+
*
|
|
87
|
+
* Pass a full ModifierDef object for advanced control (e.g. JS-trackable
|
|
88
|
+
* interactive variants with custom jsMatch logic).
|
|
89
|
+
*/
|
|
90
|
+
addVariant(name: string, selectorOrDef: string | ModifierDef): void;
|
|
91
|
+
theme(path: string, defaultValue?: unknown): unknown;
|
|
92
|
+
e(className: string): string;
|
|
93
|
+
}
|
|
94
|
+
interface FrameworkConfig {
|
|
95
|
+
darkMode?: DarkMode;
|
|
96
|
+
theme?: Partial<ThemeConfig>;
|
|
97
|
+
/** Additive theme extension — accepts either `extend.theme.X` or `extend.X` directly. */
|
|
98
|
+
extend?: {
|
|
99
|
+
theme?: Partial<ThemeConfig>;
|
|
100
|
+
} & Partial<ThemeConfig>;
|
|
101
|
+
plugins?: Array<(api: PluginAPI) => void>;
|
|
102
|
+
content?: string[];
|
|
103
|
+
}
|
|
3
104
|
|
|
4
105
|
interface KbachPluginOptions {
|
|
5
106
|
framework?: FrameworkConfig;
|
package/dist/vite-plugin.js
CHANGED
|
@@ -437,7 +437,10 @@ var defaultTheme = {
|
|
|
437
437
|
"2/3": "66.666667%",
|
|
438
438
|
"1/4": "25%",
|
|
439
439
|
"3/4": "75%",
|
|
440
|
-
screen
|
|
440
|
+
// Dynamic viewport unit — see the comment on the 'screen' standalone utilities
|
|
441
|
+
// in utilities.ts for why dvh beats vh on mobile. Used by h-screen (w-screen
|
|
442
|
+
// has its own standalone entry so it never reaches this spacing lookup).
|
|
443
|
+
screen: "100dvh",
|
|
441
444
|
min: "min-content",
|
|
442
445
|
max: "max-content",
|
|
443
446
|
fit: "fit-content"
|
|
@@ -748,15 +751,19 @@ function buildStandalone() {
|
|
|
748
751
|
// Display
|
|
749
752
|
// React Native only supports display:'flex'|'none'. Setting 'flex' explicitly is
|
|
750
753
|
// a no-op normally, but is needed to re-show an element that was hidden via `hidden`.
|
|
751
|
-
// `grid`, `
|
|
754
|
+
// `grid`, `contents`, `flow-root` have no native equivalent and stay null there.
|
|
755
|
+
// The inline-* family (inline, inline-block, inline-flex, inline-grid) falls back
|
|
756
|
+
// to 'flex' on native instead — like plain `flex`, this is a no-op most of the
|
|
757
|
+
// time, but without it these utilities couldn't re-show a `hidden` element on
|
|
758
|
+
// native either (null → no style applied → still display:'none').
|
|
752
759
|
flex: { display: "flex" },
|
|
753
760
|
block: web ? { display: "block" } : null,
|
|
754
|
-
"inline-block":
|
|
755
|
-
inline: web ?
|
|
761
|
+
"inline-block": { display: web ? "inline-block" : "flex" },
|
|
762
|
+
inline: { display: web ? "inline" : "flex" },
|
|
756
763
|
grid: web ? { display: "grid" } : null,
|
|
757
764
|
grd: web ? { display: "grid" } : null,
|
|
758
765
|
"inline-flex": { display: web ? "inline-flex" : "flex" },
|
|
759
|
-
"inline-grid":
|
|
766
|
+
"inline-grid": { display: web ? "inline-grid" : "flex" },
|
|
760
767
|
hidden: { display: "none" },
|
|
761
768
|
contents: web ? { display: "contents" } : null,
|
|
762
769
|
"flow-root": web ? { display: "flow-root" } : null,
|
|
@@ -1015,12 +1022,17 @@ function buildStandalone() {
|
|
|
1015
1022
|
"text-nowrap": web ? { textWrap: "nowrap" } : null,
|
|
1016
1023
|
"text-balance": web ? { textWrap: "balance" } : null,
|
|
1017
1024
|
"text-pretty": web ? { textWrap: "pretty" } : null,
|
|
1018
|
-
// Screen sizing
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1025
|
+
// Screen sizing — dvw/dvh (dynamic viewport units) instead of vw/vh: on mobile
|
|
1026
|
+
// browsers, vh/vw are pinned to the LARGEST viewport size (address bar hidden),
|
|
1027
|
+
// so `h-screen` overflows behind the address bar when it's shown. dvh/dvw track
|
|
1028
|
+
// the actual visible viewport as browser chrome shows/hides. Desktop behavior
|
|
1029
|
+
// is unchanged since there's no dynamic chrome to account for.
|
|
1030
|
+
// (vw/dvw values are web-only; vh/dvh values work cross-platform via spacing scale for h-*)
|
|
1031
|
+
"w-screen": web ? { width: "100dvw" } : null,
|
|
1032
|
+
"min-h-screen": { minHeight: "100dvh" },
|
|
1033
|
+
"max-h-screen": { maxHeight: "100dvh" },
|
|
1034
|
+
"min-w-screen": web ? { minWidth: "100dvw" } : null,
|
|
1035
|
+
"max-w-screen": web ? { maxWidth: "100dvw" } : null,
|
|
1024
1036
|
// max-w named container sizes (mirrors Tailwind's container scale)
|
|
1025
1037
|
"max-w-none": { maxWidth: "none" },
|
|
1026
1038
|
"max-w-xs": { maxWidth: 320 },
|
|
@@ -2146,34 +2158,50 @@ var RESOLVERS = {
|
|
|
2146
2158
|
const ms = isArbitrary ? value : `${value}ms`;
|
|
2147
2159
|
return { transitionDelay: ms };
|
|
2148
2160
|
},
|
|
2149
|
-
// ── Ring
|
|
2161
|
+
// ── Ring ───────────────────────────────────────────────────────────────────
|
|
2162
|
+
// Web: box-shadow outline ring (doesn't affect layout).
|
|
2163
|
+
// Native: React Native has no box-shadow, so this falls back to borderWidth/
|
|
2164
|
+
// borderColor — the closest visual approximation (used by other RN Tailwind-
|
|
2165
|
+
// likes for the same reason). Unlike the web ring, this DOES affect layout,
|
|
2166
|
+
// and it shares its properties with the `border` utility — combining
|
|
2167
|
+
// `border-*` and `ring-*` on the same native element means whichever class
|
|
2168
|
+
// comes later wins, since both ultimately set borderWidth/borderColor.
|
|
2150
2169
|
ring: ({ value, isArbitrary }, { colors }) => {
|
|
2151
|
-
|
|
2170
|
+
const onWeb = getEffectiveIsWeb();
|
|
2152
2171
|
const DEFAULT_COLOR = "rgba(59, 130, 246, 0.5)";
|
|
2153
2172
|
const DEFAULT_WIDTH = 3;
|
|
2173
|
+
const asNative = (w, color2) => w === 0 ? { borderWidth: 0 } : { borderWidth: w, borderColor: color2 };
|
|
2154
2174
|
if (!value) {
|
|
2155
|
-
return { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` };
|
|
2175
|
+
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
2156
2176
|
}
|
|
2157
2177
|
if (value === "inset") {
|
|
2158
|
-
return { boxShadow: `inset 0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` };
|
|
2178
|
+
return onWeb ? { boxShadow: `inset 0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
2159
2179
|
}
|
|
2160
2180
|
const widthTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
|
|
2161
2181
|
if (!isArbitrary && value in widthTokens) {
|
|
2162
2182
|
const w = widthTokens[value];
|
|
2163
|
-
return { boxShadow: w === 0 ? "none" : `0 0 0 ${w}px ${DEFAULT_COLOR}` };
|
|
2183
|
+
return onWeb ? { boxShadow: w === 0 ? "none" : `0 0 0 ${w}px ${DEFAULT_COLOR}` } : asNative(w, DEFAULT_COLOR);
|
|
2164
2184
|
}
|
|
2165
2185
|
if (isArbitrary) {
|
|
2166
2186
|
const numMatch = /^(\d+(?:\.\d+)?)(px|rem|em|vw|vh)?$/.exec(value);
|
|
2167
2187
|
if (numMatch) {
|
|
2168
2188
|
const unit = numMatch[2] ?? "px";
|
|
2169
|
-
return { boxShadow: `0 0 0 ${numMatch[1]}${unit} ${DEFAULT_COLOR}` };
|
|
2189
|
+
if (onWeb) return { boxShadow: `0 0 0 ${numMatch[1]}${unit} ${DEFAULT_COLOR}` };
|
|
2190
|
+
return unit === "px" ? asNative(parseFloat(numMatch[1]), DEFAULT_COLOR) : null;
|
|
2170
2191
|
}
|
|
2171
|
-
return { boxShadow: value.replace(/_/g, " ") };
|
|
2192
|
+
return onWeb ? { boxShadow: value.replace(/_/g, " ") } : null;
|
|
2172
2193
|
}
|
|
2173
2194
|
const color = resolveColor(value, colors, false);
|
|
2174
|
-
if (color)
|
|
2195
|
+
if (color) {
|
|
2196
|
+
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${color}` } : asNative(DEFAULT_WIDTH, color);
|
|
2197
|
+
}
|
|
2175
2198
|
return null;
|
|
2176
2199
|
},
|
|
2200
|
+
// Web-only, unlike `ring` above: this stacks a second box-shadow layer to
|
|
2201
|
+
// create a gap between the element and the ring. There's no native
|
|
2202
|
+
// equivalent to approximate that with (a border can't create a gap outside
|
|
2203
|
+
// its own element without an extra wrapper view), so this stays a no-op
|
|
2204
|
+
// on native rather than rendering a misleading half-translation.
|
|
2177
2205
|
"ring-offset": ({ value, isArbitrary }, _theme) => {
|
|
2178
2206
|
if (!getEffectiveIsWeb()) return null;
|
|
2179
2207
|
const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
|