openplanr 3.2.0 → 3.3.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 (231) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cli/commands/spec.d.ts +2 -1
  3. package/dist/cli/commands/spec.d.ts.map +1 -1
  4. package/dist/cli/commands/spec.js +45 -5
  5. package/dist/cli/commands/spec.js.map +1 -1
  6. package/dist/dashboard/.vite/manifest.json +1 -1
  7. package/dist/dashboard/assets/index-B_96uzCl.js +572 -0
  8. package/dist/dashboard/assets/index-B_96uzCl.js.map +1 -0
  9. package/dist/dashboard/dashboard-manifest.json +10 -10
  10. package/dist/dashboard/index.html +1 -1
  11. package/dist/services/claude-plugin-service.d.ts +5 -0
  12. package/dist/services/claude-plugin-service.d.ts.map +1 -1
  13. package/dist/services/claude-plugin-service.js +18 -2
  14. package/dist/services/claude-plugin-service.js.map +1 -1
  15. package/dist/services/codex-plugin-service.d.ts.map +1 -1
  16. package/dist/services/codex-plugin-service.js +11 -3
  17. package/dist/services/codex-plugin-service.js.map +1 -1
  18. package/dist/services/runtime-manager/codex-discovery.d.ts +1 -3
  19. package/dist/services/runtime-manager/codex-discovery.d.ts.map +1 -1
  20. package/dist/services/runtime-manager/codex-discovery.js +3 -16
  21. package/dist/services/runtime-manager/codex-discovery.js.map +1 -1
  22. package/dist/services/runtime-manager/doctor.d.ts +25 -0
  23. package/dist/services/runtime-manager/doctor.d.ts.map +1 -1
  24. package/dist/services/runtime-manager/doctor.js +480 -0
  25. package/dist/services/runtime-manager/doctor.js.map +1 -1
  26. package/dist/services/runtime-manager/errors.d.ts +12 -0
  27. package/dist/services/runtime-manager/errors.d.ts.map +1 -0
  28. package/dist/services/runtime-manager/errors.js +14 -0
  29. package/dist/services/runtime-manager/errors.js.map +1 -0
  30. package/dist/services/runtime-manager/global-state.d.ts +7 -0
  31. package/dist/services/runtime-manager/global-state.d.ts.map +1 -1
  32. package/dist/services/runtime-manager/global-state.js +116 -0
  33. package/dist/services/runtime-manager/global-state.js.map +1 -1
  34. package/dist/services/runtime-manager/host-version-probe.d.ts +8 -0
  35. package/dist/services/runtime-manager/host-version-probe.d.ts.map +1 -0
  36. package/dist/services/runtime-manager/host-version-probe.js +14 -0
  37. package/dist/services/runtime-manager/host-version-probe.js.map +1 -0
  38. package/dist/services/runtime-manager/install-plan.d.ts +25 -0
  39. package/dist/services/runtime-manager/install-plan.d.ts.map +1 -1
  40. package/dist/services/runtime-manager/install-plan.js +305 -0
  41. package/dist/services/runtime-manager/install-plan.js.map +1 -1
  42. package/dist/services/runtime-manager/inventory.d.ts +6 -0
  43. package/dist/services/runtime-manager/inventory.d.ts.map +1 -1
  44. package/dist/services/runtime-manager/inventory.js +16 -1
  45. package/dist/services/runtime-manager/inventory.js.map +1 -1
  46. package/dist/services/runtime-manager/legacy-adapters.d.ts +9 -0
  47. package/dist/services/runtime-manager/legacy-adapters.d.ts.map +1 -0
  48. package/dist/services/runtime-manager/legacy-adapters.js +187 -0
  49. package/dist/services/runtime-manager/legacy-adapters.js.map +1 -0
  50. package/dist/services/runtime-manager/paths.d.ts +18 -0
  51. package/dist/services/runtime-manager/paths.d.ts.map +1 -0
  52. package/dist/services/runtime-manager/paths.js +83 -0
  53. package/dist/services/runtime-manager/paths.js.map +1 -0
  54. package/dist/services/runtime-manager/runtime-package.d.ts +21 -0
  55. package/dist/services/runtime-manager/runtime-package.d.ts.map +1 -1
  56. package/dist/services/runtime-manager/runtime-package.js +77 -0
  57. package/dist/services/runtime-manager/runtime-package.js.map +1 -1
  58. package/dist/services/runtime-manager/storage.d.ts +47 -0
  59. package/dist/services/runtime-manager/storage.d.ts.map +1 -0
  60. package/dist/services/runtime-manager/storage.js +604 -0
  61. package/dist/services/runtime-manager/storage.js.map +1 -0
  62. package/dist/services/runtime-manager-service.d.ts +7 -17
  63. package/dist/services/runtime-manager-service.d.ts.map +1 -1
  64. package/dist/services/runtime-manager-service.js +32 -1695
  65. package/dist/services/runtime-manager-service.js.map +1 -1
  66. package/dist/services/ship-checks/contract.d.ts +13 -1
  67. package/dist/services/ship-checks/contract.d.ts.map +1 -1
  68. package/dist/services/ship-checks/contract.js +1 -1
  69. package/dist/services/ship-checks/contract.js.map +1 -1
  70. package/dist/services/ship-checks/coverage.d.ts +4 -0
  71. package/dist/services/ship-checks/coverage.d.ts.map +1 -0
  72. package/dist/services/ship-checks/coverage.js +113 -0
  73. package/dist/services/ship-checks/coverage.js.map +1 -0
  74. package/dist/services/ship-checks/discover.d.ts.map +1 -1
  75. package/dist/services/ship-checks/discover.js +3 -0
  76. package/dist/services/ship-checks/discover.js.map +1 -1
  77. package/dist/services/spec-service.d.ts +18 -0
  78. package/dist/services/spec-service.d.ts.map +1 -1
  79. package/dist/services/spec-service.js +174 -9
  80. package/dist/services/spec-service.js.map +1 -1
  81. package/dist/templates/spec/spec-shaped.md.hbs +1 -1
  82. package/dist/templates/spec/spec.md.hbs +2 -2
  83. package/docs/CLI.md +49 -2
  84. package/lib/host-packages/adapter-registry.json +5 -5
  85. package/lib/host-packages/capability-map.json +3 -3
  86. package/lib/host-packages/claude/.claude-plugin/marketplace.json +2 -2
  87. package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +1 -1
  88. package/lib/host-packages/claude/openplanr/.openplanr-content.json +50 -46
  89. package/lib/host-packages/claude/openplanr/README.md +1 -1
  90. package/lib/host-packages/claude/openplanr/agents/planr-qa.md +5 -3
  91. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +87 -2
  92. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +1 -1
  93. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +1 -1
  94. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +102 -9
  95. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +130 -1
  96. package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +271 -28
  97. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -32
  98. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +77 -1
  99. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +4 -4
  100. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -4
  101. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +2 -2
  102. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +5 -5
  103. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +72 -2
  104. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +14 -7
  105. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +71 -34
  106. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +28 -14
  107. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +12 -12
  108. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +2 -2
  109. package/lib/host-packages/{cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0 → claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0}/design-document.schema.json +131 -4
  110. package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
  111. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +78 -1
  112. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +30 -2
  113. package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +2 -2
  114. package/lib/host-packages/claude/openplanr/skills/design/references/design-system.md +17 -2
  115. package/lib/host-packages/claude/openplanr/skills/design/references/generation.md +60 -2
  116. package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +11 -1
  117. package/lib/host-packages/claude/openplanr/skills/design/schemas/design-document.schema.json +131 -4
  118. package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-system.md +17 -2
  119. package/lib/host-packages/claude/openplanr/skills/design-loop/references/generation.md +60 -2
  120. package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +11 -1
  121. package/lib/host-packages/claude/openplanr/skills/design-loop/schemas/design-document.schema.json +131 -4
  122. package/lib/host-packages/claude/openplanr/skills/design-review/references/design-system.md +17 -2
  123. package/lib/host-packages/claude/openplanr/skills/design-review/references/generation.md +60 -2
  124. package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +11 -1
  125. package/lib/host-packages/claude/openplanr/skills/design-review/schemas/design-document.schema.json +131 -4
  126. package/lib/host-packages/claude/openplanr/skills/investigate/SKILL.md +1 -1
  127. package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +21 -11
  128. package/lib/host-packages/claude/openplanr/skills/plan/schemas/design-document.schema.json +131 -4
  129. package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +31 -10
  130. package/lib/host-packages/claude/openplanr/skills/spec/SKILL.md +6 -0
  131. package/lib/host-packages/claude/openplanr/skills/spec/references/specification-contract.md +3 -1
  132. package/lib/host-packages/cursor/openplanr/.openplanr-content.json +48 -44
  133. package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
  134. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-system.md +17 -2
  135. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/generation.md +60 -2
  136. package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +11 -1
  137. package/lib/host-packages/cursor/openplanr/rules/planr-design/schemas/design-document.schema.json +131 -4
  138. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-system.md +17 -2
  139. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/generation.md +60 -2
  140. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +11 -1
  141. package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/schemas/design-document.schema.json +131 -4
  142. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-system.md +17 -2
  143. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/generation.md +60 -2
  144. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +11 -1
  145. package/lib/host-packages/cursor/openplanr/rules/planr-design-review/schemas/design-document.schema.json +131 -4
  146. package/lib/host-packages/cursor/openplanr/rules/planr-investigate.mdc +1 -1
  147. package/lib/host-packages/cursor/openplanr/rules/planr-plan/schemas/design-document.schema.json +131 -4
  148. package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +21 -11
  149. package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +31 -10
  150. package/lib/host-packages/cursor/openplanr/rules/planr-spec/references/specification-contract.md +3 -1
  151. package/lib/host-packages/cursor/openplanr/rules/planr-spec.mdc +6 -0
  152. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +87 -2
  153. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +1 -1
  154. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +1 -1
  155. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +102 -9
  156. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +130 -1
  157. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +271 -28
  158. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -32
  159. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +77 -1
  160. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +4 -4
  161. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -4
  162. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +2 -2
  163. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +5 -5
  164. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +72 -2
  165. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +14 -7
  166. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +71 -34
  167. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +28 -14
  168. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +12 -12
  169. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +2 -2
  170. package/lib/host-packages/{openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0 → cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0}/design-document.schema.json +131 -4
  171. package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
  172. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +78 -1
  173. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +30 -2
  174. package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +2 -2
  175. package/lib/host-packages/openai/.claude-plugin/marketplace.json +2 -2
  176. package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +1 -1
  177. package/lib/host-packages/openai/openplanr/.openplanr-content.json +54 -50
  178. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +87 -2
  179. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +1 -1
  180. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +1 -1
  181. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +102 -9
  182. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +130 -1
  183. package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +271 -28
  184. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -32
  185. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +77 -1
  186. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +4 -4
  187. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -4
  188. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +2 -2
  189. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +5 -5
  190. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +72 -2
  191. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +14 -7
  192. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +71 -34
  193. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +28 -14
  194. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +12 -12
  195. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +2 -2
  196. package/lib/host-packages/{claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0 → openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0}/design-document.schema.json +131 -4
  197. package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
  198. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +78 -1
  199. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +30 -2
  200. package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +2 -2
  201. package/lib/host-packages/openai/openplanr/skills/design/references/design-system.md +17 -2
  202. package/lib/host-packages/openai/openplanr/skills/design/references/generation.md +60 -2
  203. package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +11 -1
  204. package/lib/host-packages/openai/openplanr/skills/design/schemas/design-document.schema.json +131 -4
  205. package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-system.md +17 -2
  206. package/lib/host-packages/openai/openplanr/skills/design-loop/references/generation.md +60 -2
  207. package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +11 -1
  208. package/lib/host-packages/openai/openplanr/skills/design-loop/schemas/design-document.schema.json +131 -4
  209. package/lib/host-packages/openai/openplanr/skills/design-review/references/design-system.md +17 -2
  210. package/lib/host-packages/openai/openplanr/skills/design-review/references/generation.md +60 -2
  211. package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +11 -1
  212. package/lib/host-packages/openai/openplanr/skills/design-review/schemas/design-document.schema.json +131 -4
  213. package/lib/host-packages/openai/openplanr/skills/investigate/SKILL.md +1 -1
  214. package/lib/host-packages/openai/openplanr/skills/investigate/agents/openai.yaml +1 -1
  215. package/lib/host-packages/openai/openplanr/skills/investigate/openplanr.skill.json +1 -1
  216. package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +21 -11
  217. package/lib/host-packages/openai/openplanr/skills/plan/openplanr.skill.json +1 -1
  218. package/lib/host-packages/openai/openplanr/skills/plan/schemas/design-document.schema.json +131 -4
  219. package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +31 -10
  220. package/lib/host-packages/openai/openplanr/skills/ship/agents/openai.yaml +1 -1
  221. package/lib/host-packages/openai/openplanr/skills/ship/openplanr.skill.json +1 -1
  222. package/lib/host-packages/openai/openplanr/skills/spec/SKILL.md +6 -0
  223. package/lib/host-packages/openai/openplanr/skills/spec/openplanr.skill.json +1 -1
  224. package/lib/host-packages/openai/openplanr/skills/spec/references/specification-contract.md +3 -1
  225. package/lib/json-schema.mjs +4 -0
  226. package/package.json +12 -12
  227. package/dist/dashboard/assets/index-L8qtwqv6.js +0 -572
  228. package/dist/dashboard/assets/index-L8qtwqv6.js.map +0 -1
  229. /package/lib/host-packages/claude/openplanr/runtime/design/scripts/{design-runtime-support-6774fd3d5d02.mjs → design-runtime-support-25485dbf1cb2.mjs} +0 -0
  230. /package/lib/host-packages/cursor/openplanr/runtime/design/scripts/{design-runtime-support-6774fd3d5d02.mjs → design-runtime-support-25485dbf1cb2.mjs} +0 -0
  231. /package/lib/host-packages/openai/openplanr/runtime/design/scripts/{design-runtime-support-6774fd3d5d02.mjs → design-runtime-support-25485dbf1cb2.mjs} +0 -0
