@medalsocial/meda 2.0.0 → 2.2.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.
Files changed (237) hide show
  1. package/dist/calendar/calendar-toolbar.d.ts +2 -0
  2. package/dist/calendar/calendar-toolbar.js +22 -0
  3. package/dist/calendar/calendar.d.ts +2 -0
  4. package/dist/calendar/calendar.js +55 -0
  5. package/dist/calendar/day-view.d.ts +2 -0
  6. package/dist/calendar/day-view.js +40 -0
  7. package/dist/calendar/index.d.ts +6 -0
  8. package/dist/calendar/index.js +7 -0
  9. package/dist/calendar/internal/date.d.ts +26 -0
  10. package/dist/calendar/internal/date.js +107 -0
  11. package/dist/calendar/internal/day-cell.d.ts +15 -0
  12. package/dist/calendar/internal/day-cell.js +38 -0
  13. package/dist/calendar/internal/event-pill.d.ts +13 -0
  14. package/dist/calendar/internal/event-pill.js +30 -0
  15. package/dist/calendar/internal/time-slot.d.ts +17 -0
  16. package/dist/calendar/internal/time-slot.js +23 -0
  17. package/dist/calendar/month-view.d.ts +2 -0
  18. package/dist/calendar/month-view.js +46 -0
  19. package/dist/calendar/public.d.ts +6 -0
  20. package/dist/calendar/public.js +8 -0
  21. package/dist/calendar/types.d.ts +113 -0
  22. package/dist/calendar/types.js +15 -0
  23. package/dist/calendar/week-view.d.ts +2 -0
  24. package/dist/calendar/week-view.js +39 -0
  25. package/dist/chat/turn-card.js +10 -5
  26. package/dist/email-builder/block-error-boundary.d.ts +16 -0
  27. package/dist/email-builder/block-error-boundary.js +21 -0
  28. package/dist/email-builder/block-palette.d.ts +7 -0
  29. package/dist/email-builder/block-palette.js +22 -0
  30. package/dist/email-builder/block-registry.d.ts +15 -0
  31. package/dist/email-builder/block-registry.js +157 -0
  32. package/dist/email-builder/block-renderer.d.ts +5 -0
  33. package/dist/email-builder/block-renderer.js +40 -0
  34. package/dist/email-builder/block-renderers/button.d.ts +4 -0
  35. package/dist/email-builder/block-renderers/button.js +26 -0
  36. package/dist/email-builder/block-renderers/columns.d.ts +5 -0
  37. package/dist/email-builder/block-renderers/columns.js +27 -0
  38. package/dist/email-builder/block-renderers/divider.d.ts +4 -0
  39. package/dist/email-builder/block-renderers/divider.js +14 -0
  40. package/dist/email-builder/block-renderers/footer.d.ts +4 -0
  41. package/dist/email-builder/block-renderers/footer.js +12 -0
  42. package/dist/email-builder/block-renderers/heading.d.ts +4 -0
  43. package/dist/email-builder/block-renderers/heading.js +19 -0
  44. package/dist/email-builder/block-renderers/image.d.ts +4 -0
  45. package/dist/email-builder/block-renderers/image.js +18 -0
  46. package/dist/email-builder/block-renderers/social.d.ts +4 -0
  47. package/dist/email-builder/block-renderers/social.js +19 -0
  48. package/dist/email-builder/block-renderers/spacer.d.ts +4 -0
  49. package/dist/email-builder/block-renderers/spacer.js +5 -0
  50. package/dist/email-builder/block-renderers/text.d.ts +4 -0
  51. package/dist/email-builder/block-renderers/text.js +17 -0
  52. package/dist/email-builder/builder-canvas.d.ts +15 -0
  53. package/dist/email-builder/builder-canvas.js +28 -0
  54. package/dist/email-builder/builder-header.d.ts +9 -0
  55. package/dist/email-builder/builder-header.js +8 -0
  56. package/dist/email-builder/builder-left-tabs.d.ts +11 -0
  57. package/dist/email-builder/builder-left-tabs.js +20 -0
  58. package/dist/email-builder/email-builder.d.ts +3 -0
  59. package/dist/email-builder/email-builder.js +94 -0
  60. package/dist/email-builder/envelope-card.d.ts +7 -0
  61. package/dist/email-builder/envelope-card.js +16 -0
  62. package/dist/email-builder/floating-bar.d.ts +13 -0
  63. package/dist/email-builder/floating-bar.js +9 -0
  64. package/dist/email-builder/index.d.ts +4 -0
  65. package/dist/email-builder/index.js +12 -0
  66. package/dist/email-builder/internal/builder-state-utils.d.ts +7 -0
  67. package/dist/email-builder/internal/builder-state-utils.js +53 -0
  68. package/dist/email-builder/internal/dnd-wrapper.d.ts +10 -0
  69. package/dist/email-builder/internal/dnd-wrapper.js +9 -0
  70. package/dist/email-builder/internal/email-font-options.d.ts +5 -0
  71. package/dist/email-builder/internal/email-font-options.js +12 -0
  72. package/dist/email-builder/mobile-drawers.d.ts +10 -0
  73. package/dist/email-builder/mobile-drawers.js +7 -0
  74. package/dist/email-builder/mobile-tab-bar.d.ts +10 -0
  75. package/dist/email-builder/mobile-tab-bar.js +9 -0
  76. package/dist/email-builder/property-editors/_shared.d.ts +58 -0
  77. package/dist/email-builder/property-editors/_shared.js +54 -0
  78. package/dist/email-builder/property-editors/button-editor.d.ts +7 -0
  79. package/dist/email-builder/property-editors/button-editor.js +10 -0
  80. package/dist/email-builder/property-editors/columns-editor.d.ts +7 -0
  81. package/dist/email-builder/property-editors/columns-editor.js +15 -0
  82. package/dist/email-builder/property-editors/divider-editor.d.ts +7 -0
  83. package/dist/email-builder/property-editors/divider-editor.js +10 -0
  84. package/dist/email-builder/property-editors/footer-editor.d.ts +7 -0
  85. package/dist/email-builder/property-editors/footer-editor.js +6 -0
  86. package/dist/email-builder/property-editors/heading-editor.d.ts +7 -0
  87. package/dist/email-builder/property-editors/heading-editor.js +16 -0
  88. package/dist/email-builder/property-editors/image-editor.d.ts +8 -0
  89. package/dist/email-builder/property-editors/image-editor.js +17 -0
  90. package/dist/email-builder/property-editors/social-editor.d.ts +7 -0
  91. package/dist/email-builder/property-editors/social-editor.js +18 -0
  92. package/dist/email-builder/property-editors/spacer-editor.d.ts +7 -0
  93. package/dist/email-builder/property-editors/spacer-editor.js +6 -0
  94. package/dist/email-builder/property-editors/text-editor.d.ts +13 -0
  95. package/dist/email-builder/property-editors/text-editor.js +8 -0
  96. package/dist/email-builder/property-inspector.d.ts +11 -0
  97. package/dist/email-builder/property-inspector.js +42 -0
  98. package/dist/email-builder/public.d.ts +1 -0
  99. package/dist/email-builder/public.js +3 -0
  100. package/dist/email-builder/render-to-email-html.d.ts +11 -0
  101. package/dist/email-builder/render-to-email-html.js +220 -0
  102. package/dist/email-builder/starter-shell.d.ts +3 -0
  103. package/dist/email-builder/starter-shell.js +21 -0
  104. package/dist/email-builder/types.d.ts +182 -0
  105. package/dist/email-builder/types.js +41 -0
  106. package/dist/email-builder/view-controls.d.ts +10 -0
  107. package/dist/email-builder/view-controls.js +12 -0
  108. package/dist/index.d.ts +4 -0
  109. package/dist/index.js +4 -0
  110. package/dist/lib/format-time.js +2 -3
  111. package/dist/marketing/index.d.ts +10 -1
  112. package/dist/marketing/index.js +9 -0
  113. package/dist/marketing/marketing-bento-card.d.ts +2 -0
  114. package/dist/marketing/marketing-bento-card.js +24 -0
  115. package/dist/marketing/marketing-bento-grid.d.ts +2 -0
  116. package/dist/marketing/marketing-bento-grid.js +12 -0
  117. package/dist/marketing/marketing-faq.d.ts +2 -0
  118. package/dist/marketing/marketing-faq.js +12 -0
  119. package/dist/marketing/marketing-footer.d.ts +2 -0
  120. package/dist/marketing/marketing-footer.js +5 -0
  121. package/dist/marketing/marketing-header-logo.d.ts +10 -0
  122. package/dist/marketing/marketing-header-logo.js +6 -0
  123. package/dist/marketing/marketing-header.d.ts +2 -0
  124. package/dist/marketing/marketing-header.js +26 -0
  125. package/dist/marketing/marketing-nav-item.d.ts +4 -0
  126. package/dist/marketing/marketing-nav-item.js +10 -0
  127. package/dist/marketing/marketing-shell.d.ts +2 -0
  128. package/dist/marketing/marketing-shell.js +5 -0
  129. package/dist/marketing/marketing-trust-bar.d.ts +2 -0
  130. package/dist/marketing/marketing-trust-bar.js +5 -0
  131. package/dist/marketing/public.d.ts +1 -1
  132. package/dist/marketing/types.d.ts +99 -0
  133. package/dist/post-preview/index.d.ts +4 -0
  134. package/dist/post-preview/index.js +7 -0
  135. package/dist/post-preview/internal/avatar.d.ts +12 -0
  136. package/dist/post-preview/internal/avatar.js +21 -0
  137. package/dist/post-preview/internal/format-content.d.ts +12 -0
  138. package/dist/post-preview/internal/format-content.js +32 -0
  139. package/dist/post-preview/internal/platform-meta.d.ts +10 -0
  140. package/dist/post-preview/internal/platform-meta.js +18 -0
  141. package/dist/post-preview/internal/textarea.d.ts +8 -0
  142. package/dist/post-preview/internal/textarea.js +12 -0
  143. package/dist/post-preview/internal/use-swipe.d.ts +17 -0
  144. package/dist/post-preview/internal/use-swipe.js +29 -0
  145. package/dist/post-preview/platforms/bluesky.d.ts +15 -0
  146. package/dist/post-preview/platforms/bluesky.js +21 -0
  147. package/dist/post-preview/platforms/discord.d.ts +44 -0
  148. package/dist/post-preview/platforms/discord.js +34 -0
  149. package/dist/post-preview/platforms/facebook.d.ts +23 -0
  150. package/dist/post-preview/platforms/facebook.js +26 -0
  151. package/dist/post-preview/platforms/generic.d.ts +22 -0
  152. package/dist/post-preview/platforms/generic.js +30 -0
  153. package/dist/post-preview/platforms/google-business.d.ts +18 -0
  154. package/dist/post-preview/platforms/google-business.js +24 -0
  155. package/dist/post-preview/platforms/index.d.ts +24 -0
  156. package/dist/post-preview/platforms/index.js +13 -0
  157. package/dist/post-preview/platforms/instagram.d.ts +31 -0
  158. package/dist/post-preview/platforms/instagram.js +104 -0
  159. package/dist/post-preview/platforms/linkedin.d.ts +52 -0
  160. package/dist/post-preview/platforms/linkedin.js +140 -0
  161. package/dist/post-preview/platforms/telegram.d.ts +46 -0
  162. package/dist/post-preview/platforms/telegram.js +44 -0
  163. package/dist/post-preview/platforms/threads.d.ts +19 -0
  164. package/dist/post-preview/platforms/threads.js +26 -0
  165. package/dist/post-preview/platforms/tiktok.d.ts +18 -0
  166. package/dist/post-preview/platforms/tiktok.js +25 -0
  167. package/dist/post-preview/platforms/twitter.d.ts +40 -0
  168. package/dist/post-preview/platforms/twitter.js +137 -0
  169. package/dist/post-preview/platforms/youtube.d.ts +17 -0
  170. package/dist/post-preview/platforms/youtube.js +23 -0
  171. package/dist/post-preview/post-preview.d.ts +29 -0
  172. package/dist/post-preview/post-preview.js +70 -0
  173. package/dist/post-preview/public.d.ts +1 -0
  174. package/dist/post-preview/public.js +6 -0
  175. package/dist/post-preview/types.d.ts +82 -0
  176. package/dist/post-preview/types.js +1 -0
  177. package/dist/primitives/filter-rail.js +17 -2
  178. package/dist/shell/command-palette.js +2 -0
  179. package/dist/shell/drag-mode-banner.js +4 -0
  180. package/dist/shell/extras/shell-scrollable-content.js +2 -2
  181. package/dist/shell/extras/workbench-layout.js +24 -13
  182. package/dist/shell/internal/mobile-bottom-nav.js +1 -0
  183. package/dist/shell/internal/mobile-drawers.js +5 -0
  184. package/dist/shell/rail-drop-slot.js +20 -3
  185. package/dist/shell/rail-drop-zones.js +2 -0
  186. package/dist/shell/right-panel.js +10 -1
  187. package/dist/shell/shell-header.js +7 -1
  188. package/dist/shell/theme-next-themes.js +7 -2
  189. package/dist/shell/theme.js +7 -1
  190. package/dist/shell/use-shell-viewport.js +2 -0
  191. package/dist/timeline/lane-timeline.js +1 -1
  192. package/dist/timeline/scrub-bar.js +1 -1
  193. package/dist/timeline/timeline-tape.js +8 -5
  194. package/dist/voice/voice-orb-scene.js +4 -4
  195. package/dist/voice/voice-status-pill.js +8 -7
  196. package/dist/workflow-builder/edges/default-edge.d.ts +10 -0
  197. package/dist/workflow-builder/edges/default-edge.js +21 -0
  198. package/dist/workflow-builder/edges/index.d.ts +3 -0
  199. package/dist/workflow-builder/edges/index.js +5 -0
  200. package/dist/workflow-builder/index.d.ts +5 -0
  201. package/dist/workflow-builder/index.js +12 -0
  202. package/dist/workflow-builder/internal/trigger-icons.d.ts +4 -0
  203. package/dist/workflow-builder/internal/trigger-icons.js +43 -0
  204. package/dist/workflow-builder/internal/trigger-sentence.d.ts +14 -0
  205. package/dist/workflow-builder/internal/trigger-sentence.js +50 -0
  206. package/dist/workflow-builder/nodes/action-node.d.ts +3 -0
  207. package/dist/workflow-builder/nodes/action-node.js +7 -0
  208. package/dist/workflow-builder/nodes/base-node.d.ts +20 -0
  209. package/dist/workflow-builder/nodes/base-node.js +18 -0
  210. package/dist/workflow-builder/nodes/condition-node.d.ts +3 -0
  211. package/dist/workflow-builder/nodes/condition-node.js +11 -0
  212. package/dist/workflow-builder/nodes/delay-node.d.ts +3 -0
  213. package/dist/workflow-builder/nodes/delay-node.js +7 -0
  214. package/dist/workflow-builder/nodes/end-node.d.ts +3 -0
  215. package/dist/workflow-builder/nodes/end-node.js +7 -0
  216. package/dist/workflow-builder/nodes/index.d.ts +13 -0
  217. package/dist/workflow-builder/nodes/index.js +22 -0
  218. package/dist/workflow-builder/nodes/trigger-node.d.ts +3 -0
  219. package/dist/workflow-builder/nodes/trigger-node.js +8 -0
  220. package/dist/workflow-builder/public.d.ts +1 -0
  221. package/dist/workflow-builder/public.js +4 -0
  222. package/dist/workflow-builder/types.d.ts +140 -0
  223. package/dist/workflow-builder/types.js +18 -0
  224. package/dist/workflow-builder/workflow-builder.d.ts +10 -0
  225. package/dist/workflow-builder/workflow-builder.js +22 -0
  226. package/dist/workflow-builder/workflow-canvas.d.ts +26 -0
  227. package/dist/workflow-builder/workflow-canvas.js +29 -0
  228. package/dist/workflow-builder/workflow-card-compact.d.ts +2 -0
  229. package/dist/workflow-builder/workflow-card-compact.js +22 -0
  230. package/dist/workflow-builder/workflow-card.d.ts +2 -0
  231. package/dist/workflow-builder/workflow-card.js +44 -0
  232. package/dist/workflow-builder/workflow-header.d.ts +2 -0
  233. package/dist/workflow-builder/workflow-header.js +32 -0
  234. package/dist/workflow-builder/workflow-toolbox.d.ts +2 -0
  235. package/dist/workflow-builder/workflow-toolbox.js +19 -0
  236. package/package.json +72 -50
  237. package/dist/styles/theme.test.ts +0 -41
