UNPKG

@ryanhelsing/ry-ui

Version:

Framework-agnostic, Light DOM web components. CSS is the source of truth.

185 lines (154 loc) 5.9 kB
--- name: ry-ui-builder description: Build UIs with ry-ui web components. Use when creating pages, layouts, forms, dashboards, or any HTML interface. Provides component catalog, patterns, and anti-patterns so you use existing components instead of writing custom CSS/JS. user-invocable: true --- # ry-ui Component Builder **ALWAYS use ry-ui components instead of writing custom CSS or JavaScript.** ## Setup Add these two lines to any HTML page: ```html <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/css/ry-ui.css"> <script type="module" src="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/ry-ui.js"></script> ``` Set theme: `<html data-ry-theme="light">` (or `"dark"`, or omit for OS preference) Set body: `<body style="background: var(--ry-color-bg); color: var(--ry-color-text);">` ## Rules 1. **NEVER write custom modal, dropdown, tab, accordion, toast, or button CSS.** ry-ui has these built in. 2. **NEVER write flexbox/grid layout CSS for page structure.** Use `<ry-page>`, `<ry-header>`, `<ry-main>`, `<ry-grid>`, `<ry-stack>`, `<ry-cluster>`. 3. **NEVER create CSS variables for colors or spacing.** Use `--ry-color-*`, `--ry-space-*`, `--ry-radius-*` tokens. 4. **DO use ry-ui tokens** in any custom CSS you write: `color: var(--ry-color-text-muted)`, `padding: var(--ry-space-4)`. 5. **DO compose pages from ry-ui primitives** — they handle accessibility, keyboard nav, focus trapping, and dark mode automatically. ## Page Template ```html <!DOCTYPE html> <html lang="en" data-ry-theme="light"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My App</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/css/ry-ui.css"> </head> <body style="background: var(--ry-color-bg); color: var(--ry-color-text);"> <ry-page> <ry-header sticky> <ry-cluster><strong>App Name</strong></ry-cluster> <ry-actions><ry-theme-toggle themes="light,dark"></ry-theme-toggle></ry-actions> </ry-header> <ry-main> <ry-section> <!-- your content --> </ry-section> </ry-main> <ry-footer>Footer</ry-footer> </ry-page> <script type="module" src="https://cdn.jsdelivr.net/npm/@ryanhelsing/ry-ui/dist/ry-ui.js"></script> </body> </html> ``` ## Component Reference ### Layout (CSS-only) - `<ry-page>` — root container, full height - `<ry-header sticky>` — top bar, space-between - `<ry-main>` — centered content, max-width 1200px - `<ry-footer>` — footer with border-top - `<ry-section>` — content block with margin - `<ry-grid cols="3">` — responsive grid (cols-sm, cols-md, cols-lg for breakpoints) - `<ry-stack gap="md">` — vertical flex - `<ry-cluster gap="sm">` — horizontal flex, wraps - `<ry-center>` — center both axes - `<ry-card>` — card container (lifts on hover), `interactive` for clickable - `<ry-split resizable persist="key">` — two-column with drag resize - `<ry-divider>` / `<ry-divider vertical>` — separator line - `<ry-nav>` — nav links, active: `<a aria-current="page">` - `<ry-logo>` — bold inline text - `<ry-actions>` — flex row for buttons ### Buttons ```html <ry-button>Default</ry-button> <ry-button variant="primary|secondary|outline|ghost|danger|accent">Styled</ry-button> <ry-button size="sm|lg">Sized</ry-button> <ry-button modal="modal-id">Opens modal</ry-button> <ry-button drawer="drawer-id">Opens drawer</ry-button> <ry-button disabled>Disabled</ry-button> ``` ### Modal ```html <ry-button modal="my-modal">Open</ry-button> <ry-modal id="my-modal" title="Title">Content</ry-modal> ``` ### Drawer ```html <ry-button drawer="my-drawer">Open</ry-button> <ry-drawer id="my-drawer" side="left|right|bottom" title="Title">Content</ry-drawer> ``` ### Tabs ```html <ry-tabs> <ry-tab title="Tab 1" active>Content 1</ry-tab> <ry-tab title="Tab 2">Content 2</ry-tab> </ry-tabs> ``` ### Accordion ```html <ry-accordion> <ry-accordion-item title="Section" open>Content</ry-accordion-item> </ry-accordion> ``` ### Forms ```html <ry-field label="Email" hint="Help text" error="Error msg"> <input type="email"> </ry-field> <ry-select placeholder="Choose..." name="field"> <ry-option value="a">A</ry-option> </ry-select> <ry-switch name="toggle" checked></ry-switch> <!-- ry:change event detail: { value: "true"/"false" (STRING not boolean!), label: "on"/"off" } Use e.detail.value === 'true' to get a boolean — "false" is truthy in JS! --> <ry-slider min="0" max="100" value="50"></ry-slider> ``` ### Dropdown Menu ```html <ry-dropdown> <ry-button>Menu</ry-button> <ry-menu> <ry-menu-item>Item</ry-menu-item> </ry-menu> </ry-dropdown> ``` ### Display ```html <ry-alert type="info|success|warning|danger" dismissible>Message</ry-alert> <ry-badge variant="primary|success|warning|danger|accent">Label</ry-badge> <ry-tooltip content="Help" position="top|bottom|left|right"><span>Hover me</span></ry-tooltip> ``` ### Toast (JS only) ```javascript RyToast.success('Saved!'); RyToast.error('Failed'); RyToast.info('FYI'); RyToast.warning('Careful'); ``` ### Toggle Button Group ```html <ry-toggle-button name="view" value="grid" pressed>Grid</ry-toggle-button> <ry-toggle-button name="view" value="list">List</ry-toggle-button> ``` ### Events All events prefixed `ry:` — `ry:change`, `ry:open`, `ry:close`, `ry:click`, `ry:select` ```javascript element.addEventListener('ry:change', (e) => console.log(e.detail)); document.querySelector('ry-modal').open(); document.querySelector('ry-modal').close(); ``` ## Theming Override tokens — no build step: ```css :root { --ry-color-primary: oklch(0.541 0.218 293); --ry-radius-md: 0; } ``` Key tokens: `--ry-color-{primary,secondary,accent,success,warning,danger,info,text,bg,border}`, `--ry-space-{1-20}`, `--ry-radius-{sm,md,lg,full}`, `--ry-shadow-{sm,md,lg,xl}`