@rovela-ai/sdk 0.14.1 → 0.15.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 (105) hide show
  1. package/dist/admin/api/emails.d.ts +2 -1
  2. package/dist/admin/api/emails.d.ts.map +1 -1
  3. package/dist/admin/api/emails.js +203 -34
  4. package/dist/admin/api/emails.js.map +1 -1
  5. package/dist/admin/components/AdminNav.d.ts.map +1 -1
  6. package/dist/admin/components/AdminNav.js +2 -1
  7. package/dist/admin/components/AdminNav.js.map +1 -1
  8. package/dist/admin/components/EmailsManager.d.ts.map +1 -1
  9. package/dist/admin/components/EmailsManager.js +168 -51
  10. package/dist/admin/components/EmailsManager.js.map +1 -1
  11. package/dist/admin/components/emails/BlocksEditor.d.ts +17 -0
  12. package/dist/admin/components/emails/BlocksEditor.d.ts.map +1 -0
  13. package/dist/admin/components/emails/BlocksEditor.js +110 -0
  14. package/dist/admin/components/emails/BlocksEditor.js.map +1 -0
  15. package/dist/admin/components/emails/EmailPreviewPane.d.ts +18 -0
  16. package/dist/admin/components/emails/EmailPreviewPane.d.ts.map +1 -0
  17. package/dist/admin/components/emails/EmailPreviewPane.js +52 -0
  18. package/dist/admin/components/emails/EmailPreviewPane.js.map +1 -0
  19. package/dist/admin/components/emails/EmailThemePanel.d.ts +27 -0
  20. package/dist/admin/components/emails/EmailThemePanel.d.ts.map +1 -0
  21. package/dist/admin/components/emails/EmailThemePanel.js +25 -0
  22. package/dist/admin/components/emails/EmailThemePanel.js.map +1 -0
  23. package/dist/admin/components/emails/FontPicker.d.ts +11 -0
  24. package/dist/admin/components/emails/FontPicker.d.ts.map +1 -0
  25. package/dist/admin/components/emails/FontPicker.js +55 -0
  26. package/dist/admin/components/emails/FontPicker.js.map +1 -0
  27. package/dist/admin/components/emails/TextBlockEditor.d.ts +7 -0
  28. package/dist/admin/components/emails/TextBlockEditor.d.ts.map +1 -0
  29. package/dist/admin/components/emails/TextBlockEditor.js +70 -0
  30. package/dist/admin/components/emails/TextBlockEditor.js.map +1 -0
  31. package/dist/core/db/queries.d.ts +38 -29
  32. package/dist/core/db/queries.d.ts.map +1 -1
  33. package/dist/core/db/queries.js +20 -0
  34. package/dist/core/db/queries.js.map +1 -1
  35. package/dist/core/db/schema.d.ts +35 -1
  36. package/dist/core/db/schema.d.ts.map +1 -1
  37. package/dist/core/db/schema.js +4 -0
  38. package/dist/core/db/schema.js.map +1 -1
  39. package/dist/emails/blocks.d.ts +95 -0
  40. package/dist/emails/blocks.d.ts.map +1 -0
  41. package/dist/emails/blocks.js +239 -0
  42. package/dist/emails/blocks.js.map +1 -0
  43. package/dist/emails/google-fonts.d.ts +13 -0
  44. package/dist/emails/google-fonts.d.ts.map +1 -0
  45. package/dist/emails/google-fonts.js +1943 -0
  46. package/dist/emails/google-fonts.js.map +1 -0
  47. package/dist/emails/overrides.d.ts +6 -0
  48. package/dist/emails/overrides.d.ts.map +1 -1
  49. package/dist/emails/overrides.js +10 -2
  50. package/dist/emails/overrides.js.map +1 -1
  51. package/dist/emails/registry.d.ts +49 -5
  52. package/dist/emails/registry.d.ts.map +1 -1
  53. package/dist/emails/registry.js +584 -122
  54. package/dist/emails/registry.js.map +1 -1
  55. package/dist/emails/send/auth.d.ts.map +1 -1
  56. package/dist/emails/send/auth.js +40 -25
  57. package/dist/emails/send/auth.js.map +1 -1
  58. package/dist/emails/send/orders.d.ts.map +1 -1
  59. package/dist/emails/send/orders.js +85 -55
  60. package/dist/emails/send/orders.js.map +1 -1
  61. package/dist/emails/templates/base.d.ts +7 -0
  62. package/dist/emails/templates/base.d.ts.map +1 -1
  63. package/dist/emails/templates/base.js +34 -12
  64. package/dist/emails/templates/base.js.map +1 -1
  65. package/dist/emails/templates/email-verification.d.ts +4 -0
  66. package/dist/emails/templates/email-verification.d.ts.map +1 -1
  67. package/dist/emails/templates/email-verification.js +10 -2
  68. package/dist/emails/templates/email-verification.js.map +1 -1
  69. package/dist/emails/templates/order-cancelled.d.ts +4 -0
  70. package/dist/emails/templates/order-cancelled.d.ts.map +1 -1
  71. package/dist/emails/templates/order-cancelled.js +18 -10
  72. package/dist/emails/templates/order-cancelled.js.map +1 -1
  73. package/dist/emails/templates/order-confirmation.d.ts +18 -0
  74. package/dist/emails/templates/order-confirmation.d.ts.map +1 -1
  75. package/dist/emails/templates/order-confirmation.js +43 -21
  76. package/dist/emails/templates/order-confirmation.js.map +1 -1
  77. package/dist/emails/templates/order-delivered.d.ts +6 -0
  78. package/dist/emails/templates/order-delivered.d.ts.map +1 -1
  79. package/dist/emails/templates/order-delivered.js +22 -16
  80. package/dist/emails/templates/order-delivered.js.map +1 -1
  81. package/dist/emails/templates/order-ready-for-pickup.d.ts +10 -0
  82. package/dist/emails/templates/order-ready-for-pickup.d.ts.map +1 -1
  83. package/dist/emails/templates/order-ready-for-pickup.js +38 -22
  84. package/dist/emails/templates/order-ready-for-pickup.js.map +1 -1
  85. package/dist/emails/templates/order-shipped.d.ts +6 -0
  86. package/dist/emails/templates/order-shipped.d.ts.map +1 -1
  87. package/dist/emails/templates/order-shipped.js +17 -9
  88. package/dist/emails/templates/order-shipped.js.map +1 -1
  89. package/dist/emails/templates/password-reset.d.ts +4 -0
  90. package/dist/emails/templates/password-reset.d.ts.map +1 -1
  91. package/dist/emails/templates/password-reset.js +10 -2
  92. package/dist/emails/templates/password-reset.js.map +1 -1
  93. package/dist/emails/templates/refund-processed.d.ts +6 -0
  94. package/dist/emails/templates/refund-processed.d.ts.map +1 -1
  95. package/dist/emails/templates/refund-processed.js +17 -7
  96. package/dist/emails/templates/refund-processed.js.map +1 -1
  97. package/dist/emails/templates/welcome.d.ts +2 -0
  98. package/dist/emails/templates/welcome.d.ts.map +1 -1
  99. package/dist/emails/templates/welcome.js +8 -4
  100. package/dist/emails/templates/welcome.js.map +1 -1
  101. package/dist/emails/theme.d.ts +35 -12
  102. package/dist/emails/theme.d.ts.map +1 -1
  103. package/dist/emails/theme.js +131 -42
  104. package/dist/emails/theme.js.map +1 -1
  105. package/package.json +7 -1