@@ -0,0 +1,41 @@
1
+ // Email builder type system.
2
+ //
3
+ // Block kinds match the spec from the source surface
4
+ // (apps/web/src/components/email-builder/block-types.ts) but are narrowed to a
5
+ // publishable subset. The Convex-coupled `contentSlot` kind is omitted.
6
+ // ============================================
7
+ // Block kinds
8
+ // ============================================
9
+ export const BLOCK_KINDS = [
10
+ 'heading',
11
+ 'text',
12
+ 'image',
13
+ 'button',
14
+ 'divider',
15
+ 'spacer',
16
+ 'columns',
17
+ 'social',
18
+ 'footer',
19
+ ];
20
+ export const defaultEmailBuilderLabels = {
21
+ addBlock: 'Add block',
22
+ blockPalette: 'Block palette',
23
+ blocksTab: 'Blocks',
24
+ designTab: 'Design',
25
+ envelopeTab: 'Envelope',
26
+ rightRailEmpty: 'Select a block to edit its properties.',
27
+ openBlocks: 'Blocks',
28
+ openInspector: 'Inspector',
29
+ openSettings: 'Settings',
30
+ preview: 'Preview',
31
+ desktopPreview: 'Desktop preview',
32
+ mobilePreview: 'Mobile preview',
33
+ exportHtml: 'Export HTML',
34
+ emptyTitle: 'Start your email',
35
+ emptyDescription: 'Add a block from the palette to get started.',
36
+ inspectorEmpty: 'Select a block to edit its properties.',
37
+ duplicateBlock: 'Duplicate block',
38
+ deleteBlock: 'Delete block',
39
+ moveUp: 'Move up',
40
+ moveDown: 'Move down',
41
+ };
@@ -0,0 +1,10 @@
1
+ import type { DevicePreview } from './types.js';
2
+ interface ViewControlsProps {
3
+ device: DevicePreview;
4
+ onDeviceChange: (next: DevicePreview) => void;
5
+ desktopLabel: string;
6
+ mobileLabel: string;
7
+ }
8
+ /** Toggle between desktop and mobile preview modes. */
9
+ export declare function ViewControls({ device, onDeviceChange, desktopLabel, mobileLabel, }: ViewControlsProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Monitor, Smartphone } from 'lucide-react';
4
+ import { cn } from '../lib/utils.js';
5
+ /** Toggle between desktop and mobile preview modes. */
6
+ export function ViewControls({ device, onDeviceChange, desktopLabel, mobileLabel, }) {
7
+ return (_jsxs("div", { role: "radiogroup", "aria-label": "Preview width", "data-slot": "email-builder-view-controls", className: "inline-flex rounded-md border border-input p-0.5", children: [_jsx("button", { type: "button", role: "radio", "aria-checked": device === 'desktop', "aria-label": desktopLabel, onClick: () => onDeviceChange('desktop'), className: cn('inline-flex h-9 w-10 items-center justify-center rounded', device === 'desktop'
8
+ ? 'bg-primary text-primary-foreground'
9
+ : 'text-muted-foreground hover:bg-accent'), children: _jsx(Monitor, { className: "size-4", "aria-hidden": true }) }), _jsx("button", { type: "button", role: "radio", "aria-checked": device === 'mobile', "aria-label": mobileLabel, onClick: () => onDeviceChange('mobile'), className: cn('inline-flex h-9 w-10 items-center justify-center rounded', device === 'mobile'
10
+ ? 'bg-primary text-primary-foreground'
11
+ : 'text-muted-foreground hover:bg-accent'), children: _jsx(Smartphone, { className: "size-4", "aria-hidden": true }) })] }));
12
+ }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  export * from './auth/public.js';
2
2
  export * from './brand/public.js';
