@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.
- package/content/docs/app/app-shell.mdx +71 -0
- package/content/docs/app/auth-section.mdx +73 -0
- package/content/docs/app/billing-panel.mdx +38 -0
- package/content/docs/app/empty-state.mdx +47 -0
- package/content/docs/app/error-page.mdx +31 -0
- package/content/docs/app/index.mdx +13 -0
- package/content/docs/app/meta.json +4 -0
- package/content/docs/app/onboarding-wizard.mdx +41 -0
- package/content/docs/app/settings-section.mdx +37 -0
- package/content/docs/app/team-members-panel.mdx +35 -0
- package/content/docs/app/update-banner.mdx +43 -0
- package/content/docs/components/activity-feed.mdx +42 -0
- package/content/docs/components/chart.mdx +47 -0
- package/content/docs/components/command-menu.mdx +41 -0
- package/content/docs/components/confirm-dialog.mdx +26 -0
- package/content/docs/components/context-menu.mdx +26 -0
- package/content/docs/components/data-table.mdx +40 -0
- package/content/docs/components/dock.mdx +26 -0
- package/content/docs/components/feature-card.mdx +26 -0
- package/content/docs/components/file-upload.mdx +35 -0
- package/content/docs/components/full-page-spinner.mdx +44 -0
- package/content/docs/components/glass-card.mdx +26 -0
- package/content/docs/components/image-card.mdx +26 -0
- package/content/docs/components/index.mdx +49 -0
- package/content/docs/components/load-more.mdx +34 -0
- package/content/docs/components/meta.json +35 -0
- package/content/docs/components/notifications-popover.mdx +34 -0
- package/content/docs/components/notify.mdx +40 -0
- package/content/docs/components/olwiba-ui-context.mdx +69 -0
- package/content/docs/components/page-header.mdx +42 -0
- package/content/docs/components/pricing-card.mdx +26 -0
- package/content/docs/components/register-hotkeys.mdx +50 -0
- package/content/docs/components/root-error-fallback.mdx +39 -0
- package/content/docs/components/spotlight.mdx +26 -0
- package/content/docs/components/stat-card.mdx +26 -0
- package/content/docs/components/suspensed.mdx +42 -0
- package/content/docs/components/testimonial-card.mdx +26 -0
- package/content/docs/components/theme-color-updater.mdx +40 -0
- package/content/docs/components/theme-switch-minimal.mdx +32 -0
- package/content/docs/components/version-banner.mdx +44 -0
- package/content/docs/email/action-email.mdx +62 -0
- package/content/docs/email/email-layout.mdx +58 -0
- package/content/docs/email/email-link-fallback.mdx +46 -0
- package/content/docs/email/index.mdx +32 -0
- package/content/docs/email/meta.json +10 -0
- package/content/docs/email/notice-email.mdx +51 -0
- package/content/docs/hooks/index.mdx +21 -0
- package/content/docs/hooks/meta.json +16 -0
- package/content/docs/hooks/use-confirm.mdx +81 -0
- package/content/docs/hooks/use-controlled-open.mdx +53 -0
- package/content/docs/hooks/use-copy-to-clipboard.mdx +26 -0
- package/content/docs/hooks/use-debounce.mdx +26 -0
- package/content/docs/hooks/use-intersection-observer.mdx +26 -0
- package/content/docs/hooks/use-local-storage.mdx +26 -0
- package/content/docs/hooks/use-media-query.mdx +26 -0
- package/content/docs/hooks/use-mounted.mdx +39 -0
- package/content/docs/hooks/use-pagination.mdx +26 -0
- package/content/docs/hooks/use-scrolled-past.mdx +44 -0
- package/content/docs/index.mdx +68 -0
- package/content/docs/marketing/contact-section.mdx +16 -0
- package/content/docs/marketing/cta-section.mdx +31 -0
- package/content/docs/marketing/faq-section.mdx +16 -0
- package/content/docs/marketing/features-section.mdx +23 -0
- package/content/docs/marketing/footer.mdx +16 -0
- package/content/docs/marketing/hero-section.mdx +16 -0
- package/content/docs/marketing/index.mdx +22 -0
- package/content/docs/marketing/meta.json +20 -0
- package/content/docs/marketing/navbar.mdx +16 -0
- package/content/docs/marketing/newsletter-section.mdx +16 -0
- package/content/docs/marketing/post-list.mdx +32 -0
- package/content/docs/marketing/pricing-section.mdx +16 -0
- package/content/docs/marketing/stats-section.mdx +16 -0
- package/content/docs/marketing/steps-section.mdx +60 -0
- package/content/docs/marketing/team-section.mdx +16 -0
- package/content/docs/marketing/testimonials-section.mdx +16 -0
- package/content/docs/mechanics/carousel.mdx +42 -0
- package/content/docs/mechanics/index.mdx +11 -0
- package/content/docs/mechanics/meta.json +4 -0
- package/content/docs/mechanics/sortable.mdx +44 -0
- package/content/docs/meta.json +4 -0
- package/content/docs/motion/animated-swap.mdx +75 -0
- package/content/docs/motion/count-up.mdx +31 -0
- package/content/docs/motion/fade-in.mdx +34 -0
- package/content/docs/motion/index.mdx +12 -0
- package/content/docs/motion/meta.json +4 -0
- package/content/docs/motion/page-transition.mdx +29 -0
- package/content/docs/motion/stagger-children.mdx +31 -0
- package/content/docs/overlays/index.mdx +9 -0
- package/content/docs/overlays/meta.json +4 -0
- package/content/docs/overlays/overlay.mdx +60 -0
- package/content/docs/overlays/underlay.mdx +56 -0
- package/dist/email/index.d.ts +8 -1
- package/dist/email/index.js +3 -3
- package/dist/email/index.js.map +1 -1
- package/docs-manifest.json +253 -0
- package/package.json +16 -8
- package/site/demos/action-email.tsx +6 -0
- package/site/demos/activity-feed.tsx +42 -0
- package/site/demos/animated-swap.tsx +42 -0
- package/site/demos/app-shell.tsx +47 -0
- package/site/demos/app-ui-page.tsx +9 -0
- package/site/demos/application-sidebar-block.tsx +9 -0
- package/site/demos/auth-section.tsx +15 -0
- package/site/demos/auth-split-block.tsx +9 -0
- package/site/demos/billing-page.tsx +157 -0
- package/site/demos/billing-panel.tsx +26 -0
- package/site/demos/carousel.tsx +34 -0
- package/site/demos/chart.tsx +55 -0
- package/site/demos/command-menu.tsx +39 -0
- package/site/demos/confirm-dialog.tsx +27 -0
- package/site/demos/contact-form-block.tsx +3 -0
- package/site/demos/contact-section.tsx +2 -0
- package/site/demos/context-menu.tsx +30 -0
- package/site/demos/count-up.tsx +23 -0
- package/site/demos/cta-section.tsx +6 -0
- package/site/demos/dashboard-overview-block.tsx +9 -0
- package/site/demos/dashboard-shell-block.tsx +10 -0
- package/site/demos/data-table.tsx +47 -0
- package/site/demos/demo-brand.tsx +23 -0
- package/site/demos/dock.tsx +20 -0
- package/site/demos/document-sidebar-block.tsx +9 -0
- package/site/demos/email-examples.tsx +58 -0
- package/site/demos/email-frame.tsx +50 -0
- package/site/demos/email-layout.tsx +6 -0
- package/site/demos/email-link-fallback.tsx +6 -0
- package/site/demos/email-previews.generated.ts +11 -0
- package/site/demos/empty-state-block.tsx +3 -0
- package/site/demos/empty-state.tsx +23 -0
- package/site/demos/error-page.tsx +5 -0
- package/site/demos/fade-in.tsx +18 -0
- package/site/demos/faq-section.tsx +6 -0
- package/site/demos/feature-card.tsx +13 -0
- package/site/demos/features-section.tsx +6 -0
- package/site/demos/file-upload.tsx +16 -0
- package/site/demos/footer.tsx +42 -0
- package/site/demos/full-page-spinner.tsx +9 -0
- package/site/demos/glass-card.tsx +14 -0
- package/site/demos/glow-effect.tsx +3 -0
- package/site/demos/gradient-background.tsx +3 -0
- package/site/demos/grid-pattern.tsx +3 -0
- package/site/demos/hero-section.tsx +6 -0
- package/site/demos/image-card.tsx +17 -0
- package/site/demos/login-block.tsx +9 -0
- package/site/demos/marketing-cta-block.tsx +3 -0
- package/site/demos/marketing-demo-data.tsx +114 -0
- package/site/demos/marketing-faq-block.tsx +3 -0
- package/site/demos/marketing-features-block.tsx +3 -0
- package/site/demos/marketing-footer-block.tsx +3 -0
- package/site/demos/marketing-hero-block.tsx +10 -0
- package/site/demos/marketing-nav-block.tsx +3 -0
- package/site/demos/marketing-newsletter-block.tsx +3 -0
- package/site/demos/marketing-page.tsx +52 -0
- package/site/demos/marketing-pricing-block.tsx +3 -0
- package/site/demos/marketing-stats-block.tsx +3 -0
- package/site/demos/marketing-team-block.tsx +3 -0
- package/site/demos/marketing-testimonials-block.tsx +3 -0
- package/site/demos/navbar.tsx +32 -0
- package/site/demos/newsletter-section.tsx +2 -0
- package/site/demos/noise-overlay.tsx +3 -0
- package/site/demos/not-found-block.tsx +3 -0
- package/site/demos/notice-email.tsx +6 -0
- package/site/demos/notifications-popover.tsx +27 -0
- package/site/demos/notify.tsx +44 -0
- package/site/demos/olwiba-ui-context.tsx +51 -0
- package/site/demos/onboarding-block.tsx +3 -0
- package/site/demos/onboarding-wizard.tsx +43 -0
- package/site/demos/overlay.tsx +72 -0
- package/site/demos/page-header.tsx +15 -0
- package/site/demos/page-transition.tsx +34 -0
- package/site/demos/post-list.tsx +24 -0
- package/site/demos/pricing-card.tsx +27 -0
- package/site/demos/pricing-section.tsx +6 -0
- package/site/demos/register-hotkeys.tsx +39 -0
- package/site/demos/root-error-fallback.tsx +28 -0
- package/site/demos/settings-layout-block.tsx +3 -0
- package/site/demos/settings-section.tsx +22 -0
- package/site/demos/sign-in-page.tsx +10 -0
- package/site/demos/sortable.tsx +30 -0
- package/site/demos/spotlight.tsx +29 -0
- package/site/demos/stagger-children.tsx +16 -0
- package/site/demos/stat-card.tsx +12 -0
- package/site/demos/stats-section.tsx +6 -0
- package/site/demos/steps-section.tsx +66 -0
- package/site/demos/suspensed.tsx +31 -0
- package/site/demos/team-members-panel.tsx +26 -0
- package/site/demos/team-section.tsx +2 -0
- package/site/demos/testimonial-card.tsx +17 -0
- package/site/demos/testimonials-section.tsx +6 -0
- package/site/demos/theme-color-updater.tsx +32 -0
- package/site/demos/theme-switch-minimal.tsx +10 -0
- package/site/demos/underlay.tsx +74 -0
- package/site/demos/update-banner.tsx +31 -0
- package/site/demos/use-copy-to-clipboard.tsx +21 -0
- package/site/demos/use-debounce.tsx +25 -0
- package/site/demos/use-intersection-observer.tsx +32 -0
- package/site/demos/use-local-storage.tsx +22 -0
- package/site/demos/use-media-query.tsx +31 -0
- package/site/demos/use-pagination.tsx +31 -0
- package/site/demos/user-profile-block.tsx +3 -0
- package/site/demos/version-banner.tsx +27 -0
- package/src/email/EmailLinkFallback.tsx +7 -1
- package/src/email/index.ts +3 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Suspensed
|
|
3
|
+
description: A thin wrapper around React.Suspense with a sensible default fallback.
|
|
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="suspensed" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @olwiba/ui
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { Suspensed } from "@olwiba/ui";
|
|
22
|
+
import { Spinner } from "@olwiba/cn";
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
// Default fallback is <Spinner />
|
|
27
|
+
<Suspensed>
|
|
28
|
+
<LazyComponent />
|
|
29
|
+
</Suspensed>
|
|
30
|
+
|
|
31
|
+
// Custom fallback
|
|
32
|
+
<Suspensed fallback={<Spinner className="size-4" />}>
|
|
33
|
+
<LazyComponent />
|
|
34
|
+
</Suspensed>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API Reference
|
|
38
|
+
|
|
39
|
+
<APIReference name="Suspensed" props={[
|
|
40
|
+
{ name: "children", type: "ReactNode", default: "-" },
|
|
41
|
+
{ name: "fallback", type: "ReactNode", default: "<Spinner />" },
|
|
42
|
+
]} />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TestimonialCard
|
|
3
|
+
description: Quote card with avatar, name, and role attribution.
|
|
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="testimonial-card" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @olwiba/ui
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { TestimonialCard } from "@olwiba/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## API Reference
|
|
25
|
+
|
|
26
|
+
<APIReference name="TestimonialCard" props={[]} />
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: ThemeColorUpdater
|
|
3
|
+
description: Syncs a color theme string to the data-theme attribute on the document root.
|
|
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="theme-color-updater" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @olwiba/ui
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { ThemeColorUpdater } from "@olwiba/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
<ThemeColorUpdater colorTheme="blue" />
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Renderless — returns `null`. Sets `data-theme` on `<html>` on every render. Your CSS targets `[data-theme]` for color tokens:
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
[data-theme="blue"] {
|
|
32
|
+
--primary: oklch(0.55 0.22 250);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## API Reference
|
|
37
|
+
|
|
38
|
+
<APIReference name="ThemeColorUpdater" props={[
|
|
39
|
+
{ name: "colorTheme", type: "string", default: "-" },
|
|
40
|
+
]} />
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: ThemeSwitchMinimal
|
|
3
|
+
description: A minimal icon button for toggling dark and light mode.
|
|
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="theme-switch-minimal" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @olwiba/ui
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { ThemeSwitchMinimal } from "@olwiba/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
<ThemeSwitchMinimal />
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
No props required. Reads and writes to `localStorage` under the `theme` key and toggles the `dark` class on `<html>`. Self-contained — no context or provider required.
|
|
29
|
+
|
|
30
|
+
## API Reference
|
|
31
|
+
|
|
32
|
+
<APIReference name="ThemeSwitchMinimal" props={[]} />
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: VersionBanner
|
|
3
|
+
description: A dismissible banner for announcing new versions or updates.
|
|
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="version-banner" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @olwiba/ui
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { VersionBanner } from "@olwiba/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
const [show, setShow] = React.useState(true);
|
|
26
|
+
|
|
27
|
+
{show && (
|
|
28
|
+
<VersionBanner
|
|
29
|
+
version="2.1.0"
|
|
30
|
+
message="New components available — see what's changed."
|
|
31
|
+
onDismiss={() => setShow(false)}
|
|
32
|
+
/>
|
|
33
|
+
)}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Dismissal is stateless — the parent controls visibility. Persist across sessions with `localStorage` in your parent component.
|
|
37
|
+
|
|
38
|
+
## API Reference
|
|
39
|
+
|
|
40
|
+
<APIReference name="VersionBanner" props={[
|
|
41
|
+
{ name: "version", type: "string", default: "-" },
|
|
42
|
+
{ name: "message", type: "string", default: "-" },
|
|
43
|
+
{ name: "onDismiss", type: "() => void", default: "-" },
|
|
44
|
+
]} />
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: ActionEmail
|
|
3
|
+
description: Transactional email built around a single call to action — sign-in links, verification, password resets.
|
|
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="action-email" />
|
|
11
|
+
|
|
12
|
+
`ActionEmail` is the template for a message whose entire purpose is one button. It composes
|
|
13
|
+
[`EmailLayout`](/docs/email/email-layout) with a heading, a line of explanation, the action
|
|
14
|
+
itself, and — unless you turn it off — a
|
|
15
|
+
[`EmailLinkFallback`](/docs/email/email-link-fallback) for clients that strip buttons.
|
|
16
|
+
|
|
17
|
+
The preview above renders in a browser. A real mail client is less forgiving, so treat it as a
|
|
18
|
+
check on copy and structure rather than a rendering guarantee.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
bun add @olwiba/ui
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { ActionEmail } from "@olwiba/ui/email";
|
|
30
|
+
import { render } from "@react-email/render";
|
|
31
|
+
|
|
32
|
+
const html = await render(
|
|
33
|
+
<ActionEmail
|
|
34
|
+
appName="Nexus Inc"
|
|
35
|
+
preview="Sign in to Nexus Inc"
|
|
36
|
+
heading="Sign in with one click"
|
|
37
|
+
description="This link expires in 15 minutes and can only be used once."
|
|
38
|
+
actionLabel="Sign in"
|
|
39
|
+
actionUrl={url}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`preview` is the line mail clients show beside the subject in an inbox list. It is not rendered
|
|
45
|
+
in the message body, and leaving it vague wastes the only copy a recipient reads before
|
|
46
|
+
deciding whether to open.
|
|
47
|
+
|
|
48
|
+
## API Reference
|
|
49
|
+
|
|
50
|
+
<APIReference
|
|
51
|
+
name="ActionEmail"
|
|
52
|
+
props={[
|
|
53
|
+
{ name: "appName", type: "string", default: "-" },
|
|
54
|
+
{ name: "preview", type: "string", default: "-" },
|
|
55
|
+
{ name: "heading", type: "string", default: "-" },
|
|
56
|
+
{ name: "description", type: "string", default: "-" },
|
|
57
|
+
{ name: "actionLabel", type: "string", default: "-" },
|
|
58
|
+
{ name: "actionUrl", type: "string", default: "-" },
|
|
59
|
+
{ name: "brandColor", type: "string", default: "emailTheme.defaultBrandColor" },
|
|
60
|
+
{ name: "showLinkFallback", type: "boolean", default: "true" },
|
|
61
|
+
]}
|
|
62
|
+
/>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: EmailLayout
|
|
3
|
+
description: The branded shell every email block is composed into — document, head, preview line, container and footer.
|
|
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="email-layout" />
|
|
11
|
+
|
|
12
|
+
`EmailLayout` is the shell the other blocks are built on. It owns the parts of a message that
|
|
13
|
+
should never vary between one email and the next: the document itself, the preview line, the
|
|
14
|
+
container width, the brand mark and the footer.
|
|
15
|
+
|
|
16
|
+
Use it directly when you are writing a message that neither
|
|
17
|
+
[`ActionEmail`](/docs/email/action-email) nor [`NoticeEmail`](/docs/email/notice-email) fits.
|
|
18
|
+
Both of those are this layout with a body already arranged, so reaching for one of them first
|
|
19
|
+
is usually the shorter path.
|
|
20
|
+
|
|
21
|
+
<Callout>
|
|
22
|
+
`EmailLayout` renders `<html>`, `<head>` and `<body>`. It is a whole document, so it cannot be
|
|
23
|
+
mounted inside a page — the preview above is a real rendered email in an iframe, not a React
|
|
24
|
+
tree. Render it with `@react-email/render` and send the string.
|
|
25
|
+
</Callout>
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
bun add @olwiba/ui
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { EmailLayout } from "@olwiba/ui/email";
|
|
37
|
+
import { EmailText } from "@olwiba/cn/email";
|
|
38
|
+
import { render } from "@react-email/render";
|
|
39
|
+
|
|
40
|
+
const html = await render(
|
|
41
|
+
<EmailLayout appName="Nexus Inc" preview="A message from Nexus Inc">
|
|
42
|
+
<EmailText>Anything you put here sits inside the branded shell.</EmailText>
|
|
43
|
+
</EmailLayout>
|
|
44
|
+
);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API Reference
|
|
48
|
+
|
|
49
|
+
<APIReference
|
|
50
|
+
name="EmailLayout"
|
|
51
|
+
props={[
|
|
52
|
+
{ name: "appName", type: "string", default: "-" },
|
|
53
|
+
{ name: "children", type: "ReactNode", default: "-" },
|
|
54
|
+
{ name: "preview", type: "string", default: "-" },
|
|
55
|
+
{ name: "brandColor", type: "string", default: "emailTheme.defaultBrandColor" },
|
|
56
|
+
{ name: "footer", type: "ReactNode", default: "-" },
|
|
57
|
+
]}
|
|
58
|
+
/>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: EmailLinkFallback
|
|
3
|
+
description: The copyable URL shown beneath an email button, for clients that strip them.
|
|
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="email-link-fallback" />
|
|
11
|
+
|
|
12
|
+
Some mail clients remove buttons, rewrite them, or render them as bare text. When the button was
|
|
13
|
+
the only way to act on the message, the email becomes useless. `EmailLinkFallback` prints the
|
|
14
|
+
destination as plain, selectable text underneath it.
|
|
15
|
+
|
|
16
|
+
[`ActionEmail`](/docs/email/action-email) includes this already — set `showLinkFallback={false}`
|
|
17
|
+
to suppress it. Use it directly when you have built a message from
|
|
18
|
+
[`EmailLayout`](/docs/email/email-layout) and put your own button in it.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
bun add @olwiba/ui
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { EmailLayout, EmailLinkFallback } from "@olwiba/ui/email";
|
|
30
|
+
|
|
31
|
+
<EmailLayout appName="Nexus Inc" preview="Sign in to Nexus Inc">
|
|
32
|
+
{/* your own heading and button */}
|
|
33
|
+
<EmailLinkFallback actionUrl={url} />
|
|
34
|
+
</EmailLayout>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API Reference
|
|
38
|
+
|
|
39
|
+
<APIReference
|
|
40
|
+
name="EmailLinkFallback"
|
|
41
|
+
props={[
|
|
42
|
+
{ name: "actionUrl", type: "string", default: "-" },
|
|
43
|
+
{ name: "label", type: "string", default: '"Or copy and paste this link into your browser:"' },
|
|
44
|
+
{ name: "brandColor", type: "string", default: "emailTheme.defaultBrandColor" },
|
|
45
|
+
]}
|
|
46
|
+
/>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Email
|
|
3
|
+
description: React Email blocks for transactional messages.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Email follows the same stack as web UI:
|
|
7
|
+
|
|
8
|
+
| Layer | Package | Role |
|
|
9
|
+
|-------|---------|------|
|
|
10
|
+
| Primitives | `@olwiba/cn/email` | Lego — `EmailText`, `EmailButton`, `EmailSection`, … |
|
|
11
|
+
| Blocks | `@olwiba/ui/email` | Real templates — `ActionEmail`, `NoticeEmail` |
|
|
12
|
+
| App | genesis | Copy + URLs only — imports **UI blocks** |
|
|
13
|
+
|
|
14
|
+
**Apps should import `@olwiba/ui/email`, not CN directly.**
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { ActionEmail } from "@olwiba/ui/email";
|
|
18
|
+
import { render } from "@react-email/render";
|
|
19
|
+
|
|
20
|
+
const html = await render(
|
|
21
|
+
<ActionEmail
|
|
22
|
+
appName="Genesis"
|
|
23
|
+
preview="Sign in"
|
|
24
|
+
heading="Sign in with one click"
|
|
25
|
+
description="This link expires soon."
|
|
26
|
+
actionLabel="Sign in"
|
|
27
|
+
actionUrl={url}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Custom Olwiba email blocks belong in `@olwiba/ui/email`. New lego pieces belong in `@olwiba/cn/email`.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: NoticeEmail
|
|
3
|
+
description: Transactional email that tells the recipient something, with no action to take.
|
|
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="notice-email" />
|
|
11
|
+
|
|
12
|
+
`NoticeEmail` is for messages that inform rather than ask: an export finished, a plan changed,
|
|
13
|
+
a job failed. It has no button, which is the point — an email with a call to action the
|
|
14
|
+
recipient cannot complete is worse than one that never offered it.
|
|
15
|
+
|
|
16
|
+
Reach for [`ActionEmail`](/docs/email/action-email) when there is exactly one thing to do.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
bun add @olwiba/ui
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { NoticeEmail } from "@olwiba/ui/email";
|
|
28
|
+
import { render } from "@react-email/render";
|
|
29
|
+
|
|
30
|
+
const html = await render(
|
|
31
|
+
<NoticeEmail
|
|
32
|
+
appName="Nexus Inc"
|
|
33
|
+
preview="Your export is ready"
|
|
34
|
+
heading="Your export is ready"
|
|
35
|
+
body="The workspace export you requested has finished. It stays available for seven days."
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## API Reference
|
|
41
|
+
|
|
42
|
+
<APIReference
|
|
43
|
+
name="NoticeEmail"
|
|
44
|
+
props={[
|
|
45
|
+
{ name: "appName", type: "string", default: "-" },
|
|
46
|
+
{ name: "preview", type: "string", default: "-" },
|
|
47
|
+
{ name: "heading", type: "string", default: "-" },
|
|
48
|
+
{ name: "body", type: "string", default: "-" },
|
|
49
|
+
{ name: "brandColor", type: "string", default: "emailTheme.defaultBrandColor" },
|
|
50
|
+
]}
|
|
51
|
+
/>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hooks
|
|
3
|
+
description: Utility hooks provided by @olwiba/ui.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Hooks for common app patterns — all framework-agnostic and composable.
|
|
7
|
+
|
|
8
|
+
## Available Hooks
|
|
9
|
+
|
|
10
|
+
| Hook | Description |
|
|
11
|
+
|------|-------------|
|
|
12
|
+
| [useCopyToClipboard](/docs/hooks/use-copy-to-clipboard) | Copies text to clipboard and exposes a boolean copied feedback state |
|
|
13
|
+
| [useConfirm](/docs/hooks/use-confirm) | Headless async confirmation dialog hook |
|
|
14
|
+
| [useControlledOpen](/docs/hooks/use-controlled-open) | Open/close state for modals, drawers, and dropdowns |
|
|
15
|
+
| [useDebounce](/docs/hooks/use-debounce) | Debounces a value — returns the stabilised value after a delay |
|
|
16
|
+
| [useIntersectionObserver](/docs/hooks/use-intersection-observer) | Returns a ref and a boolean for scroll-triggered visibility detection |
|
|
17
|
+
| [useLocalStorage](/docs/hooks/use-local-storage) | Persisted state backed by localStorage with SSR safety |
|
|
18
|
+
| [useMediaQuery](/docs/hooks/use-media-query) | Returns true/false for any CSS media query string |
|
|
19
|
+
| [useMounted](/docs/hooks/use-mounted) | Detect when the component has mounted on the client |
|
|
20
|
+
| [usePagination](/docs/hooks/use-pagination) | Page and offset state management — pairs with data tables and lists |
|
|
21
|
+
| [useScrolledPast](/docs/hooks/use-scrolled-past) | Detect when the page has scrolled past a threshold |
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Hooks",
|
|
3
|
+
"pages": [
|
|
4
|
+
"index",
|
|
5
|
+
"use-confirm",
|
|
6
|
+
"use-controlled-open",
|
|
7
|
+
"use-copy-to-clipboard",
|
|
8
|
+
"use-debounce",
|
|
9
|
+
"use-intersection-observer",
|
|
10
|
+
"use-local-storage",
|
|
11
|
+
"use-media-query",
|
|
12
|
+
"use-mounted",
|
|
13
|
+
"use-pagination",
|
|
14
|
+
"use-scrolled-past"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useConfirm
|
|
3
|
+
description: A headless confirmation hook that returns state and handlers for wiring up any confirm dialog.
|
|
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
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
bun add @olwiba/ui
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { useConfirm } from "@olwiba/ui";
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { AlertDialog, AlertDialogContent, AlertDialogTitle,
|
|
24
|
+
AlertDialogFooter, AlertDialogCancel, AlertDialogAction } from "@olwiba/cn";
|
|
25
|
+
|
|
26
|
+
function DeleteButton() {
|
|
27
|
+
const { confirm, isOpen, options, handleConfirm, handleCancel } = useConfirm();
|
|
28
|
+
|
|
29
|
+
const handleDelete = async () => {
|
|
30
|
+
const ok = await confirm({
|
|
31
|
+
title: 'Delete item?',
|
|
32
|
+
description: 'This cannot be undone.',
|
|
33
|
+
confirmLabel: 'Delete',
|
|
34
|
+
cancelLabel: 'Cancel',
|
|
35
|
+
});
|
|
36
|
+
if (ok) {
|
|
37
|
+
// proceed with deletion
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<button onClick={handleDelete}>Delete</button>
|
|
44
|
+
|
|
45
|
+
<AlertDialog open={isOpen}>
|
|
46
|
+
<AlertDialogContent>
|
|
47
|
+
<AlertDialogTitle>{options.title}</AlertDialogTitle>
|
|
48
|
+
{options.description && <p>{options.description}</p>}
|
|
49
|
+
<AlertDialogFooter>
|
|
50
|
+
<AlertDialogCancel onClick={handleCancel}>
|
|
51
|
+
{options.cancelLabel ?? 'Cancel'}
|
|
52
|
+
</AlertDialogCancel>
|
|
53
|
+
<AlertDialogAction onClick={handleConfirm}>
|
|
54
|
+
{options.confirmLabel ?? 'Confirm'}
|
|
55
|
+
</AlertDialogAction>
|
|
56
|
+
</AlertDialogFooter>
|
|
57
|
+
</AlertDialogContent>
|
|
58
|
+
</AlertDialog>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`useConfirm` manages only state and async resolution — you wire up your own dialog, giving you full control over styling and which primitive to use.
|
|
65
|
+
|
|
66
|
+
## API Reference
|
|
67
|
+
|
|
68
|
+
<APIReference name="useConfirm → returns" props={[
|
|
69
|
+
{ name: "confirm", type: "(options?: ConfirmOptions) => Promise<boolean>", default: "-" },
|
|
70
|
+
{ name: "isOpen", type: "boolean", default: "-" },
|
|
71
|
+
{ name: "options", type: "ConfirmOptions", default: "-" },
|
|
72
|
+
{ name: "handleConfirm", type: "() => void", default: "-" },
|
|
73
|
+
{ name: "handleCancel", type: "() => void", default: "-" },
|
|
74
|
+
]} />
|
|
75
|
+
|
|
76
|
+
<APIReference name="ConfirmOptions" props={[
|
|
77
|
+
{ name: "title", type: "string", default: "-" },
|
|
78
|
+
{ name: "description", type: "string", default: "-" },
|
|
79
|
+
{ name: "confirmLabel", type: "string", default: "-" },
|
|
80
|
+
{ name: "cancelLabel", type: "string", default: "-" },
|
|
81
|
+
]} />
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useControlledOpen
|
|
3
|
+
description: Simple open/close state for modals, drawers, dropdowns, and any toggleable UI.
|
|
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
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
bun add @olwiba/ui
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { useControlledOpen } from "@olwiba/ui";
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { Dialog } from "@olwiba/cn";
|
|
24
|
+
|
|
25
|
+
function Example() {
|
|
26
|
+
const { isOpen, open, close, toggle, setIsOpen } = useControlledOpen();
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<>
|
|
30
|
+
<button onClick={open}>Open dialog</button>
|
|
31
|
+
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
|
32
|
+
...
|
|
33
|
+
</Dialog>
|
|
34
|
+
</>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`setIsOpen` is stable and safe to pass directly to Radix `onOpenChange` handlers. All returned functions are memoized with `useCallback`.
|
|
40
|
+
|
|
41
|
+
## API Reference
|
|
42
|
+
|
|
43
|
+
<APIReference name="useControlledOpen" props={[
|
|
44
|
+
{ name: "defaultOpen", type: "boolean", default: "false" },
|
|
45
|
+
]} />
|
|
46
|
+
|
|
47
|
+
<APIReference name="useControlledOpen → returns" props={[
|
|
48
|
+
{ name: "isOpen", type: "boolean", default: "-" },
|
|
49
|
+
{ name: "open", type: "() => void", default: "-" },
|
|
50
|
+
{ name: "close", type: "() => void", default: "-" },
|
|
51
|
+
{ name: "toggle", type: "() => void", default: "-" },
|
|
52
|
+
{ name: "setIsOpen", type: "Dispatch<SetStateAction<boolean>>", default: "-" },
|
|
53
|
+
]} />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useCopyToClipboard
|
|
3
|
+
description: Copies text to clipboard and exposes a boolean copied feedback state.
|
|
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="use-copy-to-clipboard" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @olwiba/ui
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { useCopyToClipboard } from "@olwiba/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## API Reference
|
|
25
|
+
|
|
26
|
+
<APIReference name="useCopyToClipboard" props={[]} />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useDebounce
|
|
3
|
+
description: Debounces a value — returns the stabilised value after a delay.
|
|
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="use-debounce" />
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
bun add @olwiba/ui
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { useDebounce } from "@olwiba/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## API Reference
|
|
25
|
+
|
|
26
|
+
<APIReference name="useDebounce" props={[]} />
|