@reekon-tools/boldr-cad 0.1.0 → 1.1.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 (555) hide show
  1. package/README.md +99 -16
  2. package/dist/app/edit.d.ts +12 -1
  3. package/dist/app/edit.js +96 -11
  4. package/dist/app/edit.js.map +1 -1
  5. package/dist/app/state.d.ts +31 -4
  6. package/dist/app/state.js +31 -2
  7. package/dist/app/state.js.map +1 -1
  8. package/dist/data/memory.d.ts +9 -1
  9. package/dist/data/memory.js +13 -8
  10. package/dist/data/memory.js.map +1 -1
  11. package/dist/data/provider.d.ts +30 -10
  12. package/dist/data/sync.d.ts +14 -3
  13. package/dist/data/sync.js +133 -66
  14. package/dist/data/sync.js.map +1 -1
  15. package/dist/editor/actions.d.ts +1 -2
  16. package/dist/editor/actions.js +391 -113
  17. package/dist/editor/actions.js.map +1 -1
  18. package/dist/editor/confirm.d.ts +23 -0
  19. package/dist/editor/confirm.js +35 -0
  20. package/dist/editor/confirm.js.map +1 -0
  21. package/dist/editor/elevation.d.ts +191 -90
  22. package/dist/editor/elevation.js +812 -616
  23. package/dist/editor/elevation.js.map +1 -1
  24. package/dist/editor/face.d.ts +73 -0
  25. package/dist/editor/face.js +269 -0
  26. package/dist/editor/face.js.map +1 -0
  27. package/dist/editor/files.d.ts +6 -0
  28. package/dist/editor/files.js +50 -4
  29. package/dist/editor/files.js.map +1 -1
  30. package/dist/editor/gestures.d.ts +18 -3
  31. package/dist/editor/gestures.js +145 -30
  32. package/dist/editor/gestures.js.map +1 -1
  33. package/dist/editor/keypad.d.ts +20 -5
  34. package/dist/editor/keypad.js +62 -15
  35. package/dist/editor/keypad.js.map +1 -1
  36. package/dist/editor/keys.js +36 -4
  37. package/dist/editor/keys.js.map +1 -1
  38. package/dist/editor/laser.d.ts +20 -4
  39. package/dist/editor/laser.js +104 -21
  40. package/dist/editor/laser.js.map +1 -1
  41. package/dist/editor/linkActions.d.ts +49 -0
  42. package/dist/editor/linkActions.js +210 -0
  43. package/dist/editor/linkActions.js.map +1 -0
  44. package/dist/editor/linkFollow.d.ts +2 -0
  45. package/dist/editor/linkFollow.js +53 -0
  46. package/dist/editor/linkFollow.js.map +1 -0
  47. package/dist/editor/linkWrite.d.ts +13 -0
  48. package/dist/editor/linkWrite.js +84 -0
  49. package/dist/editor/linkWrite.js.map +1 -0
  50. package/dist/editor/links.d.ts +84 -0
  51. package/dist/editor/links.js +130 -0
  52. package/dist/editor/links.js.map +1 -0
  53. package/dist/editor/markup.d.ts +29 -3
  54. package/dist/editor/markup.js +95 -10
  55. package/dist/editor/markup.js.map +1 -1
  56. package/dist/editor/mode.d.ts +40 -2
  57. package/dist/editor/mode.js +71 -4
  58. package/dist/editor/mode.js.map +1 -1
  59. package/dist/editor/ports.d.ts +38 -6
  60. package/dist/editor/ports.js +10 -1
  61. package/dist/editor/ports.js.map +1 -1
  62. package/dist/editor/project.d.ts +38 -6
  63. package/dist/editor/project.js +170 -27
  64. package/dist/editor/project.js.map +1 -1
  65. package/dist/editor/selection.d.ts +10 -0
  66. package/dist/editor/selection.js +62 -8
  67. package/dist/editor/selection.js.map +1 -1
  68. package/dist/editor/status.js +3 -0
  69. package/dist/editor/status.js.map +1 -1
  70. package/dist/editor/tooltips.d.ts +5 -0
  71. package/dist/editor/tooltips.js +48 -0
  72. package/dist/editor/tooltips.js.map +1 -0
  73. package/dist/editor/view3d.d.ts +17 -0
  74. package/dist/editor/view3d.js +135 -0
  75. package/dist/editor/view3d.js.map +1 -0
  76. package/dist/editor/view3dState.d.ts +39 -0
  77. package/dist/editor/view3dState.js +44 -0
  78. package/dist/editor/view3dState.js.map +1 -0
  79. package/dist/export/dxf.js +1 -1
  80. package/dist/export/dxf.js.map +1 -1
  81. package/dist/export/pdf.js +17 -12
  82. package/dist/export/pdf.js.map +1 -1
  83. package/dist/export/plan.d.ts +23 -6
  84. package/dist/export/plan.js +127 -44
  85. package/dist/export/plan.js.map +1 -1
  86. package/dist/index.d.ts +7 -1
  87. package/dist/index.js +2 -0
  88. package/dist/index.js.map +1 -1
  89. package/dist/model/constraints.js +15 -4
  90. package/dist/model/constraints.js.map +1 -1
  91. package/dist/model/demo.js +3 -3
  92. package/dist/model/demo.js.map +1 -1
  93. package/dist/model/elevation.d.ts +6 -9
  94. package/dist/model/elevation.js +5 -13
  95. package/dist/model/elevation.js.map +1 -1
  96. package/dist/model/faces.d.ts +58 -0
  97. package/dist/model/faces.js +197 -0
  98. package/dist/model/faces.js.map +1 -0
  99. package/dist/model/facesolve.d.ts +72 -0
  100. package/dist/model/facesolve.js +369 -0
  101. package/dist/model/facesolve.js.map +1 -0
  102. package/dist/model/history.d.ts +3 -2
  103. package/dist/model/history.js +17 -11
  104. package/dist/model/history.js.map +1 -1
  105. package/dist/model/images.d.ts +18 -0
  106. package/dist/model/images.js +26 -0
  107. package/dist/model/images.js.map +1 -0
  108. package/dist/model/links.d.ts +46 -0
  109. package/dist/model/links.js +73 -0
  110. package/dist/model/links.js.map +1 -0
  111. package/dist/model/markup.d.ts +46 -0
  112. package/dist/model/markup.js +71 -0
  113. package/dist/model/markup.js.map +1 -0
  114. package/dist/model/measurement.d.ts +11 -0
  115. package/dist/model/measurement.js +24 -0
  116. package/dist/model/measurement.js.map +1 -0
  117. package/dist/model/openings.d.ts +4 -0
  118. package/dist/model/openings.js +4 -0
  119. package/dist/model/openings.js.map +1 -1
  120. package/dist/model/planGeom.d.ts +72 -2
  121. package/dist/model/planGeom.js +184 -10
  122. package/dist/model/planGeom.js.map +1 -1
  123. package/dist/model/project.js +3 -2
  124. package/dist/model/project.js.map +1 -1
  125. package/dist/model/projectfile.js +2 -1
  126. package/dist/model/projectfile.js.map +1 -1
  127. package/dist/model/rooms.js +2 -2
  128. package/dist/model/rooms.js.map +1 -1
  129. package/dist/model/settings.d.ts +6 -0
  130. package/dist/model/settings.js +2 -2
  131. package/dist/model/settings.js.map +1 -1
  132. package/dist/model/sketch.d.ts +14 -0
  133. package/dist/model/sketch.js +143 -24
  134. package/dist/model/sketch.js.map +1 -1
  135. package/dist/model/smooth.d.ts +6 -0
  136. package/dist/model/smooth.js +52 -0
  137. package/dist/model/smooth.js.map +1 -0
  138. package/dist/model/store.d.ts +12 -0
  139. package/dist/model/store.js +35 -3
  140. package/dist/model/store.js.map +1 -1
  141. package/dist/model/types.d.ts +173 -8
  142. package/dist/model/wallfaces.d.ts +32 -0
  143. package/dist/model/wallfaces.js +133 -20
  144. package/dist/model/wallfaces.js.map +1 -1
  145. package/dist/model/wallshape.d.ts +15 -0
  146. package/dist/model/wallshape.js +89 -0
  147. package/dist/model/wallshape.js.map +1 -0
  148. package/dist/react/BottomBar.d.ts +9 -5
  149. package/dist/react/BottomBar.js +213 -24
  150. package/dist/react/BottomBar.js.map +1 -1
  151. package/dist/react/Buttons.d.ts +13 -2
  152. package/dist/react/Buttons.js +37 -5
  153. package/dist/react/Buttons.js.map +1 -1
  154. package/dist/react/CadEditor.d.ts +54 -4
  155. package/dist/react/CadEditor.js +79 -21
  156. package/dist/react/CadEditor.js.map +1 -1
  157. package/dist/react/ConfirmSheet.d.ts +4 -0
  158. package/dist/react/ConfirmSheet.js +31 -0
  159. package/dist/react/ConfirmSheet.js.map +1 -0
  160. package/dist/react/ConflictSheet.d.ts +2 -1
  161. package/dist/react/ConflictSheet.js +16 -8
  162. package/dist/react/ConflictSheet.js.map +1 -1
  163. package/dist/react/Drawer.d.ts +8 -2
  164. package/dist/react/Drawer.js +167 -38
  165. package/dist/react/Drawer.js.map +1 -1
  166. package/dist/react/Duck.d.ts +13 -0
  167. package/dist/react/Duck.js +45 -0
  168. package/dist/react/Duck.js.map +1 -0
  169. package/dist/react/Empty3D.d.ts +2 -0
  170. package/dist/react/Empty3D.js +39 -0
  171. package/dist/react/Empty3D.js.map +1 -0
  172. package/dist/react/FitScroll.d.ts +6 -0
  173. package/dist/react/FitScroll.js +14 -0
  174. package/dist/react/FitScroll.js.map +1 -0
  175. package/dist/react/Icon.native.d.ts +6 -0
  176. package/dist/react/Icon.native.js +4 -0
  177. package/dist/react/Icon.native.js.map +1 -1
  178. package/dist/react/Icon.web.d.ts +6 -0
  179. package/dist/react/Icon.web.js +4 -0
  180. package/dist/react/Icon.web.js.map +1 -1
  181. package/dist/react/KeypadSheet.d.ts +9 -2
  182. package/dist/react/KeypadSheet.js +174 -42
  183. package/dist/react/KeypadSheet.js.map +1 -1
  184. package/dist/react/LaserTray.js +8 -5
  185. package/dist/react/LaserTray.js.map +1 -1
  186. package/dist/react/MarkupPanel.d.ts +8 -0
  187. package/dist/react/MarkupPanel.js +67 -0
  188. package/dist/react/MarkupPanel.js.map +1 -0
  189. package/dist/react/PageThumb.native.d.ts +7 -2
  190. package/dist/react/PageThumb.native.js +19 -7
  191. package/dist/react/PageThumb.native.js.map +1 -1
  192. package/dist/react/PageThumb.web.d.ts +3 -2
  193. package/dist/react/PageThumb.web.js +4 -4
  194. package/dist/react/PageThumb.web.js.map +1 -1
  195. package/dist/react/PlanCanvas.native.d.ts +1 -1
  196. package/dist/react/PlanCanvas.native.js +134 -36
  197. package/dist/react/PlanCanvas.native.js.map +1 -1
  198. package/dist/react/PlanCanvas.web.js +16 -5
  199. package/dist/react/PlanCanvas.web.js.map +1 -1
  200. package/dist/react/Popovers.d.ts +12 -6
  201. package/dist/react/Popovers.js +53 -26
  202. package/dist/react/Popovers.js.map +1 -1
  203. package/dist/react/Rail.d.ts +24 -0
  204. package/dist/react/Rail.js +324 -34
  205. package/dist/react/Rail.js.map +1 -1
  206. package/dist/react/ShapeMenu.d.ts +7 -0
  207. package/dist/react/ShapeMenu.js +58 -0
  208. package/dist/react/ShapeMenu.js.map +1 -0
  209. package/dist/react/Sheet.d.ts +14 -4
  210. package/dist/react/Sheet.js +54 -9
  211. package/dist/react/Sheet.js.map +1 -1
  212. package/dist/react/Slider.d.ts +18 -0
  213. package/dist/react/Slider.js +27 -0
  214. package/dist/react/Slider.js.map +1 -0
  215. package/dist/react/Toast.js +14 -6
  216. package/dist/react/Toast.js.map +1 -1
  217. package/dist/react/ToolTip.d.ts +7 -0
  218. package/dist/react/ToolTip.js +43 -0
  219. package/dist/react/ToolTip.js.map +1 -0
  220. package/dist/react/TopBar.d.ts +6 -3
  221. package/dist/react/TopBar.js +48 -17
  222. package/dist/react/TopBar.js.map +1 -1
  223. package/dist/react/Tween.d.ts +7 -0
  224. package/dist/react/Tween.js +26 -0
  225. package/dist/react/Tween.js.map +1 -0
  226. package/dist/react/Tween.native.d.ts +6 -0
  227. package/dist/react/Tween.native.js +43 -0
  228. package/dist/react/Tween.native.js.map +1 -0
  229. package/dist/react/View3D.native.d.ts +4 -0
  230. package/dist/react/View3D.native.js +103 -0
  231. package/dist/react/View3D.native.js.map +1 -0
  232. package/dist/react/View3D.web.d.ts +4 -0
  233. package/dist/react/View3D.web.js +151 -0
  234. package/dist/react/View3D.web.js.map +1 -0
  235. package/dist/react/View3DHost.d.ts +143 -0
  236. package/dist/react/View3DHost.js +377 -0
  237. package/dist/react/View3DHost.js.map +1 -0
  238. package/dist/react/corners.d.ts +7 -0
  239. package/dist/react/corners.js +51 -0
  240. package/dist/react/corners.js.map +1 -0
  241. package/dist/react/easing.d.ts +15 -0
  242. package/dist/react/easing.js +10 -0
  243. package/dist/react/easing.js.map +1 -0
  244. package/dist/react/host.d.ts +7 -2
  245. package/dist/react/host.js +8 -3
  246. package/dist/react/host.js.map +1 -1
  247. package/dist/react/hostKeypad.d.ts +56 -0
  248. package/dist/react/hostKeypad.js +5 -0
  249. package/dist/react/hostKeypad.js.map +1 -0
  250. package/dist/react/motion.d.ts +77 -0
  251. package/dist/react/motion.js +173 -0
  252. package/dist/react/motion.js.map +1 -0
  253. package/dist/react/ports.js +90 -8
  254. package/dist/react/ports.js.map +1 -1
  255. package/dist/react/saving.d.ts +15 -0
  256. package/dist/react/saving.js +76 -0
  257. package/dist/react/saving.js.map +1 -0
  258. package/dist/react/store.d.ts +38 -1
  259. package/dist/react/store.js +31 -1
  260. package/dist/react/store.js.map +1 -1
  261. package/dist/react/theme.d.ts +10 -0
  262. package/dist/react/theme.js +8 -0
  263. package/dist/react/theme.js.map +1 -1
  264. package/dist/react/topRow.d.ts +22 -0
  265. package/dist/react/topRow.js +61 -0
  266. package/dist/react/topRow.js.map +1 -0
  267. package/dist/react/touch.d.ts +6 -0
  268. package/dist/react/touch.js +9 -0
  269. package/dist/react/touch.js.map +1 -0
  270. package/dist/render/ctx.d.ts +8 -0
  271. package/dist/render/draw.d.ts +33 -1
  272. package/dist/render/draw.js +593 -215
  273. package/dist/render/draw.js.map +1 -1
  274. package/dist/render/elevation.d.ts +65 -43
  275. package/dist/render/elevation.js +414 -140
  276. package/dist/render/elevation.js.map +1 -1
  277. package/dist/render/figmaIcons.d.ts +12 -0
  278. package/dist/render/figmaIcons.js +21 -0
  279. package/dist/render/figmaIcons.js.map +1 -0
  280. package/dist/render/hit.d.ts +22 -2
  281. package/dist/render/hit.js +168 -25
  282. package/dist/render/hit.js.map +1 -1
  283. package/dist/render/icons.js +69 -10
  284. package/dist/render/icons.js.map +1 -1
  285. package/dist/render/linkTile.d.ts +15 -0
  286. package/dist/render/linkTile.js +369 -0
  287. package/dist/render/linkTile.js.map +1 -0
  288. package/dist/render/markup.d.ts +11 -0
  289. package/dist/render/markup.js +112 -0
  290. package/dist/render/markup.js.map +1 -0
  291. package/dist/render/navigate.d.ts +88 -0
  292. package/dist/render/navigate.js +100 -0
  293. package/dist/render/navigate.js.map +1 -0
  294. package/dist/render/snap.d.ts +20 -1
  295. package/dist/render/snap.js +118 -25
  296. package/dist/render/snap.js.map +1 -1
  297. package/dist/render/squircle.d.ts +8 -0
  298. package/dist/render/squircle.js +71 -0
  299. package/dist/render/squircle.js.map +1 -0
  300. package/dist/render/view.d.ts +115 -2
  301. package/dist/render/view.js +244 -19
  302. package/dist/render/view.js.map +1 -1
  303. package/dist/skia/SkiaDrawCtx.d.ts +30 -2
  304. package/dist/skia/SkiaDrawCtx.js +198 -43
  305. package/dist/skia/SkiaDrawCtx.js.map +1 -1
  306. package/dist/skia/host.d.ts +18 -2
  307. package/dist/skia/host.js +46 -1
  308. package/dist/skia/host.js.map +1 -1
  309. package/dist/solver/equations.js +37 -2
  310. package/dist/solver/equations.js.map +1 -1
  311. package/dist/solver/gauss-newton.d.ts +17 -0
  312. package/dist/solver/gauss-newton.js +144 -36
  313. package/dist/solver/gauss-newton.js.map +1 -1
  314. package/dist/solver/linalg.d.ts +45 -2
  315. package/dist/solver/linalg.js +164 -10
  316. package/dist/solver/linalg.js.map +1 -1
  317. package/dist/solver/types.d.ts +5 -0
  318. package/dist/tools/annotate.d.ts +57 -1
  319. package/dist/tools/annotate.js +64 -43
  320. package/dist/tools/annotate.js.map +1 -1
  321. package/dist/tools/chamfer.d.ts +12 -0
  322. package/dist/tools/chamfer.js +114 -0
  323. package/dist/tools/chamfer.js.map +1 -0
  324. package/dist/tools/corner.d.ts +38 -0
  325. package/dist/tools/corner.js +99 -0
  326. package/dist/tools/corner.js.map +1 -0
  327. package/dist/tools/dim.d.ts +86 -9
  328. package/dist/tools/dim.js +582 -97
  329. package/dist/tools/dim.js.map +1 -1
  330. package/dist/tools/elevation.js +5 -5
  331. package/dist/tools/elevation.js.map +1 -1
  332. package/dist/tools/fillet.d.ts +9 -0
  333. package/dist/tools/fillet.js +86 -0
  334. package/dist/tools/fillet.js.map +1 -0
  335. package/dist/tools/freehand.d.ts +3 -2
  336. package/dist/tools/freehand.js +19 -12
  337. package/dist/tools/freehand.js.map +1 -1
  338. package/dist/tools/index.js +14 -4
  339. package/dist/tools/index.js.map +1 -1
  340. package/dist/tools/line.d.ts +8 -3
  341. package/dist/tools/line.js +66 -30
  342. package/dist/tools/line.js.map +1 -1
  343. package/dist/tools/modify.d.ts +13 -0
  344. package/dist/tools/modify.js +105 -25
  345. package/dist/tools/modify.js.map +1 -1
  346. package/dist/tools/openings.js +25 -18
  347. package/dist/tools/openings.js.map +1 -1
  348. package/dist/tools/registry.d.ts +8 -0
  349. package/dist/tools/registry.js +42 -2
  350. package/dist/tools/registry.js.map +1 -1
  351. package/dist/tools/select.d.ts +77 -3
  352. package/dist/tools/select.js +560 -74
  353. package/dist/tools/select.js.map +1 -1
  354. package/dist/tools/shapes.d.ts +14 -0
  355. package/dist/tools/shapes.js +154 -75
  356. package/dist/tools/shapes.js.map +1 -1
  357. package/dist/units/format.d.ts +11 -3
  358. package/dist/units/format.js +27 -6
  359. package/dist/units/format.js.map +1 -1
  360. package/dist/units/parse.d.ts +2 -1
  361. package/dist/units/parse.js +5 -4
  362. package/dist/units/parse.js.map +1 -1
  363. package/dist/units/prefs.d.ts +9 -1
  364. package/dist/units/prefs.js +6 -0
  365. package/dist/units/prefs.js.map +1 -1
  366. package/dist/view3d/build.d.ts +35 -0
  367. package/dist/view3d/build.js +630 -0
  368. package/dist/view3d/build.js.map +1 -0
  369. package/dist/view3d/camera.d.ts +60 -0
  370. package/dist/view3d/camera.js +84 -0
  371. package/dist/view3d/camera.js.map +1 -0
  372. package/dist/view3d/fatLines.d.ts +11 -0
  373. package/dist/view3d/fatLines.js +83 -0
  374. package/dist/view3d/fatLines.js.map +1 -0
  375. package/dist/view3d/lines.d.ts +17 -0
  376. package/dist/view3d/lines.js +271 -0
  377. package/dist/view3d/lines.js.map +1 -0
  378. package/dist/view3d/mesh.d.ts +51 -0
  379. package/dist/view3d/mesh.js +101 -0
  380. package/dist/view3d/mesh.js.map +1 -0
  381. package/dist/view3d/poly.d.ts +16 -0
  382. package/dist/view3d/poly.js +109 -0
  383. package/dist/view3d/poly.js.map +1 -0
  384. package/dist/view3d/viewer.d.ts +86 -0
  385. package/dist/view3d/viewer.js +350 -0
  386. package/dist/view3d/viewer.js.map +1 -0
  387. package/package.json +15 -2
  388. package/src/app/edit.ts +83 -12
  389. package/src/app/main.ts +11 -5
  390. package/src/app/state.ts +38 -5
  391. package/src/data/memory.ts +15 -10
  392. package/src/data/provider.ts +25 -10
  393. package/src/data/sync.ts +107 -53
  394. package/src/editor/actions.ts +292 -83
  395. package/src/editor/confirm.ts +58 -0
  396. package/src/editor/elevation.ts +698 -478
  397. package/src/editor/face.ts +227 -0
  398. package/src/editor/files.ts +40 -4
  399. package/src/editor/gestures.ts +147 -31
  400. package/src/editor/keypad.ts +67 -18
  401. package/src/editor/keys.ts +25 -5
  402. package/src/editor/laser.ts +98 -20
  403. package/src/editor/linkActions.ts +194 -0
  404. package/src/editor/linkFollow.ts +43 -0
  405. package/src/editor/linkWrite.ts +77 -0
  406. package/src/editor/links.ts +181 -0
  407. package/src/editor/markup.ts +92 -8
  408. package/src/editor/mode.ts +83 -7
  409. package/src/editor/ports.ts +39 -6
  410. package/src/editor/project.ts +157 -26
  411. package/src/editor/selection.ts +54 -8
  412. package/src/editor/status.ts +2 -0
  413. package/src/editor/tooltips.ts +47 -0
  414. package/src/editor/view3d.ts +119 -0
  415. package/src/editor/view3dState.ts +61 -0
  416. package/src/export/dxf.ts +1 -1
  417. package/src/export/pdf.ts +15 -7
  418. package/src/export/plan.ts +119 -35
  419. package/src/index.ts +7 -1
  420. package/src/input/keyboard.ts +2 -4
  421. package/src/model/constraints.ts +13 -4
  422. package/src/model/demo.ts +3 -3
  423. package/src/model/elevation.ts +6 -16
  424. package/src/model/faces.ts +153 -0
  425. package/src/model/facesolve.ts +322 -0
  426. package/src/model/history.ts +19 -11
  427. package/src/model/images.ts +35 -0
  428. package/src/model/links.ts +77 -0
  429. package/src/model/markup.ts +80 -0
  430. package/src/model/measurement.ts +26 -0
  431. package/src/model/openings.ts +6 -0
  432. package/src/model/planGeom.ts +174 -8
  433. package/src/model/project.ts +3 -2
  434. package/src/model/projectfile.ts +2 -1
  435. package/src/model/rooms.ts +1 -1
  436. package/src/model/settings.ts +8 -2
  437. package/src/model/sketch.ts +101 -14
  438. package/src/model/smooth.ts +51 -0
  439. package/src/model/store.ts +35 -4
  440. package/src/model/types.ts +170 -8
  441. package/src/model/wallfaces.ts +126 -17
  442. package/src/model/wallshape.ts +97 -0
  443. package/src/react/BottomBar.tsx +263 -46
  444. package/src/react/Buttons.tsx +50 -9
  445. package/src/react/CadEditor.tsx +142 -34
  446. package/src/react/ConfirmSheet.tsx +38 -0
  447. package/src/react/ConflictSheet.tsx +19 -12
  448. package/src/react/Drawer.tsx +213 -110
  449. package/src/react/Duck.tsx +50 -0
  450. package/src/react/Empty3D.tsx +32 -0
  451. package/src/react/FitScroll.tsx +19 -0
  452. package/src/react/Icon.native.tsx +5 -0
  453. package/src/react/Icon.web.tsx +5 -0
  454. package/src/react/KeypadSheet.tsx +253 -60
  455. package/src/react/LaserTray.tsx +12 -8
  456. package/src/react/MarkupPanel.tsx +150 -0
  457. package/src/react/PageThumb.native.tsx +18 -7
  458. package/src/react/PageThumb.web.tsx +4 -4
  459. package/src/react/PlanCanvas.native.tsx +151 -34
  460. package/src/react/PlanCanvas.web.tsx +15 -5
  461. package/src/react/Popovers.tsx +116 -51
  462. package/src/react/Rail.tsx +360 -27
  463. package/src/react/ShapeMenu.tsx +66 -0
  464. package/src/react/Sheet.tsx +56 -11
  465. package/src/react/Slider.tsx +48 -0
  466. package/src/react/Toast.tsx +16 -9
  467. package/src/react/ToolTip.tsx +49 -0
  468. package/src/react/TopBar.tsx +97 -39
  469. package/src/react/Tween.native.tsx +36 -0
  470. package/src/react/Tween.tsx +24 -0
  471. package/src/react/View3D.native.tsx +131 -0
  472. package/src/react/View3D.web.tsx +131 -0
  473. package/src/react/View3DHost.ts +367 -0
  474. package/src/react/corners.ts +52 -0
  475. package/src/react/easing.ts +14 -0
  476. package/src/react/host.ts +8 -3
  477. package/src/react/hostKeypad.ts +66 -0
  478. package/src/react/motion.tsx +239 -0
  479. package/src/react/ports.ts +78 -9
  480. package/src/react/saving.ts +80 -0
  481. package/src/react/store.ts +35 -3
  482. package/src/react/theme.ts +8 -0
  483. package/src/react/topRow.ts +71 -0
  484. package/src/react/touch.ts +10 -0
  485. package/src/render/ctx.ts +8 -0
  486. package/src/render/draw.ts +437 -175
  487. package/src/render/elevation.ts +349 -143
  488. package/src/render/figmaIcons.ts +22 -0
  489. package/src/render/hit.ts +140 -21
  490. package/src/render/icons.ts +69 -10
  491. package/src/render/linkTile.ts +297 -0
  492. package/src/render/markup.ts +91 -0
  493. package/src/render/navigate.ts +114 -0
  494. package/src/render/snap.ts +105 -22
  495. package/src/render/squircle.ts +73 -0
  496. package/src/render/view.ts +255 -19
  497. package/src/skia/SkiaDrawCtx.ts +163 -41
  498. package/src/skia/host.ts +46 -1
  499. package/src/solver/equations.ts +37 -2
  500. package/src/solver/gauss-newton.ts +125 -28
  501. package/src/solver/linalg.ts +141 -5
  502. package/src/solver/types.ts +5 -0
  503. package/src/styles.css +91 -42
  504. package/src/tools/annotate.ts +58 -29
  505. package/src/tools/chamfer.ts +103 -0
  506. package/src/tools/corner.ts +99 -0
  507. package/src/tools/dim.ts +525 -93
  508. package/src/tools/elevation.ts +5 -5
  509. package/src/tools/fillet.ts +82 -0
  510. package/src/tools/freehand.ts +20 -16
  511. package/src/tools/index.ts +17 -4
  512. package/src/tools/line.ts +59 -23
  513. package/src/tools/modify.ts +86 -24
  514. package/src/tools/openings.ts +11 -16
  515. package/src/tools/registry.ts +27 -2
  516. package/src/tools/select.ts +424 -75
  517. package/src/tools/shapes.ts +119 -58
  518. package/src/ui/ctx.ts +2 -1
  519. package/src/ui/domPorts.ts +23 -4
  520. package/src/ui/drawer.ts +6 -26
  521. package/src/ui/elevation.ts +10 -101
  522. package/src/ui/keypad.ts +8 -14
  523. package/src/ui/laser.ts +2 -2
  524. package/src/ui/menu.ts +63 -17
  525. package/src/ui/noteinput.ts +3 -3
  526. package/src/ui/opacity.ts +108 -0
  527. package/src/ui/palette.ts +67 -12
  528. package/src/ui/rail.ts +21 -7
  529. package/src/ui/topbar.ts +4 -14
  530. package/src/units/format.ts +24 -6
  531. package/src/units/parse.ts +4 -3
  532. package/src/units/prefs.ts +13 -1
  533. package/src/view3d/build.ts +607 -0
  534. package/src/view3d/camera.ts +113 -0
  535. package/src/view3d/fatLines.ts +83 -0
  536. package/src/view3d/lines.ts +258 -0
  537. package/src/view3d/mesh.ts +111 -0
  538. package/src/view3d/poly.ts +104 -0
  539. package/src/view3d/viewer.ts +348 -0
  540. package/dist/react/ElevCanvas.native.d.ts +0 -3
  541. package/dist/react/ElevCanvas.native.js +0 -58
  542. package/dist/react/ElevCanvas.native.js.map +0 -1
  543. package/dist/react/ElevCanvas.web.d.ts +0 -4
  544. package/dist/react/ElevCanvas.web.js +0 -44
  545. package/dist/react/ElevCanvas.web.js.map +0 -1
  546. package/dist/react/ElevationSheet.d.ts +0 -2
  547. package/dist/react/ElevationSheet.js +0 -38
  548. package/dist/react/ElevationSheet.js.map +0 -1
  549. package/dist/render/elevationView.d.ts +0 -3
  550. package/dist/render/elevationView.js +0 -100
  551. package/dist/render/elevationView.js.map +0 -1
  552. package/src/react/ElevCanvas.native.tsx +0 -68
  553. package/src/react/ElevCanvas.web.tsx +0 -42
  554. package/src/react/ElevationSheet.tsx +0 -88
  555. package/src/render/elevationView.ts +0 -73
