@jacshuo/onyx 2.1.0 → 2.2.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 CHANGED
@@ -3,6 +3,9 @@
3
3
  <img src="https://img.shields.io/npm/l/@jacshuo/onyx?style=flat-square" alt="license" />
4
4
  <img src="https://img.shields.io/github/actions/workflow/status/jacshuo/OnyxUI/ci.yml?branch=main&style=flat-square&label=CI" alt="CI" />
5
5
  <img src="https://img.shields.io/npm/dm/@jacshuo/onyx?color=10b981&style=flat-square" alt="downloads" />
6
+ <img src="https://img.shields.io/badge/React-18%2B-61dafb?style=flat-square&logo=react" alt="React 18+" />
7
+ <img src="https://img.shields.io/badge/Tailwind_CSS-v4-38bdf8?style=flat-square&logo=tailwindcss" alt="Tailwind CSS v4" />
8
+ <img src="https://img.shields.io/badge/TypeScript-strict-3178c6?style=flat-square&logo=typescript" alt="TypeScript" />
6
9
  </p>
7
10
 
8
11
  <p align="right">
@@ -11,9 +14,9 @@
11
14
 
12
15
  # @jacshuo/onyx
13
16
 
14
- A **React UI component library** built with Tailwind CSS v4 — crafted for responsive web apps and Electron desktop applications alike. Ships tree-shakeable ESM + CJS bundles with per-component subpath exports, modular CSS, and full TypeScript declarations.
17
+ A **cross-platform React UI component library** built on Tailwind CSS v4 — designed for responsive web apps, content-rich dashboards, and Electron desktop applications. Ships 55+ production-ready components as individually tree-shakeable ESM + CJS bundles with full TypeScript declarations.
15
18
 
16
- Born from a passion for **polished cross-platform experiences**, Onyx delivers a consistent look and feel from mobile screens to 4K displays — with dark mode, keyboard navigation, and touch interactions built in from day one.
19
+ Born from a passion for **polished cross-platform experiences**, Onyx delivers a consistent look and feel from mobile screens to 4K displays — with dark mode, keyboard navigation, accessible form wiring, and touch interactions built in from day one.
17
20
 
