@panphora/clayjs 1.22.0 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/all.js +1 -1
  2. package/dist/clay-dom.js +1 -1
  3. package/dist/clay-events.js +1 -1
  4. package/dist/clay-internals.js +1 -1
  5. package/dist/clay-options.js +1 -1
  6. package/dist/clay-router.js +1 -1
  7. package/dist/clay-ui.js +1 -1
  8. package/dist/clay-utils.js +1 -1
  9. package/dist/clay.js +1 -1
  10. package/dist/clay.standalone.js +1228 -715
  11. package/dist/m/attrs/{save-freeze-MTFVVYV5.js → save-freeze-JZHKRQLR.js} +1 -1
  12. package/dist/m/{c-TV7JHSRL.js → c-24PMUJIV.js} +1 -1
  13. package/dist/m/{c-NBNRLZXO.js → c-2AYVYEI4.js} +1 -1
  14. package/dist/m/{c-VIW5X35H.js → c-2L6O5PDS.js} +1 -1
  15. package/dist/m/{c-FNIGX4FI.js → c-2RYOGUQM.js} +1 -1
  16. package/dist/m/{c-LDUNOR57.js → c-2Z22FCFK.js} +13 -25
  17. package/dist/m/{c-DKFSOJCV.js → c-2ZVOEU4M.js} +1 -1
  18. package/dist/m/{c-BJPZCWAV.js → c-37NAONZA.js} +1 -1
  19. package/dist/m/{c-CSNE5EIF.js → c-4PO3YGDC.js} +1 -1
  20. package/dist/m/{c-UWT4CXQ4.js → c-5OJ7YF2N.js} +1 -1
  21. package/dist/m/{c-CAWNFER6.js → c-5TIZ2I64.js} +1 -1
  22. package/dist/m/{c-ZO6VL2SC.js → c-5WMXEKFH.js} +1 -1
  23. package/dist/m/{c-4TWARTLS.js → c-6RDOKLN7.js} +1 -1
  24. package/dist/m/{c-6RC66MYY.js → c-6TYGD5AB.js} +1 -1
  25. package/dist/m/c-A4IP6MBC.js +1 -0
  26. package/dist/m/{c-ZAHTFCXQ.js → c-ALDVFPWL.js} +1 -1
  27. package/dist/m/{c-LV5MABYD.js → c-AYVGD6A6.js} +1 -1
  28. package/dist/m/{c-N33TPVTL.js → c-B6O7AJYG.js} +1 -1
  29. package/dist/m/{c-P3WATEDR.js → c-BCGWJYXW.js} +1 -1
  30. package/dist/m/{c-4OGEVKR3.js → c-BGKAT2FL.js} +1 -1
  31. package/dist/m/{c-N7Y52HJH.js → c-BXYSDKAN.js} +1 -1
  32. package/dist/m/c-CRPIDGXC.js +78 -0
  33. package/dist/m/c-CUMXGHVD.js +1 -0
  34. package/dist/m/{c-Q5KAQJAG.js → c-DTMZ3ZHI.js} +1 -1
  35. package/dist/m/{c-GY4ODHO2.js → c-ELYIIYRS.js} +1 -1
  36. package/dist/m/{c-67LGZ52V.js → c-FCSZ3DC5.js} +1 -1
  37. package/dist/m/{c-NLWEZYKJ.js → c-FQGHR32O.js} +1 -1
  38. package/dist/m/{c-PCEMXY2K.js → c-G4PWUDD5.js} +1 -1
  39. package/dist/m/{c-6KBKYLPO.js → c-G6COVIZB.js} +1 -1
  40. package/dist/m/c-GBTVCJXC.js +1 -0
  41. package/dist/m/c-GC2HICFJ.js +1 -0
  42. package/dist/m/{c-TMT5TL65.js → c-HCNWJE4A.js} +2 -2
  43. package/dist/m/{c-DZBZ57EE.js → c-JCOQVZYS.js} +1 -1
  44. package/dist/m/{c-FAXQU7MQ.js → c-JGHEACGK.js} +1 -1
  45. package/dist/m/{c-PWBJVHA4.js → c-JGLX6TBK.js} +1 -1
  46. package/dist/m/c-JNRKHYWO.js +1 -0
  47. package/dist/m/{c-6UEFPHHE.js → c-KDXIJEEF.js} +1 -1
  48. package/dist/m/{c-FMCPQ4VT.js → c-L4KMT7FO.js} +2 -2
  49. package/dist/m/{c-OI2BYWVV.js → c-LCYPMULG.js} +1 -1
  50. package/dist/m/{c-4RFZROCF.js → c-LIGQYZ7M.js} +4 -4
  51. package/dist/m/{c-QHVCUTJV.js → c-LKIWEPAV.js} +1 -1
  52. package/dist/m/{c-EDSPKYMA.js → c-LUXAB2XI.js} +1 -1
  53. package/dist/m/{c-DEAFCHDO.js → c-LWIDDWAR.js} +2 -2
  54. package/dist/m/c-MPSKIU2I.js +1 -0
  55. package/dist/m/{c-6PBXRWDX.js → c-NK33MMYF.js} +1 -1
  56. package/dist/m/{c-F5AER2ID.js → c-NQLWOHLH.js} +1 -1
  57. package/dist/m/{c-L7K5EXU2.js → c-NTHUTABN.js} +1 -1
  58. package/dist/m/{c-4PHDUV3H.js → c-NW54NHKE.js} +1 -1
  59. package/dist/m/{c-3AXJDL2P.js → c-OG6GFSUX.js} +1 -1
  60. package/dist/m/{c-MTQHWQC3.js → c-OKEGUICD.js} +1 -1
  61. package/dist/m/c-OPONJ2UK.js +128 -0
  62. package/dist/m/{c-LF6HNVPU.js → c-OWQWOGYI.js} +1 -1
  63. package/dist/m/{c-FDAXZ2PM.js → c-P6Q2ZTFQ.js} +1 -1
  64. package/dist/m/c-PKCCHJ5X.js +1 -0
  65. package/dist/m/c-PWJSJEJU.js +1 -0
  66. package/dist/m/{c-Z7RJANGO.js → c-PXLTUYZC.js} +1 -1
  67. package/dist/m/c-QEN6HZCA.js +1 -0
  68. package/dist/m/{c-26KVJS6J.js → c-QGAPG7OM.js} +1 -1
  69. package/dist/m/{c-HWR6GMGK.js → c-QIR5CAKM.js} +1 -1
  70. package/dist/m/{c-QJFYVCJO.js → c-QM5LXRDT.js} +1 -1
  71. package/dist/m/{c-MRURHLKV.js → c-QUGCKMWF.js} +1 -1
  72. package/dist/m/{c-KE33W4RE.js → c-QYYUVLVG.js} +1 -1
  73. package/dist/m/c-RO73MKKR.js +1 -0
  74. package/dist/m/c-SBCBXKOZ.js +26 -0
  75. package/dist/m/{c-XDVAZDUE.js → c-SGRIYOAJ.js} +1 -1
  76. package/dist/m/c-SKF5HL4I.js +4 -0
  77. package/dist/m/{c-IWTTOC2V.js → c-SRPC3VBE.js} +1 -1
  78. package/dist/m/{c-XZJ5IK6Q.js → c-T5NK2TVY.js} +1 -1
  79. package/dist/m/{c-VFES2BP5.js → c-TANBH7FI.js} +1 -1
  80. package/dist/m/{c-H6DXQEH2.js → c-THGQQDYY.js} +1 -1
  81. package/dist/m/{c-BV6FQQXM.js → c-TSBVMWAH.js} +1 -1
  82. package/dist/m/{c-QTC6VGA4.js → c-UD5JZTDL.js} +1 -1
  83. package/dist/m/{c-ZYEJLZEY.js → c-UDGEFWNU.js} +1 -1
  84. package/dist/m/{c-ZSCBEB7I.js → c-UHUNXWKN.js} +1 -1
  85. package/dist/m/{c-FWFJUU3T.js → c-VIRFF5HG.js} +1 -1
  86. package/dist/m/{c-GPTKI7AQ.js → c-VYJ7O4RI.js} +1 -1
  87. package/dist/m/{c-TUGVINJR.js → c-W5E5P2TZ.js} +1 -1
  88. package/dist/m/{c-WWE67K5Y.js → c-W7IPVCAA.js} +1 -1
  89. package/dist/m/{c-HAVGDXAL.js → c-WJ5DRBHT.js} +1 -1
  90. package/dist/m/{c-V2J5C5MT.js → c-WQZTI5P2.js} +1 -1
  91. package/dist/m/c-X5WC4PX5.js +1 -0
  92. package/dist/m/{c-ZKELCT4T.js → c-XCFQEWW6.js} +2 -2
  93. package/dist/m/c-XLQ3BDMM.js +1 -0
  94. package/dist/m/{c-FLBUYV3P.js → c-XX75FFNL.js} +1 -1
  95. package/dist/m/{c-JHJR5BQX.js → c-YK2L436K.js} +1 -1
  96. package/dist/m/{c-MEWUGR4D.js → c-YYMZWQLR.js} +1 -1
  97. package/dist/m/core/{admin-attrs-ZG7R5V3E.js → admin-attrs-U7IJNYBG.js} +1 -1
  98. package/dist/m/core/{autosave-GI3WNJYN.js → autosave-F5YQCKVL.js} +1 -1
  99. package/dist/m/core/{conflict-notice-CEI3XY6A.js → conflict-notice-42H4ASLA.js} +1 -1
  100. package/dist/m/core/{persist-3OPWJKZS.js → persist-CJXIL7D4.js} +1 -1
  101. package/dist/m/core/{save-OJ5NSLS7.js → save-ESPSQPLV.js} +1 -1
  102. package/dist/m/core/{save-core-DX3RFVO3.js → save-core-6SQHOR6W.js} +1 -1
  103. package/dist/m/core/snapshot-FJP5IJL3.js +1 -0
  104. package/dist/m/core/{unsaved-warning-HGYH7O4H.js → unsaved-warning-HNQVTA2D.js} +1 -1
  105. package/dist/m/internals/{index-V4WC44FU.js → index-NRPNDTSA.js} +1 -1
  106. package/dist/m/loader-FBDE2UAB.js +1 -0
  107. package/dist/m/manifest-1D2F5CA5.js +1 -0
  108. package/dist/m/manifest-edit-F7CC5CFD.js +1 -0
  109. package/dist/m/manifest.json +1090 -1020
  110. package/dist/m/page/{editor-BQEPCJLG.js → editor-OSKOW6RS.js} +2 -2
  111. package/dist/m/plugins/{ai-edit-45A2J6LC.js → ai-edit-VV4QTINH.js} +1 -1
  112. package/dist/m/plugins/{cms-IFTKWF4S.js → cms-H7DTMUQX.js} +1 -1
  113. package/dist/m/plugins/{indicator-IPZJ35K6.js → indicator-WVPGMOZ7.js} +1 -1
  114. package/dist/m/plugins/{live-GPQXSXSM.js → live-DCUBKXY4.js} +1 -1
  115. package/dist/m/plugins/menu-Q4MFFQ6E.js +1 -0
  116. package/dist/m/plugins/{page-BAVLWCP6.js → page-OAWUJQEL.js} +2 -2
  117. package/dist/m/plugins/{page-view-P3UGJFDZ.js → page-view-DZ26ZDDQ.js} +1 -1
  118. package/dist/m/plugins/{people-Z4RGVQAV.js → people-5XRNRP5U.js} +1 -1
  119. package/dist/m/plugins/{quickcrop-E34PUYA3.js → quickcrop-WWF5I422.js} +2 -2
  120. package/dist/m/plugins/{richclay-S4NVJYIK.js → richclay-PGOOJ4OK.js} +2 -2
  121. package/dist/m/plugins/{sortable-WJZZBM7R.js → sortable-266HY6TR.js} +1 -1
  122. package/dist/m/plugins/{source-KVN6YNTY.js → source-6BKMK4PO.js} +1 -1
  123. package/dist/m/plugins/{upgrade-KTSICB22.js → upgrade-BNZVFHMZ.js} +1 -1
  124. package/dist/m/plugins/visitor-drafts-2AUYKAIJ.js +20 -0
  125. package/dist/m/plugins/{visitor-drafts-owner-MZP45XSG.js → visitor-drafts-owner-Z5B2OQBR.js} +1 -1
  126. package/dist/m/plugins/visitor-menu-4LQMKLPP.js +1 -0
  127. package/dist/m/plugins/{wire-SYVIBNSE.js → wire-W2EV36KZ.js} +1 -1
  128. package/dist/m/{reader-core-RUIFH32Y.js → reader-core-POFQCKRV.js} +2 -2
  129. package/dist/m/sync/{live-sync-RGQMMWK2.js → live-sync-XGUPHI3I.js} +1 -1
  130. package/dist/m/ui/{index-EZGLEM5P.js → index-VGYAKAKI.js} +1 -1
  131. package/dist/offline-manifest.json +636 -570
  132. package/docs/guide.md +36 -25
  133. package/package.json +1 -1
  134. package/src/core/save-replace.js +5 -2
  135. package/src/core/serialize-steps.js +10 -2
  136. package/src/core/snapshot.js +37 -1
  137. package/src/core/upgrade-run.js +16 -2
  138. package/src/loader-logic.js +6 -2
  139. package/src/plugins/menu/dom-items.js +45 -0
  140. package/src/plugins/menu/looks.js +32 -0
  141. package/src/plugins/menu/shell-style.js +143 -0
  142. package/src/plugins/menu/shell.js +398 -0
  143. package/src/plugins/menu/style.js +15 -116
  144. package/src/plugins/menu/variants.js +56 -10
  145. package/src/plugins/menu/visitor.js +78 -0
  146. package/src/plugins/menu.js +21 -313
  147. package/src/plugins/visitor-drafts/inert.js +1 -0
  148. package/src/plugins/visitor-drafts/intro-style.js +6 -0
  149. package/src/plugins/visitor-drafts/intro.js +77 -25
  150. package/src/plugins/visitor-drafts/owner-chip.js +18 -23
  151. package/src/plugins/visitor-drafts/prompt.js +2 -2
  152. package/src/plugins/visitor-drafts/store.js +58 -5
  153. package/src/plugins/visitor-drafts.js +1 -0
  154. package/src/plugins/visitor-menu.js +13 -0
  155. package/src/sync/live-sync.js +2 -1
  156. package/src/sync/page-relay.js +2 -2
  157. package/src/ui/page-colour.js +17 -9
  158. package/dist/m/c-5AQYL27I.js +0 -1
  159. package/dist/m/c-DP4X4JID.js +0 -1
  160. package/dist/m/c-ECY5AZMH.js +0 -1
  161. package/dist/m/c-EGTIAL6P.js +0 -1
  162. package/dist/m/c-HDWZEJHM.js +0 -183
  163. package/dist/m/c-ILGQ3UXQ.js +0 -1
  164. package/dist/m/c-JFST6QE7.js +0 -1
  165. package/dist/m/c-JH5FF4NL.js +0 -20
  166. package/dist/m/c-KV7R47FR.js +0 -1
  167. package/dist/m/c-MHI3GYKF.js +0 -1
  168. package/dist/m/c-NNNR7OXA.js +0 -3
  169. package/dist/m/c-VSPAFOKU.js +0 -1
  170. package/dist/m/core/snapshot-O7II2AGG.js +0 -1
  171. package/dist/m/loader-V6VI46HU.js +0 -1
  172. package/dist/m/manifest-83C18DED.js +0 -1
  173. package/dist/m/manifest-edit-B28C1985.js +0 -1
  174. package/dist/m/plugins/menu-UN3KRCOF.js +0 -1
  175. package/dist/m/plugins/visitor-drafts-2AWNT23K.js +0 -20
  176. /package/dist/m/plugins/{quickcrop-E34PUYA3.js.LEGAL.txt → quickcrop-WWF5I422.js.LEGAL.txt} +0 -0
  177. /package/dist/m/plugins/{richclay-S4NVJYIK.js.LEGAL.txt → richclay-PGOOJ4OK.js.LEGAL.txt} +0 -0
