@reekon-tools/boldr-utils 1.6.4 → 1.6.6

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 (67) hide show
  1. package/dist/canvas/AnnotationCanvas.d.ts +11 -0
  2. package/dist/canvas/AnnotationCanvas.js +10 -0
  3. package/dist/canvas/AnnotationCanvas.native.d.ts +8 -0
  4. package/dist/canvas/AnnotationCanvas.native.js +6 -0
  5. package/dist/canvas/AnnotationCanvasInner.d.ts +37 -0
  6. package/dist/canvas/AnnotationCanvasInner.js +179 -0
  7. package/dist/canvas/AnnotationCanvasInner.native.d.ts +33 -0
  8. package/dist/canvas/AnnotationCanvasInner.native.js +102 -0
  9. package/dist/canvas/AnnotationCanvasSkia.d.ts +26 -0
  10. package/dist/canvas/AnnotationCanvasSkia.js +19 -0
  11. package/dist/canvas/Tool.d.ts +38 -0
  12. package/dist/canvas/Tool.js +1 -0
  13. package/dist/canvas/elements/BackgroundImageElement.d.ts +9 -0
  14. package/dist/canvas/elements/BackgroundImageElement.js +37 -0
  15. package/dist/canvas/elements/MeasurementStampElement.d.ts +13 -0
  16. package/dist/canvas/elements/MeasurementStampElement.js +30 -0
  17. package/dist/canvas/elements/ShapeElement.d.ts +7 -0
  18. package/dist/canvas/elements/ShapeElement.js +62 -0
  19. package/dist/canvas/elements/StrokeElement.d.ts +7 -0
  20. package/dist/canvas/elements/StrokeElement.js +18 -0
  21. package/dist/canvas/measurementPicker.d.ts +10 -0
  22. package/dist/canvas/measurementPicker.js +1 -0
  23. package/dist/canvas/pointerAdapter.d.ts +3 -0
  24. package/dist/canvas/pointerAdapter.js +19 -0
  25. package/dist/canvas/stampLayout.d.ts +4 -0
  26. package/dist/canvas/stampLayout.js +8 -0
  27. package/dist/canvas/tools/measurementStampTool.d.ts +9 -0
  28. package/dist/canvas/tools/measurementStampTool.js +37 -0
  29. package/dist/canvas/tools/panTool.d.ts +5 -0
  30. package/dist/canvas/tools/panTool.js +25 -0
  31. package/dist/canvas/tools/penTool.d.ts +13 -0
  32. package/dist/canvas/tools/penTool.js +68 -0
  33. package/dist/canvas/tools/selectTool.d.ts +2 -0
  34. package/dist/canvas/tools/selectTool.js +182 -0
  35. package/dist/canvas/useAnnotationCanvasState.d.ts +53 -0
  36. package/dist/canvas/useAnnotationCanvasState.js +182 -0
  37. package/dist/canvas/viewport.d.ts +16 -0
  38. package/dist/canvas/viewport.js +54 -0
  39. package/dist/data/AnnotationDataContext.d.ts +8 -0
  40. package/dist/data/AnnotationDataContext.js +11 -0
  41. package/dist/data/AnnotationDataProvider.d.ts +65 -0
  42. package/dist/data/AnnotationDataProvider.js +4 -0
  43. package/dist/data/InMemoryAnnotationProvider.d.ts +30 -0
  44. package/dist/data/InMemoryAnnotationProvider.js +197 -0
  45. package/dist/data/hooks/useAnnotationDoc.d.ts +7 -0
  46. package/dist/data/hooks/useAnnotationDoc.js +33 -0
  47. package/dist/data/hooks/useAnnotationList.d.ts +7 -0
  48. package/dist/data/hooks/useAnnotationList.js +26 -0
  49. package/dist/data/hooks/useAnnotationMutations.d.ts +9 -0
  50. package/dist/data/hooks/useAnnotationMutations.js +11 -0
  51. package/dist/exports.d.ts +25 -0
  52. package/dist/exports.js +26 -0
  53. package/dist/index.d.ts +2 -8
  54. package/dist/index.js +6 -8
  55. package/dist/index.native.d.ts +5 -0
  56. package/dist/index.native.js +6 -0
  57. package/dist/types/annotation.d.ts +139 -0
  58. package/dist/types/annotation.js +147 -0
  59. package/dist/types/firestore.d.ts +4 -15
  60. package/dist/types/firestore.js +0 -2
  61. package/dist/utils/groups.d.ts +4 -0
  62. package/dist/utils/groups.js +3 -0
  63. package/dist/utils/micrometersToUnit.d.ts +0 -1
  64. package/dist/utils/micrometersToUnit.js +1 -24
  65. package/dist/utils/tolerance.d.ts +0 -15
  66. package/dist/utils/tolerance.js +0 -41
  67. package/package.json +33 -2
