@caffeinebounce/ui 0.62.2

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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/FinancialStatementTable-BNUrdTU4.d.cts +249 -0
  4. package/dist/FinancialStatementTable-BNUrdTU4.d.ts +249 -0
  5. package/dist/NewsletterSignup-BPreFi5W.d.cts +37 -0
  6. package/dist/NewsletterSignup-BPreFi5W.d.ts +37 -0
  7. package/dist/TestimonialsSection-DtPu2OeR.d.ts +736 -0
  8. package/dist/TestimonialsSection-z-yotRfv.d.cts +736 -0
  9. package/dist/UnifiedTableControls-CG299y9h.d.ts +1233 -0
  10. package/dist/UnifiedTableControls-CIjRpNhy.d.cts +1233 -0
  11. package/dist/blog.d.cts +99 -0
  12. package/dist/blog.d.ts +99 -0
  13. package/dist/blog.js +292 -0
  14. package/dist/blog.mjs +279 -0
  15. package/dist/button-BHnoRUkF.d.cts +34 -0
  16. package/dist/button-BHnoRUkF.d.ts +34 -0
  17. package/dist/charts.d.cts +80 -0
  18. package/dist/charts.d.ts +80 -0
  19. package/dist/charts.js +19 -0
  20. package/dist/charts.mjs +2 -0
  21. package/dist/chunk-33JR5SYE.js +44 -0
  22. package/dist/chunk-3NDB4YPC.js +247 -0
  23. package/dist/chunk-5RW4PYZ6.js +1504 -0
  24. package/dist/chunk-5THF4YP6.mjs +155 -0
  25. package/dist/chunk-6BUBNZPG.mjs +164 -0
  26. package/dist/chunk-6DVWMJ3H.mjs +7029 -0
  27. package/dist/chunk-6TGV2DNP.js +120 -0
  28. package/dist/chunk-72JGQ7IJ.mjs +1498 -0
  29. package/dist/chunk-7DHKQODW.mjs +2932 -0
  30. package/dist/chunk-7IKHZKAC.js +160 -0
  31. package/dist/chunk-ADIDI7AJ.js +11 -0
  32. package/dist/chunk-BFWX5GJZ.mjs +940 -0
  33. package/dist/chunk-BMFQG6RA.mjs +5537 -0
  34. package/dist/chunk-C4UT5V3P.js +65 -0
  35. package/dist/chunk-CC4KUIKC.js +2004 -0
  36. package/dist/chunk-D3QXPL47.mjs +1814 -0
  37. package/dist/chunk-DQWHYBV2.js +36 -0
  38. package/dist/chunk-E42B4GSB.js +993 -0
  39. package/dist/chunk-ESZ7CBA2.js +1007 -0
  40. package/dist/chunk-EYJJQVV4.js +111 -0
  41. package/dist/chunk-FRRS2YZH.mjs +129 -0
  42. package/dist/chunk-G5TQWWQA.mjs +37 -0
  43. package/dist/chunk-GAIQJCAZ.js +5612 -0
  44. package/dist/chunk-GMBGWOCR.mjs +48 -0
  45. package/dist/chunk-GUSTCU2W.mjs +105 -0
  46. package/dist/chunk-HBLKVQIQ.mjs +23 -0
  47. package/dist/chunk-HMAMMC72.js +26 -0
  48. package/dist/chunk-IMKLN273.mjs +9 -0
  49. package/dist/chunk-J6OLBSZR.js +250 -0
  50. package/dist/chunk-JAE45W2T.js +28 -0
  51. package/dist/chunk-JORVSG52.js +606 -0
  52. package/dist/chunk-KB7UXIQZ.mjs +984 -0
  53. package/dist/chunk-KGGQ5NZV.js +186 -0
  54. package/dist/chunk-KHCC5UKW.mjs +22 -0
  55. package/dist/chunk-KRRIRS6A.mjs +1945 -0
  56. package/dist/chunk-LQCVRWVF.js +48 -0
  57. package/dist/chunk-MHZXUOGN.mjs +168 -0
  58. package/dist/chunk-MPZFPU4X.js +349 -0
  59. package/dist/chunk-MVYRNJA6.js +74 -0
  60. package/dist/chunk-N6AFNFZR.mjs +565 -0
  61. package/dist/chunk-OFQLWSUR.mjs +214 -0
  62. package/dist/chunk-OLAAXLXY.mjs +219 -0
  63. package/dist/chunk-OZZWDIOY.js +1859 -0
  64. package/dist/chunk-PZRI43EZ.js +111 -0
  65. package/dist/chunk-Q256HRYD.js +176 -0
  66. package/dist/chunk-Q52ZEL62.mjs +223 -0
  67. package/dist/chunk-R26Y7LGJ.js +142 -0
  68. package/dist/chunk-RBUYW6QQ.js +39 -0
  69. package/dist/chunk-RVEFPVZF.mjs +43 -0
  70. package/dist/chunk-SORWLKOK.js +96 -0
  71. package/dist/chunk-STEP6C4C.mjs +33 -0
  72. package/dist/chunk-T5R6HUDG.mjs +22 -0
  73. package/dist/chunk-T6ZBA6VJ.js +7109 -0
  74. package/dist/chunk-UM7WMXIU.js +2995 -0
  75. package/dist/chunk-VBD4Q5LL.mjs +117 -0
  76. package/dist/chunk-WOITB4JL.js +195 -0
  77. package/dist/chunk-YKZEKJMZ.mjs +71 -0
  78. package/dist/chunk-YL7RZRHM.mjs +103 -0
  79. package/dist/chunk-YSLD2HLP.mjs +346 -0
  80. package/dist/chunk-ZFLZA7UP.mjs +140 -0
  81. package/dist/chunk-ZKUIUE7W.mjs +26 -0
  82. package/dist/chunk-ZOA7B32D.js +248 -0
  83. package/dist/data-table.d.cts +46 -0
  84. package/dist/data-table.d.ts +46 -0
  85. package/dist/data-table.js +270 -0
  86. package/dist/data-table.mjs +13 -0
  87. package/dist/editor.d.cts +89 -0
  88. package/dist/editor.d.ts +89 -0
  89. package/dist/editor.js +10 -0
  90. package/dist/editor.mjs +1 -0
  91. package/dist/forms.d.cts +142 -0
  92. package/dist/forms.d.ts +142 -0
  93. package/dist/forms.js +24 -0
  94. package/dist/forms.mjs +11 -0
  95. package/dist/hooks-8ORd7T1A.d.cts +751 -0
  96. package/dist/hooks-B2jU1GVT.d.ts +751 -0
  97. package/dist/hooks.d.cts +6 -0
  98. package/dist/hooks.d.ts +6 -0
  99. package/dist/hooks.js +99 -0
  100. package/dist/hooks.mjs +10 -0
  101. package/dist/index.d.cts +3141 -0
  102. package/dist/index.d.ts +3141 -0
  103. package/dist/index.js +7332 -0
  104. package/dist/index.mjs +5876 -0
  105. package/dist/layouts-DPfDDF53.d.cts +1001 -0
  106. package/dist/layouts-DPfDDF53.d.ts +1001 -0
  107. package/dist/layouts.d.cts +4 -0
  108. package/dist/layouts.d.ts +4 -0
  109. package/dist/layouts.js +100 -0
  110. package/dist/layouts.mjs +11 -0
  111. package/dist/marketing-3d.d.cts +51 -0
  112. package/dist/marketing-3d.d.ts +51 -0
  113. package/dist/marketing-3d.js +553 -0
  114. package/dist/marketing-3d.mjs +526 -0
  115. package/dist/marketing.d.cts +583 -0
  116. package/dist/marketing.d.ts +583 -0
  117. package/dist/marketing.js +299 -0
  118. package/dist/marketing.mjs +10 -0
  119. package/dist/media.d.cts +29 -0
  120. package/dist/media.d.ts +29 -0
  121. package/dist/media.js +189 -0
  122. package/dist/media.mjs +182 -0
  123. package/dist/navigation.d.cts +591 -0
  124. package/dist/navigation.d.ts +591 -0
  125. package/dist/navigation.js +108 -0
  126. package/dist/navigation.mjs +15 -0
  127. package/dist/portal.d.cts +58 -0
  128. package/dist/portal.d.ts +58 -0
  129. package/dist/portal.js +403 -0
  130. package/dist/portal.mjs +395 -0
  131. package/dist/primitives.d.cts +508 -0
  132. package/dist/primitives.d.ts +508 -0
  133. package/dist/primitives.js +295 -0
  134. package/dist/primitives.mjs +14 -0
  135. package/dist/settings.d.cts +216 -0
  136. package/dist/settings.d.ts +216 -0
  137. package/dist/settings.js +34 -0
  138. package/dist/settings.mjs +9 -0
  139. package/dist/shared-Dqn36QHZ.d.cts +4 -0
  140. package/dist/shared-Dqn36QHZ.d.ts +4 -0
  141. package/dist/styles.css +1213 -0
  142. package/package.json +189 -0
  143. package/styles.css +1 -0
