@hyperframes/studio 0.7.28 → 0.7.29

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 (43) hide show
  1. package/dist/assets/{index-Bz6Eqd_G.js → index-BX3GR25I.js} +1 -1
  2. package/dist/assets/{index-BGUJ2C2G.js → index-CthldRjm.js} +1 -1
  3. package/dist/assets/{index-CLlPjdPl.js → index-mz4av-V1.js} +137 -137
  4. package/dist/{chunk-AN2EWWK3.js → chunk-JND3XUJL.js} +38 -10
  5. package/dist/chunk-JND3XUJL.js.map +1 -0
  6. package/dist/{domEditingLayers-EK7R7R4G.js → domEditingLayers-UIQZJCOA.js} +4 -2
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.html +1 -1
  9. package/dist/index.js +1086 -656
  10. package/dist/index.js.map +1 -1
  11. package/package.json +7 -7
  12. package/src/components/editor/DomEditOverlay.test.ts +95 -0
  13. package/src/components/editor/DomEditOverlay.tsx +5 -3
  14. package/src/components/editor/domEditOverlayGestures.ts +3 -4
  15. package/src/components/editor/domEditing.ts +1 -0
  16. package/src/components/editor/domEditingLayers.test.ts +52 -0
  17. package/src/components/editor/domEditingLayers.ts +55 -19
  18. package/src/components/editor/domEditingTypes.ts +1 -0
  19. package/src/components/editor/persistSeam.integration.test.ts +264 -0
  20. package/src/components/editor/propertyPanelPrimitives.tsx +15 -1
  21. package/src/components/editor/useDomEditOverlayGestures.ts +1 -0
  22. package/src/hooks/domEditCommitRunner.ts +46 -0
  23. package/src/hooks/domEditPersistFailure.test.ts +123 -0
  24. package/src/hooks/domEditPersistFailure.ts +89 -0
  25. package/src/hooks/domEditTextFieldCommitOps.test.ts +111 -0
  26. package/src/hooks/domEditTextFieldCommitOps.ts +63 -0
  27. package/src/hooks/domSelectionTestHarness.ts +40 -0
  28. package/src/hooks/useDomEditAttributeCommits.ts +227 -0
  29. package/src/hooks/useDomEditCommits.test.tsx +775 -0
  30. package/src/hooks/useDomEditCommits.ts +33 -5
  31. package/src/hooks/useDomEditTextCommits.ts +243 -220
  32. package/src/hooks/useDomSelection.test.ts +134 -0
  33. package/src/hooks/useDomSelection.ts +29 -15
  34. package/src/hooks/usePreviewInteraction.test.ts +260 -0
  35. package/src/hooks/usePreviewInteraction.ts +60 -19
  36. package/src/utils/sdkCutoverEligibility.test.ts +17 -0
  37. package/src/utils/sdkCutoverEligibility.ts +8 -2
  38. package/src/utils/sourcePatcher.ts +2 -0
  39. package/src/utils/studioPreviewHelpers.test.ts +95 -1
  40. package/src/utils/studioPreviewHelpers.ts +109 -10
  41. package/src/utils/studioSaveDiagnostics.ts +5 -2
  42. package/dist/chunk-AN2EWWK3.js.map +0 -1
  43. /package/dist/{domEditingLayers-EK7R7R4G.js.map → domEditingLayers-UIQZJCOA.js.map} +0 -0
@@ -90,6 +90,8 @@ export interface PatchOperation {
90
90
  type: "inline-style" | "attribute" | "text-content" | "html-attribute";
91
91
  property: string;
92
92
  value: string | null;
93
+ childSelector?: string;
94
+ childIndex?: number;
93
95
  }
94
96
 
95
97
  // Runtime validation for hfId lives in findTagByTarget → execDataAttrPattern (CSS attr-value
@@ -1,5 +1,29 @@
1
+ // @vitest-environment happy-dom
2
+
1
3
  import { describe, expect, it, vi } from "vitest";
2
- import { coversComposition, pauseStudioPreviewPlayback } from "./studioPreviewHelpers";
4
+ import {
5
+ coversComposition,
6
+ getPreviewTargetFromPointer,
7
+ pauseStudioPreviewPlayback,
8
+ } from "./studioPreviewHelpers";
9
+
10
+ function domRect(left: number, top: number, width: number, height: number): DOMRect {
11
+ return {
12
+ x: left,
13
+ y: top,
14
+ left,
15
+ top,
16
+ width,
17
+ height,
18
+ right: left + width,
19
+ bottom: top + height,
20
+ toJSON: () => ({}),
21
+ };
22
+ }
23
+
24
+ function stubRect(el: Element, rect: DOMRect): void {
25
+ el.getBoundingClientRect = () => rect;
26
+ }
3
27
 
4
28
  describe("coversComposition (full-bleed canvas-pick exclusion)", () => {
5
29
  const viewport = { width: 1920, height: 1080 };
@@ -79,3 +103,73 @@ describe("pauseStudioPreviewPlayback", () => {
79
103
  expect(siblingPause).toHaveBeenCalledTimes(1);
80
104
  });
81
105
  });
106
+
107
+ describe("getPreviewTargetFromPointer", () => {
108
+ it("skips candidates hidden from author hit-testing by inherited pointer-events:none", () => {
109
+ const iframe = document.createElement("iframe");
110
+ document.body.append(iframe);
111
+ const doc = iframe.contentDocument;
112
+ if (!doc) throw new Error("Expected iframe document");
113
+
114
+ doc.body.innerHTML = `
115
+ <main id="scene" data-composition-id="scene">
116
+ <h1 id="headline">Launch title</h1>
117
+ <div id="overlay-parent" style="pointer-events: none;">
118
+ <div id="overlay" style="position: absolute; background: rgba(0, 0, 0, 0.1);"></div>
119
+ </div>
120
+ </main>
121
+ `;
122
+
123
+ const scene = doc.getElementById("scene");
124
+ const headline = doc.getElementById("headline");
125
+ const overlayParent = doc.getElementById("overlay-parent");
126
+ const overlay = doc.getElementById("overlay");
127
+ if (!scene || !headline || !overlayParent || !overlay) {
128
+ throw new Error("Expected preview fixture elements");
129
+ }
130
+
131
+ stubRect(iframe, domRect(0, 0, 400, 300));
132
+ stubRect(scene, domRect(0, 0, 400, 300));
133
+ stubRect(headline, domRect(40, 40, 160, 48));
134
+ stubRect(overlayParent, domRect(0, 0, 360, 260));
135
+ stubRect(overlay, domRect(0, 0, 360, 260));
136
+ doc.elementsFromPoint = () => [overlay, overlayParent, headline, scene];
137
+
138
+ expect(getPreviewTargetFromPointer(iframe, 80, 64, "index.html")).toBe(headline);
139
+
140
+ iframe.remove();
141
+ });
142
+
143
+ it("honors a CSS-class pointer-events:auto opt-in under a pointer-events:none ancestor", () => {
144
+ const iframe = document.createElement("iframe");
145
+ document.body.append(iframe);
146
+ const doc = iframe.contentDocument;
147
+ if (!doc) throw new Error("Expected iframe document");
148
+
149
+ doc.head.innerHTML = `<style>.clickable { pointer-events: auto; }</style>`;
150
+ doc.body.innerHTML = `
151
+ <main id="scene" data-composition-id="scene">
152
+ <div id="overlay-parent" style="pointer-events: none;">
153
+ <button id="clickable-child" class="clickable">Play</button>
154
+ </div>
155
+ </main>
156
+ `;
157
+
158
+ const scene = doc.getElementById("scene");
159
+ const overlayParent = doc.getElementById("overlay-parent");
160
+ const clickableChild = doc.getElementById("clickable-child");
161
+ if (!scene || !overlayParent || !clickableChild) {
162
+ throw new Error("Expected preview fixture elements");
163
+ }
164
+
165
+ stubRect(iframe, domRect(0, 0, 400, 300));
166
+ stubRect(scene, domRect(0, 0, 400, 300));
167
+ stubRect(overlayParent, domRect(0, 0, 360, 260));
168
+ stubRect(clickableChild, domRect(40, 40, 80, 24));
169
+ doc.elementsFromPoint = () => [clickableChild, overlayParent, scene];
170
+
171
+ expect(getPreviewTargetFromPointer(iframe, 60, 50, "index.html")).toBe(clickableChild);
172
+
173
+ iframe.remove();
174
+ });
175
+ });
@@ -4,6 +4,7 @@ import {
4
4
  isElementComputedVisible,
5
5
  resolveAllVisualDomEditTargets,
6
6
  } from "../components/editor/domEditingElement";
7
+ import { isHtmlElement } from "../components/editor/domEditingDom";
7
8
  import { getEventTargetElement } from "./studioHelpers";