@@ -0,0 +1,139 @@
1
+ import type { Units } from './firestore.js';
2
+ export type AnnotationElementId = string;
3
+ export type AnnotationLayerId = string;
4
+ export interface Vec2 {
5
+ x: number;
6
+ y: number;
7
+ }
8
+ export interface AnnotationStroke {
9
+ id: AnnotationElementId;
10
+ layerId: AnnotationLayerId;
11
+ tool: 'pen' | 'marker' | 'highlighter';
12
+ color: string;
13
+ width: number;
14
+ points: number[];
15
+ pressure?: number[];
16
+ createdAt: number;
17
+ }
18
+ export type AnnotationShapeKind = 'rect' | 'ellipse' | 'line' | 'arrow' | 'polygon' | 'text';
19
+ export interface AnnotationShapeStyle {
20
+ stroke?: string;
21
+ fill?: string;
22
+ strokeWidth?: number;
23
+ fontSize?: number;
24
+ fontFamily?: string;
25
+ }
26
+ export interface AnnotationShape {
27
+ id: AnnotationElementId;
28
+ layerId: AnnotationLayerId;
29
+ kind: AnnotationShapeKind;
30
+ geometry: {
31
+ points: Vec2[];
32
+ rotation?: number;
33
+ };
34
+ style: AnnotationShapeStyle;
35
+ text?: string;
36
+ createdAt: number;
37
+ }
38
+ export interface PlacedMeasurementRef {
39
+ id: AnnotationElementId;
40
+ layerId: AnnotationLayerId;
41
+ measurementPath: string;
42
+ measurementId: string;
43
+ groupId: string;
44
+ anchor: Vec2;
45
+ leader?: {
46
+ from: Vec2;
47
+ to: Vec2;
48
+ };
49
+ labelOverride?: string;
50
+ showValue?: boolean;
51
+ showLabel?: boolean;
52
+ scale?: number;
53
+ unitOverride?: Units;
54
+ createdAt: number;
55
+ }
56
+ export interface AnnotationLayer {
57
+ id: AnnotationLayerId;
58
+ name: string;
59
+ index: number;
60
+ visible: boolean;
61
+ locked: boolean;
62
+ }
63
+ export type BackgroundFit = 'contain' | 'cover' | 'stretch';
64
+ export interface AnnotationBackgroundImage {
65
+ storagePath: string;
66
+ downloadUrl: string;
67
+ widthPx: number;
68
+ heightPx: number;
69
+ }
70
+ export interface AnnotationViewport {
71
+ width: number;
72
+ height: number;
73
+ backgroundImage?: AnnotationBackgroundImage;
74
+ backgroundFit?: BackgroundFit;
75
+ }
76
+ export interface AnnotationCanvasState {
77
+ schemaVersion: 1;
78
+ layers: AnnotationLayer[];
79
+ viewport: AnnotationViewport;
80
+ strokes: AnnotationStroke[];
81
+ shapes: AnnotationShape[];
82
+ placedMeasurements: PlacedMeasurementRef[];
83
+ externalPayloadPath?: string;
84
+ }
85
+ export type AnnotationElement = (AnnotationStroke & {
86
+ kind: 'stroke';
87
+ }) | (AnnotationShape & {
88
+ kind: 'shape';
89
+ }) | (PlacedMeasurementRef & {
90
+ kind: 'measurement';
91
+ });
92
+ export interface Selection {
93
+ ids: AnnotationElementId[];
94
+ }
95
+ export type AnnotationPatchOp = {
96
+ op: 'addStroke';
97
+ stroke: AnnotationStroke;
98
+ } | {
99
+ op: 'updateStroke';
100
+ id: AnnotationElementId;
101
+ patch: Partial<AnnotationStroke>;
102
+ } | {
103
+ op: 'removeStroke';
104
+ id: AnnotationElementId;
105
+ } | {
106
+ op: 'addShape';
107
+ shape: AnnotationShape;
108
+ } | {
109
+ op: 'updateShape';
110
+ id: AnnotationElementId;
111
+ patch: Partial<AnnotationShape>;
112
+ } | {
113
+ op: 'removeShape';
114
+ id: AnnotationElementId;
115
+ } | {
116
+ op: 'addMeasurement';
117
+ measurement: PlacedMeasurementRef;
118
+ } | {
119
+ op: 'updateMeasurement';
120
+ id: AnnotationElementId;
121
+ patch: Partial<PlacedMeasurementRef>;
122
+ } | {
123
+ op: 'removeMeasurement';
124
+ id: AnnotationElementId;
125
+ } | {
126
+ op: 'setViewport';
127
+ patch: Partial<AnnotationViewport>;
128
+ } | {
129
+ op: 'setLayers';
130
+ layers: AnnotationLayer[];
131
+ };
132
+ export interface AnnotationDocumentPatch {
133
+ ops: AnnotationPatchOp[];
134
+ }
135
+ export declare const DEFAULT_LAYER_ID = "default";
136
+ export declare const createDefaultLayer: () => AnnotationLayer;
137
+ export declare const createEmptyCanvasState: (viewport?: Partial<AnnotationViewport>) => AnnotationCanvasState;
138
+ export declare const applyPatch: (state: AnnotationCanvasState, patch: AnnotationDocumentPatch) => AnnotationCanvasState;
139
+ export declare const invertPatch: (before: AnnotationCanvasState, patch: AnnotationDocumentPatch) => AnnotationDocumentPatch;
@@ -0,0 +1,147 @@
1
+ export const DEFAULT_LAYER_ID = 'default';
2
+ export const createDefaultLayer = () => ({
3
+ id: DEFAULT_LAYER_ID,
4
+ name: 'Layer 1',
5
+ index: 0,
6
+ visible: true,
7
+ locked: false,
8
+ });
9
+ export const createEmptyCanvasState = (viewport) => ({
10
+ schemaVersion: 1,
11
+ layers: [createDefaultLayer()],
12
+ viewport: {
13
+ width: viewport?.width ?? 1000,
14
+ height: viewport?.height ?? 1000,
15
+ backgroundImage: viewport?.backgroundImage,
16
+ backgroundFit: viewport?.backgroundFit,
17
+ },
18
+ strokes: [],
19
+ shapes: [],
20
+ placedMeasurements: [],
21
+ });
22
+ // Apply an in-memory patch to a canvas state. Pure — returns a new object.
23
+ // Used by the canvas reducer and by InMemoryAnnotationProvider; consumers
24
+ // can also call this when they receive a patch from the canvas to compute
25
+ // the next document to persist.
26
+ export const applyPatch = (state, patch) => {
27
+ let next = state;
28
+ for (const op of patch.ops) {
29
+ next = applyOp(next, op);
30
+ }
31
+ return next;
32
+ };
33
+ const applyOp = (state, op) => {
34
+ switch (op.op) {
35
+ case 'addStroke':
36
+ return { ...state, strokes: [...state.strokes, op.stroke] };
37
+ case 'updateStroke':
38
+ return {
39
+ ...state,
40
+ strokes: state.strokes.map((s) => s.id === op.id ? { ...s, ...op.patch } : s),
41
+ };
42
+ case 'removeStroke':
43
+ return { ...state, strokes: state.strokes.filter((s) => s.id !== op.id) };
44
+ case 'addShape':
45
+ return { ...state, shapes: [...state.shapes, op.shape] };
46
+ case 'updateShape':
47
+ return {
48
+ ...state,
49
+ shapes: state.shapes.map((s) => s.id === op.id ? { ...s, ...op.patch } : s),
50
+ };
51
+ case 'removeShape':
52
+ return { ...state, shapes: state.shapes.filter((s) => s.id !== op.id) };
53
+ case 'addMeasurement':
54
+ return {
55
+ ...state,
56
+ placedMeasurements: [...state.placedMeasurements, op.measurement],
57
+ };
58
+ case 'updateMeasurement':
59
+ return {
60
+ ...state,
61
+ placedMeasurements: state.placedMeasurements.map((m) => m.id === op.id ? { ...m, ...op.patch } : m),
62
+ };
63
+ case 'removeMeasurement':
64
+ return {
65
+ ...state,
66
+ placedMeasurements: state.placedMeasurements.filter((m) => m.id !== op.id),
67
+ };
68
+ case 'setViewport':
69
+ return { ...state, viewport: { ...state.viewport, ...op.patch } };
70
+ case 'setLayers':
71
+ return { ...state, layers: op.layers };
72
+ }
73
+ };
74
+ // Inverse of a patch, for undo stacks. Needs the pre-patch state to find
75
+ // the previous values for update/remove ops. Returns null if the patch
76
+ // cannot be inverted (e.g. an addX with no matching element to remove).
77
+ export const invertPatch = (before, patch) => {
78
+ const ops = [];
79
+ for (let i = patch.ops.length - 1; i >= 0; i--) {
80
+ const op = patch.ops[i];
81
+ const inverse = invertOp(before, op);
82
+ if (inverse)
83
+ ops.push(inverse);
84
+ }
85
+ return { ops };
86
+ };
87
+ const invertOp = (before, op) => {
88
+ switch (op.op) {
89
+ case 'addStroke':
90
+ return { op: 'removeStroke', id: op.stroke.id };
91
+ case 'removeStroke': {
92
+ const prev = before.strokes.find((s) => s.id === op.id);
93
+ return prev ? { op: 'addStroke', stroke: prev } : null;
94
+ }
95
+ case 'updateStroke': {
96
+ const prev = before.strokes.find((s) => s.id === op.id);
97
+ if (!prev)
98
+ return null;
99
+ const inversePatch = {};
100
+ for (const k of Object.keys(op.patch)) {
101
+ inversePatch[k] = prev[k];
102
+ }
103
+ return { op: 'updateStroke', id: op.id, patch: inversePatch };
104
+ }
105
+ case 'addShape':
106
+ return { op: 'removeShape', id: op.shape.id };
107
+ case 'removeShape': {
108
+ const prev = before.shapes.find((s) => s.id === op.id);
109
+ return prev ? { op: 'addShape', shape: prev } : null;
110
+ }
111
+ case 'updateShape': {
112
+ const prev = before.shapes.find((s) => s.id === op.id);
113
+ if (!prev)
114
+ return null;
115
+ const inversePatch = {};
116
+ for (const k of Object.keys(op.patch)) {
117
+ inversePatch[k] = prev[k];
118
+ }
119
+ return { op: 'updateShape', id: op.id, patch: inversePatch };
120
+ }
121
+ case 'addMeasurement':
122
+ return { op: 'removeMeasurement', id: op.measurement.id };
123
+ case 'removeMeasurement': {
124
+ const prev = before.placedMeasurements.find((m) => m.id === op.id);
125
+ return prev ? { op: 'addMeasurement', measurement: prev } : null;
126
+ }
127
+ case 'updateMeasurement': {
128
+ const prev = before.placedMeasurements.find((m) => m.id === op.id);
129
+ if (!prev)
130
+ return null;
131
+ const inversePatch = {};
132
+ for (const k of Object.keys(op.patch)) {
133
+ inversePatch[k] = prev[k];
134
+ }
135
+ return { op: 'updateMeasurement', id: op.id, patch: inversePatch };
136
+ }
137
+ case 'setViewport': {
138
+ const inversePatch = {};
139
+ for (const k of Object.keys(op.patch)) {
140
+ inversePatch[k] = before.viewport[k];
141
+ }
142
+ return { op: 'setViewport', patch: inversePatch };
143
+ }
144
+ case 'setLayers':
145
+ return { op: 'setLayers', layers: before.layers };
146
+ }
147
+ };
@@ -1,3 +1,4 @@
1
+ import type { AnnotationCanvasState } from './annotation.js';
1
2
  interface FirestoreDoc {
2
3
  id: string;
3
4
  }
