import { Plugin, PropPanel, DEFAULT_FONT_NAME, getFallbackFontName, PropPanelSchema, PropPanelWidgetProps, } from "@pdfme/common"; import { text } from "@pdfme/schemas"; import type { TextSchema } from "@pdfme/schemas/dist/types/src/text/types"; import { DEFAULT_FONT_SIZE, DEFAULT_ALIGNMENT, DEFAULT_VERTICAL_ALIGNMENT, DEFAULT_CHARACTER_SPACING, DEFAULT_LINE_HEIGHT, VERTICAL_ALIGN_TOP, VERTICAL_ALIGN_MIDDLE, VERTICAL_ALIGN_BOTTOM, DEFAULT_FONT_COLOR, DYNAMIC_FIT_VERTICAL, DYNAMIC_FIT_HORIZONTAL, DEFAULT_DYNAMIC_FIT, DEFAULT_DYNAMIC_MIN_FONT_SIZE, DEFAULT_DYNAMIC_MAX_FONT_SIZE, ALIGN_RIGHT, ALIGN_CENTER, DEFAULT_OPACITY, HEX_COLOR_PATTERN, } from "./constants"; import { GebaeudeStammdaten, Rechnungen, } from "@ibcornelsen/database/client"; import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { zodGetKeys } from "#lib/helpers/zod"; import { verbrauchsausweisWohnenPDFValidator } from "#lib/validators/verbrauchsausweis-wohnen-pdf-validator"; const UseDynamicFontSize = (props: PropPanelWidgetProps) => { const { rootElement, changeSchemas, activeSchema, i18n } = props; const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.checked = Boolean((activeSchema as any)?.dynamicFontSize); checkbox.onchange = (e: any) => { const val = e.target.checked ? { min: DEFAULT_DYNAMIC_MIN_FONT_SIZE, max: DEFAULT_DYNAMIC_MAX_FONT_SIZE, fit: DEFAULT_DYNAMIC_FIT, } : undefined; changeSchemas([ { key: "dynamicFontSize", value: val, schemaId: activeSchema.id }, ]); }; const label = document.createElement("label"); label.innerText = i18n("schemas.text.dynamicFontSize") || ""; label.style.cssText = "display: flex; width: 100%;"; label.appendChild(checkbox); rootElement.appendChild(label); }; type AusweisIndex = keyof Omit, "rechnungen"> | `gebaeude_aufnahme_allgemein.${keyof VerbrauchsausweisWohnenClient["gebaeude_aufnahme_allgemein"]}` | `gebaeude_aufnahme_allgemein.gebaeude_stammdaten.${keyof VerbrauchsausweisWohnenClient["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]}` | `rechnungen.${keyof Rechnungen}`; const ausweisKeys = zodGetKeys(verbrauchsausweisWohnenPDFValidator); const variableOptions: { label: string; value: AusweisIndex; }[] = ausweisKeys.map((key: AusweisIndex) => ({ label: key as string, value: key })); interface VariableSchema extends TextSchema { variable: AusweisIndex | undefined } const propPanel: PropPanel = { schema: ({ options, activeSchema, i18n }) => { const font = options.font || { [DEFAULT_FONT_NAME]: { data: "", fallback: true }, }; const fontNames = Object.keys(font); const fallbackFontName = getFallbackFontName(font); const enableDynamicFont = Boolean( (activeSchema as any)?.dynamicFontSize ); const textSchema: Record = { variable: { title: "Variable", type: "string", widget: "select", props: { options: variableOptions }, span: 24, }, fontName: { title: i18n("schemas.text.fontName"), type: "string", widget: "select", default: fallbackFontName, props: { options: fontNames.map((name) => ({ label: name, value: name, })), }, span: 12, }, fontSize: { title: i18n("schemas.text.size"), type: "number", widget: "inputNumber", span: 6, disabled: enableDynamicFont, }, characterSpacing: { title: i18n("schemas.text.spacing"), type: "number", widget: "inputNumber", span: 6, }, alignment: { title: i18n("schemas.text.textAlign"), type: "string", widget: "select", props: { options: [ { label: i18n("schemas.left"), value: DEFAULT_ALIGNMENT, }, { label: i18n("schemas.center"), value: ALIGN_CENTER }, { label: i18n("schemas.right"), value: ALIGN_RIGHT }, ], }, span: 8, }, verticalAlignment: { title: i18n("schemas.text.verticalAlign"), type: "string", widget: "select", props: { options: [ { label: i18n("schemas.top"), value: VERTICAL_ALIGN_TOP, }, { label: i18n("schemas.middle"), value: VERTICAL_ALIGN_MIDDLE, }, { label: i18n("schemas.bottom"), value: VERTICAL_ALIGN_BOTTOM, }, ], }, span: 8, }, lineHeight: { title: i18n("schemas.text.lineHeight"), type: "number", widget: "inputNumber", props: { step: 0.1, }, span: 8, }, useDynamicFontSize: { type: "boolean", widget: "UseDynamicFontSize", bind: false, span: 16, }, dynamicFontSize: { type: "object", widget: "card", column: 3, properties: { min: { title: i18n("schemas.text.min"), type: "number", widget: "inputNumber", hidden: !enableDynamicFont, }, max: { title: i18n("schemas.text.max"), type: "number", widget: "inputNumber", hidden: !enableDynamicFont, }, fit: { title: i18n("schemas.text.fit"), type: "string", widget: "select", hidden: !enableDynamicFont, props: { options: [ { label: i18n("schemas.horizontal"), value: DYNAMIC_FIT_HORIZONTAL, }, { label: i18n("schemas.vertical"), value: DYNAMIC_FIT_VERTICAL, }, ], }, }, }, }, fontColor: { title: i18n("schemas.textColor"), type: "string", widget: "color", rules: [ { pattern: HEX_COLOR_PATTERN, message: i18n("hexColorPrompt"), }, ], }, backgroundColor: { title: i18n("schemas.bgColor"), type: "string", widget: "color", rules: [ { pattern: HEX_COLOR_PATTERN, message: i18n("hexColorPrompt"), }, ], }, }; return textSchema; }, widgets: { UseDynamicFontSize }, defaultValue: "Type Something...", defaultSchema: { type: "variable", position: { x: 0, y: 0 }, width: 45, height: 10, rotate: 0, alignment: DEFAULT_ALIGNMENT, verticalAlignment: DEFAULT_VERTICAL_ALIGNMENT, fontSize: DEFAULT_FONT_SIZE, lineHeight: DEFAULT_LINE_HEIGHT, characterSpacing: DEFAULT_CHARACTER_SPACING, dynamicFontSize: undefined, fontColor: DEFAULT_FONT_COLOR, fontName: undefined, backgroundColor: "", opacity: DEFAULT_OPACITY, variable: undefined } }; export const variable: Plugin = { ui: function(props) { // Wir binden die inputs auf dieses Element, damit wir die Werte später auslesen können. if (props.schema.variable && this) { props.value = (this as unknown as Record)[props.schema.variable] as string; } return text.ui(props); }, pdf: (props) => { if (props.schema.variable && this) { props.value = (this as unknown as Record)[props.schema.variable] as string; } text.pdf(props); }, propPanel, };