react-iiif-vault 1.0.8 → 1.0.10
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/.build/types/canvas-panel/Viewer.d.ts +1 -1
- package/.build/types/canvas-panel/index.d.ts +2 -1
- package/.build/types/canvas-panel/render/Audio.d.ts +1 -1
- package/.build/types/canvas-panel/render/Canvas.d.ts +2 -2
- package/.build/types/canvas-panel/render/CanvasBackground.d.ts +1 -1
- package/.build/types/canvas-panel/render/DefaultCanvasFallback.d.ts +1 -1
- package/.build/types/canvas-panel/render/Image.d.ts +1 -1
- package/.build/types/canvas-panel/render/Model.d.ts +1 -1
- package/.build/types/canvas-panel/render/Video.d.ts +1 -1
- package/.build/types/canvas-panel/render/VideoYouTube.d.ts +1 -1
- package/.build/types/components/CanvasAnnotations.d.ts +10 -0
- package/.build/types/components/CombinedMetadata.d.ts +4 -0
- package/.build/types/components/Image.d.ts +15 -0
- package/.build/types/components/ManifestMetadata.d.ts +4 -0
- package/.build/types/components/Metadata.d.ts +39 -0
- package/.build/types/components/SequenceThumbnails.d.ts +29 -0
- package/.build/types/components/SingleCanvasThumbnail.d.ts +20 -0
- package/.build/types/context/AnnotationContext.d.ts +1 -1
- package/.build/types/context/AnnotationPageContext.d.ts +1 -1
- package/.build/types/context/CanvasContext.d.ts +1 -1
- package/.build/types/context/CollectionContext.d.ts +1 -1
- package/.build/types/context/ContextBridge.d.ts +1 -1
- package/.build/types/context/ManifestContext.d.ts +1 -1
- package/.build/types/context/MediaContext.d.ts +1 -1
- package/.build/types/context/RangeContext.d.ts +1 -1
- package/.build/types/context/ResourceContext.d.ts +2 -2
- package/.build/types/context/VaultContext.d.ts +1 -1
- package/.build/types/demo/media-controls.d.ts +1 -1
- package/.build/types/demo/viewer-controls.d.ts +1 -1
- package/.build/types/features/rendering-strategy/3d-strategy.d.ts +1 -1
- package/.build/types/features/rendering-strategy/image-strategy.d.ts +1 -1
- package/.build/types/features/rendering-strategy/resource-types.d.ts +7 -7
- package/.build/types/features/rendering-strategy/strategies.d.ts +5 -5
- package/.build/types/features/rendering-strategy/textual-content-strategy.d.ts +1 -1
- package/.build/types/hooks/useEventListener.d.ts +1 -1
- package/.build/types/hooks/useExistingVault.d.ts +2 -1
- package/.build/types/hooks/useExternalResource.d.ts +1 -1
- package/.build/types/hooks/useImage.d.ts +10 -0
- package/.build/types/hooks/useLoadImageService.d.ts +1 -1
- package/.build/types/hooks/useRenderingStrategy.d.ts +3 -3
- package/.build/types/hooks/useSimpleMediaPlayer.d.ts +2 -2
- package/.build/types/hooks/useVirtualAnnotationPageContext.d.ts +81 -81
- package/.build/types/index.d.ts +8 -0
- package/.build/types/utility/i18n-utils.d.ts +8 -6
- package/.build/types/viewers/SimpleViewerContext.d.ts +2 -2
- package/.build/types/viewers/SimpleViewerContext.hooks.d.ts +2 -0
- package/.build/types/viewers/SimpleViewerContext.types.d.ts +8 -4
- package/README.md +495 -177
- package/dist/bundle/cjs/index.js +7 -6
- package/dist/bundle/cjs/index.js.map +1 -1
- package/dist/bundle/esm/index.mjs +2391 -1186
- package/dist/bundle/esm/index.mjs.map +1 -1
- package/dist/canvas-panel/cjs/canvas-panel.js +5 -5
- package/dist/canvas-panel/cjs/canvas-panel.js.map +1 -1
- package/dist/canvas-panel/esm/canvas-panel.mjs +596 -547
- package/dist/canvas-panel/esm/canvas-panel.mjs.map +1 -1
- package/dist/index.umd.js +78 -76
- package/dist/index.umd.js.map +1 -1
- package/dist/react17/cjs/index.js +7 -6
- package/dist/react17/cjs/index.js.map +1 -1
- package/dist/react17/esm/index.mjs +2391 -1186
- package/dist/react17/esm/index.mjs.map +1 -1
- package/dist/utils/cjs/utils.js +1 -1
- package/dist/utils/cjs/utils.js.map +1 -1
- package/dist/utils/esm/utils.mjs +21 -21
- package/dist/utils/esm/utils.mjs.map +1 -1
- package/package.json +24 -22
package/README.md
CHANGED
|
@@ -1,213 +1,531 @@
|
|
|
1
|
-
# React
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
- useAnnotation
|
|
27
|
-
- useAnnotationPage
|
|
28
|
-
- useCanvas
|
|
29
|
-
- useCollection
|
|
30
|
-
- useDispatch
|
|
31
|
-
- useExternalAnnotationList
|
|
32
|
-
- useExternalCollection
|
|
33
|
-
- useExternalManifest
|
|
34
|
-
- useManifest
|
|
35
|
-
- useVault
|
|
36
|
-
- useVaultEffect
|
|
37
|
-
|
|
38
|
-
Create viewer abstractions
|
|
39
|
-
- SimpleViewerContext
|
|
40
|
-
- SingleCanvasContext
|
|
41
|
-
|
|
42
|
-
Canvas clock implementation
|
|
43
|
-
- useAnnotationsAtTime
|
|
44
|
-
- useCanvasClock
|
|
45
|
-
- useCanvasTimeline
|
|
46
|
-
|
|
47
|
-
Other helpers
|
|
48
|
-
- RangeContext
|
|
49
|
-
- usePaintingAnnotations
|
|
50
|
-
- useRange
|
|
51
|
-
- useSearchService
|
|
52
|
-
- useVirtualCanvas
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
### New hooks
|
|
56
|
-
|
|
57
|
-
#### useRenderingStrategy
|
|
58
|
-
There are many ways that a canvas can be rendered, some are easier than others. A hook
|
|
59
|
-
that breaks these down into easier to render chunks will make iteratively supporting
|
|
60
|
-
features easier.
|
|
61
|
-
|
|
62
|
-
This hook will return a type, some data and some actions. The types may be something like:
|
|
63
|
-
|
|
64
|
-
- Single image - A single image or image service.
|
|
65
|
-
- Composite image - A composition of more than one image or image service.
|
|
66
|
-
- Choice - A choice that needs to be given to the user (with functions to make choice)
|
|
67
|
-
- Audio - A single audio file, or sequential audio files
|
|
68
|
-
- Video - A single video file, or sequential video files
|
|
69
|
-
- Complex timeline - A composite of either multiple audio, video and composite images on a timeline.
|
|
70
|
-
|
|
71
|
-
This gives implementations a goal, and can easily let users know that they don't support
|
|
72
|
-
the given canvas without an error.
|
|
73
|
-
|
|
74
|
-
The data models returned from this strategy should be similar to each other. A single image
|
|
75
|
-
should have a way to load an image service, generate tiles or fixed sizes. Composite image
|
|
76
|
-
should be the same as single image but with multiple. A choice should be available from the
|
|
77
|
-
hook regardless of the type, to support a menu-like system for choices even after a choice
|
|
78
|
-
is made. Audio and video should use a similar interface with controls. Complex timeline should
|
|
79
|
-
be very similar to audio/video with the same controls but with additional structure similar
|
|
80
|
-
to composite image.
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
type UseRenderingStrategy = {
|
|
84
|
-
type: 'single-image' | 'composite-image' | 'audio' | 'video' | 'complex-timeline';
|
|
85
|
-
image: { type: 'fixed-size' } | { type: 'image-service' } | null;
|
|
86
|
-
images: [];
|
|
87
|
-
media: { type: 'audio' } | { type: 'video' } | { type: 'sequence' };
|
|
88
|
-
duration: number;
|
|
89
|
-
choice: {} | null;
|
|
1
|
+
# React IIIF Vault
|
|
2
|
+
This library is a fully featured IIIF Library for reading and displaying IIIF Manifests, Collections and Annotations.
|
|
3
|
+
|
|
4
|
+
It is built on `@iiif/helpers` ([Repository](https://github.com/IIIF-Commons/iiif-helpers)) and uses the IIIF Vault to
|
|
5
|
+
request, parse, upgrade and store IIIF. It also contains the React implementation of [Canvas Panel](https://github.com/digirati-co-uk/iiif-canvas-panel) which is built on [Atlas Viewer](https://github.com/atlas-viewer/atlas).
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
npm i react-iiif-vault
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
It is recommended to install the helpers too, and the TypeScript types for IIIF, if you are using TypeScript.
|
|
12
|
+
```
|
|
13
|
+
npm i @iiif/helpers @iiif/presentation-3
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Canvas Panel
|
|
17
|
+
|
|
18
|
+
The easiest way to get a simple headless and extensible viewer is to use the Canvas Panel component. You can
|
|
19
|
+
use it as a single component, or you can build your own Viewer from it's part, deciding which types of Content you want to support (images, video, audio, 3D, HTML etc.).
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { CanvasPanel } from 'react-iiif-vault';
|
|
23
|
+
|
|
24
|
+
function MyViewer() {
|
|
25
|
+
return <CanvasPanel manifest="https://digirati-co-uk.github.io/wunder.json" />
|
|
90
26
|
}
|
|
91
27
|
```
|
|
92
28
|
|
|
93
|
-
|
|
29
|
+
There are a lot of options you can pass to Canvas Panel to customise the way it renders IIIF and also
|
|
30
|
+
slots for inserting UI that will have access to the [Contexts](https://react.dev/learn/passing-data-deeply-with-context) provided by the library.
|
|
94
31
|
|
|
95
|
-
|
|
32
|
+

|
|
96
33
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
34
|
+
For example, you can use the `useSimpleViewer()` hook to gain access to controls for moving forward and back and
|
|
35
|
+
also the `useManifest` or other resource hooks to get access to the IIIF.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { CanvasPanel, useSimpleViewer, useManifest, LocaleString } from 'react-iiif-vault';
|
|
39
|
+
|
|
40
|
+
function MyViewer() {
|
|
41
|
+
return (
|
|
42
|
+
<CanvasPanel
|
|
43
|
+
header={<Label />}
|
|
44
|
+
manifest="https://digirati-co-uk.github.io/wunder.json"
|
|
45
|
+
>
|
|
46
|
+
<MyControls />
|
|
47
|
+
</CanvasPanel>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function MyControls() {
|
|
52
|
+
const { previousCanvas, nextCanvas } = useSimpleViewer();
|
|
53
|
+
return (
|
|
54
|
+
<div>
|
|
55
|
+
<button onClick={previousCanvas}>Prev</button>
|
|
56
|
+
<button onClick={nextCanvas}>Next</button>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function Label() {
|
|
62
|
+
const manifest = useManifest();
|
|
63
|
+
|
|
64
|
+
if (!manifest) {
|
|
65
|
+
return <div>Loading..</div>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<LocaleString as="h2" className="text-2xl my-3">
|
|
70
|
+
{manifest.label}
|
|
71
|
+
</LocaleString>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `useSimpleViewer()` hook returns the following:
|
|
77
|
+
```ts
|
|
78
|
+
type SimpleViewerContext = {
|
|
79
|
+
items: Reference<'Canvas'>[];
|
|
80
|
+
sequence: number[][];
|
|
81
|
+
hasNext: boolean;
|
|
82
|
+
hasPrevious: boolean;
|
|
83
|
+
setSequenceIndex: (newId: number) => void;
|
|
84
|
+
setCurrentCanvasId: (newId: string) => void;
|
|
85
|
+
setCurrentCanvasIndex: (newId: number) => void;
|
|
86
|
+
currentSequenceIndex: number;
|
|
87
|
+
nextCanvas: () => void;
|
|
88
|
+
previousCanvas: () => void;
|
|
136
89
|
};
|
|
90
|
+
```
|
|
137
91
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
92
|
+
For paged items, `sequence` will be a list of indices into `items`. For example:
|
|
93
|
+
```ts
|
|
94
|
+
const sequence = [
|
|
95
|
+
[0],
|
|
96
|
+
[1, 2],
|
|
97
|
+
[3, 4]
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const items = [
|
|
101
|
+
{/* front page */},
|
|
102
|
+
{/* page 1v */},
|
|
103
|
+
{/* page 1r */},
|
|
104
|
+
{/* page 2v */},
|
|
105
|
+
{/* page 2r */},
|
|
106
|
+
];
|
|
145
107
|
```
|
|
146
108
|
|
|
109
|
+
You can create a list of the sequence, grouped by "row" with a simple map:
|
|
110
|
+
```ts
|
|
111
|
+
const itemSequence = sequence.map(row => row.map(idx => items[idx]));
|
|
112
|
+
// [
|
|
113
|
+
// [ {/* front page */} ],
|
|
114
|
+
// [ {/* page 1v */}, {/* page 1r */} ]
|
|
115
|
+
// [ {/* page 2v */}, {/* page 2r */} ]
|
|
116
|
+
// ]
|
|
117
|
+
```
|
|
147
118
|
|
|
148
|
-
|
|
119
|
+
The sequence is pre-generated, so paging forward and back is as simple as going to the next index in the sequence.
|
|
120
|
+
The items returned will be all the IIIF Canvases that should be rendered.
|
|
149
121
|
|
|
150
|
-
|
|
122
|
+
For continuous Manifests (e.g. a long Scroll), there will only be one item in the sequence:
|
|
123
|
+
```ts
|
|
124
|
+
const sequence = [
|
|
125
|
+
[0, 1, 2, 3, 4 ...],
|
|
126
|
+
]
|
|
127
|
+
```
|
|
128
|
+
Indicating that all the canvases should be displayed in a single view.
|
|
151
129
|
|
|
152
|
-
|
|
130
|
+
You can disable paging by passing `pagingEnabled={false}` to `<CanvasPanel />`.
|
|
153
131
|
|
|
154
|
-
|
|
155
|
-
const manager = useEventManager();
|
|
132
|
+
You can grab the [React ref](https://react.dev/learn/referencing-values-with-refs) from the `<CanvasPanel />` component to control it from outside of the component.
|
|
156
133
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
134
|
+
Example:
|
|
135
|
+
```tsx
|
|
136
|
+
function MyViewer() {
|
|
137
|
+
const ref = useRef();
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
return <>
|
|
141
|
+
<CanvasPanel ref={ref} manifest={...} />
|
|
142
|
+
<div>
|
|
143
|
+
<button onClick={() => ref.current.previousCanvas()}>Prev</button>
|
|
144
|
+
<button onClick={() => ref.current.nextCanvas()}>Next</button>
|
|
145
|
+
</div>
|
|
146
|
+
</>;
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The ref is the same as what is returned from `useSimpleViewer()`.
|
|
151
|
+
|
|
152
|
+
## Simple Viewer Provider
|
|
153
|
+
|
|
154
|
+
One of the main components of this Library is the `<SimpleViewerProvider />`. This is a component you can
|
|
155
|
+
wrap around other IIIF components to load a IIIF Manifest and enable all the other hooks and components.
|
|
156
|
+
|
|
157
|
+
It takes the following properties:
|
|
158
|
+
```
|
|
159
|
+
manifest: string;
|
|
160
|
+
pagingEnabled?: boolean;
|
|
161
|
+
startCanvas?: string;
|
|
162
|
+
rangeId?: string;
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Example:
|
|
166
|
+
```tsx
|
|
167
|
+
import { SimpleViewerProvider, useManifest, LocaleString } from 'react-iiif-vault';
|
|
168
|
+
|
|
169
|
+
function MyViewer() {
|
|
170
|
+
return (
|
|
171
|
+
<SimpleViewerProvider manifest="https://digirati-co-uk.github.io/wunder.json">
|
|
172
|
+
<ManifestTitle />
|
|
173
|
+
</SimpleViewerProvider>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
function ManifestTitle() {
|
|
179
|
+
const manifest = useManifest();
|
|
180
|
+
|
|
181
|
+
return <LocaleString as="h1">{manifest.label}</LocaleString>
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
Will display:
|
|
185
|
+
|
|
186
|
+
> # Wunder der Vererbung / von Fritz Bolle.
|
|
164
187
|
|
|
165
|
-
|
|
166
|
-
|
|
188
|
+
Components inside this context can also use the `useSimpleViewer()` hook, similar to Canvas Panel.
|
|
189
|
+
|
|
190
|
+
## Vault provider
|
|
191
|
+
|
|
192
|
+
If you want to use the context manually, and not build a viewer specifically, you can wrap your application in a `VaultProvider`, passing a custom Vault instance if you want (This can be useful for server side rendering).
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
function MyApp() {
|
|
196
|
+
return (
|
|
197
|
+
<VaultProvider>
|
|
198
|
+
<App />
|
|
199
|
+
</VaultProvider>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
From anywhere in your app, you will be able to access the Vault using:
|
|
205
|
+
```ts
|
|
206
|
+
const vault = useVault();
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### Example NextJS hydration of IIIF Manifest
|
|
210
|
+
For server side rendering, you can pass IIIF resources into Vault. You will need a client component
|
|
211
|
+
that wraps other components. Only client components can use the hooks, since they depend on the provider.
|
|
212
|
+
```tsx
|
|
213
|
+
// ManifestLoader.tsx
|
|
214
|
+
"use client";
|
|
215
|
+
import { SimpleViewerProvider, VaultProvider } from "react-iiif-vault";
|
|
216
|
+
import { Vault } from "@iiif/helpers/vault";
|
|
217
|
+
import type { Manifest } from '@iiif/presentation-3';
|
|
218
|
+
|
|
219
|
+
export const vault = new Vault();
|
|
220
|
+
|
|
221
|
+
export function ManifestLoader(props: { manifest: Manifest; children: React.ReactNode }) {
|
|
222
|
+
// On the client, use `vault.requestStatus()` to check if the Manifest already exists
|
|
223
|
+
// if not, use `vault.loadSync()` to load it and ensure its loaded immediately from the JSON.
|
|
224
|
+
if (props.manifest && props.manifest.id && !vault.requestStatus(props.manifest.id)) {
|
|
225
|
+
vault.loadSync(props.manifest.id, props.manifest)
|
|
167
226
|
}
|
|
168
|
-
}, [annotation]);
|
|
169
227
|
|
|
170
|
-
|
|
228
|
+
return (
|
|
229
|
+
<SimpleViewerProvider manifest={props.manifest} vault={vault}>
|
|
230
|
+
{props.children}
|
|
231
|
+
</SimpleViewerProvider>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
171
235
|
|
|
172
|
-
|
|
236
|
+
You can then use this in a server component, passing down the Manifest JSON.
|
|
237
|
+
```ts
|
|
238
|
+
// app/page.tsx
|
|
239
|
+
import { readFile } from 'node:fs/promises';
|
|
173
240
|
|
|
174
|
-
|
|
241
|
+
export default async function Page() {
|
|
242
|
+
const manifestJson = await readFile('./manifests/my-manifest.json').then(s => JSON.parse(s));
|
|
175
243
|
|
|
176
|
-
|
|
244
|
+
return (
|
|
245
|
+
<ManifestLoader manifest={manifestJson}>
|
|
246
|
+
{/* ... Other server or client components ... */}
|
|
247
|
+
</ManifestLoader>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
```
|
|
177
251
|
|
|
178
|
-
|
|
252
|
+
This will prevent the IIIF Resource being requested remotely, speeding up the initial rendering of pages.
|
|
253
|
+
|
|
254
|
+
## Providers + Hooks
|
|
255
|
+
|
|
256
|
+
Some hooks, like `use{RESOURCE}` require a context to be set. Some will be available from the `SimpleViewerProvider` and others may be required before using the hooks. The available providers are:
|
|
257
|
+
- `<AnnotationProvider annotation="..." />` - Single annotation context, enables:
|
|
258
|
+
- `useAnnotation()`
|
|
259
|
+
- `usePaintingAnnotation()`
|
|
260
|
+
- `<AnnotationPageProvider annotationPage="..." />` - Single annotation page context, enables `useAnnotationPage()`
|
|
261
|
+
- `<CanvasContext canvas="..." />` - Single canvas context, enables:
|
|
262
|
+
- `useThumbnail()`
|
|
263
|
+
- `useCanvas()`
|
|
264
|
+
- `usePaintables()`
|
|
265
|
+
- `useRenderingStrategy()`
|
|
266
|
+
- `useLoadImageService()`
|
|
267
|
+
- `useImageTile()`
|
|
268
|
+
- `useImageService()`
|
|
269
|
+
- `<CollectionContext collection="..." />` - Single collection context, enables `useCollection()`
|
|
270
|
+
- `<ManifestContext manifest="..." />` - Single manifest context, enables:
|
|
271
|
+
- `useManifest()`
|
|
272
|
+
- `useThumbnail()`
|
|
273
|
+
- `useSearchService()`
|
|
274
|
+
- `<RangeContext range="..." />` - Single range context, enables `useRange()`
|
|
275
|
+
|
|
276
|
+
## Components
|
|
277
|
+
|
|
278
|
+
Included are a few components that can be used within a Canvas Panel, Simple Viewer or Manifest provider.
|
|
279
|
+
|
|
280
|
+
### Image
|
|
281
|
+
This is a component that can render an Image from an image service or image service ID.
|
|
282
|
+
```tsx
|
|
283
|
+
<Image
|
|
284
|
+
size={{ width: 256 }}
|
|
285
|
+
src="https://iiif.io/api/image/3.0/example/reference/918ecd18c2592080851777620de9bcb5-gottingen"
|
|
286
|
+
/>
|
|
287
|
+
```
|
|
288
|
+
It supports:
|
|
289
|
+
- `rotation`
|
|
290
|
+
- `region`
|
|
291
|
+
- `quality`
|
|
292
|
+
- `size`
|
|
293
|
+
- `format`
|
|
179
294
|
|
|
180
|
-
|
|
295
|
+
You can also pass `fetchImageService={true}` to enable it to fetch the image service. This can be useful if
|
|
296
|
+
you want some validation on the generated URLs (e.g. level0 services). In the future more validation will be
|
|
297
|
+
provided. You can also pass in an image service object in the `src={{ id: ..., profile: ... }}`.
|
|
181
298
|
|
|
182
|
-
|
|
299
|
+
If you only pass in the image service ID, then you have to ensure that you provide valid options supported
|
|
300
|
+
by the image service.
|
|
183
301
|
|
|
184
|
-
|
|
302
|
+
### Single Canvas Thumbnail
|
|
185
303
|
|
|
186
|
-
|
|
304
|
+
This will display a thumbnail using either a `canvasId` or the current canvas in the context.
|
|
187
305
|
|
|
306
|
+
```tsx
|
|
307
|
+
<SimpleViewerContext manifest="https://digirati-co-uk.github.io/wunder.json">
|
|
308
|
+
<SingleCanvasThumbnail size={{ width: 128 }} />
|
|
309
|
+
</SimpleViewerContext>
|
|
188
310
|
```
|
|
189
311
|
|
|
312
|
+
It supports the following props:
|
|
313
|
+
```ts
|
|
314
|
+
interface SingleCanvasThumbnailProps {
|
|
315
|
+
canvasId?: string;
|
|
316
|
+
size?: Partial<SizeParameter>;
|
|
317
|
+
visible?: boolean;
|
|
318
|
+
alt?: string;
|
|
319
|
+
dereference?: boolean;
|
|
320
|
+
|
|
321
|
+
// Style
|
|
322
|
+
figure?: boolean;
|
|
323
|
+
showLabel?: boolean;
|
|
324
|
+
classes?: {
|
|
325
|
+
figure?: string;
|
|
326
|
+
img?: string;
|
|
327
|
+
label?: string;
|
|
328
|
+
imageWrapper?: string;
|
|
329
|
+
};
|
|
190
330
|
|
|
331
|
+
// Slots.
|
|
332
|
+
placeholder?: React.ReactNode;
|
|
333
|
+
fallback?: React.ReactNode;
|
|
334
|
+
}
|
|
335
|
+
```
|
|
191
336
|
|
|
192
|
-
###
|
|
337
|
+
### Sequence thumbnails
|
|
338
|
+
|
|
339
|
+
This wraps the `SingleCanvasThumbnail` but provides a list that is lazy-loaded based on the current sequence from the Simple Viewer Context.
|
|
340
|
+
|
|
341
|
+

|
|
342
|
+
|
|
343
|
+
Example:
|
|
344
|
+
```tsx
|
|
345
|
+
<SimpleViewerContext manifest="https://digirati-co-uk.github.io/wunder.json">
|
|
346
|
+
<SequenceThumbnails
|
|
347
|
+
classes={{
|
|
348
|
+
container: 'flex gap-1 overflow-x-auto',
|
|
349
|
+
row: 'flex gap-2 border border-gray-200 flex-none p-2 m-2',
|
|
350
|
+
img: 'max-h-[128px] max-w-[128px] object-contain h-full w-full',
|
|
351
|
+
selected: {
|
|
352
|
+
row: 'flex gap-2 border border-blue-400 flex-none p-2 m-2 bg-blue-100',
|
|
353
|
+
},
|
|
354
|
+
}}
|
|
355
|
+
fallback={
|
|
356
|
+
<div className="flex items-center justify-center w-32 h-32 bg-gray-200 text-gray-400 select-none">
|
|
357
|
+
No thumb
|
|
358
|
+
</div>
|
|
359
|
+
}
|
|
360
|
+
/>
|
|
361
|
+
</SimpleViewerContext>
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
The available props:
|
|
365
|
+
```ts
|
|
366
|
+
interface SequenceThumbnailsProps {
|
|
367
|
+
flat?: boolean;
|
|
368
|
+
size?: { width: number; height?: number };
|
|
369
|
+
classes?: {
|
|
370
|
+
container?: string;
|
|
371
|
+
row?: string;
|
|
372
|
+
item?: string;
|
|
373
|
+
|
|
374
|
+
// SingleCanvasThumbnail
|
|
375
|
+
figure?: string;
|
|
376
|
+
imageWrapper?: string;
|
|
377
|
+
img?: string;
|
|
378
|
+
label?: string;
|
|
379
|
+
|
|
380
|
+
selected?: {
|
|
381
|
+
row?: string;
|
|
382
|
+
item?: string;
|
|
383
|
+
figure?: string;
|
|
384
|
+
img?: string;
|
|
385
|
+
label?: string;
|
|
386
|
+
imageWrapper?: string;
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
figure?: boolean;
|
|
391
|
+
showLabel?: boolean;
|
|
392
|
+
// Slots
|
|
393
|
+
fallback?: React.ReactNode;
|
|
394
|
+
}
|
|
395
|
+
```
|
|
193
396
|
|
|
194
|
-
|
|
195
|
-
- Annotation pages on manifests
|
|
196
|
-
- Annotation pages with manifestId in meta
|
|
197
|
-
- Annotation pages with canvasId in meta
|
|
397
|
+
### Metadata components
|
|
198
398
|
|
|
199
|
-
|
|
399
|
+
These components will display metadata for different resources:
|
|
400
|
+
- `ManifestMetadata` - Displays only the metadata for the current Manifest
|
|
401
|
+
- `CombinedMetadata` - Displays the metadata for the current Manifest, Canvas and Range - combined
|
|
402
|
+
- `Metadata` - Has an extra `metadata={}` property, where you can pass down your own metadata.
|
|
200
403
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
404
|
+

|
|
405
|
+
|
|
406
|
+
Example:
|
|
407
|
+
|
|
408
|
+
```tsx
|
|
409
|
+
<CombinedMetadata
|
|
410
|
+
allowHtml={true}
|
|
411
|
+
classes={{
|
|
412
|
+
container: 'm-4',
|
|
413
|
+
row: 'border-b border-gray-200',
|
|
414
|
+
label: 'font-bold p-2 text-slate-600',
|
|
415
|
+
value: 'text-sm p-2 text-slate-800',
|
|
416
|
+
empty: 'text-gray-400',
|
|
417
|
+
}}
|
|
418
|
+
/>
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
These are provided without styles, and a `classes={}` prop for adding class names. The full list of options are available here:
|
|
422
|
+
```ts
|
|
423
|
+
export interface MetadataProps {
|
|
424
|
+
config?: FacetConfig[];
|
|
425
|
+
metadata?: Array<{ label: InternationalString; value: InternationalString } | null>;
|
|
426
|
+
labelWidth?: number;
|
|
427
|
+
allowHtml?: boolean;
|
|
428
|
+
showEmptyMessage?: boolean;
|
|
429
|
+
separator?: string;
|
|
430
|
+
|
|
431
|
+
classes?: {
|
|
432
|
+
container?: string;
|
|
433
|
+
row?: string;
|
|
434
|
+
label?: string;
|
|
435
|
+
value?: string;
|
|
436
|
+
empty?: string;
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
emptyMessage?: string;
|
|
440
|
+
emptyValueFallback?: string;
|
|
441
|
+
emptyLabelFallback?: string;
|
|
442
|
+
|
|
443
|
+
// Slots.
|
|
444
|
+
tableHeader?: React.ReactNode;
|
|
445
|
+
tableFooter?: React.ReactNode;
|
|
446
|
+
emptyFallback?: React.ReactNode;
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
The `facetConfig` options allows you to change the way the metadata is displayed. The types are:
|
|
451
|
+
```ts
|
|
452
|
+
type FacetConfig = {
|
|
453
|
+
id: string;
|
|
454
|
+
label: InternationalString;
|
|
455
|
+
keys: string[];
|
|
456
|
+
values?: FacetConfigValue[];
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
type FacetConfigValue = {
|
|
460
|
+
id: string;
|
|
461
|
+
label: InternationalString;
|
|
462
|
+
values: string[];
|
|
463
|
+
key: string;
|
|
464
|
+
};
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
Example:
|
|
468
|
+
```ts
|
|
469
|
+
const facetConfig = [
|
|
470
|
+
{
|
|
471
|
+
id: 'topics',
|
|
472
|
+
label: { en: ['Topics'] },
|
|
473
|
+
keys: ['Topic', 'Subject'],
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
id: 'collections',
|
|
477
|
+
label: { en: ['Collection'] },
|
|
478
|
+
keys: ['Collection'],
|
|
479
|
+
values: [
|
|
480
|
+
{
|
|
481
|
+
id: 'featured',
|
|
482
|
+
label: { en: ['Featured collection'] },
|
|
483
|
+
values: ['col_00001', 'col_00002'],
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
id: 'paintings',
|
|
487
|
+
label: { en: ['Paintings'] },
|
|
488
|
+
values: ['col_00003'],
|
|
209
489
|
}
|
|
210
|
-
|
|
490
|
+
]
|
|
211
491
|
}
|
|
212
|
-
|
|
492
|
+
];
|
|
213
493
|
```
|
|
494
|
+
|
|
495
|
+
It's unlikely that this type of configuration would be created by hand, instead a tool would be used to clean up the Metadata or curated from multiple sources. In the example above, given the following metadata input:
|
|
496
|
+
```json
|
|
497
|
+
[
|
|
498
|
+
{
|
|
499
|
+
"label": {"none": ["Topic"]},
|
|
500
|
+
"value": {"none": ["Some topic"]}
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"label": {"none": ["Subject"]},
|
|
504
|
+
"value": {"none": ["Some subject", "Another subject"]}
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"label": {"none": ["Collection"]},
|
|
508
|
+
"value": {"none": ["col_0003"]}
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
"label": {"none": ["Object identifier"]},
|
|
512
|
+
"value": {"none": ["123456"]}
|
|
513
|
+
}
|
|
514
|
+
]
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Would be transformed to:
|
|
518
|
+
```json
|
|
519
|
+
[
|
|
520
|
+
{
|
|
521
|
+
"label": {"en": ["Topics"]},
|
|
522
|
+
"value": {"none": ["Some topic", "Some subject", "Another subject"]}
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"label": {"en": ["Collection"]},
|
|
526
|
+
"value": {"en": ["Paintings"]}
|
|
527
|
+
}
|
|
528
|
+
]
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
So the metadata that wasn't configured is skipped, values mapped and combined.
|