@salsita-ai/sdk 0.50.0-develop.eb204e0da4 → 0.50.0-develop.ed1806b910

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 (2181) hide show
  1. package/README.md +28 -15
  2. package/dist/admin/create-admin-pages-from-spec.d.ts +1 -1
  3. package/dist/admin/default-admin-elements.d.ts +9 -0
  4. package/dist/admin/default-admin-elements.js +1 -0
  5. package/dist/admin/default-elements/built-in-entity-element.d.ts +10 -0
  6. package/dist/admin/default-elements/built-in-entity-element.js +1 -0
  7. package/dist/admin/default-elements/built-in-layout-element.d.ts +10 -0
  8. package/dist/admin/default-elements/built-in-layout-element.js +1 -0
  9. package/dist/admin/default-elements/index.d.ts +2 -0
  10. package/dist/admin/default-elements/index.js +1 -0
  11. package/dist/admin/index.d.ts +1 -0
  12. package/dist/admin/index.js +1 -1
  13. package/dist/application/index.d.ts +1 -0
  14. package/dist/application/index.js +1 -1
  15. package/dist/application/mount-application.d.ts +1 -1
  16. package/dist/application/mount-application.js +1 -1
  17. package/dist/application/mount-configurator.d.ts +19 -0
  18. package/dist/application/mount-configurator.js +1 -0
  19. package/dist/application/mounted-application-runtime.d.ts +4 -0
  20. package/dist/application/mounted-application-runtime.js +1 -0
  21. package/dist/application/register-web-component.d.ts +2 -0
  22. package/dist/application/register-web-component.js +1 -0
  23. package/dist/application-spec/caching/content-diff.js +1 -1
  24. package/dist/application-spec/core/application-file.d.ts +0 -2
  25. package/dist/application-spec/core/application-file.js +1 -1
  26. package/dist/application-spec/core/components/component-filter.d.ts +53 -0
  27. package/dist/application-spec/core/components/component-filter.js +1 -0
  28. package/dist/application-spec/core/components/index.d.ts +2 -0
  29. package/dist/application-spec/core/components/index.js +1 -0
  30. package/dist/application-spec/core/components/sdk-code-ref.d.ts +9 -0
  31. package/dist/application-spec/core/components/sdk-code-ref.js +1 -0
  32. package/dist/application-spec/core/enhanced-json-value.d.ts +0 -68
  33. package/dist/application-spec/core/enhanced-json-value.js +1 -1
  34. package/dist/application-spec/core/expressions/index.d.ts +2 -0
  35. package/dist/application-spec/core/expressions/index.js +1 -0
  36. package/dist/application-spec/core/expressions/relation-expression-params.d.ts +11 -0
  37. package/dist/application-spec/core/expressions/sdk-expression-implementation.d.ts +24 -0
  38. package/dist/application-spec/core/expressions/sdk-expression-implementation.js +1 -0
  39. package/dist/application-spec/core/index.d.ts +2 -0
  40. package/dist/application-spec/core/index.js +1 -1
  41. package/dist/application-spec/core/json-value.d.ts +1 -1
  42. package/dist/application-spec/enhanced-json/eval-to-constant.d.ts +14 -0
  43. package/dist/application-spec/enhanced-json/index.d.ts +4 -0
  44. package/dist/application-spec/enhanced-json/index.js +1 -0
  45. package/dist/application-spec/enhanced-json/is-enhanced-json-array.d.ts +2 -0
  46. package/dist/application-spec/enhanced-json/is-enhanced-json-array.js +1 -0
  47. package/dist/application-spec/enhanced-json/resolve-enhanced-json-value.d.ts +18 -0
  48. package/dist/application-spec/enhanced-json/resolve-enhanced-json-value.js +1 -0
  49. package/dist/application-spec/enhanced-json/schema-from-value.d.ts +24 -0
  50. package/dist/application-spec/enhanced-json/schema-from-value.js +1 -0
  51. package/dist/application-spec/enhanced-json/stringify-enhanced-json-value.d.ts +14 -0
  52. package/dist/application-spec/enhanced-json/stringify-enhanced-json-value.js +1 -0
  53. package/dist/application-spec/enhanced-json/validate-enhanced-json-value-caps.d.ts +12 -0
  54. package/dist/application-spec/enhanced-json/validate-enhanced-json-value-caps.js +1 -0
  55. package/dist/application-spec/enhanced-json/validate-no-legacy-code-ref.d.ts +13 -0
  56. package/dist/application-spec/enhanced-json/validate-no-legacy-code-ref.js +1 -0
  57. package/dist/application-spec/errors/diagnostic-codes.d.ts +29 -0
  58. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  59. package/dist/application-spec/errors/diagnostic-messages.d.ts +33 -1
  60. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  61. package/dist/application-spec/generate-application/code/common/code-imports.js +1 -1
  62. package/dist/application-spec/generate-application/code/common/env-reader.js +2 -2
  63. package/dist/application-spec/generate-application/code/common/index.d.ts +2 -0
  64. package/dist/application-spec/generate-application/code/common/index.js +1 -1
  65. package/dist/application-spec/generate-application/code/common/project-module-list.d.ts +8 -0
  66. package/dist/application-spec/generate-application/code/common/project-module-list.js +3 -0
  67. package/dist/application-spec/generate-application/code/common/single-quoted-string.d.ts +6 -0
  68. package/dist/application-spec/generate-application/code/common/single-quoted-string.js +1 -0
  69. package/dist/application-spec/generate-application/code/domain-runtime-files.js +1 -1
  70. package/dist/application-spec/generate-application/code/generate-application-code.d.ts +3 -2
  71. package/dist/application-spec/generate-application/code/generate-application-code.js +1 -1
  72. package/dist/application-spec/generate-application/code/project-scaffolding.d.ts +22 -14
  73. package/dist/application-spec/generate-application/code/project-scaffolding.js +2 -2
  74. package/dist/application-spec/generate-application/code/standalone-app-files.d.ts +2 -2
  75. package/dist/application-spec/generate-application/code/standalone-app-files.js +1 -1
  76. package/dist/application-spec/generate-application/code/story-files.js +1 -1
  77. package/dist/application-spec/generate-application/code/templates/admin-config.js +3 -0
  78. package/dist/application-spec/generate-application/code/templates/admin-domain-code.d.ts +1 -2
  79. package/dist/application-spec/generate-application/code/templates/admin-domain-code.js +6 -14
  80. package/dist/application-spec/generate-application/code/templates/admin-frontend-code.d.ts +1 -2
  81. package/dist/application-spec/generate-application/code/templates/admin-frontend-code.js +4 -4
  82. package/dist/application-spec/generate-application/code/templates/application-types.js +6 -6
  83. package/dist/application-spec/generate-application/code/templates/common/doc-comment.d.ts +2 -0
  84. package/dist/application-spec/generate-application/code/templates/common/doc-comment.js +1 -0
  85. package/dist/application-spec/generate-application/code/templates/common/format-property-key.d.ts +7 -0
  86. package/dist/application-spec/generate-application/code/templates/common/format-property-key.js +1 -0
  87. package/dist/application-spec/generate-application/code/templates/common/schema-to-type-string.js +3 -3
  88. package/dist/application-spec/generate-application/code/templates/configurator-config.js +6 -4
  89. package/dist/application-spec/generate-application/code/templates/configurator-domain-code.d.ts +2 -2
  90. package/dist/application-spec/generate-application/code/templates/configurator-domain-code.js +7 -13
  91. package/dist/application-spec/generate-application/code/templates/configurator-frontend-code.d.ts +1 -2
  92. package/dist/application-spec/generate-application/code/templates/configurator-frontend-code.js +7 -9
  93. package/dist/application-spec/generate-application/code/templates/configurator-globals.d.ts +2 -1
  94. package/dist/application-spec/generate-application/code/templates/configurator-globals.js +19 -6
  95. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/domain-factory-types.d.ts +35 -0
  96. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/domain-factory-types.js +5 -0
  97. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/index.d.ts +1 -0
  98. package/dist/application-spec/generate-application/code/templates/domain-spec/factory-types/index.js +1 -0
  99. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-assistant.d.ts +2 -2
  100. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-assistant.js +1 -1
  101. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-component-optics.d.ts +1 -1
  102. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-component-optics.js +7 -7
  103. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-defaults.d.ts +4 -2
  104. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-defaults.js +1 -1
  105. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.d.ts +3 -1
  106. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.js +73 -73
  107. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-invariants.d.ts +9 -1
  108. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-invariants.js +1 -1
  109. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-phx-globals.js +6 -0
  110. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-presets.js +1 -1
  111. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-relation-expressions.js +1 -1
  112. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-resources.d.ts +6 -8
  113. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-resources.js +21 -21
  114. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-states.d.ts +1 -1
  115. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-states.js +2 -2
  116. package/dist/application-spec/generate-application/code/templates/domain-spec/index.d.ts +3 -2
  117. package/dist/application-spec/generate-application/code/templates/domain-spec/index.js +1 -1
  118. package/dist/application-spec/generate-application/code/templates/domain-spec.js +11 -11
  119. package/dist/application-spec/generate-application/code/templates/domain.js +4 -4
  120. package/dist/application-spec/generate-application/code/templates/eslint-config.d.ts +5 -0
  121. package/dist/application-spec/generate-application/code/templates/eslint-config.js +4 -5
  122. package/dist/application-spec/generate-application/code/templates/frontend-config.js +3 -5
  123. package/dist/application-spec/generate-application/code/templates/gitignore.js +0 -3
  124. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.d.ts +11 -0
  125. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.js +8 -0
  126. package/dist/application-spec/generate-application/code/templates/global-definition/generate-assistant-form-element-types.d.ts +12 -0
  127. package/dist/application-spec/generate-application/code/templates/global-definition/generate-assistant-form-element-types.js +7 -0
  128. package/dist/application-spec/generate-application/code/templates/global-definition/generate-phx-types.d.ts +43 -0
  129. package/dist/application-spec/generate-application/code/templates/global-definition/generate-phx-types.js +33 -0
  130. package/dist/application-spec/generate-application/code/templates/global-definition/index.d.ts +3 -0
  131. package/dist/application-spec/generate-application/code/templates/global-definition/index.js +1 -1
  132. package/dist/application-spec/generate-application/code/templates/globals.js +24 -42
  133. package/dist/application-spec/generate-application/code/templates/index.d.ts +4 -10
  134. package/dist/application-spec/generate-application/code/templates/index.js +1 -1
  135. package/dist/application-spec/generate-application/code/templates/lingui-rc.d.ts +5 -0
  136. package/dist/application-spec/generate-application/code/templates/lingui-rc.js +4 -4
  137. package/dist/application-spec/generate-application/code/templates/prettier-config.d.ts +5 -0
  138. package/dist/application-spec/generate-application/code/templates/prettier-config.js +4 -5
  139. package/dist/application-spec/generate-application/code/templates/root-tsconfig.d.ts +6 -0
  140. package/dist/application-spec/generate-application/code/templates/root-tsconfig.js +2 -0
  141. package/dist/application-spec/generate-application/code/templates/skills/phoenix-cli-skill.js +1 -1
  142. package/dist/application-spec/generate-application/code/templates/skills/phoenix-create-configurator-skill.js +95 -41
  143. package/dist/application-spec/generate-application/code/templates/skills/phoenix-feedback-skill.js +40 -17
  144. package/dist/application-spec/generate-application/code/templates/skills/phoenix-review-skill.js +13 -5
  145. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill.js +1 -1
  146. package/dist/application-spec/generate-application/code/templates/skills/phoenix-variants-skill.d.ts +1 -0
  147. package/dist/application-spec/generate-application/code/templates/skills/phoenix-variants-skill.js +6 -0
  148. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +69 -16
  149. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +19 -7
  150. package/dist/application-spec/generate-application/code/templates/spec-code/collect-spec-code.d.ts +58 -0
  151. package/dist/application-spec/generate-application/code/templates/spec-code/collect-spec-code.js +1 -0
  152. package/dist/application-spec/generate-application/code/templates/spec-code/index.d.ts +2 -0
  153. package/dist/application-spec/generate-application/code/templates/spec-code/index.js +1 -0
  154. package/dist/application-spec/generate-application/code/templates/spec-code/spec-code.d.ts +18 -0
  155. package/dist/application-spec/generate-application/code/templates/spec-code/spec-code.js +41 -0
  156. package/dist/application-spec/generate-application/code/templates/spec-messages/index.d.ts +1 -0
  157. package/dist/application-spec/generate-application/code/templates/spec-messages/index.js +1 -0
  158. package/dist/application-spec/generate-application/code/templates/spec-messages/spec-messages.d.ts +20 -0
  159. package/dist/application-spec/generate-application/code/templates/spec-messages/spec-messages.js +6 -0
  160. package/dist/application-spec/generate-application/code/templates/story/phx-module.d.ts +8 -2
  161. package/dist/application-spec/generate-application/code/templates/story/phx-module.js +15 -3
  162. package/dist/application-spec/generate-application/code/templates/story/wrapper.d.ts +3 -0
  163. package/dist/application-spec/generate-application/code/templates/story/wrapper.js +2 -1
  164. package/dist/application-spec/generate-application/code/templates/tsconfig.d.ts +5 -0
  165. package/dist/application-spec/generate-application/code/templates/tsconfig.js +1 -1
  166. package/dist/application-spec/generate-application/code/templates/webhook-builders.js +9 -4
  167. package/dist/application-spec/generate-application/code/templates/webhook-index.d.ts +6 -1
  168. package/dist/application-spec/generate-application/code/templates/webhook-index.js +10 -1
  169. package/dist/application-spec/generate-application/code/templates/webhooks-config.js +2 -3
  170. package/dist/application-spec/generate-application/implementations/phx-application-types.d.ts +25 -0
  171. package/dist/application-spec/generate-application/implementations/phx-application-types.js +1 -0
  172. package/dist/application-spec/generate-application/implementations/phx-domain.d.ts +36 -0
  173. package/dist/application-spec/generate-application/implementations/phx-domain.js +1 -0
  174. package/dist/application-spec/generate-application/implementations/phx-model.d.ts +24 -0
  175. package/dist/application-spec/generate-application/implementations/phx-model.js +1 -0
  176. package/dist/application-spec/generate-application/implementations/phx.d.ts +22 -0
  177. package/dist/application-spec/generate-application/implementations/phx.js +1 -0
  178. package/dist/application-spec/generate-application/index.d.ts +4 -0
  179. package/dist/application-spec/generate-application/index.js +1 -1
  180. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-model-runtime.d.ts +6 -4
  181. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-model-runtime.js +1 -1
  182. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-runtime.d.ts +12 -4
  183. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-runtime.js +1 -1
  184. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-spec-runtime.d.ts +16 -0
  185. package/dist/application-spec/generate-application/runtime/admin-runtime/admin-spec-runtime.js +1 -0
  186. package/dist/application-spec/generate-application/runtime/admin-runtime/states-runtime.d.ts +2 -2
  187. package/dist/application-spec/generate-application/runtime/application-runtime.d.ts +35 -10
  188. package/dist/application-spec/generate-application/runtime/application-runtime.js +1 -1
  189. package/dist/application-spec/generate-application/runtime/application-spec-slice.d.ts +71 -0
  190. package/dist/application-spec/generate-application/runtime/application-spec-slice.js +1 -0
  191. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-model-runtime.d.ts +7 -5
  192. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-model-runtime.js +1 -1
  193. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.d.ts +14 -7
  194. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.js +1 -1
  195. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-spec-runtime.d.ts +16 -0
  196. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-spec-runtime.js +1 -0
  197. package/dist/application-spec/generate-application/runtime/configurator-runtime/states-runtime.d.ts +2 -2
  198. package/dist/application-spec/generate-application/runtime/create-application.d.ts +57 -0
  199. package/dist/application-spec/generate-application/runtime/create-application.js +1 -0
  200. package/dist/application-spec/generate-application/runtime/factory-data/factory-data-runtime.d.ts +43 -0
  201. package/dist/application-spec/generate-application/runtime/factory-data/factory-data-runtime.js +1 -0
  202. package/dist/application-spec/generate-application/runtime/factory-data/index.d.ts +3 -0
  203. package/dist/application-spec/generate-application/runtime/factory-data/index.js +1 -0
  204. package/dist/application-spec/generate-application/runtime/factory-data/recipe-defaults.d.ts +13 -0
  205. package/dist/application-spec/generate-application/runtime/factory-data/recipe-defaults.js +1 -0
  206. package/dist/application-spec/generate-application/runtime/factory-data/static-violations.d.ts +16 -0
  207. package/dist/application-spec/generate-application/runtime/factory-data/static-violations.js +1 -0
  208. package/dist/application-spec/generate-application/runtime/index.d.ts +8 -0
  209. package/dist/application-spec/generate-application/runtime/index.js +1 -0
  210. package/dist/application-spec/generate-application/runtime/migrations/index.d.ts +1 -0
  211. package/dist/application-spec/generate-application/runtime/migrations/index.js +1 -0
  212. package/dist/application-spec/generate-application/runtime/migrations/migration-runtime.d.ts +53 -0
  213. package/dist/application-spec/generate-application/runtime/migrations/migration-runtime.js +1 -0
  214. package/dist/application-spec/generate-application/runtime/sections/actions-runtime.d.ts +14 -0
  215. package/dist/application-spec/generate-application/runtime/sections/actions-runtime.js +1 -0
  216. package/dist/application-spec/generate-application/runtime/sections/assistant-runtime.d.ts +5 -4
  217. package/dist/application-spec/generate-application/runtime/sections/assistant-runtime.js +1 -1
  218. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.d.ts +3 -2
  219. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.js +1 -1
  220. package/dist/application-spec/generate-application/runtime/sections/build-user-bound-optic.d.ts +2 -1
  221. package/dist/application-spec/generate-application/runtime/sections/build-user-bound-optic.js +1 -1
  222. package/dist/application-spec/generate-application/runtime/sections/component-optic.d.ts +5 -1
  223. package/dist/application-spec/generate-application/runtime/sections/component-optic.js +1 -1
  224. package/dist/application-spec/generate-application/runtime/sections/data-runtime.d.ts +4 -4
  225. package/dist/application-spec/generate-application/runtime/sections/expression-runtime.d.ts +15 -6
  226. package/dist/application-spec/generate-application/runtime/sections/expression-runtime.js +1 -1
  227. package/dist/application-spec/generate-application/runtime/sections/generate-memo-eval-plan-runtime.d.ts +9 -5
  228. package/dist/application-spec/generate-application/runtime/sections/generate-memo-eval-plan-runtime.js +1 -1
  229. package/dist/application-spec/generate-application/runtime/sections/index.d.ts +1 -0
  230. package/dist/application-spec/generate-application/runtime/sections/index.js +1 -1
  231. package/dist/application-spec/generate-application/runtime/sections/reflection-constants-runtime.d.ts +3 -1
  232. package/dist/application-spec/generate-application/runtime/sections/reflection-constants-runtime.js +1 -1
  233. package/dist/application-spec/generate-application/runtime/sections/theme-runtime.d.ts +2 -2
  234. package/dist/application-spec/generate-application/runtime/sections/transformers-runtime.d.ts +4 -6
  235. package/dist/application-spec/generate-application/runtime/spec-code/index.d.ts +2 -0
  236. package/dist/application-spec/generate-application/runtime/spec-code/index.js +1 -0
  237. package/dist/application-spec/generate-application/runtime/spec-code/resolve-spec-code.d.ts +18 -0
  238. package/dist/application-spec/generate-application/runtime/spec-code/resolve-spec-code.js +1 -0
  239. package/dist/application-spec/generate-application/runtime/spec-code/spec-code-module.d.ts +17 -0
  240. package/dist/application-spec/generate-application/runtime/spec-runtime.d.ts +21 -0
  241. package/dist/application-spec/generate-application/runtime/spec-runtime.js +1 -0
  242. package/dist/application-spec/generate-application/runtime-spec/decode-runtime-spec.d.ts +9 -0
  243. package/dist/application-spec/generate-application/runtime-spec/decode-runtime-spec.js +1 -0
  244. package/dist/application-spec/generate-application/runtime-spec/encode-runtime-spec.d.ts +8 -0
  245. package/dist/application-spec/generate-application/runtime-spec/encode-runtime-spec.js +1 -0
  246. package/dist/application-spec/generate-application/runtime-spec/encoded-runtime-spec.d.ts +28 -0
  247. package/dist/application-spec/generate-application/runtime-spec/encoded-runtime-spec.js +1 -0
  248. package/dist/application-spec/generate-application/runtime-spec/index.d.ts +5 -0
  249. package/dist/application-spec/generate-application/runtime-spec/index.js +1 -0
  250. package/dist/application-spec/generate-application/runtime-spec/runtime-spec.d.ts +103 -0
  251. package/dist/application-spec/generate-application/runtime-spec/runtime-spec.js +1 -0
  252. package/dist/application-spec/generate-application/runtime-spec/spec-code-id.d.ts +40 -0
  253. package/dist/application-spec/generate-application/runtime-spec/spec-code-id.js +1 -0
  254. package/dist/application-spec/index.d.ts +1 -0
  255. package/dist/application-spec/index.js +1 -1
  256. package/dist/application-spec/parse-application-files/categorize/categorize-files.d.ts +37 -1
  257. package/dist/application-spec/parse-application-files/categorize/categorize-files.js +1 -1
  258. package/dist/application-spec/parse-application-files/categorize/earlier-generated-editor-configs.d.ts +16 -0
  259. package/dist/application-spec/parse-application-files/categorize/earlier-generated-editor-configs.js +9 -0
  260. package/dist/application-spec/parse-application-files/categorize/earlier-generated-tsconfig.d.ts +9 -0
  261. package/dist/application-spec/parse-application-files/categorize/earlier-generated-tsconfig.js +1 -0
  262. package/dist/application-spec/parse-application-files/categorize/module-analysis.d.ts +1 -1
  263. package/dist/application-spec/parse-application-files/categorize/module-analysis.js +1 -1
  264. package/dist/application-spec/parse-application-files/merge/index.d.ts +1 -0
  265. package/dist/application-spec/parse-application-files/merge/index.js +1 -1
  266. package/dist/application-spec/parse-application-files/merge/merged-actions.d.ts +11 -0
  267. package/dist/application-spec/parse-application-files/merge/merged-actions.js +1 -0
  268. package/dist/application-spec/parse-application-files/merge/merged-spec.d.ts +2 -0
  269. package/dist/application-spec/parse-application-files/merge/merged-spec.js +1 -1
  270. package/dist/application-spec/parse-application-files/raw-spec/index.d.ts +1 -0
  271. package/dist/application-spec/parse-application-files/raw-spec/index.js +1 -1
  272. package/dist/application-spec/parse-application-files/raw-spec/parse-yaml-spec-file.js +1 -1
  273. package/dist/application-spec/parse-application-files/raw-spec/raw-actions.d.ts +18 -0
  274. package/dist/application-spec/parse-application-files/raw-spec/raw-actions.js +1 -0
  275. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.d.ts +59 -4
  276. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.js +1 -1
  277. package/dist/application-spec/parse-application-files/raw-spec/raw-spec-file.d.ts +2 -0
  278. package/dist/application-spec/parse-application-files/raw-spec/raw-spec-file.js +1 -1
  279. package/dist/application-spec/parse-application-files/resolve/resolve-import-modules.js +1 -1
  280. package/dist/application-spec/parse-application-files/spec/application/admin-spec/admin-spec.js +1 -1
  281. package/dist/application-spec/parse-application-files/spec/application/application-spec.js +1 -1
  282. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/configurator-spec.d.ts +4 -2
  283. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/configurator-spec.js +1 -1
  284. package/dist/application-spec/parse-application-files/spec/common/index.d.ts +2 -0
  285. package/dist/application-spec/parse-application-files/spec/common/index.js +1 -1
  286. package/dist/application-spec/parse-application-files/spec/common/schema-ref-resolver.d.ts +23 -0
  287. package/dist/application-spec/parse-application-files/spec/common/schema-ref-resolver.js +1 -0
  288. package/dist/application-spec/parse-application-files/spec/common/value-type/format-value-type.d.ts +3 -0
  289. package/dist/application-spec/parse-application-files/spec/common/value-type/format-value-type.js +1 -0
  290. package/dist/application-spec/parse-application-files/spec/common/value-type/index.d.ts +5 -0
  291. package/dist/application-spec/parse-application-files/spec/common/value-type/index.js +1 -0
  292. package/dist/application-spec/parse-application-files/spec/common/value-type/intersect-value-types.d.ts +6 -0
  293. package/dist/application-spec/parse-application-files/spec/common/value-type/intersect-value-types.js +1 -0
  294. package/dist/application-spec/parse-application-files/spec/common/value-type/is-assignable-value-type.d.ts +8 -0
  295. package/dist/application-spec/parse-application-files/spec/common/value-type/is-assignable-value-type.js +1 -0
  296. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type-at.d.ts +10 -0
  297. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type-at.js +1 -0
  298. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type.d.ts +98 -0
  299. package/dist/application-spec/parse-application-files/spec/common/value-type/value-type.js +1 -0
  300. package/dist/application-spec/parse-application-files/spec/components/bindings/component-path.d.ts +13 -0
  301. package/dist/application-spec/parse-application-files/spec/components/bindings/component-path.js +1 -0
  302. package/dist/application-spec/parse-application-files/spec/components/bindings/index.d.ts +2 -0
  303. package/dist/application-spec/parse-application-files/spec/components/bindings/index.js +1 -1
  304. package/dist/application-spec/parse-application-files/spec/components/bindings/read-binding-type.d.ts +24 -0
  305. package/dist/application-spec/parse-application-files/spec/components/bindings/read-binding-type.js +1 -0
  306. package/dist/application-spec/parse-application-files/spec/components/component-entry.d.ts +1 -9
  307. package/dist/application-spec/parse-application-files/spec/components/component-entry.js +1 -1
  308. package/dist/application-spec/parse-application-files/spec/components/component-filter.d.ts +1 -54
  309. package/dist/application-spec/parse-application-files/spec/components/component-filter.js +1 -1
  310. package/dist/application-spec/parse-application-files/spec/components/component-state-type.d.ts +8 -0
  311. package/dist/application-spec/parse-application-files/spec/components/component-state-type.js +1 -0
  312. package/dist/application-spec/parse-application-files/spec/components/filter-criterion-types.d.ts +13 -0
  313. package/dist/application-spec/parse-application-files/spec/components/filter-criterion-types.js +1 -0
  314. package/dist/application-spec/parse-application-files/spec/components/index.d.ts +1 -1
  315. package/dist/application-spec/parse-application-files/spec/components/index.js +1 -1
  316. package/dist/application-spec/parse-application-files/spec/components/static-entity-id.d.ts +14 -0
  317. package/dist/application-spec/parse-application-files/spec/components/static-entity-id.js +1 -0
  318. package/dist/application-spec/parse-application-files/spec/components/user-component-entry.d.ts +6 -0
  319. package/dist/application-spec/parse-application-files/spec/components/user-component-entry.js +1 -1
  320. package/dist/application-spec/parse-application-files/spec/components/user-components.d.ts +7 -4
  321. package/dist/application-spec/parse-application-files/spec/components/user-components.js +1 -1
  322. package/dist/application-spec/parse-application-files/spec/expressions/expression-read-types.d.ts +24 -0
  323. package/dist/application-spec/parse-application-files/spec/expressions/expression-read-types.js +1 -0
  324. package/dist/application-spec/parse-application-files/spec/expressions/expression-read.d.ts +13 -0
  325. package/dist/application-spec/parse-application-files/spec/expressions/expression-value-type.d.ts +9 -0
  326. package/dist/application-spec/parse-application-files/spec/expressions/expression-value-type.js +1 -0
  327. package/dist/application-spec/parse-application-files/spec/expressions/expression.d.ts +1 -28
  328. package/dist/application-spec/parse-application-files/spec/expressions/expression.js +1 -1
  329. package/dist/application-spec/parse-application-files/spec/expressions/expressions.d.ts +7 -3
  330. package/dist/application-spec/parse-application-files/spec/expressions/expressions.js +1 -1
  331. package/dist/application-spec/parse-application-files/spec/expressions/index.d.ts +0 -1
  332. package/dist/application-spec/parse-application-files/spec/expressions/index.js +1 -1
  333. package/dist/application-spec/parse-application-files/spec/expressions/memo-eval-plan.js +1 -1
  334. package/dist/application-spec/parse-application-files/spec/expressions/user-expressions.d.ts +3 -1
  335. package/dist/application-spec/parse-application-files/spec/expressions/user-expressions.js +1 -1
  336. package/dist/application-spec/parse-application-files/spec/invariants/invariants.d.ts +2 -2
  337. package/dist/application-spec/parse-application-files/spec/invariants/invariants.js +1 -1
  338. package/dist/application-spec/parse-application-files/spec/model/defaults.d.ts +7 -2
  339. package/dist/application-spec/parse-application-files/spec/model/defaults.js +1 -1
  340. package/dist/application-spec/parse-application-files/spec/model/index.d.ts +1 -0
  341. package/dist/application-spec/parse-application-files/spec/model/index.js +1 -1
  342. package/dist/application-spec/parse-application-files/spec/model/model-type-resolution.d.ts +10 -0
  343. package/dist/application-spec/parse-application-files/spec/model/model-type-resolution.js +1 -0
  344. package/dist/application-spec/parse-application-files/spec/model/names/action-name.d.ts +10 -0
  345. package/dist/application-spec/parse-application-files/spec/model/names/action-name.js +1 -0
  346. package/dist/application-spec/parse-application-files/spec/model/names/index.d.ts +1 -0
  347. package/dist/application-spec/parse-application-files/spec/model/names/index.js +1 -1
  348. package/dist/application-spec/parse-application-files/spec/relations/reference-field-type.d.ts +25 -0
  349. package/dist/application-spec/parse-application-files/spec/relations/reference-field-type.js +1 -0
  350. package/dist/application-spec/parse-application-files/spec/relations/relation-field-mismatch.d.ts +46 -0
  351. package/dist/application-spec/parse-application-files/spec/relations/relation-field-mismatch.js +1 -0
  352. package/dist/application-spec/parse-application-files/spec/relations/relations.d.ts +4 -3
  353. package/dist/application-spec/parse-application-files/spec/relations/relations.js +1 -1
  354. package/dist/application-spec/parse-application-files/spec/sections/actions.d.ts +35 -0
  355. package/dist/application-spec/parse-application-files/spec/sections/actions.js +1 -0
  356. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-field-type.d.ts +5 -21
  357. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-field-type.js +1 -1
  358. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-form-elements.d.ts +9 -0
  359. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-form-elements.js +1 -0
  360. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.d.ts +18 -40
  361. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.js +1 -1
  362. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-server-settings.d.ts +2 -2
  363. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant.d.ts +5 -19
  364. package/dist/application-spec/parse-application-files/spec/sections/index.d.ts +1 -0
  365. package/dist/application-spec/parse-application-files/spec/sections/index.js +1 -1
  366. package/dist/application-spec/parse-application-files/spec/sections/infra.d.ts +2 -0
  367. package/dist/application-spec/parse-application-files/spec/sections/infra.js +1 -1
  368. package/dist/client/authorized-client.d.ts +3 -1
  369. package/dist/client/authorized-client.js +1 -1
  370. package/dist/client/contract.d.ts +34 -0
  371. package/dist/client/contract.js +1 -1
  372. package/dist/client/index.d.ts +2 -2
  373. package/dist/client/index.js +1 -1
  374. package/dist/client/local-authorized-client.d.ts +3 -1
  375. package/dist/client/local-authorized-client.js +1 -1
  376. package/dist/client/memory-authorized-client.d.ts +3 -1
  377. package/dist/client/memory-authorized-client.js +1 -1
  378. package/dist/client/phoenix-api.d.ts +761 -57
  379. package/dist/configurator/ConfiguratorApp.js +1 -1
  380. package/dist/configurator/app-loader-content/DefaultAppLoaderContent.d.ts +2 -0
  381. package/dist/configurator/app-loader-content/DefaultAppLoaderContent.js +5 -0
  382. package/dist/configurator/app-loader-content/index.d.ts +1 -0
  383. package/dist/configurator/app-loader-content/index.js +1 -0
  384. package/dist/configurator/application-runtime/extensions/configurator-extension-systems.d.ts +2 -1
  385. package/dist/configurator/application-runtime/extensions/configurator-extension-systems.js +1 -1
  386. package/dist/configurator/application-runtime/extensions/create-configurator-extensions.js +1 -1
  387. package/dist/configurator/application-runtime/extensions/selectors.d.ts +5 -2
  388. package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
  389. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +305 -0
  390. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -0
  391. package/dist/configurator/application-runtime/extensions/systems/assistant-system/browser-details.d.ts +17 -0
  392. package/dist/configurator/application-runtime/extensions/systems/assistant-system/browser-details.js +1 -0
  393. package/dist/configurator/application-runtime/extensions/systems/assistant-system/change-recorder.d.ts +85 -0
  394. package/dist/configurator/application-runtime/extensions/systems/assistant-system/change-recorder.js +1 -0
  395. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.d.ts +192 -0
  396. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.js +1 -0
  397. package/dist/configurator/application-runtime/extensions/systems/camera-control-system/camera-control-system.d.ts +1 -1
  398. package/dist/configurator/application-runtime/extensions/systems/canvas-system.d.ts +8 -0
  399. package/dist/configurator/application-runtime/extensions/systems/canvas-system.js +1 -1
  400. package/dist/configurator/application-runtime/extensions/systems/drag-and-drop-system/drag-and-drop-system.d.ts +3 -3
  401. package/dist/configurator/application-runtime/extensions/systems/export-system/export-busy-error.d.ts +8 -0
  402. package/dist/configurator/application-runtime/extensions/systems/export-system/export-busy-error.js +1 -0
  403. package/dist/configurator/application-runtime/extensions/systems/export-system/export-system.d.ts +23 -1
  404. package/dist/configurator/application-runtime/extensions/systems/export-system/export-system.js +1 -1
  405. package/dist/configurator/application-runtime/extensions/systems/graphql-system/close-unclosed-braces.d.ts +12 -0
  406. package/dist/configurator/application-runtime/extensions/systems/graphql-system/close-unclosed-braces.js +1 -0
  407. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.d.ts +18 -1
  408. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.js +1 -1
  409. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.d.ts +80 -8
  410. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.js +1 -1
  411. package/dist/configurator/application-runtime/extensions/systems/graphql-system/inject-assistant-lenses.d.ts +11 -0
  412. package/dist/configurator/application-runtime/extensions/systems/graphql-system/inject-assistant-lenses.js +1 -0
  413. package/dist/configurator/application-runtime/extensions/systems/graphql-system/side-effects.d.ts +9 -0
  414. package/dist/configurator/application-runtime/extensions/systems/graphql-system/side-effects.js +1 -0
  415. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/image-rendering-system.d.ts +14 -5
  416. package/dist/configurator/application-runtime/extensions/systems/image-rendering-system/image-rendering-system.js +1 -1
  417. package/dist/configurator/application-runtime/extensions/systems/index.d.ts +2 -1
  418. package/dist/configurator/application-runtime/extensions/systems/index.js +1 -1
  419. package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.d.ts +4 -2
  420. package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.js +1 -1
  421. package/dist/configurator/common/configurator-interface.d.ts +145 -5
  422. package/dist/configurator/common/configurator-interface.js +1 -1
  423. package/dist/configurator/common/index.d.ts +3 -1
  424. package/dist/configurator/common/index.js +1 -1
  425. package/dist/configurator/common/use-reset-camera.d.ts +6 -0
  426. package/dist/configurator/common/use-reset-camera.js +1 -0
  427. package/dist/configurator/configuration-not-found-page/BuiltInConfigurationNotFoundPage.d.ts +5 -0
  428. package/dist/configurator/configuration-not-found-page/BuiltInConfigurationNotFoundPage.js +1 -0
  429. package/dist/configurator/configuration-not-found-page/ConfigurationNotFoundPageElement.d.ts +6 -0
  430. package/dist/configurator/configuration-not-found-page/ConfigurationNotFoundPageElement.js +1 -0
  431. package/dist/configurator/configuration-not-found-page/index.d.ts +2 -0
  432. package/dist/configurator/configuration-not-found-page/index.js +1 -0
  433. package/dist/configurator/configurator-context/ConfiguratorResponsiveProvider.d.ts +12 -0
  434. package/dist/configurator/configurator-context/ConfiguratorResponsiveProvider.js +1 -0
  435. package/dist/configurator/configurator-context/PresetSelectionProvider.js +1 -1
  436. package/dist/configurator/configurator-context/PreviewContextProvider.js +1 -1
  437. package/dist/configurator/configurator-context/ViewportStateSync.d.ts +2 -2
  438. package/dist/configurator/configurator-context/ViewportStateSync.js +1 -1
  439. package/dist/configurator/configurator-context/configurator-hooks/layout-hooks.d.ts +11 -1
  440. package/dist/configurator/configurator-context/configurator-routing/ConfiguratorRoutingProvider.js +1 -1
  441. package/dist/configurator/configurator-error-page/BuiltInConfiguratorErrorPage.d.ts +6 -0
  442. package/dist/configurator/configurator-error-page/BuiltInConfiguratorErrorPage.js +1 -0
  443. package/dist/configurator/configurator-error-page/ConfiguratorErrorPageElement.d.ts +7 -0
  444. package/dist/configurator/configurator-error-page/ConfiguratorErrorPageElement.js +1 -0
  445. package/dist/configurator/configurator-error-page/index.d.ts +2 -0
  446. package/dist/configurator/configurator-error-page/index.js +1 -0
  447. package/dist/configurator/index.d.ts +10 -1
  448. package/dist/configurator/index.js +1 -1
  449. package/dist/configurator/pages/ConfiguratorErrorPage.d.ts +0 -1
  450. package/dist/configurator/pages/ConfiguratorErrorPage.js +1 -1
  451. package/dist/configurator/pages/ConfiguratorNotFoundPage.js +1 -1
  452. package/dist/configurator/pages/DefaultConfiguratorLayout.d.ts +7 -0
  453. package/dist/configurator/pages/DefaultConfiguratorLayout.js +1 -0
  454. package/dist/configurator/pages/DefaultNotAuthenticatedPage.d.ts +8 -0
  455. package/dist/configurator/pages/DefaultNotAuthenticatedPage.js +1 -0
  456. package/dist/configurator/pages/DefaultPresetUi.d.ts +7 -0
  457. package/dist/configurator/pages/DefaultPresetUi.js +1 -0
  458. package/dist/configurator/pages/LoadedConfiguratorDetailPage.js +1 -1
  459. package/dist/configurator/pages/NewConfiguratorPage.js +1 -1
  460. package/dist/configurator/pages/PresetCreationErrorPage.d.ts +1 -1
  461. package/dist/configurator/pages/PresetCreationErrorPage.js +1 -1
  462. package/dist/configurator/pages/RootPage.js +1 -1
  463. package/dist/configurator/pages/configurator-layout-name.d.ts +2 -0
  464. package/dist/configurator/pages/configurator-layout-name.js +1 -0
  465. package/dist/configurator/pages/default-configurator-elements.d.ts +13 -0
  466. package/dist/configurator/pages/default-configurator-elements.js +1 -0
  467. package/dist/configurator/pages/default-elements/built-in-entity-element.d.ts +10 -0
  468. package/dist/configurator/pages/default-elements/built-in-entity-element.js +1 -0
  469. package/dist/configurator/pages/default-elements/built-in-layout-element.d.ts +10 -0
  470. package/dist/configurator/pages/default-elements/built-in-layout-element.js +1 -0
  471. package/dist/configurator/pages/default-elements/domain-control-elements.d.ts +6 -0
  472. package/dist/configurator/pages/default-elements/domain-control-elements.js +1 -0
  473. package/dist/configurator/pages/default-elements/index.d.ts +5 -0
  474. package/dist/configurator/pages/default-elements/index.js +1 -0
  475. package/dist/configurator/pages/default-elements/recipe-panel-elements.d.ts +3 -0
  476. package/dist/configurator/pages/default-elements/recipe-panel-elements.js +1 -0
  477. package/dist/configurator/pages/default-elements/scene-controls/BuiltInAddEntityFab.d.ts +3 -0
  478. package/dist/configurator/pages/default-elements/scene-controls/BuiltInAddEntityFab.js +1 -0
  479. package/dist/configurator/pages/default-elements/scene-controls/BuiltInDeleteEntityFab.d.ts +3 -0
  480. package/dist/configurator/pages/default-elements/scene-controls/BuiltInDeleteEntityFab.js +1 -0
  481. package/dist/configurator/pages/default-elements/scene-controls/BuiltInNavigationHotspot.d.ts +3 -0
  482. package/dist/configurator/pages/default-elements/scene-controls/BuiltInNavigationHotspot.js +1 -0
  483. package/dist/configurator/pages/default-elements/scene-controls/BuiltInSelectionHotspot.d.ts +3 -0
  484. package/dist/configurator/pages/default-elements/scene-controls/BuiltInSelectionHotspot.js +1 -0
  485. package/dist/configurator/pages/default-elements/scene-controls/BuiltInToolMenuFab.d.ts +3 -0
  486. package/dist/configurator/pages/default-elements/scene-controls/BuiltInToolMenuFab.js +1 -0
  487. package/dist/configurator/pages/default-elements/scene-controls/index.d.ts +6 -0
  488. package/dist/configurator/pages/default-elements/scene-controls/index.js +1 -0
  489. package/dist/configurator/pages/default-elements/scene-controls/scene-control-elements.d.ts +6 -0
  490. package/dist/configurator/pages/default-elements/scene-controls/scene-control-elements.js +1 -0
  491. package/dist/configurator/pages/default-elements/sidebar-footer-elements.d.ts +7 -0
  492. package/dist/configurator/pages/default-elements/sidebar-footer-elements.js +1 -0
  493. package/dist/configurator/pages/default-elements/toolbar-elements.d.ts +7 -0
  494. package/dist/configurator/pages/default-elements/toolbar-elements.js +1 -0
  495. package/dist/configurator/pages/error-boundaries/GeneralErrorBoundary.js +1 -1
  496. package/dist/configurator/pages/error-boundaries/LoadingErrorBoundary.js +1 -1
  497. package/dist/configurator/pages/index.d.ts +1 -0
  498. package/dist/configurator/pages/index.js +1 -1
  499. package/dist/configurator/preset-screen-elements/PresetDeviceNotSupportedElement.d.ts +4 -0
  500. package/dist/configurator/preset-screen-elements/PresetDeviceNotSupportedElement.js +1 -0
  501. package/dist/configurator/preset-screen-elements/PresetPageActionElement.d.ts +4 -0
  502. package/dist/configurator/preset-screen-elements/PresetPageActionElement.js +1 -0
  503. package/dist/configurator/preset-screen-elements/index.d.ts +2 -0
  504. package/dist/configurator/preset-screen-elements/index.js +1 -0
  505. package/dist/configurator/scene/index.d.ts +1 -0
  506. package/dist/configurator/scene/index.js +1 -1
  507. package/dist/configurator/scene/scene-analytics/scene-analytics.d.ts +2 -2
  508. package/dist/configurator/scene/scene-controls/DeleteEntityFab.js +1 -1
  509. package/dist/configurator/scene/scene-controls/SelectionHotspot.js +1 -1
  510. package/dist/configurator/scene/scene-controls/ToolFab.d.ts +4 -0
  511. package/dist/configurator/scene/scene-controls/ToolFab.js +1 -1
  512. package/dist/configurator/scene/scene-controls/hotspot-drag-handle/HotspotDragHandle.d.ts +1 -1
  513. package/dist/configurator/scene/scene-controls/hotspot-drag-handle/HotspotDragSceneHandle.d.ts +1 -1
  514. package/dist/configurator/scene/scene-controls/use-scene-control-tooltip.d.ts +2 -1
  515. package/dist/configurator/scene/scene-entity/dimension-indicators/DimensionIndicator.d.ts +1 -1
  516. package/dist/configurator/scene/scene-entity/dimension-indicators/DimensionIndicatorInternal.d.ts +1 -1
  517. package/dist/configurator/scene/scene-entity/drag-and-drop/shared.d.ts +2 -2
  518. package/dist/configurator/scene/scene-entity/drag-and-drop/use-drag-object.d.ts +1 -1
  519. package/dist/configurator/scene/scene-entity/materials/RemoteReplacedMaterial.js +1 -1
  520. package/dist/configurator/scene/scene-entity/objects/SceneEntityObjectTextDecal.d.ts +1 -1
  521. package/dist/configurator/scene/scene-entity/scene-controls/SceneEntityHtmlHotspots.js +1 -1
  522. package/dist/configurator/toolbar-actions/index.d.ts +3 -0
  523. package/dist/configurator/toolbar-actions/index.js +1 -0
  524. package/dist/configurator/toolbar-actions/use-assistant-panel.d.ts +18 -0
  525. package/dist/configurator/toolbar-actions/use-assistant-panel.js +1 -0
  526. package/dist/configurator/toolbar-actions/use-measurements.d.ts +35 -0
  527. package/dist/configurator/toolbar-actions/use-measurements.js +1 -0
  528. package/dist/configurator/toolbar-actions/use-toolbar-actions.d.ts +100 -0
  529. package/dist/configurator/toolbar-actions/use-toolbar-actions.js +1 -0
  530. package/dist/configurator/toolbar-actions/use-toolbar-help.d.ts +7 -0
  531. package/dist/configurator/toolbar-actions/use-toolbar-help.js +1 -0
  532. package/dist/configurator/ui/assistant/AssistantChips.d.ts +18 -0
  533. package/dist/configurator/ui/assistant/AssistantChips.js +1 -0
  534. package/dist/configurator/ui/assistant/AssistantComposer.d.ts +7 -0
  535. package/dist/configurator/ui/assistant/AssistantComposer.js +1 -0
  536. package/dist/configurator/ui/assistant/AssistantMarkdown.d.ts +12 -0
  537. package/dist/configurator/ui/assistant/AssistantMarkdown.js +1 -0
  538. package/dist/configurator/ui/assistant/AssistantPanel.d.ts +11 -0
  539. package/dist/configurator/ui/assistant/AssistantPanel.js +1 -0
  540. package/dist/configurator/ui/assistant/AssistantThread.d.ts +10 -0
  541. package/dist/configurator/ui/assistant/AssistantThread.js +1 -0
  542. package/dist/configurator/ui/assistant/alert/AssistantAlert.d.ts +8 -0
  543. package/dist/configurator/ui/assistant/alert/AssistantAlert.js +1 -0
  544. package/dist/configurator/ui/assistant/alert/index.d.ts +2 -0
  545. package/dist/configurator/ui/assistant/alert/index.js +1 -0
  546. package/dist/configurator/ui/assistant/alert/remark-alerts.d.ts +10 -0
  547. package/dist/configurator/ui/assistant/alert/remark-alerts.js +1 -0
  548. package/dist/configurator/ui/assistant/assistant-failure.d.ts +18 -0
  549. package/dist/configurator/ui/assistant/assistant-failure.js +1 -0
  550. package/dist/configurator/ui/assistant/entity-link/AssistantEntityLink.d.ts +13 -0
  551. package/dist/configurator/ui/assistant/entity-link/AssistantEntityLink.js +1 -0
  552. package/dist/configurator/ui/assistant/entity-link/entity-link-selection.d.ts +22 -0
  553. package/dist/configurator/ui/assistant/entity-link/entity-link-selection.js +1 -0
  554. package/dist/configurator/ui/assistant/entity-link/entity-link-state.d.ts +27 -0
  555. package/dist/configurator/ui/assistant/entity-link/entity-link-state.js +1 -0
  556. package/dist/configurator/ui/assistant/entity-link/index.d.ts +2 -0
  557. package/dist/configurator/ui/assistant/entity-link/index.js +1 -0
  558. package/dist/configurator/ui/assistant/form/AssistantForm.d.ts +19 -0
  559. package/dist/configurator/ui/assistant/form/AssistantForm.js +1 -0
  560. package/dist/configurator/ui/assistant/form/compose-answer.d.ts +11 -0
  561. package/dist/configurator/ui/assistant/form/compose-answer.js +1 -0
  562. package/dist/configurator/ui/assistant/form/describe-build-errors.d.ts +6 -0
  563. package/dist/configurator/ui/assistant/form/describe-build-errors.js +1 -0
  564. package/dist/configurator/ui/assistant/form/form-model.d.ts +37 -0
  565. package/dist/configurator/ui/assistant/form/form-state.d.ts +4 -0
  566. package/dist/configurator/ui/assistant/form/index.d.ts +4 -0
  567. package/dist/configurator/ui/assistant/form/index.js +1 -0
  568. package/dist/configurator/ui/assistant/form/parse-form-block.d.ts +10 -0
  569. package/dist/configurator/ui/assistant/form/parse-form-block.js +1 -0
  570. package/dist/configurator/ui/assistant/form/read-form-attributes.d.ts +13 -0
  571. package/dist/configurator/ui/assistant/form/read-form-attributes.js +1 -0
  572. package/dist/configurator/ui/assistant/form/registry/built-in-form-elements.d.ts +3 -0
  573. package/dist/configurator/ui/assistant/form/registry/built-in-form-elements.js +1 -0
  574. package/dist/configurator/ui/assistant/form/registry/create-assistant-form-element.d.ts +31 -0
  575. package/dist/configurator/ui/assistant/form/registry/create-assistant-form-element.js +1 -0
  576. package/dist/configurator/ui/assistant/form/registry/form-element-definition.d.ts +16 -0
  577. package/dist/configurator/ui/assistant/form/registry/form-element-definition.js +1 -0
  578. package/dist/configurator/ui/assistant/form/registry/form-registry.d.ts +31 -0
  579. package/dist/configurator/ui/assistant/form/registry/form-registry.js +1 -0
  580. package/dist/configurator/ui/assistant/form/registry/index.d.ts +6 -0
  581. package/dist/configurator/ui/assistant/form/registry/index.js +1 -0
  582. package/dist/configurator/ui/assistant/form/registry/use-form-registry.d.ts +8 -0
  583. package/dist/configurator/ui/assistant/form/registry/use-form-registry.js +1 -0
  584. package/dist/configurator/ui/assistant/form-elements/FormCard.d.ts +9 -0
  585. package/dist/configurator/ui/assistant/form-elements/FormCard.js +1 -0
  586. package/dist/configurator/ui/assistant/form-elements/FormConfirm.d.ts +9 -0
  587. package/dist/configurator/ui/assistant/form-elements/FormConfirm.js +1 -0
  588. package/dist/configurator/ui/assistant/form-elements/FormGroup.d.ts +6 -0
  589. package/dist/configurator/ui/assistant/form-elements/FormGroup.js +1 -0
  590. package/dist/configurator/ui/assistant/form-elements/FormNumber.d.ts +9 -0
  591. package/dist/configurator/ui/assistant/form-elements/FormNumber.js +1 -0
  592. package/dist/configurator/ui/assistant/form-elements/FormOptions.d.ts +6 -0
  593. package/dist/configurator/ui/assistant/form-elements/FormOptions.js +1 -0
  594. package/dist/configurator/ui/assistant/form-elements/FormReply.d.ts +6 -0
  595. package/dist/configurator/ui/assistant/form-elements/FormReply.js +1 -0
  596. package/dist/configurator/ui/assistant/form-elements/FormSwatch.d.ts +10 -0
  597. package/dist/configurator/ui/assistant/form-elements/FormSwatch.js +1 -0
  598. package/dist/configurator/ui/assistant/form-elements/FormText.d.ts +6 -0
  599. package/dist/configurator/ui/assistant/form-elements/FormText.js +1 -0
  600. package/dist/configurator/ui/assistant/form-elements/clamp-form-number.d.ts +10 -0
  601. package/dist/configurator/ui/assistant/form-elements/clamp-form-number.js +1 -0
  602. package/dist/configurator/ui/assistant/form-elements/form-element-props.d.ts +38 -0
  603. package/dist/configurator/ui/assistant/form-elements/index.d.ts +9 -0
  604. package/dist/configurator/ui/assistant/form-elements/index.js +1 -0
  605. package/dist/configurator/ui/assistant/index.d.ts +5 -0
  606. package/dist/configurator/ui/assistant/index.js +1 -0
  607. package/dist/configurator/ui/assistant/reference-link/AssistantReferenceLink.d.ts +16 -0
  608. package/dist/configurator/ui/assistant/reference-link/AssistantReferenceLink.js +1 -0
  609. package/dist/configurator/ui/assistant/reference-link/assistant-link-target.d.ts +34 -0
  610. package/dist/configurator/ui/assistant/reference-link/assistant-link-target.js +1 -0
  611. package/dist/configurator/ui/assistant/reference-link/assistant-reference-details.d.ts +25 -0
  612. package/dist/configurator/ui/assistant/reference-link/assistant-reference-details.js +1 -0
  613. package/dist/configurator/ui/assistant/reference-link/index.d.ts +3 -0
  614. package/dist/configurator/ui/assistant/reference-link/index.js +1 -0
  615. package/dist/configurator/ui/assistant/reference-link/reference-styles.d.ts +12 -0
  616. package/dist/configurator/ui/assistant/reference-link/reference-styles.js +1 -0
  617. package/dist/configurator/ui/assistant/reference-link/use-assistant-reference-details.d.ts +8 -0
  618. package/dist/configurator/ui/assistant/reference-link/use-assistant-reference-details.js +1 -0
  619. package/dist/configurator/ui/assistant/resource-image/AssistantImage.d.ts +9 -0
  620. package/dist/configurator/ui/assistant/resource-image/AssistantImage.js +1 -0
  621. package/dist/configurator/ui/assistant/resource-image/index.d.ts +3 -0
  622. package/dist/configurator/ui/assistant/resource-image/index.js +1 -0
  623. package/dist/configurator/ui/assistant/resource-image/resource-path.d.ts +2 -0
  624. package/dist/configurator/ui/assistant/resource-image/resource-path.js +1 -0
  625. package/dist/configurator/ui/assistant/resource-image/use-resource-image-url.d.ts +5 -0
  626. package/dist/configurator/ui/assistant/resource-image/use-resource-image-url.js +1 -0
  627. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.d.ts +9 -0
  628. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.js +1 -0
  629. package/dist/configurator/ui/assistant/screenshots/index.d.ts +2 -0
  630. package/dist/configurator/ui/assistant/screenshots/index.js +1 -0
  631. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.d.ts +14 -0
  632. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.js +1 -0
  633. package/dist/configurator/ui/assistant/streamed-markdown.d.ts +8 -0
  634. package/dist/configurator/ui/assistant/streamed-markdown.js +2 -0
  635. package/dist/configurator/ui/assistant/theme.d.ts +2 -0
  636. package/dist/configurator/ui/assistant/theme.js +1 -0
  637. package/dist/configurator/ui/assistant/thread-items.d.ts +55 -0
  638. package/dist/configurator/ui/assistant/thread-items.js +1 -0
  639. package/dist/configurator/ui/assistant/tool-chip.d.ts +44 -0
  640. package/dist/configurator/ui/assistant/tool-chip.js +1 -0
  641. package/dist/configurator/ui/assistant/use-follow-stream.d.ts +17 -0
  642. package/dist/configurator/ui/assistant/use-follow-stream.js +1 -0
  643. package/dist/configurator/ui/assistant/use-is-assistant-panel-open.d.ts +5 -0
  644. package/dist/configurator/ui/assistant/use-is-assistant-panel-open.js +1 -0
  645. package/dist/configurator/ui/configurator-layout/sidebar-keys/index.d.ts +1 -0
  646. package/dist/configurator/ui/configurator-layout/sidebar-keys/index.js +1 -0
  647. package/dist/configurator/ui/configurator-layout/sidebar-keys/sidebar-keys.d.ts +11 -0
  648. package/dist/configurator/ui/configurator-layout/sidebar-keys/sidebar-keys.js +1 -0
  649. package/dist/configurator/ui/configurator-layout/slots/canvas/LayoutCanvas.js +1 -1
  650. package/dist/configurator/ui/configurator-layout/slots/canvas/SharedCanvas.js +1 -1
  651. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/DesktopSidebar.d.ts +101 -0
  652. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/DesktopSidebar.js +16 -0
  653. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/index.d.ts +1 -0
  654. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/index.js +1 -0
  655. package/dist/configurator/ui/configurator-layout/slots/mobile-tabs/use-mobile-tabs.d.ts +1 -1
  656. package/dist/configurator/ui/configurator-layout/slots/mobile-tabs/use-mobile-tabs.js +1 -1
  657. package/dist/configurator/ui/configurator-layout/slots/services/InvariantViolations.d.ts +4 -4
  658. package/dist/configurator/ui/configurator-layout/slots/services/InvariantViolations.js +1 -1
  659. package/dist/configurator/ui/configurator-layout/slots/services/Services.js +1 -1
  660. package/dist/configurator/ui/configurator-layout/slots/services/SideEffects.d.ts +3 -6
  661. package/dist/configurator/ui/configurator-layout/slots/services/SideEffects.js +1 -1
  662. package/dist/configurator/ui/configurator-layout/slots/sidebar-tabs/use-sidebar-tabs.d.ts +1 -1
  663. package/dist/configurator/ui/configurator-layout/slots/sidebar-tabs/use-sidebar-tabs.js +1 -1
  664. package/dist/configurator/ui/configurator-layout/slots/slots.d.ts +1 -0
  665. package/dist/configurator/ui/configurator-layout/slots/slots.js +1 -1
  666. package/dist/configurator/ui/configurator-layout/universal/DesktopLayout.d.ts +0 -74
  667. package/dist/configurator/ui/configurator-layout/universal/DesktopLayout.js +5 -20
  668. package/dist/configurator/ui/configurator-layout/universal/DesktopPreview.js +1 -1
  669. package/dist/configurator/ui/configurator-layout/universal/ExportingOverlay.d.ts +5 -0
  670. package/dist/configurator/ui/configurator-layout/universal/ExportingOverlay.js +1 -0
  671. package/dist/configurator/ui/configurator-layout/universal/Layout.js +1 -1
  672. package/dist/configurator/ui/configurator-layout/universal/MobileLayout.d.ts +2 -0
  673. package/dist/configurator/ui/configurator-layout/universal/MobileLayout.js +3 -3
  674. package/dist/configurator/ui/configurator-layout/universal/MobilePreview.js +1 -1
  675. package/dist/configurator/ui/configurator-layout/universal/use-layout-scene-safe-area.d.ts +47 -0
  676. package/dist/configurator/ui/configurator-layout/universal/use-layout-scene-safe-area.js +1 -0
  677. package/dist/configurator/ui/configurator-layout/universal/use-scene-safe-area.d.ts +11 -26
  678. package/dist/configurator/ui/configurator-layout/universal/use-scene-safe-area.js +1 -1
  679. package/dist/configurator/ui/index.d.ts +1 -0
  680. package/dist/configurator/ui/index.js +1 -1
  681. package/dist/configurator/ui/legacy/layout/common/CommonFinalizeButton.js +1 -1
  682. package/dist/configurator/ui/legacy/layout/common/CommonSummaryButton.js +1 -1
  683. package/dist/configurator/ui/legacy/layout/common/CommonTopNavigation.js +1 -1
  684. package/dist/configurator/ui/legacy/layout/common/ReactiveInterfaceLayout.js +1 -1
  685. package/dist/configurator/ui/legacy/layout/common/ResponsiveFinalizeButton.js +1 -1
  686. package/dist/configurator/ui/legacy/layout/common/SummaryReadLayout.js +1 -1
  687. package/dist/configurator/ui/legacy/layout/simple/SimpleOwnerLayout.js +1 -1
  688. package/dist/configurator/ui/legacy/layout/simple/SimpleTopNavigation.js +1 -1
  689. package/dist/configurator/ui/legacy/layout/steps/StepsNavigation.d.ts +2 -2
  690. package/dist/configurator/ui/legacy/layout/steps/StepsNavigation.js +1 -1
  691. package/dist/configurator/ui/legacy/layout/steps/StepsOwnerLayout.js +1 -1
  692. package/dist/configurator/ui/legacy/layout/steps/StepsSidebarFooter.js +1 -1
  693. package/dist/configurator/ui/legacy/layout/tabs/TabsOwnerLayout.js +1 -1
  694. package/dist/configurator/ui/legacy/mobile-controls/MobileControls.d.ts +1 -1
  695. package/dist/configurator/ui/legacy/toolbar/common/DimensionUnitSelector.js +1 -1
  696. package/dist/configurator/ui/legacy/toolbar/common/MeasurementsIndicatorsSwitch.js +1 -1
  697. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/FullscreenToolbarAction.js +1 -1
  698. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/HelpToolbarAction.js +1 -1
  699. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/MeasurementsToolbarAction.js +1 -1
  700. package/dist/configurator/ui/legacy/toolbar/desktop-toolbar/UndoRedoToolbarGroup.js +1 -1
  701. package/dist/configurator/ui/phoenix-layout-elements/AppLoader.d.ts +0 -7
  702. package/dist/configurator/ui/phoenix-layout-elements/AppLoader.js +2 -6
  703. package/dist/configurator/ui/phoenix-layout-elements/AssistantToolbarButton.d.ts +10 -0
  704. package/dist/configurator/ui/phoenix-layout-elements/AssistantToolbarButton.js +1 -0
  705. package/dist/configurator/ui/phoenix-layout-elements/EnterFullscreenToolbarButton.js +1 -1
  706. package/dist/configurator/ui/phoenix-layout-elements/ExitFullscreenToolbarButton.js +1 -1
  707. package/dist/configurator/ui/phoenix-layout-elements/HelpToolbarButton.js +1 -1
  708. package/dist/configurator/ui/phoenix-layout-elements/LanguageMenuAction.js +1 -1
  709. package/dist/configurator/ui/phoenix-layout-elements/LanguageToolbarButton.js +1 -1
  710. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomOwnerUi.d.ts +1 -0
  711. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomOwnerUi.js +1 -1
  712. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomReadUi.d.ts +1 -0
  713. package/dist/configurator/ui/phoenix-layout-elements/LayoutCustomReadUi.js +1 -1
  714. package/dist/configurator/ui/phoenix-layout-elements/MeasurementsMenuAction.js +1 -1
  715. package/dist/configurator/ui/phoenix-layout-elements/MeasurementsToolbarButton.js +1 -1
  716. package/dist/configurator/ui/phoenix-layout-elements/RedoToolbarButton.js +1 -1
  717. package/dist/configurator/ui/phoenix-layout-elements/ShareToolbarButton.js +1 -1
  718. package/dist/configurator/ui/phoenix-layout-elements/UndoToolbarButton.js +1 -1
  719. package/dist/configurator/ui/phoenix-layout-elements/header/common/back-button/use-go-back-action.js +1 -1
  720. package/dist/configurator/ui/phoenix-layout-elements/header/common/horizontal-tabs/DesktopHorizontalTabs.js +1 -1
  721. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/DesktopNavigationSteps.d.ts +1 -1
  722. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/DesktopNavigationSteps.js +1 -1
  723. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/StepsNavigation.d.ts +2 -8
  724. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/StepsNavigation.js +1 -1
  725. package/dist/configurator/ui/phoenix-layout-elements/index.d.ts +9 -1
  726. package/dist/configurator/ui/phoenix-layout-elements/index.js +1 -1
  727. package/dist/configurator/ui/phoenix-layout-elements/measurements/DimensionUnitSelector.js +1 -1
  728. package/dist/configurator/ui/phoenix-layout-elements/measurements/MeasurementsIndicatorsSwitch.js +1 -1
  729. package/dist/configurator/ui/phoenix-layout-elements/share/ShareModal.js +1 -1
  730. package/dist/configurator/ui/phoenix-layout-elements/share/use-share.d.ts +7 -8
  731. package/dist/configurator/ui/phoenix-layout-elements/share/use-share.js +1 -1
  732. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/basic/BasicFinalizeButton.js +1 -1
  733. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/CustomFinalizeButton.js +1 -1
  734. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/EnterSummaryButton.js +1 -1
  735. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/FinalizeActions.js +1 -1
  736. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/NextStepButton.js +1 -1
  737. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/PreviousStepButton.js +1 -1
  738. package/dist/configurator/ui/preset-layout/CategoryPresetUi.js +1 -1
  739. package/dist/configurator/ui/preset-layout/PresetUi.d.ts +4 -2
  740. package/dist/configurator/ui/preset-layout/PresetUi.js +1 -1
  741. package/dist/configurator/ui/preset-layout/index.d.ts +6 -1
  742. package/dist/configurator/ui/preset-layout/index.js +1 -1
  743. package/dist/configurator/ui/save-message-snackbars/SaveMessageSnackbars.d.ts +10 -0
  744. package/dist/configurator/ui/save-message-snackbars/SaveMessageSnackbars.js +1 -0
  745. package/dist/configurator/ui/save-message-snackbars/index.d.ts +1 -0
  746. package/dist/configurator/ui/save-message-snackbars/index.js +1 -0
  747. package/dist/docs/complex-use-cases/filtered-controls-with-fix-dialog.mdx +100 -117
  748. package/dist/docs/complex-use-cases/focus-mode.mdx +2 -0
  749. package/dist/docs/complex-use-cases/navigation-reset-selection.mdx +18 -12
  750. package/dist/docs/complex-use-cases/sketching.mdx +0 -38
  751. package/dist/docs/controls/select-attribute/cardselect.mdx +9 -13
  752. package/dist/docs/controls/select-child-entity/cardselect.mdx +1 -0
  753. package/dist/docs/dimensions/3d-scene-integration/dimension-indicators.mdx +2 -2
  754. package/dist/docs/dimensions/3d-scene-integration/editable-angle-indicator.mdx +1 -1
  755. package/dist/docs/dimensions/3d-scene-integration/editable-distance-dimension-indicator.mdx +1 -1
  756. package/dist/docs/dimensions/3d-scene-integration/list-selector-dimension-indicator.mdx +1 -1
  757. package/dist/docs/drag-and-drop/drag-handle.mdx +1 -1
  758. package/dist/docs/drag-and-drop/hotspot-handle.mdx +1 -1
  759. package/dist/docs/drag-and-drop/planes.mdx +1 -1
  760. package/dist/docs/drag-and-drop/rotatable.mdx +2 -2
  761. package/dist/docs/fabs/basic.mdx +6 -2
  762. package/dist/docs/index.json +147 -2
  763. package/dist/docs/integrations/webcomponent-api/basics.mdx +2 -0
  764. package/dist/docs/integrations/woocommerce/local-development.mdx +1 -1
  765. package/dist/docs/layouts/custom-layout.mdx +2597 -0
  766. package/dist/docs/layouts/custom-price.mdx +14 -16
  767. package/dist/docs/layouts/gallery/ardent-compressor.mdx +3516 -0
  768. package/dist/docs/layouts/gallery/corvid-drone.mdx +3428 -0
  769. package/dist/docs/layouts/gallery/fenwick-window.mdx +2803 -0
  770. package/dist/docs/layouts/gallery/ferrule-bar-station.mdx +6567 -0
  771. package/dist/docs/layouts/gallery/kestrel-kettle.mdx +1858 -0
  772. package/dist/docs/layouts/gallery/nightjar-guitar.mdx +3698 -0
  773. package/dist/docs/layouts/gallery/sunfold-solar.mdx +2683 -0
  774. package/dist/docs/layouts/gallery/tidepool-aquascape.mdx +5203 -0
  775. package/dist/docs/layouts/header/fixed.mdx +2 -2
  776. package/dist/docs/layouts/header/floating.mdx +2 -2
  777. package/dist/docs/layouts/sidebar/in-a-custom-layout.mdx +380 -0
  778. package/dist/docs/layouts/sidebar/tabs.mdx +24 -21
  779. package/dist/docs/layouts/sidebar-footer/basic.mdx +32 -77
  780. package/dist/docs/layouts/toolbar.mdx +6 -0
  781. package/dist/docs/other-features/client-side-rendering/declarative.mdx +2 -2
  782. package/dist/docs/other-features/domain-actions.mdx +418 -0
  783. package/dist/docs/other-features/error-5xx.mdx +1 -1
  784. package/dist/docs/other-features/navigation-hotspot.mdx +2 -0
  785. package/dist/docs/other-features/not-found-404.mdx +1 -1
  786. package/dist/docs/other-features/side-effects.mdx +76 -45
  787. package/dist/docs/other-features/transformers.mdx +5 -1
  788. package/dist/docs/other-features/violation-messages.mdx +52 -56
  789. package/dist/docs/phoenix/admin.mdx +11 -26
  790. package/dist/docs/phoenix/application-states.mdx +9 -7
  791. package/dist/docs/phoenix/best-practices.mdx +1 -0
  792. package/dist/docs/phoenix/clerk-sign-in.mdx +1 -1
  793. package/dist/docs/phoenix/components.mdx +6 -0
  794. package/dist/docs/phoenix/configurator-interface.mdx +402 -81
  795. package/dist/docs/phoenix/deployments.mdx +3 -7
  796. package/dist/docs/phoenix/domain-model.mdx +6 -0
  797. package/dist/docs/phoenix/expression-context.mdx +11 -3
  798. package/dist/docs/phoenix/finalization.mdx +2 -2
  799. package/dist/docs/phoenix/getting-started.mdx +7 -4
  800. package/dist/docs/phoenix/integration/headless-mode-external.mdx +5 -5
  801. package/dist/docs/phoenix/integration/widget-mode-external.mdx +5 -5
  802. package/dist/docs/phoenix/layout-slots.mdx +116 -0
  803. package/dist/docs/phoenix/localization.mdx +13 -28
  804. package/dist/docs/phoenix/migration-guide.mdx +24 -11
  805. package/dist/docs/phoenix/phoenix-cli.mdx +249 -83
  806. package/dist/docs/phoenix/project-structure.mdx +90 -36
  807. package/dist/docs/phoenix/quickstart.mdx +9 -9
  808. package/dist/docs/phoenix/sdk-builder-workflow.mdx +24 -20
  809. package/dist/docs/phoenix/sessions-and-access.mdx +2 -0
  810. package/dist/docs/phoenix/testing.mdx +148 -0
  811. package/dist/docs/phoenix/webhook-membership.mdx +10 -9
  812. package/dist/docs/phoenix/webhooks.mdx +23 -6
  813. package/dist/docs/recipes-and-delete/recipe-hierarchy-selection.mdx +15 -13
  814. package/dist/docs/relations/hierarchy.mdx +13 -2
  815. package/dist/docs/selection-and-highlight/hotspots.mdx +2 -0
  816. package/dist/docs/ux-guidelines/choosing-a-control.mdx +11 -0
  817. package/dist/domain/admin-domain/__generated/enhanced-model.d.ts +1 -2
  818. package/dist/domain/admin-domain/__generated/model/versions/v1.d.ts +1 -1
  819. package/dist/domain/admin-domain/__generated/model/versions/v2.d.ts +1 -1
  820. package/dist/domain/admin-domain/__generated/model/versions/v3.d.ts +1 -1
  821. package/dist/domain/admin-domain/__generated/model/versions/v4.d.ts +1 -1
  822. package/dist/domain/admin-domain/__generated/model/versions/v5.d.ts +1 -1
  823. package/dist/domain/admin-domain/__generated/model/versions/v6.d.ts +2 -2
  824. package/dist/domain/admin-domain/__generated/model/versions/v6.js +1 -1
  825. package/dist/domain/admin-domain/implementation/common-admin-expressions.d.ts +26 -14
  826. package/dist/domain/admin-domain/implementation/common-admin-migrations.d.ts +1 -1
  827. package/dist/domain/admin-domain/implementation/common-admin-publish.d.ts +1 -2
  828. package/dist/domain/admin-domain/index.d.ts +9 -5
  829. package/dist/domain/admin-domain/index.js +1 -1
  830. package/dist/domain/application/GetApplicationWrapperHandler.d.ts +2 -2
  831. package/dist/domain/application/GetThemeHandler.d.ts +1 -1
  832. package/dist/domain/application/GetWebComponentOptions.d.ts +1 -1
  833. package/dist/domain/application/admin-page-factories.d.ts +1 -2
  834. package/dist/domain/application/application-config.d.ts +30 -95
  835. package/dist/domain/application/assistant/assistant-fields.d.ts +12 -0
  836. package/dist/domain/application/assistant/assistant-fields.js +1 -0
  837. package/dist/domain/application/assistant/assistant-manifest.d.ts +86 -0
  838. package/dist/domain/application/assistant/assistant-manifest.js +1 -0
  839. package/dist/domain/application/assistant/assistant-resolved-manifest.d.ts +138 -0
  840. package/dist/domain/application/assistant/assistant-resolved-manifest.js +1 -0
  841. package/dist/domain/application/assistant/assistant-value-type.d.ts +9 -0
  842. package/dist/domain/application/assistant/assistant-value-type.js +1 -0
  843. package/dist/domain/application/assistant/build-assistant-lenses.d.ts +14 -0
  844. package/dist/domain/application/assistant/build-assistant-lenses.js +5 -0
  845. package/dist/domain/application/assistant/build-assistant-manifest.d.ts +4 -0
  846. package/dist/domain/application/assistant/build-assistant-manifest.js +1 -0
  847. package/dist/domain/application/assistant/create-assistant-execution-schema.d.ts +32 -0
  848. package/dist/domain/application/assistant/create-assistant-execution-schema.js +1 -0
  849. package/dist/domain/application/assistant/form/assistant-form-element-name.d.ts +11 -0
  850. package/dist/domain/application/assistant/form/assistant-form-element-name.js +8 -0
  851. package/dist/domain/application/assistant/form/assistant-form-elements.d.ts +174 -0
  852. package/dist/domain/application/assistant/form/assistant-form-elements.js +1 -0
  853. package/dist/domain/application/assistant/form/assistant-resource-path.d.ts +10 -0
  854. package/dist/domain/application/assistant/form/assistant-resource-path.js +1 -0
  855. package/dist/domain/application/assistant/form/index.d.ts +4 -0
  856. package/dist/domain/application/assistant/form/index.js +1 -0
  857. package/dist/domain/application/assistant/generate-assistant-prompt.d.ts +6 -0
  858. package/dist/domain/application/assistant/generate-assistant-prompt.js +1 -0
  859. package/dist/domain/application/assistant/index.d.ts +10 -0
  860. package/dist/domain/application/assistant/index.js +1 -0
  861. package/dist/domain/application/assistant/session-setup/AssistantSetupHandler.d.ts +20 -0
  862. package/dist/domain/application/assistant/session-setup/AssistantSetupHandler.js +1 -0
  863. package/dist/domain/application/assistant/session-setup/apply-assistant-setup.d.ts +10 -0
  864. package/dist/domain/application/assistant/session-setup/apply-assistant-setup.js +1 -0
  865. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.d.ts +50 -0
  866. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.js +1 -0
  867. package/dist/domain/application/assistant/session-setup/create-session-assistant.d.ts +15 -0
  868. package/dist/domain/application/assistant/session-setup/create-session-assistant.js +1 -0
  869. package/dist/domain/application/assistant/session-setup/index.d.ts +4 -0
  870. package/dist/domain/application/assistant/session-setup/index.js +1 -0
  871. package/dist/domain/application/assistant-field-options.d.ts +2 -3
  872. package/dist/domain/application/assistant-mutations.d.ts +16 -17
  873. package/dist/domain/application/assistant-mutations.js +1 -1
  874. package/dist/domain/application/assistant-recipe-groups.d.ts +6 -8
  875. package/dist/domain/application/configurator-builder.d.ts +42 -18
  876. package/dist/domain/application/configurator-builder.js +1 -1
  877. package/dist/domain/application/create-initial-published-data.d.ts +6 -7
  878. package/dist/domain/application/index.d.ts +4 -7
  879. package/dist/domain/application/index.js +1 -1
  880. package/dist/domain/application/published-data/DataRowValidatorHandler.d.ts +1 -1
  881. package/dist/domain/application/published-data/FilterPublishedChunksHandler.d.ts +1 -1
  882. package/dist/domain/application/published-data/MapPublishedChunkedDataHandler.d.ts +1 -1
  883. package/dist/domain/application/published-data/MapPublishedRevisionDataHandler.d.ts +1 -1
  884. package/dist/domain/application/published-data/SheetValidatorHandler.d.ts +1 -1
  885. package/dist/domain/application/published-data/build-legend-data.d.ts +1 -1
  886. package/dist/domain/application/published-data/create-finalize-admin-domain.d.ts +1 -2
  887. package/dist/domain/application/published-data/format-field-type.d.ts +1 -1
  888. package/dist/domain/application/published-data/map-data-to-sheet.d.ts +1 -1
  889. package/dist/domain/application/published-data/map-published-chunked-data.d.ts +3 -3
  890. package/dist/domain/application/published-data/map-published-data.d.ts +7 -4
  891. package/dist/domain/application/published-data/validate-sheet-data.d.ts +1 -1
  892. package/dist/domain/application/standard-properties.js +1 -1
  893. package/dist/domain/application/web-component-property.d.ts +3 -1
  894. package/dist/domain/application/web-component-property.js +1 -1
  895. package/dist/domain/available-system-components.d.ts +1 -1
  896. package/dist/domain/available-system-components.js +1 -1
  897. package/dist/domain/core/action/action-factory.d.ts +11 -0
  898. package/dist/domain/core/action/action-factory.js +1 -0
  899. package/dist/domain/core/action/action.d.ts +71 -0
  900. package/dist/domain/core/action/action.js +1 -0
  901. package/dist/domain/core/action/index.d.ts +2 -0
  902. package/dist/domain/core/action/index.js +1 -0
  903. package/dist/domain/core/component/component-reader-types.d.ts +43 -0
  904. package/dist/domain/core/component/component-reader-types.js +1 -0
  905. package/dist/domain/core/component/debug-state-component.d.ts +14 -0
  906. package/dist/domain/core/component/debug-state-component.js +1 -0
  907. package/dist/domain/core/component/domain-component-optic.d.ts +65 -0
  908. package/dist/domain/core/component/domain-component-optic.js +16 -0
  909. package/dist/domain/core/component/drag-state-component.d.ts +16 -0
  910. package/dist/domain/core/component/drag-state-component.js +1 -0
  911. package/dist/domain/core/component/export-state-component.d.ts +15 -0
  912. package/dist/domain/core/component/export-state-component.js +1 -0
  913. package/dist/domain/core/component/fullscreen-state-component.d.ts +14 -0
  914. package/dist/domain/core/component/fullscreen-state-component.js +1 -0
  915. package/dist/domain/core/component/group-components-by-entity-id-and-name.d.ts +8 -0
  916. package/dist/domain/core/component/group-components-by-entity-id-and-name.js +1 -0
  917. package/dist/domain/core/component/hover-state-component.d.ts +14 -0
  918. package/dist/domain/core/component/hover-state-component.js +1 -0
  919. package/dist/domain/core/component/index.d.ts +18 -0
  920. package/dist/domain/core/component/index.js +1 -0
  921. package/dist/domain/core/component/legacy-filter.d.ts +498 -0
  922. package/dist/domain/core/component/navigation-state-component.d.ts +15 -0
  923. package/dist/domain/core/component/navigation-state-component.js +1 -0
  924. package/dist/domain/core/component/selection-state-component.d.ts +14 -0
  925. package/dist/domain/core/component/selection-state-component.js +1 -0
  926. package/dist/domain/core/component/system-component-builder.d.ts +11 -0
  927. package/dist/domain/core/component/system-component-builder.js +1 -0
  928. package/dist/domain/core/component/system-component-filter.d.ts +811 -0
  929. package/dist/domain/core/component/system-virtual-entity.js +1 -0
  930. package/dist/domain/core/component/tool-state-component.d.ts +14 -0
  931. package/dist/domain/core/component/tool-state-component.js +1 -0
  932. package/dist/domain/core/component/updates.d.ts +123 -0
  933. package/dist/domain/core/component/view-state-component.d.ts +14 -0
  934. package/dist/domain/core/component/view-state-component.js +1 -0
  935. package/dist/domain/core/component/viewport-state-component.d.ts +29 -0
  936. package/dist/domain/core/component/viewport-state-component.js +1 -0
  937. package/dist/domain/core/data-schema/data-cell-value.d.ts +4 -0
  938. package/dist/domain/core/data-schema/data-cell-value.js +1 -0
  939. package/dist/domain/core/data-schema/data-schema-array-field.d.ts +5 -0
  940. package/dist/domain/core/data-schema/data-schema-array-field.js +1 -0
  941. package/dist/domain/core/data-schema/data-schema-field-object.d.ts +4 -0
  942. package/dist/domain/core/data-schema/data-schema-field-object.js +1 -0
  943. package/dist/domain/core/data-schema/data-schema-field.d.ts +2 -0
  944. package/dist/domain/core/data-schema/data-schema-field.js +1 -0
  945. package/dist/domain/core/data-schema/data-schema-localized-field.d.ts +4 -0
  946. package/dist/domain/core/data-schema/data-schema-localized-field.js +1 -0
  947. package/dist/domain/core/data-schema/data-schema-primitive-field.d.ts +5 -0
  948. package/dist/domain/core/data-schema/data-schema-primitive-field.js +1 -0
  949. package/dist/domain/core/data-schema/data-schema.d.ts +2 -0
  950. package/dist/domain/core/data-schema/data-schema.js +1 -0
  951. package/dist/domain/core/data-schema/index.d.ts +7 -0
  952. package/dist/domain/core/data-schema/index.js +1 -0
  953. package/dist/domain/core/decoder/create-decoder.d.ts +6 -0
  954. package/dist/domain/core/decoder/create-decoder.js +1 -0
  955. package/dist/domain/core/decoder/decoder.d.ts +6 -0
  956. package/dist/domain/core/decoder/decoder.js +1 -0
  957. package/dist/domain/core/decoder/index.d.ts +2 -0
  958. package/dist/domain/core/decoder/index.js +1 -0
  959. package/dist/domain/core/domain-factory.d.ts +7 -4
  960. package/dist/domain/core/domain-factory.js +1 -1
  961. package/dist/domain/core/domain.d.ts +4 -5
  962. package/dist/domain/core/domain.js +1 -1
  963. package/dist/domain/core/emission/index.d.ts +8 -0
  964. package/dist/domain/core/emission/index.js +1 -0
  965. package/dist/domain/core/emission/reset-state-emission.d.ts +12 -0
  966. package/dist/domain/core/emission/reset-state-emission.js +1 -0
  967. package/dist/domain/core/emission/state-emission.d.ts +4 -0
  968. package/dist/domain/core/emission/state-emission.js +1 -0
  969. package/dist/domain/core/emission/state-update-emission.d.ts +14 -0
  970. package/dist/domain/core/emission/state-update-emission.js +1 -0
  971. package/dist/domain/core/emission/state-validation-result.d.ts +18 -0
  972. package/dist/domain/core/emission/state-validation-result.js +1 -0
  973. package/dist/domain/core/emission/transformation-log.d.ts +2 -0
  974. package/dist/domain/core/emission/transformation-log.js +1 -0
  975. package/dist/domain/core/emission/transformer-log-entry.d.ts +6 -0
  976. package/dist/domain/core/emission/transformer-log-entry.js +1 -0
  977. package/dist/domain/core/emission/transformer-log.d.ts +11 -0
  978. package/dist/domain/core/emission/transformer-log.js +1 -0
  979. package/dist/domain/core/emission/transformer-phase.d.ts +1 -0
  980. package/dist/domain/core/emission/transformer-phase.js +1 -0
  981. package/dist/domain/core/expression/aliased-expressions.d.ts +10 -0
  982. package/dist/domain/core/expression/aliased-expressions.js +1 -0
  983. package/dist/domain/core/expression/constant-expressions.d.ts +16 -0
  984. package/dist/domain/core/expression/constant-expressions.js +1 -0
  985. package/dist/domain/core/expression/custom-expression.d.ts +25 -0
  986. package/dist/domain/core/expression/custom-expression.js +1 -0
  987. package/dist/domain/core/expression/expression.d.ts +46 -0
  988. package/dist/domain/core/expression/expression.js +1 -0
  989. package/dist/domain/core/expression/index.d.ts +4 -0
  990. package/dist/domain/core/expression/index.js +1 -0
  991. package/dist/domain/core/index.d.ts +13 -16
  992. package/dist/domain/core/index.js +1 -1
  993. package/dist/domain/core/invariant/builtin-invariant.d.ts +5 -0
  994. package/dist/domain/core/invariant/custom-invariants.d.ts +13 -0
  995. package/dist/domain/core/invariant/custom-invariants.js +1 -0
  996. package/dist/domain/core/invariant/index.d.ts +5 -0
  997. package/dist/domain/core/invariant/index.js +1 -0
  998. package/dist/domain/core/invariant/invariants.d.ts +10 -0
  999. package/dist/domain/core/invariant/invariants.js +1 -0
  1000. package/dist/domain/core/invariant/violation-component.js +1 -0
  1001. package/dist/domain/core/invariant/violation.d.ts +133 -0
  1002. package/dist/domain/core/invariant/violation.js +1 -0
  1003. package/dist/domain/core/model/component.d.ts +46 -0
  1004. package/dist/domain/core/model/index.d.ts +6 -0
  1005. package/dist/domain/core/model/index.js +1 -0
  1006. package/dist/domain/core/model/model.d.ts +127 -0
  1007. package/dist/domain/core/model/reflection.d.ts +114 -0
  1008. package/dist/domain/core/model/reflection.js +1 -0
  1009. package/dist/domain/core/recipe/index.d.ts +1 -0
  1010. package/dist/domain/core/recipe/index.js +1 -0
  1011. package/dist/domain/core/recipe/recipes.d.ts +23 -0
  1012. package/dist/domain/core/recipe/recipes.js +1 -0
  1013. package/dist/domain/core/relation/all-of-type-relation.d.ts +19 -0
  1014. package/dist/domain/core/relation/all-of-type-relation.js +1 -0
  1015. package/dist/domain/core/relation/component-factories.d.ts +14 -0
  1016. package/dist/domain/core/relation/component-factories.js +1 -0
  1017. package/dist/domain/core/relation/composed-of.d.ts +12 -0
  1018. package/dist/domain/core/relation/composed-of.js +1 -0
  1019. package/dist/domain/core/relation/direct-relation.d.ts +17 -0
  1020. package/dist/domain/core/relation/index.d.ts +8 -0
  1021. package/dist/domain/core/relation/index.js +1 -0
  1022. package/dist/domain/core/relation/indirect-relation.d.ts +25 -0
  1023. package/dist/domain/core/relation/indirect-relation.js +1 -0
  1024. package/dist/domain/core/relation/reference-component.d.ts +17 -0
  1025. package/dist/domain/core/relation/reference-component.js +1 -0
  1026. package/dist/domain/core/relation/reference-field.d.ts +7 -0
  1027. package/dist/domain/core/relation/reference-field.js +1 -0
  1028. package/dist/domain/core/relation/relation-factory.d.ts +22 -0
  1029. package/dist/domain/core/relation/relation-factory.js +1 -0
  1030. package/dist/domain/core/schema/enhanced-json-schema.js +1 -0
  1031. package/dist/domain/core/schema/extended-schema-validator.js +1 -0
  1032. package/dist/domain/core/schema/index.d.ts +3 -0
  1033. package/dist/domain/core/schema/index.js +1 -0
  1034. package/dist/domain/core/schema/schema-validator.js +1 -0
  1035. package/dist/domain/core/state/id-sequence.d.ts +15 -0
  1036. package/dist/domain/core/state/id-sequence.js +1 -0
  1037. package/dist/domain/core/state/index.d.ts +3 -0
  1038. package/dist/domain/core/state/index.js +1 -0
  1039. package/dist/domain/core/state/migrations.d.ts +67 -0
  1040. package/dist/domain/core/state/migrations.js +1 -0
  1041. package/dist/domain/core/state/state.d.ts +9 -0
  1042. package/dist/domain/domain-builder.d.ts +22 -9
  1043. package/dist/domain/domain-builder.js +1 -1
  1044. package/dist/domain/domain-context/action-system/action-system.d.ts +38 -0
  1045. package/dist/domain/domain-context/action-system/action-system.js +1 -0
  1046. package/dist/domain/domain-context/action-system/index.d.ts +1 -0
  1047. package/dist/domain/domain-context/action-system/index.js +1 -0
  1048. package/dist/domain/domain-context/analytics-system/index.d.ts +2 -0
  1049. package/dist/domain/domain-context/analytics-system/index.js +1 -0
  1050. package/dist/domain/domain-context/create-transformer.d.ts +2 -2
  1051. package/dist/domain/domain-context/dimension-system/dimension-state.js +1 -1
  1052. package/dist/domain/domain-context/dimension-system/dimension-system.d.ts +3 -4
  1053. package/dist/domain/domain-context/dimension-system/dimension-system.js +1 -1
  1054. package/dist/domain/domain-context/dimension-system/index.d.ts +1 -0
  1055. package/dist/domain/domain-context/dimension-system/index.js +1 -0
  1056. package/dist/domain/domain-context/domain-context-systems.d.ts +11 -10
  1057. package/dist/domain/domain-context/index.d.ts +8 -17
  1058. package/dist/domain/domain-context/index.js +1 -1
  1059. package/dist/domain/domain-context/navigation-system/index.d.ts +3 -0
  1060. package/dist/domain/domain-context/navigation-system/index.js +1 -0
  1061. package/dist/domain/domain-context/navigation-system/navigation-system.d.ts +5 -8
  1062. package/dist/domain/domain-context/navigation-system/navigation-system.js +1 -1
  1063. package/dist/domain/domain-context/navigation-system/navigation-updates.d.ts +1 -12
  1064. package/dist/domain/domain-context/navigation-system/navigation-updates.js +1 -1
  1065. package/dist/domain/domain-context/navigation-system/selection-transformers.d.ts +2 -2
  1066. package/dist/domain/domain-context/navigation-system/selection-transformers.js +1 -1
  1067. package/dist/domain/domain-context/recipe-system/index.d.ts +1 -0
  1068. package/dist/domain/domain-context/recipe-system/index.js +1 -0
  1069. package/dist/domain/domain-context/recipe-system/recipe-cooker-system.d.ts +2 -4
  1070. package/dist/domain/domain-context/recipe-system/recipe-cooker-system.js +1 -1
  1071. package/dist/domain/domain-context/relation-transformers/cascade-deletes.d.ts +3 -3
  1072. package/dist/domain/domain-context/relation-transformers/cascade-deletes.js +1 -1
  1073. package/dist/domain/domain-context/relation-transformers/cascade-ref-pruning.d.ts +3 -3
  1074. package/dist/domain/domain-context/relation-transformers/cascade-ref-pruning.js +1 -1
  1075. package/dist/domain/domain-context/relation-transformers/create-entity-refs.d.ts +3 -3
  1076. package/dist/domain/domain-context/relation-transformers/create-entity-refs.js +2 -2
  1077. package/dist/domain/domain-context/relation-transformers/index.d.ts +4 -0
  1078. package/dist/domain/domain-context/relation-transformers/index.js +1 -0
  1079. package/dist/domain/domain-context/relation-transformers/replace-refs.d.ts +3 -3
  1080. package/dist/domain/domain-context/relation-transformers/replace-refs.js +1 -1
  1081. package/dist/domain/domain-context/store-system/apply-updates.d.ts +1 -3
  1082. package/dist/domain/domain-context/store-system/apply-updates.js +1 -1
  1083. package/dist/domain/domain-context/store-system/index.d.ts +4 -0
  1084. package/dist/domain/domain-context/store-system/index.js +1 -0
  1085. package/dist/domain/domain-context/store-system/next-domain-entity-id.d.ts +1 -13
  1086. package/dist/domain/domain-context/store-system/next-domain-entity-id.js +1 -1
  1087. package/dist/domain/domain-context/store-system/reconcile-projected-entities.d.ts +1 -2
  1088. package/dist/domain/domain-context/store-system/reconcile-projected-entities.js +1 -1
  1089. package/dist/domain/domain-context/store-system/store-system.d.ts +7 -39
  1090. package/dist/domain/domain-context/store-system/store-system.js +2 -2
  1091. package/dist/domain/domain-context/store-system/system-state.d.ts +2 -4
  1092. package/dist/domain/domain-context/store-system/system-state.js +1 -1
  1093. package/dist/domain/domain-context/transformers/actions-builder.d.ts +1 -2
  1094. package/dist/domain/domain-context/transformers/actions-builder.js +1 -1
  1095. package/dist/domain/domain-context/transformers/auto-snap-transformer.d.ts +6 -10
  1096. package/dist/domain/domain-context/transformers/auto-snap-transformer.js +1 -1
  1097. package/dist/domain/domain-context/transformers/chain-builder.d.ts +3 -3
  1098. package/dist/domain/domain-context/transformers/context.d.ts +2 -7
  1099. package/dist/domain/domain-context/transformers/context.js +1 -1
  1100. package/dist/domain/domain-context/transformers/entity-builder.d.ts +1 -5
  1101. package/dist/domain/domain-context/transformers/entity-builder.js +1 -1
  1102. package/dist/domain/domain-context/transformers/index.d.ts +1 -1
  1103. package/dist/domain/domain-context/transformers/index.js +1 -1
  1104. package/dist/domain/domain-context/transformers/then-builder.d.ts +1 -2
  1105. package/dist/domain/domain-context/transformers/then-builder.js +1 -1
  1106. package/dist/domain/domain-context/transformers/when-builder.d.ts +3 -9
  1107. package/dist/domain/domain-context/transformers/when-builder.js +1 -1
  1108. package/dist/domain/domain-context/undo-system.d.ts +29 -3
  1109. package/dist/domain/domain-context/undo-system.js +1 -1
  1110. package/dist/domain/domain-runtime/access/selectors.d.ts +9 -0
  1111. package/dist/domain/domain-runtime/access/selectors.js +1 -1
  1112. package/dist/domain/domain-runtime/access/types.d.ts +2 -0
  1113. package/dist/domain/domain-runtime/access/types.js +1 -1
  1114. package/dist/domain/domain-runtime/application.d.ts +39 -0
  1115. package/dist/domain/domain-runtime/application.js +1 -0
  1116. package/dist/domain/domain-runtime/domain-context/action-context.d.ts +11 -0
  1117. package/dist/domain/domain-runtime/domain-context/action-context.js +1 -0
  1118. package/dist/domain/domain-runtime/domain-context/component-reader.d.ts +1 -4
  1119. package/dist/domain/domain-runtime/domain-context/component-reader.js +1 -1
  1120. package/dist/domain/domain-runtime/domain-context/domain-context.js +1 -1
  1121. package/dist/domain/domain-runtime/domain-context/expression-context.d.ts +8 -0
  1122. package/dist/domain/domain-runtime/domain-context/expression-context.js +1 -0
  1123. package/dist/domain/domain-runtime/domain-context/index.d.ts +3 -0
  1124. package/dist/domain/domain-runtime/domain-context/runtime-expression-context.d.ts +18 -0
  1125. package/dist/domain/domain-runtime/domain-context/runtime-expression-context.js +1 -0
  1126. package/dist/domain/domain-runtime/domain-context/selectors.d.ts +23 -24
  1127. package/dist/domain/domain-runtime/domain-context/selectors.js +1 -1
  1128. package/dist/domain/domain-runtime/domain-context/types.d.ts +4 -1
  1129. package/dist/domain/domain-runtime/domain-runtime.d.ts +144 -76
  1130. package/dist/domain/domain-runtime/domain-runtime.js +1 -1
  1131. package/dist/domain/domain-runtime/environment/initialize.d.ts +1 -1
  1132. package/dist/domain/domain-runtime/environment/types.d.ts +1 -1
  1133. package/dist/domain/domain-runtime/errors/implementation-error-collector.d.ts +21 -0
  1134. package/dist/domain/domain-runtime/errors/implementation-error-collector.js +1 -0
  1135. package/dist/domain/domain-runtime/errors/implementation-error.d.ts +46 -0
  1136. package/dist/domain/domain-runtime/errors/implementation-error.js +1 -0
  1137. package/dist/domain/domain-runtime/errors/implementation-errors.d.ts +13 -0
  1138. package/dist/domain/domain-runtime/errors/implementation-errors.js +1 -0
  1139. package/dist/domain/domain-runtime/errors/index.d.ts +4 -0
  1140. package/dist/domain/domain-runtime/errors/index.js +1 -0
  1141. package/dist/domain/domain-runtime/errors/to-implementation-errors.d.ts +10 -0
  1142. package/dist/domain/domain-runtime/errors/to-implementation-errors.js +1 -0
  1143. package/dist/domain/domain-runtime/index.d.ts +2 -0
  1144. package/dist/domain/domain-runtime/index.js +1 -1
  1145. package/dist/domain/domain-runtime/spec/create-violation-expressions.d.ts +24 -0
  1146. package/dist/domain/domain-runtime/spec/create-violation-expressions.js +1 -0
  1147. package/dist/domain/domain-runtime/spec/index.d.ts +5 -0
  1148. package/dist/domain/domain-runtime/spec/index.js +1 -1
  1149. package/dist/domain/domain-runtime/spec/initialize.d.ts +11 -0
  1150. package/dist/domain/domain-runtime/spec/initialize.js +1 -1
  1151. package/dist/domain/domain-runtime/spec/memoize-expression.d.ts +16 -0
  1152. package/dist/domain/domain-runtime/spec/module-checks/element-registration.d.ts +125 -0
  1153. package/dist/domain/domain-runtime/spec/module-checks/element-registration.js +1 -0
  1154. package/dist/domain/domain-runtime/spec/module-checks/find-assistant-form-element-errors.d.ts +12 -0
  1155. package/dist/domain/domain-runtime/spec/module-checks/find-assistant-form-element-errors.js +1 -0
  1156. package/dist/domain/domain-runtime/spec/module-checks/handler-registration.d.ts +34 -0
  1157. package/dist/domain/domain-runtime/spec/module-checks/handler-registration.js +1 -0
  1158. package/dist/domain/domain-runtime/spec/module-checks/index.d.ts +10 -0
  1159. package/dist/domain/domain-runtime/spec/module-checks/index.js +1 -0
  1160. package/dist/domain/domain-runtime/spec/module-checks/merge-expression-modules.d.ts +23 -0
  1161. package/dist/domain/domain-runtime/spec/module-checks/merge-expression-modules.js +1 -0
  1162. package/dist/domain/domain-runtime/spec/module-checks/project-modules.d.ts +32 -0
  1163. package/dist/domain/domain-runtime/spec/module-checks/project-modules.js +1 -0
  1164. package/dist/domain/domain-runtime/spec/module-checks/resolve-action-modules.d.ts +4 -0
  1165. package/dist/domain/domain-runtime/spec/module-checks/resolve-action-modules.js +1 -0
  1166. package/dist/domain/domain-runtime/spec/module-checks/resolve-component-optic-modules.d.ts +4 -0
  1167. package/dist/domain/domain-runtime/spec/module-checks/resolve-component-optic-modules.js +1 -0
  1168. package/dist/domain/domain-runtime/spec/module-checks/resolve-expression-modules.d.ts +14 -0
  1169. package/dist/domain/domain-runtime/spec/module-checks/resolve-expression-modules.js +1 -0
  1170. package/dist/domain/domain-runtime/spec/module-checks/resolve-imported-transformers.d.ts +22 -0
  1171. package/dist/domain/domain-runtime/spec/module-checks/resolve-imported-transformers.js +1 -0
  1172. package/dist/domain/domain-runtime/spec/module-checks/resolve-invariant-modules.d.ts +6 -0
  1173. package/dist/domain/domain-runtime/spec/module-checks/resolve-invariant-modules.js +1 -0
  1174. package/dist/domain/domain-runtime/spec/prepare-action-implementations.d.ts +15 -0
  1175. package/dist/domain/domain-runtime/spec/prepare-action-implementations.js +5 -0
  1176. package/dist/domain/domain-runtime/spec/prepare-domain-expressions.d.ts +16 -0
  1177. package/dist/domain/domain-runtime/spec/selectors.d.ts +10 -9
  1178. package/dist/domain/domain-runtime/spec/selectors.js +1 -1
  1179. package/dist/domain/domain-runtime/spec/types.d.ts +22 -6
  1180. package/dist/domain/domain-runtime/web-component/actions.d.ts +3 -0
  1181. package/dist/domain/domain-runtime/web-component/actions.js +1 -1
  1182. package/dist/domain/domain-runtime/web-component/initialize.d.ts +1 -0
  1183. package/dist/domain/domain-runtime/web-component/initialize.js +1 -1
  1184. package/dist/domain/domain-runtime/web-component/selectors.d.ts +2 -0
  1185. package/dist/domain/domain-runtime/web-component/selectors.js +1 -1
  1186. package/dist/domain/domain-runtime/web-component/types.d.ts +6 -3
  1187. package/dist/domain/extensions/angle-indicator.d.ts +21 -0
  1188. package/dist/domain/extensions/angle-indicator.js +1 -0
  1189. package/dist/domain/extensions/attribute-switch.d.ts +8 -0
  1190. package/dist/domain/extensions/attribute-switch.js +1 -0
  1191. package/dist/domain/extensions/autorotate-camera-component.d.ts +19 -0
  1192. package/dist/domain/extensions/autorotate-camera-component.js +1 -0
  1193. package/dist/domain/extensions/basic-sidebar-footer.d.ts +8 -0
  1194. package/dist/domain/extensions/basic-sidebar-footer.js +1 -0
  1195. package/dist/domain/extensions/camera-based-hidden-entity-object.js +1 -0
  1196. package/dist/domain/extensions/camera-based-hidden-entity.js +1 -0
  1197. package/dist/domain/extensions/canvas-config.d.ts +87 -0
  1198. package/dist/domain/extensions/canvas-config.js +1 -0
  1199. package/dist/domain/extensions/canvas-custom-environment.js +1 -0
  1200. package/dist/domain/extensions/canvas-padding.d.ts +25 -0
  1201. package/dist/domain/extensions/canvas-padding.js +1 -0
  1202. package/dist/domain/extensions/canvas-preset-environment.d.ts +37 -0
  1203. package/dist/domain/extensions/canvas-preset-environment.js +1 -0
  1204. package/dist/domain/extensions/child-entity-recipe-hierarchy.d.ts +21 -0
  1205. package/dist/domain/extensions/child-entity-recipe-hierarchy.js +1 -0
  1206. package/dist/domain/extensions/color-value.js +1 -0
  1207. package/dist/domain/extensions/common/angle-indicator-schema.d.ts +292 -0
  1208. package/dist/domain/extensions/common/angle-indicator-schema.js +1 -0
  1209. package/dist/domain/extensions/common/dimension-indicator-schema.d.ts +607 -0
  1210. package/dist/domain/extensions/common/dimension-indicator-schema.js +1 -0
  1211. package/dist/domain/extensions/common/index.d.ts +4 -0
  1212. package/dist/domain/extensions/common/index.js +1 -0
  1213. package/dist/domain/extensions/custom-header.d.ts +11 -0
  1214. package/dist/domain/extensions/custom-header.js +1 -0
  1215. package/dist/domain/extensions/custom-price-footer.js +1 -0
  1216. package/dist/domain/extensions/custom-sidebar-footer.d.ts +11 -0
  1217. package/dist/domain/extensions/custom-sidebar-footer.js +1 -0
  1218. package/dist/domain/extensions/dimension-indicator.d.ts +31 -0
  1219. package/dist/domain/extensions/dimension-indicator.js +1 -0
  1220. package/dist/domain/extensions/editable-angle-indicator.d.ts +39 -0
  1221. package/dist/domain/extensions/editable-angle-indicator.js +1 -0
  1222. package/dist/domain/extensions/editable-distance-dimension-indicator.d.ts +43 -0
  1223. package/dist/domain/extensions/editable-distance-dimension-indicator.js +1 -0
  1224. package/dist/domain/extensions/editable-offset-indicator.d.ts +42 -0
  1225. package/dist/domain/extensions/editable-offset-indicator.js +1 -0
  1226. package/dist/domain/extensions/editable-size-indicator.d.ts +39 -0
  1227. package/dist/domain/extensions/editable-size-indicator.js +1 -0
  1228. package/dist/domain/extensions/entity-header.d.ts +22 -0
  1229. package/dist/domain/extensions/entity-header.js +1 -0
  1230. package/dist/domain/extensions/exit-tool-mode-fab.d.ts +25 -0
  1231. package/dist/domain/extensions/exit-tool-mode-fab.js +1 -0
  1232. package/dist/domain/extensions/export-images/agent-screenshot.d.ts +24 -0
  1233. package/dist/domain/extensions/export-images/agent-screenshot.js +1 -0
  1234. package/dist/domain/extensions/export-images/client-side-image.d.ts +14 -0
  1235. package/dist/domain/extensions/export-images/client-side-image.js +1 -0
  1236. package/dist/domain/extensions/export-images/index.d.ts +3 -0
  1237. package/dist/domain/extensions/export-images/index.js +1 -0
  1238. package/dist/domain/extensions/export-images/save-template-thumbnail.d.ts +14 -0
  1239. package/dist/domain/extensions/export-images/save-template-thumbnail.js +1 -0
  1240. package/dist/domain/extensions/finalize-action.d.ts +20 -0
  1241. package/dist/domain/extensions/finalize-action.js +1 -0
  1242. package/dist/domain/extensions/finalize-component.js +1 -0
  1243. package/dist/domain/extensions/fit-selection-orthographic-camera-component.js +1 -0
  1244. package/dist/domain/extensions/fit-selection-perspective-camera-component.js +1 -0
  1245. package/dist/domain/extensions/fixed-header.d.ts +10 -0
  1246. package/dist/domain/extensions/fixed-header.js +1 -0
  1247. package/dist/domain/extensions/floating-header.d.ts +10 -0
  1248. package/dist/domain/extensions/floating-header.js +1 -0
  1249. package/dist/domain/extensions/hidden-header.d.ts +8 -0
  1250. package/dist/domain/extensions/hidden-header.js +1 -0
  1251. package/dist/domain/extensions/hidden-sidebar-footer.d.ts +21 -0
  1252. package/dist/domain/extensions/hidden-sidebar-footer.js +1 -0
  1253. package/dist/domain/extensions/horizontal-tabs.d.ts +28 -0
  1254. package/dist/domain/extensions/horizontal-tabs.js +1 -0
  1255. package/dist/domain/extensions/index.d.ts +68 -0
  1256. package/dist/domain/extensions/index.js +1 -0
  1257. package/dist/domain/extensions/list-selector-dimension-indicator.d.ts +31 -0
  1258. package/dist/domain/extensions/list-selector-dimension-indicator.js +1 -0
  1259. package/dist/domain/extensions/multilingual-text-value.js +1 -0
  1260. package/dist/domain/extensions/navigation-steps.d.ts +19 -0
  1261. package/dist/domain/extensions/navigation-steps.js +1 -0
  1262. package/dist/domain/extensions/offset-anchors.d.ts +20 -0
  1263. package/dist/domain/extensions/offset-anchors.js +1 -0
  1264. package/dist/domain/extensions/offset-indicator.d.ts +83 -0
  1265. package/dist/domain/extensions/offset-indicator.js +1 -0
  1266. package/dist/domain/extensions/offset.d.ts +31 -0
  1267. package/dist/domain/extensions/offset.js +1 -0
  1268. package/dist/domain/extensions/other-action.d.ts +14 -0
  1269. package/dist/domain/extensions/other-action.js +1 -0
  1270. package/dist/domain/extensions/property-page.d.ts +16 -0
  1271. package/dist/domain/extensions/property-page.js +1 -0
  1272. package/dist/domain/extensions/read-sidebar-footer.d.ts +8 -0
  1273. package/dist/domain/extensions/read-sidebar-footer.js +1 -0
  1274. package/dist/domain/extensions/replace-entity-recipe-hierarchy.d.ts +21 -0
  1275. package/dist/domain/extensions/replace-entity-recipe-hierarchy.js +1 -0
  1276. package/dist/domain/extensions/rotatable.js +1 -0
  1277. package/dist/domain/extensions/rotation-handle.d.ts +53 -0
  1278. package/dist/domain/extensions/rotation-handle.js +1 -0
  1279. package/dist/domain/extensions/scene-entity-add-fab.d.ts +32 -0
  1280. package/dist/domain/extensions/scene-entity-add-fab.js +1 -0
  1281. package/dist/domain/extensions/scene-entity-animation.js +1 -0
  1282. package/dist/domain/extensions/scene-entity-control.js +1 -0
  1283. package/dist/domain/extensions/scene-entity-delete-fab.d.ts +19 -0
  1284. package/dist/domain/extensions/scene-entity-delete-fab.js +1 -0
  1285. package/dist/domain/extensions/scene-entity-floor-object.js +1 -0
  1286. package/dist/domain/extensions/scene-entity-html-hotspot.d.ts +27 -0
  1287. package/dist/domain/extensions/scene-entity-html-hotspot.js +1 -0
  1288. package/dist/domain/extensions/scene-entity-navigation-hotspot.d.ts +20 -0
  1289. package/dist/domain/extensions/scene-entity-navigation-hotspot.js +1 -0
  1290. package/dist/domain/extensions/scene-entity-object-html-hotspot.d.ts +31 -0
  1291. package/dist/domain/extensions/scene-entity-object-html-hotspot.js +1 -0
  1292. package/dist/domain/extensions/scene-entity-select-hotspot.d.ts +5 -0
  1293. package/dist/domain/extensions/scene-entity-select-hotspot.js +1 -0
  1294. package/dist/domain/extensions/scene-entity-wall-object.js +1 -0
  1295. package/dist/domain/extensions/selectable-component.js +1 -0
  1296. package/dist/domain/extensions/sidebar-tabs.d.ts +29 -0
  1297. package/dist/domain/extensions/sidebar-tabs.js +1 -0
  1298. package/dist/domain/extensions/simple-summary.js +1 -0
  1299. package/dist/domain/extensions/size.d.ts +21 -0
  1300. package/dist/domain/extensions/size.js +1 -0
  1301. package/dist/domain/extensions/sketching-draw.d.ts +17 -0
  1302. package/dist/domain/extensions/sketching-draw.js +1 -0
  1303. package/dist/domain/extensions/sketching-edit.d.ts +28 -0
  1304. package/dist/domain/extensions/sketching-edit.js +1 -0
  1305. package/dist/domain/extensions/summary-component.js +1 -0
  1306. package/dist/domain/extensions/text-value.js +1 -0
  1307. package/dist/domain/extensions/tool-controls.js +1 -0
  1308. package/dist/domain/extensions/tool-menu-fab.d.ts +40 -0
  1309. package/dist/domain/extensions/tool-menu-fab.js +1 -0
  1310. package/dist/domain/extensions/toolbar.d.ts +13 -0
  1311. package/dist/domain/extensions/toolbar.js +1 -0
  1312. package/dist/domain/extensions/universal-sidebar-footer.d.ts +12 -0
  1313. package/dist/domain/extensions/universal-sidebar-footer.js +1 -0
  1314. package/dist/domain/extensions/view-controls.js +1 -0
  1315. package/dist/domain/index.d.ts +2 -30
  1316. package/dist/domain/index.js +1 -1
  1317. package/dist/domain/mocks/create-mock-domain-context.d.ts +1 -1
  1318. package/dist/domain/mocks/create-mock-domain-runtime-services.d.ts +1 -1
  1319. package/dist/domain/mocks/create-mock-domain-runtime.d.ts +45 -21
  1320. package/dist/domain/mocks/create-mock-domain-runtime.js +1 -1
  1321. package/dist/domain/mocks/create-mock-domain.d.ts +1 -1
  1322. package/dist/domain/mocks/create-mock-domain.js +1 -1
  1323. package/dist/domain/mocks/create-mock-state.d.ts +2 -2
  1324. package/dist/domain/mocks/create-test-application-config.d.ts +59 -0
  1325. package/dist/domain/mocks/create-test-application-config.js +1 -0
  1326. package/dist/domain/mocks/index.d.ts +1 -0
  1327. package/dist/domain/mocks/index.js +1 -1
  1328. package/dist/domain/projections/blender-projections/blender-projections.d.ts +2 -3
  1329. package/dist/domain/projections/blender-projections/blender-projections.js +1 -1
  1330. package/dist/domain/projections/blender-projections/camera.d.ts +2 -2
  1331. package/dist/domain/projections/collision-projections.d.ts +1 -1
  1332. package/dist/domain/projections/composition-projections.d.ts +1 -1
  1333. package/dist/domain/projections/composition-projections.js +1 -1
  1334. package/dist/domain/projections/constraint-projections.d.ts +1 -1
  1335. package/dist/domain/projections/index.d.ts +1 -1
  1336. package/dist/domain/projections/position-projections.d.ts +1 -1
  1337. package/dist/domain/projections/projected-entities-projections.d.ts +2 -3
  1338. package/dist/domain/projections/snap-matching.d.ts +1 -2
  1339. package/dist/domain/projections/snap-utils.d.ts +1 -2
  1340. package/dist/domain/projections/snapping-projections.d.ts +1 -1
  1341. package/dist/domain/projections/validation-projections.d.ts +3 -20
  1342. package/dist/domain/projections/validation-projections.js +1 -1
  1343. package/dist/domain/sketching/sketching-projections.d.ts +1 -1
  1344. package/dist/domain/system-components/admin-sidebar.d.ts +1 -1
  1345. package/dist/domain/system-components/admin-sidebar.js +1 -1
  1346. package/dist/domain/system-components/angle-dimension.js +1 -1
  1347. package/dist/domain/system-components/application-config.d.ts +3 -3
  1348. package/dist/domain/system-components/application-config.js +1 -1
  1349. package/dist/domain/system-components/attribute-selection.js +1 -1
  1350. package/dist/domain/system-components/bounding-box-component.d.ts +1 -1
  1351. package/dist/domain/system-components/bounding-box-component.js +1 -1
  1352. package/dist/domain/system-components/bounding-sphere-component.d.ts +1 -1
  1353. package/dist/domain/system-components/bounding-sphere-component.js +1 -1
  1354. package/dist/domain/system-components/child-entity-recipes.d.ts +1 -1
  1355. package/dist/domain/system-components/child-entity-recipes.js +1 -1
  1356. package/dist/domain/system-components/child-entity-selection.d.ts +1 -2
  1357. package/dist/domain/system-components/child-entity-selection.js +1 -1
  1358. package/dist/domain/system-components/collision-box-geometry.d.ts +5 -3
  1359. package/dist/domain/system-components/collision-box-geometry.js +1 -1
  1360. package/dist/domain/system-components/collision-geometries.d.ts +1 -1
  1361. package/dist/domain/system-components/collision-geometry.d.ts +5 -3
  1362. package/dist/domain/system-components/collision-geometry.js +1 -1
  1363. package/dist/domain/system-components/collision-point-geometry.d.ts +5 -3
  1364. package/dist/domain/system-components/collision-point-geometry.js +1 -1
  1365. package/dist/domain/system-components/common/index.d.ts +0 -4
  1366. package/dist/domain/system-components/common/index.js +1 -1
  1367. package/dist/domain/system-components/common/material-override-schema.d.ts +2 -2
  1368. package/dist/domain/system-components/common/recipes.d.ts +21 -4
  1369. package/dist/domain/system-components/common/recipes.js +1 -1
  1370. package/dist/domain/system-components/common/scene-entity-control-schema.d.ts +3 -0
  1371. package/dist/domain/system-components/common/scene-entity-control-schema.js +1 -1
  1372. package/dist/domain/system-components/constraint.d.ts +11 -24
  1373. package/dist/domain/system-components/constraint.js +1 -1
  1374. package/dist/domain/system-components/create-blueprint.d.ts +1 -1
  1375. package/dist/domain/system-components/custom-scene-entity.d.ts +1 -1
  1376. package/dist/domain/system-components/custom-scene-entity.js +1 -1
  1377. package/dist/domain/system-components/detail.js +1 -1
  1378. package/dist/domain/system-components/distance-dimension-select.d.ts +1 -1
  1379. package/dist/domain/system-components/distance-dimension-select.js +1 -1
  1380. package/dist/domain/system-components/distance-dimension.d.ts +1 -1
  1381. package/dist/domain/system-components/distance-dimension.js +1 -1
  1382. package/dist/domain/system-components/drag-handle.d.ts +2 -2
  1383. package/dist/domain/system-components/drag-handle.js +1 -1
  1384. package/dist/domain/system-components/fit-entity-orthographic-camera-component.js +1 -1
  1385. package/dist/domain/system-components/fit-entity-perspective-camera-component.js +1 -1
  1386. package/dist/domain/system-components/fit-root-orthographic-camera-component.js +1 -1
  1387. package/dist/domain/system-components/fit-root-perspective-camera-component.js +1 -1
  1388. package/dist/domain/system-components/generic-dimension.d.ts +1 -1
  1389. package/dist/domain/system-components/generic-dimension.js +1 -1
  1390. package/dist/domain/system-components/hidden-entity.js +1 -1
  1391. package/dist/domain/system-components/hotspot-drag-handle.d.ts +2 -3
  1392. package/dist/domain/system-components/hotspot-drag-handle.js +1 -1
  1393. package/dist/domain/system-components/index.d.ts +0 -68
  1394. package/dist/domain/system-components/index.js +1 -1
  1395. package/dist/domain/system-components/material-override-property-transition.js +1 -1
  1396. package/dist/domain/system-components/material-override-transformer.js +1 -1
  1397. package/dist/domain/system-components/material-swatch.js +1 -1
  1398. package/dist/domain/system-components/navigation-page.js +1 -1
  1399. package/dist/domain/system-components/navigation-panel-list.js +1 -1
  1400. package/dist/domain/system-components/phoenix-entity-elements/admin-data-table-sidebar.d.ts +1 -1
  1401. package/dist/domain/system-components/phoenix-layout-elements/admin-connected-resource-page.d.ts +1 -1
  1402. package/dist/domain/system-components/phoenix-layout-elements/admin-data-table-actions.d.ts +1 -1
  1403. package/dist/domain/system-components/phoenix-layout-elements/admin-data-table-page.d.ts +1 -1
  1404. package/dist/domain/system-components/phoenix-layout-elements/assistant-toolbar-button.d.ts +44 -0
  1405. package/dist/domain/system-components/phoenix-layout-elements/assistant-toolbar-button.js +1 -0
  1406. package/dist/domain/system-components/phoenix-layout-elements/index.d.ts +1 -0
  1407. package/dist/domain/system-components/phoenix-layout-elements/index.js +1 -1
  1408. package/dist/domain/system-components/phoenix-layout-elements/phoenix-layout-element.d.ts +2 -1
  1409. package/dist/domain/system-components/phoenix-layout-elements/phoenix-layout-element.js +1 -1
  1410. package/dist/domain/system-components/pivot-point.d.ts +1 -1
  1411. package/dist/domain/system-components/pivot-point.js +1 -1
  1412. package/dist/domain/system-components/price.js +1 -1
  1413. package/dist/domain/system-components/projected-entities.d.ts +1 -1
  1414. package/dist/domain/system-components/projected-entities.js +1 -1
  1415. package/dist/domain/system-components/replace-entity-recipes.d.ts +1 -1
  1416. package/dist/domain/system-components/replace-entity-recipes.js +1 -1
  1417. package/dist/domain/system-components/scene-entity-ambient-light.js +1 -1
  1418. package/dist/domain/system-components/scene-entity-box-object.js +1 -1
  1419. package/dist/domain/system-components/scene-entity-directional-light.js +1 -1
  1420. package/dist/domain/system-components/scene-entity-local-material-override.js +1 -1
  1421. package/dist/domain/system-components/scene-entity-material-override.d.ts +1 -1
  1422. package/dist/domain/system-components/scene-entity-material-override.js +1 -1
  1423. package/dist/domain/system-components/scene-entity-object-clip.js +1 -1
  1424. package/dist/domain/system-components/scene-entity-object-decal.js +1 -1
  1425. package/dist/domain/system-components/scene-entity-object-group.js +1 -1
  1426. package/dist/domain/system-components/scene-entity-object-local-material-override.js +1 -1
  1427. package/dist/domain/system-components/scene-entity-object-material-override.d.ts +1 -1
  1428. package/dist/domain/system-components/scene-entity-object-material-override.js +1 -1
  1429. package/dist/domain/system-components/scene-entity-object-properties.js +1 -1
  1430. package/dist/domain/system-components/scene-entity-object-remote-material-override.js +1 -1
  1431. package/dist/domain/system-components/scene-entity-object-text-decal.d.ts +1 -1
  1432. package/dist/domain/system-components/scene-entity-object-text-decal.js +1 -1
  1433. package/dist/domain/system-components/scene-entity-object-transformer.js +1 -1
  1434. package/dist/domain/system-components/scene-entity-object-transimissive-material-override.d.ts +1 -1
  1435. package/dist/domain/system-components/scene-entity-object-transimissive-material-override.js +1 -1
  1436. package/dist/domain/system-components/scene-entity-object.js +1 -1
  1437. package/dist/domain/system-components/scene-entity-point-light.js +1 -1
  1438. package/dist/domain/system-components/scene-entity-properties.js +1 -1
  1439. package/dist/domain/system-components/scene-entity-rect-area-light.js +1 -1
  1440. package/dist/domain/system-components/scene-entity-remote-material-override.js +1 -1
  1441. package/dist/domain/system-components/scene-entity-remote-object.js +1 -1
  1442. package/dist/domain/system-components/scene-entity-spot-light.js +1 -1
  1443. package/dist/domain/system-components/scene-entity-transimissive-material-override.d.ts +1 -1
  1444. package/dist/domain/system-components/scene-entity-transimissive-material-override.js +1 -1
  1445. package/dist/domain/system-components/sketching-line.d.ts +1 -1
  1446. package/dist/domain/system-components/sketching-line.js +1 -1
  1447. package/dist/domain/system-components/sketching-rectangle.d.ts +1 -1
  1448. package/dist/domain/system-components/sketching-rectangle.js +1 -1
  1449. package/dist/domain/system-components/sketching.d.ts +1 -1
  1450. package/dist/domain/system-components/sketching.js +1 -1
  1451. package/dist/domain/system-components/snap-axis.d.ts +1 -1
  1452. package/dist/domain/system-components/snap-axis.js +1 -1
  1453. package/dist/domain/system-components/snap-edge.d.ts +1 -1
  1454. package/dist/domain/system-components/snap-edge.js +1 -1
  1455. package/dist/domain/system-components/snap-plane.d.ts +1 -1
  1456. package/dist/domain/system-components/snap-plane.js +1 -1
  1457. package/dist/domain/system-components/snap-point.d.ts +1 -1
  1458. package/dist/domain/system-components/snap-point.js +1 -1
  1459. package/dist/domain/system-components/static-orthographic-camera-component.d.ts +1 -1
  1460. package/dist/domain/system-components/static-orthographic-camera-component.js +1 -1
  1461. package/dist/domain/system-components/static-perspective-camera-component.d.ts +1 -1
  1462. package/dist/domain/system-components/static-perspective-camera-component.js +1 -1
  1463. package/dist/domain/utils/eval-cache.d.ts +2 -3
  1464. package/dist/domain/utils/map-nested-object.d.ts +1 -1
  1465. package/dist/domain/utils/memo-eval.d.ts +2 -4
  1466. package/dist/editor/Editor.d.ts +7 -0
  1467. package/dist/editor/Editor.js +1 -1
  1468. package/dist/editor/domain-editors/DomainSpecContext.js +1 -1
  1469. package/dist/editor/domain-editors/apply-spec-update.d.ts +10 -2
  1470. package/dist/editor/domain-editors/apply-spec-update.js +1 -1
  1471. package/dist/editor/domain-editors/use-implementation-files.d.ts +12 -16
  1472. package/dist/editor/domain-editors/use-implementation-files.js +1 -1
  1473. package/dist/editor/graphql/GraphQLPanel.js +1 -1
  1474. package/dist/editor/mocks/CreateMockYaml.js +2 -2
  1475. package/dist/editor/mocks/EditorMockContext.d.ts +2 -0
  1476. package/dist/editor/mocks/EditorMockContext.js +1 -1
  1477. package/dist/editor/screenshot/ScreenshotHandler.js +1 -1
  1478. package/dist/editor/variants/VariantAnswerFooter.d.ts +17 -0
  1479. package/dist/editor/variants/VariantAnswerFooter.js +1 -0
  1480. package/dist/editor/variants/VariantPreviewHandler.d.ts +6 -0
  1481. package/dist/editor/variants/VariantPreviewHandler.js +1 -0
  1482. package/dist/editor/variants/variant-preview-styles.d.ts +49 -0
  1483. package/dist/editor/variants/variant-preview-styles.js +1 -0
  1484. package/dist/globals/index.d.ts +2 -0
  1485. package/dist/i18n/locales/cs/messages.js +1 -1
  1486. package/dist/i18n/locales/da/messages.js +1 -1
  1487. package/dist/i18n/locales/de/messages.js +1 -1
  1488. package/dist/i18n/locales/de-AT/messages.js +1 -1
  1489. package/dist/i18n/locales/en/messages.js +1 -1
  1490. package/dist/i18n/locales/en-AU/messages.js +1 -1
  1491. package/dist/i18n/locales/en-GB/messages.js +1 -1
  1492. package/dist/i18n/locales/es/messages.js +1 -1
  1493. package/dist/i18n/locales/fr/messages.js +1 -1
  1494. package/dist/i18n/locales/hu/messages.js +1 -1
  1495. package/dist/i18n/locales/it/messages.js +1 -1
  1496. package/dist/i18n/locales/nl/messages.js +1 -1
  1497. package/dist/i18n/locales/pl/messages.js +1 -1
  1498. package/dist/i18n/locales/pt/messages.js +1 -1
  1499. package/dist/i18n/locales/ro/messages.js +1 -1
  1500. package/dist/i18n/locales/sk/messages.js +1 -1
  1501. package/dist/i18n/locales/tr/messages.js +1 -1
  1502. package/dist/legacy/domain-cli/gen/configurator-builder.js +30 -16
  1503. package/dist/legacy/domain-cli/gen/constant-expressions.js +1 -3
  1504. package/dist/legacy/domain-cli/gen/defaults.js +1 -7
  1505. package/dist/legacy/domain-cli/gen/implementation.js +7 -11
  1506. package/dist/legacy/domain-cli/gen/invariants.js +7 -6
  1507. package/dist/legacy/domain-cli/gen/relations.js +1 -1
  1508. package/dist/legacy/domain-cli/utils/cache.d.ts +1 -1
  1509. package/dist/legacy/domain-cli/utils/cache.js +1 -1
  1510. package/dist/legacy/domain-spec/__generated/domain-schema.d.ts +182 -148
  1511. package/dist/legacy/domain-spec/spec/domain-spec.js +1 -1
  1512. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/claude-md.d.ts +1 -1
  1513. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/cursor-rules.d.ts +1 -1
  1514. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.d.ts +1 -1
  1515. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.js +13 -0
  1516. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/domain-index.js +17 -15
  1517. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/env-example.d.ts +1 -1
  1518. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/env-example.js +4 -0
  1519. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/frontend-admin.js +18 -18
  1520. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/frontend-configurator.js +16 -15
  1521. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/frontend-embedded-admin.js +24 -24
  1522. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/frontend-embedded-configurator.js +16 -15
  1523. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/generator-shared.d.ts +7 -2
  1524. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/generator-shared.js +8 -12
  1525. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/index.d.ts +1 -1
  1526. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/index.js +1 -1
  1527. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/webhook-builders.js +7 -7
  1528. package/dist/phoenix/application-spec/application-spec-builder.d.ts +0 -2
  1529. package/dist/phoenix/application-spec/application-spec-builder.js +1 -1
  1530. package/dist/phoenix/application-spec/generate-application-spec-project.d.ts +0 -2
  1531. package/dist/phoenix/application-spec/generate-application-spec-project.js +2 -2
  1532. package/dist/phoenix/application-spec/generate-application-spec-story.js +2 -2
  1533. package/dist/phoenix/application-spec/generate-project-files.d.ts +0 -2
  1534. package/dist/phoenix/application-spec/project-files.js +1 -1
  1535. package/dist/phoenix/application-spec/resolve-deployment-data.d.ts +4 -3
  1536. package/dist/phoenix/application-spec/resolve-deployment-data.js +2 -2
  1537. package/dist/phoenix/bin.d.ts +2 -0
  1538. package/dist/phoenix/bin.js +2 -0
  1539. package/dist/phoenix/check-configs/built-in-eslint-config.d.ts +9 -0
  1540. package/dist/phoenix/check-configs/built-in-eslint-config.js +1 -0
  1541. package/dist/phoenix/check-configs/eslint-config.d.ts +10 -0
  1542. package/dist/phoenix/check-configs/eslint-config.js +1 -0
  1543. package/dist/phoenix/check-configs/index.d.ts +8 -0
  1544. package/dist/phoenix/check-configs/index.js +1 -0
  1545. package/dist/phoenix/check-configs/typescript-project.d.ts +5 -0
  1546. package/dist/phoenix/check-configs/typescript-project.js +1 -0
  1547. package/dist/phoenix/cli.d.ts +0 -1
  1548. package/dist/phoenix/cli.js +1 -2
  1549. package/dist/phoenix/commands/build.d.ts +5 -0
  1550. package/dist/phoenix/commands/build.js +1 -1
  1551. package/dist/phoenix/commands/check.js +1 -1
  1552. package/dist/phoenix/commands/clean.js +1 -1
  1553. package/dist/phoenix/commands/deploy.js +2 -2
  1554. package/dist/phoenix/commands/deps/deps.d.ts +73 -0
  1555. package/dist/phoenix/commands/deps/deps.js +3 -0
  1556. package/dist/phoenix/commands/deps/index.d.ts +1 -0
  1557. package/dist/phoenix/commands/deps/index.js +1 -0
  1558. package/dist/phoenix/commands/deps/sdk-manifest.d.ts +12 -0
  1559. package/dist/phoenix/commands/deps/sdk-manifest.js +1 -0
  1560. package/dist/phoenix/commands/dev.js +5 -5
  1561. package/dist/phoenix/commands/feedback.d.ts +2 -1
  1562. package/dist/phoenix/commands/feedback.js +1 -1
  1563. package/dist/phoenix/commands/fix.js +1 -1
  1564. package/dist/phoenix/commands/index.d.ts +2 -0
  1565. package/dist/phoenix/commands/index.js +1 -1
  1566. package/dist/phoenix/commands/init.d.ts +17 -5
  1567. package/dist/phoenix/commands/init.js +1 -1
  1568. package/dist/phoenix/commands/link.js +1 -1
  1569. package/dist/phoenix/commands/login.d.ts +24 -6
  1570. package/dist/phoenix/commands/login.js +2 -2
  1571. package/dist/phoenix/commands/prepare-deployment-command.js +2 -2
  1572. package/dist/phoenix/commands/prepare-local-environment-command.js +1 -1
  1573. package/dist/phoenix/commands/prettier.js +1 -1
  1574. package/dist/phoenix/commands/story-dev.js +2 -2
  1575. package/dist/phoenix/commands/sync.js +1 -1
  1576. package/dist/phoenix/commands/unlink.js +1 -1
  1577. package/dist/phoenix/commands/variants.d.ts +35 -0
  1578. package/dist/phoenix/commands/variants.js +1 -0
  1579. package/dist/phoenix/editor-server/commands-router.d.ts +68 -1
  1580. package/dist/phoenix/editor-server/commands-router.js +1 -1
  1581. package/dist/phoenix/editor-server/editor-router.d.ts +65 -0
  1582. package/dist/phoenix/editor-server/editor-server.d.ts +3 -3
  1583. package/dist/phoenix/editor-server/editor-server.js +1 -1
  1584. package/dist/phoenix/editor-server/protocol.d.ts +1 -0
  1585. package/dist/phoenix/editor-server/spec-router.js +1 -1
  1586. package/dist/phoenix/editor-server/trpc.d.ts +3 -0
  1587. package/dist/phoenix/scripts/build-admin.js +1 -1
  1588. package/dist/phoenix/services/application-spec-project-watcher.d.ts +15 -4
  1589. package/dist/phoenix/services/application-spec-project-watcher.js +3 -3
  1590. package/dist/phoenix/services/index.d.ts +5 -0
  1591. package/dist/phoenix/services/index.js +1 -1
  1592. package/dist/phoenix/services/lingui.d.ts +8 -0
  1593. package/dist/phoenix/services/lingui.js +1 -1
  1594. package/dist/phoenix/services/phoenix-application.d.ts +21 -0
  1595. package/dist/phoenix/services/phoenix-application.js +1 -0
  1596. package/dist/phoenix/services/phoenix-store.d.ts +48 -0
  1597. package/dist/phoenix/services/phoenix-store.js +1 -0
  1598. package/dist/phoenix/services/phx-banner-plugin.d.ts +32 -0
  1599. package/dist/phoenix/services/phx-banner-plugin.js +1 -0
  1600. package/dist/phoenix/services/phx-licenses-plugin.d.ts +55 -0
  1601. package/dist/phoenix/services/phx-licenses-plugin.js +8 -0
  1602. package/dist/phoenix/services/phx-variant-previews-plugin.d.ts +9 -0
  1603. package/dist/phoenix/services/phx-variant-previews-plugin.js +1 -0
  1604. package/dist/phoenix/services/prepare-development-environment.js +1 -1
  1605. package/dist/phoenix/services/source-archive.d.ts +1 -0
  1606. package/dist/phoenix/services/source-archive.js +1 -1
  1607. package/dist/phoenix/services/swc.js +1 -1
  1608. package/dist/phoenix/services/variant-file-session.d.ts +36 -0
  1609. package/dist/phoenix/services/variant-file-session.js +1 -0
  1610. package/dist/phoenix/services/variant-preview-service.d.ts +80 -0
  1611. package/dist/phoenix/services/variant-preview-service.js +1 -0
  1612. package/dist/phoenix/services/vite-config.d.ts +2 -0
  1613. package/dist/phoenix/services/vite-config.js +1 -1
  1614. package/dist/phoenix/utils/git/index.d.ts +1 -0
  1615. package/dist/phoenix/utils/git/index.js +1 -0
  1616. package/dist/phoenix/utils/git/is-inside-git-repository.d.ts +6 -0
  1617. package/dist/phoenix/utils/git/is-inside-git-repository.js +1 -0
  1618. package/dist/phoenix/utils/index.d.ts +6 -2
  1619. package/dist/phoenix/utils/index.js +1 -1
  1620. package/dist/phoenix/utils/node-version/index.d.ts +1 -0
  1621. package/dist/phoenix/utils/node-version/index.js +1 -0
  1622. package/dist/phoenix/utils/node-version/supported-node-version.d.ts +12 -0
  1623. package/dist/phoenix/utils/node-version/supported-node-version.js +4 -0
  1624. package/dist/phoenix/utils/package-info.d.ts +0 -9
  1625. package/dist/phoenix/utils/package-info.js +1 -1
  1626. package/dist/phoenix/utils/package-manager/index.d.ts +2 -0
  1627. package/dist/phoenix/utils/package-manager/index.js +1 -0
  1628. package/dist/phoenix/utils/package-manager/package-manager-commands.d.ts +19 -0
  1629. package/dist/phoenix/utils/package-manager/package-manager-commands.js +1 -0
  1630. package/dist/phoenix/utils/package-manager/pnpm-project.d.ts +9 -0
  1631. package/dist/phoenix/utils/package-manager/pnpm-project.js +1 -0
  1632. package/dist/phoenix/utils/read-git-commit.d.ts +14 -0
  1633. package/dist/phoenix/utils/read-git-commit.js +1 -0
  1634. package/dist/phoenix/utils/run-command.d.ts +11 -0
  1635. package/dist/phoenix/utils/run-command.js +1 -1
  1636. package/dist/phoenix/utils/sdk-tool/index.d.ts +1 -0
  1637. package/dist/phoenix/utils/sdk-tool/index.js +1 -0
  1638. package/dist/phoenix/utils/sdk-tool/resolve-sdk-tool-bin.d.ts +15 -0
  1639. package/dist/phoenix/utils/sdk-tool/resolve-sdk-tool-bin.js +1 -0
  1640. package/dist/react-sdk/application-runtime/common-services/analytics/analytics-service.d.ts +3 -3
  1641. package/dist/react-sdk/application-runtime/common-services/analytics/domain-controls-analytics.d.ts +21 -21
  1642. package/dist/react-sdk/application-runtime/common-services/analytics/frontend-analytics.d.ts +52 -0
  1643. package/dist/react-sdk/application-runtime/common-services/analytics/frontend-analytics.js +1 -0
  1644. package/dist/react-sdk/application-runtime/common-services/analytics/index.d.ts +1 -0
  1645. package/dist/react-sdk/application-runtime/common-services/analytics/index.js +1 -1
  1646. package/dist/react-sdk/application-runtime/common-services/initialize.d.ts +2 -2
  1647. package/dist/react-sdk/application-runtime/hooks/data/use-published-data.d.ts +1 -1
  1648. package/dist/react-sdk/application-runtime/hooks/index.d.ts +2 -0
  1649. package/dist/react-sdk/application-runtime/hooks/index.js +1 -1
  1650. package/dist/react-sdk/application-runtime/hooks/loading/index.d.ts +5 -0
  1651. package/dist/react-sdk/application-runtime/hooks/loading/index.js +1 -0
  1652. package/dist/react-sdk/application-runtime/hooks/loading/loader-host-context.d.ts +11 -0
  1653. package/dist/react-sdk/application-runtime/hooks/loading/loader-host-context.js +1 -0
  1654. package/dist/react-sdk/application-runtime/hooks/loading/use-is-awaiting-loading-phase.d.ts +8 -0
  1655. package/dist/react-sdk/application-runtime/hooks/loading/use-is-awaiting-loading-phase.js +1 -0
  1656. package/dist/react-sdk/application-runtime/hooks/loading/use-is-loader-hosted.d.ts +7 -0
  1657. package/dist/react-sdk/application-runtime/hooks/loading/use-is-loader-hosted.js +1 -0
  1658. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-actions.d.ts +9 -0
  1659. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-actions.js +1 -0
  1660. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-application.d.ts +24 -0
  1661. package/dist/react-sdk/application-runtime/hooks/loading/use-loading-application.js +1 -0
  1662. package/dist/react-sdk/application-runtime/hooks/responsive/index.d.ts +3 -0
  1663. package/dist/react-sdk/application-runtime/hooks/responsive/index.js +1 -0
  1664. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-actions.d.ts +9 -0
  1665. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-actions.js +1 -0
  1666. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-application.d.ts +26 -0
  1667. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-application.js +1 -0
  1668. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-state.d.ts +10 -0
  1669. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-state.js +1 -0
  1670. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-store.d.ts +24 -0
  1671. package/dist/react-sdk/application-runtime/hooks/responsive/use-responsive-store.js +1 -0
  1672. package/dist/react-sdk/application-runtime/hooks/use-access-service.d.ts +7 -0
  1673. package/dist/react-sdk/application-runtime/hooks/use-access-service.js +1 -1
  1674. package/dist/react-sdk/application-runtime/hooks/use-domain-application-props.d.ts +5 -2
  1675. package/dist/react-sdk/application-runtime/hooks/use-phoenix-element-slots.d.ts +2 -1
  1676. package/dist/react-sdk/application-runtime/hooks/use-spec.d.ts +1 -1
  1677. package/dist/react-sdk/application-runtime/hooks/use-web-component-readonly-sync.d.ts +4 -11
  1678. package/dist/react-sdk/application-runtime/hooks/use-web-component-readonly-sync.js +1 -1
  1679. package/dist/react-sdk/application-runtime/hooks/use-web-component.d.ts +5 -0
  1680. package/dist/react-sdk/application-runtime/hooks/use-web-component.js +1 -1
  1681. package/dist/react-sdk/application-runtime/host-properties/actions.d.ts +15 -0
  1682. package/dist/react-sdk/application-runtime/host-properties/actions.js +1 -0
  1683. package/dist/react-sdk/application-runtime/host-properties/connect-host-properties.d.ts +30 -0
  1684. package/dist/react-sdk/application-runtime/host-properties/connect-host-properties.js +1 -0
  1685. package/dist/react-sdk/application-runtime/host-properties/domain-host-properties.d.ts +7 -0
  1686. package/dist/react-sdk/application-runtime/host-properties/domain-host-properties.js +1 -0
  1687. package/dist/react-sdk/application-runtime/host-properties/host-property-descriptors.d.ts +21 -0
  1688. package/dist/react-sdk/application-runtime/host-properties/host-property-descriptors.js +1 -0
  1689. package/dist/react-sdk/application-runtime/host-properties/host-property-scopes.d.ts +42 -0
  1690. package/dist/react-sdk/application-runtime/host-properties/host-property-scopes.js +1 -0
  1691. package/dist/react-sdk/application-runtime/host-properties/index.d.ts +8 -0
  1692. package/dist/react-sdk/application-runtime/host-properties/index.js +1 -0
  1693. package/dist/react-sdk/application-runtime/host-properties/initialize.d.ts +7 -0
  1694. package/dist/react-sdk/application-runtime/host-properties/initialize.js +1 -0
  1695. package/dist/react-sdk/application-runtime/host-properties/selectors.d.ts +54 -0
  1696. package/dist/react-sdk/application-runtime/host-properties/selectors.js +1 -0
  1697. package/dist/react-sdk/application-runtime/host-properties/types.d.ts +18 -0
  1698. package/dist/react-sdk/application-runtime/host-properties/types.js +1 -0
  1699. package/dist/react-sdk/application-runtime/index.d.ts +3 -0
  1700. package/dist/react-sdk/application-runtime/integration/initialize.d.ts +7 -6
  1701. package/dist/react-sdk/application-runtime/integration/initialize.js +1 -1
  1702. package/dist/react-sdk/application-runtime/integration/selectors.d.ts +11 -2
  1703. package/dist/react-sdk/application-runtime/integration/selectors.js +1 -1
  1704. package/dist/react-sdk/application-runtime/integration/types.d.ts +5 -2
  1705. package/dist/react-sdk/application-runtime/loading/actions.d.ts +45 -0
  1706. package/dist/react-sdk/application-runtime/loading/actions.js +1 -0
  1707. package/dist/react-sdk/application-runtime/loading/index.d.ts +4 -0
  1708. package/dist/react-sdk/application-runtime/loading/index.js +1 -0
  1709. package/dist/react-sdk/application-runtime/loading/initialize.d.ts +3 -0
  1710. package/dist/react-sdk/application-runtime/loading/initialize.js +1 -0
  1711. package/dist/react-sdk/application-runtime/loading/selectors.d.ts +18 -0
  1712. package/dist/react-sdk/application-runtime/loading/selectors.js +1 -0
  1713. package/dist/react-sdk/application-runtime/loading/types.d.ts +59 -0
  1714. package/dist/react-sdk/application-runtime/loading/types.js +1 -0
  1715. package/dist/react-sdk/application-runtime/mocks/create-mock-application-runtime.d.ts +1 -1
  1716. package/dist/react-sdk/application-runtime/mocks/create-mock-application-runtime.js +1 -1
  1717. package/dist/react-sdk/application-runtime/provider/ApplicationRuntime.d.ts +6 -0
  1718. package/dist/react-sdk/application-runtime/provider/ApplicationRuntime.js +1 -1
  1719. package/dist/react-sdk/application-runtime/provider/ApplicationType.d.ts +7 -0
  1720. package/dist/react-sdk/application-runtime/provider/ApplicationType.js +1 -1
  1721. package/dist/react-sdk/application-runtime/responsive/actions.d.ts +47 -0
  1722. package/dist/react-sdk/application-runtime/responsive/actions.js +1 -0
  1723. package/dist/react-sdk/application-runtime/responsive/index.d.ts +4 -0
  1724. package/dist/react-sdk/application-runtime/responsive/index.js +1 -0
  1725. package/dist/react-sdk/application-runtime/responsive/initialize.d.ts +3 -0
  1726. package/dist/react-sdk/application-runtime/responsive/initialize.js +1 -0
  1727. package/dist/react-sdk/application-runtime/responsive/selectors.d.ts +20 -0
  1728. package/dist/react-sdk/application-runtime/responsive/selectors.js +1 -0
  1729. package/dist/react-sdk/application-runtime/responsive/types.d.ts +104 -0
  1730. package/dist/react-sdk/application-runtime/responsive/types.js +1 -0
  1731. package/dist/react-sdk/application-runtime/routing/access-service.d.ts +1 -0
  1732. package/dist/react-sdk/application-runtime/routing/routing-service.d.ts +34 -2
  1733. package/dist/react-sdk/application-runtime/routing/routing-service.js +1 -1
  1734. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.d.ts +382 -50
  1735. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.js +1 -1
  1736. package/dist/react-sdk/domain-application-context/BackendDataProvider.js +1 -1
  1737. package/dist/react-sdk/domain-application-context/DomainLifecycleBoundary.js +1 -1
  1738. package/dist/react-sdk/domain-application-context/FrontendDataProvider.js +1 -1
  1739. package/dist/react-sdk/domain-application-context/PublishedDataProvider.js +1 -1
  1740. package/dist/react-sdk/domain-context/common-hooks/index.d.ts +9 -0
  1741. package/dist/react-sdk/domain-context/common-hooks/index.js +1 -0
  1742. package/dist/react-sdk/domain-context/common-hooks/use-configuration-save-state.d.ts +23 -0
  1743. package/dist/react-sdk/domain-context/common-hooks/use-configuration-save-state.js +1 -0
  1744. package/dist/react-sdk/domain-context/common-hooks/use-configurator-messages.d.ts +41 -0
  1745. package/dist/react-sdk/domain-context/common-hooks/use-configurator-messages.js +1 -0
  1746. package/dist/react-sdk/domain-context/common-hooks/use-domain-context.d.ts +13 -9
  1747. package/dist/react-sdk/domain-context/component-hooks/index.d.ts +1 -0
  1748. package/dist/react-sdk/domain-context/component-hooks/index.js +1 -0
  1749. package/dist/react-sdk/domain-context/component-hooks/use-component.js +1 -1
  1750. package/dist/react-sdk/domain-context/entity-hooks/use-domain-entity-state.js +1 -1
  1751. package/dist/react-sdk/domain-context/entity-hooks/use-entity-price.js +1 -1
  1752. package/dist/react-sdk/domain-context/entity-hooks/use-root-entity-id.js +1 -1
  1753. package/dist/react-sdk/domain-context/entity-hooks/use-root-entity-state.js +1 -1
  1754. package/dist/react-sdk/domain-context/index.d.ts +9 -1
  1755. package/dist/react-sdk/domain-context/index.js +1 -1
  1756. package/dist/react-sdk/domain-context/system-hooks/composition-hooks.js +1 -1
  1757. package/dist/react-sdk/domain-context/system-hooks/dimension-hooks.js +1 -1
  1758. package/dist/react-sdk/domain-context/system-hooks/generate-share-link-hooks.d.ts +8 -0
  1759. package/dist/react-sdk/domain-context/system-hooks/generate-share-link-hooks.js +1 -0
  1760. package/dist/react-sdk/domain-context/system-hooks/hover-hooks.js +1 -1
  1761. package/dist/react-sdk/domain-context/system-hooks/locale-switch-hooks.d.ts +24 -0
  1762. package/dist/react-sdk/domain-context/system-hooks/locale-switch-hooks.js +1 -0
  1763. package/dist/react-sdk/domain-context/system-hooks/navigation-hooks.d.ts +11 -0
  1764. package/dist/react-sdk/domain-context/system-hooks/navigation-hooks.js +1 -1
  1765. package/dist/react-sdk/domain-context/system-hooks/selection-hooks.js +1 -1
  1766. package/dist/react-sdk/domain-context/system-hooks/share-links-hooks.d.ts +32 -0
  1767. package/dist/react-sdk/domain-context/system-hooks/share-links-hooks.js +1 -0
  1768. package/dist/react-sdk/domain-context/system-hooks/step-navigation-hooks.d.ts +57 -0
  1769. package/dist/react-sdk/domain-context/system-hooks/step-navigation-hooks.js +1 -0
  1770. package/dist/react-sdk/domain-context/system-hooks/tab-navigation-hooks.d.ts +61 -0
  1771. package/dist/react-sdk/domain-context/system-hooks/tab-navigation-hooks.js +1 -0
  1772. package/dist/react-sdk/domain-context/system-hooks/undo-redo-hooks.d.ts +20 -0
  1773. package/dist/react-sdk/domain-context/system-hooks/undo-redo-hooks.js +1 -0
  1774. package/dist/react-sdk/domain-controls/hooks/use-angle-dimension.d.ts +1 -1
  1775. package/dist/react-sdk/handlers/FinalizeActionRunner.d.ts +13 -0
  1776. package/dist/react-sdk/handlers/FinalizeActionRunner.js +1 -0
  1777. package/dist/react-sdk/handlers/FinalizeActionsHost.d.ts +10 -0
  1778. package/dist/react-sdk/handlers/FinalizeActionsHost.js +1 -0
  1779. package/dist/react-sdk/handlers/FinalizeActionsProvider.d.ts +11 -0
  1780. package/dist/react-sdk/handlers/FinalizeActionsProvider.js +1 -0
  1781. package/dist/react-sdk/handlers/finalize-actions-context.d.ts +6 -0
  1782. package/dist/react-sdk/handlers/finalize-actions-context.js +1 -0
  1783. package/dist/react-sdk/handlers/finalize-actions-store.d.ts +23 -0
  1784. package/dist/react-sdk/handlers/finalize-actions-store.js +1 -0
  1785. package/dist/react-sdk/handlers/index.d.ts +6 -0
  1786. package/dist/react-sdk/handlers/index.js +1 -1
  1787. package/dist/react-sdk/handlers/use-finalize-action.d.ts +32 -0
  1788. package/dist/react-sdk/handlers/use-finalize-action.js +1 -0
  1789. package/dist/react-sdk/handlers/use-finalize-actions.d.ts +53 -0
  1790. package/dist/react-sdk/handlers/use-finalize-actions.js +1 -0
  1791. package/dist/react-sdk/index.d.ts +2 -0
  1792. package/dist/react-sdk/index.js +1 -1
  1793. package/dist/react-sdk/loading-state/LoaderHost.d.ts +20 -0
  1794. package/dist/react-sdk/loading-state/LoaderHost.js +1 -0
  1795. package/dist/react-sdk/loading-state/built-in-loading-phase.d.ts +9 -0
  1796. package/dist/react-sdk/loading-state/built-in-loading-phase.js +1 -0
  1797. package/dist/react-sdk/loading-state/create-app-loader.d.ts +18 -0
  1798. package/dist/react-sdk/loading-state/create-app-loader.js +1 -0
  1799. package/dist/react-sdk/loading-state/index.d.ts +4 -2
  1800. package/dist/react-sdk/loading-state/index.js +1 -1
  1801. package/dist/react-sdk/loading-state/loading-state-hooks.d.ts +22 -0
  1802. package/dist/react-sdk/loading-state/loading-state-hooks.js +1 -0
  1803. package/dist/react-sdk/page-elements/ConfigurationNotFoundPagePropsProvider.d.ts +17 -0
  1804. package/dist/react-sdk/page-elements/ConfigurationNotFoundPagePropsProvider.js +1 -0
  1805. package/dist/react-sdk/page-elements/ConfiguratorErrorPagePropsProvider.d.ts +17 -0
  1806. package/dist/react-sdk/page-elements/ConfiguratorErrorPagePropsProvider.js +1 -0
  1807. package/dist/react-sdk/page-elements/configurator-error-page-props.d.ts +20 -0
  1808. package/dist/react-sdk/page-elements/configurator-error-page-props.js +1 -0
  1809. package/dist/react-sdk/page-elements/create-configuration-not-found-page.d.ts +15 -0
  1810. package/dist/react-sdk/page-elements/create-configuration-not-found-page.js +1 -0
  1811. package/dist/react-sdk/page-elements/create-configurator-error-page.d.ts +14 -0
  1812. package/dist/react-sdk/page-elements/create-configurator-error-page.js +1 -0
  1813. package/dist/react-sdk/page-elements/create-preset-ui.d.ts +9 -0
  1814. package/dist/react-sdk/page-elements/create-preset-ui.js +1 -0
  1815. package/dist/react-sdk/page-elements/index.d.ts +6 -0
  1816. package/dist/react-sdk/page-elements/index.js +1 -0
  1817. package/dist/react-sdk/scene-control-elements/AddEntityFabElement.d.ts +36 -0
  1818. package/dist/react-sdk/scene-control-elements/AddEntityFabElement.js +1 -0
  1819. package/dist/react-sdk/scene-control-elements/DeleteEntityFabElement.d.ts +44 -0
  1820. package/dist/react-sdk/scene-control-elements/DeleteEntityFabElement.js +1 -0
  1821. package/dist/react-sdk/scene-control-elements/NavigationHotspotElement.d.ts +38 -0
  1822. package/dist/react-sdk/scene-control-elements/NavigationHotspotElement.js +1 -0
  1823. package/dist/react-sdk/scene-control-elements/SelectionHotspotElement.d.ts +30 -0
  1824. package/dist/react-sdk/scene-control-elements/SelectionHotspotElement.js +1 -0
  1825. package/dist/react-sdk/scene-control-elements/ToolMenuFabElement.d.ts +30 -0
  1826. package/dist/react-sdk/scene-control-elements/ToolMenuFabElement.js +1 -0
  1827. package/dist/react-sdk/scene-control-elements/create-add-entity-fab.d.ts +9 -0
  1828. package/dist/react-sdk/scene-control-elements/create-add-entity-fab.js +1 -0
  1829. package/dist/react-sdk/scene-control-elements/create-delete-entity-fab.d.ts +9 -0
  1830. package/dist/react-sdk/scene-control-elements/create-delete-entity-fab.js +1 -0
  1831. package/dist/react-sdk/scene-control-elements/create-navigation-hotspot.d.ts +10 -0
  1832. package/dist/react-sdk/scene-control-elements/create-navigation-hotspot.js +1 -0
  1833. package/dist/react-sdk/scene-control-elements/create-selection-hotspot.d.ts +9 -0
  1834. package/dist/react-sdk/scene-control-elements/create-selection-hotspot.js +1 -0
  1835. package/dist/react-sdk/scene-control-elements/create-tool-menu-fab.d.ts +9 -0
  1836. package/dist/react-sdk/scene-control-elements/create-tool-menu-fab.js +1 -0
  1837. package/dist/react-sdk/scene-control-elements/index.d.ts +11 -0
  1838. package/dist/react-sdk/scene-control-elements/index.js +1 -0
  1839. package/dist/react-sdk/scene-control-elements/scene-control-tooltip-visibility.d.ts +5 -0
  1840. package/dist/react-sdk/scene-control-elements/scene-control-tooltip-visibility.js +1 -0
  1841. package/dist/react-sdk/session/NotAuthenticatedPage.d.ts +4 -0
  1842. package/dist/react-sdk/session/NotAuthenticatedPage.js +1 -1
  1843. package/dist/react-sdk/session/SessionServiceProvider.js +1 -1
  1844. package/dist/react-sdk/web-component/create-web-component.js +1 -1
  1845. package/dist/react-sdk/web-component/god-mode/god-mode-registry.d.ts +30 -0
  1846. package/dist/react-sdk/web-component/god-mode/god-mode-registry.js +1 -0
  1847. package/dist/react-sdk/web-component/god-mode/index.d.ts +1 -0
  1848. package/dist/react-sdk/web-component/god-mode/index.js +1 -0
  1849. package/dist/ui-sdk/common/use-viewport-size.d.ts +4 -1
  1850. package/dist/ui-sdk/common/use-viewport-size.js +1 -1
  1851. package/dist/ui-sdk/components/mobile-controls/index.d.ts +1 -1
  1852. package/dist/ui-sdk/icons/__generated/Lightbulb.d.ts +3 -0
  1853. package/dist/ui-sdk/icons/__generated/Lightbulb.js +1 -0
  1854. package/dist/ui-sdk/icons/__generated/XCircle.d.ts +3 -0
  1855. package/dist/ui-sdk/icons/__generated/XCircle.js +1 -0
  1856. package/dist/ui-sdk/icons/__generated/index.d.ts +4 -0
  1857. package/dist/ui-sdk/icons/__generated/index.js +1 -1
  1858. package/dist/ui-sdk/icons/icons-registry.js +1 -1
  1859. package/dist/ui-sdk/responsive-application/ResponsiveApplicationProvider.d.ts +9 -0
  1860. package/dist/ui-sdk/responsive-application/ResponsiveApplicationProvider.js +1 -1
  1861. package/dist/ui-sdk/responsive-application/index.d.ts +1 -0
  1862. package/dist/ui-sdk/responsive-application/responsive-state-store.d.ts +59 -0
  1863. package/dist/ui-sdk/responsive-application/responsive-state-store.js +1 -0
  1864. package/dist/ui-sdk/responsive-application/use-store-responsive-info.d.ts +7 -0
  1865. package/dist/ui-sdk/responsive-application/use-store-responsive-info.js +1 -0
  1866. package/dist/ui-sdk/theme/types.d.ts +8 -0
  1867. package/dist/webhook/builders/common.d.ts +8 -0
  1868. package/dist/webhook/builders/webhook-builder.d.ts +1 -1
  1869. package/dist/webhook/builders/webhook-builder.js +1 -1
  1870. package/package.json +60 -41
  1871. package/schema/domain-spec.json +1365 -217
  1872. package/dist/application-spec/core/eval-to-constant.d.ts +0 -14
  1873. package/dist/application-spec/generate-application/code/templates/env-ci.d.ts +0 -1
  1874. package/dist/application-spec/generate-application/code/templates/env-ci.js +0 -25
  1875. package/dist/application-spec/generate-application/code/templates/env-example.d.ts +0 -1
  1876. package/dist/application-spec/generate-application/code/templates/env-example.js +0 -90
  1877. package/dist/application-spec/generate-application/code/templates/nvmrc.d.ts +0 -1
  1878. package/dist/application-spec/generate-application/code/templates/nvmrc.js +0 -2
  1879. package/dist/application-spec/generate-application/code/templates/package-json.d.ts +0 -10
  1880. package/dist/application-spec/generate-application/code/templates/package-json.js +0 -1
  1881. package/dist/application-spec/generate-application/code/templates/prettier-ignore.d.ts +0 -1
  1882. package/dist/application-spec/generate-application/code/templates/prettier-ignore.js +0 -6
  1883. package/dist/application-spec/generate-application/code/templates/private-assets-readme.d.ts +0 -1
  1884. package/dist/application-spec/generate-application/code/templates/private-assets-readme.js +0 -24
  1885. package/dist/application-spec/generate-application/code/templates/public-assets-readme.d.ts +0 -1
  1886. package/dist/application-spec/generate-application/code/templates/public-assets-readme.js +0 -24
  1887. package/dist/application-spec/generate-application/code/templates/readme.d.ts +0 -1
  1888. package/dist/application-spec/generate-application/code/templates/readme.js +0 -23
  1889. package/dist/application-spec/generate-application/code/templates/skills/agents-md.d.ts +0 -1
  1890. package/dist/application-spec/generate-application/code/templates/skills/agents-md.js +0 -2
  1891. package/dist/application-spec/generate-application/code/templates/webhook-implementation.d.ts +0 -1
  1892. package/dist/application-spec/generate-application/code/templates/webhook-implementation.js +0 -7
  1893. package/dist/configurator/assistant/browser-details.d.ts +0 -17
  1894. package/dist/configurator/assistant/browser-details.js +0 -1
  1895. package/dist/configurator/assistant/graphql-tools.d.ts +0 -156
  1896. package/dist/configurator/assistant/graphql-tools.js +0 -1
  1897. package/dist/configurator/assistant/index.d.ts +0 -1
  1898. package/dist/configurator/assistant/index.js +0 -1
  1899. package/dist/configurator/assistant/use-assistant-chat.d.ts +0 -20
  1900. package/dist/configurator/assistant/use-assistant-chat.js +0 -1
  1901. package/dist/configurator/common/frontend-analytics.d.ts +0 -46
  1902. package/dist/configurator/common/frontend-analytics.js +0 -1
  1903. package/dist/configurator/ui/phoenix-layout-elements/language/use-locale-options.d.ts +0 -4
  1904. package/dist/configurator/ui/phoenix-layout-elements/language/use-locale-options.js +0 -1
  1905. package/dist/configurator/ui/phoenix-layout-elements/measurements/use-measurements-visibility.d.ts +0 -4
  1906. package/dist/configurator/ui/phoenix-layout-elements/measurements/use-measurements-visibility.js +0 -1
  1907. package/dist/domain/application/element-registration.d.ts +0 -105
  1908. package/dist/domain/application/element-registration.js +0 -1
  1909. package/dist/domain/application/handler-registration.d.ts +0 -29
  1910. package/dist/domain/application/handler-registration.js +0 -1
  1911. package/dist/domain/application/resolve-imported-transformers.d.ts +0 -13
  1912. package/dist/domain/application/resolve-imported-transformers.js +0 -1
  1913. package/dist/domain/application/resource-builder.d.ts +0 -13
  1914. package/dist/domain/application/resource-builder.js +0 -1
  1915. package/dist/domain/components/component-reader-types.d.ts +0 -44
  1916. package/dist/domain/components/debug-state-component.d.ts +0 -14
  1917. package/dist/domain/components/debug-state-component.js +0 -1
  1918. package/dist/domain/components/domain-component-optic.d.ts +0 -76
  1919. package/dist/domain/components/domain-component-optic.js +0 -16
  1920. package/dist/domain/components/drag-state-component.d.ts +0 -16
  1921. package/dist/domain/components/drag-state-component.js +0 -1
  1922. package/dist/domain/components/export-state-component.d.ts +0 -15
  1923. package/dist/domain/components/export-state-component.js +0 -1
  1924. package/dist/domain/components/fullscreen-state-component.d.ts +0 -14
  1925. package/dist/domain/components/fullscreen-state-component.js +0 -1
  1926. package/dist/domain/components/group-components-by-entity-id-and-name.d.ts +0 -9
  1927. package/dist/domain/components/group-components-by-entity-id-and-name.js +0 -1
  1928. package/dist/domain/components/hover-state-component.d.ts +0 -14
  1929. package/dist/domain/components/hover-state-component.js +0 -1
  1930. package/dist/domain/components/index.d.ts +0 -2
  1931. package/dist/domain/components/index.js +0 -1
  1932. package/dist/domain/components/legacy-filter.d.ts +0 -513
  1933. package/dist/domain/components/navigation-state-component.d.ts +0 -15
  1934. package/dist/domain/components/navigation-state-component.js +0 -1
  1935. package/dist/domain/components/selection-state-component.d.ts +0 -14
  1936. package/dist/domain/components/selection-state-component.js +0 -1
  1937. package/dist/domain/components/system-component-builder.d.ts +0 -12
  1938. package/dist/domain/components/system-component-builder.js +0 -1
  1939. package/dist/domain/components/system-component-filter.d.ts +0 -793
  1940. package/dist/domain/components/system-virtual-entity.js +0 -1
  1941. package/dist/domain/components/tool-state-component.d.ts +0 -14
  1942. package/dist/domain/components/tool-state-component.js +0 -1
  1943. package/dist/domain/components/updates.d.ts +0 -108
  1944. package/dist/domain/components/view-state-component.d.ts +0 -14
  1945. package/dist/domain/components/view-state-component.js +0 -1
  1946. package/dist/domain/components/viewport-state-component.d.ts +0 -29
  1947. package/dist/domain/components/viewport-state-component.js +0 -1
  1948. package/dist/domain/core/component.d.ts +0 -46
  1949. package/dist/domain/core/expression.d.ts +0 -50
  1950. package/dist/domain/core/json-schema.js +0 -1
  1951. package/dist/domain/core/migrations.d.ts +0 -99
  1952. package/dist/domain/core/migrations.js +0 -1
  1953. package/dist/domain/core/model.d.ts +0 -127
  1954. package/dist/domain/core/reflection.d.ts +0 -114
  1955. package/dist/domain/core/reflection.js +0 -1
  1956. package/dist/domain/core/state.d.ts +0 -10
  1957. package/dist/domain/domain-context/recipe-system/recipes.d.ts +0 -57
  1958. package/dist/domain/domain-context/recipe-system/recipes.js +0 -1
  1959. package/dist/domain/expressions/constant-expressions.d.ts +0 -9
  1960. package/dist/domain/expressions/constant-expressions.js +0 -1
  1961. package/dist/domain/expressions/custom-expression.d.ts +0 -13
  1962. package/dist/domain/expressions/custom-expression.js +0 -1
  1963. package/dist/domain/expressions/index.d.ts +0 -1
  1964. package/dist/domain/expressions/index.js +0 -1
  1965. package/dist/domain/expressions/memoize-expression.d.ts +0 -17
  1966. package/dist/domain/expressions/prepare-domain-expressions.d.ts +0 -16
  1967. package/dist/domain/invariants/builtin-invariant.d.ts +0 -5
  1968. package/dist/domain/invariants/custom-invariants.d.ts +0 -22
  1969. package/dist/domain/invariants/custom-invariants.js +0 -1
  1970. package/dist/domain/invariants/invariants.d.ts +0 -68
  1971. package/dist/domain/invariants/invariants.js +0 -1
  1972. package/dist/domain/invariants/violation-component.js +0 -1
  1973. package/dist/domain/invariants/violation.d.ts +0 -85
  1974. package/dist/domain/invariants/violation.js +0 -1
  1975. package/dist/domain/relations/all-of-type-relation.d.ts +0 -33
  1976. package/dist/domain/relations/all-of-type-relation.js +0 -1
  1977. package/dist/domain/relations/component-factories.d.ts +0 -15
  1978. package/dist/domain/relations/component-factories.js +0 -1
  1979. package/dist/domain/relations/composed-of.d.ts +0 -12
  1980. package/dist/domain/relations/composed-of.js +0 -1
  1981. package/dist/domain/relations/direct-relation.d.ts +0 -29
  1982. package/dist/domain/relations/indirect-relation.d.ts +0 -81
  1983. package/dist/domain/relations/indirect-relation.js +0 -1
  1984. package/dist/domain/relations/reference-component.d.ts +0 -18
  1985. package/dist/domain/relations/reference-component.js +0 -1
  1986. package/dist/domain/relations/reference-field.d.ts +0 -7
  1987. package/dist/domain/relations/relation-factory.d.ts +0 -19
  1988. package/dist/domain/relations/relation-factory.js +0 -1
  1989. package/dist/domain/relations/relation-implementation.d.ts +0 -8
  1990. package/dist/domain/system-components/angle-indicator.d.ts +0 -21
  1991. package/dist/domain/system-components/angle-indicator.js +0 -1
  1992. package/dist/domain/system-components/attribute-switch.d.ts +0 -8
  1993. package/dist/domain/system-components/attribute-switch.js +0 -1
  1994. package/dist/domain/system-components/autorotate-camera-component.d.ts +0 -19
  1995. package/dist/domain/system-components/autorotate-camera-component.js +0 -1
  1996. package/dist/domain/system-components/basic-sidebar-footer.d.ts +0 -8
  1997. package/dist/domain/system-components/basic-sidebar-footer.js +0 -1
  1998. package/dist/domain/system-components/camera-based-hidden-entity-object.js +0 -1
  1999. package/dist/domain/system-components/camera-based-hidden-entity.js +0 -1
  2000. package/dist/domain/system-components/canvas-config.d.ts +0 -87
  2001. package/dist/domain/system-components/canvas-config.js +0 -1
  2002. package/dist/domain/system-components/canvas-custom-environment.js +0 -1
  2003. package/dist/domain/system-components/canvas-padding.d.ts +0 -25
  2004. package/dist/domain/system-components/canvas-padding.js +0 -1
  2005. package/dist/domain/system-components/canvas-preset-environment.d.ts +0 -37
  2006. package/dist/domain/system-components/canvas-preset-environment.js +0 -1
  2007. package/dist/domain/system-components/child-entity-recipe-hierarchy.d.ts +0 -21
  2008. package/dist/domain/system-components/child-entity-recipe-hierarchy.js +0 -1
  2009. package/dist/domain/system-components/client-side-image.d.ts +0 -14
  2010. package/dist/domain/system-components/client-side-image.js +0 -1
  2011. package/dist/domain/system-components/color-value.js +0 -1
  2012. package/dist/domain/system-components/common/angle-indicator-schema.d.ts +0 -292
  2013. package/dist/domain/system-components/common/angle-indicator-schema.js +0 -1
  2014. package/dist/domain/system-components/common/dimension-indicator-schema.d.ts +0 -607
  2015. package/dist/domain/system-components/common/dimension-indicator-schema.js +0 -1
  2016. package/dist/domain/system-components/custom-header.d.ts +0 -11
  2017. package/dist/domain/system-components/custom-header.js +0 -1
  2018. package/dist/domain/system-components/custom-price-footer.js +0 -1
  2019. package/dist/domain/system-components/custom-sidebar-footer.d.ts +0 -11
  2020. package/dist/domain/system-components/custom-sidebar-footer.js +0 -1
  2021. package/dist/domain/system-components/dimension-indicator.d.ts +0 -31
  2022. package/dist/domain/system-components/dimension-indicator.js +0 -1
  2023. package/dist/domain/system-components/editable-angle-indicator.d.ts +0 -38
  2024. package/dist/domain/system-components/editable-angle-indicator.js +0 -1
  2025. package/dist/domain/system-components/editable-distance-dimension-indicator.d.ts +0 -42
  2026. package/dist/domain/system-components/editable-distance-dimension-indicator.js +0 -1
  2027. package/dist/domain/system-components/editable-offset-indicator.d.ts +0 -41
  2028. package/dist/domain/system-components/editable-offset-indicator.js +0 -1
  2029. package/dist/domain/system-components/editable-size-indicator.d.ts +0 -38
  2030. package/dist/domain/system-components/editable-size-indicator.js +0 -1
  2031. package/dist/domain/system-components/entity-header.d.ts +0 -22
  2032. package/dist/domain/system-components/entity-header.js +0 -1
  2033. package/dist/domain/system-components/exit-tool-mode-fab.d.ts +0 -25
  2034. package/dist/domain/system-components/exit-tool-mode-fab.js +0 -1
  2035. package/dist/domain/system-components/finalize-action.d.ts +0 -20
  2036. package/dist/domain/system-components/finalize-action.js +0 -1
  2037. package/dist/domain/system-components/finalize-component.js +0 -1
  2038. package/dist/domain/system-components/fit-selection-orthographic-camera-component.js +0 -1
  2039. package/dist/domain/system-components/fit-selection-perspective-camera-component.js +0 -1
  2040. package/dist/domain/system-components/fixed-header.d.ts +0 -10
  2041. package/dist/domain/system-components/fixed-header.js +0 -1
  2042. package/dist/domain/system-components/floating-header.d.ts +0 -10
  2043. package/dist/domain/system-components/floating-header.js +0 -1
  2044. package/dist/domain/system-components/hidden-header.d.ts +0 -8
  2045. package/dist/domain/system-components/hidden-header.js +0 -1
  2046. package/dist/domain/system-components/hidden-sidebar-footer.d.ts +0 -21
  2047. package/dist/domain/system-components/hidden-sidebar-footer.js +0 -1
  2048. package/dist/domain/system-components/horizontal-tabs.d.ts +0 -28
  2049. package/dist/domain/system-components/horizontal-tabs.js +0 -1
  2050. package/dist/domain/system-components/list-selector-dimension-indicator.d.ts +0 -30
  2051. package/dist/domain/system-components/list-selector-dimension-indicator.js +0 -1
  2052. package/dist/domain/system-components/multilingual-text-value.js +0 -1
  2053. package/dist/domain/system-components/navigation-steps.d.ts +0 -19
  2054. package/dist/domain/system-components/navigation-steps.js +0 -1
  2055. package/dist/domain/system-components/offset-anchors.d.ts +0 -20
  2056. package/dist/domain/system-components/offset-anchors.js +0 -1
  2057. package/dist/domain/system-components/offset-indicator.d.ts +0 -84
  2058. package/dist/domain/system-components/offset-indicator.js +0 -1
  2059. package/dist/domain/system-components/offset.d.ts +0 -31
  2060. package/dist/domain/system-components/offset.js +0 -1
  2061. package/dist/domain/system-components/other-action.d.ts +0 -14
  2062. package/dist/domain/system-components/other-action.js +0 -1
  2063. package/dist/domain/system-components/property-page.d.ts +0 -16
  2064. package/dist/domain/system-components/property-page.js +0 -1
  2065. package/dist/domain/system-components/read-sidebar-footer.d.ts +0 -8
  2066. package/dist/domain/system-components/read-sidebar-footer.js +0 -1
  2067. package/dist/domain/system-components/replace-entity-recipe-hierarchy.d.ts +0 -21
  2068. package/dist/domain/system-components/replace-entity-recipe-hierarchy.js +0 -1
  2069. package/dist/domain/system-components/rotatable.js +0 -1
  2070. package/dist/domain/system-components/rotation-handle.d.ts +0 -53
  2071. package/dist/domain/system-components/rotation-handle.js +0 -1
  2072. package/dist/domain/system-components/save-template-thumbnail.d.ts +0 -14
  2073. package/dist/domain/system-components/save-template-thumbnail.js +0 -1
  2074. package/dist/domain/system-components/scene-entity-add-fab.d.ts +0 -32
  2075. package/dist/domain/system-components/scene-entity-add-fab.js +0 -1
  2076. package/dist/domain/system-components/scene-entity-animation.js +0 -1
  2077. package/dist/domain/system-components/scene-entity-control.js +0 -1
  2078. package/dist/domain/system-components/scene-entity-delete-fab.d.ts +0 -19
  2079. package/dist/domain/system-components/scene-entity-delete-fab.js +0 -1
  2080. package/dist/domain/system-components/scene-entity-floor-object.js +0 -1
  2081. package/dist/domain/system-components/scene-entity-html-hotspot.d.ts +0 -27
  2082. package/dist/domain/system-components/scene-entity-html-hotspot.js +0 -1
  2083. package/dist/domain/system-components/scene-entity-navigation-hotspot.d.ts +0 -20
  2084. package/dist/domain/system-components/scene-entity-navigation-hotspot.js +0 -1
  2085. package/dist/domain/system-components/scene-entity-object-html-hotspot.d.ts +0 -31
  2086. package/dist/domain/system-components/scene-entity-object-html-hotspot.js +0 -1
  2087. package/dist/domain/system-components/scene-entity-select-hotspot.d.ts +0 -5
  2088. package/dist/domain/system-components/scene-entity-select-hotspot.js +0 -1
  2089. package/dist/domain/system-components/scene-entity-wall-object.js +0 -1
  2090. package/dist/domain/system-components/selectable-component.js +0 -1
  2091. package/dist/domain/system-components/sidebar-tabs.d.ts +0 -29
  2092. package/dist/domain/system-components/sidebar-tabs.js +0 -1
  2093. package/dist/domain/system-components/simple-summary.js +0 -1
  2094. package/dist/domain/system-components/size.d.ts +0 -21
  2095. package/dist/domain/system-components/size.js +0 -1
  2096. package/dist/domain/system-components/sketching-draw.d.ts +0 -17
  2097. package/dist/domain/system-components/sketching-draw.js +0 -1
  2098. package/dist/domain/system-components/sketching-edit.d.ts +0 -28
  2099. package/dist/domain/system-components/sketching-edit.js +0 -1
  2100. package/dist/domain/system-components/summary-component.js +0 -1
  2101. package/dist/domain/system-components/text-value.js +0 -1
  2102. package/dist/domain/system-components/tool-controls.js +0 -1
  2103. package/dist/domain/system-components/tool-menu-fab.d.ts +0 -40
  2104. package/dist/domain/system-components/tool-menu-fab.js +0 -1
  2105. package/dist/domain/system-components/toolbar.d.ts +0 -13
  2106. package/dist/domain/system-components/toolbar.js +0 -1
  2107. package/dist/domain/system-components/universal-sidebar-footer.d.ts +0 -12
  2108. package/dist/domain/system-components/universal-sidebar-footer.js +0 -1
  2109. package/dist/domain/system-components/view-controls.js +0 -1
  2110. package/dist/extras/assistant/AssistantChat.d.ts +0 -6
  2111. package/dist/extras/assistant/AssistantChat.js +0 -1
  2112. package/dist/extras/assistant/index.d.ts +0 -1
  2113. package/dist/extras/assistant/index.js +0 -1
  2114. package/dist/phoenix/application-spec/generate-assistant-prompt.d.ts +0 -12
  2115. package/dist/phoenix/application-spec/generate-assistant-prompt.js +0 -1
  2116. package/dist/phoenix/commands/generate-project-files.d.ts +0 -6
  2117. package/dist/phoenix/commands/generate-project-files.js +0 -1
  2118. package/dist/react-sdk/application-runtime/runtime/god-mode.d.ts +0 -19
  2119. package/dist/react-sdk/application-runtime/runtime/god-mode.js +0 -1
  2120. package/dist/react-sdk/loading-state/LoadingStateProvider.d.ts +0 -31
  2121. package/dist/react-sdk/loading-state/LoadingStateProvider.js +0 -1
  2122. package/dist/react-sdk/loading-state/loading-state-manager.d.ts +0 -32
  2123. package/dist/react-sdk/loading-state/loading-state-manager.js +0 -1
  2124. /package/dist/{domain/components/component-reader-types.js → application-spec/core/expressions/relation-expression-params.js} +0 -0
  2125. /package/dist/application-spec/{core → enhanced-json}/eval-code-uses-self.d.ts +0 -0
  2126. /package/dist/application-spec/{core → enhanced-json}/eval-code-uses-self.js +0 -0
  2127. /package/dist/application-spec/{core → enhanced-json}/eval-to-constant.js +0 -0
  2128. /package/dist/{domain/core/enhanced-json-schema.js → application-spec/generate-application/runtime/spec-code/spec-code-module.js} +0 -0
  2129. /package/dist/{domain/core/expression.js → application-spec/parse-application-files/spec/expressions/expression-read.js} +0 -0
  2130. /package/dist/{domain/relations/reference-field.js → configurator/ui/assistant/form/form-model.js} +0 -0
  2131. /package/dist/{domain/relations/relation-implementation.js → configurator/ui/assistant/form/form-state.js} +0 -0
  2132. /package/dist/{domain/core/schema-validator.js → configurator/ui/assistant/form-elements/form-element-props.js} +0 -0
  2133. /package/dist/domain/{components → core/component}/legacy-filter.js +0 -0
  2134. /package/dist/domain/{components → core/component}/system-component-filter.js +0 -0
  2135. /package/dist/domain/{components → core/component}/system-virtual-entity.d.ts +0 -0
  2136. /package/dist/domain/{components → core/component}/updates.js +0 -0
  2137. /package/dist/domain/{invariants → core/invariant}/builtin-invariant.js +0 -0
  2138. /package/dist/domain/{invariants → core/invariant}/violation-component.d.ts +0 -0
  2139. /package/dist/domain/core/{alias.d.ts → model/alias.d.ts} +0 -0
  2140. /package/dist/domain/core/{alias.js → model/alias.js} +0 -0
  2141. /package/dist/domain/core/{common-definitions.d.ts → model/common-definitions.d.ts} +0 -0
  2142. /package/dist/domain/core/{common-definitions.js → model/common-definitions.js} +0 -0
  2143. /package/dist/domain/core/{component.js → model/component.js} +0 -0
  2144. /package/dist/domain/core/{model.js → model/model.js} +0 -0
  2145. /package/dist/domain/core/{preset.d.ts → model/preset.d.ts} +0 -0
  2146. /package/dist/domain/core/{preset.js → model/preset.js} +0 -0
  2147. /package/dist/domain/{relations → core/relation}/direct-relation.js +0 -0
  2148. /package/dist/domain/core/{schema-validator-ajv.d.ts → schema/create-ajv-schema-validator.d.ts} +0 -0
  2149. /package/dist/domain/core/{schema-validator-ajv.js → schema/create-ajv-schema-validator.js} +0 -0
  2150. /package/dist/domain/core/{schema-validator-csp.d.ts → schema/create-csp-schema-validator.d.ts} +0 -0
  2151. /package/dist/domain/core/{schema-validator-csp.js → schema/create-csp-schema-validator.js} +0 -0
  2152. /package/dist/domain/core/{enhanced-json-schema.d.ts → schema/enhanced-json-schema.d.ts} +0 -0
  2153. /package/dist/domain/core/{json-schema.d.ts → schema/extended-schema-validator.d.ts} +0 -0
  2154. /package/dist/domain/core/{schema-validator.d.ts → schema/schema-validator.d.ts} +0 -0
  2155. /package/dist/domain/core/{state.js → state/state.js} +0 -0
  2156. /package/dist/domain/{expressions → domain-runtime/spec}/memoize-expression.js +0 -0
  2157. /package/dist/domain/{expressions → domain-runtime/spec}/prepare-domain-expressions.js +0 -0
  2158. /package/dist/domain/{system-components → extensions}/camera-based-hidden-entity-object.d.ts +0 -0
  2159. /package/dist/domain/{system-components → extensions}/camera-based-hidden-entity.d.ts +0 -0
  2160. /package/dist/domain/{system-components → extensions}/canvas-custom-environment.d.ts +0 -0
  2161. /package/dist/domain/{system-components → extensions}/color-value.d.ts +0 -0
  2162. /package/dist/domain/{system-components → extensions}/common/dimension-indicators.d.ts +0 -0
  2163. /package/dist/domain/{system-components → extensions}/common/dimension-indicators.js +0 -0
  2164. /package/dist/domain/{system-components → extensions}/common/editable-indicator-button-variant.d.ts +0 -0
  2165. /package/dist/domain/{system-components → extensions}/common/editable-indicator-button-variant.js +0 -0
  2166. /package/dist/domain/{system-components → extensions}/custom-price-footer.d.ts +0 -0
  2167. /package/dist/domain/{system-components → extensions}/finalize-component.d.ts +0 -0
  2168. /package/dist/domain/{system-components → extensions}/fit-selection-orthographic-camera-component.d.ts +0 -0
  2169. /package/dist/domain/{system-components → extensions}/fit-selection-perspective-camera-component.d.ts +0 -0
  2170. /package/dist/domain/{system-components → extensions}/multilingual-text-value.d.ts +0 -0
  2171. /package/dist/domain/{system-components → extensions}/rotatable.d.ts +0 -0
  2172. /package/dist/domain/{system-components → extensions}/scene-entity-animation.d.ts +0 -0
  2173. /package/dist/domain/{system-components → extensions}/scene-entity-control.d.ts +0 -0
  2174. /package/dist/domain/{system-components → extensions}/scene-entity-floor-object.d.ts +0 -0
  2175. /package/dist/domain/{system-components → extensions}/scene-entity-wall-object.d.ts +0 -0
  2176. /package/dist/domain/{system-components → extensions}/selectable-component.d.ts +0 -0
  2177. /package/dist/domain/{system-components → extensions}/simple-summary.d.ts +0 -0
  2178. /package/dist/domain/{system-components → extensions}/summary-component.d.ts +0 -0
  2179. /package/dist/domain/{system-components → extensions}/text-value.d.ts +0 -0
  2180. /package/dist/domain/{system-components → extensions}/tool-controls.d.ts +0 -0
  2181. /package/dist/domain/{system-components → extensions}/view-controls.d.ts +0 -0
@@ -0,0 +1,3698 @@
1
+ # Nightjar Guitar
2
+
3
+ Walk a customer through a product one step at a time and end in an order. A custom guitar shop, Northfret, sells its Nightjar electric guitar through a five-step wizard: the body, the neck, the electronics, a signature on the headstock and a summary with **Place order**. A stepper across the top shows where the customer is, each step's choices slide in beside the guitar, the camera moves to what the step changes, and a bar at the bottom keeps the price, **Back** and **Next** in reach. The project writes the wizard as one layout element; the spec holds the steps, which step asks each choice, the cameras, the rules and the order action.
4
+
5
+ - [Try it](#try-it)
6
+ - [What the example demonstrates](#what-the-example-demonstrates)
7
+ - [Steps from the spec](#steps-from-the-spec)
8
+ - [Each step shows the choices the spec gives it](#each-step-shows-the-choices-the-spec-gives-it)
9
+ - [The camera follows the wizard](#the-camera-follows-the-wizard)
10
+ - [Finish swatches](#finish-swatches)
11
+ - [A signature on the headstock](#a-signature-on-the-headstock)
12
+ - [Summary and conflicts](#summary-and-conflicts)
13
+ - [Place the order](#place-the-order)
14
+ - [Pages that slide in](#pages-that-slide-in)
15
+ - [On a phone](#on-a-phone)
16
+ - [The stage and the model](#the-stage-and-the-model)
17
+ - [Test cases](#test-cases)
18
+ - [What this layout leaves out](#what-this-layout-leaves-out)
19
+ - [Related pages](#related-pages)
20
+ - [Complete Implementation](#complete-implementation)
21
+
22
+ ## Try it
23
+
24
+ The phone version is under [On a phone](#on-a-phone).
25
+
26
+ ## What the example demonstrates
27
+
28
+ [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 product sold in ordered steps, and it shows the pieces Custom Layout does not use:
29
+
30
+ | Piece | Where |
31
+ | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
32
+ | `phx.frontend.useStepNavigation()` for a stepper and **Back** and **Next** from the spec's `navigationSteps` | `StepHeader`, `OrderBar`, [Steps from the spec](#steps-from-the-spec) |
33
+ | A step's fields from the components a `$filter` leaves active, read with `phx.frontend.useComponents()` | `use-active-choices`, [Each step shows…](#each-step-shows-the-choices-the-spec-gives-it) |
34
+ | Cameras filtered by navigation state, so the camera follows the wizard with no camera code | the spec, [The camera follows the wizard](#the-camera-follows-the-wizard) |
35
+ | `phx.frontend.useSwatchSelection()` for a `materialSwatch` | `FinishField`, [Finish swatches](#finish-swatches) |
36
+ | `phx.frontend.useTextValue()` with a `sceneEntityObjectTextDecal`, and a `fixable` rule on the text | `SignatureField`, [A signature on the headstock](#a-signature-on-the-headstock) |
37
+ | A summary read with the control hooks, and warnings from `phx.frontend.useFinalizeViolations()` | `SummaryPanel`, `SummaryRows`, [Summary and conflicts](#summary-and-conflicts) |
38
+ | `phx.frontend.useFinalizeActions()` with its pending state and error, and an `ordered` confirmation | `OrderBar`, `SummaryPanel`, [Place the order](#place-the-order) |
39
+ | `phx.frontend.useSceneSafeArea().update()` once a page has slid in | `DesktopPage`, `PhonePage`, [Pages that slide in](#pages-that-slide-in) |
40
+ | `phx.frontend.useAnalytics()` with `FrontendAnalyticsFactory.SummaryButtonClicked()` | `OrderBar`, [Steps from the spec](#steps-from-the-spec) |
41
+ | `sceneEntityObjectLocalMaterialOverride` with a clearcoat, and a `canvasCustomEnvironment` stage | the spec, `NightjarStage`, [The stage and the model](#the-stage-and-the-model) |
42
+
43
+ ## Steps from the spec
44
+
45
+ The steps are product structure, so they live in the spec. Each navigation state is a page of the wizard; `navigationSteps` groups them into the steps the stepper shows, with their labels and their order. The summary step holds two states: `summary`, and `ordered` for the confirmation after the order.
46
+
47
+ ```yaml
48
+ navigationStates:
49
+ - body
50
+ - neck
51
+ - electronics
52
+ - details
53
+ - summary
54
+ - ordered
55
+ ```
56
+
57
+ ```yaml
58
+ components:
59
+ Guitar:
60
+ navigationSteps:
61
+ main:
62
+ steps:
63
+ - label: Body
64
+ navigationStates:
65
+ - body
66
+ - label: Neck
67
+ navigationStates:
68
+ - neck
69
+ - label: Electronics
70
+ navigationStates:
71
+ - electronics
72
+ - label: Details
73
+ navigationStates:
74
+ - details
75
+ - label: Summary
76
+ navigationStates:
77
+ - summary
78
+ - ordered
79
+ ```
80
+
81
+ `phx.frontend.useStepNavigation()` reads them and returns every step with its label resolved and its `status`, `'complete'`, `'active'` or `'upcoming'`, with `next()`, `previous()` and `goTo(index)` to move. `StepHeader` draws the stepper from `steps`, and `OrderBar` the buttons from `canGoPrevious`, `isLast` and the label of the step after the active one:
82
+
83
+ - **A wizard that remembers.** The hook enforces no order: `goTo` enters any step. `StepHeader` lets the customer go back to any step they have reached and never ahead of it, so after changing the body from the summary they return to the summary in one click. The furthest step is the layout's own state, kept in `ConfiguratorLayout` with `useReachedStep()` so it survives the switch between the desktop and the phone page.
84
+ - **Analytics come with the moves.** `next()` and `previous()` record the built-in step buttons' events and `goTo()` the header stepper's, so the stepper and the bar need no analytics code. The button that opens the summary is the exception: like the built-in **Summary** button, it records `FrontendAnalyticsFactory.SummaryButtonClicked()` from `@salsita-ai/sdk/configurator` through `phx.frontend.useAnalytics().push()` and enters the state with `phx.frontend.useNavigate()`, because `next()` would record the next-step button's event instead.
85
+ - **Locked once ordered.** The stepper takes no clicks while the order is being placed or after it was placed; **Design another** in the bar returns to the first step.
86
+
87
+ ## Each step shows the choices the spec gives it
88
+
89
+ The layout does not list which choice belongs to which step. A `$filter` with `navigationStates` makes a spec component active only in those states, so each choice names its step in the spec, plus the summary and the confirmation, which list every choice:
90
+
91
+ ```yaml
92
+ components:
93
+ Guitar:
94
+ attributeSelection:
95
+ bodyShape:
96
+ value:
97
+ $bind: bodyShape
98
+ options:
99
+ - label: Offset
100
+ description: Contoured waist, 3.4 kg
101
+ value: Offset
102
+ - label: Single-cut
103
+ description: Thicker body, long sustain
104
+ value: SingleCut
105
+ $filter:
106
+ navigationStates:
107
+ - body
108
+ - summary
109
+ - ordered
110
+ ```
111
+
112
+ `useActiveChoices` reads the `attributeSelection`, `materialSwatch` and `textValue` components active now with `phx.frontend.useComponents()` and orders them by the layout's field list, which also names each choice: the spec's control components carry no label.
113
+
114
+ ```ts
115
+ import { useMemo } from 'react'
116
+
117
+ import { attributeSelectionComponent, materialSwatchComponent, textValueComponent } from '@salsita-ai/sdk/domain'
118
+
119
+ import { phx } from '../../.phoenix/phx.js'
120
+ import { byFieldOrder } from './fields.js'
121
+
122
+ export type ChoiceKind = 'selection' | 'swatch' | 'text'
123
+
124
+ /** A choice of the spec that is active now. */
125
+ export interface ActiveChoice {
126
+ readonly instanceName: string
127
+ readonly kind: ChoiceKind
128
+ }
129
+
130
+ // The guitar's choices whose spec component is active in the current navigation state, in the layout's order. A
131
+ // `$filter` with `navigationStates` makes a component active only in those states, so on each step this is the step's
132
+ // choices, and on the summary every choice. The control hooks throw for an inactive component; a field mounts only
133
+ // for a choice listed here.
134
+ export const useActiveChoices = (): readonly ActiveChoice[] => {
135
+ const guitarId = phx.frontend.useRootEntityId()
136
+ const selections = phx.frontend.useComponents({
137
+ componentTypes: [attributeSelectionComponent],
138
+ entityIds: [guitarId],
139
+ })
140
+ const swatches = phx.frontend.useComponents({ componentTypes: [materialSwatchComponent], entityIds: [guitarId] })
141
+ const texts = phx.frontend.useComponents({ componentTypes: [textValueComponent], entityIds: [guitarId] })
142
+
143
+ return useMemo(() => {
144
+ const choices = [
145
+ ...(selections ?? []).map(
146
+ ({ componentInstance }): ActiveChoice => ({ instanceName: componentInstance.instanceName, kind: 'selection' })
147
+ ),
148
+ ...(swatches ?? []).map(
149
+ ({ componentInstance }): ActiveChoice => ({ instanceName: componentInstance.instanceName, kind: 'swatch' })
150
+ ),
151
+ ...(texts ?? []).map(
152
+ ({ componentInstance }): ActiveChoice => ({ instanceName: componentInstance.instanceName, kind: 'text' })
153
+ ),
154
+ ]
155
+
156
+ return choices.sort((a, b) => byFieldOrder(a.instanceName, b.instanceName))
157
+ }, [selections, swatches, texts])
158
+ }
159
+ ```
160
+
161
+ `StepFields` then mounts one field per active choice, by its kind. Moving a choice to another step is a change of its `$filter` in the spec, and the step follows:
162
+
163
+ ```tsx
164
+ import { Box } from '@mui/material'
165
+
166
+ import { ChoiceField } from './ChoiceField.js'
167
+ import { FinishField } from './FinishField.js'
168
+ import { SignatureField } from './SignatureField.js'
169
+ import { fieldOf } from './fields.js'
170
+ import { useActiveChoices } from './use-active-choices.js'
171
+
172
+ interface StepFieldsProps {
173
+ readonly compact: boolean
174
+ }
175
+
176
+ // The fields of the active step. The layout does not list which choice belongs to which step: it shows the choices
177
+ // the spec leaves active, so moving a choice to another step is a change of its `$filter` in the spec.
178
+ export const StepFields = ({ compact }: StepFieldsProps) => {
179
+ const choices = useActiveChoices()
180
+
181
+ return (
182
+ <Box component="div" sx={{ display: 'grid', gap: compact ? 2.5 : 4 }}>
183
+ {choices.map(({ instanceName, kind }) => {
184
+ const { label, warningTypes } = fieldOf(instanceName)
185
+ const props = { instanceName, label, warningTypes, compact }
186
+
187
+ switch (kind) {
188
+ case 'selection':
189
+ return <ChoiceField key={instanceName} {...props} />
190
+ case 'swatch':
191
+ return <FinishField key={instanceName} {...props} />
192
+ case 'text':
193
+ return <SignatureField key={instanceName} {...props} />
194
+ }
195
+ })}
196
+ </Box>
197
+ )
198
+ }
199
+ ```
200
+
201
+ Mount a field only for a choice that is active. The control hooks, such as `useAttributeSelection`, throw for a component that a `$filter` makes inactive, so a layout that renders its fields some other way checks first with `phx.frontend.useComponent({ entityId, componentType, instanceName })`, which returns `null` for an inactive component.
202
+
203
+ ## The camera follows the wizard
204
+
205
+ The cameras are spec components too, and the same `$filter` switches them: the whole guitar for the body, the summary and the confirmation, the upper neck and the headstock for the neck, the pickups for the electronics, and the headstock close up for the signature. Entering a step activates its camera and the camera moves there; the layout has no camera code.
206
+
207
+ ```yaml
208
+ components:
209
+ Guitar:
210
+ fitRootPerspectiveCamera:
211
+ overview:
212
+ fov: 30
213
+ fitToBox: true
214
+ $filter:
215
+ navigationStates:
216
+ - body
217
+ - summary
218
+ - ordered
219
+ staticPerspectiveCamera:
220
+ neck:
221
+ fov: 30
222
+ lookAtX: 0
223
+ lookAtY: 625
224
+ lookAtZ: 0
225
+ distance: 1350
226
+ azimuthAngle: 0.55
227
+ polarAngle: 1.36
228
+ $filter:
229
+ navigationStates:
230
+ - neck
231
+ ```
232
+
233
+ The overview fits the guitar into the safe area the page leaves free. A `staticPerspectiveCamera` looks at a point of the model from a fixed distance, in millimetres, which suits a close-up of one part; the camera padding of the safe area still applies, so the part stays beside the panel. [Cameras / Transitions](?path=/docs/3d-scene-cameras-transitions--docs) describes when the camera moves between cameras.
234
+
235
+ ## Finish swatches
236
+
237
+ The finish is a `materialSwatch`: the spec lists each swatch with its name and the colour of its chip.
238
+
239
+ ```yaml
240
+ components:
241
+ Guitar:
242
+ materialSwatch:
243
+ finish:
244
+ selectedSwatchKey:
245
+ $bind: finish
246
+ swatches:
247
+ Seafoam:
248
+ swatchName: Seafoam green
249
+ color: '#8fcab6'
250
+ CandyRed:
251
+ swatchName: Candy apple red
252
+ color: '#b0141f'
253
+ Midnight:
254
+ swatchName: Midnight blue metallic
255
+ color: '#1d2b4f'
256
+ NaturalAsh:
257
+ swatchName: Natural ash
258
+ color: '#d8b98a'
259
+ ```
260
+
261
+ `FinishField` reads it with `phx.frontend.useSwatchSelection(guitarId, 'finish', [])`. Each option has `swatchKey`, `swatchName`, `color`, `selected`, `disabled`, `hint` and `onClick()`, which writes the swatch; the third argument lists the `fixable` violation types the options ignore. The field draws the swatches as round chips in the spec's colours with the chosen one's name beside the label. How the finish renders on the guitar is the material override's business, see [The stage and the model](#the-stage-and-the-model).
262
+
263
+ ## A signature on the headstock
264
+
265
+ The customer can sign the headstock. The signature is a `textValue`, and a `sceneEntityObjectTextDecal` on the `headstock` object prints it in script along the headstock's face:
266
+
267
+ ```yaml
268
+ components:
269
+ Guitar:
270
+ textValue:
271
+ signature:
272
+ value:
273
+ $bind: signature
274
+ sceneEntityObjectTextDecal:
275
+ headstock:
276
+ text:
277
+ $read: signature
278
+ font: SignPainter-HouseScript
279
+ preloadFonts:
280
+ - SignPainter-HouseScript
281
+ fontSize: auto
282
+ textColor:
283
+ $read: $signatureColor
284
+ positionX: 0.002
285
+ positionY: 0.76
286
+ positionZ: 0.004
287
+ rotationZ: 1.5708
288
+ sizeX: 0.13
289
+ sizeY: 0.03
290
+ sizeZ: 0.02
291
+ ```
292
+
293
+ The decal's instance name is the object's: `headstock` in `sceneEntityRemoteObject`. Its position, rotation and size are in the object's own units, metres for this model, and `fontSize: auto` fits the text into the decal's width. The font must be loaded by the page; `preloadFonts` redraws the decal once it is.
294
+
295
+ The headstock takes 16 characters. The limit is the expression `$signatureLimit`, declared in the spec so the layout can read it, and a `fixable` rule rejects a longer signature with a message that names it:
296
+
297
+ ```ts
298
+ import { phx } from '../../.phoenix/phx.js'
299
+
300
+ export default phx.domain.implementCustomInvariants({
301
+ Guitar: {
302
+ // `fixable`: a change that makes the signature too long is rejected, so the headstock never shows more than fits.
303
+ // The message names the limit, so it is built here rather than in the spec.
304
+ signatureLength: s => {
305
+ if (s.signature.length <= s.$signatureLimit) {
306
+ return []
307
+ }
308
+
309
+ return [
310
+ {
311
+ type: 'signatureTooLong',
312
+ severity: 'fixable',
313
+ message: `The headstock fits ${s.$signatureLimit} characters. Shorten the signature.`,
314
+ },
315
+ ]
316
+ },
317
+ // `warning` in the spec: the change is kept, so a body chosen after the pickups does not undo them, and ordering
318
+ // waits until the customer resolves it
319
+ offsetHumbuckers: s => {
320
+ return s.bodyShape !== 'Offset' || s.pickups !== 'Humbuckers'
321
+ },
322
+ },
323
+ })
324
+ ```
325
+
326
+ `SignatureField` writes with `phx.frontend.useTextValue(guitarId, 'signature')`. `update(event, value)` stages each value as the customer types, so the headstock follows every key, and `resolve()` commits it when they leave the field or press Enter. While the staged text breaks the rule, `hasErrors` is set and `hints` holds the rule's message, which the field shows in red with the counter; `resolve()` then rolls back to the committed signature instead, so the guitar never keeps a signature that does not fit.
327
+
328
+ ```tsx
329
+ import { Box, InputBase, Typography } from '@mui/material'
330
+
331
+ import { phx } from '../../.phoenix/phx.js'
332
+ import { FieldShell } from './FieldShell.js'
333
+ import { NIGHTJAR } from './tokens.js'
334
+
335
+ interface SignatureFieldProps {
336
+ readonly instanceName: string
337
+ readonly label: string
338
+ readonly warningTypes: readonly string[]
339
+ readonly compact: boolean
340
+ }
341
+
342
+ // The spec's `textValue`, which the spec prints on the headstock with a text decal. Typing stages each value, so the
343
+ // headstock follows every key; leaving the field or pressing Enter commits it. A value the `fixable` length rule
344
+ // rejects shows the rule's message as the hook's `hints`, and leaving the field rolls back to the last value that
345
+ // fitted. The counter reads the limit from the spec's `$signatureLimit` expression, which the rule checks too.
346
+ export const SignatureField = ({ instanceName, label, warningTypes, compact }: SignatureFieldProps) => {
347
+ const guitarId = phx.frontend.useRootEntityId()
348
+ const guitar = phx.frontend.useRootEntityState()
349
+ const signature = phx.frontend.useTextValue(guitarId, instanceName)
350
+ const limit = guitar.$signatureLimit
351
+
352
+ return (
353
+ <FieldShell
354
+ id={`nightjar-${instanceName}`}
355
+ label={label}
356
+ aside={
357
+ <Typography
358
+ aria-live="polite"
359
+ sx={{
360
+ fontFamily: NIGHTJAR.font,
361
+ fontSize: 13,
362
+ fontVariantNumeric: 'tabular-nums',
363
+ color: signature.hasErrors ? NIGHTJAR.alert : NIGHTJAR.muted,
364
+ }}
365
+ >
366
+ {signature.value.length} / {limit}
367
+ </Typography>
368
+ }
369
+ hint={
370
+ compact ? undefined : 'In gold leaf on dark necks, in black on maple. Leave it empty for a plain headstock.'
371
+ }
372
+ warningTypes={warningTypes}
373
+ compact={compact}
374
+ >
375
+ <Box
376
+ component="div"
377
+ sx={{
378
+ display: 'grid',
379
+ gap: 1,
380
+ paddingInline: 2,
381
+ paddingBlock: compact ? 1 : 1.5,
382
+ borderRadius: 1.5,
383
+ border: `1px solid ${signature.hasErrors ? NIGHTJAR.alert : NIGHTJAR.line}`,
384
+ bgcolor: NIGHTJAR.raised,
385
+ '&:focus-within': { borderColor: signature.hasErrors ? NIGHTJAR.alert : NIGHTJAR.amber },
386
+ }}
387
+ >
388
+ <InputBase
389
+ value={signature.value}
390
+ placeholder="Your name"
391
+ onChange={event => signature.update(event, event.target.value)}
392
+ onBlur={signature.resolve}
393
+ onKeyDown={event => {
394
+ if (event.key === 'Enter') {
395
+ signature.resolve()
396
+ }
397
+ }}
398
+ inputProps={{
399
+ 'aria-labelledby': `nightjar-${instanceName}-label`,
400
+ 'aria-invalid': signature.hasErrors,
401
+ 'aria-describedby': `nightjar-${instanceName}-error`,
402
+ spellCheck: false,
403
+ }}
404
+ sx={{
405
+ fontFamily: NIGHTJAR.script,
406
+ fontSize: compact ? 30 : 38,
407
+ lineHeight: 1.2,
408
+ color: NIGHTJAR.amber,
409
+ '& input::placeholder': { color: NIGHTJAR.faint, opacity: 1 },
410
+ }}
411
+ />
412
+ </Box>
413
+ <Typography
414
+ id={`nightjar-${instanceName}-error`}
415
+ role="alert"
416
+ sx={{ fontFamily: NIGHTJAR.font, fontSize: 14, color: NIGHTJAR.alert, '&:empty': { display: 'none' } }}
417
+ >
418
+ {signature.hasErrors ? signature.hints : ''}
419
+ </Typography>
420
+ </FieldShell>
421
+ )
422
+ }
423
+ ```
424
+
425
+ ## Summary and conflicts
426
+
427
+ The last step reviews the guitar. `SummaryRows` lists every choice active in the `summary` state with the control hook of its kind: the option's `title` from `useAttributeSelection`, the swatch's name and colour from `useSwatchSelection`, the text from `useTextValue`. The summary only reviews; a choice is changed on its step.
428
+
429
+ One rule spans two steps: the Offset body is routed for single-coil-sized pickups. It is a `warning`, so a change that breaks it is kept, and a body chosen after the pickups does not undo them:
430
+
431
+ ```yaml
432
+ invariants:
433
+ Guitar:
434
+ offsetHumbuckers:
435
+ type: offsetHumbuckers
436
+ severity: warning
437
+ message: The Offset body is routed for single-coil-sized pickups. Choose single coils or P-90s, or the Single-cut body for humbuckers.
438
+ ```
439
+
440
+ While it holds, the layout shows it three times, each read from `phx.frontend.useFinalizeViolations().violations`: under the **Pickups** and **Body shape** fields, as a mark on the **Electronics** step, and on the summary with **Go to Electronics**. The layout's `STEP_WARNINGS` names the step that resolves each warning. `phx.frontend.useStateValidity()` holds the same violations, but on `phx.frontend` it is typed as the validity value instead of a hook, so calling it does not type-check; `useWarnings` uses `useFinalizeViolations` instead.
441
+
442
+ ## Place the order
443
+
444
+ The spec declares the order action, and the handler, `src/handlers/place-order.ts`, stands in for the shop's order service:
445
+
446
+ ```yaml
447
+ components:
448
+ Guitar:
449
+ finalizeAction:
450
+ placeOrder:
451
+ variant: primary
452
+ label: Place order
453
+ title: Send the guitar as configured to the Northfret workshop
454
+ icon: ShoppingBag
455
+ handler: placeOrder
456
+ ```
457
+
458
+ ```ts
459
+ import { useCallback } from 'react'
460
+
461
+ import { phx } from '../../.phoenix/phx.js'
462
+
463
+ // Stands in for Northfret's order service. Placing an order takes a moment. The service checks stock when the order
464
+ // arrives, which the configurator cannot know beforehand: gold hardware is back-ordered, so it refuses that order with
465
+ // its reason; any other order is accepted and the page shows the confirmation.
466
+ export default phx.frontend.createPhoenixHandler('placeOrder', () => {
467
+ const navigate = phx.frontend.useNavigate()
468
+ const guitar = phx.frontend.useRootEntityState()
469
+
470
+ return {
471
+ handler: useCallback(async () => {
472
+ await new Promise(resolve => setTimeout(resolve, 1600))
473
+
474
+ if (guitar.hardware === 'Gold') {
475
+ throw new Error(
476
+ 'Gold hardware is back-ordered until next month. Choose chrome or black hardware, or order later.'
477
+ )
478
+ }
479
+
480
+ navigate('ordered')
481
+ }, [guitar.hardware, navigate]),
482
+ }
483
+ })
484
+ ```
485
+
486
+ **Place order** sits in the bar on the summary step. It runs `phx.frontend.useFinalizeActions().primary`:
487
+
488
+ - **Blocked.** While a warning holds, the action is `disabled` and `hints` holds the warnings' text: the bar shows "Settle the choices above first" beside the button, and the summary lists the conflicts. The name and the e-mail are the layout's own state. The button stays clickable; while either blocks the order, a click reveals what is missing from the form instead of ordering.
489
+ - **Pending.** `run()` starts the handler beside the layout; `isPending` turns the button into "Placing order…" with a spinner and locks the stepper, **Back** and the form.
490
+ - **Failed.** The service refuses gold hardware, which the configurator cannot know beforehand. The handler throws, and the action's `error` is shown at the top of the summary; no snackbar is raised. **Place order** stays available to try again.
491
+ - **Placed.** The handler enters `ordered`, where the panel thanks the customer by name with an order number made from the configuration's id, and lists the build.
492
+
493
+ A viewer of a shared configuration sees no **Place order**: neither hook checks read mode, so the bar hides it while `phx.frontend.useAccessService().accessInfo.viewMode` is set.
494
+
495
+ ## Pages that slide in
496
+
497
+ `ConfiguratorLayout` keeps the scene mounted and lays the desktop or the phone page over it, by the width of the configurator's container from `phx.frontend.useActiveViewports()`. It also holds the contact form's state and the furthest step reached, so both survive the switch between the two, and the form survives the move to the confirmation.
498
+
499
+ ```tsx
500
+ import { Box } from '@mui/material'
501
+
502
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
503
+
504
+ import { phx } from '../../.phoenix/phx.js'
505
+ import { NIGHTJAR } from '../_fields/index.js'
506
+ import { DesktopPage } from '../_shared/DesktopPage.js'
507
+ import { PhonePage } from '../_shared/PhonePage.js'
508
+ import { useOrderForm } from '../_shared/order-form.js'
509
+ import { useReachedStep } from '../_shared/use-reached-step.js'
510
+
511
+ // A wizard over the scene. The canvas stays mounted the whole time; the desktop or the phone page lies over it. The
512
+ // contact form's state and the furthest step reached live here, so they survive the switch between the two; the form
513
+ // also survives the move to the confirmation.
514
+ const ConfiguratorLayout = () => {
515
+ // `null` until the container has been measured; only the scene shows until then
516
+ const viewports = phx.frontend.useActiveViewports()
517
+ const { activeIndex } = phx.frontend.useStepNavigation()
518
+ const form = useOrderForm()
519
+ const reached = useReachedStep(activeIndex)
520
+ const isDesktop = viewports?.includes('desktop') ?? false
521
+
522
+ return (
523
+ <Box component="div" sx={{ position: 'absolute', inset: 0, overflow: 'clip', bgcolor: NIGHTJAR.ink }}>
524
+ <LayoutSlots.SharedCanvas />
525
+ {viewports !== null &&
526
+ (isDesktop ? <DesktopPage form={form} reached={reached} /> : <PhonePage form={form} reached={reached} />)}
527
+ </Box>
528
+ )
529
+ }
530
+
531
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
532
+ ```
533
+
534
+ Each page measures its safe area with `phx.frontend.useSceneSafeArea()`. The summary's panel is wider than a step's, so the steps, the summary and the confirmation are three pages, each with its own safe area, and each slides in when it opens. The safe area slides with its page: the measurement taken when the page mounts sees it shifted, and a `transform` that ends is not a resize, so nothing measures again. The page calls `update()` from the same hook when its own slide ends, not when the step content's slide inside it does. Without it the guitar stays shifted sideways by the slide's 48 pixels.
535
+
536
+ ```tsx
537
+ import { Box, Typography } from '@mui/material'
538
+ import type { AnimationEvent } from 'react'
539
+
540
+ import { phx } from '../../.phoenix/phx.js'
541
+ import { ENTER_FROM_END, HEADING_SX, NIGHTJAR } from '../_fields/index.js'
542
+ import { OrderBar } from './OrderBar.js'
543
+ import { OrderConfirmation } from './OrderConfirmation.js'
544
+ import { StepHeader } from './StepHeader.js'
545
+ import { StepPanel } from './StepPanel.js'
546
+ import { SummaryPanel } from './SummaryPanel.js'
547
+ import type { OrderForm } from './order-form.js'
548
+
549
+ type Page = 'steps' | 'summary' | 'ordered'
550
+
551
+ // The summary needs room for the contact form, so its panel is wider
552
+ const PANEL_WIDTHS: Readonly<Record<Page, number>> = { steps: 420, summary: 520, ordered: 420 }
553
+
554
+ const pageOf = (navigationState: string): Page => {
555
+ return navigationState === 'ordered' ? 'ordered' : navigationState === 'summary' ? 'summary' : 'steps'
556
+ }
557
+
558
+ // The brand's mark: a fret of amber over the name of the shop
559
+ const Brand = () => {
560
+ return (
561
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', gap: 1.5, flex: 'none' }}>
562
+ <Box component="span" aria-hidden sx={{ inlineSize: 4, blockSize: 28, bgcolor: NIGHTJAR.amber }} />
563
+ <Box component="div" sx={{ display: 'grid' }}>
564
+ <Typography sx={{ ...HEADING_SX, fontSize: 16, letterSpacing: '0.32em', lineHeight: 1.1 }}>
565
+ Northfret
566
+ </Typography>
567
+ <Typography sx={{ ...HEADING_SX, fontSize: 10, letterSpacing: '0.36em', color: NIGHTJAR.muted }}>
568
+ Custom shop
569
+ </Typography>
570
+ </Box>
571
+ </Box>
572
+ )
573
+ }
574
+
575
+ interface DesktopPageProps {
576
+ readonly form: OrderForm
577
+ readonly reached: number
578
+ }
579
+
580
+ // The desktop wizard: the stepper on top, the guitar in the free area on the left, the panel of the step on the
581
+ // right and the bar with the price at the bottom.
582
+ //
583
+ // The summary's panel is wider than a step's, so the steps, the summary and the confirmation are three pages, each
584
+ // with its own safe area, and each slides in when it opens. The safe area slides with its page: the first
585
+ // measurement, taken when the page mounts, sees it shifted, and no resize follows when the slide ends. `update()`
586
+ // from `useSceneSafeArea` measures again once the slide has settled, so the camera frames the guitar in the place the
587
+ // page leaves for it.
588
+ export const DesktopPage = ({ form, reached }: DesktopPageProps) => {
589
+ const { containerRef, safeAreaRef, update } = phx.frontend.useSceneSafeArea()
590
+ const navigationState = phx.frontend.useActiveNavigationState()
591
+ const page = pageOf(navigationState)
592
+
593
+ // The step's own content slides too; only the page's slide moves the safe area
594
+ const handleAnimationEnd = (event: AnimationEvent<HTMLDivElement>) => {
595
+ if (event.target === event.currentTarget) {
596
+ update()
597
+ }
598
+ }
599
+
600
+ return (
601
+ <Box
602
+ component="div"
603
+ ref={containerRef}
604
+ sx={{
605
+ position: 'absolute',
606
+ inset: 0,
607
+ display: 'grid',
608
+ gridTemplateRows: 'auto minmax(0, 1fr) auto',
609
+ fontFamily: NIGHTJAR.font,
610
+ color: NIGHTJAR.cream,
611
+ // The free area lies over the canvas; only the bars and the panel take the pointer
612
+ pointerEvents: 'none',
613
+ }}
614
+ >
615
+ <Box
616
+ component="header"
617
+ sx={{
618
+ display: 'flex',
619
+ alignItems: 'center',
620
+ gap: 5,
621
+ minBlockSize: 72,
622
+ paddingInline: 4,
623
+ bgcolor: NIGHTJAR.ink,
624
+ borderBlockEnd: `1px solid ${NIGHTJAR.line}`,
625
+ pointerEvents: 'auto',
626
+ }}
627
+ >
628
+ <Brand />
629
+ <StepHeader compact={false} reached={reached} />
630
+ </Box>
631
+
632
+ <Box
633
+ component="div"
634
+ key={page}
635
+ onAnimationEnd={handleAnimationEnd}
636
+ sx={{
637
+ display: 'grid',
638
+ gridTemplateColumns: `minmax(0, 1fr) ${PANEL_WIDTHS[page]}px`,
639
+ minBlockSize: 0,
640
+ animation: `${ENTER_FROM_END} 480ms cubic-bezier(0.2, 0.7, 0.2, 1)`,
641
+ '@media (prefers-reduced-motion: reduce)': { animation: 'none' },
642
+ }}
643
+ >
644
+ <Box component="div" sx={{ position: 'relative', minInlineSize: 0 }}>
645
+ {/* The camera fits the guitar into this box, so its inset is the room around the guitar */}
646
+ <Box component="div" ref={safeAreaRef} sx={{ position: 'absolute', inset: '40px 72px 56px' }} />
647
+ <Typography
648
+ sx={{
649
+ position: 'absolute',
650
+ insetBlockEnd: 20,
651
+ insetInline: 0,
652
+ textAlign: 'center',
653
+ fontSize: 12,
654
+ letterSpacing: '0.14em',
655
+ textTransform: 'uppercase',
656
+ color: NIGHTJAR.faint,
657
+ }}
658
+ >
659
+ Drag to turn the guitar
660
+ </Typography>
661
+ </Box>
662
+ <Box
663
+ component="aside"
664
+ aria-label={page === 'steps' ? 'Step' : page === 'summary' ? 'Summary' : 'Order'}
665
+ sx={{
666
+ overflowY: 'auto',
667
+ paddingInline: 4,
668
+ paddingBlock: 4,
669
+ bgcolor: NIGHTJAR.panel,
670
+ borderInlineStart: `1px solid ${NIGHTJAR.line}`,
671
+ pointerEvents: 'auto',
672
+ }}
673
+ >
674
+ {page === 'steps' && <StepPanel compact={false} />}
675
+ {page === 'summary' && <SummaryPanel compact={false} form={form} />}
676
+ {page === 'ordered' && <OrderConfirmation compact={false} contact={form.contact} />}
677
+ </Box>
678
+ </Box>
679
+
680
+ <OrderBar compact={false} form={form} />
681
+ </Box>
682
+ )
683
+ }
684
+ ```
685
+
686
+ ## On a phone
687
+
688
+ The same layout in a frame 390 pixels wide, as on a phone. A compact "2 / 5 · Neck" line with a thin progress bar replaces the stepper, the choices become chips in a row that scrolls sideways, the guitar keeps the top of the screen and the bar stays fixed at the bottom. Opened on its own from the sidebar, the **Phone** story sets Storybook's viewport to 390 × 844.
689
+
690
+ ## The stage and the model
691
+
692
+ The spec's `canvasCustomEnvironment` names `NightjarStage`, a layout element rendered inside the scene: a dark room with a warm glow on the wall behind the guitar, a warm key light and a cool rim. drei's `Lightformer` panels exist only in the reflections, where they draw the long highlights on the clearcoat and the hardware, and no image has to be downloaded.
693
+
694
+ ```tsx
695
+ import { Environment, Lightformer } from '@react-three/drei'
696
+ import { useMemo } from 'react'
697
+ import { CanvasTexture, SRGBColorSpace } from 'three'
698
+
699
+ import { phx } from '../../.phoenix/phx.js'
700
+ import { NIGHTJAR } from '../_fields/index.js'
701
+
702
+ /** A warm pool of light that fades into the dark, drawn once on a canvas. */
703
+ const createGlow = (): CanvasTexture => {
704
+ const size = 512
705
+ const canvas = document.createElement('canvas')
706
+ canvas.width = size
707
+ canvas.height = size
708
+ const context = canvas.getContext('2d')
709
+
710
+ if (context) {
711
+ const gradient = context.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2)
712
+ gradient.addColorStop(0, 'rgba(242, 163, 58, 0.42)')
713
+ gradient.addColorStop(0.22, 'rgba(214, 112, 46, 0.2)')
714
+ gradient.addColorStop(0.5, 'rgba(122, 30, 43, 0.07)')
715
+ gradient.addColorStop(0.75, 'rgba(14, 15, 18, 0)')
716
+ context.fillStyle = gradient
717
+ context.fillRect(0, 0, size, size)
718
+ }
719
+
720
+ const texture = new CanvasTexture(canvas)
721
+ texture.colorSpace = SRGBColorSpace
722
+ return texture
723
+ }
724
+
725
+ // The stage named by the spec's `canvasCustomEnvironment`: a dark room with a warm glow on the wall behind the guitar,
726
+ // a warm key light and a cool rim. The light panels exist only in the reflections, where they draw the long highlights
727
+ // on the clearcoat and the hardware. The scene is in millimetres.
728
+ export default phx.frontend.createCustomPhoenixLayoutElement('NightjarStage', () => {
729
+ const glow = useMemo(createGlow, [])
730
+
731
+ return (
732
+ <>
733
+ <color attach="background" args={[NIGHTJAR.ink]} />
734
+ <ambientLight intensity={0.4} />
735
+ <directionalLight position={[-900, 1400, 1600]} intensity={2.4} color="#ffe6c7" />
736
+ <directionalLight position={[1400, 700, -900]} intensity={1.2} color="#a9c1ff" />
737
+
738
+ {/* The glow on the wall, behind the guitar and out of the camera's fit */}
739
+ <mesh position={[-250, 300, -900]}>
740
+ <planeGeometry args={[3600, 3600]} />
741
+ <meshBasicMaterial map={glow} transparent depthWrite={false} toneMapped={false} />
742
+ </mesh>
743
+
744
+ <Environment resolution={256} frames={1}>
745
+ <color attach="background" args={['#15161b']} />
746
+ {/* Tall strips at both sides for the long highlights, a softbox above, an amber wash behind */}
747
+ <Lightformer form="rect" intensity={7} position={[-5, 1, 3]} rotation-y={Math.PI / 3} scale={[1.2, 9, 1]} />
748
+ <Lightformer form="rect" intensity={4} position={[5, 1, 2]} rotation-y={-Math.PI / 3} scale={[1, 9, 1]} />
749
+ <Lightformer form="rect" intensity={2.5} position={[0, 6, 1]} rotation-x={Math.PI / 2} scale={[8, 3, 1]} />
750
+ <Lightformer form="rect" intensity={1.2} position={[0, 1, 7]} rotation-y={Math.PI} scale={[8, 4, 1]} />
751
+ <Lightformer form="rect" color={NIGHTJAR.amber} intensity={0.8} position={[0, -2, -7]} scale={[10, 3, 1]} />
752
+ </Environment>
753
+ </>
754
+ )
755
+ })
756
+ ```
757
+
758
+ The finish is a physical material with a clearcoat, set per body object with `sceneEntityObjectLocalMaterialOverride`: the override names the object, and only that object's `Finish` material changes. Natural ash shows a wood texture through the clearcoat; the paints have none. The materials many parts share, such as `Hardware` on the tuners, the bridges, the knobs and the switches, use `sceneEntityLocalMaterialOverride`, which changes every object of the entity that carries the material. The values come from expressions in `src/expressions/guitar.ts`, which also price the guitar.
759
+
760
+ ```yaml
761
+ components:
762
+ Guitar:
763
+ sceneEntityObjectLocalMaterialOverride:
764
+ bodyOffset:
765
+ materialsToOverride:
766
+ - Finish
767
+ materialType: physical
768
+ color:
769
+ $read: $finishColor
770
+ textureUrl:
771
+ $read: $finishTexture
772
+ metalness:
773
+ $read: $finishMetalness
774
+ roughness:
775
+ $read: $finishRoughness
776
+ clearcoat: 1
777
+ clearcoatRoughness: 0.04
778
+ ```
779
+
780
+ The guitar is `public/models/gallery/guitar.glb`, generated by `scripts/models/guitar.ts` in the Storybook package from three.js geometry: two bodies extruded from their outlines with a rounded bevel, a pickguard for each, the neck, fretboard, frets, inlays, headstock, tuners and strings, three pickup sets and the bridges, knobs and switches of each body. Each part is a named node the spec loads with `sceneEntityRemoteObject.<name>.objectName`; `sceneEntityObjectProperties` shows the parts of the chosen body and pickups. The script lives in `scripts/models/`, outside the example's `src/`, because every file under `src/` is part of this page.
781
+
782
+ ## Test cases
783
+
784
+ - The page opens on **Body**: the Offset in Seafoam green with a parchment pickguard, maple neck, rosewood board, single coils and chrome, **$1,650.00**, and **Next: Neck**. The stepper shows step 1 active and the rest upcoming, which cannot be clicked yet.
785
+ - **Candy apple red** turns the body red under a glossy clearcoat at $1,830.00; **Natural ash** shows the wood grain. The finish's name appears beside the label.
786
+ - **Single-cut** swaps the body, its small pickguard, the bar bridge with a tailpiece, four knobs and the toggle switch, and adds $150. **None** removes the pickguard.
787
+ - **Next: Neck** slides the neck's choices in from the right and moves the camera to the upper neck and the headstock. **Roasted maple** and **Ebony** change the neck and the board; on a maple board the dots turn black.
788
+ - **Back** slides the body's choices in from the left and returns the camera to the whole guitar.
789
+ - On **Electronics** the camera moves to the pickups. **Humbuckers** on the Offset shows "The Offset body is routed for single-coil-sized pickups. …" under **Pickups**, and the stepper marks **Electronics**. **P-90s** clears both.
790
+ - **Gold** turns the tuners, the bridge, the knobs and the switch gold.
791
+ - On **Details** the camera shows the headstock. Typing a name prints it on the headstock as you type, in gold on a dark neck and in black on maple; the counter shows the characters used of 16, and the price rises by $45.
792
+ - Typing past 16 characters turns the counter and the field red and shows "The headstock fits 16 characters. Shorten the signature."; leaving the field puts back the signature committed before, and the headstock with it.
793
+ - **Review order** opens the summary: a wider panel lists every choice, with the signature in script. With the humbucker conflict, the summary lists it with **Go to Electronics**, the bar shows "Settle the choices above first", and **Place order** reveals "Enter the name the order is for." and "Enter an e-mail address for the build updates." under the empty fields.
794
+ - **Go to Electronics** opens that step; after **P-90s**, the stepper's **Summary** returns to the summary in one click.
795
+ - After going back from the summary to an earlier step, narrowing the window until the phone page shows and widening it again leaves the stepper's **Summary** enabled.
796
+ - With a name and an e-mail, **Place order** shows "Placing order…" with a spinner for under two seconds. With gold hardware it then shows "The order did not go through" and the service's reason at the top of the summary; with chrome or black it opens the confirmation: "Thank you, …", the order number, the e-mail and the build. The stepper no longer takes clicks, and **Design another** returns to **Body**.
797
+ - Each step, the summary and the confirmation leave the guitar centred in the area beside the panel once their slide has settled.
798
+ - With the browser console's Verbose level, **Next** and **Back** log the step buttons' `nextStepButton` and `previousStepButton` events, the stepper the `topNavigation` `step` event, **Review order** the `summaryButton` event and **Place order** the `finalizeButton` event: without a Google Tag Manager id, Storybook's analytics log their events with `console.debug`.
799
+ - In the **Phone** story the guitar keeps the top of the screen, "1 / 5 · Body" and the progress line sit above it, the choices are chips in rows that scroll sideways, and **Next**, **Review order** and **Place order** work as on the desktop.
800
+ - The browser console shows no errors, apart from the "Failed to finalize" line that the refused order with gold hardware logs.
801
+
802
+ ## What this layout leaves out
803
+
804
+ - **Messages for rejected changes.** The only rule that rejects a change is the signature's, which the field explains itself, so the layout mounts neither `LayoutSlots.Services` nor `phx.frontend.useConfiguratorMessages()`. A project whose other rules reject changes, or that saves the configuration, mounts one of the two so a rejected change or a failed save is not silent; see [Custom Layout → Show messages](?path=/docs/layouts-custom-layout--docs#show-messages).
805
+ - **Read mode.** **Place order** is hidden while `phx.frontend.useAccessService().accessInfo.viewMode` is set, but the fields stay editable and the example ships no read template; [Custom Layout → Serve read mode](?path=/docs/layouts-custom-layout--docs#serve-read-mode) shows one.
806
+ - **An order that outlives the page.** The order number is made from the configuration's id and the contact details are the layout's state, so a configuration reopened in the `ordered` state thanks no one by name. A deployed project sends the details with the order and shows what its service answers.
807
+ - **The built-in arrangement.** Header, sidebar, sidebar footer, tabs, tool and view controls and the toolbar are not mounted; [Layout Slots](?path=/docs/phoenix-layout-slots--docs) lists every slot a project layout can mount.
808
+
809
+ ## Related pages
810
+
811
+ - [Kestrel Kettle](?path=/docs/layouts-gallery-kestrel-kettle--docs) sells a small product from one page, and [Ardent Compressor](?path=/docs/layouts-gallery-ardent-compressor--docs) is a stepped quote builder without a scene.
812
+ - [Custom Layout](?path=/docs/layouts-custom-layout--docs) explains a project layout step by step.
813
+ - [Configurator Interface → Hooks for a Project Layout](?path=/docs/phoenix-configurator-interface--docs#hooks-for-a-project-layout) lists the hooks used here, steps and tabs included.
814
+ - [Floating Header → Adding step navigation](?path=/docs/layouts-header-floating--docs#adding-step-navigation) shows the built-in stepper over the same `navigationSteps`.
815
+ - [Domain Model → Invariants](?path=/docs/phoenix-domain-model--docs#invariants) describes the rules.
816
+ - [Finalization](?path=/docs/phoenix-finalization--docs) describes the server side of a finalize action.
817
+
818
+ ## Complete Implementation
819
+
820
+ {/* AUTO-GENERATED SECTION: This section is automatically updated by 'phoenix story build' */}
821
+
822
+ <details>
823
+ <summary>Click to view the complete implementation files</summary>
824
+
825
+ ### ./spec/domain.yaml
826
+
827
+ ```yaml
828
+ model:
829
+ latest:
830
+ entityTypes:
831
+ - Guitar
832
+ aliases:
833
+ RootEntity:
834
+ - Guitar
835
+ commonTypes:
836
+ BodyShape:
837
+ enum:
838
+ - Offset
839
+ - SingleCut
840
+ Finish:
841
+ enum:
842
+ - Seafoam
843
+ - CandyRed
844
+ - Midnight
845
+ - NaturalAsh
846
+ Pickguard:
847
+ enum:
848
+ - Parchment
849
+ - Black
850
+ - Pearloid
851
+ - None
852
+ NeckWood:
853
+ enum:
854
+ - Maple
855
+ - RoastedMaple
856
+ - Mahogany
857
+ Fretboard:
858
+ enum:
859
+ - Maple
860
+ - Rosewood
861
+ - Ebony
862
+ Pickups:
863
+ enum:
864
+ - SingleCoils
865
+ - Humbuckers
866
+ - P90s
867
+ Hardware:
868
+ enum:
869
+ - Chrome
870
+ - Gold
871
+ - Black
872
+ shapes:
873
+ Guitar:
874
+ bodyShape:
875
+ $ref: '#/model/latest/commonTypes/BodyShape'
876
+ finish:
877
+ $ref: '#/model/latest/commonTypes/Finish'
878
+ pickguard:
879
+ $ref: '#/model/latest/commonTypes/Pickguard'
880
+ neckWood:
881
+ $ref: '#/model/latest/commonTypes/NeckWood'
882
+ fretboard:
883
+ $ref: '#/model/latest/commonTypes/Fretboard'
884
+ pickups:
885
+ $ref: '#/model/latest/commonTypes/Pickups'
886
+ hardware:
887
+ $ref: '#/model/latest/commonTypes/Hardware'
888
+ signature:
889
+ type: string
890
+
891
+ presets:
892
+ - rootEntityType: Guitar
893
+ initialDomainEntities:
894
+ - id: Guitar-1
895
+ type: Guitar
896
+ bodyShape: Offset
897
+ finish: Seafoam
898
+ pickguard: Parchment
899
+ neckWood: Maple
900
+ fretboard: Rosewood
901
+ pickups: SingleCoils
902
+ hardware: Chrome
903
+ signature: ''
904
+
905
+ # One state per wizard step, and `ordered` for the confirmation after the order
906
+ navigationStates:
907
+ - body
908
+ - neck
909
+ - electronics
910
+ - details
911
+ - summary
912
+ - ordered
913
+
914
+ # The longest signature the headstock takes; the invariant and the layout's counter both read it
915
+ expressions:
916
+ Guitar:
917
+ $signatureLimit:
918
+ type: number
919
+
920
+ invariants:
921
+ Guitar:
922
+ signatureLength:
923
+ types:
924
+ - signatureTooLong
925
+ offsetHumbuckers:
926
+ type: offsetHumbuckers
927
+ severity: warning
928
+ message: The Offset body is routed for single-coil-sized pickups. Choose single coils or P-90s, or the Single-cut body for humbuckers.
929
+
930
+ components:
931
+ Guitar:
932
+ detail:
933
+ main:
934
+ title: Nightjar
935
+ subtitle: Northfret Custom Shop
936
+ description: A hand-built electric guitar. Choose the body, the neck, the electronics and the details, then order it from the summary.
937
+ price:
938
+ main:
939
+ price:
940
+ $read: $price
941
+ navigationSteps:
942
+ main:
943
+ steps:
944
+ - label: Body
945
+ navigationStates:
946
+ - body
947
+ - label: Neck
948
+ navigationStates:
949
+ - neck
950
+ - label: Electronics
951
+ navigationStates:
952
+ - electronics
953
+ - label: Details
954
+ navigationStates:
955
+ - details
956
+ - label: Summary
957
+ navigationStates:
958
+ - summary
959
+ - ordered
960
+ finalizeAction:
961
+ placeOrder:
962
+ variant: primary
963
+ label: Place order
964
+ title: Send the guitar as configured to the Northfret workshop
965
+ icon: ShoppingBag
966
+ handler: placeOrder
967
+
968
+ # Each choice is active on its own step, and on the summary and the confirmation, which list every choice
969
+ attributeSelection:
970
+ bodyShape:
971
+ value:
972
+ $bind: bodyShape
973
+ options:
974
+ - label: Offset
975
+ description: Contoured waist, 3.4 kg
976
+ value: Offset
977
+ - label: Single-cut
978
+ description: Thicker body, long sustain
979
+ value: SingleCut
980
+ $filter:
981
+ navigationStates:
982
+ - body
983
+ - summary
984
+ - ordered
985
+ pickguard:
986
+ value:
987
+ $bind: pickguard
988
+ options:
989
+ - label: Parchment
990
+ value: Parchment
991
+ - label: Black
992
+ value: Black
993
+ - label: Pearloid
994
+ description: Shimmers in the light
995
+ value: Pearloid
996
+ - label: None
997
+ value: None
998
+ $filter:
999
+ navigationStates:
1000
+ - body
1001
+ - summary
1002
+ - ordered
1003
+ neckWood:
1004
+ value:
1005
+ $bind: neckWood
1006
+ options:
1007
+ - label: Maple
1008
+ description: Bright and snappy
1009
+ value: Maple
1010
+ - label: Roasted maple
1011
+ description: Baked for stability, caramel colour
1012
+ value: RoastedMaple
1013
+ - label: Mahogany
1014
+ description: Warm and round
1015
+ value: Mahogany
1016
+ $filter:
1017
+ navigationStates:
1018
+ - neck
1019
+ - summary
1020
+ - ordered
1021
+ fretboard:
1022
+ value:
1023
+ $bind: fretboard
1024
+ options:
1025
+ - label: Maple
1026
+ value: Maple
1027
+ - label: Rosewood
1028
+ value: Rosewood
1029
+ - label: Ebony
1030
+ description: Dense and smooth
1031
+ value: Ebony
1032
+ $filter:
1033
+ navigationStates:
1034
+ - neck
1035
+ - summary
1036
+ - ordered
1037
+ pickups:
1038
+ value:
1039
+ $bind: pickups
1040
+ options:
1041
+ - label: Single coils
1042
+ description: Glassy and articulate
1043
+ value: SingleCoils
1044
+ - label: Humbuckers
1045
+ description: Thick and hum-free
1046
+ value: Humbuckers
1047
+ - label: P-90s
1048
+ description: Gritty, with bite
1049
+ value: P90s
1050
+ $filter:
1051
+ navigationStates:
1052
+ - electronics
1053
+ - summary
1054
+ - ordered
1055
+ hardware:
1056
+ value:
1057
+ $bind: hardware
1058
+ options:
1059
+ - label: Chrome
1060
+ value: Chrome
1061
+ - label: Gold
1062
+ value: Gold
1063
+ - label: Black
1064
+ value: Black
1065
+ $filter:
1066
+ navigationStates:
1067
+ - electronics
1068
+ - summary
1069
+ - ordered
1070
+ materialSwatch:
1071
+ finish:
1072
+ selectedSwatchKey:
1073
+ $bind: finish
1074
+ swatches:
1075
+ Seafoam:
1076
+ swatchName: Seafoam green
1077
+ color: '#8fcab6'
1078
+ CandyRed:
1079
+ swatchName: Candy apple red
1080
+ color: '#b0141f'
1081
+ Midnight:
1082
+ swatchName: Midnight blue metallic
1083
+ color: '#1d2b4f'
1084
+ NaturalAsh:
1085
+ swatchName: Natural ash
1086
+ color: '#d8b98a'
1087
+ $filter:
1088
+ navigationStates:
1089
+ - body
1090
+ - summary
1091
+ - ordered
1092
+ textValue:
1093
+ signature:
1094
+ value:
1095
+ $bind: signature
1096
+ $filter:
1097
+ navigationStates:
1098
+ - details
1099
+ - summary
1100
+ - ordered
1101
+
1102
+ canvasConfig:
1103
+ main:
1104
+ highlightingDisabled: true
1105
+ canvasCustomEnvironment:
1106
+ main:
1107
+ name: NightjarStage
1108
+
1109
+ # The camera follows the wizard: the whole guitar for the body and the summary, then a closer view of what each
1110
+ # step changes. Each camera is active only in its step's navigation state; the scene is in millimetres.
1111
+ fitRootPerspectiveCamera:
1112
+ overview:
1113
+ fov: 30
1114
+ near: 10
1115
+ far: 20000
1116
+ minDistance: 600
1117
+ maxDistance: 9000
1118
+ azimuthAngle: 0.28
1119
+ polarAngle: 1.48
1120
+ minPolarAngle: 0.9
1121
+ maxPolarAngle: 2
1122
+ fitToBox: true
1123
+ fitMeshChanges: false
1124
+ $filter:
1125
+ navigationStates:
1126
+ - body
1127
+ - summary
1128
+ - ordered
1129
+ staticPerspectiveCamera:
1130
+ neck:
1131
+ fov: 30
1132
+ near: 10
1133
+ far: 20000
1134
+ lookAtX: 0
1135
+ lookAtY: 625
1136
+ lookAtZ: 0
1137
+ distance: 1350
1138
+ minDistance: 300
1139
+ maxDistance: 3000
1140
+ azimuthAngle: 0.55
1141
+ polarAngle: 1.36
1142
+ $filter:
1143
+ navigationStates:
1144
+ - neck
1145
+ electronics:
1146
+ fov: 30
1147
+ near: 10
1148
+ far: 20000
1149
+ lookAtX: 0
1150
+ lookAtY: 40
1151
+ lookAtZ: 0
1152
+ distance: 1150
1153
+ minDistance: 300
1154
+ maxDistance: 3000
1155
+ azimuthAngle: -0.32
1156
+ polarAngle: 1.22
1157
+ $filter:
1158
+ navigationStates:
1159
+ - electronics
1160
+ details:
1161
+ fov: 30
1162
+ near: 10
1163
+ far: 20000
1164
+ lookAtX: -10
1165
+ lookAtY: 750
1166
+ lookAtZ: 0
1167
+ distance: 520
1168
+ minDistance: 200
1169
+ maxDistance: 3000
1170
+ azimuthAngle: 0.12
1171
+ polarAngle: 1.5
1172
+ $filter:
1173
+ navigationStates:
1174
+ - details
1175
+
1176
+ sceneEntityRemoteObject:
1177
+ bodyOffset:
1178
+ fileUrl: /models/gallery/guitar.glb
1179
+ objectName: BodyOffset
1180
+ dimensionUnit: m
1181
+ bodySingleCut:
1182
+ fileUrl: /models/gallery/guitar.glb
1183
+ objectName: BodySingleCut
1184
+ dimensionUnit: m
1185
+ pickguardOffset:
1186
+ fileUrl: /models/gallery/guitar.glb
1187
+ objectName: PickguardOffset
1188
+ dimensionUnit: m
1189
+ pickguardSingleCut:
1190
+ fileUrl: /models/gallery/guitar.glb
1191
+ objectName: PickguardSingleCut
1192
+ dimensionUnit: m
1193
+ neck:
1194
+ fileUrl: /models/gallery/guitar.glb
1195
+ objectName: Neck
1196
+ dimensionUnit: m
1197
+ headstock:
1198
+ fileUrl: /models/gallery/guitar.glb
1199
+ objectName: Headstock
1200
+ dimensionUnit: m
1201
+ fretboard:
1202
+ fileUrl: /models/gallery/guitar.glb
1203
+ objectName: Fretboard
1204
+ dimensionUnit: m
1205
+ frets:
1206
+ fileUrl: /models/gallery/guitar.glb
1207
+ objectName: Frets
1208
+ dimensionUnit: m
1209
+ inlays:
1210
+ fileUrl: /models/gallery/guitar.glb
1211
+ objectName: Inlays
1212
+ dimensionUnit: m
1213
+ nut:
1214
+ fileUrl: /models/gallery/guitar.glb
1215
+ objectName: Nut
1216
+ dimensionUnit: m
1217
+ strings:
1218
+ fileUrl: /models/gallery/guitar.glb
1219
+ objectName: Strings
1220
+ dimensionUnit: m
1221
+ tuners:
1222
+ fileUrl: /models/gallery/guitar.glb
1223
+ objectName: Tuners
1224
+ dimensionUnit: m
1225
+ pickupsSingleCoil:
1226
+ fileUrl: /models/gallery/guitar.glb
1227
+ objectName: PickupsSingleCoil
1228
+ dimensionUnit: m
1229
+ polesSingleCoil:
1230
+ fileUrl: /models/gallery/guitar.glb
1231
+ objectName: PolesSingleCoil
1232
+ dimensionUnit: m
1233
+ pickupsHumbucker:
1234
+ fileUrl: /models/gallery/guitar.glb
1235
+ objectName: PickupsHumbucker
1236
+ dimensionUnit: m
1237
+ polesHumbucker:
1238
+ fileUrl: /models/gallery/guitar.glb
1239
+ objectName: PolesHumbucker
1240
+ dimensionUnit: m
1241
+ pickupsP90:
1242
+ fileUrl: /models/gallery/guitar.glb
1243
+ objectName: PickupsP90
1244
+ dimensionUnit: m
1245
+ polesP90:
1246
+ fileUrl: /models/gallery/guitar.glb
1247
+ objectName: PolesP90
1248
+ dimensionUnit: m
1249
+ bridgeTremolo:
1250
+ fileUrl: /models/gallery/guitar.glb
1251
+ objectName: BridgeTremolo
1252
+ dimensionUnit: m
1253
+ bridgeTuneOMatic:
1254
+ fileUrl: /models/gallery/guitar.glb
1255
+ objectName: BridgeTuneOMatic
1256
+ dimensionUnit: m
1257
+ knobsOffset:
1258
+ fileUrl: /models/gallery/guitar.glb
1259
+ objectName: KnobsOffset
1260
+ dimensionUnit: m
1261
+ knobsSingleCut:
1262
+ fileUrl: /models/gallery/guitar.glb
1263
+ objectName: KnobsSingleCut
1264
+ dimensionUnit: m
1265
+ switchOffset:
1266
+ fileUrl: /models/gallery/guitar.glb
1267
+ objectName: SwitchOffset
1268
+ dimensionUnit: m
1269
+ switchSingleCut:
1270
+ fileUrl: /models/gallery/guitar.glb
1271
+ objectName: SwitchSingleCut
1272
+ dimensionUnit: m
1273
+
1274
+ # Each body brings its own pickguard, bridge, knobs and switch; the pickups show the chosen set
1275
+ sceneEntityObjectProperties:
1276
+ bodyOffset:
1277
+ visible:
1278
+ $eval: self.bodyShape === 'Offset'
1279
+ bodySingleCut:
1280
+ visible:
1281
+ $eval: self.bodyShape === 'SingleCut'
1282
+ pickguardOffset:
1283
+ visible:
1284
+ $eval: self.bodyShape === 'Offset' && self.pickguard !== 'None'
1285
+ pickguardSingleCut:
1286
+ visible:
1287
+ $eval: self.bodyShape === 'SingleCut' && self.pickguard !== 'None'
1288
+ bridgeTremolo:
1289
+ visible:
1290
+ $eval: self.bodyShape === 'Offset'
1291
+ bridgeTuneOMatic:
1292
+ visible:
1293
+ $eval: self.bodyShape === 'SingleCut'
1294
+ knobsOffset:
1295
+ visible:
1296
+ $eval: self.bodyShape === 'Offset'
1297
+ knobsSingleCut:
1298
+ visible:
1299
+ $eval: self.bodyShape === 'SingleCut'
1300
+ switchOffset:
1301
+ visible:
1302
+ $eval: self.bodyShape === 'Offset'
1303
+ switchSingleCut:
1304
+ visible:
1305
+ $eval: self.bodyShape === 'SingleCut'
1306
+ pickupsSingleCoil:
1307
+ visible:
1308
+ $eval: self.pickups === 'SingleCoils'
1309
+ polesSingleCoil:
1310
+ visible:
1311
+ $eval: self.pickups === 'SingleCoils'
1312
+ pickupsHumbucker:
1313
+ visible:
1314
+ $eval: self.pickups === 'Humbuckers'
1315
+ polesHumbucker:
1316
+ visible:
1317
+ $eval: self.pickups === 'Humbuckers'
1318
+ pickupsP90:
1319
+ visible:
1320
+ $eval: self.pickups === 'P90s'
1321
+ polesP90:
1322
+ visible:
1323
+ $eval: self.pickups === 'P90s'
1324
+
1325
+ # The nitro finish: a physical material with a clearcoat on each body object; natural ash shows the grain
1326
+ sceneEntityObjectLocalMaterialOverride:
1327
+ bodyOffset:
1328
+ materialsToOverride:
1329
+ - Finish
1330
+ materialType: physical
1331
+ color:
1332
+ $read: $finishColor
1333
+ textureUrl:
1334
+ $read: $finishTexture
1335
+ rotation: 1.5708
1336
+ repeatX: 2.2
1337
+ repeatY: 2.2
1338
+ metalness:
1339
+ $read: $finishMetalness
1340
+ roughness:
1341
+ $read: $finishRoughness
1342
+ clearcoat: 1
1343
+ clearcoatRoughness: 0.04
1344
+ bodySingleCut:
1345
+ materialsToOverride:
1346
+ - Finish
1347
+ materialType: physical
1348
+ color:
1349
+ $read: $finishColor
1350
+ textureUrl:
1351
+ $read: $finishTexture
1352
+ rotation: 1.5708
1353
+ repeatX: 2.2
1354
+ repeatY: 2.2
1355
+ metalness:
1356
+ $read: $finishMetalness
1357
+ roughness:
1358
+ $read: $finishRoughness
1359
+ clearcoat: 1
1360
+ clearcoatRoughness: 0.04
1361
+
1362
+ # The materials many parts share change for every object that carries them
1363
+ sceneEntityLocalMaterialOverride:
1364
+ pickguard:
1365
+ materialsToOverride:
1366
+ - Pickguard
1367
+ materialType: physical
1368
+ color:
1369
+ $read: $pickguardColor
1370
+ roughness:
1371
+ $read: $pickguardRoughness
1372
+ metalness: 0
1373
+ iridescence:
1374
+ $read: $pickguardIridescence
1375
+ iridescenceIor: 1.4
1376
+ clearcoat:
1377
+ $read: $pickguardIridescence
1378
+ neck:
1379
+ materialsToOverride:
1380
+ - Neck
1381
+ materialType: physical
1382
+ color:
1383
+ $read: $neckColor
1384
+ textureUrl:
1385
+ $read: $neckTexture
1386
+ repeatX: 5
1387
+ repeatY: 1
1388
+ offsetX: 0.5
1389
+ metalness: 0
1390
+ roughness: 0.42
1391
+ clearcoat: 0.6
1392
+ clearcoatRoughness: 0.2
1393
+ fretboard:
1394
+ materialsToOverride:
1395
+ - Fretboard
1396
+ color:
1397
+ $read: $fretboardColor
1398
+ textureUrl:
1399
+ $read: $fretboardTexture
1400
+ repeatX: 5
1401
+ repeatY: 1
1402
+ offsetX: 0.5
1403
+ metalness: 0
1404
+ roughness: 0.62
1405
+ inlays:
1406
+ materialsToOverride:
1407
+ - Inlay
1408
+ color:
1409
+ $read: $inlayColor
1410
+ metalness: 0
1411
+ roughness: 0.3
1412
+ hardware:
1413
+ materialsToOverride:
1414
+ - Hardware
1415
+ color:
1416
+ $read: $hardwareColor
1417
+ metalness:
1418
+ $read: $hardwareMetalness
1419
+ roughness:
1420
+ $read: $hardwareRoughness
1421
+ pickupCover:
1422
+ materialsToOverride:
1423
+ - PickupCover
1424
+ color:
1425
+ $read: $pickupCoverColor
1426
+ metalness: 0
1427
+ roughness: 0.45
1428
+
1429
+ # The signature in script on the headstock's face, along its length; the text is the customer's own
1430
+ sceneEntityObjectTextDecal:
1431
+ headstock:
1432
+ text:
1433
+ $read: signature
1434
+ font: SignPainter-HouseScript
1435
+ preloadFonts:
1436
+ - SignPainter-HouseScript
1437
+ fontSize: auto
1438
+ textColor:
1439
+ $read: $signatureColor
1440
+ textCanvasHeight: 256
1441
+ positionX: 0.002
1442
+ positionY: 0.76
1443
+ positionZ: 0.004
1444
+ rotationX: 0
1445
+ rotationY: 0
1446
+ rotationZ: 1.5708
1447
+ sizeX: 0.13
1448
+ sizeY: 0.03
1449
+ sizeZ: 0.02
1450
+ roughness: 0.4
1451
+ metalness: 0.2
1452
+ bumpScale: 0.4
1453
+ invertedBump: true
1454
+ ```
1455
+
1456
+ ### ./src/\_fields/ChoiceField.tsx
1457
+
1458
+ ```tsx
1459
+ import { Box, ButtonBase, Typography } from '@mui/material'
1460
+ import type { KeyboardEvent } from 'react'
1461
+
1462
+ import { phx } from '../../.phoenix/phx.js'
1463
+ import { FieldShell } from './FieldShell.js'
1464
+ import { NIGHTJAR } from './tokens.js'
1465
+
1466
+ // The body outlines of the model, drawn small, with a stub of the neck
1467
+ const BODY_PATHS: Readonly<Record<string, string>> = {
1468
+ Offset:
1469
+ 'M20 52L23.2 51.8L26.4 51.6L29.6 50.8L32.5 49.5L35.1 47.6L36.9 45L38.1 41.9L38.6 38.8L38.5 35.6L37.8 32.4L36.8 29.4L35.5 26.4L34.6 23.3L34.3 20.1L34.8 17L35 13.7L34.4 10.6L32.8 7.8L30.1 6.2L27.4 7.7L25.5 10.3L22.6 10.7L19.4 10.1L16.4 8.9L15.2 6L14.1 3L11.7 1L8.7 2L7 4.7L6.1 7.8L5.4 10.9L5.3 14.1L5.8 17.3L5.5 20.5L4.8 23.6L3.8 26.7L2.8 29.8L2.2 33L1.8 36.2L1.8 39.4L2.1 42.6L3.1 45.7L4.9 48.3L7.3 50.4L10.4 51.5L13.6 52L16.8 52.1Z',
1470
+ SingleCut:
1471
+ 'M20 51L22.9 50.9L25.7 50.7L28.5 50.2L31.2 49.1L33.6 47.5L35.4 45.3L36.5 42.7L37.1 39.9L37.3 37L36.9 34.2L36 31.5L34.5 29L33.2 26.5L32.2 23.8L32.2 21L31.9 18.1L31 15.4L29.6 12.9L27.7 10.8L25.1 11.6L23.9 14.2L23 12.2L23.1 9.3L21.6 7.1L18.9 6.2L16 6L13.2 6.5L10.6 7.7L8.5 9.6L7.3 12.2L7 15L7.6 17.8L7.3 20.7L6.5 23.4L5.6 26.2L4.6 28.8L3.8 31.6L3.3 34.4L3.1 37.3L3.2 40.1L3.7 43L4.7 45.6L6.4 47.9L8.8 49.5L11.4 50.6L14.3 51L17.1 51.1Z',
1472
+ }
1473
+
1474
+ // Two pickups as seen from the front: thin single coils, double humbuckers, wide P-90s
1475
+ const PICKUP_SHAPES: Readonly<Record<string, readonly { x: number; y: number; width: number; height: number }[]>> = {
1476
+ SingleCoils: [
1477
+ { x: 8, y: 13, width: 24, height: 5 },
1478
+ { x: 8, y: 30, width: 24, height: 5 },
1479
+ ],
1480
+ Humbuckers: [
1481
+ { x: 9, y: 9, width: 22, height: 5 },
1482
+ { x: 9, y: 15, width: 22, height: 5 },
1483
+ { x: 9, y: 28, width: 22, height: 5 },
1484
+ { x: 9, y: 34, width: 22, height: 5 },
1485
+ ],
1486
+ P90s: [
1487
+ { x: 6, y: 10, width: 28, height: 10 },
1488
+ { x: 6, y: 28, width: 28, height: 10 },
1489
+ ],
1490
+ }
1491
+
1492
+ // Swatches as CSS backgrounds: wood with a hint of grain, metal with a highlight, the pearloid's shimmer
1493
+ const WOOD_GRAIN = 'repeating-linear-gradient(100deg, rgba(0, 0, 0, 0.08) 0 2px, transparent 2px 6px)'
1494
+
1495
+ const SWATCHES: Readonly<Record<string, Readonly<Record<string, string>>>> = {
1496
+ pickguard: {
1497
+ Parchment: '#ece2cb',
1498
+ Black: 'radial-gradient(circle at 30% 30%, #3a3a40, #0c0c0e 70%)',
1499
+ Pearloid: 'conic-gradient(from 40deg, #f6f1ea, #e6eef6, #f4e6f0, #eef6ea, #f6f1ea)',
1500
+ None: 'transparent',
1501
+ },
1502
+ neckWood: {
1503
+ Maple: `${WOOD_GRAIN}, #ecd3a3`,
1504
+ RoastedMaple: `${WOOD_GRAIN}, #b9804a`,
1505
+ Mahogany: `${WOOD_GRAIN}, #7b3f28`,
1506
+ },
1507
+ fretboard: {
1508
+ Maple: `${WOOD_GRAIN}, #ecd3a3`,
1509
+ Rosewood: `${WOOD_GRAIN}, #4a2a1c`,
1510
+ Ebony: `${WOOD_GRAIN}, #1d1916`,
1511
+ },
1512
+ hardware: {
1513
+ Chrome: 'linear-gradient(135deg, #ffffff, #9aa1a8 55%, #e4e7ea)',
1514
+ Gold: 'linear-gradient(135deg, #fff1c4, #b8862e 55%, #f3d38a)',
1515
+ Black: 'linear-gradient(135deg, #6a6a70, #121214 55%, #3a3a40)',
1516
+ },
1517
+ }
1518
+
1519
+ interface OptionArtProps {
1520
+ readonly instanceName: string
1521
+ readonly value: string
1522
+ readonly size: number
1523
+ }
1524
+
1525
+ // The small picture beside an option: a silhouette for the body, the pickup layout, or a swatch of the material
1526
+ const OptionArt = ({ instanceName, value, size }: OptionArtProps) => {
1527
+ const bodyPath = instanceName === 'bodyShape' ? BODY_PATHS[value] : undefined
1528
+ const pickups = instanceName === 'pickups' ? PICKUP_SHAPES[value] : undefined
1529
+ const swatch = SWATCHES[instanceName]?.[value]
1530
+
1531
+ if (bodyPath) {
1532
+ return (
1533
+ <Box component="svg" viewBox="0 0 40 54" aria-hidden sx={{ inlineSize: size, blockSize: size, flex: 'none' }}>
1534
+ <rect x={17.8} y={0} width={4.4} height={12} rx={1} fill={NIGHTJAR.faint} />
1535
+ <path d={bodyPath} fill={NIGHTJAR.cream} />
1536
+ </Box>
1537
+ )
1538
+ }
1539
+
1540
+ if (pickups) {
1541
+ return (
1542
+ <Box component="svg" viewBox="0 0 40 48" aria-hidden sx={{ inlineSize: size, blockSize: size, flex: 'none' }}>
1543
+ {pickups.map(shape => (
1544
+ <rect key={`${shape.x}-${shape.y}`} {...shape} rx={2.5} fill={NIGHTJAR.cream} />
1545
+ ))}
1546
+ </Box>
1547
+ )
1548
+ }
1549
+
1550
+ if (swatch === undefined) {
1551
+ return null
1552
+ }
1553
+
1554
+ return (
1555
+ <Box
1556
+ component="span"
1557
+ aria-hidden
1558
+ sx={{
1559
+ inlineSize: size,
1560
+ blockSize: size,
1561
+ flex: 'none',
1562
+ borderRadius: '50%',
1563
+ background: swatch,
1564
+ boxShadow: `inset 0 0 0 1px ${NIGHTJAR.line}`,
1565
+ // "None" is an empty, dashed ring
1566
+ ...(value === 'None' && {
1567
+ border: `1.5px dashed ${NIGHTJAR.faint}`,
1568
+ boxShadow: 'none',
1569
+ }),
1570
+ }}
1571
+ />
1572
+ )
1573
+ }
1574
+
1575
+ // Arrow keys move the selection between the options, as in a native radio group
1576
+ const ARROW_STEPS: Readonly<Record<string, number | undefined>> = {
1577
+ ArrowRight: 1,
1578
+ ArrowDown: 1,
1579
+ ArrowLeft: -1,
1580
+ ArrowUp: -1,
1581
+ }
1582
+
1583
+ interface ChoiceFieldProps {
1584
+ readonly instanceName: string
1585
+ readonly label: string
1586
+ readonly warningTypes: readonly string[]
1587
+ /** Chips in one scrolling row, for a phone; cards in a grid otherwise */
1588
+ readonly compact: boolean
1589
+ }
1590
+
1591
+ // One `attributeSelection` of the spec: cards with a picture, a title and a description, or chips on a phone. An
1592
+ // option a `fixable` invariant rules out is faded with the reason below; it stays clickable, so the change is tried
1593
+ // and rejected.
1594
+ export const ChoiceField = ({ instanceName, label, warningTypes, compact }: ChoiceFieldProps) => {
1595
+ const resolve = phx.frontend.useResolveLocalizable()
1596
+ const guitarId = phx.frontend.useRootEntityId()
1597
+ const { value, options } = phx.frontend.useAttributeSelection(guitarId, instanceName)
1598
+ const selected = options.find(option => option.value === value)
1599
+ const ruledOut = options.find(option => option.disabled && option.hint)?.hint
1600
+
1601
+ const handleKeyDown = (event: KeyboardEvent<HTMLElement>, index: number) => {
1602
+ const step = ARROW_STEPS[event.key]
1603
+
1604
+ if (step === undefined) {
1605
+ return
1606
+ }
1607
+
1608
+ event.preventDefault()
1609
+ const next = (index + step + options.length) % options.length
1610
+ options[next]?.onSelect()
1611
+ event.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role="radio"]')[next]?.focus()
1612
+ }
1613
+
1614
+ return (
1615
+ <FieldShell
1616
+ id={`nightjar-${instanceName}`}
1617
+ label={label}
1618
+ aside={
1619
+ compact && selected ? (
1620
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 14, color: NIGHTJAR.cream }}>
1621
+ {resolve(selected.title)}
1622
+ </Typography>
1623
+ ) : undefined
1624
+ }
1625
+ hint={ruledOut}
1626
+ warningTypes={warningTypes}
1627
+ compact={compact}
1628
+ >
1629
+ <Box
1630
+ component="div"
1631
+ role="radiogroup"
1632
+ aria-labelledby={`nightjar-${instanceName}-label`}
1633
+ sx={
1634
+ compact
1635
+ ? {
1636
+ display: 'flex',
1637
+ gap: 1,
1638
+ marginInline: -2,
1639
+ paddingInline: 2,
1640
+ paddingBlockEnd: 0.5,
1641
+ overflowX: 'auto',
1642
+ scrollbarWidth: 'none',
1643
+ }
1644
+ : { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))', gap: 1 }
1645
+ }
1646
+ >
1647
+ {options.map((option, index) => {
1648
+ const isSelected = option.value === value
1649
+ const description = resolve(option.description)
1650
+
1651
+ return (
1652
+ <ButtonBase
1653
+ key={String(option.value)}
1654
+ role="radio"
1655
+ aria-checked={isSelected}
1656
+ aria-disabled={option.disabled}
1657
+ tabIndex={isSelected ? 0 : -1}
1658
+ onClick={option.onSelect}
1659
+ onKeyDown={event => handleKeyDown(event, index)}
1660
+ sx={{
1661
+ display: 'flex',
1662
+ alignItems: 'center',
1663
+ justifyContent: 'flex-start',
1664
+ gap: compact ? 1 : 1.5,
1665
+ flex: compact ? 'none' : undefined,
1666
+ minBlockSize: compact ? 44 : 64,
1667
+ paddingInline: compact ? 1.5 : 1.5,
1668
+ paddingBlock: compact ? 0.75 : 1.25,
1669
+ textAlign: 'start',
1670
+ borderRadius: compact ? 999 : 1.5,
1671
+ border: `1px solid ${isSelected ? NIGHTJAR.amber : NIGHTJAR.line}`,
1672
+ bgcolor: isSelected ? NIGHTJAR.amberTint : NIGHTJAR.raised,
1673
+ color: NIGHTJAR.cream,
1674
+ opacity: option.disabled ? 0.45 : 1,
1675
+ transition: 'border-color 160ms, background-color 160ms',
1676
+ '&:hover': { bgcolor: isSelected ? NIGHTJAR.amberTint : NIGHTJAR.raisedHover },
1677
+ '&.Mui-focusVisible': { outline: `2px solid ${NIGHTJAR.amber}`, outlineOffset: 2 },
1678
+ }}
1679
+ >
1680
+ <OptionArt instanceName={instanceName} value={String(option.value)} size={compact ? 22 : 36} />
1681
+ <Box component="span" sx={{ display: 'grid', gap: 0.25 }}>
1682
+ <Typography
1683
+ component="span"
1684
+ sx={{
1685
+ fontFamily: NIGHTJAR.font,
1686
+ fontSize: compact ? 14 : 15,
1687
+ fontWeight: 500,
1688
+ whiteSpace: 'nowrap',
1689
+ color: NIGHTJAR.cream,
1690
+ }}
1691
+ >
1692
+ {resolve(option.title)}
1693
+ </Typography>
1694
+ {!compact && description && (
1695
+ <Typography
1696
+ component="span"
1697
+ sx={{ fontFamily: NIGHTJAR.font, fontSize: 13, lineHeight: 1.3, color: NIGHTJAR.muted }}
1698
+ >
1699
+ {description}
1700
+ </Typography>
1701
+ )}
1702
+ </Box>
1703
+ </ButtonBase>
1704
+ )
1705
+ })}
1706
+ </Box>
1707
+ </FieldShell>
1708
+ )
1709
+ }
1710
+ ```
1711
+
1712
+ ### ./src/\_fields/FieldShell.tsx
1713
+
1714
+ ```tsx
1715
+ import { Box, Typography } from '@mui/material'
1716
+ import type { ReactNode } from 'react'
1717
+
1718
+ import { LABEL_SX, NIGHTJAR } from './tokens.js'
1719
+ import { useWarnings } from './use-warnings.js'
1720
+
1721
+ interface FieldShellProps {
1722
+ readonly id: string
1723
+ readonly label: string
1724
+ /** Beside the label: the chosen option's name, or a counter */
1725
+ readonly aside?: ReactNode
1726
+ /** Below the field: why an option is ruled out, or what the customer should know */
1727
+ readonly hint?: string | undefined
1728
+ readonly warningTypes: readonly string[]
1729
+ readonly compact: boolean
1730
+ readonly children: ReactNode
1731
+ }
1732
+
1733
+ // A labelled field. A `warning` violation the field explains is shown below it while it holds; it is the same text
1734
+ // the summary lists, and the stepper marks the step until it is resolved.
1735
+ export const FieldShell = ({ id, label, aside, hint, warningTypes, compact, children }: FieldShellProps) => {
1736
+ const warning = useWarnings().find(candidate => warningTypes.includes(candidate.type))
1737
+
1738
+ return (
1739
+ <Box component="section" aria-labelledby={`${id}-label`} sx={{ display: 'grid', gap: compact ? 1 : 1.5 }}>
1740
+ <Box component="div" sx={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 2 }}>
1741
+ <Typography component="h3" id={`${id}-label`} sx={LABEL_SX}>
1742
+ {label}
1743
+ </Typography>
1744
+ {aside}
1745
+ </Box>
1746
+ {children}
1747
+ {hint && <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 13, color: NIGHTJAR.muted }}>{hint}</Typography>}
1748
+ {warning && (
1749
+ <Typography
1750
+ role="status"
1751
+ sx={{
1752
+ paddingInline: 1.5,
1753
+ paddingBlock: 1,
1754
+ borderInlineStart: `3px solid ${NIGHTJAR.amber}`,
1755
+ bgcolor: NIGHTJAR.amberTint,
1756
+ fontFamily: NIGHTJAR.font,
1757
+ fontSize: 14,
1758
+ lineHeight: 1.4,
1759
+ color: NIGHTJAR.cream,
1760
+ }}
1761
+ >
1762
+ {warning.text}
1763
+ </Typography>
1764
+ )}
1765
+ </Box>
1766
+ )
1767
+ }
1768
+ ```
1769
+
1770
+ ### ./src/\_fields/FinishField.tsx
1771
+
1772
+ ```tsx
1773
+ import { Box, ButtonBase, Tooltip, Typography } from '@mui/material'
1774
+ import type { KeyboardEvent } from 'react'
1775
+
1776
+ import { phx } from '../../.phoenix/phx.js'
1777
+ import { FieldShell } from './FieldShell.js'
1778
+ import { NIGHTJAR } from './tokens.js'
1779
+
1780
+ const ARROW_STEPS: Readonly<Record<string, number | undefined>> = {
1781
+ ArrowRight: 1,
1782
+ ArrowDown: 1,
1783
+ ArrowLeft: -1,
1784
+ ArrowUp: -1,
1785
+ }
1786
+
1787
+ // A highlight over each swatch, so the paint reads as a glossy finish
1788
+ const GLOSS = 'radial-gradient(circle at 32% 28%, rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0) 42%)'
1789
+
1790
+ interface FinishFieldProps {
1791
+ readonly instanceName: string
1792
+ readonly label: string
1793
+ readonly warningTypes: readonly string[]
1794
+ readonly compact: boolean
1795
+ }
1796
+
1797
+ // The spec's `materialSwatch`: round swatches in the colours the spec gives each finish, the chosen one's name
1798
+ // beside the label. `useSwatchSelection` takes the `fixable` violation types to ignore as its third argument.
1799
+ export const FinishField = ({ instanceName, label, warningTypes, compact }: FinishFieldProps) => {
1800
+ const resolve = phx.frontend.useResolveLocalizable()
1801
+ const guitarId = phx.frontend.useRootEntityId()
1802
+ const { options } = phx.frontend.useSwatchSelection(guitarId, instanceName, [])
1803
+ const selected = options.find(option => option.selected)
1804
+ const ruledOut = options.find(option => option.disabled && option.hint)?.hint
1805
+ const size = compact ? 40 : 48
1806
+
1807
+ const handleKeyDown = (event: KeyboardEvent<HTMLElement>, index: number) => {
1808
+ const step = ARROW_STEPS[event.key]
1809
+
1810
+ if (step === undefined) {
1811
+ return
1812
+ }
1813
+
1814
+ event.preventDefault()
1815
+ const next = (index + step + options.length) % options.length
1816
+ options[next]?.onClick()
1817
+ event.currentTarget.parentElement?.querySelectorAll<HTMLElement>('[role="radio"]')[next]?.focus()
1818
+ }
1819
+
1820
+ return (
1821
+ <FieldShell
1822
+ id={`nightjar-${instanceName}`}
1823
+ label={label}
1824
+ aside={
1825
+ selected && (
1826
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 14, color: NIGHTJAR.cream }}>
1827
+ {resolve(selected.swatchName)}
1828
+ </Typography>
1829
+ )
1830
+ }
1831
+ hint={ruledOut ?? undefined}
1832
+ warningTypes={warningTypes}
1833
+ compact={compact}
1834
+ >
1835
+ <Box
1836
+ component="div"
1837
+ role="radiogroup"
1838
+ aria-labelledby={`nightjar-${instanceName}-label`}
1839
+ sx={{ display: 'flex', flexWrap: 'wrap', gap: compact ? 1.5 : 2 }}
1840
+ >
1841
+ {options.map((option, index) => {
1842
+ const name = resolve(option.swatchName)
1843
+
1844
+ return (
1845
+ <Tooltip key={option.swatchKey} title={name}>
1846
+ <ButtonBase
1847
+ role="radio"
1848
+ aria-label={name}
1849
+ aria-checked={option.selected}
1850
+ aria-disabled={option.disabled}
1851
+ tabIndex={option.selected ? 0 : -1}
1852
+ onClick={option.onClick}
1853
+ onKeyDown={event => handleKeyDown(event, index)}
1854
+ sx={{
1855
+ inlineSize: size,
1856
+ blockSize: size,
1857
+ borderRadius: '50%',
1858
+ background: `${GLOSS}, ${option.color}`,
1859
+ // The ring sits outside the swatch, in the panel's colour, so the swatch keeps its full size
1860
+ boxShadow: option.selected
1861
+ ? `0 0 0 3px ${NIGHTJAR.ink}, 0 0 0 5px ${NIGHTJAR.amber}`
1862
+ : `inset 0 0 0 1px ${NIGHTJAR.line}`,
1863
+ opacity: option.disabled ? 0.4 : 1,
1864
+ transition: 'box-shadow 160ms, transform 160ms',
1865
+ '&:hover': { transform: 'scale(1.06)' },
1866
+ '&.Mui-focusVisible': { outline: `2px solid ${NIGHTJAR.cream}`, outlineOffset: 6 },
1867
+ }}
1868
+ />
1869
+ </Tooltip>
1870
+ )
1871
+ })}
1872
+ </Box>
1873
+ </FieldShell>
1874
+ )
1875
+ }
1876
+ ```
1877
+
1878
+ ### ./src/\_fields/SignatureField.tsx
1879
+
1880
+ ```tsx
1881
+ import { Box, InputBase, Typography } from '@mui/material'
1882
+
1883
+ import { phx } from '../../.phoenix/phx.js'
1884
+ import { FieldShell } from './FieldShell.js'
1885
+ import { NIGHTJAR } from './tokens.js'
1886
+
1887
+ interface SignatureFieldProps {
1888
+ readonly instanceName: string
1889
+ readonly label: string
1890
+ readonly warningTypes: readonly string[]
1891
+ readonly compact: boolean
1892
+ }
1893
+
1894
+ // The spec's `textValue`, which the spec prints on the headstock with a text decal. Typing stages each value, so the
1895
+ // headstock follows every key; leaving the field or pressing Enter commits it. A value the `fixable` length rule
1896
+ // rejects shows the rule's message as the hook's `hints`, and leaving the field rolls back to the last value that
1897
+ // fitted. The counter reads the limit from the spec's `$signatureLimit` expression, which the rule checks too.
1898
+ export const SignatureField = ({ instanceName, label, warningTypes, compact }: SignatureFieldProps) => {
1899
+ const guitarId = phx.frontend.useRootEntityId()
1900
+ const guitar = phx.frontend.useRootEntityState()
1901
+ const signature = phx.frontend.useTextValue(guitarId, instanceName)
1902
+ const limit = guitar.$signatureLimit
1903
+
1904
+ return (
1905
+ <FieldShell
1906
+ id={`nightjar-${instanceName}`}
1907
+ label={label}
1908
+ aside={
1909
+ <Typography
1910
+ aria-live="polite"
1911
+ sx={{
1912
+ fontFamily: NIGHTJAR.font,
1913
+ fontSize: 13,
1914
+ fontVariantNumeric: 'tabular-nums',
1915
+ color: signature.hasErrors ? NIGHTJAR.alert : NIGHTJAR.muted,
1916
+ }}
1917
+ >
1918
+ {signature.value.length} / {limit}
1919
+ </Typography>
1920
+ }
1921
+ hint={
1922
+ compact ? undefined : 'In gold leaf on dark necks, in black on maple. Leave it empty for a plain headstock.'
1923
+ }
1924
+ warningTypes={warningTypes}
1925
+ compact={compact}
1926
+ >
1927
+ <Box
1928
+ component="div"
1929
+ sx={{
1930
+ display: 'grid',
1931
+ gap: 1,
1932
+ paddingInline: 2,
1933
+ paddingBlock: compact ? 1 : 1.5,
1934
+ borderRadius: 1.5,
1935
+ border: `1px solid ${signature.hasErrors ? NIGHTJAR.alert : NIGHTJAR.line}`,
1936
+ bgcolor: NIGHTJAR.raised,
1937
+ '&:focus-within': { borderColor: signature.hasErrors ? NIGHTJAR.alert : NIGHTJAR.amber },
1938
+ }}
1939
+ >
1940
+ <InputBase
1941
+ value={signature.value}
1942
+ placeholder="Your name"
1943
+ onChange={event => signature.update(event, event.target.value)}
1944
+ onBlur={signature.resolve}
1945
+ onKeyDown={event => {
1946
+ if (event.key === 'Enter') {
1947
+ signature.resolve()
1948
+ }
1949
+ }}
1950
+ inputProps={{
1951
+ 'aria-labelledby': `nightjar-${instanceName}-label`,
1952
+ 'aria-invalid': signature.hasErrors,
1953
+ 'aria-describedby': `nightjar-${instanceName}-error`,
1954
+ spellCheck: false,
1955
+ }}
1956
+ sx={{
1957
+ fontFamily: NIGHTJAR.script,
1958
+ fontSize: compact ? 30 : 38,
1959
+ lineHeight: 1.2,
1960
+ color: NIGHTJAR.amber,
1961
+ '& input::placeholder': { color: NIGHTJAR.faint, opacity: 1 },
1962
+ }}
1963
+ />
1964
+ </Box>
1965
+ <Typography
1966
+ id={`nightjar-${instanceName}-error`}
1967
+ role="alert"
1968
+ sx={{ fontFamily: NIGHTJAR.font, fontSize: 14, color: NIGHTJAR.alert, '&:empty': { display: 'none' } }}
1969
+ >
1970
+ {signature.hasErrors ? signature.hints : ''}
1971
+ </Typography>
1972
+ </FieldShell>
1973
+ )
1974
+ }
1975
+ ```
1976
+
1977
+ ### ./src/\_fields/StepFields.tsx
1978
+
1979
+ ```tsx
1980
+ import { Box } from '@mui/material'
1981
+
1982
+ import { ChoiceField } from './ChoiceField.js'
1983
+ import { FinishField } from './FinishField.js'
1984
+ import { SignatureField } from './SignatureField.js'
1985
+ import { fieldOf } from './fields.js'
1986
+ import { useActiveChoices } from './use-active-choices.js'
1987
+
1988
+ interface StepFieldsProps {
1989
+ readonly compact: boolean
1990
+ }
1991
+
1992
+ // The fields of the active step. The layout does not list which choice belongs to which step: it shows the choices
1993
+ // the spec leaves active, so moving a choice to another step is a change of its `$filter` in the spec.
1994
+ export const StepFields = ({ compact }: StepFieldsProps) => {
1995
+ const choices = useActiveChoices()
1996
+
1997
+ return (
1998
+ <Box component="div" sx={{ display: 'grid', gap: compact ? 2.5 : 4 }}>
1999
+ {choices.map(({ instanceName, kind }) => {
2000
+ const { label, warningTypes } = fieldOf(instanceName)
2001
+ const props = { instanceName, label, warningTypes, compact }
2002
+
2003
+ switch (kind) {
2004
+ case 'selection':
2005
+ return <ChoiceField key={instanceName} {...props} />
2006
+ case 'swatch':
2007
+ return <FinishField key={instanceName} {...props} />
2008
+ case 'text':
2009
+ return <SignatureField key={instanceName} {...props} />
2010
+ }
2011
+ })}
2012
+ </Box>
2013
+ )
2014
+ }
2015
+ ```
2016
+
2017
+ ### ./src/\_fields/SummaryRows.tsx
2018
+
2019
+ ```tsx
2020
+ import { Box, Typography } from '@mui/material'
2021
+ import type { ReactNode } from 'react'
2022
+
2023
+ import { phx } from '../../.phoenix/phx.js'
2024
+ import { fieldOf } from './fields.js'
2025
+ import { NIGHTJAR } from './tokens.js'
2026
+ import type { ActiveChoice } from './use-active-choices.js'
2027
+ import { useActiveChoices } from './use-active-choices.js'
2028
+
2029
+ interface RowProps {
2030
+ readonly label: string
2031
+ readonly children: ReactNode
2032
+ }
2033
+
2034
+ const Row = ({ label, children }: RowProps) => {
2035
+ return (
2036
+ <Box
2037
+ component="div"
2038
+ sx={{
2039
+ display: 'flex',
2040
+ alignItems: 'baseline',
2041
+ justifyContent: 'space-between',
2042
+ gap: 2,
2043
+ paddingBlock: 1.1,
2044
+ borderBlockEnd: `1px solid ${NIGHTJAR.line}`,
2045
+ }}
2046
+ >
2047
+ <Typography component="dt" sx={{ fontFamily: NIGHTJAR.font, fontSize: 14, color: NIGHTJAR.muted }}>
2048
+ {label}
2049
+ </Typography>
2050
+ <Typography
2051
+ component="dd"
2052
+ sx={{
2053
+ display: 'flex',
2054
+ alignItems: 'center',
2055
+ gap: 1,
2056
+ margin: 0,
2057
+ fontFamily: NIGHTJAR.font,
2058
+ fontSize: 15,
2059
+ fontWeight: 500,
2060
+ textAlign: 'end',
2061
+ color: NIGHTJAR.cream,
2062
+ }}
2063
+ >
2064
+ {children}
2065
+ </Typography>
2066
+ </Box>
2067
+ )
2068
+ }
2069
+
2070
+ interface ChoiceRowProps {
2071
+ readonly instanceName: string
2072
+ readonly label: string
2073
+ }
2074
+
2075
+ // Each row reads its choice with the same control hook the step uses: the option's title, the swatch's name and
2076
+ // colour, the text as written
2077
+ const SelectionRow = ({ instanceName, label }: ChoiceRowProps) => {
2078
+ const resolve = phx.frontend.useResolveLocalizable()
2079
+ const guitarId = phx.frontend.useRootEntityId()
2080
+ const { value, options } = phx.frontend.useAttributeSelection(guitarId, instanceName)
2081
+ const selected = options.find(option => option.value === value)
2082
+
2083
+ return <Row label={label}>{selected ? resolve(selected.title) : '—'}</Row>
2084
+ }
2085
+
2086
+ const SwatchRow = ({ instanceName, label }: ChoiceRowProps) => {
2087
+ const resolve = phx.frontend.useResolveLocalizable()
2088
+ const guitarId = phx.frontend.useRootEntityId()
2089
+ const { options } = phx.frontend.useSwatchSelection(guitarId, instanceName, [])
2090
+ const selected = options.find(option => option.selected)
2091
+
2092
+ return (
2093
+ <Row label={label}>
2094
+ {selected && (
2095
+ <Box
2096
+ component="span"
2097
+ aria-hidden
2098
+ sx={{ inlineSize: 12, blockSize: 12, borderRadius: '50%', bgcolor: selected.color }}
2099
+ />
2100
+ )}
2101
+ {selected ? resolve(selected.swatchName) : '—'}
2102
+ </Row>
2103
+ )
2104
+ }
2105
+
2106
+ const TextRow = ({ instanceName, label }: ChoiceRowProps) => {
2107
+ const guitarId = phx.frontend.useRootEntityId()
2108
+ const { value } = phx.frontend.useTextValue(guitarId, instanceName)
2109
+
2110
+ return (
2111
+ <Row label={label}>
2112
+ {value.trim() === '' ? (
2113
+ 'None'
2114
+ ) : (
2115
+ <Box component="span" sx={{ fontFamily: NIGHTJAR.script, fontSize: 24, lineHeight: 1, color: NIGHTJAR.amber }}>
2116
+ {value}
2117
+ </Box>
2118
+ )}
2119
+ </Row>
2120
+ )
2121
+ }
2122
+
2123
+ const ChoiceRow = ({ instanceName, kind }: ActiveChoice) => {
2124
+ const { label } = fieldOf(instanceName)
2125
+
2126
+ switch (kind) {
2127
+ case 'selection':
2128
+ return <SelectionRow instanceName={instanceName} label={label} />
2129
+ case 'swatch':
2130
+ return <SwatchRow instanceName={instanceName} label={label} />
2131
+ case 'text':
2132
+ return <TextRow instanceName={instanceName} label={label} />
2133
+ }
2134
+ }
2135
+
2136
+ // Every choice, read-only: the summary and the confirmation list the choices the spec leaves active in their states
2137
+ export const SummaryRows = () => {
2138
+ const choices = useActiveChoices()
2139
+
2140
+ return (
2141
+ <Box component="dl" sx={{ margin: 0 }}>
2142
+ {choices.map(choice => (
2143
+ <ChoiceRow key={choice.instanceName} {...choice} />
2144
+ ))}
2145
+ </Box>
2146
+ )
2147
+ }
2148
+ ```
2149
+
2150
+ ### ./src/\_fields/fields.ts
2151
+
2152
+ ```ts
2153
+ /** A choice of the spec as the layout presents it. */
2154
+ export interface Field {
2155
+ /** The spec component's instance name */
2156
+ readonly instanceName: string
2157
+ /** The spec's `attributeSelection`, `materialSwatch` and `textValue` carry no label; the layout names the choice */
2158
+ readonly label: string
2159
+ /** The `warning` violations the field explains when they hold */
2160
+ readonly warningTypes: readonly string[]
2161
+ }
2162
+
2163
+ // Every choice the layout knows, in the order it lists them. Which ones a step shows is the spec's business: a step
2164
+ // lists the choices whose `$filter` leaves them active in its navigation state.
2165
+ export const FIELDS: readonly Field[] = [
2166
+ { instanceName: 'bodyShape', label: 'Body shape', warningTypes: ['offsetHumbuckers'] },
2167
+ { instanceName: 'finish', label: 'Finish', warningTypes: [] },
2168
+ { instanceName: 'pickguard', label: 'Pickguard', warningTypes: [] },
2169
+ { instanceName: 'neckWood', label: 'Neck wood', warningTypes: [] },
2170
+ { instanceName: 'fretboard', label: 'Fretboard', warningTypes: [] },
2171
+ { instanceName: 'pickups', label: 'Pickups', warningTypes: ['offsetHumbuckers'] },
2172
+ { instanceName: 'hardware', label: 'Hardware', warningTypes: [] },
2173
+ { instanceName: 'signature', label: 'Headstock signature', warningTypes: [] },
2174
+ ]
2175
+
2176
+ /** The layout's field for an instance name, or a plain one for a choice the layout does not know. */
2177
+ export const fieldOf = (instanceName: string): Field => {
2178
+ return (
2179
+ FIELDS.find(field => field.instanceName === instanceName) ?? { instanceName, label: instanceName, warningTypes: [] }
2180
+ )
2181
+ }
2182
+
2183
+ /** Orders instance names as the layout lists them; unknown ones go last. */
2184
+ export const byFieldOrder = (a: string, b: string): number => {
2185
+ const rank = (instanceName: string) => {
2186
+ const index = FIELDS.findIndex(field => field.instanceName === instanceName)
2187
+
2188
+ return index === -1 ? FIELDS.length : index
2189
+ }
2190
+
2191
+ return rank(a) - rank(b)
2192
+ }
2193
+ ```
2194
+
2195
+ ### ./src/\_fields/tokens.ts
2196
+
2197
+ ```ts
2198
+ import { keyframes } from '@mui/material'
2199
+
2200
+ // Backstage at night: ink panels, amber light and cream type. Barlow is the brand's typeface, loaded by the page;
2201
+ // SignPainter only previews the headstock signature. The stacks fall back to system fonts where they are not loaded.
2202
+ export const NIGHTJAR = {
2203
+ ink: '#0e0f12',
2204
+ panel: 'rgba(14, 15, 18, 0.9)',
2205
+ raised: '#181a20',
2206
+ raisedHover: '#20232a',
2207
+ line: 'rgba(237, 230, 214, 0.14)',
2208
+ amber: '#f2a33a',
2209
+ amberHover: '#ffb54f',
2210
+ amberTint: 'rgba(242, 163, 58, 0.12)',
2211
+ cream: '#ede6d6',
2212
+ muted: 'rgba(237, 230, 214, 0.64)',
2213
+ faint: 'rgba(237, 230, 214, 0.38)',
2214
+ oxblood: '#7a1e2b',
2215
+ alert: '#f07a84',
2216
+ alertTint: 'rgba(122, 30, 43, 0.32)',
2217
+ font: "'Barlow', 'Helvetica Neue', Arial, sans-serif",
2218
+ script: "'SignPainter-HouseScript', 'Brush Script MT', cursive",
2219
+ } as const
2220
+
2221
+ // Bold capitals with wide tracking, for headings and the stepper
2222
+ export const HEADING_SX = {
2223
+ fontFamily: NIGHTJAR.font,
2224
+ fontWeight: 700,
2225
+ letterSpacing: '0.16em',
2226
+ textTransform: 'uppercase',
2227
+ color: NIGHTJAR.cream,
2228
+ } as const
2229
+
2230
+ // Small capitals, for field labels and overlines
2231
+ export const LABEL_SX = {
2232
+ fontFamily: NIGHTJAR.font,
2233
+ fontSize: 12,
2234
+ fontWeight: 500,
2235
+ letterSpacing: '0.2em',
2236
+ textTransform: 'uppercase',
2237
+ color: NIGHTJAR.muted,
2238
+ } as const
2239
+
2240
+ // A page or a step's content enters from the side it comes from, or a phone's sheet from below, fading in
2241
+ export const ENTER_FROM_END = keyframes`
2242
+ from { opacity: 0; transform: translateX(48px); }
2243
+ to { opacity: 1; transform: none; }
2244
+ `
2245
+
2246
+ export const ENTER_FROM_START = keyframes`
2247
+ from { opacity: 0; transform: translateX(-48px); }
2248
+ to { opacity: 1; transform: none; }
2249
+ `
2250
+
2251
+ export const ENTER_FROM_BELOW = keyframes`
2252
+ from { opacity: 0; transform: translateY(56px); }
2253
+ to { opacity: 1; transform: none; }
2254
+ `
2255
+ ```
2256
+
2257
+ ### ./src/\_fields/use-active-choices.ts
2258
+
2259
+ ```ts
2260
+ import { useMemo } from 'react'
2261
+
2262
+ import { attributeSelectionComponent, materialSwatchComponent, textValueComponent } from '@salsita-ai/sdk/domain'
2263
+
2264
+ import { phx } from '../../.phoenix/phx.js'
2265
+ import { byFieldOrder } from './fields.js'
2266
+
2267
+ export type ChoiceKind = 'selection' | 'swatch' | 'text'
2268
+
2269
+ /** A choice of the spec that is active now. */
2270
+ export interface ActiveChoice {
2271
+ readonly instanceName: string
2272
+ readonly kind: ChoiceKind
2273
+ }
2274
+
2275
+ // The guitar's choices whose spec component is active in the current navigation state, in the layout's order. A
2276
+ // `$filter` with `navigationStates` makes a component active only in those states, so on each step this is the step's
2277
+ // choices, and on the summary every choice. The control hooks throw for an inactive component; a field mounts only
2278
+ // for a choice listed here.
2279
+ export const useActiveChoices = (): readonly ActiveChoice[] => {
2280
+ const guitarId = phx.frontend.useRootEntityId()
2281
+ const selections = phx.frontend.useComponents({
2282
+ componentTypes: [attributeSelectionComponent],
2283
+ entityIds: [guitarId],
2284
+ })
2285
+ const swatches = phx.frontend.useComponents({ componentTypes: [materialSwatchComponent], entityIds: [guitarId] })
2286
+ const texts = phx.frontend.useComponents({ componentTypes: [textValueComponent], entityIds: [guitarId] })
2287
+
2288
+ return useMemo(() => {
2289
+ const choices = [
2290
+ ...(selections ?? []).map(
2291
+ ({ componentInstance }): ActiveChoice => ({ instanceName: componentInstance.instanceName, kind: 'selection' })
2292
+ ),
2293
+ ...(swatches ?? []).map(
2294
+ ({ componentInstance }): ActiveChoice => ({ instanceName: componentInstance.instanceName, kind: 'swatch' })
2295
+ ),
2296
+ ...(texts ?? []).map(
2297
+ ({ componentInstance }): ActiveChoice => ({ instanceName: componentInstance.instanceName, kind: 'text' })
2298
+ ),
2299
+ ]
2300
+
2301
+ return choices.sort((a, b) => byFieldOrder(a.instanceName, b.instanceName))
2302
+ }, [selections, swatches, texts])
2303
+ }
2304
+ ```
2305
+
2306
+ ### ./src/\_fields/use-warnings.ts
2307
+
2308
+ ```ts
2309
+ import { useMemo } from 'react'
2310
+
2311
+ import { phx } from '../../.phoenix/phx.js'
2312
+
2313
+ export interface Warning {
2314
+ readonly type: string
2315
+ readonly text: string
2316
+ }
2317
+
2318
+ // The warnings of the committed configuration, with their text resolved. A `warning` invariant keeps the change, so
2319
+ // its violation stays until the customer resolves it, and ordering waits for that. `useFinalizeViolations` lists them;
2320
+ // `useStateValidity` holds the same list, but on `phx.frontend` it is typed as the validity value instead of a hook,
2321
+ // so calling it does not type-check.
2322
+ export const useWarnings = (): readonly Warning[] => {
2323
+ const { violations } = phx.frontend.useFinalizeViolations()
2324
+ const resolve = phx.frontend.useResolveLocalizable()
2325
+
2326
+ return useMemo(() => {
2327
+ return (violations ?? [])
2328
+ .filter(({ violation }) => violation.severity === 'warning')
2329
+ .map(({ violation }) => ({ type: violation.type, text: resolve(violation.message) ?? violation.type }))
2330
+ }, [violations, resolve])
2331
+ }
2332
+ ```
2333
+
2334
+ ### ./src/\_shared/DesktopPage.tsx
2335
+
2336
+ ```tsx
2337
+ import { Box, Typography } from '@mui/material'
2338
+ import type { AnimationEvent } from 'react'
2339
+
2340
+ import { phx } from '../../.phoenix/phx.js'
2341
+ import { ENTER_FROM_END, HEADING_SX, NIGHTJAR } from '../_fields/index.js'
2342
+ import { OrderBar } from './OrderBar.js'
2343
+ import { OrderConfirmation } from './OrderConfirmation.js'
2344
+ import { StepHeader } from './StepHeader.js'
2345
+ import { StepPanel } from './StepPanel.js'
2346
+ import { SummaryPanel } from './SummaryPanel.js'
2347
+ import type { OrderForm } from './order-form.js'
2348
+
2349
+ type Page = 'steps' | 'summary' | 'ordered'
2350
+
2351
+ // The summary needs room for the contact form, so its panel is wider
2352
+ const PANEL_WIDTHS: Readonly<Record<Page, number>> = { steps: 420, summary: 520, ordered: 420 }
2353
+
2354
+ const pageOf = (navigationState: string): Page => {
2355
+ return navigationState === 'ordered' ? 'ordered' : navigationState === 'summary' ? 'summary' : 'steps'
2356
+ }
2357
+
2358
+ // The brand's mark: a fret of amber over the name of the shop
2359
+ const Brand = () => {
2360
+ return (
2361
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', gap: 1.5, flex: 'none' }}>
2362
+ <Box component="span" aria-hidden sx={{ inlineSize: 4, blockSize: 28, bgcolor: NIGHTJAR.amber }} />
2363
+ <Box component="div" sx={{ display: 'grid' }}>
2364
+ <Typography sx={{ ...HEADING_SX, fontSize: 16, letterSpacing: '0.32em', lineHeight: 1.1 }}>
2365
+ Northfret
2366
+ </Typography>
2367
+ <Typography sx={{ ...HEADING_SX, fontSize: 10, letterSpacing: '0.36em', color: NIGHTJAR.muted }}>
2368
+ Custom shop
2369
+ </Typography>
2370
+ </Box>
2371
+ </Box>
2372
+ )
2373
+ }
2374
+
2375
+ interface DesktopPageProps {
2376
+ readonly form: OrderForm
2377
+ readonly reached: number
2378
+ }
2379
+
2380
+ // The desktop wizard: the stepper on top, the guitar in the free area on the left, the panel of the step on the
2381
+ // right and the bar with the price at the bottom.
2382
+ //
2383
+ // The summary's panel is wider than a step's, so the steps, the summary and the confirmation are three pages, each
2384
+ // with its own safe area, and each slides in when it opens. The safe area slides with its page: the first
2385
+ // measurement, taken when the page mounts, sees it shifted, and no resize follows when the slide ends. `update()`
2386
+ // from `useSceneSafeArea` measures again once the slide has settled, so the camera frames the guitar in the place the
2387
+ // page leaves for it.
2388
+ export const DesktopPage = ({ form, reached }: DesktopPageProps) => {
2389
+ const { containerRef, safeAreaRef, update } = phx.frontend.useSceneSafeArea()
2390
+ const navigationState = phx.frontend.useActiveNavigationState()
2391
+ const page = pageOf(navigationState)
2392
+
2393
+ // The step's own content slides too; only the page's slide moves the safe area
2394
+ const handleAnimationEnd = (event: AnimationEvent<HTMLDivElement>) => {
2395
+ if (event.target === event.currentTarget) {
2396
+ update()
2397
+ }
2398
+ }
2399
+
2400
+ return (
2401
+ <Box
2402
+ component="div"
2403
+ ref={containerRef}
2404
+ sx={{
2405
+ position: 'absolute',
2406
+ inset: 0,
2407
+ display: 'grid',
2408
+ gridTemplateRows: 'auto minmax(0, 1fr) auto',
2409
+ fontFamily: NIGHTJAR.font,
2410
+ color: NIGHTJAR.cream,
2411
+ // The free area lies over the canvas; only the bars and the panel take the pointer
2412
+ pointerEvents: 'none',
2413
+ }}
2414
+ >
2415
+ <Box
2416
+ component="header"
2417
+ sx={{
2418
+ display: 'flex',
2419
+ alignItems: 'center',
2420
+ gap: 5,
2421
+ minBlockSize: 72,
2422
+ paddingInline: 4,
2423
+ bgcolor: NIGHTJAR.ink,
2424
+ borderBlockEnd: `1px solid ${NIGHTJAR.line}`,
2425
+ pointerEvents: 'auto',
2426
+ }}
2427
+ >
2428
+ <Brand />
2429
+ <StepHeader compact={false} reached={reached} />
2430
+ </Box>
2431
+
2432
+ <Box
2433
+ component="div"
2434
+ key={page}
2435
+ onAnimationEnd={handleAnimationEnd}
2436
+ sx={{
2437
+ display: 'grid',
2438
+ gridTemplateColumns: `minmax(0, 1fr) ${PANEL_WIDTHS[page]}px`,
2439
+ minBlockSize: 0,
2440
+ animation: `${ENTER_FROM_END} 480ms cubic-bezier(0.2, 0.7, 0.2, 1)`,
2441
+ '@media (prefers-reduced-motion: reduce)': { animation: 'none' },
2442
+ }}
2443
+ >
2444
+ <Box component="div" sx={{ position: 'relative', minInlineSize: 0 }}>
2445
+ {/* The camera fits the guitar into this box, so its inset is the room around the guitar */}
2446
+ <Box component="div" ref={safeAreaRef} sx={{ position: 'absolute', inset: '40px 72px 56px' }} />
2447
+ <Typography
2448
+ sx={{
2449
+ position: 'absolute',
2450
+ insetBlockEnd: 20,
2451
+ insetInline: 0,
2452
+ textAlign: 'center',
2453
+ fontSize: 12,
2454
+ letterSpacing: '0.14em',
2455
+ textTransform: 'uppercase',
2456
+ color: NIGHTJAR.faint,
2457
+ }}
2458
+ >
2459
+ Drag to turn the guitar
2460
+ </Typography>
2461
+ </Box>
2462
+ <Box
2463
+ component="aside"
2464
+ aria-label={page === 'steps' ? 'Step' : page === 'summary' ? 'Summary' : 'Order'}
2465
+ sx={{
2466
+ overflowY: 'auto',
2467
+ paddingInline: 4,
2468
+ paddingBlock: 4,
2469
+ bgcolor: NIGHTJAR.panel,
2470
+ borderInlineStart: `1px solid ${NIGHTJAR.line}`,
2471
+ pointerEvents: 'auto',
2472
+ }}
2473
+ >
2474
+ {page === 'steps' && <StepPanel compact={false} />}
2475
+ {page === 'summary' && <SummaryPanel compact={false} form={form} />}
2476
+ {page === 'ordered' && <OrderConfirmation compact={false} contact={form.contact} />}
2477
+ </Box>
2478
+ </Box>
2479
+
2480
+ <OrderBar compact={false} form={form} />
2481
+ </Box>
2482
+ )
2483
+ }
2484
+ ```
2485
+
2486
+ ### ./src/\_shared/OrderBar.tsx
2487
+
2488
+ ```tsx
2489
+ import { Box, Button, CircularProgress, IconButton, Tooltip, Typography } from '@mui/material'
2490
+
2491
+ import { FrontendAnalyticsFactory } from '@salsita-ai/sdk/configurator'
2492
+ import { detailComponent } from '@salsita-ai/sdk/domain'
2493
+
2494
+ import { phx } from '../../.phoenix/phx.js'
2495
+ import { HEADING_SX, LABEL_SX, NIGHTJAR } from '../_fields/index.js'
2496
+ import type { OrderForm } from './order-form.js'
2497
+
2498
+ const BACK_ICON = 'M15 5l-7 7 7 7'
2499
+
2500
+ interface OrderBarProps {
2501
+ /** The phone's bar: price and two buttons */
2502
+ readonly compact: boolean
2503
+ readonly form: OrderForm
2504
+ }
2505
+
2506
+ // The bar at the bottom: the guitar's name and price, Back, and the step's main action. On a step that is Next, on
2507
+ // the step before the summary **Review order**, on the summary **Place order**, and after the order **Design another**.
2508
+ export const OrderBar = ({ compact, form }: OrderBarProps) => {
2509
+ const resolve = phx.frontend.useResolveLocalizable()
2510
+ const detail = phx.frontend.useFirstRootComponent(detailComponent)
2511
+ const price = phx.frontend.useRootEntityPrice()
2512
+ const { steps, activeIndex, canGoPrevious, isLast, next, previous } = phx.frontend.useStepNavigation()
2513
+ const navigationState = phx.frontend.useActiveNavigationState()
2514
+ const navigate = phx.frontend.useNavigate()
2515
+ const analytics = phx.frontend.useAnalytics()
2516
+ const { primary, hints } = phx.frontend.useFinalizeActions()
2517
+ const { accessInfo } = phx.frontend.useAccessService()
2518
+
2519
+ const isOrdered = navigationState === 'ordered'
2520
+ const isPending = primary?.isPending ?? false
2521
+ const nextStep = steps[activeIndex + 1]
2522
+ const firstStep = steps[0]
2523
+
2524
+ // The step before the last one leads to the summary. Like the built-in summary button, it records
2525
+ // `SummaryButtonClicked`, which `next()` would not: it records the next-step button's event.
2526
+ const enterSummary = () => {
2527
+ if (nextStep === undefined) {
2528
+ return
2529
+ }
2530
+
2531
+ analytics.push(FrontendAnalyticsFactory.SummaryButtonClicked())
2532
+ navigate(nextStep.state)
2533
+ }
2534
+
2535
+ // A conflict or a missing detail blocks the order; the button stays clickable and shows what is missing instead
2536
+ const placeOrder = () => {
2537
+ if (primary === null) {
2538
+ return
2539
+ }
2540
+
2541
+ if (primary.disabled || !form.isComplete) {
2542
+ form.revealErrors()
2543
+ return
2544
+ }
2545
+
2546
+ void primary.run()
2547
+ }
2548
+
2549
+ const designAnother = () => {
2550
+ if (firstStep) {
2551
+ navigate(firstStep.state)
2552
+ }
2553
+ }
2554
+
2555
+ const action = isOrdered
2556
+ ? { label: 'Design another', onClick: designAnother, blocked: false }
2557
+ : isLast
2558
+ ? { label: primary?.label ?? 'Place order', onClick: placeOrder, blocked: primary?.disabled ?? true }
2559
+ : nextStep?.index === steps.length - 1
2560
+ ? { label: 'Review order', onClick: enterSummary, blocked: false }
2561
+ : { label: compact ? 'Next' : `Next: ${nextStep?.label ?? ''}`, onClick: next, blocked: false }
2562
+ const showAction = !(isLast && !isOrdered && (primary === null || accessInfo.viewMode))
2563
+ const blockedNote = isLast && !isOrdered && primary?.disabled && hints ? 'Settle the choices above first' : null
2564
+
2565
+ return (
2566
+ <Box
2567
+ component="footer"
2568
+ sx={{
2569
+ display: 'flex',
2570
+ alignItems: 'center',
2571
+ gap: compact ? 1.5 : 3,
2572
+ minBlockSize: compact ? 72 : 84,
2573
+ paddingInline: compact ? 2 : 4,
2574
+ paddingBlock: 1.5,
2575
+ bgcolor: NIGHTJAR.ink,
2576
+ borderBlockStart: `1px solid ${NIGHTJAR.line}`,
2577
+ pointerEvents: 'auto',
2578
+ }}
2579
+ >
2580
+ {!compact && (
2581
+ <Box component="div" sx={{ display: 'grid', gap: 0.25, minInlineSize: 0 }}>
2582
+ <Typography sx={{ ...HEADING_SX, fontSize: 18, letterSpacing: '0.24em' }}>
2583
+ {detail ? resolve(detail.state.title) : 'Nightjar'}
2584
+ </Typography>
2585
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 13, color: NIGHTJAR.muted, whiteSpace: 'nowrap' }}>
2586
+ {detail ? resolve(detail.state.subtitle) : ''}
2587
+ </Typography>
2588
+ </Box>
2589
+ )}
2590
+
2591
+ <Box component="div" sx={{ display: 'grid', marginInlineStart: compact ? 0 : 'auto', minInlineSize: 0 }}>
2592
+ <Typography sx={{ ...LABEL_SX, fontSize: 11 }}>{isOrdered ? 'Ordered' : 'Your price'}</Typography>
2593
+ <Typography
2594
+ aria-live="polite"
2595
+ sx={{
2596
+ fontFamily: NIGHTJAR.font,
2597
+ fontSize: compact ? 22 : 28,
2598
+ fontWeight: 700,
2599
+ lineHeight: 1.1,
2600
+ fontVariantNumeric: 'tabular-nums',
2601
+ color: NIGHTJAR.cream,
2602
+ }}
2603
+ >
2604
+ {price}
2605
+ </Typography>
2606
+ </Box>
2607
+
2608
+ <Box
2609
+ component="div"
2610
+ sx={{ display: 'flex', alignItems: 'center', gap: 1.5, marginInlineStart: compact ? 'auto' : 2 }}
2611
+ >
2612
+ {blockedNote && !compact && (
2613
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 14, color: NIGHTJAR.amber }}>{blockedNote}</Typography>
2614
+ )}
2615
+ {canGoPrevious && !isOrdered && (
2616
+ <Tooltip title="Back">
2617
+ <span>
2618
+ <IconButton
2619
+ aria-label="Back"
2620
+ onClick={previous}
2621
+ disabled={isPending}
2622
+ sx={{
2623
+ inlineSize: 48,
2624
+ blockSize: 48,
2625
+ border: `1px solid ${NIGHTJAR.line}`,
2626
+ color: NIGHTJAR.cream,
2627
+ '&:hover': { bgcolor: NIGHTJAR.raisedHover },
2628
+ '&.Mui-disabled': { color: NIGHTJAR.faint },
2629
+ }}
2630
+ >
2631
+ <svg viewBox="0 0 24 24" width={20} height={20} fill="none" stroke="currentColor" strokeWidth={2}>
2632
+ <path d={BACK_ICON} strokeLinecap="round" strokeLinejoin="round" />
2633
+ </svg>
2634
+ </IconButton>
2635
+ </span>
2636
+ </Tooltip>
2637
+ )}
2638
+ {showAction && (
2639
+ <Button
2640
+ onClick={action.onClick}
2641
+ disabled={isPending}
2642
+ aria-disabled={action.blocked || undefined}
2643
+ title={isLast && !isOrdered ? (hints ?? primary?.title) : undefined}
2644
+ startIcon={isPending ? <CircularProgress size={16} sx={{ color: NIGHTJAR.ink }} /> : undefined}
2645
+ sx={{
2646
+ ...HEADING_SX,
2647
+ minBlockSize: 48,
2648
+ paddingInline: compact ? 2.5 : 3.5,
2649
+ borderRadius: 1,
2650
+ fontSize: 14,
2651
+ whiteSpace: 'nowrap',
2652
+ color: NIGHTJAR.ink,
2653
+ bgcolor: action.blocked ? NIGHTJAR.muted : NIGHTJAR.amber,
2654
+ '&:hover': { bgcolor: action.blocked ? NIGHTJAR.muted : NIGHTJAR.amberHover },
2655
+ '&.Mui-disabled': { color: NIGHTJAR.ink, bgcolor: NIGHTJAR.amber, opacity: 0.75 },
2656
+ '&.Mui-focusVisible': { outline: `2px solid ${NIGHTJAR.cream}`, outlineOffset: 2 },
2657
+ }}
2658
+ >
2659
+ {isPending ? 'Placing order…' : action.label}
2660
+ </Button>
2661
+ )}
2662
+ </Box>
2663
+ </Box>
2664
+ )
2665
+ }
2666
+ ```
2667
+
2668
+ ### ./src/\_shared/OrderConfirmation.tsx
2669
+
2670
+ ```tsx
2671
+ import { Box, Typography } from '@mui/material'
2672
+
2673
+ import { phx } from '../../.phoenix/phx.js'
2674
+ import { HEADING_SX, LABEL_SX, NIGHTJAR, SummaryRows } from '../_fields/index.js'
2675
+ import type { Contact } from './order-form.js'
2676
+
2677
+ const CHECK_ICON = 'M5 12.5 10 17.5 19 7'
2678
+
2679
+ interface OrderConfirmationProps {
2680
+ readonly compact: boolean
2681
+ readonly contact: Contact
2682
+ }
2683
+
2684
+ // The `ordered` navigation state, which the order handler enters once the order is accepted. The order number is
2685
+ // made from the configuration's id, so it stays the same when the confirmation is shown again.
2686
+ export const OrderConfirmation = ({ compact, contact }: OrderConfirmationProps) => {
2687
+ const configurationId = phx.frontend.useConfigurationId()
2688
+ const price = phx.frontend.useRootEntityPrice()
2689
+ const orderNumber = `NJ-${String(configurationId)
2690
+ .replace(/[^a-z0-9]/gi, '')
2691
+ .slice(-6)
2692
+ .toUpperCase()}`
2693
+ const name = contact.name.trim()
2694
+
2695
+ return (
2696
+ <Box component="div" role="status" sx={{ display: 'grid', gap: compact ? 2.5 : 3 }}>
2697
+ <Box component="header" sx={{ display: 'grid', gap: 1.5, justifyItems: 'start' }}>
2698
+ <Box
2699
+ component="svg"
2700
+ viewBox="0 0 24 24"
2701
+ aria-hidden
2702
+ sx={{ inlineSize: 44, blockSize: 44, padding: 1.25, borderRadius: '50%', bgcolor: NIGHTJAR.amber }}
2703
+ >
2704
+ <path d={CHECK_ICON} fill="none" stroke={NIGHTJAR.ink} strokeWidth={2.6} strokeLinecap="round" />
2705
+ </Box>
2706
+ <Typography sx={LABEL_SX}>Order {orderNumber}</Typography>
2707
+ <Typography component="h2" sx={{ ...HEADING_SX, fontSize: compact ? 24 : 30, lineHeight: 1.05 }}>
2708
+ {name ? `Thank you, ${name}` : 'Thank you'}
2709
+ </Typography>
2710
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 15, lineHeight: 1.5, color: NIGHTJAR.muted }}>
2711
+ Your Nightjar goes into the build queue at {price}. We will write to {contact.email.trim() || 'you'} when the
2712
+ shop confirms it; a build takes about eight weeks.
2713
+ </Typography>
2714
+ </Box>
2715
+ <Box component="section" sx={{ display: 'grid', gap: 1.5 }}>
2716
+ <Typography component="h3" sx={LABEL_SX}>
2717
+ What we are building
2718
+ </Typography>
2719
+ <SummaryRows />
2720
+ </Box>
2721
+ </Box>
2722
+ )
2723
+ }
2724
+ ```
2725
+
2726
+ ### ./src/\_shared/PhonePage.tsx
2727
+
2728
+ ```tsx
2729
+ import { Box, Typography } from '@mui/material'
2730
+ import type { AnimationEvent } from 'react'
2731
+
2732
+ import { phx } from '../../.phoenix/phx.js'
2733
+ import { ENTER_FROM_BELOW, HEADING_SX, NIGHTJAR } from '../_fields/index.js'
2734
+ import { OrderBar } from './OrderBar.js'
2735
+ import { OrderConfirmation } from './OrderConfirmation.js'
2736
+ import { StepHeader } from './StepHeader.js'
2737
+ import { StepPanel } from './StepPanel.js'
2738
+ import { SummaryPanel } from './SummaryPanel.js'
2739
+ import type { OrderForm } from './order-form.js'
2740
+
2741
+ type Page = 'steps' | 'summary' | 'ordered'
2742
+
2743
+ // How much of the screen below the header the guitar keeps: the summary's form needs more of it
2744
+ const SCENE_SHARES: Readonly<Record<Page, string>> = { steps: '46%', summary: '30%', ordered: '40%' }
2745
+
2746
+ const pageOf = (navigationState: string): Page => {
2747
+ return navigationState === 'ordered' ? 'ordered' : navigationState === 'summary' ? 'summary' : 'steps'
2748
+ }
2749
+
2750
+ interface PhonePageProps {
2751
+ readonly form: OrderForm
2752
+ readonly reached: number
2753
+ }
2754
+
2755
+ // The phone wizard: a compact progress line, the guitar at the top, the step's choices in a sheet below it and the
2756
+ // bar fixed at the bottom. Like the desktop pages, each page rises in with its own safe area and measures it again
2757
+ // with `update()` once the slide has settled.
2758
+ export const PhonePage = ({ form, reached }: PhonePageProps) => {
2759
+ const { containerRef, safeAreaRef, update } = phx.frontend.useSceneSafeArea()
2760
+ const navigationState = phx.frontend.useActiveNavigationState()
2761
+ const page = pageOf(navigationState)
2762
+
2763
+ const handleAnimationEnd = (event: AnimationEvent<HTMLDivElement>) => {
2764
+ if (event.target === event.currentTarget) {
2765
+ update()
2766
+ }
2767
+ }
2768
+
2769
+ return (
2770
+ <Box
2771
+ component="div"
2772
+ ref={containerRef}
2773
+ sx={{
2774
+ position: 'absolute',
2775
+ inset: 0,
2776
+ display: 'flex',
2777
+ flexDirection: 'column',
2778
+ fontFamily: NIGHTJAR.font,
2779
+ color: NIGHTJAR.cream,
2780
+ pointerEvents: 'none',
2781
+ }}
2782
+ >
2783
+ <Box
2784
+ component="header"
2785
+ sx={{
2786
+ display: 'grid',
2787
+ gap: 1.25,
2788
+ paddingInline: 2,
2789
+ paddingBlock: 1.5,
2790
+ bgcolor: NIGHTJAR.ink,
2791
+ borderBlockEnd: `1px solid ${NIGHTJAR.line}`,
2792
+ pointerEvents: 'auto',
2793
+ }}
2794
+ >
2795
+ <Box component="div" sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
2796
+ <Box component="span" aria-hidden sx={{ inlineSize: 3, blockSize: 16, bgcolor: NIGHTJAR.amber }} />
2797
+ <Typography sx={{ ...HEADING_SX, fontSize: 13, letterSpacing: '0.32em' }}>Northfret</Typography>
2798
+ </Box>
2799
+ <StepHeader compact reached={reached} />
2800
+ </Box>
2801
+
2802
+ <Box
2803
+ component="div"
2804
+ key={page}
2805
+ onAnimationEnd={handleAnimationEnd}
2806
+ sx={{
2807
+ display: 'flex',
2808
+ flexDirection: 'column',
2809
+ flex: '1 1 0',
2810
+ minBlockSize: 0,
2811
+ animation: `${ENTER_FROM_BELOW} 460ms cubic-bezier(0.2, 0.7, 0.2, 1)`,
2812
+ '@media (prefers-reduced-motion: reduce)': { animation: 'none' },
2813
+ }}
2814
+ >
2815
+ <Box component="div" sx={{ position: 'relative', flex: `0 0 ${SCENE_SHARES[page]}`, minBlockSize: 0 }}>
2816
+ <Box component="div" ref={safeAreaRef} sx={{ position: 'absolute', inset: '12px 16px 8px' }} />
2817
+ </Box>
2818
+ <Box
2819
+ component="main"
2820
+ sx={{
2821
+ flex: '1 1 0',
2822
+ minBlockSize: 0,
2823
+ overflowY: 'auto',
2824
+ overscrollBehavior: 'contain',
2825
+ paddingInline: 2,
2826
+ paddingBlock: 2.5,
2827
+ bgcolor: NIGHTJAR.panel,
2828
+ borderBlockStart: `1px solid ${NIGHTJAR.line}`,
2829
+ borderStartStartRadius: 16,
2830
+ borderStartEndRadius: 16,
2831
+ pointerEvents: 'auto',
2832
+ }}
2833
+ >
2834
+ {page === 'steps' && <StepPanel compact />}
2835
+ {page === 'summary' && <SummaryPanel compact form={form} />}
2836
+ {page === 'ordered' && <OrderConfirmation compact contact={form.contact} />}
2837
+ </Box>
2838
+ </Box>
2839
+
2840
+ <OrderBar compact form={form} />
2841
+ </Box>
2842
+ )
2843
+ }
2844
+ ```
2845
+
2846
+ ### ./src/\_shared/StepHeader.tsx
2847
+
2848
+ ```tsx
2849
+ import { Box, ButtonBase, Typography } from '@mui/material'
2850
+
2851
+ import { phx } from '../../.phoenix/phx.js'
2852
+ import { HEADING_SX, NIGHTJAR, useWarnings } from '../_fields/index.js'
2853
+ import { STEP_WARNINGS } from './step-warnings.js'
2854
+
2855
+ const CHECK_ICON = 'M5 12.5 10 17.5 19 7'
2856
+
2857
+ interface StepHeaderProps {
2858
+ /** One line with a progress bar, for a phone; the full stepper otherwise */
2859
+ readonly compact: boolean
2860
+ /** The furthest step the customer has reached; the layout keeps it, so it survives the switch between the pages */
2861
+ readonly reached: number
2862
+ }
2863
+
2864
+ // The spec's `navigationSteps` as a stepper. Labels and order come from the spec; `useStepNavigation` gives each step
2865
+ // its status, and `goTo` enters a step and records the stepper's analytics event. The customer can go back to any step
2866
+ // they have reached, never ahead of it, and nowhere while the order is being placed or after it was placed.
2867
+ export const StepHeader = ({ compact, reached }: StepHeaderProps) => {
2868
+ const { steps, activeIndex, activeStep, goTo } = phx.frontend.useStepNavigation()
2869
+ const navigationState = phx.frontend.useActiveNavigationState()
2870
+ const { primary } = phx.frontend.useFinalizeActions()
2871
+ const warnings = useWarnings()
2872
+ const isLocked = navigationState === 'ordered' || (primary?.isPending ?? false)
2873
+
2874
+ const hasWarning = (state: string) => {
2875
+ return warnings.some(warning => STEP_WARNINGS[state]?.includes(warning.type))
2876
+ }
2877
+
2878
+ if (compact) {
2879
+ const progress = steps.length === 0 ? 0 : (activeIndex + 1) / steps.length
2880
+
2881
+ return (
2882
+ <Box component="nav" aria-label="Build steps" sx={{ display: 'grid', gap: 1 }}>
2883
+ <Typography
2884
+ sx={{ ...HEADING_SX, fontSize: 13, letterSpacing: '0.14em', display: 'flex', alignItems: 'center', gap: 1 }}
2885
+ >
2886
+ <Box component="span" sx={{ color: NIGHTJAR.amber, fontVariantNumeric: 'tabular-nums' }}>
2887
+ {activeIndex + 1} / {steps.length}
2888
+ </Box>
2889
+ <Box component="span" aria-hidden sx={{ color: NIGHTJAR.faint }}>
2890
+ ·
2891
+ </Box>
2892
+ <Box component="span" aria-current="step">
2893
+ {activeStep?.label}
2894
+ </Box>
2895
+ </Typography>
2896
+ <Box
2897
+ component="div"
2898
+ role="progressbar"
2899
+ aria-label="Build progress"
2900
+ aria-valuemin={0}
2901
+ aria-valuemax={steps.length}
2902
+ aria-valuenow={activeIndex + 1}
2903
+ sx={{ blockSize: 2, borderRadius: 1, bgcolor: NIGHTJAR.line, overflow: 'hidden' }}
2904
+ >
2905
+ <Box
2906
+ component="div"
2907
+ sx={{
2908
+ blockSize: '100%',
2909
+ inlineSize: `${progress * 100}%`,
2910
+ bgcolor: NIGHTJAR.amber,
2911
+ transition: 'inline-size 400ms ease-out',
2912
+ }}
2913
+ />
2914
+ </Box>
2915
+ </Box>
2916
+ )
2917
+ }
2918
+
2919
+ return (
2920
+ <Box component="nav" aria-label="Build steps">
2921
+ <Box
2922
+ component="ol"
2923
+ sx={{ display: 'flex', alignItems: 'center', gap: 1, margin: 0, padding: 0, listStyle: 'none' }}
2924
+ >
2925
+ {steps.map(step => {
2926
+ const isActive = step.status === 'active'
2927
+ const isComplete = step.status === 'complete'
2928
+ const canEnter = !isLocked && !isActive && step.index <= reached
2929
+ const warn = hasWarning(step.state)
2930
+
2931
+ return (
2932
+ <Box component="li" key={step.state} sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
2933
+ {step.index > 0 && (
2934
+ <Box
2935
+ component="span"
2936
+ aria-hidden
2937
+ sx={{
2938
+ inlineSize: 28,
2939
+ blockSize: '1px',
2940
+ bgcolor: step.index <= reached ? NIGHTJAR.muted : NIGHTJAR.line,
2941
+ }}
2942
+ />
2943
+ )}
2944
+ <ButtonBase
2945
+ aria-label={warn ? `${step.label}, needs attention` : step.label}
2946
+ aria-current={isActive ? 'step' : undefined}
2947
+ disabled={!canEnter}
2948
+ onClick={() => goTo(step.index)}
2949
+ sx={{
2950
+ display: 'flex',
2951
+ alignItems: 'center',
2952
+ gap: 1,
2953
+ paddingInline: 1,
2954
+ paddingBlock: 0.75,
2955
+ borderRadius: 1,
2956
+ color: isActive ? NIGHTJAR.cream : step.index <= reached ? NIGHTJAR.muted : NIGHTJAR.faint,
2957
+ '&:hover': { color: NIGHTJAR.cream },
2958
+ '&.Mui-focusVisible': { outline: `2px solid ${NIGHTJAR.amber}` },
2959
+ }}
2960
+ >
2961
+ <Box
2962
+ component="span"
2963
+ sx={{
2964
+ display: 'grid',
2965
+ placeItems: 'center',
2966
+ inlineSize: 24,
2967
+ blockSize: 24,
2968
+ borderRadius: '50%',
2969
+ fontFamily: NIGHTJAR.font,
2970
+ fontSize: 12,
2971
+ fontWeight: 700,
2972
+ color: isActive ? NIGHTJAR.ink : 'inherit',
2973
+ bgcolor: isActive ? NIGHTJAR.amber : 'transparent',
2974
+ border: isActive ? 'none' : `1px solid ${isComplete ? NIGHTJAR.muted : NIGHTJAR.line}`,
2975
+ }}
2976
+ >
2977
+ {isComplete ? (
2978
+ <Box component="svg" viewBox="0 0 24 24" aria-hidden sx={{ inlineSize: 14, blockSize: 14 }}>
2979
+ <path d={CHECK_ICON} fill="none" stroke="currentColor" strokeWidth={2.6} strokeLinecap="round" />
2980
+ </Box>
2981
+ ) : (
2982
+ step.index + 1
2983
+ )}
2984
+ </Box>
2985
+ {/* In a narrow window only the active step keeps its label; the others keep their number */}
2986
+ <Typography
2987
+ component="span"
2988
+ sx={{
2989
+ ...HEADING_SX,
2990
+ display: { xs: isActive ? 'inline' : 'none', lg: 'inline' },
2991
+ fontSize: 13,
2992
+ color: 'inherit',
2993
+ }}
2994
+ >
2995
+ {step.label}
2996
+ </Typography>
2997
+ {warn && (
2998
+ <Box
2999
+ component="span"
3000
+ aria-hidden
3001
+ sx={{ inlineSize: 7, blockSize: 7, borderRadius: '50%', bgcolor: NIGHTJAR.amber }}
3002
+ />
3003
+ )}
3004
+ </ButtonBase>
3005
+ </Box>
3006
+ )
3007
+ })}
3008
+ </Box>
3009
+ </Box>
3010
+ )
3011
+ }
3012
+ ```
3013
+
3014
+ ### ./src/\_shared/StepPanel.tsx
3015
+
3016
+ ```tsx
3017
+ import { Box, Typography } from '@mui/material'
3018
+ import { useState } from 'react'
3019
+
3020
+ import { phx } from '../../.phoenix/phx.js'
3021
+ import { ENTER_FROM_END, ENTER_FROM_START, HEADING_SX, LABEL_SX, NIGHTJAR, StepFields } from '../_fields/index.js'
3022
+
3023
+ // A line under each step's title; the layout's copy, keyed by the step's navigation state
3024
+ const STEP_INTROS: Readonly<Record<string, string>> = {
3025
+ body: 'The shape sets the feel, the finish and the pickguard the look.',
3026
+ neck: 'What your hand holds: the neck and the board under the strings.',
3027
+ electronics: 'The sound: two pickups, and the metal parts around them.',
3028
+ details: 'Sign the headstock. The shop paints it on by hand.',
3029
+ }
3030
+
3031
+ /** 1 when the active step moved forward, -1 when it moved back; the step's content slides in from that side. */
3032
+ const useStepDirection = (activeIndex: number): 1 | -1 => {
3033
+ const [shown, setShown] = useState<{ readonly index: number; readonly direction: 1 | -1 }>({
3034
+ index: activeIndex,
3035
+ direction: 1,
3036
+ })
3037
+
3038
+ if (activeIndex !== shown.index) {
3039
+ setShown({ index: activeIndex, direction: activeIndex > shown.index ? 1 : -1 })
3040
+ }
3041
+
3042
+ return shown.direction
3043
+ }
3044
+
3045
+ interface StepPanelProps {
3046
+ readonly compact: boolean
3047
+ }
3048
+
3049
+ // The active step: its number, its label from the spec, and its fields. The content is keyed by the step, so each
3050
+ // step slides in from the side the customer moves towards.
3051
+ export const StepPanel = ({ compact }: StepPanelProps) => {
3052
+ const { steps, activeStep, activeIndex } = phx.frontend.useStepNavigation()
3053
+ const direction = useStepDirection(activeIndex)
3054
+
3055
+ if (activeStep === null) {
3056
+ return null
3057
+ }
3058
+
3059
+ return (
3060
+ <Box
3061
+ component="div"
3062
+ key={activeStep.state}
3063
+ sx={{
3064
+ display: 'grid',
3065
+ gap: compact ? 2.5 : 3.5,
3066
+ animation: `${direction === 1 ? ENTER_FROM_END : ENTER_FROM_START} 420ms cubic-bezier(0.2, 0.7, 0.2, 1)`,
3067
+ '@media (prefers-reduced-motion: reduce)': { animation: 'none' },
3068
+ }}
3069
+ >
3070
+ {!compact && (
3071
+ <Box component="header" sx={{ display: 'grid', gap: 1 }}>
3072
+ <Typography sx={LABEL_SX}>
3073
+ Step {activeIndex + 1} of {steps.length}
3074
+ </Typography>
3075
+ <Typography component="h2" sx={{ ...HEADING_SX, fontSize: 30, lineHeight: 1.05 }}>
3076
+ {activeStep.label}
3077
+ </Typography>
3078
+ {STEP_INTROS[activeStep.state] && (
3079
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 15, lineHeight: 1.45, color: NIGHTJAR.muted }}>
3080
+ {STEP_INTROS[activeStep.state]}
3081
+ </Typography>
3082
+ )}
3083
+ </Box>
3084
+ )}
3085
+ <StepFields compact={compact} />
3086
+ </Box>
3087
+ )
3088
+ }
3089
+ ```
3090
+
3091
+ ### ./src/\_shared/SummaryPanel.tsx
3092
+
3093
+ ```tsx
3094
+ import { Box, Button, InputBase, Typography } from '@mui/material'
3095
+ import type { ReactNode } from 'react'
3096
+ import { useEffect, useRef } from 'react'
3097
+
3098
+ import { phx } from '../../.phoenix/phx.js'
3099
+ import { HEADING_SX, LABEL_SX, NIGHTJAR, SummaryRows, useWarnings } from '../_fields/index.js'
3100
+ import type { OrderForm } from './order-form.js'
3101
+ import { STEP_WARNINGS } from './step-warnings.js'
3102
+
3103
+ const SECTION_SX = { display: 'grid', gap: 1.5 } as const
3104
+
3105
+ interface ContactInputProps {
3106
+ readonly id: string
3107
+ readonly label: string
3108
+ readonly value: string
3109
+ readonly onChange: (value: string) => void
3110
+ readonly error: string | undefined
3111
+ readonly type: 'text' | 'email'
3112
+ readonly autoComplete: string
3113
+ readonly disabled: boolean
3114
+ }
3115
+
3116
+ const ContactInput = ({ id, label, value, onChange, error, type, autoComplete, disabled }: ContactInputProps) => {
3117
+ return (
3118
+ <Box component="div" sx={{ display: 'grid', gap: 0.75 }}>
3119
+ <Typography
3120
+ component="label"
3121
+ htmlFor={id}
3122
+ sx={{ fontFamily: NIGHTJAR.font, fontSize: 14, color: NIGHTJAR.muted }}
3123
+ >
3124
+ {label}
3125
+ </Typography>
3126
+ <InputBase
3127
+ id={id}
3128
+ type={type}
3129
+ value={value}
3130
+ disabled={disabled}
3131
+ autoComplete={autoComplete}
3132
+ onChange={event => onChange(event.target.value)}
3133
+ inputProps={{ 'aria-invalid': error !== undefined, 'aria-describedby': error ? `${id}-error` : undefined }}
3134
+ sx={{
3135
+ paddingInline: 1.5,
3136
+ paddingBlock: 0.75,
3137
+ borderRadius: 1.5,
3138
+ border: `1px solid ${error ? NIGHTJAR.alert : NIGHTJAR.line}`,
3139
+ bgcolor: NIGHTJAR.raised,
3140
+ fontFamily: NIGHTJAR.font,
3141
+ fontSize: 16,
3142
+ color: NIGHTJAR.cream,
3143
+ '&.Mui-focused': { borderColor: error ? NIGHTJAR.alert : NIGHTJAR.amber },
3144
+ }}
3145
+ />
3146
+ {error && (
3147
+ <Typography id={`${id}-error`} sx={{ fontFamily: NIGHTJAR.font, fontSize: 13, color: NIGHTJAR.alert }}>
3148
+ {error}
3149
+ </Typography>
3150
+ )}
3151
+ </Box>
3152
+ )
3153
+ }
3154
+
3155
+ const Card = ({ children, tone }: { readonly children: ReactNode; readonly tone: 'plain' | 'warning' | 'alert' }) => {
3156
+ const borders = { plain: NIGHTJAR.line, warning: NIGHTJAR.amber, alert: NIGHTJAR.alert }
3157
+ const backgrounds = { plain: NIGHTJAR.raised, warning: NIGHTJAR.amberTint, alert: NIGHTJAR.alertTint }
3158
+
3159
+ return (
3160
+ <Box
3161
+ component="section"
3162
+ sx={{
3163
+ display: 'grid',
3164
+ gap: 1.5,
3165
+ padding: 2,
3166
+ borderRadius: 2,
3167
+ border: `1px solid ${borders[tone]}`,
3168
+ bgcolor: backgrounds[tone],
3169
+ }}
3170
+ >
3171
+ {children}
3172
+ </Box>
3173
+ )
3174
+ }
3175
+
3176
+ // The warnings left between choices, each with the way to the step that resolves it. Ordering waits until none is
3177
+ // left: `useFinalizeActions` reports the action `disabled` with the same texts as `hints`.
3178
+ const Conflicts = () => {
3179
+ const warnings = useWarnings()
3180
+ const { steps, goTo } = phx.frontend.useStepNavigation()
3181
+ const conflicts = warnings.flatMap(warning => {
3182
+ const step = steps.find(candidate => STEP_WARNINGS[candidate.state]?.includes(warning.type))
3183
+
3184
+ return step ? [{ ...warning, step }] : []
3185
+ })
3186
+
3187
+ if (conflicts.length === 0) {
3188
+ return null
3189
+ }
3190
+
3191
+ return (
3192
+ <Card tone="warning">
3193
+ <Typography component="h3" sx={{ ...LABEL_SX, color: NIGHTJAR.amber }}>
3194
+ {conflicts.length === 1 ? 'One choice to settle before ordering' : `${conflicts.length} choices to settle`}
3195
+ </Typography>
3196
+ {conflicts.map(conflict => (
3197
+ <Box component="div" key={conflict.type} sx={{ display: 'grid', gap: 1, justifyItems: 'start' }}>
3198
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 15, lineHeight: 1.45, color: NIGHTJAR.cream }}>
3199
+ {conflict.text}
3200
+ </Typography>
3201
+ <Button
3202
+ onClick={() => goTo(conflict.step.index)}
3203
+ sx={{
3204
+ ...LABEL_SX,
3205
+ minBlockSize: 36,
3206
+ paddingInline: 1.5,
3207
+ color: NIGHTJAR.ink,
3208
+ bgcolor: NIGHTJAR.amber,
3209
+ '&:hover': { bgcolor: NIGHTJAR.amberHover },
3210
+ }}
3211
+ >
3212
+ Go to {conflict.step.label}
3213
+ </Button>
3214
+ </Box>
3215
+ ))}
3216
+ </Card>
3217
+ )
3218
+ }
3219
+
3220
+ interface SummaryPanelProps {
3221
+ readonly compact: boolean
3222
+ readonly form: OrderForm
3223
+ }
3224
+
3225
+ // The last step: every choice as the spec's control hooks read it, the conflicts left, the contact form and the
3226
+ // order's error. The summary only reviews; a choice is changed on its step, which the stepper and the conflicts link
3227
+ // to. **Place order** is in the bar at the bottom.
3228
+ export const SummaryPanel = ({ compact, form }: SummaryPanelProps) => {
3229
+ const { primary } = phx.frontend.useFinalizeActions()
3230
+ const { contact, setContact, errors, showErrors, blockedAttempts, isComplete } = form
3231
+ const isPending = primary?.isPending ?? false
3232
+ const topRef = useRef<HTMLDivElement>(null)
3233
+ const detailsRef = useRef<HTMLElement>(null)
3234
+ // The attempts already handled; the summary opens again after a blocked attempt without scrolling
3235
+ const scrolledFor = useRef(blockedAttempts)
3236
+
3237
+ // After each blocked attempt to order, bring what blocks it into view: the missing details, or the conflicts on top.
3238
+ // Typing into the form changes `isComplete` but is no new attempt, so it does not scroll.
3239
+ useEffect(() => {
3240
+ if (blockedAttempts === scrolledFor.current) {
3241
+ return
3242
+ }
3243
+
3244
+ scrolledFor.current = blockedAttempts
3245
+ const target = isComplete ? topRef.current : detailsRef.current
3246
+ target?.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
3247
+ }, [blockedAttempts, isComplete])
3248
+
3249
+ return (
3250
+ <Box component="div" ref={topRef} sx={{ display: 'grid', gap: compact ? 2.5 : 3, scrollMarginBlockStart: 32 }}>
3251
+ {!compact && (
3252
+ <Box component="header" sx={{ display: 'grid', gap: 1 }}>
3253
+ <Typography sx={LABEL_SX}>Last step</Typography>
3254
+ <Typography component="h2" sx={{ ...HEADING_SX, fontSize: 30, lineHeight: 1.05 }}>
3255
+ Your Nightjar
3256
+ </Typography>
3257
+ <Typography sx={{ fontFamily: NIGHTJAR.font, fontSize: 15, lineHeight: 1.45, color: NIGHTJAR.muted }}>
3258
+ Check the build, tell us who it is for, and place the order. Nothing is charged until the shop confirms.
3259
+ </Typography>
3260
+ </Box>
3261
+ )}
3262
+
3263
+ {primary?.error && (
3264
+ <Card tone="alert">
3265
+ <Typography component="h3" sx={{ ...LABEL_SX, color: NIGHTJAR.alert }}>
3266
+ The order did not go through
3267
+ </Typography>
3268
+ <Typography
3269
+ role="alert"
3270
+ sx={{ fontFamily: NIGHTJAR.font, fontSize: 15, lineHeight: 1.45, color: NIGHTJAR.cream }}
3271
+ >
3272
+ {primary.error.message}
3273
+ </Typography>
3274
+ </Card>
3275
+ )}
3276
+
3277
+ <Conflicts />
3278
+
3279
+ <Box component="section" sx={SECTION_SX}>
3280
+ <Typography component="h3" sx={LABEL_SX}>
3281
+ The build
3282
+ </Typography>
3283
+ <SummaryRows />
3284
+ </Box>
3285
+
3286
+ <Box component="section" ref={detailsRef} sx={{ ...SECTION_SX, scrollMarginBlockEnd: 32 }}>
3287
+ <Typography component="h3" sx={LABEL_SX}>
3288
+ Your details
3289
+ </Typography>
3290
+ <Box component="div" sx={{ display: 'grid', gridTemplateColumns: compact ? '1fr' : '1fr 1fr', gap: 1.5 }}>
3291
+ <ContactInput
3292
+ id="nightjar-name"
3293
+ label="Name"
3294
+ type="text"
3295
+ autoComplete="name"
3296
+ value={contact.name}
3297
+ onChange={name => setContact({ ...contact, name })}
3298
+ error={showErrors ? errors.name : undefined}
3299
+ disabled={isPending}
3300
+ />
3301
+ <ContactInput
3302
+ id="nightjar-email"
3303
+ label="E-mail"
3304
+ type="email"
3305
+ autoComplete="email"
3306
+ value={contact.email}
3307
+ onChange={email => setContact({ ...contact, email })}
3308
+ error={showErrors ? errors.email : undefined}
3309
+ disabled={isPending}
3310
+ />
3311
+ </Box>
3312
+ </Box>
3313
+ </Box>
3314
+ )
3315
+ }
3316
+ ```
3317
+
3318
+ ### ./src/\_shared/order-form.ts
3319
+
3320
+ ```ts
3321
+ import { useState } from 'react'
3322
+
3323
+ /** The customer's name and e-mail, which the summary asks for. */
3324
+ export interface Contact {
3325
+ readonly name: string
3326
+ readonly email: string
3327
+ }
3328
+
3329
+ /** What is missing from the contact details, per field. */
3330
+ export interface ContactErrors {
3331
+ readonly name?: string
3332
+ readonly email?: string
3333
+ }
3334
+
3335
+ /**
3336
+ * The summary's contact form. It is the layout's own state, not the configuration's: the details are needed only to
3337
+ * place the order, and the confirmation thanks the customer by name.
3338
+ */
3339
+ export interface OrderForm {
3340
+ readonly contact: Contact
3341
+ readonly setContact: (contact: Contact) => void
3342
+ readonly errors: ContactErrors
3343
+ readonly isComplete: boolean
3344
+ /** Whether the form shows what is missing: from the first attempt to order on */
3345
+ readonly showErrors: boolean
3346
+ /** How many attempts to order were blocked; the summary scrolls to what blocks the order after each */
3347
+ readonly blockedAttempts: number
3348
+ readonly revealErrors: () => void
3349
+ }
3350
+
3351
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/
3352
+
3353
+ export const useOrderForm = (): OrderForm => {
3354
+ const [contact, setContact] = useState<Contact>({ name: '', email: '' })
3355
+ const [blockedAttempts, setBlockedAttempts] = useState(0)
3356
+ const errors: ContactErrors = {
3357
+ ...(contact.name.trim() === '' && { name: 'Enter the name the order is for.' }),
3358
+ ...(!EMAIL.test(contact.email.trim()) && { email: 'Enter an e-mail address for the build updates.' }),
3359
+ }
3360
+
3361
+ return {
3362
+ contact,
3363
+ setContact,
3364
+ errors,
3365
+ isComplete: errors.name === undefined && errors.email === undefined,
3366
+ showErrors: blockedAttempts > 0,
3367
+ blockedAttempts,
3368
+ revealErrors: () => setBlockedAttempts(attempts => attempts + 1),
3369
+ }
3370
+ }
3371
+ ```
3372
+
3373
+ ### ./src/\_shared/step-warnings.ts
3374
+
3375
+ ```ts
3376
+ // Which step resolves each warning: the stepper marks the step while the warning holds, and the summary sends the
3377
+ // customer there. A warning can involve several steps; this names the one the layout sends the customer to.
3378
+ export const STEP_WARNINGS: Readonly<Record<string, readonly string[]>> = {
3379
+ electronics: ['offsetHumbuckers'],
3380
+ }
3381
+ ```
3382
+
3383
+ ### ./src/\_shared/use-reached-step.ts
3384
+
3385
+ ```ts
3386
+ import { useState } from 'react'
3387
+
3388
+ // The furthest step the customer has reached. The stepper offers every step up to it, so after changing an earlier
3389
+ // step the customer returns to where they were without stepping through the ones between. The layout calls this, where
3390
+ // it stays mounted, so the furthest step survives the switch between the desktop and the phone page.
3391
+ export const useReachedStep = (activeIndex: number): number => {
3392
+ const [reached, setReached] = useState(activeIndex)
3393
+
3394
+ if (activeIndex > reached) {
3395
+ setReached(activeIndex)
3396
+ }
3397
+
3398
+ return Math.max(reached, activeIndex)
3399
+ }
3400
+ ```
3401
+
3402
+ ### ./src/elements/ConfiguratorLayout.tsx
3403
+
3404
+ ```tsx
3405
+ import { Box } from '@mui/material'
3406
+
3407
+ import { LayoutSlots } from '@salsita-ai/sdk/configurator'
3408
+
3409
+ import { phx } from '../../.phoenix/phx.js'
3410
+ import { NIGHTJAR } from '../_fields/index.js'
3411
+ import { DesktopPage } from '../_shared/DesktopPage.js'
3412
+ import { PhonePage } from '../_shared/PhonePage.js'
3413
+ import { useOrderForm } from '../_shared/order-form.js'
3414
+ import { useReachedStep } from '../_shared/use-reached-step.js'
3415
+
3416
+ // A wizard over the scene. The canvas stays mounted the whole time; the desktop or the phone page lies over it. The
3417
+ // contact form's state and the furthest step reached live here, so they survive the switch between the two; the form
3418
+ // also survives the move to the confirmation.
3419
+ const ConfiguratorLayout = () => {
3420
+ // `null` until the container has been measured; only the scene shows until then
3421
+ const viewports = phx.frontend.useActiveViewports()
3422
+ const { activeIndex } = phx.frontend.useStepNavigation()
3423
+ const form = useOrderForm()
3424
+ const reached = useReachedStep(activeIndex)
3425
+ const isDesktop = viewports?.includes('desktop') ?? false
3426
+
3427
+ return (
3428
+ <Box component="div" sx={{ position: 'absolute', inset: 0, overflow: 'clip', bgcolor: NIGHTJAR.ink }}>
3429
+ <LayoutSlots.SharedCanvas />
3430
+ {viewports !== null &&
3431
+ (isDesktop ? <DesktopPage form={form} reached={reached} /> : <PhonePage form={form} reached={reached} />)}
3432
+ </Box>
3433
+ )
3434
+ }
3435
+
3436
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
3437
+ ```
3438
+
3439
+ ### ./src/elements/NightjarStage.tsx
3440
+
3441
+ ```tsx
3442
+ import { Environment, Lightformer } from '@react-three/drei'
3443
+ import { useMemo } from 'react'
3444
+ import { CanvasTexture, SRGBColorSpace } from 'three'
3445
+
3446
+ import { phx } from '../../.phoenix/phx.js'
3447
+ import { NIGHTJAR } from '../_fields/index.js'
3448
+
3449
+ /** A warm pool of light that fades into the dark, drawn once on a canvas. */
3450
+ const createGlow = (): CanvasTexture => {
3451
+ const size = 512
3452
+ const canvas = document.createElement('canvas')
3453
+ canvas.width = size
3454
+ canvas.height = size
3455
+ const context = canvas.getContext('2d')
3456
+
3457
+ if (context) {
3458
+ const gradient = context.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2)
3459
+ gradient.addColorStop(0, 'rgba(242, 163, 58, 0.42)')
3460
+ gradient.addColorStop(0.22, 'rgba(214, 112, 46, 0.2)')
3461
+ gradient.addColorStop(0.5, 'rgba(122, 30, 43, 0.07)')
3462
+ gradient.addColorStop(0.75, 'rgba(14, 15, 18, 0)')
3463
+ context.fillStyle = gradient
3464
+ context.fillRect(0, 0, size, size)
3465
+ }
3466
+
3467
+ const texture = new CanvasTexture(canvas)
3468
+ texture.colorSpace = SRGBColorSpace
3469
+ return texture
3470
+ }
3471
+
3472
+ // The stage named by the spec's `canvasCustomEnvironment`: a dark room with a warm glow on the wall behind the guitar,
3473
+ // a warm key light and a cool rim. The light panels exist only in the reflections, where they draw the long highlights
3474
+ // on the clearcoat and the hardware. The scene is in millimetres.
3475
+ export default phx.frontend.createCustomPhoenixLayoutElement('NightjarStage', () => {
3476
+ const glow = useMemo(createGlow, [])
3477
+
3478
+ return (
3479
+ <>
3480
+ <color attach="background" args={[NIGHTJAR.ink]} />
3481
+ <ambientLight intensity={0.4} />
3482
+ <directionalLight position={[-900, 1400, 1600]} intensity={2.4} color="#ffe6c7" />
3483
+ <directionalLight position={[1400, 700, -900]} intensity={1.2} color="#a9c1ff" />
3484
+
3485
+ {/* The glow on the wall, behind the guitar and out of the camera's fit */}
3486
+ <mesh position={[-250, 300, -900]}>
3487
+ <planeGeometry args={[3600, 3600]} />
3488
+ <meshBasicMaterial map={glow} transparent depthWrite={false} toneMapped={false} />
3489
+ </mesh>
3490
+
3491
+ <Environment resolution={256} frames={1}>
3492
+ <color attach="background" args={['#15161b']} />
3493
+ {/* Tall strips at both sides for the long highlights, a softbox above, an amber wash behind */}
3494
+ <Lightformer form="rect" intensity={7} position={[-5, 1, 3]} rotation-y={Math.PI / 3} scale={[1.2, 9, 1]} />
3495
+ <Lightformer form="rect" intensity={4} position={[5, 1, 2]} rotation-y={-Math.PI / 3} scale={[1, 9, 1]} />
3496
+ <Lightformer form="rect" intensity={2.5} position={[0, 6, 1]} rotation-x={Math.PI / 2} scale={[8, 3, 1]} />
3497
+ <Lightformer form="rect" intensity={1.2} position={[0, 1, 7]} rotation-y={Math.PI} scale={[8, 4, 1]} />
3498
+ <Lightformer form="rect" color={NIGHTJAR.amber} intensity={0.8} position={[0, -2, -7]} scale={[10, 3, 1]} />
3499
+ </Environment>
3500
+ </>
3501
+ )
3502
+ })
3503
+ ```
3504
+
3505
+ ### ./src/expressions/guitar.ts
3506
+
3507
+ ```ts
3508
+ import { phx } from '../../.phoenix/phx.js'
3509
+
3510
+ const BASE_PRICE = 1650
3511
+ const SIGNATURE_PRICE = 45
3512
+ const SIGNATURE_LIMIT = 16
3513
+
3514
+ const SURCHARGES = {
3515
+ bodyShape: { Offset: 0, SingleCut: 150 },
3516
+ finish: { Seafoam: 0, CandyRed: 180, Midnight: 120, NaturalAsh: 90 },
3517
+ pickguard: { Parchment: 0, Black: 0, Pearloid: 40, None: 0 },
3518
+ neckWood: { Maple: 0, RoastedMaple: 110, Mahogany: 80 },
3519
+ fretboard: { Maple: 0, Rosewood: 0, Ebony: 140 },
3520
+ pickups: { SingleCoils: 0, Humbuckers: 120, P90s: 90 },
3521
+ hardware: { Chrome: 0, Gold: 160, Black: 60 },
3522
+ }
3523
+
3524
+ // The wood textures ship with Storybook; a texture is multiplied by the material's colour
3525
+ const LIGHT_WOOD = '/textures/Material_Lightwood.png'
3526
+ const DARK_WOOD = '/textures/Material_Darkwood.png'
3527
+ const ASH = '/textures/oak_varnished_BaseColor.png'
3528
+
3529
+ // How each finish renders under the clearcoat: the paints are solid, natural ash shows the grain through a tint
3530
+ const FINISHES = {
3531
+ Seafoam: { color: '#9fd8c4', metalness: 0, roughness: 0.38, texture: null },
3532
+ CandyRed: { color: '#a3101c', metalness: 0.35, roughness: 0.3, texture: null },
3533
+ Midnight: { color: '#1b2a52', metalness: 0.55, roughness: 0.34, texture: null },
3534
+ NaturalAsh: { color: '#f4e2c4', metalness: 0, roughness: 0.5, texture: ASH },
3535
+ }
3536
+
3537
+ const PICKGUARDS = {
3538
+ Parchment: { color: '#ece2cb', roughness: 0.5, iridescence: 0 },
3539
+ Black: { color: '#121214', roughness: 0.3, iridescence: 0 },
3540
+ Pearloid: { color: '#f2ede6', roughness: 0.22, iridescence: 1 },
3541
+ None: { color: '#ece2cb', roughness: 0.5, iridescence: 0 },
3542
+ }
3543
+
3544
+ const NECKS = {
3545
+ Maple: { color: '#f6dcae', texture: LIGHT_WOOD },
3546
+ RoastedMaple: { color: '#c58a4e', texture: LIGHT_WOOD },
3547
+ Mahogany: { color: '#c47a5a', texture: DARK_WOOD },
3548
+ }
3549
+
3550
+ const FRETBOARDS = {
3551
+ Maple: { color: '#f6dcae', texture: LIGHT_WOOD, inlay: '#1b1714' },
3552
+ Rosewood: { color: '#ffffff', texture: DARK_WOOD, inlay: '#efe9df' },
3553
+ Ebony: { color: '#3a3330', texture: DARK_WOOD, inlay: '#efe9df' },
3554
+ }
3555
+
3556
+ const HARDWARE = {
3557
+ Chrome: { color: '#eceef0', metalness: 1, roughness: 0.12 },
3558
+ Gold: { color: '#e6b964', metalness: 1, roughness: 0.2 },
3559
+ Black: { color: '#26262a', metalness: 0.7, roughness: 0.32 },
3560
+ }
3561
+
3562
+ export default phx.domain.implementCustomExpressions({
3563
+ Guitar: {
3564
+ $price: s => {
3565
+ return (
3566
+ BASE_PRICE +
3567
+ SURCHARGES.bodyShape[s.bodyShape] +
3568
+ SURCHARGES.finish[s.finish] +
3569
+ SURCHARGES.pickguard[s.pickguard] +
3570
+ SURCHARGES.neckWood[s.neckWood] +
3571
+ SURCHARGES.fretboard[s.fretboard] +
3572
+ SURCHARGES.pickups[s.pickups] +
3573
+ SURCHARGES.hardware[s.hardware] +
3574
+ (s.signature.trim() === '' ? 0 : SIGNATURE_PRICE)
3575
+ )
3576
+ },
3577
+ $signatureLimit: () => {
3578
+ return SIGNATURE_LIMIT
3579
+ },
3580
+ $finishColor: s => {
3581
+ return FINISHES[s.finish].color
3582
+ },
3583
+ $finishMetalness: s => {
3584
+ return FINISHES[s.finish].metalness
3585
+ },
3586
+ $finishRoughness: s => {
3587
+ return FINISHES[s.finish].roughness
3588
+ },
3589
+ $finishTexture: s => {
3590
+ return FINISHES[s.finish].texture
3591
+ },
3592
+ $pickguardColor: s => {
3593
+ return PICKGUARDS[s.pickguard].color
3594
+ },
3595
+ $pickguardRoughness: s => {
3596
+ return PICKGUARDS[s.pickguard].roughness
3597
+ },
3598
+ $pickguardIridescence: s => {
3599
+ return PICKGUARDS[s.pickguard].iridescence
3600
+ },
3601
+ $neckColor: s => {
3602
+ return NECKS[s.neckWood].color
3603
+ },
3604
+ $neckTexture: s => {
3605
+ return NECKS[s.neckWood].texture
3606
+ },
3607
+ $fretboardColor: s => {
3608
+ return FRETBOARDS[s.fretboard].color
3609
+ },
3610
+ $fretboardTexture: s => {
3611
+ return FRETBOARDS[s.fretboard].texture
3612
+ },
3613
+ $inlayColor: s => {
3614
+ return FRETBOARDS[s.fretboard].inlay
3615
+ },
3616
+ $hardwareColor: s => {
3617
+ return HARDWARE[s.hardware].color
3618
+ },
3619
+ $hardwareMetalness: s => {
3620
+ return HARDWARE[s.hardware].metalness
3621
+ },
3622
+ $hardwareRoughness: s => {
3623
+ return HARDWARE[s.hardware].roughness
3624
+ },
3625
+ // Single coils match a black pickguard and are cream otherwise; humbuckers and P-90s are black
3626
+ $pickupCoverColor: s => {
3627
+ return s.pickups === 'SingleCoils' && s.pickguard !== 'Black' ? '#efe7d4' : '#141416'
3628
+ },
3629
+ // Gold leaf on the dark woods, black ink on maple
3630
+ $signatureColor: s => {
3631
+ return s.neckWood === 'Maple' ? '#1c1714' : '#e8c27a'
3632
+ },
3633
+ },
3634
+ })
3635
+ ```
3636
+
3637
+ ### ./src/handlers/place-order.ts
3638
+
3639
+ ```ts
3640
+ import { useCallback } from 'react'
3641
+
3642
+ import { phx } from '../../.phoenix/phx.js'
3643
+
3644
+ // Stands in for Northfret's order service. Placing an order takes a moment. The service checks stock when the order
3645
+ // arrives, which the configurator cannot know beforehand: gold hardware is back-ordered, so it refuses that order with
3646
+ // its reason; any other order is accepted and the page shows the confirmation.
3647
+ export default phx.frontend.createPhoenixHandler('placeOrder', () => {
3648
+ const navigate = phx.frontend.useNavigate()
3649
+ const guitar = phx.frontend.useRootEntityState()
3650
+
3651
+ return {
3652
+ handler: useCallback(async () => {
3653
+ await new Promise(resolve => setTimeout(resolve, 1600))
3654
+
3655
+ if (guitar.hardware === 'Gold') {
3656
+ throw new Error(
3657
+ 'Gold hardware is back-ordered until next month. Choose chrome or black hardware, or order later.'
3658
+ )
3659
+ }
3660
+
3661
+ navigate('ordered')
3662
+ }, [guitar.hardware, navigate]),
3663
+ }
3664
+ })
3665
+ ```
3666
+
3667
+ ### ./src/invariants/guitar.ts
3668
+
3669
+ ```ts
3670
+ import { phx } from '../../.phoenix/phx.js'
3671
+
3672
+ export default phx.domain.implementCustomInvariants({
3673
+ Guitar: {
3674
+ // `fixable`: a change that makes the signature too long is rejected, so the headstock never shows more than fits.
3675
+ // The message names the limit, so it is built here rather than in the spec.
3676
+ signatureLength: s => {
3677
+ if (s.signature.length <= s.$signatureLimit) {
3678
+ return []
3679
+ }
3680
+
3681
+ return [
3682
+ {
3683
+ type: 'signatureTooLong',
3684
+ severity: 'fixable',
3685
+ message: `The headstock fits ${s.$signatureLimit} characters. Shorten the signature.`,
3686
+ },
3687
+ ]
3688
+ },
3689
+ // `warning` in the spec: the change is kept, so a body chosen after the pickups does not undo them, and ordering
3690
+ // waits until the customer resolves it
3691
+ offsetHumbuckers: s => {
3692
+ return s.bodyShape !== 'Offset' || s.pickups !== 'Humbuckers'
3693
+ },
3694
+ },
3695
+ })
3696
+ ```
3697
+
3698
+ </details>