@seliseblocks/mailcraft 0.2.13 → 0.2.15

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 (59) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/DOCS.md +5 -4
  3. package/README.md +2 -1
  4. package/README.md.txt +2 -1
  5. package/dist/mailcraft-editor.bundle.js +72 -72
  6. package/dist/mailcraft-editor.bundle.js.map +3 -3
  7. package/examples/templates/back-in-stock.html +1 -8
  8. package/examples/templates/cart-left-behind.html +1 -8
  9. package/examples/templates/meet-nova-launch.html +5 -0
  10. package/examples/templates/rate-your-headphones.html +1 -8
  11. package/examples/templates/the-sunday-brief.html +5 -0
  12. package/examples/templates/your-order-shipped.html +1 -0
  13. package/examples/vanilla.html +14 -24
  14. package/package.json +1 -1
  15. package/src/core/editor-core.js +116 -1
  16. package/src/core/i18n/ar.js +2 -1
  17. package/src/core/i18n/bg.js +2 -1
  18. package/src/core/i18n/bn.js +2 -1
  19. package/src/core/i18n/ca.js +2 -1
  20. package/src/core/i18n/cs.js +2 -1
  21. package/src/core/i18n/da.js +2 -1
  22. package/src/core/i18n/de-CH.js +2 -1
  23. package/src/core/i18n/de.js +2 -1
  24. package/src/core/i18n/dz.js +2 -1
  25. package/src/core/i18n/el.js +2 -1
  26. package/src/core/i18n/en.js +2 -1
  27. package/src/core/i18n/es.js +2 -1
  28. package/src/core/i18n/et.js +2 -1
  29. package/src/core/i18n/fi.js +2 -1
  30. package/src/core/i18n/fr.js +2 -1
  31. package/src/core/i18n/hr.js +2 -1
  32. package/src/core/i18n/hu.js +2 -1
  33. package/src/core/i18n/index.js +83 -83
  34. package/src/core/i18n/it.js +2 -1
  35. package/src/core/i18n/lt.js +2 -1
  36. package/src/core/i18n/lv.js +2 -1
  37. package/src/core/i18n/nb.js +2 -1
  38. package/src/core/i18n/nl.js +2 -1
  39. package/src/core/i18n/pl.js +2 -1
  40. package/src/core/i18n/pt.js +2 -1
  41. package/src/core/i18n/ro.js +2 -1
  42. package/src/core/i18n/ru.js +2 -1
  43. package/src/core/i18n/sk.js +2 -1
  44. package/src/core/i18n/sl.js +2 -1
  45. package/src/core/i18n/sv.js +2 -1
  46. package/src/core/i18n/tr.js +2 -1
  47. package/src/core/i18n/uk.js +2 -1
  48. package/src/core/ids.js +1 -1
  49. package/src/core/layout-style.js +100 -100
  50. package/src/core/parse.js +10 -10
  51. package/src/core/placeholder.js +15 -15
  52. package/src/core/variables.js +11 -11
  53. package/src/mailcraft-editor.js +20 -8
  54. package/src/render/block-body.js +7 -1
  55. package/src/render/focus-preserve.js +158 -158
  56. package/src/render/rte.js +4 -1
  57. package/src/render/screenshot.js +81 -5
  58. package/src/render/story.js +513 -415
  59. package/types/index.d.ts +22 -7
@@ -21,14 +21,7 @@
21
21
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:#f6f1e9; ">
22
22
  <tr>
23
23
  <td width="38%" valign="middle" align="center" style="padding:22px 18px;">
24
- <table role="presentation" cellpadding="0" cellspacing="0" style="background-color:#b85c38; ">
25
- <tr>
26
- <td align="center" style="padding:30px 24px;">
27
- <p style="margin:0 0 4px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.18em; text-transform:uppercase; color:#f3dcc9;">Terracotta</p>
28
- <p style="margin:0; font-family:Georgia, serif; font-size:22px; color:#ffffff;">Trainer</p>
29
- </td>
30
- </tr>
31
- </table>
24
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22340%22%20height%3D%22340%22%20viewBox%3D%220%200%20340%20340%22%3E%20%3Crect%20width%3D%22340%22%20height%3D%22340%22%20fill%3D%22%23b85c38%22%2F%3E%20%3Ccircle%20cx%3D%22264%22%20cy%3D%2272%22%20r%3D%2242%22%20fill%3D%22%23c96f4a%22%2F%3E%20%3Ccircle%20cx%3D%2256%22%20cy%3D%22290%22%20r%3D%2254%22%20fill%3D%22%23a9502e%22%2F%3E%20%3Cellipse%20cx%3D%22172%22%20cy%3D%22252%22%20rx%3D%22120%22%20ry%3D%2213%22%20fill%3D%22%238f4526%22%2F%3E%20%3Cpath%20d%3D%22M52%20222%20Q52%20242%2076%20242%20L268%20242%20Q288%20242%20288%20224%20L288%20216%20Q288%20208%20278%20206%20L62%20206%20Q52%20208%2052%20222%20Z%22%20fill%3D%22%23f3e9dc%22%2F%3E%20%3Cpath%20d%3D%22M62%20208%20Q60%20152%2096%20140%20Q128%20130%20148%20150%20Q170%20172%20210%20178%20L262%20188%20Q286%20194%20286%20208%20Z%22%20fill%3D%22%23e8d9c4%22%2F%3E%20%3Cpath%20d%3D%22M148%20150%20Q170%20172%20210%20178%20L262%20188%20Q286%20194%20286%20208%20L196%20208%20Q170%20198%20156%20174%20Z%22%20fill%3D%22%23caa27f%22%2F%3E%20%3Cpath%20d%3D%22M62%20208%20Q61%20170%2082%20152%20Q68%20172%2070%20208%20Z%22%20fill%3D%22%23d9c3a6%22%2F%3E%20%3Cg%20stroke%3D%22%238f5a3a%22%20stroke-width%3D%226%22%20stroke-linecap%3D%22round%22%3E%20%3Cline%20x1%3D%22112%22%20y1%3D%22152%22%20x2%3D%22140%22%20y2%3D%22166%22%2F%3E%20%3Cline%20x1%3D%22106%22%20y1%3D%22168%22%20x2%3D%22136%22%20y2%3D%22182%22%2F%3E%20%3Cline%20x1%3D%22102%22%20y1%3D%22184%22%20x2%3D%22132%22%20y2%3D%22198%22%2F%3E%20%3C%2Fg%3E%20%3Crect%20x%3D%2258%22%20y%3D%22230%22%20width%3D%22224%22%20height%3D%226%22%20rx%3D%223%22%20fill%3D%22%23d9c3a6%22%2F%3E%20%3C%2Fsvg%3E" width="170" alt="Terracotta Trainer — suede and canvas sneaker" style="display:block; width:170px; max-width:100%; height:auto;" />
32
25
  </td>
33
26
  <td width="62%" valign="middle" style="padding:18px 18px 18px 6px;">
34
27
  <h2 style="margin:0 0 6px; font-family:Georgia, serif; font-size:19px; color:#29241d;">Terracotta Trainer</h2>
@@ -29,14 +29,7 @@
29
29
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid #e7e3f2; ">
30
30
  <tr>
31
31
  <td width="30%" valign="middle" align="center" style="padding:22px 16px;">
