@duffcloudservices/cms 0.12.0 → 0.13.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 (39) hide show
  1. package/README.md +244 -8
  2. package/dist/chunk-A5F4C72F.js +500 -0
  3. package/dist/chunk-A5F4C72F.js.map +1 -0
  4. package/dist/{chunk-F3EIWEZD.js → chunk-HVSF23P7.js} +971 -73
  5. package/dist/chunk-HVSF23P7.js.map +1 -0
  6. package/dist/editor/editorBridge.d.ts +13 -1
  7. package/dist/editor/editorBridge.js +75 -5
  8. package/dist/editor/editorBridge.js.map +1 -1
  9. package/dist/headHonesty-OzxvLuwd.d.ts +222 -0
  10. package/dist/index.d.ts +365 -22
  11. package/dist/index.js +421 -21
  12. package/dist/index.js.map +1 -1
  13. package/dist/installSeoHead-kWQwObez.d.ts +627 -0
  14. package/dist/plugins/index.d.ts +90 -6
  15. package/dist/plugins/index.js +530 -49
  16. package/dist/plugins/index.js.map +1 -1
  17. package/dist/seo/index.d.ts +763 -4
  18. package/dist/seo/index.js +2 -2
  19. package/dist/{vitepressTransform-DfmABXmK.d.ts → vitepressTransform-JG_zlaux.d.ts} +99 -6
  20. package/package.json +17 -6
  21. package/src/components/DcsCallButton.test.ts +58 -0
  22. package/src/components/DcsCallButton.vue +19 -4
  23. package/src/components/LiteMediaEmbed.vue +3 -3
  24. package/src/components/ManagedImage.test.ts +34 -0
  25. package/src/components/ManagedImage.vue +5 -0
  26. package/src/components/PreviewRibbon.vue +4 -1
  27. package/src/composables/useConversionTracking.test.ts +492 -0
  28. package/src/composables/useConversionTracking.ts +770 -0
  29. package/src/composables/useReleaseNotes.ts +7 -1
  30. package/src/composables/useSEO.applyHead.test.ts +150 -0
  31. package/src/composables/useSEO.ts +63 -17
  32. package/src/composables/useSiteVersion.ts +4 -1
  33. package/src/composables/useSiteVisitorSession.test.ts +56 -0
  34. package/src/composables/useSiteVisitorSession.ts +39 -3
  35. package/src/composables/useTextContent.ts +9 -1
  36. package/dist/chunk-DAYLLSEE.js +0 -3
  37. package/dist/chunk-DAYLLSEE.js.map +0 -1
  38. package/dist/chunk-F3EIWEZD.js.map +0 -1
  39. package/dist/spliceHeadHtml-CsBEucGy.d.ts +0 -254