@@ -5,6 +5,8 @@ import { bootPhase } from "../../core/boot-phase.js";
5
5
 
6
6
  export const COPY = {
7
7
  close: "Hide this introduction",
8
+ hide: "Hide intro",
9
+ show: "Show intro",
8
10
  label: (appName) => `About ${appName}`,
9
11
  };
10
12
 
@@ -43,17 +45,7 @@ function focusApp() {
43
45
  else document.body.focus({ preventScroll: true });
44
46
  }
45
47
 
46
- export function mountIntro({ memory, template, appName, hadDraft }) {
47
- if (!template || !template.content.textContent.trim() && !template.content.querySelector("img, svg, video, canvas")) return null;
48
- if (!forced()) {
49
- if (memory.get().intro.done || hadDraft) return null;
50
- if (bootPhase.servedHash) return null;
51
- if (window.matchMedia && window.matchMedia("print").matches) return null;
52
- }
53
- return mount({ memory, template, appName });
54
- }
55
-
56
- function mount({ memory, template, appName }) {
48
+ function buildSection({ template, appName, labelText, onClose }) {
57
49
  stylesOnce();
58
50
 
59
51
  const section = document.createElement("section");
@@ -66,11 +58,48 @@ function mount({ memory, template, appName }) {
66
58
  const close = document.createElement("button");
67
59
  close.type = "button";
68
60
  close.className = "clay-intro__close";
69
- close.setAttribute("aria-label", COPY.close);
70
- close.innerHTML = '<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true"><path d="M1.4 0 6 4.6 10.6 0 12 1.4 7.4 6 12 10.6 10.6 12 6 7.4 1.4 12 0 10.6 4.6 6 0 1.4z"/></svg>';
71
- close.addEventListener("click", () => dismiss("closed"));
61
+ if (labelText) {
62
+ close.textContent = labelText;
63
+ close.setAttribute("data-manual", "");
64
+ } else {
65
+ close.setAttribute("aria-label", COPY.close);
66
+ close.innerHTML = '<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true"><path d="M1.4 0 6 4.6 10.6 0 12 1.4 7.4 6 12 10.6 10.6 12 6 7.4 1.4 12 0 10.6 4.6 6 0 1.4z"/></svg>';
67
+ }
68
+ close.addEventListener("click", () => onClose());
72
69
  mountEditorUI({ name: "intro-close", content: close, css: [CLOSE_CSS], parent: section });
73
70
 
71
+ section.addEventListener("click", (event) => {
72
+ if (event.target.closest("[visitor-intro-dismiss]")) {
73
+ onClose();
74
+ return;
75
+ }
76
+ if (event.target.closest("[visitor-intro-start]")) {
77
+ event.preventDefault();
78
+ window.scrollTo({ top: window.scrollY + section.getBoundingClientRect().bottom, behavior: "smooth" });
79
+ }
80
+ });
81
+
82
+ return section;
83
+ }
84
+
85
+ export function mountIntro({ memory, template, appName, hadDraft }) {
86
+ if (!template || !template.content.textContent.trim() && !template.content.querySelector("img, svg, video, canvas")) return null;
87
+ if (template.getAttribute("visitor-intro") === "manual") {
88
+ const printing = window.matchMedia && window.matchMedia("print").matches;
89
+ const open = forced() || !(memory.get().intro.done || hadDraft || bootPhase.servedHash || printing);
90
+ return mountManual({ memory, template, appName, open });
91
+ }
92
+ if (!forced()) {
93
+ if (memory.get().intro.done || hadDraft) return null;
94
+ if (bootPhase.servedHash) return null;
95
+ if (window.matchMedia && window.matchMedia("print").matches) return null;
96
+ }
97
+ return mount({ memory, template, appName });
98
+ }
99
+
100
+ function mount({ memory, template, appName }) {
101
+ const section = buildSection({ template, appName, onClose: () => dismiss("closed") });
102
+
74
103
  let gone = false;
75
104
  let frame = 0;
76
105
 
@@ -102,20 +131,43 @@ function mount({ memory, template, appName }) {
102
131
  });
103
132
  }
104
133
 
105
- section.addEventListener("click", (event) => {
106
- if (event.target.closest("[visitor-intro-dismiss]")) {
107
- dismiss("closed");
108
- return;
109
- }
110
- if (event.target.closest("[visitor-intro-start]")) {
111
- event.preventDefault();
112
- window.scrollTo({ top: window.scrollY + section.getBoundingClientRect().bottom, behavior: "smooth" });
113
- }
114
- });
115
-
116
134
  document.body.prepend(section);
117
135
  announceBottomUi();
118
136
  addEventListener("scroll", onScroll, { passive: true });
119
137
 
120
138
  return section;
121
139
  }
