@olwiba/ui 0.2.24 → 0.2.26

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 (209) hide show
  1. package/content/docs/app/app-shell.mdx +71 -0
  2. package/content/docs/app/auth-section.mdx +73 -0
  3. package/content/docs/app/billing-panel.mdx +38 -0
  4. package/content/docs/app/empty-state.mdx +47 -0
  5. package/content/docs/app/error-page.mdx +31 -0
  6. package/content/docs/app/index.mdx +13 -0
  7. package/content/docs/app/meta.json +4 -0
  8. package/content/docs/app/onboarding-wizard.mdx +41 -0
  9. package/content/docs/app/settings-section.mdx +37 -0
  10. package/content/docs/app/team-members-panel.mdx +35 -0
  11. package/content/docs/app/update-banner.mdx +43 -0
  12. package/content/docs/components/activity-feed.mdx +42 -0
  13. package/content/docs/components/chart.mdx +47 -0
  14. package/content/docs/components/command-menu.mdx +41 -0
  15. package/content/docs/components/confirm-dialog.mdx +26 -0
  16. package/content/docs/components/context-menu.mdx +26 -0
  17. package/content/docs/components/data-table.mdx +40 -0
  18. package/content/docs/components/dock.mdx +26 -0
  19. package/content/docs/components/feature-card.mdx +26 -0
  20. package/content/docs/components/file-upload.mdx +35 -0
  21. package/content/docs/components/full-page-spinner.mdx +44 -0
  22. package/content/docs/components/glass-card.mdx +26 -0
  23. package/content/docs/components/image-card.mdx +26 -0
  24. package/content/docs/components/index.mdx +49 -0
  25. package/content/docs/components/load-more.mdx +34 -0
  26. package/content/docs/components/meta.json +35 -0
  27. package/content/docs/components/notifications-popover.mdx +34 -0
  28. package/content/docs/components/notify.mdx +40 -0
  29. package/content/docs/components/olwiba-ui-context.mdx +69 -0
  30. package/content/docs/components/page-header.mdx +42 -0
  31. package/content/docs/components/pricing-card.mdx +26 -0
  32. package/content/docs/components/register-hotkeys.mdx +50 -0
  33. package/content/docs/components/root-error-fallback.mdx +39 -0
  34. package/content/docs/components/spotlight.mdx +26 -0
  35. package/content/docs/components/stat-card.mdx +26 -0
  36. package/content/docs/components/suspensed.mdx +42 -0
  37. package/content/docs/components/testimonial-card.mdx +26 -0
  38. package/content/docs/components/theme-color-updater.mdx +40 -0
  39. package/content/docs/components/theme-switch-minimal.mdx +32 -0
  40. package/content/docs/components/version-banner.mdx +44 -0
  41. package/content/docs/email/action-email.mdx +62 -0
  42. package/content/docs/email/email-layout.mdx +58 -0
  43. package/content/docs/email/email-link-fallback.mdx +46 -0
  44. package/content/docs/email/index.mdx +32 -0
  45. package/content/docs/email/meta.json +10 -0
  46. package/content/docs/email/notice-email.mdx +51 -0
  47. package/content/docs/hooks/index.mdx +21 -0
  48. package/content/docs/hooks/meta.json +16 -0
  49. package/content/docs/hooks/use-confirm.mdx +81 -0
  50. package/content/docs/hooks/use-controlled-open.mdx +53 -0
  51. package/content/docs/hooks/use-copy-to-clipboard.mdx +26 -0
  52. package/content/docs/hooks/use-debounce.mdx +26 -0
  53. package/content/docs/hooks/use-intersection-observer.mdx +26 -0
  54. package/content/docs/hooks/use-local-storage.mdx +26 -0
  55. package/content/docs/hooks/use-media-query.mdx +26 -0
  56. package/content/docs/hooks/use-mounted.mdx +39 -0
  57. package/content/docs/hooks/use-pagination.mdx +26 -0
  58. package/content/docs/hooks/use-scrolled-past.mdx +44 -0
  59. package/content/docs/index.mdx +68 -0
  60. package/content/docs/marketing/contact-section.mdx +16 -0
  61. package/content/docs/marketing/cta-section.mdx +31 -0
  62. package/content/docs/marketing/faq-section.mdx +16 -0
  63. package/content/docs/marketing/features-section.mdx +23 -0
  64. package/content/docs/marketing/footer.mdx +16 -0
  65. package/content/docs/marketing/hero-section.mdx +16 -0
  66. package/content/docs/marketing/index.mdx +22 -0
  67. package/content/docs/marketing/meta.json +20 -0
  68. package/content/docs/marketing/navbar.mdx +16 -0
  69. package/content/docs/marketing/newsletter-section.mdx +16 -0
  70. package/content/docs/marketing/post-list.mdx +32 -0
  71. package/content/docs/marketing/pricing-section.mdx +16 -0
  72. package/content/docs/marketing/stats-section.mdx +16 -0
  73. package/content/docs/marketing/steps-section.mdx +60 -0
  74. package/content/docs/marketing/team-section.mdx +16 -0
  75. package/content/docs/marketing/testimonials-section.mdx +16 -0
  76. package/content/docs/mechanics/carousel.mdx +42 -0
  77. package/content/docs/mechanics/index.mdx +11 -0
  78. package/content/docs/mechanics/meta.json +4 -0
  79. package/content/docs/mechanics/sortable.mdx +44 -0
  80. package/content/docs/meta.json +4 -0
  81. package/content/docs/motion/animated-swap.mdx +75 -0
  82. package/content/docs/motion/count-up.mdx +31 -0
  83. package/content/docs/motion/fade-in.mdx +34 -0
  84. package/content/docs/motion/index.mdx +12 -0
  85. package/content/docs/motion/meta.json +4 -0
  86. package/content/docs/motion/page-transition.mdx +29 -0
  87. package/content/docs/motion/stagger-children.mdx +31 -0
  88. package/content/docs/overlays/index.mdx +9 -0
  89. package/content/docs/overlays/meta.json +4 -0
  90. package/content/docs/overlays/overlay.mdx +60 -0
  91. package/content/docs/overlays/underlay.mdx +56 -0
  92. package/dist/email/index.d.ts +8 -1
  93. package/dist/email/index.js +3 -3
  94. package/dist/email/index.js.map +1 -1
  95. package/dist/index.d.ts +51 -3
  96. package/dist/index.js +40 -16
  97. package/dist/index.js.map +1 -1
  98. package/docs-manifest.json +253 -0
  99. package/package.json +17 -9
  100. package/site/demos/action-email.tsx +6 -0
  101. package/site/demos/activity-feed.tsx +42 -0
  102. package/site/demos/animated-swap.tsx +42 -0
  103. package/site/demos/app-shell.tsx +47 -0
  104. package/site/demos/app-ui-page.tsx +9 -0
  105. package/site/demos/application-sidebar-block.tsx +9 -0
  106. package/site/demos/auth-section.tsx +15 -0
  107. package/site/demos/auth-split-block.tsx +9 -0
  108. package/site/demos/billing-page.tsx +157 -0
  109. package/site/demos/billing-panel.tsx +26 -0
  110. package/site/demos/carousel.tsx +34 -0
  111. package/site/demos/chart.tsx +55 -0
  112. package/site/demos/command-menu.tsx +39 -0
  113. package/site/demos/confirm-dialog.tsx +27 -0
  114. package/site/demos/contact-form-block.tsx +3 -0
  115. package/site/demos/contact-section.tsx +2 -0
  116. package/site/demos/context-menu.tsx +30 -0
  117. package/site/demos/count-up.tsx +23 -0
  118. package/site/demos/cta-section.tsx +6 -0
  119. package/site/demos/dashboard-overview-block.tsx +9 -0
  120. package/site/demos/dashboard-shell-block.tsx +10 -0
  121. package/site/demos/data-table.tsx +47 -0
  122. package/site/demos/demo-brand.tsx +23 -0
  123. package/site/demos/dock.tsx +20 -0
  124. package/site/demos/document-sidebar-block.tsx +9 -0
  125. package/site/demos/email-examples.tsx +58 -0
  126. package/site/demos/email-frame.tsx +50 -0
  127. package/site/demos/email-layout.tsx +6 -0
  128. package/site/demos/email-link-fallback.tsx +6 -0
  129. package/site/demos/email-previews.generated.ts +11 -0
  130. package/site/demos/empty-state-block.tsx +3 -0
  131. package/site/demos/empty-state.tsx +23 -0
  132. package/site/demos/error-page.tsx +5 -0
  133. package/site/demos/fade-in.tsx +18 -0
  134. package/site/demos/faq-section.tsx +6 -0
  135. package/site/demos/feature-card.tsx +13 -0
  136. package/site/demos/features-section.tsx +6 -0
  137. package/site/demos/file-upload.tsx +16 -0
  138. package/site/demos/footer.tsx +42 -0
  139. package/site/demos/full-page-spinner.tsx +9 -0
  140. package/site/demos/glass-card.tsx +14 -0
  141. package/site/demos/glow-effect.tsx +3 -0
  142. package/site/demos/gradient-background.tsx +3 -0
  143. package/site/demos/grid-pattern.tsx +3 -0
  144. package/site/demos/hero-section.tsx +6 -0
  145. package/site/demos/image-card.tsx +17 -0
  146. package/site/demos/login-block.tsx +9 -0
  147. package/site/demos/marketing-cta-block.tsx +3 -0
  148. package/site/demos/marketing-demo-data.tsx +114 -0
  149. package/site/demos/marketing-faq-block.tsx +3 -0
  150. package/site/demos/marketing-features-block.tsx +3 -0
  151. package/site/demos/marketing-footer-block.tsx +3 -0
  152. package/site/demos/marketing-hero-block.tsx +10 -0
  153. package/site/demos/marketing-nav-block.tsx +3 -0
  154. package/site/demos/marketing-newsletter-block.tsx +3 -0
  155. package/site/demos/marketing-page.tsx +52 -0
  156. package/site/demos/marketing-pricing-block.tsx +3 -0
  157. package/site/demos/marketing-stats-block.tsx +3 -0
  158. package/site/demos/marketing-team-block.tsx +3 -0
  159. package/site/demos/marketing-testimonials-block.tsx +3 -0
  160. package/site/demos/navbar.tsx +32 -0
  161. package/site/demos/newsletter-section.tsx +2 -0
  162. package/site/demos/noise-overlay.tsx +3 -0
  163. package/site/demos/not-found-block.tsx +3 -0
  164. package/site/demos/notice-email.tsx +6 -0
  165. package/site/demos/notifications-popover.tsx +27 -0
  166. package/site/demos/notify.tsx +44 -0
  167. package/site/demos/olwiba-ui-context.tsx +51 -0
  168. package/site/demos/onboarding-block.tsx +3 -0
  169. package/site/demos/onboarding-wizard.tsx +43 -0
  170. package/site/demos/overlay.tsx +72 -0
  171. package/site/demos/page-header.tsx +15 -0
  172. package/site/demos/page-transition.tsx +34 -0
  173. package/site/demos/post-list.tsx +24 -0
  174. package/site/demos/pricing-card.tsx +27 -0
  175. package/site/demos/pricing-section.tsx +6 -0
  176. package/site/demos/register-hotkeys.tsx +39 -0
  177. package/site/demos/root-error-fallback.tsx +28 -0
  178. package/site/demos/settings-layout-block.tsx +3 -0
  179. package/site/demos/settings-section.tsx +22 -0
  180. package/site/demos/sign-in-page.tsx +10 -0
  181. package/site/demos/sortable.tsx +30 -0
  182. package/site/demos/spotlight.tsx +29 -0
  183. package/site/demos/stagger-children.tsx +16 -0
  184. package/site/demos/stat-card.tsx +12 -0
  185. package/site/demos/stats-section.tsx +6 -0
  186. package/site/demos/steps-section.tsx +66 -0
  187. package/site/demos/suspensed.tsx +31 -0
  188. package/site/demos/team-members-panel.tsx +26 -0
  189. package/site/demos/team-section.tsx +2 -0
  190. package/site/demos/testimonial-card.tsx +17 -0
  191. package/site/demos/testimonials-section.tsx +6 -0
  192. package/site/demos/theme-color-updater.tsx +32 -0
  193. package/site/demos/theme-switch-minimal.tsx +10 -0
  194. package/site/demos/underlay.tsx +74 -0
  195. package/site/demos/update-banner.tsx +31 -0
  196. package/site/demos/use-copy-to-clipboard.tsx +21 -0
  197. package/site/demos/use-debounce.tsx +25 -0
  198. package/site/demos/use-intersection-observer.tsx +32 -0
  199. package/site/demos/use-local-storage.tsx +22 -0
  200. package/site/demos/use-media-query.tsx +31 -0
  201. package/site/demos/use-pagination.tsx +31 -0
  202. package/site/demos/user-profile-block.tsx +3 -0
  203. package/site/demos/version-banner.tsx +27 -0
  204. package/src/components/Chart.tsx +38 -7
  205. package/src/components/DataTable.tsx +56 -8
  206. package/src/components/Notify.tsx +32 -1
  207. package/src/email/EmailLinkFallback.tsx +7 -1
  208. package/src/email/index.ts +3 -0
  209. package/src/marketing/Footer.tsx +7 -1
