@ryanhelsing/ry-ui 1.0.3 → 1.0.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/AGENT.md ADDED
@@ -0,0 +1,460 @@
1
+ # ry-ui — Agent Reference
2
+
3
+ > Framework-agnostic Light DOM web components. CSS is the source of truth.
4
+ > This file is for AI agents building apps with ry-ui.
5
+
6
+ ## Quick Start
7
+
8
+ ```html
9
+ <!-- CDN (full bundle) -->
10
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/css/ry-ui.css">
11
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/ry-ui.js"></script>
12
+
13
+ <!-- Or individual layers (for custom themes) -->
14
+ <link rel="stylesheet" href="ry-tokens.css">
15
+ <link rel="stylesheet" href="ry-structure.css">
16
+ <link rel="stylesheet" href="your-theme.css">
17
+ ```
18
+
19
+ ## Clean Syntax
20
+
21
+ Wrap markup in `<ry>` to use unprefixed tags:
22
+
23
+ ```html
24
+ <ry>
25
+ <accordion>
26
+ <accordion-item title="FAQ" open>No ry- prefix needed.</accordion-item>
27
+ </accordion>
28
+ </ry>
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Component Catalog
34
+
35
+ ### Layout (CSS-only, no JS)
36
+
37
+ | Component | Attributes | Description |
38
+ |-----------|-----------|-------------|
39
+ | `<ry-page>` | — | Root page container, flex column, min-height 100dvh, container queries |
40
+ | `<ry-header>` | `sticky` | Flex row, space-between. `sticky` pins to top |
41
+ | `<ry-main>` | — | Content area, max-width 1200px, centered |
42
+ | `<ry-footer>` | — | Footer with border-top |
43
+ | `<ry-section>` | — | Block section with bottom margin, container queries |
44
+ | `<ry-grid>` | `cols="1-6\|auto-fit\|auto-fill"`, `cols-sm="1-3"`, `cols-md="1-4"`, `cols-lg="2-6"` | CSS grid. See [Grid](#grid) |
45
+ | `<ry-stack>` | `gap="sm\|md\|lg\|xl"` | Vertical flex column |
46
+ | `<ry-cluster>` | `gap="sm\|md\|lg"` | Horizontal flex row, wraps |
47
+ | `<ry-split>` | `resizable`, `persist="key"`, CSS vars: `--ry-split-width`, `--ry-split-min-width`, `--ry-split-max-width` | Two-column: flex-1 left + fixed right. Stacks on mobile. Optional drag resize + localStorage persistence |
48
+ | `<ry-center>` | — | Flex center (both axes) |
49
+ | `<ry-nav>` | — | Horizontal nav links. Active: `a[aria-current="page"]` |
50
+ | `<ry-logo>` | — | Inline-flex, bold text |
51
+ | `<ry-actions>` | — | Flex row for action buttons |
52
+ | `<ry-divider>` | `vertical` | Horizontal line; `vertical` for inline separator |
53
+ | `<ry-aside>` | — | Sidebar content area |
54
+
55
+ ### Interactive Components
56
+
57
+ | Component | Key Attributes | Events |
58
+ |-----------|---------------|--------|
59
+ | `<ry-button>` | `variant="primary\|secondary\|outline\|ghost\|danger\|accent"`, `size="sm\|lg"`, `disabled`, `pressed`, `icon`, `modal="id"` | `ry:click` |
60
+ | `<ry-button-group>` | `name`, `value` | `ry:change` `{value}` — radio-group behavior for child buttons |
61
+ | `<ry-toggle-button>` | `pressed`, `name`, `value`, `size`, `icon`, `block`, `disabled` | `ry:change` `{pressed, value}` |
62
+ | `<ry-modal>` | `id`, `title` | Trigger with `<ry-button modal="id">`. Centered with backdrop |
63
+ | `<ry-drawer>` | `id`, `position="left\|right"`, `size` | Trigger with `<ry-button drawer="id">` |
64
+ | `<ry-accordion>` | — | Container for accordion-items |
65
+ | `<ry-accordion-item>` | `title`, `open` | Collapsible section |
66
+ | `<ry-tabs>` | — | Container. Children: `<ry-tab title="...">content</ry-tab>` |
67
+ | `<ry-dropdown>` | — | Dropdown trigger + menu |
68
+ | `<ry-select>` | `placeholder`, `name`, `value`, `disabled` | `ry:change` `{value}`. Children: `<ry-option value="...">` |
69
+ | `<ry-switch>` | `checked`, `disabled`, `name` | `ry:change` `{checked}` |
70
+ | `<ry-tooltip>` | `content`, `position` | Hover tooltip |
71
+ | `<ry-toast>` | — | Programmatic: `RyToast.success('msg')`, `.error()`, `.warning()`, `.info()` |
72
+ | `<ry-slider>` | `min`, `max`, `step`, `value`, `color`, `disabled` | `ry:change` `{value}` |
73
+ | `<ry-knob>` | `min`, `max`, `step`, `value`, `color`, `size`, `disabled` | `ry:change` `{value}` |
74
+ | `<ry-number-select>` | `min`, `max`, `step`, `value`, `arrows`, `size`, `prefix`, `suffix`, `label` | `ry:change` `{value}` |
75
+ | `<ry-color-picker>` | `value`, `format` | `ry:change` `{value}` |
76
+ | `<ry-color-input>` | `value`, `format` | `ry:change` `{value}` |
77
+ | `<ry-gradient-picker>` | `value` | `ry:change` `{value}` |
78
+ | `<ry-tree>` | `data` (JSON) | `ry:select`, `ry:move` — file tree with drag-and-drop |
79
+ | `<ry-tag>` | `removable` | `ry:remove` |
80
+ | `<ry-tag-input>` | `name`, `value`, `placeholder` | `ry:change` `{tags}` |
81
+ | `<ry-carousel>` | `autoplay`, `interval` | `ry:change` `{index}` |
82
+ | `<ry-theme-toggle>` | `themes="light,dark"` | Cycles through themes |
83
+
84
+ ### Display Components
85
+
86
+ | Component | Key Attributes | Description |
87
+ |-----------|---------------|-------------|
88
+ | `<ry-card>` | — | Bordered card with padding. Put any content inside |
89
+ | `<ry-badge>` | `variant="primary\|success\|warning\|danger\|accent"` | Pill badge. Arbitrary color: `style="--ry-badge-color: #8B5CF6"` |
90
+ | `<ry-alert>` | `type="info\|success\|warning\|danger"` | Alert box with optional `[slot="title"]` |
91
+ | `<ry-field>` | `label`, `error`, `hint` | Form field wrapper. See [Forms](#forms) |
92
+ | `<ry-icon>` | `name` | SVG icon from registry |
93
+ | `<ry-code>` | `language`, `title` | Syntax-highlighted code block |
94
+ | `<ry-hero>` | `size="sm\|lg"`, `full-bleed`, `align="left"` | Marketing hero section. Children: h1, p, buttons |
95
+ | `<ry-stat>` | `size="sm\|lg"` | Stat card with `slot="value"`, `slot="label"`, trend arrows |
96
+ | `<ry-feature>` | `icon` | Feature card with icon from registry |
97
+ | `<ry-feature-grid>` | `cols="2\|3\|4"` | Responsive grid for feature cards |
98
+ | `<ry-pricing>` | — | Container for pricing cards (flex row, responsive) |
99
+ | `<ry-pricing-card>` | `featured` | Pricing tier card. `featured` scales up with bold border |
100
+
101
+ ---
102
+
103
+ ## Patterns
104
+
105
+ ### Grid
106
+
107
+ ```html
108
+ <!-- Fixed columns with auto-responsive -->
109
+ <ry-grid cols="3">...</ry-grid>
110
+ <!-- cols 3-6 → 2 at ≤1024px → 1 at ≤640px (automatic) -->
111
+
112
+ <!-- Explicit per-breakpoint -->
113
+ <ry-grid cols="5" cols-md="3" cols-sm="1">...</ry-grid>
114
+
115
+ <!-- Fluid auto-fit (like repeat(auto-fit, minmax(280px, 1fr))) -->
116
+ <ry-grid cols="auto-fit">...</ry-grid>
117
+
118
+ <!-- Custom min-width for auto-fit -->
119
+ <ry-grid cols="auto-fit" style="--ry-grid-min: 240px">...</ry-grid>
120
+ ```
121
+
122
+ ### Split Layout
123
+
124
+ ```html
125
+ <!-- Default 300px sidebar -->
126
+ <ry-split>
127
+ <div>Main content</div>
128
+ <div>Sidebar</div>
129
+ </ry-split>
130
+
131
+ <!-- Custom width -->
132
+ <ry-split style="--ry-split-width: 600px; --ry-split-min-width: 400px">
133
+ <div>Main</div>
134
+ <div>Panel</div>
135
+ </ry-split>
136
+
137
+ <!-- Resizable with persistence -->
138
+ <ry-split resizable persist="my-panel" style="--ry-split-width: 400px">
139
+ <div>Main</div>
140
+ <div>Resizable panel — drag handle, keyboard arrows, double-click to reset</div>
141
+ </ry-split>
142
+ ```
143
+
144
+ Split resize features:
145
+ - **Drag handle** between panes (mouse + touch)
146
+ - **Keyboard**: Arrow keys (±10px), Shift+Arrow (±50px), Home/End for min/max
147
+ - **Double-click** handle to reset to default width
148
+ - **`persist="key"`**: Saves width to `localStorage` as `ry-split:key`, restores on load
149
+ - **`ry:resize`** event fires with `{ width }` after drag ends
150
+
151
+ ### Forms
152
+
153
+ ```html
154
+ <ry-field label="Email" hint="We'll never share your email">
155
+ <input type="email" placeholder="you@example.com">
156
+ </ry-field>
157
+
158
+ <ry-field label="Password" error="Must be at least 8 characters">
159
+ <input type="password">
160
+ </ry-field>
161
+
162
+ <!-- Error hides hint automatically. Set error="" to clear and show hint again. -->
163
+ ```
164
+
165
+ ### Button Group (Segmented Control)
166
+
167
+ ```html
168
+ <!-- Radio-group behavior -->
169
+ <ry-button-group name="billing" value="monthly">
170
+ <ry-button value="monthly">Monthly</ry-button>
171
+ <ry-button value="annually">Annually</ry-button>
172
+ </ry-button-group>
173
+
174
+ <!-- Mode switcher -->
175
+ <ry-button-group name="mode" value="terminal">
176
+ <ry-button value="direct">Direct</ry-button>
177
+ <ry-button value="terminal">Terminal</ry-button>
178
+ <ry-button value="release">Release</ry-button>
179
+ </ry-button-group>
180
+
181
+ <!-- Listen for changes -->
182
+ <script>
183
+ document.querySelector('ry-button-group').addEventListener('ry:change', e => {
184
+ console.log(e.detail.value); // "monthly" | "annually"
185
+ });
186
+ </script>
187
+ ```
188
+
189
+ ### Button Variants
190
+
191
+ ```html
192
+ <ry-button>Primary (default)</ry-button>
193
+ <ry-button variant="secondary">Secondary</ry-button>
194
+ <ry-button variant="outline">Outline</ry-button>
195
+ <ry-button variant="ghost">Ghost</ry-button>
196
+ <ry-button variant="danger">Danger</ry-button>
197
+ <ry-button variant="accent">Accent</ry-button>
198
+ <ry-button pressed>Pressed/Active</ry-button>
199
+ <ry-button size="sm">Small</ry-button>
200
+ <ry-button size="lg">Large</ry-button>
201
+ ```
202
+
203
+ ### Badge with Arbitrary Color
204
+
205
+ ```html
206
+ <ry-badge variant="success">Active</ry-badge>
207
+ <ry-badge variant="accent">Pro</ry-badge>
208
+ <ry-badge style="--ry-badge-color: #8B5CF6">Custom</ry-badge>
209
+ <ry-badge style="--ry-badge-color: oklch(0.7 0.15 200); --ry-badge-text: #000">Custom + text</ry-badge>
210
+ ```
211
+
212
+ ### Check List (Pricing Features)
213
+
214
+ ```html
215
+ <ul class="ry-check-list">
216
+ <li>Unlimited projects</li>
217
+ <li>Priority support</li>
218
+ <li>Custom domains</li>
219
+ </ul>
220
+ ```
221
+
222
+ ### Nav Bar
223
+
224
+ ```html
225
+ <ry-header sticky>
226
+ <ry-cluster>
227
+ <ry-logo>MyApp</ry-logo>
228
+ <ry-divider vertical></ry-divider>
229
+ <ry-nav>
230
+ <a href="/" aria-current="page">Home</a>
231
+ <a href="/docs">Docs</a>
232
+ <a href="/pricing">Pricing</a>
233
+ </ry-nav>
234
+ </ry-cluster>
235
+ <ry-actions>
236
+ <ry-button variant="ghost" size="sm">Login</ry-button>
237
+ <ry-button size="sm">Sign Up</ry-button>
238
+ </ry-actions>
239
+ </ry-header>
240
+ ```
241
+
242
+ ### Pricing Page
243
+
244
+ ```html
245
+ <ry-pricing>
246
+ <ry-pricing-card>
247
+ <h3>Free</h3>
248
+ <div class="ry-pricing__price">$0<span>/mo</span></div>
249
+ <p>For individuals</p>
250
+ <ul class="ry-check-list">
251
+ <li>3 projects</li>
252
+ <li>Basic support</li>
253
+ </ul>
254
+ <ry-button variant="outline">Get Started</ry-button>
255
+ </ry-pricing-card>
256
+
257
+ <ry-pricing-card featured>
258
+ <h3>Pro</h3>
259
+ <div class="ry-pricing__price">$19<span>/mo</span></div>
260
+ <p>For teams</p>
261
+ <ul class="ry-check-list">
262
+ <li>Unlimited projects</li>
263
+ <li>Priority support</li>
264
+ </ul>
265
+ <ry-button>Upgrade</ry-button>
266
+ </ry-pricing-card>
267
+ </ry-pricing>
268
+ ```
269
+
270
+ ### Hero Section
271
+
272
+ ```html
273
+ <ry-hero>
274
+ <h1>Build faster with ry-ui</h1>
275
+ <p>Framework-agnostic components for any app.</p>
276
+ <ry-cluster>
277
+ <ry-button size="lg">Get Started</ry-button>
278
+ <ry-button variant="outline" size="lg">View Docs</ry-button>
279
+ </ry-cluster>
280
+ </ry-hero>
281
+ ```
282
+
283
+ ### Modal & Drawer
284
+
285
+ ```html
286
+ <!-- Modal -->
287
+ <ry-button modal="confirm">Open Modal</ry-button>
288
+ <ry-modal id="confirm" title="Confirm Action">
289
+ <p>Are you sure?</p>
290
+ <ry-cluster>
291
+ <ry-button variant="danger">Delete</ry-button>
292
+ <ry-button variant="ghost">Cancel</ry-button>
293
+ </ry-cluster>
294
+ </ry-modal>
295
+
296
+ <!-- Drawer -->
297
+ <ry-button drawer="settings">Settings</ry-button>
298
+ <ry-drawer id="settings" position="right" size="400px">
299
+ <h3>Settings</h3>
300
+ <!-- content -->
301
+ </ry-drawer>
302
+ ```
303
+
304
+ ---
305
+
306
+ ## CSS Token System
307
+
308
+ All visual properties use CSS custom properties. Override in your own CSS to customize.
309
+
310
+ ### Colors
311
+
312
+ | Token | Purpose |
313
+ |-------|---------|
314
+ | `--ry-color-primary` / `-hover` / `-active` | Primary action color (blue) |
315
+ | `--ry-color-secondary` / `-hover` / `-active` | Secondary muted color |
316
+ | `--ry-color-accent` / `-hover` / `-active` | Accent/highlight color (purple) |
317
+ | `--ry-color-success` | Green for positive states |
318
+ | `--ry-color-warning` | Yellow/orange for caution |
319
+ | `--ry-color-danger` / `-hover` | Red for destructive actions |
320
+ | `--ry-color-info` | Blue for informational |
321
+ | `--ry-color-text` / `-muted` / `-inverse` | Text colors |
322
+ | `--ry-color-bg` / `-subtle` / `-muted` | Background colors |
323
+ | `--ry-color-border` / `-strong` | Border colors |
324
+ | `--ry-color-overlay` | Modal/drawer backdrop |
325
+
326
+ Each color also has `-bg` and `-text` variants for alert/badge backgrounds:
327
+ `--ry-color-{info,success,warning,danger}-bg` / `--ry-color-{info,success,warning,danger}-text`
328
+
329
+ ### Spacing
330
+
331
+ `--ry-space-{0,1,2,3,4,5,6,8,10,12,16,20}` — 0 to 5rem
332
+
333
+ ### Typography
334
+
335
+ | Token | Value |
336
+ |-------|-------|
337
+ | `--ry-font-sans` | system-ui stack |
338
+ | `--ry-font-mono` | ui-monospace stack |
339
+ | `--ry-text-{xs,sm,base,lg,xl,2xl,3xl,4xl}` | 0.75rem to 2.25rem |
340
+ | `--ry-font-{normal,medium,semibold,bold}` | 400 to 700 |
341
+ | `--ry-leading-{tight,normal,relaxed}` | 1.25 to 1.75 |
342
+
343
+ ### Borders & Shadows
344
+
345
+ | Token | Value |
346
+ |-------|-------|
347
+ | `--ry-radius-{none,sm,md,lg,xl,2xl,full}` | 0 to 9999px |
348
+ | `--ry-shadow-{sm,md,lg,xl}` | Elevation shadows |
349
+ | `--ry-border-width` | 1px |
350
+
351
+ ### Transitions
352
+
353
+ | Token | Value |
354
+ |-------|-------|
355
+ | `--ry-duration-{fast,normal,slow}` | 100ms, 200ms, 300ms |
356
+ | `--ry-ease` / `-in` / `-out` | Cubic bezier easing |
357
+
358
+ ### Z-Index
359
+
360
+ | Token | Value |
361
+ |-------|-------|
362
+ | `--ry-z-dropdown` | 1000 |
363
+ | `--ry-z-sticky` | 1020 |
364
+ | `--ry-z-fixed` | 1030 |
365
+ | `--ry-z-modal-backdrop` | 1040 |
366
+ | `--ry-z-modal` | 1050 |
367
+ | `--ry-z-popover` | 1060 |
368
+ | `--ry-z-tooltip` | 1070 |
369
+ | `--ry-z-toast` | 1080 |
370
+
371
+ ---
372
+
373
+ ## CSS Architecture
374
+
375
+ Three layers, ordered by specificity:
376
+
377
+ 1. **ry-tokens** — CSS custom properties (colors, spacing, etc.)
378
+ 2. **ry-structure** — Pure layout (no colors). Selectors: element names + `[data-ry-target]`
379
+ 3. **ry-theme** — All visual styling. Selectors: `.ry-*` classes + element names
380
+
381
+ ### Custom Theming
382
+
383
+ Load structure only + your own theme:
384
+
385
+ ```html
386
+ <link rel="stylesheet" href="ry-tokens.css"> <!-- or your own tokens -->
387
+ <link rel="stylesheet" href="ry-structure.css">
388
+ <link rel="stylesheet" href="your-theme.css">
389
+ ```
390
+
391
+ ### Dark Mode
392
+
393
+ Built into tokens via `light-dark()`. No separate dark.css needed.
394
+
395
+ ```html
396
+ <html data-ry-theme="dark"> <!-- force dark -->
397
+ <html data-ry-theme="light"> <!-- force light -->
398
+ <!-- omit attribute for OS preference -->
399
+ ```
400
+
401
+ ---
402
+
403
+ ## Patterns NOT in ry-ui (Keep Custom)
404
+
405
+ These patterns are intentionally outside the design system's scope:
406
+
407
+ | Pattern | Reason | Recommended approach |
408
+ |---------|--------|---------------------|
409
+ | Click-positioned dialog / popover | GSAP animations, cursor anchoring | Use ry-ui tokens inside custom dialog |
410
+ | File drop zone | App-specific UX | Custom component, tokenize colors |
411
+ | Color swatch selector | Too specialized | Custom radio buttons with ry-ui tokens |
412
+ | Terminal / xterm.js wrapper | Third-party integration | Custom container, tokenize colors |
413
+ | Infinite canvas / artboard | Canvas 2D, not DOM | Use `getComputedStyle` to read ry-ui tokens for canvas rendering |
414
+ | Chat / streaming replay | App-specific data format | Custom layout, use ry-ui header/badge/button inside |
415
+ | Floating properties panel | Positioned at coordinates | Use `position: absolute` + ry-ui form components inside |
416
+
417
+ For all of these: **use ry-ui tokens for colors, spacing, and typography** so they match the theme, but keep the structural markup custom.
418
+
419
+ ---
420
+
421
+ ## TypeScript
422
+
423
+ ```ts
424
+ import { RyElement, RyButton, RyToast } from '@ryanhelsing/ry-ui';
425
+
426
+ // Programmatic toast
427
+ RyToast.success('Saved!');
428
+ RyToast.error('Failed to save');
429
+
430
+ // Listen for component events
431
+ document.querySelector('ry-select')?.addEventListener('ry:change', (e: CustomEvent) => {
432
+ console.log(e.detail.value);
433
+ });
434
+
435
+ // Extend components
436
+ class MyWidget extends RyElement {
437
+ setup() {
438
+ this.on(this, 'click', () => this.emit('activate'));
439
+ }
440
+ }
441
+ ```
442
+
443
+ ---
444
+
445
+ ## Icon Registry
446
+
447
+ ```ts
448
+ import { registerIcon, registerIcons } from '@ryanhelsing/ry-ui';
449
+
450
+ // Single icon
451
+ registerIcon('custom', '<svg>...</svg>');
452
+
453
+ // Batch
454
+ registerIcons({
455
+ 'app-logo': '<svg>...</svg>',
456
+ 'custom-arrow': '<svg>...</svg>'
457
+ });
458
+ ```
459
+
460
+ Built-in icons: `settings`, `heart`, `star`, `chevron-up`, `chevron-down`, `chevron-left`, `chevron-right`, `check`, `x`, `plus`, `minus`, `search`, `sun`, `moon`, `copy`, `trash`, `edit`, `eye`, `folder`, `file`, `drag`
package/AGENTS.md CHANGED
@@ -25,7 +25,7 @@ Theme: `<html data-ry-theme="light">` — light | dark
25
25
  |----------|-----------|
26
26
  | **Layout** | page, header, main, footer, section, aside, grid, stack, cluster, split, center, card, nav, logo, actions, divider |
27
27
  | **Overlays** | modal, drawer, dropdown, tooltip, toast |
28
- | **Forms** | field, select, switch, toggle-button, checkbox/radio (native) |
28
+ | **Forms** | field, select, switch, button-group, toggle-button, checkbox/radio (native) |
29
29
  | **Values** | slider, knob, number-select, color-picker, color-input, gradient-picker |
30
30
  | **Display** | badge, alert, icon, code, table (native), tree |
31
31
  | **Utility** | theme-toggle |
@@ -38,6 +38,7 @@ Pull the page you need for full attributes, events, JS API, and examples:
38
38
  |-----|-------------|
39
39
  | [docs/components/layout.md](docs/components/layout.md) | page, header, main, footer, section, aside, grid, stack, cluster, split, center, card, nav, logo, actions, divider |
40
40
  | [docs/components/button.md](docs/components/button.md) | button, toggle-button |
41
+ | [docs/components/button-group.md](docs/components/button-group.md) | button-group (segmented control) |
41
42
  | [docs/components/accordion.md](docs/components/accordion.md) | accordion, accordion-item |
42
43
  | [docs/components/tabs.md](docs/components/tabs.md) | tabs, tab |
43
44
  | [docs/components/modal.md](docs/components/modal.md) | modal |
package/README.md CHANGED
@@ -28,7 +28,7 @@ ry-ui normalizes this. No decisions to make. No architecture to debate. An LLM c
28
28
 
29
29
  ### Backlog
30
30
 
31
- - [ ] Placeholder, Step/Wizard, Loader/Progress, Comment/Feed, Statistic/Graph, Hero, Calendar, Rating, Search, Shape, Sticky, dialog/alert, carousel, qr-code, diff, split-panel, format-bytes-number-currency, mutation-observer and resize observer
31
+ - [ ] Placeholder, Step/Wizard, Loader/Progress, Comment/Feed, Statistic/Graph, Hero, Calendar, Rating, Search, Shape, Sticky, dialog/alert, carousel, qr-code, diff, format-bytes-number-currency, mutation-observer and resize observer
32
32
 
33
33
  - [ ] This is a theme on its own: https://codepen.io/oathanrex/pen/EayVMqZ
34
34
 
@@ -54,8 +54,12 @@ ry-ui normalizes this. No decisions to make. No architecture to debate. An LLM c
54
54
  - `<ry-grid cols="3">` - Responsive grid
55
55
  - `<ry-stack>` / `<ry-cluster>` - Flex layouts
56
56
 
57
+ ### Layout
58
+ - `<ry-split>` - Resizable two-column layout with optional `persist` for localStorage-backed width
59
+
57
60
  ### Interactive
58
61
  - `<ry-button>` - Buttons with variants
62
+ - `<ry-button-group>` - Segmented control / radio button group
59
63
  - `<ry-modal>` - Modal dialogs
60
64
  - `<ry-drawer>` - Slide-out panels
61
65
  - `<ry-accordion>` - Collapsible sections
@@ -66,6 +70,9 @@ ry-ui normalizes this. No decisions to make. No architecture to debate. An LLM c
66
70
  - `<ry-tooltip>` - Hover tooltips
67
71
  - `<ry-toast>` - Notifications
68
72
 
73
+ ### Forms
74
+ - `<ry-field>` - Form field wrapper with auto label, error, and hint
75
+
69
76
  ### Display
70
77
  - `<ry-card>` - Card containers
71
78
  - `<ry-badge>` - Status badges
@@ -102,6 +109,23 @@ Use `<ry>` wrapper to write unprefixed markup:
102
109
  <ry-option value="uk">United Kingdom</ry-option>
103
110
  </ry-select>
104
111
 
112
+ <!-- Split Panel (resizable, persistent) -->
113
+ <ry-split resizable persist="sidebar">
114
+ <main>Main content</main>
115
+ <aside>Sidebar</aside>
116
+ </ry-split>
117
+
118
+ <!-- Button Group -->
119
+ <ry-button-group value="monthly">
120
+ <ry-button value="monthly">Monthly</ry-button>
121
+ <ry-button value="annually">Annually</ry-button>
122
+ </ry-button-group>
123
+
124
+ <!-- Form Field -->
125
+ <ry-field label="Email" error="Invalid email">
126
+ <input type="email" name="email">
127
+ </ry-field>
128
+
105
129
  <!-- Toast (programmatic) -->
106
130
  <script>
107
131
  RyToast.success('Saved!');
@@ -167,12 +191,7 @@ npm run typecheck
167
191
  ## Publishing
168
192
 
169
193
  ```bash
