@kbach/react 0.6.3 → 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-4A24NQ5X.mjs → chunk-EU7RK3K4.mjs} +1 -1
- package/dist/{chunk-ZZWJK33J.mjs → chunk-SVPKCLOI.mjs} +27 -0
- package/dist/index.js +27 -0
- package/dist/index.mjs +1 -1
- package/dist/jsx-dev-runtime.js +27 -0
- package/dist/jsx-dev-runtime.mjs +2 -2
- package/dist/jsx-runtime.js +27 -0
- package/dist/jsx-runtime.mjs +2 -2
- package/dist/vite-plugin.js +33 -0
- package/dist/vite-plugin.mjs +33 -0
- package/kbach-react.md +10 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,9 +20,11 @@ npm install @kbach/react
|
|
|
20
20
|
|
|
21
21
|
## Setup
|
|
22
22
|
|
|
23
|
+
Two steps, and you're done — styles work immediately via runtime CSS injection, no build plugin required:
|
|
24
|
+
|
|
23
25
|
### 1. Configure the JSX runtime
|
|
24
26
|
|
|
25
|
-
**tsconfig.json**
|
|
27
|
+
**tsconfig.json** (works for Vite, Next.js, React Router, and most other tooling — it's the one setting that everything reads):
|
|
26
28
|
|
|
27
29
|
```json
|
|
28
30
|
{
|
|
@@ -33,121 +35,85 @@ npm install @kbach/react
|
|
|
33
35
|
}
|
|
34
36
|
```
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
Don't also pass `jsxImportSource` to `@vitejs/plugin-react` (or any other bundler plugin) unless you have a specific reason to — the tsconfig setting alone is enough, and pointing two different places at the JSX runtime is a common source of "it's not applying" confusion (or, worse, plugin conflicts — see the React Router note below).
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
/** @jsxImportSource @kbach/react */
|
|
40
|
-
```
|
|
40
|
+
Alternatives if you can't use tsconfig: a per-file `/** @jsxImportSource @kbach/react */` pragma comment, or `['@babel/preset-react', { runtime: 'automatic', importSource: '@kbach/react' }]` in `babel.config.js` for non-Vite/non-SWC toolchains.
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
### 2. Wrap your app
|
|
43
43
|
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
```jsx
|
|
45
|
+
import { ThemeProvider } from '@kbach/react';
|
|
46
|
+
|
|
47
|
+
export default function Root() {
|
|
48
|
+
return (
|
|
49
|
+
<ThemeProvider defaultMode="system">
|
|
50
|
+
<App />
|
|
51
|
+
</ThemeProvider>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
51
54
|
```
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
That's the whole setup. `@kbach/react` ships its own `"use client"` directive, so this works directly in a Next.js App Router Server Component tree too — no manual client wrapper needed.
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
### Optional: static CSS for production (Vite only)
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
npm install -D vite @vitejs/plugin-react
|
|
59
|
-
```
|
|
60
|
+
By default, styles are generated and injected into a `<style>` tag by client-side JS at runtime — simple, but it means server-rendered HTML has no matching CSS until hydration runs (a brief flash of unstyled content on first paint). If you're on a Vite-based project and want zero-runtime-cost CSS instead, add the `@kbach/react/vite` plugin:
|
|
60
61
|
|
|
61
62
|
```ts
|
|
62
63
|
// vite.config.ts
|
|
63
64
|
import { defineConfig } from 'vite';
|
|
64
|
-
import react from '@vitejs/plugin-react';
|
|
65
65
|
import { kbach } from '@kbach/react/vite';
|
|
66
66
|
|
|
67
67
|
export default defineConfig({
|
|
68
68
|
plugins: [
|
|
69
|
-
|
|
69
|
+
// ...your framework's own plugin(s) — see the framework notes below
|
|
70
|
+
// before adding @vitejs/plugin-react yourself.
|
|
70
71
|
kbach(),
|
|
71
72
|
],
|
|
72
73
|
});
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
### 3. Create and import kbach.css
|
|
78
|
-
|
|
79
|
-
Create `kbach.css` anywhere in your project (e.g. `src/kbach.css`):
|
|
76
|
+
Then create an empty `kbach.css` anywhere in your project and import it once in your app entry:
|
|
80
77
|
|
|
81
78
|
```css
|
|
79
|
+
/* src/kbach.css */
|
|
82
80
|
/* kbach:start */
|
|
83
81
|
/* kbach:end */
|
|
84
82
|
```
|
|
85
83
|
|
|
86
|
-
Import it in your app entry:
|
|
87
|
-
|
|
88
84
|
```ts
|
|
89
85
|
// main.tsx
|
|
90
86
|
import './kbach.css';
|
|
91
87
|
```
|
|
92
88
|
|
|
93
|
-
Importing `kbach.css` automatically disables runtime
|
|
94
|
-
|
|
95
|
-
### 4. Wrap your app
|
|
96
|
-
|
|
97
|
-
```jsx
|
|
98
|
-
import { ThemeProvider } from '@kbach/react';
|
|
99
|
-
|
|
100
|
-
export default function Root() {
|
|
101
|
-
return (
|
|
102
|
-
<ThemeProvider defaultMode="system">
|
|
103
|
-
<App />
|
|
104
|
-
</ThemeProvider>
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
```
|
|
89
|
+
The plugin scans your source files and writes generated CSS between the `/* kbach:start */`/`/* kbach:end */` markers. Importing `kbach.css` automatically disables runtime injection — all styles come from the file instead. On HMR, only the changed file is rescanned; unchanged tokens reuse cached CSS.
|
|
108
90
|
|
|
109
91
|
## Next.js
|
|
110
92
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Two things differ from the Vite setup:
|
|
93
|
+
Step 1 (tsconfig `jsxImportSource`) and step 2 (`ThemeProvider`) above apply as-is — Next.js's SWC compiler reads `jsxImportSource` from `tsconfig.json` the same way Vite does, and `@kbach/react` shipping its own `"use client"` directive means `ThemeProvider` works directly in a Server Component tree (e.g. the App Router root `layout.tsx`) with no wrapper of your own needed.
|
|
114
94
|
|
|
115
|
-
|
|
95
|
+
The "Optional: static CSS" step above doesn't apply — Next.js builds with webpack/Turbopack, not Vite, so there's currently no static-CSS build step for it. Styles fall back to runtime injection, which means the same first-paint FOUC note above applies: expect a brief flash of unstyled content before hydration completes. This is a known limitation, not a per-project bug to work around.
|
|
116
96
|
|
|
117
|
-
|
|
97
|
+
## React Router
|
|
118
98
|
|
|
119
|
-
|
|
120
|
-
// app/providers.tsx
|
|
121
|
-
'use client';
|
|
122
|
-
import { ThemeProvider } from '@kbach/react';
|
|
99
|
+
**Framework mode (v7+, SSR by default):** `@react-router/dev`'s own `reactRouter()` Vite plugin already includes its own React JSX transform and Fast Refresh integration — **do not also add `@vitejs/plugin-react`.** Having both active makes each one inject its own Fast Refresh preamble into the same module, which crashes the page at runtime (`Identifier 'RefreshRuntime' has already been declared`) before React ever hydrates — every class on the page will silently fail to style because the app never actually mounts. The correct setup is just:
|
|
123
100
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
```tsx
|
|
130
|
-
// app/layout.tsx (Server Component — no 'use client' needed here)
|
|
131
|
-
import { Providers } from './providers';
|
|
101
|
+
```ts
|
|
102
|
+
// vite.config.ts
|
|
103
|
+
import { reactRouter } from '@react-router/dev/vite';
|
|
104
|
+
import { defineConfig } from 'vite';
|
|
105
|
+
import { kbach } from '@kbach/react/vite'; // omit if you're not using static CSS
|
|
132
106
|
|
|
133
|
-
export default
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<body>
|
|
137
|
-
<Providers>{children}</Providers>
|
|
138
|
-
</body>
|
|
139
|
-
</html>
|
|
140
|
-
);
|
|
141
|
-
}
|
|
107
|
+
export default defineConfig({
|
|
108
|
+
plugins: [kbach(), reactRouter()],
|
|
109
|
+
});
|
|
142
110
|
```
|
|
143
111
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
## React Router
|
|
112
|
+
`jsxImportSource` in `tsconfig.json` (step 1 above) is all that's needed for the JSX runtime — React Router's Vite plugin reads it the same way plain Vite does. `include`'s default scan dirs (`['src', 'app', 'pages', 'components', 'views', 'layouts']`) already cover React Router's `app/` routes convention if you're using the static-CSS plugin.
|
|
147
113
|
|
|
148
|
-
|
|
114
|
+
If you do add `kbach()` to `vite.config.ts` and it detects both plugins active together, it prints a warning explaining exactly this at dev-server startup — so this doesn't have to be a silent, hard-to-diagnose blank page.
|
|
149
115
|
|
|
150
|
-
**Library mode (client-only, `createBrowserRouter`/`<BrowserRouter>`):** no SSR involved — set it up exactly like any other Vite + React app
|
|
116
|
+
**Library mode (client-only, `createBrowserRouter`/`<BrowserRouter>`):** no SSR involved — set it up exactly like any other Vite + React app. Since there's no meta-framework Vite plugin providing JSX handling here, you likely do need `@vitejs/plugin-react({ jsxImportSource: '@kbach/react' })` (or rely on tsconfig alone — Vite's default esbuild-based transform reads it too).
|
|
151
117
|
|
|
152
118
|
## API
|
|
153
119
|
|
|
@@ -2001,6 +2001,33 @@ var RESOLVERS = {
|
|
|
2001
2001
|
const color = resolveColor(value, colors, isArbitrary);
|
|
2002
2002
|
return color ? { accentColor: color } : null;
|
|
2003
2003
|
},
|
|
2004
|
+
// ── SVG stroke/fill (web-only) ────────────────────────────────────────────
|
|
2005
|
+
// Native is intentionally excluded: react-native-svg's <Path>/<Circle>/etc.
|
|
2006
|
+
// take stroke/fill as component PROPS, not style entries, so there's no
|
|
2007
|
+
// reliable way to apply a resolved color through the `style` prop there.
|
|
2008
|
+
// `stroke-{n}` sets strokeWidth (a plain number, unlike a color) — same
|
|
2009
|
+
// color-first-then-numeric-fallback disambiguation `border` uses above.
|
|
2010
|
+
stroke: ({ value, isArbitrary }, { colors }) => {
|
|
2011
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2012
|
+
if (!value) return null;
|
|
2013
|
+
if (value === "none") return { stroke: "none" };
|
|
2014
|
+
if (isArbitrary) {
|
|
2015
|
+
const w = toNativeValue(value);
|
|
2016
|
+
return typeof w === "number" ? { strokeWidth: w } : { stroke: value };
|
|
2017
|
+
}
|
|
2018
|
+
const color = resolveColor(value, colors, false);
|
|
2019
|
+
if (color) return { stroke: color };
|
|
2020
|
+
const n = parseFloat(value);
|
|
2021
|
+
return isNaN(n) ? null : { strokeWidth: n };
|
|
2022
|
+
},
|
|
2023
|
+
fill: ({ value, isArbitrary }, { colors }) => {
|
|
2024
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2025
|
+
if (!value) return null;
|
|
2026
|
+
if (value === "none") return { fill: "none" };
|
|
2027
|
+
if (isArbitrary) return { fill: value };
|
|
2028
|
+
const color = resolveColor(value, colors, false);
|
|
2029
|
+
return color ? { fill: color } : null;
|
|
2030
|
+
},
|
|
2004
2031
|
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
2005
2032
|
flex: ({ value, isArbitrary }, { flex }) => {
|
|
2006
2033
|
if (!value) return { display: "flex" };
|
package/dist/index.js
CHANGED
|
@@ -2120,6 +2120,33 @@ var RESOLVERS = {
|
|
|
2120
2120
|
const color = resolveColor(value, colors, isArbitrary);
|
|
2121
2121
|
return color ? { accentColor: color } : null;
|
|
2122
2122
|
},
|
|
2123
|
+
// ── SVG stroke/fill (web-only) ────────────────────────────────────────────
|
|
2124
|
+
// Native is intentionally excluded: react-native-svg's <Path>/<Circle>/etc.
|
|
2125
|
+
// take stroke/fill as component PROPS, not style entries, so there's no
|
|
2126
|
+
// reliable way to apply a resolved color through the `style` prop there.
|
|
2127
|
+
// `stroke-{n}` sets strokeWidth (a plain number, unlike a color) — same
|
|
2128
|
+
// color-first-then-numeric-fallback disambiguation `border` uses above.
|
|
2129
|
+
stroke: ({ value, isArbitrary }, { colors }) => {
|
|
2130
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2131
|
+
if (!value) return null;
|
|
2132
|
+
if (value === "none") return { stroke: "none" };
|
|
2133
|
+
if (isArbitrary) {
|
|
2134
|
+
const w = toNativeValue(value);
|
|
2135
|
+
return typeof w === "number" ? { strokeWidth: w } : { stroke: value };
|
|
2136
|
+
}
|
|
2137
|
+
const color = resolveColor(value, colors, false);
|
|
2138
|
+
if (color) return { stroke: color };
|
|
2139
|
+
const n = parseFloat(value);
|
|
2140
|
+
return isNaN(n) ? null : { strokeWidth: n };
|
|
2141
|
+
},
|
|
2142
|
+
fill: ({ value, isArbitrary }, { colors }) => {
|
|
2143
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2144
|
+
if (!value) return null;
|
|
2145
|
+
if (value === "none") return { fill: "none" };
|
|
2146
|
+
if (isArbitrary) return { fill: value };
|
|
2147
|
+
const color = resolveColor(value, colors, false);
|
|
2148
|
+
return color ? { fill: color } : null;
|
|
2149
|
+
},
|
|
2123
2150
|
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
2124
2151
|
flex: ({ value, isArbitrary }, { flex }) => {
|
|
2125
2152
|
if (!value) return { display: "flex" };
|
package/dist/index.mjs
CHANGED
package/dist/jsx-dev-runtime.js
CHANGED
|
@@ -2079,6 +2079,33 @@ var RESOLVERS = {
|
|
|
2079
2079
|
const color = resolveColor(value, colors, isArbitrary);
|
|
2080
2080
|
return color ? { accentColor: color } : null;
|
|
2081
2081
|
},
|
|
2082
|
+
// ── SVG stroke/fill (web-only) ────────────────────────────────────────────
|
|
2083
|
+
// Native is intentionally excluded: react-native-svg's <Path>/<Circle>/etc.
|
|
2084
|
+
// take stroke/fill as component PROPS, not style entries, so there's no
|
|
2085
|
+
// reliable way to apply a resolved color through the `style` prop there.
|
|
2086
|
+
// `stroke-{n}` sets strokeWidth (a plain number, unlike a color) — same
|
|
2087
|
+
// color-first-then-numeric-fallback disambiguation `border` uses above.
|
|
2088
|
+
stroke: ({ value, isArbitrary }, { colors }) => {
|
|
2089
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2090
|
+
if (!value) return null;
|
|
2091
|
+
if (value === "none") return { stroke: "none" };
|
|
2092
|
+
if (isArbitrary) {
|
|
2093
|
+
const w = toNativeValue(value);
|
|
2094
|
+
return typeof w === "number" ? { strokeWidth: w } : { stroke: value };
|
|
2095
|
+
}
|
|
2096
|
+
const color = resolveColor(value, colors, false);
|
|
2097
|
+
if (color) return { stroke: color };
|
|
2098
|
+
const n = parseFloat(value);
|
|
2099
|
+
return isNaN(n) ? null : { strokeWidth: n };
|
|
2100
|
+
},
|
|
2101
|
+
fill: ({ value, isArbitrary }, { colors }) => {
|
|
2102
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2103
|
+
if (!value) return null;
|
|
2104
|
+
if (value === "none") return { fill: "none" };
|
|
2105
|
+
if (isArbitrary) return { fill: value };
|
|
2106
|
+
const color = resolveColor(value, colors, false);
|
|
2107
|
+
return color ? { fill: color } : null;
|
|
2108
|
+
},
|
|
2082
2109
|
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
2083
2110
|
flex: ({ value, isArbitrary }, { flex }) => {
|
|
2084
2111
|
if (!value) return { display: "flex" };
|
package/dist/jsx-dev-runtime.mjs
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
Fragment,
|
|
4
4
|
jsx,
|
|
5
5
|
jsxs
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-EU7RK3K4.mjs";
|
|
7
|
+
import "./chunk-SVPKCLOI.mjs";
|
|
8
8
|
|
|
9
9
|
// src/jsx-dev-runtime.tsx
|
|
10
10
|
function jsxDEV(type, props, key, isStaticChildren, source, self) {
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -2080,6 +2080,33 @@ var RESOLVERS = {
|
|
|
2080
2080
|
const color = resolveColor(value, colors, isArbitrary);
|
|
2081
2081
|
return color ? { accentColor: color } : null;
|
|
2082
2082
|
},
|
|
2083
|
+
// ── SVG stroke/fill (web-only) ────────────────────────────────────────────
|
|
2084
|
+
// Native is intentionally excluded: react-native-svg's <Path>/<Circle>/etc.
|
|
2085
|
+
// take stroke/fill as component PROPS, not style entries, so there's no
|
|
2086
|
+
// reliable way to apply a resolved color through the `style` prop there.
|
|
2087
|
+
// `stroke-{n}` sets strokeWidth (a plain number, unlike a color) — same
|
|
2088
|
+
// color-first-then-numeric-fallback disambiguation `border` uses above.
|
|
2089
|
+
stroke: ({ value, isArbitrary }, { colors }) => {
|
|
2090
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2091
|
+
if (!value) return null;
|
|
2092
|
+
if (value === "none") return { stroke: "none" };
|
|
2093
|
+
if (isArbitrary) {
|
|
2094
|
+
const w = toNativeValue(value);
|
|
2095
|
+
return typeof w === "number" ? { strokeWidth: w } : { stroke: value };
|
|
2096
|
+
}
|
|
2097
|
+
const color = resolveColor(value, colors, false);
|
|
2098
|
+
if (color) return { stroke: color };
|
|
2099
|
+
const n = parseFloat(value);
|
|
2100
|
+
return isNaN(n) ? null : { strokeWidth: n };
|
|
2101
|
+
},
|
|
2102
|
+
fill: ({ value, isArbitrary }, { colors }) => {
|
|
2103
|
+
if (!getEffectiveIsWeb()) return null;
|
|
2104
|
+
if (!value) return null;
|
|
2105
|
+
if (value === "none") return { fill: "none" };
|
|
2106
|
+
if (isArbitrary) return { fill: value };
|
|
2107
|
+
const color = resolveColor(value, colors, false);
|
|
2108
|
+
return color ? { fill: color } : null;
|
|
2109
|
+
},
|
|
2083
2110
|
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
2084
2111
|
flex: ({ value, isArbitrary }, { flex }) => {
|
|
2085
2112
|
if (!value) return { display: "flex" };
|
package/dist/jsx-runtime.mjs
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
_invalidateDefaultFontCache,
|
|
5
5
|
jsx,
|
|
6
6
|
jsxs
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EU7RK3K4.mjs";
|
|
8
8
|
import {
|
|
9
9
|
registerWebElement
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SVPKCLOI.mjs";
|
|
11
11
|
export {
|
|
12
12
|
Fragment,
|
|
13
13
|
_invalidateDefaultFontCache,
|
package/dist/vite-plugin.js
CHANGED
|
@@ -1939,6 +1939,33 @@ var RESOLVERS = {
|
|
|
1939
1939
|
const color = resolveColor(value, colors, isArbitrary);
|
|
1940
1940
|
return color ? { accentColor: color } : null;
|
|
1941
1941
|
},
|
|
1942
|
+
// ── SVG stroke/fill (web-only) ────────────────────────────────────────────
|
|
1943
|
+
// Native is intentionally excluded: react-native-svg's <Path>/<Circle>/etc.
|
|
1944
|
+
// take stroke/fill as component PROPS, not style entries, so there's no
|
|
1945
|
+
// reliable way to apply a resolved color through the `style` prop there.
|
|
1946
|
+
// `stroke-{n}` sets strokeWidth (a plain number, unlike a color) — same
|
|
1947
|
+
// color-first-then-numeric-fallback disambiguation `border` uses above.
|
|
1948
|
+
stroke: ({ value, isArbitrary }, { colors }) => {
|
|
1949
|
+
if (!getEffectiveIsWeb()) return null;
|
|
1950
|
+
if (!value) return null;
|
|
1951
|
+
if (value === "none") return { stroke: "none" };
|
|
1952
|
+
if (isArbitrary) {
|
|
1953
|
+
const w = toNativeValue(value);
|
|
1954
|
+
return typeof w === "number" ? { strokeWidth: w } : { stroke: value };
|
|
1955
|
+
}
|
|
1956
|
+
const color = resolveColor(value, colors, false);
|
|
1957
|
+
if (color) return { stroke: color };
|
|
1958
|
+
const n = parseFloat(value);
|
|
1959
|
+
return isNaN(n) ? null : { strokeWidth: n };
|
|
1960
|
+
},
|
|
1961
|
+
fill: ({ value, isArbitrary }, { colors }) => {
|
|
1962
|
+
if (!getEffectiveIsWeb()) return null;
|
|
1963
|
+
if (!value) return null;
|
|
1964
|
+
if (value === "none") return { fill: "none" };
|
|
1965
|
+
if (isArbitrary) return { fill: value };
|
|
1966
|
+
const color = resolveColor(value, colors, false);
|
|
1967
|
+
return color ? { fill: color } : null;
|
|
1968
|
+
},
|
|
1942
1969
|
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
1943
1970
|
flex: ({ value, isArbitrary }, { flex }) => {
|
|
1944
1971
|
if (!value) return { display: "flex" };
|
|
@@ -3224,6 +3251,12 @@ function kbach(userConfigOrOptions) {
|
|
|
3224
3251
|
enforce: "pre",
|
|
3225
3252
|
configResolved(resolved) {
|
|
3226
3253
|
root = resolved.root;
|
|
3254
|
+
const names = new Set(resolved.plugins.map((p) => p.name));
|
|
3255
|
+
if (names.has("react-router") && names.has("vite:react-refresh")) {
|
|
3256
|
+
console.warn(
|
|
3257
|
+
`[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.`
|
|
3258
|
+
);
|
|
3259
|
+
}
|
|
3227
3260
|
},
|
|
3228
3261
|
// When any JS/TS file imports kbach.css, prepend a disableRuntimeCSS() call
|
|
3229
3262
|
// so styles come solely from the static stylesheet — no duplicate injection.
|
package/dist/vite-plugin.mjs
CHANGED
|
@@ -1905,6 +1905,33 @@ var RESOLVERS = {
|
|
|
1905
1905
|
const color = resolveColor(value, colors, isArbitrary);
|
|
1906
1906
|
return color ? { accentColor: color } : null;
|
|
1907
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
|
+
},
|
|
1908
1935
|
// ── Flex ───────────────────────────────────────────────────────────────────
|
|
1909
1936
|
flex: ({ value, isArbitrary }, { flex }) => {
|
|
1910
1937
|
if (!value) return { display: "flex" };
|
|
@@ -3190,6 +3217,12 @@ function kbach(userConfigOrOptions) {
|
|
|
3190
3217
|
enforce: "pre",
|
|
3191
3218
|
configResolved(resolved) {
|
|
3192
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
|
+
}
|
|
3193
3226
|
},
|
|
3194
3227
|
// When any JS/TS file imports kbach.css, prepend a disableRuntimeCSS() call
|
|
3195
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
|
|
|
@@ -630,6 +636,8 @@ aspect-auto / aspect-square / aspect-video / aspect-[4/3]
|
|
|
630
636
|
columns-{n} / columns-auto / columns-{size}
|
|
631
637
|
caret-{color} / caret-auto / caret-transparent
|
|
632
638
|
accent-{color} / accent-auto
|
|
639
|
+
stroke-{color} / stroke-{n} / stroke-none (web only, SVG)
|
|
640
|
+
fill-{color} / fill-none (web only, SVG)
|
|
633
641
|
mix-blend-{mode}
|
|
634
642
|
bg-blend-{mode}
|
|
635
643
|
will-change-auto/scroll/contents/transform
|