@jacshuo/onyx 0.1.9 → 1.0.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.
Files changed (218) hide show
  1. package/README.md +191 -30
  2. package/README.zh-CN.md +745 -0
  3. package/dist/Accordion.cjs +1 -1
  4. package/dist/Accordion.d.cts +3 -1
  5. package/dist/Accordion.d.ts +3 -1
  6. package/dist/Accordion.js +1 -1
  7. package/dist/Alert.cjs +1 -1
  8. package/dist/Alert.d.cts +3 -1
  9. package/dist/Alert.d.ts +3 -1
  10. package/dist/Alert.js +1 -1
  11. package/dist/Badge.cjs +1 -1
  12. package/dist/Badge.d.cts +1 -1
  13. package/dist/Badge.d.ts +1 -1
  14. package/dist/Badge.js +1 -1
  15. package/dist/Button.cjs +1 -1
  16. package/dist/Button.js +1 -1
  17. package/dist/Card.cjs +1 -1
  18. package/dist/Card.d.cts +3 -1
  19. package/dist/Card.d.ts +3 -1
  20. package/dist/Card.js +1 -1
  21. package/dist/Checkbox.cjs +1 -0
  22. package/dist/Checkbox.d.cts +21 -0
  23. package/dist/Checkbox.d.ts +21 -0
  24. package/dist/Checkbox.js +1 -0
  25. package/dist/CodeBlock.cjs +1 -0
  26. package/dist/CodeBlock.d.cts +22 -0
  27. package/dist/CodeBlock.d.ts +22 -0
  28. package/dist/CodeBlock.js +1 -0
  29. package/dist/Dialog.cjs +1 -1
  30. package/dist/Dialog.d.cts +5 -2
  31. package/dist/Dialog.d.ts +5 -2
  32. package/dist/Dialog.js +1 -1
  33. package/dist/Dropdown.cjs +1 -1
  34. package/dist/Dropdown.d.cts +12 -0
  35. package/dist/Dropdown.d.ts +12 -0
  36. package/dist/Dropdown.js +1 -1
  37. package/dist/DropdownButton.cjs +1 -1
  38. package/dist/DropdownButton.d.cts +3 -1
  39. package/dist/DropdownButton.d.ts +3 -1
  40. package/dist/DropdownButton.js +1 -1
  41. package/dist/FileExplorer.cjs +1 -1
  42. package/dist/FileExplorer.js +1 -1
  43. package/dist/Form.cjs +1 -0
  44. package/dist/Form.d.cts +101 -0
  45. package/dist/Form.d.ts +101 -0
  46. package/dist/Form.js +1 -0
  47. package/dist/Header.cjs +1 -1
  48. package/dist/Header.d.cts +7 -1
  49. package/dist/Header.d.ts +7 -1
  50. package/dist/Header.js +1 -1
  51. package/dist/Indicator.cjs +1 -0
  52. package/dist/Indicator.d.cts +19 -0
  53. package/dist/Indicator.d.ts +19 -0
  54. package/dist/Indicator.js +1 -0
  55. package/dist/Input.cjs +1 -1
  56. package/dist/Input.js +1 -1
  57. package/dist/Label.cjs +1 -1
  58. package/dist/Label.js +1 -1
  59. package/dist/List.cjs +1 -1
  60. package/dist/List.d.cts +11 -4
  61. package/dist/List.d.ts +11 -4
  62. package/dist/List.js +1 -1
  63. package/dist/Masonry.cjs +1 -0
  64. package/dist/Masonry.d.cts +41 -0
  65. package/dist/Masonry.d.ts +41 -0
  66. package/dist/Masonry.js +1 -0
  67. package/dist/NavLink.cjs +1 -0
  68. package/dist/NavLink.d.cts +13 -0
  69. package/dist/NavLink.d.ts +13 -0
  70. package/dist/NavLink.js +1 -0
  71. package/dist/Panel.cjs +1 -1
  72. package/dist/Panel.js +1 -1
  73. package/dist/ProgressBar.cjs +1 -0
  74. package/dist/ProgressBar.d.cts +21 -0
  75. package/dist/ProgressBar.d.ts +21 -0
  76. package/dist/ProgressBar.js +1 -0
  77. package/dist/Radio.cjs +1 -0
  78. package/dist/Radio.d.cts +35 -0
  79. package/dist/Radio.d.ts +35 -0
  80. package/dist/Radio.js +1 -0
  81. package/dist/SideNav.cjs +1 -1
  82. package/dist/SideNav.d.cts +14 -1
  83. package/dist/SideNav.d.ts +14 -1
  84. package/dist/SideNav.js +1 -1
  85. package/dist/Spin.cjs +1 -0
  86. package/dist/Spin.d.cts +26 -0
  87. package/dist/Spin.d.ts +26 -0
  88. package/dist/Spin.js +1 -0
  89. package/dist/Switch.cjs +1 -0
  90. package/dist/Switch.d.cts +23 -0
  91. package/dist/Switch.d.ts +23 -0
  92. package/dist/Switch.js +1 -0
  93. package/dist/Table.cjs +1 -1
  94. package/dist/Table.d.cts +24 -4
  95. package/dist/Table.d.ts +24 -4
  96. package/dist/Table.js +1 -1
  97. package/dist/Tabs.cjs +1 -1
  98. package/dist/Tabs.d.cts +3 -1
  99. package/dist/Tabs.d.ts +3 -1
  100. package/dist/Tabs.js +1 -1
  101. package/dist/TextBox.cjs +1 -0
  102. package/dist/TextBox.d.cts +16 -0
  103. package/dist/TextBox.d.ts +16 -0
  104. package/dist/TextBox.js +1 -0
  105. package/dist/Tooltip.cjs +1 -1
  106. package/dist/Tooltip.d.cts +3 -1
  107. package/dist/Tooltip.d.ts +3 -1
  108. package/dist/Tooltip.js +1 -1
  109. package/dist/Tree.cjs +1 -1
  110. package/dist/Tree.d.cts +6 -2
  111. package/dist/Tree.d.ts +6 -2
  112. package/dist/Tree.js +1 -1
  113. package/dist/chunks/chunk-2JLNRAXS.cjs +1 -0
  114. package/dist/chunks/{chunk-BQLPFPCA.cjs → chunk-2KVAFCQI.cjs} +1 -1
  115. package/dist/chunks/chunk-3I7Y6FUJ.js +1 -0
  116. package/dist/chunks/chunk-47UMFXDG.js +1 -0
  117. package/dist/chunks/{chunk-MXDZHU6E.cjs → chunk-4D3XBPZX.cjs} +2 -2
  118. package/dist/chunks/{chunk-VDC7N5TC.js → chunk-4VFV5U3S.js} +1 -1
  119. package/dist/chunks/{chunk-N36YROV3.js → chunk-5FUEJFGY.js} +1 -1
  120. package/dist/chunks/chunk-5XT6TJGF.js +1 -0
  121. package/dist/chunks/{chunk-XCP37UUA.cjs → chunk-6BI4QL37.cjs} +1 -1
  122. package/dist/chunks/chunk-6E5ARQBB.cjs +1 -0
  123. package/dist/chunks/chunk-7CEOIZXK.js +1 -0
  124. package/dist/chunks/chunk-7XPIY2SQ.cjs +1 -0
  125. package/dist/chunks/chunk-A6HIQADJ.cjs +1 -0
  126. package/dist/chunks/{chunk-66LIYNLT.cjs → chunk-AEBULFON.cjs} +1 -1
  127. package/dist/chunks/chunk-AK5IK7ZD.js +1 -0
  128. package/dist/chunks/chunk-AN2R5URJ.js +1 -0
  129. package/dist/chunks/chunk-BTR2N5MO.cjs +2 -0
  130. package/dist/chunks/chunk-BUNOVZ23.cjs +2 -0
  131. package/dist/chunks/chunk-CEEQE7SY.js +1 -0
  132. package/dist/chunks/chunk-CMHBPMXE.js +1 -0
  133. package/dist/chunks/chunk-DWYAPPDB.cjs +1 -0
  134. package/dist/chunks/chunk-E3DST3QD.cjs +1 -0
  135. package/dist/chunks/chunk-E4EMAZ6V.js +2 -0
  136. package/dist/chunks/chunk-E5UKEXJE.js +1 -0
  137. package/dist/chunks/{chunk-HA5QPLJP.cjs → chunk-FDTREGBQ.cjs} +1 -1
  138. package/dist/chunks/chunk-FGUFBTKI.cjs +1 -0
  139. package/dist/chunks/chunk-FQZX67Z7.js +1 -0
  140. package/dist/chunks/chunk-FROZM2O6.js +1 -0
  141. package/dist/chunks/chunk-G2VO67XY.js +1 -0
  142. package/dist/chunks/{chunk-NG7F3GCN.js → chunk-GYFFUCBT.js} +1 -1
  143. package/dist/chunks/chunk-I425OSJL.js +1 -0
  144. package/dist/chunks/chunk-ICDAUJ2G.cjs +1 -0
  145. package/dist/chunks/chunk-IFRKP7M2.js +1 -0
  146. package/dist/chunks/chunk-IHBP6FI4.js +1 -0
  147. package/dist/chunks/chunk-IL5XDMUA.cjs +1 -0
  148. package/dist/chunks/chunk-IRSGPS7D.cjs +1 -0
  149. package/dist/chunks/chunk-ITWFMFVO.js +1 -0
  150. package/dist/chunks/chunk-JJP23IOG.cjs +1 -0
  151. package/dist/chunks/chunk-JRYYWYGV.cjs +1 -0
  152. package/dist/chunks/chunk-KCIICUZN.cjs +1 -0
  153. package/dist/chunks/chunk-KFQVZ2HC.cjs +1 -0
  154. package/dist/chunks/chunk-KGRBVUVK.cjs +1 -0
  155. package/dist/chunks/chunk-KY4NDB23.cjs +1 -0
  156. package/dist/chunks/chunk-KZBYFKOH.js +1 -0
  157. package/dist/chunks/chunk-LFJEIO3X.cjs +1 -0
  158. package/dist/chunks/chunk-NY27TTWN.js +1 -0
  159. package/dist/chunks/chunk-OEXZGLB4.js +1 -0
  160. package/dist/chunks/chunk-QC67HOC2.cjs +1 -0
  161. package/dist/chunks/chunk-QLFCH4TD.js +1 -0
  162. package/dist/chunks/chunk-RPBESM5F.cjs +1 -0
  163. package/dist/chunks/chunk-SC4PNYQT.js +2 -0
  164. package/dist/chunks/chunk-SLHD7PST.cjs +1 -0
  165. package/dist/chunks/chunk-UEGTVAFV.cjs +1 -0
  166. package/dist/chunks/chunk-V34PT6H4.cjs +1 -0
  167. package/dist/chunks/chunk-VUWT3NFR.js +1 -0
  168. package/dist/chunks/chunk-W5UXZVLS.cjs +1 -0
  169. package/dist/chunks/chunk-WQOSJM7L.js +2 -0
  170. package/dist/chunks/chunk-WRPPKNRG.js +1 -0
  171. package/dist/chunks/chunk-XAOBJSFW.js +1 -0
  172. package/dist/chunks/chunk-XK7SMEDO.cjs +2 -0
  173. package/dist/chunks/chunk-XO6CNALX.js +1 -0
  174. package/dist/chunks/chunk-ZY7GZOBS.js +1 -0
  175. package/dist/index.cjs +1 -1
  176. package/dist/index.d.cts +15 -4
  177. package/dist/index.d.ts +15 -4
  178. package/dist/index.js +1 -1
  179. package/dist/styles/base.css +1239 -6
  180. package/dist/styles/tokens.css +230 -0
  181. package/dist/styles.css +1333 -6
  182. package/dist/theme.cjs +1 -1
  183. package/dist/theme.d.cts +63 -1
  184. package/dist/theme.d.ts +63 -1
  185. package/dist/theme.js +1 -1
  186. package/package.json +2 -1
  187. package/dist/chunks/chunk-2DFUB3KN.js +0 -1
  188. package/dist/chunks/chunk-4BKLB4KV.cjs +0 -1
  189. package/dist/chunks/chunk-5PFWPAB6.js +0 -1
  190. package/dist/chunks/chunk-5XPTHIGM.cjs +0 -1
  191. package/dist/chunks/chunk-63LKYF4D.cjs +0 -1
  192. package/dist/chunks/chunk-6HZRNHE6.js +0 -1
  193. package/dist/chunks/chunk-6OLB4BUJ.js +0 -1
  194. package/dist/chunks/chunk-7NYDMXZT.cjs +0 -1
  195. package/dist/chunks/chunk-AAFG7R4U.cjs +0 -1
  196. package/dist/chunks/chunk-ACQOSYBI.js +0 -1
  197. package/dist/chunks/chunk-BW6NCATH.js +0 -1
  198. package/dist/chunks/chunk-DWTXICFN.js +0 -1
  199. package/dist/chunks/chunk-DXXCR4ON.js +0 -1
  200. package/dist/chunks/chunk-EK4BC3WT.cjs +0 -1
  201. package/dist/chunks/chunk-ENRXEISR.js +0 -1
  202. package/dist/chunks/chunk-ER2MYWQO.cjs +0 -1
  203. package/dist/chunks/chunk-GAK5OQW4.cjs +0 -1
  204. package/dist/chunks/chunk-JAKATE3I.js +0 -1
  205. package/dist/chunks/chunk-KVV5ZEYV.cjs +0 -1
  206. package/dist/chunks/chunk-NBLJWONR.cjs +0 -1
  207. package/dist/chunks/chunk-NCJ5A6VE.js +0 -1
  208. package/dist/chunks/chunk-ORNYPP3O.cjs +0 -1
  209. package/dist/chunks/chunk-P652JDOU.cjs +0 -1
  210. package/dist/chunks/chunk-PODSD5UT.js +0 -1
  211. package/dist/chunks/chunk-PSMWVB3O.js +0 -1
  212. package/dist/chunks/chunk-QLKUAE3R.cjs +0 -1
  213. package/dist/chunks/chunk-R2K6KI4L.js +0 -1
  214. package/dist/chunks/chunk-SCSMM2J4.js +0 -1
  215. package/dist/chunks/chunk-SMZQSZH2.js +0 -1
  216. package/dist/chunks/chunk-TDI2N27U.cjs +0 -1
  217. package/dist/chunks/chunk-U2ZQHP4I.cjs +0 -1
  218. package/dist/chunks/chunk-XOO3AGIT.js +0 -1
