@intlayer/editor 8.10.1 → 8.11.0-canary.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/cjs/components/ContentSelectorWrapper.cjs +19 -0
- package/dist/cjs/components/ContentSelectorWrapper.cjs.map +1 -1
- package/dist/esm/components/ContentSelectorWrapper.mjs +19 -0
- package/dist/esm/components/ContentSelectorWrapper.mjs.map +1 -1
- package/dist/types/components/ContentSelectorWrapper.d.ts +1 -0
- package/dist/types/components/ContentSelectorWrapper.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -129,8 +129,27 @@ var IntlayerContentSelectorWrapperElement = class extends _HTMLElement {
|
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
131
|
const keyPath = this._getFilteredKeyPath();
|
|
132
|
+
const wasSelected = this._isSelected;
|
|
132
133
|
this._isSelected = focusedContent.dictionaryKey === this._dictionaryKey && (focusedContent.keyPath?.length ?? 0) > 0 && (0, _intlayer_core_utils.isSameKeyPath)(focusedContent.keyPath ?? [], keyPath);
|
|
133
134
|
this._updateSelectorAttr();
|
|
135
|
+
if (this._isSelected && !wasSelected) this._scrollIntoViewIfNeeded();
|
|
136
|
+
}
|
|
137
|
+
_scrollIntoViewIfNeeded() {
|
|
138
|
+
try {
|
|
139
|
+
let rect;
|
|
140
|
+
if (this.childNodes.length > 0) {
|
|
141
|
+
const range = document.createRange();
|
|
142
|
+
range.selectNode(this);
|
|
143
|
+
rect = range.getBoundingClientRect();
|
|
144
|
+
} else rect = this.getBoundingClientRect();
|
|
145
|
+
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
146
|
+
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
147
|
+
if (!(rect.width > 0 && rect.height > 0 && rect.bottom > 0 && rect.right > 0 && rect.top < viewportHeight && rect.left < viewportWidth)) (this.firstElementChild ?? this).scrollIntoView({
|
|
148
|
+
behavior: "smooth",
|
|
149
|
+
block: "nearest",
|
|
150
|
+
inline: "nearest"
|
|
151
|
+
});
|
|
152
|
+
} catch {}
|
|
134
153
|
}
|
|
135
154
|
_updateSelectorAttr() {
|
|
136
155
|
if (!this._selector) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentSelectorWrapper.cjs","names":["getGlobalEditorManager","NodeTypes","node","onGlobalEditorManagerChange"],"sources":["../../../src/components/ContentSelectorWrapper.ts"],"sourcesContent":["import { isSameKeyPath } from '@intlayer/core/utils';\n\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n EditorStateManager,\n FileContent,\n} from '../core/EditorStateManager';\nimport {\n getGlobalEditorManager,\n onGlobalEditorManagerChange,\n} from '../core/globalManager';\nimport { MessageKey } from '../messageKey';\n\ntype RenderState = 'simple' | 'wrapped-slot' | 'wrapped-text';\n\nconst _HTMLElement =\n typeof HTMLElement !== 'undefined'\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n/**\n * <intlayer-content-selector-wrapper>\n *\n * Framework-agnostic web component that wraps content with the Intlayer editor\n * selection UI. It replaces the per-framework ContentSelectorWrapper components\n * (Vue, Svelte, Solid, Preact).\n *\n * It reads from the global EditorStateManager singleton (set by initEditorClient)\n * and conditionally renders <intlayer-content-selector> around its slot content\n * when the editor is active and the app is running inside an iframe.\n *\n * @attr {string} key-path - JSON-serialized KeyPath[] for this content node\n * @attr {string} dictionary-key - The dictionary key owning this content node\n */\nexport class IntlayerContentSelectorWrapperElement extends _HTMLElement {\n private _keyPathJson = '[]';\n private _dictionaryKey = '';\n private _editorEnabled = false;\n private _isInIframe = false;\n private _isSelected = false;\n private _editedValue: ContentNode | undefined = undefined;\n\n private _renderState: RenderState | null = null;\n private _selector: HTMLElement | null = null;\n\n private _unsubManager: (() => void) | null = null;\n private _unsubEnabled: (() => void) | null = null;\n private _unsubFocused: (() => void) | null = null;\n private _unsubEditedContent: (() => void) | null = null;\n\n static get observedAttributes(): string[] {\n return ['key-path', 'dictionary-key'];\n }\n\n get keyPathJson(): string {\n return this._keyPathJson;\n }\n set keyPathJson(v: string) {\n this._keyPathJson = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n get dictionaryKey(): string {\n return this._dictionaryKey;\n }\n set dictionaryKey(v: string) {\n this._dictionaryKey = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = ':host { display: contents; }';\n shadow.appendChild(style);\n }\n\n attributeChangedCallback(\n name: string,\n _oldVal: string | null,\n newVal: string | null\n ): void {\n if (name === 'key-path') {\n this._keyPathJson = newVal ?? '[]';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n } else if (name === 'dictionary-key') {\n this._dictionaryKey = newVal ?? '';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n }\n\n connectedCallback(): void {\n if (typeof window !== 'undefined') {\n this._isInIframe = window.self !== window.top;\n }\n this._subscribeToManager();\n this._render();\n }\n\n disconnectedCallback(): void {\n this._teardown();\n }\n\n private _teardown(): void {\n this._unsubManager?.();\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubManager = null;\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n }\n\n private _getRawKeyPath(): KeyPath[] {\n try {\n return JSON.parse(this._keyPathJson) as KeyPath[];\n } catch {\n return [];\n }\n }\n\n private _getFilteredKeyPath(): KeyPath[] {\n return this._getRawKeyPath().filter(\n (keyPath) => keyPath.type !== NodeTypes.TRANSLATION\n );\n }\n\n private _updateEditedValue(manager: EditorStateManager): void {\n const filteredKeyPath = this._getFilteredKeyPath();\n if (!this._dictionaryKey || filteredKeyPath.length === 0) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n // Node types whose display requires framework-level rendering (markdown,\n // HTML, insertion, file): do not override the slot — the framework handles\n // those. Only plain / translated strings can be substituted here.\n const rawKeyPath = this._getRawKeyPath();\n const lastStepType = rawKeyPath[rawKeyPath.length - 1]?.type;\n if (\n lastStepType === NodeTypes.MARKDOWN ||\n lastStepType === NodeTypes.HTML ||\n lastStepType === NodeTypes.INSERTION ||\n lastStepType === NodeTypes.FILE\n ) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n let value = manager.getContentValue(this._dictionaryKey, filteredKeyPath);\n\n // getContentNodeByKeyPath resolves translation nodes only at intermediate\n // steps, not the final leaf. Resolve manually when the returned value is\n // still a translation object (happens when Translation steps are filtered\n // out and the leaf IS the translation object).\n if (\n value !== null &&\n value !== undefined &&\n typeof value === 'object' &&\n (value as { nodeType?: unknown }).nodeType === NodeTypes.TRANSLATION\n ) {\n const locale = manager.currentLocale.value as string | undefined;\n // TypedNodeModel<Translation, …> structurally satisfies TypedNode<BaseNode>\n // (both have nodeType), so this narrowing cast is sound.\n const node = value as TypedNodeModel<\n typeof NodeTypes.TRANSLATION,\n Record<string, ContentNode>\n >;\n value = locale ? node[NodeTypes.TRANSLATION][locale] : undefined;\n }\n\n this._editedValue = value;\n this._render();\n }\n\n private _updateIsSelected(\n focusedContent: FileContent | null | undefined\n ): void {\n if (!focusedContent) {\n this._isSelected = false;\n this._updateSelectorAttr();\n return;\n }\n const keyPath = this._getFilteredKeyPath();\n this._isSelected =\n focusedContent.dictionaryKey === this._dictionaryKey &&\n (focusedContent.keyPath?.length ?? 0) > 0 &&\n isSameKeyPath(focusedContent.keyPath ?? [], keyPath);\n this._updateSelectorAttr();\n }\n\n private _updateSelectorAttr(): void {\n if (!this._selector) return;\n if (this._isSelected) {\n this._selector.setAttribute('is-selecting', '');\n } else {\n this._selector.removeAttribute('is-selecting');\n }\n }\n\n private _subscribeToManager(): void {\n const manager = getGlobalEditorManager();\n if (manager) {\n this._setupManagerSubscriptions(manager);\n }\n // Keep listening for manager changes (handles stop + re-init cycles)\n this._unsubManager = onGlobalEditorManagerChange((m) => {\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n if (m) {\n this._setupManagerSubscriptions(m);\n } else {\n this._editorEnabled = false;\n this._isSelected = false;\n this._editedValue = undefined;\n this._render();\n }\n });\n }\n\n private _setupManagerSubscriptions(manager: EditorStateManager): void {\n this._editorEnabled = manager.editorEnabled.value ?? false;\n this._updateIsSelected(manager.focusedContent.value);\n this._updateEditedValue(manager);\n\n const handleEnabledChange = (e: Event) => {\n this._editorEnabled = (e as CustomEvent<boolean>).detail;\n this._render();\n };\n const handleFocusedChange = (e: Event) => {\n this._updateIsSelected((e as CustomEvent<FileContent | null>).detail);\n };\n const handleEditedContentChange = () => {\n this._updateEditedValue(manager);\n };\n\n manager.editorEnabled.addEventListener('change', handleEnabledChange);\n manager.focusedContent.addEventListener('change', handleFocusedChange);\n manager.editedContent.addEventListener('change', handleEditedContentChange);\n\n this._unsubEnabled = () =>\n manager.editorEnabled.removeEventListener('change', handleEnabledChange);\n this._unsubFocused = () =>\n manager.focusedContent.removeEventListener('change', handleFocusedChange);\n this._unsubEditedContent = () =>\n manager.editedContent.removeEventListener(\n 'change',\n handleEditedContentChange\n );\n }\n\n private _handlePress(e: Event): void {\n // Stop propagation so nested wrappers don't also fire (composed + bubbles)\n e.stopPropagation();\n const manager = getGlobalEditorManager();\n if (!manager) return;\n manager.focusedContent.set({\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n });\n }\n\n private _handleHover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n {\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n }\n );\n }\n\n private _handleUnhover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n null\n );\n }\n\n private _render(): void {\n const useWrapper = this._isInIframe && this._editorEnabled;\n const editedValue = this._editedValue;\n const isSimpleValue =\n typeof editedValue === 'string' ||\n typeof editedValue === 'number' ||\n typeof editedValue === 'boolean';\n\n const newState: RenderState = !useWrapper\n ? 'simple'\n : isSimpleValue\n ? 'wrapped-text'\n : 'wrapped-slot';\n\n if (this._renderState !== newState) {\n this._rebuildContent(newState);\n return;\n }\n\n // Structure unchanged — update only dynamic parts\n if (newState !== 'simple' && this._selector) {\n this._updateSelectorAttr();\n if (\n newState === 'wrapped-text' &&\n this._selector.firstChild?.nodeType === Node.TEXT_NODE\n ) {\n (this._selector.firstChild as Text).data = String(editedValue);\n }\n }\n }\n\n private _rebuildContent(state: RenderState): void {\n const shadow = this.shadowRoot!;\n // Remove all nodes except the style element (first child)\n while (shadow.childNodes.length > 1) {\n shadow.removeChild(shadow.lastChild!);\n }\n this._selector = null;\n\n if (state === 'simple') {\n shadow.appendChild(document.createElement('slot'));\n } else {\n const selector = document.createElement('intlayer-content-selector');\n this._selector = selector;\n if (this._isSelected) selector.setAttribute('is-selecting', '');\n selector.addEventListener('intlayer:press', (e) => this._handlePress(e));\n selector.addEventListener('intlayer:hover', (e) => this._handleHover(e));\n selector.addEventListener('intlayer:unhover', (e) =>\n this._handleUnhover(e)\n );\n\n if (state === 'wrapped-text') {\n selector.appendChild(\n document.createTextNode(String(this._editedValue))\n );\n } else {\n selector.appendChild(document.createElement('slot'));\n }\n shadow.appendChild(selector);\n }\n\n this._renderState = state;\n }\n}\n\nexport const defineIntlayerContentSelectorWrapper = (): void => {\n if (typeof customElements === 'undefined') return;\n\n if (!customElements.get('intlayer-content-selector-wrapper')) {\n customElements.define(\n 'intlayer-content-selector-wrapper',\n IntlayerContentSelectorWrapperElement\n );\n }\n};\n"],"mappings":";;;;;;;;;AAkBA,MAAM,eACJ,OAAO,gBAAgB,cACnB,cACC,MAAM,CAAC;;;;;;;;;;;;;;;AAgBd,IAAa,wCAAb,cAA2D,aAAa;CACtE,AAAQ,eAAe;CACvB,AAAQ,iBAAiB;CACzB,AAAQ,iBAAiB;CACzB,AAAQ,cAAc;CACtB,AAAQ,cAAc;CACtB,AAAQ,eAAwC;CAEhD,AAAQ,eAAmC;CAC3C,AAAQ,YAAgC;CAExC,AAAQ,gBAAqC;CAC7C,AAAQ,gBAAqC;CAC7C,AAAQ,gBAAqC;CAC7C,AAAQ,sBAA2C;CAEnD,WAAW,qBAA+B;EACxC,OAAO,CAAC,YAAY,gBAAgB;CACtC;CAEA,IAAI,cAAsB;EACxB,OAAO,KAAK;CACd;CACA,IAAI,YAAY,GAAW;EACzB,KAAK,eAAe;EACpB,MAAM,UAAUA,kDAAuB;EACvC,IAAI,SAAS,KAAK,mBAAmB,OAAO;CAC9C;CAEA,IAAI,gBAAwB;EAC1B,OAAO,KAAK;CACd;CACA,IAAI,cAAc,GAAW;EAC3B,KAAK,iBAAiB;EACtB,MAAM,UAAUA,kDAAuB;EACvC,IAAI,SAAS,KAAK,mBAAmB,OAAO;CAC9C;CAEA,cAAc;EACZ,MAAM;EACN,MAAM,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;EACjD,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,cAAc;EACpB,OAAO,YAAY,KAAK;CAC1B;CAEA,yBACE,MACA,SACA,QACM;EACN,IAAI,SAAS,YAAY;GACvB,KAAK,eAAe,UAAU;GAC9B,MAAM,UAAUA,kDAAuB;GACvC,IAAI,SAAS,KAAK,mBAAmB,OAAO;EAC9C,OAAO,IAAI,SAAS,kBAAkB;GACpC,KAAK,iBAAiB,UAAU;GAChC,MAAM,UAAUA,kDAAuB;GACvC,IAAI,SAAS,KAAK,mBAAmB,OAAO;EAC9C;CACF;CAEA,oBAA0B;EACxB,IAAI,OAAO,WAAW,aACpB,KAAK,cAAc,OAAO,SAAS,OAAO;EAE5C,KAAK,oBAAoB;EACzB,KAAK,QAAQ;CACf;CAEA,uBAA6B;EAC3B,KAAK,UAAU;CACjB;CAEA,AAAQ,YAAkB;EACxB,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,sBAAsB;EAC3B,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,sBAAsB;CAC7B;CAEA,AAAQ,iBAA4B;EAClC,IAAI;GACF,OAAO,KAAK,MAAM,KAAK,YAAY;EACrC,QAAQ;GACN,OAAO,CAAC;EACV;CACF;CAEA,AAAQ,sBAAiC;EACvC,OAAO,KAAK,eAAe,EAAE,QAC1B,YAAY,QAAQ,SAASC,yBAAU,WAC1C;CACF;CAEA,AAAQ,mBAAmB,SAAmC;EAC5D,MAAM,kBAAkB,KAAK,oBAAoB;EACjD,IAAI,CAAC,KAAK,kBAAkB,gBAAgB,WAAW,GAAG;GACxD,KAAK,eAAe;GACpB,KAAK,QAAQ;GACb;EACF;EAKA,MAAM,aAAa,KAAK,eAAe;EACvC,MAAM,eAAe,WAAW,WAAW,SAAS,IAAI;EACxD,IACE,iBAAiBA,yBAAU,YAC3B,iBAAiBA,yBAAU,QAC3B,iBAAiBA,yBAAU,aAC3B,iBAAiBA,yBAAU,MAC3B;GACA,KAAK,eAAe;GACpB,KAAK,QAAQ;GACb;EACF;EAEA,IAAI,QAAQ,QAAQ,gBAAgB,KAAK,gBAAgB,eAAe;EAMxE,IACE,UAAU,QACV,UAAU,UACV,OAAO,UAAU,YAChB,MAAiC,aAAaA,yBAAU,aACzD;GACA,MAAM,SAAS,QAAQ,cAAc;GAOrC,QAAQ,SAASC,MAAKD,yBAAU,aAAa,UAAU;EACzD;EAEA,KAAK,eAAe;EACpB,KAAK,QAAQ;CACf;CAEA,AAAQ,kBACN,gBACM;EACN,IAAI,CAAC,gBAAgB;GACnB,KAAK,cAAc;GACnB,KAAK,oBAAoB;GACzB;EACF;EACA,MAAM,UAAU,KAAK,oBAAoB;EACzC,KAAK,cACH,eAAe,kBAAkB,KAAK,mBACrC,eAAe,SAAS,UAAU,KAAK,6CAC1B,eAAe,WAAW,CAAC,GAAG,OAAO;EACrD,KAAK,oBAAoB;CAC3B;CAEA,AAAQ,sBAA4B;EAClC,IAAI,CAAC,KAAK,WAAW;EACrB,IAAI,KAAK,aACP,KAAK,UAAU,aAAa,gBAAgB,EAAE;OAE9C,KAAK,UAAU,gBAAgB,cAAc;CAEjD;CAEA,AAAQ,sBAA4B;EAClC,MAAM,UAAUD,kDAAuB;EACvC,IAAI,SACF,KAAK,2BAA2B,OAAO;EAGzC,KAAK,gBAAgBG,wDAA6B,MAAM;GACtD,KAAK,gBAAgB;GACrB,KAAK,gBAAgB;GACrB,KAAK,sBAAsB;GAC3B,KAAK,gBAAgB;GACrB,KAAK,gBAAgB;GACrB,KAAK,sBAAsB;GAC3B,IAAI,GACF,KAAK,2BAA2B,CAAC;QAC5B;IACL,KAAK,iBAAiB;IACtB,KAAK,cAAc;IACnB,KAAK,eAAe;IACpB,KAAK,QAAQ;GACf;EACF,CAAC;CACH;CAEA,AAAQ,2BAA2B,SAAmC;EACpE,KAAK,iBAAiB,QAAQ,cAAc,SAAS;EACrD,KAAK,kBAAkB,QAAQ,eAAe,KAAK;EACnD,KAAK,mBAAmB,OAAO;EAE/B,MAAM,uBAAuB,MAAa;GACxC,KAAK,iBAAkB,EAA2B;GAClD,KAAK,QAAQ;EACf;EACA,MAAM,uBAAuB,MAAa;GACxC,KAAK,kBAAmB,EAAsC,MAAM;EACtE;EACA,MAAM,kCAAkC;GACtC,KAAK,mBAAmB,OAAO;EACjC;EAEA,QAAQ,cAAc,iBAAiB,UAAU,mBAAmB;EACpE,QAAQ,eAAe,iBAAiB,UAAU,mBAAmB;EACrE,QAAQ,cAAc,iBAAiB,UAAU,yBAAyB;EAE1E,KAAK,sBACH,QAAQ,cAAc,oBAAoB,UAAU,mBAAmB;EACzE,KAAK,sBACH,QAAQ,eAAe,oBAAoB,UAAU,mBAAmB;EAC1E,KAAK,4BACH,QAAQ,cAAc,oBACpB,UACA,yBACF;CACJ;CAEA,AAAQ,aAAa,GAAgB;EAEnC,EAAE,gBAAgB;EAClB,MAAM,UAAUH,kDAAuB;EACvC,IAAI,CAAC,SAAS;EACd,QAAQ,eAAe,IAAI;GACzB,eAAe,KAAK;GACpB,SAAS,KAAK,oBAAoB;EACpC,CAAC;CACH;CAEA,AAAQ,aAAa,GAAgB;EACnC,EAAE,gBAAgB;EAClB,kDAAuB,GAAG,UAAU,KAClC,sCAA+C,QAC/C;GACE,eAAe,KAAK;GACpB,SAAS,KAAK,oBAAoB;EACpC,CACF;CACF;CAEA,AAAQ,eAAe,GAAgB;EACrC,EAAE,gBAAgB;EAClB,kDAAuB,GAAG,UAAU,KAClC,sCAA+C,QAC/C,IACF;CACF;CAEA,AAAQ,UAAgB;EACtB,MAAM,aAAa,KAAK,eAAe,KAAK;EAC5C,MAAM,cAAc,KAAK;EAMzB,MAAM,WAAwB,CAAC,aAC3B,WALF,OAAO,gBAAgB,YACvB,OAAO,gBAAgB,YACvB,OAAO,gBAAgB,YAKnB,iBACA;EAEN,IAAI,KAAK,iBAAiB,UAAU;GAClC,KAAK,gBAAgB,QAAQ;GAC7B;EACF;EAGA,IAAI,aAAa,YAAY,KAAK,WAAW;GAC3C,KAAK,oBAAoB;GACzB,IACE,aAAa,kBACb,KAAK,UAAU,YAAY,aAAa,KAAK,WAE7C,AAAC,KAAK,UAAU,WAAoB,OAAO,OAAO,WAAW;EAEjE;CACF;CAEA,AAAQ,gBAAgB,OAA0B;EAChD,MAAM,SAAS,KAAK;EAEpB,OAAO,OAAO,WAAW,SAAS,GAChC,OAAO,YAAY,OAAO,SAAU;EAEtC,KAAK,YAAY;EAEjB,IAAI,UAAU,UACZ,OAAO,YAAY,SAAS,cAAc,MAAM,CAAC;OAC5C;GACL,MAAM,WAAW,SAAS,cAAc,2BAA2B;GACnE,KAAK,YAAY;GACjB,IAAI,KAAK,aAAa,SAAS,aAAa,gBAAgB,EAAE;GAC9D,SAAS,iBAAiB,mBAAmB,MAAM,KAAK,aAAa,CAAC,CAAC;GACvE,SAAS,iBAAiB,mBAAmB,MAAM,KAAK,aAAa,CAAC,CAAC;GACvE,SAAS,iBAAiB,qBAAqB,MAC7C,KAAK,eAAe,CAAC,CACvB;GAEA,IAAI,UAAU,gBACZ,SAAS,YACP,SAAS,eAAe,OAAO,KAAK,YAAY,CAAC,CACnD;QAEA,SAAS,YAAY,SAAS,cAAc,MAAM,CAAC;GAErD,OAAO,YAAY,QAAQ;EAC7B;EAEA,KAAK,eAAe;CACtB;AACF;AAEA,MAAa,6CAAmD;CAC9D,IAAI,OAAO,mBAAmB,aAAa;CAE3C,IAAI,CAAC,eAAe,IAAI,mCAAmC,GACzD,eAAe,OACb,qCACA,qCACF;AAEJ"}
|
|
1
|
+
{"version":3,"file":"ContentSelectorWrapper.cjs","names":["getGlobalEditorManager","NodeTypes","node","onGlobalEditorManagerChange"],"sources":["../../../src/components/ContentSelectorWrapper.ts"],"sourcesContent":["import { isSameKeyPath } from '@intlayer/core/utils';\n\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n EditorStateManager,\n FileContent,\n} from '../core/EditorStateManager';\nimport {\n getGlobalEditorManager,\n onGlobalEditorManagerChange,\n} from '../core/globalManager';\nimport { MessageKey } from '../messageKey';\n\ntype RenderState = 'simple' | 'wrapped-slot' | 'wrapped-text';\n\nconst _HTMLElement =\n typeof HTMLElement !== 'undefined'\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n/**\n * <intlayer-content-selector-wrapper>\n *\n * Framework-agnostic web component that wraps content with the Intlayer editor\n * selection UI. It replaces the per-framework ContentSelectorWrapper components\n * (Vue, Svelte, Solid, Preact).\n *\n * It reads from the global EditorStateManager singleton (set by initEditorClient)\n * and conditionally renders <intlayer-content-selector> around its slot content\n * when the editor is active and the app is running inside an iframe.\n *\n * @attr {string} key-path - JSON-serialized KeyPath[] for this content node\n * @attr {string} dictionary-key - The dictionary key owning this content node\n */\nexport class IntlayerContentSelectorWrapperElement extends _HTMLElement {\n private _keyPathJson = '[]';\n private _dictionaryKey = '';\n private _editorEnabled = false;\n private _isInIframe = false;\n private _isSelected = false;\n private _editedValue: ContentNode | undefined = undefined;\n\n private _renderState: RenderState | null = null;\n private _selector: HTMLElement | null = null;\n\n private _unsubManager: (() => void) | null = null;\n private _unsubEnabled: (() => void) | null = null;\n private _unsubFocused: (() => void) | null = null;\n private _unsubEditedContent: (() => void) | null = null;\n\n static get observedAttributes(): string[] {\n return ['key-path', 'dictionary-key'];\n }\n\n get keyPathJson(): string {\n return this._keyPathJson;\n }\n set keyPathJson(v: string) {\n this._keyPathJson = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n get dictionaryKey(): string {\n return this._dictionaryKey;\n }\n set dictionaryKey(v: string) {\n this._dictionaryKey = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = ':host { display: contents; }';\n shadow.appendChild(style);\n }\n\n attributeChangedCallback(\n name: string,\n _oldVal: string | null,\n newVal: string | null\n ): void {\n if (name === 'key-path') {\n this._keyPathJson = newVal ?? '[]';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n } else if (name === 'dictionary-key') {\n this._dictionaryKey = newVal ?? '';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n }\n\n connectedCallback(): void {\n if (typeof window !== 'undefined') {\n this._isInIframe = window.self !== window.top;\n }\n this._subscribeToManager();\n this._render();\n }\n\n disconnectedCallback(): void {\n this._teardown();\n }\n\n private _teardown(): void {\n this._unsubManager?.();\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubManager = null;\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n }\n\n private _getRawKeyPath(): KeyPath[] {\n try {\n return JSON.parse(this._keyPathJson) as KeyPath[];\n } catch {\n return [];\n }\n }\n\n private _getFilteredKeyPath(): KeyPath[] {\n return this._getRawKeyPath().filter(\n (keyPath) => keyPath.type !== NodeTypes.TRANSLATION\n );\n }\n\n private _updateEditedValue(manager: EditorStateManager): void {\n const filteredKeyPath = this._getFilteredKeyPath();\n if (!this._dictionaryKey || filteredKeyPath.length === 0) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n // Node types whose display requires framework-level rendering (markdown,\n // HTML, insertion, file): do not override the slot — the framework handles\n // those. Only plain / translated strings can be substituted here.\n const rawKeyPath = this._getRawKeyPath();\n const lastStepType = rawKeyPath[rawKeyPath.length - 1]?.type;\n if (\n lastStepType === NodeTypes.MARKDOWN ||\n lastStepType === NodeTypes.HTML ||\n lastStepType === NodeTypes.INSERTION ||\n lastStepType === NodeTypes.FILE\n ) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n let value = manager.getContentValue(this._dictionaryKey, filteredKeyPath);\n\n // getContentNodeByKeyPath resolves translation nodes only at intermediate\n // steps, not the final leaf. Resolve manually when the returned value is\n // still a translation object (happens when Translation steps are filtered\n // out and the leaf IS the translation object).\n if (\n value !== null &&\n value !== undefined &&\n typeof value === 'object' &&\n (value as { nodeType?: unknown }).nodeType === NodeTypes.TRANSLATION\n ) {\n const locale = manager.currentLocale.value as string | undefined;\n // TypedNodeModel<Translation, …> structurally satisfies TypedNode<BaseNode>\n // (both have nodeType), so this narrowing cast is sound.\n const node = value as TypedNodeModel<\n typeof NodeTypes.TRANSLATION,\n Record<string, ContentNode>\n >;\n value = locale ? node[NodeTypes.TRANSLATION][locale] : undefined;\n }\n\n this._editedValue = value;\n this._render();\n }\n\n private _updateIsSelected(\n focusedContent: FileContent | null | undefined\n ): void {\n if (!focusedContent) {\n this._isSelected = false;\n this._updateSelectorAttr();\n return;\n }\n const keyPath = this._getFilteredKeyPath();\n const wasSelected = this._isSelected;\n this._isSelected =\n focusedContent.dictionaryKey === this._dictionaryKey &&\n (focusedContent.keyPath?.length ?? 0) > 0 &&\n isSameKeyPath(focusedContent.keyPath ?? [], keyPath);\n this._updateSelectorAttr();\n\n // Scroll into view when this element becomes selected and is not already\n // visible in the iframe viewport. This covers the case where the editor\n // focuses a content block that is off-screen in the client app.\n if (this._isSelected && !wasSelected) {\n this._scrollIntoViewIfNeeded();\n }\n }\n\n private _scrollIntoViewIfNeeded(): void {\n try {\n // this element has display:contents so getBoundingClientRect() returns\n // all zeros. Use a Range over its children to get the real visual bounds.\n let rect: DOMRect;\n if (this.childNodes.length > 0) {\n const range = document.createRange();\n range.selectNode(this);\n rect = range.getBoundingClientRect();\n } else {\n rect = this.getBoundingClientRect();\n }\n\n const viewportHeight =\n window.innerHeight || document.documentElement.clientHeight;\n const viewportWidth =\n window.innerWidth || document.documentElement.clientWidth;\n\n const isVisible =\n rect.width > 0 &&\n rect.height > 0 &&\n rect.bottom > 0 &&\n rect.right > 0 &&\n rect.top < viewportHeight &&\n rect.left < viewportWidth;\n\n if (!isVisible) {\n // Scroll the first real child into view — display:contents hosts have no\n // box of their own and browsers may ignore scrollIntoView on them.\n const scrollTarget =\n (this.firstElementChild as Element | null) ?? this;\n scrollTarget.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n }\n } catch {\n // scrollIntoView may not be available in all environments\n }\n }\n\n private _updateSelectorAttr(): void {\n if (!this._selector) return;\n if (this._isSelected) {\n this._selector.setAttribute('is-selecting', '');\n } else {\n this._selector.removeAttribute('is-selecting');\n }\n }\n\n private _subscribeToManager(): void {\n const manager = getGlobalEditorManager();\n if (manager) {\n this._setupManagerSubscriptions(manager);\n }\n // Keep listening for manager changes (handles stop + re-init cycles)\n this._unsubManager = onGlobalEditorManagerChange((m) => {\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n if (m) {\n this._setupManagerSubscriptions(m);\n } else {\n this._editorEnabled = false;\n this._isSelected = false;\n this._editedValue = undefined;\n this._render();\n }\n });\n }\n\n private _setupManagerSubscriptions(manager: EditorStateManager): void {\n this._editorEnabled = manager.editorEnabled.value ?? false;\n this._updateIsSelected(manager.focusedContent.value);\n this._updateEditedValue(manager);\n\n const handleEnabledChange = (e: Event) => {\n this._editorEnabled = (e as CustomEvent<boolean>).detail;\n this._render();\n };\n const handleFocusedChange = (e: Event) => {\n this._updateIsSelected((e as CustomEvent<FileContent | null>).detail);\n };\n const handleEditedContentChange = () => {\n this._updateEditedValue(manager);\n };\n\n manager.editorEnabled.addEventListener('change', handleEnabledChange);\n manager.focusedContent.addEventListener('change', handleFocusedChange);\n manager.editedContent.addEventListener('change', handleEditedContentChange);\n\n this._unsubEnabled = () =>\n manager.editorEnabled.removeEventListener('change', handleEnabledChange);\n this._unsubFocused = () =>\n manager.focusedContent.removeEventListener('change', handleFocusedChange);\n this._unsubEditedContent = () =>\n manager.editedContent.removeEventListener(\n 'change',\n handleEditedContentChange\n );\n }\n\n private _handlePress(e: Event): void {\n // Stop propagation so nested wrappers don't also fire (composed + bubbles)\n e.stopPropagation();\n const manager = getGlobalEditorManager();\n if (!manager) return;\n manager.focusedContent.set({\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n });\n }\n\n private _handleHover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n {\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n }\n );\n }\n\n private _handleUnhover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n null\n );\n }\n\n private _render(): void {\n const useWrapper = this._isInIframe && this._editorEnabled;\n const editedValue = this._editedValue;\n const isSimpleValue =\n typeof editedValue === 'string' ||\n typeof editedValue === 'number' ||\n typeof editedValue === 'boolean';\n\n const newState: RenderState = !useWrapper\n ? 'simple'\n : isSimpleValue\n ? 'wrapped-text'\n : 'wrapped-slot';\n\n if (this._renderState !== newState) {\n this._rebuildContent(newState);\n return;\n }\n\n // Structure unchanged — update only dynamic parts\n if (newState !== 'simple' && this._selector) {\n this._updateSelectorAttr();\n if (\n newState === 'wrapped-text' &&\n this._selector.firstChild?.nodeType === Node.TEXT_NODE\n ) {\n (this._selector.firstChild as Text).data = String(editedValue);\n }\n }\n }\n\n private _rebuildContent(state: RenderState): void {\n const shadow = this.shadowRoot!;\n // Remove all nodes except the style element (first child)\n while (shadow.childNodes.length > 1) {\n shadow.removeChild(shadow.lastChild!);\n }\n this._selector = null;\n\n if (state === 'simple') {\n shadow.appendChild(document.createElement('slot'));\n } else {\n const selector = document.createElement('intlayer-content-selector');\n this._selector = selector;\n if (this._isSelected) selector.setAttribute('is-selecting', '');\n selector.addEventListener('intlayer:press', (e) => this._handlePress(e));\n selector.addEventListener('intlayer:hover', (e) => this._handleHover(e));\n selector.addEventListener('intlayer:unhover', (e) =>\n this._handleUnhover(e)\n );\n\n if (state === 'wrapped-text') {\n selector.appendChild(\n document.createTextNode(String(this._editedValue))\n );\n } else {\n selector.appendChild(document.createElement('slot'));\n }\n shadow.appendChild(selector);\n }\n\n this._renderState = state;\n }\n}\n\nexport const defineIntlayerContentSelectorWrapper = (): void => {\n if (typeof customElements === 'undefined') return;\n\n if (!customElements.get('intlayer-content-selector-wrapper')) {\n customElements.define(\n 'intlayer-content-selector-wrapper',\n IntlayerContentSelectorWrapperElement\n );\n }\n};\n"],"mappings":"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"}
|
|
@@ -126,8 +126,27 @@ var IntlayerContentSelectorWrapperElement = class extends _HTMLElement {
|
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
128
|
const keyPath = this._getFilteredKeyPath();
|
|
129
|
+
const wasSelected = this._isSelected;
|
|
129
130
|
this._isSelected = focusedContent.dictionaryKey === this._dictionaryKey && (focusedContent.keyPath?.length ?? 0) > 0 && isSameKeyPath(focusedContent.keyPath ?? [], keyPath);
|
|
130
131
|
this._updateSelectorAttr();
|
|
132
|
+
if (this._isSelected && !wasSelected) this._scrollIntoViewIfNeeded();
|
|
133
|
+
}
|
|
134
|
+
_scrollIntoViewIfNeeded() {
|
|
135
|
+
try {
|
|
136
|
+
let rect;
|
|
137
|
+
if (this.childNodes.length > 0) {
|
|
138
|
+
const range = document.createRange();
|
|
139
|
+
range.selectNode(this);
|
|
140
|
+
rect = range.getBoundingClientRect();
|
|
141
|
+
} else rect = this.getBoundingClientRect();
|
|
142
|
+
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
|
143
|
+
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
|
144
|
+
if (!(rect.width > 0 && rect.height > 0 && rect.bottom > 0 && rect.right > 0 && rect.top < viewportHeight && rect.left < viewportWidth)) (this.firstElementChild ?? this).scrollIntoView({
|
|
145
|
+
behavior: "smooth",
|
|
146
|
+
block: "nearest",
|
|
147
|
+
inline: "nearest"
|
|
148
|
+
});
|
|
149
|
+
} catch {}
|
|
131
150
|
}
|
|
132
151
|
_updateSelectorAttr() {
|
|
133
152
|
if (!this._selector) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentSelectorWrapper.mjs","names":["node"],"sources":["../../../src/components/ContentSelectorWrapper.ts"],"sourcesContent":["import { isSameKeyPath } from '@intlayer/core/utils';\n\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n EditorStateManager,\n FileContent,\n} from '../core/EditorStateManager';\nimport {\n getGlobalEditorManager,\n onGlobalEditorManagerChange,\n} from '../core/globalManager';\nimport { MessageKey } from '../messageKey';\n\ntype RenderState = 'simple' | 'wrapped-slot' | 'wrapped-text';\n\nconst _HTMLElement =\n typeof HTMLElement !== 'undefined'\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n/**\n * <intlayer-content-selector-wrapper>\n *\n * Framework-agnostic web component that wraps content with the Intlayer editor\n * selection UI. It replaces the per-framework ContentSelectorWrapper components\n * (Vue, Svelte, Solid, Preact).\n *\n * It reads from the global EditorStateManager singleton (set by initEditorClient)\n * and conditionally renders <intlayer-content-selector> around its slot content\n * when the editor is active and the app is running inside an iframe.\n *\n * @attr {string} key-path - JSON-serialized KeyPath[] for this content node\n * @attr {string} dictionary-key - The dictionary key owning this content node\n */\nexport class IntlayerContentSelectorWrapperElement extends _HTMLElement {\n private _keyPathJson = '[]';\n private _dictionaryKey = '';\n private _editorEnabled = false;\n private _isInIframe = false;\n private _isSelected = false;\n private _editedValue: ContentNode | undefined = undefined;\n\n private _renderState: RenderState | null = null;\n private _selector: HTMLElement | null = null;\n\n private _unsubManager: (() => void) | null = null;\n private _unsubEnabled: (() => void) | null = null;\n private _unsubFocused: (() => void) | null = null;\n private _unsubEditedContent: (() => void) | null = null;\n\n static get observedAttributes(): string[] {\n return ['key-path', 'dictionary-key'];\n }\n\n get keyPathJson(): string {\n return this._keyPathJson;\n }\n set keyPathJson(v: string) {\n this._keyPathJson = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n get dictionaryKey(): string {\n return this._dictionaryKey;\n }\n set dictionaryKey(v: string) {\n this._dictionaryKey = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = ':host { display: contents; }';\n shadow.appendChild(style);\n }\n\n attributeChangedCallback(\n name: string,\n _oldVal: string | null,\n newVal: string | null\n ): void {\n if (name === 'key-path') {\n this._keyPathJson = newVal ?? '[]';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n } else if (name === 'dictionary-key') {\n this._dictionaryKey = newVal ?? '';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n }\n\n connectedCallback(): void {\n if (typeof window !== 'undefined') {\n this._isInIframe = window.self !== window.top;\n }\n this._subscribeToManager();\n this._render();\n }\n\n disconnectedCallback(): void {\n this._teardown();\n }\n\n private _teardown(): void {\n this._unsubManager?.();\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubManager = null;\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n }\n\n private _getRawKeyPath(): KeyPath[] {\n try {\n return JSON.parse(this._keyPathJson) as KeyPath[];\n } catch {\n return [];\n }\n }\n\n private _getFilteredKeyPath(): KeyPath[] {\n return this._getRawKeyPath().filter(\n (keyPath) => keyPath.type !== NodeTypes.TRANSLATION\n );\n }\n\n private _updateEditedValue(manager: EditorStateManager): void {\n const filteredKeyPath = this._getFilteredKeyPath();\n if (!this._dictionaryKey || filteredKeyPath.length === 0) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n // Node types whose display requires framework-level rendering (markdown,\n // HTML, insertion, file): do not override the slot — the framework handles\n // those. Only plain / translated strings can be substituted here.\n const rawKeyPath = this._getRawKeyPath();\n const lastStepType = rawKeyPath[rawKeyPath.length - 1]?.type;\n if (\n lastStepType === NodeTypes.MARKDOWN ||\n lastStepType === NodeTypes.HTML ||\n lastStepType === NodeTypes.INSERTION ||\n lastStepType === NodeTypes.FILE\n ) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n let value = manager.getContentValue(this._dictionaryKey, filteredKeyPath);\n\n // getContentNodeByKeyPath resolves translation nodes only at intermediate\n // steps, not the final leaf. Resolve manually when the returned value is\n // still a translation object (happens when Translation steps are filtered\n // out and the leaf IS the translation object).\n if (\n value !== null &&\n value !== undefined &&\n typeof value === 'object' &&\n (value as { nodeType?: unknown }).nodeType === NodeTypes.TRANSLATION\n ) {\n const locale = manager.currentLocale.value as string | undefined;\n // TypedNodeModel<Translation, …> structurally satisfies TypedNode<BaseNode>\n // (both have nodeType), so this narrowing cast is sound.\n const node = value as TypedNodeModel<\n typeof NodeTypes.TRANSLATION,\n Record<string, ContentNode>\n >;\n value = locale ? node[NodeTypes.TRANSLATION][locale] : undefined;\n }\n\n this._editedValue = value;\n this._render();\n }\n\n private _updateIsSelected(\n focusedContent: FileContent | null | undefined\n ): void {\n if (!focusedContent) {\n this._isSelected = false;\n this._updateSelectorAttr();\n return;\n }\n const keyPath = this._getFilteredKeyPath();\n this._isSelected =\n focusedContent.dictionaryKey === this._dictionaryKey &&\n (focusedContent.keyPath?.length ?? 0) > 0 &&\n isSameKeyPath(focusedContent.keyPath ?? [], keyPath);\n this._updateSelectorAttr();\n }\n\n private _updateSelectorAttr(): void {\n if (!this._selector) return;\n if (this._isSelected) {\n this._selector.setAttribute('is-selecting', '');\n } else {\n this._selector.removeAttribute('is-selecting');\n }\n }\n\n private _subscribeToManager(): void {\n const manager = getGlobalEditorManager();\n if (manager) {\n this._setupManagerSubscriptions(manager);\n }\n // Keep listening for manager changes (handles stop + re-init cycles)\n this._unsubManager = onGlobalEditorManagerChange((m) => {\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n if (m) {\n this._setupManagerSubscriptions(m);\n } else {\n this._editorEnabled = false;\n this._isSelected = false;\n this._editedValue = undefined;\n this._render();\n }\n });\n }\n\n private _setupManagerSubscriptions(manager: EditorStateManager): void {\n this._editorEnabled = manager.editorEnabled.value ?? false;\n this._updateIsSelected(manager.focusedContent.value);\n this._updateEditedValue(manager);\n\n const handleEnabledChange = (e: Event) => {\n this._editorEnabled = (e as CustomEvent<boolean>).detail;\n this._render();\n };\n const handleFocusedChange = (e: Event) => {\n this._updateIsSelected((e as CustomEvent<FileContent | null>).detail);\n };\n const handleEditedContentChange = () => {\n this._updateEditedValue(manager);\n };\n\n manager.editorEnabled.addEventListener('change', handleEnabledChange);\n manager.focusedContent.addEventListener('change', handleFocusedChange);\n manager.editedContent.addEventListener('change', handleEditedContentChange);\n\n this._unsubEnabled = () =>\n manager.editorEnabled.removeEventListener('change', handleEnabledChange);\n this._unsubFocused = () =>\n manager.focusedContent.removeEventListener('change', handleFocusedChange);\n this._unsubEditedContent = () =>\n manager.editedContent.removeEventListener(\n 'change',\n handleEditedContentChange\n );\n }\n\n private _handlePress(e: Event): void {\n // Stop propagation so nested wrappers don't also fire (composed + bubbles)\n e.stopPropagation();\n const manager = getGlobalEditorManager();\n if (!manager) return;\n manager.focusedContent.set({\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n });\n }\n\n private _handleHover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n {\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n }\n );\n }\n\n private _handleUnhover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n null\n );\n }\n\n private _render(): void {\n const useWrapper = this._isInIframe && this._editorEnabled;\n const editedValue = this._editedValue;\n const isSimpleValue =\n typeof editedValue === 'string' ||\n typeof editedValue === 'number' ||\n typeof editedValue === 'boolean';\n\n const newState: RenderState = !useWrapper\n ? 'simple'\n : isSimpleValue\n ? 'wrapped-text'\n : 'wrapped-slot';\n\n if (this._renderState !== newState) {\n this._rebuildContent(newState);\n return;\n }\n\n // Structure unchanged — update only dynamic parts\n if (newState !== 'simple' && this._selector) {\n this._updateSelectorAttr();\n if (\n newState === 'wrapped-text' &&\n this._selector.firstChild?.nodeType === Node.TEXT_NODE\n ) {\n (this._selector.firstChild as Text).data = String(editedValue);\n }\n }\n }\n\n private _rebuildContent(state: RenderState): void {\n const shadow = this.shadowRoot!;\n // Remove all nodes except the style element (first child)\n while (shadow.childNodes.length > 1) {\n shadow.removeChild(shadow.lastChild!);\n }\n this._selector = null;\n\n if (state === 'simple') {\n shadow.appendChild(document.createElement('slot'));\n } else {\n const selector = document.createElement('intlayer-content-selector');\n this._selector = selector;\n if (this._isSelected) selector.setAttribute('is-selecting', '');\n selector.addEventListener('intlayer:press', (e) => this._handlePress(e));\n selector.addEventListener('intlayer:hover', (e) => this._handleHover(e));\n selector.addEventListener('intlayer:unhover', (e) =>\n this._handleUnhover(e)\n );\n\n if (state === 'wrapped-text') {\n selector.appendChild(\n document.createTextNode(String(this._editedValue))\n );\n } else {\n selector.appendChild(document.createElement('slot'));\n }\n shadow.appendChild(selector);\n }\n\n this._renderState = state;\n }\n}\n\nexport const defineIntlayerContentSelectorWrapper = (): void => {\n if (typeof customElements === 'undefined') return;\n\n if (!customElements.get('intlayer-content-selector-wrapper')) {\n customElements.define(\n 'intlayer-content-selector-wrapper',\n IntlayerContentSelectorWrapperElement\n );\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ContentSelectorWrapper.mjs","names":["node"],"sources":["../../../src/components/ContentSelectorWrapper.ts"],"sourcesContent":["import { isSameKeyPath } from '@intlayer/core/utils';\n\nimport type { ContentNode } from '@intlayer/types/dictionary';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n EditorStateManager,\n FileContent,\n} from '../core/EditorStateManager';\nimport {\n getGlobalEditorManager,\n onGlobalEditorManagerChange,\n} from '../core/globalManager';\nimport { MessageKey } from '../messageKey';\n\ntype RenderState = 'simple' | 'wrapped-slot' | 'wrapped-text';\n\nconst _HTMLElement =\n typeof HTMLElement !== 'undefined'\n ? HTMLElement\n : (class {} as unknown as typeof HTMLElement);\n\n/**\n * <intlayer-content-selector-wrapper>\n *\n * Framework-agnostic web component that wraps content with the Intlayer editor\n * selection UI. It replaces the per-framework ContentSelectorWrapper components\n * (Vue, Svelte, Solid, Preact).\n *\n * It reads from the global EditorStateManager singleton (set by initEditorClient)\n * and conditionally renders <intlayer-content-selector> around its slot content\n * when the editor is active and the app is running inside an iframe.\n *\n * @attr {string} key-path - JSON-serialized KeyPath[] for this content node\n * @attr {string} dictionary-key - The dictionary key owning this content node\n */\nexport class IntlayerContentSelectorWrapperElement extends _HTMLElement {\n private _keyPathJson = '[]';\n private _dictionaryKey = '';\n private _editorEnabled = false;\n private _isInIframe = false;\n private _isSelected = false;\n private _editedValue: ContentNode | undefined = undefined;\n\n private _renderState: RenderState | null = null;\n private _selector: HTMLElement | null = null;\n\n private _unsubManager: (() => void) | null = null;\n private _unsubEnabled: (() => void) | null = null;\n private _unsubFocused: (() => void) | null = null;\n private _unsubEditedContent: (() => void) | null = null;\n\n static get observedAttributes(): string[] {\n return ['key-path', 'dictionary-key'];\n }\n\n get keyPathJson(): string {\n return this._keyPathJson;\n }\n set keyPathJson(v: string) {\n this._keyPathJson = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n get dictionaryKey(): string {\n return this._dictionaryKey;\n }\n set dictionaryKey(v: string) {\n this._dictionaryKey = v;\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = ':host { display: contents; }';\n shadow.appendChild(style);\n }\n\n attributeChangedCallback(\n name: string,\n _oldVal: string | null,\n newVal: string | null\n ): void {\n if (name === 'key-path') {\n this._keyPathJson = newVal ?? '[]';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n } else if (name === 'dictionary-key') {\n this._dictionaryKey = newVal ?? '';\n const manager = getGlobalEditorManager();\n if (manager) this._updateEditedValue(manager);\n }\n }\n\n connectedCallback(): void {\n if (typeof window !== 'undefined') {\n this._isInIframe = window.self !== window.top;\n }\n this._subscribeToManager();\n this._render();\n }\n\n disconnectedCallback(): void {\n this._teardown();\n }\n\n private _teardown(): void {\n this._unsubManager?.();\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubManager = null;\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n }\n\n private _getRawKeyPath(): KeyPath[] {\n try {\n return JSON.parse(this._keyPathJson) as KeyPath[];\n } catch {\n return [];\n }\n }\n\n private _getFilteredKeyPath(): KeyPath[] {\n return this._getRawKeyPath().filter(\n (keyPath) => keyPath.type !== NodeTypes.TRANSLATION\n );\n }\n\n private _updateEditedValue(manager: EditorStateManager): void {\n const filteredKeyPath = this._getFilteredKeyPath();\n if (!this._dictionaryKey || filteredKeyPath.length === 0) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n // Node types whose display requires framework-level rendering (markdown,\n // HTML, insertion, file): do not override the slot — the framework handles\n // those. Only plain / translated strings can be substituted here.\n const rawKeyPath = this._getRawKeyPath();\n const lastStepType = rawKeyPath[rawKeyPath.length - 1]?.type;\n if (\n lastStepType === NodeTypes.MARKDOWN ||\n lastStepType === NodeTypes.HTML ||\n lastStepType === NodeTypes.INSERTION ||\n lastStepType === NodeTypes.FILE\n ) {\n this._editedValue = undefined;\n this._render();\n return;\n }\n\n let value = manager.getContentValue(this._dictionaryKey, filteredKeyPath);\n\n // getContentNodeByKeyPath resolves translation nodes only at intermediate\n // steps, not the final leaf. Resolve manually when the returned value is\n // still a translation object (happens when Translation steps are filtered\n // out and the leaf IS the translation object).\n if (\n value !== null &&\n value !== undefined &&\n typeof value === 'object' &&\n (value as { nodeType?: unknown }).nodeType === NodeTypes.TRANSLATION\n ) {\n const locale = manager.currentLocale.value as string | undefined;\n // TypedNodeModel<Translation, …> structurally satisfies TypedNode<BaseNode>\n // (both have nodeType), so this narrowing cast is sound.\n const node = value as TypedNodeModel<\n typeof NodeTypes.TRANSLATION,\n Record<string, ContentNode>\n >;\n value = locale ? node[NodeTypes.TRANSLATION][locale] : undefined;\n }\n\n this._editedValue = value;\n this._render();\n }\n\n private _updateIsSelected(\n focusedContent: FileContent | null | undefined\n ): void {\n if (!focusedContent) {\n this._isSelected = false;\n this._updateSelectorAttr();\n return;\n }\n const keyPath = this._getFilteredKeyPath();\n const wasSelected = this._isSelected;\n this._isSelected =\n focusedContent.dictionaryKey === this._dictionaryKey &&\n (focusedContent.keyPath?.length ?? 0) > 0 &&\n isSameKeyPath(focusedContent.keyPath ?? [], keyPath);\n this._updateSelectorAttr();\n\n // Scroll into view when this element becomes selected and is not already\n // visible in the iframe viewport. This covers the case where the editor\n // focuses a content block that is off-screen in the client app.\n if (this._isSelected && !wasSelected) {\n this._scrollIntoViewIfNeeded();\n }\n }\n\n private _scrollIntoViewIfNeeded(): void {\n try {\n // this element has display:contents so getBoundingClientRect() returns\n // all zeros. Use a Range over its children to get the real visual bounds.\n let rect: DOMRect;\n if (this.childNodes.length > 0) {\n const range = document.createRange();\n range.selectNode(this);\n rect = range.getBoundingClientRect();\n } else {\n rect = this.getBoundingClientRect();\n }\n\n const viewportHeight =\n window.innerHeight || document.documentElement.clientHeight;\n const viewportWidth =\n window.innerWidth || document.documentElement.clientWidth;\n\n const isVisible =\n rect.width > 0 &&\n rect.height > 0 &&\n rect.bottom > 0 &&\n rect.right > 0 &&\n rect.top < viewportHeight &&\n rect.left < viewportWidth;\n\n if (!isVisible) {\n // Scroll the first real child into view — display:contents hosts have no\n // box of their own and browsers may ignore scrollIntoView on them.\n const scrollTarget =\n (this.firstElementChild as Element | null) ?? this;\n scrollTarget.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n }\n } catch {\n // scrollIntoView may not be available in all environments\n }\n }\n\n private _updateSelectorAttr(): void {\n if (!this._selector) return;\n if (this._isSelected) {\n this._selector.setAttribute('is-selecting', '');\n } else {\n this._selector.removeAttribute('is-selecting');\n }\n }\n\n private _subscribeToManager(): void {\n const manager = getGlobalEditorManager();\n if (manager) {\n this._setupManagerSubscriptions(manager);\n }\n // Keep listening for manager changes (handles stop + re-init cycles)\n this._unsubManager = onGlobalEditorManagerChange((m) => {\n this._unsubEnabled?.();\n this._unsubFocused?.();\n this._unsubEditedContent?.();\n this._unsubEnabled = null;\n this._unsubFocused = null;\n this._unsubEditedContent = null;\n if (m) {\n this._setupManagerSubscriptions(m);\n } else {\n this._editorEnabled = false;\n this._isSelected = false;\n this._editedValue = undefined;\n this._render();\n }\n });\n }\n\n private _setupManagerSubscriptions(manager: EditorStateManager): void {\n this._editorEnabled = manager.editorEnabled.value ?? false;\n this._updateIsSelected(manager.focusedContent.value);\n this._updateEditedValue(manager);\n\n const handleEnabledChange = (e: Event) => {\n this._editorEnabled = (e as CustomEvent<boolean>).detail;\n this._render();\n };\n const handleFocusedChange = (e: Event) => {\n this._updateIsSelected((e as CustomEvent<FileContent | null>).detail);\n };\n const handleEditedContentChange = () => {\n this._updateEditedValue(manager);\n };\n\n manager.editorEnabled.addEventListener('change', handleEnabledChange);\n manager.focusedContent.addEventListener('change', handleFocusedChange);\n manager.editedContent.addEventListener('change', handleEditedContentChange);\n\n this._unsubEnabled = () =>\n manager.editorEnabled.removeEventListener('change', handleEnabledChange);\n this._unsubFocused = () =>\n manager.focusedContent.removeEventListener('change', handleFocusedChange);\n this._unsubEditedContent = () =>\n manager.editedContent.removeEventListener(\n 'change',\n handleEditedContentChange\n );\n }\n\n private _handlePress(e: Event): void {\n // Stop propagation so nested wrappers don't also fire (composed + bubbles)\n e.stopPropagation();\n const manager = getGlobalEditorManager();\n if (!manager) return;\n manager.focusedContent.set({\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n });\n }\n\n private _handleHover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n {\n dictionaryKey: this._dictionaryKey,\n keyPath: this._getFilteredKeyPath(),\n }\n );\n }\n\n private _handleUnhover(e: Event): void {\n e.stopPropagation();\n getGlobalEditorManager()?.messenger.send(\n `${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,\n null\n );\n }\n\n private _render(): void {\n const useWrapper = this._isInIframe && this._editorEnabled;\n const editedValue = this._editedValue;\n const isSimpleValue =\n typeof editedValue === 'string' ||\n typeof editedValue === 'number' ||\n typeof editedValue === 'boolean';\n\n const newState: RenderState = !useWrapper\n ? 'simple'\n : isSimpleValue\n ? 'wrapped-text'\n : 'wrapped-slot';\n\n if (this._renderState !== newState) {\n this._rebuildContent(newState);\n return;\n }\n\n // Structure unchanged — update only dynamic parts\n if (newState !== 'simple' && this._selector) {\n this._updateSelectorAttr();\n if (\n newState === 'wrapped-text' &&\n this._selector.firstChild?.nodeType === Node.TEXT_NODE\n ) {\n (this._selector.firstChild as Text).data = String(editedValue);\n }\n }\n }\n\n private _rebuildContent(state: RenderState): void {\n const shadow = this.shadowRoot!;\n // Remove all nodes except the style element (first child)\n while (shadow.childNodes.length > 1) {\n shadow.removeChild(shadow.lastChild!);\n }\n this._selector = null;\n\n if (state === 'simple') {\n shadow.appendChild(document.createElement('slot'));\n } else {\n const selector = document.createElement('intlayer-content-selector');\n this._selector = selector;\n if (this._isSelected) selector.setAttribute('is-selecting', '');\n selector.addEventListener('intlayer:press', (e) => this._handlePress(e));\n selector.addEventListener('intlayer:hover', (e) => this._handleHover(e));\n selector.addEventListener('intlayer:unhover', (e) =>\n this._handleUnhover(e)\n );\n\n if (state === 'wrapped-text') {\n selector.appendChild(\n document.createTextNode(String(this._editedValue))\n );\n } else {\n selector.appendChild(document.createElement('slot'));\n }\n shadow.appendChild(selector);\n }\n\n this._renderState = state;\n }\n}\n\nexport const defineIntlayerContentSelectorWrapper = (): void => {\n if (typeof customElements === 'undefined') return;\n\n if (!customElements.get('intlayer-content-selector-wrapper')) {\n customElements.define(\n 'intlayer-content-selector-wrapper',\n IntlayerContentSelectorWrapperElement\n );\n }\n};\n"],"mappings":"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"}
|
|
@@ -44,6 +44,7 @@ declare class IntlayerContentSelectorWrapperElement extends _HTMLElement {
|
|
|
44
44
|
private _getFilteredKeyPath;
|
|
45
45
|
private _updateEditedValue;
|
|
46
46
|
private _updateIsSelected;
|
|
47
|
+
private _scrollIntoViewIfNeeded;
|
|
47
48
|
private _updateSelectorAttr;
|
|
48
49
|
private _subscribeToManager;
|
|
49
50
|
private _setupManagerSubscriptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentSelectorWrapper.d.ts","names":[],"sources":["../../../src/components/ContentSelectorWrapper.ts"],"mappings":";cAkBM,YAAA;EAAA,QAG2C,WAAA;aAAA,WAAA;AAAA;;;;;;;AAgBjD;;;;;;;;cAAa,qCAAA,SAA8C,YAAY;EAAA,QAC7D,YAAA;EAAA,QACA,cAAA;EAAA,QACA,cAAA;EAAA,QACA,WAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QAEA,YAAA;EAAA,QACA,SAAA;EAAA,QAEA,aAAA;EAAA,QACA,aAAA;EAAA,QACA,aAAA;EAAA,QACA,mBAAA;EAAA,WAEG,kBAAA,CAAA;EAAA,IAIP,WAAA,CAAA;EAAA,IAGA,WAAA,CAAY,CAAA;EAAA,IAMZ,aAAA,CAAA;EAAA,IAGA,aAAA,CAAc,CAAA;;EAclB,wBAAA,CACE,IAAA,UACA,OAAA,iBACA,MAAA;EAaF,iBAAA,CAAA;EAQA,oBAAA,CAAA;EAAA,QAIQ,SAAA;EAAA,QAWA,cAAA;EAAA,QAQA,mBAAA;EAAA,QAMA,kBAAA;EAAA,QAkDA,iBAAA;EAAA,
|
|
1
|
+
{"version":3,"file":"ContentSelectorWrapper.d.ts","names":[],"sources":["../../../src/components/ContentSelectorWrapper.ts"],"mappings":";cAkBM,YAAA;EAAA,QAG2C,WAAA;aAAA,WAAA;AAAA;;;;;;;AAgBjD;;;;;;;;cAAa,qCAAA,SAA8C,YAAY;EAAA,QAC7D,YAAA;EAAA,QACA,cAAA;EAAA,QACA,cAAA;EAAA,QACA,WAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EAAA,QAEA,YAAA;EAAA,QACA,SAAA;EAAA,QAEA,aAAA;EAAA,QACA,aAAA;EAAA,QACA,aAAA;EAAA,QACA,mBAAA;EAAA,WAEG,kBAAA,CAAA;EAAA,IAIP,WAAA,CAAA;EAAA,IAGA,WAAA,CAAY,CAAA;EAAA,IAMZ,aAAA,CAAA;EAAA,IAGA,aAAA,CAAc,CAAA;;EAclB,wBAAA,CACE,IAAA,UACA,OAAA,iBACA,MAAA;EAaF,iBAAA,CAAA;EAQA,oBAAA,CAAA;EAAA,QAIQ,SAAA;EAAA,QAWA,cAAA;EAAA,QAQA,mBAAA;EAAA,QAMA,kBAAA;EAAA,QAkDA,iBAAA;EAAA,QAwBA,uBAAA;EAAA,QA0CA,mBAAA;EAAA,QASA,mBAAA;EAAA,QAwBA,0BAAA;EAAA,QA+BA,YAAA;EAAA,QAWA,YAAA;EAAA,QAWA,cAAA;EAAA,QAQA,OAAA;EAAA,QA+BA,eAAA;AAAA;AAAA,cAkCG,oCAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/editor",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.11.0-canary.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Provides the utilities to interface the application with the Intlayer editor and manipulate dictionaries",
|
|
6
6
|
"keywords": [
|
|
@@ -75,10 +75,10 @@
|
|
|
75
75
|
"typecheck": "tsc --noEmit --project tsconfig.types.json"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@intlayer/config": "8.
|
|
79
|
-
"@intlayer/core": "8.
|
|
80
|
-
"@intlayer/types": "8.
|
|
81
|
-
"@intlayer/unmerged-dictionaries-entry": "8.
|
|
78
|
+
"@intlayer/config": "8.11.0-canary.0",
|
|
79
|
+
"@intlayer/core": "8.11.0-canary.0",
|
|
80
|
+
"@intlayer/types": "8.11.0-canary.0",
|
|
81
|
+
"@intlayer/unmerged-dictionaries-entry": "8.11.0-canary.0"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@types/node": "25.9.1",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"rimraf": "6.1.3",
|
|
89
89
|
"tsdown": "0.22.00",
|
|
90
90
|
"typescript": "6.0.3",
|
|
91
|
-
"vitest": "4.1.
|
|
91
|
+
"vitest": "4.1.7"
|
|
92
92
|
},
|
|
93
93
|
"engines": {
|
|
94
94
|
"node": ">=14.18"
|