@craftile/preview-client 1.1.1 → 1.2.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.
package/dist/index.cjs CHANGED
@@ -147,6 +147,7 @@ class Inspector {
147
147
  __publicField(this, "resizeObserver", null);
148
148
  __publicField(this, "mutationObserver", null);
149
149
  __publicField(this, "transitionCleanupFunctions", []);
150
+ __publicField(this, "pendingViewportResizeFrame", null);
150
151
  this.messenger = messenger;
151
152
  this.events = events;
152
153
  this.messenger.listen("craftile.inspector.enable", () => this.enable());
@@ -156,6 +157,7 @@ class Inspector {
156
157
  this.messenger.listen("craftile.editor.select-block", this.handleEditorSelectBlock.bind(this));
157
158
  this.messenger.listen("craftile.editor.deselect-block", this.handleEditorDeselectBlock.bind(this));
158
159
  window.addEventListener("scroll", this.handleScroll.bind(this), { passive: true });
160
+ window.addEventListener("resize", this.handleViewportResize.bind(this), { passive: true });
159
161
  this.setupGlobalEventListeners();
160
162
  }
161
163
  /**
@@ -232,6 +234,25 @@ class Inspector {
232
234
  }
233
235
  }
234
236
  handleScroll() {
237
+ this.refreshTrackedBlockPositions();
238
+ }
239
+ /**
240
+ * The iframe viewport resizes whenever the editor layout changes around it
241
+ * (e.g. the configuration panel opening). A block can move without its own
242
+ * box changing size, which the ResizeObserver would not catch, so re-measure
243
+ * on the next frame. Resize events arrive once per frame during layout
244
+ * transitions, so coalesce them into a single pending frame.
245
+ */
246
+ handleViewportResize() {
247
+ if (!this.active || this.pendingViewportResizeFrame !== null) {
248
+ return;
249
+ }
250
+ this.pendingViewportResizeFrame = requestAnimationFrame(() => {
251
+ this.pendingViewportResizeFrame = null;
252
+ this.refreshTrackedBlockPositions();
253
+ });
254
+ }
255
+ refreshTrackedBlockPositions() {
235
256
  if (!this.active) {
236
257
  return;
237
258
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../messenger/src/index.ts","../../event-bus/src/index.ts","../src/inspector.ts","../src/client.ts"],"sourcesContent":["export interface TypedMessage<T = any> {\n type: string;\n payload: T | undefined;\n}\n\nexport class WindowMessenger<Messages extends Record<string, any>> {\n private handlers = new Map<keyof Messages, Function[]>();\n private targetWindow: Window;\n private targetOrigin: string;\n private fallbackHandler?: (data: any, event: MessageEvent) => void;\n\n constructor(targetWindow: Window, targetOrigin: string = '*') {\n this.targetWindow = targetWindow;\n this.targetOrigin = targetOrigin;\n\n window.addEventListener('message', this.handleMessage.bind(this));\n }\n\n private handleMessage(event: MessageEvent) {\n const message = event.data as TypedMessage;\n\n if (!message.type) {\n return;\n }\n\n const handlers = this.handlers.get(message.type);\n\n if (handlers) {\n handlers.forEach((handler) => handler(message.payload, event));\n } else if (this.fallbackHandler) {\n this.fallbackHandler(event.data, event);\n }\n }\n\n send<K extends keyof Messages>(type: K, payload?: Messages[K]): void {\n const message: TypedMessage<Messages[K]> = { type: type as string, payload };\n this.targetWindow.postMessage(message, this.targetOrigin);\n }\n\n listen<K extends keyof Messages>(type: K, handler: (data: Messages[K], event: MessageEvent) => void): () => void {\n if (!this.handlers.has(type)) {\n this.handlers.set(type, []);\n }\n\n this.handlers.get(type)!.push(handler);\n\n return () => {\n const handlers = this.handlers.get(type);\n if (handlers) {\n const index = handlers.indexOf(handler);\n if (index > -1) {\n handlers.splice(index, 1);\n }\n }\n };\n }\n\n registerFallbackHandler(handler: (data: any, event: MessageEvent) => void) {\n this.fallbackHandler = handler;\n }\n}\n\nexport function createIframeMessenger<T extends Record<string, any>>(iframe: HTMLIFrameElement, targetOrigin = '*') {\n return new WindowMessenger<T>(iframe.contentWindow!, targetOrigin);\n}\n\nexport function createParentMessenger<T extends Record<string, any>>(targetOrigin = '*') {\n if (window.parent === window) {\n throw new Error('Not inside an iframe');\n }\n return new WindowMessenger<T>(window.parent, targetOrigin);\n}\n","export type EventListener<T = any> = (data: T) => void;\nexport type EventMap = {\n [event: string]: any;\n};\n\n/**\n * Type-safe EventBus with generic event map support\n *\n * @template T Event map interface that defines the events and their data types\n */\nexport class EventBus<T extends EventMap = EventMap> {\n private listeners: Map<keyof T, Set<EventListener<any>>> = new Map();\n\n /**\n * Add an event listener\n *\n * @param event Event name\n * @param listener Event listener function\n *\n * @returns Cleanup function to remove the listener\n */\n on<K extends keyof T>(event: K, listener: EventListener<T[K]>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n this.listeners.get(event)!.add(listener);\n\n return () => {\n this.off(event, listener);\n };\n }\n\n /**\n * Remove an event listener\n *\n * @param event Event name\n * @param listener Event listener function to remove\n */\n off<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n eventListeners.delete(listener);\n\n if (eventListeners.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Add a one-time event listener\n *\n * @param event Event name\n * @param listener Event listener function\n */\n once<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const onceWrapper = (data: T[K]) => {\n listener(data);\n this.off(event, onceWrapper);\n };\n\n this.on(event, onceWrapper);\n }\n\n /**\n * Emit an event\n *\n * @param event Event name\n * @param args Event data (optional, depending on event type)\n */\n emit<K extends keyof T>(event: K, ...args: T[K] extends void ? [] : [T[K]]): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n const data = args[0];\n eventListeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`Error in event listener for '${String(event)}':`, error);\n }\n });\n }\n }\n\n /**\n * Remove all listeners for an event, or all listeners if no event specified\n *\n * @param event Optional event name. If not provided, removes all listeners\n */\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n","import type { WindowMessenger } from '@craftile/messenger';\nimport type { Block, WindowMessages } from '@craftile/types';\nimport type { PreviewClientEvents } from './client';\n\ninterface PreviewClientEventsEmitter {\n emit<K extends keyof PreviewClientEvents>(\n event: K,\n ...args: PreviewClientEvents[K] extends void ? [] : [PreviewClientEvents[K]]\n ): void;\n getBlock(blockId: string): Block | undefined;\n}\n\nexport class Inspector {\n private active = true;\n private messenger: WindowMessenger<WindowMessages>;\n private events: PreviewClientEventsEmitter;\n private currentHoveredBlock: HTMLElement | null = null;\n private currentSelectedBlock: HTMLElement | null = null;\n private overlayButtonHovered = false;\n\n private resizeObserver: ResizeObserver | null = null;\n private mutationObserver: MutationObserver | null = null;\n private transitionCleanupFunctions: (() => void)[] = [];\n\n constructor(\n messenger: WindowMessenger<WindowMessages>,\n events: PreviewClientEventsEmitter = { emit: () => {}, getBlock: () => undefined }\n ) {\n this.messenger = messenger;\n this.events = events;\n\n this.messenger.listen('craftile.inspector.enable', () => this.enable());\n this.messenger.listen('craftile.inspector.disable', () => this.disable());\n this.messenger.listen('craftile.inspector.overlay-button-enter', this.handleOverlayButtonEnter.bind(this));\n this.messenger.listen('craftile.inspector.overlay-button-leave', this.handleOverlayButtonLeave.bind(this));\n this.messenger.listen('craftile.editor.select-block', this.handleEditorSelectBlock.bind(this));\n this.messenger.listen('craftile.editor.deselect-block', this.handleEditorDeselectBlock.bind(this));\n\n window.addEventListener('scroll', this.handleScroll.bind(this), { passive: true });\n this.setupGlobalEventListeners();\n }\n\n /**\n * Update the tracked element reference when a block's DOM element changes.\n * This is needed when the root tag of a block changes during an update.\n */\n updateTrackedElement(blockId: string, newElement: HTMLElement): void {\n // Update hovered block if it matches\n if (this.currentHoveredBlock?.dataset.block === blockId) {\n this.currentHoveredBlock = newElement;\n this.sendHoveredBlockPosition();\n }\n\n // Update selected block if it matches and re-track it\n if (this.currentSelectedBlock?.dataset.block === blockId) {\n this.currentSelectedBlock = newElement;\n requestAnimationFrame(() => {\n this.sendSelectedBlockPosition(true);\n });\n this.trackSelectedBlock();\n }\n }\n\n enable() {\n this.active = true;\n document.body.classList.add('craftile-inspector-active');\n\n // Re-track selected block if it exists\n if (this.currentSelectedBlock) {\n this.trackSelectedBlock();\n }\n }\n\n disable() {\n this.active = false;\n document.body.classList.remove('craftile-inspector-active');\n this.currentHoveredBlock = null;\n this.overlayButtonHovered = false;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n }\n\n private handleOverlayButtonEnter() {\n this.overlayButtonHovered = true;\n }\n\n private handleOverlayButtonLeave(_data: { blockId: string }) {\n this.overlayButtonHovered = false;\n\n if (!this.currentHoveredBlock) {\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleEditorSelectBlock(data: { blockId: string }) {\n const element = document.querySelector(`[data-block=\"${data.blockId}\"]`) as HTMLElement;\n\n if (element) {\n this.setSelectedBlock(element);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });\n }\n }\n\n private handleEditorDeselectBlock() {\n const selectedBlock = this.currentSelectedBlock;\n this.currentSelectedBlock = null;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n if (selectedBlock?.dataset.block) {\n this.emitBlockDeselect(selectedBlock.dataset.block, selectedBlock);\n }\n }\n\n private handleScroll() {\n if (!this.active) {\n return;\n }\n\n if (this.currentSelectedBlock) {\n this.sendSelectedBlockPosition();\n }\n\n if (this.currentHoveredBlock) {\n this.sendHoveredBlockPosition();\n }\n }\n\n private setupGlobalEventListeners() {\n document.addEventListener('mouseover', this.handleGlobalHover.bind(this));\n document.addEventListener('mouseout', this.handleGlobalLeave.bind(this));\n document.addEventListener('click', this.handleGlobalClick.bind(this), { capture: true });\n }\n\n private handleGlobalHover(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n\n if (!blockElement) {\n return;\n }\n\n e.stopPropagation();\n this.currentHoveredBlock = blockElement;\n this.sendHoveredBlockPosition();\n }\n\n private handleGlobalLeave(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n // Only clear overlay if button is not being hovered\n if (!this.overlayButtonHovered) {\n this.currentHoveredBlock = null;\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleGlobalClick(e: Event) {\n this.messenger.send('craftile.preview.click');\n\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n const blockId = blockElement.getAttribute('data-block');\n if (!blockId) {\n return;\n }\n\n const isAlreadySelected = this.currentSelectedBlock === blockElement;\n\n if (!isAlreadySelected) {\n e.preventDefault();\n e.stopImmediatePropagation();\n\n this.setSelectedBlock(blockElement);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n }\n }\n\n private setSelectedBlock(element: HTMLElement): void {\n const previousBlock = this.currentSelectedBlock;\n\n if (previousBlock === element) {\n return;\n }\n\n if (previousBlock?.dataset.block) {\n this.emitBlockDeselect(previousBlock.dataset.block, previousBlock);\n }\n\n this.currentSelectedBlock = element;\n\n if (element.dataset.block) {\n this.emitBlockSelect(element.dataset.block, element);\n }\n }\n\n private createBlockEventPayload(blockId: string, element: HTMLElement) {\n const block = this.events.getBlock(blockId);\n\n return {\n blockId,\n ...(block\n ? {\n block,\n blockType: block.type,\n }\n : {}),\n element,\n };\n }\n\n private emitBlockSelect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.select', this.createBlockEventPayload(blockId, element));\n }\n\n private emitBlockDeselect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.deselect', this.createBlockEventPayload(blockId, element));\n }\n\n private sendHoveredBlockPosition() {\n const position = this.computeElementPositioning(this.currentHoveredBlock!);\n\n this.messenger.send('craftile.preview.block-hover', {\n blockRect: position.rect,\n parentRect: position.parentRect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentHoveredBlock!.dataset.block as string,\n parentFlexDirection: position.parentFlexDirection,\n });\n }\n\n private sendSelectedBlockPosition(updates: boolean = false) {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const position = this.computeElementPositioning(this.currentSelectedBlock!);\n this.messenger.send(updates ? 'craftile.preview.update-selected-block' : 'craftile.preview.block-select', {\n blockRect: position.rect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentSelectedBlock!.dataset.block as string,\n });\n }\n\n private trackSelectedBlock() {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n this.resizeObserver = new ResizeObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n this.resizeObserver.observe(this.currentSelectedBlock);\n\n this.mutationObserver = new MutationObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n\n this.mutationObserver.observe(this.currentSelectedBlock, {\n attributes: true,\n subtree: false,\n });\n\n // Also observe parent elements that might affect positioning\n let parent = this.currentSelectedBlock.parentElement;\n while (parent) {\n this.mutationObserver.observe(parent, {\n childList: true,\n subtree: false,\n });\n\n if (parent === document.body) {\n break;\n }\n\n parent = parent.parentElement;\n }\n\n this.trackSelectedBlockTransitions();\n }\n\n private clearTransitionListeners(): void {\n this.transitionCleanupFunctions.forEach((cleanup) => cleanup());\n this.transitionCleanupFunctions = [];\n }\n\n private trackSelectedBlockTransitions(): void {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const updatePosition = () => {\n if (!this.active || !this.currentSelectedBlock?.isConnected) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (this.active && this.currentSelectedBlock?.isConnected) {\n this.sendSelectedBlockPosition(true);\n }\n });\n };\n\n let element: HTMLElement | null = this.currentSelectedBlock;\n while (element) {\n const trackedElement: HTMLElement = element;\n const handleTransitionComplete = (event: Event) => {\n if (event.target !== trackedElement) {\n return;\n }\n\n updatePosition();\n };\n\n trackedElement.addEventListener('transitionend', handleTransitionComplete);\n trackedElement.addEventListener('transitioncancel', handleTransitionComplete);\n\n this.transitionCleanupFunctions.push(() => {\n trackedElement.removeEventListener('transitionend', handleTransitionComplete);\n trackedElement.removeEventListener('transitioncancel', handleTransitionComplete);\n });\n\n if (trackedElement === document.body) {\n break;\n }\n\n element = trackedElement.parentElement;\n }\n }\n\n private computeElementPositioning(element: HTMLElement) {\n const rect = element.getBoundingClientRect();\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;\n\n const eldestParent = this.findEldestParentBlock(element);\n const parentRect = eldestParent && eldestParent !== element ? eldestParent.getBoundingClientRect() : undefined;\n const parentFlexDirection = this.getElementFlexDirection(element.parentElement);\n\n return {\n rect,\n parentRect,\n scrollTop,\n scrollLeft,\n parentFlexDirection,\n };\n }\n\n private findEldestParentBlock(element: HTMLElement): HTMLElement | null {\n let eldestParent: HTMLElement | null = null;\n let parentElement = element.parentElement;\n\n while (parentElement && parentElement !== document.body) {\n if (parentElement.hasAttribute('data-block')) {\n eldestParent = parentElement;\n }\n parentElement = parentElement.parentElement;\n }\n\n return eldestParent;\n }\n\n private getElementFlexDirection(element: HTMLElement | null): 'row' | 'column' {\n if (!element) {\n return 'column';\n }\n\n const style = window.getComputedStyle(element);\n const flexDirection = style.display.includes('flex') ? style.flexDirection : 'column';\n\n return flexDirection === 'row' || flexDirection === 'row-reverse' ? 'row' : 'column';\n }\n}\n","import type { Block, WindowMessages } from '@craftile/types';\nimport { createParentMessenger, WindowMessenger } from '@craftile/messenger';\nimport { EventBus } from '@craftile/event-bus';\nimport { Inspector } from './inspector';\n\nexport interface PreviewClientEvents extends WindowMessages {\n [event: string]: any;\n\n 'block.select': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n\n 'block.deselect': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n}\n\nexport class PreviewClient extends EventBus<PreviewClientEvents> {\n private messenger: WindowMessenger<WindowMessages>;\n private blocks = new Map<string, Block>();\n public inspector: Inspector;\n\n constructor() {\n super();\n\n this.messenger = createParentMessenger(window.origin);\n this.inspector = new Inspector(this.messenger, this);\n\n this.initialize();\n }\n\n private initialize() {\n window.addEventListener('load', () => {\n this.messenger.send('craftile.preview.ready', {});\n setTimeout(() => {\n this.sendPageData();\n }, 0);\n });\n\n this.messenger.listen('craftile.editor.updates', (payload) => {\n this.updateBlocks(payload);\n this.emit('craftile.editor.updates', payload);\n });\n\n this.messenger.registerFallbackHandler((data: any) => {\n const { type, payload } = data;\n this.emit(type, payload);\n });\n }\n\n getBlock(blockId: string): Block | undefined {\n return this.blocks.get(blockId);\n }\n\n private updateBlocks(updates: WindowMessages['craftile.editor.updates']): void {\n for (const [blockId, block] of Object.entries(updates.blocks)) {\n this.blocks.set(blockId, block);\n }\n\n for (const blockId of updates.changes.removed) {\n this.blocks.delete(blockId);\n }\n }\n\n private sendPageData() {\n const pageDataElement = document.getElementById('page-data');\n\n if (!pageDataElement) {\n return;\n }\n\n try {\n const pageData = JSON.parse(pageDataElement.textContent || '{}');\n this.blocks.clear();\n\n for (const [blockId, block] of Object.entries(pageData.content.blocks || {}) as [string, Block][]) {\n this.blocks.set(blockId, block);\n }\n\n this.messenger.send('craftile.preview.page-data', { pageData });\n } catch (error) {\n console.error('Failed to parse page data:', error);\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../messenger/src/index.ts","../../event-bus/src/index.ts","../src/inspector.ts","../src/client.ts"],"sourcesContent":["export interface TypedMessage<T = any> {\n type: string;\n payload: T | undefined;\n}\n\nexport class WindowMessenger<Messages extends Record<string, any>> {\n private handlers = new Map<keyof Messages, Function[]>();\n private targetWindow: Window;\n private targetOrigin: string;\n private fallbackHandler?: (data: any, event: MessageEvent) => void;\n\n constructor(targetWindow: Window, targetOrigin: string = '*') {\n this.targetWindow = targetWindow;\n this.targetOrigin = targetOrigin;\n\n window.addEventListener('message', this.handleMessage.bind(this));\n }\n\n private handleMessage(event: MessageEvent) {\n const message = event.data as TypedMessage;\n\n if (!message.type) {\n return;\n }\n\n const handlers = this.handlers.get(message.type);\n\n if (handlers) {\n handlers.forEach((handler) => handler(message.payload, event));\n } else if (this.fallbackHandler) {\n this.fallbackHandler(event.data, event);\n }\n }\n\n send<K extends keyof Messages>(type: K, payload?: Messages[K]): void {\n const message: TypedMessage<Messages[K]> = { type: type as string, payload };\n this.targetWindow.postMessage(message, this.targetOrigin);\n }\n\n listen<K extends keyof Messages>(type: K, handler: (data: Messages[K], event: MessageEvent) => void): () => void {\n if (!this.handlers.has(type)) {\n this.handlers.set(type, []);\n }\n\n this.handlers.get(type)!.push(handler);\n\n return () => {\n const handlers = this.handlers.get(type);\n if (handlers) {\n const index = handlers.indexOf(handler);\n if (index > -1) {\n handlers.splice(index, 1);\n }\n }\n };\n }\n\n registerFallbackHandler(handler: (data: any, event: MessageEvent) => void) {\n this.fallbackHandler = handler;\n }\n}\n\nexport function createIframeMessenger<T extends Record<string, any>>(iframe: HTMLIFrameElement, targetOrigin = '*') {\n return new WindowMessenger<T>(iframe.contentWindow!, targetOrigin);\n}\n\nexport function createParentMessenger<T extends Record<string, any>>(targetOrigin = '*') {\n if (window.parent === window) {\n throw new Error('Not inside an iframe');\n }\n return new WindowMessenger<T>(window.parent, targetOrigin);\n}\n","export type EventListener<T = any> = (data: T) => void;\nexport type EventMap = {\n [event: string]: any;\n};\n\n/**\n * Type-safe EventBus with generic event map support\n *\n * @template T Event map interface that defines the events and their data types\n */\nexport class EventBus<T extends EventMap = EventMap> {\n private listeners: Map<keyof T, Set<EventListener<any>>> = new Map();\n\n /**\n * Add an event listener\n *\n * @param event Event name\n * @param listener Event listener function\n *\n * @returns Cleanup function to remove the listener\n */\n on<K extends keyof T>(event: K, listener: EventListener<T[K]>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n this.listeners.get(event)!.add(listener);\n\n return () => {\n this.off(event, listener);\n };\n }\n\n /**\n * Remove an event listener\n *\n * @param event Event name\n * @param listener Event listener function to remove\n */\n off<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n eventListeners.delete(listener);\n\n if (eventListeners.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Add a one-time event listener\n *\n * @param event Event name\n * @param listener Event listener function\n */\n once<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const onceWrapper = (data: T[K]) => {\n listener(data);\n this.off(event, onceWrapper);\n };\n\n this.on(event, onceWrapper);\n }\n\n /**\n * Emit an event\n *\n * @param event Event name\n * @param args Event data (optional, depending on event type)\n */\n emit<K extends keyof T>(event: K, ...args: T[K] extends void ? [] : [T[K]]): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n const data = args[0];\n eventListeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`Error in event listener for '${String(event)}':`, error);\n }\n });\n }\n }\n\n /**\n * Remove all listeners for an event, or all listeners if no event specified\n *\n * @param event Optional event name. If not provided, removes all listeners\n */\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n","import type { WindowMessenger } from '@craftile/messenger';\nimport type { Block, WindowMessages } from '@craftile/types';\nimport type { PreviewClientEvents } from './client';\n\ninterface PreviewClientEventsEmitter {\n emit<K extends keyof PreviewClientEvents>(\n event: K,\n ...args: PreviewClientEvents[K] extends void ? [] : [PreviewClientEvents[K]]\n ): void;\n getBlock(blockId: string): Block | undefined;\n}\n\nexport class Inspector {\n private active = true;\n private messenger: WindowMessenger<WindowMessages>;\n private events: PreviewClientEventsEmitter;\n private currentHoveredBlock: HTMLElement | null = null;\n private currentSelectedBlock: HTMLElement | null = null;\n private overlayButtonHovered = false;\n\n private resizeObserver: ResizeObserver | null = null;\n private mutationObserver: MutationObserver | null = null;\n private transitionCleanupFunctions: (() => void)[] = [];\n private pendingViewportResizeFrame: number | null = null;\n\n constructor(\n messenger: WindowMessenger<WindowMessages>,\n events: PreviewClientEventsEmitter = { emit: () => {}, getBlock: () => undefined }\n ) {\n this.messenger = messenger;\n this.events = events;\n\n this.messenger.listen('craftile.inspector.enable', () => this.enable());\n this.messenger.listen('craftile.inspector.disable', () => this.disable());\n this.messenger.listen('craftile.inspector.overlay-button-enter', this.handleOverlayButtonEnter.bind(this));\n this.messenger.listen('craftile.inspector.overlay-button-leave', this.handleOverlayButtonLeave.bind(this));\n this.messenger.listen('craftile.editor.select-block', this.handleEditorSelectBlock.bind(this));\n this.messenger.listen('craftile.editor.deselect-block', this.handleEditorDeselectBlock.bind(this));\n\n window.addEventListener('scroll', this.handleScroll.bind(this), { passive: true });\n window.addEventListener('resize', this.handleViewportResize.bind(this), { passive: true });\n this.setupGlobalEventListeners();\n }\n\n /**\n * Update the tracked element reference when a block's DOM element changes.\n * This is needed when the root tag of a block changes during an update.\n */\n updateTrackedElement(blockId: string, newElement: HTMLElement): void {\n // Update hovered block if it matches\n if (this.currentHoveredBlock?.dataset.block === blockId) {\n this.currentHoveredBlock = newElement;\n this.sendHoveredBlockPosition();\n }\n\n // Update selected block if it matches and re-track it\n if (this.currentSelectedBlock?.dataset.block === blockId) {\n this.currentSelectedBlock = newElement;\n requestAnimationFrame(() => {\n this.sendSelectedBlockPosition(true);\n });\n this.trackSelectedBlock();\n }\n }\n\n enable() {\n this.active = true;\n document.body.classList.add('craftile-inspector-active');\n\n // Re-track selected block if it exists\n if (this.currentSelectedBlock) {\n this.trackSelectedBlock();\n }\n }\n\n disable() {\n this.active = false;\n document.body.classList.remove('craftile-inspector-active');\n this.currentHoveredBlock = null;\n this.overlayButtonHovered = false;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n }\n\n private handleOverlayButtonEnter() {\n this.overlayButtonHovered = true;\n }\n\n private handleOverlayButtonLeave(_data: { blockId: string }) {\n this.overlayButtonHovered = false;\n\n if (!this.currentHoveredBlock) {\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleEditorSelectBlock(data: { blockId: string }) {\n const element = document.querySelector(`[data-block=\"${data.blockId}\"]`) as HTMLElement;\n\n if (element) {\n this.setSelectedBlock(element);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });\n }\n }\n\n private handleEditorDeselectBlock() {\n const selectedBlock = this.currentSelectedBlock;\n this.currentSelectedBlock = null;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n if (selectedBlock?.dataset.block) {\n this.emitBlockDeselect(selectedBlock.dataset.block, selectedBlock);\n }\n }\n\n private handleScroll() {\n this.refreshTrackedBlockPositions();\n }\n\n /**\n * The iframe viewport resizes whenever the editor layout changes around it\n * (e.g. the configuration panel opening). A block can move without its own\n * box changing size, which the ResizeObserver would not catch, so re-measure\n * on the next frame. Resize events arrive once per frame during layout\n * transitions, so coalesce them into a single pending frame.\n */\n private handleViewportResize() {\n if (!this.active || this.pendingViewportResizeFrame !== null) {\n return;\n }\n\n this.pendingViewportResizeFrame = requestAnimationFrame(() => {\n this.pendingViewportResizeFrame = null;\n this.refreshTrackedBlockPositions();\n });\n }\n\n private refreshTrackedBlockPositions() {\n if (!this.active) {\n return;\n }\n\n if (this.currentSelectedBlock) {\n this.sendSelectedBlockPosition();\n }\n\n if (this.currentHoveredBlock) {\n this.sendHoveredBlockPosition();\n }\n }\n\n private setupGlobalEventListeners() {\n document.addEventListener('mouseover', this.handleGlobalHover.bind(this));\n document.addEventListener('mouseout', this.handleGlobalLeave.bind(this));\n document.addEventListener('click', this.handleGlobalClick.bind(this), { capture: true });\n }\n\n private handleGlobalHover(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n\n if (!blockElement) {\n return;\n }\n\n e.stopPropagation();\n this.currentHoveredBlock = blockElement;\n this.sendHoveredBlockPosition();\n }\n\n private handleGlobalLeave(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n // Only clear overlay if button is not being hovered\n if (!this.overlayButtonHovered) {\n this.currentHoveredBlock = null;\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleGlobalClick(e: Event) {\n this.messenger.send('craftile.preview.click');\n\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n const blockId = blockElement.getAttribute('data-block');\n if (!blockId) {\n return;\n }\n\n const isAlreadySelected = this.currentSelectedBlock === blockElement;\n\n if (!isAlreadySelected) {\n e.preventDefault();\n e.stopImmediatePropagation();\n\n this.setSelectedBlock(blockElement);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n }\n }\n\n private setSelectedBlock(element: HTMLElement): void {\n const previousBlock = this.currentSelectedBlock;\n\n if (previousBlock === element) {\n return;\n }\n\n if (previousBlock?.dataset.block) {\n this.emitBlockDeselect(previousBlock.dataset.block, previousBlock);\n }\n\n this.currentSelectedBlock = element;\n\n if (element.dataset.block) {\n this.emitBlockSelect(element.dataset.block, element);\n }\n }\n\n private createBlockEventPayload(blockId: string, element: HTMLElement) {\n const block = this.events.getBlock(blockId);\n\n return {\n blockId,\n ...(block\n ? {\n block,\n blockType: block.type,\n }\n : {}),\n element,\n };\n }\n\n private emitBlockSelect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.select', this.createBlockEventPayload(blockId, element));\n }\n\n private emitBlockDeselect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.deselect', this.createBlockEventPayload(blockId, element));\n }\n\n private sendHoveredBlockPosition() {\n const position = this.computeElementPositioning(this.currentHoveredBlock!);\n\n this.messenger.send('craftile.preview.block-hover', {\n blockRect: position.rect,\n parentRect: position.parentRect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentHoveredBlock!.dataset.block as string,\n parentFlexDirection: position.parentFlexDirection,\n });\n }\n\n private sendSelectedBlockPosition(updates: boolean = false) {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const position = this.computeElementPositioning(this.currentSelectedBlock!);\n this.messenger.send(updates ? 'craftile.preview.update-selected-block' : 'craftile.preview.block-select', {\n blockRect: position.rect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentSelectedBlock!.dataset.block as string,\n });\n }\n\n private trackSelectedBlock() {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n this.resizeObserver = new ResizeObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n this.resizeObserver.observe(this.currentSelectedBlock);\n\n this.mutationObserver = new MutationObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n\n this.mutationObserver.observe(this.currentSelectedBlock, {\n attributes: true,\n subtree: false,\n });\n\n // Also observe parent elements that might affect positioning\n let parent = this.currentSelectedBlock.parentElement;\n while (parent) {\n this.mutationObserver.observe(parent, {\n childList: true,\n subtree: false,\n });\n\n if (parent === document.body) {\n break;\n }\n\n parent = parent.parentElement;\n }\n\n this.trackSelectedBlockTransitions();\n }\n\n private clearTransitionListeners(): void {\n this.transitionCleanupFunctions.forEach((cleanup) => cleanup());\n this.transitionCleanupFunctions = [];\n }\n\n private trackSelectedBlockTransitions(): void {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const updatePosition = () => {\n if (!this.active || !this.currentSelectedBlock?.isConnected) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (this.active && this.currentSelectedBlock?.isConnected) {\n this.sendSelectedBlockPosition(true);\n }\n });\n };\n\n let element: HTMLElement | null = this.currentSelectedBlock;\n while (element) {\n const trackedElement: HTMLElement = element;\n const handleTransitionComplete = (event: Event) => {\n if (event.target !== trackedElement) {\n return;\n }\n\n updatePosition();\n };\n\n trackedElement.addEventListener('transitionend', handleTransitionComplete);\n trackedElement.addEventListener('transitioncancel', handleTransitionComplete);\n\n this.transitionCleanupFunctions.push(() => {\n trackedElement.removeEventListener('transitionend', handleTransitionComplete);\n trackedElement.removeEventListener('transitioncancel', handleTransitionComplete);\n });\n\n if (trackedElement === document.body) {\n break;\n }\n\n element = trackedElement.parentElement;\n }\n }\n\n private computeElementPositioning(element: HTMLElement) {\n const rect = element.getBoundingClientRect();\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;\n\n const eldestParent = this.findEldestParentBlock(element);\n const parentRect = eldestParent && eldestParent !== element ? eldestParent.getBoundingClientRect() : undefined;\n const parentFlexDirection = this.getElementFlexDirection(element.parentElement);\n\n return {\n rect,\n parentRect,\n scrollTop,\n scrollLeft,\n parentFlexDirection,\n };\n }\n\n private findEldestParentBlock(element: HTMLElement): HTMLElement | null {\n let eldestParent: HTMLElement | null = null;\n let parentElement = element.parentElement;\n\n while (parentElement && parentElement !== document.body) {\n if (parentElement.hasAttribute('data-block')) {\n eldestParent = parentElement;\n }\n parentElement = parentElement.parentElement;\n }\n\n return eldestParent;\n }\n\n private getElementFlexDirection(element: HTMLElement | null): 'row' | 'column' {\n if (!element) {\n return 'column';\n }\n\n const style = window.getComputedStyle(element);\n const flexDirection = style.display.includes('flex') ? style.flexDirection : 'column';\n\n return flexDirection === 'row' || flexDirection === 'row-reverse' ? 'row' : 'column';\n }\n}\n","import type { Block, WindowMessages } from '@craftile/types';\nimport { createParentMessenger, WindowMessenger } from '@craftile/messenger';\nimport { EventBus } from '@craftile/event-bus';\nimport { Inspector } from './inspector';\n\nexport interface PreviewClientEvents extends WindowMessages {\n [event: string]: any;\n\n 'block.select': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n\n 'block.deselect': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n}\n\nexport class PreviewClient extends EventBus<PreviewClientEvents> {\n private messenger: WindowMessenger<WindowMessages>;\n private blocks = new Map<string, Block>();\n public inspector: Inspector;\n\n constructor() {\n super();\n\n this.messenger = createParentMessenger(window.origin);\n this.inspector = new Inspector(this.messenger, this);\n\n this.initialize();\n }\n\n private initialize() {\n window.addEventListener('load', () => {\n this.messenger.send('craftile.preview.ready', {});\n setTimeout(() => {\n this.sendPageData();\n }, 0);\n });\n\n this.messenger.listen('craftile.editor.updates', (payload) => {\n this.updateBlocks(payload);\n this.emit('craftile.editor.updates', payload);\n });\n\n this.messenger.registerFallbackHandler((data: any) => {\n const { type, payload } = data;\n this.emit(type, payload);\n });\n }\n\n getBlock(blockId: string): Block | undefined {\n return this.blocks.get(blockId);\n }\n\n private updateBlocks(updates: WindowMessages['craftile.editor.updates']): void {\n for (const [blockId, block] of Object.entries(updates.blocks)) {\n this.blocks.set(blockId, block);\n }\n\n for (const blockId of updates.changes.removed) {\n this.blocks.delete(blockId);\n }\n }\n\n private sendPageData() {\n const pageDataElement = document.getElementById('page-data');\n\n if (!pageDataElement) {\n return;\n }\n\n try {\n const pageData = JSON.parse(pageDataElement.textContent || '{}');\n this.blocks.clear();\n\n for (const [blockId, block] of Object.entries(pageData.content.blocks || {}) as [string, Block][]) {\n this.blocks.set(blockId, block);\n }\n\n this.messenger.send('craftile.preview.page-data', { pageData });\n } catch (error) {\n console.error('Failed to parse page data:', error);\n }\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export declare class Inspector {
13
13
  private resizeObserver;
14
14
  private mutationObserver;
15
15
  private transitionCleanupFunctions;
16
+ private pendingViewportResizeFrame;
16
17
  constructor(messenger: WindowMessenger<WindowMessages>, events?: PreviewClientEventsEmitter);
17
18
  /**
18
19
  * Update the tracked element reference when a block's DOM element changes.
@@ -26,6 +27,15 @@ export declare class Inspector {
26
27
  private handleEditorSelectBlock;
27
28
  private handleEditorDeselectBlock;
28
29
  private handleScroll;
30
+ /**
31
+ * The iframe viewport resizes whenever the editor layout changes around it
32
+ * (e.g. the configuration panel opening). A block can move without its own
33
+ * box changing size, which the ResizeObserver would not catch, so re-measure
34
+ * on the next frame. Resize events arrive once per frame during layout
35
+ * transitions, so coalesce them into a single pending frame.
36
+ */
37
+ private handleViewportResize;
38
+ private refreshTrackedBlockPositions;
29
39
  private setupGlobalEventListeners;
30
40
  private handleGlobalHover;
31
41
  private handleGlobalLeave;
package/dist/index.js CHANGED
@@ -145,6 +145,7 @@ class Inspector {
145
145
  __publicField(this, "resizeObserver", null);
146
146
  __publicField(this, "mutationObserver", null);
147
147
  __publicField(this, "transitionCleanupFunctions", []);
148
+ __publicField(this, "pendingViewportResizeFrame", null);
148
149
  this.messenger = messenger;
149
150
  this.events = events;
150
151
  this.messenger.listen("craftile.inspector.enable", () => this.enable());
@@ -154,6 +155,7 @@ class Inspector {
154
155
  this.messenger.listen("craftile.editor.select-block", this.handleEditorSelectBlock.bind(this));
155
156
  this.messenger.listen("craftile.editor.deselect-block", this.handleEditorDeselectBlock.bind(this));
156
157
  window.addEventListener("scroll", this.handleScroll.bind(this), { passive: true });
158
+ window.addEventListener("resize", this.handleViewportResize.bind(this), { passive: true });
157
159
  this.setupGlobalEventListeners();
158
160
  }
159
161
  /**
@@ -230,6 +232,25 @@ class Inspector {
230
232
  }
231
233
  }
232
234
  handleScroll() {
235
+ this.refreshTrackedBlockPositions();
236
+ }
237
+ /**
238
+ * The iframe viewport resizes whenever the editor layout changes around it
239
+ * (e.g. the configuration panel opening). A block can move without its own
240
+ * box changing size, which the ResizeObserver would not catch, so re-measure
241
+ * on the next frame. Resize events arrive once per frame during layout
242
+ * transitions, so coalesce them into a single pending frame.
243
+ */
244
+ handleViewportResize() {
245
+ if (!this.active || this.pendingViewportResizeFrame !== null) {
246
+ return;
247
+ }
248
+ this.pendingViewportResizeFrame = requestAnimationFrame(() => {
249
+ this.pendingViewportResizeFrame = null;
250
+ this.refreshTrackedBlockPositions();
251
+ });
252
+ }
253
+ refreshTrackedBlockPositions() {
233
254
  if (!this.active) {
234
255
  return;
235
256
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../messenger/src/index.ts","../../event-bus/src/index.ts","../src/inspector.ts","../src/client.ts"],"sourcesContent":["export interface TypedMessage<T = any> {\n type: string;\n payload: T | undefined;\n}\n\nexport class WindowMessenger<Messages extends Record<string, any>> {\n private handlers = new Map<keyof Messages, Function[]>();\n private targetWindow: Window;\n private targetOrigin: string;\n private fallbackHandler?: (data: any, event: MessageEvent) => void;\n\n constructor(targetWindow: Window, targetOrigin: string = '*') {\n this.targetWindow = targetWindow;\n this.targetOrigin = targetOrigin;\n\n window.addEventListener('message', this.handleMessage.bind(this));\n }\n\n private handleMessage(event: MessageEvent) {\n const message = event.data as TypedMessage;\n\n if (!message.type) {\n return;\n }\n\n const handlers = this.handlers.get(message.type);\n\n if (handlers) {\n handlers.forEach((handler) => handler(message.payload, event));\n } else if (this.fallbackHandler) {\n this.fallbackHandler(event.data, event);\n }\n }\n\n send<K extends keyof Messages>(type: K, payload?: Messages[K]): void {\n const message: TypedMessage<Messages[K]> = { type: type as string, payload };\n this.targetWindow.postMessage(message, this.targetOrigin);\n }\n\n listen<K extends keyof Messages>(type: K, handler: (data: Messages[K], event: MessageEvent) => void): () => void {\n if (!this.handlers.has(type)) {\n this.handlers.set(type, []);\n }\n\n this.handlers.get(type)!.push(handler);\n\n return () => {\n const handlers = this.handlers.get(type);\n if (handlers) {\n const index = handlers.indexOf(handler);\n if (index > -1) {\n handlers.splice(index, 1);\n }\n }\n };\n }\n\n registerFallbackHandler(handler: (data: any, event: MessageEvent) => void) {\n this.fallbackHandler = handler;\n }\n}\n\nexport function createIframeMessenger<T extends Record<string, any>>(iframe: HTMLIFrameElement, targetOrigin = '*') {\n return new WindowMessenger<T>(iframe.contentWindow!, targetOrigin);\n}\n\nexport function createParentMessenger<T extends Record<string, any>>(targetOrigin = '*') {\n if (window.parent === window) {\n throw new Error('Not inside an iframe');\n }\n return new WindowMessenger<T>(window.parent, targetOrigin);\n}\n","export type EventListener<T = any> = (data: T) => void;\nexport type EventMap = {\n [event: string]: any;\n};\n\n/**\n * Type-safe EventBus with generic event map support\n *\n * @template T Event map interface that defines the events and their data types\n */\nexport class EventBus<T extends EventMap = EventMap> {\n private listeners: Map<keyof T, Set<EventListener<any>>> = new Map();\n\n /**\n * Add an event listener\n *\n * @param event Event name\n * @param listener Event listener function\n *\n * @returns Cleanup function to remove the listener\n */\n on<K extends keyof T>(event: K, listener: EventListener<T[K]>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n this.listeners.get(event)!.add(listener);\n\n return () => {\n this.off(event, listener);\n };\n }\n\n /**\n * Remove an event listener\n *\n * @param event Event name\n * @param listener Event listener function to remove\n */\n off<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n eventListeners.delete(listener);\n\n if (eventListeners.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Add a one-time event listener\n *\n * @param event Event name\n * @param listener Event listener function\n */\n once<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const onceWrapper = (data: T[K]) => {\n listener(data);\n this.off(event, onceWrapper);\n };\n\n this.on(event, onceWrapper);\n }\n\n /**\n * Emit an event\n *\n * @param event Event name\n * @param args Event data (optional, depending on event type)\n */\n emit<K extends keyof T>(event: K, ...args: T[K] extends void ? [] : [T[K]]): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n const data = args[0];\n eventListeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`Error in event listener for '${String(event)}':`, error);\n }\n });\n }\n }\n\n /**\n * Remove all listeners for an event, or all listeners if no event specified\n *\n * @param event Optional event name. If not provided, removes all listeners\n */\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n","import type { WindowMessenger } from '@craftile/messenger';\nimport type { Block, WindowMessages } from '@craftile/types';\nimport type { PreviewClientEvents } from './client';\n\ninterface PreviewClientEventsEmitter {\n emit<K extends keyof PreviewClientEvents>(\n event: K,\n ...args: PreviewClientEvents[K] extends void ? [] : [PreviewClientEvents[K]]\n ): void;\n getBlock(blockId: string): Block | undefined;\n}\n\nexport class Inspector {\n private active = true;\n private messenger: WindowMessenger<WindowMessages>;\n private events: PreviewClientEventsEmitter;\n private currentHoveredBlock: HTMLElement | null = null;\n private currentSelectedBlock: HTMLElement | null = null;\n private overlayButtonHovered = false;\n\n private resizeObserver: ResizeObserver | null = null;\n private mutationObserver: MutationObserver | null = null;\n private transitionCleanupFunctions: (() => void)[] = [];\n\n constructor(\n messenger: WindowMessenger<WindowMessages>,\n events: PreviewClientEventsEmitter = { emit: () => {}, getBlock: () => undefined }\n ) {\n this.messenger = messenger;\n this.events = events;\n\n this.messenger.listen('craftile.inspector.enable', () => this.enable());\n this.messenger.listen('craftile.inspector.disable', () => this.disable());\n this.messenger.listen('craftile.inspector.overlay-button-enter', this.handleOverlayButtonEnter.bind(this));\n this.messenger.listen('craftile.inspector.overlay-button-leave', this.handleOverlayButtonLeave.bind(this));\n this.messenger.listen('craftile.editor.select-block', this.handleEditorSelectBlock.bind(this));\n this.messenger.listen('craftile.editor.deselect-block', this.handleEditorDeselectBlock.bind(this));\n\n window.addEventListener('scroll', this.handleScroll.bind(this), { passive: true });\n this.setupGlobalEventListeners();\n }\n\n /**\n * Update the tracked element reference when a block's DOM element changes.\n * This is needed when the root tag of a block changes during an update.\n */\n updateTrackedElement(blockId: string, newElement: HTMLElement): void {\n // Update hovered block if it matches\n if (this.currentHoveredBlock?.dataset.block === blockId) {\n this.currentHoveredBlock = newElement;\n this.sendHoveredBlockPosition();\n }\n\n // Update selected block if it matches and re-track it\n if (this.currentSelectedBlock?.dataset.block === blockId) {\n this.currentSelectedBlock = newElement;\n requestAnimationFrame(() => {\n this.sendSelectedBlockPosition(true);\n });\n this.trackSelectedBlock();\n }\n }\n\n enable() {\n this.active = true;\n document.body.classList.add('craftile-inspector-active');\n\n // Re-track selected block if it exists\n if (this.currentSelectedBlock) {\n this.trackSelectedBlock();\n }\n }\n\n disable() {\n this.active = false;\n document.body.classList.remove('craftile-inspector-active');\n this.currentHoveredBlock = null;\n this.overlayButtonHovered = false;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n }\n\n private handleOverlayButtonEnter() {\n this.overlayButtonHovered = true;\n }\n\n private handleOverlayButtonLeave(_data: { blockId: string }) {\n this.overlayButtonHovered = false;\n\n if (!this.currentHoveredBlock) {\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleEditorSelectBlock(data: { blockId: string }) {\n const element = document.querySelector(`[data-block=\"${data.blockId}\"]`) as HTMLElement;\n\n if (element) {\n this.setSelectedBlock(element);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });\n }\n }\n\n private handleEditorDeselectBlock() {\n const selectedBlock = this.currentSelectedBlock;\n this.currentSelectedBlock = null;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n if (selectedBlock?.dataset.block) {\n this.emitBlockDeselect(selectedBlock.dataset.block, selectedBlock);\n }\n }\n\n private handleScroll() {\n if (!this.active) {\n return;\n }\n\n if (this.currentSelectedBlock) {\n this.sendSelectedBlockPosition();\n }\n\n if (this.currentHoveredBlock) {\n this.sendHoveredBlockPosition();\n }\n }\n\n private setupGlobalEventListeners() {\n document.addEventListener('mouseover', this.handleGlobalHover.bind(this));\n document.addEventListener('mouseout', this.handleGlobalLeave.bind(this));\n document.addEventListener('click', this.handleGlobalClick.bind(this), { capture: true });\n }\n\n private handleGlobalHover(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n\n if (!blockElement) {\n return;\n }\n\n e.stopPropagation();\n this.currentHoveredBlock = blockElement;\n this.sendHoveredBlockPosition();\n }\n\n private handleGlobalLeave(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n // Only clear overlay if button is not being hovered\n if (!this.overlayButtonHovered) {\n this.currentHoveredBlock = null;\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleGlobalClick(e: Event) {\n this.messenger.send('craftile.preview.click');\n\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n const blockId = blockElement.getAttribute('data-block');\n if (!blockId) {\n return;\n }\n\n const isAlreadySelected = this.currentSelectedBlock === blockElement;\n\n if (!isAlreadySelected) {\n e.preventDefault();\n e.stopImmediatePropagation();\n\n this.setSelectedBlock(blockElement);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n }\n }\n\n private setSelectedBlock(element: HTMLElement): void {\n const previousBlock = this.currentSelectedBlock;\n\n if (previousBlock === element) {\n return;\n }\n\n if (previousBlock?.dataset.block) {\n this.emitBlockDeselect(previousBlock.dataset.block, previousBlock);\n }\n\n this.currentSelectedBlock = element;\n\n if (element.dataset.block) {\n this.emitBlockSelect(element.dataset.block, element);\n }\n }\n\n private createBlockEventPayload(blockId: string, element: HTMLElement) {\n const block = this.events.getBlock(blockId);\n\n return {\n blockId,\n ...(block\n ? {\n block,\n blockType: block.type,\n }\n : {}),\n element,\n };\n }\n\n private emitBlockSelect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.select', this.createBlockEventPayload(blockId, element));\n }\n\n private emitBlockDeselect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.deselect', this.createBlockEventPayload(blockId, element));\n }\n\n private sendHoveredBlockPosition() {\n const position = this.computeElementPositioning(this.currentHoveredBlock!);\n\n this.messenger.send('craftile.preview.block-hover', {\n blockRect: position.rect,\n parentRect: position.parentRect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentHoveredBlock!.dataset.block as string,\n parentFlexDirection: position.parentFlexDirection,\n });\n }\n\n private sendSelectedBlockPosition(updates: boolean = false) {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const position = this.computeElementPositioning(this.currentSelectedBlock!);\n this.messenger.send(updates ? 'craftile.preview.update-selected-block' : 'craftile.preview.block-select', {\n blockRect: position.rect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentSelectedBlock!.dataset.block as string,\n });\n }\n\n private trackSelectedBlock() {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n this.resizeObserver = new ResizeObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n this.resizeObserver.observe(this.currentSelectedBlock);\n\n this.mutationObserver = new MutationObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n\n this.mutationObserver.observe(this.currentSelectedBlock, {\n attributes: true,\n subtree: false,\n });\n\n // Also observe parent elements that might affect positioning\n let parent = this.currentSelectedBlock.parentElement;\n while (parent) {\n this.mutationObserver.observe(parent, {\n childList: true,\n subtree: false,\n });\n\n if (parent === document.body) {\n break;\n }\n\n parent = parent.parentElement;\n }\n\n this.trackSelectedBlockTransitions();\n }\n\n private clearTransitionListeners(): void {\n this.transitionCleanupFunctions.forEach((cleanup) => cleanup());\n this.transitionCleanupFunctions = [];\n }\n\n private trackSelectedBlockTransitions(): void {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const updatePosition = () => {\n if (!this.active || !this.currentSelectedBlock?.isConnected) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (this.active && this.currentSelectedBlock?.isConnected) {\n this.sendSelectedBlockPosition(true);\n }\n });\n };\n\n let element: HTMLElement | null = this.currentSelectedBlock;\n while (element) {\n const trackedElement: HTMLElement = element;\n const handleTransitionComplete = (event: Event) => {\n if (event.target !== trackedElement) {\n return;\n }\n\n updatePosition();\n };\n\n trackedElement.addEventListener('transitionend', handleTransitionComplete);\n trackedElement.addEventListener('transitioncancel', handleTransitionComplete);\n\n this.transitionCleanupFunctions.push(() => {\n trackedElement.removeEventListener('transitionend', handleTransitionComplete);\n trackedElement.removeEventListener('transitioncancel', handleTransitionComplete);\n });\n\n if (trackedElement === document.body) {\n break;\n }\n\n element = trackedElement.parentElement;\n }\n }\n\n private computeElementPositioning(element: HTMLElement) {\n const rect = element.getBoundingClientRect();\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;\n\n const eldestParent = this.findEldestParentBlock(element);\n const parentRect = eldestParent && eldestParent !== element ? eldestParent.getBoundingClientRect() : undefined;\n const parentFlexDirection = this.getElementFlexDirection(element.parentElement);\n\n return {\n rect,\n parentRect,\n scrollTop,\n scrollLeft,\n parentFlexDirection,\n };\n }\n\n private findEldestParentBlock(element: HTMLElement): HTMLElement | null {\n let eldestParent: HTMLElement | null = null;\n let parentElement = element.parentElement;\n\n while (parentElement && parentElement !== document.body) {\n if (parentElement.hasAttribute('data-block')) {\n eldestParent = parentElement;\n }\n parentElement = parentElement.parentElement;\n }\n\n return eldestParent;\n }\n\n private getElementFlexDirection(element: HTMLElement | null): 'row' | 'column' {\n if (!element) {\n return 'column';\n }\n\n const style = window.getComputedStyle(element);\n const flexDirection = style.display.includes('flex') ? style.flexDirection : 'column';\n\n return flexDirection === 'row' || flexDirection === 'row-reverse' ? 'row' : 'column';\n }\n}\n","import type { Block, WindowMessages } from '@craftile/types';\nimport { createParentMessenger, WindowMessenger } from '@craftile/messenger';\nimport { EventBus } from '@craftile/event-bus';\nimport { Inspector } from './inspector';\n\nexport interface PreviewClientEvents extends WindowMessages {\n [event: string]: any;\n\n 'block.select': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n\n 'block.deselect': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n}\n\nexport class PreviewClient extends EventBus<PreviewClientEvents> {\n private messenger: WindowMessenger<WindowMessages>;\n private blocks = new Map<string, Block>();\n public inspector: Inspector;\n\n constructor() {\n super();\n\n this.messenger = createParentMessenger(window.origin);\n this.inspector = new Inspector(this.messenger, this);\n\n this.initialize();\n }\n\n private initialize() {\n window.addEventListener('load', () => {\n this.messenger.send('craftile.preview.ready', {});\n setTimeout(() => {\n this.sendPageData();\n }, 0);\n });\n\n this.messenger.listen('craftile.editor.updates', (payload) => {\n this.updateBlocks(payload);\n this.emit('craftile.editor.updates', payload);\n });\n\n this.messenger.registerFallbackHandler((data: any) => {\n const { type, payload } = data;\n this.emit(type, payload);\n });\n }\n\n getBlock(blockId: string): Block | undefined {\n return this.blocks.get(blockId);\n }\n\n private updateBlocks(updates: WindowMessages['craftile.editor.updates']): void {\n for (const [blockId, block] of Object.entries(updates.blocks)) {\n this.blocks.set(blockId, block);\n }\n\n for (const blockId of updates.changes.removed) {\n this.blocks.delete(blockId);\n }\n }\n\n private sendPageData() {\n const pageDataElement = document.getElementById('page-data');\n\n if (!pageDataElement) {\n return;\n }\n\n try {\n const pageData = JSON.parse(pageDataElement.textContent || '{}');\n this.blocks.clear();\n\n for (const [blockId, block] of Object.entries(pageData.content.blocks || {}) as [string, Block][]) {\n this.blocks.set(blockId, block);\n }\n\n this.messenger.send('craftile.preview.page-data', { pageData });\n } catch (error) {\n console.error('Failed to parse page data:', error);\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../messenger/src/index.ts","../../event-bus/src/index.ts","../src/inspector.ts","../src/client.ts"],"sourcesContent":["export interface TypedMessage<T = any> {\n type: string;\n payload: T | undefined;\n}\n\nexport class WindowMessenger<Messages extends Record<string, any>> {\n private handlers = new Map<keyof Messages, Function[]>();\n private targetWindow: Window;\n private targetOrigin: string;\n private fallbackHandler?: (data: any, event: MessageEvent) => void;\n\n constructor(targetWindow: Window, targetOrigin: string = '*') {\n this.targetWindow = targetWindow;\n this.targetOrigin = targetOrigin;\n\n window.addEventListener('message', this.handleMessage.bind(this));\n }\n\n private handleMessage(event: MessageEvent) {\n const message = event.data as TypedMessage;\n\n if (!message.type) {\n return;\n }\n\n const handlers = this.handlers.get(message.type);\n\n if (handlers) {\n handlers.forEach((handler) => handler(message.payload, event));\n } else if (this.fallbackHandler) {\n this.fallbackHandler(event.data, event);\n }\n }\n\n send<K extends keyof Messages>(type: K, payload?: Messages[K]): void {\n const message: TypedMessage<Messages[K]> = { type: type as string, payload };\n this.targetWindow.postMessage(message, this.targetOrigin);\n }\n\n listen<K extends keyof Messages>(type: K, handler: (data: Messages[K], event: MessageEvent) => void): () => void {\n if (!this.handlers.has(type)) {\n this.handlers.set(type, []);\n }\n\n this.handlers.get(type)!.push(handler);\n\n return () => {\n const handlers = this.handlers.get(type);\n if (handlers) {\n const index = handlers.indexOf(handler);\n if (index > -1) {\n handlers.splice(index, 1);\n }\n }\n };\n }\n\n registerFallbackHandler(handler: (data: any, event: MessageEvent) => void) {\n this.fallbackHandler = handler;\n }\n}\n\nexport function createIframeMessenger<T extends Record<string, any>>(iframe: HTMLIFrameElement, targetOrigin = '*') {\n return new WindowMessenger<T>(iframe.contentWindow!, targetOrigin);\n}\n\nexport function createParentMessenger<T extends Record<string, any>>(targetOrigin = '*') {\n if (window.parent === window) {\n throw new Error('Not inside an iframe');\n }\n return new WindowMessenger<T>(window.parent, targetOrigin);\n}\n","export type EventListener<T = any> = (data: T) => void;\nexport type EventMap = {\n [event: string]: any;\n};\n\n/**\n * Type-safe EventBus with generic event map support\n *\n * @template T Event map interface that defines the events and their data types\n */\nexport class EventBus<T extends EventMap = EventMap> {\n private listeners: Map<keyof T, Set<EventListener<any>>> = new Map();\n\n /**\n * Add an event listener\n *\n * @param event Event name\n * @param listener Event listener function\n *\n * @returns Cleanup function to remove the listener\n */\n on<K extends keyof T>(event: K, listener: EventListener<T[K]>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n\n this.listeners.get(event)!.add(listener);\n\n return () => {\n this.off(event, listener);\n };\n }\n\n /**\n * Remove an event listener\n *\n * @param event Event name\n * @param listener Event listener function to remove\n */\n off<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n eventListeners.delete(listener);\n\n if (eventListeners.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Add a one-time event listener\n *\n * @param event Event name\n * @param listener Event listener function\n */\n once<K extends keyof T>(event: K, listener: EventListener<T[K]>): void {\n const onceWrapper = (data: T[K]) => {\n listener(data);\n this.off(event, onceWrapper);\n };\n\n this.on(event, onceWrapper);\n }\n\n /**\n * Emit an event\n *\n * @param event Event name\n * @param args Event data (optional, depending on event type)\n */\n emit<K extends keyof T>(event: K, ...args: T[K] extends void ? [] : [T[K]]): void {\n const eventListeners = this.listeners.get(event);\n\n if (eventListeners) {\n const data = args[0];\n eventListeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`Error in event listener for '${String(event)}':`, error);\n }\n });\n }\n }\n\n /**\n * Remove all listeners for an event, or all listeners if no event specified\n *\n * @param event Optional event name. If not provided, removes all listeners\n */\n removeAllListeners<K extends keyof T>(event?: K): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n}\n","import type { WindowMessenger } from '@craftile/messenger';\nimport type { Block, WindowMessages } from '@craftile/types';\nimport type { PreviewClientEvents } from './client';\n\ninterface PreviewClientEventsEmitter {\n emit<K extends keyof PreviewClientEvents>(\n event: K,\n ...args: PreviewClientEvents[K] extends void ? [] : [PreviewClientEvents[K]]\n ): void;\n getBlock(blockId: string): Block | undefined;\n}\n\nexport class Inspector {\n private active = true;\n private messenger: WindowMessenger<WindowMessages>;\n private events: PreviewClientEventsEmitter;\n private currentHoveredBlock: HTMLElement | null = null;\n private currentSelectedBlock: HTMLElement | null = null;\n private overlayButtonHovered = false;\n\n private resizeObserver: ResizeObserver | null = null;\n private mutationObserver: MutationObserver | null = null;\n private transitionCleanupFunctions: (() => void)[] = [];\n private pendingViewportResizeFrame: number | null = null;\n\n constructor(\n messenger: WindowMessenger<WindowMessages>,\n events: PreviewClientEventsEmitter = { emit: () => {}, getBlock: () => undefined }\n ) {\n this.messenger = messenger;\n this.events = events;\n\n this.messenger.listen('craftile.inspector.enable', () => this.enable());\n this.messenger.listen('craftile.inspector.disable', () => this.disable());\n this.messenger.listen('craftile.inspector.overlay-button-enter', this.handleOverlayButtonEnter.bind(this));\n this.messenger.listen('craftile.inspector.overlay-button-leave', this.handleOverlayButtonLeave.bind(this));\n this.messenger.listen('craftile.editor.select-block', this.handleEditorSelectBlock.bind(this));\n this.messenger.listen('craftile.editor.deselect-block', this.handleEditorDeselectBlock.bind(this));\n\n window.addEventListener('scroll', this.handleScroll.bind(this), { passive: true });\n window.addEventListener('resize', this.handleViewportResize.bind(this), { passive: true });\n this.setupGlobalEventListeners();\n }\n\n /**\n * Update the tracked element reference when a block's DOM element changes.\n * This is needed when the root tag of a block changes during an update.\n */\n updateTrackedElement(blockId: string, newElement: HTMLElement): void {\n // Update hovered block if it matches\n if (this.currentHoveredBlock?.dataset.block === blockId) {\n this.currentHoveredBlock = newElement;\n this.sendHoveredBlockPosition();\n }\n\n // Update selected block if it matches and re-track it\n if (this.currentSelectedBlock?.dataset.block === blockId) {\n this.currentSelectedBlock = newElement;\n requestAnimationFrame(() => {\n this.sendSelectedBlockPosition(true);\n });\n this.trackSelectedBlock();\n }\n }\n\n enable() {\n this.active = true;\n document.body.classList.add('craftile-inspector-active');\n\n // Re-track selected block if it exists\n if (this.currentSelectedBlock) {\n this.trackSelectedBlock();\n }\n }\n\n disable() {\n this.active = false;\n document.body.classList.remove('craftile-inspector-active');\n this.currentHoveredBlock = null;\n this.overlayButtonHovered = false;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n }\n\n private handleOverlayButtonEnter() {\n this.overlayButtonHovered = true;\n }\n\n private handleOverlayButtonLeave(_data: { blockId: string }) {\n this.overlayButtonHovered = false;\n\n if (!this.currentHoveredBlock) {\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleEditorSelectBlock(data: { blockId: string }) {\n const element = document.querySelector(`[data-block=\"${data.blockId}\"]`) as HTMLElement;\n\n if (element) {\n this.setSelectedBlock(element);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });\n }\n }\n\n private handleEditorDeselectBlock() {\n const selectedBlock = this.currentSelectedBlock;\n this.currentSelectedBlock = null;\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n if (selectedBlock?.dataset.block) {\n this.emitBlockDeselect(selectedBlock.dataset.block, selectedBlock);\n }\n }\n\n private handleScroll() {\n this.refreshTrackedBlockPositions();\n }\n\n /**\n * The iframe viewport resizes whenever the editor layout changes around it\n * (e.g. the configuration panel opening). A block can move without its own\n * box changing size, which the ResizeObserver would not catch, so re-measure\n * on the next frame. Resize events arrive once per frame during layout\n * transitions, so coalesce them into a single pending frame.\n */\n private handleViewportResize() {\n if (!this.active || this.pendingViewportResizeFrame !== null) {\n return;\n }\n\n this.pendingViewportResizeFrame = requestAnimationFrame(() => {\n this.pendingViewportResizeFrame = null;\n this.refreshTrackedBlockPositions();\n });\n }\n\n private refreshTrackedBlockPositions() {\n if (!this.active) {\n return;\n }\n\n if (this.currentSelectedBlock) {\n this.sendSelectedBlockPosition();\n }\n\n if (this.currentHoveredBlock) {\n this.sendHoveredBlockPosition();\n }\n }\n\n private setupGlobalEventListeners() {\n document.addEventListener('mouseover', this.handleGlobalHover.bind(this));\n document.addEventListener('mouseout', this.handleGlobalLeave.bind(this));\n document.addEventListener('click', this.handleGlobalClick.bind(this), { capture: true });\n }\n\n private handleGlobalHover(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n\n if (!blockElement) {\n return;\n }\n\n e.stopPropagation();\n this.currentHoveredBlock = blockElement;\n this.sendHoveredBlockPosition();\n }\n\n private handleGlobalLeave(e: Event) {\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n // Only clear overlay if button is not being hovered\n if (!this.overlayButtonHovered) {\n this.currentHoveredBlock = null;\n this.messenger.send('craftile.preview.block-leave');\n }\n }\n\n private handleGlobalClick(e: Event) {\n this.messenger.send('craftile.preview.click');\n\n if (!this.active) {\n return;\n }\n\n const blockElement = (e.target as Element).closest('[data-block]') as HTMLElement;\n if (!blockElement) {\n return;\n }\n\n const blockId = blockElement.getAttribute('data-block');\n if (!blockId) {\n return;\n }\n\n const isAlreadySelected = this.currentSelectedBlock === blockElement;\n\n if (!isAlreadySelected) {\n e.preventDefault();\n e.stopImmediatePropagation();\n\n this.setSelectedBlock(blockElement);\n this.sendSelectedBlockPosition();\n this.trackSelectedBlock();\n }\n }\n\n private setSelectedBlock(element: HTMLElement): void {\n const previousBlock = this.currentSelectedBlock;\n\n if (previousBlock === element) {\n return;\n }\n\n if (previousBlock?.dataset.block) {\n this.emitBlockDeselect(previousBlock.dataset.block, previousBlock);\n }\n\n this.currentSelectedBlock = element;\n\n if (element.dataset.block) {\n this.emitBlockSelect(element.dataset.block, element);\n }\n }\n\n private createBlockEventPayload(blockId: string, element: HTMLElement) {\n const block = this.events.getBlock(blockId);\n\n return {\n blockId,\n ...(block\n ? {\n block,\n blockType: block.type,\n }\n : {}),\n element,\n };\n }\n\n private emitBlockSelect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.select', this.createBlockEventPayload(blockId, element));\n }\n\n private emitBlockDeselect(blockId: string, element: HTMLElement): void {\n this.events.emit('block.deselect', this.createBlockEventPayload(blockId, element));\n }\n\n private sendHoveredBlockPosition() {\n const position = this.computeElementPositioning(this.currentHoveredBlock!);\n\n this.messenger.send('craftile.preview.block-hover', {\n blockRect: position.rect,\n parentRect: position.parentRect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentHoveredBlock!.dataset.block as string,\n parentFlexDirection: position.parentFlexDirection,\n });\n }\n\n private sendSelectedBlockPosition(updates: boolean = false) {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const position = this.computeElementPositioning(this.currentSelectedBlock!);\n this.messenger.send(updates ? 'craftile.preview.update-selected-block' : 'craftile.preview.block-select', {\n blockRect: position.rect,\n scrollTop: position.scrollTop,\n scrollLeft: position.scrollLeft,\n blockId: this.currentSelectedBlock!.dataset.block as string,\n });\n }\n\n private trackSelectedBlock() {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n this.mutationObserver = null;\n }\n\n this.clearTransitionListeners();\n\n this.resizeObserver = new ResizeObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n this.resizeObserver.observe(this.currentSelectedBlock);\n\n this.mutationObserver = new MutationObserver(() => {\n if (this.active && this.currentSelectedBlock) {\n this.sendSelectedBlockPosition(true);\n }\n });\n\n this.mutationObserver.observe(this.currentSelectedBlock, {\n attributes: true,\n subtree: false,\n });\n\n // Also observe parent elements that might affect positioning\n let parent = this.currentSelectedBlock.parentElement;\n while (parent) {\n this.mutationObserver.observe(parent, {\n childList: true,\n subtree: false,\n });\n\n if (parent === document.body) {\n break;\n }\n\n parent = parent.parentElement;\n }\n\n this.trackSelectedBlockTransitions();\n }\n\n private clearTransitionListeners(): void {\n this.transitionCleanupFunctions.forEach((cleanup) => cleanup());\n this.transitionCleanupFunctions = [];\n }\n\n private trackSelectedBlockTransitions(): void {\n if (!this.currentSelectedBlock) {\n return;\n }\n\n const updatePosition = () => {\n if (!this.active || !this.currentSelectedBlock?.isConnected) {\n return;\n }\n\n requestAnimationFrame(() => {\n if (this.active && this.currentSelectedBlock?.isConnected) {\n this.sendSelectedBlockPosition(true);\n }\n });\n };\n\n let element: HTMLElement | null = this.currentSelectedBlock;\n while (element) {\n const trackedElement: HTMLElement = element;\n const handleTransitionComplete = (event: Event) => {\n if (event.target !== trackedElement) {\n return;\n }\n\n updatePosition();\n };\n\n trackedElement.addEventListener('transitionend', handleTransitionComplete);\n trackedElement.addEventListener('transitioncancel', handleTransitionComplete);\n\n this.transitionCleanupFunctions.push(() => {\n trackedElement.removeEventListener('transitionend', handleTransitionComplete);\n trackedElement.removeEventListener('transitioncancel', handleTransitionComplete);\n });\n\n if (trackedElement === document.body) {\n break;\n }\n\n element = trackedElement.parentElement;\n }\n }\n\n private computeElementPositioning(element: HTMLElement) {\n const rect = element.getBoundingClientRect();\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\n const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;\n\n const eldestParent = this.findEldestParentBlock(element);\n const parentRect = eldestParent && eldestParent !== element ? eldestParent.getBoundingClientRect() : undefined;\n const parentFlexDirection = this.getElementFlexDirection(element.parentElement);\n\n return {\n rect,\n parentRect,\n scrollTop,\n scrollLeft,\n parentFlexDirection,\n };\n }\n\n private findEldestParentBlock(element: HTMLElement): HTMLElement | null {\n let eldestParent: HTMLElement | null = null;\n let parentElement = element.parentElement;\n\n while (parentElement && parentElement !== document.body) {\n if (parentElement.hasAttribute('data-block')) {\n eldestParent = parentElement;\n }\n parentElement = parentElement.parentElement;\n }\n\n return eldestParent;\n }\n\n private getElementFlexDirection(element: HTMLElement | null): 'row' | 'column' {\n if (!element) {\n return 'column';\n }\n\n const style = window.getComputedStyle(element);\n const flexDirection = style.display.includes('flex') ? style.flexDirection : 'column';\n\n return flexDirection === 'row' || flexDirection === 'row-reverse' ? 'row' : 'column';\n }\n}\n","import type { Block, WindowMessages } from '@craftile/types';\nimport { createParentMessenger, WindowMessenger } from '@craftile/messenger';\nimport { EventBus } from '@craftile/event-bus';\nimport { Inspector } from './inspector';\n\nexport interface PreviewClientEvents extends WindowMessages {\n [event: string]: any;\n\n 'block.select': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n\n 'block.deselect': {\n blockId: string;\n block?: Block;\n blockType?: string;\n element: HTMLElement;\n };\n}\n\nexport class PreviewClient extends EventBus<PreviewClientEvents> {\n private messenger: WindowMessenger<WindowMessages>;\n private blocks = new Map<string, Block>();\n public inspector: Inspector;\n\n constructor() {\n super();\n\n this.messenger = createParentMessenger(window.origin);\n this.inspector = new Inspector(this.messenger, this);\n\n this.initialize();\n }\n\n private initialize() {\n window.addEventListener('load', () => {\n this.messenger.send('craftile.preview.ready', {});\n setTimeout(() => {\n this.sendPageData();\n }, 0);\n });\n\n this.messenger.listen('craftile.editor.updates', (payload) => {\n this.updateBlocks(payload);\n this.emit('craftile.editor.updates', payload);\n });\n\n this.messenger.registerFallbackHandler((data: any) => {\n const { type, payload } = data;\n this.emit(type, payload);\n });\n }\n\n getBlock(blockId: string): Block | undefined {\n return this.blocks.get(blockId);\n }\n\n private updateBlocks(updates: WindowMessages['craftile.editor.updates']): void {\n for (const [blockId, block] of Object.entries(updates.blocks)) {\n this.blocks.set(blockId, block);\n }\n\n for (const blockId of updates.changes.removed) {\n this.blocks.delete(blockId);\n }\n }\n\n private sendPageData() {\n const pageDataElement = document.getElementById('page-data');\n\n if (!pageDataElement) {\n return;\n }\n\n try {\n const pageData = JSON.parse(pageDataElement.textContent || '{}');\n this.blocks.clear();\n\n for (const [blockId, block] of Object.entries(pageData.content.blocks || {}) as [string, Block][]) {\n this.blocks.set(blockId, block);\n }\n\n this.messenger.send('craftile.preview.page-data', { pageData });\n } catch (error) {\n console.error('Failed to parse page data:', error);\n }\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craftile/preview-client",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Browser client for Craftile editor preview iframe functionality",
5
5
  "keywords": [
6
6
  "craftile",
@@ -37,9 +37,9 @@
37
37
  "vite": "^7.0.0",
38
38
  "vite-plugin-dts": "^4.3.0",
39
39
  "vitest": "^3.2.4",
40
- "@craftile/event-bus": "1.1.1",
41
- "@craftile/messenger": "1.1.1",
42
- "@craftile/types": "1.1.1"
40
+ "@craftile/event-bus": "1.2.0",
41
+ "@craftile/messenger": "1.2.0",
42
+ "@craftile/types": "1.2.0"
43
43
  },
44
44
  "repository": {
45
45
  "type": "git",