@pdfme/ui 0.0.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.
Files changed (97) hide show
  1. package/README.md +9 -0
  2. package/__mocks__/assetsTransformer.js +7 -0
  3. package/__mocks__/form-render.js +7 -0
  4. package/__mocks__/lucide-react.js +19 -0
  5. package/dist/index.es.js +159393 -0
  6. package/dist/index.umd.js +1041 -0
  7. package/dist/types/__tests__/assets/helper.d.ts +3 -0
  8. package/dist/types/__tests__/components/Designer.test.d.ts +1 -0
  9. package/dist/types/__tests__/components/PluginIcon.test.d.ts +1 -0
  10. package/dist/types/__tests__/components/Preview.test.d.ts +1 -0
  11. package/dist/types/__tests__/helper.test.d.ts +1 -0
  12. package/dist/types/src/Designer.d.ts +21 -0
  13. package/dist/types/src/Form.d.ts +24 -0
  14. package/dist/types/src/Viewer.d.ts +15 -0
  15. package/dist/types/src/class.d.ts +89 -0
  16. package/dist/types/src/components/AppContextProvider.d.ts +11 -0
  17. package/dist/types/src/components/CtlBar.d.ts +14 -0
  18. package/dist/types/src/components/Designer/Canvas/Guides.d.ts +9 -0
  19. package/dist/types/src/components/Designer/Canvas/Mask.d.ts +4 -0
  20. package/dist/types/src/components/Designer/Canvas/Moveable.d.ts +37 -0
  21. package/dist/types/src/components/Designer/Canvas/Padding.d.ts +6 -0
  22. package/dist/types/src/components/Designer/Canvas/Selecto.d.ts +10 -0
  23. package/dist/types/src/components/Designer/Canvas/index.d.ts +22 -0
  24. package/dist/types/src/components/Designer/LeftSidebar.d.ts +8 -0
  25. package/dist/types/src/components/Designer/PluginIcon.d.ts +10 -0
  26. package/dist/types/src/components/Designer/RightSidebar/DetailView/AlignWidget.d.ts +4 -0
  27. package/dist/types/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.d.ts +4 -0
  28. package/dist/types/src/components/Designer/RightSidebar/DetailView/WidgetRenderer.d.ts +7 -0
  29. package/dist/types/src/components/Designer/RightSidebar/DetailView/index.d.ts +8 -0
  30. package/dist/types/src/components/Designer/RightSidebar/ListView/Item.d.ts +45 -0
  31. package/dist/types/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.d.ts +4 -0
  32. package/dist/types/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.d.ts +14 -0
  33. package/dist/types/src/components/Designer/RightSidebar/ListView/index.d.ts +4 -0
  34. package/dist/types/src/components/Designer/RightSidebar/index.d.ts +4 -0
  35. package/dist/types/src/components/Designer/RightSidebar/layout.d.ts +15 -0
  36. package/dist/types/src/components/Designer/index.d.ts +11 -0
  37. package/dist/types/src/components/ErrorScreen.d.ts +7 -0
  38. package/dist/types/src/components/Paper.d.ts +20 -0
  39. package/dist/types/src/components/Preview.d.ts +15 -0
  40. package/dist/types/src/components/Renderer.d.ts +13 -0
  41. package/dist/types/src/components/Root.d.ts +9 -0
  42. package/dist/types/src/components/Spinner.d.ts +3 -0
  43. package/dist/types/src/components/StaticSchema.d.ts +10 -0
  44. package/dist/types/src/components/UnitPager.d.ts +10 -0
  45. package/dist/types/src/constants.d.ts +11 -0
  46. package/dist/types/src/contexts.d.ts +10 -0
  47. package/dist/types/src/helper.d.ts +73 -0
  48. package/dist/types/src/hooks.d.ts +46 -0
  49. package/dist/types/src/i18n.d.ts +3 -0
  50. package/dist/types/src/index.d.ts +4 -0
  51. package/dist/types/src/theme.d.ts +2 -0
  52. package/dist/types/src/types.d.ts +19 -0
  53. package/eslint.config.mjs +41 -0
  54. package/package.json +127 -0
  55. package/src/Designer.tsx +107 -0
  56. package/src/Form.tsx +102 -0
  57. package/src/Viewer.tsx +59 -0
  58. package/src/class.ts +188 -0
  59. package/src/components/AppContextProvider.tsx +78 -0
  60. package/src/components/CtlBar.tsx +183 -0
  61. package/src/components/Designer/Canvas/Guides.tsx +49 -0
  62. package/src/components/Designer/Canvas/Mask.tsx +20 -0
  63. package/src/components/Designer/Canvas/Moveable.tsx +91 -0
  64. package/src/components/Designer/Canvas/Padding.tsx +56 -0
  65. package/src/components/Designer/Canvas/Selecto.tsx +45 -0
  66. package/src/components/Designer/Canvas/index.tsx +536 -0
  67. package/src/components/Designer/LeftSidebar.tsx +120 -0
  68. package/src/components/Designer/PluginIcon.tsx +87 -0
  69. package/src/components/Designer/RightSidebar/DetailView/AlignWidget.tsx +229 -0
  70. package/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.tsx +78 -0
  71. package/src/components/Designer/RightSidebar/DetailView/WidgetRenderer.tsx +28 -0
  72. package/src/components/Designer/RightSidebar/DetailView/index.tsx +469 -0
  73. package/src/components/Designer/RightSidebar/ListView/Item.tsx +158 -0
  74. package/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.tsx +204 -0
  75. package/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.tsx +88 -0
  76. package/src/components/Designer/RightSidebar/ListView/index.tsx +116 -0
  77. package/src/components/Designer/RightSidebar/index.tsx +72 -0
  78. package/src/components/Designer/RightSidebar/layout.tsx +75 -0
  79. package/src/components/Designer/index.tsx +389 -0
  80. package/src/components/ErrorScreen.tsx +33 -0
  81. package/src/components/Paper.tsx +117 -0
  82. package/src/components/Preview.tsx +220 -0
  83. package/src/components/Renderer.tsx +165 -0
  84. package/src/components/Root.tsx +38 -0
  85. package/src/components/Spinner.tsx +45 -0
  86. package/src/components/StaticSchema.tsx +50 -0
  87. package/src/components/UnitPager.tsx +119 -0
  88. package/src/constants.ts +21 -0
  89. package/src/contexts.ts +14 -0
  90. package/src/helper.ts +534 -0
  91. package/src/hooks.ts +308 -0
  92. package/src/i18n.ts +903 -0
  93. package/src/index.ts +5 -0
  94. package/src/theme.ts +20 -0
  95. package/src/types.ts +20 -0
  96. package/tsconfig.json +48 -0
  97. package/vite.config.mts +22 -0
