@anaralabs/lector 3.5.2 → 3.5.4

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.
@@ -31,15 +31,16 @@ declare interface Annotation {
31
31
  width: number;
32
32
  pageNumber: number;
33
33
  }>;
34
- comment?: string;
35
- color?: string;
34
+ color: string;
36
35
  createdAt: Date;
37
36
  updatedAt: Date;
37
+ comment?: string;
38
+ metadata?: Record<string, unknown>;
38
39
  }
39
40
  export { Annotation }
40
41
  export { Annotation as Annotation_alias_1 }
41
42
 
42
- export declare const AnnotationHighlightLayer: ({ className, style, renderTooltipContent, tooltipClassName, focusedAnnotationId, onAnnotationClick, }: AnnotationHighlightLayerProps) => JSX.Element;
43
+ export declare const AnnotationHighlightLayer: ({ className, style, renderTooltipContent, renderHoverTooltipContent, tooltipClassName, focusedAnnotationId, onAnnotationClick, hoverTooltipClassName }: AnnotationHighlightLayerProps) => JSX.Element;
43
44
 
44
45
  declare interface AnnotationHighlightLayerProps {
45
46
  className?: string;
@@ -48,9 +49,14 @@ declare interface AnnotationHighlightLayerProps {
48
49
  annotation: Annotation;
49
50
  onClose: () => void;
50
51
  }) => React.ReactNode;
52
+ renderHoverTooltipContent: (props: {
53
+ annotation: Annotation;
54
+ onClose: () => void;
55
+ }) => React.ReactNode;
51
56
  focusedAnnotationId?: string;
52
57
  onAnnotationClick?: (annotation: Annotation) => void;
53
58
  tooltipClassName?: string;
59
+ hoverTooltipClassName?: string;
54
60
  }
55
61
 
