diff --git a/src/__tests__/live-editing.test.ts b/src/__tests__/live-editing.test.ts new file mode 100644 index 00000000..c29bcf6f --- /dev/null +++ b/src/__tests__/live-editing.test.ts @@ -0,0 +1,10 @@ +import { describe, expect, it } from 'vitest'; +import StoryblokLiveEditing from '../rsc/live-editing'; +import type { ISbStoryData } from '@storyblok/js'; + +describe('storyblokLiveEditing', () => { + it('should return null when not in visual editor', () => { + const component = StoryblokLiveEditing({ story: { uuid: '123' } as ISbStoryData, bridgeOptions: {} }); + expect(component).toBeNull(); + }); +}); diff --git a/src/common/client.ts b/src/common/client.ts index cdff6f96..c3ab56c5 100644 --- a/src/common/client.ts +++ b/src/common/client.ts @@ -10,7 +10,7 @@ export const useStoryblokState: TUseStoryblokState = ( ) => { const [story, setStory] = useState(initialStory); - const storyId = (initialStory as any)?.internalId ?? initialStory?.id ?? 0; + const storyId = initialStory?.id ?? 0; const isBridgeEnabled = typeof window !== 'undefined' && typeof window.storyblokRegisterEvent !== 'undefined'; diff --git a/src/rsc/common.ts b/src/rsc/common.ts index 1cd3b1a5..d8ff5c71 100644 --- a/src/rsc/common.ts +++ b/src/rsc/common.ts @@ -11,7 +11,12 @@ const componentsMap: Map = new Map(); +declare global { + // eslint-disable-next-line no-var, vars-on-top + var storyCache: Map; +} + +globalThis.storyCache = !globalThis.storyCache ? new Map() : globalThis.storyCache; export const useStoryblokApi = (): StoryblokClient => { if (!storyblokApiInstance) { diff --git a/src/rsc/live-edit-update-action.ts b/src/rsc/live-edit-update-action.ts index 8e988219..23233a93 100644 --- a/src/rsc/live-edit-update-action.ts +++ b/src/rsc/live-edit-update-action.ts @@ -1,6 +1,8 @@ 'use server'; -export async function liveEditUpdateAction({ story, pathToRevalidate }) { +import type { ISbStoryData } from '@storyblok/js'; + +export async function liveEditUpdateAction({ story, pathToRevalidate }: { story: ISbStoryData; pathToRevalidate: string }) { if (!story || !pathToRevalidate) { return console.error('liveEditUpdateAction: story or pathToRevalidate is not provided'); } diff --git a/src/rsc/live-editing.tsx b/src/rsc/live-editing.tsx index 3c5672eb..1b48b5f6 100644 --- a/src/rsc/live-editing.tsx +++ b/src/rsc/live-editing.tsx @@ -1,15 +1,22 @@ 'use client'; -import { registerStoryblokBridge } from '@storyblok/js'; +import { type ISbStoryData, registerStoryblokBridge, type StoryblokBridgeConfigV2 } from '@storyblok/js'; import { startTransition, useEffect } from 'react'; import { liveEditUpdateAction } from './live-edit-update-action'; -const StoryblokLiveEditing = ({ story = null, bridgeOptions = {} }) => { +const isVisualEditor = (): boolean => { if (typeof window === 'undefined') { + return false; + } + return typeof window.storyblokRegisterEvent !== 'undefined' && window.location.search.includes('_storyblok'); +}; + +const StoryblokLiveEditing = ({ story = null, bridgeOptions = {} }: { story: ISbStoryData; bridgeOptions: StoryblokBridgeConfigV2 }) => { + if (!isVisualEditor()) { return null; } - const handleInput = (story) => { + const handleInput = (story: ISbStoryData) => { if (!story) { return; } @@ -18,7 +25,7 @@ const StoryblokLiveEditing = ({ story = null, bridgeOptions = {} }) => { }); }; - const storyId = story?.internalId ?? story?.id ?? 0; + const storyId = story?.id ?? 0; useEffect(() => { registerStoryblokBridge(storyId, newStory => handleInput(newStory), bridgeOptions); }, []); diff --git a/src/rsc/story.tsx b/src/rsc/story.tsx index 6a9fffff..1edbcc0d 100644 --- a/src/rsc/story.tsx +++ b/src/rsc/story.tsx @@ -19,6 +19,8 @@ const StoryblokStory = forwardRef( if (globalThis.storyCache.has(story.uuid)) { story = globalThis.storyCache.get(story.uuid); + // Delete the story from the cache to avoid draft content leaking + globalThis.storyCache.delete(story.uuid); } if (typeof story.content === 'string') {