@pdfme/ui 1.0.5 → 1.0.8

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.
Files changed (35) hide show
  1. package/README.md +30 -2
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.LICENSE.txt +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/types/class.d.ts +1 -1
  6. package/dist/types/components/{Preview/Pager/Page.d.ts → CtlBar/Pager.d.ts} +0 -0
  7. package/dist/types/components/CtlBar/Zoom.d.ts +6 -0
  8. package/dist/types/components/CtlBar/index.d.ts +11 -0
  9. package/dist/types/components/Paper.d.ts +2 -2
  10. package/dist/types/components/{Preview/index.d.ts → Preview.d.ts} +0 -0
  11. package/dist/types/components/UnitPager.d.ts +9 -0
  12. package/dist/types/contexts.d.ts +1 -1
  13. package/dist/types/helper.d.ts +4 -0
  14. package/dist/types/hooks.d.ts +4 -4
  15. package/dist/types/i18n.d.ts +2 -0
  16. package/package.json +9 -1
  17. package/src/assets/icons/add.svg +3 -0
  18. package/src/assets/icons/remove.svg +3 -0
  19. package/src/components/CtlBar/Pager.tsx +60 -0
  20. package/src/components/CtlBar/Zoom.tsx +57 -0
  21. package/src/components/CtlBar/index.tsx +49 -0
  22. package/src/components/Designer/Main/index.tsx +2 -2
  23. package/src/components/Designer/Sidebar/index.tsx +9 -4
  24. package/src/components/Designer/index.tsx +28 -12
  25. package/src/components/Error.tsx +1 -1
  26. package/src/components/Paper.tsx +3 -2
  27. package/src/components/{Preview/index.tsx → Preview.tsx} +48 -38
  28. package/src/components/Root.tsx +1 -1
  29. package/src/components/UnitPager.tsx +105 -0
  30. package/src/helper.ts +14 -0
  31. package/src/hooks.ts +16 -18
  32. package/src/i18n.ts +4 -0
  33. package/dist/types/components/Preview/Pager/Unit.d.ts +0 -7
  34. package/src/components/Preview/Pager/Page.tsx +0 -85
  35. package/src/components/Preview/Pager/Unit.tsx +0 -87
