@salsita-ai/sdk 0.50.0-develop.f101f4c3c9 → 0.50.0-develop.f354d3576d

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 (1542) hide show
  1. package/README.md +8 -2
  2. package/dist/admin/AdminShell.js +1 -1
  3. package/dist/admin/common/admin-interface.d.ts +1 -1
  4. package/dist/admin/legacy-admin/Application.js +1 -1
  5. package/dist/application/index.d.ts +1 -0
  6. package/dist/application/index.js +1 -1
  7. package/dist/application/mount-application.d.ts +1 -1
  8. package/dist/application/mount-application.js +1 -1
  9. package/dist/application/mount-configurator.d.ts +19 -0
  10. package/dist/application/mount-configurator.js +1 -0
  11. package/dist/application/mounted-application-runtime.d.ts +4 -0
  12. package/dist/application/mounted-application-runtime.js +1 -0
  13. package/dist/application/register-web-component.d.ts +2 -0
  14. package/dist/application/register-web-component.js +1 -0
  15. package/dist/application-spec/caching/index.d.ts +6 -1
  16. package/dist/application-spec/caching/index.js +1 -1
  17. package/dist/application-spec/core/enhanced-json-value.d.ts +2 -31
  18. package/dist/application-spec/core/enhanced-json-value.js +1 -1
  19. package/dist/application-spec/core/index.d.ts +1 -3
  20. package/dist/application-spec/core/index.js +1 -1
  21. package/dist/application-spec/core/json-schema.d.ts +2 -52
  22. package/dist/application-spec/core/markers/index.d.ts +1 -1
  23. package/dist/application-spec/core/markers/index.js +1 -1
  24. package/dist/application-spec/core/markers/msg-marker.d.ts +2 -28
  25. package/dist/application-spec/core/markers/msg-marker.js +1 -1
  26. package/dist/application-spec/core/markers/raw-eval-write-marker.d.ts +1 -1
  27. package/dist/application-spec/core/markers/raw-eval-write-marker.js +1 -1
  28. package/dist/application-spec/core/markers/raw-read-write-marker.js +1 -1
  29. package/dist/application-spec/errors/diagnostic-codes.d.ts +18 -1
  30. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  31. package/dist/application-spec/errors/diagnostic-messages.d.ts +26 -2
  32. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  33. package/dist/application-spec/generate-application/code/domain-runtime-files.d.ts +0 -19
  34. package/dist/application-spec/generate-application/code/domain-runtime-files.js +1 -1
  35. package/dist/application-spec/generate-application/code/project-scaffolding.js +2 -2
  36. package/dist/application-spec/generate-application/code/templates/application-types.js +6 -6
  37. package/dist/application-spec/generate-application/code/templates/common/doc-comment.d.ts +2 -0
  38. package/dist/application-spec/generate-application/code/templates/common/doc-comment.js +1 -0
  39. package/dist/application-spec/generate-application/code/templates/configurator-globals.d.ts +2 -1
  40. package/dist/application-spec/generate-application/code/templates/configurator-globals.js +19 -6
  41. package/dist/application-spec/generate-application/code/templates/gitignore.js +2 -1
  42. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.js +7 -7
  43. package/dist/application-spec/generate-application/code/templates/global-definition/generate-assistant-form-element-types.d.ts +12 -0
  44. package/dist/application-spec/generate-application/code/templates/global-definition/generate-assistant-form-element-types.js +7 -0
  45. package/dist/application-spec/generate-application/code/templates/global-definition/generate-phx-types.js +24 -22
  46. package/dist/application-spec/generate-application/code/templates/global-definition/index.d.ts +1 -0
  47. package/dist/application-spec/generate-application/code/templates/global-definition/index.js +1 -1
  48. package/dist/application-spec/generate-application/code/templates/index.d.ts +2 -6
  49. package/dist/application-spec/generate-application/code/templates/index.js +1 -1
  50. package/dist/application-spec/generate-application/code/templates/lingui-rc.js +5 -4
  51. package/dist/application-spec/generate-application/code/templates/skills/core/cli.d.ts +2 -0
  52. package/dist/application-spec/generate-application/code/templates/skills/core/cli.js +1 -0
  53. package/dist/application-spec/generate-application/code/templates/skills/core/index.d.ts +3 -0
  54. package/dist/application-spec/generate-application/code/templates/skills/core/index.js +1 -0
  55. package/dist/application-spec/generate-application/code/templates/skills/core/sdk.d.ts +2 -0
  56. package/dist/application-spec/generate-application/code/templates/skills/core/sdk.js +118 -0
  57. package/dist/application-spec/generate-application/code/templates/skills/core/workflow.d.ts +2 -0
  58. package/dist/application-spec/generate-application/code/templates/skills/core/workflow.js +44 -0
  59. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/application-states.d.ts +3 -0
  60. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/application-states.js +3 -0
  61. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/index.d.ts +1 -0
  62. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/index.js +1 -0
  63. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/navigation.d.ts +3 -0
  64. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/navigation.js +48 -0
  65. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/presets.d.ts +3 -0
  66. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/presets.js +38 -0
  67. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/selection.d.ts +3 -0
  68. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/selection.js +35 -0
  69. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/views-and-tools.d.ts +3 -0
  70. package/dist/application-spec/generate-application/code/templates/skills/features/application-states/views-and-tools.js +61 -0
  71. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/custom-layout.d.ts +3 -0
  72. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/custom-layout.js +7 -0
  73. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/finalization-actions.d.ts +3 -0
  74. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/finalization-actions.js +79 -0
  75. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/index.d.ts +1 -0
  76. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/index.js +1 -0
  77. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/messages.d.ts +3 -0
  78. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/messages.js +52 -0
  79. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/pages.d.ts +3 -0
  80. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/pages.js +49 -0
  81. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/scene-and-safe-area.d.ts +3 -0
  82. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/scene-and-safe-area.js +62 -0
  83. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/slots.d.ts +3 -0
  84. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/slots.js +40 -0
  85. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/tabs-and-steps.d.ts +3 -0
  86. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/tabs-and-steps.js +65 -0
  87. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/toolbar-actions.d.ts +3 -0
  88. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/toolbar-actions.js +58 -0
  89. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/view-mode.d.ts +3 -0
  90. package/dist/application-spec/generate-application/code/templates/skills/features/custom-layout/view-mode.js +41 -0
  91. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/control-components.d.ts +3 -0
  92. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/control-components.js +24 -0
  93. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/control-hooks.d.ts +3 -0
  94. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/control-hooks.js +44 -0
  95. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/custom-controls.d.ts +3 -0
  96. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/custom-controls.js +74 -0
  97. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/domain-controls.d.ts +3 -0
  98. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/domain-controls.js +8 -0
  99. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/index.d.ts +1 -0
  100. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/index.js +1 -0
  101. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/scene-controls.d.ts +3 -0
  102. package/dist/application-spec/generate-application/code/templates/skills/features/domain-controls/scene-controls.js +48 -0
  103. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/actions.d.ts +3 -0
  104. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/actions.js +64 -0
  105. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/components.d.ts +3 -0
  106. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/components.js +62 -0
  107. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/domain-model.d.ts +3 -0
  108. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/domain-model.js +1 -0
  109. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/entities-and-relations.d.ts +3 -0
  110. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/entities-and-relations.js +59 -0
  111. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/expressions.d.ts +3 -0
  112. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/expressions.js +46 -0
  113. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/index.d.ts +1 -0
  114. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/index.js +1 -0
  115. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/transformers.d.ts +3 -0
  116. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/transformers.js +43 -0
  117. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/validation-and-repair.d.ts +3 -0
  118. package/dist/application-spec/generate-application/code/templates/skills/features/domain-model/validation-and-repair.js +30 -0
  119. package/dist/application-spec/generate-application/code/templates/skills/features/features.d.ts +3 -0
  120. package/dist/application-spec/generate-application/code/templates/skills/features/features.js +1 -0
  121. package/dist/application-spec/generate-application/code/templates/skills/features/index.d.ts +1 -0
  122. package/dist/application-spec/generate-application/code/templates/skills/features/index.js +1 -0
  123. package/dist/application-spec/generate-application/code/templates/skills/features/inspection.d.ts +2 -0
  124. package/dist/application-spec/generate-application/code/templates/skills/features/inspection.js +1 -0
  125. package/dist/application-spec/generate-application/code/templates/skills/features/localization.d.ts +3 -0
  126. package/dist/application-spec/generate-application/code/templates/skills/features/localization.js +87 -0
  127. package/dist/application-spec/generate-application/code/templates/skills/features/scene-objects.d.ts +3 -0
  128. package/dist/application-spec/generate-application/code/templates/skills/features/scene-objects.js +43 -0
  129. package/dist/application-spec/generate-application/code/templates/skills/features/state/index.d.ts +1 -0
  130. package/dist/application-spec/generate-application/code/templates/skills/features/state/index.js +1 -0
  131. package/dist/application-spec/generate-application/code/templates/skills/features/state/slices.d.ts +3 -0
  132. package/dist/application-spec/generate-application/code/templates/skills/features/state/slices.js +48 -0
  133. package/dist/application-spec/generate-application/code/templates/skills/features/state/state.d.ts +3 -0
  134. package/dist/application-spec/generate-application/code/templates/skills/features/state/state.js +1 -0
  135. package/dist/application-spec/generate-application/code/templates/skills/features/state/updates.d.ts +3 -0
  136. package/dist/application-spec/generate-application/code/templates/skills/features/state/updates.js +39 -0
  137. package/dist/application-spec/generate-application/code/templates/skills/features/state/violations.d.ts +3 -0
  138. package/dist/application-spec/generate-application/code/templates/skills/features/state/violations.js +36 -0
  139. package/dist/application-spec/generate-application/code/templates/skills/features/variants.d.ts +2 -0
  140. package/dist/application-spec/generate-application/code/templates/skills/features/variants.js +1 -0
  141. package/dist/application-spec/generate-application/code/templates/skills/features/webhooks.d.ts +2 -0
  142. package/dist/application-spec/generate-application/code/templates/skills/features/webhooks.js +1 -0
  143. package/dist/application-spec/generate-application/code/templates/skills/guide.d.ts +68 -0
  144. package/dist/application-spec/generate-application/code/templates/skills/guide.js +18 -0
  145. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill-bundle.d.ts +10 -0
  146. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill-bundle.js +14 -0
  147. package/dist/application-spec/generate-application/code/templates/skills/phx-members-without-guide.d.ts +9 -0
  148. package/dist/application-spec/generate-application/code/templates/skills/phx-members-without-guide.js +1 -0
  149. package/dist/application-spec/generate-application/code/templates/skills/processes/asset-conversion.d.ts +2 -0
  150. package/dist/application-spec/generate-application/code/templates/skills/processes/asset-conversion.js +23 -0
  151. package/dist/application-spec/generate-application/code/templates/skills/{phoenix-skill.d.ts → processes/beta.d.ts} +2 -1
  152. package/dist/application-spec/generate-application/code/templates/skills/processes/beta.js +4 -0
  153. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/evaluate.d.ts +2 -0
  154. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/evaluate.js +38 -0
  155. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/feedback.d.ts +3 -0
  156. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/feedback.js +1 -0
  157. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/index.d.ts +1 -0
  158. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/index.js +1 -0
  159. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/report.d.ts +2 -0
  160. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/report.js +7 -0
  161. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/send.d.ts +2 -0
  162. package/dist/application-spec/generate-application/code/templates/skills/processes/feedback/send.js +2 -0
  163. package/dist/application-spec/generate-application/code/templates/skills/processes/finalization.d.ts +2 -0
  164. package/dist/application-spec/generate-application/code/templates/skills/processes/finalization.js +2 -0
  165. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/build.d.ts +2 -0
  166. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/build.js +25 -0
  167. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/direction.d.ts +2 -0
  168. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/direction.js +35 -0
  169. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/first-draft.d.ts +3 -0
  170. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/first-draft.js +3 -0
  171. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/handoff.d.ts +2 -0
  172. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/handoff.js +9 -0
  173. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/index.d.ts +1 -0
  174. package/dist/application-spec/generate-application/code/templates/skills/processes/first-draft/index.js +1 -0
  175. package/dist/application-spec/generate-application/code/templates/skills/processes/index.d.ts +8 -0
  176. package/dist/application-spec/generate-application/code/templates/skills/processes/index.js +1 -0
  177. package/dist/application-spec/generate-application/code/templates/skills/processes/model-migration.d.ts +2 -0
  178. package/dist/application-spec/generate-application/code/templates/skills/processes/model-migration.js +1 -0
  179. package/dist/application-spec/generate-application/code/templates/skills/processes/review/appearance.d.ts +2 -0
  180. package/dist/application-spec/generate-application/code/templates/skills/processes/review/appearance.js +46 -0
  181. package/dist/application-spec/generate-application/code/templates/skills/processes/review/code.d.ts +2 -0
  182. package/dist/application-spec/generate-application/code/templates/skills/processes/review/code.js +2 -0
  183. package/dist/application-spec/generate-application/code/templates/skills/processes/review/hand-over.d.ts +2 -0
  184. package/dist/application-spec/generate-application/code/templates/skills/processes/review/hand-over.js +6 -0
  185. package/dist/application-spec/generate-application/code/templates/skills/processes/review/index.d.ts +1 -0
  186. package/dist/application-spec/generate-application/code/templates/skills/processes/review/index.js +1 -0
  187. package/dist/application-spec/generate-application/code/templates/skills/processes/review/review.d.ts +3 -0
  188. package/dist/application-spec/generate-application/code/templates/skills/processes/review/review.js +1 -0
  189. package/dist/application-spec/generate-application/code/templates/skills/processes/review/visual-inspection.d.ts +2 -0
  190. package/dist/application-spec/generate-application/code/templates/skills/processes/review/visual-inspection.js +13 -0
  191. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/branding.d.ts +2 -0
  192. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/branding.js +20 -0
  193. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/catalog.d.ts +2 -0
  194. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/catalog.js +1 -0
  195. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/index.d.ts +1 -0
  196. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/index.js +1 -0
  197. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/product-definition.d.ts +2 -0
  198. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/product-definition.js +22 -0
  199. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/specification.d.ts +3 -0
  200. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/specification.js +1 -0
  201. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/ux-guidelines.d.ts +2 -0
  202. package/dist/application-spec/generate-application/code/templates/skills/processes/specification/ux-guidelines.js +25 -0
  203. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +51 -251
  204. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +3 -58
  205. package/dist/application-spec/generate-application/code/templates/skills/sdk-subpath-imports.d.ts +9 -0
  206. package/dist/application-spec/generate-application/code/templates/skills/sdk-subpath-imports.js +1 -0
  207. package/dist/application-spec/generate-application/code/templates/spec-code/collect-spec-code.d.ts +1 -1
  208. package/dist/application-spec/generate-application/code/templates/spec-code/collect-spec-code.js +1 -1
  209. package/dist/application-spec/generate-application/code/templates/story/wrapper.js +2 -4
  210. package/dist/application-spec/generate-application/code/templates/tsconfig.js +2 -1
  211. package/dist/application-spec/generate-application/index.d.ts +1 -6
  212. package/dist/application-spec/generate-application/index.js +1 -1
  213. package/dist/application-spec/parse-application-files/merge/merged-assistant.d.ts +13 -4
  214. package/dist/application-spec/parse-application-files/merge/merged-assistant.js +1 -1
  215. package/dist/application-spec/parse-application-files/merge/merged-infra.d.ts +4 -11
  216. package/dist/application-spec/parse-application-files/merge/merged-transformers.d.ts +2 -4
  217. package/dist/application-spec/parse-application-files/parse-application-files.js +1 -1
  218. package/dist/application-spec/parse-application-files/raw-spec/raw-acl.d.ts +2 -2
  219. package/dist/application-spec/parse-application-files/raw-spec/raw-acl.js +1 -1
  220. package/dist/application-spec/parse-application-files/raw-spec/raw-admin-pages.d.ts +3 -24
  221. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.d.ts +58 -23
  222. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.js +1 -1
  223. package/dist/application-spec/parse-application-files/raw-spec/raw-expressions.d.ts +1 -1
  224. package/dist/application-spec/parse-application-files/raw-spec/raw-expressions.js +1 -1
  225. package/dist/application-spec/parse-application-files/raw-spec/raw-resources.d.ts +19 -64
  226. package/dist/application-spec/parse-application-files/spec/application/admin-spec/admin-pages.d.ts +3 -20
  227. package/dist/application-spec/parse-application-files/spec/application/admin-spec/states.d.ts +3 -5
  228. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/states.d.ts +3 -8
  229. package/dist/application-spec/parse-application-files/spec/components/bindings/read-binding.d.ts +3 -13
  230. package/dist/application-spec/parse-application-files/spec/components/bindings/write-binding.d.ts +4 -32
  231. package/dist/application-spec/parse-application-files/spec/components/component-filter.d.ts +4 -10
  232. package/dist/application-spec/parse-application-files/spec/components/components.d.ts +3 -4
  233. package/dist/application-spec/parse-application-files/spec/components/index.d.ts +1 -2
  234. package/dist/application-spec/parse-application-files/spec/components/index.js +1 -1
  235. package/dist/application-spec/parse-application-files/spec/components/sdk-component-entry.d.ts +1 -1
  236. package/dist/application-spec/parse-application-files/spec/components/user-component-entry.d.ts +2 -3
  237. package/dist/application-spec/parse-application-files/spec/components/user-component-entry.js +1 -1
  238. package/dist/application-spec/parse-application-files/spec/components/user-components.d.ts +2 -3
  239. package/dist/application-spec/parse-application-files/spec/expressions/expression-read-types.d.ts +2 -2
  240. package/dist/application-spec/parse-application-files/spec/expressions/expressions.d.ts +7 -29
  241. package/dist/application-spec/parse-application-files/spec/expressions/index.d.ts +0 -1
  242. package/dist/application-spec/parse-application-files/spec/expressions/memo-eval-plan.d.ts +4 -71
  243. package/dist/application-spec/parse-application-files/spec/expressions/memo-eval-plan.js +1 -1
  244. package/dist/application-spec/parse-application-files/spec/expressions/user-expressions.d.ts +2 -2
  245. package/dist/application-spec/parse-application-files/spec/invariants/invariant.d.ts +5 -21
  246. package/dist/application-spec/parse-application-files/spec/invariants/invariants.d.ts +4 -14
  247. package/dist/application-spec/parse-application-files/spec/model/aliases.d.ts +3 -9
  248. package/dist/application-spec/parse-application-files/spec/model/common-types.d.ts +6 -14
  249. package/dist/application-spec/parse-application-files/spec/model/defaults.d.ts +6 -31
  250. package/dist/application-spec/parse-application-files/spec/model/entity-types.d.ts +3 -8
  251. package/dist/application-spec/parse-application-files/spec/model/model-version-key.d.ts +3 -3
  252. package/dist/application-spec/parse-application-files/spec/model/names/action-name.d.ts +3 -7
  253. package/dist/application-spec/parse-application-files/spec/model/names/alias-name.d.ts +3 -7
  254. package/dist/application-spec/parse-application-files/spec/model/names/entity-or-alias-name.d.ts +3 -8
  255. package/dist/application-spec/parse-application-files/spec/model/names/entity-type-name.d.ts +3 -8
  256. package/dist/application-spec/parse-application-files/spec/model/names/expression-name.d.ts +3 -6
  257. package/dist/application-spec/parse-application-files/spec/model/names/instance-name.d.ts +3 -7
  258. package/dist/application-spec/parse-application-files/spec/model/names/invariant-name.d.ts +3 -3
  259. package/dist/application-spec/parse-application-files/spec/model/names/shape-property-name.d.ts +3 -11
  260. package/dist/application-spec/parse-application-files/spec/model/names/violation-type-name.d.ts +3 -3
  261. package/dist/application-spec/parse-application-files/spec/model/presets.d.ts +6 -29
  262. package/dist/application-spec/parse-application-files/spec/sections/actions.d.ts +6 -23
  263. package/dist/application-spec/parse-application-files/spec/sections/app-metadata.d.ts +3 -18
  264. package/dist/application-spec/parse-application-files/spec/sections/application-version.d.ts +3 -7
  265. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-form-elements.d.ts +9 -0
  266. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-form-elements.js +1 -0
  267. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.d.ts +4 -1
  268. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.js +1 -1
  269. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant.js +1 -1
  270. package/dist/application-spec/parse-application-files/spec/sections/data-spec/chunks.d.ts +6 -23
  271. package/dist/application-spec/parse-application-files/spec/sections/data-spec/custom-data-spec.d.ts +1 -16
  272. package/dist/application-spec/parse-application-files/spec/sections/data-spec/data-entry-key.d.ts +3 -9
  273. package/dist/application-spec/parse-application-files/spec/sections/data-spec/data-spec.d.ts +1 -10
  274. package/dist/application-spec/parse-application-files/spec/sections/data-spec/swatch-data-spec.d.ts +1 -14
  275. package/dist/application-spec/parse-application-files/spec/sections/state-value.d.ts +3 -7
  276. package/dist/application-spec/parse-application-files/spec/sections/theme.d.ts +3 -10
  277. package/dist/application-spec/parse-application-files/spec/sections/transformers.d.ts +4 -11
  278. package/dist/application-spec/parse-application-files/spec/sections/ui.d.ts +3 -12
  279. package/dist/client/authorized-client.d.ts +4 -2
  280. package/dist/client/authorized-client.js +1 -1
  281. package/dist/client/contract.d.ts +34 -4
  282. package/dist/client/contract.js +1 -1
  283. package/dist/client/index.d.ts +1 -1
  284. package/dist/client/local-authorized-client.d.ts +3 -1
  285. package/dist/client/local-authorized-client.js +1 -1
  286. package/dist/client/memory-authorized-client.d.ts +4 -1
  287. package/dist/client/memory-authorized-client.js +1 -1
  288. package/dist/client/phoenix-api.d.ts +279 -2
  289. package/dist/configurator/ConfiguratorApp.js +1 -1
  290. package/dist/configurator/app-loader-content/index.d.ts +0 -1
  291. package/dist/configurator/app-loader-content/index.js +1 -1
  292. package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
  293. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-annotation.d.ts +31 -0
  294. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +140 -27
  295. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -1
  296. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.d.ts +52 -9
  297. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.js +1 -1
  298. package/dist/configurator/application-runtime/extensions/systems/camera-control-system/camera-control-system.d.ts +43 -0
  299. package/dist/configurator/application-runtime/extensions/systems/camera-control-system/camera-control-system.js +1 -1
  300. package/dist/configurator/application-runtime/extensions/systems/canvas-system.d.ts +8 -0
  301. package/dist/configurator/application-runtime/extensions/systems/canvas-system.js +1 -1
  302. package/dist/configurator/application-runtime/extensions/systems/export-system/export-busy-error.d.ts +8 -0
  303. package/dist/configurator/application-runtime/extensions/systems/export-system/export-busy-error.js +1 -0
  304. package/dist/configurator/application-runtime/extensions/systems/export-system/export-system.d.ts +23 -1
  305. package/dist/configurator/application-runtime/extensions/systems/export-system/export-system.js +1 -1
  306. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.d.ts +82 -55
  307. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.js +1 -1
  308. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.d.ts +73 -5
  309. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.js +1 -1
  310. package/dist/configurator/application-runtime/extensions/systems/graphql-system/violations.d.ts +40 -0
  311. package/dist/configurator/application-runtime/extensions/systems/graphql-system/violations.js +1 -0
  312. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/capture-next-frame.d.ts +10 -0
  313. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/capture-next-frame.js +1 -0
  314. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/image-rendering-system.d.ts +22 -5
  315. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/image-rendering-system.js +1 -1
  316. package/dist/configurator/application-runtime/extensions/systems/index.d.ts +3 -2
  317. package/dist/configurator/application-runtime/extensions/systems/index.js +1 -1
  318. package/dist/configurator/common/configurator-interface.d.ts +10 -7
  319. package/dist/configurator/common/configurator-interface.js +1 -1
  320. package/dist/configurator/configuration-not-found-page/BuiltInConfigurationNotFoundPage.d.ts +5 -0
  321. package/dist/configurator/configuration-not-found-page/BuiltInConfigurationNotFoundPage.js +1 -0
  322. package/dist/configurator/configuration-not-found-page/ConfigurationNotFoundPageElement.d.ts +0 -6
  323. package/dist/configurator/configuration-not-found-page/ConfigurationNotFoundPageElement.js +1 -1
  324. package/dist/configurator/configuration-not-found-page/index.d.ts +2 -2
  325. package/dist/configurator/configuration-not-found-page/index.js +1 -1
  326. package/dist/configurator/configurator-context/PreviewContextProvider.js +1 -1
  327. package/dist/configurator/configurator-context/configurator-hooks/index.d.ts +0 -1
  328. package/dist/configurator/configurator-context/configurator-hooks/index.js +1 -1
  329. package/dist/configurator/configurator-context/configurator-hooks/layout-hooks.js +1 -1
  330. package/dist/configurator/configurator-context/index.d.ts +0 -5
  331. package/dist/configurator/configurator-context/index.js +1 -1
  332. package/dist/configurator/configurator-error-page/BuiltInConfiguratorErrorPage.d.ts +3 -3
  333. package/dist/configurator/configurator-error-page/BuiltInConfiguratorErrorPage.js +1 -1
  334. package/dist/configurator/configurator-error-page/ConfiguratorErrorPageElement.d.ts +0 -5
  335. package/dist/configurator/configurator-error-page/ConfiguratorErrorPageElement.js +1 -1
  336. package/dist/configurator/configurator-error-page/index.d.ts +1 -2
  337. package/dist/configurator/configurator-error-page/index.js +1 -1
  338. package/dist/configurator/index.d.ts +9 -2
  339. package/dist/configurator/index.js +1 -1
  340. package/dist/configurator/pages/ConfiguratorNotFoundPage.js +1 -1
  341. package/dist/configurator/pages/LoadedConfiguratorDetailPage.js +1 -1
  342. package/dist/configurator/pages/NewConfiguratorPage.js +1 -1
  343. package/dist/configurator/pages/default-configurator-elements.d.ts +6 -2
  344. package/dist/configurator/pages/default-configurator-elements.js +1 -1
  345. package/dist/configurator/pages/error-boundaries/BuiltInGeneralErrorFallback.d.ts +5 -0
  346. package/dist/configurator/pages/error-boundaries/BuiltInGeneralErrorFallback.js +1 -0
  347. package/dist/configurator/pages/error-boundaries/DevContextFallback.js +1 -1
  348. package/dist/configurator/pages/error-boundaries/DevLoadingFallback.js +1 -1
  349. package/dist/configurator/pages/error-boundaries/LoadingErrorBoundary.js +1 -1
  350. package/dist/configurator/pages/error-boundaries/index.d.ts +1 -0
  351. package/dist/configurator/pages/error-boundaries/index.js +1 -1
  352. package/dist/configurator/{configurator-context → pages/provider-slots}/ConfiguratorResponsiveProvider.d.ts +3 -3
  353. package/dist/configurator/pages/provider-slots/ConfiguratorResponsiveProvider.js +1 -0
  354. package/dist/configurator/pages/provider-slots/ContainerSlotProvider.d.ts +3 -0
  355. package/dist/configurator/pages/provider-slots/ContainerSlotProvider.js +1 -0
  356. package/dist/configurator/pages/provider-slots/LoaderSlotProvider.d.ts +3 -0
  357. package/dist/configurator/pages/provider-slots/LoaderSlotProvider.js +1 -0
  358. package/dist/configurator/pages/provider-slots/MessageHostSlotProvider.d.ts +3 -0
  359. package/dist/configurator/pages/provider-slots/MessageHostSlotProvider.js +1 -0
  360. package/dist/configurator/pages/provider-slots/SceneResourcesSlotProvider.d.ts +3 -0
  361. package/dist/configurator/pages/provider-slots/SceneResourcesSlotProvider.js +1 -0
  362. package/dist/configurator/pages/provider-slots/ThemeSlotProvider.d.ts +3 -0
  363. package/dist/configurator/pages/provider-slots/ThemeSlotProvider.js +1 -0
  364. package/dist/configurator/pages/provider-slots/configurator-provider-slot-elements.d.ts +3 -0
  365. package/dist/configurator/pages/provider-slots/configurator-provider-slot-elements.js +1 -0
  366. package/dist/configurator/pages/provider-slots/index.d.ts +6 -0
  367. package/dist/configurator/pages/provider-slots/index.js +1 -0
  368. package/dist/configurator/pages/ui-elements/BuiltInInvalidDeploymentReload.d.ts +2 -0
  369. package/dist/configurator/pages/ui-elements/BuiltInInvalidDeploymentReload.js +1 -0
  370. package/dist/configurator/pages/ui-elements/configurator-ui-elements.d.ts +3 -0
  371. package/dist/configurator/pages/ui-elements/configurator-ui-elements.js +1 -0
  372. package/dist/configurator/pages/ui-elements/index.d.ts +2 -0
  373. package/dist/configurator/pages/ui-elements/index.js +1 -0
  374. package/dist/configurator/scene/cameras/CameraPadding.js +1 -1
  375. package/dist/configurator/ui/assistant/AssistantChips.d.ts +13 -2
  376. package/dist/configurator/ui/assistant/AssistantChips.js +1 -1
  377. package/dist/configurator/ui/assistant/AssistantComposer.d.ts +6 -0
  378. package/dist/configurator/ui/assistant/AssistantComposer.js +2 -1
  379. package/dist/configurator/ui/assistant/AssistantMarkdown.js +1 -1
  380. package/dist/configurator/ui/assistant/AssistantThread.d.ts +4 -3
  381. package/dist/configurator/ui/assistant/AssistantThread.js +1 -1
  382. package/dist/configurator/ui/assistant/alert/AssistantAlert.d.ts +4 -1
  383. package/dist/configurator/ui/assistant/alert/AssistantAlert.js +1 -1
  384. package/dist/configurator/ui/assistant/annotation/AnnotationBadge.d.ts +9 -0
  385. package/dist/configurator/ui/assistant/annotation/AnnotationBadge.js +1 -0
  386. package/dist/configurator/ui/assistant/annotation/AnnotationOverlay.d.ts +6 -0
  387. package/dist/configurator/ui/assistant/annotation/AnnotationOverlay.js +1 -0
  388. package/dist/configurator/ui/assistant/annotation/AnnotationPin.d.ts +14 -0
  389. package/dist/configurator/ui/assistant/annotation/AnnotationPin.js +1 -0
  390. package/dist/configurator/ui/assistant/annotation/AnnotationViewer.d.ts +12 -0
  391. package/dist/configurator/ui/assistant/annotation/AnnotationViewer.js +1 -0
  392. package/dist/configurator/ui/assistant/annotation/MessageAnnotations.d.ts +11 -0
  393. package/dist/configurator/ui/assistant/annotation/MessageAnnotations.js +1 -0
  394. package/dist/configurator/ui/assistant/annotation/annotation-host-context.d.ts +5 -0
  395. package/dist/configurator/ui/assistant/annotation/annotation-host-context.js +1 -0
  396. package/dist/configurator/ui/assistant/annotation/annotation-layout.d.ts +26 -0
  397. package/dist/configurator/ui/assistant/annotation/annotation-layout.js +1 -0
  398. package/dist/configurator/ui/assistant/annotation/editor/AnnotationComment.d.ts +15 -0
  399. package/dist/configurator/ui/assistant/annotation/editor/AnnotationComment.js +1 -0
  400. package/dist/configurator/ui/assistant/annotation/editor/AnnotationEditor.d.ts +18 -0
  401. package/dist/configurator/ui/assistant/annotation/editor/AnnotationEditor.js +1 -0
  402. package/dist/configurator/ui/assistant/annotation/editor/annotation-drawing.d.ts +22 -0
  403. package/dist/configurator/ui/assistant/annotation/editor/annotation-drawing.js +1 -0
  404. package/dist/configurator/ui/assistant/annotation/editor/annotation-pins.d.ts +22 -0
  405. package/dist/configurator/ui/assistant/annotation/editor/annotation-pins.js +1 -0
  406. package/dist/configurator/ui/assistant/annotation/editor/flatten-annotation.d.ts +17 -0
  407. package/dist/configurator/ui/assistant/annotation/editor/flatten-annotation.js +1 -0
  408. package/dist/configurator/ui/assistant/annotation/editor/index.d.ts +1 -0
  409. package/dist/configurator/ui/assistant/annotation/editor/index.js +1 -0
  410. package/dist/configurator/ui/assistant/annotation/index.d.ts +4 -0
  411. package/dist/configurator/ui/assistant/annotation/index.js +1 -0
  412. package/dist/configurator/ui/assistant/annotation/prefers-reduced-motion.d.ts +2 -0
  413. package/dist/configurator/ui/assistant/annotation/prefers-reduced-motion.js +1 -0
  414. package/dist/configurator/ui/assistant/annotation/use-end-on-unmount.d.ts +6 -0
  415. package/dist/configurator/ui/assistant/annotation/use-end-on-unmount.js +1 -0
  416. package/dist/configurator/ui/assistant/assistant-failure.d.ts +15 -7
  417. package/dist/configurator/ui/assistant/assistant-failure.js +1 -1
  418. package/dist/configurator/ui/assistant/attachments/MessageImages.d.ts +19 -0
  419. package/dist/configurator/ui/assistant/attachments/MessageImages.js +1 -0
  420. package/dist/configurator/ui/assistant/attachments/index.d.ts +2 -0
  421. package/dist/configurator/ui/assistant/attachments/index.js +1 -0
  422. package/dist/configurator/ui/assistant/attachments/prepare-image.d.ts +24 -0
  423. package/dist/configurator/ui/assistant/attachments/prepare-image.js +1 -0
  424. package/dist/configurator/ui/assistant/composer/composer-frame.d.ts +15 -0
  425. package/dist/configurator/ui/assistant/composer/composer-frame.js +1 -0
  426. package/dist/configurator/ui/assistant/composer/index.d.ts +1 -0
  427. package/dist/configurator/ui/assistant/composer/index.js +1 -0
  428. package/dist/configurator/ui/assistant/entity-link/AssistantEntityLink.js +1 -1
  429. package/dist/configurator/ui/assistant/form/AssistantForm.js +1 -1
  430. package/dist/configurator/ui/assistant/form/compose-answer.d.ts +1 -2
  431. package/dist/configurator/ui/assistant/form/compose-answer.js +1 -1
  432. package/dist/configurator/ui/assistant/form/form-model.d.ts +1 -3
  433. package/dist/configurator/ui/assistant/form/form-state.d.ts +1 -1
  434. package/dist/configurator/ui/assistant/form/index.d.ts +2 -0
  435. package/dist/configurator/ui/assistant/form/index.js +1 -1
  436. package/dist/configurator/ui/assistant/form/parse-form-block.d.ts +1 -1
  437. package/dist/configurator/ui/assistant/form/parse-form-block.js +1 -1
  438. package/dist/configurator/ui/assistant/form/read-form-attributes.d.ts +1 -1
  439. package/dist/configurator/ui/assistant/form/read-form-attributes.js +1 -1
  440. package/dist/configurator/ui/assistant/form/registry/built-in-form-elements.d.ts +29 -0
  441. package/dist/configurator/ui/assistant/form/registry/built-in-form-elements.js +1 -0
  442. package/dist/configurator/ui/assistant/form/registry/create-assistant-form-element.d.ts +31 -0
  443. package/dist/configurator/ui/assistant/form/registry/create-assistant-form-element.js +1 -0
  444. package/dist/configurator/ui/assistant/form/{form-element-definition.d.ts → registry/form-element-definition.d.ts} +3 -1
  445. package/dist/configurator/ui/assistant/form/registry/form-element-definition.js +1 -0
  446. package/dist/configurator/ui/assistant/form/{form-registry.d.ts → registry/form-registry.d.ts} +1 -1
  447. package/dist/configurator/ui/assistant/form/registry/form-registry.js +1 -0
  448. package/dist/configurator/ui/assistant/form/registry/index.d.ts +6 -0
  449. package/dist/configurator/ui/assistant/form/registry/index.js +1 -0
  450. package/dist/configurator/ui/assistant/form/registry/use-form-registry.d.ts +8 -0
  451. package/dist/configurator/ui/assistant/form/registry/use-form-registry.js +1 -0
  452. package/dist/configurator/ui/assistant/form-elements/FormCard.d.ts +1 -1
  453. package/dist/configurator/ui/assistant/form-elements/FormCard.js +1 -1
  454. package/dist/configurator/ui/assistant/form-elements/FormNumber.js +1 -1
  455. package/dist/configurator/ui/assistant/form-elements/FormReply.d.ts +1 -1
  456. package/dist/configurator/ui/assistant/form-elements/FormReply.js +1 -1
  457. package/dist/configurator/ui/assistant/form-elements/FormSwatch.d.ts +1 -1
  458. package/dist/configurator/ui/assistant/form-elements/FormSwatch.js +1 -1
  459. package/dist/configurator/ui/assistant/form-elements/form-element-props.d.ts +5 -5
  460. package/dist/configurator/ui/assistant/index.d.ts +4 -0
  461. package/dist/configurator/ui/assistant/index.js +1 -1
  462. package/dist/configurator/ui/assistant/popover/AssistantPopover.d.ts +24 -0
  463. package/dist/configurator/ui/assistant/popover/AssistantPopover.js +1 -0
  464. package/dist/configurator/ui/assistant/popover/index.d.ts +1 -0
  465. package/dist/configurator/ui/assistant/popover/index.js +1 -0
  466. package/dist/configurator/ui/assistant/reference-link/AssistantReferenceLink.js +1 -1
  467. package/dist/configurator/ui/assistant/reference-link/reference-styles.js +1 -1
  468. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.d.ts +9 -0
  469. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.js +1 -0
  470. package/dist/configurator/ui/assistant/screenshots/index.d.ts +3 -0
  471. package/dist/configurator/ui/assistant/screenshots/index.js +1 -0
  472. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.d.ts +16 -0
  473. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.js +1 -0
  474. package/dist/configurator/ui/assistant/screenshots/use-screenshot-src.d.ts +8 -0
  475. package/dist/configurator/ui/assistant/screenshots/use-screenshot-src.js +1 -0
  476. package/dist/configurator/ui/assistant/streamed-markdown.d.ts +11 -0
  477. package/dist/configurator/ui/assistant/streamed-markdown.js +2 -2
  478. package/dist/configurator/ui/assistant/thread-items.d.ts +5 -0
  479. package/dist/configurator/ui/assistant/thread-items.js +1 -1
  480. package/dist/configurator/ui/assistant/tool-chip.d.ts +19 -9
  481. package/dist/configurator/ui/assistant/tool-chip.js +1 -1
  482. package/dist/configurator/ui/assistant/use-load-older-on-top.d.ts +22 -0
  483. package/dist/configurator/ui/assistant/use-load-older-on-top.js +1 -0
  484. package/dist/configurator/ui/configurator-layout/slots/canvas/GPUAccelerationDisabled.js +1 -1
  485. package/dist/configurator/ui/configurator-layout/slots/canvas/LayoutCanvas.js +1 -1
  486. package/dist/configurator/ui/configurator-layout/slots/canvas/SharedCanvas.js +1 -1
  487. package/dist/configurator/ui/configurator-layout/slots/canvas/WebGLNotSupported.js +1 -1
  488. package/dist/configurator/ui/configurator-layout/slots/readonly-banner/CloneToEditDialog.js +1 -1
  489. package/dist/configurator/ui/configurator-layout/universal/DesktopPreview.js +1 -1
  490. package/dist/configurator/ui/configurator-layout/universal/ExportingOverlay.d.ts +5 -0
  491. package/dist/configurator/ui/configurator-layout/universal/ExportingOverlay.js +1 -0
  492. package/dist/configurator/ui/configurator-layout/universal/Layout.js +1 -1
  493. package/dist/configurator/ui/configurator-layout/universal/MobilePreview.js +1 -1
  494. package/dist/configurator/ui/configurator-layout/universal/use-layout-scene-safe-area.js +1 -1
  495. package/dist/configurator/ui/index.d.ts +1 -0
  496. package/dist/configurator/ui/index.js +1 -1
  497. package/dist/configurator/ui/legacy/chat/MobileChat.js +1 -1
  498. package/dist/configurator/ui/legacy/layout/common/CommonTopNavigation.js +1 -1
  499. package/dist/configurator/ui/legacy/layout/common/ReactiveInterfaceLayout.js +1 -1
  500. package/dist/configurator/ui/legacy/layout/simple/SimpleSidebar.js +1 -1
  501. package/dist/configurator/ui/legacy/layout/simple/SimpleTopNavigation.js +1 -1
  502. package/dist/configurator/ui/legacy/layout/steps/StepsNavigation.js +1 -1
  503. package/dist/configurator/ui/legacy/layout/steps/StepsOwnerLayout.js +1 -1
  504. package/dist/configurator/ui/legacy/layout/steps/StepsSideBar.js +1 -1
  505. package/dist/configurator/ui/legacy/layout/tabs/TabsSidebar.js +1 -1
  506. package/dist/configurator/ui/phoenix-layout-elements/AppLoader.d.ts +0 -7
  507. package/dist/configurator/ui/phoenix-layout-elements/AppLoader.js +2 -2
  508. package/dist/configurator/ui/phoenix-layout-elements/header/common/back-button/use-go-back-action.js +1 -1
  509. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/StepsNavigation.js +1 -1
  510. package/dist/configurator/ui/phoenix-layout-elements/index.d.ts +8 -1
  511. package/dist/configurator/ui/phoenix-layout-elements/index.js +1 -1
  512. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/basic/use-basic-sidebar-footer.js +1 -1
  513. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/PreviousStepButton.js +1 -1
  514. package/dist/configurator/ui/preset-layout/CategoryPresetUi.js +1 -1
  515. package/dist/configurator/ui/preset-layout/PresetUi.d.ts +0 -2
  516. package/dist/configurator/ui/preset-layout/PresetUi.js +1 -1
  517. package/dist/configurator/ui/preset-layout/index.d.ts +6 -1
  518. package/dist/configurator/ui/preset-layout/index.js +1 -1
  519. package/dist/configurator/ui/save-message-snackbars/SaveMessageSnackbars.js +1 -1
  520. package/dist/docs/3d-scene/animations-basic.mdx +0 -4
  521. package/dist/docs/3d-scene/camera-based-hiding.mdx +0 -2
  522. package/dist/docs/3d-scene/cameras/custom.mdx +4 -4
  523. package/dist/docs/3d-scene/cameras/fit-during-drag.mdx +0 -4
  524. package/dist/docs/3d-scene/cameras/locks.mdx +0 -4
  525. package/dist/docs/3d-scene/cameras/transitions.mdx +0 -2
  526. package/dist/docs/3d-scene/engraving.mdx +0 -4
  527. package/dist/docs/3d-scene/materials/custom.mdx +1 -2
  528. package/dist/docs/3d-scene/materials/inherit.mdx +0 -4
  529. package/dist/docs/3d-scene/materials/multilevel.mdx +0 -47
  530. package/dist/docs/3d-scene/materials/override.mdx +0 -4
  531. package/dist/docs/3d-scene/materials/simple.mdx +0 -4
  532. package/dist/docs/3d-scene/materials/transformer.mdx +0 -4
  533. package/dist/docs/3d-scene/materials/transition.mdx +0 -4
  534. package/dist/docs/3d-scene/materials/transmissive.mdx +0 -4
  535. package/dist/docs/3d-scene/postprocessing.mdx +0 -2
  536. package/dist/docs/3d-scene/rendering/basic.mdx +5 -9
  537. package/dist/docs/3d-scene/rendering/custom-entity.mdx +0 -6
  538. package/dist/docs/3d-scene/rendering/lights/ambient-light.mdx +0 -2
  539. package/dist/docs/3d-scene/rendering/lights/directional-light.mdx +0 -2
  540. package/dist/docs/3d-scene/rendering/lights/point-light.mdx +0 -2
  541. package/dist/docs/3d-scene/rendering/lights/rect-area-light.mdx +0 -2
  542. package/dist/docs/3d-scene/rendering/lights/spot-light.mdx +0 -2
  543. package/dist/docs/3d-scene/rendering/object-groups.mdx +0 -2
  544. package/dist/docs/3d-scene/rendering/objects.mdx +0 -4
  545. package/dist/docs/3d-scene/rendering/scene-entity-object.mdx +0 -43
  546. package/dist/docs/3d-scene/rendering/smma.mdx +0 -2
  547. package/dist/docs/3d-scene/rendering/soft-shadows.mdx +0 -2
  548. package/dist/docs/3d-scene/rendering/transformer.mdx +1 -3
  549. package/dist/docs/complex-use-cases/custom-ui-on-root-level.mdx +0 -1
  550. package/dist/docs/complex-use-cases/filtered-controls-with-fix-dialog.mdx +19 -19
  551. package/dist/docs/complex-use-cases/navigation-guard.mdx +81 -19
  552. package/dist/docs/complex-use-cases/navigation-reset-selection.mdx +28 -65
  553. package/dist/docs/complex-use-cases/navigation-reset-undo.mdx +16 -20
  554. package/dist/docs/complex-use-cases/sketching.mdx +2 -10
  555. package/dist/docs/controls/custom.mdx +88 -87
  556. package/dist/docs/controls/manage-child-entities/entitychildrenlist.mdx +0 -4
  557. package/dist/docs/controls/nullable-attributes.mdx +0 -2
  558. package/dist/docs/controls/scene/custom-controls.mdx +7 -8
  559. package/dist/docs/controls/scene/html-hotspots.mdx +0 -4
  560. package/dist/docs/controls/scene/object-html-hotspots.mdx +0 -4
  561. package/dist/docs/controls/select-attribute/cardselect.mdx +0 -4
  562. package/dist/docs/controls/select-attribute/listselect.mdx +0 -4
  563. package/dist/docs/controls/select-attribute/select.mdx +0 -4
  564. package/dist/docs/controls/select-attribute/swatchselect.mdx +0 -4
  565. package/dist/docs/controls/select-attribute/switchselect.mdx +0 -4
  566. package/dist/docs/controls/select-attribute/toggleselect.mdx +0 -4
  567. package/dist/docs/controls/select-child-entity/cardselect.mdx +2 -6
  568. package/dist/docs/controls/select-child-entity/listselect.mdx +5 -11
  569. package/dist/docs/controls/select-child-entity/toggleselect.mdx +4 -10
  570. package/dist/docs/controls/text-input.mdx +90 -19
  571. package/dist/docs/demos/glass.mdx +0 -4
  572. package/dist/docs/demos/heater.mdx +0 -10
  573. package/dist/docs/demos/office-chair.mdx +0 -8
  574. package/dist/docs/demos/office-desk.mdx +0 -8
  575. package/dist/docs/demos/ring.mdx +0 -9
  576. package/dist/docs/dimensions/3d-scene-integration/angle-indicators.mdx +0 -2
  577. package/dist/docs/dimensions/3d-scene-integration/editable-angle-indicator.mdx +0 -2
  578. package/dist/docs/dimensions/3d-scene-integration/editable-distance-dimension-indicator.mdx +0 -2
  579. package/dist/docs/dimensions/3d-scene-integration/editable-offset-indicator.mdx +0 -6
  580. package/dist/docs/dimensions/3d-scene-integration/editable-size-indicator.mdx +0 -4
  581. package/dist/docs/dimensions/3d-scene-integration/list-selector-dimension-indicator.mdx +0 -4
  582. package/dist/docs/dimensions/3d-scene-integration/offset-indicator.mdx +0 -6
  583. package/dist/docs/dimensions/3d-scene-integration/overlap-offset-demo.mdx +0 -6
  584. package/dist/docs/dimensions/input-controls/distance-slider.mdx +6 -6
  585. package/dist/docs/dimensions/selection-controls/list-selector.mdx +0 -2
  586. package/dist/docs/dimensions/selection-controls/toggle-selector.mdx +0 -2
  587. package/dist/docs/drag-and-drop/drag-handle.mdx +0 -1
  588. package/dist/docs/drag-and-drop/hotspot-handle.mdx +0 -1
  589. package/dist/docs/drag-and-drop/no-selection.mdx +0 -1
  590. package/dist/docs/drag-and-drop/planes.mdx +0 -3
  591. package/dist/docs/drag-and-drop/room-planner.mdx +1 -7
  592. package/dist/docs/drag-and-drop/rotatable.mdx +0 -1
  593. package/dist/docs/drag-and-drop/snapping/auto-rotation-demo.mdx +0 -2
  594. package/dist/docs/drag-and-drop/snapping/label-matching-demo.mdx +0 -2
  595. package/dist/docs/drag-and-drop/snapping/multi-snap-composition-demo.mdx +0 -2
  596. package/dist/docs/drag-and-drop/snapping/nested-entity-demo.mdx +0 -2
  597. package/dist/docs/drag-and-drop/snapping/priority-demo.mdx +0 -2
  598. package/dist/docs/drag-and-drop/snapping/snap-axis-demo.mdx +0 -2
  599. package/dist/docs/drag-and-drop/snapping/snap-edge-demo.mdx +0 -2
  600. package/dist/docs/drag-and-drop/snapping/snap-plane-demo.mdx +0 -5
  601. package/dist/docs/drag-and-drop/snapping/snap-point-demo.mdx +0 -2
  602. package/dist/docs/drag-and-drop/spatial-constraints/collision-system.mdx +0 -2
  603. package/dist/docs/drag-and-drop/spatial-constraints/disjoint-and-within.mdx +0 -6
  604. package/dist/docs/drag-and-drop/spatial-constraints/geometry-override.mdx +0 -4
  605. package/dist/docs/drag-and-drop/spatial-constraints/multiple-collision-meshes.mdx +0 -4
  606. package/dist/docs/drag-and-drop/spatial-constraints/touches.mdx +0 -4
  607. package/dist/docs/drag-and-drop/swap.mdx +0 -4
  608. package/dist/docs/fabs/basic.mdx +8 -12
  609. package/dist/docs/fabs/layout.mdx +0 -7
  610. package/dist/docs/index.json +98 -4
  611. package/dist/docs/integrations/lifecycle-providers.mdx +0 -12
  612. package/dist/docs/integrations/onloadprovider.mdx +0 -3
  613. package/dist/docs/integrations/webcomponent-api/basics.mdx +4 -2
  614. package/dist/docs/integrations/webcomponent-api/preset-tags.mdx +0 -1
  615. package/dist/docs/layouts/custom-layout.mdx +309 -189
  616. package/dist/docs/layouts/custom-price.mdx +0 -2
  617. package/dist/docs/layouts/custom-theme-handler.mdx +0 -4
  618. package/dist/docs/layouts/gallery/ardent-compressor.mdx +3485 -0
  619. package/dist/docs/layouts/gallery/corvid-drone.mdx +3399 -0
  620. package/dist/docs/layouts/gallery/fenwick-window.mdx +2778 -0
  621. package/dist/docs/layouts/gallery/ferrule-bar-station.mdx +6540 -0
  622. package/dist/docs/layouts/gallery/kestrel-kettle.mdx +1829 -0
  623. package/dist/docs/layouts/gallery/nightjar-guitar.mdx +3665 -0
  624. package/dist/docs/layouts/gallery/sunfold-solar.mdx +2657 -0
  625. package/dist/docs/layouts/gallery/tidepool-aquascape.mdx +5157 -0
  626. package/dist/docs/layouts/header/custom.mdx +0 -2
  627. package/dist/docs/layouts/icon-sets.mdx +0 -6
  628. package/dist/docs/layouts/phoenix-elements.mdx +0 -4
  629. package/dist/docs/layouts/phoenix-handlers.mdx +19 -28
  630. package/dist/docs/layouts/presets/action-and-overlay.mdx +0 -8
  631. package/dist/docs/layouts/presets/custom.mdx +6 -13
  632. package/dist/docs/layouts/preview/always-expand.mdx +4 -14
  633. package/dist/docs/layouts/preview/always.mdx +4 -14
  634. package/dist/docs/layouts/preview/auto-presets.mdx +4 -14
  635. package/dist/docs/layouts/preview/auto.mdx +4 -14
  636. package/dist/docs/layouts/preview/never.mdx +4 -14
  637. package/dist/docs/layouts/sidebar/in-a-custom-layout.mdx +18 -13
  638. package/dist/docs/layouts/sidebar/property-page-stack.mdx +0 -2
  639. package/dist/docs/layouts/sidebar/property-page.mdx +0 -2
  640. package/dist/docs/layouts/sidebar/tabs.mdx +0 -4
  641. package/dist/docs/layouts/sidebar-footer/custom.mdx +0 -2
  642. package/dist/docs/layouts/sidebar-footer/universal.mdx +0 -10
  643. package/dist/docs/layouts/tool-controls.mdx +0 -1
  644. package/dist/docs/layouts/toolbar.mdx +0 -4
  645. package/dist/docs/layouts/universal.mdx +2 -10
  646. package/dist/docs/other-features/client-side-rendering/camera-padding.mdx +0 -2
  647. package/dist/docs/other-features/client-side-rendering/custom.mdx +0 -6
  648. package/dist/docs/other-features/client-side-rendering/declarative.mdx +1 -5
  649. package/dist/docs/other-features/client-side-rendering/postprocessing.mdx +0 -6
  650. package/dist/docs/other-features/component-filters.mdx +0 -7
  651. package/dist/docs/other-features/currency.mdx +5 -6
  652. package/dist/docs/other-features/domain-actions.mdx +0 -5
  653. package/dist/docs/other-features/dynamic-component-attachments.mdx +75 -46
  654. package/dist/docs/other-features/error-5xx.mdx +0 -2
  655. package/dist/docs/other-features/navigation-hotspot.mdx +0 -5
  656. package/dist/docs/other-features/not-found-404.mdx +0 -2
  657. package/dist/docs/other-features/projected-entities.mdx +0 -5
  658. package/dist/docs/other-features/side-effects.mdx +0 -7
  659. package/dist/docs/other-features/transformers.mdx +101 -96
  660. package/dist/docs/other-features/violation-messages.mdx +0 -4
  661. package/dist/docs/other-features/violation-severity.mdx +2 -3
  662. package/dist/docs/performance/clone-highlight.mdx +0 -7
  663. package/dist/docs/performance/dynamic-components.mdx +0 -6
  664. package/dist/docs/performance/editable-dimension-stress-test.mdx +0 -2
  665. package/dist/docs/performance/fast-highlight.mdx +0 -7
  666. package/dist/docs/performance/general.mdx +0 -7
  667. package/dist/docs/performance/render-isolation.mdx +0 -6
  668. package/dist/docs/phoenix/admin.mdx +75 -100
  669. package/dist/docs/phoenix/application-states.mdx +45 -27
  670. package/dist/docs/phoenix/components.mdx +53 -46
  671. package/dist/docs/phoenix/configurator-interface.mdx +205 -123
  672. package/dist/docs/phoenix/deployments.mdx +11 -1
  673. package/dist/docs/phoenix/domain-model.mdx +24 -16
  674. package/dist/docs/phoenix/expression-context.mdx +3 -29
  675. package/dist/docs/phoenix/getting-started.mdx +0 -2
  676. package/dist/docs/phoenix/layout-slots.mdx +21 -0
  677. package/dist/docs/phoenix/localization.mdx +64 -54
  678. package/dist/docs/phoenix/migration-guide.mdx +10 -11
  679. package/dist/docs/phoenix/phoenix-cli.mdx +57 -15
  680. package/dist/docs/phoenix/project-structure.mdx +52 -55
  681. package/dist/docs/phoenix/quickstart.mdx +1 -3
  682. package/dist/docs/phoenix/sdk-builder-workflow.mdx +7 -11
  683. package/dist/docs/phoenix/sessions-and-access.mdx +2 -0
  684. package/dist/docs/phoenix/state-management.mdx +18 -16
  685. package/dist/docs/phoenix/testing.mdx +6 -1
  686. package/dist/docs/phoenix/webhooks.mdx +9 -1
  687. package/dist/docs/recipes-and-delete/delete-entity.mdx +3 -6
  688. package/dist/docs/recipes-and-delete/dynamic-root-entity.mdx +0 -2
  689. package/dist/docs/recipes-and-delete/grouped-button.mdx +0 -3
  690. package/dist/docs/recipes-and-delete/grouped-panel.mdx +0 -3
  691. package/dist/docs/recipes-and-delete/horizontal.mdx +3 -6
  692. package/dist/docs/recipes-and-delete/recipe-hierarchy-lists.mdx +0 -3
  693. package/dist/docs/recipes-and-delete/recipe-hierarchy-selection.mdx +0 -5
  694. package/dist/docs/recipes-and-delete/replace-dropdown.mdx +3 -6
  695. package/dist/docs/recipes-and-delete/replace-panel.mdx +0 -7
  696. package/dist/docs/recipes-and-delete/simple.mdx +3 -6
  697. package/dist/docs/recipes-and-delete/vertical.mdx +3 -6
  698. package/dist/docs/relations/aliases.mdx +0 -2
  699. package/dist/docs/relations/all-of-type.mdx +0 -4
  700. package/dist/docs/relations/child-nullable.mdx +0 -4
  701. package/dist/docs/relations/child-required.mdx +0 -2
  702. package/dist/docs/relations/collection-direct.mdx +0 -4
  703. package/dist/docs/relations/collection-indirect.mdx +0 -4
  704. package/dist/docs/relations/collection-multiple.mdx +0 -2
  705. package/dist/docs/relations/cross-reference.mdx +0 -2
  706. package/dist/docs/relations/hierarchy.mdx +0 -2
  707. package/dist/docs/selection-and-highlight/canvas.mdx +0 -1
  708. package/dist/docs/selection-and-highlight/disable-highlight-per-object.mdx +0 -1
  709. package/dist/docs/selection-and-highlight/disable-highlight.mdx +0 -1
  710. package/dist/docs/selection-and-highlight/effects/outline.mdx +0 -3
  711. package/dist/docs/selection-and-highlight/effects/overlay.mdx +0 -3
  712. package/dist/docs/selection-and-highlight/fast-emissive-highlight.mdx +0 -3
  713. package/dist/docs/selection-and-highlight/group-highlighting.mdx +0 -1
  714. package/dist/docs/selection-and-highlight/hierarchy.mdx +100 -151
  715. package/dist/docs/selection-and-highlight/hotspots.mdx +0 -1
  716. package/dist/domain/application/GetApplicationWrapperHandler.d.ts +1 -1
  717. package/dist/domain/application/GetThemeHandler.d.ts +1 -1
  718. package/dist/domain/application/GetWebComponentOptions.d.ts +1 -1
  719. package/dist/domain/application/application-config.d.ts +6 -26
  720. package/dist/domain/application/assistant/assistant-fields.d.ts +1 -1
  721. package/dist/domain/application/assistant/assistant-value-type.d.ts +1 -1
  722. package/dist/domain/application/assistant/build-assistant-lenses.d.ts +1 -2
  723. package/dist/domain/application/assistant/build-assistant-lenses.js +1 -1
  724. package/dist/domain/application/assistant/build-assistant-manifest.d.ts +1 -2
  725. package/dist/domain/application/assistant/build-assistant-manifest.js +1 -1
  726. package/dist/domain/application/assistant/generate-assistant-prompt.d.ts +2 -3
  727. package/dist/domain/application/assistant/generate-assistant-prompt.js +1 -1
  728. package/dist/domain/application/assistant/index.d.ts +0 -4
  729. package/dist/domain/application/assistant/index.js +1 -1
  730. package/dist/domain/application/assistant/session-setup/AssistantSetupHandler.d.ts +1 -1
  731. package/dist/domain/application/assistant/session-setup/apply-assistant-setup.d.ts +1 -1
  732. package/dist/domain/application/assistant/session-setup/apply-assistant-setup.js +1 -1
  733. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.d.ts +5 -5
  734. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.js +1 -1
  735. package/dist/domain/application/assistant/session-setup/create-session-assistant.d.ts +1 -2
  736. package/dist/domain/application/assistant-field-options.d.ts +1 -1
  737. package/dist/domain/application/assistant-mutations.d.ts +1 -1
  738. package/dist/domain/application/assistant-mutations.js +1 -1
  739. package/dist/domain/application/assistant-recipe-groups.d.ts +1 -1
  740. package/dist/domain/application/configurator-builder.d.ts +7 -2
  741. package/dist/domain/application/configurator-builder.js +1 -1
  742. package/dist/domain/application/create-initial-published-data.d.ts +2 -1
  743. package/dist/domain/application/index.d.ts +1 -1
  744. package/dist/domain/application/index.js +1 -1
  745. package/dist/domain/application/published-data/DataRowValidatorHandler.d.ts +1 -1
  746. package/dist/domain/application/published-data/FilterPublishedChunksHandler.d.ts +1 -1
  747. package/dist/domain/application/published-data/MapPublishedChunkedDataHandler.d.ts +1 -1
  748. package/dist/domain/application/published-data/MapPublishedRevisionDataHandler.d.ts +1 -1
  749. package/dist/domain/application/published-data/SheetValidatorHandler.d.ts +1 -1
  750. package/dist/domain/application/standard-properties.js +1 -1
  751. package/dist/domain/application/web-component-property.d.ts +3 -1
  752. package/dist/domain/application/web-component-property.js +1 -1
  753. package/dist/domain/available-system-components/available-system-components.d.ts +11 -0
  754. package/dist/domain/available-system-components/available-system-components.js +1 -0
  755. package/dist/domain/available-system-components/index.d.ts +1 -0
  756. package/dist/domain/available-system-components/index.js +1 -0
  757. package/dist/domain/core/invariant/violation.d.ts +3 -2
  758. package/dist/domain/{domain-builder.d.ts → domain-builder/domain-builder.d.ts} +11 -5
  759. package/dist/domain/domain-builder/domain-builder.js +1 -0
  760. package/dist/domain/domain-builder/index.d.ts +1 -0
  761. package/dist/domain/domain-builder/index.js +1 -0
  762. package/dist/domain/domain-context/store-system/store-system.d.ts +5 -0
  763. package/dist/domain/domain-context/store-system/store-system.js +1 -1
  764. package/dist/domain/domain-context/transformers/context.d.ts +4 -2
  765. package/dist/domain/domain-context/transformers/when-builder.d.ts +2 -1
  766. package/dist/domain/domain-runtime/application.d.ts +39 -0
  767. package/dist/domain/domain-runtime/application.js +1 -0
  768. package/dist/domain/domain-runtime/domain-context/selectors.d.ts +1 -0
  769. package/dist/domain/domain-runtime/domain-context/selectors.js +1 -1
  770. package/dist/domain/domain-runtime/domain-runtime.d.ts +68 -28
  771. package/dist/domain/domain-runtime/domain-runtime.js +1 -1
  772. package/dist/domain/domain-runtime/environment/initialize.d.ts +1 -1
  773. package/dist/domain/domain-runtime/environment/types.d.ts +1 -1
  774. package/dist/domain/domain-runtime/index.d.ts +1 -1
  775. package/dist/domain/domain-runtime/index.js +1 -1
  776. package/dist/domain/domain-runtime/spec/create-violation-expressions.d.ts +1 -1
  777. package/dist/domain/domain-runtime/spec/create-violation-expressions.js +1 -1
  778. package/dist/domain/domain-runtime/spec/index.d.ts +1 -1
  779. package/dist/domain/domain-runtime/spec/index.js +1 -1
  780. package/dist/domain/domain-runtime/spec/initialize.js +1 -1
  781. package/dist/domain/domain-runtime/spec/{module-checks/resolve-imported-transformers.d.ts → resolve-imported-transformers.d.ts} +3 -3
  782. package/dist/domain/domain-runtime/spec/resolve-imported-transformers.js +1 -0
  783. package/dist/domain/domain-runtime/spec/selectors.d.ts +8 -6
  784. package/dist/domain/domain-runtime/spec/selectors.js +1 -1
  785. package/dist/domain/domain-runtime/spec/types.d.ts +2 -2
  786. package/dist/domain/domain-runtime/web-component/actions.d.ts +3 -0
  787. package/dist/domain/domain-runtime/web-component/actions.js +1 -1
  788. package/dist/domain/domain-runtime/web-component/initialize.d.ts +1 -0
  789. package/dist/domain/domain-runtime/web-component/initialize.js +1 -1
  790. package/dist/domain/domain-runtime/web-component/selectors.d.ts +2 -0
  791. package/dist/domain/domain-runtime/web-component/selectors.js +1 -1
  792. package/dist/domain/domain-runtime/web-component/types.d.ts +6 -3
  793. package/dist/domain/extensions/export-images/agent-screenshot.d.ts +30 -0
  794. package/dist/domain/extensions/export-images/agent-screenshot.js +1 -0
  795. package/dist/domain/extensions/{client-side-image.d.ts → export-images/client-side-image.d.ts} +2 -2
  796. package/dist/domain/extensions/export-images/client-side-image.js +1 -0
  797. package/dist/domain/extensions/export-images/index.d.ts +3 -0
  798. package/dist/domain/extensions/export-images/index.js +1 -0
  799. package/dist/domain/extensions/{save-template-thumbnail.d.ts → export-images/save-template-thumbnail.d.ts} +2 -2
  800. package/dist/domain/extensions/export-images/save-template-thumbnail.js +1 -0
  801. package/dist/domain/extensions/index.d.ts +1 -2
  802. package/dist/domain/extensions/index.js +1 -1
  803. package/dist/domain/index.d.ts +15 -2
  804. package/dist/domain/index.js +1 -1
  805. package/dist/domain/mocks/create-mock-domain-runtime.d.ts +9 -0
  806. package/dist/domain/mocks/create-test-application-config.d.ts +1 -1
  807. package/dist/domain/spec/application/admin-pages-section.d.ts +29 -0
  808. package/dist/domain/spec/application/admin-pages.d.ts +26 -0
  809. package/dist/domain/spec/application/admin-states.d.ts +5 -0
  810. package/dist/domain/spec/application/configurator-states.d.ts +8 -0
  811. package/dist/domain/spec/application/index.d.ts +5 -0
  812. package/dist/domain/spec/application/index.js +1 -0
  813. package/dist/domain/spec/components/bindings/index.d.ts +2 -0
  814. package/dist/domain/spec/components/bindings/read-binding.d.ts +13 -0
  815. package/dist/domain/spec/components/bindings/write-binding.d.ts +32 -0
  816. package/dist/{application-spec/parse-application-files → domain}/spec/components/component-entry.d.ts +3 -3
  817. package/dist/domain/spec/components/component-entry.js +1 -0
  818. package/dist/{application-spec/core → domain/spec}/components/component-filter.d.ts +3 -2
  819. package/dist/domain/spec/components/component-filters.d.ts +10 -0
  820. package/dist/domain/spec/components/component-filters.js +1 -0
  821. package/dist/domain/spec/components/components.d.ts +4 -0
  822. package/dist/domain/spec/components/components.js +1 -0
  823. package/dist/domain/spec/components/index.d.ts +6 -0
  824. package/dist/domain/spec/enhanced-json/enhanced-json-value.d.ts +30 -0
  825. package/dist/domain/spec/enhanced-json/enhanced-json-value.js +1 -0
  826. package/dist/domain/spec/enhanced-json/index.d.ts +1 -0
  827. package/dist/domain/spec/enhanced-json/index.js +1 -0
  828. package/dist/domain/{domain-runtime → spec}/errors/implementation-error-collector.d.ts +2 -0
  829. package/dist/domain/{domain-runtime → spec}/errors/implementation-error-collector.js +1 -1
  830. package/dist/{application-spec/parse-application-files → domain}/spec/expressions/expression.d.ts +9 -3
  831. package/dist/domain/spec/expressions/expression.js +1 -0
  832. package/dist/domain/spec/expressions/expressions.d.ts +27 -0
  833. package/dist/domain/spec/expressions/expressions.js +1 -0
  834. package/dist/domain/spec/expressions/index.d.ts +5 -0
  835. package/dist/domain/spec/expressions/memo-eval-plan.d.ts +70 -0
  836. package/dist/domain/spec/expressions/memo-eval-plan.js +1 -0
  837. package/dist/domain/spec/expressions/relation-expression-params.js +1 -0
  838. package/dist/domain/spec/index.d.ts +4 -0
  839. package/dist/domain/spec/index.js +1 -0
  840. package/dist/domain/spec/invariants/index.d.ts +2 -0
  841. package/dist/domain/spec/invariants/index.js +1 -0
  842. package/dist/domain/spec/invariants/invariant.d.ts +24 -0
  843. package/dist/domain/spec/invariants/invariant.js +1 -0
  844. package/dist/domain/spec/invariants/invariants.d.ts +14 -0
  845. package/dist/domain/spec/invariants/invariants.js +1 -0
  846. package/dist/domain/spec/json-schema.d.ts +52 -0
  847. package/dist/domain/spec/json-schema.js +1 -0
  848. package/dist/domain/spec/markers/index.d.ts +3 -0
  849. package/dist/domain/spec/markers/index.js +1 -0
  850. package/dist/domain/spec/markers/msg-marker.d.ts +28 -0
  851. package/dist/domain/spec/markers/msg-marker.js +1 -0
  852. package/dist/domain/spec/model/aliases.d.ts +9 -0
  853. package/dist/domain/spec/model/aliases.js +1 -0
  854. package/dist/domain/spec/model/common-types.d.ts +15 -0
  855. package/dist/domain/spec/model/common-types.js +1 -0
  856. package/dist/domain/spec/model/defaults.d.ts +33 -0
  857. package/dist/domain/spec/model/defaults.js +1 -0
  858. package/dist/domain/spec/model/entity-types.d.ts +8 -0
  859. package/dist/domain/spec/model/entity-types.js +1 -0
  860. package/dist/domain/spec/model/index.d.ts +7 -0
  861. package/dist/domain/spec/model/index.js +1 -0
  862. package/dist/domain/spec/model/model-version-key.d.ts +3 -0
  863. package/dist/domain/spec/model/model-version-key.js +1 -0
  864. package/dist/domain/spec/model/names/action-name.d.ts +7 -0
  865. package/dist/domain/spec/model/names/action-name.js +1 -0
  866. package/dist/domain/spec/model/names/alias-name.d.ts +7 -0
  867. package/dist/domain/spec/model/names/alias-name.js +1 -0
  868. package/dist/domain/spec/model/names/entity-or-alias-name.d.ts +8 -0
  869. package/dist/domain/spec/model/names/entity-or-alias-name.js +1 -0
  870. package/dist/domain/spec/model/names/entity-type-name.d.ts +8 -0
  871. package/dist/domain/spec/model/names/entity-type-name.js +1 -0
  872. package/dist/domain/spec/model/names/expression-name.d.ts +6 -0
  873. package/dist/domain/spec/model/names/expression-name.js +1 -0
  874. package/dist/domain/spec/model/names/index.d.ts +9 -0
  875. package/dist/domain/spec/model/names/index.js +1 -0
  876. package/dist/domain/spec/model/names/instance-name.d.ts +7 -0
  877. package/dist/domain/spec/model/names/instance-name.js +1 -0
  878. package/dist/domain/spec/model/names/invariant-name.d.ts +3 -0
  879. package/dist/domain/spec/model/names/invariant-name.js +1 -0
  880. package/dist/domain/spec/model/names/shape-property-name.d.ts +11 -0
  881. package/dist/domain/spec/model/names/shape-property-name.js +1 -0
  882. package/dist/domain/spec/model/names/violation-type-name.d.ts +3 -0
  883. package/dist/domain/spec/model/names/violation-type-name.js +1 -0
  884. package/dist/domain/spec/model/presets.d.ts +30 -0
  885. package/dist/domain/spec/model/presets.js +1 -0
  886. package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/element-registration.d.ts +16 -2
  887. package/dist/domain/spec/modules/element-registration.js +1 -0
  888. package/dist/domain/spec/modules/find-assistant-form-element-errors.d.ts +12 -0
  889. package/dist/domain/spec/modules/find-assistant-form-element-errors.js +1 -0
  890. package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/index.d.ts +4 -3
  891. package/dist/domain/spec/modules/index.js +1 -0
  892. package/dist/domain/spec/modules/merge-expression-modules.d.ts +23 -0
  893. package/dist/domain/spec/modules/merge-expression-modules.js +1 -0
  894. package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/project-modules.d.ts +1 -1
  895. package/dist/domain/spec/modules/project-modules.js +1 -0
  896. package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/resolve-action-modules.d.ts +1 -1
  897. package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/resolve-component-optic-modules.d.ts +1 -1
  898. package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/resolve-expression-modules.d.ts +4 -5
  899. package/dist/domain/spec/modules/resolve-expression-modules.js +1 -0
  900. package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/resolve-invariant-modules.d.ts +1 -1
  901. package/dist/domain/spec/phx/index.d.ts +1 -0
  902. package/dist/domain/spec/phx/index.js +1 -0
  903. package/dist/domain/spec/phx/phx-application-types.d.ts +25 -0
  904. package/dist/domain/spec/phx/phx-application-types.js +1 -0
  905. package/dist/domain/spec/phx/phx-domain.d.ts +36 -0
  906. package/dist/domain/spec/phx/phx-domain.js +1 -0
  907. package/dist/domain/spec/phx/phx-model.d.ts +24 -0
  908. package/dist/domain/spec/phx/phx-model.js +1 -0
  909. package/dist/domain/spec/phx/phx.d.ts +21 -0
  910. package/dist/domain/spec/phx/phx.js +1 -0
  911. package/dist/domain/spec/runtime/admin-runtime/admin-runtime.d.ts +32 -0
  912. package/dist/domain/spec/runtime/admin-runtime/admin-runtime.js +1 -0
  913. package/dist/domain/spec/runtime/admin-runtime/admin-spec-runtime.d.ts +16 -0
  914. package/dist/domain/spec/runtime/admin-runtime/admin-spec-runtime.js +1 -0
  915. package/dist/domain/spec/runtime/admin-runtime/index.d.ts +2 -0
  916. package/dist/domain/spec/runtime/admin-runtime/index.js +1 -0
  917. package/dist/{application-spec/generate-application → domain/spec}/runtime/admin-runtime/states-runtime.d.ts +1 -1
  918. package/dist/{application-spec/generate-application → domain/spec}/runtime/application-runtime.d.ts +23 -8
  919. package/dist/domain/spec/runtime/application-runtime.js +1 -0
  920. package/dist/domain/spec/runtime/application-spec-slice.d.ts +73 -0
  921. package/dist/domain/spec/runtime/application-spec-slice.js +1 -0
  922. package/dist/domain/spec/runtime/configurator-runtime/configurator-runtime.d.ts +37 -0
  923. package/dist/domain/spec/runtime/configurator-runtime/configurator-runtime.js +1 -0
  924. package/dist/domain/spec/runtime/configurator-runtime/configurator-spec-runtime.d.ts +16 -0
  925. package/dist/domain/spec/runtime/configurator-runtime/configurator-spec-runtime.js +1 -0
  926. package/dist/domain/spec/runtime/configurator-runtime/index.d.ts +2 -0
  927. package/dist/domain/spec/runtime/configurator-runtime/index.js +1 -0
  928. package/dist/{application-spec/generate-application → domain/spec}/runtime/configurator-runtime/states-runtime.d.ts +1 -1
  929. package/dist/domain/spec/runtime/create-application.d.ts +58 -0
  930. package/dist/domain/spec/runtime/create-application.js +1 -0
  931. package/dist/{application-spec/generate-application/runtime/sections → domain/spec/runtime/expressions}/expression-runtime.d.ts +13 -5
  932. package/dist/domain/spec/runtime/expressions/expression-runtime.js +1 -0
  933. package/dist/{application-spec/generate-application/runtime/sections → domain/spec/runtime/expressions}/generate-memo-eval-plan-runtime.d.ts +2 -2
  934. package/dist/domain/spec/runtime/expressions/generate-memo-eval-plan-runtime.js +1 -0
  935. package/dist/domain/spec/runtime/expressions/index.d.ts +3 -0
  936. package/dist/domain/spec/runtime/expressions/index.js +1 -0
  937. package/dist/{application-spec/generate-application/runtime/sections → domain/spec/runtime/expressions}/reflection-constants-runtime.d.ts +2 -1
  938. package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/factory-data-runtime.d.ts +4 -3
  939. package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/recipe-defaults.d.ts +1 -1
  940. package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/recipe-defaults.js +1 -1
  941. package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/static-violations.d.ts +2 -2
  942. package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/static-violations.js +1 -1
  943. package/dist/{application-spec/generate-application → domain/spec}/runtime/generate-runtime-instance.d.ts +1 -1
  944. package/dist/domain/spec/runtime/generate-runtime-instance.js +1 -0
  945. package/dist/domain/spec/runtime/index.d.ts +13 -0
  946. package/dist/domain/spec/runtime/index.js +1 -0
  947. package/dist/{application-spec/generate-application → domain/spec}/runtime/migrations/migration-runtime.d.ts +2 -2
  948. package/dist/domain/spec/runtime/migrations/migration-runtime.js +1 -0
  949. package/dist/{application-spec/generate-application/runtime/admin-runtime → domain/spec/runtime/model}/admin-model-runtime.d.ts +6 -5
  950. package/dist/domain/spec/runtime/model/admin-model-runtime.js +1 -0
  951. package/dist/{application-spec/generate-application/runtime/configurator-runtime → domain/spec/runtime/model}/configurator-model-runtime.d.ts +6 -5
  952. package/dist/domain/spec/runtime/model/configurator-model-runtime.js +1 -0
  953. package/dist/domain/spec/runtime/model/index.d.ts +2 -0
  954. package/dist/domain/spec/runtime/model/index.js +1 -0
  955. package/dist/domain/spec/runtime/optics/build-sdk-optic.d.ts +7 -0
  956. package/dist/domain/spec/runtime/optics/build-sdk-optic.js +1 -0
  957. package/dist/domain/spec/runtime/optics/build-user-bound-optic.d.ts +7 -0
  958. package/dist/domain/spec/runtime/optics/build-user-bound-optic.js +1 -0
  959. package/dist/domain/spec/runtime/optics/built-component-optic.d.ts +11 -0
  960. package/dist/domain/spec/runtime/optics/built-component-optic.js +1 -0
  961. package/dist/{application-spec/generate-application/runtime/sections → domain/spec/runtime/optics}/component-optic.d.ts +4 -14
  962. package/dist/domain/spec/runtime/optics/index.d.ts +2 -0
  963. package/dist/domain/spec/runtime/optics/index.js +1 -0
  964. package/dist/{application-spec/caching → domain/spec/runtime}/runtime-reference-store.d.ts +1 -5
  965. package/dist/domain/spec/runtime/runtime-reference-store.js +1 -0
  966. package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/actions-runtime.d.ts +3 -3
  967. package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/assistant-runtime.d.ts +2 -2
  968. package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/data-runtime.d.ts +1 -1
  969. package/dist/domain/spec/runtime/sections/index.d.ts +6 -0
  970. package/dist/domain/spec/runtime/sections/index.js +1 -0
  971. package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/preset-runtime.d.ts +4 -4
  972. package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/theme-runtime.d.ts +1 -1
  973. package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/transformers-runtime.d.ts +2 -2
  974. package/dist/{application-spec/generate-application → domain/spec}/runtime/spec-code/resolve-spec-code.d.ts +1 -1
  975. package/dist/domain/spec/runtime/spec-code/spec-code-module.js +1 -0
  976. package/dist/domain/spec/runtime/spec-runtime.d.ts +21 -0
  977. package/dist/domain/spec/runtime/spec-runtime.js +1 -0
  978. package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/encoded-runtime-spec.d.ts +3 -2
  979. package/dist/domain/spec/runtime-spec/index.d.ts +4 -0
  980. package/dist/domain/spec/runtime-spec/index.js +1 -0
  981. package/dist/domain/spec/runtime-spec/runtime-spec.d.ts +174 -0
  982. package/dist/domain/spec/runtime-spec/runtime-spec.js +1 -0
  983. package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/spec-code-id.d.ts +1 -1
  984. package/dist/domain/spec/sections/actions.d.ts +23 -0
  985. package/dist/domain/spec/sections/actions.js +1 -0
  986. package/dist/domain/spec/sections/app-metadata.d.ts +18 -0
  987. package/dist/domain/spec/sections/app-metadata.js +1 -0
  988. package/dist/domain/spec/sections/application-version.d.ts +7 -0
  989. package/dist/domain/spec/sections/application-version.js +1 -0
  990. package/dist/domain/{application → spec/sections}/assistant/assistant-manifest.d.ts +29 -4
  991. package/dist/domain/{application → spec/sections}/assistant/assistant-resolved-manifest.d.ts +12 -9
  992. package/dist/domain/spec/sections/assistant/assistant-resolved-manifest.js +1 -0
  993. package/dist/domain/spec/sections/assistant/form/assistant-form-element-name.d.ts +11 -0
  994. package/dist/domain/spec/sections/assistant/form/assistant-form-element-name.js +8 -0
  995. package/dist/domain/{application → spec/sections}/assistant/form/assistant-form-elements.d.ts +39 -28
  996. package/dist/domain/spec/sections/assistant/form/assistant-form-elements.js +1 -0
  997. package/dist/domain/{application → spec/sections}/assistant/form/index.d.ts +1 -1
  998. package/dist/domain/spec/sections/assistant/form/index.js +1 -0
  999. package/dist/domain/spec/sections/assistant/index.d.ts +4 -0
  1000. package/dist/domain/spec/sections/assistant/index.js +1 -0
  1001. package/dist/domain/spec/sections/data-spec/chunks.d.ts +23 -0
  1002. package/dist/domain/spec/sections/data-spec/chunks.js +1 -0
  1003. package/dist/domain/spec/sections/data-spec/custom-data-spec-entry.d.ts +16 -0
  1004. package/dist/domain/spec/sections/data-spec/custom-data-spec-entry.js +1 -0
  1005. package/dist/domain/spec/sections/data-spec/data-entry-key.d.ts +9 -0
  1006. package/dist/domain/spec/sections/data-spec/data-entry-key.js +1 -0
  1007. package/dist/domain/spec/sections/data-spec/index.d.ts +5 -0
  1008. package/dist/domain/spec/sections/data-spec/index.js +1 -0
  1009. package/dist/domain/spec/sections/data-spec/parsed-data-spec-entries.d.ts +10 -0
  1010. package/dist/domain/spec/sections/data-spec/parsed-data-spec-entries.js +1 -0
  1011. package/dist/domain/spec/sections/data-spec/swatch-data-spec-entry.d.ts +14 -0
  1012. package/dist/domain/spec/sections/data-spec/swatch-data-spec-entry.js +1 -0
  1013. package/dist/domain/spec/sections/index.d.ts +10 -0
  1014. package/dist/domain/spec/sections/index.js +1 -0
  1015. package/dist/domain/spec/sections/infra/acl.d.ts +12 -0
  1016. package/dist/domain/spec/sections/infra/acl.js +1 -0
  1017. package/dist/domain/spec/sections/infra/index.d.ts +3 -0
  1018. package/dist/domain/spec/sections/infra/index.js +1 -0
  1019. package/dist/domain/spec/sections/infra/resource-entry.d.ts +46 -0
  1020. package/dist/domain/spec/sections/infra/resource-entry.js +1 -0
  1021. package/dist/domain/spec/sections/infra/resources-config.d.ts +10 -0
  1022. package/dist/domain/spec/sections/infra/resources-config.js +1 -0
  1023. package/dist/domain/spec/sections/state-value.d.ts +7 -0
  1024. package/dist/domain/spec/sections/state-value.js +1 -0
  1025. package/dist/domain/spec/sections/theme.d.ts +10 -0
  1026. package/dist/domain/spec/sections/theme.js +1 -0
  1027. package/dist/domain/spec/sections/transformers.d.ts +15 -0
  1028. package/dist/domain/spec/sections/transformers.js +1 -0
  1029. package/dist/domain/spec/sections/ui.d.ts +12 -0
  1030. package/dist/domain/spec/sections/ui.js +1 -0
  1031. package/dist/domain/system-components/phoenix-entity-elements/child-entity-card-selector.d.ts +2 -3
  1032. package/dist/domain/system-components/phoenix-entity-elements/child-entity-list-selector.d.ts +2 -3
  1033. package/dist/domain/system-components/phoenix-entity-elements/child-entity-toggle-selector.d.ts +2 -3
  1034. package/dist/domain/system-definitions.js +1 -1
  1035. package/dist/domain/utils/index.d.ts +2 -0
  1036. package/dist/domain/utils/index.js +1 -0
  1037. package/dist/editor/domain-editors/DomainSpecContext.js +1 -1
  1038. package/dist/editor/domain-editors/apply-spec-update.d.ts +10 -2
  1039. package/dist/editor/domain-editors/apply-spec-update.js +1 -1
  1040. package/dist/editor/domain-editors/use-implementation-files.d.ts +6 -14
  1041. package/dist/editor/domain-editors/use-implementation-files.js +1 -1
  1042. package/dist/editor/graphql/GraphQLPanel.js +1 -1
  1043. package/dist/editor/screenshot/ScreenshotHandler.js +1 -1
  1044. package/dist/i18n/locales/cs/messages.js +1 -1
  1045. package/dist/i18n/locales/da/messages.js +1 -1
  1046. package/dist/i18n/locales/de/messages.js +1 -1
  1047. package/dist/i18n/locales/de-AT/messages.js +1 -1
  1048. package/dist/i18n/locales/en/messages.js +1 -1
  1049. package/dist/i18n/locales/en-AU/messages.js +1 -1
  1050. package/dist/i18n/locales/en-GB/messages.js +1 -1
  1051. package/dist/i18n/locales/es/messages.js +1 -1
  1052. package/dist/i18n/locales/fr/messages.js +1 -1
  1053. package/dist/i18n/locales/hu/messages.js +1 -1
  1054. package/dist/i18n/locales/it/messages.js +1 -1
  1055. package/dist/i18n/locales/nl/messages.js +1 -1
  1056. package/dist/i18n/locales/pl/messages.js +1 -1
  1057. package/dist/i18n/locales/pt/messages.js +1 -1
  1058. package/dist/i18n/locales/ro/messages.js +1 -1
  1059. package/dist/i18n/locales/sk/messages.js +1 -1
  1060. package/dist/i18n/locales/tr/messages.js +1 -1
  1061. package/dist/legacy/domain-cli/utils/cache.d.ts +1 -1
  1062. package/dist/legacy/domain-cli/utils/cache.js +1 -1
  1063. package/dist/legacy/domain-spec/__generated/domain-schema.d.ts +16 -0
  1064. package/dist/legacy/domain-spec/spec/domain-spec.js +1 -1
  1065. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/claude-md.d.ts +1 -1
  1066. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/cursor-rules.d.ts +1 -1
  1067. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.d.ts +1 -1
  1068. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.js +11 -5
  1069. package/dist/legacy/phoenix-cli/services/webhook-service/transport.js +1 -1
  1070. package/dist/legacy/phoenix-cli/services/webhook-service/tunnel.d.ts +1 -0
  1071. package/dist/legacy/phoenix-cli/services/webhook-service/tunnel.js +1 -1
  1072. package/dist/legacy/webhook-cli/lambda-local/index.js +1 -1
  1073. package/dist/phoenix/application-spec/application-spec-builder.js +1 -1
  1074. package/dist/phoenix/application-spec/generate-application-spec-project.d.ts +1 -0
  1075. package/dist/phoenix/application-spec/generate-application-spec-project.js +2 -2
  1076. package/dist/phoenix/application-spec/generate-project-files.d.ts +1 -0
  1077. package/dist/phoenix/application-spec/index.d.ts +2 -0
  1078. package/dist/phoenix/application-spec/index.js +1 -1
  1079. package/dist/phoenix/application-spec/project-files.d.ts +8 -2
  1080. package/dist/phoenix/application-spec/project-files.js +1 -1
  1081. package/dist/phoenix/application-spec/resolve-deployment-data.d.ts +11 -0
  1082. package/dist/phoenix/application-spec/resolve-deployment-data.js +2 -2
  1083. package/dist/phoenix/bin.js +1 -1
  1084. package/dist/phoenix/cli.js +1 -1
  1085. package/dist/phoenix/commands/activate-deployment.js +1 -1
  1086. package/dist/phoenix/commands/build.js +1 -1
  1087. package/dist/phoenix/commands/changelog.js +1 -1
  1088. package/dist/phoenix/commands/check.js +1 -1
  1089. package/dist/phoenix/commands/clean.js +1 -1
  1090. package/dist/phoenix/commands/cleanup-environment.js +2 -2
  1091. package/dist/phoenix/commands/create-environment.js +1 -1
  1092. package/dist/phoenix/commands/data.js +1 -1
  1093. package/dist/phoenix/commands/deploy.js +3 -3
  1094. package/dist/phoenix/commands/deployment-build-envs-command.js +1 -1
  1095. package/dist/phoenix/commands/dev.js +4 -5
  1096. package/dist/phoenix/commands/docs.js +1 -1
  1097. package/dist/phoenix/commands/finish-deployment-command.js +1 -1
  1098. package/dist/phoenix/commands/fix.js +1 -1
  1099. package/dist/phoenix/commands/index.d.ts +1 -1
  1100. package/dist/phoenix/commands/index.js +1 -1
  1101. package/dist/phoenix/commands/inspect-assets.js +1 -1
  1102. package/dist/phoenix/commands/list-environments.js +1 -1
  1103. package/dist/phoenix/commands/login.d.ts +4 -1
  1104. package/dist/phoenix/commands/login.js +2 -2
  1105. package/dist/phoenix/commands/prepare-deployment-command.js +2 -2
  1106. package/dist/phoenix/commands/register-deployment.js +1 -1
  1107. package/dist/phoenix/commands/scene.js +1 -1
  1108. package/dist/phoenix/commands/screenshot.js +1 -1
  1109. package/dist/phoenix/commands/state.js +1 -1
  1110. package/dist/phoenix/commands/story-build.js +3 -3
  1111. package/dist/phoenix/commands/story-create.js +1 -1
  1112. package/dist/phoenix/commands/story-dev.js +2 -2
  1113. package/dist/phoenix/commands/sync.js +1 -1
  1114. package/dist/phoenix/commands/variants.js +1 -1
  1115. package/dist/phoenix/editor-server/commands-router.js +1 -1
  1116. package/dist/phoenix/editor-server/editor-server.d.ts +2 -13
  1117. package/dist/phoenix/editor-server/editor-server.js +1 -1
  1118. package/dist/phoenix/editor-server/spec-router.js +1 -1
  1119. package/dist/phoenix/editor-server/trpc.d.ts +2 -12
  1120. package/dist/phoenix/lingui/index.d.ts +1 -0
  1121. package/dist/phoenix/lingui/index.js +1 -0
  1122. package/dist/phoenix/lingui/lingui.d.ts +18 -0
  1123. package/dist/phoenix/lingui/lingui.js +1 -0
  1124. package/dist/phoenix/scripts/docs-utils.js +1 -1
  1125. package/dist/phoenix/services/application-spec-project-watcher.d.ts +11 -6
  1126. package/dist/phoenix/services/application-spec-project-watcher.js +2 -2
  1127. package/dist/phoenix/services/cli-credentials.d.ts +3 -0
  1128. package/dist/phoenix/services/cli-credentials.js +1 -1
  1129. package/dist/phoenix/services/cli-exit.d.ts +5 -0
  1130. package/dist/phoenix/services/cli-exit.js +1 -0
  1131. package/dist/phoenix/services/deployment/deployment-preparation-service.d.ts +28 -0
  1132. package/dist/phoenix/services/deployment/deployment-preparation-service.js +1 -0
  1133. package/dist/phoenix/{commands → services/deployment}/generated-env-markers.d.ts +1 -0
  1134. package/dist/phoenix/services/deployment/generated-env-markers.js +1 -0
  1135. package/dist/phoenix/services/deployment/index.d.ts +2 -0
  1136. package/dist/phoenix/services/deployment/index.js +1 -0
  1137. package/dist/phoenix/services/index.d.ts +5 -1
  1138. package/dist/phoenix/services/index.js +1 -1
  1139. package/dist/phoenix/services/lingui-watcher.js +1 -1
  1140. package/dist/phoenix/services/phoenix-store.d.ts +3 -0
  1141. package/dist/phoenix/services/phoenix-store.js +1 -1
  1142. package/dist/phoenix/services/prepare-development-environment.js +1 -1
  1143. package/dist/phoenix/services/session/editor-server-handle.d.ts +5 -0
  1144. package/dist/phoenix/services/session/editor-server-handle.js +1 -0
  1145. package/dist/phoenix/services/session/index.d.ts +2 -0
  1146. package/dist/phoenix/services/session/index.js +1 -0
  1147. package/dist/phoenix/services/session/phoenix-application.d.ts +82 -0
  1148. package/dist/phoenix/services/session/phoenix-application.js +2 -0
  1149. package/dist/phoenix/services/source-archive.d.ts +2 -0
  1150. package/dist/phoenix/services/source-archive.js +1 -1
  1151. package/dist/phoenix/services/swc.d.ts +5 -4
  1152. package/dist/phoenix/services/swc.js +2 -2
  1153. package/dist/phoenix/services/telemetry/amplitude-telemetry-transport.d.ts +9 -0
  1154. package/dist/phoenix/services/telemetry/amplitude-telemetry-transport.js +1 -0
  1155. package/dist/phoenix/services/telemetry/index.d.ts +3 -0
  1156. package/dist/phoenix/services/telemetry/index.js +1 -0
  1157. package/dist/phoenix/services/telemetry/telemetry-client.d.ts +25 -0
  1158. package/dist/phoenix/services/telemetry/telemetry-client.js +1 -0
  1159. package/dist/phoenix/services/telemetry/telemetry-command.d.ts +2 -0
  1160. package/dist/phoenix/services/telemetry/telemetry-command.js +1 -0
  1161. package/dist/phoenix/services/telemetry/telemetry-event.d.ts +44 -0
  1162. package/dist/phoenix/services/telemetry/telemetry-event.js +1 -0
  1163. package/dist/phoenix/services/telemetry/telemetry-state.d.ts +25 -0
  1164. package/dist/phoenix/services/telemetry/telemetry-state.js +2 -0
  1165. package/dist/phoenix/services/vite-config.js +1 -1
  1166. package/dist/phoenix/services/webhook-service/transport.js +1 -1
  1167. package/dist/phoenix/services/webhook-service/tunnel.d.ts +1 -0
  1168. package/dist/phoenix/services/webhook-service/tunnel.js +1 -1
  1169. package/dist/react-sdk/application-runtime/common-services/analytics/analytics-service.d.ts +1 -1
  1170. package/dist/react-sdk/application-runtime/common-services/initialize.d.ts +2 -2
  1171. package/dist/react-sdk/application-runtime/domain-application-context/chat-system.d.ts +1 -1
  1172. package/dist/react-sdk/application-runtime/hooks/index.d.ts +2 -0
  1173. package/dist/react-sdk/application-runtime/hooks/index.js +1 -1
  1174. package/dist/react-sdk/application-runtime/hooks/loading/index.d.ts +5 -0
  1175. package/dist/react-sdk/application-runtime/hooks/loading/index.js +1 -0
  1176. package/dist/react-sdk/application-runtime/hooks/loading/loader-host-context.d.ts +11 -0
  1177. package/dist/react-sdk/application-runtime/hooks/loading/loader-host-context.js +1 -0
  1178. package/dist/react-sdk/application-runtime/hooks/loading/use-is-awaiting-loading-phase.d.ts +8 -0
  1179. package/dist/react-sdk/application-runtime/hooks/loading/use-is-awaiting-loading-phase.js +1 -0
  1180. package/dist/react-sdk/application-runtime/hooks/loading/use-is-loader-hosted.d.ts +7 -0
  1181. package/dist/react-sdk/application-runtime/hooks/loading/use-is-loader-hosted.js +1 -0
  1182. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-actions.d.ts +9 -0
  1183. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-actions.js +1 -0
  1184. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-application.d.ts +24 -0
  1185. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-application.js +1 -0
  1186. package/dist/react-sdk/application-runtime/hooks/responsive/index.d.ts +3 -0
  1187. package/dist/react-sdk/application-runtime/hooks/responsive/index.js +1 -0
  1188. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-actions.d.ts +9 -0
  1189. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-actions.js +1 -0
  1190. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-application.d.ts +26 -0
  1191. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-application.js +1 -0
  1192. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-state.d.ts +10 -0
  1193. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-state.js +1 -0
  1194. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-store.d.ts +24 -0
  1195. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-store.js +1 -0
  1196. package/dist/react-sdk/application-runtime/hooks/use-access-service.d.ts +5 -0
  1197. package/dist/react-sdk/application-runtime/hooks/use-access-service.js +1 -1
  1198. package/dist/react-sdk/application-runtime/hooks/use-phoenix-element-slots.d.ts +2 -1
  1199. package/dist/react-sdk/application-runtime/hooks/use-web-component-readonly-sync.d.ts +4 -11
  1200. package/dist/react-sdk/application-runtime/hooks/use-web-component-readonly-sync.js +1 -1
  1201. package/dist/react-sdk/application-runtime/hooks/use-web-component.d.ts +5 -0
  1202. package/dist/react-sdk/application-runtime/hooks/use-web-component.js +1 -1
  1203. package/dist/react-sdk/application-runtime/host-properties/actions.d.ts +15 -0
  1204. package/dist/react-sdk/application-runtime/host-properties/actions.js +1 -0
  1205. package/dist/react-sdk/application-runtime/host-properties/connect-host-properties.d.ts +30 -0
  1206. package/dist/react-sdk/application-runtime/host-properties/connect-host-properties.js +1 -0
  1207. package/dist/react-sdk/application-runtime/host-properties/domain-host-properties.d.ts +7 -0
  1208. package/dist/react-sdk/application-runtime/host-properties/domain-host-properties.js +1 -0
  1209. package/dist/react-sdk/application-runtime/host-properties/host-property-descriptors.d.ts +21 -0
  1210. package/dist/react-sdk/application-runtime/host-properties/host-property-descriptors.js +1 -0
  1211. package/dist/react-sdk/application-runtime/host-properties/host-property-scopes.d.ts +42 -0
  1212. package/dist/react-sdk/application-runtime/host-properties/host-property-scopes.js +1 -0
  1213. package/dist/react-sdk/application-runtime/host-properties/index.d.ts +8 -0
  1214. package/dist/react-sdk/application-runtime/host-properties/index.js +1 -0
  1215. package/dist/react-sdk/application-runtime/host-properties/initialize.d.ts +7 -0
  1216. package/dist/react-sdk/application-runtime/host-properties/initialize.js +1 -0
  1217. package/dist/react-sdk/application-runtime/host-properties/selectors.d.ts +54 -0
  1218. package/dist/react-sdk/application-runtime/host-properties/selectors.js +1 -0
  1219. package/dist/react-sdk/application-runtime/host-properties/types.d.ts +18 -0
  1220. package/dist/react-sdk/application-runtime/host-properties/types.js +1 -0
  1221. package/dist/react-sdk/application-runtime/index.d.ts +3 -0
  1222. package/dist/react-sdk/application-runtime/integration/initialize.d.ts +7 -6
  1223. package/dist/react-sdk/application-runtime/integration/initialize.js +1 -1
  1224. package/dist/react-sdk/application-runtime/integration/selectors.d.ts +11 -2
  1225. package/dist/react-sdk/application-runtime/integration/selectors.js +1 -1
  1226. package/dist/react-sdk/application-runtime/integration/types.d.ts +5 -2
  1227. package/dist/react-sdk/application-runtime/loading/actions.d.ts +45 -0
  1228. package/dist/react-sdk/application-runtime/loading/actions.js +1 -0
  1229. package/dist/react-sdk/application-runtime/loading/index.d.ts +4 -0
  1230. package/dist/react-sdk/application-runtime/loading/index.js +1 -0
  1231. package/dist/react-sdk/application-runtime/loading/initialize.d.ts +3 -0
  1232. package/dist/react-sdk/application-runtime/loading/initialize.js +1 -0
  1233. package/dist/react-sdk/application-runtime/loading/selectors.d.ts +18 -0
  1234. package/dist/react-sdk/application-runtime/loading/selectors.js +1 -0
  1235. package/dist/react-sdk/application-runtime/loading/types.d.ts +59 -0
  1236. package/dist/react-sdk/application-runtime/loading/types.js +1 -0
  1237. package/dist/react-sdk/application-runtime/mocks/create-mock-application-runtime.js +1 -1
  1238. package/dist/react-sdk/application-runtime/provider/ApplicationRuntime.d.ts +6 -0
  1239. package/dist/react-sdk/application-runtime/provider/ApplicationRuntime.js +1 -1
  1240. package/dist/react-sdk/application-runtime/provider/ApplicationType.d.ts +7 -0
  1241. package/dist/react-sdk/application-runtime/provider/ApplicationType.js +1 -1
  1242. package/dist/react-sdk/application-runtime/responsive/actions.d.ts +47 -0
  1243. package/dist/react-sdk/application-runtime/responsive/actions.js +1 -0
  1244. package/dist/react-sdk/application-runtime/responsive/index.d.ts +4 -0
  1245. package/dist/react-sdk/application-runtime/responsive/index.js +1 -0
  1246. package/dist/react-sdk/application-runtime/responsive/initialize.d.ts +3 -0
  1247. package/dist/react-sdk/application-runtime/responsive/initialize.js +1 -0
  1248. package/dist/react-sdk/application-runtime/responsive/selectors.d.ts +20 -0
  1249. package/dist/react-sdk/application-runtime/responsive/selectors.js +1 -0
  1250. package/dist/react-sdk/application-runtime/responsive/types.d.ts +104 -0
  1251. package/dist/react-sdk/application-runtime/responsive/types.js +1 -0
  1252. package/dist/react-sdk/application-runtime/routing/routing-service.d.ts +34 -2
  1253. package/dist/react-sdk/application-runtime/routing/routing-service.js +1 -1
  1254. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.d.ts +313 -10
  1255. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.js +1 -1
  1256. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/ConfiguratorRoutingProvider.d.ts +1 -1
  1257. package/dist/react-sdk/configurator-routing/ConfiguratorRoutingProvider.js +1 -0
  1258. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/OnGoToIndexHandler.d.ts +1 -2
  1259. package/dist/react-sdk/configurator-routing/OnGoToIndexHandler.js +1 -0
  1260. package/dist/react-sdk/configurator-routing/index.d.ts +3 -0
  1261. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/index.js +1 -1
  1262. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/use-power-routing-lifecycle.d.ts +2 -0
  1263. package/dist/react-sdk/configurator-routing/use-power-routing-lifecycle.js +1 -0
  1264. package/dist/react-sdk/configurator-ui-elements/ConfiguratorUiElementHost.d.ts +7 -0
  1265. package/dist/react-sdk/configurator-ui-elements/ConfiguratorUiElementHost.js +1 -0
  1266. package/dist/react-sdk/configurator-ui-elements/ErrorFallbackElement.d.ts +14 -0
  1267. package/dist/react-sdk/configurator-ui-elements/ErrorFallbackElement.js +1 -0
  1268. package/dist/react-sdk/configurator-ui-elements/ErrorFallbackPropsProvider.d.ts +18 -0
  1269. package/dist/react-sdk/configurator-ui-elements/ErrorFallbackPropsProvider.js +1 -0
  1270. package/dist/react-sdk/configurator-ui-elements/PlainErrorFallback.d.ts +5 -0
  1271. package/dist/react-sdk/configurator-ui-elements/PlainErrorFallback.js +1 -0
  1272. package/dist/react-sdk/configurator-ui-elements/configurator-ui-element.d.ts +17 -0
  1273. package/dist/react-sdk/configurator-ui-elements/configurator-ui-element.js +1 -0
  1274. package/dist/react-sdk/configurator-ui-elements/create-configurator-ui-element.d.ts +5 -0
  1275. package/dist/react-sdk/configurator-ui-elements/create-configurator-ui-element.js +1 -0
  1276. package/dist/react-sdk/configurator-ui-elements/index.d.ts +6 -0
  1277. package/dist/react-sdk/configurator-ui-elements/index.js +1 -0
  1278. package/dist/react-sdk/domain-application-context/BackendDataProvider.js +1 -1
  1279. package/dist/react-sdk/domain-application-context/ConfigurationPersistSystemFailureHandler.js +1 -1
  1280. package/dist/react-sdk/domain-application-context/FrontendDataProvider.js +1 -1
  1281. package/dist/react-sdk/domain-application-context/OnPresetLoadedHandler.js +1 -0
  1282. package/dist/react-sdk/domain-application-context/PublishedDataProvider.js +1 -1
  1283. package/dist/react-sdk/domain-application-context/chat-hooks.d.ts +4 -0
  1284. package/dist/react-sdk/domain-application-context/chat-hooks.js +1 -0
  1285. package/dist/react-sdk/domain-application-context/index.d.ts +2 -0
  1286. package/dist/react-sdk/domain-application-context/index.js +1 -1
  1287. package/dist/react-sdk/domain-context/common-hooks/index.d.ts +1 -0
  1288. package/dist/react-sdk/domain-context/common-hooks/index.js +1 -1
  1289. package/dist/react-sdk/domain-context/common-hooks/use-configuration-save-state.d.ts +23 -0
  1290. package/dist/react-sdk/domain-context/common-hooks/use-configuration-save-state.js +1 -0
  1291. package/dist/react-sdk/domain-context/common-hooks/use-domain-context.d.ts +1 -0
  1292. package/dist/react-sdk/domain-context/common-hooks/use-state-validity.d.ts +7 -1
  1293. package/dist/react-sdk/domain-context/index.d.ts +1 -0
  1294. package/dist/react-sdk/domain-context/index.js +1 -1
  1295. package/dist/react-sdk/domain-controls/ChildEntityCardSelector.d.ts +2 -3
  1296. package/dist/react-sdk/domain-controls/ChildEntityListSelector.d.ts +2 -3
  1297. package/dist/react-sdk/domain-controls/ChildEntityToggleSelector.d.ts +2 -3
  1298. package/dist/react-sdk/domain-controls/hooks/use-cook-replace-recipes.d.ts +2 -2
  1299. package/dist/react-sdk/elements/PhoenixEntityElement.js +1 -1
  1300. package/dist/react-sdk/elements/PhoenixLayoutElement.js +1 -1
  1301. package/dist/react-sdk/elements/index.d.ts +0 -1
  1302. package/dist/react-sdk/index.d.ts +8 -1
  1303. package/dist/react-sdk/index.js +1 -1
  1304. package/dist/react-sdk/integration/IntegrationSubscription.js +1 -0
  1305. package/dist/react-sdk/integration/index.d.ts +1 -0
  1306. package/dist/react-sdk/integration/index.js +1 -0
  1307. package/dist/react-sdk/lifecycle-providers/ConfiguratorDataProvider.d.ts +8 -0
  1308. package/dist/react-sdk/lifecycle-providers/ConfiguratorDataProvider.js +1 -0
  1309. package/dist/react-sdk/lifecycle-providers/LifecycleProviders.js +1 -0
  1310. package/dist/react-sdk/lifecycle-providers/index.d.ts +2 -0
  1311. package/dist/react-sdk/lifecycle-providers/index.js +1 -0
  1312. package/dist/react-sdk/loading-state/LoaderHost.d.ts +20 -0
  1313. package/dist/react-sdk/loading-state/LoaderHost.js +1 -0
  1314. package/dist/react-sdk/loading-state/built-in-loading-phase.d.ts +9 -0
  1315. package/dist/react-sdk/loading-state/built-in-loading-phase.js +1 -0
  1316. package/dist/react-sdk/loading-state/create-app-loader.d.ts +18 -0
  1317. package/dist/react-sdk/loading-state/create-app-loader.js +1 -0
  1318. package/dist/react-sdk/loading-state/index.d.ts +4 -2
  1319. package/dist/react-sdk/loading-state/index.js +1 -1
  1320. package/dist/react-sdk/loading-state/{LoadingStateProvider.d.ts → loading-state-hooks.d.ts} +3 -12
  1321. package/dist/react-sdk/loading-state/loading-state-hooks.js +1 -0
  1322. package/dist/react-sdk/notifications/index.d.ts +1 -0
  1323. package/dist/react-sdk/notifications/index.js +1 -0
  1324. package/dist/react-sdk/notifications/snackbar-action-button.d.ts +30 -0
  1325. package/dist/react-sdk/notifications/snackbar-action-button.js +1 -0
  1326. package/dist/react-sdk/page-elements/ConfigurationNotFoundPagePropsProvider.d.ts +17 -0
  1327. package/dist/react-sdk/page-elements/ConfigurationNotFoundPagePropsProvider.js +1 -0
  1328. package/dist/react-sdk/page-elements/ConfiguratorErrorPagePropsProvider.d.ts +17 -0
  1329. package/dist/react-sdk/page-elements/ConfiguratorErrorPagePropsProvider.js +1 -0
  1330. package/dist/react-sdk/page-elements/configurator-error-page-props.js +1 -0
  1331. package/dist/{configurator/configuration-not-found-page → react-sdk/page-elements}/create-configuration-not-found-page.d.ts +7 -1
  1332. package/dist/react-sdk/page-elements/create-configuration-not-found-page.js +1 -0
  1333. package/dist/{configurator/configurator-error-page → react-sdk/page-elements}/create-configurator-error-page.d.ts +6 -1
  1334. package/dist/react-sdk/page-elements/create-configurator-error-page.js +1 -0
  1335. package/dist/react-sdk/page-elements/create-preset-ui.d.ts +9 -0
  1336. package/dist/react-sdk/page-elements/create-preset-ui.js +1 -0
  1337. package/dist/react-sdk/page-elements/index.d.ts +6 -0
  1338. package/dist/react-sdk/page-elements/index.js +1 -0
  1339. package/dist/react-sdk/preset-selection/PresetSelectionProvider.js +1 -0
  1340. package/dist/react-sdk/preset-selection/index.d.ts +1 -0
  1341. package/dist/react-sdk/preset-selection/index.js +1 -0
  1342. package/dist/react-sdk/provider-slots/ConfiguratorProviderSlotHost.d.ts +11 -0
  1343. package/dist/react-sdk/provider-slots/ConfiguratorProviderSlotHost.js +1 -0
  1344. package/dist/react-sdk/provider-slots/configurator-provider-slot.d.ts +24 -0
  1345. package/dist/react-sdk/provider-slots/configurator-provider-slot.js +1 -0
  1346. package/dist/react-sdk/provider-slots/create-configurator-provider-slot.d.ts +5 -0
  1347. package/dist/react-sdk/provider-slots/create-configurator-provider-slot.js +1 -0
  1348. package/dist/react-sdk/provider-slots/index.d.ts +3 -0
  1349. package/dist/react-sdk/provider-slots/index.js +1 -0
  1350. package/dist/react-sdk/session/SessionServiceProvider.d.ts +5 -0
  1351. package/dist/react-sdk/session/SessionServiceProvider.js +1 -1
  1352. package/dist/react-sdk/web-component/create-web-component.js +1 -1
  1353. package/dist/react-sdk/web-component/god-mode/god-mode-registry.d.ts +30 -0
  1354. package/dist/react-sdk/web-component/god-mode/god-mode-registry.js +1 -0
  1355. package/dist/react-sdk/web-component/god-mode/index.d.ts +1 -0
  1356. package/dist/react-sdk/web-component/god-mode/index.js +1 -0
  1357. package/dist/ui-sdk/components/numerical-input/InputField.d.ts +2 -0
  1358. package/dist/ui-sdk/components/numerical-input/InputField.js +1 -1
  1359. package/dist/ui-sdk/components/numerical-input/NumericalInput.d.ts +2 -2
  1360. package/dist/ui-sdk/components/numerical-input/Slider.d.ts +3 -1
  1361. package/dist/ui-sdk/components/numerical-input/Slider.js +1 -1
  1362. package/dist/ui-sdk/components/snackbar/Snackbar.d.ts +24 -3
  1363. package/dist/ui-sdk/components/snackbar/Snackbar.js +1 -1
  1364. package/dist/ui-sdk/icons/__generated/ChatCircleText.d.ts +3 -0
  1365. package/dist/ui-sdk/icons/__generated/ChatCircleText.js +1 -0
  1366. package/dist/ui-sdk/icons/__generated/Paperclip.d.ts +3 -0
  1367. package/dist/ui-sdk/icons/__generated/Paperclip.js +1 -0
  1368. package/dist/ui-sdk/icons/__generated/PencilSimpleLine.d.ts +3 -0
  1369. package/dist/ui-sdk/icons/__generated/PencilSimpleLine.js +1 -0
  1370. package/dist/ui-sdk/icons/__generated/index.d.ts +6 -0
  1371. package/dist/ui-sdk/icons/__generated/index.js +1 -1
  1372. package/dist/ui-sdk/icons/icons-registry.js +1 -1
  1373. package/dist/ui-sdk/responsive-application/ResponsiveApplicationProvider.d.ts +2 -2
  1374. package/dist/ui-sdk/responsive-application/responsive-state-store.d.ts +11 -9
  1375. package/dist/ui-sdk/responsive-application/use-store-responsive-info.js +1 -1
  1376. package/dist/ui-sdk/theme/types.d.ts +5 -1
  1377. package/dist/watch/glob-matcher.d.ts +4 -4
  1378. package/dist/watch/glob-matcher.js +1 -1
  1379. package/dist/watch/watch.d.ts +4 -4
  1380. package/dist/watch/watch.js +1 -1
  1381. package/package.json +13 -3
  1382. package/schema/domain-spec.json +158 -0
  1383. package/dist/application-spec/caching/runtime-reference-store.js +0 -1
  1384. package/dist/application-spec/core/components/index.d.ts +0 -2
  1385. package/dist/application-spec/core/expressions/index.d.ts +0 -2
  1386. package/dist/application-spec/generate-application/code/templates/skills/phoenix-cli-skill.d.ts +0 -1
  1387. package/dist/application-spec/generate-application/code/templates/skills/phoenix-cli-skill.js +0 -1
  1388. package/dist/application-spec/generate-application/code/templates/skills/phoenix-create-configurator-skill.d.ts +0 -3
  1389. package/dist/application-spec/generate-application/code/templates/skills/phoenix-create-configurator-skill.js +0 -166
  1390. package/dist/application-spec/generate-application/code/templates/skills/phoenix-feedback-skill.d.ts +0 -1
  1391. package/dist/application-spec/generate-application/code/templates/skills/phoenix-feedback-skill.js +0 -54
  1392. package/dist/application-spec/generate-application/code/templates/skills/phoenix-review-skill.d.ts +0 -1
  1393. package/dist/application-spec/generate-application/code/templates/skills/phoenix-review-skill.js +0 -115
  1394. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill.js +0 -1
  1395. package/dist/application-spec/generate-application/code/templates/skills/phoenix-variants-skill.d.ts +0 -1
  1396. package/dist/application-spec/generate-application/code/templates/skills/phoenix-variants-skill.js +0 -6
  1397. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-model-runtime.js +0 -1
  1398. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-runtime.d.ts +0 -28
  1399. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-runtime.js +0 -1
  1400. package/dist/application-spec/generate-application/runtime/application-runtime.js +0 -1
  1401. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-model-runtime.js +0 -1
  1402. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.d.ts +0 -37
  1403. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.js +0 -1
  1404. package/dist/application-spec/generate-application/runtime/generate-runtime-instance.js +0 -1
  1405. package/dist/application-spec/generate-application/runtime/migrations/migration-runtime.js +0 -1
  1406. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.d.ts +0 -8
  1407. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.js +0 -1
  1408. package/dist/application-spec/generate-application/runtime/sections/build-user-bound-optic.d.ts +0 -8
  1409. package/dist/application-spec/generate-application/runtime/sections/build-user-bound-optic.js +0 -1
  1410. package/dist/application-spec/generate-application/runtime/sections/expression-runtime.js +0 -1
  1411. package/dist/application-spec/generate-application/runtime/sections/generate-memo-eval-plan-runtime.js +0 -1
  1412. package/dist/application-spec/generate-application/runtime/sections/index.d.ts +0 -10
  1413. package/dist/application-spec/generate-application/runtime/sections/index.js +0 -1
  1414. package/dist/application-spec/generate-application/runtime-spec/index.d.ts +0 -5
  1415. package/dist/application-spec/generate-application/runtime-spec/index.js +0 -1
  1416. package/dist/application-spec/generate-application/runtime-spec/runtime-spec.d.ts +0 -68
  1417. package/dist/application-spec/generate-application/runtime-spec/runtime-spec.js +0 -1
  1418. package/dist/configurator/app-loader-content/app-loader-content-name.d.ts +0 -5
  1419. package/dist/configurator/app-loader-content/app-loader-content-name.js +0 -1
  1420. package/dist/configurator/application-runtime/extensions/systems/assistant-system/browser-details.d.ts +0 -17
  1421. package/dist/configurator/application-runtime/extensions/systems/assistant-system/browser-details.js +0 -1
  1422. package/dist/configurator/configuration-not-found-page/create-configuration-not-found-page.js +0 -1
  1423. package/dist/configurator/configurator-context/ConfiguratorDataProvider.d.ts +0 -2
  1424. package/dist/configurator/configurator-context/ConfiguratorDataProvider.js +0 -1
  1425. package/dist/configurator/configurator-context/ConfiguratorResponsiveProvider.js +0 -1
  1426. package/dist/configurator/configurator-context/IntegrationSubscription.js +0 -1
  1427. package/dist/configurator/configurator-context/LifecycleProviders.js +0 -1
  1428. package/dist/configurator/configurator-context/OnPresetLoadedHandler.js +0 -1
  1429. package/dist/configurator/configurator-context/PresetSelectionProvider.js +0 -1
  1430. package/dist/configurator/configurator-context/configurator-hooks/chat-hooks.d.ts +0 -1
  1431. package/dist/configurator/configurator-context/configurator-hooks/chat-hooks.js +0 -1
  1432. package/dist/configurator/configurator-context/configurator-routing/ConfiguratorRoutingProvider.js +0 -1
  1433. package/dist/configurator/configurator-context/configurator-routing/OnGoToIndexHandler.js +0 -1
  1434. package/dist/configurator/configurator-context/configurator-routing/index.d.ts +0 -2
  1435. package/dist/configurator/configurator-context/configurator-routing/use-power-routing-lifecycle.js +0 -1
  1436. package/dist/configurator/configurator-error-page/create-configurator-error-page.js +0 -1
  1437. package/dist/configurator/ui/assistant/form/built-in-form-registry.d.ts +0 -10
  1438. package/dist/configurator/ui/assistant/form/built-in-form-registry.js +0 -1
  1439. package/dist/configurator/ui/assistant/form/form-registry.js +0 -8
  1440. package/dist/domain/application/assistant/form/assistant-form-elements.js +0 -1
  1441. package/dist/domain/application/assistant/form/get-assistant-form-value-attribute.d.ts +0 -6
  1442. package/dist/domain/application/assistant/form/get-assistant-form-value-attribute.js +0 -1
  1443. package/dist/domain/application/assistant/form/index.js +0 -1
  1444. package/dist/domain/available-system-components.d.ts +0 -11
  1445. package/dist/domain/available-system-components.js +0 -1
  1446. package/dist/domain/domain-builder.js +0 -1
  1447. package/dist/domain/domain-runtime/spec/module-checks/element-registration.js +0 -1
  1448. package/dist/domain/domain-runtime/spec/module-checks/index.js +0 -1
  1449. package/dist/domain/domain-runtime/spec/module-checks/project-modules.js +0 -1
  1450. package/dist/domain/domain-runtime/spec/module-checks/resolve-expression-modules.js +0 -1
  1451. package/dist/domain/domain-runtime/spec/module-checks/resolve-imported-transformers.js +0 -1
  1452. package/dist/domain/extensions/client-side-image.js +0 -1
  1453. package/dist/domain/extensions/save-template-thumbnail.js +0 -1
  1454. package/dist/phoenix/commands/generated-env-markers.js +0 -1
  1455. package/dist/phoenix/services/lingui.d.ts +0 -15
  1456. package/dist/phoenix/services/lingui.js +0 -1
  1457. package/dist/phoenix/services/phoenix-application.d.ts +0 -21
  1458. package/dist/phoenix/services/phoenix-application.js +0 -1
  1459. package/dist/react-sdk/application-runtime/runtime/god-mode.d.ts +0 -19
  1460. package/dist/react-sdk/application-runtime/runtime/god-mode.js +0 -1
  1461. package/dist/react-sdk/loading-state/LoadingStateProvider.js +0 -1
  1462. package/dist/react-sdk/loading-state/loading-state-manager.d.ts +0 -37
  1463. package/dist/react-sdk/loading-state/loading-state-manager.js +0 -1
  1464. package/dist/react-sdk/responsive-state/ResponsiveStateProvider.d.ts +0 -25
  1465. package/dist/react-sdk/responsive-state/ResponsiveStateProvider.js +0 -1
  1466. package/dist/react-sdk/responsive-state/canvas-padding.d.ts +0 -14
  1467. package/dist/react-sdk/responsive-state/index.d.ts +0 -5
  1468. package/dist/react-sdk/responsive-state/index.js +0 -1
  1469. package/dist/react-sdk/responsive-state/responsive-state-manager.d.ts +0 -111
  1470. package/dist/react-sdk/responsive-state/responsive-state-manager.js +0 -1
  1471. package/dist/react-sdk/responsive-state/use-responsive-state-manager.d.ts +0 -10
  1472. package/dist/react-sdk/responsive-state/use-responsive-state-manager.js +0 -1
  1473. package/dist/react-sdk/responsive-state/use-responsive-state.d.ts +0 -11
  1474. package/dist/react-sdk/responsive-state/use-responsive-state.js +0 -1
  1475. /package/dist/{application-spec/core/expressions/relation-expression-params.js → configurator/application-runtime/extensions/systems/assistant-system/assistant-annotation.js} +0 -0
  1476. /package/dist/{application-spec/generate-application/runtime/spec-code/spec-code-module.js → domain/spec/application/admin-pages-section.js} +0 -0
  1477. /package/dist/{application-spec/parse-application-files/spec/components/component-entry.js → domain/spec/application/admin-pages.js} +0 -0
  1478. /package/dist/{application-spec/parse-application-files/spec/expressions/expression.js → domain/spec/application/admin-states.js} +0 -0
  1479. /package/dist/{application-spec/core → domain/spec/application}/application-instance.d.ts +0 -0
  1480. /package/dist/{application-spec/core → domain/spec/application}/application-instance.js +0 -0
  1481. /package/dist/{configurator/ui/assistant/form/form-element-definition.js → domain/spec/application/configurator-states.js} +0 -0
  1482. /package/dist/domain/{application/assistant/assistant-manifest.js → spec/components/bindings/index.js} +0 -0
  1483. /package/dist/{react-sdk/elements/configurator-error-page-props.js → domain/spec/components/bindings/read-binding.js} +0 -0
  1484. /package/dist/{react-sdk/responsive-state/canvas-padding.js → domain/spec/components/bindings/write-binding.js} +0 -0
  1485. /package/dist/{application-spec/core → domain/spec}/components/component-filter.js +0 -0
  1486. /package/dist/{application-spec/core → domain/spec}/components/index.js +0 -0
  1487. /package/dist/{application-spec/core → domain/spec}/components/sdk-code-ref.d.ts +0 -0
  1488. /package/dist/{application-spec/core → domain/spec}/components/sdk-code-ref.js +0 -0
  1489. /package/dist/domain/{domain-runtime → spec}/errors/implementation-error.d.ts +0 -0
  1490. /package/dist/domain/{domain-runtime → spec}/errors/implementation-error.js +0 -0
  1491. /package/dist/domain/{domain-runtime → spec}/errors/implementation-errors.d.ts +0 -0
  1492. /package/dist/domain/{domain-runtime → spec}/errors/implementation-errors.js +0 -0
  1493. /package/dist/domain/{domain-runtime → spec}/errors/index.d.ts +0 -0
  1494. /package/dist/domain/{domain-runtime → spec}/errors/index.js +0 -0
  1495. /package/dist/domain/{domain-runtime → spec}/errors/to-implementation-errors.d.ts +0 -0
  1496. /package/dist/domain/{domain-runtime → spec}/errors/to-implementation-errors.js +0 -0
  1497. /package/dist/{application-spec/core → domain/spec}/expressions/index.js +0 -0
  1498. /package/dist/{application-spec/core → domain/spec}/expressions/relation-expression-params.d.ts +0 -0
  1499. /package/dist/{application-spec/core → domain/spec}/expressions/sdk-expression-implementation.d.ts +0 -0
  1500. /package/dist/{application-spec/core → domain/spec}/expressions/sdk-expression-implementation.js +0 -0
  1501. /package/dist/{application-spec/parse-application-files/spec/components → domain/spec/markers}/component-prop-target.d.ts +0 -0
  1502. /package/dist/{application-spec/parse-application-files/spec/components → domain/spec/markers}/component-prop-target.js +0 -0
  1503. /package/dist/{application-spec/core → domain/spec}/markers/eval-marker.d.ts +0 -0
  1504. /package/dist/{application-spec/core → domain/spec}/markers/eval-marker.js +0 -0
  1505. /package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/handler-registration.d.ts +0 -0
  1506. /package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/handler-registration.js +0 -0
  1507. /package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/resolve-action-modules.js +0 -0
  1508. /package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/resolve-component-optic-modules.js +0 -0
  1509. /package/dist/domain/{domain-runtime/spec/module-checks → spec/modules}/resolve-invariant-modules.js +0 -0
  1510. /package/dist/{application-spec/generate-application → domain/spec}/runtime/admin-runtime/states-runtime.js +0 -0
  1511. /package/dist/{application-spec/generate-application → domain/spec}/runtime/configurator-runtime/states-runtime.js +0 -0
  1512. /package/dist/{application-spec/generate-application/runtime/sections → domain/spec/runtime/expressions}/reflection-constants-runtime.js +0 -0
  1513. /package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/factory-data-runtime.js +0 -0
  1514. /package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/index.d.ts +0 -0
  1515. /package/dist/{application-spec/generate-application → domain/spec}/runtime/factory-data/index.js +0 -0
  1516. /package/dist/{application-spec/generate-application → domain/spec}/runtime/migrations/index.d.ts +0 -0
  1517. /package/dist/{application-spec/generate-application → domain/spec}/runtime/migrations/index.js +0 -0
  1518. /package/dist/{application-spec/generate-application/runtime/sections → domain/spec/runtime/optics}/component-optic.js +0 -0
  1519. /package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/actions-runtime.js +0 -0
  1520. /package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/assistant-runtime.js +0 -0
  1521. /package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/data-runtime.js +0 -0
  1522. /package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/preset-runtime.js +0 -0
  1523. /package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/theme-runtime.js +0 -0
  1524. /package/dist/{application-spec/generate-application → domain/spec}/runtime/sections/transformers-runtime.js +0 -0
  1525. /package/dist/{application-spec/generate-application → domain/spec}/runtime/spec-code/index.d.ts +0 -0
  1526. /package/dist/{application-spec/generate-application → domain/spec}/runtime/spec-code/index.js +0 -0
  1527. /package/dist/{application-spec/generate-application → domain/spec}/runtime/spec-code/resolve-spec-code.js +0 -0
  1528. /package/dist/{application-spec/generate-application → domain/spec}/runtime/spec-code/spec-code-module.d.ts +0 -0
  1529. /package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/decode-runtime-spec.d.ts +0 -0
  1530. /package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/decode-runtime-spec.js +0 -0
  1531. /package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/encode-runtime-spec.d.ts +0 -0
  1532. /package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/encode-runtime-spec.js +0 -0
  1533. /package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/encoded-runtime-spec.js +0 -0
  1534. /package/dist/{application-spec/generate-application → domain/spec}/runtime-spec/spec-code-id.js +0 -0
  1535. /package/dist/domain/{application/assistant/assistant-resolved-manifest.js → spec/sections/assistant/assistant-manifest.js} +0 -0
  1536. /package/dist/domain/{application → spec/sections}/assistant/form/assistant-resource-path.d.ts +0 -0
  1537. /package/dist/domain/{application → spec/sections}/assistant/form/assistant-resource-path.js +0 -0
  1538. /package/dist/{configurator/configurator-context → react-sdk/domain-application-context}/OnPresetLoadedHandler.d.ts +0 -0
  1539. /package/dist/{configurator/configurator-context → react-sdk/integration}/IntegrationSubscription.d.ts +0 -0
  1540. /package/dist/{configurator/configurator-context → react-sdk/lifecycle-providers}/LifecycleProviders.d.ts +0 -0
  1541. /package/dist/react-sdk/{elements → page-elements}/configurator-error-page-props.d.ts +0 -0
  1542. /package/dist/{configurator/configurator-context → react-sdk/preset-selection}/PresetSelectionProvider.d.ts +0 -0
