Files
documenso/packages/lib/universal/field-renderer/field-generic-items.ts
David Nguyen 7f09ba72f4 feat: add envelopes (#2025)
This PR is handles the changes required to support envelopes. The new
envelope editor/signing page will be hidden during release.

The core changes here is to migrate the documents and templates model to
a centralized envelopes model.

Even though Documents and Templates are removed, from the user
perspective they will still exist as we remap envelopes to documents and
templates.
2025-10-14 21:56:36 +11:00

120 lines
2.7 KiB
TypeScript

import Konva from 'konva';
import {
DEFAULT_RECT_BACKGROUND,
RECIPIENT_COLOR_STYLES,
} from '@documenso/ui/lib/recipient-colors';
import type { FieldToRender, RenderFieldElementOptions } from './field-renderer';
import { calculateFieldPosition } from './field-renderer';
export const upsertFieldGroup = (
field: FieldToRender,
options: RenderFieldElementOptions,
): Konva.Group => {
const { pageWidth, pageHeight, pageLayer, editable } = options;
const { fieldX, fieldY, fieldWidth, fieldHeight } = calculateFieldPosition(
field,
pageWidth,
pageHeight,
);
const fieldGroup: Konva.Group =
pageLayer.findOne(`#${field.renderId}`) ||
new Konva.Group({
id: field.renderId,
name: 'field-group',
});
fieldGroup.setAttrs({
scaleX: 1,
scaleY: 1,
x: fieldX,
y: fieldY,
draggable: editable,
dragBoundFunc: (pos) => {
const newX = Math.max(0, Math.min(pageWidth - fieldWidth, pos.x));
const newY = Math.max(0, Math.min(pageHeight - fieldHeight, pos.y));
return { x: newX, y: newY };
},
} satisfies Partial<Konva.GroupConfig>);
return fieldGroup;
};
export const upsertFieldRect = (
field: FieldToRender,
options: RenderFieldElementOptions,
): Konva.Rect => {
const { pageWidth, pageHeight, mode, pageLayer, color } = options;
const { fieldWidth, fieldHeight } = calculateFieldPosition(field, pageWidth, pageHeight);
const fieldRect: Konva.Rect =
pageLayer.findOne(`#${field.renderId}-rect`) ||
new Konva.Rect({
id: `${field.renderId}-rect`,
name: 'field-rect',
});
fieldRect.setAttrs({
width: fieldWidth,
height: fieldHeight,
fill: DEFAULT_RECT_BACKGROUND,
stroke: color ? RECIPIENT_COLOR_STYLES[color].baseRing : '#e5e7eb',
strokeWidth: 2,
cornerRadius: 2,
strokeScaleEnabled: false,
visible: mode !== 'export',
} satisfies Partial<Konva.RectConfig>);
return fieldRect;
};
export const createSpinner = ({
fieldWidth,
fieldHeight,
}: {
fieldWidth: number;
fieldHeight: number;
}) => {
const loadingGroup = new Konva.Group({
name: 'loading-spinner-group',
});
const rect = new Konva.Rect({
x: 4,
y: 4,
width: fieldWidth - 8,
height: fieldHeight - 8,
fill: 'white',
opacity: 1,
});
const spinner = new Konva.Arc({
x: fieldWidth / 2,
y: fieldHeight / 2,
innerRadius: fieldWidth / 10,
outerRadius: fieldHeight / 10,
angle: 270,
rotation: 0,
fill: 'rgba(122, 195, 85, 1)',
lineCap: 'round',
});
rect.moveToTop();
spinner.moveToTop();
loadingGroup.add(rect);
loadingGroup.add(spinner);
const anim = new Konva.Animation((frame) => {
spinner.rotate(180 * (frame.timeDiff / 500));
});
anim.start();
return loadingGroup;
};