package/README.md CHANGED
@@ -5,11 +5,15 @@
5
5
  <img src="https://img.shields.io/npm/dm/@jacshuo/onyx?color=10b981&style=flat-square" alt="downloads" />
6
6
  </p>
7
7
 
8
+ <p align="right">
9
+ <strong>English</strong> | <a href="./README.zh-CN.md">中文</a>
10
+ </p>
11
+
8
12
  # @jacshuo/onyx
9
13
 
10
- A cross-platform **React UI component library** built with Tailwind CSS v4 — designed for web browsers and Electron desktop apps. Ships tree-shakeable ESM + CJS bundles with per-component subpath exports, modular CSS, and full TypeScript declarations.
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.
11
15
 
12
- Born out of a personal passion for **cross-platform desktop development**, Onyx focuses on delivering a polished, consistent look and feel across Electron and web the kind of UI toolkit I always wished existed when building desktop apps with web technologies.
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.
13
17
 
14
18
  > **Live Demo →** [jacshuo.github.io/jac-ui](https://jacshuo.github.io/jac-ui)
15
19
 
@@ -17,24 +21,27 @@ Born out of a personal passion for **cross-platform desktop development**, Onyx
17
21
 
18
22
  ## Why Onyx?
19
23
 
20
- - **Desktop-first philosophy** — Unlike most React UI libraries that target mobile or generic web, Onyx is crafted with desktop and Electron apps as a first-class concern. Components are optimized for pointer interactions, keyboard navigation, and desktop-sized viewports.
21
- - **Production-ready out of the box** — Dark mode, design tokens, accessibility, and keyboard shortcuts are built in from day one not bolted on as an afterthought.
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.
22
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.
23
- - **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 desktop-class applications.
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.
24
29
 
25
30
  ---
26
31
 
27
32
  ## Features
28
33
 
29
- - 🎨 **30+ components** — from Button → DataTable → CinePlayer
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)
30
36
  - 🌗 **Dark / Light mode** — class-based, works out of the box
