@kbach/ui 0.1.0-beta.7 → 1.0.0-beta.1
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 +37 -179
- package/dist/index.d.mts +43 -0
- package/dist/index.d.ts +33 -319
- package/dist/index.js +24 -1170
- package/dist/index.mjs +21 -592
- package/package.json +17 -77
- package/KBACH.md +0 -1059
- package/dist/chunk-LY753XBX.mjs +0 -4259
- package/dist/chunk-UVXTWGHQ.mjs +0 -208
- package/dist/core/index.d.ts +0 -1404
- package/dist/core/index.js +0 -3778
- package/dist/jsx-dev-runtime.d.ts +0 -21
- package/dist/jsx-dev-runtime.js +0 -780
- package/dist/jsx-dev-runtime.mjs +0 -21
- package/dist/jsx-runtime.d.ts +0 -17
- package/dist/jsx-runtime.js +0 -779
- package/dist/jsx-runtime.mjs +0 -17
- package/dist/native.js +0 -78
- package/dist/native.mjs +0 -49
- package/dist/vite-plugin.d.mts +0 -174
- package/dist/vite-plugin.d.ts +0 -174
- package/dist/vite-plugin.js +0 -4064
- package/dist/vite-plugin.mjs +0 -4027
- package/dist/web-substitute-6xH1WxpZ.d.ts +0 -22
- package/jsx-dev-runtime.js +0 -3
- package/jsx-runtime.js +0 -3
- package/kbach-ui.md +0 -921
- package/scripts/postinstall.js +0 -45
- package/src/native/babel/index.js +0 -30
- package/src/native/babel-plugin/index.js +0 -605
- package/src/native/babel-plugin/index.test.ts +0 -86
- package/types.d.ts +0 -1
package/README.md
CHANGED
|
@@ -1,205 +1,63 @@
|
|
|
1
1
|
# @kbach/ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A tiny, dependency-free class-name composer — the same public API and
|
|
4
|
+
behavior as the widely-used [`clsx`](https://www.npmjs.com/package/clsx)
|
|
5
|
+
package, reimplemented from scratch so using it adds zero runtime
|
|
6
|
+
dependencies to your project.
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
<div className="bg-white dark:bg-gray-10 p-4 rounded-xl shadow" />
|
|
7
|
-
<div className="bg-blue-7 hover:bg-blue-8 dark:bg-indigo-6 rounded-lg px-6 py-3" />
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
[npm package](https://www.npmjs.com/package/@kbach/ui)
|
|
8
|
+
> Beta — API may still change before 1.0.0.
|
|
11
9
|
|
|
12
|
-
##
|
|
10
|
+
## Install
|
|
13
11
|
|
|
14
|
-
```
|
|
12
|
+
```sh
|
|
15
13
|
npm install @kbach/ui
|
|
16
14
|
```
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
**tsconfig.json:**
|
|
21
|
-
|
|
22
|
-
```json
|
|
23
|
-
{ "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "@kbach/ui" } }
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
That's the only setting needed — Vite, Next.js, and React Router all read it. Don't *also* set `jsxImportSource` on a bundler plugin (e.g. `@vitejs/plugin-react`); one source of truth avoids conflicts.
|
|
27
|
-
|
|
28
|
-
### Which setup do I need?
|
|
29
|
-
|
|
30
|
-
| Framework | Use |
|
|
31
|
-
|---|---|
|
|
32
|
-
| Vite, React Router library mode, CRA, other Vite-based | **[Static CSS](#static-css)** (recommended) — zero runtime cost, catches typos at build time |
|
|
33
|
-
| React Router, framework mode | **[Static CSS](#static-css)** — and skip `@vitejs/plugin-react`, see note below |
|
|
34
|
-
| Next.js | **[Next.js](#nextjs)** — Runtime setup, plus one App Router-specific detail |
|
|
35
|
-
| React Native, Expo | **[React Native / Expo](#react-native--expo)** — different setup entirely (Babel preset, not the JSX runtime step above) |
|
|
36
|
-
|
|
37
|
-
### Static CSS
|
|
38
|
-
|
|
39
|
-
Vite only, and the recommended setup for any Vite-based app — a build-time plugin writes real CSS into a file you import at build time, so nothing is generated client-side and there's zero runtime cost. Three pieces, all required:
|
|
40
|
-
|
|
41
|
-
**1. Add the plugin:**
|
|
16
|
+
## Usage
|
|
42
17
|
|
|
43
18
|
```ts
|
|
44
|
-
|
|
45
|
-
import { defineConfig } from 'vite';
|
|
46
|
-
import { kbach } from '@kbach/ui/vite';
|
|
19
|
+
import { clsx } from '@kbach/ui';
|
|
47
20
|
|
|
48
|
-
|
|
21
|
+
clsx('px-4 py-2', isActive && 'bg-blue-6', { 'opacity-50': disabled });
|
|
22
|
+
// "px-4 py-2 bg-blue-6" — when isActive is true and disabled is false
|
|
49
23
|
```
|
|
50
24
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```css
|
|
54
|
-
/* src/kbach.css */
|
|
55
|
-
/* kbach:start */
|
|
56
|
-
/* kbach:end */
|
|
57
|
-
```
|
|
25
|
+
Also available as the default export, matching how `clsx` itself is
|
|
26
|
+
conventionally imported:
|
|
58
27
|
|
|
59
28
|
```ts
|
|
60
|
-
|
|
61
|
-
import './kbach.css';
|
|
29
|
+
import clsx from '@kbach/ui';
|
|
62
30
|
```
|
|
63
31
|
|
|
64
|
-
|
|
32
|
+
Accepts, in any combination and to any nesting depth:
|
|
65
33
|
|
|
66
|
-
**
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return <ThemeProvider defaultMode="system"><App /></ThemeProvider>;
|
|
73
|
-
}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Done. The plugin scans your source at build time and writes CSS between the markers, and warns in the terminal (with a clickable `file:line`) for any class it doesn't recognize — usually a typo.
|
|
77
|
-
|
|
78
|
-
Using a custom `kbach.config.js`? See [Wiring a custom config in](#wiring-a-custom-config-in) below — it needs to be passed in twice for Static CSS specifically.
|
|
79
|
-
|
|
80
|
-
**React Router framework mode:** don't add `@vitejs/plugin-react` — `reactRouter()` already provides JSX handling, and both together crash the page (`Identifier 'RefreshRuntime' has already been declared`).
|
|
34
|
+
- **Strings** (`'px-4'`) — kept as-is.
|
|
35
|
+
- **Falsy values** (`false`, `null`, `undefined`, `0`, `''`, `NaN`) — dropped
|
|
36
|
+
entirely, so `isActive && 'bg-blue-6'` reads naturally.
|
|
37
|
+
- **Objects** (`{ 'opacity-50': disabled }`) — a key is kept only when its
|
|
38
|
+
value is truthy.
|
|
39
|
+
- **Arrays** (`['px-4', condition && 'py-2']`) — flattened recursively.
|
|
81
40
|
|
|
82
41
|
```ts
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
import { defineConfig } from 'vite';
|
|
86
|
-
import { kbach } from '@kbach/ui/vite'; // omit if using Runtime setup instead
|
|
87
|
-
|
|
88
|
-
export default defineConfig({ plugins: [kbach(), reactRouter()] });
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
(React Router library mode — `createBrowserRouter`, no SSR — has no such conflict; set it up like any Vite + React app.)
|
|
92
|
-
|
|
93
|
-
### Runtime
|
|
94
|
-
|
|
95
|
-
Client-side CSS injection — works with any bundler (Vite, webpack, Turbopack, Metro-for-web, …), no build plugin. Next.js always uses this, or use it on Vite if you'd rather not wire up the plugin yet:
|
|
96
|
-
|
|
97
|
-
```jsx
|
|
98
|
-
import { ThemeProvider, KbachReset } from '@kbach/ui';
|
|
99
|
-
|
|
100
|
-
export default function Root() {
|
|
101
|
-
return (
|
|
102
|
-
<ThemeProvider defaultMode="system">
|
|
103
|
-
<KbachReset />
|
|
104
|
-
<App />
|
|
105
|
-
</ThemeProvider>
|
|
106
|
-
);
|
|
107
|
-
}
|
|
42
|
+
clsx('base', ['px-4', { 'bg-blue-6': true }], { 'opacity-50': false });
|
|
43
|
+
// "base px-4 bg-blue-6"
|
|
108
44
|
```
|
|
109
45
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
Using a custom `kbach.config.js`? Pass it to `ThemeProvider` — see [Wiring a custom config in](#wiring-a-custom-config-in).
|
|
113
|
-
|
|
114
|
-
Don't also set up Static CSS above in the same app — pick one.
|
|
115
|
-
|
|
116
|
-
### Next.js
|
|
117
|
-
|
|
118
|
-
Always [Runtime setup](#runtime) above — Static CSS doesn't apply (webpack/Turbopack, not Vite). The `tsconfig.json` step from [Setup](#setup) applies as-is; SWC reads `jsxImportSource` the same way Vite does.
|
|
119
|
-
|
|
120
|
-
The one Next.js-specific detail: render `<KbachReset />` once in the root App Router `layout.tsx`:
|
|
121
|
-
|
|
122
|
-
```jsx
|
|
123
|
-
// app/layout.tsx
|
|
124
|
-
import { ThemeProvider, KbachReset } from '@kbach/ui';
|
|
125
|
-
|
|
126
|
-
export default function RootLayout({ children }) {
|
|
127
|
-
return (
|
|
128
|
-
<html lang="en">
|
|
129
|
-
<body>
|
|
130
|
-
<ThemeProvider defaultMode="system">
|
|
131
|
-
<KbachReset />
|
|
132
|
-
{children}
|
|
133
|
-
</ThemeProvider>
|
|
134
|
-
</body>
|
|
135
|
-
</html>
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
Without it, expect a flash of raw browser defaults on first paint until hydration completes. `@kbach/ui`'s compiled output ships its own `"use client"` directive, so App Router Server Components can use `className`, `styled()`, hooks, `<ThemeProvider>`, and `<KbachReset>` directly — no manual `'use client'` wrapper needed.
|
|
141
|
-
|
|
142
|
-
### React Native / Expo
|
|
143
|
-
|
|
144
|
-
Same `npm install @kbach/ui` — no separate package. Everything else (API, modifiers, color system) is the same import as web; only setup differs.
|
|
145
|
-
|
|
146
|
-
**1. babel.config.js:**
|
|
147
|
-
|
|
148
|
-
```js
|
|
149
|
-
module.exports = function (api) {
|
|
150
|
-
api.cache(true);
|
|
151
|
-
return {
|
|
152
|
-
presets: [
|
|
153
|
-
'babel-preset-expo',
|
|
154
|
-
'@kbach/ui/babel',
|
|
155
|
-
],
|
|
156
|
-
};
|
|
157
|
-
};
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Or the one-liner helper: `const { createKbachConfig } = require('@kbach/ui/native'); module.exports = createKbachConfig();`. After changing this file, clear the Metro cache: `npx expo start --clear`.
|
|
161
|
-
|
|
162
|
-
**2. Wrap your app:**
|
|
163
|
-
|
|
164
|
-
```jsx
|
|
165
|
-
import { ThemeProvider } from '@kbach/ui';
|
|
166
|
-
|
|
167
|
-
export default function App() {
|
|
168
|
-
return (
|
|
169
|
-
<ThemeProvider defaultMode="system">
|
|
170
|
-
<AppContent />
|
|
171
|
-
</ThemeProvider>
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
`ThemeProvider` auto-detects React Native at render time and reads `useColorScheme()`/`useWindowDimensions()` automatically — same import as web, no `/native` subpath needed.
|
|
177
|
-
|
|
178
|
-
A handful of utilities are native-only or web-only, and Expo Web/React Native Web has its own notes — see [KBACH.md](./KBACH.md#native-only-utilities) for the full platform-differences reference.
|
|
179
|
-
|
|
180
|
-
### Wiring a custom config in
|
|
181
|
-
|
|
182
|
-
`kbach.config.js` isn't picked up automatically — it has to be passed in explicitly, and **where** depends on what it affects:
|
|
183
|
-
|
|
184
|
-
- **Runtime** (dark mode, `useColors()`, animations) — needed by every setup above, pass it to `ThemeProvider`:
|
|
185
|
-
```jsx
|
|
186
|
-
import { ThemeProvider } from '@kbach/ui';
|
|
187
|
-
import kbachConfig from '../kbach.config';
|
|
188
|
-
|
|
189
|
-
<ThemeProvider defaultMode="system" config={kbachConfig}><App /></ThemeProvider>
|
|
190
|
-
```
|
|
191
|
-
- **Build-time** (what the Vite plugin scans against) — only for [Static CSS](#static-css), pass it to the plugin:
|
|
192
|
-
```ts
|
|
193
|
-
import { kbach } from '@kbach/ui/vite';
|
|
194
|
-
import kbachConfig from './kbach.config';
|
|
195
|
-
|
|
196
|
-
export default defineConfig({ plugins: [kbach(kbachConfig)] });
|
|
197
|
-
```
|
|
46
|
+
## Do you need this with Kbach?
|
|
198
47
|
|
|
199
|
-
|
|
48
|
+
Not really — a Kbach `className` is just a plain string, so plain
|
|
49
|
+
JavaScript already composes it fine (`"bg-" + color + '-6'`,
|
|
50
|
+
`[base, active && 'opacity-100'].join(' ')`; see
|
|
51
|
+
[`@kbach/react`](https://www.npmjs.com/package/@kbach/react)'s own README).
|
|
52
|
+
This package exists purely as an ergonomic convenience for anyone who'd
|
|
53
|
+
rather write conditional classes declaratively, and for porting code that
|
|
54
|
+
already uses `clsx`/`classnames` without adding a second dependency.
|
|
200
55
|
|
|
201
|
-
|
|
56
|
+
`@kbach/react`'s static build-time scanner already recognizes `clsx(...)`
|
|
57
|
+
call sites (alongside `cn`/`classnames`/`cx`/`kb`) and extracts every string
|
|
58
|
+
literal inside them on its own — using this function needs no extra plugin
|
|
59
|
+
configuration to keep working with the static CSS build.
|
|
202
60
|
|
|
203
|
-
|
|
61
|
+
## License
|
|
204
62
|
|
|
205
|
-
|
|
63
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny, dependency-free class-name composer — combine strings, arrays,
|
|
3
|
+
* and objects (with boolean values) into one space-separated className,
|
|
4
|
+
* skipping anything falsy. Matches the widely-used `clsx` npm package's
|
|
5
|
+
* public API and behavior exactly (a from-scratch reimplementation, not a
|
|
6
|
+
* fork or a thin wrapper around it) — Kbach ships its own copy so using it
|
|
7
|
+
* adds zero runtime dependencies, and so it works identically whether or
|
|
8
|
+
* not `clsx`/`classnames` happens to already be installed.
|
|
9
|
+
*
|
|
10
|
+
* Kbach class strings never NEED this — a Kbach `className` is just a
|
|
11
|
+
* plain string, composable with plain JS (`"bg-" + color + "-6"`,
|
|
12
|
+
* `[base, active && "opacity-100"].join(" ")`, see `@kbach/react`'s own
|
|
13
|
+
* README) with no special API required. This exists purely as an
|
|
14
|
+
* ergonomic convenience for the common "several conditional classes on one
|
|
15
|
+
* element" shape, for anyone who'd rather write it declaratively:
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* clsx("px-4 py-2", isActive && "bg-blue-6", { "opacity-50": disabled });
|
|
19
|
+
* // "px-4 py-2 bg-blue-6" (when isActive is true and disabled is false)
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* `@kbach/react`'s static build-time scanner already recognizes `clsx(...)`
|
|
23
|
+
* call sites (alongside `cn`/`classnames`/`cx`/`kb`) and extracts every
|
|
24
|
+
* string literal inside them on its own — using this function needs no
|
|
25
|
+
* extra plugin configuration to keep working with the static CSS build.
|
|
26
|
+
*/
|
|
27
|
+
/** Anything `clsx` accepts as one argument — recursively, for arrays. */
|
|
28
|
+
type ClassValue = ClassArray | ClassDictionary | string | number | bigint | boolean | null | undefined;
|
|
29
|
+
/** A key is kept (as a literal class name) only when its value is truthy — `{ "opacity-50": disabled }`. */
|
|
30
|
+
interface ClassDictionary {
|
|
31
|
+
[className: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
type ClassArray = ClassValue[];
|
|
34
|
+
/**
|
|
35
|
+
* Joins every truthy piece across all arguments with a single space,
|
|
36
|
+
* skipping falsy values (`false`, `null`, `undefined`, `0`, `""`, `NaN`)
|
|
37
|
+
* entirely — they contribute nothing, not even an extra space. Arrays are
|
|
38
|
+
* flattened (recursively, to any depth); a plain object keeps only the
|
|
39
|
+
* keys whose value is truthy.
|
|
40
|
+
*/
|
|
41
|
+
declare function clsx(...inputs: ClassValue[]): string;
|
|
42
|
+
|
|
43
|
+
export { type ClassArray, type ClassDictionary, type ClassValue, clsx, clsx as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,329 +1,43 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import React__default, { Context, ReactNode, ComponentType, ForwardRefExoticComponent } from 'react';
|
|
3
|
-
import * as __core from './core';
|
|
4
|
-
import { ThemeMode, ResolvedConfig, DefaultColorName, defaultColors, ThemeColors, DefaultSpacingKey, ThemeSpacing, FrameworkConfig, StyleValue, ResolvedStyle } from './core';
|
|
5
|
-
export { DefaultColorName, DefaultSpacingKey, FrameworkConfig, ParsedClass, PluginAPI, ResolvedConfig, ResolvedStyle, StyleValue, ThemeConfig, ThemeMode, buildConfig, clearCache, defaultColors, defaultTheme, disableRuntimeCSS, flatten, generateKbachTypesDts, getConfig, initConfig, normalizeClassString, parseClass, parseClasses, resolve, setResolveTarget, splitClassTokens, updateConfig } from './core';
|
|
6
|
-
export { r as registerWebElement } from './web-substitute-6xH1WxpZ.js';
|
|
7
|
-
|
|
8
|
-
interface ThemeContextValue {
|
|
9
|
-
/** The user-selected mode ('light' | 'dark' | 'system') */
|
|
10
|
-
mode: ThemeMode;
|
|
11
|
-
/** The effective resolved mode (never 'system') */
|
|
12
|
-
resolvedMode: 'light' | 'dark';
|
|
13
|
-
/** Convenience boolean */
|
|
14
|
-
isDark: boolean;
|
|
15
|
-
/** Change the theme mode programmatically */
|
|
16
|
-
setMode: (mode: ThemeMode) => void;
|
|
17
|
-
/** Toggle between light and dark (ignores system) */
|
|
18
|
-
toggle: () => void;
|
|
19
|
-
/** The fully resolved framework config (theme values, darkMode strategy, etc.) */
|
|
20
|
-
config: ResolvedConfig;
|
|
21
|
-
}
|
|
22
|
-
declare const ThemeContext: Context<ThemeContextValue | null>;
|
|
23
|
-
declare function useTheme(): ThemeContextValue;
|
|
24
|
-
declare function useIsDark(): boolean;
|
|
25
|
-
|
|
26
|
-
interface ColorScale {
|
|
27
|
-
/** `colors.blue[6]` → raw hex string */
|
|
28
|
-
readonly [shade: number]: string;
|
|
29
|
-
/** `colors.blue['6/50']` → shade 6 at 50% opacity */
|
|
30
|
-
readonly [key: string]: string;
|
|
31
|
-
}
|
|
32
1
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
2
|
+
* A tiny, dependency-free class-name composer — combine strings, arrays,
|
|
3
|
+
* and objects (with boolean values) into one space-separated className,
|
|
4
|
+
* skipping anything falsy. Matches the widely-used `clsx` npm package's
|
|
5
|
+
* public API and behavior exactly (a from-scratch reimplementation, not a
|
|
6
|
+
* fork or a thin wrapper around it) — Kbach ships its own copy so using it
|
|
7
|
+
* adds zero runtime dependencies, and so it works identically whether or
|
|
8
|
+
* not `clsx`/`classnames` happens to already be installed.
|
|
9
|
+
*
|
|
10
|
+
* Kbach class strings never NEED this — a Kbach `className` is just a
|
|
11
|
+
* plain string, composable with plain JS (`"bg-" + color + "-6"`,
|
|
12
|
+
* `[base, active && "opacity-100"].join(" ")`, see `@kbach/react`'s own
|
|
13
|
+
* README) with no special API required. This exists purely as an
|
|
14
|
+
* ergonomic convenience for the common "several conditional classes on one
|
|
15
|
+
* element" shape, for anyone who'd rather write it declaratively:
|
|
40
16
|
*
|
|
41
17
|
* ```ts
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* interface KbachCustomColors {
|
|
45
|
-
* primary: string; // a flat color, like the built-in `white`/`black`
|
|
46
|
-
* brand: ColorScale; // a 1–12 shade scale, like the built-in `blue`/`red`
|
|
47
|
-
* }
|
|
48
|
-
* }
|
|
18
|
+
* clsx("px-4 py-2", isActive && "bg-blue-6", { "opacity-50": disabled });
|
|
19
|
+
* // "px-4 py-2 bg-blue-6" (when isActive is true and disabled is false)
|
|
49
20
|
* ```
|
|
50
21
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
|
|
55
|
-
interface KbachCustomColors {
|
|
56
|
-
}
|
|
57
|
-
type ColorValueFor<K extends string> = K extends keyof typeof defaultColors ? (typeof defaultColors)[K] extends string ? string : ColorScale : K extends keyof KbachCustomColors ? KbachCustomColors[K] : ColorScale | string;
|
|
58
|
-
/** Every color name TypeScript knows about without an explicit type parameter: the built-in theme plus whatever's been added via the KbachCustomColors augmentation above. */
|
|
59
|
-
type KnownColorName = DefaultColorName | Extract<keyof KbachCustomColors, string>;
|
|
60
|
-
/**
|
|
61
|
-
* `ColorName` defaults to `KnownColorName` (the built-in theme's color names
|
|
62
|
-
* plus anything augmented onto `KbachCustomColors` above), so `useColors()`
|
|
63
|
-
* gets full autocomplete and typo-catching out of the box — including custom
|
|
64
|
-
* `kbach.config.js` colors, once augmented once project-wide. Without that
|
|
65
|
-
* augmentation, a project with extra colors can still widen per call instead:
|
|
66
|
-
* `useColors<DefaultColorName | 'brand'>()`.
|
|
67
|
-
*/
|
|
68
|
-
type ColorsAPI<ColorName extends string = KnownColorName> = {
|
|
69
|
-
readonly [K in ColorName]: ColorValueFor<K>;
|
|
70
|
-
} & {
|
|
71
|
-
/**
|
|
72
|
-
* Pass any CSS color through, optionally applying an opacity (0–100).
|
|
73
|
-
* - `colors.alpha('#3b82f6', 50)` → `'rgba(59,130,246,0.5)'`
|
|
74
|
-
* - `colors.alpha('rgb(0,0,0)', 10)` → `'rgba(0,0,0,0.1)'`
|
|
75
|
-
* - `colors.alpha('rgba(0,0,0,0.5)')` → `'rgba(0,0,0,0.5)'` (passthrough)
|
|
76
|
-
*/
|
|
77
|
-
readonly alpha: (color: string, opacity?: number) => string;
|
|
78
|
-
};
|
|
79
|
-
declare function wrapColors<ColorName extends string = KnownColorName>(rawColors: ThemeColors, isDark?: boolean): ColorsAPI<ColorName>;
|
|
80
|
-
declare function useColors<ColorName extends string = KnownColorName>(): ColorsAPI<ColorName>;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Empty on purpose — augment it via declaration merging so `useSpacing()`
|
|
84
|
-
* (like `useColors()`'s `KbachCustomColors`) knows about a project's
|
|
85
|
-
* `kbach.config.js` spacing keys without repeating a type parameter at every
|
|
86
|
-
* call site:
|
|
87
|
-
*
|
|
88
|
-
* ```ts
|
|
89
|
-
* import '@kbach/ui'; // or '@kbach/native'
|
|
90
|
-
* declare module '@kbach/ui' {
|
|
91
|
-
* interface KbachCustomSpacing {
|
|
92
|
-
* 18: true; // value doesn't matter — only the key is read (see SpacingAPI)
|
|
93
|
-
* }
|
|
94
|
-
* }
|
|
95
|
-
* ```
|
|
22
|
+
* `@kbach/react`'s static build-time scanner already recognizes `clsx(...)`
|
|
23
|
+
* call sites (alongside `cn`/`classnames`/`cx`/`kb`) and extracts every
|
|
24
|
+
* string literal inside them on its own — using this function needs no
|
|
25
|
+
* extra plugin configuration to keep working with the static CSS build.
|
|
96
26
|
*/
|
|
97
|
-
|
|
27
|
+
/** Anything `clsx` accepts as one argument — recursively, for arrays. */
|
|
28
|
+
type ClassValue = ClassArray | ClassDictionary | string | number | bigint | boolean | null | undefined;
|
|
29
|
+
/** A key is kept (as a literal class name) only when its value is truthy — `{ "opacity-50": disabled }`. */
|
|
30
|
+
interface ClassDictionary {
|
|
31
|
+
[className: string]: unknown;
|
|
98
32
|
}
|
|
99
|
-
|
|
100
|
-
type KnownSpacingKey = DefaultSpacingKey | Extract<keyof KbachCustomSpacing, string>;
|
|
101
|
-
/**
|
|
102
|
-
* `SpacingKey` defaults to `KnownSpacingKey` (the built-in theme's spacing keys
|
|
103
|
-
* plus anything augmented onto `KbachCustomSpacing` above), so `useSpacing()`
|
|
104
|
-
* gets full autocomplete and typo-catching out of the box — including custom
|
|
105
|
-
* `kbach.config.js` keys, once augmented once project-wide. Without that
|
|
106
|
-
* augmentation, a project with extra keys can still widen per call instead:
|
|
107
|
-
* `useSpacing<DefaultSpacingKey | '18'>()`.
|
|
108
|
-
*/
|
|
109
|
-
type SpacingAPI<SpacingKey extends string = KnownSpacingKey> = {
|
|
110
|
-
readonly [K in SpacingKey]: number | string;
|
|
111
|
-
};
|
|
112
|
-
declare function wrapSpacing<SpacingKey extends string = KnownSpacingKey>(rawSpacing: ThemeSpacing): SpacingAPI<SpacingKey>;
|
|
33
|
+
type ClassArray = ClassValue[];
|
|
113
34
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* ```ts
|
|
121
|
-
* const spacing = useSpacing();
|
|
122
|
-
* spacing[4] // 16
|
|
123
|
-
* spacing.full // '100%'
|
|
124
|
-
* spacing['1/2'] // '50%'
|
|
125
|
-
* ```
|
|
126
|
-
*/
|
|
127
|
-
declare function useSpacing<SpacingKey extends string = KnownSpacingKey>(): SpacingAPI<SpacingKey>;
|
|
128
|
-
|
|
129
|
-
interface ThemeProviderProps {
|
|
130
|
-
children: ReactNode;
|
|
131
|
-
/** Initial mode. Falls back to persisted value, then 'system'. */
|
|
132
|
-
defaultMode?: ThemeMode;
|
|
133
|
-
/**
|
|
134
|
-
* System color scheme for native `defaultMode="system"`.
|
|
135
|
-
*
|
|
136
|
-
* On React Native this is detected automatically via `useColorScheme()` —
|
|
137
|
-
* pass this prop only to override that (e.g. in tests, or Storybook).
|
|
138
|
-
*
|
|
139
|
-
* @example
|
|
140
|
-
* ```tsx
|
|
141
|
-
* <ThemeProvider defaultMode="system" colorScheme="dark">…</ThemeProvider>
|
|
142
|
-
* ```
|
|
143
|
-
*/
|
|
144
|
-
colorScheme?: 'light' | 'dark' | null;
|
|
145
|
-
/**
|
|
146
|
-
* Current window/screen width in pixels for responsive breakpoints.
|
|
147
|
-
* Detected automatically on both web (`window.innerWidth`) and React
|
|
148
|
-
* Native (`useWindowDimensions()`) — pass this prop only to override that.
|
|
149
|
-
*/
|
|
150
|
-
windowWidth?: number;
|
|
151
|
-
/** Override the config (useful for per-tree config). Defaults to global getConfig(). */
|
|
152
|
-
config?: FrameworkConfig;
|
|
153
|
-
/** Disable persistence to localStorage */
|
|
154
|
-
disablePersistence?: boolean;
|
|
155
|
-
}
|
|
156
|
-
declare function ThemeProvider({ children, defaultMode, colorScheme, windowWidth: windowWidthProp, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Renders Kbach's base browser-default reset (borderless button/input,
|
|
160
|
-
* visible checkbox/radio, no arrow-less <select>, etc.) as a plain <style>
|
|
161
|
-
* tag so it's part of the page's initial HTML.
|
|
162
|
-
*
|
|
163
|
-
* Runtime-only setups (no Vite plugin / static kbach.css) otherwise only get
|
|
164
|
-
* this reset once ThemeProvider's client-side effect runs — fine for a plain
|
|
165
|
-
* CSR app, but under SSR the server has no JS to run it, so the first paint
|
|
166
|
-
* ships with raw browser defaults (e.g. the native button border) until
|
|
167
|
-
* hydration catches up. Render this once, as high in <head> as your
|
|
168
|
-
* framework allows, to close that gap.
|
|
169
|
-
*
|
|
170
|
-
* Skips rendering entirely once disableRuntimeCSS() has fired — the Vite
|
|
171
|
-
* plugin calls it automatically wherever kbach.css gets imported (see
|
|
172
|
-
* vite-plugin.ts's transform hook), and that static file already inlines
|
|
173
|
-
* this exact reset. Previously this rendered unconditionally regardless of
|
|
174
|
-
* that flag, so an app using the static-CSS setup that ALSO keeps
|
|
175
|
-
* <KbachReset/> mounted (e.g. copied from a starter template's root layout
|
|
176
|
-
* and never revisited) got the same reset rules twice — once from the
|
|
177
|
-
* static file, once from this tag — on every single page load, real static
|
|
178
|
-
* CSS or not. Checked here (render time), not just documented, so the
|
|
179
|
-
* static setup is actually leak-free even when this stays in the tree.
|
|
180
|
-
*/
|
|
181
|
-
declare function KbachReset(): React.JSX.Element | null;
|
|
182
|
-
|
|
183
|
-
interface StyledProps {
|
|
184
|
-
/** Additional utility classes applied on top of the base classes */
|
|
185
|
-
kb?: string;
|
|
186
|
-
/** Merged with resolved kb styles; applied last */
|
|
187
|
-
style?: StyleValue | StyleValue[];
|
|
188
|
-
}
|
|
189
|
-
type OmittedKeys = 'style';
|
|
190
|
-
/**
|
|
191
|
-
* Create a styled component from any React / React Native component.
|
|
192
|
-
*
|
|
193
|
-
* ```tsx
|
|
194
|
-
* const Card = styled(View, 'bg-white dark:bg-gray-9 rounded-xl p-4 shadow-md');
|
|
195
|
-
* const Button = styled(TouchableOpacity, 'bg-blue-6 pressed:bg-blue-8 dark:bg-blue-7 rounded-lg p-3');
|
|
196
|
-
*
|
|
197
|
-
* // Use it:
|
|
198
|
-
* <Card kb="mt-4">...</Card>
|
|
199
|
-
* <Button onPress={handlePress} kb="w-full" />
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
declare function styled<T extends ComponentType<any>>(Component: T, baseClasses?: string): ForwardRefExoticComponent<Omit<React__default.ComponentPropsWithRef<T>, OmittedKeys> & StyledProps>;
|
|
203
|
-
|
|
204
|
-
interface InteractionState {
|
|
205
|
-
hover?: boolean;
|
|
206
|
-
focus?: boolean;
|
|
207
|
-
/** Maps to 'pressed' and 'active' modifiers */
|
|
208
|
-
pressed?: boolean;
|
|
209
|
-
active?: boolean;
|
|
210
|
-
disabled?: boolean;
|
|
211
|
-
checked?: boolean;
|
|
212
|
-
visited?: boolean;
|
|
213
|
-
placeholder?: boolean;
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Resolve a utility class string to a style object for the current theme + state.
|
|
217
|
-
*
|
|
218
|
-
* ```tsx
|
|
219
|
-
* // Basic usage
|
|
220
|
-
* const styles = useStyles('bg-white dark:bg-gray-9 p-4');
|
|
221
|
-
*
|
|
222
|
-
* // With interaction state
|
|
223
|
-
* const [pressed, setPressed] = useState(false);
|
|
224
|
-
* const styles = useStyles('bg-blue-6 pressed:bg-blue-8', { pressed });
|
|
225
|
-
*
|
|
226
|
-
* // Multiple class strings (merged left-to-right)
|
|
227
|
-
* const styles = useStyles(['bg-white p-4', 'dark:bg-gray-9 rounded-xl']);
|
|
228
|
-
* ```
|
|
229
|
-
*/
|
|
230
|
-
declare function useStyles(classString: string | string[], state?: InteractionState): StyleValue;
|
|
231
|
-
/**
|
|
232
|
-
* Returns the full ResolvedStyle bucket map (base, dark, hover, …).
|
|
233
|
-
* Useful when you need to apply styles selectively or pass them to Animated.
|
|
234
|
-
*/
|
|
235
|
-
declare function useResolvedStyle(classString: string | string[]): __core.ResolvedStyle;
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Subscribe to the global dark-mode store with React's concurrent-safe
|
|
239
|
-
* useSyncExternalStore so that any component using className/kb re-renders
|
|
240
|
-
* immediately when the theme changes — without needing ThemeContext.
|
|
241
|
-
*/
|
|
242
|
-
declare function useGlobalDarkMode(): boolean;
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Returns the name of the currently active breakpoint — the largest breakpoint
|
|
246
|
-
* whose min-width the window satisfies, or `'xs'` when below all breakpoints.
|
|
247
|
-
*
|
|
248
|
-
* ```ts
|
|
249
|
-
* const bp = useBreakpoint(); // 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
|
|
250
|
-
* ```
|
|
251
|
-
*/
|
|
252
|
-
declare function useBreakpoint(): string;
|
|
253
|
-
/**
|
|
254
|
-
* Returns a record of boolean flags for each breakpoint — `true` when the
|
|
255
|
-
* window width satisfies that breakpoint's min-width threshold.
|
|
256
|
-
*
|
|
257
|
-
* ```ts
|
|
258
|
-
* const { sm, md, lg } = useResponsive();
|
|
259
|
-
* const padding = lg ? 32 : sm ? 16 : 8;
|
|
260
|
-
* ```
|
|
261
|
-
*/
|
|
262
|
-
declare function useResponsive(): Record<string, boolean>;
|
|
263
|
-
|
|
264
|
-
interface InteractiveWrapperProps {
|
|
265
|
-
/** The real component to render (View, TouchableOpacity, div, a third-party button…) */
|
|
266
|
-
Component: React__default.ComponentType<any> | string;
|
|
267
|
-
/** Pre-resolved style buckets from resolve() */
|
|
268
|
-
resolvedStyle: ResolvedStyle;
|
|
269
|
-
/** On web: original class string so CSS pseudo-rules still fire */
|
|
270
|
-
className?: string;
|
|
271
|
-
/** Extra style prop passed by the user */
|
|
272
|
-
style?: StyleValue | StyleValue[];
|
|
273
|
-
children?: React__default.ReactNode;
|
|
274
|
-
onPressIn?: (...args: any[]) => void;
|
|
275
|
-
onPressOut?: (...args: any[]) => void;
|
|
276
|
-
onPointerDown?: (...args: any[]) => void;
|
|
277
|
-
onPointerUp?: (...args: any[]) => void;
|
|
278
|
-
onPointerLeave?: (...args: any[]) => void;
|
|
279
|
-
onPointerCancel?: (...args: any[]) => void;
|
|
280
|
-
onMouseEnter?: (...args: any[]) => void;
|
|
281
|
-
onMouseLeave?: (...args: any[]) => void;
|
|
282
|
-
onFocus?: (...args: any[]) => void;
|
|
283
|
-
onBlur?: (...args: any[]) => void;
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Thin wrapper rendered automatically by the JSX runtime whenever a className/kb
|
|
287
|
-
* string contains interactive modifiers (hover:, pressed:, focus:, active:, …).
|
|
288
|
-
*
|
|
289
|
-
* Manages interaction state locally and flattens the correct style bucket on
|
|
290
|
-
* every render. The wrapped component sees a plain `style` prop — it never
|
|
291
|
-
* knows it was wrapped.
|
|
292
|
-
*
|
|
293
|
-
* Refs are forwarded so the host component's imperative API still works.
|
|
294
|
-
*/
|
|
295
|
-
declare const InteractiveWrapper: React__default.ForwardRefExoticComponent<InteractiveWrapperProps & React__default.RefAttributes<unknown>>;
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Resolve a utility class string outside of a React component.
|
|
299
|
-
*
|
|
300
|
-
* On **native** — returns a StyleValue (style object) for the given mode.
|
|
301
|
-
* On **web** — injects CSS and returns the original class string (use as className).
|
|
302
|
-
*
|
|
303
|
-
* ```ts
|
|
304
|
-
* // Inside a component use useStyles() instead.
|
|
305
|
-
* // kb() is useful for StyleSheet.create() calls and static values.
|
|
306
|
-
*
|
|
307
|
-
* const styles = StyleSheet.create({
|
|
308
|
-
* container: kb('flex-1 bg-white p-4') as any,
|
|
309
|
-
* });
|
|
310
|
-
*
|
|
311
|
-
* // Web: use as className
|
|
312
|
-
* <div className={kb('bg-white dark:bg-gray-9 p-4') as string} />
|
|
313
|
-
* ```
|
|
314
|
-
*
|
|
315
|
-
* @param classString Space-separated utility classes
|
|
316
|
-
* @param isDark Whether dark mode is active (default: false)
|
|
317
|
-
*/
|
|
318
|
-
declare function kb(classString: string, isDark?: boolean): StyleValue | string;
|
|
319
|
-
/**
|
|
320
|
-
* Conditionally join class names. Falsy values are ignored.
|
|
321
|
-
*
|
|
322
|
-
* ```ts
|
|
323
|
-
* cx('bg-white p-4', isActive && 'border-2 border-blue-6', undefined)
|
|
324
|
-
* // → 'bg-white p-4 border-2 border-blue-6'
|
|
325
|
-
* ```
|
|
35
|
+
* Joins every truthy piece across all arguments with a single space,
|
|
36
|
+
* skipping falsy values (`false`, `null`, `undefined`, `0`, `""`, `NaN`)
|
|
37
|
+
* entirely — they contribute nothing, not even an extra space. Arrays are
|
|
38
|
+
* flattened (recursively, to any depth); a plain object keeps only the
|
|
39
|
+
* keys whose value is truthy.
|
|
326
40
|
*/
|
|
327
|
-
declare function
|
|
41
|
+
declare function clsx(...inputs: ClassValue[]): string;
|
|
328
42
|
|
|
329
|
-
export { type
|
|
43
|
+
export { type ClassArray, type ClassDictionary, type ClassValue, clsx, clsx as default };
|