@@ -0,0 +1,110 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * @rovela/sdk/admin/components/emails/BlocksEditor
5
+ *
6
+ * The email body editor (Phase D2): a Klaviyo-style vertical block stack.
7
+ * Drag to reorder (dnd-kit), add static blocks (heading, text, button,
8
+ * image, badge, divider, spacer, note) or this email's dynamic data blocks
9
+ * (order items, totals, tracking…), edit each inline. Rich text loads
10
+ * TipTap lazily — the bundle only ships when this editor mounts.
11
+ *
12
+ * Emits plain EmailBlock JSON — the server sanitizes on save/preview and
13
+ * renders through the same base.ts helpers as the shipped templates.
14
+ */
15
+ import { Suspense, lazy, useMemo, useState } from 'react';
16
+ import { DndContext, closestCenter, PointerSensor, KeyboardSensor, useSensor, useSensors, } from '@dnd-kit/core';
17
+ import { SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable, arrayMove, } from '@dnd-kit/sortable';
18
+ import { CSS } from '@dnd-kit/utilities';
19
+ import { GripVertical, Trash2, Plus, Type, Heading1, MousePointerClick, Image as ImageIcon, BadgeCheck, Minus, MoveVertical, StickyNote, Database, } from 'lucide-react';
20
+ const TextBlockEditor = lazy(() => import('./TextBlockEditor'));
21
+ let newBlockSeq = 0;
22
+ function newId() {
23
+ newBlockSeq += 1;
24
+ return `m${Date.now().toString(36)}${newBlockSeq}`;
25
+ }
26
+ const STATIC_BLOCKS = [
27
+ { type: 'heading', label: 'Heading', icon: _jsx(Heading1, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'heading', text: 'A clear headline' }) },
28
+ { type: 'text', label: 'Text', icon: _jsx(Type, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'text', html: '<p>Write something…</p>', align: 'center' }) },
29
+ { type: 'button', label: 'Button', icon: _jsx(MousePointerClick, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'button', label: 'Visit the store', url: '{{shopUrl}}', style: 'filled' }) },
30
+ { type: 'image', label: 'Image', icon: _jsx(ImageIcon, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'image', url: '', alt: '' }) },
31
+ { type: 'badge', label: 'Badge', icon: _jsx(BadgeCheck, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'badge', text: 'Good news' }) },
32
+ { type: 'divider', label: 'Divider', icon: _jsx(Minus, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'divider' }) },
33
+ { type: 'spacer', label: 'Spacer', icon: _jsx(MoveVertical, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'spacer', size: 'md' }) },
34
+ { type: 'note', label: 'Note box', icon: _jsx(StickyNote, { className: "h-4 w-4" }), make: () => ({ id: newId(), type: 'note', html: '<p>A short highlighted note.</p>' }) },
35
+ ];
36
+ const BLOCK_LABELS = {
37
+ heading: 'Heading',
38
+ text: 'Text',
39
+ button: 'Button',
40
+ image: 'Image',
41
+ badge: 'Badge',
42
+ divider: 'Divider',
43
+ spacer: 'Spacer',
44
+ note: 'Note box',
45
+ dynamic: 'Data block',
46
+ };
47
+ // =============================================================================
48
+ // Per-block inline editors
49
+ // =============================================================================
50
+ function BlockBody({ block, slots, disabled, onPatch, }) {
51
+ switch (block.type) {
52
+ case 'heading':
53
+ return (_jsx("input", { className: "admin-input w-full font-semibold", value: block.text, disabled: disabled, onChange: (e) => onPatch({ text: e.target.value }) }));
54
+ case 'text':
55
+ case 'note': {
56
+ const isText = block.type === 'text';
57
+ return (_jsxs("div", { className: "space-y-1.5", children: [_jsx(Suspense, { fallback: _jsx("div", { className: "h-[104px] animate-pulse rounded-md bg-[hsl(var(--admin-muted))]" }), children: _jsx(TextBlockEditor, { value: block.html, disabled: disabled, onChange: (html) => onPatch({ html }) }) }), isText && (_jsxs("select", { className: "admin-input h-8 w-auto py-0 text-xs", value: block.align ?? 'center', disabled: disabled, onChange: (e) => onPatch({ align: e.target.value }), "aria-label": "Text alignment", children: [_jsx("option", { value: "center", children: "Centered" }), _jsx("option", { value: "left", children: "Left aligned" })] }))] }));
58
+ }
59
+ case 'button':
60
+ return (_jsxs("div", { className: "space-y-1.5", children: [_jsx("input", { className: "admin-input w-full", value: block.label, disabled: disabled, placeholder: "Button text", onChange: (e) => onPatch({ label: e.target.value }) }), _jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { className: "admin-input w-full", value: block.url, disabled: disabled, placeholder: "https://\u2026 or {{shopUrl}}", onChange: (e) => onPatch({ url: e.target.value }) }), _jsxs("select", { className: "admin-input h-10 w-auto shrink-0 text-xs", value: block.style ?? 'filled', disabled: disabled, onChange: (e) => onPatch({ style: e.target.value }), "aria-label": "Button style", children: [_jsx("option", { value: "filled", children: "Filled" }), _jsx("option", { value: "outline", children: "Outline" })] })] })] }));
61
+ case 'image':
62
+ return (_jsxs("div", { className: "space-y-1.5", children: [_jsx("input", { className: "admin-input w-full", value: block.url, disabled: disabled, placeholder: "Image address (copy one from your Files page)", onChange: (e) => onPatch({ url: e.target.value }) }), _jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { className: "admin-input w-full", value: block.alt ?? '', disabled: disabled, placeholder: "Describe the image (alt text)", onChange: (e) => onPatch({ alt: e.target.value }) }), _jsx("input", { className: "admin-input w-24 shrink-0", type: "number", min: 40, max: 600, value: block.width ?? '', disabled: disabled, placeholder: "Width", onChange: (e) => onPatch({ width: e.target.value ? Number(e.target.value) : undefined }), "aria-label": "Image width in pixels" })] }), block.url && (
63
+ // eslint-disable-next-line @next/next/no-img-element
64
+ _jsx("img", { src: block.url, alt: "", className: "max-h-28 rounded-md border border-[hsl(var(--admin-border))]" }))] }));
65
+ case 'badge':
66
+ return (_jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { className: "admin-input w-full", value: block.text, disabled: disabled, onChange: (e) => onPatch({ text: e.target.value }) }), _jsx("input", { className: "admin-input w-16 shrink-0 text-center", value: block.emoji ?? '', disabled: disabled, placeholder: "\u2713", maxLength: 4, onChange: (e) => onPatch({ emoji: e.target.value || undefined }), "aria-label": "Badge emoji" })] }));
67
+ case 'spacer':
68
+ return (_jsxs("select", { className: "admin-input h-8 w-auto py-0 text-xs", value: block.size ?? 'md', disabled: disabled, onChange: (e) => onPatch({ size: e.target.value }), "aria-label": "Spacer size", children: [_jsx("option", { value: "sm", children: "Small" }), _jsx("option", { value: "md", children: "Medium" }), _jsx("option", { value: "lg", children: "Large" })] }));
69
+ case 'divider':
70
+ return _jsx("div", { className: "border-t border-dashed border-[hsl(var(--admin-border))]" });
71
+ case 'dynamic': {
72
+ const meta = slots.find((s) => s.key === block.slot);
73
+ return (_jsx("p", { className: "text-xs text-[hsl(var(--admin-foreground-muted))]", children: meta?.description ?? 'Filled automatically from real data at send time.' }));
74
+ }
75
+ }
76
+ }
77
+ // =============================================================================
78
+ // Sortable row
79
+ // =============================================================================
80
+ function SortableBlockRow({ block, slots, disabled, onPatch, onRemove, }) {
81
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: block.id });
82
+ const slotMeta = block.type === 'dynamic' ? slots.find((s) => s.key === block.slot) : null;
83
+ const label = block.type === 'dynamic' ? (slotMeta?.label ?? 'Data block') : BLOCK_LABELS[block.type];
84
+ return (_jsxs("div", { ref: setNodeRef, style: { transform: CSS.Transform.toString(transform), transition }, className: `rounded-lg border border-[hsl(var(--admin-border))] bg-[hsl(var(--admin-card))] ${isDragging ? 'z-10 opacity-80 shadow-lg' : ''}`, children: [_jsxs("div", { className: "flex items-center gap-1.5 border-b border-[hsl(var(--admin-border))]/60 px-2 py-1.5", children: [_jsx("button", { type: "button", ...attributes, ...listeners, disabled: disabled, className: "cursor-grab touch-none text-[hsl(var(--admin-foreground-subtle))] hover:text-[hsl(var(--admin-foreground))]", "aria-label": `Reorder ${label}`, children: _jsx(GripVertical, { className: "h-4 w-4" }) }), _jsxs("span", { className: "inline-flex items-center gap-1 text-xs font-semibold text-[hsl(var(--admin-foreground-muted))]", children: [block.type === 'dynamic' && _jsx(Database, { className: "h-3 w-3" }), label] }), block.type === 'dynamic' && (_jsx("span", { className: "admin-badge admin-badge-neutral !py-0 text-[10px]", children: "auto-filled" })), _jsx("button", { type: "button", onClick: onRemove, disabled: disabled, className: "ml-auto text-[hsl(var(--admin-foreground-subtle))] hover:text-red-500", "aria-label": `Remove ${label}`, children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }), _jsx("div", { className: "px-2.5 py-2", children: _jsx(BlockBody, { block: block, slots: slots, disabled: disabled, onPatch: onPatch }) })] }));
85
+ }
86
+ // =============================================================================
87
+ // Editor
88
+ // =============================================================================
89
+ export function BlocksEditor({ blocks, onChange, slots, variables, disabled }) {
90
+ const [addOpen, setAddOpen] = useState(false);
91
+ const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
92
+ const ids = useMemo(() => blocks.map((b) => b.id), [blocks]);
93
+ const handleDragEnd = (event) => {
94
+ const { active, over } = event;
95
+ if (!over || active.id === over.id)
96
+ return;
97
+ const from = blocks.findIndex((b) => b.id === active.id);
98
+ const to = blocks.findIndex((b) => b.id === over.id);
99
+ if (from === -1 || to === -1)
100
+ return;
101
+ onChange(arrayMove(blocks, from, to));
102
+ };
103
+ const patchBlock = (id, patch) => onChange(blocks.map((b) => (b.id === id ? { ...b, ...patch } : b)));
104
+ const addBlock = (block) => {
105
+ onChange([...blocks, block]);
106
+ setAddOpen(false);
107
+ };
108
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: ids, strategy: verticalListSortingStrategy, children: _jsx("div", { className: "space-y-2", children: blocks.map((block) => (_jsx(SortableBlockRow, { block: block, slots: slots, disabled: disabled, onPatch: (patch) => patchBlock(block.id, patch), onRemove: () => onChange(blocks.filter((b) => b.id !== block.id)) }, block.id))) }) }) }), blocks.length === 0 && (_jsx("p", { className: "rounded-lg border border-dashed border-[hsl(var(--admin-border))] px-3 py-4 text-center text-sm text-[hsl(var(--admin-foreground-muted))]", children: "No blocks yet \u2014 add your first one below." })), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setAddOpen((o) => !o), disabled: disabled, className: "admin-btn admin-btn-secondary admin-btn-sm inline-flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), " Add block"] }), addOpen && (_jsxs("div", { className: "mt-2 rounded-lg border border-[hsl(var(--admin-border))] bg-[hsl(var(--admin-card))] p-2", children: [_jsx("p", { className: "mb-1 px-1 text-[10px] font-semibold uppercase tracking-wide text-[hsl(var(--admin-foreground-subtle))]", children: "Content" }), _jsx("div", { className: "grid grid-cols-2 gap-1", children: STATIC_BLOCKS.map((s) => (_jsxs("button", { type: "button", onClick: () => addBlock(s.make()), className: "flex items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm hover:bg-[hsl(var(--admin-muted))]", children: [_jsx("span", { className: "text-[hsl(var(--admin-foreground-muted))]", children: s.icon }), s.label] }, s.type))) }), slots.length > 0 && (_jsxs(_Fragment, { children: [_jsx("p", { className: "mb-1 mt-2 px-1 text-[10px] font-semibold uppercase tracking-wide text-[hsl(var(--admin-foreground-subtle))]", children: "Data from this email" }), _jsx("div", { className: "grid grid-cols-1 gap-1", children: slots.map((s) => (_jsxs("button", { type: "button", onClick: () => addBlock({ id: newId(), type: 'dynamic', slot: s.key }), className: "flex items-start gap-2 rounded-md px-2 py-1.5 text-left hover:bg-[hsl(var(--admin-muted))]", children: [_jsx(Database, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-[hsl(var(--admin-foreground-muted))]" }), _jsxs("span", { children: [_jsx("span", { className: "block text-sm", children: s.label }), _jsx("span", { className: "block text-xs text-[hsl(var(--admin-foreground-muted))]", children: s.description })] })] }, s.key))) })] }))] }))] }), variables.length > 0 && (_jsxs("p", { className: "text-xs text-[hsl(var(--admin-foreground-subtle))]", children: ["Available anywhere in your text: ", variables.map((v) => `{{${v}}}`).join(' · ')] }))] }));
109
+ }
110
+ //# sourceMappingURL=BlocksEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlocksEditor.js","sourceRoot":"","sources":["../../../../src/admin/components/emails/BlocksEditor.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACzD,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,SAAS,EACT,UAAU,GAEX,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,2BAA2B,EAC3B,WAAW,EACX,SAAS,GACV,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AACxC,OAAO,EACL,YAAY,EACZ,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,iBAAiB,EACjB,KAAK,IAAI,SAAS,EAClB,UAAU,EACV,KAAK,EACL,YAAY,EACZ,UAAU,EACV,QAAQ,GACT,MAAM,cAAc,CAAA;AAGrB,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAA;AAkB/D,IAAI,WAAW,GAAG,CAAC,CAAA;AACnB,SAAS,KAAK;IACZ,WAAW,IAAI,CAAC,CAAA;IAChB,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAA;AACpD,CAAC;AAED,MAAM,aAAa,GAAsG;IACvH,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,EAAE;IACvJ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAC,IAAI,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE;IAClK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAC,iBAAiB,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE;IAClM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE;IAC1I,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAC,UAAU,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE;IAC5I,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAC,KAAK,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE;IAC1H,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAC,YAAY,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE;IAC1I,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,KAAC,UAAU,IAAC,SAAS,EAAC,SAAS,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kCAAkC,EAAE,CAAC,EAAE;CACrK,CAAA;AAED,MAAM,YAAY,GAAuC;IACvD,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,YAAY;CACtB,CAAA;AAED,gFAAgF;AAChF,2BAA2B;AAC3B,gFAAgF;AAEhF,SAAS,SAAS,CAAC,EACjB,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,GAMR;IACC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,CACL,gBACE,SAAS,EAAC,kCAAkC,EAC5C,KAAK,EAAE,KAAK,CAAC,IAAI,EACjB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAyB,CAAC,GACzE,CACH,CAAA;QACH,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAA;YACpC,OAAO,CACL,eAAK,SAAS,EAAC,aAAa,aAC1B,KAAC,QAAQ,IAAC,QAAQ,EAAE,cAAK,SAAS,EAAC,iEAAiE,GAAG,YACrG,KAAC,eAAe,IACd,KAAK,EAAE,KAAK,CAAC,IAAI,EACjB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAyB,CAAC,GAC5D,GACO,EACV,MAAM,IAAI,CACT,kBACE,SAAS,EAAC,qCAAqC,EAC/C,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,QAAQ,EAC9B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAA0B,EAAyB,CAAC,gBACpF,gBAAgB,aAE3B,iBAAQ,KAAK,EAAC,QAAQ,yBAAkB,EACxC,iBAAQ,KAAK,EAAC,MAAM,6BAAsB,IACnC,CACV,IACG,CACP,CAAA;QACH,CAAC;QACD,KAAK,QAAQ;YACX,OAAO,CACL,eAAK,SAAS,EAAC,aAAa,aAC1B,gBACE,SAAS,EAAC,oBAAoB,EAC9B,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAC,aAAa,EACzB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAyB,CAAC,GAC1E,EACF,eAAK,SAAS,EAAC,cAAc,aAC3B,gBACE,SAAS,EAAC,oBAAoB,EAC9B,KAAK,EAAE,KAAK,CAAC,GAAG,EAChB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAC,+BAA0B,EACtC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAyB,CAAC,GACxE,EACF,kBACE,SAAS,EAAC,0CAA0C,EACpD,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,QAAQ,EAC9B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAA6B,EAAyB,CAAC,gBACvF,cAAc,aAEzB,iBAAQ,KAAK,EAAC,QAAQ,uBAAgB,EACtC,iBAAQ,KAAK,EAAC,SAAS,wBAAiB,IACjC,IACL,IACF,CACP,CAAA;QACH,KAAK,OAAO;YACV,OAAO,CACL,eAAK,SAAS,EAAC,aAAa,aAC1B,gBACE,SAAS,EAAC,oBAAoB,EAC9B,KAAK,EAAE,KAAK,CAAC,GAAG,EAChB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAC,+CAA+C,EAC3D,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAyB,CAAC,GACxE,EACF,eAAK,SAAS,EAAC,cAAc,aAC3B,gBACE,SAAS,EAAC,oBAAoB,EAC9B,KAAK,EAAE,KAAK,CAAC,GAAG,IAAI,EAAE,EACtB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAC,+BAA+B,EAC3C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAyB,CAAC,GACxE,EACF,gBACE,SAAS,EAAC,2BAA2B,EACrC,IAAI,EAAC,QAAQ,EACb,GAAG,EAAE,EAAE,EACP,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,EACxB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAC,OAAO,EACnB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAyB,CAAC,gBAErF,uBAAuB,GAClC,IACE,EACL,KAAK,CAAC,GAAG,IAAI;oBACZ,qDAAqD;oBACrD,cAAK,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAC,EAAE,EAAC,SAAS,EAAC,8DAA8D,GAAG,CACxG,IACG,CACP,CAAA;QACH,KAAK,OAAO;YACV,OAAO,CACL,eAAK,SAAS,EAAC,cAAc,aAC3B,gBACE,SAAS,EAAC,oBAAoB,EAC9B,KAAK,EAAE,KAAK,CAAC,IAAI,EACjB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAyB,CAAC,GACzE,EACF,gBACE,SAAS,EAAC,uCAAuC,EACjD,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,EACxB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAC,QAAG,EACf,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS,EAAyB,CAAC,gBAC5E,aAAa,GACxB,IACE,CACP,CAAA;QACH,KAAK,QAAQ;YACX,OAAO,CACL,kBACE,SAAS,EAAC,qCAAqC,EAC/C,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI,EACzB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAA2B,EAAyB,CAAC,gBACpF,aAAa,aAExB,iBAAQ,KAAK,EAAC,IAAI,sBAAe,EACjC,iBAAQ,KAAK,EAAC,IAAI,uBAAgB,EAClC,iBAAQ,KAAK,EAAC,IAAI,sBAAe,IAC1B,CACV,CAAA;QACH,KAAK,SAAS;YACZ,OAAO,cAAK,SAAS,EAAC,0DAA0D,GAAG,CAAA;QACrF,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,CAAC,CAAA;YACpD,OAAO,CACL,YAAG,SAAS,EAAC,mDAAmD,YAC7D,IAAI,EAAE,WAAW,IAAI,mDAAmD,GACvE,CACL,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF,SAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,QAAQ,GAOT;IACC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAA;IAC9G,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC1F,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAErG,OAAO,CACL,eACE,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,EACnE,SAAS,EAAE,mFAAmF,UAAU,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE,EAAE,aAE7I,eAAK,SAAS,EAAC,qFAAqF,aAClG,iBACE,IAAI,EAAC,QAAQ,KACT,UAAU,KACV,SAAS,EACb,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAC,6GAA6G,gBAC3G,WAAW,KAAK,EAAE,YAE9B,KAAC,YAAY,IAAC,SAAS,EAAC,SAAS,GAAG,GAC7B,EACT,gBAAM,SAAS,EAAC,gGAAgG,aAC7G,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,GAAG,EAC5D,KAAK,IACD,EACN,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,CAC3B,eAAM,SAAS,EAAC,mDAAmD,4BAAmB,CACvF,EACD,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAC,uEAAuE,gBACrE,UAAU,KAAK,EAAE,YAE7B,KAAC,MAAM,IAAC,SAAS,EAAC,aAAa,GAAG,GAC3B,IACL,EACN,cAAK,SAAS,EAAC,aAAa,YAC1B,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAI,GAC3E,IACF,CACP,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,SAAS;AACT,gFAAgF;AAEhF,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAqB;IAC9F,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,OAAO,GAAG,UAAU,CACxB,SAAS,CAAC,aAAa,EAAE,EAAE,oBAAoB,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,EACnE,SAAS,CAAC,cAAc,EAAE,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,CAAC,CAC7E,CAAA;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAE5D,MAAM,aAAa,GAAG,CAAC,KAAmB,EAAE,EAAE;QAC5C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;QAC9B,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE;YAAE,OAAM;QAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAA;QACxD,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAA;QACpD,IAAI,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,OAAM;QACpC,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;IACvC,CAAC,CAAA;IAED,MAAM,UAAU,GAAG,CAAC,EAAU,EAAE,KAA0B,EAAE,EAAE,CAC5D,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAE,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,EAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAErF,MAAM,QAAQ,GAAG,CAAC,KAAiB,EAAE,EAAE;QACrC,QAAQ,CAAC,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;QAC5B,UAAU,CAAC,KAAK,CAAC,CAAA;IACnB,CAAC,CAAA;IAED,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACxB,KAAC,UAAU,IAAC,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,YACvF,KAAC,eAAe,IAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,2BAA2B,YAChE,cAAK,SAAS,EAAC,WAAW,YACvB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,KAAC,gBAAgB,IAEf,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,EAC/C,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,IAL5D,KAAK,CAAC,EAAE,CAMb,CACH,CAAC,GACE,GACU,GACP,EAEZ,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CACtB,YAAG,SAAS,EAAC,2IAA2I,+DAEpJ,CACL,EAED,0BACE,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EACpC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAC,6EAA6E,aAEvF,KAAC,IAAI,IAAC,SAAS,EAAC,aAAa,GAAG,kBACzB,EACR,OAAO,IAAI,CACV,eAAK,SAAS,EAAC,0FAA0F,aACvG,YAAG,SAAS,EAAC,wGAAwG,wBAEjH,EACJ,cAAK,SAAS,EAAC,wBAAwB,YACpC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACxB,kBAEE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EACjC,SAAS,EAAC,qGAAqG,aAE/G,eAAM,SAAS,EAAC,2CAA2C,YAAE,CAAC,CAAC,IAAI,GAAQ,EAC1E,CAAC,CAAC,KAAK,KANH,CAAC,CAAC,IAAI,CAOJ,CACV,CAAC,GACE,EACL,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CACnB,8BACE,YAAG,SAAS,EAAC,6GAA6G,qCAEtH,EACJ,cAAK,SAAS,EAAC,wBAAwB,YACpC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAChB,kBAEE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,EACtE,SAAS,EAAC,4FAA4F,aAEtG,KAAC,QAAQ,IAAC,SAAS,EAAC,uEAAuE,GAAG,EAC9F,2BACE,eAAM,SAAS,EAAC,eAAe,YAAE,CAAC,CAAC,KAAK,GAAQ,EAChD,eAAM,SAAS,EAAC,yDAAyD,YAAE,CAAC,CAAC,WAAW,GAAQ,IAC3F,KATF,CAAC,CAAC,GAAG,CAUH,CACV,CAAC,GACE,IACL,CACJ,IACG,CACP,IACG,EAEL,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CACvB,aAAG,SAAS,EAAC,oDAAoD,kDAC7B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAC5E,CACL,IACG,CACP,CAAA;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface EmailPreviewPaneProps {
2
+ subject: string;
3
+ html: string;
4
+ isLoading: boolean;
5
+ width: 'desktop' | 'mobile';
6
+ onWidthChange: (w: 'desktop' | 'mobile') => void;
7
+ /** From-line identity (inbox chrome). */
8
+ fromName: string;
9
+ fromEmail?: string | null;
10
+ /** To-line — the sample recipient. */
11
+ toLine?: string;
12
+ /** Locale selector (multilingual stores only). */
13
+ localeOptions?: string[];
14
+ locale?: string;
15
+ onLocaleChange?: (locale: string) => void;
16
+ }
17
+ export declare function EmailPreviewPane({ subject, html, isLoading, width, onWidthChange, fromName, fromEmail, toLine, localeOptions, locale, onLocaleChange, }: EmailPreviewPaneProps): import("react/jsx-runtime").JSX.Element;
18
+ //# sourceMappingURL=EmailPreviewPane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailPreviewPane.d.ts","sourceRoot":"","sources":["../../../../src/admin/components/emails/EmailPreviewPane.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC3B,aAAa,EAAE,CAAC,CAAC,EAAE,SAAS,GAAG,QAAQ,KAAK,IAAI,CAAA;IAChD,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;CAC1C;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,KAAK,EACL,aAAa,EACb,QAAQ,EACR,SAAS,EACT,MAAyC,EACzC,aAAa,EACb,MAAM,EACN,cAAc,GACf,EAAE,qBAAqB,2CAkIvB"}
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * @rovela/sdk/admin/components/emails/EmailPreviewPane
5
+ *
6
+ * The email preview surface:
7
+ * - inbox-style header (avatar, From/To, live subject) so what the merchant
8
+ * sees reads like the customer's inbox, not a raw HTML dump;
9
+ * - a DOUBLE-BUFFERED iframe pair with an opacity crossfade — updates morph
10
+ * instead of flashing white (srcDoc swaps reload the frame, so the new
11
+ * render loads invisibly in the inactive buffer and fades in on load);
12
+ * - desktop = full pane width (the email's own background owns the canvas
13
+ * edge-to-edge, no banding), mobile = a centered 390px device frame.
14
+ */
15
+ import { useEffect, useRef, useState } from 'react';
16
+ import { Monitor, Smartphone } from 'lucide-react';
17
+ export function EmailPreviewPane({ subject, html, isLoading, width, onWidthChange, fromName, fromEmail, toLine = 'Alex Martin <alex@example.com>', localeOptions, locale, onLocaleChange, }) {
18
+ // Double buffer: new html renders into the INACTIVE iframe; its onLoad
19
+ // flips the crossfade. Rapid updates just overwrite the inactive buffer —
20
+ // the latest-html guard keeps stale loads from flipping early.
21
+ const [buffers, setBuffers] = useState({ a: '', b: '' });
22
+ const [active, setActive] = useState('a');
23
+ const latestHtml = useRef('');
24
+ const activeRef = useRef('a');
25
+ activeRef.current = active;
26
+ // Pattern A — reset internal state on prop change.
27
+ useEffect(() => {
28
+ if (!html || html === latestHtml.current)
29
+ return;
30
+ latestHtml.current = html;
31
+ if (!buffers.a && !buffers.b) {
32
+ // First render: straight into the active buffer, no fade.
33
+ setBuffers((prev) => ({ ...prev, [activeRef.current]: html }));
34
+ return;
35
+ }
36
+ const inactive = activeRef.current === 'a' ? 'b' : 'a';
37
+ setBuffers((prev) => ({ ...prev, [inactive]: html }));
38
+ // eslint-disable-next-line react-hooks/exhaustive-deps
39
+ }, [html]);
40
+ const onFrameLoad = (which) => {
41
+ if (which === activeRef.current)
42
+ return;
43
+ if (buffers[which] !== latestHtml.current)
44
+ return; // stale load
45
+ setActive(which);
46
+ };
47
+ const frame = (which) => (_jsx("iframe", { title: `Email preview ${which}`, srcDoc: buffers[which] || '<p></p>', sandbox: "", onLoad: () => onFrameLoad(which), className: "absolute inset-0 h-full w-full border-0 transition-opacity duration-200", style: { opacity: active === which && buffers[which] ? 1 : 0, pointerEvents: active === which ? 'auto' : 'none' } }, which));
48
+ const initial = (fromName || 'S').trim().charAt(0).toUpperCase();
49
+ const empty = !buffers.a && !buffers.b;
50
+ return (_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("p", { className: "text-xs font-semibold uppercase tracking-wide text-[hsl(var(--admin-foreground-muted))]", children: ["Preview", isLoading && _jsx("span", { className: "ml-2 font-normal normal-case text-[hsl(var(--admin-foreground-subtle))]", children: "updating\u2026" })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [localeOptions && localeOptions.length > 1 && onLocaleChange && (_jsx("select", { className: "admin-input h-8 w-auto py-0 text-xs", value: locale, onChange: (e) => onLocaleChange(e.target.value), "aria-label": "Preview language", children: localeOptions.map((l) => (_jsx("option", { value: l, children: l.toUpperCase() }, l))) })), _jsx("button", { type: "button", onClick: () => onWidthChange('desktop'), className: `inline-flex h-8 w-8 items-center justify-center rounded-md border border-[hsl(var(--admin-border))] ${width === 'desktop' ? 'bg-[hsl(var(--admin-muted))]' : ''}`, "aria-label": "Desktop width", children: _jsx(Monitor, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => onWidthChange('mobile'), className: `inline-flex h-8 w-8 items-center justify-center rounded-md border border-[hsl(var(--admin-border))] ${width === 'mobile' ? 'bg-[hsl(var(--admin-muted))]' : ''}`, "aria-label": "Mobile width", children: _jsx(Smartphone, { className: "h-4 w-4" }) })] })] }), _jsxs("div", { className: "overflow-hidden rounded-xl border border-[hsl(var(--admin-border))]", children: [_jsxs("div", { className: "flex items-start gap-3 border-b border-[hsl(var(--admin-border))] bg-[hsl(var(--admin-card))] px-4 py-3", children: [_jsx("div", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[hsl(var(--admin-primary))] text-sm font-bold text-white", children: initial }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "truncate text-sm font-semibold", children: subject || '—' }), _jsxs("p", { className: "truncate text-xs text-[hsl(var(--admin-foreground-muted))]", children: [fromName, fromEmail ? ` <${fromEmail}>` : '', _jsx("span", { className: "mx-1.5 text-[hsl(var(--admin-foreground-subtle))]", children: "to" }), toLine] })] })] }), width === 'desktop' ? (_jsxs("div", { className: "relative h-[620px]", children: [frame('a'), frame('b'), empty && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-[hsl(var(--admin-foreground-muted))]", children: "Loading preview\u2026" }))] })) : (_jsx("div", { className: "flex justify-center bg-[hsl(var(--admin-muted))] py-6", style: { backgroundImage: 'radial-gradient(hsl(var(--admin-border)) 1px, transparent 1px)', backgroundSize: '16px 16px' }, children: _jsxs("div", { className: "relative h-[620px] w-[390px] overflow-hidden rounded-[20px] border-4 border-[hsl(var(--admin-foreground))]/80 shadow-xl", children: [frame('a'), frame('b'), empty && (_jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-[hsl(var(--admin-card))] text-sm text-[hsl(var(--admin-foreground-muted))]", children: "Loading preview\u2026" }))] }) }))] })] }));
51
+ }
52
+ //# sourceMappingURL=EmailPreviewPane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailPreviewPane.js","sourceRoot":"","sources":["../../../../src/admin/components/emails/EmailPreviewPane.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export interface ThemeDraft {
2
+ primaryColor?: string;
3
+ backgroundColor?: string;
4
+ cardColor?: string;
5
+ textColor?: string;
6
+ headingFont?: string;
7
+ bodyFont?: string;
8
+ fontName?: string;
9
+ buttonRadius?: 'sm' | 'md' | 'full';
10
+ cardRadius?: 'sm' | 'md' | 'lg';
11
+ logoSize?: 'sm' | 'md' | 'lg';
12
+ logoAlign?: 'left' | 'center';
13
+ footerNote?: string;
14
+ }
15
+ export interface EmailThemePanelProps {
16
+ draft: ThemeDraft;
17
+ derived: ThemeDraft;
18
+ palette: string[];
19
+ suggestedFonts: string[];
20
+ onChange: (patch: Partial<ThemeDraft>) => void;
21
+ onSave: () => void;
22
+ onReset: () => void;
23
+ isSaving: boolean;
24
+ saveFlash: string | null;
25
+ }
26
+ export declare function EmailThemePanel({ draft, derived, palette, suggestedFonts, onChange, onSave, onReset, isSaving, saveFlash, }: EmailThemePanelProps): import("react/jsx-runtime").JSX.Element;
27
+ //# sourceMappingURL=EmailThemePanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailThemePanel.d.ts","sourceRoot":"","sources":["../../../../src/admin/components/emails/EmailThemePanel.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAA;IACnC,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,UAAU,CAAA;IACjB,OAAO,EAAE,UAAU,CAAA;IACnB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;IAC9C,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAgDD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,EACP,OAAO,EACP,cAAc,EACd,QAAQ,EACR,MAAM,EACN,OAAO,EACP,QAAQ,EACR,SAAS,GACV,EAAE,oBAAoB,2CAsKtB"}
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * @rovela/sdk/admin/components/emails/EmailThemePanel
5
+ *
6
+ * The shared email theme controls — one edit restyles every email at once.
7
+ * Four groups: Colors (with one-click brand swatches), Typography (heading +
8
+ * body, full Google Fonts search), Shape (button + card corners, logo), and
9
+ * Footer. Everything defaults to the store's brand; Reset returns to that.
10
+ */
11
+ import { RotateCcw, Check } from 'lucide-react';
12
+ import { FontPicker } from './FontPicker';
13
+ function ColorField({ label, hint, value, fallback, onChange, }) {
14
+ return (_jsxs("div", { children: [_jsx("label", { className: "admin-label", children: label }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "color", value: value ?? fallback, onChange: (e) => onChange(e.target.value), className: "h-10 w-12 cursor-pointer rounded-md border border-[hsl(var(--admin-border))] bg-transparent p-1", "aria-label": label }), _jsx("input", { className: "admin-input w-full", value: value ?? '', onChange: (e) => onChange(e.target.value), placeholder: fallback, maxLength: 7 })] }), hint && _jsx("p", { className: "mt-1 text-xs text-[hsl(var(--admin-foreground-subtle))]", children: hint })] }));
15
+ }
16
+ function Group({ title, children }) {
17
+ return (_jsxs("div", { className: "space-y-3 rounded-lg border border-[hsl(var(--admin-border))] p-3", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-[hsl(var(--admin-foreground-muted))]", children: title }), children] }));
18
+ }
19
+ export function EmailThemePanel({ draft, derived, palette, suggestedFonts, onChange, onSave, onReset, isSaving, saveFlash, }) {
20
+ const effective = { ...derived, ...draft };
21
+ const effectiveBody = effective.bodyFont ?? effective.fontName ?? 'Plus Jakarta Sans';
22
+ const effectiveHeading = effective.headingFont ?? effectiveBody;
23
+ return (_jsxs("div", { className: "w-full max-w-sm space-y-4", children: [_jsxs(Group, { title: "Colors", children: [palette.length > 0 && (_jsxs("div", { children: [_jsx("p", { className: "mb-1.5 text-xs text-[hsl(var(--admin-foreground-muted))]", children: "Your brand colors \u2014 click to use as the accent:" }), _jsx("div", { className: "flex flex-wrap gap-1.5", children: palette.map((hex) => (_jsx("button", { type: "button", title: hex, onClick: () => onChange({ primaryColor: hex }), className: `h-7 w-7 rounded-full border ${effective.primaryColor === hex ? 'ring-2 ring-[hsl(var(--admin-primary))] ring-offset-1' : 'border-[hsl(var(--admin-border))]'}`, style: { backgroundColor: hex }, "aria-label": `Use ${hex} as the accent color` }, hex))) })] })), _jsx(ColorField, { label: "Accent", hint: "Buttons, links, badges and highlights.", value: effective.primaryColor, fallback: "#0CAF7D", onChange: (hex) => onChange({ primaryColor: hex }) }), _jsx(ColorField, { label: "Background", hint: "Behind the email card.", value: effective.backgroundColor, fallback: "#F7F7F7", onChange: (hex) => onChange({ backgroundColor: hex }) }), _jsx(ColorField, { label: "Card", hint: "The email surface itself.", value: effective.cardColor, fallback: "#FFFFFF", onChange: (hex) => onChange({ cardColor: hex }) }), _jsx(ColorField, { label: "Headings", hint: "Headline and strong text.", value: effective.textColor, fallback: "#0A0A0A", onChange: (hex) => onChange({ textColor: hex }) })] }), _jsxs(Group, { title: "Typography", children: [_jsx(FontPicker, { label: "Heading font", value: effectiveHeading, suggested: suggestedFonts, derivedHint: derived.headingFont ? `From your brand: ${derived.headingFont}` : undefined, onChange: (font) => onChange({ headingFont: font }) }), _jsx(FontPicker, { label: "Body font", value: effectiveBody, suggested: suggestedFonts, derivedHint: derived.bodyFont ? `From your brand: ${derived.bodyFont}` : undefined, onChange: (font) => onChange({ bodyFont: font }) })] }), _jsxs(Group, { title: "Shape", children: [_jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Button corners" }), _jsxs("select", { className: "admin-input w-full", value: effective.buttonRadius ?? 'md', onChange: (e) => onChange({ buttonRadius: e.target.value }), children: [_jsx("option", { value: "sm", children: "Subtle" }), _jsx("option", { value: "md", children: "Rounded" }), _jsx("option", { value: "full", children: "Pill" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Card corners" }), _jsxs("select", { className: "admin-input w-full", value: effective.cardRadius ?? 'lg', onChange: (e) => onChange({ cardRadius: e.target.value }), children: [_jsx("option", { value: "sm", children: "Subtle" }), _jsx("option", { value: "md", children: "Soft" }), _jsx("option", { value: "lg", children: "Round" })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Logo size" }), _jsxs("select", { className: "admin-input w-full", value: effective.logoSize ?? 'md', onChange: (e) => onChange({ logoSize: e.target.value }), children: [_jsx("option", { value: "sm", children: "Small" }), _jsx("option", { value: "md", children: "Medium" }), _jsx("option", { value: "lg", children: "Large" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Logo position" }), _jsxs("select", { className: "admin-input w-full", value: effective.logoAlign ?? 'center', onChange: (e) => onChange({ logoAlign: e.target.value }), children: [_jsx("option", { value: "center", children: "Centered" }), _jsx("option", { value: "left", children: "Left" })] })] })] })] }), _jsx(Group, { title: "Footer", children: _jsxs("div", { children: [_jsx("label", { className: "admin-label", children: "Footer note (optional)" }), _jsx("textarea", { className: "admin-input w-full", rows: 3, value: effective.footerNote ?? '', onChange: (e) => onChange({ footerNote: e.target.value }), placeholder: "A legal line or tagline shown at the bottom of every email", maxLength: 300 })] }) }), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx("button", { type: "button", onClick: onSave, disabled: isSaving, className: "admin-btn admin-btn-primary admin-btn-sm disabled:opacity-50", children: isSaving ? 'Saving…' : 'Save theme' }), _jsxs("button", { type: "button", onClick: onReset, disabled: isSaving, className: "admin-btn admin-btn-secondary admin-btn-sm inline-flex items-center gap-1 disabled:opacity-50", children: [_jsx(RotateCcw, { className: "h-3.5 w-3.5" }), " Reset to brand"] }), saveFlash && (_jsxs("span", { className: "inline-flex items-center gap-1 text-sm text-[hsl(var(--admin-success,142_71%_45%))]", children: [_jsx(Check, { className: "h-4 w-4" }), " ", saveFlash] }))] })] }));
24
+ }
25
+ //# sourceMappingURL=EmailThemePanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailThemePanel.js","sourceRoot":"","sources":["../../../../src/admin/components/emails/EmailThemePanel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface FontPickerProps {
2
+ label: string;
3
+ value: string;
4
+ suggested: string[];
5
+ /** Shown as a hint under the field ("From your brand: Inter"). */
6
+ derivedHint?: string;
7
+ onChange: (font: string) => void;
8
+ disabled?: boolean;
9
+ }
10
+ export declare function FontPicker({ label, value, suggested, derivedHint, onChange, disabled }: FontPickerProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=FontPicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontPicker.d.ts","sourceRoot":"","sources":["../../../../src/admin/components/emails/FontPicker.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAID,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,eAAe,2CAmGvG"}
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * @rovela/sdk/admin/components/emails/FontPicker
5
+ *
6
+ * Searchable font combobox over the FULL Google Fonts catalog (~1,900
7
+ * fonts). Suggested (email-tested) fonts surface first; typing filters the
8
+ * whole catalog. Pure client component — the catalog ships with the admin
9
+ * chunk, no per-keystroke network.
10
+ */
11
+ import { useEffect, useMemo, useRef, useState } from 'react';
12
+ import { ChevronDown, Check } from 'lucide-react';
13
+ import { GOOGLE_FONT_NAMES } from '../../../emails/google-fonts';
14
+ const MAX_RESULTS = 12;
15
+ export function FontPicker({ label, value, suggested, derivedHint, onChange, disabled }) {
16
+ const [open, setOpen] = useState(false);
17
+ const [query, setQuery] = useState('');
18
+ const rootRef = useRef(null);
19
+ const results = useMemo(() => {
20
+ const q = query.trim().toLowerCase();
21
+ if (!q) {
22
+ const rest = GOOGLE_FONT_NAMES.filter((f) => !suggested.includes(f)).slice(0, MAX_RESULTS - suggested.length);
23
+ return { suggested, others: rest };
24
+ }
25
+ const matches = GOOGLE_FONT_NAMES.filter((f) => f.toLowerCase().includes(q)).slice(0, MAX_RESULTS);
26
+ return { suggested: [], others: matches };
27
+ }, [query, suggested]);
28
+ // Close on outside click.
29
+ useEffect(() => {
30
+ if (!open)
31
+ return;
32
+ const onDown = (e) => {
33
+ if (rootRef.current && !rootRef.current.contains(e.target))
34
+ setOpen(false);
35
+ };
36
+ document.addEventListener('mousedown', onDown);
37
+ return () => document.removeEventListener('mousedown', onDown);
38
+ }, [open]);
39
+ const pick = (font) => {
40
+ onChange(font);
41
+ setQuery('');
42
+ setOpen(false);
43
+ };
44
+ const row = (font) => (_jsxs("button", { type: "button", onClick: () => pick(font), className: "flex w-full items-center justify-between px-3 py-1.5 text-left text-sm hover:bg-[hsl(var(--admin-muted))]", children: [_jsx("span", { className: "truncate", children: font }), font === value && _jsx(Check, { className: "h-3.5 w-3.5 shrink-0 text-[hsl(var(--admin-primary))]" })] }, font));
45
+ return (_jsxs("div", { ref: rootRef, className: "relative", children: [_jsx("label", { className: "admin-label", children: label }), _jsxs("button", { type: "button", disabled: disabled, onClick: () => setOpen((o) => !o), className: "admin-input flex w-full items-center justify-between gap-2 text-left disabled:opacity-50", children: [_jsx("span", { className: "truncate", children: value || 'Choose a font' }), _jsx(ChevronDown, { className: "h-4 w-4 shrink-0 text-[hsl(var(--admin-foreground-muted))]" })] }), derivedHint && (_jsx("p", { className: "mt-1 text-xs text-[hsl(var(--admin-foreground-subtle))]", children: derivedHint })), open && (_jsxs("div", { className: "absolute left-0 right-0 top-full z-20 mt-1 overflow-hidden rounded-lg border border-[hsl(var(--admin-border))] bg-[hsl(var(--admin-card))] shadow-lg", children: [_jsx("div", { className: "border-b border-[hsl(var(--admin-border))] p-2", children: _jsx("input", { autoFocus: true, className: "admin-input h-8 w-full text-sm", placeholder: `Search ${GOOGLE_FONT_NAMES.length.toLocaleString()} Google Fonts…`, value: query, onChange: (e) => setQuery(e.target.value), onKeyDown: (e) => {
46
+ if (e.key === 'Escape')
47
+ setOpen(false);
48
+ if (e.key === 'Enter') {
49
+ const first = results.suggested[0] ?? results.others[0];
50
+ if (first)
51
+ pick(first);
52
+ }
53
+ } }) }), _jsxs("div", { className: "max-h-64 overflow-y-auto py-1", children: [results.suggested.length > 0 && (_jsxs(_Fragment, { children: [_jsx("p", { className: "px-3 py-1 text-[10px] font-semibold uppercase tracking-wide text-[hsl(var(--admin-foreground-subtle))]", children: "Suggested for email" }), results.suggested.map(row), results.others.length > 0 && (_jsx("p", { className: "px-3 py-1 text-[10px] font-semibold uppercase tracking-wide text-[hsl(var(--admin-foreground-subtle))]", children: "All fonts" }))] })), results.others.map(row), results.suggested.length === 0 && results.others.length === 0 && (_jsx("p", { className: "px-3 py-2 text-sm text-[hsl(var(--admin-foreground-muted))]", children: "No font matches." }))] })] }))] }));
54
+ }
55
+ //# sourceMappingURL=FontPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontPicker.js","sourceRoot":"","sources":["../../../../src/admin/components/emails/FontPicker.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface TextBlockEditorProps {
2
+ value: string;
3
+ onChange: (html: string) => void;
4
+ disabled?: boolean;
5
+ }
6
+ export default function TextBlockEditor({ value, onChange, disabled }: TextBlockEditorProps): import("react/jsx-runtime").JSX.Element;
7
+ //# sourceMappingURL=TextBlockEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextBlockEditor.d.ts","sourceRoot":"","sources":["../../../../src/admin/components/emails/TextBlockEditor.tsx"],"names":[],"mappings":"AAiBA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,oBAAoB,2CAkF1F"}
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * @rovela/sdk/admin/components/emails/TextBlockEditor
5
+ *
6
+ * Minimal rich-text editing for email text blocks — TipTap with exactly the
7
+ * marks the email sanitizer allows (bold, italic, links, lists). Loaded via
8
+ * React.lazy from BlocksEditor so the TipTap bundle only ships when a
9
+ * merchant actually opens the block editor. Default export for React.lazy.
10
+ */
11
+ import { useEffect } from 'react';
12
+ import { useEditor, EditorContent } from '@tiptap/react';
13
+ import StarterKit from '@tiptap/starter-kit';
14
+ import Link from '@tiptap/extension-link';
15
+ import { Bold, Italic, Link as LinkIcon, List, ListOrdered } from 'lucide-react';
16
+ export default function TextBlockEditor({ value, onChange, disabled }) {
17
+ const editor = useEditor({
18
+ immediatelyRender: false,
19
+ editable: !disabled,
20
+ extensions: [
21
+ StarterKit.configure({
22
+ heading: false,
23
+ blockquote: false,
24
+ codeBlock: false,
25
+ code: false,
26
+ horizontalRule: false,
27
+ }),
28
+ Link.configure({ openOnClick: false, autolink: true }),
29
+ ],
30
+ content: value,
31
+ onUpdate: ({ editor: e }) => onChange(e.getHTML()),
32
+ editorProps: {
33
+ attributes: {
34
+ class: 'rv-email-text-editor min-h-[72px] px-3 py-2 text-sm leading-relaxed focus:outline-none',
35
+ },
36
+ },
37
+ });
38
+ // Pattern A — reset editor content when the outside value changes (block
39
+ // switch / locale tab switch), without clobbering in-progress typing.
40
+ useEffect(() => {
41
+ if (!editor)
42
+ return;
43
+ if (editor.getHTML() !== value && !editor.isFocused) {
44
+ editor.commands.setContent(value, { emitUpdate: false });
45
+ }
46
+ }, [editor, value]);
47
+ if (!editor)
48
+ return _jsx("div", { className: "h-[104px] animate-pulse rounded-md bg-[hsl(var(--admin-muted))]" });
49
+ const setLink = () => {
50
+ const prev = editor.getAttributes('link').href;
51
+ const url = window.prompt('Link address (https://… or {{shopUrl}})', prev ?? 'https://');
52
+ if (url === null)
53
+ return;
54
+ if (url === '') {
55
+ editor.chain().focus().unsetLink().run();
56
+ return;
57
+ }
58
+ editor.chain().focus().setLink({ href: url }).run();
59
+ };
60
+ const toolBtn = (activeCheck, onClick, icon, label) => (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, "aria-label": label, className: `inline-flex h-7 w-7 items-center justify-center rounded ${activeCheck ? 'bg-[hsl(var(--admin-muted))] text-[hsl(var(--admin-primary))]' : 'text-[hsl(var(--admin-foreground-muted))] hover:bg-[hsl(var(--admin-muted))]'}`, children: icon }));
61
+ return (_jsxs("div", { className: "rounded-md border border-[hsl(var(--admin-border))] bg-[hsl(var(--admin-card))]", children: [_jsxs("div", { className: "flex items-center gap-0.5 border-b border-[hsl(var(--admin-border))] px-1.5 py-1", children: [toolBtn(editor.isActive('bold'), () => editor.chain().focus().toggleBold().run(), _jsx(Bold, { className: "h-3.5 w-3.5" }), 'Bold'), toolBtn(editor.isActive('italic'), () => editor.chain().focus().toggleItalic().run(), _jsx(Italic, { className: "h-3.5 w-3.5" }), 'Italic'), toolBtn(editor.isActive('link'), setLink, _jsx(LinkIcon, { className: "h-3.5 w-3.5" }), 'Link'), toolBtn(editor.isActive('bulletList'), () => editor.chain().focus().toggleBulletList().run(), _jsx(List, { className: "h-3.5 w-3.5" }), 'Bullet list'), toolBtn(editor.isActive('orderedList'), () => editor.chain().focus().toggleOrderedList().run(), _jsx(ListOrdered, { className: "h-3.5 w-3.5" }), 'Numbered list')] }), _jsx(EditorContent, { editor: editor }), _jsx("style", { children: `
62
+ .rv-email-text-editor p { margin: 0 0 8px 0; }
63
+ .rv-email-text-editor p:last-child { margin-bottom: 0; }
64
+ .rv-email-text-editor a { color: hsl(var(--admin-primary)); text-decoration: underline; }
65
+ .rv-email-text-editor ul, .rv-email-text-editor ol { margin: 0 0 8px 0; padding-left: 20px; }
66
+ .rv-email-text-editor ul { list-style: disc; }
67
+ .rv-email-text-editor ol { list-style: decimal; }
68
+ ` })] }));
69
+ }
70
+ //# sourceMappingURL=TextBlockEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextBlockEditor.js","sourceRoot":"","sources":["../../../../src/admin/components/emails/TextBlockEditor.tsx"],"names":[],"mappings":"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"}