@salsita-ai/sdk 0.50.0-develop.ca72986c39 → 0.50.0-develop.cba048b0d7

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 (1313) hide show
  1. package/README.md +9 -5
  2. package/dist/admin/default-admin-elements.d.ts +9 -0
  3. package/dist/admin/default-admin-elements.js +1 -0
  4. package/dist/admin/default-elements/built-in-entity-element.d.ts +10 -0
  5. package/dist/admin/default-elements/built-in-entity-element.js +1 -0
  6. package/dist/admin/default-elements/built-in-layout-element.d.ts +10 -0
  7. package/dist/admin/default-elements/built-in-layout-element.js +1 -0
  8. package/dist/admin/default-elements/index.d.ts +2 -0
  9. package/dist/admin/default-elements/index.js +1 -0
  10. package/dist/admin/index.d.ts +1 -0
  11. package/dist/admin/index.js +1 -1
  12. package/dist/application/index.d.ts +1 -0
  13. package/dist/application/index.js +1 -1
  14. package/dist/application/mount-application.d.ts +1 -1
  15. package/dist/application/mount-application.js +1 -1
  16. package/dist/application/mount-configurator.d.ts +19 -0
  17. package/dist/application/mount-configurator.js +1 -0
  18. package/dist/application/mounted-application-runtime.d.ts +4 -0
  19. package/dist/application/mounted-application-runtime.js +1 -0
  20. package/dist/application/register-web-component.d.ts +2 -0
  21. package/dist/application/register-web-component.js +1 -0
  22. package/dist/application-spec/caching/content-diff.js +1 -1
  23. package/dist/application-spec/core/application-file.d.ts +0 -2
  24. package/dist/application-spec/core/application-file.js +1 -1
  25. package/dist/application-spec/core/enhanced-json-value.d.ts +2 -31
  26. package/dist/application-spec/core/enhanced-json-value.js +1 -1
  27. package/dist/application-spec/core/index.d.ts +1 -3
  28. package/dist/application-spec/core/index.js +1 -1
  29. package/dist/application-spec/core/json-schema.d.ts +2 -52
  30. package/dist/application-spec/core/markers/index.d.ts +1 -1
  31. package/dist/application-spec/core/markers/index.js +1 -1
  32. package/dist/application-spec/core/markers/msg-marker.d.ts +2 -28
  33. package/dist/application-spec/core/markers/msg-marker.js +1 -1
  34. package/dist/application-spec/core/markers/raw-eval-write-marker.d.ts +1 -1
  35. package/dist/application-spec/core/markers/raw-eval-write-marker.js +1 -1
  36. package/dist/application-spec/core/markers/raw-read-write-marker.js +1 -1
  37. package/dist/application-spec/errors/diagnostic-codes.d.ts +22 -1
  38. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  39. package/dist/application-spec/errors/diagnostic-messages.d.ts +30 -2
  40. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  41. package/dist/application-spec/generate-application/code/common/code-imports.js +1 -1
  42. package/dist/application-spec/generate-application/code/common/env-reader.js +2 -2
  43. package/dist/application-spec/generate-application/code/common/index.d.ts +1 -0
  44. package/dist/application-spec/generate-application/code/common/index.js +1 -1
  45. package/dist/application-spec/generate-application/code/common/single-quoted-string.d.ts +6 -0
  46. package/dist/application-spec/generate-application/code/common/single-quoted-string.js +1 -0
  47. package/dist/application-spec/generate-application/code/domain-runtime-files.js +1 -1
  48. package/dist/application-spec/generate-application/code/project-scaffolding.d.ts +10 -14
  49. package/dist/application-spec/generate-application/code/project-scaffolding.js +2 -2
  50. package/dist/application-spec/generate-application/code/story-files.js +1 -1
  51. package/dist/application-spec/generate-application/code/templates/admin-config.js +3 -0
  52. package/dist/application-spec/generate-application/code/templates/application-types.js +6 -6
  53. package/dist/application-spec/generate-application/code/templates/common/doc-comment.d.ts +2 -0
  54. package/dist/application-spec/generate-application/code/templates/common/doc-comment.js +1 -0
  55. package/dist/application-spec/generate-application/code/templates/common/format-property-key.d.ts +7 -0
  56. package/dist/application-spec/generate-application/code/templates/common/format-property-key.js +1 -0
  57. package/dist/application-spec/generate-application/code/templates/common/schema-to-type-string.js +3 -3
  58. package/dist/application-spec/generate-application/code/templates/configurator-globals.d.ts +2 -1
  59. package/dist/application-spec/generate-application/code/templates/configurator-globals.js +19 -6
  60. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/domain-factory-types.d.ts +35 -0
  61. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/domain-factory-types.js +5 -0
  62. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/index.d.ts +1 -0
  63. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/index.js +1 -0
  64. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-component-optics.d.ts +1 -1
  65. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-component-optics.js +6 -6
  66. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.js +59 -63
  67. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-invariants.d.ts +8 -0
  68. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-invariants.js +1 -1
  69. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-presets.js +1 -1
  70. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-resources.js +13 -13
  71. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-states.d.ts +1 -1
  72. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-states.js +2 -2
  73. package/dist/application-spec/generate-application/code/templates/domain-spec/index.d.ts +2 -1
  74. package/dist/application-spec/generate-application/code/templates/domain-spec/index.js +1 -1
  75. package/dist/application-spec/generate-application/code/templates/eslint-config.d.ts +5 -0
  76. package/dist/application-spec/generate-application/code/templates/eslint-config.js +4 -5
  77. package/dist/application-spec/generate-application/code/templates/gitignore.js +1 -3
  78. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.js +7 -7
  79. package/dist/application-spec/generate-application/code/templates/global-definition/generate-assistant-form-element-types.d.ts +12 -0
  80. package/dist/application-spec/generate-application/code/templates/global-definition/generate-assistant-form-element-types.js +7 -0
  81. package/dist/application-spec/generate-application/code/templates/global-definition/generate-phx-types.d.ts +43 -0
  82. package/dist/application-spec/generate-application/code/templates/global-definition/generate-phx-types.js +33 -0
  83. package/dist/application-spec/generate-application/code/templates/global-definition/index.d.ts +2 -0
  84. package/dist/application-spec/generate-application/code/templates/global-definition/index.js +1 -1
  85. package/dist/application-spec/generate-application/code/templates/globals.js +24 -43
  86. package/dist/application-spec/generate-application/code/templates/index.d.ts +4 -8
  87. package/dist/application-spec/generate-application/code/templates/index.js +1 -1
  88. package/dist/application-spec/generate-application/code/templates/lingui-rc.d.ts +5 -0
  89. package/dist/application-spec/generate-application/code/templates/lingui-rc.js +4 -4
  90. package/dist/application-spec/generate-application/code/templates/prettier-config.d.ts +5 -0
  91. package/dist/application-spec/generate-application/code/templates/prettier-config.js +4 -5
  92. package/dist/application-spec/generate-application/code/templates/skills/phoenix-cli-skill.js +1 -1
  93. package/dist/application-spec/generate-application/code/templates/skills/phoenix-create-configurator-skill.js +1 -1
  94. package/dist/application-spec/generate-application/code/templates/skills/phoenix-feedback-skill.js +5 -5
  95. package/dist/application-spec/generate-application/code/templates/skills/phoenix-review-skill.js +3 -3
  96. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill-bundle.d.ts +10 -0
  97. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill-bundle.js +7 -0
  98. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill.js +1 -1
  99. package/dist/application-spec/generate-application/code/templates/skills/phoenix-variants-skill.js +2 -2
  100. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +27 -9
  101. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +2 -2
  102. package/dist/application-spec/generate-application/code/templates/spec-code/collect-spec-code.d.ts +58 -0
  103. package/dist/application-spec/generate-application/code/templates/spec-code/collect-spec-code.js +1 -0
  104. package/dist/application-spec/generate-application/code/templates/spec-code/index.d.ts +2 -0
  105. package/dist/application-spec/generate-application/code/templates/spec-code/index.js +1 -0
  106. package/dist/application-spec/generate-application/code/templates/spec-code/spec-code.d.ts +18 -0
  107. package/dist/application-spec/generate-application/code/templates/spec-code/spec-code.js +41 -0
  108. package/dist/application-spec/generate-application/code/templates/spec-messages/index.d.ts +1 -0
  109. package/dist/application-spec/generate-application/code/templates/spec-messages/index.js +1 -0
  110. package/dist/application-spec/generate-application/code/templates/spec-messages/spec-messages.d.ts +20 -0
  111. package/dist/application-spec/generate-application/code/templates/spec-messages/spec-messages.js +6 -0
  112. package/dist/application-spec/generate-application/code/templates/story/phx-module.d.ts +8 -2
  113. package/dist/application-spec/generate-application/code/templates/story/phx-module.js +15 -3
  114. package/dist/application-spec/generate-application/code/templates/story/wrapper.d.ts +3 -0
  115. package/dist/application-spec/generate-application/code/templates/story/wrapper.js +2 -1
  116. package/dist/application-spec/generate-application/implementations/phx-application-types.d.ts +25 -0
  117. package/dist/application-spec/generate-application/implementations/phx-application-types.js +1 -0
  118. package/dist/application-spec/generate-application/implementations/phx-domain.d.ts +36 -0
  119. package/dist/application-spec/generate-application/implementations/phx-domain.js +1 -0
  120. package/dist/application-spec/generate-application/implementations/phx-model.d.ts +24 -0
  121. package/dist/application-spec/generate-application/implementations/phx-model.js +1 -0
  122. package/dist/application-spec/generate-application/implementations/phx.d.ts +22 -0
  123. package/dist/application-spec/generate-application/implementations/phx.js +1 -0
  124. package/dist/application-spec/generate-application/index.d.ts +2 -0
  125. package/dist/application-spec/generate-application/index.js +1 -1
  126. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-model-runtime.d.ts +6 -5
  127. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-model-runtime.js +1 -1
  128. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-runtime.d.ts +9 -5
  129. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-runtime.js +1 -1
  130. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-spec-runtime.d.ts +16 -0
  131. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-spec-runtime.js +1 -0
  132. package/dist/application-spec/generate-application/runtime/admin-runtime/states-runtime.d.ts +2 -2
  133. package/dist/application-spec/generate-application/runtime/application-runtime.d.ts +29 -9
  134. package/dist/application-spec/generate-application/runtime/application-runtime.js +1 -1
  135. package/dist/application-spec/generate-application/runtime/application-spec-slice.d.ts +71 -0
  136. package/dist/application-spec/generate-application/runtime/application-spec-slice.js +1 -0
  137. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-model-runtime.d.ts +7 -6
  138. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-model-runtime.js +1 -1
  139. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.d.ts +9 -6
  140. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.js +1 -1
  141. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-spec-runtime.d.ts +16 -0
  142. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-spec-runtime.js +1 -0
  143. package/dist/application-spec/generate-application/runtime/configurator-runtime/states-runtime.d.ts +2 -2
  144. package/dist/application-spec/generate-application/runtime/create-application.d.ts +57 -0
  145. package/dist/application-spec/generate-application/runtime/create-application.js +1 -0
  146. package/dist/application-spec/generate-application/runtime/factory-data/factory-data-runtime.d.ts +1 -2
  147. package/dist/application-spec/generate-application/runtime/factory-data/recipe-defaults.d.ts +1 -1
  148. package/dist/application-spec/generate-application/runtime/factory-data/recipe-defaults.js +1 -1
  149. package/dist/application-spec/generate-application/runtime/factory-data/static-violations.d.ts +1 -2
  150. package/dist/application-spec/generate-application/runtime/factory-data/static-violations.js +1 -1
  151. package/dist/application-spec/generate-application/runtime/generate-runtime-instance.d.ts +1 -1
  152. package/dist/application-spec/generate-application/runtime/generate-runtime-instance.js +1 -1
  153. package/dist/application-spec/generate-application/runtime/index.d.ts +8 -0
  154. package/dist/application-spec/generate-application/runtime/index.js +1 -0
  155. package/dist/application-spec/generate-application/runtime/migrations/migration-runtime.d.ts +2 -2
  156. package/dist/application-spec/generate-application/runtime/sections/actions-runtime.d.ts +1 -2
  157. package/dist/application-spec/generate-application/runtime/sections/assistant-runtime.d.ts +2 -2
  158. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.d.ts +3 -2
  159. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.js +1 -1
  160. package/dist/application-spec/generate-application/runtime/sections/build-user-bound-optic.d.ts +3 -2
  161. package/dist/application-spec/generate-application/runtime/sections/build-user-bound-optic.js +1 -1
  162. package/dist/application-spec/generate-application/runtime/sections/component-optic.d.ts +4 -2
  163. package/dist/application-spec/generate-application/runtime/sections/component-optic.js +1 -1
  164. package/dist/application-spec/generate-application/runtime/sections/data-runtime.d.ts +4 -4
  165. package/dist/application-spec/generate-application/runtime/sections/expression-runtime.d.ts +14 -6
  166. package/dist/application-spec/generate-application/runtime/sections/expression-runtime.js +1 -1
  167. package/dist/application-spec/generate-application/runtime/sections/generate-memo-eval-plan-runtime.d.ts +10 -7
  168. package/dist/application-spec/generate-application/runtime/sections/generate-memo-eval-plan-runtime.js +1 -1
  169. package/dist/application-spec/generate-application/runtime/sections/preset-runtime.d.ts +2 -3
  170. package/dist/application-spec/generate-application/runtime/sections/reflection-constants-runtime.d.ts +4 -2
  171. package/dist/application-spec/generate-application/runtime/sections/reflection-constants-runtime.js +1 -1
  172. package/dist/application-spec/generate-application/runtime/sections/theme-runtime.d.ts +2 -2
  173. package/dist/application-spec/generate-application/runtime/sections/transformers-runtime.d.ts +3 -3
  174. package/dist/application-spec/generate-application/runtime/spec-code/index.d.ts +2 -0
  175. package/dist/application-spec/generate-application/runtime/spec-code/index.js +1 -0
  176. package/dist/application-spec/generate-application/runtime/spec-code/resolve-spec-code.d.ts +18 -0
  177. package/dist/application-spec/generate-application/runtime/spec-code/resolve-spec-code.js +1 -0
  178. package/dist/application-spec/generate-application/runtime/spec-code/spec-code-module.d.ts +17 -0
  179. package/dist/application-spec/generate-application/runtime/spec-runtime.d.ts +21 -0
  180. package/dist/application-spec/generate-application/runtime/spec-runtime.js +1 -0
  181. package/dist/application-spec/generate-application/runtime-spec/decode-runtime-spec.d.ts +9 -0
  182. package/dist/application-spec/generate-application/runtime-spec/decode-runtime-spec.js +1 -0
  183. package/dist/application-spec/generate-application/runtime-spec/encode-runtime-spec.d.ts +8 -0
  184. package/dist/application-spec/generate-application/runtime-spec/encode-runtime-spec.js +1 -0
  185. package/dist/application-spec/generate-application/runtime-spec/encoded-runtime-spec.d.ts +28 -0
  186. package/dist/application-spec/generate-application/runtime-spec/encoded-runtime-spec.js +1 -0
  187. package/dist/application-spec/generate-application/runtime-spec/index.d.ts +5 -0
  188. package/dist/application-spec/generate-application/runtime-spec/index.js +1 -0
  189. package/dist/application-spec/generate-application/runtime-spec/runtime-spec.d.ts +168 -0
  190. package/dist/application-spec/generate-application/runtime-spec/runtime-spec.js +1 -0
  191. package/dist/application-spec/generate-application/runtime-spec/spec-code-id.d.ts +40 -0
  192. package/dist/application-spec/generate-application/runtime-spec/spec-code-id.js +1 -0
  193. package/dist/application-spec/parse-application-files/categorize/categorize-files.d.ts +18 -0
  194. package/dist/application-spec/parse-application-files/categorize/categorize-files.js +1 -1
  195. package/dist/application-spec/parse-application-files/categorize/earlier-generated-editor-configs.d.ts +16 -0
  196. package/dist/application-spec/parse-application-files/categorize/earlier-generated-editor-configs.js +9 -0
  197. package/dist/application-spec/parse-application-files/merge/merged-assistant.d.ts +13 -4
  198. package/dist/application-spec/parse-application-files/merge/merged-assistant.js +1 -1
  199. package/dist/application-spec/parse-application-files/merge/merged-infra.d.ts +4 -11
  200. package/dist/application-spec/parse-application-files/merge/merged-transformers.d.ts +2 -4
  201. package/dist/application-spec/parse-application-files/parse-application-files.js +1 -1
  202. package/dist/application-spec/parse-application-files/raw-spec/parse-yaml-spec-file.js +1 -1
  203. package/dist/application-spec/parse-application-files/raw-spec/raw-acl.d.ts +2 -2
  204. package/dist/application-spec/parse-application-files/raw-spec/raw-acl.js +1 -1
  205. package/dist/application-spec/parse-application-files/raw-spec/raw-admin-pages.d.ts +3 -24
  206. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.d.ts +58 -23
  207. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.js +1 -1
  208. package/dist/application-spec/parse-application-files/raw-spec/raw-expressions.d.ts +1 -1
  209. package/dist/application-spec/parse-application-files/raw-spec/raw-expressions.js +1 -1
  210. package/dist/application-spec/parse-application-files/raw-spec/raw-resources.d.ts +19 -64
  211. package/dist/application-spec/parse-application-files/spec/application/admin-spec/admin-pages.d.ts +3 -20
  212. package/dist/application-spec/parse-application-files/spec/application/admin-spec/admin-spec.js +1 -1
  213. package/dist/application-spec/parse-application-files/spec/application/admin-spec/states.d.ts +3 -5
  214. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/configurator-spec.js +1 -1
  215. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/states.d.ts +3 -8
  216. package/dist/application-spec/parse-application-files/spec/common/index.d.ts +1 -0
  217. package/dist/application-spec/parse-application-files/spec/common/index.js +1 -1
  218. package/dist/application-spec/parse-application-files/spec/common/value-type/format-value-type.d.ts +3 -0
  219. package/dist/application-spec/parse-application-files/spec/common/value-type/format-value-type.js +1 -0
  220. package/dist/application-spec/parse-application-files/spec/common/value-type/index.d.ts +5 -0
  221. package/dist/application-spec/parse-application-files/spec/common/value-type/index.js +1 -0
  222. package/dist/application-spec/parse-application-files/spec/common/value-type/intersect-value-types.d.ts +6 -0
  223. package/dist/application-spec/parse-application-files/spec/common/value-type/intersect-value-types.js +1 -0
  224. package/dist/application-spec/parse-application-files/spec/common/value-type/is-assignable-value-type.d.ts +8 -0
  225. package/dist/application-spec/parse-application-files/spec/common/value-type/is-assignable-value-type.js +1 -0
  226. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type-at.d.ts +10 -0
  227. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type-at.js +1 -0
  228. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type.d.ts +98 -0
  229. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type.js +1 -0
  230. package/dist/application-spec/parse-application-files/spec/components/bindings/component-path.d.ts +13 -0
  231. package/dist/application-spec/parse-application-files/spec/components/bindings/component-path.js +1 -0
  232. package/dist/application-spec/parse-application-files/spec/components/bindings/index.d.ts +2 -0
  233. package/dist/application-spec/parse-application-files/spec/components/bindings/index.js +1 -1
  234. package/dist/application-spec/parse-application-files/spec/components/bindings/read-binding-type.d.ts +24 -0
  235. package/dist/application-spec/parse-application-files/spec/components/bindings/read-binding-type.js +1 -0
  236. package/dist/application-spec/parse-application-files/spec/components/bindings/read-binding.d.ts +3 -13
  237. package/dist/application-spec/parse-application-files/spec/components/bindings/write-binding.d.ts +4 -32
  238. package/dist/application-spec/parse-application-files/spec/components/component-filter.d.ts +4 -10
  239. package/dist/application-spec/parse-application-files/spec/components/component-state-type.d.ts +8 -0
  240. package/dist/application-spec/parse-application-files/spec/components/component-state-type.js +1 -0
  241. package/dist/application-spec/parse-application-files/spec/components/components.d.ts +3 -4
  242. package/dist/application-spec/parse-application-files/spec/components/filter-criterion-types.d.ts +13 -0
  243. package/dist/application-spec/parse-application-files/spec/components/filter-criterion-types.js +1 -0
  244. package/dist/application-spec/parse-application-files/spec/components/index.d.ts +1 -2
  245. package/dist/application-spec/parse-application-files/spec/components/index.js +1 -1
  246. package/dist/application-spec/parse-application-files/spec/components/sdk-component-entry.d.ts +1 -1
  247. package/dist/application-spec/parse-application-files/spec/components/static-entity-id.d.ts +14 -0
  248. package/dist/application-spec/parse-application-files/spec/components/static-entity-id.js +1 -0
  249. package/dist/application-spec/parse-application-files/spec/components/user-component-entry.d.ts +8 -3
  250. package/dist/application-spec/parse-application-files/spec/components/user-component-entry.js +1 -1
  251. package/dist/application-spec/parse-application-files/spec/components/user-components.d.ts +9 -7
  252. package/dist/application-spec/parse-application-files/spec/components/user-components.js +1 -1
  253. package/dist/application-spec/parse-application-files/spec/expressions/expression-read-types.d.ts +24 -0
  254. package/dist/application-spec/parse-application-files/spec/expressions/expression-read-types.js +1 -0
  255. package/dist/application-spec/parse-application-files/spec/expressions/expression-read.d.ts +13 -0
  256. package/dist/application-spec/parse-application-files/spec/expressions/expression-value-type.d.ts +9 -0
  257. package/dist/application-spec/parse-application-files/spec/expressions/expression-value-type.js +1 -0
  258. package/dist/application-spec/parse-application-files/spec/expressions/expressions.d.ts +12 -30
  259. package/dist/application-spec/parse-application-files/spec/expressions/expressions.js +1 -1
  260. package/dist/application-spec/parse-application-files/spec/expressions/index.d.ts +0 -1
  261. package/dist/application-spec/parse-application-files/spec/expressions/memo-eval-plan.d.ts +4 -71
  262. package/dist/application-spec/parse-application-files/spec/expressions/memo-eval-plan.js +1 -1
  263. package/dist/application-spec/parse-application-files/spec/expressions/user-expressions.d.ts +5 -3
  264. package/dist/application-spec/parse-application-files/spec/expressions/user-expressions.js +1 -1
  265. package/dist/application-spec/parse-application-files/spec/invariants/invariant.d.ts +5 -21
  266. package/dist/application-spec/parse-application-files/spec/invariants/invariants.d.ts +6 -16
  267. package/dist/application-spec/parse-application-files/spec/invariants/invariants.js +1 -1
  268. package/dist/application-spec/parse-application-files/spec/model/aliases.d.ts +3 -9
  269. package/dist/application-spec/parse-application-files/spec/model/common-types.d.ts +6 -14
  270. package/dist/application-spec/parse-application-files/spec/model/defaults.d.ts +6 -31
  271. package/dist/application-spec/parse-application-files/spec/model/entity-types.d.ts +3 -8
  272. package/dist/application-spec/parse-application-files/spec/model/index.d.ts +1 -0
  273. package/dist/application-spec/parse-application-files/spec/model/index.js +1 -1
  274. package/dist/application-spec/parse-application-files/spec/model/model-type-resolution.d.ts +10 -0
  275. package/dist/application-spec/parse-application-files/spec/model/model-type-resolution.js +1 -0
  276. package/dist/application-spec/parse-application-files/spec/model/model-version-key.d.ts +3 -3
  277. package/dist/application-spec/parse-application-files/spec/model/names/action-name.d.ts +3 -7
  278. package/dist/application-spec/parse-application-files/spec/model/names/alias-name.d.ts +3 -7
  279. package/dist/application-spec/parse-application-files/spec/model/names/entity-or-alias-name.d.ts +3 -8
  280. package/dist/application-spec/parse-application-files/spec/model/names/entity-type-name.d.ts +3 -8
  281. package/dist/application-spec/parse-application-files/spec/model/names/expression-name.d.ts +3 -6
  282. package/dist/application-spec/parse-application-files/spec/model/names/instance-name.d.ts +3 -7
  283. package/dist/application-spec/parse-application-files/spec/model/names/invariant-name.d.ts +3 -3
  284. package/dist/application-spec/parse-application-files/spec/model/names/shape-property-name.d.ts +3 -11
  285. package/dist/application-spec/parse-application-files/spec/model/names/violation-type-name.d.ts +3 -3
  286. package/dist/application-spec/parse-application-files/spec/model/presets.d.ts +6 -29
  287. package/dist/application-spec/parse-application-files/spec/sections/actions.d.ts +6 -23
  288. package/dist/application-spec/parse-application-files/spec/sections/app-metadata.d.ts +3 -18
  289. package/dist/application-spec/parse-application-files/spec/sections/application-version.d.ts +3 -7
  290. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-form-elements.d.ts +9 -0
  291. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-form-elements.js +1 -0
  292. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.d.ts +4 -1
  293. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.js +1 -1
  294. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant.js +1 -1
  295. package/dist/application-spec/parse-application-files/spec/sections/data-spec/chunks.d.ts +6 -23
  296. package/dist/application-spec/parse-application-files/spec/sections/data-spec/custom-data-spec.d.ts +1 -16
  297. package/dist/application-spec/parse-application-files/spec/sections/data-spec/data-entry-key.d.ts +3 -9
  298. package/dist/application-spec/parse-application-files/spec/sections/data-spec/data-spec.d.ts +1 -10
  299. package/dist/application-spec/parse-application-files/spec/sections/data-spec/swatch-data-spec.d.ts +1 -14
  300. package/dist/application-spec/parse-application-files/spec/sections/state-value.d.ts +3 -7
  301. package/dist/application-spec/parse-application-files/spec/sections/theme.d.ts +3 -10
  302. package/dist/application-spec/parse-application-files/spec/sections/transformers.d.ts +4 -11
  303. package/dist/application-spec/parse-application-files/spec/sections/ui.d.ts +3 -12
  304. package/dist/client/authorized-client.d.ts +3 -1
  305. package/dist/client/authorized-client.js +1 -1
  306. package/dist/client/contract.d.ts +17 -0
  307. package/dist/client/index.d.ts +1 -1
  308. package/dist/client/local-authorized-client.d.ts +3 -1
  309. package/dist/client/local-authorized-client.js +1 -1
  310. package/dist/client/memory-authorized-client.d.ts +4 -1
  311. package/dist/client/memory-authorized-client.js +1 -1
  312. package/dist/client/phoenix-api.d.ts +228 -0
  313. package/dist/configurator/ConfiguratorApp.js +1 -1
  314. package/dist/configurator/app-loader-content/DefaultAppLoaderContent.d.ts +2 -0
  315. package/dist/configurator/app-loader-content/DefaultAppLoaderContent.js +5 -0
  316. package/dist/configurator/app-loader-content/index.d.ts +1 -0
  317. package/dist/configurator/app-loader-content/index.js +1 -0
  318. package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
  319. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +24 -4
  320. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -1
  321. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.d.ts +52 -9
  322. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.js +1 -1
  323. package/dist/configurator/application-runtime/extensions/systems/camera-control-system/camera-control-system.d.ts +1 -1
  324. package/dist/configurator/application-runtime/extensions/systems/canvas-system.d.ts +8 -0
  325. package/dist/configurator/application-runtime/extensions/systems/canvas-system.js +1 -1
  326. package/dist/configurator/application-runtime/extensions/systems/export-system/export-busy-error.d.ts +8 -0
  327. package/dist/configurator/application-runtime/extensions/systems/export-system/export-busy-error.js +1 -0
  328. package/dist/configurator/application-runtime/extensions/systems/export-system/export-system.d.ts +23 -1
  329. package/dist/configurator/application-runtime/extensions/systems/export-system/export-system.js +1 -1
  330. package/dist/configurator/application-runtime/extensions/systems/graphql-system/close-unclosed-braces.d.ts +12 -0
  331. package/dist/configurator/application-runtime/extensions/systems/graphql-system/close-unclosed-braces.js +1 -0
  332. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.d.ts +82 -55
  333. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.js +1 -1
  334. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.d.ts +67 -5
  335. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.js +1 -1
  336. package/dist/configurator/application-runtime/extensions/systems/graphql-system/violations.d.ts +40 -0
  337. package/dist/configurator/application-runtime/extensions/systems/graphql-system/violations.js +1 -0
  338. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/image-rendering-system.d.ts +14 -5
  339. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/image-rendering-system.js +1 -1
  340. package/dist/configurator/application-runtime/extensions/systems/index.d.ts +1 -1
  341. package/dist/configurator/common/configurator-interface.d.ts +121 -6
  342. package/dist/configurator/common/configurator-interface.js +1 -1
  343. package/dist/configurator/common/index.d.ts +2 -2
  344. package/dist/configurator/common/index.js +1 -1
  345. package/dist/configurator/configuration-not-found-page/BuiltInConfigurationNotFoundPage.d.ts +5 -0
  346. package/dist/configurator/configuration-not-found-page/BuiltInConfigurationNotFoundPage.js +1 -0
  347. package/dist/configurator/configuration-not-found-page/ConfigurationNotFoundPageElement.d.ts +6 -0
  348. package/dist/configurator/configuration-not-found-page/ConfigurationNotFoundPageElement.js +1 -0
  349. package/dist/configurator/configuration-not-found-page/index.d.ts +2 -0
  350. package/dist/configurator/configuration-not-found-page/index.js +1 -0
  351. package/dist/configurator/configurator-context/ConfiguratorResponsiveProvider.d.ts +12 -0
  352. package/dist/configurator/configurator-context/ConfiguratorResponsiveProvider.js +1 -0
  353. package/dist/configurator/configurator-context/PreviewContextProvider.js +1 -1
  354. package/dist/configurator/configurator-context/ViewportStateSync.d.ts +2 -2
  355. package/dist/configurator/configurator-context/ViewportStateSync.js +1 -1
  356. package/dist/configurator/configurator-context/configurator-hooks/index.d.ts +0 -1
  357. package/dist/configurator/configurator-context/configurator-hooks/index.js +1 -1
  358. package/dist/configurator/configurator-context/configurator-hooks/layout-hooks.d.ts +10 -0
  359. package/dist/configurator/configurator-context/configurator-hooks/layout-hooks.js +1 -1
  360. package/dist/configurator/configurator-context/index.d.ts +0 -5
  361. package/dist/configurator/configurator-context/index.js +1 -1
  362. package/dist/configurator/configurator-error-page/BuiltInConfiguratorErrorPage.d.ts +6 -0
  363. package/dist/configurator/configurator-error-page/BuiltInConfiguratorErrorPage.js +1 -0
  364. package/dist/configurator/configurator-error-page/ConfiguratorErrorPageElement.d.ts +7 -0
  365. package/dist/configurator/configurator-error-page/ConfiguratorErrorPageElement.js +1 -0
  366. package/dist/configurator/configurator-error-page/index.d.ts +2 -0
  367. package/dist/configurator/configurator-error-page/index.js +1 -0
  368. package/dist/configurator/index.d.ts +10 -0
  369. package/dist/configurator/index.js +1 -1
  370. package/dist/configurator/pages/ConfiguratorErrorPage.d.ts +0 -1
  371. package/dist/configurator/pages/ConfiguratorErrorPage.js +1 -1
  372. package/dist/configurator/pages/ConfiguratorNotFoundPage.js +1 -1
  373. package/dist/configurator/pages/DefaultConfiguratorLayout.d.ts +3 -2
  374. package/dist/configurator/pages/DefaultNotAuthenticatedPage.d.ts +8 -0
  375. package/dist/configurator/pages/DefaultNotAuthenticatedPage.js +1 -0
  376. package/dist/configurator/pages/DefaultPresetUi.d.ts +7 -0
  377. package/dist/configurator/pages/DefaultPresetUi.js +1 -0
  378. package/dist/configurator/pages/LoadedConfiguratorDetailPage.js +1 -1
  379. package/dist/configurator/pages/NewConfiguratorPage.js +1 -1
  380. package/dist/configurator/pages/PresetCreationErrorPage.d.ts +1 -1
  381. package/dist/configurator/pages/PresetCreationErrorPage.js +1 -1
  382. package/dist/configurator/pages/RootPage.js +1 -1
  383. package/dist/configurator/pages/default-configurator-elements.d.ts +7 -1
  384. package/dist/configurator/pages/default-configurator-elements.js +1 -1
  385. package/dist/configurator/pages/default-elements/built-in-entity-element.d.ts +10 -0
  386. package/dist/configurator/pages/default-elements/built-in-entity-element.js +1 -0
  387. package/dist/configurator/pages/default-elements/built-in-layout-element.d.ts +10 -0
  388. package/dist/configurator/pages/default-elements/built-in-layout-element.js +1 -0
  389. package/dist/configurator/pages/default-elements/domain-control-elements.d.ts +6 -0
  390. package/dist/configurator/pages/default-elements/domain-control-elements.js +1 -0
  391. package/dist/configurator/pages/default-elements/index.d.ts +5 -0
  392. package/dist/configurator/pages/default-elements/index.js +1 -0
  393. package/dist/configurator/pages/default-elements/recipe-panel-elements.d.ts +3 -0
  394. package/dist/configurator/pages/default-elements/recipe-panel-elements.js +1 -0
  395. package/dist/configurator/pages/default-elements/scene-controls/BuiltInAddEntityFab.d.ts +3 -0
  396. package/dist/configurator/pages/default-elements/scene-controls/BuiltInAddEntityFab.js +1 -0
  397. package/dist/configurator/pages/default-elements/scene-controls/BuiltInDeleteEntityFab.d.ts +3 -0
  398. package/dist/configurator/pages/default-elements/scene-controls/BuiltInDeleteEntityFab.js +1 -0
  399. package/dist/configurator/pages/default-elements/scene-controls/BuiltInNavigationHotspot.d.ts +3 -0
  400. package/dist/configurator/pages/default-elements/scene-controls/BuiltInNavigationHotspot.js +1 -0
  401. package/dist/configurator/pages/default-elements/scene-controls/BuiltInSelectionHotspot.d.ts +3 -0
  402. package/dist/configurator/pages/default-elements/scene-controls/BuiltInSelectionHotspot.js +1 -0
  403. package/dist/configurator/pages/default-elements/scene-controls/BuiltInToolMenuFab.d.ts +3 -0
  404. package/dist/configurator/pages/default-elements/scene-controls/BuiltInToolMenuFab.js +1 -0
  405. package/dist/configurator/pages/default-elements/scene-controls/index.d.ts +6 -0
  406. package/dist/configurator/pages/default-elements/scene-controls/index.js +1 -0
  407. package/dist/configurator/pages/default-elements/scene-controls/scene-control-elements.d.ts +6 -0
  408. package/dist/configurator/pages/default-elements/scene-controls/scene-control-elements.js +1 -0
  409. package/dist/configurator/pages/default-elements/sidebar-footer-elements.d.ts +7 -0
  410. package/dist/configurator/pages/default-elements/sidebar-footer-elements.js +1 -0
  411. package/dist/configurator/pages/default-elements/toolbar-elements.d.ts +7 -0
  412. package/dist/configurator/pages/default-elements/toolbar-elements.js +1 -0
  413. package/dist/configurator/pages/error-boundaries/DevContextFallback.js +1 -1
  414. package/dist/configurator/pages/error-boundaries/DevLoadingFallback.js +1 -1
  415. package/dist/configurator/pages/error-boundaries/GeneralErrorBoundary.js +1 -1
  416. package/dist/configurator/pages/error-boundaries/LoadingErrorBoundary.js +1 -1
  417. package/dist/configurator/preset-screen-elements/PresetDeviceNotSupportedElement.d.ts +4 -0
  418. package/dist/configurator/preset-screen-elements/PresetDeviceNotSupportedElement.js +1 -0
  419. package/dist/configurator/preset-screen-elements/PresetPageActionElement.d.ts +4 -0
  420. package/dist/configurator/preset-screen-elements/PresetPageActionElement.js +1 -0
  421. package/dist/configurator/preset-screen-elements/index.d.ts +2 -0
  422. package/dist/configurator/preset-screen-elements/index.js +1 -0
  423. package/dist/configurator/scene/index.d.ts +1 -0
  424. package/dist/configurator/scene/index.js +1 -1
  425. package/dist/configurator/scene/scene-controls/DeleteEntityFab.js +1 -1
  426. package/dist/configurator/scene/scene-controls/SelectionHotspot.js +1 -1
  427. package/dist/configurator/scene/scene-controls/ToolFab.d.ts +4 -0
  428. package/dist/configurator/scene/scene-controls/ToolFab.js +1 -1
  429. package/dist/configurator/scene/scene-controls/use-scene-control-tooltip.d.ts +2 -1
  430. package/dist/configurator/scene/scene-entity/scene-controls/SceneEntityHtmlHotspots.js +1 -1
  431. package/dist/configurator/toolbar-actions/index.d.ts +3 -0
  432. package/dist/configurator/toolbar-actions/index.js +1 -0
  433. package/dist/configurator/toolbar-actions/use-assistant-panel.d.ts +18 -0
  434. package/dist/configurator/toolbar-actions/use-assistant-panel.js +1 -0
  435. package/dist/configurator/toolbar-actions/use-measurements.d.ts +35 -0
  436. package/dist/configurator/toolbar-actions/use-measurements.js +1 -0
  437. package/dist/configurator/toolbar-actions/use-toolbar-actions.d.ts +100 -0
  438. package/dist/configurator/toolbar-actions/use-toolbar-actions.js +1 -0
  439. package/dist/configurator/toolbar-actions/use-toolbar-help.d.ts +7 -0
  440. package/dist/configurator/toolbar-actions/use-toolbar-help.js +1 -0
  441. package/dist/configurator/ui/assistant/AssistantChips.d.ts +3 -2
  442. package/dist/configurator/ui/assistant/AssistantChips.js +1 -1
  443. package/dist/configurator/ui/assistant/AssistantMarkdown.d.ts +7 -2
  444. package/dist/configurator/ui/assistant/AssistantMarkdown.js +1 -1
  445. package/dist/configurator/ui/assistant/AssistantPanel.js +1 -1
  446. package/dist/configurator/ui/assistant/AssistantThread.js +1 -1
  447. package/dist/configurator/ui/assistant/alert/AssistantAlert.d.ts +8 -0
  448. package/dist/configurator/ui/assistant/alert/AssistantAlert.js +1 -0
  449. package/dist/configurator/ui/assistant/alert/index.d.ts +2 -0
  450. package/dist/configurator/ui/assistant/alert/index.js +1 -0
  451. package/dist/configurator/ui/assistant/alert/remark-alerts.d.ts +10 -0
  452. package/dist/configurator/ui/assistant/alert/remark-alerts.js +1 -0
  453. package/dist/configurator/ui/assistant/entity-link/AssistantEntityLink.d.ts +1 -1
  454. package/dist/configurator/ui/assistant/entity-link/AssistantEntityLink.js +1 -1
  455. package/dist/configurator/ui/assistant/entity-link/entity-link-state.d.ts +1 -1
  456. package/dist/configurator/ui/assistant/entity-link/index.d.ts +0 -1
  457. package/dist/configurator/ui/assistant/entity-link/index.js +1 -1
  458. package/dist/configurator/ui/assistant/form/AssistantForm.d.ts +19 -0
  459. package/dist/configurator/ui/assistant/form/AssistantForm.js +1 -0
  460. package/dist/configurator/ui/assistant/form/compose-answer.d.ts +11 -0
  461. package/dist/configurator/ui/assistant/form/compose-answer.js +1 -0
  462. package/dist/configurator/ui/assistant/form/describe-build-errors.d.ts +6 -0
  463. package/dist/configurator/ui/assistant/form/describe-build-errors.js +1 -0
  464. package/dist/configurator/ui/assistant/form/form-model.d.ts +37 -0
  465. package/dist/configurator/ui/assistant/form/form-model.js +1 -0
  466. package/dist/configurator/ui/assistant/form/form-state.d.ts +4 -0
  467. package/dist/configurator/ui/assistant/form/form-state.js +1 -0
  468. package/dist/configurator/ui/assistant/form/index.d.ts +4 -0
  469. package/dist/configurator/ui/assistant/form/index.js +1 -0
  470. package/dist/configurator/ui/assistant/form/parse-form-block.d.ts +10 -0
  471. package/dist/configurator/ui/assistant/form/parse-form-block.js +1 -0
  472. package/dist/configurator/ui/assistant/form/read-form-attributes.d.ts +13 -0
  473. package/dist/configurator/ui/assistant/form/read-form-attributes.js +1 -0
  474. package/dist/configurator/ui/assistant/form/registry/built-in-form-elements.d.ts +3 -0
  475. package/dist/configurator/ui/assistant/form/registry/built-in-form-elements.js +1 -0
  476. package/dist/configurator/ui/assistant/form/registry/create-assistant-form-element.d.ts +31 -0
  477. package/dist/configurator/ui/assistant/form/registry/create-assistant-form-element.js +1 -0
  478. package/dist/configurator/ui/assistant/form/registry/form-element-definition.d.ts +16 -0
  479. package/dist/configurator/ui/assistant/form/registry/form-element-definition.js +1 -0
  480. package/dist/configurator/ui/assistant/form/registry/form-registry.d.ts +31 -0
  481. package/dist/configurator/ui/assistant/form/registry/form-registry.js +1 -0
  482. package/dist/configurator/ui/assistant/form/registry/index.d.ts +6 -0
  483. package/dist/configurator/ui/assistant/form/registry/index.js +1 -0
  484. package/dist/configurator/ui/assistant/form/registry/use-form-registry.d.ts +8 -0
  485. package/dist/configurator/ui/assistant/form/registry/use-form-registry.js +1 -0
  486. package/dist/configurator/ui/assistant/form-elements/FormCard.d.ts +9 -0
  487. package/dist/configurator/ui/assistant/form-elements/FormCard.js +1 -0
  488. package/dist/configurator/ui/assistant/form-elements/FormConfirm.d.ts +9 -0
  489. package/dist/configurator/ui/assistant/form-elements/FormConfirm.js +1 -0
  490. package/dist/configurator/ui/assistant/form-elements/FormGroup.d.ts +6 -0
  491. package/dist/configurator/ui/assistant/form-elements/FormGroup.js +1 -0
  492. package/dist/configurator/ui/assistant/form-elements/FormNumber.d.ts +9 -0
  493. package/dist/configurator/ui/assistant/form-elements/FormNumber.js +1 -0
  494. package/dist/configurator/ui/assistant/form-elements/FormOptions.d.ts +6 -0
  495. package/dist/configurator/ui/assistant/form-elements/FormOptions.js +1 -0
  496. package/dist/configurator/ui/assistant/form-elements/FormReply.d.ts +6 -0
  497. package/dist/configurator/ui/assistant/form-elements/FormReply.js +1 -0
  498. package/dist/configurator/ui/assistant/form-elements/FormSwatch.d.ts +10 -0
  499. package/dist/configurator/ui/assistant/form-elements/FormSwatch.js +1 -0
  500. package/dist/configurator/ui/assistant/form-elements/FormText.d.ts +6 -0
  501. package/dist/configurator/ui/assistant/form-elements/FormText.js +1 -0
  502. package/dist/configurator/ui/assistant/form-elements/clamp-form-number.d.ts +10 -0
  503. package/dist/configurator/ui/assistant/form-elements/clamp-form-number.js +1 -0
  504. package/dist/configurator/ui/assistant/form-elements/form-element-props.d.ts +38 -0
  505. package/dist/configurator/ui/assistant/form-elements/index.d.ts +9 -0
  506. package/dist/configurator/ui/assistant/form-elements/index.js +1 -0
  507. package/dist/configurator/ui/assistant/index.d.ts +3 -0
  508. package/dist/configurator/ui/assistant/index.js +1 -1
  509. package/dist/configurator/ui/assistant/reference-link/AssistantReferenceLink.d.ts +16 -0
  510. package/dist/configurator/ui/assistant/reference-link/AssistantReferenceLink.js +1 -0
  511. package/dist/configurator/ui/assistant/reference-link/assistant-link-target.d.ts +34 -0
  512. package/dist/configurator/ui/assistant/reference-link/assistant-link-target.js +1 -0
  513. package/dist/configurator/ui/assistant/reference-link/assistant-reference-details.d.ts +25 -0
  514. package/dist/configurator/ui/assistant/reference-link/assistant-reference-details.js +1 -0
  515. package/dist/configurator/ui/assistant/reference-link/index.d.ts +3 -0
  516. package/dist/configurator/ui/assistant/reference-link/index.js +1 -0
  517. package/dist/configurator/ui/assistant/reference-link/reference-styles.d.ts +12 -0
  518. package/dist/configurator/ui/assistant/reference-link/reference-styles.js +1 -0
  519. package/dist/configurator/ui/assistant/reference-link/use-assistant-reference-details.d.ts +8 -0
  520. package/dist/configurator/ui/assistant/reference-link/use-assistant-reference-details.js +1 -0
  521. package/dist/configurator/ui/assistant/resource-image/AssistantImage.d.ts +9 -0
  522. package/dist/configurator/ui/assistant/resource-image/AssistantImage.js +1 -0
  523. package/dist/configurator/ui/assistant/resource-image/index.d.ts +3 -0
  524. package/dist/configurator/ui/assistant/resource-image/index.js +1 -0
  525. package/dist/configurator/ui/assistant/resource-image/resource-path.d.ts +2 -0
  526. package/dist/configurator/ui/assistant/resource-image/resource-path.js +1 -0
  527. package/dist/configurator/ui/assistant/resource-image/use-resource-image-url.d.ts +5 -0
  528. package/dist/configurator/ui/assistant/resource-image/use-resource-image-url.js +1 -0
  529. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.d.ts +9 -0
  530. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.js +1 -0
  531. package/dist/configurator/ui/assistant/screenshots/index.d.ts +2 -0
  532. package/dist/configurator/ui/assistant/screenshots/index.js +1 -0
  533. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.d.ts +22 -0
  534. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.js +1 -0
  535. package/dist/configurator/ui/assistant/screenshots/use-screenshot-src.d.ts +8 -0
  536. package/dist/configurator/ui/assistant/screenshots/use-screenshot-src.js +1 -0
  537. package/dist/configurator/ui/assistant/streamed-markdown.d.ts +4 -2
  538. package/dist/configurator/ui/assistant/streamed-markdown.js +2 -2
  539. package/dist/configurator/ui/assistant/thread-items.d.ts +8 -1
  540. package/dist/configurator/ui/assistant/thread-items.js +1 -1
  541. package/dist/configurator/ui/assistant/tool-chip.d.ts +19 -9
  542. package/dist/configurator/ui/assistant/tool-chip.js +1 -1
  543. package/dist/configurator/ui/assistant/use-follow-stream.js +1 -1
  544. package/dist/configurator/ui/configurator-layout/slots/canvas/GPUAccelerationDisabled.js +1 -1
  545. package/dist/configurator/ui/configurator-layout/slots/canvas/LayoutCanvas.js +1 -1
  546. package/dist/configurator/ui/configurator-layout/slots/canvas/SharedCanvas.js +1 -1
  547. package/dist/configurator/ui/configurator-layout/slots/canvas/WebGLNotSupported.js +1 -1
  548. package/dist/configurator/ui/configurator-layout/slots/mobile-tabs/use-mobile-tabs.d.ts +1 -1
  549. package/dist/configurator/ui/configurator-layout/slots/mobile-tabs/use-mobile-tabs.js +1 -1
  550. package/dist/configurator/ui/configurator-layout/slots/readonly-banner/CloneToEditDialog.js +1 -1
  551. package/dist/configurator/ui/configurator-layout/slots/services/InvariantViolations.js +1 -1
  552. package/dist/configurator/ui/configurator-layout/slots/services/Services.js +1 -1
  553. package/dist/configurator/ui/configurator-layout/slots/sidebar-tabs/use-sidebar-tabs.d.ts +1 -1
  554. package/dist/configurator/ui/configurator-layout/slots/sidebar-tabs/use-sidebar-tabs.js +1 -1
  555. package/dist/configurator/ui/configurator-layout/universal/DesktopPreview.js +1 -1
  556. package/dist/configurator/ui/configurator-layout/universal/ExportingOverlay.d.ts +5 -0
  557. package/dist/configurator/ui/configurator-layout/universal/ExportingOverlay.js +1 -0
  558. package/dist/configurator/ui/configurator-layout/universal/Layout.js +1 -1
  559. package/dist/configurator/ui/configurator-layout/universal/MobilePreview.js +1 -1
  560. package/dist/configurator/ui/configurator-layout/universal/use-layout-scene-safe-area.d.ts +1 -1
  561. package/dist/configurator/ui/configurator-layout/universal/use-layout-scene-safe-area.js +1 -1
  562. package/dist/configurator/ui/configurator-layout/universal/use-scene-safe-area.d.ts +1 -1
  563. package/dist/configurator/ui/index.d.ts +1 -0
  564. package/dist/configurator/ui/index.js +1 -1
  565. package/dist/configurator/ui/legacy/chat/MobileChat.js +1 -1
  566. package/dist/configurator/ui/legacy/layout/common/CommonFinalizeButton.js +1 -1
  567. package/dist/configurator/ui/legacy/layout/common/CommonSummaryButton.js +1 -1
  568. package/dist/configurator/ui/legacy/layout/common/CommonTopNavigation.js +1 -1
  569. package/dist/configurator/ui/legacy/layout/common/ReactiveInterfaceLayout.js +1 -1
  570. package/dist/configurator/ui/legacy/layout/common/ResponsiveFinalizeButton.js +1 -1
  571. package/dist/configurator/ui/legacy/layout/common/SummaryReadLayout.js +1 -1
  572. package/dist/configurator/ui/legacy/layout/simple/SimpleOwnerLayout.js +1 -1
  573. package/dist/configurator/ui/legacy/layout/simple/SimpleSidebar.js +1 -1
  574. package/dist/configurator/ui/legacy/layout/simple/SimpleTopNavigation.js +1 -1
  575. package/dist/configurator/ui/legacy/layout/steps/StepsNavigation.js +1 -1
  576. package/dist/configurator/ui/legacy/layout/steps/StepsOwnerLayout.js +1 -1
  577. package/dist/configurator/ui/legacy/layout/steps/StepsSideBar.js +1 -1
  578. package/dist/configurator/ui/legacy/layout/steps/StepsSidebarFooter.js +1 -1
  579. package/dist/configurator/ui/legacy/layout/tabs/TabsOwnerLayout.js +1 -1
  580. package/dist/configurator/ui/legacy/layout/tabs/TabsSidebar.js +1 -1
  581. package/dist/configurator/ui/legacy/toolbar/common/DimensionUnitSelector.js +1 -1
  582. package/dist/configurator/ui/legacy/toolbar/common/MeasurementsIndicatorsSwitch.js +1 -1
  583. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/FullscreenToolbarAction.js +1 -1
  584. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/HelpToolbarAction.js +1 -1
  585. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/MeasurementsToolbarAction.js +1 -1
  586. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/UndoRedoToolbarGroup.js +1 -1
  587. package/dist/configurator/ui/phoenix-layout-elements/AppLoader.d.ts +0 -7
  588. package/dist/configurator/ui/phoenix-layout-elements/AppLoader.js +2 -6
  589. package/dist/configurator/ui/phoenix-layout-elements/AssistantToolbarButton.js +1 -1
  590. package/dist/configurator/ui/phoenix-layout-elements/EnterFullscreenToolbarButton.js +1 -1
  591. package/dist/configurator/ui/phoenix-layout-elements/ExitFullscreenToolbarButton.js +1 -1
  592. package/dist/configurator/ui/phoenix-layout-elements/HelpToolbarButton.js +1 -1
  593. package/dist/configurator/ui/phoenix-layout-elements/LanguageMenuAction.js +1 -1
  594. package/dist/configurator/ui/phoenix-layout-elements/LanguageToolbarButton.js +1 -1
  595. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomOwnerUi.d.ts +1 -0
  596. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomOwnerUi.js +1 -1
  597. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomReadUi.d.ts +1 -0
  598. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomReadUi.js +1 -1
  599. package/dist/configurator/ui/phoenix-layout-elements/MeasurementsMenuAction.js +1 -1
  600. package/dist/configurator/ui/phoenix-layout-elements/MeasurementsToolbarButton.js +1 -1
  601. package/dist/configurator/ui/phoenix-layout-elements/RedoToolbarButton.js +1 -1
  602. package/dist/configurator/ui/phoenix-layout-elements/ShareToolbarButton.js +1 -1
  603. package/dist/configurator/ui/phoenix-layout-elements/UndoToolbarButton.js +1 -1
  604. package/dist/configurator/ui/phoenix-layout-elements/header/common/back-button/use-go-back-action.js +1 -1
  605. package/dist/configurator/ui/phoenix-layout-elements/header/common/horizontal-tabs/DesktopHorizontalTabs.js +1 -1
  606. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/DesktopNavigationSteps.d.ts +1 -1
  607. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/DesktopNavigationSteps.js +1 -1
  608. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/StepsNavigation.d.ts +2 -8
  609. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/StepsNavigation.js +1 -1
  610. package/dist/configurator/ui/phoenix-layout-elements/index.d.ts +8 -1
  611. package/dist/configurator/ui/phoenix-layout-elements/index.js +1 -1
  612. package/dist/configurator/ui/phoenix-layout-elements/measurements/DimensionUnitSelector.js +1 -1
  613. package/dist/configurator/ui/phoenix-layout-elements/measurements/MeasurementsIndicatorsSwitch.js +1 -1
  614. package/dist/configurator/ui/phoenix-layout-elements/share/ShareModal.js +1 -1
  615. package/dist/configurator/ui/phoenix-layout-elements/share/use-share.d.ts +7 -8
  616. package/dist/configurator/ui/phoenix-layout-elements/share/use-share.js +1 -1
  617. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/basic/BasicFinalizeButton.js +1 -1
  618. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/basic/use-basic-sidebar-footer.js +1 -1
  619. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/CustomFinalizeButton.js +1 -1
  620. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/EnterSummaryButton.js +1 -1
  621. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/FinalizeActions.js +1 -1
  622. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/NextStepButton.js +1 -1
  623. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/PreviousStepButton.js +1 -1
  624. package/dist/configurator/ui/preset-layout/CategoryPresetUi.js +1 -1
  625. package/dist/configurator/ui/preset-layout/PresetUi.d.ts +4 -2
  626. package/dist/configurator/ui/preset-layout/PresetUi.js +1 -1
  627. package/dist/configurator/ui/preset-layout/index.d.ts +6 -1
  628. package/dist/configurator/ui/preset-layout/index.js +1 -1
  629. package/dist/configurator/ui/save-message-snackbars/SaveMessageSnackbars.d.ts +10 -0
  630. package/dist/configurator/ui/save-message-snackbars/SaveMessageSnackbars.js +1 -0
  631. package/dist/configurator/ui/save-message-snackbars/index.d.ts +1 -0
  632. package/dist/configurator/ui/save-message-snackbars/index.js +1 -0
  633. package/dist/docs/3d-scene/cameras/custom.mdx +4 -2
  634. package/dist/docs/complex-use-cases/focus-mode.mdx +2 -0
  635. package/dist/docs/controls/select-child-entity/cardselect.mdx +1 -0
  636. package/dist/docs/drag-and-drop/room-planner.mdx +1 -1
  637. package/dist/docs/fabs/basic.mdx +6 -2
  638. package/dist/docs/index.json +95 -1
  639. package/dist/docs/integrations/webcomponent-api/basics.mdx +2 -0
  640. package/dist/docs/layouts/custom-layout.mdx +637 -165
  641. package/dist/docs/layouts/gallery/ardent-compressor.mdx +3516 -0
  642. package/dist/docs/layouts/gallery/corvid-drone.mdx +3428 -0
  643. package/dist/docs/layouts/gallery/fenwick-window.mdx +2803 -0
  644. package/dist/docs/layouts/gallery/ferrule-bar-station.mdx +6567 -0
  645. package/dist/docs/layouts/gallery/kestrel-kettle.mdx +1858 -0
  646. package/dist/docs/layouts/gallery/nightjar-guitar.mdx +3698 -0
  647. package/dist/docs/layouts/gallery/sunfold-solar.mdx +2683 -0
  648. package/dist/docs/layouts/gallery/tidepool-aquascape.mdx +5203 -0
  649. package/dist/docs/other-features/client-side-rendering/declarative.mdx +1 -1
  650. package/dist/docs/other-features/error-5xx.mdx +1 -1
  651. package/dist/docs/other-features/navigation-hotspot.mdx +2 -0
  652. package/dist/docs/other-features/not-found-404.mdx +1 -1
  653. package/dist/docs/phoenix/clerk-sign-in.mdx +1 -1
  654. package/dist/docs/phoenix/components.mdx +6 -0
  655. package/dist/docs/phoenix/configurator-interface.mdx +223 -59
  656. package/dist/docs/phoenix/domain-model.mdx +6 -1
  657. package/dist/docs/phoenix/finalization.mdx +1 -1
  658. package/dist/docs/phoenix/getting-started.mdx +5 -3
  659. package/dist/docs/phoenix/layout-slots.mdx +44 -23
  660. package/dist/docs/phoenix/localization.mdx +6 -2
  661. package/dist/docs/phoenix/migration-guide.mdx +12 -10
  662. package/dist/docs/phoenix/phoenix-cli.mdx +44 -20
  663. package/dist/docs/phoenix/project-structure.mdx +57 -31
  664. package/dist/docs/phoenix/quickstart.mdx +7 -7
  665. package/dist/docs/phoenix/sdk-builder-workflow.mdx +13 -11
  666. package/dist/docs/phoenix/sessions-and-access.mdx +2 -0
  667. package/dist/docs/phoenix/testing.mdx +8 -0
  668. package/dist/docs/phoenix/webhooks.mdx +5 -1
  669. package/dist/docs/selection-and-highlight/hotspots.mdx +2 -0
  670. package/dist/domain/application/application-config.d.ts +6 -24
  671. package/dist/domain/application/assistant/assistant-manifest.d.ts +29 -4
  672. package/dist/domain/application/assistant/assistant-manifest.js +1 -1
  673. package/dist/domain/application/assistant/assistant-resolved-manifest.d.ts +12 -9
  674. package/dist/domain/application/assistant/assistant-resolved-manifest.js +1 -1
  675. package/dist/domain/application/assistant/build-assistant-lenses.js +1 -1
  676. package/dist/domain/application/assistant/build-assistant-manifest.js +1 -1
  677. package/dist/domain/application/assistant/form/assistant-form-element-name.d.ts +11 -0
  678. package/dist/domain/application/assistant/form/assistant-form-element-name.js +8 -0
  679. package/dist/domain/application/assistant/form/assistant-form-elements.d.ts +174 -0
  680. package/dist/domain/application/assistant/form/assistant-form-elements.js +1 -0
  681. package/dist/domain/application/assistant/form/assistant-resource-path.d.ts +10 -0
  682. package/dist/domain/application/assistant/form/assistant-resource-path.js +1 -0
  683. package/dist/domain/application/assistant/form/index.d.ts +4 -0
  684. package/dist/domain/application/assistant/form/index.js +1 -0
  685. package/dist/domain/application/assistant/generate-assistant-prompt.d.ts +3 -0
  686. package/dist/domain/application/assistant/generate-assistant-prompt.js +1 -1
  687. package/dist/domain/application/assistant/index.d.ts +4 -3
  688. package/dist/domain/application/assistant/index.js +1 -1
  689. package/dist/domain/application/assistant/session-setup/apply-assistant-setup.js +1 -1
  690. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.d.ts +4 -4
  691. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.js +1 -1
  692. package/dist/domain/application/assistant-mutations.js +1 -1
  693. package/dist/domain/application/assistant-recipe-groups.d.ts +3 -1
  694. package/dist/domain/application/configurator-builder.d.ts +7 -1
  695. package/dist/domain/application/configurator-builder.js +1 -1
  696. package/dist/domain/application/index.d.ts +1 -1
  697. package/dist/domain/application/index.js +1 -1
  698. package/dist/domain/application/standard-properties.js +1 -1
  699. package/dist/domain/application/web-component-property.d.ts +3 -1
  700. package/dist/domain/application/web-component-property.js +1 -1
  701. package/dist/domain/available-system-components/available-system-components.d.ts +11 -0
  702. package/dist/domain/available-system-components/available-system-components.js +1 -0
  703. package/dist/domain/available-system-components/index.d.ts +1 -0
  704. package/dist/domain/available-system-components/index.js +1 -0
  705. package/dist/domain/core/schema/extended-schema-validator.js +1 -1
  706. package/dist/domain/{domain-builder.d.ts → domain-builder/domain-builder.d.ts} +11 -5
  707. package/dist/domain/domain-builder/domain-builder.js +1 -0
  708. package/dist/domain/domain-builder/index.d.ts +1 -0
  709. package/dist/domain/domain-builder/index.js +1 -0
  710. package/dist/domain/domain-context/store-system/store-system.d.ts +5 -0
  711. package/dist/domain/domain-context/store-system/store-system.js +1 -1
  712. package/dist/domain/domain-runtime/application.d.ts +39 -0
  713. package/dist/domain/domain-runtime/application.js +1 -0
  714. package/dist/domain/domain-runtime/domain-context/selectors.d.ts +1 -0
  715. package/dist/domain/domain-runtime/domain-context/selectors.js +1 -1
  716. package/dist/domain/domain-runtime/domain-runtime.d.ts +44 -4
  717. package/dist/domain/domain-runtime/domain-runtime.js +1 -1
  718. package/dist/domain/domain-runtime/environment/initialize.d.ts +1 -1
  719. package/dist/domain/domain-runtime/environment/types.d.ts +1 -1
  720. package/dist/domain/domain-runtime/errors/implementation-error-collector.d.ts +2 -0
  721. package/dist/domain/domain-runtime/errors/implementation-error-collector.js +1 -1
  722. package/dist/domain/domain-runtime/index.d.ts +2 -1
  723. package/dist/domain/domain-runtime/index.js +1 -1
  724. package/dist/domain/domain-runtime/spec/index.d.ts +1 -1
  725. package/dist/domain/domain-runtime/spec/index.js +1 -1
  726. package/dist/domain/domain-runtime/spec/initialize.js +1 -1
  727. package/dist/domain/domain-runtime/spec/module-checks/element-registration.d.ts +27 -12
  728. package/dist/domain/domain-runtime/spec/module-checks/element-registration.js +1 -1
  729. package/dist/domain/domain-runtime/spec/module-checks/find-assistant-form-element-errors.d.ts +12 -0
  730. package/dist/domain/domain-runtime/spec/module-checks/find-assistant-form-element-errors.js +1 -0
  731. package/dist/domain/domain-runtime/spec/module-checks/index.d.ts +3 -1
  732. package/dist/domain/domain-runtime/spec/module-checks/index.js +1 -1
  733. package/dist/domain/domain-runtime/spec/module-checks/merge-expression-modules.d.ts +23 -0
  734. package/dist/domain/domain-runtime/spec/module-checks/merge-expression-modules.js +1 -0
  735. package/dist/domain/domain-runtime/spec/module-checks/resolve-expression-modules.d.ts +3 -4
  736. package/dist/domain/domain-runtime/spec/module-checks/resolve-expression-modules.js +1 -1
  737. package/dist/domain/domain-runtime/spec/selectors.d.ts +3 -1
  738. package/dist/domain/domain-runtime/spec/selectors.js +1 -1
  739. package/dist/domain/domain-runtime/web-component/actions.d.ts +3 -0
  740. package/dist/domain/domain-runtime/web-component/actions.js +1 -1
  741. package/dist/domain/domain-runtime/web-component/initialize.d.ts +1 -0
  742. package/dist/domain/domain-runtime/web-component/initialize.js +1 -1
  743. package/dist/domain/domain-runtime/web-component/selectors.d.ts +2 -0
  744. package/dist/domain/domain-runtime/web-component/selectors.js +1 -1
  745. package/dist/domain/domain-runtime/web-component/types.d.ts +6 -3
  746. package/dist/domain/extensions/export-images/agent-screenshot.d.ts +24 -0
  747. package/dist/domain/extensions/export-images/agent-screenshot.js +1 -0
  748. package/dist/domain/extensions/{client-side-image.d.ts → export-images/client-side-image.d.ts} +2 -2
  749. package/dist/domain/extensions/export-images/client-side-image.js +1 -0
  750. package/dist/domain/extensions/export-images/index.d.ts +3 -0
  751. package/dist/domain/extensions/export-images/index.js +1 -0
  752. package/dist/domain/extensions/{save-template-thumbnail.d.ts → export-images/save-template-thumbnail.d.ts} +2 -2
  753. package/dist/domain/extensions/export-images/save-template-thumbnail.js +1 -0
  754. package/dist/domain/extensions/index.d.ts +1 -2
  755. package/dist/domain/extensions/index.js +1 -1
  756. package/dist/domain/index.d.ts +3 -2
  757. package/dist/domain/index.js +1 -1
  758. package/dist/domain/mocks/create-mock-domain-runtime.d.ts +9 -0
  759. package/dist/domain/spec/application/admin-pages-section.d.ts +29 -0
  760. package/dist/domain/spec/application/admin-pages-section.js +1 -0
  761. package/dist/domain/spec/application/admin-pages.d.ts +26 -0
  762. package/dist/domain/spec/application/admin-pages.js +1 -0
  763. package/dist/domain/spec/application/admin-states.d.ts +5 -0
  764. package/dist/domain/spec/application/admin-states.js +1 -0
  765. package/dist/domain/spec/application/configurator-states.d.ts +8 -0
  766. package/dist/domain/spec/application/configurator-states.js +1 -0
  767. package/dist/domain/spec/application/index.d.ts +5 -0
  768. package/dist/domain/spec/application/index.js +1 -0
  769. package/dist/domain/spec/components/bindings/index.d.ts +2 -0
  770. package/dist/domain/spec/components/bindings/index.js +1 -0
  771. package/dist/domain/spec/components/bindings/read-binding.d.ts +13 -0
  772. package/dist/domain/spec/components/bindings/read-binding.js +1 -0
  773. package/dist/domain/spec/components/bindings/write-binding.d.ts +32 -0
  774. package/dist/domain/spec/components/bindings/write-binding.js +1 -0
  775. package/dist/{application-spec/parse-application-files → domain}/spec/components/component-entry.d.ts +3 -3
  776. package/dist/domain/spec/components/component-entry.js +1 -0
  777. package/dist/{application-spec/core → domain/spec}/components/component-filter.d.ts +3 -2
  778. package/dist/domain/spec/components/component-filters.d.ts +10 -0
  779. package/dist/domain/spec/components/component-filters.js +1 -0
  780. package/dist/domain/spec/components/components.d.ts +4 -0
  781. package/dist/domain/spec/components/components.js +1 -0
  782. package/dist/domain/spec/components/index.d.ts +6 -0
  783. package/dist/domain/spec/enhanced-json/enhanced-json-value.d.ts +30 -0
  784. package/dist/domain/spec/enhanced-json/enhanced-json-value.js +1 -0
  785. package/dist/domain/spec/enhanced-json/index.d.ts +1 -0
  786. package/dist/domain/spec/enhanced-json/index.js +1 -0
  787. package/dist/{application-spec/parse-application-files → domain}/spec/expressions/expression.d.ts +9 -3
  788. package/dist/domain/spec/expressions/expression.js +1 -0
  789. package/dist/domain/spec/expressions/expressions.d.ts +27 -0
  790. package/dist/domain/spec/expressions/expressions.js +1 -0
  791. package/dist/domain/spec/expressions/index.d.ts +5 -0
  792. package/dist/domain/spec/expressions/memo-eval-plan.d.ts +70 -0
  793. package/dist/domain/spec/expressions/memo-eval-plan.js +1 -0
  794. package/dist/domain/spec/expressions/relation-expression-params.js +1 -0
  795. package/dist/domain/spec/index.d.ts +9 -0
  796. package/dist/domain/spec/index.js +1 -0
  797. package/dist/domain/spec/invariants/index.d.ts +2 -0
  798. package/dist/domain/spec/invariants/index.js +1 -0
  799. package/dist/domain/spec/invariants/invariant.d.ts +24 -0
  800. package/dist/domain/spec/invariants/invariant.js +1 -0
  801. package/dist/domain/spec/invariants/invariants.d.ts +14 -0
  802. package/dist/domain/spec/invariants/invariants.js +1 -0
  803. package/dist/domain/spec/json-schema.d.ts +52 -0
  804. package/dist/domain/spec/json-schema.js +1 -0
  805. package/dist/domain/spec/markers/index.d.ts +3 -0
  806. package/dist/domain/spec/markers/index.js +1 -0
  807. package/dist/domain/spec/markers/msg-marker.d.ts +28 -0
  808. package/dist/domain/spec/markers/msg-marker.js +1 -0
  809. package/dist/domain/spec/model/aliases.d.ts +9 -0
  810. package/dist/domain/spec/model/aliases.js +1 -0
  811. package/dist/domain/spec/model/common-types.d.ts +15 -0
  812. package/dist/domain/spec/model/common-types.js +1 -0
  813. package/dist/domain/spec/model/defaults.d.ts +33 -0
  814. package/dist/domain/spec/model/defaults.js +1 -0
  815. package/dist/domain/spec/model/entity-types.d.ts +8 -0
  816. package/dist/domain/spec/model/entity-types.js +1 -0
  817. package/dist/domain/spec/model/index.d.ts +7 -0
  818. package/dist/domain/spec/model/index.js +1 -0
  819. package/dist/domain/spec/model/model-version-key.d.ts +3 -0
  820. package/dist/domain/spec/model/model-version-key.js +1 -0
  821. package/dist/domain/spec/model/names/action-name.d.ts +7 -0
  822. package/dist/domain/spec/model/names/action-name.js +1 -0
  823. package/dist/domain/spec/model/names/alias-name.d.ts +7 -0
  824. package/dist/domain/spec/model/names/alias-name.js +1 -0
  825. package/dist/domain/spec/model/names/entity-or-alias-name.d.ts +8 -0
  826. package/dist/domain/spec/model/names/entity-or-alias-name.js +1 -0
  827. package/dist/domain/spec/model/names/entity-type-name.d.ts +8 -0
  828. package/dist/domain/spec/model/names/entity-type-name.js +1 -0
  829. package/dist/domain/spec/model/names/expression-name.d.ts +6 -0
  830. package/dist/domain/spec/model/names/expression-name.js +1 -0
  831. package/dist/domain/spec/model/names/index.d.ts +9 -0
  832. package/dist/domain/spec/model/names/index.js +1 -0
  833. package/dist/domain/spec/model/names/instance-name.d.ts +7 -0
  834. package/dist/domain/spec/model/names/instance-name.js +1 -0
  835. package/dist/domain/spec/model/names/invariant-name.d.ts +3 -0
  836. package/dist/domain/spec/model/names/invariant-name.js +1 -0
  837. package/dist/domain/spec/model/names/shape-property-name.d.ts +11 -0
  838. package/dist/domain/spec/model/names/shape-property-name.js +1 -0
  839. package/dist/domain/spec/model/names/violation-type-name.d.ts +3 -0
  840. package/dist/domain/spec/model/names/violation-type-name.js +1 -0
  841. package/dist/domain/spec/model/presets.d.ts +30 -0
  842. package/dist/domain/spec/model/presets.js +1 -0
  843. package/dist/domain/spec/sections/actions.d.ts +23 -0
  844. package/dist/domain/spec/sections/actions.js +1 -0
  845. package/dist/domain/spec/sections/app-metadata.d.ts +18 -0
  846. package/dist/domain/spec/sections/app-metadata.js +1 -0
  847. package/dist/domain/spec/sections/application-version.d.ts +7 -0
  848. package/dist/domain/spec/sections/application-version.js +1 -0
  849. package/dist/domain/spec/sections/data-spec/chunks.d.ts +23 -0
  850. package/dist/domain/spec/sections/data-spec/chunks.js +1 -0
  851. package/dist/domain/spec/sections/data-spec/custom-data-spec-entry.d.ts +16 -0
  852. package/dist/domain/spec/sections/data-spec/custom-data-spec-entry.js +1 -0
  853. package/dist/domain/spec/sections/data-spec/data-entry-key.d.ts +9 -0
  854. package/dist/domain/spec/sections/data-spec/data-entry-key.js +1 -0
  855. package/dist/domain/spec/sections/data-spec/index.d.ts +5 -0
  856. package/dist/domain/spec/sections/data-spec/index.js +1 -0
  857. package/dist/domain/spec/sections/data-spec/parsed-data-spec-entries.d.ts +10 -0
  858. package/dist/domain/spec/sections/data-spec/parsed-data-spec-entries.js +1 -0
  859. package/dist/domain/spec/sections/data-spec/swatch-data-spec-entry.d.ts +14 -0
  860. package/dist/domain/spec/sections/data-spec/swatch-data-spec-entry.js +1 -0
  861. package/dist/domain/spec/sections/index.d.ts +9 -0
  862. package/dist/domain/spec/sections/index.js +1 -0
  863. package/dist/domain/spec/sections/infra/acl.d.ts +12 -0
  864. package/dist/domain/spec/sections/infra/acl.js +1 -0
  865. package/dist/domain/spec/sections/infra/index.d.ts +3 -0
  866. package/dist/domain/spec/sections/infra/index.js +1 -0
  867. package/dist/domain/spec/sections/infra/resource-entry.d.ts +46 -0
  868. package/dist/domain/spec/sections/infra/resource-entry.js +1 -0
  869. package/dist/domain/spec/sections/infra/resources-config.d.ts +10 -0
  870. package/dist/domain/spec/sections/infra/resources-config.js +1 -0
  871. package/dist/domain/spec/sections/state-value.d.ts +7 -0
  872. package/dist/domain/spec/sections/state-value.js +1 -0
  873. package/dist/domain/spec/sections/theme.d.ts +10 -0
  874. package/dist/domain/spec/sections/theme.js +1 -0
  875. package/dist/domain/spec/sections/transformers.d.ts +15 -0
  876. package/dist/domain/spec/sections/transformers.js +1 -0
  877. package/dist/domain/spec/sections/ui.d.ts +12 -0
  878. package/dist/domain/spec/sections/ui.js +1 -0
  879. package/dist/domain/system-components/child-entity-selection.js +1 -1
  880. package/dist/domain/system-components/common/scene-entity-control-schema.d.ts +3 -0
  881. package/dist/domain/system-components/common/scene-entity-control-schema.js +1 -1
  882. package/dist/domain/system-definitions.js +1 -1
  883. package/dist/domain/utils/index.d.ts +2 -0
  884. package/dist/domain/utils/index.js +1 -0
  885. package/dist/editor/Editor.d.ts +7 -0
  886. package/dist/editor/Editor.js +1 -1
  887. package/dist/editor/domain-editors/DomainSpecContext.js +1 -1
  888. package/dist/editor/domain-editors/apply-spec-update.d.ts +10 -2
  889. package/dist/editor/domain-editors/apply-spec-update.js +1 -1
  890. package/dist/editor/domain-editors/use-implementation-files.d.ts +6 -14
  891. package/dist/editor/domain-editors/use-implementation-files.js +1 -1
  892. package/dist/editor/graphql/GraphQLPanel.js +1 -1
  893. package/dist/editor/mocks/CreateMockYaml.js +2 -2
  894. package/dist/editor/mocks/EditorMockContext.d.ts +2 -0
  895. package/dist/editor/mocks/EditorMockContext.js +1 -1
  896. package/dist/editor/screenshot/ScreenshotHandler.js +1 -1
  897. package/dist/i18n/locales/cs/messages.js +1 -1
  898. package/dist/i18n/locales/da/messages.js +1 -1
  899. package/dist/i18n/locales/de/messages.js +1 -1
  900. package/dist/i18n/locales/de-AT/messages.js +1 -1
  901. package/dist/i18n/locales/en/messages.js +1 -1
  902. package/dist/i18n/locales/en-AU/messages.js +1 -1
  903. package/dist/i18n/locales/en-GB/messages.js +1 -1
  904. package/dist/i18n/locales/es/messages.js +1 -1
  905. package/dist/i18n/locales/fr/messages.js +1 -1
  906. package/dist/i18n/locales/hu/messages.js +1 -1
  907. package/dist/i18n/locales/it/messages.js +1 -1
  908. package/dist/i18n/locales/nl/messages.js +1 -1
  909. package/dist/i18n/locales/pl/messages.js +1 -1
  910. package/dist/i18n/locales/pt/messages.js +1 -1
  911. package/dist/i18n/locales/ro/messages.js +1 -1
  912. package/dist/i18n/locales/sk/messages.js +1 -1
  913. package/dist/i18n/locales/tr/messages.js +1 -1
  914. package/dist/legacy/domain-cli/utils/cache.d.ts +1 -1
  915. package/dist/legacy/domain-cli/utils/cache.js +1 -1
  916. package/dist/legacy/domain-spec/__generated/domain-schema.d.ts +95 -80
  917. package/dist/legacy/domain-spec/spec/domain-spec.js +1 -1
  918. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/claude-md.d.ts +1 -1
  919. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/cursor-rules.d.ts +1 -1
  920. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.d.ts +1 -1
  921. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.js +11 -5
  922. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/frontend-admin.js +10 -11
  923. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/frontend-embedded-admin.js +9 -10
  924. package/dist/phoenix/application-spec/application-spec-builder.d.ts +0 -2
  925. package/dist/phoenix/application-spec/application-spec-builder.js +1 -1
  926. package/dist/phoenix/application-spec/generate-application-spec-project.d.ts +1 -2
  927. package/dist/phoenix/application-spec/generate-application-spec-project.js +2 -2
  928. package/dist/phoenix/application-spec/generate-application-spec-story.js +2 -2
  929. package/dist/phoenix/application-spec/generate-project-files.d.ts +1 -2
  930. package/dist/phoenix/application-spec/index.d.ts +1 -0
  931. package/dist/phoenix/application-spec/index.js +1 -1
  932. package/dist/phoenix/application-spec/project-files.js +1 -1
  933. package/dist/phoenix/application-spec/resolve-deployment-data.d.ts +11 -0
  934. package/dist/phoenix/application-spec/resolve-deployment-data.js +2 -2
  935. package/dist/phoenix/bin.d.ts +2 -0
  936. package/dist/phoenix/bin.js +2 -0
  937. package/dist/phoenix/check-configs/built-in-eslint-config.d.ts +9 -0
  938. package/dist/phoenix/check-configs/built-in-eslint-config.js +1 -0
  939. package/dist/phoenix/check-configs/eslint-config.d.ts +10 -0
  940. package/dist/phoenix/check-configs/eslint-config.js +1 -0
  941. package/dist/phoenix/check-configs/index.d.ts +8 -0
  942. package/dist/phoenix/check-configs/index.js +1 -0
  943. package/dist/phoenix/check-configs/typescript-project.d.ts +5 -0
  944. package/dist/phoenix/check-configs/typescript-project.js +1 -0
  945. package/dist/phoenix/cli.d.ts +0 -1
  946. package/dist/phoenix/cli.js +1 -2
  947. package/dist/phoenix/commands/build.js +1 -1
  948. package/dist/phoenix/commands/check.js +1 -1
  949. package/dist/phoenix/commands/clean.js +1 -1
  950. package/dist/phoenix/commands/deploy.js +2 -2
  951. package/dist/phoenix/commands/deps/deps.d.ts +22 -1
  952. package/dist/phoenix/commands/deps/deps.js +2 -2
  953. package/dist/phoenix/commands/deps/index.d.ts +1 -1
  954. package/dist/phoenix/commands/deps/index.js +1 -1
  955. package/dist/phoenix/commands/deps/sdk-manifest.js +1 -1
  956. package/dist/phoenix/commands/dev.js +5 -5
  957. package/dist/phoenix/commands/fix.js +1 -1
  958. package/dist/phoenix/commands/generated-env-markers.d.ts +1 -0
  959. package/dist/phoenix/commands/generated-env-markers.js +1 -1
  960. package/dist/phoenix/commands/index.d.ts +1 -1
  961. package/dist/phoenix/commands/index.js +1 -1
  962. package/dist/phoenix/commands/init.d.ts +17 -5
  963. package/dist/phoenix/commands/init.js +1 -1
  964. package/dist/phoenix/commands/link.js +1 -1
  965. package/dist/phoenix/commands/prettier.js +1 -1
  966. package/dist/phoenix/commands/sync.js +1 -1
  967. package/dist/phoenix/commands/unlink.js +1 -1
  968. package/dist/phoenix/lingui/index.d.ts +1 -0
  969. package/dist/phoenix/lingui/index.js +1 -0
  970. package/dist/phoenix/lingui/lingui.d.ts +18 -0
  971. package/dist/phoenix/lingui/lingui.js +1 -0
  972. package/dist/phoenix/services/application-spec-project-watcher.d.ts +3 -3
  973. package/dist/phoenix/services/application-spec-project-watcher.js +2 -2
  974. package/dist/phoenix/services/index.d.ts +1 -0
  975. package/dist/phoenix/services/index.js +1 -1
  976. package/dist/phoenix/services/lingui-watcher.js +1 -1
  977. package/dist/phoenix/services/prepare-development-environment.js +1 -1
  978. package/dist/phoenix/services/swc.js +1 -1
  979. package/dist/phoenix/services/vite-config.js +1 -1
  980. package/dist/phoenix/utils/index.d.ts +3 -2
  981. package/dist/phoenix/utils/index.js +1 -1
  982. package/dist/phoenix/utils/node-version/index.d.ts +1 -0
  983. package/dist/phoenix/utils/node-version/index.js +1 -0
  984. package/dist/phoenix/utils/node-version/supported-node-version.d.ts +12 -0
  985. package/dist/phoenix/utils/node-version/supported-node-version.js +4 -0
  986. package/dist/phoenix/utils/package-info.d.ts +0 -9
  987. package/dist/phoenix/utils/package-info.js +1 -1
  988. package/dist/phoenix/utils/package-manager/index.d.ts +2 -0
  989. package/dist/phoenix/utils/package-manager/index.js +1 -0
  990. package/dist/phoenix/utils/package-manager/package-manager-commands.d.ts +19 -0
  991. package/dist/phoenix/utils/package-manager/package-manager-commands.js +1 -0
  992. package/dist/phoenix/utils/package-manager/pnpm-project.d.ts +9 -0
  993. package/dist/phoenix/utils/package-manager/pnpm-project.js +1 -0
  994. package/dist/phoenix/utils/run-command.d.ts +11 -0
  995. package/dist/phoenix/utils/run-command.js +1 -1
  996. package/dist/phoenix/utils/sdk-tool/index.d.ts +1 -0
  997. package/dist/phoenix/utils/sdk-tool/index.js +1 -0
  998. package/dist/phoenix/utils/sdk-tool/resolve-sdk-tool-bin.d.ts +15 -0
  999. package/dist/phoenix/utils/sdk-tool/resolve-sdk-tool-bin.js +1 -0
  1000. package/dist/react-sdk/application-runtime/common-services/analytics/analytics-service.d.ts +1 -1
  1001. package/dist/{configurator/common → react-sdk/application-runtime/common-services/analytics}/frontend-analytics.d.ts +4 -0
  1002. package/dist/react-sdk/application-runtime/common-services/analytics/index.d.ts +1 -0
  1003. package/dist/react-sdk/application-runtime/common-services/analytics/index.js +1 -1
  1004. package/dist/react-sdk/application-runtime/common-services/initialize.d.ts +2 -2
  1005. package/dist/react-sdk/application-runtime/domain-application-context/chat-system.d.ts +1 -1
  1006. package/dist/react-sdk/application-runtime/hooks/index.d.ts +2 -0
  1007. package/dist/react-sdk/application-runtime/hooks/index.js +1 -1
  1008. package/dist/react-sdk/application-runtime/hooks/loading/index.d.ts +5 -0
  1009. package/dist/react-sdk/application-runtime/hooks/loading/index.js +1 -0
  1010. package/dist/react-sdk/application-runtime/hooks/loading/loader-host-context.d.ts +11 -0
  1011. package/dist/react-sdk/application-runtime/hooks/loading/loader-host-context.js +1 -0
  1012. package/dist/react-sdk/application-runtime/hooks/loading/use-is-awaiting-loading-phase.d.ts +8 -0
  1013. package/dist/react-sdk/application-runtime/hooks/loading/use-is-awaiting-loading-phase.js +1 -0
  1014. package/dist/react-sdk/application-runtime/hooks/loading/use-is-loader-hosted.d.ts +7 -0
  1015. package/dist/react-sdk/application-runtime/hooks/loading/use-is-loader-hosted.js +1 -0
  1016. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-actions.d.ts +9 -0
  1017. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-actions.js +1 -0
  1018. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-application.d.ts +24 -0
  1019. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-application.js +1 -0
  1020. package/dist/react-sdk/application-runtime/hooks/responsive/index.d.ts +3 -0
  1021. package/dist/react-sdk/application-runtime/hooks/responsive/index.js +1 -0
  1022. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-actions.d.ts +9 -0
  1023. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-actions.js +1 -0
  1024. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-application.d.ts +26 -0
  1025. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-application.js +1 -0
  1026. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-state.d.ts +10 -0
  1027. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-state.js +1 -0
  1028. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-store.d.ts +24 -0
  1029. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-store.js +1 -0
  1030. package/dist/react-sdk/application-runtime/hooks/use-access-service.d.ts +5 -0
  1031. package/dist/react-sdk/application-runtime/hooks/use-access-service.js +1 -1
  1032. package/dist/react-sdk/application-runtime/hooks/use-phoenix-element-slots.d.ts +2 -1
  1033. package/dist/react-sdk/application-runtime/hooks/use-web-component-readonly-sync.d.ts +4 -11
  1034. package/dist/react-sdk/application-runtime/hooks/use-web-component-readonly-sync.js +1 -1
  1035. package/dist/react-sdk/application-runtime/hooks/use-web-component.d.ts +5 -0
  1036. package/dist/react-sdk/application-runtime/hooks/use-web-component.js +1 -1
  1037. package/dist/react-sdk/application-runtime/host-properties/actions.d.ts +15 -0
  1038. package/dist/react-sdk/application-runtime/host-properties/actions.js +1 -0
  1039. package/dist/react-sdk/application-runtime/host-properties/connect-host-properties.d.ts +30 -0
  1040. package/dist/react-sdk/application-runtime/host-properties/connect-host-properties.js +1 -0
  1041. package/dist/react-sdk/application-runtime/host-properties/domain-host-properties.d.ts +7 -0
  1042. package/dist/react-sdk/application-runtime/host-properties/domain-host-properties.js +1 -0
  1043. package/dist/react-sdk/application-runtime/host-properties/host-property-descriptors.d.ts +21 -0
  1044. package/dist/react-sdk/application-runtime/host-properties/host-property-descriptors.js +1 -0
  1045. package/dist/react-sdk/application-runtime/host-properties/host-property-scopes.d.ts +42 -0
  1046. package/dist/react-sdk/application-runtime/host-properties/host-property-scopes.js +1 -0
  1047. package/dist/react-sdk/application-runtime/host-properties/index.d.ts +8 -0
  1048. package/dist/react-sdk/application-runtime/host-properties/index.js +1 -0
  1049. package/dist/react-sdk/application-runtime/host-properties/initialize.d.ts +7 -0
  1050. package/dist/react-sdk/application-runtime/host-properties/initialize.js +1 -0
  1051. package/dist/react-sdk/application-runtime/host-properties/selectors.d.ts +54 -0
  1052. package/dist/react-sdk/application-runtime/host-properties/selectors.js +1 -0
  1053. package/dist/react-sdk/application-runtime/host-properties/types.d.ts +18 -0
  1054. package/dist/react-sdk/application-runtime/host-properties/types.js +1 -0
  1055. package/dist/react-sdk/application-runtime/index.d.ts +3 -0
  1056. package/dist/react-sdk/application-runtime/integration/initialize.d.ts +7 -6
  1057. package/dist/react-sdk/application-runtime/integration/initialize.js +1 -1
  1058. package/dist/react-sdk/application-runtime/integration/selectors.d.ts +11 -2
  1059. package/dist/react-sdk/application-runtime/integration/selectors.js +1 -1
  1060. package/dist/react-sdk/application-runtime/integration/types.d.ts +5 -2
  1061. package/dist/react-sdk/application-runtime/loading/actions.d.ts +45 -0
  1062. package/dist/react-sdk/application-runtime/loading/actions.js +1 -0
  1063. package/dist/react-sdk/application-runtime/loading/index.d.ts +4 -0
  1064. package/dist/react-sdk/application-runtime/loading/index.js +1 -0
  1065. package/dist/react-sdk/application-runtime/loading/initialize.d.ts +3 -0
  1066. package/dist/react-sdk/application-runtime/loading/initialize.js +1 -0
  1067. package/dist/react-sdk/application-runtime/loading/selectors.d.ts +18 -0
  1068. package/dist/react-sdk/application-runtime/loading/selectors.js +1 -0
  1069. package/dist/react-sdk/application-runtime/loading/types.d.ts +59 -0
  1070. package/dist/react-sdk/application-runtime/loading/types.js +1 -0
  1071. package/dist/react-sdk/application-runtime/mocks/create-mock-application-runtime.js +1 -1
  1072. package/dist/react-sdk/application-runtime/provider/ApplicationRuntime.d.ts +6 -0
  1073. package/dist/react-sdk/application-runtime/provider/ApplicationRuntime.js +1 -1
  1074. package/dist/react-sdk/application-runtime/provider/ApplicationType.d.ts +7 -0
  1075. package/dist/react-sdk/application-runtime/provider/ApplicationType.js +1 -1
  1076. package/dist/react-sdk/application-runtime/responsive/actions.d.ts +47 -0
  1077. package/dist/react-sdk/application-runtime/responsive/actions.js +1 -0
  1078. package/dist/react-sdk/application-runtime/responsive/index.d.ts +4 -0
  1079. package/dist/react-sdk/application-runtime/responsive/index.js +1 -0
  1080. package/dist/react-sdk/application-runtime/responsive/initialize.d.ts +3 -0
  1081. package/dist/react-sdk/application-runtime/responsive/initialize.js +1 -0
  1082. package/dist/react-sdk/application-runtime/responsive/selectors.d.ts +20 -0
  1083. package/dist/react-sdk/application-runtime/responsive/selectors.js +1 -0
  1084. package/dist/react-sdk/application-runtime/responsive/types.d.ts +104 -0
  1085. package/dist/react-sdk/application-runtime/responsive/types.js +1 -0
  1086. package/dist/react-sdk/application-runtime/routing/routing-service.d.ts +34 -2
  1087. package/dist/react-sdk/application-runtime/routing/routing-service.js +1 -1
  1088. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.d.ts +313 -10
  1089. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.js +1 -1
  1090. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/ConfiguratorRoutingProvider.d.ts +1 -1
  1091. package/dist/react-sdk/configurator-routing/ConfiguratorRoutingProvider.js +1 -0
  1092. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/OnGoToIndexHandler.d.ts +1 -2
  1093. package/dist/react-sdk/configurator-routing/OnGoToIndexHandler.js +1 -0
  1094. package/dist/react-sdk/configurator-routing/index.d.ts +3 -0
  1095. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/index.js +1 -1
  1096. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/use-power-routing-lifecycle.d.ts +2 -0
  1097. package/dist/react-sdk/configurator-routing/use-power-routing-lifecycle.js +1 -0
  1098. package/dist/react-sdk/domain-application-context/BackendDataProvider.js +1 -1
  1099. package/dist/react-sdk/domain-application-context/ConfigurationPersistSystemFailureHandler.js +1 -1
  1100. package/dist/react-sdk/domain-application-context/DomainLifecycleBoundary.js +1 -1
  1101. package/dist/react-sdk/domain-application-context/FrontendDataProvider.js +1 -1
  1102. package/dist/react-sdk/domain-application-context/OnPresetLoadedHandler.js +1 -0
  1103. package/dist/react-sdk/domain-application-context/PublishedDataProvider.js +1 -1
  1104. package/dist/react-sdk/domain-application-context/chat-hooks.d.ts +4 -0
  1105. package/dist/react-sdk/domain-application-context/chat-hooks.js +1 -0
  1106. package/dist/react-sdk/domain-application-context/index.d.ts +2 -0
  1107. package/dist/react-sdk/domain-application-context/index.js +1 -1
  1108. package/dist/react-sdk/domain-context/common-hooks/index.d.ts +9 -0
  1109. package/dist/react-sdk/domain-context/common-hooks/index.js +1 -0
  1110. package/dist/react-sdk/domain-context/common-hooks/use-configuration-save-state.d.ts +23 -0
  1111. package/dist/react-sdk/domain-context/common-hooks/use-configuration-save-state.js +1 -0
  1112. package/dist/react-sdk/domain-context/common-hooks/use-configurator-messages.d.ts +15 -4
  1113. package/dist/react-sdk/domain-context/common-hooks/use-configurator-messages.js +1 -1
  1114. package/dist/react-sdk/domain-context/common-hooks/use-domain-context.d.ts +1 -0
  1115. package/dist/react-sdk/domain-context/component-hooks/index.d.ts +1 -0
  1116. package/dist/react-sdk/domain-context/component-hooks/index.js +1 -0
  1117. package/dist/react-sdk/domain-context/component-hooks/use-component.js +1 -1
  1118. package/dist/react-sdk/domain-context/entity-hooks/use-domain-entity-state.js +1 -1
  1119. package/dist/react-sdk/domain-context/entity-hooks/use-entity-price.js +1 -1
  1120. package/dist/react-sdk/domain-context/entity-hooks/use-root-entity-id.js +1 -1
  1121. package/dist/react-sdk/domain-context/entity-hooks/use-root-entity-state.js +1 -1
  1122. package/dist/react-sdk/domain-context/index.d.ts +7 -0
  1123. package/dist/react-sdk/domain-context/index.js +1 -1
  1124. package/dist/react-sdk/domain-context/system-hooks/composition-hooks.js +1 -1
  1125. package/dist/react-sdk/domain-context/system-hooks/dimension-hooks.js +1 -1
  1126. package/dist/react-sdk/domain-context/system-hooks/generate-share-link-hooks.d.ts +8 -0
  1127. package/dist/react-sdk/domain-context/system-hooks/generate-share-link-hooks.js +1 -0
  1128. package/dist/react-sdk/domain-context/system-hooks/hover-hooks.js +1 -1
  1129. package/dist/react-sdk/domain-context/system-hooks/locale-switch-hooks.d.ts +24 -0
  1130. package/dist/react-sdk/domain-context/system-hooks/locale-switch-hooks.js +1 -0
  1131. package/dist/react-sdk/domain-context/system-hooks/navigation-hooks.js +1 -1
  1132. package/dist/react-sdk/domain-context/system-hooks/selection-hooks.js +1 -1
  1133. package/dist/react-sdk/domain-context/system-hooks/share-links-hooks.d.ts +32 -0
  1134. package/dist/react-sdk/domain-context/system-hooks/share-links-hooks.js +1 -0
  1135. package/dist/react-sdk/domain-context/system-hooks/step-navigation-hooks.d.ts +57 -0
  1136. package/dist/react-sdk/domain-context/system-hooks/step-navigation-hooks.js +1 -0
  1137. package/dist/react-sdk/domain-context/system-hooks/tab-navigation-hooks.d.ts +61 -0
  1138. package/dist/react-sdk/domain-context/system-hooks/tab-navigation-hooks.js +1 -0
  1139. package/dist/react-sdk/domain-context/system-hooks/undo-redo-hooks.d.ts +20 -0
  1140. package/dist/react-sdk/domain-context/system-hooks/undo-redo-hooks.js +1 -0
  1141. package/dist/react-sdk/handlers/FinalizeActionRunner.d.ts +13 -0
  1142. package/dist/react-sdk/handlers/FinalizeActionRunner.js +1 -0
  1143. package/dist/react-sdk/handlers/FinalizeActionsHost.d.ts +10 -0
  1144. package/dist/react-sdk/handlers/FinalizeActionsHost.js +1 -0
  1145. package/dist/react-sdk/handlers/FinalizeActionsProvider.d.ts +11 -0
  1146. package/dist/react-sdk/handlers/FinalizeActionsProvider.js +1 -0
  1147. package/dist/react-sdk/handlers/finalize-actions-context.d.ts +6 -0
  1148. package/dist/react-sdk/handlers/finalize-actions-context.js +1 -0
  1149. package/dist/react-sdk/handlers/finalize-actions-store.d.ts +23 -0
  1150. package/dist/react-sdk/handlers/finalize-actions-store.js +1 -0
  1151. package/dist/react-sdk/handlers/index.d.ts +6 -0
  1152. package/dist/react-sdk/handlers/index.js +1 -1
  1153. package/dist/{configurator/common → react-sdk/handlers}/use-finalize-action.d.ts +3 -2
  1154. package/dist/react-sdk/handlers/use-finalize-action.js +1 -0
  1155. package/dist/react-sdk/handlers/use-finalize-actions.d.ts +53 -0
  1156. package/dist/react-sdk/handlers/use-finalize-actions.js +1 -0
  1157. package/dist/react-sdk/index.d.ts +7 -0
  1158. package/dist/react-sdk/index.js +1 -1
  1159. package/dist/react-sdk/integration/IntegrationSubscription.js +1 -0
  1160. package/dist/react-sdk/integration/index.d.ts +1 -0
  1161. package/dist/react-sdk/integration/index.js +1 -0
  1162. package/dist/react-sdk/lifecycle-providers/ConfiguratorDataProvider.d.ts +8 -0
  1163. package/dist/react-sdk/lifecycle-providers/ConfiguratorDataProvider.js +1 -0
  1164. package/dist/react-sdk/lifecycle-providers/LifecycleProviders.js +1 -0
  1165. package/dist/react-sdk/lifecycle-providers/index.d.ts +2 -0
  1166. package/dist/react-sdk/lifecycle-providers/index.js +1 -0
  1167. package/dist/react-sdk/loading-state/LoaderHost.d.ts +20 -0
  1168. package/dist/react-sdk/loading-state/LoaderHost.js +1 -0
  1169. package/dist/react-sdk/loading-state/built-in-loading-phase.d.ts +9 -0
  1170. package/dist/react-sdk/loading-state/built-in-loading-phase.js +1 -0
  1171. package/dist/react-sdk/loading-state/create-app-loader.d.ts +18 -0
  1172. package/dist/react-sdk/loading-state/create-app-loader.js +1 -0
  1173. package/dist/react-sdk/loading-state/index.d.ts +4 -2
  1174. package/dist/react-sdk/loading-state/index.js +1 -1
  1175. package/dist/react-sdk/loading-state/{LoadingStateProvider.d.ts → loading-state-hooks.d.ts} +3 -12
  1176. package/dist/react-sdk/loading-state/loading-state-hooks.js +1 -0
  1177. package/dist/react-sdk/notifications/index.d.ts +1 -0
  1178. package/dist/react-sdk/notifications/index.js +1 -0
  1179. package/dist/react-sdk/notifications/snackbar-action-button.d.ts +30 -0
  1180. package/dist/react-sdk/notifications/snackbar-action-button.js +1 -0
  1181. package/dist/react-sdk/page-elements/ConfigurationNotFoundPagePropsProvider.d.ts +17 -0
  1182. package/dist/react-sdk/page-elements/ConfigurationNotFoundPagePropsProvider.js +1 -0
  1183. package/dist/react-sdk/page-elements/ConfiguratorErrorPagePropsProvider.d.ts +17 -0
  1184. package/dist/react-sdk/page-elements/ConfiguratorErrorPagePropsProvider.js +1 -0
  1185. package/dist/react-sdk/page-elements/configurator-error-page-props.d.ts +20 -0
  1186. package/dist/react-sdk/page-elements/configurator-error-page-props.js +1 -0
  1187. package/dist/react-sdk/page-elements/create-configuration-not-found-page.d.ts +15 -0
  1188. package/dist/react-sdk/page-elements/create-configuration-not-found-page.js +1 -0
  1189. package/dist/react-sdk/page-elements/create-configurator-error-page.d.ts +14 -0
  1190. package/dist/react-sdk/page-elements/create-configurator-error-page.js +1 -0
  1191. package/dist/react-sdk/page-elements/create-preset-ui.d.ts +9 -0
  1192. package/dist/react-sdk/page-elements/create-preset-ui.js +1 -0
  1193. package/dist/react-sdk/page-elements/index.d.ts +6 -0
  1194. package/dist/react-sdk/page-elements/index.js +1 -0
  1195. package/dist/react-sdk/preset-selection/PresetSelectionProvider.js +1 -0
  1196. package/dist/react-sdk/preset-selection/index.d.ts +1 -0
  1197. package/dist/react-sdk/preset-selection/index.js +1 -0
  1198. package/dist/react-sdk/scene-control-elements/AddEntityFabElement.d.ts +36 -0
  1199. package/dist/react-sdk/scene-control-elements/AddEntityFabElement.js +1 -0
  1200. package/dist/react-sdk/scene-control-elements/DeleteEntityFabElement.d.ts +44 -0
  1201. package/dist/react-sdk/scene-control-elements/DeleteEntityFabElement.js +1 -0
  1202. package/dist/react-sdk/scene-control-elements/NavigationHotspotElement.d.ts +38 -0
  1203. package/dist/react-sdk/scene-control-elements/NavigationHotspotElement.js +1 -0
  1204. package/dist/react-sdk/scene-control-elements/SelectionHotspotElement.d.ts +30 -0
  1205. package/dist/react-sdk/scene-control-elements/SelectionHotspotElement.js +1 -0
  1206. package/dist/react-sdk/scene-control-elements/ToolMenuFabElement.d.ts +30 -0
  1207. package/dist/react-sdk/scene-control-elements/ToolMenuFabElement.js +1 -0
  1208. package/dist/react-sdk/scene-control-elements/create-add-entity-fab.d.ts +9 -0
  1209. package/dist/react-sdk/scene-control-elements/create-add-entity-fab.js +1 -0
  1210. package/dist/react-sdk/scene-control-elements/create-delete-entity-fab.d.ts +9 -0
  1211. package/dist/react-sdk/scene-control-elements/create-delete-entity-fab.js +1 -0
  1212. package/dist/react-sdk/scene-control-elements/create-navigation-hotspot.d.ts +10 -0
  1213. package/dist/react-sdk/scene-control-elements/create-navigation-hotspot.js +1 -0
  1214. package/dist/react-sdk/scene-control-elements/create-selection-hotspot.d.ts +9 -0
  1215. package/dist/react-sdk/scene-control-elements/create-selection-hotspot.js +1 -0
  1216. package/dist/react-sdk/scene-control-elements/create-tool-menu-fab.d.ts +9 -0
  1217. package/dist/react-sdk/scene-control-elements/create-tool-menu-fab.js +1 -0
  1218. package/dist/react-sdk/scene-control-elements/index.d.ts +11 -0
  1219. package/dist/react-sdk/scene-control-elements/index.js +1 -0
  1220. package/dist/react-sdk/scene-control-elements/scene-control-tooltip-visibility.d.ts +5 -0
  1221. package/dist/react-sdk/scene-control-elements/scene-control-tooltip-visibility.js +1 -0
  1222. package/dist/react-sdk/session/NotAuthenticatedPage.d.ts +4 -0
  1223. package/dist/react-sdk/session/NotAuthenticatedPage.js +1 -1
  1224. package/dist/react-sdk/session/SessionServiceProvider.js +1 -1
  1225. package/dist/react-sdk/web-component/create-web-component.js +1 -1
  1226. package/dist/react-sdk/web-component/god-mode/god-mode-registry.d.ts +30 -0
  1227. package/dist/react-sdk/web-component/god-mode/god-mode-registry.js +1 -0
  1228. package/dist/react-sdk/web-component/god-mode/index.d.ts +1 -0
  1229. package/dist/react-sdk/web-component/god-mode/index.js +1 -0
  1230. package/dist/ui-sdk/components/snackbar/Snackbar.d.ts +24 -3
  1231. package/dist/ui-sdk/components/snackbar/Snackbar.js +1 -1
  1232. package/dist/ui-sdk/icons/__generated/Lightbulb.d.ts +3 -0
  1233. package/dist/ui-sdk/icons/__generated/Lightbulb.js +1 -0
  1234. package/dist/ui-sdk/icons/__generated/XCircle.d.ts +3 -0
  1235. package/dist/ui-sdk/icons/__generated/XCircle.js +1 -0
  1236. package/dist/ui-sdk/icons/__generated/index.d.ts +4 -0
  1237. package/dist/ui-sdk/icons/__generated/index.js +1 -1
  1238. package/dist/ui-sdk/icons/icons-registry.js +1 -1
  1239. package/dist/ui-sdk/responsive-application/ResponsiveApplicationProvider.d.ts +9 -0
  1240. package/dist/ui-sdk/responsive-application/ResponsiveApplicationProvider.js +1 -1
  1241. package/dist/ui-sdk/responsive-application/index.d.ts +1 -0
  1242. package/dist/ui-sdk/responsive-application/responsive-state-store.d.ts +59 -0
  1243. package/dist/ui-sdk/responsive-application/responsive-state-store.js +1 -0
  1244. package/dist/ui-sdk/responsive-application/use-store-responsive-info.d.ts +7 -0
  1245. package/dist/ui-sdk/responsive-application/use-store-responsive-info.js +1 -0
  1246. package/dist/ui-sdk/theme/types.d.ts +5 -1
  1247. package/dist/watch/glob-matcher.d.ts +4 -4
  1248. package/dist/watch/glob-matcher.js +1 -1
  1249. package/dist/watch/watch.d.ts +4 -4
  1250. package/dist/watch/watch.js +1 -1
  1251. package/package.json +29 -11
  1252. package/schema/domain-spec.json +226 -8
  1253. package/dist/application-spec/core/components/index.d.ts +0 -2
  1254. package/dist/application-spec/core/expressions/index.d.ts +0 -2
  1255. package/dist/application-spec/generate-application/code/templates/nvmrc.d.ts +0 -1
  1256. package/dist/application-spec/generate-application/code/templates/nvmrc.js +0 -2
  1257. package/dist/application-spec/generate-application/code/templates/package-json.d.ts +0 -10
  1258. package/dist/application-spec/generate-application/code/templates/package-json.js +0 -1
  1259. package/dist/configurator/common/use-finalize-action.js +0 -1
  1260. package/dist/configurator/configurator-context/ConfiguratorDataProvider.d.ts +0 -2
  1261. package/dist/configurator/configurator-context/ConfiguratorDataProvider.js +0 -1
  1262. package/dist/configurator/configurator-context/IntegrationSubscription.js +0 -1
  1263. package/dist/configurator/configurator-context/LifecycleProviders.js +0 -1
  1264. package/dist/configurator/configurator-context/OnPresetLoadedHandler.js +0 -1
  1265. package/dist/configurator/configurator-context/PresetSelectionProvider.js +0 -1
  1266. package/dist/configurator/configurator-context/configurator-hooks/chat-hooks.d.ts +0 -1
  1267. package/dist/configurator/configurator-context/configurator-hooks/chat-hooks.js +0 -1
  1268. package/dist/configurator/configurator-context/configurator-routing/ConfiguratorRoutingProvider.js +0 -1
  1269. package/dist/configurator/configurator-context/configurator-routing/OnGoToIndexHandler.js +0 -1
  1270. package/dist/configurator/configurator-context/configurator-routing/index.d.ts +0 -2
  1271. package/dist/configurator/configurator-context/configurator-routing/use-power-routing-lifecycle.js +0 -1
  1272. package/dist/configurator/ui/assistant/entity-link/entity-link-target.d.ts +0 -5
  1273. package/dist/configurator/ui/assistant/entity-link/entity-link-target.js +0 -1
  1274. package/dist/configurator/ui/phoenix-layout-elements/language/use-locale-options.d.ts +0 -4
  1275. package/dist/configurator/ui/phoenix-layout-elements/language/use-locale-options.js +0 -1
  1276. package/dist/configurator/ui/phoenix-layout-elements/measurements/use-measurements-visibility.d.ts +0 -4
  1277. package/dist/configurator/ui/phoenix-layout-elements/measurements/use-measurements-visibility.js +0 -1
  1278. package/dist/domain/available-system-components.d.ts +0 -11
  1279. package/dist/domain/available-system-components.js +0 -1
  1280. package/dist/domain/domain-builder.js +0 -1
  1281. package/dist/domain/extensions/client-side-image.js +0 -1
  1282. package/dist/domain/extensions/save-template-thumbnail.js +0 -1
  1283. package/dist/phoenix/commands/generate-project-files.d.ts +0 -6
  1284. package/dist/phoenix/commands/generate-project-files.js +0 -1
  1285. package/dist/phoenix/services/lingui.d.ts +0 -7
  1286. package/dist/phoenix/services/lingui.js +0 -1
  1287. package/dist/react-sdk/application-runtime/runtime/god-mode.d.ts +0 -19
  1288. package/dist/react-sdk/application-runtime/runtime/god-mode.js +0 -1
  1289. package/dist/react-sdk/loading-state/LoadingStateProvider.js +0 -1
  1290. package/dist/react-sdk/loading-state/loading-state-manager.d.ts +0 -32
  1291. package/dist/react-sdk/loading-state/loading-state-manager.js +0 -1
  1292. /package/dist/application-spec/{core/expressions/relation-expression-params.js → generate-application/runtime/spec-code/spec-code-module.js} +0 -0
  1293. /package/dist/application-spec/parse-application-files/spec/{components/component-entry.js → expressions/expression-read.js} +0 -0
  1294. /package/dist/{application-spec/parse-application-files/spec/expressions/expression.js → configurator/ui/assistant/form-elements/form-element-props.js} +0 -0
  1295. /package/dist/{application-spec/core → domain/spec/application}/application-instance.d.ts +0 -0
  1296. /package/dist/{application-spec/core → domain/spec/application}/application-instance.js +0 -0
  1297. /package/dist/{application-spec/core → domain/spec}/components/component-filter.js +0 -0
  1298. /package/dist/{application-spec/core → domain/spec}/components/index.js +0 -0
  1299. /package/dist/{application-spec/core → domain/spec}/components/sdk-code-ref.d.ts +0 -0
  1300. /package/dist/{application-spec/core → domain/spec}/components/sdk-code-ref.js +0 -0
  1301. /package/dist/{application-spec/core → domain/spec}/expressions/index.js +0 -0
  1302. /package/dist/{application-spec/core → domain/spec}/expressions/relation-expression-params.d.ts +0 -0
  1303. /package/dist/{application-spec/core → domain/spec}/expressions/sdk-expression-implementation.d.ts +0 -0
  1304. /package/dist/{application-spec/core → domain/spec}/expressions/sdk-expression-implementation.js +0 -0
  1305. /package/dist/{application-spec/parse-application-files/spec/components → domain/spec/markers}/component-prop-target.d.ts +0 -0
  1306. /package/dist/{application-spec/parse-application-files/spec/components → domain/spec/markers}/component-prop-target.js +0 -0
  1307. /package/dist/{application-spec/core → domain/spec}/markers/eval-marker.d.ts +0 -0
  1308. /package/dist/{application-spec/core → domain/spec}/markers/eval-marker.js +0 -0
  1309. /package/dist/{configurator/common → react-sdk/application-runtime/common-services/analytics}/frontend-analytics.js +0 -0
  1310. /package/dist/{configurator/configurator-context → react-sdk/domain-application-context}/OnPresetLoadedHandler.d.ts +0 -0
  1311. /package/dist/{configurator/configurator-context → react-sdk/integration}/IntegrationSubscription.d.ts +0 -0
  1312. /package/dist/{configurator/configurator-context → react-sdk/lifecycle-providers}/LifecycleProviders.d.ts +0 -0
  1313. /package/dist/{configurator/configurator-context → react-sdk/preset-selection}/PresetSelectionProvider.d.ts +0 -0