@@ -0,0 +1,220 @@
1
+ import React, { useRef, useState, useEffect, useContext } from 'react';
2
+ import {
3
+ Template,
4
+ SchemaForUI,
5
+ PreviewProps,
6
+ Size,
7
+ getDynamicTemplate,
8
+ replacePlaceholders,
9
+ } from '@pdfme/common';
10
+ import { getDynamicHeightsForTable } from '@pdfme/schemas/utils';
11
+ import UnitPager from './UnitPager.js';
12
+ import Root from './Root.js';
13
+ import StaticSchema from './StaticSchema.js';
14
+ import ErrorScreen from './ErrorScreen.js';
15
+ import CtlBar from './CtlBar.js';
16
+ import Paper from './Paper.js';
17
+ import Renderer from './Renderer.js';
18
+ import { useUIPreProcessor, useScrollPageCursor } from '../hooks.js';
19
+ import { FontContext, OptionsContext } from '../contexts.js';
20
+ import { template2SchemasList, getPagesScrollTopByIndex, useMaxZoom } from '../helper.js';
21
+ import { theme } from 'antd';
22
+
23
+ const _cache = new Map<string | number, unknown>();
24
+
25
+ const Preview = ({
26
+ template,
27
+ inputs,
28
+ size,
29
+ onChangeInput,
30
+ onPageChange,
31
+ }: Omit<PreviewProps, 'domContainer'> & {
32
+ onChangeInput?: (args: { index: number; value: string; name: string }) => void;
33
+ onPageChange?: (pageInfo: { currentPage: number; totalPages: number }) => void;
34
+ size: Size;
35
+ }) => {
36
+ const { token } = theme.useToken();
37
+
38
+ const font = useContext(FontContext);
39
+ const options = useContext(OptionsContext);
40
+ const maxZoom = useMaxZoom();
41
+
42
+ const containerRef = useRef<HTMLDivElement>(null);
43
+ const paperRefs = useRef<HTMLDivElement[]>([]);
44
+
45
+ const [unitCursor, setUnitCursor] = useState(0);
46
+ const [pageCursor, setPageCursor] = useState(0);
47
+ const [zoomLevel, setZoomLevel] = useState(options.zoomLevel ?? 1);
48
+ const [schemasList, setSchemasList] = useState<SchemaForUI[][]>([[]] as SchemaForUI[][]);
49
+
50
+ const { backgrounds, pageSizes, scale, error, refresh } = useUIPreProcessor({
51
+ template,
52
+ size,
53
+ zoomLevel,
54
+ maxZoom,
55
+ });
56
+
57
+ const isForm = Boolean(onChangeInput);
58
+
59
+ const input = inputs[unitCursor];
60
+
61
+ const init = (template: Template) => {
62
+ const options = { font };
63
+ getDynamicTemplate({
64
+ template,
65
+ input,
66
+ options,
67
+ _cache,
68
+ getDynamicHeights: (value, args) => {
69
+ switch (args.schema.type) {
70
+ case 'table':
71
+ return getDynamicHeightsForTable(value, args);
72
+ default:
73
+ return Promise.resolve([args.schema.height]);
74
+ }
75
+ },
76
+ })
77
+ .then(async (dynamicTemplate) => {
78
+ const sl = await template2SchemasList(dynamicTemplate);
79
+ setSchemasList(sl);
80
+ await refresh(dynamicTemplate);
81
+ })
82
+ .catch((err) => console.error(`[@pdfme/ui] `, err));
83
+ };
84
+
85
+ // Update component state only when _options_ changes
86
+ // Ignore exhaustive useEffect dependency warnings here
87
+ useEffect(() => {
88
+ if (typeof options.zoomLevel === 'number' && options.zoomLevel !== zoomLevel) {
89
+ setZoomLevel(options.zoomLevel);
90
+ }
91
+ // eslint-disable-next-line
92
+ }, [options]);
93
+
94
+ useEffect(() => {
95
+ if (unitCursor > inputs.length - 1) {
96
+ setUnitCursor(inputs.length - 1);
97
+ }
98
+
99
+ init(template);
100
+ }, [template, inputs, size]);
101
+
102
+ useScrollPageCursor({
103
+ ref: containerRef,
104
+ pageSizes,
105
+ scale,
106
+ pageCursor,
107
+ onChangePageCursor: (p) => {
108
+ setPageCursor(p);
109
+ if (onPageChange) {
110
+ onPageChange({ currentPage: p, totalPages: schemasList.length });
111
+ }
112
+ },
113
+ });
114
+
115
+ const handleChangeInput = ({ name, value }: { name: string; value: string }) =>
116
+ onChangeInput && onChangeInput({ index: unitCursor, name, value });
117
+
118
+ const handleOnChangeRenderer = (args: { key: string; value: unknown }[], schema: SchemaForUI) => {
119
+ let isNeedInit = false;
120
+ args.forEach(({ key: _key, value }) => {
121
+ if (_key === 'content') {
122
+ const newValue = value as string;
123
+ const oldValue = (input?.[schema.name] as string) || '';
124
+ if (newValue === oldValue) return;
125
+ handleChangeInput({ name: schema.name, value: newValue });
126
+ // TODO Improve this to allow schema types to determine whether the execution of getDynamicTemplate is required.
127
+ if (schema.type === 'table') isNeedInit = true;
128
+ } else {
129
+ const targetSchema = schemasList[pageCursor].find((s) => s.id === schema.id) as SchemaForUI;
130
+ if (!targetSchema) return;
131
+
132
+ // @ts-expect-error Dynamic property assignment
133
+ targetSchema[_key] = value as string;
134
+ }
135
+ });
136
+ if (isNeedInit) {
137
+ init(template);
138
+ }
139
+ setSchemasList([...schemasList]);
140
+ };
141
+
142
+ if (error) {
143
+ return <ErrorScreen size={size} error={error} />;
144
+ }
145
+
146
+ return (
147
+ <Root size={size} scale={scale}>
148
+ <CtlBar
149
+ size={size}
150
+ pageCursor={pageCursor}
151
+ pageNum={schemasList.length}
152
+ setPageCursor={(p) => {
153
+ if (!containerRef.current) return;
154
+ containerRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, p, scale);
155
+ setPageCursor(p);
156
+ if (onPageChange) {
157
+ onPageChange({ currentPage: p, totalPages: schemasList.length });
158
+ }
159
+ }}
160
+ zoomLevel={zoomLevel}
161
+ setZoomLevel={setZoomLevel}
162
+ />
163
+ <UnitPager
164
+ size={size}
165
+ unitCursor={unitCursor}
166
+ unitNum={inputs.length}
167
+ setUnitCursor={setUnitCursor}
168
+ />
169
+ <div ref={containerRef} style={{ ...size, position: 'relative', overflow: 'auto' }}>
170
+ <Paper
171
+ paperRefs={paperRefs}
172
+ scale={scale}
173
+ size={size}
174
+ schemasList={schemasList}
175
+ pageSizes={pageSizes}
176
+ backgrounds={backgrounds}
177
+ renderSchema={({ schema, index }) => {
178
+ const value = schema.readOnly
179
+ ? replacePlaceholders({
180
+ content: schema.content || '',
181
+ variables: { ...input, totalPages: schemasList.length, currentPage: index + 1 },
182
+ schemas: schemasList,
183
+ })
184
+ : String((input && input[schema.name]) || '');
185
+ return (
186
+ <Renderer
187
+ key={schema.id}
188
+ schema={schema}
189
+ basePdf={template.basePdf}
190
+ value={value}
191
+ mode={isForm ? 'form' : 'viewer'}
192
+ placeholder={schema.content}
193
+ tabIndex={index + 100}
194
+ onChange={(arg) => {
195
+ const args = Array.isArray(arg) ? arg : [arg];
196
+ handleOnChangeRenderer(args, schema);
197
+ }}
198
+ outline={
199
+ isForm && !schema.readOnly ? `1px dashed ${token.colorPrimary}` : 'transparent'
200
+ }
201
+ scale={scale}
202
+ />
203
+ );
204
+ }}
205
+ renderPaper={({ index }) => (
206
+ <StaticSchema
207
+ template={template}
208
+ scale={scale}
209
+ input={input}
210
+ totalPages={schemasList.length}
211
+ currentPage={index + 1}
212
+ />
213
+ )}
214
+ />
215
+ </div>
216
+ </Root>
217
+ );
218
+ };
219
+
220
+ export default Preview;
@@ -0,0 +1,165 @@
1
+ import React, { useEffect, useContext, ReactNode, useRef, useMemo } from 'react';
2
+ import {
3
+ Mode,
4
+ ZOOM,
5
+ UIRenderProps,
6
+ SchemaForUI,
7
+ BasePdf,
8
+ Schema,
9
+ Plugin,
10
+ UIOptions,
11
+ cloneDeep,
12
+ } from '@pdfme/common';
13
+ import { theme as antdTheme } from 'antd';
14
+ import { SELECTABLE_CLASSNAME } from '../constants.js';
15
+ import { PluginsRegistry, OptionsContext, I18nContext, CacheContext } from '../contexts.js';
16
+
17
+ type RendererProps = Omit<
18
+ UIRenderProps<Schema>,
19
+ 'schema' | 'rootElement' | 'options' | 'theme' | 'i18n' | '_cache'
20
+ > & {
21
+ basePdf: BasePdf;
22
+ schema: SchemaForUI;
23
+ value: string;
24
+ outline: string;
25
+ onChangeHoveringSchemaId?: (id: string | null) => void;
26
+ scale: number;
27
+ selectable?: boolean;
28
+ };
29
+
30
+ type ReRenderCheckProps = {
31
+ plugin?: Plugin<Schema>;
32
+ value: string;
33
+ mode: Mode;
34
+ scale: number;
35
+ schema: SchemaForUI;
36
+ options: UIOptions;
37
+ };
38
+
39
+ const useRerenderDependencies = (arg: ReRenderCheckProps) => {
40
+ const { plugin, value, mode, scale, schema, options } = arg;
41
+ const _options = cloneDeep(options);
42
+ if (_options.font) {
43
+ Object.values(_options.font).forEach((fontObj) => {
44
+ (fontObj as { data: string }).data = '...';
45
+ });
46
+ }
47
+ const optionStr = JSON.stringify(_options);
48
+
49
+ return useMemo(() => {
50
+ if (plugin?.uninterruptedEditMode && mode === 'designer') {
51
+ return [mode];
52
+ } else {
53
+ return [value, mode, scale, JSON.stringify(schema), optionStr];
54
+ }
55
+ }, [value, mode, scale, schema, optionStr, plugin]);
56
+ };
57
+
58
+ const Wrapper = ({
59
+ children,
60
+ outline,
61
+ onChangeHoveringSchemaId,
62
+ schema,
63
+ selectable = true,
64
+ }: RendererProps & { children: ReactNode }) => (
65
+ <div
66
+ title={schema.name}
67
+ onMouseEnter={() => onChangeHoveringSchemaId && onChangeHoveringSchemaId(schema.id)}
68
+ onMouseLeave={() => onChangeHoveringSchemaId && onChangeHoveringSchemaId(null)}
69
+ className={selectable ? SELECTABLE_CLASSNAME : ''}
70
+ id={schema.id}
71
+ style={{
72
+ position: 'absolute',
73
+ cursor: schema.readOnly ? 'initial' : 'pointer',
74
+ height: schema.height * ZOOM,
75
+ width: schema.width * ZOOM,
76
+ top: schema.position.y * ZOOM,
77
+ left: schema.position.x * ZOOM,
78
+ transform: `rotate(${schema.rotate ?? 0}deg)`,
79
+ opacity: schema.opacity ?? 1,
80
+ outline,
81
+ }}
82
+ >
83
+ {schema.required && (
84
+ <span
85
+ style={{
86
+ color: 'red',
87
+ position: 'absolute',
88
+ top: -12,
89
+ left: -12,
90
+ fontSize: 18,
91
+ fontWeight: 700,
92
+ }}
93
+ >
94
+ *
95
+ </span>
96
+ )}
97
+ {children}
98
+ </div>
99
+ );
100
+
101
+ const Renderer = (props: RendererProps) => {
102
+ const { schema, basePdf, value, mode, onChange, stopEditing, tabIndex, placeholder, scale } =
103
+ props;
104
+
105
+ const pluginsRegistry = useContext(PluginsRegistry);
106
+ const options = useContext(OptionsContext);
107
+ const i18n = useContext(I18nContext) as (key: string) => string;
108
+ const { token: theme } = antdTheme.useToken();
109
+
110
+ const ref = useRef<HTMLDivElement>(null);
111
+ const _cache = useContext(CacheContext);
112
+ const plugin = pluginsRegistry.findByType(schema.type);
113
+
114
+ const reRenderDependencies = useRerenderDependencies({
115
+ plugin,
116
+ value,
117
+ mode,
118
+ scale,
119
+ schema,
120
+ options,
121
+ });
122
+
123
+ useEffect(() => {
124
+ if (!plugin?.ui || !ref.current || !schema.type) return;
125
+
126
+ ref.current.innerHTML = '';
127
+ const render = plugin.ui;
128
+
129
+ void render({
130
+ value,
131
+ schema,
132
+ basePdf,
133
+ rootElement: ref.current,
134
+ mode,
135
+ onChange,
136
+ stopEditing,
137
+ tabIndex,
138
+ placeholder,
139
+ options,
140
+ theme,
141
+ i18n,
142
+ scale,
143
+ _cache,
144
+ });
145
+
146
+ return () => {
147
+ if (ref.current) {
148
+ ref.current.innerHTML = '';
149
+ }
150
+ };
151
+ }, reRenderDependencies);
152
+
153
+ if (!plugin) {
154
+ console.error(`[@pdfme/ui] Renderer for type ${schema.type} not found.
155
+ Check this document: https://pdfme.com/docs/custom-schemas`);
156
+ return <></>;
157
+ }
158
+
159
+ return (
160
+ <Wrapper {...props}>
161
+ <div style={{ height: '100%', width: '100%' }} ref={ref} />
162
+ </Wrapper>
163
+ );
164
+ };
165
+ export default Renderer;
@@ -0,0 +1,38 @@
1
+ import React, { useContext, forwardRef, ReactNode, Ref, useEffect } from 'react';
2
+ import { Size } from '@pdfme/common';
3
+ import { FontContext } from '../contexts.js';
4
+ import { BACKGROUND_COLOR, DESIGNER_CLASSNAME } from '../constants.js';
5
+ import Spinner from './Spinner.js';
6
+
7
+ type Props = { size: Size; scale: number; children: ReactNode };
8
+
9
+ const Root = ({ size, scale, children }: Props, ref: Ref<HTMLDivElement>) => {
10
+ const font = useContext(FontContext);
11
+
12
+ useEffect(() => {
13
+ if (!document || !document.fonts) return;
14
+ const fontFaces = Object.entries(font).map(
15
+ ([key, { data }]) =>
16
+ new FontFace(key, typeof data === 'string' ? `url(${data})` : (data as BufferSource), {
17
+ display: 'swap',
18
+ }),
19
+ );
20
+ const newFontFaces = fontFaces.filter((fontFace) => !document.fonts.has(fontFace));
21
+
22
+ void Promise.allSettled(newFontFaces.map((f) => f.load())).then((loadedFontFaces) => {
23
+ loadedFontFaces.forEach((loadedFontFace) => {
24
+ if (loadedFontFace.status === 'fulfilled') {
25
+ document.fonts.add(loadedFontFace.value);
26
+ }
27
+ });
28
+ });
29
+ }, [font]);
30
+
31
+ return (
32
+ <div className={DESIGNER_CLASSNAME + 'root'} ref={ref} style={{ position: 'relative', background: BACKGROUND_COLOR, ...size }}>
33
+ <div className={DESIGNER_CLASSNAME + 'background'} style={{ margin: '0 auto', ...size }}>{scale === 0 ? <Spinner /> : children}</div>
34
+ </div>
35
+ );
36
+ };
37
+
38
+ export default forwardRef<HTMLDivElement, Props>(Root);
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { LoaderCircle } from 'lucide-react';
3
+ import { theme } from 'antd';
4
+
5
+ const Spinner: React.FC = () => {
6
+ const { token } = theme.useToken();
7
+
8
+ const containerStyle: React.CSSProperties = {
9
+ position: 'relative',
10
+ width: '100%',
11
+ height: '100%',
12
+ overflow: 'hidden',
13
+ display: 'flex',
14
+ alignItems: 'center',
15
+ justifyContent: 'center',
16
+ borderRadius: '50%',
17
+ color: token.colorPrimary,
18
+ };
19
+
20
+ const loaderStyle: React.CSSProperties = {
21
+ animation: 'spin 1s linear infinite',
22
+ };
23
+
24
+ const keyframes = `
25
+ @keyframes spin {
26
+ 0% {
27
+ transform: rotate(0deg);
28
+ }
29
+ 100% {
30
+ transform: rotate(360deg);
31
+ }
32
+ }
33
+ `;
34
+
35
+ return (
36
+ <>
37
+ <style>{keyframes}</style>
38
+ <div style={containerStyle}>
39
+ <LoaderCircle size={50} style={loaderStyle} />
40
+ </div>
41
+ </>
42
+ );
43
+ };
44
+
45
+ export default Spinner;
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { isBlankPdf, replacePlaceholders, Template } from '@pdfme/common';
3
+ import Renderer from './Renderer.js';
4
+ import { uuid } from '../helper.js';
5
+
6
+ const StaticSchema = (props: {
7
+ template: Template;
8
+ input: Record<string, string>;
9
+ scale: number;
10
+ totalPages: number;
11
+ currentPage: number;
12
+ }) => {
13
+ const {
14
+ template: { schemas, basePdf },
15
+ input,
16
+ scale,
17
+ totalPages,
18
+ currentPage,
19
+ } = props;
20
+ if (!isBlankPdf(basePdf) || !basePdf.staticSchema) return null;
21
+ return (
22
+ <>
23
+ {basePdf.staticSchema.map((schema) => (
24
+ <Renderer
25
+ key={schema.name}
26
+ schema={{ ...schema, id: uuid() }}
27
+ basePdf={basePdf}
28
+ value={
29
+ schema.readOnly
30
+ ? replacePlaceholders({
31
+ content: schema.content || '',
32
+ variables: { ...input, totalPages, currentPage },
33
+ schemas,
34
+ })
35
+ : schema.content || ''
36
+ }
37
+ onChangeHoveringSchemaId={() => {
38
+ void 0;
39
+ }}
40
+ mode={'viewer'}
41
+ outline={`none`}
42
+ scale={scale}
43
+ selectable={false}
44
+ />
45
+ ))}
46
+ </>
47
+ );
48
+ };
49
+
50
+ export default StaticSchema;
@@ -0,0 +1,119 @@
1
+ import React from 'react';
2
+ import { Size } from '@pdfme/common';
3
+ import { theme, Typography, Button } from 'antd';
4
+ import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';
5
+
6
+ const { Text } = Typography;
7
+
8
+ type UnitButtonProps = {
9
+ type: 'left' | 'right' | 'doubleLeft' | 'doubleRight';
10
+ onClick: () => void;
11
+ disabled: boolean;
12
+ textStyle: { color: string; fontSize: number; margin: number };
13
+ };
14
+
15
+ const icons = {
16
+ left: ChevronLeft,
17
+ right: ChevronRight,
18
+ doubleLeft: ChevronsLeft,
19
+ doubleRight: ChevronsRight,
20
+ };
21
+
22
+ const UnitButton: React.FC<UnitButtonProps> = ({ type, onClick, disabled, textStyle }) => {
23
+ const Icon = icons[type];
24
+
25
+ return (
26
+ <Button type="text" onClick={onClick} disabled={disabled}>
27
+ <Icon style={{ color: textStyle.color }} />
28
+ </Button>
29
+ );
30
+ };
31
+
32
+ type Props = {
33
+ size: Size;
34
+ unitCursor: number;
35
+ unitNum: number;
36
+ setUnitCursor: (page: number) => void;
37
+ };
38
+
39
+ const UnitPager = ({ size, unitCursor, unitNum, setUnitCursor }: Props) => {
40
+ if (unitNum <= 1) return null;
41
+
42
+ const { token } = theme.useToken();
43
+
44
+ const buttonWrapStyle: React.CSSProperties = {
45
+ pointerEvents: 'initial',
46
+ position: 'sticky',
47
+ zIndex: 1,
48
+ display: 'flex',
49
+ alignItems: 'center',
50
+ boxSizing: 'border-box',
51
+ height: 40,
52
+ padding: token.paddingSM,
53
+ borderRadius: token.borderRadius,
54
+ backgroundColor: token.colorBgMask,
55
+ };
56
+ const textStyle = {
57
+ color: token.colorWhite,
58
+ fontSize: token.fontSize,
59
+ margin: token.marginXS,
60
+ };
61
+
62
+ return (
63
+ <div style={{ position: 'absolute', ...size }}>
64
+ <div
65
+ style={{
66
+ position: 'sticky',
67
+ width: '100%',
68
+ zIndex: 1,
69
+ top: `calc(50% - ${(buttonWrapStyle.height as number) / 2}px)`,
70
+ display: 'flex',
71
+ alignItems: 'center',
72
+ }}
73
+ >
74
+ {unitCursor > 0 && (
75
+ <div style={{ left: '1rem', marginLeft: '1rem', ...buttonWrapStyle }}>
76
+ <UnitButton
77
+ type="doubleLeft"
78
+ onClick={() => setUnitCursor(0)}
79
+ disabled={unitCursor <= 0}
80
+ textStyle={textStyle}
81
+ />
82
+ <UnitButton
83
+ type="left"
84
+ onClick={() => setUnitCursor(unitCursor - 1)}
85
+ disabled={unitCursor <= 0}
86
+ textStyle={textStyle}
87
+ />
88
+ <Text strong style={textStyle}>
89
+ {unitCursor + 1}/{unitNum}
90
+ </Text>
91
+ </div>
92
+ )}
93
+ {unitCursor + 1 < unitNum && (
94
+ <div
95
+ style={{ right: '1rem', marginLeft: 'auto', marginRight: '1rem', ...buttonWrapStyle }}
96
+ >
97
+ <Text strong style={textStyle}>
98
+ {unitCursor + 1}/{unitNum}
99
+ </Text>
100
+ <UnitButton
101
+ type="right"
102
+ onClick={() => setUnitCursor(unitCursor + 1)}
103
+ disabled={unitCursor + 1 >= unitNum}
104
+ textStyle={textStyle}
105
+ />
106
+ <UnitButton
107
+ type="doubleRight"
108
+ onClick={() => setUnitCursor(unitNum - 1)}
109
+ disabled={unitCursor + 1 >= unitNum}
110
+ textStyle={textStyle}
111
+ />
112
+ </div>
113
+ )}
114
+ </div>
115
+ </div>
116
+ );
117
+ };
118
+
119
+ export default UnitPager;
@@ -0,0 +1,21 @@
1
+ export const DEFAULT_LANG = 'en';
2
+
3
+ export const DESTROYED_ERR_MSG = '[@pdfme/ui] this instance is already destroyed';
4
+
5
+ export const SELECTABLE_CLASSNAME = 'selectable';
6
+
7
+ export const RULER_HEIGHT = 30;
8
+
9
+ export const PAGE_GAP = 10;
10
+
11
+ export const LEFT_SIDEBAR_WIDTH = 45;
12
+
13
+ export const RIGHT_SIDEBAR_WIDTH = 400;
14
+
15
+ export const BACKGROUND_COLOR = 'rgb(74, 74, 74)';
16
+
17
+ export const DEFAULT_MAX_ZOOM = 2;
18
+
19
+ export const DESIGNER_CLASSNAME = 'pdfme-designer-';
20
+
21
+ export const UI_CLASSNAME = 'pdfme-ui-';
@@ -0,0 +1,14 @@
1
+ import { createContext } from 'react';
2
+ import { i18n } from './i18n.js';
3
+ import { getDefaultFont, PluginRegistry, pluginRegistry, UIOptions } from '@pdfme/common';
4
+ import { builtInPlugins } from '@pdfme/schemas';
5
+
6
+ export const I18nContext = createContext(i18n);
7
+
8
+ export const FontContext = createContext(getDefaultFont());
9
+
10
+ export const PluginsRegistry = createContext<PluginRegistry>(pluginRegistry(builtInPlugins));
11
+
12
+ export const OptionsContext = createContext<UIOptions>({});
13
+
14
+ export const CacheContext = createContext<Map<string | number, unknown>>(new Map());