@intlayer/editor-react 5.0.6 → 5.1.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/ChangedContentContext.cjs +2 -2
- package/dist/cjs/ChangedContentContext.cjs.map +1 -1
- package/dist/cjs/CommunicatorContext.cjs +20 -10
- package/dist/cjs/CommunicatorContext.cjs.map +1 -1
- package/dist/cjs/ConfigurationContext.cjs +1 -1
- package/dist/cjs/ConfigurationContext.cjs.map +1 -1
- package/dist/cjs/DictionariesRecordContext.cjs +19 -29
- package/dist/cjs/DictionariesRecordContext.cjs.map +1 -1
- package/dist/cjs/EditedContentContext.cjs +12 -7
- package/dist/cjs/EditedContentContext.cjs.map +1 -1
- package/dist/cjs/EditorEnabledContext.cjs +1 -1
- package/dist/cjs/EditorEnabledContext.cjs.map +1 -1
- package/dist/cjs/EditorProvider.cjs +3 -4
- package/dist/cjs/EditorProvider.cjs.map +1 -1
- package/dist/cjs/FocusDictionaryContext.cjs +2 -2
- package/dist/cjs/FocusDictionaryContext.cjs.map +1 -1
- package/dist/cjs/useCrossFrameMessageListener.cjs +9 -7
- package/dist/cjs/useCrossFrameMessageListener.cjs.map +1 -1
- package/dist/cjs/useCrossFrameState.cjs +15 -9
- package/dist/cjs/useCrossFrameState.cjs.map +1 -1
- package/dist/cjs/useCrossURLPathState.cjs.map +1 -1
- package/dist/esm/ChangedContentContext.mjs +2 -2
- package/dist/esm/ChangedContentContext.mjs.map +1 -1
- package/dist/esm/CommunicatorContext.mjs +23 -11
- package/dist/esm/CommunicatorContext.mjs.map +1 -1
- package/dist/esm/ConfigurationContext.mjs +5 -2
- package/dist/esm/ConfigurationContext.mjs.map +1 -1
- package/dist/esm/DictionariesRecordContext.mjs +21 -30
- package/dist/esm/DictionariesRecordContext.mjs.map +1 -1
- package/dist/esm/EditedContentContext.mjs +12 -7
- package/dist/esm/EditedContentContext.mjs.map +1 -1
- package/dist/esm/EditorEnabledContext.mjs +1 -1
- package/dist/esm/EditorEnabledContext.mjs.map +1 -1
- package/dist/esm/EditorProvider.mjs +3 -4
- package/dist/esm/EditorProvider.mjs.map +1 -1
- package/dist/esm/FocusDictionaryContext.mjs +2 -2
- package/dist/esm/FocusDictionaryContext.mjs.map +1 -1
- package/dist/esm/useCrossFrameMessageListener.mjs +10 -8
- package/dist/esm/useCrossFrameMessageListener.mjs.map +1 -1
- package/dist/esm/useCrossFrameState.mjs +15 -9
- package/dist/esm/useCrossFrameState.mjs.map +1 -1
- package/dist/esm/useCrossURLPathState.mjs.map +1 -1
- package/dist/types/CommunicatorContext.d.ts +3 -1
- package/dist/types/CommunicatorContext.d.ts.map +1 -1
- package/dist/types/ConfigurationContext.d.ts +2 -2
- package/dist/types/ConfigurationContext.d.ts.map +1 -1
- package/dist/types/DictionariesRecordContext.d.ts +3 -3
- package/dist/types/DictionariesRecordContext.d.ts.map +1 -1
- package/dist/types/EditedContentContext.d.ts +2 -2
- package/dist/types/EditedContentContext.d.ts.map +1 -1
- package/dist/types/EditorEnabledContext.d.ts +1 -1
- package/dist/types/EditorEnabledContext.d.ts.map +1 -1
- package/dist/types/EditorProvider.d.ts +4 -4
- package/dist/types/EditorProvider.d.ts.map +1 -1
- package/dist/types/useCrossFrameMessageListener.d.ts.map +1 -1
- package/dist/types/useCrossFrameState.d.ts.map +1 -1
- package/dist/types/useCrossURLPathState.d.ts.map +1 -1
- package/package.json +14 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ChangedContentContext.tsx"],"sourcesContent":["'use client';\n\nimport type { Dictionary } from '@intlayer/core';\nimport {\n createContext,\n useContext,\n useState,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport type { DictionaryContent } from './DictionariesRecordContext';\n\ntype ChangedContentStateContextType = {\n changedContent: Record<Dictionary['key'], Dictionary> | undefined;\n};\n\nconst ChangedContentStateContext = createContext<\n ChangedContentStateContextType | undefined\n>(undefined);\n\ntype ChangedContentActionsContextType = {\n setChangedContent: (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => void;\n};\n\nconst ChangedContentActionsContext = createContext<\n ChangedContentActionsContextType | undefined\n>(undefined);\n\nexport const ChangedContentProvider: FC<PropsWithChildren> = ({ children }) => {\n const [changedContent, setChangedContentState] = useState<DictionaryContent>(\n {}\n );\n\n const setChangedContent = (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => {\n setChangedContentState((prev) => ({\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: newValue,\n },\n }));\n };\n\n return (\n <ChangedContentStateContext
|
|
1
|
+
{"version":3,"sources":["../../src/ChangedContentContext.tsx"],"sourcesContent":["'use client';\n\nimport type { Dictionary } from '@intlayer/core';\nimport {\n createContext,\n useContext,\n useState,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport type { DictionaryContent } from './DictionariesRecordContext';\n\ntype ChangedContentStateContextType = {\n changedContent: Record<Dictionary['key'], Dictionary> | undefined;\n};\n\nconst ChangedContentStateContext = createContext<\n ChangedContentStateContextType | undefined\n>(undefined);\n\ntype ChangedContentActionsContextType = {\n setChangedContent: (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => void;\n};\n\nconst ChangedContentActionsContext = createContext<\n ChangedContentActionsContextType | undefined\n>(undefined);\n\nexport const ChangedContentProvider: FC<PropsWithChildren> = ({ children }) => {\n const [changedContent, setChangedContentState] = useState<DictionaryContent>(\n {}\n );\n\n const setChangedContent = (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => {\n setChangedContentState((prev) => ({\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: newValue,\n },\n }));\n };\n\n return (\n <ChangedContentStateContext\n value={{\n changedContent,\n }}\n >\n <ChangedContentActionsContext\n value={{\n setChangedContent,\n }}\n >\n {children}\n </ChangedContentActionsContext>\n </ChangedContentStateContext>\n );\n};\n\nexport const useChangedContentActions = () => {\n const context = useContext(ChangedContentActionsContext);\n\n if (!context) {\n throw new Error(\n 'useChangedContent must be used within an ChangedContentProvider'\n );\n }\n\n return context;\n};\n\nexport const useChangedContent = () => {\n const stateContext = useContext(ChangedContentStateContext);\n const actionContext = useChangedContentActions();\n\n if (!stateContext) {\n throw new Error(\n 'useChangedContent must be used within an ChangedContentProvider'\n );\n }\n\n return { ...stateContext, ...actionContext };\n};\n"],"mappings":";AAuDM;AApDN;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAOP,MAAM,6BAA6B,cAEjC,MAAS;AASX,MAAM,+BAA+B,cAEnC,MAAS;AAEJ,MAAM,yBAAgD,CAAC,EAAE,SAAS,MAAM;AAC7E,QAAM,CAAC,gBAAgB,sBAAsB,IAAI;AAAA,IAC/C,CAAC;AAAA,EACH;AAEA,QAAM,oBAAoB,CACxB,eACA,aACG;AACH,2BAAuB,CAAC,UAAU;AAAA,MAChC,GAAG;AAAA,MACH,CAAC,aAAa,GAAG;AAAA,QACf,GAAG,OAAO,aAAa;AAAA,QACvB,SAAS;AAAA,MACX;AAAA,IACF,EAAE;AAAA,EACJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL;AAAA,MACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL;AAAA,UACF;AAAA,UAEC;AAAA;AAAA,MACH;AAAA;AAAA,EACF;AAEJ;AAEO,MAAM,2BAA2B,MAAM;AAC5C,QAAM,UAAU,WAAW,4BAA4B;AAEvD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,MAAM,oBAAoB,MAAM;AACrC,QAAM,eAAe,WAAW,0BAA0B;AAC1D,QAAM,gBAAgB,yBAAyB;AAE/C,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,cAAc,GAAG,cAAc;AAC7C;","names":[]}
|
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { getConfiguration } from "@intlayer/config/client";
|
|
3
4
|
import {
|
|
4
5
|
createContext,
|
|
5
|
-
useContext
|
|
6
|
+
useContext,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef
|
|
6
9
|
} from "react";
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
import { v4 as uuid } from "uuid";
|
|
11
|
+
const { editor } = getConfiguration();
|
|
12
|
+
const CommunicatorContext = createContext({
|
|
13
|
+
postMessage: () => null,
|
|
14
|
+
allowedOrigins: [editor.applicationURL, editor.editorURL, editor.cmsURL],
|
|
15
|
+
senderId: ""
|
|
16
|
+
});
|
|
17
|
+
const CommunicatorProvider = ({
|
|
18
|
+
children,
|
|
19
|
+
allowedOrigins,
|
|
20
|
+
postMessage
|
|
21
|
+
}) => {
|
|
22
|
+
const senderIdRef = useRef(uuid());
|
|
23
|
+
const value = useMemo(
|
|
24
|
+
() => ({ postMessage, allowedOrigins, senderId: senderIdRef.current }),
|
|
25
|
+
[postMessage, allowedOrigins, senderIdRef.current]
|
|
26
|
+
);
|
|
27
|
+
return /* @__PURE__ */ jsx(CommunicatorContext, { value, children });
|
|
17
28
|
};
|
|
29
|
+
const useCommunicator = () => useContext(CommunicatorContext);
|
|
18
30
|
export {
|
|
19
31
|
CommunicatorProvider,
|
|
20
32
|
useCommunicator
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/CommunicatorContext.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\n\nexport type UseCrossPlatformStateProps = {\n postMessage: typeof window.postMessage;\n allowedOrigins?: string[];\n};\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/CommunicatorContext.tsx"],"sourcesContent":["'use client';\n\nimport { getConfiguration } from '@intlayer/config/client';\nimport {\n createContext,\n useContext,\n useMemo,\n useRef,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport { v4 as uuid } from 'uuid'; // if you prefer a UUID library\n\nexport type UseCrossPlatformStateProps = {\n postMessage: typeof window.postMessage;\n allowedOrigins?: string[];\n senderId: string;\n};\n\nconst { editor } = getConfiguration();\n\nconst CommunicatorContext = createContext<UseCrossPlatformStateProps>({\n postMessage: () => null,\n allowedOrigins: [editor.applicationURL, editor.editorURL, editor.cmsURL],\n senderId: '',\n});\n\nexport type CommunicatorProviderProps = PropsWithChildren<\n Omit<UseCrossPlatformStateProps, 'senderId'>\n>;\n\nexport const CommunicatorProvider: FC<CommunicatorProviderProps> = ({\n children,\n allowedOrigins,\n postMessage,\n}) => {\n // Create a stable, unique ID for the lifetime of this app/iframe instance.\n const senderIdRef = useRef(uuid());\n\n const value = useMemo(\n () => ({ postMessage, allowedOrigins, senderId: senderIdRef.current }),\n [postMessage, allowedOrigins, senderIdRef.current]\n );\n\n return <CommunicatorContext value={value}>{children}</CommunicatorContext>;\n};\n\nexport const useCommunicator = () => useContext(CommunicatorContext);\n"],"mappings":";AA4CS;AA1CT,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,MAAM,YAAY;AAQ3B,MAAM,EAAE,OAAO,IAAI,iBAAiB;AAEpC,MAAM,sBAAsB,cAA0C;AAAA,EACpE,aAAa,MAAM;AAAA,EACnB,gBAAgB,CAAC,OAAO,gBAAgB,OAAO,WAAW,OAAO,MAAM;AAAA,EACvE,UAAU;AACZ,CAAC;AAMM,MAAM,uBAAsD,CAAC;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AACF,MAAM;AAEJ,QAAM,cAAc,OAAO,KAAK,CAAC;AAEjC,QAAM,QAAQ;AAAA,IACZ,OAAO,EAAE,aAAa,gBAAgB,UAAU,YAAY,QAAQ;AAAA,IACpE,CAAC,aAAa,gBAAgB,YAAY,OAAO;AAAA,EACnD;AAEA,SAAO,oBAAC,uBAAoB,OAAe,UAAS;AACtD;AAEO,MAAM,kBAAkB,MAAM,WAAW,mBAAmB;","names":[]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createContext,
|
|
5
|
+
useContext
|
|
6
|
+
} from "react";
|
|
4
7
|
import { useCrossFrameState } from "./useCrossFrameState.mjs";
|
|
5
8
|
const ConfigurationStatesContext = createContext(
|
|
6
9
|
void 0
|
|
@@ -9,7 +12,7 @@ const useConfigurationState = () => useCrossFrameState("INTLAYER_CONFIGURATION",
|
|
|
9
12
|
receive: false,
|
|
10
13
|
emit: true
|
|
11
14
|
});
|
|
12
|
-
const ConfigurationProvider = ({ children, configuration }) => /* @__PURE__ */ jsx(ConfigurationStatesContext
|
|
15
|
+
const ConfigurationProvider = ({ children, configuration }) => /* @__PURE__ */ jsx(ConfigurationStatesContext, { value: configuration, children });
|
|
13
16
|
const useConfiguration = () => {
|
|
14
17
|
const statesContext = useContext(ConfigurationStatesContext);
|
|
15
18
|
if (!statesContext) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ConfigurationContext.tsx"],"sourcesContent":["'use client';\n\nimport { type IntlayerConfig } from '@intlayer/config/client';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/ConfigurationContext.tsx"],"sourcesContent":["'use client';\n\nimport { type IntlayerConfig } from '@intlayer/config/client';\nimport {\n type FC,\n type PropsWithChildren,\n createContext,\n useContext,\n} from 'react';\nimport { useCrossFrameState } from './useCrossFrameState';\n\nconst ConfigurationStatesContext = createContext<IntlayerConfig | undefined>(\n undefined\n);\n\nexport const useConfigurationState = () =>\n useCrossFrameState<IntlayerConfig>('INTLAYER_CONFIGURATION', undefined, {\n receive: false,\n emit: true,\n });\n\nexport type ConfigurationProviderProps = {\n configuration?: IntlayerConfig;\n};\n\nexport const ConfigurationProvider: FC<\n PropsWithChildren<ConfigurationProviderProps>\n> = ({ children, configuration }) => (\n <ConfigurationStatesContext value={configuration}>\n {children}\n </ConfigurationStatesContext>\n);\n\nexport const useConfiguration = () => {\n const statesContext = useContext(ConfigurationStatesContext);\n\n if (!statesContext) {\n throw new Error(\n 'useConfigurationStates must be used within a ConfigurationProvider'\n );\n }\n\n return statesContext;\n};\n"],"mappings":";AA4BE;AAzBF;AAAA,EAGE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AAEnC,MAAM,6BAA6B;AAAA,EACjC;AACF;AAEO,MAAM,wBAAwB,MACnC,mBAAmC,0BAA0B,QAAW;AAAA,EACtE,SAAS;AAAA,EACT,MAAM;AACR,CAAC;AAMI,MAAM,wBAET,CAAC,EAAE,UAAU,cAAc,MAC7B,oBAAC,8BAA2B,OAAO,eAChC,UACH;AAGK,MAAM,mBAAmB,MAAM;AACpC,QAAM,gBAAgB,WAAW,0BAA0B;AAE3D,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import {
|
|
4
4
|
createContext,
|
|
5
|
-
useContext
|
|
5
|
+
useContext,
|
|
6
|
+
useMemo
|
|
6
7
|
} from "react";
|
|
7
8
|
import { useCrossFrameState } from "./useCrossFrameState.mjs";
|
|
8
9
|
const DictionariesRecordStatesContext = createContext(void 0);
|
|
@@ -14,37 +15,27 @@ const DictionariesRecordProvider = ({
|
|
|
14
15
|
"INTLAYER_LOCALE_DICTIONARIES_CHANGED",
|
|
15
16
|
void 0
|
|
16
17
|
);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
DictionariesRecordActionsContext.Provider,
|
|
23
|
-
{
|
|
24
|
-
value: {
|
|
25
|
-
setLocaleDictionaries,
|
|
26
|
-
setLocaleDictionary: (dictionary) => {
|
|
27
|
-
setLocaleDictionaries((dictionaries) => ({
|
|
28
|
-
...dictionaries,
|
|
29
|
-
[dictionary.key]: dictionary
|
|
30
|
-
}));
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
children
|
|
34
|
-
}
|
|
35
|
-
)
|
|
36
|
-
}
|
|
18
|
+
const stateValue = useMemo(
|
|
19
|
+
() => ({
|
|
20
|
+
localeDictionaries: localeDictionaries ?? {}
|
|
21
|
+
}),
|
|
22
|
+
[localeDictionaries]
|
|
37
23
|
);
|
|
24
|
+
const actionValue = useMemo(
|
|
25
|
+
() => ({
|
|
26
|
+
setLocaleDictionaries,
|
|
27
|
+
setLocaleDictionary: (dictionary) => {
|
|
28
|
+
setLocaleDictionaries((dictionaries) => ({
|
|
29
|
+
...dictionaries,
|
|
30
|
+
[dictionary.key]: dictionary
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
}),
|
|
34
|
+
[setLocaleDictionaries]
|
|
35
|
+
);
|
|
36
|
+
return /* @__PURE__ */ jsx(DictionariesRecordStatesContext, { value: stateValue, children: /* @__PURE__ */ jsx(DictionariesRecordActionsContext, { value: actionValue, children }) });
|
|
38
37
|
};
|
|
39
|
-
const useDictionariesRecordActions = () =>
|
|
40
|
-
const context = useContext(DictionariesRecordActionsContext);
|
|
41
|
-
if (!context) {
|
|
42
|
-
throw new Error(
|
|
43
|
-
"useDictionariesRecordActions must be used within a DictionariesRecordProvider"
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
return context;
|
|
47
|
-
};
|
|
38
|
+
const useDictionariesRecordActions = () => useContext(DictionariesRecordActionsContext);
|
|
48
39
|
const useDictionariesRecord = () => {
|
|
49
40
|
const actionsContext = useDictionariesRecordActions();
|
|
50
41
|
const statesContext = useContext(DictionariesRecordStatesContext);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/DictionariesRecordContext.tsx"],"sourcesContent":["'use client';\n\nimport type { Dictionary } from '@intlayer/core';\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport { useCrossFrameState } from './useCrossFrameState';\n\nexport type DictionaryContent = Record<Dictionary['key'], Dictionary>;\n\ntype DictionariesRecordStatesContextType = {\n localeDictionaries: DictionaryContent;\n};\ntype DictionariesRecordActionsContextType = {\n setLocaleDictionaries:
|
|
1
|
+
{"version":3,"sources":["../../src/DictionariesRecordContext.tsx"],"sourcesContent":["'use client';\n\nimport type { Dictionary } from '@intlayer/core';\nimport {\n createContext,\n useContext,\n type Dispatch,\n type SetStateAction,\n type FC,\n type PropsWithChildren,\n useMemo,\n} from 'react';\nimport { useCrossFrameState } from './useCrossFrameState';\n\nexport type DictionaryContent = Record<Dictionary['key'], Dictionary>;\n\ntype DictionariesRecordStatesContextType = {\n localeDictionaries: DictionaryContent;\n};\ntype DictionariesRecordActionsContextType = {\n setLocaleDictionaries: Dispatch<SetStateAction<DictionaryContent>>;\n setLocaleDictionary: (dictionary: Dictionary) => void;\n};\n\nconst DictionariesRecordStatesContext = createContext<\n DictionariesRecordStatesContextType | undefined\n>(undefined);\nconst DictionariesRecordActionsContext = createContext<\n DictionariesRecordActionsContextType | undefined\n>(undefined);\n\nexport const DictionariesRecordProvider: FC<PropsWithChildren> = ({\n children,\n}) => {\n const [localeDictionaries, setLocaleDictionaries] =\n useCrossFrameState<DictionaryContent>(\n 'INTLAYER_LOCALE_DICTIONARIES_CHANGED',\n undefined\n );\n\n const stateValue = useMemo(\n () => ({\n localeDictionaries: localeDictionaries ?? {},\n }),\n [localeDictionaries]\n );\n\n const actionValue = useMemo(\n () => ({\n setLocaleDictionaries,\n setLocaleDictionary: (dictionary: Dictionary) => {\n setLocaleDictionaries((dictionaries) => ({\n ...dictionaries,\n [dictionary.key]: dictionary,\n }));\n },\n }),\n [setLocaleDictionaries]\n );\n\n return (\n <DictionariesRecordStatesContext value={stateValue}>\n <DictionariesRecordActionsContext value={actionValue}>\n {children}\n </DictionariesRecordActionsContext>\n </DictionariesRecordStatesContext>\n );\n};\n\nexport const useDictionariesRecordActions = () =>\n useContext(DictionariesRecordActionsContext);\n\nexport const useDictionariesRecord = () => {\n const actionsContext = useDictionariesRecordActions();\n const statesContext = useContext(DictionariesRecordStatesContext);\n\n if (!statesContext) {\n throw new Error(\n 'useDictionariesRecordStates must be used within a DictionariesRecordProvider'\n );\n }\n\n return { ...statesContext, ...actionsContext };\n};\n"],"mappings":";AA8DM;AA3DN;AAAA,EACE;AAAA,EACA;AAAA,EAKA;AAAA,OACK;AACP,SAAS,0BAA0B;AAYnC,MAAM,kCAAkC,cAEtC,MAAS;AACX,MAAM,mCAAmC,cAEvC,MAAS;AAEJ,MAAM,6BAAoD,CAAC;AAAA,EAChE;AACF,MAAM;AACJ,QAAM,CAAC,oBAAoB,qBAAqB,IAC9C;AAAA,IACE;AAAA,IACA;AAAA,EACF;AAEF,QAAM,aAAa;AAAA,IACjB,OAAO;AAAA,MACL,oBAAoB,sBAAsB,CAAC;AAAA,IAC7C;AAAA,IACA,CAAC,kBAAkB;AAAA,EACrB;AAEA,QAAM,cAAc;AAAA,IAClB,OAAO;AAAA,MACL;AAAA,MACA,qBAAqB,CAAC,eAA2B;AAC/C,8BAAsB,CAAC,kBAAkB;AAAA,UACvC,GAAG;AAAA,UACH,CAAC,WAAW,GAAG,GAAG;AAAA,QACpB,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,CAAC,qBAAqB;AAAA,EACxB;AAEA,SACE,oBAAC,mCAAgC,OAAO,YACtC,8BAAC,oCAAiC,OAAO,aACtC,UACH,GACF;AAEJ;AAEO,MAAM,+BAA+B,MAC1C,WAAW,gCAAgC;AAEtC,MAAM,wBAAwB,MAAM;AACzC,QAAM,iBAAiB,6BAA6B;AACpD,QAAM,gBAAgB,WAAW,+BAA+B;AAEhE,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,eAAe,GAAG,eAAe;AAC/C;","names":[]}
|
|
@@ -24,8 +24,7 @@ const EditedContentProvider = ({ children }) => {
|
|
|
24
24
|
const { localeDictionaries } = useDictionariesRecord();
|
|
25
25
|
const [editedContent, setEditedContentState] = useCrossFrameState(
|
|
26
26
|
"INTLAYER_EDITED_CONTENT_CHANGED",
|
|
27
|
-
void 0
|
|
28
|
-
{ emit: true, receive: true }
|
|
27
|
+
void 0
|
|
29
28
|
);
|
|
30
29
|
const setEditedContent = (dictionaryKey, newValue) => {
|
|
31
30
|
setEditedContentState((prev) => ({
|
|
@@ -39,7 +38,9 @@ const EditedContentProvider = ({ children }) => {
|
|
|
39
38
|
const addEditedContent = (dictionaryKey, newValue, keyPath = [], overwrite = true) => {
|
|
40
39
|
setEditedContentState((prev) => {
|
|
41
40
|
const originalContent = localeDictionaries[dictionaryKey]?.content;
|
|
42
|
-
const currentContent =
|
|
41
|
+
const currentContent = structuredClone(
|
|
42
|
+
prev?.[dictionaryKey]?.content ?? originalContent
|
|
43
|
+
);
|
|
43
44
|
let newKeyPath = keyPath;
|
|
44
45
|
if (!overwrite) {
|
|
45
46
|
let index = 0;
|
|
@@ -72,7 +73,9 @@ const EditedContentProvider = ({ children }) => {
|
|
|
72
73
|
const renameEditedContent = (dictionaryKey, newKey, keyPath = []) => {
|
|
73
74
|
setEditedContentState((prev) => {
|
|
74
75
|
const originalContent = localeDictionaries[dictionaryKey]?.content;
|
|
75
|
-
const currentContent =
|
|
76
|
+
const currentContent = structuredClone(
|
|
77
|
+
prev?.[dictionaryKey]?.content ?? originalContent
|
|
78
|
+
);
|
|
76
79
|
const contentWithNewField = renameContentNodeByKeyPath(
|
|
77
80
|
currentContent,
|
|
78
81
|
newKey,
|
|
@@ -90,7 +93,9 @@ const EditedContentProvider = ({ children }) => {
|
|
|
90
93
|
const removeEditedContent = (dictionaryKey, keyPath) => {
|
|
91
94
|
setEditedContentState((prev) => {
|
|
92
95
|
const originalContent = localeDictionaries[dictionaryKey]?.content;
|
|
93
|
-
const currentContent =
|
|
96
|
+
const currentContent = structuredClone(
|
|
97
|
+
prev?.[dictionaryKey]?.content ?? originalContent
|
|
98
|
+
);
|
|
94
99
|
const initialContent = getContentNodeByKeyPath(originalContent, keyPath);
|
|
95
100
|
const restoredContent = editDictionaryByKeyPath(
|
|
96
101
|
currentContent,
|
|
@@ -132,13 +137,13 @@ const EditedContentProvider = ({ children }) => {
|
|
|
132
137
|
return getContentNodeByKeyPath(currentContent, keyPath);
|
|
133
138
|
};
|
|
134
139
|
return /* @__PURE__ */ jsx(
|
|
135
|
-
EditedContentStateContext
|
|
140
|
+
EditedContentStateContext,
|
|
136
141
|
{
|
|
137
142
|
value: {
|
|
138
143
|
editedContent
|
|
139
144
|
},
|
|
140
145
|
children: /* @__PURE__ */ jsx(
|
|
141
|
-
EditedContentActionsContext
|
|
146
|
+
EditedContentActionsContext,
|
|
142
147
|
{
|
|
143
148
|
value: {
|
|
144
149
|
setEditedContentState,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/EditedContentContext.tsx"],"sourcesContent":["'use client';\n\nimport {\n type Dictionary,\n type ContentNode,\n type KeyPath,\n editDictionaryByKeyPath,\n getContentNodeByKeyPath,\n renameContentNodeByKeyPath,\n} from '@intlayer/core';\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport {\n useDictionariesRecord,\n type DictionaryContent,\n} from './DictionariesRecordContext';\nimport { useCrossFrameState } from './useCrossFrameState';\n\ntype EditedContentStateContextType = {\n editedContent: Record<Dictionary['key'], Dictionary> | undefined;\n};\n\nconst EditedContentStateContext = createContext<\n EditedContentStateContextType | undefined\n>(undefined);\n\ntype EditedContentActionsContextType = {\n setEditedContentState: (\n editedContent: Record<Dictionary['key'], Dictionary>\n ) => void;\n setEditedContent: (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => void;\n addEditedContent: (\n dictionaryKey: Dictionary['key'],\n newValue: ContentNode,\n keyPath?: KeyPath[],\n overwrite?: boolean\n ) => void;\n renameEditedContent: (\n dictionaryKey: Dictionary['key'],\n newKey: KeyPath['key'],\n keyPath?: KeyPath[]\n ) => void;\n removeEditedContent: (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ) => void;\n restoreEditedContent: (dictionaryKey: Dictionary['key']) => void;\n clearEditedDictionaryContent: (dictionaryKey: Dictionary['key']) => void;\n clearEditedContent: () => void;\n getEditedContentValue: (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ) => ContentNode | undefined;\n};\n\nconst EditedContentActionsContext = createContext<\n EditedContentActionsContextType | undefined\n>(undefined);\n\nexport const useEditedContentState = () =>\n useCrossFrameState<DictionaryContent>(\n 'INTLAYER_EDITED_CONTENT_CHANGED',\n undefined,\n { emit: true, receive: false }\n );\n\nexport const EditedContentProvider: FC<PropsWithChildren> = ({ children }) => {\n const { localeDictionaries } = useDictionariesRecord();\n\n const [editedContent, setEditedContentState] =\n useCrossFrameState<DictionaryContent>(\n 'INTLAYER_EDITED_CONTENT_CHANGED',\n undefined,\n { emit: true, receive: true }\n );\n\n const setEditedContent = (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => {\n setEditedContentState((prev) => ({\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: newValue,\n },\n }));\n };\n\n const addEditedContent = (\n dictionaryKey: Dictionary['key'],\n newValue: ContentNode,\n keyPath: KeyPath[] = [],\n overwrite: boolean = true\n ) => {\n setEditedContentState((prev) => {\n // Get the starting content: edited version if available, otherwise a deep copy of the original\n const originalContent = localeDictionaries[dictionaryKey]?.content;\n const currentContent =\n prev?.[dictionaryKey]?.content ||\n JSON.parse(JSON.stringify(originalContent));\n\n let newKeyPath = keyPath;\n if (!overwrite) {\n // Find a unique key based on the keyPath provided\n let index = 0;\n const otherKeyPath = keyPath.slice(0, -1);\n const lastKeyPath: KeyPath = keyPath[keyPath.length - 1];\n let finalKey = lastKeyPath.key;\n\n // Loop until we find a key that does not exist\n while (\n typeof getContentNodeByKeyPath(currentContent, newKeyPath) !==\n 'undefined'\n ) {\n index++;\n finalKey =\n index === 0 ? lastKeyPath.key : `${lastKeyPath.key} (${index})`;\n newKeyPath = [\n ...otherKeyPath,\n { ...lastKeyPath, key: finalKey } as KeyPath,\n ];\n }\n }\n\n const updatedContent = editDictionaryByKeyPath(\n currentContent,\n newKeyPath,\n newValue\n );\n\n return {\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: updatedContent as Dictionary['content'],\n },\n };\n });\n };\n\n const renameEditedContent = (\n dictionaryKey: Dictionary['key'],\n newKey: KeyPath['key'],\n keyPath: KeyPath[] = []\n ) => {\n setEditedContentState((prev) => {\n // Retrieve the base content: use edited version if available, otherwise deep copy of original\n const originalContent = localeDictionaries[dictionaryKey]?.content;\n const currentContent =\n prev?.[dictionaryKey]?.content ||\n JSON.parse(JSON.stringify(originalContent));\n\n const contentWithNewField = renameContentNodeByKeyPath(\n currentContent,\n newKey,\n keyPath\n );\n\n return {\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: contentWithNewField as Dictionary['content'],\n },\n };\n });\n };\n\n const removeEditedContent = (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ) => {\n setEditedContentState((prev) => {\n // Retrieve the original content as reference\n const originalContent = localeDictionaries[dictionaryKey]?.content;\n const currentContent =\n prev?.[dictionaryKey]?.content ||\n JSON.parse(JSON.stringify(originalContent));\n\n // Get the initial value from the original dictionary content\n const initialContent = getContentNodeByKeyPath(originalContent, keyPath);\n\n // Restore the value at the given keyPath\n const restoredContent = editDictionaryByKeyPath(\n currentContent,\n keyPath,\n initialContent\n );\n\n return {\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: restoredContent as Dictionary['content'],\n },\n };\n });\n };\n\n const restoreEditedContent = (dictionaryKey: Dictionary['key']) => {\n setEditedContentState((prev) => {\n const updated = { ...prev };\n delete updated[dictionaryKey];\n return updated;\n });\n };\n\n const clearEditedDictionaryContent = (dictionaryKey: Dictionary['key']) => {\n setEditedContentState((prev) => {\n const filtered = Object.entries(prev).reduce((acc, [key, value]) => {\n if (key === dictionaryKey) {\n return acc;\n }\n return { ...acc, [key]: value };\n }, {} as DictionaryContent);\n return filtered;\n });\n };\n\n const clearEditedContent = () => {\n setEditedContentState({});\n };\n\n const getEditedContentValue = (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ): ContentNode | undefined => {\n const currentContent = editedContent?.[dictionaryKey]?.content ?? {};\n return getContentNodeByKeyPath(currentContent, keyPath);\n };\n\n return (\n <EditedContentStateContext.Provider\n value={{\n editedContent,\n }}\n >\n <EditedContentActionsContext.Provider\n value={{\n setEditedContentState,\n setEditedContent,\n addEditedContent,\n renameEditedContent,\n removeEditedContent,\n restoreEditedContent,\n clearEditedDictionaryContent,\n clearEditedContent,\n getEditedContentValue,\n }}\n >\n {children}\n </EditedContentActionsContext.Provider>\n </EditedContentStateContext.Provider>\n );\n};\n\nexport const useEditedContentActions = () => {\n const context = useContext(EditedContentActionsContext);\n\n if (!context) {\n throw new Error(\n 'useEditedContent must be used within an EditedContentProvider'\n );\n }\n\n return context;\n};\n\nexport const useEditedContent = () => {\n const stateContext = useContext(EditedContentStateContext);\n const actionContext = useEditedContentActions();\n\n if (!stateContext) {\n throw new Error(\n 'useEditedContent must be used within an EditedContentProvider'\n );\n }\n\n return { ...stateContext, ...actionContext };\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/EditedContentContext.tsx"],"sourcesContent":["'use client';\n\nimport {\n type Dictionary,\n type ContentNode,\n type KeyPath,\n editDictionaryByKeyPath,\n getContentNodeByKeyPath,\n renameContentNodeByKeyPath,\n} from '@intlayer/core';\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport {\n useDictionariesRecord,\n type DictionaryContent,\n} from './DictionariesRecordContext';\nimport { useCrossFrameState } from './useCrossFrameState';\n\ntype EditedContentStateContextType = {\n editedContent: Record<Dictionary['key'], Dictionary> | undefined;\n};\n\nconst EditedContentStateContext = createContext<\n EditedContentStateContextType | undefined\n>(undefined);\n\ntype EditedContentActionsContextType = {\n setEditedContentState: (\n editedContent: Record<Dictionary['key'], Dictionary>\n ) => void;\n setEditedContent: (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => void;\n addEditedContent: (\n dictionaryKey: Dictionary['key'],\n newValue: ContentNode<any>,\n keyPath?: KeyPath[],\n overwrite?: boolean\n ) => void;\n renameEditedContent: (\n dictionaryKey: Dictionary['key'],\n newKey: KeyPath['key'],\n keyPath?: KeyPath[]\n ) => void;\n removeEditedContent: (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ) => void;\n restoreEditedContent: (dictionaryKey: Dictionary['key']) => void;\n clearEditedDictionaryContent: (dictionaryKey: Dictionary['key']) => void;\n clearEditedContent: () => void;\n getEditedContentValue: (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ) => ContentNode | undefined;\n};\n\nconst EditedContentActionsContext = createContext<\n EditedContentActionsContextType | undefined\n>(undefined);\n\nexport const useEditedContentState = () =>\n useCrossFrameState<DictionaryContent>(\n 'INTLAYER_EDITED_CONTENT_CHANGED',\n undefined,\n { emit: true, receive: false }\n );\n\nexport const EditedContentProvider: FC<PropsWithChildren> = ({ children }) => {\n const { localeDictionaries } = useDictionariesRecord();\n\n const [editedContent, setEditedContentState] =\n useCrossFrameState<DictionaryContent>(\n 'INTLAYER_EDITED_CONTENT_CHANGED',\n undefined\n );\n\n const setEditedContent = (\n dictionaryKey: Dictionary['key'],\n newValue: Dictionary['content']\n ) => {\n setEditedContentState((prev) => ({\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: newValue,\n },\n }));\n };\n\n const addEditedContent = (\n dictionaryKey: Dictionary['key'],\n newValue: ContentNode,\n keyPath: KeyPath[] = [],\n overwrite: boolean = true\n ) => {\n setEditedContentState((prev) => {\n // Get the starting content: edited version if available, otherwise a deep copy of the original\n const originalContent = localeDictionaries[dictionaryKey]?.content;\n const currentContent = structuredClone(\n prev?.[dictionaryKey]?.content ?? originalContent\n );\n\n let newKeyPath = keyPath;\n if (!overwrite) {\n // Find a unique key based on the keyPath provided\n let index = 0;\n const otherKeyPath = keyPath.slice(0, -1);\n const lastKeyPath: KeyPath = keyPath[keyPath.length - 1];\n let finalKey = lastKeyPath.key;\n\n // Loop until we find a key that does not exist\n while (\n typeof getContentNodeByKeyPath(currentContent, newKeyPath) !==\n 'undefined'\n ) {\n index++;\n finalKey =\n index === 0 ? lastKeyPath.key : `${lastKeyPath.key} (${index})`;\n newKeyPath = [\n ...otherKeyPath,\n { ...lastKeyPath, key: finalKey } as KeyPath,\n ];\n }\n }\n\n const updatedContent = editDictionaryByKeyPath(\n currentContent,\n newKeyPath,\n newValue\n );\n\n return {\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: updatedContent as Dictionary['content'],\n },\n };\n });\n };\n\n const renameEditedContent = (\n dictionaryKey: Dictionary['key'],\n newKey: KeyPath['key'],\n keyPath: KeyPath[] = []\n ) => {\n setEditedContentState((prev) => {\n // Retrieve the base content: use edited version if available, otherwise deep copy of original\n const originalContent = localeDictionaries[dictionaryKey]?.content;\n const currentContent = structuredClone(\n prev?.[dictionaryKey]?.content ?? originalContent\n );\n\n const contentWithNewField = renameContentNodeByKeyPath(\n currentContent,\n newKey,\n keyPath\n );\n\n return {\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: contentWithNewField as Dictionary['content'],\n },\n };\n });\n };\n\n const removeEditedContent = (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ) => {\n setEditedContentState((prev) => {\n // Retrieve the original content as reference\n const originalContent = localeDictionaries[dictionaryKey]?.content;\n const currentContent = structuredClone(\n prev?.[dictionaryKey]?.content ?? originalContent\n );\n\n // Get the initial value from the original dictionary content\n const initialContent = getContentNodeByKeyPath(originalContent, keyPath);\n\n // Restore the value at the given keyPath\n const restoredContent = editDictionaryByKeyPath(\n currentContent,\n keyPath,\n initialContent\n );\n\n return {\n ...prev,\n [dictionaryKey]: {\n ...prev?.[dictionaryKey],\n content: restoredContent as Dictionary['content'],\n },\n };\n });\n };\n\n const restoreEditedContent = (dictionaryKey: Dictionary['key']) => {\n setEditedContentState((prev) => {\n const updated = { ...prev };\n delete updated[dictionaryKey];\n return updated;\n });\n };\n\n const clearEditedDictionaryContent = (dictionaryKey: Dictionary['key']) => {\n setEditedContentState((prev) => {\n const filtered = Object.entries(prev).reduce((acc, [key, value]) => {\n if (key === dictionaryKey) {\n return acc;\n }\n return { ...acc, [key]: value };\n }, {} as DictionaryContent);\n return filtered;\n });\n };\n\n const clearEditedContent = () => {\n setEditedContentState({});\n };\n\n const getEditedContentValue = (\n dictionaryKey: Dictionary['key'],\n keyPath: KeyPath[]\n ): ContentNode | undefined => {\n const currentContent = editedContent?.[dictionaryKey]?.content ?? {};\n return getContentNodeByKeyPath(currentContent, keyPath);\n };\n\n return (\n <EditedContentStateContext\n value={{\n editedContent,\n }}\n >\n <EditedContentActionsContext\n value={{\n setEditedContentState,\n setEditedContent,\n addEditedContent,\n renameEditedContent,\n removeEditedContent,\n restoreEditedContent,\n clearEditedDictionaryContent,\n clearEditedContent,\n getEditedContentValue,\n }}\n >\n {children}\n </EditedContentActionsContext>\n </EditedContentStateContext>\n );\n};\n\nexport const useEditedContentActions = () => {\n const context = useContext(EditedContentActionsContext);\n\n if (!context) {\n throw new Error(\n 'useEditedContent must be used within an EditedContentProvider'\n );\n }\n\n return context;\n};\n\nexport const useEditedContent = () => {\n const stateContext = useContext(EditedContentStateContext);\n const actionContext = useEditedContentActions();\n\n if (!stateContext) {\n throw new Error(\n 'useEditedContent must be used within an EditedContentProvider'\n );\n }\n\n return { ...stateContext, ...actionContext };\n};\n"],"mappings":"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","names":[]}
|
|
@@ -16,7 +16,7 @@ const EditorEnabledProvider = ({ children }) => {
|
|
|
16
16
|
emit: false,
|
|
17
17
|
receive: true
|
|
18
18
|
});
|
|
19
|
-
return /* @__PURE__ */ jsx(EditorEnabledContext
|
|
19
|
+
return /* @__PURE__ */ jsx(EditorEnabledContext, { value: { enabled: isEnabled }, children });
|
|
20
20
|
};
|
|
21
21
|
const useEditorEnabled = () => {
|
|
22
22
|
const context = useContext(EditorEnabledContext);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/EditorEnabledContext.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport {\n CrossFrameStateOptions,\n useCrossFrameState,\n} from './useCrossFrameState';\n\nexport type EditorEnabledStateProps = {\n enabled: boolean;\n};\n\nconst EditorEnabledContext = createContext<EditorEnabledStateProps | undefined>(\n undefined\n);\n\nexport const useEditorEnabledState = (options?: CrossFrameStateOptions) =>\n useCrossFrameState('INTLAYER_EDITOR_ENABLED', false, options);\n\nexport const EditorEnabledProvider: FC<PropsWithChildren> = ({ children }) => {\n const [isEnabled] = useEditorEnabledState({\n emit: false,\n receive: true,\n });\n\n return (\n <EditorEnabledContext
|
|
1
|
+
{"version":3,"sources":["../../src/EditorEnabledContext.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n} from 'react';\nimport {\n type CrossFrameStateOptions,\n useCrossFrameState,\n} from './useCrossFrameState';\n\nexport type EditorEnabledStateProps = {\n enabled: boolean;\n};\n\nconst EditorEnabledContext = createContext<EditorEnabledStateProps | undefined>(\n undefined\n);\n\nexport const useEditorEnabledState = (options?: CrossFrameStateOptions) =>\n useCrossFrameState('INTLAYER_EDITOR_ENABLED', false, options);\n\nexport const EditorEnabledProvider: FC<PropsWithChildren> = ({ children }) => {\n const [isEnabled] = useEditorEnabledState({\n emit: false,\n receive: true,\n });\n\n return (\n <EditorEnabledContext value={{ enabled: isEnabled }}>\n {children}\n </EditorEnabledContext>\n );\n};\n\nexport const useEditorEnabled = () => {\n const context = useContext(EditorEnabledContext);\n\n if (!context) {\n throw new Error('useEditorEnabled must be used within a EnabledProvider');\n }\n return context;\n};\n"],"mappings":";AA+BI;AA7BJ;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EAEE;AAAA,OACK;AAMP,MAAM,uBAAuB;AAAA,EAC3B;AACF;AAEO,MAAM,wBAAwB,CAAC,YACpC,mBAAmB,2BAA2B,OAAO,OAAO;AAEvD,MAAM,wBAA+C,CAAC,EAAE,SAAS,MAAM;AAC5E,QAAM,CAAC,SAAS,IAAI,sBAAsB;AAAA,IACxC,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AAED,SACE,oBAAC,wBAAqB,OAAO,EAAE,SAAS,UAAU,GAC/C,UACH;AAEJ;AAEO,MAAM,mBAAmB,MAAM;AACpC,QAAM,UAAU,WAAW,oBAAoB;AAE/C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,SAAO;AACT;","names":[]}
|
|
@@ -13,16 +13,15 @@ import {
|
|
|
13
13
|
useEditorEnabled
|
|
14
14
|
} from "./EditorEnabledContext.mjs";
|
|
15
15
|
import { FocusDictionaryProvider } from "./FocusDictionaryContext.mjs";
|
|
16
|
-
const EditorProviderEnabled = ({ mode, children }) => {
|
|
16
|
+
const EditorProviderEnabled = ({ mode, children, ...props }) => {
|
|
17
17
|
const { enabled } = useEditorEnabled();
|
|
18
|
-
return enabled || mode === "editor" ? /* @__PURE__ */ jsx(DictionariesRecordProvider, { children: /* @__PURE__ */ jsx(EditedContentProvider, { children: /* @__PURE__ */ jsx(FocusDictionaryProvider, { children }) }) }) : children;
|
|
18
|
+
return enabled || mode === "editor" ? /* @__PURE__ */ jsx(CommunicatorProvider, { ...props, children: /* @__PURE__ */ jsx(DictionariesRecordProvider, { children: /* @__PURE__ */ jsx(EditedContentProvider, { children: /* @__PURE__ */ jsx(FocusDictionaryProvider, { children }) }) }) }) : children;
|
|
19
19
|
};
|
|
20
20
|
const EditorProvider = ({
|
|
21
21
|
children,
|
|
22
|
-
mode,
|
|
23
22
|
configuration,
|
|
24
23
|
...props
|
|
25
|
-
}) => /* @__PURE__ */ jsx(
|
|
24
|
+
}) => /* @__PURE__ */ jsx(EditorEnabledProvider, { children: /* @__PURE__ */ jsx(ConfigurationProvider, { configuration, children: /* @__PURE__ */ jsx(EditorProviderEnabled, { ...props, children }) }) });
|
|
26
25
|
export {
|
|
27
26
|
EditorProvider
|
|
28
27
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/EditorProvider.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, type PropsWithChildren } from 'react';\nimport {\n
|
|
1
|
+
{"version":3,"sources":["../../src/EditorProvider.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, type PropsWithChildren } from 'react';\nimport {\n type CommunicatorProviderProps,\n CommunicatorProvider,\n} from './CommunicatorContext';\nimport {\n type ConfigurationProviderProps,\n ConfigurationProvider,\n} from './ConfigurationContext';\nimport { DictionariesRecordProvider } from './DictionariesRecordContext';\nimport { EditedContentProvider } from './EditedContentContext';\nimport {\n EditorEnabledProvider,\n useEditorEnabled,\n} from './EditorEnabledContext';\nimport { FocusDictionaryProvider } from './FocusDictionaryContext';\n\ntype EditorProviderEnabledProps = CommunicatorProviderProps & {\n mode: 'editor' | 'client';\n};\n\nconst EditorProviderEnabled: FC<\n PropsWithChildren<EditorProviderEnabledProps>\n> = ({ mode, children, ...props }) => {\n const { enabled } = useEditorEnabled();\n\n return enabled || mode === 'editor' ? (\n <CommunicatorProvider {...props}>\n <DictionariesRecordProvider>\n <EditedContentProvider>\n <FocusDictionaryProvider>{children}</FocusDictionaryProvider>\n </EditedContentProvider>\n </DictionariesRecordProvider>\n </CommunicatorProvider>\n ) : (\n children\n );\n};\n\nexport type EditorProviderProps = EditorProviderEnabledProps &\n ConfigurationProviderProps;\n\nexport const EditorProvider: FC<PropsWithChildren<EditorProviderProps>> = ({\n children,\n configuration,\n ...props\n}) => (\n <EditorEnabledProvider>\n <ConfigurationProvider configuration={configuration}>\n <EditorProviderEnabled {...props}>{children}</EditorProviderEnabled>\n </ConfigurationProvider>\n </EditorEnabledProvider>\n);\n"],"mappings":";AAgCU;AA7BV;AAAA,EAEE;AAAA,OACK;AACP;AAAA,EAEE;AAAA,OACK;AACP,SAAS,kCAAkC;AAC3C,SAAS,6BAA6B;AACtC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,+BAA+B;AAMxC,MAAM,wBAEF,CAAC,EAAE,MAAM,UAAU,GAAG,MAAM,MAAM;AACpC,QAAM,EAAE,QAAQ,IAAI,iBAAiB;AAErC,SAAO,WAAW,SAAS,WACzB,oBAAC,wBAAsB,GAAG,OACxB,8BAAC,8BACC,8BAAC,yBACC,8BAAC,2BAAyB,UAAS,GACrC,GACF,GACF,IAEA;AAEJ;AAKO,MAAM,iBAA6D,CAAC;AAAA,EACzE;AAAA,EACA;AAAA,EACA,GAAG;AACL,MACE,oBAAC,yBACC,8BAAC,yBAAsB,eACrB,8BAAC,yBAAuB,GAAG,OAAQ,UAAS,GAC9C,GACF;","names":[]}
|
|
@@ -22,8 +22,8 @@ const FocusDictionaryProvider = ({
|
|
|
22
22
|
return { ...prev, keyPath };
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
|
-
return /* @__PURE__ */ jsx(FocusDictionaryStateContext
|
|
26
|
-
FocusDictionaryActionsContext
|
|
25
|
+
return /* @__PURE__ */ jsx(FocusDictionaryStateContext, { value: { focusedContent }, children: /* @__PURE__ */ jsx(
|
|
26
|
+
FocusDictionaryActionsContext,
|
|
27
27
|
{
|
|
28
28
|
value: { setFocusedContent, setFocusedContentKeyPath },
|
|
29
29
|
children
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/FocusDictionaryContext.tsx"],"sourcesContent":["'use client';\n\nimport type { KeyPath } from '@intlayer/core';\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n type Dispatch,\n type SetStateAction,\n} from 'react';\nimport { useCrossFrameState } from './useCrossFrameState';\n\ntype DictionaryPath = string;\n\nexport type FileContent = {\n dictionaryKey: string;\n keyPath?: KeyPath[];\n dictionaryPath?: DictionaryPath;\n};\n\ntype FocusDictionaryState = {\n focusedContent: FileContent | null;\n};\n\ntype FocusDictionaryActions = {\n setFocusedContent: Dispatch<SetStateAction<FileContent | null>>;\n setFocusedContentKeyPath: (keyPath: KeyPath[]) => void;\n};\n\nconst FocusDictionaryStateContext = createContext<\n FocusDictionaryState | undefined\n>(undefined);\nconst FocusDictionaryActionsContext = createContext<\n FocusDictionaryActions | undefined\n>(undefined);\n\nexport const FocusDictionaryProvider: FC<PropsWithChildren> = ({\n children,\n}) => {\n const [focusedContent, setFocusedContent] =\n useCrossFrameState<FileContent | null>(\n 'INTLAYER_FOCUSED_CONTENT_CHANGED',\n null\n );\n\n const setFocusedContentKeyPath = (keyPath: KeyPath[]) => {\n setFocusedContent((prev) => {\n if (!prev) {\n return prev; // nothing to update if there's no focused content\n }\n return { ...prev, keyPath };\n });\n };\n\n return (\n <FocusDictionaryStateContext
|
|
1
|
+
{"version":3,"sources":["../../src/FocusDictionaryContext.tsx"],"sourcesContent":["'use client';\n\nimport type { KeyPath } from '@intlayer/core';\nimport {\n createContext,\n useContext,\n type FC,\n type PropsWithChildren,\n type Dispatch,\n type SetStateAction,\n} from 'react';\nimport { useCrossFrameState } from './useCrossFrameState';\n\ntype DictionaryPath = string;\n\nexport type FileContent = {\n dictionaryKey: string;\n keyPath?: KeyPath[];\n dictionaryPath?: DictionaryPath;\n};\n\ntype FocusDictionaryState = {\n focusedContent: FileContent | null;\n};\n\ntype FocusDictionaryActions = {\n setFocusedContent: Dispatch<SetStateAction<FileContent | null>>;\n setFocusedContentKeyPath: (keyPath: KeyPath[]) => void;\n};\n\nconst FocusDictionaryStateContext = createContext<\n FocusDictionaryState | undefined\n>(undefined);\nconst FocusDictionaryActionsContext = createContext<\n FocusDictionaryActions | undefined\n>(undefined);\n\nexport const FocusDictionaryProvider: FC<PropsWithChildren> = ({\n children,\n}) => {\n const [focusedContent, setFocusedContent] =\n useCrossFrameState<FileContent | null>(\n 'INTLAYER_FOCUSED_CONTENT_CHANGED',\n null\n );\n\n const setFocusedContentKeyPath = (keyPath: KeyPath[]) => {\n setFocusedContent((prev) => {\n if (!prev) {\n return prev; // nothing to update if there's no focused content\n }\n return { ...prev, keyPath };\n });\n };\n\n return (\n <FocusDictionaryStateContext value={{ focusedContent }}>\n <FocusDictionaryActionsContext\n value={{ setFocusedContent, setFocusedContentKeyPath }}\n >\n {children}\n </FocusDictionaryActionsContext>\n </FocusDictionaryStateContext>\n );\n};\n\nexport const useFocusDictionaryActions = () => {\n const context = useContext(FocusDictionaryActionsContext);\n if (context === undefined) {\n throw new Error(\n 'useFocusDictionaryActions must be used within a FocusDictionaryProvider'\n );\n }\n return context;\n};\n\nexport const useFocusDictionary = () => {\n const actionContext = useFocusDictionaryActions();\n const stateContext = useContext(FocusDictionaryStateContext);\n\n if (stateContext === undefined) {\n throw new Error(\n 'useFocusDictionaryState must be used within a FocusDictionaryProvider'\n );\n }\n\n return { ...stateContext, ...actionContext };\n};\n"],"mappings":";AAyDM;AAtDN;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AACP,SAAS,0BAA0B;AAmBnC,MAAM,8BAA8B,cAElC,MAAS;AACX,MAAM,gCAAgC,cAEpC,MAAS;AAEJ,MAAM,0BAAiD,CAAC;AAAA,EAC7D;AACF,MAAM;AACJ,QAAM,CAAC,gBAAgB,iBAAiB,IACtC;AAAA,IACE;AAAA,IACA;AAAA,EACF;AAEF,QAAM,2BAA2B,CAAC,YAAuB;AACvD,sBAAkB,CAAC,SAAS;AAC1B,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AACA,aAAO,EAAE,GAAG,MAAM,QAAQ;AAAA,IAC5B,CAAC;AAAA,EACH;AAEA,SACE,oBAAC,+BAA4B,OAAO,EAAE,eAAe,GACnD;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,mBAAmB,yBAAyB;AAAA,MAEpD;AAAA;AAAA,EACH,GACF;AAEJ;AAEO,MAAM,4BAA4B,MAAM;AAC7C,QAAM,UAAU,WAAW,6BAA6B;AACxD,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,MAAM,qBAAqB,MAAM;AACtC,QAAM,gBAAgB,0BAA0B;AAChD,QAAM,eAAe,WAAW,2BAA2B;AAE3D,MAAI,iBAAiB,QAAW;AAC9B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,GAAG,cAAc,GAAG,cAAc;AAC7C;","names":[]}
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useCallback, useEffect } from "react";
|
|
2
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
3
3
|
import { useCommunicator } from "./CommunicatorContext.mjs";
|
|
4
4
|
const useCrossFrameMessageListener = (key, onEventTriggered) => {
|
|
5
|
-
const { allowedOrigins, postMessage } = useCommunicator();
|
|
5
|
+
const { allowedOrigins, postMessage, senderId } = useCommunicator();
|
|
6
6
|
useEffect(() => {
|
|
7
7
|
if (onEventTriggered) {
|
|
8
8
|
const handleMessage = (event) => {
|
|
9
|
-
|
|
9
|
+
const { type, data, senderId: msgSenderId } = event.data;
|
|
10
|
+
if (type !== key) return;
|
|
11
|
+
if (msgSenderId === senderId) return;
|
|
10
12
|
if (typeof allowedOrigins === "undefined" || allowedOrigins?.includes(event.origin) || allowedOrigins?.includes("*")) {
|
|
11
|
-
onEventTriggered(
|
|
13
|
+
onEventTriggered(data);
|
|
12
14
|
}
|
|
13
15
|
};
|
|
14
16
|
window.addEventListener("message", handleMessage);
|
|
15
17
|
return () => window.removeEventListener("message", handleMessage);
|
|
16
18
|
}
|
|
17
|
-
}, [
|
|
19
|
+
}, [allowedOrigins, postMessage, senderId]);
|
|
18
20
|
const postMessageWrapper = useCallback(
|
|
19
21
|
(data) => {
|
|
20
|
-
postMessage({ type: key, data });
|
|
22
|
+
postMessage({ type: key, data, senderId });
|
|
21
23
|
},
|
|
22
|
-
[key,
|
|
24
|
+
[postMessage, key, senderId]
|
|
23
25
|
);
|
|
24
|
-
return postMessageWrapper;
|
|
26
|
+
return useMemo(() => postMessageWrapper, [postMessageWrapper]);
|
|
25
27
|
};
|
|
26
28
|
export {
|
|
27
29
|
useCrossFrameMessageListener
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/useCrossFrameMessageListener.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect } from 'react';\nimport { useCommunicator } from './CommunicatorContext';\nimport { type MessageKey } from './messageKey';\n\n/**\n * useCrossFrameMessageListener\n *\n * This React hook listens for messages sent via the `postMessage` API and triggers a callback\n * whenever a message of the specified type (`key`) is received. It is useful for synchronizing\n * state or events across different windows, iframes, or contexts.\n *\n * @template S - The type of the data payload in the message.\n * @param {`${MessageKey}` | `${MessageKey}/post` | `${MessageKey}/get`} key - A unique identifier for the message type to listen for.\n * @param {(data: S) => void} [onEventTriggered] - A callback function triggered when a message\n * with the specified key is received. The callback receives the message data as its argument.\n *\n * @returns {{ postMessage: (data: S) => void }} An object containing a `postMessage` function\n * that allows broadcasting messages with the specified key and data.\n */\nexport const useCrossFrameMessageListener = <S,>(\n key: `${MessageKey}` | `${MessageKey}/post` | `${MessageKey}/get`,\n onEventTriggered?: (data: S) => void\n) => {\n const { allowedOrigins, postMessage } = useCommunicator();\n\n useEffect(() => {\n if (onEventTriggered) {\n /**\n * Message handler to process incoming messages.\n *\n * - **Message Filtering:** Ensures only messages with the specified `key` are processed.\n * - **Origin Validation:** Checks that the origin of the message is within the allowed origins.\n *\n * @param {MessageEvent<{ type: string; data: S }>} event - The incoming message event object.\n */\n const handleMessage = (\n event: MessageEvent<{ type: string; data: S }>\n ) => {\n // Ignore messages that do not match the current key\n if (
|
|
1
|
+
{"version":3,"sources":["../../src/useCrossFrameMessageListener.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo } from 'react';\nimport { useCommunicator } from './CommunicatorContext';\nimport { type MessageKey } from './messageKey';\n\n/**\n * useCrossFrameMessageListener\n *\n * This React hook listens for messages sent via the `postMessage` API and triggers a callback\n * whenever a message of the specified type (`key`) is received. It is useful for synchronizing\n * state or events across different windows, iframes, or contexts.\n *\n * @template S - The type of the data payload in the message.\n * @param {`${MessageKey}` | `${MessageKey}/post` | `${MessageKey}/get`} key - A unique identifier for the message type to listen for.\n * @param {(data: S) => void} [onEventTriggered] - A callback function triggered when a message\n * with the specified key is received. The callback receives the message data as its argument.\n *\n * @returns {{ postMessage: (data: S) => void }} An object containing a `postMessage` function\n * that allows broadcasting messages with the specified key and data.\n */\nexport const useCrossFrameMessageListener = <S,>(\n key: `${MessageKey}` | `${MessageKey}/post` | `${MessageKey}/get`,\n onEventTriggered?: (data: S) => void\n) => {\n const { allowedOrigins, postMessage, senderId } = useCommunicator();\n\n useEffect(() => {\n if (onEventTriggered) {\n /**\n * Message handler to process incoming messages.\n *\n * - **Message Filtering:** Ensures only messages with the specified `key` are processed.\n * - **Origin Validation:** Checks that the origin of the message is within the allowed origins.\n *\n * @param {MessageEvent<{ type: string; data: S }>} event - The incoming message event object.\n */\n const handleMessage = (\n event: MessageEvent<{ type: string; data: S; senderId: string }>\n ) => {\n const { type, data, senderId: msgSenderId } = event.data;\n\n // Ignore messages that do not match the current key\n if (type !== key) return;\n\n // Ignore messages from myself\n if (msgSenderId === senderId) return;\n\n // Check if the message origin is allowed\n if (\n typeof allowedOrigins === 'undefined' ||\n allowedOrigins?.includes(event.origin) ||\n allowedOrigins?.includes('*')\n ) {\n // Update the local state with the received data\n onEventTriggered(data);\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n // Clean up the event listener on unmount\n return () => window.removeEventListener('message', handleMessage);\n }\n }, [allowedOrigins, postMessage, senderId]);\n\n /**\n * A wrapper function around the `postMessage` function to broadcast messages efficiently.\n *\n * - **Encapsulation:** Ensures the `postMessage` function is scoped to the provided key.\n * - **Ease of Use:** Simplifies broadcasting messages with consistent type and format.\n *\n * @param {S} data - The data payload to include in the message.\n * @returns {void}\n */\n const postMessageWrapper: (data: S) => void = useCallback(\n (data) => {\n postMessage({ type: key, data, senderId });\n },\n [postMessage, key, senderId]\n );\n\n return useMemo(() => postMessageWrapper, [postMessageWrapper]);\n};\n"],"mappings":";AAEA,SAAS,aAAa,WAAW,eAAe;AAChD,SAAS,uBAAuB;AAkBzB,MAAM,+BAA+B,CAC1C,KACA,qBACG;AACH,QAAM,EAAE,gBAAgB,aAAa,SAAS,IAAI,gBAAgB;AAElE,YAAU,MAAM;AACd,QAAI,kBAAkB;AASpB,YAAM,gBAAgB,CACpB,UACG;AACH,cAAM,EAAE,MAAM,MAAM,UAAU,YAAY,IAAI,MAAM;AAGpD,YAAI,SAAS,IAAK;AAGlB,YAAI,gBAAgB,SAAU;AAG9B,YACE,OAAO,mBAAmB,eAC1B,gBAAgB,SAAS,MAAM,MAAM,KACrC,gBAAgB,SAAS,GAAG,GAC5B;AAEA,2BAAiB,IAAI;AAAA,QACvB;AAAA,MACF;AAEA,aAAO,iBAAiB,WAAW,aAAa;AAGhD,aAAO,MAAM,OAAO,oBAAoB,WAAW,aAAa;AAAA,IAClE;AAAA,EACF,GAAG,CAAC,gBAAgB,aAAa,QAAQ,CAAC;AAW1C,QAAM,qBAAwC;AAAA,IAC5C,CAAC,SAAS;AACR,kBAAY,EAAE,MAAM,KAAK,MAAM,SAAS,CAAC;AAAA,IAC3C;AAAA,IACA,CAAC,aAAa,KAAK,QAAQ;AAAA,EAC7B;AAEA,SAAO,QAAQ,MAAM,oBAAoB,CAAC,kBAAkB,CAAC;AAC/D;","names":[]}
|
|
@@ -9,7 +9,7 @@ import { useCommunicator } from "./CommunicatorContext.mjs";
|
|
|
9
9
|
import { useCrossFrameMessageListener } from "./useCrossFrameMessageListener.mjs";
|
|
10
10
|
const resolveState = (state, prevState) => typeof state === "function" ? state(prevState) : state;
|
|
11
11
|
const useCrossFrameState = (key, initialState, options) => {
|
|
12
|
-
const { postMessage } = useCommunicator();
|
|
12
|
+
const { postMessage, senderId } = useCommunicator();
|
|
13
13
|
const { emit, receive } = useMemo(
|
|
14
14
|
() => options ?? { emit: true, receive: true },
|
|
15
15
|
[options]
|
|
@@ -17,12 +17,12 @@ const useCrossFrameState = (key, initialState, options) => {
|
|
|
17
17
|
const handleStateChange = useCallback(
|
|
18
18
|
(state2, prevState) => {
|
|
19
19
|
const resolvedState = resolveState(state2, prevState);
|
|
20
|
-
if (emit && typeof postMessage === "function" && typeof resolvedState !== "undefined") {
|
|
21
|
-
postMessage({ type: `${key}/post`, data: resolvedState });
|
|
20
|
+
if (emit && typeof postMessage === "function" && typeof resolvedState !== "undefined" && JSON.stringify(resolvedState) !== JSON.stringify(prevState)) {
|
|
21
|
+
postMessage({ type: `${key}/post`, data: resolvedState, senderId });
|
|
22
22
|
}
|
|
23
23
|
return resolvedState;
|
|
24
24
|
},
|
|
25
|
-
[
|
|
25
|
+
[key, postMessage, senderId]
|
|
26
26
|
);
|
|
27
27
|
const [state, setState] = useState(() => handleStateChange(initialState));
|
|
28
28
|
const setStateWrapper = useCallback(
|
|
@@ -34,17 +34,23 @@ const useCrossFrameState = (key, initialState, options) => {
|
|
|
34
34
|
// Only activate the state listener if the `receive` option is true
|
|
35
35
|
receive ? setState : void 0
|
|
36
36
|
);
|
|
37
|
+
const onGetMessage = useCallback(
|
|
38
|
+
(_, originSenderId) => {
|
|
39
|
+
if (!emit || typeof postMessage !== "function") return;
|
|
40
|
+
if (originSenderId === senderId) return;
|
|
41
|
+
if (typeof state === "undefined") return;
|
|
42
|
+
postMessage({ type: `${key}/post`, data: state, senderId });
|
|
43
|
+
},
|
|
44
|
+
[emit, key, postMessage, senderId, state]
|
|
45
|
+
);
|
|
37
46
|
useCrossFrameMessageListener(
|
|
38
47
|
`${key}/get`,
|
|
39
48
|
// Only activate the state listener if the `emit` option is true
|
|
40
|
-
emit ?
|
|
41
|
-
if (typeof state === "undefined") return;
|
|
42
|
-
postMessage({ type: `${key}/post`, data: state });
|
|
43
|
-
} : void 0
|
|
49
|
+
emit ? onGetMessage : void 0
|
|
44
50
|
);
|
|
45
51
|
useEffect(() => {
|
|
46
52
|
if (receive && typeof postMessage === "function") {
|
|
47
|
-
postMessage({ type: `${key}/get
|
|
53
|
+
postMessage({ type: `${key}/get`, senderId });
|
|
48
54
|
}
|
|
49
55
|
}, []);
|
|
50
56
|
return useMemo(() => [state, setStateWrapper], [state, setStateWrapper]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/useCrossFrameState.tsx"],"sourcesContent":["'use client';\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type Dispatch,\n type SetStateAction,\n} from 'react';\nimport { useCommunicator } from './CommunicatorContext';\nimport { type MessageKey } from './messageKey';\nimport { useCrossFrameMessageListener } from './useCrossFrameMessageListener';\n\nexport type CrossFrameStateOptions = {\n emit?: boolean;\n receive?: boolean;\n};\n\nconst resolveState = <S,>(state?: SetStateAction<S>, prevState?: S): S =>\n typeof state === 'function'\n ? (state as (prevState?: S) => S)(prevState)\n : (state as S);\n\n/**\n * Configuration options for `useCrossFrameState`.\n * @typedef {Object} CrossFrameStateOptions\n * @property {boolean} [emit=true] - Whether to broadcast state changes to other instances.\n * @property {boolean} [receive=true] - Whether to listen for state updates from other instances.\n */\n\n/**\n * useCrossFrameState\n *\n * This React hook synchronizes state across multiple instances (e.g., different iframes or windows).\n * It uses the `postMessage` API to communicate state changes and updates between instances.\n *\n * @template S - The type of the state.\n * @param {`${MessageKey}`} key - A unique identifier for the state to synchronize.\n * @param {S | (() => S)} [initialState] - The initial state value or a function to compute it lazily.\n * @param {CrossFrameStateOptions} [options] - Configuration options to control emitting and receiving messages.\n * - `emit` (default: true): Whether to broadcast state changes to other instances.\n * - `receive` (default: true): Whether to listen for state updates from other instances.\n *\n * @returns {[S, Dispatch<SetStateAction<S>>]} An array containing the current state and a setter function.\n */\nexport const useCrossFrameState = <S,>(\n key: `${MessageKey}`,\n initialState?: S | (() => S),\n options?: CrossFrameStateOptions\n): [S, Dispatch<SetStateAction<S>>] => {\n const { postMessage } = useCommunicator();\n\n const { emit, receive } = useMemo(\n () => options ?? { emit: true, receive: true },\n [options]\n );\n\n const handleStateChange = useCallback(\n (state?: SetStateAction<S>, prevState?: S) => {\n // Initialize state from the provided initial value, if defined\n const resolvedState: S = resolveState(state, prevState);\n\n // Emit the initial state if `emit` is enabled and initial state is defined\n if (\n emit &&\n typeof postMessage === 'function' &&\n typeof resolvedState !== 'undefined'\n ) {\n postMessage({ type: `${key}/post`, data: resolvedState });\n }\n\n return resolvedState;\n },\n [
|
|
1
|
+
{"version":3,"sources":["../../src/useCrossFrameState.tsx"],"sourcesContent":["'use client';\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n type Dispatch,\n type SetStateAction,\n} from 'react';\nimport { useCommunicator } from './CommunicatorContext';\nimport { type MessageKey } from './messageKey';\nimport { useCrossFrameMessageListener } from './useCrossFrameMessageListener';\n\nexport type CrossFrameStateOptions = {\n emit?: boolean;\n receive?: boolean;\n};\n\nconst resolveState = <S,>(state?: SetStateAction<S>, prevState?: S): S =>\n typeof state === 'function'\n ? (state as (prevState?: S) => S)(prevState)\n : (state as S);\n\n/**\n * Configuration options for `useCrossFrameState`.\n * @typedef {Object} CrossFrameStateOptions\n * @property {boolean} [emit=true] - Whether to broadcast state changes to other instances.\n * @property {boolean} [receive=true] - Whether to listen for state updates from other instances.\n */\n\n/**\n * useCrossFrameState\n *\n * This React hook synchronizes state across multiple instances (e.g., different iframes or windows).\n * It uses the `postMessage` API to communicate state changes and updates between instances.\n *\n * @template S - The type of the state.\n * @param {`${MessageKey}`} key - A unique identifier for the state to synchronize.\n * @param {S | (() => S)} [initialState] - The initial state value or a function to compute it lazily.\n * @param {CrossFrameStateOptions} [options] - Configuration options to control emitting and receiving messages.\n * - `emit` (default: true): Whether to broadcast state changes to other instances.\n * - `receive` (default: true): Whether to listen for state updates from other instances.\n *\n * @returns {[S, Dispatch<SetStateAction<S>>]} An array containing the current state and a setter function.\n */\nexport const useCrossFrameState = <S,>(\n key: `${MessageKey}`,\n initialState?: S | (() => S),\n options?: CrossFrameStateOptions\n): [S, Dispatch<SetStateAction<S>>] => {\n const { postMessage, senderId } = useCommunicator();\n\n const { emit, receive } = useMemo(\n () => options ?? { emit: true, receive: true },\n [options]\n );\n\n const handleStateChange = useCallback(\n (state?: SetStateAction<S>, prevState?: S) => {\n // Initialize state from the provided initial value, if defined\n const resolvedState: S = resolveState(state, prevState);\n\n // Emit the initial state if `emit` is enabled and initial state is defined\n if (\n emit &&\n typeof postMessage === 'function' &&\n typeof resolvedState !== 'undefined' &&\n JSON.stringify(resolvedState) !== JSON.stringify(prevState)\n ) {\n postMessage({ type: `${key}/post`, data: resolvedState, senderId });\n }\n\n return resolvedState;\n },\n [key, postMessage, senderId]\n );\n\n const [state, setState] = useState<S>(() => handleStateChange(initialState));\n\n /**\n * A wrapper function around the `setState` function to handle messaging efficiently.\n *\n * This approach has several advantages over using an additional `useEffect`:\n * - **Avoid Redundant Re-renders:** By emitting the message directly within the `setState` logic,\n * it prevents the extra render cycle that would be triggered when using `useEffect`.\n * - **Consistency:** Ensures the message is emitted immediately when the state is updated,\n * avoiding potential delays caused by the asynchronous nature of `useEffect`.\n *\n * This function keeps the same API as `setState` and is memoized using `useCallback`\n * to prevent unnecessary re-renders of dependent components.\n *\n * @template S - The type of the state.\n * @param {SetStateAction<S>} valueOrUpdater - The new state or a function to produce it.\n * @returns {void}\n */\n const setStateWrapper: Dispatch<SetStateAction<S>> = useCallback(\n (valueOrUpdater) =>\n setState((prevState) => handleStateChange(valueOrUpdater, prevState)),\n [handleStateChange]\n );\n\n /**\n * Listen for messages with the specified key and update the state accordingly.\n */\n useCrossFrameMessageListener<S>(\n `${key}/post`,\n // Only activate the state listener if the `receive` option is true\n receive ? setState : undefined\n );\n\n const onGetMessage = useCallback(\n (_: unknown, originSenderId?: string) => {\n if (!emit || typeof postMessage !== 'function') return;\n if (originSenderId === senderId) return;\n if (typeof state === 'undefined') return;\n\n postMessage({ type: `${key}/post`, data: state, senderId });\n },\n [emit, key, postMessage, senderId, state]\n );\n\n /**\n * Listen for messages request to get the state content and send it back.\n */\n useCrossFrameMessageListener<S>(\n `${key}/get`,\n // Only activate the state listener if the `emit` option is true\n emit ? onGetMessage : undefined\n );\n\n useEffect(() => {\n // If the component is mounted and the hook in receive mode,\n // Request the state from the other instance\n if (receive && typeof postMessage === 'function') {\n postMessage({ type: `${key}/get`, senderId });\n }\n }, []);\n\n // Return the useState state and setter\n return useMemo(() => [state, setStateWrapper], [state, setStateWrapper]);\n};\n"],"mappings":";AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,uBAAuB;AAEhC,SAAS,oCAAoC;AAO7C,MAAM,eAAe,CAAK,OAA2B,cACnD,OAAO,UAAU,aACZ,MAA+B,SAAS,IACxC;AAwBA,MAAM,qBAAqB,CAChC,KACA,cACA,YACqC;AACrC,QAAM,EAAE,aAAa,SAAS,IAAI,gBAAgB;AAElD,QAAM,EAAE,MAAM,QAAQ,IAAI;AAAA,IACxB,MAAM,WAAW,EAAE,MAAM,MAAM,SAAS,KAAK;AAAA,IAC7C,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,oBAAoB;AAAA,IACxB,CAACA,QAA2B,cAAkB;AAE5C,YAAM,gBAAmB,aAAaA,QAAO,SAAS;AAGtD,UACE,QACA,OAAO,gBAAgB,cACvB,OAAO,kBAAkB,eACzB,KAAK,UAAU,aAAa,MAAM,KAAK,UAAU,SAAS,GAC1D;AACA,oBAAY,EAAE,MAAM,GAAG,GAAG,SAAS,MAAM,eAAe,SAAS,CAAC;AAAA,MACpE;AAEA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,KAAK,aAAa,QAAQ;AAAA,EAC7B;AAEA,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAY,MAAM,kBAAkB,YAAY,CAAC;AAkB3E,QAAM,kBAA+C;AAAA,IACnD,CAAC,mBACC,SAAS,CAAC,cAAc,kBAAkB,gBAAgB,SAAS,CAAC;AAAA,IACtE,CAAC,iBAAiB;AAAA,EACpB;AAKA;AAAA,IACE,GAAG,GAAG;AAAA;AAAA,IAEN,UAAU,WAAW;AAAA,EACvB;AAEA,QAAM,eAAe;AAAA,IACnB,CAAC,GAAY,mBAA4B;AACvC,UAAI,CAAC,QAAQ,OAAO,gBAAgB,WAAY;AAChD,UAAI,mBAAmB,SAAU;AACjC,UAAI,OAAO,UAAU,YAAa;AAElC,kBAAY,EAAE,MAAM,GAAG,GAAG,SAAS,MAAM,OAAO,SAAS,CAAC;AAAA,IAC5D;AAAA,IACA,CAAC,MAAM,KAAK,aAAa,UAAU,KAAK;AAAA,EAC1C;AAKA;AAAA,IACE,GAAG,GAAG;AAAA;AAAA,IAEN,OAAO,eAAe;AAAA,EACxB;AAEA,YAAU,MAAM;AAGd,QAAI,WAAW,OAAO,gBAAgB,YAAY;AAChD,kBAAY,EAAE,MAAM,GAAG,GAAG,QAAQ,SAAS,CAAC;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,SAAO,QAAQ,MAAM,CAAC,OAAO,eAAe,GAAG,CAAC,OAAO,eAAe,CAAC;AACzE;","names":["state"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/useCrossURLPathState.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/useCrossURLPathState.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect } from 'react';\nimport {\n useCrossFrameState,\n type CrossFrameStateOptions,\n} from './useCrossFrameState';\n\nexport const useCrossURLPathState = (\n initialState?: string,\n options?: CrossFrameStateOptions\n) => {\n const states = useCrossFrameState<string>(\n 'INTLAYER_URL_CHANGE',\n initialState,\n options\n );\n const [_state, setState] = states;\n\n useEffect(() => {\n /**\n * 1) Monkey patch history methods (pushState, replaceState)\n * to dispatch a custom event whenever they are called.\n */\n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n\n const injectLocationChangeEvent = (method: (...args: any[]) => void) =>\n function (this: typeof history, ...args: [any, string, string?]) {\n method.apply(this, args);\n window.dispatchEvent(new Event('locationchange'));\n };\n\n history.pushState = injectLocationChangeEvent(originalPushState);\n history.replaceState = injectLocationChangeEvent(originalReplaceState);\n\n /**\n * 2) The callback to update our state whenever the URL changes.\n */\n const updateURLState = () => {\n setState(window.location.pathname);\n };\n\n /**\n * 3) Attach event listeners for locationchange, popstate, hashchange.\n * - 'locationchange' is our custom event triggered by push/replaceState overrides.\n * - 'popstate' is fired on back/forward navigation.\n * - 'hashchange' is for URL hash (#) changes.\n * - 'load' is when new page is loaded\n */\n window.addEventListener('locationchange', updateURLState);\n window.addEventListener('popstate', updateURLState);\n window.addEventListener('hashchange', updateURLState);\n window.addEventListener('load', updateURLState);\n\n // Initialize our state immediately on mount\n updateURLState();\n\n /**\n * 4) Cleanup when the component unmounts:\n * - Remove event listeners.\n * - Restore original pushState & replaceState to avoid side effects.\n */\n return () => {\n window.removeEventListener('locationchange', updateURLState);\n window.removeEventListener('popstate', updateURLState);\n window.removeEventListener('hashchange', updateURLState);\n window.removeEventListener('load', updateURLState);\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n };\n }, [setState]);\n\n return states;\n};\n"],"mappings":";AAEA,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,OAEK;AAEA,MAAM,uBAAuB,CAClC,cACA,YACG;AACH,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,CAAC,QAAQ,QAAQ,IAAI;AAE3B,YAAU,MAAM;AAKd,UAAM,oBAAoB,QAAQ;AAClC,UAAM,uBAAuB,QAAQ;AAErC,UAAM,4BAA4B,CAAC,WACjC,YAAmC,MAA8B;AAC/D,aAAO,MAAM,MAAM,IAAI;AACvB,aAAO,cAAc,IAAI,MAAM,gBAAgB,CAAC;AAAA,IAClD;AAEF,YAAQ,YAAY,0BAA0B,iBAAiB;AAC/D,YAAQ,eAAe,0BAA0B,oBAAoB;AAKrE,UAAM,iBAAiB,MAAM;AAC3B,eAAS,OAAO,SAAS,QAAQ;AAAA,IACnC;AASA,WAAO,iBAAiB,kBAAkB,cAAc;AACxD,WAAO,iBAAiB,YAAY,cAAc;AAClD,WAAO,iBAAiB,cAAc,cAAc;AACpD,WAAO,iBAAiB,QAAQ,cAAc;AAG9C,mBAAe;AAOf,WAAO,MAAM;AACX,aAAO,oBAAoB,kBAAkB,cAAc;AAC3D,aAAO,oBAAoB,YAAY,cAAc;AACrD,aAAO,oBAAoB,cAAc,cAAc;AACvD,aAAO,oBAAoB,QAAQ,cAAc;AACjD,cAAQ,YAAY;AACpB,cAAQ,eAAe;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,SAAO;AACT;","names":[]}
|
|
@@ -2,7 +2,9 @@ import { type FC, type PropsWithChildren } from 'react';
|
|
|
2
2
|
export type UseCrossPlatformStateProps = {
|
|
3
3
|
postMessage: typeof window.postMessage;
|
|
4
4
|
allowedOrigins?: string[];
|
|
5
|
+
senderId: string;
|
|
5
6
|
};
|
|
6
|
-
export
|
|
7
|
+
export type CommunicatorProviderProps = PropsWithChildren<Omit<UseCrossPlatformStateProps, 'senderId'>>;
|
|
8
|
+
export declare const CommunicatorProvider: FC<CommunicatorProviderProps>;
|
|
7
9
|
export declare const useCommunicator: () => UseCrossPlatformStateProps;
|
|
8
10
|
//# sourceMappingURL=CommunicatorContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommunicatorContext.d.ts","sourceRoot":"","sources":["../../src/CommunicatorContext.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CommunicatorContext.d.ts","sourceRoot":"","sources":["../../src/CommunicatorContext.tsx"],"names":[],"mappings":"AAGA,OAAO,EAKL,KAAK,EAAE,EACP,KAAK,iBAAiB,EACvB,MAAM,OAAO,CAAC;AAGf,MAAM,MAAM,0BAA0B,GAAG;IACvC,WAAW,EAAE,OAAO,MAAM,CAAC,WAAW,CAAC;IACvC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAUF,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,CACvD,IAAI,CAAC,0BAA0B,EAAE,UAAU,CAAC,CAC7C,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAc9D,CAAC;AAEF,eAAO,MAAM,eAAe,kCAAwC,CAAC"}
|