mirror of
https://github.com/pdfme/pdfme.git
synced 2026-05-19 20:25:34 -04:00
style: format codebase
This commit is contained in:
@@ -349,35 +349,36 @@ const layoutStaticBlocks = async (arg: {
|
||||
_cache: Map<string | number, unknown>;
|
||||
}) => {
|
||||
const contentWidth = Math.max(0, arg.pageSize.width - arg.margin.left - arg.margin.right);
|
||||
const blockFrames: Array<{ children: PdfJsxChild[]; frame: Rect; placement?: StaticPlacement }> = [
|
||||
{
|
||||
children: arg.blocks.staticTop,
|
||||
frame: { x: 0, y: 0, width: arg.pageSize.width, height: arg.pageSize.height },
|
||||
},
|
||||
{
|
||||
children: arg.blocks.header,
|
||||
frame: {
|
||||
x: arg.margin.left,
|
||||
y: 0,
|
||||
width: contentWidth,
|
||||
height: arg.margin.top,
|
||||
const blockFrames: Array<{ children: PdfJsxChild[]; frame: Rect; placement?: StaticPlacement }> =
|
||||
[
|
||||
{
|
||||
children: arg.blocks.staticTop,
|
||||
frame: { x: 0, y: 0, width: arg.pageSize.width, height: arg.pageSize.height },
|
||||
},
|
||||
},
|
||||
{
|
||||
children: arg.blocks.footer,
|
||||
frame: {
|
||||
x: arg.margin.left,
|
||||
y: arg.pageSize.height - arg.margin.bottom,
|
||||
width: contentWidth,
|
||||
height: arg.margin.bottom,
|
||||
{
|
||||
children: arg.blocks.header,
|
||||
frame: {
|
||||
x: arg.margin.left,
|
||||
y: 0,
|
||||
width: contentWidth,
|
||||
height: arg.margin.top,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
children: arg.blocks.staticBottom,
|
||||
frame: { x: 0, y: 0, width: arg.pageSize.width, height: arg.pageSize.height },
|
||||
placement: 'bottom',
|
||||
},
|
||||
];
|
||||
{
|
||||
children: arg.blocks.footer,
|
||||
frame: {
|
||||
x: arg.margin.left,
|
||||
y: arg.pageSize.height - arg.margin.bottom,
|
||||
width: contentWidth,
|
||||
height: arg.margin.bottom,
|
||||
},
|
||||
},
|
||||
{
|
||||
children: arg.blocks.staticBottom,
|
||||
frame: { x: 0, y: 0, width: arg.pageSize.width, height: arg.pageSize.height },
|
||||
placement: 'bottom',
|
||||
},
|
||||
];
|
||||
|
||||
for (const { children, frame, placement } of blockFrames) {
|
||||
if (children.length === 0) continue;
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import puppeteer, { Browser, Page } from 'puppeteer';
|
||||
import { pdf2img } from '@pdfme/converter';
|
||||
import { Template, Schema, PAGE_SIZE_PRESETS, cloneDeep, getInputFromTemplate } from '@pdfme/common';
|
||||
import {
|
||||
Template,
|
||||
Schema,
|
||||
PAGE_SIZE_PRESETS,
|
||||
cloneDeep,
|
||||
getInputFromTemplate,
|
||||
} from '@pdfme/common';
|
||||
import { text, table, image, barcodes, select, checkbox, radioGroup } from '@pdfme/schemas';
|
||||
import { ChildProcessWithoutNullStreams, spawn } from 'node:child_process';
|
||||
import { stripVTControlCharacters } from 'node:util';
|
||||
@@ -240,38 +246,47 @@ async function loadRouteWithStorage(
|
||||
storageState: PlaygroundStorageState,
|
||||
) {
|
||||
const projectId = 'project_e2e_deterministic_template';
|
||||
const inputs = storageState.inputs ?? (storageState.template ? getInputFromTemplate(storageState.template) : []);
|
||||
const inputs =
|
||||
storageState.inputs ??
|
||||
(storageState.template ? getInputFromTemplate(storageState.template) : []);
|
||||
|
||||
await page.goto(baseUrl, { waitUntil: 'networkidle2', timeout });
|
||||
await page.evaluate((state, resolvedInputs, id, projectsStorageKey, activeProjectStorageKey) => {
|
||||
localStorage.removeItem('template');
|
||||
localStorage.removeItem('inputs');
|
||||
localStorage.removeItem('mode');
|
||||
localStorage.removeItem(projectsStorageKey);
|
||||
localStorage.removeItem(activeProjectStorageKey);
|
||||
await page.evaluate(
|
||||
(state, resolvedInputs, id, projectsStorageKey, activeProjectStorageKey) => {
|
||||
localStorage.removeItem('template');
|
||||
localStorage.removeItem('inputs');
|
||||
localStorage.removeItem('mode');
|
||||
localStorage.removeItem(projectsStorageKey);
|
||||
localStorage.removeItem(activeProjectStorageKey);
|
||||
|
||||
if (state.template) {
|
||||
const now = Date.now();
|
||||
localStorage.setItem(
|
||||
projectsStorageKey,
|
||||
JSON.stringify([
|
||||
{
|
||||
createdAt: now,
|
||||
id,
|
||||
inputs: resolvedInputs,
|
||||
kind: 'template',
|
||||
template: state.template,
|
||||
title: 'E2E deterministic template',
|
||||
updatedAt: now,
|
||||
},
|
||||
]),
|
||||
);
|
||||
localStorage.setItem(activeProjectStorageKey, id);
|
||||
}
|
||||
if (state.mode) {
|
||||
localStorage.setItem('mode', state.mode);
|
||||
}
|
||||
}, storageState, inputs, projectId, playgroundProjectsStorageKey, activePlaygroundProjectStorageKey);
|
||||
if (state.template) {
|
||||
const now = Date.now();
|
||||
localStorage.setItem(
|
||||
projectsStorageKey,
|
||||
JSON.stringify([
|
||||
{
|
||||
createdAt: now,
|
||||
id,
|
||||
inputs: resolvedInputs,
|
||||
kind: 'template',
|
||||
template: state.template,
|
||||
title: 'E2E deterministic template',
|
||||
updatedAt: now,
|
||||
},
|
||||
]),
|
||||
);
|
||||
localStorage.setItem(activeProjectStorageKey, id);
|
||||
}
|
||||
if (state.mode) {
|
||||
localStorage.setItem('mode', state.mode);
|
||||
}
|
||||
},
|
||||
storageState,
|
||||
inputs,
|
||||
projectId,
|
||||
playgroundProjectsStorageKey,
|
||||
activePlaygroundProjectStorageKey,
|
||||
);
|
||||
|
||||
await page.goto(`${baseUrl}${path}?project=${encodeURIComponent(projectId)}`, {
|
||||
waitUntil: 'networkidle2',
|
||||
@@ -492,7 +507,10 @@ describe('Playground E2E Tests', () => {
|
||||
if (!browser || !page) throw new Error('Browser/Page not initialized');
|
||||
|
||||
// 5. Load the Pedigree designer directly to avoid flaky list-page navigation in CI
|
||||
await page.goto(`${baseUrl}/designer?template=pedigree`, { waitUntil: 'networkidle2', timeout });
|
||||
await page.goto(`${baseUrl}/designer?template=pedigree`, {
|
||||
waitUntil: 'networkidle2',
|
||||
timeout,
|
||||
});
|
||||
|
||||
await waitForDesignerReady(page, 'Pet Name');
|
||||
|
||||
|
||||
@@ -18,29 +18,25 @@ const buttonVariants: Record<PlaygroundButtonVariant, string> = {
|
||||
const joinClassNames = (...classes: Array<string | false | null | undefined>) =>
|
||||
classes.filter(Boolean).join(' ');
|
||||
|
||||
const PlaygroundButton = forwardRef<HTMLButtonElement, PlaygroundButtonProps>(function PlaygroundButton(
|
||||
{
|
||||
className,
|
||||
fullWidth = false,
|
||||
type = 'button',
|
||||
variant = 'secondary',
|
||||
...props
|
||||
const PlaygroundButton = forwardRef<HTMLButtonElement, PlaygroundButtonProps>(
|
||||
function PlaygroundButton(
|
||||
{ className, fullWidth = false, type = 'button', variant = 'secondary', ...props },
|
||||
ref,
|
||||
) {
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
type={type}
|
||||
className={joinClassNames(
|
||||
'inline-flex min-w-0 items-center justify-center gap-1 whitespace-nowrap rounded border px-2 py-1.5 text-sm font-medium transition disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-offset-2 sm:px-3',
|
||||
buttonVariants[variant],
|
||||
fullWidth && 'w-full',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
ref,
|
||||
) {
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
type={type}
|
||||
className={joinClassNames(
|
||||
'inline-flex min-w-0 items-center justify-center gap-1 whitespace-nowrap rounded border px-2 py-1.5 text-sm font-medium transition disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-offset-2 sm:px-3',
|
||||
buttonVariants[variant],
|
||||
fullWidth && 'w-full',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
export default PlaygroundButton;
|
||||
|
||||
@@ -124,8 +124,8 @@ function DesignerApp() {
|
||||
const currentTitle =
|
||||
(currentProject?.title ?? projectTitleRef.current) || 'Untitled Template';
|
||||
const title = saveAs
|
||||
? window.prompt('Save as', `${currentTitle} Copy`) ?? ''
|
||||
: currentProject?.title ?? window.prompt('Project name', currentTitle) ?? '';
|
||||
? (window.prompt('Save as', `${currentTitle} Copy`) ?? '')
|
||||
: (currentProject?.title ?? window.prompt('Project name', currentTitle) ?? '');
|
||||
if (!title.trim()) return;
|
||||
|
||||
const thumbnail = await createTemplateThumbnailDataUrl(
|
||||
@@ -148,86 +148,89 @@ function DesignerApp() {
|
||||
[setCurrentProjectTitle],
|
||||
);
|
||||
|
||||
const buildDesigner = useCallback(async (isCancelled: () => boolean) => {
|
||||
if (!designerRef.current) return;
|
||||
try {
|
||||
let template: Template = getBlankTemplate();
|
||||
let project: PlaygroundProject | null = null;
|
||||
loadRequestRef.current ??= getDesignerLoadRequest();
|
||||
const {
|
||||
projectId: projectIdFromQuery,
|
||||
searchParams: initialSearchParams,
|
||||
shouldConsumeQuery,
|
||||
shouldCreateNewProject,
|
||||
templateId: templateIdFromQuery,
|
||||
} = loadRequestRef.current;
|
||||
const buildDesigner = useCallback(
|
||||
async (isCancelled: () => boolean) => {
|
||||
if (!designerRef.current) return;
|
||||
try {
|
||||
let template: Template = getBlankTemplate();
|
||||
let project: PlaygroundProject | null = null;
|
||||
loadRequestRef.current ??= getDesignerLoadRequest();
|
||||
const {
|
||||
projectId: projectIdFromQuery,
|
||||
searchParams: initialSearchParams,
|
||||
shouldConsumeQuery,
|
||||
shouldCreateNewProject,
|
||||
templateId: templateIdFromQuery,
|
||||
} = loadRequestRef.current;
|
||||
|
||||
if (shouldCreateNewProject) {
|
||||
clearActivePlaygroundProject();
|
||||
setCurrentProjectTitle('Untitled Template');
|
||||
} else if (projectIdFromQuery) {
|
||||
project = getPlaygroundProject(projectIdFromQuery);
|
||||
if (!project) throw new Error('Project not found');
|
||||
template = project.template;
|
||||
} else if (templateIdFromQuery) {
|
||||
const templateJson = await getTemplateById(templateIdFromQuery);
|
||||
checkTemplate(templateJson);
|
||||
template = templateJson;
|
||||
setCurrentProjectTitle(fromKebabCase(templateIdFromQuery));
|
||||
} else {
|
||||
project = getActivePlaygroundProject();
|
||||
if (project) {
|
||||
if (shouldCreateNewProject) {
|
||||
clearActivePlaygroundProject();
|
||||
setCurrentProjectTitle('Untitled Template');
|
||||
} else if (projectIdFromQuery) {
|
||||
project = getPlaygroundProject(projectIdFromQuery);
|
||||
if (!project) throw new Error('Project not found');
|
||||
template = project.template;
|
||||
} else if (templateIdFromQuery) {
|
||||
const templateJson = await getTemplateById(templateIdFromQuery);
|
||||
checkTemplate(templateJson);
|
||||
template = templateJson;
|
||||
setCurrentProjectTitle(fromKebabCase(templateIdFromQuery));
|
||||
} else {
|
||||
template = await getDefaultPlaygroundTemplate();
|
||||
setCurrentProjectTitle(fromKebabCase('invoice'));
|
||||
project = getActivePlaygroundProject();
|
||||
if (project) {
|
||||
template = project.template;
|
||||
} else {
|
||||
template = await getDefaultPlaygroundTemplate();
|
||||
setCurrentProjectTitle(fromKebabCase('invoice'));
|
||||
}
|
||||
}
|
||||
|
||||
projectRef.current = project;
|
||||
if (project) setCurrentProjectTitle(project.title);
|
||||
|
||||
if (shouldConsumeQuery && !didCleanLoadQueryRef.current) {
|
||||
const nextSearchParams = new URLSearchParams(initialSearchParams);
|
||||
nextSearchParams.delete('new');
|
||||
nextSearchParams.delete('template');
|
||||
nextSearchParams.delete('project');
|
||||
didCleanLoadQueryRef.current = true;
|
||||
setSearchParams(nextSearchParams, { replace: true });
|
||||
}
|
||||
|
||||
if (isCancelled() || !designerRef.current) return null;
|
||||
|
||||
const nextDesigner = new Designer({
|
||||
domContainer: designerRef.current,
|
||||
template,
|
||||
options: {
|
||||
font: getFontsData(),
|
||||
lang: 'en',
|
||||
labels: {
|
||||
'signature.clear': '🗑️',
|
||||
},
|
||||
theme: {
|
||||
token: { colorPrimary: '#25c2a0' },
|
||||
},
|
||||
icons: {
|
||||
multiVariableText:
|
||||
'<svg fill="#000000" width="24px" height="24px" viewBox="0 0 24 24"><path d="M6.643,13.072,17.414,2.3a1.027,1.027,0,0,1,1.452,0L20.7,4.134a1.027,1.027,0,0,1,0,1.452L9.928,16.357,5,18ZM21,20H3a1,1,0,0,0,0,2H21a1,1,0,0,0,0-2Z"/></svg>',
|
||||
},
|
||||
maxZoom: 250,
|
||||
},
|
||||
plugins: getPlugins(),
|
||||
});
|
||||
designer.current = nextDesigner;
|
||||
nextDesigner.onSaveTemplate(onSaveTemplate);
|
||||
return nextDesigner;
|
||||
} catch (error) {
|
||||
if (isCancelled()) return null;
|
||||
projectRef.current = null;
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
|
||||
projectRef.current = project;
|
||||
if (project) setCurrentProjectTitle(project.title);
|
||||
|
||||
if (shouldConsumeQuery && !didCleanLoadQueryRef.current) {
|
||||
const nextSearchParams = new URLSearchParams(initialSearchParams);
|
||||
nextSearchParams.delete('new');
|
||||
nextSearchParams.delete('template');
|
||||
nextSearchParams.delete('project');
|
||||
didCleanLoadQueryRef.current = true;
|
||||
setSearchParams(nextSearchParams, { replace: true });
|
||||
}
|
||||
|
||||
if (isCancelled() || !designerRef.current) return null;
|
||||
|
||||
const nextDesigner = new Designer({
|
||||
domContainer: designerRef.current,
|
||||
template,
|
||||
options: {
|
||||
font: getFontsData(),
|
||||
lang: 'en',
|
||||
labels: {
|
||||
'signature.clear': '🗑️',
|
||||
},
|
||||
theme: {
|
||||
token: { colorPrimary: '#25c2a0' },
|
||||
},
|
||||
icons: {
|
||||
multiVariableText:
|
||||
'<svg fill="#000000" width="24px" height="24px" viewBox="0 0 24 24"><path d="M6.643,13.072,17.414,2.3a1.027,1.027,0,0,1,1.452,0L20.7,4.134a1.027,1.027,0,0,1,0,1.452L9.928,16.357,5,18ZM21,20H3a1,1,0,0,0,0,2H21a1,1,0,0,0,0-2Z"/></svg>',
|
||||
},
|
||||
maxZoom: 250,
|
||||
},
|
||||
plugins: getPlugins(),
|
||||
});
|
||||
designer.current = nextDesigner;
|
||||
nextDesigner.onSaveTemplate(onSaveTemplate);
|
||||
return nextDesigner;
|
||||
} catch (error) {
|
||||
if (isCancelled()) return null;
|
||||
projectRef.current = null;
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
}, [onSaveTemplate, setCurrentProjectTitle, setSearchParams]);
|
||||
},
|
||||
[onSaveTemplate, setCurrentProjectTitle, setSearchParams],
|
||||
);
|
||||
|
||||
const onChangeBasePDF = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files?.[0]) {
|
||||
|
||||
@@ -168,8 +168,8 @@ function FormAndViewerApp() {
|
||||
const nextTemplate = ui.current.getTemplate();
|
||||
const currentTitle = (currentProject?.title ?? projectTitle) || 'Untitled Template';
|
||||
const title = saveAs
|
||||
? window.prompt('Save as', `${currentTitle} Copy`) ?? ''
|
||||
: currentProject?.title ?? window.prompt('Project name', currentTitle) ?? '';
|
||||
? (window.prompt('Save as', `${currentTitle} Copy`) ?? '')
|
||||
: (currentProject?.title ?? window.prompt('Project name', currentTitle) ?? '');
|
||||
if (!title.trim()) return;
|
||||
|
||||
const thumbnail = await createTemplateThumbnailDataUrl(nextTemplate, nextInputs).catch(
|
||||
@@ -248,9 +248,7 @@ function FormAndViewerApp() {
|
||||
<div className="flex gap-1">
|
||||
<PlaygroundButton onClick={onGetInputs}>Get</PlaygroundButton>
|
||||
<PlaygroundButton onClick={onSetInputs}>Set</PlaygroundButton>
|
||||
<PlaygroundButton onClick={() => void onSaveInputs()}>
|
||||
Save
|
||||
</PlaygroundButton>
|
||||
<PlaygroundButton onClick={() => void onSaveInputs()}>Save</PlaygroundButton>
|
||||
<PlaygroundButton onClick={() => void onSaveInputs(true)}>Save As</PlaygroundButton>
|
||||
<PlaygroundButton onClick={onResetInputs}>Reset</PlaygroundButton>
|
||||
</div>
|
||||
|
||||
@@ -342,7 +342,7 @@ export default function JsxPlayground() {
|
||||
title ??
|
||||
(saveAs
|
||||
? window.prompt('Save as', `${currentTitle} Copy`)
|
||||
: projectRef.current?.title ?? window.prompt('Project name', currentTitle)) ??
|
||||
: (projectRef.current?.title ?? window.prompt('Project name', currentTitle))) ??
|
||||
'';
|
||||
if (!projectTitle.trim()) return null;
|
||||
|
||||
|
||||
@@ -178,8 +178,8 @@ export default function Md2Pdf() {
|
||||
|
||||
const currentTitle = projectRef.current?.title ?? `md2pdf - ${sourceTitle}`;
|
||||
const title = saveAs
|
||||
? window.prompt('Save as', `${currentTitle} Copy`) ?? ''
|
||||
: projectRef.current?.title ?? window.prompt('Project name', currentTitle) ?? '';
|
||||
? (window.prompt('Save as', `${currentTitle} Copy`) ?? '')
|
||||
: (projectRef.current?.title ?? window.prompt('Project name', currentTitle) ?? '');
|
||||
if (!title.trim()) return;
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user