326 lines
9.8 KiB
TypeScript
326 lines
9.8 KiB
TypeScript
import { useCallback, useMemo, useState } from 'react';
|
|
import type { AnnotationToolId } from '@app/components/viewer/viewerTypes';
|
|
|
|
type Size = { width: number; height: number };
|
|
|
|
export type BuildToolOptionsExtras = {
|
|
includeMetadata?: boolean;
|
|
stampImageData?: string;
|
|
stampImageSize?: Size | null;
|
|
};
|
|
|
|
interface StyleState {
|
|
inkColor: string;
|
|
inkWidth: number;
|
|
highlightColor: string;
|
|
highlightOpacity: number;
|
|
freehandHighlighterWidth: number;
|
|
underlineColor: string;
|
|
underlineOpacity: number;
|
|
strikeoutColor: string;
|
|
strikeoutOpacity: number;
|
|
squigglyColor: string;
|
|
squigglyOpacity: number;
|
|
textColor: string;
|
|
textSize: number;
|
|
textAlignment: 'left' | 'center' | 'right';
|
|
textBackgroundColor: string;
|
|
noteBackgroundColor: string;
|
|
shapeStrokeColor: string;
|
|
shapeFillColor: string;
|
|
shapeOpacity: number;
|
|
shapeStrokeOpacity: number;
|
|
shapeFillOpacity: number;
|
|
shapeThickness: number;
|
|
}
|
|
|
|
interface StyleActions {
|
|
setInkColor: (value: string) => void;
|
|
setInkWidth: (value: number) => void;
|
|
setHighlightColor: (value: string) => void;
|
|
setHighlightOpacity: (value: number) => void;
|
|
setFreehandHighlighterWidth: (value: number) => void;
|
|
setUnderlineColor: (value: string) => void;
|
|
setUnderlineOpacity: (value: number) => void;
|
|
setStrikeoutColor: (value: string) => void;
|
|
setStrikeoutOpacity: (value: number) => void;
|
|
setSquigglyColor: (value: string) => void;
|
|
setSquigglyOpacity: (value: number) => void;
|
|
setTextColor: (value: string) => void;
|
|
setTextSize: (value: number) => void;
|
|
setTextAlignment: (value: 'left' | 'center' | 'right') => void;
|
|
setTextBackgroundColor: (value: string) => void;
|
|
setNoteBackgroundColor: (value: string) => void;
|
|
setShapeStrokeColor: (value: string) => void;
|
|
setShapeFillColor: (value: string) => void;
|
|
setShapeOpacity: (value: number) => void;
|
|
setShapeStrokeOpacity: (value: number) => void;
|
|
setShapeFillOpacity: (value: number) => void;
|
|
setShapeThickness: (value: number) => void;
|
|
}
|
|
|
|
export type BuildToolOptionsFn = (
|
|
toolId: AnnotationToolId,
|
|
extras?: BuildToolOptionsExtras
|
|
) => Record<string, unknown>;
|
|
|
|
export interface AnnotationStyleStateReturn {
|
|
styleState: StyleState;
|
|
styleActions: StyleActions;
|
|
buildToolOptions: BuildToolOptionsFn;
|
|
getActiveColor: (target: string | null) => string;
|
|
}
|
|
|
|
export const useAnnotationStyleState = (
|
|
cssToPdfSize?: (size: Size) => Size
|
|
): AnnotationStyleStateReturn => {
|
|
const [inkColor, setInkColor] = useState('#1f2933');
|
|
const [inkWidth, setInkWidth] = useState(2);
|
|
const [highlightColor, setHighlightColor] = useState('#ffd54f');
|
|
const [highlightOpacity, setHighlightOpacity] = useState(60);
|
|
const [freehandHighlighterWidth, setFreehandHighlighterWidth] = useState(6);
|
|
const [underlineColor, setUnderlineColor] = useState('#ffb300');
|
|
const [underlineOpacity, setUnderlineOpacity] = useState(100);
|
|
const [strikeoutColor, setStrikeoutColor] = useState('#e53935');
|
|
const [strikeoutOpacity, setStrikeoutOpacity] = useState(100);
|
|
const [squigglyColor, setSquigglyColor] = useState('#00acc1');
|
|
const [squigglyOpacity, setSquigglyOpacity] = useState(100);
|
|
const [textColor, setTextColor] = useState('#111111');
|
|
const [textSize, setTextSize] = useState(14);
|
|
const [textAlignment, setTextAlignment] = useState<'left' | 'center' | 'right'>('left');
|
|
const [textBackgroundColor, setTextBackgroundColor] = useState<string>('');
|
|
const [noteBackgroundColor, setNoteBackgroundColor] = useState('#ffd54f');
|
|
const [shapeStrokeColor, setShapeStrokeColor] = useState('#cf5b5b');
|
|
const [shapeFillColor, setShapeFillColor] = useState('#0000ff');
|
|
const [shapeOpacity, setShapeOpacity] = useState(50);
|
|
const [shapeStrokeOpacity, setShapeStrokeOpacity] = useState(50);
|
|
const [shapeFillOpacity, setShapeFillOpacity] = useState(50);
|
|
const [shapeThickness, setShapeThickness] = useState(2);
|
|
|
|
const buildToolOptions = useCallback<BuildToolOptionsFn>(
|
|
(toolId, extras) => {
|
|
const includeMetadata = extras?.includeMetadata ?? true;
|
|
const metadata = includeMetadata
|
|
? {
|
|
customData: {
|
|
toolId,
|
|
annotationToolId: toolId,
|
|
source: 'annotate',
|
|
author: 'User',
|
|
createdAt: new Date().toISOString(),
|
|
modifiedAt: new Date().toISOString(),
|
|
},
|
|
}
|
|
: {};
|
|
|
|
switch (toolId) {
|
|
case 'ink':
|
|
return { color: inkColor, thickness: inkWidth, ...metadata };
|
|
case 'inkHighlighter':
|
|
return {
|
|
color: highlightColor,
|
|
opacity: highlightOpacity / 100,
|
|
thickness: freehandHighlighterWidth,
|
|
...metadata,
|
|
};
|
|
case 'highlight':
|
|
return { color: highlightColor, opacity: highlightOpacity / 100, ...metadata };
|
|
case 'underline':
|
|
return { color: underlineColor, opacity: underlineOpacity / 100, ...metadata };
|
|
case 'strikeout':
|
|
return { color: strikeoutColor, opacity: strikeoutOpacity / 100, ...metadata };
|
|
case 'squiggly':
|
|
return { color: squigglyColor, opacity: squigglyOpacity / 100, ...metadata };
|
|
case 'text': {
|
|
const textAlignNumber = textAlignment === 'left' ? 0 : textAlignment === 'center' ? 1 : 2;
|
|
return {
|
|
color: textColor,
|
|
textColor: textColor,
|
|
fontSize: textSize,
|
|
textAlign: textAlignNumber,
|
|
...(textBackgroundColor ? { fillColor: textBackgroundColor } : {}),
|
|
...metadata,
|
|
};
|
|
}
|
|
case 'note': {
|
|
const noteFillColor = noteBackgroundColor || 'transparent';
|
|
return {
|
|
color: textColor,
|
|
fillColor: noteFillColor,
|
|
opacity: 1,
|
|
...metadata,
|
|
};
|
|
}
|
|
case 'square':
|
|
case 'circle':
|
|
case 'polygon':
|
|
return {
|
|
color: shapeFillColor,
|
|
strokeColor: shapeStrokeColor,
|
|
opacity: shapeOpacity / 100,
|
|
strokeOpacity: shapeStrokeOpacity / 100,
|
|
fillOpacity: shapeFillOpacity / 100,
|
|
borderWidth: shapeThickness,
|
|
...metadata,
|
|
};
|
|
case 'line':
|
|
case 'polyline':
|
|
case 'lineArrow':
|
|
return {
|
|
color: shapeStrokeColor,
|
|
strokeColor: shapeStrokeColor,
|
|
opacity: shapeStrokeOpacity / 100,
|
|
borderWidth: shapeThickness,
|
|
...metadata,
|
|
};
|
|
case 'stamp': {
|
|
const pdfSize =
|
|
extras?.stampImageSize && cssToPdfSize ? cssToPdfSize(extras.stampImageSize) : undefined;
|
|
return {
|
|
imageSrc: extras?.stampImageData,
|
|
...(pdfSize ? { imageSize: pdfSize } : {}),
|
|
...metadata,
|
|
};
|
|
}
|
|
default:
|
|
return { ...metadata };
|
|
}
|
|
},
|
|
[
|
|
cssToPdfSize,
|
|
freehandHighlighterWidth,
|
|
highlightColor,
|
|
highlightOpacity,
|
|
inkColor,
|
|
inkWidth,
|
|
noteBackgroundColor,
|
|
shapeFillColor,
|
|
shapeFillOpacity,
|
|
shapeOpacity,
|
|
shapeStrokeColor,
|
|
shapeStrokeOpacity,
|
|
shapeThickness,
|
|
squigglyColor,
|
|
squigglyOpacity,
|
|
strikeoutColor,
|
|
strikeoutOpacity,
|
|
textAlignment,
|
|
textBackgroundColor,
|
|
textColor,
|
|
textSize,
|
|
underlineColor,
|
|
underlineOpacity,
|
|
]
|
|
);
|
|
|
|
const getActiveColor = useCallback(
|
|
(target: string | null) => {
|
|
if (target === 'ink') return inkColor;
|
|
if (target === 'highlight' || target === 'inkHighlighter') return highlightColor;
|
|
if (target === 'underline') return underlineColor;
|
|
if (target === 'strikeout') return strikeoutColor;
|
|
if (target === 'squiggly') return squigglyColor;
|
|
if (target === 'shapeStroke') return shapeStrokeColor;
|
|
if (target === 'shapeFill') return shapeFillColor;
|
|
if (target === 'textBackground') return textBackgroundColor || '#ffffff';
|
|
if (target === 'noteBackground') return noteBackgroundColor || '#ffffff';
|
|
return textColor;
|
|
},
|
|
[
|
|
highlightColor,
|
|
inkColor,
|
|
noteBackgroundColor,
|
|
shapeFillColor,
|
|
shapeStrokeColor,
|
|
squigglyColor,
|
|
strikeoutColor,
|
|
textBackgroundColor,
|
|
textColor,
|
|
underlineColor,
|
|
]
|
|
);
|
|
|
|
const styleState: StyleState = useMemo(
|
|
() => ({
|
|
inkColor,
|
|
inkWidth,
|
|
highlightColor,
|
|
highlightOpacity,
|
|
freehandHighlighterWidth,
|
|
underlineColor,
|
|
underlineOpacity,
|
|
strikeoutColor,
|
|
strikeoutOpacity,
|
|
squigglyColor,
|
|
squigglyOpacity,
|
|
textColor,
|
|
textSize,
|
|
textAlignment,
|
|
textBackgroundColor,
|
|
noteBackgroundColor,
|
|
shapeStrokeColor,
|
|
shapeFillColor,
|
|
shapeOpacity,
|
|
shapeStrokeOpacity,
|
|
shapeFillOpacity,
|
|
shapeThickness,
|
|
}),
|
|
[
|
|
freehandHighlighterWidth,
|
|
highlightColor,
|
|
highlightOpacity,
|
|
inkColor,
|
|
inkWidth,
|
|
noteBackgroundColor,
|
|
shapeFillColor,
|
|
shapeFillOpacity,
|
|
shapeOpacity,
|
|
shapeStrokeColor,
|
|
shapeStrokeOpacity,
|
|
shapeThickness,
|
|
squigglyColor,
|
|
squigglyOpacity,
|
|
strikeoutColor,
|
|
strikeoutOpacity,
|
|
textAlignment,
|
|
textBackgroundColor,
|
|
textColor,
|
|
textSize,
|
|
underlineColor,
|
|
underlineOpacity,
|
|
]
|
|
);
|
|
|
|
const styleActions: StyleActions = {
|
|
setInkColor,
|
|
setInkWidth,
|
|
setHighlightColor,
|
|
setHighlightOpacity,
|
|
setFreehandHighlighterWidth,
|
|
setUnderlineColor,
|
|
setUnderlineOpacity,
|
|
setStrikeoutColor,
|
|
setStrikeoutOpacity,
|
|
setSquigglyColor,
|
|
setSquigglyOpacity,
|
|
setTextColor,
|
|
setTextSize,
|
|
setTextAlignment,
|
|
setTextBackgroundColor,
|
|
setNoteBackgroundColor,
|
|
setShapeStrokeColor,
|
|
setShapeFillColor,
|
|
setShapeOpacity,
|
|
setShapeStrokeOpacity,
|
|
setShapeFillOpacity,
|
|
setShapeThickness,
|
|
};
|
|
|
|
return {
|
|
styleState,
|
|
styleActions,
|
|
buildToolOptions,
|
|
getActiveColor,
|
|
};
|
|
};
|