@distinctagency/cms-client 1.25.0 → 1.26.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.
@@ -38,6 +38,15 @@ function enforceMaxLength(value, max) {
38
38
  if (max == null) return value;
39
39
  return value.length > max ? value.slice(0, Math.max(0, max)) : value;
40
40
  }
41
+ function resolveFieldAddress(el, root) {
42
+ const field = el.getAttribute("data-cms-field") ?? "";
43
+ const item = el.closest("[data-cms-item]");
44
+ if (!item) return { field };
45
+ const list = item.getAttribute("data-cms-item") ?? "";
46
+ const siblings = Array.from(root.querySelectorAll(`[data-cms-item="${CSS.escape(list)}"]`));
47
+ const index = siblings.indexOf(item);
48
+ return { field, list, index };
49
+ }
41
50
 
42
51
  // src/visual-editing/bridge.ts
43
52
  function createVisualBridge(options = {}) {
@@ -47,6 +56,8 @@ function createVisualBridge(options = {}) {
47
56
  let parentOrigin = null;
48
57
  let schema = {};
49
58
  let activeEl = null;
59
+ let activeAddr = null;
60
+ let hoverEnabled = false;
50
61
  const counter = createCounterEl();
51
62
  function post(msg) {
52
63
  if (parentOrigin) window.parent.postMessage(msg, parentOrigin);
@@ -54,59 +65,71 @@ function createVisualBridge(options = {}) {
54
65
  function elFor(name) {
55
66
  return document.querySelector(`[data-cms-field="${CSS.escape(name)}"]`);
56
67
  }
57
- function applyValue(name, value) {
58
- const el = elFor(name);
68
+ function elForAddress(field, list, index) {
69
+ if (list == null || index == null) return elFor(field);
70
+ const items = document.querySelectorAll(`[data-cms-item="${CSS.escape(list)}"]`);
71
+ const item = items[index];
72
+ return item ? item.querySelector(`[data-cms-field="${CSS.escape(field)}"]`) : null;
73
+ }
74
+ function applyValueEl(el, value) {
59
75
  if (!el) return;
60
76
  if (el.getAttribute("data-cms-type") === "image") {
61
77
  if (el instanceof HTMLImageElement) el.src = value;
62
- } else {
63
- el.textContent = value;
64
- }
78
+ } else el.textContent = value;
79
+ }
80
+ function applyValue(name, value) {
81
+ applyValueEl(elFor(name), value);
82
+ }
83
+ function schemaKeyOf(a) {
84
+ return a.list ? `${a.list}.${a.field}` : a.field;
65
85
  }
66
86
  function onClick(e) {
67
87
  const el = e.target?.closest("[data-cms-field]");
68
88
  if (!el || !parentOrigin) return;
69
- const name = el.getAttribute("data-cms-field");
70
89
  e.preventDefault();
90
+ const addr = resolveFieldAddress(el, document);
71
91
  if (el.getAttribute("data-cms-type") === "image") {
72
- post({ source: CMS_VISUAL_SOURCE, type: "pick-image", name });
92
+ post({ source: CMS_VISUAL_SOURCE, type: "pick-image", name: addr.field, list: addr.list, index: addr.index });
73
93
  return;
74
94
  }
75
95
  activeEl = el;
96
+ activeAddr = addr;
76
97
  el.setAttribute("contenteditable", "true");
77
98
  el.focus();
78
- positionCounter(el, name);
99
+ positionCounter(el, schemaKeyOf(addr));
79
100
  }
80
101
  function onInput(e) {
81
102
  const el = e.target;
82
- const name = el.getAttribute?.("data-cms-field");
83
- if (!name || el !== activeEl) return;
84
- const max = schema[name]?.max_length;
103
+ if (!el.getAttribute?.("data-cms-field") || el !== activeEl) return;
104
+ const addr = activeAddr ?? { field: el.getAttribute("data-cms-field") ?? "" };
105
+ const key = schemaKeyOf(addr);
106
+ const max = schema[key]?.max_length;
85
107
  const clamped = enforceMaxLength(el.textContent ?? "", max);
86
108
  if (clamped !== el.textContent) {
87
109
  el.textContent = clamped;
88
110
  placeCaretAtEnd(el);
89
111
  }
90
- updateCounter(name, clamped.length);
91
- post({ source: CMS_VISUAL_SOURCE, type: "edit", name, value: clamped, length: clamped.length });
112
+ updateCounter(key, clamped.length);
113
+ post({ source: CMS_VISUAL_SOURCE, type: "edit", name: addr.field, value: clamped, length: clamped.length, list: addr.list, index: addr.index });
92
114
  }
93
115
  function onBlur(e) {
94
116
  const el = e.target;
95
117
  if (el === activeEl) {
96
118
  el.removeAttribute("contenteditable");
97
119
  activeEl = null;
120
+ activeAddr = null;
98
121
  counter.style.display = "none";
99
122
  }
100
123
  }
101
- function positionCounter(el, name) {
124
+ function positionCounter(el, schemaKey) {
102
125
  const r = el.getBoundingClientRect();
103
126
  counter.style.top = `${window.scrollY + r.bottom + 4}px`;
104
127
  counter.style.left = `${window.scrollX + r.left}px`;
105
128
  counter.style.display = "block";
106
- updateCounter(name, (el.textContent ?? "").length);
129
+ updateCounter(schemaKey, (el.textContent ?? "").length);
107
130
  }
108
- function updateCounter(name, len) {
109
- const f = schema[name];
131
+ function updateCounter(schemaKey, len) {
132
+ const f = schema[schemaKey];
110
133
  const rec = f?.recommended_length;
111
134
  const max = f?.max_length;
112
135
  counter.textContent = max ? `${len} / ${rec ?? max}${rec && max ? ` \xB7 max ${max}` : ""}` : `${len}`;
@@ -124,10 +147,12 @@ function createVisualBridge(options = {}) {
124
147
  for (const [name, value] of Object.entries(msg.values)) applyValue(name, value);
125
148
  enableHover();
126
149
  } else if (msg.type === "set") {
127
- applyValue(msg.name, msg.value);
150
+ applyValueEl(elForAddress(msg.name, msg.list, msg.index), msg.value);
128
151
  }
129
152
  }
130
153
  function enableHover() {
154
+ if (hoverEnabled) return;
155
+ hoverEnabled = true;
131
156
  document.body.setAttribute("data-cms-editing", "true");
132
157
  injectHoverStyles();
133
158
  document.addEventListener("click", onClick, true);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/visual-editing/react.tsx","../src/visual-editing/protocol.ts","../src/visual-editing/dom.ts","../src/visual-editing/bridge.ts"],"sourcesContent":["// packages/client/src/visual-editing/react.tsx\n\"use client\"\nimport { useEffect } from \"react\"\nimport { createVisualBridge } from \"./bridge\"\n\nexport interface CmsVisualBridgeProps {\n /** Override the CMS origins the bridge trusts (defaults to Distinct CMS origins + localhost). */\n trustedOrigins?: string[]\n /** Query param that activates preview mode. Defaults to \"cms_preview\". */\n param?: string\n}\n\n/**\n * Mount once in your site (e.g. root layout). Renders nothing and stays inert\n * for normal visitors — it only activates when the page is loaded with the\n * preview param inside a trusted CMS frame.\n */\nexport function CmsVisualBridge({ trustedOrigins, param = \"cms_preview\" }: CmsVisualBridgeProps) {\n useEffect(() => {\n if (typeof window === \"undefined\") return\n const params = new URLSearchParams(window.location.search)\n if (!params.has(param)) return\n const cleanup = createVisualBridge({ trustedOrigins })\n return cleanup\n }, [trustedOrigins, param])\n return null\n}\n","/** Discriminator stamped on every visual-editing postMessage. */\nexport const CMS_VISUAL_SOURCE = \"cms-visual\" as const\n\n/** CMS origins the bridge will trust by default. */\nexport const DEFAULT_TRUSTED_ORIGINS: readonly string[] = [\n \"https://cms.distinctstudio.co.nz\",\n \"https://distinctcms.com\",\n]\n\nexport type VisualFieldType = \"text\" | \"image\"\n\n/** Compact wire type announced in `ready`; the schema adds length constraints. */\nexport interface VisualFieldMeta {\n name: string\n type: VisualFieldType\n}\n\nexport interface VisualFieldSchema {\n name: string\n type: VisualFieldType\n max_length?: number\n recommended_length?: number\n}\n\n// bridge -> parent\nexport interface ReadyMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"ready\"\n fields: VisualFieldMeta[]\n}\nexport interface EditMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"edit\"\n name: string\n value: string\n length: number\n}\nexport interface PickImageMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"pick-image\"\n name: string\n}\n\n// parent -> bridge\nexport interface InitMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"init\"\n values: Record<string, string>\n schema: Record<string, VisualFieldSchema>\n}\nexport interface SetMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"set\"\n name: string\n value: string\n}\n\nexport type BridgeOutbound = ReadyMessage | EditMessage | PickImageMessage\nexport type BridgeInbound = InitMessage | SetMessage\nexport type VisualMessage = BridgeOutbound | BridgeInbound\n\n/** Exact-match origin allowlist, plus any localhost port for local dev. */\nexport function isTrustedOrigin(\n origin: string,\n allowlist: readonly string[]\n): boolean {\n if (allowlist.includes(origin)) return true\n return /^https?:\\/\\/localhost(:\\d+)?$/.test(origin)\n}\n\nconst VALID_VISUAL_TYPES = new Set([\"ready\", \"edit\", \"pick-image\", \"init\", \"set\"])\n\n/** Narrow an unknown postMessage payload to a visual message, or null. */\nexport function parseVisualMessage(data: unknown): VisualMessage | null {\n if (\n typeof data === \"object\" &&\n data !== null &&\n (data as Record<string, unknown>).source === CMS_VISUAL_SOURCE &&\n typeof (data as Record<string, unknown>).type === \"string\" &&\n VALID_VISUAL_TYPES.has((data as Record<string, unknown>).type as string)\n ) {\n return data as VisualMessage\n }\n return null\n}\n","import type { VisualFieldMeta } from \"./protocol\"\n\n/** Read every [data-cms-field] element in document order. */\nexport function discoverFields(root: Document | HTMLElement): VisualFieldMeta[] {\n const nodes = root.querySelectorAll<HTMLElement>(\"[data-cms-field]\")\n const fields: VisualFieldMeta[] = []\n nodes.forEach((el) => {\n const name = el.getAttribute(\"data-cms-field\")\n if (!name) return\n const type = el.getAttribute(\"data-cms-type\") === \"image\" ? \"image\" : \"text\"\n fields.push({ name, type })\n })\n return fields\n}\n\n/** Truncate text to a hard max. Undefined max means no limit. */\nexport function enforceMaxLength(value: string, max: number | undefined): string {\n if (max == null) return value\n return value.length > max ? value.slice(0, Math.max(0, max)) : value\n}\n","// packages/client/src/visual-editing/bridge.ts\nimport {\n CMS_VISUAL_SOURCE,\n DEFAULT_TRUSTED_ORIGINS,\n isTrustedOrigin,\n parseVisualMessage,\n type BridgeOutbound,\n type VisualFieldSchema,\n} from \"./protocol\"\nimport { discoverFields, enforceMaxLength } from \"./dom\"\n\nexport interface VisualBridgeOptions {\n trustedOrigins?: string[]\n}\n\n/**\n * Mounts the in-page editor bridge. Dormant until a trusted CMS parent sends\n * `init`. Returns a cleanup function. No-op when not running inside a frame.\n */\nexport function createVisualBridge(options: VisualBridgeOptions = {}): () => void {\n if (typeof window === \"undefined\" || window.parent === window) return () => {}\n const allow = options.trustedOrigins ?? DEFAULT_TRUSTED_ORIGINS\n\n let parentOrigin: string | null = null\n let schema: Record<string, VisualFieldSchema> = {}\n let activeEl: HTMLElement | null = null\n const counter = createCounterEl()\n\n function post(msg: BridgeOutbound) {\n if (parentOrigin) window.parent.postMessage(msg, parentOrigin)\n }\n\n function elFor(name: string): HTMLElement | null {\n return document.querySelector<HTMLElement>(`[data-cms-field=\"${CSS.escape(name)}\"]`)\n }\n\n function applyValue(name: string, value: string) {\n const el = elFor(name)\n if (!el) return\n if (el.getAttribute(\"data-cms-type\") === \"image\") {\n if (el instanceof HTMLImageElement) el.src = value\n } else {\n el.textContent = value\n }\n }\n\n function onClick(e: MouseEvent) {\n const el = (e.target as HTMLElement)?.closest<HTMLElement>(\"[data-cms-field]\")\n if (!el || !parentOrigin) return\n const name = el.getAttribute(\"data-cms-field\")!\n e.preventDefault()\n if (el.getAttribute(\"data-cms-type\") === \"image\") {\n post({ source: CMS_VISUAL_SOURCE, type: \"pick-image\", name })\n return\n }\n // text: edit in place\n activeEl = el\n el.setAttribute(\"contenteditable\", \"true\")\n el.focus()\n positionCounter(el, name)\n }\n\n function onInput(e: Event) {\n const el = e.target as HTMLElement\n const name = el.getAttribute?.(\"data-cms-field\")\n if (!name || el !== activeEl) return\n const max = schema[name]?.max_length\n const clamped = enforceMaxLength(el.textContent ?? \"\", max)\n if (clamped !== el.textContent) {\n el.textContent = clamped\n placeCaretAtEnd(el)\n }\n updateCounter(name, clamped.length)\n post({ source: CMS_VISUAL_SOURCE, type: \"edit\", name, value: clamped, length: clamped.length })\n }\n\n function onBlur(e: FocusEvent) {\n const el = e.target as HTMLElement\n if (el === activeEl) {\n el.removeAttribute(\"contenteditable\")\n activeEl = null\n counter.style.display = \"none\"\n }\n }\n\n function positionCounter(el: HTMLElement, name: string) {\n const r = el.getBoundingClientRect()\n counter.style.top = `${window.scrollY + r.bottom + 4}px`\n counter.style.left = `${window.scrollX + r.left}px`\n counter.style.display = \"block\"\n updateCounter(name, (el.textContent ?? \"\").length)\n }\n\n function updateCounter(name: string, len: number) {\n const f = schema[name]\n const rec = f?.recommended_length\n const max = f?.max_length\n counter.textContent = max ? `${len} / ${rec ?? max}${rec && max ? ` · max ${max}` : \"\"}` : `${len}`\n const over = max != null && len >= max\n const warn = !over && rec != null && len > rec\n counter.style.background = over ? \"#ef4444\" : warn ? \"#f59e0b\" : \"#334155\"\n }\n\n function onMessage(e: MessageEvent) {\n if (!isTrustedOrigin(e.origin, allow)) return\n const msg = parseVisualMessage(e.data)\n if (!msg) return\n if (msg.type === \"init\") {\n parentOrigin = e.origin\n schema = msg.schema\n for (const [name, value] of Object.entries(msg.values)) applyValue(name, value)\n enableHover()\n } else if (msg.type === \"set\") {\n applyValue(msg.name, msg.value)\n }\n }\n\n function enableHover() {\n document.body.setAttribute(\"data-cms-editing\", \"true\")\n injectHoverStyles()\n document.addEventListener(\"click\", onClick, true)\n document.addEventListener(\"input\", onInput, true)\n document.addEventListener(\"blur\", onBlur, true)\n }\n\n window.addEventListener(\"message\", onMessage)\n // Announce readiness to whatever parent embedded us.\n window.parent.postMessage(\n { source: CMS_VISUAL_SOURCE, type: \"ready\", fields: discoverFields(document) },\n \"*\" // ready carries no data; parent validates origin on its side\n )\n\n return () => {\n window.removeEventListener(\"message\", onMessage)\n document.removeEventListener(\"click\", onClick, true)\n document.removeEventListener(\"input\", onInput, true)\n document.removeEventListener(\"blur\", onBlur, true)\n document.body.removeAttribute(\"data-cms-editing\")\n counter.remove()\n }\n}\n\nfunction createCounterEl(): HTMLElement {\n const el = document.createElement(\"div\")\n el.setAttribute(\"data-cms-counter\", \"\")\n Object.assign(el.style, {\n position: \"absolute\", display: \"none\", zIndex: \"2147483647\",\n padding: \"2px 6px\", borderRadius: \"4px\", color: \"#fff\",\n font: \"12px/1.4 system-ui, sans-serif\", pointerEvents: \"none\",\n } as CSSStyleDeclaration)\n document.body.appendChild(el)\n return el\n}\n\nfunction injectHoverStyles() {\n if (document.getElementById(\"cms-visual-styles\")) return\n const s = document.createElement(\"style\")\n s.id = \"cms-visual-styles\"\n s.textContent = `\n [data-cms-editing] [data-cms-field]{outline:1px dashed rgba(99,102,241,.6);outline-offset:2px;cursor:text}\n [data-cms-editing] [data-cms-field][data-cms-type=\"image\"]{cursor:pointer}\n [data-cms-editing] [data-cms-field]:hover{outline:2px solid #6366f1}\n `\n document.head.appendChild(s)\n}\n\nfunction placeCaretAtEnd(el: HTMLElement) {\n const range = document.createRange()\n range.selectNodeContents(el)\n range.collapse(false)\n const sel = window.getSelection()\n sel?.removeAllRanges()\n sel?.addRange(range)\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/visual-editing/react.tsx","../src/visual-editing/protocol.ts","../src/visual-editing/dom.ts","../src/visual-editing/bridge.ts"],"sourcesContent":["// packages/client/src/visual-editing/react.tsx\n\"use client\"\nimport { useEffect } from \"react\"\nimport { createVisualBridge } from \"./bridge\"\n\nexport interface CmsVisualBridgeProps {\n /** Override the CMS origins the bridge trusts (defaults to Distinct CMS origins + localhost). */\n trustedOrigins?: string[]\n /** Query param that activates preview mode. Defaults to \"cms_preview\". */\n param?: string\n}\n\n/**\n * Mount once in your site (e.g. root layout). Renders nothing and stays inert\n * for normal visitors — it only activates when the page is loaded with the\n * preview param inside a trusted CMS frame.\n */\nexport function CmsVisualBridge({ trustedOrigins, param = \"cms_preview\" }: CmsVisualBridgeProps) {\n useEffect(() => {\n if (typeof window === \"undefined\") return\n const params = new URLSearchParams(window.location.search)\n if (!params.has(param)) return\n const cleanup = createVisualBridge({ trustedOrigins })\n return cleanup\n }, [trustedOrigins, param])\n return null\n}\n","/** Discriminator stamped on every visual-editing postMessage. */\nexport const CMS_VISUAL_SOURCE = \"cms-visual\" as const\n\n/** CMS origins the bridge will trust by default. */\nexport const DEFAULT_TRUSTED_ORIGINS: readonly string[] = [\n \"https://cms.distinctstudio.co.nz\",\n \"https://distinctcms.com\",\n]\n\nexport type VisualFieldType = \"text\" | \"image\"\n\n/** Compact wire type announced in `ready`; the schema adds length constraints. */\nexport interface VisualFieldMeta {\n name: string\n type: VisualFieldType\n}\n\nexport interface VisualFieldSchema {\n name: string\n type: VisualFieldType\n max_length?: number\n recommended_length?: number\n}\n\n// bridge -> parent\nexport interface ReadyMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"ready\"\n fields: VisualFieldMeta[]\n}\nexport interface EditMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"edit\"\n name: string\n value: string\n length: number\n /** When the field is inside a repeating group item, the group field name. */\n list?: string\n /** Item index within the group (document order). */\n index?: number\n}\nexport interface PickImageMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"pick-image\"\n name: string\n /** When the field is inside a repeating group item, the group field name. */\n list?: string\n /** Item index within the group (document order). */\n index?: number\n}\n\n// parent -> bridge\nexport interface InitMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"init\"\n values: Record<string, string>\n schema: Record<string, VisualFieldSchema>\n}\nexport interface SetMessage {\n source: typeof CMS_VISUAL_SOURCE\n type: \"set\"\n name: string\n value: string\n /** When the field is inside a repeating group item, the group field name. */\n list?: string\n /** Item index within the group (document order). */\n index?: number\n}\n\nexport type BridgeOutbound = ReadyMessage | EditMessage | PickImageMessage\nexport type BridgeInbound = InitMessage | SetMessage\nexport type VisualMessage = BridgeOutbound | BridgeInbound\n\n/** Exact-match origin allowlist, plus any localhost port for local dev. */\nexport function isTrustedOrigin(\n origin: string,\n allowlist: readonly string[]\n): boolean {\n if (allowlist.includes(origin)) return true\n return /^https?:\\/\\/localhost(:\\d+)?$/.test(origin)\n}\n\nconst VALID_VISUAL_TYPES = new Set([\"ready\", \"edit\", \"pick-image\", \"init\", \"set\"])\n\n/** Narrow an unknown postMessage payload to a visual message, or null. */\nexport function parseVisualMessage(data: unknown): VisualMessage | null {\n if (\n typeof data === \"object\" &&\n data !== null &&\n (data as Record<string, unknown>).source === CMS_VISUAL_SOURCE &&\n typeof (data as Record<string, unknown>).type === \"string\" &&\n VALID_VISUAL_TYPES.has((data as Record<string, unknown>).type as string)\n ) {\n return data as VisualMessage\n }\n return null\n}\n","import type { VisualFieldMeta } from \"./protocol\"\n\n/** Read every [data-cms-field] element in document order. */\nexport function discoverFields(root: Document | HTMLElement): VisualFieldMeta[] {\n const nodes = root.querySelectorAll<HTMLElement>(\"[data-cms-field]\")\n const fields: VisualFieldMeta[] = []\n nodes.forEach((el) => {\n const name = el.getAttribute(\"data-cms-field\")\n if (!name) return\n const type = el.getAttribute(\"data-cms-type\") === \"image\" ? \"image\" : \"text\"\n fields.push({ name, type })\n })\n return fields\n}\n\n/** Truncate text to a hard max. Undefined max means no limit. */\nexport function enforceMaxLength(value: string, max: number | undefined): string {\n if (max == null) return value\n return value.length > max ? value.slice(0, Math.max(0, max)) : value\n}\n\nexport interface FieldAddress {\n field: string\n list?: string\n index?: number\n}\n\n/** Resolve a [data-cms-field] element to a flat field or a repeating-item address. */\nexport function resolveFieldAddress(el: HTMLElement, root: Document | HTMLElement): FieldAddress {\n const field = el.getAttribute(\"data-cms-field\") ?? \"\"\n const item = el.closest<HTMLElement>(\"[data-cms-item]\")\n if (!item) return { field }\n const list = item.getAttribute(\"data-cms-item\") ?? \"\"\n const siblings = Array.from(root.querySelectorAll<HTMLElement>(`[data-cms-item=\"${CSS.escape(list)}\"]`))\n const index = siblings.indexOf(item)\n return { field, list, index }\n}\n","// packages/client/src/visual-editing/bridge.ts\nimport {\n CMS_VISUAL_SOURCE,\n DEFAULT_TRUSTED_ORIGINS,\n isTrustedOrigin,\n parseVisualMessage,\n type BridgeOutbound,\n type VisualFieldSchema,\n} from \"./protocol\"\nimport { discoverFields, enforceMaxLength, resolveFieldAddress, type FieldAddress } from \"./dom\"\n\nexport interface VisualBridgeOptions {\n trustedOrigins?: string[]\n}\n\n/**\n * Mounts the in-page editor bridge. Dormant until a trusted CMS parent sends\n * `init`. Returns a cleanup function. No-op when not running inside a frame.\n */\nexport function createVisualBridge(options: VisualBridgeOptions = {}): () => void {\n if (typeof window === \"undefined\" || window.parent === window) return () => {}\n const allow = options.trustedOrigins ?? DEFAULT_TRUSTED_ORIGINS\n\n let parentOrigin: string | null = null\n let schema: Record<string, VisualFieldSchema> = {}\n let activeEl: HTMLElement | null = null\n let activeAddr: FieldAddress | null = null\n let hoverEnabled = false\n const counter = createCounterEl()\n\n function post(msg: BridgeOutbound) {\n if (parentOrigin) window.parent.postMessage(msg, parentOrigin)\n }\n\n function elFor(name: string): HTMLElement | null {\n return document.querySelector<HTMLElement>(`[data-cms-field=\"${CSS.escape(name)}\"]`)\n }\n\n function elForAddress(field: string, list?: string, index?: number): HTMLElement | null {\n if (list == null || index == null) return elFor(field)\n const items = document.querySelectorAll<HTMLElement>(`[data-cms-item=\"${CSS.escape(list)}\"]`)\n const item = items[index]\n return item ? item.querySelector<HTMLElement>(`[data-cms-field=\"${CSS.escape(field)}\"]`) : null\n }\n\n function applyValueEl(el: HTMLElement | null, value: string) {\n if (!el) return\n if (el.getAttribute(\"data-cms-type\") === \"image\") { if (el instanceof HTMLImageElement) el.src = value }\n else el.textContent = value\n }\n\n function applyValue(name: string, value: string) { applyValueEl(elFor(name), value) }\n\n function schemaKeyOf(a: FieldAddress): string { return a.list ? `${a.list}.${a.field}` : a.field }\n\n function onClick(e: MouseEvent) {\n const el = (e.target as HTMLElement)?.closest<HTMLElement>(\"[data-cms-field]\")\n if (!el || !parentOrigin) return\n e.preventDefault()\n const addr = resolveFieldAddress(el, document)\n if (el.getAttribute(\"data-cms-type\") === \"image\") {\n post({ source: CMS_VISUAL_SOURCE, type: \"pick-image\", name: addr.field, list: addr.list, index: addr.index })\n return\n }\n // text: edit in place\n activeEl = el\n activeAddr = addr\n el.setAttribute(\"contenteditable\", \"true\")\n el.focus()\n positionCounter(el, schemaKeyOf(addr))\n }\n\n function onInput(e: Event) {\n const el = e.target as HTMLElement\n if (!el.getAttribute?.(\"data-cms-field\") || el !== activeEl) return\n const addr = activeAddr ?? { field: el.getAttribute(\"data-cms-field\") ?? \"\" }\n const key = schemaKeyOf(addr)\n const max = schema[key]?.max_length\n const clamped = enforceMaxLength(el.textContent ?? \"\", max)\n if (clamped !== el.textContent) { el.textContent = clamped; placeCaretAtEnd(el) }\n updateCounter(key, clamped.length)\n post({ source: CMS_VISUAL_SOURCE, type: \"edit\", name: addr.field, value: clamped, length: clamped.length, list: addr.list, index: addr.index })\n }\n\n function onBlur(e: FocusEvent) {\n const el = e.target as HTMLElement\n if (el === activeEl) {\n el.removeAttribute(\"contenteditable\")\n activeEl = null\n activeAddr = null\n counter.style.display = \"none\"\n }\n }\n\n function positionCounter(el: HTMLElement, schemaKey: string) {\n const r = el.getBoundingClientRect()\n counter.style.top = `${window.scrollY + r.bottom + 4}px`\n counter.style.left = `${window.scrollX + r.left}px`\n counter.style.display = \"block\"\n updateCounter(schemaKey, (el.textContent ?? \"\").length)\n }\n\n function updateCounter(schemaKey: string, len: number) {\n const f = schema[schemaKey]\n const rec = f?.recommended_length\n const max = f?.max_length\n counter.textContent = max ? `${len} / ${rec ?? max}${rec && max ? ` · max ${max}` : \"\"}` : `${len}`\n const over = max != null && len >= max\n const warn = !over && rec != null && len > rec\n counter.style.background = over ? \"#ef4444\" : warn ? \"#f59e0b\" : \"#334155\"\n }\n\n function onMessage(e: MessageEvent) {\n if (!isTrustedOrigin(e.origin, allow)) return\n const msg = parseVisualMessage(e.data)\n if (!msg) return\n if (msg.type === \"init\") {\n parentOrigin = e.origin\n schema = msg.schema\n for (const [name, value] of Object.entries(msg.values)) applyValue(name, value)\n enableHover()\n } else if (msg.type === \"set\") {\n applyValueEl(elForAddress(msg.name, msg.list, msg.index), msg.value)\n }\n }\n\n function enableHover() {\n if (hoverEnabled) return\n hoverEnabled = true\n document.body.setAttribute(\"data-cms-editing\", \"true\")\n injectHoverStyles()\n document.addEventListener(\"click\", onClick, true)\n document.addEventListener(\"input\", onInput, true)\n document.addEventListener(\"blur\", onBlur, true)\n }\n\n window.addEventListener(\"message\", onMessage)\n // Announce readiness to whatever parent embedded us.\n window.parent.postMessage(\n { source: CMS_VISUAL_SOURCE, type: \"ready\", fields: discoverFields(document) },\n \"*\" // ready carries no data; parent validates origin on its side\n )\n\n return () => {\n window.removeEventListener(\"message\", onMessage)\n document.removeEventListener(\"click\", onClick, true)\n document.removeEventListener(\"input\", onInput, true)\n document.removeEventListener(\"blur\", onBlur, true)\n document.body.removeAttribute(\"data-cms-editing\")\n counter.remove()\n }\n}\n\nfunction createCounterEl(): HTMLElement {\n const el = document.createElement(\"div\")\n el.setAttribute(\"data-cms-counter\", \"\")\n Object.assign(el.style, {\n position: \"absolute\", display: \"none\", zIndex: \"2147483647\",\n padding: \"2px 6px\", borderRadius: \"4px\", color: \"#fff\",\n font: \"12px/1.4 system-ui, sans-serif\", pointerEvents: \"none\",\n } as CSSStyleDeclaration)\n document.body.appendChild(el)\n return el\n}\n\nfunction injectHoverStyles() {\n if (document.getElementById(\"cms-visual-styles\")) return\n const s = document.createElement(\"style\")\n s.id = \"cms-visual-styles\"\n s.textContent = `\n [data-cms-editing] [data-cms-field]{outline:1px dashed rgba(99,102,241,.6);outline-offset:2px;cursor:text}\n [data-cms-editing] [data-cms-field][data-cms-type=\"image\"]{cursor:pointer}\n [data-cms-editing] [data-cms-field]:hover{outline:2px solid #6366f1}\n `\n document.head.appendChild(s)\n}\n\nfunction placeCaretAtEnd(el: HTMLElement) {\n const range = document.createRange()\n range.selectNodeContents(el)\n range.collapse(false)\n const sel = window.getSelection()\n sel?.removeAllRanges()\n sel?.addRange(range)\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@distinctagency/cms-client",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
4
4
  "description": "Client library for Distinct CMS — query content, products, and manage orders",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",