32
- <table role="presentation" cellpadding="0" cellspacing="0" style="background-color:#7048b8; ">
33
- <tr>
34
- <td align="center" style="padding:26px 22px;">
35
- <p style="margin:0 0 4px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.18em; text-transform:uppercase; color:#dddcf3;">Chestnut</p>
36
- <p style="margin:0; font-family:Georgia, serif; font-size:19px; color:#ffffff;">Weekend bag</p>
37
- </td>
38
- </tr>
39
- </table>
32
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22300%22%20viewBox%3D%220%200%20300%20300%22%3E%20%3Crect%20width%3D%22300%22%20height%3D%22300%22%20fill%3D%22%237048b8%22%2F%3E%20%3Ccircle%20cx%3D%22250%22%20cy%3D%2256%22%20r%3D%2236%22%20fill%3D%22%237f57c6%22%2F%3E%20%3Ccircle%20cx%3D%2244%22%20cy%3D%22256%22%20r%3D%2240%22%20fill%3D%22%23633fa8%22%2F%3E%20%3Cellipse%20cx%3D%22150%22%20cy%3D%22236%22%20rx%3D%22106%22%20ry%3D%2211%22%20fill%3D%22%235d3aa0%22%2F%3E%20%3Cpath%20d%3D%22M110%20122%20Q110%2084%20150%2084%20Q190%2084%20190%20122%22%20fill%3D%22none%22%20stroke%3D%22%235c3a1e%22%20stroke-width%3D%2210%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Crect%20x%3D%2258%22%20y%3D%22118%22%20width%3D%22184%22%20height%3D%22114%22%20rx%3D%2226%22%20fill%3D%22%238a5a33%22%2F%3E%20%3Cpath%20d%3D%22M84%20118%20Q58%20118%2058%20144%20L58%20206%20Q58%20232%2084%20232%20Z%22%20fill%3D%22%237a4e2b%22%2F%3E%20%3Cpath%20d%3D%22M216%20118%20Q242%20118%20242%20144%20L242%20206%20Q242%20232%20216%20232%20Z%22%20fill%3D%22%237a4e2b%22%2F%3E%20%3Crect%20x%3D%22106%22%20y%3D%22118%22%20width%3D%2212%22%20height%3D%22114%22%20fill%3D%22%236e4526%22%2F%3E%20%3Crect%20x%3D%22182%22%20y%3D%22118%22%20width%3D%2212%22%20height%3D%22114%22%20fill%3D%22%236e4526%22%2F%3E%20%3Cline%20x1%3D%2298%22%20y1%3D%22134%22%20x2%3D%22202%22%20y2%3D%22134%22%20stroke%3D%22%23e8d9c4%22%20stroke-width%3D%225%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Ccircle%20cx%3D%22202%22%20cy%3D%22134%22%20r%3D%226%22%20fill%3D%22%23e8d9c4%22%2F%3E%20%3C%2Fsvg%3E" width="150" alt="Chestnut leather weekend bag" style="display:block; width:150px; max-width:100%; height:auto;" />
40
33
  </td>
41
34
  <td width="70%" valign="middle" style="padding:16px 16px 16px 4px;">
42
35
  <h2 style="margin:0 0 4px; font-family:Arial, Helvetica, sans-serif; font-size:16px; color:#241b3a;">Leather weekend bag</h2>
@@ -16,6 +16,11 @@
16
16
  <p style="margin:10px 0 0; font-family:Arial, Helvetica, sans-serif; font-size:15px; line-height:1.5; color:#dbeafe;">Our biggest release yet &mdash; and it&rsquo;s already in your account.</p>
17
17
  </td>
18
18
  </tr>
19
+ <tr>
20
+ <td style="padding:0;">
21
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22600%22%20height%3D%22230%22%20viewBox%3D%220%200%20600%20230%22%3E%20%3Crect%20width%3D%22600%22%20height%3D%22230%22%20fill%3D%22%230b1020%22%2F%3E%20%3Ccircle%20cx%3D%22524%22%20cy%3D%2230%22%20r%3D%2296%22%20fill%3D%22%23111832%22%2F%3E%20%3Ccircle%20cx%3D%2260%22%20cy%3D%22216%22%20r%3D%2280%22%20fill%3D%22%23111832%22%2F%3E%20%3Crect%20x%3D%22150%22%20y%3D%2240%22%20width%3D%22300%22%20height%3D%22172%22%20rx%3D%2212%22%20fill%3D%22%2316203c%22%2F%3E%20%3Cpath%20d%3D%22M150%2052%20Q150%2040%20162%2040%20L438%2040%20Q450%2040%20450%2052%20L450%2072%20L150%2072%20Z%22%20fill%3D%22%231c2848%22%2F%3E%20%3Ccircle%20cx%3D%22172%22%20cy%3D%2256%22%20r%3D%225%22%20fill%3D%22%2358a8e3%22%2F%3E%20%3Ccircle%20cx%3D%22190%22%20cy%3D%2256%22%20r%3D%225%22%20fill%3D%22%233b6ea5%22%2F%3E%20%3Ccircle%20cx%3D%22208%22%20cy%3D%2256%22%20r%3D%225%22%20fill%3D%22%2328497a%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%2290%22%20width%3D%22122%22%20height%3D%2214%22%20rx%3D%227%22%20fill%3D%22%232b3d69%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22118%22%20width%3D%22264%22%20height%3D%2210%22%20rx%3D%225%22%20fill%3D%22%2322335c%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22136%22%20width%3D%22236%22%20height%3D%2210%22%20rx%3D%225%22%20fill%3D%22%2322335c%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22154%22%20width%3D%22250%22%20height%3D%2210%22%20rx%3D%225%22%20fill%3D%22%2322335c%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22180%22%20width%3D%2298%22%20height%3D%2220%22%20rx%3D%2210%22%20fill%3D%22%2358a8e3%22%2F%3E%20%3Cpath%20d%3D%22M470%2084%20L479%20108%20L502%20117%20L479%20126%20L470%20150%20L461%20126%20L438%20117%20L461%20108%20Z%22%20fill%3D%22%23d9e9f9%22%2F%3E%20%3Cpath%20d%3D%22M502%2056%20L506%2067%20L517%2071%20L506%2075%20L502%2086%20L498%2075%20L487%2071%20L498%2067%20Z%22%20fill%3D%22%2358a8e3%22%2F%3E%20%3C%2Fsvg%3E" width="600" alt="Nova — the new workspace" style="display:block; width:100%; max-width:600px; height:auto;" />
22
+ </td>
23
+ </tr>
19
24
  <tr>
20
25
  <td align="center" style="padding:32px 36px 6px;">
21
26
  <h2 style="margin:0 0 12px; font-family:Arial, Helvetica, sans-serif; font-size:21px; line-height:1.3; color:#ffffff;">Everything you asked for, in one update</h2>
@@ -35,14 +35,7 @@
35
35
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:#f6f9fd; ">
36
36
  <tr>
37
37
  <td valign="middle" width="30%" align="center" style="padding:22px 16px;">
38
- <table role="presentation" cellpadding="0" cellspacing="0" style="background-color:#16233a; ">
39
- <tr>
40
- <td align="center" style="padding:24px 20px;">
41
- <p style="margin:0 0 4px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.18em; text-transform:uppercase; color:#93a7c4;">Studio</p>
42
- <p style="margin:0; font-family:Georgia, serif; font-size:18px; color:#ffffff;">MK II</p>
43
- </td>
44
- </tr>
45
- </table>
38
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22280%22%20height%3D%22280%22%20viewBox%3D%220%200%20280%20280%22%3E%20%3Crect%20width%3D%22280%22%20height%3D%22280%22%20fill%3D%22%2316233a%22%2F%3E%20%3Ccircle%20cx%3D%22230%22%20cy%3D%2250%22%20r%3D%2232%22%20fill%3D%22%231e2f4d%22%2F%3E%20%3Ccircle%20cx%3D%2244%22%20cy%3D%22240%22%20r%3D%2242%22%20fill%3D%22%23121c30%22%2F%3E%20%3Cpath%20d%3D%22M70%20162%20L70%20120%20Q70%2050%20140%2050%20Q210%2050%20210%20120%20L210%20162%22%20fill%3D%22none%22%20stroke%3D%22%23dbe5f2%22%20stroke-width%3D%2214%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Cline%20x1%3D%2270%22%20y1%3D%22152%22%20x2%3D%2270%22%20y2%3D%22178%22%20stroke%3D%22%2393a7c4%22%20stroke-width%3D%228%22%2F%3E%20%3Cline%20x1%3D%22210%22%20y1%3D%22152%22%20x2%3D%22210%22%20y2%3D%22178%22%20stroke%3D%22%2393a7c4%22%20stroke-width%3D%228%22%2F%3E%20%3Crect%20x%3D%2246%22%20y%3D%22168%22%20width%3D%2248%22%20height%3D%2266%22%20rx%3D%2220%22%20fill%3D%22%23dbe5f2%22%2F%3E%20%3Crect%20x%3D%22186%22%20y%3D%22168%22%20width%3D%2248%22%20height%3D%2266%22%20rx%3D%2220%22%20fill%3D%22%23dbe5f2%22%2F%3E%20%3Crect%20x%3D%2258%22%20y%3D%22178%22%20width%3D%2224%22%20height%3D%2246%22%20rx%3D%2212%22%20fill%3D%22%2393a7c4%22%2F%3E%20%3Crect%20x%3D%22198%22%20y%3D%22178%22%20width%3D%2224%22%20height%3D%2246%22%20rx%3D%2212%22%20fill%3D%22%2393a7c4%22%2F%3E%20%3C%2Fsvg%3E" width="140" alt="Studio Headphones MK II" style="display:block; width:140px; max-width:100%; height:auto;" />
46
39
  </td>
