@knaw-huc/osd-iiif-viewer 0.3.0 → 0.4.0

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/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { Viewer } from './Viewer.tsx';
2
2
  export { useImageInfo } from './useImageInfo.tsx';
3
3
  export { Overlay } from './Overlay.tsx';
4
+ export { usePointerDown } from './usePointerDown.tsx';
4
5
  export { ViewerProvider } from './ViewerProvider';
5
6
  export { useViewer } from './useViewer';
6
7
  export { useViewerControls } from './useViewerControls';
package/dist/index.js CHANGED
@@ -170,7 +170,7 @@ function useManifest() {
170
170
  function useLoadManifest() {
171
171
  return useViewerStoreSelector((s) => s.loadManifest);
172
172
  }
173
- function useStableProp(options) {
173
+ function useStableState(options) {
174
174
  const [stable, setStable] = useState(options), [key, setKey] = useState(() => JSON.stringify(options)), json = JSON.stringify(options);
175
175
  return json !== key && (setKey(json), setStable(options)), stable;
176
176
  }
@@ -180,7 +180,7 @@ const defaultOptions = {
180
180
  showNavigationControl: !0
181
181
  };
182
182
  function Viewer(props) {
183
- const containerRef = useRef(null), store = useViewerStore(), { vault } = useManifest(), { current } = useCanvas(), tileSource = current ? findTileSource(vault, current) : null, size = useContainerSize(containerRef), isContainerReady = size.width > 0 && size.height > 0, options = useStableProp(props.options);
183
+ const containerRef = useRef(null), store = useViewerStore(), { vault } = useManifest(), { current } = useCanvas(), tileSource = current ? findTileSource(vault, current) : null, size = useContainerSize(containerRef), isContainerReady = size.width && size.height, options = useStableState(props.options);
184
184
  useEffect(createOsdViewer, [isContainerReady, store, options]);
185
185
  function createOsdViewer() {
186
186
  if (!containerRef.current || !isContainerReady)
@@ -227,10 +227,10 @@ function Viewer(props) {
227
227
  );
228
228
  }
229
229
  function observeResize(element, callback) {
230
- const ro = new ResizeObserver((entries) => {
230
+ const observer = new ResizeObserver((entries) => {
231
231
  callback(entries[0].contentRect);
232
232
  });
233
- return ro.observe(element), () => ro.disconnect();
233
+ return observer.observe(element), () => observer.disconnect();
234
234
  }
235
235
  function useContainerSize(ref) {
236
236
  const [size, setSize] = useState({ width: 0, height: 0 });
@@ -238,9 +238,9 @@ function useContainerSize(ref) {
238
238
  const element = ref.current;
239
239
  if (!element)
240
240
  return;
241
- const rect = element.getBoundingClientRect();
242
- return setSize({ width: rect.width, height: rect.height }), observeResize(element, (rect2) => {
243
- setSize({ width: rect2.width, height: rect2.height });
241
+ const { width, height } = element.getBoundingClientRect();
242
+ return setSize({ width, height }), observeResize(element, ({ width: width2, height: height2 }) => {
243
+ setSize({ width: width2, height: height2 });
244
244
  });
245
245
  }, [ref]), size;
246
246
  }
@@ -268,19 +268,33 @@ function Overlay({ location, children }) {
268
268
  return div.style.position = "absolute", div.style.pointerEvents = "none", div;
269
269
  });
270
270
  return useEffect(() => {
271
- function stopPropagation(event) {
272
- event.target !== overlay && event.stopPropagation();
273
- }
274
- return overlay.addEventListener("pointerdown", stopPropagation), () => {
275
- overlay.removeEventListener("pointerdown", stopPropagation);
276
- };
277
- }, [overlay]), useEffect(() => {
278
271
  if (viewer)
279
272
  return viewer.addOverlay({ element: overlay, location }), () => {
280
273
  viewer.isOpen() && viewer.removeOverlay(overlay);
281
274
  };
282
275
  }, [viewer, location, overlay]), viewer ? createPortal(children, overlay) : null;
283
276
  }
277
+ function hasMoved(from, to, threshold) {
278
+ return Math.hypot(to.x - from.x, to.y - from.y) > threshold;
279
+ }
280
+ function usePointerDown({
281
+ onClick,
282
+ onDrag,
283
+ onDragEnd,
284
+ dragThreshold = 5,
285
+ clickTimeLimit = 1 / 0
286
+ }) {
287
+ return function(event) {
288
+ const from = { x: event.clientX, y: event.clientY }, startTime = Date.now(), gesture = new AbortController(), { signal } = gesture;
289
+ let dragging = !1;
290
+ window.addEventListener("pointermove", (move) => {
291
+ const to = { x: move.clientX, y: move.clientY };
292
+ dragging ||= hasMoved(from, to, dragThreshold), dragging && onDrag?.(move);
293
+ }, { signal }), window.addEventListener("pointerup", (up) => {
294
+ gesture.abort(), dragging ? onDragEnd?.(up) : Date.now() - startTime <= clickTimeLimit && onClick?.(up);
295
+ }, { signal }), window.addEventListener("pointercancel", () => gesture.abort(), { signal });
296
+ };
297
+ }
284
298
  function ViewerProvider({ children }) {
285
299
  const [store] = useState(() => createViewerStore());
286
300
  return /* @__PURE__ */ jsx(ViewerContext.Provider, { value: store, children });
@@ -325,7 +339,8 @@ function useViewerControls(fullscreenRef) {
325
339
  };
326
340
  }
327
341
  function findThumbnail(vault, canvas, height = 120) {
328
- return getImageServiceId(vault, canvas) ? `/full/,${height}/0/default.jpg` : null;
342
+ const id = getImageServiceId(vault, canvas);
343
+ return id ? `${id}/full/,${height}/0/default.jpg` : null;
329
344
  }
330
345
  export {
331
346
  Overlay,
@@ -338,6 +353,7 @@ export {
338
353
  useImageInfo,
339
354
  useLoadManifest,
340
355
  useManifest,
356
+ usePointerDown,
341
357
  useViewer,
342
358
  useViewerControls,
343
359
  useViewerReady,
@@ -0,0 +1,13 @@
1
+ import { PointerEvent as ReactPointerEvent } from 'react';
2
+ type PointerDownOptions = {
3
+ onClick?: (event: PointerEvent) => void;
4
+ onDrag?: (event: PointerEvent) => void;
5
+ onDragEnd?: (event: PointerEvent) => void;
6
+ dragThreshold?: number;
7
+ clickTimeLimit?: number;
8
+ };
9
+ /**
10
+ * Tell a click apart from a drag, and leave the drag itself to the viewer
11
+ */
12
+ export declare function usePointerDown({ onClick, onDrag, onDragEnd, dragThreshold, clickTimeLimit, }: PointerDownOptions): (event: ReactPointerEvent) => void;
13
+ export {};
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Keep object reference intact when stringified content remains equal
3
+ */
4
+ export declare function useStableState<T>(options: T): T;
@@ -0,0 +1,6 @@
1
+ type Point = {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ export declare function hasMoved(from: Point, to: Point, threshold: number): boolean;
6
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knaw-huc/osd-iiif-viewer",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/knaw-huc/osd-iiif-viewer.git"
@@ -1 +0,0 @@
1
- export declare function useStableProp<T>(options: T): T;