@kbach/ui 0.1.0-beta.5 → 0.1.0-beta.7
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/KBACH.md +8 -1
- package/dist/vite-plugin.d.mts +18 -0
- package/dist/vite-plugin.d.ts +18 -0
- package/dist/vite-plugin.js +17 -4
- package/dist/vite-plugin.mjs +17 -4
- package/kbach-ui.md +21 -0
- package/package.json +1 -1
package/KBACH.md
CHANGED
|
@@ -122,12 +122,19 @@ const Button = styled('button', 'bg-blue-7 hover:bg-blue-8 rounded-xl px-6 py-3'
|
|
|
122
122
|
On web, `styled()` forwards the full class string as `className` so CSS rules (group-hover:, before:, print:) match the element.
|
|
123
123
|
|
|
124
124
|
### useStyles(classes)
|
|
125
|
-
Resolve classes to a style object inside a component.
|
|
125
|
+
Resolve classes to a style object inside a component. This is also the escape hatch for genuinely dynamic class strings (`` `bg-${color}-${shade}` ``) that the static Vite plugin can't discover by scanning source text — it always resolves at render time regardless.
|
|
126
126
|
```jsx
|
|
127
127
|
import { useStyles } from '@kbach/ui';
|
|
128
128
|
const style = useStyles('bg-blue-6 px-3 py-1 rounded-full');
|
|
129
129
|
return <span style={style}>Badge</span>;
|
|
130
130
|
```
|
|
131
|
+
Want that same dynamic set of classes as real CSS in the static file instead of an inline style? Generate the full list yourself and pass it to the plugin's `safelist` option:
|
|
132
|
+
```ts
|
|
133
|
+
// vite.config.ts
|
|
134
|
+
const families = ['red', 'blue' /* … */];
|
|
135
|
+
const shades = [1, 2, 3 /* … */];
|
|
136
|
+
kbach({ safelist: families.flatMap((f) => shades.map((s) => `bg-${f}-${s}`)) })
|
|
137
|
+
```
|
|
131
138
|
|
|
132
139
|
### kb(classes)
|
|
133
140
|
Resolve outside a component (static contexts).
|
package/dist/vite-plugin.d.mts
CHANGED
|
@@ -150,6 +150,24 @@ interface KbachPluginOptions {
|
|
|
150
150
|
framework?: FrameworkConfig;
|
|
151
151
|
/** Directories to scan for class strings (relative to Vite root). Defaults to common source dirs. */
|
|
152
152
|
include?: string[];
|
|
153
|
+
/**
|
|
154
|
+
* Class names to always include in the generated kbach.css, even if no
|
|
155
|
+
* scan finds them literally in your source. Static extraction only ever
|
|
156
|
+
* sees complete class strings as they appear in your files — it can't
|
|
157
|
+
* evaluate `` `bg-${color}-${shade}` `` or similar runtime-built strings,
|
|
158
|
+
* because the actual value doesn't exist until the component renders (see
|
|
159
|
+
* useStyles()'s own docblock for the same limitation from the other
|
|
160
|
+
* direction). Same purpose as Tailwind's `safelist` config: list the
|
|
161
|
+
* complete class names explicitly, e.g. generated from the same
|
|
162
|
+
* color/shade arrays your component already loops over —
|
|
163
|
+
*
|
|
164
|
+
* ```js
|
|
165
|
+
* const families = ['red', 'blue', 'green'];
|
|
166
|
+
* const shades = [1, 2, 3];
|
|
167
|
+
* safelist: families.flatMap((f) => shades.map((s) => `bg-${f}-${s}`))
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
safelist?: string[];
|
|
153
171
|
}
|
|
154
172
|
declare function kbach(userConfigOrOptions?: FrameworkConfig | KbachPluginOptions): Plugin;
|
|
155
173
|
|
package/dist/vite-plugin.d.ts
CHANGED
|
@@ -150,6 +150,24 @@ interface KbachPluginOptions {
|
|
|
150
150
|
framework?: FrameworkConfig;
|
|
151
151
|
/** Directories to scan for class strings (relative to Vite root). Defaults to common source dirs. */
|
|
152
152
|
include?: string[];
|
|
153
|
+
/**
|
|
154
|
+
* Class names to always include in the generated kbach.css, even if no
|
|
155
|
+
* scan finds them literally in your source. Static extraction only ever
|
|
156
|
+
* sees complete class strings as they appear in your files — it can't
|
|
157
|
+
* evaluate `` `bg-${color}-${shade}` `` or similar runtime-built strings,
|
|
158
|
+
* because the actual value doesn't exist until the component renders (see
|
|
159
|
+
* useStyles()'s own docblock for the same limitation from the other
|
|
160
|
+
* direction). Same purpose as Tailwind's `safelist` config: list the
|
|
161
|
+
* complete class names explicitly, e.g. generated from the same
|
|
162
|
+
* color/shade arrays your component already loops over —
|
|
163
|
+
*
|
|
164
|
+
* ```js
|
|
165
|
+
* const families = ['red', 'blue', 'green'];
|
|
166
|
+
* const shades = [1, 2, 3];
|
|
167
|
+
* safelist: families.flatMap((f) => shades.map((s) => `bg-${f}-${s}`))
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
safelist?: string[];
|
|
153
171
|
}
|
|
154
172
|
declare function kbach(userConfigOrOptions?: FrameworkConfig | KbachPluginOptions): Plugin;
|
|
155
173
|
|
package/dist/vite-plugin.js
CHANGED
|
@@ -3757,8 +3757,8 @@ function extractClassStrings(code) {
|
|
|
3757
3757
|
jsxExprRe.lastIndex = i + 1;
|
|
3758
3758
|
pushClassLikeStrings(block, found);
|
|
3759
3759
|
}
|
|
3760
|
-
const
|
|
3761
|
-
while ((m =
|
|
3760
|
+
const classComposerCallRe = /(?:clsx|cn|classnames|cx|kb)\(/g;
|
|
3761
|
+
while ((m = classComposerCallRe.exec(code)) !== null) {
|
|
3762
3762
|
let depth = 1;
|
|
3763
3763
|
let i = m.index + m[0].length;
|
|
3764
3764
|
let block = "";
|
|
@@ -3771,7 +3771,7 @@ function extractClassStrings(code) {
|
|
|
3771
3771
|
block += ch;
|
|
3772
3772
|
i++;
|
|
3773
3773
|
}
|
|
3774
|
-
|
|
3774
|
+
classComposerCallRe.lastIndex = i + 1;
|
|
3775
3775
|
pushClassLikeStrings(block, found);
|
|
3776
3776
|
}
|
|
3777
3777
|
const styledCallRe = /\bstyled\(/g;
|
|
@@ -3860,9 +3860,10 @@ function stripModifierPrefix(token) {
|
|
|
3860
3860
|
}
|
|
3861
3861
|
var DEFAULT_SCAN_DIRS = ["src", "app", "pages", "components", "views", "layouts"];
|
|
3862
3862
|
function kbach(userConfigOrOptions) {
|
|
3863
|
-
const isOptions = userConfigOrOptions != null && ("framework" in userConfigOrOptions || "include" in userConfigOrOptions);
|
|
3863
|
+
const isOptions = userConfigOrOptions != null && ("framework" in userConfigOrOptions || "include" in userConfigOrOptions || "safelist" in userConfigOrOptions);
|
|
3864
3864
|
const userConfig = isOptions ? userConfigOrOptions.framework : userConfigOrOptions;
|
|
3865
3865
|
const includeDirs = (isOptions ? userConfigOrOptions.include : void 0) ?? DEFAULT_SCAN_DIRS;
|
|
3866
|
+
const safelist = (isOptions ? userConfigOrOptions.safelist : void 0) ?? [];
|
|
3866
3867
|
const cfg = buildConfig(userConfig ?? {});
|
|
3867
3868
|
const screens = toNumericScreens(cfg.theme.screens ?? {});
|
|
3868
3869
|
const screenKeys = Object.keys(cfg.theme.screens ?? {});
|
|
@@ -3895,6 +3896,17 @@ function kbach(userConfigOrOptions) {
|
|
|
3895
3896
|
}
|
|
3896
3897
|
fileTokens.set(key, tokens);
|
|
3897
3898
|
}
|
|
3899
|
+
const SAFELIST_KEY = "\0kbach-safelist";
|
|
3900
|
+
function processSafelist() {
|
|
3901
|
+
if (safelist.length === 0) return;
|
|
3902
|
+
const tokens = new Set(safelist);
|
|
3903
|
+
for (const tok of tokens) {
|
|
3904
|
+
if (!tokenCSS.has(tok)) {
|
|
3905
|
+
tokenCSS.set(tok, generateClassCSS(tok, cfg.theme, cfg.darkMode, screens));
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
fileTokens.set(SAFELIST_KEY, tokens);
|
|
3909
|
+
}
|
|
3898
3910
|
function scanProjectCssSelectors() {
|
|
3899
3911
|
for (const dir of includeDirs) scanCssSelectorsInto((0, import_path.join)(root, dir), projectCssClasses);
|
|
3900
3912
|
}
|
|
@@ -3992,6 +4004,7 @@ ${code}`,
|
|
|
3992
4004
|
mainCSSFile = findKbachCSS(root);
|
|
3993
4005
|
scanProjectCssSelectors();
|
|
3994
4006
|
initialScan();
|
|
4007
|
+
processSafelist();
|
|
3995
4008
|
if (mainCSSFile) writeKbachToFile(mainCSSFile, generateCSS());
|
|
3996
4009
|
},
|
|
3997
4010
|
// Vite's `handleHotUpdate` hook only fires for `type === "update"` (plain
|
package/dist/vite-plugin.mjs
CHANGED
|
@@ -3721,8 +3721,8 @@ function extractClassStrings(code) {
|
|
|
3721
3721
|
jsxExprRe.lastIndex = i + 1;
|
|
3722
3722
|
pushClassLikeStrings(block, found);
|
|
3723
3723
|
}
|
|
3724
|
-
const
|
|
3725
|
-
while ((m =
|
|
3724
|
+
const classComposerCallRe = /(?:clsx|cn|classnames|cx|kb)\(/g;
|
|
3725
|
+
while ((m = classComposerCallRe.exec(code)) !== null) {
|
|
3726
3726
|
let depth = 1;
|
|
3727
3727
|
let i = m.index + m[0].length;
|
|
3728
3728
|
let block = "";
|
|
@@ -3735,7 +3735,7 @@ function extractClassStrings(code) {
|
|
|
3735
3735
|
block += ch;
|
|
3736
3736
|
i++;
|
|
3737
3737
|
}
|
|
3738
|
-
|
|
3738
|
+
classComposerCallRe.lastIndex = i + 1;
|
|
3739
3739
|
pushClassLikeStrings(block, found);
|
|
3740
3740
|
}
|
|
3741
3741
|
const styledCallRe = /\bstyled\(/g;
|
|
@@ -3824,9 +3824,10 @@ function stripModifierPrefix(token) {
|
|
|
3824
3824
|
}
|
|
3825
3825
|
var DEFAULT_SCAN_DIRS = ["src", "app", "pages", "components", "views", "layouts"];
|
|
3826
3826
|
function kbach(userConfigOrOptions) {
|
|
3827
|
-
const isOptions = userConfigOrOptions != null && ("framework" in userConfigOrOptions || "include" in userConfigOrOptions);
|
|
3827
|
+
const isOptions = userConfigOrOptions != null && ("framework" in userConfigOrOptions || "include" in userConfigOrOptions || "safelist" in userConfigOrOptions);
|
|
3828
3828
|
const userConfig = isOptions ? userConfigOrOptions.framework : userConfigOrOptions;
|
|
3829
3829
|
const includeDirs = (isOptions ? userConfigOrOptions.include : void 0) ?? DEFAULT_SCAN_DIRS;
|
|
3830
|
+
const safelist = (isOptions ? userConfigOrOptions.safelist : void 0) ?? [];
|
|
3830
3831
|
const cfg = buildConfig(userConfig ?? {});
|
|
3831
3832
|
const screens = toNumericScreens(cfg.theme.screens ?? {});
|
|
3832
3833
|
const screenKeys = Object.keys(cfg.theme.screens ?? {});
|
|
@@ -3859,6 +3860,17 @@ function kbach(userConfigOrOptions) {
|
|
|
3859
3860
|
}
|
|
3860
3861
|
fileTokens.set(key, tokens);
|
|
3861
3862
|
}
|
|
3863
|
+
const SAFELIST_KEY = "\0kbach-safelist";
|
|
3864
|
+
function processSafelist() {
|
|
3865
|
+
if (safelist.length === 0) return;
|
|
3866
|
+
const tokens = new Set(safelist);
|
|
3867
|
+
for (const tok of tokens) {
|
|
3868
|
+
if (!tokenCSS.has(tok)) {
|
|
3869
|
+
tokenCSS.set(tok, generateClassCSS(tok, cfg.theme, cfg.darkMode, screens));
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
fileTokens.set(SAFELIST_KEY, tokens);
|
|
3873
|
+
}
|
|
3862
3874
|
function scanProjectCssSelectors() {
|
|
3863
3875
|
for (const dir of includeDirs) scanCssSelectorsInto(join(root, dir), projectCssClasses);
|
|
3864
3876
|
}
|
|
@@ -3956,6 +3968,7 @@ ${code}`,
|
|
|
3956
3968
|
mainCSSFile = findKbachCSS(root);
|
|
3957
3969
|
scanProjectCssSelectors();
|
|
3958
3970
|
initialScan();
|
|
3971
|
+
processSafelist();
|
|
3959
3972
|
if (mainCSSFile) writeKbachToFile(mainCSSFile, generateCSS());
|
|
3960
3973
|
},
|
|
3961
3974
|
// Vite's `handleHotUpdate` hook only fires for `type === "update"` (plain
|
package/kbach-ui.md
CHANGED
|
@@ -120,6 +120,27 @@ kbach({
|
|
|
120
120
|
})
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
+
`kbach()` also accepts an options wrapper — `{ framework, include, safelist }` — instead of a bare framework config directly:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
kbach({
|
|
127
|
+
framework: { darkMode: 'attribute', theme: { colors: { brand: { 6: '#6366f1' } } } },
|
|
128
|
+
include: ['src'], // dirs to scan (relative to Vite root) — default: src, app, pages, components, views, layouts
|
|
129
|
+
safelist: [ /* see below */ ],
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**`safelist`** — class names to always include, even if no scan finds them. Static extraction only ever sees complete class strings as they appear in your source — it can't evaluate `` `bg-${family}-${shade}` `` or similar runtime-built strings, since the actual value doesn't exist until the component renders (this is exactly why `useStyles()` exists — see its own docs above — it resolves those to a real inline style instead). If you want a genuinely dynamic set of classes in the static file anyway, generate the full list yourself and pass it in — same purpose as Tailwind's own `safelist` config:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const families = ['red', 'blue', 'green' /* … */];
|
|
137
|
+
const shades = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
|
138
|
+
|
|
139
|
+
kbach({
|
|
140
|
+
safelist: families.flatMap((f) => shades.map((s) => `bg-${f}-${s}`)),
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
123
144
|
Generated output format:
|
|
124
145
|
```css
|
|
125
146
|
/* kbach:start */
|