@reekon-tools/boldr-utils 1.15.5 → 1.16.0
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/AnnotationCanvasSkia.js +8 -3
- package/dist/annotation/canvas/backgroundLayers.d.ts +1 -0
- package/dist/annotation/canvas/backgroundLayers.js +8 -0
- package/dist/annotation/canvas/tools/selectTool.js +14 -3
- package/dist/calculator/index.d.ts +1 -0
- package/dist/calculator/index.js +1 -0
- package/dist/calculator/preview.d.ts +22 -0
- package/dist/calculator/preview.js +43 -0
- package/dist/calculator/schema.d.ts +14 -0
- package/dist/calculator/schema.js +2 -0
- package/dist/calculator/validate.d.ts +1 -0
- package/dist/calculator/validate.js +17 -0
- package/dist/exports.d.ts +1 -1
- package/dist/exports.js +1 -1
- package/dist/types/firestore.d.ts +2 -0
- package/package.json +1 -1
- package/dist/canvas/AnnotationCanvas.d.ts +0 -11
- package/dist/canvas/AnnotationCanvas.js +0 -10
- package/dist/canvas/AnnotationCanvas.native.d.ts +0 -8
- package/dist/canvas/AnnotationCanvas.native.js +0 -6
- package/dist/canvas/AnnotationCanvasInner.d.ts +0 -39
- package/dist/canvas/AnnotationCanvasInner.js +0 -219
- package/dist/canvas/AnnotationCanvasInner.native.d.ts +0 -35
- package/dist/canvas/AnnotationCanvasInner.native.js +0 -138
- package/dist/canvas/AnnotationCanvasSkia.d.ts +0 -27
- package/dist/canvas/AnnotationCanvasSkia.js +0 -20
- package/dist/canvas/Tool.d.ts +0 -38
- package/dist/canvas/Tool.js +0 -1
- package/dist/canvas/elements/BackgroundImageElement.d.ts +0 -9
- package/dist/canvas/elements/BackgroundImageElement.js +0 -37
- package/dist/canvas/elements/MeasurementStampElement.d.ts +0 -13
- package/dist/canvas/elements/MeasurementStampElement.js +0 -30
- package/dist/canvas/elements/ShapeElement.d.ts +0 -7
- package/dist/canvas/elements/ShapeElement.js +0 -62
- package/dist/canvas/elements/StrokeElement.d.ts +0 -7
- package/dist/canvas/elements/StrokeElement.js +0 -18
- package/dist/canvas/measurementPicker.d.ts +0 -10
- package/dist/canvas/measurementPicker.js +0 -1
- package/dist/canvas/measurementStampOverlay.d.ts +0 -11
- package/dist/canvas/measurementStampOverlay.js +0 -1
- package/dist/canvas/pointerAdapter.d.ts +0 -3
- package/dist/canvas/pointerAdapter.js +0 -19
- package/dist/canvas/stampLayout.d.ts +0 -5
- package/dist/canvas/stampLayout.js +0 -14
- package/dist/canvas/tools/measurementStampTool.d.ts +0 -9
- package/dist/canvas/tools/measurementStampTool.js +0 -37
- package/dist/canvas/tools/panTool.d.ts +0 -5
- package/dist/canvas/tools/panTool.js +0 -25
- package/dist/canvas/tools/penTool.d.ts +0 -13
- package/dist/canvas/tools/penTool.js +0 -68
- package/dist/canvas/tools/selectTool.d.ts +0 -2
- package/dist/canvas/tools/selectTool.js +0 -182
- package/dist/canvas/useAnnotationCanvasState.d.ts +0 -54
- package/dist/canvas/useAnnotationCanvasState.js +0 -210
- package/dist/canvas/viewport.d.ts +0 -16
- package/dist/canvas/viewport.js +0 -54
- package/dist/data/AnnotationDataContext.d.ts +0 -8
- package/dist/data/AnnotationDataContext.js +0 -11
- package/dist/data/AnnotationDataProvider.d.ts +0 -65
- package/dist/data/AnnotationDataProvider.js +0 -4
- package/dist/data/InMemoryAnnotationProvider.d.ts +0 -30
- package/dist/data/InMemoryAnnotationProvider.js +0 -197
- package/dist/data/canvasPersistence.d.ts +0 -3
- package/dist/data/canvasPersistence.js +0 -26
- package/dist/data/hooks/useAnnotationCanvasDoc.d.ts +0 -33
- package/dist/data/hooks/useAnnotationCanvasDoc.js +0 -314
- package/dist/data/hooks/useAnnotationDoc.d.ts +0 -7
- package/dist/data/hooks/useAnnotationDoc.js +0 -33
- package/dist/data/hooks/useAnnotationList.d.ts +0 -7
- package/dist/data/hooks/useAnnotationList.js +0 -26
- package/dist/data/hooks/useAnnotationMutations.d.ts +0 -9
- package/dist/data/hooks/useAnnotationMutations.js +0 -11
- package/dist/hooks/useParseMeasurement.d.ts +0 -4
- package/dist/hooks/useParseMeasurement.js +0 -14
- package/dist/utils/evaluateFormula.d.ts +0 -20
- package/dist/utils/evaluateFormula.js +0 -31
|
@@ -4,7 +4,7 @@ import { normalizeRect, placementOf } from './measurementGeometry.js';
|
|
|
4
4
|
import { arrowheadTriangle, dashIntervals, toSkiaStrokeCap, } from './strokeGeometry.js';
|
|
5
5
|
import { SELECTION_PAD, textResizeGeometry, textShapeBounds, } from './textGeometry.js';
|
|
6
6
|
import { visualShapeBounds } from './shapeGeometry.js';
|
|
7
|
-
import { backgroundLayerDocRect, backgroundLayersOf, } from './backgroundLayers.js';
|
|
7
|
+
import { backgroundLayerDocRect, backgroundLayersOf, canEditBackgroundLayers, } from './backgroundLayers.js';
|
|
8
8
|
import { BackgroundLayerElement } from './elements/BackgroundImageElement.js';
|
|
9
9
|
import { PlaneElement, PLANE_CHROME_COLOR, PLANE_GRID_COLOR, PLANE_GRID_OPACITY, PLANE_GRID_WIDTH, PLANE_OUTLINE_WIDTH, } from './elements/PlaneElement.js';
|
|
10
10
|
import { ShapeElement } from './elements/ShapeElement.js';
|
|
@@ -251,8 +251,13 @@ export const AnnotationCanvasSkia = ({ width, height, effectiveCanvas, worldTran
|
|
|
251
251
|
// bottom-right handle — backgrounds scale uniformly about their
|
|
252
252
|
// top-left corner (the transform origin), so a single opposite-corner
|
|
253
253
|
// grab is the whole gizmo. Chrome tracks the live drag/resize
|
|
254
|
-
// transform the same way the layer itself does above.
|
|
255
|
-
|
|
254
|
+
// transform the same way the layer itself does above. A lone
|
|
255
|
+
// background is never editable (canEditBackgroundLayers), so it gets
|
|
256
|
+
// no chrome even when a stale selection still names it — e.g. right
|
|
257
|
+
// after the other layer of a pair was removed.
|
|
258
|
+
const layer = canEditBackgroundLayers(effectiveCanvas.viewport)
|
|
259
|
+
? backgroundLayersOf(effectiveCanvas.viewport).find((l) => l.id === selectedId)
|
|
260
|
+
: undefined;
|
|
256
261
|
if (layer) {
|
|
257
262
|
const r = backgroundLayerDocRect(layer);
|
|
258
263
|
const isResizing = layer.id === resizingId;
|
|
@@ -2,6 +2,7 @@ import type { AnnotationBackgroundLayer, AnnotationViewport, BackgroundLayerTran
|
|
|
2
2
|
export declare const LEGACY_BACKGROUND_LAYER_ID = "background-legacy";
|
|
3
3
|
export declare const BACKGROUND_PLACEMENT_GAP_RATIO = 0.02;
|
|
4
4
|
export declare const backgroundLayersOf: (viewport: AnnotationViewport) => AnnotationBackgroundLayer[];
|
|
5
|
+
export declare const canEditBackgroundLayers: (viewport: AnnotationViewport) => boolean;
|
|
5
6
|
export declare const backgroundLayerDocRect: (layer: AnnotationBackgroundLayer) => {
|
|
6
7
|
x: number;
|
|
7
8
|
y: number;
|
|
@@ -46,6 +46,14 @@ export const backgroundLayersOf = (viewport) => {
|
|
|
46
46
|
},
|
|
47
47
|
];
|
|
48
48
|
};
|
|
49
|
+
// Whether the background stack is user-editable at all — selectable, draggable,
|
|
50
|
+
// corner-scalable. A lone image IS the canvas: there is nothing to arrange it
|
|
51
|
+
// against, so it exposes no selection chrome and never moves; taps and drags
|
|
52
|
+
// on it fall through to the ordinary empty-canvas behavior (deselect / pan).
|
|
53
|
+
// Only once a second image exists does arranging make sense, and then every
|
|
54
|
+
// layer becomes editable. Shared by the select tool's hit-tests and the
|
|
55
|
+
// selection chrome so both platforms agree on the rule.
|
|
56
|
+
export const canEditBackgroundLayers = (viewport) => backgroundLayersOf(viewport).length > 1;
|
|
49
57
|
// The doc-space rectangle a layer occupies: the intrinsic pixel grid under
|
|
50
58
|
// the layer's translate+scale.
|
|
51
59
|
export const backgroundLayerDocRect = (layer) => ({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { backgroundLayerDocRect, backgroundLayersOf, } from '../backgroundLayers.js';
|
|
1
|
+
import { backgroundLayerDocRect, backgroundLayersOf, canEditBackgroundLayers, } from '../backgroundLayers.js';
|
|
2
2
|
import { stampTileDims } from '../stampLayout.js';
|
|
3
3
|
import { placementOf, linePosOf, snapLinePos, lerp, recomputeAnchor, rectCenter, rectCornerPoint, oppositeRectCorner, hitPlacedMeasurement, } from '../measurementGeometry.js';
|
|
4
4
|
import { hitShapeOutline, visualShapeBounds } from '../shapeGeometry.js';
|
|
@@ -462,7 +462,10 @@ const shapeCornerPatch = (doc, id, corner, delta) => {
|
|
|
462
462
|
// hit-test: a tap selects one only when every stroke/shape/measurement
|
|
463
463
|
// misses, and a drag translates one only when it is ALREADY selected — the
|
|
464
464
|
// layout tool's two-step model, which keeps a full-bleed background from
|
|
465
|
-
// hijacking pan/marquee gestures.
|
|
465
|
+
// hijacking pan/marquee gestures. And none of it applies to a LONE image: with
|
|
466
|
+
// a single background there is nothing to arrange, so it is not selectable,
|
|
467
|
+
// draggable, or scalable at all (canEditBackgroundLayers) — every hit-test
|
|
468
|
+
// below misses, and the gesture falls through to deselect / pan. ---
|
|
466
469
|
// Doc-space clamp on a resized background's larger doc dimension. The floor
|
|
467
470
|
// keeps a corner drag from collapsing a layer below grabbable size; the
|
|
468
471
|
// ceiling keeps the doc rect (which feeds fit math and the web SVG raster
|
|
@@ -478,6 +481,8 @@ const pointInBackgroundLayer = (layer, p) => {
|
|
|
478
481
|
// layers draw on top). Point-in-doc-rect, no padding: a background is a big
|
|
479
482
|
// target already.
|
|
480
483
|
const findBackgroundHit = (doc, world) => {
|
|
484
|
+
if (!canEditBackgroundLayers(doc.viewport))
|
|
485
|
+
return null;
|
|
481
486
|
const layers = backgroundLayersOf(doc.viewport);
|
|
482
487
|
for (let i = layers.length - 1; i >= 0; i--) {
|
|
483
488
|
if (pointInBackgroundLayer(layers[i], world)) {
|
|
@@ -490,6 +495,8 @@ const findBackgroundHit = (doc, world) => {
|
|
|
490
495
|
// paths call this only after the general hit-test misses, so annotation
|
|
491
496
|
// elements always win a grab over the background beneath them.
|
|
492
497
|
const findSelectedBackgroundHit = (doc, world, selectedIds) => {
|
|
498
|
+
if (!canEditBackgroundLayers(doc.viewport))
|
|
499
|
+
return null;
|
|
493
500
|
const layers = backgroundLayersOf(doc.viewport);
|
|
494
501
|
for (let i = layers.length - 1; i >= 0; i--) {
|
|
495
502
|
const layer = layers[i];
|
|
@@ -527,7 +534,11 @@ const backgroundResizeGeometry = (layer) => {
|
|
|
527
534
|
// endpoint handles either way.
|
|
528
535
|
const findResizeHandleHit = (doc, id, world, zoom) => {
|
|
529
536
|
const s = doc.shapes.find((x) => x.id === id);
|
|
530
|
-
|
|
537
|
+
// A lone background is not editable at all (canEditBackgroundLayers), so
|
|
538
|
+
// its corner offers no handle — even to a stale selection naming it.
|
|
539
|
+
const layer = s || !canEditBackgroundLayers(doc.viewport)
|
|
540
|
+
? null
|
|
541
|
+
: backgroundLayerById(doc, id);
|
|
531
542
|
const geom = s
|
|
532
543
|
? textResizeGeometry(s)
|
|
533
544
|
: layer
|
|
@@ -9,4 +9,5 @@ export * from './instance.js';
|
|
|
9
9
|
export * from './runtime.js';
|
|
10
10
|
export * from './display.js';
|
|
11
11
|
export * from './chips.js';
|
|
12
|
+
export * from './preview.js';
|
|
12
13
|
export { calculatorDefinitionSchema, expressionSymbols, validateCalculatorDefinition, type IssueSeverity, type ValidationIssue, type ValidationResult, } from './validate.js';
|
package/dist/calculator/index.js
CHANGED
|
@@ -15,4 +15,5 @@ export * from './instance.js';
|
|
|
15
15
|
export * from './runtime.js';
|
|
16
16
|
export * from './display.js';
|
|
17
17
|
export * from './chips.js';
|
|
18
|
+
export * from './preview.js';
|
|
18
19
|
export { calculatorDefinitionSchema, expressionSymbols, validateCalculatorDefinition, } from './validate.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CalculatorDefinition, type CalculatorField } from './schema.js';
|
|
2
|
+
import type { CalculatorInstanceFileData } from './instance.js';
|
|
3
|
+
/**
|
|
4
|
+
* The field a thumbnail headlines, per CalculatorDefinition.previewFieldId's
|
|
5
|
+
* tri-state: an explicit id (when it names a numeric output), null for none,
|
|
6
|
+
* absent for auto — the sole numeric output, if there is exactly one.
|
|
7
|
+
*/
|
|
8
|
+
export declare const previewFieldFor: (definition: Pick<CalculatorDefinition, "fields" | "previewFieldId">) => CalculatorField | null;
|
|
9
|
+
export interface PreviewValue {
|
|
10
|
+
field: CalculatorField;
|
|
11
|
+
/** Display string in `unit` — fractional inches etc., same as the runtime. */
|
|
12
|
+
value: string;
|
|
13
|
+
/** Unit label; empty for unit-less numbers. */
|
|
14
|
+
unit: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The headline value for an instance, or null when there is nothing to show:
|
|
18
|
+
* no preview field, the field is unresolved (inputs missing), or it is in
|
|
19
|
+
* conflict (the runtime withholds conflicted values behind a dash — a tile
|
|
20
|
+
* should show nothing rather than a dash).
|
|
21
|
+
*/
|
|
22
|
+
export declare const previewValueFor: (fileData: Pick<CalculatorInstanceFileData, "definition" | "entries" | "displayUnitOverrides">) => PreviewValue | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Thumbnail headline for a saved calculator instance (Asana
|
|
2
|
+
// 1217881404454870): which output a tile shows, and its formatted value.
|
|
3
|
+
// Shared by boldr-pro's FilePreview and rock-desktop so both platforms pick
|
|
4
|
+
// the same field and print the same string. Pure — runs the same
|
|
5
|
+
// deriveRuntime pass the runtime and the T1R drift check use, so it needs no
|
|
6
|
+
// stored result (computed values are never persisted; see instance.ts).
|
|
7
|
+
import { isEquationTargetKind, } from './schema.js';
|
|
8
|
+
import { deriveRuntime } from './runtime.js';
|
|
9
|
+
import { displayUnitFor, formatFieldValue } from './display.js';
|
|
10
|
+
/** Outputs eligible to headline a thumbnail: numeric, equation-target kinds. */
|
|
11
|
+
const numericOutputs = (definition) => definition.fields.filter((field) => field.role === 'output' && isEquationTargetKind(field.kind));
|
|
12
|
+
/**
|
|
13
|
+
* The field a thumbnail headlines, per CalculatorDefinition.previewFieldId's
|
|
14
|
+
* tri-state: an explicit id (when it names a numeric output), null for none,
|
|
15
|
+
* absent for auto — the sole numeric output, if there is exactly one.
|
|
16
|
+
*/
|
|
17
|
+
export const previewFieldFor = (definition) => {
|
|
18
|
+
if (definition.previewFieldId === null)
|
|
19
|
+
return null;
|
|
20
|
+
const candidates = numericOutputs(definition);
|
|
21
|
+
if (typeof definition.previewFieldId === 'string') {
|
|
22
|
+
return (candidates.find((field) => field.id === definition.previewFieldId) ?? null);
|
|
23
|
+
}
|
|
24
|
+
return candidates.length === 1 ? candidates[0] : null;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The headline value for an instance, or null when there is nothing to show:
|
|
28
|
+
* no preview field, the field is unresolved (inputs missing), or it is in
|
|
29
|
+
* conflict (the runtime withholds conflicted values behind a dash — a tile
|
|
30
|
+
* should show nothing rather than a dash).
|
|
31
|
+
*/
|
|
32
|
+
export const previewValueFor = (fileData) => {
|
|
33
|
+
const field = previewFieldFor(fileData.definition);
|
|
34
|
+
if (!field)
|
|
35
|
+
return null;
|
|
36
|
+
const resolved = deriveRuntime(fileData.definition, fileData.entries ?? {})
|
|
37
|
+
.resolved[field.id];
|
|
38
|
+
if (!resolved || resolved.conflict || typeof resolved.value !== 'number') {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const unit = displayUnitFor(field, fileData.displayUnitOverrides ?? {});
|
|
42
|
+
return { field, ...formatFieldValue(field, unit, resolved.value) };
|
|
43
|
+
};
|
|
@@ -190,6 +190,20 @@ export interface CalculatorDefinition {
|
|
|
190
190
|
/** Inputs + outputs in one list, discriminated by `role`. */
|
|
191
191
|
fields: CalculatorField[];
|
|
192
192
|
equations: CalculatorEquation[];
|
|
193
|
+
/**
|
|
194
|
+
* The output whose resolved value a saved instance's THUMBNAIL headlines
|
|
195
|
+
* (Asana 1217881404454870 — Area/Volume and every T1R function calculator
|
|
196
|
+
* are impractical to open one by one just to read the result). Tri-state:
|
|
197
|
+
* - absent (undefined): AUTO — the sole numeric output when the
|
|
198
|
+
* calculator has exactly one, nothing when it has several. This is also
|
|
199
|
+
* what instances frozen before the field existed resolve to, so they
|
|
200
|
+
* gain a headline without being re-saved.
|
|
201
|
+
* - null: explicitly none — the author opted a single-output calc out.
|
|
202
|
+
* - id: that output. Must be role 'output' and an equation-target kind;
|
|
203
|
+
* anything else is validated as a warning and ignored at runtime.
|
|
204
|
+
* Always resolve through previewFieldFor() — never read this raw.
|
|
205
|
+
*/
|
|
206
|
+
previewFieldId?: string | null;
|
|
193
207
|
/** Diagram file (files subcollection doc carrying the Skia canvas). */
|
|
194
208
|
diagramFileId?: string | null;
|
|
195
209
|
/** Public calculators are readable by everyone; rules/query key. */
|
|
@@ -208,6 +208,8 @@ export const createEmptyCalculatorDefinition = (id) => ({
|
|
|
208
208
|
category: null,
|
|
209
209
|
fields: [],
|
|
210
210
|
equations: [],
|
|
211
|
+
// previewFieldId is deliberately ABSENT, not null: absent means "auto"
|
|
212
|
+
// (headline the sole numeric output), null means the author opted out.
|
|
211
213
|
diagramFileId: null,
|
|
212
214
|
isPublic: false,
|
|
213
215
|
});
|
|
@@ -174,6 +174,7 @@ export declare const calculatorDefinitionSchema: z.ZodObject<{
|
|
|
174
174
|
variableUnits: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
175
175
|
resultUnit: z.ZodOptional<z.ZodString>;
|
|
176
176
|
}, z.core.$strip>>;
|
|
177
|
+
previewFieldId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
177
178
|
diagramFileId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
178
179
|
isPublic: z.ZodBoolean;
|
|
179
180
|
sharedUserIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -127,6 +127,9 @@ export const calculatorDefinitionSchema = z.object({
|
|
|
127
127
|
category: z.string().nullish(),
|
|
128
128
|
fields: z.array(calculatorFieldSchema),
|
|
129
129
|
equations: z.array(calculatorEquationSchema),
|
|
130
|
+
// Listed so zod's unknown-key stripping doesn't silently drop it (see the
|
|
131
|
+
// `category` note above). Referential checks live in the invariant pass.
|
|
132
|
+
previewFieldId: z.string().nullish(),
|
|
130
133
|
diagramFileId: z.string().nullable().optional(),
|
|
131
134
|
isPublic: z.boolean(),
|
|
132
135
|
sharedUserIds: z.array(z.string()).optional(),
|
|
@@ -229,6 +232,20 @@ export const validateCalculatorDefinition = (input) => {
|
|
|
229
232
|
}
|
|
230
233
|
fieldIds.add(field.id);
|
|
231
234
|
});
|
|
235
|
+
// --- Thumbnail headline field -------------------------------------------
|
|
236
|
+
// Warnings, not errors: a dangling or mis-typed previewFieldId must not brick
|
|
237
|
+
// a published calculator (or every instance that froze it) — the runtime
|
|
238
|
+
// helper (previewFieldFor) simply shows no headline for it.
|
|
239
|
+
if (typeof def.previewFieldId === 'string') {
|
|
240
|
+
const previewField = def.fields.find((f) => f.id === def.previewFieldId);
|
|
241
|
+
if (!previewField) {
|
|
242
|
+
push('preview-field-missing', 'previewFieldId', `Thumbnail result field "${def.previewFieldId}" does not exist`, 'warning');
|
|
243
|
+
}
|
|
244
|
+
else if (previewField.role !== 'output' ||
|
|
245
|
+
!isEquationTargetKind(previewField.kind)) {
|
|
246
|
+
push('preview-field-not-numeric-output', 'previewFieldId', `Thumbnail result field "${previewField.name}" must be a numeric output`, 'warning');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
232
249
|
const equationIds = new Set();
|
|
233
250
|
def.equations.forEach((eq, i) => {
|
|
234
251
|
if (equationIds.has(eq.id)) {
|
package/dist/exports.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export type { MeasurementStampRenderArgs, RenderMeasurementStamp, } from './anno
|
|
|
32
32
|
export { STAMP_TILE_SIZE, GROUP_HEADER_TILE_WIDTH, GROUP_HEADER_TILE_HEIGHT, GROUP_HEADER_COLLAPSED_WIDTH, GROUP_HEADER_COLLAPSED_HEIGHT, GROUP_HEADER_DESIGN, groupHeaderBaseDims, DEFAULT_TILE_SCALE, TILE_SCALE_MIN, TILE_SCALE_MAX, clampTileScale, resolveTileScaleFactor, resolveHeaderTileScaleFactor, resolveFileTileScaleFactor, tileDocSizeForFactor, tileScaleFromDocSize, stampTileSize, stampTileDims, isUnassociatedStamp, isFileStamp, type StampTileDims, } from './annotation/canvas/stampLayout.js';
|
|
33
33
|
export { GROUP_HEADER_STYLE, describeGroupHeader, groupHeaderSignature, type GroupHeaderBadge, type GroupHeaderDescriptor, } from './annotation/canvas/groupHeaderLayout.js';
|
|
34
34
|
export { createViewportApi, fitToScreen, fitRectToScreen, imageDocRect, panBy, zoomAt, DEFAULT_VIEWPORT, type ViewportApi, type ViewportState, } from './annotation/canvas/viewport.js';
|
|
35
|
-
export { LEGACY_BACKGROUND_LAYER_ID, BACKGROUND_PLACEMENT_GAP_RATIO, backgroundLayersOf, backgroundLayerDocRect, backgroundLayersUnionRect, placeNewBackgroundLayer, } from './annotation/canvas/backgroundLayers.js';
|
|
35
|
+
export { LEGACY_BACKGROUND_LAYER_ID, BACKGROUND_PLACEMENT_GAP_RATIO, backgroundLayersOf, canEditBackgroundLayers, backgroundLayerDocRect, backgroundLayersUnionRect, placeNewBackgroundLayer, } from './annotation/canvas/backgroundLayers.js';
|
|
36
36
|
export { createPenTool, type PenToolOptions, } from './annotation/canvas/tools/penTool.js';
|
|
37
37
|
export { createSelectTool, type SelectToolOptions, } from './annotation/canvas/tools/selectTool.js';
|
|
38
38
|
export { createMeasurementStampTool, type MeasurementStampToolOptions, } from './annotation/canvas/tools/measurementStampTool.js';
|
package/dist/exports.js
CHANGED
|
@@ -37,7 +37,7 @@ export { InMemoryAnnotationProvider } from './annotation/data/InMemoryAnnotation
|
|
|
37
37
|
export { STAMP_TILE_SIZE, GROUP_HEADER_TILE_WIDTH, GROUP_HEADER_TILE_HEIGHT, GROUP_HEADER_COLLAPSED_WIDTH, GROUP_HEADER_COLLAPSED_HEIGHT, GROUP_HEADER_DESIGN, groupHeaderBaseDims, DEFAULT_TILE_SCALE, TILE_SCALE_MIN, TILE_SCALE_MAX, clampTileScale, resolveTileScaleFactor, resolveHeaderTileScaleFactor, resolveFileTileScaleFactor, tileDocSizeForFactor, tileScaleFromDocSize, stampTileSize, stampTileDims, isUnassociatedStamp, isFileStamp, } from './annotation/canvas/stampLayout.js';
|
|
38
38
|
export { GROUP_HEADER_STYLE, describeGroupHeader, groupHeaderSignature, } from './annotation/canvas/groupHeaderLayout.js';
|
|
39
39
|
export { createViewportApi, fitToScreen, fitRectToScreen, imageDocRect, panBy, zoomAt, DEFAULT_VIEWPORT, } from './annotation/canvas/viewport.js';
|
|
40
|
-
export { LEGACY_BACKGROUND_LAYER_ID, BACKGROUND_PLACEMENT_GAP_RATIO, backgroundLayersOf, backgroundLayerDocRect, backgroundLayersUnionRect, placeNewBackgroundLayer, } from './annotation/canvas/backgroundLayers.js';
|
|
40
|
+
export { LEGACY_BACKGROUND_LAYER_ID, BACKGROUND_PLACEMENT_GAP_RATIO, backgroundLayersOf, canEditBackgroundLayers, backgroundLayerDocRect, backgroundLayersUnionRect, placeNewBackgroundLayer, } from './annotation/canvas/backgroundLayers.js';
|
|
41
41
|
export { createPenTool, } from './annotation/canvas/tools/penTool.js';
|
|
42
42
|
export { createSelectTool, } from './annotation/canvas/tools/selectTool.js';
|
|
43
43
|
export { createMeasurementStampTool, } from './annotation/canvas/tools/measurementStampTool.js';
|
|
@@ -67,6 +67,7 @@ export interface Project extends FirestoreDoc, Timestamps {
|
|
|
67
67
|
state: string;
|
|
68
68
|
collectionId: string | null;
|
|
69
69
|
index: number | null;
|
|
70
|
+
bgImgUpdatedAt?: number;
|
|
70
71
|
}
|
|
71
72
|
export declare enum TemplateType {
|
|
72
73
|
Layout = "layout",
|
|
@@ -228,6 +229,7 @@ export interface Job extends FirestoreDoc, Timestamps {
|
|
|
228
229
|
description?: string;
|
|
229
230
|
starred?: boolean;
|
|
230
231
|
lastModified: Date;
|
|
232
|
+
bgImgUpdatedAt?: number;
|
|
231
233
|
}
|
|
232
234
|
export interface Section extends Timestamps {
|
|
233
235
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
|
-
import type { AnnotationCanvasInnerProps } from './AnnotationCanvasInner.js';
|
|
3
|
-
export type { AnnotationCanvasHandle, GestureConfig, PanTrigger, } from './AnnotationCanvasInner.js';
|
|
4
|
-
export interface CanvasKitOpts {
|
|
5
|
-
locateFile?: (file: string) => string;
|
|
6
|
-
}
|
|
7
|
-
export type AnnotationCanvasProps = AnnotationCanvasInnerProps & {
|
|
8
|
-
fallback?: ReactNode;
|
|
9
|
-
canvasKitOpts?: CanvasKitOpts;
|
|
10
|
-
};
|
|
11
|
-
export declare const AnnotationCanvas: ({ fallback, canvasKitOpts, ...rest }: AnnotationCanvasProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { WithSkiaWeb } from '@shopify/react-native-skia/lib/module/web/index.js';
|
|
3
|
-
// Web-only entry point: lazy-loads CanvasKit wasm via WithSkiaWeb. Imperative
|
|
4
|
-
// API (undo/redo/zoom) is exposed through the `imperativeRef` prop rather
|
|
5
|
-
// than React refs, since WithSkiaWeb can't forward refs through its lazy
|
|
6
|
-
// component boundary. The native build sits in `AnnotationCanvas.native.tsx`
|
|
7
|
-
// and skips WithSkiaWeb entirely (no wasm to load).
|
|
8
|
-
export const AnnotationCanvas = ({ fallback, canvasKitOpts, ...rest }) => (_jsx(WithSkiaWeb, { getComponent: () => import('./AnnotationCanvasInner.js').then((m) => ({
|
|
9
|
-
default: m.AnnotationCanvasInner,
|
|
10
|
-
})), fallback: fallback ?? null, componentProps: rest, opts: canvasKitOpts }));
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { AnnotationCanvasInnerProps } from './AnnotationCanvasInner.native.js';
|
|
2
|
-
export type { AnnotationCanvasHandle, } from './useAnnotationCanvasState.js';
|
|
3
|
-
export type { GestureConfig, PanTrigger, } from './AnnotationCanvasInner.js';
|
|
4
|
-
export type AnnotationCanvasProps = AnnotationCanvasInnerProps & {
|
|
5
|
-
fallback?: unknown;
|
|
6
|
-
canvasKitOpts?: unknown;
|
|
7
|
-
};
|
|
8
|
-
export declare const AnnotationCanvas: (props: AnnotationCanvasProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { AnnotationCanvasInner } from './AnnotationCanvasInner.native.js';
|
|
3
|
-
export const AnnotationCanvas = (props) => {
|
|
4
|
-
const { fallback: _f, canvasKitOpts: _o, ...rest } = props;
|
|
5
|
-
return _jsx(AnnotationCanvasInner, { ...rest });
|
|
6
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { type CSSProperties, type MutableRefObject } from 'react';
|
|
2
|
-
import type { DecimalTolerance, FractionalTolerance, Measurement, Units } from '../types/firestore.js';
|
|
3
|
-
import type { AnnotationCanvasState, AnnotationDocumentPatch, Selection } from '../types/annotation.js';
|
|
4
|
-
import type { MeasurementRef } from './measurementPicker.js';
|
|
5
|
-
import type { Tool } from './Tool.js';
|
|
6
|
-
import { type AnnotationCanvasHandle } from './useAnnotationCanvasState.js';
|
|
7
|
-
import { type ViewportState } from './viewport.js';
|
|
8
|
-
import type { RenderMeasurementStamp } from './measurementStampOverlay.js';
|
|
9
|
-
export type { AnnotationCanvasHandle };
|
|
10
|
-
export interface AnnotationCanvasInnerProps {
|
|
11
|
-
canvas: AnnotationCanvasState;
|
|
12
|
-
onCommit(patch: AnnotationDocumentPatch): void;
|
|
13
|
-
tools: Tool[];
|
|
14
|
-
activeToolId: string;
|
|
15
|
-
selection: Selection | null;
|
|
16
|
-
onSelectionChange(selection: Selection | null): void;
|
|
17
|
-
measurements?: Measurement[];
|
|
18
|
-
fallbackUnit?: Units;
|
|
19
|
-
fractionalTolerance?: FractionalTolerance;
|
|
20
|
-
decimalTolerance?: DecimalTolerance;
|
|
21
|
-
resolveImageUrl?: (storagePath: string) => Promise<string>;
|
|
22
|
-
pickMeasurement?: () => Promise<MeasurementRef | null>;
|
|
23
|
-
renderMeasurementStamp?: RenderMeasurementStamp;
|
|
24
|
-
stampFontSource?: unknown;
|
|
25
|
-
stampValueFontSize?: number;
|
|
26
|
-
stampLabelFontSize?: number;
|
|
27
|
-
gestures?: GestureConfig;
|
|
28
|
-
width: number;
|
|
29
|
-
height: number;
|
|
30
|
-
initialViewport?: ViewportState;
|
|
31
|
-
style?: CSSProperties;
|
|
32
|
-
imperativeRef?: MutableRefObject<AnnotationCanvasHandle | null>;
|
|
33
|
-
}
|
|
34
|
-
export type PanTrigger = 'middleMouse' | 'rightMouse' | 'space';
|
|
35
|
-
export interface GestureConfig {
|
|
36
|
-
wheel?: 'zoom' | 'pan' | 'auto';
|
|
37
|
-
panTriggers?: PanTrigger[];
|
|
38
|
-
}
|
|
39
|
-
export declare const AnnotationCanvasInner: (props: AnnotationCanvasInnerProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,219 +0,0 @@
|
|
|
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';
|
|
4
|
-
import { AnnotationCanvasSkia } from './AnnotationCanvasSkia.js';
|
|
5
|
-
import { useAnnotationCanvasState, } from './useAnnotationCanvasState.js';
|
|
6
|
-
import { STAMP_TILE_SIZE } from './stampLayout.js';
|
|
7
|
-
const DEFAULT_PAN_TRIGGERS = ['middleMouse', 'space'];
|
|
8
|
-
export const AnnotationCanvasInner = (props) => {
|
|
9
|
-
const { fallbackUnit, fractionalTolerance, decimalTolerance, resolveImageUrl, stampFontSource, stampValueFontSize = 14, stampLabelFontSize = 11, gestures, width, height, style, activeToolId, tools, } = props;
|
|
10
|
-
const wheelMode = gestures?.wheel ?? 'auto';
|
|
11
|
-
const panTriggers = gestures?.panTriggers ?? DEFAULT_PAN_TRIGGERS;
|
|
12
|
-
const allowSpacePan = panTriggers.includes('space');
|
|
13
|
-
const allowMiddlePan = panTriggers.includes('middleMouse');
|
|
14
|
-
const allowRightPan = panTriggers.includes('rightMouse');
|
|
15
|
-
const valueFont = useFont(stampFontSource, stampValueFontSize);
|
|
16
|
-
const labelFont = useFont(stampFontSource, stampLabelFontSize);
|
|
17
|
-
const state = useAnnotationCanvasState(props);
|
|
18
|
-
const containerRef = useRef(null);
|
|
19
|
-
const panGestureRef = useRef(null);
|
|
20
|
-
const spaceDownRef = useRef(false);
|
|
21
|
-
const activeTool = tools.find((t) => t.id === activeToolId) ?? null;
|
|
22
|
-
const toCanvasPointer = useCallback((event) => {
|
|
23
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
24
|
-
const screen = {
|
|
25
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
26
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
27
|
-
};
|
|
28
|
-
return {
|
|
29
|
-
pointerId: event.pointerId,
|
|
30
|
-
screen,
|
|
31
|
-
world: state.ctx.viewport.screenToWorld(screen),
|
|
32
|
-
pressure: event.pressure || undefined,
|
|
33
|
-
shiftKey: event.shiftKey,
|
|
34
|
-
altKey: event.altKey,
|
|
35
|
-
metaKey: event.metaKey,
|
|
36
|
-
ctrlKey: event.ctrlKey,
|
|
37
|
-
};
|
|
38
|
-
}, [state.ctx.viewport]);
|
|
39
|
-
const isPanTriggerDown = useCallback((event) => {
|
|
40
|
-
if (allowMiddlePan && event.button === 1)
|
|
41
|
-
return true;
|
|
42
|
-
if (allowRightPan && event.button === 2)
|
|
43
|
-
return true;
|
|
44
|
-
if (allowSpacePan && event.button === 0 && spaceDownRef.current)
|
|
45
|
-
return true;
|
|
46
|
-
return false;
|
|
47
|
-
}, [allowMiddlePan, allowRightPan, allowSpacePan]);
|
|
48
|
-
const handlePointerDown = useCallback((event) => {
|
|
49
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
50
|
-
const screen = {
|
|
51
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
52
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
53
|
-
};
|
|
54
|
-
if (isPanTriggerDown(event)) {
|
|
55
|
-
panGestureRef.current = { pointerId: event.pointerId, lastScreen: screen };
|
|
56
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
57
|
-
event.preventDefault();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
61
|
-
state.dispatchPointerDown(toCanvasPointer(event));
|
|
62
|
-
}, [state, toCanvasPointer, isPanTriggerDown]);
|
|
63
|
-
const handlePointerMove = useCallback((event) => {
|
|
64
|
-
const pan = panGestureRef.current;
|
|
65
|
-
if (pan && event.pointerId === pan.pointerId) {
|
|
66
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
67
|
-
const screen = {
|
|
68
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
69
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
70
|
-
};
|
|
71
|
-
state.pan({
|
|
72
|
-
x: screen.x - pan.lastScreen.x,
|
|
73
|
-
y: screen.y - pan.lastScreen.y,
|
|
74
|
-
});
|
|
75
|
-
panGestureRef.current = { pointerId: pan.pointerId, lastScreen: screen };
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
state.dispatchPointerMove(toCanvasPointer(event));
|
|
79
|
-
}, [state, toCanvasPointer]);
|
|
80
|
-
const handlePointerUp = useCallback((event) => {
|
|
81
|
-
const pan = panGestureRef.current;
|
|
82
|
-
if (pan && event.pointerId === pan.pointerId) {
|
|
83
|
-
panGestureRef.current = null;
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
state.dispatchPointerUp(toCanvasPointer(event));
|
|
87
|
-
}, [state, toCanvasPointer]);
|
|
88
|
-
const handlePointerCancel = useCallback(() => {
|
|
89
|
-
panGestureRef.current = null;
|
|
90
|
-
state.dispatchPointerCancel();
|
|
91
|
-
}, [state]);
|
|
92
|
-
const handleWheel = useCallback((event) => {
|
|
93
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
94
|
-
const focal = {
|
|
95
|
-
x: event.clientX - (rect?.left ?? 0),
|
|
96
|
-
y: event.clientY - (rect?.top ?? 0),
|
|
97
|
-
};
|
|
98
|
-
if (event.ctrlKey || event.metaKey) {
|
|
99
|
-
const factor = Math.exp(-event.deltaY / 200);
|
|
100
|
-
state.zoom(focal, state.ctx.viewport.state.zoom * factor);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (wheelMode === 'zoom') {
|
|
104
|
-
const factor = Math.exp(-event.deltaY / 300);
|
|
105
|
-
state.zoom(focal, state.ctx.viewport.state.zoom * factor);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (event.shiftKey) {
|
|
109
|
-
state.pan({ x: event.deltaY, y: event.deltaX });
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
state.pan({ x: event.deltaX, y: event.deltaY });
|
|
113
|
-
}, [state, wheelMode]);
|
|
114
|
-
const handleContextMenu = useCallback((event) => {
|
|
115
|
-
if (allowRightPan)
|
|
116
|
-
event.preventDefault();
|
|
117
|
-
}, [allowRightPan]);
|
|
118
|
-
useEffect(() => {
|
|
119
|
-
const el = containerRef.current;
|
|
120
|
-
if (!el)
|
|
121
|
-
return;
|
|
122
|
-
const stop = (e) => {
|
|
123
|
-
if (e.target === el || el.contains(e.target)) {
|
|
124
|
-
e.preventDefault();
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
el.addEventListener('wheel', stop, { passive: false });
|
|
128
|
-
return () => el.removeEventListener('wheel', stop);
|
|
129
|
-
}, []);
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
if (!allowSpacePan)
|
|
132
|
-
return;
|
|
133
|
-
const onKeyDown = (e) => {
|
|
134
|
-
if (e.code === 'Space' && !e.repeat) {
|
|
135
|
-
spaceDownRef.current = true;
|
|
136
|
-
if (containerRef.current)
|
|
137
|
-
containerRef.current.style.cursor = 'grab';
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
const onKeyUp = (e) => {
|
|
141
|
-
if (e.code === 'Space') {
|
|
142
|
-
spaceDownRef.current = false;
|
|
143
|
-
if (containerRef.current)
|
|
144
|
-
containerRef.current.style.cursor = '';
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
window.addEventListener('keydown', onKeyDown);
|
|
148
|
-
window.addEventListener('keyup', onKeyUp);
|
|
149
|
-
return () => {
|
|
150
|
-
window.removeEventListener('keydown', onKeyDown);
|
|
151
|
-
window.removeEventListener('keyup', onKeyUp);
|
|
152
|
-
};
|
|
153
|
-
}, [allowSpacePan]);
|
|
154
|
-
const containerStyle = {
|
|
155
|
-
position: 'relative',
|
|
156
|
-
width,
|
|
157
|
-
height,
|
|
158
|
-
overflow: 'hidden',
|
|
159
|
-
touchAction: 'none',
|
|
160
|
-
userSelect: 'none',
|
|
161
|
-
cursor: activeTool?.cursor ?? 'default',
|
|
162
|
-
...style,
|
|
163
|
-
};
|
|
164
|
-
const customPreview = activeTool?.renderPreview?.(state.customPreviewState, state.ctx);
|
|
165
|
-
const { renderMeasurementStamp, selection } = props;
|
|
166
|
-
return (_jsxs("div", { ref: containerRef, style: containerStyle, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, onPointerCancel: handlePointerCancel, onWheel: handleWheel, onContextMenu: handleContextMenu, children: [AnnotationCanvasSkia({
|
|
167
|
-
width,
|
|
168
|
-
height,
|
|
169
|
-
effectiveCanvas: state.effectiveCanvas,
|
|
170
|
-
worldTransform: state.worldTransform,
|
|
171
|
-
measurementsById: state.measurementsById,
|
|
172
|
-
fallbackUnit,
|
|
173
|
-
fractionalTolerance,
|
|
174
|
-
decimalTolerance,
|
|
175
|
-
resolveImageUrl,
|
|
176
|
-
valueFont,
|
|
177
|
-
labelFont,
|
|
178
|
-
hideMeasurementStamps: !!renderMeasurementStamp,
|
|
179
|
-
penDrawingStroke: state.penDrawingStroke,
|
|
180
|
-
customPreview,
|
|
181
|
-
}), renderMeasurementStamp && (_jsx("div", { style: {
|
|
182
|
-
position: 'absolute',
|
|
183
|
-
inset: 0,
|
|
184
|
-
pointerEvents: 'none',
|
|
185
|
-
}, children: state.effectiveCanvas.placedMeasurements.map((placed) => {
|
|
186
|
-
const size = STAMP_TILE_SIZE * (placed.scale ?? 1);
|
|
187
|
-
const cx = (placed.anchor.x - state.viewport.pan.x) * state.viewport.zoom;
|
|
188
|
-
const cy = (placed.anchor.y - state.viewport.pan.y) * state.viewport.zoom;
|
|
189
|
-
const isSelected = selection?.ids.includes(placed.id) ?? false;
|
|
190
|
-
return (_jsxs("div", { style: {
|
|
191
|
-
position: 'absolute',
|
|
192
|
-
left: 0,
|
|
193
|
-
top: 0,
|
|
194
|
-
width: size,
|
|
195
|
-
height: size,
|
|
196
|
-
transform: `translate(${cx - size / 2}px, ${cy - size / 2}px)`,
|
|
197
|
-
}, children: [renderMeasurementStamp({
|
|
198
|
-
placed,
|
|
199
|
-
measurement: state.measurementsById.get(placed.measurementId) ?? null,
|
|
200
|
-
selected: isSelected,
|
|
201
|
-
size,
|
|
202
|
-
zoom: state.viewport.zoom,
|
|
203
|
-
}), isSelected && (_jsx("div", { role: "button", "aria-label": "Remove measurement", onPointerDown: (e) => {
|
|
204
|
-
e.stopPropagation();
|
|
205
|
-
state.ctx.commit({
|
|
206
|
-
ops: [{ op: 'removeMeasurement', id: placed.id }],
|
|
207
|
-
});
|
|
208
|
-
state.ctx.setSelection(null);
|
|
209
|
-
}, style: {
|
|
210
|
-
position: 'absolute',
|
|
211
|
-
top: -10,
|
|
212
|
-
right: -10,
|
|
213
|
-
width: 40,
|
|
214
|
-
height: 40,
|
|
215
|
-
cursor: 'pointer',
|
|
216
|
-
pointerEvents: 'auto',
|
|
217
|
-
} }))] }, placed.id));
|
|
218
|
-
}) }))] }));
|
|
219
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { type MutableRefObject } from 'react';
|
|
2
|
-
import { type ViewStyle } from 'react-native';
|
|
3
|
-
import type { RenderMeasurementStamp } from './measurementStampOverlay.js';
|
|
4
|
-
import type { DecimalTolerance, FractionalTolerance, Measurement, Units } from '../types/firestore.js';
|
|
5
|
-
import type { AnnotationCanvasState, AnnotationDocumentPatch, Selection } from '../types/annotation.js';
|
|
6
|
-
import type { MeasurementRef } from './measurementPicker.js';
|
|
7
|
-
import type { Tool } from './Tool.js';
|
|
8
|
-
import { type AnnotationCanvasHandle } from './useAnnotationCanvasState.js';
|
|
9
|
-
import type { ViewportState } from './viewport.js';
|
|
10
|
-
export type { AnnotationCanvasHandle };
|
|
11
|
-
export interface AnnotationCanvasInnerProps {
|
|
12
|
-
canvas: AnnotationCanvasState;
|
|
13
|
-
onCommit(patch: AnnotationDocumentPatch): void;
|
|
14
|
-
tools: Tool[];
|
|
15
|
-
activeToolId: string;
|
|
16
|
-
selection: Selection | null;
|
|
17
|
-
onSelectionChange(selection: Selection | null): void;
|
|
18
|
-
measurements?: Measurement[];
|
|
19
|
-
fallbackUnit?: Units;
|
|
20
|
-
fractionalTolerance?: FractionalTolerance;
|
|
21
|
-
decimalTolerance?: DecimalTolerance;
|
|
22
|
-
resolveImageUrl?: (storagePath: string) => Promise<string>;
|
|
23
|
-
pickMeasurement?: () => Promise<MeasurementRef | null>;
|
|
24
|
-
renderMeasurementStamp?: RenderMeasurementStamp;
|
|
25
|
-
stampFontSource?: unknown;
|
|
26
|
-
stampValueFontSize?: number;
|
|
27
|
-
stampLabelFontSize?: number;
|
|
28
|
-
gestures?: unknown;
|
|
29
|
-
width: number;
|
|
30
|
-
height: number;
|
|
31
|
-
initialViewport?: ViewportState;
|
|
32
|
-
style?: ViewStyle;
|
|
33
|
-
imperativeRef?: MutableRefObject<AnnotationCanvasHandle | null>;
|
|
34
|
-
}
|
|
35
|
-
export declare const AnnotationCanvasInner: (props: AnnotationCanvasInnerProps) => import("react/jsx-runtime").JSX.Element;
|