@@ -0,0 +1,11 @@
1
+ ---
2
+ title: Mechanics
3
+ description: Behavior wrappers — components you put other components inside to gain an interaction pattern.
4
+ ---
5
+
6
+ Mechanics are the inverse of blocks: a block gives you content with a fixed behavior, a mechanic gives you behavior with no opinion about content. Put any components inside one and it plays them with its interaction pattern.
7
+
8
+ | Component | Description |
9
+ |-----------|-------------|
10
+ | `Carousel` | Plays children as slides in a scroll-snap track with prev/next controls |
11
+ | `Sortable` | Makes children drag-to-reorder by pointer or keyboard |
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Mechanics",
3
+ "pages": ["index", "carousel", "sortable"]
4
+ }
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Sortable
3
+ description: Drag-to-reorder behavior — wrap any children and they become sortable by pointer or keyboard.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="sortable" />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { Sortable } from "@olwiba/ui";
22
+
23
+ const [order, setOrder] = React.useState(tasks.map((t) => t.id));
24
+
25
+ <Sortable items={order} onReorder={setOrder}>
26
+ {order.map((id) => <TaskRow key={id} task={taskById[id]} />)}
27
+ </Sortable>
28
+ ```
29
+
30
+ Sortable is a mechanic: it has no opinion about what the items look like — rows, cards, or tiles all work. It's controlled — `items` is the id order, `onReorder` hands you the new order after a drag, and you re-render children in that order. Pairing is positional: the i-th child gets the i-th id.
31
+
32
+ `direction="horizontal"` for rows of chips or columns, `direction="grid"` for tile boards (add your grid columns via `className`):
33
+
34
+ ```tsx
35
+ <Sortable items={order} onReorder={setOrder} direction="grid" className="grid-cols-3">
36
+ {order.map((id) => <Tile key={id} id={id} />)}
37
+ </Sortable>
38
+ ```
39
+
40
+ Keyboard reordering works out of the box — focus an item, space to lift, arrows to move, space to drop.
41
+
42
+ ## API Reference
43
+
44
+ <APIReference name="Sortable" props={[]} />
@@ -0,0 +1,4 @@
1
+ {
2
+ "root": true,
3
+ "pages": ["index", "app", "marketing", "email", "overlays", "motion", "mechanics", "components", "hooks"]
4
+ }
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: AnimatedSwap
3
+ description: Animates the replacement of any content when its swap key changes — a rolling price, a crossfading chart, a sliding status pill.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="animated-swap" />
11
+
12
+ ## Usage
13
+
14
+ `swapKey` is what triggers the animation. The component can't see inside `children`,
15
+ so re-rendering with different content under the same key updates in place, silently.
16
+
17
+ ```tsx
18
+ import { AnimatedSwap } from "@olwiba/ui";
19
+
20
+ <AnimatedSwap swapKey={price} effect="roll" className="text-4xl font-bold">
21
+ {price}
22
+ </AnimatedSwap>
23
+ ```
24
+
25
+ Any content works, not just text:
26
+
27
+ ```tsx
28
+ <AnimatedSwap swapKey={range} effect="fade">
29
+ <RevenueChart range={range} />
30
+ </AnimatedSwap>
31
+ ```
32
+
33
+ ## Effects
34
+
35
+ | Effect | Behaviour |
36
+ |--------|-----------|
37
+ | `roll` | Odometer. The old value is displaced upward as the new one rises into its place. No fade — the values stay solid, which is what makes it read as a mechanism. |
38
+ | `fade` | Crossfade, no movement. Safe inside a layout that's also reflowing. |
39
+ | `slide` | Short horizontal travel carried by opacity. Needs no clipping, so it won't crop a ring or shadow. |
40
+ | `none` | Instant swap. |
41
+
42
+ Omit `effect` and the current `OlwibaUIProvider` mode picks one:
43
+ `default` → `fade`, `playful` → `roll`, `smooth` → `slide`. An explicit `effect`
44
+ always wins. Under `prefers-reduced-motion: reduce` every effect degrades to an
45
+ instant swap.
46
+
47
+ ## Custom effects
48
+
49
+ `effect` also takes a spec object, so you aren't limited to the named set. A
50
+ transition is just two layers with a start and an end style:
51
+
52
+ ```tsx
53
+ <AnimatedSwap
54
+ swapKey={status}
55
+ effect={{
56
+ clip: false,
57
+ duration: 400,
58
+ easing: "cubic-bezier(0.34, 1.56, 0.64, 1)",
59
+ enter: { from: { opacity: 0, transform: "scale(0.8)" }, to: { opacity: 1, transform: "scale(1)" } },
60
+ exit: { from: { opacity: 1, transform: "scale(1)" }, to: { opacity: 0, transform: "scale(1.2)" } },
61
+ }}
62
+ >
63
+ <StatusPill status={status} />
64
+ </AnimatedSwap>
65
+ ```
66
+
67
+ ## API Reference
68
+
69
+ <APIReference name="AnimatedSwap" props={[
70
+ { name: "swapKey", type: "React.Key", description: "Changing this triggers the animation. Nothing else does." },
71
+ { name: "children", type: "ReactNode", description: "The content being swapped." },
72
+ { name: "effect", type: "\"roll\" | \"fade\" | \"slide\" | \"none\" | AnimatedSwapSpec", default: "from UI mode", description: "Named effect, or a spec of your own." },
73
+ { name: "duration", type: "number", description: "Overrides the effect's duration, in ms." },
74
+ { name: "className", type: "string", description: "Class applied to the wrapper. Both layers inherit its type styles." },
75
+ ]} />
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: CountUp
3
+ description: Animates a number from 0 to a target value when it enters the viewport.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="count-up" />
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { CountUp } from "@olwiba/ui";
16
+
17
+ <CountUp to={1000} />
18
+ <CountUp to={99.9} decimals={1} suffix="%" duration={2} />
19
+ ```
20
+
21
+ ## API Reference
22
+
23
+ <APIReference name="CountUp" props={[
24
+ { name: "to", type: "number", description: "Target value to count up to." },
25
+ { name: "from", type: "number", default: "0", description: "Starting value." },
26
+ { name: "decimals", type: "number", default: "0", description: "Number of decimal places." },
27
+ { name: "duration", type: "number", default: "1.5", description: "Animation duration (seconds)." },
28
+ { name: "prefix", type: "string", description: "String prepended to the number." },
29
+ { name: "suffix", type: "string", description: "String appended to the number." },
30
+ { name: "className", type: "string", description: "Class applied to the span." },
31
+ ]} />
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: FadeIn
3
+ description: Fade and slide entrance animation wrapper.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="fade-in" />
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { FadeIn } from "@olwiba/ui";
16
+
17
+ <FadeIn>
18
+ <MyContent />
19
+ </FadeIn>
20
+
21
+ <FadeIn delay={0.2} duration={0.5} direction="up">
22
+ <MyContent />
23
+ </FadeIn>
24
+ ```
25
+
26
+ ## API Reference
27
+
28
+ <APIReference name="FadeIn" props={[
29
+ { name: "children", type: "ReactNode", description: "Content to animate in." },
30
+ { name: "delay", type: "number", default: "0", description: "Delay before the animation starts (seconds)." },
31
+ { name: "duration", type: "number", default: "0.4", description: "Animation duration (seconds)." },
32
+ { name: "direction", type: '"up" | "down" | "left" | "right" | "none"', default: '"up"', description: "Slide direction of the entrance." },
33
+ { name: "className", type: "string", description: "Class applied to the wrapper." },
34
+ ]} />
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Motion
3
+ description: Lightweight animation primitives — entrance effects, staggered lists, number counters, and page transitions.
4
+ ---
5
+
6
+ | Component | Description |
7
+ |-----------|-------------|
8
+ | `FadeIn` | Fade and slide entrance animation |
9
+ | `StaggerChildren` | Staggers `FadeIn` across a list of children |
10
+ | `CountUp` | Animates a number from 0 to a target value |
11
+ | `AnimatedSwap` | Animates the replacement of any content when its swap key changes |
12
+ | `PageTransition` | Wraps route content in an entrance animation |
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Motion",
3
+ "pages": ["index", "fade-in", "stagger-children", "count-up", "animated-swap", "page-transition"]
4
+ }
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: PageTransition
3
+ description: Wraps route content in a fade entrance animation — drop it around your route component output.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="page-transition" />
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { PageTransition } from "@olwiba/ui";
16
+
17
+ // In a TanStack Router or Next.js layout
18
+ export default function Layout({ children }) {
19
+ return <PageTransition>{children}</PageTransition>;
20
+ }
21
+ ```
22
+
23
+ ## API Reference
24
+
25
+ <APIReference name="PageTransition" props={[
26
+ { name: "children", type: "ReactNode", description: "Route content to animate." },
27
+ { name: "duration", type: "number", default: "0.3", description: "Animation duration (seconds)." },
28
+ { name: "className", type: "string", description: "Class applied to the wrapper." },
29
+ ]} />
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: StaggerChildren
3
+ description: Wraps a list of children and staggers their FadeIn entrance animations.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <Sandbox id="stagger-children" />
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { StaggerChildren } from "@olwiba/ui";
16
+
17
+ <StaggerChildren stagger={0.1}>
18
+ <Card />
19
+ <Card />
20
+ <Card />
21
+ </StaggerChildren>
22
+ ```
23
+
24
+ ## API Reference
25
+
26
+ <APIReference name="StaggerChildren" props={[
27
+ { name: "children", type: "ReactNode", description: "Children to stagger." },
28
+ { name: "stagger", type: "number", default: "0.1", description: "Delay between each child (seconds)." },
29
+ { name: "initialDelay", type: "number", default: "0", description: "Delay before the first child animates." },
30
+ { name: "className", type: "string", description: "Class applied to the wrapper." },
31
+ ]} />
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: Layering
3
+ description: Components for adding depth — underlays sit behind content, overlays sit in front.
4
+ ---
5
+
6
+ | Component | Variants |
7
+ |-----------|----------|
8
+ | `Underlay` | `dots`, `lines`, `cross`, `glow` |
9
+ | `Overlay` | `dim`, `scrim`, `loading` |
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Layering",
3
+ "pages": ["index", "underlay", "overlay"]
4
+ }
@@ -0,0 +1,60 @@
1
+ ---
2
+ title: Overlay
3
+ description: Dim, scrim, and loading overlays that sit in front of content inside a container.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <ComponentPreview name="overlay" noPadding />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { Overlay } from "@olwiba/ui";
22
+
23
+ // Overlay sits on top — place after your content in a relative container
24
+ <div className="relative overflow-hidden rounded-xl">
25
+ {/* your content */}
26
+ <Overlay variant="loading" label="Saving..." />
27
+ </div>
28
+
29
+ // Dim — semi-transparent wash over content
30
+ <Overlay variant="dim" opacity={0.5} />
31
+
32
+ // Scrim — gradient fade from an edge (great for image text legibility)
33
+ <Overlay variant="scrim" direction="bottom" />
34
+ ```
35
+
36
+ ## API Reference
37
+
38
+ <APIReference name="Overlay" props={[
39
+ { name: "variant", type: '"dim" | "scrim" | "loading"', description: "Selects the overlay treatment." },
40
+ { name: "className", type: "string", description: "Class applied to the root element." },
41
+ ]} />
42
+
43
+ ### Dim variant
44
+
45
+ <APIReference name="Overlay (dim)" props={[
46
+ { name: "opacity", type: "number", default: "0.5", description: "Opacity of the background wash." },
47
+ ]} />
48
+
49
+ ### Scrim variant
50
+
51
+ <APIReference name="Overlay (scrim)" props={[
52
+ { name: "direction", type: '"top" | "bottom" | "left" | "right"', default: '"bottom"', description: "Direction the gradient fades toward." },
53
+ { name: "color", type: "string", default: '"var(--background)"', description: "The opaque color the scrim fades to." },
54
+ ]} />
55
+
56
+ ### Loading variant
57
+
58
+ <APIReference name="Overlay (loading)" props={[
59
+ { name: "label", type: "string", description: "Optional status label shown below the spinner." },
60
+ ]} />
@@ -0,0 +1,56 @@
1
+ ---
2
+ title: Underlay
3
+ description: Grid patterns and glow effects that sit behind content inside a container.
4
+ ---
5
+
6
+ <div className="flex flex-col md:flex-row items-center justify-start gap-2 mb-2">
7
+ <CopyCommandButton command="bun add @olwiba/ui" />
8
+ </div>
9
+
10
+ <ComponentPreview name="underlay" noPadding />
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @olwiba/ui
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { Underlay } from "@olwiba/ui";
22
+
23
+ // Place inside a relative container — content goes on top with z-10
24
+ <div className="relative overflow-hidden rounded-xl">
25
+ <Underlay variant="dots" />
26
+ <div className="relative z-10 p-8">Content</div>
27
+ </div>
28
+
29
+ // Glow — follows cursor when followCursor is true
30
+ <div className="relative overflow-hidden rounded-xl">
31
+ <Underlay variant="glow" size={400} followCursor />
32
+ <div className="relative z-10 p-8">Hover me</div>
33
+ </div>
34
+ ```
35
+
36
+ ## API Reference
37
+
38
+ <APIReference name="Underlay" props={[
39
+ { name: "variant", type: '"dots" | "lines" | "cross" | "glow"', description: "Selects the visual treatment." },
40
+ { name: "className", type: "string", description: "Class applied to the root element." },
41
+ ]} />
42
+
43
+ ### Grid variants (`dots`, `lines`, `cross`)
44
+
45
+ <APIReference name="Underlay (grid)" props={[
46
+ { name: "size", type: "number", default: "24", description: "Pattern tile size in pixels." },
47
+ ]} />
48
+
49
+ ### Glow variant
50
+
51
+ <APIReference name="Underlay (glow)" props={[
52
+ { name: "size", type: "number", default: "400", description: "Diameter of the glow orb in pixels." },
53
+ { name: "color", type: "string", default: '"color-mix(in oklch, var(--primary) 45%, transparent)"', description: "Glow color." },
54
+ { name: "followCursor", type: "boolean", default: "false", description: "Tracks cursor position within the container." },
55
+ { name: "blur", type: '"sm" | "md" | "lg" | "xl"', default: '"lg"', description: "Blur intensity of the glow." },
56
+ ]} />
@@ -32,4 +32,11 @@ interface EmailLayoutProps {
32
32
  /** Branded email shell — UI block composed from CN primitives. */
33
33
  declare function EmailLayout({ preview, appName, brandColor, children, footer, }: EmailLayoutProps): react_jsx_runtime.JSX.Element;
34
34
 
35
- export { ActionEmail, type ActionEmailProps, EmailLayout, type EmailLayoutProps, NoticeEmail, type NoticeEmailProps };
35
+ interface EmailLinkFallbackProps {
36
+ actionUrl: string;
37
+ label?: string;
38
+ brandColor?: string;
39
+ }
40
+ declare function EmailLinkFallback({ actionUrl, label, brandColor, }: EmailLinkFallbackProps): react_jsx_runtime.JSX.Element;
41
+
42
+ export { ActionEmail, type ActionEmailProps, EmailLayout, type EmailLayoutProps, EmailLinkFallback, type EmailLinkFallbackProps, NoticeEmail, type NoticeEmailProps };
@@ -1,4 +1,4 @@
1
- import { EmailRoot, EmailHead, EmailPreview, EmailBody, emailTheme, EmailContainer, EmailSection, EmailText, EmailHeading, EmailButton, EmailLink } from '@olwiba/cn/email';
1
+ import { EmailRoot, EmailHead, EmailPreview, EmailBody, emailTheme, EmailContainer, EmailSection, EmailText, EmailLink, EmailHeading, EmailButton } from '@olwiba/cn/email';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
 
4
4
  // src/email/ActionEmail.tsx
@@ -97,7 +97,7 @@ function EmailLinkFallback({
97
97
  }) {
98
98
  return /* @__PURE__ */ jsxs(Fragment, { children: [
99
99
  /* @__PURE__ */ jsx(EmailText, { variant: "caption", style: { margin: "24px 0 8px" }, children: label }),
100
- /* @__PURE__ */ jsx(EmailText, { style: { margin: 0 }, children: /* @__PURE__ */ jsx(EmailLink, { href: actionUrl, brandColor, children: actionUrl }) })
100
+ /* @__PURE__ */ jsx(EmailText, { style: { margin: 0 }, children: /* @__PURE__ */ jsx(EmailLink, { href: actionUrl, style: brandColor ? { color: brandColor } : void 0, children: actionUrl }) })
101
101
  ] });
102
102
  }
103
103
  function ActionEmail({
@@ -130,6 +130,6 @@ function NoticeEmail({
130
130
  ] });
131
131
  }
132
132
 
133
- export { ActionEmail, EmailLayout, NoticeEmail };
133
+ export { ActionEmail, EmailLayout, EmailLinkFallback, NoticeEmail };
134
134
  //# sourceMappingURL=index.js.map
135
135
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/email/EmailLayout.tsx","../../src/email/EmailLinkFallback.tsx","../../src/email/ActionEmail.tsx","../../src/email/NoticeEmail.tsx"],"names":["jsxs","jsx","EmailText","emailTheme","EmailHeading"],"mappings":"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","file":"index.js","sourcesContent":["import type { ReactNode } from 'react';\nimport {\n EmailBody,\n EmailContainer,\n EmailHead,\n EmailPreview,\n EmailRoot,\n EmailSection,\n EmailText,\n emailTheme,\n} from '@olwiba/cn/email';\n\nexport interface EmailLayoutProps {\n preview?: string;\n appName: string;\n brandColor?: string;\n children: ReactNode;\n footer?: ReactNode;\n}\n\n/** Branded email shell — UI block composed from CN primitives. */\nexport function EmailLayout({\n preview,\n appName,\n brandColor = emailTheme.defaultBrandColor,\n children,\n footer,\n}: EmailLayoutProps) {\n const year = new Date().getFullYear();\n\n return (\n <EmailRoot>\n <EmailHead />\n {preview ? <EmailPreview>{preview}</EmailPreview> : null}\n <EmailBody\n style={{\n backgroundColor: emailTheme.pageBackground,\n fontFamily: emailTheme.fontFamily,\n margin: 0,\n padding: '24px 0',\n }}\n >\n <EmailContainer\n style={{\n maxWidth: '560px',\n margin: '0 auto',\n backgroundColor: emailTheme.cardBackground,\n borderRadius: '16px',\n overflow: 'hidden',\n border: `1px solid ${emailTheme.cardBorder}`,\n }}\n >\n <EmailSection\n style={{\n padding: '24px 32px',\n borderBottom: `1px solid ${emailTheme.cardBorder}`,\n }}\n >\n <EmailText\n style={{\n margin: 0,\n fontSize: '18px',\n fontWeight: 600,\n color: brandColor,\n }}\n >\n {appName}\n </EmailText>\n </EmailSection>\n\n <EmailSection style={{ padding: '32px' }}>{children}</EmailSection>\n\n {footer ?? (\n <EmailSection\n style={{\n padding: '20px 32px',\n borderTop: `1px solid ${emailTheme.cardBorder}`,\n backgroundColor: emailTheme.mutedBackground,\n }}\n >\n <EmailText\n variant=\"caption\"\n style={{\n margin: 0,\n textAlign: 'center',\n }}\n >\n © {year} {appName}. All rights reserved.\n </EmailText>\n </EmailSection>\n )}\n </EmailContainer>\n </EmailBody>\n </EmailRoot>\n );\n}\n","import { EmailLink, EmailText } from '@olwiba/cn/email';\n\nexport interface EmailLinkFallbackProps {\n actionUrl: string;\n label?: string;\n brandColor?: string;\n}\n\nexport function EmailLinkFallback({\n actionUrl,\n label = 'Or copy and paste this link into your browser:',\n brandColor,\n}: EmailLinkFallbackProps) {\n return (\n <>\n <EmailText variant=\"caption\" style={{ margin: '24px 0 8px' }}>\n {label}\n </EmailText>\n <EmailText style={{ margin: 0 }}>\n <EmailLink href={actionUrl} brandColor={brandColor}>\n {actionUrl}\n </EmailLink>\n </EmailText>\n </>\n );\n}\n","import {\n EmailButton,\n EmailHeading,\n EmailText,\n emailTheme,\n} from '@olwiba/cn/email';\nimport { EmailLayout } from './EmailLayout';\nimport { EmailLinkFallback } from './EmailLinkFallback';\n\nexport interface ActionEmailProps {\n appName: string;\n preview: string;\n heading: string;\n description: string;\n actionLabel: string;\n actionUrl: string;\n brandColor?: string;\n showLinkFallback?: boolean;\n}\n\nexport function ActionEmail({\n appName,\n preview,\n heading,\n description,\n actionLabel,\n actionUrl,\n brandColor = emailTheme.defaultBrandColor,\n showLinkFallback = true,\n}: ActionEmailProps) {\n return (\n <EmailLayout preview={preview} appName={appName} brandColor={brandColor}>\n <EmailHeading>{heading}</EmailHeading>\n <EmailText variant=\"muted\" style={{ margin: '0 0 24px' }}>\n {description}\n </EmailText>\n <EmailButton href={actionUrl} label={actionLabel} brandColor={brandColor} />\n {showLinkFallback ? (\n <EmailLinkFallback actionUrl={actionUrl} brandColor={brandColor} />\n ) : null}\n </EmailLayout>\n );\n}\n","import {\n EmailHeading,\n EmailText,\n emailTheme,\n} from '@olwiba/cn/email';\nimport { EmailLayout } from './EmailLayout';\n\nexport interface NoticeEmailProps {\n appName: string;\n preview: string;\n heading: string;\n body: string;\n brandColor?: string;\n}\n\nexport function NoticeEmail({\n appName,\n preview,\n heading,\n body,\n brandColor = emailTheme.defaultBrandColor,\n}: NoticeEmailProps) {\n return (\n <EmailLayout preview={preview} appName={appName} brandColor={brandColor}>\n <EmailHeading>{heading}</EmailHeading>\n <EmailText variant=\"muted\" style={{ margin: 0, whiteSpace: 'pre-wrap' }}>\n {body}\n </EmailText>\n </EmailLayout>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/email/EmailLayout.tsx","../../src/email/EmailLinkFallback.tsx","../../src/email/ActionEmail.tsx","../../src/email/NoticeEmail.tsx"],"names":["jsxs","jsx","EmailText","emailTheme","EmailHeading"],"mappings":"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","file":"index.js","sourcesContent":["import type { ReactNode } from 'react';\nimport {\n EmailBody,\n EmailContainer,\n EmailHead,\n EmailPreview,\n EmailRoot,\n EmailSection,\n EmailText,\n emailTheme,\n} from '@olwiba/cn/email';\n\nexport interface EmailLayoutProps {\n preview?: string;\n appName: string;\n brandColor?: string;\n children: ReactNode;\n footer?: ReactNode;\n}\n\n/** Branded email shell — UI block composed from CN primitives. */\nexport function EmailLayout({\n preview,\n appName,\n brandColor = emailTheme.defaultBrandColor,\n children,\n footer,\n}: EmailLayoutProps) {\n const year = new Date().getFullYear();\n\n return (\n <EmailRoot>\n <EmailHead />\n {preview ? <EmailPreview>{preview}</EmailPreview> : null}\n <EmailBody\n style={{\n backgroundColor: emailTheme.pageBackground,\n fontFamily: emailTheme.fontFamily,\n margin: 0,\n padding: '24px 0',\n }}\n >\n <EmailContainer\n style={{\n maxWidth: '560px',\n margin: '0 auto',\n backgroundColor: emailTheme.cardBackground,\n borderRadius: '16px',\n overflow: 'hidden',\n border: `1px solid ${emailTheme.cardBorder}`,\n }}\n >\n <EmailSection\n style={{\n padding: '24px 32px',\n borderBottom: `1px solid ${emailTheme.cardBorder}`,\n }}\n >\n <EmailText\n style={{\n margin: 0,\n fontSize: '18px',\n fontWeight: 600,\n color: brandColor,\n }}\n >\n {appName}\n </EmailText>\n </EmailSection>\n\n <EmailSection style={{ padding: '32px' }}>{children}</EmailSection>\n\n {footer ?? (\n <EmailSection\n style={{\n padding: '20px 32px',\n borderTop: `1px solid ${emailTheme.cardBorder}`,\n backgroundColor: emailTheme.mutedBackground,\n }}\n >\n <EmailText\n variant=\"caption\"\n style={{\n margin: 0,\n textAlign: 'center',\n }}\n >\n © {year} {appName}. All rights reserved.\n </EmailText>\n </EmailSection>\n )}\n </EmailContainer>\n </EmailBody>\n </EmailRoot>\n );\n}\n","import { EmailLink, EmailText } from '@olwiba/cn/email';\n\nexport interface EmailLinkFallbackProps {\n actionUrl: string;\n label?: string;\n brandColor?: string;\n}\n\nexport function EmailLinkFallback({\n actionUrl,\n label = 'Or copy and paste this link into your browser:',\n brandColor,\n}: EmailLinkFallbackProps) {\n return (\n <>\n <EmailText variant=\"caption\" style={{ margin: '24px 0 8px' }}>\n {label}\n </EmailText>\n <EmailText style={{ margin: 0 }}>\n {/*\n Set through `style` rather than CN's `brandColor` prop, which this\n package's pinned @olwiba/cn does not have yet. CN applies that prop as\n `color` anyway, and `style` wins over its default, so the result is\n identical without coupling this file to a release.\n */}\n <EmailLink href={actionUrl} style={brandColor ? { color: brandColor } : undefined}>\n {actionUrl}\n </EmailLink>\n </EmailText>\n </>\n );\n}\n","import {\n EmailButton,\n EmailHeading,\n EmailText,\n emailTheme,\n} from '@olwiba/cn/email';\nimport { EmailLayout } from './EmailLayout';\nimport { EmailLinkFallback } from './EmailLinkFallback';\n\nexport interface ActionEmailProps {\n appName: string;\n preview: string;\n heading: string;\n description: string;\n actionLabel: string;\n actionUrl: string;\n brandColor?: string;\n showLinkFallback?: boolean;\n}\n\nexport function ActionEmail({\n appName,\n preview,\n heading,\n description,\n actionLabel,\n actionUrl,\n brandColor = emailTheme.defaultBrandColor,\n showLinkFallback = true,\n}: ActionEmailProps) {\n return (\n <EmailLayout preview={preview} appName={appName} brandColor={brandColor}>\n <EmailHeading>{heading}</EmailHeading>\n <EmailText variant=\"muted\" style={{ margin: '0 0 24px' }}>\n {description}\n </EmailText>\n <EmailButton href={actionUrl} label={actionLabel} brandColor={brandColor} />\n {showLinkFallback ? (\n <EmailLinkFallback actionUrl={actionUrl} brandColor={brandColor} />\n ) : null}\n </EmailLayout>\n );\n}\n","import {\n EmailHeading,\n EmailText,\n emailTheme,\n} from '@olwiba/cn/email';\nimport { EmailLayout } from './EmailLayout';\n\nexport interface NoticeEmailProps {\n appName: string;\n preview: string;\n heading: string;\n body: string;\n brandColor?: string;\n}\n\nexport function NoticeEmail({\n appName,\n preview,\n heading,\n body,\n brandColor = emailTheme.defaultBrandColor,\n}: NoticeEmailProps) {\n return (\n <EmailLayout preview={preview} appName={appName} brandColor={brandColor}>\n <EmailHeading>{heading}</EmailHeading>\n <EmailText variant=\"muted\" style={{ margin: 0, whiteSpace: 'pre-wrap' }}>\n {body}\n </EmailText>\n </EmailLayout>\n );\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1217,8 +1217,14 @@ interface FooterProps {
1217
1217
  icon: ReactNode;
1218
1218
  }>;
1219
1219
  legal?: string;
1220
+ /**
1221
+ * Live status pill. `label` is a ReactNode, not a string: a real status
1222
+ * pill often carries per-service detail in a tooltip, and typing it as
1223
+ * string forced consumers to smuggle that through `as unknown as string`.
1224
+ * A plain string still works and is the common case.
1225
+ */
1220
1226
  status?: {
1221
- label: string;
1227
+ label: ReactNode;
1222
1228
  operational?: boolean;
1223
1229
  };
1224
1230
  renderLink?: AppShellRenderLink;
@@ -1513,6 +1519,23 @@ interface DataTableProps<TData> {
1513
1519
  onSelectionChange?: (rows: TData[]) => void;
1514
1520
  /** Rows per page. Set to `0` to disable pagination entirely. @default 10 */
1515
1521
  pageSize?: number;
1522
+ /**
1523
+ * Hands pagination to the caller, for data the client does not hold all of.
1524
+ *
1525
+ * With this set, `data` is treated as the current page rather than the whole
1526
+ * set: the table stops slicing, and the footer reports and drives the
1527
+ * caller's page instead of its own. Without it nothing changes — a table
1528
+ * given every row keeps paginating locally, which is right for the common
1529
+ * case and avoids making every consumer implement paging to get a table.
1530
+ */
1531
+ pagination?: {
1532
+ pageIndex: number;
1533
+ /** Total pages. Omit when unknown — the footer then relies on `hasNext`. */
1534
+ pageCount?: number;
1535
+ hasNext?: boolean;
1536
+ hasPrevious?: boolean;
1537
+ onPageChange: (pageIndex: number) => void;
1538
+ };
1516
1539
  /** Slot rendered top-right of the toolbar — e.g. an "Add" button. */
1517
1540
  toolbar?: React.ReactNode;
1518
1541
  onRowClick?: (row: TData) => void;
@@ -1524,7 +1547,7 @@ interface DataTableProps<TData> {
1524
1547
  * toggle `searchKey`/`selectable`/`pageSize` rather than reaching for a
1525
1548
  * different table component per use case.
1526
1549
  */
1527
- declare function DataTable<TData>({ columns, data, searchKey, searchPlaceholder, selectable, onSelectionChange, pageSize, toolbar, onRowClick, emptyMessage, className, }: DataTableProps<TData>): react_jsx_runtime.JSX.Element;
1550
+ declare function DataTable<TData>({ columns, data, searchKey, searchPlaceholder, selectable, onSelectionChange, pageSize, pagination, toolbar, onRowClick, emptyMessage, className, }: DataTableProps<TData>): react_jsx_runtime.JSX.Element;
1528
1551
 
1529
1552
  interface LoadMoreProps extends React.HTMLAttributes<HTMLDivElement> {
1530
1553
  hasNextPage: boolean;
@@ -1635,6 +1658,27 @@ interface ChartProps {
1635
1658
  grid?: boolean;
1636
1659
  /** Legend. @default true for multiple series or donut, false for one series */
1637
1660
  legend?: boolean;
1661
+ /**
1662
+ * Stack series instead of overlaying them. Area and bar only — a stacked
1663
+ * line is a shape people misread as absolute values.
1664
+ *
1665
+ * Off by default: stacking answers "what does the total split into", and
1666
+ * silently switching a two-series comparison to it would change what an
1667
+ * existing chart claims.
1668
+ */
1669
+ stacked?: boolean;
1670
+ /**
1671
+ * Formats x-axis ticks. Separate from `valueFormatter`, which formats the
1672
+ * measured value — an axis of ISO dates wants shortening without changing
1673
+ * what the tooltip reports.
1674
+ */
1675
+ xTickFormatter?: (value: string) => string;
1676
+ /**
1677
+ * Fixes the y-axis range. Without it recharts scales to the data, which for
1678
+ * a percentage series makes a 98-100%% band fill the plot and read as
1679
+ * volatility.
1680
+ */
1681
+ yDomain?: [number, number];
1638
1682
  /** Formats values in tooltips and the y-axis, e.g. `(v) => \`$${v}\``. */