47
40
  <td valign="middle" width="70%" style="padding:16px 16px 16px 4px;">
48
41
  <h2 style="margin:0 0 4px; font-family:Arial, Helvetica, sans-serif; font-size:15.5px; color:#16233a;">Studio Headphones MK II</h2>
@@ -18,6 +18,11 @@
18
18
  <tr>
19
19
  <td style="height:5px; line-height:5px; font-size:0; background-color:#a06b2c;">&nbsp;</td>
20
20
  </tr>
21
+ <tr>
22
+ <td style="padding:0;">
23
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22600%22%20height%3D%22250%22%20viewBox%3D%220%200%20600%20250%22%3E%20%3Crect%20width%3D%22600%22%20height%3D%22250%22%20fill%3D%22%23eee9dd%22%2F%3E%20%3Ccircle%20cx%3D%22176%22%20cy%3D%22158%22%20r%3D%2266%22%20fill%3D%22%23d9a05b%22%2F%3E%20%3Ccircle%20cx%3D%22176%22%20cy%3D%22158%22%20r%3D%2266%22%20fill%3D%22none%22%20stroke%3D%22%23a06b2c%22%20stroke-width%3D%223%22%2F%3E%20%3Cg%20stroke%3D%22%23a06b2c%22%20stroke-width%3D%223%22%20stroke-linecap%3D%22round%22%3E%20%3Cline%20x1%3D%22176%22%20y1%3D%2266%22%20x2%3D%22176%22%20y2%3D%2248%22%2F%3E%20%3Cline%20x1%3D%22224%22%20y1%3D%2284%22%20x2%3D%22238%22%20y2%3D%2270%22%2F%3E%20%3Cline%20x1%3D%22128%22%20y1%3D%2284%22%20x2%3D%22114%22%20y2%3D%2270%22%2F%3E%20%3C%2Fg%3E%20%3Cpath%20d%3D%22M370%2078%20q9%20-9%2018%200%20M398%2092%20q8%20-8%2016%200%20M348%20100%20q7%20-7%2014%200%22%20stroke%3D%22%231c1b18%22%20stroke-width%3D%223%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Cpath%20d%3D%22M0%20202%20Q100%20140%20220%20190%20Q330%20234%20420%20192%20Q510%20152%20600%20182%20L600%20250%20L0%20250%20Z%22%20fill%3D%22%231c1b18%22%2F%3E%20%3Cpath%20d%3D%22M0%20222%20Q140%20180%20300%20214%20Q450%20244%20600%20212%20L600%20250%20L0%20250%20Z%22%20fill%3D%22%233d3a33%22%2F%3E%20%3C%2Fsvg%3E" width="600" alt="Morning sun over quiet hills" style="display:block; width:100%; max-width:600px; height:auto;" />
24
+ </td>
25
+ </tr>
21
26
  <tr>
22
27
  <td align="center" style="background-color:#f6f4ee; padding:36px 40px 34px; border-bottom:1px solid #e3e0d8;">
23
28
  <p style="margin:0 0 10px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.14em; text-transform:uppercase; color:#a06b2c;">Cover story</p>
@@ -16,6 +16,7 @@
16
16
  </tr>
17
17
  <tr>
18
18
  <td align="center" style="padding:34px 36px 8px;">
19
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22240%22%20height%3D%22170%22%20viewBox%3D%220%200%20240%20170%22%3E%20%3Cellipse%20cx%3D%22126%22%20cy%3D%22150%22%20rx%3D%2286%22%20ry%3D%2210%22%20fill%3D%22%23e1e8ef%22%2F%3E%20%3Cpath%20d%3D%22M126%2020%20L200%2052%20L200%20118%20L126%20150%20L52%20118%20L52%2052%20Z%22%20fill%3D%22%23d9995b%22%2F%3E%20%3Cpath%20d%3D%22M126%2020%20L200%2052%20L126%2084%20L52%2052%20Z%22%20fill%3D%22%23e8b988%22%2F%3E%20%3Cpath%20d%3D%22M126%2084%20L200%2052%20L200%20118%20L126%20150%20Z%22%20fill%3D%22%23c67f42%22%2F%3E%20%3Cpath%20d%3D%22M126%2084%20L126%20150%22%20stroke%3D%22%23a86a35%22%20stroke-width%3D%224%22%2F%3E%20%3Cpath%20d%3D%22M88%2036%20L162%2068%22%20stroke%3D%22%23f2d9bd%22%20stroke-width%3D%228%22%2F%3E%20%3Cg%20stroke%3D%22%230065b3%22%20stroke-width%3D%226%22%20stroke-linecap%3D%22round%22%3E%20%3Cline%20x1%3D%2212%22%20y1%3D%2266%22%20x2%3D%2232%22%20y2%3D%2266%22%2F%3E%20%3Cline%20x1%3D%224%22%20y1%3D%2290%22%20x2%3D%2230%22%20y2%3D%2290%22%2F%3E%20%3Cline%20x1%3D%2214%22%20y1%3D%22114%22%20x2%3D%2232%22%20y2%3D%22114%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E" width="120" alt="Your parcel, on the move" style="display:block; width:120px; max-width:100%; height:auto; margin:0 auto 18px;" />
19
20
  <p style="margin:0 0 12px; font-family:Arial, Helvetica, sans-serif; font-size:11px; font-weight:bold; letter-spacing:0.2em; text-transform:uppercase; color:#0065b3;">Shipped &middot; Order #48213</p>
20
21
  <h1 style="margin:0 0 10px; font-family:Arial, Helvetica, sans-serif; font-size:24px; line-height:1.3; color:#10243c;">Your order is on its way, {{ first_name }}</h1>
21
22
  <p style="margin:0; font-family:Arial, Helvetica, sans-serif; font-size:14.5px; line-height:1.65; color:#3f5063;">Order <strong>#48213</strong> left our warehouse this morning and arrives <strong>Thursday, 2 September</strong>.</p>
@@ -289,14 +289,7 @@
289
289
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:#f6f1e9; ">
290
290
  <tr>
291
291
  <td width="38%" valign="middle" align="center" style="padding:22px 18px;">
292
- <table role="presentation" cellpadding="0" cellspacing="0" style="background-color:#b85c38; ">
293
- <tr>
294
- <td align="center" style="padding:30px 24px;">
295
- <p style="margin:0 0 4px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.18em; text-transform:uppercase; color:#f3dcc9;">Terracotta</p>
296
- <p style="margin:0; font-family:Georgia, serif; font-size:22px; color:#ffffff;">Trainer</p>
297
- </td>
298
- </tr>
299
- </table>
292
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22340%22%20height%3D%22340%22%20viewBox%3D%220%200%20340%20340%22%3E%20%3Crect%20width%3D%22340%22%20height%3D%22340%22%20fill%3D%22%23b85c38%22%2F%3E%20%3Ccircle%20cx%3D%22264%22%20cy%3D%2272%22%20r%3D%2242%22%20fill%3D%22%23c96f4a%22%2F%3E%20%3Ccircle%20cx%3D%2256%22%20cy%3D%22290%22%20r%3D%2254%22%20fill%3D%22%23a9502e%22%2F%3E%20%3Cellipse%20cx%3D%22172%22%20cy%3D%22252%22%20rx%3D%22120%22%20ry%3D%2213%22%20fill%3D%22%238f4526%22%2F%3E%20%3Cpath%20d%3D%22M52%20222%20Q52%20242%2076%20242%20L268%20242%20Q288%20242%20288%20224%20L288%20216%20Q288%20208%20278%20206%20L62%20206%20Q52%20208%2052%20222%20Z%22%20fill%3D%22%23f3e9dc%22%2F%3E%20%3Cpath%20d%3D%22M62%20208%20Q60%20152%2096%20140%20Q128%20130%20148%20150%20Q170%20172%20210%20178%20L262%20188%20Q286%20194%20286%20208%20Z%22%20fill%3D%22%23e8d9c4%22%2F%3E%20%3Cpath%20d%3D%22M148%20150%20Q170%20172%20210%20178%20L262%20188%20Q286%20194%20286%20208%20L196%20208%20Q170%20198%20156%20174%20Z%22%20fill%3D%22%23caa27f%22%2F%3E%20%3Cpath%20d%3D%22M62%20208%20Q61%20170%2082%20152%20Q68%20172%2070%20208%20Z%22%20fill%3D%22%23d9c3a6%22%2F%3E%20%3Cg%20stroke%3D%22%238f5a3a%22%20stroke-width%3D%226%22%20stroke-linecap%3D%22round%22%3E%20%3Cline%20x1%3D%22112%22%20y1%3D%22152%22%20x2%3D%22140%22%20y2%3D%22166%22%2F%3E%20%3Cline%20x1%3D%22106%22%20y1%3D%22168%22%20x2%3D%22136%22%20y2%3D%22182%22%2F%3E%20%3Cline%20x1%3D%22102%22%20y1%3D%22184%22%20x2%3D%22132%22%20y2%3D%22198%22%2F%3E%20%3C%2Fg%3E%20%3Crect%20x%3D%2258%22%20y%3D%22230%22%20width%3D%22224%22%20height%3D%226%22%20rx%3D%223%22%20fill%3D%22%23d9c3a6%22%2F%3E%20%3C%2Fsvg%3E" width="170" alt="Terracotta Trainer — suede and canvas sneaker" style="display:block; width:170px; max-width:100%; height:auto;" />
300
293
  </td>
