svelte-intlayer 8.3.3 → 8.3.4
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/client/setupIntlayer.svelte.js +0 -6
- package/dist/editor/ContentSelectorWrapper.svelte +24 -33
- package/dist/editor/communicator.d.ts +5 -7
- package/dist/editor/communicator.js +45 -40
- package/dist/editor/dictionariesRecord.d.ts +3 -3
- package/dist/editor/dictionariesRecord.js +8 -15
- package/dist/editor/editorEnabled.d.ts +2 -11
- package/dist/editor/editorEnabled.js +9 -39
- package/dist/editor/focusDictionary.d.ts +6 -12
- package/dist/editor/focusDictionary.js +13 -20
- package/dist/editor/index.d.ts +1 -0
- package/dist/editor/index.js +1 -0
- package/dist/editor/useCrossFrameMessageListener.d.ts +1 -1
- package/dist/editor/useCrossFrameMessageListener.js +6 -54
- package/dist/editor/useCrossFrameState.d.ts +3 -3
- package/dist/editor/useCrossFrameState.js +25 -77
- package/dist/editor/useEditor.js +18 -42
- package/dist/editor/useIframeClickInterceptor.js +2 -23
- package/package.json +7 -8
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { createCommunicator } from '../editor/communicator';
|
|
2
|
-
import { createEditorEnabledClient } from '../editor/editorEnabled';
|
|
3
|
-
import { createFocusDictionaryClient } from '../editor/focusDictionary';
|
|
4
1
|
import { useEditor } from '../editor/useEditor';
|
|
5
2
|
// Assuming setIntlayerContext exports a specific key or symbol
|
|
6
3
|
import { setIntlayerContext } from './intlayerContext';
|
|
@@ -25,9 +22,6 @@ export const setupIntlayer = (initialLocale) => {
|
|
|
25
22
|
// 1. Initialize your side effects
|
|
26
23
|
// Note: If these need to run only in the browser, wrap them in $effect or onMount
|
|
27
24
|
// inside your side-effect logic if they aren't already safe.
|
|
28
|
-
createCommunicator();
|
|
29
|
-
createEditorEnabledClient();
|
|
30
|
-
createFocusDictionaryClient();
|
|
31
25
|
useEditor();
|
|
32
26
|
// 2. Create Reactive State (Svelte 5)
|
|
33
27
|
// We make the locale a "rune" so updates propagate
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { NodeProps } from '@intlayer/core/interpreter';
|
|
3
3
|
import { isSameKeyPath } from '@intlayer/core/utils';
|
|
4
|
-
import { MessageKey } from '@intlayer/editor';
|
|
4
|
+
import { defineIntlayerElements, MessageKey } from '@intlayer/editor';
|
|
5
5
|
import { NodeType } from '@intlayer/types/nodeType';
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import { useCommunicator } from './communicator';
|
|
6
|
+
import { onMount } from 'svelte';
|
|
7
|
+
import { getEditorStateManager } from './communicator';
|
|
9
8
|
import { useEditorEnabled } from './editorEnabled';
|
|
10
9
|
import { useFocusDictionary } from './focusDictionary';
|
|
11
10
|
import { useEditor } from './useEditor';
|
|
@@ -13,13 +12,14 @@ import { useEditor } from './useEditor';
|
|
|
13
12
|
export let dictionaryKey: NodeProps['dictionaryKey'];
|
|
14
13
|
export let keyPath: NodeProps['keyPath'];
|
|
15
14
|
|
|
15
|
+
const manager = getEditorStateManager();
|
|
16
16
|
const { focusedContent, setFocusedContent } = useFocusDictionary();
|
|
17
|
-
const
|
|
18
|
-
const communicatorStore = useCommunicator();
|
|
19
|
-
const { enabled } = editorEnabled;
|
|
17
|
+
const { enabled } = useEditorEnabled();
|
|
20
18
|
|
|
21
19
|
useEditor();
|
|
22
20
|
|
|
21
|
+
onMount(() => defineIntlayerElements());
|
|
22
|
+
|
|
23
23
|
$: filteredKeyPath = keyPath.filter((key) => key.type !== NodeType.Translation);
|
|
24
24
|
|
|
25
25
|
$: isSelected =
|
|
@@ -27,44 +27,35 @@ $: isSelected =
|
|
|
27
27
|
($focusedContent?.keyPath?.length ?? 0) > 0 &&
|
|
28
28
|
isSameKeyPath($focusedContent?.keyPath ?? [], filteredKeyPath);
|
|
29
29
|
|
|
30
|
-
const
|
|
31
|
-
setFocusedContent({
|
|
32
|
-
dictionaryKey,
|
|
33
|
-
keyPath: filteredKeyPath,
|
|
34
|
-
});
|
|
30
|
+
const handlePress = () => {
|
|
31
|
+
setFocusedContent({ dictionaryKey, keyPath: filteredKeyPath });
|
|
35
32
|
};
|
|
36
33
|
|
|
37
34
|
const handleHover = () => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
dictionaryKey,
|
|
43
|
-
keyPath: filteredKeyPath,
|
|
44
|
-
},
|
|
45
|
-
senderId,
|
|
46
|
-
});
|
|
35
|
+
manager.messenger.send(
|
|
36
|
+
`${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,
|
|
37
|
+
{ dictionaryKey, keyPath: filteredKeyPath }
|
|
38
|
+
);
|
|
47
39
|
};
|
|
48
40
|
|
|
49
41
|
const handleUnhover = () => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
senderId,
|
|
55
|
-
});
|
|
42
|
+
manager.messenger.send(
|
|
43
|
+
`${MessageKey.INTLAYER_HOVERED_CONTENT_CHANGED}/post`,
|
|
44
|
+
null
|
|
45
|
+
);
|
|
56
46
|
};
|
|
57
47
|
</script>
|
|
58
48
|
|
|
59
49
|
{#if $enabled}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
50
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
51
|
+
<intlayer-content-selector
|
|
52
|
+
is-selecting={isSelected || undefined}
|
|
53
|
+
on:intlayer:press={handlePress}
|
|
54
|
+
on:intlayer:hover={handleHover}
|
|
55
|
+
on:intlayer:unhover={handleUnhover}
|
|
65
56
|
>
|
|
66
57
|
<slot />
|
|
67
|
-
</
|
|
58
|
+
</intlayer-content-selector>
|
|
68
59
|
{:else}
|
|
69
60
|
<slot />
|
|
70
61
|
{/if}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { EditorStateManager } from '@intlayer/editor';
|
|
2
|
+
export declare const createEditorStateManager: () => EditorStateManager;
|
|
3
|
+
export declare const getEditorStateManager: () => EditorStateManager;
|
|
4
|
+
export declare const useCommunicator: () => {
|
|
5
|
+
postMessage: (data: any) => void;
|
|
5
6
|
senderId: string;
|
|
6
7
|
};
|
|
7
|
-
export type CommunicatorOptions = Omit<Communicator, 'senderId'>;
|
|
8
|
-
export declare const createCommunicator: (options?: Partial<CommunicatorOptions>) => Writable<Communicator>;
|
|
9
|
-
export declare const useCommunicator: () => Writable<Communicator>;
|
|
@@ -1,54 +1,59 @@
|
|
|
1
1
|
import configuration from '@intlayer/config/built';
|
|
2
|
+
import { EditorStateManager } from '@intlayer/editor';
|
|
2
3
|
import { getContext, setContext } from 'svelte';
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const { editor } = configuration;
|
|
6
|
-
const postMessage = (data) => {
|
|
7
|
-
if (typeof window === 'undefined')
|
|
8
|
-
return;
|
|
9
|
-
const isInIframe = window.self !== window.top;
|
|
10
|
-
if (!isInIframe)
|
|
11
|
-
return;
|
|
12
|
-
if (editor.applicationURL.length > 0) {
|
|
13
|
-
window.postMessage(data, editor.applicationURL);
|
|
14
|
-
}
|
|
15
|
-
if (editor.editorURL.length > 0) {
|
|
16
|
-
window.parent.postMessage(data, editor.editorURL);
|
|
17
|
-
}
|
|
18
|
-
if (editor.cmsURL.length > 0) {
|
|
19
|
-
window.parent.postMessage(data, editor.cmsURL);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
const defaultValue = {
|
|
23
|
-
postMessage,
|
|
4
|
+
const { editor } = configuration ?? {};
|
|
5
|
+
const buildDefaultMessengerConfig = () => ({
|
|
24
6
|
allowedOrigins: [
|
|
25
7
|
editor?.applicationURL,
|
|
26
8
|
editor?.editorURL,
|
|
27
9
|
editor?.cmsURL,
|
|
28
|
-
],
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
10
|
+
].filter(Boolean),
|
|
11
|
+
postMessageFn: (payload, origin) => {
|
|
12
|
+
if (typeof window === 'undefined')
|
|
13
|
+
return;
|
|
14
|
+
const isInIframe = window.self !== window.top;
|
|
15
|
+
if (!isInIframe)
|
|
16
|
+
return;
|
|
17
|
+
window.parent?.postMessage(payload, origin);
|
|
18
|
+
window.postMessage(payload, origin);
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
const MANAGER_KEY = Symbol('INTLAYER_EDITOR_STATE_MANAGER');
|
|
22
|
+
let globalManager = null;
|
|
23
|
+
export const createEditorStateManager = () => {
|
|
24
|
+
const manager = new EditorStateManager({
|
|
25
|
+
mode: 'client',
|
|
26
|
+
messenger: buildDefaultMessengerConfig(),
|
|
27
|
+
configuration,
|
|
36
28
|
});
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
try {
|
|
30
|
+
setContext(MANAGER_KEY, manager);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Outside component context
|
|
34
|
+
}
|
|
35
|
+
globalManager = manager;
|
|
36
|
+
return manager;
|
|
39
37
|
};
|
|
40
|
-
export const
|
|
41
|
-
let context;
|
|
42
|
-
// `getContext` must only run inside a component.
|
|
43
|
-
// If this is called in plain JS, we catch the error and fallback.
|
|
38
|
+
export const getEditorStateManager = () => {
|
|
44
39
|
try {
|
|
45
|
-
|
|
40
|
+
const ctx = getContext(MANAGER_KEY);
|
|
41
|
+
if (ctx)
|
|
42
|
+
return ctx;
|
|
46
43
|
}
|
|
47
44
|
catch {
|
|
48
|
-
//
|
|
45
|
+
// Outside component context
|
|
49
46
|
}
|
|
50
|
-
if (!
|
|
51
|
-
return
|
|
47
|
+
if (!globalManager) {
|
|
48
|
+
return createEditorStateManager();
|
|
52
49
|
}
|
|
53
|
-
return
|
|
50
|
+
return globalManager;
|
|
51
|
+
};
|
|
52
|
+
// Backward-compat alias
|
|
53
|
+
export const useCommunicator = () => {
|
|
54
|
+
const manager = getEditorStateManager();
|
|
55
|
+
return {
|
|
56
|
+
postMessage: (data) => manager.messenger.send(data.type, data.data),
|
|
57
|
+
senderId: manager.messenger.senderId,
|
|
58
|
+
};
|
|
54
59
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type DictionaryContent
|
|
1
|
+
import type { DictionaryContent } from '@intlayer/editor';
|
|
2
|
+
export type { DictionaryContent };
|
|
3
3
|
export declare const useDictionariesRecord: () => {
|
|
4
|
-
dictionariesRecord: import("svelte/store").
|
|
4
|
+
dictionariesRecord: import("svelte/store").Readable<DictionaryContent>;
|
|
5
5
|
};
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
let loaded = false;
|
|
1
|
+
import { readable } from 'svelte/store';
|
|
2
|
+
import { getEditorStateManager } from './communicator';
|
|
4
3
|
export const useDictionariesRecord = () => {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
.flat()
|
|
12
|
-
.map((dictionary) => [dictionary.localId, dictionary]));
|
|
13
|
-
setDictionariesRecord?.(dictionariesList);
|
|
14
|
-
});
|
|
15
|
-
loaded = true;
|
|
16
|
-
}
|
|
4
|
+
const manager = getEditorStateManager();
|
|
5
|
+
const dictionariesRecord = readable(manager.localeDictionaries.value ?? {}, (set) => {
|
|
6
|
+
const handler = (e) => set(e.detail ?? {});
|
|
7
|
+
manager.localeDictionaries.addEventListener('change', handler);
|
|
8
|
+
return () => manager.localeDictionaries.removeEventListener('change', handler);
|
|
9
|
+
});
|
|
17
10
|
return { dictionariesRecord };
|
|
18
11
|
};
|
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readable } from 'svelte/store';
|
|
2
2
|
export type EditorEnabledStateProps = {
|
|
3
|
-
|
|
4
|
-
wrapperEnabled: Writable<boolean>;
|
|
5
|
-
isInIframe: Writable<boolean>;
|
|
6
|
-
enabled: Readable<boolean>;
|
|
7
|
-
};
|
|
8
|
-
export declare const createEditorEnabledClient: () => {
|
|
9
|
-
settingEnabled: Writable<boolean>;
|
|
10
|
-
wrapperEnabled: Writable<boolean>;
|
|
11
|
-
isInIframe: Writable<boolean>;
|
|
12
|
-
enabled: Readable<boolean>;
|
|
3
|
+
enabled: ReturnType<typeof readable<boolean>>;
|
|
13
4
|
};
|
|
14
5
|
export declare const useEditorEnabled: () => EditorEnabledStateProps;
|
|
@@ -1,41 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { derived, writable } from 'svelte/store';
|
|
4
|
-
const EDITOR_ENABLED_KEY = Symbol('EDITOR_ENABLED');
|
|
5
|
-
const detectIframe = () => {
|
|
6
|
-
if (typeof window === 'undefined')
|
|
7
|
-
return false;
|
|
8
|
-
return window.self !== window.top;
|
|
9
|
-
};
|
|
10
|
-
export const createEditorEnabledClient = () => {
|
|
11
|
-
const settingEnabled = writable(configuration.editor.enabled);
|
|
12
|
-
const wrapperEnabled = writable(false);
|
|
13
|
-
const isInIframe = writable(false);
|
|
14
|
-
const enabled = derived([settingEnabled, wrapperEnabled, isInIframe], ([$setting, $wrapper, $iframe]) => $setting && $wrapper && $iframe);
|
|
15
|
-
if (typeof window !== 'undefined') {
|
|
16
|
-
isInIframe.set(detectIframe());
|
|
17
|
-
}
|
|
18
|
-
const state = {
|
|
19
|
-
settingEnabled,
|
|
20
|
-
wrapperEnabled,
|
|
21
|
-
isInIframe,
|
|
22
|
-
enabled,
|
|
23
|
-
};
|
|
24
|
-
setContext(EDITOR_ENABLED_KEY, state);
|
|
25
|
-
return state;
|
|
26
|
-
};
|
|
1
|
+
import { readable } from 'svelte/store';
|
|
2
|
+
import { getEditorStateManager } from './communicator';
|
|
27
3
|
export const useEditorEnabled = () => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// called outside component -> ignore, we’ll use global store
|
|
36
|
-
}
|
|
37
|
-
if (!context) {
|
|
38
|
-
return createEditorEnabledClient();
|
|
39
|
-
}
|
|
40
|
-
return context;
|
|
4
|
+
const manager = getEditorStateManager();
|
|
5
|
+
const enabled = readable(manager.editorEnabled.value ?? false, (set) => {
|
|
6
|
+
const handler = (e) => set(e.detail);
|
|
7
|
+
manager.editorEnabled.addEventListener('change', handler);
|
|
8
|
+
return () => manager.editorEnabled.removeEventListener('change', handler);
|
|
9
|
+
});
|
|
10
|
+
return { enabled };
|
|
41
11
|
};
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
+
import type { FileContent } from '@intlayer/editor';
|
|
1
2
|
import type { KeyPath } from '@intlayer/types/keyPath';
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
export type FocusedContent = {
|
|
5
|
-
dictionaryKey: DictionaryKeys;
|
|
6
|
-
keyPath: KeyPath[];
|
|
7
|
-
} | null;
|
|
3
|
+
import { readable } from 'svelte/store';
|
|
4
|
+
export type { FileContent };
|
|
8
5
|
export type FocusDictionaryStateProps = {
|
|
9
|
-
focusedContent
|
|
10
|
-
setFocusedContent: (content:
|
|
11
|
-
|
|
12
|
-
export declare const createFocusDictionaryClient: () => {
|
|
13
|
-
focusedContent: Writable<FocusedContent | undefined>;
|
|
14
|
-
setFocusedContent: (v: FocusedContent | ((prev: FocusedContent | undefined) => FocusedContent)) => void;
|
|
6
|
+
focusedContent: ReturnType<typeof readable<FileContent | null>>;
|
|
7
|
+
setFocusedContent: (content: FileContent | null) => void;
|
|
8
|
+
setFocusedContentKeyPath: (keyPath: KeyPath[]) => void;
|
|
15
9
|
};
|
|
16
10
|
export declare const useFocusDictionary: () => FocusDictionaryStateProps;
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { useCrossFrameState } from './useCrossFrameState';
|
|
4
|
-
const FOCUS_DICTIONARY_KEY = Symbol('FOCUS_DICTIONARY');
|
|
5
|
-
export const createFocusDictionaryClient = () => {
|
|
6
|
-
const [focusedContent, setFocusedContent] = useCrossFrameState(MessageKey.INTLAYER_FOCUSED_CONTENT_CHANGED, null);
|
|
7
|
-
setContext(FOCUS_DICTIONARY_KEY, { focusedContent, setFocusedContent });
|
|
8
|
-
return { focusedContent, setFocusedContent };
|
|
9
|
-
};
|
|
1
|
+
import { readable } from 'svelte/store';
|
|
2
|
+
import { getEditorStateManager } from './communicator';
|
|
10
3
|
export const useFocusDictionary = () => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
4
|
+
const manager = getEditorStateManager();
|
|
5
|
+
const focusedContent = readable(manager.focusedContent.value ?? null, (set) => {
|
|
6
|
+
const handler = (e) => set(e.detail);
|
|
7
|
+
manager.focusedContent.addEventListener('change', handler);
|
|
8
|
+
return () => manager.focusedContent.removeEventListener('change', handler);
|
|
9
|
+
});
|
|
10
|
+
return {
|
|
11
|
+
focusedContent,
|
|
12
|
+
setFocusedContent: (content) => manager.focusedContent.set(content),
|
|
13
|
+
setFocusedContentKeyPath: (keyPath) => manager.setFocusedContentKeyPath(keyPath),
|
|
14
|
+
};
|
|
22
15
|
};
|
package/dist/editor/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as ContentSelector } from './ContentSelector.svelte';
|
|
2
2
|
export { default as ContentSelectorWrapper } from './ContentSelectorWrapper.svelte';
|
|
3
3
|
export * from './communicator';
|
|
4
|
+
export * from './dictionariesRecord';
|
|
4
5
|
export * from './editorEnabled';
|
|
5
6
|
export * from './focusDictionary';
|
|
6
7
|
export * from './useCrossFrameMessageListener';
|
package/dist/editor/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as ContentSelector } from './ContentSelector.svelte';
|
|
2
2
|
export { default as ContentSelectorWrapper } from './ContentSelectorWrapper.svelte';
|
|
3
3
|
export * from './communicator';
|
|
4
|
+
export * from './dictionariesRecord';
|
|
4
5
|
export * from './editorEnabled';
|
|
5
6
|
export * from './focusDictionary';
|
|
6
7
|
export * from './useCrossFrameMessageListener';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { MessageKey } from '@intlayer/editor';
|
|
2
2
|
export declare const useCrossFrameMessageListener: <S>(key: `${MessageKey}` | `${MessageKey}/post` | `${MessageKey}/get`, onEventTriggered?: (data: S) => void, autoCleanup?: boolean) => (data?: S) => void;
|
|
@@ -1,65 +1,17 @@
|
|
|
1
|
-
import { compareUrls } from '@intlayer/editor';
|
|
2
1
|
import { onDestroy } from 'svelte';
|
|
3
|
-
import {
|
|
4
|
-
import { useCommunicator } from './communicator';
|
|
5
|
-
const subscribers = new Map();
|
|
6
|
-
let windowListenerAttached = false;
|
|
7
|
-
const addSubscriber = (key, cb) => {
|
|
8
|
-
let set = subscribers.get(key);
|
|
9
|
-
if (!set) {
|
|
10
|
-
set = new Set();
|
|
11
|
-
subscribers.set(key, set);
|
|
12
|
-
}
|
|
13
|
-
set.add(cb);
|
|
14
|
-
};
|
|
15
|
-
const removeSubscriber = (key, cb) => {
|
|
16
|
-
const set = subscribers.get(key);
|
|
17
|
-
if (!set)
|
|
18
|
-
return;
|
|
19
|
-
set.delete(cb);
|
|
20
|
-
if (set.size === 0)
|
|
21
|
-
subscribers.delete(key);
|
|
22
|
-
};
|
|
23
|
-
const ensureGlobalListener = (allowedOrigins, selfId) => {
|
|
24
|
-
if (windowListenerAttached)
|
|
25
|
-
return;
|
|
26
|
-
if (typeof window === 'undefined')
|
|
27
|
-
return;
|
|
28
|
-
window.addEventListener('message', (event) => {
|
|
29
|
-
const { type, data, senderId } = event.data ?? {};
|
|
30
|
-
if (!type)
|
|
31
|
-
return;
|
|
32
|
-
if (senderId === selfId)
|
|
33
|
-
return;
|
|
34
|
-
if (!allowedOrigins ||
|
|
35
|
-
allowedOrigins.includes('*') ||
|
|
36
|
-
allowedOrigins.some((o) => compareUrls(o, event.origin))) {
|
|
37
|
-
subscribers.get(type)?.forEach((cb) => {
|
|
38
|
-
cb(data);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
windowListenerAttached = true;
|
|
43
|
-
};
|
|
2
|
+
import { getEditorStateManager } from './communicator';
|
|
44
3
|
export const useCrossFrameMessageListener = (key, onEventTriggered, autoCleanup = true) => {
|
|
45
|
-
const
|
|
46
|
-
const { allowedOrigins, senderId } = get(communicatorStore);
|
|
47
|
-
ensureGlobalListener(allowedOrigins, senderId);
|
|
4
|
+
const manager = getEditorStateManager();
|
|
48
5
|
if (onEventTriggered) {
|
|
49
|
-
const
|
|
50
|
-
addSubscriber(key, cb);
|
|
6
|
+
const unsub = manager.messenger.subscribe(key, onEventTriggered);
|
|
51
7
|
if (autoCleanup) {
|
|
52
8
|
try {
|
|
53
|
-
onDestroy(
|
|
9
|
+
onDestroy(unsub);
|
|
54
10
|
}
|
|
55
11
|
catch {
|
|
56
|
-
//
|
|
12
|
+
// Outside component context
|
|
57
13
|
}
|
|
58
14
|
}
|
|
59
15
|
}
|
|
60
|
-
|
|
61
|
-
const { postMessage, senderId: currentSenderId } = get(communicatorStore);
|
|
62
|
-
postMessage({ type: key, data, senderId: currentSenderId }, '*');
|
|
63
|
-
};
|
|
64
|
-
return postMessageWrapper;
|
|
16
|
+
return (data) => manager.messenger.send(key, data);
|
|
65
17
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
1
|
+
import { type MessageKey } from '@intlayer/editor';
|
|
2
|
+
import { writable } from 'svelte/store';
|
|
3
3
|
export type CrossFrameStateOptions = {
|
|
4
4
|
emit?: boolean;
|
|
5
5
|
receive?: boolean;
|
|
6
6
|
};
|
|
7
|
-
export declare const useCrossFrameState: <S>(key: `${MessageKey}`, initialState?: S
|
|
7
|
+
export declare const useCrossFrameState: <S>(key: `${MessageKey}`, initialState?: S, options?: CrossFrameStateOptions) => [ReturnType<typeof writable<S | undefined>>, (value: S) => void];
|
|
@@ -1,82 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
const resolveState = (state, prevState) => {
|
|
6
|
-
if (typeof state === 'function') {
|
|
7
|
-
return state(prevState);
|
|
8
|
-
}
|
|
9
|
-
return state;
|
|
10
|
-
};
|
|
11
|
-
const toSerializable = (obj) => {
|
|
12
|
-
if (obj === null || obj === undefined)
|
|
13
|
-
return obj;
|
|
14
|
-
return JSON.parse(JSON.stringify(obj));
|
|
15
|
-
};
|
|
1
|
+
import { CrossFrameStateManager } from '@intlayer/editor';
|
|
2
|
+
import { onDestroy } from 'svelte';
|
|
3
|
+
import { writable } from 'svelte/store';
|
|
4
|
+
import { getEditorStateManager } from './communicator';
|
|
16
5
|
export const useCrossFrameState = (key, initialState, options = { emit: true, receive: true }) => {
|
|
17
|
-
|
|
18
|
-
const { state, setState } = crossFrameStateCache.get(key);
|
|
19
|
-
return [state, setState];
|
|
20
|
-
}
|
|
6
|
+
const manager = getEditorStateManager();
|
|
21
7
|
const { emit = true, receive = true } = options;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
data: value,
|
|
36
|
-
senderId,
|
|
37
|
-
}, '*');
|
|
38
|
-
};
|
|
39
|
-
const setState = (valueOrUpdater) => {
|
|
40
|
-
state.update((prev) => {
|
|
41
|
-
const next = resolveState(valueOrUpdater, prev);
|
|
42
|
-
const serialised = toSerializable(next);
|
|
43
|
-
broadcastState(serialised);
|
|
44
|
-
return serialised;
|
|
8
|
+
const stateManager = new CrossFrameStateManager(key, manager.messenger, {
|
|
9
|
+
emit,
|
|
10
|
+
receive,
|
|
11
|
+
initialValue: initialState,
|
|
12
|
+
});
|
|
13
|
+
stateManager.start();
|
|
14
|
+
const store = writable(stateManager.value);
|
|
15
|
+
const handler = (e) => store.set(e.detail);
|
|
16
|
+
stateManager.addEventListener('change', handler);
|
|
17
|
+
try {
|
|
18
|
+
onDestroy(() => {
|
|
19
|
+
stateManager.removeEventListener('change', handler);
|
|
20
|
+
stateManager.stop();
|
|
45
21
|
});
|
|
46
|
-
};
|
|
47
|
-
const postState = () => {
|
|
48
|
-
const { postMessage, senderId } = get(communicatorStore) ?? {};
|
|
49
|
-
if (typeof postMessage !== 'function')
|
|
50
|
-
return;
|
|
51
|
-
postMessage({
|
|
52
|
-
type: `${key}/post`,
|
|
53
|
-
data: get(state),
|
|
54
|
-
senderId,
|
|
55
|
-
}, '*');
|
|
56
|
-
};
|
|
57
|
-
// Emit initial state
|
|
58
|
-
broadcastState(initialValue);
|
|
59
|
-
// If receiving, ask for state
|
|
60
|
-
if (receive && typeof get(state) === 'undefined') {
|
|
61
|
-
const { postMessage, senderId } = get(communicatorStore) ?? {};
|
|
62
|
-
if (typeof postMessage === 'function') {
|
|
63
|
-
postMessage({ type: `${key}/get`, senderId }, '*');
|
|
64
|
-
}
|
|
65
22
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// Listen for requests
|
|
74
|
-
const getListenerKey = emit ? `${key}/get` : `${key}/ignore`;
|
|
75
|
-
useCrossFrameMessageListener(getListenerKey, (_) => {
|
|
76
|
-
if (emit) {
|
|
77
|
-
broadcastState(get(state));
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
crossFrameStateCache.set(key, { state, setState, postState });
|
|
81
|
-
return [state, setState];
|
|
23
|
+
catch {
|
|
24
|
+
// Outside component context
|
|
25
|
+
}
|
|
26
|
+
const setState = (value) => {
|
|
27
|
+
stateManager.set(value);
|
|
28
|
+
};
|
|
29
|
+
return [store, setState];
|
|
82
30
|
};
|
package/dist/editor/useEditor.js
CHANGED
|
@@ -1,46 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { onDestroy } from 'svelte';
|
|
3
|
-
import {
|
|
4
|
-
import { useDictionariesRecord } from './dictionariesRecord';
|
|
5
|
-
import { useEditorEnabled } from './editorEnabled';
|
|
6
|
-
import { useCrossFrameMessageListener } from './useCrossFrameMessageListener';
|
|
7
|
-
import { useIframeClickMerger } from './useIframeClickInterceptor';
|
|
8
|
-
let initialized = false;
|
|
9
|
-
let unsubscribeIsInIframe = null;
|
|
1
|
+
import { defineIntlayerElements } from '@intlayer/editor';
|
|
2
|
+
import { onDestroy, onMount } from 'svelte';
|
|
3
|
+
import { createEditorStateManager } from './communicator';
|
|
10
4
|
export const useEditor = () => {
|
|
11
5
|
if (typeof window === 'undefined')
|
|
12
6
|
return;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const inIframe = get(editorEnabled.isInIframe);
|
|
29
|
-
const setting = get(editorEnabled.settingEnabled);
|
|
30
|
-
if (inIframe && setting) {
|
|
31
|
-
getEditorEnabled();
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
checkEnabled();
|
|
35
|
-
// Subscribe to changes
|
|
36
|
-
editorEnabled.isInIframe.subscribe(() => checkEnabled());
|
|
37
|
-
// Keep track of unsubscribe so we *could* clean up if we ever wanted
|
|
38
|
-
unsubscribeIsInIframe = editorEnabled.isInIframe.subscribe(() => checkEnabled());
|
|
39
|
-
onDestroy(() => {
|
|
40
|
-
initialized = false;
|
|
41
|
-
if (unsubscribeIsInIframe) {
|
|
42
|
-
unsubscribeIsInIframe();
|
|
43
|
-
unsubscribeIsInIframe = null;
|
|
44
|
-
}
|
|
45
|
-
});
|
|
7
|
+
const manager = createEditorStateManager();
|
|
8
|
+
try {
|
|
9
|
+
onMount(() => {
|
|
10
|
+
defineIntlayerElements();
|
|
11
|
+
manager.start();
|
|
12
|
+
});
|
|
13
|
+
onDestroy(() => {
|
|
14
|
+
manager.stop();
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Outside component context - start immediately
|
|
19
|
+
defineIntlayerElements();
|
|
20
|
+
manager.start();
|
|
21
|
+
}
|
|
46
22
|
};
|
|
@@ -1,29 +1,8 @@
|
|
|
1
1
|
import { MessageKey, mergeIframeClick } from '@intlayer/editor';
|
|
2
|
-
import { onDestroy, onMount } from 'svelte';
|
|
3
2
|
import { useCrossFrameMessageListener } from './useCrossFrameMessageListener';
|
|
4
3
|
export const useIframeClickInterceptor = () => {
|
|
5
|
-
|
|
6
|
-
const handler = () => {
|
|
7
|
-
postMessage();
|
|
8
|
-
};
|
|
9
|
-
onMount(() => {
|
|
10
|
-
if (typeof window !== 'undefined') {
|
|
11
|
-
window.addEventListener('mousedown', handler);
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
onDestroy(() => {
|
|
15
|
-
if (typeof window !== 'undefined') {
|
|
16
|
-
window.removeEventListener('mousedown', handler);
|
|
17
|
-
}
|
|
18
|
-
});
|
|
4
|
+
useCrossFrameMessageListener(MessageKey.INTLAYER_IFRAME_CLICKED);
|
|
19
5
|
};
|
|
20
6
|
export const useIframeClickMerger = () => {
|
|
21
|
-
|
|
22
|
-
useCrossFrameMessageListener(MessageKey.INTLAYER_IFRAME_CLICKED, (data) => {
|
|
23
|
-
// mergeIframeClick(data); // mergeIframeClick expects an event, but data might be stripped?
|
|
24
|
-
// Actually mergeIframeClick logic in editor package probably dispatches a custom event or similar.
|
|
25
|
-
// The Vue implementation passes `mergeIframeClick` directly as the callback.
|
|
26
|
-
// Let's assume mergeIframeClick handles whatever data is passed, or we wrap it if needed.
|
|
27
|
-
mergeIframeClick(data);
|
|
28
|
-
});
|
|
7
|
+
useCrossFrameMessageListener(MessageKey.INTLAYER_IFRAME_CLICKED, mergeIframeClick);
|
|
29
8
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-intlayer",
|
|
3
|
-
"version": "8.3.
|
|
3
|
+
"version": "8.3.4",
|
|
4
4
|
"description": "Easily internationalize i18n your Svelte applications with type-safe multilingual content management.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"intlayer",
|
|
@@ -72,12 +72,11 @@
|
|
|
72
72
|
"typecheck": "tsc --noEmit --project tsconfig.types.json"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@intlayer/api": "8.3.
|
|
76
|
-
"@intlayer/config": "8.3.
|
|
77
|
-
"@intlayer/core": "8.3.
|
|
78
|
-
"@intlayer/editor": "8.3.
|
|
79
|
-
"@intlayer/types": "8.3.
|
|
80
|
-
"@intlayer/unmerged-dictionaries-entry": "8.3.3"
|
|
75
|
+
"@intlayer/api": "8.3.4",
|
|
76
|
+
"@intlayer/config": "8.3.4",
|
|
77
|
+
"@intlayer/core": "8.3.4",
|
|
78
|
+
"@intlayer/editor": "8.3.4",
|
|
79
|
+
"@intlayer/types": "8.3.4"
|
|
81
80
|
},
|
|
82
81
|
"devDependencies": {
|
|
83
82
|
"@sveltejs/adapter-auto": "7.0.1",
|
|
@@ -90,7 +89,7 @@
|
|
|
90
89
|
"rimraf": "6.1.3",
|
|
91
90
|
"svelte": "5.53.11",
|
|
92
91
|
"svelte-check": "4.4.5",
|
|
93
|
-
"tsdown": "0.21.
|
|
92
|
+
"tsdown": "0.21.4",
|
|
94
93
|
"typescript": "5.9.3",
|
|
95
94
|
"vite": "8.0.0",
|
|
96
95
|
"vitest": "4.1.0"
|