@things-factory/figure-ui 10.1.84 → 10.1.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/client/modeller/editor.ts +46 -2
  2. package/client/modeller/figure-parts.ts +4 -4
  3. package/client/modeller/figure-section-editor.ts +484 -0
  4. package/client/modeller/figure-section-panel.ts +211 -75
  5. package/client/modeller/live.ts +13 -4
  6. package/client/modeller/section-controls.ts +89 -8
  7. package/client/modeller/section-drawing.ts +97 -0
  8. package/dist-client/modeller/clips.d.ts +1 -1
  9. package/dist-client/modeller/editor.d.ts +8 -0
  10. package/dist-client/modeller/editor.js +51 -1
  11. package/dist-client/modeller/editor.js.map +1 -1
  12. package/dist-client/modeller/figure-parts.js +1 -3
  13. package/dist-client/modeller/figure-parts.js.map +1 -1
  14. package/dist-client/modeller/figure-section-editor.d.ts +62 -0
  15. package/dist-client/modeller/figure-section-editor.js +495 -0
  16. package/dist-client/modeller/figure-section-editor.js.map +1 -0
  17. package/dist-client/modeller/figure-section-panel.d.ts +26 -12
  18. package/dist-client/modeller/figure-section-panel.js +193 -69
  19. package/dist-client/modeller/figure-section-panel.js.map +1 -1
  20. package/dist-client/modeller/live.d.ts +3 -1
  21. package/dist-client/modeller/live.js +13 -3
  22. package/dist-client/modeller/live.js.map +1 -1
  23. package/dist-client/modeller/section-controls.d.ts +33 -0
  24. package/dist-client/modeller/section-controls.js +71 -7
  25. package/dist-client/modeller/section-controls.js.map +1 -1
  26. package/dist-client/modeller/section-drawing.d.ts +33 -0
  27. package/dist-client/modeller/section-drawing.js +82 -0
  28. package/dist-client/modeller/section-drawing.js.map +1 -0
  29. package/dist-client/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +3 -3
  31. package/test/browser/acceptance-page.js +7 -0
  32. package/test/palette-icons.test.ts +1 -1
  33. package/test/parts-wiring.test.ts +6 -2
  34. package/test/section-editor.test.ts +192 -0
  35. package/test/section-panel.test.ts +108 -6
  36. package/translations/en.json +37 -2
  37. package/translations/ja.json +37 -2
  38. package/translations/ko.json +37 -2
  39. package/translations/ms.json +37 -2
  40. package/translations/zh.json +37 -2