3
+ export * from './calendar/public.js';
3
4
  export * from './chat/public.js';
5
+ export * from './email-builder/public.js';
4
6
  export * from './marketing/public.js';
5
7
  export * from './panel/public.js';
8
+ export * from './post-preview/public.js';
6
9
  export * from './primitives/index.js';
7
10
  export * from './shell/index.js';
8
11
  export * from './theme/index.js';
9
12
  export * from './timeline/public.js';
13
+ export * from './workflow-builder/public.js';
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
1
  export * from './auth/public.js';
2
2
  export * from './brand/public.js';
3
+ export * from './calendar/public.js';
3
4
  export * from './chat/public.js';
5
+ export * from './email-builder/public.js';
4
6
  export * from './marketing/public.js';
5
7
  export * from './panel/public.js';
8
+ export * from './post-preview/public.js';
6
9
  export * from './primitives/index.js';
7
10
  export * from './shell/index.js'; // v2 surface
8
11
  export * from './theme/index.js';
9
12
  export * from './timeline/public.js';
13
+ export * from './workflow-builder/public.js';
@@ -10,9 +10,8 @@ export function formatClock(date, opts = {}) {
10
10
  return fmt.format(date);
11
11
  }
12
12
  export function formatDuration(ms) {
13
- if (ms < 0)
14
- ms = 0;
15
- const totalSec = Math.floor(ms / 1000);
13
+ const clampedMs = ms < 0 ? 0 : ms;
14
+ const totalSec = Math.floor(clampedMs / 1000);
16
15
  const h = Math.floor(totalSec / 3600);
17
16
  const m = Math.floor((totalSec % 3600) / 60);
18
17
  const s = totalSec % 60;
@@ -1,5 +1,14 @@
1
+ export { MarketingBentoCard } from './marketing-bento-card.js';
2
+ export { MarketingBentoGrid } from './marketing-bento-grid.js';
1
3
  export { MarketingCallout } from './marketing-callout.js';
2
4
  export { MarketingContact } from './marketing-contact.js';
3
5
  export { MarketingCtaList } from './marketing-cta-list.js';
6
+ export { MarketingFAQ } from './marketing-faq.js';
7
+ export { MarketingFooter } from './marketing-footer.js';
8
+ export { MarketingHeader } from './marketing-header.js';
9
+ export { MarketingHeaderLogo } from './marketing-header-logo.js';
4
10
  export { MarketingLeadMagnet } from './marketing-lead-magnet.js';
5
- export type { MarketingAlign, MarketingCalloutProps, MarketingCalloutVariant, MarketingContactPerson, MarketingContactProps, MarketingCta, MarketingCtaListProps, MarketingCtaVariant, MarketingLeadMagnetProps, MarketingLeadMagnetVariant, MarketingOffice, } from './types.js';
11
+ export { MarketingNavItem } from './marketing-nav-item.js';
12
+ export { MarketingShell } from './marketing-shell.js';
13
+ export { MarketingTrustBar } from './marketing-trust-bar.js';
14
+ export type { MarketingAlign, MarketingBentoCardProps, MarketingBentoGridProps, MarketingCalloutProps, MarketingCalloutVariant, MarketingContactPerson, MarketingContactProps, MarketingCta, MarketingCtaListProps, MarketingCtaVariant, MarketingFAQItem, MarketingFAQProps, MarketingFooterColumn, MarketingFooterProps, MarketingHeaderProps, MarketingHeaderUser, MarketingLeadMagnetProps, MarketingLeadMagnetVariant, MarketingNavItemDescriptor, MarketingOffice, MarketingShellProps, MarketingTrustBarProps, MarketingTrustStat, } from './types.js';
@@ -1,4 +1,13 @@
1
+ export { MarketingBentoCard } from './marketing-bento-card.js';
2
+ export { MarketingBentoGrid } from './marketing-bento-grid.js';
1
3
  export { MarketingCallout } from './marketing-callout.js';
2
4
  export { MarketingContact } from './marketing-contact.js';
3
5
  export { MarketingCtaList } from './marketing-cta-list.js';
6
+ export { MarketingFAQ } from './marketing-faq.js';
7
+ export { MarketingFooter } from './marketing-footer.js';
8
+ export { MarketingHeader } from './marketing-header.js';
9
+ export { MarketingHeaderLogo } from './marketing-header-logo.js';
4
10
  export { MarketingLeadMagnet } from './marketing-lead-magnet.js';
11
+ export { MarketingNavItem } from './marketing-nav-item.js';
12
+ export { MarketingShell } from './marketing-shell.js';
13
+ export { MarketingTrustBar } from './marketing-trust-bar.js';
@@ -0,0 +1,2 @@
1
+ import type { MarketingBentoCardProps } from './types.js';
2
+ export declare function MarketingBentoCard({ colSpan, rowSpan, variant, icon, title, description, children, href, className, }: MarketingBentoCardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from './utils.js';
3
+ const COL_SPAN = {
4
+ 1: 'col-span-1',
5
+ 2: 'col-span-2 sm:col-span-2',
6
+ 3: 'col-span-3 sm:col-span-3',
7
+ 4: 'col-span-4 sm:col-span-4',
8
+ 6: 'col-span-6 sm:col-span-6',
9
+ 12: 'col-span-12',
10
+ };
11
+ const ROW_SPAN = {
12
+ 1: 'row-span-1',
13
+ 2: 'row-span-2',
14
+ 3: 'row-span-3',
15
+ };
16
+ const PADDING = {
17
+ default: 'p-6',
18
+ feature: 'p-8',
19
+ compact: 'p-4',
20
+ };
21
+ export function MarketingBentoCard({ colSpan = 4, rowSpan = 1, variant = 'default', icon, title, description, children, href, className, }) {
22
+ const Tag = href ? 'a' : 'div';
23
+ return (_jsxs(Tag, { "data-bento-card": true, ...(href ? { href } : {}), className: cx('rounded-2xl border border-border bg-card text-card-foreground transition', PADDING[variant], COL_SPAN[colSpan], ROW_SPAN[rowSpan], href && 'hover:border-primary/40 hover:bg-card/80', className), children: [icon && (_jsx("div", { className: "mb-4 inline-flex h-9 w-9 items-center justify-center rounded-xl bg-primary/10 text-primary", children: icon })), title && _jsx("h3", { className: "text-lg font-semibold", children: title }), description && _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: description }), children] }));
24
+ }
@@ -0,0 +1,2 @@
1
+ import type { MarketingBentoGridProps } from './types.js';
2
+ export declare function MarketingBentoGrid({ cols, children, className }: MarketingBentoGridProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cx } from './utils.js';
3
+ const COLS = {
4
+ 2: 'grid-cols-2',
5
+ 3: 'grid-cols-3',
6
+ 4: 'grid-cols-4',
7
+ 6: 'grid-cols-6',
8
+ 12: 'grid-cols-12',
9
+ };
10
+ export function MarketingBentoGrid({ cols = 12, children, className }) {
11
+ return (_jsx("section", { className: cx('mx-auto w-full max-w-6xl px-6 py-16', className), children: _jsx("div", { className: cx('grid gap-4', COLS[cols]), children: children }) }));
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { MarketingFAQProps } from './types.js';
2
+ export declare function MarketingFAQ({ eyebrow, title, items, defaultOpenId, className, }: MarketingFAQProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronDown } from 'lucide-react';
4
+ import { useState } from 'react';
5
+ import { cx } from './utils.js';
6
+ export function MarketingFAQ({ eyebrow, title, items, defaultOpenId, className, }) {
7
+ const [openId, setOpenId] = useState(defaultOpenId ?? null);
8
+ return (_jsxs("section", { className: cx('mx-auto w-full max-w-3xl px-6 py-16', className), children: [(eyebrow || title) && (_jsxs("div", { className: "mb-10 text-center", children: [eyebrow && _jsx("p", { className: "text-sm font-semibold text-primary", children: eyebrow }), title && _jsx("h2", { className: "mt-2 text-3xl font-semibold sm:text-4xl", children: title })] })), _jsx("ul", { className: "space-y-3", children: items.map((item) => {
9
+ const open = openId === item.id;
10
+ return (_jsxs("li", { className: "rounded-2xl border border-border bg-card", children: [_jsxs("button", { type: "button", "aria-expanded": open, onClick: () => setOpenId(open ? null : item.id), className: "flex w-full items-center justify-between px-5 py-4 text-left text-base font-medium", children: [item.question, _jsx(ChevronDown, { className: cx('h-4 w-4 transition', open && 'rotate-180'), "aria-hidden": true })] }), open && (_jsx("div", { className: "border-t border-border px-5 py-4 text-sm text-muted-foreground", children: item.answer }))] }, item.id));
11
+ }) })] }));
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { MarketingFooterProps } from './types.js';
2
+ export declare function MarketingFooter({ brand, tagline, columns, bottomSlot, className, }: MarketingFooterProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from './utils.js';
3
+ export function MarketingFooter({ brand, tagline, columns = [], bottomSlot, className, }) {
4
+ return (_jsxs("div", { className: cx('border-t border-border bg-background', className), children: [_jsxs("div", { className: "mx-auto grid w-full max-w-6xl gap-12 px-6 py-16 md:grid-cols-12", children: [_jsxs("div", { className: "md:col-span-4 space-y-3", children: [_jsx("div", { className: "text-lg font-semibold", children: brand }), tagline && _jsx("p", { className: "max-w-sm text-sm text-muted-foreground", children: tagline })] }), columns.map((col, i) => (_jsxs("div", { className: "md:col-span-2 space-y-3", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: col.title }), _jsx("ul", { className: "space-y-2", children: col.links.map((link, j) => (_jsx("li", { children: _jsx("a", { href: link.href, className: "text-sm text-muted-foreground hover:text-foreground", children: link.label }) }, `${j}-${link.href}`))) })] }, i)))] }), bottomSlot && (_jsx("div", { className: "border-t border-border", children: _jsx("div", { className: "mx-auto flex w-full max-w-6xl items-center justify-between px-6 py-4 text-xs text-muted-foreground", children: bottomSlot }) }))] }));
5
+ }
@@ -0,0 +1,10 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface MarketingHeaderLogoProps {
3
+ mark?: ReactNode;
4
+ word?: ReactNode;
5
+ href?: string;
6
+ /** Accessible name for the logo link. Falls back to `word` if it's a string, then to "Home". */
7
+ label?: string;
8
+ className?: string;
9
+ }
10
+ export declare function MarketingHeaderLogo({ mark, word, href, label, className, }: MarketingHeaderLogoProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from './utils.js';
3
+ export function MarketingHeaderLogo({ mark, word, href = '/', label, className, }) {
4
+ const accessibleName = label ?? (typeof word === 'string' ? word : undefined) ?? 'Home';
5
+ return (_jsxs("a", { href: href, "aria-label": accessibleName, className: cx('flex items-center gap-2 font-semibold tracking-tight', className), children: [mark, word && _jsx("span", { children: word })] }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { MarketingHeaderProps } from './types.js';
2
+ export declare function MarketingHeader({ logo, navItems, user, signInHref, signUpHref, appHref, rightSlot, toggles, renderLoggedOut, renderLoggedIn, className, }: MarketingHeaderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { MarketingNavItem } from './marketing-nav-item.js';
4
+ import { cx } from './utils.js';
5
+ const DEFAULT_SIGN_IN = '/sign-in';
6
+ const DEFAULT_SIGN_UP = '/sign-up';
7
+ const DEFAULT_APP = '/app';
8
+ function DefaultLoggedOut({ signInHref, signUpHref }) {
9
+ return (_jsxs(_Fragment, { children: [_jsx("a", { href: signInHref, className: "text-sm text-foreground/80 hover:text-foreground", children: "Sign in" }), _jsx("a", { href: signUpHref, className: "inline-flex items-center rounded-full bg-primary px-4 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90", children: "Start free" })] }));
10
+ }
11
+ function DefaultLoggedIn({ appHref }) {
12
+ return (_jsx("a", { href: appHref, className: "inline-flex items-center rounded-full bg-primary px-4 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90", children: "Open dashboard" }));
13
+ }
14
+ export function MarketingHeader({ logo, navItems = [], user, signInHref = DEFAULT_SIGN_IN, signUpHref = DEFAULT_SIGN_UP, appHref = DEFAULT_APP, rightSlot, toggles, renderLoggedOut, renderLoggedIn, className, }) {
15
+ let right;
16
+ if (rightSlot !== undefined) {
17
+ right = rightSlot;
18
+ }
19
+ else if (user) {
20
+ right = renderLoggedIn ? (renderLoggedIn(user, { appHref })) : (_jsx(DefaultLoggedIn, { appHref: appHref }));
21
+ }
22
+ else {
23
+ right = renderLoggedOut ? (renderLoggedOut({ signInHref, signUpHref })) : (_jsx(DefaultLoggedOut, { signInHref: signInHref, signUpHref: signUpHref }));
24
+ }
25
+ return (_jsxs("nav", { "aria-label": "Primary", className: cx('mx-auto flex w-full max-w-6xl items-center justify-between rounded-full border border-border/60 bg-background/70 px-4 py-2 backdrop-blur supports-[backdrop-filter]:bg-background/50', className), children: [_jsxs("div", { className: "flex items-center gap-6", children: [logo, _jsx("ul", { className: "hidden items-center gap-1 md:flex", children: navItems.map((item) => (_jsx("li", { children: _jsx(MarketingNavItem, { ...item }) }, item.id))) })] }), _jsxs("div", { className: "flex items-center gap-3", children: [toggles, right] })] }));
26
+ }
@@ -0,0 +1,4 @@
1
+ import type { MarketingNavItemDescriptor } from './types.js';
2
+ export declare function MarketingNavItem({ id, label, className, ...rest }: MarketingNavItemDescriptor & {
3
+ className?: string;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,10 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronDown } from 'lucide-react';
4
+ import { cx } from './utils.js';
5
+ export function MarketingNavItem({ id, label, className, ...rest }) {
6
+ if (rest.hasMenu) {
7
+ return (_jsxs("button", { type: "button", "data-nav-id": id, "aria-expanded": false, "aria-haspopup": "menu", className: cx('inline-flex items-center gap-1 rounded-full px-3 py-1.5 text-sm text-foreground/80 hover:text-foreground', className), children: [label, _jsx(ChevronDown, { "data-chevron": true, className: "h-3.5 w-3.5", "aria-hidden": true })] }));
8
+ }
9
+ return (_jsx("a", { href: rest.href, "data-nav-id": id, className: cx('inline-flex items-center rounded-full px-3 py-1.5 text-sm text-foreground/80 hover:text-foreground', className), children: label }));
10
+ }
@@ -0,0 +1,2 @@
1
+ import type { MarketingShellProps } from './types.js';
2
+ export declare function MarketingShell({ header, footer, children, className }: MarketingShellProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from './utils.js';
3
+ export function MarketingShell({ header, footer, children, className }) {
4
+ return (_jsxs("div", { className: cx('flex min-h-screen flex-col bg-background text-foreground', className), children: [header && _jsx("header", { className: "sticky top-4 z-40 px-4 sm:px-6", children: header }), _jsx("main", { className: "flex-1", children: children }), footer && _jsx("footer", { className: "mt-auto", children: footer })] }));
5
+ }
@@ -0,0 +1,2 @@
1
+ import type { MarketingTrustBarProps } from './types.js';
2
+ export declare function MarketingTrustBar({ eyebrow, title, stats, className }: MarketingTrustBarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from './utils.js';
3
+ export function MarketingTrustBar({ eyebrow, title, stats, className }) {
4
+ return (_jsxs("section", { className: cx('mx-auto w-full max-w-6xl px-6 py-16', className), children: [(eyebrow || title) && (_jsxs("div", { className: "mb-10 flex flex-col items-center gap-2 text-center", children: [eyebrow && _jsx("p", { className: "text-sm font-semibold text-primary", children: eyebrow }), title && _jsx("h2", { className: "text-2xl font-semibold sm:text-3xl", children: title })] })), _jsx("ul", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: stats.map((s, i) => (_jsxs("li", { className: "rounded-2xl border border-border bg-card p-6 text-card-foreground", children: [_jsx("div", { className: "text-3xl font-semibold tracking-tight", children: s.value }), _jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: s.label }), s.caption && _jsx("div", { className: "mt-2 text-xs text-muted-foreground", children: s.caption })] }, i))) })] }));
5
+ }
@@ -1 +1 @@
1
- export type { MarketingCalloutProps, MarketingContactPerson, MarketingContactProps, MarketingCta, MarketingLeadMagnetProps, MarketingOffice, } from './types.js';
1
+ export type { MarketingBentoCardProps, MarketingBentoGridProps, MarketingCalloutProps, MarketingContactPerson, MarketingContactProps, MarketingCta, MarketingFAQItem, MarketingFAQProps, MarketingFooterColumn, MarketingFooterProps, MarketingHeaderProps, MarketingHeaderUser, MarketingLeadMagnetProps, MarketingNavItemDescriptor, MarketingOffice, MarketingShellProps, MarketingTrustBarProps, MarketingTrustStat, } from './types.js';
@@ -65,3 +65,102 @@ export interface MarketingLeadMagnetProps {
65
65
  onOpenChange?: (open: boolean) => void;
66
66
  className?: string;
67
67
  }
68
+ export interface MarketingHeaderUser {
69
+ name: string;
70
+ email?: string;
71
+ image?: string;
72
+ workspaceSlug?: string;
73
+ }
74
+ interface MarketingNavItemBase {
75
+ id: string;
76
+ label: ReactNode;
77
+ }
78
+ export interface MarketingNavLinkItem extends MarketingNavItemBase {
79
+ href: string;
80
+ hasMenu?: false;
81
+ panel?: never;
82
+ }
83
+ export interface MarketingNavMenuItem extends MarketingNavItemBase {
84
+ hasMenu: true;
85
+ href?: string;
86
+ panel?: ReactNode;
87
+ }
88
+ export type MarketingNavItemDescriptor = MarketingNavLinkItem | MarketingNavMenuItem;
89
+ export interface MarketingHeaderProps {
90
+ logo?: ReactNode;
91
+ navItems?: MarketingNavItemDescriptor[];
92
+ user?: MarketingHeaderUser | null;
93
+ signInHref?: string;
94
+ signUpHref?: string;
95
+ appHref?: string;
96
+ rightSlot?: ReactNode;
97
+ toggles?: ReactNode;
98
+ renderLoggedOut?: (defaults: {
99
+ signInHref: string;
100
+ signUpHref: string;
101
+ }) => ReactNode;
102
+ renderLoggedIn?: (user: MarketingHeaderUser, defaults: {
103
+ appHref: string;
104
+ }) => ReactNode;
105
+ className?: string;
106
+ }
107
+ export interface MarketingShellProps {
108
+ header?: ReactNode;
109
+ footer?: ReactNode;
110
+ children?: ReactNode;
111
+ className?: string;
112
+ }
113
+ export interface MarketingFooterColumn {
114
+ title: ReactNode;
115
+ links: Array<{
116
+ label: ReactNode;
117
+ href: string;
118
+ }>;
119
+ }
120
+ export interface MarketingFooterProps {
121
+ brand?: ReactNode;
122
+ tagline?: ReactNode;
123
+ columns?: MarketingFooterColumn[];
124
+ bottomSlot?: ReactNode;
125
+ className?: string;
126
+ }
127
+ export interface MarketingTrustStat {
128
+ value: ReactNode;
129
+ label: ReactNode;
130
+ caption?: ReactNode;
131
+ }
132
+ export interface MarketingTrustBarProps {
133
+ eyebrow?: ReactNode;
134
+ title?: ReactNode;
135
+ stats: MarketingTrustStat[];
136
+ className?: string;
137
+ }
138
+ export interface MarketingBentoGridProps {
139
+ cols?: 2 | 3 | 4 | 6 | 12;
140
+ children?: ReactNode;
141
+ className?: string;
142
+ }
143
+ export interface MarketingBentoCardProps {
144
+ colSpan?: 1 | 2 | 3 | 4 | 6 | 12;
145
+ rowSpan?: 1 | 2 | 3;
146
+ variant?: 'default' | 'feature' | 'compact';
147
+ icon?: ReactNode;
148
+ title?: ReactNode;
149
+ description?: ReactNode;
150
+ children?: ReactNode;
151
+ href?: string;
152
+ className?: string;
153
+ }
154
+ export interface MarketingFAQItem {
155
+ id: string;
156
+ question: ReactNode;
157
+ answer: ReactNode;
158
+ }
159
+ export interface MarketingFAQProps {
160
+ eyebrow?: ReactNode;
161
+ title?: ReactNode;
162
+ items: MarketingFAQItem[];
163
+ defaultOpenId?: string;
164
+ className?: string;
165
+ }
166
+ export {};
@@ -0,0 +1,4 @@
1
+ export type { BlueSkyLabels, BlueSkyPreviewProps, DiscordEmbedDraft, DiscordLabels, DiscordPreviewProps, FacebookLabels, FacebookPreviewProps, GenericLabels, GenericPreviewProps, GoogleBusinessLabels, GoogleBusinessPreviewProps, InstagramLabels, InstagramPostType, InstagramPreviewProps, LinkedInLabels, LinkedInMentionData, LinkedInMentionPickerContext, LinkedInPreviewProps, TelegramInlineKeyboardButton, TelegramInlineKeyboardMarkup, TelegramLabels, TelegramPollState, TelegramPreviewProps, ThreadsLabels, ThreadsPreviewProps, TikTokLabels, TikTokPreviewProps, TwitterLabels, TwitterMentionPickerContext, TwitterPreviewProps, TwitterTheme, YouTubeLabels, YouTubePreviewProps, } from './platforms/index.js';
2
+ export { DEFAULT_BLUESKY_LABELS, DEFAULT_DISCORD_LABELS, DEFAULT_FACEBOOK_LABELS, DEFAULT_GENERIC_LABELS, DEFAULT_GOOGLE_BUSINESS_LABELS, DEFAULT_INSTAGRAM_LABELS, DEFAULT_LINKEDIN_LABELS, DEFAULT_TELEGRAM_LABELS, DEFAULT_THREADS_LABELS, DEFAULT_TIKTOK_LABELS, DEFAULT_TWITTER_LABELS, DEFAULT_YOUTUBE_LABELS, } from './platforms/index.js';
3
+ export { PostPreview, type PostPreviewProps } from './post-preview.js';
4
+ export type { PlatformId, PostPreviewBaseProps, PostPreviewFrame, PostPreviewSlots, } from './types.js';
@@ -0,0 +1,7 @@
1
+ // open/meda/src/post-preview/index.ts
2
+ //
3
+ // Subpath barrel for `@medalsocial/meda/post-preview`. Single top-level
4
+ // `PostPreview` component dispatches per-platform via the `platform` prop.
5
+ // Per-platform components, chromes, and helpers remain internal.
6
+ export { DEFAULT_BLUESKY_LABELS, DEFAULT_DISCORD_LABELS, DEFAULT_FACEBOOK_LABELS, DEFAULT_GENERIC_LABELS, DEFAULT_GOOGLE_BUSINESS_LABELS, DEFAULT_INSTAGRAM_LABELS, DEFAULT_LINKEDIN_LABELS, DEFAULT_TELEGRAM_LABELS, DEFAULT_THREADS_LABELS, DEFAULT_TIKTOK_LABELS, DEFAULT_TWITTER_LABELS, DEFAULT_YOUTUBE_LABELS, } from './platforms/index.js';
7
+ export { PostPreview } from './post-preview.js';
@@ -0,0 +1,12 @@
1
+ export interface AvatarProps {
2
+ src?: string;
3
+ displayName: string;
4
+ className?: string;
5
+ }
6
+ /**
7
+ * Internal avatar primitive used by post-preview platforms.
8
+ * Plain `<img>` with an initials fallback; deliberately not exported
9
+ * from the public surface so we don't lock consumers in. Consumers
10
+ * who want a richer Avatar primitive should pull one from elsewhere.
11
+ */
12
+ export declare function Avatar({ src, displayName, className }: AvatarProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { cn } from '../../lib/utils.js';
5
+ function initialOf(name) {
6
+ const trimmed = name.trim();
7
+ if (!trimmed)
8
+ return '?';
9
+ return trimmed.charAt(0).toUpperCase();
10
+ }
11
+ /**
12
+ * Internal avatar primitive used by post-preview platforms.
13
+ * Plain `<img>` with an initials fallback; deliberately not exported
14
+ * from the public surface so we don't lock consumers in. Consumers
15
+ * who want a richer Avatar primitive should pull one from elsewhere.
16
+ */
17
+ export function Avatar({ src, displayName, className }) {
18
+ const [errored, setErrored] = useState(false);
19
+ const showFallback = !src || errored;
20
+ return (_jsx("span", { "data-slot": "post-preview-avatar", className: cn('inline-flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-full bg-muted text-sm font-medium text-muted-foreground', className), children: showFallback ? (_jsx("span", { role: "img", "aria-label": displayName, children: initialOf(displayName) })) : (_jsx("img", { src: src, alt: displayName, loading: "lazy", decoding: "async", onError: () => setErrored(true), className: "h-full w-full object-cover" })) }));
21
+ }
@@ -0,0 +1,12 @@
1
+ export type ContentPartType = 'text' | 'mention' | 'hashtag' | 'url';
2
+ export interface ContentPart {
3
+ type: ContentPartType;
4
+ value: string;
5
+ }
6
+ /**
7
+ * Split a content string into typed parts so platform components can
8
+ * apply per-platform styling for mentions, hashtags, and URLs.
9
+ *
10
+ * Empty strings return an empty array (callers can render nothing).
11
+ */
12
+ export declare function splitContent(content: string): ContentPart[];
@@ -0,0 +1,32 @@
1
+ const PATTERN = /(@[A-Za-z0-9_]+|#[A-Za-z0-9_]+|https?:\/\/\S+)/g;
2
+ /**
3
+ * Split a content string into typed parts so platform components can
4
+ * apply per-platform styling for mentions, hashtags, and URLs.
5
+ *
6
+ * Empty strings return an empty array (callers can render nothing).
7
+ */
8
+ export function splitContent(content) {
9
+ if (!content)
10
+ return [];
11
+ const parts = [];
12
+ let lastIndex = 0;
13
+ for (const match of content.matchAll(PATTERN)) {
14
+ /* v8 ignore next — match.index is always defined for matchAll results */
15
+ const matchIndex = match.index ?? 0;
16
+ if (matchIndex > lastIndex) {
17
+ parts.push({ type: 'text', value: content.slice(lastIndex, matchIndex) });
18
+ }
19
+ const value = match[0];
20
+ if (value.startsWith('@'))
21
+ parts.push({ type: 'mention', value });
22
+ else if (value.startsWith('#'))
23
+ parts.push({ type: 'hashtag', value });
24
+ else
25
+ parts.push({ type: 'url', value });
26
+ lastIndex = matchIndex + value.length;
27
+ }
28
+ if (lastIndex < content.length) {
29
+ parts.push({ type: 'text', value: content.slice(lastIndex) });
30
+ }
31
+ return parts;
32
+ }
@@ -0,0 +1,10 @@
1
+ import type { PlatformId } from '../types.js';
2
+ export interface PlatformMeta {
3
+ /** Human-readable name (e.g. "Twitter / X"). */
4
+ displayName: string;
5
+ /** Platform brand color (hex with leading #). */
6
+ brandColor: string;
7
+ /** Soft per-platform character limit (consumers may override per render). */
8
+ characterLimit: number;
9
+ }
10
+ export declare const PLATFORM_META: Record<PlatformId, PlatformMeta>;
@@ -0,0 +1,18 @@
1
+ export const PLATFORM_META = {
2
+ twitter: { displayName: 'X', brandColor: '#000000', characterLimit: 280 },
3
+ linkedin: { displayName: 'LinkedIn', brandColor: '#0A66C2', characterLimit: 3000 },
4
+ instagram: { displayName: 'Instagram', brandColor: '#E4405F', characterLimit: 2200 },
5
+ facebook: { displayName: 'Facebook', brandColor: '#1877F2', characterLimit: 63_206 },
6
+ threads: { displayName: 'Threads', brandColor: '#000000', characterLimit: 500 },
7
+ bluesky: { displayName: 'Bluesky', brandColor: '#0085FF', characterLimit: 300 },
8
+ tiktok: { displayName: 'TikTok', brandColor: '#000000', characterLimit: 4000 },
9
+ youtube: { displayName: 'YouTube', brandColor: '#FF0000', characterLimit: 5000 },
10
+ google_business: {
11
+ displayName: 'Google Business',
12
+ brandColor: '#4285F4',
13
+ characterLimit: 1500,
14
+ },
15
+ telegram: { displayName: 'Telegram', brandColor: '#26A5E4', characterLimit: 4096 },
16
+ discord: { displayName: 'Discord', brandColor: '#5865F2', characterLimit: 2000 },
17
+ generic: { displayName: 'Generic', brandColor: '#6B7280', characterLimit: 63_206 },
18
+ };
@@ -0,0 +1,8 @@
1
+ import { type ComponentProps } from 'react';
2
+ export type TextareaProps = ComponentProps<'textarea'>;
3
+ /**
4
+ * Internal textarea used by post-preview platforms in editable mode.
5
+ * Minimal styling — platform-specific previews layer on their own
6
+ * background, font, and color via className. Not exported publicly.
7
+ */
8
+ export declare const Textarea: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref"> & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { forwardRef } from 'react';
4
+ import { cn } from '../../lib/utils.js';
5
+ /**
6
+ * Internal textarea used by post-preview platforms in editable mode.
7
+ * Minimal styling — platform-specific previews layer on their own
8
+ * background, font, and color via className. Not exported publicly.
9
+ */
10
+ export const Textarea = forwardRef(function Textarea({ className, ...props }, ref) {
11
+ return (_jsx("textarea", { ref: ref, "data-slot": "post-preview-textarea", className: cn('block w-full resize-none border-0 bg-transparent p-0 outline-none', 'placeholder:text-muted-foreground/60', 'focus-visible:ring-0 focus-visible:ring-offset-0', className), ...props }));
12
+ });
@@ -0,0 +1,17 @@
1
+ import type { TouchEvent } from 'react';
2
+ export interface UseSwipeOptions {
3
+ onSwipeLeft: () => void;
4
+ onSwipeRight: () => void;
5
+ }
6
+ /**
7
+ * Touch swipe detection for carousel navigation. Tracks touchstart/touchend
8
+ * and fires onSwipeLeft / onSwipeRight when the horizontal delta exceeds
9
+ * SWIPE_THRESHOLD (50px). Returns event handlers to spread onto the
10
+ * swipeable container.
11
+ *
12
+ * Ported from `apps/web/src/components/composer/editors/use-swipe.ts`.
13
+ */
14
+ export declare function useSwipe({ onSwipeLeft, onSwipeRight }: UseSwipeOptions): {
15
+ onTouchStart: (e: TouchEvent) => void;
16
+ onTouchEnd: (e: TouchEvent) => void;
17
+ };