8
9
 
9
10
  interface PreviewLocalPointer {
@@ -81,11 +82,90 @@ function removePointerEventsOverride(style: HTMLStyleElement | null): void {
81
82
  }
82
83
  }
83
84
 
85
+ const pointerEventsInheritanceFallbackByDocument = new WeakMap<Document, boolean>();
86
+
87
+ function needsPointerEventsInheritanceFallback(doc: Document, win: Window): boolean {
88
+ const cached = pointerEventsInheritanceFallbackByDocument.get(doc);
89
+ if (cached !== undefined) return cached;
90
+
91
+ const parent = doc.createElement("div");
92
+ const child = doc.createElement("div");
93
+ parent.style.pointerEvents = "none";
94
+ parent.appendChild(child);
95
+ const host = doc.body ?? doc.documentElement;
96
+ if (!host) return false;
97
+
98
+ host.appendChild(parent);
99
+ const needsFallback = win.getComputedStyle(child).pointerEvents !== "none";
100
+ parent.remove();
101
+ pointerEventsInheritanceFallbackByDocument.set(doc, needsFallback);
102
+ return needsFallback;
103
+ }
104
+
105
+ // Own declared pointer-events value, via computed style rather than inline
106
+ // style, so a CSS-class opt-in/opt-out (not just an inline style attribute)
107
+ // is honored when walking back down from a pointer-events:none ancestor.
108
+ function hasOwnPointerEventsOverride(el: HTMLElement, win: Window): boolean {
109
+ const value = win.getComputedStyle(el).pointerEvents;
110
+ return value !== "" && value !== "inherit" && value !== "unset";
111
+ }
112
+
113
+ function inheritsPointerEventsNoneFromAncestor(el: HTMLElement, win: Window): boolean {
114
+ let current = el.parentElement;
115
+ while (current) {
116
+ if (win.getComputedStyle(current).pointerEvents === "none") {
117
+ let descendant: HTMLElement | null = el;
118
+ while (descendant && descendant !== current) {
119
+ if (hasOwnPointerEventsOverride(descendant, win)) {
120
+ return win.getComputedStyle(descendant).pointerEvents === "none";
121
+ }
122
+ descendant = descendant.parentElement;
123
+ }
124
+ return true;
125
+ }
126
+ current = current.parentElement;
127
+ }
128
+ return false;
129
+ }
130
+
131
+ function hasAuthorPointerEventsNone(el: HTMLElement): boolean {
132
+ const win = el.ownerDocument.defaultView;
133
+ if (!win) return false;
134
+ if (win.getComputedStyle(el).pointerEvents === "none") return true;
135
+ if (!needsPointerEventsInheritanceFallback(el.ownerDocument, win)) return false;
136
+ return inheritsPointerEventsNoneFromAncestor(el, win);
137
+ }
138
+
139
+ function collectPointerEventsNoneTargets(
140
+ elements: Iterable<Element | null | undefined>,
141
+ ): WeakSet<HTMLElement> {
142
+ const disabled = new WeakSet<HTMLElement>();
143
+ for (const entry of elements) {
144
+ if (isHtmlElement(entry) && hasAuthorPointerEventsNone(entry)) {
145
+ disabled.add(entry);
146
+ }
147
+ }
148
+ return disabled;
149
+ }
150
+
151
+ // Shared tail of both pointer resolvers: hit-test candidates minus elements the
152
+ // author hid from hit-testing via pointer-events:none.
153
+ function filterAuthorInteractiveTargets(
154
+ elements: Element[],
155
+ activeCompositionPath: string | null,
156
+ ): HTMLElement[] {
157
+ const pointerEventsNoneTargets = collectPointerEventsNoneTargets(elements);
158
+ return resolveAllVisualDomEditTargets(elements, { activeCompositionPath }).filter(
159
+ (el) => !pointerEventsNoneTargets.has(el),
160
+ );
161
+ }
162
+
84
163
  // Animated group members can move outside their wrapper's static layout box, so
85
164
  // the empty space inside a group's *visual* bounds (the member-union the overlay
86
165
  // draws) doesn't hit-test to the group via elementsFromPoint. Recover it: if the
87
166
  // point falls within a group's live member-union rect, return that wrapper.
88
167
  // Innermost (smallest-area) group wins for nested groups.
