@things-factory/figure-ui 10.1.75 → 10.1.77
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.
- package/client/figure-assistant.ts +3 -3
- package/client/graphql/{v3-store.ts → store.ts} +6 -6
- package/client/modeller/{v3-ai-proposal.ts → ai-proposal.ts} +8 -8
- package/client/modeller/{v3-align.ts → align.ts} +14 -14
- package/client/modeller/{v3-canvas.ts → canvas.ts} +13 -13
- package/client/modeller/{v3-clips.ts → clips.ts} +5 -5
- package/client/modeller/{v3-controls.ts → controls.ts} +2 -2
- package/client/modeller/{v3-editor.ts → editor.ts} +117 -117
- package/client/modeller/{figure-v3-capability.ts → figure-capability-panel.ts} +7 -7
- package/client/modeller/{figure-v3-clips.ts → figure-clips.ts} +10 -10
- package/client/modeller/{figure-v3-controls.ts → figure-controls.ts} +9 -9
- package/client/modeller/{v3-figure-facts.ts → figure-facts.ts} +11 -11
- package/client/modeller/{figure-v3-first-save.ts → figure-first-save.ts} +3 -3
- package/client/modeller/figure-history-panel.ts +1 -1
- package/client/modeller/{figure-v3-links.ts → figure-links.ts} +35 -35
- package/client/modeller/{figure-v3-material.ts → figure-material-panel.ts} +20 -20
- package/client/modeller/{figure-v3-parts.ts → figure-parts.ts} +15 -15
- package/client/modeller/{figure-v3-preview.ts → figure-preview.ts} +14 -14
- package/client/modeller/{figure-v3-properties.ts → figure-properties.ts} +25 -25
- package/client/modeller/{figure-v3-recipe-catalog.ts → figure-recipe-catalog.ts} +10 -10
- package/client/modeller/{figure-v3-verdict.ts → figure-verdict.ts} +24 -24
- package/client/modeller/gate-findings.ts +2 -2
- package/client/modeller/{v3-gizmo.ts → gizmo.ts} +11 -11
- package/client/modeller/{v3-joint-drag.ts → joint-drag.ts} +11 -11
- package/client/modeller/{v3-joint-fan.ts → joint-fan.ts} +13 -13
- package/client/modeller/{v3-links.ts → links.ts} +59 -59
- package/client/modeller/{v3-live.ts → live.ts} +9 -9
- package/client/modeller/{v3-maturity.ts → maturity.ts} +65 -65
- package/client/modeller/modeller-route.ts +1 -1
- package/client/modeller/{v3-occupancy.ts → occupancy.ts} +6 -6
- package/client/modeller/{v3-palette.ts → palette.ts} +3 -3
- package/client/modeller/{v3-preview-model.ts → preview-model.ts} +8 -8
- package/client/modeller/{v3-product-session.ts → product-session.ts} +25 -25
- package/client/modeller/{v3-recipe-source.ts → recipe-source.ts} +2 -2
- package/client/modeller/{v3-recipes.ts → recipes.ts} +9 -9
- package/client/modeller/{v3-renderer.ts → renderer.ts} +16 -16
- package/client/modeller/{v3-stage-model.ts → stage-model.ts} +15 -15
- package/client/modeller/{v3-thumbnail.ts → thumbnail.ts} +8 -8
- package/client/pages/figure-list-page.ts +4 -4
- package/client/pages/{figure-v3-modeller-page.ts → figure-modeller-page.ts} +37 -37
- package/client/route.ts +1 -5
- package/dist-client/figure-assistant.js +3 -3
- package/dist-client/figure-assistant.js.map +1 -1
- package/dist-client/graphql/store.d.ts +3 -0
- package/dist-client/graphql/{v3-store.js → store.js} +6 -6
- package/dist-client/graphql/store.js.map +1 -0
- package/dist-client/modeller/{v3-ai-proposal.d.ts → ai-proposal.d.ts} +7 -7
- package/dist-client/modeller/{v3-ai-proposal.js → ai-proposal.js} +1 -1
- package/dist-client/modeller/ai-proposal.js.map +1 -0
- package/dist-client/modeller/{v3-align.d.ts → align.d.ts} +8 -8
- package/dist-client/modeller/{v3-align.js → align.js} +6 -6
- package/dist-client/modeller/align.js.map +1 -0
- package/dist-client/modeller/{v3-canvas.d.ts → canvas.d.ts} +7 -7
- package/dist-client/modeller/{v3-canvas.js → canvas.js} +20 -20
- package/dist-client/modeller/canvas.js.map +1 -0
- package/dist-client/modeller/{v3-clips.d.ts → clips.d.ts} +4 -4
- package/dist-client/modeller/{v3-clips.js → clips.js} +1 -1
- package/dist-client/modeller/clips.js.map +1 -0
- package/dist-client/modeller/{v3-controls.d.ts → controls.d.ts} +2 -2
- package/dist-client/modeller/{v3-controls.js → controls.js} +1 -1
- package/dist-client/modeller/controls.js.map +1 -0
- package/dist-client/modeller/{v3-editor.d.ts → editor.d.ts} +19 -19
- package/dist-client/modeller/{v3-editor.js → editor.js} +103 -103
- package/dist-client/modeller/editor.js.map +1 -0
- package/dist-client/modeller/{v3-fields.js → fields.js} +1 -1
- package/dist-client/modeller/fields.js.map +1 -0
- package/dist-client/modeller/{figure-v3-capability.d.ts → figure-capability-panel.d.ts} +4 -4
- package/dist-client/modeller/{figure-v3-capability.js → figure-capability-panel.js} +12 -12
- package/dist-client/modeller/figure-capability-panel.js.map +1 -0
- package/dist-client/modeller/{figure-v3-clips.d.ts → figure-clips.d.ts} +4 -4
- package/dist-client/modeller/{figure-v3-clips.js → figure-clips.js} +16 -16
- package/dist-client/modeller/figure-clips.js.map +1 -0
- package/dist-client/modeller/{figure-v3-controls.d.ts → figure-controls.d.ts} +5 -5
- package/dist-client/modeller/{figure-v3-controls.js → figure-controls.js} +16 -16
- package/dist-client/modeller/figure-controls.js.map +1 -0
- package/dist-client/modeller/{v3-figure-facts.d.ts → figure-facts.d.ts} +5 -5
- package/dist-client/modeller/{v3-figure-facts.js → figure-facts.js} +5 -5
- package/dist-client/modeller/figure-facts.js.map +1 -0
- package/dist-client/modeller/{figure-v3-first-save.d.ts → figure-first-save.d.ts} +1 -1
- package/dist-client/modeller/{figure-v3-first-save.js → figure-first-save.js} +11 -11
- package/dist-client/modeller/figure-first-save.js.map +1 -0
- package/dist-client/modeller/figure-history-panel.d.ts +1 -1
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/{figure-v3-links.d.ts → figure-links.d.ts} +5 -5
- package/dist-client/modeller/{figure-v3-links.js → figure-links.js} +24 -24
- package/dist-client/modeller/figure-links.js.map +1 -0
- package/dist-client/modeller/{figure-v3-material.d.ts → figure-material-panel.d.ts} +9 -9
- package/dist-client/modeller/{figure-v3-material.js → figure-material-panel.js} +19 -19
- package/dist-client/modeller/figure-material-panel.js.map +1 -0
- package/dist-client/modeller/{figure-v3-parts.d.ts → figure-parts.d.ts} +12 -12
- package/dist-client/modeller/{figure-v3-parts.js → figure-parts.js} +14 -14
- package/dist-client/modeller/figure-parts.js.map +1 -0
- package/dist-client/modeller/{figure-v3-preview.d.ts → figure-preview.d.ts} +4 -4
- package/dist-client/modeller/{figure-v3-preview.js → figure-preview.js} +21 -21
- package/dist-client/modeller/figure-preview.js.map +1 -0
- package/dist-client/modeller/{figure-v3-properties.d.ts → figure-properties.d.ts} +8 -8
- package/dist-client/modeller/{figure-v3-properties.js → figure-properties.js} +25 -25
- package/dist-client/modeller/figure-properties.js.map +1 -0
- package/dist-client/modeller/{figure-v3-recipe-catalog.d.ts → figure-recipe-catalog.d.ts} +4 -4
- package/dist-client/modeller/{figure-v3-recipe-catalog.js → figure-recipe-catalog.js} +21 -21
- package/dist-client/modeller/figure-recipe-catalog.js.map +1 -0
- package/dist-client/modeller/{figure-v3-verdict.d.ts → figure-verdict.d.ts} +2 -2
- package/dist-client/modeller/{figure-v3-verdict.js → figure-verdict.js} +26 -26
- package/dist-client/modeller/figure-verdict.js.map +1 -0
- package/dist-client/modeller/{v3-first-save.js → first-save.js} +1 -1
- package/dist-client/modeller/first-save.js.map +1 -0
- package/dist-client/modeller/gate-findings.d.ts +2 -2
- package/dist-client/modeller/gate-findings.js +2 -2
- package/dist-client/modeller/gate-findings.js.map +1 -1
- package/dist-client/modeller/{v3-gizmo.d.ts → gizmo.d.ts} +5 -5
- package/dist-client/modeller/{v3-gizmo.js → gizmo.js} +3 -3
- package/dist-client/modeller/gizmo.js.map +1 -0
- package/dist-client/modeller/{v3-help.js → help.js} +1 -1
- package/dist-client/modeller/help.js.map +1 -0
- package/dist-client/modeller/joint-drag.d.ts +19 -0
- package/dist-client/modeller/{v3-joint-drag.js → joint-drag.js} +4 -4
- package/dist-client/modeller/joint-drag.js.map +1 -0
- package/dist-client/modeller/{v3-joint-fan.d.ts → joint-fan.d.ts} +3 -3
- package/dist-client/modeller/{v3-joint-fan.js → joint-fan.js} +6 -6
- package/dist-client/modeller/joint-fan.js.map +1 -0
- package/dist-client/modeller/{v3-keys.js → keys.js} +1 -1
- package/dist-client/modeller/keys.js.map +1 -0
- package/dist-client/modeller/{v3-links.d.ts → links.d.ts} +48 -48
- package/dist-client/modeller/{v3-links.js → links.js} +15 -15
- package/dist-client/modeller/links.js.map +1 -0
- package/dist-client/modeller/{v3-live.d.ts → live.d.ts} +6 -6
- package/dist-client/modeller/{v3-live.js → live.js} +5 -5
- package/dist-client/modeller/live.js.map +1 -0
- package/dist-client/modeller/{v3-maturity.d.ts → maturity.d.ts} +26 -26
- package/dist-client/modeller/{v3-maturity.js → maturity.js} +28 -28
- package/dist-client/modeller/maturity.js.map +1 -0
- package/dist-client/modeller/modeller-route.d.ts +1 -1
- package/dist-client/modeller/modeller-route.js +1 -1
- package/dist-client/modeller/modeller-route.js.map +1 -1
- package/dist-client/modeller/{v3-occupancy.d.ts → occupancy.d.ts} +4 -4
- package/dist-client/modeller/{v3-occupancy.js → occupancy.js} +6 -6
- package/dist-client/modeller/occupancy.js.map +1 -0
- package/dist-client/modeller/palette.d.ts +7 -0
- package/dist-client/modeller/{v3-palette.js → palette.js} +1 -1
- package/dist-client/modeller/palette.js.map +1 -0
- package/dist-client/modeller/{v3-preview-model.d.ts → preview-model.d.ts} +3 -3
- package/dist-client/modeller/{v3-preview-model.js → preview-model.js} +6 -6
- package/dist-client/modeller/preview-model.js.map +1 -0
- package/dist-client/modeller/{v3-product-session.d.ts → product-session.d.ts} +56 -56
- package/dist-client/modeller/{v3-product-session.js → product-session.js} +7 -7
- package/dist-client/modeller/product-session.js.map +1 -0
- package/dist-client/modeller/{v3-recipe-source.d.ts → recipe-source.d.ts} +2 -2
- package/dist-client/modeller/{v3-recipe-source.js → recipe-source.js} +3 -3
- package/dist-client/modeller/recipe-source.js.map +1 -0
- package/dist-client/modeller/{v3-recipes.d.ts → recipes.d.ts} +7 -7
- package/dist-client/modeller/{v3-recipes.js → recipes.js} +4 -4
- package/dist-client/modeller/recipes.js.map +1 -0
- package/dist-client/modeller/{v3-refusals.js → refusals.js} +1 -1
- package/dist-client/modeller/refusals.js.map +1 -0
- package/dist-client/modeller/{v3-renderer.d.ts → renderer.d.ts} +6 -6
- package/dist-client/modeller/{v3-renderer.js → renderer.js} +13 -13
- package/dist-client/modeller/renderer.js.map +1 -0
- package/dist-client/modeller/{v3-stage-model.d.ts → stage-model.d.ts} +7 -7
- package/dist-client/modeller/{v3-stage-model.js → stage-model.js} +5 -5
- package/dist-client/modeller/stage-model.js.map +1 -0
- package/dist-client/modeller/thumbnail.d.ts +3 -0
- package/dist-client/modeller/{v3-thumbnail.js → thumbnail.js} +6 -6
- package/dist-client/modeller/thumbnail.js.map +1 -0
- package/dist-client/pages/figure-list-page.d.ts +1 -1
- package/dist-client/pages/figure-list-page.js +4 -4
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/{figure-v3-modeller-page.d.ts → figure-modeller-page.d.ts} +10 -10
- package/dist-client/pages/{figure-v3-modeller-page.js → figure-modeller-page.js} +42 -42
- package/dist-client/pages/figure-modeller-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +1 -5
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/docs/product-cutover.md +25 -0
- package/package.json +5 -5
- package/test/{v3-ai-proposal.test.ts → ai-proposal.test.ts} +6 -6
- package/test/{v3-align.test.ts → align.test.ts} +8 -8
- package/test/browser/modeller-page.js +30 -30
- package/test/browser/modeller.check.mjs +14 -14
- package/test/browser/serve.mjs +1 -1
- package/test/browser/thumbnail-page.js +6 -6
- package/test/{v3-clips.test.ts → clips.test.ts} +18 -18
- package/test/{v3-controls.test.ts → controls.test.ts} +15 -15
- package/test/{v3-fields.test.ts → fields.test.ts} +13 -13
- package/test/figure-assistant-surface.test.ts +3 -3
- package/test/{v3-first-save.test.ts → first-save.test.ts} +10 -10
- package/test/fixtures/joint-column.json +2 -2
- package/test/fixtures/joint-roller.json +2 -2
- package/test/fixtures/robot-arm-6dof.json +2 -2
- package/test/{v3-gizmo.test.ts → gizmo.test.ts} +33 -33
- package/test/{v3-joint-drag.test.ts → joint-drag.test.ts} +17 -17
- package/test/{v3-joint-fan.test.ts → joint-fan.test.ts} +18 -18
- package/test/joints.ts +6 -6
- package/test/{v3-keys.test.ts → keys.test.ts} +2 -2
- package/test/{v3-layout.test.ts → layout.test.ts} +8 -8
- package/test/{v3-links.test.ts → links.test.ts} +201 -201
- package/test/{v3-live.test.ts → live.test.ts} +18 -18
- package/test/{v3-material.test.ts → material.test.ts} +12 -12
- package/test/{v3-maturity.test.ts → maturity.test.ts} +74 -74
- package/test/modeller-route.test.ts +5 -6
- package/test/{v3-palette-icons.test.ts → palette-icons.test.ts} +1 -1
- package/test/{v3-parts-wiring.test.ts → parts-wiring.test.ts} +5 -5
- package/test/{v3-preview.test.ts → preview.test.ts} +12 -12
- package/test/{v3-product-session.test.ts → product-session.test.ts} +17 -17
- package/test/{v3-product-write.test.ts → product-write.test.ts} +20 -20
- package/test/{v3-properties.test.ts → properties.test.ts} +24 -24
- package/test/{v3-recipes.test.ts → recipes.test.ts} +9 -9
- package/test/{v3-refusals.test.ts → refusals.test.ts} +43 -43
- package/test/{v3-release-panel.test.ts → release-panel.test.ts} +21 -21
- package/test/renderer.test.ts +24 -0
- package/test/resolve-ts-siblings.mjs +1 -1
- package/test/{v3-scene-canvas.test.ts → scene-canvas.test.ts} +6 -6
- package/test/{v3-stage-model.test.ts → stage-model.test.ts} +5 -5
- package/test/{v3-theme.test.ts → theme.test.ts} +4 -4
- package/test/{v3-thumbnail.test.ts → thumbnail.test.ts} +4 -4
- package/test/{v3-verdict.test.ts → verdict.test.ts} +17 -17
- package/test/{v3-view.test.ts → view.test.ts} +2 -2
- package/things-factory.config.js +2 -3
- package/translations/en.json +2 -2
- package/translations/ja.json +2 -2
- package/translations/ko.json +2 -2
- package/translations/ms.json +2 -2
- package/translations/zh.json +2 -2
- package/dist-client/graphql/v3-store.d.ts +0 -3
- package/dist-client/graphql/v3-store.js.map +0 -1
- package/dist-client/modeller/figure-v3-capability.js.map +0 -1
- package/dist-client/modeller/figure-v3-clips.js.map +0 -1
- package/dist-client/modeller/figure-v3-controls.js.map +0 -1
- package/dist-client/modeller/figure-v3-first-save.js.map +0 -1
- package/dist-client/modeller/figure-v3-links.js.map +0 -1
- package/dist-client/modeller/figure-v3-material.js.map +0 -1
- package/dist-client/modeller/figure-v3-parts.js.map +0 -1
- package/dist-client/modeller/figure-v3-preview.js.map +0 -1
- package/dist-client/modeller/figure-v3-properties.js.map +0 -1
- package/dist-client/modeller/figure-v3-recipe-catalog.js.map +0 -1
- package/dist-client/modeller/figure-v3-verdict.js.map +0 -1
- package/dist-client/modeller/v3-ai-proposal.js.map +0 -1
- package/dist-client/modeller/v3-align.js.map +0 -1
- package/dist-client/modeller/v3-canvas.js.map +0 -1
- package/dist-client/modeller/v3-clips.js.map +0 -1
- package/dist-client/modeller/v3-controls.js.map +0 -1
- package/dist-client/modeller/v3-editor.js.map +0 -1
- package/dist-client/modeller/v3-fields.js.map +0 -1
- package/dist-client/modeller/v3-figure-facts.js.map +0 -1
- package/dist-client/modeller/v3-first-save.js.map +0 -1
- package/dist-client/modeller/v3-gizmo.js.map +0 -1
- package/dist-client/modeller/v3-help.js.map +0 -1
- package/dist-client/modeller/v3-joint-drag.d.ts +0 -19
- package/dist-client/modeller/v3-joint-drag.js.map +0 -1
- package/dist-client/modeller/v3-joint-fan.js.map +0 -1
- package/dist-client/modeller/v3-keys.js.map +0 -1
- package/dist-client/modeller/v3-links.js.map +0 -1
- package/dist-client/modeller/v3-live.js.map +0 -1
- package/dist-client/modeller/v3-maturity.js.map +0 -1
- package/dist-client/modeller/v3-occupancy.js.map +0 -1
- package/dist-client/modeller/v3-palette.d.ts +0 -7
- package/dist-client/modeller/v3-palette.js.map +0 -1
- package/dist-client/modeller/v3-preview-model.js.map +0 -1
- package/dist-client/modeller/v3-product-session.js.map +0 -1
- package/dist-client/modeller/v3-recipe-source.js.map +0 -1
- package/dist-client/modeller/v3-recipes.js.map +0 -1
- package/dist-client/modeller/v3-refusals.js.map +0 -1
- package/dist-client/modeller/v3-renderer.js.map +0 -1
- package/dist-client/modeller/v3-stage-model.js.map +0 -1
- package/dist-client/modeller/v3-thumbnail.d.ts +0 -3
- package/dist-client/modeller/v3-thumbnail.js.map +0 -1
- package/dist-client/pages/figure-v3-modeller-page.js.map +0 -1
- package/dist-client/tsconfig.chk.tsbuildinfo +0 -1
- package/dist-client/tsconfig.fui.tsbuildinfo +0 -1
- package/dist-client/tsconfig.scratch-fm.tsbuildinfo +0 -1
- package/docs/v3-product-cutover.md +0 -25
- package/test/v3-renderer.test.ts +0 -24
- /package/client/modeller/{v3-fields.ts → fields.ts} +0 -0
- /package/client/modeller/{v3-first-save.ts → first-save.ts} +0 -0
- /package/client/modeller/{v3-help.ts → help.ts} +0 -0
- /package/client/modeller/{v3-keys.ts → keys.ts} +0 -0
- /package/client/modeller/{v3-refusals.ts → refusals.ts} +0 -0
- /package/dist-client/modeller/{v3-fields.d.ts → fields.d.ts} +0 -0
- /package/dist-client/modeller/{v3-first-save.d.ts → first-save.d.ts} +0 -0
- /package/dist-client/modeller/{v3-help.d.ts → help.d.ts} +0 -0
- /package/dist-client/modeller/{v3-keys.d.ts → keys.d.ts} +0 -0
- /package/dist-client/modeller/{v3-refusals.d.ts → refusals.d.ts} +0 -0
|
@@ -4,41 +4,41 @@ import type { OxThreePane } from '@operato/layout'
|
|
|
4
4
|
import '@operato/layout'
|
|
5
5
|
import { customElement, property, state } from 'lit/decorators.js'
|
|
6
6
|
import { live } from 'lit/directives/live.js'
|
|
7
|
-
import { PART_LIMIT,
|
|
8
|
-
import type { RecipeTemplate } from './
|
|
9
|
-
import './figure-
|
|
10
|
-
import type {
|
|
11
|
-
import type {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import './
|
|
15
|
-
import './figure-
|
|
16
|
-
import './figure-
|
|
17
|
-
import './figure-
|
|
18
|
-
import './figure-
|
|
19
|
-
import './figure-
|
|
20
|
-
import './figure-
|
|
7
|
+
import { PART_LIMIT, parseFigureRecipe, resolveFigureRecipe, figurePartCountOf, figureRecipeIdFor } from '@hatiolab/figure-model'
|
|
8
|
+
import type { RecipeTemplate } from './recipes.js'
|
|
9
|
+
import './figure-recipe-catalog.js'
|
|
10
|
+
import type { FigureAsset, FigureAuthoringAction, FigureInputChange, FigurePartEdit, FigurePrimitiveCreation, FigureProposalStep, FigureRecipe, FigureRecipeValue } from '@hatiolab/figure-model'
|
|
11
|
+
import type { FigureProductSession } from './product-session.js'
|
|
12
|
+
import { captureFigureThumbnail } from './thumbnail.js'
|
|
13
|
+
import { drawableFigureParts } from './renderer.js'
|
|
14
|
+
import './canvas.js'
|
|
15
|
+
import './figure-parts.js'
|
|
16
|
+
import './figure-material-panel.js'
|
|
17
|
+
import './figure-links.js'
|
|
18
|
+
import './figure-controls.js'
|
|
19
|
+
import './figure-clips.js'
|
|
20
|
+
import './figure-preview.js'
|
|
21
21
|
import './figure-settings.js'
|
|
22
22
|
import { DEFAULT_VIEW, type ViewSettings } from './figure-view.js'
|
|
23
|
-
import './figure-
|
|
24
|
-
import { gizmoChanges, gizmoReachOf, keepBottomChanges, type GizmoReach, type GizmoResult } from './
|
|
25
|
-
import { keyActionOf } from './
|
|
26
|
-
import { groupFields, ownerOf, partLabelOf, repeatOf, type FieldLike, type FieldGroup } from './
|
|
23
|
+
import './figure-capability-panel.js'
|
|
24
|
+
import { gizmoChanges, gizmoReachOf, keepBottomChanges, type GizmoReach, type GizmoResult } from './gizmo.js'
|
|
25
|
+
import { keyActionOf } from './keys.js'
|
|
26
|
+
import { groupFields, ownerOf, partLabelOf, repeatOf, type FieldLike, type FieldGroup } from './fields.js'
|
|
27
27
|
import { SidePanelStyles } from './side-panel-styles.js'
|
|
28
28
|
import { ScrollbarStyles } from '@operato/styles'
|
|
29
|
-
import { alignChanges, boxOf, canMirror, mirrorChanges, type AlignTool } from './
|
|
30
|
-
import type {
|
|
31
|
-
import { paletteRecipe } from './
|
|
32
|
-
import type {
|
|
33
|
-
import { nudgeOf } from './
|
|
34
|
-
import { editRefusalOf, inDeclaredRoom, inputRangeRefusalOf, narrowingRetryOf, partRefusalOf, placementRefusalOf, recipeRefusalOf, removalNoticeOf, sizeRangeRefusalOf } from './
|
|
35
|
-
import type {
|
|
36
|
-
import type {
|
|
37
|
-
import { instanceRangeOf, instanceRangeToDeclare, proportionToFollow, rangeDiffers, rangeWith, turnsAboutAJoint, valueNow } from './
|
|
38
|
-
import { jointFanOf } from './
|
|
39
|
-
import { jointDragOf } from './
|
|
40
|
-
import type { FirstSave } from './
|
|
41
|
-
import { isLive, livePartsOf, liveOverSession, NOTHING_LIVE, scrubbed, scrubStep, type LiveValues } from './
|
|
29
|
+
import { alignChanges, boxOf, canMirror, mirrorChanges, type AlignTool } from './align.js'
|
|
30
|
+
import type { FigurePaletteKind, FigurePartRow } from './figure-parts.js'
|
|
31
|
+
import { paletteRecipe } from './palette.js'
|
|
32
|
+
import type { FigureCanvas } from './canvas.js'
|
|
33
|
+
import { nudgeOf } from './stage-model.js'
|
|
34
|
+
import { editRefusalOf, inDeclaredRoom, inputRangeRefusalOf, narrowingRetryOf, partRefusalOf, placementRefusalOf, recipeRefusalOf, removalNoticeOf, sizeRangeRefusalOf } from './refusals.js'
|
|
35
|
+
import type { FigureRenderPart } from './renderer.js'
|
|
36
|
+
import type { FigureBudgetLine } from './maturity.js'
|
|
37
|
+
import { instanceRangeOf, instanceRangeToDeclare, proportionToFollow, rangeDiffers, rangeWith, turnsAboutAJoint, valueNow } from './links.js'
|
|
38
|
+
import { jointFanOf } from './joint-fan.js'
|
|
39
|
+
import { jointDragOf } from './joint-drag.js'
|
|
40
|
+
import type { FirstSave } from './first-save.js'
|
|
41
|
+
import { isLive, livePartsOf, liveOverSession, NOTHING_LIVE, scrubbed, scrubStep, type LiveValues } from './live.js'
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -48,8 +48,8 @@ import { isLive, livePartsOf, liveOverSession, NOTHING_LIVE, scrubbed, scrubStep
|
|
|
48
48
|
type SideTab = 'properties' | 'capability' | 'motion' | 'verdict' | 'view' | 'history'
|
|
49
49
|
|
|
50
50
|
/** Product editor surface. The injected session is shared by page persistence and AI commands. */
|
|
51
|
-
@customElement('figure-
|
|
52
|
-
export class
|
|
51
|
+
@customElement('figure-editor')
|
|
52
|
+
export class FigureEditor extends LitElement {
|
|
53
53
|
/* The operato scrollbar, as every scrolling panel of the app has it -- the side panel scrolled with the browser's own. */
|
|
54
54
|
static styles = [ScrollbarStyles, SidePanelStyles, css`
|
|
55
55
|
:host {
|
|
@@ -105,7 +105,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
105
105
|
opacity: 0.38;
|
|
106
106
|
cursor: default;
|
|
107
107
|
}
|
|
108
|
-
figure-
|
|
108
|
+
figure-preview {
|
|
109
109
|
min-width: 0;
|
|
110
110
|
min-height: 0;
|
|
111
111
|
}
|
|
@@ -131,10 +131,10 @@ export class FigureV3Editor extends LitElement {
|
|
|
131
131
|
flex: 1;
|
|
132
132
|
min-height: 0;
|
|
133
133
|
}
|
|
134
|
-
figure-
|
|
134
|
+
figure-parts {
|
|
135
135
|
min-height: 0;
|
|
136
136
|
}
|
|
137
|
-
figure-
|
|
137
|
+
figure-canvas {
|
|
138
138
|
min-width: 0;
|
|
139
139
|
min-height: 0;
|
|
140
140
|
}
|
|
@@ -263,7 +263,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
263
263
|
line-height: 1.5;
|
|
264
264
|
}
|
|
265
265
|
`]
|
|
266
|
-
@property({ attribute: false }) session?:
|
|
266
|
+
@property({ attribute: false }) session?: FigureProductSession
|
|
267
267
|
/** The recipe templates (ADR-0095), read by the page from the server. */
|
|
268
268
|
@property({ attribute: false }) templates: RecipeTemplate[] = []
|
|
269
269
|
/** Reads a template's guide; given by the page. */
|
|
@@ -278,7 +278,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
278
278
|
/** The verdict's count, drawn on its tab so it stays in sight while another tab is open. */
|
|
279
279
|
@property({ type: Number }) instances?: number
|
|
280
280
|
/** The cost line the parts list shows, from the maturity report. */
|
|
281
|
-
@property({ attribute: false }) budget?:
|
|
281
|
+
@property({ attribute: false }) budget?: FigureBudgetLine
|
|
282
282
|
/**
|
|
283
283
|
* Asks the type and name of a figure saved for the first time (the host has the catalogue's names); undefined
|
|
284
284
|
* when the author cancels, and then nothing is saved. Without it a new figure is saved under a temporary type.
|
|
@@ -287,7 +287,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
287
287
|
@state() private selected = ''
|
|
288
288
|
@state() private error = ''
|
|
289
289
|
/** The same link offered again with the size range narrowed, after a link the declared range could not hold. */
|
|
290
|
-
@state() private retry?: { label: string; action?:
|
|
290
|
+
@state() private retry?: { label: string; action?: FigureAuthoringAction; run?: () => void }
|
|
291
291
|
@state() private tab: SideTab = 'properties'
|
|
292
292
|
/** The frame the bar folds - found after the first render, since the bar is drawn before it. */
|
|
293
293
|
@state() private panes?: OxThreePane
|
|
@@ -301,10 +301,10 @@ export class FigureV3Editor extends LitElement {
|
|
|
301
301
|
* How the workbench shows the figure, in the board's own state names. The viewer's, kept in
|
|
302
302
|
* their browser, never in the figure.
|
|
303
303
|
*/
|
|
304
|
-
@state() private view: ViewSettings =
|
|
304
|
+
@state() private view: ViewSettings = FigureEditor.storedView()
|
|
305
305
|
private static storedView(): ViewSettings {
|
|
306
306
|
try {
|
|
307
|
-
const stored = JSON.parse(localStorage.getItem('figure-
|
|
307
|
+
const stored = JSON.parse(localStorage.getItem('figure-view') ?? 'null')
|
|
308
308
|
return stored && typeof stored === 'object' ? { ...DEFAULT_VIEW, ...stored } : { ...DEFAULT_VIEW }
|
|
309
309
|
} catch {
|
|
310
310
|
return { ...DEFAULT_VIEW }
|
|
@@ -313,7 +313,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
313
313
|
private setView(view: ViewSettings) {
|
|
314
314
|
this.view = { ...DEFAULT_VIEW, ...view }
|
|
315
315
|
try {
|
|
316
|
-
localStorage.setItem('figure-
|
|
316
|
+
localStorage.setItem('figure-view', JSON.stringify(this.view))
|
|
317
317
|
} catch {
|
|
318
318
|
/* A browser that keeps nothing still shows the change for this visit. */
|
|
319
319
|
}
|
|
@@ -353,11 +353,11 @@ export class FigureV3Editor extends LitElement {
|
|
|
353
353
|
)}
|
|
354
354
|
</span>`
|
|
355
355
|
}
|
|
356
|
-
/** The modeller's keys (`
|
|
356
|
+
/** The modeller's keys (`keys.ts`): undo, redo, duplicate, remove, back to the whole figure, the gizmo's modes. */
|
|
357
357
|
private onKey = (e: KeyboardEvent) => {
|
|
358
358
|
const view = this.session?.read()
|
|
359
359
|
if (!view || view.loading || view.saving || !view.context || !this.isConnected) return
|
|
360
|
-
const canvas = this.renderRoot.querySelector<
|
|
360
|
+
const canvas = this.renderRoot.querySelector<FigureCanvas>('figure-canvas')
|
|
361
361
|
const path = e.composedPath()
|
|
362
362
|
const action = keyActionOf(
|
|
363
363
|
{ key: e.key, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey, altKey: e.altKey, target: path[0] as HTMLElement, inScene: !!canvas && path.includes(canvas) },
|
|
@@ -399,7 +399,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
399
399
|
}
|
|
400
400
|
/** The scene toggles: the mode already shown takes the gizmo away. */
|
|
401
401
|
private useGizmo(mode: 'translate' | 'rotate' | 'scale') {
|
|
402
|
-
this.renderRoot.querySelector<
|
|
402
|
+
this.renderRoot.querySelector<FigureCanvas>('figure-canvas')?.gizmo(mode)
|
|
403
403
|
this.gizmoMode = this.gizmoMode === mode ? undefined : mode
|
|
404
404
|
}
|
|
405
405
|
/**
|
|
@@ -425,15 +425,15 @@ export class FigureV3Editor extends LitElement {
|
|
|
425
425
|
}
|
|
426
426
|
}
|
|
427
427
|
/** What the canvas draws: the figure with the value in hand when there is one, and without the parts hidden on the workbench. */
|
|
428
|
-
private drawnParts(geometry: Parameters<typeof
|
|
429
|
-
const parts = (asset ? liveOverSession(asset as
|
|
428
|
+
private drawnParts(geometry: Parameters<typeof drawableFigureParts>[0] | undefined, asset: unknown) {
|
|
429
|
+
const parts = (asset ? liveOverSession(asset as FigureAsset, this.currentInputs(), this.live) : null) ?? drawableFigureParts(geometry ?? [])
|
|
430
430
|
return parts.filter(body => !this.hiddenParts.has(ownerOf((body as { id: string }).id)))
|
|
431
431
|
}
|
|
432
432
|
/**
|
|
433
433
|
* Where the selected part turns and how far, with the pose as it is drawn now -- a value in hand included, so the
|
|
434
|
-
* fan follows the arm while a control is dragged. Its size comes from what the joint turns (`
|
|
434
|
+
* fan follows the arm while a control is dragged. Its size comes from what the joint turns (`joint-fan`).
|
|
435
435
|
*/
|
|
436
|
-
private fanOf(asset:
|
|
436
|
+
private fanOf(asset: FigureAsset | undefined) {
|
|
437
437
|
if (!asset || !this.selected || this.hiddenParts.has(this.selected)) return null
|
|
438
438
|
try {
|
|
439
439
|
return jointFanOf(asset, this.selected, { ...this.currentInputs(), ...this.live.values })
|
|
@@ -451,12 +451,12 @@ export class FigureV3Editor extends LitElement {
|
|
|
451
451
|
return view ? Object.fromEntries(view.fields.map(field => [field.id, field.value as number])) : {}
|
|
452
452
|
}
|
|
453
453
|
/** A value in hand: an input's value (design or pose) or a part edit. Nothing is recorded. */
|
|
454
|
-
private hold(values: Record<string, number>, edit?:
|
|
454
|
+
private hold(values: Record<string, number>, edit?: FigurePartEdit) {
|
|
455
455
|
this.live = { values: { ...this.live.values, ...values }, ...(edit ? { edit } : this.live.edit ? { edit: this.live.edit } : {}) }
|
|
456
456
|
}
|
|
457
457
|
private changed() {
|
|
458
458
|
this.requestUpdate()
|
|
459
|
-
this.dispatchEvent(new CustomEvent('
|
|
459
|
+
this.dispatchEvent(new CustomEvent('changed', { bubbles: true, composed: true }))
|
|
460
460
|
}
|
|
461
461
|
private async save() {
|
|
462
462
|
if (!this.session) return
|
|
@@ -464,7 +464,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
464
464
|
/*
|
|
465
465
|
The card's picture is taken before the save starts, from a canvas of its own at the card's size —
|
|
466
466
|
not from the one on screen, which stands wherever the author left it turned. A picture that cannot
|
|
467
|
-
be taken is not an error: the save goes on without it (see `
|
|
467
|
+
be taken is not an error: the save goes on without it (see `thumbnail.ts`).
|
|
468
468
|
*/
|
|
469
469
|
let type: string | undefined
|
|
470
470
|
if (!this.session.read().id && this.firstSave) {
|
|
@@ -478,7 +478,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
478
478
|
type = answer.type
|
|
479
479
|
}
|
|
480
480
|
const view = this.session.read()
|
|
481
|
-
const thumbnail = await
|
|
481
|
+
const thumbnail = await captureFigureThumbnail(drawableFigureParts(view.geometry ?? []), view.palette ?? {})
|
|
482
482
|
const promise = this.session.save({ thumbnail, type })
|
|
483
483
|
this.changed()
|
|
484
484
|
await promise
|
|
@@ -489,7 +489,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
489
489
|
this.changed()
|
|
490
490
|
}
|
|
491
491
|
}
|
|
492
|
-
private add(kind:
|
|
492
|
+
private add(kind: FigurePaletteKind) {
|
|
493
493
|
if (!this.session) return
|
|
494
494
|
this.run(() => {
|
|
495
495
|
const ids = new Set(this.session!.read().geometry.map(g => g.id))
|
|
@@ -501,7 +501,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
501
501
|
})
|
|
502
502
|
}
|
|
503
503
|
/**
|
|
504
|
-
* The list's own operations, as
|
|
504
|
+
* The list's own operations, as part edits — each one step of the session's history. The copy and the moved
|
|
505
505
|
* part stay selected.
|
|
506
506
|
*/
|
|
507
507
|
private duplicatePart(id: string) {
|
|
@@ -545,12 +545,12 @@ export class FigureV3Editor extends LitElement {
|
|
|
545
545
|
* A recipe put in (ADR-0095): resolved on the figure as it stands -- its parts take the next free name, onto the part
|
|
546
546
|
* chosen -- and applied as one step. Refused, the kernel's sentence goes to the form as it is (condition 3).
|
|
547
547
|
*/
|
|
548
|
-
private insertRecipe(recipe:
|
|
548
|
+
private insertRecipe(recipe: FigureRecipe, values: Record<string, FigureRecipeValue>) {
|
|
549
549
|
try {
|
|
550
|
-
const asset = JSON.parse(this.session!.source()) as
|
|
551
|
-
const checked =
|
|
552
|
-
const id =
|
|
553
|
-
const steps =
|
|
550
|
+
const asset = JSON.parse(this.session!.source()) as FigureAsset
|
|
551
|
+
const checked = parseFigureRecipe(recipe)
|
|
552
|
+
const id = figureRecipeIdFor(asset, checked)
|
|
553
|
+
const steps = resolveFigureRecipe(checked, { id, ...(checked.target === 'part' ? { target: this.selected } : {}), values })
|
|
554
554
|
this.session!.applyRecipe(steps)
|
|
555
555
|
this.recipeError = ''
|
|
556
556
|
this.catalogOpen = false
|
|
@@ -583,8 +583,8 @@ export class FigureV3Editor extends LitElement {
|
|
|
583
583
|
private transformed(id: string, result: GizmoResult) {
|
|
584
584
|
const view = this.session!.read()
|
|
585
585
|
/* A part hanging from a joint: the drag edits the joint -- its value, or where it sits (ADR-0093). */
|
|
586
|
-
const asset = JSON.parse(this.session!.source()) as
|
|
587
|
-
const drawn = view.geometry.find(g => g.id === id) as unknown as
|
|
586
|
+
const asset = JSON.parse(this.session!.source()) as FigureAsset
|
|
587
|
+
const drawn = view.geometry.find(g => g.id === id) as unknown as FigureRenderPart | undefined
|
|
588
588
|
const drag = drawn ? jointDragOf(asset, ownerOf(id), drawn, result, this.currentInputs()) : null
|
|
589
589
|
if (drag) {
|
|
590
590
|
if (drag.kind === 'value') this.run(() => this.session!.apply([{ kind: 'set-state', input: drag.input, unit: drag.unit, value: drag.value }]))
|
|
@@ -618,7 +618,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
618
618
|
its rule (`nudge-part`). A part a joint or a fastening places, or a size that is worked out, is refused -- said in
|
|
619
619
|
words, not by the part silently springing back (user, 2026-09-24: 「기즈모 컨트롤도 전혀 작동이 안되는군」).
|
|
620
620
|
*/
|
|
621
|
-
const body = view.geometry.find(g => g.id === id) as unknown as
|
|
621
|
+
const body = view.geometry.find(g => g.id === id) as unknown as FigureRenderPart | undefined
|
|
622
622
|
if (!body) return this.requestUpdate()
|
|
623
623
|
const { by, turn } = nudgeOf(body, result)
|
|
624
624
|
/* A size worked out from the figure's: the drag's factor beside its rule, so it still follows. */
|
|
@@ -745,15 +745,15 @@ export class FigureV3Editor extends LitElement {
|
|
|
745
745
|
} catch {
|
|
746
746
|
dims = undefined
|
|
747
747
|
}
|
|
748
|
-
return html`<figure-
|
|
748
|
+
return html`<figure-links
|
|
749
749
|
.asset=${asset}
|
|
750
750
|
.section=${section}
|
|
751
751
|
.partId=${this.selected}
|
|
752
752
|
.dims=${dims}
|
|
753
753
|
?locked=${unavailable}
|
|
754
|
-
@
|
|
755
|
-
@
|
|
756
|
-
></figure-
|
|
754
|
+
@command=${(e: CustomEvent) => this.linkCommand(e.detail.action)}
|
|
755
|
+
@part-edit=${(e: CustomEvent) => this.run(() => this.session!.edit(e.detail.edit))}
|
|
756
|
+
></figure-links>`
|
|
757
757
|
}
|
|
758
758
|
/** The figure's controls: try a value, name it, set its range and travel time, keep the pose. */
|
|
759
759
|
private renderControls(view: { fields: Array<{ id: string; role?: string; value: number }> }, unavailable: boolean) {
|
|
@@ -764,25 +764,25 @@ export class FigureV3Editor extends LitElement {
|
|
|
764
764
|
return null
|
|
765
765
|
}
|
|
766
766
|
const values = Object.fromEntries(view.fields.filter(f => f.role === 'state').map(f => [f.id, f.value]))
|
|
767
|
-
return html`<figure-
|
|
767
|
+
return html`<figure-controls
|
|
768
768
|
.asset=${asset}
|
|
769
769
|
.values=${values}
|
|
770
770
|
?locked=${unavailable}
|
|
771
|
-
@
|
|
772
|
-
@
|
|
773
|
-
@
|
|
774
|
-
></figure-
|
|
775
|
-
<figure-
|
|
771
|
+
@state=${(e: CustomEvent) => this.run(() => this.session!.apply([{ kind: 'set-state', input: e.detail.input, unit: e.detail.unit, value: e.detail.value }]))}
|
|
772
|
+
@state-live=${(e: CustomEvent) => this.hold({ [e.detail.input]: e.detail.value })}
|
|
773
|
+
@part-edit=${(e: CustomEvent) => this.run(() => this.session!.edit(e.detail.edit))}
|
|
774
|
+
></figure-controls>
|
|
775
|
+
<figure-clips
|
|
776
776
|
.asset=${asset}
|
|
777
777
|
.values=${values}
|
|
778
778
|
?locked=${unavailable}
|
|
779
|
-
@
|
|
780
|
-
@
|
|
781
|
-
@
|
|
782
|
-
></figure-
|
|
779
|
+
@states=${(e: CustomEvent) => this.run(() => this.session!.apply(e.detail.changes))}
|
|
780
|
+
@states-live=${(e: CustomEvent) => this.hold(e.detail.values)}
|
|
781
|
+
@part-edit=${(e: CustomEvent) => this.run(() => this.session!.edit(e.detail.edit))}
|
|
782
|
+
></figure-clips>`
|
|
783
783
|
}
|
|
784
784
|
/** One command, one step of the history. A refusal a person can meet here is said in their words. */
|
|
785
|
-
private linkCommand(action:
|
|
785
|
+
private linkCommand(action: FigureAuthoringAction) {
|
|
786
786
|
this.retry = undefined
|
|
787
787
|
this.notice = ''
|
|
788
788
|
const hadSize = this.hasSize()
|
|
@@ -804,7 +804,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
804
804
|
const narrowing = narrowingRetryOf(action, error, (key, params) => i18next.t(key, params))
|
|
805
805
|
if (narrowing) {
|
|
806
806
|
this.error = narrowing.message
|
|
807
|
-
this.retry = { label: narrowing.label, action: narrowing.retry as
|
|
807
|
+
this.retry = { label: narrowing.label, action: narrowing.retry as FigureAuthoringAction }
|
|
808
808
|
return
|
|
809
809
|
}
|
|
810
810
|
this.error =
|
|
@@ -817,7 +817,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
817
817
|
this.said(error)
|
|
818
818
|
}
|
|
819
819
|
}
|
|
820
|
-
private changeField(field: { id: string; unit:
|
|
820
|
+
private changeField(field: { id: string; unit: FigureInputChange['unit']; role?: string }, event: Event) {
|
|
821
821
|
const input = event.target as HTMLInputElement,
|
|
822
822
|
value = input.valueAsNumber
|
|
823
823
|
/* A height typed in keeps the part's bottom where it is, as the scale gizmo does. */
|
|
@@ -841,7 +841,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
841
841
|
* Drag a field's label (or an axis letter) sideways to scrub its value, as vector tools do: the figure follows the
|
|
842
842
|
* pointer, and the release records one step. The field's number follows too, so the value in hand is always read.
|
|
843
843
|
*/
|
|
844
|
-
private scrub(field: { id: string; unit:
|
|
844
|
+
private scrub(field: { id: string; unit: FigureInputChange['unit']; role?: string; value: number }, down: PointerEvent, unavailable: boolean) {
|
|
845
845
|
if (unavailable || down.button !== 0) return
|
|
846
846
|
const label = down.currentTarget as HTMLElement
|
|
847
847
|
const input = (label.closest('div[cell]')?.querySelector('input') ?? label.nextElementSibling) as HTMLInputElement | null
|
|
@@ -876,7 +876,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
876
876
|
/** The measured range, kept for the revision it was measured at: measuring evaluates the figure at its edges. */
|
|
877
877
|
private range?: { at: string; of: ReturnType<typeof instanceRangeOf>; toDeclare?: ReturnType<typeof instanceRangeToDeclare> }
|
|
878
878
|
/** The sizes a board may give the figure, and the way to measure them again after its parts changed. */
|
|
879
|
-
private renderInstanceRange(asset:
|
|
879
|
+
private renderInstanceRange(asset: FigureAsset | undefined, unavailable: boolean) {
|
|
880
880
|
if (!asset) return nothing
|
|
881
881
|
/* Another figure, or another step of this one, is measured again. */
|
|
882
882
|
const at = `${this.session?.read().context ?? ''}:${this.revision}`
|
|
@@ -951,7 +951,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
951
951
|
* How the figure grows. One ratio (`sizing: 'uniform'`) is said as it is; a figure with joints that has not declared
|
|
952
952
|
* it is offered it -- a mechanism does not shear -- and the author decides (chief architect's ruling 2026-09-24).
|
|
953
953
|
*/
|
|
954
|
-
private renderSizingRule(asset:
|
|
954
|
+
private renderSizingRule(asset: FigureAsset, unavailable: boolean) {
|
|
955
955
|
if (asset.sizing === 'uniform') {
|
|
956
956
|
/* One ratio reaches only what reads the size: every other length is offered to follow it, in one step. */
|
|
957
957
|
const follow = proportionToFollow(asset)
|
|
@@ -973,8 +973,8 @@ export class FigureV3Editor extends LitElement {
|
|
|
973
973
|
* The parts list, one row per part the author made: a repeat is one row with how many copies it makes now
|
|
974
974
|
* (user, 2026-09-24: the conveyor's sixteen rollers were sixteen rows).
|
|
975
975
|
*/
|
|
976
|
-
private partRows(geometry: readonly { id: string }[]):
|
|
977
|
-
const rows = new Map<string,
|
|
976
|
+
private partRows(geometry: readonly { id: string }[]): FigurePartRow[] {
|
|
977
|
+
const rows = new Map<string, FigurePartRow>()
|
|
978
978
|
for (const g of geometry) {
|
|
979
979
|
const id = ownerOf(g.id)
|
|
980
980
|
const row = rows.get(id)
|
|
@@ -993,10 +993,10 @@ export class FigureV3Editor extends LitElement {
|
|
|
993
993
|
return [...rows.values()]
|
|
994
994
|
}
|
|
995
995
|
/** The detail level's part budget for the list's head, from figure-model's count (a repeat once). */
|
|
996
|
-
private partBudgetOf(asset:
|
|
996
|
+
private partBudgetOf(asset: FigureAsset | undefined) {
|
|
997
997
|
if (!asset) return undefined
|
|
998
998
|
try {
|
|
999
|
-
return { level: asset.detailLevel ?? null, used:
|
|
999
|
+
return { level: asset.detailLevel ?? null, used: figurePartCountOf(asset), limit: asset.detailLevel ? PART_LIMIT[asset.detailLevel] : null }
|
|
1000
1000
|
} catch {
|
|
1001
1001
|
return undefined
|
|
1002
1002
|
}
|
|
@@ -1006,7 +1006,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1006
1006
|
* The pitch of a row that fills its length is edited as a number (`set-repeat` makes it the part's own the first
|
|
1007
1007
|
* time); a row of a fixed count says its pitch cannot be set yet (figure-model refuses it the same way).
|
|
1008
1008
|
*/
|
|
1009
|
-
private renderRepeat(asset:
|
|
1009
|
+
private renderRepeat(asset: FigureAsset | undefined, geometry: readonly { id: string }[], unavailable: boolean) {
|
|
1010
1010
|
const repeat = repeatOf(this.selected, geometry)
|
|
1011
1011
|
if (!asset || !repeat || repeat.index) return nothing
|
|
1012
1012
|
/* The row is set on its part; what hangs from that part is copied with it and has no row of its own. */
|
|
@@ -1062,7 +1062,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1062
1062
|
</section>`
|
|
1063
1063
|
}
|
|
1064
1064
|
/** The design input a row's pitch is read from, when it is read from one (ADR-0096). */
|
|
1065
|
-
private pitchInputOf(asset:
|
|
1065
|
+
private pitchInputOf(asset: FigureAsset, part: string): string | undefined {
|
|
1066
1066
|
const pitch = asset.joints?.find(j => j.body1.part === part && j.repeat)?.repeat?.pitch as { from?: { of?: string; input?: string } } | number | undefined
|
|
1067
1067
|
return typeof pitch === 'object' && pitch?.from?.of === 'input' ? pitch.from.input : undefined
|
|
1068
1068
|
}
|
|
@@ -1070,7 +1070,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1070
1070
|
* 「보드에서 바꿀 수 있음」 (ADR-0096): the row's pitch made a design input the figure publishes -- a name on the board and
|
|
1071
1071
|
* a range the board's value is held to -- in one step; changed or withdrawn the same way. Only a row with a record.
|
|
1072
1072
|
*/
|
|
1073
|
-
private renderPublicPitch(asset:
|
|
1073
|
+
private renderPublicPitch(asset: FigureAsset, pitch: number, unavailable: boolean) {
|
|
1074
1074
|
const part = this.selected
|
|
1075
1075
|
if (!asset.joints?.some(j => j.body1.part === part && j.repeat)) return nothing
|
|
1076
1076
|
const from = this.pitchInputOf(asset, part)
|
|
@@ -1088,18 +1088,18 @@ export class FigureV3Editor extends LitElement {
|
|
|
1088
1088
|
const base = form ?? { part, label: '', min: 0, max: 0 }
|
|
1089
1089
|
this.publishing = { ...base, [key]: key === 'label' ? target.value : target.valueAsNumber }
|
|
1090
1090
|
}
|
|
1091
|
-
const steps = ():
|
|
1091
|
+
const steps = (): FigureProposalStep[] => {
|
|
1092
1092
|
const f = form!
|
|
1093
1093
|
const id = from ?? `${part}.pitch`
|
|
1094
|
-
if (listed) return [{ kind: 'set-input-range', input: id, min: f.min, max: f.max }, { kind: 'publish-input', input: id, label: f.label }] as
|
|
1094
|
+
if (listed) return [{ kind: 'set-input-range', input: id, min: f.min, max: f.max }, { kind: 'publish-input', input: id, label: f.label }] as FigureProposalStep[]
|
|
1095
1095
|
const exists = asset.document.model.inputs.some(i => i.id === id)
|
|
1096
1096
|
return [
|
|
1097
1097
|
...(exists ? [{ kind: 'set-input-range', input: id, min: f.min, max: f.max }] : [{ kind: 'add-design-input', id, unit: 'mm', min: f.min, max: f.max, value: pitch }]),
|
|
1098
1098
|
...(from ? [] : [{ kind: 'set-repeat', part, pitch: { from: { of: 'input', input: id } } }]),
|
|
1099
1099
|
{ kind: 'publish-input', input: id, label: f.label }
|
|
1100
|
-
] as
|
|
1100
|
+
] as FigureProposalStep[]
|
|
1101
1101
|
}
|
|
1102
|
-
const run = (list:
|
|
1102
|
+
const run = (list: FigureProposalStep[]) => {
|
|
1103
1103
|
try {
|
|
1104
1104
|
this.session!.applyRecipe(list)
|
|
1105
1105
|
this.publishing = undefined
|
|
@@ -1120,7 +1120,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1120
1120
|
(e.target as HTMLInputElement).checked
|
|
1121
1121
|
? (this.publishing = { part, label: i18next.t('figure.label.repeat-gap'), min: Math.max(1, Math.round(pitch / 2)), max: Math.round(pitch * 2) })
|
|
1122
1122
|
: listed
|
|
1123
|
-
? run([{ kind: 'unpublish-input', input: from }, { kind: 'set-repeat', part, pitch }] as
|
|
1123
|
+
? run([{ kind: 'unpublish-input', input: from }, { kind: 'set-repeat', part, pitch }] as FigureProposalStep[])
|
|
1124
1124
|
: (this.publishing = undefined)}
|
|
1125
1125
|
/>
|
|
1126
1126
|
${i18next.t('figure.label.board-sets')}
|
|
@@ -1145,7 +1145,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1145
1145
|
const pitch = input.valueAsNumber
|
|
1146
1146
|
if (!Number.isFinite(pitch) || pitch === field.value) return
|
|
1147
1147
|
/* Read from a design input the board may set: the input's value changes, the row keeps reading it (ADR-0096). */
|
|
1148
|
-
const from = this.pitchInputOf(JSON.parse(this.session!.source()) as
|
|
1148
|
+
const from = this.pitchInputOf(JSON.parse(this.session!.source()) as FigureAsset, this.selected)
|
|
1149
1149
|
if (from) {
|
|
1150
1150
|
this.run(() => this.session!.apply([{ kind: 'set-design', input: from, unit: 'mm', value: pitch }]))
|
|
1151
1151
|
input.value = String(this.session!.read().fields.find(i => i.id === from)?.value ?? field.value)
|
|
@@ -1227,7 +1227,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1227
1227
|
.pane=${this.panes}
|
|
1228
1228
|
@canvas-undo=${() => this.run(() => this.session!.undo())}
|
|
1229
1229
|
@canvas-redo=${() => this.run(() => this.session!.redo())}
|
|
1230
|
-
@canvas-fit=${() => this.renderRoot.querySelector<
|
|
1230
|
+
@canvas-fit=${() => this.renderRoot.querySelector<FigureCanvas>('figure-canvas')?.fit()}
|
|
1231
1231
|
>
|
|
1232
1232
|
${this.renderGizmoTools(!unavailable && this.middle === 'edit')}
|
|
1233
1233
|
${(['edit', 'preview'] as const).map(
|
|
@@ -1248,7 +1248,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1248
1248
|
: null}
|
|
1249
1249
|
${this.notice ? html`<div role="status" class="notice">${this.notice}</div>` : null}
|
|
1250
1250
|
${this.catalogOpen
|
|
1251
|
-
? html`<figure-
|
|
1251
|
+
? html`<figure-recipe-catalog
|
|
1252
1252
|
.templates=${this.templates}
|
|
1253
1253
|
.selected=${this.selected}
|
|
1254
1254
|
.error=${this.recipeError}
|
|
@@ -1257,15 +1257,15 @@ export class FigureV3Editor extends LitElement {
|
|
|
1257
1257
|
?locked=${unavailable}
|
|
1258
1258
|
@insert-recipe=${(e: CustomEvent) => this.insertRecipe(e.detail.recipe, e.detail.values)}
|
|
1259
1259
|
@close-catalog=${() => (this.catalogOpen = false)}
|
|
1260
|
-
></figure-
|
|
1260
|
+
></figure-recipe-catalog>`
|
|
1261
1261
|
: null}
|
|
1262
1262
|
<ox-three-pane>
|
|
1263
|
-
<figure-
|
|
1263
|
+
<figure-parts
|
|
1264
1264
|
slot="start"
|
|
1265
1265
|
.budget=${this.budget}
|
|
1266
1266
|
@show-maturity=${() => (this.tab = 'verdict')}
|
|
1267
1267
|
.parts=${this.partRows(view.geometry)}
|
|
1268
|
-
.partBudget=${this.partBudgetOf(asset as
|
|
1268
|
+
.partBudget=${this.partBudgetOf(asset as FigureAsset | undefined)}
|
|
1269
1269
|
@set-detail-level=${(e: CustomEvent) => this.linkCommand({ kind: 'set-detail-level', level: e.detail.level })}
|
|
1270
1270
|
.selected=${this.selected}
|
|
1271
1271
|
?locked=${unavailable}
|
|
@@ -1280,18 +1280,18 @@ export class FigureV3Editor extends LitElement {
|
|
|
1280
1280
|
@move-part-down=${(e: CustomEvent) => this.movePart(e.detail.id, e.detail.to)}
|
|
1281
1281
|
@duplicate-part=${(e: CustomEvent) => this.duplicatePart(e.detail.id)}
|
|
1282
1282
|
@remove-part=${(e: CustomEvent) => this.removePart(e.detail.id)}
|
|
1283
|
-
></figure-
|
|
1283
|
+
></figure-parts>
|
|
1284
1284
|
${this.middle === 'preview'
|
|
1285
|
-
? html`<figure-
|
|
1285
|
+
? html`<figure-preview
|
|
1286
1286
|
.asset=${asset}
|
|
1287
1287
|
.context=${view.context ?? ''}
|
|
1288
1288
|
.view=${this.view}
|
|
1289
|
-
@
|
|
1290
|
-
></figure-
|
|
1291
|
-
: html`<figure-
|
|
1289
|
+
@part-edit=${(e: CustomEvent) => this.run(() => this.session!.edit(e.detail.edit))}
|
|
1290
|
+
></figure-preview>`
|
|
1291
|
+
: html`<figure-canvas
|
|
1292
1292
|
.view=${this.view}
|
|
1293
1293
|
.parts=${this.drawnParts(view.geometry, asset)}
|
|
1294
|
-
.fan=${this.fanOf(asset as
|
|
1294
|
+
.fan=${this.fanOf(asset as FigureAsset | undefined)}
|
|
1295
1295
|
.palette=${view.palette ?? {}}
|
|
1296
1296
|
.context=${view.context ?? ''}
|
|
1297
1297
|
.selected=${this.selected}
|
|
@@ -1301,7 +1301,7 @@ export class FigureV3Editor extends LitElement {
|
|
|
1301
1301
|
@render-error=${(e: CustomEvent<Error>) => {
|
|
1302
1302
|
this.error = e.detail.message
|
|
1303
1303
|
}}
|
|
1304
|
-
></figure-
|
|
1304
|
+
></figure-canvas>`}
|
|
1305
1305
|
<aside slot="end">
|
|
1306
1306
|
<div tabs>
|
|
1307
1307
|
${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}
|
|
@@ -1329,30 +1329,30 @@ export class FigureV3Editor extends LitElement {
|
|
|
1329
1329
|
</div>
|
|
1330
1330
|
${this.renderRepeatNote(view.geometry)}
|
|
1331
1331
|
</section>
|
|
1332
|
-
${this.renderRepeat(asset as
|
|
1332
|
+
${this.renderRepeat(asset as FigureAsset | undefined, view.geometry, unavailable)}
|
|
1333
1333
|
${this.renderGroups(groupFields(own, this.selected), 'figure.label.group-placement-size', 'figure.label.group-shape', unavailable, this.renderTools(unavailable))}
|
|
1334
1334
|
${this.renderLinks(unavailable, 'shape')}
|
|
1335
|
-
<figure-
|
|
1335
|
+
<figure-material-panel
|
|
1336
1336
|
.body=${{ ...part, id: this.selected }}
|
|
1337
1337
|
.palette=${view.palette ?? {}}
|
|
1338
1338
|
?locked=${unavailable}
|
|
1339
|
-
@
|
|
1340
|
-
@
|
|
1341
|
-
></figure-
|
|
1339
|
+
@part-edit=${(e: CustomEvent) => this.run(() => this.session!.edit(e.detail.edit))}
|
|
1340
|
+
@part-live=${(e: CustomEvent) => this.hold({}, e.detail.edit)}
|
|
1341
|
+
></figure-material-panel>`
|
|
1342
1342
|
: html`<slot name="figure"></slot>
|
|
1343
1343
|
${this.renderGroups(groupFields(common), 'figure.label.group-figure-size', 'figure.label.design-inputs', unavailable)}
|
|
1344
|
-
${this.renderInstanceRange(asset as
|
|
1344
|
+
${this.renderInstanceRange(asset as FigureAsset | undefined, unavailable)}`}
|
|
1345
1345
|
</div>
|
|
1346
1346
|
<div panel ?off=${tab !== 'capability'}>
|
|
1347
1347
|
${this.renderSubject()}
|
|
1348
1348
|
${this.selected && part ? this.renderLinks(unavailable, 'places') : null}
|
|
1349
|
-
<figure-
|
|
1349
|
+
<figure-capability-panel
|
|
1350
1350
|
.asset=${asset}
|
|
1351
1351
|
.selected=${this.selected}
|
|
1352
1352
|
?locked=${unavailable}
|
|
1353
1353
|
@select-part=${(e: CustomEvent) => this.choose(e.detail.id)}
|
|
1354
|
-
@
|
|
1355
|
-
></figure-
|
|
1354
|
+
@part-edit=${(e: CustomEvent) => this.run(() => this.session!.edit(e.detail.edit))}
|
|
1355
|
+
></figure-capability-panel>
|
|
1356
1356
|
</div>
|
|
1357
1357
|
<div panel ?off=${tab !== 'motion'}>
|
|
1358
1358
|
${this.renderSubject()}
|
|
@@ -3,8 +3,8 @@ import { customElement, property } from 'lit/decorators.js'
|
|
|
3
3
|
import { live } from 'lit/directives/live.js'
|
|
4
4
|
|
|
5
5
|
import { i18next, localize } from '@operato/i18n'
|
|
6
|
-
import {
|
|
7
|
-
import type { FigureCapability,
|
|
6
|
+
import { figureBindingsOf } from '@hatiolab/figure-model'
|
|
7
|
+
import type { FigureCapability, FigureAsset } from '@hatiolab/figure-model'
|
|
8
8
|
import { SidePanelStyles } from './side-panel-styles.js'
|
|
9
9
|
|
|
10
10
|
/*
|
|
@@ -32,8 +32,8 @@ export function rungOf(names: readonly string[] | undefined): Rung | null {
|
|
|
32
32
|
* holding things, to passing them on, and every place things are held, whatever part it is on. A place is not drawn,
|
|
33
33
|
* so the list is the only way to find one; choosing a row selects its part, where the place is edited.
|
|
34
34
|
*/
|
|
35
|
-
@customElement('figure-
|
|
36
|
-
export class
|
|
35
|
+
@customElement('figure-capability-panel')
|
|
36
|
+
export class FigureCapabilityPanel extends localize(i18next)(LitElement) {
|
|
37
37
|
static styles = [SidePanelStyles, css`
|
|
38
38
|
:host {
|
|
39
39
|
display: block;
|
|
@@ -84,7 +84,7 @@ export class FigureV3Capability extends localize(i18next)(LitElement) {
|
|
|
84
84
|
}
|
|
85
85
|
`]
|
|
86
86
|
|
|
87
|
-
@property({ attribute: false }) asset?:
|
|
87
|
+
@property({ attribute: false }) asset?: FigureAsset
|
|
88
88
|
/** The selected part, whose places are marked. */
|
|
89
89
|
@property() selected = ''
|
|
90
90
|
@property({ type: Boolean }) locked = false
|
|
@@ -94,7 +94,7 @@ export class FigureV3Capability extends localize(i18next)(LitElement) {
|
|
|
94
94
|
if (!asset) return nothing
|
|
95
95
|
const names = asset.document.capabilities.names ?? []
|
|
96
96
|
const rung = rungOf(names)
|
|
97
|
-
const places =
|
|
97
|
+
const places = figureBindingsOf(asset)
|
|
98
98
|
return html`<section>
|
|
99
99
|
<h3>${i18next.t('figure.label.what-this-does')}</h3>
|
|
100
100
|
${(['none', 'hold', 'flow'] as const).map(
|
|
@@ -128,7 +128,7 @@ export class FigureV3Capability extends localize(i18next)(LitElement) {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
private setRung(which: Rung) {
|
|
131
|
-
this.dispatchEvent(new CustomEvent('
|
|
131
|
+
this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which]] } }, bubbles: true, composed: true }))
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
private pick(part: string) {
|