@@ -276,6 +276,7 @@
276
276
  "maxContains",
277
277
  "required",
278
278
  "properties",
279
+ "propertyNames",
279
280
  "additionalProperties",
280
281
  "maxProperties",
281
282
  "dependentRequired",
@@ -344,6 +345,7 @@
344
345
  maxContains: ["a non-negative integer", isCount],
345
346
  required: ["an array of unique strings", isUniqueStrings],
346
347
  properties: ["an object of schemas", isSchemaMap],
348
+ propertyNames: ["a schema", isSchema],
347
349
  additionalProperties: ["a schema", isSchema],
348
350
  maxProperties: ["a non-negative integer", isCount],
349
351
  dependentRequired: [
@@ -612,6 +614,8 @@
612
614
  }
613
615
  const props = schema6.properties || {};
614
616
  for (const [k, v] of Object.entries(value)) {
617
+ if (schema6.propertyNames !== void 0)
618
+ validateNode(k, schema6.propertyNames, `${path}.${k}`, errs, context);
615
619
  if (Object.hasOwn(props, k)) evaluated.add(k);
616
620
  else if (schema6.additionalProperties !== void 0) evaluated.add(k);
617
621
  if (!Object.hasOwn(props, k)) {
@@ -4768,7 +4772,7 @@
4768
4772
  }
4769
4773
  }
