@b10cks/vue 0.10.2 → 0.10.3

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.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("vue"),b={key:1},h=o.defineComponent({__name:"B10cksComponent",props:{block:{}},setup(e,{expose:t}){const s=e,n=o.useTemplateRef("blockRef");t({value:n});const r=o.shallowRef(null),u=o.computed(()=>s.block?.block||null);return o.watch(()=>u.value,async l=>{if(!l){r.value=null;return}const p=l.replace(/^([a-z])/,i=>i.toUpperCase()).replace(/([a-z])([A-Z])/g,"$1$2");try{r.value=o.defineAsyncComponent({loader:()=>import(`~/b10cks/${p}.vue`),timeout:3e3,onError:(i,d,v)=>{console.warn(`Failed to load block component for type "${l}":`,i),v()}})}catch(i){console.error(`Error resolving component for block type "${l}":`,i)}},{immediate:!0}),(l,p)=>r.value?(o.openBlock(),o.createBlock(o.resolveDynamicComponent(r.value),o.mergeProps({key:0,ref_key:"blockRef",ref:n},{...l.$props,...l.$attrs}),null,16)):(o.openBlock(),o.createElementBlock("div",b,'Component for block type "'+o.toDisplayString(u.value)+'" not found.',1))}});class c{static instance;eventListeners={};isEnabled=!1;constructor(){this.isEnabled=this.isIframe()}init(){this.isEnabled&&window&&window.addEventListener("message",this.handleMessage)}static getInstance(){return c.instance||(c.instance=new c),c.instance}isInPreviewMode(){return this.isEnabled}isIframe(){return window&&window.self!==window.top}handleMessage=t=>{if(!t.data||typeof t.data!="object")return;const{type:s,payload:n}=t.data;this.notifyListeners(s,n)};notifyListeners(t,s){const n=this.eventListeners[t];n&&n.forEach(r=>{r(s)})}on(t,s){return this.isEnabled?(this.eventListeners[t]||(this.eventListeners[t]=[]),this.eventListeners[t].push(s),()=>{this.eventListeners[t]=this.eventListeners[t].filter(n=>n!==s)}):()=>{}}selectItem(t){this.isEnabled&&window.parent.postMessage({type:"SELECT_UPDATE",payload:{selectedItem:t}},"*")}updateField(t,s,n){this.isEnabled&&window.parent.postMessage({type:"FIELD_UPDATE",payload:{itemId:t,field:s,value:n}},"*")}destroy(){this.isEnabled&&(window.removeEventListener("message",this.handleMessage),this.isEnabled=!1),this.eventListeners={}}}const a=c.getInstance(),f={mounted(e,t,s){if(!a.isInPreviewMode())return;const{id:n}=t.value;if(!n){console.warn("v-editable directive requires a block with an id");return}e.classList.add("b10cks-preview");const r=i=>{i.preventDefault(),i.stopPropagation(),a.selectItem(n)},u=({selectedItem:i})=>{s.el&&(i===n?(s.el.classList.add("b10cks-selected"),m(e)):s.el.classList.remove("b10cks-selected"))},l=({selectedItem:i})=>{s.el&&(i===n?s.el.classList.add("b10cks-hover"):s.el.classList.remove("b10cks-hover"))},p=({content:i})=>{if(i&&i.id===n){const d=s.ctx;d.parent.attrs.block=i,d.update(),d.props.block=i,d.update()}};e.addEventListener("click",r),a.on("SELECT_UPDATE",u),a.on("HOVER_UPDATE",l),a.on("CONTENT_UPDATE",p),e._editableCleanup=()=>{e.removeEventListener("click",r)}},updated(e,t,s){a.isInPreviewMode()&&t.value!==t.oldValue&&(e._editableCleanup&&e._editableCleanup(),f.mounted(e,t,s))},unmounted(e){a.isInPreviewMode()&&(e._editableCleanup&&(e._editableCleanup(),delete e._editableCleanup),e.classList.remove("b10cks-preview","b10cks-selected"))}};function m(e){e.scrollIntoView&&e.scrollIntoView({behavior:"smooth"})}if(a.isInPreviewMode()){const e=document.createElement("style");e.innerHTML=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("vue"),b={key:1},h=o.defineComponent({__name:"B10cksComponent",props:{block:{}},setup(e,{expose:t}){const s=e,n=o.useTemplateRef("blockRef");t({value:n});const r=o.shallowRef(null),u=o.computed(()=>s.block?.block||null);return o.watch(()=>u.value,async l=>{if(!l){r.value=null;return}const p=l.replace(/^([a-z])/,i=>i.toUpperCase()).replace(/([a-z])([A-Z])/g,"$1$2");try{r.value=o.defineAsyncComponent({loader:()=>import(`~/b10cks/${p}.vue`),timeout:3e3,onError:(i,d,v)=>{console.warn(`Failed to load block component for type "${l}":`,i),v()}})}catch(i){console.error(`Error resolving component for block type "${l}":`,i)}},{immediate:!0}),(l,p)=>r.value?(o.openBlock(),o.createBlock(o.resolveDynamicComponent(r.value),o.mergeProps({key:0,ref_key:"blockRef",ref:n},{...l.$props,...l.$attrs}),null,16)):(o.openBlock(),o.createElementBlock("div",b,'Component for block type "'+o.toDisplayString(u.value)+'" not found.',1))}});class c{static instance;eventListeners={};isEnabled=!1;constructor(){this.isEnabled=this.isIframe()}init(){this.isEnabled&&window&&window.addEventListener("message",this.handleMessage)}static getInstance(){return c.instance||(c.instance=new c),c.instance}isInPreviewMode(){return this.isEnabled}isIframe(){return typeof window<"u"&&window.self!==window.top}handleMessage=t=>{if(!t.data||typeof t.data!="object")return;const{type:s,payload:n}=t.data;this.notifyListeners(s,n)};notifyListeners(t,s){const n=this.eventListeners[t];n&&n.forEach(r=>{r(s)})}on(t,s){return this.isEnabled?(this.eventListeners[t]||(this.eventListeners[t]=[]),this.eventListeners[t].push(s),()=>{this.eventListeners[t]=this.eventListeners[t].filter(n=>n!==s)}):()=>{}}selectItem(t){this.isEnabled&&window.parent.postMessage({type:"SELECT_UPDATE",payload:{selectedItem:t}},"*")}updateField(t,s,n){this.isEnabled&&window.parent.postMessage({type:"FIELD_UPDATE",payload:{itemId:t,field:s,value:n}},"*")}destroy(){this.isEnabled&&(window.removeEventListener("message",this.handleMessage),this.isEnabled=!1),this.eventListeners={}}}const a=c.getInstance(),f={mounted(e,t,s){if(!a.isInPreviewMode())return;const{id:n}=t.value;if(!n){console.warn("v-editable directive requires a block with an id");return}e.classList.add("b10cks-preview");const r=i=>{i.preventDefault(),i.stopPropagation(),a.selectItem(n)},u=({selectedItem:i})=>{s.el&&(i===n?(s.el.classList.add("b10cks-selected"),m(e)):s.el.classList.remove("b10cks-selected"))},l=({selectedItem:i})=>{s.el&&(i===n?s.el.classList.add("b10cks-hover"):s.el.classList.remove("b10cks-hover"))},p=({content:i})=>{if(i&&i.id===n){const d=s.ctx;d.parent.attrs.block=i,d.update(),d.props.block=i,d.update()}};e.addEventListener("click",r),a.on("SELECT_UPDATE",u),a.on("HOVER_UPDATE",l),a.on("CONTENT_UPDATE",p),e._editableCleanup=()=>{e.removeEventListener("click",r)}},updated(e,t,s){a.isInPreviewMode()&&t.value!==t.oldValue&&(e._editableCleanup&&e._editableCleanup(),f.mounted(e,t,s))},unmounted(e){a.isInPreviewMode()&&(e._editableCleanup&&(e._editableCleanup(),delete e._editableCleanup),e.classList.remove("b10cks-preview","b10cks-selected"))}};function m(e){e.scrollIntoView&&e.scrollIntoView({behavior:"smooth"})}if(a.isInPreviewMode()){const e=document.createElement("style");e.innerHTML=`
2
2
  .b10cks-hover,
3
3
  .b10cks-preview:hover {
4
4
  outline: 2px dashed rgba(59, 130, 246, 0.5);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/components/B10cksComponent.vue","../src/preview-bridge.ts","../src/directives/v-editable.ts","../src/directives/v-editable-content.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { IBContent } from '@b10cks/client'\nimport {\n type Component,\n computed,\n defineAsyncComponent,\n shallowRef,\n useTemplateRef,\n watch,\n} from 'vue'\n\nconst props = defineProps<{\n block: IBContent<string> & Record<string, never>\n}>()\n\nconst blockRef = useTemplateRef('blockRef')\ndefineExpose({ value: blockRef })\n\nconst resolvedComponent = shallowRef<Component | null>(null)\nconst componentName = computed(() => props.block?.block || null)\n\nwatch(\n () => componentName.value,\n async (newComponentName: string | null) => {\n if (!newComponentName) {\n resolvedComponent.value = null\n return\n }\n\n const pascalCaseBlockType = newComponentName\n .replace(/^([a-z])/, (match: string) => match.toUpperCase())\n .replace(/([a-z])([A-Z])/g, '$1$2')\n\n try {\n resolvedComponent.value = defineAsyncComponent({\n loader: () => import(`~/b10cks/${pascalCaseBlockType}.vue`),\n timeout: 3000,\n onError: (error, _, fail) => {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn(`Failed to load block component for type \"${newComponentName}\":`, error)\n fail()\n },\n })\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.error(`Error resolving component for block type \"${newComponentName}\":`, error)\n }\n },\n { immediate: true }\n)\n</script>\n<template>\n <component\n :is=\"resolvedComponent\"\n v-if=\"resolvedComponent\"\n ref=\"blockRef\"\n v-bind=\"{ ...$props, ...$attrs }\"\n />\n <div v-else>Component for block type \"{{ componentName }}\" not found.</div>\n</template>\n","export type ContentUpdateEvent = {\n content: Record<string, unknown>\n}\n\nexport type SelectUpdateEvent = {\n selectedItem: string\n}\n\nexport type EventType = 'CONTENT_UPDATE' | 'SELECT_UPDATE' | 'HOVER_UPDATE'\n\nexport type EventPayloadMap = {\n CONTENT_UPDATE: ContentUpdateEvent\n SELECT_UPDATE: SelectUpdateEvent\n HOVER_UPDATE: SelectUpdateEvent\n}\n\nexport type BridgeEvent = {\n type: EventType\n payload: ContentUpdateEvent | SelectUpdateEvent\n b10cksId?: string\n}\n\ntype EventCallback<T> = (payload: T) => void\n\nclass PreviewBridge {\n private static instance: PreviewBridge\n private eventListeners: {\n [key in EventType]?: Array<EventCallback<EventPayloadMap[key]>>\n } = {}\n\n private isEnabled = false\n\n private constructor() {\n this.isEnabled = this.isIframe()\n }\n\n public init(): void {\n if (this.isEnabled && window) {\n window.addEventListener('message', this.handleMessage)\n }\n }\n\n public static getInstance(): PreviewBridge {\n if (!PreviewBridge.instance) {\n PreviewBridge.instance = new PreviewBridge()\n }\n return PreviewBridge.instance\n }\n\n public isInPreviewMode(): boolean {\n return this.isEnabled\n }\n\n private isIframe(): boolean {\n return window && window.self !== window.top\n }\n\n private handleMessage = (event: MessageEvent): void => {\n if (!event.data || typeof event.data !== 'object') return\n const { type, payload } = event.data as BridgeEvent\n\n this.notifyListeners(type as EventType, payload)\n }\n\n private notifyListeners<T extends EventType>(type: T, payload: EventPayloadMap[T]): void {\n const listeners = this.eventListeners[type] as\n | Array<EventCallback<EventPayloadMap[T]>>\n | undefined\n\n if (listeners) {\n listeners.forEach((listener) => {\n listener(payload)\n })\n }\n }\n\n public on<T extends EventType>(\n eventType: T,\n callback: EventCallback<EventPayloadMap[T]>\n ): () => void {\n if (!this.isEnabled) return () => {}\n\n if (!this.eventListeners[eventType]) {\n this.eventListeners[eventType] = []\n }\n\n ;(this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>).push(callback)\n\n return () => {\n this.eventListeners[eventType] = (\n this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>\n ).filter((listener) => listener !== callback) as never\n }\n }\n\n public selectItem(selectedItem: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'SELECT_UPDATE',\n payload: { selectedItem },\n },\n '*'\n )\n }\n\n public updateField(itemId: string, field: string, value: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'FIELD_UPDATE',\n payload: { itemId, field, value },\n },\n '*'\n )\n }\n\n public destroy(): void {\n if (this.isEnabled) {\n window.removeEventListener('message', this.handleMessage)\n this.isEnabled = false\n }\n this.eventListeners = {}\n }\n}\n\nexport const previewBridge = PreviewBridge.getInstance()\n","import type { DirectiveBinding, VNode } from 'vue'\n\nimport type { SelectUpdateEvent } from '../preview-bridge'\n\nimport { previewBridge } from '../preview-bridge'\n\ninterface EditableElement extends HTMLElement {\n _editableCleanup?: () => void\n}\n\nexport const EditableDirective = {\n mounted(el: EditableElement, binding: DirectiveBinding, node: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n const { id: itemId } = binding.value\n\n if (!itemId) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn('v-editable directive requires a block with an id')\n return\n }\n\n el.classList.add('b10cks-preview')\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n previewBridge.selectItem(itemId)\n }\n\n const handleSelectionChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-selected')\n scrollIntoViewIfNeeded(el)\n } else {\n node.el.classList.remove('b10cks-selected')\n }\n }\n\n const handleHoverChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-hover')\n } else {\n node.el.classList.remove('b10cks-hover')\n }\n }\n\n const handleUpdate = ({ content }: { content: any }) => {\n if (content && content.id === itemId) {\n // biome-ignore lint/suspicious/noExplicitAny: use of any to access internal properties\n const ctx = (node as any).ctx\n ctx.parent.attrs.block = content\n ctx.update()\n ctx.props.block = content\n ctx.update()\n }\n }\n\n el.addEventListener('click', handleClick)\n previewBridge.on('SELECT_UPDATE', handleSelectionChange)\n previewBridge.on('HOVER_UPDATE', handleHoverChange)\n previewBridge.on('CONTENT_UPDATE', handleUpdate)\n\n el._editableCleanup = () => {\n el.removeEventListener('click', handleClick)\n }\n },\n\n updated(el: EditableElement, binding: DirectiveBinding, vnode: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (binding.value !== binding.oldValue) {\n if (el._editableCleanup) {\n el._editableCleanup()\n }\n\n EditableDirective.mounted(el, binding, vnode)\n }\n },\n\n unmounted(el: EditableElement) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (el._editableCleanup) {\n el._editableCleanup()\n delete el._editableCleanup\n }\n\n el.classList.remove('b10cks-preview', 'b10cks-selected')\n },\n}\n\nfunction scrollIntoViewIfNeeded(el: HTMLElement) {\n if (el.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth' })\n }\n}\n\nif (previewBridge.isInPreviewMode()) {\n const style = document.createElement('style')\n style.innerHTML = `\n .b10cks-hover,\n .b10cks-preview:hover {\n outline: 2px dashed rgba(59, 130, 246, 0.5);\n outline-offset: 2px;\n }\n .b10cks-selected {\n outline: 2px solid rgb(59, 130, 246) !important;\n outline-offset: 2px;\n }\n `\n document.head.appendChild(style)\n}\n","import type { Directive, DirectiveBinding } from 'vue'\n\nimport { previewBridge } from '../preview-bridge'\n\nexport const EditableContentDirective: Directive<HTMLElement> = {\n mounted(el: HTMLElement, binding: DirectiveBinding) {\n const { id: itemId, field } = binding.value\n if (!previewBridge.isInPreviewMode()) return\n el.setAttribute('contenteditable', 'true')\n\n el.addEventListener('input', (event: Event) => {\n previewBridge.updateField(itemId, field, (event.target as HTMLInputElement).innerText)\n })\n },\n}\n","import type { Plugin } from 'vue'\n\nimport type { B10cksVuePluginOptions } from './types'\n\nimport B10cksComponent from './components/B10cksComponent.vue'\nimport { EditableDirective } from './directives/v-editable'\nimport { EditableContentDirective } from './directives/v-editable-content'\n\nexport { previewBridge } from './preview-bridge'\n\nexport const B10cksVue: Plugin = {\n install(app, pluginOptions: B10cksVuePluginOptions) {\n app.provide('b10cksVueOptions', pluginOptions)\n\n app.directive('editable', EditableDirective)\n app.directive('editable-field', EditableContentDirective)\n app.component('B10cksComponent', B10cksComponent)\n },\n}\n"],"names":["props","__props","blockRef","useTemplateRef","__expose","resolvedComponent","shallowRef","componentName","computed","watch","newComponentName","pascalCaseBlockType","match","defineAsyncComponent","error","_","fail","_createBlock","_resolveDynamicComponent","_mergeProps","$props","$attrs","_openBlock","_createElementBlock","_hoisted_1","_toDisplayString","PreviewBridge","event","type","payload","listeners","listener","eventType","callback","selectedItem","itemId","field","value","previewBridge","EditableDirective","el","binding","node","handleClick","e","handleSelectionChange","scrollIntoViewIfNeeded","handleHoverChange","handleUpdate","content","ctx","vnode","style","EditableContentDirective","B10cksVue","app","pluginOptions","B10cksComponent"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/components/B10cksComponent.vue","../src/preview-bridge.ts","../src/directives/v-editable.ts","../src/directives/v-editable-content.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { IBContent } from '@b10cks/client'\nimport {\n type Component,\n computed,\n defineAsyncComponent,\n shallowRef,\n useTemplateRef,\n watch,\n} from 'vue'\n\nconst props = defineProps<{\n block: IBContent<string> & Record<string, never>\n}>()\n\nconst blockRef = useTemplateRef('blockRef')\ndefineExpose({ value: blockRef })\n\nconst resolvedComponent = shallowRef<Component | null>(null)\nconst componentName = computed(() => props.block?.block || null)\n\nwatch(\n () => componentName.value,\n async (newComponentName: string | null) => {\n if (!newComponentName) {\n resolvedComponent.value = null\n return\n }\n\n const pascalCaseBlockType = newComponentName\n .replace(/^([a-z])/, (match: string) => match.toUpperCase())\n .replace(/([a-z])([A-Z])/g, '$1$2')\n\n try {\n resolvedComponent.value = defineAsyncComponent({\n loader: () => import(`~/b10cks/${pascalCaseBlockType}.vue`),\n timeout: 3000,\n onError: (error, _, fail) => {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn(`Failed to load block component for type \"${newComponentName}\":`, error)\n fail()\n },\n })\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.error(`Error resolving component for block type \"${newComponentName}\":`, error)\n }\n },\n { immediate: true }\n)\n</script>\n<template>\n <component\n :is=\"resolvedComponent\"\n v-if=\"resolvedComponent\"\n ref=\"blockRef\"\n v-bind=\"{ ...$props, ...$attrs }\"\n />\n <div v-else>Component for block type \"{{ componentName }}\" not found.</div>\n</template>\n","export type ContentUpdateEvent = {\n content: Record<string, unknown>\n}\n\nexport type SelectUpdateEvent = {\n selectedItem: string\n}\n\nexport type EventType = 'CONTENT_UPDATE' | 'SELECT_UPDATE' | 'HOVER_UPDATE'\n\nexport type EventPayloadMap = {\n CONTENT_UPDATE: ContentUpdateEvent\n SELECT_UPDATE: SelectUpdateEvent\n HOVER_UPDATE: SelectUpdateEvent\n}\n\nexport type BridgeEvent = {\n type: EventType\n payload: ContentUpdateEvent | SelectUpdateEvent\n b10cksId?: string\n}\n\ntype EventCallback<T> = (payload: T) => void\n\nclass PreviewBridge {\n private static instance: PreviewBridge\n private eventListeners: {\n [key in EventType]?: Array<EventCallback<EventPayloadMap[key]>>\n } = {}\n\n private isEnabled = false\n\n private constructor() {\n this.isEnabled = this.isIframe()\n }\n\n public init(): void {\n if (this.isEnabled && window) {\n window.addEventListener('message', this.handleMessage)\n }\n }\n\n public static getInstance(): PreviewBridge {\n if (!PreviewBridge.instance) {\n PreviewBridge.instance = new PreviewBridge()\n }\n return PreviewBridge.instance\n }\n\n public isInPreviewMode(): boolean {\n return this.isEnabled\n }\n\n private isIframe(): boolean {\n return typeof window !== 'undefined' && window.self !== window.top\n }\n\n private handleMessage = (event: MessageEvent): void => {\n if (!event.data || typeof event.data !== 'object') return\n const { type, payload } = event.data as BridgeEvent\n\n this.notifyListeners(type as EventType, payload)\n }\n\n private notifyListeners<T extends EventType>(type: T, payload: EventPayloadMap[T]): void {\n const listeners = this.eventListeners[type] as\n | Array<EventCallback<EventPayloadMap[T]>>\n | undefined\n\n if (listeners) {\n listeners.forEach((listener) => {\n listener(payload)\n })\n }\n }\n\n public on<T extends EventType>(\n eventType: T,\n callback: EventCallback<EventPayloadMap[T]>\n ): () => void {\n if (!this.isEnabled) return () => {}\n\n if (!this.eventListeners[eventType]) {\n this.eventListeners[eventType] = []\n }\n\n ;(this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>).push(callback)\n\n return () => {\n this.eventListeners[eventType] = (\n this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>\n ).filter((listener) => listener !== callback) as never\n }\n }\n\n public selectItem(selectedItem: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'SELECT_UPDATE',\n payload: { selectedItem },\n },\n '*'\n )\n }\n\n public updateField(itemId: string, field: string, value: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'FIELD_UPDATE',\n payload: { itemId, field, value },\n },\n '*'\n )\n }\n\n public destroy(): void {\n if (this.isEnabled) {\n window.removeEventListener('message', this.handleMessage)\n this.isEnabled = false\n }\n this.eventListeners = {}\n }\n}\n\nexport const previewBridge = PreviewBridge.getInstance()\n","import type { DirectiveBinding, VNode } from 'vue'\n\nimport type { SelectUpdateEvent } from '../preview-bridge'\n\nimport { previewBridge } from '../preview-bridge'\n\ninterface EditableElement extends HTMLElement {\n _editableCleanup?: () => void\n}\n\nexport const EditableDirective = {\n mounted(el: EditableElement, binding: DirectiveBinding, node: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n const { id: itemId } = binding.value\n\n if (!itemId) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn('v-editable directive requires a block with an id')\n return\n }\n\n el.classList.add('b10cks-preview')\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n previewBridge.selectItem(itemId)\n }\n\n const handleSelectionChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-selected')\n scrollIntoViewIfNeeded(el)\n } else {\n node.el.classList.remove('b10cks-selected')\n }\n }\n\n const handleHoverChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-hover')\n } else {\n node.el.classList.remove('b10cks-hover')\n }\n }\n\n const handleUpdate = ({ content }: { content: any }) => {\n if (content && content.id === itemId) {\n // biome-ignore lint/suspicious/noExplicitAny: use of any to access internal properties\n const ctx = (node as any).ctx\n ctx.parent.attrs.block = content\n ctx.update()\n ctx.props.block = content\n ctx.update()\n }\n }\n\n el.addEventListener('click', handleClick)\n previewBridge.on('SELECT_UPDATE', handleSelectionChange)\n previewBridge.on('HOVER_UPDATE', handleHoverChange)\n previewBridge.on('CONTENT_UPDATE', handleUpdate)\n\n el._editableCleanup = () => {\n el.removeEventListener('click', handleClick)\n }\n },\n\n updated(el: EditableElement, binding: DirectiveBinding, vnode: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (binding.value !== binding.oldValue) {\n if (el._editableCleanup) {\n el._editableCleanup()\n }\n\n EditableDirective.mounted(el, binding, vnode)\n }\n },\n\n unmounted(el: EditableElement) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (el._editableCleanup) {\n el._editableCleanup()\n delete el._editableCleanup\n }\n\n el.classList.remove('b10cks-preview', 'b10cks-selected')\n },\n}\n\nfunction scrollIntoViewIfNeeded(el: HTMLElement) {\n if (el.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth' })\n }\n}\n\nif (previewBridge.isInPreviewMode()) {\n const style = document.createElement('style')\n style.innerHTML = `\n .b10cks-hover,\n .b10cks-preview:hover {\n outline: 2px dashed rgba(59, 130, 246, 0.5);\n outline-offset: 2px;\n }\n .b10cks-selected {\n outline: 2px solid rgb(59, 130, 246) !important;\n outline-offset: 2px;\n }\n `\n document.head.appendChild(style)\n}\n","import type { Directive, DirectiveBinding } from 'vue'\n\nimport { previewBridge } from '../preview-bridge'\n\nexport const EditableContentDirective: Directive<HTMLElement> = {\n mounted(el: HTMLElement, binding: DirectiveBinding) {\n const { id: itemId, field } = binding.value\n if (!previewBridge.isInPreviewMode()) return\n el.setAttribute('contenteditable', 'true')\n\n el.addEventListener('input', (event: Event) => {\n previewBridge.updateField(itemId, field, (event.target as HTMLInputElement).innerText)\n })\n },\n}\n","import type { Plugin } from 'vue'\n\nimport type { B10cksVuePluginOptions } from './types'\n\nimport B10cksComponent from './components/B10cksComponent.vue'\nimport { EditableDirective } from './directives/v-editable'\nimport { EditableContentDirective } from './directives/v-editable-content'\n\nexport { previewBridge } from './preview-bridge'\n\nexport const B10cksVue: Plugin = {\n install(app, pluginOptions: B10cksVuePluginOptions) {\n app.provide('b10cksVueOptions', pluginOptions)\n\n app.directive('editable', EditableDirective)\n app.directive('editable-field', EditableContentDirective)\n app.component('B10cksComponent', B10cksComponent)\n },\n}\n"],"names":["props","__props","blockRef","useTemplateRef","__expose","resolvedComponent","shallowRef","componentName","computed","watch","newComponentName","pascalCaseBlockType","match","defineAsyncComponent","error","_","fail","_createBlock","_resolveDynamicComponent","_mergeProps","$props","$attrs","_openBlock","_createElementBlock","_hoisted_1","_toDisplayString","PreviewBridge","event","type","payload","listeners","listener","eventType","callback","selectedItem","itemId","field","value","previewBridge","EditableDirective","el","binding","node","handleClick","e","handleSelectionChange","scrollIntoViewIfNeeded","handleHoverChange","handleUpdate","content","ctx","vnode","style","EditableContentDirective","B10cksVue","app","pluginOptions","B10cksComponent"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -53,7 +53,7 @@ class l {
53
53
  return this.isEnabled;
54
54
  }
55
55
  isIframe() {
56
- return window && window.self !== window.top;
56
+ return typeof window < "u" && window.self !== window.top;
57
57
  }
58
58
  handleMessage = (t) => {
59
59
  if (!t.data || typeof t.data != "object") return;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/components/B10cksComponent.vue","../src/preview-bridge.ts","../src/directives/v-editable.ts","../src/directives/v-editable-content.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { IBContent } from '@b10cks/client'\nimport {\n type Component,\n computed,\n defineAsyncComponent,\n shallowRef,\n useTemplateRef,\n watch,\n} from 'vue'\n\nconst props = defineProps<{\n block: IBContent<string> & Record<string, never>\n}>()\n\nconst blockRef = useTemplateRef('blockRef')\ndefineExpose({ value: blockRef })\n\nconst resolvedComponent = shallowRef<Component | null>(null)\nconst componentName = computed(() => props.block?.block || null)\n\nwatch(\n () => componentName.value,\n async (newComponentName: string | null) => {\n if (!newComponentName) {\n resolvedComponent.value = null\n return\n }\n\n const pascalCaseBlockType = newComponentName\n .replace(/^([a-z])/, (match: string) => match.toUpperCase())\n .replace(/([a-z])([A-Z])/g, '$1$2')\n\n try {\n resolvedComponent.value = defineAsyncComponent({\n loader: () => import(`~/b10cks/${pascalCaseBlockType}.vue`),\n timeout: 3000,\n onError: (error, _, fail) => {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn(`Failed to load block component for type \"${newComponentName}\":`, error)\n fail()\n },\n })\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.error(`Error resolving component for block type \"${newComponentName}\":`, error)\n }\n },\n { immediate: true }\n)\n</script>\n<template>\n <component\n :is=\"resolvedComponent\"\n v-if=\"resolvedComponent\"\n ref=\"blockRef\"\n v-bind=\"{ ...$props, ...$attrs }\"\n />\n <div v-else>Component for block type \"{{ componentName }}\" not found.</div>\n</template>\n","export type ContentUpdateEvent = {\n content: Record<string, unknown>\n}\n\nexport type SelectUpdateEvent = {\n selectedItem: string\n}\n\nexport type EventType = 'CONTENT_UPDATE' | 'SELECT_UPDATE' | 'HOVER_UPDATE'\n\nexport type EventPayloadMap = {\n CONTENT_UPDATE: ContentUpdateEvent\n SELECT_UPDATE: SelectUpdateEvent\n HOVER_UPDATE: SelectUpdateEvent\n}\n\nexport type BridgeEvent = {\n type: EventType\n payload: ContentUpdateEvent | SelectUpdateEvent\n b10cksId?: string\n}\n\ntype EventCallback<T> = (payload: T) => void\n\nclass PreviewBridge {\n private static instance: PreviewBridge\n private eventListeners: {\n [key in EventType]?: Array<EventCallback<EventPayloadMap[key]>>\n } = {}\n\n private isEnabled = false\n\n private constructor() {\n this.isEnabled = this.isIframe()\n }\n\n public init(): void {\n if (this.isEnabled && window) {\n window.addEventListener('message', this.handleMessage)\n }\n }\n\n public static getInstance(): PreviewBridge {\n if (!PreviewBridge.instance) {\n PreviewBridge.instance = new PreviewBridge()\n }\n return PreviewBridge.instance\n }\n\n public isInPreviewMode(): boolean {\n return this.isEnabled\n }\n\n private isIframe(): boolean {\n return window && window.self !== window.top\n }\n\n private handleMessage = (event: MessageEvent): void => {\n if (!event.data || typeof event.data !== 'object') return\n const { type, payload } = event.data as BridgeEvent\n\n this.notifyListeners(type as EventType, payload)\n }\n\n private notifyListeners<T extends EventType>(type: T, payload: EventPayloadMap[T]): void {\n const listeners = this.eventListeners[type] as\n | Array<EventCallback<EventPayloadMap[T]>>\n | undefined\n\n if (listeners) {\n listeners.forEach((listener) => {\n listener(payload)\n })\n }\n }\n\n public on<T extends EventType>(\n eventType: T,\n callback: EventCallback<EventPayloadMap[T]>\n ): () => void {\n if (!this.isEnabled) return () => {}\n\n if (!this.eventListeners[eventType]) {\n this.eventListeners[eventType] = []\n }\n\n ;(this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>).push(callback)\n\n return () => {\n this.eventListeners[eventType] = (\n this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>\n ).filter((listener) => listener !== callback) as never\n }\n }\n\n public selectItem(selectedItem: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'SELECT_UPDATE',\n payload: { selectedItem },\n },\n '*'\n )\n }\n\n public updateField(itemId: string, field: string, value: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'FIELD_UPDATE',\n payload: { itemId, field, value },\n },\n '*'\n )\n }\n\n public destroy(): void {\n if (this.isEnabled) {\n window.removeEventListener('message', this.handleMessage)\n this.isEnabled = false\n }\n this.eventListeners = {}\n }\n}\n\nexport const previewBridge = PreviewBridge.getInstance()\n","import type { DirectiveBinding, VNode } from 'vue'\n\nimport type { SelectUpdateEvent } from '../preview-bridge'\n\nimport { previewBridge } from '../preview-bridge'\n\ninterface EditableElement extends HTMLElement {\n _editableCleanup?: () => void\n}\n\nexport const EditableDirective = {\n mounted(el: EditableElement, binding: DirectiveBinding, node: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n const { id: itemId } = binding.value\n\n if (!itemId) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn('v-editable directive requires a block with an id')\n return\n }\n\n el.classList.add('b10cks-preview')\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n previewBridge.selectItem(itemId)\n }\n\n const handleSelectionChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-selected')\n scrollIntoViewIfNeeded(el)\n } else {\n node.el.classList.remove('b10cks-selected')\n }\n }\n\n const handleHoverChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-hover')\n } else {\n node.el.classList.remove('b10cks-hover')\n }\n }\n\n const handleUpdate = ({ content }: { content: any }) => {\n if (content && content.id === itemId) {\n // biome-ignore lint/suspicious/noExplicitAny: use of any to access internal properties\n const ctx = (node as any).ctx\n ctx.parent.attrs.block = content\n ctx.update()\n ctx.props.block = content\n ctx.update()\n }\n }\n\n el.addEventListener('click', handleClick)\n previewBridge.on('SELECT_UPDATE', handleSelectionChange)\n previewBridge.on('HOVER_UPDATE', handleHoverChange)\n previewBridge.on('CONTENT_UPDATE', handleUpdate)\n\n el._editableCleanup = () => {\n el.removeEventListener('click', handleClick)\n }\n },\n\n updated(el: EditableElement, binding: DirectiveBinding, vnode: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (binding.value !== binding.oldValue) {\n if (el._editableCleanup) {\n el._editableCleanup()\n }\n\n EditableDirective.mounted(el, binding, vnode)\n }\n },\n\n unmounted(el: EditableElement) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (el._editableCleanup) {\n el._editableCleanup()\n delete el._editableCleanup\n }\n\n el.classList.remove('b10cks-preview', 'b10cks-selected')\n },\n}\n\nfunction scrollIntoViewIfNeeded(el: HTMLElement) {\n if (el.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth' })\n }\n}\n\nif (previewBridge.isInPreviewMode()) {\n const style = document.createElement('style')\n style.innerHTML = `\n .b10cks-hover,\n .b10cks-preview:hover {\n outline: 2px dashed rgba(59, 130, 246, 0.5);\n outline-offset: 2px;\n }\n .b10cks-selected {\n outline: 2px solid rgb(59, 130, 246) !important;\n outline-offset: 2px;\n }\n `\n document.head.appendChild(style)\n}\n","import type { Directive, DirectiveBinding } from 'vue'\n\nimport { previewBridge } from '../preview-bridge'\n\nexport const EditableContentDirective: Directive<HTMLElement> = {\n mounted(el: HTMLElement, binding: DirectiveBinding) {\n const { id: itemId, field } = binding.value\n if (!previewBridge.isInPreviewMode()) return\n el.setAttribute('contenteditable', 'true')\n\n el.addEventListener('input', (event: Event) => {\n previewBridge.updateField(itemId, field, (event.target as HTMLInputElement).innerText)\n })\n },\n}\n","import type { Plugin } from 'vue'\n\nimport type { B10cksVuePluginOptions } from './types'\n\nimport B10cksComponent from './components/B10cksComponent.vue'\nimport { EditableDirective } from './directives/v-editable'\nimport { EditableContentDirective } from './directives/v-editable-content'\n\nexport { previewBridge } from './preview-bridge'\n\nexport const B10cksVue: Plugin = {\n install(app, pluginOptions: B10cksVuePluginOptions) {\n app.provide('b10cksVueOptions', pluginOptions)\n\n app.directive('editable', EditableDirective)\n app.directive('editable-field', EditableContentDirective)\n app.component('B10cksComponent', B10cksComponent)\n },\n}\n"],"names":["props","__props","blockRef","useTemplateRef","__expose","resolvedComponent","shallowRef","componentName","computed","watch","newComponentName","pascalCaseBlockType","match","defineAsyncComponent","error","_","fail","_createBlock","_resolveDynamicComponent","_mergeProps","$props","$attrs","_openBlock","_createElementBlock","_hoisted_1","_toDisplayString","PreviewBridge","event","type","payload","listeners","listener","eventType","callback","selectedItem","itemId","field","value","previewBridge","EditableDirective","el","binding","node","handleClick","e","handleSelectionChange","scrollIntoViewIfNeeded","handleHoverChange","handleUpdate","content","ctx","vnode","style","EditableContentDirective","B10cksVue","app","pluginOptions","B10cksComponent"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/components/B10cksComponent.vue","../src/preview-bridge.ts","../src/directives/v-editable.ts","../src/directives/v-editable-content.ts","../src/index.ts"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { IBContent } from '@b10cks/client'\nimport {\n type Component,\n computed,\n defineAsyncComponent,\n shallowRef,\n useTemplateRef,\n watch,\n} from 'vue'\n\nconst props = defineProps<{\n block: IBContent<string> & Record<string, never>\n}>()\n\nconst blockRef = useTemplateRef('blockRef')\ndefineExpose({ value: blockRef })\n\nconst resolvedComponent = shallowRef<Component | null>(null)\nconst componentName = computed(() => props.block?.block || null)\n\nwatch(\n () => componentName.value,\n async (newComponentName: string | null) => {\n if (!newComponentName) {\n resolvedComponent.value = null\n return\n }\n\n const pascalCaseBlockType = newComponentName\n .replace(/^([a-z])/, (match: string) => match.toUpperCase())\n .replace(/([a-z])([A-Z])/g, '$1$2')\n\n try {\n resolvedComponent.value = defineAsyncComponent({\n loader: () => import(`~/b10cks/${pascalCaseBlockType}.vue`),\n timeout: 3000,\n onError: (error, _, fail) => {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn(`Failed to load block component for type \"${newComponentName}\":`, error)\n fail()\n },\n })\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.error(`Error resolving component for block type \"${newComponentName}\":`, error)\n }\n },\n { immediate: true }\n)\n</script>\n<template>\n <component\n :is=\"resolvedComponent\"\n v-if=\"resolvedComponent\"\n ref=\"blockRef\"\n v-bind=\"{ ...$props, ...$attrs }\"\n />\n <div v-else>Component for block type \"{{ componentName }}\" not found.</div>\n</template>\n","export type ContentUpdateEvent = {\n content: Record<string, unknown>\n}\n\nexport type SelectUpdateEvent = {\n selectedItem: string\n}\n\nexport type EventType = 'CONTENT_UPDATE' | 'SELECT_UPDATE' | 'HOVER_UPDATE'\n\nexport type EventPayloadMap = {\n CONTENT_UPDATE: ContentUpdateEvent\n SELECT_UPDATE: SelectUpdateEvent\n HOVER_UPDATE: SelectUpdateEvent\n}\n\nexport type BridgeEvent = {\n type: EventType\n payload: ContentUpdateEvent | SelectUpdateEvent\n b10cksId?: string\n}\n\ntype EventCallback<T> = (payload: T) => void\n\nclass PreviewBridge {\n private static instance: PreviewBridge\n private eventListeners: {\n [key in EventType]?: Array<EventCallback<EventPayloadMap[key]>>\n } = {}\n\n private isEnabled = false\n\n private constructor() {\n this.isEnabled = this.isIframe()\n }\n\n public init(): void {\n if (this.isEnabled && window) {\n window.addEventListener('message', this.handleMessage)\n }\n }\n\n public static getInstance(): PreviewBridge {\n if (!PreviewBridge.instance) {\n PreviewBridge.instance = new PreviewBridge()\n }\n return PreviewBridge.instance\n }\n\n public isInPreviewMode(): boolean {\n return this.isEnabled\n }\n\n private isIframe(): boolean {\n return typeof window !== 'undefined' && window.self !== window.top\n }\n\n private handleMessage = (event: MessageEvent): void => {\n if (!event.data || typeof event.data !== 'object') return\n const { type, payload } = event.data as BridgeEvent\n\n this.notifyListeners(type as EventType, payload)\n }\n\n private notifyListeners<T extends EventType>(type: T, payload: EventPayloadMap[T]): void {\n const listeners = this.eventListeners[type] as\n | Array<EventCallback<EventPayloadMap[T]>>\n | undefined\n\n if (listeners) {\n listeners.forEach((listener) => {\n listener(payload)\n })\n }\n }\n\n public on<T extends EventType>(\n eventType: T,\n callback: EventCallback<EventPayloadMap[T]>\n ): () => void {\n if (!this.isEnabled) return () => {}\n\n if (!this.eventListeners[eventType]) {\n this.eventListeners[eventType] = []\n }\n\n ;(this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>).push(callback)\n\n return () => {\n this.eventListeners[eventType] = (\n this.eventListeners[eventType] as Array<EventCallback<EventPayloadMap[T]>>\n ).filter((listener) => listener !== callback) as never\n }\n }\n\n public selectItem(selectedItem: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'SELECT_UPDATE',\n payload: { selectedItem },\n },\n '*'\n )\n }\n\n public updateField(itemId: string, field: string, value: string): void {\n if (!this.isEnabled) return\n\n window.parent.postMessage(\n {\n type: 'FIELD_UPDATE',\n payload: { itemId, field, value },\n },\n '*'\n )\n }\n\n public destroy(): void {\n if (this.isEnabled) {\n window.removeEventListener('message', this.handleMessage)\n this.isEnabled = false\n }\n this.eventListeners = {}\n }\n}\n\nexport const previewBridge = PreviewBridge.getInstance()\n","import type { DirectiveBinding, VNode } from 'vue'\n\nimport type { SelectUpdateEvent } from '../preview-bridge'\n\nimport { previewBridge } from '../preview-bridge'\n\ninterface EditableElement extends HTMLElement {\n _editableCleanup?: () => void\n}\n\nexport const EditableDirective = {\n mounted(el: EditableElement, binding: DirectiveBinding, node: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n const { id: itemId } = binding.value\n\n if (!itemId) {\n // biome-ignore lint/suspicious/noConsole: give developers feedback\n console.warn('v-editable directive requires a block with an id')\n return\n }\n\n el.classList.add('b10cks-preview')\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n previewBridge.selectItem(itemId)\n }\n\n const handleSelectionChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-selected')\n scrollIntoViewIfNeeded(el)\n } else {\n node.el.classList.remove('b10cks-selected')\n }\n }\n\n const handleHoverChange = ({ selectedItem }: SelectUpdateEvent) => {\n if (!node.el) return\n\n if (selectedItem === itemId) {\n node.el.classList.add('b10cks-hover')\n } else {\n node.el.classList.remove('b10cks-hover')\n }\n }\n\n const handleUpdate = ({ content }: { content: any }) => {\n if (content && content.id === itemId) {\n // biome-ignore lint/suspicious/noExplicitAny: use of any to access internal properties\n const ctx = (node as any).ctx\n ctx.parent.attrs.block = content\n ctx.update()\n ctx.props.block = content\n ctx.update()\n }\n }\n\n el.addEventListener('click', handleClick)\n previewBridge.on('SELECT_UPDATE', handleSelectionChange)\n previewBridge.on('HOVER_UPDATE', handleHoverChange)\n previewBridge.on('CONTENT_UPDATE', handleUpdate)\n\n el._editableCleanup = () => {\n el.removeEventListener('click', handleClick)\n }\n },\n\n updated(el: EditableElement, binding: DirectiveBinding, vnode: VNode) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (binding.value !== binding.oldValue) {\n if (el._editableCleanup) {\n el._editableCleanup()\n }\n\n EditableDirective.mounted(el, binding, vnode)\n }\n },\n\n unmounted(el: EditableElement) {\n if (!previewBridge.isInPreviewMode()) return\n\n if (el._editableCleanup) {\n el._editableCleanup()\n delete el._editableCleanup\n }\n\n el.classList.remove('b10cks-preview', 'b10cks-selected')\n },\n}\n\nfunction scrollIntoViewIfNeeded(el: HTMLElement) {\n if (el.scrollIntoView) {\n el.scrollIntoView({ behavior: 'smooth' })\n }\n}\n\nif (previewBridge.isInPreviewMode()) {\n const style = document.createElement('style')\n style.innerHTML = `\n .b10cks-hover,\n .b10cks-preview:hover {\n outline: 2px dashed rgba(59, 130, 246, 0.5);\n outline-offset: 2px;\n }\n .b10cks-selected {\n outline: 2px solid rgb(59, 130, 246) !important;\n outline-offset: 2px;\n }\n `\n document.head.appendChild(style)\n}\n","import type { Directive, DirectiveBinding } from 'vue'\n\nimport { previewBridge } from '../preview-bridge'\n\nexport const EditableContentDirective: Directive<HTMLElement> = {\n mounted(el: HTMLElement, binding: DirectiveBinding) {\n const { id: itemId, field } = binding.value\n if (!previewBridge.isInPreviewMode()) return\n el.setAttribute('contenteditable', 'true')\n\n el.addEventListener('input', (event: Event) => {\n previewBridge.updateField(itemId, field, (event.target as HTMLInputElement).innerText)\n })\n },\n}\n","import type { Plugin } from 'vue'\n\nimport type { B10cksVuePluginOptions } from './types'\n\nimport B10cksComponent from './components/B10cksComponent.vue'\nimport { EditableDirective } from './directives/v-editable'\nimport { EditableContentDirective } from './directives/v-editable-content'\n\nexport { previewBridge } from './preview-bridge'\n\nexport const B10cksVue: Plugin = {\n install(app, pluginOptions: B10cksVuePluginOptions) {\n app.provide('b10cksVueOptions', pluginOptions)\n\n app.directive('editable', EditableDirective)\n app.directive('editable-field', EditableContentDirective)\n app.component('B10cksComponent', B10cksComponent)\n },\n}\n"],"names":["props","__props","blockRef","useTemplateRef","__expose","resolvedComponent","shallowRef","componentName","computed","watch","newComponentName","pascalCaseBlockType","match","defineAsyncComponent","error","_","fail","_createBlock","_resolveDynamicComponent","_mergeProps","$props","$attrs","_openBlock","_createElementBlock","_hoisted_1","_toDisplayString","PreviewBridge","event","type","payload","listeners","listener","eventType","callback","selectedItem","itemId","field","value","previewBridge","EditableDirective","el","binding","node","handleClick","e","handleSelectionChange","scrollIntoViewIfNeeded","handleHoverChange","handleUpdate","content","ctx","vnode","style","EditableContentDirective","B10cksVue","app","pluginOptions","B10cksComponent"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b10cks/vue",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "SDK to integrate b10cks into your vue applications",
5
5
  "license": "MIT",
6
6
  "author": "Michael Wallner @ Coder's Cantina",