@knaw-huc/osd-iiif-viewer 0.1.1 → 0.1.3

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 {};
@@ -0,0 +1,5 @@
1
+ type ViewerCanvasProps = {
2
+ showControls?: boolean;
3
+ };
4
+ export declare function Viewer({ showControls }: ViewerCanvasProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { HighlightOverlay, type Highlight } from './HighlightOverlay.tsx';
2
- export { ViewerCanvas } from './ViewerCanvas';
1
+ export { useImageInfo } from './useImageInfo.tsx';
2
+ export { Overlay } from './Overlay.tsx';
3
+ export { Viewer } from './Viewer.tsx';
3
4
  export { ViewerProvider } from './ViewerProvider';
4
5
  export { useViewer } from './useViewer';
5
6
  export { useViewerControls } from './useViewerControls';
@@ -7,4 +8,4 @@ export { useViewerReady } from './useViewerReady';
7
8
  export { useViewerStore } from './useViewerStore';
8
9
  export { useManifest, useLoadManifest } from './manifest/useManifest';
9
10
  export { useCanvas } from './manifest/useCanvas';
10
- export type { ViewerManifest, ViewerCanvas as ViewerCanvasModel, ViewerRange, ViewerMetadata } from './manifest/model';
11
+ export type { ViewerManifest, ViewerCanvas, ViewerRange, ViewerMetadata } from './manifest/model';
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { useStore } from "zustand/index";
2
- import { createContext, useContext, useEffect, useRef, useState, useCallback } from "react";
2
+ import { createContext, useContext, useMemo, useState, useEffect, useRef, useCallback } from "react";
3
3
  import { createStore } from "zustand/vanilla";
4
+ import { createPortal } from "react-dom";
4
5
  import { jsx } from "react/jsx-runtime";
5
- import { Viewer } from "openseadragon";
6
+ import { Viewer as Viewer$1 } from "openseadragon";
6
7
  const createInstanceSlice = (set) => ({
7
8
  viewer: null,
8
9
  viewerReady: !1,
@@ -163,42 +164,30 @@ function useViewer() {
163
164
  function useViewerReady() {
164
165
  return useViewerStoreSelector((s) => s.viewerReady);
165
166
  }
166
- function assertSvgElement(element) {
167
- if (!(element instanceof SVGElement))
168
- throw new Error("Expected SVGElement");
169
- }
170
- function HighlightOverlay({ highlights, onHover = noop }) {
167
+ function useImageInfo() {
171
168
  const viewer = useViewer(), ready = useViewerReady();
172
- return useEffect(() => {
173
- if (!viewer || !ready || !highlights.length)
174
- return;
169
+ return useMemo(() => {
170
+ if (!viewer || !ready)
171
+ return null;
175
172
  const item = viewer.world.getItemAt(0);
176
173
  if (!item)
177
- return;
178
- const size = item.getContentSize(), imageRect = item.imageToViewportRectangle(0, 0, size.x, size.y), overlayElements = [];
179
- for (const highlight of highlights) {
180
- const container = document.createElement("div");
181
- container.style.position = "absolute", container.style.pointerEvents = "none";
182
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
183
- svg.setAttribute("viewBox", `0 0 ${size.x} ${size.y}`), svg.style.width = "100%", svg.style.height = "100%", svg.style.pointerEvents = "none";
184
- const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
185
- g.innerHTML = highlight.path;
186
- const shape = g.firstElementChild;
187
- assertSvgElement(shape), shape.setAttribute("fill", "transparent"), shape.style.pointerEvents = "auto", shape.style.cursor = "pointer", shape.addEventListener("mouseenter", (event) => {
188
- shape.setAttribute("fill", "rgba(0,0,0,0.1)"), onHover(highlight.id, event);
189
- }), shape.addEventListener("mousemove", (event) => {
190
- onHover(highlight.id, event);
191
- }), shape.addEventListener("mouseleave", (event) => {
192
- shape.setAttribute("fill", "transparent"), onHover(null, event);
193
- }), svg.appendChild(g), container.appendChild(svg), viewer.addOverlay({ element: container, location: imageRect }), overlayElements.push(container);
194
- }
195
- return () => {
196
- overlayElements.forEach((el) => viewer.removeOverlay(el));
197
- };
198
- }, [viewer, ready, highlights, onHover]), null;
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;
199
190
  }
200
- const noop = () => {
201
- };
202
191
  function findTileSource(canvas) {
203
192
  return canvas.imageServiceId + "/info.json";
204
193
  }
@@ -210,12 +199,12 @@ function useCanvas() {
210
199
  );
211
200
  return { currentIndex, goTo, next, prev, current, total };
212
201
  }
213
- function ViewerCanvas({ showControls = !0 }) {
202
+ function Viewer({ showControls = !0 }) {
214
203
  const containerRef = useRef(null), store = useViewerStore(), { current } = useCanvas(), tileSource = current ? findTileSource(current) : null;
215
204
  return useEffect(() => {
216
205
  if (!containerRef.current || !tileSource)
217
206
  return;
218
- const viewer = new Viewer({
207
+ const viewer = new Viewer$1({
219
208
  element: containerRef.current,
220
209
  prefixUrl: "https://openseadragon.github.io/openseadragon/images/",
221
210
  crossOriginPolicy: "Anonymous",
@@ -286,10 +275,11 @@ function useLoadManifest() {
286
275
  return useViewerStoreSelector((s) => s.loadManifest);
287
276
  }
288
277
  export {
289
- HighlightOverlay,
290
- ViewerCanvas,
278
+ Overlay,
279
+ Viewer,
291
280
  ViewerProvider,
292
281
  useCanvas,
282
+ useImageInfo,
293
283
  useLoadManifest,
294
284
  useManifest,
295
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.1",
3
+ "version": "0.1.3",
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 {};
@@ -1,5 +0,0 @@
1
- type ViewerCanvasProps = {
2
- showControls?: boolean;
3
- };
4
- export declare function ViewerCanvas({ showControls }: ViewerCanvasProps): import("react/jsx-runtime").JSX.Element;
5
- export {};