31
- - 🎯 **CSS variable design tokens** — override any color via `--cp-*`, `--mp-*`, `--fe-*` custom properties
37
+ - 🎯 **CSS variable design tokens** — override any design decision via CSS custom properties, including at media query breakpoints
32
38
  - ⚡ **Tailwind CSS v4** — zero config, `@theme` tokens, `color-mix()` accent support
33
39
  - 📦 **Tree-shakeable** — Per-component ESM entries with code splitting; import only what you use
34
40
  - 🗂️ **On-demand imports** — Subpath exports (`@jacshuo/onyx/Button`) for maximum control
35
41
  - 🎨 **Modular CSS** — Full bundle, base-only, or per-component CSS — pick exactly what you need
36
42
  - 🖥️ **Cross-platform** — built for web & Electron desktop apps
37
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
38
45
  - 🔤 **Full TypeScript** — every prop, event, and variant is typed
39
46
  - 🧩 **Composable API** — compound component patterns (e.g., `Dialog` → `DialogContent` + `DialogHeader` + `DialogFooter`) let you assemble exactly what you need
40
47
 
@@ -185,6 +192,7 @@ import { CinePlayer } from '@jacshuo/onyx/CinePlayer';
185
192
  | **List / ListItem** | Styled list component |
186
193
  | **Tree / TreeItem** | Expandable tree view |
