@panphora/clayjs 1.12.1 → 1.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /* clayjs 1.12.1 standalone build: every clayjs module in one file. https://clayjs.com/offline
1
+ /* clayjs 1.12.2 standalone build: every clayjs module in one file. https://clayjs.com/offline
2
2
  Third-party code inside keeps its own license (Sortable MIT, Squire MIT, DOMPurify Apache-2.0 OR MPL-2.0, MicroModal MIT, parse5 MIT): https://clayjs.com/THIRD-PARTY-NOTICES.md */
3
3
  (() => {
4
4
  var __create = Object.create;
@@ -102,29 +102,29 @@
102
102
  });
103
103
 
104
104
  // src/lib/region-capabilities.js
105
- function hasPolicyToken(element, token) {
105
+ function hasPolicyToken(element, token2) {
106
106
  if (!element || element.nodeType !== 1) return false;
107
107
  const clay5 = element.getAttribute?.("clay");
108
- return !!(clay5 && clay5.split(/\s+/).includes(token) || element.hasAttribute?.(token));
108
+ return !!(clay5 && clay5.split(/\s+/).includes(token2) || element.hasAttribute?.(token2));
109
109
  }
110
- function expandsTo(element, token) {
111
- if (hasPolicyToken(element, token)) return true;
110
+ function expandsTo(element, token2) {
111
+ if (hasPolicyToken(element, token2)) return true;
112
112
  for (const [bundle, members] of Object.entries(BUNDLES)) {
113
- if (members.includes(token) && hasPolicyToken(element, bundle)) return true;
113
+ if (members.includes(token2) && hasPolicyToken(element, bundle)) return true;
114
114
  }
115
115
  return false;
116
116
  }
117
117
  function capabilitySelector(capability) {
118
118
  const definition = CAPABILITIES[capability];
119
119
  if (!definition) throw new Error(`Unknown region capability: ${capability}`);
120
- return [...definition.tokens, ...definition.bundles].flatMap((token) => [`[clay~="${token}"]`, `[${token}]`]).join(", ");
120
+ return [...definition.tokens, ...definition.bundles].flatMap((token2) => [`[clay~="${token2}"]`, `[${token2}]`]).join(", ");
121
121
  }
122
122
  function closestWithCapability(node, capability) {
123
123
  let element = node && node.nodeType === 1 ? node : node?.parentElement;
124
124
  while (element && element.nodeType === 1) {
125
125
  const definition = CAPABILITIES[capability];
126
126
  if (!definition) throw new Error(`Unknown region capability: ${capability}`);
127
- if (definition.tokens.some((token) => expandsTo(element, token)) || definition.bundles.some((bundle) => hasPolicyToken(element, bundle))) return element;
127
+ if (definition.tokens.some((token2) => expandsTo(element, token2)) || definition.bundles.some((bundle) => hasPolicyToken(element, bundle))) return element;
128
128
  element = element.parentElement;
129
129
  }
130
130
  return null;
@@ -569,10 +569,10 @@
569
569
  strictestPolicy: () => strictestPolicy,
570
570
  windowRegionShape: () => windowRegionShape
571
571
  });
572
- function addRegionToken(el5, token) {
572
+ function addRegionToken(el5, token2) {
573
573
  const tokens = new Set((el5.getAttribute("clay") || "").trim().split(/\s+/).filter(Boolean));
574
- if (tokens.has(token)) return;
575
- tokens.add(token);
574
+ if (tokens.has(token2)) return;
575
+ tokens.add(token2);
576
576
  el5.setAttribute("clay", Array.from(tokens).join(" "));
577
577
  }
578
578
  function isSnapshotRemoved(node) {
@@ -922,14 +922,14 @@
922
922
  }
923
923
  this._log("Resumed", this._pauseDepth);
924
924
  },
925
- _log(message, data = null, type = "log") {
925
+ _log(message2, data = null, type = "log") {
926
926
  if (!this.debug) return;
927
927
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
928
928
  const prefix = `[Mutation ${timestamp}]`;
929
929
  if (data) {
930
- console[type](prefix, message, data);
930
+ console[type](prefix, message2, data);
931
931
  } else {
932
- console[type](prefix, message);
932
+ console[type](prefix, message2);
933
933
  }
934
934
  },
935
935
  _notify(type, changes2, onlyNonPausable = false) {
@@ -1526,7 +1526,7 @@
1526
1526
  }
1527
1527
  function hasOwnCapability(element, capability) {
1528
1528
  const definition = CAPABILITIES[capability];
1529
- return definition.tokens.some((token) => expandsTo(element, token)) || definition.bundles.some((bundle) => hasPolicyToken(element, bundle));
1529
+ return definition.tokens.some((token2) => expandsTo(element, token2)) || definition.bundles.some((bundle) => hasPolicyToken(element, bundle));
1530
1530
  }
1531
1531
  function pairTree(source3, copy2, maps, drop) {
1532
1532
  if (source3.nodeType === 1 && drop(source3)) {
@@ -2875,8 +2875,8 @@
2875
2875
  }
2876
2876
  async function fetchMeta() {
2877
2877
  if (!/^https?:$/.test(window.location.protocol)) return settle("none");
2878
- const token = saveToken();
2879
- const path = token ? `${META_PATH}/${token}` : META_PATH;
2878
+ const token2 = saveToken();
2879
+ const path = token2 ? `${META_PATH}/${token2}` : META_PATH;
2880
2880
  const controller = new AbortController();
2881
2881
  const timeoutId = setTimeout(() => controller.abort(), META_TIMEOUT_MS);
2882
2882
  try {
@@ -2885,7 +2885,7 @@
2885
2885
  // Same rule as the save lane. The token IS the credential, and a host that
2886
2886
  // mints per-document tokens must never send Access-Control-Allow-Credentials
2887
2887
  // back, so asking for cookies gets the answer blocked before it is read.
2888
- credentials: token ? "omit" : "same-origin",
2888
+ credentials: token2 ? "omit" : "same-origin",
2889
2889
  headers: { "Document-URL": window.location.href },
2890
2890
  cache: "no-store",
2891
2891
  // A redirect is not an answer (§5), and following one would send the
@@ -3162,11 +3162,11 @@
3162
3162
  return { ok: false, msg, msgType: "skipped", code: null, etag: null };
3163
3163
  }
3164
3164
  function buildSaveRequest(content, userDriven, signal, saveId, etag, keepalive = false) {
3165
- const token = saveToken();
3166
- const path = token ? `${SAVE_PATH}/${token}` : SAVE_PATH;
3165
+ const token2 = saveToken();
3166
+ const path = token2 ? `${SAVE_PATH}/${token2}` : SAVE_PATH;
3167
3167
  const options = {
3168
3168
  method: "POST",
3169
- credentials: token ? "omit" : "same-origin",
3169
+ credentials: token2 ? "omit" : "same-origin",
3170
3170
  signal,
3171
3171
  headers: {
3172
3172
  "Document-URL": window.location.href,
@@ -3204,11 +3204,11 @@
3204
3204
  return { ok: status >= 200 && status < 300, status, statusText: status === 200 ? "OK" : "Insufficient Storage", text: () => Promise.resolve(text) };
3205
3205
  }
3206
3206
  function sendToDraftStore(content) {
3207
- const send3 = draftTransport();
3208
- if (!send3) return Promise.resolve(draftResponse(503, { msg: "Saving in this browser is not ready yet", msgType: "error", code: "draft-not-ready" }));
3207
+ const send4 = draftTransport();
3208
+ if (!send4) return Promise.resolve(draftResponse(503, { msg: "Saving in this browser is not ready yet", msgType: "error", code: "draft-not-ready" }));
3209
3209
  return Promise.resolve().then(() => {
3210
3210
  try {
3211
- send3(content);
3211
+ send4(content);
3212
3212
  return draftResponse(200, { msg: "Saved in this browser", msgType: "success" });
3213
3213
  } catch (error) {
3214
3214
  return draftResponse(507, { msg: "Couldn't save in this browser. Storage is full or turned off.", msgType: "error", code: error.code || "draft-storage" });
@@ -3485,12 +3485,12 @@
3485
3485
  changes++;
3486
3486
  scheduleAnnounce();
3487
3487
  }
3488
- function gateClearIfUnchanged(token) {
3489
- if (!token) return;
3490
- if (changes === token.gen) {
3491
- clearedAt = token.gen;
3488
+ function gateClearIfUnchanged(token2) {
3489
+ if (!token2) return;
3490
+ if (changes === token2.gen) {
3491
+ clearedAt = token2.gen;
3492
3492
  }
3493
- for (const [el5, sig] of token.probe) {
3493
+ for (const [el5, sig] of token2.probe) {
3494
3494
  if (controlSignature(el5) === sig) probeCache.set(el5, sig);
3495
3495
  }
3496
3496
  scheduleAnnounce();
@@ -4069,8 +4069,8 @@
4069
4069
  for (const name of events) document.addEventListener(name, onSettle);
4070
4070
  });
4071
4071
  }
4072
- function flushError(message, state2) {
4073
- return Object.assign(new Error(message), { state: state2 });
4072
+ function flushError(message2, state2) {
4073
+ return Object.assign(new Error(message2), { state: state2 });
4074
4074
  }
4075
4075
  function nextEvent(name, deadline) {
4076
4076
  return new Promise((resolve, reject) => {
@@ -4110,9 +4110,9 @@
4110
4110
  for (let attempt = 0; attempt < 4; attempt++) {
4111
4111
  if (isSaveInProgress()) await settled(deadline);
4112
4112
  if (isSaveConflicted()) throw flushError("This document has a conflict to resolve.", "conflict");
4113
- const token = gateCaptureToken();
4113
+ const token2 = gateCaptureToken();
4114
4114
  if (!bytesUnsaved()) {
4115
- gateClearIfUnchanged(token);
4115
+ gateClearIfUnchanged(token2);
4116
4116
  if (hasUnsavedState()) throw flushError("This document has unsaved work a save cannot write.", "blocked");
4117
4117
  return { state: saved2 ? "saved" : "clean", etag: etag ?? lastSeenEtag() };
4118
4118
  }
@@ -4354,8 +4354,8 @@
4354
4354
  setPageDataLiveSync: () => setPageDataLiveSync,
4355
4355
  writeData: () => writeData
4356
4356
  });
4357
- function refusal(code, message, details) {
4358
- const error = new Error(message);
4357
+ function refusal(code, message2, details) {
4358
+ const error = new Error(message2);
4359
4359
  error.code = code;
4360
4360
  error.details = details;
4361
4361
  return error;
@@ -4371,8 +4371,8 @@
4371
4371
  body = await responseBody(response) || {};
4372
4372
  } catch {
4373
4373
  }
4374
- const message = body.message || body.error || response.statusText || `Request failed (${response.status})`;
4375
- const error = new Error(message);
4374
+ const message2 = body.message || body.error || response.statusText || `Request failed (${response.status})`;
4375
+ const error = new Error(message2);
4376
4376
  error.status = response.status;
4377
4377
  error.error = body.error;
4378
4378
  error.details = body.details;
@@ -4468,7 +4468,7 @@
4468
4468
  }
4469
4469
  function createPageDataApi({
4470
4470
  supports = hostSupports,
4471
- token = saveToken,
4471
+ token: token2 = saveToken,
4472
4472
  fetchImpl = (...args) => fetch(...args),
4473
4473
  getLocation = () => window.location,
4474
4474
  eventTarget = document,
@@ -4570,7 +4570,7 @@
4570
4570
  "Content-Type": "application/json",
4571
4571
  "If-Match": match
4572
4572
  };
4573
- const currentToken = token();
4573
+ const currentToken = token2();
4574
4574
  if (currentToken) headers["Save-Token"] = currentToken;
4575
4575
  const body = JSON.stringify(values);
4576
4576
  waiter = syncWaiter(eventTarget, syncTimeoutMs);
@@ -13610,8 +13610,8 @@
13610
13610
  RETRY_MS = 2e3;
13611
13611
  EVENTS = ["focusin", "focusout", "selectionchange", "clay:sync-applied", "clay:workspace-background", "clay:workspace-foreground"];
13612
13612
  EditingSender = class {
13613
- constructor({ send: send3, now: now3 = () => Date.now() }) {
13614
- this.send = send3;
13613
+ constructor({ send: send4, now: now3 = () => Date.now() }) {
13614
+ this.send = send4;
13615
13615
  this.now = now3;
13616
13616
  this.others = false;
13617
13617
  this.background = false;
@@ -14149,13 +14149,13 @@
14149
14149
  get unresolvedConflicts() {
14150
14150
  return conflicts.list().filter((c2) => c2.kind !== "apply-incomplete");
14151
14151
  }
14152
- _log(message, data = null) {
14152
+ _log(message2, data = null) {
14153
14153
  if (!this.debug) return;
14154
14154
  const prefix = `[LiveSync ${(/* @__PURE__ */ new Date()).toISOString()}]`;
14155
14155
  if (data !== null) {
14156
- console.log(prefix, message, data);
14156
+ console.log(prefix, message2, data);
14157
14157
  } else {
14158
- console.log(prefix, message);
14158
+ console.log(prefix, message2);
14159
14159
  }
14160
14160
  }
14161
14161
  /**
@@ -15085,7 +15085,7 @@
15085
15085
  ...extra
15086
15086
  };
15087
15087
  const dirty = this.lane === "live" && pageMaybeDirty();
15088
- const token = gateCaptureToken();
15088
+ const token2 = gateCaptureToken();
15089
15089
  let pending4;
15090
15090
  let localRoot = null;
15091
15091
  let applyId = null;
@@ -15150,7 +15150,7 @@
15150
15150
  }
15151
15151
  throw err;
15152
15152
  }
15153
- const typedDuringWait = gateCaptureToken().gen !== token.gen;
15153
+ const typedDuringWait = gateCaptureToken().gen !== token2.gen;
15154
15154
  let conflictIds;
15155
15155
  try {
15156
15156
  lineageCapture.prepareComplete(report2, conflicts.list());
@@ -15159,7 +15159,7 @@
15159
15159
  lineageCapture.finish(conflicts.list());
15160
15160
  }
15161
15161
  if (dirty && !report2.localDiverged) {
15162
- gateClearIfUnchanged(token);
15162
+ gateClearIfUnchanged(token2);
15163
15163
  }
15164
15164
  const mapIds = new Set(isIdMap(identityMap) ? Object.values(identityMap) : []);
15165
15165
  for (const [el5, id2] of report2.identities) {
@@ -16477,12 +16477,12 @@
16477
16477
  function drawBar(m2) {
16478
16478
  const n2 = m2 === "failed" ? failures().length : losses().length;
16479
16479
  const bar2 = bevelSurface("div", ["display:flex", "flex-wrap:wrap", "align-items:center", "gap:10px 12px", "padding:8px 8px 8px 14px", "width:max-content", "max-width:calc(100vw - 24px)"]);
16480
- const message = barMessage(m2, n2);
16481
- if (message !== lastAnnounced) {
16480
+ const message2 = barMessage(m2, n2);
16481
+ if (message2 !== lastAnnounced) {
16482
16482
  bar2.setAttribute("role", m2 === "refused" ? "alert" : "status");
16483
- lastAnnounced = message;
16483
+ lastAnnounced = message2;
16484
16484
  }
16485
- bar2.append(dot(), bevelText("span", [], message), key(bevelButton("Review", { onClick: openPanel }), "review"));
16485
+ bar2.append(dot(), bevelText("span", [], message2), key(bevelButton("Review", { onClick: openPanel }), "review"));
16486
16486
  return bar2;
16487
16487
  }
16488
16488
  function action(label, name, { variant = "default", onClick: onClick2, push = false } = {}) {
@@ -16806,8 +16806,8 @@
16806
16806
  return;
16807
16807
  }
16808
16808
  if (Date.now() - armedAt < DOUBLE_PRESS_MS) return;
16809
- const token = armed;
16810
- const current4 = () => armed === token && token.refusalGeneration === refusalGeneration && token.ledgerRevision === ledgerRevision && token.dirtyGeneration === gateCaptureToken().gen;
16809
+ const token2 = armed;
16810
+ const current4 = () => armed === token2 && token2.refusalGeneration === refusalGeneration && token2.ledgerRevision === ledgerRevision && token2.dirtyGeneration === gateCaptureToken().gen;
16811
16811
  if (!reloadAfterDiscard({ isCurrent: current4, reload: () => window.location.reload() })) {
16812
16812
  disarm();
16813
16813
  armLost = true;
@@ -22888,8 +22888,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
22888
22888
  const retired = /* @__PURE__ */ new Set();
22889
22889
  const kept = /* @__PURE__ */ new Map();
22890
22890
  let mirror = { epoch: null, seq: 0, sequencer: null, closedBy: null, stale: false, seen: /* @__PURE__ */ new Map(), stores: /* @__PURE__ */ new Map() };
22891
- function post(message) {
22892
- channel?.postMessage({ v: VERSION, ...message });
22891
+ function post2(message2) {
22892
+ channel?.postMessage({ v: VERSION, ...message2 });
22893
22893
  }
22894
22894
  function pushLog(m2, entry) {
22895
22895
  entry.bytes = encoder2.encode(JSON.stringify(entry.ops)).length;
@@ -22981,7 +22981,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
22981
22981
  }
22982
22982
  function announce() {
22983
22983
  const state2 = roomState();
22984
- post({ type: "data-state", state: state2 });
22984
+ post2({ type: "data-state", state: state2 });
22985
22985
  handlers2.state(state2);
22986
22986
  }
22987
22987
  function renewEpoch() {
@@ -23040,7 +23040,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
23040
23040
  }
23041
23041
  function closeRoom() {
23042
23042
  if (!room) return;
23043
- post({ type: "closed", from: clientId, state: roomState() });
23043
+ post2({ type: "closed", from: clientId, state: roomState() });
23044
23044
  room = null;
23045
23045
  releaseLock?.();
23046
23046
  releaseLock = null;
@@ -23100,7 +23100,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
23100
23100
  room.lastN.set(nKey, { n: frame.n, seq: room.seq });
23101
23101
  const data = { epoch: room.epoch, seq: room.seq, name: frame.name, ops, from, n: frame.n };
23102
23102
  advance(data);
23103
- post({ type: "data", data });
23103
+ post2({ type: "data", data });
23104
23104
  handlers2.frame(cloneJson(data));
23105
23105
  return { status: 200, body: { seq: room.seq, epoch: room.epoch }, retryAfter: 0 };
23106
23106
  }
@@ -23186,7 +23186,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
23186
23186
  if (changed2) announce();
23187
23187
  else tellLanded(moved);
23188
23188
  }
23189
- function request(message) {
23189
+ function request(message2) {
23190
23190
  return new Promise((resolve) => {
23191
23191
  const id2 = ++rid;
23192
23192
  const timer = setTimeout(() => {
@@ -23194,14 +23194,14 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
23194
23194
  ownPosts.delete(id2);
23195
23195
  resolve(null);
23196
23196
  }, REQUEST_MS);
23197
- if (message.type === "post") ownPosts.set(id2, mirror.sequencer);
23197
+ if (message2.type === "post") ownPosts.set(id2, mirror.sequencer);
23198
23198
  waiting.set(id2, (result2) => {
23199
23199
  clearTimeout(timer);
23200
23200
  waiting.delete(id2);
23201
23201
  ownPosts.delete(id2);
23202
23202
  resolve(result2);
23203
23203
  });
23204
- post({ ...message, from: clientId, rid: id2 });
23204
+ post2({ ...message2, from: clientId, rid: id2 });
23205
23205
  });
23206
23206
  }
23207
23207
  function onData(data) {
@@ -23236,7 +23236,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
23236
23236
  return;
23237
23237
  }
23238
23238
  if (!room && m2.type === "data-state" && m2.state?.epoch === mirror.epoch && m2.state.writer !== mirror.sequencer && Number.isInteger(m2.state.seq) && m2.state.seq < mirror.seq) {
23239
- post({ type: "forked", epoch: mirror.epoch, to: m2.state.writer });
23239
+ post2({ type: "forked", epoch: mirror.epoch, to: m2.state.writer });
23240
23240
  return;
23241
23241
  }
23242
23242
  if (m2.type === "forked") {
@@ -23254,9 +23254,9 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
23254
23254
  } else if (m2.type === "answer") {
23255
23255
  if (m2.to === clientId) waiting.get(m2.rid)?.(m2.result);
23256
23256
  } else if (room && m2.type === "post") {
23257
- if (m2.epoch === room.epoch) post({ type: "answer", to: m2.from, rid: m2.rid, result: roomApply(m2.from, m2.frame) });
23257
+ if (m2.epoch === room.epoch) post2({ type: "answer", to: m2.from, rid: m2.rid, result: roomApply(m2.from, m2.frame) });
23258
23258
  } else if (room && m2.type === "state-request") {
23259
- post({ type: "answer", to: m2.from, rid: m2.rid, result: roomState() });
23259
+ post2({ type: "answer", to: m2.from, rid: m2.rid, result: roomState() });
23260
23260
  }
23261
23261
  }
23262
23262
  function onPageHide() {
@@ -23317,7 +23317,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
23317
23317
  landed(name, at4) {
23318
23318
  if (stopped || !at4) return;
23319
23319
  if (applyLanded(name, at4)) tellLanded([name]);
23320
- post({ type: "landed", name, at: { epoch: at4.epoch, seq: at4.seq } });
23320
+ post2({ type: "landed", name, at: { epoch: at4.epoch, seq: at4.seq } });
23321
23321
  },
23322
23322
  get isSequencer() {
23323
23323
  return room !== null;
@@ -32069,8 +32069,8 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
32069
32069
  }
32070
32070
  function send(file, { onProgress, signal }) {
32071
32071
  return new Promise((resolve) => {
32072
- const token = saveToken();
32073
- const path = token ? `${UPLOAD_PATH}/${token}` : UPLOAD_PATH;
32072
+ const token2 = saveToken();
32073
+ const path = token2 ? `${UPLOAD_PATH}/${token2}` : UPLOAD_PATH;
32074
32074
  const url = new URL(path, window.location.origin).href;
32075
32075
  const xhr = new XMLHttpRequest();
32076
32076
  let settled2 = false;
@@ -32766,8 +32766,8 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
32766
32766
  return new URL(path, window.location.origin).href;
32767
32767
  }
32768
32768
  function wireToken() {
32769
- const token = saveToken();
32770
- return typeof token === "string" && token !== "" ? token : null;
32769
+ const token2 = saveToken();
32770
+ return typeof token2 === "string" && token2 !== "" ? token2 : null;
32771
32771
  }
32772
32772
  function view2(rec) {
32773
32773
  return {
@@ -32800,12 +32800,12 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
32800
32800
  rec.state = state2;
32801
32801
  emit3(rec);
32802
32802
  }
32803
- function arm(rec, ms2, message, { cancelFirst = false, errorCode = null } = {}) {
32803
+ function arm(rec, ms2, message2, { cancelFirst = false, errorCode = null } = {}) {
32804
32804
  clearTimeout(rec.timer);
32805
32805
  rec.timer = setTimeout(() => {
32806
32806
  rec.timer = null;
32807
32807
  if (cancelFirst) postCancel(rec);
32808
- finish(rec, "error", message, { errorCode, errorSource: "client" });
32808
+ finish(rec, "error", message2, { errorCode, errorSource: "client" });
32809
32809
  }, ms2);
32810
32810
  }
32811
32811
  function disarm2(rec) {
@@ -32821,8 +32821,8 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
32821
32821
  }
32822
32822
  function openStream() {
32823
32823
  if (streamReady) return streamReady;
32824
- const token = wireToken();
32825
- const path = `/_/wire/subscribe?page-url=${encodeURIComponent(window.location.href)}` + (token ? `&token=${encodeURIComponent(token)}` : "");
32824
+ const token2 = wireToken();
32825
+ const path = `/_/wire/subscribe?page-url=${encodeURIComponent(window.location.href)}` + (token2 ? `&token=${encodeURIComponent(token2)}` : "");
32826
32826
  stream = new EventSource(wireURL(path));
32827
32827
  stream.onmessage = (event) => {
32828
32828
  let frame;
@@ -33041,8 +33041,8 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
33041
33041
  "Content-Type": "application/json",
33042
33042
  "Page-URL": window.location.href
33043
33043
  };
33044
- const token = wireToken();
33045
- if (token) headers["Save-Token"] = token;
33044
+ const token2 = wireToken();
33045
+ if (token2) headers["Save-Token"] = token2;
33046
33046
  const response = await fetch(wireURL("/_/wire/send"), {
33047
33047
  method: "POST",
33048
33048
  headers,
@@ -33272,6 +33272,183 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
33272
33272
  }
33273
33273
  });
33274
33274
 
33275
+ // src/dom/form-data.js
33276
+ function getDataFromForm(container) {
33277
+ const formData = {};
33278
+ const processElement = (elem) => {
33279
+ const name = elem.getAttribute("name");
33280
+ const value = elem.value ?? elem.getAttribute("value");
33281
+ if (!name || elem.disabled) return;
33282
+ switch (elem.type) {
33283
+ case "checkbox":
33284
+ if (!formData[name]) {
33285
+ formData[name] = [];
33286
+ }
33287
+ if (elem.checked) {
33288
+ formData[name].push(value);
33289
+ }
33290
+ break;
33291
+ case "radio":
33292
+ if (elem.checked) {
33293
+ formData[name] = value;
33294
+ }
33295
+ break;
33296
+ case "select-multiple":
33297
+ formData[name] = Array.from(elem.selectedOptions, (option) => option.value);
33298
+ break;
33299
+ case "button":
33300
+ case "submit":
33301
+ case "reset":
33302
+ if (name && value) {
33303
+ formData[name] = value;
33304
+ }
33305
+ break;
33306
+ default:
33307
+ formData[name] = value;
33308
+ }
33309
+ };
33310
+ if (container instanceof HTMLFormElement) {
33311
+ Array.from(container.elements).forEach(processElement);
33312
+ } else {
33313
+ if (container.hasAttribute("name")) {
33314
+ processElement(container);
33315
+ }
33316
+ const elements = container.querySelectorAll("[name]");
33317
+ elements.forEach(processElement);
33318
+ }
33319
+ return formData;
33320
+ }
33321
+ var form_data_default;
33322
+ var init_form_data = __esm({
33323
+ "src/dom/form-data.js"() {
33324
+ form_data_default = getDataFromForm;
33325
+ }
33326
+ });
33327
+
33328
+ // src/plugins/message.js
33329
+ var message_exports = {};
33330
+ __export(message_exports, {
33331
+ default: () => message_default,
33332
+ message: () => message,
33333
+ send: () => send3
33334
+ });
33335
+ function fetchToken() {
33336
+ if (!tokenRequest) {
33337
+ tokenRequest = fetch(TOKEN_PATH, { credentials: "omit", cache: "no-store" }).then((res) => res.ok ? res.json() : null).then((body) => {
33338
+ if (body && typeof body.token === "string") {
33339
+ token = body.token;
33340
+ tokenAt = Date.now();
33341
+ }
33342
+ }).catch(() => {
33343
+ }).finally(() => {
33344
+ tokenRequest = null;
33345
+ });
33346
+ }
33347
+ return tokenRequest;
33348
+ }
33349
+ async function takeToken() {
33350
+ if (!token || Date.now() - tokenAt > TOKEN_MAX_AGE_MS) await fetchToken();
33351
+ const taken = token;
33352
+ token = null;
33353
+ return taken;
33354
+ }
33355
+ function signals() {
33356
+ return { webdriver: navigator.webdriver === true, trusted: { ...trusted } };
33357
+ }
33358
+ function isMessageForm(form) {
33359
+ if (!(form instanceof HTMLFormElement)) return false;
33360
+ if (form.hasAttribute("message-form")) return true;
33361
+ const action2 = form.getAttribute("action");
33362
+ if (!action2) return false;
33363
+ try {
33364
+ const url = new URL(action2, window.location.href);
33365
+ return url.origin === window.location.origin && url.pathname === MESSAGE_PATH;
33366
+ } catch {
33367
+ return false;
33368
+ }
33369
+ }
33370
+ async function send3(data = {}) {
33371
+ const result2 = await post(data);
33372
+ if (result2.code === "form-token") return post(data);
33373
+ return result2;
33374
+ }
33375
+ async function post(data) {
33376
+ const formToken = await takeToken();
33377
+ let res;
33378
+ try {
33379
+ res = await fetch(MESSAGE_PATH, {
33380
+ method: "POST",
33381
+ // A signed-in owner testing their own form must not trip the host's CSRF
33382
+ // guard, and the message never needs the visitor's cookies.
33383
+ credentials: "omit",
33384
+ headers: { "Content-Type": "application/json", "Document-URL": window.location.href },
33385
+ body: JSON.stringify({ ...data, formToken, formSignals: signals() })
33386
+ });
33387
+ } catch {
33388
+ return { ok: false, error: "The message couldn't be sent. Check your connection and try again." };
33389
+ }
33390
+ const body = await res.json().catch(() => null);
33391
+ if (res.ok) return body ? { ok: true, error: null } : { ok: false, error: "This page can't send messages." };
33392
+ if (!body) return { ok: false, error: `The message couldn't be sent (${res.status}).` };
33393
+ const error = body.error || body.msg || `The message couldn't be sent (${res.status}).`;
33394
+ return body.code === "form-token" ? { ok: false, error, code: "form-token" } : { ok: false, error };
33395
+ }
33396
+ async function onSubmit(event) {
33397
+ const form = event.target;
33398
+ if (event.defaultPrevented || !isMessageForm(form)) return;
33399
+ event.preventDefault();
33400
+ if (sending.has(form)) return;
33401
+ sending.add(form);
33402
+ try {
33403
+ const result2 = await send3(form_data_default(form));
33404
+ if (result2.ok) form.reset();
33405
+ const outcome2 = new CustomEvent(result2.ok ? "clay:message-sent" : "clay:message-failed", {
33406
+ bubbles: true,
33407
+ cancelable: true,
33408
+ detail: result2
33409
+ });
33410
+ if (!form.dispatchEvent(outcome2)) return;
33411
+ const toast3 = window.clay?.toast;
33412
+ if (!toast3) return;
33413
+ if (result2.ok) toast3(form.getAttribute("message-form") || "Sent", "success");
33414
+ else toast3(result2.error, "error");
33415
+ } finally {
33416
+ sending.delete(form);
33417
+ }
33418
+ }
33419
+ function warmToken(event) {
33420
+ if (token || tokenRequest) return;
33421
+ const form = event.target?.closest?.("form");
33422
+ if (form && isMessageForm(form)) fetchToken();
33423
+ }
33424
+ var MESSAGE_PATH, TOKEN_PATH, TOKEN_MAX_AGE_MS, TRUSTED_EVENTS, trusted, token, tokenAt, tokenRequest, sending, message, message_default;
33425
+ var init_message = __esm({
33426
+ "src/plugins/message.js"() {
33427
+ init_form_data();
33428
+ MESSAGE_PATH = "/_/message";
33429
+ TOKEN_PATH = "/_/form-token";
33430
+ TOKEN_MAX_AGE_MS = 90 * 60 * 1e3;
33431
+ TRUSTED_EVENTS = ["click", "keydown", "pointerdown", "touchstart", "input", "change"];
33432
+ trusted = Object.fromEntries(TRUSTED_EVENTS.map((type) => [type, 0]));
33433
+ token = null;
33434
+ tokenAt = 0;
33435
+ tokenRequest = null;
33436
+ sending = /* @__PURE__ */ new WeakSet();
33437
+ if (typeof document !== "undefined") {
33438
+ for (const type of TRUSTED_EVENTS) {
33439
+ document.addEventListener(type, (event) => {
33440
+ if (event.isTrusted) trusted[type]++;
33441
+ }, { capture: true, passive: true });
33442
+ }
33443
+ document.addEventListener("focusin", warmToken, true);
33444
+ document.addEventListener("input", warmToken, true);
33445
+ document.addEventListener("submit", onSubmit);
33446
+ }
33447
+ message = { send: send3 };
33448
+ message_default = message;
33449
+ }
33450
+ });
33451
+
33275
33452
  // src/plugins/ai-edit.js
33276
33453
  var ai_edit_exports = {};
33277
33454
  __export(ai_edit_exports, {
@@ -33519,11 +33696,11 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
33519
33696
  if (model2) parts.push(`(${model2})`);
33520
33697
  return parts.join(" ");
33521
33698
  }
33522
- function onError(message) {
33699
+ function onError(message2) {
33523
33700
  if (!session) return;
33524
33701
  revertSession();
33525
33702
  showBar("error");
33526
- setBarStatus(message, "warn");
33703
+ setBarStatus(message2, "warn");
33527
33704
  }
33528
33705
  function revertSession() {
33529
33706
  const s2 = session;
@@ -35264,8 +35441,8 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35264
35441
  } };
35265
35442
  return w2;
35266
35443
  }
35267
- function Ge2(e) {
35268
- let t = e && e.ownerDocument ? e.ownerDocument : e, n2 = j(G, t, "api");
35444
+ function Xe2(e) {
35445
+ let t = e && e.ownerDocument ? e.ownerDocument : e, n2 = j(X, t, "api");
35269
35446
  if (!n2) throw new R.NoRulesTag("api");
35270
35447
  return n2.rules;
35271
35448
  }
@@ -35347,29 +35524,29 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35347
35524
  }
35348
35525
  return e instanceof R.WriteRefused ? e.details = e.refusals : e instanceof R.WriteRejected ? e.details = { unknownKeys: e.unknownKeys, unmatched: e.unmatched } : e instanceof R.ShapeMismatch ? e.details = e.mismatches : Array.isArray(e.path) ? e.details = { path: e.path } : typeof e.target == "string" ? e.details = { target: e.target } : e.token !== void 0 ? e.details = { token: e.token } : e.version !== void 0 ? e.details = { version: e.version } : e.details = {}, e;
35349
35526
  }
35350
- function Xe2(e, t) {
35527
+ function Ge2(e, t) {
35351
35528
  let n2 = Te2(e) ? e : document, r = Te2(e) ? t : e;
35352
- return r === void 0 ? C(M(n2), n2, Ge2(n2)) : ne2.bind(n2, r).get();
35529
+ return r === void 0 ? C(M(n2), n2, Xe2(n2)) : ne2.bind(n2, r).get();
35353
35530
  }
35354
35531
  function Ye2(e, t, n2) {
35355
35532
  try {
35356
35533
  if (!Te2(e)) throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");
35357
- let r = n2 === void 0 ? Ge2(e) : ne2.bind(e, n2).rules;
35534
+ let r = n2 === void 0 ? Xe2(e) : ne2.bind(e, n2).rules;
35358
35535
  Wt2(e, r, t);
35359
35536
  } catch (r) {
35360
35537
  throw vt2(r);
35361
35538
  }
35362
35539
  return e;
35363
35540
  }
35364
- var Qe2, et2, X, Y, re2, $2, Ee2, R, k, W2, L2, P2, v, N, B, H, Z2, oe2, se2, Ne2, Pe2, Tt2, _e2, ee2, wt2, De2, me2, Ot2, xt2, Ct2, It2, x, G, ne2, Te2;
35541
+ var Qe2, et2, G, Y, re2, $2, Ee2, R, k, W2, L2, P2, v, N, B, H, Z2, oe2, se2, Ne2, Pe2, Tt2, _e2, ee2, wt2, De2, me2, Ot2, xt2, Ct2, It2, x, X, ne2, Te2;
35365
35542
  var init_hyper_html_api_data_vendor = __esm({
35366
35543
  "src/vendor/hyper-html-api-data.vendor.js"() {
35367
35544
  Qe2 = Object.defineProperty;
35368
35545
  et2 = (e, t) => {
35369
35546
  for (var n2 in t) Qe2(e, n2, { get: t[n2], enumerable: true });
35370
35547
  };
35371
- X = ["textContent", "innerText", "innerHTML", "outerHTML", "value", "checked", "selected", "disabled", "readOnly", "type", "tagName", "nodeName", "nodeType", "nodeValue", "childElementCount", "id", "className", "classList", "baseURI", "offsetWidth", "offsetHeight", "clientWidth", "clientHeight", "scrollWidth", "scrollHeight", "dataset", "currentSrc", "duration", "paused", "title", "documentURI", "contentType"];
35372
- Y = new Set(X);
35548
+ G = ["textContent", "innerText", "innerHTML", "outerHTML", "value", "checked", "selected", "disabled", "readOnly", "type", "tagName", "nodeName", "nodeType", "nodeValue", "childElementCount", "id", "className", "classList", "baseURI", "offsetWidth", "offsetHeight", "clientWidth", "clientHeight", "scrollWidth", "scrollHeight", "dataset", "currentSrc", "duration", "paused", "title", "documentURI", "contentType"];
35549
+ Y = new Set(G);
35373
35550
  re2 = /* @__PURE__ */ new Set(["textContent", "innerText", "innerHTML", "value", "checked", "selected", "disabled", "readOnly", "type", "id", "className", "title"]);
35374
35551
  $2 = /* @__PURE__ */ new Set(["tagName", "nodeName", "nodeType", "nodeValue", "childElementCount", "classList", "baseURI", "documentURI", "contentType", "offsetWidth", "offsetHeight", "clientWidth", "clientHeight", "scrollWidth", "scrollHeight", "currentSrc", "duration", "paused", "dataset"]);
35375
35552
  Ee2 = /* @__PURE__ */ new Set(["checked", "selected", "disabled", "readOnly", "paused"]);
@@ -35500,15 +35677,15 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35500
35677
  }, sameNode(e, t) {
35501
35678
  return e === t;
35502
35679
  } };
35503
- G = x;
35504
- ne2 = { extract: (e, t, n2 = {}) => C(M(e, n2), e, t, n2), apply: (e, t, n2, r = {}) => I2(M(e, { ...r, _write: true }), e, t, n2, r), findRulesIn: (e, t) => j(G, e, t), findRules: (e, t) => Ae2(G, e, t), bind: (e, t, n2 = {}) => {
35505
- let r = Ae2(G, e, t);
35680
+ X = x;
35681
+ ne2 = { extract: (e, t, n2 = {}) => C(M(e, n2), e, t, n2), apply: (e, t, n2, r = {}) => I2(M(e, { ...r, _write: true }), e, t, n2, r), findRulesIn: (e, t) => j(X, e, t), findRules: (e, t) => Ae2(X, e, t), bind: (e, t, n2 = {}) => {
35682
+ let r = Ae2(X, e, t);
35506
35683
  if (!r) {
35507
35684
  let i2 = typeof t == "string" ? `data-rules-name~="${t}"` : "the provided rules object";
35508
35685
  throw new Error(`hyper-html-api: could not resolve rules for ${i2}`);
35509
35686
  }
35510
35687
  return { ...r, get: () => C(M(e, n2), e, r.rules, n2), set: (i2) => I2(M(e, { ...n2, _write: true }), e, r.rules, i2, n2) };
35511
- }, parseStrict: de2, parseRelaxed: z2, ruleAttrIndex: b, splitRule: le2, errors: R, DOM_PROPERTIES: X };
35688
+ }, parseStrict: de2, parseRelaxed: z2, ruleAttrIndex: b, splitRule: le2, errors: R, DOM_PROPERTIES: G };
35512
35689
  Te2 = (e) => !!e && typeof e.nodeType == "number";
35513
35690
  }
35514
35691
  });
@@ -35615,12 +35792,12 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35615
35792
  return { raw, record: parse2(raw) };
35616
35793
  }
35617
35794
  function live2() {
35618
- return Xe2(doc, rules);
35795
+ return Ge2(doc, rules);
35619
35796
  }
35620
35797
  function captured() {
35621
35798
  const getHTML = window.clay?.getHTML;
35622
35799
  if (typeof getHTML !== "function") return live2();
35623
- return Xe2(new DOMParser().parseFromString(getHTML.call(window.clay), "text/html"), rules);
35800
+ return Ge2(new DOMParser().parseFromString(getHTML.call(window.clay), "text/html"), rules);
35624
35801
  }
35625
35802
  function storedKeys() {
35626
35803
  try {
@@ -35695,7 +35872,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35695
35872
  dropped.push(...failing);
35696
35873
  continue;
35697
35874
  }
35698
- const got = Xe2(trial, rules);
35875
+ const got = Ge2(trial, rules);
35699
35876
  const misfits = Object.keys(wanted).filter((name) => !fitsInto(wanted[name], got[name]));
35700
35877
  if (!misfits.length) return { data: wanted, dropped };
35701
35878
  for (const name of misfits) delete wanted[name];
@@ -35773,7 +35950,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35773
35950
  if (unparked != null && park(unparked, { keepSlot: true }) === null) {
35774
35951
  throw storageFailure(doc, new Error("an earlier saved copy could not be kept aside"));
35775
35952
  }
35776
- const mine = Xe2(new DOMParser().parseFromString(html, "text/html"), rules);
35953
+ const mine = Ge2(new DOMParser().parseFromString(html, "text/html"), rules);
35777
35954
  const current4 = getRaw();
35778
35955
  if (fitsInto(mine, base) && (current4 === lastRaw || current4 == null)) {
35779
35956
  setDraftStoreFailed(false);
@@ -35895,11 +36072,6 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
35895
36072
  if (path && !/\.(html|htmlclay)$/.test(path)) path += ".html";
35896
36073
  return `/_/download${path}?as=htmlclay${src ? `&src=${encodeURIComponent(src)}` : ""}`;
35897
36074
  }
35898
- function signupTag(slot2, template) {
35899
- const explicit = template?.getAttribute("signup-tag");
35900
- const name = explicit || slot2.replace(/-v\d+$/, "");
35901
- return `app-${name}`.slice(0, 50);
35902
- }
35903
36075
  var SRC;
35904
36076
  var init_source = __esm({
35905
36077
  "src/plugins/visitor-drafts/source.js"() {
@@ -36004,6 +36176,8 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36004
36176
  .hcp .hcp-btn--primary:hover { background: color-mix(in srgb, var(--hcp-ink), var(--hcp-ground) 12%); color: var(--hcp-ground); }
36005
36177
 
36006
36178
  .hcp-dock { display: flex; align-items: stretch; box-shadow: 0 6px 16px -8px rgba(43, 36, 27, .45); }
36179
+ .hcp:not([data-hcp-arrived]) .hcp-dock { animation: hcp-arrive 2.4s cubic-bezier(.16, 1, .3, 1) 3s both; }
36180
+ @keyframes hcp-arrive { from { transform: translateX(calc(100% + 48px)); } to { transform: none; } }
36007
36181
  .hcp-tab { font-size: 13.5px; padding: 0 12px 0 10px; }
36008
36182
  .hcp-tab svg { color: var(--hcp-brass); }
36009
36183
  .hcp-dock .hcp-x {
@@ -36064,22 +36238,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36064
36238
  .hcp-file small { display: block; font-size: 12px; color: var(--hcp-muted); line-height: 1.4; }
36065
36239
  .hcp-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
36066
36240
  .hcp-actions .hcp-btn--primary { flex: 1 1 auto; }
36067
- .hcp-signup { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--hcp-line); }
36068
- .hcp-signup label { display: block; font-size: 13px; line-height: 1.45; color: var(--hcp-ink-2); margin-bottom: 8px; }
36069
- .hcp-signup-row { display: flex; gap: 8px; }
36070
- .hcp-signup-row[hidden] { display: none; }
36071
- .hcp-signup input[type="email"] {
36072
- flex: 1 1 auto; min-width: 0; height: 34px; padding: 0 10px; margin: 0;
36073
- font: 14px var(--hcp-sans); color: var(--hcp-ink); background: var(--hcp-surface);
36074
- border: 1px solid var(--hcp-line-2); border-radius: 0; box-shadow: none;
36075
- }
36076
- .hcp-signup input[type="email"]:focus-visible { outline: 2px solid var(--hcp-brass); outline-offset: 1px; }
36077
- .hcp-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
36078
- .hcp-msg { margin-top: 8px; font-size: 13px; color: var(--hcp-ink-2); }
36079
- .hcp[data-hcp-reason="error"] .hcp-signup { display: none; }
36080
- @media (max-width: 360px) { .hcp-signup-row { flex-direction: column; } }
36081
- .hcp-foot { margin-top: 12px; display: flex; justify-content: space-between; align-items: center; gap: 10px; }
36082
- .hcp-foot small { font-size: 12px; color: var(--hcp-muted); }
36241
+ .hcp-foot { margin-top: 12px; display: flex; justify-content: flex-end; }
36083
36242
  .hcp-quiet {
36084
36243
  min-height: 0; border-radius: 0;
36085
36244
  font-size: 12px; color: var(--hcp-muted); cursor: pointer;
@@ -36101,6 +36260,8 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36101
36260
  @media (prefers-reduced-motion: reduce) {
36102
36261
  .hcp { transition: none; }
36103
36262
  .hcp[data-hcp-state="card"] .hcp-card { animation: none; }
36263
+ .hcp:not([data-hcp-arrived]) .hcp-dock { animation: hcp-arrive-fade .4s ease 3s both; }
36264
+ @keyframes hcp-arrive-fade { from { opacity: 0; } to { opacity: 1; } }
36104
36265
  .hcp-btn:active > span { translate: none; }
36105
36266
  }
36106
36267
  @media (forced-colors: active) {
@@ -36148,7 +36309,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36148
36309
  });
36149
36310
 
36150
36311
  // src/plugins/visitor-drafts/prompt.js
36151
- function mountPrompt({ memory, appName, link: link2, tag, source: source3 }) {
36312
+ function mountPrompt({ memory, appName, link: link2 }) {
36152
36313
  if (!document.getElementById("hcp-style")) {
36153
36314
  document.head.insertAdjacentHTML("beforeend", `<link rel="stylesheet" clay="editor-ui" href="${FONT_HREF}">
36154
36315
  <style clay="editor-ui" id="hcp-style">${PROMPT_CSS}</style>`);
@@ -36164,30 +36325,6 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36164
36325
  const OUR_UI = "#hcp, .clay-intro, .clay-owner";
36165
36326
  const linkEl = root3.querySelector("[data-hcp-link]");
36166
36327
  linkEl.href = link2;
36167
- const signup = root3.querySelector("[data-hcp-signup]");
36168
- if (signup) {
36169
- const email = signup.querySelector("#hcp-email");
36170
- const honey = signup.querySelector(".hcp-hp");
36171
- const row = signup.querySelector(".hcp-signup-row");
36172
- const message = signup.querySelector(".hcp-msg");
36173
- signup.addEventListener("submit", (event) => {
36174
- event.preventDefault();
36175
- fetch("/_/newsletter/subscribe", {
36176
- method: "POST",
36177
- headers: { "Content-Type": "application/json" },
36178
- credentials: "same-origin",
36179
- body: JSON.stringify({ email: email.value.trim(), tags: [tag], source: source3, website: honey.value })
36180
- }).then((response) => {
36181
- if (!response.ok) throw new Error("signup failed");
36182
- row.hidden = true;
36183
- message.textContent = SIGNUP_COPY.thanks;
36184
- message.hidden = false;
36185
- }).catch(() => {
36186
- message.textContent = SIGNUP_COPY.failed;
36187
- message.hidden = false;
36188
- });
36189
- });
36190
- }
36191
36328
  if (appName) root3.querySelector("[data-hcp-name]").textContent = appName;
36192
36329
  const tab = root3.querySelector("[data-hcp=open]");
36193
36330
  function set3(state2, reason) {
@@ -36198,6 +36335,7 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36198
36335
  if (state2 === "card") {
36199
36336
  mem.shown = true;
36200
36337
  memory.save();
36338
+ root3.setAttribute("data-hcp-arrived", "");
36201
36339
  }
36202
36340
  lift();
36203
36341
  }
@@ -36293,6 +36431,9 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36293
36431
  memory.save();
36294
36432
  }
36295
36433
  });
36434
+ root3.addEventListener("animationend", (e) => {
36435
+ if (e.animationName === "hcp-arrive" || e.animationName === "hcp-arrive-fade") root3.setAttribute("data-hcp-arrived", "");
36436
+ });
36296
36437
  root3.addEventListener("keydown", (e) => {
36297
36438
  if (e.key === "Escape" && root3.getAttribute("data-hcp-state") === "card") {
36298
36439
  set3("mini");
@@ -36321,15 +36462,11 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36321
36462
  if (!mem.shown && (mem.uses || 0) >= USES_TO_SHOW) maybeShow("return");
36322
36463
  return api;
36323
36464
  }
36324
- var SIGNUP_COPY, FONT_HREF, ASIDE;
36465
+ var FONT_HREF, ASIDE;
36325
36466
  var init_prompt = __esm({
36326
36467
  "src/plugins/visitor-drafts/prompt.js"() {
36327
36468
  init_prompt_style();
36328
36469
  init_bottom_ui();
36329
- SIGNUP_COPY = {
36330
- thanks: "Thanks. Check your email for a link to confirm.",
36331
- failed: "That didn't go through. Check the address and try again."
36332
- };
36333
36470
  FONT_HREF = "https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@500&family=IBM+Plex+Sans:wght@400;500;600&family=Newsreader:opsz,wght@6..72,500&display=swap";
36334
36471
  ASIDE = `<aside class="hcp" id="hcp" hidden aria-label="Download this app" data-hcp-state="tab" data-hcp-reason="open" sap-ignore clay="editor-ui">
36335
36472
  <section class="hcp-card" id="hcp-card" role="dialog" aria-modal="false" aria-labelledby="hcp-title">
@@ -36341,18 +36478,10 @@ tr.hcms-shell.hcms-inline-ghost { display: table-row; }
36341
36478
  <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z"/></svg>
36342
36479
  <div><b class="hcp-name" data-hcp-name>This app</b><small>One file with the whole app and your work in it</small></div>
36343
36480
  </div>
36344
- <p class="hcp-body">Open it with HTML Clay, a free app for Mac, Windows and Linux. It opens the file in a window and saves every change into it, so your work stays on your computer.</p>
36345
36481
  <div class="hcp-actions">
36346
36482
  <a class="hcp-btn hcp-btn--primary" data-hcp-link href="/_/download?as=htmlclay"><span><svg width="16" height="16" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z"/></svg>Download free</span></a>
36347
- <button type="button" class="hcp-btn" data-hcp="minimize"><span>Not now</span></button>
36348
36483
  </div>
36349
- <form class="hcp-signup" data-hcp-signup novalidate>
36350
- <label for="hcp-email">I make one of these about every two weeks. Get the next one by email.</label>
36351
- <div class="hcp-signup-row"><input id="hcp-email" type="email" autocomplete="email" required placeholder="you@example.com"><button type="submit" class="hcp-btn"><span>Send me the next one</span></button></div>
36352
- <input class="hcp-hp" name="website" tabindex="-1" autocomplete="off" aria-hidden="true">
36353
- <p class="hcp-msg" role="status" hidden></p>
36354
- </form>
36355
- <div class="hcp-foot"><small>Free, and the file is yours to keep.</small><button type="button" class="hcp-quiet" data-hcp="dismiss">Don&rsquo;t show again</button></div>
36484
+ <div class="hcp-foot"><button type="button" class="hcp-quiet" data-hcp="dismiss">Don&rsquo;t show again</button></div>
36356
36485
  </section>
36357
36486
  <div class="hcp-dock">
36358
36487
  <button type="button" class="hcp-btn hcp-tab" data-hcp="open" aria-controls="hcp-card" aria-expanded="false" aria-label="This app is free to keep"><span><svg width="16" height="16" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true"><path d="M224,144v64a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V144a8,8,0,0,1,16,0v56H208V144a8,8,0,0,1,16,0Zm-101.66,5.66a8,8,0,0,0,11.32,0l40-40a8,8,0,0,0-11.32-11.32L136,124.69V32a8,8,0,0,0-16,0v92.69L93.66,98.34a8,8,0,0,0-11.32,11.32Z"/></svg><span class="hcp-tab__label">This app is free to keep</span></span></button>
@@ -36735,7 +36864,7 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
36735
36864
  const appName = document.querySelector('meta[name="application-name"]')?.content?.trim() || document.title.split(/:|\s\|\s/)[0].trim() || "This app";
36736
36865
  const template = document.querySelector("template[visitor-intro]");
36737
36866
  const start2 = () => {
36738
- const prompt = mountPrompt({ memory, appName, link: downloadLink, tag: signupTag(slot, template), source });
36867
+ const prompt = mountPrompt({ memory, appName, link: downloadLink });
36739
36868
  mountIntro({ memory, template, appName, hadDraft: result2.hadDraft });
36740
36869
  if (isOwner) mountOwnerChip();
36741
36870
  document.addEventListener("clay:drafts-store-failed", () => prompt.showError());
@@ -42388,7 +42517,7 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
42388
42517
  };
42389
42518
  var ot4 = (e) => it4(re4({}, "__esModule", { value: true }), e);
42390
42519
  var Vt3 = {};
42391
- Se4(Vt3, { applyData: () => xe4, default: () => Ft3, engine: () => X3, extractData: () => Oe4 });
42520
+ Se4(Vt3, { applyData: () => xe4, default: () => Ft3, engine: () => G3, extractData: () => Oe4 });
42392
42521
  var Y3 = ["textContent", "innerText", "innerHTML", "outerHTML", "value", "checked", "selected", "disabled", "readOnly", "type", "tagName", "nodeName", "nodeType", "nodeValue", "childElementCount", "id", "className", "classList", "baseURI", "offsetWidth", "offsetHeight", "clientWidth", "clientHeight", "scrollWidth", "scrollHeight", "dataset", "currentSrc", "duration", "paused", "title", "documentURI", "contentType"], Z4 = new Set(Y3), ie4 = /* @__PURE__ */ new Set(["textContent", "innerText", "innerHTML", "value", "checked", "selected", "disabled", "readOnly", "type", "id", "className", "title"]), $4 = /* @__PURE__ */ new Set(["tagName", "nodeName", "nodeType", "nodeValue", "childElementCount", "classList", "baseURI", "documentURI", "contentType", "offsetWidth", "offsetHeight", "clientWidth", "clientHeight", "scrollWidth", "scrollHeight", "currentSrc", "duration", "paused", "dataset"]), be4 = /* @__PURE__ */ new Set(["checked", "selected", "disabled", "readOnly", "paused"]);
42393
42522
  function oe4(e, t) {
42394
42523
  return t == null ? be4.has(e) ? false : "" : be4.has(e) ? t === "false" ? false : !!t : t;
@@ -43230,13 +43359,13 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
43230
43359
  return p2 ? l.importNode(p2, true) : null;
43231
43360
  } };
43232
43361
  }
43233
- function Xe4(e) {
43362
+ function Ge4(e) {
43234
43363
  return e && e.nodeType === 1 && e.tagName === "SCRIPT" && e.hasAttribute && e.hasAttribute("data-rules-name");
43235
43364
  }
43236
43365
  function $t4(e) {
43237
43366
  return e ? (e.nodeType === 9 || e.nodeType === 11, e) : null;
43238
43367
  }
43239
- function Ge4(e, t, n2) {
43368
+ function Xe4(e, t, n2) {
43240
43369
  !e || e.nodeType !== 1 || (t === "value" && e.tagName === "INPUT" ? e.value = n2 === null ? "" : n2 : t === "checked" && e.tagName === "INPUT" ? e.checked = n2 !== null : t === "selected" && e.tagName === "OPTION" && (e.selected = n2 !== null));
43241
43370
  }
43242
43371
  function Ye4(e, t) {
@@ -43255,7 +43384,7 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
43255
43384
  let i2 = $t4(e);
43256
43385
  if (!i2 || !i2.querySelectorAll) return [];
43257
43386
  let r = Array.from(i2.querySelectorAll(t));
43258
- n2.includeRulesTag || (r = r.filter((c2) => !Xe4(c2)));
43387
+ n2.includeRulesTag || (r = r.filter((c2) => !Ge4(c2)));
43259
43388
  let s2 = [];
43260
43389
  n2.skip && s2.push(n2.skip);
43261
43390
  let l = n2.templateAttr === null ? null : n2.templateAttr || "cms-template";
@@ -43275,9 +43404,9 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
43275
43404
  e.textContent = t, Ye4(e, t);
43276
43405
  }, attr(e, t, n2) {
43277
43406
  if (n2 === void 0) return e.hasAttribute && e.hasAttribute(t) ? e.getAttribute(t) : null;
43278
- e.setAttribute(t, n2), Ge4(e, t, n2);
43407
+ e.setAttribute(t, n2), Xe4(e, t, n2);
43279
43408
  }, removeAttr(e, t) {
43280
- e && e.removeAttribute && e.removeAttribute(t), Ge4(e, t, null);
43409
+ e && e.removeAttribute && e.removeAttribute(t), Xe4(e, t, null);
43281
43410
  }, prop(e, t, n2) {
43282
43411
  if (n2 === void 0) {
43283
43412
  let i2 = e ? e[t] : void 0;
@@ -43345,7 +43474,7 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
43345
43474
  let h = f2(a);
43346
43475
  if (!h?.querySelectorAll) return [];
43347
43476
  let y2 = o2().query(p2, h);
43348
- g.includeRulesTag || (y2 = y2.filter((S2) => !Xe4(S2)));
43477
+ g.includeRulesTag || (y2 = y2.filter((S2) => !Ge4(S2)));
43349
43478
  let A2 = [];
43350
43479
  g.skip && A2.push(g.skip);
43351
43480
  let T2 = g.templateAttr === null ? null : g.templateAttr || "cms-template";
@@ -43452,9 +43581,9 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
43452
43581
  } };
43453
43582
  return w2;
43454
43583
  }
43455
- var G3 = x3;
43456
- var X3 = { extract: (e, t, n2 = {}) => C3(M3(e, n2), e, t, n2), apply: (e, t, n2, i2 = {}) => I4(M3(e, { ...i2, _write: true }), e, t, n2, i2), findRulesIn: (e, t) => j3(G3, e, t), findRules: (e, t) => Te4(G3, e, t), bind: (e, t, n2 = {}) => {
43457
- let i2 = Te4(G3, e, t);
43584
+ var X3 = x3;
43585
+ var G3 = { extract: (e, t, n2 = {}) => C3(M3(e, n2), e, t, n2), apply: (e, t, n2, i2 = {}) => I4(M3(e, { ...i2, _write: true }), e, t, n2, i2), findRulesIn: (e, t) => j3(X3, e, t), findRules: (e, t) => Te4(X3, e, t), bind: (e, t, n2 = {}) => {
43586
+ let i2 = Te4(X3, e, t);
43458
43587
  if (!i2) {
43459
43588
  let r = typeof t == "string" ? `data-rules-name~="${t}"` : "the provided rules object";
43460
43589
  throw new Error(`hyper-html-api: could not resolve rules for ${r}`);
@@ -43462,7 +43591,7 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
43462
43591
  return { ...i2, get: () => C3(M3(e, n2), e, i2.rules, n2), set: (r) => I4(M3(e, { ...n2, _write: true }), e, i2.rules, r, n2) };
43463
43592
  }, parseStrict: pe4, parseRelaxed: z3, ruleAttrIndex: b2, splitRule: ce4, errors: R3, DOM_PROPERTIES: Y3 }, we4 = (e) => !!e && typeof e.nodeType == "number";
43464
43593
  function Qe4(e) {
43465
- let t = e && e.ownerDocument ? e.ownerDocument : e, n2 = j3(G3, t, "api");
43594
+ let t = e && e.ownerDocument ? e.ownerDocument : e, n2 = j3(X3, t, "api");
43466
43595
  if (!n2) throw new R3.NoRulesTag("api");
43467
43596
  return n2.rules;
43468
43597
  }
@@ -43546,19 +43675,19 @@ body:has(> .clay-intro) { height: auto !important; overflow: visible !important;
43546
43675
  }
43547
43676
  function Oe4(e, t) {
43548
43677
  let n2 = we4(e) ? e : document, i2 = we4(e) ? t : e;
43549
- return i2 === void 0 ? C3(M3(n2), n2, Qe4(n2)) : X3.bind(n2, i2).get();
43678
+ return i2 === void 0 ? C3(M3(n2), n2, Qe4(n2)) : G3.bind(n2, i2).get();
43550
43679
  }
43551
43680
  function xe4(e, t, n2) {
43552
43681
  try {
43553
43682
  if (!we4(e)) throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");
43554
- let i2 = n2 === void 0 ? Qe4(e) : X3.bind(e, n2).rules;
43683
+ let i2 = n2 === void 0 ? Qe4(e) : G3.bind(e, n2).rules;
43555
43684
  Ut3(e, i2, t);
43556
43685
  } catch (i2) {
43557
43686
  throw zt3(i2);
43558
43687
  }
43559
43688
  return e;
43560
43689
  }
43561
- var Kt3 = { engine: X3, extractData: Oe4, applyData: xe4 }, Ft3 = Kt3;
43690
+ var Kt3 = { engine: G3, extractData: Oe4, applyData: xe4 }, Ft3 = Kt3;
43562
43691
  return ot4(Vt3);
43563
43692
  })();
43564
43693
  window.clay = window.clay || {};
@@ -46212,7 +46341,7 @@ ${t}` : `"use strict"; return (${t});`;
46212
46341
  document.body.append(box);
46213
46342
  return box;
46214
46343
  }
46215
- function build3(message, type) {
46344
+ function build3(message2, type) {
46216
46345
  const tone = TONES[type];
46217
46346
  const el5 = bevelSurface("div", [
46218
46347
  "display:flex",
@@ -46230,7 +46359,7 @@ ${t}` : `"use strict"; return (${t});`;
46230
46359
  const glyph = bevelText("span", ["display:inline-grid", "flex:none", "padding-top:1px", `color:${tone.edge}`]);
46231
46360
  glyph.innerHTML = tone.icon;
46232
46361
  protectIcon(glyph.firstElementChild, 16);
46233
- const text = bevelText("span", ["flex:1 1 auto", "min-width:120px", ...RULES.toastTitle, "overflow-wrap:anywhere"], message);
46362
+ const text = bevelText("span", ["flex:1 1 auto", "min-width:120px", ...RULES.toastTitle, "overflow-wrap:anywhere"], message2);
46234
46363
  el5.append(glyph, text);
46235
46364
  return el5;
46236
46365
  }
@@ -46280,34 +46409,34 @@ ${t}` : `"use strict"; return (${t});`;
46280
46409
  after?.();
46281
46410
  }, 500);
46282
46411
  }
46283
- function toast2(message, messageType = "success") {
46284
- const el5 = build3(message, TONES[messageType] ? messageType : "success");
46412
+ function toast2(message2, messageType = "success") {
46413
+ const el5 = build3(message2, TONES[messageType] ? messageType : "success");
46285
46414
  el5.addEventListener("click", () => dismiss2(el5));
46286
46415
  reveal(el5);
46287
46416
  setTimeout(() => dismiss2(el5), 6600);
46288
46417
  }
46289
- function toastPersistent(message, messageType = "warning") {
46290
- const existing = activePersistentToasts.get(message);
46418
+ function toastPersistent(message2, messageType = "warning") {
46419
+ const existing = activePersistentToasts.get(message2);
46291
46420
  if (existing) {
46292
46421
  dismiss2(existing);
46293
- activePersistentToasts.delete(message);
46422
+ activePersistentToasts.delete(message2);
46294
46423
  }
46295
- const el5 = build3(message, TONES[messageType] ? messageType : "warning");
46424
+ const el5 = build3(message2, TONES[messageType] ? messageType : "warning");
46296
46425
  set(el5, "cursor", "default");
46297
46426
  const close = closeButton((e) => {
46298
46427
  e.stopPropagation();
46299
46428
  dismiss2(el5, () => {
46300
- if (activePersistentToasts.get(message) === el5) activePersistentToasts.delete(message);
46429
+ if (activePersistentToasts.get(message2) === el5) activePersistentToasts.delete(message2);
46301
46430
  });
46302
46431
  });
46303
46432
  el5.append(close);
46304
- activePersistentToasts.set(message, el5);
46433
+ activePersistentToasts.set(message2, el5);
46305
46434
  reveal(el5);
46306
46435
  }
46307
- function dismissPersistent(message) {
46308
- const el5 = activePersistentToasts.get(message);
46436
+ function dismissPersistent(message2) {
46437
+ const el5 = activePersistentToasts.get(message2);
46309
46438
  if (!el5) return;
46310
- activePersistentToasts.delete(message);
46439
+ activePersistentToasts.delete(message2);
46311
46440
  dismiss2(el5);
46312
46441
  }
46313
46442
  var TONES, CLOSE_ICON, HIDDEN2, activePersistentToasts, toast_default;
@@ -47646,6 +47775,9 @@ ${t}` : `"use strict"; return (${t});`;
47646
47775
  // Who is editing and who wrote what. Not editOnly: a reader still sees names.
47647
47776
  people: { path: "plugins/people.js", editOnly: false, default: false },
47648
47777
  wire: { path: "plugins/wire.js", editOnly: false, default: false },
47778
+ // A visitor's contact form to the document's owner. Not editOnly: visitors are
47779
+ // who send messages.
47780
+ message: { path: "plugins/message.js", editOnly: false, default: false },
47649
47781
  // Edit mode only: the AI comment box is an editing gesture. Opt in with
47650
47782
  // `plugins=ai-edit`; it stays dormant on any host that does not list a ready
47651
47783
  // `ai-edit` helper.
@@ -47694,18 +47826,19 @@ ${t}` : `"use strict"; return (${t});`;
47694
47826
  "plugins/upload.js": () => Promise.resolve().then(() => (init_upload(), upload_exports)),
47695
47827
  "plugins/people.js": () => Promise.resolve().then(() => (init_people(), people_exports)),
47696
47828
  "plugins/wire.js": () => Promise.resolve().then(() => (init_wire(), wire_exports)),
47829
+ "plugins/message.js": () => Promise.resolve().then(() => (init_message(), message_exports)),
47697
47830
  "plugins/ai-edit.js": () => Promise.resolve().then(() => (init_ai_edit(), ai_edit_exports)),
47698
47831
  "plugins/demo.js": () => Promise.resolve().then(() => (init_demo(), demo_exports)),
47699
47832
  "plugins/visitor-drafts.js": () => Promise.resolve().then(() => (init_visitor_drafts(), visitor_drafts_exports)),
47700
47833
  "plugins/source.js": () => Promise.resolve().then(() => (init_source2(), source_exports))
47701
47834
  };
47702
- var PLUGIN_ORDER = ["visitor-drafts", "richclay", "indicator", "sortable", "undo", "quickcrop", "upload", "people", "cms", "sync", "live", "wire", "ai-edit", "demo", "source"];
47835
+ var PLUGIN_ORDER = ["visitor-drafts", "richclay", "indicator", "sortable", "undo", "quickcrop", "upload", "people", "cms", "sync", "live", "message", "wire", "ai-edit", "demo", "source"];
47703
47836
  var IMPLIES = { cms: ["quickcrop", "upload"], "ai-edit": ["wire"] };
47704
47837
  function parseCsv(params, key2, enabled, apply2) {
47705
47838
  const raw = params.get(key2);
47706
47839
  if (!raw) return;
47707
- for (const token of raw.split(",")) {
47708
- const name = token.trim();
47840
+ for (const token2 of raw.split(",")) {
47841
+ const name = token2.trim();
47709
47842
  if (!name) continue;
47710
47843
  if (!PLUGIN_PATHS[name]) {
47711
47844
  console.warn(`clayjs: unknown plugin "${name}"`);
@@ -47848,6 +47981,8 @@ ${t}` : `"use strict"; return (${t});`;
47848
47981
  clay5.people = mod.people;
47849
47982
  clay5.author = mod.author;
47850
47983
  Object.defineProperty(clay5, "me", { get: mod.currentMe, configurable: true, enumerable: true });
47984
+ } else if (path === "plugins/message.js") {
47985
+ clay5.message = mod.message;
47851
47986
  } else if (path === "plugins/wire.js") {
47852
47987
  clay5.wire = mod.wire || mod.default;
47853
47988
  } else if (path === "plugins/ai-edit.js") {