@ctrl-ui/react 0.8.4 → 0.8.6

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 (134) hide show
  1. package/dist/audio-visualizer.js +1 -1
  2. package/dist/chat-composer-editor/extensions/mention.js +4 -0
  3. package/dist/chat-layout.d.ts +5 -0
  4. package/dist/chat-layout.js +61 -20
  5. package/dist/chat-message.d.ts +5 -0
  6. package/dist/chat-message.js +19 -2
  7. package/dist/context.js +0 -2
  8. package/dist/email/email-brand.d.ts +60 -0
  9. package/dist/email/email-brand.js +101 -0
  10. package/dist/email/email-code.d.ts +18 -0
  11. package/dist/email/email-code.js +172 -0
  12. package/dist/email/email-footer.d.ts +63 -0
  13. package/dist/email/email-footer.js +98 -0
  14. package/dist/email/email.d.ts +60 -11
  15. package/dist/email/email.js +155 -24
  16. package/dist/email/templates.d.ts +54 -9
  17. package/dist/email/templates.js +314 -116
  18. package/dist/email/theme.d.ts +13 -5
  19. package/dist/email/theme.js +30 -8
  20. package/dist/hooks/use-chat-message.d.ts +1 -0
  21. package/dist/hooks/use-chat-message.js +1 -0
  22. package/dist/hooks/use-chat-thread-scroll.d.ts +8 -0
  23. package/dist/hooks/use-chat-thread-scroll.js +66 -0
  24. package/dist/hooks/use-user-ask.d.ts +6 -4
  25. package/dist/hooks/use-user-ask.js +56 -17
  26. package/dist/inline-attachment.js +1 -1
  27. package/dist/knob-contracts/action-bar-knobs.d.ts +1 -1
  28. package/dist/knob-contracts/action-bar-knobs.js +1 -1
  29. package/dist/knob-contracts/activity-knobs.d.ts +1 -1
  30. package/dist/knob-contracts/activity-knobs.js +2 -1
  31. package/dist/knob-contracts/audio-visualizer-knobs.d.ts +1 -1
  32. package/dist/knob-contracts/audio-visualizer-knobs.js +1 -0
  33. package/dist/knob-contracts/chat-composer-attachment-knobs.d.ts +1 -1
  34. package/dist/knob-contracts/chat-composer-attachment-knobs.js +2 -0
  35. package/dist/knob-contracts/chat-composer-knobs.d.ts +1 -1
  36. package/dist/knob-contracts/chat-composer-knobs.js +1 -0
  37. package/dist/knob-contracts/chat-layout-knobs.d.ts +1 -1
  38. package/dist/knob-contracts/chat-layout-knobs.js +2 -1
  39. package/dist/knob-contracts/chat-message-knobs.d.ts +1 -1
  40. package/dist/knob-contracts/chat-message-knobs.js +3 -1
  41. package/dist/knob-contracts/context-knobs.d.ts +1 -1
  42. package/dist/knob-contracts/context-knobs.js +3 -0
  43. package/dist/knob-contracts/inline-attachment-knobs.d.ts +1 -1
  44. package/dist/knob-contracts/inline-attachment-knobs.js +4 -0
  45. package/dist/knob-contracts/inline-citation-knobs.d.ts +1 -1
  46. package/dist/knob-contracts/inline-citation-knobs.js +3 -1
  47. package/dist/knob-contracts/page-layout-knobs.d.ts +4 -0
  48. package/dist/knob-contracts/page-layout-knobs.js +16 -0
  49. package/dist/knob-contracts/table-of-contents-knobs.d.ts +1 -1
  50. package/dist/knob-contracts/table-of-contents-knobs.js +3 -3
  51. package/dist/knob-contracts/task-list-knobs.d.ts +1 -1
  52. package/dist/knob-contracts/task-list-knobs.js +4 -0
  53. package/dist/knob-contracts/user-ask-knobs.d.ts +1 -1
  54. package/dist/knob-contracts/user-ask-knobs.js +4 -0
  55. package/dist/lib/phone-input-format.js +1 -1
  56. package/dist/markdown-block.js +1 -1
  57. package/dist/styles/index.css +2 -1
  58. package/dist/styles/recipes/action-bar.css +37 -5
  59. package/dist/styles/recipes/activity.css +36 -3
  60. package/dist/styles/recipes/alert.css +2 -0
  61. package/dist/styles/recipes/audio-visualizer.css +8 -1
  62. package/dist/styles/recipes/button-group.css +8 -0
  63. package/dist/styles/recipes/button.css +15 -0
  64. package/dist/styles/recipes/calendar.css +21 -0
  65. package/dist/styles/recipes/card.css +2 -0
  66. package/dist/styles/recipes/chat-composer-attachment.css +33 -2
  67. package/dist/styles/recipes/chat-composer.css +16 -2
  68. package/dist/styles/recipes/chat-layout.css +25 -1
  69. package/dist/styles/recipes/chat-message.css +69 -2
  70. package/dist/styles/recipes/choice.css +12 -0
  71. package/dist/styles/recipes/code-diff.css +1 -0
  72. package/dist/styles/recipes/code.css +25 -0
  73. package/dist/styles/recipes/context.css +30 -18
  74. package/dist/styles/recipes/dynamic-notification-input.css +6 -0
  75. package/dist/styles/recipes/dynamic-notification.css +1 -0
  76. package/dist/styles/recipes/environment-variables.css +1 -0
  77. package/dist/styles/recipes/field-parts.css +2 -0
  78. package/dist/styles/recipes/field.css +6 -0
  79. package/dist/styles/recipes/gradient-editor.css +17 -0
  80. package/dist/styles/recipes/inline-attachment.css +57 -14
  81. package/dist/styles/recipes/inline-citation.css +44 -6
  82. package/dist/styles/recipes/item.css +3 -1
  83. package/dist/styles/recipes/markdown-block.css +1 -0
  84. package/dist/styles/recipes/markdown.css +7 -0
  85. package/dist/styles/recipes/page-layout.css +219 -0
  86. package/dist/styles/recipes/pagination.css +16 -0
  87. package/dist/styles/recipes/popup-drawer.css +3 -1
  88. package/dist/styles/recipes/popup-toast.css +2 -0
  89. package/dist/styles/recipes/popup.css +8 -12
  90. package/dist/styles/recipes/range.css +24 -2
  91. package/dist/styles/recipes/rich-tooltip.css +1 -0
  92. package/dist/styles/recipes/source-badge.css +20 -0
  93. package/dist/styles/recipes/table-of-contents.css +10 -10
  94. package/dist/styles/recipes/tabs.css +16 -0
  95. package/dist/styles/recipes/task-list.css +61 -8
  96. package/dist/styles/recipes/thread-rail.css +19 -13
  97. package/dist/styles/recipes/toolbar.css +21 -0
  98. package/dist/styles/recipes/transcript-divider.css +1 -0
  99. package/dist/styles/recipes/user-ask.css +59 -16
  100. package/dist/styles/theme.css +34 -0
  101. package/dist/thread-rail.js +1 -1
  102. package/dist/ui/alert-dialog.js +2 -2
  103. package/dist/ui/autocomplete.js +1 -1
  104. package/dist/ui/color-picker.js +3 -3
  105. package/dist/ui/combobox.js +1 -1
  106. package/dist/ui/command.d.ts +5 -3
  107. package/dist/ui/command.js +27 -3
  108. package/dist/ui/context-menu.js +2 -2
  109. package/dist/ui/dialog.js +2 -2
  110. package/dist/ui/drawer.js +2 -2
  111. package/dist/ui/dropdown-menu.js +1 -1
  112. package/dist/ui/dropzone.js +4 -1
  113. package/dist/ui/gradient-editor.js +2 -2
  114. package/dist/ui/hover-card.js +1 -1
  115. package/dist/ui/infinite-canvas.js +1 -0
  116. package/dist/ui/menubar.js +2 -2
  117. package/dist/ui/navigation-menu.js +1 -1
  118. package/dist/ui/number-field.js +1 -1
  119. package/dist/ui/page-layout.d.ts +44 -0
  120. package/dist/ui/page-layout.js +108 -0
  121. package/dist/ui/phone-input.js +4 -4
  122. package/dist/ui/popover.js +1 -1
  123. package/dist/ui/resizable.js +1 -1
  124. package/dist/ui/rich-tooltip.js +1 -1
  125. package/dist/ui/select.js +1 -1
  126. package/dist/ui/sheet.js +2 -2
  127. package/dist/ui/sidebar-resize-rail.js +1 -1
  128. package/dist/ui/slider.js +1 -1
  129. package/dist/ui/toast.js +2 -2
  130. package/dist/ui/tooltip.js +1 -1
  131. package/dist/ui/trigger-menu.js +1 -1
  132. package/dist/user-ask.d.ts +5 -3
  133. package/dist/user-ask.js +38 -13
  134. package/package.json +3 -2