187
194
  | **Chat** | Chat message list with sent/received styling |
195
+ | **CodeBlock** | Syntax-highlighted code block powered by Shiki, supports 20+ languages, line numbers, and live editable mode |
188
196
 
189
197
  ### Navigation
190
198
 
@@ -192,6 +200,7 @@ import { CinePlayer } from '@jacshuo/onyx/CinePlayer';
192
200
  |---|---|
193
201
  | **SideNav** | Collapsible sidebar with icons, sections, and multiple collapse modes |
194
202
  | **Header** | App header with nav items and action buttons |
203
+ | **NavLink** | Semantic text link (`<a>`) with auto external-link detection, intent/size/underline variants |
195
204
  | **Tabs** | Tab bar with sliding indicator animation |
196
205
 
197
206
  ### Disclosure
@@ -315,6 +324,137 @@ All component colors are defined as CSS custom properties in `:root` and `.dark`
315
324
 
316
325
  ---
317
326
 
327
+ ## Responsive Design
328
+
329
+ Onyx components handle responsive behavior internally — you get adaptive layouts without writing media queries yourself.
330
+
331
+ ### Responsive Header
332
+
333
+ `Header` automatically collapses nav items into a hamburger drawer on mobile. No extra config needed:
334
+
335
+ ```tsx
336
+ import { Header } from '@jacshuo/onyx';
337
+
338
+ // On ≥md screens: full nav bar + action buttons
339
+ // On <md screens: hamburger menu (nav) + overflow menu (actions) — automatic
340
+ <Header
341
+ title="My App"
342
+ navItems={[
343
+ { label: 'Home', href: '/' },
344
+ { label: 'Docs', href: '/docs' },
345
+ { label: 'Changelog', href: '/changelog' },
346
+ ]}
347
+ actions={[
348
+ <Button size="sm" intent="primary">Sign In</Button>,
349
+ ]}
350
+ />
351
+ ```
352
+
353
+ ### Responsive Sidebar
354
+
355
+ `SideNav` ships with three collapse modes. Wire them to a responsive state to get a desktop-to-mobile transition with one state variable:
356
+
357
+ ```tsx
358
+ import { useState } from 'react';
359
+ import { SideNav, type SideNavCollapseMode } from '@jacshuo/onyx';
360
+
361
+ function AppShell() {
362
+ const [mode, setMode] = useState<SideNavCollapseMode>('expanded');
363
+
364
+ return (
365
+ <div className="flex h-screen">
366
+ {/* Hidden on mobile; collapsible on desktop */}
367
+ <aside className="hidden md:block shrink-0">
368
+ <SideNav
369
+ items={navItems}
370
+ collapsible
371
+ collapseMode={mode}
372
+ onCollapseModeChange={setMode}
373
+ />
374
+ </aside>
375
+
376
+ {/* Slide-over drawer on mobile */}
377
+ <aside className="md:hidden">
378
+ <SideNav items={navItems} />
379
+ </aside>
380
+
381
+ <main className="flex-1 overflow-y-auto p-4 md:p-8">
382
+ {/* page content */}
383
+ </main>
384
+ </div>
385
+ );
386
+ }
387
+ ```
388
+
389
+ ### Dialog — Bottom Sheet on Mobile
390
+
391
+ `Dialog` automatically renders as a bottom sheet on small screens, keeping the dismiss-by-swipe pattern users expect on mobile:
392
+
393
+ ```tsx
394
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, Button } from '@jacshuo/onyx';
395
+
396
+ // On ≥md screens: centered modal dialog
397
+ // On <md screens: slides up from bottom as a full-width sheet — no extra props
398
+ <Dialog open={open} onOpenChange={setOpen}>
399
+ <DialogContent size="sm">
400
+ <DialogHeader>
401
+ <DialogTitle>Confirm Action</DialogTitle>
402
+ </DialogHeader>
403
+ <p>Are you sure you want to proceed?</p>
404
+ <div className="flex justify-end gap-2">
405
+ <Button intent="ghost" onClick={() => setOpen(false)}>Cancel</Button>
406
+ <Button intent="primary" onClick={() => setOpen(false)}>Confirm</Button>
407
+ </div>
408
+ </DialogContent>
409
+ </Dialog>
410
+ ```
411
+
412
+ ### Size Variants for Density Control
413
+
414
+ All components expose a `size` prop (`sm` / `md` / `lg`) for adapting density to the target context — tight mobile layouts or spacious desktop dashboards:
415
+
416
+ ```tsx
417
+ import { DataTable, Button, Tabs, TabList, TabTrigger } from '@jacshuo/onyx';
418
+
419
+ // Compact for mobile
420
+ <DataTable columns={columns} data={rows} size="sm" />
421
+
422
+ // Comfortable for desktop
423
+ <DataTable columns={columns} data={rows} size="lg" />
424
+
425
+ // Mix sizes to match your layout density
426
+ <Tabs defaultValue="a">
427
+ <TabList size="sm"> {/* compact tabs */}
428
+ <TabTrigger value="a">Tab A</TabTrigger>
429
+ <TabTrigger value="b">Tab B</TabTrigger>
430
+ </TabList>
431
+ </Tabs>
432
+ ```
433
+
434
+ ### Token Overrides at Breakpoints
435
+
436
+ All sizing and spacing values are CSS custom properties. Override them at any breakpoint for precisely tuned responsive behavior:
437
+
438
+ ```css
439
+ /* Default (mobile-first) form layout */
440
+ :root {
441
+ --form-label-w-md: 5rem;
442
+ --form-item-gap-md: 0.5rem;
443
+ --form-row-gap-md: 0.75rem;
444
+ }
445
+
446
+ /* Wider label column and increased spacing on desktop */
447
+ @media (min-width: 768px) {
448
+ :root {
449
+ --form-label-w-md: 7rem;
450
+ --form-item-gap-md: 0.75rem;
451
+ --form-row-gap-md: 1.25rem;
452
+ }
453
+ }
454
+ ```
455
+
456
+ ---
457
+
318
458
  ## Usage Examples