56
62
  /**
@@ -84,21 +90,27 @@ declare interface AnnotationLayerParams {
84
90
 
85
91
  declare interface AnnotationState {
86
92
  annotations: Annotation[];
87
- addAnnotation: (annotation: Omit<Annotation, "id" | "createdAt" | "updatedAt">) => void;
93
+ addAnnotation: (annotation: Annotation) => void;
88
94
  updateAnnotation: (id: string, updates: Partial<Annotation>) => void;
89
95
  deleteAnnotation: (id: string) => void;
90
96
  setAnnotations: (annotations: Annotation[]) => void;
91
97
  }
92
98
 
93
- export declare const AnnotationTooltip: ({ annotation, children, tooltipContent, onOpenChange, className, isOpen: controlledIsOpen, }: AnnotationTooltipProps) => JSX.Element;
99
+ export declare const AnnotationTooltip: ({ annotation, children, tooltipContent, hoverTooltipContent, onOpenChange, className, hoverClassName, isOpen: controlledIsOpen, }: AnnotationTooltipProps) => JSX.Element;
94
100
 
95
101
  declare interface AnnotationTooltipProps {
96
102
  annotation: Annotation;
97
103
  children: React.ReactNode;
98
104
  tooltipContent: React.ReactNode;
105
+ hoverTooltipContent?: React.ReactNode;
99
106
  onOpenChange?: (open: boolean) => void;
100
107
  isOpen?: boolean;
101
108
  className?: string;
109
+ hoverClassName?: string;
110
+ renderHoverTooltipContent?: (props: {
111
+ annotation: Annotation;
112
+ onClose: () => void;
113
+ }) => React.ReactNode;
102
114
  }
103
115
 
104
116
  /**
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  'use client';
2
2
 
3
- import React, { createContext, forwardRef, useCallback, useContext, useState, useRef, useEffect, cloneElement, createRef, useLayoutEffect } from 'react';
3
+ import React, { createContext, forwardRef, useRef, useCallback, useContext, useState, useEffect, cloneElement, createRef, useLayoutEffect } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
  import { useFloating, autoUpdate, offset, shift, useDismiss, useInteractions, inline, flip } from '@floating-ui/react';
6
6
  import { useVirtualizer, elementScroll, debounce } from '@tanstack/react-virtual';
7
7
  import { create, useStore, createStore } from 'zustand';
8
8
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
9
- import { v4 } from 'uuid';
10
9
  import { AnnotationLayer, TextLayer, getDocument } from 'pdfjs-dist';
11
10
  import { useDebounce } from 'use-debounce';
11
+ import { v4 } from 'uuid';
12
12
  import { Slot } from '@radix-ui/react-slot';
13
13
 
14
14
  // src/components/annotation-tooltip.tsx
@@ -261,11 +261,15 @@ var AnnotationTooltip = ({
261
261
  annotation,
262
262
  children,
263
263
  tooltipContent,
264
+ hoverTooltipContent,
264
265
  onOpenChange,
265
266
  className,
267
+ hoverClassName,
266
268
  isOpen: controlledIsOpen
267
269
  }) => {
268
270
  const viewportRef = usePdf((state) => state.viewportRef);
271
+ const closeTimeoutRef = useRef(null);
272
+ const isMouseInTooltipRef = useRef(false);
269
273
  const {
270
274
  isOpen: uncontrolledIsOpen,
271
275
  setIsOpen,
@@ -277,19 +281,64 @@ var AnnotationTooltip = ({
277
281
  annotation,
278
282
  onOpenChange
279
283
  });
284
+ const {
285
+ isOpen: hoverIsOpen,
286
+ setIsOpen: setHoverIsOpen,
287
+ refs: hoverRefs,
288
+ floatingStyles: hoverFloatingStyles,
289
+ getFloatingProps: getHoverFloatingProps,
290
+ getReferenceProps: getHoverReferenceProps
291
+ } = useAnnotationTooltip({
292
+ annotation
293
+ });
280
294
  const isOpen = controlledIsOpen ?? uncontrolledIsOpen;
281
295
  const handleClick = useCallback(() => {
282
296
  if (controlledIsOpen === void 0) {
283
297
  setIsOpen(!isOpen);
284
298
  }
285
299
  }, [controlledIsOpen, isOpen, setIsOpen]);
300
+ const handleMouseEnter = useCallback(() => {
301
+ if (hoverTooltipContent) {
302
+ if (closeTimeoutRef.current) {
303
+ clearTimeout(closeTimeoutRef.current);
304
+ closeTimeoutRef.current = null;
305
+ }
306
+ setHoverIsOpen(true);
307
+ }
308
+ }, [hoverTooltipContent, setHoverIsOpen]);
309
+ const closeTooltip = useCallback(() => {
310
+ if (!isMouseInTooltipRef.current) {
311
+ setHoverIsOpen(false);
312
+ }
313
+ }, [setHoverIsOpen]);
314
+ const handleMouseLeave = useCallback(() => {
315
+ if (!hoverTooltipContent) return;
316
+ closeTimeoutRef.current = setTimeout(closeTooltip, 100);
317
+ }, [hoverTooltipContent, closeTooltip]);
318
+ const handleTooltipMouseEnter = useCallback(() => {
319
+ isMouseInTooltipRef.current = true;
320
+ if (closeTimeoutRef.current) {
321
+ clearTimeout(closeTimeoutRef.current);
322
+ closeTimeoutRef.current = null;
323
+ }
324
+ }, []);
325
+ const handleTooltipMouseLeave = useCallback(() => {
326
+ isMouseInTooltipRef.current = false;
327
+ setHoverIsOpen(false);
328
+ }, [setHoverIsOpen]);
286
329
  return /* @__PURE__ */ jsxs(Fragment, { children: [
287
330
  /* @__PURE__ */ jsx(
288
331
  "div",
289
332
  {
290
- ref: refs.setReference,
333
+ ref: (node) => {
334
+ refs.setReference(node);
335
+ hoverRefs.setReference(node);
336
+ },
291
337
  onClick: handleClick,
338
+ onMouseEnter: handleMouseEnter,
339
+ onMouseLeave: handleMouseLeave,
292
340
  ...getReferenceProps(),
341
+ ...getHoverReferenceProps(),
293
342
  children
294
343
  }
295
344
  ),
@@ -299,16 +348,39 @@ var AnnotationTooltip = ({
299
348
  {
300
349
  ref: refs.setFloating,
301
350
  className,
351
+ "data-annotation-tooltip": "click",
302
352
  style: {
303
353
  ...floatingStyles,
304
354
  position: "absolute",
305
- pointerEvents: "auto"
355
+ pointerEvents: "auto",
356
+ zIndex: 50
306
357
  },
307
358
  ...getFloatingProps(),
308
359
  children: tooltipContent
309
360
  }
310
361
  ),
311
362
  viewportRef.current
363
+ ),
364
+ !isOpen && hoverIsOpen && annotation.comment && hoverTooltipContent && viewportRef.current && createPortal(
365
+ /* @__PURE__ */ jsx(
366
+ "div",
367
+ {
368
+ ref: hoverRefs.setFloating,
369
+ className: hoverClassName,
370
+ "data-annotation-tooltip": "hover",
371
+ style: {
372
+ ...hoverFloatingStyles,
373
+ position: "absolute",
374
+ pointerEvents: "auto",
375
+ zIndex: 51
376
+ },
377
+ onMouseEnter: handleTooltipMouseEnter,
378
+ onMouseLeave: handleTooltipMouseLeave,
379
+ ...getHoverFloatingProps(),
380
+ children: hoverTooltipContent
381
+ }
382
+ ),
383
+ viewportRef.current
312
384
  )
313
385
  ] });