@@ -94,8 +94,20 @@ declare function recordPendingImageOverride(key: string, src: string, alt?: stri
94
94
  * @returns true when the key was handled as an image revert (skip text handling).
95
95
  */
96
96
  declare function revertImageOverrideIfImageKey(key: string, value: string): boolean;
97
+ /**
98
+ * Handle a `dcs:update-text` that targets a MANAGED IMAGE **ALT** key
99
+ * (`data-dcs-image-alt-key`). The portal stages an alt change alongside the
100
+ * src change on "Replace without AI"; on discard/undo it reverts each staged
101
+ * key via `dcs:update-text`. Alt keys are attributes, not text nodes, so
102
+ * `updateTextInPlace` would be a silent no-op — instead restore the `<img>`
103
+ * alt and refresh any pending image override (keyed by the SRC key) so a
104
+ * re-render replay does not resurrect the discarded alt.
105
+ *
106
+ * @returns true when the key was handled as an image-alt revert.
107
+ */
108
+ declare function revertImageAltOverrideIfAltKey(key: string, value: string): boolean;
97
109
  /** Clear all pending image overrides (test isolation). */
98
110
  declare function clearPendingImageOverrides(): void;
99
111
  declare function initEditorBridge(): void;
100
112
 
101
- export { type EditorReadyPayload, type SectionInfo, applyImageOverride, applyPendingImageOverrides, clearPendingImageOverrides, initEditorBridge, recordPendingImageOverride, revertImageOverrideIfImageKey };
113
+ export { type EditorReadyPayload, type SectionInfo, applyImageOverride, applyPendingImageOverrides, clearPendingImageOverrides, initEditorBridge, recordPendingImageOverride, revertImageAltOverrideIfAltKey, revertImageOverrideIfImageKey };
@@ -218,6 +218,7 @@ function applyEditorToElements() {
218
218
  htmlEl.addEventListener("dblclick", handleTextKeyDblClick);
219
219
  htmlEl.addEventListener("blur", handleTextKeyBlur);
220
220
  htmlEl.addEventListener("keydown", handleTextKeyKeydown);
221
+ htmlEl.addEventListener("paste", handleTextKeyPaste);
221
222
  htmlEl.addEventListener("mouseenter", () => {
222
223
  if (activeEditElement) return;
223
224
  const key = getTextKey(htmlEl);
@@ -388,12 +389,21 @@ function handleTextKeyDblClick(e) {
388
389
  postToParent("dcs:text-key-dblclick", { key, sectionId });
389
390
  startInlineEdit(el, key, sectionId);
390
391
  }
392
+ function supportsPlaintextOnly() {
393
+ try {
394
+ const probe = document.createElement("div");
395
+ probe.contentEditable = "plaintext-only";
396
+ return probe.getAttribute("contenteditable") === "plaintext-only";
397
+ } catch {
398
+ return false;
399
+ }
400
+ }
391
401
  function startInlineEdit(el, key, sectionId) {
392
402
  if (activeEditElement && activeEditElement !== el) {
393
403
  finishEdit(activeEditElement);
394
404
  }
395
405
  originalTextValues.set(el, el.innerText.trim());
396
- el.setAttribute("contenteditable", "true");
406
+ el.setAttribute("contenteditable", supportsPlaintextOnly() ? "plaintext-only" : "true");
397
407
  el.classList.add("dcs-editing");
398
408
  el.focus();
399
409
  activeEditElement = el;
@@ -415,8 +425,43 @@ function handleTextKeyKeydown(e) {
415
425
  }
416
426
  if (e.key === "Escape") {
417
427
  e.preventDefault();
418
- e.currentTarget.blur();
428
+ cancelInlineEdit(e.currentTarget);
429
+ }
430
+ }
431
+ function handleTextKeyPaste(e) {
432
+ const el = e.currentTarget;
433
+ if (el !== activeEditElement) return;
434
+ if (el.getAttribute("contenteditable") === "plaintext-only") return;
435
+ const text = e.clipboardData?.getData("text/plain") ?? "";
436
+ e.preventDefault();
437
+ insertPlainTextAtCaret(el, text);
438
+ }
439
+ function insertPlainTextAtCaret(el, text) {
440
+ const selection = getSelection();
441
+ if (!selection || selection.rangeCount === 0) {
442
+ el.appendChild(document.createTextNode(text));
443
+ return;
444
+ }
445
+ const range = selection.getRangeAt(0);
446
+ if (!el.contains(range.commonAncestorContainer)) return;
447
+ range.deleteContents();
448
+ if (text) {
449
+ const node = document.createTextNode(text);
450
+ range.insertNode(node);
451
+ range.setStartAfter(node);
419
452
  }
453
+ range.collapse(true);
454
+ selection.removeAllRanges();
455
+ selection.addRange(range);
456
+ }
457
+ function cancelInlineEdit(el) {
458
+ if (!el.hasAttribute("contenteditable")) return;
459
+ const original = originalTextValues.get(el);
460
+ if (original !== void 0) {
461
+ el.innerText = original;
462
+ }
463
+ el.blur();
464
+ finishEdit(el);
420
465
  }
421
466
  function finishEdit(el) {
422
467
  if (!el.hasAttribute("contenteditable")) return;
@@ -664,6 +709,9 @@ function createImageEditIcon(label) {
664
709
  function getManagedImageKey(img) {
665
710
  return img.dataset.dcsImageKey || img.closest("[data-dcs-image-key]")?.dataset.dcsImageKey || null;
666
711
  }
712
+ function getManagedImageAltKey(img) {
713
+ return img.dataset.dcsImageAltKey || img.closest("[data-dcs-image-alt-key]")?.dataset.dcsImageAltKey || null;
714
+ }
667
715
  var pendingImageOverrides = /* @__PURE__ */ new Map();
668
716
  function cssEscapeAttributeValue(value) {
669
717
  const cssGlobal = globalThis.CSS;
@@ -716,6 +764,25 @@ function revertImageOverrideIfImageKey(key, value) {
716
764
  if (value) applyImageOverride(key, value);
717
765
  return true;
718
766
  }
767
+ function revertImageAltOverrideIfAltKey(key, value) {
768
+ if (!key) return false;
769
+ const escapedKey = cssEscapeAttributeValue(key);
770
+ const hosts = document.querySelectorAll(`[data-dcs-image-alt-key="${escapedKey}"]`);
771
+ if (hosts.length === 0) return false;
772
+ hosts.forEach((host) => {
773
+ const imgs = host instanceof HTMLImageElement ? [host] : Array.from(host.querySelectorAll("img"));
774
+ imgs.forEach((img) => {
775
+ img.alt = value;
776
+ img.dataset.dcsImageAlt = value;
777
+ });
778
+ const srcKey = host.dataset.dcsImageKey || host.closest("[data-dcs-image-key]")?.dataset.dcsImageKey;
779
+ if (srcKey) {
780
+ const pending = pendingImageOverrides.get(srcKey);
781
+ if (pending) pendingImageOverrides.set(srcKey, { ...pending, alt: value });
782
+ }
783
+ });
784
+ return true;
785
+ }
719
786
  function clearPendingImageOverrides() {
720
787
  pendingImageOverrides.clear();
721
788
  }
@@ -745,6 +812,7 @@ function showImageEditIcons(images) {
745
812
  imageWidth: img.naturalWidth,
746
813
  imageHeight: img.naturalHeight,
747
814
  imageKey: getManagedImageKey(img),
815
+ imageAltKey: getManagedImageAltKey(img),
748
816
  sectionId: sectionEl?.dataset.section ?? null,
749
817
  sectionLabel: sectionEl?.dataset.sectionLabel ?? null
750
818
  });
@@ -1083,7 +1151,7 @@ function handleMessage(event) {
1083
1151
  case "dcs:update-text":
1084
1152
  if (data && typeof data === "object" && "key" in data && "value" in data) {
1085
1153
  const d = data;
1086
- if (!revertImageOverrideIfImageKey(d.key, d.value)) {
1154
+ if (!revertImageOverrideIfImageKey(d.key, d.value) && !revertImageAltOverrideIfAltKey(d.key, d.value)) {
1087
1155
  updateTextInPlace(d.key, d.value);
1088
1156
  }
1089
1157
  }
@@ -1201,13 +1269,15 @@ function initEditorBridge() {
1201
1269
  imageWidth: topImage?.naturalWidth ?? null,
1202
1270
  imageHeight: topImage?.naturalHeight ?? null,
1203
1271
  imageKey: topImage ? getManagedImageKey(topImage) : null,
1272
+ imageAltKey: topImage ? getManagedImageAltKey(topImage) : null,
1204
1273
  // All images at click point (for overlapping image scenarios like before/after sliders)
1205
1274
  images: allImages.length > 1 ? allImages.map((img) => ({
1206
1275
  imageUrl: img.currentSrc ?? img.src,
1207
1276
  imageAlt: img.alt ?? null,
1208
1277
  imageWidth: img.naturalWidth,
1209
1278
  imageHeight: img.naturalHeight,
1210
- imageKey: getManagedImageKey(img)
1279
+ imageKey: getManagedImageKey(img),
1280
+ imageAltKey: getManagedImageAltKey(img)
1211
1281
  })) : null
1212
1282
  });
1213
1283
  }, true);
@@ -1248,6 +1318,6 @@ function initEditorBridge() {
1248
1318
  observeSectionLayout();
1249
1319
  }
1250
1320
 
1251
- export { applyImageOverride, applyPendingImageOverrides, clearPendingImageOverrides, initEditorBridge, recordPendingImageOverride, revertImageOverrideIfImageKey };
1321
+ export { applyImageOverride, applyPendingImageOverrides, clearPendingImageOverrides, initEditorBridge, recordPendingImageOverride, revertImageAltOverrideIfAltKey, revertImageOverrideIfImageKey };
1252
1322
  //# sourceMappingURL=editorBridge.js.map
1253
1323
  //# sourceMappingURL=editorBridge.js.map