@reekon-tools/boldr-utils 1.21.1 → 1.22.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.
Files changed (98) hide show
  1. package/dist/annotation/canvas/AnnotationCanvasSkia.js +3 -11
  2. package/dist/annotation/canvas/measurementLineStyle.d.ts +3 -0
  3. package/dist/annotation/canvas/measurementLineStyle.js +14 -0
  4. package/dist/export/pdf/color.d.ts +7 -0
  5. package/dist/export/pdf/color.js +39 -0
  6. package/dist/export/pdf/emit.d.ts +37 -0
  7. package/dist/export/pdf/emit.js +129 -0
  8. package/dist/export/pdf/fonts.d.ts +38 -0
  9. package/dist/export/pdf/fonts.js +97 -0
  10. package/dist/export/pdf/index.d.ts +5 -0
  11. package/dist/export/pdf/index.js +5 -0
  12. package/dist/export/pdf/layers.d.ts +5 -0
  13. package/dist/export/pdf/layers.js +19 -0
  14. package/dist/export/pdf/marks.d.ts +20 -0
  15. package/dist/export/pdf/marks.js +336 -0
  16. package/dist/export/pdf/pageMapping.d.ts +49 -0
  17. package/dist/export/pdf/pageMapping.js +67 -0
  18. package/dist/export/pdf/renderCanvasToPdf.d.ts +2 -0
  19. package/dist/export/pdf/renderCanvasToPdf.js +201 -0
  20. package/dist/export/pdf/tileContent.d.ts +39 -0
  21. package/dist/export/pdf/tileContent.js +218 -0
  22. package/dist/export/pdf/tiles.d.ts +43 -0
  23. package/dist/export/pdf/tiles.js +392 -0
  24. package/dist/export/pdf/types.d.ts +101 -0
  25. package/dist/export/pdf/types.js +10 -0
  26. package/dist/exports.d.ts +1 -1
  27. package/dist/exports.js +1 -1
  28. package/dist/formulas/calculateFormula.d.ts +1 -1
  29. package/dist/formulas/calculateFormula.js +23 -10
  30. package/dist/formulas/evaluateFormula.d.ts +0 -10
  31. package/dist/formulas/evaluateFormula.js +1 -12
  32. package/dist/formulas/groupFormula.d.ts +43 -0
  33. package/dist/formulas/groupFormula.js +168 -0
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.js +1 -1
  36. package/dist/server.d.ts +4 -1
  37. package/dist/server.js +6 -1
  38. package/package.json +4 -1
  39. package/dist/canvas/AnnotationCanvas.d.ts +0 -11
  40. package/dist/canvas/AnnotationCanvas.js +0 -10
  41. package/dist/canvas/AnnotationCanvas.native.d.ts +0 -8
  42. package/dist/canvas/AnnotationCanvas.native.js +0 -6
  43. package/dist/canvas/AnnotationCanvasInner.d.ts +0 -39
  44. package/dist/canvas/AnnotationCanvasInner.js +0 -219
  45. package/dist/canvas/AnnotationCanvasInner.native.d.ts +0 -35
  46. package/dist/canvas/AnnotationCanvasInner.native.js +0 -138
  47. package/dist/canvas/AnnotationCanvasSkia.d.ts +0 -27
  48. package/dist/canvas/AnnotationCanvasSkia.js +0 -20
  49. package/dist/canvas/Tool.d.ts +0 -38
  50. package/dist/canvas/Tool.js +0 -1
  51. package/dist/canvas/elements/BackgroundImageElement.d.ts +0 -9
  52. package/dist/canvas/elements/BackgroundImageElement.js +0 -37
  53. package/dist/canvas/elements/MeasurementStampElement.d.ts +0 -13
  54. package/dist/canvas/elements/MeasurementStampElement.js +0 -30
  55. package/dist/canvas/elements/ShapeElement.d.ts +0 -7
  56. package/dist/canvas/elements/ShapeElement.js +0 -62
  57. package/dist/canvas/elements/StrokeElement.d.ts +0 -7
  58. package/dist/canvas/elements/StrokeElement.js +0 -18
  59. package/dist/canvas/measurementPicker.d.ts +0 -10
  60. package/dist/canvas/measurementPicker.js +0 -1
  61. package/dist/canvas/measurementStampOverlay.d.ts +0 -11
  62. package/dist/canvas/measurementStampOverlay.js +0 -1
  63. package/dist/canvas/pointerAdapter.d.ts +0 -3
  64. package/dist/canvas/pointerAdapter.js +0 -19
  65. package/dist/canvas/stampLayout.d.ts +0 -5
  66. package/dist/canvas/stampLayout.js +0 -14
  67. package/dist/canvas/tools/measurementStampTool.d.ts +0 -9
  68. package/dist/canvas/tools/measurementStampTool.js +0 -37
  69. package/dist/canvas/tools/panTool.d.ts +0 -5
  70. package/dist/canvas/tools/panTool.js +0 -25
  71. package/dist/canvas/tools/penTool.d.ts +0 -13
  72. package/dist/canvas/tools/penTool.js +0 -68
  73. package/dist/canvas/tools/selectTool.d.ts +0 -2
  74. package/dist/canvas/tools/selectTool.js +0 -182
  75. package/dist/canvas/useAnnotationCanvasState.d.ts +0 -54
  76. package/dist/canvas/useAnnotationCanvasState.js +0 -210
  77. package/dist/canvas/viewport.d.ts +0 -16
  78. package/dist/canvas/viewport.js +0 -54
  79. package/dist/data/AnnotationDataContext.d.ts +0 -8
  80. package/dist/data/AnnotationDataContext.js +0 -11
  81. package/dist/data/AnnotationDataProvider.d.ts +0 -65
  82. package/dist/data/AnnotationDataProvider.js +0 -4
  83. package/dist/data/InMemoryAnnotationProvider.d.ts +0 -30
  84. package/dist/data/InMemoryAnnotationProvider.js +0 -197
  85. package/dist/data/canvasPersistence.d.ts +0 -3
  86. package/dist/data/canvasPersistence.js +0 -26
  87. package/dist/data/hooks/useAnnotationCanvasDoc.d.ts +0 -33
  88. package/dist/data/hooks/useAnnotationCanvasDoc.js +0 -314
  89. package/dist/data/hooks/useAnnotationDoc.d.ts +0 -7
  90. package/dist/data/hooks/useAnnotationDoc.js +0 -33
  91. package/dist/data/hooks/useAnnotationList.d.ts +0 -7
  92. package/dist/data/hooks/useAnnotationList.js +0 -26
  93. package/dist/data/hooks/useAnnotationMutations.d.ts +0 -9
  94. package/dist/data/hooks/useAnnotationMutations.js +0 -11
  95. package/dist/hooks/useParseMeasurement.d.ts +0 -4
  96. package/dist/hooks/useParseMeasurement.js +0 -14
  97. package/dist/utils/evaluateFormula.d.ts +0 -20
  98. package/dist/utils/evaluateFormula.js +0 -31