18
21
  > **Live Demo →** [jacshuo.github.io/OnyxUI](https://jacshuo.github.io/OnyxUI)
19
22
 
@@ -21,29 +24,39 @@ Born from a passion for **polished cross-platform experiences**, Onyx delivers a
21
24
 
22
25
  ## Why Onyx?
23
26
 
24
- - **Responsive by design** — Every component adapts from a phone screen to a 4K display without a single extra media query from you. Headers fold to hamburger menus, sidebars slide to icon-only or drawer modes, dialogs become bottom sheets — all built in. Size variants (`sm` / `md` / `lg`) and semantic CSS tokens make density adjustments trivial.
25
- - **Desktop & Electron first-class support** Onyx is crafted with Electron and desktop apps as a primary use case. Components are optimized for keyboard navigation, pointer interactions, and content-dense layouts that most mobile-first libraries struggle to deliver.
26
- - **Production-ready out of the box** — Dark mode, design tokens, accessibility, touch gestures, and keyboard shortcuts are built in from day one — not bolted on as an afterthought.
27
- - **Minimal footprint, maximum control** No runtime CSS-in-JS. Just Tailwind CSS v4 utility classes and CSS custom properties. Override any token without ejecting or fighting specificity wars.
28
- - **Rich, specialized components**Beyond the usual buttons and inputs, Onyx includes `CinePlayer`, `MiniPlayer`, `FileExplorer`, and `DataTable` — components that are hard to find in general-purpose libraries but essential for media-rich and desktop-class applications.
27
+ ### Responsive without compromise
28
+ Every component adapts from a phone screen to a 4K display without a single extra media query from you. Headers fold to hamburger menus, sidebars become draggable mobile drawers, dialogs become bottom sheets, and table layouts reflow gracefully. Size variants (`sm` / `md` / `lg`) and CSS custom property tokens make density adjustments trivial.
29
+
30
+ ### Desktop & Electronfirst-class
31
+ Onyx treats Electron and desktop apps as primary targets. Components are optimized for keyboard navigation, pointer interactions, content-dense layouts, and drag interactions territory where most mobile-first libraries underdeliver. `CinePlayer`, `MiniPlayer`, `FileExplorer`, `CommandPalette`, `RibbonBar`, and `FilmReel` are purpose-built for desktop-class applications.
32
+
33
+ ### Accessible by construction
34
+ `FormItem` automatically injects `id`, `aria-describedby`, and `aria-invalid` into child controls — no manual wiring. Every interactive component follows WCAG label-for semantics. Screen readers, keyboard users, and autofill all work correctly out of the box.
35
+
36
+ ### Zero-config theming
37
+ No build tool plugins. No `tailwind.config.js`. Override any design decision via `@theme {}` tokens or CSS custom properties — including at media query breakpoints. Dark mode is class-based (`.dark` on any ancestor) and works everywhere.
38
+
39
+ ### Minimal footprint, maximum control
40
+ No runtime CSS-in-JS. No styled-components. Just Tailwind CSS v4 utility classes and CSS custom properties. Import only what you use — per-component subpath exports ensure unused components never reach your bundle.
29
41
 
30
42
  ---
31
43
 
32
- ## Features
33
-
34
- - 🎨 **30+ components** — from Button → DataTable → CinePlayer → CodeBlock
35
- - 📱 **Responsive by default** — built-in breakpoint layouts, touch-friendly tap targets, and adaptive component modes (hamburger nav, drawer sidebar, bottom-sheet dialog)
36
- - 🌗 **Dark / Light mode** class-based, works out of the box
37
- - 🎯 **CSS variable design tokens** override any design decision via CSS custom properties, including at media query breakpoints
38
- - **Tailwind CSS v4** zero config, `@theme` tokens, `color-mix()` accent support
39
- - 📦 **Tree-shakeable** Per-component ESM entries with code splitting; import only what you use
40
- - 🗂️ **On-demand imports** — Subpath exports (`@jacshuo/onyx/Button`) for maximum control
41
- - 🎨 **Modular CSS** — Full bundle, base-only, or per-component CSS pick exactly what you need
42
- - 🖥️ **Cross-platform** — built for web & Electron desktop apps
43
- - ⌨️ **Keyboard-first** comprehensive keyboard shortcuts for CinePlayer, FileExplorer, and more
44
- - 👆 **Touch & gesture support** — tap-to-reveal, focus-visible states, and touch-optimized interactions across all interactive components
45
- - 🔤 **Full TypeScript** every prop, event, and variant is typed
46
- - 🧩 **Composable API** compound component patterns (e.g., `Dialog` `DialogContent` + `DialogHeader` + `DialogFooter`) let you assemble exactly what you need
44
+ ## Features at a Glance
45
+
46
+ | | |
47
+ |---|---|
48
+ | 🧩 **55+ components** | Primitives Charts CinePlayer DataTable, covering the full UI spectrum |
49
+ | 📱 **Responsive by default** | Built-in breakpoint layouts, adaptive component modes, touch-friendly tap targets |
50
+ | **Accessible by default** | WCAG label-for, ARIA roles, keyboard navigation, and sr-only wiring throughout |
51
+ | 🌗 **Dark / Light mode** | Class-based dark mode, works on any subtree |
52
+ | 📊 **Charts included** | BarChart, LineChart, PieChart, ScatterChart no extra charting library needed |
53
+ | **Tailwind CSS v4** | Zero config `@theme` tokens, pure CSS design system |
54
+ | 📦 **Tree-shakeable** | Per-component ESM subpath exports import only what you use |
55
+ | 🎨 **Modular CSS** | Full bundle, base-only, or per-component CSS pick what you need |
56
+ | 🖥️ **Electron ready** | Keyboard shortcuts, drag interactions, content-dense layouts |
57
+ | 🔤 **Full TypeScript** | Every prop, variant, and event is strictly typed |
58
+ | 🧩 **Composable API** | Compound component patterns for full layout control |
59
+ | ✅ **519 tests** | 36 test files — Vitest + jsdom + Testing Library |
47
60
 
48
61
  ---
49
62
 
@@ -57,13 +70,7 @@ pnpm add @jacshuo/onyx
57
70
  yarn add @jacshuo/onyx
58
71
  ```
59
72
 
60
- ### Peer Dependencies
61
-
62
- ```bash
63
- npm install react react-dom
64
- ```
65
-
66
- > Requires **React ≥ 18.0.0**.
73
+ Requires **React ≥ 18.0.0** and **react-dom ≥ 18.0.0**.
67
74
 
68
75
  ---
69
76
 
@@ -72,7 +79,6 @@ npm install react react-dom
72
79
  **1. Import the stylesheet** (once, at your app entry point):
73
80
 
74
81
  ```tsx
75
- // main.tsx or App.tsx
76
82
  import '@jacshuo/onyx/styles.css';
77
83
  ```
78
84
 
@@ -99,140 +105,211 @@ function App() {
99
105
 
100
106
  ## Import Strategies
101
107
 
102
- Onyx supports multiple import styles — pick the one that best fits your bundler and performance requirements.
108
+ Choose the style that fits your bundler and performance requirements.
103
109
 
104
- ### Full import (simplest)
110
+ ### Flat import (simplest)
105
111
 
106
- Import everything from the barrel entry. Modern bundlers (Vite, Next.js, webpack 5) will tree-shake unused components automatically.
112
+ Modern bundlers (Vite, Next.js, webpack 5) tree-shake unused components automatically.
107
113
 
108
114
  ```tsx
109
- import { Button, Dialog, Tabs } from '@jacshuo/onyx';
115
+ import { Button, Dialog, Tabs, Form, FormItem, Input } from '@jacshuo/onyx';
110
116
  import '@jacshuo/onyx/styles.css';
111
117
  ```
112
118
 
113
119
  ### Per-component import (maximum tree-shaking)
114
120
 
115
- Import each component from its own subpath. This guarantees only the code you use is included, even with bundlers that don't tree-shake well.
116
-
117
- Components are organized under category subpaths (`Primitives`, `Overlay`, `Disclosure`, `DataDisplay`, `Navigation`, `Layout`, `Feedback`, `Forms`, `Extras`):
121
+ Guarantees only the code you use is included, even with bundlers that don't tree-shake well.
118
122
 
119
123
  ```tsx
120
- // Individual component
121
124
  import { Button } from '@jacshuo/onyx/Primitives/Button';
122
125
  import { Dialog, DialogContent } from '@jacshuo/onyx/Overlay/Dialog';
123
- import { Tabs, TabList, TabTrigger } from '@jacshuo/onyx/Disclosure/Tabs';
126
+ import { LineChart } from '@jacshuo/onyx/Chart/LineChart';
127
+ ```
128
+
129
+ ### Category namespace
130
+
131
+ ```tsx
132
+ import { Primitives, Overlay, Chart } from '@jacshuo/onyx';
124
133
 
125
- // Or import everything from a category at once
126
- import { Button, Input, Badge } from '@jacshuo/onyx/Primitives';
127
- import { Alert } from '@jacshuo/onyx/Feedback';
134
+ <Primitives.Button intent="primary">Save</Primitives.Button>
135
+ <Chart.BarChart data={data} />
128
136
  ```
129
137
 
130
138
  ### CSS options
131
139
 
132
- | Import | Size | Description |
133
- |---|---|---|
134
- | `@jacshuo/onyx/styles.css` | ~102 KB | Full pre-compiled bundle — all utilities + all component CSS. Simplest setup. |
135
- | `@jacshuo/onyx/styles/base.css` | ~95 KB | Tailwind utilities + core design tokens. No component-specific keyframes. |
136
- | `@jacshuo/onyx/styles/tailwind.css` | ~4 KB | **For projects with their own Tailwind CSS v4.** Includes `@source` directive, tokens & dark mode variant. |
137
- | `@jacshuo/onyx/styles/tokens.css` | ~4 KB | Raw `@theme` tokens only — no `@source`, no Tailwind import. |
138
- | `@jacshuo/onyx/styles/CinePlayer.css` | ~2.5 KB | CinePlayer keyframes & `--cp-*` design tokens |
139
- | `@jacshuo/onyx/styles/MiniPlayer.css` | ~2.2 KB | MiniPlayer keyframes & `--mp-*` design tokens |
140
- | `@jacshuo/onyx/styles/FileExplorer.css` | ~1.6 KB | FileExplorer `--fe-*` design tokens |
141
- | `@jacshuo/onyx/styles/FilmReel.css` | ~0.6 KB | FilmReel keyframes |
142
-
143
- #### Using with your own Tailwind CSS v4 setup
140
+ | Import | Description |
141
+ |---|---|
142
+ | `@jacshuo/onyx/styles.css` | Full pre-compiled bundle — all utilities + all component CSS. Simplest setup. |
143
+ | `@jacshuo/onyx/styles/base.css` | Tailwind utilities + core design tokens. No component-specific keyframes. |
144
+ | `@jacshuo/onyx/styles/tailwind.css` | **For projects with their own Tailwind CSS v4.** Includes `@source` + tokens + dark variant. |
145
+ | `@jacshuo/onyx/styles/tokens.css` | Raw `@theme` tokens only. |
146
+ | `@jacshuo/onyx/styles/CinePlayer.css` | CinePlayer keyframes & `--cp-*` tokens |
147
+ | `@jacshuo/onyx/styles/MiniPlayer.css` | MiniPlayer keyframes & `--mp-*` tokens |
148
+ | `@jacshuo/onyx/styles/FileExplorer.css` | FileExplorer `--fe-*` tokens |
149
+ | `@jacshuo/onyx/styles/FilmReel.css` | FilmReel keyframes |
144
150
 
145
- If your project already runs Tailwind CSS v4 and you want to import only the tokens (not the full pre-compiled bundle), you **must** use `tailwind.css` so that Tailwind scans the library's JS files for class names:
151
+ #### Using alongside your own Tailwind CSS v4
146
152
 
147
153
  ```css
148
154
  /* your app's CSS entry */
149
155
  @import "tailwindcss";
150
156
  @import "@jacshuo/onyx/styles/tailwind.css";
151
157
 
152
- /* optionally add per-component CSS for CinePlayer, MiniPlayer, etc. */
158
+ /* add per-component CSS as needed */
153
159
  @import "@jacshuo/onyx/styles/CinePlayer.css";
154
160
  ```
155
161
 
156
- > **Why?** Onyx components use Tailwind utility classes defined in JavaScript (via CVA). Without `@source`, your Tailwind build won't know about these classes and they won't be generated. The `tailwind.css` file includes `@source ".."` which tells Tailwind v4 to scan the library's compiled JS.
157
- >
158
- > **Do NOT** use `tokens.css` alone — it only provides design tokens without the `@source` directive, so component styles will be incomplete.
159
-
160
- **Example — minimal setup with CinePlayer only:**
161
-
162
- ```tsx
163
- import '@jacshuo/onyx/styles/base.css';
164
- import '@jacshuo/onyx/styles/CinePlayer.css';
165
- import { CinePlayer } from '@jacshuo/onyx/Extras/CinePlayer';
166
- ```
162
+ > Use `tailwind.css` not `tokens.css` so that Tailwind's scanner picks up class names from Onyx's compiled JS via the included `@source` directive.
167
163
 
168
164
  ---
169
165
 
170
- ## Components
166
+ ## Component Library
171
167
 
172
168
  ### Primitives
173
169
 
174
170
  | Component | Description |
175
171
  |---|---|
176
- | **Button** | Primary, secondary, danger, warning, ghost, outline intents with sm/md/lg sizes |
177
- | **Input** | Styled text input with variant support |
172
+ | **Button** | 6 intents (primary, secondary, danger, warning, ghost, outline) × 3 sizes |
173
+ | **Input** | Text input with prefix, suffix, action button, and size variants |
174
+ | **TextBox** | Textarea with live word/character count and CJK-aware counting |
175
+ | **Dropdown** | Single & multi-select with search, grouped options, clearable, and keyboard nav |
176
+ | **Checkbox** | Tri-state (checked, unchecked, indeterminate) with label |
177
+ | **Radio / RadioGroup** | Grouped radio buttons with intent and size variants |
178
+ | **Switch** | Toggle switch with checked/unchecked slot content |
179
+ | **Slider / SliderRange** | Single-value and range sliders with keyboard control |
180
+ | **Badge** | Inline status badge with dot, outline, and pill variants |
181
+ | **Tag / Chip** | Dismissible tag for selections and filters |
178
182
  | **Label** | Form label with size variants |
179
- | **Badge** | Inline status badges |
180
- | **Dropdown** | Single & multi-select dropdowns |
181
- | **DropdownButton** | Button with a dropdown menu |
183
+ | **Avatar** | User avatar with image, initials fallback, and status indicator |
184
+ | **Indicator** | Numeric badge overlay for icons and avatars |
182
185
 
183
186
  ### Layout
184
187
 
185
188
  | Component | Description |
186
189
  |---|---|
187
- | **Card** | Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter |
188
- | **HorizontalCard** | Side-by-side image + content card |
189
- | **ImageCard** | Image-first card with overlay actions |
190
- | **Panel** | Collapsible panel with header |
190
+ | **Card** | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter` |
191
+ | **ImageCard** | Image-first card with overlay actions and hover states |
192
+ | **Panel** | Collapsible content panel with header |
191
193
 
192
194
  ### Data Display
193
195
 
194
196
  | Component | Description |
195
197
  |---|---|
196
- | **Table** | Basic table primitives (Table, TableHeader, TableBody, TableRow, etc.) |
197
- | **SortableTable** | Click-to-sort column headers |
198
- | **DataTable** | Full-featured data table with sorting, selection, pagination |
199
- | **List / ListItem** | Styled list component |
200
- | **Tree / TreeItem** | Expandable tree view |
201
- | **Chat** | Chat message list with sent/received styling |
202
- | **CodeBlock** | Syntax-highlighted code block powered by Shiki, supports 20+ languages, line numbers, and live editable mode |
198
+ | **Table / DataTable** | Basic table primitives + full-featured sortable/selectable/paginated data table |
199
+ | **List / ListItem** | Styled list with leading icon/avatar, title, description, and trailing action |
200
+ | **Tree / TreeItem** | Expandable tree view with keyboard navigation |
201
+ | **Chat** | Chat message thread with sent/received bubbles and timestamps |
202
+ | **CodeBlock** | Shiki-powered syntax highlighting — 20+ languages, line numbers, live-editable mode |
203
+ | **MetricCard** | KPI card with trend indicator and sparkline slot |
204
+ | **Stat** | Compact statistic display with label, value, and change indicator |
203
205
 
204
206
  ### Navigation
205
207
 
206
208
  | Component | Description |
207
209
  |---|---|
208
- | **SideNav** | Collapsible sidebar with icons, sections, and multiple collapse modes |
209
- | **Header** | App header with nav items and action buttons |
210
- | **NavLink** | Semantic text link (`<a>`) with auto external-link detection, intent/size/underline variants |
211
- | **Tabs** | Tab bar with sliding indicator animation |
210
+ | **Header** | App header with responsive hamburger collapse, nav items, and action buttons |
211
+ | **SideNav** | Collapsible sidebar — expanded / icon-only / rail modes; mobile drawer with draggable pull-tab and `mobileDrawerSlot` |
212
+ | **NavLink** | Semantic link with auto external-link detection, intent/size/underline variants |
213
+ | **Breadcrumb** | Breadcrumb trail with truncation |
214
+ | **Pagination** | Page number navigation with first/last/prev/next |
215
+ | **RibbonBar** | Office-style ribbon toolbar with grouped commands |
212
216
 
213
217
  ### Disclosure
214
218
 
215
219
  | Component | Description |
216
220
  |---|---|
217
- | **Accordion** | Expandable accordion sections |
218
- | **Tabs** | TabList, TabTrigger, TabPanels, TabContent |
221
+ | **Accordion** | Expandable sections with animated open/close |
222
+ | **Tabs** | `TabList`, `TabTrigger`, `TabPanels`, `TabContent` with sliding indicator |
219
223
 
220
224
  ### Overlay
221
225
 
222
226
  | Component | Description |
223
227
  |---|---|
224
- | **Dialog** | Modal dialog with stacking support, backdrop click, ESC handling |
225
- | **Tooltip** | Hover tooltip with configurable placement |
226
- | **Alert** | Toast-style alert system with `useAlert()` hook |
228
+ | **Dialog** | Modal dialog centered on desktop, bottom sheet on mobile; stacking support |
229
+ | **Drawer** | Side drawer with responsive swipe-to-dismiss |
230
+ | **Tooltip** | Hover tooltip with configurable placement and delay |
231
+ | **ContextMenu** | Right-click context menu with submenus |
232
+
233
+ ### Feedback
234
+
235
+ | Component | Description |
236
+ |---|---|
237
+ | **Alert / useAlert()** | Toast-style alerts with `useAlert()` hook — success, error, warning, info |
238
+ | **ProgressBar** | Determinate and indeterminate progress |
239
+ | **Skeleton** | Loading placeholder with pulse animation |
240
+ | **Spin** | Spinner with intent and size variants |
241
+ | **Toast** | Standalone toast notification |
242
+
243
+ ### Forms
244
+
245
+ | Component | Description |
246
+ |---|---|
247
+ | **Form / FormItem / FormSection** | Stacked & inline layouts, card/inset appearance, auto `id`/`aria-describedby` injection, bulk validation via `onValues` |
248
+ | **Select** | Native-style accessible select with custom styling |
249
+
250
+ ### Charts
251
+
252
+ | Component | Description |
253
+ |---|---|
254
+ | **BarChart** | Vertical/horizontal bar chart with tooltip and legend |
255
+ | **LineChart** | Multi-series line chart with area fill option |
256
+ | **PieChart** | Pie/donut chart with animated segments |
257
+ | **ScatterChart** | Scatter plot with configurable point size and color |
227
258
 
228
259
  ### Extras
229
260
 
230
261
  | Component | Description |
231
262
  |---|---|
232
- | **FilmReel** | Cinematic photo gallery with lightbox |
233
- | **MiniPlayer** | Floating mini music player with dock, playlist, shuffle, loop |
234
- | **CinePlayer** | Full video player with cinema mode, playlist, keyboard shortcuts |
235
- | **FileExplorer** | Sci-fi themed file explorer with drag, resize, dock, multi-select, Delete key |
263
+ | **CinePlayer** | Full-featured video player cinema mode, playlist, keyboard shortcuts, accent color |
264
+ | **MiniPlayer** | Floating music player dock, playlist, shuffle, loop, accent color |
265
+ | **FileExplorer** | File manager drag-select, resize, dock, multi-select, `Delete` key with confirmation |
266
+ | **FilmReel** | Cinematic photo gallery with lightbox and keyboard navigation |
267
+ | **CommandPalette** | Spotlight-style command palette with fuzzy search |
268
+ | **DateTimePicker** | Date and time picker with calendar grid and time sliders |
269
+ | **Timeline** | Vertical timeline with icon, status, and time slots |
270
+ | **Masonry** | Responsive masonry grid layout |
271
+ | **TypewriterText** | Animated typewriter text with configurable speed and cursor |
272
+
273
+ ---
274
+
275
+ ## Forms & Accessibility
276
+
277
+ `FormItem` is the connectivity layer between labels and controls. It injects `id`, `aria-describedby`, and `aria-invalid` into its first child automatically — every labelable control (`Input`, `TextBox`, `Dropdown`, `Switch`, `Checkbox`, `Slider`) receives correct WCAG label-for wiring without any manual props.
278
+
279
+ ```tsx
280
+ import { Form, FormItem, Input, Dropdown, Switch, Button } from '@jacshuo/onyx';
281
+
282
+ <Form layout="inline">
283
+ <FormItem label="Email" required>
284
+ <Input type="email" placeholder="you@example.com" />
285
+ </FormItem>
286
+
287
+ <FormItem label="Role">
288
+ <Dropdown options={roles} placeholder="Select a role…" />
289
+ </FormItem>
290
+
291
+ <FormItem label="Notifications">
292
+ {/* id injected directly onto Switch's native <input> */}
293
+ <Switch label="Receive email notifications" />
294
+ </FormItem>
295
+ </Form>
296
+ ```
297
+
298
+ ### Validation
299
+
300
+ ```tsx
301
+ <FormItem
302
+ label="Username"
303
+ required
304
+ onValidate={(value) =>
305
+ value.length >= 3
306
+ ? { result: true, reason: 'Username is available.' }
307
+ : { result: false, reason: 'Must be at least 3 characters.' }
308
+ }
309
+ >
310
+ <Input placeholder="jane_doe" />
311
+ </FormItem>
312
+ ```
236
313
 
237
314
  ---
238
315
 
@@ -240,55 +317,50 @@ import { CinePlayer } from '@jacshuo/onyx/Extras/CinePlayer';
240
317
 
241
318
  ### Dark Mode
242
319
 
243
- The library uses Tailwind's **class-based** dark mode. Add `class="dark"` to your `<html>` or any ancestor element:
320
+ Class-based dark mode add `.dark` to any ancestor:
244
321
 
245
322
  ```html
246
323
  <html class="dark">
247
- <!-- all OnyxUI components render in dark mode -->
324
+ <!-- all Onyx components render in dark mode -->
248
325
  </html>
249
326
  ```
250
327
 
251
- ### Accent Colors
252
-
253
- Many components accept an `accent` prop (any CSS color string):
254
-
255
- ```tsx
256
- <MiniPlayer accent="#3b82f6" playlist={tracks} />
257
- <CinePlayer accent="#f43f5e" playlist={videos} />
258
- <FileExplorer accent="#10b981" files={files} />
259
- ```
328
+ ### Override Design Tokens
260
329
 
261
- ### CSS Custom Properties
262
-
263
- All component colors are defined as CSS custom properties in `:root` and `.dark`, making them fully overridable:
330
+ All colors, spacing, and sizing values are CSS custom properties overridable without ejecting:
264
331
 
265
332
  ```css
266
- /* Override CinePlayer colors */
267
- :root {
268
- --cp-bg: #111;
269
- --cp-text: rgba(255, 255, 255, 0.8);
270
- --cp-surface-hover: rgba(255, 255, 255, 0.15);
333
+ /* Widen label column on desktop */
334
+ @media (min-width: 768px) {
335
+ :root {
336
+ --form-label-w-md: 9rem;
337
+ --form-item-gap-md: 1rem;
338
+ }
271
339
  }
272
340
 
273
- /* Override MiniPlayer colors */
341
+ /* Retheme CinePlayer */
274
342
  :root {
275
- --mp-bg: rgba(255, 255, 255, 0.95);
276
- --mp-text: #1e293b;
277
- }
278
- .dark {
279
- --mp-bg: rgba(20, 18, 30, 0.95);
280
- --mp-text: #ffffff;
343
+ --cp-bg: #0a0a0a;
344
+ --cp-surface-hover: rgba(255, 255, 255, 0.15);
281
345
  }
282
346
 
283
- /* Override FileExplorer colors */
284
- :root {
285
- --fe-bg: linear-gradient(145deg, #fff, #f8f8fc);
286
- --fe-text: #475569;
287
- }
347
+ /* Retheme MiniPlayer */
348
+ :root { --mp-bg: rgba(255, 255, 255, 0.92); }
349
+ .dark { --mp-bg: rgba(18, 15, 28, 0.96); }
350
+ ```
351
+
352
+ ### Accent Colors
353
+
354
+ Media-rich components accept a CSS color string for branding consistency:
355
+
356
+ ```tsx
357
+ <CinePlayer accent="#f43f5e" playlist={videos} />
358
+ <MiniPlayer accent="#8b5cf6" playlist={tracks} />
359
+ <FileExplorer accent="#10b981" files={files} />
288
360
  ```
289
361
 
290
362
  <details>
291
- <summary><strong>Full token reference</strong></summary>
363
+ <summary><strong>Full component token reference</strong></summary>
292
364
 
293
365
  #### CinePlayer (`--cp-*`)
294
366
  | Token | Default | Description |
@@ -333,176 +405,104 @@ All component colors are defined as CSS custom properties in `:root` and `.dark`
333
405
 
334
406
  ## Responsive Design
335
407
 
336
- Onyx components handle responsive behavior internally — you get adaptive layouts without writing media queries yourself.
337
-
338
- ### Responsive Header
408
+ Onyx handles responsive behavior internally — you don't write breakpoint logic.
339
409
 
340
- `Header` automatically collapses nav items into a hamburger drawer on mobile. No extra config needed:
410
+ ### Header automatic hamburger collapse
341
411
 
342
412
  ```tsx
343
- import { Header } from '@jacshuo/onyx';
344
-
345
- // On ≥md screens: full nav bar + action buttons
346
- // On <md screens: hamburger menu (nav) + overflow menu (actions) — automatic
347
413
  <Header
348
414
  brand="My App"
349
415
  mobileMenu
350
416
  navItems={[
351
417
  { label: 'Home', href: '/' },
352
418
  { label: 'Docs', href: '/docs' },
353
- { label: 'Changelog', href: '/changelog' },
354
- ]}
355
- actions={[
356
- { icon: <UserIcon />, 'aria-label': 'Sign in', onClick: () => navigate('/login') },
357
419
  ]}
420
+ actions={[{ icon: <SearchIcon />, 'aria-label': 'Search', onClick: openSearch }]}
358
421
  />
422
+ // ≥md: full nav bar <md: hamburger menu — no extra props
359
423
  ```
360
424
 
361
- ### Responsive Sidebar
362
-
363
- `SideNav` ships with three collapse modes. Wire them to a responsive state to get a desktop-to-mobile transition with one state variable:
425
+ ### SideNav — mobile drawer with draggable pull-tab
364
426
 
365
427
  ```tsx
366
- import { useState } from 'react';
367
- import { SideNav, type SideNavCollapseMode } from '@jacshuo/onyx';
368
-
369
- function AppShell() {
370
- const [mode, setMode] = useState<SideNavCollapseMode>('expanded');
371
-
372
- return (
373
- <div className="flex h-screen">
374
- {/* Hidden on mobile; collapsible on desktop */}
375
- <aside className="hidden md:block shrink-0">
376
- <SideNav
377
- items={navItems}
378
- collapsible
379
- collapseMode={mode}
380
- onCollapseModeChange={setMode}
381
- />
382
- </aside>
383
-
384
- {/* Slide-over drawer on mobile */}
385
- <aside className="md:hidden">
386
- <SideNav items={navItems} />
387
- </aside>
388
-
389
- <main className="flex-1 overflow-y-auto p-4 md:p-8">
390
- {/* page content */}
391
- </main>
392
- </div>
393
- );
394
- }
428
+ <SideNav
429
+ items={navItems}
430
+ collapsible
431
+ mobileDrawerSlot={
432
+ <Input prefix={<SearchIcon />} placeholder="Search…" />
433
+ }
434
+ />
435
+ // Desktop: expanded / icon-only / rail collapse modes
436
+ // Mobile: slide-out drawer, draggable repositionable pull-tab
395
437
  ```
396
438
 
397
- ### Dialog — Bottom Sheet on Mobile
398
-
399
- `Dialog` automatically renders as a bottom sheet on small screens, keeping the dismiss-by-swipe pattern users expect on mobile:
439
+ ### Dialog — bottom sheet on mobile
400
440
 
401
441
  ```tsx
402
- import { Dialog, DialogContent, DialogHeader, DialogTitle, Button } from '@jacshuo/onyx';
403
-
404
- // On ≥md screens: centered modal dialog
405
- // On <md screens: slides up from bottom as a full-width sheet — no extra props
406
442
  <Dialog open={open} onOpenChange={setOpen}>
407
443
  <DialogContent size="sm">
408
- <DialogHeader>
409
- <DialogTitle>Confirm Action</DialogTitle>
410
- </DialogHeader>
411
- <p>Are you sure you want to proceed?</p>
412
- <div className="flex justify-end gap-2">
444
+ <DialogHeader><DialogTitle>Confirm</DialogTitle></DialogHeader>
445
+ <p>Are you sure?</p>
446
+ <DialogFooter>
413
447
  <Button intent="ghost" onClick={() => setOpen(false)}>Cancel</Button>
414
448
  <Button intent="primary" onClick={() => setOpen(false)}>Confirm</Button>
415
- </div>
449
+ </DialogFooter>
416
450
  </DialogContent>
417
451
  </Dialog>
452
+ // ≥md: centered modal <md: slides up from bottom
418
453
  ```
419
454
 
420
- ### Size Variants for Density Control
421
-
422
- All components expose a `size` prop (`sm` / `md` / `lg`) for adapting density to the target context — tight mobile layouts or spacious desktop dashboards:
423
-
424
- ```tsx
425
- import { DataTable, Button, Tabs, TabList, TabTrigger } from '@jacshuo/onyx';
426
-
427
- // Compact for mobile
428
- <DataTable columns={columns} data={rows} size="sm" />
429
-
430
- // Comfortable for desktop
431
- <DataTable columns={columns} data={rows} size="lg" />
432
-
433
- // Mix sizes to match your layout density
434
- <Tabs defaultValue="a">
435
- <TabList size="sm"> {/* compact tabs */}
436
- <TabTrigger value="a">Tab A</TabTrigger>
437
- <TabTrigger value="b">Tab B</TabTrigger>
438
- </TabList>
439
- </Tabs>
440
- ```
441
-
442
- ### Token Overrides at Breakpoints
443
-
444
- All sizing and spacing values are CSS custom properties. Override them at any breakpoint for precisely tuned responsive behavior:
455
+ ### Token overrides at breakpoints
445
456
 
446
457
  ```css
447
- /* Default (mobile-first) form layout */
458
+ /* Mobile-first defaults */
448
459
  :root {
449
460
  --form-label-w-md: 5rem;
450
461
  --form-item-gap-md: 0.5rem;
451
- --form-row-gap-md: 0.75rem;
452
462
  }
453
463
 
454
- /* Wider label column and increased spacing on desktop */
464
+ /* Wider labels and more breathing room on desktop */
455
465
  @media (min-width: 768px) {
456
466
  :root {
457
- --form-label-w-md: 7rem;
458
- --form-item-gap-md: 0.75rem;
459
- --form-row-gap-md: 1.25rem;
467
+ --form-label-w-md: 9rem;
468
+ --form-item-gap-md: 1rem;
460
469
  }
461
470
  }
462
471
  ```
463
472
 
464
473
  ---
465
474
 
466
- ## Usage Examples
475
+ ## Selected Usage Examples
467
476
 
468
- ### Button
477
+ ### Charts
469
478
 
470
479
  ```tsx
471
- import { Button } from '@jacshuo/onyx';
472
-
473
- <Button intent="primary" size="lg">Save</Button>
474
- <Button intent="danger">Delete</Button>
475
- <Button intent="ghost">Cancel</Button>
476
- <Button intent="outline">Settings</Button>
477
- ```
478
-
479
- ### Dialog
480
+ import { BarChart, LineChart, PieChart } from '@jacshuo/onyx';
480
481
 
481
- ```tsx
482
- import { useState } from 'react';
483
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, Button } from '@jacshuo/onyx';
482
+ <BarChart
483
+ data={[
484
+ { label: 'Jan', value: 420 },
485
+ { label: 'Feb', value: 380 },
486
+ { label: 'Mar', value: 510 },
487
+ ]}
488
+ />
484
489
 
485
- function ConfirmDialog() {
486
- const [open, setOpen] = useState(false);
490
+ <LineChart
491
+ series={[
492
+ { name: 'Revenue', data: [120, 180, 240, 310] },
493
+ { name: 'Costs', data: [80, 100, 130, 160] },
494
+ ]}
495
+ labels={['Q1', 'Q2', 'Q3', 'Q4']}
496
+ />
487
497
 
488
- return (
489
- <>
490
- <Button onClick={() => setOpen(true)}>Open Dialog</Button>
491
- <Dialog open={open} onOpenChange={setOpen}>
492
- <DialogContent size="sm">
493
- <DialogHeader>
494
- <DialogTitle>Confirm Action</DialogTitle>
495
- </DialogHeader>
496
- <p>Are you sure you want to proceed?</p>
497
- <DialogFooter>
498
- <Button intent="ghost" onClick={() => setOpen(false)}>Cancel</Button>
499
- <Button intent="primary" onClick={() => setOpen(false)}>Confirm</Button>
500
- </DialogFooter>
501
- </DialogContent>
502
- </Dialog>
503
- </>
504
- );
505
- }
498
+ <PieChart
499
+ segments={[
500
+ { label: 'Product A', value: 45 },
501
+ { label: 'Product B', value: 30 },
502
+ { label: 'Other', value: 25 },
503
+ ]}
504
+ donut
505
+ />
506
506
  ```
507
507
 
508
508
  ### DataTable
@@ -510,15 +510,42 @@ function ConfirmDialog() {
510
510
  ```tsx
511
511
  import { DataTable, type ColumnDef } from '@jacshuo/onyx';
512
512
 
513
- type User = { id: number; name: string; email: string };
513
+ type User = { id: number; name: string; email: string; role: string };
514
514
 
515
515
  const columns: ColumnDef<User>[] = [
516
- { key: 'id', header: 'ID', width: 60 },
517
- { key: 'name', header: 'Name', sortable: true },
516
+ { key: 'id', header: 'ID', width: 60 },
517
+ { key: 'name', header: 'Name', sortable: true },
518
518
  { key: 'email', header: 'Email', sortable: true },
519
+ { key: 'role', header: 'Role' },
519
520
  ];
520
521
 
521
- <DataTable columns={columns} data={users} selectionMode="multi" pageSize={10} />
522
+ <DataTable
523
+ columns={columns}
524
+ data={users}
525
+ selectionMode="multi"
526
+ pageSize={10}
527
+ />
528
+ ```
529
+
530
+ ### Alert (Toast)
531
+
532
+ ```tsx
533
+ import { useAlert, Button } from '@jacshuo/onyx';
534
+
535
+ function SaveButton() {
536
+ const alert = useAlert();
537
+
538
+ return (
539
+ <Button
540
+ intent="primary"
541
+ onClick={() =>
542
+ alert({ title: 'Saved!', description: 'Your changes have been saved.', variant: 'success' })
543
+ }
544
+ >
545
+ Save
546
+ </Button>
547
+ );
548
+ }
522
549
  ```
523
550
 
524
551
  ### Tabs
@@ -538,22 +565,6 @@ import { Tabs, TabList, TabTrigger, TabPanels, TabContent } from '@jacshuo/onyx'
538
565
  </Tabs>
539
566
  ```
540
567
 
541
- ### Alert (Toast)
542
-
543
- ```tsx
544
- import { useAlert, Button } from '@jacshuo/onyx';
545
-
546
- function NotifyButton() {
547
- const alert = useAlert();
548
-
549
- return (
550
- <Button onClick={() => alert({ title: 'Saved!', description: 'Your changes have been saved.', variant: 'success' })}>
551
- Save
552
- </Button>
553
- );
554
- }
555
- ```
556
-
557
568
  ### NavLink
558
569
 
559
570
  ```tsx
@@ -562,28 +573,20 @@ import { NavLink } from '@jacshuo/onyx';
562
573
  {/* Internal link */}
563
574
  <NavLink href="/about">About</NavLink>
564
575
 
565
- {/* Auto-detected external — shows icon + sets target="_blank" automatically */}
576
+ {/* Auto-detected external — shows icon + sets target="_blank" */}
566
577
  <NavLink href="https://github.com">GitHub</NavLink>
567
578
 
568
- {/* Suppress external icon */}
569
- <NavLink href="https://example.com" external={false}>Example</NavLink>
570
-
571
579
  {/* Variants */}
572
580
  <NavLink href="/docs" intent="secondary" size="lg" underline="always">Docs</NavLink>
573
581
  ```
574
582
 
575
583
  ### CodeBlock
576
584
 
577
- > **Note:** `CodeBlock` uses [Shiki](https://shiki.style/) for syntax highlighting. Shiki is included as a direct dependency and installed automatically with Onyx — no extra steps needed.
578
-
579
585
  ```tsx
580
586
  import { CodeBlock } from '@jacshuo/onyx';
581
587
 
582
- {/* Basic syntax highlighting */}
583
- <CodeBlock code={`const x = 42;`} language="typescript" />
584
-
585
- {/* With line numbers */}
586
- <CodeBlock code={sourceCode} language="tsx" lineNumbers />
588
+ {/* Syntax highlighting (Shiki — included, no extra install) */}
589
+ <CodeBlock code={`const x: number = 42;`} language="typescript" lineNumbers />
587
590
 
588
591
  {/* Live editable editor */}
589
592
  function Editor() {
@@ -600,22 +603,35 @@ function Editor() {
600
603
  }
601
604
  ```
602
605
 
606
+ ### CommandPalette
607
+
608
+ ```tsx
609
+ import { CommandPalette } from '@jacshuo/onyx';
610
+
611
+ <CommandPalette
612
+ open={open}
613
+ onOpenChange={setOpen}
614
+ commands={[
615
+ { id: 'new-file', label: 'New File', icon: <FileIcon />, action: newFile },
616
+ { id: 'open-prefs', label: 'Preferences', icon: <SettingsIcon />, action: openPrefs },
617
+ { id: 'git-commit', label: 'Commit Changes', icon: <GitIcon />, action: commit },
618
+ ]}
619
+ />
620
+ ```
621
+
603
622
  ### MiniPlayer
604
623
 
605
624
  ```tsx
606
625
  import { MiniPlayer } from '@jacshuo/onyx';
607
626
 
608
- const tracks = [
609
- { title: 'Midnight City', artist: 'M83', src: '/audio/midnight.mp3', cover: '/covers/m83.jpg' },
610
- { title: 'Intro', artist: 'The xx', src: '/audio/intro.mp3' },
611
- ];
612
-
613
627
  <MiniPlayer
614
- playlist={tracks}
628
+ playlist={[
629
+ { title: 'Midnight City', artist: 'M83', src: '/audio/midnight.mp3', cover: '/covers/m83.jpg' },
630
+ { title: 'Intro', artist: 'The xx', src: '/audio/intro.mp3' },
631
+ ]}
615
632
  position="bottom-right"
616
633
  accent="#8b5cf6"
617
634
  shuffle
618
- autoPlay
619
635
  />
620
636
  ```
621
637
 
@@ -624,14 +640,10 @@ const tracks = [
624
640
  ```tsx
625
641
  import { CinePlayer } from '@jacshuo/onyx';
626
642
 
627
- const videos = [
628
- { title: 'Big Buck Bunny', src: 'https://example.com/bunny.mp4', subtitle: 'Open source' },
629
- ];
630
-
631
643
  <CinePlayer
632
- playlist={videos}
644
+ playlist={[{ title: 'Product Demo', src: '/video/demo.mp4' }]}
633
645
  accent="#f43f5e"
634
- onPlayChange={(playing, index) => console.log(playing, index)}
646
+ onPlayChange={(playing, index) => trackAnalytics(playing, index)}
635
647
  />
636
648
  ```
637
649
 
@@ -641,7 +653,7 @@ const videos = [
641
653
  import { FileExplorer, type FileExplorerItem } from '@jacshuo/onyx';
642
654
 
643
655
  const files: FileExplorerItem[] = [
644
- { name: 'src', path: '/src', type: 'directory' },
656
+ { name: 'src', path: '/src', type: 'directory' },
645
657
  { name: 'index.ts', path: '/src/index.ts', type: 'file', size: 2048, extension: '.ts' },
646
658
  ];
647
659
 
@@ -649,8 +661,8 @@ const files: FileExplorerItem[] = [
649
661
  files={files}
650
662
  accent="#10b981"
651
663
  dockable
652
- onFileOpen={(f) => console.log('Open', f.name)}
653
- onDelete={(items) => console.log('Delete', items)}
664
+ onFileOpen={(f) => openEditor(f.path)}
665
+ onDelete={(items) => confirmDelete(items)}
654
666
  />
655
667
  ```
656
668
 
@@ -658,49 +670,41 @@ const files: FileExplorerItem[] = [
658
670
 
659
671
  ## Keyboard Shortcuts
660
672
 
661
- ### FileExplorer
662
- | Key | Action |
663
- |---|---|
664
- | `Click` | Select file |
665
- | `Ctrl+Click` | Multi-select |
666
- | `Ctrl+A` | Select all |
667
- | `Delete` | Delete selected (with confirmation dialog) |
668
- | `Escape` | Clear selection |
669
- | `Double-click` | Open file / Navigate directory |
670
-
671
673
  ### CinePlayer
672
674
  | Key | Action |
673
675
  |---|---|
674
676
  | `Space` | Play / Pause |
675
- | `←` / `→` | Seek ±5s |
676
- | `↑` / `↓` | Volume ±5% |
677
+ | `← / →` | Seek ±5 s |
678
+ | `↑ / ↓` | Volume ±5% |
677
679
  | `F` | Toggle fullscreen |
678
680
  | `C` | Toggle cinema mode |
679
681
  | `L` | Toggle playlist |
680
682
  | `M` | Mute / Unmute |
681
- | `N` | Next track |
682
- | `P` | Previous track |
683
+ | `N / P` | Next / Previous track |
683
684
  | `S` | Toggle shuffle |
684
685
 
686
+ ### FileExplorer
687
+ | Key | Action |
688
+ |---|---|
689
+ | `Click` | Select |
690
+ | `Ctrl+Click` | Multi-select |
691
+ | `Ctrl+A` | Select all |
692
+ | `Delete` | Delete selected (with confirmation) |
693
+ | `Escape` | Clear selection |
694
+ | `Double-click` | Open file / navigate directory |
695
+
685
696
  ---
686
697
 
687
698
  ## Development
688
699
 
689
700
  ```bash
690
- # Install dependencies
691
- npm install
692
-
693
- # Start demo dev server (http://localhost:8080)
694
- npm run dev
695
-
696
- # Production library build (dist/)
697
- npm run dist
698
-
699
- # Build demo site (dist-demo/)
700
- npm run build:demo
701
-
702
- # Typecheck
703
- npm run typecheck
701
+ npm install # install dependencies
702
+ npm run dev # demo dev server → http://localhost:3001
703
+ npm run build # library build → dist/
704
+ npm run build:demo # demo site build → dist-demo/
705
+ npm run test # run all 519 tests (Vitest)
706
+ npm run typecheck # tsc --noEmit
707
+ npm run lint # eslint src demo
704
708
  ```
705
709
 
706
710
  ---
@@ -708,33 +712,30 @@ npm run typecheck
708
712
  ## Project Structure
709
713
 
710
714
  ```
711
- OnyxUI/
712
- ├── src/
713
- │ ├── components/ # All React components
714
- │ ├── lib/utils.ts # cn() utility (clsx + tailwind-merge)
715
- └── styles/
716
- ├── index.css # Full CSS entry (Tailwind + all tokens + all component CSS)
717
- ├── base.css # Tailwind + core tokens only
718
- ├── tokens.css # @theme semantic tokens & core keyframes
719
- ├── theme.ts # CVA variant definitions
720
- └── components/ # Per-component CSS (keyframes & design tokens)
721
- ├── CinePlayer.css
722
- ├── MiniPlayer.css
723
- ├── FileExplorer.css
724
- └── FilmReel.css
725
- ├── demo/ # Demo site (GitHub Pages)
726
- │ ├── App.tsx
727
- │ ├── main.tsx
728
- │ └── pages/ # Per-component demo pages
729
- ├── .github/workflows/
730
- │ ├── ci.yml # PR/push: typecheck + build
731
- │ └── release.yml # Manual: version bump → npm → GitHub Release → Pages
732
- ├── dist/ # Library build output (ESM + CJS + DTS + CSS)
733
- │ ├── *.js / *.cjs # Per-component entry points
734
- │ ├── chunks/ # Shared code (auto-extracted by tsup)
735
- │ ├── styles.css # Full pre-compiled CSS bundle
736
- │ └── styles/ # Modular CSS files
737
- └── dist-demo/ # Demo build output
715
+ src/
716
+ ├── components/ 55+ components across 10 categories
717
+ │ ├── Primitives/ Button, Input, Dropdown, Switch, Slider, Checkbox, Radio…
718
+ │ ├── Layout/ Card, ImageCard, Panel
719
+ ├── DataDisplay/ Table, DataTable, List, Tree, Chat, CodeBlock, MetricCard…
720
+ ├── Navigation/ Header, SideNav, NavLink, Breadcrumb, RibbonBar, Pagination
721
+ ├── Disclosure/ Accordion, Tabs
722
+ ├── Overlay/ Dialog, Drawer, Tooltip, ContextMenu
723
+ ├── Feedback/ Alert, ProgressBar, Skeleton, Spin, Toast
724
+ ├── Forms/ Form, FormItem, FormSection, Select
725
+ ├── Extras/ CinePlayer, MiniPlayer, FileExplorer, CommandPalette…
726
+ └── Chart/ BarChart, LineChart, PieChart, ScatterChart
727
+ ├── styles/
728
+ ├── tokens/core.css @theme semantic color tokens
729
+ ├── tokens/animations.css Shared keyframes & animation utilities
730
+ │ ├── theme/ CVA variant functions (one file per category)
731
+ │ ├── index.css Full bundle entry
732
+ │ └── tailwind.css Consumer integration entry
733
+ └── __tests__/ 36 test files, 519 tests
734
+ demo/ Interactive demo site (GitHub Pages)
735
+ .github/
736
+ ├── workflows/ci.yml PR checks: typecheck + build
737
+ └── workflows/release.yml Manual release: patch / minor / major
738
+ dist/ Published library (ESM + CJS + DTS + CSS)
738
739
  ```
739
740
 
740
741
  ---
@@ -742,16 +743,12 @@ OnyxUI/
742
743
  ## Contributing
743
744
 
744
745
  1. Fork the repository
745
- 2. Create a feature branch (`git checkout -b feature/my-feature`)
746
- 3. Commit your changes (`git commit -m 'feat: add new component'`)
747
- 4. Push to the branch (`git push origin feature/my-feature`)
748
- 5. Open a Pull Request
749
-
750
- ### Community & Security
746
+ 2. Create a feature branch: `git checkout -b feat/my-feature`
747
+ 3. Commit your changes following [Conventional Commits](https://www.conventionalcommits.org/)
748
+ 4. Push and open a Pull Request
751
749
 
752
750
  - Contribution guide: [CONTRIBUTING.md](./CONTRIBUTING.md)
753
- - Code of conduct: [CODE_OF_CONDUCT.md](./.github/CODE_OF_CONDUCT.md)
754
- - Security policy: [SECURITY.md](./.github/SECURITY.md)
751
+ - Security policy: [SECURITY.md](./SECURITY.md)
755
752
 
756
753
  ---
757
754