301
294
  <td width="62%" valign="middle" style="padding:18px 18px 18px 6px;">
302
295
  <h2 style="margin:0 0 6px; font-family:Georgia, serif; font-size:19px; color:#29241d;">Terracotta Trainer</h2>
@@ -362,14 +355,7 @@
362
355
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border:1px solid #e7e3f2; ">
363
356
  <tr>
364
357
  <td width="30%" valign="middle" align="center" style="padding:22px 16px;">
365
- <table role="presentation" cellpadding="0" cellspacing="0" style="background-color:#7048b8; ">
366
- <tr>
367
- <td align="center" style="padding:26px 22px;">
368
- <p style="margin:0 0 4px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.18em; text-transform:uppercase; color:#dddcf3;">Chestnut</p>
369
- <p style="margin:0; font-family:Georgia, serif; font-size:19px; color:#ffffff;">Weekend bag</p>
370
- </td>
371
- </tr>
372
- </table>
358
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22300%22%20height%3D%22300%22%20viewBox%3D%220%200%20300%20300%22%3E%20%3Crect%20width%3D%22300%22%20height%3D%22300%22%20fill%3D%22%237048b8%22%2F%3E%20%3Ccircle%20cx%3D%22250%22%20cy%3D%2256%22%20r%3D%2236%22%20fill%3D%22%237f57c6%22%2F%3E%20%3Ccircle%20cx%3D%2244%22%20cy%3D%22256%22%20r%3D%2240%22%20fill%3D%22%23633fa8%22%2F%3E%20%3Cellipse%20cx%3D%22150%22%20cy%3D%22236%22%20rx%3D%22106%22%20ry%3D%2211%22%20fill%3D%22%235d3aa0%22%2F%3E%20%3Cpath%20d%3D%22M110%20122%20Q110%2084%20150%2084%20Q190%2084%20190%20122%22%20fill%3D%22none%22%20stroke%3D%22%235c3a1e%22%20stroke-width%3D%2210%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Crect%20x%3D%2258%22%20y%3D%22118%22%20width%3D%22184%22%20height%3D%22114%22%20rx%3D%2226%22%20fill%3D%22%238a5a33%22%2F%3E%20%3Cpath%20d%3D%22M84%20118%20Q58%20118%2058%20144%20L58%20206%20Q58%20232%2084%20232%20Z%22%20fill%3D%22%237a4e2b%22%2F%3E%20%3Cpath%20d%3D%22M216%20118%20Q242%20118%20242%20144%20L242%20206%20Q242%20232%20216%20232%20Z%22%20fill%3D%22%237a4e2b%22%2F%3E%20%3Crect%20x%3D%22106%22%20y%3D%22118%22%20width%3D%2212%22%20height%3D%22114%22%20fill%3D%22%236e4526%22%2F%3E%20%3Crect%20x%3D%22182%22%20y%3D%22118%22%20width%3D%2212%22%20height%3D%22114%22%20fill%3D%22%236e4526%22%2F%3E%20%3Cline%20x1%3D%2298%22%20y1%3D%22134%22%20x2%3D%22202%22%20y2%3D%22134%22%20stroke%3D%22%23e8d9c4%22%20stroke-width%3D%225%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Ccircle%20cx%3D%22202%22%20cy%3D%22134%22%20r%3D%226%22%20fill%3D%22%23e8d9c4%22%2F%3E%20%3C%2Fsvg%3E" width="150" alt="Chestnut leather weekend bag" style="display:block; width:150px; max-width:100%; height:auto;" />
373
359
  </td>
374
360
  <td width="70%" valign="middle" style="padding:16px 16px 16px 4px;">
375
361
  <h2 style="margin:0 0 4px; font-family:Arial, Helvetica, sans-serif; font-size:16px; color:#241b3a;">Leather weekend bag</h2>
@@ -729,6 +715,11 @@
729
715
  <p style="margin:10px 0 0; font-family:Arial, Helvetica, sans-serif; font-size:15px; line-height:1.5; color:#dbeafe;">Our biggest release yet &mdash; and it&rsquo;s already in your account.</p>
730
716
  </td>
731
717
  </tr>
718
+ <tr>
719
+ <td style="padding:0;">
720
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22600%22%20height%3D%22230%22%20viewBox%3D%220%200%20600%20230%22%3E%20%3Crect%20width%3D%22600%22%20height%3D%22230%22%20fill%3D%22%230b1020%22%2F%3E%20%3Ccircle%20cx%3D%22524%22%20cy%3D%2230%22%20r%3D%2296%22%20fill%3D%22%23111832%22%2F%3E%20%3Ccircle%20cx%3D%2260%22%20cy%3D%22216%22%20r%3D%2280%22%20fill%3D%22%23111832%22%2F%3E%20%3Crect%20x%3D%22150%22%20y%3D%2240%22%20width%3D%22300%22%20height%3D%22172%22%20rx%3D%2212%22%20fill%3D%22%2316203c%22%2F%3E%20%3Cpath%20d%3D%22M150%2052%20Q150%2040%20162%2040%20L438%2040%20Q450%2040%20450%2052%20L450%2072%20L150%2072%20Z%22%20fill%3D%22%231c2848%22%2F%3E%20%3Ccircle%20cx%3D%22172%22%20cy%3D%2256%22%20r%3D%225%22%20fill%3D%22%2358a8e3%22%2F%3E%20%3Ccircle%20cx%3D%22190%22%20cy%3D%2256%22%20r%3D%225%22%20fill%3D%22%233b6ea5%22%2F%3E%20%3Ccircle%20cx%3D%22208%22%20cy%3D%2256%22%20r%3D%225%22%20fill%3D%22%2328497a%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%2290%22%20width%3D%22122%22%20height%3D%2214%22%20rx%3D%227%22%20fill%3D%22%232b3d69%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22118%22%20width%3D%22264%22%20height%3D%2210%22%20rx%3D%225%22%20fill%3D%22%2322335c%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22136%22%20width%3D%22236%22%20height%3D%2210%22%20rx%3D%225%22%20fill%3D%22%2322335c%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22154%22%20width%3D%22250%22%20height%3D%2210%22%20rx%3D%225%22%20fill%3D%22%2322335c%22%2F%3E%20%3Crect%20x%3D%22168%22%20y%3D%22180%22%20width%3D%2298%22%20height%3D%2220%22%20rx%3D%2210%22%20fill%3D%22%2358a8e3%22%2F%3E%20%3Cpath%20d%3D%22M470%2084%20L479%20108%20L502%20117%20L479%20126%20L470%20150%20L461%20126%20L438%20117%20L461%20108%20Z%22%20fill%3D%22%23d9e9f9%22%2F%3E%20%3Cpath%20d%3D%22M502%2056%20L506%2067%20L517%2071%20L506%2075%20L502%2086%20L498%2075%20L487%2071%20L498%2067%20Z%22%20fill%3D%22%2358a8e3%22%2F%3E%20%3C%2Fsvg%3E" width="600" alt="Nova — the new workspace" style="display:block; width:100%; max-width:600px; height:auto;" />
721
+ </td>
722
+ </tr>
732
723
  <tr>
733
724
  <td align="center" style="padding:32px 36px 6px;">
734
725
  <h2 style="margin:0 0 12px; font-family:Arial, Helvetica, sans-serif; font-size:21px; line-height:1.3; color:#ffffff;">Everything you asked for, in one update</h2>
@@ -960,14 +951,7 @@
960
951
  <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background-color:#f6f9fd; ">
961
952
  <tr>
962
953
  <td valign="middle" width="30%" align="center" style="padding:22px 16px;">
