@kbach/react 0.4.2 → 0.5.0
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 +106 -28
- package/dist/{chunk-JFQ7QYQM.mjs → chunk-2BRVUJPY.mjs} +74 -19
- package/dist/{chunk-HY6PU2XS.mjs → chunk-LTYLJ4B3.mjs} +981 -38
- package/dist/index.d.mts +2 -9
- package/dist/index.d.ts +2 -9
- package/dist/index.js +1072 -113
- package/dist/index.mjs +21 -3
- package/dist/jsx-dev-runtime.js +1049 -56
- package/dist/jsx-dev-runtime.mjs +2 -2
- package/dist/jsx-runtime.js +1049 -56
- package/dist/jsx-runtime.mjs +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @kbach/react
|
|
2
2
|
|
|
3
|
-
Tailwind-like utility classes for **React (web)**. Classes are converted to inline styles at render time through a custom JSX runtime — no stylesheet required.
|
|
3
|
+
Tailwind-like utility classes for **React (web)**. Classes are converted to inline styles at render time through a custom JSX runtime — no stylesheet required. Responsive, dark mode, hover, and pseudo-element rules are injected as real CSS so they work with pure CSS cascading.
|
|
4
4
|
|
|
5
5
|
```jsx
|
|
6
6
|
/** @jsxImportSource @kbach/react */
|
|
@@ -8,6 +8,9 @@ Tailwind-like utility classes for **React (web)**. Classes are converted to inli
|
|
|
8
8
|
<div className="bg-white dark:bg-gray-10 p-4 rounded-xl shadow" />
|
|
9
9
|
<div className="bg-blue-7 hover:bg-blue-8 dark:bg-indigo-6 rounded-lg px-6 py-3" />
|
|
10
10
|
<div className="bg-[#6366f1] p-[14px] rounded-[20px]" />
|
|
11
|
+
<div className="group">
|
|
12
|
+
<span className="group-hover:text-blue-6 transition" />
|
|
13
|
+
</div>
|
|
11
14
|
```
|
|
12
15
|
|
|
13
16
|
## Install
|
|
@@ -83,12 +86,13 @@ Works on any HTML element or React component once the JSX runtime is configured.
|
|
|
83
86
|
```jsx
|
|
84
87
|
<div className="bg-white dark:bg-gray-10 p-4 rounded-xl" />
|
|
85
88
|
<p className="text-gray-10 dark:text-white text-lg font-bold" />
|
|
86
|
-
<button className="bg-blue-7 hover:bg-blue-8 pressed:bg-blue-
|
|
89
|
+
<button className="bg-blue-7 hover:bg-blue-8 pressed:bg-blue-9 rounded-lg px-4 py-2" />
|
|
90
|
+
<input className="caret-blue-6 focus:ring-2" />
|
|
87
91
|
```
|
|
88
92
|
|
|
89
93
|
### styled(Component, classes)
|
|
90
94
|
|
|
91
|
-
Pre-style any component. Returns a new component that merges the base classes with any `
|
|
95
|
+
Pre-style any component. Returns a new component that merges the base classes with any `kb` prop passed at use time. On web, the class string is forwarded as `className` so CSS rules (group-hover:, before:, print:, etc.) match the element.
|
|
92
96
|
|
|
93
97
|
```jsx
|
|
94
98
|
import { styled } from '@kbach/react';
|
|
@@ -121,7 +125,7 @@ function Badge() {
|
|
|
121
125
|
|
|
122
126
|
### kb(classes)
|
|
123
127
|
|
|
124
|
-
Resolve classes outside a component (static contexts,
|
|
128
|
+
Resolve classes outside a component (static contexts, etc.).
|
|
125
129
|
|
|
126
130
|
```js
|
|
127
131
|
import { kb } from '@kbach/react';
|
|
@@ -179,29 +183,13 @@ import { useColors } from '@kbach/react';
|
|
|
179
183
|
|
|
180
184
|
const colors = useColors();
|
|
181
185
|
|
|
182
|
-
// Shade access
|
|
183
186
|
colors.blue[6] // '#6c87b6'
|
|
184
|
-
colors.red[11] // '#3e0606'
|
|
185
|
-
|
|
186
|
-
// Shade + opacity (0–100)
|
|
187
187
|
colors.blue['6/50'] // 'rgba(108,135,182,0.5)'
|
|
188
|
-
colors.slate['3/10'] // 'rgba(221,227,242,0.1)'
|
|
189
|
-
|
|
190
|
-
// Flat colors
|
|
191
188
|
colors.white // '#ffffff'
|
|
192
|
-
colors.transparent // 'transparent'
|
|
193
|
-
|
|
194
|
-
// Flat color + opacity
|
|
195
189
|
colors['white/20'] // 'rgba(255,255,255,0.2)'
|
|
196
|
-
colors
|
|
197
|
-
|
|
198
|
-
// Arbitrary CSS color with opacity
|
|
199
|
-
colors.alpha('#ff6b35', 60) // 'rgba(255,107,53,0.6)'
|
|
200
|
-
colors.alpha('rgb(100,200,100)', 30) // 'rgba(100,200,100,0.3)'
|
|
190
|
+
colors.alpha('#ff6b35', 60) // 'rgba(255,107,53,0.6)'
|
|
201
191
|
```
|
|
202
192
|
|
|
203
|
-
Common uses: chart libraries that need raw hex values, dynamic inline styles, color pickers that mirror the theme palette.
|
|
204
|
-
|
|
205
193
|
### ThemeToggle
|
|
206
194
|
|
|
207
195
|
Drop-in toggle component.
|
|
@@ -217,19 +205,95 @@ Drop-in toggle component.
|
|
|
217
205
|
|
|
218
206
|
Up to 3 modifiers can be chained in any order.
|
|
219
207
|
|
|
208
|
+
### Theme & interaction
|
|
209
|
+
|
|
220
210
|
| Modifier | Trigger |
|
|
221
211
|
|---|---|
|
|
222
212
|
| `dark:` | Dark mode active |
|
|
223
213
|
| `light:` | Light mode active |
|
|
224
214
|
| `hover:` | Mouse hover |
|
|
225
|
-
| `pressed:` | Click
|
|
226
|
-
| `focus:` |
|
|
227
|
-
| `active:` |
|
|
228
|
-
| `disabled:` |
|
|
215
|
+
| `pressed:` | Click / touch |
|
|
216
|
+
| `focus:` | Focused |
|
|
217
|
+
| `active:` | Active state |
|
|
218
|
+
| `disabled:` | Disabled |
|
|
219
|
+
| `checked:` | Checked (checkbox/radio) |
|
|
220
|
+
| `visited:` | Visited link |
|
|
221
|
+
| `focus-within:` | Focus inside element |
|
|
222
|
+
| `focus-visible:` | Keyboard focus ring |
|
|
223
|
+
|
|
224
|
+
Negated forms: `not-hover:`, `not-focus:`, `not-active:`, `not-pressed:`, `not-disabled:`, `not-checked:`, `not-visited:`
|
|
225
|
+
|
|
226
|
+
### Structural
|
|
227
|
+
|
|
228
|
+
| Modifier | Matches |
|
|
229
|
+
|---|---|
|
|
230
|
+
| `first:` | `:first-child` |
|
|
231
|
+
| `last:` | `:last-child` |
|
|
232
|
+
| `odd:` | `:nth-child(odd)` |
|
|
233
|
+
| `even:` | `:nth-child(even)` |
|
|
234
|
+
| `only:` | `:only-child` |
|
|
235
|
+
|
|
236
|
+
### Responsive
|
|
237
|
+
|
|
238
|
+
| Modifier | Min-width |
|
|
239
|
+
|---|---|
|
|
240
|
+
| `sm:` | 640 px |
|
|
241
|
+
| `md:` | 768 px |
|
|
242
|
+
| `lg:` | 1024 px |
|
|
243
|
+
| `xl:` | 1280 px |
|
|
244
|
+
| `2xl:` | 1536 px |
|
|
245
|
+
|
|
246
|
+
### Group / peer
|
|
247
|
+
|
|
248
|
+
Mark an ancestor with `group` or `peer`, then style descendants with the modifier:
|
|
249
|
+
|
|
250
|
+
```jsx
|
|
251
|
+
<div className="group">
|
|
252
|
+
<span className="opacity-0 group-hover:opacity-100 transition" />
|
|
253
|
+
</div>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Modifier | Fires when |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `group-hover:` | Ancestor `.group` is hovered |
|
|
259
|
+
| `group-focus:` | Ancestor `.group` is focused |
|
|
260
|
+
| `peer-hover:` | Previous sibling `.peer` is hovered |
|
|
261
|
+
| `peer-focus:` | Previous sibling `.peer` is focused |
|
|
262
|
+
|
|
263
|
+
### Pseudo-elements
|
|
264
|
+
|
|
265
|
+
Inject content or style structural parts of an element with real CSS:
|
|
266
|
+
|
|
267
|
+
```jsx
|
|
268
|
+
<div className="before:content-['*'] before:text-red-6 relative" />
|
|
269
|
+
<p className="first-letter:text-4xl first-letter:font-bold" />
|
|
270
|
+
<input className="placeholder:text-gray-5" />
|
|
271
|
+
<p className="selection:bg-blue-3" />
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
| Modifier | CSS |
|
|
275
|
+
|---|---|
|
|
276
|
+
| `before:` | `::before` |
|
|
277
|
+
| `after:` | `::after` |
|
|
278
|
+
| `selection:` | `::selection` |
|
|
279
|
+
| `first-letter:` | `::first-letter` |
|
|
280
|
+
| `first-line:` | `::first-line` |
|
|
281
|
+
| `marker:` | `::marker` |
|
|
282
|
+
| `placeholder:` | `::placeholder` |
|
|
283
|
+
|
|
284
|
+
### Print
|
|
285
|
+
|
|
286
|
+
```jsx
|
|
287
|
+
<div className="print:hidden" />
|
|
288
|
+
<div className="print:text-black print:bg-white" />
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Important modifier
|
|
292
|
+
|
|
293
|
+
Prefix any class with `!` to add `!important` to every CSS declaration it produces:
|
|
229
294
|
|
|
230
295
|
```jsx
|
|
231
|
-
<div className="
|
|
232
|
-
<button className="dark:pressed:bg-indigo-8" />
|
|
296
|
+
<div className="!p-0 !m-0" />
|
|
233
297
|
```
|
|
234
298
|
|
|
235
299
|
## Arbitrary values
|
|
@@ -238,6 +302,7 @@ Up to 3 modifiers can be chained in any order.
|
|
|
238
302
|
<div className="bg-[#6366f1]" />
|
|
239
303
|
<div className="p-[14px]" />
|
|
240
304
|
<div className="text-[18px]" />
|
|
305
|
+
<div className="w-[calc(100%-2rem)]" />
|
|
241
306
|
<div className="bg-[rgba(99,102,241,0.15)]" />
|
|
242
307
|
```
|
|
243
308
|
|
|
@@ -265,13 +330,26 @@ Available families: slate, gray, zinc, neutral, stone, red, orange, amber, yello
|
|
|
265
330
|
|---|---|
|
|
266
331
|
| Background | `bg-white`, `bg-gray-10`, `bg-blue-6`, `bg-[#fff]` |
|
|
267
332
|
| Text | `text-sm`, `text-2xl`, `text-gray-10`, `font-bold` |
|
|
333
|
+
| Text wrap | `text-balance`, `text-pretty`, `text-nowrap`, `text-wrap` |
|
|
334
|
+
| Line clamp | `line-clamp-3`, `line-clamp-none` |
|
|
268
335
|
| Padding | `p-4`, `px-6`, `py-3` |
|
|
269
336
|
| Margin | `m-4`, `mx-auto`, `mt-2`, `-mt-4` |
|
|
270
|
-
| Size | `w-full`, `h-
|
|
337
|
+
| Size | `size-12`, `w-full`, `h-screen`, `w-screen`, `w-[200px]` |
|
|
271
338
|
| Flex | `flex-1`, `flex-row`, `items-center`, `justify-between`, `gap-4` |
|
|
339
|
+
| Grid | `grid-3`, `col-span-2`, `grid-flow-col` |
|
|
272
340
|
| Border | `border`, `border-2`, `border-gray-4`, `rounded-xl` |
|
|
273
341
|
| Shadow | `shadow`, `shadow-md`, `shadow-lg` |
|
|
274
342
|
| Opacity | `opacity-50`, `opacity-75` |
|
|
343
|
+
| Overflow | `overflow-hidden`, `overflow-clip`, `overflow-x-auto` |
|
|
344
|
+
| Cursor | `cursor-pointer`, `cursor-grab`, `cursor-zoom-in` |
|
|
345
|
+
| Scroll | `scroll-smooth`, `scroll-auto` |
|
|
346
|
+
| Float / clear | `float-left`, `float-right`, `clear-both` |
|
|
347
|
+
| Vertical align | `align-middle`, `align-top`, `align-baseline` |
|
|
348
|
+
| Touch action | `touch-none`, `touch-pan-x`, `touch-manipulation` |
|
|
349
|
+
| Caret | `caret-blue-6`, `caret-transparent` |
|
|
350
|
+
| Accent | `accent-blue-6`, `accent-auto` |
|
|
351
|
+
| Animation | `animate-spin`, `animate-pulse`, `animate-bounce`, `animate-ping` |
|
|
352
|
+
| Transition | `transition`, `duration-300`, `delay-150` |
|
|
275
353
|
|
|
276
354
|
## Configuration
|
|
277
355
|
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
resolve,
|
|
9
9
|
useConditionalWidth,
|
|
10
10
|
useGlobalDarkMode
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LTYLJ4B3.mjs";
|
|
12
12
|
|
|
13
13
|
// src/jsx-runtime.tsx
|
|
14
14
|
import { jsx as _jsx, jsxs as _jsxs, Fragment } from "react/jsx-runtime";
|
|
@@ -32,6 +32,7 @@ var DarkWrapper = React.forwardRef(
|
|
|
32
32
|
const width = useConditionalWidth(needsWidth);
|
|
33
33
|
const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
|
|
34
34
|
const computedStyle = flatten(resolvedStyle, isDark, {}, breakpoints);
|
|
35
|
+
stripInternalMarkers(computedStyle);
|
|
35
36
|
if (typeof Component !== "string") stripWebOnlyProps(computedStyle);
|
|
36
37
|
const finalStyle = styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
|
|
37
38
|
const props = { ref, ...rest, style: finalStyle };
|
|
@@ -39,6 +40,13 @@ var DarkWrapper = React.forwardRef(
|
|
|
39
40
|
}
|
|
40
41
|
);
|
|
41
42
|
DarkWrapper.displayName = "Kbach.DarkWrapper";
|
|
43
|
+
function stripInternalMarkers(s) {
|
|
44
|
+
delete s.__divideX;
|
|
45
|
+
delete s.__divideY;
|
|
46
|
+
delete s.__divideColor;
|
|
47
|
+
delete s.__divideStyle;
|
|
48
|
+
delete s.__keyframe;
|
|
49
|
+
}
|
|
42
50
|
function stripWebOnlyProps(s) {
|
|
43
51
|
if (s.display === "grid" || s.display === "inline-grid") delete s.display;
|
|
44
52
|
delete s.gridTemplateColumns;
|
|
@@ -46,9 +54,18 @@ function stripWebOnlyProps(s) {
|
|
|
46
54
|
delete s.gridColumn;
|
|
47
55
|
delete s.gridRow;
|
|
48
56
|
delete s.gridArea;
|
|
57
|
+
delete s.gridColumnStart;
|
|
58
|
+
delete s.gridColumnEnd;
|
|
59
|
+
delete s.gridRowStart;
|
|
60
|
+
delete s.gridRowEnd;
|
|
49
61
|
delete s.gridAutoFlow;
|
|
50
62
|
delete s.gridAutoColumns;
|
|
51
63
|
delete s.gridAutoRows;
|
|
64
|
+
delete s.placeItems;
|
|
65
|
+
delete s.placeContent;
|
|
66
|
+
delete s.justifyItems;
|
|
67
|
+
delete s.placeSelf;
|
|
68
|
+
delete s.justifySelf;
|
|
52
69
|
if (s.position === "sticky" || s.position === "fixed" || s.position === "static") {
|
|
53
70
|
delete s.position;
|
|
54
71
|
}
|
|
@@ -122,6 +139,57 @@ function mergeStyle(computed, userStyle) {
|
|
|
122
139
|
function makeElement(isStaticChildren, type, props, key) {
|
|
123
140
|
return (isStaticChildren ? _jsxs : _jsx)(type, props, key);
|
|
124
141
|
}
|
|
142
|
+
function hasGridStyles(resolved) {
|
|
143
|
+
for (const styles of Object.values(resolved)) {
|
|
144
|
+
if (!styles) continue;
|
|
145
|
+
if (styles.display === "grid" || styles.display === "inline-grid") return true;
|
|
146
|
+
if ("gridTemplateColumns" in styles || "gridTemplateRows" in styles) return true;
|
|
147
|
+
if ("gridColumn" in styles || "gridRow" in styles) return true;
|
|
148
|
+
if ("gridColumnStart" in styles || "gridColumnEnd" in styles) return true;
|
|
149
|
+
if ("gridRowStart" in styles || "gridRowEnd" in styles) return true;
|
|
150
|
+
if ("gridAutoFlow" in styles || "gridAutoColumns" in styles || "gridAutoRows" in styles) return true;
|
|
151
|
+
if ("placeItems" in styles || "placeContent" in styles || "justifyItems" in styles) return true;
|
|
152
|
+
if ("placeSelf" in styles || "justifySelf" in styles) return true;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
function hasWebPositionStyles(resolved) {
|
|
157
|
+
for (const styles of Object.values(resolved)) {
|
|
158
|
+
if (!styles) continue;
|
|
159
|
+
if (styles.position === "sticky" || styles.position === "fixed" || styles.position === "static") return true;
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
function stripInternalMarkers2(s) {
|
|
164
|
+
delete s.__divideX;
|
|
165
|
+
delete s.__divideY;
|
|
166
|
+
delete s.__divideColor;
|
|
167
|
+
delete s.__divideStyle;
|
|
168
|
+
delete s.__keyframe;
|
|
169
|
+
}
|
|
170
|
+
function stripWebOnlyInlineProps(s) {
|
|
171
|
+
if (s.display === "grid" || s.display === "inline-grid") delete s.display;
|
|
172
|
+
delete s.gridTemplateColumns;
|
|
173
|
+
delete s.gridTemplateRows;
|
|
174
|
+
delete s.gridColumn;
|
|
175
|
+
delete s.gridRow;
|
|
176
|
+
delete s.gridArea;
|
|
177
|
+
delete s.gridColumnStart;
|
|
178
|
+
delete s.gridColumnEnd;
|
|
179
|
+
delete s.gridRowStart;
|
|
180
|
+
delete s.gridRowEnd;
|
|
181
|
+
delete s.gridAutoFlow;
|
|
182
|
+
delete s.gridAutoColumns;
|
|
183
|
+
delete s.gridAutoRows;
|
|
184
|
+
delete s.placeItems;
|
|
185
|
+
delete s.placeContent;
|
|
186
|
+
delete s.justifyItems;
|
|
187
|
+
delete s.placeSelf;
|
|
188
|
+
delete s.justifySelf;
|
|
189
|
+
if (s.position === "sticky" || s.position === "fixed" || s.position === "static") {
|
|
190
|
+
delete s.position;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
125
193
|
function processElement(type, rawProps, key, isStaticChildren) {
|
|
126
194
|
if (!rawProps) return _jsx(type, null, key);
|
|
127
195
|
const { className, kb: kbProp, __kbachStyles, __kbachClasses } = rawProps;
|
|
@@ -130,13 +198,12 @@ function processElement(type, rawProps, key, isStaticChildren) {
|
|
|
130
198
|
return makeElement(isStaticChildren, type, rawProps, key);
|
|
131
199
|
}
|
|
132
200
|
const config = getConfig();
|
|
133
|
-
const isOnWeb = typeof document !== "undefined" && classStr != null;
|
|
134
|
-
const isGrdOnWeb = isOnWeb && /(?:^|\s)grd(?:\s|$)/.test(classStr);
|
|
135
|
-
const hasWebPosition = isOnWeb && /(?:^|\s)(?:[\w-]+:)*(?:fixed|sticky)(?:\s|$)/.test(classStr);
|
|
136
|
-
const actualType = isGrdOnWeb || hasWebPosition ? "div" : type;
|
|
137
201
|
const resolved = __kbachStyles ?? (classStr ? resolve(classStr, config.theme, config.darkMode) : {});
|
|
138
202
|
const { style: userStyle, ...passProps } = omitConsumed(rawProps);
|
|
139
203
|
const { interactive, modeOrResponsive } = bucketMods(resolved);
|
|
204
|
+
const onWeb = typeof document !== "undefined";
|
|
205
|
+
const needsDiv = onWeb && (hasGridStyles(resolved) || hasWebPositionStyles(resolved));
|
|
206
|
+
const actualType = needsDiv ? "div" : type;
|
|
140
207
|
if (interactive) {
|
|
141
208
|
return _jsx(InteractiveWrapper, {
|
|
142
209
|
Component: actualType,
|
|
@@ -156,20 +223,8 @@ function processElement(type, rawProps, key, isStaticChildren) {
|
|
|
156
223
|
}, key);
|
|
157
224
|
}
|
|
158
225
|
const computedStyle = flatten(resolved, false);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
delete computedStyle.gridTemplateColumns;
|
|
162
|
-
delete computedStyle.gridTemplateRows;
|
|
163
|
-
delete computedStyle.gridColumn;
|
|
164
|
-
delete computedStyle.gridRow;
|
|
165
|
-
delete computedStyle.gridArea;
|
|
166
|
-
delete computedStyle.gridAutoFlow;
|
|
167
|
-
delete computedStyle.gridAutoColumns;
|
|
168
|
-
delete computedStyle.gridAutoRows;
|
|
169
|
-
if (computedStyle.position === "sticky" || computedStyle.position === "fixed" || computedStyle.position === "static") {
|
|
170
|
-
delete computedStyle.position;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
226
|
+
stripInternalMarkers2(computedStyle);
|
|
227
|
+
if (typeof actualType !== "string") stripWebOnlyInlineProps(computedStyle);
|
|
173
228
|
const finalStyle = mergeStyle(computedStyle, userStyle);
|
|
174
229
|
return makeElement(isStaticChildren, actualType, {
|
|
175
230
|
...passProps,
|