319
459
 
320
460
  ### Button
@@ -406,6 +546,50 @@ function NotifyButton() {
406
546
  }
407
547
  ```
408
548
 
549
+ ### NavLink
550
+
551
+ ```tsx
552
+ import { NavLink } from '@jacshuo/onyx';
553
+
554
+ {/* Internal link */}
555
+ <NavLink href="/about">About</NavLink>
556
+
557
+ {/* Auto-detected external — shows icon + sets target="_blank" automatically */}
558
+ <NavLink href="https://github.com">GitHub</NavLink>
559
+
560
+ {/* Suppress external icon */}
561
+ <NavLink href="https://example.com" external={false}>Example</NavLink>
562
+
563
+ {/* Variants */}
564
+ <NavLink href="/docs" intent="secondary" size="lg" underline="always">Docs</NavLink>
565
+ ```
566
+
567
+ ### CodeBlock
568
+
569
+ ```tsx
570
+ import { CodeBlock } from '@jacshuo/onyx';
571
+
572
+ {/* Basic syntax highlighting */}
573
+ <CodeBlock code={`const x = 42;`} language="typescript" />
574
+
575
+ {/* With line numbers */}
576
+ <CodeBlock code={sourceCode} language="tsx" lineNumbers />
577
+
578
+ {/* Live editable editor */}
579
+ function Editor() {
580
+ const [code, setCode] = useState('console.log("hello")');
581
+ return (
582
+ <CodeBlock
583
+ code={code}
584
+ language="typescript"
585
+ editable
586
+ onCodeChange={setCode}
587
+ lineNumbers
588
+ />
589
+ );
590
+ }
591
+ ```
592
+
409
593
  ### MiniPlayer
410
594
 
411
595
  ```tsx