168
+ // fallow-ignore-next-line complexity
89
169
  function findGroupAtPoint(doc: Document, x: number, y: number): HTMLElement | null {
90
170
  let best: HTMLElement | null = null;
91
171
  let bestArea = Infinity;
@@ -132,26 +212,39 @@ export function getPreviewTargetFromPointer(
132
212
  const localPointer = resolvePreviewLocalPointer(iframe, doc, win, clientX, clientY);
133
213
  if (!localPointer) return null;
134
214
 
135
- const overrideStyle = forcePointerEventsAuto(doc);
215
+ let overrideStyle = forcePointerEventsAuto(doc);
136
216
  try {
137
217
  if (typeof doc.elementsFromPoint === "function") {
138
- const candidates = resolveAllVisualDomEditTargets(
139
- doc.elementsFromPoint(localPointer.x, localPointer.y),
140
- { activeCompositionPath },
141
- );
218
+ const elements = doc.elementsFromPoint(localPointer.x, localPointer.y);
219
+ removePointerEventsOverride(overrideStyle);
220
+ overrideStyle = null;
221
+ const candidates = filterAuthorInteractiveTargets(elements, activeCompositionPath);
142
222
  const visualTarget =
143
223
  candidates.find((el) => !isFullBleedTarget(el, localPointer.viewport)) ?? null;
144
224
  if (visualTarget) return visualTarget;
145
225
  }
146
226
 
227
+ // Belt-and-suspenders: elementsFromPoint is universally supported in the
228
+ // browsers this ships in, so the override is already removed by this
229
+ // point in practice — but guard the environment without it too, so
230
+ // hasAuthorPointerEventsNone below never reads a forced-auto value.
231
+ removePointerEventsOverride(overrideStyle);
232
+ overrideStyle = null;
233
+
147
234
  // No element hit (e.g. empty space inside an animated group's overlay) — fall
148
235
  // back to the group whose member-union contains the point, so the whole group
149
236
  // area is hoverable/selectable, not just where a member currently sits.
150
237
  const groupHit = findGroupAtPoint(doc, localPointer.x, localPointer.y);
151
- if (groupHit && getDomLayerPatchTarget(groupHit, activeCompositionPath)) return groupHit;
238
+ if (
239
+ groupHit &&
240
+ !hasAuthorPointerEventsNone(groupHit) &&
241
+ getDomLayerPatchTarget(groupHit, activeCompositionPath)
242
+ )
243
+ return groupHit;
152
244
 
153
245
  const fallback = getEventTargetElement(doc.elementFromPoint(localPointer.x, localPointer.y));
154
246
  if (!fallback || !getDomLayerPatchTarget(fallback, activeCompositionPath)) return null;
247
+ if (hasAuthorPointerEventsNone(fallback)) return null;
155
248
  if (!isElementComputedVisible(fallback)) return null;
156
249
  if (isFullBleedTarget(fallback, localPointer.viewport)) return null;
157
250
  return fallback;
@@ -180,15 +273,21 @@ export function getAllPreviewTargetsFromPointer(
180
273
  const localPointer = resolvePreviewLocalPointer(iframe, doc, win, clientX, clientY);
181
274
  if (!localPointer) return [];
182
275
 
183
- const overrideStyle = forcePointerEventsAuto(doc);
276
+ let overrideStyle = forcePointerEventsAuto(doc);
184
277
  try {
185
278
  if (typeof doc.elementsFromPoint === "function") {
186
- return resolveAllVisualDomEditTargets(doc.elementsFromPoint(localPointer.x, localPointer.y), {
187
- activeCompositionPath,
188
- }).filter((el) => !isFullBleedTarget(el, localPointer.viewport));
279
+ const elements = doc.elementsFromPoint(localPointer.x, localPointer.y);
280
+ removePointerEventsOverride(overrideStyle);
281
+ overrideStyle = null;
282
+ return filterAuthorInteractiveTargets(elements, activeCompositionPath).filter(
283
+ (el) => !isFullBleedTarget(el, localPointer.viewport),
284
+ );
189
285
  }
190
286
  const fallback = getEventTargetElement(doc.elementFromPoint(localPointer.x, localPointer.y));
191
287
  if (!fallback || !getDomLayerPatchTarget(fallback, activeCompositionPath)) return [];
288
+ removePointerEventsOverride(overrideStyle);
289
+ overrideStyle = null;
290
+ if (hasAuthorPointerEventsNone(fallback)) return [];
192
291
  if (!isElementComputedVisible(fallback)) return [];
193
292
  if (isFullBleedTarget(fallback, localPointer.viewport)) return [];
194
293
  return [fallback];
@@ -18,11 +18,13 @@ export interface StudioSaveFailureInput {
18
18
 
19
19
  export class StudioSaveHttpError extends Error {
20
20
  readonly statusCode: number;
21
+ readonly alreadyToasted: boolean;
21
22
 
22
- constructor(message: string, statusCode: number) {
23
+ constructor(message: string, statusCode: number, options: { alreadyToasted?: boolean } = {}) {
23
24
  super(message);
24
25
  this.name = "StudioSaveHttpError";
25
26
  this.statusCode = statusCode;
27
+ this.alreadyToasted = options.alreadyToasted ?? false;
26
28
  }
27
29
  }
28
30
 
@@ -130,6 +132,7 @@ export function trackStudioSaveFailure(input: StudioSaveFailureInput): void {
130
132
  export async function createStudioSaveHttpError(
131
133
  response: Response,
132
134
  fallbackMessage: string,
135
+ options: { alreadyToasted?: boolean } = {},
133
136
  ): Promise<StudioSaveHttpError> {
134
137
  let body = "";
135
138
  try {
@@ -141,7 +144,7 @@ export async function createStudioSaveHttpError(
141
144
  const message = detail
142
145
  ? `${fallbackMessage} (${response.status}): ${detail}`
143
146
  : `${fallbackMessage} (${response.status})`;
144
- return new StudioSaveHttpError(message, response.status);
147
+ return new StudioSaveHttpError(message, response.status, options);
145
148
  }
146
149
 
147
150
  export async function retryStudioSave<T>(
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/editor/domEditingLayers.ts","../src/components/editor/domEditingTypes.ts","../src/components/editor/domEditingDom.ts","../src/components/editor/domEditingGroups.ts","../src/components/editor/domEditingElement.ts","../src/components/editor/domEditingRootLayer.ts"],"sourcesContent":["/**\n * Layer items, text fields, capabilities, selection resolution, and patch operations\n * for dom editing.\n */\nimport type { PatchOperation } from \"../../utils/sourcePatcher\";\nimport {\n resolveEditingAffordances,\n resolveEditingSections,\n type EditableElementFacts,\n} from \"@hyperframes/core/editing\";\nimport { groupScopedLayerRoots, resolveGroupCapture } from \"./domEditingGroups\";\nimport type {\n DomEditCapabilities,\n DomEditContextOptions,\n DomEditLayerItem,\n DomEditSelection,\n DomEditTextField,\n} from \"./domEditingTypes\";\nimport {\n buildElementLabel,\n buildStableSelector,\n findClosestByAttribute,\n getCuratedComputedStyles,\n getDataAttributes,\n getInlineStyles,\n getSelectorIndex,\n getSourceFileForElement,\n isHtmlElement,\n isTextBearingTag,\n} from \"./domEditingDom\";\nimport {\n findElementForSelection,\n getDomLayerPatchTarget,\n getDirectLayerChildren,\n getSelectionCandidate,\n} from \"./domEditingElement\";\nimport { isCompositionRootLayer } from \"./domEditingRootLayer\";\n\n// ─── Text fields ────────────────────────────────────────────────────────────\n\nexport function isEditableTextLeaf(el: HTMLElement): boolean {\n return isTextBearingTag(el.tagName.toLowerCase()) && el.children.length === 0;\n}\n\nfunction getTextFieldLabel(\n _tagName: string,\n index: number,\n total: number,\n source: \"self\" | \"child\",\n): string {\n if (source === \"self\" || total === 1) return \"Content\";\n return `Text ${index + 1}`;\n}\n\nfunction buildTextField(\n el: HTMLElement,\n index: number,\n total: number,\n source: \"self\" | \"child\",\n): DomEditTextField {\n const tagName = el.tagName.toLowerCase();\n const key = el.getAttribute(\"data-hf-text-key\") ?? `${source}:${index}:${tagName}`;\n return {\n key,\n label: getTextFieldLabel(tagName, index, total, source),\n value: el.textContent ?? \"\",\n tagName,\n attributes: Array.from(el.attributes)\n .filter((attribute) => attribute.name !== \"style\")\n .map((attribute) => ({\n name: attribute.name,\n value: attribute.value,\n })),\n inlineStyles: getInlineStyles(el),\n computedStyles: getCuratedComputedStyles(el),\n source,\n };\n}\n\n// fallow-ignore-next-line complexity\nexport function collectDomEditTextFields(el: HTMLElement): DomEditTextField[] {\n const childElements = Array.from(el.children).filter(isHtmlElement).filter(isEditableTextLeaf);\n\n if (childElements.length > 0) {\n const hasMixedContent = Array.from(el.childNodes).some(\n (node) => node.nodeType === 3 && node.textContent?.trim(),\n );\n\n if (hasMixedContent) {\n const fields: DomEditTextField[] = [];\n let childIdx = 0;\n for (const node of el.childNodes) {\n if (node.nodeType === 3) {\n const text = node.textContent ?? \"\";\n if (!text.trim()) continue;\n fields.push({\n key: `text-node:${childIdx}`,\n label: `Text ${childIdx + 1}`,\n value: text,\n tagName: \"#text\",\n attributes: [],\n inlineStyles: {},\n computedStyles: {},\n source: \"text-node\",\n });\n childIdx++;\n } else if (isHtmlElement(node) && isEditableTextLeaf(node)) {\n fields.push(buildTextField(node, childIdx, childElements.length, \"child\"));\n childIdx++;\n }\n }\n return fields;\n }\n\n return childElements.map((child, index) =>\n buildTextField(child, index, childElements.length, \"child\"),\n );\n }\n\n if (isEditableTextLeaf(el)) {\n return [buildTextField(el, 0, 1, \"self\")];\n }\n\n return [];\n}\n\nfunction escapeHtmlText(value: string): string {\n return value.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\nfunction serializeTextFieldStyle(field: DomEditTextField): string {\n const entries = Object.entries(field.inlineStyles).filter(([, value]) => Boolean(value));\n if (entries.length === 0) return \"\";\n return entries.map(([key, value]) => `${key}: ${value}`).join(\"; \");\n}\n\nexport function serializeDomEditTextFields(fields: DomEditTextField[]): string {\n return fields\n .filter((field) => field.source === \"child\" || field.source === \"text-node\")\n .map((field) => {\n if (field.source === \"text-node\") {\n return escapeHtmlText(field.value);\n }\n const attrs = [\n ...field.attributes.filter((attribute) => attribute.name !== \"data-hf-text-key\"),\n { name: \"data-hf-text-key\", value: field.key },\n ]\n .map((attribute) => ` ${attribute.name}=\"${attribute.value.replace(/\"/g, \"&quot;\")}\"`)\n .join(\"\");\n const style = serializeTextFieldStyle(field);\n const styleAttr = style ? ` style=\"${style.replace(/\"/g, \"&quot;\")}\"` : \"\";\n return `<${field.tagName}${attrs}${styleAttr}>${escapeHtmlText(field.value)}</${field.tagName}>`;\n })\n .join(\"\");\n}\n\nexport function buildDefaultDomEditTextField(base?: Partial<DomEditTextField>): DomEditTextField {\n return {\n key: `child:new:${Date.now()}`,\n label: \"Text\",\n value: \"New text\",\n tagName: \"span\",\n attributes: [],\n inlineStyles: {\n \"font-family\": base?.computedStyles?.[\"font-family\"] ?? \"inherit\",\n \"font-size\": base?.computedStyles?.[\"font-size\"] ?? \"16px\",\n \"font-weight\": base?.computedStyles?.[\"font-weight\"] ?? \"400\",\n color: base?.computedStyles?.color ?? \"inherit\",\n },\n computedStyles: {},\n source: \"child\",\n };\n}\n\n// ─── Capabilities ────────────────────────────────────────────────────────────\n\n/**\n * Build the geometry/capability half of EditableElementFacts. Section inputs\n * (text/timing/animation) are irrelevant to capability resolution, so they are\n * zeroed here. Shared by the wrapper and the live-selection path so the two\n * fact-construction sites can't disagree.\n */\nfunction capabilityFacts(geometry: {\n hasStableTarget: boolean;\n tag: string;\n inlineStyles: Record<string, string>;\n computedStyles: Record<string, string>;\n isCompositionHost: boolean;\n isCompositionRoot: boolean;\n isInsideLockedComposition: boolean;\n isMasterView: boolean;\n existsInSource: boolean;\n}): EditableElementFacts {\n return {\n ...geometry,\n hasEditableText: false,\n hasTimingStart: false,\n animationCount: 0,\n };\n}\n\n/**\n * Build core EditableElementFacts from a fully-resolved DomEditSelection.\n * `animationCount` is supplied by the caller because live GSAP tweens arrive on\n * a separate channel (the PropertyPanel `gsapAnimations` prop), not on the\n * selection — `selection.gsapAnimations` is never populated.\n */\nexport function domEditSelectionToFacts(\n selection: DomEditSelection,\n animationCount = selection.gsapAnimations?.length ?? 0,\n): EditableElementFacts {\n return {\n hasStableTarget: Boolean(selection.selector || selection.hfId),\n tag: selection.tagName,\n inlineStyles: selection.inlineStyles,\n computedStyles: selection.computedStyles,\n isCompositionHost: selection.isCompositionHost,\n isCompositionRoot: false,\n isInsideLockedComposition: selection.isInsideLockedComposition,\n isMasterView: false,\n existsInSource: true,\n hasEditableText: selection.textFields.length > 0,\n hasTimingStart: selection.dataAttributes.start != null,\n animationCount,\n };\n}\n\n/**\n * Resolve DOM edit capabilities for a given element.\n * Thin wrapper over core resolveEditingAffordances — kept for backward\n * compatibility (tests and the barrel import this signature directly).\n */\nexport function resolveDomEditCapabilities(args: {\n selector?: string;\n hfId?: string;\n tagName?: string;\n inlineStyles: Record<string, string>;\n computedStyles: Record<string, string>;\n isCompositionHost: boolean;\n isCompositionRoot?: boolean;\n isInsideLockedComposition: boolean;\n isMasterView: boolean;\n existsInSource?: boolean;\n}): DomEditCapabilities {\n return resolveEditingAffordances(\n capabilityFacts({\n hasStableTarget: Boolean(args.selector || args.hfId),\n tag: (args.tagName ?? \"div\").toLowerCase(),\n inlineStyles: args.inlineStyles,\n computedStyles: args.computedStyles,\n isCompositionHost: args.isCompositionHost,\n isCompositionRoot: args.isCompositionRoot ?? false,\n isInsideLockedComposition: args.isInsideLockedComposition ?? false,\n isMasterView: args.isMasterView,\n existsInSource: args.existsInSource ?? true,\n }),\n ).capabilities;\n}\n\n// ─── Element label ────────────────────────────────────────────────────────────\n\n// ─── Source probe ────────────────────────────────────────────────────────────\n\nasync function probeSourceElement(\n projectId: string,\n sourceFile: string,\n target: { id?: string; hfId?: string; selector?: string; selectorIndex?: number },\n): Promise<boolean> {\n try {\n const response = await fetch(\n `/api/projects/${projectId}/file-mutations/probe-element/${encodeURIComponent(sourceFile)}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ target }),\n },\n );\n if (!response.ok) return true;\n const data = (await response.json()) as { exists?: boolean };\n return data.exists !== false;\n } catch {\n return true;\n }\n}\n\n// ─── Selection resolution ────────────────────────────────────────────────────\n\n// fallow-ignore-next-line complexity\nexport async function resolveDomEditSelection(\n startEl: HTMLElement | null,\n options: DomEditContextOptions & { projectId?: string | null; skipSourceProbe?: boolean },\n): Promise<DomEditSelection | null> {\n if (!startEl) return null;\n const doc = startEl.ownerDocument;\n\n let capture = resolveGroupCapture(startEl, options.activeGroupElement ?? null);\n if (capture.kind === \"out-of-scope\") {\n // Drill-in is non-sticky: clicking/hovering OUTSIDE the drilled-into group\n // exits it and resolves the target normally, rather than selecting nothing\n // (which felt like \"can't select anything\" once you'd drilled in).\n capture = resolveGroupCapture(startEl, null);\n }\n let current: HTMLElement | null =\n capture.kind === \"unit\" ? capture.element : getSelectionCandidate(startEl, options);\n while (current && current !== doc.body && current !== doc.documentElement) {\n const selector = buildStableSelector(current);\n const hfId = readHfId(current);\n if (!selector && !hfId) {\n current = current.parentElement;\n continue;\n }\n\n const { sourceFile, compositionPath } = getSourceFileForElement(\n current,\n options.activeCompositionPath,\n );\n const selectorIndex = selector\n ? getSelectorIndex(doc, current, selector, sourceFile, options.activeCompositionPath)\n : undefined;\n const compositionSrc =\n current.getAttribute(\"data-composition-src\") ??\n current.getAttribute(\"data-composition-file\") ??\n undefined;\n const inlineStyles = getInlineStyles(current);\n const computedStyles = getCuratedComputedStyles(current);\n const isCompositionRoot =\n (current.hasAttribute(\"data-composition-id\") && !compositionSrc) ||\n isCompositionRootLayer(current, doc, computedStyles);\n const textFields = collectDomEditTextFields(current);\n const isInsideLocked = Boolean(findClosestByAttribute(current, [\"data-timeline-locked\"]));\n let existsInSource: boolean | undefined;\n if (!options.skipSourceProbe && options.projectId && (current.id || selector || hfId)) {\n const probeTarget: { id?: string; hfId?: string; selector?: string; selectorIndex?: number } =\n {};\n if (current.id) probeTarget.id = current.id;\n if (hfId) probeTarget.hfId = hfId;\n if (selector) probeTarget.selector = selector;\n if (selectorIndex != null) probeTarget.selectorIndex = selectorIndex;\n existsInSource = await probeSourceElement(options.projectId, sourceFile, probeTarget);\n }\n const capabilities = resolveEditingAffordances(\n capabilityFacts({\n hasStableTarget: Boolean(selector || hfId),\n tag: current.tagName.toLowerCase(),\n inlineStyles,\n computedStyles,\n isCompositionHost: Boolean(compositionSrc),\n isCompositionRoot,\n isInsideLockedComposition: isInsideLocked,\n isMasterView: options.isMasterView,\n existsInSource: existsInSource ?? true,\n }),\n ).capabilities;\n const rect = current.getBoundingClientRect();\n\n return {\n element: current,\n id: current.id || undefined,\n hfId,\n selector,\n selectorIndex,\n sourceFile,\n compositionPath,\n compositionSrc,\n isCompositionHost: Boolean(compositionSrc),\n isInsideLockedComposition: isInsideLocked,\n label: buildElementLabel(current),\n tagName: current.tagName.toLowerCase(),\n boundingBox: {\n x: rect.left,\n y: rect.top,\n width: rect.width,\n height: rect.height,\n },\n textContent: current.textContent?.trim() || null,\n dataAttributes: getDataAttributes(current),\n inlineStyles,\n computedStyles,\n textFields,\n capabilities,\n };\n }\n\n return null;\n}\n\nexport async function refreshDomEditSelection(\n selection: DomEditSelection,\n activeCompositionPath: string | null,\n): Promise<DomEditSelection | null> {\n const doc = selection.element.ownerDocument;\n const nextElement = findElementForSelection(doc, selection, activeCompositionPath);\n return nextElement\n ? resolveDomEditSelection(nextElement, {\n activeCompositionPath,\n isMasterView: !activeCompositionPath || activeCompositionPath === \"index.html\",\n })\n : null;\n}\n\n// ─── Layer items ─────────────────────────────────────────────────────────────\n\nexport function getDomEditLayerKey(\n target: Pick<DomEditSelection, \"id\" | \"selector\" | \"selectorIndex\" | \"sourceFile\">,\n): string {\n const selectorIndex = target.selectorIndex ?? 0;\n return `${target.sourceFile}:${target.id ?? target.selector ?? \"layer\"}:${selectorIndex}`;\n}\n\nexport function countDomEditChildLayers(\n root: HTMLElement | null | undefined,\n options: DomEditContextOptions,\n maxCount = 99,\n): number {\n if (!root) return 0;\n\n let count = 0;\n const visit = (el: HTMLElement) => {\n for (const child of Array.from(el.children)) {\n if (!isHtmlElement(child)) continue;\n if (getDomLayerPatchTarget(child, options.activeCompositionPath)) {\n count += 1;\n if (count >= maxCount) return;\n }\n visit(child);\n if (count >= maxCount) return;\n }\n };\n\n visit(root);\n return count;\n}\n\nexport function collectDomEditLayerItems(\n root: HTMLElement | null | undefined,\n options: DomEditContextOptions,\n maxItems = 80,\n): DomEditLayerItem[] {\n if (!root) return [];\n\n const items: DomEditLayerItem[] = [];\n // fallow-ignore-next-line complexity\n const visit = (el: HTMLElement, depth: number) => {\n if (items.length >= maxItems) return;\n\n const target = getDomLayerPatchTarget(el, options.activeCompositionPath);\n if (target) {\n items.push({\n key: getDomEditLayerKey(target),\n element: el,\n label: buildElementLabel(el),\n tagName: el.tagName.toLowerCase(),\n depth,\n childCount: getDirectLayerChildren(el, options).length,\n id: target.id ?? undefined,\n hfId: target.hfId ?? undefined,\n selector: target.selector ?? undefined,\n selectorIndex: target.selectorIndex,\n sourceFile: target.sourceFile,\n });\n }\n\n const nextDepth = target ? depth + 1 : depth;\n for (const child of Array.from(el.children)) {\n if (!isHtmlElement(child)) continue;\n visit(child, nextDepth);\n if (items.length >= maxItems) return;\n }\n };\n\n // Drilled into a group → show only its members; otherwise the whole tree.\n for (const el of groupScopedLayerRoots(root, options.activeGroupElement ?? null)) visit(el, 0);\n return items;\n}\n\n// ─── Patch operations ────────────────────────────────────────────────────────\n\nexport function buildDomEditStylePatchOperation(property: string, value: string): PatchOperation {\n return {\n type: \"inline-style\",\n property,\n value,\n };\n}\n\nexport function buildDomEditTextPatchOperation(value: string): PatchOperation {\n return {\n type: \"text-content\",\n property: \"text\",\n value,\n };\n}\n\n// ─── Non-editable reason ─────────────────────────────────────────────────────\n\nfunction hasSupportedDirectEdit(capabilities: DomEditCapabilities): boolean {\n return (\n capabilities.canEditStyles ||\n capabilities.canMove ||\n capabilities.canResize ||\n capabilities.canApplyManualOffset ||\n capabilities.canApplyManualSize ||\n capabilities.canApplyManualRotation\n );\n}\n\nexport function getDomEditNonEditableReason(\n element: HTMLElement,\n selection: DomEditSelection | null,\n): string | null {\n if (!selection) {\n return \"No stable source target\";\n }\n\n if (selection.element !== element) {\n return selection.isCompositionHost\n ? \"Nested composition boundary\"\n : `Selection resolves to ${selection.label}`;\n }\n\n if (!hasSupportedDirectEdit(selection.capabilities)) {\n return selection.capabilities.reasonIfDisabled ?? \"No supported direct edits\";\n }\n\n return null;\n}\n\nexport function getDomEditTargetKey(\n selection: Pick<DomEditSelection, \"id\" | \"hfId\" | \"selector\" | \"selectorIndex\" | \"sourceFile\">,\n): string {\n return [\n selection.sourceFile || \"index.html\",\n selection.hfId ?? \"\",\n selection.id ?? \"\",\n selection.selector ?? \"\",\n selection.selectorIndex ?? \"\",\n ].join(\"|\");\n}\n\nexport function isTextEditableSelection(selection: DomEditSelection): boolean {\n return resolveEditingSections(domEditSelectionToFacts(selection)).text;\n}\n\n// buildElementAgentPrompt is in domEditingAgentPrompt.ts\n\nexport function readHfId(element: Element): string | undefined {\n return element.getAttribute(\"data-hf-id\")?.trim() || undefined;\n}\n\nexport function buildDomEditPatchTarget(\n selection: Pick<DomEditSelection, \"id\" | \"hfId\" | \"selector\" | \"selectorIndex\">,\n): { id?: string | null; hfId?: string; selector?: string; selectorIndex?: number } {\n return {\n id: selection.id,\n hfId: selection.hfId,\n selector: selection.selector,\n selectorIndex: selection.selectorIndex,\n };\n}\n","import type { PatchTarget } from \"../../utils/sourcePatcher\";\nimport type { GsapAnimation } from \"@hyperframes/parsers/gsap-parser\";\n\nexport const CURATED_STYLE_PROPERTIES = [\n \"position\",\n \"display\",\n \"top\",\n \"left\",\n \"right\",\n \"bottom\",\n \"inset\",\n \"width\",\n \"height\",\n \"gap\",\n \"justify-content\",\n \"align-items\",\n \"flex-direction\",\n \"font-size\",\n \"font-style\",\n \"font-weight\",\n \"font-family\",\n \"line-height\",\n \"letter-spacing\",\n \"text-align\",\n \"text-transform\",\n \"color\",\n \"background-color\",\n \"background-image\",\n \"opacity\",\n \"mix-blend-mode\",\n \"border-radius\",\n \"border-width\",\n \"border-style\",\n \"border-color\",\n \"border-top-width\",\n \"border-top-style\",\n \"border-top-color\",\n \"outline-color\",\n \"overflow\",\n \"clip-path\",\n \"box-shadow\",\n \"filter\",\n \"backdrop-filter\",\n \"z-index\",\n \"transform\",\n \"object-fit\",\n \"object-position\",\n] as const;\n\nexport interface DomEditCapabilities {\n canSelect: boolean;\n canEditStyles: boolean;\n /** Directly editable authored left/top style fields. Canvas drag uses manual edits instead. */\n canMove: boolean;\n /** Directly editable authored width/height style fields. Canvas resize uses manual edits instead. */\n canResize: boolean;\n canApplyManualOffset: boolean;\n canApplyManualSize: boolean;\n canApplyManualRotation: boolean;\n reasonIfDisabled?: string;\n}\n\nexport interface DomEditTextField {\n key: string;\n label: string;\n value: string;\n tagName: string;\n attributes: Array<{ name: string; value: string }>;\n inlineStyles: Record<string, string>;\n computedStyles: Record<string, string>;\n source: \"self\" | \"child\" | \"text-node\";\n}\n\nexport interface DomEditSelection extends PatchTarget {\n element: HTMLElement;\n label: string;\n tagName: string;\n sourceFile: string;\n compositionPath: string;\n compositionSrc?: string;\n isCompositionHost: boolean;\n isInsideLockedComposition: boolean;\n boundingBox: { x: number; y: number; width: number; height: number };\n textContent: string | null;\n dataAttributes: Record<string, string>;\n inlineStyles: Record<string, string>;\n computedStyles: Record<string, string>;\n textFields: DomEditTextField[];\n capabilities: DomEditCapabilities;\n gsapAnimations?: GsapAnimation[];\n}\n\nexport interface DomEditLayerItem {\n key: string;\n element: HTMLElement;\n label: string;\n tagName: string;\n depth: number;\n childCount: number;\n id?: string;\n hfId?: string;\n selector?: string;\n selectorIndex?: number;\n sourceFile: string;\n}\n\nexport interface DomEditContextOptions {\n activeCompositionPath: string | null;\n isMasterView: boolean;\n preferClipAncestor?: boolean;\n /** The group wrapper the user has drilled into (null = top level). Selection\n * resolution treats groups as a unit unless drilled into one. */\n activeGroupElement?: HTMLElement | null;\n}\n\nexport interface DomEditViewport {\n width: number;\n height: number;\n}\n\nexport interface TimelineElementDomTarget {\n id?: string;\n domId?: string;\n selector?: string;\n selectorIndex?: number;\n sourceFile?: string;\n compositionSrc?: string;\n}\n\nexport interface TimelineElementDomTargetOptions {\n activeCompositionPath: string | null;\n compIdToSrc?: ReadonlyMap<string, string>;\n isMasterView: boolean;\n}\n","/**\n * Low-level DOM primitives: type guards, style getters, CSS escaping,\n * selector utilities, and composition source resolution.\n * No imports from other domEditing* modules — safe to import from anywhere.\n */\nimport { CURATED_STYLE_PROPERTIES } from \"./domEditingTypes\";\n\n// ─── Type guard ───────────────────────────────────────────────────────────────\n\nexport function isHtmlElement(value: unknown): value is HTMLElement {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"nodeType\" in value &&\n typeof (value as { nodeType?: unknown }).nodeType === \"number\" &&\n (value as { nodeType: number }).nodeType === 1\n );\n}\n\n// ─── Style parsing ────────────────────────────────────────────────────────────\n\n// Single source of truth lives in @hyperframes/core/editing so the studio\n// callers and the core resolver can't drift. Re-exported here to keep this\n// module's public surface (6 studio callers import parsePx from it).\nexport { parsePx } from \"@hyperframes/core/editing\";\n\nexport function isTextBearingTag(tagName: string): boolean {\n return [\"div\", \"span\", \"p\", \"strong\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"].includes(tagName);\n}\n\nconst COLOR_GRADING_SOURCE_HIDDEN_ATTR = \"data-hf-color-grading-source-hidden\";\n\nexport function isElementVisibleThroughAncestors(el: HTMLElement): boolean {\n const win = el.ownerDocument.defaultView;\n if (!win) return true;\n let current: HTMLElement | null = el;\n while (current) {\n const computed = win.getComputedStyle(current);\n if (computed.display === \"none\" || computed.visibility === \"hidden\") return false;\n const opacity = Number.parseFloat(computed.opacity);\n if (\n Number.isFinite(opacity) &&\n opacity <= 0.01 &&\n !current.hasAttribute(COLOR_GRADING_SOURCE_HIDDEN_ATTR)\n )\n return false;\n current = current.parentElement;\n }\n return true;\n}\n\n// ─── Style accessors ──────────────────────────────────────────────────────────\n\nexport function getCuratedComputedStyles(el: HTMLElement): Record<string, string> {\n const styles: Record<string, string> = {};\n const computed = el.ownerDocument.defaultView?.getComputedStyle(el);\n if (!computed) return styles;\n\n for (const prop of CURATED_STYLE_PROPERTIES) {\n const value = computed.getPropertyValue(prop);\n if (value) styles[prop] = value;\n }\n\n return styles;\n}\n\nexport function getInlineStyles(el: HTMLElement): Record<string, string> {\n const styles: Record<string, string> = {};\n for (const property of CURATED_STYLE_PROPERTIES) {\n const value = el.style.getPropertyValue(property);\n if (value) styles[property] = value;\n }\n return styles;\n}\n\nexport function getDataAttributes(el: HTMLElement): Record<string, string> {\n const attrs: Record<string, string> = {};\n for (const attr of el.attributes) {\n if (attr.name.startsWith(\"data-\")) {\n attrs[attr.name.slice(5)] = attr.value;\n }\n }\n return attrs;\n}\n\n// ─── DOM traversal ────────────────────────────────────────────────────────────\n\nexport function findClosestByAttribute(\n el: HTMLElement,\n attributeNames: string[],\n): HTMLElement | null {\n let current: HTMLElement | null = el;\n while (current) {\n const candidate = current;\n if (attributeNames.some((attribute) => candidate.hasAttribute(attribute))) {\n return candidate;\n }\n current = current.parentElement;\n }\n return null;\n}\n// ─── Composition source resolution ───────────────────────────────────────────\n\n// The runtime INLINES subcompositions and strips the source-file linkage from the\n// mounted root (it keeps `data-composition-id` but drops `data-composition-src`/\n// `-file`), so a subcomp element's DOM ancestors no longer say which file it came\n// from. This project-global map (composition-id → source file, built once from\n// index.html's clips — see NLELayout) recovers it. The studio loads one project at a\n// time, so module scope is the right lifetime; it's empty until set, in which case\n// resolution falls back to the historical attribute-only behavior.\nlet compositionSourceMap: Map<string, string> = new Map();\n\nexport function setCompositionSourceMap(map: Map<string, string>): void {\n compositionSourceMap = map;\n}\n\nfunction sourceFromCompositionId(ownerRoot: HTMLElement | null): string | undefined {\n if (!ownerRoot || compositionSourceMap.size === 0) return undefined;\n // The runtime may rename the mounted id to a runtime-unique one, preserving the\n // authored id on `data-hf-original-composition-id` — prefer that, then the current id.\n const authored = ownerRoot.getAttribute(\"data-hf-original-composition-id\");\n const current = ownerRoot.getAttribute(\"data-composition-id\");\n return (\n (authored ? compositionSourceMap.get(authored) : undefined) ??\n (current ? compositionSourceMap.get(current) : undefined)\n );\n}\n\nexport function getSourceFileForElement(\n el: HTMLElement,\n activeCompositionPath: string | null,\n): { sourceFile: string; compositionPath: string } {\n const sourceHost = findClosestByAttribute(el, [\"data-composition-file\", \"data-composition-src\"]);\n const ownerRoot = findClosestByAttribute(el, [\"data-composition-id\"]);\n const sourceFile =\n sourceHost?.getAttribute(\"data-composition-file\") ??\n sourceHost?.getAttribute(\"data-composition-src\") ??\n ownerRoot?.getAttribute(\"data-composition-file\") ??\n ownerRoot?.getAttribute(\"data-composition-src\") ??\n sourceFromCompositionId(ownerRoot) ??\n activeCompositionPath ??\n \"index.html\";\n\n return {\n sourceFile,\n compositionPath: sourceFile,\n };\n}\n\nexport function normalizeTimelineCompositionSource(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n if (!trimmed) return undefined;\n\n let pathname = trimmed;\n try {\n pathname = new URL(trimmed, \"http://studio.local\").pathname;\n } catch {\n pathname = trimmed;\n }\n\n for (const marker of [\"/preview/comp/\", \"/preview/\"]) {\n const markerIndex = pathname.indexOf(marker);\n if (markerIndex < 0) continue;\n const sourcePath = pathname.slice(markerIndex + marker.length).replace(/^\\/+/, \"\");\n return sourcePath || trimmed;\n }\n\n return trimmed;\n}\n\n// ─── CSS escaping ─────────────────────────────────────────────────────────────\n\nfunction escapeCssIdentifier(value: string): string {\n const css = globalThis.CSS as { escape?: (input: string) => string } | undefined;\n if (typeof css?.escape === \"function\") return css.escape(value);\n\n if (value === \"-\") return \"\\\\-\";\n\n let escaped = \"\";\n for (let index = 0; index < value.length; index += 1) {\n const char = value[index] ?? \"\";\n const code = char.charCodeAt(0);\n if (code === 0) {\n escaped += \"�\";\n continue;\n }\n\n const isDigit = code >= 48 && code <= 57;\n const isUpperAlpha = code >= 65 && code <= 90;\n const isLowerAlpha = code >= 97 && code <= 122;\n const isControl = (code >= 1 && code <= 31) || code === 127;\n const isLeadingDigit = index === 0 && isDigit;\n const isSecondDigitAfterDash = index === 1 && value.startsWith(\"-\") && isDigit;\n if (isControl || isLeadingDigit || isSecondDigitAfterDash) {\n escaped += `\\\\${code.toString(16)} `;\n continue;\n }\n if (isUpperAlpha || isLowerAlpha || isDigit || char === \"-\" || char === \"_\" || code >= 128) {\n escaped += char;\n continue;\n }\n escaped += `\\\\${char}`;\n }\n return escaped;\n}\n\nexport function escapeCssString(value: string): string {\n return value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\a \")\n .replace(/\\r/g, \"\\\\d \")\n .replace(/\\f/g, \"\\\\c \");\n}\n\nexport function querySelectorAllSafely(doc: Document, selector: string): Element[] {\n try {\n return Array.from(doc.querySelectorAll(selector));\n } catch {\n return [];\n }\n}\n\nfunction humanizeIdentifier(value: string): string {\n return (\n value\n .replace(/\\.html$/i, \"\")\n .replace(/^compositions\\//i, \"\")\n .split(\"/\")\n .at(-1)\n ?.replace(/[-_]+/g, \" \")\n .replace(/\\b\\w/g, (char) => char.toUpperCase()) ?? value\n );\n}\n\n// ─── CSS selector building ────────────────────────────────────────────────────\n\nexport function buildStableSelector(el: HTMLElement): string | undefined {\n if (el.id) return `#${escapeCssIdentifier(el.id)}`;\n\n const compositionId = el.getAttribute(\"data-composition-id\");\n if (compositionId) return `[data-composition-id=\"${escapeCssString(compositionId)}\"]`;\n\n // Group wrappers carry no id/class; their data-hf-group value is the unique,\n // stable handle the source mutations write — use it so the wrapper is\n // selectable, patchable (move/scale), and addressable for ungroup.\n const group = el.getAttribute(\"data-hf-group\");\n if (group) return `[data-hf-group=\"${escapeCssString(group)}\"]`;\n\n return getPreferredClassSelector(el);\n}\n\nfunction getPreferredClassSelector(el: HTMLElement): string | undefined {\n const classes = Array.from(el.classList)\n .map((value) => value.trim())\n .filter(Boolean);\n if (classes.length === 0) return undefined;\n const preferred =\n classes.find((value) => value !== \"clip\" && !value.startsWith(\"__hf-\")) ?? classes[0];\n return preferred ? `.${escapeCssIdentifier(preferred)}` : undefined;\n}\n\n// fallow-ignore-next-line complexity\nexport function buildElementLabel(el: HTMLElement): string {\n const compositionId = el.getAttribute(\"data-composition-id\");\n if (compositionId && compositionId !== \"main\") {\n return humanizeIdentifier(compositionId);\n }\n\n const compositionSrc =\n el.getAttribute(\"data-composition-src\") ?? el.getAttribute(\"data-composition-file\");\n if (compositionSrc) {\n return humanizeIdentifier(compositionSrc);\n }\n\n const group = el.getAttribute(\"data-hf-group\");\n if (group) return group;\n\n if (el.id) return humanizeIdentifier(el.id);\n\n const preferredClass = getPreferredClassSelector(el);\n if (preferredClass) {\n return humanizeIdentifier(preferredClass.replace(/^\\./, \"\"));\n }\n\n const text = (el.textContent ?? \"\").trim().replace(/\\s+/g, \" \");\n if (text) return text.length > 40 ? `${text.slice(0, 39)}…` : text;\n return el.tagName.toLowerCase();\n}\n\nexport function getSelectorIndex(\n doc: Document,\n el: HTMLElement,\n selector: string | undefined,\n sourceFile: string,\n activeCompositionPath: string | null,\n): number | undefined {\n if (!selector?.startsWith(\".\")) return undefined;\n\n const candidates = querySelectorAllSafely(doc, selector).filter(\n (candidate): candidate is HTMLElement =>\n isHtmlElement(candidate) &&\n getSourceFileForElement(candidate, activeCompositionPath).sourceFile === sourceFile,\n );\n const index = candidates.indexOf(el);\n return index >= 0 ? index : undefined;\n}\n","import { isHtmlElement } from \"./domEditingDom\";\n\n// `data-hf-group` selection semantics: a group wrapper is selected as one unit\n// until the user drills into it; once drilled in, clicks resolve to its children\n// (or to the next nested group inside it). One level of drill-in at a time keeps\n// nested groups navigable.\n\nexport type GroupCapture =\n | { kind: \"unit\"; element: HTMLElement } // select this group wrapper as one unit\n | { kind: \"child\" } // resolve the clicked element normally\n | { kind: \"out-of-scope\" }; // clicked outside the drilled-into group → select nothing\n\n// Layer-tree roots: the drilled-into group's element children, else the doc root.\nexport function groupScopedLayerRoots(\n root: HTMLElement,\n activeGroupElement: HTMLElement | null,\n): HTMLElement[] {\n const els = activeGroupElement?.isConnected ? Array.from(activeGroupElement.children) : [root];\n return els.filter(isHtmlElement);\n}\n\nexport function resolveGroupCapture(\n startEl: HTMLElement,\n activeGroupElement: HTMLElement | null,\n): GroupCapture {\n const groups: HTMLElement[] = [];\n for (let n: HTMLElement | null = startEl; n; n = n.parentElement) {\n if (n.hasAttribute(\"data-hf-group\")) groups.push(n);\n }\n const result = ((): GroupCapture => {\n if (!activeGroupElement) {\n const outermost = groups[groups.length - 1];\n return outermost ? { kind: \"unit\", element: outermost } : { kind: \"child\" };\n }\n const idx = groups.indexOf(activeGroupElement);\n if (idx === -1) return { kind: \"out-of-scope\" };\n const nestedInside = groups[idx - 1];\n return nestedInside ? { kind: \"unit\", element: nestedInside } : { kind: \"child\" };\n })();\n return result;\n}\n","/**\n * Element visibility, visual scoring, layer patch targets, element finders,\n * and the `findElementForSelection` / `findElementForTimelineElement` lookups.\n */\nimport type {\n DomEditContextOptions,\n DomEditSelection,\n DomEditViewport,\n TimelineElementDomTarget,\n TimelineElementDomTargetOptions,\n} from \"./domEditingTypes\";\nimport {\n buildStableSelector,\n escapeCssString,\n getSelectorIndex,\n getSourceFileForElement,\n isHtmlElement,\n isElementVisibleThroughAncestors,\n normalizeTimelineCompositionSource,\n querySelectorAllSafely,\n} from \"./domEditingDom\";\n\n// ─── Visibility ──────────────────────────────────────────────────────────────\n\nexport function isElementComputedVisible(el: HTMLElement): boolean {\n return isElementVisibleThroughAncestors(el);\n}\n\nconst VISUAL_LEAF_TAGS = new Set([\"img\", \"video\", \"canvas\", \"svg\", \"audio\"]);\n\nfunction hasVisualPresence(el: HTMLElement): boolean {\n const win = el.ownerDocument.defaultView;\n if (!win) return false;\n const cs = win.getComputedStyle(el);\n if (cs.backgroundImage !== \"none\") return true;\n if (\n cs.backgroundColor &&\n cs.backgroundColor !== \"transparent\" &&\n cs.backgroundColor !== \"rgba(0, 0, 0, 0)\"\n )\n return true;\n if (cs.borderWidth && parseFloat(cs.borderWidth) > 0 && cs.borderStyle !== \"none\") return true;\n if (cs.boxShadow && cs.boxShadow !== \"none\") return true;\n return false;\n}\n\nfunction isEmptyVisualContainer(el: HTMLElement): boolean {\n const tag = el.tagName.toLowerCase();\n if (VISUAL_LEAF_TAGS.has(tag)) return false;\n if (hasVisualPresence(el)) return false;\n\n const { children } = el;\n if (children.length === 0) {\n return (el.textContent ?? \"\").trim().length === 0;\n }\n\n for (let i = 0; i < children.length; i += 1) {\n const child = children[i];\n if (!isHtmlElement(child)) continue;\n if (VISUAL_LEAF_TAGS.has(child.tagName.toLowerCase())) return false;\n if (isElementComputedVisible(child)) return false;\n }\n\n return true;\n}\n\nfunction hasRenderedBox(el: HTMLElement): boolean {\n const rect = el.getBoundingClientRect();\n if (rect.width <= 1 || rect.height <= 1) return false;\n if (!isElementComputedVisible(el)) return false;\n if (isEmptyVisualContainer(el)) return false;\n return true;\n}\n\n// ─── Visual scoring ──────────────────────────────────────────────────────────\n\n// ─── Layer patch target ──────────────────────────────────────────────────────\n\nconst DOM_LAYER_IGNORED_TAGS = new Set([\n \"base\",\n \"br\",\n \"canvas\",\n \"link\",\n \"meta\",\n \"script\",\n \"source\",\n \"style\",\n \"template\",\n \"track\",\n \"wbr\",\n]);\n\nfunction isInspectableLayerElement(el: HTMLElement): boolean {\n const tagName = el.tagName.toLowerCase();\n if (DOM_LAYER_IGNORED_TAGS.has(tagName)) return false;\n\n const computed = el.ownerDocument.defaultView?.getComputedStyle(el);\n if (computed?.display === \"none\" || computed?.visibility === \"hidden\") return false;\n\n return true;\n}\n\nexport function getDomLayerPatchTarget(\n el: HTMLElement,\n activeCompositionPath: string | null,\n): Pick<DomEditSelection, \"id\" | \"hfId\" | \"selector\" | \"selectorIndex\" | \"sourceFile\"> | null {\n if (!isInspectableLayerElement(el)) return null;\n if (el.hasAttribute(\"data-composition-id\")) return null;\n\n const selector = buildStableSelector(el);\n if (!selector) return null;\n\n const { sourceFile } = getSourceFileForElement(el, activeCompositionPath);\n return {\n id: el.id || undefined,\n hfId: el.getAttribute(\"data-hf-id\") || undefined,\n selector,\n selectorIndex: getSelectorIndex(\n el.ownerDocument,\n el,\n selector,\n sourceFile,\n activeCompositionPath,\n ),\n sourceFile,\n };\n}\n\n// ─── Clip ancestor / selection candidate ─────────────────────────────────────\n\nfunction getPreferredClipAncestor(startEl: HTMLElement): HTMLElement | null {\n let current: HTMLElement | null = startEl;\n while (current) {\n if (current.classList.contains(\"clip\")) {\n const isCompositionHost =\n current.hasAttribute(\"data-composition-src\") ||\n current.hasAttribute(\"data-composition-file\");\n if (!isCompositionHost || current === startEl) return current;\n }\n current = current.parentElement;\n }\n return null;\n}\n\nexport function getSelectionCandidate(\n startEl: HTMLElement,\n options: DomEditContextOptions,\n): HTMLElement {\n if (options.preferClipAncestor) {\n const clipAncestor = getPreferredClipAncestor(startEl);\n if (clipAncestor) {\n return clipAncestor;\n }\n }\n\n return startEl;\n}\n\n// ─── Visual target resolution ─────────────────────────────────────────────────\n\nexport function resolveVisualDomEditSelectionTarget(\n elementsFromPoint: Iterable<Element | null | undefined>,\n options: Pick<DomEditContextOptions, \"activeCompositionPath\">,\n): HTMLElement | null {\n const candidates = resolveAllVisualDomEditTargets(elementsFromPoint, options);\n return candidates[0] ?? null;\n}\n\n/**\n * Returns all independently-selectable elements at the given point, in paint\n * order (topmost first). Used for click-cycling through stacked layers.\n *\n * Each entry in the returned array is an independent \"layer\" — an element\n * that is not an ancestor of an earlier entry. This gives one result per\n * z-stacked element rather than one per DOM node.\n */\nexport function resolveAllVisualDomEditTargets(\n elementsFromPoint: Iterable<Element | null | undefined>,\n options: Pick<DomEditContextOptions, \"activeCompositionPath\">,\n): HTMLElement[] {\n const raw: HTMLElement[] = [];\n\n for (const entry of elementsFromPoint) {\n if (!isHtmlElement(entry)) continue;\n if (hasRenderedBox(entry) && getDomLayerPatchTarget(entry, options.activeCompositionPath)) {\n raw.push(entry);\n }\n }\n\n if (raw.length === 0) return [];\n\n // First pass: for each contiguous ancestor-descendant run, keep only the\n // deepest (most specific) element, matching the original single-pick logic.\n const layers: HTMLElement[] = [];\n let best = raw[0];\n for (let i = 1; i < raw.length; i++) {\n const el = raw[i];\n if (best.contains(el)) {\n best = el; // go deeper in this subtree\n } else {\n layers.push(best);\n best = el;\n }\n }\n layers.push(best);\n\n return layers;\n}\n\n// ─── Raster detection ────────────────────────────────────────────────────────\n\nfunction hasRasterBackground(selection: Pick<DomEditSelection, \"computedStyles\">): boolean {\n const backgroundImage = selection.computedStyles[\"background-image\"]?.trim();\n return Boolean(backgroundImage && backgroundImage !== \"none\");\n}\n\nexport function isLargeRasterDomEditSelection(\n selection: Pick<DomEditSelection, \"boundingBox\" | \"computedStyles\" | \"tagName\">,\n viewport?: DomEditViewport | null,\n): boolean {\n const tagName = selection.tagName.toLowerCase();\n const isRasterLike = tagName === \"img\" || hasRasterBackground(selection);\n if (!isRasterLike) return false;\n\n const { width, height } = selection.boundingBox;\n if (width <= 1 || height <= 1) return false;\n if (!viewport || viewport.width <= 1 || viewport.height <= 1) {\n return width >= 960 && height >= 540;\n }\n\n const areaRatio = (width * height) / (viewport.width * viewport.height);\n const widthRatio = width / viewport.width;\n const heightRatio = height / viewport.height;\n return areaRatio >= 0.4 || (widthRatio >= 0.7 && heightRatio >= 0.5);\n}\n\n// ─── Element finders ──────────────────────────────────────────────────────────\n\nexport function findElementForSelection(\n doc: Document,\n selection: Pick<DomEditSelection, \"id\" | \"hfId\" | \"selector\" | \"selectorIndex\" | \"sourceFile\">,\n activeCompositionPath: string | null = null,\n): HTMLElement | null {\n if (selection.hfId) {\n const byHfId = doc.querySelector(`[data-hf-id=\"${CSS.escape(selection.hfId)}\"]`);\n if (isHtmlElement(byHfId)) return byHfId;\n }\n\n if (selection.id) {\n const byId = doc.getElementById(selection.id);\n if (\n isHtmlElement(byId) &&\n (!selection.sourceFile ||\n getSourceFileForElement(byId, activeCompositionPath).sourceFile === selection.sourceFile)\n ) {\n return byId;\n }\n }\n\n if (!selection.selector) return null;\n\n if (selection.selector.startsWith(\".\") && selection.selectorIndex != null) {\n const matches = querySelectorAllSafely(doc, selection.selector).filter(\n (candidate): candidate is HTMLElement =>\n isHtmlElement(candidate) &&\n (!selection.sourceFile ||\n getSourceFileForElement(candidate, activeCompositionPath).sourceFile ===\n selection.sourceFile),\n );\n return matches[selection.selectorIndex] ?? null;\n }\n\n const matches = querySelectorAllSafely(doc, selection.selector).filter(\n (candidate): candidate is HTMLElement =>\n isHtmlElement(candidate) &&\n (!selection.sourceFile ||\n getSourceFileForElement(candidate, activeCompositionPath).sourceFile ===\n selection.sourceFile),\n );\n return matches[0] ?? null;\n}\n\n// fallow-ignore-next-line complexity\nexport function findElementForTimelineElement(\n doc: Document,\n element: TimelineElementDomTarget,\n options: TimelineElementDomTargetOptions,\n): HTMLElement | null {\n const elementId = typeof element.id === \"string\" ? element.id : \"\";\n const compositionSource =\n normalizeTimelineCompositionSource(element.compositionSrc) ??\n options.compIdToSrc?.get(elementId);\n const sourceFile =\n compositionSource ??\n normalizeTimelineCompositionSource(element.sourceFile) ??\n options.activeCompositionPath ??\n \"index.html\";\n const escapedElementId = escapeCssString(elementId);\n const escapedCompositionSource = compositionSource ? escapeCssString(compositionSource) : null;\n const selector =\n element.selector ??\n (compositionSource\n ? `[data-composition-src=\"${escapedCompositionSource}\"],[data-composition-file=\"${escapedCompositionSource}\"],[data-composition-id=\"${escapedElementId}\"]`\n : escapedElementId\n ? `[data-composition-id=\"${escapedElementId}\"]`\n : undefined);\n\n if (selector || element.domId) {\n const targetElement = findElementForSelection(\n doc,\n {\n id: element.domId ?? undefined,\n selector,\n selectorIndex: element.selectorIndex,\n sourceFile,\n },\n options.activeCompositionPath,\n );\n if (targetElement) return targetElement;\n }\n\n const hasExplicitDomTarget = Boolean(element.domId || element.selector || compositionSource);\n if (options.isMasterView || hasExplicitDomTarget || !options.activeCompositionPath) {\n return null;\n }\n\n const root = doc.querySelector(\"[data-composition-id]\");\n if (!isHtmlElement(root)) return null;\n return getSourceFileForElement(root, options.activeCompositionPath).sourceFile === sourceFile\n ? root\n : null;\n}\n\n// ─── Layer children ───────────────────────────────────────────────────────────\n\nexport function getDirectLayerChildren(\n el: HTMLElement,\n options: DomEditContextOptions,\n): HTMLElement[] {\n return Array.from(el.children).filter(\n (child): child is HTMLElement =>\n isHtmlElement(child) && getDomLayerPatchTarget(child, options.activeCompositionPath) !== null,\n );\n}\n","import { parsePx } from \"./domEditingDom\";\n\nconst COMPOSITION_ROOT_LAYER_EPSILON_PX = 1;\n\nfunction readPositiveDimension(value: string | null): number | null {\n if (!value) return null;\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\n\nfunction approximatelyEqual(a: number, b: number) {\n return Math.abs(a - b) <= COMPOSITION_ROOT_LAYER_EPSILON_PX;\n}\n\nfunction getCompositionRootBounds(doc: Document) {\n const root =\n doc.querySelector<HTMLElement>(\"[data-composition-id]\") ?? doc.documentElement ?? null;\n const rootWidth = readPositiveDimension(root?.getAttribute(\"data-width\") ?? null);\n const rootHeight = readPositiveDimension(root?.getAttribute(\"data-height\") ?? null);\n if (!root || !rootWidth || !rootHeight) return null;\n return { rect: root.getBoundingClientRect(), width: rootWidth, height: rootHeight };\n}\n\nfunction getRenderedLayerSize(element: HTMLElement, computedStyles: Record<string, string>) {\n const rect = element.getBoundingClientRect();\n const width = rect.width || parsePx(computedStyles.width);\n const height = rect.height || parsePx(computedStyles.height);\n return width && height ? { width, height } : null;\n}\n\nfunction matchesCompositionRootBounds(\n elementRect: DOMRect,\n elementSize: { width: number; height: number },\n rootBounds: { rect: DOMRect; width: number; height: number },\n) {\n return (\n approximatelyEqual(elementRect.left, rootBounds.rect.left) &&\n approximatelyEqual(elementRect.top, rootBounds.rect.top) &&\n approximatelyEqual(elementSize.width, rootBounds.width) &&\n approximatelyEqual(elementSize.height, rootBounds.height)\n );\n}\n\nfunction isExplicitFullBleedLayer(computedStyles: Record<string, string>) {\n return computedStyles.position === \"absolute\" || computedStyles.position === \"fixed\";\n}\n\nexport function isCompositionRootLayer(\n element: HTMLElement,\n doc: Document,\n computedStyles: Record<string, string>,\n) {\n if (element.parentElement !== doc.body) return false;\n if (element.hasAttribute(\"data-hf-allow-root-edit\")) return false;\n if (isExplicitFullBleedLayer(computedStyles)) return false;\n\n const rootBounds = getCompositionRootBounds(doc);\n const elementSize = getRenderedLayerSize(element, computedStyles);\n return Boolean(\n rootBounds &&\n elementSize &&\n matchesCompositionRootBounds(element.getBoundingClientRect(), elementSize, rootBounds),\n );\n}\n"],"mappings":"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","names":["matches"]}