140
+
141
+ function mountManual({ memory, template, appName, open }) {
142
+ let section = null;
143
+ const showRow = (wanted) => {
144
+ const menu = window.clay?.menu;
145
+ if (!menu) return;
146
+ if (wanted) menu.addItem({ id: "clay.intro", label: COPY.show, run: show });
147
+ else menu.removeItem("clay.intro");
148
+ };
149
+ function attach() {
150
+ section ??= buildSection({ template, appName, labelText: COPY.hide, onClose: hide });
151
+ document.body.prepend(section);
152
+ announceBottomUi();
153
+ showRow(false);
154
+ }
155
+ function hide() {
156
+ memory.get().intro.done = "closed";
157
+ memory.save();
158
+ section.remove();
159
+ announceBottomUi();
160
+ showRow(true);
161
+ focusApp();
162
+ }
163
+ function show() {
164
+ memory.get().intro.done = null;
165
+ memory.save();
166
+ attach();
167
+ window.scrollTo(0, 0);
168
+ }
169
+ document.addEventListener("clay:menu-ready", () => showRow(!section?.isConnected));
170
+ if (open) attach();
171
+ else showRow(true);
172
+ return section;
173
+ }
@@ -1,6 +1,11 @@
1
1
  import { isDraftMode } from "../../core/is-edit-mode.js";
