@things-factory/figure-ui 10.1.46 → 10.1.48
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/modeller/angle-dial.ts +70 -0
- package/client/modeller/figure-settings.ts +328 -0
- package/client/modeller/figure-v3-capability.ts +137 -0
- package/client/modeller/figure-v3-clips.ts +253 -0
- package/client/modeller/figure-v3-controls.ts +212 -0
- package/client/modeller/figure-v3-links.ts +61 -81
- package/client/modeller/figure-v3-material.ts +108 -35
- package/client/modeller/figure-v3-parts.ts +96 -3
- package/client/modeller/figure-v3-preview.ts +326 -0
- package/client/modeller/figure-v3-properties.ts +29 -57
- package/client/modeller/figure-v3-verdict.ts +598 -60
- package/client/modeller/figure-view.ts +152 -0
- package/client/modeller/side-panel-styles.ts +326 -0
- package/client/modeller/v3-canvas.ts +254 -262
- package/client/modeller/v3-clips.ts +89 -0
- package/client/modeller/v3-controls.ts +54 -0
- package/client/modeller/v3-editor.ts +566 -223
- package/client/modeller/v3-fields.ts +84 -0
- package/client/modeller/v3-help.ts +41 -0
- package/client/modeller/v3-joint-fan.ts +292 -0
- package/client/modeller/v3-keys.ts +34 -0
- package/client/modeller/v3-links.ts +101 -9
- package/client/modeller/v3-live.ts +79 -0
- package/client/modeller/v3-maturity.ts +415 -0
- package/client/modeller/v3-palette.ts +45 -0
- package/client/modeller/v3-preview-model.ts +54 -0
- package/client/modeller/v3-stage-model.ts +159 -0
- package/client/modeller/v3-thumbnail.ts +8 -4
- package/client/pages/figure-list-page.ts +4 -4
- package/client/pages/figure-v3-modeller-page.ts +66 -134
- package/dist-client/modeller/angle-dial.d.ts +32 -0
- package/dist-client/modeller/angle-dial.js +41 -0
- package/dist-client/modeller/angle-dial.js.map +1 -0
- package/dist-client/modeller/figure-settings.d.ts +39 -0
- package/dist-client/modeller/figure-settings.js +317 -0
- package/dist-client/modeller/figure-settings.js.map +1 -0
- package/dist-client/modeller/figure-v3-capability.d.ts +22 -0
- package/dist-client/modeller/figure-v3-capability.js +141 -0
- package/dist-client/modeller/figure-v3-capability.js.map +1 -0
- package/dist-client/modeller/figure-v3-clips.d.ts +31 -0
- package/dist-client/modeller/figure-v3-clips.js +268 -0
- package/dist-client/modeller/figure-v3-clips.js.map +1 -0
- package/dist-client/modeller/figure-v3-controls.d.ts +36 -0
- package/dist-client/modeller/figure-v3-controls.js +226 -0
- package/dist-client/modeller/figure-v3-controls.js.map +1 -0
- package/dist-client/modeller/figure-v3-links.d.ts +4 -1
- package/dist-client/modeller/figure-v3-links.js +64 -82
- package/dist-client/modeller/figure-v3-links.js.map +1 -1
- package/dist-client/modeller/figure-v3-material.d.ts +4 -1
- package/dist-client/modeller/figure-v3-material.js +109 -35
- package/dist-client/modeller/figure-v3-material.js.map +1 -1
- package/dist-client/modeller/figure-v3-parts.d.ts +10 -0
- package/dist-client/modeller/figure-v3-parts.js +88 -3
- package/dist-client/modeller/figure-v3-parts.js.map +1 -1
- package/dist-client/modeller/figure-v3-preview.d.ts +34 -0
- package/dist-client/modeller/figure-v3-preview.js +322 -0
- package/dist-client/modeller/figure-v3-preview.js.map +1 -0
- package/dist-client/modeller/figure-v3-properties.d.ts +1 -1
- package/dist-client/modeller/figure-v3-properties.js +29 -57
- package/dist-client/modeller/figure-v3-properties.js.map +1 -1
- package/dist-client/modeller/figure-v3-verdict.d.ts +31 -17
- package/dist-client/modeller/figure-v3-verdict.js +579 -59
- package/dist-client/modeller/figure-v3-verdict.js.map +1 -1
- package/dist-client/modeller/figure-view.d.ts +118 -0
- package/dist-client/modeller/figure-view.js +78 -0
- package/dist-client/modeller/figure-view.js.map +1 -0
- package/dist-client/modeller/side-panel-styles.d.ts +23 -0
- package/dist-client/modeller/side-panel-styles.js +326 -0
- package/dist-client/modeller/side-panel-styles.js.map +1 -0
- package/dist-client/modeller/v3-canvas.d.ts +44 -37
- package/dist-client/modeller/v3-canvas.js +230 -260
- package/dist-client/modeller/v3-canvas.js.map +1 -1
- package/dist-client/modeller/v3-clips.d.ts +39 -0
- package/dist-client/modeller/v3-clips.js +58 -0
- package/dist-client/modeller/v3-clips.js.map +1 -0
- package/dist-client/modeller/v3-controls.d.ts +28 -0
- package/dist-client/modeller/v3-controls.js +28 -0
- package/dist-client/modeller/v3-controls.js.map +1 -0
- package/dist-client/modeller/v3-editor.d.ts +73 -1
- package/dist-client/modeller/v3-editor.js +593 -218
- package/dist-client/modeller/v3-editor.js.map +1 -1
- package/dist-client/modeller/v3-fields.d.ts +39 -0
- package/dist-client/modeller/v3-fields.js +69 -0
- package/dist-client/modeller/v3-fields.js.map +1 -0
- package/dist-client/modeller/v3-help.d.ts +18 -0
- package/dist-client/modeller/v3-help.js +37 -0
- package/dist-client/modeller/v3-help.js.map +1 -0
- package/dist-client/modeller/v3-joint-fan.d.ts +9 -0
- package/dist-client/modeller/v3-joint-fan.js +264 -0
- package/dist-client/modeller/v3-joint-fan.js.map +1 -0
- package/dist-client/modeller/v3-keys.d.ts +14 -0
- package/dist-client/modeller/v3-keys.js +23 -0
- package/dist-client/modeller/v3-keys.js.map +1 -0
- package/dist-client/modeller/v3-links.d.ts +35 -1
- package/dist-client/modeller/v3-links.js +101 -8
- package/dist-client/modeller/v3-links.js.map +1 -1
- package/dist-client/modeller/v3-live.d.ts +31 -0
- package/dist-client/modeller/v3-live.js +58 -0
- package/dist-client/modeller/v3-live.js.map +1 -0
- package/dist-client/modeller/v3-maturity.d.ts +120 -0
- package/dist-client/modeller/v3-maturity.js +317 -0
- package/dist-client/modeller/v3-maturity.js.map +1 -0
- package/dist-client/modeller/v3-palette.d.ts +7 -0
- package/dist-client/modeller/v3-palette.js +42 -0
- package/dist-client/modeller/v3-palette.js.map +1 -0
- package/dist-client/modeller/v3-preview-model.d.ts +32 -0
- package/dist-client/modeller/v3-preview-model.js +48 -0
- package/dist-client/modeller/v3-preview-model.js.map +1 -0
- package/dist-client/modeller/v3-stage-model.d.ts +31 -0
- package/dist-client/modeller/v3-stage-model.js +121 -0
- package/dist-client/modeller/v3-stage-model.js.map +1 -0
- package/dist-client/modeller/v3-thumbnail.js +6 -3
- package/dist-client/modeller/v3-thumbnail.js.map +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 +2 -6
- package/dist-client/pages/figure-v3-modeller-page.js +64 -136
- package/dist-client/pages/figure-v3-modeller-page.js.map +1 -1
- package/dist-client/tsconfig.chk.tsbuildinfo +1 -0
- package/dist-client/tsconfig.scratch-fm.tsbuildinfo +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/test/v3-clips.test.ts +70 -0
- package/test/v3-controls.test.ts +68 -0
- package/test/v3-fields.test.ts +71 -0
- package/test/v3-gizmo.test.ts +3 -5
- package/test/v3-joint-fan.test.ts +210 -0
- package/test/v3-keys.test.ts +37 -0
- package/test/v3-layout.test.ts +78 -0
- package/test/v3-links.test.ts +89 -6
- package/test/v3-live.test.ts +99 -0
- package/test/v3-material.test.ts +6 -0
- package/test/v3-maturity.test.ts +268 -0
- package/test/v3-palette-icons.test.ts +22 -0
- package/test/v3-parts-wiring.test.ts +3 -1
- package/test/v3-preview.test.ts +42 -0
- package/test/v3-properties.test.ts +4 -2
- package/test/v3-scene-canvas.test.ts +85 -0
- package/test/v3-stage-model.test.ts +25 -0
- package/test/v3-theme.test.ts +16 -25
- package/test/v3-thumbnail.test.ts +29 -0
- package/test/v3-verdict.test.ts +12 -6
- package/test/v3-view.test.ts +20 -0
- package/translations/en.json +90 -6
- package/translations/ja.json +92 -8
- package/translations/ko.json +90 -6
- package/translations/ms.json +92 -8
- package/translations/zh.json +92 -8
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import type { V3Asset } from '@hatiolab/figure-model';
|
|
3
|
+
import { type ViewSettings } from './figure-view.js';
|
|
4
|
+
declare const FigureV3Preview_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
5
|
+
export declare class FigureV3Preview extends FigureV3Preview_base {
|
|
6
|
+
static styles: import("lit").CSSResult;
|
|
7
|
+
/** The figure being authored, as the editor holds it now. */
|
|
8
|
+
asset?: V3Asset;
|
|
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,322 @@
|
|
|
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 { compileV3Asset } from '@hatiolab/figure-model';
|
|
6
|
+
import { create, registerFigureV3, unregisterFigureV3 } 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, previewInstances } from './v3-preview-model.js';
|
|
10
|
+
let FigureV3Preview = class FigureV3Preview 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
|
+
}
|
|
50
|
+
div[clips] {
|
|
51
|
+
position: absolute;
|
|
52
|
+
right: 8px;
|
|
53
|
+
bottom: 8px;
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
gap: 6px;
|
|
57
|
+
padding: 8px 10px;
|
|
58
|
+
color: rgba(255, 255, 255, 0.92);
|
|
59
|
+
background-color: rgba(28, 28, 30, 0.72);
|
|
60
|
+
border-radius: 8px;
|
|
61
|
+
font-size: 0.72rem;
|
|
62
|
+
}
|
|
63
|
+
div[clips] label {
|
|
64
|
+
display: grid;
|
|
65
|
+
grid-template-columns: auto 20px 96px 34px;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 8px;
|
|
68
|
+
}
|
|
69
|
+
div[clips] svg[dial] {
|
|
70
|
+
width: 20px;
|
|
71
|
+
height: 20px;
|
|
72
|
+
}
|
|
73
|
+
div[clips] svg[dial] path {
|
|
74
|
+
fill: rgba(255, 255, 255, 0.22);
|
|
75
|
+
}
|
|
76
|
+
div[clips] svg[dial] line {
|
|
77
|
+
stroke: var(--md-sys-color-primary, #7cc6ff);
|
|
78
|
+
stroke-width: 2;
|
|
79
|
+
stroke-linecap: round;
|
|
80
|
+
}
|
|
81
|
+
div[clips] svg[dial] circle {
|
|
82
|
+
fill: none;
|
|
83
|
+
stroke: rgba(255, 255, 255, 0.35);
|
|
84
|
+
}
|
|
85
|
+
div[clips] button[pose] {
|
|
86
|
+
align-self: stretch;
|
|
87
|
+
padding: 4px 8px;
|
|
88
|
+
font: inherit;
|
|
89
|
+
font-size: 0.7rem;
|
|
90
|
+
color: rgba(255, 255, 255, 0.92);
|
|
91
|
+
background-color: rgba(255, 255, 255, 0.14);
|
|
92
|
+
border: 1px solid rgba(255, 255, 255, 0.22);
|
|
93
|
+
border-radius: 5px;
|
|
94
|
+
cursor: pointer;
|
|
95
|
+
}
|
|
96
|
+
div[clips] button[pose]:hover {
|
|
97
|
+
background-color: rgba(255, 255, 255, 0.24);
|
|
98
|
+
}
|
|
99
|
+
div[clips] span[drive] {
|
|
100
|
+
opacity: 0.6;
|
|
101
|
+
font-size: 0.66rem;
|
|
102
|
+
}
|
|
103
|
+
div[clips] input {
|
|
104
|
+
width: 96px;
|
|
105
|
+
accent-color: var(--md-sys-color-primary);
|
|
106
|
+
}
|
|
107
|
+
div[clips] output {
|
|
108
|
+
font-variant-numeric: tabular-nums;
|
|
109
|
+
text-align: right;
|
|
110
|
+
opacity: 0.85;
|
|
111
|
+
}
|
|
112
|
+
div[cannot] {
|
|
113
|
+
position: absolute;
|
|
114
|
+
inset: 0;
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
padding: 12px;
|
|
119
|
+
text-align: center;
|
|
120
|
+
line-height: 1.6;
|
|
121
|
+
color: #f4f4f4;
|
|
122
|
+
background-color: ${unsafeCSS(WORKBENCH)};
|
|
123
|
+
}
|
|
124
|
+
`; }
|
|
125
|
+
render() {
|
|
126
|
+
const asset = this.asset;
|
|
127
|
+
const controls = asset ? asset.document.model.inputs.filter(i => i.role === 'state') : [];
|
|
128
|
+
const clips = asset ? [...new Set((asset.drivers ?? []).map(d => d.clip))] : [];
|
|
129
|
+
return html `<div stage></div>
|
|
130
|
+
${this.cannot
|
|
131
|
+
? html `<div cannot>${this.cannot}</div>`
|
|
132
|
+
: html `<div legend>${PREVIEW_WAYS.map(way => html `<span>${way.axes.length ? way.name : i18next.t('figure.label.preview-base')}</span>`)}</div>
|
|
133
|
+
${controls.length + clips.length ? this.renderDrivers(asset, controls, clips) : nothing}`}`;
|
|
134
|
+
}
|
|
135
|
+
renderDrivers(asset, controls, clips) {
|
|
136
|
+
const changed = controls.filter(c => this.giving[c.id] !== undefined && this.giving[c.id] !== asset.stateDefaults[c.id]);
|
|
137
|
+
return html `<div clips>
|
|
138
|
+
${changed.length
|
|
139
|
+
? html `<button pose title=${i18next.t('figure.text.pose-as-default-explained')} @click=${() => this.poseAsDefault()}>
|
|
140
|
+
${i18next.t('figure.button.pose-as-default')}
|
|
141
|
+
</button>`
|
|
142
|
+
: nothing}
|
|
143
|
+
${controls.map(control => {
|
|
144
|
+
const value = this.giving[control.id] ?? asset.stateDefaults[control.id] ?? control.min;
|
|
145
|
+
const step = Math.max((control.max - control.min) / 100, 0.01);
|
|
146
|
+
const label = asset.stateInputs?.[control.id]?.label ?? control.id;
|
|
147
|
+
return html `<label>
|
|
148
|
+
<span>${label} <span drive>${control.unit}</span></span>
|
|
149
|
+
${this.renderDial(control, value)}
|
|
150
|
+
<input
|
|
151
|
+
type="range"
|
|
152
|
+
min=${control.min}
|
|
153
|
+
max=${control.max}
|
|
154
|
+
step=${step}
|
|
155
|
+
.value=${String(value)}
|
|
156
|
+
@input=${(e) => this.give(control.id, Number(e.target.value))}
|
|
157
|
+
/>
|
|
158
|
+
<output>${Math.round(value)}</output>
|
|
159
|
+
</label>`;
|
|
160
|
+
})}
|
|
161
|
+
${clips.map(clip => {
|
|
162
|
+
const value = this.driving[clip] ?? 1;
|
|
163
|
+
return html `<label>
|
|
164
|
+
<span>${clip} <span drive>${i18next.t('figure.label.playback-speed')}</span></span>
|
|
165
|
+
<span></span>
|
|
166
|
+
<input type="range" min="0" max="3" step="0.05" .value=${String(value)} @input=${(e) => this.drive(clip, Number(e.target.value))} />
|
|
167
|
+
<output>${value.toFixed(2)}</output>
|
|
168
|
+
</label>`;
|
|
169
|
+
})}
|
|
170
|
+
</div>`;
|
|
171
|
+
}
|
|
172
|
+
renderDial(control, value) {
|
|
173
|
+
if (control.unit !== 'deg')
|
|
174
|
+
return html `<span></span>`;
|
|
175
|
+
const dial = dialShape(control.min, control.max, value);
|
|
176
|
+
const span = dial.radius * 2 + 2;
|
|
177
|
+
return html `<svg dial viewBox="0 0 ${span} ${span}" aria-hidden="true">
|
|
178
|
+
<path d=${dial.sector}></path>
|
|
179
|
+
<circle cx=${dial.centre.x} cy=${dial.centre.y} r=${dial.radius}></circle>
|
|
180
|
+
<line x1=${dial.centre.x} y1=${dial.centre.y} x2=${dial.needle.x} y2=${dial.needle.y}></line>
|
|
181
|
+
</svg>`;
|
|
182
|
+
}
|
|
183
|
+
drive(clip, value) {
|
|
184
|
+
this.driving = { ...this.driving, [clip]: value };
|
|
185
|
+
this.tellInstances('clips', this.driving);
|
|
186
|
+
}
|
|
187
|
+
give(id, value) {
|
|
188
|
+
this.giving = { ...this.giving, [id]: value };
|
|
189
|
+
this.tellInstances('parameters', this.giving);
|
|
190
|
+
}
|
|
191
|
+
poseAsDefault() {
|
|
192
|
+
this.dispatchEvent(new CustomEvent('v3-part-edit', { detail: { edit: { kind: 'set-state-defaults', values: { ...this.giving } } }, bubbles: true, composed: true }));
|
|
193
|
+
this.giving = {};
|
|
194
|
+
}
|
|
195
|
+
tellInstances(key, values) {
|
|
196
|
+
for (const component of this.scene?.root?.components ?? [])
|
|
197
|
+
component.set?.(key, { ...values });
|
|
198
|
+
}
|
|
199
|
+
willUpdate(changed) {
|
|
200
|
+
if (!this.hasUpdated)
|
|
201
|
+
return;
|
|
202
|
+
if (changed.has('asset') || changed.has('context')) {
|
|
203
|
+
this.standUp();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (!changed.has('view'))
|
|
207
|
+
return;
|
|
208
|
+
const before = changed.get('view');
|
|
209
|
+
const now = this.view ?? DEFAULT_VIEW;
|
|
210
|
+
if (before?.placement !== now.placement || before?.ceilingHeight !== now.ceilingHeight)
|
|
211
|
+
this.standUp();
|
|
212
|
+
else
|
|
213
|
+
this.scene?.root?.set?.(sceneLook(now));
|
|
214
|
+
}
|
|
215
|
+
firstUpdated() {
|
|
216
|
+
this.standUp();
|
|
217
|
+
this.watcher = new ResizeObserver(() => this.scene?.resize?.());
|
|
218
|
+
this.watcher.observe(this);
|
|
219
|
+
}
|
|
220
|
+
disconnectedCallback() {
|
|
221
|
+
super.disconnectedCallback();
|
|
222
|
+
this.watcher?.disconnect();
|
|
223
|
+
this.watcher = undefined;
|
|
224
|
+
this.teardown();
|
|
225
|
+
}
|
|
226
|
+
standUp() {
|
|
227
|
+
const asset = this.asset;
|
|
228
|
+
const view = this.view ?? DEFAULT_VIEW;
|
|
229
|
+
if (!asset || !asset.appearance.length) {
|
|
230
|
+
this.cannot = i18next.t('figure.text.preview-needs-a-part');
|
|
231
|
+
this.teardown();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const signature = JSON.stringify([asset, view.placement, view.ceilingHeight]);
|
|
235
|
+
if (this.scene && this.standing === signature)
|
|
236
|
+
return;
|
|
237
|
+
try {
|
|
238
|
+
compileV3Asset(asset);
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
this.cannot = i18next.t('figure.text.preview-blocked-by-errors');
|
|
242
|
+
this.teardown();
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.teardown();
|
|
246
|
+
this.driving = {};
|
|
247
|
+
try {
|
|
248
|
+
/* Registered as a board registers it, under a type of this preview's own: a real type's drawings stay as they are. */
|
|
249
|
+
const type = `figure-v3-preview-${this.context || 'new'}`;
|
|
250
|
+
registerFigureV3(type, asset);
|
|
251
|
+
this.registered = type;
|
|
252
|
+
const size = authoredSizeOf(asset);
|
|
253
|
+
const { components, board } = previewInstances(type, size);
|
|
254
|
+
this.scene = create({
|
|
255
|
+
target: this.stage,
|
|
256
|
+
model: {
|
|
257
|
+
type: 'model-layer',
|
|
258
|
+
width: board.width,
|
|
259
|
+
height: board.height,
|
|
260
|
+
depth: previewBoardDepth({ placement: asset.occupancy?.placement, base: { y: size.y } }, view.ceilingHeight, PREVIEW_FACTOR),
|
|
261
|
+
threed: true,
|
|
262
|
+
sky: 'color',
|
|
263
|
+
...sceneLook(view),
|
|
264
|
+
placement: view.placement,
|
|
265
|
+
heights: { floor: 0, ceiling: view.ceilingHeight },
|
|
266
|
+
pixelRatio: Math.min(3, (window.devicePixelRatio || 1) * 2),
|
|
267
|
+
components
|
|
268
|
+
},
|
|
269
|
+
mode: 0
|
|
270
|
+
});
|
|
271
|
+
this.standing = signature;
|
|
272
|
+
this.scene.resize?.();
|
|
273
|
+
this.scene.fit?.('ratio');
|
|
274
|
+
this.scene.root?.fitCameraToModel?.();
|
|
275
|
+
this.cannot = '';
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
this.cannot = error.message;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
teardown() {
|
|
282
|
+
this.scene?.dispose?.();
|
|
283
|
+
this.scene = undefined;
|
|
284
|
+
this.standing = undefined;
|
|
285
|
+
if (this.registered)
|
|
286
|
+
unregisterFigureV3(this.registered);
|
|
287
|
+
this.registered = undefined;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
__decorate([
|
|
291
|
+
property({ attribute: false }),
|
|
292
|
+
__metadata("design:type", Object)
|
|
293
|
+
], FigureV3Preview.prototype, "asset", void 0);
|
|
294
|
+
__decorate([
|
|
295
|
+
property(),
|
|
296
|
+
__metadata("design:type", Object)
|
|
297
|
+
], FigureV3Preview.prototype, "context", void 0);
|
|
298
|
+
__decorate([
|
|
299
|
+
property({ attribute: false }),
|
|
300
|
+
__metadata("design:type", Object)
|
|
301
|
+
], FigureV3Preview.prototype, "view", void 0);
|
|
302
|
+
__decorate([
|
|
303
|
+
query('div[stage]'),
|
|
304
|
+
__metadata("design:type", HTMLDivElement)
|
|
305
|
+
], FigureV3Preview.prototype, "stage", void 0);
|
|
306
|
+
__decorate([
|
|
307
|
+
state(),
|
|
308
|
+
__metadata("design:type", Object)
|
|
309
|
+
], FigureV3Preview.prototype, "cannot", void 0);
|
|
310
|
+
__decorate([
|
|
311
|
+
state(),
|
|
312
|
+
__metadata("design:type", Object)
|
|
313
|
+
], FigureV3Preview.prototype, "driving", void 0);
|
|
314
|
+
__decorate([
|
|
315
|
+
state(),
|
|
316
|
+
__metadata("design:type", Object)
|
|
317
|
+
], FigureV3Preview.prototype, "giving", void 0);
|
|
318
|
+
FigureV3Preview = __decorate([
|
|
319
|
+
customElement('figure-v3-preview')
|
|
320
|
+
], FigureV3Preview);
|
|
321
|
+
export { FigureV3Preview };
|
|
322
|
+
//# sourceMappingURL=figure-v3-preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-v3-preview.js","sourceRoot":"","sources":["../../client/modeller/figure-v3-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 { compileV3Asset } from '@hatiolab/figure-model'\nimport type { V3Asset } from '@hatiolab/figure-model'\nimport { create, registerFigureV3, unregisterFigureV3 } 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, previewInstances } from './v3-preview-model.js'\n\n/**\n * The figure placed on a board -- V2's preview, for a V3 figure.\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 (V2's eight). The board draws them as it will on a real board --\n * placement, lights, environment, the same V3 renderer.\n *\n * The controls are V2's too: 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-v3-preview')\nexport class FigureV3Preview 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 }\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?: V3Asset\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 return html`<div stage></div>\n ${this.cannot\n ? html`<div cannot>${this.cannot}</div>`\n : html`<div legend>${PREVIEW_WAYS.map(way => html`<span>${way.axes.length ? way.name : i18next.t('figure.label.preview-base')}</span>`)}</div>\n ${controls.length + clips.length ? this.renderDrivers(asset!, controls, clips) : nothing}`}`\n }\n\n private renderDrivers(asset: V3Asset, controls: V3Asset['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('v3-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 compileV3Asset(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-v3-preview-${this.context || 'new'}`\n registerFigureV3(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) unregisterFigureV3(this.registered)\n this.registered = undefined\n }\n}\n"]}
|
|
@@ -18,7 +18,7 @@ declare const FigureV3Properties_base: (new (...args: any[]) => LitElement) & ty
|
|
|
18
18
|
* parts, as graph expressions), and the detail level (the converter records it as lost). Both wait on a V3 ruling.
|
|
19
19
|
*/
|
|
20
20
|
export declare class FigureV3Properties extends FigureV3Properties_base {
|
|
21
|
-
static styles: import("lit").CSSResult;
|
|
21
|
+
static styles: import("lit").CSSResult[];
|
|
22
22
|
/** The source being edited. */
|
|
23
23
|
source?: string;
|
|
24
24
|
/** The saved row, if any. Category and tags live on it. */
|
|
@@ -6,6 +6,7 @@ import { i18next, localize } from '@operato/i18n';
|
|
|
6
6
|
import { V3_FACES } from '@hatiolab/figure-model';
|
|
7
7
|
import { occupancyFromParts } from './v3-occupancy.js';
|
|
8
8
|
import { tagsOf, v3FigureFacts } from './v3-figure-facts.js';
|
|
9
|
+
import { SidePanelStyles } from './side-panel-styles.js';
|
|
9
10
|
const PLACEMENTS = ['floor', 'ceiling', 'center'];
|
|
10
11
|
const FACES = Object.keys(V3_FACES);
|
|
11
12
|
/**
|
|
@@ -25,71 +26,30 @@ const FACES = Object.keys(V3_FACES);
|
|
|
25
26
|
* parts, as graph expressions), and the detail level (the converter records it as lost). Both wait on a V3 ruling.
|
|
26
27
|
*/
|
|
27
28
|
let FigureV3Properties = class FigureV3Properties extends localize(i18next)(LitElement) {
|
|
28
|
-
static { this.styles = css `
|
|
29
|
+
static { this.styles = [SidePanelStyles, css `
|
|
29
30
|
:host {
|
|
30
|
-
display:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
padding: 12px;
|
|
31
|
+
display: block;
|
|
32
|
+
/* It stands inside the properties tab's panel, which gives the margin; a second one indented it past the type. */
|
|
33
|
+
padding: 0;
|
|
34
34
|
overflow: auto;
|
|
35
|
-
font-size: 0.76rem;
|
|
36
|
-
color: var(--md-sys-color-on-surface);
|
|
37
|
-
}
|
|
38
|
-
div[field] {
|
|
39
|
-
display: grid;
|
|
40
|
-
gap: 4px;
|
|
41
|
-
}
|
|
42
|
-
div[field] > label {
|
|
43
|
-
font-weight: 600;
|
|
44
35
|
}
|
|
45
36
|
div[row] {
|
|
46
37
|
display: flex;
|
|
47
38
|
gap: 6px;
|
|
48
39
|
align-items: center;
|
|
49
40
|
}
|
|
50
|
-
input,
|
|
51
|
-
select,
|
|
52
|
-
button {
|
|
53
|
-
font: inherit;
|
|
54
|
-
min-width: 0;
|
|
55
|
-
}
|
|
56
|
-
input,
|
|
57
|
-
select {
|
|
58
|
-
padding: 5px 8px;
|
|
59
|
-
border: 1px solid var(--md-sys-color-outline-variant);
|
|
60
|
-
border-radius: 4px;
|
|
61
|
-
background: var(--md-sys-color-surface);
|
|
62
|
-
color: var(--md-sys-color-on-surface);
|
|
63
|
-
}
|
|
64
41
|
div[row] > select {
|
|
65
42
|
flex: 1;
|
|
66
43
|
}
|
|
67
|
-
button {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
padding: 4px 10px;
|
|
72
|
-
border: none;
|
|
73
|
-
border-radius: 999em;
|
|
74
|
-
cursor: pointer;
|
|
75
|
-
color: var(--md-sys-color-on-secondary-container);
|
|
76
|
-
background: var(--md-sys-color-secondary-container);
|
|
77
|
-
}
|
|
78
|
-
button:disabled,
|
|
79
|
-
input:disabled,
|
|
80
|
-
select:disabled {
|
|
81
|
-
opacity: 0.5;
|
|
82
|
-
cursor: default;
|
|
83
|
-
}
|
|
84
|
-
button md-icon {
|
|
85
|
-
font-size: 16px;
|
|
86
|
-
width: 16px;
|
|
87
|
-
height: 16px;
|
|
44
|
+
div[row] > button[act] {
|
|
45
|
+
flex: 1;
|
|
46
|
+
width: auto;
|
|
47
|
+
margin-top: 0;
|
|
88
48
|
}
|
|
89
|
-
|
|
90
|
-
|
|
49
|
+
div[row] > span {
|
|
50
|
+
flex: 1;
|
|
91
51
|
}
|
|
92
|
-
|
|
52
|
+
`]; }
|
|
93
53
|
facts() {
|
|
94
54
|
try {
|
|
95
55
|
return this.source ? v3FigureFacts(this.source) : undefined;
|
|
@@ -103,8 +63,20 @@ let FigureV3Properties = class FigureV3Properties extends localize(i18next)(LitE
|
|
|
103
63
|
const facts = this.facts();
|
|
104
64
|
if (!facts)
|
|
105
65
|
return nothing;
|
|
106
|
-
|
|
107
|
-
|
|
66
|
+
/* The figure's type is the page's (it lives on the row); it is slotted into the first section, as V2 had it. */
|
|
67
|
+
return html `<section>
|
|
68
|
+
<h3>${i18next.t('figure.label.group-figure')}</h3>
|
|
69
|
+
<slot name="type"></slot>
|
|
70
|
+
${this.renderName(facts)} ${this.renderPlacement(facts)}
|
|
71
|
+
</section>
|
|
72
|
+
<section>
|
|
73
|
+
<h3>${i18next.t('figure.label.group-standing')}</h3>
|
|
74
|
+
${this.renderSpace(facts)} ${this.renderMounting(facts)}
|
|
75
|
+
</section>
|
|
76
|
+
<section>
|
|
77
|
+
<h3>${i18next.t('figure.label.group-catalog')}</h3>
|
|
78
|
+
${this.renderCatalog()}
|
|
79
|
+
</section>`;
|
|
108
80
|
}
|
|
109
81
|
renderName(facts) {
|
|
110
82
|
return html `
|
|
@@ -152,7 +124,7 @@ let FigureV3Properties = class FigureV3Properties extends localize(i18next)(LitE
|
|
|
152
124
|
<label>${i18next.t('figure.label.declared-space')}</label>
|
|
153
125
|
<div row>
|
|
154
126
|
<span>${i18next.t(facts.declared ? 'figure.text.declared-space-declared' : 'figure.text.declared-space-none')}</span>
|
|
155
|
-
<button
|
|
127
|
+
<button act ?disabled=${!facts.parts.length} @click=${() => this.declare(facts.placement ?? 'floor')}>
|
|
156
128
|
<md-icon>fit_screen</md-icon>${i18next.t('figure.button.fit-base-to-parts')}
|
|
157
129
|
</button>
|
|
158
130
|
</div>
|
|
@@ -175,10 +147,10 @@ let FigureV3Properties = class FigureV3Properties extends localize(i18next)(LitE
|
|
|
175
147
|
</select>
|
|
176
148
|
</div>
|
|
177
149
|
<div row>
|
|
178
|
-
<button ?disabled=${!facts.declared || !part} @click=${() => this.command({ kind: 'set-mounting-face', part: part, face })}>
|
|
150
|
+
<button act ?disabled=${!facts.declared || !part} @click=${() => this.command({ kind: 'set-mounting-face', part: part, face })}>
|
|
179
151
|
${i18next.t('figure.button.set-mounting-face')}
|
|
180
152
|
</button>
|
|
181
|
-
<button ?disabled=${!mounting} @click=${() => this.command({ kind: 'clear-mounting-face' })}>
|
|
153
|
+
<button act ?disabled=${!mounting} @click=${() => this.command({ kind: 'clear-mounting-face' })}>
|
|
182
154
|
${i18next.t('figure.button.clear-mounting-face')}
|
|
183
155
|
</button>
|
|
184
156
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-v3-properties.js","sourceRoot":"","sources":["../../client/modeller/figure-v3-properties.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { V3_FACES } from '@hatiolab/figure-model'\nimport type { V3AuthoringAction, V3Face } from '@hatiolab/figure-model'\n\nimport { occupancyFromParts } from './v3-occupancy.js'\nimport { tagsOf, v3FigureFacts, type Placement, type V3FigureFacts } from './v3-figure-facts.js'\n\nconst PLACEMENTS: Placement[] = ['floor', 'ceiling', 'center']\nconst FACES = Object.keys(V3_FACES) as V3Face[]\n\n/**\n * 속성 — the V3 modeller's figure properties (parity row ②).\n *\n * The V2 inspector opens with what the figure is: its name, the face it is placed by, the room it takes up, where\n * the catalogue files it. The V3 page had only the type. The same rows, in the same order, drawn the way the V2\n * inspector draws them.\n *\n * Two kinds of change leave this tab, and it does neither itself:\n * - `v3-command` carries an authoring command (rename, declare the room, the mounting face). The page runs it\n * through the session, so it is one step of the same undo history as every other edit, and is saved with it.\n * - `v3-catalog` carries a change to the row (category, tags). Those are not in the asset; the page writes them\n * to the saved row at once, so they need a saved figure.\n *\n * Not here yet, because V3 has no place for them: editing the declared room by hand (V3 declares it from the\n * parts, as graph expressions), and the detail level (the converter records it as lost). Both wait on a V3 ruling.\n */\n@customElement('figure-v3-properties')\nexport class FigureV3Properties extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n overflow: auto;\n font-size: 0.76rem;\n color: var(--md-sys-color-on-surface);\n }\n div[field] {\n display: grid;\n gap: 4px;\n }\n div[field] > label {\n font-weight: 600;\n }\n div[row] {\n display: flex;\n gap: 6px;\n align-items: center;\n }\n input,\n select,\n button {\n font: inherit;\n min-width: 0;\n }\n input,\n select {\n padding: 5px 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n }\n div[row] > select {\n flex: 1;\n }\n button {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border: none;\n border-radius: 999em;\n cursor: pointer;\n color: var(--md-sys-color-on-secondary-container);\n background: var(--md-sys-color-secondary-container);\n }\n button:disabled,\n input:disabled,\n select:disabled {\n opacity: 0.5;\n cursor: default;\n }\n button md-icon {\n font-size: 16px;\n width: 16px;\n height: 16px;\n }\n small {\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n\n /** The source being edited. */\n @property({ type: String }) source?: string\n /** The saved row, if any. Category and tags live on it. */\n @property({ type: String }) figureId?: string\n @property({ type: String }) figureCategory?: string\n @property({ type: Array }) figureTags?: string[]\n /** The part and face picked for the mounting face, before 「이 면으로」 is pressed. */\n @state() private pickedPart?: string\n @state() private pickedFace?: V3Face\n\n private facts(): V3FigureFacts | undefined {\n try {\n return this.source ? v3FigureFacts(this.source) : undefined\n } catch {\n /* A source the format refuses has no facts to show; the verdict tab says why. */\n return undefined\n }\n }\n\n render() {\n const facts = this.facts()\n if (!facts) return nothing\n return html`${this.renderName(facts)} ${this.renderPlacement(facts)} ${this.renderSpace(facts)} ${this.renderMounting(facts)}\n ${this.renderCatalog()}`\n }\n\n private renderName(facts: V3FigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.name')}</label>\n <input\n .value=${facts.name}\n placeholder=${i18next.t('figure.text.figure-display-name')}\n @change=${(event: Event) => {\n const input = event.target as HTMLInputElement\n if (!input.value.trim()) {\n /* The format refuses a blank name; put the old one back rather than send a command that fails. */\n input.value = facts.name\n return\n }\n if (input.value.trim() !== facts.name) this.command({ kind: 'rename', name: input.value })\n }}\n />\n </div>\n `\n }\n\n /**\n * The face the figure is placed by. In V3 it is part of the room declaration, so choosing one declares the room\n * again from the parts — the only way V3 declares it — with the new face. The hint says so.\n */\n private renderPlacement(facts: V3FigureFacts) {\n const current = facts.placement ?? 'floor'\n return html`\n <div field>\n <label>${i18next.t('figure.label.figure-placement')}</label>\n <select\n ?disabled=${!facts.parts.length}\n @change=${(event: Event) => this.declare((event.target as HTMLSelectElement).value as Placement)}\n >\n ${PLACEMENTS.map(\n one => html`<option value=${one} ?selected=${one === current}>${i18next.t('figure.label.placement-' + one)}</option>`\n )}\n </select>\n <small>${i18next.t(facts.parts.length ? 'figure.text.placement-redeclares' : 'figure.text.fit-needs-parts')}</small>\n </div>\n `\n }\n\n private renderSpace(facts: V3FigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.declared-space')}</label>\n <div row>\n <span>${i18next.t(facts.declared ? 'figure.text.declared-space-declared' : 'figure.text.declared-space-none')}</span>\n <button fit ?disabled=${!facts.parts.length} @click=${() => this.declare(facts.placement ?? 'floor')}>\n <md-icon>fit_screen</md-icon>${i18next.t('figure.button.fit-base-to-parts')}\n </button>\n </div>\n </div>\n `\n }\n\n private renderMounting(facts: V3FigureFacts) {\n const mounting = facts.mounting\n const part = [this.pickedPart, mounting?.part, facts.parts[0]].find(one => one && facts.parts.includes(one))\n const face: V3Face = this.pickedFace ?? mounting?.face ?? 'bottom'\n return html`\n <div field>\n <label>${i18next.t('figure.label.mounting-face')}</label>\n <div row>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedPart = (e.target as HTMLSelectElement).value)}>\n ${facts.parts.map(one => html`<option value=${one} ?selected=${one === part}>${one}</option>`)}\n </select>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedFace = (e.target as HTMLSelectElement).value as V3Face)}>\n ${FACES.map(one => html`<option value=${one} ?selected=${one === face}>${i18next.t('figure.label.face-' + one)}</option>`)}\n </select>\n </div>\n <div row>\n <button ?disabled=${!facts.declared || !part} @click=${() => this.command({ kind: 'set-mounting-face', part: part!, face })}>\n ${i18next.t('figure.button.set-mounting-face')}\n </button>\n <button ?disabled=${!mounting} @click=${() => this.command({ kind: 'clear-mounting-face' })}>\n ${i18next.t('figure.button.clear-mounting-face')}\n </button>\n </div>\n <small>\n ${facts.declared\n ? mounting\n ? `${mounting.part} · ${i18next.t('figure.label.face-' + mounting.face)}`\n : i18next.t('figure.label.mounting-face-none')\n : i18next.t('figure.text.mounting-face-needs-space')}\n </small>\n </div>\n `\n }\n\n private renderCatalog() {\n const saved = !!this.figureId\n return html`\n <div field>\n <label>${i18next.t('figure.label.category')}</label>\n <input\n .value=${this.figureCategory ?? ''}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.category-placeholder')}\n @change=${(e: Event) => this.catalog({ category: (e.target as HTMLInputElement).value.trim() })}\n />\n </div>\n <div field>\n <label>${i18next.t('figure.label.tags')}</label>\n <input\n .value=${(this.figureTags ?? []).join(', ')}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.tags-placeholder')}\n @change=${(e: Event) => this.catalog({ tags: tagsOf((e.target as HTMLInputElement).value) })}\n />\n ${saved ? nothing : html`<small>${i18next.t('figure.text.catalog-needs-a-save')}</small>`}\n </div>\n `\n }\n\n private declare(placement: Placement) {\n if (!this.source) return\n this.command(occupancyFromParts(this.source, placement))\n }\n\n private command(action: V3AuthoringAction) {\n this.dispatchEvent(new CustomEvent('v3-command', { detail: { action }, bubbles: true, composed: true }))\n }\n\n private catalog(patch: { category?: string; tags?: string[] }) {\n this.dispatchEvent(new CustomEvent('v3-catalog', { detail: patch, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-v3-properties.js","sourceRoot":"","sources":["../../client/modeller/figure-v3-properties.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { V3_FACES } from '@hatiolab/figure-model'\nimport type { V3AuthoringAction, V3Face } from '@hatiolab/figure-model'\n\nimport { occupancyFromParts } from './v3-occupancy.js'\nimport { tagsOf, v3FigureFacts, type Placement, type V3FigureFacts } from './v3-figure-facts.js'\nimport { SidePanelStyles } from './side-panel-styles.js'\n\nconst PLACEMENTS: Placement[] = ['floor', 'ceiling', 'center']\nconst FACES = Object.keys(V3_FACES) as V3Face[]\n\n/**\n * 속성 — the V3 modeller's figure properties (parity row ②).\n *\n * The V2 inspector opens with what the figure is: its name, the face it is placed by, the room it takes up, where\n * the catalogue files it. The V3 page had only the type. The same rows, in the same order, drawn the way the V2\n * inspector draws them.\n *\n * Two kinds of change leave this tab, and it does neither itself:\n * - `v3-command` carries an authoring command (rename, declare the room, the mounting face). The page runs it\n * through the session, so it is one step of the same undo history as every other edit, and is saved with it.\n * - `v3-catalog` carries a change to the row (category, tags). Those are not in the asset; the page writes them\n * to the saved row at once, so they need a saved figure.\n *\n * Not here yet, because V3 has no place for them: editing the declared room by hand (V3 declares it from the\n * parts, as graph expressions), and the detail level (the converter records it as lost). Both wait on a V3 ruling.\n */\n@customElement('figure-v3-properties')\nexport class FigureV3Properties extends localize(i18next)(LitElement) {\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n /* It stands inside the properties tab's panel, which gives the margin; a second one indented it past the type. */\n padding: 0;\n overflow: auto;\n }\n div[row] {\n display: flex;\n gap: 6px;\n align-items: center;\n }\n div[row] > select {\n flex: 1;\n }\n div[row] > button[act] {\n flex: 1;\n width: auto;\n margin-top: 0;\n }\n div[row] > span {\n flex: 1;\n }\n `]\n\n /** The source being edited. */\n @property({ type: String }) source?: string\n /** The saved row, if any. Category and tags live on it. */\n @property({ type: String }) figureId?: string\n @property({ type: String }) figureCategory?: string\n @property({ type: Array }) figureTags?: string[]\n /** The part and face picked for the mounting face, before 「이 면으로」 is pressed. */\n @state() private pickedPart?: string\n @state() private pickedFace?: V3Face\n\n private facts(): V3FigureFacts | undefined {\n try {\n return this.source ? v3FigureFacts(this.source) : undefined\n } catch {\n /* A source the format refuses has no facts to show; the verdict tab says why. */\n return undefined\n }\n }\n\n render() {\n const facts = this.facts()\n if (!facts) return nothing\n /* The figure's type is the page's (it lives on the row); it is slotted into the first section, as V2 had it. */\n return html`<section>\n <h3>${i18next.t('figure.label.group-figure')}</h3>\n <slot name=\"type\"></slot>\n ${this.renderName(facts)} ${this.renderPlacement(facts)}\n </section>\n <section>\n <h3>${i18next.t('figure.label.group-standing')}</h3>\n ${this.renderSpace(facts)} ${this.renderMounting(facts)}\n </section>\n <section>\n <h3>${i18next.t('figure.label.group-catalog')}</h3>\n ${this.renderCatalog()}\n </section>`\n }\n\n private renderName(facts: V3FigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.name')}</label>\n <input\n .value=${facts.name}\n placeholder=${i18next.t('figure.text.figure-display-name')}\n @change=${(event: Event) => {\n const input = event.target as HTMLInputElement\n if (!input.value.trim()) {\n /* The format refuses a blank name; put the old one back rather than send a command that fails. */\n input.value = facts.name\n return\n }\n if (input.value.trim() !== facts.name) this.command({ kind: 'rename', name: input.value })\n }}\n />\n </div>\n `\n }\n\n /**\n * The face the figure is placed by. In V3 it is part of the room declaration, so choosing one declares the room\n * again from the parts — the only way V3 declares it — with the new face. The hint says so.\n */\n private renderPlacement(facts: V3FigureFacts) {\n const current = facts.placement ?? 'floor'\n return html`\n <div field>\n <label>${i18next.t('figure.label.figure-placement')}</label>\n <select\n ?disabled=${!facts.parts.length}\n @change=${(event: Event) => this.declare((event.target as HTMLSelectElement).value as Placement)}\n >\n ${PLACEMENTS.map(\n one => html`<option value=${one} ?selected=${one === current}>${i18next.t('figure.label.placement-' + one)}</option>`\n )}\n </select>\n <small>${i18next.t(facts.parts.length ? 'figure.text.placement-redeclares' : 'figure.text.fit-needs-parts')}</small>\n </div>\n `\n }\n\n private renderSpace(facts: V3FigureFacts) {\n return html`\n <div field>\n <label>${i18next.t('figure.label.declared-space')}</label>\n <div row>\n <span>${i18next.t(facts.declared ? 'figure.text.declared-space-declared' : 'figure.text.declared-space-none')}</span>\n <button act ?disabled=${!facts.parts.length} @click=${() => this.declare(facts.placement ?? 'floor')}>\n <md-icon>fit_screen</md-icon>${i18next.t('figure.button.fit-base-to-parts')}\n </button>\n </div>\n </div>\n `\n }\n\n private renderMounting(facts: V3FigureFacts) {\n const mounting = facts.mounting\n const part = [this.pickedPart, mounting?.part, facts.parts[0]].find(one => one && facts.parts.includes(one))\n const face: V3Face = this.pickedFace ?? mounting?.face ?? 'bottom'\n return html`\n <div field>\n <label>${i18next.t('figure.label.mounting-face')}</label>\n <div row>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedPart = (e.target as HTMLSelectElement).value)}>\n ${facts.parts.map(one => html`<option value=${one} ?selected=${one === part}>${one}</option>`)}\n </select>\n <select ?disabled=${!facts.declared} @change=${(e: Event) => (this.pickedFace = (e.target as HTMLSelectElement).value as V3Face)}>\n ${FACES.map(one => html`<option value=${one} ?selected=${one === face}>${i18next.t('figure.label.face-' + one)}</option>`)}\n </select>\n </div>\n <div row>\n <button act ?disabled=${!facts.declared || !part} @click=${() => this.command({ kind: 'set-mounting-face', part: part!, face })}>\n ${i18next.t('figure.button.set-mounting-face')}\n </button>\n <button act ?disabled=${!mounting} @click=${() => this.command({ kind: 'clear-mounting-face' })}>\n ${i18next.t('figure.button.clear-mounting-face')}\n </button>\n </div>\n <small>\n ${facts.declared\n ? mounting\n ? `${mounting.part} · ${i18next.t('figure.label.face-' + mounting.face)}`\n : i18next.t('figure.label.mounting-face-none')\n : i18next.t('figure.text.mounting-face-needs-space')}\n </small>\n </div>\n `\n }\n\n private renderCatalog() {\n const saved = !!this.figureId\n return html`\n <div field>\n <label>${i18next.t('figure.label.category')}</label>\n <input\n .value=${this.figureCategory ?? ''}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.category-placeholder')}\n @change=${(e: Event) => this.catalog({ category: (e.target as HTMLInputElement).value.trim() })}\n />\n </div>\n <div field>\n <label>${i18next.t('figure.label.tags')}</label>\n <input\n .value=${(this.figureTags ?? []).join(', ')}\n ?disabled=${!saved}\n placeholder=${i18next.t('figure.text.tags-placeholder')}\n @change=${(e: Event) => this.catalog({ tags: tagsOf((e.target as HTMLInputElement).value) })}\n />\n ${saved ? nothing : html`<small>${i18next.t('figure.text.catalog-needs-a-save')}</small>`}\n </div>\n `\n }\n\n private declare(placement: Placement) {\n if (!this.source) return\n this.command(occupancyFromParts(this.source, placement))\n }\n\n private command(action: V3AuthoringAction) {\n this.dispatchEvent(new CustomEvent('v3-command', { detail: { action }, bubbles: true, composed: true }))\n }\n\n private catalog(patch: { category?: string; tags?: string[] }) {\n this.dispatchEvent(new CustomEvent('v3-catalog', { detail: patch, bubbles: true, composed: true }))\n }\n}\n"]}
|