@wordpress/core-data 7.41.2-next.v.202603161435.0 → 7.42.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/CHANGELOG.md +1 -1
- package/build/awareness/post-editor-awareness.cjs +12 -5
- package/build/awareness/post-editor-awareness.cjs.map +2 -2
- package/build/entities.cjs +30 -5
- package/build/entities.cjs.map +2 -2
- package/build/hooks/use-post-editor-awareness-state.cjs +1 -1
- package/build/hooks/use-post-editor-awareness-state.cjs.map +2 -2
- package/build/queried-data/get-query-parts.cjs +7 -0
- package/build/queried-data/get-query-parts.cjs.map +2 -2
- package/build/queried-data/selectors.cjs +14 -3
- package/build/queried-data/selectors.cjs.map +2 -2
- package/build/reducer.cjs +6 -0
- package/build/reducer.cjs.map +2 -2
- package/build/sync.cjs +3 -0
- package/build/sync.cjs.map +2 -2
- package/build/types.cjs.map +2 -2
- package/build/utils/block-selection-history.cjs +1 -1
- package/build/utils/block-selection-history.cjs.map +2 -2
- package/build/utils/crdt-blocks.cjs +17 -3
- package/build/utils/crdt-blocks.cjs.map +2 -2
- package/build/utils/crdt-selection.cjs +4 -1
- package/build/utils/crdt-selection.cjs.map +2 -2
- package/build/utils/crdt-user-selections.cjs +1 -1
- package/build/utils/crdt-user-selections.cjs.map +2 -2
- package/build/utils/crdt-utils.cjs +54 -2
- package/build/utils/crdt-utils.cjs.map +2 -2
- package/build/utils/crdt.cjs +4 -23
- package/build/utils/crdt.cjs.map +2 -2
- package/build-module/awareness/post-editor-awareness.mjs +12 -5
- package/build-module/awareness/post-editor-awareness.mjs.map +2 -2
- package/build-module/entities.mjs +30 -5
- package/build-module/entities.mjs.map +2 -2
- package/build-module/hooks/use-post-editor-awareness-state.mjs +1 -1
- package/build-module/hooks/use-post-editor-awareness-state.mjs.map +2 -2
- package/build-module/queried-data/get-query-parts.mjs +7 -0
- package/build-module/queried-data/get-query-parts.mjs.map +2 -2
- package/build-module/queried-data/selectors.mjs +14 -3
- package/build-module/queried-data/selectors.mjs.map +2 -2
- package/build-module/reducer.mjs +6 -0
- package/build-module/reducer.mjs.map +2 -2
- package/build-module/sync.mjs +2 -0
- package/build-module/sync.mjs.map +2 -2
- package/build-module/types.mjs.map +2 -2
- package/build-module/utils/block-selection-history.mjs +5 -2
- package/build-module/utils/block-selection-history.mjs.map +2 -2
- package/build-module/utils/crdt-blocks.mjs +17 -3
- package/build-module/utils/crdt-blocks.mjs.map +2 -2
- package/build-module/utils/crdt-selection.mjs +8 -2
- package/build-module/utils/crdt-selection.mjs.map +2 -2
- package/build-module/utils/crdt-user-selections.mjs +2 -2
- package/build-module/utils/crdt-user-selections.mjs.map +2 -2
- package/build-module/utils/crdt-utils.mjs +51 -1
- package/build-module/utils/crdt-utils.mjs.map +2 -2
- package/build-module/utils/crdt.mjs +4 -23
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-types/awareness/post-editor-awareness.d.ts +2 -2
- package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/queried-data/get-query-parts.d.ts +7 -0
- package/build-types/queried-data/get-query-parts.d.ts.map +1 -1
- package/build-types/queried-data/selectors.d.ts.map +1 -1
- package/build-types/reducer.d.ts.map +1 -1
- package/build-types/sync.d.ts +2 -2
- package/build-types/sync.d.ts.map +1 -1
- package/build-types/types.d.ts +4 -2
- package/build-types/types.d.ts.map +1 -1
- package/build-types/utils/block-selection-history.d.ts.map +1 -1
- package/build-types/utils/crdt-blocks.d.ts.map +1 -1
- package/build-types/utils/crdt-selection.d.ts.map +1 -1
- package/build-types/utils/crdt-user-selections.d.ts +1 -2
- package/build-types/utils/crdt-user-selections.d.ts.map +1 -1
- package/build-types/utils/crdt-utils.d.ts +20 -0
- package/build-types/utils/crdt-utils.d.ts.map +1 -1
- package/build-types/utils/crdt.d.ts +6 -7
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/build-types/utils/test/crdt-utils.d.ts +2 -0
- package/build-types/utils/test/crdt-utils.d.ts.map +1 -0
- package/package.json +18 -18
- package/src/awareness/post-editor-awareness.ts +13 -6
- package/src/awareness/test/post-editor-awareness.ts +15 -10
- package/src/entities.js +36 -5
- package/src/hooks/test/use-post-editor-awareness-state.ts +3 -3
- package/src/hooks/use-post-editor-awareness-state.ts +1 -1
- package/src/queried-data/get-query-parts.js +13 -0
- package/src/queried-data/selectors.js +22 -4
- package/src/queried-data/test/get-query-parts.js +34 -0
- package/src/queried-data/test/selectors.js +158 -0
- package/src/reducer.js +11 -0
- package/src/sync.ts +2 -0
- package/src/test/entities.js +185 -1
- package/src/types.ts +8 -2
- package/src/utils/block-selection-history.ts +5 -2
- package/src/utils/crdt-blocks.ts +32 -3
- package/src/utils/crdt-selection.ts +8 -2
- package/src/utils/crdt-user-selections.ts +13 -13
- package/src/utils/crdt-utils.ts +99 -0
- package/src/utils/crdt.ts +8 -30
- package/src/utils/test/crdt-blocks.ts +146 -0
- package/src/utils/test/crdt-user-selections.ts +5 -0
- package/src/utils/test/crdt-utils.ts +387 -0
- package/src/utils/test/crdt.ts +120 -53
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/hooks/use-post-editor-awareness-state.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport { usePrevious } from '@wordpress/compose';\nimport { useEffect, useState } from '@wordpress/element';\nimport type { Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport { getSyncManager } from '../sync';\nimport type {\n\tPostEditorAwarenessState as ActiveCollaborator,\n\tPostSaveEvent,\n\tYDocDebugData,\n} from '../awareness/types';\nimport type { SelectionState, ResolvedSelection } from '../types';\nimport type { PostEditorAwareness } from '../awareness/post-editor-awareness';\n\ninterface AwarenessState {\n\tactiveCollaborators: ActiveCollaborator[];\n\tresolveSelection: ( selection: SelectionState ) => ResolvedSelection;\n\tgetDebugData: () => YDocDebugData;\n\tisCurrentCollaboratorDisconnected: boolean;\n}\n\nconst defaultResolvedSelection: ResolvedSelection = {\n\ttextIndex: null,\n\tlocalClientId: null,\n};\n\nconst defaultState: AwarenessState = {\n\tactiveCollaborators: [],\n\tresolveSelection: () => defaultResolvedSelection,\n\tgetDebugData: () => ( {\n\t\tdoc: {},\n\t\tclients: {},\n\t\tcollaboratorMap: {},\n\t} ),\n\tisCurrentCollaboratorDisconnected: false,\n};\n\nfunction getAwarenessState(\n\tawareness: PostEditorAwareness,\n\tnewState?: ActiveCollaborator[]\n): AwarenessState {\n\tconst activeCollaborators = newState ?? awareness.getCurrentState();\n\n\treturn {\n\t\tactiveCollaborators,\n\t\tresolveSelection: ( selection: SelectionState ) =>\n\t\t\tawareness.convertSelectionStateToAbsolute( selection ),\n\t\tgetDebugData: () => awareness.getDebugData(),\n\t\tisCurrentCollaboratorDisconnected:\n\t\t\tactiveCollaborators.find( ( collaborator ) => collaborator.isMe )\n\t\t\t\t?.isConnected === false,\n\t};\n}\n\nfunction usePostEditorAwarenessState(\n\tpostId: number | null,\n\tpostType: string | null\n): AwarenessState {\n\tconst [ state, setState ] = useState< AwarenessState >( defaultState );\n\n\tuseEffect( () => {\n\t\tif ( null === postId || null === postType ) {\n\t\t\tsetState( defaultState );\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectType = `postType/${ postType }`;\n\t\tconst objectId = postId.toString();\n\t\tconst awareness = getSyncManager()?.getAwareness< PostEditorAwareness >(\n\t\t\tobjectType,\n\t\t\tobjectId\n\t\t);\n\n\t\tif ( ! awareness ) {\n\t\t\tsetState( defaultState );\n\t\t\treturn;\n\t\t}\n\n\t\tawareness.setUp();\n\n\t\t// Initialize with current awareness state.\n\t\tsetState( getAwarenessState( awareness ) );\n\n\t\tconst unsubscribe = awareness?.onStateChange(\n\t\t\t( newState: ActiveCollaborator[] ) => {\n\t\t\t\tsetState( getAwarenessState( awareness, newState ) );\n\t\t\t}\n\t\t);\n\n\t\treturn unsubscribe;\n\t}, [ postId, postType ] );\n\n\treturn state;\n}\n\n/**\n * Hook to get the active collaborators for a post editor.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return {ActiveCollaborator[]} The active collaborators.\n */\nexport function useActiveCollaborators(\n\tpostId: number | null,\n\tpostType: string | null\n): ActiveCollaborator[] {\n\treturn usePostEditorAwarenessState( postId, postType ).activeCollaborators;\n}\n\n/**\n * Hook to resolve a selection state to a text index and block client ID.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return A function that resolves a selection to its text index and block client ID.\n */\nexport function useResolvedSelection(\n\tpostId: number | null,\n\tpostType: string | null\n): ( selection: SelectionState ) => ResolvedSelection {\n\treturn usePostEditorAwarenessState( postId, postType ).resolveSelection;\n}\n\n/**\n * Hook to get data for debugging, using the awareness state.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return {YDocDebugData} The debug data.\n */\nexport function useGetDebugData(\n\tpostId: number | null,\n\tpostType: string | null\n): YDocDebugData {\n\treturn usePostEditorAwarenessState( postId, postType ).getDebugData();\n}\n\n/**\n * Hook to check if the current collaborator is disconnected.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return {boolean} Whether the current collaborator is disconnected.\n */\nexport function useIsDisconnected(\n\tpostId: number | null,\n\tpostType: string | null\n): boolean {\n\treturn usePostEditorAwarenessState( postId, postType )\n\t\t.isCurrentCollaboratorDisconnected;\n}\n\n/**\n * Hook that subscribes to the CRDT state map and returns the most recent\n * save event (timestamp + client ID). The state map is updated by\n * `markEntityAsSaved` in `@wordpress/sync`\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n */\nfunction useLastPostSave(\n\tpostId: number | null,\n\tpostType: string | null\n): PostSaveEvent | null {\n\tconst [ lastSave, setLastSave ] = useState< PostSaveEvent | null >( null );\n\n\tuseEffect( () => {\n\t\tif ( null === postId || null === postType ) {\n\t\t\tsetLastSave( null );\n\t\t\treturn;\n\t\t}\n\n\t\tconst awareness = getSyncManager()?.getAwareness< PostEditorAwareness >(\n\t\t\t`postType/${ postType }`,\n\t\t\tpostId.toString()\n\t\t);\n\n\t\tif ( ! awareness ) {\n\t\t\tsetLastSave( null );\n\t\t\treturn;\n\t\t}\n\n\t\tawareness.setUp();\n\n\t\tconst stateMap = awareness.doc.getMap( 'state' );\n\t\tconst recordMap = awareness.doc.getMap( 'document' );\n\n\t\t// Only notify for saves that occur after the observer is\n\t\t// set up. This prevents false notifications when the Y.Doc\n\t\t// syncs historical state on page load or peer reconnect.\n\t\tconst setupTime = Date.now();\n\n\t\tconst observer = ( event: Y.YMapEvent< unknown > ) => {\n\t\t\tif ( event.keysChanged.has( 'savedAt' ) ) {\n\t\t\t\tconst savedAt = stateMap.get( 'savedAt' ) as number;\n\t\t\t\tconst savedByClientId = stateMap.get( 'savedBy' ) as number;\n\n\t\t\t\tif (\n\t\t\t\t\ttypeof savedAt === 'number' &&\n\t\t\t\t\ttypeof savedByClientId === 'number' &&\n\t\t\t\t\tsavedAt > setupTime\n\t\t\t\t) {\n\t\t\t\t\tconst postStatus = recordMap.get( 'status' ) as\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tsetLastSave( { savedAt, savedByClientId, postStatus } );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tstateMap.observe( observer );\n\n\t\treturn () => {\n\t\t\tstateMap.unobserve( observer );\n\t\t};\n\t}, [ postId, postType ] );\n\n\treturn lastSave;\n}\n\n/**\n * Hook that fires a callback when a new collaborator joins the post.\n * Handles initial hydration and state diffing internally\u2014consumers\n * only receive \"join\" events for collaborators that appear after the\n * initial state has loaded.\n *\n * The callback receives the joining collaborator and, when available,\n * the current user's state (useful for comparing `enteredAt` timestamps).\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n * @param callback Invoked for each collaborator that joins.\n */\nexport function useOnCollaboratorJoin(\n\tpostId: number | null,\n\tpostType: string | null,\n\tcallback: (\n\t\tcollaborator: ActiveCollaborator,\n\t\tme?: ActiveCollaborator\n\t) => void\n): void {\n\tconst { activeCollaborators } = usePostEditorAwarenessState(\n\t\tpostId,\n\t\tpostType\n\t);\n\tconst prevCollaborators = usePrevious( activeCollaborators );\n\n\tuseEffect( () => {\n\t\t/*\n\t\t * On first render usePrevious returns undefined. On subsequent\n\t\t * renders the list may still be empty while the store hydrates.\n\t\t * In both cases, skip to avoid spurious \"joined\" callbacks for\n\t\t * users already present.\n\t\t */\n\t\tif ( ! prevCollaborators || prevCollaborators.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst prevMap = new Map< number, ActiveCollaborator >(\n\t\t\tprevCollaborators.map( ( collaborator ) => [\n\t\t\t\tcollaborator.clientId,\n\t\t\t\tcollaborator,\n\t\t\t] )\n\t\t);\n\t\tconst me = activeCollaborators.find(\n\t\t\t( collaborator ) => collaborator.isMe\n\t\t);\n\n\t\tfor ( const collaborator of activeCollaborators ) {\n\t\t\tif (\n\t\t\t\t! prevMap.has( collaborator.clientId ) &&\n\t\t\t\t! collaborator.isMe\n\t\t\t) {\n\t\t\t\tcallback( collaborator, me );\n\t\t\t}\n\t\t}\n\t}, [ activeCollaborators, prevCollaborators, callback ] );\n}\n\n/**\n * Hook that fires a callback when a collaborator leaves the post.\n * A \"leave\" is detected when a previously-connected collaborator either\n * transitions to `isConnected = false` or disappears from the list\n * entirely while still connected. Already-disconnected collaborators\n * that are later removed from the list are silently ignored.\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n * @param callback Invoked for each collaborator that leaves.\n */\nexport function useOnCollaboratorLeave(\n\tpostId: number | null,\n\tpostType: string | null,\n\tcallback: ( collaborator: ActiveCollaborator ) => void\n): void {\n\tconst { activeCollaborators } = usePostEditorAwarenessState(\n\t\tpostId,\n\t\tpostType\n\t);\n\tconst prevCollaborators = usePrevious( activeCollaborators );\n\n\tuseEffect( () => {\n\t\tif ( ! prevCollaborators || prevCollaborators.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newMap = new Map< number, ActiveCollaborator >(\n\t\t\tactiveCollaborators.map( ( collaborator ) => [\n\t\t\t\tcollaborator.clientId,\n\t\t\t\tcollaborator,\n\t\t\t] )\n\t\t);\n\n\t\tfor ( const prevCollab of prevCollaborators ) {\n\t\t\tif ( prevCollab.isMe || ! prevCollab.isConnected ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newCollab = newMap.get( prevCollab.clientId );\n\t\t\tif ( ! newCollab?.isConnected ) {\n\t\t\t\tcallback( prevCollab );\n\t\t\t}\n\t\t}\n\t}, [ activeCollaborators, prevCollaborators, callback ] );\n}\n\n/**\n * Hook that fires a callback when a remote collaborator saves the post.\n * Only fires for saves by other collaborators (not the current user).\n * Deduplicates by `savedAt` timestamp so the same save event is never\n * reported twice.\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n * @param callback Invoked with the save event, the collaborator who saved,\n * and the previous save event (if any) for transition detection.\n */\nexport function useOnPostSave(\n\tpostId: number | null,\n\tpostType: string | null,\n\tcallback: (\n\t\tevent: PostSaveEvent,\n\t\tsaver: ActiveCollaborator,\n\t\tprevEvent: PostSaveEvent | null\n\t) => void\n): void {\n\tconst { activeCollaborators } = usePostEditorAwarenessState(\n\t\tpostId,\n\t\tpostType\n\t);\n\tconst lastPostSave = useLastPostSave( postId, postType );\n\tconst prevPostSave = usePrevious( lastPostSave );\n\n\tuseEffect( () => {\n\t\tif ( ! lastPostSave ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( prevPostSave && lastPostSave.savedAt === prevPostSave.savedAt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst saver = activeCollaborators.find(\n\t\t\t( collaborator ) =>\n\t\t\t\tcollaborator.clientId === lastPostSave.savedByClientId &&\n\t\t\t\t! collaborator.isMe\n\t\t);\n\n\t\tif ( ! saver ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcallback( lastPostSave, saver, prevPostSave ?? null );\n\t}, [ lastPostSave, prevPostSave, activeCollaborators, callback ] );\n}\n"],
|
|
5
|
-
"mappings": ";AAGA,SAAS,mBAAmB;AAC5B,SAAS,WAAW,gBAAgB;AAMpC,SAAS,sBAAsB;AAgB/B,IAAM,2BAA8C;AAAA,EACnD,
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport { usePrevious } from '@wordpress/compose';\nimport { useEffect, useState } from '@wordpress/element';\nimport type { Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport { getSyncManager } from '../sync';\nimport type {\n\tPostEditorAwarenessState as ActiveCollaborator,\n\tPostSaveEvent,\n\tYDocDebugData,\n} from '../awareness/types';\nimport type { SelectionState, ResolvedSelection } from '../types';\nimport type { PostEditorAwareness } from '../awareness/post-editor-awareness';\n\ninterface AwarenessState {\n\tactiveCollaborators: ActiveCollaborator[];\n\tresolveSelection: ( selection: SelectionState ) => ResolvedSelection;\n\tgetDebugData: () => YDocDebugData;\n\tisCurrentCollaboratorDisconnected: boolean;\n}\n\nconst defaultResolvedSelection: ResolvedSelection = {\n\trichTextOffset: null,\n\tlocalClientId: null,\n};\n\nconst defaultState: AwarenessState = {\n\tactiveCollaborators: [],\n\tresolveSelection: () => defaultResolvedSelection,\n\tgetDebugData: () => ( {\n\t\tdoc: {},\n\t\tclients: {},\n\t\tcollaboratorMap: {},\n\t} ),\n\tisCurrentCollaboratorDisconnected: false,\n};\n\nfunction getAwarenessState(\n\tawareness: PostEditorAwareness,\n\tnewState?: ActiveCollaborator[]\n): AwarenessState {\n\tconst activeCollaborators = newState ?? awareness.getCurrentState();\n\n\treturn {\n\t\tactiveCollaborators,\n\t\tresolveSelection: ( selection: SelectionState ) =>\n\t\t\tawareness.convertSelectionStateToAbsolute( selection ),\n\t\tgetDebugData: () => awareness.getDebugData(),\n\t\tisCurrentCollaboratorDisconnected:\n\t\t\tactiveCollaborators.find( ( collaborator ) => collaborator.isMe )\n\t\t\t\t?.isConnected === false,\n\t};\n}\n\nfunction usePostEditorAwarenessState(\n\tpostId: number | null,\n\tpostType: string | null\n): AwarenessState {\n\tconst [ state, setState ] = useState< AwarenessState >( defaultState );\n\n\tuseEffect( () => {\n\t\tif ( null === postId || null === postType ) {\n\t\t\tsetState( defaultState );\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectType = `postType/${ postType }`;\n\t\tconst objectId = postId.toString();\n\t\tconst awareness = getSyncManager()?.getAwareness< PostEditorAwareness >(\n\t\t\tobjectType,\n\t\t\tobjectId\n\t\t);\n\n\t\tif ( ! awareness ) {\n\t\t\tsetState( defaultState );\n\t\t\treturn;\n\t\t}\n\n\t\tawareness.setUp();\n\n\t\t// Initialize with current awareness state.\n\t\tsetState( getAwarenessState( awareness ) );\n\n\t\tconst unsubscribe = awareness?.onStateChange(\n\t\t\t( newState: ActiveCollaborator[] ) => {\n\t\t\t\tsetState( getAwarenessState( awareness, newState ) );\n\t\t\t}\n\t\t);\n\n\t\treturn unsubscribe;\n\t}, [ postId, postType ] );\n\n\treturn state;\n}\n\n/**\n * Hook to get the active collaborators for a post editor.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return {ActiveCollaborator[]} The active collaborators.\n */\nexport function useActiveCollaborators(\n\tpostId: number | null,\n\tpostType: string | null\n): ActiveCollaborator[] {\n\treturn usePostEditorAwarenessState( postId, postType ).activeCollaborators;\n}\n\n/**\n * Hook to resolve a selection state to a text index and block client ID.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return A function that resolves a selection to its text index and block client ID.\n */\nexport function useResolvedSelection(\n\tpostId: number | null,\n\tpostType: string | null\n): ( selection: SelectionState ) => ResolvedSelection {\n\treturn usePostEditorAwarenessState( postId, postType ).resolveSelection;\n}\n\n/**\n * Hook to get data for debugging, using the awareness state.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return {YDocDebugData} The debug data.\n */\nexport function useGetDebugData(\n\tpostId: number | null,\n\tpostType: string | null\n): YDocDebugData {\n\treturn usePostEditorAwarenessState( postId, postType ).getDebugData();\n}\n\n/**\n * Hook to check if the current collaborator is disconnected.\n *\n * @param postId - The ID of the post.\n * @param postType - The type of the post.\n * @return {boolean} Whether the current collaborator is disconnected.\n */\nexport function useIsDisconnected(\n\tpostId: number | null,\n\tpostType: string | null\n): boolean {\n\treturn usePostEditorAwarenessState( postId, postType )\n\t\t.isCurrentCollaboratorDisconnected;\n}\n\n/**\n * Hook that subscribes to the CRDT state map and returns the most recent\n * save event (timestamp + client ID). The state map is updated by\n * `markEntityAsSaved` in `@wordpress/sync`\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n */\nfunction useLastPostSave(\n\tpostId: number | null,\n\tpostType: string | null\n): PostSaveEvent | null {\n\tconst [ lastSave, setLastSave ] = useState< PostSaveEvent | null >( null );\n\n\tuseEffect( () => {\n\t\tif ( null === postId || null === postType ) {\n\t\t\tsetLastSave( null );\n\t\t\treturn;\n\t\t}\n\n\t\tconst awareness = getSyncManager()?.getAwareness< PostEditorAwareness >(\n\t\t\t`postType/${ postType }`,\n\t\t\tpostId.toString()\n\t\t);\n\n\t\tif ( ! awareness ) {\n\t\t\tsetLastSave( null );\n\t\t\treturn;\n\t\t}\n\n\t\tawareness.setUp();\n\n\t\tconst stateMap = awareness.doc.getMap( 'state' );\n\t\tconst recordMap = awareness.doc.getMap( 'document' );\n\n\t\t// Only notify for saves that occur after the observer is\n\t\t// set up. This prevents false notifications when the Y.Doc\n\t\t// syncs historical state on page load or peer reconnect.\n\t\tconst setupTime = Date.now();\n\n\t\tconst observer = ( event: Y.YMapEvent< unknown > ) => {\n\t\t\tif ( event.keysChanged.has( 'savedAt' ) ) {\n\t\t\t\tconst savedAt = stateMap.get( 'savedAt' ) as number;\n\t\t\t\tconst savedByClientId = stateMap.get( 'savedBy' ) as number;\n\n\t\t\t\tif (\n\t\t\t\t\ttypeof savedAt === 'number' &&\n\t\t\t\t\ttypeof savedByClientId === 'number' &&\n\t\t\t\t\tsavedAt > setupTime\n\t\t\t\t) {\n\t\t\t\t\tconst postStatus = recordMap.get( 'status' ) as\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\tsetLastSave( { savedAt, savedByClientId, postStatus } );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tstateMap.observe( observer );\n\n\t\treturn () => {\n\t\t\tstateMap.unobserve( observer );\n\t\t};\n\t}, [ postId, postType ] );\n\n\treturn lastSave;\n}\n\n/**\n * Hook that fires a callback when a new collaborator joins the post.\n * Handles initial hydration and state diffing internally\u2014consumers\n * only receive \"join\" events for collaborators that appear after the\n * initial state has loaded.\n *\n * The callback receives the joining collaborator and, when available,\n * the current user's state (useful for comparing `enteredAt` timestamps).\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n * @param callback Invoked for each collaborator that joins.\n */\nexport function useOnCollaboratorJoin(\n\tpostId: number | null,\n\tpostType: string | null,\n\tcallback: (\n\t\tcollaborator: ActiveCollaborator,\n\t\tme?: ActiveCollaborator\n\t) => void\n): void {\n\tconst { activeCollaborators } = usePostEditorAwarenessState(\n\t\tpostId,\n\t\tpostType\n\t);\n\tconst prevCollaborators = usePrevious( activeCollaborators );\n\n\tuseEffect( () => {\n\t\t/*\n\t\t * On first render usePrevious returns undefined. On subsequent\n\t\t * renders the list may still be empty while the store hydrates.\n\t\t * In both cases, skip to avoid spurious \"joined\" callbacks for\n\t\t * users already present.\n\t\t */\n\t\tif ( ! prevCollaborators || prevCollaborators.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst prevMap = new Map< number, ActiveCollaborator >(\n\t\t\tprevCollaborators.map( ( collaborator ) => [\n\t\t\t\tcollaborator.clientId,\n\t\t\t\tcollaborator,\n\t\t\t] )\n\t\t);\n\t\tconst me = activeCollaborators.find(\n\t\t\t( collaborator ) => collaborator.isMe\n\t\t);\n\n\t\tfor ( const collaborator of activeCollaborators ) {\n\t\t\tif (\n\t\t\t\t! prevMap.has( collaborator.clientId ) &&\n\t\t\t\t! collaborator.isMe\n\t\t\t) {\n\t\t\t\tcallback( collaborator, me );\n\t\t\t}\n\t\t}\n\t}, [ activeCollaborators, prevCollaborators, callback ] );\n}\n\n/**\n * Hook that fires a callback when a collaborator leaves the post.\n * A \"leave\" is detected when a previously-connected collaborator either\n * transitions to `isConnected = false` or disappears from the list\n * entirely while still connected. Already-disconnected collaborators\n * that are later removed from the list are silently ignored.\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n * @param callback Invoked for each collaborator that leaves.\n */\nexport function useOnCollaboratorLeave(\n\tpostId: number | null,\n\tpostType: string | null,\n\tcallback: ( collaborator: ActiveCollaborator ) => void\n): void {\n\tconst { activeCollaborators } = usePostEditorAwarenessState(\n\t\tpostId,\n\t\tpostType\n\t);\n\tconst prevCollaborators = usePrevious( activeCollaborators );\n\n\tuseEffect( () => {\n\t\tif ( ! prevCollaborators || prevCollaborators.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst newMap = new Map< number, ActiveCollaborator >(\n\t\t\tactiveCollaborators.map( ( collaborator ) => [\n\t\t\t\tcollaborator.clientId,\n\t\t\t\tcollaborator,\n\t\t\t] )\n\t\t);\n\n\t\tfor ( const prevCollab of prevCollaborators ) {\n\t\t\tif ( prevCollab.isMe || ! prevCollab.isConnected ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newCollab = newMap.get( prevCollab.clientId );\n\t\t\tif ( ! newCollab?.isConnected ) {\n\t\t\t\tcallback( prevCollab );\n\t\t\t}\n\t\t}\n\t}, [ activeCollaborators, prevCollaborators, callback ] );\n}\n\n/**\n * Hook that fires a callback when a remote collaborator saves the post.\n * Only fires for saves by other collaborators (not the current user).\n * Deduplicates by `savedAt` timestamp so the same save event is never\n * reported twice.\n *\n * @param postId The ID of the post.\n * @param postType The type of the post.\n * @param callback Invoked with the save event, the collaborator who saved,\n * and the previous save event (if any) for transition detection.\n */\nexport function useOnPostSave(\n\tpostId: number | null,\n\tpostType: string | null,\n\tcallback: (\n\t\tevent: PostSaveEvent,\n\t\tsaver: ActiveCollaborator,\n\t\tprevEvent: PostSaveEvent | null\n\t) => void\n): void {\n\tconst { activeCollaborators } = usePostEditorAwarenessState(\n\t\tpostId,\n\t\tpostType\n\t);\n\tconst lastPostSave = useLastPostSave( postId, postType );\n\tconst prevPostSave = usePrevious( lastPostSave );\n\n\tuseEffect( () => {\n\t\tif ( ! lastPostSave ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( prevPostSave && lastPostSave.savedAt === prevPostSave.savedAt ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst saver = activeCollaborators.find(\n\t\t\t( collaborator ) =>\n\t\t\t\tcollaborator.clientId === lastPostSave.savedByClientId &&\n\t\t\t\t! collaborator.isMe\n\t\t);\n\n\t\tif ( ! saver ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcallback( lastPostSave, saver, prevPostSave ?? null );\n\t}, [ lastPostSave, prevPostSave, activeCollaborators, callback ] );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -6,6 +6,7 @@ function getQueryParts(query) {
|
|
|
6
6
|
stableKey: "",
|
|
7
7
|
page: 1,
|
|
8
8
|
perPage: 10,
|
|
9
|
+
offset: void 0,
|
|
9
10
|
fields: null,
|
|
10
11
|
include: null,
|
|
11
12
|
context: "default"
|
|
@@ -25,6 +26,12 @@ function getQueryParts(query) {
|
|
|
25
26
|
parts.context = value;
|
|
26
27
|
break;
|
|
27
28
|
default:
|
|
29
|
+
if (key === "offset") {
|
|
30
|
+
const numericOffset = Number(value);
|
|
31
|
+
if (Number.isFinite(numericOffset)) {
|
|
32
|
+
parts.offset = numericOffset;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
28
35
|
if (key === "_fields") {
|
|
29
36
|
parts.fields = getNormalizedCommaSeparable(value) ?? [];
|
|
30
37
|
value = parts.fields.join();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/queried-data/get-query-parts.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { addQueryArgs } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport { withWeakMapCache, getNormalizedCommaSeparable } from '../utils';\n\n/**\n * An object of properties describing a specific query.\n *\n * @typedef {Object} WPQueriedDataQueryParts\n *\n * @property {number} page The query page (1-based index, default 1).\n * @property {number} perPage Items per page for query (default 10).\n * @property {string} stableKey An encoded stable string of all non-\n * pagination, non-fields query parameters.\n * @property {?(string[])} fields Target subset of fields to derive from\n * item objects.\n * @property {?(number[])} include Specific item IDs to include.\n * @property {string} context Scope under which the request is made;\n * determines returned fields in response.\n */\n\n/**\n * Given a query object, returns an object of parts, including pagination\n * details (`page` and `perPage`, or default values). All other properties are\n * encoded into a stable (idempotent) `stableKey` value.\n *\n * @param {Object} query Optional query object.\n *\n * @return {WPQueriedDataQueryParts} Query parts.\n */\nexport function getQueryParts( query ) {\n\t/**\n\t * @type {WPQueriedDataQueryParts}\n\t */\n\tconst parts = {\n\t\tstableKey: '',\n\t\tpage: 1,\n\t\tperPage: 10,\n\t\tfields: null,\n\t\tinclude: null,\n\t\tcontext: 'default',\n\t};\n\n\t// Ensure stable key by sorting keys. Also more efficient for iterating.\n\tconst keys = Object.keys( query ).sort();\n\n\tfor ( let i = 0; i < keys.length; i++ ) {\n\t\tconst key = keys[ i ];\n\t\tlet value = query[ key ];\n\n\t\tswitch ( key ) {\n\t\t\tcase 'page':\n\t\t\t\tparts[ key ] = Number( value );\n\t\t\t\tbreak;\n\n\t\t\tcase 'per_page':\n\t\t\t\tparts.perPage = Number( value );\n\t\t\t\tbreak;\n\n\t\t\tcase 'context':\n\t\t\t\tparts.context = value;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// While in theory, we could exclude \"_fields\" from the stableKey\n\t\t\t\t// because two request with different fields have the same results\n\t\t\t\t// We're not able to ensure that because the server can decide to omit\n\t\t\t\t// fields from the response even if we explicitly asked for it.\n\t\t\t\t// Example: Asking for titles in posts without title support.\n\t\t\t\tif ( key === '_fields' ) {\n\t\t\t\t\tparts.fields = getNormalizedCommaSeparable( value ) ?? [];\n\t\t\t\t\t// Make sure to normalize value for `stableKey`\n\t\t\t\t\tvalue = parts.fields.join();\n\t\t\t\t}\n\n\t\t\t\t// Two requests with different include values cannot have same results.\n\t\t\t\tif ( key === 'include' ) {\n\t\t\t\t\tif ( typeof value === 'number' ) {\n\t\t\t\t\t\tvalue = value.toString();\n\t\t\t\t\t}\n\t\t\t\t\tparts.include = (\n\t\t\t\t\t\tgetNormalizedCommaSeparable( value ) ?? []\n\t\t\t\t\t).map( Number );\n\t\t\t\t\t// Normalize value for `stableKey`.\n\t\t\t\t\tvalue = parts.include.join();\n\t\t\t\t}\n\n\t\t\t\t// While it could be any deterministic string, for simplicity's\n\t\t\t\t// sake mimic querystring encoding for stable key.\n\t\t\t\t//\n\t\t\t\t// TODO: For consistency with PHP implementation, addQueryArgs\n\t\t\t\t// should accept a key value pair, which may optimize its\n\t\t\t\t// implementation for our use here, vs. iterating an object\n\t\t\t\t// with only a single key.\n\t\t\t\tparts.stableKey +=\n\t\t\t\t\t( parts.stableKey ? '&' : '' ) +\n\t\t\t\t\taddQueryArgs( '', { [ key ]: value } ).slice( 1 );\n\t\t}\n\t}\n\n\treturn parts;\n}\n\nexport default withWeakMapCache( getQueryParts );\n"],
|
|
5
|
-
"mappings": ";AAGA,SAAS,oBAAoB;AAK7B,SAAS,kBAAkB,mCAAmC;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { addQueryArgs } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport { withWeakMapCache, getNormalizedCommaSeparable } from '../utils';\n\n/**\n * An object of properties describing a specific query.\n *\n * @typedef {Object} WPQueriedDataQueryParts\n *\n * @property {number} page The query page (1-based index, default 1).\n * @property {number} perPage Items per page for query (default 10).\n * @property {number} offset Absolute item offset (default undefined).\n * When present, also encoded into stableKey.\n * @property {string} stableKey An encoded stable string of all non-\n * pagination, non-fields query parameters.\n * @property {?(string[])} fields Target subset of fields to derive from\n * item objects.\n * @property {?(number[])} include Specific item IDs to include.\n * @property {string} context Scope under which the request is made;\n * determines returned fields in response.\n */\n\n/**\n * Given a query object, returns an object of parts, including pagination\n * details (`page` and `perPage`, or default values). All other properties are\n * encoded into a stable (idempotent) `stableKey` value.\n *\n * @param {Object} query Optional query object.\n *\n * @return {WPQueriedDataQueryParts} Query parts.\n */\nexport function getQueryParts( query ) {\n\t/**\n\t * @type {WPQueriedDataQueryParts}\n\t */\n\tconst parts = {\n\t\tstableKey: '',\n\t\tpage: 1,\n\t\tperPage: 10,\n\t\toffset: undefined,\n\t\tfields: null,\n\t\tinclude: null,\n\t\tcontext: 'default',\n\t};\n\n\t// Ensure stable key by sorting keys. Also more efficient for iterating.\n\tconst keys = Object.keys( query ).sort();\n\n\tfor ( let i = 0; i < keys.length; i++ ) {\n\t\tconst key = keys[ i ];\n\t\tlet value = query[ key ];\n\n\t\tswitch ( key ) {\n\t\t\tcase 'page':\n\t\t\t\tparts[ key ] = Number( value );\n\t\t\t\tbreak;\n\n\t\t\tcase 'per_page':\n\t\t\t\tparts.perPage = Number( value );\n\t\t\t\tbreak;\n\n\t\t\tcase 'context':\n\t\t\t\tparts.context = value;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Extract offset for use in pagination calculations while\n\t\t\t\t// still including it in the stableKey (different offsets\n\t\t\t\t// produce different result sets).\n\t\t\t\tif ( key === 'offset' ) {\n\t\t\t\t\tconst numericOffset = Number( value );\n\t\t\t\t\tif ( Number.isFinite( numericOffset ) ) {\n\t\t\t\t\t\tparts.offset = numericOffset;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// While in theory, we could exclude \"_fields\" from the stableKey\n\t\t\t\t// because two request with different fields have the same results\n\t\t\t\t// We're not able to ensure that because the server can decide to omit\n\t\t\t\t// fields from the response even if we explicitly asked for it.\n\t\t\t\t// Example: Asking for titles in posts without title support.\n\t\t\t\tif ( key === '_fields' ) {\n\t\t\t\t\tparts.fields = getNormalizedCommaSeparable( value ) ?? [];\n\t\t\t\t\t// Make sure to normalize value for `stableKey`\n\t\t\t\t\tvalue = parts.fields.join();\n\t\t\t\t}\n\n\t\t\t\t// Two requests with different include values cannot have same results.\n\t\t\t\tif ( key === 'include' ) {\n\t\t\t\t\tif ( typeof value === 'number' ) {\n\t\t\t\t\t\tvalue = value.toString();\n\t\t\t\t\t}\n\t\t\t\t\tparts.include = (\n\t\t\t\t\t\tgetNormalizedCommaSeparable( value ) ?? []\n\t\t\t\t\t).map( Number );\n\t\t\t\t\t// Normalize value for `stableKey`.\n\t\t\t\t\tvalue = parts.include.join();\n\t\t\t\t}\n\n\t\t\t\t// While it could be any deterministic string, for simplicity's\n\t\t\t\t// sake mimic querystring encoding for stable key.\n\t\t\t\t//\n\t\t\t\t// TODO: For consistency with PHP implementation, addQueryArgs\n\t\t\t\t// should accept a key value pair, which may optimize its\n\t\t\t\t// implementation for our use here, vs. iterating an object\n\t\t\t\t// with only a single key.\n\t\t\t\tparts.stableKey +=\n\t\t\t\t\t( parts.stableKey ? '&' : '' ) +\n\t\t\t\t\taddQueryArgs( '', { [ key ]: value } ).slice( 1 );\n\t\t}\n\t}\n\n\treturn parts;\n}\n\nexport default withWeakMapCache( getQueryParts );\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,oBAAoB;AAK7B,SAAS,kBAAkB,mCAAmC;AA6BvD,SAAS,cAAe,OAAQ;AAItC,QAAM,QAAQ;AAAA,IACb,WAAW;AAAA,IACX,MAAM;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,EACV;AAGA,QAAM,OAAO,OAAO,KAAM,KAAM,EAAE,KAAK;AAEvC,WAAU,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAM;AACvC,UAAM,MAAM,KAAM,CAAE;AACpB,QAAI,QAAQ,MAAO,GAAI;AAEvB,YAAS,KAAM;AAAA,MACd,KAAK;AACJ,cAAO,GAAI,IAAI,OAAQ,KAAM;AAC7B;AAAA,MAED,KAAK;AACJ,cAAM,UAAU,OAAQ,KAAM;AAC9B;AAAA,MAED,KAAK;AACJ,cAAM,UAAU;AAChB;AAAA,MAED;AAIC,YAAK,QAAQ,UAAW;AACvB,gBAAM,gBAAgB,OAAQ,KAAM;AACpC,cAAK,OAAO,SAAU,aAAc,GAAI;AACvC,kBAAM,SAAS;AAAA,UAChB;AAAA,QACD;AAOA,YAAK,QAAQ,WAAY;AACxB,gBAAM,SAAS,4BAA6B,KAAM,KAAK,CAAC;AAExD,kBAAQ,MAAM,OAAO,KAAK;AAAA,QAC3B;AAGA,YAAK,QAAQ,WAAY;AACxB,cAAK,OAAO,UAAU,UAAW;AAChC,oBAAQ,MAAM,SAAS;AAAA,UACxB;AACA,gBAAM,WACL,4BAA6B,KAAM,KAAK,CAAC,GACxC,IAAK,MAAO;AAEd,kBAAQ,MAAM,QAAQ,KAAK;AAAA,QAC5B;AASA,cAAM,cACH,MAAM,YAAY,MAAM,MAC1B,aAAc,IAAI,EAAE,CAAE,GAAI,GAAG,MAAM,CAAE,EAAE,MAAO,CAAE;AAAA,IACnD;AAAA,EACD;AAEA,SAAO;AACR;AAEA,IAAO,0BAAQ,iBAAkB,aAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,7 +5,15 @@ import getQueryParts from "./get-query-parts.mjs";
|
|
|
5
5
|
import { setNestedValue } from "../utils/index.mjs";
|
|
6
6
|
var queriedItemsCacheByState = /* @__PURE__ */ new WeakMap();
|
|
7
7
|
function getQueriedItemsUncached(state, query) {
|
|
8
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
stableKey,
|
|
10
|
+
page,
|
|
11
|
+
perPage,
|
|
12
|
+
offset: queryOffset,
|
|
13
|
+
include,
|
|
14
|
+
fields,
|
|
15
|
+
context
|
|
16
|
+
} = getQueryParts(query);
|
|
9
17
|
const itemIds = state.queries?.[context]?.[stableKey]?.itemIds;
|
|
10
18
|
if (!itemIds) {
|
|
11
19
|
return null;
|
|
@@ -14,8 +22,11 @@ function getQueriedItemsUncached(state, query) {
|
|
|
14
22
|
const endOffset = perPage === -1 ? itemIds.length : Math.min(startOffset + perPage, itemIds.length);
|
|
15
23
|
if (perPage !== -1 && itemIds.length < startOffset + perPage) {
|
|
16
24
|
const totalItems = state.queries[context][stableKey].meta?.totalItems;
|
|
17
|
-
if (Number.isFinite(totalItems)
|
|
18
|
-
|
|
25
|
+
if (Number.isFinite(totalItems)) {
|
|
26
|
+
const effectiveTotal = queryOffset !== void 0 ? totalItems - queryOffset : totalItems;
|
|
27
|
+
if (itemIds.length < effectiveTotal) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
19
30
|
}
|
|
20
31
|
}
|
|
21
32
|
const items = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/queried-data/selectors.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport EquivalentKeyMap from 'equivalent-key-map';\n\n/**\n * WordPress dependencies\n */\nimport { createSelector } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport getQueryParts from './get-query-parts';\nimport { setNestedValue } from '../utils';\n\n/**\n * Cache of state keys to EquivalentKeyMap where the inner map tracks queries\n * to their resulting items set. WeakMap allows garbage collection on expired\n * state references.\n *\n * @type {WeakMap<Object,EquivalentKeyMap>}\n */\nconst queriedItemsCacheByState = new WeakMap();\n\n/**\n * Returns items for a given query, or null if the items are not known.\n *\n * @param {Object} state State object.\n * @param {?Object} query Optional query.\n *\n * @return {?Array} Query items.\n */\nfunction getQueriedItemsUncached( state, query ) {\n\tconst {
|
|
5
|
-
"mappings": ";AAGA,OAAO,sBAAsB;AAK7B,SAAS,sBAAsB;AAK/B,OAAO,mBAAmB;AAC1B,SAAS,sBAAsB;AAS/B,IAAM,2BAA2B,oBAAI,QAAQ;AAU7C,SAAS,wBAAyB,OAAO,OAAQ;AAChD,QAAM,
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport EquivalentKeyMap from 'equivalent-key-map';\n\n/**\n * WordPress dependencies\n */\nimport { createSelector } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport getQueryParts from './get-query-parts';\nimport { setNestedValue } from '../utils';\n\n/**\n * Cache of state keys to EquivalentKeyMap where the inner map tracks queries\n * to their resulting items set. WeakMap allows garbage collection on expired\n * state references.\n *\n * @type {WeakMap<Object,EquivalentKeyMap>}\n */\nconst queriedItemsCacheByState = new WeakMap();\n\n/**\n * Returns items for a given query, or null if the items are not known.\n *\n * @param {Object} state State object.\n * @param {?Object} query Optional query.\n *\n * @return {?Array} Query items.\n */\nfunction getQueriedItemsUncached( state, query ) {\n\tconst {\n\t\tstableKey,\n\t\tpage,\n\t\tperPage,\n\t\toffset: queryOffset,\n\t\tinclude,\n\t\tfields,\n\t\tcontext,\n\t} = getQueryParts( query );\n\n\tconst itemIds = state.queries?.[ context ]?.[ stableKey ]?.itemIds;\n\tif ( ! itemIds ) {\n\t\treturn null;\n\t}\n\n\tconst startOffset = perPage === -1 ? 0 : ( page - 1 ) * perPage;\n\tconst endOffset =\n\t\tperPage === -1\n\t\t\t? itemIds.length\n\t\t\t: Math.min( startOffset + perPage, itemIds.length );\n\n\t// If the requested page range exceeds the stored itemIds, the data for\n\t// this specific pagination window may not have been fetched yet. Return\n\t// null unless totalItems confirms we already have all available items.\n\tif ( perPage !== -1 && itemIds.length < startOffset + perPage ) {\n\t\tconst totalItems =\n\t\t\tstate.queries[ context ][ stableKey ].meta?.totalItems;\n\t\tif ( Number.isFinite( totalItems ) ) {\n\t\t\t// For offset-based queries, totalItems (from X-WP-Total)\n\t\t\t// reflects the global count of all matching items, not the\n\t\t\t// count remaining after the offset. The number of items\n\t\t\t// available for this query is (totalItems - offset), so a\n\t\t\t// partial last page is expected and valid.\n\t\t\tconst effectiveTotal =\n\t\t\t\tqueryOffset !== undefined\n\t\t\t\t\t? totalItems - queryOffset\n\t\t\t\t\t: totalItems;\n\t\t\tif ( itemIds.length < effectiveTotal ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst items = [];\n\tfor ( let i = startOffset; i < endOffset; i++ ) {\n\t\tconst itemId = itemIds[ i ];\n\t\tif ( Array.isArray( include ) && ! include.includes( itemId ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( itemId === undefined ) {\n\t\t\tcontinue;\n\t\t}\n\t\t// Having a target item ID doesn't guarantee that this object has been queried.\n\t\tif ( ! state.items[ context ]?.hasOwnProperty( itemId ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst item = state.items[ context ][ itemId ];\n\n\t\tlet filteredItem;\n\t\tif ( Array.isArray( fields ) ) {\n\t\t\tfilteredItem = {};\n\n\t\t\tfor ( let f = 0; f < fields.length; f++ ) {\n\t\t\t\tconst field = fields[ f ].split( '.' );\n\t\t\t\tlet value = item;\n\t\t\t\tfield.forEach( ( fieldName ) => {\n\t\t\t\t\tvalue = value?.[ fieldName ];\n\t\t\t\t} );\n\n\t\t\t\tsetNestedValue( filteredItem, field, value );\n\t\t\t}\n\t\t} else {\n\t\t\t// If expecting a complete item, validate that completeness, or\n\t\t\t// otherwise abort.\n\t\t\tif ( ! state.itemIsComplete[ context ]?.[ itemId ] ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tfilteredItem = item;\n\t\t}\n\n\t\titems.push( filteredItem );\n\t}\n\n\treturn items;\n}\n\n/**\n * Returns items for a given query, or null if the items are not known. Caches\n * result both per state (by reference) and per query (by deep equality).\n * The caching approach is intended to be durable to query objects which are\n * deeply but not referentially equal, since otherwise:\n *\n * `getQueriedItems( state, {} ) !== getQueriedItems( state, {} )`\n *\n * @param {Object} state State object.\n * @param {?Object} query Optional query.\n *\n * @return {?Array} Query items.\n */\nexport const getQueriedItems = createSelector( ( state, query = {} ) => {\n\tlet queriedItemsCache = queriedItemsCacheByState.get( state );\n\tif ( queriedItemsCache ) {\n\t\tconst queriedItems = queriedItemsCache.get( query );\n\t\tif ( queriedItems !== undefined ) {\n\t\t\treturn queriedItems;\n\t\t}\n\t} else {\n\t\tqueriedItemsCache = new EquivalentKeyMap();\n\t\tqueriedItemsCacheByState.set( state, queriedItemsCache );\n\t}\n\n\tconst items = getQueriedItemsUncached( state, query );\n\tqueriedItemsCache.set( query, items );\n\treturn items;\n} );\n\nexport function getQueriedTotalItems( state, query = {} ) {\n\tconst { stableKey, context } = getQueryParts( query );\n\n\treturn state.queries?.[ context ]?.[ stableKey ]?.meta?.totalItems ?? null;\n}\n\nexport function getQueriedTotalPages( state, query = {} ) {\n\tconst { stableKey, context } = getQueryParts( query );\n\n\treturn state.queries?.[ context ]?.[ stableKey ]?.meta?.totalPages ?? null;\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,OAAO,sBAAsB;AAK7B,SAAS,sBAAsB;AAK/B,OAAO,mBAAmB;AAC1B,SAAS,sBAAsB;AAS/B,IAAM,2BAA2B,oBAAI,QAAQ;AAU7C,SAAS,wBAAyB,OAAO,OAAQ;AAChD,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,cAAe,KAAM;AAEzB,QAAM,UAAU,MAAM,UAAW,OAAQ,IAAK,SAAU,GAAG;AAC3D,MAAK,CAAE,SAAU;AAChB,WAAO;AAAA,EACR;AAEA,QAAM,cAAc,YAAY,KAAK,KAAM,OAAO,KAAM;AACxD,QAAM,YACL,YAAY,KACT,QAAQ,SACR,KAAK,IAAK,cAAc,SAAS,QAAQ,MAAO;AAKpD,MAAK,YAAY,MAAM,QAAQ,SAAS,cAAc,SAAU;AAC/D,UAAM,aACL,MAAM,QAAS,OAAQ,EAAG,SAAU,EAAE,MAAM;AAC7C,QAAK,OAAO,SAAU,UAAW,GAAI;AAMpC,YAAM,iBACL,gBAAgB,SACb,aAAa,cACb;AACJ,UAAK,QAAQ,SAAS,gBAAiB;AACtC,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAEA,QAAM,QAAQ,CAAC;AACf,WAAU,IAAI,aAAa,IAAI,WAAW,KAAM;AAC/C,UAAM,SAAS,QAAS,CAAE;AAC1B,QAAK,MAAM,QAAS,OAAQ,KAAK,CAAE,QAAQ,SAAU,MAAO,GAAI;AAC/D;AAAA,IACD;AACA,QAAK,WAAW,QAAY;AAC3B;AAAA,IACD;AAEA,QAAK,CAAE,MAAM,MAAO,OAAQ,GAAG,eAAgB,MAAO,GAAI;AACzD,aAAO;AAAA,IACR;AAEA,UAAM,OAAO,MAAM,MAAO,OAAQ,EAAG,MAAO;AAE5C,QAAI;AACJ,QAAK,MAAM,QAAS,MAAO,GAAI;AAC9B,qBAAe,CAAC;AAEhB,eAAU,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAM;AACzC,cAAM,QAAQ,OAAQ,CAAE,EAAE,MAAO,GAAI;AACrC,YAAI,QAAQ;AACZ,cAAM,QAAS,CAAE,cAAe;AAC/B,kBAAQ,QAAS,SAAU;AAAA,QAC5B,CAAE;AAEF,uBAAgB,cAAc,OAAO,KAAM;AAAA,MAC5C;AAAA,IACD,OAAO;AAGN,UAAK,CAAE,MAAM,eAAgB,OAAQ,IAAK,MAAO,GAAI;AACpD,eAAO;AAAA,MACR;AAEA,qBAAe;AAAA,IAChB;AAEA,UAAM,KAAM,YAAa;AAAA,EAC1B;AAEA,SAAO;AACR;AAeO,IAAM,kBAAkB,eAAgB,CAAE,OAAO,QAAQ,CAAC,MAAO;AACvE,MAAI,oBAAoB,yBAAyB,IAAK,KAAM;AAC5D,MAAK,mBAAoB;AACxB,UAAM,eAAe,kBAAkB,IAAK,KAAM;AAClD,QAAK,iBAAiB,QAAY;AACjC,aAAO;AAAA,IACR;AAAA,EACD,OAAO;AACN,wBAAoB,IAAI,iBAAiB;AACzC,6BAAyB,IAAK,OAAO,iBAAkB;AAAA,EACxD;AAEA,QAAM,QAAQ,wBAAyB,OAAO,KAAM;AACpD,oBAAkB,IAAK,OAAO,KAAM;AACpC,SAAO;AACR,CAAE;AAEK,SAAS,qBAAsB,OAAO,QAAQ,CAAC,GAAI;AACzD,QAAM,EAAE,WAAW,QAAQ,IAAI,cAAe,KAAM;AAEpD,SAAO,MAAM,UAAW,OAAQ,IAAK,SAAU,GAAG,MAAM,cAAc;AACvE;AAEO,SAAS,qBAAsB,OAAO,QAAQ,CAAC,GAAI;AACzD,QAAM,EAAE,WAAW,QAAQ,IAAI,cAAe,KAAM;AAEpD,SAAO,MAAM,UAAW,OAAQ,IAAK,SAAU,GAAG,MAAM,cAAc;AACvE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build-module/reducer.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { createUndoManager } from "@wordpress/undo-manager";
|
|
|
6
6
|
import { ifMatchingAction, replaceAction } from "./utils/index.mjs";
|
|
7
7
|
import { reducer as queriedDataReducer } from "./queried-data/index.mjs";
|
|
8
8
|
import { rootEntitiesConfig, DEFAULT_ENTITY_KEY } from "./entities.mjs";
|
|
9
|
+
import { ConnectionErrorCode } from "./sync.mjs";
|
|
9
10
|
function users(state = { byId: {}, queries: {} }, action) {
|
|
10
11
|
switch (action.type) {
|
|
11
12
|
case "RECEIVE_USER_QUERY":
|
|
@@ -420,6 +421,11 @@ function collaborationSupported(state = true, action) {
|
|
|
420
421
|
switch (action.type) {
|
|
421
422
|
case "SET_COLLABORATION_SUPPORTED":
|
|
422
423
|
return action.supported;
|
|
424
|
+
case "SET_SYNC_CONNECTION_STATUS":
|
|
425
|
+
if (ConnectionErrorCode.DOCUMENT_SIZE_LIMIT_EXCEEDED === action.status?.error?.code) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
return state;
|
|
423
429
|
}
|
|
424
430
|
return state;
|
|
425
431
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/reducer.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport fastDeepEqual from 'fast-deep-equal/es6/index.js';\n\n/**\n * WordPress dependencies\n */\nimport { compose } from '@wordpress/compose';\nimport { combineReducers } from '@wordpress/data';\nimport { createUndoManager } from '@wordpress/undo-manager';\n\n/**\n * Internal dependencies\n */\nimport { ifMatchingAction, replaceAction } from './utils';\nimport { reducer as queriedDataReducer } from './queried-data';\nimport { rootEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';\n\n/** @typedef {import('./types').AnyFunction} AnyFunction */\n\n/**\n * Reducer managing authors state. Keyed by id.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function users( state = { byId: {}, queries: {} }, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_USER_QUERY':\n\t\t\treturn {\n\t\t\t\tbyId: {\n\t\t\t\t\t...state.byId,\n\t\t\t\t\t// Key users by their ID.\n\t\t\t\t\t...action.users.reduce(\n\t\t\t\t\t\t( newUsers, user ) => ( {\n\t\t\t\t\t\t\t...newUsers,\n\t\t\t\t\t\t\t[ user.id ]: user,\n\t\t\t\t\t\t} ),\n\t\t\t\t\t\t{}\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\tqueries: {\n\t\t\t\t\t...state.queries,\n\t\t\t\t\t[ action.queryID ]: action.users.map( ( user ) => user.id ),\n\t\t\t\t},\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing current user state.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function currentUser( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_CURRENT_USER':\n\t\t\treturn action.currentUser;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the current theme.\n *\n * @param {string|undefined} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {string|undefined} Updated state.\n */\nexport function currentTheme( state = undefined, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_CURRENT_THEME':\n\t\t\treturn action.currentTheme.stylesheet;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the current global styles id.\n *\n * @param {string|undefined} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {string|undefined} Updated state.\n */\nexport function currentGlobalStylesId( state = undefined, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_CURRENT_GLOBAL_STYLES_ID':\n\t\t\treturn action.id;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the theme base global styles.\n *\n * @param {Record<string, object>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, object>} Updated state.\n */\nexport function themeBaseGlobalStyles( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_THEME_GLOBAL_STYLES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.stylesheet ]: action.globalStyles,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the theme global styles variations.\n *\n * @param {Record<string, object>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, object>} Updated state.\n */\nexport function themeGlobalStyleVariations( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.stylesheet ]: action.variations,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\nconst withMultiEntityRecordEdits = ( reducer ) => ( state, action ) => {\n\tif ( action.type === 'UNDO' || action.type === 'REDO' ) {\n\t\tconst { record } = action;\n\n\t\tlet newState = state;\n\t\trecord.forEach( ( { id: { kind, name, recordId }, changes } ) => {\n\t\t\tnewState = reducer( newState, {\n\t\t\t\ttype: 'EDIT_ENTITY_RECORD',\n\t\t\t\tkind,\n\t\t\t\tname,\n\t\t\t\trecordId,\n\t\t\t\tedits: Object.entries( changes ).reduce(\n\t\t\t\t\t( acc, [ key, value ] ) => {\n\t\t\t\t\t\tacc[ key ] =\n\t\t\t\t\t\t\taction.type === 'UNDO' ? value.from : value.to;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t),\n\t\t\t} );\n\t\t} );\n\t\treturn newState;\n\t}\n\n\treturn reducer( state, action );\n};\n\n/**\n * Higher Order Reducer for a given entity config. It supports:\n *\n * - Fetching\n * - Editing\n * - Saving\n *\n * @param {Object} entityConfig Entity config.\n *\n * @return {AnyFunction} Reducer.\n */\nfunction entity( entityConfig ) {\n\treturn compose( [\n\t\twithMultiEntityRecordEdits,\n\n\t\t// Limit to matching action type so we don't attempt to replace action on\n\t\t// an unhandled action.\n\t\tifMatchingAction(\n\t\t\t( action ) =>\n\t\t\t\taction.name &&\n\t\t\t\taction.kind &&\n\t\t\t\taction.name === entityConfig.name &&\n\t\t\t\taction.kind === entityConfig.kind\n\t\t),\n\n\t\t// Inject the entity config into the action.\n\t\treplaceAction( ( action ) => {\n\t\t\treturn {\n\t\t\t\tkey: entityConfig.key || DEFAULT_ENTITY_KEY,\n\t\t\t\t...action,\n\t\t\t};\n\t\t} ),\n\t] )(\n\t\tcombineReducers( {\n\t\t\tqueriedData: queriedDataReducer,\n\t\t\tedits: ( state = {}, action ) => {\n\t\t\t\tswitch ( action.type ) {\n\t\t\t\t\tcase 'RECEIVE_ITEMS':\n\t\t\t\t\t\tconst context = action?.query?.context ?? 'default';\n\t\t\t\t\t\tif ( context !== 'default' ) {\n\t\t\t\t\t\t\treturn state;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst nextState = { ...state };\n\t\t\t\t\t\tconst itemsList = Array.isArray( action.items )\n\t\t\t\t\t\t\t? action.items\n\t\t\t\t\t\t\t: [ action.items ];\n\n\t\t\t\t\t\tfor ( const record of itemsList ) {\n\t\t\t\t\t\t\tconst recordId = record?.[ action.key ];\n\t\t\t\t\t\t\tconst edits = nextState[ recordId ];\n\t\t\t\t\t\t\tif ( ! edits ) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst nextEdits = Object.keys( edits ).reduce(\n\t\t\t\t\t\t\t\t( acc, key ) => {\n\t\t\t\t\t\t\t\t\t// If the edited value is still different to the persisted value,\n\t\t\t\t\t\t\t\t\t// keep the edited value in edits.\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t// Edits are the \"raw\" attribute values, but records may have\n\t\t\t\t\t\t\t\t\t\t// objects with more properties, so we use `get` here for the\n\t\t\t\t\t\t\t\t\t\t// comparison.\n\t\t\t\t\t\t\t\t\t\t! fastDeepEqual(\n\t\t\t\t\t\t\t\t\t\t\tedits[ key ],\n\t\t\t\t\t\t\t\t\t\t\trecord[ key ]?.raw ?? record[ key ]\n\t\t\t\t\t\t\t\t\t\t) &&\n\t\t\t\t\t\t\t\t\t\t// Sometimes the server alters the sent value which means\n\t\t\t\t\t\t\t\t\t\t// we need to also remove the edits before the api request.\n\t\t\t\t\t\t\t\t\t\t( ! action.persistedEdits ||\n\t\t\t\t\t\t\t\t\t\t\t! fastDeepEqual(\n\t\t\t\t\t\t\t\t\t\t\t\tedits[ key ],\n\t\t\t\t\t\t\t\t\t\t\t\taction.persistedEdits[ key ]\n\t\t\t\t\t\t\t\t\t\t\t) )\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tacc[ key ] = edits[ key ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{}\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif ( Object.keys( nextEdits ).length ) {\n\t\t\t\t\t\t\t\tnextState[ recordId ] = nextEdits;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdelete nextState[ recordId ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nextState;\n\n\t\t\t\t\tcase 'EDIT_ENTITY_RECORD':\n\t\t\t\t\t\tconst nextEdits = {\n\t\t\t\t\t\t\t...state[ action.recordId ],\n\t\t\t\t\t\t\t...action.edits,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tObject.keys( nextEdits ).forEach( ( key ) => {\n\t\t\t\t\t\t\t// Delete cleared edits so that the properties\n\t\t\t\t\t\t\t// are not considered dirty.\n\t\t\t\t\t\t\tif ( nextEdits[ key ] === undefined ) {\n\t\t\t\t\t\t\t\tdelete nextEdits[ key ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...state,\n\t\t\t\t\t\t\t[ action.recordId ]: nextEdits,\n\t\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\n\t\t\tsaving: ( state = {}, action ) => {\n\t\t\t\tswitch ( action.type ) {\n\t\t\t\t\tcase 'SAVE_ENTITY_RECORD_START':\n\t\t\t\t\tcase 'SAVE_ENTITY_RECORD_FINISH':\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...state,\n\t\t\t\t\t\t\t[ action.recordId ]: {\n\t\t\t\t\t\t\t\tpending:\n\t\t\t\t\t\t\t\t\taction.type === 'SAVE_ENTITY_RECORD_START',\n\t\t\t\t\t\t\t\terror: action.error,\n\t\t\t\t\t\t\t\tisAutosave: action.isAutosave,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\n\t\t\tdeleting: ( state = {}, action ) => {\n\t\t\t\tswitch ( action.type ) {\n\t\t\t\t\tcase 'DELETE_ENTITY_RECORD_START':\n\t\t\t\t\tcase 'DELETE_ENTITY_RECORD_FINISH':\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...state,\n\t\t\t\t\t\t\t[ action.recordId ]: {\n\t\t\t\t\t\t\t\tpending:\n\t\t\t\t\t\t\t\t\taction.type ===\n\t\t\t\t\t\t\t\t\t'DELETE_ENTITY_RECORD_START',\n\t\t\t\t\t\t\t\terror: action.error,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\n\t\t\trevisions: ( state = {}, action ) => {\n\t\t\t\t// Use the same queriedDataReducer shape for revisions.\n\t\t\t\tif ( action.type === 'RECEIVE_ITEM_REVISIONS' ) {\n\t\t\t\t\tconst recordKey = action.recordKey;\n\t\t\t\t\tdelete action.recordKey;\n\t\t\t\t\tconst newState = queriedDataReducer( state[ recordKey ], {\n\t\t\t\t\t\t...action,\n\t\t\t\t\t\ttype: 'RECEIVE_ITEMS',\n\t\t\t\t\t} );\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...state,\n\t\t\t\t\t\t[ recordKey ]: newState,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif ( action.type === 'REMOVE_ITEMS' ) {\n\t\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t\tObject.entries( state ).filter(\n\t\t\t\t\t\t\t( [ id ] ) =>\n\t\t\t\t\t\t\t\t! action.itemIds.some( ( itemId ) => {\n\t\t\t\t\t\t\t\t\tif ( Number.isInteger( itemId ) ) {\n\t\t\t\t\t\t\t\t\t\treturn itemId === +id;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn itemId === id;\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\t\t} )\n\t);\n}\n\n/**\n * Reducer keeping track of the registered entities.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function entitiesConfig( state = rootEntitiesConfig, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'ADD_ENTITIES':\n\t\t\treturn [ ...state, ...action.entities ];\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer keeping track of the registered entities config and data.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport const entities = ( state = {}, action ) => {\n\tconst newConfig = entitiesConfig( state.config, action );\n\n\t// Generates a reducer for the entities nested by `kind` and `name`.\n\t// A config array with shape:\n\t// ```\n\t// [\n\t// { kind: 'taxonomy', name: 'category' },\n\t// { kind: 'taxonomy', name: 'post_tag' },\n\t// { kind: 'postType', name: 'post' },\n\t// { kind: 'postType', name: 'page' },\n\t// ]\n\t// ```\n\t// generates a reducer for state tree with shape:\n\t// ```\n\t// {\n\t// taxonomy: {\n\t// category,\n\t// post_tag,\n\t// },\n\t// postType: {\n\t// post,\n\t// page,\n\t// },\n\t// }\n\t// ```\n\tlet entitiesDataReducer = state.reducer;\n\tif ( ! entitiesDataReducer || newConfig !== state.config ) {\n\t\tconst entitiesByKind = newConfig.reduce( ( acc, record ) => {\n\t\t\tconst { kind } = record;\n\t\t\tif ( ! acc[ kind ] ) {\n\t\t\t\tacc[ kind ] = [];\n\t\t\t}\n\t\t\tacc[ kind ].push( record );\n\t\t\treturn acc;\n\t\t}, {} );\n\n\t\tentitiesDataReducer = combineReducers(\n\t\t\tObject.fromEntries(\n\t\t\t\tObject.entries( entitiesByKind ).map(\n\t\t\t\t\t( [ kind, subEntities ] ) => {\n\t\t\t\t\t\tconst kindReducer = combineReducers(\n\t\t\t\t\t\t\tObject.fromEntries(\n\t\t\t\t\t\t\t\tsubEntities.map( ( entityConfig ) => [\n\t\t\t\t\t\t\t\t\tentityConfig.name,\n\t\t\t\t\t\t\t\t\tentity( entityConfig ),\n\t\t\t\t\t\t\t\t] )\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn [ kind, kindReducer ];\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\tconst newData = entitiesDataReducer( state.records, action );\n\n\tif (\n\t\tnewData === state.records &&\n\t\tnewConfig === state.config &&\n\t\tentitiesDataReducer === state.reducer\n\t) {\n\t\treturn state;\n\t}\n\n\treturn {\n\t\treducer: entitiesDataReducer,\n\t\trecords: newData,\n\t\tconfig: newConfig,\n\t};\n};\n\n/**\n * @type {UndoManager}\n */\nexport function undoManager( state = createUndoManager() ) {\n\treturn state;\n}\n\nexport function editsReference( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'EDIT_ENTITY_RECORD':\n\t\tcase 'UNDO':\n\t\tcase 'REDO':\n\t\t\treturn {};\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing embed preview data.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function embedPreviews( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_EMBED_PREVIEW':\n\t\t\tconst { url, preview } = action;\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ url ]: preview,\n\t\t\t};\n\t}\n\treturn state;\n}\n\n/**\n * State which tracks whether the user can perform an action on a REST\n * resource.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function userPermissions( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_USER_PERMISSION':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.key ]: action.isAllowed,\n\t\t\t};\n\t\tcase 'RECEIVE_USER_PERMISSIONS':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t...action.permissions,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer returning autosaves keyed by their parent's post id.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function autosaves( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_AUTOSAVES':\n\t\t\tconst { postId, autosaves: autosavesData } = action;\n\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ postId ]: autosavesData,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\nexport function blockPatterns( state = [], action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_BLOCK_PATTERNS':\n\t\t\treturn action.patterns;\n\t}\n\n\treturn state;\n}\n\nexport function blockPatternCategories( state = [], action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_BLOCK_PATTERN_CATEGORIES':\n\t\t\treturn action.categories;\n\t}\n\n\treturn state;\n}\n\nexport function userPatternCategories( state = [], action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_USER_PATTERN_CATEGORIES':\n\t\t\treturn action.patternCategories;\n\t}\n\treturn state;\n}\n\nexport function navigationFallbackId( state = null, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_NAVIGATION_FALLBACK_ID':\n\t\t\treturn action.fallbackId;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the theme global styles revisions.\n *\n * @param {Record<string, object>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, object>} Updated state.\n */\nexport function themeGlobalStyleRevisions( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.currentId ]: action.revisions,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the template lookup per query.\n *\n * @param {Record<string, string>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, string>} Updated state.\n */\nexport function defaultTemplates( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_DEFAULT_TEMPLATE':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ JSON.stringify( action.query ) ]: action.templateId,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer returning an object of registered post meta.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function registeredPostMeta( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_REGISTERED_POST_META':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.postType ]: action.registeredPostMeta,\n\t\t\t};\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing editor settings.\n *\n * @param {Object} state Current state.\n * @param {Object} action Action object.\n *\n * @return {Object} Updated state.\n */\nexport function editorSettings( state = null, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_EDITOR_SETTINGS':\n\t\t\treturn action.settings;\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing editor assets.\n *\n * @param {Object} state Current state.\n * @param {Object} action Action object.\n *\n * @return {Object} Updated state.\n */\nexport function editorAssets( state = null, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_EDITOR_ASSETS':\n\t\t\treturn action.assets;\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing sync connection states for entities.\n * Keyed by \"kind/name:id\" (e.g., \"postType/post:123\").\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function syncConnectionStatuses( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'SET_SYNC_CONNECTION_STATUS': {\n\t\t\tconst key = `${ action.kind }/${ action.name }:${ action.key }`;\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ key ]: action.status,\n\t\t\t};\n\t\t}\n\t\tcase 'CLEAR_SYNC_CONNECTION_STATUS': {\n\t\t\tconst key = `${ action.kind }/${ action.name }:${ action.key }`;\n\t\t\tconst { [ key ]: _, ...rest } = state;\n\t\t\treturn rest;\n\t\t}\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing whether collaboration is supported.\n *\n * Default to true, as collaboration is supported by default\n * unless explicitly disabled due to unsupported conditions\n * such as metaboxes.\n *\n * @param {boolean} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {boolean} Updated state.\n */\nexport function collaborationSupported( state = true, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'SET_COLLABORATION_SUPPORTED':\n\t\t\treturn action.supported;\n\t}\n\treturn state;\n}\n\nexport default combineReducers( {\n\tusers,\n\tcurrentTheme,\n\tcurrentGlobalStylesId,\n\tcurrentUser,\n\tthemeGlobalStyleVariations,\n\tthemeBaseGlobalStyles,\n\tthemeGlobalStyleRevisions,\n\tentities,\n\teditsReference,\n\tundoManager,\n\tembedPreviews,\n\tuserPermissions,\n\tautosaves,\n\tblockPatterns,\n\tblockPatternCategories,\n\tuserPatternCategories,\n\tnavigationFallbackId,\n\tdefaultTemplates,\n\tregisteredPostMeta,\n\teditorSettings,\n\teditorAssets,\n\tsyncConnectionStatuses,\n\tcollaborationSupported,\n} );\n"],
|
|
5
|
-
"mappings": ";AAGA,OAAO,mBAAmB;AAK1B,SAAS,eAAe;AACxB,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAKlC,SAAS,kBAAkB,qBAAqB;AAChD,SAAS,WAAW,0BAA0B;AAC9C,SAAS,oBAAoB,0BAA0B;
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport fastDeepEqual from 'fast-deep-equal/es6/index.js';\n\n/**\n * WordPress dependencies\n */\nimport { compose } from '@wordpress/compose';\nimport { combineReducers } from '@wordpress/data';\nimport { createUndoManager } from '@wordpress/undo-manager';\n\n/**\n * Internal dependencies\n */\nimport { ifMatchingAction, replaceAction } from './utils';\nimport { reducer as queriedDataReducer } from './queried-data';\nimport { rootEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';\nimport { ConnectionErrorCode } from './sync';\n\n/** @typedef {import('./types').AnyFunction} AnyFunction */\n\n/**\n * Reducer managing authors state. Keyed by id.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function users( state = { byId: {}, queries: {} }, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_USER_QUERY':\n\t\t\treturn {\n\t\t\t\tbyId: {\n\t\t\t\t\t...state.byId,\n\t\t\t\t\t// Key users by their ID.\n\t\t\t\t\t...action.users.reduce(\n\t\t\t\t\t\t( newUsers, user ) => ( {\n\t\t\t\t\t\t\t...newUsers,\n\t\t\t\t\t\t\t[ user.id ]: user,\n\t\t\t\t\t\t} ),\n\t\t\t\t\t\t{}\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\tqueries: {\n\t\t\t\t\t...state.queries,\n\t\t\t\t\t[ action.queryID ]: action.users.map( ( user ) => user.id ),\n\t\t\t\t},\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing current user state.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function currentUser( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_CURRENT_USER':\n\t\t\treturn action.currentUser;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the current theme.\n *\n * @param {string|undefined} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {string|undefined} Updated state.\n */\nexport function currentTheme( state = undefined, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_CURRENT_THEME':\n\t\t\treturn action.currentTheme.stylesheet;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the current global styles id.\n *\n * @param {string|undefined} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {string|undefined} Updated state.\n */\nexport function currentGlobalStylesId( state = undefined, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_CURRENT_GLOBAL_STYLES_ID':\n\t\t\treturn action.id;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the theme base global styles.\n *\n * @param {Record<string, object>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, object>} Updated state.\n */\nexport function themeBaseGlobalStyles( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_THEME_GLOBAL_STYLES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.stylesheet ]: action.globalStyles,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the theme global styles variations.\n *\n * @param {Record<string, object>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, object>} Updated state.\n */\nexport function themeGlobalStyleVariations( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.stylesheet ]: action.variations,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\nconst withMultiEntityRecordEdits = ( reducer ) => ( state, action ) => {\n\tif ( action.type === 'UNDO' || action.type === 'REDO' ) {\n\t\tconst { record } = action;\n\n\t\tlet newState = state;\n\t\trecord.forEach( ( { id: { kind, name, recordId }, changes } ) => {\n\t\t\tnewState = reducer( newState, {\n\t\t\t\ttype: 'EDIT_ENTITY_RECORD',\n\t\t\t\tkind,\n\t\t\t\tname,\n\t\t\t\trecordId,\n\t\t\t\tedits: Object.entries( changes ).reduce(\n\t\t\t\t\t( acc, [ key, value ] ) => {\n\t\t\t\t\t\tacc[ key ] =\n\t\t\t\t\t\t\taction.type === 'UNDO' ? value.from : value.to;\n\t\t\t\t\t\treturn acc;\n\t\t\t\t\t},\n\t\t\t\t\t{}\n\t\t\t\t),\n\t\t\t} );\n\t\t} );\n\t\treturn newState;\n\t}\n\n\treturn reducer( state, action );\n};\n\n/**\n * Higher Order Reducer for a given entity config. It supports:\n *\n * - Fetching\n * - Editing\n * - Saving\n *\n * @param {Object} entityConfig Entity config.\n *\n * @return {AnyFunction} Reducer.\n */\nfunction entity( entityConfig ) {\n\treturn compose( [\n\t\twithMultiEntityRecordEdits,\n\n\t\t// Limit to matching action type so we don't attempt to replace action on\n\t\t// an unhandled action.\n\t\tifMatchingAction(\n\t\t\t( action ) =>\n\t\t\t\taction.name &&\n\t\t\t\taction.kind &&\n\t\t\t\taction.name === entityConfig.name &&\n\t\t\t\taction.kind === entityConfig.kind\n\t\t),\n\n\t\t// Inject the entity config into the action.\n\t\treplaceAction( ( action ) => {\n\t\t\treturn {\n\t\t\t\tkey: entityConfig.key || DEFAULT_ENTITY_KEY,\n\t\t\t\t...action,\n\t\t\t};\n\t\t} ),\n\t] )(\n\t\tcombineReducers( {\n\t\t\tqueriedData: queriedDataReducer,\n\t\t\tedits: ( state = {}, action ) => {\n\t\t\t\tswitch ( action.type ) {\n\t\t\t\t\tcase 'RECEIVE_ITEMS':\n\t\t\t\t\t\tconst context = action?.query?.context ?? 'default';\n\t\t\t\t\t\tif ( context !== 'default' ) {\n\t\t\t\t\t\t\treturn state;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst nextState = { ...state };\n\t\t\t\t\t\tconst itemsList = Array.isArray( action.items )\n\t\t\t\t\t\t\t? action.items\n\t\t\t\t\t\t\t: [ action.items ];\n\n\t\t\t\t\t\tfor ( const record of itemsList ) {\n\t\t\t\t\t\t\tconst recordId = record?.[ action.key ];\n\t\t\t\t\t\t\tconst edits = nextState[ recordId ];\n\t\t\t\t\t\t\tif ( ! edits ) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst nextEdits = Object.keys( edits ).reduce(\n\t\t\t\t\t\t\t\t( acc, key ) => {\n\t\t\t\t\t\t\t\t\t// If the edited value is still different to the persisted value,\n\t\t\t\t\t\t\t\t\t// keep the edited value in edits.\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t// Edits are the \"raw\" attribute values, but records may have\n\t\t\t\t\t\t\t\t\t\t// objects with more properties, so we use `get` here for the\n\t\t\t\t\t\t\t\t\t\t// comparison.\n\t\t\t\t\t\t\t\t\t\t! fastDeepEqual(\n\t\t\t\t\t\t\t\t\t\t\tedits[ key ],\n\t\t\t\t\t\t\t\t\t\t\trecord[ key ]?.raw ?? record[ key ]\n\t\t\t\t\t\t\t\t\t\t) &&\n\t\t\t\t\t\t\t\t\t\t// Sometimes the server alters the sent value which means\n\t\t\t\t\t\t\t\t\t\t// we need to also remove the edits before the api request.\n\t\t\t\t\t\t\t\t\t\t( ! action.persistedEdits ||\n\t\t\t\t\t\t\t\t\t\t\t! fastDeepEqual(\n\t\t\t\t\t\t\t\t\t\t\t\tedits[ key ],\n\t\t\t\t\t\t\t\t\t\t\t\taction.persistedEdits[ key ]\n\t\t\t\t\t\t\t\t\t\t\t) )\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\tacc[ key ] = edits[ key ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn acc;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{}\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tif ( Object.keys( nextEdits ).length ) {\n\t\t\t\t\t\t\t\tnextState[ recordId ] = nextEdits;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdelete nextState[ recordId ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn nextState;\n\n\t\t\t\t\tcase 'EDIT_ENTITY_RECORD':\n\t\t\t\t\t\tconst nextEdits = {\n\t\t\t\t\t\t\t...state[ action.recordId ],\n\t\t\t\t\t\t\t...action.edits,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tObject.keys( nextEdits ).forEach( ( key ) => {\n\t\t\t\t\t\t\t// Delete cleared edits so that the properties\n\t\t\t\t\t\t\t// are not considered dirty.\n\t\t\t\t\t\t\tif ( nextEdits[ key ] === undefined ) {\n\t\t\t\t\t\t\t\tdelete nextEdits[ key ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...state,\n\t\t\t\t\t\t\t[ action.recordId ]: nextEdits,\n\t\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\n\t\t\tsaving: ( state = {}, action ) => {\n\t\t\t\tswitch ( action.type ) {\n\t\t\t\t\tcase 'SAVE_ENTITY_RECORD_START':\n\t\t\t\t\tcase 'SAVE_ENTITY_RECORD_FINISH':\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...state,\n\t\t\t\t\t\t\t[ action.recordId ]: {\n\t\t\t\t\t\t\t\tpending:\n\t\t\t\t\t\t\t\t\taction.type === 'SAVE_ENTITY_RECORD_START',\n\t\t\t\t\t\t\t\terror: action.error,\n\t\t\t\t\t\t\t\tisAutosave: action.isAutosave,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\n\t\t\tdeleting: ( state = {}, action ) => {\n\t\t\t\tswitch ( action.type ) {\n\t\t\t\t\tcase 'DELETE_ENTITY_RECORD_START':\n\t\t\t\t\tcase 'DELETE_ENTITY_RECORD_FINISH':\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...state,\n\t\t\t\t\t\t\t[ action.recordId ]: {\n\t\t\t\t\t\t\t\tpending:\n\t\t\t\t\t\t\t\t\taction.type ===\n\t\t\t\t\t\t\t\t\t'DELETE_ENTITY_RECORD_START',\n\t\t\t\t\t\t\t\terror: action.error,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\n\t\t\trevisions: ( state = {}, action ) => {\n\t\t\t\t// Use the same queriedDataReducer shape for revisions.\n\t\t\t\tif ( action.type === 'RECEIVE_ITEM_REVISIONS' ) {\n\t\t\t\t\tconst recordKey = action.recordKey;\n\t\t\t\t\tdelete action.recordKey;\n\t\t\t\t\tconst newState = queriedDataReducer( state[ recordKey ], {\n\t\t\t\t\t\t...action,\n\t\t\t\t\t\ttype: 'RECEIVE_ITEMS',\n\t\t\t\t\t} );\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...state,\n\t\t\t\t\t\t[ recordKey ]: newState,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif ( action.type === 'REMOVE_ITEMS' ) {\n\t\t\t\t\treturn Object.fromEntries(\n\t\t\t\t\t\tObject.entries( state ).filter(\n\t\t\t\t\t\t\t( [ id ] ) =>\n\t\t\t\t\t\t\t\t! action.itemIds.some( ( itemId ) => {\n\t\t\t\t\t\t\t\t\tif ( Number.isInteger( itemId ) ) {\n\t\t\t\t\t\t\t\t\t\treturn itemId === +id;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn itemId === id;\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn state;\n\t\t\t},\n\t\t} )\n\t);\n}\n\n/**\n * Reducer keeping track of the registered entities.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function entitiesConfig( state = rootEntitiesConfig, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'ADD_ENTITIES':\n\t\t\treturn [ ...state, ...action.entities ];\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer keeping track of the registered entities config and data.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport const entities = ( state = {}, action ) => {\n\tconst newConfig = entitiesConfig( state.config, action );\n\n\t// Generates a reducer for the entities nested by `kind` and `name`.\n\t// A config array with shape:\n\t// ```\n\t// [\n\t// { kind: 'taxonomy', name: 'category' },\n\t// { kind: 'taxonomy', name: 'post_tag' },\n\t// { kind: 'postType', name: 'post' },\n\t// { kind: 'postType', name: 'page' },\n\t// ]\n\t// ```\n\t// generates a reducer for state tree with shape:\n\t// ```\n\t// {\n\t// taxonomy: {\n\t// category,\n\t// post_tag,\n\t// },\n\t// postType: {\n\t// post,\n\t// page,\n\t// },\n\t// }\n\t// ```\n\tlet entitiesDataReducer = state.reducer;\n\tif ( ! entitiesDataReducer || newConfig !== state.config ) {\n\t\tconst entitiesByKind = newConfig.reduce( ( acc, record ) => {\n\t\t\tconst { kind } = record;\n\t\t\tif ( ! acc[ kind ] ) {\n\t\t\t\tacc[ kind ] = [];\n\t\t\t}\n\t\t\tacc[ kind ].push( record );\n\t\t\treturn acc;\n\t\t}, {} );\n\n\t\tentitiesDataReducer = combineReducers(\n\t\t\tObject.fromEntries(\n\t\t\t\tObject.entries( entitiesByKind ).map(\n\t\t\t\t\t( [ kind, subEntities ] ) => {\n\t\t\t\t\t\tconst kindReducer = combineReducers(\n\t\t\t\t\t\t\tObject.fromEntries(\n\t\t\t\t\t\t\t\tsubEntities.map( ( entityConfig ) => [\n\t\t\t\t\t\t\t\t\tentityConfig.name,\n\t\t\t\t\t\t\t\t\tentity( entityConfig ),\n\t\t\t\t\t\t\t\t] )\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn [ kind, kindReducer ];\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\tconst newData = entitiesDataReducer( state.records, action );\n\n\tif (\n\t\tnewData === state.records &&\n\t\tnewConfig === state.config &&\n\t\tentitiesDataReducer === state.reducer\n\t) {\n\t\treturn state;\n\t}\n\n\treturn {\n\t\treducer: entitiesDataReducer,\n\t\trecords: newData,\n\t\tconfig: newConfig,\n\t};\n};\n\n/**\n * @type {UndoManager}\n */\nexport function undoManager( state = createUndoManager() ) {\n\treturn state;\n}\n\nexport function editsReference( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'EDIT_ENTITY_RECORD':\n\t\tcase 'UNDO':\n\t\tcase 'REDO':\n\t\t\treturn {};\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing embed preview data.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function embedPreviews( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_EMBED_PREVIEW':\n\t\t\tconst { url, preview } = action;\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ url ]: preview,\n\t\t\t};\n\t}\n\treturn state;\n}\n\n/**\n * State which tracks whether the user can perform an action on a REST\n * resource.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function userPermissions( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_USER_PERMISSION':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.key ]: action.isAllowed,\n\t\t\t};\n\t\tcase 'RECEIVE_USER_PERMISSIONS':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t...action.permissions,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer returning autosaves keyed by their parent's post id.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function autosaves( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_AUTOSAVES':\n\t\t\tconst { postId, autosaves: autosavesData } = action;\n\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ postId ]: autosavesData,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\nexport function blockPatterns( state = [], action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_BLOCK_PATTERNS':\n\t\t\treturn action.patterns;\n\t}\n\n\treturn state;\n}\n\nexport function blockPatternCategories( state = [], action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_BLOCK_PATTERN_CATEGORIES':\n\t\t\treturn action.categories;\n\t}\n\n\treturn state;\n}\n\nexport function userPatternCategories( state = [], action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_USER_PATTERN_CATEGORIES':\n\t\t\treturn action.patternCategories;\n\t}\n\treturn state;\n}\n\nexport function navigationFallbackId( state = null, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_NAVIGATION_FALLBACK_ID':\n\t\t\treturn action.fallbackId;\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the theme global styles revisions.\n *\n * @param {Record<string, object>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, object>} Updated state.\n */\nexport function themeGlobalStyleRevisions( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.currentId ]: action.revisions,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer managing the template lookup per query.\n *\n * @param {Record<string, string>} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Record<string, string>} Updated state.\n */\nexport function defaultTemplates( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_DEFAULT_TEMPLATE':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ JSON.stringify( action.query ) ]: action.templateId,\n\t\t\t};\n\t}\n\n\treturn state;\n}\n\n/**\n * Reducer returning an object of registered post meta.\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function registeredPostMeta( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_REGISTERED_POST_META':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ action.postType ]: action.registeredPostMeta,\n\t\t\t};\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing editor settings.\n *\n * @param {Object} state Current state.\n * @param {Object} action Action object.\n *\n * @return {Object} Updated state.\n */\nexport function editorSettings( state = null, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_EDITOR_SETTINGS':\n\t\t\treturn action.settings;\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing editor assets.\n *\n * @param {Object} state Current state.\n * @param {Object} action Action object.\n *\n * @return {Object} Updated state.\n */\nexport function editorAssets( state = null, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'RECEIVE_EDITOR_ASSETS':\n\t\t\treturn action.assets;\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing sync connection states for entities.\n * Keyed by \"kind/name:id\" (e.g., \"postType/post:123\").\n *\n * @param {Object} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {Object} Updated state.\n */\nexport function syncConnectionStatuses( state = {}, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'SET_SYNC_CONNECTION_STATUS': {\n\t\t\tconst key = `${ action.kind }/${ action.name }:${ action.key }`;\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\t[ key ]: action.status,\n\t\t\t};\n\t\t}\n\t\tcase 'CLEAR_SYNC_CONNECTION_STATUS': {\n\t\t\tconst key = `${ action.kind }/${ action.name }:${ action.key }`;\n\t\t\tconst { [ key ]: _, ...rest } = state;\n\t\t\treturn rest;\n\t\t}\n\t}\n\treturn state;\n}\n\n/**\n * Reducer managing whether collaboration is supported.\n *\n * Default to true, as collaboration is supported by default\n * unless explicitly disabled due to unsupported conditions\n * such as metaboxes.\n *\n * @param {boolean} state Current state.\n * @param {Object} action Dispatched action.\n *\n * @return {boolean} Updated state.\n */\nexport function collaborationSupported( state = true, action ) {\n\tswitch ( action.type ) {\n\t\tcase 'SET_COLLABORATION_SUPPORTED':\n\t\t\treturn action.supported;\n\n\t\tcase 'SET_SYNC_CONNECTION_STATUS':\n\t\t\tif (\n\t\t\t\tConnectionErrorCode.DOCUMENT_SIZE_LIMIT_EXCEEDED ===\n\t\t\t\taction.status?.error?.code\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn state;\n\t}\n\treturn state;\n}\n\nexport default combineReducers( {\n\tusers,\n\tcurrentTheme,\n\tcurrentGlobalStylesId,\n\tcurrentUser,\n\tthemeGlobalStyleVariations,\n\tthemeBaseGlobalStyles,\n\tthemeGlobalStyleRevisions,\n\tentities,\n\teditsReference,\n\tundoManager,\n\tembedPreviews,\n\tuserPermissions,\n\tautosaves,\n\tblockPatterns,\n\tblockPatternCategories,\n\tuserPatternCategories,\n\tnavigationFallbackId,\n\tdefaultTemplates,\n\tregisteredPostMeta,\n\teditorSettings,\n\teditorAssets,\n\tsyncConnectionStatuses,\n\tcollaborationSupported,\n} );\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["nextEdits"]
|
|
7
7
|
}
|
package/build-module/sync.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from "@wordpress/sync";
|
|
5
5
|
import { unlock } from "./lock-unlock.mjs";
|
|
6
6
|
var {
|
|
7
|
+
ConnectionErrorCode,
|
|
7
8
|
createSyncManager,
|
|
8
9
|
Delta,
|
|
9
10
|
CRDT_DOC_META_PERSISTENCE_KEY,
|
|
@@ -23,6 +24,7 @@ function getSyncManager() {
|
|
|
23
24
|
export {
|
|
24
25
|
CRDT_DOC_META_PERSISTENCE_KEY,
|
|
25
26
|
CRDT_RECORD_MAP_KEY,
|
|
27
|
+
ConnectionErrorCode,
|
|
26
28
|
Delta,
|
|
27
29
|
LOCAL_EDITOR_ORIGIN,
|
|
28
30
|
LOCAL_UNDO_IGNORED_ORIGIN,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/sync.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tprivateApis as syncPrivateApis,\n\ttype SyncManager,\n} from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport { unlock } from './lock-unlock';\n\nconst {\n\tcreateSyncManager,\n\tDelta,\n\tCRDT_DOC_META_PERSISTENCE_KEY,\n\tCRDT_RECORD_MAP_KEY,\n\tLOCAL_EDITOR_ORIGIN,\n\tLOCAL_UNDO_IGNORED_ORIGIN,\n\tretrySyncConnection,\n} = unlock( syncPrivateApis );\n\nexport {\n\tDelta,\n\tCRDT_DOC_META_PERSISTENCE_KEY,\n\tCRDT_RECORD_MAP_KEY,\n\tLOCAL_EDITOR_ORIGIN,\n\tLOCAL_UNDO_IGNORED_ORIGIN,\n\tretrySyncConnection,\n};\n\nlet syncManager: SyncManager;\n\nexport function getSyncManager(): SyncManager | undefined {\n\tif ( syncManager ) {\n\t\treturn syncManager;\n\t}\n\n\tsyncManager = createSyncManager();\n\n\treturn syncManager;\n}\n"],
|
|
5
|
-
"mappings": ";AAGA;AAAA,EACC,eAAe;AAAA,OAET;AAKP,SAAS,cAAc;AAEvB,IAAM;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,IAAI,OAAQ,eAAgB;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tprivateApis as syncPrivateApis,\n\ttype SyncManager,\n} from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport { unlock } from './lock-unlock';\n\nconst {\n\tConnectionErrorCode,\n\tcreateSyncManager,\n\tDelta,\n\tCRDT_DOC_META_PERSISTENCE_KEY,\n\tCRDT_RECORD_MAP_KEY,\n\tLOCAL_EDITOR_ORIGIN,\n\tLOCAL_UNDO_IGNORED_ORIGIN,\n\tretrySyncConnection,\n} = unlock( syncPrivateApis );\n\nexport {\n\tConnectionErrorCode,\n\tDelta,\n\tCRDT_DOC_META_PERSISTENCE_KEY,\n\tCRDT_RECORD_MAP_KEY,\n\tLOCAL_EDITOR_ORIGIN,\n\tLOCAL_UNDO_IGNORED_ORIGIN,\n\tretrySyncConnection,\n};\n\nlet syncManager: SyncManager;\n\nexport function getSyncManager(): SyncManager | undefined {\n\tif ( syncManager ) {\n\t\treturn syncManager;\n\t}\n\n\tsyncManager = createSyncManager();\n\n\treturn syncManager;\n}\n"],
|
|
5
|
+
"mappings": ";AAGA;AAAA,EACC,eAAe;AAAA,OAET;AAKP,SAAS,cAAc;AAEvB,IAAM;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,IAAI,OAAQ,eAAgB;AAY5B,IAAI;AAEG,SAAS,iBAA0C;AACzD,MAAK,aAAc;AAClB,WAAO;AAAA,EACR;AAEA,gBAAc,kBAAkB;AAEhC,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/types.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport type { Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport type { SelectionType } from './utils/crdt-user-selections';\n\nexport interface AnyFunction {\n\t( ...args: any[] ): any;\n}\n\n/**\n * An index path from the root of the block tree to a specific block.\n *\n * For example, `[0, 1]` refers to `blocks[0].innerBlocks[1]`.\n *\n * These paths are \"absolute\" in that they start from the post content root\n * (not from the template root when \"Show Template\" mode is active).\n * Both the Yjs document and the block-editor store share the same tree\n * structure for post content blocks, so the same path can be used to\n * navigate either tree.\n */\nexport type AbsoluteBlockIndexPath = number[];\n\n/**\n * Avoid a circular dependency with @wordpress/editor\n *\n * Additionaly, this type marks `attributeKey` and `offset` as possibly\n * `undefined`, which can happen in two known scenarios:\n *\n * 1. If a user has an entire block highlighted (e.g., a `core/image` block).\n * 2. If there's an intermediate selection state while inserting a block, those\n * properties will be temporarily`undefined`.\n */\nexport interface WPBlockSelection {\n\tclientId: string;\n\tattributeKey?: string;\n\toffset?: number;\n}\n\nexport interface WPSelection {\n\tselectionEnd: WPBlockSelection;\n\tselectionStart: WPBlockSelection;\n\tinitialPosition?: number | null;\n}\n\n/**\n * The position of the cursor.\n */\nexport type CursorPosition = {\n\trelativePosition: Y.RelativePosition;\n\n\t// Also store the absolute offset index of the cursor from the perspective\n\t// of the user who is updating the selection.\n\t//\n\t// Do not use this value directly, instead use `createAbsolutePositionFromRelativePosition()`\n\t// on relativePosition for the most up-to-date positioning.\n\t//\n\t// This is used because local Y.Text changes (e.g. adding or deleting a character)\n\t// can result in the same relative position if it is pinned to an unchanged\n\t// character. With both of these values as editor state, a change in perceived\n\t// position will always result in a redraw.\n\tabsoluteOffset: number;\n};\n\n/**\n * The direction of a text selection, indicating where the caret sits.\n */\nexport enum SelectionDirection {\n\t/** The caret is at the end of the selection (default / left-to-right). */\n\tForward = 'f',\n\t/** The caret is at the start of the selection (right-to-left). */\n\tBackward = 'b',\n}\n\nexport type SelectionNone = {\n\t// The user has not made a selection.\n\ttype: SelectionType.None;\n};\n\nexport type SelectionCursor = {\n\t// The user has a cursor position in a block with no text highlighted.\n\t// The block is derived on the receiver side by navigating up from the\n\t// resolved cursorPosition via Y.AbstractType.parent.\n\ttype: SelectionType.Cursor;\n\tcursorPosition: CursorPosition;\n};\n\nexport type SelectionInOneBlock = {\n\t// The user has highlighted text in a single block.\n\t// The block is derived on the receiver side by navigating up from the\n\t// resolved cursorStartPosition via Y.AbstractType.parent.\n\ttype: SelectionType.SelectionInOneBlock;\n\tcursorStartPosition: CursorPosition;\n\tcursorEndPosition: CursorPosition;\n\t// The direction of the selection, indicating where the caret sits.\n\tselectionDirection?: SelectionDirection;\n};\n\nexport type SelectionInMultipleBlocks = {\n\t// The user has highlighted text over multiple blocks.\n\t// The blocks are derived on the receiver side by navigating up from the\n\t// resolved cursor positions via Y.AbstractType.parent.\n\ttype: SelectionType.SelectionInMultipleBlocks;\n\tcursorStartPosition: CursorPosition;\n\tcursorEndPosition: CursorPosition;\n\t// The direction of the selection, indicating where the caret sits.\n\tselectionDirection?: SelectionDirection;\n};\n\nexport type SelectionWholeBlock = {\n\t// The user has a non-text block selected, like an image block.\n\t// Uses a Y.RelativePosition pointing to the block in its parent Y.Array,\n\t// since there is no text cursor to navigate up from.\n\ttype: SelectionType.WholeBlock;\n\tblockPosition: Y.RelativePosition;\n};\n\nexport type SelectionState =\n\t| SelectionNone\n\t| SelectionCursor\n\t| SelectionInOneBlock\n\t| SelectionInMultipleBlocks\n\t| SelectionWholeBlock;\n\nexport interface ResolvedSelection {\n\
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport type { ConnectionStatusDisconnected, Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport type { SelectionType } from './utils/crdt-user-selections';\n\nexport type { ConnectionStatus } from '@wordpress/sync';\n\nexport type ConnectionError = NonNullable<\n\tConnectionStatusDisconnected[ 'error' ]\n>;\n\nexport interface AnyFunction {\n\t( ...args: any[] ): any;\n}\n\n/**\n * An index path from the root of the block tree to a specific block.\n *\n * For example, `[0, 1]` refers to `blocks[0].innerBlocks[1]`.\n *\n * These paths are \"absolute\" in that they start from the post content root\n * (not from the template root when \"Show Template\" mode is active).\n * Both the Yjs document and the block-editor store share the same tree\n * structure for post content blocks, so the same path can be used to\n * navigate either tree.\n */\nexport type AbsoluteBlockIndexPath = number[];\n\n/**\n * Avoid a circular dependency with @wordpress/editor\n *\n * Additionaly, this type marks `attributeKey` and `offset` as possibly\n * `undefined`, which can happen in two known scenarios:\n *\n * 1. If a user has an entire block highlighted (e.g., a `core/image` block).\n * 2. If there's an intermediate selection state while inserting a block, those\n * properties will be temporarily`undefined`.\n */\nexport interface WPBlockSelection {\n\tclientId: string;\n\tattributeKey?: string;\n\toffset?: number;\n}\n\nexport interface WPSelection {\n\tselectionEnd: WPBlockSelection;\n\tselectionStart: WPBlockSelection;\n\tinitialPosition?: number | null;\n}\n\n/**\n * The position of the cursor.\n */\nexport type CursorPosition = {\n\trelativePosition: Y.RelativePosition;\n\n\t// Also store the absolute offset index of the cursor from the perspective\n\t// of the user who is updating the selection.\n\t//\n\t// Do not use this value directly, instead use `createAbsolutePositionFromRelativePosition()`\n\t// on relativePosition for the most up-to-date positioning.\n\t//\n\t// This is used because local Y.Text changes (e.g. adding or deleting a character)\n\t// can result in the same relative position if it is pinned to an unchanged\n\t// character. With both of these values as editor state, a change in perceived\n\t// position will always result in a redraw.\n\tabsoluteOffset: number;\n};\n\n/**\n * The direction of a text selection, indicating where the caret sits.\n */\nexport enum SelectionDirection {\n\t/** The caret is at the end of the selection (default / left-to-right). */\n\tForward = 'f',\n\t/** The caret is at the start of the selection (right-to-left). */\n\tBackward = 'b',\n}\n\nexport type SelectionNone = {\n\t// The user has not made a selection.\n\ttype: SelectionType.None;\n};\n\nexport type SelectionCursor = {\n\t// The user has a cursor position in a block with no text highlighted.\n\t// The block is derived on the receiver side by navigating up from the\n\t// resolved cursorPosition via Y.AbstractType.parent.\n\ttype: SelectionType.Cursor;\n\tcursorPosition: CursorPosition;\n};\n\nexport type SelectionInOneBlock = {\n\t// The user has highlighted text in a single block.\n\t// The block is derived on the receiver side by navigating up from the\n\t// resolved cursorStartPosition via Y.AbstractType.parent.\n\ttype: SelectionType.SelectionInOneBlock;\n\tcursorStartPosition: CursorPosition;\n\tcursorEndPosition: CursorPosition;\n\t// The direction of the selection, indicating where the caret sits.\n\tselectionDirection?: SelectionDirection;\n};\n\nexport type SelectionInMultipleBlocks = {\n\t// The user has highlighted text over multiple blocks.\n\t// The blocks are derived on the receiver side by navigating up from the\n\t// resolved cursor positions via Y.AbstractType.parent.\n\ttype: SelectionType.SelectionInMultipleBlocks;\n\tcursorStartPosition: CursorPosition;\n\tcursorEndPosition: CursorPosition;\n\t// The direction of the selection, indicating where the caret sits.\n\tselectionDirection?: SelectionDirection;\n};\n\nexport type SelectionWholeBlock = {\n\t// The user has a non-text block selected, like an image block.\n\t// Uses a Y.RelativePosition pointing to the block in its parent Y.Array,\n\t// since there is no text cursor to navigate up from.\n\ttype: SelectionType.WholeBlock;\n\tblockPosition: Y.RelativePosition;\n};\n\nexport type SelectionState =\n\t| SelectionNone\n\t| SelectionCursor\n\t| SelectionInOneBlock\n\t| SelectionInMultipleBlocks\n\t| SelectionWholeBlock;\n\nexport interface ResolvedSelection {\n\trichTextOffset: number | null;\n\tlocalClientId: string | null;\n}\n"],
|
|
5
|
+
"mappings": ";AA6EO,IAAK,qBAAL,kBAAKA,wBAAL;AAEN,EAAAA,oBAAA,aAAU;AAEV,EAAAA,oBAAA,cAAW;AAJA,SAAAA;AAAA,GAAA;",
|
|
6
6
|
"names": ["SelectionDirection"]
|
|
7
7
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// packages/core-data/src/utils/block-selection-history.ts
|
|
2
2
|
import { Y } from "@wordpress/sync";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
findBlockByClientIdInDoc,
|
|
5
|
+
richTextOffsetToHtmlIndex
|
|
6
|
+
} from "./crdt-utils.mjs";
|
|
4
7
|
var SELECTION_HISTORY_DEFAULT_SIZE = 5;
|
|
5
8
|
var YSelectionType = /* @__PURE__ */ ((YSelectionType2) => {
|
|
6
9
|
YSelectionType2["RelativeSelection"] = "RelativeSelection";
|
|
@@ -58,7 +61,7 @@ function convertWPBlockSelectionToSelection(selection, ydoc) {
|
|
|
58
61
|
const offset = selection.offset ?? 0;
|
|
59
62
|
const relativePosition = Y.createRelativePositionFromTypeIndex(
|
|
60
63
|
changedYText,
|
|
61
|
-
offset
|
|
64
|
+
richTextOffsetToHtmlIndex(changedYText.toString(), offset)
|
|
62
65
|
);
|
|
63
66
|
return {
|
|
64
67
|
type: "RelativeSelection" /* RelativeSelection */,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/block-selection-history.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\n/**\n * WordPress dependencies\n */\nimport { Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport {
|
|
5
|
-
"mappings": ";AAMA,SAAS,SAAS;AAKlB,
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\n/**\n * WordPress dependencies\n */\nimport { Y } from '@wordpress/sync';\n\n/**\n * Internal dependencies\n */\nimport {\n\tfindBlockByClientIdInDoc,\n\trichTextOffsetToHtmlIndex,\n} from './crdt-utils';\nimport type { WPBlockSelection, WPSelection } from '../types';\n\n// Default size for selection history (not including current selection)\nconst SELECTION_HISTORY_DEFAULT_SIZE = 5;\n\nexport enum YSelectionType {\n\tRelativeSelection = 'RelativeSelection',\n\tBlockSelection = 'BlockSelection',\n}\n\nexport interface YRelativeSelection {\n\ttype: YSelectionType.RelativeSelection;\n\tattributeKey: string;\n\trelativePosition: Y.RelativePosition;\n\tclientId: string;\n\toffset: number;\n}\n\nexport interface YBlockSelection {\n\ttype: YSelectionType.BlockSelection;\n\tclientId: string;\n}\n\nexport type YSelection = YRelativeSelection | YBlockSelection;\n\nexport type YFullSelection = {\n\tstart: YSelection;\n\tend: YSelection;\n};\n\nexport interface YSelectionHistory {\n\tselection: YFullSelection;\n\tbackupSelections?: YFullSelection[];\n}\n\nexport interface BlockSelectionHistory {\n\tgetSelectionHistory: () => YFullSelection[];\n\tupdateSelection: ( newSelection: WPSelection ) => void;\n}\n\n/**\n * This function is used to track recent block selections to help in restoring\n * a user's selection after an undo or redo operation.\n *\n * Maintains a history array for previous selections, which can be used for\n * backup restoration locations.\n * @param ydoc\n * @param historySize\n */\nexport function createBlockSelectionHistory(\n\tydoc: Y.Doc,\n\thistorySize: number = SELECTION_HISTORY_DEFAULT_SIZE\n): BlockSelectionHistory {\n\tlet history: YFullSelection[] = [];\n\n\t/**\n\t * Get the block history including current selection.\n\t */\n\tconst getSelectionHistory = (): YFullSelection[] => {\n\t\treturn history.slice( 0 );\n\t};\n\n\t/**\n\t * Update the selection history with a new selection.\n\t * @param newSelection\n\t */\n\tconst updateSelection = ( newSelection: WPSelection ): void => {\n\t\tif (\n\t\t\t! newSelection?.selectionStart?.clientId ||\n\t\t\t! newSelection?.selectionEnd?.clientId\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { selectionStart, selectionEnd } = newSelection;\n\t\tconst start = convertWPBlockSelectionToSelection(\n\t\t\tselectionStart,\n\t\t\tydoc\n\t\t);\n\t\tconst end = convertWPBlockSelectionToSelection( selectionEnd, ydoc );\n\n\t\taddToHistory( { start, end } );\n\t};\n\n\t/**\n\t * Add a selection to the history, maintaining only the last `historySize` unique selections.\n\t * New selections are added to the front.\n\t * Removes any existing entries with the same start and end block combination.\n\t * @param yFullSelection\n\t */\n\tconst addToHistory = ( yFullSelection: YFullSelection ): void => {\n\t\t// Remove any existing entries with the same start and end block combination\n\t\tconst startClientId = yFullSelection.start.clientId;\n\t\tconst endClientId = yFullSelection.end.clientId;\n\n\t\thistory = history.filter( ( entry ) => {\n\t\t\tconst isSameBlockCombination =\n\t\t\t\tentry.start.clientId === startClientId &&\n\t\t\t\tentry.end.clientId === endClientId;\n\n\t\t\treturn ! isSameBlockCombination;\n\t\t} );\n\n\t\t// Add the new selection to the front\n\t\thistory.unshift( yFullSelection );\n\n\t\t// Trim to max size (remove oldest entries from the back)\n\t\tif ( history.length > historySize + 1 ) {\n\t\t\thistory = history.slice( 0, historySize + 1 );\n\t\t}\n\t};\n\n\treturn {\n\t\tgetSelectionHistory,\n\t\tupdateSelection,\n\t};\n}\n\n/**\n * Convert a WPBlockSelection to a YSelection.\n * @param selection\n * @param ydoc\n * @return A YSelection object.\n */\nfunction convertWPBlockSelectionToSelection(\n\tselection: WPBlockSelection,\n\tydoc: Y.Doc\n): YSelection {\n\tconst clientId = selection.clientId;\n\tconst block = findBlockByClientIdInDoc( clientId, ydoc );\n\tconst attributes = block?.get( 'attributes' );\n\tconst attributeKey = selection.attributeKey;\n\n\tconst changedYText = attributeKey\n\t\t? attributes?.get( attributeKey )\n\t\t: undefined;\n\n\tconst isYText = changedYText instanceof Y.Text;\n\tconst isFullyDefinedSelection = attributeKey && clientId;\n\n\tif ( ! isYText || ! isFullyDefinedSelection ) {\n\t\t// We either don't have a valid YText (it's been deleted) or we've\n\t\t// been passed a selection that's just a block clientId.\n\t\t// Store as BlockSelection.\n\t\treturn {\n\t\t\ttype: YSelectionType.BlockSelection,\n\t\t\tclientId,\n\t\t};\n\t}\n\n\tconst offset = selection.offset ?? 0;\n\tconst relativePosition = Y.createRelativePositionFromTypeIndex(\n\t\tchangedYText,\n\t\trichTextOffsetToHtmlIndex( changedYText.toString(), offset )\n\t);\n\n\treturn {\n\t\ttype: YSelectionType.RelativeSelection,\n\t\tattributeKey,\n\t\trelativePosition,\n\t\tclientId,\n\t\toffset,\n\t};\n}\n"],
|
|
5
|
+
"mappings": ";AAMA,SAAS,SAAS;AAKlB;AAAA,EACC;AAAA,EACA;AAAA,OACM;AAIP,IAAM,iCAAiC;AAEhC,IAAK,iBAAL,kBAAKA,oBAAL;AACN,EAAAA,gBAAA,uBAAoB;AACpB,EAAAA,gBAAA,oBAAiB;AAFN,SAAAA;AAAA,GAAA;AA4CL,SAAS,4BACf,MACA,cAAsB,gCACE;AACxB,MAAI,UAA4B,CAAC;AAKjC,QAAM,sBAAsB,MAAwB;AACnD,WAAO,QAAQ,MAAO,CAAE;AAAA,EACzB;AAMA,QAAM,kBAAkB,CAAE,iBAAqC;AAC9D,QACC,CAAE,cAAc,gBAAgB,YAChC,CAAE,cAAc,cAAc,UAC7B;AACD;AAAA,IACD;AAEA,UAAM,EAAE,gBAAgB,aAAa,IAAI;AACzC,UAAM,QAAQ;AAAA,MACb;AAAA,MACA;AAAA,IACD;AACA,UAAM,MAAM,mCAAoC,cAAc,IAAK;AAEnE,iBAAc,EAAE,OAAO,IAAI,CAAE;AAAA,EAC9B;AAQA,QAAM,eAAe,CAAE,mBAA0C;AAEhE,UAAM,gBAAgB,eAAe,MAAM;AAC3C,UAAM,cAAc,eAAe,IAAI;AAEvC,cAAU,QAAQ,OAAQ,CAAE,UAAW;AACtC,YAAM,yBACL,MAAM,MAAM,aAAa,iBACzB,MAAM,IAAI,aAAa;AAExB,aAAO,CAAE;AAAA,IACV,CAAE;AAGF,YAAQ,QAAS,cAAe;AAGhC,QAAK,QAAQ,SAAS,cAAc,GAAI;AACvC,gBAAU,QAAQ,MAAO,GAAG,cAAc,CAAE;AAAA,IAC7C;AAAA,EACD;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,EACD;AACD;AAQA,SAAS,mCACR,WACA,MACa;AACb,QAAM,WAAW,UAAU;AAC3B,QAAM,QAAQ,yBAA0B,UAAU,IAAK;AACvD,QAAM,aAAa,OAAO,IAAK,YAAa;AAC5C,QAAM,eAAe,UAAU;AAE/B,QAAM,eAAe,eAClB,YAAY,IAAK,YAAa,IAC9B;AAEH,QAAM,UAAU,wBAAwB,EAAE;AAC1C,QAAM,0BAA0B,gBAAgB;AAEhD,MAAK,CAAE,WAAW,CAAE,yBAA0B;AAI7C,WAAO;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACD;AAAA,EACD;AAEA,QAAM,SAAS,UAAU,UAAU;AACnC,QAAM,mBAAmB,EAAE;AAAA,IAC1B;AAAA,IACA,0BAA2B,aAAa,SAAS,GAAG,MAAO;AAAA,EAC5D;AAEA,SAAO;AAAA,IACN,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;",
|
|
6
6
|
"names": ["YSelectionType"]
|
|
7
7
|
}
|
|
@@ -7,6 +7,22 @@ import { Y } from "@wordpress/sync";
|
|
|
7
7
|
import { createYMap } from "./crdt-utils.mjs";
|
|
8
8
|
import { Delta } from "../sync.mjs";
|
|
9
9
|
var serializableBlocksCache = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
function serializeAttributeValue(value) {
|
|
11
|
+
if (value instanceof RichTextData) {
|
|
12
|
+
return value.valueOf();
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return value.map(serializeAttributeValue);
|
|
16
|
+
}
|
|
17
|
+
if (value && typeof value === "object") {
|
|
18
|
+
const result = {};
|
|
19
|
+
for (const [k, v] of Object.entries(value)) {
|
|
20
|
+
result[k] = serializeAttributeValue(v);
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
10
26
|
function makeBlockAttributesSerializable(blockName, attributes) {
|
|
11
27
|
const newAttributes = { ...attributes };
|
|
12
28
|
for (const [key, value] of Object.entries(attributes)) {
|
|
@@ -14,9 +30,7 @@ function makeBlockAttributesSerializable(blockName, attributes) {
|
|
|
14
30
|
delete newAttributes[key];
|
|
15
31
|
continue;
|
|
16
32
|
}
|
|
17
|
-
|
|
18
|
-
newAttributes[key] = value.valueOf();
|
|
19
|
-
}
|
|
33
|
+
newAttributes[key] = serializeAttributeValue(value);
|
|
20
34
|
}
|
|
21
35
|
return newAttributes;
|
|
22
36
|
}
|