4770
4774
  });
4771
- var DESIGN_DOCUMENT_SCHEMA = freeze({
4775
+ var DESIGN_DOCUMENT_V120_SCHEMA = freeze({
4772
4776
  ...DESIGN_DOCUMENT_V1_SCHEMA,
4773
4777
  $id: "https://openplanr.dev/schemas/v1.20.0/design-document.schema.json",
4774
4778
  "x-openplanr-contract": { id: "design-document", version: "1.20.0" },
@@ -4827,6 +4831,78 @@
4827
4831
  coordinate: { type: "number", minimum: -1e7, maximum: 1e7 }
4828
4832
  }
4829
4833
  });
4834
+ var PROP_TOKEN_SCHEMA = {
4835
+ type: "string",
4836
+ minLength: 1,
4837
+ maxLength: 128,
4838
+ pattern: "^[a-z][a-z0-9-]*(?![\\s\\S])"
4839
+ };
4840
+ var propTokenPattern = new RegExp(PROP_TOKEN_SCHEMA.pattern, "u");
4841
+ var currentDocument = (
4842
+ /** @type {{ properties: Record<string, unknown>; [key: string]: unknown }} */
4843
+ structuredClone(DESIGN_DOCUMENT_V120_SCHEMA)
4844
+ );
4845
+ currentDocument.$id = "https://openplanr.dev/schemas/v1.22.0/design-document.schema.json";
4846
+ currentDocument["x-openplanr-contract"] = { id: "design-document", version: "1.22.0" };
4847
+ currentDocument.properties.schemaVersion = { enum: ["1.0.0", "1.1.0"] };
4848
+ var screenSchema = (
4849
+ /** @type {{ items: { properties: Record<string, unknown> } }} */
4850
+ currentDocument.properties.screens
4851
+ );
4852
+ screenSchema.items.properties.props = {
4853
+ type: "object",
4854
+ propertyNames: PROP_TOKEN_SCHEMA,
4855
+ additionalProperties: {
4856
+ oneOf: [
4857
+ {
4858
+ type: "object",
4859
+ additionalProperties: false,
4860
+ required: ["type", "options", "default"],
4861
+ properties: {
4862
+ type: { const: "enum" },
4863
+ options: {
4864
+ type: "array",
4865
+ minItems: 1,
4866
+ uniqueItems: true,
4867
+ items: PROP_TOKEN_SCHEMA
4868
+ },
4869
+ default: PROP_TOKEN_SCHEMA
4870
+ }
4871
+ },
4872
+ {
4873
+ type: "object",
4874
+ additionalProperties: false,
4875
+ required: ["type", "default"],
4876
+ properties: { type: { const: "boolean" }, default: { type: "boolean" } }
4877
+ }
4878
+ ]
4879
+ }
4880
+ };
4881
+ var variantSchema = (
4882
+ /** @type {{ items: { properties: Record<string, unknown> } }} */
4883
+ currentDocument.properties.variants
4884
+ );
4885
+ variantSchema.items.properties.props = {
4886
+ type: "object",
4887
+ propertyNames: { $ref: "#/$defs/id" },
4888
+ additionalProperties: {
4889
+ type: "object",
4890
+ propertyNames: PROP_TOKEN_SCHEMA,
4891
+ additionalProperties: { anyOf: [PROP_TOKEN_SCHEMA, { type: "boolean" }] }
4892
+ }
4893
+ };
4894
+ currentDocument.allOf = [
4895
+ {
4896
+ if: { properties: { schemaVersion: { const: "1.1.0" } }, required: ["schemaVersion"] },
4897
+ else: {
4898
+ properties: {
4899
+ screens: { items: { not: { required: ["props"] } } },
4900
+ variants: { items: { not: { required: ["props"] } } }
4901
+ }
4902
+ }
4903
+ }
4904
+ ];
4905
+ var DESIGN_DOCUMENT_SCHEMA = freeze(currentDocument);
4830
4906
 
4831
4907
  // ../protocol/src/workspace-contracts.mjs
4832
4908
  var DESIGN_WORKSPACE_VERSION = "1.0.0";
@@ -2,8 +2,8 @@
2
2
  "kind": "openplanr-runtime-asset-sources",
3
3
  "schemaVersion": "1.0.0",
4
4
  "asset": "artifact-review-stage.js",
5
- "bytes": 537191,
6
- "sha256": "d9f30ef394d0fb333e6f90f62b9d736bc84972f476ec1b1ec2e394de58938e84",
5
+ "bytes": 539739,
6
+ "sha256": "42ea407da5d301f26f0c26eebcb20c404419c89fc9a455132a68eafdf099d891",
7
7
  "scopes": [
8
8
  {
9
9
  "id": "bundle",
@@ -55,8 +55,8 @@
55
55
  "packages/protocol/src/studio-presentation-contracts.mjs",
56
56
  "packages/protocol/src/workspace-contracts.mjs"
57
57
  ],
58
- "bytes": 189121,
59
- "sha256": "c5ecc1e13bc56b399f69808c609b21f69865ff134e50a8b4898dd8a93bd582ef"
58
+ "bytes": 191669,
59
+ "sha256": "fbf069e668fecf9519cab318f88033b106b93933ea0788f2c4c8cf8374c35e38"
60
60
  },
61
61
  {
62
62
  "path": "artifact-review-stage.js.sources/04-compression.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openplanr/design",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Canonical OpenPlanr design helpers and design-loop engine",
@@ -46,9 +46,9 @@
46
46
  "node": ">=22.13.0"
47
47
  },
48
48
  "dependencies": {
49
- "@openplanr/artifact": "0.7.0",
50
- "@openplanr/canvas": "0.0.0",
51
- "@openplanr/protocol": "0.14.0"
49
+ "@openplanr/artifact": "0.8.0",
50
+ "@openplanr/canvas": "0.0.1",
51
+ "@openplanr/protocol": "0.15.0"
52
52
  },
53
53
  "scripts": {
54
54
  "test": "node --test --test-concurrency=2 tests/*.test.mjs",
@@ -465,7 +465,7 @@
465
465
  exports.useTransition = function() {
466
466
  return ReactSharedInternals.H.useTransition();
467
467
  };
468
- exports.version = "19.3.0";
468
+ exports.version = "19.3.1";
469
469
  }
470
470
  });