1639
1683
  valueFormatter?: (value: number) => string;
1640
1684
  className?: string;
@@ -1646,7 +1690,7 @@ interface ChartProps {
1646
1690
  * comparison, donut for part-of-whole identity. More than 5 donut slices:
1647
1691
  * fold the tail into an "Other" slice in your data instead of adding hues.
1648
1692
  */
1649
- declare function Chart({ type, data, xKey, series, height, grid, legend, valueFormatter, className, }: ChartProps): react_jsx_runtime.JSX.Element;
1693
+ declare function Chart({ type, data, xKey, series, height, grid, legend, stacked, xTickFormatter, yDomain, valueFormatter, className, }: ChartProps): react_jsx_runtime.JSX.Element;
1650
1694
 
1651
1695
  interface FileUploadEntry {
1652
1696
  id: string;
@@ -1706,6 +1750,10 @@ interface NotificationToastProps {
1706
1750
  */
1707
1751
  declare function NotificationToast({ variant, title, description, avatar, action, secondaryAction, onDismiss, }: NotificationToastProps): react_jsx_runtime.JSX.Element;
1708
1752
  interface NotifyOptions extends Omit<NotificationToastProps, 'onDismiss'> {
1753
+ /**
1754
+ * Overrides the per-variant default below. Explicit always wins — a caller
1755
+ * that has thought about the timing knows more than this heuristic does.
1756
+ */
1709
1757
  duration?: number;
1710
1758
  }
1711
1759
  /** Fires a `NotificationToast` through sonner. Requires `<Toaster />` from `@olwiba/cn` mounted once in your app. */