@@ -0,0 +1,495 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { css, html, LitElement, nothing, svg } from 'lit';
3
+ import { customElement, property, state } from 'lit/decorators.js';
4
+ import { live } from 'lit/directives/live.js';
5
+ import { i18next, localize } from '@operato/i18n';
6
+ import { figureSectionSidesOf } from '@hatiolab/figure-model';
7
+ import { SidePanelStyles } from './side-panel-styles.js';
8
+ import { extentOf, insertAfter, issueWords, issuesOf, markedBy, movePoint, pointLabel, removePoint } from './section-drawing.js';
9
+ /** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */
10
+ const SCREEN = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] };
11
+ /** The editor's width and room for the solid beside it: below this the two take turns. */
12
+ export const NARROW_BELOW = 900;
13
+ /**
14
+ * 단면 편집 — a drawn section edited point by point (ADR-0100 §3.2, stage 2).
15
+ *
16
+ * The outline is drawn flat, looking along the push, in millimetres from the part's origin; the figure behind stays in
17
+ * view and shows the solid the working points make (`command-live`, the same preview the section panel uses), so the 2D
18
+ * and the 3D stand side by side. A point is dragged or typed; a side pressed gains a point in its middle; a point is
19
+ * deleted by its button or the Delete key, never below three. What the kernel would refuse is marked on the outline and
20
+ * said in the list; apply is held back, and the solid shows the last valid shape, which the caption names.
21
+ *
22
+ * Apply sends one `command` (one step of the history); cancel or Esc sends nothing and lets the preview go. The undo
23
+ * here is the editor's own, for the working points only. If the figure changes while the editor is open, the working
24
+ * points are no longer of the figure as it is, and apply is refused until the editor is opened again.
25
+ */
26
+ let FigureSectionEditor = class FigureSectionEditor extends localize(i18next)(LitElement) {
27
+ constructor() {
28
+ super(...arguments);
29
+ /** The figure's revision now; the editor remembers the one it opened at. */
30
+ this.revision = 0;
31
+ /** Narrow: the outline or the solid behind. */
32
+ this.show = 'outline';
33
+ /** Set when the space the editor stands in leaves too little beside it to see the solid. */
34
+ this.narrow = false;
35
+ this.room = new ResizeObserver(([entry]) => {
36
+ this.narrow = (entry?.contentRect.width ?? 0) < NARROW_BELOW;
37
+ if (!this.narrow)
38
+ this.show = 'outline';
39
+ });
40
+ this.working = [];
41
+ this.selected = null;
42
+ this.note = '';
43
+ this.history = [];
44
+ this.lastValid = [];
45
+ this.openedAt = 0;
46
+ this.dragging = null;
47
+ /** The points as they were when a drag began: kept once the point moves, so a press alone is not a step back. */
48
+ this.dragFrom = null;
49
+ this.extent = 200;
50
+ /*
51
+ * Heard first (capture on the window), and a key the editor takes goes no further: the scene behind listens too, and
52
+ * would take Esc as "select nothing" and Delete as "delete the part".
53
+ */
54
+ this.keys = (e) => {
55
+ const inField = e.composedPath()[0]?.tagName === 'INPUT';
56
+ const take = () => (e.preventDefault(), e.stopImmediatePropagation());
57
+ if (e.key === 'Escape') {
58
+ take();
59
+ this.cancel();
60
+ }
61
+ else if ((e.key === 'Delete' || e.key === 'Backspace') && !inField && this.selected) {
62
+ /* In a field the key deletes a character; outside, the chosen point. */
63
+ take();
64
+ this.removePoint(this.selected);
65
+ }
66
+ else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'z' && !inField) {
67
+ take();
68
+ this.back();
69
+ }
70
+ };
71
+ }
72
+ static { this.styles = [SidePanelStyles, css `
73
+ :host {
74
+ position: absolute;
75
+ left: 12px;
76
+ top: 12px;
77
+ bottom: 12px;
78
+ z-index: 5;
79
+ display: grid;
80
+ grid-template-rows: auto auto minmax(0, 1fr) auto;
81
+ width: min(560px, calc(100% - 24px));
82
+ background: var(--md-sys-color-surface);
83
+ color: var(--md-sys-color-on-surface);
84
+ border: 1px solid var(--md-sys-color-outline-variant);
85
+ border-radius: 12px;
86
+ box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
87
+ overflow: hidden;
88
+ }
89
+ /* Each in its own row: the tabs are hidden on a wide screen, and without the rows named the body fell into theirs. */
90
+ header {
91
+ grid-row: 1;
92
+ }
93
+ nav[tabs] {
94
+ grid-row: 2;
95
+ }
96
+ div[body] {
97
+ grid-row: 3;
98
+ }
99
+ footer {
100
+ grid-row: 4;
101
+ }
102
+ header {
103
+ display: flex;
104
+ align-items: baseline;
105
+ gap: 10px;
106
+ padding: 10px 14px 4px;
107
+ }
108
+ header h2 {
109
+ margin: 0;
110
+ font-size: var(--ui-t-body);
111
+ }
112
+ header span {
113
+ font-size: 0.72rem;
114
+ color: var(--md-sys-color-on-surface-variant);
115
+ }
116
+ nav[tabs] {
117
+ display: none;
118
+ gap: 4px;
119
+ padding: 0 14px 6px;
120
+ }
121
+ nav[tabs] button,
122
+ footer button,
123
+ li button {
124
+ font: inherit;
125
+ font-size: 0.78rem;
126
+ min-height: 30px;
127
+ padding: 0 12px;
128
+ border-radius: 15px;
129
+ border: 1px solid var(--md-sys-color-outline-variant);
130
+ background: var(--md-sys-color-surface-container-lowest);
131
+ color: var(--md-sys-color-on-surface);
132
+ cursor: pointer;
133
+ }
134
+ nav[tabs] button[on] {
135
+ background: var(--md-sys-color-secondary-container);
136
+ color: var(--md-sys-color-on-secondary-container);
137
+ }
138
+ div[body] {
139
+ display: grid;
140
+ grid-template-rows: minmax(160px, 1fr) auto;
141
+ min-height: 0;
142
+ border-top: 1px solid var(--md-sys-color-outline-variant);
143
+ }
144
+ div[outline] {
145
+ position: relative;
146
+ min-height: 0;
147
+ }
148
+ svg {
149
+ width: 100%;
150
+ height: 100%;
151
+ display: block;
152
+ touch-action: none;
153
+ user-select: none;
154
+ }
155
+ div[caption] {
156
+ position: absolute;
157
+ left: 8px;
158
+ top: 6px;
159
+ font-size: 0.68rem;
160
+ color: var(--md-sys-color-on-surface-variant);
161
+ pointer-events: none;
162
+ }
163
+ div[caption][last-valid] {
164
+ color: var(--md-sys-color-error);
165
+ font-weight: 600;
166
+ }
167
+ aside {
168
+ max-height: 34vh;
169
+ overflow: auto;
170
+ padding: 8px 14px;
171
+ border-top: 1px solid var(--md-sys-color-outline-variant);
172
+ }
173
+ ol[points] {
174
+ list-style: none;
175
+ margin: 0;
176
+ padding: 0;
177
+ display: grid;
178
+ gap: 4px;
179
+ }
180
+ ol[points] li {
181
+ display: grid;
182
+ grid-template-columns: 2.2em minmax(0, 1fr) minmax(0, 1fr) auto;
183
+ gap: 6px;
184
+ align-items: center;
185
+ padding: 2px 4px;
186
+ border-radius: 6px;
187
+ }
188
+ ol[points] li[selected] {
189
+ background: var(--md-sys-color-secondary-container);
190
+ }
191
+ ol[points] li[marked] b {
192
+ color: var(--md-sys-color-error);
193
+ }
194
+ ol[points] input {
195
+ min-width: 0;
196
+ font: inherit;
197
+ }
198
+ ul[issues] {
199
+ margin: 8px 0 0;
200
+ padding: 0 0 0 16px;
201
+ color: var(--md-sys-color-error);
202
+ font-size: 0.76rem;
203
+ }
204
+ small {
205
+ color: var(--md-sys-color-on-surface-variant);
206
+ }
207
+ footer {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 8px;
211
+ padding: 8px 14px;
212
+ border-top: 1px solid var(--md-sys-color-outline-variant);
213
+ }
214
+ footer span[grow] {
215
+ flex: 1;
216
+ font-size: 0.72rem;
217
+ color: var(--md-sys-color-on-surface-variant);
218
+ }
219
+ footer span[grow][stale] {
220
+ color: var(--md-sys-color-error);
221
+ }
222
+ footer button[primary] {
223
+ background: var(--md-sys-color-primary);
224
+ color: var(--md-sys-color-on-primary);
225
+ border-color: transparent;
226
+ }
227
+ button:disabled {
228
+ opacity: 0.45;
229
+ cursor: default;
230
+ }
231
+ /* Too little room beside the editor for the solid: the outline and the solid take turns (§7). */
232
+ :host([narrow]) nav[tabs] {
233
+ display: flex;
234
+ }
235
+ :host([narrow][show='solid']) div[body] {
236
+ display: none;
237
+ }
238
+ :host([narrow][show='solid']) {
239
+ bottom: auto;
240
+ }
241
+ `]; }
242
+ get axis() {
243
+ return (this.body?.shape.extrusion?.axis ?? 'y');
244
+ }
245
+ connectedCallback() {
246
+ super.connectedCallback();
247
+ const s = this.body?.shape.extrusion?.section;
248
+ this.working = s?.kind === 'polygon' ? s.points.map(p => ({ ...p })) : [];
249
+ this.lastValid = this.working;
250
+ this.openedAt = this.revision;
251
+ this.extent = extentOf(this.working, this.axis);
252
+ window.addEventListener('keydown', this.keys, true);
253
+ if (this.parentElement)
254
+ this.room.observe(this.parentElement);
255
+ }
256
+ disconnectedCallback() {
257
+ window.removeEventListener('keydown', this.keys, true);
258
+ this.room.disconnect();
259
+ super.disconnectedCallback();
260
+ }
261
+ get stale() {
262
+ return this.revision !== this.openedAt;
263
+ }
264
+ change(next) {
265
+ this.history.push(this.working);
266
+ this.working = next;
267
+ this.note = '';
268
+ if (!issuesOf(next, this.axis).length)
269
+ this.lastValid = next;
270
+ this.preview();
271
+ }
272
+ back() {
273
+ const before = this.history.pop();
274
+ if (!before)
275
+ return;
276
+ this.working = before;
277
+ if (!issuesOf(before, this.axis).length)
278
+ this.lastValid = before;
279
+ this.preview();
280
+ }
281
+ /** The solid behind shows the working points, or the last valid ones while the working ones are refused. */
282
+ preview() {
283
+ this.dispatchEvent(new CustomEvent('command-live', { detail: { action: this.action(this.lastValid) }, bubbles: true, composed: true }));
284
+ }
285
+ action(points) {
286
+ return { kind: 'set-section-points', part: this.body.id, points: points.map(p => ({ ...p })) };
287
+ }
288
+ removePoint(id) {
289
+ const next = removePoint(this.working, id);
290
+ if ('refused' in next) {
291
+ this.note = i18next.t('figure.text.section-issue-too-few');
292
+ return;
293
+ }
294
+ this.selected = null;
295
+ this.change(next);
296
+ }
297
+ apply() {
298
+ if (this.stale || issuesOf(this.working, this.axis).length)
299
+ return;
300
+ this.dispatchEvent(new CustomEvent('command', { detail: { action: this.action(this.working) }, bubbles: true, composed: true }));
301
+ this.close();
302
+ }
303
+ cancel() {
304
+ this.dispatchEvent(new CustomEvent('command-live', { detail: { action: null }, bubbles: true, composed: true }));
305
+ this.close();
306
+ }
307
+ close() {
308
+ this.dispatchEvent(new CustomEvent('section-editor-close', { bubbles: true, composed: true }));
309
+ }
310
+ svgPoint(e) {
311
+ const el = this.renderRoot.querySelector('svg');
312
+ const pt = el.createSVGPoint();
313
+ pt.x = e.clientX;
314
+ pt.y = e.clientY;
315
+ const p = pt.matrixTransform(el.getScreenCTM().inverse());
316
+ return { h: Math.round(p.x), v: Math.round(p.y) };
317
+ }
318
+ render() {
319
+ if (!this.body)
320
+ return nothing;
321
+ const issues = issuesOf(this.working, this.axis);
322
+ const length = this.body.shape.extrusion ? this.body.shape.extrusion.end - this.body.shape.extrusion.start : 0;
323
+ return html `
324
+ <header>
325
+ <h2>${i18next.t('figure.label.section-editor')}</h2>
326
+ <span>${this.body.id} · ${i18next.t('figure.text.section-editor-length', { length: String(Math.round(length * 1000) / 1000) })}</span>
327
+ </header>
328
+ <nav tabs>
329
+ ${['outline', 'solid'].map(one => html `<button ?on=${this.show === one} @click=${() => (this.show = one)}>${i18next.t(`figure.label.section-editor-${one}`)}</button>`)}
330
+ </nav>
331
+ <div body>
332
+ <div outline>${this.drawing(issues)}</div>
333
+ <aside>${this.list(issues)}</aside>
334
+ </div>
335
+ <footer>
336
+ <button ?disabled=${!this.history.length} @click=${() => this.back()}>${i18next.t('figure.button.section-editor-back')}</button>
337
+ <span grow ?stale=${this.stale}>
338
+ ${this.stale ? i18next.t('figure.text.section-editor-stale') : i18next.t('figure.text.section-editor-hint')}
339
+ </span>
340
+ <button @click=${() => this.cancel()}>${i18next.t('figure.button.section-editor-cancel')}</button>
341
+ <button primary ?disabled=${this.stale || issues.length > 0} @click=${() => this.apply()}>${i18next.t('figure.button.section-editor-apply')}</button>
342
+ </footer>
343
+ `;
344
+ }
345
+ drawing(issues) {
346
+ const [h, v] = SCREEN[this.axis];
347
+ const e = this.extent;
348
+ const marked = markedBy(issues);
349
+ const pts = this.working;
350
+ const sides = pts.length >= 2 ? figureSectionSidesOf({ kind: 'polygon', points: pts }, this.axis) : [];
351
+ const at = (id) => pts.find(p => p.id === id);
352
+ const grid = Math.max(10, Math.pow(10, Math.floor(Math.log10(e))) / 2);
353
+ const lines = [];
354
+ for (let g = -Math.floor(e / grid) * grid; g <= e; g += grid)
355
+ lines.push(g);
356
+ const invalid = issues.length > 0;
357
+ return html `<div caption ?last-valid=${invalid}>
358
+ ${invalid ? i18next.t('figure.text.section-editor-last-valid') : i18next.t('figure.text.section-editor-units', { h: h.toUpperCase(), v: v.toUpperCase() })}
359
+ </div>
360
+ <svg
361
+ viewBox=${`${-e} ${-e} ${2 * e} ${2 * e}`}
362
+ role="img"
363
+ aria-label=${i18next.t('figure.label.section-editor')}
364
+ @pointermove=${(ev) => {
365
+ if (!this.dragging)
366
+ return;
367
+ if (this.dragFrom)
368
+ this.history.push(this.dragFrom), (this.dragFrom = null);
369
+ const p = this.svgPoint(ev);
370
+ this.working = movePoint(this.working, this.dragging, { [h]: p.h, [v]: p.v });
371
+ if (!issuesOf(this.working, this.axis).length)
372
+ this.lastValid = this.working;
373
+ this.preview();
374
+ }}
375
+ @pointerup=${() => ((this.dragging = null), (this.dragFrom = null))}
376
+ @pointerleave=${() => ((this.dragging = null), (this.dragFrom = null))}
377
+ >
378
+ ${svg `${lines.map(g => svg `<line x1=${g} y1=${-e} x2=${g} y2=${e} stroke="var(--md-sys-color-outline-variant)" stroke-width=${e / 400} opacity="0.5" />
379
+ <line x1=${-e} y1=${g} x2=${e} y2=${g} stroke="var(--md-sys-color-outline-variant)" stroke-width=${e / 400} opacity="0.5" />`)}
380
+ <line x1=${-e} y1="0" x2=${e} y2="0" stroke="var(--md-sys-color-outline)" stroke-width=${e / 250} />
381
+ <line x1="0" y1=${-e} x2="0" y2=${e} stroke="var(--md-sys-color-outline)" stroke-width=${e / 250} />
382
+ <text x=${e * 0.92} y=${-e * 0.02} font-size=${e / 18} fill="var(--md-sys-color-on-surface-variant)">${h.toUpperCase()}</text>
383
+ <text x=${e * 0.02} y=${e * 0.95} font-size=${e / 18} fill="var(--md-sys-color-on-surface-variant)">${v.toUpperCase()}</text>
384
+ ${invalid && this.lastValid.length
385
+ ? svg `<polygon points=${this.lastValid.map(p => `${p[h]},${p[v]}`).join(' ')} fill="none" stroke="var(--md-sys-color-outline)" stroke-dasharray=${`${e / 50} ${e / 70}`} stroke-width=${e / 250} />`
386
+ : nothing}
387
+ <polygon points=${pts.map(p => `${p[h]},${p[v]}`).join(' ')} fill=${invalid ? 'none' : 'color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent)'} stroke="none" />
388
+ ${sides.map(s => {
389
+ const a = at(s.from), b = at(s.to);
390
+ const bad = marked.sides.has(s.id);
391
+ return svg `<line x1=${a[h]} y1=${a[v]} x2=${b[h]} y2=${b[v]}
392
+ stroke=${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'} stroke-width=${e / (bad ? 90 : 130)}
393
+ stroke-dasharray=${bad ? `${e / 40} ${e / 80}` : ''} />
394
+ <line side=${s.id} x1=${a[h]} y1=${a[v]} x2=${b[h]} y2=${b[v]} stroke="transparent" stroke-width=${e / 25} style="cursor: copy"
395
+ @pointerdown=${(ev) => {
396
+ ev.stopPropagation();
397
+ const made = insertAfter(this.working, s.from, this.axis);
398
+ this.change(made.points);
399
+ this.selected = made.id;
400
+ }}><title>${i18next.t('figure.text.section-editor-add-here', { a: pointLabel(s.from), b: pointLabel(s.to) })}</title></line>`;
401
+ })}
402
+ ${pts.map(p => {
403
+ const bad = marked.points.has(p.id), on = this.selected === p.id;
404
+ return svg `<g point=${p.id} style="cursor: grab"
405
+ @pointerdown=${(ev) => {
406
+ ev.stopPropagation();
407
+ ev.target.setPointerCapture?.(ev.pointerId);
408
+ this.dragFrom = this.working;
409
+ this.selected = p.id;
410
+ this.dragging = p.id;
411
+ }}>
412
+ <circle cx=${p[h]} cy=${p[v]} r=${e / (on ? 28 : 36)} fill=${bad ? 'var(--md-sys-color-error)' : on ? 'var(--md-sys-color-primary)' : 'var(--md-sys-color-surface)'}
413
+ stroke=${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'} stroke-width=${e / 250} />
414
+ <text x=${p[h] + e / 22} y=${p[v] - e / 22} font-size=${e / 16} font-weight="600"
415
+ fill=${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-on-surface)'}>${pointLabel(p.id)}</text>
416
+ </g>`;
417
+ })}`}
418
+ </svg>`;
419
+ }
420
+ list(issues) {
421
+ const [h, v] = SCREEN[this.axis];
422
+ const marked = markedBy(issues);
423
+ return html `<ol points aria-label=${i18next.t('figure.label.section-editor-points')}>
424
+ ${this.working.map(p => html `<li ?selected=${this.selected === p.id} ?marked=${marked.points.has(p.id)} @focusin=${() => (this.selected = p.id)}>
425
+ <b>${pointLabel(p.id)}</b>
426
+ ${[h, v].map(axis => html `<input
427
+ type="number"
428
+ step="any"
429
+ inputmode="decimal"
430
+ aria-label=${i18next.t('figure.label.section-editor-coordinate', { point: pointLabel(p.id), axis: axis.toUpperCase() })}
431
+ .value=${live(String(p[axis] ?? ''))}
432
+ @change=${(ev) => {
433
+ const input = ev.target;
434
+ const value = Number(input.value);
435
+ if (input.value === '' || !Number.isFinite(value)) {
436
+ input.value = String(p[axis] ?? '');
437
+ return;
438
+ }
439
+ this.change(movePoint(this.working, p.id, { [axis]: value }));
440
+ }}
441
+ />`)}
442
+ <button
443
+ ?disabled=${this.working.length <= 3}
444
+ title=${this.working.length <= 3 ? i18next.t('figure.text.section-issue-too-few') : ''}
445
+ aria-label=${i18next.t('figure.button.section-editor-remove', { point: pointLabel(p.id) })}
446
+ @click=${() => this.removePoint(p.id)}
447
+ >
448
+ ${i18next.t('figure.button.section-editor-remove', { point: pointLabel(p.id) })}
449
+ </button>
450
+ </li>`)}
451
+ </ol>
452
+ ${this.note ? html `<small role="status">${this.note}</small>` : nothing}
453
+ ${issues.length
454
+ ? html `<ul issues role="alert">
455
+ ${issues.map(i => {
456
+ const w = issueWords(i, this.working, this.axis);
457
+ return html `<li>${i18next.t(w.key, w.params)}</li>`;
458
+ })}
459
+ </ul>`
460
+ : nothing}`;
461
+ }
462
+ };
463
+ __decorate([
464
+ property({ attribute: false }),
465
+ __metadata("design:type", Object)
466
+ ], FigureSectionEditor.prototype, "body", void 0);
467
+ __decorate([
468
+ property({ type: Number }),
469
+ __metadata("design:type", Object)
470
+ ], FigureSectionEditor.prototype, "revision", void 0);
471
+ __decorate([
472
+ property({ reflect: true }),
473
+ __metadata("design:type", String)
474
+ ], FigureSectionEditor.prototype, "show", void 0);
475
+ __decorate([
476
+ property({ type: Boolean, reflect: true }),
477
+ __metadata("design:type", Object)
478
+ ], FigureSectionEditor.prototype, "narrow", void 0);
479
+ __decorate([
480
+ state(),
481
+ __metadata("design:type", Array)
482
+ ], FigureSectionEditor.prototype, "working", void 0);
483
+ __decorate([
484
+ state(),
485
+ __metadata("design:type", Object)
486
+ ], FigureSectionEditor.prototype, "selected", void 0);
487
+ __decorate([
488
+ state(),
489
+ __metadata("design:type", Object)
490
+ ], FigureSectionEditor.prototype, "note", void 0);
491
+ FigureSectionEditor = __decorate([
492
+ customElement('figure-section-editor')
493
+ ], FigureSectionEditor);
494
+ export { FigureSectionEditor };
495
+ //# sourceMappingURL=figure-section-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figure-section-editor.js","sourceRoot":"","sources":["../../client/modeller/figure-section-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureSectionSidesOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureEvaluatedShape, FigureSectionPoint } from '@hatiolab/figure-model'\nimport { SidePanelStyles } from './side-panel-styles.js'\nimport { extentOf, insertAfter, issueWords, issuesOf, markedBy, movePoint, pointLabel, removePoint, type Points } from './section-drawing.js'\n\ntype Axis = 'x' | 'y' | 'z'\n\n/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */\nconst SCREEN: Record<Axis, [Axis, Axis]> = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] }\n\n/** The editor's width and room for the solid beside it: below this the two take turns. */\nexport const NARROW_BELOW = 900\n\n/**\n * 단면 편집 — a drawn section edited point by point (ADR-0100 §3.2, stage 2).\n *\n * The outline is drawn flat, looking along the push, in millimetres from the part's origin; the figure behind stays in\n * view and shows the solid the working points make (`command-live`, the same preview the section panel uses), so the 2D\n * and the 3D stand side by side. A point is dragged or typed; a side pressed gains a point in its middle; a point is\n * deleted by its button or the Delete key, never below three. What the kernel would refuse is marked on the outline and\n * said in the list; apply is held back, and the solid shows the last valid shape, which the caption names.\n *\n * Apply sends one `command` (one step of the history); cancel or Esc sends nothing and lets the preview go. The undo\n * here is the editor's own, for the working points only. If the figure changes while the editor is open, the working\n * points are no longer of the figure as it is, and apply is refused until the editor is opened again.\n */\n@customElement('figure-section-editor')\nexport class FigureSectionEditor extends localize(i18next)(LitElement) {\n static styles = [SidePanelStyles, css`\n :host {\n position: absolute;\n left: 12px;\n top: 12px;\n bottom: 12px;\n z-index: 5;\n display: grid;\n grid-template-rows: auto auto minmax(0, 1fr) auto;\n width: min(560px, calc(100% - 24px));\n background: var(--md-sys-color-surface);\n color: var(--md-sys-color-on-surface);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 12px;\n box-shadow: 0 8px 24px rgb(0 0 0 / 18%);\n overflow: hidden;\n }\n /* Each in its own row: the tabs are hidden on a wide screen, and without the rows named the body fell into theirs. */\n header {\n grid-row: 1;\n }\n nav[tabs] {\n grid-row: 2;\n }\n div[body] {\n grid-row: 3;\n }\n footer {\n grid-row: 4;\n }\n header {\n display: flex;\n align-items: baseline;\n gap: 10px;\n padding: 10px 14px 4px;\n }\n header h2 {\n margin: 0;\n font-size: var(--ui-t-body);\n }\n header span {\n font-size: 0.72rem;\n color: var(--md-sys-color-on-surface-variant);\n }\n nav[tabs] {\n display: none;\n gap: 4px;\n padding: 0 14px 6px;\n }\n nav[tabs] button,\n footer button,\n li button {\n font: inherit;\n font-size: 0.78rem;\n min-height: 30px;\n padding: 0 12px;\n border-radius: 15px;\n border: 1px solid var(--md-sys-color-outline-variant);\n background: var(--md-sys-color-surface-container-lowest);\n color: var(--md-sys-color-on-surface);\n cursor: pointer;\n }\n nav[tabs] button[on] {\n background: var(--md-sys-color-secondary-container);\n color: var(--md-sys-color-on-secondary-container);\n }\n div[body] {\n display: grid;\n grid-template-rows: minmax(160px, 1fr) auto;\n min-height: 0;\n border-top: 1px solid var(--md-sys-color-outline-variant);\n }\n div[outline] {\n position: relative;\n min-height: 0;\n }\n svg {\n width: 100%;\n height: 100%;\n display: block;\n touch-action: none;\n user-select: none;\n }\n div[caption] {\n position: absolute;\n left: 8px;\n top: 6px;\n font-size: 0.68rem;\n color: var(--md-sys-color-on-surface-variant);\n pointer-events: none;\n }\n div[caption][last-valid] {\n color: var(--md-sys-color-error);\n font-weight: 600;\n }\n aside {\n max-height: 34vh;\n overflow: auto;\n padding: 8px 14px;\n border-top: 1px solid var(--md-sys-color-outline-variant);\n }\n ol[points] {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 4px;\n }\n ol[points] li {\n display: grid;\n grid-template-columns: 2.2em minmax(0, 1fr) minmax(0, 1fr) auto;\n gap: 6px;\n align-items: center;\n padding: 2px 4px;\n border-radius: 6px;\n }\n ol[points] li[selected] {\n background: var(--md-sys-color-secondary-container);\n }\n ol[points] li[marked] b {\n color: var(--md-sys-color-error);\n }\n ol[points] input {\n min-width: 0;\n font: inherit;\n }\n ul[issues] {\n margin: 8px 0 0;\n padding: 0 0 0 16px;\n color: var(--md-sys-color-error);\n font-size: 0.76rem;\n }\n small {\n color: var(--md-sys-color-on-surface-variant);\n }\n footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border-top: 1px solid var(--md-sys-color-outline-variant);\n }\n footer span[grow] {\n flex: 1;\n font-size: 0.72rem;\n color: var(--md-sys-color-on-surface-variant);\n }\n footer span[grow][stale] {\n color: var(--md-sys-color-error);\n }\n footer button[primary] {\n background: var(--md-sys-color-primary);\n color: var(--md-sys-color-on-primary);\n border-color: transparent;\n }\n button:disabled {\n opacity: 0.45;\n cursor: default;\n }\n /* Too little room beside the editor for the solid: the outline and the solid take turns (§7). */\n :host([narrow]) nav[tabs] {\n display: flex;\n }\n :host([narrow][show='solid']) div[body] {\n display: none;\n }\n :host([narrow][show='solid']) {\n bottom: auto;\n }\n `]\n\n /** The part and its evaluated shape as they stand when the editor opens. */\n @property({ attribute: false }) body?: { id: string; shape: FigureEvaluatedShape }\n /** The figure's revision now; the editor remembers the one it opened at. */\n @property({ type: Number }) revision = 0\n /** Narrow: the outline or the solid behind. */\n @property({ reflect: true }) show: 'outline' | 'solid' = 'outline'\n /** Set when the space the editor stands in leaves too little beside it to see the solid. */\n @property({ type: Boolean, reflect: true }) narrow = false\n private room = new ResizeObserver(([entry]) => {\n this.narrow = (entry?.contentRect.width ?? 0) < NARROW_BELOW\n if (!this.narrow) this.show = 'outline'\n })\n\n @state() private working: FigureSectionPoint[] = []\n @state() private selected: string | null = null\n @state() private note = ''\n private history: FigureSectionPoint[][] = []\n private lastValid: FigureSectionPoint[] = []\n private openedAt = 0\n private dragging: string | null = null\n /** The points as they were when a drag began: kept once the point moves, so a press alone is not a step back. */\n private dragFrom: FigureSectionPoint[] | null = null\n private extent = 200\n\n private get axis(): Axis {\n return (this.body?.shape.extrusion?.axis ?? 'y') as Axis\n }\n\n connectedCallback() {\n super.connectedCallback()\n const s = this.body?.shape.extrusion?.section\n this.working = s?.kind === 'polygon' ? s.points.map(p => ({ ...p })) : []\n this.lastValid = this.working\n this.openedAt = this.revision\n this.extent = extentOf(this.working, this.axis)\n window.addEventListener('keydown', this.keys, true)\n if (this.parentElement) this.room.observe(this.parentElement)\n }\n\n disconnectedCallback() {\n window.removeEventListener('keydown', this.keys, true)\n this.room.disconnect()\n super.disconnectedCallback()\n }\n\n /*\n * Heard first (capture on the window), and a key the editor takes goes no further: the scene behind listens too, and\n * would take Esc as \"select nothing\" and Delete as \"delete the part\".\n */\n private keys = (e: KeyboardEvent) => {\n const inField = (e.composedPath()[0] as HTMLElement)?.tagName === 'INPUT'\n const take = () => (e.preventDefault(), e.stopImmediatePropagation())\n if (e.key === 'Escape') {\n take()\n this.cancel()\n } else if ((e.key === 'Delete' || e.key === 'Backspace') && !inField && this.selected) {\n /* In a field the key deletes a character; outside, the chosen point. */\n take()\n this.removePoint(this.selected)\n } else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'z' && !inField) {\n take()\n this.back()\n }\n }\n\n private get stale() {\n return this.revision !== this.openedAt\n }\n\n private change(next: FigureSectionPoint[]) {\n this.history.push(this.working)\n this.working = next\n this.note = ''\n if (!issuesOf(next, this.axis).length) this.lastValid = next\n this.preview()\n }\n\n private back() {\n const before = this.history.pop()\n if (!before) return\n this.working = before\n if (!issuesOf(before, this.axis).length) this.lastValid = before\n this.preview()\n }\n\n /** The solid behind shows the working points, or the last valid ones while the working ones are refused. */\n private preview() {\n this.dispatchEvent(\n new CustomEvent('command-live', { detail: { action: this.action(this.lastValid) }, bubbles: true, composed: true })\n )\n }\n\n private action(points: Points): FigureAuthoringAction {\n return { kind: 'set-section-points', part: this.body!.id, points: points.map(p => ({ ...p })) }\n }\n\n private removePoint(id: string) {\n const next = removePoint(this.working, id)\n if ('refused' in next) {\n this.note = i18next.t('figure.text.section-issue-too-few')\n return\n }\n this.selected = null\n this.change(next)\n }\n\n private apply() {\n if (this.stale || issuesOf(this.working, this.axis).length) return\n this.dispatchEvent(new CustomEvent('command', { detail: { action: this.action(this.working) }, bubbles: true, composed: true }))\n this.close()\n }\n\n private cancel() {\n this.dispatchEvent(new CustomEvent('command-live', { detail: { action: null }, bubbles: true, composed: true }))\n this.close()\n }\n\n private close() {\n this.dispatchEvent(new CustomEvent('section-editor-close', { bubbles: true, composed: true }))\n }\n\n private svgPoint(e: PointerEvent): { h: number; v: number } {\n const el = this.renderRoot.querySelector('svg')!\n const pt = el.createSVGPoint()\n pt.x = e.clientX\n pt.y = e.clientY\n const p = pt.matrixTransform(el.getScreenCTM()!.inverse())\n return { h: Math.round(p.x), v: Math.round(p.y) }\n }\n\n render() {\n if (!this.body) return nothing\n const issues = issuesOf(this.working, this.axis)\n const length = this.body.shape.extrusion ? this.body.shape.extrusion.end - this.body.shape.extrusion.start : 0\n return html`\n <header>\n <h2>${i18next.t('figure.label.section-editor')}</h2>\n <span>${this.body.id} · ${i18next.t('figure.text.section-editor-length', { length: String(Math.round(length * 1000) / 1000) })}</span>\n </header>\n <nav tabs>\n ${(['outline', 'solid'] as const).map(\n one => html`<button ?on=${this.show === one} @click=${() => (this.show = one)}>${i18next.t(`figure.label.section-editor-${one}`)}</button>`\n )}\n </nav>\n <div body>\n <div outline>${this.drawing(issues)}</div>\n <aside>${this.list(issues)}</aside>\n </div>\n <footer>\n <button ?disabled=${!this.history.length} @click=${() => this.back()}>${i18next.t('figure.button.section-editor-back')}</button>\n <span grow ?stale=${this.stale}>\n ${this.stale ? i18next.t('figure.text.section-editor-stale') : i18next.t('figure.text.section-editor-hint')}\n </span>\n <button @click=${() => this.cancel()}>${i18next.t('figure.button.section-editor-cancel')}</button>\n <button primary ?disabled=${this.stale || issues.length > 0} @click=${() => this.apply()}>${i18next.t('figure.button.section-editor-apply')}</button>\n </footer>\n `\n }\n\n private drawing(issues: ReturnType<typeof issuesOf>) {\n const [h, v] = SCREEN[this.axis]\n const e = this.extent\n const marked = markedBy(issues)\n const pts = this.working\n const sides = pts.length >= 2 ? figureSectionSidesOf({ kind: 'polygon', points: pts }, this.axis) : []\n const at = (id: string) => pts.find(p => p.id === id)!\n const grid = Math.max(10, Math.pow(10, Math.floor(Math.log10(e))) / 2)\n const lines: number[] = []\n for (let g = -Math.floor(e / grid) * grid; g <= e; g += grid) lines.push(g)\n const invalid = issues.length > 0\n return html`<div caption ?last-valid=${invalid}>\n ${invalid ? i18next.t('figure.text.section-editor-last-valid') : i18next.t('figure.text.section-editor-units', { h: h.toUpperCase(), v: v.toUpperCase() })}\n </div>\n <svg\n viewBox=${`${-e} ${-e} ${2 * e} ${2 * e}`}\n role=\"img\"\n aria-label=${i18next.t('figure.label.section-editor')}\n @pointermove=${(ev: PointerEvent) => {\n if (!this.dragging) return\n if (this.dragFrom) this.history.push(this.dragFrom), (this.dragFrom = null)\n const p = this.svgPoint(ev)\n this.working = movePoint(this.working, this.dragging, { [h]: p.h, [v]: p.v })\n if (!issuesOf(this.working, this.axis).length) this.lastValid = this.working\n this.preview()\n }}\n @pointerup=${() => ((this.dragging = null), (this.dragFrom = null))}\n @pointerleave=${() => ((this.dragging = null), (this.dragFrom = null))}\n >\n ${svg`${lines.map(g => svg`<line x1=${g} y1=${-e} x2=${g} y2=${e} stroke=\"var(--md-sys-color-outline-variant)\" stroke-width=${e / 400} opacity=\"0.5\" />\n <line x1=${-e} y1=${g} x2=${e} y2=${g} stroke=\"var(--md-sys-color-outline-variant)\" stroke-width=${e / 400} opacity=\"0.5\" />`)}\n <line x1=${-e} y1=\"0\" x2=${e} y2=\"0\" stroke=\"var(--md-sys-color-outline)\" stroke-width=${e / 250} />\n <line x1=\"0\" y1=${-e} x2=\"0\" y2=${e} stroke=\"var(--md-sys-color-outline)\" stroke-width=${e / 250} />\n <text x=${e * 0.92} y=${-e * 0.02} font-size=${e / 18} fill=\"var(--md-sys-color-on-surface-variant)\">${h.toUpperCase()}</text>\n <text x=${e * 0.02} y=${e * 0.95} font-size=${e / 18} fill=\"var(--md-sys-color-on-surface-variant)\">${v.toUpperCase()}</text>\n ${invalid && this.lastValid.length\n ? svg`<polygon points=${this.lastValid.map(p => `${p[h]},${p[v]}`).join(' ')} fill=\"none\" stroke=\"var(--md-sys-color-outline)\" stroke-dasharray=${`${e / 50} ${e / 70}`} stroke-width=${e / 250} />`\n : nothing}\n <polygon points=${pts.map(p => `${p[h]},${p[v]}`).join(' ')} fill=${invalid ? 'none' : 'color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent)'} stroke=\"none\" />\n ${sides.map(s => {\n const a = at(s.from!),\n b = at(s.to!)\n const bad = marked.sides.has(s.id)\n return svg`<line x1=${a[h]} y1=${a[v]} x2=${b[h]} y2=${b[v]}\n stroke=${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'} stroke-width=${e / (bad ? 90 : 130)}\n stroke-dasharray=${bad ? `${e / 40} ${e / 80}` : ''} />\n <line side=${s.id} x1=${a[h]} y1=${a[v]} x2=${b[h]} y2=${b[v]} stroke=\"transparent\" stroke-width=${e / 25} style=\"cursor: copy\"\n @pointerdown=${(ev: PointerEvent) => {\n ev.stopPropagation()\n const made = insertAfter(this.working, s.from!, this.axis)\n this.change(made.points)\n this.selected = made.id\n }}><title>${i18next.t('figure.text.section-editor-add-here', { a: pointLabel(s.from!), b: pointLabel(s.to!) })}</title></line>`\n })}\n ${pts.map(p => {\n const bad = marked.points.has(p.id),\n on = this.selected === p.id\n return svg`<g point=${p.id} style=\"cursor: grab\"\n @pointerdown=${(ev: PointerEvent) => {\n ev.stopPropagation()\n ;(ev.target as Element).setPointerCapture?.(ev.pointerId)\n this.dragFrom = this.working\n this.selected = p.id\n this.dragging = p.id\n }}>\n <circle cx=${p[h]} cy=${p[v]} r=${e / (on ? 28 : 36)} fill=${bad ? 'var(--md-sys-color-error)' : on ? 'var(--md-sys-color-primary)' : 'var(--md-sys-color-surface)'}\n stroke=${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'} stroke-width=${e / 250} />\n <text x=${p[h]! + e / 22} y=${p[v]! - e / 22} font-size=${e / 16} font-weight=\"600\"\n fill=${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-on-surface)'}>${pointLabel(p.id)}</text>\n </g>`\n })}`}\n </svg>`\n }\n\n private list(issues: ReturnType<typeof issuesOf>) {\n const [h, v] = SCREEN[this.axis]\n const marked = markedBy(issues)\n return html`<ol points aria-label=${i18next.t('figure.label.section-editor-points')}>\n ${this.working.map(\n p => html`<li ?selected=${this.selected === p.id} ?marked=${marked.points.has(p.id)} @focusin=${() => (this.selected = p.id)}>\n <b>${pointLabel(p.id)}</b>\n ${([h, v] as const).map(\n axis => html`<input\n type=\"number\"\n step=\"any\"\n inputmode=\"decimal\"\n aria-label=${i18next.t('figure.label.section-editor-coordinate', { point: pointLabel(p.id), axis: axis.toUpperCase() })}\n .value=${live(String(p[axis] ?? ''))}\n @change=${(ev: Event) => {\n const input = ev.target as HTMLInputElement\n const value = Number(input.value)\n if (input.value === '' || !Number.isFinite(value)) {\n input.value = String(p[axis] ?? '')\n return\n }\n this.change(movePoint(this.working, p.id, { [axis]: value }))\n }}\n />`\n )}\n <button\n ?disabled=${this.working.length <= 3}\n title=${this.working.length <= 3 ? i18next.t('figure.text.section-issue-too-few') : ''}\n aria-label=${i18next.t('figure.button.section-editor-remove', { point: pointLabel(p.id) })}\n @click=${() => this.removePoint(p.id)}\n >\n ${i18next.t('figure.button.section-editor-remove', { point: pointLabel(p.id) })}\n </button>\n </li>`\n )}\n </ol>\n ${this.note ? html`<small role=\"status\">${this.note}</small>` : nothing}\n ${issues.length\n ? html`<ul issues role=\"alert\">\n ${issues.map(i => {\n const w = issueWords(i, this.working, this.axis)\n return html`<li>${i18next.t(w.key, w.params)}</li>`\n })}\n </ul>`\n : nothing}`\n }\n}\n"]}
@@ -1,28 +1,42 @@
1
- import { LitElement, nothing } from 'lit';
1
+ import { LitElement, nothing, type PropertyValues } from 'lit';
2
2
  import type { FigureEvaluatedShape } from '@hatiolab/figure-model';
