@knaw-huc/osd-iiif-viewer 0.1.1 → 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,4 +1,5 @@
1
- export { HighlightOverlay, type Highlight } from './HighlightOverlay.tsx';
1
+ export { useImageInfo } from './useImageInfo.tsx';
2
+ export { Overlay } from './Overlay.tsx';
2
3
  export { ViewerCanvas } from './ViewerCanvas';
3
4
  export { ViewerProvider } from './ViewerProvider';
4
5
  export { useViewer } from './useViewer';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
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
6
  import { Viewer } from "openseadragon";
6
7
  const createInstanceSlice = (set) => ({
@@ -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
  }
@@ -286,10 +275,11 @@ function useLoadManifest() {
286
275
  return useViewerStoreSelector((s) => s.loadManifest);
287
276
  }
288
277
  export {
289
- HighlightOverlay,
278
+ Overlay,
290
279
  ViewerCanvas,
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.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 {};