@reekon-tools/boldr-utils 1.6.15 → 1.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/annotation/canvas/AnnotationCanvasInner.js +18 -2
- package/dist/annotation/canvas/AnnotationCanvasSkia.d.ts +3 -2
- package/dist/annotation/canvas/AnnotationCanvasSkia.js +1 -1
- package/dist/annotation/canvas/elements/ShapeElement.d.ts +4 -2
- package/dist/annotation/canvas/elements/ShapeElement.js +36 -11
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useFont } from '@shopify/react-native-skia';
|
|
3
|
-
import { useCallback, useEffect, useRef, } from 'react';
|
|
2
|
+
import { Skia, useFont, useTypeface } from '@shopify/react-native-skia';
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, } from 'react';
|
|
4
4
|
import { AnnotationCanvasSkia } from './AnnotationCanvasSkia.js';
|
|
5
|
+
import { TEXT_FONT_FAMILY } from './elements/ShapeElement.js';
|
|
5
6
|
import { buildRemoveMeasurementOps } from './measurementGeometry.js';
|
|
6
7
|
import { useAnnotationCanvasState, } from './useAnnotationCanvasState.js';
|
|
7
8
|
import { stampTileSize } from './stampLayout.js';
|
|
@@ -17,6 +18,20 @@ export const AnnotationCanvasInner = (props) => {
|
|
|
17
18
|
const allowMiddlePan = panTriggers.includes('middleMouse');
|
|
18
19
|
const allowRightPan = panTriggers.includes('rightMouse');
|
|
19
20
|
const valueFont = useFont(stampFontSource, stampValueFontSize);
|
|
21
|
+
// Typeface provider for text-shape Paragraphs. CanvasKit's registerFont
|
|
22
|
+
// rejects the raw pointer valueFont.getTypeface() returns, and useFonts can't
|
|
23
|
+
// take a plain URL (its resolveAsset expects a bundled module). So load the
|
|
24
|
+
// typeface via useTypeface — which fetches the URL and builds a *managed*
|
|
25
|
+
// typeface (MakeFreeTypeFaceFromData) — then register that. Null until the
|
|
26
|
+
// async load resolves; ShapeElement renders text only once it's ready.
|
|
27
|
+
const textTypeface = useTypeface(stampFontSource);
|
|
28
|
+
const textFontMgr = useMemo(() => {
|
|
29
|
+
if (!textTypeface)
|
|
30
|
+
return null;
|
|
31
|
+
const provider = Skia.TypefaceFontProvider.Make();
|
|
32
|
+
provider.registerFont(textTypeface, TEXT_FONT_FAMILY);
|
|
33
|
+
return provider;
|
|
34
|
+
}, [textTypeface]);
|
|
20
35
|
const state = useAnnotationCanvasState(props);
|
|
21
36
|
const containerRef = useRef(null);
|
|
22
37
|
const panGestureRef = useRef(null);
|
|
@@ -179,6 +194,7 @@ export const AnnotationCanvasInner = (props) => {
|
|
|
179
194
|
worldTransform: state.worldTransform,
|
|
180
195
|
resolveImageUrl,
|
|
181
196
|
valueFont,
|
|
197
|
+
textFontMgr,
|
|
182
198
|
penDrawingStroke: state.penDrawingStroke,
|
|
183
199
|
// Endpoint handles on the selected line annotation. Web drives endpoint
|
|
184
200
|
// drag through selectTool's pointer handlers (preview patches update the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SkFont, type SkPath, type Transforms3d } from '@shopify/react-native-skia';
|
|
1
|
+
import { type SkFont, type SkPath, type SkTypefaceFontProvider, type Transforms3d } from '@shopify/react-native-skia';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
import type { AnnotationCanvasState, AnnotationStroke, StrokeCap } from '../../types/annotation.js';
|
|
4
4
|
type AnimatedPoint = {
|
|
@@ -22,6 +22,7 @@ export interface AnnotationCanvasSkiaProps {
|
|
|
22
22
|
};
|
|
23
23
|
resolveImageUrl?: (storagePath: string) => Promise<string>;
|
|
24
24
|
valueFont: SkFont | null;
|
|
25
|
+
textFontMgr?: SkTypefaceFontProvider | null;
|
|
25
26
|
penDrawingStroke: AnnotationStroke | null;
|
|
26
27
|
livePreview?: {
|
|
27
28
|
path: SkPath | {
|
|
@@ -72,5 +73,5 @@ export interface AnnotationCanvasSkiaProps {
|
|
|
72
73
|
};
|
|
73
74
|
customPreview?: ReactNode;
|
|
74
75
|
}
|
|
75
|
-
export declare const AnnotationCanvasSkia: ({ width, height, effectiveCanvas, worldTransform, resolveImageUrl, valueFont, penDrawingStroke, livePreview, shapePreview, draggingId, dragTransform, resizingId, resizeTransform, selectedId, endpointDragId, liveLineP1, liveLineP2, rectDragId, liveRect, handleRadius, customPreview, }: AnnotationCanvasSkiaProps) => import("react/jsx-runtime").JSX.Element;
|
|
76
|
+
export declare const AnnotationCanvasSkia: ({ width, height, effectiveCanvas, worldTransform, resolveImageUrl, valueFont, textFontMgr, penDrawingStroke, livePreview, shapePreview, draggingId, dragTransform, resizingId, resizeTransform, selectedId, endpointDragId, liveLineP1, liveLineP2, rectDragId, liveRect, handleRadius, customPreview, }: AnnotationCanvasSkiaProps) => import("react/jsx-runtime").JSX.Element;
|
|
76
77
|
export {};
|
|
@@ -86,7 +86,7 @@ const SelectionBox = ({ bounds, isDragging, transform, }) => (_jsx(DraggableElem
|
|
|
86
86
|
// since the function-call pattern works identically on native we use it
|
|
87
87
|
// in both Inners for consistency. Don't add hooks here; this is a plain
|
|
88
88
|
// JSX-returning helper, not a component.
|
|
89
|
-
export const AnnotationCanvasSkia = ({ width, height, effectiveCanvas, worldTransform, resolveImageUrl, valueFont, penDrawingStroke, livePreview, shapePreview, draggingId, dragTransform, resizingId, resizeTransform, selectedId, endpointDragId, liveLineP1, liveLineP2, rectDragId, liveRect, handleRadius, customPreview, }) => (_jsx(Canvas, { style: { width, height }, children: _jsxs(Group, { transform: worldTransform, children: [effectiveCanvas.viewport.backgroundImage && (_jsx(BackgroundImageElement, { image: effectiveCanvas.viewport.backgroundImage, docWidth: effectiveCanvas.viewport.width, docHeight: effectiveCanvas.viewport.height, fit: effectiveCanvas.viewport.backgroundFit ?? 'contain', resolveUrl: resolveImageUrl })), effectiveCanvas.strokes.map((stroke) => (_jsx(DraggableElement, { isDragging: stroke.id === draggingId, transform: dragTransform, children: _jsx(StrokeElement, { stroke: stroke }) }, stroke.id))), effectiveCanvas.shapes.map((shape) => (_jsx(DraggableElement, { isDragging: shape.id === draggingId || shape.id === resizingId, transform: shape.id === resizingId ? resizeTransform : dragTransform, children: _jsx(ShapeElement, { shape: shape, font: valueFont }) }, shape.id))), effectiveCanvas.placedMeasurements.map((placed) => {
|
|
89
|
+
export const AnnotationCanvasSkia = ({ width, height, effectiveCanvas, worldTransform, resolveImageUrl, valueFont, textFontMgr, penDrawingStroke, livePreview, shapePreview, draggingId, dragTransform, resizingId, resizeTransform, selectedId, endpointDragId, liveLineP1, liveLineP2, rectDragId, liveRect, handleRadius, customPreview, }) => (_jsx(Canvas, { style: { width, height }, children: _jsxs(Group, { transform: worldTransform, children: [effectiveCanvas.viewport.backgroundImage && (_jsx(BackgroundImageElement, { image: effectiveCanvas.viewport.backgroundImage, docWidth: effectiveCanvas.viewport.width, docHeight: effectiveCanvas.viewport.height, fit: effectiveCanvas.viewport.backgroundFit ?? 'contain', resolveUrl: resolveImageUrl })), effectiveCanvas.strokes.map((stroke) => (_jsx(DraggableElement, { isDragging: stroke.id === draggingId, transform: dragTransform, children: _jsx(StrokeElement, { stroke: stroke }) }, stroke.id))), effectiveCanvas.shapes.map((shape) => (_jsx(DraggableElement, { isDragging: shape.id === draggingId || shape.id === resizingId, transform: shape.id === resizingId ? resizeTransform : dragTransform, children: _jsx(ShapeElement, { shape: shape, font: valueFont, textFontMgr: textFontMgr }) }, shape.id))), effectiveCanvas.placedMeasurements.map((placed) => {
|
|
90
90
|
// Rectangle annotation: a stroked border whose center carries the
|
|
91
91
|
// tile. A corner drag renders from the live geometry (outside the
|
|
92
92
|
// group translate, like an endpoint drag); otherwise the committed
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type SkFont } from '@shopify/react-native-skia';
|
|
1
|
+
import { type SkFont, type SkTypefaceFontProvider } from '@shopify/react-native-skia';
|
|
2
2
|
import type { AnnotationShape } from '../../../types/annotation.js';
|
|
3
|
+
export declare const TEXT_FONT_FAMILY = "annotation-text";
|
|
3
4
|
export interface ShapeElementProps {
|
|
4
5
|
shape: AnnotationShape;
|
|
5
6
|
font?: SkFont | null;
|
|
7
|
+
textFontMgr?: SkTypefaceFontProvider | null;
|
|
6
8
|
}
|
|
7
|
-
export declare const ShapeElement: import("react").MemoExoticComponent<({ shape, font }: ShapeElementProps) => import("react/jsx-runtime").JSX.Element | null>;
|
|
9
|
+
export declare const ShapeElement: import("react").MemoExoticComponent<({ shape, font, textFontMgr }: ShapeElementProps) => import("react/jsx-runtime").JSX.Element | null>;
|
|
@@ -3,10 +3,10 @@ import { Circle, DashPathEffect, Line, Paragraph, Path, Rect, Skia, TextDecorati
|
|
|
3
3
|
import { memo, useMemo } from 'react';
|
|
4
4
|
import { arrowheadTriangle, dashIntervals, toSkiaStrokeCap, } from '../strokeGeometry.js';
|
|
5
5
|
import { DEFAULT_TEXT_FONT_SIZE, TEXT_LINE_HEIGHT_FACTOR, } from '../textGeometry.js';
|
|
6
|
-
// Family the loaded annotation typeface is registered under in the
|
|
7
|
-
// TypefaceFontProvider that backs the text Paragraph
|
|
8
|
-
//
|
|
9
|
-
const TEXT_FONT_FAMILY = 'annotation-text';
|
|
6
|
+
// Family the loaded annotation typeface is registered under in the
|
|
7
|
+
// TypefaceFontProvider that backs the text Paragraph. Exported so the web
|
|
8
|
+
// canvas can register its font under the same name via useFonts (see below).
|
|
9
|
+
export const TEXT_FONT_FAMILY = 'annotation-text';
|
|
10
10
|
// A wide layout width so text only breaks on explicit '\n' (never auto-wraps).
|
|
11
11
|
// Left-aligned, so the unused width is never visible.
|
|
12
12
|
const TEXT_LAYOUT_WIDTH = 100000;
|
|
@@ -36,7 +36,7 @@ const polygonPath = (points, closed) => {
|
|
|
36
36
|
};
|
|
37
37
|
// Memoized — see StrokeElement. Unchanged shapes keep their identity across
|
|
38
38
|
// applyPatch, so only the edited shape (and the shared font) re-render.
|
|
39
|
-
export const ShapeElement = memo(({ shape, font }) => {
|
|
39
|
+
export const ShapeElement = memo(({ shape, font, textFontMgr }) => {
|
|
40
40
|
const { kind, geometry, style, text } = shape;
|
|
41
41
|
const stroke = style.stroke ?? '#000000';
|
|
42
42
|
const fill = style.fill;
|
|
@@ -78,10 +78,29 @@ export const ShapeElement = memo(({ shape, font }) => {
|
|
|
78
78
|
// is registered into a provider so the Paragraph draws with the same typeface
|
|
79
79
|
// as the rest of the canvas. Built only for text shapes.
|
|
80
80
|
const textParagraph = useMemo(() => {
|
|
81
|
-
if (kind !== 'text' || !text
|
|
81
|
+
if (kind !== 'text' || !text)
|
|
82
82
|
return null;
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
// Resolve the typeface provider that backs the Paragraph. Web threads one
|
|
84
|
+
// pre-built via useFonts (managed typeface); native builds one here from
|
|
85
|
+
// the loaded SkFont. `textFontMgr === undefined` distinguishes "native, no
|
|
86
|
+
// manager threaded" from "web, manager still loading (null)" — in the
|
|
87
|
+
// latter we render nothing rather than fall back to the SkFont path, which
|
|
88
|
+
// throws on CanvasKit (raw pointer to registerFont).
|
|
89
|
+
let provider;
|
|
90
|
+
if (textFontMgr !== undefined) {
|
|
91
|
+
provider = textFontMgr;
|
|
92
|
+
}
|
|
93
|
+
else if (font) {
|
|
94
|
+
const typeface = font.getTypeface();
|
|
95
|
+
if (!typeface)
|
|
96
|
+
return null;
|
|
97
|
+
provider = Skia.TypefaceFontProvider.Make();
|
|
98
|
+
provider.registerFont(typeface, TEXT_FONT_FAMILY);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
provider = null;
|
|
102
|
+
}
|
|
103
|
+
if (!provider)
|
|
85
104
|
return null;
|
|
86
105
|
const fontSize = style.fontSize ?? DEFAULT_TEXT_FONT_SIZE;
|
|
87
106
|
const decoration = style.textDecoration;
|
|
@@ -105,8 +124,6 @@ export const ShapeElement = memo(({ shape, font }) => {
|
|
|
105
124
|
else if (decoration === 'highlight') {
|
|
106
125
|
textStyle.backgroundColor = Skia.Color(colorStr);
|
|
107
126
|
}
|
|
108
|
-
const provider = Skia.TypefaceFontProvider.Make();
|
|
109
|
-
provider.registerFont(typeface, TEXT_FONT_FAMILY);
|
|
110
127
|
const builder = Skia.ParagraphBuilder.Make({
|
|
111
128
|
textStyle,
|
|
112
129
|
strutStyle: {
|
|
@@ -119,7 +136,15 @@ export const ShapeElement = memo(({ shape, font }) => {
|
|
|
119
136
|
builder.pushStyle(textStyle);
|
|
120
137
|
builder.addText(text);
|
|
121
138
|
return builder.build();
|
|
122
|
-
}, [
|
|
139
|
+
}, [
|
|
140
|
+
kind,
|
|
141
|
+
text,
|
|
142
|
+
font,
|
|
143
|
+
textFontMgr,
|
|
144
|
+
style.fontSize,
|
|
145
|
+
style.textDecoration,
|
|
146
|
+
style.stroke,
|
|
147
|
+
]);
|
|
123
148
|
const dashEffect = style.dash ? (_jsx(DashPathEffect, { intervals: dashIntervals(strokeWidth) })) : null;
|
|
124
149
|
switch (kind) {
|
|
125
150
|
case 'rect': {
|