@olwiba/ui 0.2.25 → 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 (202) 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/docs-manifest.json +253 -0
  96. package/package.json +16 -8
  97. package/site/demos/action-email.tsx +6 -0
  98. package/site/demos/activity-feed.tsx +42 -0
  99. package/site/demos/animated-swap.tsx +42 -0
  100. package/site/demos/app-shell.tsx +47 -0
  101. package/site/demos/app-ui-page.tsx +9 -0
  102. package/site/demos/application-sidebar-block.tsx +9 -0
  103. package/site/demos/auth-section.tsx +15 -0
  104. package/site/demos/auth-split-block.tsx +9 -0
  105. package/site/demos/billing-page.tsx +157 -0
  106. package/site/demos/billing-panel.tsx +26 -0
  107. package/site/demos/carousel.tsx +34 -0
  108. package/site/demos/chart.tsx +55 -0
  109. package/site/demos/command-menu.tsx +39 -0
  110. package/site/demos/confirm-dialog.tsx +27 -0
  111. package/site/demos/contact-form-block.tsx +3 -0
  112. package/site/demos/contact-section.tsx +2 -0
  113. package/site/demos/context-menu.tsx +30 -0
  114. package/site/demos/count-up.tsx +23 -0
  115. package/site/demos/cta-section.tsx +6 -0
  116. package/site/demos/dashboard-overview-block.tsx +9 -0
  117. package/site/demos/dashboard-shell-block.tsx +10 -0
  118. package/site/demos/data-table.tsx +47 -0
  119. package/site/demos/demo-brand.tsx +23 -0
  120. package/site/demos/dock.tsx +20 -0
  121. package/site/demos/document-sidebar-block.tsx +9 -0
  122. package/site/demos/email-examples.tsx +58 -0
  123. package/site/demos/email-frame.tsx +50 -0
  124. package/site/demos/email-layout.tsx +6 -0
  125. package/site/demos/email-link-fallback.tsx +6 -0
  126. package/site/demos/email-previews.generated.ts +11 -0
  127. package/site/demos/empty-state-block.tsx +3 -0
  128. package/site/demos/empty-state.tsx +23 -0
  129. package/site/demos/error-page.tsx +5 -0
  130. package/site/demos/fade-in.tsx +18 -0
  131. package/site/demos/faq-section.tsx +6 -0
  132. package/site/demos/feature-card.tsx +13 -0
  133. package/site/demos/features-section.tsx +6 -0
  134. package/site/demos/file-upload.tsx +16 -0
  135. package/site/demos/footer.tsx +42 -0
  136. package/site/demos/full-page-spinner.tsx +9 -0
  137. package/site/demos/glass-card.tsx +14 -0
  138. package/site/demos/glow-effect.tsx +3 -0
  139. package/site/demos/gradient-background.tsx +3 -0
  140. package/site/demos/grid-pattern.tsx +3 -0
  141. package/site/demos/hero-section.tsx +6 -0
  142. package/site/demos/image-card.tsx +17 -0
  143. package/site/demos/login-block.tsx +9 -0
  144. package/site/demos/marketing-cta-block.tsx +3 -0
  145. package/site/demos/marketing-demo-data.tsx +114 -0
  146. package/site/demos/marketing-faq-block.tsx +3 -0
  147. package/site/demos/marketing-features-block.tsx +3 -0
  148. package/site/demos/marketing-footer-block.tsx +3 -0
  149. package/site/demos/marketing-hero-block.tsx +10 -0
  150. package/site/demos/marketing-nav-block.tsx +3 -0
  151. package/site/demos/marketing-newsletter-block.tsx +3 -0
  152. package/site/demos/marketing-page.tsx +52 -0
  153. package/site/demos/marketing-pricing-block.tsx +3 -0
  154. package/site/demos/marketing-stats-block.tsx +3 -0
  155. package/site/demos/marketing-team-block.tsx +3 -0
  156. package/site/demos/marketing-testimonials-block.tsx +3 -0
  157. package/site/demos/navbar.tsx +32 -0
  158. package/site/demos/newsletter-section.tsx +2 -0
  159. package/site/demos/noise-overlay.tsx +3 -0
  160. package/site/demos/not-found-block.tsx +3 -0
  161. package/site/demos/notice-email.tsx +6 -0
  162. package/site/demos/notifications-popover.tsx +27 -0
  163. package/site/demos/notify.tsx +44 -0
  164. package/site/demos/olwiba-ui-context.tsx +51 -0
  165. package/site/demos/onboarding-block.tsx +3 -0
  166. package/site/demos/onboarding-wizard.tsx +43 -0
  167. package/site/demos/overlay.tsx +72 -0
  168. package/site/demos/page-header.tsx +15 -0
  169. package/site/demos/page-transition.tsx +34 -0
  170. package/site/demos/post-list.tsx +24 -0
  171. package/site/demos/pricing-card.tsx +27 -0
  172. package/site/demos/pricing-section.tsx +6 -0
  173. package/site/demos/register-hotkeys.tsx +39 -0
  174. package/site/demos/root-error-fallback.tsx +28 -0
  175. package/site/demos/settings-layout-block.tsx +3 -0
  176. package/site/demos/settings-section.tsx +22 -0
  177. package/site/demos/sign-in-page.tsx +10 -0
  178. package/site/demos/sortable.tsx +30 -0
  179. package/site/demos/spotlight.tsx +29 -0
  180. package/site/demos/stagger-children.tsx +16 -0
  181. package/site/demos/stat-card.tsx +12 -0
  182. package/site/demos/stats-section.tsx +6 -0
  183. package/site/demos/steps-section.tsx +66 -0
  184. package/site/demos/suspensed.tsx +31 -0
  185. package/site/demos/team-members-panel.tsx +26 -0
  186. package/site/demos/team-section.tsx +2 -0
  187. package/site/demos/testimonial-card.tsx +17 -0
  188. package/site/demos/testimonials-section.tsx +6 -0
  189. package/site/demos/theme-color-updater.tsx +32 -0
  190. package/site/demos/theme-switch-minimal.tsx +10 -0
  191. package/site/demos/underlay.tsx +74 -0
  192. package/site/demos/update-banner.tsx +31 -0
  193. package/site/demos/use-copy-to-clipboard.tsx +21 -0
  194. package/site/demos/use-debounce.tsx +25 -0
  195. package/site/demos/use-intersection-observer.tsx +32 -0
  196. package/site/demos/use-local-storage.tsx +22 -0
  197. package/site/demos/use-media-query.tsx +31 -0
  198. package/site/demos/use-pagination.tsx +31 -0
  199. package/site/demos/user-profile-block.tsx +3 -0
  200. package/site/demos/version-banner.tsx +27 -0
  201. package/src/email/EmailLinkFallback.tsx +7 -1
  202. package/src/email/index.ts +3 -0
@@ -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"]}