@things-factory/figure-ui 10.1.74 → 10.1.76

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 (244) hide show
  1. package/client/figure-assistant.ts +3 -3
  2. package/client/graphql/{v3-store.ts → store.ts} +6 -6
  3. package/client/modeller/{v3-ai-proposal.ts → ai-proposal.ts} +8 -8
  4. package/client/modeller/{v3-align.ts → align.ts} +14 -14
  5. package/client/modeller/{v3-canvas.ts → canvas.ts} +13 -13
  6. package/client/modeller/{v3-clips.ts → clips.ts} +5 -5
  7. package/client/modeller/{v3-controls.ts → controls.ts} +2 -2
  8. package/client/modeller/{v3-editor.ts → editor.ts} +137 -126
  9. package/client/modeller/{figure-v3-capability.ts → figure-capability-panel.ts} +7 -7
  10. package/client/modeller/{figure-v3-clips.ts → figure-clips.ts} +10 -10
  11. package/client/modeller/{figure-v3-controls.ts → figure-controls.ts} +9 -9
  12. package/client/modeller/{v3-figure-facts.ts → figure-facts.ts} +11 -11
  13. package/client/modeller/{figure-v3-first-save.ts → figure-first-save.ts} +3 -3
  14. package/client/modeller/figure-history-panel.ts +1 -1
  15. package/client/modeller/{figure-v3-links.ts → figure-links.ts} +35 -35
  16. package/client/modeller/{figure-v3-material.ts → figure-material-panel.ts} +20 -20
  17. package/client/modeller/{figure-v3-parts.ts → figure-parts.ts} +15 -15
  18. package/client/modeller/{figure-v3-preview.ts → figure-preview.ts} +14 -14
  19. package/client/modeller/{figure-v3-properties.ts → figure-properties.ts} +25 -25
  20. package/client/modeller/{figure-v3-recipe-catalog.ts → figure-recipe-catalog.ts} +10 -10
  21. package/client/modeller/{figure-v3-verdict.ts → figure-verdict.ts} +24 -24
  22. package/client/modeller/gate-findings.ts +2 -2
  23. package/client/modeller/{v3-gizmo.ts → gizmo.ts} +11 -11
  24. package/client/modeller/{v3-joint-drag.ts → joint-drag.ts} +11 -11
  25. package/client/modeller/{v3-joint-fan.ts → joint-fan.ts} +13 -13
  26. package/client/modeller/{v3-links.ts → links.ts} +59 -59
  27. package/client/modeller/{v3-live.ts → live.ts} +9 -9
  28. package/client/modeller/{v3-maturity.ts → maturity.ts} +65 -65
  29. package/client/modeller/modeller-route.ts +1 -1
  30. package/client/modeller/{v3-occupancy.ts → occupancy.ts} +6 -6
  31. package/client/modeller/{v3-palette.ts → palette.ts} +3 -3
  32. package/client/modeller/{v3-preview-model.ts → preview-model.ts} +8 -8
  33. package/client/modeller/{v3-product-session.ts → product-session.ts} +25 -25
  34. package/client/modeller/{v3-recipe-source.ts → recipe-source.ts} +2 -2
  35. package/client/modeller/{v3-recipes.ts → recipes.ts} +9 -9
  36. package/client/modeller/{v3-refusals.ts → refusals.ts} +62 -13
  37. package/client/modeller/{v3-renderer.ts → renderer.ts} +16 -16
  38. package/client/modeller/{v3-stage-model.ts → stage-model.ts} +15 -15
  39. package/client/modeller/{v3-thumbnail.ts → thumbnail.ts} +8 -8
  40. package/client/pages/figure-list-page.ts +4 -4
  41. package/client/pages/{figure-v3-modeller-page.ts → figure-modeller-page.ts} +37 -37
  42. package/client/route.ts +1 -5
  43. package/dist-client/figure-assistant.js +3 -3
  44. package/dist-client/figure-assistant.js.map +1 -1
  45. package/dist-client/graphql/store.d.ts +3 -0
  46. package/dist-client/graphql/store.js +39 -0
  47. package/dist-client/graphql/store.js.map +1 -0
  48. package/dist-client/modeller/ai-proposal.d.ts +51 -0
  49. package/dist-client/modeller/ai-proposal.js +64 -0
  50. package/dist-client/modeller/ai-proposal.js.map +1 -0
  51. package/dist-client/modeller/align.d.ts +30 -0
  52. package/dist-client/modeller/align.js +75 -0
  53. package/dist-client/modeller/align.js.map +1 -0
  54. package/dist-client/modeller/canvas.d.ts +72 -0
  55. package/dist-client/modeller/canvas.js +379 -0
  56. package/dist-client/modeller/canvas.js.map +1 -0
  57. package/dist-client/modeller/clips.d.ts +39 -0
  58. package/dist-client/modeller/clips.js +58 -0
  59. package/dist-client/modeller/clips.js.map +1 -0
  60. package/dist-client/modeller/controls.d.ts +28 -0
  61. package/dist-client/modeller/controls.js +28 -0
  62. package/dist-client/modeller/controls.js.map +1 -0
  63. package/dist-client/modeller/editor.d.ts +203 -0
  64. package/dist-client/modeller/editor.js +1526 -0
  65. package/dist-client/modeller/editor.js.map +1 -0
  66. package/dist-client/modeller/fields.d.ts +45 -0
  67. package/dist-client/modeller/fields.js +83 -0
  68. package/dist-client/modeller/fields.js.map +1 -0
  69. package/dist-client/modeller/figure-capability-panel.d.ts +22 -0
  70. package/dist-client/modeller/figure-capability-panel.js +141 -0
  71. package/dist-client/modeller/figure-capability-panel.js.map +1 -0
  72. package/dist-client/modeller/figure-clips.d.ts +31 -0
  73. package/dist-client/modeller/figure-clips.js +268 -0
  74. package/dist-client/modeller/figure-clips.js.map +1 -0
  75. package/dist-client/modeller/figure-controls.d.ts +36 -0
  76. package/dist-client/modeller/figure-controls.js +226 -0
  77. package/dist-client/modeller/figure-controls.js.map +1 -0
  78. package/dist-client/modeller/figure-facts.d.ts +35 -0
  79. package/dist-client/modeller/figure-facts.js +55 -0
  80. package/dist-client/modeller/figure-facts.js.map +1 -0
  81. package/dist-client/modeller/figure-first-save.d.ts +20 -0
  82. package/dist-client/modeller/figure-first-save.js +118 -0
  83. package/dist-client/modeller/figure-first-save.js.map +1 -0
  84. package/dist-client/modeller/figure-history-panel.d.ts +1 -1
  85. package/dist-client/modeller/figure-history-panel.js.map +1 -1
  86. package/dist-client/modeller/figure-links.d.ts +77 -0
  87. package/dist-client/modeller/figure-links.js +649 -0
  88. package/dist-client/modeller/figure-links.js.map +1 -0
  89. package/dist-client/modeller/figure-material-panel.d.ts +39 -0
  90. package/dist-client/modeller/figure-material-panel.js +323 -0
  91. package/dist-client/modeller/figure-material-panel.js.map +1 -0
  92. package/dist-client/modeller/figure-parts.d.ts +69 -0
  93. package/dist-client/modeller/figure-parts.js +559 -0
  94. package/dist-client/modeller/figure-parts.js.map +1 -0
  95. package/dist-client/modeller/figure-preview.d.ts +34 -0
  96. package/dist-client/modeller/figure-preview.js +346 -0
  97. package/dist-client/modeller/figure-preview.js.map +1 -0
  98. package/dist-client/modeller/figure-properties.d.ts +45 -0
  99. package/dist-client/modeller/figure-properties.js +239 -0
  100. package/dist-client/modeller/figure-properties.js.map +1 -0
  101. package/dist-client/modeller/figure-recipe-catalog.d.ts +38 -0
  102. package/dist-client/modeller/figure-recipe-catalog.js +399 -0
  103. package/dist-client/modeller/figure-recipe-catalog.js.map +1 -0
  104. package/dist-client/modeller/figure-verdict.d.ts +64 -0
  105. package/dist-client/modeller/figure-verdict.js +787 -0
  106. package/dist-client/modeller/figure-verdict.js.map +1 -0
  107. package/dist-client/modeller/first-save.d.ts +17 -0
  108. package/dist-client/modeller/first-save.js +26 -0
  109. package/dist-client/modeller/first-save.js.map +1 -0
  110. package/dist-client/modeller/gate-findings.d.ts +2 -2
  111. package/dist-client/modeller/gate-findings.js +2 -2
  112. package/dist-client/modeller/gate-findings.js.map +1 -1
  113. package/dist-client/modeller/gizmo.d.ts +72 -0
  114. package/dist-client/modeller/gizmo.js +111 -0
  115. package/dist-client/modeller/gizmo.js.map +1 -0
  116. package/dist-client/modeller/help.d.ts +18 -0
  117. package/dist-client/modeller/help.js +37 -0
  118. package/dist-client/modeller/help.js.map +1 -0
  119. package/dist-client/modeller/joint-drag.d.ts +19 -0
  120. package/dist-client/modeller/joint-drag.js +97 -0
  121. package/dist-client/modeller/joint-drag.js.map +1 -0
  122. package/dist-client/modeller/joint-fan.d.ts +9 -0
  123. package/dist-client/modeller/joint-fan.js +276 -0
  124. package/dist-client/modeller/joint-fan.js.map +1 -0
  125. package/dist-client/modeller/keys.d.ts +22 -0
  126. package/dist-client/modeller/keys.js +26 -0
  127. package/dist-client/modeller/keys.js.map +1 -0
  128. package/dist-client/modeller/links.d.ts +267 -0
  129. package/dist-client/modeller/links.js +480 -0
  130. package/dist-client/modeller/links.js.map +1 -0
  131. package/dist-client/modeller/live.d.ts +37 -0
  132. package/dist-client/modeller/live.js +68 -0
  133. package/dist-client/modeller/live.js.map +1 -0
  134. package/dist-client/modeller/maturity.d.ts +120 -0
  135. package/dist-client/modeller/maturity.js +313 -0
  136. package/dist-client/modeller/maturity.js.map +1 -0
  137. package/dist-client/modeller/modeller-route.d.ts +1 -1
  138. package/dist-client/modeller/modeller-route.js +1 -1
  139. package/dist-client/modeller/modeller-route.js.map +1 -1
  140. package/dist-client/modeller/occupancy.d.ts +18 -0
  141. package/dist-client/modeller/occupancy.js +24 -0
  142. package/dist-client/modeller/occupancy.js.map +1 -0
  143. package/dist-client/modeller/palette.d.ts +7 -0
  144. package/dist-client/modeller/palette.js +46 -0
  145. package/dist-client/modeller/palette.js.map +1 -0
  146. package/dist-client/modeller/preview-model.d.ts +47 -0
  147. package/dist-client/modeller/preview-model.js +68 -0
  148. package/dist-client/modeller/preview-model.js.map +1 -0
  149. package/dist-client/modeller/product-session.d.ts +510 -0
  150. package/dist-client/modeller/product-session.js +157 -0
  151. package/dist-client/modeller/product-session.js.map +1 -0
  152. package/dist-client/modeller/recipe-source.d.ts +8 -0
  153. package/dist-client/modeller/recipe-source.js +14 -0
  154. package/dist-client/modeller/recipe-source.js.map +1 -0
  155. package/dist-client/modeller/recipes.d.ts +37 -0
  156. package/dist-client/modeller/recipes.js +103 -0
  157. package/dist-client/modeller/recipes.js.map +1 -0
  158. package/dist-client/modeller/refusals.d.ts +68 -0
  159. package/dist-client/modeller/refusals.js +142 -0
  160. package/dist-client/modeller/refusals.js.map +1 -0
  161. package/dist-client/modeller/renderer.d.ts +40 -0
  162. package/dist-client/modeller/renderer.js +73 -0
  163. package/dist-client/modeller/renderer.js.map +1 -0
  164. package/dist-client/modeller/stage-model.d.ts +39 -0
  165. package/dist-client/modeller/stage-model.js +147 -0
  166. package/dist-client/modeller/stage-model.js.map +1 -0
  167. package/dist-client/modeller/thumbnail.d.ts +3 -0
  168. package/dist-client/modeller/thumbnail.js +75 -0
  169. package/dist-client/modeller/thumbnail.js.map +1 -0
  170. package/dist-client/modeller/v3-clips.d.ts +1 -1
  171. package/dist-client/modeller/v3-editor.d.ts +5 -0
  172. package/dist-client/modeller/v3-editor.js +21 -10
  173. package/dist-client/modeller/v3-editor.js.map +1 -1
  174. package/dist-client/modeller/v3-product-session.d.ts +31 -0
  175. package/dist-client/modeller/v3-refusals.d.ts +37 -5
  176. package/dist-client/modeller/v3-refusals.js +59 -16
  177. package/dist-client/modeller/v3-refusals.js.map +1 -1
  178. package/dist-client/pages/figure-list-page.d.ts +1 -1
  179. package/dist-client/pages/figure-list-page.js +4 -4
  180. package/dist-client/pages/figure-list-page.js.map +1 -1
  181. package/dist-client/pages/figure-modeller-page.d.ts +102 -0
  182. package/dist-client/pages/figure-modeller-page.js +548 -0
  183. package/dist-client/pages/figure-modeller-page.js.map +1 -0
  184. package/dist-client/route.d.ts +1 -1
  185. package/dist-client/route.js +1 -5
  186. package/dist-client/route.js.map +1 -1
  187. package/dist-client/tsconfig.tsbuildinfo +1 -1
  188. package/docs/product-cutover.md +25 -0
  189. package/package.json +5 -5
  190. package/test/{v3-ai-proposal.test.ts → ai-proposal.test.ts} +6 -6
  191. package/test/{v3-align.test.ts → align.test.ts} +8 -8
  192. package/test/browser/modeller-page.js +30 -30
  193. package/test/browser/modeller.check.mjs +17 -16
  194. package/test/browser/serve.mjs +1 -1
  195. package/test/browser/thumbnail-page.js +6 -6
  196. package/test/{v3-clips.test.ts → clips.test.ts} +18 -18
  197. package/test/{v3-controls.test.ts → controls.test.ts} +15 -15
  198. package/test/{v3-fields.test.ts → fields.test.ts} +13 -13
  199. package/test/figure-assistant-surface.test.ts +3 -3
  200. package/test/{v3-first-save.test.ts → first-save.test.ts} +10 -10
  201. package/test/fixtures/joint-column.json +2 -2
  202. package/test/fixtures/joint-roller.json +2 -2
  203. package/test/fixtures/robot-arm-6dof.json +2 -2
  204. package/test/{v3-gizmo.test.ts → gizmo.test.ts} +33 -33
  205. package/test/{v3-joint-drag.test.ts → joint-drag.test.ts} +17 -17
  206. package/test/{v3-joint-fan.test.ts → joint-fan.test.ts} +18 -18
  207. package/test/joints.ts +6 -6
  208. package/test/{v3-keys.test.ts → keys.test.ts} +2 -2
  209. package/test/{v3-layout.test.ts → layout.test.ts} +8 -8
  210. package/test/{v3-links.test.ts → links.test.ts} +201 -201
  211. package/test/{v3-live.test.ts → live.test.ts} +18 -18
  212. package/test/{v3-material.test.ts → material.test.ts} +12 -12
  213. package/test/{v3-maturity.test.ts → maturity.test.ts} +74 -74
  214. package/test/modeller-route.test.ts +5 -6
  215. package/test/{v3-palette-icons.test.ts → palette-icons.test.ts} +1 -1
  216. package/test/{v3-parts-wiring.test.ts → parts-wiring.test.ts} +11 -7
  217. package/test/{v3-preview.test.ts → preview.test.ts} +12 -12
  218. package/test/{v3-product-session.test.ts → product-session.test.ts} +17 -17
  219. package/test/{v3-product-write.test.ts → product-write.test.ts} +20 -20
  220. package/test/{v3-properties.test.ts → properties.test.ts} +24 -24
  221. package/test/{v3-recipes.test.ts → recipes.test.ts} +10 -10
  222. package/test/refusals.test.ts +166 -0
  223. package/test/{v3-release-panel.test.ts → release-panel.test.ts} +21 -21
  224. package/test/renderer.test.ts +24 -0
  225. package/test/resolve-ts-siblings.mjs +1 -1
  226. package/test/{v3-scene-canvas.test.ts → scene-canvas.test.ts} +6 -6
  227. package/test/{v3-stage-model.test.ts → stage-model.test.ts} +5 -5
  228. package/test/{v3-theme.test.ts → theme.test.ts} +4 -4
  229. package/test/{v3-thumbnail.test.ts → thumbnail.test.ts} +4 -4
  230. package/test/{v3-verdict.test.ts → verdict.test.ts} +17 -17
  231. package/test/{v3-view.test.ts → view.test.ts} +2 -2
  232. package/things-factory.config.js +2 -3
  233. package/translations/en.json +15 -7
  234. package/translations/ja.json +15 -7
  235. package/translations/ko.json +15 -7
  236. package/translations/ms.json +15 -7
  237. package/translations/zh.json +15 -7
  238. package/docs/v3-product-cutover.md +0 -25
  239. package/test/v3-refusals.test.ts +0 -136
  240. package/test/v3-renderer.test.ts +0 -24
  241. /package/client/modeller/{v3-fields.ts → fields.ts} +0 -0
  242. /package/client/modeller/{v3-first-save.ts → first-save.ts} +0 -0
  243. /package/client/modeller/{v3-help.ts → help.ts} +0 -0
  244. /package/client/modeller/{v3-keys.ts → keys.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figure-parts.js","sourceRoot":"","sources":["../../client/modeller/figure-parts.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { PART_LIMIT } from '@hatiolab/figure-model'\nimport type { FigurePrimitiveCreation } from '@hatiolab/figure-model'\nimport type { FigureBudgetLine } from './maturity.js'\nimport { partLabelOf } from './fields.js'\n\n/**\n * 도형 팔레트와 부품 목록 — 자산의 것.\n *\n * 팔레트는 목록 위에, 눈 단추는 늘 자리를 차지하고, 조작은 고른 줄에서만 보인다.\n *\n * 부품의 도형은 평가가 준 `provider` 로 읽는다. 「숨김」은 여기서도 **작업대의 것**이다 — 저장되지 않고, 자산의 `visibility`(상태에 따라\n * 보이고 안 보이는 것)와는 다른 것이다. 그것은 속성 패널의 몫이다.\n *\n * 이 컴포넌트는 정본을 만지지 않는다. 무엇을 하겠다는 것만 알린다.\n */\n\n/** 한 줄 — 평가에서 이 패널이 읽는 것만. */\nexport interface FigurePartRow {\n id: string\n provider: string\n /** 작업대에서 잠깐 가린 것. 저장되지 않는다. */\n hidden?: boolean\n /** 자산이 지금 상태에서 보이지 않는다고 한 것. 저장되는 것이고, 여기서는 표시만 한다. */\n invisible?: boolean\n /** 되풀이한 부품이면 지금 몇 개로 그려지나. 되풀이는 한 부품이다 — 한 줄로 보인다. */\n copies?: number\n}\n\n/** 제공자마다의 아이콘. Material Symbols 이름이다. */\nconst PROVIDER_ICON: Record<string, string> = {\n box: 'deployed_code',\n cylinder: 'database',\n ellipticCylinder: 'database',\n frustum: 'change_history',\n sphere: 'circle',\n roundedBox: 'crop_square',\n roundedBoxXZ: 'crop_square',\n hollowBox: 'check_box_outline_blank',\n hollowBoxXZ: 'check_box_outline_blank',\n polygon: 'pentagon',\n portal: 'door_front'\n}\n\n/** 팔레트 — 저작 API 가 만들 수 있는 것만 보인다. */\n/*\n The palette. A plate and a wall are boxes of a shape a person reaches for, so they are starting sizes, not kinds of their own.\n*/\nexport type FigurePaletteKind = FigurePrimitiveCreation['kind'] | 'plate' | 'wall'\nconst RECIPES: Array<{ kind: FigurePaletteKind; icon: string; label: string }> = [\n { kind: 'box', icon: 'deployed_code', label: 'figure.label.primitive-cube' },\n { kind: 'cylinder', icon: 'database', label: 'figure.label.primitive-cylinder' },\n { kind: 'rounded-box', icon: 'crop_square', label: 'figure.label.primitive-rounded-box' },\n { kind: 'sphere', icon: 'circle', label: 'figure.label.primitive-sphere' },\n { kind: 'frustum', icon: 'change_history', label: 'figure.label.primitive-frustum' },\n { kind: 'polygon', icon: 'hexagon', label: 'figure.label.primitive-polygon' },\n { kind: 'plate', icon: 'check_box_outline_blank', label: 'figure.label.primitive-plate' },\n { kind: 'wall', icon: 'crop_portrait', label: 'figure.label.primitive-wall' },\n { kind: 'portal', icon: 'door_front', label: 'figure.label.primitive-portal' },\n { kind: 'hollow-box', icon: 'inventory_2', label: 'figure.label.primitive-hollow-box' }\n]\n\n@customElement('figure-parts')\nexport class FigureParts extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n background-color: var(--md-sys-color-surface-container-lowest);\n /* The divider beside it is the editor's frame's (ox-three-pane). */\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n font-size: 0.76rem;\n /* Folds by its own width: the editor gives this column 140 px when it has two columns (UX, 2026-09-24). */\n container-type: inline-size;\n }\n section {\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n section[list] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n }\n h3 {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 6px;\n margin: 0 0 6px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n /* The cost line: the grade's letter in its colour, then what the figure costs. */\n button[budget] {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n width: 100%;\n margin: 0 0 6px;\n padding: 4px 6px;\n font: inherit;\n font-size: 0.68rem;\n line-height: 1.5;\n text-align: left;\n color: var(--md-sys-color-on-surface-variant);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[budget]:hover {\n background: var(--md-sys-color-surface-container);\n }\n button[budget] b {\n flex: none;\n min-width: 16px;\n text-align: center;\n border-radius: 4px;\n color: var(--md-sys-color-on-primary-container);\n background: var(--md-sys-color-primary-container);\n }\n button[budget][grade='C'] b {\n color: var(--md-sys-color-on-tertiary-container);\n background: var(--md-sys-color-tertiary-container);\n }\n button[budget][grade='D'] {\n border-color: var(--md-sys-color-error);\n }\n button[budget][grade='D'] b {\n color: var(--md-sys-color-on-error);\n background: var(--md-sys-color-error);\n }\n button[budget] em {\n display: block;\n font-style: normal;\n color: var(--md-sys-color-error);\n }\n span[room][full] {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n p[full] {\n margin: 4px 0 0;\n font-size: 0.68rem;\n color: var(--md-sys-color-error);\n }\n div[level] {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n align-items: center;\n gap: 6px;\n margin: 0 0 6px;\n font-size: 0.68rem;\n color: var(--md-sys-color-on-surface-variant);\n }\n div[level] select {\n min-width: 0;\n padding: 2px 4px;\n font: inherit;\n font-size: 0.7rem;\n color: var(--md-sys-color-on-surface);\n background: var(--md-sys-color-surface-container-lowest);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n }\n small[copies] {\n color: var(--md-sys-color-on-surface-variant);\n }\n span[room] {\n font-size: 0.7rem;\n font-weight: 400;\n letter-spacing: 0;\n text-transform: none;\n }\n /* Three to a row, small (user, 2026-09-24): the palette is reached for, not read -- the list below is what grows. */\n div[palette] {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 3px;\n }\n button[shape] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1px;\n min-width: 0;\n padding: 5px 1px 4px;\n font: var(--label-font, inherit);\n font-size: 0.6rem;\n line-height: 1.2;\n text-align: center;\n overflow-wrap: anywhere;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[recipe-catalog] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n font: inherit;\n font-size: 0.75rem;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 999em;\n cursor: pointer;\n }\n button[shape]:hover:not([disabled]) {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-color: transparent;\n }\n button[shape][disabled] {\n opacity: 0.35;\n cursor: default;\n }\n button[shape] md-icon {\n --md-icon-size: 18px;\n }\n ol {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n li {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 6px;\n border-radius: 6px;\n cursor: pointer;\n }\n li:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n li[selected] {\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n }\n li md-icon {\n --md-icon-size: 16px;\n flex: none;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n button[eye][all] {\n margin-left: auto;\n opacity: 0.75;\n }\n button[eye][all]:hover {\n opacity: 1;\n }\n button[eye] {\n display: flex;\n flex: none;\n padding: 1px;\n color: inherit;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n opacity: 0;\n }\n li:hover button[eye],\n li[selected] button[eye],\n button[eye][off] {\n opacity: 1;\n }\n button[eye][off] {\n color: var(--md-sys-color-tertiary);\n }\n button[eye] md-icon {\n --md-icon-size: 15px;\n color: inherit;\n }\n li[off] span[label],\n li[off] > md-icon,\n li[invisible] span[label],\n li[invisible] > md-icon {\n opacity: 0.45;\n }\n li[selected] md-icon {\n color: inherit;\n }\n span[label] {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 0.78rem;\n }\n span[label] small {\n margin-left: 4px;\n font-size: 0.66rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n div[ops] {\n display: none;\n gap: 1px;\n }\n li[selected] div[ops] {\n display: flex;\n }\n div[ops] button {\n display: flex;\n padding: 2px;\n color: inherit;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n }\n div[ops] button:hover:not([disabled]) {\n background-color: var(--md-sys-color-surface-container-lowest);\n }\n div[ops] button[disabled] {\n opacity: 0.3;\n cursor: default;\n }\n div[ops] md-icon {\n --md-icon-size: 15px;\n color: inherit;\n }\n /*\n Under 200 px the selected row's four buttons pushed its name out and the last one past the edge (seen at 140,\n 2026-09-24). They go to a line of their own under the name.\n */\n @container (max-width: 199px) {\n li[selected] {\n flex-wrap: wrap;\n }\n li[selected] div[ops] {\n flex-basis: 100%;\n justify-content: flex-end;\n }\n }\n p[quiet] {\n margin: 0;\n font-size: 0.76rem;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n `\n ]\n\n @property({ type: Array }) parts: FigurePartRow[] = []\n /** 고른 부품의 id. 자리(index)가 아니다 — 부품은 id 로 안정하게 가리킨다. */\n @property({ type: String }) selected = ''\n /** 편집할 수 없을 때(불러오는 중 · 저장 중) 팔레트와 조작을 잠근다. */\n @property({ type: Boolean }) locked = false\n /**\n * 이 도형이 치르는 값 — 삼각형 · 묶음 · 한 화면에 몇 대 · 등급. 부품을 더하는 바로 그 자리에서 보여야 로우폴리의\n * 기준이 저작을 이끈다. 등급이 D 면 무엇이 넘쳤는지를 적는다. 누르면 성숙도 탭이 열린다.\n */\n @property({ attribute: false }) budget?: FigureBudgetLine\n /**\n * 디테일 등급(S/M/L)의 부품 한도(사용자 2026-09-24). 부품을 넣기 **전에** 몇 개 남았는지 보이고, 다 차면 팔레트가\n * 잠긴다. 되풀이는 한 부품으로 센다. 등급을 안 정했으면 한도는 없다.\n */\n @property({ attribute: false }) partBudget?: { level: 'S' | 'M' | 'L' | null; used: number; limit: number | null }\n /** How many recipe templates the catalog holds; none, and the section is not drawn. */\n @property({ type: Number }) recipeCount = 0\n\n render() {\n const b = this.partBudget\n const full = !!b && b.limit !== null && b.used >= b.limit\n return html`\n <section>\n <h3>${i18next.t('figure.label.shapes')}</h3>\n <div palette>\n ${RECIPES.map(\n recipe => html`\n <button\n shape\n ?disabled=${this.locked || full}\n title=${full ? i18next.t('figure.text.part-limit-reached') : i18next.t(recipe.label)}\n @click=${() => this.ask('add-part', { kind: recipe.kind })}\n >\n <md-icon>${recipe.icon}</md-icon>\n <span>${i18next.t(recipe.label)}</span>\n </button>\n `\n )}\n </div>\n ${full ? html`<p full>${i18next.t('figure.text.part-limit-reached-short', { level: b!.level, limit: b!.limit })}</p>` : nothing}\n </section>\n ${this.renderRecipes(full)}\n\n <section list>\n <h3>\n <span>${i18next.t('figure.label.parts')}</span>\n <span room ?full=${full} title=${i18next.t('figure.text.limit-comes-from-level')}\n >${b && b.limit !== null ? i18next.t('figure.text.n-of-limit', { used: b.used, limit: b.limit }) : (b?.used ?? this.parts.length)}</span\n >\n ${this.renderShowAll()}\n </h3>\n ${this.renderLevel()}\n ${this.renderBudget()}\n ${this.parts.length === 0\n ? html`<p quiet>${i18next.t('figure.text.no-parts-yet')}</p>`\n : html`<ol>\n ${this.parts.map((part, index) => this.renderRow(part, index))}\n </ol>`}\n </section>\n `\n }\n\n /** 디테일 등급 — 고르면 한도가 바뀐다. 목록 머리 아래. */\n private renderLevel() {\n const b = this.partBudget\n if (!b) return nothing\n return html`<div level>\n <label for=\"detail-level\">${i18next.t('figure.label.detail-level')}</label>\n <select\n id=\"detail-level\"\n title=${i18next.t('figure.text.detail-level-explained')}\n .value=${b.level ?? ''}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const value = (e.target as HTMLSelectElement).value\n this.dispatchEvent(new CustomEvent('set-detail-level', { detail: { level: value || null }, bubbles: true, composed: true }))\n }}\n >\n <option value=\"\" ?selected=${!b.level}>${i18next.t('figure.label.detail-none')}</option>\n ${(['S', 'M', 'L'] as const).map(\n one => html`<option value=${one} ?selected=${one === b.level}>\n ${one} ${i18next.t('figure.label.detail-' + one)} · ${i18next.t('figure.text.n-parts-at-most', { limit: PART_LIMIT[one] })}\n </option>`\n )}\n </select>\n </div>`\n }\n\n private renderBudget() {\n const b = this.budget\n if (!b || !this.parts.length) return nothing\n const over = b.grade === 'D'\n return html`<button\n budget\n grade=${b.grade}\n title=${i18next.t('figure.text.parts-budget-open')}\n @click=${() => this.dispatchEvent(new CustomEvent('show-maturity', { bubbles: true, composed: true }))}\n >\n <b>${b.grade}</b>\n <span>\n <strong performance-cost>${i18next.t('figure.label.performance-cost')}</strong>\n ${i18next.t('figure.text.parts-budget', {\n triangles: b.triangles.toLocaleString(),\n groups: b.groups.toLocaleString(),\n instances: b.instances.toLocaleString()\n })}\n ${over\n ? html`<em\n >${i18next.t('figure.text.parts-budget-over', {\n budget: i18next.t('figure.label.budget-' + b.tightest.key),\n used: b.tightest.used.toLocaleString(),\n limit: b.tightest.limit.toLocaleString()\n })}</em\n >`\n : nothing}\n </span>\n </button>`\n }\n\n /** 한꺼번에 감추고 한꺼번에 되돌린다 — 하나라도 감춰져 있으면 다 되돌리고, 다 보이면 다 감춘다. */\n private renderShowAll() {\n if (this.parts.length === 0) return nothing\n const anyHidden = this.parts.some(part => part.hidden)\n return html`\n <button\n eye\n all\n ?off=${!anyHidden}\n title=${i18next.t(anyHidden ? 'figure.text.show-all-parts' : 'figure.text.hide-all-parts')}\n @click=${(e: Event) => {\n e.stopPropagation()\n this.ask('set-all-parts-hidden', { hidden: !anyHidden })\n }}\n >\n <md-icon>${anyHidden ? 'visibility' : 'visibility_off'}</md-icon>\n </button>\n `\n }\n\n private renderRow(part: FigurePartRow, index: number) {\n const selected = part.id === this.selected\n const off = !!part.hidden\n return html`\n <li\n ?selected=${selected}\n ?off=${off}\n ?invisible=${!!part.invisible}\n @click=${() => this.ask('select-part', { id: part.id })}\n >\n <button\n eye\n ?off=${off}\n title=${i18next.t(off ? 'figure.text.show-this-part' : 'figure.text.hide-this-part')}\n @click=${(e: Event) => {\n e.stopPropagation()\n this.ask('toggle-part-hidden', { id: part.id })\n }}\n >\n <md-icon>${off ? 'visibility_off' : 'visibility'}</md-icon>\n </button>\n <md-icon>${PROVIDER_ICON[part.provider] ?? 'deployed_code'}</md-icon>\n <span label title=${part.id}\n >${partLabelOf(part.id)}${part.copies ? html` <small copies>× ${part.copies}</small>` : nothing}${part.invisible ? html`<small>${i18next.t('figure.label.state-hidden')}</small>` : nothing}</span\n >\n ${selected ? this.renderOps(part.id, index) : nothing}\n </li>\n `\n }\n\n /** 고른 줄의 조작. 못 하는 것은 빼지 않고 흐리게 둔다 — 자리가 밀리면 연달아 지우다 엉뚱한 것을 누른다. */\n private renderOps(id: string, index: number) {\n const count = this.parts.length\n const op = (name: string, icon: string, detail: object, enabled = true) => html`\n <button\n op=${name}\n ?disabled=${!enabled || this.locked}\n title=${i18next.t('figure.button.' + name)}\n @click=${(e: Event) => {\n e.stopPropagation()\n if (enabled && !this.locked) this.ask(name, detail)\n }}\n >\n <md-icon>${icon}</md-icon>\n </button>\n `\n return html`\n <div ops>\n ${op('move-part-up', 'arrow_upward', { id, to: index - 1 }, index > 0)}\n ${op('move-part-down', 'arrow_downward', { id, to: index + 1 }, index < count - 1)}\n ${op('duplicate-part', 'content_copy', { id })} ${op('remove-part', 'delete', { id })}\n </div>\n `\n }\n\n /**\n * Recipes (ADR-0095): the catalog of templates -- a door, a roller row -- opened over the modeller, put onto the chosen\n * part in one step.\n */\n private renderRecipes(full: boolean) {\n if (!this.recipeCount) return nothing\n return html`<section recipes>\n <h3>${i18next.t('figure.label.recipes')}</h3>\n <button recipe-catalog ?disabled=${this.locked || full} @click=${() => this.ask('open-recipe-catalog', {})}>\n <md-icon>widgets</md-icon>${i18next.t('figure.button.open-recipe-catalog', { count: this.recipeCount })}\n </button>\n </section>`\n }\n\n /** 정본을 고치지 않는다 — 무엇을 하겠다는 것만 알린다. */\n private ask(what: string, detail: object) {\n this.dispatchEvent(new CustomEvent(what, { detail, bubbles: true, composed: true }))\n }\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import { LitElement } from 'lit';
2
+ import type { FigureAsset } from '@hatiolab/figure-model';
3
+ import { type ViewSettings } from './figure-view.js';
4
+ declare const FigurePreview_base: (new (...args: any[]) => LitElement) & typeof LitElement;
5
+ export declare class FigurePreview extends FigurePreview_base {
6
+ static styles: import("lit").CSSResult;
7
+ /** The figure being authored, as the editor holds it now. */
8
+ asset?: FigureAsset;
9
+ /** Which figure: the type it is registered under here is this one's own, never a real type a board uses. */
10
+ context: string;
11
+ view: ViewSettings;
12
+ private stage;
13
+ private cannot;
14
+ /** Clip speeds and control values given here -- the preview's, not the figure's. */
15
+ private driving;
16
+ private giving;
17
+ private scene?;
18
+ private standing?;
19
+ private registered?;
20
+ private watcher?;
21
+ render(): import("lit-html").TemplateResult<1>;
22
+ private renderDrivers;
23
+ private renderDial;
24
+ private drive;
25
+ private give;
26
+ private poseAsDefault;
27
+ private tellInstances;
28
+ willUpdate(changed: Map<string, unknown>): void;
29
+ firstUpdated(): void;
30
+ disconnectedCallback(): void;
31
+ private standUp;
32
+ private teardown;
33
+ }
34
+ export {};
@@ -0,0 +1,346 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
3
+ import { customElement, property, query, state } from 'lit/decorators.js';
4
+ import { i18next, localize } from '@operato/i18n';
5
+ import { compileFigureAsset } from '@hatiolab/figure-model';
6
+ import { create, registerFigure, unregisterFigure } from '@hatiolab/things-scene';
7
+ import { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH } from './figure-view.js';
8
+ import { dialShape } from './angle-dial.js';
9
+ import { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances } from './preview-model.js';
10
+ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
11
+ constructor() {
12
+ super(...arguments);
13
+ /** Which figure: the type it is registered under here is this one's own, never a real type a board uses. */
14
+ this.context = '';
15
+ this.view = DEFAULT_VIEW;
16
+ this.cannot = '';
17
+ /** Clip speeds and control values given here -- the preview's, not the figure's. */
18
+ this.driving = {};
19
+ this.giving = {};
20
+ }
21
+ static { this.styles = css `
22
+ :host {
23
+ position: relative;
24
+ display: flex;
25
+ min-width: 0;
26
+ min-height: 0;
27
+ overflow: hidden;
28
+ background-color: ${unsafeCSS(WORKBENCH)};
29
+ font-size: 0.76rem;
30
+ }
31
+ div[stage] {
32
+ position: absolute;
33
+ inset: 0;
34
+ width: 100%;
35
+ height: 100%;
36
+ }
37
+ /* Which is which: side by side means nothing without a legend. */
38
+ div[legend] {
39
+ position: absolute;
40
+ top: 8px;
41
+ left: 8px;
42
+ display: flex;
43
+ gap: 6px;
44
+ padding: 4px 8px;
45
+ color: rgba(255, 255, 255, 0.9);
46
+ background-color: rgba(28, 28, 30, 0.6);
47
+ border-radius: 6px;
48
+ font-size: 0.72rem;
49
+ flex-wrap: wrap;
50
+ max-width: calc(100% - 16px);
51
+ }
52
+ /* A variant drawn at another size than it asks: the figure does not declare that size. */
53
+ div[legend] small[clamp] {
54
+ margin-left: 4px;
55
+ color: #ffcc80;
56
+ }
57
+ div[clips] {
58
+ position: absolute;
59
+ right: 8px;
60
+ bottom: 8px;
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: 6px;
64
+ padding: 8px 10px;
65
+ color: rgba(255, 255, 255, 0.92);
66
+ background-color: rgba(28, 28, 30, 0.72);
67
+ border-radius: 8px;
68
+ font-size: 0.72rem;
69
+ }
70
+ div[clips] label {
71
+ display: grid;
72
+ grid-template-columns: auto 20px 96px 34px;
73
+ align-items: center;
74
+ gap: 8px;
75
+ }
76
+ div[clips] svg[dial] {
77
+ width: 20px;
78
+ height: 20px;
79
+ }
80
+ div[clips] svg[dial] path {
81
+ fill: rgba(255, 255, 255, 0.22);
82
+ }
83
+ div[clips] svg[dial] line {
84
+ stroke: var(--md-sys-color-primary, #7cc6ff);
85
+ stroke-width: 2;
86
+ stroke-linecap: round;
87
+ }
88
+ div[clips] svg[dial] circle {
89
+ fill: none;
90
+ stroke: rgba(255, 255, 255, 0.35);
91
+ }
92
+ div[clips] button[pose] {
93
+ align-self: stretch;
94
+ padding: 4px 8px;
95
+ font: inherit;
96
+ font-size: 0.7rem;
97
+ color: rgba(255, 255, 255, 0.92);
98
+ background-color: rgba(255, 255, 255, 0.14);
99
+ border: 1px solid rgba(255, 255, 255, 0.22);
100
+ border-radius: 5px;
101
+ cursor: pointer;
102
+ }
103
+ div[clips] button[pose]:hover {
104
+ background-color: rgba(255, 255, 255, 0.24);
105
+ }
106
+ div[clips] span[drive] {
107
+ opacity: 0.6;
108
+ font-size: 0.66rem;
109
+ }
110
+ div[clips] input {
111
+ width: 96px;
112
+ accent-color: var(--md-sys-color-primary);
113
+ }
114
+ div[clips] output {
115
+ font-variant-numeric: tabular-nums;
116
+ text-align: right;
117
+ opacity: 0.85;
118
+ }
119
+ div[cannot] {
120
+ position: absolute;
121
+ inset: 0;
122
+ display: flex;
123
+ align-items: center;
124
+ justify-content: center;
125
+ padding: 12px;
126
+ text-align: center;
127
+ line-height: 1.6;
128
+ color: #f4f4f4;
129
+ background-color: ${unsafeCSS(WORKBENCH)};
130
+ }
131
+ `; }
132
+ render() {
133
+ const asset = this.asset;
134
+ const controls = asset ? asset.document.model.inputs.filter(i => i.role === 'state') : [];
135
+ const clips = asset ? [...new Set((asset.drivers ?? []).map(d => d.clip))] : [];
136
+ let clampsByWay = {};
137
+ try {
138
+ clampsByWay = asset ? previewClampsOf(asset, authoredSizeOf(asset)) : {};
139
+ }
140
+ catch {
141
+ clampsByWay = {};
142
+ }
143
+ return html `<div stage></div>
144
+ ${this.cannot
145
+ ? html `<div cannot>${this.cannot}</div>`
146
+ : html `<div legend>
147
+ ${PREVIEW_WAYS.map(way => {
148
+ const clamps = clampsByWay[way.name] ?? [];
149
+ return html `<span>
150
+ ${way.axes.length ? way.name : i18next.t('figure.label.preview-base')}
151
+ ${clamps.length
152
+ ? html `<small clamp>${clamps.map(c => i18next.t('figure.text.preview-clamped', { axis: c.axis.toUpperCase(), asked: c.asked.toLocaleString(), used: c.used.toLocaleString() })).join(' · ')}</small>`
153
+ : nothing}
154
+ </span>`;
155
+ })}
156
+ </div>
157
+ ${controls.length + clips.length ? this.renderDrivers(asset, controls, clips) : nothing}`}`;
158
+ }
159
+ renderDrivers(asset, controls, clips) {
160
+ const changed = controls.filter(c => this.giving[c.id] !== undefined && this.giving[c.id] !== asset.stateDefaults[c.id]);
161
+ return html `<div clips>
162
+ ${changed.length
163
+ ? html `<button pose title=${i18next.t('figure.text.pose-as-default-explained')} @click=${() => this.poseAsDefault()}>
164
+ ${i18next.t('figure.button.pose-as-default')}
165
+ </button>`
166
+ : nothing}
167
+ ${controls.map(control => {
168
+ const value = this.giving[control.id] ?? asset.stateDefaults[control.id] ?? control.min;
169
+ const step = Math.max((control.max - control.min) / 100, 0.01);
170
+ const label = asset.stateInputs?.[control.id]?.label ?? control.id;
171
+ return html `<label>
172
+ <span>${label} <span drive>${control.unit}</span></span>
173
+ ${this.renderDial(control, value)}
174
+ <input
175
+ type="range"
176
+ min=${control.min}
177
+ max=${control.max}
178
+ step=${step}
179
+ .value=${String(value)}
180
+ @input=${(e) => this.give(control.id, Number(e.target.value))}
181
+ />
182
+ <output>${Math.round(value)}</output>
183
+ </label>`;
184
+ })}
185
+ ${clips.map(clip => {
186
+ const value = this.driving[clip] ?? 1;
187
+ return html `<label>
188
+ <span>${clip} <span drive>${i18next.t('figure.label.playback-speed')}</span></span>
189
+ <span></span>
190
+ <input type="range" min="0" max="3" step="0.05" .value=${String(value)} @input=${(e) => this.drive(clip, Number(e.target.value))} />
191
+ <output>${value.toFixed(2)}</output>
192
+ </label>`;
193
+ })}
194
+ </div>`;
195
+ }
196
+ renderDial(control, value) {
197
+ if (control.unit !== 'deg')
198
+ return html `<span></span>`;
199
+ const dial = dialShape(control.min, control.max, value);
200
+ const span = dial.radius * 2 + 2;
201
+ return html `<svg dial viewBox="0 0 ${span} ${span}" aria-hidden="true">
202
+ <path d=${dial.sector}></path>
203
+ <circle cx=${dial.centre.x} cy=${dial.centre.y} r=${dial.radius}></circle>
204
+ <line x1=${dial.centre.x} y1=${dial.centre.y} x2=${dial.needle.x} y2=${dial.needle.y}></line>
205
+ </svg>`;
206
+ }
207
+ drive(clip, value) {
208
+ this.driving = { ...this.driving, [clip]: value };
209
+ this.tellInstances('clips', this.driving);
210
+ }
211
+ give(id, value) {
212
+ this.giving = { ...this.giving, [id]: value };
213
+ this.tellInstances('parameters', this.giving);
214
+ }
215
+ poseAsDefault() {
216
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-state-defaults', values: { ...this.giving } } }, bubbles: true, composed: true }));
217
+ this.giving = {};
218
+ }
219
+ tellInstances(key, values) {
220
+ for (const component of this.scene?.root?.components ?? [])
221
+ component.set?.(key, { ...values });
222
+ }
223
+ willUpdate(changed) {
224
+ if (!this.hasUpdated)
225
+ return;
226
+ if (changed.has('asset') || changed.has('context')) {
227
+ this.standUp();
228
+ return;
229
+ }
230
+ if (!changed.has('view'))
231
+ return;
232
+ const before = changed.get('view');
233
+ const now = this.view ?? DEFAULT_VIEW;
234
+ if (before?.placement !== now.placement || before?.ceilingHeight !== now.ceilingHeight)
235
+ this.standUp();
236
+ else
237
+ this.scene?.root?.set?.(sceneLook(now));
238
+ }
239
+ firstUpdated() {
240
+ this.standUp();
241
+ this.watcher = new ResizeObserver(() => this.scene?.resize?.());
242
+ this.watcher.observe(this);
243
+ }
244
+ disconnectedCallback() {
245
+ super.disconnectedCallback();
246
+ this.watcher?.disconnect();
247
+ this.watcher = undefined;
248
+ this.teardown();
249
+ }
250
+ standUp() {
251
+ const asset = this.asset;
252
+ const view = this.view ?? DEFAULT_VIEW;
253
+ if (!asset || !asset.appearance.length) {
254
+ this.cannot = i18next.t('figure.text.preview-needs-a-part');
255
+ this.teardown();
256
+ return;
257
+ }
258
+ const signature = JSON.stringify([asset, view.placement, view.ceilingHeight]);
259
+ if (this.scene && this.standing === signature)
260
+ return;
261
+ try {
262
+ compileFigureAsset(asset);
263
+ }
264
+ catch {
265
+ this.cannot = i18next.t('figure.text.preview-blocked-by-errors');
266
+ this.teardown();
267
+ return;
268
+ }
269
+ this.teardown();
270
+ this.driving = {};
271
+ try {
272
+ /* Registered as a board registers it, under a type of this preview's own: a real type's drawings stay as they are. */
273
+ const type = `figure-preview-${this.context || 'new'}`;
274
+ registerFigure(type, asset);
275
+ this.registered = type;
276
+ const size = authoredSizeOf(asset);
277
+ const { components, board } = previewInstances(type, size);
278
+ this.scene = create({
279
+ target: this.stage,
280
+ model: {
281
+ type: 'model-layer',
282
+ width: board.width,
283
+ height: board.height,
284
+ depth: previewBoardDepth({ placement: asset.occupancy?.placement, base: { y: size.y } }, view.ceilingHeight, PREVIEW_FACTOR),
285
+ threed: true,
286
+ sky: 'color',
287
+ ...sceneLook(view),
288
+ placement: view.placement,
289
+ heights: { floor: 0, ceiling: view.ceilingHeight },
290
+ pixelRatio: Math.min(3, (window.devicePixelRatio || 1) * 2),
291
+ components
292
+ },
293
+ mode: 0
294
+ });
295
+ this.standing = signature;
296
+ this.scene.resize?.();
297
+ this.scene.fit?.('ratio');
298
+ this.scene.root?.fitCameraToModel?.();
299
+ this.cannot = '';
300
+ }
301
+ catch (error) {
302
+ this.cannot = error.message;
303
+ }
304
+ }
305
+ teardown() {
306
+ this.scene?.dispose?.();
307
+ this.scene = undefined;
308
+ this.standing = undefined;
309
+ if (this.registered)
310
+ unregisterFigure(this.registered);
311
+ this.registered = undefined;
312
+ }
313
+ };
314
+ __decorate([
315
+ property({ attribute: false }),
316
+ __metadata("design:type", Object)
317
+ ], FigurePreview.prototype, "asset", void 0);
318
+ __decorate([
319
+ property(),
320
+ __metadata("design:type", Object)
321
+ ], FigurePreview.prototype, "context", void 0);
322
+ __decorate([
323
+ property({ attribute: false }),
324
+ __metadata("design:type", Object)
325
+ ], FigurePreview.prototype, "view", void 0);
326
+ __decorate([
327
+ query('div[stage]'),
328
+ __metadata("design:type", HTMLDivElement)
329
+ ], FigurePreview.prototype, "stage", void 0);
330
+ __decorate([
331
+ state(),
332
+ __metadata("design:type", Object)
333
+ ], FigurePreview.prototype, "cannot", void 0);
334
+ __decorate([
335
+ state(),
336
+ __metadata("design:type", Object)
337
+ ], FigurePreview.prototype, "driving", void 0);
338
+ __decorate([
339
+ state(),
340
+ __metadata("design:type", Object)
341
+ ], FigurePreview.prototype, "giving", void 0);
342
+ FigurePreview = __decorate([
343
+ customElement('figure-preview')
344
+ ], FigurePreview);
345
+ export { FigurePreview };
346
+ //# sourceMappingURL=figure-preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figure-preview.js","sourceRoot":"","sources":["../../client/modeller/figure-preview.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { compileFigureAsset } from '@hatiolab/figure-model'\nimport type { FigureAsset } from '@hatiolab/figure-model'\nimport { create, registerFigure, unregisterFigure } from '@hatiolab/things-scene'\n\nimport { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH, type ViewSettings } from './figure-view.js'\nimport { dialShape } from './angle-dial.js'\nimport { authoredSizeOf, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances } from './preview-model.js'\n\n/**\n * The figure placed on a board.\n *\n * The editing canvas shows the figure at the size it was made. Half of what a figure is lies in how it answers a\n * different size, so here the figure being authored is registered as a board registers it and placed as\n * `FigureInstance`s: the size it was made, and each of the seven ways of growing one, two or three axes twice as\n * large, side by side at one scale, four to a row. The board draws them as it will on a real board --\n * placement, lights, environment, the same renderer.\n *\n * The controls: each value that poses the figure with a slider (and a dial for an angle), each clip's\n * speed, and 「이 자세를 기본으로」 to keep the pose as the one it stands in. Nothing here is edited; the canvas edits.\n */\n\ninterface SceneHandle {\n dispose?: () => void\n resize?: () => void\n fit?: (type?: string) => void\n root?: {\n set?: (patch: Record<string, unknown>) => void\n fitCameraToModel?: () => void\n components?: { set?: (property: string, value: unknown) => void }[]\n }\n}\n\n@customElement('figure-preview')\nexport class FigurePreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n position: relative;\n display: flex;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n background-color: ${unsafeCSS(WORKBENCH)};\n font-size: 0.76rem;\n }\n div[stage] {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n }\n /* Which is which: side by side means nothing without a legend. */\n div[legend] {\n position: absolute;\n top: 8px;\n left: 8px;\n display: flex;\n gap: 6px;\n padding: 4px 8px;\n color: rgba(255, 255, 255, 0.9);\n background-color: rgba(28, 28, 30, 0.6);\n border-radius: 6px;\n font-size: 0.72rem;\n flex-wrap: wrap;\n max-width: calc(100% - 16px);\n }\n /* A variant drawn at another size than it asks: the figure does not declare that size. */\n div[legend] small[clamp] {\n margin-left: 4px;\n color: #ffcc80;\n }\n div[clips] {\n position: absolute;\n right: 8px;\n bottom: 8px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px 10px;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(28, 28, 30, 0.72);\n border-radius: 8px;\n font-size: 0.72rem;\n }\n div[clips] label {\n display: grid;\n grid-template-columns: auto 20px 96px 34px;\n align-items: center;\n gap: 8px;\n }\n div[clips] svg[dial] {\n width: 20px;\n height: 20px;\n }\n div[clips] svg[dial] path {\n fill: rgba(255, 255, 255, 0.22);\n }\n div[clips] svg[dial] line {\n stroke: var(--md-sys-color-primary, #7cc6ff);\n stroke-width: 2;\n stroke-linecap: round;\n }\n div[clips] svg[dial] circle {\n fill: none;\n stroke: rgba(255, 255, 255, 0.35);\n }\n div[clips] button[pose] {\n align-self: stretch;\n padding: 4px 8px;\n font: inherit;\n font-size: 0.7rem;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(255, 255, 255, 0.14);\n border: 1px solid rgba(255, 255, 255, 0.22);\n border-radius: 5px;\n cursor: pointer;\n }\n div[clips] button[pose]:hover {\n background-color: rgba(255, 255, 255, 0.24);\n }\n div[clips] span[drive] {\n opacity: 0.6;\n font-size: 0.66rem;\n }\n div[clips] input {\n width: 96px;\n accent-color: var(--md-sys-color-primary);\n }\n div[clips] output {\n font-variant-numeric: tabular-nums;\n text-align: right;\n opacity: 0.85;\n }\n div[cannot] {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n text-align: center;\n line-height: 1.6;\n color: #f4f4f4;\n background-color: ${unsafeCSS(WORKBENCH)};\n }\n `\n\n /** The figure being authored, as the editor holds it now. */\n @property({ attribute: false }) asset?: FigureAsset\n /** Which figure: the type it is registered under here is this one's own, never a real type a board uses. */\n @property() context = ''\n @property({ attribute: false }) view: ViewSettings = DEFAULT_VIEW\n\n @query('div[stage]') private stage!: HTMLDivElement\n @state() private cannot = ''\n /** Clip speeds and control values given here -- the preview's, not the figure's. */\n @state() private driving: Record<string, number> = {}\n @state() private giving: Record<string, number> = {}\n\n private scene?: SceneHandle\n private standing?: string\n private registered?: string\n private watcher?: ResizeObserver\n\n render() {\n const asset = this.asset\n const controls = asset ? asset.document.model.inputs.filter(i => i.role === 'state') : []\n const clips = asset ? [...new Set((asset.drivers ?? []).map(d => d.clip))] : []\n let clampsByWay: ReturnType<typeof previewClampsOf> = {}\n try {\n clampsByWay = asset ? previewClampsOf(asset, authoredSizeOf(asset)) : {}\n } catch {\n clampsByWay = {}\n }\n return html`<div stage></div>\n ${this.cannot\n ? html`<div cannot>${this.cannot}</div>`\n : html`<div legend>\n ${PREVIEW_WAYS.map(way => {\n const clamps = clampsByWay[way.name] ?? []\n return html`<span>\n ${way.axes.length ? way.name : i18next.t('figure.label.preview-base')}\n ${clamps.length\n ? html`<small clamp>${clamps.map(c => i18next.t('figure.text.preview-clamped', { axis: c.axis.toUpperCase(), asked: c.asked.toLocaleString(), used: c.used.toLocaleString() })).join(' · ')}</small>`\n : nothing}\n </span>`\n })}\n </div>\n ${controls.length + clips.length ? this.renderDrivers(asset!, controls, clips) : nothing}`}`\n }\n\n private renderDrivers(asset: FigureAsset, controls: FigureAsset['document']['model']['inputs'], clips: string[]) {\n const changed = controls.filter(c => this.giving[c.id] !== undefined && this.giving[c.id] !== asset.stateDefaults[c.id])\n return html`<div clips>\n ${changed.length\n ? html`<button pose title=${i18next.t('figure.text.pose-as-default-explained')} @click=${() => this.poseAsDefault()}>\n ${i18next.t('figure.button.pose-as-default')}\n </button>`\n : nothing}\n ${controls.map(control => {\n const value = this.giving[control.id] ?? asset.stateDefaults[control.id] ?? control.min\n const step = Math.max((control.max - control.min) / 100, 0.01)\n const label = asset.stateInputs?.[control.id]?.label ?? control.id\n return html`<label>\n <span>${label} <span drive>${control.unit}</span></span>\n ${this.renderDial(control, value)}\n <input\n type=\"range\"\n min=${control.min}\n max=${control.max}\n step=${step}\n .value=${String(value)}\n @input=${(e: Event) => this.give(control.id, Number((e.target as HTMLInputElement).value))}\n />\n <output>${Math.round(value)}</output>\n </label>`\n })}\n ${clips.map(clip => {\n const value = this.driving[clip] ?? 1\n return html`<label>\n <span>${clip} <span drive>${i18next.t('figure.label.playback-speed')}</span></span>\n <span></span>\n <input type=\"range\" min=\"0\" max=\"3\" step=\"0.05\" .value=${String(value)} @input=${(e: Event) => this.drive(clip, Number((e.target as HTMLInputElement).value))} />\n <output>${value.toFixed(2)}</output>\n </label>`\n })}\n </div>`\n }\n\n private renderDial(control: { unit: string; min: number; max: number }, value: number) {\n if (control.unit !== 'deg') return html`<span></span>`\n const dial = dialShape(control.min, control.max, value)\n const span = dial.radius * 2 + 2\n return html`<svg dial viewBox=\"0 0 ${span} ${span}\" aria-hidden=\"true\">\n <path d=${dial.sector}></path>\n <circle cx=${dial.centre.x} cy=${dial.centre.y} r=${dial.radius}></circle>\n <line x1=${dial.centre.x} y1=${dial.centre.y} x2=${dial.needle.x} y2=${dial.needle.y}></line>\n </svg>`\n }\n\n private drive(clip: string, value: number) {\n this.driving = { ...this.driving, [clip]: value }\n this.tellInstances('clips', this.driving)\n }\n\n private give(id: string, value: number) {\n this.giving = { ...this.giving, [id]: value }\n this.tellInstances('parameters', this.giving)\n }\n\n private poseAsDefault() {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-state-defaults', values: { ...this.giving } } }, bubbles: true, composed: true }))\n this.giving = {}\n }\n\n private tellInstances(key: 'clips' | 'parameters', values: Record<string, number>) {\n for (const component of this.scene?.root?.components ?? []) component.set?.(key, { ...values })\n }\n\n willUpdate(changed: Map<string, unknown>) {\n if (!this.hasUpdated) return\n if (changed.has('asset') || changed.has('context')) {\n this.standUp()\n return\n }\n if (!changed.has('view')) return\n const before = changed.get('view') as ViewSettings | undefined\n const now = this.view ?? DEFAULT_VIEW\n if (before?.placement !== now.placement || before?.ceilingHeight !== now.ceilingHeight) this.standUp()\n else this.scene?.root?.set?.(sceneLook(now))\n }\n\n firstUpdated() {\n this.standUp()\n this.watcher = new ResizeObserver(() => this.scene?.resize?.())\n this.watcher.observe(this)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.watcher?.disconnect()\n this.watcher = undefined\n this.teardown()\n }\n\n private standUp() {\n const asset = this.asset\n const view = this.view ?? DEFAULT_VIEW\n if (!asset || !asset.appearance.length) {\n this.cannot = i18next.t('figure.text.preview-needs-a-part')\n this.teardown()\n return\n }\n const signature = JSON.stringify([asset, view.placement, view.ceilingHeight])\n if (this.scene && this.standing === signature) return\n try {\n compileFigureAsset(asset)\n } catch {\n this.cannot = i18next.t('figure.text.preview-blocked-by-errors')\n this.teardown()\n return\n }\n this.teardown()\n this.driving = {}\n try {\n /* Registered as a board registers it, under a type of this preview's own: a real type's drawings stay as they are. */\n const type = `figure-preview-${this.context || 'new'}`\n registerFigure(type, asset)\n this.registered = type\n const size = authoredSizeOf(asset)\n const { components, board } = previewInstances(type, size)\n this.scene = create({\n target: this.stage,\n model: {\n type: 'model-layer',\n width: board.width,\n height: board.height,\n depth: previewBoardDepth({ placement: asset.occupancy?.placement, base: { y: size.y } }, view.ceilingHeight, PREVIEW_FACTOR),\n threed: true,\n sky: 'color',\n ...sceneLook(view),\n placement: view.placement,\n heights: { floor: 0, ceiling: view.ceilingHeight },\n pixelRatio: Math.min(3, (window.devicePixelRatio || 1) * 2),\n components\n },\n mode: 0\n }) as SceneHandle\n this.standing = signature\n this.scene.resize?.()\n this.scene.fit?.('ratio')\n this.scene.root?.fitCameraToModel?.()\n this.cannot = ''\n } catch (error) {\n this.cannot = (error as Error).message\n }\n }\n\n private teardown() {\n this.scene?.dispose?.()\n this.scene = undefined\n this.standing = undefined\n if (this.registered) unregisterFigure(this.registered)\n this.registered = undefined\n }\n}\n"]}
@@ -0,0 +1,45 @@
1
+ import '@material/web/icon/icon.js';
2
+ import { LitElement, nothing } from 'lit';
3
+ declare const FigureProperties_base: (new (...args: any[]) => LitElement) & typeof LitElement;
4
+ /**
5
+ * 속성 — the modeller's figure properties.
6
+ *
7
+ * The tab opens with what the figure is: its name, the face it is placed by, the room it takes up, where the
8
+ * catalogue files it.
9
+ *
10
+ * Two kinds of change leave this tab, and it does neither itself:
11
+ * - `command` carries an authoring command (rename, declare the room, the mounting face). The page runs it
12
+ * through the session, so it is one step of the same undo history as every other edit, and is saved with it.
13
+ * - `catalog` carries a change to the row (category, tags). Those are not in the asset; the page writes them
14
+ * to the saved row at once, so they need a saved figure.
15
+ *
16
+ * Not here yet, because has no place for them: editing the declared room by hand (declares it from the
17
+ * parts, as graph expressions), and the detail level. Both wait on a ruling.
18
+ */
19
+ export declare class FigureProperties extends FigureProperties_base {
20
+ static styles: import("lit").CSSResult[];
21
+ /** The source being edited. */
22
+ source?: string;
23
+ /** The saved row, if any. Category and tags live on it. */
24
+ figureId?: string;
25
+ figureCategory?: string;
26
+ figureTags?: string[];
27
+ /** The part and face picked for the mounting face, before 「이 면으로」 is pressed. */
28
+ private pickedPart?;
29
+ private pickedFace?;
30
+ private facts;
31
+ render(): import("lit-html").TemplateResult<1> | typeof nothing;
32
+ private renderName;
33
+ /**
34
+ * The face the figure is placed by. In it is part of the room declaration, so choosing one declares the room
35
+ * again from the parts — the only way declares it — with the new face. The hint says so.
36
+ */
37
+ private renderPlacement;
38
+ private renderSpace;
39
+ private renderMounting;
40
+ private renderCatalog;
41
+ private declare;
42
+ private command;
43
+ private catalog;
44
+ }
45
+ export {};