package/src/data/sync.ts CHANGED
@@ -1,12 +1,18 @@
1
+ import { imagesOf } from '../model/images';
1
2
  import { analyze } from '../app/edit';
2
3
  import { ed } from '../app/state';
3
4
  import { existsSel } from '../app/edit';
4
5
  import { refreshDrawerSoon, renderElevation, updateCtx, updateStatus, updateTopBar } from '../editor/ports';
6
+ import { refreshLinks } from '../editor/links';
5
7
  import { newPage } from '../model/demo';
6
- import { clearPageHistory } from '../model/history';
8
+ import { allCons } from '../model/faces';
9
+ import { syncFaces } from '../model/facesolve';
10
+ import { clearPageHistory, imageStored } from '../model/history';
7
11
  import { defaultLayers, settings } from '../model/settings';
8
- import { saveSoon, store, type Persistence } from '../model/store';
12
+ import { store, type Persistence } from '../model/store';
9
13
  import type { Constraint, Page, Project } from '../model/types';
14
+ import { dimMeasurement, dimValueOf } from '../model/measurement';
15
+ import { linkedMeasurements } from '../model/links';
10
16
  import { setDimValue } from '../tools/dim';
11
17
  import { aliasImage, requestDraw } from '../render/view';
12
18
  import type { CadDataProvider, CadFileMeta, CadMeasurementValue, CadPageDoc } from './provider';