@@ -545,29 +729,6 @@ jac-ui/
545
729
 
546
730
  ---
547
731
 
548
- ## Roadmap
549
-
550
- ### Responsiveness & Mobile Support
551
-
552
- > **Current status: not supported**
553
-
554
- Onyx is a **desktop-first** library. All components are currently designed for desktop-sized viewports and pointer-based interactions. Responsive / mobile layouts are **not yet available**.
555
-
556
- This is a personal side project, and my day job keeps me quite busy. My primary interest lies in **cross-platform desktop application development** (Electron + web), which is where I spend most of my limited spare time. As a result, responsive design and mobile device support have not been prioritized — and there is **no concrete timeline** for adding them.
557
-
558
- That said, responsiveness is absolutely a worthwhile direction. If this is something you need, **pull requests are very welcome!** The rough areas that would benefit from community contributions include:
559
-
560
- - **Fluid layouts** — Making `Card`, `DataTable`, `Dialog`, etc. adapt to narrow viewports via container queries or relative units.
561
- - **Responsive typography** — Auto-scaling font sizes and spacing based on viewport width.
562
- - **Touch-friendly interactions** — Larger tap targets, swipe gestures for `CinePlayer` / `MiniPlayer`, touch-optimized drag handles.
563
- - **Adaptive component variants** — `DataTable` → card list on mobile, `SideNav` → slide-over drawer, `Header` → hamburger menu.
564
- - **Breakpoint-aware props** — e.g., `<Button size={{ base: 'sm', md: 'lg' }}>` aligned with Tailwind CSS v4 breakpoints.
565
- - **Mobile-first CSS refactor** — Layering complexity at wider breakpoints instead of overriding desktop defaults.
566
-
567
- If you're interested in contributing any of these, check out the [Contributing](#contributing) section — I'd love the help! 🙌
568
-
569
- ---
570
-
571
732
  ## Contributing
572
733
 
573
734
  1. Fork the repository