Fix zoom resizing, add multi page support, fix text box bugs, fix broken upload button
Some checks failed
Automated Container Build / build-and-push (push) Failing after 3s
CI / Backend (Python) (push) Failing after 11s
CI / Frontend (TypeScript) (push) Failing after 4m49s

This commit is contained in:
Elijah 2026-06-13 12:55:30 -07:00
parent 5b2140187f
commit 7ff5c8130d
3 changed files with 113 additions and 30 deletions

View file

@ -53,21 +53,71 @@ export function TextFormatToolbar({ annotationId, viewportParams }: TextFormatTo
const applyStyle = (styleName: string, value: any, globalPropName: keyof TextProps, globalValue?: any) => {
const canvas = (window as any).__fabricCanvas as any;
let didInline = false;
if (canvas) {
const activeObj = canvas.getActiveObject();
if (activeObj && activeObj.id === annotationId) {
if (activeObj.isEditing) {
if (activeObj.selectionStart !== activeObj.selectionEnd) {
activeObj.setSelectionStyles({ [styleName]: value });
didInline = true;
} else {
activeObj.set(styleName, value);
const isStructural = styleName === 'fontSize' || styleName === 'fontFamily';
if (isStructural) {
// Structural properties MUST be applied to the base object. Fabric 7's bounding box calculations
// frequently fail when inline styles are used for size/font.
activeObj.set(styleName, value);
// Obliterate any inline styles for this property so the base property strictly applies to all text
if (activeObj.styles) {
for (const line in activeObj.styles) {
for (const char in activeObj.styles[line]) {
if (activeObj.styles[line][char]) {
delete activeObj.styles[line][char][styleName];
}
}
}
}
// If the box is empty and we are currently editing it, Fabric's invisible cursor
// cache will still stubbornly hold the old size unless we violently wipe it.
if (activeObj.isEditing && !activeObj.text) {
activeObj.styles = {};
if (activeObj.hiddenTextarea) {
if (styleName === 'fontSize') activeObj.hiddenTextarea.style.fontSize = `${value}px`;
if (styleName === 'fontFamily') activeObj.hiddenTextarea.style.fontFamily = value;
}
}
} else {
activeObj.set(styleName, value);
// Cosmetic properties (bold, italic, color) work fine with inline styles
if (activeObj.isEditing) {
activeObj.setSelectionStyles({ [styleName]: value });
if (!activeObj.text) {
activeObj.set(styleName, value);
}
} else {
// If NOT editing, they selected the whole box. Update the base property.
activeObj.set(styleName, value);
// Clear any inline styles for this property so the base property actually takes effect!
if (activeObj.styles) {
for (const line in activeObj.styles) {
for (const char in activeObj.styles[line]) {
if (activeObj.styles[line][char]) {
delete activeObj.styles[line][char][styleName];
}
}
}
}
}
}
// Critical: Fabric 7 heavily caches text. We MUST mark it dirty to force a redraw!
activeObj.dirty = true;
if ((activeObj as any)._forceClearCache !== undefined) {
(activeObj as any)._forceClearCache = true;
}
// Remove manual height constraint so the box can grow with the new font size
delete activeObj.customHeight;
if (activeObj.initDimensions) activeObj.initDimensions();
activeObj.setCoords();
canvas.requestRenderAll();
}
}
@ -76,9 +126,10 @@ export function TextFormatToolbar({ annotationId, viewportParams }: TextFormatTo
const newProps = { [globalPropName]: finalGlobalValue } as any;
setDefaultTextProps(newProps);
if (!didInline && !isDraft) {
// Always update store so the toolbar displays the new value
if (!isDraft) {
updateAnnotation(annotationId, { props: { ...props, ...newProps } });
} else if (!didInline && isDraft) {
} else {
useEditorStore.getState().setDraftAnnotation({
...textAnn,
props: { ...props, ...newProps }
@ -120,6 +171,12 @@ export function TextFormatToolbar({ annotationId, viewportParams }: TextFormatTo
ref={toolbarRef}
className="absolute z-50 bg-white rounded-md shadow-lg border border-neutral-200 flex items-center p-1 gap-1 h-10"
style={{ top: `${Math.max(0, top)}px`, left: `${left}px` }}
onMouseDown={(e) => {
// Prevent clicking the toolbar from stealing focus and deselecting the canvas object
if ((e.target as HTMLElement).tagName !== 'INPUT') {
e.preventDefault();
}
}}
>
{/* Font Family Dropdown */}
<div className="relative">