@knaw-huc/osd-iiif-viewer 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1 +1,46 @@
1
- # osd-iiif-viewer
1
+ # @knaw-huc/osd-iiif-viewer
2
+
3
+ React wrapper around OpenSeadragon to display and browse image sources from iiif manifests.
4
+
5
+ Current features (WIP):
6
+ - Canvas navigation
7
+ - Highlight overlay
8
+ - Zoom and fullscreen controls
9
+ - Manifest parsing (iiif manifests v3, ImageService2)
10
+
11
+ ## Minimal example
12
+ ```tsx
13
+ import {useEffect} from 'react';
14
+ import {
15
+ ViewerProvider,
16
+ ViewerCanvas,
17
+ useLoadManifest,
18
+ useManifest,
19
+ } from '@knaw-huc/osd-iiif-viewer';
20
+
21
+ export function Example() {
22
+ return <ViewerProvider>
23
+ <Viewer/>
24
+ </ViewerProvider>
25
+ }
26
+
27
+ function Viewer() {
28
+ const loadManifest = useLoadManifest();
29
+ const manifest = useManifest();
30
+
31
+ useEffect(() => {
32
+ loadManifest('/manifest.json');
33
+ }, [loadManifest]);
34
+
35
+ if (!manifest.data) {
36
+ return null;
37
+ }
38
+
39
+ return (
40
+ <div style={{width: '100%', height: '100vh'}}>
41
+ <ViewerCanvas/>
42
+ </div>
43
+ );
44
+ }
45
+ ```
46
+
@@ -0,0 +1,6 @@
1
+ type OverlayProps = {
2
+ location: OpenSeadragon.Rect;
3
+ children: React.ReactNode;
4
+ };
5
+ export declare function Overlay({ location, children }: OverlayProps): import('react').ReactPortal | null;
6
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { useImageInfo } from './useImageInfo.tsx';
2
+ export { Overlay } from './Overlay.tsx';
1
3
  export { ViewerCanvas } from './ViewerCanvas';
2
4
  export { ViewerProvider } from './ViewerProvider';
3
5
  export { useViewer } from './useViewer';
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
+ import { useStore } from "zustand/index";
2
+ import { createContext, useContext, useMemo, useState, useEffect, useRef, useCallback } from "react";
3
+ import { createStore } from "zustand/vanilla";
4
+ import { createPortal } from "react-dom";
1
5
  import { jsx } from "react/jsx-runtime";
2
6
  import { Viewer } from "openseadragon";
