index.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import React, {
  2. useEffect, useState, useRef, useCallback,
  3. } from 'react';
  4. import { WithTranslation } from 'next-i18next';
  5. import { withTranslation } from '../../i18n';
  6. import Typography from '../Typography';
  7. import Item from '../AnnotationItem';
  8. import {
  9. AnnotationType, ViewportType, ScrollStateType, PositionType,
  10. } from '../../constants/type';
  11. import { watchScroll } from '../../helpers/utility';
  12. import { getAnnotationText } from '../../helpers/annotation';
  13. import { Body } from '../../global/sidebarStyled';
  14. type i18nProps = {
  15. t: (key: string) => string;
  16. };
  17. type OwnerProps = {
  18. isActive?: boolean;
  19. annotations: AnnotationType[];
  20. viewport: ViewportType;
  21. scale: number;
  22. pdf: any;
  23. };
  24. type Props = i18nProps & OwnerProps;
  25. const AnnotationList: React.FC<Props> = ({
  26. t,
  27. isActive = false,
  28. annotations,
  29. viewport,
  30. scale,
  31. pdf,
  32. }: Props) => {
  33. const [renderQueue, setQueue] = useState<AnnotationType[]>([]);
  34. const containerRef = useRef<HTMLDivElement>(null);
  35. const innerRef = useRef<HTMLDivElement>(null);
  36. const getText = async (page: number, position: PositionType[]): Promise<any> => {
  37. const text = await getAnnotationText({
  38. pdf,
  39. viewport,
  40. scale,
  41. page,
  42. coords: position,
  43. });
  44. return text;
  45. };
  46. const scrollUpdate = useCallback((state: ScrollStateType): void => {
  47. const innerHeight = innerRef.current?.offsetHeight || 0;
  48. const wrapperHeight = containerRef.current?.offsetHeight || 0;
  49. if (
  50. wrapperHeight + state.lastY >= innerHeight
  51. && renderQueue.length !== annotations.length
  52. ) {
  53. const start = renderQueue.length;
  54. const end = renderQueue.length + 10;
  55. const newQueue = [...renderQueue, ...annotations.slice(start, end)];
  56. setQueue(newQueue);
  57. }
  58. }, [renderQueue, annotations]);
  59. useEffect(() => {
  60. const state = watchScroll(containerRef.current, scrollUpdate);
  61. return (): void => {
  62. state.subscriber.unsubscribe();
  63. };
  64. }, [scrollUpdate]);
  65. useEffect(() => {
  66. if (isActive) {
  67. setQueue(annotations.slice(0, 10));
  68. }
  69. }, [isActive]);
  70. return (
  71. <Body ref={containerRef}>
  72. <div ref={innerRef}>
  73. <Typography light align="left">
  74. {`${annotations.length} ${t('annotation')}`}
  75. </Typography>
  76. {isActive && renderQueue.map((ele, index) => {
  77. const key = `annot_item_${index}`;
  78. const {
  79. obj_type,
  80. obj_attr: {
  81. page,
  82. bdcolor,
  83. position,
  84. transparency,
  85. },
  86. } = ele;
  87. const actualPage = page + 1;
  88. const prevPage = index > 0 ? annotations[index - 1].obj_attr.page + 1 : -1;
  89. return (
  90. <Item
  91. key={key}
  92. type={obj_type}
  93. page={actualPage}
  94. bdcolor={bdcolor || ''}
  95. transparency={transparency || 0}
  96. getText={(): Promise<any> => getText(actualPage, position as PositionType[])}
  97. showPageNum={actualPage !== prevPage}
  98. />
  99. );
  100. })}
  101. </div>
  102. </Body>
  103. );
  104. };
  105. const translator = withTranslation('sidebar');
  106. type TransProps = WithTranslation & OwnerProps;
  107. export default translator<TransProps>(AnnotationList);