@@ -0,0 +1,1858 @@
1
+ # Kestrel Kettle
2
+
3
+ Sell a small product from one calm page that looks like the shop's own. A specialty-coffee shop, Aldermoor Coffee, sells its Kestrel pour-over kettle in three finishes, two handle woods and with or without a thermometer lid. The page reads like an editorial product page: the kettle on the left, a quiet column on the right with the name, the story, three rows of choices, the price and **Add to cart**, and the shop's promises in a thin strip at the bottom. On a phone the page opens on the shop's own start screen, "Make it yours", and then shows the kettle above one scrolling column. The project writes the page as one layout element; the spec holds the product, its prices, the rule between finish and wood, and the cart action.
4
+
5
+ - [Try it](#try-it)
6
+ - [What the example demonstrates](#what-the-example-demonstrates)
7
+ - [One page over the scene](#one-page-over-the-scene)
8
+ - [Choices from the spec](#choices-from-the-spec)
9
+ - [A rule between two choices](#a-rule-between-two-choices)
10
+ - [Add to cart](#add-to-cart)
11
+ - [The phone's start screen](#the-phones-start-screen)
12
+ - [The shop's footer and the Powered by mark](#the-shops-footer-and-the-powered-by-mark)
13
+ - [Texts from the spec](#texts-from-the-spec)
14
+ - [The stage and the model](#the-stage-and-the-model)
15
+ - [Test cases](#test-cases)
16
+ - [What this layout leaves out](#what-this-layout-leaves-out)
17
+ - [Related pages](#related-pages)
18
+ - [Complete Implementation](#complete-implementation)
19
+
20
+ ## Try it
21
+
22
+ The phone version is under [The phone's start screen](#the-phones-start-screen).
23
+
24
+ ## What the example demonstrates
25
+
26
+ [Custom Layout](?path=/docs/layouts-custom-layout--docs) explains how a project layout works: the element name, the scene, the safe area and the hooks. This page is a finished design built the same way, for a single-page product with no steps or tabs, and it shows the pieces Custom Layout does not use:
27
+
28
+ | Piece | Where |
29
+ | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
30
+ | `phx.frontend.useAttributeSwitch()` for an on/off choice | `ThermometerRow`, [Choices from the spec](#choices-from-the-spec) |
31
+ | `LayoutSlots.Services` with the built-in snackbars in `DesktopSnackbarsRoot` and `MobileSnackbarsRoot` | [A rule between two choices](#a-rule-between-two-choices) |
32
+ | `phx.frontend.useFinalizeActions()` for the spec's `addToCart` action | `CartBlock`, [Add to cart](#add-to-cart) |
33
+ | `phx.frontend.usePreview()` with the layout's own start screen, and `phx.frontend.useCloseAction()` | `PhonePoster`, `PhonePage`, [The phone's start screen](#the-phones-start-screen) |
34
+ | `phx.frontend.createLayoutFooter` with `LayoutSlots.DesktopFooter` and `MobileFooter` | [The shop's footer](#the-shops-footer-and-the-powered-by-mark) |
35
+ | `LayoutSlots.DesktopPoweredBy` and `MobilePoweredBy` | the footer strip and the end of the phone's column |
36
+ | `phx.frontend.useLocalizable()` and `LocalizableMessage` | `ProductHeading`, [Texts from the spec](#texts-from-the-spec) |
37
+ | A `canvasCustomEnvironment` stage with procedural light and a contact shadow | `KettleStudio`, [The stage and the model](#the-stage-and-the-model) |
38
+
39
+ ## One page over the scene
40
+
41
+ `src/elements/ConfiguratorLayout.tsx` keeps the scene and the services mounted for as long as the configuration is open and chooses what lies over the scene: the start screen on a phone while `phx.frontend.usePreview().isPreview` is set, the phone page, or the desktop page. `phx.frontend.useActiveViewports()` tells desktop from phone by the width of the configurator's container, not the window.
42
+
43
+ ```tsx
44
+ import { Box } from '@mui/material'
45
+
46
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
47
+
48
+ import { phx } from '../../.phoenix/phx.js'
49
+ import { DesktopPage } from '../_shared/DesktopPage.js'
50
+ import { PhonePage } from '../_shared/PhonePage.js'
51
+ import { PhonePoster } from '../_shared/PhonePoster.js'
52
+ import { KESTREL } from '../_shared/tokens.js'
53
+
54
+ // One page, no steps or tabs. The canvas and the services stay mounted the whole time; what lies over the canvas is
55
+ // the phone's start screen, the phone page or the desktop page. Each calls `useSceneSafeArea` itself, so only the one
56
+ // on screen tells the camera where the kettle goes.
57
+ const ConfiguratorLayout = () => {
58
+ // `null` until the container has been measured; only the scene shows until then
59
+ const viewports = phx.frontend.useActiveViewports()
60
+ const { isPreview } = phx.frontend.usePreview()
61
+ const isDesktop = viewports?.includes('desktop') ?? false
62
+
63
+ return (
64
+ <Box component="div" sx={{ position: 'absolute', inset: 0, overflow: 'clip', bgcolor: KESTREL.oat }}>
65
+ <LayoutSlots.Services />
66
+ <LayoutSlots.SharedCanvas />
67
+ {viewports !== null && (isPreview ? <PhonePoster /> : isDesktop ? <DesktopPage /> : <PhonePage />)}
68
+ </Box>
69
+ )
70
+ }
71
+
72
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
73
+ ```
74
+
75
+ - **Each arrangement measures its own safe area.** `DesktopPage`, `PhonePage` and `PhonePoster` each call `phx.frontend.useSceneSafeArea()` and attach `safeAreaRef` to a box inside the free area, inset from its edges. The camera fits the kettle into that box, so the inset is the breathing room around the product. Only the arrangement on screen is mounted, so only one of them steers the camera.
76
+ - **The camera fits the product, it does not use a fixed distance.** Both `fitRootPerspectiveCamera` instances leave `distance` out and set `fitToBox: true`. A `distance` overrides the fit, and the kettle is then as large on a 390-pixel phone as on a desktop.
77
+ - **Fullscreen** removes the column and the footer, so the free area, and the kettle with it, takes the whole canvas. The button sets the flag with `phx.frontend.useSetFullscreen()`; the layout reads it with `phx.frontend.useIsFullscreenActive()`. Like the built-in fullscreen button, it records `FrontendAnalyticsFactory.FullScreenModeToggled()` from `@salsita-ai/sdk/configurator` through `phx.frontend.useAnalytics().push()`, on entering and on leaving.
78
+
79
+ ## Choices from the spec
80
+
81
+ The three choices are plain spec components on the root entity. The layout decides how they look: round swatches for the finish and the wood, a switch for the thermometer lid.
82
+
83
+ ```yaml
84
+ components:
85
+ Kettle:
86
+ attributeSelection:
87
+ bodyFinish:
88
+ value:
89
+ $bind: bodyFinish
90
+ options:
91
+ - label: Brushed steel
92
+ description: Satin stainless that hides fingerprints
93
+ value: BrushedSteel
94
+ - label: Matte black
95
+ description: A soft powder coat
96
+ value: MatteBlack
97
+ - label: Copper
98
+ description: Lacquered copper, warm in the light
99
+ value: Copper
100
+ handleWood:
101
+ value:
102
+ $bind: handleWood
103
+ options:
104
+ - label: Walnut
105
+ description: Dark and oiled
106
+ value: Walnut
107
+ - label: Oak
108
+ description: Pale and matte
109
+ value: Oak
110
+ attributeSwitch:
111
+ thermometer:
112
+ value:
113
+ $bind: thermometer
114
+ ```
115
+
116
+ `SwatchRow` draws one `attributeSelection` with `phx.frontend.useAttributeSelection(kettleId, instanceName)`: a `radiogroup` of round buttons, the chosen option's `title` beside the label and its `description` below. The colours of the swatches are the layout's, keyed by the option `value`; the spec's `attributeSelection` carries no label either, so "Body finish" and "Handle" are the layout's text too. The arrow keys move the selection within a row.
117
+
118
+ An `attributeSwitch` is a boolean. `phx.frontend.useAttributeSwitch(kettleId, 'thermometer')` returns `state.value` and `onChange()`, which writes the opposite value, so it fits a switch directly:
119
+
120
+ ```tsx
121
+ import { Box, Switch, Typography } from '@mui/material'
122
+
123
+ import { phx } from '../../.phoenix/phx.js'
124
+ import { KESTREL, LABEL_SX } from './tokens.js'
125
+
126
+ interface ThermometerRowProps {
127
+ readonly readOnly: boolean
128
+ }
129
+
130
+ // The spec's `attributeSwitch` as a labelled switch: on, the lid carries a dial thermometer; off, a plain wooden knob
131
+ export const ThermometerRow = ({ readOnly }: ThermometerRowProps) => {
132
+ const kettleId = phx.frontend.useRootEntityId()
133
+ const thermometer = phx.frontend.useAttributeSwitch(kettleId, 'thermometer')
134
+ const isOn = thermometer.state.value
135
+
136
+ return (
137
+ <Box component="section" sx={{ display: 'grid', gap: 0.5, paddingBlock: 2 }}>
138
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2 }}>
139
+ <Typography component="h3" id="kestrel-thermometer-label" sx={LABEL_SX}>
140
+ Thermometer lid
141
+ </Typography>
142
+ <Switch
143
+ checked={isOn}
144
+ disabled={readOnly || thermometer.disabled}
145
+ onChange={thermometer.onChange}
146
+ inputProps={{ 'aria-labelledby': 'kestrel-thermometer-label' }}
147
+ sx={{
148
+ '& .MuiSwitch-switchBase.Mui-checked': { color: KESTREL.oat },
149
+ '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { bgcolor: KESTREL.copper, opacity: 1 },
150
+ '& .MuiSwitch-track': { bgcolor: KESTREL.hairline, opacity: 1 },
151
+ }}
152
+ />
153
+ </Box>
154
+ <Typography sx={{ fontSize: 13, color: KESTREL.muted }}>
155
+ {isOn ? 'A dial in the lid shows when the water is ready to pour.' : 'A plain lid with a wooden knob.'}
156
+ </Typography>
157
+ </Box>
158
+ )
159
+ }
160
+ ```
161
+
162
+ The choices change the scene through the spec, not through the layout. A material override recolours the `Body` material from expressions in `src/expressions/kettle.ts`, which also add each choice's surcharge to `$price`, and the switch shows the dial or the knob:
163
+
164
+ ```yaml
165
+ components:
166
+ Kettle:
167
+ sceneEntityObjectProperties:
168
+ knob:
169
+ visible:
170
+ $read: $plainKnob
171
+ thermometerDial:
172
+ visible:
173
+ $read: thermometer
174
+ sceneEntityLocalMaterialOverride:
175
+ body:
176
+ materialsToOverride: [Body]
177
+ materialType: physical
178
+ color:
179
+ $read: $bodyColor
180
+ metalness:
181
+ $read: $bodyMetalness
182
+ roughness:
183
+ $read: $bodyRoughness
184
+ clearcoat:
185
+ $read: $bodyClearcoat
186
+ clearcoatRoughness: 0.15
187
+ ```
188
+
189
+ ## A rule between two choices
190
+
191
+ The copper body is sold only with the walnut handle. The rule is an invariant: its message and severity are in the spec, its condition in `src/invariants/kettle.ts`.
192
+
193
+ ```yaml
194
+ invariants:
195
+ Kettle:
196
+ copperNeedsWalnut:
197
+ type: copperNeedsWalnut
198
+ severity: fixable
199
+ message: The copper body comes only with the walnut handle.
200
+ ```
201
+
202
+ ```ts
203
+ import { phx } from '../../.phoenix/phx.js'
204
+
205
+ // The copper body is sold only with the walnut handle. The spec marks the violation `fixable`, so a change that breaks
206
+ // it is rejected and the built-in snackbar shows the spec's message.
207
+ export default phx.domain.implementCustomInvariants({
208
+ Kettle: {
209
+ copperNeedsWalnut: s => {
210
+ return s.bodyFinish !== 'Copper' || s.handleWood === 'Walnut'
211
+ },
212
+ },
213
+ })
214
+ ```
215
+
216
+ The customer sees the rule twice:
217
+
218
+ - **Before choosing.** While the handle is oak, the control hook marks the copper option `disabled` with `hint` set to the invariant's message. `SwatchRow` fades the swatch, sets `aria-disabled` and shows the hint below the row; while the body is copper, the oak swatch is faded the same way.
219
+ - **After choosing anyway.** The faded swatch stays clickable and calls the option's `onSelect()`. A `fixable` violation rejects the change, the kettle keeps its finish, and `LayoutSlots.Services` raises the built-in snackbar "Kettle-1: The copper body comes only with the walnut handle." The built-in snackbar puts the entity id before the message.
220
+
221
+ The snackbars render where the layout mounts a root. On a desktop `LayoutSlots.DesktopSnackbarsRoot` is a zero-height element at the bottom left of the free area, and the snackbars stack upwards from it. On a phone `LayoutSlots.MobileSnackbarsRoot` leaves them fixed to the viewport; `PhonePage` places them below its top bar by styling `notistackSnackbarClasses.container` from `@salsita-ai/sdk/ui`. Mount the snackbars or `phx.frontend.useConfiguratorMessages()`, not both, see [Custom Layout → Show messages](?path=/docs/layouts-custom-layout--docs#show-messages) for the other way.
222
+
223
+ Passing the violation type to the hook's third argument, `fixableViolations`, does not enable the option: it only drops the violation from `hint`. A layout that wants the option clickable calls `onSelect()` on the disabled option, as `SwatchRow` does.
224
+
225
+ ## Add to cart
226
+
227
+ The spec declares one finalize action. Its handler, `src/handlers/add-to-cart.ts`, stands in for the shop's cart: it waits, then enters the `added` navigation state.
228
+
229
+ ```yaml
230
+ navigationStates:
231
+ - configure
232
+ - added
233
+ ```
234
+
235
+ ```yaml
236
+ components:
237
+ Kettle:
238
+ finalizeAction:
239
+ addToCart:
240
+ variant: primary
241
+ label: Add to cart
242
+ title: Add the kettle as configured to the cart
243
+ icon: ShoppingBag
244
+ handler: addToCart
245
+ ```
246
+
247
+ ```ts
248
+ import { useCallback } from 'react'
249
+
250
+ import { phx } from '../../.phoenix/phx.js'
251
+
252
+ // Stands in for the shop's cart: adding takes a moment, then the page shows the confirmation
253
+ export default phx.frontend.createPhoenixHandler('addToCart', () => {
254
+ const navigate = phx.frontend.useNavigate()
255
+
256
+ return {
257
+ handler: useCallback(async () => {
258
+ await new Promise(resolve => setTimeout(resolve, 1200))
259
+ navigate('added')
260
+ }, [navigate]),
261
+ }
262
+ })
263
+ ```
264
+
265
+ `CartBlock` shows the price from `phx.frontend.useRootEntityPrice()` and runs the action from `phx.frontend.useFinalizeActions().primary`. The hook runs the handler beside the layout, so the pending state survives the block unmounting, for example in fullscreen. In the `added` state the block confirms the purchase and **Make another** returns to `configure`; `KettleOptions` keeps the choices as they were added until then. A viewer of a shared configuration sees the price and no button, because neither hook checks read mode. `DesktopPage` keeps the block at the bottom of the column with `position: sticky`, so the button stays in view when a short window makes the column scroll.
266
+
267
+ ```tsx
268
+ import { Alert, Box, Button, CircularProgress, Typography } from '@mui/material'
269
+
270
+ import { phx } from '../../.phoenix/phx.js'
271
+ import { KESTREL } from './tokens.js'
272
+
273
+ const CHECK_ICON = 'M5 12.5 10 17.5 19 7'
274
+
275
+ // The price and the spec's `addToCart` finalize action. `useFinalizeActions` runs the action's handler beside the
276
+ // layout, so its pending state survives this block unmounting, as it does in fullscreen. The handler moves to the
277
+ // `added` navigation state, where the block confirms the purchase instead. A viewer sees the price only.
278
+ export const CartBlock = () => {
279
+ const price = phx.frontend.useRootEntityPrice()
280
+ const { primary, hints } = phx.frontend.useFinalizeActions()
281
+ const navigationState = phx.frontend.useActiveNavigationState()
282
+ const navigate = phx.frontend.useNavigate()
283
+ const { accessInfo } = phx.frontend.useAccessService()
284
+ const isPending = primary?.isPending ?? false
285
+
286
+ if (navigationState === 'added') {
287
+ return (
288
+ <Box component="div" role="status" sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
289
+ <Box
290
+ component="svg"
291
+ viewBox="0 0 24 24"
292
+ aria-hidden
293
+ sx={{ inlineSize: 40, blockSize: 40, flex: 'none', padding: 1, borderRadius: '50%', bgcolor: KESTREL.sage }}
294
+ >
295
+ <path d={CHECK_ICON} fill="none" stroke={KESTREL.oat} strokeWidth={2.4} strokeLinecap="round" />
296
+ </Box>
297
+ <Box component="div" sx={{ display: 'grid', flex: 1 }}>
298
+ <Typography sx={{ fontFamily: KESTREL.display, fontSize: 20, color: KESTREL.charcoal }}>
299
+ In your cart
300
+ </Typography>
301
+ <Typography sx={{ fontSize: 13, color: KESTREL.muted }}>Kestrel, {price}</Typography>
302
+ </Box>
303
+ <Button
304
+ onClick={() => navigate('configure')}
305
+ sx={{ textTransform: 'none', color: KESTREL.charcoal, textDecoration: 'underline', fontSize: 14 }}
306
+ >
307
+ Make another
308
+ </Button>
309
+ </Box>
310
+ )
311
+ }
312
+
313
+ const showButton = primary !== null && !accessInfo.viewMode
314
+
315
+ return (
316
+ <Box component="div" sx={{ display: 'grid', gap: 1.5 }}>
317
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2 }}>
318
+ <Box component="div" sx={{ display: 'grid' }}>
319
+ <Typography sx={{ fontFamily: KESTREL.display, fontSize: 30, lineHeight: 1.1, color: KESTREL.charcoal }}>
320
+ {price}
321
+ </Typography>
322
+ <Typography sx={{ fontSize: 12, color: KESTREL.muted, whiteSpace: 'nowrap' }}>Ships in two days</Typography>
323
+ </Box>
324
+ {showButton && (
325
+ <Button
326
+ variant="contained"
327
+ disableElevation
328
+ disabled={primary.disabled || isPending}
329
+ onClick={() => void primary.run()}
330
+ title={primary.title}
331
+ startIcon={isPending ? <CircularProgress size={16} color="inherit" /> : undefined}
332
+ sx={{
333
+ minBlockSize: 52,
334
+ paddingInline: 4.5,
335
+ borderRadius: 999,
336
+ bgcolor: KESTREL.charcoal,
337
+ color: KESTREL.oat,
338
+ fontFamily: KESTREL.body,
339
+ fontSize: 15,
340
+ letterSpacing: '0.02em',
341
+ textTransform: 'none',
342
+ '&:hover': { bgcolor: '#000000' },
343
+ '&.Mui-disabled': { bgcolor: KESTREL.charcoal, color: KESTREL.oat, opacity: 0.55 },
344
+ }}
345
+ >
346
+ {isPending ? 'Adding…' : primary.label}
347
+ </Button>
348
+ )}
349
+ </Box>
350
+ {showButton && primary.disabled && hints && (
351
+ <Typography sx={{ fontSize: 13, color: KESTREL.muted }}>{hints}</Typography>
352
+ )}
353
+ {primary?.error && <Alert severity="error">The kettle could not be added: {primary.error.message}</Alert>}
354
+ </Box>
355
+ )
356
+ }
357
+ ```
358
+
359
+ ## The phone's start screen
360
+
361
+ `preview: auto` at the top of the spec asks for a start screen when the configurator's container is phone-sized. The built-in layout shows `MobilePreview`; a project layout shows its own while `phx.frontend.usePreview().isPreview` is set, and calls `enter()` to open the page. The poster frames the kettle in the area above its text with its own `useSceneSafeArea()`.
362
+
363
+ ```yaml
364
+ preview: auto
365
+ ```
366
+
367
+ The same layout in a frame 390 pixels wide, as on a phone. It opens on the start screen; **Start designing** opens the page, and the close button at the top left returns to the start screen. Opened on its own from the sidebar, the **Phone** story sets Storybook's viewport to 390 × 844.
368
+
369
+ ```tsx
370
+ import { Box, Button, Typography } from '@mui/material'
371
+
372
+ import { phx } from '../../.phoenix/phx.js'
373
+ import { KESTREL, LABEL_SX } from './tokens.js'
374
+
375
+ // The layout's own start screen, shown on a phone while `usePreview().isPreview` is set (the spec's `preview: auto`).
376
+ // It frames the kettle in the area above the text with its own safe area; `enter()` opens the page.
377
+ export const PhonePoster = () => {
378
+ const { containerRef, safeAreaRef } = phx.frontend.useSceneSafeArea()
379
+ const { enter } = phx.frontend.usePreview()
380
+ const price = phx.frontend.useRootEntityPrice()
381
+
382
+ return (
383
+ <Box
384
+ component="div"
385
+ ref={containerRef}
386
+ sx={{
387
+ position: 'absolute',
388
+ inset: 0,
389
+ display: 'flex',
390
+ flexDirection: 'column',
391
+ fontFamily: KESTREL.body,
392
+ pointerEvents: 'none',
393
+ }}
394
+ >
395
+ <Typography
396
+ sx={{
397
+ paddingBlockStart: 3,
398
+ textAlign: 'center',
399
+ fontFamily: KESTREL.display,
400
+ fontSize: 20,
401
+ color: KESTREL.charcoal,
402
+ }}
403
+ >
404
+ Aldermoor
405
+ </Typography>
406
+ <Box component="div" ref={safeAreaRef} sx={{ flex: '1 1 0', minBlockSize: 0, marginInline: 3 }} />
407
+ <Box component="div" sx={{ display: 'grid', gap: 2, padding: 3, paddingBlockEnd: 4, pointerEvents: 'auto' }}>
408
+ <Typography sx={{ ...LABEL_SX, color: KESTREL.copper }}>The Kestrel pour-over kettle</Typography>
409
+ <Typography
410
+ component="h1"
411
+ sx={{
412
+ fontFamily: KESTREL.display,
413
+ fontSize: 48,
414
+ lineHeight: 1,
415
+ letterSpacing: '-0.01em',
416
+ color: KESTREL.charcoal,
417
+ }}
418
+ >
419
+ Make it yours
420
+ </Typography>
421
+ <Typography sx={{ fontSize: 15, lineHeight: 1.6, color: KESTREL.muted }}>
422
+ Three finishes, two woods and a thermometer lid if you want one. As shown, {price}.
423
+ </Typography>
424
+ <Button
425
+ variant="contained"
426
+ disableElevation
427
+ onClick={enter}
428
+ sx={{
429
+ marginBlockStart: 1,
430
+ minBlockSize: 52,
431
+ borderRadius: 999,
432
+ bgcolor: KESTREL.charcoal,
433
+ color: KESTREL.oat,
434
+ fontFamily: KESTREL.body,
435
+ fontSize: 15,
436
+ textTransform: 'none',
437
+ '&:hover': { bgcolor: '#000000' },
438
+ }}
439
+ >
440
+ Start designing
441
+ </Button>
442
+ </Box>
443
+ </Box>
444
+ )
445
+ }
446
+ ```
447
+
448
+ On a phone, `enter()` also expands the configurator, which `usePreview().isExpanded` reports. `PhonePage` offers one close button at the top left: the host's close action from `phx.frontend.useCloseAction()` when the integration provides one, otherwise `usePreview().leave()`, which returns to the start screen. Storybook provides no close action, so here the button returns to the start screen; with neither, the button is not shown.
449
+
450
+ ## The shop's footer and the Powered by mark
451
+
452
+ `LayoutSlots.DesktopFooter` and `LayoutSlots.MobileFooter` render the project's `LayoutFooter` element, registered with `phx.frontend.createLayoutFooter`, and nothing when there is none. The desktop page mounts it in the footer strip, with `LayoutSlots.DesktopPoweredBy` at the strip's right end; the phone page mounts `MobileFooter` and `MobilePoweredBy` at the end of its column.
453
+
454
+ ```tsx
455
+ import { Box } from '@mui/material'
456
+
457
+ import { phx } from '../../.phoenix/phx.js'
458
+ import { KESTREL } from '../_shared/tokens.js'
459
+
460
+ const PROMISES = ['Free delivery over $75', 'Two-year warranty', '30-day returns']
461
+
462
+ // The shop's promises. `createLayoutFooter` registers it as the `LayoutFooter` element, which the layout shows where it
463
+ // mounts `LayoutSlots.DesktopFooter` or `LayoutSlots.MobileFooter`.
464
+ const LayoutFooter = () => {
465
+ return (
466
+ <Box
467
+ component="ul"
468
+ sx={{
469
+ display: 'flex',
470
+ flexWrap: 'wrap',
471
+ columnGap: 3,
472
+ rowGap: 0.5,
473
+ margin: 0,
474
+ padding: 0,
475
+ listStyle: 'none',
476
+ fontSize: 12,
477
+ letterSpacing: '0.04em',
478
+ color: KESTREL.muted,
479
+ }}
480
+ >
481
+ {PROMISES.map(promise => (
482
+ <Box
483
+ component="li"
484
+ key={promise}
485
+ sx={{ display: 'flex', alignItems: 'center', gap: 1, '&::before': { content: '"·"', color: KESTREL.sage } }}
486
+ >
487
+ {promise}
488
+ </Box>
489
+ ))}
490
+ </Box>
491
+ )
492
+ }
493
+
494
+ export default phx.frontend.createLayoutFooter(LayoutFooter)
495
+ ```
496
+
497
+ ## Texts from the spec
498
+
499
+ The `detail` component holds the name, the subtitle and the story. Its fields are `Localizable`, not `string`. `ProductHeading` resolves the title and subtitle with `phx.frontend.useLocalizable()` and renders the description in place with `LocalizableMessage` from `@salsita-ai/sdk/react`; `SwatchRow` resolves a list of option titles with `phx.frontend.useResolveLocalizable()`. See [Localization](?path=/docs/phoenix-localization--docs).
500
+
501
+ ```yaml
502
+ components:
503
+ Kettle:
504
+ detail:
505
+ main:
506
+ title: Kestrel
507
+ subtitle: Pour-over kettle, 0.9 litres
508
+ ```
509
+
510
+ ```tsx
511
+ import { Box, Typography } from '@mui/material'
512
+
513
+ import { detailComponent } from '@salsita-ai/sdk/domain'
514
+ import { LocalizableMessage } from '@salsita-ai/sdk/react'
515
+
516
+ import { phx } from '../../.phoenix/phx.js'
517
+ import { KESTREL, LABEL_SX } from './tokens.js'
518
+
519
+ interface ProductHeadingProps {
520
+ readonly size: 'large' | 'small'
521
+ }
522
+
523
+ // The overline, the name and the story from the spec's `detail` component. Its texts are `Localizable`:
524
+ // `useLocalizable` resolves one into a string and `LocalizableMessage` renders one in place.
525
+ export const ProductHeading = ({ size }: ProductHeadingProps) => {
526
+ const detail = phx.frontend.useFirstRootComponent(detailComponent)
527
+ const title = phx.frontend.useLocalizable(detail?.state.title)
528
+ const subtitle = phx.frontend.useLocalizable(detail?.state.subtitle)
529
+
530
+ return (
531
+ <Box component="header" sx={{ display: 'grid', gap: size === 'large' ? 2 : 1.5 }}>
532
+ <Typography sx={{ ...LABEL_SX, color: KESTREL.copper }}>Aldermoor Coffee</Typography>
533
+ <Box component="div" sx={{ display: 'grid', gap: 0.75 }}>
534
+ <Typography
535
+ component="h1"
536
+ sx={{
537
+ fontFamily: KESTREL.display,
538
+ fontSize: size === 'large' ? 60 : 40,
539
+ lineHeight: 1,
540
+ letterSpacing: '-0.01em',
541
+ color: KESTREL.charcoal,
542
+ }}
543
+ >
544
+ {title}
545
+ </Typography>
546
+ <Typography sx={{ fontFamily: KESTREL.body, fontSize: 15, color: KESTREL.muted }}>{subtitle}</Typography>
547
+ </Box>
548
+ <Typography sx={{ fontFamily: KESTREL.body, fontSize: 15, lineHeight: 1.65, color: KESTREL.charcoal }}>
549
+ <LocalizableMessage>{detail?.state.description}</LocalizableMessage>
550
+ </Typography>
551
+ </Box>
552
+ )
553
+ }
554
+ ```
555
+
556
+ ## The stage and the model
557
+
558
+ The spec's `canvasCustomEnvironment` names `KettleStudio`, a layout element rendered inside the scene. It paints the page's oat colour as the scene's background, so the scene and the column read as one surface, lights the kettle with drei's `Lightformer` panels, which show only in the reflections and need no image download, and grounds it with a `ContactShadows` plane just below its base. The scene is in millimetres.
559
+
560
+ ```tsx
561
+ import { ContactShadows, Environment, Lightformer } from '@react-three/drei'
562
+
563
+ import { phx } from '../../.phoenix/phx.js'
564
+ import { KESTREL } from '../_shared/tokens.js'
565
+
566
+ // The stage named by the spec's `canvasCustomEnvironment`: a backdrop, a soft shadow under the kettle and a studio of
567
+ // light panels. The panels exist only in the reflections, so the metal finishes have something to mirror and no image
568
+ // has to be downloaded. The scene is in millimetres.
569
+ export default phx.frontend.createCustomPhoenixLayoutElement('KettleStudio', () => {
570
+ return (
571
+ <>
572
+ {/* The page's oat background, so the scene and the layout read as one surface */}
573
+ <color attach="background" args={[KESTREL.oat]} />
574
+ <ambientLight intensity={0.35} />
575
+ <directionalLight position={[400, 900, 600]} intensity={1.1} />
576
+
577
+ <Environment resolution={256} frames={1}>
578
+ <color attach="background" args={['#77706a']} />
579
+ {/* A softbox above, tall strips at the sides for the long highlights, a warm fill behind, a dim one in front */}
580
+ <Lightformer form="rect" intensity={2.4} position={[0, 6, 0]} rotation-x={Math.PI / 2} scale={[10, 6, 1]} />
581
+ <Lightformer form="rect" intensity={3} position={[-6, 1, 2]} rotation-y={Math.PI / 2} scale={[1.2, 8, 1]} />
582
+ <Lightformer form="rect" intensity={1.6} position={[6, 1, 3]} rotation-y={-Math.PI / 2} scale={[1.2, 8, 1]} />
583
+ <Lightformer form="rect" color="#f3d9c2" intensity={1} position={[0, 1, -8]} scale={[12, 4, 1]} />
584
+ <Lightformer form="rect" intensity={0.8} position={[0, 0, 8]} rotation-y={Math.PI} scale={[10, 3, 1]} />
585
+ </Environment>
586
+
587
+ <ContactShadows position={[0, -1, 0]} scale={520} far={60} blur={2.2} opacity={0.7} resolution={512} />
588
+ </>
589
+ )
590
+ })
591
+ ```
592
+
593
+ The kettle is `public/models/gallery/kettle.glb`, generated by `scripts/models/kettle.ts` in the Storybook package from three.js geometry: lathed body, lid, base ring and knob, a gooseneck spout and a flat handle swept along curves, and a dial with ticks and a needle. Each part is a named node the spec loads with `sceneEntityRemoteObject.<name>.objectName`; the parts that change with a choice carry the `Body` and `Handle` materials the overrides target. The script and its helper live in `scripts/models/`, outside the example's `src/`, because every file under `src/` is part of this page.
594
+
595
+ ## Test cases
596
+
597
+ - The kettle stands on the left of the page, centred in the free area beside the column, with a soft shadow below it. The column shows "Aldermoor Coffee", **Kestrel**, the subtitle, the story, the three choices, **$175.00** and **Add to cart**; the footer strip shows the three promises and the Powered by mark.
598
+ - **Matte black** turns the body, lid and spout black and the price to $185.00; **Copper** turns them copper at $220.00. The chosen swatch has a ring and its name and description change.
599
+ - **Oak** turns the handle and, without the thermometer, the knob pale. The price drops by $10.
600
+ - With **Oak** chosen, the **Copper** swatch is faded and "The copper body comes only with the walnut handle." is shown below the finishes. Clicking it keeps the finish and shows the snackbar "Kettle-1: The copper body comes only with the walnut handle." at the bottom left of the free area.
601
+ - With **Copper** chosen, the **Oak** swatch is faded and the same sentence is shown below the handles.
602
+ - Turning **Thermometer lid** off replaces the dial with a wooden knob and lowers the price by $20; turning it on brings the dial back.
603
+ - Tab reaches the chosen swatch of each row, and the arrow keys move the selection, skipping a faded swatch.
604
+ - **Add to cart** shows a spinner and "Adding…" for about a second, then "In your cart" with the price; the choices cannot be changed until **Make another**, which brings the button back.
605
+ - **Fullscreen** removes the column and the footer, and the kettle moves to the centre of the canvas; **Exit fullscreen** brings both back.
606
+ - Clicking **Fullscreen** and **Exit fullscreen** each pushes the `fullscreenButton` user-action event, as an `AnalyticsService.push` line in the browser console shows with its Verbose level enabled: without a Google Tag Manager id, Storybook's analytics log their events with `console.debug`.
607
+ - In a window too short for the column, the column scrolls and the price with **Add to cart** stays at its bottom edge.
608
+ - Dragging in the free area turns the kettle.
609
+ - In the **Phone** story the start screen shows the kettle above "Make it yours" and **Start designing**. **Start designing** opens the page: the kettle at the top, the column below it and the price with **Add to cart** in a bar at the bottom of the screen.
610
+ - On the phone, the column scrolls under the kettle and ends with the promises and the Powered by mark; the bar with the price stays.
611
+ - On the phone, the snackbar of the copper rule appears below the top bar.
612
+ - On the phone, the close button at the top left returns to the start screen.
613
+ - The browser console shows no errors.
614
+
615
+ ## What this layout leaves out
616
+
617
+ - **Undo and redo, sharing, measurements and the language switch.** The page has none of the toolbar's actions. A layout adds undo and redo with `phx.frontend.useUndoRedo()`, see [Configurator Interface → Hooks for a Project Layout](?path=/docs/phoenix-configurator-interface--docs#hooks-for-a-project-layout).
618
+ - **Read mode.** The layout hides **Add to cart** and makes the choices inert 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.
619
+ - **Messages in the layout's own UI.** The rejected change is a built-in snackbar; a layout that wants its own toast uses `phx.frontend.useConfiguratorMessages()` instead.
620
+ - **The built-in arrangement.** Header, sidebar, sidebar footer, tabs, tool controls, view controls and the built-in `DesktopPreview` and `MobilePreview` are not mounted; this page draws its own. [Layout Slots](?path=/docs/phoenix-layout-slots--docs) lists every slot a project layout can mount.
621
+
622
+ ## Related pages
623
+
624
+ - [Custom Layout](?path=/docs/layouts-custom-layout--docs) explains a project layout step by step.
625
+ - [Configurator Interface → Hooks for a Project Layout](?path=/docs/phoenix-configurator-interface--docs#hooks-for-a-project-layout) lists every hook used here.
626
+ - [Layout Slots](?path=/docs/phoenix-layout-slots--docs) describes `Services`, the snackbar roots, the footers and the Powered by mark.
627
+ - [Preview / Auto](?path=/docs/layouts-preview-auto--docs) shows the built-in start screen that `preview: auto` opens.
628
+
629
+ ## Complete Implementation
630
+
631
+ {/* AUTO-GENERATED SECTION: This section is automatically updated by 'phoenix story build' */}
632
+
633
+ <details>
634
+ <summary>Click to view the complete implementation files</summary>
635
+
636
+ ### ./spec/domain.yaml
637
+
638
+ ```yaml
639
+ preview: auto
640
+
641
+ model:
642
+ latest:
643
+ entityTypes:
644
+ - Kettle
645
+ aliases:
646
+ RootEntity:
647
+ - Kettle
648
+ commonTypes:
649
+ BodyFinish:
650
+ enum:
651
+ - BrushedSteel
652
+ - MatteBlack
653
+ - Copper
654
+ HandleWood:
655
+ enum:
656
+ - Walnut
657
+ - Oak
658
+ shapes:
659
+ Kettle:
660
+ bodyFinish:
661
+ $ref: '#/model/latest/commonTypes/BodyFinish'
662
+ handleWood:
663
+ $ref: '#/model/latest/commonTypes/HandleWood'
664
+ thermometer:
665
+ type: boolean
666
+
667
+ presets:
668
+ - rootEntityType: Kettle
669
+ initialDomainEntities:
670
+ - id: Kettle-1
671
+ type: Kettle
672
+ bodyFinish: BrushedSteel
673
+ handleWood: Walnut
674
+ thermometer: true
675
+
676
+ navigationStates:
677
+ - configure
678
+ - added
679
+
680
+ invariants:
681
+ Kettle:
682
+ copperNeedsWalnut:
683
+ type: copperNeedsWalnut
684
+ severity: fixable
685
+ message: The copper body comes only with the walnut handle.
686
+
687
+ components:
688
+ Kettle:
689
+ detail:
690
+ main:
691
+ title: Kestrel
692
+ subtitle: Pour-over kettle, 0.9 litres
693
+ description: A gooseneck kettle for slow, even pours. The spout narrows to a steady thread of water, and the dial in the lid tells you when it has cooled to brewing temperature.
694
+ price:
695
+ main:
696
+ price:
697
+ $read: $price
698
+ attributeSelection:
699
+ bodyFinish:
700
+ value:
701
+ $bind: bodyFinish
702
+ options:
703
+ - label: Brushed steel
704
+ description: Satin stainless that hides fingerprints
705
+ value: BrushedSteel
706
+ - label: Matte black
707
+ description: A soft powder coat
708
+ value: MatteBlack
709
+ - label: Copper
710
+ description: Lacquered copper, warm in the light
711
+ value: Copper
712
+ handleWood:
713
+ value:
714
+ $bind: handleWood
715
+ options:
716
+ - label: Walnut
717
+ description: Dark and oiled
718
+ value: Walnut
719
+ - label: Oak
720
+ description: Pale and matte
721
+ value: Oak
722
+ attributeSwitch:
723
+ thermometer:
724
+ value:
725
+ $bind: thermometer
726
+ finalizeAction:
727
+ addToCart:
728
+ variant: primary
729
+ label: Add to cart
730
+ title: Add the kettle as configured to the cart
731
+ icon: ShoppingBag
732
+ handler: addToCart
733
+
734
+ canvasConfig:
735
+ main:
736
+ highlightingDisabled: true
737
+ canvasCustomEnvironment:
738
+ main:
739
+ name: KettleStudio
740
+ fitRootPerspectiveCamera:
741
+ desktop:
742
+ priority: 2
743
+ fov: 30
744
+ near: 10
745
+ far: 5000
746
+ minDistance: 350
747
+ maxDistance: 1400
748
+ azimuthAngle: 0.35
749
+ polarAngle: 1.2
750
+ minPolarAngle: 0.5
751
+ maxPolarAngle: 1.5
752
+ fitToBox: true
753
+ fitMeshChanges: false
754
+ $filter:
755
+ viewports: [desktop]
756
+ phone:
757
+ priority: 1
758
+ fov: 30
759
+ near: 10
760
+ far: 5000
761
+ minDistance: 350
762
+ maxDistance: 1600
763
+ azimuthAngle: 0.35
764
+ polarAngle: 1.2
765
+ minPolarAngle: 0.5
766
+ maxPolarAngle: 1.5
767
+ fitToBox: true
768
+ fitMeshChanges: false
769
+ $filter:
770
+ viewports: [mobile]
771
+
772
+ sceneEntityRemoteObject:
773
+ body:
774
+ fileUrl: /models/gallery/kettle.glb
775
+ objectName: Body
776
+ dimensionUnit: m
777
+ lid:
778
+ fileUrl: /models/gallery/kettle.glb
779
+ objectName: Lid
780
+ dimensionUnit: m
781
+ spout:
782
+ fileUrl: /models/gallery/kettle.glb
783
+ objectName: Spout
784
+ dimensionUnit: m
785
+ baseRing:
786
+ fileUrl: /models/gallery/kettle.glb
787
+ objectName: BaseRing
788
+ dimensionUnit: m
789
+ handle:
790
+ fileUrl: /models/gallery/kettle.glb
791
+ objectName: Handle
792
+ dimensionUnit: m
793
+ handleCollars:
794
+ fileUrl: /models/gallery/kettle.glb
795
+ objectName: HandleCollars
796
+ dimensionUnit: m
797
+ knob:
798
+ fileUrl: /models/gallery/kettle.glb
799
+ objectName: Knob
800
+ dimensionUnit: m
801
+ thermometerDial:
802
+ fileUrl: /models/gallery/kettle.glb
803
+ objectName: ThermometerDial
804
+ dimensionUnit: m
805
+ dialFace:
806
+ fileUrl: /models/gallery/kettle.glb
807
+ objectName: DialFace
808
+ dimensionUnit: m
809
+ dialGlass:
810
+ fileUrl: /models/gallery/kettle.glb
811
+ objectName: DialGlass
812
+ dimensionUnit: m
813
+ sceneEntityObjectProperties:
814
+ knob:
815
+ visible:
816
+ $read: $plainKnob
817
+ thermometerDial:
818
+ visible:
819
+ $read: thermometer
820
+ dialFace:
821
+ visible:
822
+ $read: thermometer
823
+ dialGlass:
824
+ visible:
825
+ $read: thermometer
826
+ sceneEntityLocalMaterialOverride:
827
+ body:
828
+ materialsToOverride: [Body]
829
+ materialType: physical
830
+ color:
831
+ $read: $bodyColor
832
+ metalness:
833
+ $read: $bodyMetalness
834
+ roughness:
835
+ $read: $bodyRoughness
836
+ clearcoat:
837
+ $read: $bodyClearcoat
838
+ clearcoatRoughness: 0.15
839
+ handle:
840
+ materialsToOverride: [Handle]
841
+ color:
842
+ $read: $handleColor
843
+ metalness: 0
844
+ roughness: 0.58
845
+ glass:
846
+ materialsToOverride: [DialGlass]
847
+ materialType: physical
848
+ color: '#ffffff'
849
+ metalness: 0
850
+ roughness: 0.05
851
+ transparent: true
852
+ opacity: 0.18
853
+ ```
854
+
855
+ ### ./src/\_shared/CartBlock.tsx
856
+
857
+ ```tsx
858
+ import { Alert, Box, Button, CircularProgress, Typography } from '@mui/material'
859
+
860
+ import { phx } from '../../.phoenix/phx.js'
861
+ import { KESTREL } from './tokens.js'
862
+
863
+ const CHECK_ICON = 'M5 12.5 10 17.5 19 7'
864
+
865
+ // The price and the spec's `addToCart` finalize action. `useFinalizeActions` runs the action's handler beside the
866
+ // layout, so its pending state survives this block unmounting, as it does in fullscreen. The handler moves to the
867
+ // `added` navigation state, where the block confirms the purchase instead. A viewer sees the price only.
868
+ export const CartBlock = () => {
869
+ const price = phx.frontend.useRootEntityPrice()
870
+ const { primary, hints } = phx.frontend.useFinalizeActions()
871
+ const navigationState = phx.frontend.useActiveNavigationState()
872
+ const navigate = phx.frontend.useNavigate()
873
+ const { accessInfo } = phx.frontend.useAccessService()
874
+ const isPending = primary?.isPending ?? false
875
+
876
+ if (navigationState === 'added') {
877
+ return (
878
+ <Box component="div" role="status" sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
879
+ <Box
880
+ component="svg"
881
+ viewBox="0 0 24 24"
882
+ aria-hidden
883
+ sx={{ inlineSize: 40, blockSize: 40, flex: 'none', padding: 1, borderRadius: '50%', bgcolor: KESTREL.sage }}
884
+ >
885
+ <path d={CHECK_ICON} fill="none" stroke={KESTREL.oat} strokeWidth={2.4} strokeLinecap="round" />
886
+ </Box>
887
+ <Box component="div" sx={{ display: 'grid', flex: 1 }}>
888
+ <Typography sx={{ fontFamily: KESTREL.display, fontSize: 20, color: KESTREL.charcoal }}>
889
+ In your cart
890
+ </Typography>
891
+ <Typography sx={{ fontSize: 13, color: KESTREL.muted }}>Kestrel, {price}</Typography>
892
+ </Box>
893
+ <Button
894
+ onClick={() => navigate('configure')}
895
+ sx={{ textTransform: 'none', color: KESTREL.charcoal, textDecoration: 'underline', fontSize: 14 }}
896
+ >
897
+ Make another
898
+ </Button>
899
+ </Box>
900
+ )
901
+ }
902
+
903
+ const showButton = primary !== null && !accessInfo.viewMode
904
+
905
+ return (
906
+ <Box component="div" sx={{ display: 'grid', gap: 1.5 }}>
907
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2 }}>
908
+ <Box component="div" sx={{ display: 'grid' }}>
909
+ <Typography sx={{ fontFamily: KESTREL.display, fontSize: 30, lineHeight: 1.1, color: KESTREL.charcoal }}>
910
+ {price}
911
+ </Typography>
912
+ <Typography sx={{ fontSize: 12, color: KESTREL.muted, whiteSpace: 'nowrap' }}>Ships in two days</Typography>
913
+ </Box>
914
+ {showButton && (
915
+ <Button
916
+ variant="contained"
917
+ disableElevation
918
+ disabled={primary.disabled || isPending}
919
+ onClick={() => void primary.run()}
920
+ title={primary.title}
921
+ startIcon={isPending ? <CircularProgress size={16} color="inherit" /> : undefined}
922
+ sx={{
923
+ minBlockSize: 52,
924
+ paddingInline: 4.5,
925
+ borderRadius: 999,
926
+ bgcolor: KESTREL.charcoal,
927
+ color: KESTREL.oat,
928
+ fontFamily: KESTREL.body,
929
+ fontSize: 15,
930
+ letterSpacing: '0.02em',
931
+ textTransform: 'none',
932
+ '&:hover': { bgcolor: '#000000' },
933
+ '&.Mui-disabled': { bgcolor: KESTREL.charcoal, color: KESTREL.oat, opacity: 0.55 },
934
+ }}
935
+ >
936
+ {isPending ? 'Adding…' : primary.label}
937
+ </Button>
938
+ )}
939
+ </Box>
940
+ {showButton && primary.disabled && hints && (
941
+ <Typography sx={{ fontSize: 13, color: KESTREL.muted }}>{hints}</Typography>
942
+ )}
943
+ {primary?.error && <Alert severity="error">The kettle could not be added: {primary.error.message}</Alert>}
944
+ </Box>
945
+ )
946
+ }
947
+ ```
948
+
949
+ ### ./src/\_shared/DesktopPage.tsx
950
+
951
+ ```tsx
952
+ import { Box, Typography } from '@mui/material'
953
+
954
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
955
+
956
+ import { phx } from '../../.phoenix/phx.js'
957
+ import { CartBlock } from './CartBlock.js'
958
+ import { FullscreenButton } from './FullscreenButton.js'
959
+ import { KettleOptions } from './KettleOptions.js'
960
+ import { ProductHeading } from './ProductHeading.js'
961
+ import { KESTREL } from './tokens.js'
962
+
963
+ const COLUMN_WIDTH = 'clamp(380px, 38%, 520px)'
964
+ const FOOTER_HEIGHT = 52
965
+ const GUTTER = 32
966
+
967
+ // The desktop page: the kettle in the free area on the left, the product column on the right and the shop's footer
968
+ // strip below both. In fullscreen only the free area stays, so the camera frames the kettle in the whole canvas.
969
+ export const DesktopPage = () => {
970
+ const { containerRef, safeAreaRef } = phx.frontend.useSceneSafeArea()
971
+ const isFullscreen = phx.frontend.useIsFullscreenActive()
972
+ const { accessInfo } = phx.frontend.useAccessService()
973
+
974
+ return (
975
+ <Box
976
+ component="div"
977
+ ref={containerRef}
978
+ sx={{
979
+ position: 'absolute',
980
+ inset: 0,
981
+ display: 'grid',
982
+ gridTemplateColumns: isFullscreen ? 'minmax(0, 1fr)' : `minmax(0, 1fr) ${COLUMN_WIDTH}`,
983
+ gridTemplateRows: isFullscreen ? 'minmax(0, 1fr)' : `minmax(0, 1fr) ${FOOTER_HEIGHT}px`,
984
+ fontFamily: KESTREL.body,
985
+ // The free area lies over the canvas; only the controls in it take the pointer
986
+ pointerEvents: 'none',
987
+ }}
988
+ >
989
+ <Box component="div" sx={{ position: 'relative', minInlineSize: 0 }}>
990
+ {/* The camera fits the kettle into this box, so its inset is the breathing room around the kettle */}
991
+ <Box component="div" ref={safeAreaRef} sx={{ position: 'absolute', inset: '112px 72px 96px' }} />
992
+ <Box
993
+ component="div"
994
+ sx={{ position: 'absolute', insetBlockStart: GUTTER, insetInlineStart: GUTTER, display: 'grid' }}
995
+ >
996
+ <Typography sx={{ fontFamily: KESTREL.display, fontSize: 22, lineHeight: 1, color: KESTREL.charcoal }}>
997
+ Aldermoor
998
+ </Typography>
999
+ </Box>
1000
+ <Box
1001
+ component="div"
1002
+ sx={{ position: 'absolute', insetBlockStart: GUTTER - 8, insetInlineEnd: GUTTER, pointerEvents: 'auto' }}
1003
+ >
1004
+ <FullscreenButton />
1005
+ </Box>
1006
+ <Typography
1007
+ sx={{
1008
+ position: 'absolute',
1009
+ insetBlockEnd: GUTTER,
1010
+ insetInline: 0,
1011
+ textAlign: 'center',
1012
+ fontSize: 12,
1013
+ letterSpacing: '0.08em',
1014
+ color: KESTREL.muted,
1015
+ }}
1016
+ >
1017
+ Drag to turn the kettle
1018
+ </Typography>
1019
+ {/* The built-in snackbars stack upwards from this zero-height root, so it sits where their bottom edge goes */}
1020
+ <Box
1021
+ component="div"
1022
+ sx={{
1023
+ position: 'absolute',
1024
+ insetBlockEnd: GUTTER,
1025
+ insetInlineStart: GUTTER,
1026
+ inlineSize: 340,
1027
+ pointerEvents: 'auto',
1028
+ }}
1029
+ >
1030
+ <LayoutSlots.DesktopSnackbarsRoot />
1031
+ </Box>
1032
+ </Box>
1033
+
1034
+ {!isFullscreen && (
1035
+ <>
1036
+ <Box
1037
+ component="aside"
1038
+ aria-label="Kestrel kettle"
1039
+ sx={{
1040
+ display: 'flex',
1041
+ flexDirection: 'column',
1042
+ overflowY: 'auto',
1043
+ bgcolor: KESTREL.oat,
1044
+ borderInlineStart: `1px solid ${KESTREL.hairline}`,
1045
+ pointerEvents: 'auto',
1046
+ }}
1047
+ >
1048
+ {/* Centred while it fits, scrolling from the top once it does not */}
1049
+ <Box
1050
+ component="div"
1051
+ sx={{ display: 'grid', gap: 3.5, marginBlock: 'auto', paddingInline: 7, paddingBlockStart: 5 }}
1052
+ >
1053
+ <ProductHeading size="large" />
1054
+ <KettleOptions readOnly={accessInfo.viewMode} />
1055
+ {/* Below the choices while the column fits; at the column's bottom edge while it scrolls */}
1056
+ <Box
1057
+ component="div"
1058
+ sx={{
1059
+ position: 'sticky',
1060
+ insetBlockEnd: 0,
1061
+ marginBlockStart: -3.5,
1062
+ paddingBlock: 3,
1063
+ bgcolor: KESTREL.oat,
1064
+ borderBlockStart: `1px solid ${KESTREL.hairline}`,
1065
+ }}
1066
+ >
1067
+ <CartBlock />
1068
+ </Box>
1069
+ </Box>
1070
+ </Box>
1071
+
1072
+ <Box
1073
+ component="footer"
1074
+ sx={{
1075
+ gridColumn: '1 / -1',
1076
+ display: 'flex',
1077
+ alignItems: 'center',
1078
+ justifyContent: 'space-between',
1079
+ gap: 3,
1080
+ paddingInline: `${GUTTER}px`,
1081
+ bgcolor: KESTREL.oat,
1082
+ borderBlockStart: `1px solid ${KESTREL.hairline}`,
1083
+ pointerEvents: 'auto',
1084
+ }}
1085
+ >
1086
+ <LayoutSlots.DesktopFooter />
1087
+ <LayoutSlots.DesktopPoweredBy />
1088
+ </Box>
1089
+ </>
1090
+ )}
1091
+ </Box>
1092
+ )
1093
+ }
1094
+ ```
1095
+
1096
+ ### ./src/\_shared/FullscreenButton.tsx
1097
+
1098
+ ```tsx
1099
+ import { IconButton, Tooltip } from '@mui/material'
1100
+
1101
+ import { FrontendAnalyticsFactory } from '@salsita-ai/sdk/configurator'
1102
+
1103
+ import { phx } from '../../.phoenix/phx.js'
1104
+ import { KESTREL } from './tokens.js'
1105
+
1106
+ const ENTER_ICON = 'M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5'
1107
+ const EXIT_ICON = 'M9 4v5H4M15 4v5h5M15 20v-5h5M9 20v-5H4'
1108
+
1109
+ // Shows the kettle alone: the layout reads the flag and leaves out everything but the scene while it is set
1110
+ export const FullscreenButton = () => {
1111
+ const isFullscreen = phx.frontend.useIsFullscreenActive()
1112
+ const setFullscreen = phx.frontend.useSetFullscreen()
1113
+ const analytics = phx.frontend.useAnalytics()
1114
+ const label = isFullscreen ? 'Exit fullscreen' : 'Fullscreen'
1115
+
1116
+ // The same event the built-in fullscreen button records, for entering and for leaving
1117
+ const toggle = () => {
1118
+ analytics.push(FrontendAnalyticsFactory.FullScreenModeToggled())
1119
+ setFullscreen(!isFullscreen)
1120
+ }
1121
+
1122
+ return (
1123
+ <Tooltip title={label}>
1124
+ <IconButton
1125
+ aria-label={label}
1126
+ onClick={toggle}
1127
+ sx={{
1128
+ inlineSize: 44,
1129
+ blockSize: 44,
1130
+ color: KESTREL.charcoal,
1131
+ border: `1px solid ${KESTREL.hairline}`,
1132
+ bgcolor: 'rgba(244, 239, 232, 0.8)',
1133
+ '&:hover': { bgcolor: KESTREL.oat },
1134
+ }}
1135
+ >
1136
+ <svg viewBox="0 0 24 24" width={18} height={18} fill="none" stroke="currentColor" strokeWidth={1.6}>
1137
+ <path d={isFullscreen ? EXIT_ICON : ENTER_ICON} />
1138
+ </svg>
1139
+ </IconButton>
1140
+ </Tooltip>
1141
+ )
1142
+ }
1143
+ ```
1144
+
1145
+ ### ./src/\_shared/KettleOptions.tsx
1146
+
1147
+ ```tsx
1148
+ import { Box, Divider } from '@mui/material'
1149
+
1150
+ import { phx } from '../../.phoenix/phx.js'
1151
+ import { SwatchRow } from './SwatchRow.js'
1152
+ import { ThermometerRow } from './ThermometerRow.js'
1153
+ import { KESTREL } from './tokens.js'
1154
+
1155
+ // The swatches' look, keyed by the option values of the spec
1156
+ const FINISH_FILLS = {
1157
+ BrushedSteel: 'linear-gradient(135deg, #f1f2f4 0%, #a9aeb4 55%, #dcdfe2 100%)',
1158
+ MatteBlack: 'linear-gradient(135deg, #4a4744 0%, #1f1d1b 100%)',
1159
+ Copper: 'linear-gradient(135deg, #f0b48a 0%, #b8693d 55%, #8a4a28 100%)',
1160
+ }
1161
+
1162
+ const WOOD_FILLS = {
1163
+ Walnut: 'linear-gradient(135deg, #7a5238 0%, #4a2f1f 100%)',
1164
+ Oak: 'linear-gradient(135deg, #ead2ad 0%, #c49a6c 100%)',
1165
+ }
1166
+
1167
+ interface KettleOptionsProps {
1168
+ readonly readOnly: boolean
1169
+ }
1170
+
1171
+ // The three choices, in the order a buyer makes them. The spec's `attributeSelection` has no label, so the labels
1172
+ // are the layout's own. Once the kettle is in the cart the choices stay as they were added, until "Make another".
1173
+ export const KettleOptions = ({ readOnly }: KettleOptionsProps) => {
1174
+ const isAdded = phx.frontend.useActiveNavigationState() === 'added'
1175
+ const locked = readOnly || isAdded
1176
+
1177
+ return (
1178
+ <Box component="div" sx={{ display: 'grid' }}>
1179
+ <Divider sx={{ borderColor: KESTREL.hairline }} />
1180
+ <SwatchRow label="Body finish" instanceName="bodyFinish" fills={FINISH_FILLS} readOnly={locked} />
1181
+ <Divider sx={{ borderColor: KESTREL.hairline }} />
1182
+ <SwatchRow label="Handle" instanceName="handleWood" fills={WOOD_FILLS} readOnly={locked} />
1183
+ <Divider sx={{ borderColor: KESTREL.hairline }} />
1184
+ <ThermometerRow readOnly={locked} />
1185
+ </Box>
1186
+ )
1187
+ }
1188
+ ```
1189
+
1190
+ ### ./src/\_shared/PhonePage.tsx
1191
+
1192
+ ```tsx
1193
+ import { Box, IconButton, Tooltip, Typography } from '@mui/material'
1194
+
1195
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
1196
+ import { notistackSnackbarClasses } from '@salsita-ai/sdk/ui'
1197
+
1198
+ import { phx } from '../../.phoenix/phx.js'
1199
+ import { CartBlock } from './CartBlock.js'
1200
+ import { FullscreenButton } from './FullscreenButton.js'
1201
+ import { KettleOptions } from './KettleOptions.js'
1202
+ import { ProductHeading } from './ProductHeading.js'
1203
+ import { KESTREL } from './tokens.js'
1204
+
1205
+ const CLOSE_ICON = 'M6 6l12 12M18 6 6 18'
1206
+ const GUTTER = 16
1207
+ const SCENE_HEIGHT = '44%'
1208
+
1209
+ // The phone page: the kettle at the top, then one column that scrolls below it, with the price and the button in a
1210
+ // bar that stays at the bottom. In fullscreen only the kettle stays.
1211
+ export const PhonePage = () => {
1212
+ const { containerRef, safeAreaRef } = phx.frontend.useSceneSafeArea()
1213
+ const isFullscreen = phx.frontend.useIsFullscreenActive()
1214
+ const { accessInfo } = phx.frontend.useAccessService()
1215
+ const closeAction = phx.frontend.useCloseAction()
1216
+ const { isExpanded, leave } = phx.frontend.usePreview()
1217
+ // The host's close action when it offers one; otherwise, once the start screen expanded the page, the way back to it
1218
+ const close = closeAction ? () => void closeAction() : isExpanded ? leave : null
1219
+
1220
+ return (
1221
+ <Box
1222
+ component="div"
1223
+ ref={containerRef}
1224
+ sx={{
1225
+ position: 'absolute',
1226
+ inset: 0,
1227
+ display: 'flex',
1228
+ flexDirection: 'column',
1229
+ fontFamily: KESTREL.body,
1230
+ pointerEvents: 'none',
1231
+ }}
1232
+ >
1233
+ <Box
1234
+ component="div"
1235
+ sx={{ position: 'relative', flex: isFullscreen ? '1 1 0' : `0 0 ${SCENE_HEIGHT}`, minBlockSize: 0 }}
1236
+ >
1237
+ {/* The camera fits the kettle into this box: below the top bar, clear of the screen's edges */}
1238
+ <Box
1239
+ component="div"
1240
+ ref={safeAreaRef}
1241
+ sx={{ position: 'absolute', inset: `${GUTTER + 52}px ${GUTTER}px ${GUTTER}px` }}
1242
+ />
1243
+ <Box
1244
+ component="div"
1245
+ sx={{
1246
+ position: 'absolute',
1247
+ insetBlockStart: GUTTER,
1248
+ insetInline: GUTTER,
1249
+ display: 'grid',
1250
+ gridTemplateColumns: '44px 1fr 44px',
1251
+ alignItems: 'center',
1252
+ }}
1253
+ >
1254
+ {close ? (
1255
+ <Tooltip title="Close">
1256
+ <IconButton aria-label="Close" onClick={close} sx={{ color: KESTREL.charcoal, pointerEvents: 'auto' }}>
1257
+ <svg viewBox="0 0 24 24" width={20} height={20} fill="none" stroke="currentColor" strokeWidth={1.6}>
1258
+ <path d={CLOSE_ICON} />
1259
+ </svg>
1260
+ </IconButton>
1261
+ </Tooltip>
1262
+ ) : (
1263
+ <span />
1264
+ )}
1265
+ <Typography sx={{ fontFamily: KESTREL.display, fontSize: 20, textAlign: 'center', color: KESTREL.charcoal }}>
1266
+ Aldermoor
1267
+ </Typography>
1268
+ <Box component="div" sx={{ pointerEvents: 'auto' }}>
1269
+ <FullscreenButton />
1270
+ </Box>
1271
+ </Box>
1272
+ {/* The phone root leaves the snackbars fixed to the viewport; here they drop in below the top bar instead */}
1273
+ <Box
1274
+ component="div"
1275
+ sx={{
1276
+ position: 'absolute',
1277
+ insetBlockStart: GUTTER + 56,
1278
+ insetInline: GUTTER,
1279
+ pointerEvents: 'auto',
1280
+ [`& .${notistackSnackbarClasses.container}`]: {
1281
+ position: 'absolute',
1282
+ inset: '0 0 auto 0',
1283
+ inlineSize: 'auto',
1284
+ transform: 'none',
1285
+ },
1286
+ }}
1287
+ >
1288
+ <LayoutSlots.MobileSnackbarsRoot />
1289
+ </Box>
1290
+ </Box>
1291
+
1292
+ {!isFullscreen && (
1293
+ <Box
1294
+ component="main"
1295
+ sx={{
1296
+ flex: '1 1 0',
1297
+ minBlockSize: 0,
1298
+ overflowY: 'auto',
1299
+ overscrollBehavior: 'contain',
1300
+ bgcolor: KESTREL.oat,
1301
+ borderBlockStart: `1px solid ${KESTREL.hairline}`,
1302
+ pointerEvents: 'auto',
1303
+ }}
1304
+ >
1305
+ <Box component="div" sx={{ display: 'grid', gap: 3, padding: 3, paddingBlockEnd: 4 }}>
1306
+ <ProductHeading size="small" />
1307
+ <KettleOptions readOnly={accessInfo.viewMode} />
1308
+ <Box
1309
+ component="div"
1310
+ sx={{
1311
+ display: 'grid',
1312
+ justifyItems: 'start',
1313
+ gap: 2,
1314
+ paddingBlockStart: 3,
1315
+ borderBlockStart: `1px solid ${KESTREL.hairline}`,
1316
+ }}
1317
+ >
1318
+ <LayoutSlots.MobileFooter />
1319
+ <LayoutSlots.MobilePoweredBy />
1320
+ </Box>
1321
+ </Box>
1322
+ <Box
1323
+ component="div"
1324
+ sx={{
1325
+ position: 'sticky',
1326
+ insetBlockEnd: 0,
1327
+ paddingInline: 3,
1328
+ paddingBlock: 2,
1329
+ bgcolor: KESTREL.oat,
1330
+ borderBlockStart: `1px solid ${KESTREL.hairline}`,
1331
+ }}
1332
+ >
1333
+ <CartBlock />
1334
+ </Box>
1335
+ </Box>
1336
+ )}
1337
+ </Box>
1338
+ )
1339
+ }
1340
+ ```
1341
+
1342
+ ### ./src/\_shared/PhonePoster.tsx
1343
+
1344
+ ```tsx
1345
+ import { Box, Button, Typography } from '@mui/material'
1346
+
1347
+ import { phx } from '../../.phoenix/phx.js'
1348
+ import { KESTREL, LABEL_SX } from './tokens.js'
1349
+
1350
+ // The layout's own start screen, shown on a phone while `usePreview().isPreview` is set (the spec's `preview: auto`).
1351
+ // It frames the kettle in the area above the text with its own safe area; `enter()` opens the page.
1352
+ export const PhonePoster = () => {
1353
+ const { containerRef, safeAreaRef } = phx.frontend.useSceneSafeArea()
1354
+ const { enter } = phx.frontend.usePreview()
1355
+ const price = phx.frontend.useRootEntityPrice()
1356
+
1357
+ return (
1358
+ <Box
1359
+ component="div"
1360
+ ref={containerRef}
1361
+ sx={{
1362
+ position: 'absolute',
1363
+ inset: 0,
1364
+ display: 'flex',
1365
+ flexDirection: 'column',
1366
+ fontFamily: KESTREL.body,
1367
+ pointerEvents: 'none',
1368
+ }}
1369
+ >
1370
+ <Typography
1371
+ sx={{
1372
+ paddingBlockStart: 3,
1373
+ textAlign: 'center',
1374
+ fontFamily: KESTREL.display,
1375
+ fontSize: 20,
1376
+ color: KESTREL.charcoal,
1377
+ }}
1378
+ >
1379
+ Aldermoor
1380
+ </Typography>
1381
+ <Box component="div" ref={safeAreaRef} sx={{ flex: '1 1 0', minBlockSize: 0, marginInline: 3 }} />
1382
+ <Box component="div" sx={{ display: 'grid', gap: 2, padding: 3, paddingBlockEnd: 4, pointerEvents: 'auto' }}>
1383
+ <Typography sx={{ ...LABEL_SX, color: KESTREL.copper }}>The Kestrel pour-over kettle</Typography>
1384
+ <Typography
1385
+ component="h1"
1386
+ sx={{
1387
+ fontFamily: KESTREL.display,
1388
+ fontSize: 48,
1389
+ lineHeight: 1,
1390
+ letterSpacing: '-0.01em',
1391
+ color: KESTREL.charcoal,
1392
+ }}
1393
+ >
1394
+ Make it yours
1395
+ </Typography>
1396
+ <Typography sx={{ fontSize: 15, lineHeight: 1.6, color: KESTREL.muted }}>
1397
+ Three finishes, two woods and a thermometer lid if you want one. As shown, {price}.
1398
+ </Typography>
1399
+ <Button
1400
+ variant="contained"
1401
+ disableElevation
1402
+ onClick={enter}
1403
+ sx={{
1404
+ marginBlockStart: 1,
1405
+ minBlockSize: 52,
1406
+ borderRadius: 999,
1407
+ bgcolor: KESTREL.charcoal,
1408
+ color: KESTREL.oat,
1409
+ fontFamily: KESTREL.body,
1410
+ fontSize: 15,
1411
+ textTransform: 'none',
1412
+ '&:hover': { bgcolor: '#000000' },
1413
+ }}
1414
+ >
1415
+ Start designing
1416
+ </Button>
1417
+ </Box>
1418
+ </Box>
1419
+ )
1420
+ }
1421
+ ```
1422
+
1423
+ ### ./src/\_shared/ProductHeading.tsx
1424
+
1425
+ ```tsx
1426
+ import { Box, Typography } from '@mui/material'
1427
+
1428
+ import { detailComponent } from '@salsita-ai/sdk/domain'
1429
+ import { LocalizableMessage } from '@salsita-ai/sdk/react'
1430
+
1431
+ import { phx } from '../../.phoenix/phx.js'
1432
+ import { KESTREL, LABEL_SX } from './tokens.js'
1433
+
1434
+ interface ProductHeadingProps {
1435
+ readonly size: 'large' | 'small'
1436
+ }
1437
+
1438
+ // The overline, the name and the story from the spec's `detail` component. Its texts are `Localizable`:
1439
+ // `useLocalizable` resolves one into a string and `LocalizableMessage` renders one in place.
1440
+ export const ProductHeading = ({ size }: ProductHeadingProps) => {
1441
+ const detail = phx.frontend.useFirstRootComponent(detailComponent)
1442
+ const title = phx.frontend.useLocalizable(detail?.state.title)
1443
+ const subtitle = phx.frontend.useLocalizable(detail?.state.subtitle)
1444
+
1445
+ return (
1446
+ <Box component="header" sx={{ display: 'grid', gap: size === 'large' ? 2 : 1.5 }}>
1447
+ <Typography sx={{ ...LABEL_SX, color: KESTREL.copper }}>Aldermoor Coffee</Typography>
1448
+ <Box component="div" sx={{ display: 'grid', gap: 0.75 }}>
1449
+ <Typography
1450
+ component="h1"
1451
+ sx={{
1452
+ fontFamily: KESTREL.display,
1453
+ fontSize: size === 'large' ? 60 : 40,
1454
+ lineHeight: 1,
1455
+ letterSpacing: '-0.01em',
1456
+ color: KESTREL.charcoal,
1457
+ }}
1458
+ >
1459
+ {title}
1460
+ </Typography>
1461
+ <Typography sx={{ fontFamily: KESTREL.body, fontSize: 15, color: KESTREL.muted }}>{subtitle}</Typography>
1462
+ </Box>
1463
+ <Typography sx={{ fontFamily: KESTREL.body, fontSize: 15, lineHeight: 1.65, color: KESTREL.charcoal }}>
1464
+ <LocalizableMessage>{detail?.state.description}</LocalizableMessage>
1465
+ </Typography>
1466
+ </Box>
1467
+ )
1468
+ }
1469
+ ```
1470
+
1471
+ ### ./src/\_shared/SwatchRow.tsx
1472
+
1473
+ ```tsx
1474
+ import { Box, ButtonBase, Typography } from '@mui/material'
1475
+ import type { KeyboardEvent } from 'react'
1476
+
1477
+ import { phx } from '../../.phoenix/phx.js'
1478
+ import { KESTREL, LABEL_SX } from './tokens.js'
1479
+
1480
+ // Arrow keys move the selection between the swatches, as in a native radio group
1481
+ const ARROW_STEPS: Readonly<Record<string, number | undefined>> = {
1482
+ ArrowRight: 1,
1483
+ ArrowDown: 1,
1484
+ ArrowLeft: -1,
1485
+ ArrowUp: -1,
1486
+ }
1487
+
1488
+ interface SwatchRowProps {
1489
+ readonly label: string
1490
+ readonly instanceName: string
1491
+ // How each option looks, keyed by the spec's option values: a CSS background
1492
+ readonly fills: Readonly<Record<string, string>>
1493
+ readonly readOnly: boolean
1494
+ }
1495
+
1496
+ // One `attributeSelection` of the spec as a row of round swatches, with the chosen option's name and description.
1497
+ // An option the spec's invariants rule out is `disabled`: it is drawn faded and its hint says why, but it can still be
1498
+ // clicked. Its `onSelect` then makes the change, which the invariant rejects, and the built-in snackbar repeats the
1499
+ // reason. The arrow keys skip it.
1500
+ export const SwatchRow = ({ label, instanceName, fills, readOnly }: SwatchRowProps) => {
1501
+ const resolve = phx.frontend.useResolveLocalizable()
1502
+ const kettleId = phx.frontend.useRootEntityId()
1503
+ const { value, options } = phx.frontend.useAttributeSelection(kettleId, instanceName)
1504
+ const selected = options.find(option => option.value === value)
1505
+ const hint = options.find(option => option.disabled && option.hint)?.hint
1506
+
1507
+ const handleKeyDown = (event: KeyboardEvent<HTMLElement>, index: number) => {
1508
+ const step = ARROW_STEPS[event.key]
1509
+
1510
+ if (step === undefined) {
1511
+ return
1512
+ }
1513
+
1514
+ event.preventDefault()
1515
+ // The next enabled option in the arrow's direction, wrapping around
1516
+ const count = options.length
1517
+ const next = Array.from(
1518
+ { length: count - 1 },
1519
+ (_, offset) => (((index + step * (offset + 1)) % count) + count) % count
1520
+ ).find(candidate => !options[candidate]?.disabled)
1521
+
1522
+ if (next === undefined) {
1523
+ return
1524
+ }
1525
+
1526
+ options[next]?.onSelect()
1527
+ event.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role="radio"]')[next]?.focus()
1528
+ }
1529
+
1530
+ return (
1531
+ <Box component="section" sx={{ display: 'grid', gap: 1.5, paddingBlock: 2 }}>
1532
+ <Box component="div" sx={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 2 }}>
1533
+ <Typography component="h3" sx={LABEL_SX}>
1534
+ {label}
1535
+ </Typography>
1536
+ <Typography sx={{ fontFamily: KESTREL.display, fontSize: 18, color: KESTREL.charcoal }}>
1537
+ {resolve(selected?.title)}
1538
+ </Typography>
1539
+ </Box>
1540
+
1541
+ <Box component="div" role="radiogroup" aria-label={label} sx={{ display: 'flex', gap: 1.5 }}>
1542
+ {options.map((option, index) => {
1543
+ const isSelected = option.value === value
1544
+ const title = resolve(option.title)
1545
+
1546
+ return (
1547
+ <ButtonBase
1548
+ key={String(option.value)}
1549
+ role="radio"
1550
+ aria-checked={isSelected}
1551
+ aria-label={title}
1552
+ title={option.hint ?? title}
1553
+ aria-disabled={option.disabled}
1554
+ tabIndex={isSelected ? 0 : -1}
1555
+ disabled={readOnly}
1556
+ onClick={option.onSelect}
1557
+ onKeyDown={event => handleKeyDown(event, index)}
1558
+ sx={{
1559
+ inlineSize: 40,
1560
+ blockSize: 40,
1561
+ borderRadius: '50%',
1562
+ background: fills[String(option.value)],
1563
+ // A ring of the page's colour between the swatch and the outline of the chosen one
1564
+ boxShadow: isSelected
1565
+ ? `0 0 0 3px ${KESTREL.oat}, 0 0 0 4px ${KESTREL.charcoal}`
1566
+ : `inset 0 0 0 1px ${KESTREL.hairline}`,
1567
+ transition: 'box-shadow 160ms, transform 160ms',
1568
+ opacity: option.disabled ? 0.3 : 1,
1569
+ '&:hover': { transform: isSelected || option.disabled ? 'none' : 'scale(1.06)' },
1570
+ '&.Mui-focusVisible': { outline: `2px solid ${KESTREL.copper}`, outlineOffset: 6 },
1571
+ // A viewer sees the chosen swatch only as chosen; the others fade
1572
+ '&.Mui-disabled': { opacity: isSelected ? 1 : 0.3 },
1573
+ }}
1574
+ />
1575
+ )
1576
+ })}
1577
+ </Box>
1578
+
1579
+ <Typography sx={{ fontSize: 13, color: KESTREL.muted }}>
1580
+ {hint && !readOnly ? hint : resolve(selected?.description)}
1581
+ </Typography>
1582
+ </Box>
1583
+ )
1584
+ }
1585
+ ```
1586
+
1587
+ ### ./src/\_shared/ThermometerRow.tsx
1588
+
1589
+ ```tsx
1590
+ import { Box, Switch, Typography } from '@mui/material'
1591
+
1592
+ import { phx } from '../../.phoenix/phx.js'
1593
+ import { KESTREL, LABEL_SX } from './tokens.js'
1594
+
1595
+ interface ThermometerRowProps {
1596
+ readonly readOnly: boolean
1597
+ }
1598
+
1599
+ // The spec's `attributeSwitch` as a labelled switch: on, the lid carries a dial thermometer; off, a plain wooden knob
1600
+ export const ThermometerRow = ({ readOnly }: ThermometerRowProps) => {
1601
+ const kettleId = phx.frontend.useRootEntityId()
1602
+ const thermometer = phx.frontend.useAttributeSwitch(kettleId, 'thermometer')
1603
+ const isOn = thermometer.state.value
1604
+
1605
+ return (
1606
+ <Box component="section" sx={{ display: 'grid', gap: 0.5, paddingBlock: 2 }}>
1607
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 2 }}>
1608
+ <Typography component="h3" id="kestrel-thermometer-label" sx={LABEL_SX}>
1609
+ Thermometer lid
1610
+ </Typography>
1611
+ <Switch
1612
+ checked={isOn}
1613
+ disabled={readOnly || thermometer.disabled}
1614
+ onChange={thermometer.onChange}
1615
+ inputProps={{ 'aria-labelledby': 'kestrel-thermometer-label' }}
1616
+ sx={{
1617
+ '& .MuiSwitch-switchBase.Mui-checked': { color: KESTREL.oat },
1618
+ '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { bgcolor: KESTREL.copper, opacity: 1 },
1619
+ '& .MuiSwitch-track': { bgcolor: KESTREL.hairline, opacity: 1 },
1620
+ }}
1621
+ />
1622
+ </Box>
1623
+ <Typography sx={{ fontSize: 13, color: KESTREL.muted }}>
1624
+ {isOn ? 'A dial in the lid shows when the water is ready to pour.' : 'A plain lid with a wooden knob.'}
1625
+ </Typography>
1626
+ </Box>
1627
+ )
1628
+ }
1629
+ ```
1630
+
1631
+ ### ./src/\_shared/tokens.ts
1632
+
1633
+ ```ts
1634
+ // The brand's palette and type. Playfair Display and Circular Std are the fonts the brand ships; the stacks fall back
1635
+ // to system fonts where they are not loaded.
1636
+ export const KESTREL = {
1637
+ oat: '#f4efe8',
1638
+ charcoal: '#1f1d1b',
1639
+ copper: '#b8693d',
1640
+ sage: '#9daa94',
1641
+ muted: 'rgba(31, 29, 27, 0.62)',
1642
+ hairline: 'rgba(31, 29, 27, 0.12)',
1643
+ display: "'PlayfairDisplay-Regular', 'Playfair Display', Georgia, serif",
1644
+ body: "'Circular-Std-Book', 'Helvetica Neue', Arial, sans-serif",
1645
+ } as const
1646
+
1647
+ // Small capitals with wide tracking, for the overline and the option labels
1648
+ export const LABEL_SX = {
1649
+ fontFamily: KESTREL.body,
1650
+ fontSize: 11,
1651
+ letterSpacing: '0.18em',
1652
+ textTransform: 'uppercase',
1653
+ color: KESTREL.muted,
1654
+ } as const
1655
+ ```
1656
+
1657
+ ### ./src/elements/ConfiguratorLayout.tsx
1658
+
1659
+ ```tsx
1660
+ import { Box } from '@mui/material'
1661
+
1662
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
1663
+
1664
+ import { phx } from '../../.phoenix/phx.js'
1665
+ import { DesktopPage } from '../_shared/DesktopPage.js'
1666
+ import { PhonePage } from '../_shared/PhonePage.js'
1667
+ import { PhonePoster } from '../_shared/PhonePoster.js'
1668
+ import { KESTREL } from '../_shared/tokens.js'
1669
+
1670
+ // One page, no steps or tabs. The canvas and the services stay mounted the whole time; what lies over the canvas is
1671
+ // the phone's start screen, the phone page or the desktop page. Each calls `useSceneSafeArea` itself, so only the one
1672
+ // on screen tells the camera where the kettle goes.
1673
+ const ConfiguratorLayout = () => {
1674
+ // `null` until the container has been measured; only the scene shows until then
1675
+ const viewports = phx.frontend.useActiveViewports()
1676
+ const { isPreview } = phx.frontend.usePreview()
1677
+ const isDesktop = viewports?.includes('desktop') ?? false
1678
+
1679
+ return (
1680
+ <Box component="div" sx={{ position: 'absolute', inset: 0, overflow: 'clip', bgcolor: KESTREL.oat }}>
1681
+ <LayoutSlots.Services />
1682
+ <LayoutSlots.SharedCanvas />
1683
+ {viewports !== null && (isPreview ? <PhonePoster /> : isDesktop ? <DesktopPage /> : <PhonePage />)}
1684
+ </Box>
1685
+ )
1686
+ }
1687
+
1688
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
1689
+ ```
1690
+
1691
+ ### ./src/elements/KettleStudio.tsx
1692
+
1693
+ ```tsx
1694
+ import { ContactShadows, Environment, Lightformer } from '@react-three/drei'
1695
+
1696
+ import { phx } from '../../.phoenix/phx.js'
1697
+ import { KESTREL } from '../_shared/tokens.js'
1698
+
1699
+ // The stage named by the spec's `canvasCustomEnvironment`: a backdrop, a soft shadow under the kettle and a studio of
1700
+ // light panels. The panels exist only in the reflections, so the metal finishes have something to mirror and no image
1701
+ // has to be downloaded. The scene is in millimetres.
1702
+ export default phx.frontend.createCustomPhoenixLayoutElement('KettleStudio', () => {
1703
+ return (
1704
+ <>
1705
+ {/* The page's oat background, so the scene and the layout read as one surface */}
1706
+ <color attach="background" args={[KESTREL.oat]} />
1707
+ <ambientLight intensity={0.35} />
1708
+ <directionalLight position={[400, 900, 600]} intensity={1.1} />
1709
+
1710
+ <Environment resolution={256} frames={1}>
1711
+ <color attach="background" args={['#77706a']} />
1712
+ {/* A softbox above, tall strips at the sides for the long highlights, a warm fill behind, a dim one in front */}
1713
+ <Lightformer form="rect" intensity={2.4} position={[0, 6, 0]} rotation-x={Math.PI / 2} scale={[10, 6, 1]} />
1714
+ <Lightformer form="rect" intensity={3} position={[-6, 1, 2]} rotation-y={Math.PI / 2} scale={[1.2, 8, 1]} />
1715
+ <Lightformer form="rect" intensity={1.6} position={[6, 1, 3]} rotation-y={-Math.PI / 2} scale={[1.2, 8, 1]} />
1716
+ <Lightformer form="rect" color="#f3d9c2" intensity={1} position={[0, 1, -8]} scale={[12, 4, 1]} />
1717
+ <Lightformer form="rect" intensity={0.8} position={[0, 0, 8]} rotation-y={Math.PI} scale={[10, 3, 1]} />
1718
+ </Environment>
1719
+
1720
+ <ContactShadows position={[0, -1, 0]} scale={520} far={60} blur={2.2} opacity={0.7} resolution={512} />
1721
+ </>
1722
+ )
1723
+ })
1724
+ ```
1725
+
1726
+ ### ./src/elements/LayoutFooter.tsx
1727
+
1728
+ ```tsx
1729
+ import { Box } from '@mui/material'
1730
+
1731
+ import { phx } from '../../.phoenix/phx.js'
1732
+ import { KESTREL } from '../_shared/tokens.js'
1733
+
1734
+ const PROMISES = ['Free delivery over $75', 'Two-year warranty', '30-day returns']
1735
+
1736
+ // The shop's promises. `createLayoutFooter` registers it as the `LayoutFooter` element, which the layout shows where it
1737
+ // mounts `LayoutSlots.DesktopFooter` or `LayoutSlots.MobileFooter`.
1738
+ const LayoutFooter = () => {
1739
+ return (
1740
+ <Box
1741
+ component="ul"
1742
+ sx={{
1743
+ display: 'flex',
1744
+ flexWrap: 'wrap',
1745
+ columnGap: 3,
1746
+ rowGap: 0.5,
1747
+ margin: 0,
1748
+ padding: 0,
1749
+ listStyle: 'none',
1750
+ fontSize: 12,
1751
+ letterSpacing: '0.04em',
1752
+ color: KESTREL.muted,
1753
+ }}
1754
+ >
1755
+ {PROMISES.map(promise => (
1756
+ <Box
1757
+ component="li"
1758
+ key={promise}
1759
+ sx={{ display: 'flex', alignItems: 'center', gap: 1, '&::before': { content: '"·"', color: KESTREL.sage } }}
1760
+ >
1761
+ {promise}
1762
+ </Box>
1763
+ ))}
1764
+ </Box>
1765
+ )
1766
+ }
1767
+
1768
+ export default phx.frontend.createLayoutFooter(LayoutFooter)
1769
+ ```
1770
+
1771
+ ### ./src/expressions/kettle.ts
1772
+
1773
+ ```ts
1774
+ import { phx } from '../../.phoenix/phx.js'
1775
+
1776
+ const BASE_PRICE = 145
1777
+ const FINISH_SURCHARGE = { BrushedSteel: 0, MatteBlack: 10, Copper: 45 }
1778
+ const WOOD_SURCHARGE = { Walnut: 10, Oak: 0 }
1779
+ const THERMOMETER_SURCHARGE = 20
1780
+
1781
+ // How each finish renders: the spec's material override of the `Body` material reads these
1782
+ const FINISHES = {
1783
+ BrushedSteel: { color: '#c9ccd0', metalness: 1, roughness: 0.3, clearcoat: 0 },
1784
+ MatteBlack: { color: '#2b2927', metalness: 0.1, roughness: 0.55, clearcoat: 0 },
1785
+ Copper: { color: '#d08a5c', metalness: 1, roughness: 0.2, clearcoat: 0.6 },
1786
+ }
1787
+
1788
+ const WOODS = { Walnut: '#4a2f1f', Oak: '#c49a6c' }
1789
+
1790
+ export default phx.domain.implementCustomExpressions({
1791
+ Kettle: {
1792
+ $price: s => {
1793
+ return (
1794
+ BASE_PRICE +
1795
+ FINISH_SURCHARGE[s.bodyFinish] +
1796
+ WOOD_SURCHARGE[s.handleWood] +
1797
+ (s.thermometer ? THERMOMETER_SURCHARGE : 0)
1798
+ )
1799
+ },
1800
+ $plainKnob: s => {
1801
+ return !s.thermometer
1802
+ },
1803
+ $bodyColor: s => {
1804
+ return FINISHES[s.bodyFinish].color
1805
+ },
1806
+ $bodyMetalness: s => {
1807
+ return FINISHES[s.bodyFinish].metalness
1808
+ },
1809
+ $bodyRoughness: s => {
1810
+ return FINISHES[s.bodyFinish].roughness
1811
+ },
1812
+ $bodyClearcoat: s => {
1813
+ return FINISHES[s.bodyFinish].clearcoat
1814
+ },
1815
+ $handleColor: s => {
1816
+ return WOODS[s.handleWood]
1817
+ },
1818
+ },
1819
+ })
1820
+ ```
1821
+
1822
+ ### ./src/handlers/add-to-cart.ts
1823
+
1824
+ ```ts
1825
+ import { useCallback } from 'react'
1826
+
1827
+ import { phx } from '../../.phoenix/phx.js'
1828
+
1829
+ // Stands in for the shop's cart: adding takes a moment, then the page shows the confirmation
1830
+ export default phx.frontend.createPhoenixHandler('addToCart', () => {
1831
+ const navigate = phx.frontend.useNavigate()
1832
+
1833
+ return {
1834
+ handler: useCallback(async () => {
1835
+ await new Promise(resolve => setTimeout(resolve, 1200))
1836
+ navigate('added')
1837
+ }, [navigate]),
1838
+ }
1839
+ })
1840
+ ```
1841
+
1842
+ ### ./src/invariants/kettle.ts
1843
+
1844
+ ```ts
1845
+ import { phx } from '../../.phoenix/phx.js'
1846
+
1847
+ // The copper body is sold only with the walnut handle. The spec marks the violation `fixable`, so a change that breaks
1848
+ // it is rejected and the built-in snackbar shows the spec's message.
1849
+ export default phx.domain.implementCustomInvariants({
1850
+ Kettle: {
1851
+ copperNeedsWalnut: s => {
1852
+ return s.bodyFinish !== 'Copper' || s.handleWood === 'Walnut'
1853
+ },
1854
+ },
1855
+ })
1856
+ ```
1857
+
1858
+ </details>