@intlayer/editor 8.4.4 → 8.4.5
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/_virtual/_@oxc-project_runtime@0.115.0/helpers/decorate.cjs +11 -0
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/cjs/compareUrls.cjs +39 -1
- package/dist/cjs/compareUrls.cjs.map +1 -1
- package/dist/cjs/components/ContentSelector.cjs +168 -1
- package/dist/cjs/components/ContentSelector.cjs.map +1 -0
- package/dist/cjs/components/ContentSelectorWrapper.cjs +193 -4
- package/dist/cjs/components/ContentSelectorWrapper.cjs.map +1 -1
- package/dist/cjs/components/EditedContent.cjs +128 -4
- package/dist/cjs/components/EditedContent.cjs.map +1 -1
- package/dist/cjs/components/IntlayerEditor.cjs +87 -1
- package/dist/cjs/components/IntlayerEditor.cjs.map +1 -0
- package/dist/cjs/components/index.cjs +14 -1
- package/dist/cjs/core/CrossFrameMessenger.cjs +77 -1
- package/dist/cjs/core/CrossFrameMessenger.cjs.map +1 -1
- package/dist/cjs/core/CrossFrameStateManager.cjs +71 -1
- package/dist/cjs/core/CrossFrameStateManager.cjs.map +1 -1
- package/dist/cjs/core/EditorStateManager.cjs +258 -1
- package/dist/cjs/core/EditorStateManager.cjs.map +1 -1
- package/dist/cjs/core/IframeClickInterceptor.cjs +45 -1
- package/dist/cjs/core/IframeClickInterceptor.cjs.map +1 -1
- package/dist/cjs/core/UrlStateManager.cjs +59 -1
- package/dist/cjs/core/UrlStateManager.cjs.map +1 -1
- package/dist/cjs/core/globalManager.cjs +82 -1
- package/dist/cjs/core/globalManager.cjs.map +1 -1
- package/dist/cjs/core/index.cjs +20 -1
- package/dist/cjs/core/initEditorClient.cjs +58 -1
- package/dist/cjs/core/initEditorClient.cjs.map +1 -0
- package/dist/cjs/index.cjs +38 -1
- package/dist/cjs/isEnabled.cjs +10 -1
- package/dist/cjs/isEnabled.cjs.map +1 -1
- package/dist/cjs/mergeIframeClick.cjs +22 -1
- package/dist/cjs/mergeIframeClick.cjs.map +1 -1
- package/dist/cjs/messageKey.cjs +30 -1
- package/dist/cjs/messageKey.cjs.map +1 -1
- package/dist/esm/_virtual/_@oxc-project_runtime@0.115.0/helpers/decorate.mjs +10 -0
- package/dist/esm/compareUrls.mjs +37 -1
- package/dist/esm/compareUrls.mjs.map +1 -1
- package/dist/esm/components/ContentSelector.mjs +165 -1
- package/dist/esm/components/ContentSelector.mjs.map +1 -0
- package/dist/esm/components/ContentSelectorWrapper.mjs +189 -4
- package/dist/esm/components/ContentSelectorWrapper.mjs.map +1 -1
- package/dist/esm/components/EditedContent.mjs +125 -4
- package/dist/esm/components/EditedContent.mjs.map +1 -1
- package/dist/esm/components/IntlayerEditor.mjs +84 -1
- package/dist/esm/components/IntlayerEditor.mjs.map +1 -0
- package/dist/esm/components/index.mjs +6 -1
- package/dist/esm/core/CrossFrameMessenger.mjs +76 -1
- package/dist/esm/core/CrossFrameMessenger.mjs.map +1 -1
- package/dist/esm/core/CrossFrameStateManager.mjs +69 -1
- package/dist/esm/core/CrossFrameStateManager.mjs.map +1 -1
- package/dist/esm/core/EditorStateManager.mjs +255 -1
- package/dist/esm/core/EditorStateManager.mjs.map +1 -1
- package/dist/esm/core/IframeClickInterceptor.mjs +44 -1
- package/dist/esm/core/IframeClickInterceptor.mjs.map +1 -1
- package/dist/esm/core/UrlStateManager.mjs +58 -1
- package/dist/esm/core/UrlStateManager.mjs.map +1 -1
- package/dist/esm/core/globalManager.mjs +78 -1
- package/dist/esm/core/globalManager.mjs.map +1 -1
- package/dist/esm/core/index.mjs +9 -1
- package/dist/esm/core/initEditorClient.mjs +53 -1
- package/dist/esm/core/initEditorClient.mjs.map +1 -0
- package/dist/esm/index.mjs +16 -1
- package/dist/esm/isEnabled.mjs +7 -1
- package/dist/esm/isEnabled.mjs.map +1 -1
- package/dist/esm/mergeIframeClick.mjs +20 -1
- package/dist/esm/mergeIframeClick.mjs.map +1 -1
- package/dist/esm/messageKey.mjs +28 -1
- package/dist/esm/messageKey.mjs.map +1 -1
- package/dist/types/components/ContentSelector.d.ts +49 -2
- package/dist/types/components/ContentSelector.d.ts.map +1 -0
- package/dist/types/components/ContentSelectorWrapper.d.ts +49 -2
- package/dist/types/components/ContentSelectorWrapper.d.ts.map +1 -0
- package/dist/types/components/EditedContent.d.ts +39 -2
- package/dist/types/components/EditedContent.d.ts.map +1 -0
- package/dist/types/components/IntlayerEditor.d.ts +40 -2
- package/dist/types/components/IntlayerEditor.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +4 -4
- package/dist/types/core/CrossFrameMessenger.d.ts +51 -2
- package/dist/types/core/CrossFrameMessenger.d.ts.map +1 -0
- package/dist/types/core/CrossFrameStateManager.d.ts +44 -2
- package/dist/types/core/CrossFrameStateManager.d.ts.map +1 -0
- package/dist/types/core/EditorStateManager.d.ts +73 -2
- package/dist/types/core/EditorStateManager.d.ts.map +1 -0
- package/dist/types/core/IframeClickInterceptor.d.ts +26 -2
- package/dist/types/core/IframeClickInterceptor.d.ts.map +1 -0
- package/dist/types/core/UrlStateManager.d.ts +21 -2
- package/dist/types/core/UrlStateManager.d.ts.map +1 -0
- package/dist/types/core/globalManager.d.ts +39 -2
- package/dist/types/core/globalManager.d.ts.map +1 -0
- package/dist/types/core/index.d.ts +7 -7
- package/dist/types/core/initEditorClient.d.ts +20 -2
- package/dist/types/core/initEditorClient.d.ts.map +1 -0
- package/dist/types/index.d.ts +11 -11
- package/package.json +5 -5
- package/dist/cjs/chunk-Bmb41Sf3.cjs +0 -1
- package/dist/cjs/components-DWu35JEb.cjs +0 -41
- package/dist/cjs/components-DWu35JEb.cjs.map +0 -1
- package/dist/cjs/decorate-Bg73f0d3.cjs +0 -1
- package/dist/esm/components-RtOXxg9h.mjs +0 -41
- package/dist/esm/components-RtOXxg9h.mjs.map +0 -1
- package/dist/esm/decorate-BWURH4oJ.mjs +0 -1
- package/dist/types/ContentSelector-sIfZu4Dd.d.ts +0 -49
- package/dist/types/ContentSelector-sIfZu4Dd.d.ts.map +0 -1
- package/dist/types/ContentSelectorWrapper-CID6anMf.d.ts +0 -49
- package/dist/types/ContentSelectorWrapper-CID6anMf.d.ts.map +0 -1
- package/dist/types/CrossFrameMessenger-CPt3Bu8S.d.ts +0 -51
- package/dist/types/CrossFrameMessenger-CPt3Bu8S.d.ts.map +0 -1
- package/dist/types/CrossFrameStateManager-CW1DPY_Z.d.ts +0 -44
- package/dist/types/CrossFrameStateManager-CW1DPY_Z.d.ts.map +0 -1
- package/dist/types/EditedContent-2kq4wk4R.d.ts +0 -39
- package/dist/types/EditedContent-2kq4wk4R.d.ts.map +0 -1
- package/dist/types/EditorStateManager-Y9j0SYCd.d.ts +0 -73
- package/dist/types/EditorStateManager-Y9j0SYCd.d.ts.map +0 -1
- package/dist/types/IframeClickInterceptor-Cm89LRcI.d.ts +0 -26
- package/dist/types/IframeClickInterceptor-Cm89LRcI.d.ts.map +0 -1
- package/dist/types/IntlayerEditor-ePRSIuBI.d.ts +0 -40
- package/dist/types/IntlayerEditor-ePRSIuBI.d.ts.map +0 -1
- package/dist/types/UrlStateManager-CIOVEeTq.d.ts +0 -21
- package/dist/types/UrlStateManager-CIOVEeTq.d.ts.map +0 -1
- package/dist/types/globalManager-BD6UaK_1.d.ts +0 -39
- package/dist/types/globalManager-BD6UaK_1.d.ts.map +0 -1
- package/dist/types/initEditorClient-ovRVUf_n.d.ts +0 -20
- package/dist/types/initEditorClient-ovRVUf_n.d.ts.map +0 -1
|
@@ -1,13 +1,137 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_core_globalManager = require('../core/globalManager.cjs');
|
|
4
|
+
const require_decorate = require('../_virtual/_@oxc-project_runtime@0.115.0/helpers/decorate.cjs');
|
|
5
|
+
let lit = require("lit");
|
|
6
|
+
let lit_decorators_js = require("lit/decorators.js");
|
|
7
|
+
let _intlayer_core_interpreter = require("@intlayer/core/interpreter");
|
|
8
|
+
|
|
9
|
+
//#region src/components/EditedContent.ts
|
|
10
|
+
/**
|
|
11
|
+
* <intlayer-edited-content>
|
|
12
|
+
*
|
|
13
|
+
* Framework-agnostic Lit element that displays edited content from the Intlayer
|
|
14
|
+
* editor. When the editor has an edited value for the given dictionary key and
|
|
15
|
+
* key path, it renders the edited value; otherwise it renders the original
|
|
16
|
+
* content via a slot.
|
|
17
|
+
*
|
|
18
|
+
* Always wraps content in <intlayer-content-selector-wrapper> for selection UI.
|
|
19
|
+
*
|
|
20
|
+
* @attr {string} dictionary-key - The dictionary key owning this content node
|
|
21
|
+
* @attr {string} key-path - JSON-serialized KeyPath[] for this content node
|
|
22
|
+
* @attr {string} locale - The current locale string
|
|
23
|
+
*/
|
|
24
|
+
var IntlayerEditedContentElement = class extends lit.LitElement {
|
|
25
|
+
constructor(..._args) {
|
|
26
|
+
super(..._args);
|
|
27
|
+
this.dictionaryKey = "";
|
|
28
|
+
this.keyPathJson = "[]";
|
|
29
|
+
this.locale = "";
|
|
30
|
+
this._editedText = null;
|
|
31
|
+
this._unsubManager = null;
|
|
32
|
+
this._unsubEditedContent = null;
|
|
33
|
+
}
|
|
34
|
+
static {
|
|
35
|
+
this.styles = lit.css`
|
|
2
36
|
:host {
|
|
3
37
|
display: contents;
|
|
4
38
|
}
|
|
5
|
-
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
connectedCallback() {
|
|
42
|
+
super.connectedCallback();
|
|
43
|
+
this._subscribeToManager();
|
|
44
|
+
}
|
|
45
|
+
disconnectedCallback() {
|
|
46
|
+
super.disconnectedCallback();
|
|
47
|
+
this._teardown();
|
|
48
|
+
}
|
|
49
|
+
_teardown() {
|
|
50
|
+
this._unsubManager?.();
|
|
51
|
+
this._unsubEditedContent?.();
|
|
52
|
+
this._unsubManager = null;
|
|
53
|
+
this._unsubEditedContent = null;
|
|
54
|
+
}
|
|
55
|
+
_getKeyPath() {
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(this.keyPathJson);
|
|
58
|
+
} catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
_resolveEditedText(manager) {
|
|
63
|
+
const keyPath = this._getKeyPath();
|
|
64
|
+
const editedValue = manager.getContentValue(this.dictionaryKey, keyPath);
|
|
65
|
+
if (editedValue === void 0 || editedValue === null) {
|
|
66
|
+
this._editedText = null;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (typeof editedValue === "string" || typeof editedValue === "number") {
|
|
70
|
+
this._editedText = String(editedValue);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (typeof editedValue === "object") {
|
|
74
|
+
const locale = this.locale || void 0;
|
|
75
|
+
const transformed = (0, _intlayer_core_interpreter.getContent)(editedValue, {
|
|
76
|
+
locale,
|
|
77
|
+
dictionaryKey: this.dictionaryKey,
|
|
78
|
+
keyPath
|
|
79
|
+
}, (0, _intlayer_core_interpreter.getBasePlugins)(locale));
|
|
80
|
+
if (typeof transformed === "string" || typeof transformed === "number") this._editedText = String(transformed);
|
|
81
|
+
else {
|
|
82
|
+
console.error(`[intlayer-edited-content] Incorrect edited content format. Expected string. Value: ${JSON.stringify(transformed)}`);
|
|
83
|
+
this._editedText = null;
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this._editedText = null;
|
|
88
|
+
}
|
|
89
|
+
_setupManagerSubscriptions(manager) {
|
|
90
|
+
this._resolveEditedText(manager);
|
|
91
|
+
const handleChange = () => this._resolveEditedText(manager);
|
|
92
|
+
manager.editedContent.addEventListener("change", handleChange);
|
|
93
|
+
this._unsubEditedContent = () => manager.editedContent.removeEventListener("change", handleChange);
|
|
94
|
+
}
|
|
95
|
+
_subscribeToManager() {
|
|
96
|
+
const manager = require_core_globalManager.getGlobalEditorManager();
|
|
97
|
+
if (manager) this._setupManagerSubscriptions(manager);
|
|
98
|
+
this._unsubManager = require_core_globalManager.onGlobalEditorManagerChange((m) => {
|
|
99
|
+
this._unsubEditedContent?.();
|
|
100
|
+
this._unsubEditedContent = null;
|
|
101
|
+
if (m) this._setupManagerSubscriptions(m);
|
|
102
|
+
else this._editedText = null;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
render() {
|
|
106
|
+
return lit.html`
|
|
6
107
|
<intlayer-content-selector-wrapper
|
|
7
108
|
key-path=${this.keyPathJson}
|
|
8
109
|
dictionary-key=${this.dictionaryKey}
|
|
9
110
|
>
|
|
10
|
-
${this._editedText
|
|
111
|
+
${this._editedText !== null ? this._editedText : lit.html`<slot></slot>`}
|
|
11
112
|
</intlayer-content-selector-wrapper>
|
|
12
|
-
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
require_decorate.__decorate([(0, lit_decorators_js.property)({
|
|
117
|
+
type: String,
|
|
118
|
+
attribute: "dictionary-key"
|
|
119
|
+
})], IntlayerEditedContentElement.prototype, "dictionaryKey", void 0);
|
|
120
|
+
require_decorate.__decorate([(0, lit_decorators_js.property)({
|
|
121
|
+
type: String,
|
|
122
|
+
attribute: "key-path"
|
|
123
|
+
})], IntlayerEditedContentElement.prototype, "keyPathJson", void 0);
|
|
124
|
+
require_decorate.__decorate([(0, lit_decorators_js.property)({
|
|
125
|
+
type: String,
|
|
126
|
+
attribute: "locale"
|
|
127
|
+
})], IntlayerEditedContentElement.prototype, "locale", void 0);
|
|
128
|
+
require_decorate.__decorate([(0, lit_decorators_js.state)()], IntlayerEditedContentElement.prototype, "_editedText", void 0);
|
|
129
|
+
const defineIntlayerEditedContent = () => {
|
|
130
|
+
if (typeof customElements === "undefined") return;
|
|
131
|
+
if (!customElements.get("intlayer-edited-content")) customElements.define("intlayer-edited-content", IntlayerEditedContentElement);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
exports.IntlayerEditedContentElement = IntlayerEditedContentElement;
|
|
136
|
+
exports.defineIntlayerEditedContent = defineIntlayerEditedContent;
|
|
13
137
|
//# sourceMappingURL=EditedContent.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditedContent.cjs","names":["LitElement","getGlobalEditorManager","onGlobalEditorManagerChange"],"sources":["../../../src/components/EditedContent.ts"],"sourcesContent":["import { getBasePlugins, getContent } from '@intlayer/core/interpreter';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport { css, html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport type { EditorStateManager } from '../core/EditorStateManager';\nimport {\n getGlobalEditorManager,\n onGlobalEditorManagerChange,\n} from '../core/globalManager';\n\n/**\n * <intlayer-edited-content>\n *\n * Framework-agnostic Lit element that displays edited content from the Intlayer\n * editor. When the editor has an edited value for the given dictionary key and\n * key path, it renders the edited value; otherwise it renders the original\n * content via a slot.\n *\n * Always wraps content in <intlayer-content-selector-wrapper> for selection UI.\n *\n * @attr {string} dictionary-key - The dictionary key owning this content node\n * @attr {string} key-path - JSON-serialized KeyPath[] for this content node\n * @attr {string} locale - The current locale string\n */\nexport class IntlayerEditedContentElement extends LitElement {\n static styles = css`\n :host {\n display: contents;\n }\n `;\n\n @property({ type: String, attribute: 'dictionary-key' }) dictionaryKey = '';\n @property({ type: String, attribute: 'key-path' }) keyPathJson = '[]';\n @property({ type: String, attribute: 'locale' }) locale = '';\n\n @state() private _editedText: string | null = null;\n\n private _unsubManager: (() => void) | null = null;\n private _unsubEditedContent: (() => void) | null = null;\n\n connectedCallback(): void {\n super.connectedCallback();\n this._subscribeToManager();\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this._teardown();\n }\n\n private _teardown(): void {\n this._unsubManager?.();\n this._unsubEditedContent?.();\n this._unsubManager = null;\n this._unsubEditedContent = null;\n }\n\n private _getKeyPath(): KeyPath[] {\n try {\n return JSON.parse(this.keyPathJson);\n } catch {\n return [];\n }\n }\n\n private _resolveEditedText(manager: EditorStateManager): void {\n const keyPath = this._getKeyPath();\n const editedValue = manager.getContentValue(this.dictionaryKey, keyPath);\n\n if (editedValue === undefined || editedValue === null) {\n this._editedText = null;\n return;\n }\n\n if (typeof editedValue === 'string' || typeof editedValue === 'number') {\n this._editedText = String(editedValue);\n return;\n }\n\n if (typeof editedValue === 'object') {\n const locale = this.locale || undefined;\n const transformed = getContent(\n editedValue,\n {\n locale: locale as any,\n dictionaryKey: this.dictionaryKey,\n keyPath,\n },\n getBasePlugins(locale as any)\n );\n if (typeof transformed === 'string' || typeof transformed === 'number') {\n this._editedText = String(transformed);\n } else {\n console.error(\n `[intlayer-edited-content] Incorrect edited content format. Expected string. Value: ${JSON.stringify(transformed)}`\n );\n this._editedText = null;\n }\n return;\n }\n\n this._editedText = null;\n }\n\n private _setupManagerSubscriptions(manager: EditorStateManager): void {\n this._resolveEditedText(manager);\n\n const handleChange = () => this._resolveEditedText(manager);\n manager.editedContent.addEventListener('change', handleChange);\n\n this._unsubEditedContent = () =>\n manager.editedContent.removeEventListener('change', handleChange);\n }\n\n private _subscribeToManager(): void {\n const manager = getGlobalEditorManager();\n if (manager) {\n this._setupManagerSubscriptions(manager);\n }\n\n this._unsubManager = onGlobalEditorManagerChange((m) => {\n this._unsubEditedContent?.();\n this._unsubEditedContent = null;\n if (m) {\n this._setupManagerSubscriptions(m);\n } else {\n this._editedText = null;\n }\n });\n }\n\n render() {\n return html`\n <intlayer-content-selector-wrapper\n key-path=${this.keyPathJson}\n dictionary-key=${this.dictionaryKey}\n >\n ${this._editedText !== null ? this._editedText : html`<slot></slot>`}\n </intlayer-content-selector-wrapper>\n `;\n }\n}\n\nexport const defineIntlayerEditedContent = (): void => {\n if (typeof customElements === 'undefined') return;\n\n if (!customElements.get('intlayer-edited-content')) {\n customElements.define(\n 'intlayer-edited-content',\n IntlayerEditedContentElement\n );\n }\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"EditedContent.cjs","names":["LitElement","getGlobalEditorManager","onGlobalEditorManagerChange"],"sources":["../../../src/components/EditedContent.ts"],"sourcesContent":["import { getBasePlugins, getContent } from '@intlayer/core/interpreter';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport { css, html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport type { EditorStateManager } from '../core/EditorStateManager';\nimport {\n getGlobalEditorManager,\n onGlobalEditorManagerChange,\n} from '../core/globalManager';\n\n/**\n * <intlayer-edited-content>\n *\n * Framework-agnostic Lit element that displays edited content from the Intlayer\n * editor. When the editor has an edited value for the given dictionary key and\n * key path, it renders the edited value; otherwise it renders the original\n * content via a slot.\n *\n * Always wraps content in <intlayer-content-selector-wrapper> for selection UI.\n *\n * @attr {string} dictionary-key - The dictionary key owning this content node\n * @attr {string} key-path - JSON-serialized KeyPath[] for this content node\n * @attr {string} locale - The current locale string\n */\nexport class IntlayerEditedContentElement extends LitElement {\n static styles = css`\n :host {\n display: contents;\n }\n `;\n\n @property({ type: String, attribute: 'dictionary-key' }) dictionaryKey = '';\n @property({ type: String, attribute: 'key-path' }) keyPathJson = '[]';\n @property({ type: String, attribute: 'locale' }) locale = '';\n\n @state() private _editedText: string | null = null;\n\n private _unsubManager: (() => void) | null = null;\n private _unsubEditedContent: (() => void) | null = null;\n\n connectedCallback(): void {\n super.connectedCallback();\n this._subscribeToManager();\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this._teardown();\n }\n\n private _teardown(): void {\n this._unsubManager?.();\n this._unsubEditedContent?.();\n this._unsubManager = null;\n this._unsubEditedContent = null;\n }\n\n private _getKeyPath(): KeyPath[] {\n try {\n return JSON.parse(this.keyPathJson);\n } catch {\n return [];\n }\n }\n\n private _resolveEditedText(manager: EditorStateManager): void {\n const keyPath = this._getKeyPath();\n const editedValue = manager.getContentValue(this.dictionaryKey, keyPath);\n\n if (editedValue === undefined || editedValue === null) {\n this._editedText = null;\n return;\n }\n\n if (typeof editedValue === 'string' || typeof editedValue === 'number') {\n this._editedText = String(editedValue);\n return;\n }\n\n if (typeof editedValue === 'object') {\n const locale = this.locale || undefined;\n const transformed = getContent(\n editedValue,\n {\n locale: locale as any,\n dictionaryKey: this.dictionaryKey,\n keyPath,\n },\n getBasePlugins(locale as any)\n );\n if (typeof transformed === 'string' || typeof transformed === 'number') {\n this._editedText = String(transformed);\n } else {\n console.error(\n `[intlayer-edited-content] Incorrect edited content format. Expected string. Value: ${JSON.stringify(transformed)}`\n );\n this._editedText = null;\n }\n return;\n }\n\n this._editedText = null;\n }\n\n private _setupManagerSubscriptions(manager: EditorStateManager): void {\n this._resolveEditedText(manager);\n\n const handleChange = () => this._resolveEditedText(manager);\n manager.editedContent.addEventListener('change', handleChange);\n\n this._unsubEditedContent = () =>\n manager.editedContent.removeEventListener('change', handleChange);\n }\n\n private _subscribeToManager(): void {\n const manager = getGlobalEditorManager();\n if (manager) {\n this._setupManagerSubscriptions(manager);\n }\n\n this._unsubManager = onGlobalEditorManagerChange((m) => {\n this._unsubEditedContent?.();\n this._unsubEditedContent = null;\n if (m) {\n this._setupManagerSubscriptions(m);\n } else {\n this._editedText = null;\n }\n });\n }\n\n render() {\n return html`\n <intlayer-content-selector-wrapper\n key-path=${this.keyPathJson}\n dictionary-key=${this.dictionaryKey}\n >\n ${this._editedText !== null ? this._editedText : html`<slot></slot>`}\n </intlayer-content-selector-wrapper>\n `;\n }\n}\n\nexport const defineIntlayerEditedContent = (): void => {\n if (typeof customElements === 'undefined') return;\n\n if (!customElements.get('intlayer-edited-content')) {\n customElements.define(\n 'intlayer-edited-content',\n IntlayerEditedContentElement\n );\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAwBA,IAAa,+BAAb,cAAkDA,eAAW;;;uBAOc;qBACR;gBACP;qBAEZ;uBAED;6BACM;;;gBAbnC,OAAG;;;;;;CAenB,oBAA0B;AACxB,QAAM,mBAAmB;AACzB,OAAK,qBAAqB;;CAG5B,uBAA6B;AAC3B,QAAM,sBAAsB;AAC5B,OAAK,WAAW;;CAGlB,AAAQ,YAAkB;AACxB,OAAK,iBAAiB;AACtB,OAAK,uBAAuB;AAC5B,OAAK,gBAAgB;AACrB,OAAK,sBAAsB;;CAG7B,AAAQ,cAAyB;AAC/B,MAAI;AACF,UAAO,KAAK,MAAM,KAAK,YAAY;UAC7B;AACN,UAAO,EAAE;;;CAIb,AAAQ,mBAAmB,SAAmC;EAC5D,MAAM,UAAU,KAAK,aAAa;EAClC,MAAM,cAAc,QAAQ,gBAAgB,KAAK,eAAe,QAAQ;AAExE,MAAI,gBAAgB,UAAa,gBAAgB,MAAM;AACrD,QAAK,cAAc;AACnB;;AAGF,MAAI,OAAO,gBAAgB,YAAY,OAAO,gBAAgB,UAAU;AACtE,QAAK,cAAc,OAAO,YAAY;AACtC;;AAGF,MAAI,OAAO,gBAAgB,UAAU;GACnC,MAAM,SAAS,KAAK,UAAU;GAC9B,MAAM,yDACJ,aACA;IACU;IACR,eAAe,KAAK;IACpB;IACD,iDACc,OAAc,CAC9B;AACD,OAAI,OAAO,gBAAgB,YAAY,OAAO,gBAAgB,SAC5D,MAAK,cAAc,OAAO,YAAY;QACjC;AACL,YAAQ,MACN,sFAAsF,KAAK,UAAU,YAAY,GAClH;AACD,SAAK,cAAc;;AAErB;;AAGF,OAAK,cAAc;;CAGrB,AAAQ,2BAA2B,SAAmC;AACpE,OAAK,mBAAmB,QAAQ;EAEhC,MAAM,qBAAqB,KAAK,mBAAmB,QAAQ;AAC3D,UAAQ,cAAc,iBAAiB,UAAU,aAAa;AAE9D,OAAK,4BACH,QAAQ,cAAc,oBAAoB,UAAU,aAAa;;CAGrE,AAAQ,sBAA4B;EAClC,MAAM,UAAUC,mDAAwB;AACxC,MAAI,QACF,MAAK,2BAA2B,QAAQ;AAG1C,OAAK,gBAAgBC,wDAA6B,MAAM;AACtD,QAAK,uBAAuB;AAC5B,QAAK,sBAAsB;AAC3B,OAAI,EACF,MAAK,2BAA2B,EAAE;OAElC,MAAK,cAAc;IAErB;;CAGJ,SAAS;AACP,SAAO,QAAI;;mBAEI,KAAK,YAAY;yBACX,KAAK,cAAc;;UAElC,KAAK,gBAAgB,OAAO,KAAK,cAAc,QAAI,gBAAgB;;;;;6DA1GjE;CAAE,MAAM;CAAQ,WAAW;CAAkB,CAAC;6DAC9C;CAAE,MAAM;CAAQ,WAAW;CAAY,CAAC;6DACxC;CAAE,MAAM;CAAQ,WAAW;CAAU,CAAC;2DAExC;AA4GV,MAAa,oCAA0C;AACrD,KAAI,OAAO,mBAAmB,YAAa;AAE3C,KAAI,CAAC,eAAe,IAAI,0BAA0B,CAChD,gBAAe,OACb,2BACA,6BACD"}
|
|
@@ -1 +1,87 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_core_globalManager = require('../core/globalManager.cjs');
|
|
4
|
+
const require_decorate = require('../_virtual/_@oxc-project_runtime@0.115.0/helpers/decorate.cjs');
|
|
5
|
+
const require_core_initEditorClient = require('../core/initEditorClient.cjs');
|
|
6
|
+
let lit = require("lit");
|
|
7
|
+
let lit_decorators_js = require("lit/decorators.js");
|
|
8
|
+
|
|
9
|
+
//#region src/components/IntlayerEditor.ts
|
|
10
|
+
/**
|
|
11
|
+
* <intlayer-editor>
|
|
12
|
+
*
|
|
13
|
+
* A framework-agnostic Lit element that manages the Intlayer editor singleton
|
|
14
|
+
* lifecycle and keeps the current locale in sync with the EditorStateManager.
|
|
15
|
+
*
|
|
16
|
+
* Drop this element once at the root of your application to activate the editor.
|
|
17
|
+
* It renders no UI (display: contents, empty shadow root).
|
|
18
|
+
*
|
|
19
|
+
* @prop {IntlayerConfig} configuration - The Intlayer config (required; set as property, not attribute)
|
|
20
|
+
* @prop {string} locale - The active application locale (attribute/property)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Svelte
|
|
24
|
+
* <intlayer-editor .configuration={config} locale={$locale} />
|
|
25
|
+
*
|
|
26
|
+
* // Vue
|
|
27
|
+
* <intlayer-editor :configuration="config" :locale="currentLocale" />
|
|
28
|
+
*/
|
|
29
|
+
var IntlayerEditorElement = class extends lit.LitElement {
|
|
30
|
+
constructor(..._args) {
|
|
31
|
+
super(..._args);
|
|
32
|
+
this._initialized = false;
|
|
33
|
+
this._unsubManager = null;
|
|
34
|
+
}
|
|
35
|
+
/** No visible UI — render nothing into the shadow root */
|
|
36
|
+
createRenderRoot() {
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
connectedCallback() {
|
|
40
|
+
super.connectedCallback();
|
|
41
|
+
this._init();
|
|
42
|
+
}
|
|
43
|
+
disconnectedCallback() {
|
|
44
|
+
super.disconnectedCallback();
|
|
45
|
+
this._unsubManager?.();
|
|
46
|
+
this._unsubManager = null;
|
|
47
|
+
if (this._initialized) {
|
|
48
|
+
require_core_initEditorClient.stopEditorClient();
|
|
49
|
+
this._initialized = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
updated(changedProperties) {
|
|
53
|
+
if (changedProperties.has("configuration") && !this._initialized) this._init();
|
|
54
|
+
if (changedProperties.has("locale") && this.locale) this._syncLocale(this.locale);
|
|
55
|
+
}
|
|
56
|
+
_init() {
|
|
57
|
+
if (this._initialized) return;
|
|
58
|
+
require_core_initEditorClient.initEditorClient();
|
|
59
|
+
this._initialized = true;
|
|
60
|
+
if (this.locale) this._syncLocale(this.locale);
|
|
61
|
+
}
|
|
62
|
+
_syncLocale(locale) {
|
|
63
|
+
const manager = require_core_globalManager.getGlobalEditorManager();
|
|
64
|
+
if (manager) manager.currentLocale.set(locale);
|
|
65
|
+
else {
|
|
66
|
+
this._unsubManager?.();
|
|
67
|
+
this._unsubManager = require_core_globalManager.onGlobalEditorManagerChange((manager) => {
|
|
68
|
+
if (manager) {
|
|
69
|
+
this._unsubManager?.();
|
|
70
|
+
this._unsubManager = null;
|
|
71
|
+
manager.currentLocale.set(locale);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
require_decorate.__decorate([(0, lit_decorators_js.property)({ attribute: false })], IntlayerEditorElement.prototype, "configuration", void 0);
|
|
78
|
+
require_decorate.__decorate([(0, lit_decorators_js.property)({ type: String })], IntlayerEditorElement.prototype, "locale", void 0);
|
|
79
|
+
const defineIntlayerEditorElement = () => {
|
|
80
|
+
if (typeof customElements === "undefined") return;
|
|
81
|
+
if (!customElements.get("intlayer-editor")) customElements.define("intlayer-editor", IntlayerEditorElement);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
exports.IntlayerEditorElement = IntlayerEditorElement;
|
|
86
|
+
exports.defineIntlayerEditorElement = defineIntlayerEditorElement;
|
|
87
|
+
//# sourceMappingURL=IntlayerEditor.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntlayerEditor.cjs","names":["LitElement","getGlobalEditorManager","onGlobalEditorManagerChange"],"sources":["../../../src/components/IntlayerEditor.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport {\n getGlobalEditorManager,\n onGlobalEditorManagerChange,\n} from '../core/globalManager';\nimport { initEditorClient, stopEditorClient } from '../core/initEditorClient';\n\n/**\n * <intlayer-editor>\n *\n * A framework-agnostic Lit element that manages the Intlayer editor singleton\n * lifecycle and keeps the current locale in sync with the EditorStateManager.\n *\n * Drop this element once at the root of your application to activate the editor.\n * It renders no UI (display: contents, empty shadow root).\n *\n * @prop {IntlayerConfig} configuration - The Intlayer config (required; set as property, not attribute)\n * @prop {string} locale - The active application locale (attribute/property)\n *\n * @example\n * // Svelte\n * <intlayer-editor .configuration={config} locale={$locale} />\n *\n * // Vue\n * <intlayer-editor :configuration=\"config\" :locale=\"currentLocale\" />\n */\nexport class IntlayerEditorElement extends LitElement {\n /** No visible UI — render nothing into the shadow root */\n createRenderRoot(): this {\n return this;\n }\n\n @property({ attribute: false }) configuration?: IntlayerConfig;\n\n @property({ type: String }) locale?: string;\n\n private _initialized = false;\n private _unsubManager: (() => void) | null = null;\n\n connectedCallback(): void {\n super.connectedCallback();\n this._init();\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this._unsubManager?.();\n this._unsubManager = null;\n\n if (this._initialized) {\n stopEditorClient();\n this._initialized = false;\n }\n }\n\n updated(changedProperties: Map<string | symbol, unknown>): void {\n if (changedProperties.has('configuration') && !this._initialized) {\n this._init();\n }\n\n if (changedProperties.has('locale') && this.locale) {\n this._syncLocale(this.locale);\n }\n }\n\n private _init(): void {\n if (this._initialized) return;\n\n initEditorClient();\n\n this._initialized = true;\n\n // Sync locale immediately after init if it is already set\n if (this.locale) {\n this._syncLocale(this.locale);\n }\n }\n\n private _syncLocale(locale: string): void {\n const manager = getGlobalEditorManager();\n\n if (manager) {\n manager.currentLocale.set(locale as Locale);\n } else {\n // Manager may not be ready yet — wait for it\n this._unsubManager?.();\n this._unsubManager = onGlobalEditorManagerChange((manager) => {\n if (manager) {\n this._unsubManager?.();\n this._unsubManager = null;\n\n manager.currentLocale.set(locale as Locale);\n }\n });\n }\n }\n}\n\nexport const defineIntlayerEditorElement = (): void => {\n if (typeof customElements === 'undefined') return;\n\n if (!customElements.get('intlayer-editor')) {\n customElements.define('intlayer-editor', IntlayerEditorElement);\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,wBAAb,cAA2CA,eAAW;;;sBAU7B;uBACsB;;;CAT7C,mBAAyB;AACvB,SAAO;;CAUT,oBAA0B;AACxB,QAAM,mBAAmB;AACzB,OAAK,OAAO;;CAGd,uBAA6B;AAC3B,QAAM,sBAAsB;AAC5B,OAAK,iBAAiB;AACtB,OAAK,gBAAgB;AAErB,MAAI,KAAK,cAAc;AACrB,mDAAkB;AAClB,QAAK,eAAe;;;CAIxB,QAAQ,mBAAwD;AAC9D,MAAI,kBAAkB,IAAI,gBAAgB,IAAI,CAAC,KAAK,aAClD,MAAK,OAAO;AAGd,MAAI,kBAAkB,IAAI,SAAS,IAAI,KAAK,OAC1C,MAAK,YAAY,KAAK,OAAO;;CAIjC,AAAQ,QAAc;AACpB,MAAI,KAAK,aAAc;AAEvB,kDAAkB;AAElB,OAAK,eAAe;AAGpB,MAAI,KAAK,OACP,MAAK,YAAY,KAAK,OAAO;;CAIjC,AAAQ,YAAY,QAAsB;EACxC,MAAM,UAAUC,mDAAwB;AAExC,MAAI,QACF,SAAQ,cAAc,IAAI,OAAiB;OACtC;AAEL,QAAK,iBAAiB;AACtB,QAAK,gBAAgBC,wDAA6B,YAAY;AAC5D,QAAI,SAAS;AACX,UAAK,iBAAiB;AACtB,UAAK,gBAAgB;AAErB,aAAQ,cAAc,IAAI,OAAiB;;KAE7C;;;;6DA7DI,EAAE,WAAW,OAAO,CAAC;6DAErB,EAAE,MAAM,QAAQ,CAAC;AAgE7B,MAAa,oCAA0C;AACrD,KAAI,OAAO,mBAAmB,YAAa;AAE3C,KAAI,CAAC,eAAe,IAAI,kBAAkB,CACxC,gBAAe,OAAO,mBAAmB,sBAAsB"}
|
|
@@ -1 +1,14 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_components_ContentSelectorWrapper = require('./ContentSelectorWrapper.cjs');
|
|
3
|
+
const require_components_EditedContent = require('./EditedContent.cjs');
|
|
4
|
+
const require_components_IntlayerEditor = require('./IntlayerEditor.cjs');
|
|
5
|
+
const require_components_ContentSelector = require('./ContentSelector.cjs');
|
|
6
|
+
|
|
7
|
+
exports.IntlayerContentSelectorElement = require_components_ContentSelector.IntlayerContentSelectorElement;
|
|
8
|
+
exports.IntlayerContentSelectorWrapperElement = require_components_ContentSelectorWrapper.IntlayerContentSelectorWrapperElement;
|
|
9
|
+
exports.IntlayerEditedContentElement = require_components_EditedContent.IntlayerEditedContentElement;
|
|
10
|
+
exports.IntlayerEditorElement = require_components_IntlayerEditor.IntlayerEditorElement;
|
|
11
|
+
exports.defineIntlayerContentSelectorWrapper = require_components_ContentSelectorWrapper.defineIntlayerContentSelectorWrapper;
|
|
12
|
+
exports.defineIntlayerEditedContent = require_components_EditedContent.defineIntlayerEditedContent;
|
|
13
|
+
exports.defineIntlayerEditorElement = require_components_IntlayerEditor.defineIntlayerEditorElement;
|
|
14
|
+
exports.defineIntlayerElements = require_components_ContentSelector.defineIntlayerElements;
|
|
@@ -1,2 +1,78 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_compareUrls = require('../compareUrls.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/core/CrossFrameMessenger.ts
|
|
5
|
+
const randomUUID = () => Math.random().toString(36).slice(2);
|
|
6
|
+
/**
|
|
7
|
+
* CrossFrameMessenger manages all cross-frame postMessage communication.
|
|
8
|
+
* It owns a single window message listener and routes incoming messages to
|
|
9
|
+
* type-specific subscribers.
|
|
10
|
+
*
|
|
11
|
+
* Replaces CommunicatorContext + useCrossFrameMessageListener across all frameworks.
|
|
12
|
+
*/
|
|
13
|
+
var CrossFrameMessenger = class {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this._subscribers = /* @__PURE__ */ new Map();
|
|
16
|
+
this._windowHandler = null;
|
|
17
|
+
this._seenMessageIds = /* @__PURE__ */ new Set();
|
|
18
|
+
this._config = config;
|
|
19
|
+
this.senderId = randomUUID();
|
|
20
|
+
}
|
|
21
|
+
/** Start listening for incoming messages on window. */
|
|
22
|
+
start() {
|
|
23
|
+
if (typeof window === "undefined") return;
|
|
24
|
+
if (this._windowHandler) return;
|
|
25
|
+
this._windowHandler = (event) => {
|
|
26
|
+
this._handleMessage(event);
|
|
27
|
+
};
|
|
28
|
+
window.addEventListener("message", this._windowHandler);
|
|
29
|
+
}
|
|
30
|
+
/** Stop listening and clean up. */
|
|
31
|
+
stop() {
|
|
32
|
+
if (this._windowHandler) {
|
|
33
|
+
window.removeEventListener("message", this._windowHandler);
|
|
34
|
+
this._windowHandler = null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Send a message payload to all configured target origins. */
|
|
38
|
+
send(type, data) {
|
|
39
|
+
const payload = {
|
|
40
|
+
type,
|
|
41
|
+
data,
|
|
42
|
+
senderId: this.senderId,
|
|
43
|
+
messageId: randomUUID()
|
|
44
|
+
};
|
|
45
|
+
for (const origin of this._config.allowedOrigins) if (origin) this._config.postMessageFn(payload, origin);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Subscribe to messages of a given type.
|
|
49
|
+
* Returns an unsubscribe function.
|
|
50
|
+
*/
|
|
51
|
+
subscribe(type, handler) {
|
|
52
|
+
if (!this._subscribers.has(type)) this._subscribers.set(type, /* @__PURE__ */ new Set());
|
|
53
|
+
this._subscribers.get(type).add(handler);
|
|
54
|
+
return () => {
|
|
55
|
+
this._subscribers.get(type)?.delete(handler);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
_handleMessage(event) {
|
|
59
|
+
const payload = event.data;
|
|
60
|
+
if (!payload || typeof payload !== "object") return;
|
|
61
|
+
const { type, data, senderId: msgSenderId, messageId } = payload;
|
|
62
|
+
if (!type || typeof type !== "string") return;
|
|
63
|
+
if (msgSenderId === this.senderId) return;
|
|
64
|
+
if (messageId) {
|
|
65
|
+
if (this._seenMessageIds.has(messageId)) return;
|
|
66
|
+
this._seenMessageIds.add(messageId);
|
|
67
|
+
if (this._seenMessageIds.size > 200) this._seenMessageIds.clear();
|
|
68
|
+
}
|
|
69
|
+
const { allowedOrigins } = this._config;
|
|
70
|
+
if (!(!allowedOrigins || allowedOrigins.length === 0 || allowedOrigins.includes("*") || allowedOrigins.filter((url) => Boolean(url) && url !== "").some((url) => require_compareUrls.compareUrls(url, event.origin)))) return;
|
|
71
|
+
const handlers = this._subscribers.get(type);
|
|
72
|
+
if (handlers) for (const handler of handlers) handler(data, msgSenderId);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
exports.CrossFrameMessenger = CrossFrameMessenger;
|
|
2
78
|
//# sourceMappingURL=CrossFrameMessenger.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrossFrameMessenger.cjs","names":["compareUrls"],"sources":["../../../src/core/CrossFrameMessenger.ts"],"sourcesContent":["import { compareUrls } from '../compareUrls';\n\nconst randomUUID = (): string => Math.random().toString(36).slice(2);\n\nexport type MessagePayload = {\n type: string;\n data?: unknown;\n senderId?: string;\n /** Unique ID per send() call — used to deduplicate when the same payload arrives via multiple target origins */\n messageId?: string;\n};\n\nexport type MessengerConfig = {\n /**\n * Origins allowed to send messages to this instance.\n * Use '*' to allow all origins (not recommended for production).\n */\n allowedOrigins: string[];\n /**\n * Function used to send messages to other frames.\n * Injected so the messenger is agnostic to the frame topology.\n */\n postMessageFn: (payload: MessagePayload, origin: string) => void;\n};\n\ntype MessageHandler<T = unknown> = (data: T, senderId?: string) => void;\n\n/**\n * CrossFrameMessenger manages all cross-frame postMessage communication.\n * It owns a single window message listener and routes incoming messages to\n * type-specific subscribers.\n *\n * Replaces CommunicatorContext + useCrossFrameMessageListener across all frameworks.\n */\nexport class CrossFrameMessenger {\n readonly senderId: string;\n private readonly _config: MessengerConfig;\n private readonly _subscribers = new Map<string, Set<MessageHandler>>();\n\n private _windowHandler: ((event: MessageEvent) => void) | null = null;\n /** Tracks recently processed messageIds to discard duplicates (same payload sent to multiple origins) */\n private readonly _seenMessageIds = new Set<string>();\n\n constructor(config: MessengerConfig) {\n this._config = config;\n this.senderId = randomUUID();\n }\n\n /** Start listening for incoming messages on window. */\n start(): void {\n if (typeof window === 'undefined') return;\n if (this._windowHandler) return;\n this._windowHandler = (event: MessageEvent<MessagePayload>) => {\n this._handleMessage(event);\n };\n window.addEventListener('message', this._windowHandler);\n }\n\n /** Stop listening and clean up. */\n stop(): void {\n if (this._windowHandler) {\n window.removeEventListener('message', this._windowHandler);\n this._windowHandler = null;\n }\n }\n\n /** Send a message payload to all configured target origins. */\n send(type: string, data?: unknown): void {\n const payload: MessagePayload = {\n type,\n data,\n senderId: this.senderId,\n messageId: randomUUID(),\n };\n\n for (const origin of this._config.allowedOrigins) {\n if (origin) {\n this._config.postMessageFn(payload, origin);\n }\n }\n }\n\n /**\n * Subscribe to messages of a given type.\n * Returns an unsubscribe function.\n */\n subscribe<T = unknown>(type: string, handler: MessageHandler<T>): () => void {\n if (!this._subscribers.has(type)) {\n this._subscribers.set(type, new Set());\n }\n this._subscribers.get(type)!.add(handler as MessageHandler);\n return () => {\n this._subscribers.get(type)?.delete(handler as MessageHandler);\n };\n }\n\n private _handleMessage(event: MessageEvent<MessagePayload>): void {\n const payload = event.data;\n if (!payload || typeof payload !== 'object') return;\n\n const { type, data, senderId: msgSenderId, messageId } = payload;\n if (!type || typeof type !== 'string') return;\n\n // Ignore messages originating from this instance\n if (msgSenderId === this.senderId) return;\n\n // Deduplicate: same messageId may arrive multiple times when the sender\n // posts to multiple target origins (one per allowedOrigin)\n if (messageId) {\n if (this._seenMessageIds.has(messageId)) return;\n this._seenMessageIds.add(messageId);\n // Keep the set bounded — clear when it exceeds 200 entries\n if (this._seenMessageIds.size > 200) this._seenMessageIds.clear();\n }\n\n // Validate message origin\n const { allowedOrigins } = this._config;\n const isAllowed =\n !allowedOrigins ||\n allowedOrigins.length === 0 ||\n allowedOrigins.includes('*') ||\n allowedOrigins\n .filter((url) => Boolean(url) && url !== '')\n .some((url) => compareUrls(url, event.origin));\n\n if (!isAllowed) return;\n\n const handlers = this._subscribers.get(type);\n\n if (handlers) {\n for (const handler of handlers) {\n handler(data, msgSenderId);\n }\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CrossFrameMessenger.cjs","names":["compareUrls"],"sources":["../../../src/core/CrossFrameMessenger.ts"],"sourcesContent":["import { compareUrls } from '../compareUrls';\n\nconst randomUUID = (): string => Math.random().toString(36).slice(2);\n\nexport type MessagePayload = {\n type: string;\n data?: unknown;\n senderId?: string;\n /** Unique ID per send() call — used to deduplicate when the same payload arrives via multiple target origins */\n messageId?: string;\n};\n\nexport type MessengerConfig = {\n /**\n * Origins allowed to send messages to this instance.\n * Use '*' to allow all origins (not recommended for production).\n */\n allowedOrigins: string[];\n /**\n * Function used to send messages to other frames.\n * Injected so the messenger is agnostic to the frame topology.\n */\n postMessageFn: (payload: MessagePayload, origin: string) => void;\n};\n\ntype MessageHandler<T = unknown> = (data: T, senderId?: string) => void;\n\n/**\n * CrossFrameMessenger manages all cross-frame postMessage communication.\n * It owns a single window message listener and routes incoming messages to\n * type-specific subscribers.\n *\n * Replaces CommunicatorContext + useCrossFrameMessageListener across all frameworks.\n */\nexport class CrossFrameMessenger {\n readonly senderId: string;\n private readonly _config: MessengerConfig;\n private readonly _subscribers = new Map<string, Set<MessageHandler>>();\n\n private _windowHandler: ((event: MessageEvent) => void) | null = null;\n /** Tracks recently processed messageIds to discard duplicates (same payload sent to multiple origins) */\n private readonly _seenMessageIds = new Set<string>();\n\n constructor(config: MessengerConfig) {\n this._config = config;\n this.senderId = randomUUID();\n }\n\n /** Start listening for incoming messages on window. */\n start(): void {\n if (typeof window === 'undefined') return;\n if (this._windowHandler) return;\n this._windowHandler = (event: MessageEvent<MessagePayload>) => {\n this._handleMessage(event);\n };\n window.addEventListener('message', this._windowHandler);\n }\n\n /** Stop listening and clean up. */\n stop(): void {\n if (this._windowHandler) {\n window.removeEventListener('message', this._windowHandler);\n this._windowHandler = null;\n }\n }\n\n /** Send a message payload to all configured target origins. */\n send(type: string, data?: unknown): void {\n const payload: MessagePayload = {\n type,\n data,\n senderId: this.senderId,\n messageId: randomUUID(),\n };\n\n for (const origin of this._config.allowedOrigins) {\n if (origin) {\n this._config.postMessageFn(payload, origin);\n }\n }\n }\n\n /**\n * Subscribe to messages of a given type.\n * Returns an unsubscribe function.\n */\n subscribe<T = unknown>(type: string, handler: MessageHandler<T>): () => void {\n if (!this._subscribers.has(type)) {\n this._subscribers.set(type, new Set());\n }\n this._subscribers.get(type)!.add(handler as MessageHandler);\n return () => {\n this._subscribers.get(type)?.delete(handler as MessageHandler);\n };\n }\n\n private _handleMessage(event: MessageEvent<MessagePayload>): void {\n const payload = event.data;\n if (!payload || typeof payload !== 'object') return;\n\n const { type, data, senderId: msgSenderId, messageId } = payload;\n if (!type || typeof type !== 'string') return;\n\n // Ignore messages originating from this instance\n if (msgSenderId === this.senderId) return;\n\n // Deduplicate: same messageId may arrive multiple times when the sender\n // posts to multiple target origins (one per allowedOrigin)\n if (messageId) {\n if (this._seenMessageIds.has(messageId)) return;\n this._seenMessageIds.add(messageId);\n // Keep the set bounded — clear when it exceeds 200 entries\n if (this._seenMessageIds.size > 200) this._seenMessageIds.clear();\n }\n\n // Validate message origin\n const { allowedOrigins } = this._config;\n const isAllowed =\n !allowedOrigins ||\n allowedOrigins.length === 0 ||\n allowedOrigins.includes('*') ||\n allowedOrigins\n .filter((url) => Boolean(url) && url !== '')\n .some((url) => compareUrls(url, event.origin));\n\n if (!isAllowed) return;\n\n const handlers = this._subscribers.get(type);\n\n if (handlers) {\n for (const handler of handlers) {\n handler(data, msgSenderId);\n }\n }\n }\n}\n"],"mappings":";;;;AAEA,MAAM,mBAA2B,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE;;;;;;;;AAgCpE,IAAa,sBAAb,MAAiC;CAS/B,YAAY,QAAyB;sCANL,IAAI,KAAkC;wBAEL;yCAE9B,IAAI,KAAa;AAGlD,OAAK,UAAU;AACf,OAAK,WAAW,YAAY;;;CAI9B,QAAc;AACZ,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI,KAAK,eAAgB;AACzB,OAAK,kBAAkB,UAAwC;AAC7D,QAAK,eAAe,MAAM;;AAE5B,SAAO,iBAAiB,WAAW,KAAK,eAAe;;;CAIzD,OAAa;AACX,MAAI,KAAK,gBAAgB;AACvB,UAAO,oBAAoB,WAAW,KAAK,eAAe;AAC1D,QAAK,iBAAiB;;;;CAK1B,KAAK,MAAc,MAAsB;EACvC,MAAM,UAA0B;GAC9B;GACA;GACA,UAAU,KAAK;GACf,WAAW,YAAY;GACxB;AAED,OAAK,MAAM,UAAU,KAAK,QAAQ,eAChC,KAAI,OACF,MAAK,QAAQ,cAAc,SAAS,OAAO;;;;;;CASjD,UAAuB,MAAc,SAAwC;AAC3E,MAAI,CAAC,KAAK,aAAa,IAAI,KAAK,CAC9B,MAAK,aAAa,IAAI,sBAAM,IAAI,KAAK,CAAC;AAExC,OAAK,aAAa,IAAI,KAAK,CAAE,IAAI,QAA0B;AAC3D,eAAa;AACX,QAAK,aAAa,IAAI,KAAK,EAAE,OAAO,QAA0B;;;CAIlE,AAAQ,eAAe,OAA2C;EAChE,MAAM,UAAU,MAAM;AACtB,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU;EAE7C,MAAM,EAAE,MAAM,MAAM,UAAU,aAAa,cAAc;AACzD,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AAGvC,MAAI,gBAAgB,KAAK,SAAU;AAInC,MAAI,WAAW;AACb,OAAI,KAAK,gBAAgB,IAAI,UAAU,CAAE;AACzC,QAAK,gBAAgB,IAAI,UAAU;AAEnC,OAAI,KAAK,gBAAgB,OAAO,IAAK,MAAK,gBAAgB,OAAO;;EAInE,MAAM,EAAE,mBAAmB,KAAK;AAShC,MAAI,EAPF,CAAC,kBACD,eAAe,WAAW,KAC1B,eAAe,SAAS,IAAI,IAC5B,eACG,QAAQ,QAAQ,QAAQ,IAAI,IAAI,QAAQ,GAAG,CAC3C,MAAM,QAAQA,gCAAY,KAAK,MAAM,OAAO,CAAC,EAElC;EAEhB,MAAM,WAAW,KAAK,aAAa,IAAI,KAAK;AAE5C,MAAI,SACF,MAAK,MAAM,WAAW,SACpB,SAAQ,MAAM,YAAY"}
|
|
@@ -1,2 +1,72 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
//#region src/core/CrossFrameStateManager.ts
|
|
4
|
+
/**
|
|
5
|
+
* CrossFrameStateManager synchronizes a single named value across frames using
|
|
6
|
+
* the postMessage API via CrossFrameMessenger.
|
|
7
|
+
*
|
|
8
|
+
* Protocol:
|
|
9
|
+
* `{key}/post` — broadcast a new value
|
|
10
|
+
* `{key}/get` — request the current value from other frames
|
|
11
|
+
*
|
|
12
|
+
* Replaces useCrossFrameState across all frameworks.
|
|
13
|
+
*
|
|
14
|
+
* @fires change — CustomEvent<T> dispatched whenever the value changes (local set or received)
|
|
15
|
+
*/
|
|
16
|
+
var CrossFrameStateManager = class extends EventTarget {
|
|
17
|
+
constructor(key, messenger, options = {}) {
|
|
18
|
+
super();
|
|
19
|
+
this._unsubscribers = [];
|
|
20
|
+
this._key = key;
|
|
21
|
+
this._messenger = messenger;
|
|
22
|
+
this._options = {
|
|
23
|
+
emit: options.emit ?? true,
|
|
24
|
+
receive: options.receive ?? true
|
|
25
|
+
};
|
|
26
|
+
if (options.initialValue !== void 0) this._value = options.initialValue;
|
|
27
|
+
}
|
|
28
|
+
get value() {
|
|
29
|
+
return this._value;
|
|
30
|
+
}
|
|
31
|
+
/** Update the value locally and broadcast it to other frames if emit is enabled. */
|
|
32
|
+
set(newValue) {
|
|
33
|
+
this._value = newValue;
|
|
34
|
+
this.dispatchEvent(new CustomEvent("change", { detail: newValue }));
|
|
35
|
+
if (this._options.emit) this._messenger.send(`${this._key}/post`, newValue);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Start listening for incoming state updates and responding to /get requests.
|
|
39
|
+
* If receive=true and no initial value is set, sends a /get to request the current value.
|
|
40
|
+
*/
|
|
41
|
+
start() {
|
|
42
|
+
if (this._options.receive) {
|
|
43
|
+
const unsub = this._messenger.subscribe(`${this._key}/post`, (data) => {
|
|
44
|
+
this._value = data;
|
|
45
|
+
this.dispatchEvent(new CustomEvent("change", { detail: data }));
|
|
46
|
+
});
|
|
47
|
+
this._unsubscribers.push(unsub);
|
|
48
|
+
}
|
|
49
|
+
if (this._options.emit) {
|
|
50
|
+
const unsub = this._messenger.subscribe(`${this._key}/get`, (_, originSenderId) => {
|
|
51
|
+
if (originSenderId === this._messenger.senderId) return;
|
|
52
|
+
if (this._value === void 0) return;
|
|
53
|
+
this._messenger.send(`${this._key}/post`, this._value);
|
|
54
|
+
});
|
|
55
|
+
this._unsubscribers.push(unsub);
|
|
56
|
+
}
|
|
57
|
+
if (this._options.receive && this._value === void 0) this._messenger.send(`${this._key}/get`);
|
|
58
|
+
}
|
|
59
|
+
/** Stop all listeners. */
|
|
60
|
+
stop() {
|
|
61
|
+
for (const unsub of this._unsubscribers) unsub();
|
|
62
|
+
this._unsubscribers.length = 0;
|
|
63
|
+
}
|
|
64
|
+
/** Broadcast the current value to all frames (useful after reconnect). */
|
|
65
|
+
postCurrentValue() {
|
|
66
|
+
if (this._value !== void 0) this._messenger.send(`${this._key}/post`, this._value);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
exports.CrossFrameStateManager = CrossFrameStateManager;
|
|
2
72
|
//# sourceMappingURL=CrossFrameStateManager.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CrossFrameStateManager.cjs","names":[],"sources":["../../../src/core/CrossFrameStateManager.ts"],"sourcesContent":["import type { CrossFrameMessenger } from './CrossFrameMessenger';\n\nexport type CrossFrameStateOptions = {\n /** Whether to broadcast state changes to other frames. Default: true */\n emit?: boolean;\n /** Whether to listen for state updates from other frames. Default: true */\n receive?: boolean;\n};\n\n/**\n * CrossFrameStateManager synchronizes a single named value across frames using\n * the postMessage API via CrossFrameMessenger.\n *\n * Protocol:\n * `{key}/post` — broadcast a new value\n * `{key}/get` — request the current value from other frames\n *\n * Replaces useCrossFrameState across all frameworks.\n *\n * @fires change — CustomEvent<T> dispatched whenever the value changes (local set or received)\n */\nexport class CrossFrameStateManager<T> extends EventTarget {\n private _value: T | undefined;\n private readonly _key: string;\n private readonly _messenger: CrossFrameMessenger;\n private readonly _options: Required<CrossFrameStateOptions>;\n private readonly _unsubscribers: Array<() => void> = [];\n\n constructor(\n key: string,\n messenger: CrossFrameMessenger,\n options: CrossFrameStateOptions & { initialValue?: T } = {}\n ) {\n super();\n this._key = key;\n this._messenger = messenger;\n this._options = {\n emit: options.emit ?? true,\n receive: options.receive ?? true,\n };\n if (options.initialValue !== undefined) {\n this._value = options.initialValue;\n }\n }\n\n get value(): T | undefined {\n return this._value;\n }\n\n /** Update the value locally and broadcast it to other frames if emit is enabled. */\n set(newValue: T): void {\n this._value = newValue;\n this.dispatchEvent(new CustomEvent<T>('change', { detail: newValue }));\n if (this._options.emit) {\n this._messenger.send(`${this._key}/post`, newValue);\n }\n }\n\n /**\n * Start listening for incoming state updates and responding to /get requests.\n * If receive=true and no initial value is set, sends a /get to request the current value.\n */\n start(): void {\n if (this._options.receive) {\n const unsub = this._messenger.subscribe<T>(\n `${this._key}/post`,\n (data) => {\n this._value = data;\n this.dispatchEvent(new CustomEvent<T>('change', { detail: data }));\n }\n );\n this._unsubscribers.push(unsub);\n }\n\n if (this._options.emit) {\n // Respond to /get requests by broadcasting current value\n const unsub = this._messenger.subscribe(\n `${this._key}/get`,\n (_, originSenderId) => {\n if (originSenderId === this._messenger.senderId) return;\n if (this._value === undefined) return;\n this._messenger.send(`${this._key}/post`, this._value);\n }\n );\n this._unsubscribers.push(unsub);\n }\n\n // If receiving and no initial value, request it from other frames\n if (this._options.receive && this._value === undefined) {\n this._messenger.send(`${this._key}/get`);\n }\n }\n\n /** Stop all listeners. */\n stop(): void {\n for (const unsub of this._unsubscribers) unsub();\n this._unsubscribers.length = 0;\n }\n\n /** Broadcast the current value to all frames (useful after reconnect). */\n postCurrentValue(): void {\n if (this._value !== undefined) {\n this._messenger.send(`${this._key}/post`, this._value);\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CrossFrameStateManager.cjs","names":[],"sources":["../../../src/core/CrossFrameStateManager.ts"],"sourcesContent":["import type { CrossFrameMessenger } from './CrossFrameMessenger';\n\nexport type CrossFrameStateOptions = {\n /** Whether to broadcast state changes to other frames. Default: true */\n emit?: boolean;\n /** Whether to listen for state updates from other frames. Default: true */\n receive?: boolean;\n};\n\n/**\n * CrossFrameStateManager synchronizes a single named value across frames using\n * the postMessage API via CrossFrameMessenger.\n *\n * Protocol:\n * `{key}/post` — broadcast a new value\n * `{key}/get` — request the current value from other frames\n *\n * Replaces useCrossFrameState across all frameworks.\n *\n * @fires change — CustomEvent<T> dispatched whenever the value changes (local set or received)\n */\nexport class CrossFrameStateManager<T> extends EventTarget {\n private _value: T | undefined;\n private readonly _key: string;\n private readonly _messenger: CrossFrameMessenger;\n private readonly _options: Required<CrossFrameStateOptions>;\n private readonly _unsubscribers: Array<() => void> = [];\n\n constructor(\n key: string,\n messenger: CrossFrameMessenger,\n options: CrossFrameStateOptions & { initialValue?: T } = {}\n ) {\n super();\n this._key = key;\n this._messenger = messenger;\n this._options = {\n emit: options.emit ?? true,\n receive: options.receive ?? true,\n };\n if (options.initialValue !== undefined) {\n this._value = options.initialValue;\n }\n }\n\n get value(): T | undefined {\n return this._value;\n }\n\n /** Update the value locally and broadcast it to other frames if emit is enabled. */\n set(newValue: T): void {\n this._value = newValue;\n this.dispatchEvent(new CustomEvent<T>('change', { detail: newValue }));\n if (this._options.emit) {\n this._messenger.send(`${this._key}/post`, newValue);\n }\n }\n\n /**\n * Start listening for incoming state updates and responding to /get requests.\n * If receive=true and no initial value is set, sends a /get to request the current value.\n */\n start(): void {\n if (this._options.receive) {\n const unsub = this._messenger.subscribe<T>(\n `${this._key}/post`,\n (data) => {\n this._value = data;\n this.dispatchEvent(new CustomEvent<T>('change', { detail: data }));\n }\n );\n this._unsubscribers.push(unsub);\n }\n\n if (this._options.emit) {\n // Respond to /get requests by broadcasting current value\n const unsub = this._messenger.subscribe(\n `${this._key}/get`,\n (_, originSenderId) => {\n if (originSenderId === this._messenger.senderId) return;\n if (this._value === undefined) return;\n this._messenger.send(`${this._key}/post`, this._value);\n }\n );\n this._unsubscribers.push(unsub);\n }\n\n // If receiving and no initial value, request it from other frames\n if (this._options.receive && this._value === undefined) {\n this._messenger.send(`${this._key}/get`);\n }\n }\n\n /** Stop all listeners. */\n stop(): void {\n for (const unsub of this._unsubscribers) unsub();\n this._unsubscribers.length = 0;\n }\n\n /** Broadcast the current value to all frames (useful after reconnect). */\n postCurrentValue(): void {\n if (this._value !== undefined) {\n this._messenger.send(`${this._key}/post`, this._value);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAa,yBAAb,cAA+C,YAAY;CAOzD,YACE,KACA,WACA,UAAyD,EAAE,EAC3D;AACA,SAAO;wBAP4C,EAAE;AAQrD,OAAK,OAAO;AACZ,OAAK,aAAa;AAClB,OAAK,WAAW;GACd,MAAM,QAAQ,QAAQ;GACtB,SAAS,QAAQ,WAAW;GAC7B;AACD,MAAI,QAAQ,iBAAiB,OAC3B,MAAK,SAAS,QAAQ;;CAI1B,IAAI,QAAuB;AACzB,SAAO,KAAK;;;CAId,IAAI,UAAmB;AACrB,OAAK,SAAS;AACd,OAAK,cAAc,IAAI,YAAe,UAAU,EAAE,QAAQ,UAAU,CAAC,CAAC;AACtE,MAAI,KAAK,SAAS,KAChB,MAAK,WAAW,KAAK,GAAG,KAAK,KAAK,QAAQ,SAAS;;;;;;CAQvD,QAAc;AACZ,MAAI,KAAK,SAAS,SAAS;GACzB,MAAM,QAAQ,KAAK,WAAW,UAC5B,GAAG,KAAK,KAAK,SACZ,SAAS;AACR,SAAK,SAAS;AACd,SAAK,cAAc,IAAI,YAAe,UAAU,EAAE,QAAQ,MAAM,CAAC,CAAC;KAErE;AACD,QAAK,eAAe,KAAK,MAAM;;AAGjC,MAAI,KAAK,SAAS,MAAM;GAEtB,MAAM,QAAQ,KAAK,WAAW,UAC5B,GAAG,KAAK,KAAK,QACZ,GAAG,mBAAmB;AACrB,QAAI,mBAAmB,KAAK,WAAW,SAAU;AACjD,QAAI,KAAK,WAAW,OAAW;AAC/B,SAAK,WAAW,KAAK,GAAG,KAAK,KAAK,QAAQ,KAAK,OAAO;KAEzD;AACD,QAAK,eAAe,KAAK,MAAM;;AAIjC,MAAI,KAAK,SAAS,WAAW,KAAK,WAAW,OAC3C,MAAK,WAAW,KAAK,GAAG,KAAK,KAAK,MAAM;;;CAK5C,OAAa;AACX,OAAK,MAAM,SAAS,KAAK,eAAgB,QAAO;AAChD,OAAK,eAAe,SAAS;;;CAI/B,mBAAyB;AACvB,MAAI,KAAK,WAAW,OAClB,MAAK,WAAW,KAAK,GAAG,KAAK,KAAK,QAAQ,KAAK,OAAO"}
|