314
386
  };
@@ -317,20 +389,14 @@ var useAnnotations = create((set) => ({
317
389
  addAnnotation: (annotation) => set((state) => ({
318
390
  annotations: [
319
391
  ...state.annotations,
320
- {
321
- ...annotation,
322
- id: v4(),
323
- createdAt: /* @__PURE__ */ new Date(),
324
- updatedAt: /* @__PURE__ */ new Date()
325
- }
392
+ annotation
326
393
  ]
327
394
  })),
328
395
  updateAnnotation: (id, updates) => set((state) => ({
329
396
  annotations: state.annotations.map(
330
397
  (annotation) => annotation.id === id ? {
331
398
  ...annotation,
332
- ...updates,
333
- updatedAt: /* @__PURE__ */ new Date()
399
+ ...updates
334
400
  } : annotation
335
401
  )
336
402
  })),
@@ -347,9 +413,11 @@ var AnnotationHighlightLayer = ({
347
413
  className,
348
414
  style,
349
415
  renderTooltipContent,
416
+ renderHoverTooltipContent,
350
417
  tooltipClassName,
351
418
  focusedAnnotationId,
352
- onAnnotationClick
419
+ onAnnotationClick,
420
+ hoverTooltipClassName
353
421
  }) => {
354
422
  const { annotations } = useAnnotations();
355
423
  const pageNumber = usePDFPageNumber();
@@ -361,6 +429,7 @@ var AnnotationHighlightLayer = ({
361
429
  {
362
430
  annotation,
363
431
  className: tooltipClassName,
432
+ hoverClassName: hoverTooltipClassName,
364
433
  isOpen: focusedAnnotationId === annotation.id,
365
434
  onOpenChange: (open) => {
366
435
  if (open && onAnnotationClick) {
@@ -372,6 +441,11 @@ var AnnotationHighlightLayer = ({
372
441
  onClose: () => {
373
442
  }
374
443
  }),
444
+ hoverTooltipContent: renderHoverTooltipContent({
445
+ annotation,
446
+ onClose: () => {
447
+ }
448
+ }),
375
449
  children: /* @__PURE__ */ jsx(
376
450
  "div",
377
451
  {
@@ -1078,7 +1152,27 @@ var SelectionTooltip = ({ children }) => {
1078
1152
  const handleSelectionChange = () => {
1079
1153
  const selection = document.getSelection();
1080
1154
  if (selection && viewportRef.current?.contains(selection.anchorNode)) {
1081
- requestAnimationFrame(updateTooltipPosition);
1155
+ const anchorNode = selection.anchorNode;
1156
+ const focusNode = selection.focusNode;
1157
+ const isInUnselectableArea = (node) => {
1158
+ if (!node) return false;
1159
+ let element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
1160
+ while (element) {
1161
+ if (element.getAttribute("data-annotation-tooltip")) {
1162
+ return true;
1163
+ }
1164
+ if (element.hasAttribute("data-floating-ui-portal")) {
1165
+ return true;
1166
+ }
1167
+ element = element.parentElement;
1168
+ }
1169
+ return false;
1170
+ };
1171
+ if (!isInUnselectableArea(anchorNode) && !isInUnselectableArea(focusNode)) {
1172
+ requestAnimationFrame(updateTooltipPosition);
1173
+ } else {
1174
+ setIsOpen(false);
1175
+ }
1082
1176
  } else {
1083
1177
  setIsOpen(false);
1084
1178
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anaralabs/lector",
3
- "version": "3.5.2",
3
+ "version": "3.5.4",
4
4
  "description": "Headless PDF viewer for React",
5
5
  "author": "andrewdr (https://github.com/andrewdoro)",
6
6
  "license": "MIT",