@@ -24,10 +30,16 @@ export class NotACadDrawing extends Error {
24
30
  }
25
31
 
26
32
  export interface CadSyncOptions {
27
- /** start a new drawing when the file has no drawing record yet (a file just created for it) */
33
+ /**
34
+ * The file was just created here: start its first page without waiting for the server's word on its pages (offline,
35
+ * the cache says there are none, as it says of any drawing never opened on this device). Also starts a new drawing
36
+ * when the file has no drawing record yet.
37
+ */
28
38
  initialize?: boolean;
29
39
  /** a write or upload failed */
30
40
  onError?: (e: unknown) => void;
41
+ /** closes the drawing while it's still opening (the person left): the promise rejects and nothing is written */
42
+ signal?: AbortSignal;
31
43
  }
32
44
 
33
45
  export interface CadSync {
@@ -41,78 +53,77 @@ export interface CadSync {
41
53
  saveThumbnail(dataUrl: string): void;
42
54
  /** the URL to draw a stored underlay from (`stored:` references; see CadDataProvider.uploadImage) */
43
55
  imageUrl?(ref: string): Promise<string>;
56
+ /** whether the drawing open in the editor differs from what was last saved (or taken in) */
57
+ hasChanges(): boolean;
58
+ /** how many writes or uploads have failed so far (a save failed if this grew) */
59
+ failures(): number;
44
60
  }
45
61
 
46
- const LENGTHS = new Set<Constraint['type']>(['dist', 'pldist', 'diam']);
47
-
48
62
  /**
49
- * A driving dimension's value as BOLDR keeps it: lengths in micrometres, angles in degrees. Null for what isn't a
50
- * measurement: reference and print dimensions, and constraints without a value.
63
+ * A driving dimension's value as BOLDR keeps it: lengths in micrometres, angles in degrees. Null for what isn't one of
64
+ * the drawing's own measurements: reference and print dimensions, constraints without a value, and dimensions linked
65
+ * to a measurement of the job (the job's, not the drawing's: see editor/links.ts).
51
66
  */
52
67
  export function measurementOf(c: Constraint): CadMeasurementValue | null {
53
- if (c.driving === false || c.layer === 'print' || c.value == null) return null;
54
- if (c.type === 'angle') return { kind: 'angle', value: Math.round(c.value * 100) / 100 };
55
- if (LENGTHS.has(c.type)) return { kind: 'length', value: Math.round(c.value * 25400) };
56
- return null;
68
+ return c.measurementRef ? null : dimMeasurement(c);
57
69
  }
58
- const toInches = (m: CadMeasurementValue): number => (m.kind === 'angle' ? m.value : m.value / 25400);
59
70
 
60
71
  /** The id of a new drawing's first page. */
61
72
  export const FIRST_PAGE_ID = 'page-1';
62
73
 
63
- const pageJson = (p: { name: string; sk: unknown; underlay: unknown }) => JSON.stringify({ name: p.name, sk: p.sk, underlay: p.underlay });
74
+ const pageJson = (p: { name: string; sk: unknown; underlays?: unknown; underlay?: unknown }) =>
75
+ JSON.stringify({ name: p.name, sk: p.sk, underlays: imagesOf(p as Parameters<typeof imagesOf>[0]) });
64
76
  const newClientId = () => Date.now().toString(36) + '-' + Math.floor(Math.random() * 0x100000000).toString(36);
65
77
 
66
78
  export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions = {}): Promise<CadSync> {
67
79
  const clientId = newClientId();
68
80
  let seq = 0, file: { name: string; meta: CadFileMeta | null } | null | undefined, pages: Record<string, CadPageDoc> | undefined;
81
+ /** whether the latest file and pages snapshots are the cache's word rather than the server's */
82
+ let fileFromCache = false, pagesFromCache = false;
69
83
  /** what each page looked like when last saved or taken in (to tell local edits from remote ones) */
70
84
  const saved = new Map<string, string>();
85
+ /** removed pages whose delete is queued or in flight */
86
+ const deleting = new Set<string>();
71
87
  /** pages with a write queued or in flight (count per page) */
72
88
  const writing = new Map<string, number>();
73
89
  let savedMeta = '', project: Project | null = null, chain: Promise<void> = Promise.resolve(), stopped = false;
74
- const fail = (e: unknown) => { opts.onError?.(e); };
90
+ let failures = 0;
91
+ const fail = (e: unknown) => { failures++; opts.onError?.(e); };
75
92
  const meas = provider.measurements;
76
93
  /** each measurement's value as last written or seen (undefined: not heard from BOLDR yet) */
77
94
  const known = new Map<string, number>();
78
- /** dimensions whose measurement is being created: "pageId|constraintId" */
79
- const creating = new Set<string>();
80
95
  /** each dimension's measurement, so a dimension that undo brought back without its id gets the same one again */
81
96
  const linked = new Map<string, string>();
82
97
  let placed = '', unsubMeas: (() => void) | null = null;
83
98
  const pagesNow = () => (store.project === project ? store.project : project)?.pages ?? [];
84
99
 
85
- /** Every driving dimension is kept as a BOLDR measurement: create the missing ones, update the changed ones. */
100
+ /**
101
+ * The drawing's own measurements in BOLDR follow its dimensions: one a dimension already has (made by an earlier
102
+ * version, which kept every driving dimension as one) gets its new value. A new dimension stays the drawing's alone
103
+ * until the person saves it to the group (editor/linkActions.ts), when it's linked like any other measurement of the
104
+ * job — and those are the job's to keep (the host's `links`), never written here.
105
+ */
86
106
  function linkMeasurements(p: Project): void {
87
107
  if (!meas) return;
88
108
  const ids = new Set<string>();
89
- for (const pg of p.pages) for (const [cid, c] of Object.entries(pg.sk.cons)) {
109
+ for (const pg of p.pages) for (const [cid, c] of allCons(pg.sk)) {
90
110
  const key = pg.id + '|' + cid;
111
+ // (linked to the job's: not the drawing's own, whatever it was before)
112
+ if (c.measurementRef) { if (c.measurementId) delete c.measurementId; linked.delete(key); continue; }
91
113
  if (!c.measurementId && linked.has(key)) c.measurementId = linked.get(key);
92
- if (c.measurementId) { ids.add(c.measurementId); linked.set(key, c.measurementId); }
114
+ if (!c.measurementId) continue;
115
+ ids.add(c.measurementId);
116
+ linked.set(key, c.measurementId);
93
117
  const m = measurementOf(c);
94
- if (!m) continue;
95
- if (!c.measurementId) {
96
- if (creating.has(key)) continue;
97
- creating.add(key);
98
- queue(async () => {
99
- try {
100
- const id = await meas.create(m);
101
- known.set(id, m.value);
102
- linked.set(key, id);
103
- // the page's sketch may have been replaced since (undo): stamp the dimension as it is now
104
- const cur = pagesNow().find(x => x.id === pg.id)?.sk.cons[cid];
105
- if (cur && !cur.measurementId) { cur.measurementId = id; saveSoon(); }
106
- } finally { creating.delete(key); }
107
- });
108
- } else if (known.has(c.measurementId) && known.get(c.measurementId) !== m.value) {
118
+ if (m && known.has(c.measurementId) && known.get(c.measurementId) !== m.value) {
109
119
  const id = c.measurementId;
110
120
  known.set(id, m.value);
111
121
  queue(() => meas.update(id, m.value));
112
122
  }
113
123
  }
114
- const pj = JSON.stringify([...ids].sort());
115
- if (meas.setPlaced && pj !== placed) { placed = pj; queue(() => meas.setPlaced!(JSON.parse(pj) as string[])); }
124
+ // where the drawing shows measurements: its own, and the job's it's linked to (each with its own group)
125
+ const job = linkedMeasurements(p), pj = JSON.stringify([[...ids].sort(), job.map(j => j.groupId + '|' + j.id + '|' + (j.columnId ?? '')).sort()]);
126
+ if (meas.setPlaced && pj !== placed) { placed = pj; const own = [...ids].sort(); queue(() => meas.setPlaced!(own, job)); }
116
127
  }
117
128
 
118
129
  /** A measurement changed elsewhere (or while the drawing was closed): its dimension follows. */
@@ -121,13 +132,21 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
121
132
  const prev = known.get(id);
122
133
  known.set(id, mv.value);
123
134
  if (prev === mv.value) continue;
124
- for (const pg of pagesNow()) for (const [cid, c] of Object.entries(pg.sk.cons)) {
135
+ for (const pg of pagesNow()) for (const [cid, c] of allCons(pg.sk)) {
125
136
  if (c.measurementId !== id) continue;
126
137
  const m = measurementOf(c);
127
138
  if (!m || m.value === mv.value) continue;
139
+ const editing = store.project === project && pg.id === store.curPageId;
140
+ const v = dimValueOf(c, mv); // (a fillet's radius is kept as its diameter)
141
+ if (!pg.sk.cons[cid]) {
142
+ // on a wall face: the face solves now on the page being edited (positions stay if it can't), elsewhere when next edited
143
+ c.value = v;
144
+ if (editing) { ed.badFaceCons = syncFaces(pg.sk); analyze(); requestDraw(); renderElevation(); }
145
+ continue;
146
+ }
128
147
  // on the page being edited the drawing solves now (or explains why it can't); elsewhere when next edited
129
- if (store.project === project && pg.id === store.curPageId) setDimValue(cid, toInches(mv));
130
- else c.value = toInches(mv);
148
+ if (editing) setDimValue(cid, v);
149
+ else c.value = v;
131
150
  }
132
151
  }
133
152
  }
@@ -137,7 +156,7 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
137
156
  format: 'boldr-cad', version: 1, pageOrder: p.pages.map(pg => pg.id),
138
157
  settings: { wallH: settings.wallH, layers: { ...settings.layers } },
139
158
  });