471
471
 
@@ -636,7 +636,7 @@
636
636
  exports.useFormStatus = function() {
637
637
  return ReactSharedInternals.H.useHostTransitionStatus();
638
638
  };
639
- exports.version = "19.3.0";
639
+ exports.version = "19.3.1";
640
640
  }
641
641
  });
642
642
 
@@ -514,12 +514,12 @@
514
514
  }
515
515
  };
516
516
  var isomorphicReactPackageVersion$jscomp$inline_2043 = React36.version;
517
- if (isomorphicReactPackageVersion$jscomp$inline_2043 !== "19.3.0")
517
+ if (isomorphicReactPackageVersion$jscomp$inline_2043 !== "19.3.1")
518
518
  throw Error(
519
519
  formatProdErrorMessage(
520
520
  527,
521
521
  isomorphicReactPackageVersion$jscomp$inline_2043,
522
- "19.3.0"
522
+ "19.3.1"
523
523
  )
524
524
  );
525
525
  ReactDOMSharedInternals.findDOMNode = function(componentOrElement) {
@@ -530,10 +530,10 @@
530
530
  };
531
531
  var internals$jscomp$inline_2586 = {
532
532
  bundleType: 0,
533
- version: "19.3.0",
533
+ version: "19.3.1",
534
534
  rendererPackageName: "react-dom",
535
535
  currentDispatcherRef: ReactSharedInternals,
536
- reconcilerVersion: "19.3.0"
536
+ reconcilerVersion: "19.3.1"
537
537
  };
538
538
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ < "u" && (hook$jscomp$inline_2587 = __REACT_DEVTOOLS_GLOBAL_HOOK__, !hook$jscomp$inline_2587.isDisabled && hook$jscomp$inline_2587.supportsFiber))
539
539
  try {
@@ -579,4 +579,4 @@
579
579
  defaultOnDefaultTransitionIndicator
580
580
  ), initialChildren.context = getContextForSubtree(null), options3 = initialChildren.current, isStrictMode = requestUpdateLane(), isStrictMode = getBumpedLaneForHydrationByLane(isStrictMode), identifierPrefix = createUpdate(isStrictMode), identifierPrefix.callback = null, enqueueUpdate(options3, identifierPrefix, isStrictMode), options3 = isStrictMode, initialChildren.current.lanes = options3, markRootUpdated$1(initialChildren, options3), ensureRootIsScheduled(initialChildren), container[internalContainerInstanceKey] = initialChildren.current, listenToAllSupportedEvents(container), new ReactDOMHydrationRoot(initialChildren);
581
581
  };
582
- exports.version = "19.3.0";
582
+ exports.version = "19.3.1";
@@ -154,7 +154,7 @@
154
154
  }
155
155
  }
156
156
  }
157
- }), DESIGN_DOCUMENT_SCHEMA = freeze({
157
+ }), DESIGN_DOCUMENT_V120_SCHEMA = freeze({
158
158
  ...DESIGN_DOCUMENT_V1_SCHEMA,
159
159
  $id: "https://openplanr.dev/schemas/v1.20.0/design-document.schema.json",
160
160
  "x-openplanr-contract": { id: "design-document", version: "1.20.0" },
@@ -212,4 +212,74 @@
212
212
  DESIGN_DOCUMENT_V1_SCHEMA.$defs,
213
213
  coordinate: { type: "number", minimum: -1e7, maximum: 1e7 }
214
214
  }
215
- });
215
+ }), PROP_TOKEN_SCHEMA = {
216
+ type: "string",
217
+ minLength: 1,
218
+ maxLength: 128,
219
+ pattern: "^[a-z][a-z0-9-]*(?![\\s\\S])"
220
+ }, propTokenPattern = new RegExp(PROP_TOKEN_SCHEMA.pattern, "u");
221
+ var currentDocument = (
222
+ /** @type {{ properties: Record<string, unknown>; [key: string]: unknown }} */
223
+ structuredClone(DESIGN_DOCUMENT_V120_SCHEMA)
224
+ );
225
+ currentDocument.$id = "https://openplanr.dev/schemas/v1.22.0/design-document.schema.json";
226
+ currentDocument["x-openplanr-contract"] = { id: "design-document", version: "1.22.0" };
227
+ currentDocument.properties.schemaVersion = { enum: ["1.0.0", "1.1.0"] };
228
+ var screenSchema = (
229
+ /** @type {{ items: { properties: Record<string, unknown> } }} */
230
+ currentDocument.properties.screens
231
+ );
232
+ screenSchema.items.properties.props = {
233
+ type: "object",
234
+ propertyNames: PROP_TOKEN_SCHEMA,
235
+ additionalProperties: {
236
+ oneOf: [
237
+ {
238
+ type: "object",
239
+ additionalProperties: !1,
240
+ required: ["type", "options", "default"],
241
+ properties: {
242
+ type: { const: "enum" },
243
+ options: {
244
+ type: "array",
245
+ minItems: 1,
246
+ uniqueItems: !0,
247
+ items: PROP_TOKEN_SCHEMA
248
+ },
249
+ default: PROP_TOKEN_SCHEMA
250
+ }
251
+ },
252
+ {
253
+ type: "object",
254
+ additionalProperties: !1,
255
+ required: ["type", "default"],
256
+ properties: { type: { const: "boolean" }, default: { type: "boolean" } }
257
+ }
258
+ ]
259
+ }
260
+ };
261
+ var variantSchema = (
262
+ /** @type {{ items: { properties: Record<string, unknown> } }} */
263
+ currentDocument.properties.variants
264
+ );
265
+ variantSchema.items.properties.props = {
266
+ type: "object",
267
+ propertyNames: { $ref: "#/$defs/id" },
268
+ additionalProperties: {
269
+ type: "object",
270
+ propertyNames: PROP_TOKEN_SCHEMA,
271
+ additionalProperties: { anyOf: [PROP_TOKEN_SCHEMA, { type: "boolean" }] }
272
+ }
273
+ };
274
+ currentDocument.allOf = [
275
+ {
276
+ if: { properties: { schemaVersion: { const: "1.1.0" } }, required: ["schemaVersion"] },
277
+ else: {
278
+ properties: {
279
+ screens: { items: { not: { required: ["props"] } } },
280
+ variants: { items: { not: { required: ["props"] } } }
281
+ }
282
+ }
283
+ }
284
+ ];
285
+ var DESIGN_DOCUMENT_SCHEMA = freeze(currentDocument);
@@ -1863,7 +1863,14 @@ ${fence}`;
1863
1863
  { class: "design-minimap-close", "aria-label": "Close minimap" }
1864
1864
  );
1865
1865
  map.append(svg, close), q(".planr-stage").append(map);
1866
- let scroll = q(".planr-stage-scroll"), geometry = null, scheduled = !1, mapBoards = /* @__PURE__ */ new Map(), viewportRect = document.createElementNS(svg.namespaceURI, "rect");
1866
+ let scroll = q(".planr-stage-scroll"), scrollSize = null, sizeObserver = typeof ResizeObserver == "function" ? new ResizeObserver(() => {
1867
+ scrollSize = null;
1868
+ }) : null;
1869
+ sizeObserver?.observe(scroll), destroyers.push(() => sizeObserver?.disconnect());
1870
+ let stageSize = () => {
1871
+ let size4 = scrollSize ?? { width: scroll.clientWidth, height: scroll.clientHeight };
1872
+ return sizeObserver && (scrollSize = size4), size4;
1873
+ }, geometry = null, scheduled = !1, mapBoards = /* @__PURE__ */ new Map(), viewportRect = document.createElementNS(svg.namespaceURI, "rect");
1867
1874
  viewportRect.setAttribute("class", "design-minimap-viewport"), viewportRect.setAttribute("pointer-events", "none"), svg.append(viewportRect);
1868
1875
  let attribute = (element, name, value) => {
1869
1876
  element.getAttribute(name) !== String(value) && element.setAttribute(name, String(value));
@@ -1885,11 +1892,11 @@ ${fence}`;
1885
1892
  };