@@ -7,7 +7,7 @@ export declare abstract class BaseUIClass {
7
7
  private font;
8
8
  private readonly setSize;
9
9
  constructor(props: UIProps);
10
- protected getI18n(): (key: "type" | "field" | "cancel" | "fieldName" | "require" | "uniq" | "inputExample" | "edit" | "plsSelect" | "plsInputName" | "plsAddNewField" | "fieldMustUniq" | "notUniq" | "noKeyName" | "fieldsList" | "addNewField" | "editField" | "goToFirst" | "goToPrevious" | "goToNext" | "goToEnd" | "select" | "errorOccurred" | "errorBulkUpdateFieldName" | "commitBulkUpdateFieldName" | "bulkUpdateFieldName") => string;
10
+ protected getI18n(): (key: "type" | "field" | "cancel" | "fieldName" | "require" | "uniq" | "inputExample" | "edit" | "plsSelect" | "plsInputName" | "plsAddNewField" | "fieldMustUniq" | "notUniq" | "noKeyName" | "fieldsList" | "addNewField" | "editField" | "goToFirst" | "goToPrevious" | "goToNext" | "goToEnd" | "select" | "zoomIn" | "zoomOut" | "errorOccurred" | "errorBulkUpdateFieldName" | "commitBulkUpdateFieldName" | "bulkUpdateFieldName") => string;
11
11
  protected getFont(): Record<string, {
12
12
  fallback?: boolean | undefined;
13
13
  subset?: boolean | undefined;
@@ -0,0 +1,6 @@
1
+ declare type Props = {
2
+ zoomLevel: number;
3
+ setZoomLevel: (zoom: number) => void;
4
+ };
5
+ declare const Pager: ({ zoomLevel, setZoomLevel }: Props) => JSX.Element;
6
+ export default Pager;
@@ -0,0 +1,11 @@
1
+ import { Size } from '@pdfme/common';
2
+ declare type Props = {
3
+ size: Size;
4
+ pageCursor: number;
5
+ pageNum: number;
6
+ setPageCursor: (page: number) => void;
7
+ zoomLevel: number;
8
+ setZoomLevel: (zoom: number) => void;
9
+ };
10
+ declare const CtlBar: (props: Props) => JSX.Element;
11
+ export default CtlBar;
@@ -1,7 +1,7 @@
1
- import React, { MutableRefObject, ReactNode } from 'react';
1
+ import { MutableRefObject, ReactNode } from 'react';
2
2
  import { SchemaForUI, Size } from '@pdfme/common';
3
3
  declare const Paper: (porps: {
4
- paperRefs?: React.MutableRefObject<HTMLDivElement[]> | undefined;
4
+ paperRefs: MutableRefObject<HTMLDivElement[]>;
5
5
  scale: number;
6
6
  size: Size;
7
7
  schemasList: SchemaForUI[][];
@@ -0,0 +1,9 @@
1
+ import { Size } from '@pdfme/common';
2
+ declare type Props = {
3
+ size: Size;
4
+ unitCursor: number;
5
+ unitNum: number;
6
+ setUnitCursor: (page: number) => void;
7
+ };
8
+ declare const UnitPager: ({ size, unitCursor, unitNum, setUnitCursor }: Props) => JSX.Element;
9
+ export default UnitPager;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- export declare const I18nContext: import("react").Context<(key: "type" | "field" | "cancel" | "fieldName" | "require" | "uniq" | "inputExample" | "edit" | "plsSelect" | "plsInputName" | "plsAddNewField" | "fieldMustUniq" | "notUniq" | "noKeyName" | "fieldsList" | "addNewField" | "editField" | "goToFirst" | "goToPrevious" | "goToNext" | "goToEnd" | "select" | "errorOccurred" | "errorBulkUpdateFieldName" | "commitBulkUpdateFieldName" | "bulkUpdateFieldName") => string>;
2
+ export declare const I18nContext: import("react").Context<(key: "type" | "field" | "cancel" | "fieldName" | "require" | "uniq" | "inputExample" | "edit" | "plsSelect" | "plsInputName" | "plsAddNewField" | "fieldMustUniq" | "notUniq" | "noKeyName" | "fieldsList" | "addNewField" | "editField" | "goToFirst" | "goToPrevious" | "goToNext" | "goToEnd" | "select" | "zoomIn" | "zoomOut" | "errorOccurred" | "errorBulkUpdateFieldName" | "commitBulkUpdateFieldName" | "bulkUpdateFieldName") => string>;
3
3
  export declare const FontContext: import("react").Context<Record<string, {
4
4
  fallback?: boolean | undefined;
5
5
  subset?: boolean | undefined;
@@ -89,4 +89,8 @@ export declare const moveCommandToChangeSchemasArg: (props: {
89
89
  value: number;
90
90
  schemaId: string;
91
91
  }[];
92
+ export declare const getPagesScrollTopByIndex: (pageSizes: {
93
+ width: number;
94
+ height: number;
95
+ }[], index: number, scale: number) => number;
92
96
  export {};
@@ -4,9 +4,9 @@ export declare const usePrevious: <T>(value: T) => T | null;
4
4
  declare type UIPreProcessorProps = {
5
5
  template: Template;
6
6
  size: Size;
7
- offset?: number;
7
+ zoomLevel: number;
8
8
  };
9
- export declare const useUIPreProcessor: ({ template, size, offset }: UIPreProcessorProps) => {
9
+ export declare const useUIPreProcessor: ({ template, size, zoomLevel }: UIPreProcessorProps) => {
10
10
  backgrounds: string[];
11
11
  pageSizes: {
12
12
  width: number;
@@ -16,12 +16,12 @@ export declare const useUIPreProcessor: ({ template, size, offset }: UIPreProces
16
16
  error: Error | null;
17
17
  };
18
18
  declare type ScrollPageCursorProps = {
19
- rootRef: RefObject<HTMLDivElement>;
19
+ ref: RefObject<HTMLDivElement>;
20
20
  pageSizes: Size[];
21
21
  scale: number;
22
22
  pageCursor: number;
23
23
  onChangePageCursor: (page: number) => void;
24
24
  };
25
- export declare const useScrollPageCursor: ({ rootRef, pageSizes, scale, pageCursor, onChangePageCursor, }: ScrollPageCursorProps) => void;
25
+ export declare const useScrollPageCursor: ({ ref, pageSizes, scale, pageCursor, onChangePageCursor, }: ScrollPageCursorProps) => void;
26
26
  export declare const useMountStatus: () => boolean;
27
27
  export {};
@@ -23,6 +23,8 @@ declare const dictEn: {
23
23
  goToNext: string;
24
24
  goToEnd: string;
25
25
  select: string;
26
+ zoomIn: string;
27
+ zoomOut: string;
26
28
  errorOccurred: string;
27
29
  errorBulkUpdateFieldName: string;
28
30
  commitBulkUpdateFieldName: string;
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "@pdfme/ui",
3
- "version": "1.0.5",
3
+ "version": "1.0.8",
4
4
  "author": "hand-dot",
5
5
  "license": "MIT",
6
+ "keywords": [
7
+ "pdf",
8
+ "pdf-generation",
9
+ "pdf-designer",
10
+ "pdf-viewer",
11
+ "typescript",
12
+ "react"
13
+ ],
6
14
  "description": "TypeScript base PDF generator and React base UI. Open source, developed by the community, and completely free to use under the MIT license!",
7
15
  "homepage": "https://pdfme.com",
8
16
  "repository": {
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
2
+ <path d="M22.5 38V25.5H10V22.5H22.5V10H25.5V22.5H38V25.5H25.5V38Z" fill="#ffffff" />
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
2
+ <path d="M10 25.5V22.5H38V25.5Z" fill="#ffffff" />
3
+ </svg>
@@ -0,0 +1,60 @@
1
+ import React, { useContext } from 'react';
2
+ import left from '../../assets/icons/left.svg';
3
+ import right from '../../assets/icons/right.svg';
4
+ import { I18nContext } from '../../contexts';
5
+
6
+ const btnStyle: React.CSSProperties = {
7
+ cursor: 'pointer',
8
+ border: 'none',
9
+ background: 'none',
10
+ display: 'flex',
11
+ alignItems: 'center',
12
+ };
13
+
14
+ type Props = {
15
+ pageCursor: number;
16
+ pageNum: number;
17
+ setPageCursor: (page: number) => void;
18
+ };
19
+
20
+ const Pager = ({ pageCursor, pageNum, setPageCursor }: Props) => {
21
+ const i18n = useContext(I18nContext);
22
+
23
+ return (
24
+ <div
25
+ style={{
26
+ display: 'flex',
27
+ alignItems: 'center',
28
+ justifyContent: 'center',
29
+ }}
30
+ >
31
+ <button
32
+ style={{
33
+ paddingLeft: '0.5rem',
34
+ ...btnStyle,
35
+ cursor: pageCursor <= 0 ? 'not-allowed' : 'pointer',
36
+ }}
37
+ disabled={pageCursor <= 0}
38
+ onClick={() => setPageCursor(pageCursor - 1)}
39
+ >
40
+ <img src={left} alt={i18n('goToPrevious')} style={{ width: 20 }} />
41
+ </button>
42
+ <strong style={{ color: 'white', fontSize: '0.9rem' }}>
43
+ {pageCursor + 1}/{pageNum}
44
+ </strong>
45
+ <button
46
+ style={{
47
+ paddingRight: '0.5rem',
48
+ ...btnStyle,
49
+ cursor: pageCursor + 1 >= pageNum ? 'not-allowed' : 'pointer',
50
+ }}
51
+ disabled={pageCursor + 1 >= pageNum}
52
+ onClick={() => setPageCursor(pageCursor + 1)}
53
+ >
54
+ <img src={right} alt={i18n('goToNext')} style={{ width: 20 }} />
55
+ </button>
56
+ </div>
57
+ );
58
+ };
59
+
60
+ export default Pager;
@@ -0,0 +1,57 @@
1
+ import React, { useContext } from 'react';
2
+ import { I18nContext } from '../../contexts';
3
+ import add from '../../assets/icons/add.svg';
4
+ import remove from '../../assets/icons/remove.svg';
5
+
6
+ const btnStyle: React.CSSProperties = {
7
+ cursor: 'pointer',
8
+ border: 'none',
9
+ background: 'none',
10
+ display: 'flex',
11
+ alignItems: 'center',
12
+ };
13
+
14
+ const zoomStep = 0.25;
15
+ const maxZoom = 2;
16
+ const minZoom = 0.25;
17
+
18
+ type Props = {
19
+ zoomLevel: number;
20
+ setZoomLevel: (zoom: number) => void;
21
+ };
22
+
23
+ const Pager = ({ zoomLevel, setZoomLevel }: Props) => {
24
+ const i18n = useContext(I18nContext);
25
+ const nextZoomOut = zoomLevel - zoomStep;
26
+ const nextZoomIn = zoomLevel + zoomStep;
27
+
28
+ return (
29
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
30
+ <button
31
+ style={{
32
+ paddingRight: '0.5rem',
33
+ ...btnStyle,
34
+ cursor: minZoom >= nextZoomOut ? 'not-allowed' : 'pointer',
35
+ }}
36
+ onClick={() => setZoomLevel(nextZoomOut)}
37
+ disabled={minZoom >= nextZoomOut}
38
+ >
39
+ <img src={remove} alt={i18n('zoomOut')} style={{ width: 20 }} />
40
+ </button>
41
+ <strong style={{ color: 'white', fontSize: '0.9rem' }}>{Math.round(zoomLevel * 100)}%</strong>
42
+ <button
43
+ style={{
44
+ paddingRight: '0.5rem',
45
+ ...btnStyle,
46
+ cursor: maxZoom < nextZoomIn ? 'not-allowed' : 'pointer',
47
+ }}
48
+ onClick={() => setZoomLevel(nextZoomIn)}
49
+ disabled={maxZoom < nextZoomIn}
50
+ >
51
+ <img src={add} alt={i18n('zoomIn')} style={{ width: 20 }} />
52
+ </button>
53
+ </div>
54
+ );
55
+ };
56
+
57
+ export default Pager;
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import Pager from './Pager';
3
+ import Zoom from './Zoom';
4
+ import { Size } from '@pdfme/common';
5
+
6
+ type Props = {
7
+ size: Size;
8
+ pageCursor: number;
9
+ pageNum: number;
10
+ setPageCursor: (page: number) => void;
11
+ zoomLevel: number;
12
+ setZoomLevel: (zoom: number) => void;
13
+ };
14
+
15
+ const barWidth = 220;
16
+
17
+ const CtlBar = (props: Props) => {
18
+ const { size, pageCursor, pageNum, setPageCursor, zoomLevel, setZoomLevel } = props;
19
+ const width = pageNum > 1 ? barWidth : barWidth / 2;
20
+ return (
21
+ <div style={{ position: 'absolute', ...size }}>
22
+ <div
23
+ style={{
24
+ display: 'flex',
25
+ alignItems: 'center',
26
+ justifyContent: 'center',
27
+ position: 'sticky',
28
+ zIndex: 1,
29
+ top: '90%',
30
+ left: `calc(50% - ${width / 2}px)`,
31
+ width,
32
+ background: '#777777e6',
33
+ borderRadius: 2,
34
+ padding: '0.5rem',
35
+ }}
36
+ >
37
+ {pageNum > 1 && (
38
+ <>
39
+ <Pager pageCursor={pageCursor} pageNum={pageNum} setPageCursor={setPageCursor} />
40
+ <strong style={{ color: 'white', fontSize: '0.9rem', padding: 0 }}>|</strong>
41
+ </>
42
+ )}
43
+ <Zoom zoomLevel={zoomLevel} setZoomLevel={setZoomLevel} />
44
+ </div>
45
+ </div>
46
+ );
47
+ };
48
+
49
+ export default CtlBar;
@@ -218,7 +218,7 @@ const Main = (props: Props, ref: Ref<HTMLDivElement>) => {
218
218
  e.stopPropagation();
219
219
  setEditing(false);
220
220
  }}
221
- style={{ height: props.height }}
221
+ style={{ overflowX: 'auto' }}
222
222
  >
223
223
  <Selecto
224
224
  container={paperRefs.current[pageCursor]}
@@ -279,7 +279,7 @@ const Main = (props: Props, ref: Ref<HTMLDivElement>) => {
279
279
  {pageCursor !== index ? (
280
280
  <Mask
281
281
  width={paperSize.width + RULER_HEIGHT}
282
- height={paperSize.height + RULER_HEIGHT}
282
+ height={paperSize.height + RULER_HEIGHT * scale}
283
283
  />
284
284
  ) : (
285
285
  !editing && (
@@ -27,7 +27,6 @@ const Sidebar = (props: SidebarProps) => {
27
27
 
28
28
  const i18n = useContext(I18nContext);
29
29
  const [open, setOpen] = useState(true);
30
- const top = 0;
31
30
 
32
31
  const getActiveSchemas = () => {
33
32
  const ids = activeElements.map((ae) => ae.id);
@@ -41,9 +40,15 @@ const Sidebar = (props: SidebarProps) => {
41
40
 
42
41
  return (
43
42
  <div
44
- style={{ position: 'absolute', right: 0, zIndex: 1, height, width: open ? SIDEBAR_WIDTH : 0 }}
43
+ style={{
44
+ position: 'absolute',
45
+ right: 0,
46
+ zIndex: 1,
47
+ height: height ? height : '100%',
48
+ width: open ? SIDEBAR_WIDTH : 0,
49
+ }}
45
50
  >
46
- <div style={{ position: 'sticky', top, zIndex: 1, fontSize: '1rem' }}>
51
+ <div style={{ position: 'sticky', top: 0, zIndex: 1, fontSize: '1rem' }}>
47
52
  <button
48
53
  style={{
49
54
  position: 'absolute',
@@ -66,7 +71,7 @@ const Sidebar = (props: SidebarProps) => {
66
71
  width: SIDEBAR_WIDTH,
67
72
  height: size.height - RULER_HEIGHT * ZOOM,
68
73
  display: open ? 'block' : 'none',
69
- top,
74
+ top: RULER_HEIGHT / 2,
70
75
  right: 0,
71
76
  position: 'absolute',
72
77
  background: '#ffffffed',
@@ -17,10 +17,12 @@ import {
17
17
  getKeepRatioHeightByWidth,
18
18
  getUniqSchemaKey,
19
19
  moveCommandToChangeSchemasArg,
20
+ getPagesScrollTopByIndex,
20
21
  } from '../../helper';
21
22
  import { useUIPreProcessor, useScrollPageCursor } from '../../hooks';
22
23
  import Root from '../Root';
23
24
  import Error from '../Error';
25
+ import CtlBar from '../CtlBar';
24
26
 
25
27
  const TemplateEditor = ({
26
28
  template,
@@ -31,22 +33,18 @@ const TemplateEditor = ({
31
33
  const copiedSchemas = useRef<SchemaForUI[] | null>(null);
32
34
  const past = useRef<SchemaForUI[][]>([]);
33
35
  const future = useRef<SchemaForUI[][]>([]);
34
- const rootRef = useRef<HTMLDivElement>(null);
35
36
  const mainRef = useRef<HTMLDivElement>(null);
36
37
  const paperRefs = useRef<HTMLDivElement[]>([]);
37
38
 
38
39
  const i18n = useContext(I18nContext);
39
40
 
40
- const { backgrounds, pageSizes, scale, error } = useUIPreProcessor({
41
- template,
42
- size,
43
- offset: RULER_HEIGHT,
44
- });
45
-
46
41
  const [hoveringSchemaId, setHoveringSchemaId] = useState<string | null>(null);
47
42
  const [activeElements, setActiveElements] = useState<HTMLElement[]>([]);
48
43
  const [schemasList, setSchemasList] = useState<SchemaForUI[][]>([[]] as SchemaForUI[][]);
49
44
  const [pageCursor, setPageCursor] = useState(0);
45
+ const [zoomLevel, setZoomLevel] = useState(1);
46
+
47
+ const { backgrounds, pageSizes, scale, error } = useUIPreProcessor({ template, size, zoomLevel });
50
48
 
51
49
  const onEdit = (targets: HTMLElement[]) => {
52
50
  setActiveElements(targets);
@@ -59,7 +57,7 @@ const TemplateEditor = ({
59
57
  };
60
58
 
61
59
  useScrollPageCursor({
62
- rootRef,
60
+ ref: mainRef,
63
61
  pageSizes,
64
62
  scale,
65
63
  pageCursor,
@@ -190,8 +188,8 @@ const TemplateEditor = ({
190
188
  setSchemasList(sl);
191
189
  onEditEnd();
192
190
  setPageCursor(0);
193
- if (rootRef.current?.scroll) {
194
- rootRef.current.scroll({ top: 0, behavior: 'smooth' });
191
+ if (mainRef.current?.scroll) {
192
+ mainRef.current.scroll({ top: 0, behavior: 'smooth' });
195
193
  }
196
194
  }, []);
197
195
 
@@ -229,11 +227,29 @@ const TemplateEditor = ({
229
227
  }
230
228
 
231
229
  return (
232
- <Root ref={rootRef} size={size} scale={scale}>
230
+ <Root size={size} scale={scale}>
231
+ <CtlBar
232
+ size={{ ...size }}
233
+ pageCursor={pageCursor}
234
+ pageNum={schemasList.length}
235
+ setPageCursor={(p) => {
236
+ if (!mainRef.current) return;
237
+ mainRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, p, scale);
238
+ setPageCursor(p);
239
+ onEditEnd();
240
+ }}
241
+ zoomLevel={zoomLevel}
242
+ setZoomLevel={(zoom) => {
243
+ if (mainRef.current) {
244
+ mainRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, pageCursor, scale);
245
+ }
246
+ setZoomLevel(zoom);
247
+ }}
248
+ />
233
249
  <Sidebar
234
250
  hoveringSchemaId={hoveringSchemaId}
235
251
  onChangeHoveringSchemaId={onChangeHoveringSchemaId}
236
- height={mainRef.current ? mainRef.current.scrollHeight : 0}
252
+ height={mainRef.current ? mainRef.current.clientHeight : 0}
237
253
  size={size}
238
254
  pageSize={pageSizes[pageCursor]}
239
255
  activeElements={activeElements}
@@ -10,7 +10,7 @@ const Error = ({ size, error }: { size: Size; error: Error }) => {
10
10
  style={{
11
11
  position: 'relative',
12
12
  background: 'rgb(74, 74, 74)',
13
- overflowY: 'auto',
13
+ overflow: 'auto',
14
14
  display: 'flex',
15
15
  alignItems: 'center',
16
16
  justifyContent: 'center',
@@ -4,7 +4,7 @@ import { FontContext } from '../contexts';
4
4
  import { ZOOM, RULER_HEIGHT } from '../constants';
5
5
 
6
6
  const Paper = (porps: {
7
- paperRefs?: MutableRefObject<HTMLDivElement[]>;
7
+ paperRefs: MutableRefObject<HTMLDivElement[]>;
8
8
  scale: number;
9
9
  size: Size;
10
10
  schemasList: SchemaForUI[][];
@@ -28,6 +28,7 @@ const Paper = (porps: {
28
28
  style={{
29
29
  transform: `scale(${scale})`,
30
30
  transformOrigin: size.width <= topPageWidth * ZOOM * scale ? `left top` : `center top`,
31
+ ...size,
31
32
  }}
32
33
  >
33
34
  {backgrounds.map((background, paperIndex) => {
@@ -39,7 +40,7 @@ const Paper = (porps: {
39
40
  id={`@pdfme/ui-paper${paperIndex}`}
40
41
  key={paperIndex + JSON.stringify(paperSize)}
41
42
  ref={(e) => {
42
- if (e && paperRefs) {
43
+ if (e) {
43
44
  paperRefs.current[paperIndex] = e;
44
45
  }
45
46
  }}
@@ -1,28 +1,26 @@
1
1
  import React, { useCallback, useRef, useState, useEffect } from 'react';
2
2
  import { PreviewReactProps, SchemaForUI } from '@pdfme/common';
3
- import { ZOOM, RULER_HEIGHT } from '../../constants';
4
- import PagePager from './Pager/Page';
5
- import UnitPager from './Pager/Unit';
6
- import Root from '../Root';
7
- import Error from '../Error';
8
- import Paper from '../Paper';
9
- import SchemaUI from '../Schemas/SchemaUI';
10
- import { useUIPreProcessor, useScrollPageCursor } from '../../hooks';
11
- import { templateSchemas2SchemasList, px2mm } from '../../helper';
3
+ import { ZOOM, RULER_HEIGHT } from '../constants';
4
+ import UnitPager from './UnitPager';
5
+ import Root from './Root';
6
+ import Error from './Error';
7
+ import CtlBar from './CtlBar';
8
+ import Paper from './Paper';
9
+ import SchemaUI from './Schemas/SchemaUI';
10
+ import { useUIPreProcessor, useScrollPageCursor } from '../hooks';
11
+ import { templateSchemas2SchemasList, getPagesScrollTopByIndex } from '../helper';
12
12
 
13
13
  const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) => {
14
- const { backgrounds, pageSizes, scale, error } = useUIPreProcessor({
15
- template,
16
- size,
17
- offset: RULER_HEIGHT,
18
- });
19
-
20
14
  const rootRef = useRef<HTMLDivElement>(null);
15
+ const paperRefs = useRef<HTMLDivElement[]>([]);
21
16
 
22
17
  const [unitCursor, setUnitCursor] = useState(0);
23
18
  const [pageCursor, setPageCursor] = useState(0);
19
+ const [zoomLevel, setZoomLevel] = useState(1);
24
20
  const [schemasList, setSchemasList] = useState<SchemaForUI[][]>([[]] as SchemaForUI[][]);
25
21
 
22
+ const { backgrounds, pageSizes, scale, error } = useUIPreProcessor({ template, size, zoomLevel });
23
+
26
24
  const init = useCallback(async () => {
27
25
  const sl = await templateSchemas2SchemasList(template);
28
26
  setSchemasList(sl);
@@ -33,7 +31,7 @@ const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) =
33
31
  }, [init]);
34
32
 
35
33
  useScrollPageCursor({
36
- rootRef,
34
+ ref: rootRef,
37
35
  pageSizes,
38
36
  scale,
39
37
  pageCursor,
@@ -50,32 +48,44 @@ const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) =
50
48
  return <Error size={size} error={error} />;
51
49
  }
52
50
 
51
+ const pageSizesHeightSum = pageSizes.reduce(
52
+ (acc, cur) => acc + (cur.height * ZOOM + RULER_HEIGHT * scale) * scale,
53
+ 0
54
+ );
55
+
56
+ const pageSizesMaxWidth = pageSizes.reduce(
57
+ (acc, cur) => Math.max(acc, cur.height * ZOOM * scale),
58
+ 0
59
+ );
60
+
53
61
  return (
54
62
  <Root ref={rootRef} size={size} scale={scale}>
55
- <div
56
- style={{
57
- height:
58
- pageSizes.reduce((acc, cur) => acc + (cur.height + px2mm(RULER_HEIGHT)) * scale, 0) +
59
- 'mm',
60
- width: '100%',
61
- top: 0,
62
- position: 'absolute',
63
+ <CtlBar
64
+ size={{ height: pageSizesHeightSum, width: Math.max(size.width, pageSizesMaxWidth) }}
65
+ pageCursor={pageCursor}
66
+ pageNum={schemasList.length}
67
+ setPageCursor={(p) => {
68
+ if (!rootRef.current) return;
69
+ rootRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, p, scale);
70
+ setPageCursor(p);
71
+ }}
72
+ zoomLevel={zoomLevel}
73
+ setZoomLevel={(zoom) => {
74
+ if (rootRef.current) {
75
+ rootRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, pageCursor, scale);
76
+ }
77
+ setZoomLevel(zoom);
63
78
  }}
64
- >
65
- <UnitPager unitCursor={unitCursor} unitNum={inputs.length} setUnitCursor={setUnitCursor} />
66
- <PagePager
67
- pageCursor={pageCursor}
68
- pageNum={schemasList.length}
69
- setPageCursor={(p) => {
70
- if (!rootRef.current) return;
71
- rootRef.current.scrollTop = pageSizes
72
- .slice(0, p)
73
- .reduce((acc, cur) => acc + (cur.height * ZOOM + RULER_HEIGHT) * scale, 0);
74
- setPageCursor(p);
75
- }}
76
- />
77
- </div>
79
+ />
80
+ <UnitPager
81
+ size={{ height: pageSizesHeightSum, width: Math.max(size.width, pageSizesMaxWidth) }}
82
+ unitCursor={unitCursor}
83
+ unitNum={inputs.length}
84
+ setUnitCursor={setUnitCursor}
85
+ />
86
+
78
87
  <Paper
88
+ paperRefs={paperRefs}
79
89
  scale={scale}
80
90
  size={size}
81
91
  schemasList={schemasList}
@@ -29,7 +29,7 @@ const Root = ({ size, scale, children }: Props, ref: Ref<HTMLDivElement>) => {
29
29
  return (
30
30
  <div
31
31
  ref={ref}
32
- style={{ position: 'relative', background: 'rgb(74, 74, 74)', overflowY: 'auto', ...size }}
32
+ style={{ position: 'relative', background: 'rgb(74, 74, 74)', overflow: 'auto', ...size }}
33
33
  >
34
34
  <div
35
35
  style={{