@renge-ui/react 1.0.0 → 1.0.2
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 +248 -29
- package/package.json +14 -5
package/README.md
CHANGED
|
@@ -10,14 +10,14 @@ pnpm add @renge-ui/react
|
|
|
10
10
|
|
|
11
11
|
## Setup
|
|
12
12
|
|
|
13
|
-
Wrap your app in `RengeProvider`. It injects the generated CSS variables into `<head>` automatically
|
|
13
|
+
Wrap your app in `RengeProvider`. It injects the generated CSS variables into `<head>` automatically via `useInsertionEffect`.
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
16
|
import { RengeProvider } from '@renge-ui/react';
|
|
17
17
|
|
|
18
18
|
function App() {
|
|
19
19
|
return (
|
|
20
|
-
<RengeProvider config={{ profile: 'ocean' }}>
|
|
20
|
+
<RengeProvider config={{ profile: 'ocean', mode: 'light' }}>
|
|
21
21
|
<YourApp />
|
|
22
22
|
</RengeProvider>
|
|
23
23
|
);
|
|
@@ -37,13 +37,13 @@ function App() {
|
|
|
37
37
|
|
|
38
38
|
### `useRenge()`
|
|
39
39
|
|
|
40
|
-
Returns the current theme and profile from context. Must be
|
|
40
|
+
Returns the current theme and profile from context. Must be inside `RengeProvider`.
|
|
41
41
|
|
|
42
42
|
```tsx
|
|
43
43
|
const { theme, profile } = useRenge();
|
|
44
44
|
// theme.vars['--renge-color-accent']
|
|
45
45
|
// theme.css → full CSS string
|
|
46
|
-
// profile → 'ocean' | 'earth' | 'twilight'
|
|
46
|
+
// profile → 'ocean' | 'earth' | 'twilight' | 'fire' | 'void' | 'leaf'
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
### `useRengeTheme(config?)`
|
|
@@ -51,7 +51,7 @@ const { theme, profile } = useRenge();
|
|
|
51
51
|
Creates a theme without a provider — useful for SSR or static export.
|
|
52
52
|
|
|
53
53
|
```tsx
|
|
54
|
-
const theme = useRengeTheme({ profile: 'twilight' });
|
|
54
|
+
const theme = useRengeTheme({ profile: 'twilight', mode: 'dark' });
|
|
55
55
|
// Inject theme.css server-side, or pass to a <style> tag
|
|
56
56
|
```
|
|
57
57
|
|
|
@@ -59,9 +59,13 @@ const theme = useRengeTheme({ profile: 'twilight' });
|
|
|
59
59
|
|
|
60
60
|
## Components
|
|
61
61
|
|
|
62
|
-
All components use `forwardRef`, accept all standard HTML props for their underlying element, and allow style overrides via the `style` prop. Most support a polymorphic `as` prop to change the rendered element.
|
|
62
|
+
All components use `forwardRef`, accept all standard HTML props for their underlying element, and allow style overrides via the `style` prop (applied last — overrides always win). Most support a polymorphic `as` prop to change the rendered element.
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### Layout
|
|
67
|
+
|
|
68
|
+
#### `Stack`
|
|
65
69
|
|
|
66
70
|
Flexbox layout container.
|
|
67
71
|
|
|
@@ -80,7 +84,7 @@ Flexbox layout container.
|
|
|
80
84
|
| `justify` | `'start' \| 'center' \| 'end' \| 'between' \| 'around'` | `'start'` |
|
|
81
85
|
| `as` | `ElementType` | `'div'` |
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
#### `Grid`
|
|
84
88
|
|
|
85
89
|
CSS Grid layout container.
|
|
86
90
|
|
|
@@ -102,7 +106,30 @@ CSS Grid layout container.
|
|
|
102
106
|
| `align` | `'start' \| 'center' \| 'end' \| 'stretch'` | `'stretch'` |
|
|
103
107
|
| `justify` | `'start' \| 'center' \| 'end' \| 'stretch'` | `'stretch'` |
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
#### `Section`
|
|
110
|
+
|
|
111
|
+
Page section with max-width constraint and auto-centering.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
<Section maxWidth="lg" paddingY="8">
|
|
115
|
+
<Heading>Welcome</Heading>
|
|
116
|
+
</Section>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Prop | Type | Default |
|
|
120
|
+
|------|------|---------|
|
|
121
|
+
| `maxWidth` | `'sm' \| 'md' \| 'lg' \| 'xl' \| 'full' \| 'none'` | `'lg'` |
|
|
122
|
+
| `padding` | `'0'–'8'` | — |
|
|
123
|
+
| `paddingX` | `'0'–'8'` | `'4'` |
|
|
124
|
+
| `paddingY` | `'0'–'8'` | `'6'` |
|
|
125
|
+
| `center` | `boolean` | `true` |
|
|
126
|
+
| `as` | `ElementType` | `'section'` |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### Text
|
|
131
|
+
|
|
132
|
+
#### `Text`
|
|
106
133
|
|
|
107
134
|
Inline or block text with token-driven sizing.
|
|
108
135
|
|
|
@@ -120,7 +147,7 @@ Inline or block text with token-driven sizing.
|
|
|
120
147
|
| `align` | `'left' \| 'center' \| 'right'` | — |
|
|
121
148
|
| `as` | `ElementType` | `'span'` |
|
|
122
149
|
|
|
123
|
-
|
|
150
|
+
#### `Heading`
|
|
124
151
|
|
|
125
152
|
Semantic heading with automatic size defaults per level.
|
|
126
153
|
|
|
@@ -135,9 +162,13 @@ Semantic heading with automatic size defaults per level.
|
|
|
135
162
|
| `size` | `'lg' \| 'xl' \| '2xl' \| '3xl' \| '4xl'` | auto (level-based) |
|
|
136
163
|
| `color` | `'fg' \| 'fg-subtle' \| 'accent'` | `'fg'` |
|
|
137
164
|
|
|
138
|
-
Default sizes
|
|
165
|
+
Default sizes: h1→3xl, h2→2xl, h3→xl, h4–h6→lg.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### Containers
|
|
139
170
|
|
|
140
|
-
|
|
171
|
+
#### `Card`
|
|
141
172
|
|
|
142
173
|
Content container with three visual variants.
|
|
143
174
|
|
|
@@ -153,7 +184,11 @@ Content container with three visual variants.
|
|
|
153
184
|
| `padding` | `'0'–'6'` | `'4'` |
|
|
154
185
|
| `radius` | `'none' \| '1'–'5' \| 'full'` | `'3'` |
|
|
155
186
|
|
|
156
|
-
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### Interactive
|
|
190
|
+
|
|
191
|
+
#### `Button`
|
|
157
192
|
|
|
158
193
|
```tsx
|
|
159
194
|
<Button variant="outline" colorScheme="danger" size="sm">
|
|
@@ -168,7 +203,61 @@ Content container with three visual variants.
|
|
|
168
203
|
| `colorScheme` | `'accent' \| 'danger' \| 'success'` | `'accent'` |
|
|
169
204
|
| `fullWidth` | `boolean` | `false` |
|
|
170
205
|
|
|
171
|
-
|
|
206
|
+
#### `Input`
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
<Input size="md" state="error" fullWidth placeholder="Enter email..." />
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
| Prop | Type | Default |
|
|
213
|
+
|------|------|---------|
|
|
214
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
|
215
|
+
| `state` | `'default' \| 'error' \| 'success'` | `'default'` |
|
|
216
|
+
| `fullWidth` | `boolean` | `false` |
|
|
217
|
+
|
|
218
|
+
Note: `Input` uses `Omit<ComponentPropsWithoutRef<'input'>, 'size'>` to shadow the native `size: number` attribute with the semantic size prop.
|
|
219
|
+
|
|
220
|
+
Focus ring is applied via `onFocus`/`onBlur` handlers (inline styles cannot target `:focus-visible`). The outline uses `--renge-color-border-focus`.
|
|
221
|
+
|
|
222
|
+
#### `Chip`
|
|
223
|
+
|
|
224
|
+
Small inline tag — dismissible or selectable.
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
<Chip>Design systems</Chip>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### Status & Decoration
|
|
233
|
+
|
|
234
|
+
#### `Badge`
|
|
235
|
+
|
|
236
|
+
Label badge with semantic color variants.
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
<Badge variant="success" size="sm">Active</Badge>
|
|
240
|
+
<Badge variant="danger">Deprecated</Badge>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Prop | Type | Default |
|
|
244
|
+
|------|------|---------|
|
|
245
|
+
| `variant` | `'accent' \| 'success' \| 'warning' \| 'danger' \| 'info' \| 'neutral'` | `'neutral'` |
|
|
246
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
|
247
|
+
|
|
248
|
+
#### `Alert`
|
|
249
|
+
|
|
250
|
+
Alert message with status-driven color.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
<Alert status="warning">Variance is enabled.</Alert>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Prop | Type | Default |
|
|
257
|
+
|------|------|---------|
|
|
258
|
+
| `status` | `'success' \| 'warning' \| 'danger' \| 'info'` | `'info'` |
|
|
259
|
+
|
|
260
|
+
#### `Divider`
|
|
172
261
|
|
|
173
262
|
```tsx
|
|
174
263
|
<Divider spacing="5" />
|
|
@@ -181,24 +270,115 @@ Content container with three visual variants.
|
|
|
181
270
|
| `spacing` | `'0'–'6'` | `'3'` |
|
|
182
271
|
| `color` | `'border' \| 'border-subtle'` | `'border-subtle'` |
|
|
183
272
|
|
|
184
|
-
|
|
273
|
+
#### `Spinner`
|
|
185
274
|
|
|
186
|
-
|
|
275
|
+
Loading indicator. Injects `@keyframes rengeSpinnerSpin` once at module load.
|
|
187
276
|
|
|
188
277
|
```tsx
|
|
189
|
-
<
|
|
190
|
-
<Heading>Welcome</Heading>
|
|
191
|
-
</Section>
|
|
278
|
+
<Spinner size="md" />
|
|
192
279
|
```
|
|
193
280
|
|
|
194
281
|
| Prop | Type | Default |
|
|
195
282
|
|------|------|---------|
|
|
196
|
-
| `
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
283
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
|
284
|
+
|
|
285
|
+
#### `Progress`
|
|
286
|
+
|
|
287
|
+
Progress bar.
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
<Progress value={65} size="md" />
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
| Prop | Type | Default |
|
|
294
|
+
|------|------|---------|
|
|
295
|
+
| `value` | `number` (0–100) | `0` |
|
|
296
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
|
297
|
+
|
|
298
|
+
#### `Avatar`
|
|
299
|
+
|
|
300
|
+
User avatar with size and shape options.
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
<Avatar src="/photo.jpg" alt="Vanessa" size="lg" shape="circle" />
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
| Prop | Type | Default |
|
|
307
|
+
|------|------|---------|
|
|
308
|
+
| `size` | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` |
|
|
309
|
+
| `shape` | `'circle' \| 'square'` | `'circle'` |
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
### Forms
|
|
314
|
+
|
|
315
|
+
#### `FormField`
|
|
316
|
+
|
|
317
|
+
Label + input wrapper with consistent spacing.
|
|
318
|
+
|
|
319
|
+
```tsx
|
|
320
|
+
<FormField label="Email" required>
|
|
321
|
+
<Input placeholder="you@example.com" />
|
|
322
|
+
</FormField>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### `Stat`
|
|
326
|
+
|
|
327
|
+
Metric display with optional trend direction.
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
<Stat label="Active users" value="1,284" trend="up" delta="+12%" />
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### Navigation
|
|
336
|
+
|
|
337
|
+
#### `Navbar`
|
|
338
|
+
|
|
339
|
+
Navigation bar primitive. Handles sticky positioning and border.
|
|
340
|
+
|
|
341
|
+
```tsx
|
|
342
|
+
<Navbar sticky border paddingX="5">
|
|
343
|
+
<Logo />
|
|
344
|
+
<Stack direction="horizontal" gap="4">
|
|
345
|
+
<a href="/docs">Docs</a>
|
|
346
|
+
</Stack>
|
|
347
|
+
</Navbar>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
| Prop | Type | Default |
|
|
351
|
+
|------|------|---------|
|
|
352
|
+
| `sticky` | `boolean` | `false` |
|
|
353
|
+
| `border` | `boolean` | `true` |
|
|
354
|
+
| `height` | `string` | `'56px'` |
|
|
355
|
+
| `paddingX` | `'0'–'8'` | `'5'` |
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### Experimental
|
|
360
|
+
|
|
361
|
+
These components are functional but not yet stabilized — APIs may change.
|
|
362
|
+
|
|
363
|
+
#### `EnergyRing`
|
|
364
|
+
|
|
365
|
+
Animated pulsing ring. Useful for loading states or ambient indicators.
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
<EnergyRing size={48} rate="slow" color="accent" />
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### `Pulse`
|
|
372
|
+
|
|
373
|
+
Pulsing animation wrapper.
|
|
374
|
+
|
|
375
|
+
```tsx
|
|
376
|
+
<Pulse rate="medium" color="success"><StatusDot /></Pulse>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
#### `FlowField`
|
|
380
|
+
|
|
381
|
+
Animated flow-field canvas visualization. Accepts energy intensity and color profile.
|
|
202
382
|
|
|
203
383
|
---
|
|
204
384
|
|
|
@@ -209,16 +389,55 @@ Use `injectCSS={false}` and inject the CSS string server-side:
|
|
|
209
389
|
```tsx
|
|
210
390
|
import { createRengeTheme } from '@renge-ui/tokens';
|
|
211
391
|
|
|
212
|
-
// Server
|
|
213
|
-
const theme = createRengeTheme({ profile: 'ocean' });
|
|
392
|
+
// Server — generate CSS for all profiles you need
|
|
393
|
+
const theme = createRengeTheme({ profile: 'ocean', mode: 'light' });
|
|
214
394
|
// Embed theme.css in your HTML <head>
|
|
215
395
|
|
|
216
|
-
// Client
|
|
217
|
-
<RengeProvider config={{ profile: 'ocean' }} injectCSS={false}>
|
|
396
|
+
// Client — match profile to avoid re-injecting
|
|
397
|
+
<RengeProvider config={{ profile: 'ocean', mode: 'light' }} injectCSS={false}>
|
|
218
398
|
<App />
|
|
219
399
|
</RengeProvider>
|
|
220
400
|
```
|
|
221
401
|
|
|
402
|
+
For multi-profile support (profile switcher), generate CSS for each profile using `data-profile` attribute selectors and inject all of them at build time. See `apps/lib/tokens.ts` in the monorepo for a reference implementation.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Architecture
|
|
407
|
+
|
|
408
|
+
Components have no opinions about class names, CSS files, or external stylesheets. Every visual decision is an inline `style` referencing a `--renge-*` CSS custom property. This means:
|
|
409
|
+
|
|
410
|
+
- Components work anywhere the token CSS is injected — React, Remix, Next.js, plain HTML.
|
|
411
|
+
- Overrides are always via the `style` prop. No specificity battles.
|
|
412
|
+
- Bundle output contains no CSS. Zero style conflicts with your existing stylesheet.
|
|
413
|
+
|
|
414
|
+
The rendering chain is:
|
|
415
|
+
|
|
416
|
+
```
|
|
417
|
+
createRengeTheme() → theme.css → injected into <head>
|
|
418
|
+
↓
|
|
419
|
+
CSS custom properties on :root
|
|
420
|
+
↓
|
|
421
|
+
Components read var(--renge-*) via inline styles
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Trade-offs
|
|
427
|
+
|
|
428
|
+
**No pseudo-class support.** Inline styles cannot target `:hover`, `:focus-visible`, `:disabled`, etc. This is the main limitation of the inline-styles approach. Workarounds:
|
|
429
|
+
|
|
430
|
+
- Focus rings use `onFocus`/`onBlur` JS handlers (see `Input`).
|
|
431
|
+
- Hover states are not currently implemented in primitives — add them via the `style` prop + event handlers in your application layer, or override with a CSS class.
|
|
432
|
+
|
|
433
|
+
**No class names means no CSS-level overrides.** You can't write `.my-button { ... }` to target a Renge component in a stylesheet. Use the `style` prop or wrap the component and override via a parent selector.
|
|
434
|
+
|
|
435
|
+
**`Spinner` injects keyframes at module load** via a module-level DOM insertion. This happens once per import, regardless of how many `Spinner` instances are rendered. It is not part of the Renge theme CSS — it lives outside the token system because CSS custom properties cannot animate `transform`.
|
|
436
|
+
|
|
437
|
+
**Single provider scope.** `RengeProvider` sets one theme for the entire subtree. If you need different themes in different parts of the tree, nest multiple `RengeProvider` instances — but note that the outermost provider's `injectCSS` behavior will apply globally unless scoped via the `selector` config option.
|
|
438
|
+
|
|
439
|
+
**Experimental components have unstable APIs.** `EnergyRing`, `Pulse`, and `FlowField` are included but not covered by the stability guarantee. Their props will likely change before v1.
|
|
440
|
+
|
|
222
441
|
---
|
|
223
442
|
|
|
224
443
|
## Development
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@renge-ui/react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "React component primitives for the Renge design system.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -12,23 +12,32 @@
|
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"files": [
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
16
18
|
"scripts": {
|
|
17
19
|
"build": "tsup",
|
|
18
20
|
"dev": "tsup --watch",
|
|
19
21
|
"typecheck": "tsc --noEmit"
|
|
20
22
|
},
|
|
21
|
-
"keywords": [
|
|
23
|
+
"keywords": [
|
|
24
|
+
"design-system",
|
|
25
|
+
"react",
|
|
26
|
+
"components",
|
|
27
|
+
"golden-ratio"
|
|
28
|
+
],
|
|
22
29
|
"author": "Vanessa Martin",
|
|
23
30
|
"license": "MIT",
|
|
24
|
-
"publishConfig": {
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
25
34
|
"repository": {
|
|
26
35
|
"type": "git",
|
|
27
36
|
"url": "https://github.com/vsm1996/renge-ui"
|
|
28
37
|
},
|
|
29
38
|
"packageManager": "pnpm@10.30.2",
|
|
30
39
|
"dependencies": {
|
|
31
|
-
"@renge-ui/tokens": "
|
|
40
|
+
"@renge-ui/tokens": "^1.0.3"
|
|
32
41
|
},
|
|
33
42
|
"peerDependencies": {
|
|
34
43
|
"react": "^18.0.0 || ^19.0.0",
|