1886
1893
  });
1887
1894
  if (!boards.length) return;
1888
- let viewport = {
1895
+ let { width: stageWidth, height: stageHeight } = stageSize(), viewport = {
1889
1896
  x: -current.camera.x / current.zoom,
1890
1897
  y: -current.camera.y / current.zoom,
1891
- width: scroll.clientWidth / current.zoom,
1892
- height: scroll.clientHeight / current.zoom
1898
+ width: stageWidth / current.zoom,
1899
+ height: stageHeight / current.zoom
1893
1900
  }, minX = Math.min(...boards.map((item) => item.x)), minY = Math.min(...boards.map((item) => item.y)), width = Math.max(...boards.map((item) => item.x + item.width)) - minX, height = Math.max(...boards.map((item) => item.y + item.height)) - minY, scale = Math.min(184 / Math.max(1, width), 112 / Math.max(1, height)), offsetX = (200 - width * scale) / 2, offsetY = (128 - height * scale) / 2;
1894
1901
  geometry = { minX, minY, scale, viewport, offsetX, offsetY };
1895
1902
  let place = (element, box) => {
@@ -1929,10 +1936,10 @@ ${fence}`;
1929
1936
  on(root, "planr:design-render", schedule), on(root, "planr:design-camera", schedule), on(window, "resize", schedule);
1930
1937
  let dragging = !1, move = (event) => {
1931
1938
  if (!geometry) return;
1932
- let bounds = svg.getBoundingClientRect(), x = (event.clientX - bounds.left) * 200 / bounds.width, y = (event.clientY - bounds.top) * 128 / bounds.height, worldX = geometry.minX + (x - geometry.offsetX) / geometry.scale, worldY = geometry.minY + (y - geometry.offsetY) / geometry.scale;
1939
+ let bounds = svg.getBoundingClientRect(), x = (event.clientX - bounds.left) * 200 / bounds.width, y = (event.clientY - bounds.top) * 128 / bounds.height, worldX = geometry.minX + (x - geometry.offsetX) / geometry.scale, worldY = geometry.minY + (y - geometry.offsetY) / geometry.scale, { width, height } = stageSize();
1933
1940
  studio.setCamera({
1934
- x: scroll.clientWidth / 2 - worldX * state().zoom,
1935
- y: scroll.clientHeight / 2 - worldY * state().zoom
1941
+ x: width / 2 - worldX * state().zoom,
1942
+ y: height / 2 - worldY * state().zoom
1936
1943
  });
1937
1944
  };
1938
1945
  on(svg, "pointerdown", (event) => {
@@ -142,7 +142,7 @@
142
142
  function createCulling(options2 = {}) {
143
143
  let marginFactor = options2.marginFactor ?? 2, chunkSize = options2.chunkSize ?? 200;
144
144
  positive("culling.marginFactor", marginFactor), marginFactor < 1 && invalid("culling.marginFactor", marginFactor), positive("culling.chunkSize", chunkSize);
145
- let grid = createSpatialGrid(options2.cellSize), nodes = /* @__PURE__ */ new Map(), sources = /* @__PURE__ */ new Map(), mounted = /* @__PURE__ */ new Set(), moved = /* @__PURE__ */ new Set(), region, dirty = !0, pinsDirty = !1, desired = /* @__PURE__ */ new Set(), queue = [], frozenUntil = -1 / 0, optionalMounts = !0;
145
+ let grid = createSpatialGrid(options2.cellSize), nodes = /* @__PURE__ */ new Map(), sources = /* @__PURE__ */ new Map(), mounted = /* @__PURE__ */ new Set(), moved = /* @__PURE__ */ new Set(), region, dirty = !0, pinsDirty = !1, desired = /* @__PURE__ */ new Set(), queue = [], queueStale = !1, frozenUntil = -1 / 0, optionalMounts = !0;
146
146
  function getPinnedIds() {
147
147
  let pins = /* @__PURE__ */ new Set();
148
148
  for (let ids of sources.values())
@@ -167,35 +167,45 @@
167
167
  let outside = !region || viewport.x < region.x || viewport.y < region.y || viewport.x + viewport.width > region.x + region.width || viewport.y + viewport.height > region.y + region.height, reevaluate = dirty || outside || zoomChanged || optionalMounts !== admitOptional;
168
168
  optionalMounts = admitOptional;
169
169
  let pins = getPinnedIds();
170
- if (reevaluate && (region = {
170
+ reevaluate && (region = {
171
171
  x: viewport.x - viewport.width * (marginFactor - 1) / 2,
172
172
  y: viewport.y - viewport.height * (marginFactor - 1) / 2,
173
173
  width: viewport.width * marginFactor,
174
174
  height: viewport.height * marginFactor
175
- }, desired = admitOptional ? grid.query(region) : /* @__PURE__ */ new Set()), reevaluate || pinsDirty) {
176
- let centerX = viewport.x + viewport.width / 2, centerY = viewport.y + viewport.height / 2, distance = (id) => {
177
- let node = nodes.get(id);
178
- return node ? (node.bounds.x + node.bounds.width / 2 - centerX) ** 2 + (node.bounds.y + node.bounds.height / 2 - centerY) ** 2 : 1 / 0;
179
- };
180
- queue = [...desired].filter((id) => !mounted.has(id) && !pins.has(id)).sort((left, right) => distance(left) - distance(right) || left.localeCompare(right));
181
- }
175
+ }, desired = admitOptional ? grid.query(region) : /* @__PURE__ */ new Set()), (reevaluate || pinsDirty) && (queueStale = !0);
182
176
  let admitted = [], removed = [];
183
177
  for (let id of mounted)
184
178
  (!nodes.has(id) || !pins.has(id) && !desired.has(id)) && (mounted.delete(id), removed.push(id));
185
179
  for (let id of pins)
186
180
  mounted.has(id) || (mounted.add(id), admitted.push(id));
187
181
  let frozen = now < frozenUntil;
182
+ if (queueStale && !frozen) {
183
+ let centerX = viewport.x + viewport.width / 2, centerY = viewport.y + viewport.height / 2, distance = (id) => {
184
+ let node = nodes.get(id);
185
+ return node ? (node.bounds.x + node.bounds.width / 2 - centerX) ** 2 + (node.bounds.y + node.bounds.height / 2 - centerY) ** 2 : 1 / 0;
186
+ };
187
+ queue = [...desired].filter((id) => !mounted.has(id) && !pins.has(id)).sort((left, right) => distance(left) - distance(right) || left.localeCompare(right)), queueStale = !1;
188
+ }
188
189
  if (!frozen && (!gesture || reevaluate)) {
189
190
  let batch = queue.splice(0, chunkSize);
190
191
  for (let id of batch)
191
192
  mounted.add(id), admitted.push(id);
192
193
  }
194
+ let waiting = queue.length > 0;
195
+ if (queueStale) {
196
+ waiting = !1;
197
+ for (let id of desired)
198
+ if (!mounted.has(id) && !pins.has(id)) {
199
+ waiting = !0;
200
+ break;
201
+ }
202
+ }
193
203
  let geometry = [...moved];
194
204
  return moved.clear(), dirty = !1, pinsDirty = !1, {
195
205
  ...admitted.length || removed.length ? { mount: { mounted: admitted, unmounted: removed } } : {},
196
206
  geometry,
197
- pending: queue.length > 0 && !gesture && !frozen,
198
- ...queue.length && frozen ? { resumeAt: frozenUntil } : {}
207
+ pending: waiting && !gesture && !frozen,
208
+ ...waiting && frozen ? { resumeAt: frozenUntil } : {}
199
209
  };
200
210
  }
201
211
  return {
@@ -220,7 +230,7 @@
220
230
  },
221
231
  getRegion: () => region,
222
232
  reset() {
223
- mounted.clear(), moved.clear(), region = void 0, desired.clear(), queue = [], frozenUntil = -1 / 0, dirty = !0;
233
+ mounted.clear(), moved.clear(), region = void 0, desired.clear(), queue = [], queueStale = !1, frozenUntil = -1 / 0, dirty = !0;
224
234
  }
225
235
  };
226
236
  }
@@ -233,7 +243,7 @@
233
243
  return { x: left, y: top, width: right - left, height: bottom - top };
234
244
  }
235
245
  function buildEdgeRoutes(nodes, edges, region, strict = !1) {
236
- let byId = new Map(Array.from(nodes, (node) => [node.id, node])), grouped = /* @__PURE__ */ new Map(), diagnostics = [], drawnBounds = [], ids = /* @__PURE__ */ new Set();
246
+ let byId = new Map(edges.length ? Array.from(nodes, (node) => [node.id, node]) : []), grouped = /* @__PURE__ */ new Map(), diagnostics = [], drawnBounds = [], ids = /* @__PURE__ */ new Set();
237
247
  for (let edge of edges) {
238
248
  (!edge || typeof edge != "object") && invalid("edge", edge);
239
249
  for (let field of ["id", "from", "to", "style"])
@@ -653,15 +663,25 @@
653
663
  function listen(target, type, listener, options2) {
654
664
  target.addEventListener(type, listener, options2), removers.push(() => target.removeEventListener(type, listener, options2));
655
665
  }
666
+ let rect2 = null, lastWheel = -1 / 0;
667
+ function stageRect() {
668
+ return rect2 ??= stage.getBoundingClientRect(), rect2;
669
+ }
670
+ let invalidate = () => {
671
+ rect2 = null;
672
+ }, observer = view?.ResizeObserver ? new view.ResizeObserver(invalidate) : void 0;
673
+ observer?.observe(stage), removers.push(() => observer?.disconnect()), view && (listen(view, "resize", invalidate), listen(document2, "scroll", invalidate, { capture: !0, passive: !0 }));
656
674
  function local(point2) {
657
- let rect2 = stage.getBoundingClientRect();
658
- return { x: point2.x - rect2.left, y: point2.y - rect2.top };
675
+ let { left, top } = stageRect();
676
+ return { x: point2.x - left, y: point2.y - top };
659
677
  }
660
678
  listen(
661
679
  stage,
662
680
  "wheel",
663
681
  (raw) => {
664
- let event = raw, delta = normalizeWheel(event, stage.getBoundingClientRect().height);
682
+ let event = raw;
683
+ event.timeStamp - lastWheel > 150 && invalidate(), lastWheel = event.timeStamp;
684
+ let delta = normalizeWheel(event, stageRect().height);
665
685
  event.preventDefault(), event.ctrlKey || event.metaKey ? controller.zoomAt(
666
686
  Math.min(
667
687
  1.25,
@@ -694,7 +714,7 @@
694
714
  let interactive = target && "closest" in target && typeof target.closest == "function" && target.closest('button, a, [role="button"]');
695
715
  if (touch && interactive && !interactive.hasAttribute("data-canvas-node-id")) return;
696
716
  let occupied = interactive || target && "closest" in target && typeof target.closest == "function" && target.closest("[data-canvas-node-id]"), pan = event.button === 1 || space || event.button === 0 && getPointerMode() === "pan" && !occupied;
697
- !touch && !pan || (pointers.set(event.pointerId, { x: event.clientX, y: event.clientY, touch }), setGesture(!0), stage.setPointerCapture && stage.setPointerCapture(event.pointerId), (touch || pan) && (stage.focus({ preventScroll: !0 }), event.preventDefault()));
717
+ !touch && !pan || (invalidate(), pointers.set(event.pointerId, { x: event.clientX, y: event.clientY, touch }), setGesture(!0), stage.setPointerCapture && stage.setPointerCapture(event.pointerId), (touch || pan) && (stage.focus({ preventScroll: !0 }), event.preventDefault()));
698
718
  }), listen(stage, "pointermove", (raw) => {
699
719
  let event = raw, previous = pointers.get(event.pointerId);
700
720
  if (!previous) return;
@@ -724,7 +744,7 @@
724
744
  stage,
725
745
  "gesturestart",
726
746
  (event) => {
727
- gestureScale = 1, setGesture(!0), event.preventDefault();
747
+ gestureScale = 1, invalidate(), setGesture(!0), event.preventDefault();
728
748
  },
729
749
  { passive: !1 }
730
750
  ), listen(
@@ -1044,7 +1064,7 @@
1044
1064
  function object(field, value) {
1045
1065
  (!value || typeof value != "object" || Array.isArray(value)) && invalid(field, value);
1046
1066
  }
1047
- var CAMERA_MOVE_MS = 200;
1067
+ var CAMERA_MOVE_MS = 200, DEMOTE_DELAY_MS = 300;
1048
1068
  function createCanvas(options2) {
1049
1069
  object("options", options2), options2.culling !== void 0 && object("culling", options2.culling), options2.zoom !== void 0 && object("zoom", options2.zoom), options2.keyboard !== void 0 && object("keyboard", options2.keyboard), options2.worldBounds !== void 0 && object("worldBounds", options2.worldBounds), (typeof options2.label != "string" || !options2.label.trim()) && invalid("label", options2.label), options2.breakpoints !== void 0 && !Array.isArray(options2.breakpoints) && invalid("breakpoints", options2.breakpoints);
1050
1070
  let breakpoints = (options2.breakpoints ?? []).map((entry, index2) => (object(`breakpoints[${index2}]`, entry), (typeof entry.name != "string" || !entry.name.trim()) && invalid(`breakpoints[${index2}].name`, entry.name), nonnegative(`breakpoints[${index2}].minWidth`, entry.minWidth), { ...entry })).sort((a, b) => a.minWidth - b.minWidth);
@@ -1063,7 +1083,7 @@
1063
1083
  options2[field] !== void 0 && typeof options2[field] != "function" && invalid(field, options2[field]);
1064
1084
  let pointerMode = options2.pointerMode === void 0 ? "pan" : options2.pointerMode;
1065
1085
  validatePointerMode(pointerMode), options2.worldBounds && (rect("worldBounds.rect", options2.worldBounds.rect), nonnegative("worldBounds.padding", options2.worldBounds.padding));
1066
- let worldBounds = options2.worldBounds ? { rect: { ...options2.worldBounds.rect }, padding: options2.worldBounds.padding } : void 0, camera = { x: 0, y: 0, zoom: Math.max(min2, Math.min(max2, 1)) }, nodes = /* @__PURE__ */ new Map(), outline = [], roving, announcer, announceZoom = !1, overviewNodes = [], level = lod.update(camera.zoom), overviewLayer, overviewCanvas, ownsOverview = !1, writeFrame = 0, cameraWriteFrame = 0, detailDirty = !0, visibility = /* @__PURE__ */ new Map(), restoreOverview, selection = [], edges = [], diagnostics = [], breakpoint = null, focused = null, registered = /* @__PURE__ */ new Map(), inputGesture = !1, zoomChanged = !1, zooming = !1, zoomIdleTimer, edgesDirty = !0, loaderDirty = !0, lastRegion, resumeTimer, loader, edgeLayer, activeFrame = null, destroyed = !1, detaching = !1, stageSize = { width: 0, height: 0 }, chrome = /* @__PURE__ */ new Map(), safeArea = computeSafeArea(stageSize, chrome.values()), composing = !1, elements, view, frameId, idleTimer, isMoving = !1, consumedKeys = /* @__PURE__ */ new WeakSet(), dirty = !1, cameraEvent = !1, activeFrameEvent = !1, animation, input, frames, restore, listeners = {
1086
+ let worldBounds = options2.worldBounds ? { rect: { ...options2.worldBounds.rect }, padding: options2.worldBounds.padding } : void 0, camera = { x: 0, y: 0, zoom: Math.max(min2, Math.min(max2, 1)) }, nodes = /* @__PURE__ */ new Map(), outline = [], roving, announcer, announceZoom = !1, overviewNodes = [], level = lod.update(camera.zoom), overviewLayer, overviewCanvas, ownsOverview = !1, writeFrame = 0, cameraWriteFrame = 0, detailDirty = !0, visibility = /* @__PURE__ */ new Map(), restoreOverview, selection = [], edges = [], diagnostics = [], breakpoint = null, focused = null, registered = /* @__PURE__ */ new Map(), inputGesture = !1, zoomChanged = !1, zooming = !1, zoomIdleTimer, edgesDirty = !0, loaderDirty = !0, lastRegion, resumeTimer, loader, edgeLayer, activeFrame = null, destroyed = !1, detaching = !1, stageSize = { width: 0, height: 0 }, chrome = /* @__PURE__ */ new Map(), safeArea = computeSafeArea(stageSize, chrome.values()), composing = !1, elements, view, frameId, idleTimer, demoteTimer, promotedZoom = null, rasterZoom = Number.NaN, demoteDue = !1, isMoving = !1, motionEvent = !1, consumedKeys = /* @__PURE__ */ new WeakSet(), dirty = !1, cameraEvent = !1, activeFrameEvent = !1, animation, input, frames, restore, listeners = {
1067
1087
  camera: /* @__PURE__ */ new Set(),
1068
1088
  "active-frame": /* @__PURE__ */ new Set(),
1069
1089
  mount: /* @__PURE__ */ new Set(),
@@ -1073,7 +1093,8 @@
1073
1093
  focus: /* @__PURE__ */ new Set(),
1074
1094
  breakpoint: /* @__PURE__ */ new Set(),
1075
1095
  "safe-area": /* @__PURE__ */ new Set(),
1076
- diagnostics: /* @__PURE__ */ new Set()
1096
+ diagnostics: /* @__PURE__ */ new Set(),
1097
+ motion: /* @__PURE__ */ new Set()
1077
1098
  }, queued = [];
1078
1099
  function emit(event, payload) {
1079
1100
  let callbacks = listeners[event];
@@ -1226,21 +1247,36 @@
1226
1247
  function schedule() {
1227
1248
  view && !detaching && frameId === void 0 && (frameId = view.requestAnimationFrame(write));
1228
1249
  }
1229
- function moving() {
1250
+ function promote() {
1230
1251
  if (view) {
1231
- if (!isMoving) {
1232
- for (let layer of layers())
1233
- layer.style.willChange !== "transform" && (layer.style.willChange = "transform");
1234
- frames?.setMoving(!0), loader?.setMoving(!0);
1252
+ if (isMoving || inputGesture) {
1253
+ if (demoteTimer !== void 0 && view.clearTimeout(demoteTimer), demoteTimer = void 0, demoteDue = !1, promotedZoom === null) {
1254
+ promotedZoom = rasterZoom;
1255
+ for (let layer of layers()) layer.style.willChange = "transform";
1256
+ }
1257
+ return;
1258
+ }
1259
+ if (promotedZoom === null) {
1260
+ rasterZoom = camera.zoom;
1261
+ return;
1262
+ }
1263
+ if (promotedZoom !== camera.zoom) {
1264
+ if (demoteDue) {
1265
+ demoteDue = !1, promotedZoom = null, rasterZoom = camera.zoom;
1266
+ for (let layer of layers()) layer.style.removeProperty("will-change");
1267
+ return;
1268
+ }
1269
+ demoteTimer ??= view.setTimeout(() => {
1270
+ demoteTimer = void 0, demoteDue = !0, schedule();
1271
+ }, DEMOTE_DELAY_MS);
1235
1272
  }
1236
- isMoving = !0, idleTimer !== void 0 && view.clearTimeout(idleTimer), idleTimer = view.setTimeout(() => {
1237
- idleTimer = void 0;
1238
- for (let layer of layers())
1239
- layer.style.willChange && layer.style.removeProperty("will-change");
1240
- isMoving = !1, frames?.setMoving(inputGesture), loader?.setMoving(inputGesture), schedule();
1241
- }, 150);
1242
1273
  }
1243
1274
  }
1275
+ function moving() {
1276
+ view && (isMoving || (frames?.setMoving(!0), loader?.setMoving(!0)), isMoving = !0, idleTimer !== void 0 && view.clearTimeout(idleTimer), idleTimer = view.setTimeout(() => {
1277
+ idleTimer = void 0, isMoving = !1, frames?.setMoving(inputGesture), loader?.setMoving(inputGesture), schedule();
1278
+ }, 150));
1279
+ }
1244
1280
  function change(value) {
1245
1281
  let next = clamp2(value), changed = next.x !== camera.x || next.y !== camera.y || next.zoom !== camera.zoom, changedZoom = next.zoom !== camera.zoom;
1246
1282
  zoomChanged ||= changedZoom, changedZoom && view && (zooming = !0, zoomIdleTimer !== void 0 && view.clearTimeout(zoomIdleTimer), zoomIdleTimer = view.setTimeout(() => {
@@ -1277,6 +1313,7 @@
1277
1313
  }
1278
1314
  wroteCamera && (cameraWriteFrame = writeFrame), activeFrame !== null && frames?.updatePosition();
1279
1315
  }
1316
+ promote();
1280
1317
  let requestedLevel = lod.update(camera.zoom), overviewReady = requestedLevel === "overview" || level === "overview" ? drawOverview() : !1, update = culling.update(
1281
1318
  viewport(),
1282
1319
  time,
@@ -1301,7 +1338,7 @@
1301
1338
  let events = queued;
1302
1339
  queued = [];
1303
1340
  let notifyCamera = cameraEvent, notifyFrame = activeFrameEvent, framePayload = activeFrame, cameraPayload = { ...camera };
1304
- cameraEvent = !1, activeFrameEvent = !1, notifyCamera && emit("camera", cameraPayload), notifyFrame && emit("active-frame", framePayload), levelChanged && emit("level", level);
1341
+ cameraEvent = !1, activeFrameEvent = !1, notifyCamera && emit("camera", cameraPayload), notifyFrame && emit("active-frame", framePayload), levelChanged && emit("level", level), motionEvent !== (isMoving || inputGesture) && (motionEvent = !motionEvent, emit("motion", motionEvent));
1305
1342
  for (let event of events) event();
1306
1343
  update.geometry.length && emit("geometry", new Set(update.geometry)), update.mount ? (loader?.refresh(), detailDirty = !0, emit("mount", new Set(culling.getMountedIds())), loader?.refresh()) : (update.geometry.length || loaderDirty) && loader?.refresh(), loaderDirty = !1, detailDirty && updateVisibility(levelChanged), level === "overview" && overviewLayer?.present(), announceZoom && !animation && (announceZoom = !1, announcer?.say(`Zoom ${Math.round(camera.zoom * 100)}%`)), (roving?.update(!animation) || animation || update.pending) && schedule(), resumeTimer !== void 0 && view?.clearTimeout(resumeTimer), resumeTimer = void 0, update.resumeAt !== void 0 && view && (resumeTimer = view.setTimeout(
1307
1344
  () => {
@@ -1323,7 +1360,7 @@
1323
1360
  }
1324
1361
  function detach() {
1325
1362
  if (alive(), !!elements) {
1326
- detaching = !0, frameId !== void 0 && view?.cancelAnimationFrame(frameId), idleTimer !== void 0 && view?.clearTimeout(idleTimer), resumeTimer !== void 0 && view?.clearTimeout(resumeTimer), zoomIdleTimer !== void 0 && view?.clearTimeout(zoomIdleTimer), zoomIdleTimer = void 0, zooming = !1, resumeTimer = void 0, frameId = void 0, idleTimer = void 0, isMoving = !1, composing = !1, animation = void 0, roving?.dispose(), roving = void 0, announcer?.dispose(), announcer = void 0, announceZoom = !1, input?.dispose(), loader?.dispose(), edgeLayer?.dispose(), overviewLayer?.dispose(), ownsOverview && overviewCanvas?.remove(), restoreOverview?.();
1363
+ detaching = !0, frameId !== void 0 && view?.cancelAnimationFrame(frameId), idleTimer !== void 0 && view?.clearTimeout(idleTimer), demoteTimer !== void 0 && view?.clearTimeout(demoteTimer), demoteTimer = void 0, demoteDue = !1, promotedZoom = null, rasterZoom = Number.NaN, motionEvent = !1, resumeTimer !== void 0 && view?.clearTimeout(resumeTimer), zoomIdleTimer !== void 0 && view?.clearTimeout(zoomIdleTimer), zoomIdleTimer = void 0, zooming = !1, resumeTimer = void 0, frameId = void 0, idleTimer = void 0, isMoving = !1, composing = !1, animation = void 0, roving?.dispose(), roving = void 0, announcer?.dispose(), announcer = void 0, announceZoom = !1, input?.dispose(), loader?.dispose(), edgeLayer?.dispose(), overviewLayer?.dispose(), ownsOverview && overviewCanvas?.remove(), restoreOverview?.();
1327
1364
  for (let [element, original] of visibility) {
1328
1365
  let realm = elements.stage.ownerDocument.defaultView;
1329
1366
  realm && (element instanceof realm.HTMLElement || element instanceof realm.SVGElement) && (element.style.visibility = original);