2
2
  import { BOTTOM_UI_CHANGED, announceBottomUi, bottomBarHeight, promptPanel } from "./bottom-ui.js";
3
3
  import { mountEditorUI } from "../../ui/editor-ui.js";
4
+ import { followLook } from "../../ui/page-colour.js";
5
+
6
+ // The notice sits on the page for as long as the owner edits, so it takes most of the
7
+ // page's colour instead of Bevel's: a navy card on a brown page reads as a foreign object.
8
+ const OWNER_LEAN = 0.8;
4
9
 
5
10
  export const COPY = {
6
11
  draft: "You're seeing a private draft, like a visitor.",
@@ -11,29 +16,17 @@ export const COPY = {
11
16
  };
12
17
 
13
18
  const CHIP_CSS = `.clay-owner {
14
- --hcp-ground: #FDF8F0;
15
- --hcp-surface: #FFFCF6;
16
- --hcp-sunk: #F4ECDF;
17
- --hcp-ink: #2B241B;
18
- --hcp-ink-2: #4A4033;
19
- --hcp-muted: #6B5942;
20
- --hcp-line: #E8DCC6;
21
- --hcp-line-2: #D8C8AF;
22
- --hcp-brass: #8F6310;
23
- --hcp-shadow: 0 1px 2px rgba(23, 28, 36, .06), 0 14px 34px -14px rgba(43, 36, 27, .32);
19
+ --hcp-surface: light-dark(#FFFCF6, #11131E);
20
+ --hcp-ground: var(--bevel-surface, var(--hcp-surface));
21
+ --hcp-ink: light-dark(#2B241B, #ECEAF2);
22
+ --hcp-ink-2: light-dark(#4A4033, #C9CDE0);
23
+ --hcp-muted: light-dark(#6B5942, #8A90AB);
24
+ --hcp-line-2: color-mix(in srgb, var(--hcp-ink) 22%, var(--hcp-ground));
25
+ --hcp-brass: light-dark(#8F6310, #D9A445);
26
+ --hcp-shadow: 0 1px 2px light-dark(rgba(23, 28, 36, .06), rgba(0, 0, 0, .4)), 0 14px 34px -14px light-dark(rgba(43, 36, 27, .32), rgba(0, 0, 0, .7));
24
27
  --hcp-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
25
28
  --hcp-lift: 0px;
26
- color-scheme: light;
27
- }
28
- @media (prefers-color-scheme: dark) {
29
- .clay-owner {
30
- --hcp-surface: #11131E; --hcp-sunk: #1A1D2C;
31
- --hcp-ink: #ECEAF2; --hcp-ink-2: #C9CDE0; --hcp-muted: #8A90AB;
32
- --hcp-line: #262B42; --hcp-line-2: #353B52;
33
- --hcp-brass: #D9A445;
34
- --hcp-shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 16px 38px -14px rgba(0, 0, 0, .7);
35
- color-scheme: dark;
36
- }
29
+ color-scheme: light dark;
37
30
  }
38
31
  .clay-owner, .clay-owner *, .clay-owner *::before, .clay-owner *::after {
39
32
  box-sizing: border-box; margin: 0; padding: 0; border: 0;
@@ -46,8 +39,8 @@ const CHIP_CSS = `.clay-owner {
46
39
  max-width: min(460px, calc(100vw - 24px));
47
40
  padding: 8px 8px 8px 12px;
48
41
  font-family: var(--hcp-sans); font-size: 13px; font-weight: 400; line-height: 1.45;
49
- color: var(--hcp-ink-2); text-align: left; background: var(--hcp-surface);
50
- border: 1px solid var(--hcp-line-2); border-left: 3px solid var(--hcp-brass);
42
+ color: var(--hcp-ink-2); text-align: left; background: var(--hcp-ground);
43
+ border: 1px solid var(--hcp-line-2);
51
44
  box-shadow: var(--hcp-shadow);
52
45
  -webkit-font-smoothing: antialiased;
53
46
  }
@@ -151,6 +144,7 @@ export function mountOwnerChip() {
151
144
  }
152
145
 
153
146
  function liftOff() {
147
+ unfollow?.();
154
148
  removeEventListener("scroll", lift);
155
149
  removeEventListener("resize", lift);
156
150
  document.removeEventListener(BOTTOM_UI_CHANGED, lift);
@@ -168,6 +162,7 @@ export function mountOwnerChip() {
168
162
  // Transition events stop at a shadow root, so the chip's own changes are heard here.
169
163
  chip.addEventListener("transitionend", lift);
170
164
  lift();
165
+ const unfollow = followLook(chip, chip, undefined, OWNER_LEAN);
171
166
  // Whoever removes the chip takes its listeners back with it: a chip mounted and unmounted
172
167
  // once per mode session would otherwise leave six behind each time.
173
168
  chip.liftOff = liftOff;
@@ -119,7 +119,7 @@ export async function mountPrompt({ memory, appName, link }) {
119
119
  const t = e.target.closest("[data-hcp]");
120
120
  if (t) {
121
121
  const act = t.getAttribute("data-hcp");
122
- if (act === "open") { set("card", "open"); linkEl.focus(); }
122
+ if (act === "open") { set("card", root.getAttribute("data-hcp-reason") === "error" ? undefined : "open"); linkEl.focus(); }
123
123
  else if (act === "minimize") { set("mini"); tab.focus(); }
124
124
  else if (act === "dismiss") {
125
125
  if (root.getAttribute("data-hcp-reason") === "error") { set("mini"); tab.focus(); }
@@ -149,7 +149,7 @@ export async function mountPrompt({ memory, appName, link }) {
149
149
  function clearError() {
150
150
  if (root.getAttribute("data-hcp-reason") === "error") root.setAttribute("data-hcp-reason", "use");
151
151
  }
152
- const api = { set, root, showError, clearError };
152
+ const api = { set, root, showError, clearError, download: () => linkEl.click() };
153
153
 
154
154
  document.addEventListener("input", onUse, true);
155
155
  document.addEventListener("change", onUse, true);
@@ -3,6 +3,7 @@ import { draftSlot, setDraftStoreFailed } from "../../core/draft-mode.js";
3
3
 
4
4
  export const KEY_PREFIX = "clay:visitor-drafts:";
5
5
  export const RECORD_VERSION = 1;
6
+ const LINEAGE = 32;
6
7
 
7
8
  // The document a pathname names, spelled the way the hosts resolve it: the path up to
8
9
  // and including the first segment that ends in .html or .htmlclay (anything after it is
@@ -228,6 +229,45 @@ export function createStore({ doc = document, storage = safeStorage(), now = ()
228
229
  let base = null;
229
230
  let unparked = null;
230
231
  let stopped = false;
232
+ // This tab's own last write: its record id, its ancestry, and the data of the record it
233
+ // was built on. A read in one tab can miss a write another tab made a few milliseconds
234
+ // earlier, so a record whose ancestry lacks this write never saw it.
235
+ let own = null;
236
+
237
+ const newId = () => Math.random().toString(36).slice(2, 10) + Math.random().toString(36).slice(2, 6);
238
+
239
+ // A record's ancestry is the ids it descends from, nearest first, ending at the empty
240
+ // slot it grew from, or at a record from a runtime that kept no ids, named by its bytes.
241
+ // Start over gives the empty slot a new id, so a write from before it never reads as
242
+ // built on the same slot as one after it.
243
+ const resetKey = key + ":reset";
244
+ function rootId() {
245
+ try { return "root:" + (storage?.getItem(resetKey) ?? ""); } catch { return "root:"; }
246
+ }
247
+
248
+ function legacyId(raw) {
249
+ let hash = 0x811c9dc5;
250
+ for (let i = 0; i < raw.length; i++) hash = Math.imul(hash ^ raw.charCodeAt(i), 0x01000193);
251
+ return "legacy:" + (hash >>> 0).toString(36) + "." + raw.length.toString(36);
252
+ }
253
+
254
+ function lineageOf(record, raw) {
255
+ if (!record) return null;
256
+ if (!record.id) return [legacyId(raw)];
257
+ return Array.isArray(record.ancestry) ? [record.id, ...record.ancestry].slice(0, LINEAGE) : null;
258
+ }
259
+
260
+ // A record that descends from this tab's own last write's parent but not from that write
261
+ // dropped it unseen, however many writes since. Merged from this tab's write, its missing
262
+ // rows would read as deletions; merged from that parent, both sides' work is kept. A full
263
+ // ancestry without this write may have seen it long ago or never, and keeping this tab's
264
+ // rows is the side that loses nothing. With no ancestry the record is taken as it is.
265
+ function forked(record) {
266
+ if (!own || own.raw !== lastRaw || !own.ancestry || !record?.id || record.id === own.id) return false;
267
+ const seen = record.ancestry;
268
+ if (!Array.isArray(seen) || seen.includes(own.id)) return false;
269
+ return seen.includes(own.ancestry[0]) || seen.length >= LINEAGE;
270
+ }
231
271
 
232
272
  function getRaw() {
233
273
  try {
@@ -386,15 +426,15 @@ export function createStore({ doc = document, storage = safeStorage(), now = ()
386
426
  function merge(mine) {
387
427
  const current = getRaw();
388
428
  const record = current == null ? null : parse(current);
389
- if (!record) return { data: mine, stored: null };
429
+ if (!record) return { data: mine, stored: null, ancestry: [rootId()], parentData: base };
390
430
  let data = mine;
391
431
  if (current !== lastRaw) {
392
- const merged = merge3(base, mine, record.data);
432
+ const merged = merge3(forked(record) ? own.parentData : base, mine, record.data);
393
433
  if (merged.conflict) keepConflict(current);
394
434
  data = merged.value;
395
435
  }
396
436
  data = complete(data, record.data);
397
- return { data, stored: same(data, record.data) ? current : null };
437
+ return { data, stored: same(data, record.data) ? current : null, ancestry: lineageOf(record, current), parentData: record.data };
398
438
  }
399
439
 
400
440
  function adopt(data) {
@@ -418,8 +458,9 @@ export function createStore({ doc = document, storage = safeStorage(), now = ()
418
458
  doc.dispatchEvent(new CustomEvent("clay:drafts-saved", { detail: { data: mine, unchanged: true } }));
419
459
  return mine;
420
460
  }
421
- const { data, stored } = merge(mine);
422
- const raw = stored ?? JSON.stringify({ v: RECORD_VERSION, savedAt: now().toISOString(), data });
461
+ const { data, stored, ancestry, parentData } = merge(mine);
462
+ const id = newId();
463
+ const raw = stored ?? JSON.stringify({ v: RECORD_VERSION, savedAt: now().toISOString(), id, ancestry, data });
423
464
  if (!stored) {
424
465
  try {
425
466
  if (!storage) throw new Error("no storage");
@@ -427,6 +468,7 @@ export function createStore({ doc = document, storage = safeStorage(), now = ()
427
468
  } catch (error) {
428
469
  throw storageFailure(doc, error);
429
470
  }
471
+ own = { id, ancestry, parentData, raw };
430
472
  }
431
473
  const taken = Object.keys(mine).filter((name) => !fitsInto(mine[name], data[name]));
432
474
  if (taken.length) adopt(Object.fromEntries(taken.map((name) => [name, data[name]])));
@@ -451,8 +493,18 @@ export function createStore({ doc = document, storage = safeStorage(), now = ()
451
493
  function adoptExternal() {
452
494
  if (stopped) return false;
453
495
  const raw = getRaw();
496
+ // Another tab pressed Start over: this tab follows it, or its next save would
497
+ // write the discarded draft back.
498
+ if (raw == null && lastRaw != null && !changed()) {
499
+ stopped = true;
500
+ window.location.reload();
501
+ return true;
502
+ }
454
503
  if (raw == null || raw === lastRaw || changed()) return false;
455
504
  const record = parse(raw);
505
+ // That tab never saw this tab's last write: this tab writes both back instead of
506
+ // adopting a record that dropped its own work.
507
+ if (forked(record) && typeof window.clay?.getHTML === "function") return writeLive();
456
508
  const adopted = record && adopt(record.data);
457
509
  if (!adopted) return false;
458
510
  lastRaw = raw;
@@ -465,6 +517,7 @@ export function createStore({ doc = document, storage = safeStorage(), now = ()
465
517
  unparked = null;
466
518
  setDraftStoreFailed(false);
467
519
  try { storage.removeItem(key); } catch {}
520
+ try { storage.setItem(resetKey, newId()); } catch {}
468
521
  }
469
522
 
470
523
  return { slot, key, rules, read, restore, write, writeLive, flush, changed, adoptExternal, park, clear, snapshot };
@@ -98,5 +98,6 @@ export const visitorDrafts = store ? {
98
98
  editOriginal,
99
99
  backToDraft,
100
100
  downloadUrl: () => downloadLink,
101
+ download: () => ready.then((prompt) => { store.flush(); return prompt?.download(); }),
101
102
  source,
102
103
  } : inertVisitorDrafts();
@@ -0,0 +1,13 @@
1
+ import { isDraftMode } from "../core/is-edit-mode.js";
2
+ import onDomReady from "../lib/dom-ready.js";
3
+ import { paintLook } from "./menu/looks.js";
4
+
5
+ if (isDraftMode) {
6
+ paintLook();
7
+ document.addEventListener("clay:drafts-restored", () => paintLook());
8
+ onDomReady(() => {
9
+ import("./menu/visitor.js")
10
+ .then((m) => m.start())
11
+ .catch((error) => console.warn("visitor-menu: the menu did not load", error));
12
+ });
13
+ }
@@ -43,7 +43,7 @@ import { NO_DIRTY_SELECTOR, LIVE_SELECTOR } from "../lib/region-policy.js";
43
43
  import { EXTENSION_NODE_SELECTOR, EXTENSION_ATTR_PATTERN } from '../lib/extension-noise.js';
44
44
  import { isEditMode, modeState } from "../core/is-edit-mode.js";
45
45
  import { attributeMerge } from "./merge-declarations.js";
46
- import { serializeForSync, copyCaptureClone, captureForComparisonAndDirty, canonicalizeReceived, captureSnapshot, originalSnapshotNode, captureForMerge, captureForSaveAndComparison } from '../core/snapshot.js';
46
+ import { noscriptsAsText, serializeForSync, copyCaptureClone, captureForComparisonAndDirty, canonicalizeReceived, captureSnapshot, originalSnapshotNode, captureForMerge, captureForSaveAndComparison } from '../core/snapshot.js';
47
47
  import { mergeIgnoresAttr, mergeVetoesAttr } from '../lib/root-attrs.js';
48
48
  import { autosaveActive } from '../lib/autosave-state.js';
49
49
  import { hostSupports } from '../core/host-meta.js';
@@ -186,6 +186,7 @@ function scratchpadsEmptied(input) {
186
186
  if (input == null) return input;
187
187
  const doc = typeof input === 'string' ? new DOMParser().parseFromString(input, 'text/html') : input;
188
188
  canonicalizeReceived(doc);
189
+ noscriptsAsText(doc);
189
190
  emptyScratchpads(doc);
190
191
  return doc;
191
192
  }
@@ -1,5 +1,5 @@
1
1
  import { importMap } from "../vendor/hyper-morph-identity.vendor.js";
2
- import { serializeForSync } from "../core/snapshot.js";
2
+ import { noscriptsAsText, serializeForSync } from "../core/snapshot.js";
3
3
 
4
4
  const PAGE = /^page(\.[0-9]+)?$/;
5
5
  const tags = (root) => [...root.querySelectorAll('script[merge][clay~="live"]')]
@@ -9,7 +9,7 @@ export function pageRelay(pending, acceptedHtml, identity) {
9
9
  // A capture with no page article has nothing to overlay, and a document without
10
10
  // one is not parsed at all: nothing outside the article would change.
11
11
  if (!pending.html.includes("data-page")) return pending;
12
- const parse = (html) => new DOMParser().parseFromString(html, "text/html");
12
+ const parse = (html) => noscriptsAsText(new DOMParser().parseFromString(html, "text/html"));
13
13
  const outgoing = parse(pending.html);
14
14
  const article = outgoing.querySelector("article[data-page]");
15
15
  if (!article) return pending;
@@ -202,11 +202,11 @@ export const BEVEL_SURFACE = { light: [0xFF, 0xFC, 0xF6], dark: [0x11, 0x13, 0x1
202
202
  /**
203
203
  * The look for UI drawn over `rect`: { scheme, surface }. `scheme` is the detected
204
204
  * one, or pageScheme() when the colour is unknown. `surface` is Bevel's surface mixed
205
- * up to 35% toward a confidently detected colour, never so far that the muted ink
206
- * drops below 4.5:1, or null to keep Bevel's own fill. A page the detector cannot
205
+ * up to `lean` (35% by default) toward a confidently detected colour, never so far that
206
+ * the muted ink drops below 4.5:1, or null to keep Bevel's own fill. A page the detector cannot
207
207
  * read is unknown, never a reason for the UI drawing over it to fail.
208
208
  */
209
- export function uiLook(rect, base = BEVEL_SURFACE) {
209
+ export function uiLook(rect, base = BEVEL_SURFACE, lean = 0.35) {
210
210
  let found = null;
211
211
  try {
212
212
  found = pageColour(rect);
@@ -215,7 +215,7 @@ export function uiLook(rect, base = BEVEL_SURFACE) {
215
215
  const { scheme } = found;
216
216
  const own = base[scheme], muted = (scheme === 'dark' ? base.mutedDark : base.mutedLight).map((v) => v / 255);
217
217
  let surface = null;
218
- for (let w = 0.35; found.confidence >= 0.75 && !surface && w > 0.01; w -= 0.05) {
218
+ for (let w = lean; found.confidence >= 0.75 && !surface && w > 0.01; w -= 0.05) {
219
219
  const mix = own.map((v, k) => Math.round(v + (found.colour[k] - v) * w));
220
220
  if (contrast(mix.map((v) => v / 255), muted) >= 4.5) surface = `rgb(${mix.join(' ')})`;
221
221
  }
@@ -246,8 +246,8 @@ export function paintLook(el, { rect = el.getBoundingClientRect(), background =
246
246
  * The same look for a surface styled by a stylesheet of Bevel variables (the page
247
247
  * menu): `color-scheme`, and `--bevel-surface` when tinted, set inline on `el`.
248
248
  */
249
- export function lookAt(el, rect, base) {
250
- const look = uiLook(rect, base);
249
+ export function lookAt(el, rect, base, lean) {
250
+ const look = uiLook(rect, base, lean);
251
251
  el.style.setProperty('color-scheme', look.scheme, 'important');
252
252
  if (look.surface) el.style.setProperty('--bevel-surface', look.surface, 'important');
253
253
  else el.style.removeProperty('--bevel-surface');
@@ -257,13 +257,13 @@ export function lookAt(el, rect, base) {
257
257
  // A fixed surface the page moves under: read again once scrolling or resizing settles,
258
258
  // when html or body change attributes (a theme toggle), when the reader's scheme
259
259
  // changes, when it moves to another corner and when it is shown again. While it has
260
- // no size (hidden) it keeps its last look.
261
- export function followLook(root, target, base) {
260
+ // no size (hidden) it keeps its last look. Returns a function that stops following.
261
+ export function followLook(root, target, base, lean) {
262
262
  let timer = 0;
263
263
  const refresh = () => {
264
264
  timer = 0;
265
265
  const rect = target.getBoundingClientRect();
266
- if (!document.hidden && root.isConnected && rect.width && rect.height) lookAt(root, rect, base);
266
+ if (!document.hidden && root.isConnected && rect.width && rect.height) lookAt(root, rect, base, lean);
267
267
  };
268
268
  const soon = () => {
269
269
  clearTimeout(timer);
@@ -278,4 +278,12 @@ export function followLook(root, target, base) {
278
278
  watch.observe(document.body, { attributes: true });
279
279
  watch.observe(root, { attributes: true, attributeFilter: ['data-corner', 'hidden'] });
280
280
  refresh();
281
+ return () => {
282
+ clearTimeout(timer);
283
+ window.removeEventListener('scroll', soon, { capture: true });
284
+ window.removeEventListener('resize', soon);
285
+ document.removeEventListener('visibilitychange', soon);
286
+ window.matchMedia?.('(prefers-color-scheme: dark)').removeEventListener?.('change', soon);
287
+ watch.disconnect();
288
+ };
281
289
  }
@@ -1 +0,0 @@
1
- import{m as g,r as k}from"./c-ZKELCT4T.js";import{a as l,b as n,c as d,h as p}from"./c-NQJRVJ56.js";var b=3e4;function a(){return{ok:!1,code:"failed"}}async function T(o,{etag:r}={}){if(typeof o!="string"||o==="")return a();let m=typeof r=="string"&&r?r:null;if(n()||await p(),!n())return{ok:!1,code:"unsupported"};let s=m||l();if(!s)return{ok:!1,code:"conflict"};let i=new AbortController,y=setTimeout(()=>i.abort(),b);try{let{url:c,options:S}=k(o,!0,i.signal,g(),s),t=await fetch(c,S),f=await t.text(),e={};if(f)try{e=JSON.parse(f)}catch{e={}}if(!t.ok)return t.status===412?{ok:!1,code:"conflict"}:t.status===401||t.status===403?{ok:!1,code:"forbidden"}:a();let u=typeof e.etag=="string"&&e.etag?e.etag:null;return d(u),{ok:!0,etag:u}}catch{return a()}finally{clearTimeout(y)}}export{T as a};
@@ -1 +0,0 @@
1
- import{a,b}from"./c-6RC66MYY.js";import"./c-QHWJ5ZIJ.js";import"./c-6KBKYLPO.js";import"./c-IHUWUKIU.js";import"./c-4JZDZFF6.js";import"./c-EUGJVHDD.js";import"./c-MHI3GYKF.js";import"./c-46XYM55L.js";import"./c-NUHP2XDB.js";import"./c-VHNSBD2M.js";export{a as SURFACE_THEME,b as default};
@@ -1 +0,0 @@
1
- import{a,b,c,d,e}from"./c-HWR6GMGK.js";import"./c-6RC66MYY.js";import"./c-QHWJ5ZIJ.js";import"./c-FAXQU7MQ.js";import"./c-UL2YUY52.js";import"./c-QY7F6EN6.js";import"./c-6KBKYLPO.js";import"./c-IHUWUKIU.js";import"./c-4JZDZFF6.js";import"./c-EUGJVHDD.js";import"./c-MHI3GYKF.js";import"./c-46XYM55L.js";import"./c-NUHP2XDB.js";import"./c-VKEDWYDF.js";import"./c-ICMAOOGK.js";import"./c-WRBKEJD4.js";import"./c-VHNSBD2M.js";export{a as ask,b as consent,e as init,d as snippet,c as tell};
@@ -1 +0,0 @@
1
- import{a as $}from"./c-XQXZAO7N.js";import{e as Y}from"./c-S7LK4KUE.js";import{c as z}from"./c-VG5XIN4T.js";import{b as H,i as I,o as N}from"./c-HA6INT6J.js";import{c as D,h as A,j as T,k,n as C,o as L}from"./c-ICMAOOGK.js";var K=[],i=[],g=new WeakMap,w=null,B=null,b=0;function de(){return b}function V(e){return g.get(e)||null}var M=new WeakMap,v=null;function he(){return v}function me(e){v&&e&&(v.artifact=e)}var R=null,x=new Map;function ye(e){R=e}function ve(e){return e==null?null:x.get(e)??null}function Se(e){return e&&M.get(e)||null}function j(e){e&&(M.delete(e),x.delete(e.captureId))}function W(e){let t=o=>{if(o.hasAttribute("onbeforesave")||o.hasAttribute("onbeforesnapshot"))return!0;let r=o.localName==="template"&&o.content?o.content:o;for(let n of r.children)if(t(n))return!0;return!1};return e.nodeType===1?t(e):!1}function l(e){for(let t of e.querySelectorAll(L))t.remove()}function h(e,t){for(let o of e.querySelectorAll(`[${t}]`))if(l(e),!(o!==e&&!e.contains(o)))try{new Function(o.getAttribute(t)).call(o)}catch(r){console.error(`[${t}] handler failed:`,r)}}var O=null;function Ce(e){O=e}function xe(e){return O?.(e),e}function Ae(e){K.push(e)}function Te(e,{steps:t=null}={}){w=e,B=t}var G="http://www.w3.org/1999/xhtml";function P(e){let t=X(e);if(!t.length)return"<!DOCTYPE html>"+e.outerHTML;let o=J(t),r;try{r="<!DOCTYPE html>"+e.outerHTML}finally{for(let[n,c]of t)n.replaceChildren(...c)}for(let[n,c]of o)r=r.split(n).join(c);return r}function X(e){let t=[],o=r=>{for(let n of r.childNodes)if(n.nodeType===1){if(n.localName==="noscript"&&n.namespaceURI===G){let c=Array.from(n.childNodes);c.length&&c.every(a=>a.nodeType===3)&&t.push([n,c]);continue}o(n.localName==="template"&&n.content?n.content:n)}};return o(e),t}function J(e){let t=Math.random().toString(36).slice(2);return e.map(([o,r],n)=>{let c=`\uE000clay-noscript-${t}-${n}\uE000`;return o.replaceChildren(o.ownerDocument.createTextNode(c)),[c,r.map(a=>a.data).join("")]})}function U(e,t){let o=v;v=e;try{return t()}finally{v=o}}function q(e,t=null){if(t&&R){let r=null;try{r=R(e)}catch{}r&&x.set(t.captureId,r)}let o=P(e);if(!w)return o;try{return U(t,()=>w(e,o))}catch(r){return console.error("clayjs: save renderer failed, sending the full serialization",r),o}}function ge(e){i.push(e)}function d(e,t=!0){let o=window.__preventOnclone;window.__preventOnclone=!0;try{return e.cloneNode(t)}finally{window.__preventOnclone=o}}function E(e,t){let o=g.get(e);o&&g.set(t,o);let r=e.children,n=t.children;for(let c=0;c<r.length;c++)E(r[c],n[c])}function f({flushUndo:e=!0,authored:t=!0,forSave:o=!1,requestRefresh:r=!1,context:n=null}={}){e&&typeof window<"u"&&window.clay?.undo?.flush&&window.clay.undo.flush();let a=$(document.documentElement,{capability:"snapshot",provenance:g}).root;for(let m of K)l(a),m(a,{original:V,forSave:o,requestRefresh:r});return Y(a),O?.(a),l(a),n&&(n.authoredHandlers=W(a)),t&&h(a,"onbeforesnapshot"),l(a),D(a),N(a),H(a),a}function _(e,{authored:t=!0}={}){l(e),t&&h(e,"onbeforesave");for(let o of i)l(e),o(e);l(e);for(let o of e.querySelectorAll(A))o.remove();return F(e),e}function F(e){for(let t of e.querySelectorAll("[sap-error]"))t.removeAttribute("sap-error")}function Q({flushUndo:e=!0,authored:t=!0}={}){return _(f({flushUndo:e,authored:t}),{authored:t})}var Z=["style","class"];function ee(e){z(e);for(let t of Z){e.getAttribute(t)===""&&e.removeAttribute(t);for(let o of e.querySelectorAll(`[${t}=""]`))o.removeAttribute(t)}}function S(e){return ee(e),"<!DOCTYPE html>"+e.outerHTML}function we({flushUndo:e=!0}={}){let t=f({flushUndo:e});h(t,"onbeforesave");for(let o of t.querySelectorAll(T))o.remove();for(let o of i)l(t),o(t);return l(t),S(t)}function Re({flushUndo:e=!0}={}){let t=f({flushUndo:e});h(t,"onbeforesave");for(let o of t.querySelectorAll(C))o.remove();for(let o of i)l(t),o(t);return l(t),S(t)}function Ee({flushUndo:e=!0}={}){let t=f({flushUndo:e});h(t,"onbeforesave");let o=t.querySelector(k)?d(t):null;o&&E(t,o);for(let c of t.querySelectorAll(T))c.remove();for(let c of i)l(t),c(t);l(t);let r=S(t),n=r;if(o){for(let c of o.querySelectorAll(C))c.remove();for(let c of i)l(o),c(o);l(o),n=S(o)}return{forComparison:r,forDirty:n}}function te({emitForSync:e=!0,flushUndo:t=!0,requestRefresh:o=!1,forRequest:r=!1,pageFormatMarker:n=null,sliced:c=!1}={}){if(!Number.isSafeInteger(b+1))throw new Error("Save capture identity exhausted");let a=++b,m=r?{captureId:a,authoredHandlers:!1,artifact:null}:null,u=f({flushUndo:t,forSave:e,requestRefresh:o,context:m});e&&document.dispatchEvent(new CustomEvent("clay:snapshot-ready",{detail:{documentElement:u,forSave:!0,captureId:a,sliced:c}})),h(u,"onbeforesave");let y=d(u);E(u,y);let p=u.querySelector(k)?d(u):null;p&&E(u,p);for(let s of i)l(u),s(u);l(u);for(let s of u.querySelectorAll(A))s.remove();F(u);for(let s of y.querySelectorAll(T))s.remove();for(let s of i)l(y),s(y);if(l(y),p){for(let s of p.querySelectorAll(C))s.remove();for(let s of i)l(p),s(p);l(p)}return{captureId:a,context:m,pageFormatMarker:n,clone:u,compareClone:y,dirtyClone:p,renderer:w,rendererSteps:B,pageStateReader:R,result:null}}function oe(e){if(!e.context||!e.pageStateReader)return;let t=null;try{t=e.pageStateReader(e.clone)}catch{}t&&x.set(e.captureId,t)}function re(e,{forSave:t,forComparison:o,forDirty:r}){let n={forSave:t,forComparison:o,forDirty:r,captureId:e.captureId};return e.context&&e.context.artifact&&M.set(n,e.context.artifact),e.result=n,n}function ne(e){j(e.result),x.delete(e.captureId),e.context&&(e.context.artifact=null),e.clone=e.compareClone=e.dirtyClone=null,e.result=null}function _e(e={}){let t=te(e);try{oe(t);let o=P(t.clone),r=t.compareClone?S(t.compareClone):null,n=t.dirtyClone?S(t.dirtyClone):r,c=t.renderer?U(t.context,()=>t.renderer(t.clone,o)):o;return re(t,{forSave:c,forComparison:r,forDirty:n})}catch(o){throw ne(t),o}}function ke(){let e=f({flushUndo:!1});h(e,"onbeforesave");let t=d(e),o=new WeakMap;(function r(n,c){o.set(n,c);let a=n.children,m=c.children;for(let u=0;u<a.length;u++)r(a[u],m[u])})(t,e);for(let r of i)l(e),r(e);l(e);for(let r of e.querySelectorAll(A))r.remove();F(e);for(let r of t.querySelectorAll(C))r.remove();for(let r of i)l(t),r(t);return l(t),{saveClone:e,compareClone:t,pairMap:o}}function ce({emitForSync:e=!0}={}){let t=f();return e&&document.dispatchEvent(new CustomEvent("clay:snapshot-ready",{detail:{documentElement:t}})),q(_(t))}function be(e){let t=d(e,!1);for(let n of I)t.removeAttribute(n);let o=t.outerHTML,r=`</${t.localName}>`;return"<!DOCTYPE html>"+o.slice(0,o.length-r.length)+e.innerHTML+r}function Me(e){return d(e)}function Oe(){return f().querySelector("body").innerHTML}function Pe({transform:e=null,flushUndo:t=!0}={}){if(!e&&t)return ce({emitForSync:!1});let o=f({flushUndo:t});if(e){let r=e(o);if(r&&typeof r.then=="function")throw new TypeError("getHTML: the transform must be synchronous")}return q(_(o))}function qe(e,{prepared:t=!1}={}){let o=d(e);return P(t?o:_(o,{authored:!1}))}function Fe(){return q(Q({flushUndo:!1,authored:!1}))}export{de as a,V as b,he as c,me as d,ye as e,ve as f,Se as g,j as h,Ce as i,xe as j,Ae as k,Te as l,P as m,X as n,J as o,U as p,ge as q,d as r,f as s,Q as t,ee as u,S as v,we as w,Re as x,Ee as y,te as z,oe as A,re as B,ne as C,_e as D,ke as E,ce as F,be as G,Me as H,Oe as I,Pe as J,qe as K,Fe as L};