@mdxui/zero 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/preview.ts +20 -0
- package/.turbo/turbo-typecheck.log +5 -0
- package/ARCHITECTURE.md +415 -0
- package/CHANGELOG.md +80 -0
- package/README.md +205 -0
- package/package.json +43 -0
- package/playwright.config.ts +55 -0
- package/src/components/index.ts +20 -0
- package/src/compose/email-composer.stories.tsx +219 -0
- package/src/compose/email-composer.tsx +619 -0
- package/src/compose/index.ts +14 -0
- package/src/dashboard/index.ts +14 -0
- package/src/dashboard/mail-shell.stories.tsx +272 -0
- package/src/dashboard/mail-shell.tsx +199 -0
- package/src/dashboard/mail-sidebar.stories.tsx +158 -0
- package/src/dashboard/mail-sidebar.tsx +388 -0
- package/src/index.ts +24 -0
- package/src/landing/index.ts +24 -0
- package/src/mail/index.ts +15 -0
- package/src/mail/mail-item.stories.tsx +422 -0
- package/src/mail/mail-item.tsx +229 -0
- package/src/mail/mail-list.stories.tsx +320 -0
- package/src/mail/mail-list.tsx +262 -0
- package/src/mail/message-view.stories.tsx +459 -0
- package/src/mail/message-view.tsx +378 -0
- package/src/mail/thread-display.stories.tsx +260 -0
- package/src/mail/thread-display.tsx +392 -0
- package/src/pages/index.ts +9 -0
- package/src/pages/mail-zero-page.stories.tsx +251 -0
- package/src/pages/mail-zero-page.tsx +334 -0
- package/tests/visual/report/index.html +85 -0
- package/tests/visual/snapshots/zero-components.spec.ts/mail-shell-default.png +0 -0
- package/tests/visual/zero-components.spec.ts +321 -0
- package/tsconfig.json +5 -0
package/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# @mdxui/zero
|
|
2
|
+
|
|
3
|
+
AI-powered email client components for mdxui. Provides a complete email application UI including mail lists, thread display, composition, and dashboard layouts.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @mdxui/zero
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { MailZeroPage } from '@mdxui/zero'
|
|
15
|
+
|
|
16
|
+
function App() {
|
|
17
|
+
return (
|
|
18
|
+
<MailZeroPage
|
|
19
|
+
initialThreads={threads}
|
|
20
|
+
initialFolders={folders}
|
|
21
|
+
initialLabels={labels}
|
|
22
|
+
user={{ name: 'John', email: 'john@example.com.ai' }}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Package Structure
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
@mdxui/zero
|
|
32
|
+
├── /mail # Core mail components
|
|
33
|
+
│ ├── MailList # Thread list with selection
|
|
34
|
+
│ ├── MailItem # Individual thread item
|
|
35
|
+
│ ├── ThreadDisplay # Full thread view
|
|
36
|
+
│ └── MessageView # Single message display
|
|
37
|
+
├── /compose # Email composition
|
|
38
|
+
│ └── EmailComposer # Full compose UI with toolbar
|
|
39
|
+
├── /dashboard # Layout components
|
|
40
|
+
│ ├── MailShell # Three-panel resizable layout
|
|
41
|
+
│ └── MailSidebar # Folder/label navigation
|
|
42
|
+
├── /landing # Landing page components
|
|
43
|
+
└── /pages # Complete page compositions
|
|
44
|
+
└── MailZeroPage # Full email app with state
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Components
|
|
48
|
+
|
|
49
|
+
### MailZeroPage
|
|
50
|
+
|
|
51
|
+
Complete email application with internal state management. Use this for a full email experience.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { MailZeroPage } from '@mdxui/zero'
|
|
55
|
+
|
|
56
|
+
<MailZeroPage
|
|
57
|
+
initialThreads={threads}
|
|
58
|
+
initialFolders={folders}
|
|
59
|
+
initialLabels={labels}
|
|
60
|
+
initialFolderId="inbox"
|
|
61
|
+
user={{ name: 'John Doe', email: 'john@example.com.ai' }}
|
|
62
|
+
/>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
All interactions (reply, archive, delete, etc.) are handled internally. Check the browser console for action logs.
|
|
66
|
+
|
|
67
|
+
### MailShell
|
|
68
|
+
|
|
69
|
+
Three-panel resizable layout combining sidebar, mail list, and thread display. Use when you need custom state management.
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { MailShell } from '@mdxui/zero/dashboard'
|
|
73
|
+
|
|
74
|
+
<MailShell
|
|
75
|
+
// Sidebar props
|
|
76
|
+
folders={folders}
|
|
77
|
+
activeFolderId="inbox"
|
|
78
|
+
onFolderClick={(folderId) => setActiveFolder(folderId)}
|
|
79
|
+
|
|
80
|
+
// List props
|
|
81
|
+
threads={threads}
|
|
82
|
+
onThreadClick={(thread) => setActiveThread(thread)}
|
|
83
|
+
|
|
84
|
+
// Thread display props
|
|
85
|
+
activeThread={activeThread}
|
|
86
|
+
onReply={(messageId) => openComposer({ replyTo: messageId })}
|
|
87
|
+
onArchive={() => archiveThread(activeThread.id)}
|
|
88
|
+
/>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### MailList
|
|
92
|
+
|
|
93
|
+
Thread list with selection, virtualization, and keyboard navigation.
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { MailList } from '@mdxui/zero/mail'
|
|
97
|
+
|
|
98
|
+
<MailList
|
|
99
|
+
threads={threads}
|
|
100
|
+
selectedIds={selectedIds}
|
|
101
|
+
activeId={activeId}
|
|
102
|
+
selectionMode="multiple"
|
|
103
|
+
displayMode="comfortable"
|
|
104
|
+
onThreadClick={(thread) => setActiveThread(thread)}
|
|
105
|
+
onSelectionChange={(ids) => setSelectedIds(ids)}
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### ThreadDisplay
|
|
110
|
+
|
|
111
|
+
Full thread view with message list and actions.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { ThreadDisplay } from '@mdxui/zero/mail'
|
|
115
|
+
|
|
116
|
+
<ThreadDisplay
|
|
117
|
+
thread={thread}
|
|
118
|
+
onReply={(messageId) => openComposer({ replyTo: messageId })}
|
|
119
|
+
onReplyAll={(messageId) => openComposer({ replyAllTo: messageId })}
|
|
120
|
+
onForward={(messageId) => openComposer({ forward: messageId })}
|
|
121
|
+
onSnooze={(isoDate) => snoozeThread(thread.id, isoDate)}
|
|
122
|
+
onMove={(folderId) => moveThread(thread.id, folderId)}
|
|
123
|
+
onLabel={(labelIds) => labelThread(thread.id, labelIds)}
|
|
124
|
+
/>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### EmailComposer
|
|
128
|
+
|
|
129
|
+
Rich email composition with toolbar, recipient input, and AI assistance.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { EmailComposer } from '@mdxui/zero/compose'
|
|
133
|
+
|
|
134
|
+
<EmailComposer
|
|
135
|
+
mode="compose"
|
|
136
|
+
initialDraft={{ to: [], subject: '', body: '' }}
|
|
137
|
+
onSend={(draft) => sendEmail(draft)}
|
|
138
|
+
onSaveDraft={(draft) => saveDraft(draft)}
|
|
139
|
+
onDiscard={() => closeComposer()}
|
|
140
|
+
/>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Callback Signatures
|
|
144
|
+
|
|
145
|
+
All callbacks receive appropriate context:
|
|
146
|
+
|
|
147
|
+
| Callback | Signature | Context |
|
|
148
|
+
|----------|-----------|---------|
|
|
149
|
+
| `onReply` | `(messageId: string) => void` | Reply to specific message |
|
|
150
|
+
| `onReplyAll` | `(messageId: string) => void` | Reply-all to specific message |
|
|
151
|
+
| `onForward` | `(messageId: string) => void` | Forward specific message |
|
|
152
|
+
| `onSnooze` | `(isoDate: string) => void` | Snooze until date |
|
|
153
|
+
| `onMove` | `(folderId: string) => void` | Move to folder |
|
|
154
|
+
| `onLabel` | `(labelIds: string[]) => void` | Toggle labels |
|
|
155
|
+
| `onThreadClick` | `(thread: Thread) => void` | Thread object |
|
|
156
|
+
| `onFolderClick` | `(folderId: string) => void` | Folder ID |
|
|
157
|
+
|
|
158
|
+
Thread-level actions (archive, delete, spam, star, print) are void callbacks - the parent tracks the active thread.
|
|
159
|
+
|
|
160
|
+
## Types
|
|
161
|
+
|
|
162
|
+
Types are defined in `mdxui` package:
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
import type {
|
|
166
|
+
MailThread as Thread,
|
|
167
|
+
MailMessage as Message,
|
|
168
|
+
Folder,
|
|
169
|
+
MailLabel as Label,
|
|
170
|
+
MailShellProps,
|
|
171
|
+
ThreadDisplayProps,
|
|
172
|
+
MailListProps,
|
|
173
|
+
} from 'mdxui'
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Development
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Type check
|
|
180
|
+
pnpm --filter @mdxui/zero typecheck
|
|
181
|
+
|
|
182
|
+
# Run Storybook
|
|
183
|
+
pnpm storybook
|
|
184
|
+
|
|
185
|
+
# Visual regression tests (requires Storybook running)
|
|
186
|
+
pnpm --filter @mdxui/zero test:visual
|
|
187
|
+
|
|
188
|
+
# Update visual baselines
|
|
189
|
+
pnpm --filter @mdxui/zero test:visual:update
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Current Limitations
|
|
193
|
+
|
|
194
|
+
This package currently provides **UI components only**. It lacks the full app infrastructure found in [Mail-0/Zero](https://github.com/Mail-0/Zero):
|
|
195
|
+
|
|
196
|
+
- No react-router integration
|
|
197
|
+
- No state management (jotai/react-query)
|
|
198
|
+
- No data layer / API integration
|
|
199
|
+
- No proper page routing
|
|
200
|
+
|
|
201
|
+
See [ARCHITECTURE.md](./ARCHITECTURE.md) for the target architecture and implementation plan.
|
|
202
|
+
|
|
203
|
+
## Credits
|
|
204
|
+
|
|
205
|
+
Components ported from [Mail-0/Zero](https://github.com/Mail-0/Zero), an AI-powered email client.
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mdxui/zero",
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"description": "Zero Email components for mdxui - AI-powered email client UI",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts",
|
|
9
|
+
"./mail": "./src/mail/index.ts",
|
|
10
|
+
"./compose": "./src/compose/index.ts",
|
|
11
|
+
"./landing": "./src/landing/index.ts",
|
|
12
|
+
"./dashboard": "./src/dashboard/index.ts",
|
|
13
|
+
"./components": "./src/components/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@playwright/test": "^1.49.0",
|
|
17
|
+
"@types/react": "^19.2.7",
|
|
18
|
+
"@types/react-dom": "^19.2.3",
|
|
19
|
+
"typescript": "5.9.3",
|
|
20
|
+
"@mdxui/typescript-config": "6.0.0"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"lucide-react": "^0.561.0",
|
|
24
|
+
"motion": "^12.23.26",
|
|
25
|
+
"react": "^19.2.3",
|
|
26
|
+
"zod": "^4.3.5",
|
|
27
|
+
"@mdxui/primitives": "6.0.0",
|
|
28
|
+
"mdxui": "6.0.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"typecheck": "tsc --noEmit",
|
|
38
|
+
"clean": "rm -rf .turbo node_modules",
|
|
39
|
+
"test:visual": "playwright test",
|
|
40
|
+
"test:visual:update": "playwright test --update-snapshots",
|
|
41
|
+
"test:visual:ui": "playwright test --ui"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test'
|
|
2
|
+
import { visualTestDefaults } from '../../playwright.base.config'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Playwright Visual Regression Test Configuration for @mdxui/zero
|
|
6
|
+
*
|
|
7
|
+
* These tests compare our Zero components against the original Mail-0/Zero design.
|
|
8
|
+
* Extends visualTestDefaults from base config.
|
|
9
|
+
*/
|
|
10
|
+
export default defineConfig({
|
|
11
|
+
testDir: './tests/visual',
|
|
12
|
+
snapshotDir: './tests/visual/snapshots',
|
|
13
|
+
snapshotPathTemplate: '{snapshotDir}/{testFilePath}/{arg}{ext}',
|
|
14
|
+
|
|
15
|
+
fullyParallel: true,
|
|
16
|
+
forbidOnly: !!process.env.CI,
|
|
17
|
+
retries: process.env.CI ? 2 : 0,
|
|
18
|
+
workers: process.env.CI ? 1 : undefined,
|
|
19
|
+
|
|
20
|
+
reporter: [
|
|
21
|
+
['html', { outputFolder: './tests/visual/report' }],
|
|
22
|
+
['list'],
|
|
23
|
+
],
|
|
24
|
+
|
|
25
|
+
// Standard visual comparison settings
|
|
26
|
+
...visualTestDefaults,
|
|
27
|
+
|
|
28
|
+
use: {
|
|
29
|
+
baseURL: 'http://localhost:6006',
|
|
30
|
+
trace: 'on-first-retry',
|
|
31
|
+
screenshot: 'only-on-failure',
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
projects: [
|
|
35
|
+
{
|
|
36
|
+
name: 'chromium',
|
|
37
|
+
use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 800 } },
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'chromium-wide',
|
|
41
|
+
use: { ...devices['Desktop Chrome'], viewport: { width: 1920, height: 1080 } },
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'mobile',
|
|
45
|
+
use: { ...devices['iPhone 14'] },
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
webServer: {
|
|
50
|
+
command: 'pnpm storybook',
|
|
51
|
+
url: 'http://localhost:6006',
|
|
52
|
+
reuseExistingServer: !process.env.CI,
|
|
53
|
+
timeout: 120_000,
|
|
54
|
+
},
|
|
55
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Components
|
|
3
|
+
*
|
|
4
|
+
* Reusable UI components used across Zero:
|
|
5
|
+
* - PricingCard: Pricing tier card
|
|
6
|
+
* - PricingSwitch: Monthly/annual toggle
|
|
7
|
+
* - SnoozeDialog: Email snooze picker
|
|
8
|
+
* - AttachmentDialog: Attachment viewer
|
|
9
|
+
* - LabelBadge: Email label badge
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Components will be added as they are ported from Zero
|
|
13
|
+
// export { PricingCard } from './pricing-card'
|
|
14
|
+
// export { PricingSwitch } from './pricing-switch'
|
|
15
|
+
// export { SnoozeDialog } from './snooze-dialog'
|
|
16
|
+
// export { AttachmentDialog } from './attachment-dialog'
|
|
17
|
+
// export { LabelBadge } from './label-badge'
|
|
18
|
+
|
|
19
|
+
// Placeholder export to make this a valid module
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import type { DraftState } from "mdxui";
|
|
3
|
+
import { EditorToolbar, EmailComposer, RecipientInput } from "./email-composer";
|
|
4
|
+
|
|
5
|
+
const sampleDraft: DraftState = {
|
|
6
|
+
to: [{ address: "alex@startup.io", name: "Alex Rivera" }],
|
|
7
|
+
cc: [],
|
|
8
|
+
bcc: [],
|
|
9
|
+
subject: "Quick follow-up on our call",
|
|
10
|
+
body: "Hi Alex,\n\nJust wanted to follow up on our conversation earlier today about the product roadmap.\n\nLet me know if you have any questions!\n\nBest,\nMe",
|
|
11
|
+
attachments: [],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const replyToMessage = {
|
|
15
|
+
id: "m1",
|
|
16
|
+
threadId: "t1",
|
|
17
|
+
subject: "Re: Product Launch Strategy",
|
|
18
|
+
from: { address: "alex@startup.io", name: "Alex Rivera" },
|
|
19
|
+
to: [{ address: "me@company.com", name: "Me" }],
|
|
20
|
+
date: new Date().toISOString(),
|
|
21
|
+
snippet: "Thanks for the update! Looking forward to the launch.",
|
|
22
|
+
textBody: "Thanks for the update! Looking forward to the launch.",
|
|
23
|
+
attachments: [],
|
|
24
|
+
labels: [],
|
|
25
|
+
isRead: true,
|
|
26
|
+
isStarred: false,
|
|
27
|
+
isImportant: false,
|
|
28
|
+
isDraft: false,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const meta: Meta<typeof EmailComposer> = {
|
|
32
|
+
title: "Zero/Compose/EmailComposer",
|
|
33
|
+
component: EmailComposer,
|
|
34
|
+
parameters: {
|
|
35
|
+
layout: "fullscreen",
|
|
36
|
+
},
|
|
37
|
+
tags: ["autodocs"],
|
|
38
|
+
decorators: [
|
|
39
|
+
(Story) => (
|
|
40
|
+
<div className="h-screen w-full max-w-4xl mx-auto p-4 bg-background">
|
|
41
|
+
<Story />
|
|
42
|
+
</div>
|
|
43
|
+
),
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default meta;
|
|
48
|
+
type Story = StoryObj<typeof meta>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* New email composition.
|
|
52
|
+
* Matches the original Zero compose interface.
|
|
53
|
+
*/
|
|
54
|
+
export const Default: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
mode: "new",
|
|
57
|
+
showCcBcc: false,
|
|
58
|
+
enableAI: true,
|
|
59
|
+
enableShortcuts: true,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* With draft content pre-filled.
|
|
65
|
+
*/
|
|
66
|
+
export const WithDraft: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
mode: "new",
|
|
69
|
+
initialDraft: sampleDraft,
|
|
70
|
+
showCcBcc: false,
|
|
71
|
+
enableAI: true,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Reply mode with quoted message.
|
|
77
|
+
*/
|
|
78
|
+
export const Reply: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
mode: "reply",
|
|
81
|
+
replyTo: replyToMessage,
|
|
82
|
+
showCcBcc: false,
|
|
83
|
+
enableAI: true,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Reply-all mode.
|
|
89
|
+
*/
|
|
90
|
+
export const ReplyAll: Story = {
|
|
91
|
+
args: {
|
|
92
|
+
mode: "reply-all",
|
|
93
|
+
replyTo: replyToMessage,
|
|
94
|
+
showCcBcc: true,
|
|
95
|
+
enableAI: true,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Forward mode.
|
|
101
|
+
*/
|
|
102
|
+
export const Forward: Story = {
|
|
103
|
+
args: {
|
|
104
|
+
mode: "forward",
|
|
105
|
+
replyTo: replyToMessage,
|
|
106
|
+
showCcBcc: false,
|
|
107
|
+
enableAI: true,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Maximized view.
|
|
113
|
+
*/
|
|
114
|
+
export const Maximized: Story = {
|
|
115
|
+
args: {
|
|
116
|
+
mode: "new",
|
|
117
|
+
isMaximized: true,
|
|
118
|
+
showCcBcc: true,
|
|
119
|
+
enableAI: true,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* With CC/BCC fields visible.
|
|
125
|
+
*/
|
|
126
|
+
export const WithCcBcc: Story = {
|
|
127
|
+
args: {
|
|
128
|
+
mode: "new",
|
|
129
|
+
showCcBcc: true,
|
|
130
|
+
enableAI: true,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Sending state.
|
|
136
|
+
*/
|
|
137
|
+
export const Sending: Story = {
|
|
138
|
+
args: {
|
|
139
|
+
mode: "new",
|
|
140
|
+
initialDraft: sampleDraft,
|
|
141
|
+
isSending: true,
|
|
142
|
+
enableAI: true,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Without AI features.
|
|
148
|
+
*/
|
|
149
|
+
export const NoAI: Story = {
|
|
150
|
+
args: {
|
|
151
|
+
mode: "new",
|
|
152
|
+
showCcBcc: false,
|
|
153
|
+
enableAI: false,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* With email signature.
|
|
159
|
+
*/
|
|
160
|
+
export const WithSignature: Story = {
|
|
161
|
+
args: {
|
|
162
|
+
mode: "new",
|
|
163
|
+
showCcBcc: false,
|
|
164
|
+
enableAI: true,
|
|
165
|
+
enableSignature: true,
|
|
166
|
+
signature: "\n\n--\nJohn Doe\nProduct Manager\nAcme Inc.",
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// RecipientInput story
|
|
171
|
+
export const RecipientInputDefault: StoryObj<typeof RecipientInput> = {
|
|
172
|
+
render: () => (
|
|
173
|
+
<div className="max-w-2xl p-4 bg-background">
|
|
174
|
+
<RecipientInput
|
|
175
|
+
field="to"
|
|
176
|
+
value={[
|
|
177
|
+
{ address: "alex@example.com.ai", name: "Alex Rivera" },
|
|
178
|
+
{ address: "sarah@example.com.ai", name: "Sarah Chen" },
|
|
179
|
+
]}
|
|
180
|
+
onChange={() => {}}
|
|
181
|
+
placeholder="Add recipients"
|
|
182
|
+
showAvatars={true}
|
|
183
|
+
disabled={false}
|
|
184
|
+
autoFocus={false}
|
|
185
|
+
allowFreeEntry={true}
|
|
186
|
+
/>
|
|
187
|
+
</div>
|
|
188
|
+
),
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// EditorToolbar story
|
|
192
|
+
export const ToolbarDefault: StoryObj<typeof EditorToolbar> = {
|
|
193
|
+
render: () => (
|
|
194
|
+
<div className="max-w-2xl p-4 bg-background border rounded-lg">
|
|
195
|
+
<EditorToolbar
|
|
196
|
+
onAction={() => {}}
|
|
197
|
+
showAI={true}
|
|
198
|
+
disabled={false}
|
|
199
|
+
compact={false}
|
|
200
|
+
sticky={false}
|
|
201
|
+
/>
|
|
202
|
+
</div>
|
|
203
|
+
),
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// EditorToolbar compact
|
|
207
|
+
export const ToolbarCompact: StoryObj<typeof EditorToolbar> = {
|
|
208
|
+
render: () => (
|
|
209
|
+
<div className="max-w-xl p-4 bg-background border rounded-lg">
|
|
210
|
+
<EditorToolbar
|
|
211
|
+
onAction={() => {}}
|
|
212
|
+
showAI={true}
|
|
213
|
+
disabled={false}
|
|
214
|
+
compact={true}
|
|
215
|
+
sticky={false}
|
|
216
|
+
/>
|
|
217
|
+
</div>
|
|
218
|
+
),
|
|
219
|
+
};
|