@reekon-tools/boldr-utils 1.10.3 → 1.11.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/calculator/chips.d.ts +32 -0
- package/dist/calculator/chips.js +79 -0
- package/dist/calculator/display.d.ts +78 -0
- package/dist/calculator/display.js +223 -0
- package/dist/calculator/index.d.ts +3 -0
- package/dist/calculator/index.js +8 -3
- package/dist/calculator/runtime.d.ts +61 -0
- package/dist/calculator/runtime.js +430 -0
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.js +3 -0
- package/dist/theme/preset.d.ts +120 -0
- package/dist/theme/preset.js +25 -0
- package/dist/theme/semantic.d.ts +136 -0
- package/dist/theme/semantic.js +116 -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
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural shape of a Tailwind `theme.extend.colors` tree.
|
|
3
|
+
*
|
|
4
|
+
* Declared locally on purpose: annotating with tailwindcss's own `Config` type
|
|
5
|
+
* would put `import type { Config } from 'tailwindcss'` into the emitted .d.ts
|
|
6
|
+
* and make tailwindcss a hard type dependency of this package.
|
|
7
|
+
*/
|
|
8
|
+
export type ColorTree = {
|
|
9
|
+
[key: string]: string | ColorTree;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Semantic design tokens — the layer apps actually consume.
|
|
13
|
+
*
|
|
14
|
+
* `colors.ts` is the palette (raw Figma variables, named by value).
|
|
15
|
+
* This file maps those values onto *roles*, and is the only color surface the
|
|
16
|
+
* apps should reference. The raw palette is deliberately NOT exposed as Tailwind
|
|
17
|
+
* classes; naming by value is how both apps accumulated hundreds of arbitrary
|
|
18
|
+
* hex classes in the first place.
|
|
19
|
+
*
|
|
20
|
+
* The shadcn/ui token names (background, card, popover, foreground, muted,
|
|
21
|
+
* accent, secondary, border, input, ring, primary, destructive) are reused
|
|
22
|
+
* rather than paralleled, so every shadcn component is re-skinned without any
|
|
23
|
+
* component edits and `shadcn add` keeps generating markup that lands on these
|
|
24
|
+
* tokens.
|
|
25
|
+
*
|
|
26
|
+
* The design is dark-only. The light calculator / form surfaces are the
|
|
27
|
+
* explicitly-named `paper.*` tokens, not a light/dark variant pair — on native
|
|
28
|
+
* NativeWind's `dark:` variant is global, and portal-rendered surfaces
|
|
29
|
+
* (bottom sheets, dialogs, selects) mount outside any scoped subtree, so a
|
|
30
|
+
* scoped override would leak dark chrome onto a light page.
|
|
31
|
+
*/
|
|
32
|
+
export declare const boldrColors: {
|
|
33
|
+
background: "#1D1F21";
|
|
34
|
+
foreground: {
|
|
35
|
+
DEFAULT: "#FFFFFF";
|
|
36
|
+
disabled: "#626364";
|
|
37
|
+
};
|
|
38
|
+
card: {
|
|
39
|
+
DEFAULT: "#2B2C2E";
|
|
40
|
+
foreground: "#FFFFFF";
|
|
41
|
+
};
|
|
42
|
+
popover: {
|
|
43
|
+
DEFAULT: "#2B2C2E";
|
|
44
|
+
foreground: "#FFFFFF";
|
|
45
|
+
};
|
|
46
|
+
muted: {
|
|
47
|
+
DEFAULT: "#424345";
|
|
48
|
+
foreground: "#9FA0A2";
|
|
49
|
+
};
|
|
50
|
+
accent: {
|
|
51
|
+
DEFAULT: "#424345";
|
|
52
|
+
foreground: "#FFFFFF";
|
|
53
|
+
};
|
|
54
|
+
secondary: {
|
|
55
|
+
DEFAULT: "#424345";
|
|
56
|
+
foreground: "#FFFFFF";
|
|
57
|
+
};
|
|
58
|
+
border: {
|
|
59
|
+
DEFAULT: "#424345";
|
|
60
|
+
strong: "#626364";
|
|
61
|
+
};
|
|
62
|
+
input: "#424345";
|
|
63
|
+
ring: "#FFAD00";
|
|
64
|
+
primary: {
|
|
65
|
+
DEFAULT: "#FFAD00";
|
|
66
|
+
foreground: "#1D1F21";
|
|
67
|
+
};
|
|
68
|
+
destructive: {
|
|
69
|
+
DEFAULT: "#DF6358";
|
|
70
|
+
foreground: "#1D1F21";
|
|
71
|
+
};
|
|
72
|
+
/** Chips, inset controls, thumbnail placeholders. */
|
|
73
|
+
elevated: {
|
|
74
|
+
DEFAULT: "#424345";
|
|
75
|
+
foreground: "#FFFFFF";
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Steppers and other interactive fills. FILL ONLY — #0066FF as text on
|
|
79
|
+
* #2B2C2E is 2.89:1. Never `text-interactive`.
|
|
80
|
+
*/
|
|
81
|
+
interactive: {
|
|
82
|
+
DEFAULT: "#0066FF";
|
|
83
|
+
foreground: "#FFFFFF";
|
|
84
|
+
};
|
|
85
|
+
/** Nav chrome (the web app's sidebar). */
|
|
86
|
+
nav: {
|
|
87
|
+
DEFAULT: "#2D3843";
|
|
88
|
+
foreground: "#FFFFFF";
|
|
89
|
+
};
|
|
90
|
+
paper: {
|
|
91
|
+
DEFAULT: "#E8EAED";
|
|
92
|
+
foreground: "#1D1F21";
|
|
93
|
+
field: "#FFFFFF";
|
|
94
|
+
line: "#BCBEC2";
|
|
95
|
+
muted: "#626364";
|
|
96
|
+
};
|
|
97
|
+
tile: {
|
|
98
|
+
/**
|
|
99
|
+
* Ink for any tile fill — `text-tile-foreground`. Shared across the
|
|
100
|
+
* measurement and formula variants because both carry white type; keeping it
|
|
101
|
+
* at the family level avoids two identical `foreground` keys that could
|
|
102
|
+
* drift apart by accident.
|
|
103
|
+
*/
|
|
104
|
+
foreground: "#FFFFFF";
|
|
105
|
+
measurement: {
|
|
106
|
+
DEFAULT: "#0066FF";
|
|
107
|
+
badge: "#50A6FF";
|
|
108
|
+
};
|
|
109
|
+
formula: {
|
|
110
|
+
DEFAULT: "#BD30A8";
|
|
111
|
+
badge: "#6C155F";
|
|
112
|
+
};
|
|
113
|
+
count: {
|
|
114
|
+
DEFAULT: "#02274B";
|
|
115
|
+
foreground: "#FFFFFF";
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
diagram: {
|
|
119
|
+
1: "#2E4C6A";
|
|
120
|
+
2: "#4B6074";
|
|
121
|
+
3: "#67819A";
|
|
122
|
+
};
|
|
123
|
+
tolerance: {
|
|
124
|
+
in: {
|
|
125
|
+
DEFAULT: "#58A942";
|
|
126
|
+
warning: "#00E920";
|
|
127
|
+
muted: "#8BB380";
|
|
128
|
+
};
|
|
129
|
+
out: {
|
|
130
|
+
DEFAULT: "#E83D2F";
|
|
131
|
+
warning: "#DA1100";
|
|
132
|
+
muted: "#DF6358";
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
export type BoldrColors = typeof boldrColors;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { GeneralColors, SecondaryColors, FormColors, TileColors, FormulaColors, YellowColors, RedColors, GreenColors, } from './colors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Semantic design tokens — the layer apps actually consume.
|
|
4
|
+
*
|
|
5
|
+
* `colors.ts` is the palette (raw Figma variables, named by value).
|
|
6
|
+
* This file maps those values onto *roles*, and is the only color surface the
|
|
7
|
+
* apps should reference. The raw palette is deliberately NOT exposed as Tailwind
|
|
8
|
+
* classes; naming by value is how both apps accumulated hundreds of arbitrary
|
|
9
|
+
* hex classes in the first place.
|
|
10
|
+
*
|
|
11
|
+
* The shadcn/ui token names (background, card, popover, foreground, muted,
|
|
12
|
+
* accent, secondary, border, input, ring, primary, destructive) are reused
|
|
13
|
+
* rather than paralleled, so every shadcn component is re-skinned without any
|
|
14
|
+
* component edits and `shadcn add` keeps generating markup that lands on these
|
|
15
|
+
* tokens.
|
|
16
|
+
*
|
|
17
|
+
* The design is dark-only. The light calculator / form surfaces are the
|
|
18
|
+
* explicitly-named `paper.*` tokens, not a light/dark variant pair — on native
|
|
19
|
+
* NativeWind's `dark:` variant is global, and portal-rendered surfaces
|
|
20
|
+
* (bottom sheets, dialogs, selects) mount outside any scoped subtree, so a
|
|
21
|
+
* scoped override would leak dark chrome onto a light page.
|
|
22
|
+
*/
|
|
23
|
+
export const boldrColors = {
|
|
24
|
+
// ── dark app chrome — shadcn-compatible names, re-pointed ────────────────
|
|
25
|
+
background: GeneralColors.darkGrey, // screen + header
|
|
26
|
+
foreground: {
|
|
27
|
+
DEFAULT: GeneralColors.white,
|
|
28
|
+
disabled: GeneralColors.grey3, // text-foreground-disabled
|
|
29
|
+
},
|
|
30
|
+
card: { DEFAULT: GeneralColors.grey1, foreground: GeneralColors.white },
|
|
31
|
+
popover: { DEFAULT: GeneralColors.grey1, foreground: GeneralColors.white },
|
|
32
|
+
// muted / accent / secondary exist so unmodified shadcn components look
|
|
33
|
+
// right. Prefer `elevated` in new boldr components — it gives future
|
|
34
|
+
// divergence a seam.
|
|
35
|
+
muted: { DEFAULT: GeneralColors.grey2, foreground: GeneralColors.grey4 },
|
|
36
|
+
accent: { DEFAULT: GeneralColors.grey2, foreground: GeneralColors.white },
|
|
37
|
+
secondary: { DEFAULT: GeneralColors.grey2, foreground: GeneralColors.white },
|
|
38
|
+
border: { DEFAULT: GeneralColors.grey2, strong: GeneralColors.grey3 },
|
|
39
|
+
input: GeneralColors.grey2,
|
|
40
|
+
ring: YellowColors.mainYellow,
|
|
41
|
+
primary: {
|
|
42
|
+
DEFAULT: YellowColors.mainYellow,
|
|
43
|
+
// White on #FFAD00 is 1.87:1. Dark ink is 8.84:1, and matches the mockups.
|
|
44
|
+
foreground: GeneralColors.darkGrey,
|
|
45
|
+
},
|
|
46
|
+
destructive: {
|
|
47
|
+
DEFAULT: RedColors.mutedRed,
|
|
48
|
+
// Confirmed against the Settings frame: the Log Out label is dark ink.
|
|
49
|
+
// White on #DF6358 would be 3.46:1; #1D1F21 is 4.77:1.
|
|
50
|
+
foreground: GeneralColors.darkGrey,
|
|
51
|
+
},
|
|
52
|
+
// ── boldr additions the shadcn vocabulary has no word for ───────────────
|
|
53
|
+
/** Chips, inset controls, thumbnail placeholders. */
|
|
54
|
+
elevated: { DEFAULT: GeneralColors.grey2, foreground: GeneralColors.white },
|
|
55
|
+
/**
|
|
56
|
+
* Steppers and other interactive fills. FILL ONLY — #0066FF as text on
|
|
57
|
+
* #2B2C2E is 2.89:1. Never `text-interactive`.
|
|
58
|
+
*/
|
|
59
|
+
interactive: {
|
|
60
|
+
DEFAULT: TileColors.activeBlue,
|
|
61
|
+
foreground: GeneralColors.white,
|
|
62
|
+
},
|
|
63
|
+
/** Nav chrome (the web app's sidebar). */
|
|
64
|
+
nav: {
|
|
65
|
+
DEFAULT: SecondaryColors.accentBlue1,
|
|
66
|
+
foreground: GeneralColors.white,
|
|
67
|
+
},
|
|
68
|
+
// ── light "paper": the calculator page and form fields ──────────────────
|
|
69
|
+
paper: {
|
|
70
|
+
DEFAULT: FormColors.lightGrey2, // bg-paper page / canvas
|
|
71
|
+
foreground: GeneralColors.darkGrey, // text-paper-foreground
|
|
72
|
+
field: GeneralColors.white, // bg-paper-field inputs, cards on paper
|
|
73
|
+
line: FormColors.lightGrey1, // border-paper-line field borders, dividers
|
|
74
|
+
// grey3, not lightGrey1: #BCBEC2 on #E8EAED is 1.54:1 — invisible.
|
|
75
|
+
// lightGrey1 is a border color only, which is why it's `paper.line`.
|
|
76
|
+
muted: GeneralColors.grey3, // text-paper-muted
|
|
77
|
+
},
|
|
78
|
+
// ── product tiles ───────────────────────────────────────────────────────
|
|
79
|
+
tile: {
|
|
80
|
+
/**
|
|
81
|
+
* Ink for any tile fill — `text-tile-foreground`. Shared across the
|
|
82
|
+
* measurement and formula variants because both carry white type; keeping it
|
|
83
|
+
* at the family level avoids two identical `foreground` keys that could
|
|
84
|
+
* drift apart by accident.
|
|
85
|
+
*/
|
|
86
|
+
foreground: GeneralColors.white,
|
|
87
|
+
measurement: {
|
|
88
|
+
DEFAULT: TileColors.activeBlue,
|
|
89
|
+
badge: TileColors.lightBlue1,
|
|
90
|
+
},
|
|
91
|
+
// Note the badge is DARKER than the tile here, inverting the old app-local
|
|
92
|
+
// values. Confirmed in the mockups: a magenta tile with a darker magenta
|
|
93
|
+
// label bar.
|
|
94
|
+
formula: { DEFAULT: FormulaColors.purple, badge: FormulaColors.darkPurple },
|
|
95
|
+
count: { DEFAULT: TileColors.darkBlue, foreground: GeneralColors.white },
|
|
96
|
+
},
|
|
97
|
+
// ── 3D / diagram depth ramp (ordered; the steps have no individual meaning) ─
|
|
98
|
+
diagram: {
|
|
99
|
+
1: SecondaryColors.accentBlue2,
|
|
100
|
+
2: SecondaryColors.accentBlue3,
|
|
101
|
+
3: SecondaryColors.accentBlue4,
|
|
102
|
+
},
|
|
103
|
+
// ── measurement tolerance ───────────────────────────────────────────────
|
|
104
|
+
tolerance: {
|
|
105
|
+
in: {
|
|
106
|
+
DEFAULT: GreenColors.green,
|
|
107
|
+
warning: GreenColors.warningGreen,
|
|
108
|
+
muted: GreenColors.mutedGreen,
|
|
109
|
+
},
|
|
110
|
+
out: {
|
|
111
|
+
DEFAULT: RedColors.red,
|
|
112
|
+
warning: RedColors.warningRed,
|
|
113
|
+
muted: RedColors.mutedRed,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
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;
|