140
- const docOf = (pg: Page): CadPageDoc => ({ name: pg.name, sk: pg.sk, underlay: pg.underlay, rev: { clientId, seq: ++seq } });
159
+ const docOf = (pg: Page): CadPageDoc => ({ name: pg.name, sk: pg.sk, underlays: pg.underlays, rev: { clientId, seq: ++seq } });
141
160
 
142
161
  /** Take in pages and the record someone else changed, where nothing local is unsaved. */
143
162
  function takeIn(): void {
@@ -149,10 +168,11 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
149
168
  const json = pageJson(doc), local = project.pages.find(p => p.id === id);
150
169
  if (local) {
151
170
  if (pageJson(local) !== saved.get(id) || json === saved.get(id)) continue; // edited here since, or nothing new
152
- local.name = doc.name; local.sk = doc.sk; local.underlay = doc.underlay;
171
+ local.name = doc.name; local.sk = doc.sk; local.underlays = imagesOf(doc);
153
172
  clearPageHistory(id);
154
173
  if (id === store.curPageId) curChanged = true;
155
- } else project.pages.push({ id, name: doc.name, sk: doc.sk, underlay: doc.underlay, view: null });
174
+ } else if (saved.has(id)) continue; // removed here (not saved yet, or its delete is on the way)
175
+ else project.pages.push({ id, name: doc.name, sk: doc.sk, underlays: imagesOf(doc), view: null });
156
176
  saved.set(id, json);
