diff --git a/packages/canvas-panel/src/components/AtlasCanvas/AtlasCanvas.tsx b/packages/canvas-panel/src/components/AtlasCanvas/AtlasCanvas.tsx index a383c37..13cb403 100644 --- a/packages/canvas-panel/src/components/AtlasCanvas/AtlasCanvas.tsx +++ b/packages/canvas-panel/src/components/AtlasCanvas/AtlasCanvas.tsx @@ -1,6 +1,8 @@ import React, { FC, useEffect, useLayoutEffect, useMemo } from 'preact/compat'; import { useCanvas, + useResources, + parseSpecificResource, useResourceEvents, useRenderingStrategy, useThumbnail, @@ -9,7 +11,7 @@ import { useAnnotationPageManager, useManifest, } from 'react-iiif-vault'; -import { createStylesHelper } from '@iiif/vault-helpers'; +import { createStylesHelper, SingleChoice, createPaintingAnnotationsHelper } from '@iiif/vault-helpers'; import { Fragment, h } from 'preact'; import { WorldObject, SingleImage } from '../../atlas-components'; import { RenderAnnotationPage } from '../RenderAnnotationPage/RenderAnnotationPage'; @@ -24,6 +26,7 @@ import { RenderVideo } from '../RenderVideo/RenderVideo'; import { RenderTextLines } from '../RenderTextLines/RenderTextLines'; import { sortAnnotationPages } from '../../helpers/sort-annotation-pages'; import { choiceEventChannel } from '../../helpers/eventbus'; +import { AnnotationPageNormalized, ContentResource } from '@iiif/presentation-3'; interface AtlasCanvasProps { x?: number; @@ -70,7 +73,7 @@ export function AtlasCanvas({ strategies: ['images', 'media'], defaultChoices: defaultChoices?.map(({ id }) => id), }); - const choice = strategy.type === 'images' ? strategy.choice : undefined; + const manager = useAnnotationPageManager(manifest?.id || canvas?.id); const fullPages = useVaultSelector( (state, vault) => { @@ -78,6 +81,65 @@ export function AtlasCanvas({ }, [...manager.availablePageIds] ); + + useEffect(() => { + // this is all hoisted from https://github.com/IIIF-Commons/iiif-helpers/blob/0f582fbcf4a8899258b7a71d2216ffeb56275de4/src/painting-annotations/helper.ts#L38 + // BUT... it doesn't work there because it assumes there's a single choice per page + const vaulthelper = createPaintingAnnotationsHelper(vault); + // get all painting annotations for a canvas + if (canvas?.id) { + const enabledChoices = defaultChoices?.map(({ id }) => id) || []; + const vaultAnnotations = vaulthelper.getAllPaintingAnnotations(canvas.id); + // Extract choices (if any) from a canvas + + for (const annotation of vaultAnnotations) { + if (annotation.type !== 'Annotation') { + throw new Error(`getPaintables() accept either a canvas or list of annotations`); + } + + const references = Array.from(Array.isArray(annotation.body) ? annotation.body : [annotation.body]); + for (const reference of references) { + const [ref, { selector }] = parseSpecificResource(reference as any); + const body = vault.get(ref) as any; + const type = (body.type || 'unknown').toLowerCase(); + // Choice + if (type !== 'choice') { + continue; + } + const nestedBodies = vault.get(body.items) as ContentResource[]; + + // if the enabledChoices has the id, then turn it on, otherwise choose the 1st item + const selected = enabledChoices.length + ? enabledChoices.map((cid) => nestedBodies.find((b) => b.id === cid)).filter(Boolean) + : [nestedBodies[0]]; + + if (selected.length === 0) { + selected.push(nestedBodies[0]); + } + const choice: SingleChoice = { + type: 'single-choice', + items: nestedBodies.map((b) => ({ + id: b.id, + label: (b as any).label as any, + selected: selected.indexOf(b) !== -1, + })) as any[], + label: (ref as any).label, + }; + choiceEventChannel.emit('onChoiceChange', { + choice, + partOf: { + canvasId: canvas.id, + choiceId: body.id, + manifestId: manifest?.id, + }, + }); + } + } + // this returns 1 choice + const choices = vaulthelper.extractChoices(canvas.id); + } + }, [canvas?.id, actions, defaultChoices]); + const pageTypes = useMemo(() => sortAnnotationPages(manager.availablePageIds, vault as any), fullPages); const hasTextLines = !!pageTypes.pageMapping.supplementing?.length; const firstTextLines = hasTextLines ? pageTypes.pageMapping.supplementing[0] : null; @@ -114,10 +176,6 @@ export function AtlasCanvas({ } }, [defaultChoices]); - useLayoutEffect(() => { - choiceEventChannel.emit('onChoiceChange', { choice }); - }, [choice]); - const thumbnail = useThumbnail({ maxWidth: 256, maxHeight: 256 }); if (!canvas) { diff --git a/packages/canvas-panel/src/helpers/eventbus.ts b/packages/canvas-panel/src/helpers/eventbus.ts index 78e7905..ea67297 100644 --- a/packages/canvas-panel/src/helpers/eventbus.ts +++ b/packages/canvas-panel/src/helpers/eventbus.ts @@ -30,7 +30,14 @@ export const choiceEventChannel = eventbus<{ * @param payload - the id and options for the choice * */ - onChoiceChange: (payload: { choice?: ChoiceDescription }) => void; + onChoiceChange: (payload: { + choice?: ChoiceDescription; + partOf?: { + choiceId?: string; + canvasId?: string; + manifestId?: string; + }; + }) => void; /** * When a canvas is changed, or a sequence is changed, this signals that * the current set of choices should be reset diff --git a/packages/canvas-panel/src/hooks/use-generic-atlas-props.ts b/packages/canvas-panel/src/hooks/use-generic-atlas-props.ts index 034ef40..a45e4b0 100644 --- a/packages/canvas-panel/src/hooks/use-generic-atlas-props.ts +++ b/packages/canvas-panel/src/hooks/use-generic-atlas-props.ts @@ -155,7 +155,7 @@ export function useGenericAtlasProps>(props: GenericAtl seenChoices.current = {}; }); - const onChoiceChange = (payload: { choice?: ChoiceDescription }) => { + const onChoiceChange = (payload: { choice?: ChoiceDescription, partOf?: any }) => { const choice = payload.choice; // sort the choices by ID in order to help with de-duping if (webComponent?.current && choice && choice.items) { @@ -181,6 +181,7 @@ export function useGenericAtlasProps>(props: GenericAtl (seenChoices.current as any)[key] = value; // move this outside the IF if we want to fire on every page + (choice as any).partOf = payload.partOf; webComponent.current.dispatchEvent(new CustomEvent('choice', { detail: { choice } })); } }; diff --git a/packages/storybook/src/stories/sequence-panel.stories.tsx b/packages/storybook/src/stories/sequence-panel.stories.tsx index 658d409..b6c63d4 100644 --- a/packages/storybook/src/stories/sequence-panel.stories.tsx +++ b/packages/storybook/src/stories/sequence-panel.stories.tsx @@ -62,7 +62,7 @@ export const SequencePanel = () => { -const bayard="https://gist.githubusercontent.com/danieltbrennan/183d6cbb0948948413394cf116e5844a/raw/11fdda729f0c2960ee1d971902cdf0badd7f31df/bayard_w_choices.json" +const bayard="https://data.getty.edu/media/manifest/bayard-custom" export const MakingChoice = () => { const viewer = useRef() @@ -135,6 +135,7 @@ export const MakingChoice = () => {
+