Skip to content

Commit

Permalink
feat(lib): add validateContent (renamed from parseContent)
Browse files Browse the repository at this point in the history
  • Loading branch information
eunjae-lee committed Oct 9, 2023
1 parent 46ef2e9 commit ca4b24f
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 44 deletions.
24 changes: 11 additions & 13 deletions packages/field-plugin/src/createFieldPlugin/createFieldPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,17 @@ import { createPluginActions } from './createPluginActions'
import { createHeightChangeListener } from './createHeightChangeListener'
import { disableDefaultStoryblokStyles } from './disableDefaultStoryblokStyles'
import { pluginUrlParamsFromUrl } from '../messaging'
import { FieldPluginResponse } from './FieldPluginResponse'
import { createPluginMessageListener } from './createPluginActions/createPluginMessageListener'
import { sandboxUrl } from './sandboxUrl'
import { isCloneable } from '../utils/isCloneable'

export type CreateFieldPluginOptions<Content> = {
onUpdateState: (state: FieldPluginResponse<Content>) => void
parseContent: (content: unknown) => Content
}

export type CreateFieldPlugin = <Content = unknown>(
options: CreateFieldPluginOptions<Content>,
) => () => void
import type { CreateFieldPlugin } from './types'

/**
* @returns cleanup function for side effects
*/
export const createFieldPlugin: CreateFieldPlugin = ({
onUpdateState,
parseContent,
validateContent,
}) => {
const isEmbedded = window.parent !== window

Expand Down Expand Up @@ -76,8 +67,13 @@ export const createFieldPlugin: CreateFieldPlugin = ({

const cleanupStyleSideEffects = disableDefaultStoryblokStyles()

// This is basically the `Content` inferred from the `validateContent`.
type InferredContent = ReturnType<
Exclude<typeof validateContent, undefined>
>['content']

const { actions, messageCallbacks, onHeightChange, initialize } =
createPluginActions({
createPluginActions<InferredContent>({
uid,
postToContainer,
onUpdateState: (data) => {
Expand All @@ -87,7 +83,9 @@ export const createFieldPlugin: CreateFieldPlugin = ({
actions,
})
},
parseContent,
validateContent:
validateContent ||
((content) => ({ content: content as InferredContent })),
})

const cleanupHeightChangeListener = createHeightChangeListener(onHeightChange)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ const wait = async (ms: number) => {
})
}

const parseContent = (content: unknown) => content
const validateContent = (content: unknown) => ({
content,
})

describe('createPluginActions', () => {
describe('initial call', () => {
Expand All @@ -41,7 +43,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
expect(postToContainer).not.toHaveBeenCalled()
})
Expand All @@ -53,7 +55,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
const randomString = '3490ruieo4jf984ej89q32jd0i2k3w09k3902'
onLoaded({
Expand Down Expand Up @@ -85,7 +87,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
setModalOpen(false)

Expand All @@ -110,7 +112,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
setModalOpen(false)

Expand Down Expand Up @@ -139,7 +141,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
const content = '409fjk340wo9jkc0954ij0943iu09c43*&(YT-0c43'
setContent(content)
Expand All @@ -157,7 +159,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
const content = '0932ui2foiuerhjv98453jeh09c34jwk-0c43'
setContent(content)
Expand All @@ -178,7 +180,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
requestContext()
expect(postToContainer).toHaveBeenLastCalledWith(
Expand All @@ -197,7 +199,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
// eslint-disable-next-line @typescript-eslint/no-floating-promises
selectAsset()
Expand All @@ -216,7 +218,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
const promise = selectAsset()
const filename = 'hello.jpg'
Expand All @@ -240,7 +242,7 @@ describe('createPluginActions', () => {
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
})
const promise = selectAsset()
const filename = 'hello.jpg'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ export type CreatePluginActions = <Content>(options: {
uid: string
postToContainer: (message: unknown) => void
onUpdateState: (state: FieldPluginData<Content>) => void
parseContent: (content: unknown) => Content
validateContent: (content: unknown) => {
content: Content
error?: string
}
}) => {
// These functions are to be called by the field plugin when the user performs actions in the UI
actions: FieldPluginActions<Content>
Expand All @@ -39,17 +42,17 @@ export const createPluginActions: CreatePluginActions = ({
uid,
postToContainer,
onUpdateState,
parseContent,
validateContent,
}) => {
const { pushCallback, popCallback } = callbackQueue()

const onStateChange: OnStateChangeMessage = (data) => {
popCallback('stateChanged', data.callbackId)?.(data)
onUpdateState(pluginStateFromStateChangeMessage(data, parseContent))
onUpdateState(pluginStateFromStateChangeMessage(data, validateContent))
}
const onLoaded: OnLoadedMessage = (data) => {
popCallback('loaded', data.callbackId)?.(data)
onUpdateState(pluginStateFromStateChangeMessage(data, parseContent))
onUpdateState(pluginStateFromStateChangeMessage(data, validateContent))
}
const onContextRequest: OnContextRequestMessage = (data) => {
popCallback('context', data.callbackId)?.(data)
Expand Down Expand Up @@ -86,7 +89,9 @@ export const createPluginActions: CreatePluginActions = ({
setContent: (content) => {
return new Promise((resolve) => {
const callbackId = pushCallback('stateChanged', (message) =>
resolve(pluginStateFromStateChangeMessage(message, parseContent)),
resolve(
pluginStateFromStateChangeMessage(message, validateContent),
),
)
postToContainer(
valueChangeMessage({ uid, callbackId, model: content }),
Expand All @@ -96,7 +101,9 @@ export const createPluginActions: CreatePluginActions = ({
setModalOpen: (isModalOpen) => {
return new Promise((resolve) => {
const callbackId = pushCallback('stateChanged', (message) =>
resolve(pluginStateFromStateChangeMessage(message, parseContent)),
resolve(
pluginStateFromStateChangeMessage(message, validateContent),
),
)
postToContainer(
modalChangeMessage({ uid, callbackId, status: isModalOpen }),
Expand Down Expand Up @@ -125,7 +132,7 @@ export const createPluginActions: CreatePluginActions = ({
initialize: () => {
return new Promise((resolve) => {
const callbackId = pushCallback('loaded', (message) =>
resolve(pluginStateFromStateChangeMessage(message, parseContent)),
resolve(pluginStateFromStateChangeMessage(message, validateContent)),
)
// Request the initial state from the Visual Editor.
postToContainer(pluginLoadedMessage({ uid, callbackId }))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,28 @@ import {

export const pluginStateFromStateChangeMessage = <Content>(
message: LoadedMessage | StateChangedMessage,
parseContent: (content: unknown) => Content,
): FieldPluginData<Content> => ({
spaceId: message.spaceId ?? undefined,
story: message.story ?? undefined,
storyId: message.storyId ?? undefined,
storyLang: message.language === '' ? 'default' : message.language,
blockUid: message.blockId ?? undefined,
token: message.token ?? undefined,
options: recordFromFieldPluginOptions(message.schema.options),
uid: message.uid ?? undefined,
content: parseContent(message.model),
isModalOpen: message.isModalOpen,
})
validateContent: (content: unknown) => {
content: Content
error?: string
},
): FieldPluginData<Content> => {
const validateResult = validateContent(message.model)
if ('error' in validateResult) {
console.warn(
`[Warning] The provided content is not valid, but it's still sent to the Visual Editor.`,
)
}

return {
spaceId: message.spaceId ?? undefined,
story: message.story ?? undefined,
storyId: message.storyId ?? undefined,
storyLang: message.language === '' ? 'default' : message.language,
blockUid: message.blockId ?? undefined,
token: message.token ?? undefined,
options: recordFromFieldPluginOptions(message.schema.options),
uid: message.uid ?? undefined,
content: validateResult.content,
isModalOpen: message.isModalOpen,
}
}
13 changes: 13 additions & 0 deletions packages/field-plugin/src/createFieldPlugin/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { FieldPluginResponse } from './FieldPluginResponse'

export type CreateFieldPluginOptions<Content> = {
onUpdateState: (state: FieldPluginResponse<Content>) => void
validateContent?: (content: unknown) => {
content: Content
error?: string
}
}

export type CreateFieldPlugin = <Content = unknown>(
options: CreateFieldPluginOptions<Content>,
) => () => void

0 comments on commit ca4b24f

Please sign in to comment.