157
177
  changed = true;
158
178
  }
@@ -165,7 +185,7 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
165
185
  if (file && file.name !== project.name) { project.name = file.name; changed = true; }
166
186
  if (!changed) return;
167
187
  if (curChanged) { analyze(); ed.sel = ed.sel.filter(existsSel); }
168
- updateTopBar(); updateCtx(); updateStatus(); refreshDrawerSoon(); renderElevation(); requestDraw();
188
+ updateTopBar(); updateCtx(); updateStatus(); refreshDrawerSoon(); renderElevation(); requestDraw(); refreshLinks();
169
189
  }
170
190
 
171
191
  const persistence: Persistence = {
@@ -176,6 +196,8 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
176
196
  const st = file?.meta?.settings;
177
197
  if (st?.wallH) settings.wallH = st.wallH;
178
198
  if (st?.layers) settings.layers = Object.assign(defaultLayers(), st.layers);
199
+ // the record as this editor would write it (a record missing newer settings isn't an unsaved change)
200
+ if (file?.meta) savedMeta = JSON.stringify(metaOf(project));
179
201
  },
180
202
  save() {
181
203
  const p = store.project;
@@ -190,24 +212,39 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
190
212
  queue(async () => {
191
213
  try {
192
214
  // traced images are stored as files: upload, then keep the reference (the picture already shown stays)
193
- if (pg.underlay && pg.underlay.src.startsWith('data:')) {
194
- const local = pg.underlay.src, ref = await provider.uploadImage(pg.id, local);
215
+ for (const u of pg.underlays) {
216
+ if (!u.src.startsWith('data:')) continue;
217
+ const local = u.src, ref = await provider.uploadImage(pg.id, local);
195
218
  aliasImage(local, ref);
196
- pg.underlay.src = ref;
219
+ // the same picture wherever it's held: the page (if it's still there), and its undo steps
220
+ for (const v of pg.underlays) if (v.src === local) v.src = ref;
221
+ imageStored(pg.id, local, ref);
197
222
  saved.set(pg.id, pageJson(pg));
198
223
  requestDraw();
199
224
  }
200
225
  await provider.writePage(pg.id, docOf(pg));
226
+ } catch (e) {
227
+ // not written: the page counts as changed again, so the next save retries it
228
+ if (saved.get(pg.id) === json || saved.get(pg.id) === pageJson(pg)) saved.delete(pg.id);
229
+ throw e;
201
230
  } finally { done(); }
202
231
  });
203
232
  }
204
233
  for (const id of [...saved.keys()]) {
205
- if (p.pages.some(pg => pg.id === id)) continue;
206
- saved.delete(id);
207
- queue(() => provider.deletePage(id));
234
+ if (p.pages.some(pg => pg.id === id) || deleting.has(id)) continue;
235
+ deleting.add(id);
236
+ queue(async () => {
237
+ try { await provider.deletePage(id); saved.delete(id); } finally { deleting.delete(id); }
238
+ });
208
239
  }
209
240
  const meta = metaOf(p), mj = JSON.stringify(meta);
210
- if (mj !== savedMeta) { savedMeta = mj; queue(() => provider.writeMeta(meta)); }
241
+ if (mj !== savedMeta) {
242
+ const was = savedMeta;
243
+ savedMeta = mj;
244
+ queue(async () => {
245
+ try { await provider.writeMeta(meta); } catch (e) { if (savedMeta === mj) savedMeta = was; throw e; }
246
+ });
247
+ }
211
248
  return true;
212
249
  },