3
- import { createContext, useContext, useRef, useEffect, useState, useCallback } from "react";
4
- import { createStore } from "zustand/vanilla";
5
- import { useStore } from "zustand/index";
6
7
  const createInstanceSlice = (set) => ({
7
8
  viewer: null,
8
9
  viewerReady: !1,
@@ -153,13 +154,43 @@ const defaultManifest = { data: null, url: "", isLoading: !1, error: null }, cre
153
154
  function useViewerStore() {
154
155
  return useContext(ViewerContext) ?? orThrow("viewer hook must be used within viewer provider");
155
156
  }
156
- function findTileSource(canvas) {
157
- return canvas.imageServiceId + "/info.json";
158
- }
159
157
  function useViewerStoreSelector(selector) {
160
158
  const store = useViewerStore();
161
159
  return useStore(store, selector);
162
160
  }
161
+ function useViewer() {
162
+ return useViewerStoreSelector((s) => s.viewer);
163
+ }
164
+ function useViewerReady() {
165
+ return useViewerStoreSelector((s) => s.viewerReady);
166
+ }
167
+ function useImageInfo() {
168
+ const viewer = useViewer(), ready = useViewerReady();
169
+ return useMemo(() => {
170
+ if (!viewer || !ready)
171
+ return null;
172
+ const item = viewer.world.getItemAt(0);
173
+ if (!item)
174
+ return null;
175
+ const size = item.getContentSize();
176
+ return { location: item.imageToViewportRectangle(0, 0, size.x, size.y), size };
177
+ }, [viewer, ready]);
178
+ }
179
+ function Overlay({ location, children }) {
180
+ const viewer = useViewer(), [container] = useState(() => {
181
+ const el = document.createElement("div");
182
+ return el.style.position = "absolute", el.style.pointerEvents = "none", el;
183
+ });
184
+ return useEffect(() => {
185
+ if (viewer)
186
+ return viewer.addOverlay({ element: container, location }), () => {
187
+ viewer.removeOverlay(container);
188
+ };
189
+ }, [viewer, location, container]), viewer ? createPortal(children, container) : null;
190
+ }
191
+ function findTileSource(canvas) {
192
+ return canvas.imageServiceId + "/info.json";
193
+ }
163
194
  function useCanvas() {
164
195
  const { currentIndex } = useViewerStoreSelector((s) => s.canvas), goTo = useViewerStoreSelector((s) => s.goToCanvas), next = useViewerStoreSelector((s) => s.nextCanvas), prev = useViewerStoreSelector((s) => s.prevCanvas), current = useViewerStoreSelector(
165
196
  (s) => s.manifest.data?.canvases[s.canvas.currentIndex] ?? null
@@ -205,9 +236,6 @@ function ViewerProvider({ children }) {
205
236
  const [store] = useState(() => createViewerStore());
206
237
  return /* @__PURE__ */ jsx(ViewerContext.Provider, { value: store, children });
207
238
  }
208
- function useViewer() {
209
- return useViewerStoreSelector((s) => s.viewer);
210
- }
211
239
  function useViewerControls(fullscreenRef) {
212
240
  const viewer = useViewer(), store = useViewerStore(), zoomLevel = useViewerStoreSelector((s) => s.zoomLevel), zoomMin = useViewerStoreSelector((s) => s.zoomMin), zoomMax = useViewerStoreSelector((s) => s.zoomMax), isFullPage = useViewerStoreSelector((s) => s.isFullPage);
213
241
  useEffect(() => {
@@ -240,9 +268,6 @@ function useViewerControls(fullscreenRef) {
240
268
  isFullPage
241
269
  };
242
270
  }
243
- function useViewerReady() {
244
- return useViewerStoreSelector((s) => s.viewerReady);
245
- }
246
271
  function useManifest() {
247
272
  return useViewerStoreSelector((s) => s.manifest);
248
273
  }
@@ -250,9 +275,11 @@ function useLoadManifest() {
250
275
  return useViewerStoreSelector((s) => s.loadManifest);
251
276
  }
252
277
  export {
278
+ Overlay,
253
279
  ViewerCanvas,
254
280
  ViewerProvider,
255
281
  useCanvas,
282
+ useImageInfo,
256
283
  useLoadManifest,
257
284
  useManifest,
258
285
  useViewer,
@@ -0,0 +1,5 @@
1
+ export type ImageInfo = {
2
+ location: OpenSeadragon.Rect;
3
+ size: OpenSeadragon.Point;
4
+ };
5
+ export declare function useImageInfo(): ImageInfo | null;
package/package.json CHANGED
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "name": "@knaw-huc/osd-iiif-viewer",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/knaw-huc/osd-iiif-viewer.git"
7
+ },
4
8
  "type": "module",
5
9
  "main": "dist/index.js",
6
10
  "types": "dist/index.d.ts",
@@ -1,11 +0,0 @@
1
- import { Id } from './Id.ts';
2
- export type Highlight = {
3
- id: Id;
4
- path: string;
5
- };
6
- type HighlightOverlayProps = {
7
- highlights: Highlight[];
8
- onHover?: (highlightId: Id | null, event: MouseEvent) => void;
9
- };
10
- export declare function HighlightOverlay({ highlights, onHover }: HighlightOverlayProps): null;
11
- export {};