@@ -0,0 +1,98 @@
1
+ import { EmailCaption, EmailDivider, EmailMutedLink } from "./email.js";
2
+ import { Fragment } from "react";
3
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
+ import { Img, Section } from "react-email";
5
+ //#region src/email/email-footer.tsx
6
+ const emailSocialPlatformNames = {
7
+ x: "X",
8
+ bluesky: "Bluesky",
9
+ threads: "Threads",
10
+ instagram: "Instagram",
11
+ facebook: "Facebook",
12
+ linkedin: "LinkedIn",
13
+ youtube: "YouTube",
14
+ tiktok: "TikTok",
15
+ github: "GitHub",
16
+ discord: "Discord",
17
+ slack: "Slack",
18
+ mastodon: "Mastodon"
19
+ };
20
+ function separatedLinks(links) {
21
+ return links.map((link, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 ? " · " : null, /* @__PURE__ */ jsx(EmailMutedLink, {
22
+ href: link.href,
23
+ children: link.label
24
+ })] }, link.href));
25
+ }
26
+ function EmailFooter({ children, align = "start", placement = "inside" }) {
27
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [placement === "inside" ? /* @__PURE__ */ jsx(EmailDivider, {}) : null, /* @__PURE__ */ jsx(Section, {
28
+ className: `${placement === "inside" ? "" : "pt-6"} ${align === "center" ? "text-center" : "text-left"}`,
29
+ children
30
+ })] });
31
+ }
32
+ function EmailFooterLegal({ children, className = "" }) {
33
+ return /* @__PURE__ */ jsx(Section, {
34
+ className: `mt-6 ${className}`,
35
+ children
36
+ });
37
+ }
38
+ function resolveSocialLink(link, iconBaseUrl) {
39
+ const label = link.platform ? link.label ?? emailSocialPlatformNames[link.platform] : link.label;
40
+ const base = iconBaseUrl?.replace(/\/$/, "");
41
+ return {
42
+ label,
43
+ iconUrl: link.iconUrl ?? (link.platform && base ? `${base}/${link.platform}.png` : void 0),
44
+ alt: link.iconAlt ?? label
45
+ };
46
+ }
47
+ function EmailSocialLinks({ links, iconBaseUrl, iconSize = 24 }) {
48
+ if (links.length === 0) return null;
49
+ return /* @__PURE__ */ jsx(Section, {
50
+ className: "mb-4",
51
+ children: links.map((link, index) => {
52
+ const { label, iconUrl, alt } = resolveSocialLink(link, iconBaseUrl);
53
+ const spacing = index < links.length - 1 ? "mr-3" : "";
54
+ return /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 ? " " : null, /* @__PURE__ */ jsx(EmailMutedLink, {
55
+ href: link.href,
56
+ className: `${iconUrl ? "no-underline" : "underline"} ${spacing}`,
57
+ children: iconUrl ? /* @__PURE__ */ jsx(Img, {
58
+ src: iconUrl,
59
+ alt,
60
+ width: iconSize,
61
+ height: iconSize,
62
+ className: "inline-block align-middle"
63
+ }) : label
64
+ })] }, link.href);
65
+ })
66
+ });
67
+ }
68
+ function EmailFooterLinks({ links }) {
69
+ if (links.length === 0) return null;
70
+ return /* @__PURE__ */ jsx(EmailCaption, {
71
+ className: "mb-2",
72
+ children: separatedLinks(links)
73
+ });
74
+ }
75
+ function EmailAddress({ company, lines }) {
76
+ return /* @__PURE__ */ jsxs(EmailCaption, {
77
+ className: "mb-2",
78
+ children: [/* @__PURE__ */ jsx("strong", {
79
+ className: "font-semibold",
80
+ children: company
81
+ }), lines.map((line) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), line] }, line))]
82
+ });
83
+ }
84
+ function EmailUnsubscribe({ unsubscribeUrl, preferencesUrl, unsubscribeLabel = "Unsubscribe", preferencesLabel = "Manage preferences" }) {
85
+ const unsubscribe = {
86
+ label: unsubscribeLabel,
87
+ href: unsubscribeUrl
88
+ };
89
+ return /* @__PURE__ */ jsx(EmailCaption, {
90
+ className: "mb-2",
91
+ children: separatedLinks(preferencesUrl ? [unsubscribe, {
92
+ label: preferencesLabel,
93
+ href: preferencesUrl
94
+ }] : [unsubscribe])
95
+ });
96
+ }
97
+ //#endregion
98
+ export { EmailAddress, EmailFooter, EmailFooterLegal, EmailFooterLinks, EmailSocialLinks, EmailUnsubscribe, emailSocialPlatformNames };
@@ -1,27 +1,76 @@
1
1
  import { EmailTheme } from "./theme.js";