213
250
  };
@@ -216,12 +253,17 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
216
253
  let ready = false;
217
254
  const tryOpen = () => {
218
255
  if (ready || file === undefined || pages === undefined) return;
256
+ // the cache's word isn't final: a file it hasn't got, or a drawing whose pages it hasn't got, may well be on the
257
+ // server — wait for its answer (a file just created here is fresh: its first page is made without waiting)
258
+ if (file === null && fileFromCache) return;
259
+ const fresh = !!opts.initialize && !file?.meta?.pageOrder.length;
260
+ if (file && !Object.keys(pages).length && pagesFromCache && !fresh) return;
219
261
  ready = true;
220
262
  if (file === null) { stop(); reject(new NotACadDrawing('missing')); return; }
221
263
  if (!file.meta && !opts.initialize) { stop(); reject(new NotACadDrawing('legacy')); return; }
222
264
  const order = file.meta?.pageOrder ?? [];
223
265
  const ids = [...order.filter(id => pages![id]), ...Object.keys(pages!).filter(id => !order.includes(id))];
224
- project = { name: file.name, pages: ids.map(id => ({ id, name: pages![id].name, sk: pages![id].sk, underlay: pages![id].underlay, view: null })) };
266
+ project = { name: file.name, pages: ids.map(id => ({ id, name: pages![id].name, sk: pages![id].sk, underlays: imagesOf(pages![id]), view: null })) };
225
267
  for (const id of ids) saved.set(id, pageJson(pages![id]));
226
268
  if (file.meta) savedMeta = JSON.stringify(file.meta);
227
269
  // a new drawing (or one whose pages are all gone) starts with one empty page, saved straight away; its id is
@@ -238,11 +280,23 @@ export function openCadDrawing(provider: CadDataProvider, opts: CadSyncOptions =
238
280
  persistence, stop, idle: () => chain,
239
281
  saveThumbnail: dataUrl => { if (provider.uploadThumbnail) queue(() => provider.uploadThumbnail!(dataUrl)); },
240
282
  imageUrl: provider.imageUrl ? ref => provider.imageUrl!(ref) : undefined,
283
+ hasChanges: () => {
284
+ const p = store.project === project ? store.project : project;
285
+ if (!p) return false;
286
+ if (p.pages.some(pg => pageJson(pg) !== saved.get(pg.id))) return true;
287
+ if ([...saved.keys()].some(id => !p.pages.some(pg => pg.id === id))) return true;
288
+ return JSON.stringify(metaOf(p)) !== savedMeta;
289
+ },
290
+ failures: () => failures,
241
291
  });
242
292
  };
243
- const unsubFile = provider.subscribeFile(f => { file = f; if (ready) takeIn(); else tryOpen(); });
244
- const unsubPages = provider.subscribePages(p => { pages = p; if (ready) takeIn(); else tryOpen(); });
293
+ const unsubFile = provider.subscribeFile((f, m) => { file = f; fileFromCache = !!m?.fromCache; if (ready) takeIn(); else tryOpen(); });
294
+ const unsubPages = provider.subscribePages((p, m) => { pages = p; pagesFromCache = !!m?.fromCache; if (ready) takeIn(); else tryOpen(); });
245
295
  unsubMeas = meas ? meas.subscribe(takeInMeasurements) : null;
246
296
  function stop() { stopped = true; unsubFile(); unsubPages(); unsubMeas?.(); }
297
+ // left while still opening: let go of the drawing, nothing written
298
+ const abort = () => { if (ready) return; ready = true; stop(); reject(new Error('closed')); };
299
+ if (opts.signal?.aborted) abort();
300
+ else opts.signal?.addEventListener('abort', abort, { once: true });
247
301
  });
248
302
  }