3
+ type Body = {
4
+ id: string;
5
+ shape: FigureEvaluatedShape;
6
+ };
3
7
  declare const FigureSectionPanel_base: (new (...args: any[]) => LitElement) & typeof LitElement;
4
8
  /**
5
- * 단면 — a pushed part's rounded corners and its inside (ADR-0100 stage 1).
9
+ * 단면 — a pushed part's rounded corners and its inside (ADR-0100 §3.3).
6
10
  *
7
- * Only what the part's section has: corners for a rectangle, an inside for a rectangle or an ellipse. A drawn section
8
- * and a turned body show nothing here. A radius or a wall entered sets every corner or every wall to it; the kernel
9
- * holds per-axis values, and when they differ the field says so and shows none of them.
11
+ * Corners for a rectangle; an inside for a rectangle or an ellipse, with its walls (one thickness, or one per side when
12
+ * asked for), its two ends open or closed, and what that makes of the part and how deep. A drawn section says beside
13
+ * the inside why it has none. A turned body shows nothing here.
10
14
  *
11
- * Every change leaves as one `command`; the editor runs it through the session, one step of the undo history.
15
+ * A value being typed is drawn at once and recorded nowhere (`command-live`); a value the kernel would refuse is said
16
+ * under its field with the most it can be, and is not sent. Enter or leaving the field sends the one `command`, one step
17
+ * of the undo history; Esc puts the value back.
12
18
  */
13
19
  export declare class FigureSectionPanel extends FigureSectionPanel_base {
14
20
  static styles: import("lit").CSSResult[];
15
- body?: {
16
- id: string;
17
- shape: FigureEvaluatedShape;
18
- };
21
+ body?: Body;
19
22
  locked: boolean;
23
+ /** What each field would not take, by field, said under it. */
24
+ private refusals;
25
+ /** What is typed in a field and not yet sent, by field: the figure drawn with it must not type over it. */
26
+ private typed;
27
+ /** Walls one per side, asked for or because they already differ. */
28
+ private perSide;
29
+ protected willUpdate(changed: PropertyValues<this>): void;
20
30
  render(): import("lit-html").TemplateResult<1> | typeof nothing;
21
31
  private renderCorner;
22
32
  private renderCavity;
23
33
  private renderEnd;
24
- /** A thickness field: a positive number, committed on change; anything else puts the old value back. */
25
- private thickness;
34
+ /**
35
+ * A millimetre field. Typing draws the value (or, if the kernel would refuse it, says why under the field and draws the
36
+ * figure as it stands); Enter or leaving sends it once; Esc puts the value back.
37
+ */
38
+ private number;
39
+ private preview;
26
40
  private command;
27
41
  }
28
42
  export {};