2
2
  import { ReactNode } from "react";
3
- import { ButtonProps, HeadingProps, LinkProps, TextProps } from "react-email";
3
+ import { ButtonProps, HeadingProps, HrProps, LinkProps, SectionProps, TextProps } from "react-email";
4
4
  //#region src/email/email.d.ts
5
- export declare function EmailLayout({ theme, preview, children, head, lang, dir }: {
5
+ export type EmailVariant = "contained" | "plain";
6
+ export type EmailFooterPlacement = "inside" | "outside";
7
+ export declare function surfaceColors(theme: EmailTheme, variant: EmailVariant): Record<"background" | "border" | "card" | "card-foreground" | "foreground" | "muted" | "muted-foreground" | "primary" | "primary-foreground" | "primary-text", string>;
8
+ export declare function EmailLayout({ theme, preview, children, footer, footerPlacement, head, lang, dir, variant }: {
6
9
  theme: EmailTheme;
7
10
  preview: string;
8
11
  children: ReactNode;
12
+ footer?: ReactNode;
13
+ footerPlacement?: EmailFooterPlacement;
9
14
  head?: ReactNode;
10
15
  lang?: string;
11
16
  dir?: "ltr" | "rtl";
17
+ variant?: EmailVariant;
12
18
  }): import("react").JSX.Element;
13
- declare const headingClasses: {
14
- h1: string;
15
- h2: string;
16
- h3: string;
17
- h4: string;
19
+ export type EmailAlign = "left" | "center" | "right";
20
+ declare const headingSizeClasses: {
21
+ display: string;
22
+ "heading-1": string;
23
+ "heading-2": string;
24
+ "heading-3": string;
25
+ "heading-4": string;
18
26
  };
19
- export declare function EmailHeading({ as, className, ...props }: Omit<HeadingProps, "as"> & {
20
- as?: keyof typeof headingClasses;
27
+ type EmailHeadingSize = keyof typeof headingSizeClasses;
28
+ declare const headingSizeForTag: {
29
+ readonly h1: "heading-1";
30
+ readonly h2: "heading-2";
31
+ readonly h3: "heading-3";
32
+ readonly h4: "heading-4";
33
+ };
34
+ export declare function EmailHeading({ as, size, align, className, ...props }: Omit<HeadingProps, "as"> & {
35
+ as?: keyof typeof headingSizeForTag;
36
+ size?: EmailHeadingSize;
37
+ align?: EmailAlign;
38
+ }): import("react").JSX.Element;
39
+ export declare function EmailSection({ align, className, ...props }: SectionProps & {
40
+ align?: EmailAlign;
21
41
  }): import("react").JSX.Element;
22
- export declare function EmailText({ tone, className, style, ...props }: TextProps & {
42
+ export declare function EmailText({ tone, align, className, style, ...props }: TextProps & {
23
43
  tone?: "default" | "muted";
44
+ align?: EmailAlign;
45
+ }): import("react").JSX.Element;
46
+ export declare function EmailButton({ width, className, ...props }: ButtonProps & {
47
+ width?: "auto" | "full";
24
48
  }): import("react").JSX.Element;
25
- export declare function EmailButton({ className, ...props }: ButtonProps): import("react").JSX.Element;
26
49
  export declare function EmailLink({ className, ...props }: LinkProps): import("react").JSX.Element;
50
+ export declare function EmailCaption({ className, ...props }: TextProps & {
51
+ align?: EmailAlign;
52
+ }): import("react").JSX.Element;
53
+ export declare function EmailMutedLink({ className, ...props }: LinkProps): import("react").JSX.Element;
54
+ export declare function EmailDivider({ className, ...props }: HrProps): import("react").JSX.Element;
55
+ export declare function EmailPanel({ className, ...props }: SectionProps): import("react").JSX.Element;
56
+ export declare function EmailOneTimeCode({ children, className }: {
57
+ children: ReactNode;
58
+ className?: string;
59
+ }): import("react").JSX.Element;
60
+ export declare function EmailBulletList({ items, className }: {
61
+ items: ReactNode[];
62
+ className?: string;
63
+ }): import("react").JSX.Element | null;
64
+ export declare function EmailColumns({ children, widths, gap, verticalAlign, className }: {
65
+ children: ReactNode[];
66
+ widths?: string[];
67
+ gap?: number;
68
+ verticalAlign?: "top" | "middle" | "bottom";
69
+ className?: string;
70
+ }): import("react").JSX.Element | null;
71
+ export declare function EmailDetailRow({ label, value, emphasis }: {
72
+ label: ReactNode;
73
+ value: ReactNode;
74
+ emphasis?: boolean;
75
+ }): import("react").JSX.Element;
27
76
  //#endregion
@@ -1,11 +1,19 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { Body, Button, Container, Head, Heading, Html, Link, Preview, Tailwind, Text, pixelBasedPreset } from "react-email";
2
+ import { Body, Button, Column, Container, Head, Heading, Hr, Html, Link, Preview, Row, Section, Tailwind, Text, pixelBasedPreset } from "react-email";
3
3
  //#region src/email/email.tsx
4
- function tailwindTheme(theme) {
4
+ function surfaceColors(theme, variant) {
5
+ if (variant === "contained") return theme.colors;
6
+ return {
7
+ ...theme.colors,
8
+ card: theme.colors.background,
9
+ "card-foreground": theme.colors.foreground
10
+ };
11
+ }
12
+ function tailwindTheme(theme, variant) {
5
13
  return {
6
14
  presets: [pixelBasedPreset],
7
15
  theme: { extend: {
8
- colors: theme.colors,
16
+ colors: surfaceColors(theme, variant),
9
17
  borderRadius: theme.radii,
10
18
  minHeight: { control: theme.button.height },
11
19
  padding: {
@@ -14,7 +22,8 @@ function tailwindTheme(theme) {
14
22
  },
15
23
  fontFamily: {
16
24
  body: theme.fonts.body,
17
- display: theme.fonts.display
25
+ display: theme.fonts.display,
26
+ mono: theme.fonts.mono
18
27
  },
19
28
  fontSize: {
20
29
  ...Object.fromEntries(Object.entries(theme.text).map(([name, { fontSize, ...options }]) => [name, [fontSize, options]])),
@@ -23,36 +32,78 @@ function tailwindTheme(theme) {
23
32
  } }
24
33
  };
25
34
  }
26
- function EmailLayout({ theme, preview, children, head, lang = "en", dir = "ltr" }) {
35
+ function EmailLayout({ theme, preview, children, footer, footerPlacement = "inside", head, lang = "en", dir = "ltr", variant = "contained" }) {
36
+ const contained = variant === "contained";
37
+ const outside = contained && footerPlacement === "outside";
38
+ const backdrop = theme.colorScheme === "light" ? "bg-muted" : "bg-background";
27
39
  return /* @__PURE__ */ jsx(Html, {
28
40
  lang,
29
41
  dir,
30
42
  children: /* @__PURE__ */ jsxs(Tailwind, {
31
- config: tailwindTheme(theme),
32
- children: [/* @__PURE__ */ jsx(Head, { children: head }), /* @__PURE__ */ jsxs(Body, {
33
- className: "m-0 bg-background p-4 font-body text-body text-foreground",
34
- children: [/* @__PURE__ */ jsx(Preview, { children: preview }), /* @__PURE__ */ jsx(Container, {
35
- className: "mx-auto w-full max-w-[600px] rounded-panel bg-card p-6 text-card-foreground",
36
- children
37
- })]
43
+ config: tailwindTheme(theme, variant),
44
+ children: [/* @__PURE__ */ jsxs(Head, { children: [
45
+ /* @__PURE__ */ jsx("meta", {
46
+ name: "color-scheme",
47
+ content: theme.colorScheme
48
+ }),
49
+ /* @__PURE__ */ jsx("meta", {
50
+ name: "supported-color-schemes",
51
+ content: theme.colorScheme
52
+ }),
53
+ head
54
+ ] }), /* @__PURE__ */ jsxs(Body, {
55
+ className: `m-0 font-body text-body text-foreground ${contained ? `${backdrop} px-4 py-8` : "bg-background p-0"}`,
56
+ children: [
57
+ /* @__PURE__ */ jsx(Preview, { children: preview }),
58
+ /* @__PURE__ */ jsxs(Container, {
59
+ className: `mx-auto w-full max-w-[600px] bg-card text-card-foreground ${contained ? "rounded-panel border border-border border-solid p-6" : "px-6 py-8"}`,
60
+ children: [children, outside ? null : footer]
61
+ }),
62
+ outside ? /* @__PURE__ */ jsx(Container, {
63
+ className: "mx-auto w-full max-w-[600px] px-6",
64
+ children: footer
65
+ }) : null
66
+ ]
38
67
  })]
39
68
  })
40
69
  });
41
70
  }
42
- const headingClasses = {
43
- h1: "text-heading-1",
44
- h2: "text-heading-2",
45
- h3: "text-heading-3",
46
- h4: "text-heading-4"
71
+ const alignClasses = {
72
+ left: "text-left",
73
+ center: "text-center",
74
+ right: "text-right"
75
+ };
76
+ function alignClass(align) {
77
+ return align ? alignClasses[align] : "";
78
+ }
79
+ const headingSizeClasses = {
80
+ display: "text-display",
81
+ "heading-1": "text-heading-1",
82
+ "heading-2": "text-heading-2",
83
+ "heading-3": "text-heading-3",
84
+ "heading-4": "text-heading-4"
85
+ };
86
+ const headingSizeForTag = {
87
+ h1: "heading-1",
88
+ h2: "heading-2",
89
+ h3: "heading-3",
90
+ h4: "heading-4"
47
91
  };
48
- function EmailHeading({ as = "h1", className = "", ...props }) {
92
+ function EmailHeading({ as = "h1", size, align, className = "", ...props }) {
93
+ const sizeClass = headingSizeClasses[size ?? headingSizeForTag[as]];
49
94
  return /* @__PURE__ */ jsx(Heading, {
50
95
  ...props,
51
96
  as,
52
- className: `mb-4 mt-0 font-display text-card-foreground ${headingClasses[as]} ${className}`
97
+ className: `mb-4 mt-0 font-display text-card-foreground ${sizeClass} ${alignClass(align)} ${className}`
98
+ });
99
+ }
100
+ function EmailSection({ align, className = "", ...props }) {
101
+ return /* @__PURE__ */ jsx(Section, {
102
+ ...props,
103
+ className: `${alignClass(align)} ${className}`
53
104
  });
54
105
  }
55
- function EmailText({ tone = "default", className = "", style, ...props }) {
106
+ function EmailText({ tone = "default", align, className = "", style, ...props }) {
56
107
  const textColor = tone === "muted" ? "text-muted-foreground" : "text-card-foreground";
57
108
  return /* @__PURE__ */ jsx(Text, {
58
109
  ...props,
@@ -60,13 +111,14 @@ function EmailText({ tone = "default", className = "", style, ...props }) {
60
111
  overflowWrap: "break-word",
61
112
  ...style
62
113
  },
63
- className: `mb-4 mt-0 font-body text-body ${textColor} ${className}`
114
+ className: `mb-4 mt-0 font-body text-body ${textColor} ${alignClass(align)} ${className}`
64
115
  });
65
116
  }
66
- function EmailButton({ className = "", ...props }) {
117
+ function EmailButton({ width = "auto", className = "", ...props }) {
118
+ const widthClass = width === "full" ? "block w-full" : "inline-block";
67
119
  return /* @__PURE__ */ jsx(Button, {
68
120
  ...props,
69
- className: `box-border min-h-control rounded-control bg-primary px-control-x py-control-y text-center font-body text-control font-medium text-primary-foreground no-underline ${className}`
121
+ className: `box-border min-h-control rounded-control bg-primary px-control-x py-control-y text-center font-body text-control font-medium text-primary-foreground no-underline ${widthClass} ${className}`
70
122
  });
71
123
  }
72
124
  function EmailLink({ className = "", ...props }) {
@@ -75,5 +127,84 @@ function EmailLink({ className = "", ...props }) {
75
127
  className: `font-body text-primary-text underline ${className}`
76
128
  });
77
129
  }
130
+ function EmailCaption({ className = "", ...props }) {
131
+ return /* @__PURE__ */ jsx(EmailText, {
132
+ tone: "muted",
133
+ ...props,
134
+ className: `text-caption ${className}`
135
+ });
136
+ }
137
+ function EmailMutedLink({ className = "", ...props }) {
138
+ return /* @__PURE__ */ jsx(EmailLink, {
139
+ ...props,
140
+ className: `text-caption text-muted-foreground ${className}`
141
+ });
142
+ }
143
+ function EmailDivider({ className = "", ...props }) {
144
+ return /* @__PURE__ */ jsx(Hr, {
145
+ ...props,
146
+ className: `my-6 border-0 border-t border-solid border-t-border ${className}`
147
+ });
148
+ }
149
+ function EmailPanel({ className = "", ...props }) {
150
+ return /* @__PURE__ */ jsx(Section, {
151
+ ...props,
152
+ className: `my-6 rounded-panel bg-muted p-5 ${className}`
153
+ });
154
+ }
155
+ function EmailOneTimeCode({ children, className = "" }) {
156
+ return /* @__PURE__ */ jsx(EmailPanel, {
157
+ className: `text-center ${className}`,
158
+ children: /* @__PURE__ */ jsx(EmailText, {
159
+ className: "mb-0 text-center font-mono text-heading-2 font-semibold tracking-[0.25em]",
160
+ children
161
+ })
162
+ });
163
+ }
164
+ function EmailBulletList({ items, className = "" }) {
165
+ if (items.length === 0) return null;
166
+ return /* @__PURE__ */ jsx("ul", {
167
+ className: `mb-4 mt-0 list-disc pl-5 font-body text-body text-card-foreground ${className}`,
168
+ children: items.map((item, index) => /* @__PURE__ */ jsx("li", {
169
+ className: "mb-1 font-body text-body text-card-foreground",
170
+ children: item
171
+ }, index))
172
+ });
173
+ }
174
+ function EmailColumns({ children, widths, gap = 20, verticalAlign = "top", className = "" }) {
175
+ if (children.length === 0) return null;
176
+ const evenWidth = `${(100 / children.length).toFixed(4)}%`;
177
+ return /* @__PURE__ */ jsx(Row, {
178
+ className: `mb-6 table-fixed ${className}`,
179
+ children: children.map((child, index) => /* @__PURE__ */ jsx(Column, {
180
+ width: widths?.[index] ?? evenWidth,
181
+ className: `max-[480px]:block max-[480px]:w-full max-[480px]:pl-0 ${index === 0 ? "" : `max-[480px]:pt-[${gap}px]`}`,
182
+ style: {
183
+ verticalAlign,
184
+ paddingLeft: index === 0 ? 0 : gap
185
+ },
186
+ children: child
187
+ }, index))
188
+ });
189
+ }
190
+ function EmailDetailRow({ label, value, emphasis = false }) {
191
+ return /* @__PURE__ */ jsxs(Row, {
192
+ className: "table-fixed",
193
+ children: [/* @__PURE__ */ jsx(Column, {
194
+ className: "align-top",
195
+ children: /* @__PURE__ */ jsx(EmailText, {
196
+ className: "mb-2",
197
+ children: label
198
+ })
199
+ }), /* @__PURE__ */ jsx(Column, {
200
+ align: "right",
201
+ className: "align-top",
202
+ children: /* @__PURE__ */ jsx(EmailText, {
203
+ className: `mb-2 ${emphasis ? "font-semibold" : ""}`,
204
+ children: value
205
+ })
206
+ })]
207
+ });
208
+ }
78
209
  //#endregion
79
- export { EmailButton, EmailHeading, EmailLayout, EmailLink, EmailText };
210
+ export { EmailBulletList, EmailButton, EmailCaption, EmailColumns, EmailDetailRow, EmailDivider, EmailHeading, EmailLayout, EmailLink, EmailMutedLink, EmailOneTimeCode, EmailPanel, EmailSection, EmailText, surfaceColors };
@@ -1,23 +1,37 @@
1
1
  import { EmailTheme } from "./theme.js";
2
+ import { EmailVariant } from "./email.js";
3
+ import { EmailBrand, EmailFooterContent } from "./email-brand.js";
4
+ import { ReactNode } from "react";
5
+ import { PrismLanguage } from "react-email";
2
6
  //#region src/email/templates.d.ts
3
- type EmailBrandProps = {
7
+ type EmailMessageProps = {
4
8
  theme: EmailTheme;
5
- brand: string;
6
- footer: string;
9
+ brand: EmailBrand;
10
+ footer: EmailFooterContent;
11
+ variant?: EmailVariant;
12
+ head?: ReactNode;
7
13
  };
8
- export declare function InvitationEmail({ theme, brand, footer, inviter, workspace, inviteUrl }: EmailBrandProps & {
14
+ type EmailBrandProps = EmailMessageProps & {
15
+ browserUrl?: string;
16
+ };
17
+ export type EmailHighlight = {
18
+ title: string;
19
+ description: string;
20
+ };
21
+ export declare function InvitationEmail({ theme, variant, head, brand, browserUrl, footer, inviter, workspace, inviteUrl }: EmailBrandProps & {
9
22
  inviter: string;
10
23
  workspace: string;
11
24
  inviteUrl: string;
12
25
  }): import("react").JSX.Element;
13
- export declare function ProductEmail({ theme, brand, footer, title, description, imageUrl, imageAlt, actionUrl }: EmailBrandProps & {
26
+ export declare function ProductEmail({ theme, variant, head, brand, browserUrl, footer, title, description, imageUrl, imageAlt, highlights, actionUrl }: EmailBrandProps & {
14
27
  title: string;
15
28
  description: string;
16
29
  imageUrl: string;
17
30
  imageAlt: string;
31
+ highlights?: EmailHighlight[];
18
32
  actionUrl: string;
19
33
  }): import("react").JSX.Element;
20
- export declare function EditorialEmail({ theme, brand, footer, title, description, imageUrl, imageAlt, articleUrl }: EmailBrandProps & {
34
+ export declare function EditorialEmail({ theme, variant, head, brand, browserUrl, footer, title, description, imageUrl, imageAlt, articleUrl }: EmailBrandProps & {
21
35
  title: string;
22
36
  description: string;
23
37
  imageUrl: string;
@@ -31,11 +45,10 @@ export type EmailArticle = {
31
45
  imageUrl: string;
32
46
  imageAlt: string;
33
47
  };
34
- export declare function NewsletterEmail({ theme, brand, footer, articles, unsubscribeUrl }: EmailBrandProps & {
48
+ export declare function NewsletterEmail({ theme, variant, head, brand, browserUrl, footer, articles }: EmailBrandProps & {
35
49
  articles: EmailArticle[];
36
- unsubscribeUrl: string;
37
50
  }): import("react").JSX.Element;
38
- export declare function SummaryEmail({ theme, brand, footer, period, metrics, details, dashboardUrl }: EmailBrandProps & {
51
+ export declare function SummaryEmail({ theme, variant, head, brand, browserUrl, footer, period, metrics, details, dashboardUrl }: EmailBrandProps & {
39
52
  period: string;
40
53
  metrics: {
41
54
  label: string;
@@ -47,4 +60,36 @@ export declare function SummaryEmail({ theme, brand, footer, period, metrics, de
47
60
  }[];
48
61
  dashboardUrl: string;
49
62
  }): import("react").JSX.Element;
63
+ export declare function VerificationEmail({ theme, variant, head, brand, footer, code, expiresInMinutes, supportUrl }: EmailMessageProps & {
64
+ code: string;
65
+ expiresInMinutes: number;
66
+ supportUrl: string;
67
+ }): import("react").JSX.Element;
68
+ export type EmailReceiptLine = {
69
+ label: string;
70
+ value: string;
71
+ };
72
+ export declare function ReceiptEmail({ theme, variant, head, brand, footer, orderNumber, orderDate, lines, total, paymentMethod, invoiceUrl }: EmailMessageProps & {
73
+ orderNumber: string;
74
+ orderDate: string;
75
+ lines: EmailReceiptLine[];
76
+ total: string;
77
+ paymentMethod: string;
78
+ invoiceUrl: string;
79
+ }): import("react").JSX.Element;
80
+ export type EmailReleaseSection = {
81
+ title: string;
82
+ changes: string[];
83
+ };
84
+ export declare function ReleaseNotesEmail({ theme, variant, head, brand, browserUrl, footer, version, summary, sections, migration, changelogUrl }: EmailBrandProps & {
85
+ version: string;
86
+ summary: string;
87
+ sections: EmailReleaseSection[];
88
+ migration?: {
89
+ notes: string;
90
+ language: PrismLanguage;
91
+ code: string;
92
+ };
93
+ changelogUrl: string;
94
+ }): import("react").JSX.Element;
50
95
  //#endregion