@@ -0,0 +1,2657 @@
1
+ # Sunfold Solar
2
+
3
+ Help a household decide on a system by showing what it would do for them. A solar installer, Sunfold, lets a homeowner plan panels and a battery for their roof: the roof's area and direction, the number of panels, the battery, the tariff and the home's yearly use. The page answers with a dashboard: four figures, the solar year month by month, the year the system pays for itself, and how much of the power the home uses. Every figure is an expression of the spec, so the dashboard changes the moment an input does, and **Book a home survey** is a finalize action. There is no 3D model; the tiles and charts are React and hand-written SVG.
4
+
5
+ - [Try it](#try-it)
6
+ - [What the example demonstrates](#what-the-example-demonstrates)
7
+ - [A dashboard instead of a scene](#a-dashboard-instead-of-a-scene)
8
+ - [Every figure is an expression](#every-figure-is-an-expression)
9
+ - [Figures on tiles](#figures-on-tiles)
10
+ - [Charts in SVG](#charts-in-svg)
11
+ - [A warning and a notice](#a-warning-and-a-notice)
12
+ - [Book a home survey](#book-a-home-survey)
13
+ - [On a phone](#on-a-phone)
14
+ - [Test cases](#test-cases)
15
+ - [What this layout leaves out](#what-this-layout-leaves-out)
16
+ - [Related pages](#related-pages)
17
+ - [Complete Implementation](#complete-implementation)
18
+
19
+ ## Try it
20
+
21
+ The phone version is under [On a phone](#on-a-phone).
22
+
23
+ ## What the example demonstrates
24
+
25
+ | Piece | Where |
26
+ | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
27
+ | A `ConfiguratorLayout` that mounts no `LayoutSlots.SharedCanvas` | [A dashboard instead of a scene](#a-dashboard-instead-of-a-scene) |
28
+ | Numbers and series declared in `expressions:` and read with `phx.frontend.useRootEntityState()` | [Every figure is an expression](#every-figure-is-an-expression) |
29
+ | KPI tiles | `KpiTiles`, [Figures on tiles](#figures-on-tiles) |
30
+ | A stacked column chart with a line, a payback curve and a split bar, with tooltips | `MonthlyEnergyChart`, `PaybackChart`, `EnergySplitBar`, [Charts in SVG](#charts-in-svg) |
31
+ | A `warning` that blocks finalizing beside a `notice` that does not | `PlannerInputs`, [A warning and a notice](#a-warning-and-a-notice) |
32
+ | `phx.frontend.useFinalizeActions()` for the spec's `survey` action | `SurveyPanel`, [Book a home survey](#book-a-home-survey) |
33
+
34
+ ## A dashboard instead of a scene
35
+
36
+ `src/elements/ConfiguratorLayout.tsx` mounts the services and a page, never `LayoutSlots.SharedCanvas`, so no scene loads and the app loader does not wait for one. On a desktop the inputs are a sidebar with the cost and the booking at its foot, and the dashboard fills the rest; on a phone everything is one scrolling column with the cost in a bar at the bottom.
37
+
38
+ ```tsx
39
+ import { Box } from '@mui/material'
40
+
41
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
42
+
43
+ import { DesktopPage } from '../_shared/DesktopPage.js'
44
+ import { PhonePage } from '../_shared/PhonePage.js'
45
+ import { SUNFOLD } from '../_shared/tokens.js'
46
+
47
+ // A planning dashboard with no scene: the layout never mounts `LayoutSlots.SharedCanvas`, and every tile and chart is
48
+ // React and SVG drawn from the spec's expressions
49
+ const ConfiguratorLayout = () => {
50
+ // `null` until the container has been measured
51
+ const viewports = phx.frontend.useActiveViewports()
52
+ const isDesktop = viewports?.includes('desktop') ?? false
53
+
54
+ return (
55
+ <Box component="div" sx={{ position: 'absolute', inset: 0, overflow: 'clip', bgcolor: SUNFOLD.linen }}>
56
+ <LayoutSlots.Services />
57
+ {viewports !== null && (isDesktop ? <DesktopPage /> : <PhonePage />)}
58
+ </Box>
59
+ )
60
+ }
61
+
62
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
63
+ ```
64
+
65
+ ## Every figure is an expression
66
+
67
+ The dashboard computes nothing itself. The system's size, its production month by month, how the production splits between the home and the grid, the yearly saving, the cost and the money returned year by year are expressions of the root entity. Declaring them in `expressions:` gives them their types, so the layout reads `$monthly` as an array of months and `$cumulativeSavings` as an array of numbers with `phx.frontend.useRootEntityState()`.
68
+
69
+ ```yaml
70
+ expressions:
71
+ SolarPlan:
72
+ $systemKwp:
73
+ type: number
74
+ $roofPanelLimit:
75
+ type: number
76
+ $panelAreaM2:
77
+ type: number
78
+ $annualProductionKwh:
79
+ type: number
80
+ $monthly:
81
+ type: array
82
+ items:
83
+ type: object
84
+ properties:
85
+ month:
86
+ type: string
87
+ productionKwh:
88
+ type: number
89
+ consumptionKwh:
90
+ type: number
91
+ selfUseKwh:
92
+ type: number
93
+ exportKwh:
94
+ type: number
95
+ required:
96
+ - month
97
+ - productionKwh
98
+ - consumptionKwh
99
+ - selfUseKwh
100
+ - exportKwh
101
+ additionalProperties: false
102
+ $selfConsumption:
103
+ type: number
104
+ $selfSufficiency:
105
+ type: number
106
+ $annualSavings:
107
+ type: number
108
+ $systemCost:
109
+ type: number
110
+ $cumulativeSavings:
111
+ type: array
112
+ items:
113
+ type: number
114
+ $paybackYears:
115
+ type: number
116
+ $co2Tonnes:
117
+ type: number
118
+ ```
119
+
120
+ The model in `src/expressions/solar.ts` is deliberately simple: a south-facing kWp yields 1,000 kWh a year, spread over the months by a typical central European sun curve. Without a battery the home uses solar power only while the sun shines; a battery carries the day's surplus into the evening. The saving counts the power the home no longer buys and the power it sells, and the running total grows with prices rising 2 % a year while the panels lose half a percent.
121
+
122
+ ```ts
123
+ const PANEL_KWP = 0.43
124
+ const PANEL_AREA_M2 = 1.95
125
+ // Vents, chimneys and the edge clearance leave about 85 % of a roof for panels
126
+ const USABLE_ROOF = 0.85
127
+ // A south-facing kWp in central Europe yields about 1,000 kWh a year
128
+ const YIELD_KWH_PER_KWP = 1000
129
+ const ORIENTATION_FACTOR = { South: 1, SouthEastWest: 0.95, EastWest: 0.82, North: 0.6 }
130
+
131
+ const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
132
+ // The share of the year's sun and of the household's use that falls in each month
133
+ const SUN_SHARE = [0.04, 0.045, 0.08, 0.105, 0.125, 0.13, 0.13, 0.115, 0.09, 0.065, 0.04, 0.035]
134
+ const USE_SHARE = [0.1, 0.09, 0.088, 0.08, 0.075, 0.07, 0.07, 0.072, 0.076, 0.085, 0.094, 0.1]
135
+ const DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
136
+
137
+ const BATTERY_KWH = { None: 0, Kwh5: 5, Kwh10: 10, Kwh15: 15 }
138
+ const BATTERY_PRICE = { None: 0, Kwh5: 3600, Kwh10: 6400, Kwh15: 8900 }
139
+ const TARIFF = {
140
+ Flat: { buy: 0.32, sell: 0.08, shiftBonus: 0 },
141
+ TimeOfUse: { buy: 0.29, sell: 0.1, shiftBonus: 0.09 },
142
+ ExportPlus: { buy: 0.32, sell: 0.15, shiftBonus: 0 },
143
+ }
144
+ // Panels lose half a percent a year; electricity gets 2 % dearer a year
145
+ const DEGRADATION = 0.995
146
+ const PRICE_GROWTH = 1.02
147
+ const YEARS = 25
148
+
149
+ export default phx.domain.implementCustomExpressions({
150
+ SolarPlan: {
151
+ $systemKwp: s => {
152
+ return s.panels * PANEL_KWP
153
+ },
154
+ $roofPanelLimit: s => {
155
+ return Math.floor((s.roofArea * USABLE_ROOF) / PANEL_AREA_M2)
156
+ },
157
+ // The roof the panels cover, rounded up to whole square metres, as the tiles and the roof warning quote it
158
+ $panelAreaM2: s => {
159
+ return Math.ceil(s.panels * PANEL_AREA_M2)
160
+ },
161
+ $annualProductionKwh: s => {
162
+ return s.$systemKwp * YIELD_KWH_PER_KWP * ORIENTATION_FACTOR[s.orientation]
163
+ },
164
+ // Each month's production and use, and how the production splits between the home and the grid. Without a
165
+ // battery the home uses solar power only while the sun shines; a battery carries the surplus into the evening,
166
+ // one charge a day, and covers the evening but not the early morning.
167
+ $monthly: s => {
168
+ const batteryKwh = BATTERY_KWH[s.battery] * 0.9
169
+
170
+ return MONTHS.map((month, index) => {
171
+ const productionKwh = s.$annualProductionKwh * (SUN_SHARE[index] ?? 0)
172
+ const consumptionKwh = s.annualUse * (USE_SHARE[index] ?? 0)
173
+ const direct = Math.min(productionKwh * 0.55, consumptionKwh * 0.45)
174
+ const stored = Math.min(
175
+ productionKwh - direct,
176
+ batteryKwh * (DAYS[index] ?? 30),
177
+ (consumptionKwh - direct) * 0.6
178
+ )
179
+ const selfUseKwh = direct + stored
180
+
181
+ return { month, productionKwh, consumptionKwh, selfUseKwh, exportKwh: productionKwh - selfUseKwh }
182
+ })
183
+ },
184
+ $selfConsumption: s => {
185
+ const selfUse = s.$monthly.reduce((sum, month) => sum + month.selfUseKwh, 0)
186
+
187
+ return s.$annualProductionKwh > 0 ? selfUse / s.$annualProductionKwh : 0
188
+ },
189
+ $selfSufficiency: s => {
190
+ const selfUse = s.$monthly.reduce((sum, month) => sum + month.selfUseKwh, 0)
191
+
192
+ return selfUse / s.annualUse
193
+ },
194
+ // A year's saving: power the home no longer buys, power sold to the grid, and on a time-of-use tariff the
195
+ // evening power a battery shifts away from the dear hours
196
+ $annualSavings: s => {
197
+ const tariff = TARIFF[s.tariff]
198
+ const selfUse = s.$monthly.reduce((sum, month) => sum + month.selfUseKwh, 0)
199
+ const exported = s.$monthly.reduce((sum, month) => sum + month.exportKwh, 0)
200
+ const shifted = s.battery === 'None' ? 0 : selfUse * 0.4
201
+
202
+ return selfUse * tariff.buy + exported * tariff.sell + shifted * tariff.shiftBonus
203
+ },
204
+ $systemCost: s => {
205
+ return Math.round(1500 + s.$systemKwp * 1050 + BATTERY_PRICE[s.battery])
206
+ },
207
+ // The money the system has returned at the end of each year, starting at minus its cost in year 0
208
+ $cumulativeSavings: s => {
209
+ return Array.from({ length: YEARS + 1 }, (_, year) => {
210
+ const earned = Array.from(
211
+ { length: year },
212
+ (__, past) => s.$annualSavings * (PRICE_GROWTH * DEGRADATION) ** past
213
+ ).reduce((sum, value) => sum + value, 0)
214
+
215
+ return earned - s.$systemCost
216
+ })
217
+ },
218
+ // The year the running total crosses zero, between whole years; beyond the panels' 25 years it is `Infinity`
219
+ $paybackYears: s => {
220
+ const totals = s.$cumulativeSavings
221
+ const year = totals.findIndex(total => total >= 0)
222
+
223
+ if (year <= 0) {
224
+ return year === 0 ? 0 : Infinity
225
+ }
226
+
227
+ const before = totals[year - 1] ?? 0
228
+ const after = totals[year] ?? 0
229
+
230
+ return year - 1 + -before / (after - before)
231
+ },
232
+ $co2Tonnes: s => {
233
+ return (s.$annualProductionKwh * 0.35) / 1000
234
+ },
235
+ },
236
+ })
237
+ ```
238
+
239
+ The cost is the `price` component's value, so `phx.frontend.useRootEntityPrice()` formats it in euros:
240
+
241
+ ```yaml
242
+ components:
243
+ SolarPlan:
244
+ price:
245
+ main:
246
+ price:
247
+ $read: $systemCost
248
+ currency: EUR
249
+ ```
250
+
251
+ ## Figures on tiles
252
+
253
+ `KpiTiles` shows the four figures a household asks first, each with the context that makes it mean something: the panels and roof behind the system size, the CO₂ behind the production, what the self-consumption share means, and the first year's saving behind the payback.
254
+
255
+ ```tsx
256
+ import { Box, Typography } from '@mui/material'
257
+
258
+ import { CARD_SX, SUNFOLD } from './tokens.js'
259
+
260
+ const euro = (value: number) => {
261
+ return value.toLocaleString('en-IE', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 })
262
+ }
263
+
264
+ interface KpiTilesProps {
265
+ readonly columns: number
266
+ }
267
+
268
+ // The four figures a household asks first, each with the context that makes it mean something. Every value is an
269
+ // expression of the spec, read from the root entity.
270
+ export const KpiTiles = ({ columns }: KpiTilesProps) => {
271
+ const plan = phx.frontend.useRootEntityState()
272
+ const payback = plan.$paybackYears
273
+ const tiles = [
274
+ {
275
+ label: 'System size',
276
+ value: `${plan.$systemKwp.toFixed(1)} kWp`,
277
+ context: `${plan.panels} panels, ${plan.$panelAreaM2} m² of roof`,
278
+ },
279
+ {
280
+ label: 'Annual production',
281
+ value: `${Math.round(plan.$annualProductionKwh).toLocaleString('en')} kWh`,
282
+ context: `About ${plan.$co2Tonnes.toFixed(1)} t of CO₂ avoided a year`,
283
+ },
284
+ {
285
+ label: 'Self-consumption',
286
+ value: `${Math.round(plan.$selfConsumption * 100)} %`,
287
+ context: 'of the solar power is used at home',
288
+ },
289
+ {
290
+ label: 'Payback',
291
+ value: Number.isFinite(payback) ? `${payback.toFixed(1)} years` : 'Over 25 years',
292
+ context: `${euro(plan.$annualSavings)} saved in the first year`,
293
+ },
294
+ ]
295
+
296
+ return (
297
+ <Box component="div" sx={{ display: 'grid', gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, gap: 2 }}>
298
+ {tiles.map(tile => (
299
+ <Box
300
+ component="section"
301
+ key={tile.label}
302
+ aria-label={tile.label}
303
+ sx={{ ...CARD_SX, display: 'grid', gap: 0.5, padding: 2 }}
304
+ >
305
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 13, color: SUNFOLD.muted }}>{tile.label}</Typography>
306
+ <Typography
307
+ sx={{
308
+ fontFamily: SUNFOLD.font,
309
+ fontSize: columns > 2 ? 30 : 24,
310
+ fontWeight: 600,
311
+ lineHeight: 1.15,
312
+ color: SUNFOLD.ink,
313
+ }}
314
+ >
315
+ {tile.value}
316
+ </Typography>
317
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>{tile.context}</Typography>
318
+ </Box>
319
+ ))}
320
+ </Box>
321
+ )
322
+ }
323
+ ```
324
+
325
+ ## Charts in SVG
326
+
327
+ The charts are hand-written SVG; the example adds no chart library. Each chart measures its width with a `ResizeObserver` and draws its text at its real size.
328
+
329
+ - **Your solar year.** `MonthlyEnergyChart` draws each month's production as a column split into what the home uses and what goes to the grid, with a 2-pixel gap between the parts and a rounded top, and the home's use as a line across it. A legend names the three series, hovering a month shows its figures, and **Show figures** swaps the chart for a table of the same numbers.
330
+ - **When it pays back.** `PaybackChart` draws `$cumulativeSavings`, which starts at minus the system's cost, marks the year it crosses zero, and reads off any year under the pointer.
331
+ - **Where the power goes.** `EnergySplitBar` splits a year of production between the home and the grid, and says how much of the home's use solar covers.
332
+
333
+ The series colours are a fixed set checked together for colour-vision deficiencies; two are lighter than 3:1 against white, which is why every chart also has a legend, a tooltip or the figures written out.
334
+
335
+ ```tsx
336
+ import { Box, ButtonBase, Typography } from '@mui/material'
337
+ import { useState } from 'react'
338
+
339
+ import { CHART, SERIES } from './chart-style.js'
340
+ import { niceScale } from './nice-scale.js'
341
+ import { useWidth } from './use-width.js'
342
+
343
+ const MARGIN = { top: 12, right: 8, bottom: 26, left: 48 }
344
+ const GAP = 2
345
+ const RADIUS = 4
346
+
347
+ const kwh = (value: number) => {
348
+ return `${Math.round(value).toLocaleString('en')} kWh`
349
+ }
350
+
351
+ // A column segment whose top corners are rounded, so the stack ends in a 4px data-end and stays square at the
352
+ // baseline
353
+ const roundedTop = (x: number, y: number, width: number, height: number) => {
354
+ const r = Math.min(RADIUS, height, width / 2)
355
+
356
+ return `M${x},${y + height} V${y + r} Q${x},${y} ${x + r},${y} H${x + width - r} Q${x + width},${y} ${x + width},${y + r} V${y + height} Z`
357
+ }
358
+
359
+ const LEGEND = [
360
+ { key: 'selfUse', label: 'Solar used at home', color: SERIES.selfUse, line: false },
361
+ { key: 'exported', label: 'Solar sent to the grid', color: SERIES.exported, line: false },
362
+ { key: 'consumption', label: 'Home use', color: SERIES.consumption, line: true },
363
+ ]
364
+
365
+ interface MonthlyEnergyChartProps {
366
+ readonly height: number
367
+ }
368
+
369
+ // Each month's solar production as a column split into what the home uses and what goes to the grid, with the
370
+ // home's use as a line across it. All figures come from the spec's `$monthly` expression. Hovering a month shows its
371
+ // figures; "Show figures" swaps the chart for a table of the same numbers.
372
+ export const MonthlyEnergyChart = ({ height }: MonthlyEnergyChartProps) => {
373
+ const plan = phx.frontend.useRootEntityState()
374
+ const { ref, width } = useWidth()
375
+ const [hovered, setHovered] = useState<number | null>(null)
376
+ const [asTable, setAsTable] = useState(false)
377
+ const months = plan.$monthly
378
+ const peak = Math.max(...months.map(month => Math.max(month.productionKwh, month.consumptionKwh)))
379
+ const { high, ticks } = niceScale(0, peak, 4)
380
+ const plotWidth = Math.max(width - MARGIN.left - MARGIN.right, 0)
381
+ const plotHeight = height - MARGIN.top - MARGIN.bottom
382
+ const band = plotWidth / months.length
383
+ const barWidth = Math.min(24, band * 0.62)
384
+ const y = (value: number) => MARGIN.top + plotHeight - (value / high) * plotHeight
385
+ const x = (index: number) => MARGIN.left + band * index + band / 2
386
+ const active = hovered === null ? undefined : months[hovered]
387
+
388
+ return (
389
+ <Box component="div" sx={{ display: 'grid', gap: 1.5 }}>
390
+ <Box component="div" sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', columnGap: 2, rowGap: 0.5 }}>
391
+ {LEGEND.map(item => (
392
+ <Box component="span" key={item.key} sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.75 }}>
393
+ <Box
394
+ component="span"
395
+ aria-hidden
396
+ sx={
397
+ item.line
398
+ ? { inlineSize: 14, blockSize: 2, borderRadius: 1, bgcolor: item.color }
399
+ : { inlineSize: 10, blockSize: 10, borderRadius: 0.5, bgcolor: item.color }
400
+ }
401
+ />
402
+ <Typography component="span" sx={{ fontFamily: CHART.font, fontSize: 12, color: CHART.inkSoft }}>
403
+ {item.label}
404
+ </Typography>
405
+ </Box>
406
+ ))}
407
+ <ButtonBase
408
+ onClick={() => setAsTable(shown => !shown)}
409
+ sx={{
410
+ marginInlineStart: 'auto',
411
+ fontFamily: CHART.font,
412
+ fontSize: 12,
413
+ color: CHART.ink,
414
+ textDecoration: 'underline',
415
+ }}
416
+ >
417
+ {asTable ? 'Show chart' : 'Show figures'}
418
+ </ButtonBase>
419
+ </Box>
420
+
421
+ {/* Measured whether the chart or the table shows, so the chart comes back at the current width */}
422
+ <Box component="div" ref={ref}>
423
+ {asTable ? (
424
+ <Box
425
+ component="table"
426
+ sx={{
427
+ inlineSize: '100%',
428
+ borderCollapse: 'collapse',
429
+ fontFamily: CHART.font,
430
+ fontSize: 12,
431
+ color: CHART.ink,
432
+ }}
433
+ >
434
+ <thead>
435
+ <tr>
436
+ {['Month', 'Produced', 'Used at home', 'Sent to grid', 'Home use'].map(heading => (
437
+ <Box
438
+ component="th"
439
+ key={heading}
440
+ sx={{
441
+ paddingBlock: 0.5,
442
+ textAlign: 'end',
443
+ fontWeight: 500,
444
+ color: CHART.inkSoft,
445
+ '&:first-of-type': { textAlign: 'start' },
446
+ }}
447
+ >
448
+ {heading}
449
+ </Box>
450
+ ))}
451
+ </tr>
452
+ </thead>
453
+ <tbody>
454
+ {months.map(month => (
455
+ <Box component="tr" key={month.month} sx={{ borderBlockStart: `1px solid ${CHART.grid}` }}>
456
+ <Box component="td" sx={{ paddingBlock: 0.5 }}>
457
+ {month.month}
458
+ </Box>
459
+ {[month.productionKwh, month.selfUseKwh, month.exportKwh, month.consumptionKwh].map(
460
+ (value, index) => (
461
+ <Box component="td" key={index} sx={{ textAlign: 'end', fontVariantNumeric: 'tabular-nums' }}>
462
+ {Math.round(value).toLocaleString('en')}
463
+ </Box>
464
+ )
465
+ )}
466
+ </Box>
467
+ ))}
468
+ </tbody>
469
+ </Box>
470
+ ) : (
471
+ <Box component="div" sx={{ position: 'relative', blockSize: height }}>
472
+ {width > 0 && (
473
+ <svg
474
+ width={width}
475
+ height={height}
476
+ role="img"
477
+ aria-label="Solar production and home use by month"
478
+ onMouseLeave={() => setHovered(null)}
479
+ >
480
+ {ticks.map(tick => (
481
+ <g key={tick}>
482
+ <line
483
+ x1={MARGIN.left}
484
+ x2={width - MARGIN.right}
485
+ y1={y(tick)}
486
+ y2={y(tick)}
487
+ stroke={tick === 0 ? CHART.axis : CHART.grid}
488
+ strokeWidth={1}
489
+ />
490
+ <text
491
+ x={MARGIN.left - 8}
492
+ y={y(tick)}
493
+ textAnchor="end"
494
+ dominantBaseline="middle"
495
+ fill={CHART.inkSoft}
496
+ fontFamily={CHART.font}
497
+ fontSize={11}
498
+ >
499
+ {tick.toLocaleString('en')}
500
+ </text>
501
+ </g>
502
+ ))}
503
+
504
+ {hovered !== null && (
505
+ <rect
506
+ x={MARGIN.left + band * hovered}
507
+ y={MARGIN.top}
508
+ width={band}
509
+ height={plotHeight}
510
+ fill={CHART.grid}
511
+ opacity={0.6}
512
+ />
513
+ )}
514
+
515
+ {months.map((month, index) => {
516
+ const left = x(index) - barWidth / 2
517
+ const selfTop = y(month.selfUseKwh)
518
+ const exportTop = y(month.productionKwh)
519
+ const exportHeight = Math.max(selfTop - exportTop - GAP, 0)
520
+
521
+ return (
522
+ <g key={month.month}>
523
+ {exportHeight > 0.5 ? (
524
+ <>
525
+ <rect x={left} y={selfTop} width={barWidth} height={y(0) - selfTop} fill={SERIES.selfUse} />
526
+ <path d={roundedTop(left, exportTop, barWidth, exportHeight)} fill={SERIES.exported} />
527
+ </>
528
+ ) : (
529
+ <path d={roundedTop(left, selfTop, barWidth, y(0) - selfTop)} fill={SERIES.selfUse} />
530
+ )}
531
+ <text
532
+ x={x(index)}
533
+ y={height - 8}
534
+ textAnchor="middle"
535
+ fill={CHART.inkSoft}
536
+ fontFamily={CHART.font}
537
+ fontSize={11}
538
+ >
539
+ {/* A narrow chart keeps only the initial */}
540
+ {band < 34 ? month.month.slice(0, 1) : month.month}
541
+ </text>
542
+ </g>
543
+ )
544
+ })}
545
+
546
+ <polyline
547
+ points={months.map((month, index) => `${x(index)},${y(month.consumptionKwh)}`).join(' ')}
548
+ fill="none"
549
+ stroke={SERIES.consumption}
550
+ strokeWidth={2}
551
+ strokeLinejoin="round"
552
+ strokeLinecap="round"
553
+ />
554
+ {months.map((month, index) => (
555
+ <circle
556
+ key={month.month}
557
+ cx={x(index)}
558
+ cy={y(month.consumptionKwh)}
559
+ r={4}
560
+ fill={SERIES.consumption}
561
+ stroke={CHART.surface}
562
+ strokeWidth={2}
563
+ />
564
+ ))}
565
+
566
+ {/* Hit areas a full band wide and the plot's height, larger than the marks */}
567
+ {months.map((month, index) => (
568
+ <rect
569
+ key={month.month}
570
+ x={MARGIN.left + band * index}
571
+ y={MARGIN.top}
572
+ width={band}
573
+ height={plotHeight}
574
+ fill="transparent"
575
+ onMouseEnter={() => setHovered(index)}
576
+ />
577
+ ))}
578
+ </svg>
579
+ )}
580
+
581
+ {active !== undefined && hovered !== null && (
582
+ <Box
583
+ component="div"
584
+ role="tooltip"
585
+ sx={{
586
+ position: 'absolute',
587
+ insetBlockStart: 0,
588
+ insetInlineStart: Math.min(Math.max(x(hovered) - 90, 0), Math.max(width - 180, 0)),
589
+ inlineSize: 180,
590
+ padding: 1.25,
591
+ borderRadius: 1.5,
592
+ bgcolor: CHART.surface,
593
+ boxShadow: '0 6px 24px rgba(28, 40, 38, 0.16)',
594
+ pointerEvents: 'none',
595
+ fontFamily: CHART.font,
596
+ }}
597
+ >
598
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 12, fontWeight: 600, color: CHART.ink }}>
599
+ {active.month}
600
+ </Typography>
601
+ {[
602
+ { label: 'Used at home', value: active.selfUseKwh, color: SERIES.selfUse },
603
+ { label: 'Sent to grid', value: active.exportKwh, color: SERIES.exported },
604
+ { label: 'Home use', value: active.consumptionKwh, color: SERIES.consumption },
605
+ ].map(row => (
606
+ <Box component="div" key={row.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>
607
+ <Box
608
+ component="span"
609
+ aria-hidden
610
+ sx={{ inlineSize: 8, blockSize: 8, borderRadius: '50%', bgcolor: row.color }}
611
+ />
612
+ <Typography
613
+ component="span"
614
+ sx={{ flex: 1, fontFamily: CHART.font, fontSize: 12, color: CHART.inkSoft }}
615
+ >
616
+ {row.label}
617
+ </Typography>
618
+ <Typography
619
+ component="span"
620
+ sx={{
621
+ fontFamily: CHART.font,
622
+ fontSize: 12,
623
+ color: CHART.ink,
624
+ fontVariantNumeric: 'tabular-nums',
625
+ }}
626
+ >
627
+ {kwh(row.value)}
628
+ </Typography>
629
+ </Box>
630
+ ))}
631
+ </Box>
632
+ )}
633
+ </Box>
634
+ )}
635
+ </Box>
636
+ </Box>
637
+ )
638
+ }
639
+ ```
640
+
641
+ ## A warning and a notice
642
+
643
+ The plan has two rules. More panels than the roof holds is a `warning`: the dashboard keeps showing the figures, so the household sees what the larger system would do, but a survey cannot be booked until the panels fit. A north-facing roof is a `notice`: it informs and never blocks.
644
+
645
+ ```yaml
646
+ invariants:
647
+ SolarPlan:
648
+ panelsFitRoof:
649
+ types:
650
+ - panelsExceedRoof
651
+ northFacing:
652
+ type: northFacing
653
+ severity: notice
654
+ message: A north-facing roof yields about 40 % less. An east-west layout on another roof usually pays back sooner.
655
+ ```
656
+
657
+ ```ts
658
+ // More panels than the roof holds is a warning: the dashboard keeps showing the figures, and a survey cannot be
659
+ // booked until the panel count fits. A north-facing roof is only a notice, so it never blocks the booking.
660
+ export default phx.domain.implementCustomInvariants({
661
+ SolarPlan: {
662
+ panelsFitRoof: s => {
663
+ if (s.panels <= s.$roofPanelLimit) {
664
+ return []
665
+ }
666
+
667
+ return [
668
+ {
669
+ type: 'panelsExceedRoof',
670
+ severity: 'warning',
671
+ message: `${s.panels} panels need about ${s.$panelAreaM2} m² of roof; ${s.roofArea} m² holds at most ${s.$roofPanelLimit}. Lower the panel count or measure the roof again.`,
672
+ },
673
+ ]
674
+ },
675
+ northFacing: s => {
676
+ return s.orientation !== 'North'
677
+ },
678
+ },
679
+ })
680
+ ```
681
+
682
+ `PlannerInputs` shows both under the roof's inputs, from `phx.frontend.useFinalizeViolations()`, which lists the violations of the committed plan with their severity: the warning in amber, the notice in blue. `phx.frontend.useFinalizeActions()` reports the survey action `disabled` only for the warning.
683
+
684
+ ```tsx
685
+ import { Box, Typography } from '@mui/material'
686
+ import type { ReactNode } from 'react'
687
+
688
+ import { PillField } from './PillField.js'
689
+ import { SliderField } from './SliderField.js'
690
+ import { SUNFOLD } from './tokens.js'
691
+
692
+ interface GroupProps {
693
+ readonly title: string
694
+ // The invariant types whose message belongs under this group
695
+ readonly messageTypes?: readonly string[]
696
+ readonly children: ReactNode
697
+ }
698
+
699
+ // A group of inputs with the message of an invariant the group can resolve: a warning, which blocks the booking, in
700
+ // amber, a notice, which only informs, in blue. `useFinalizeViolations` lists both.
701
+ const Group = ({ title, messageTypes = [], children }: GroupProps) => {
702
+ const { violations } = phx.frontend.useFinalizeViolations()
703
+ const resolve = phx.frontend.useResolveLocalizable()
704
+ const messages = (violations ?? []).filter(({ violation }) => messageTypes.includes(violation.type))
705
+
706
+ return (
707
+ <Box component="section" sx={{ display: 'grid', gap: 2 }}>
708
+ <Typography component="h3" sx={{ fontFamily: SUNFOLD.font, fontSize: 13, fontWeight: 600, color: SUNFOLD.muted }}>
709
+ {title}
710
+ </Typography>
711
+ {children}
712
+ {messages.map(({ violation }) => {
713
+ const isNotice = violation.severity === 'notice'
714
+
715
+ return (
716
+ <Typography
717
+ key={violation.type}
718
+ role={isNotice ? 'status' : 'alert'}
719
+ sx={{
720
+ paddingInline: 1.5,
721
+ paddingBlock: 1,
722
+ borderRadius: 2,
723
+ bgcolor: isNotice ? SUNFOLD.infoTint : SUNFOLD.warningTint,
724
+ color: isNotice ? SUNFOLD.info : SUNFOLD.warning,
725
+ fontFamily: SUNFOLD.font,
726
+ fontSize: 13,
727
+ lineHeight: 1.45,
728
+ }}
729
+ >
730
+ {resolve(violation.message)}
731
+ </Typography>
732
+ )
733
+ })}
734
+ </Box>
735
+ )
736
+ }
737
+
738
+ interface PlannerInputsProps {
739
+ readonly readOnly: boolean
740
+ }
741
+
742
+ // The household's inputs: the roof, the panels on it, the home's use and tariff, and the battery
743
+ export const PlannerInputs = ({ readOnly }: PlannerInputsProps) => {
744
+ const plan = phx.frontend.useRootEntityState()
745
+
746
+ return (
747
+ <Box component="div" sx={{ display: 'grid', gap: 3.5 }}>
748
+ <Group title="Your roof" messageTypes={['panelsExceedRoof', 'northFacing']}>
749
+ <SliderField instanceName="roofArea" label="Usable roof area" step={1} readOnly={readOnly} />
750
+ <PillField instanceName="orientation" label="Facing" readOnly={readOnly} />
751
+ <SliderField instanceName="panels" label="Panels" step={1} readOnly={readOnly} />
752
+ <Typography sx={{ marginBlockStart: -1.5, fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>
753
+ 430 W panels, 1.95 m² each. This roof holds up to {plan.$roofPanelLimit}.
754
+ </Typography>
755
+ </Group>
756
+ <Group title="Your home">
757
+ <SliderField instanceName="annualUse" label="Electricity used a year" step={100} readOnly={readOnly} />
758
+ <PillField instanceName="tariff" label="Tariff" readOnly={readOnly} />
759
+ </Group>
760
+ <Group title="Storage">
761
+ <PillField instanceName="battery" label="Home battery" readOnly={readOnly} />
762
+ </Group>
763
+ </Box>
764
+ )
765
+ }
766
+ ```
767
+
768
+ ## Book a home survey
769
+
770
+ The spec declares one finalize action. Its handler, `src/handlers/book-survey.ts`, stands in for the installer's booking service: it waits, then enters the `booked` navigation state. In that state the panel confirms the request and the inputs are locked until **Back to the plan**. A viewer of a shared configuration sees the cost and no button.
771
+
772
+ ```yaml
773
+ components:
774
+ SolarPlan:
775
+ finalizeAction:
776
+ survey:
777
+ variant: primary
778
+ label: Book a home survey
779
+ title: Ask an installer to survey the roof and confirm the plan
780
+ icon: CalendarCheck
781
+ handler: bookSurvey
782
+ ```
783
+
784
+ ```tsx
785
+ import { Alert, Box, Button, CircularProgress, Typography } from '@mui/material'
786
+
787
+ import { SUNFOLD } from './tokens.js'
788
+
789
+ interface SurveyPanelProps {
790
+ // On a phone the panel is a bar: the cost beside the button, without the hints
791
+ readonly compact: boolean
792
+ }
793
+
794
+ // The system's cost, the `price` component's value, and the spec's `survey` finalize action. A warning blocks the
795
+ // booking and its `hints` say why; a notice does not. In the `booked` navigation state the panel confirms the
796
+ // request instead.
797
+ export const SurveyPanel = ({ compact }: SurveyPanelProps) => {
798
+ const cost = phx.frontend.useRootEntityPrice()
799
+ const { primary, hints } = phx.frontend.useFinalizeActions()
800
+ const navigationState = phx.frontend.useActiveNavigationState()
801
+ const navigate = phx.frontend.useNavigate()
802
+ const { accessInfo } = phx.frontend.useAccessService()
803
+ const isPending = primary?.isPending ?? false
804
+
805
+ if (navigationState === 'booked') {
806
+ return (
807
+ <Box component="div" role="status" sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
808
+ <Box component="div" sx={{ display: 'grid', flex: 1 }}>
809
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 16, fontWeight: 600, color: SUNFOLD.green }}>
810
+ Survey requested
811
+ </Typography>
812
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 13, color: SUNFOLD.muted }}>
813
+ An installer calls within two working days.
814
+ </Typography>
815
+ </Box>
816
+ <Button
817
+ onClick={() => navigate('plan')}
818
+ sx={{
819
+ fontFamily: SUNFOLD.font,
820
+ fontSize: 13,
821
+ color: SUNFOLD.ink,
822
+ textTransform: 'none',
823
+ textDecoration: 'underline',
824
+ }}
825
+ >
826
+ Back to the plan
827
+ </Button>
828
+ </Box>
829
+ )
830
+ }
831
+
832
+ const showButton = primary !== null && !accessInfo.viewMode
833
+
834
+ return (
835
+ <Box component="div" sx={{ display: 'grid', gap: 1.25 }}>
836
+ <Box
837
+ component="div"
838
+ sx={{
839
+ display: 'flex',
840
+ flexDirection: compact ? 'row' : 'column',
841
+ alignItems: compact ? 'center' : 'stretch',
842
+ justifyContent: 'space-between',
843
+ gap: compact ? 2 : 1.5,
844
+ }}
845
+ >
846
+ <Box component="div" sx={{ display: 'grid' }}>
847
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>Installed cost</Typography>
848
+ <Typography
849
+ sx={{ fontFamily: SUNFOLD.font, fontSize: compact ? 20 : 26, fontWeight: 600, color: SUNFOLD.ink }}
850
+ >
851
+ {cost}
852
+ </Typography>
853
+ </Box>
854
+ {showButton && (
855
+ <Button
856
+ variant="contained"
857
+ disableElevation
858
+ disabled={primary.disabled || isPending}
859
+ onClick={() => void primary.run()}
860
+ title={primary.title}
861
+ startIcon={isPending ? <CircularProgress size={16} color="inherit" /> : undefined}
862
+ sx={{
863
+ minBlockSize: 46,
864
+ paddingInline: 2.5,
865
+ borderRadius: 999,
866
+ bgcolor: SUNFOLD.green,
867
+ fontFamily: SUNFOLD.font,
868
+ fontSize: 14,
869
+ fontWeight: 500,
870
+ textTransform: 'none',
871
+ '&:hover': { bgcolor: SUNFOLD.greenDark },
872
+ '&.Mui-disabled': { bgcolor: SUNFOLD.line, color: SUNFOLD.muted },
873
+ }}
874
+ >
875
+ {isPending ? 'Booking…' : primary.label}
876
+ </Button>
877
+ )}
878
+ </Box>
879
+ {!compact && showButton && primary.disabled && hints && (
880
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.warning }}>{hints}</Typography>
881
+ )}
882
+ {primary?.error && <Alert severity="error">The survey could not be booked: {primary.error.message}</Alert>}
883
+ </Box>
884
+ )
885
+ }
886
+ ```
887
+
888
+ ## On a phone
889
+
890
+ The same layout in a frame 390 pixels wide: the four figures in two rows, the inputs in a card below them, the charts stacked under the inputs, and the cost with **Book a home survey** in a bar at the bottom. Opened on its own from the sidebar, the **Phone** story sets Storybook's viewport to 390 × 844.
891
+
892
+ ## Test cases
893
+
894
+ - The plan opens with 14 panels on a 42 m² south-facing roof, no battery, a flat rate and 4,500 kWh a year. The tiles read **6.0 kWp**, **6,020 kWh**, **30 %** and **8.2 years**, the installed cost is **€7,821.00**, and the split bar shows 30 % used at home.
895
+ - In **Your solar year**, the summer columns are mostly sent to the grid and the winter ones mostly used at home, and the home's use is a line that is higher in winter. Hovering June shows 142 kWh used at home, 641 kWh sent to the grid and 315 kWh of home use.
896
+ - Moving the pointer across **When it pays back** reads off the year; the curve crosses zero at the marked payback year.
897
+ - A 10 kWh battery, the time-of-use tariff and 18 panels change every tile and chart: 7.7 kWp, 7,740 kWh, 44 % used at home and 9.8 years, at €16,027.00. The columns' home part grows.
898
+ - 22 panels on the 42 m² roof show "22 panels need about 43 m² of roof; 42 m² holds at most 18. …" and disable **Book a home survey**; a roof of 52 m² clears it.
899
+ - **North** shows the notice "A north-facing roof yields about 40 % less. …" in blue, lowers the production and lengthens the payback, and leaves **Book a home survey** enabled.
900
+ - **Show figures** shows a table of the twelve months; **Show chart** brings the chart back.
901
+ - **Book a home survey** shows a spinner and "Booking…", then "Survey requested"; the inputs are locked until **Back to the plan**.
902
+ - In the **Phone** story the tiles sit in two rows, the inputs and charts scroll below, the same changes update every figure, and the bottom bar confirms the booking.
903
+ - The browser console shows no errors, the page has no `canvas` element, and no model or texture is requested.
904
+
905
+ ## What this layout leaves out
906
+
907
+ - **Read mode.** The inputs are inert and **Book a home survey** is hidden while `phx.frontend.useAccessService().accessInfo.viewMode` is set, but the example ships no read template; [Custom Layout → Serve read mode](?path=/docs/layouts-custom-layout--docs#serve-read-mode) shows one.
908
+ - **Real yields and prices.** The model is an illustration. A deployed planner would read the site's irradiance and the household's tariff from data the project publishes, see [Data Sources](?path=/docs/phoenix-data-sources--docs).
909
+ - **A dark theme.** The page is the installer's own light design; the configurator's theme does not switch it.
910
+ - **The built-in arrangement.** Header, sidebar, footer, tabs and the preview start screen are not mounted; [Layout Slots](?path=/docs/phoenix-layout-slots--docs) lists every slot a project layout can mount.
911
+
912
+ ## Related pages
913
+
914
+ - [Ardent Compressor](?path=/docs/layouts-gallery-ardent-compressor--docs) is a quote form with steps, and [Fenwick Window](?path=/docs/layouts-gallery-fenwick-window--docs) a live shop drawing; neither mounts a canvas either.
915
+ - [Custom Layout](?path=/docs/layouts-custom-layout--docs) explains a project layout step by step.
916
+ - [Configurator Interface → Hooks for a Project Layout](?path=/docs/phoenix-configurator-interface--docs#hooks-for-a-project-layout) lists the hooks used here.
917
+ - [Domain Model → Expressions](?path=/docs/phoenix-domain-model--docs#expressions) and [Domain Model → Invariants](?path=/docs/phoenix-domain-model--docs#invariants) describe declared expressions and severities.
918
+
919
+ ## Complete Implementation
920
+
921
+ {/* AUTO-GENERATED SECTION: This section is automatically updated by 'phoenix story build' */}
922
+
923
+ <details>
924
+ <summary>Click to view the complete implementation files</summary>
925
+
926
+ ### ./spec/domain.yaml
927
+
928
+ ```yaml
929
+ model:
930
+ latest:
931
+ entityTypes:
932
+ - SolarPlan
933
+ aliases:
934
+ RootEntity:
935
+ - SolarPlan
936
+ commonTypes:
937
+ Orientation:
938
+ enum:
939
+ - South
940
+ - SouthEastWest
941
+ - EastWest
942
+ - North
943
+ Battery:
944
+ enum:
945
+ - None
946
+ - Kwh5
947
+ - Kwh10
948
+ - Kwh15
949
+ Tariff:
950
+ enum:
951
+ - Flat
952
+ - TimeOfUse
953
+ - ExportPlus
954
+ shapes:
955
+ SolarPlan:
956
+ roofArea:
957
+ type: number
958
+ orientation:
959
+ $ref: '#/model/latest/commonTypes/Orientation'
960
+ panels:
961
+ type: number
962
+ battery:
963
+ $ref: '#/model/latest/commonTypes/Battery'
964
+ tariff:
965
+ $ref: '#/model/latest/commonTypes/Tariff'
966
+ annualUse:
967
+ type: number
968
+
969
+ presets:
970
+ - rootEntityType: SolarPlan
971
+ initialDomainEntities:
972
+ - id: SolarPlan-1
973
+ type: SolarPlan
974
+ roofArea: 42
975
+ orientation: South
976
+ panels: 14
977
+ battery: None
978
+ tariff: Flat
979
+ annualUse: 4500
980
+
981
+ navigationStates:
982
+ - plan
983
+ - booked
984
+
985
+ # Every figure on the dashboard: declared here, computed in src/expressions/solar.ts from the roof, the panels, the
986
+ # battery, the tariff and the household's use
987
+ expressions:
988
+ SolarPlan:
989
+ $systemKwp:
990
+ type: number
991
+ $roofPanelLimit:
992
+ type: number
993
+ $panelAreaM2:
994
+ type: number
995
+ $annualProductionKwh:
996
+ type: number
997
+ $monthly:
998
+ type: array
999
+ items:
1000
+ type: object
1001
+ properties:
1002
+ month:
1003
+ type: string
1004
+ productionKwh:
1005
+ type: number
1006
+ consumptionKwh:
1007
+ type: number
1008
+ selfUseKwh:
1009
+ type: number
1010
+ exportKwh:
1011
+ type: number
1012
+ required:
1013
+ - month
1014
+ - productionKwh
1015
+ - consumptionKwh
1016
+ - selfUseKwh
1017
+ - exportKwh
1018
+ additionalProperties: false
1019
+ $selfConsumption:
1020
+ type: number
1021
+ $selfSufficiency:
1022
+ type: number
1023
+ $annualSavings:
1024
+ type: number
1025
+ $systemCost:
1026
+ type: number
1027
+ $cumulativeSavings:
1028
+ type: array
1029
+ items:
1030
+ type: number
1031
+ $paybackYears:
1032
+ type: number
1033
+ $co2Tonnes:
1034
+ type: number
1035
+
1036
+ invariants:
1037
+ SolarPlan:
1038
+ panelsFitRoof:
1039
+ types:
1040
+ - panelsExceedRoof
1041
+ northFacing:
1042
+ type: northFacing
1043
+ severity: notice
1044
+ message: A north-facing roof yields about 40 % less. An east-west layout on another roof usually pays back sooner.
1045
+
1046
+ components:
1047
+ SolarPlan:
1048
+ price:
1049
+ main:
1050
+ price:
1051
+ $read: $systemCost
1052
+ currency: EUR
1053
+ finalizeAction:
1054
+ survey:
1055
+ variant: primary
1056
+ label: Book a home survey
1057
+ title: Ask an installer to survey the roof and confirm the plan
1058
+ icon: CalendarCheck
1059
+ handler: bookSurvey
1060
+ genericDimension:
1061
+ roofArea:
1062
+ value:
1063
+ $bind: roofArea
1064
+ min: 10
1065
+ max: 120
1066
+ unit: m²
1067
+ decimalPlaces: 0
1068
+ panels:
1069
+ value:
1070
+ $bind: panels
1071
+ min: 4
1072
+ max: 40
1073
+ unit: panels
1074
+ decimalPlaces: 0
1075
+ annualUse:
1076
+ value:
1077
+ $bind: annualUse
1078
+ min: 1500
1079
+ max: 12000
1080
+ unit: kWh
1081
+ decimalPlaces: 0
1082
+ attributeSelection:
1083
+ orientation:
1084
+ value:
1085
+ $bind: orientation
1086
+ options:
1087
+ - label: South
1088
+ value: South
1089
+ - label: South-east or south-west
1090
+ value: SouthEastWest
1091
+ - label: East and west
1092
+ value: EastWest
1093
+ - label: North
1094
+ value: North
1095
+ battery:
1096
+ value:
1097
+ $bind: battery
1098
+ options:
1099
+ - label: None
1100
+ value: None
1101
+ - label: 5 kWh
1102
+ value: Kwh5
1103
+ - label: 10 kWh
1104
+ value: Kwh10
1105
+ - label: 15 kWh
1106
+ value: Kwh15
1107
+ tariff:
1108
+ value:
1109
+ $bind: tariff
1110
+ options:
1111
+ - label: Flat rate
1112
+ description: €0.32 per kWh bought, €0.08 per kWh sold
1113
+ value: Flat
1114
+ - label: Time of use
1115
+ description: Cheap nights, dear evenings; a battery shifts the evening
1116
+ value: TimeOfUse
1117
+ - label: Export plus
1118
+ description: €0.15 per kWh sold to the grid
1119
+ value: ExportPlus
1120
+ ```
1121
+
1122
+ ### ./src/\_charts/EnergySplitBar.tsx
1123
+
1124
+ ```tsx
1125
+ import { Box, Typography } from '@mui/material'
1126
+
1127
+ import { CHART, SERIES } from './chart-style.js'
1128
+
1129
+ // Where a year of solar power goes, as one bar split between the home and the grid, from the spec's `$monthly` and
1130
+ // `$selfConsumption` expressions. A battery moves the split towards the home.
1131
+ export const EnergySplitBar = () => {
1132
+ const plan = phx.frontend.useRootEntityState()
1133
+ const selfUse = plan.$monthly.reduce((sum, month) => sum + month.selfUseKwh, 0)
1134
+ const exported = plan.$monthly.reduce((sum, month) => sum + month.exportKwh, 0)
1135
+ const share = plan.$selfConsumption
1136
+ const parts = [
1137
+ { key: 'home', label: 'Used at home', kwh: selfUse, share, color: SERIES.selfUse },
1138
+ { key: 'grid', label: 'Sent to the grid', kwh: exported, share: 1 - share, color: SERIES.exported },
1139
+ ]
1140
+
1141
+ return (
1142
+ <Box component="div" sx={{ display: 'grid', gap: 1.5 }}>
1143
+ <Box
1144
+ component="div"
1145
+ role="img"
1146
+ aria-label={`${Math.round(share * 100)} % of the solar power is used at home`}
1147
+ sx={{ display: 'flex', gap: '2px', blockSize: 20 }}
1148
+ >
1149
+ {parts.map((part, index) => (
1150
+ <Box
1151
+ component="span"
1152
+ key={part.key}
1153
+ sx={{
1154
+ flexBasis: `${part.share * 100}%`,
1155
+ minInlineSize: part.share > 0 ? 4 : 0,
1156
+ bgcolor: part.color,
1157
+ borderStartStartRadius: index === 0 ? 4 : 0,
1158
+ borderEndStartRadius: index === 0 ? 4 : 0,
1159
+ borderStartEndRadius: index === parts.length - 1 ? 4 : 0,
1160
+ borderEndEndRadius: index === parts.length - 1 ? 4 : 0,
1161
+ transition: 'flex-basis 240ms ease-out',
1162
+ }}
1163
+ />
1164
+ ))}
1165
+ </Box>
1166
+ <Box component="div" sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 2 }}>
1167
+ {parts.map(part => (
1168
+ <Box component="div" key={part.key} sx={{ display: 'grid', gap: 0.25 }}>
1169
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>
1170
+ <Box
1171
+ component="span"
1172
+ aria-hidden
1173
+ sx={{ inlineSize: 10, blockSize: 10, borderRadius: 0.5, bgcolor: part.color }}
1174
+ />
1175
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 12, color: CHART.inkSoft }}>{part.label}</Typography>
1176
+ </Box>
1177
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 20, fontWeight: 600, color: CHART.ink }}>
1178
+ {Math.round(part.share * 100)} %
1179
+ </Typography>
1180
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 12, color: CHART.inkSoft }}>
1181
+ {Math.round(part.kwh).toLocaleString('en')} kWh a year
1182
+ </Typography>
1183
+ </Box>
1184
+ ))}
1185
+ </Box>
1186
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 13, color: CHART.ink }}>
1187
+ Solar covers {Math.round(plan.$selfSufficiency * 100)} % of the home's {plan.annualUse.toLocaleString('en')}{' '}
1188
+ kWh.
1189
+ </Typography>
1190
+ </Box>
1191
+ )
1192
+ }
1193
+ ```
1194
+
1195
+ ### ./src/\_charts/MonthlyEnergyChart.tsx
1196
+
1197
+ ```tsx
1198
+ import { Box, ButtonBase, Typography } from '@mui/material'
1199
+ import { useState } from 'react'
1200
+
1201
+ import { CHART, SERIES } from './chart-style.js'
1202
+ import { niceScale } from './nice-scale.js'
1203
+ import { useWidth } from './use-width.js'
1204
+
1205
+ const MARGIN = { top: 12, right: 8, bottom: 26, left: 48 }
1206
+ const GAP = 2
1207
+ const RADIUS = 4
1208
+
1209
+ const kwh = (value: number) => {
1210
+ return `${Math.round(value).toLocaleString('en')} kWh`
1211
+ }
1212
+
1213
+ // A column segment whose top corners are rounded, so the stack ends in a 4px data-end and stays square at the
1214
+ // baseline
1215
+ const roundedTop = (x: number, y: number, width: number, height: number) => {
1216
+ const r = Math.min(RADIUS, height, width / 2)
1217
+
1218
+ return `M${x},${y + height} V${y + r} Q${x},${y} ${x + r},${y} H${x + width - r} Q${x + width},${y} ${x + width},${y + r} V${y + height} Z`
1219
+ }
1220
+
1221
+ const LEGEND = [
1222
+ { key: 'selfUse', label: 'Solar used at home', color: SERIES.selfUse, line: false },
1223
+ { key: 'exported', label: 'Solar sent to the grid', color: SERIES.exported, line: false },
1224
+ { key: 'consumption', label: 'Home use', color: SERIES.consumption, line: true },
1225
+ ]
1226
+
1227
+ interface MonthlyEnergyChartProps {
1228
+ readonly height: number
1229
+ }
1230
+
1231
+ // Each month's solar production as a column split into what the home uses and what goes to the grid, with the
1232
+ // home's use as a line across it. All figures come from the spec's `$monthly` expression. Hovering a month shows its
1233
+ // figures; "Show figures" swaps the chart for a table of the same numbers.
1234
+ export const MonthlyEnergyChart = ({ height }: MonthlyEnergyChartProps) => {
1235
+ const plan = phx.frontend.useRootEntityState()
1236
+ const { ref, width } = useWidth()
1237
+ const [hovered, setHovered] = useState<number | null>(null)
1238
+ const [asTable, setAsTable] = useState(false)
1239
+ const months = plan.$monthly
1240
+ const peak = Math.max(...months.map(month => Math.max(month.productionKwh, month.consumptionKwh)))
1241
+ const { high, ticks } = niceScale(0, peak, 4)
1242
+ const plotWidth = Math.max(width - MARGIN.left - MARGIN.right, 0)
1243
+ const plotHeight = height - MARGIN.top - MARGIN.bottom
1244
+ const band = plotWidth / months.length
1245
+ const barWidth = Math.min(24, band * 0.62)
1246
+ const y = (value: number) => MARGIN.top + plotHeight - (value / high) * plotHeight
1247
+ const x = (index: number) => MARGIN.left + band * index + band / 2
1248
+ const active = hovered === null ? undefined : months[hovered]
1249
+
1250
+ return (
1251
+ <Box component="div" sx={{ display: 'grid', gap: 1.5 }}>
1252
+ <Box component="div" sx={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', columnGap: 2, rowGap: 0.5 }}>
1253
+ {LEGEND.map(item => (
1254
+ <Box component="span" key={item.key} sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.75 }}>
1255
+ <Box
1256
+ component="span"
1257
+ aria-hidden
1258
+ sx={
1259
+ item.line
1260
+ ? { inlineSize: 14, blockSize: 2, borderRadius: 1, bgcolor: item.color }
1261
+ : { inlineSize: 10, blockSize: 10, borderRadius: 0.5, bgcolor: item.color }
1262
+ }
1263
+ />
1264
+ <Typography component="span" sx={{ fontFamily: CHART.font, fontSize: 12, color: CHART.inkSoft }}>
1265
+ {item.label}
1266
+ </Typography>
1267
+ </Box>
1268
+ ))}
1269
+ <ButtonBase
1270
+ onClick={() => setAsTable(shown => !shown)}
1271
+ sx={{
1272
+ marginInlineStart: 'auto',
1273
+ fontFamily: CHART.font,
1274
+ fontSize: 12,
1275
+ color: CHART.ink,
1276
+ textDecoration: 'underline',
1277
+ }}
1278
+ >
1279
+ {asTable ? 'Show chart' : 'Show figures'}
1280
+ </ButtonBase>
1281
+ </Box>
1282
+
1283
+ {/* Measured whether the chart or the table shows, so the chart comes back at the current width */}
1284
+ <Box component="div" ref={ref}>
1285
+ {asTable ? (
1286
+ <Box
1287
+ component="table"
1288
+ sx={{
1289
+ inlineSize: '100%',
1290
+ borderCollapse: 'collapse',
1291
+ fontFamily: CHART.font,
1292
+ fontSize: 12,
1293
+ color: CHART.ink,
1294
+ }}
1295
+ >
1296
+ <thead>
1297
+ <tr>
1298
+ {['Month', 'Produced', 'Used at home', 'Sent to grid', 'Home use'].map(heading => (
1299
+ <Box
1300
+ component="th"
1301
+ key={heading}
1302
+ sx={{
1303
+ paddingBlock: 0.5,
1304
+ textAlign: 'end',
1305
+ fontWeight: 500,
1306
+ color: CHART.inkSoft,
1307
+ '&:first-of-type': { textAlign: 'start' },
1308
+ }}
1309
+ >
1310
+ {heading}
1311
+ </Box>
1312
+ ))}
1313
+ </tr>
1314
+ </thead>
1315
+ <tbody>
1316
+ {months.map(month => (
1317
+ <Box component="tr" key={month.month} sx={{ borderBlockStart: `1px solid ${CHART.grid}` }}>
1318
+ <Box component="td" sx={{ paddingBlock: 0.5 }}>
1319
+ {month.month}
1320
+ </Box>
1321
+ {[month.productionKwh, month.selfUseKwh, month.exportKwh, month.consumptionKwh].map(
1322
+ (value, index) => (
1323
+ <Box component="td" key={index} sx={{ textAlign: 'end', fontVariantNumeric: 'tabular-nums' }}>
1324
+ {Math.round(value).toLocaleString('en')}
1325
+ </Box>
1326
+ )
1327
+ )}
1328
+ </Box>
1329
+ ))}
1330
+ </tbody>
1331
+ </Box>
1332
+ ) : (
1333
+ <Box component="div" sx={{ position: 'relative', blockSize: height }}>
1334
+ {width > 0 && (
1335
+ <svg
1336
+ width={width}
1337
+ height={height}
1338
+ role="img"
1339
+ aria-label="Solar production and home use by month"
1340
+ onMouseLeave={() => setHovered(null)}
1341
+ >
1342
+ {ticks.map(tick => (
1343
+ <g key={tick}>
1344
+ <line
1345
+ x1={MARGIN.left}
1346
+ x2={width - MARGIN.right}
1347
+ y1={y(tick)}
1348
+ y2={y(tick)}
1349
+ stroke={tick === 0 ? CHART.axis : CHART.grid}
1350
+ strokeWidth={1}
1351
+ />
1352
+ <text
1353
+ x={MARGIN.left - 8}
1354
+ y={y(tick)}
1355
+ textAnchor="end"
1356
+ dominantBaseline="middle"
1357
+ fill={CHART.inkSoft}
1358
+ fontFamily={CHART.font}
1359
+ fontSize={11}
1360
+ >
1361
+ {tick.toLocaleString('en')}
1362
+ </text>
1363
+ </g>
1364
+ ))}
1365
+
1366
+ {hovered !== null && (
1367
+ <rect
1368
+ x={MARGIN.left + band * hovered}
1369
+ y={MARGIN.top}
1370
+ width={band}
1371
+ height={plotHeight}
1372
+ fill={CHART.grid}
1373
+ opacity={0.6}
1374
+ />
1375
+ )}
1376
+
1377
+ {months.map((month, index) => {
1378
+ const left = x(index) - barWidth / 2
1379
+ const selfTop = y(month.selfUseKwh)
1380
+ const exportTop = y(month.productionKwh)
1381
+ const exportHeight = Math.max(selfTop - exportTop - GAP, 0)
1382
+
1383
+ return (
1384
+ <g key={month.month}>
1385
+ {exportHeight > 0.5 ? (
1386
+ <>
1387
+ <rect x={left} y={selfTop} width={barWidth} height={y(0) - selfTop} fill={SERIES.selfUse} />
1388
+ <path d={roundedTop(left, exportTop, barWidth, exportHeight)} fill={SERIES.exported} />
1389
+ </>
1390
+ ) : (
1391
+ <path d={roundedTop(left, selfTop, barWidth, y(0) - selfTop)} fill={SERIES.selfUse} />
1392
+ )}
1393
+ <text
1394
+ x={x(index)}
1395
+ y={height - 8}
1396
+ textAnchor="middle"
1397
+ fill={CHART.inkSoft}
1398
+ fontFamily={CHART.font}
1399
+ fontSize={11}
1400
+ >
1401
+ {/* A narrow chart keeps only the initial */}
1402
+ {band < 34 ? month.month.slice(0, 1) : month.month}
1403
+ </text>
1404
+ </g>
1405
+ )
1406
+ })}
1407
+
1408
+ <polyline
1409
+ points={months.map((month, index) => `${x(index)},${y(month.consumptionKwh)}`).join(' ')}
1410
+ fill="none"
1411
+ stroke={SERIES.consumption}
1412
+ strokeWidth={2}
1413
+ strokeLinejoin="round"
1414
+ strokeLinecap="round"
1415
+ />
1416
+ {months.map((month, index) => (
1417
+ <circle
1418
+ key={month.month}
1419
+ cx={x(index)}
1420
+ cy={y(month.consumptionKwh)}
1421
+ r={4}
1422
+ fill={SERIES.consumption}
1423
+ stroke={CHART.surface}
1424
+ strokeWidth={2}
1425
+ />
1426
+ ))}
1427
+
1428
+ {/* Hit areas a full band wide and the plot's height, larger than the marks */}
1429
+ {months.map((month, index) => (
1430
+ <rect
1431
+ key={month.month}
1432
+ x={MARGIN.left + band * index}
1433
+ y={MARGIN.top}
1434
+ width={band}
1435
+ height={plotHeight}
1436
+ fill="transparent"
1437
+ onMouseEnter={() => setHovered(index)}
1438
+ />
1439
+ ))}
1440
+ </svg>
1441
+ )}
1442
+
1443
+ {active !== undefined && hovered !== null && (
1444
+ <Box
1445
+ component="div"
1446
+ role="tooltip"
1447
+ sx={{
1448
+ position: 'absolute',
1449
+ insetBlockStart: 0,
1450
+ insetInlineStart: Math.min(Math.max(x(hovered) - 90, 0), Math.max(width - 180, 0)),
1451
+ inlineSize: 180,
1452
+ padding: 1.25,
1453
+ borderRadius: 1.5,
1454
+ bgcolor: CHART.surface,
1455
+ boxShadow: '0 6px 24px rgba(28, 40, 38, 0.16)',
1456
+ pointerEvents: 'none',
1457
+ fontFamily: CHART.font,
1458
+ }}
1459
+ >
1460
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 12, fontWeight: 600, color: CHART.ink }}>
1461
+ {active.month}
1462
+ </Typography>
1463
+ {[
1464
+ { label: 'Used at home', value: active.selfUseKwh, color: SERIES.selfUse },
1465
+ { label: 'Sent to grid', value: active.exportKwh, color: SERIES.exported },
1466
+ { label: 'Home use', value: active.consumptionKwh, color: SERIES.consumption },
1467
+ ].map(row => (
1468
+ <Box component="div" key={row.label} sx={{ display: 'flex', alignItems: 'center', gap: 0.75 }}>
1469
+ <Box
1470
+ component="span"
1471
+ aria-hidden
1472
+ sx={{ inlineSize: 8, blockSize: 8, borderRadius: '50%', bgcolor: row.color }}
1473
+ />
1474
+ <Typography
1475
+ component="span"
1476
+ sx={{ flex: 1, fontFamily: CHART.font, fontSize: 12, color: CHART.inkSoft }}
1477
+ >
1478
+ {row.label}
1479
+ </Typography>
1480
+ <Typography
1481
+ component="span"
1482
+ sx={{
1483
+ fontFamily: CHART.font,
1484
+ fontSize: 12,
1485
+ color: CHART.ink,
1486
+ fontVariantNumeric: 'tabular-nums',
1487
+ }}
1488
+ >
1489
+ {kwh(row.value)}
1490
+ </Typography>
1491
+ </Box>
1492
+ ))}
1493
+ </Box>
1494
+ )}
1495
+ </Box>
1496
+ )}
1497
+ </Box>
1498
+ </Box>
1499
+ )
1500
+ }
1501
+ ```
1502
+
1503
+ ### ./src/\_charts/PaybackChart.tsx
1504
+
1505
+ ```tsx
1506
+ import { Box, Typography } from '@mui/material'
1507
+ import type { MouseEvent } from 'react'
1508
+ import { useState } from 'react'
1509
+
1510
+ import { CHART } from './chart-style.js'
1511
+ import { niceScale } from './nice-scale.js'
1512
+ import { useWidth } from './use-width.js'
1513
+
1514
+ const MARGIN = { top: 16, right: 16, bottom: 26, left: 56 }
1515
+ const LINE = '#1f6f54'
1516
+ const YEAR_TICKS = [0, 5, 10, 15, 20, 25]
1517
+
1518
+ const euro = (value: number) => {
1519
+ return value.toLocaleString('en-IE', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 })
1520
+ }
1521
+
1522
+ interface PaybackChartProps {
1523
+ readonly height: number
1524
+ }
1525
+
1526
+ // The money the system has returned, year by year over the panels' 25 years, from the spec's `$cumulativeSavings`
1527
+ // expression: it starts at minus the system's cost and crosses zero in the payback year, which is marked. Moving the
1528
+ // pointer across the chart reads off any year.
1529
+ export const PaybackChart = ({ height }: PaybackChartProps) => {
1530
+ const plan = phx.frontend.useRootEntityState()
1531
+ const { ref, width } = useWidth()
1532
+ const [year, setYear] = useState<number | null>(null)
1533
+ const totals = plan.$cumulativeSavings
1534
+ const lastYear = totals.length - 1
1535
+ const { low, high, ticks } = niceScale(Math.min(...totals), Math.max(...totals, 0), 4)
1536
+ const plotWidth = Math.max(width - MARGIN.left - MARGIN.right, 0)
1537
+ const plotHeight = height - MARGIN.top - MARGIN.bottom
1538
+ const x = (value: number) => MARGIN.left + (value / lastYear) * plotWidth
1539
+ const y = (value: number) => MARGIN.top + ((high - value) / (high - low)) * plotHeight
1540
+ const points = totals.map((total, index) => `${x(index)},${y(total)}`)
1541
+ const payback = plan.$paybackYears
1542
+ const paysBack = Number.isFinite(payback) && payback <= lastYear
1543
+ const hoveredTotal = year === null ? null : totals[year]
1544
+
1545
+ const handleMove = (event: MouseEvent<SVGRectElement>) => {
1546
+ const bounds = event.currentTarget.getBoundingClientRect()
1547
+ const fraction = (event.clientX - bounds.left) / bounds.width
1548
+
1549
+ setYear(Math.min(lastYear, Math.max(0, Math.round(fraction * lastYear))))
1550
+ }
1551
+
1552
+ return (
1553
+ <Box component="div" ref={ref} sx={{ position: 'relative', blockSize: height }}>
1554
+ {width > 0 && (
1555
+ <svg
1556
+ width={width}
1557
+ height={height}
1558
+ role="img"
1559
+ aria-label={
1560
+ paysBack
1561
+ ? `The system pays back after ${payback.toFixed(1)} years`
1562
+ : 'The system does not pay back within 25 years'
1563
+ }
1564
+ >
1565
+ {ticks.map(tick => (
1566
+ <g key={tick}>
1567
+ <line
1568
+ x1={MARGIN.left}
1569
+ x2={width - MARGIN.right}
1570
+ y1={y(tick)}
1571
+ y2={y(tick)}
1572
+ stroke={tick === 0 ? CHART.axis : CHART.grid}
1573
+ strokeWidth={1}
1574
+ />
1575
+ <text
1576
+ x={MARGIN.left - 8}
1577
+ y={y(tick)}
1578
+ textAnchor="end"
1579
+ dominantBaseline="middle"
1580
+ fill={CHART.inkSoft}
1581
+ fontFamily={CHART.font}
1582
+ fontSize={11}
1583
+ >
1584
+ {tick === 0 ? '€0' : `${tick < 0 ? '−' : ''}€${Math.abs(tick / 1000)}k`}
1585
+ </text>
1586
+ </g>
1587
+ ))}
1588
+ {YEAR_TICKS.map(tick => (
1589
+ <text
1590
+ key={tick}
1591
+ x={x(tick)}
1592
+ y={height - 8}
1593
+ textAnchor="middle"
1594
+ fill={CHART.inkSoft}
1595
+ fontFamily={CHART.font}
1596
+ fontSize={11}
1597
+ >
1598
+ {tick === 0 ? 'Year 0' : tick}
1599
+ </text>
1600
+ ))}
1601
+
1602
+ {/* A wash between the line and zero: what is still owed below, what is earned above */}
1603
+ <polygon points={`${x(0)},${y(0)} ${points.join(' ')} ${x(lastYear)},${y(0)}`} fill={LINE} opacity={0.1} />
1604
+ <polyline
1605
+ points={points.join(' ')}
1606
+ fill="none"
1607
+ stroke={LINE}
1608
+ strokeWidth={2}
1609
+ strokeLinejoin="round"
1610
+ strokeLinecap="round"
1611
+ />
1612
+
1613
+ {paysBack && (
1614
+ <g>
1615
+ <line
1616
+ x1={x(payback)}
1617
+ x2={x(payback)}
1618
+ y1={y(0)}
1619
+ y2={MARGIN.top + plotHeight}
1620
+ stroke={CHART.axis}
1621
+ strokeWidth={1}
1622
+ />
1623
+ <circle cx={x(payback)} cy={y(0)} r={5} fill={LINE} stroke={CHART.surface} strokeWidth={2} />
1624
+ {/* Right of the point the line runs above zero and left of it below, so the label takes the empty side */}
1625
+ <text
1626
+ x={x(payback) + (x(payback) > width * 0.7 ? -10 : 10)}
1627
+ y={x(payback) > width * 0.7 ? y(0) - 10 : y(0) + 20}
1628
+ textAnchor={x(payback) > width * 0.7 ? 'end' : 'start'}
1629
+ fill={CHART.ink}
1630
+ fontFamily={CHART.font}
1631
+ fontSize={12}
1632
+ fontWeight={600}
1633
+ >
1634
+ Pays back in year {Math.ceil(payback)}
1635
+ </text>
1636
+ </g>
1637
+ )}
1638
+
1639
+ {year !== null && hoveredTotal !== undefined && hoveredTotal !== null && (
1640
+ <g>
1641
+ <line
1642
+ x1={x(year)}
1643
+ x2={x(year)}
1644
+ y1={MARGIN.top}
1645
+ y2={MARGIN.top + plotHeight}
1646
+ stroke={CHART.inkSoft}
1647
+ strokeWidth={1}
1648
+ />
1649
+ <circle cx={x(year)} cy={y(hoveredTotal)} r={4} fill={LINE} stroke={CHART.surface} strokeWidth={2} />
1650
+ </g>
1651
+ )}
1652
+ <rect
1653
+ x={MARGIN.left}
1654
+ y={MARGIN.top}
1655
+ width={plotWidth}
1656
+ height={plotHeight}
1657
+ fill="transparent"
1658
+ onMouseMove={handleMove}
1659
+ onMouseLeave={() => setYear(null)}
1660
+ />
1661
+ </svg>
1662
+ )}
1663
+
1664
+ {year !== null && hoveredTotal !== undefined && hoveredTotal !== null && (
1665
+ <Box
1666
+ component="div"
1667
+ role="tooltip"
1668
+ sx={{
1669
+ position: 'absolute',
1670
+ insetBlockStart: 0,
1671
+ insetInlineStart: Math.min(Math.max(x(year) - 80, 0), Math.max(width - 160, 0)),
1672
+ inlineSize: 160,
1673
+ padding: 1.25,
1674
+ borderRadius: 1.5,
1675
+ bgcolor: CHART.surface,
1676
+ boxShadow: '0 6px 24px rgba(28, 40, 38, 0.16)',
1677
+ pointerEvents: 'none',
1678
+ }}
1679
+ >
1680
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 12, fontWeight: 600, color: CHART.ink }}>
1681
+ After year {year}
1682
+ </Typography>
1683
+ <Typography sx={{ fontFamily: CHART.font, fontSize: 12, color: CHART.inkSoft }}>
1684
+ {hoveredTotal >= 0 ? `${euro(hoveredTotal)} ahead` : `${euro(-hoveredTotal)} still to recover`}
1685
+ </Typography>
1686
+ </Box>
1687
+ )}
1688
+ </Box>
1689
+ )
1690
+ }
1691
+ ```
1692
+
1693
+ ### ./src/\_charts/chart-style.ts
1694
+
1695
+ ```ts
1696
+ // The charts' series colours, in a fixed order and checked as a set for colour-vision deficiencies on the white
1697
+ // card. Two of them sit below 3:1 against white, so every chart keeps a legend, a tooltip and a table of its figures.
1698
+ export const SERIES = {
1699
+ selfUse: '#e8770e',
1700
+ exported: '#1baf7a',
1701
+ consumption: '#2a78d6',
1702
+ } as const
1703
+
1704
+ export const CHART = {
1705
+ surface: '#ffffff',
1706
+ ink: '#1c2826',
1707
+ inkSoft: '#5b6664',
1708
+ grid: '#e9e6df',
1709
+ axis: '#c9c4b8',
1710
+ font: "'Poppins', 'Helvetica Neue', Arial, sans-serif",
1711
+ } as const
1712
+ ```
1713
+
1714
+ ### ./src/\_charts/nice-scale.ts
1715
+
1716
+ ```ts
1717
+ // Round axis bounds and ticks for a value range: steps of 1, 2 or 5 times a power of ten, about `count` of them
1718
+ export const niceScale = (min: number, max: number, count: number) => {
1719
+ const span = Math.max(max - min, 1)
1720
+ const raw = span / count
1721
+ const magnitude = 10 ** Math.floor(Math.log10(raw))
1722
+ const step = [1, 2, 5, 10].map(factor => factor * magnitude).find(candidate => candidate >= raw) ?? 10 * magnitude
1723
+ const low = Math.floor(min / step) * step
1724
+ const high = Math.ceil(max / step) * step
1725
+ const ticks = Array.from({ length: Math.round((high - low) / step) + 1 }, (_, index) => low + index * step)
1726
+
1727
+ return { low, high, ticks }
1728
+ }
1729
+ ```
1730
+
1731
+ ### ./src/\_charts/use-width.ts
1732
+
1733
+ ```ts
1734
+ import { useLayoutEffect, useRef, useState } from 'react'
1735
+
1736
+ // The element's width in pixels, measured again whenever it changes, so a chart draws its text at its real size
1737
+ // instead of scaling a fixed drawing
1738
+ export const useWidth = () => {
1739
+ const ref = useRef<HTMLDivElement>(null)
1740
+ const [width, setWidth] = useState(0)
1741
+
1742
+ useLayoutEffect(() => {
1743
+ const element = ref.current
1744
+
1745
+ if (element === null) {
1746
+ return
1747
+ }
1748
+
1749
+ const observer = new ResizeObserver(([entry]) => {
1750
+ if (entry) {
1751
+ setWidth(entry.contentRect.width)
1752
+ }
1753
+ })
1754
+ observer.observe(element)
1755
+
1756
+ return () => observer.disconnect()
1757
+ }, [])
1758
+
1759
+ return { ref, width }
1760
+ }
1761
+ ```
1762
+
1763
+ ### ./src/\_shared/ChartCards.tsx
1764
+
1765
+ ```tsx
1766
+ import { Box, Typography } from '@mui/material'
1767
+ import type { ReactNode } from 'react'
1768
+
1769
+ import { EnergySplitBar, MonthlyEnergyChart, PaybackChart } from '../_charts/index.js'
1770
+ import { CARD_SX, SUNFOLD } from './tokens.js'
1771
+
1772
+ interface ChartCardProps {
1773
+ readonly title: string
1774
+ readonly subtitle: string
1775
+ readonly area?: string
1776
+ readonly children: ReactNode
1777
+ }
1778
+
1779
+ const ChartCard = ({ title, subtitle, area, children }: ChartCardProps) => {
1780
+ return (
1781
+ <Box
1782
+ component="section"
1783
+ aria-label={title}
1784
+ sx={{ ...CARD_SX, display: 'grid', alignContent: 'start', gap: 2, gridArea: area }}
1785
+ >
1786
+ <Box component="header" sx={{ display: 'grid', gap: 0.25 }}>
1787
+ <Typography component="h2" sx={{ fontFamily: SUNFOLD.font, fontSize: 16, fontWeight: 600, color: SUNFOLD.ink }}>
1788
+ {title}
1789
+ </Typography>
1790
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>{subtitle}</Typography>
1791
+ </Box>
1792
+ {children}
1793
+ </Box>
1794
+ )
1795
+ }
1796
+
1797
+ interface ChartCardsProps {
1798
+ readonly compact: boolean
1799
+ }
1800
+
1801
+ // The dashboard's charts: the year month by month across the full width, then the payback curve beside where the
1802
+ // power goes. On a phone they stack.
1803
+ export const ChartCards = ({ compact }: ChartCardsProps) => {
1804
+ return (
1805
+ <Box
1806
+ component="div"
1807
+ sx={{
1808
+ display: 'grid',
1809
+ gap: 2,
1810
+ gridTemplateColumns: compact ? 'minmax(0, 1fr)' : 'minmax(0, 3fr) minmax(0, 2fr)',
1811
+ gridTemplateAreas: compact ? '"monthly" "payback" "split"' : '"monthly monthly" "payback split"',
1812
+ }}
1813
+ >
1814
+ <ChartCard
1815
+ area="monthly"
1816
+ title="Your solar year"
1817
+ subtitle="Production by month, how much the home uses, and the home's own use"
1818
+ >
1819
+ <MonthlyEnergyChart height={compact ? 200 : 240} />
1820
+ </ChartCard>
1821
+ <ChartCard
1822
+ area="payback"
1823
+ title="When it pays back"
1824
+ subtitle="Money returned after the installed cost, with prices rising 2 % a year"
1825
+ >
1826
+ <PaybackChart height={compact ? 190 : 210} />
1827
+ </ChartCard>
1828
+ <ChartCard
1829
+ area="split"
1830
+ title="Where the power goes"
1831
+ subtitle="A year of production, split between the home and the grid"
1832
+ >
1833
+ <EnergySplitBar />
1834
+ </ChartCard>
1835
+ </Box>
1836
+ )
1837
+ }
1838
+ ```
1839
+
1840
+ ### ./src/\_shared/DesktopPage.tsx
1841
+
1842
+ ```tsx
1843
+ import { Box, Typography } from '@mui/material'
1844
+
1845
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
1846
+
1847
+ import { ChartCards } from './ChartCards.js'
1848
+ import { KpiTiles } from './KpiTiles.js'
1849
+ import { PlannerInputs } from './PlannerInputs.js'
1850
+ import { SurveyPanel } from './SurveyPanel.js'
1851
+ import { SUNFOLD } from './tokens.js'
1852
+
1853
+ const SIDEBAR_WIDTH = 340
1854
+
1855
+ // The desktop page: the inputs in a sidebar with the cost and the booking at its foot, and the dashboard beside it,
1856
+ // four figures above three charts
1857
+ export const DesktopPage = () => {
1858
+ const { accessInfo } = phx.frontend.useAccessService()
1859
+ const navigationState = phx.frontend.useActiveNavigationState()
1860
+ // A booked plan keeps its inputs until the household returns to the plan
1861
+ const readOnly = accessInfo.viewMode || navigationState === 'booked'
1862
+
1863
+ return (
1864
+ <Box
1865
+ component="div"
1866
+ sx={{
1867
+ position: 'absolute',
1868
+ inset: 0,
1869
+ display: 'grid',
1870
+ gridTemplateColumns: `${SIDEBAR_WIDTH}px minmax(0, 1fr)`,
1871
+ bgcolor: SUNFOLD.linen,
1872
+ fontFamily: SUNFOLD.font,
1873
+ }}
1874
+ >
1875
+ <Box
1876
+ component="aside"
1877
+ aria-label="Your plan"
1878
+ sx={{
1879
+ display: 'flex',
1880
+ flexDirection: 'column',
1881
+ minBlockSize: 0,
1882
+ bgcolor: SUNFOLD.card,
1883
+ borderInlineEnd: `1px solid ${SUNFOLD.line}`,
1884
+ }}
1885
+ >
1886
+ <Box
1887
+ component="div"
1888
+ sx={{ display: 'flex', alignItems: 'center', gap: 1.25, paddingInline: 3, paddingBlock: 2.5 }}
1889
+ >
1890
+ <Box
1891
+ component="span"
1892
+ aria-hidden
1893
+ sx={{
1894
+ inlineSize: 26,
1895
+ blockSize: 26,
1896
+ borderRadius: '50%',
1897
+ bgcolor: SUNFOLD.amber,
1898
+ boxShadow: `0 0 0 5px ${SUNFOLD.amberTint}`,
1899
+ }}
1900
+ />
1901
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 20, fontWeight: 600, color: SUNFOLD.ink }}>
1902
+ sunfold
1903
+ </Typography>
1904
+ </Box>
1905
+ <Box component="div" sx={{ flex: 1, minBlockSize: 0, overflowY: 'auto', paddingInline: 3, paddingBlockEnd: 3 }}>
1906
+ <PlannerInputs readOnly={readOnly} />
1907
+ </Box>
1908
+ <Box component="div" sx={{ padding: 3, borderBlockStart: `1px solid ${SUNFOLD.line}` }}>
1909
+ <SurveyPanel compact={false} />
1910
+ </Box>
1911
+ </Box>
1912
+
1913
+ <Box component="main" sx={{ minBlockSize: 0, overflowY: 'auto' }}>
1914
+ <Box component="div" sx={{ display: 'grid', gap: 2.5, maxInlineSize: 1180, marginInline: 'auto', padding: 4 }}>
1915
+ <Box component="header" sx={{ display: 'grid', gap: 0.5 }}>
1916
+ <Typography
1917
+ component="h1"
1918
+ sx={{ fontFamily: SUNFOLD.font, fontSize: 28, fontWeight: 600, color: SUNFOLD.ink }}
1919
+ >
1920
+ Your solar plan
1921
+ </Typography>
1922
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 14, color: SUNFOLD.muted }}>
1923
+ Estimates for a home in central Europe. Every figure follows the plan on the left.
1924
+ </Typography>
1925
+ </Box>
1926
+ <KpiTiles columns={4} />
1927
+ <ChartCards compact={false} />
1928
+ </Box>
1929
+ </Box>
1930
+
1931
+ {/* Snackbars, such as a failed save, stack upwards from the dashboard's bottom right corner */}
1932
+ <Box component="div" sx={{ position: 'absolute', insetBlockEnd: 24, insetInlineEnd: 24, inlineSize: 320 }}>
1933
+ <LayoutSlots.DesktopSnackbarsRoot />
1934
+ </Box>
1935
+ </Box>
1936
+ )
1937
+ }
1938
+ ```
1939
+
1940
+ ### ./src/\_shared/KpiTiles.tsx
1941
+
1942
+ ```tsx
1943
+ import { Box, Typography } from '@mui/material'
1944
+
1945
+ import { CARD_SX, SUNFOLD } from './tokens.js'
1946
+
1947
+ const euro = (value: number) => {
1948
+ return value.toLocaleString('en-IE', { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 })
1949
+ }
1950
+
1951
+ interface KpiTilesProps {
1952
+ readonly columns: number
1953
+ }
1954
+
1955
+ // The four figures a household asks first, each with the context that makes it mean something. Every value is an
1956
+ // expression of the spec, read from the root entity.
1957
+ export const KpiTiles = ({ columns }: KpiTilesProps) => {
1958
+ const plan = phx.frontend.useRootEntityState()
1959
+ const payback = plan.$paybackYears
1960
+ const tiles = [
1961
+ {
1962
+ label: 'System size',
1963
+ value: `${plan.$systemKwp.toFixed(1)} kWp`,
1964
+ context: `${plan.panels} panels, ${plan.$panelAreaM2} m² of roof`,
1965
+ },
1966
+ {
1967
+ label: 'Annual production',
1968
+ value: `${Math.round(plan.$annualProductionKwh).toLocaleString('en')} kWh`,
1969
+ context: `About ${plan.$co2Tonnes.toFixed(1)} t of CO₂ avoided a year`,
1970
+ },
1971
+ {
1972
+ label: 'Self-consumption',
1973
+ value: `${Math.round(plan.$selfConsumption * 100)} %`,
1974
+ context: 'of the solar power is used at home',
1975
+ },
1976
+ {
1977
+ label: 'Payback',
1978
+ value: Number.isFinite(payback) ? `${payback.toFixed(1)} years` : 'Over 25 years',
1979
+ context: `${euro(plan.$annualSavings)} saved in the first year`,
1980
+ },
1981
+ ]
1982
+
1983
+ return (
1984
+ <Box component="div" sx={{ display: 'grid', gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, gap: 2 }}>
1985
+ {tiles.map(tile => (
1986
+ <Box
1987
+ component="section"
1988
+ key={tile.label}
1989
+ aria-label={tile.label}
1990
+ sx={{ ...CARD_SX, display: 'grid', gap: 0.5, padding: 2 }}
1991
+ >
1992
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 13, color: SUNFOLD.muted }}>{tile.label}</Typography>
1993
+ <Typography
1994
+ sx={{
1995
+ fontFamily: SUNFOLD.font,
1996
+ fontSize: columns > 2 ? 30 : 24,
1997
+ fontWeight: 600,
1998
+ lineHeight: 1.15,
1999
+ color: SUNFOLD.ink,
2000
+ }}
2001
+ >
2002
+ {tile.value}
2003
+ </Typography>
2004
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>{tile.context}</Typography>
2005
+ </Box>
2006
+ ))}
2007
+ </Box>
2008
+ )
2009
+ }
2010
+ ```
2011
+
2012
+ ### ./src/\_shared/PhonePage.tsx
2013
+
2014
+ ```tsx
2015
+ import { Box, Typography } from '@mui/material'
2016
+
2017
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
2018
+
2019
+ import { ChartCards } from './ChartCards.js'
2020
+ import { KpiTiles } from './KpiTiles.js'
2021
+ import { PlannerInputs } from './PlannerInputs.js'
2022
+ import { SurveyPanel } from './SurveyPanel.js'
2023
+ import { CARD_SX, SUNFOLD } from './tokens.js'
2024
+
2025
+ // The phone page: one scrolling column with the figures first, the inputs below them and the charts last, and the
2026
+ // cost with the booking in a bar at the bottom
2027
+ export const PhonePage = () => {
2028
+ const { accessInfo } = phx.frontend.useAccessService()
2029
+ const navigationState = phx.frontend.useActiveNavigationState()
2030
+ const readOnly = accessInfo.viewMode || navigationState === 'booked'
2031
+
2032
+ return (
2033
+ <Box
2034
+ component="div"
2035
+ sx={{
2036
+ position: 'absolute',
2037
+ inset: 0,
2038
+ display: 'grid',
2039
+ gridTemplateRows: 'minmax(0, 1fr) auto',
2040
+ bgcolor: SUNFOLD.linen,
2041
+ fontFamily: SUNFOLD.font,
2042
+ }}
2043
+ >
2044
+ <Box component="main" sx={{ minBlockSize: 0, overflowY: 'auto' }}>
2045
+ <Box component="div" sx={{ display: 'grid', gap: 2, padding: 2 }}>
2046
+ <Box component="header" sx={{ display: 'flex', alignItems: 'center', gap: 1.25 }}>
2047
+ <Box
2048
+ component="span"
2049
+ aria-hidden
2050
+ sx={{
2051
+ inlineSize: 22,
2052
+ blockSize: 22,
2053
+ borderRadius: '50%',
2054
+ bgcolor: SUNFOLD.amber,
2055
+ boxShadow: `0 0 0 4px ${SUNFOLD.amberTint}`,
2056
+ }}
2057
+ />
2058
+ <Typography
2059
+ component="h1"
2060
+ sx={{ fontFamily: SUNFOLD.font, fontSize: 20, fontWeight: 600, color: SUNFOLD.ink }}
2061
+ >
2062
+ Your solar plan
2063
+ </Typography>
2064
+ </Box>
2065
+ <KpiTiles columns={2} />
2066
+ <Box component="div" sx={CARD_SX}>
2067
+ <PlannerInputs readOnly={readOnly} />
2068
+ </Box>
2069
+ <ChartCards compact />
2070
+ </Box>
2071
+ </Box>
2072
+ <Box
2073
+ component="footer"
2074
+ sx={{
2075
+ padding: 2,
2076
+ bgcolor: SUNFOLD.card,
2077
+ borderBlockStart: `1px solid ${SUNFOLD.line}`,
2078
+ boxShadow: '0 -8px 24px rgba(28, 40, 38, 0.08)',
2079
+ }}
2080
+ >
2081
+ <SurveyPanel compact />
2082
+ </Box>
2083
+ <LayoutSlots.MobileSnackbarsRoot />
2084
+ </Box>
2085
+ )
2086
+ }
2087
+ ```
2088
+
2089
+ ### ./src/\_shared/PillField.tsx
2090
+
2091
+ ```tsx
2092
+ import { Box, ButtonBase, Typography } from '@mui/material'
2093
+ import type { KeyboardEvent } from 'react'
2094
+
2095
+ import { SUNFOLD } from './tokens.js'
2096
+
2097
+ // Arrow keys move the selection between the pills, as in a native radio group
2098
+ const ARROW_STEPS: Readonly<Record<string, number | undefined>> = {
2099
+ ArrowRight: 1,
2100
+ ArrowDown: 1,
2101
+ ArrowLeft: -1,
2102
+ ArrowUp: -1,
2103
+ }
2104
+
2105
+ interface PillFieldProps {
2106
+ readonly instanceName: string
2107
+ readonly label: string
2108
+ readonly readOnly: boolean
2109
+ }
2110
+
2111
+ // One `attributeSelection` of the spec as a row of pills, with the chosen option's description below it
2112
+ export const PillField = ({ instanceName, label, readOnly }: PillFieldProps) => {
2113
+ const resolve = phx.frontend.useResolveLocalizable()
2114
+ const planId = phx.frontend.useRootEntityId()
2115
+ const { value, options } = phx.frontend.useAttributeSelection(planId, instanceName)
2116
+ const selected = options.find(option => option.value === value)
2117
+ const labelId = `sunfold-${instanceName}-label`
2118
+
2119
+ const handleKeyDown = (event: KeyboardEvent<HTMLElement>, index: number) => {
2120
+ const step = ARROW_STEPS[event.key]
2121
+
2122
+ if (step === undefined) {
2123
+ return
2124
+ }
2125
+
2126
+ event.preventDefault()
2127
+ const next = (index + step + options.length) % options.length
2128
+ options[next]?.onSelect()
2129
+ event.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role="radio"]')[next]?.focus()
2130
+ }
2131
+
2132
+ return (
2133
+ <Box component="div" sx={{ display: 'grid', gap: 0.75 }}>
2134
+ <Typography id={labelId} sx={{ fontFamily: SUNFOLD.font, fontSize: 14, color: SUNFOLD.ink }}>
2135
+ {label}
2136
+ </Typography>
2137
+ <Box
2138
+ component="div"
2139
+ role="radiogroup"
2140
+ aria-labelledby={labelId}
2141
+ sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.75 }}
2142
+ >
2143
+ {options.map((option, index) => {
2144
+ const isSelected = option.value === value
2145
+
2146
+ return (
2147
+ <ButtonBase
2148
+ key={String(option.value)}
2149
+ role="radio"
2150
+ aria-checked={isSelected}
2151
+ tabIndex={isSelected ? 0 : -1}
2152
+ disabled={readOnly && !isSelected}
2153
+ onClick={readOnly ? undefined : option.onSelect}
2154
+ onKeyDown={readOnly ? undefined : event => handleKeyDown(event, index)}
2155
+ sx={{
2156
+ paddingInline: 1.5,
2157
+ paddingBlock: 0.75,
2158
+ borderRadius: 999,
2159
+ border: `1px solid ${isSelected ? SUNFOLD.green : SUNFOLD.line}`,
2160
+ bgcolor: isSelected ? SUNFOLD.green : SUNFOLD.card,
2161
+ color: isSelected ? SUNFOLD.card : SUNFOLD.ink,
2162
+ fontFamily: SUNFOLD.font,
2163
+ fontSize: 13,
2164
+ fontWeight: isSelected ? 500 : 400,
2165
+ transition: 'background-color 120ms',
2166
+ '&:hover': { borderColor: SUNFOLD.green },
2167
+ '&.Mui-focusVisible': { outline: `2px solid ${SUNFOLD.amber}`, outlineOffset: 2 },
2168
+ }}
2169
+ >
2170
+ {resolve(option.title)}
2171
+ </ButtonBase>
2172
+ )
2173
+ })}
2174
+ </Box>
2175
+ {selected?.description && (
2176
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>
2177
+ {resolve(selected.description)}
2178
+ </Typography>
2179
+ )}
2180
+ </Box>
2181
+ )
2182
+ }
2183
+ ```
2184
+
2185
+ ### ./src/\_shared/PlannerInputs.tsx
2186
+
2187
+ ```tsx
2188
+ import { Box, Typography } from '@mui/material'
2189
+ import type { ReactNode } from 'react'
2190
+
2191
+ import { PillField } from './PillField.js'
2192
+ import { SliderField } from './SliderField.js'
2193
+ import { SUNFOLD } from './tokens.js'
2194
+
2195
+ interface GroupProps {
2196
+ readonly title: string
2197
+ // The invariant types whose message belongs under this group
2198
+ readonly messageTypes?: readonly string[]
2199
+ readonly children: ReactNode
2200
+ }
2201
+
2202
+ // A group of inputs with the message of an invariant the group can resolve: a warning, which blocks the booking, in
2203
+ // amber, a notice, which only informs, in blue. `useFinalizeViolations` lists both.
2204
+ const Group = ({ title, messageTypes = [], children }: GroupProps) => {
2205
+ const { violations } = phx.frontend.useFinalizeViolations()
2206
+ const resolve = phx.frontend.useResolveLocalizable()
2207
+ const messages = (violations ?? []).filter(({ violation }) => messageTypes.includes(violation.type))
2208
+
2209
+ return (
2210
+ <Box component="section" sx={{ display: 'grid', gap: 2 }}>
2211
+ <Typography component="h3" sx={{ fontFamily: SUNFOLD.font, fontSize: 13, fontWeight: 600, color: SUNFOLD.muted }}>
2212
+ {title}
2213
+ </Typography>
2214
+ {children}
2215
+ {messages.map(({ violation }) => {
2216
+ const isNotice = violation.severity === 'notice'
2217
+
2218
+ return (
2219
+ <Typography
2220
+ key={violation.type}
2221
+ role={isNotice ? 'status' : 'alert'}
2222
+ sx={{
2223
+ paddingInline: 1.5,
2224
+ paddingBlock: 1,
2225
+ borderRadius: 2,
2226
+ bgcolor: isNotice ? SUNFOLD.infoTint : SUNFOLD.warningTint,
2227
+ color: isNotice ? SUNFOLD.info : SUNFOLD.warning,
2228
+ fontFamily: SUNFOLD.font,
2229
+ fontSize: 13,
2230
+ lineHeight: 1.45,
2231
+ }}
2232
+ >
2233
+ {resolve(violation.message)}
2234
+ </Typography>
2235
+ )
2236
+ })}
2237
+ </Box>
2238
+ )
2239
+ }
2240
+
2241
+ interface PlannerInputsProps {
2242
+ readonly readOnly: boolean
2243
+ }
2244
+
2245
+ // The household's inputs: the roof, the panels on it, the home's use and tariff, and the battery
2246
+ export const PlannerInputs = ({ readOnly }: PlannerInputsProps) => {
2247
+ const plan = phx.frontend.useRootEntityState()
2248
+
2249
+ return (
2250
+ <Box component="div" sx={{ display: 'grid', gap: 3.5 }}>
2251
+ <Group title="Your roof" messageTypes={['panelsExceedRoof', 'northFacing']}>
2252
+ <SliderField instanceName="roofArea" label="Usable roof area" step={1} readOnly={readOnly} />
2253
+ <PillField instanceName="orientation" label="Facing" readOnly={readOnly} />
2254
+ <SliderField instanceName="panels" label="Panels" step={1} readOnly={readOnly} />
2255
+ <Typography sx={{ marginBlockStart: -1.5, fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>
2256
+ 430 W panels, 1.95 m² each. This roof holds up to {plan.$roofPanelLimit}.
2257
+ </Typography>
2258
+ </Group>
2259
+ <Group title="Your home">
2260
+ <SliderField instanceName="annualUse" label="Electricity used a year" step={100} readOnly={readOnly} />
2261
+ <PillField instanceName="tariff" label="Tariff" readOnly={readOnly} />
2262
+ </Group>
2263
+ <Group title="Storage">
2264
+ <PillField instanceName="battery" label="Home battery" readOnly={readOnly} />
2265
+ </Group>
2266
+ </Box>
2267
+ )
2268
+ }
2269
+ ```
2270
+
2271
+ ### ./src/\_shared/SliderField.tsx
2272
+
2273
+ ```tsx
2274
+ import { Box, Slider, Typography } from '@mui/material'
2275
+
2276
+ import { SUNFOLD } from './tokens.js'
2277
+
2278
+ interface SliderFieldProps {
2279
+ readonly instanceName: string
2280
+ readonly label: string
2281
+ readonly step: number
2282
+ readonly readOnly: boolean
2283
+ }
2284
+
2285
+ // One `genericDimension` of the spec as a slider with its value and unit above it. Dragging stages each value, so
2286
+ // every tile and chart follows the thumb, and letting go commits it.
2287
+ export const SliderField = ({ instanceName, label, step, readOnly }: SliderFieldProps) => {
2288
+ const planId = phx.frontend.useRootEntityId()
2289
+ const dimension = phx.frontend.useGenericDimension(planId, instanceName)
2290
+ const labelId = `sunfold-${instanceName}-label`
2291
+
2292
+ return (
2293
+ <Box component="div" sx={{ display: 'grid', gap: 0.25 }}>
2294
+ <Box component="div" sx={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 2 }}>
2295
+ <Typography id={labelId} sx={{ fontFamily: SUNFOLD.font, fontSize: 14, color: SUNFOLD.ink }}>
2296
+ {label}
2297
+ </Typography>
2298
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 15, fontWeight: 600, color: SUNFOLD.ink }}>
2299
+ {dimension.value.toLocaleString('en')} {dimension.unit}
2300
+ </Typography>
2301
+ </Box>
2302
+ <Slider
2303
+ value={dimension.value}
2304
+ min={dimension.min ?? 0}
2305
+ max={dimension.max ?? 100}
2306
+ step={step}
2307
+ disabled={readOnly}
2308
+ onChange={(_, value) => dimension.update(Array.isArray(value) ? (value[0] ?? 0) : value)}
2309
+ onChangeCommitted={() => dimension.resolve()}
2310
+ slotProps={{ input: { 'aria-labelledby': labelId } }}
2311
+ sx={{
2312
+ color: SUNFOLD.green,
2313
+ '& .MuiSlider-rail': { bgcolor: SUNFOLD.line, opacity: 1 },
2314
+ '& .MuiSlider-thumb': {
2315
+ inlineSize: 18,
2316
+ blockSize: 18,
2317
+ bgcolor: SUNFOLD.card,
2318
+ border: `3px solid ${SUNFOLD.green}`,
2319
+ },
2320
+ }}
2321
+ />
2322
+ </Box>
2323
+ )
2324
+ }
2325
+ ```
2326
+
2327
+ ### ./src/\_shared/SurveyPanel.tsx
2328
+
2329
+ ```tsx
2330
+ import { Alert, Box, Button, CircularProgress, Typography } from '@mui/material'
2331
+
2332
+ import { SUNFOLD } from './tokens.js'
2333
+
2334
+ interface SurveyPanelProps {
2335
+ // On a phone the panel is a bar: the cost beside the button, without the hints
2336
+ readonly compact: boolean
2337
+ }
2338
+
2339
+ // The system's cost, the `price` component's value, and the spec's `survey` finalize action. A warning blocks the
2340
+ // booking and its `hints` say why; a notice does not. In the `booked` navigation state the panel confirms the
2341
+ // request instead.
2342
+ export const SurveyPanel = ({ compact }: SurveyPanelProps) => {
2343
+ const cost = phx.frontend.useRootEntityPrice()
2344
+ const { primary, hints } = phx.frontend.useFinalizeActions()
2345
+ const navigationState = phx.frontend.useActiveNavigationState()
2346
+ const navigate = phx.frontend.useNavigate()
2347
+ const { accessInfo } = phx.frontend.useAccessService()
2348
+ const isPending = primary?.isPending ?? false
2349
+
2350
+ if (navigationState === 'booked') {
2351
+ return (
2352
+ <Box component="div" role="status" sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
2353
+ <Box component="div" sx={{ display: 'grid', flex: 1 }}>
2354
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 16, fontWeight: 600, color: SUNFOLD.green }}>
2355
+ Survey requested
2356
+ </Typography>
2357
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 13, color: SUNFOLD.muted }}>
2358
+ An installer calls within two working days.
2359
+ </Typography>
2360
+ </Box>
2361
+ <Button
2362
+ onClick={() => navigate('plan')}
2363
+ sx={{
2364
+ fontFamily: SUNFOLD.font,
2365
+ fontSize: 13,
2366
+ color: SUNFOLD.ink,
2367
+ textTransform: 'none',
2368
+ textDecoration: 'underline',
2369
+ }}
2370
+ >
2371
+ Back to the plan
2372
+ </Button>
2373
+ </Box>
2374
+ )
2375
+ }
2376
+
2377
+ const showButton = primary !== null && !accessInfo.viewMode
2378
+
2379
+ return (
2380
+ <Box component="div" sx={{ display: 'grid', gap: 1.25 }}>
2381
+ <Box
2382
+ component="div"
2383
+ sx={{
2384
+ display: 'flex',
2385
+ flexDirection: compact ? 'row' : 'column',
2386
+ alignItems: compact ? 'center' : 'stretch',
2387
+ justifyContent: 'space-between',
2388
+ gap: compact ? 2 : 1.5,
2389
+ }}
2390
+ >
2391
+ <Box component="div" sx={{ display: 'grid' }}>
2392
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.muted }}>Installed cost</Typography>
2393
+ <Typography
2394
+ sx={{ fontFamily: SUNFOLD.font, fontSize: compact ? 20 : 26, fontWeight: 600, color: SUNFOLD.ink }}
2395
+ >
2396
+ {cost}
2397
+ </Typography>
2398
+ </Box>
2399
+ {showButton && (
2400
+ <Button
2401
+ variant="contained"
2402
+ disableElevation
2403
+ disabled={primary.disabled || isPending}
2404
+ onClick={() => void primary.run()}
2405
+ title={primary.title}
2406
+ startIcon={isPending ? <CircularProgress size={16} color="inherit" /> : undefined}
2407
+ sx={{
2408
+ minBlockSize: 46,
2409
+ paddingInline: 2.5,
2410
+ borderRadius: 999,
2411
+ bgcolor: SUNFOLD.green,
2412
+ fontFamily: SUNFOLD.font,
2413
+ fontSize: 14,
2414
+ fontWeight: 500,
2415
+ textTransform: 'none',
2416
+ '&:hover': { bgcolor: SUNFOLD.greenDark },
2417
+ '&.Mui-disabled': { bgcolor: SUNFOLD.line, color: SUNFOLD.muted },
2418
+ }}
2419
+ >
2420
+ {isPending ? 'Booking…' : primary.label}
2421
+ </Button>
2422
+ )}
2423
+ </Box>
2424
+ {!compact && showButton && primary.disabled && hints && (
2425
+ <Typography sx={{ fontFamily: SUNFOLD.font, fontSize: 12, color: SUNFOLD.warning }}>{hints}</Typography>
2426
+ )}
2427
+ {primary?.error && <Alert severity="error">The survey could not be booked: {primary.error.message}</Alert>}
2428
+ </Box>
2429
+ )
2430
+ }
2431
+ ```
2432
+
2433
+ ### ./src/\_shared/tokens.ts
2434
+
2435
+ ```ts
2436
+ // Sunfold's palette and type: warm linen, a deep green ink and the amber of the logo. Poppins is the brand's typeface;
2437
+ // the stack falls back to system fonts where it is not loaded.
2438
+ export const SUNFOLD = {
2439
+ linen: '#f6f3ec',
2440
+ card: '#ffffff',
2441
+ ink: '#1c2826',
2442
+ muted: '#5b6664',
2443
+ line: '#e7e2d8',
2444
+ green: '#1f6f54',
2445
+ greenDark: '#17583f',
2446
+ amber: '#f2a516',
2447
+ amberTint: '#fff4dc',
2448
+ warning: '#9a4b00',
2449
+ warningTint: '#fff3e0',
2450
+ info: '#2a5c8a',
2451
+ infoTint: '#e9f1f9',
2452
+ font: "'Poppins', 'Helvetica Neue', Arial, sans-serif",
2453
+ } as const
2454
+
2455
+ export const CARD_SX = {
2456
+ padding: 2.5,
2457
+ borderRadius: 3,
2458
+ bgcolor: SUNFOLD.card,
2459
+ boxShadow: '0 1px 2px rgba(28, 40, 38, 0.06)',
2460
+ border: `1px solid ${SUNFOLD.line}`,
2461
+ } as const
2462
+ ```
2463
+
2464
+ ### ./src/elements/ConfiguratorLayout.tsx
2465
+
2466
+ ```tsx
2467
+ import { Box } from '@mui/material'
2468
+
2469
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
2470
+
2471
+ import { DesktopPage } from '../_shared/DesktopPage.js'
2472
+ import { PhonePage } from '../_shared/PhonePage.js'
2473
+ import { SUNFOLD } from '../_shared/tokens.js'
2474
+
2475
+ // A planning dashboard with no scene: the layout never mounts `LayoutSlots.SharedCanvas`, and every tile and chart is
2476
+ // React and SVG drawn from the spec's expressions
2477
+ const ConfiguratorLayout = () => {
2478
+ // `null` until the container has been measured
2479
+ const viewports = phx.frontend.useActiveViewports()
2480
+ const isDesktop = viewports?.includes('desktop') ?? false
2481
+
2482
+ return (
2483
+ <Box component="div" sx={{ position: 'absolute', inset: 0, overflow: 'clip', bgcolor: SUNFOLD.linen }}>
2484
+ <LayoutSlots.Services />
2485
+ {viewports !== null && (isDesktop ? <DesktopPage /> : <PhonePage />)}
2486
+ </Box>
2487
+ )
2488
+ }
2489
+
2490
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
2491
+ ```
2492
+
2493
+ ### ./src/expressions/solar.ts
2494
+
2495
+ ```ts
2496
+ const PANEL_KWP = 0.43
2497
+ const PANEL_AREA_M2 = 1.95
2498
+ // Vents, chimneys and the edge clearance leave about 85 % of a roof for panels
2499
+ const USABLE_ROOF = 0.85
2500
+ // A south-facing kWp in central Europe yields about 1,000 kWh a year
2501
+ const YIELD_KWH_PER_KWP = 1000
2502
+ const ORIENTATION_FACTOR = { South: 1, SouthEastWest: 0.95, EastWest: 0.82, North: 0.6 }
2503
+
2504
+ const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
2505
+ // The share of the year's sun and of the household's use that falls in each month
2506
+ const SUN_SHARE = [0.04, 0.045, 0.08, 0.105, 0.125, 0.13, 0.13, 0.115, 0.09, 0.065, 0.04, 0.035]
2507
+ const USE_SHARE = [0.1, 0.09, 0.088, 0.08, 0.075, 0.07, 0.07, 0.072, 0.076, 0.085, 0.094, 0.1]
2508
+ const DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
2509
+
2510
+ const BATTERY_KWH = { None: 0, Kwh5: 5, Kwh10: 10, Kwh15: 15 }
2511
+ const BATTERY_PRICE = { None: 0, Kwh5: 3600, Kwh10: 6400, Kwh15: 8900 }
2512
+ const TARIFF = {
2513
+ Flat: { buy: 0.32, sell: 0.08, shiftBonus: 0 },
2514
+ TimeOfUse: { buy: 0.29, sell: 0.1, shiftBonus: 0.09 },
2515
+ ExportPlus: { buy: 0.32, sell: 0.15, shiftBonus: 0 },
2516
+ }
2517
+ // Panels lose half a percent a year; electricity gets 2 % dearer a year
2518
+ const DEGRADATION = 0.995
2519
+ const PRICE_GROWTH = 1.02
2520
+ const YEARS = 25
2521
+
2522
+ export default phx.domain.implementCustomExpressions({
2523
+ SolarPlan: {
2524
+ $systemKwp: s => {
2525
+ return s.panels * PANEL_KWP
2526
+ },
2527
+ $roofPanelLimit: s => {
2528
+ return Math.floor((s.roofArea * USABLE_ROOF) / PANEL_AREA_M2)
2529
+ },
2530
+ // The roof the panels cover, rounded up to whole square metres, as the tiles and the roof warning quote it
2531
+ $panelAreaM2: s => {
2532
+ return Math.ceil(s.panels * PANEL_AREA_M2)
2533
+ },
2534
+ $annualProductionKwh: s => {
2535
+ return s.$systemKwp * YIELD_KWH_PER_KWP * ORIENTATION_FACTOR[s.orientation]
2536
+ },
2537
+ // Each month's production and use, and how the production splits between the home and the grid. Without a
2538
+ // battery the home uses solar power only while the sun shines; a battery carries the surplus into the evening,
2539
+ // one charge a day, and covers the evening but not the early morning.
2540
+ $monthly: s => {
2541
+ const batteryKwh = BATTERY_KWH[s.battery] * 0.9
2542
+
2543
+ return MONTHS.map((month, index) => {
2544
+ const productionKwh = s.$annualProductionKwh * (SUN_SHARE[index] ?? 0)
2545
+ const consumptionKwh = s.annualUse * (USE_SHARE[index] ?? 0)
2546
+ const direct = Math.min(productionKwh * 0.55, consumptionKwh * 0.45)
2547
+ const stored = Math.min(
2548
+ productionKwh - direct,
2549
+ batteryKwh * (DAYS[index] ?? 30),
2550
+ (consumptionKwh - direct) * 0.6
2551
+ )
2552
+ const selfUseKwh = direct + stored
2553
+
2554
+ return { month, productionKwh, consumptionKwh, selfUseKwh, exportKwh: productionKwh - selfUseKwh }
2555
+ })
2556
+ },
2557
+ $selfConsumption: s => {
2558
+ const selfUse = s.$monthly.reduce((sum, month) => sum + month.selfUseKwh, 0)
2559
+
2560
+ return s.$annualProductionKwh > 0 ? selfUse / s.$annualProductionKwh : 0
2561
+ },
2562
+ $selfSufficiency: s => {
2563
+ const selfUse = s.$monthly.reduce((sum, month) => sum + month.selfUseKwh, 0)
2564
+
2565
+ return selfUse / s.annualUse
2566
+ },
2567
+ // A year's saving: power the home no longer buys, power sold to the grid, and on a time-of-use tariff the
2568
+ // evening power a battery shifts away from the dear hours
2569
+ $annualSavings: s => {
2570
+ const tariff = TARIFF[s.tariff]
2571
+ const selfUse = s.$monthly.reduce((sum, month) => sum + month.selfUseKwh, 0)
2572
+ const exported = s.$monthly.reduce((sum, month) => sum + month.exportKwh, 0)
2573
+ const shifted = s.battery === 'None' ? 0 : selfUse * 0.4
2574
+
2575
+ return selfUse * tariff.buy + exported * tariff.sell + shifted * tariff.shiftBonus
2576
+ },
2577
+ $systemCost: s => {
2578
+ return Math.round(1500 + s.$systemKwp * 1050 + BATTERY_PRICE[s.battery])
2579
+ },
2580
+ // The money the system has returned at the end of each year, starting at minus its cost in year 0
2581
+ $cumulativeSavings: s => {
2582
+ return Array.from({ length: YEARS + 1 }, (_, year) => {
2583
+ const earned = Array.from(
2584
+ { length: year },
2585
+ (__, past) => s.$annualSavings * (PRICE_GROWTH * DEGRADATION) ** past
2586
+ ).reduce((sum, value) => sum + value, 0)
2587
+
2588
+ return earned - s.$systemCost
2589
+ })
2590
+ },
2591
+ // The year the running total crosses zero, between whole years; beyond the panels' 25 years it is `Infinity`
2592
+ $paybackYears: s => {
2593
+ const totals = s.$cumulativeSavings
2594
+ const year = totals.findIndex(total => total >= 0)
2595
+
2596
+ if (year <= 0) {
2597
+ return year === 0 ? 0 : Infinity
2598
+ }
2599
+
2600
+ const before = totals[year - 1] ?? 0
2601
+ const after = totals[year] ?? 0
2602
+
2603
+ return year - 1 + -before / (after - before)
2604
+ },
2605
+ $co2Tonnes: s => {
2606
+ return (s.$annualProductionKwh * 0.35) / 1000
2607
+ },
2608
+ },
2609
+ })
2610
+ ```
2611
+
2612
+ ### ./src/handlers/book-survey.ts
2613
+
2614
+ ```ts
2615
+ import { useCallback } from 'react'
2616
+
2617
+ // Stands in for the installer's booking service: the request takes a moment, then the page shows the confirmation
2618
+ export default phx.frontend.createPhoenixHandler('bookSurvey', () => {
2619
+ const navigate = phx.frontend.useNavigate()
2620
+
2621
+ return {
2622
+ handler: useCallback(async () => {
2623
+ await new Promise(resolve => setTimeout(resolve, 1200))
2624
+ navigate('booked')
2625
+ }, [navigate]),
2626
+ }
2627
+ })
2628
+ ```
2629
+
2630
+ ### ./src/invariants/solar.ts
2631
+
2632
+ ```ts
2633
+ // More panels than the roof holds is a warning: the dashboard keeps showing the figures, and a survey cannot be
2634
+ // booked until the panel count fits. A north-facing roof is only a notice, so it never blocks the booking.
2635
+ export default phx.domain.implementCustomInvariants({
2636
+ SolarPlan: {
2637
+ panelsFitRoof: s => {
2638
+ if (s.panels <= s.$roofPanelLimit) {
2639
+ return []
2640
+ }
2641
+
2642
+ return [
2643
+ {
2644
+ type: 'panelsExceedRoof',
2645
+ severity: 'warning',
2646
+ message: `${s.panels} panels need about ${s.$panelAreaM2} m² of roof; ${s.roofArea} m² holds at most ${s.$roofPanelLimit}. Lower the panel count or measure the roof again.`,
2647
+ },
2648
+ ]
2649
+ },
2650
+ northFacing: s => {
2651
+ return s.orientation !== 'North'
2652
+ },
2653
+ },
2654
+ })
2655
+ ```
2656
+
2657
+ </details>