@@ -104,12 +105,12 @@ export declare enum FileUploadType {
104
105
  LayoutGroup = "layoutGroup",
105
106
  Calculator = "calculator",
106
107
  Conversion = "conversion",
107
- Note = "note",
108
- Label = "label"
108
+ Note = "note"
109
109
  }
110
110
  export interface AnnotationFileData {
111
111
  fileType: 'sketch' | 'document';
112
112
  isLabel?: boolean;
113
+ canvas?: AnnotationCanvasState;
113
114
  }
114
115
  export interface CalculatorFileData {
115
116
  templateId: string;
@@ -174,9 +175,6 @@ export type FileUpload = FileUploadBase & ({
174
175
  } | {
175
176
  type: FileUploadType.Template;
176
177
  fileData?: undefined;
177
- } | {
178
- type: FileUploadType.Label;
179
- fileData: Label;
180
178
  });
181
179
  export interface Folder extends FirestoreDoc, Timestamps {
182
180
  name: string;
@@ -249,8 +247,7 @@ export declare enum ColumnType {
249
247
  SingleSelect = "singleSelect",
250
248
  MultiSelect = "multiSelect",
251
249
  Angle = "angle",
252
- ConversionTable = "conversionTable",
253
- Instructions = "instructions"
250
+ ConversionTable = "conversionTable"
254
251
  }
255
252
  export interface Formula extends FirestoreDoc, Timestamps {
256
253
  expression: string;
@@ -272,11 +269,6 @@ export interface SelectColumnData {
272
269
  export interface ConversionTableColumnData {
273
270
  conversions: Conversion[];
274
271
  }
275
- export interface InstructionsColumnData {
276
- text: string;
277
- textColor: string;
278
- backgroundColor: string;
279
- }
280
272
  interface ColumnConfigBase {
281
273
  id: string;
282
274
  name: string;
@@ -308,9 +300,6 @@ export type ColumnConfig = ColumnConfigBase & ({
308
300
  } | {
309
301
  type: ColumnType.Angle;
310
302
  columnData?: undefined;
311
- } | {
312
- type: ColumnType.Instructions;
313
- columnData: InstructionsColumnData;
314
303
  });
315
304
  export interface Row {
316
305
  [key: string]: any;
@@ -24,7 +24,6 @@ export var FileUploadType;
24
24
  FileUploadType["Calculator"] = "calculator";
25
25
  FileUploadType["Conversion"] = "conversion";
26
26
  FileUploadType["Note"] = "note";
27
- FileUploadType["Label"] = "label";
28
27
  })(FileUploadType || (FileUploadType = {}));
29
28
  export var GroupType;
30
29
  (function (GroupType) {
@@ -42,7 +41,6 @@ export var ColumnType;
42
41
  ColumnType["MultiSelect"] = "multiSelect";
43
42
  ColumnType["Angle"] = "angle";
44
43
  ColumnType["ConversionTable"] = "conversionTable";
45
- ColumnType["Instructions"] = "instructions";
46
44
  })(ColumnType || (ColumnType = {}));
47
45
  export var MeasurementType;
48
46
  (function (MeasurementType) {
@@ -0,0 +1,4 @@
1
+ import type { Group } from '../types/firestore.js';
2
+ export declare const DEFAULT_GROUP_INDEX = 0;
3
+ export declare const isDefaultGroup: (group: Pick<Group, "groupIndex"> | null | undefined) => boolean;
4
+ export declare const findDefaultGroup: <T extends Pick<Group, "groupIndex">>(groups: T[] | null | undefined) => T | null;
@@ -0,0 +1,3 @@
1
+ export const DEFAULT_GROUP_INDEX = 0;
2
+ export const isDefaultGroup = (group) => group?.groupIndex === DEFAULT_GROUP_INDEX;
3
+ export const findDefaultGroup = (groups) => groups?.find((g) => g.groupIndex === DEFAULT_GROUP_INDEX) ?? null;
@@ -1,5 +1,4 @@
1
1
  import { DecimalTolerance, FractionalTolerance, Units } from '../types/firestore.js';
2
- export declare const roundToT1Values: (value: number, u: Units) => number;
3
2
  export declare const convertMicrometers: (micrometers: number | null | undefined, unit: Units, fractionalTolerance: FractionalTolerance, decimalTolerance: DecimalTolerance) => {
4
3
  value: string;
5
4
  unit: string;
@@ -1,35 +1,12 @@
1
1
  import { Units, convertUnitsToReadable, } from '../types/firestore.js';
2
2
  import { create, all } from 'mathjs';
3
3
  const math = create(all);
4
- // The T1 rounds differently depending on the selected measurement unit.
5
- // This function mirrors the rounding behavior implemented on the firmware.
6
- // The value being rounded is in microns.
7
- export const roundToT1Values = (value, u) => {
8
- switch (u) {
9
- case Units.Millimeters:
10
- case Units.Centimeters:
11
- return Math.round(value / 500) * 500;
12
- case Units.Meters:
13
- return Math.round(value / 1000) * 1000;
14
- case Units.Inches:
15
- return Math.round(value / 508) * 508;
16
- case Units.Feet:
17
- return Math.round(value / 304.8) * 304.8;
18
- case Units.FeetInchesDecimal:
19
- return Math.round(value / 508) * 508;
20
- case Units.FractionalInches:
21
- case Units.FeetInchesFractional:
22
- return value;
23
- default:
24
- return Math.round(value / 500) * 500;
25
- }
26
- };
27
4
  export const convertMicrometers = (micrometers, unit, fractionalTolerance, decimalTolerance) => {
28
5
  if (micrometers == null || isNaN(micrometers)) {
29
6
  return { value: 'NaN', unit: '' };
30
7
  }
31
8
  try {
32
- const converted = math.unit(roundToT1Values(micrometers, unit), 'um');
9
+ const converted = math.unit(micrometers, 'um');
33
10
  let value = 0;
34
11
  let displayUnit = '';
35
12
  switch (unit) {
@@ -16,10 +16,6 @@ export declare const DEFAULT_TOLERANCE_COLORS: {
16
16
  readonly IN_TOLERANCE: "#22c55e";
17
17
  readonly OUT_OF_TOLERANCE: "#ef4444";
18
18
  };
19
- export declare const DEFAULT_TOLERANCE_SECONDARY_COLORS: {
20
- readonly IN_TOLERANCE: "#268F0A";
21
- readonly OUT_OF_TOLERANCE: "#A91507";
22
- };
23
19
  /**
24
20
  * Calculates the appropriate color for a measurement based on tolerance thresholds
25
21
  *
@@ -31,17 +27,6 @@ export declare const DEFAULT_TOLERANCE_SECONDARY_COLORS: {
31
27
  * @returns The color hex string to use for the measurement
32
28
  */
33
29
  export declare function getToleranceColor(actualValue: number, target: number, min: number, max: number, toleranceConfig?: ToleranceConfig | null): string;
34
- /**
35
- * Calculates the appropriate color for a measurement based on tolerance thresholds
36
- *
37
- * @param actualValue - The measured value
38
- * @param target - The target/nominal value
39
- * @param min - The minimum acceptable value (used as negative tolerance from target)
40
- * @param max - The maximum acceptable value (used as positive tolerance from target)
41
- * @param toleranceConfig - Optional tolerance configuration with custom thresholds
42
- * @returns The color hex string to use for the measurement
43
- */
44
- export declare function getToleranceSecondaryColor(actualValue: number, target: number, min: number, max: number, toleranceConfig?: ToleranceConfig | null): string;
45
30
  /**
46
31
  * Calculates the deviation percentage of a measurement from its target
47
32
  *
@@ -5,10 +5,6 @@ export const DEFAULT_TOLERANCE_COLORS = {
5
5
  IN_TOLERANCE: '#22c55e', // Green
6
6
  OUT_OF_TOLERANCE: '#ef4444', // Red
7
7
  };
8
- export const DEFAULT_TOLERANCE_SECONDARY_COLORS = {
9
- IN_TOLERANCE: '#268F0A', // Green
10
- OUT_OF_TOLERANCE: '#A91507', // Red
11
- };
12
8
  /**
13
9
  * Calculates the appropriate color for a measurement based on tolerance thresholds
14
10
  *
@@ -46,43 +42,6 @@ export function getToleranceColor(actualValue, target, min, max, toleranceConfig
46
42
  }
47
43
  return applicableColor;
48
44
  }
49
- /**
50
- * Calculates the appropriate color for a measurement based on tolerance thresholds
51
- *
52
- * @param actualValue - The measured value
53
- * @param target - The target/nominal value
54
- * @param min - The minimum acceptable value (used as negative tolerance from target)
55
- * @param max - The maximum acceptable value (used as positive tolerance from target)
56
- * @param toleranceConfig - Optional tolerance configuration with custom thresholds
57
- * @returns The color hex string to use for the measurement
58
- */
59
- export function getToleranceSecondaryColor(actualValue, target, min, max, toleranceConfig) {
60
- // If no tolerance config provided, use simple green/red logic
61
- if (!toleranceConfig?.thresholds || toleranceConfig.thresholds.length === 0) {
62
- const isWithinTolerance = actualValue >= target - min && actualValue <= target + max;
63
- return isWithinTolerance
64
- ? DEFAULT_TOLERANCE_SECONDARY_COLORS.IN_TOLERANCE
65
- : DEFAULT_TOLERANCE_SECONDARY_COLORS.OUT_OF_TOLERANCE;
66
- }
67
- // Calculate deviation percentage
68
- const deviation = Math.abs(actualValue - target);
69
- const toleranceRange = max + min; // Fixed: total tolerance range
70
- const deviationPercentage = toleranceRange > 0 ? (deviation / toleranceRange) * 100 : 0;
71
- // Sort thresholds by percentage to ensure correct evaluation order
72
- const sortedThresholds = toleranceConfig.thresholds.sort((a, b) => a.percentage - b.percentage);
73
- // If deviation is below the first threshold, it's in tolerance (green)
74
- if (deviationPercentage < sortedThresholds[0].percentage) {
75
- return DEFAULT_TOLERANCE_SECONDARY_COLORS.IN_TOLERANCE;
76
- }
77
- // Find the highest threshold that the deviation exceeds
78
- let applicableColor = sortedThresholds[0].color;
79
- for (const threshold of sortedThresholds) {
80
- if (deviationPercentage >= threshold.percentage) {
81
- applicableColor = threshold.color;
82
- }
83
- }
84
- return applicableColor;
85
- }
86
45
  /**
87
46
  * Calculates the deviation percentage of a measurement from its target
88
47
  *
package/package.json CHANGED
@@ -1,15 +1,26 @@
1
1
  {
2
2
  "name": "@reekon-tools/boldr-utils",
3
- "version": "1.6.4",
3
+ "version": "1.6.6",
4
4
  "description": "Shared utilities for formulas and measurement conversion used in Reekon apps",
5
5
  "author": "REEKON Tools",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
+ "sideEffects": false,
8
9
  "files": [
9
10
  "dist"
10
11
  ],
11
12
  "main": "dist/index.js",
12
13
  "types": "dist/index.d.ts",
14
+ "react-native": "dist/index.native.js",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "react-native": "./dist/index.native.js",
19
+ "import": "./dist/index.js",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
13
24
  "scripts": {
14
25
  "build": "tsc",
15
26
  "test": "vitest",
@@ -25,14 +36,34 @@
25
36
  "mathjs": "^11.11.0"
26
37
  },
27
38
  "peerDependencies": {
28
- "react": "^18.0.0"
39
+ "@shopify/react-native-skia": ">=2.5.0",
40
+ "react": "^18.0.0 || ^19.0.0",
41
+ "react-native": ">=0.74.0",
42
+ "react-native-gesture-handler": ">=2.0.0",
43
+ "react-native-reanimated": ">=3.0.0"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "react-native": {
47
+ "optional": true
48
+ },
49
+ "react-native-gesture-handler": {
50
+ "optional": true
51
+ },
52
+ "react-native-reanimated": {
53
+ "optional": true
54
+ }
29
55
  },
30
56
  "devDependencies": {
31
57
  "@arethetypeswrong/cli": "^0.18.1",
58
+ "@shopify/react-native-skia": "^2.6.2",
32
59
  "@types/node": "^22.15.18",
33
60
  "@types/react": "^19.0.8",
34
61
  "@vitest/coverage-v8": "3.1.3",
35
62
  "prettier": "^3.5.3",
63
+ "react": "^19.0.0",
64
+ "react-native": "0.83.2",
65
+ "react-native-gesture-handler": "~2.30.0",
66
+ "react-native-reanimated": "4.2.1",
36
67
  "ts-node": "^10.9.2",
37
68
  "typescript": "^5.8.3",
38
69
  "vitest": "^3.1.3"