@@ -0,0 +1,39 @@
1
+ import type { AnnotationCanvasState, PlacedMeasurementRef } from '../../types/annotation.js';
2
+ import { DecimalTolerance, FractionalTolerance, Units, type Formula, type Group, type Measurement, type Section } from '../../types/firestore.js';
3
+ import type { EmbeddedImage, ResolvedTileContent } from './types.js';
4
+ /** Fill for a FORM formula-column tile (the job page's purple). */
5
+ export declare const FORMULA_COLUMN_TILE_FILL = "#7B4783";
6
+ /** Fill for a plane-computed length tile (calibration teal). */
7
+ export declare const PLANE_COMPUTED_TILE_FILL = "#0E7490";
8
+ export interface TileFileInfo {
9
+ name: string;
10
+ type?: string;
11
+ thumbnail?: EmbeddedImage;
12
+ }
13
+ export interface TileResolutionContext {
14
+ canvas: Pick<AnnotationCanvasState, 'planes'>;
15
+ units: Units;
16
+ fractionalTolerance?: FractionalTolerance;
17
+ decimalTolerance?: DecimalTolerance;
18
+ groups: Group[];
19
+ sections: Section[];
20
+ /** Every measurement a tile may reference, by id. */
21
+ measurementsById: Map<string, Measurement>;
22
+ formulas?: Formula[];
23
+ /** Placed object files, by file id. */
24
+ filesById?: Map<string, TileFileInfo>;
25
+ /** The canvas file's own group — the fallback source group for a tile. */
26
+ hostGroupId?: string;
27
+ }
28
+ /**
29
+ * The tile fill, in measurementTileFill's precedence: unsaved scratch grey-blue,
30
+ * completed grey, an explicit colour, formula magenta, else tile blue.
31
+ */
32
+ export declare const measurementTileFillFor: ({ internal, isCompleted, groupFormula, color, }: {
33
+ internal?: boolean;
34
+ isCompleted?: boolean;
35
+ groupFormula?: unknown;
36
+ color?: string;
37
+ }) => string;
38
+ /** What a placed tile shows, from the documents in `ctx`. */
39
+ export declare const resolveTileContent: (placed: PlacedMeasurementRef, ctx: TileResolutionContext) => ResolvedTileContent;
@@ -0,0 +1,218 @@
1
+ // Resolve what each placed tile SHOWS, from the documents the caller loaded.
2
+ // A pure mirror of the mobile canvas's renderMeasurementStamp branches
3
+ // (skia-annotation.tsx) and the tile components' own rules (measurementTileFill,
4
+ // convertMicrometers, the position labels), so a server render and the screen
5
+ // agree on value, label and fill. No I/O: the caller fetches the docs.
6
+ import { ColumnType, DecimalTolerance, FractionalTolerance, MeasurementType, convertUnitsToReadable, } from '../../types/firestore.js';
7
+ import { describeGroupHeader } from '../../annotation/canvas/groupHeaderLayout.js';
8
+ import { planeDimensionValueUm, planeLengthForPlaced, } from '../../annotation/canvas/planeGeometry.js';
9
+ import { convertMicrometers } from '../../utils/micrometersToUnit.js';
10
+ import { formGroupInputLabel, listGroupMeasurementLabel, } from '../../utils/indexLabels.js';
11
+ import { calculateFormula } from '../../formulas/calculateFormula.js';
12
+ import { applyGroupFormulaUm } from '../../formulas/groupFormula.js';
13
+ import { FormulaColors, GeneralColors, SecondaryColors, TileColors, } from '../../theme/colors.js';
14
+ /** Fill for a FORM formula-column tile (the job page's purple). */
15
+ export const FORMULA_COLUMN_TILE_FILL = '#7B4783';
16
+ /** Fill for a plane-computed length tile (calibration teal). */
17
+ export const PLANE_COMPUTED_TILE_FILL = '#0E7490';
18
+ const isScalarType = (type) => (type ?? MeasurementType.Length) !== MeasurementType.Length;
19
+ /**
20
+ * The tile fill, in measurementTileFill's precedence: unsaved scratch grey-blue,
21
+ * completed grey, an explicit colour, formula magenta, else tile blue.
22
+ */
23
+ export const measurementTileFillFor = ({ internal, isCompleted, groupFormula, color, }) => {
24
+ if (internal)
25
+ return SecondaryColors.accentBlue3;
26
+ if (isCompleted)
27
+ return GeneralColors.grey3;
28
+ if (color)
29
+ return color;
30
+ if (groupFormula)
31
+ return FormulaColors.purple;
32
+ return TileColors.activeBlue;
33
+ };
34
+ const columnOf = (ctx, placed) => {
35
+ const group = ctx.groups.find((g) => g.id === placed.groupId);
36
+ const section = ctx.sections.find((s) => s.id === group?.sectionId);
37
+ const columnIndex = section?.tableConfig.findIndex((c) => c.id === placed.columnId) ?? -1;
38
+ const column = columnIndex >= 0 ? section?.tableConfig[columnIndex] : undefined;
39
+ return { group, section, column, columnIndex };
40
+ };
41
+ const columnTileLabels = (ctx, placed) => {
42
+ const { group, column, columnIndex } = columnOf(ctx, placed);
43
+ return {
44
+ topLeftLabel: formGroupInputLabel(columnIndex, group?.groupIndex ?? 0),
45
+ topRightLabel: convertUnitsToReadable(ctx.units) ?? '',
46
+ bottomLabel: column?.name ?? 'Measurement',
47
+ };
48
+ };
49
+ const tileGroup = (ctx, placed) => ctx.groups.find((g) => g.id === (placed.groupId ?? ctx.hostGroupId));
50
+ const convert = (ctx, um, unit, device) => convertMicrometers(um, unit, ctx.fractionalTolerance ?? FractionalTolerance.Sixteenth, ctx.decimalTolerance ?? DecimalTolerance.Hundredth, device);
51
+ const measurementContent = (ctx, placed, m, column, columnIndex) => {
52
+ const group = tileGroup(ctx, placed);
53
+ const groupIndex = group?.groupIndex ?? 0;
54
+ const positionLabel = placed.columnId
55
+ ? formGroupInputLabel(columnIndex, groupIndex)
56
+ : listGroupMeasurementLabel(m.deviceMeasurementNumber, groupIndex);
57
+ // MeasurementTile shows the measurement's own label first, then the host's
58
+ // `label` prop (the override, else the column name).
59
+ const label = m.label || placed.labelOverride || column?.name;
60
+ const fill = measurementTileFillFor({
61
+ internal: m.fileId != null,
62
+ isCompleted: !!m.isCompleted,
63
+ groupFormula: group?.formula,
64
+ });
65
+ const formulaBar = fill === FormulaColors.purple;
66
+ // Angles and unitless numbers are stored as typed — never converted.
67
+ const scalar = column?.type === ColumnType.Angle || (!column && isScalarType(m.type));
68
+ if (scalar) {
69
+ const suffix = column?.type === ColumnType.Angle || m.type === MeasurementType.Angle
70
+ ? '°'
71
+ : '';
72
+ return {
73
+ kind: 'measurement',
74
+ value: `${m.value}${suffix}`,
75
+ unit: '',
76
+ positionLabel,
77
+ label,
78
+ fill,
79
+ formulaBar,
80
+ };
81
+ }
82
+ const groupFormula = group?.formula;
83
+ const unit = placed.unitOverride ?? ctx.units;
84
+ const formulaUm = groupFormula
85
+ ? applyGroupFormulaUm(groupFormula, m.value, unit)
86
+ : null;
87
+ const um = formulaUm ?? m.value;
88
+ const converted = convert(ctx, Math.abs(um), unit, formulaUm != null ? undefined : m.device);
89
+ return {
90
+ kind: 'measurement',
91
+ value: converted.value,
92
+ unit: converted.unit,
93
+ positionLabel,
94
+ label,
95
+ fill,
96
+ formulaBar,
97
+ negative: um < 0,
98
+ };
99
+ };
100
+ /** What a placed tile shows, from the documents in `ctx`. */
101
+ export const resolveTileContent = (placed, ctx) => {
102
+ // Object tile: the placed file's preview.
103
+ if (placed.fileId) {
104
+ const file = ctx.filesById?.get(placed.fileId);
105
+ return file
106
+ ? {
107
+ kind: 'object',
108
+ name: file.name,
109
+ fileType: file.type,
110
+ thumbnail: file.thumbnail,
111
+ }
112
+ : { kind: 'object', name: 'Object removed' };
113
+ }
114
+ // Group-header chip.
115
+ if (placed.isGroupHeader) {
116
+ const group = ctx.groups.find((g) => g.id === placed.groupId);
117
+ const section = ctx.sections.find((s) => s.id === group?.sectionId);
118
+ return {
119
+ kind: 'header',
120
+ descriptor: describeGroupHeader({
121
+ group,
122
+ section,
123
+ collapsed: !!placed.collapsed,
124
+ }),
125
+ };
126
+ }
127
+ const { group, section, column, columnIndex } = columnOf(ctx, placed);
128
+ const columnType = column?.type;
129
+ // Plane-calibration dimension tile.
130
+ if (placed.planeEdge) {
131
+ const plane = ctx.canvas.planes?.find((p) => p.id === placed.planeId);
132
+ const dimUm = plane ? planeDimensionValueUm(plane, placed.planeEdge) : null;
133
+ if (dimUm != null) {
134
+ const c = convert(ctx, dimUm, ctx.units);
135
+ return { kind: 'planeDimension', value: c.value, unit: c.unit };
136
+ }
137
+ return { kind: 'empty' };
138
+ }
139
+ if (columnType === ColumnType.Instructions) {
140
+ const data = (column?.columnData ?? {});
141
+ return {
142
+ kind: 'instructions',
143
+ text: data.text ?? '',
144
+ textColor: data.textColor,
145
+ backgroundColor: data.backgroundColor,
146
+ };
147
+ }
148
+ // FORM formula column: the computed output, or the empty tile.
149
+ if (columnType === ColumnType.Formula) {
150
+ const formula = ctx.formulas?.find((f) => f.id ===
151
+ column?.columnData?.formulaId);
152
+ let result = null;
153
+ if (group && section && formula) {
154
+ try {
155
+ result = calculateFormula(formula, ctx.formulas ?? [], group.columns, section.tableConfig, Array.from(ctx.measurementsById.values()), ctx.units, ctx.fractionalTolerance ?? FractionalTolerance.Sixteenth, ctx.decimalTolerance ?? DecimalTolerance.Tenth);
156
+ }
157
+ catch {
158
+ result = null;
159
+ }
160
+ }
161
+ if (result !== null && result !== '' && Number.isFinite(Number(result))) {
162
+ const converted = convert(ctx, Math.abs(Number(result)), ctx.units);
163
+ return {
164
+ kind: 'measurement',
165
+ value: converted.value,
166
+ unit: converted.unit,
167
+ positionLabel: formGroupInputLabel(columnIndex, group?.groupIndex ?? 0),
168
+ label: placed.labelOverride ?? column?.name,
169
+ fill: FORMULA_COLUMN_TILE_FILL,
170
+ negative: Number(result) < 0,
171
+ };
172
+ }
173
+ return { kind: 'empty', ...columnTileLabels(ctx, placed) };
174
+ }
175
+ // Every other non-measurement FORM column stores a literal string.
176
+ // (Formula and Instructions columns returned above.)
177
+ const isNonMeasurementColumn = columnType != null &&
178
+ columnType !== ColumnType.Measurement &&
179
+ columnType !== ColumnType.Angle;
180
+ if (isNonMeasurementColumn) {
181
+ const raw = placed.columnId ? group?.columns?.[placed.columnId] : undefined;
182
+ return {
183
+ kind: 'literal',
184
+ value: raw != null && raw !== '' ? String(raw) : '',
185
+ ...columnTileLabels(ctx, placed),
186
+ };
187
+ }
188
+ // Bound measurement: by id, else through the FORM group's column slot.
189
+ let resolved;
190
+ if (placed.measurementId)
191
+ resolved = ctx.measurementsById.get(placed.measurementId);
192
+ if (!resolved && placed.columnId && group) {
193
+ const mid = group.columns?.[placed.columnId];
194
+ if (mid)
195
+ resolved = ctx.measurementsById.get(mid);
196
+ }
197
+ if (resolved)
198
+ return measurementContent(ctx, placed, resolved, column, columnIndex);
199
+ // Plane-computed length on a calibrated canvas.
200
+ if (placed.valueSource === 'plane') {
201
+ const um = planeLengthForPlaced(ctx.canvas.planes, placed);
202
+ if (um != null) {
203
+ const c = convert(ctx, Math.abs(um), placed.unitOverride ?? ctx.units);
204
+ return {
205
+ kind: 'measurement',
206
+ value: c.value,
207
+ unit: c.unit,
208
+ positionLabel: '',
209
+ label: placed.labelOverride,
210
+ fill: PLANE_COMPUTED_TILE_FILL,
211
+ negative: um < 0,
212
+ };
213
+ }
214
+ }
215
+ return placed.columnId
216
+ ? { kind: 'empty', ...columnTileLabels(ctx, placed) }
217
+ : { kind: 'empty' };
218
+ };
@@ -0,0 +1,43 @@
1
+ import { type PDFName, type PDFOperator, type PDFPage } from 'pdf-lib';
2
+ import type { AnnotationCanvasState, PlacedMeasurementRef } from '../../types/annotation.js';
3
+ import type { PdfFonts } from './fonts.js';
4
+ import type { AffineMatrix, DocRect } from './pageMapping.js';
5
+ import type { PdfExportCalibration, ResolvedTileContent } from './types.js';
6
+ /** An image XObject already registered on the page, with its pixel size. */
7
+ export interface PageImage {
8
+ name: PDFName;
9
+ width: number;
10
+ height: number;
11
+ }
12
+ export interface TilePaintContext {
13
+ page: PDFPage;
14
+ fonts: PdfFonts;
15
+ /** Object-tile thumbnail, when the content carries one and it embedded. */
16
+ thumbnail?: PageImage;
17
+ }
18
+ export interface TileFootprint extends DocRect {
19
+ /** Design-space box the painter lays out in. */
20
+ design: {
21
+ width: number;
22
+ height: number;
23
+ };
24
+ }
25
+ /**
26
+ * Doc-space footprint of a placed tile. `fallbackDocEdge` is the doc-space
27
+ * edge a scale-1 measurement tile covers when neither the request nor the
28
+ * document carries a calibration.
29
+ */
30
+ export declare const tileFootprint: (ref: PlacedMeasurementRef, canvas: Pick<AnnotationCanvasState, "tileDocSize">, calibration: PdfExportCalibration | undefined, fallbackDocEdge: number, design: {
31
+ width: number;
32
+ height: number;
33
+ }) => TileFootprint;
34
+ export declare const designBoxFor: (ref: PlacedMeasurementRef, content: ResolvedTileContent) => {
35
+ width: number;
36
+ height: number;
37
+ };
38
+ /** Doc ← design matrix for a footprint. */
39
+ export declare const designToDocMatrix: (f: TileFootprint) => AffineMatrix;
40
+ /** Operators for a tile in DESIGN space. */
41
+ export declare const tileDesignOps: (ctx: TilePaintContext, content: ResolvedTileContent) => PDFOperator[];
42
+ /** Operators for a tile in DOC space: design ops under the footprint matrix. */
43
+ export declare const tileOps: (ctx: TilePaintContext, content: ResolvedTileContent, footprint: TileFootprint) => PDFOperator[];