@olwiba/ui 0.0.38 → 0.0.42

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olwiba/ui",
3
- "version": "0.0.38",
3
+ "version": "0.0.42",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -9,7 +9,12 @@
9
9
  "module": "./dist/index.js",
10
10
  "exports": {
11
11
  ".": {
12
- "import": "./dist/index.js"
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./email": {
16
+ "import": "./dist/email/index.js",
17
+ "types": "./dist/email/index.d.ts"
13
18
  }
14
19
  },
15
20
  "files": [
@@ -44,7 +49,7 @@
44
49
  },
45
50
  "peerDependencies": {
46
51
  "@content-collections/mdx": ">=0.2.0",
47
- "@olwiba/cn": ">=0.1.2",
52
+ "@olwiba/cn": ">=0.1.16",
48
53
  "react": ">=18.0.0",
49
54
  "react-dom": ">=18.0.0"
50
55
  },
@@ -55,7 +60,7 @@
55
60
  },
56
61
  "devDependencies": {
57
62
  "@content-collections/mdx": "^0.2.2",
58
- "@olwiba/cn": "^0.1.15",
63
+ "@olwiba/cn": "0.1.17",
59
64
  "@tailwindcss/vite": "^4.1.18",
60
65
  "@tanstack/react-router": "1.154.8",
61
66
  "@tanstack/react-router-devtools": "1.154.8",
@@ -219,7 +219,11 @@ function ShellSidebar({
219
219
  href: brand.href ?? '#',
220
220
  children: (
221
221
  <>
222
- {brand.logo ?? (
222
+ {brand.logo ? (
223
+ <span className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground">
224
+ {brand.logo}
225
+ </span>
226
+ ) : (
223
227
  <span className="flex size-4 shrink-0 items-center justify-center text-sm font-semibold">
224
228
  {fallbackLogo}
225
229
  </span>
@@ -0,0 +1,43 @@
1
+ import {
2
+ EmailButton,
3
+ EmailHeading,
4
+ EmailText,
5
+ emailTheme,
6
+ } from '@olwiba/cn/email';
7
+ import { EmailLayout } from './EmailLayout';
8
+ import { EmailLinkFallback } from './EmailLinkFallback';
9
+
10
+ export interface ActionEmailProps {
11
+ appName: string;
12
+ preview: string;
13
+ heading: string;
14
+ description: string;
15
+ actionLabel: string;
16
+ actionUrl: string;
17
+ brandColor?: string;
18
+ showLinkFallback?: boolean;
19
+ }
20
+
21
+ export function ActionEmail({
22
+ appName,
23
+ preview,
24
+ heading,
25
+ description,
26
+ actionLabel,
27
+ actionUrl,
28
+ brandColor = emailTheme.defaultBrandColor,
29
+ showLinkFallback = true,
30
+ }: ActionEmailProps) {
31
+ return (
32
+ <EmailLayout preview={preview} appName={appName} brandColor={brandColor}>
33
+ <EmailHeading>{heading}</EmailHeading>
34
+ <EmailText variant="muted" style={{ margin: '0 0 24px' }}>
35
+ {description}
36
+ </EmailText>
37
+ <EmailButton href={actionUrl} label={actionLabel} brandColor={brandColor} />
38
+ {showLinkFallback ? (
39
+ <EmailLinkFallback actionUrl={actionUrl} brandColor={brandColor} />
40
+ ) : null}
41
+ </EmailLayout>
42
+ );
43
+ }
@@ -0,0 +1,96 @@
1
+ import type { ReactNode } from 'react';
2
+ import {
3
+ EmailBody,
4
+ EmailContainer,
5
+ EmailHead,
6
+ EmailPreview,
7
+ EmailRoot,
8
+ EmailSection,
9
+ EmailText,
10
+ emailTheme,
11
+ } from '@olwiba/cn/email';
12
+
13
+ export interface EmailLayoutProps {
14
+ preview?: string;
15
+ appName: string;
16
+ brandColor?: string;
17
+ children: ReactNode;
18
+ footer?: ReactNode;
19
+ }
20
+
21
+ /** Branded email shell — UI block composed from CN primitives. */
22
+ export function EmailLayout({
23
+ preview,
24
+ appName,
25
+ brandColor = emailTheme.defaultBrandColor,
26
+ children,
27
+ footer,
28
+ }: EmailLayoutProps) {
29
+ const year = new Date().getFullYear();
30
+
31
+ return (
32
+ <EmailRoot>
33
+ <EmailHead />
34
+ {preview ? <EmailPreview>{preview}</EmailPreview> : null}
35
+ <EmailBody
36
+ style={{
37
+ backgroundColor: emailTheme.pageBackground,
38
+ fontFamily: emailTheme.fontFamily,
39
+ margin: 0,
40
+ padding: '24px 0',
41
+ }}
42
+ >
43
+ <EmailContainer
44
+ style={{
45
+ maxWidth: '560px',
46
+ margin: '0 auto',
47
+ backgroundColor: emailTheme.cardBackground,
48
+ borderRadius: '16px',
49
+ overflow: 'hidden',
50
+ border: `1px solid ${emailTheme.cardBorder}`,
51
+ }}
52
+ >
53
+ <EmailSection
54
+ style={{
55
+ padding: '24px 32px',
56
+ borderBottom: `1px solid ${emailTheme.cardBorder}`,
57
+ }}
58
+ >
59
+ <EmailText
60
+ style={{
61
+ margin: 0,
62
+ fontSize: '18px',
63
+ fontWeight: 600,
64
+ color: brandColor,
65
+ }}
66
+ >
67
+ {appName}
68
+ </EmailText>
69
+ </EmailSection>
70
+
71
+ <EmailSection style={{ padding: '32px' }}>{children}</EmailSection>
72
+
73
+ {footer ?? (
74
+ <EmailSection
75
+ style={{
76
+ padding: '20px 32px',
77
+ borderTop: `1px solid ${emailTheme.cardBorder}`,
78
+ backgroundColor: emailTheme.mutedBackground,
79
+ }}
80
+ >
81
+ <EmailText
82
+ variant="caption"
83
+ style={{
84
+ margin: 0,
85
+ textAlign: 'center',
86
+ }}
87
+ >
88
+ © {year} {appName}. All rights reserved.
89
+ </EmailText>
90
+ </EmailSection>
91
+ )}
92
+ </EmailContainer>
93
+ </EmailBody>
94
+ </EmailRoot>
95
+ );
96
+ }
@@ -0,0 +1,26 @@
1
+ import { EmailLink, EmailText } from '@olwiba/cn/email';
2
+
3
+ export interface EmailLinkFallbackProps {
4
+ actionUrl: string;
5
+ label?: string;
6
+ brandColor?: string;
7
+ }
8
+
9
+ export function EmailLinkFallback({
10
+ actionUrl,
11
+ label = 'Or copy and paste this link into your browser:',
12
+ brandColor,
13
+ }: EmailLinkFallbackProps) {
14
+ return (
15
+ <>
16
+ <EmailText variant="caption" style={{ margin: '24px 0 8px' }}>
17
+ {label}
18
+ </EmailText>
19
+ <EmailText style={{ margin: 0 }}>
20
+ <EmailLink href={actionUrl} brandColor={brandColor}>
21
+ {actionUrl}
22
+ </EmailLink>
23
+ </EmailText>
24
+ </>
25
+ );
26
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ EmailHeading,
3
+ EmailText,
4
+ emailTheme,
5
+ } from '@olwiba/cn/email';
6
+ import { EmailLayout } from './EmailLayout';
7
+
8
+ export interface NoticeEmailProps {
9
+ appName: string;
10
+ preview: string;
11
+ heading: string;
12
+ body: string;
13
+ brandColor?: string;
14
+ }
15
+
16
+ export function NoticeEmail({
17
+ appName,
18
+ preview,
19
+ heading,
20
+ body,
21
+ brandColor = emailTheme.defaultBrandColor,
22
+ }: NoticeEmailProps) {
23
+ return (
24
+ <EmailLayout preview={preview} appName={appName} brandColor={brandColor}>
25
+ <EmailHeading>{heading}</EmailHeading>
26
+ <EmailText variant="muted" style={{ margin: 0, whiteSpace: 'pre-wrap' }}>
27
+ {body}
28
+ </EmailText>
29
+ </EmailLayout>
30
+ );
31
+ }
@@ -0,0 +1,3 @@
1
+ export { ActionEmail, type ActionEmailProps } from './ActionEmail';
2
+ export { NoticeEmail, type NoticeEmailProps } from './NoticeEmail';
3
+ export { EmailLayout, type EmailLayoutProps } from './EmailLayout';
package/src/index.ts CHANGED
@@ -14,6 +14,9 @@ export {
14
14
  // ─── Primitives — mode-aware re-exports of @olwiba/cn components ─────────────
15
15
  export * from './primitives';
16
16
 
17
+ // ─── Layout — grid, stack, section primitives ────────────────────────────────
18
+ export * from './layout';
19
+
17
20
  // ─── App — shells, auth, feedback ────────────────────────────────────────────
18
21
  export {
19
22
  AppShell,
@@ -0,0 +1,72 @@
1
+ import React from 'react'
2
+ import { cn } from '../lib/utils'
3
+
4
+ const colsMap: Record<number, string> = {
5
+ 1: 'grid-cols-1',
6
+ 2: 'grid-cols-2',
7
+ 3: 'grid-cols-3',
8
+ 4: 'grid-cols-4',
9
+ 5: 'grid-cols-5',
10
+ 6: 'grid-cols-6',
11
+ 12: 'grid-cols-12',
12
+ }
13
+
14
+ const gapMap = {
15
+ none: 'gap-0',
16
+ xs: 'gap-2',
17
+ sm: 'gap-3',
18
+ md: 'gap-4',
19
+ lg: 'gap-6',
20
+ xl: 'gap-8',
21
+ }
22
+
23
+ const spanMap: Record<number, string> = {
24
+ 1: 'col-span-1',
25
+ 2: 'col-span-2',
26
+ 3: 'col-span-3',
27
+ 4: 'col-span-4',
28
+ 5: 'col-span-5',
29
+ 6: 'col-span-6',
30
+ 7: 'col-span-7',
31
+ 8: 'col-span-8',
32
+ 9: 'col-span-9',
33
+ 10: 'col-span-10',
34
+ 11: 'col-span-11',
35
+ 12: 'col-span-12',
36
+ }
37
+
38
+ const rowSpanMap: Record<number, string> = {
39
+ 1: 'row-span-1',
40
+ 2: 'row-span-2',
41
+ 3: 'row-span-3',
42
+ 4: 'row-span-4',
43
+ }
44
+
45
+ export interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
46
+ columns?: 1 | 2 | 3 | 4 | 5 | 6 | 12
47
+ gap?: keyof typeof gapMap
48
+ }
49
+
50
+ export function Grid({ columns = 3, gap = 'md', className, children, ...props }: GridProps) {
51
+ return (
52
+ <div className={cn('grid', colsMap[columns], gapMap[gap], className)} {...props}>
53
+ {children}
54
+ </div>
55
+ )
56
+ }
57
+
58
+ export interface GridItemProps extends React.HTMLAttributes<HTMLDivElement> {
59
+ span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
60
+ rowSpan?: 1 | 2 | 3 | 4
61
+ }
62
+
63
+ export function GridItem({ span = 1, rowSpan, className, children, ...props }: GridItemProps) {
64
+ return (
65
+ <div
66
+ className={cn(spanMap[span], rowSpan != null && rowSpanMap[rowSpan], className)}
67
+ {...props}
68
+ >
69
+ {children}
70
+ </div>
71
+ )
72
+ }
@@ -0,0 +1,29 @@
1
+ import React from 'react'
2
+ import { cn } from '../lib/utils'
3
+
4
+ const paddingMap = {
5
+ none: '',
6
+ sm: 'py-4',
7
+ md: 'py-8',
8
+ lg: 'py-16',
9
+ }
10
+
11
+ export interface SectionProps extends React.HTMLAttributes<HTMLElement> {
12
+ title?: string
13
+ description?: string
14
+ padding?: keyof typeof paddingMap
15
+ }
16
+
17
+ export function Section({ title, description, padding = 'md', className, children, ...props }: SectionProps) {
18
+ return (
19
+ <section className={cn('w-full', paddingMap[padding], className)} {...props}>
20
+ {(title || description) && (
21
+ <div className="mb-6">
22
+ {title && <h2 className="text-xl font-semibold text-foreground">{title}</h2>}
23
+ {description && <p className="mt-1 text-sm text-muted-foreground">{description}</p>}
24
+ </div>
25
+ )}
26
+ {children}
27
+ </section>
28
+ )
29
+ }
@@ -0,0 +1,62 @@
1
+ import React from 'react'
2
+ import { cn } from '../lib/utils'
3
+
4
+ const gapMap = {
5
+ none: 'gap-0',
6
+ xs: 'gap-2',
7
+ sm: 'gap-3',
8
+ md: 'gap-4',
9
+ lg: 'gap-6',
10
+ xl: 'gap-8',
11
+ }
12
+
13
+ const alignMap = {
14
+ start: 'items-start',
15
+ center: 'items-center',
16
+ end: 'items-end',
17
+ stretch: 'items-stretch',
18
+ }
19
+
20
+ const justifyMap = {
21
+ start: 'justify-start',
22
+ center: 'justify-center',
23
+ end: 'justify-end',
24
+ between: 'justify-between',
25
+ around: 'justify-around',
26
+ }
27
+
28
+ export interface StackProps extends React.HTMLAttributes<HTMLDivElement> {
29
+ direction?: 'col' | 'row'
30
+ gap?: keyof typeof gapMap
31
+ align?: keyof typeof alignMap
32
+ justify?: keyof typeof justifyMap
33
+ wrap?: boolean
34
+ }
35
+
36
+ export function Stack({
37
+ direction = 'col',
38
+ gap = 'md',
39
+ align = 'stretch',
40
+ justify = 'start',
41
+ wrap = false,
42
+ className,
43
+ children,
44
+ ...props
45
+ }: StackProps) {
46
+ return (
47
+ <div
48
+ className={cn(
49
+ 'flex',
50
+ direction === 'col' ? 'flex-col' : 'flex-row',
51
+ gapMap[gap],
52
+ alignMap[align],
53
+ justifyMap[justify],
54
+ wrap && 'flex-wrap',
55
+ className,
56
+ )}
57
+ {...props}
58
+ >
59
+ {children}
60
+ </div>
61
+ )
62
+ }
@@ -0,0 +1,6 @@
1
+ export { Grid, GridItem } from './Grid'
2
+ export type { GridProps, GridItemProps } from './Grid'
3
+ export { Stack } from './Stack'
4
+ export type { StackProps } from './Stack'
5
+ export { Section } from './Section'
6
+ export type { SectionProps } from './Section'
@@ -106,28 +106,37 @@ export function ContactSection({
106
106
  </div>
107
107
  ) : (
108
108
  <form onSubmit={handleSubmit} className="space-y-5">
109
+ <input
110
+ type="text"
111
+ name="company"
112
+ tabIndex={-1}
113
+ autoComplete="off"
114
+ aria-hidden="true"
115
+ className="hidden"
116
+ />
109
117
  <div className="grid gap-4 sm:grid-cols-2">
110
118
  <div className="space-y-1.5">
111
119
  <Label htmlFor="contact-first">First name</Label>
112
- <Input id="contact-first" placeholder="Olivia" required />
120
+ <Input id="contact-first" name="firstName" placeholder="Olivia" required />
113
121
  </div>
114
122
  <div className="space-y-1.5">
115
123
  <Label htmlFor="contact-last">Last name</Label>
116
- <Input id="contact-last" placeholder="Reed" required />
124
+ <Input id="contact-last" name="lastName" placeholder="Reed" required />
117
125
  </div>
118
126
  </div>
119
127
  <div className="space-y-1.5">
120
128
  <Label htmlFor="contact-email">Email</Label>
121
- <Input id="contact-email" type="email" placeholder="olivia@company.com" required />
129
+ <Input id="contact-email" name="email" type="email" placeholder="olivia@company.com" required />
122
130
  </div>
123
131
  <div className="space-y-1.5">
124
132
  <Label htmlFor="contact-subject">Subject</Label>
125
- <Input id="contact-subject" placeholder="How can we help?" required />
133
+ <Input id="contact-subject" name="subject" placeholder="How can we help?" required />
126
134
  </div>
127
135
  <div className="space-y-1.5">
128
136
  <Label htmlFor="contact-message">Message</Label>
129
137
  <Textarea
130
138
  id="contact-message"
139
+ name="message"
131
140
  placeholder="Tell us what you're working on..."
132
141
  className="min-h-28 resize-none"
133
142
  required
@@ -26,8 +26,8 @@ export function Footer({
26
26
  const copyrightText = legal ?? `\u00A9 ${new Date().getFullYear()} ${brand.name}. All rights reserved.`;
27
27
 
28
28
  return (
29
- <footer className="bg-gray-900">
30
- <div className="mx-auto max-w-7xl overflow-hidden px-6 py-20 sm:py-24 lg:px-8">
29
+ <footer className="overflow-hidden rounded-2xl border bg-foreground text-background">
30
+ <div className="mx-auto max-w-7xl px-6 py-20 sm:py-24 lg:px-8">
31
31
  {/* Brand */}
32
32
  <div className="flex justify-center">
33
33
  {renderLink({
@@ -36,11 +36,11 @@ export function Footer({
36
36
  children: (
37
37
  <>
38
38
  {brand.logo && (
39
- <span className="flex h-8 w-8 items-center justify-center rounded-lg bg-white/10 text-white">
39
+ <span className="flex h-8 w-8 items-center justify-center rounded-lg bg-background/10 text-background">
40
40
  {brand.logo}
41
41
  </span>
42
42
  )}
43
- <span className="text-lg font-semibold text-white">{brand.name}</span>
43
+ <span className="text-lg font-semibold text-background">{brand.name}</span>
44
44
  </>
45
45
  ),
46
46
  })}
@@ -53,7 +53,7 @@ export function Footer({
53
53
  <div key={label}>
54
54
  {renderLink({
55
55
  href,
56
- className: 'text-sm/6 text-gray-400 hover:text-white transition-colors',
56
+ className: 'text-sm/6 text-background/70 transition-colors hover:text-background',
57
57
  children: label,
58
58
  })}
59
59
  </div>
@@ -69,7 +69,7 @@ export function Footer({
69
69
  key={label}
70
70
  href={href}
71
71
  aria-label={label}
72
- className="text-gray-400 hover:text-gray-300 transition-colors"
72
+ className="text-background/70 transition-colors hover:text-background"
73
73
  >
74
74
  {icon}
75
75
  </a>
@@ -78,7 +78,7 @@ export function Footer({
78
78
  )}
79
79
 
80
80
  {/* Copyright */}
81
- <p className="mt-10 text-center text-sm/6 text-gray-500">
81
+ <p className="mt-10 text-center text-sm/6 text-background/50">
82
82
  {copyrightText}
83
83
  </p>
84
84
  </div>
@@ -40,7 +40,7 @@ export function Navbar({
40
40
  children: (
41
41
  <span className="flex items-center gap-2 font-semibold">
42
42
  {brand.logo && (
43
- <span className="flex h-7 w-7 items-center justify-center rounded-lg bg-primary text-primary-foreground">
43
+ <span className="flex h-9 w-9 items-center justify-center rounded-xl bg-primary text-primary-foreground">
44
44
  {brand.logo}
45
45
  </span>
46
46
  )}
@@ -74,6 +74,14 @@ export function NewsletterSection({
74
74
  </div>
75
75
  ) : (
76
76
  <form onSubmit={handleSubmit} className="mt-8 flex flex-col gap-3 sm:flex-row">
77
+ <input
78
+ type="text"
79
+ name="company"
80
+ tabIndex={-1}
81
+ autoComplete="off"
82
+ aria-hidden="true"
83
+ className="hidden"
84
+ />
77
85
  <Input
78
86
  type="email"
79
87
  placeholder={placeholder}
@@ -1,79 +1,31 @@
1
- declare module '@olwiba/docs' {
2
- import * as React from 'react';
3
-
4
- export const Theme: {
5
- Purple: string;
6
- [key: string]: string;
1
+ declare module '@olwiba/cn/email' {
2
+ export const emailTheme: {
3
+ pageBackground: string;
4
+ cardBackground: string;
5
+ cardBorder: string;
6
+ mutedBackground: string;
7
+ text: string;
8
+ mutedText: string;
9
+ link: string;
10
+ buttonText: string;
11
+ defaultBrandColor: string;
12
+ fontFamily: string;
7
13
  };
8
14
 
9
- export function createDocsRoot(config: Record<string, unknown>): unknown;
10
- export const DocsHeader: React.ComponentType<any>;
11
- export const DocsFooter: React.ComponentType<any>;
12
- export const DocsLayout: React.ComponentType<any>;
13
- export const DocsCopyPage: React.ComponentType<any>;
14
- export const DocsMobileNav: React.ComponentType<any>;
15
- export const DocsToc: React.ComponentType<any>;
16
- export const CopyCommandButton: React.ComponentType<any>;
17
- export const CopyButton: React.ComponentType<any>;
18
- export const mdxComponents: Record<string, React.ComponentType<any>>;
19
- export function extractTextFromReactNode(node: React.ReactNode): string;
20
- export function cn(...inputs: any[]): string;
21
- export const Sandbox: React.ComponentType<any>;
22
- export const CodeFence: React.ComponentType<any>;
23
-
24
- export interface SandboxDefinition {
25
- id: string;
26
- defaultViewport?: 'desktop' | 'tablet' | 'mobile' | 'custom';
27
- files: Array<{ path: string; language: string; code: string }>;
28
- preview: React.LazyExoticComponent<React.FC>;
29
- }
30
-
31
- export type SandboxRegistryInput =
32
- | SandboxDefinition[]
33
- | Record<string, SandboxDefinition>;
34
-
35
- export function registerSandboxes(input: SandboxRegistryInput): void;
36
- export function getSandboxDefinition(id: string): SandboxDefinition | undefined;
37
-
38
- export interface UIModeOption {
39
- value: string;
40
- label: string;
41
- }
42
- export interface UIModeDropdownProps {
43
- modes: UIModeOption[];
44
- }
45
- export const UIModeDropdown: React.ComponentType<UIModeDropdownProps>;
46
- export function getUIMode(): string;
47
- export function setUIMode(mode: string): void;
48
- export function subscribeUIMode(fn: (mode: string) => void): () => void;
49
-
50
- export interface SidebarSection {
51
- name: string;
52
- href: string;
53
- }
54
-
55
- export interface TocItem {
56
- title: string;
57
- url: string;
58
- depth: number;
59
- }
60
-
61
- export interface PageLoaderData {
62
- path: string;
63
- url: string;
64
- pageTree: unknown;
65
- frontmatter: { title?: string; description?: string };
66
- toc: TocItem[];
67
- rawContent: string;
68
- neighbours: {
69
- previous: { url: string; name: string } | null;
70
- next: { url: string; name: string } | null;
71
- };
72
- }
73
- }
74
-
75
- declare module '@olwiba/docs/server' {
76
- export function createServer(): unknown;
15
+ export type EmailTheme = typeof emailTheme;
16
+
17
+ export function EmailRoot(props: { children?: React.ReactNode }): JSX.Element;
18
+ export function EmailHead(props: { children?: React.ReactNode }): JSX.Element;
19
+ export function EmailBody(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
20
+ export function EmailPreview(props: { children?: string }): JSX.Element;
21
+ export function EmailContainer(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
22
+ export function EmailSection(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
23
+ export function EmailText(props: {
24
+ children?: React.ReactNode;
25
+ variant?: 'default' | 'muted' | 'caption';
26
+ style?: React.CSSProperties;
27
+ }): JSX.Element;
28
+ export function EmailHeading(props: { children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
29
+ export function EmailLink(props: { href: string; children?: React.ReactNode; style?: React.CSSProperties }): JSX.Element;
30
+ export function EmailButton(props: { href: string; label: string; brandColor?: string }): JSX.Element;
77
31
  }
78
-
79
-