963
- <table role="presentation" cellpadding="0" cellspacing="0" style="background-color:#16233a; ">
964
- <tr>
965
- <td align="center" style="padding:24px 20px;">
966
- <p style="margin:0 0 4px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.18em; text-transform:uppercase; color:#93a7c4;">Studio</p>
967
- <p style="margin:0; font-family:Georgia, serif; font-size:18px; color:#ffffff;">MK II</p>
968
- </td>
969
- </tr>
970
- </table>
954
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22280%22%20height%3D%22280%22%20viewBox%3D%220%200%20280%20280%22%3E%20%3Crect%20width%3D%22280%22%20height%3D%22280%22%20fill%3D%22%2316233a%22%2F%3E%20%3Ccircle%20cx%3D%22230%22%20cy%3D%2250%22%20r%3D%2232%22%20fill%3D%22%231e2f4d%22%2F%3E%20%3Ccircle%20cx%3D%2244%22%20cy%3D%22240%22%20r%3D%2242%22%20fill%3D%22%23121c30%22%2F%3E%20%3Cpath%20d%3D%22M70%20162%20L70%20120%20Q70%2050%20140%2050%20Q210%2050%20210%20120%20L210%20162%22%20fill%3D%22none%22%20stroke%3D%22%23dbe5f2%22%20stroke-width%3D%2214%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Cline%20x1%3D%2270%22%20y1%3D%22152%22%20x2%3D%2270%22%20y2%3D%22178%22%20stroke%3D%22%2393a7c4%22%20stroke-width%3D%228%22%2F%3E%20%3Cline%20x1%3D%22210%22%20y1%3D%22152%22%20x2%3D%22210%22%20y2%3D%22178%22%20stroke%3D%22%2393a7c4%22%20stroke-width%3D%228%22%2F%3E%20%3Crect%20x%3D%2246%22%20y%3D%22168%22%20width%3D%2248%22%20height%3D%2266%22%20rx%3D%2220%22%20fill%3D%22%23dbe5f2%22%2F%3E%20%3Crect%20x%3D%22186%22%20y%3D%22168%22%20width%3D%2248%22%20height%3D%2266%22%20rx%3D%2220%22%20fill%3D%22%23dbe5f2%22%2F%3E%20%3Crect%20x%3D%2258%22%20y%3D%22178%22%20width%3D%2224%22%20height%3D%2246%22%20rx%3D%2212%22%20fill%3D%22%2393a7c4%22%2F%3E%20%3Crect%20x%3D%22198%22%20y%3D%22178%22%20width%3D%2224%22%20height%3D%2246%22%20rx%3D%2212%22%20fill%3D%22%2393a7c4%22%2F%3E%20%3C%2Fsvg%3E" width="140" alt="Studio Headphones MK II" style="display:block; width:140px; max-width:100%; height:auto;" />
971
955
  </td>
972
956
  <td valign="middle" width="70%" style="padding:16px 16px 16px 4px;">
973
957
  <h2 style="margin:0 0 4px; font-family:Arial, Helvetica, sans-serif; font-size:15.5px; color:#16233a;">Studio Headphones MK II</h2>
@@ -1142,6 +1126,11 @@
1142
1126
  <tr>
1143
1127
  <td style="height:5px; line-height:5px; font-size:0; background-color:#a06b2c;">&nbsp;</td>
1144
1128
  </tr>
1129
+ <tr>
1130
+ <td style="padding:0;">
1131
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22600%22%20height%3D%22250%22%20viewBox%3D%220%200%20600%20250%22%3E%20%3Crect%20width%3D%22600%22%20height%3D%22250%22%20fill%3D%22%23eee9dd%22%2F%3E%20%3Ccircle%20cx%3D%22176%22%20cy%3D%22158%22%20r%3D%2266%22%20fill%3D%22%23d9a05b%22%2F%3E%20%3Ccircle%20cx%3D%22176%22%20cy%3D%22158%22%20r%3D%2266%22%20fill%3D%22none%22%20stroke%3D%22%23a06b2c%22%20stroke-width%3D%223%22%2F%3E%20%3Cg%20stroke%3D%22%23a06b2c%22%20stroke-width%3D%223%22%20stroke-linecap%3D%22round%22%3E%20%3Cline%20x1%3D%22176%22%20y1%3D%2266%22%20x2%3D%22176%22%20y2%3D%2248%22%2F%3E%20%3Cline%20x1%3D%22224%22%20y1%3D%2284%22%20x2%3D%22238%22%20y2%3D%2270%22%2F%3E%20%3Cline%20x1%3D%22128%22%20y1%3D%2284%22%20x2%3D%22114%22%20y2%3D%2270%22%2F%3E%20%3C%2Fg%3E%20%3Cpath%20d%3D%22M370%2078%20q9%20-9%2018%200%20M398%2092%20q8%20-8%2016%200%20M348%20100%20q7%20-7%2014%200%22%20stroke%3D%22%231c1b18%22%20stroke-width%3D%223%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%2F%3E%20%3Cpath%20d%3D%22M0%20202%20Q100%20140%20220%20190%20Q330%20234%20420%20192%20Q510%20152%20600%20182%20L600%20250%20L0%20250%20Z%22%20fill%3D%22%231c1b18%22%2F%3E%20%3Cpath%20d%3D%22M0%20222%20Q140%20180%20300%20214%20Q450%20244%20600%20212%20L600%20250%20L0%20250%20Z%22%20fill%3D%22%233d3a33%22%2F%3E%20%3C%2Fsvg%3E" width="600" alt="Morning sun over quiet hills" style="display:block; width:100%; max-width:600px; height:auto;" />
1132
+ </td>
1133
+ </tr>
1145
1134
  <tr>
1146
1135
  <td align="center" style="background-color:#f6f4ee; padding:36px 40px 34px; border-bottom:1px solid #e3e0d8;">
1147
1136
  <p style="margin:0 0 10px; font-family:Georgia, serif; font-size:12px; letter-spacing:0.14em; text-transform:uppercase; color:#a06b2c;">Cover story</p>
@@ -1253,6 +1242,7 @@
1253
1242
  </tr>
1254
1243
  <tr>
1255
1244
  <td align="center" style="padding:34px 36px 8px;">
1245
+ <img src="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22240%22%20height%3D%22170%22%20viewBox%3D%220%200%20240%20170%22%3E%20%3Cellipse%20cx%3D%22126%22%20cy%3D%22150%22%20rx%3D%2286%22%20ry%3D%2210%22%20fill%3D%22%23e1e8ef%22%2F%3E%20%3Cpath%20d%3D%22M126%2020%20L200%2052%20L200%20118%20L126%20150%20L52%20118%20L52%2052%20Z%22%20fill%3D%22%23d9995b%22%2F%3E%20%3Cpath%20d%3D%22M126%2020%20L200%2052%20L126%2084%20L52%2052%20Z%22%20fill%3D%22%23e8b988%22%2F%3E%20%3Cpath%20d%3D%22M126%2084%20L200%2052%20L200%20118%20L126%20150%20Z%22%20fill%3D%22%23c67f42%22%2F%3E%20%3Cpath%20d%3D%22M126%2084%20L126%20150%22%20stroke%3D%22%23a86a35%22%20stroke-width%3D%224%22%2F%3E%20%3Cpath%20d%3D%22M88%2036%20L162%2068%22%20stroke%3D%22%23f2d9bd%22%20stroke-width%3D%228%22%2F%3E%20%3Cg%20stroke%3D%22%230065b3%22%20stroke-width%3D%226%22%20stroke-linecap%3D%22round%22%3E%20%3Cline%20x1%3D%2212%22%20y1%3D%2266%22%20x2%3D%2232%22%20y2%3D%2266%22%2F%3E%20%3Cline%20x1%3D%224%22%20y1%3D%2290%22%20x2%3D%2230%22%20y2%3D%2290%22%2F%3E%20%3Cline%20x1%3D%2214%22%20y1%3D%22114%22%20x2%3D%2232%22%20y2%3D%22114%22%2F%3E%20%3C%2Fg%3E%20%3C%2Fsvg%3E" width="120" alt="Your parcel, on the move" style="display:block; width:120px; max-width:100%; height:auto; margin:0 auto 18px;" />
1256
1246
  <p style="margin:0 0 12px; font-family:Arial, Helvetica, sans-serif; font-size:11px; font-weight:bold; letter-spacing:0.2em; text-transform:uppercase; color:#0065b3;">Shipped &middot; Order #48213</p>