@@ -0,0 +1,1498 @@
1
+ import StudioEditorSDK from '@grapesjs/studio-sdk/react';
2
+ import '@grapesjs/studio-sdk/style';
3
+ import { useRef, useEffect, useMemo, useCallback } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ // src/blocks/editor/StudioEditor.tsx
7
+ var EMAIL_CONTENT_MAX_WIDTH = 600;
8
+ var emailBlocks = [
9
+ {
10
+ id: "email-header",
11
+ label: "Header with Logo",
12
+ category: "Email",
13
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="2" y="4" width="20" height="6" rx="1" stroke="currentColor" fill="none" stroke-width="2"/><circle cx="7" cy="7" r="2" stroke="currentColor" fill="none" stroke-width="2"/><line x1="11" y1="7" x2="20" y2="7" stroke="currentColor" stroke-width="2"/></svg>`,
14
+ content: `
15
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background: linear-gradient(135deg, #1e293b 0%, #334155 100%);">
16
+ <tr>
17
+ <td align="center" style="padding: 32px 24px;">
18
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width: ${EMAIL_CONTENT_MAX_WIDTH}px;">
19
+ <tr>
20
+ <td align="left" style="padding-bottom: 8px;">
21
+ <span style="font-size: 24px; font-weight: 700; color: #ffffff; letter-spacing: -0.5px;">Your Company</span>
22
+ <span style="font-size: 24px; font-weight: 400; color: #94a3b8; letter-spacing: -0.5px;"> Name Here</span>
23
+ </td>
24
+ </tr>
25
+ <tr>
26
+ <td align="left">
27
+ <span style="font-size: 14px; color: #94a3b8;">Add your email header tagline here</span>
28
+ </td>
29
+ </tr>
30
+ </table>
31
+ </td>
32
+ </tr>
33
+ </table>
34
+ `
35
+ },
36
+ {
37
+ id: "email-hero",
38
+ label: "Hero Section",
39
+ category: "Email",
40
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="2" y="3" width="20" height="18" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><line x1="6" y1="8" x2="18" y2="8" stroke="currentColor" stroke-width="2"/><line x1="6" y1="12" x2="14" y2="12" stroke="currentColor" stroke-width="2"/></svg>`,
41
+ content: `
42
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color: #ffffff;">
43
+ <tr>
44
+ <td align="center" style="padding: 48px 24px;">
45
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width: ${EMAIL_CONTENT_MAX_WIDTH}px;">
46
+ <tr>
47
+ <td align="center" style="padding-bottom: 24px;">
48
+ <h1 style="margin: 0; font-size: 32px; font-weight: 700; color: #111827; line-height: 1.2;">Your Headline Here</h1>
49
+ </td>
50
+ </tr>
51
+ <tr>
52
+ <td align="center" style="padding-bottom: 32px;">
53
+ <p style="margin: 0; font-size: 18px; color: #6b7280; line-height: 1.6;">Write a compelling introduction that captures your reader's attention and sets the stage for your message.</p>
54
+ </td>
55
+ </tr>
56
+ <tr>
57
+ <td align="center">
58
+ <a href="#" style="display: inline-block; padding: 14px 32px; background-color: #3b82f6; color: #ffffff; text-decoration: none; border-radius: 8px; font-size: 16px; font-weight: 600;">Get Started</a>
59
+ </td>
60
+ </tr>
61
+ </table>
62
+ </td>
63
+ </tr>
64
+ </table>
65
+ `
66
+ },
67
+ {
68
+ id: "email-text",
69
+ label: "Text Block",
70
+ category: "Email",
71
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><line x1="3" y1="6" x2="21" y2="6" stroke="currentColor" stroke-width="2"/><line x1="3" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="2"/><line x1="3" y1="18" x2="15" y2="18" stroke="currentColor" stroke-width="2"/></svg>`,
72
+ content: `
73
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color: #ffffff;">
74
+ <tr>
75
+ <td align="center" style="padding: 24px;">
76
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width: ${EMAIL_CONTENT_MAX_WIDTH}px;">
77
+ <tr>
78
+ <td style="color: #374151; font-size: 16px; line-height: 1.6;">
79
+ <p style="margin: 0 0 16px 0;">This is a paragraph of text. You can edit this content to say whatever you need. Keep your paragraphs short and focused for better readability in email clients.</p>
80
+ <p style="margin: 0;">Add multiple paragraphs as needed to communicate your message effectively.</p>
81
+ </td>
82
+ </tr>
83
+ </table>
84
+ </td>
85
+ </tr>
86
+ </table>
87
+ `
88
+ },
89
+ {
90
+ id: "email-button",
91
+ label: "Button",
92
+ category: "Email",
93
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="7" width="18" height="10" rx="5" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
94
+ content: `
95
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0">
96
+ <tr>
97
+ <td align="center" style="padding: 24px;">
98
+ <a href="#" style="display: inline-block; padding: 14px 32px; background-color: #3b82f6; color: #ffffff; text-decoration: none; border-radius: 8px; font-size: 16px; font-weight: 600;">Call to Action</a>
99
+ </td>
100
+ </tr>
101
+ </table>
102
+ `
103
+ },
104
+ {
105
+ id: "email-image",
106
+ label: "Image",
107
+ category: "Email",
108
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><circle cx="8.5" cy="8.5" r="1.5" fill="currentColor"/><path d="M21 15l-5-5L5 21" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
109
+ content: `
110
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0">
111
+ <tr>
112
+ <td align="center" style="padding: 24px;">
113
+ <img src="https://placehold.co/600x300/e5e7eb/6b7280?text=Your+Image" alt="Image description" width="100%" style="max-width: ${EMAIL_CONTENT_MAX_WIDTH}px; height: auto; display: block;" />
114
+ </td>
115
+ </tr>
116
+ </table>
117
+ `
118
+ },
119
+ {
120
+ id: "email-divider",
121
+ label: "Divider",
122
+ category: "Email",
123
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><line x1="3" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="2"/></svg>`,
124
+ content: `
125
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0">
126
+ <tr>
127
+ <td align="center" style="padding: 16px 24px;">
128
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width: ${EMAIL_CONTENT_MAX_WIDTH}px;">
129
+ <tr>
130
+ <td style="border-bottom: 1px solid #e5e7eb;"></td>
131
+ </tr>
132
+ </table>
133
+ </td>
134
+ </tr>
135
+ </table>
136
+ `
137
+ },
138
+ {
139
+ id: "email-spacer",
140
+ label: "Spacer",
141
+ category: "Email",
142
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><line x1="12" y1="5" x2="12" y2="19" stroke="currentColor" stroke-width="2" stroke-dasharray="2,2"/></svg>`,
143
+ content: `
144
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0">
145
+ <tr>
146
+ <td style="height: 32px; line-height: 32px; font-size: 1px;">&nbsp;</td>
147
+ </tr>
148
+ </table>
149
+ `
150
+ },
151
+ {
152
+ id: "email-two-columns",
153
+ label: "Two Columns",
154
+ category: "Email",
155
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="2" y="3" width="8" height="18" rx="1" stroke="currentColor" fill="none" stroke-width="2"/><rect x="14" y="3" width="8" height="18" rx="1" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
156
+ content: `
157
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color: #ffffff;">
158
+ <tr>
159
+ <td align="center" style="padding: 24px;">
160
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width: ${EMAIL_CONTENT_MAX_WIDTH}px;">
161
+ <tr>
162
+ <td width="48%" valign="top" style="padding-right: 12px;">
163
+ <h3 style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: #111827;">Column One</h3>
164
+ <p style="margin: 0; font-size: 14px; color: #6b7280; line-height: 1.5;">Add your content here. This column takes up about half the width.</p>
165
+ </td>
166
+ <td width="4%"></td>
167
+ <td width="48%" valign="top" style="padding-left: 12px;">
168
+ <h3 style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: #111827;">Column Two</h3>
169
+ <p style="margin: 0; font-size: 14px; color: #6b7280; line-height: 1.5;">Add your content here. This column takes up about half the width.</p>
170
+ </td>
171
+ </tr>
172
+ </table>
173
+ </td>
174
+ </tr>
175
+ </table>
176
+ `
177
+ },
178
+ {
179
+ id: "email-feature-card",
180
+ label: "Feature Card",
181
+ category: "Email",
182
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><circle cx="12" cy="9" r="3" stroke="currentColor" fill="none" stroke-width="2"/><line x1="7" y1="15" x2="17" y2="15" stroke="currentColor" stroke-width="2"/><line x1="9" y1="18" x2="15" y2="18" stroke="currentColor" stroke-width="2"/></svg>`,
183
+ content: `
184
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color: #ffffff;">
185
+ <tr>
186
+ <td align="center" style="padding: 24px;">
187
+ <table role="presentation" cellpadding="0" cellspacing="0" style="max-width: 280px; background-color: #f9fafb; border: 1px solid #e5e7eb;">
188
+ <tr>
189
+ <td align="center" style="padding: 32px 24px;">
190
+ <table role="presentation" cellpadding="0" cellspacing="0" style="margin-bottom: 16px;">
191
+ <tr>
192
+ <td align="center" style="width: 56px; height: 56px; background-color: #dbeafe; text-align: center; line-height: 56px;">
193
+ <svg role="img" aria-label="Feature icon" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
194
+ <polygon points="12,2 15,9 22,9 17,14 19,21 12,17 5,21 7,14 2,9 9,9" fill="#1d4ed8" />
195
+ </svg>
196
+ </td>
197
+ </tr>
198
+ </table>
199
+ <h3 style="margin: 0 0 8px 0; font-size: 18px; font-weight: 600; color: #111827;">Feature Title</h3>
200
+ <p style="margin: 0; font-size: 14px; color: #6b7280; line-height: 1.5;">Describe this feature and its benefits for the reader.</p>
201
+ </td>
202
+ </tr>
203
+ </table>
204
+ </td>
205
+ </tr>
206
+ </table>
207
+ `
208
+ },
209
+ {
210
+ id: "email-social-links",
211
+ label: "Social Links",
212
+ category: "Email",
213
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><circle cx="6" cy="12" r="3" stroke="currentColor" fill="none" stroke-width="2"/><circle cx="12" cy="12" r="3" stroke="currentColor" fill="none" stroke-width="2"/><circle cx="18" cy="12" r="3" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
214
+ content: `
215
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0">
216
+ <tr>
217
+ <td align="center" style="padding: 24px;">
218
+ <table role="presentation" cellpadding="0" cellspacing="0">
219
+ <tr>
220
+ <td style="padding: 0 8px;">
221
+ <a href="#" aria-label="Visit our X (Twitter) profile" title="X (Twitter)" style="display: inline-block; width: 40px; height: 40px; background-color: #000000; text-align: center; line-height: 40px; text-decoration: none; color: #ffffff; font-size: 18px; font-weight: bold;">X</a>
222
+ </td>
223
+ <td style="padding: 0 8px;">
224
+ <a href="#" aria-label="Visit our LinkedIn profile" title="LinkedIn" style="display: inline-block; width: 40px; height: 40px; background-color: #0077b5; text-align: center; line-height: 40px; text-decoration: none; color: #ffffff; font-size: 16px; font-weight: bold;">in</a>
225
+ </td>
226
+ <td style="padding: 0 8px;">
227
+ <a href="#" aria-label="Visit our Instagram profile" title="Instagram" style="display: inline-block; width: 40px; height: 40px; background-color: #e4405f; text-align: center; line-height: 40px; text-decoration: none; color: #ffffff; font-size: 14px; font-weight: bold;">IG</a>
228
+ </td>
229
+ </tr>
230
+ </table>
231
+ </td>
232
+ </tr>
233
+ </table>
234
+ `
235
+ },
236
+ {
237
+ id: "email-footer",
238
+ label: "Footer",
239
+ category: "Email",
240
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="2" y="14" width="20" height="6" rx="1" stroke="currentColor" fill="none" stroke-width="2"/><line x1="6" y1="17" x2="18" y2="17" stroke="currentColor" stroke-width="2"/></svg>`,
241
+ content: `
242
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color: #f9fafb; border-top: 1px solid #e5e7eb;">
243
+ <tr>
244
+ <td align="center" style="padding: 32px 24px;">
245
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width: ${EMAIL_CONTENT_MAX_WIDTH}px;">
246
+ <tr>
247
+ <td align="center" style="padding-bottom: 16px;">
248
+ <span style="font-size: 16px; font-weight: 600; color: #374151;">Your Company Name</span>
249
+ </td>
250
+ </tr>
251
+ <tr>
252
+ <td align="center" style="padding-bottom: 16px;">
253
+ <span style="font-size: 13px; color: #6b7280;">123 Street Address, Suite 100</span><br/>
254
+ <span style="font-size: 13px; color: #6b7280;">City, State 00000</span>
255
+ </td>
256
+ </tr>
257
+ <tr>
258
+ <td align="center" style="padding-bottom: 16px;">
259
+ <a href="#" style="color: #3b82f6; text-decoration: none; font-size: 13px;">Unsubscribe</a>
260
+ <span style="color: #d1d5db; margin: 0 8px;">|</span>
261
+ <a href="#" style="color: #3b82f6; text-decoration: none; font-size: 13px;">Manage Preferences</a>
262
+ <span style="color: #d1d5db; margin: 0 8px;">|</span>
263
+ <a href="#" style="color: #3b82f6; text-decoration: none; font-size: 13px;">View in Browser</a>
264
+ </td>
265
+ </tr>
266
+ <tr>
267
+ <td align="center">
268
+ <span style="font-size: 12px; color: #9ca3af;">\xA9 2026 Your Company. All rights reserved.</span>
269
+ </td>
270
+ </tr>
271
+ </table>
272
+ </td>
273
+ </tr>
274
+ </table>
275
+ `
276
+ }
277
+ ];
278
+ var emailCanvasStyles = `
279
+ * {
280
+ box-sizing: border-box;
281
+ }
282
+ body {
283
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
284
+ font-size: 16px;
285
+ line-height: 1.5;
286
+ color: #111827;
287
+ margin: 0;
288
+ padding: 0;
289
+ background: #f3f4f6;
290
+ -webkit-font-smoothing: antialiased;
291
+ }
292
+ table {
293
+ border-collapse: collapse;
294
+ mso-table-lspace: 0pt;
295
+ mso-table-rspace: 0pt;
296
+ }
297
+ img {
298
+ border: 0;
299
+ height: auto;
300
+ line-height: 100%;
301
+ outline: none;
302
+ text-decoration: none;
303
+ -ms-interpolation-mode: bicubic;
304
+ }
305
+ a {
306
+ color: #3b82f6;
307
+ }
308
+ `;
309
+ var formBlocks = [
310
+ {
311
+ id: "form-section",
312
+ label: "Form Section",
313
+ category: "Form",
314
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><line x1="7" y1="8" x2="17" y2="8" stroke="currentColor" stroke-width="2"/></svg>`,
315
+ content: `
316
+ <div class="form-section" data-gjs-name="Form Section" data-gjs-droppable="true" style="background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 24px; margin-bottom: 24px;">
317
+ <h3 class="section-title" data-gjs-name="Section Title" style="font-size: 18px; font-weight: 600; margin: 0 0 8px 0; color: #111827;">Section Title</h3>
318
+ <p class="section-description" data-gjs-name="Section Description" style="color: #6b7280; margin: 0 0 24px 0; font-size: 14px;">Section description text</p>
319
+ <div class="section-fields" data-gjs-name="Section Fields Container" data-gjs-droppable="true" style="min-height: 60px;"></div>
320
+ </div>
321
+ `
322
+ },
323
+ {
324
+ id: "text-input",
325
+ label: "Text Input",
326
+ category: "Form",
327
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="6" width="18" height="12" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><line x1="7" y1="12" x2="12" y2="12" stroke="currentColor" stroke-width="2"/></svg>`,
328
+ content: `
329
+ <div class="form-field" data-gjs-name="Text Input Field" style="margin-bottom: 20px;">
330
+ <label data-gjs-name="Field Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Field Label</label>
331
+ <input type="text" data-gjs-name="Text Input" placeholder="Enter text..." style="width: 100%; padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: #ffffff; color: #111827;" />
332
+ </div>
333
+ `
334
+ },
335
+ {
336
+ id: "email-input",
337
+ label: "Email Input",
338
+ category: "Form",
339
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><path d="M3 7l9 6 9-6" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
340
+ content: `
341
+ <div class="form-field" data-gjs-name="Email Input Field" style="margin-bottom: 20px;">
342
+ <label data-gjs-name="Email Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Email Address</label>
343
+ <input type="email" data-gjs-name="Email Input" placeholder="email@example.com" style="width: 100%; padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: #ffffff; color: #111827;" />
344
+ </div>
345
+ `
346
+ },
347
+ {
348
+ id: "textarea",
349
+ label: "Textarea",
350
+ category: "Form",
351
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><line x1="7" y1="8" x2="17" y2="8" stroke="currentColor" stroke-width="2"/><line x1="7" y1="12" x2="17" y2="12" stroke="currentColor" stroke-width="2"/><line x1="7" y1="16" x2="12" y2="16" stroke="currentColor" stroke-width="2"/></svg>`,
352
+ content: `
353
+ <div class="form-field" data-gjs-name="Textarea Field" style="margin-bottom: 20px;">
354
+ <label data-gjs-name="Textarea Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Description</label>
355
+ <textarea data-gjs-name="Textarea Input" placeholder="Enter description..." rows="4" style="width: 100%; padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: #ffffff; color: #111827; resize: vertical; min-height: 100px;"></textarea>
356
+ </div>
357
+ `
358
+ },
359
+ {
360
+ id: "select-dropdown",
361
+ label: "Select Dropdown",
362
+ category: "Form",
363
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="6" width="18" height="12" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><path d="M8 10l4 4 4-4" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
364
+ content: `
365
+ <div class="form-field" data-gjs-name="Select Dropdown Field" style="margin-bottom: 20px;">
366
+ <label data-gjs-name="Select Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Select Option</label>
367
+ <select data-gjs-name="Select Dropdown" style="width: 100%; padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: #ffffff; color: #111827;">
368
+ <option value="">Select an option...</option>
369
+ <option value="1">Option 1</option>
370
+ <option value="2">Option 2</option>
371
+ <option value="3">Option 3</option>
372
+ </select>
373
+ </div>
374
+ `
375
+ },
376
+ {
377
+ id: "checkbox",
378
+ label: "Checkbox",
379
+ category: "Form",
380
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="3" width="18" height="18" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><path d="M9 12l2 2 4-4" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
381
+ content: `
382
+ <div class="form-field" data-gjs-name="Checkbox Field" style="margin-bottom: 20px;">
383
+ <label data-gjs-name="Checkbox Label" style="display: flex; align-items: center; gap: 10px; cursor: pointer; font-size: 14px; color: #374151;">
384
+ <input type="checkbox" data-gjs-name="Checkbox Input" style="width: 18px; height: 18px; border-radius: 4px;" />
385
+ <span data-gjs-name="Checkbox Text">Checkbox label</span>
386
+ </label>
387
+ </div>
388
+ `
389
+ },
390
+ {
391
+ id: "radio-group",
392
+ label: "Radio Group",
393
+ category: "Form",
394
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="9" stroke="currentColor" fill="none" stroke-width="2"/><circle cx="12" cy="12" r="4" fill="currentColor"/></svg>`,
395
+ content: `
396
+ <div class="form-field" data-gjs-name="Radio Group Field" style="margin-bottom: 20px;">
397
+ <label data-gjs-name="Radio Group Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 12px; color: #374151;">Select one option</label>
398
+ <div class="radio-group" data-gjs-name="Radio Options Container" style="display: flex; flex-direction: column; gap: 10px;">
399
+ <label data-gjs-name="Radio Option 1" style="display: flex; align-items: center; gap: 10px; cursor: pointer; padding: 8px 12px; border-radius: 8px; font-size: 14px; color: #374151;">
400
+ <input type="radio" data-gjs-name="Radio Input 1" name="radio-group" style="width: 18px; height: 18px;" />
401
+ <span data-gjs-name="Radio Text 1">Option 1</span>
402
+ </label>
403
+ <label data-gjs-name="Radio Option 2" style="display: flex; align-items: center; gap: 10px; cursor: pointer; padding: 8px 12px; border-radius: 8px; font-size: 14px; color: #374151;">
404
+ <input type="radio" data-gjs-name="Radio Input 2" name="radio-group" style="width: 18px; height: 18px;" />
405
+ <span data-gjs-name="Radio Text 2">Option 2</span>
406
+ </label>
407
+ <label data-gjs-name="Radio Option 3" style="display: flex; align-items: center; gap: 10px; cursor: pointer; padding: 8px 12px; border-radius: 8px; font-size: 14px; color: #374151;">
408
+ <input type="radio" data-gjs-name="Radio Input 3" name="radio-group" style="width: 18px; height: 18px;" />
409
+ <span data-gjs-name="Radio Text 3">Option 3</span>
410
+ </label>
411
+ </div>
412
+ </div>
413
+ `
414
+ },
415
+ {
416
+ id: "submit-button",
417
+ label: "Submit Button",
418
+ category: "Form",
419
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="7" width="18" height="10" rx="5" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
420
+ content: `
421
+ <button type="submit" data-gjs-name="Submit Button" style="display: inline-flex; align-items: center; justify-content: center; padding: 12px 24px; background: #3b82f6; color: #ffffff; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer;">
422
+ Submit
423
+ </button>
424
+ `
425
+ },
426
+ {
427
+ id: "number-input",
428
+ label: "Number Input",
429
+ category: "Form",
430
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="6" width="18" height="12" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><text x="12" y="14" text-anchor="middle" font-size="8" fill="currentColor">123</text></svg>`,
431
+ content: `
432
+ <div class="form-field" data-gjs-name="Number Input Field" style="margin-bottom: 20px;">
433
+ <label data-gjs-name="Number Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Number</label>
434
+ <input type="number" data-gjs-name="Number Input" placeholder="0" min="0" max="100" step="1" style="width: 100%; padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: #ffffff; color: #111827;" />
435
+ </div>
436
+ `
437
+ },
438
+ {
439
+ id: "date-input",
440
+ label: "Date Picker",
441
+ category: "Form",
442
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="4" width="18" height="18" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><line x1="3" y1="10" x2="21" y2="10" stroke="currentColor" stroke-width="2"/><line x1="8" y1="2" x2="8" y2="6" stroke="currentColor" stroke-width="2"/><line x1="16" y1="2" x2="16" y2="6" stroke="currentColor" stroke-width="2"/></svg>`,
443
+ content: `
444
+ <div class="form-field" data-gjs-name="Date Picker Field" style="margin-bottom: 20px;">
445
+ <label data-gjs-name="Date Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Date</label>
446
+ <input type="date" data-gjs-name="Date Input" style="width: 100%; padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: #ffffff; color: #111827;" />
447
+ </div>
448
+ `
449
+ },
450
+ {
451
+ id: "file-upload",
452
+ label: "File Upload",
453
+ category: "Form",
454
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" fill="none" stroke-width="2"/><polyline points="14 2 14 8 20 8" stroke="currentColor" fill="none" stroke-width="2"/><line x1="12" y1="18" x2="12" y2="12" stroke="currentColor" stroke-width="2"/><polyline points="9 15 12 12 15 15" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
455
+ content: `
456
+ <div class="form-field" data-gjs-name="File Upload Field" style="margin-bottom: 20px;">
457
+ <label data-gjs-name="File Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Upload File</label>
458
+ <div data-gjs-name="File Upload Zone" style="border: 2px dashed #d1d5db; border-radius: 8px; padding: 24px; text-align: center; cursor: pointer; transition: border-color 0.2s;">
459
+ <input type="file" data-gjs-name="File Input" accept=".pdf,.doc,.docx,.png,.jpg,.jpeg" style="display: none;" />
460
+ <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="#9ca3af" stroke-width="2" style="margin: 0 auto 12px;">
461
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
462
+ <polyline points="17 8 12 3 7 8"></polyline>
463
+ <line x1="12" y1="3" x2="12" y2="15"></line>
464
+ </svg>
465
+ <p data-gjs-name="Upload Text" style="margin: 0 0 4px 0; font-size: 14px; color: #374151;">Click to upload or drag and drop</p>
466
+ <p data-gjs-name="Upload Hint" style="margin: 0; font-size: 12px; color: #9ca3af;">PDF, DOC, DOCX, PNG, JPG up to 10MB</p>
467
+ </div>
468
+ </div>
469
+ `
470
+ },
471
+ {
472
+ id: "combobox",
473
+ label: "Combobox",
474
+ category: "Form",
475
+ media: `<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="6" width="18" height="12" rx="2" stroke="currentColor" fill="none" stroke-width="2"/><circle cx="8" cy="12" r="2" stroke="currentColor" fill="none" stroke-width="2"/><line x1="12" y1="12" x2="18" y2="12" stroke="currentColor" stroke-width="2"/><path d="M17 10l2 2-2 2" stroke="currentColor" fill="none" stroke-width="2"/></svg>`,
476
+ content: `
477
+ <div class="form-field" data-gjs-name="Combobox Field" style="margin-bottom: 20px;">
478
+ <label data-gjs-name="Combobox Label" style="display: block; font-size: 14px; font-weight: 500; margin-bottom: 8px; color: #374151;">Search & Select</label>
479
+ <div data-gjs-name="Combobox Container" style="position: relative;">
480
+ <input type="text" data-gjs-name="Combobox Input" list="combobox-options" placeholder="Type to search..." style="width: 100%; padding: 10px 40px 10px 14px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; background: #ffffff; color: #111827;" />
481
+ <datalist id="combobox-options" data-gjs-name="Combobox Options">
482
+ <option value="Option 1">Option 1</option>
483
+ <option value="Option 2">Option 2</option>
484
+ <option value="Option 3">Option 3</option>
485
+ </datalist>
486
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#9ca3af" stroke-width="2" style="position: absolute; right: 12px; top: 50%; transform: translateY(-50%); pointer-events: none;">
487
+ <circle cx="11" cy="11" r="8"></circle>
488
+ <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
489
+ </svg>
490
+ </div>
491
+ </div>
492
+ `
493
+ }
494
+ ];
495
+ var lightCanvasStyles = `
496
+ :root {
497
+ --bg-page: #ffffff;
498
+ --bg-card: #ffffff;
499
+ --bg-input: #ffffff;
500
+ --bg-hover: #f4f4f5;
501
+ --bg-option: #fafafa;
502
+ --bg-option-hover: #f4f4f5;
503
+ --bg-option-selected: #18181b;
504
+ --text-primary: #18181b;
505
+ --text-secondary: #71717a;
506
+ --text-muted: #a1a1aa;
507
+ --text-on-selected: #fafafa;
508
+ --border-default: #e4e4e7;
509
+ --border-focus: #18181b;
510
+ --accent: #18181b;
511
+ --primary: #3b82f6;
512
+ --success: #22c55e;
513
+ --error: #ef4444;
514
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
515
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
516
+ --radius: 12px;
517
+ --radius-sm: 8px;
518
+ --transition: 0.15s ease;
519
+ }
520
+
521
+ *, *::before, *::after {
522
+ box-sizing: border-box;
523
+ margin: 0;
524
+ padding: 0;
525
+ }
526
+
527
+ body {
528
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
529
+ font-size: 16px;
530
+ line-height: 1.6;
531
+ color: var(--text-primary);
532
+ background: var(--bg-page);
533
+ -webkit-font-smoothing: antialiased;
534
+ min-height: 100vh;
535
+ padding: 24px;
536
+ }
537
+
538
+ .form-container {
539
+ max-width: 640px;
540
+ margin: 0 auto;
541
+ padding: 3rem 1.5rem;
542
+ }
543
+
544
+ .form-section {
545
+ background: var(--bg-card);
546
+ border: 1px solid var(--border-default);
547
+ border-radius: var(--radius);
548
+ padding: 2rem;
549
+ margin-bottom: 1.5rem;
550
+ box-shadow: var(--shadow-sm);
551
+ }
552
+
553
+ .section-title {
554
+ font-size: 1.25rem;
555
+ font-weight: 600;
556
+ color: var(--text-primary);
557
+ margin: 0 0 0.5rem 0;
558
+ }
559
+
560
+ .section-description {
561
+ font-size: 0.9375rem;
562
+ color: var(--text-secondary);
563
+ margin: 0 0 2rem 0;
564
+ line-height: 1.5;
565
+ }
566
+
567
+ .form-field {
568
+ margin-bottom: 2rem;
569
+ }
570
+ .form-field:last-child {
571
+ margin-bottom: 0;
572
+ }
573
+
574
+ label, .label {
575
+ display: block;
576
+ font-size: 1rem;
577
+ font-weight: 500;
578
+ color: var(--text-primary);
579
+ margin-bottom: 0.75rem;
580
+ }
581
+
582
+ .field-hint {
583
+ font-size: 0.875rem;
584
+ color: var(--text-secondary);
585
+ margin: -0.25rem 0 0.75rem 0;
586
+ }
587
+
588
+ input[type="text"],
589
+ input[type="email"],
590
+ input[type="tel"],
591
+ input[type="url"],
592
+ input[type="number"],
593
+ input[type="password"],
594
+ input[type="date"],
595
+ .form-input {
596
+ display: block;
597
+ width: 100%;
598
+ height: 2.5rem;
599
+ padding: 0 0.875rem;
600
+ font-size: 0.875rem;
601
+ font-family: inherit;
602
+ color: var(--text-primary);
603
+ background: var(--bg-input);
604
+ border: 1px solid var(--border-default);
605
+ border-radius: var(--radius-sm);
606
+ transition: all var(--transition);
607
+ }
608
+
609
+ input:focus, select:focus, textarea:focus {
610
+ outline: none;
611
+ border-color: var(--border-focus);
612
+ box-shadow: 0 0 0 3px rgba(24, 24, 27, 0.08);
613
+ }
614
+
615
+ textarea, .form-textarea {
616
+ display: block;
617
+ width: 100%;
618
+ min-height: 100px;
619
+ padding: 0.75rem 0.875rem;
620
+ font-size: 0.875rem;
621
+ font-family: inherit;
622
+ color: var(--text-primary);
623
+ background: var(--bg-input);
624
+ border: 1px solid var(--border-default);
625
+ border-radius: var(--radius-sm);
626
+ resize: vertical;
627
+ }
628
+
629
+ select, .form-select {
630
+ display: block;
631
+ width: 100%;
632
+ height: 2.5rem;
633
+ padding: 0 2.5rem 0 0.875rem;
634
+ font-size: 0.875rem;
635
+ font-family: inherit;
636
+ color: var(--text-primary);
637
+ background-color: var(--bg-input);
638
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2371717a' stroke-width='2'%3e%3cpath stroke-linecap='round' stroke-linejoin='round' d='M19 9l-7 7-7-7'/%3e%3c/svg%3e");
639
+ background-position: right 0.75rem center;
640
+ background-repeat: no-repeat;
641
+ background-size: 1rem;
642
+ border: 1px solid var(--border-default);
643
+ border-radius: var(--radius-sm);
644
+ cursor: pointer;
645
+ -webkit-appearance: none;
646
+ -moz-appearance: none;
647
+ appearance: none;
648
+ }
649
+
650
+ .radio-group {
651
+ display: flex;
652
+ flex-direction: column;
653
+ gap: 0.5rem;
654
+ }
655
+ .radio-horizontal {
656
+ flex-direction: row;
657
+ flex-wrap: wrap;
658
+ }
659
+ .radio-option {
660
+ display: flex;
661
+ align-items: center;
662
+ gap: 0.625rem;
663
+ padding: 0.625rem 0.875rem;
664
+ background: var(--bg-option);
665
+ border: 1px solid var(--border-default);
666
+ border-radius: var(--radius-sm);
667
+ font-size: 0.875rem;
668
+ color: var(--text-primary);
669
+ cursor: pointer;
670
+ transition: all var(--transition);
671
+ }
672
+ .radio-option:hover {
673
+ background: var(--bg-option-hover);
674
+ border-color: var(--text-muted);
675
+ }
676
+ .radio-option:has(input:checked) {
677
+ background: var(--bg-option-selected);
678
+ border-color: var(--bg-option-selected);
679
+ color: var(--text-on-selected);
680
+ }
681
+ .radio-horizontal .radio-option {
682
+ flex: 1;
683
+ min-width: 80px;
684
+ justify-content: center;
685
+ }
686
+
687
+ /* Hide radio/checkbox inputs inside styled option cards (Typeform-style) */
688
+ .radio-option input[type="radio"],
689
+ .checkbox-option input[type="checkbox"] {
690
+ position: absolute;
691
+ opacity: 0;
692
+ width: 0;
693
+ height: 0;
694
+ pointer-events: none;
695
+ }
696
+
697
+ /* Show radio/checkbox inputs when not inside styled cards */
698
+ input[type="radio"],
699
+ input[type="checkbox"] {
700
+ width: 1rem;
701
+ height: 1rem;
702
+ accent-color: var(--accent);
703
+ cursor: pointer;
704
+ flex-shrink: 0;
705
+ }
706
+
707
+ .checkbox-group {
708
+ display: flex;
709
+ flex-direction: column;
710
+ gap: 0.5rem;
711
+ }
712
+ .checkbox-option {
713
+ display: flex;
714
+ align-items: flex-start;
715
+ gap: 0.625rem;
716
+ padding: 0.625rem 0.875rem;
717
+ background: var(--bg-option);
718
+ border: 1px solid var(--border-default);
719
+ border-radius: var(--radius-sm);
720
+ font-size: 0.875rem;
721
+ cursor: pointer;
722
+ }
723
+ .checkbox-option:hover {
724
+ background: var(--bg-option-hover);
725
+ }
726
+ .checkbox-option:has(input:checked) {
727
+ background: var(--bg-option-selected);
728
+ border-color: var(--bg-option-selected);
729
+ color: var(--text-on-selected);
730
+ }
731
+
732
+ .conditional-field,
733
+ [data-condition-field] {
734
+ display: none;
735
+ position: relative;
736
+ }
737
+ .conditional-field.visible,
738
+ [data-condition-field].visible {
739
+ display: block;
740
+ margin-top: 1.5rem;
741
+ }
742
+
743
+ button {
744
+ font-family: inherit;
745
+ }
746
+ `;
747
+ var conditionalLogicScript = `
748
+ (function() {
749
+ function initConditionalLogic() {
750
+ var conditionalFields = document.querySelectorAll('[data-condition-field]');
751
+
752
+ conditionalFields.forEach(function(field) {
753
+ var conditionField = field.getAttribute('data-condition-field');
754
+ var conditionValue = field.getAttribute('data-condition-value');
755
+
756
+ if (!conditionField) return;
757
+
758
+ var controlInputs = document.querySelectorAll(
759
+ 'input[name="' + conditionField + '"], ' +
760
+ 'select[name="' + conditionField + '"], ' +
761
+ '[data-field-name="' + conditionField + '"] input, ' +
762
+ '[data-field-name="' + conditionField + '"] select'
763
+ );
764
+
765
+ function checkCondition() {
766
+ var shouldShow = false;
767
+
768
+ controlInputs.forEach(function(input) {
769
+ if (input.type === 'radio' || input.type === 'checkbox') {
770
+ if (input.checked) {
771
+ var inputValue = input.value || input.parentElement.textContent.trim();
772
+ if (!conditionValue || inputValue === conditionValue) {
773
+ shouldShow = true;
774
+ }
775
+ }
776
+ } else if (input.tagName === 'SELECT') {
777
+ if (!conditionValue || input.value === conditionValue) {
778
+ shouldShow = input.value !== '';
779
+ }
780
+ } else {
781
+ if (!conditionValue || input.value === conditionValue) {
782
+ shouldShow = input.value !== '';
783
+ }
784
+ }
785
+ });
786
+
787
+ field.classList.toggle('visible', shouldShow);
788
+ }
789
+
790
+ controlInputs.forEach(function(input) {
791
+ input.addEventListener('change', checkCondition);
792
+ input.addEventListener('input', checkCondition);
793
+ });
794
+
795
+ checkCondition();
796
+ });
797
+ }
798
+
799
+ if (document.readyState === 'loading') {
800
+ document.addEventListener('DOMContentLoaded', initConditionalLogic);
801
+ } else {
802
+ initConditionalLogic();
803
+ }
804
+
805
+ var observer = new MutationObserver(function(mutations) {
806
+ mutations.forEach(function(mutation) {
807
+ if (mutation.addedNodes.length > 0) {
808
+ setTimeout(initConditionalLogic, 100);
809
+ }
810
+ });
811
+ });
812
+
813
+ observer.observe(document.body, { childList: true, subtree: true });
814
+ })();
815
+ `;
816
+ var darkCanvasStyles = `
817
+ :root {
818
+ --bg-page: #09090b;
819
+ --bg-card: #18181b;
820
+ --bg-input: #27272a;
821
+ --bg-hover: #27272a;
822
+ --bg-option: #27272a;
823
+ --bg-option-hover: #3f3f46;
824
+ --bg-option-selected: #fafafa;
825
+ --text-primary: #fafafa;
826
+ --text-secondary: #a1a1aa;
827
+ --text-muted: #71717a;
828
+ --text-on-selected: #18181b;
829
+ --border-default: #3f3f46;
830
+ --border-focus: #fafafa;
831
+ --accent: #fafafa;
832
+ --primary: #3b82f6;
833
+ --success: #22c55e;
834
+ --error: #ef4444;
835
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
836
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.3);
837
+ --radius: 12px;
838
+ --radius-sm: 8px;
839
+ --transition: 0.15s ease;
840
+ }
841
+
842
+ *, *::before, *::after {
843
+ box-sizing: border-box;
844
+ margin: 0;
845
+ padding: 0;
846
+ }
847
+
848
+ body {
849
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
850
+ font-size: 16px;
851
+ line-height: 1.6;
852
+ color: var(--text-primary);
853
+ background: var(--bg-page);
854
+ -webkit-font-smoothing: antialiased;
855
+ min-height: 100vh;
856
+ padding: 24px;
857
+ }
858
+
859
+ .form-container {
860
+ max-width: 640px;
861
+ margin: 0 auto;
862
+ padding: 3rem 1.5rem;
863
+ }
864
+
865
+ .form-section {
866
+ background: var(--bg-card);
867
+ border: 1px solid var(--border-default);
868
+ border-radius: var(--radius);
869
+ padding: 2rem;
870
+ margin-bottom: 1.5rem;
871
+ box-shadow: var(--shadow-sm);
872
+ }
873
+
874
+ .section-title {
875
+ font-size: 1.25rem;
876
+ font-weight: 600;
877
+ color: var(--text-primary);
878
+ margin: 0 0 0.5rem 0;
879
+ }
880
+
881
+ .section-description {
882
+ font-size: 0.9375rem;
883
+ color: var(--text-secondary);
884
+ margin: 0 0 2rem 0;
885
+ line-height: 1.5;
886
+ }
887
+
888
+ .form-field {
889
+ margin-bottom: 2rem;
890
+ }
891
+ .form-field:last-child {
892
+ margin-bottom: 0;
893
+ }
894
+
895
+ label, .label {
896
+ display: block;
897
+ font-size: 1rem;
898
+ font-weight: 500;
899
+ color: var(--text-primary);
900
+ margin-bottom: 0.75rem;
901
+ }
902
+
903
+ .field-hint {
904
+ font-size: 0.875rem;
905
+ color: var(--text-secondary);
906
+ margin: -0.25rem 0 0.75rem 0;
907
+ }
908
+
909
+ input[type="text"],
910
+ input[type="email"],
911
+ input[type="tel"],
912
+ input[type="url"],
913
+ input[type="number"],
914
+ input[type="password"],
915
+ input[type="date"],
916
+ .form-input {
917
+ display: block;
918
+ width: 100%;
919
+ height: 2.5rem;
920
+ padding: 0 0.875rem;
921
+ font-size: 0.875rem;
922
+ font-family: inherit;
923
+ color: var(--text-primary);
924
+ background: var(--bg-input);
925
+ border: 1px solid var(--border-default);
926
+ border-radius: var(--radius-sm);
927
+ transition: all var(--transition);
928
+ }
929
+
930
+ input:focus, select:focus, textarea:focus {
931
+ outline: none;
932
+ border-color: var(--border-focus);
933
+ box-shadow: 0 0 0 3px rgba(250, 250, 250, 0.1);
934
+ }
935
+
936
+ input::placeholder, textarea::placeholder {
937
+ color: var(--text-muted);
938
+ }
939
+
940
+ textarea, .form-textarea {
941
+ display: block;
942
+ width: 100%;
943
+ min-height: 100px;
944
+ padding: 0.75rem 0.875rem;
945
+ font-size: 0.875rem;
946
+ font-family: inherit;
947
+ color: var(--text-primary);
948
+ background: var(--bg-input);
949
+ border: 1px solid var(--border-default);
950
+ border-radius: var(--radius-sm);
951
+ resize: vertical;
952
+ }
953
+
954
+ select, .form-select {
955
+ display: block;
956
+ width: 100%;
957
+ height: 2.5rem;
958
+ padding: 0 2.5rem 0 0.875rem;
959
+ font-size: 0.875rem;
960
+ font-family: inherit;
961
+ color: var(--text-primary);
962
+ background-color: var(--bg-input);
963
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2371717a' stroke-width='2'%3e%3cpath stroke-linecap='round' stroke-linejoin='round' d='M19 9l-7 7-7-7'/%3e%3c/svg%3e");
964
+ background-position: right 0.75rem center;
965
+ background-repeat: no-repeat;
966
+ background-size: 1rem;
967
+ border: 1px solid var(--border-default);
968
+ border-radius: var(--radius-sm);
969
+ cursor: pointer;
970
+ -webkit-appearance: none;
971
+ -moz-appearance: none;
972
+ appearance: none;
973
+ }
974
+
975
+ .radio-group {
976
+ display: flex;
977
+ flex-direction: column;
978
+ gap: 0.5rem;
979
+ }
980
+ .radio-horizontal {
981
+ flex-direction: row;
982
+ flex-wrap: wrap;
983
+ }
984
+ .radio-option {
985
+ display: flex;
986
+ align-items: center;
987
+ gap: 0.625rem;
988
+ padding: 0.625rem 0.875rem;
989
+ background: var(--bg-option);
990
+ border: 1px solid var(--border-default);
991
+ border-radius: var(--radius-sm);
992
+ font-size: 0.875rem;
993
+ color: var(--text-primary);
994
+ cursor: pointer;
995
+ transition: all var(--transition);
996
+ }
997
+ .radio-option:hover {
998
+ background: var(--bg-option-hover);
999
+ border-color: var(--text-muted);
1000
+ }
1001
+ .radio-option:has(input:checked) {
1002
+ background: var(--bg-option-selected);
1003
+ border-color: var(--bg-option-selected);
1004
+ color: var(--text-on-selected);
1005
+ }
1006
+ .radio-horizontal .radio-option {
1007
+ flex: 1;
1008
+ min-width: 80px;
1009
+ justify-content: center;
1010
+ }
1011
+
1012
+ /* Hide radio/checkbox inputs inside styled option cards (Typeform-style) */
1013
+ .radio-option input[type="radio"],
1014
+ .checkbox-option input[type="checkbox"] {
1015
+ position: absolute;
1016
+ opacity: 0;
1017
+ width: 0;
1018
+ height: 0;
1019
+ pointer-events: none;
1020
+ }
1021
+
1022
+ /* Show radio/checkbox inputs when not inside styled cards */
1023
+ input[type="radio"],
1024
+ input[type="checkbox"] {
1025
+ width: 1rem;
1026
+ height: 1rem;
1027
+ accent-color: var(--accent);
1028
+ cursor: pointer;
1029
+ flex-shrink: 0;
1030
+ }
1031
+
1032
+ .checkbox-group {
1033
+ display: flex;
1034
+ flex-direction: column;
1035
+ gap: 0.5rem;
1036
+ }
1037
+ .checkbox-option {
1038
+ display: flex;
1039
+ align-items: flex-start;
1040
+ gap: 0.625rem;
1041
+ padding: 0.625rem 0.875rem;
1042
+ background: var(--bg-option);
1043
+ border: 1px solid var(--border-default);
1044
+ border-radius: var(--radius-sm);
1045
+ font-size: 0.875rem;
1046
+ cursor: pointer;
1047
+ }
1048
+ .checkbox-option:hover {
1049
+ background: var(--bg-option-hover);
1050
+ }
1051
+ .checkbox-option:has(input:checked) {
1052
+ background: var(--bg-option-selected);
1053
+ border-color: var(--bg-option-selected);
1054
+ color: var(--text-on-selected);
1055
+ }
1056
+
1057
+ .conditional-field,
1058
+ [data-condition-field] {
1059
+ display: none;
1060
+ position: relative;
1061
+ }
1062
+ .conditional-field.visible,
1063
+ [data-condition-field].visible {
1064
+ display: block;
1065
+ margin-top: 1.5rem;
1066
+ }
1067
+
1068
+ button {
1069
+ font-family: inherit;
1070
+ }
1071
+ `;
1072
+ var getCanvasStyles = (theme, projectType) => {
1073
+ if (projectType === "email") {
1074
+ return emailCanvasStyles;
1075
+ }
1076
+ return theme === "dark" ? darkCanvasStyles : lightCanvasStyles;
1077
+ };
1078
+ function StudioEditor({
1079
+ projectType = "web",
1080
+ initialContent,
1081
+ initialProject,
1082
+ onChange,
1083
+ onSave,
1084
+ theme = "light",
1085
+ customBlocks,
1086
+ blockCategories: _blockCategories,
1087
+ showPages: _showPages = false,
1088
+ showLayers: _showLayers = true,
1089
+ height = "100%",
1090
+ canvasStyles,
1091
+ licenseKey = "DEV_LICENSE_KEY",
1092
+ onReady,
1093
+ storage = { type: false },
1094
+ editorKey,
1095
+ previewMode = false,
1096
+ lockPreview = false,
1097
+ initialDevice,
1098
+ onDeviceChange,
1099
+ debug = false
1100
+ }) {
1101
+ const editorRef = useRef(null);
1102
+ useEffect(() => {
1103
+ if (storage.type === false && typeof window !== "undefined") {
1104
+ try {
1105
+ const keysToRemove = [
1106
+ "gjsProject",
1107
+ "gjs-project",
1108
+ "gjs",
1109
+ "gjsData",
1110
+ "gjs-data",
1111
+ "gjs-studio",
1112
+ "gjsStudio",
1113
+ "gjs-assets",
1114
+ "gjsAssets"
1115
+ ];
1116
+ for (const key of keysToRemove) {
1117
+ localStorage.removeItem(key);
1118
+ }
1119
+ const dynamicKeys = [];
1120
+ for (let i = 0; i < localStorage.length; i += 1) {
1121
+ const key = localStorage.key(i);
1122
+ if (key !== null) {
1123
+ dynamicKeys.push(key);
1124
+ }
1125
+ }
1126
+ for (const key of dynamicKeys) {
1127
+ if (key.startsWith("gjs-") || key.startsWith("gjs") || key.startsWith("grapes")) {
1128
+ localStorage.removeItem(key);
1129
+ }
1130
+ }
1131
+ } catch {
1132
+ }
1133
+ }
1134
+ }, [storage.type]);
1135
+ const baseBlocks = useMemo(
1136
+ () => projectType === "email" ? emailBlocks : formBlocks,
1137
+ [projectType]
1138
+ );
1139
+ const allBlocks = useMemo(() => {
1140
+ const blocks = [...baseBlocks];
1141
+ if (customBlocks) {
1142
+ blocks.push(...customBlocks);
1143
+ }
1144
+ return blocks;
1145
+ }, [baseBlocks, customBlocks]);
1146
+ const handleReady = useCallback(
1147
+ (editor) => {
1148
+ editorRef.current = editor;
1149
+ if (debug) {
1150
+ console.log("[StudioEditor] handleReady called:", {
1151
+ hasInitialProject: !!initialProject,
1152
+ initialProjectKeys: initialProject ? Object.keys(initialProject) : null,
1153
+ previewMode,
1154
+ lockPreview
1155
+ });
1156
+ }
1157
+ const blockManager = editor.Blocks;
1158
+ for (const block of allBlocks) {
1159
+ blockManager.add(block.id, {
1160
+ label: block.label,
1161
+ category: block.category,
1162
+ content: block.content,
1163
+ media: block.media,
1164
+ attributes: block.attributes
1165
+ });
1166
+ }
1167
+ if (debug) {
1168
+ editor.onReady(() => {
1169
+ const loadedData = editor.getProjectData();
1170
+ console.log("[StudioEditor] onReady - SDK loaded data:", loadedData);
1171
+ console.log("[StudioEditor] onReady - getHtml():", editor.getHtml());
1172
+ console.log(
1173
+ "[StudioEditor] onReady - Components:",
1174
+ editor.getComponents().length
1175
+ );
1176
+ const canvasEl = editor.Canvas.getElement();
1177
+ const canvasDoc = editor.Canvas.getDocument();
1178
+ const canvasBody = editor.Canvas.getBody();
1179
+ const canvasFrame = editor.Canvas.getFrameEl();
1180
+ const wrapper = editor.getWrapper();
1181
+ console.log("[StudioEditor] onReady - Canvas debug:", {
1182
+ canvasEl,
1183
+ canvasElDimensions: canvasEl ? { width: canvasEl.offsetWidth, height: canvasEl.offsetHeight } : null,
1184
+ canvasDoc,
1185
+ canvasBody,
1186
+ canvasBodyChildren: canvasBody?.children?.length,
1187
+ canvasFrame,
1188
+ canvasFrameSrc: canvasFrame?.src,
1189
+ wrapper,
1190
+ wrapperHtml: wrapper?.toHTML?.()
1191
+ });
1192
+ if (canvasBody) {
1193
+ console.log("[StudioEditor] Canvas body children:");
1194
+ Array.from(canvasBody.children).forEach((child, i) => {
1195
+ console.log(` [${i}] ${child.tagName}`, child);
1196
+ });
1197
+ }
1198
+ const wrapperEl = canvasBody?.querySelector(
1199
+ '[data-gjs-type="wrapper"]'
1200
+ );
1201
+ if (wrapperEl) {
1202
+ const styles = window.getComputedStyle(wrapperEl);
1203
+ console.log("[StudioEditor] Wrapper element styles:", {
1204
+ display: styles.display,
1205
+ visibility: styles.visibility,
1206
+ opacity: styles.opacity,
1207
+ height: styles.height,
1208
+ width: styles.width,
1209
+ overflow: styles.overflow,
1210
+ position: styles.position,
1211
+ zIndex: styles.zIndex,
1212
+ backgroundColor: styles.backgroundColor
1213
+ });
1214
+ console.log(
1215
+ "[StudioEditor] Wrapper element dimensions:",
1216
+ wrapperEl.getBoundingClientRect()
1217
+ );
1218
+ console.log(
1219
+ "[StudioEditor] Wrapper innerHTML preview:",
1220
+ wrapperEl.innerHTML.substring(0, 300)
1221
+ );
1222
+ }
1223
+ if (canvasFrame) {
1224
+ const frameStyles = window.getComputedStyle(canvasFrame);
1225
+ console.log("[StudioEditor] Canvas frame styles:", {
1226
+ display: frameStyles.display,
1227
+ visibility: frameStyles.visibility,
1228
+ opacity: frameStyles.opacity,
1229
+ height: frameStyles.height,
1230
+ width: frameStyles.width,
1231
+ position: frameStyles.position
1232
+ });
1233
+ console.log(
1234
+ "[StudioEditor] Canvas frame dimensions:",
1235
+ canvasFrame.getBoundingClientRect()
1236
+ );
1237
+ }
1238
+ });
1239
+ }
1240
+ if (onChange) {
1241
+ editor.on("update", () => {
1242
+ const html = editor.getHtml();
1243
+ const css = editor.getCss();
1244
+ const json = editor.getProjectData();
1245
+ onChange(html, css || "", json);
1246
+ });
1247
+ }
1248
+ if (onSave) {
1249
+ let isInitialLoad = true;
1250
+ editor.on("storage:store", () => {
1251
+ if (isInitialLoad) {
1252
+ isInitialLoad = false;
1253
+ return;
1254
+ }
1255
+ const html = editor.getHtml();
1256
+ const css = editor.getCss();
1257
+ const json = editor.getProjectData();
1258
+ onSave({ html, css: css || "", json });
1259
+ });
1260
+ }
1261
+ if (onDeviceChange) {
1262
+ editor.on("change:device", () => {
1263
+ const device = editor.getDevice();
1264
+ onDeviceChange(device);
1265
+ });
1266
+ }
1267
+ if (initialDevice) {
1268
+ editor.setDevice(initialDevice);
1269
+ }
1270
+ if (previewMode) {
1271
+ editor.onReady(() => {
1272
+ const attemptPreview = (retries = 0) => {
1273
+ const canvasDoc = editor.Canvas.getDocument();
1274
+ if (canvasDoc?.body) {
1275
+ editor.runCommand("core:preview");
1276
+ if (lockPreview) {
1277
+ editor.on(
1278
+ "command:stop:before:core:preview",
1279
+ (event) => {
1280
+ event.options.abort = true;
1281
+ }
1282
+ );
1283
+ }
1284
+ } else if (retries < 10) {
1285
+ setTimeout(
1286
+ () => attemptPreview(retries + 1),
1287
+ 100 * (retries + 1)
1288
+ );
1289
+ }
1290
+ };
1291
+ setTimeout(() => attemptPreview(), 200);
1292
+ });
1293
+ }
1294
+ onReady?.(editor);
1295
+ },
1296
+ [
1297
+ allBlocks,
1298
+ debug,
1299
+ initialProject,
1300
+ onChange,
1301
+ onSave,
1302
+ onReady,
1303
+ onDeviceChange,
1304
+ initialDevice,
1305
+ previewMode,
1306
+ lockPreview
1307
+ ]
1308
+ );
1309
+ const themeStyles = useMemo(
1310
+ () => canvasStyles || getCanvasStyles(theme, projectType),
1311
+ [canvasStyles, theme, projectType]
1312
+ );
1313
+ const defaultProject = useMemo(() => {
1314
+ const isEmail = projectType === "email";
1315
+ if (debug) {
1316
+ console.log("[StudioEditor] defaultProject computation:", {
1317
+ hasInitialProject: !!initialProject,
1318
+ initialProjectLength: initialProject ? Object.keys(initialProject).length : 0,
1319
+ willUseInitialProject: !!(initialProject && Object.keys(initialProject).length > 0)
1320
+ });
1321
+ }
1322
+ if (initialProject && Object.keys(initialProject).length > 0) {
1323
+ return initialProject;
1324
+ }
1325
+ const defaultEmailContent = `
1326
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color: #f3f4f6; min-height: 100vh;">
1327
+ <tr>
1328
+ <td align="center" style="padding: 24px;">
1329
+ <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="max-width: 600px; background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1);" data-gjs-droppable="true">
1330
+ <tr>
1331
+ <td data-gjs-droppable="true" style="min-height: 200px;">
1332
+ <p style="text-align: center; color: #6b7280; padding: 48px 24px;">Drop email blocks here to build your template</p>
1333
+ </td>
1334
+ </tr>
1335
+ </table>
1336
+ </td>
1337
+ </tr>
1338
+ </table>
1339
+ `;
1340
+ const defaultFormContent = "<div data-gjs-droppable='true' style='min-height: 200px; padding: 24px;'><p>Drop form elements here to build your form</p></div>";
1341
+ const content = initialContent || (isEmail ? defaultEmailContent : defaultFormContent);
1342
+ return {
1343
+ pages: [
1344
+ {
1345
+ name: isEmail ? "Email" : "Form",
1346
+ component: content
1347
+ }
1348
+ ]
1349
+ };
1350
+ }, [debug, initialContent, initialProject, projectType]);
1351
+ const themeStylesPlugin = useCallback(
1352
+ (editor) => {
1353
+ editor.onReady(() => {
1354
+ editor.Css.addRules(themeStyles);
1355
+ if (projectType === "web") {
1356
+ const canvasDoc = editor.Canvas.getDocument();
1357
+ if (canvasDoc) {
1358
+ const existingScript = canvasDoc.getElementById(
1359
+ "conditional-logic-script"
1360
+ );
1361
+ if (!existingScript) {
1362
+ const scriptEl = canvasDoc.createElement("script");
1363
+ scriptEl.id = "conditional-logic-script";
1364
+ scriptEl.textContent = conditionalLogicScript;
1365
+ canvasDoc.body.appendChild(scriptEl);
1366
+ }
1367
+ }
1368
+ }
1369
+ });
1370
+ },
1371
+ [themeStyles, projectType]
1372
+ );
1373
+ return /* @__PURE__ */ jsxs(
1374
+ "div",
1375
+ {
1376
+ className: `studio-editor-container${lockPreview ? " studio-editor-locked-preview" : ""}`,
1377
+ style: {
1378
+ height: typeof height === "number" ? `${height}px` : height,
1379
+ minHeight: 400,
1380
+ // Minimum usable height
1381
+ width: "100%",
1382
+ position: "relative",
1383
+ display: "flex",
1384
+ flexDirection: "column"
1385
+ },
1386
+ children: [
1387
+ /* @__PURE__ */ jsx("style", { children: `
1388
+ .studio-editor-container {
1389
+ overflow: hidden !important;
1390
+ }
1391
+ /* SDK root wrapper - the gs-studio-root element */
1392
+ .studio-editor-container > div:first-child,
1393
+ .studio-editor-container .gs-studio-root,
1394
+ .studio-editor-container .gs-studio-editor {
1395
+ display: flex !important;
1396
+ flex-direction: column !important;
1397
+ height: 100% !important;
1398
+ overflow: hidden !important;
1399
+ }
1400
+ /* The main row containing sidebars and canvas */
1401
+ .studio-editor-container .gs-cmp-row {
1402
+ flex: 1 1 auto !important;
1403
+ min-height: 0 !important;
1404
+ overflow: hidden !important;
1405
+ }
1406
+ /* Canvas sidebar top - contains the canvas area */
1407
+ .studio-editor-container .gs-canvas-sidebar-top {
1408
+ flex: 1 1 auto !important;
1409
+ min-height: 0 !important;
1410
+ overflow: hidden !important;
1411
+ }
1412
+ /* The canvas wrapper element */
1413
+ .studio-editor-container .gs-canvas {
1414
+ flex: 1 1 auto !important;
1415
+ min-height: 0 !important;
1416
+ overflow: hidden !important;
1417
+ }
1418
+ /* GrapesJS editor container */
1419
+ .studio-editor-container .gjs-editor-cont,
1420
+ .studio-editor-container .gjs-editor {
1421
+ height: 100% !important;
1422
+ overflow: hidden !important;
1423
+ }
1424
+ /* Canvas container - this is where the iframe lives */
1425
+ .studio-editor-container .gjs-cv-canvas {
1426
+ height: 100% !important;
1427
+ overflow: hidden !important;
1428
+ }
1429
+ /* The frames wrapper inside canvas */
1430
+ .studio-editor-container .gjs-cv-canvas__frames {
1431
+ height: 100% !important;
1432
+ overflow: hidden !important;
1433
+ }
1434
+ /* Frame wrapper that contains the iframe */
1435
+ .studio-editor-container .gjs-frame-wrapper {
1436
+ height: 100% !important;
1437
+ overflow: hidden !important;
1438
+ }
1439
+ /* The actual iframe - allow internal scrolling only */
1440
+ .studio-editor-container .gjs-frame {
1441
+ height: 100% !important;
1442
+ width: 100% !important;
1443
+ border: none !important;
1444
+ }
1445
+ /* Hide the duplicate canvas */
1446
+ .studio-editor-container .cv-canvas {
1447
+ display: none !important;
1448
+ }
1449
+ /* Ensure sidebars don't create scrollbars */
1450
+ .studio-editor-container .gs-sidebar-left,
1451
+ .studio-editor-container .gs-sidebar-right {
1452
+ overflow: hidden !important;
1453
+ }
1454
+ /* Allow layer manager to scroll internally */
1455
+ .studio-editor-container .gs-layer-manager {
1456
+ overflow: hidden !important;
1457
+ }
1458
+ .studio-editor-container .gs-layer-manager > div:last-child {
1459
+ overflow-y: auto !important;
1460
+ overflow-x: hidden !important;
1461
+ }
1462
+ /* Remove outer border from the editor wrapper */
1463
+ .studio-editor-container .gjs-editor-wrapper {
1464
+ border: none !important;
1465
+ }
1466
+ /* Hide exit preview button when preview is locked */
1467
+ .studio-editor-locked-preview .gs-cmp-close-preview {
1468
+ display: none !important;
1469
+ }
1470
+ ` }),
1471
+ /* @__PURE__ */ jsx(
1472
+ StudioEditorSDK,
1473
+ {
1474
+ options: {
1475
+ licenseKey,
1476
+ theme,
1477
+ project: {
1478
+ type: projectType,
1479
+ default: defaultProject
1480
+ },
1481
+ // Use plugins to inject CSS via CssComposer - the SDK-native approach
1482
+ plugins: [themeStylesPlugin],
1483
+ storage: storage.type === false ? false : {
1484
+ type: storage.type || "browser",
1485
+ autosaveChanges: storage.autosaveChanges,
1486
+ autosaveIntervalMs: storage.autosaveIntervalMs
1487
+ }
1488
+ },
1489
+ onEditor: handleReady
1490
+ }
1491
+ )
1492
+ ]
1493
+ },
1494
+ editorKey
1495
+ );
1496
+ }
1497
+
1498
+ export { StudioEditor };