170
- nvm use 22
171
- npm login
172
- npm run build
173
- git add -A && git commit -m "new build"
174
- npm version patch # or minor, major
175
- npm publish --access public
194
+ npm run release
176
195
  ```
177
196
 
178
197
  Automatically available on CDN via [unpkg](https://unpkg.com/@ryanhelsing/ry-ui/) and [jsdelivr](https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/).
@@ -0,0 +1,32 @@
1
+ /**
2
+ * <ry-button-group>
3
+ *
4
+ * Segmented control / button group. Groups child buttons with
5
+ * connected borders and optional radio-group behavior.
6
+ *
7
+ * Usage (visual grouping only):
8
+ * <ry-button-group>
9
+ * <ry-button>Left</ry-button>
10
+ * <ry-button>Center</ry-button>
11
+ * <ry-button>Right</ry-button>
12
+ * </ry-button-group>
13
+ *
14
+ * Usage (radio behavior — single selection):
15
+ * <ry-button-group name="mode" value="terminal">
16
+ * <ry-button value="direct">Direct</ry-button>
17
+ * <ry-button value="terminal">Terminal</ry-button>
18
+ * <ry-button value="release">Release</ry-button>
19
+ * </ry-button-group>
20
+ *
21
+ * Emits ry:change with { value } when selection changes.
22
+ */
23
+ import { RyElement } from '../core/ry-element.js';
24
+ export declare class RyButtonGroup extends RyElement {
25
+ #private;
26
+ static get observedAttributes(): string[];
27
+ get value(): string;
28
+ set value(v: string);
29
+ setup(): void;
30
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
31
+ }
32
+ //# sourceMappingURL=ry-button-group.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ry-button-group.d.ts","sourceRoot":"","sources":["../../src/ts/components/ry-button-group.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,qBAAa,aAAc,SAAQ,SAAS;;IAC1C,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,EAElB;IAED,KAAK,IAAI,IAAI;IAMb,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;CAiC/F"}
@@ -1,18 +1,24 @@
1
1
  /**
2
2
  * <ry-field>
3
3
  *
4
- * Form field wrapper with label.
4
+ * Form field wrapper with label, error, and hint.
5
5
  *
6
6
  * Usage:
7
7
  * <ry-field label="Email">
8
8
  * <input type="email" placeholder="you@example.com">
9
9
  * </ry-field>
10
10
  *
11
+ * <ry-field label="Password" hint="Min 8 characters" error="Too short">
12
+ * <input type="password">
13
+ * </ry-field>
14
+ *
11
15
  * JS uses data-ry-target for queries, CSS uses classes for styling.
12
16
  */
13
17
  import { RyElement } from '../core/ry-element.js';
14
18
  export declare class RyField extends RyElement {
15
19
  #private;
20
+ static get observedAttributes(): string[];
16
21
  setup(): void;
22
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
17
23
  }
18
24
  //# sourceMappingURL=ry-field.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ry-field.d.ts","sourceRoot":"","sources":["../../src/ts/components/ry-field.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,qBAAa,OAAQ,SAAQ,SAAS;;IACpC,KAAK,IAAI,IAAI;CA2Bd"}
1
+ {"version":3,"file":"ry-field.d.ts","sourceRoot":"","sources":["../../src/ts/components/ry-field.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,qBAAa,OAAQ,SAAQ,SAAS;;IACpC,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,KAAK,IAAI,IAAI;IAIb,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;CA6G/F"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * <ry-split>
3
+ *
4
+ * Two-column split layout with optional resizable divider and persistence.
5
+ *
6
+ * Usage:
7
+ * <ry-split>
8
+ * <div>Main content</div>
9
+ * <div>Sidebar</div>
10
+ * </ry-split>
11
+ *
12
+ * Resizable with persistence:
13
+ * <ry-split resizable persist="my-panel">
14
+ * <div>Main</div>
15
+ * <div>Panel</div>
16
+ * </ry-split>
17
+ *
18
+ * CSS custom properties:
19
+ * --ry-split-width: Sidebar width (default 300px)
20
+ * --ry-split-min-width: Sidebar minimum during resize (default 100px)
21
+ * --ry-split-max-width: Sidebar maximum during resize (default 80% of container)
22
+ */
23
+ import { RyElement } from '../core/ry-element.js';
24
+ export declare class RySplit extends RyElement {
25
+ #private;
26
+ setup(): void;
27
+ }
28
+ //# sourceMappingURL=ry-split.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ry-split.d.ts","sourceRoot":"","sources":["../../src/ts/components/ry-split.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,qBAAa,OAAQ,SAAQ,SAAS;;IAMpC,KAAK,IAAI,IAAI;CA6Kd"}
@@ -1 +1 @@
1
- {"version":3,"file":"ry-transform.d.ts","sourceRoot":"","sources":["../../src/ts/core/ry-transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAqDH;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAgBxC"}
1
+ {"version":3,"file":"ry-transform.d.ts","sourceRoot":"","sources":["../../src/ts/core/ry-transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAsDH;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAgBxC"}