1257
1247
  <h1 style="margin:0 0 10px; font-family:Arial, Helvetica, sans-serif; font-size:24px; line-height:1.3; color:#10243c;">Your order is on its way, {{ first_name }}</h1>
1258
1248
  <p style="margin:0; font-family:Arial, Helvetica, sans-serif; font-size:14.5px; line-height:1.65; color:#3f5063;">Order <strong>#48213</strong> left our warehouse this morning and arrives <strong>Thursday, 2 September</strong>.</p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seliseblocks/mailcraft",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Framework-agnostic drag-and-drop email template editor, packaged as a zero-dependency Web Component.",
5
5
  "license": "MIT",
6
6
  "author": "SELISE Digital Platforms",
@@ -580,7 +580,7 @@ export class EditorCore {
580
580
  * dragging through uniformly-formatted text rebuilds nothing at all.
581
581
  */
582
582
  formatFingerprint(b) {
583
- let s = b.id + '|' + this.currentTag() + '|' + (b.props.size || 16) + '|' + (this.state.linkDraft ? 1 : 0) + '|';
583
+ let s = b.id + '|' + this.currentTag() + '|' + this.selSize(b) + '|' + (this.state.linkDraft ? 1 : 0) + '|';
584
584
  for (const cmd of ['bold', 'italic', 'underline', 'strikeThrough', 'superscript', 'subscript', 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', 'insertUnorderedList', 'insertOrderedList']) {
585
585
  let on = false;
586
586
  try { on = document.queryCommandState(cmd); } catch { /* ignore */ }
@@ -622,6 +622,13 @@ export class EditorCore {
622
622
  };
623
623
 
624
624
  size(b, delta) {
625
+ // A non-collapsed selection inside a rich text block means the user is
626
+ // sizing a *run*, not the block -- every neighbouring control (bold,
627
+ // color, highlight) is selection-scoped, so a ± that rewrote the whole
628
+ // block's prop here read as broken. Only `text` can keep the resulting
629
+ // spans: a heading folds back through `textContent` (syncEdit), which
630
+ // would silently drop them, so it stays block-level.
631
+ if (b.type === 'text' && this.sizeSelection(b, delta)) return;
625
632
  // Uncommitted inline formatting is folded into props by `setProp` below
626
633
  // (`onFoldLiveEdit`), not here. This used to do its own fold, as a second
627
634
  // commit: that read `editEl.innerHTML` unconditionally, so a second click
@@ -639,6 +646,114 @@ export class EditorCore {
639
646
  this.setProp(b.id, 'size', Math.max(lo, Math.min(hi, cur + delta)));
640
647
  }
641
648
 
649
+ /** Nearest inline px font-size walking up from `node` to the edited block's wrapper -- null when no run declares one (the block prop then owns the size). */
650
+ inlineSizeAt(node) {
651
+ let n = node && node.nodeType === 1 ? node : (node ? node.parentElement : null);
652
+ while (n && n !== this.editEl) {
653
+ const m = /^([\d.]+)px$/.exec((n.style && n.style.fontSize) || '');
654
+ if (m) return parseFloat(m[1]);
655
+ n = n.parentElement;
656
+ }
657
+ return null;
658
+ }
659
+
660
+ /** What the ± readout should show: the inline size at the selection when the caret sits inside a sized run, else the block's own size. Also part of `formatFingerprint`, so moving the caret across differently-sized runs refreshes the toolbar. */
661
+ selSize(b) {
662
+ const live = this.find(this.state.doc, b.id).block || b;
663
+ const base = Number(live.props.size) || 16;
664
+ if (b.type !== 'text' || this.state.editing !== b.id || !this.editEl) return base;
665
+ const sel = this.getSelection();
666
+ const node = sel && sel.rangeCount && this.editEl.contains(sel.anchorNode)
667
+ ? sel.anchorNode
668
+ : (this.savedRange && this.editEl.contains(this.savedRange.startContainer) ? this.savedRange.startContainer : null);
669
+ const inline = node ? this.inlineSizeAt(node) : null;
670
+ return inline == null ? base : Math.round(inline);
671
+ }
672
+
673
+ /**
674
+ * Sizes just the selected run(s) of text by wrapping each selected text node
675
+ * in a `font-size` span (or restepping the span a previous click made --
676
+ * repeated ± must not nest one span per click). Wrapping happens at the text
677
+ * node, the innermost level, so the new size always outranks any inline size
678
+ * an imported ancestor carries. The change lives in the contenteditable like
679
+ * bold/italic do and folds into props through the same blur/commit path.
680
+ *
681
+ * Returns false when the click is not selection-scoped -- no live edit, a
682
+ * bare caret, or a selection covering the whole block. The last keeps
683
+ * select-all + ± behaving as the block-level master scale it always was
684
+ * (`syncRichContent` then *scales* mixed sizes instead of flattening them,
685
+ * and the saved `size` prop stays truthful).
686
+ */
687
+ sizeSelection(b, delta) {
688
+ const root = this.editEl;
689
+ if (!root || !root.isConnected || this.state.editing !== b.id) return false;
690
+ const sel = this.getSelection();
691
+ // Same fallback discipline as `exec`: the live selection wins when it is
692
+ // inside the edited block; `savedRange` covers focus stolen by a control.
693
+ let src = sel && sel.rangeCount && root.contains(sel.anchorNode) && root.contains(sel.focusNode) ? sel.getRangeAt(0) : null;
694
+ if (!src && this.savedRange && root.contains(this.savedRange.startContainer) && root.contains(this.savedRange.endContainer)) src = this.savedRange;
695
+ if (!src || src.collapsed) return false;
696
+ const range = src.cloneRange();
697
+ const total = root.textContent.length;
698
+ if (charOffset(root, range.startContainer, range.startOffset) === 0
699
+ && charOffset(root, range.endContainer, range.endOffset) === total) return false;
700
+
701
+ const [lo, hi] = SIZE_SPAN.text;
702
+ const live = this.find(this.state.doc, b.id).block || b;
703
+ const cur = this.inlineSizeAt(range.startContainer) || Number(live.props.size) || 16;
704
+ const next = Math.max(lo, Math.min(hi, Math.round(cur) + delta));
705
+
706
+ // Split the boundary text nodes so every text node intersecting the range
707
+ // is *fully* inside it; order matters when both ends share one node.
708
+ const endC = range.endContainer;
709
+ if (endC.nodeType === 3 && range.endOffset < endC.nodeValue.length) endC.splitText(range.endOffset);
710
+ const startC = range.startContainer;
711
+ if (startC.nodeType === 3 && range.startOffset > 0) {
712
+ const tail = startC.splitText(range.startOffset);
713
+ range.setStart(tail, 0);
714
+ if (endC === startC) range.setEnd(tail, tail.nodeValue.length);
715
+ }
716
+ const s = charOffset(root, range.startContainer, range.startOffset);
717
+ const e = charOffset(root, range.endContainer, range.endOffset);
718
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
719
+ const hits = [];
720
+ let pos = 0; let tn;
721
+ while ((tn = walker.nextNode())) {
722
+ const len = tn.nodeValue.length;
723
+ if (len && pos >= s && pos + len <= e) hits.push(tn);
724
+ pos += len;
725
+ if (pos >= e) break;
726
+ }
727
+ // Something non-text was selected (an image, say): still handled -- the
728
+ // click must not fall through and resize the whole block.
729
+ if (!hits.length) return true;
730
+ const wraps = hits.map((node) => {
731
+ const parent = node.parentElement;
732
+ if (parent && parent !== root && parent.tagName === 'SPAN' && parent.childNodes.length === 1) {
733
+ parent.style.fontSize = next + 'px';
734
+ return parent;
735
+ }
736
+ const span = document.createElement('span');
737
+ span.style.fontSize = next + 'px';
738
+ node.replaceWith(span);
739
+ span.appendChild(node);
740
+ return span;
741
+ });
742
+ // Reselect the runs so the next ± click steps from here, and cache the
743
+ // range the way `exec` does for controls that steal focus. Boundaries go
744
+ // *inside* the first/last wrap (each holds exactly one text node), so the
745
+ // selection anchor sits under the new span and `selSize` reads it for the
746
+ // toolbar readout.
747
+ const first = wraps[0].firstChild;
748
+ const last = wraps[wraps.length - 1].lastChild;
749
+ const r2 = document.createRange();
750
+ r2.setStart(first, 0);
751
+ r2.setEnd(last, last.nodeValue.length);
752
+ if (sel) { sel.removeAllRanges(); sel.addRange(r2); }
753
+ this.savedRange = r2.cloneRange();
754
+ return true;
755
+ }
756
+
642
757
  hasCountdown() { return this.state.doc.rows.some((r) => r.cols.some((c) => c.blocks.some((b) => b.type === 'countdown'))); }
643
758
 
644
759
  persist(doc, assets, chrome) {
@@ -204,7 +204,6 @@ export const AR = {
204
204
  'rte.highlightColor': 'لون التمييز',
205
205
  'rte.removeHighlight': 'إزالة التمييز',
206
206
  'rte.clearFormatting': 'مسح التنسيق',
207
- 'action.downloadPng': 'تنزيل PNG',
208
207
  'action.screenshot': 'لقطة شاشة',
209
208
  'action.screenshotHint': 'معاينة القالب كاملاً كصورة، ثم تنزيله',
210
209
  'toast.pngSaved': 'تم تنزيل لقطة الشاشة',
@@ -221,6 +220,8 @@ export const AR = {
221
220
  'story.pause': 'إيقاف مؤقت',
222
221
  'story.replay': 'إعادة التشغيل',
223
222
  'story.copy': 'نسخ',
223
+ 'story.download': 'تنزيل {fmt}',
224
+ 'story.format': 'صيغة الصورة — PNG بلا فقدان، وJPG وWebP ملفات أصغر',
224
225
  'story.meta': '{w}×{h} · شاشة {i} من {n}',
225
226
  'footer.poweredBy': 'مدعوم من SELISE Blocks © 2026',
226
227
  };
@@ -181,7 +181,6 @@ export const BG = {
181
181
  'rte.highlightColor': 'Цвят на маркиране',
182
182
  'rte.removeHighlight': 'Премахване на маркирането',
183
183
  'rte.clearFormatting': 'Изчистване на форматирането',
184
- 'action.downloadPng': 'Изтегляне на PNG',
185
184
  'action.screenshot': 'Екранна снимка',
186
185
  'action.screenshotHint': 'Прегледайте целия шаблон като изображение и го изтеглете',
187
186
  'toast.pngSaved': 'Екранната снимка е изтеглена',
@@ -198,6 +197,8 @@ export const BG = {
198
197
  'story.pause': 'Пауза',
199
198
  'story.replay': 'Отначало',
200
199
  'story.copy': 'Копиране',
200
+ 'story.download': 'Изтегляне на {fmt}',
201
+ 'story.format': 'Формат на изображението — PNG е без загуби, JPG и WebP са по-малки файлове',
201
202
  'story.meta': '{w}×{h} · екран {i} от {n}',
202
203
  'footer.poweredBy': 'С технологията на SELISE Blocks © 2026',
203
204
  };
@@ -203,7 +203,6 @@ export const BN = {
203
203
  'rte.highlightColor': 'হাইলাইট রং',
204
204
  'rte.removeHighlight': 'হাইলাইট সরান',
205
205
  'rte.clearFormatting': 'ফরম্যাটিং মুছুন',
206
- 'action.downloadPng': 'PNG ডাউনলোড',
207
206
  'action.screenshot': 'স্ক্রিনশট',
208
207
  'action.screenshotHint': 'পুরো টেমপ্লেট ছবি হিসেবে দেখুন, তারপর ডাউনলোড করুন',
209
208
  'toast.pngSaved': 'স্ক্রিনশট ডাউনলোড হয়েছে',
@@ -220,6 +219,8 @@ export const BN = {
220
219
  'story.pause': 'থামান',
221
220
  'story.replay': 'আবার চালান',
222
221
  'story.copy': 'কপি',
222
+ 'story.download': '{fmt} ডাউনলোড',
223
+ 'story.format': 'ছবির ফরম্যাট — PNG লসলেস, JPG ও WebP ফাইল ছোট',
223
224
  'story.meta': '{w}×{h} · স্ক্রিন {i} / {n}',
224
225
  'footer.poweredBy': 'SELISE Blocks দ্বারা পরিচালিত © 2026',
225
226
  };
@@ -181,7 +181,6 @@ export const CA = {
181
181
  'rte.highlightColor': 'Color de ressaltat',
182
182
  'rte.removeHighlight': 'Treu el ressaltat',
183
183
  'rte.clearFormatting': 'Neteja el format',
184
- 'action.downloadPng': 'Baixa el PNG',
185
184
  'action.screenshot': 'Captura',
186
185
  'action.screenshotHint': 'Previsualitza tota la plantilla com a imatge i baixa-la',
187
186
  'toast.pngSaved': 'Captura baixada',
@@ -198,6 +197,8 @@ export const CA = {
198
197
  'story.pause': 'Pausa',
199
198
  'story.replay': 'Torna a reproduir',
200
199
  'story.copy': 'Copia',
200
+ 'story.download': 'Baixa el {fmt}',
201
+ 'story.format': 'Format de la imatge — el PNG és sense pèrdues; JPG i WebP són fitxers més petits',
201
202
  'story.meta': '{w}×{h} · pantalla {i} de {n}',
202
203
  'footer.poweredBy': 'Amb la tecnologia de SELISE Blocks © 2026',
203
204
  };
@@ -181,7 +181,6 @@ export const CS = {
181
181
  'rte.highlightColor': 'Barva zvýraznění',
182
182
  'rte.removeHighlight': 'Odebrat zvýraznění',
183
183
  'rte.clearFormatting': 'Zrušit formátování',
184
- 'action.downloadPng': 'Stáhnout PNG',
185
184
  'action.screenshot': 'Snímek',
186
185
  'action.screenshotHint': 'Zobrazit celou šablonu jako obrázek a stáhnout ji',
187
186
  'toast.pngSaved': 'Snímek stažen',
@@ -198,6 +197,8 @@ export const CS = {
198
197
  'story.pause': 'Pozastavit',
199
198
  'story.replay': 'Přehrát znovu',
200
199
  'story.copy': 'Kopírovat',
200
+ 'story.download': 'Stáhnout {fmt}',
201
+ 'story.format': 'Formát obrázku — PNG je bezeztrátový, JPG a WebP jsou menší soubory',
201
202
  'story.meta': '{w}×{h} · obrazovka {i} z {n}',
202
203
  'footer.poweredBy': 'Běží na SELISE Blocks © 2026',
203
204
  };
@@ -181,7 +181,6 @@ export const DA = {
181
181
  'rte.highlightColor': 'Fremhævningsfarve',
182
182
  'rte.removeHighlight': 'Fjern fremhævning',
183
183
  'rte.clearFormatting': 'Ryd formatering',
184
- 'action.downloadPng': 'Hent PNG',
185
184
  'action.screenshot': 'Skærmbillede',
186
185
  'action.screenshotHint': 'Se hele skabelonen som et billede, og hent det',
187
186
  'toast.pngSaved': 'Skærmbillede hentet',
@@ -198,6 +197,8 @@ export const DA = {
198
197
  'story.pause': 'Pause',
199
198
  'story.replay': 'Afspil igen',
200
199
  'story.copy': 'Kopiér',
200
+ 'story.download': 'Hent {fmt}',
201
+ 'story.format': 'Billedformat — PNG er tabsfrit, JPG og WebP er mindre filer',
201
202
  'story.meta': '{w}×{h} · skærm {i} af {n}',
202
203
  'footer.poweredBy': 'Drevet af SELISE Blocks © 2026',
203
204
  };
@@ -181,7 +181,6 @@ export const DE_CH = {
181
181
  'rte.highlightColor': 'Markierungsfarbe',
182
182
  'rte.removeHighlight': 'Markierung entfernen',
183
183
  'rte.clearFormatting': 'Formatierung entfernen',
184
- 'action.downloadPng': 'PNG herunterladen',
185
184
  'action.screenshot': 'Screenshot',
186
185
  'action.screenshotHint': 'Die ganze Vorlage als Bild ansehen und herunterladen',
187
186
  'toast.pngSaved': 'Screenshot heruntergeladen',
@@ -198,6 +197,8 @@ export const DE_CH = {
198
197
  'story.pause': 'Pause',
199
198
  'story.replay': 'Nochmals abspielen',
200
199
  'story.copy': 'Kopieren',
200
+ 'story.download': '{fmt} herunterladen',
201
+ 'story.format': 'Bildformat — PNG ist verlustfrei, JPG und WebP sind kleinere Dateien',
201
202
  'story.meta': '{w}×{h} · Ansicht {i} von {n}',
202
203
  'footer.poweredBy': 'Bereitgestellt von SELISE Blocks © 2026',
203
204
  };
@@ -181,7 +181,6 @@ export const DE = {
181
181
  'rte.highlightColor': 'Markierungsfarbe',
182
182
  'rte.removeHighlight': 'Markierung entfernen',
183
183
  'rte.clearFormatting': 'Formatierung entfernen',
184
- 'action.downloadPng': 'PNG herunterladen',
185
184
  'action.screenshot': 'Screenshot',
186
185
  'action.screenshotHint': 'Die gesamte Vorlage als Bild ansehen und herunterladen',
187
186
  'toast.pngSaved': 'Screenshot heruntergeladen',
@@ -198,6 +197,8 @@ export const DE = {
198
197
  'story.pause': 'Pause',
199
198
  'story.replay': 'Erneut abspielen',
200
199
  'story.copy': 'Kopieren',
200
+ 'story.download': '{fmt} herunterladen',
201
+ 'story.format': 'Bildformat — PNG ist verlustfrei, JPG und WebP sind kleinere Dateien',
201
202
  'story.meta': '{w}×{h} · Ansicht {i} von {n}',
202
203
  'footer.poweredBy': 'Bereitgestellt von SELISE Blocks © 2026',
203
204
  };
@@ -206,7 +206,6 @@ export const DZ = {
206
206
  'rte.highlightColor': 'གསལ་སྟོན་ཚོས་གཞི',
207
207
  'rte.removeHighlight': 'གསལ་སྟོན་རྩ་བསྐྲད',
208
208
  'rte.clearFormatting': 'རྣམ་གཞག་བསུབ',
209
- 'action.downloadPng': 'PNG ཕབ་ལེན',
210
209
  'action.screenshot': 'བརྙན་ཤེལ་པར',
211
210
  'action.screenshotHint': 'ཊེམ་པེལེཊ་ཧྲིལ་བུ་པར་བཟུམ་སྦེ་བལྟ་ཞིནམ་ལས་ཕབ་ལེན་འབད',
212
211
  'toast.pngSaved': 'བརྙན་ཤེལ་པར་ཕབ་ལེན་བྱུང',
@@ -223,6 +222,8 @@ export const DZ = {
223
222
  'story.pause': 'འཕྲལ་བཀག',
224
223
  'story.replay': 'སླར་གཏང',
225
224
  'story.copy': 'འདྲ་བཤུས',
225
+ 'story.download': '{fmt} ཕབ་ལེན',
226
+ 'story.format': 'པར་གྱི་རྣམ་གཞག — PNG ཉམས་ཆག་མེད། JPG དང་ WebP ཡིག་སྣོད་ཆུང་ཀུ་ཨིན',
226
227
  'story.meta': '{w}×{h} · གསལ་གཞི {i}/{n}',
227
228
  'footer.poweredBy': 'SELISE Blocks གིས་མཁོ་སྤྲོད © 2026',
228
229
  };
@@ -181,7 +181,6 @@ export const EL = {
181
181
  'rte.highlightColor': 'Χρώμα επισήμανσης',
182
182
  'rte.removeHighlight': 'Αφαίρεση επισήμανσης',
183
183
  'rte.clearFormatting': 'Καθαρισμός μορφοποίησης',
184
- 'action.downloadPng': 'Λήψη PNG',
185
184
  'action.screenshot': 'Στιγμιότυπο',
186
185
  'action.screenshotHint': 'Δείτε όλο το πρότυπο ως εικόνα και κατεβάστε το',
187
186
  'toast.pngSaved': 'Το στιγμιότυπο κατέβηκε',
@@ -198,6 +197,8 @@ export const EL = {
198
197
  'story.pause': 'Παύση',
199
198
  'story.replay': 'Επανάληψη',
200
199
  'story.copy': 'Αντιγραφή',
200
+ 'story.download': 'Λήψη {fmt}',
201
+ 'story.format': 'Μορφή εικόνας — το PNG είναι χωρίς απώλειες, τα JPG και WebP είναι μικρότερα αρχεία',
201
202
  'story.meta': '{w}×{h} · οθόνη {i} από {n}',
202
203
  'footer.poweredBy': 'Με την υποστήριξη του SELISE Blocks © 2026',
203
204
  };
@@ -238,7 +238,6 @@ export const EN = {
238
238
  'rte.clearFormatting': 'Clear formatting',
239
239
 
240
240
  // Screenshot export (export modal / element `screenshotPng()`)
241
- 'action.downloadPng': 'Download PNG',
242
241
  'action.screenshot': 'Screenshot',
243
242
  'action.screenshotHint': 'Preview the full template as an image, then download it',
244
243
  'toast.pngSaved': 'Screenshot downloaded',
@@ -257,6 +256,8 @@ export const EN = {
257
256
  'story.pause': 'Pause',
258
257
  'story.replay': 'Replay',
259
258
  'story.copy': 'Copy',
259
+ 'story.download': 'Download {fmt}',
260
+ 'story.format': 'Image format — PNG is lossless, JPG and WebP are smaller files',
260
261
  'story.meta': '{w}×{h} · screen {i} of {n}',
261
262
 
262
263
  // Footer strip (core/footer.js). One string, so a translator localizes
@@ -181,7 +181,6 @@ export const ES = {
181
181
  'rte.highlightColor': 'Color de resaltado',
182
182
  'rte.removeHighlight': 'Quitar resaltado',
183
183
  'rte.clearFormatting': 'Borrar formato',
184
- 'action.downloadPng': 'Descargar PNG',
185
184
  'action.screenshot': 'Captura',
186
185
  'action.screenshotHint': 'Ver toda la plantilla como imagen y descargarla',
187
186
  'toast.pngSaved': 'Captura descargada',
@@ -198,6 +197,8 @@ export const ES = {
198
197
  'story.pause': 'Pausar',
199
198
  'story.replay': 'Repetir',
200
199
  'story.copy': 'Copiar',
200
+ 'story.download': 'Descargar {fmt}',
201
+ 'story.format': 'Formato de imagen — PNG no tiene pérdidas; JPG y WebP son archivos más pequeños',
201
202
  'story.meta': '{w}×{h} · pantalla {i} de {n}',
202
203
  'footer.poweredBy': 'Con la tecnología de SELISE Blocks © 2026',
203
204
  };
@@ -181,7 +181,6 @@ export const ET = {
181
181
  'rte.highlightColor': 'Esiletõstu värv',
182
182
  'rte.removeHighlight': 'Eemalda esiletõst',
183
183
  'rte.clearFormatting': 'Eemalda vorming',
184
- 'action.downloadPng': 'Laadi PNG alla',
185
184
  'action.screenshot': 'Kuvatõmmis',
186
185
  'action.screenshotHint': 'Vaata kogu malli pildina ja laadi see alla',
187
186
  'toast.pngSaved': 'Kuvatõmmis laaditi alla',
@@ -198,6 +197,8 @@ export const ET = {
198
197
  'story.pause': 'Peata',
199
198
  'story.replay': 'Esita uuesti',
200
199
  'story.copy': 'Kopeeri',
200
+ 'story.download': 'Laadi {fmt} alla',
201
+ 'story.format': 'Pildivorming — PNG on kadudeta, JPG ja WebP on väiksemad failid',
201
202
  'story.meta': '{w}×{h} · vaade {i}/{n}',
202
203
  'footer.poweredBy': 'Töötab SELISE Blocks © 2026 põhjal',
203
204
  };
@@ -181,7 +181,6 @@ export const FI = {
181
181
  'rte.highlightColor': 'Korostusväri',
182
182
  'rte.removeHighlight': 'Poista korostus',
183
183
  'rte.clearFormatting': 'Poista muotoilut',
184
- 'action.downloadPng': 'Lataa PNG',
185
184
  'action.screenshot': 'Kuvakaappaus',
186
185
  'action.screenshotHint': 'Katso koko pohja kuvana ja lataa se',
187
186
  'toast.pngSaved': 'Kuvakaappaus ladattiin',
@@ -198,6 +197,8 @@ export const FI = {
198
197
  'story.pause': 'Keskeytä',
199
198
  'story.replay': 'Toista uudelleen',
200
199
  'story.copy': 'Kopioi',
200
+ 'story.download': 'Lataa {fmt}',
201
+ 'story.format': 'Kuvamuoto — PNG on häviötön, JPG ja WebP ovat pienempiä tiedostoja',
201
202
  'story.meta': '{w}×{h} · näkymä {i}/{n}',
202
203
  'footer.poweredBy': 'Taustalla SELISE Blocks © 2026',
203
204
  };