@kbach/react 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -73
- package/dist/{chunk-NWW57Q5Q.mjs → chunk-EU7RK3K4.mjs} +1 -1
- package/dist/{chunk-GRZ6MVIL.mjs → chunk-SVPKCLOI.mjs} +74 -19
- package/dist/index.js +74 -19
- package/dist/index.mjs +1 -1
- package/dist/jsx-dev-runtime.js +74 -19
- package/dist/jsx-dev-runtime.mjs +2 -2
- package/dist/jsx-runtime.js +74 -19
- package/dist/jsx-runtime.mjs +2 -2
- package/dist/vite-plugin.js +80 -19
- package/dist/vite-plugin.mjs +80 -19
- package/kbach-react.md +20 -6
- package/package.json +1 -1
package/dist/vite-plugin.mjs
CHANGED
|
@@ -403,7 +403,10 @@ var defaultTheme = {
|
|
|
403
403
|
"2/3": "66.666667%",
|
|
404
404
|
"1/4": "25%",
|
|
405
405
|
"3/4": "75%",
|
|
406
|
-
screen
|
|
406
|
+
// Dynamic viewport unit — see the comment on the 'screen' standalone utilities
|
|
407
|
+
// in utilities.ts for why dvh beats vh on mobile. Used by h-screen (w-screen
|
|
408
|
+
// has its own standalone entry so it never reaches this spacing lookup).
|
|
409
|
+
screen: "100dvh",
|
|
407
410
|
min: "min-content",
|
|
408
411
|
max: "max-content",
|
|
409
412
|
fit: "fit-content"
|
|
@@ -714,15 +717,19 @@ function buildStandalone() {
|
|
|
714
717
|
// Display
|
|
715
718
|
// React Native only supports display:'flex'|'none'. Setting 'flex' explicitly is
|
|
716
719
|
// a no-op normally, but is needed to re-show an element that was hidden via `hidden`.
|
|
717
|
-
// `grid`, `
|
|
720
|
+
// `grid`, `contents`, `flow-root` have no native equivalent and stay null there.
|
|
721
|
+
// The inline-* family (inline, inline-block, inline-flex, inline-grid) falls back
|
|
722
|
+
// to 'flex' on native instead — like plain `flex`, this is a no-op most of the
|
|
723
|
+
// time, but without it these utilities couldn't re-show a `hidden` element on
|
|
724
|
+
// native either (null → no style applied → still display:'none').
|
|
718
725
|
flex: { display: "flex" },
|
|
719
726
|
block: web ? { display: "block" } : null,
|
|
720
|
-
"inline-block":
|
|
721
|
-
inline: web ?
|
|
727
|
+
"inline-block": { display: web ? "inline-block" : "flex" },
|
|
728
|
+
inline: { display: web ? "inline" : "flex" },
|
|
722
729
|
grid: web ? { display: "grid" } : null,
|
|
723
730
|
grd: web ? { display: "grid" } : null,
|
|
724
731
|
"inline-flex": { display: web ? "inline-flex" : "flex" },
|
|
725
|
-
"inline-grid":
|
|
732
|
+
"inline-grid": { display: web ? "inline-grid" : "flex" },
|
|
726
733
|
hidden: { display: "none" },
|
|
727
734
|
contents: web ? { display: "contents" } : null,
|
|
728
735
|
"flow-root": web ? { display: "flow-root" } : null,
|
|
@@ -981,12 +988,17 @@ function buildStandalone() {
|
|
|
981
988
|
"text-nowrap": web ? { textWrap: "nowrap" } : null,
|
|
982
989
|
"text-balance": web ? { textWrap: "balance" } : null,
|
|
983
990
|
"text-pretty": web ? { textWrap: "pretty" } : null,
|
|
984
|
-
// Screen sizing
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
991
|
+
// Screen sizing — dvw/dvh (dynamic viewport units) instead of vw/vh: on mobile
|
|
992
|
+
// browsers, vh/vw are pinned to the LARGEST viewport size (address bar hidden),
|
|
993
|
+
// so `h-screen` overflows behind the address bar when it's shown. dvh/dvw track
|
|
994
|
+
// the actual visible viewport as browser chrome shows/hides. Desktop behavior
|
|
995
|
+
// is unchanged since there's no dynamic chrome to account for.
|
|
996
|
+
// (vw/dvw values are web-only; vh/dvh values work cross-platform via spacing scale for h-*)
|
|
997
|
+
"w-screen": web ? { width: "100dvw" } : null,
|
|
998
|
+
"min-h-screen": { minHeight: "100dvh" },
|
|
999
|
+
"max-h-screen": { maxHeight: "100dvh" },
|
|
1000
|
+
"min-w-screen": web ? { minWidth: "100dvw" } : null,
|
|
1001
|
+
"max-w-screen": web ? { maxWidth: "100dvw" } : null,
|
|
990
1002
|
// max-w named container sizes (mirrors Tailwind's container scale)
|
|
991
1003
|
"max-w-none": { maxWidth: "none" },
|
|
992
1004
|
"max-w-xs": { maxWidth: 320 },
|
|
@@ -1893,6 +1905,33 @@ var RESOLVERS = {
|
|
|
1893
1905
|
const color = resolveColor(value, colors, isArbitrary);
|
|
1894
1906
|
return color ? { accentColor: color } : null;
|
|
1895
1907
|
},
|
|
1908
|
+
// ── SVG stroke/fill (web-only) ────────────────────────────────────────────
|
|
1909
|
+
// Native is intentionally excluded: react-native-svg's <Path>/<Circle>/etc.
|
|
1910
|
+
// take stroke/fill as component PROPS, not style entries, so there's no
|
|
1911
|
+
// reliable way to apply a resolved color through the `style` prop there.
|
|
1912
|
+
// `stroke-{n}` sets strokeWidth (a plain number, unlike a color) — same
|
|
1913
|
+
// color-first-then-numeric-fallback disambiguation `border` uses above.
|
|
1914
|
+
stroke: ({ value, isArbitrary }, { colors }) => {
|
|
1915
|
+
if (!getEffectiveIsWeb()) return null;
|
|
1916
|
+
if (!value) return null;
|
|
1917
|
+
if (value === "none") return { stroke: "none" };
|
|
1918
|
+
if (isArbitrary) {
|
|
1919
|
+
const w = toNativeValue(value);
|
|
1920
|
+
return typeof w === "number" ? { strokeWidth: w } : { stroke: value };
|
|
1921
|
+
}
|
|
1922
|
+
const color = resolveColor(value, colors, false);
|
|
1923
|
+
if (color) return { stroke: color };
|
|
1924
|
+
const n = parseFloat(value);
|
|
1925
|
+
return isNaN(n) ? null : { strokeWidth: n };
|
|
1926
|
+
},
|
|
1927
|
+
fill: ({ value, isArbitrary }, { colors }) => {
|
|
1928
|
+
if (!getEffectiveIsWeb()) return null;
|
|
1929
|
+
if (!value) return null;
|
|
1930
|
+
if (value === "none") return { fill: "none" };
|
|
1931
|
+
if (isArbitrary) return { fill: value };
|
|
1932
|
+
const color = resolveColor(value, colors, false);
|
|
1933
|
+
return color ? { fill: color } : null;
|
|
1934
|
+
},
|
|
1896
1935
|
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
1897
1936
|
flex: ({ value, isArbitrary }, { flex }) => {
|
|
1898
1937
|
if (!value) return { display: "flex" };
|
|
@@ -2112,34 +2151,50 @@ var RESOLVERS = {
|
|
|
2112
2151
|
const ms = isArbitrary ? value : `${value}ms`;
|
|
2113
2152
|
return { transitionDelay: ms };
|
|
2114
2153
|
},
|
|
2115
|
-
// ── Ring
|
|
2154
|
+
// ── Ring ───────────────────────────────────────────────────────────────────
|
|
2155
|
+
// Web: box-shadow outline ring (doesn't affect layout).
|
|
2156
|
+
// Native: React Native has no box-shadow, so this falls back to borderWidth/
|
|
2157
|
+
// borderColor — the closest visual approximation (used by other RN Tailwind-
|
|
2158
|
+
// likes for the same reason). Unlike the web ring, this DOES affect layout,
|
|
2159
|
+
// and it shares its properties with the `border` utility — combining
|
|
2160
|
+
// `border-*` and `ring-*` on the same native element means whichever class
|
|
2161
|
+
// comes later wins, since both ultimately set borderWidth/borderColor.
|
|
2116
2162
|
ring: ({ value, isArbitrary }, { colors }) => {
|
|
2117
|
-
|
|
2163
|
+
const onWeb = getEffectiveIsWeb();
|
|
2118
2164
|
const DEFAULT_COLOR = "rgba(59, 130, 246, 0.5)";
|
|
2119
2165
|
const DEFAULT_WIDTH = 3;
|
|
2166
|
+
const asNative = (w, color2) => w === 0 ? { borderWidth: 0 } : { borderWidth: w, borderColor: color2 };
|
|
2120
2167
|
if (!value) {
|
|
2121
|
-
return { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` };
|
|
2168
|
+
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
2122
2169
|
}
|
|
2123
2170
|
if (value === "inset") {
|
|
2124
|
-
return { boxShadow: `inset 0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` };
|
|
2171
|
+
return onWeb ? { boxShadow: `inset 0 0 0 ${DEFAULT_WIDTH}px ${DEFAULT_COLOR}` } : asNative(DEFAULT_WIDTH, DEFAULT_COLOR);
|
|
2125
2172
|
}
|
|
2126
2173
|
const widthTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
|
|
2127
2174
|
if (!isArbitrary && value in widthTokens) {
|
|
2128
2175
|
const w = widthTokens[value];
|
|
2129
|
-
return { boxShadow: w === 0 ? "none" : `0 0 0 ${w}px ${DEFAULT_COLOR}` };
|
|
2176
|
+
return onWeb ? { boxShadow: w === 0 ? "none" : `0 0 0 ${w}px ${DEFAULT_COLOR}` } : asNative(w, DEFAULT_COLOR);
|
|
2130
2177
|
}
|
|
2131
2178
|
if (isArbitrary) {
|
|
2132
2179
|
const numMatch = /^(\d+(?:\.\d+)?)(px|rem|em|vw|vh)?$/.exec(value);
|
|
2133
2180
|
if (numMatch) {
|
|
2134
2181
|
const unit = numMatch[2] ?? "px";
|
|
2135
|
-
return { boxShadow: `0 0 0 ${numMatch[1]}${unit} ${DEFAULT_COLOR}` };
|
|
2182
|
+
if (onWeb) return { boxShadow: `0 0 0 ${numMatch[1]}${unit} ${DEFAULT_COLOR}` };
|
|
2183
|
+
return unit === "px" ? asNative(parseFloat(numMatch[1]), DEFAULT_COLOR) : null;
|
|
2136
2184
|
}
|
|
2137
|
-
return { boxShadow: value.replace(/_/g, " ") };
|
|
2185
|
+
return onWeb ? { boxShadow: value.replace(/_/g, " ") } : null;
|
|
2138
2186
|
}
|
|
2139
2187
|
const color = resolveColor(value, colors, false);
|
|
2140
|
-
if (color)
|
|
2188
|
+
if (color) {
|
|
2189
|
+
return onWeb ? { boxShadow: `0 0 0 ${DEFAULT_WIDTH}px ${color}` } : asNative(DEFAULT_WIDTH, color);
|
|
2190
|
+
}
|
|
2141
2191
|
return null;
|
|
2142
2192
|
},
|
|
2193
|
+
// Web-only, unlike `ring` above: this stacks a second box-shadow layer to
|
|
2194
|
+
// create a gap between the element and the ring. There's no native
|
|
2195
|
+
// equivalent to approximate that with (a border can't create a gap outside
|
|
2196
|
+
// its own element without an extra wrapper view), so this stays a no-op
|
|
2197
|
+
// on native rather than rendering a misleading half-translation.
|
|
2143
2198
|
"ring-offset": ({ value, isArbitrary }, _theme) => {
|
|
2144
2199
|
if (!getEffectiveIsWeb()) return null;
|
|
2145
2200
|
const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
|
|
@@ -3162,6 +3217,12 @@ function kbach(userConfigOrOptions) {
|
|
|
3162
3217
|
enforce: "pre",
|
|
3163
3218
|
configResolved(resolved) {
|
|
3164
3219
|
root = resolved.root;
|
|
3220
|
+
const names = new Set(resolved.plugins.map((p) => p.name));
|
|
3221
|
+
if (names.has("react-router") && names.has("vite:react-refresh")) {
|
|
3222
|
+
console.warn(
|
|
3223
|
+
`[kbach] Detected both @vitejs/plugin-react and @react-router/dev's reactRouter() plugin active together. reactRouter() already includes its own JSX transform and Fast Refresh integration \u2014 having both crashes the page at runtime with "Identifier 'RefreshRuntime' has already been declared" before React hydrates, which looks like every class silently failing to style. Remove the react() plugin from vite.config.ts; jsxImportSource in tsconfig.json is enough on its own.`
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
3165
3226
|
},
|
|
3166
3227
|
// When any JS/TS file imports kbach.css, prepend a disableRuntimeCSS() call
|
|
3167
3228
|
// so styles come solely from the static stylesheet — no duplicate injection.
|
package/kbach-react.md
CHANGED
|
@@ -13,7 +13,7 @@ Package: `@kbach/react`
|
|
|
13
13
|
{ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "@kbach/react" } }
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
### vite.config.ts
|
|
16
|
+
### vite.config.ts (plain Vite only — skip @vitejs/plugin-react if a meta-framework already provides its own Vite/React plugin, e.g. React Router's reactRouter(); see below)
|
|
17
17
|
Requires `vite` and `@vitejs/plugin-react` as dev dependencies — not installed by `@kbach/react` itself: `npm install -D vite @vitejs/plugin-react`.
|
|
18
18
|
```ts
|
|
19
19
|
import { defineConfig } from 'vite';
|
|
@@ -50,7 +50,13 @@ import { ThemeProvider } from '@kbach/react';
|
|
|
50
50
|
tsconfig `jsxImportSource` setup above applies as-is. No Vite plugin for Next.js (webpack/Turbopack) — falls back to runtime CSS injection, which only runs client-side, so expect a brief flash of unstyled content on first paint before hydration. `@kbach/react`'s compiled output ships its own `"use client"` directive, so App Router Server Components can use `className`, `styled()`, hooks, and `<ThemeProvider>` directly, with no manual client wrapper needed.
|
|
51
51
|
|
|
52
52
|
### React Router
|
|
53
|
-
Framework mode (v7
|
|
53
|
+
Framework mode (v7+, SSR): do NOT add `@vitejs/plugin-react` — `@react-router/dev`'s `reactRouter()` Vite plugin already includes its own JSX transform + Fast Refresh integration. Adding both makes each inject its own Fast Refresh preamble into the same module, crashing the page (`Identifier 'RefreshRuntime' has already been declared`) before React hydrates — every class on the page silently fails to style because the app never mounts. tsconfig `jsxImportSource` alone is enough:
|
|
54
|
+
```ts
|
|
55
|
+
import { reactRouter } from '@react-router/dev/vite';
|
|
56
|
+
import { kbach } from '@kbach/react/vite'; // omit if not using static CSS
|
|
57
|
+
export default { plugins: [kbach(), reactRouter()] };
|
|
58
|
+
```
|
|
59
|
+
Default scan dirs include `app/`. Library mode (client-only, no meta-framework Vite plugin involved) needs no special handling beyond the standard Vite setup above.
|
|
54
60
|
|
|
55
61
|
---
|
|
56
62
|
|
|
@@ -428,7 +434,7 @@ mx-auto (centers element)
|
|
|
428
434
|
```
|
|
429
435
|
|
|
430
436
|
Spacing scale (1 unit = 4px):
|
|
431
|
-
`px(1) 0 0.5(2) 1(4) 1.5(6) 2(8) 2.5(10) 3(12) 3.5(14) 4(16) 5(20) 6(24) 7(28) 8(32) 9(36) 10(40) 11(44) 12(48) 14(56) 16(64) 20(80) 24(96) 28(112) 32(128) 36(144) 40(160) 44(176) 48(192) 52(208) 56(224) 60(240) 64(256) 72(288) 80(320) 96(384) auto full(100%) 1/2 1/3 2/3 1/4 3/4 screen(
|
|
437
|
+
`px(1) 0 0.5(2) 1(4) 1.5(6) 2(8) 2.5(10) 3(12) 3.5(14) 4(16) 5(20) 6(24) 7(28) 8(32) 9(36) 10(40) 11(44) 12(48) 14(56) 16(64) 20(80) 24(96) 28(112) 32(128) 36(144) 40(160) 44(176) 48(192) 52(208) 56(224) 60(240) 64(256) 72(288) 80(320) 96(384) auto full(100%) 1/2 1/3 2/3 1/4 3/4 screen(100dvh) min max fit`
|
|
432
438
|
|
|
433
439
|
### Sizing
|
|
434
440
|
```
|
|
@@ -437,7 +443,9 @@ w-{n} h-{n} size-{n} min-w-{n} min-h-{n} max-w-{n} max-h-{n}
|
|
|
437
443
|
Named max-w: none xs(320) sm(384) md(448) lg(512) xl(576) 2xl(672) 3xl(768)
|
|
438
444
|
4xl(896) 5xl(1024) 6xl(1152) 7xl(1280) prose(65ch)
|
|
439
445
|
|
|
440
|
-
Screen
|
|
446
|
+
Screen (dvw/dvh — correct on mobile where browser chrome resizes the
|
|
447
|
+
visible viewport; vw/vh are pinned to the largest viewport and overflow
|
|
448
|
+
behind a shown address bar): w-screen(100dvw) h-screen(100dvh)
|
|
441
449
|
min-w-screen max-w-screen min-h-screen max-h-screen
|
|
442
450
|
```
|
|
443
451
|
|
|
@@ -517,11 +525,15 @@ opacity-0/5/10/15/20/25/30/40/50/60/70/75/80/90/95/100
|
|
|
517
525
|
```
|
|
518
526
|
|
|
519
527
|
### Ring
|
|
528
|
+
Web: box-shadow ring. Native: approximated via borderWidth/borderColor
|
|
529
|
+
(no box-shadow on RN) — affects layout there and shares properties with
|
|
530
|
+
`border-*` (last class wins if both are used). `ring-offset-*`/`ring-inset`
|
|
531
|
+
stay web-only, with no native equivalent.
|
|
520
532
|
```
|
|
521
533
|
ring / ring-{n}(0 1 2 4 8)
|
|
522
534
|
ring-{color}
|
|
523
|
-
ring-inset
|
|
524
|
-
ring-offset-{n}(0 1 2 4 8)
|
|
535
|
+
ring-inset (web only)
|
|
536
|
+
ring-offset-{n}(0 1 2 4 8) (web only)
|
|
525
537
|
```
|
|
526
538
|
|
|
527
539
|
### Outline
|
|
@@ -624,6 +636,8 @@ aspect-auto / aspect-square / aspect-video / aspect-[4/3]
|
|
|
624
636
|
columns-{n} / columns-auto / columns-{size}
|
|
625
637
|
caret-{color} / caret-auto / caret-transparent
|
|
626
638
|
accent-{color} / accent-auto
|
|
639
|
+
stroke-{color} / stroke-{n} / stroke-none (web only, SVG)
|
|
640
|
+
fill-{color} / fill-none (web only, SVG)
|
|
627
641
|
mix-blend-{mode}
|
|
628
642
|
bg-blend-{mode}
|
|
629
643
|
will-change-auto/scroll/contents/transform
|