@things-factory/figure-ui 10.1.222 → 10.1.224
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/canvas.ts +2 -2
- package/client/modeller/consumer-capabilities.ts +66 -0
- package/client/modeller/data-interface.ts +230 -80
- package/client/modeller/editor.ts +14 -7
- package/client/modeller/figure-capability-panel.ts +145 -1
- package/client/modeller/figure-data-panel.ts +495 -188
- package/client/modeller/figure-links.ts +130 -12
- package/client/modeller/figure-preview.ts +19 -2
- package/client/modeller/figure-slot-layout-panel.ts +7 -3
- package/client/modeller/links.ts +58 -0
- package/client/modeller/refusals.ts +12 -4
- package/client/modeller/slot-layout-host.ts +76 -5
- package/dist-client/modeller/canvas.js +2 -2
- package/dist-client/modeller/canvas.js.map +1 -1
- package/dist-client/modeller/consumer-capabilities.d.ts +29 -0
- package/dist-client/modeller/consumer-capabilities.js +60 -0
- package/dist-client/modeller/consumer-capabilities.js.map +1 -0
- package/dist-client/modeller/data-interface.d.ts +83 -17
- package/dist-client/modeller/data-interface.js +194 -82
- package/dist-client/modeller/data-interface.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +5 -2
- package/dist-client/modeller/editor.js +16 -5
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-capability-panel.d.ts +12 -0
- package/dist-client/modeller/figure-capability-panel.js +123 -1
- package/dist-client/modeller/figure-capability-panel.js.map +1 -1
- package/dist-client/modeller/figure-data-panel.d.ts +57 -13
- package/dist-client/modeller/figure-data-panel.js +461 -180
- package/dist-client/modeller/figure-data-panel.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +11 -0
- package/dist-client/modeller/figure-links.js +137 -16
- package/dist-client/modeller/figure-links.js.map +1 -1
- package/dist-client/modeller/figure-preview.d.ts +4 -0
- package/dist-client/modeller/figure-preview.js +19 -1
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-slot-layout-panel.js +6 -4
- package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -1
- package/dist-client/modeller/links.d.ts +22 -0
- package/dist-client/modeller/links.js +48 -0
- package/dist-client/modeller/links.js.map +1 -1
- package/dist-client/modeller/refusals.js +14 -6
- package/dist-client/modeller/refusals.js.map +1 -1
- package/dist-client/modeller/slot-layout-host.d.ts +28 -3
- package/dist-client/modeller/slot-layout-host.js +68 -6
- package/dist-client/modeller/slot-layout-host.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/test/browser/data-table-page.js +9 -0
- package/test/browser/links.check.mjs +25 -3
- package/test/consumer-capabilities.test.ts +116 -0
- package/test/data-motion.test.ts +94 -27
- package/test/links.test.ts +15 -0
- package/test/slot-layout-host.test.ts +63 -5
- package/translations/en.json +81 -23
- package/translations/es.json +81 -23
- package/translations/ja.json +81 -23
- package/translations/ko.json +81 -23
- package/translations/ms.json +81 -23
- package/translations/zh.json +81 -23
|
@@ -7,7 +7,8 @@ import './figure-size-editor.js';
|
|
|
7
7
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
8
8
|
import { i18next, localize } from '@operato/i18n';
|
|
9
9
|
import { figureFaceOverhangOf, figureMotionsOf, motionIdOf } from '@hatiolab/figure-model';
|
|
10
|
-
import { acceptsOf, AXES, canFasten, canFollow, positionIsShare, heldBy, shownWhenOf, visibilityControlsOf, fasteningOf, hasInstanceSize, holdsThings, leadersFor, motionOf, motionFormOf, motionFormRefusalOf, endPlaceKeyOf, motionJoint, controlIdFor, withoutAxis, placeFacesOf, placeIdFor, placesOn, rowAxesOf, rowBlockOf, fixedJointOf, rowOf, positionsWorkedOut } from './links.js';
|
|
10
|
+
import { acceptsOf, AXES, canFasten, canFollow, positionIsShare, heldBy, shownWhenOf, visibilityControlsOf, fasteningOf, hasInstanceSize, holdsThings, leadersFor, motionOf, motionFormOf, motionFormRefusalOf, endPlaceKeyOf, motionJoint, controlIdFor, withoutAxis, placeFacesOf, placeIdFor, placesOn, rowAxesOf, rowBlockOf, fixedJointOf, rowOf, positionsWorkedOut, followOf, followableAxes, measureNow, freshStateSize, stateSizeIdFor, stateSizeCommandOf, stateSizeFixedOf } from './links.js';
|
|
11
|
+
import { measureFactor } from './size-response.js';
|
|
11
12
|
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
|
|
12
13
|
import { insideAlignmentOf } from './fasten-geometry.js';
|
|
13
14
|
import { fastenFormOf, fastenPlanOf, fastenSentenceOf } from './fasten-form.js';
|
|
@@ -62,7 +63,11 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
62
63
|
/** Why 정렬·간격 고치기 moved nothing, said under it; empty once it moved the part or the part changed. */
|
|
63
64
|
this.fixNote = '';
|
|
64
65
|
this.motion = freshMotion();
|
|
66
|
+
/* The form for a measure a control sets (「상태에 따라 크기」). */
|
|
67
|
+
this.stateSize = freshStateSize();
|
|
65
68
|
this.place = freshPlace();
|
|
69
|
+
/** The id of the place the form changes, kept so the place keeps its id (a release refuses a place id that goes); null adds one. */
|
|
70
|
+
this.placeEditing = null;
|
|
66
71
|
this.row = freshRow();
|
|
67
72
|
/** The motion form is open over the part's own motion, to change it where it is. */
|
|
68
73
|
this.editingMotion = false;
|
|
@@ -151,6 +156,7 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
151
156
|
this.loadedFor = this.partId;
|
|
152
157
|
this.motion = freshMotion();
|
|
153
158
|
this.place = freshPlace();
|
|
159
|
+
this.placeEditing = null;
|
|
154
160
|
this.row = freshRow();
|
|
155
161
|
this.rowOpen = false;
|
|
156
162
|
this.rowCandidate = undefined;
|
|
@@ -186,7 +192,7 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
186
192
|
return nothing;
|
|
187
193
|
if (this.section === 'motion')
|
|
188
194
|
return html `<section><h3>${i18next.t('figure.label.motion')}${this.help.button('figure.text.motion-explained')}</h3>${this.help.hint('figure.text.motion-explained')}
|
|
189
|
-
${this.renderMotion(asset)}${this.renderShown(asset)}</section>`;
|
|
195
|
+
${this.renderMotion(asset)}${this.renderShown(asset)}${this.renderStateSize(asset)}</section>`;
|
|
190
196
|
if (this.section === 'places') {
|
|
191
197
|
/*
|
|
192
198
|
One idea, places, two ways to make them (ADR-0118): one at a time on this part, or many by a rule -- the figure's
|
|
@@ -253,6 +259,11 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
253
259
|
this.candidate = this.fastenCandidate;
|
|
254
260
|
return shown;
|
|
255
261
|
}
|
|
262
|
+
/** A place on this part into the form, to change it under its own id. */
|
|
263
|
+
editPlace(one) {
|
|
264
|
+
this.placeEditing = one.id;
|
|
265
|
+
this.place = { role: one.role, face: one.face ?? 'top', label: one.label, accepts: (one.accepts ?? []).join(', '), capacity: one.capacity };
|
|
266
|
+
}
|
|
256
267
|
/** Where things are held on this part: a seat things rest on, or a grip things are held in. */
|
|
257
268
|
renderPlaces(asset) {
|
|
258
269
|
const faces = placeFacesOf(asset, this.partId);
|
|
@@ -267,6 +278,9 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
267
278
|
<b bound>${one.label}</b>
|
|
268
279
|
<small>${one.face ? i18next.t('figure.label.face-' + one.face) + ' · ' : ''}${placeTerms(one, (key, params) => i18next.t(key, params))}</small>
|
|
269
280
|
</span>
|
|
281
|
+
<button quiet edit-place ?disabled=${this.locked} @click=${() => this.editPlace(one)}>
|
|
282
|
+
<md-icon>edit</md-icon>${i18next.t('figure.button.edit-place')}
|
|
283
|
+
</button>
|
|
270
284
|
<button quiet ?disabled=${this.locked} @click=${() => this.command({ kind: 'remove-binding', id: one.id })}>
|
|
271
285
|
<md-icon>close</md-icon>${i18next.t('figure.button.remove-place')}
|
|
272
286
|
</button>
|
|
@@ -290,27 +304,35 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
290
304
|
<span>${i18next.t('figure.label.place-name')}</span>
|
|
291
305
|
<input .value=${p.label} placeholder=${roleName(p.role)} @change=${(e) => (this.place = { ...p, label: e.target.value })} />
|
|
292
306
|
<span>${i18next.t('figure.label.place-accepts')}</span>
|
|
293
|
-
<input .value=${p.accepts} placeholder
|
|
307
|
+
<input .value=${p.accepts} placeholder=${i18next.t('figure.text.place-accepts-any')} @input=${(e) => (this.place = { ...p, accepts: e.target.value })} />
|
|
294
308
|
<span>${i18next.t('figure.label.place-capacity')}</span>
|
|
295
309
|
<input type="number" min="1" step="1" .value=${String(p.capacity)} @change=${(e) => (this.place = { ...p, capacity: e.target.valueAsNumber })} />
|
|
296
310
|
</div>
|
|
297
|
-
${accepts.length ? nothing : html `<small>${i18next.t('figure.text.place-accepts-needed')}</small>`}
|
|
298
311
|
<button
|
|
299
312
|
act
|
|
300
|
-
?disabled=${this.locked || !
|
|
301
|
-
@click=${() =>
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
313
|
+
?disabled=${this.locked || !capacityOk}
|
|
314
|
+
@click=${() => {
|
|
315
|
+
this.command({
|
|
316
|
+
kind: 'add-binding',
|
|
317
|
+
id: this.placeEditing ?? placeIdFor(asset, this.partId, p.role),
|
|
318
|
+
label: p.label.trim() || roleName(p.role),
|
|
319
|
+
role: p.role,
|
|
320
|
+
part: this.partId,
|
|
321
|
+
face,
|
|
322
|
+
/* None named: it takes any item (ADR-0051 §4.1 decision 5). */
|
|
323
|
+
...(accepts.length ? { accepts } : {}),
|
|
324
|
+
capacity: p.capacity,
|
|
325
|
+
...(this.placeEditing ? { replace: true } : {})
|
|
326
|
+
});
|
|
327
|
+
this.placeEditing = null;
|
|
328
|
+
this.place = freshPlace();
|
|
329
|
+
}}
|
|
311
330
|
>
|
|
312
|
-
<md-icon>back_hand</md-icon>${i18next.t('figure.button.add-place')}
|
|
331
|
+
<md-icon>back_hand</md-icon>${i18next.t(this.placeEditing ? 'figure.button.save-place' : 'figure.button.add-place')}
|
|
313
332
|
</button>
|
|
333
|
+
${this.placeEditing
|
|
334
|
+
? html `<button quiet @click=${() => ((this.placeEditing = null), (this.place = freshPlace()))}>${i18next.t('figure.button.cancel-place-edit')}</button>`
|
|
335
|
+
: nothing}
|
|
314
336
|
`;
|
|
315
337
|
}
|
|
316
338
|
/** The figure holds things: `Capacity` and `Holdable`, the ladder's middle rung. One part edit, one undo step. */
|
|
@@ -519,6 +541,97 @@ let FigureLinks = class FigureLinks extends localize(i18next)(LitElement) {
|
|
|
519
541
|
* When the part is drawn: always, or while a control is at least a value -- a lamp lit while the gate is open. One
|
|
520
542
|
* part edit (`set-visibility`), one step. Offered once the figure has a control; a motion is what makes one.
|
|
521
543
|
*/
|
|
544
|
+
/**
|
|
545
|
+
* A measure a control sets (modeller snag C1, 2026-10-26): a wound roll shrinking to its core. Each measure that does is
|
|
546
|
+
* one line with the way back to a fixed number; the form makes another. Measures read as the size row shows them --
|
|
547
|
+
* a cylinder's X as its diameter.
|
|
548
|
+
*/
|
|
549
|
+
renderStateSize(asset) {
|
|
550
|
+
const revision = this.revision;
|
|
551
|
+
if (!revision)
|
|
552
|
+
return nothing;
|
|
553
|
+
const part = this.partId;
|
|
554
|
+
const axes = followableAxes(asset, part);
|
|
555
|
+
if (!axes.length)
|
|
556
|
+
return nothing;
|
|
557
|
+
const word = (axis) => `${axis.toUpperCase()}${measureFactor(asset, part, axis) === 2 ? ' · ' + i18next.t('figure.label.size-diameter') : ''}`;
|
|
558
|
+
const unitWord = (unit) => i18next.t(`figure.label.state-unit-${unit}`);
|
|
559
|
+
const sized = axes.flatMap(axis => {
|
|
560
|
+
const f = followOf(asset, part, axis);
|
|
561
|
+
return f.of === 'state' ? [{ axis, f }] : [];
|
|
562
|
+
});
|
|
563
|
+
const free = axes.filter(axis => !sized.some(one => one.axis === axis));
|
|
564
|
+
const form = this.stateSize;
|
|
565
|
+
const axis = form.axis && free.includes(form.axis) ? form.axis : free[0] ?? '';
|
|
566
|
+
const factor = axis ? measureFactor(asset, part, axis) : 1;
|
|
567
|
+
const atMax = Number.isFinite(form.atMax) ? form.atMax : axis ? (measureNow(revision, part, axis) ?? NaN) : NaN;
|
|
568
|
+
const id = form.id || stateSizeIdFor(asset, part);
|
|
569
|
+
const controls = visibilityControlsOf(asset);
|
|
570
|
+
const command = stateSizeCommandOf(asset, part, { ...form, axis, atMax }, factor, id);
|
|
571
|
+
/* A control already there is taken with its unit and range; another unit or range would be refused. */
|
|
572
|
+
const pickControl = (value) => {
|
|
573
|
+
const there = controls.find(c => c.id === value);
|
|
574
|
+
this.stateSize = there && ['percent', 'ratio', 'mm'].includes(there.unit)
|
|
575
|
+
? { ...form, id: value, unit: there.unit, min: there.min, max: there.max }
|
|
576
|
+
: { ...form, id: value };
|
|
577
|
+
};
|
|
578
|
+
const number = (key) => (e) => (this.stateSize = { ...form, axis, [key]: e.target.valueAsNumber });
|
|
579
|
+
return html `<h4 state-size>${i18next.t('figure.label.state-size')}</h4>
|
|
580
|
+
${sized.map(({ axis: one, f }) => {
|
|
581
|
+
const k = measureFactor(asset, part, one);
|
|
582
|
+
const input = controls.find(c => c.id === f.input);
|
|
583
|
+
return html `<div pair state-size-row=${one}>
|
|
584
|
+
<span>${word(one)}
|
|
585
|
+
<small>${i18next.t('figure.text.state-size-row', {
|
|
586
|
+
control: input?.label ?? f.input,
|
|
587
|
+
min: String(input?.min ?? ''),
|
|
588
|
+
max: String(input?.max ?? ''),
|
|
589
|
+
unit: input ? unitWord(input.unit) : '',
|
|
590
|
+
from: String(Math.round(f.at.min * k * 1000) / 1000),
|
|
591
|
+
to: String(Math.round(f.at.max * k * 1000) / 1000)
|
|
592
|
+
})}</small>
|
|
593
|
+
</span>
|
|
594
|
+
<button act ?disabled=${this.locked} @click=${() => {
|
|
595
|
+
const back = stateSizeFixedOf(asset, part, one);
|
|
596
|
+
if (back)
|
|
597
|
+
this.command(back);
|
|
598
|
+
}}><md-icon>close</md-icon>${i18next.t('figure.button.state-size-fix')}</button>
|
|
599
|
+
</div>`;
|
|
600
|
+
})}
|
|
601
|
+
${free.length
|
|
602
|
+
? html `<div form state-size-form>
|
|
603
|
+
<span>${i18next.t('figure.label.state-size-measure')}</span>
|
|
604
|
+
<select ?disabled=${this.locked} @change=${(e) => (this.stateSize = { ...form, axis: e.target.value, atMax: NaN })}>
|
|
605
|
+
${free.map(one => html `<option value=${one} ?selected=${one === axis}>${word(one)}</option>`)}
|
|
606
|
+
</select>
|
|
607
|
+
<span>${i18next.t('figure.label.control-id')}</span>
|
|
608
|
+
<input list="state-size-controls" .value=${id} ?disabled=${this.locked} @change=${(e) => pickControl(e.target.value.trim())} />
|
|
609
|
+
<datalist id="state-size-controls">${controls.map(c => html `<option value=${c.id}>${c.label}</option>`)}</datalist>
|
|
610
|
+
<span>${i18next.t('figure.label.state-size-unit')}</span>
|
|
611
|
+
<select ?disabled=${this.locked} @change=${(e) => {
|
|
612
|
+
const unit = e.target.value;
|
|
613
|
+
this.stateSize = { ...form, axis, unit, ...(unit === 'percent' ? { min: 0, max: 100 } : unit === 'ratio' ? { min: 0, max: 1 } : {}) };
|
|
614
|
+
}}>
|
|
615
|
+
${['percent', 'ratio', 'mm'].map(u => html `<option value=${u} ?selected=${u === form.unit}>${unitWord(u)}</option>`)}
|
|
616
|
+
</select>
|
|
617
|
+
<span>${i18next.t('figure.label.control-range')} (${unitWord(form.unit)})</span>
|
|
618
|
+
<div pair>
|
|
619
|
+
<input type="number" step="any" .value=${String(form.min)} ?disabled=${this.locked} @change=${number('min')} />
|
|
620
|
+
<input type="number" step="any" .value=${String(form.max)} ?disabled=${this.locked} @change=${number('max')} />
|
|
621
|
+
</div>
|
|
622
|
+
<span>${i18next.t('figure.label.state-size-at-min')} (mm)</span>
|
|
623
|
+
<input type="number" step="any" min="0" state-size-at-min .value=${Number.isFinite(form.atMin) ? String(form.atMin) : ''} ?disabled=${this.locked} @change=${number('atMin')} />
|
|
624
|
+
<span>${i18next.t('figure.label.state-size-at-max')} (mm)</span>
|
|
625
|
+
<input type="number" step="any" min="0" state-size-at-max .value=${Number.isFinite(atMax) ? String(atMax) : ''} ?disabled=${this.locked} @change=${number('atMax')} />
|
|
626
|
+
</div>
|
|
627
|
+
<button act add-state-size ?disabled=${this.locked || !command} @click=${() => {
|
|
628
|
+
if (!command)
|
|
629
|
+
return;
|
|
630
|
+
this.command(command);
|
|
631
|
+
this.stateSize = freshStateSize();
|
|
632
|
+
}}><md-icon>open_in_full</md-icon>${i18next.t('figure.button.add-state-size')}</button>`
|
|
633
|
+
: nothing}`;
|
|
634
|
+
}
|
|
522
635
|
renderShown(asset) {
|
|
523
636
|
const controls = visibilityControlsOf(asset);
|
|
524
637
|
if (!controls.length)
|
|
@@ -783,10 +896,18 @@ __decorate([
|
|
|
783
896
|
state(),
|
|
784
897
|
__metadata("design:type", Object)
|
|
785
898
|
], FigureLinks.prototype, "motion", void 0);
|
|
899
|
+
__decorate([
|
|
900
|
+
state(),
|
|
901
|
+
__metadata("design:type", Object)
|
|
902
|
+
], FigureLinks.prototype, "stateSize", void 0);
|
|
786
903
|
__decorate([
|
|
787
904
|
state(),
|
|
788
905
|
__metadata("design:type", Object)
|
|
789
906
|
], FigureLinks.prototype, "place", void 0);
|
|
907
|
+
__decorate([
|
|
908
|
+
state(),
|
|
909
|
+
__metadata("design:type", Object)
|
|
910
|
+
], FigureLinks.prototype, "placeEditing", void 0);
|
|
790
911
|
__decorate([
|
|
791
912
|
state(),
|
|
792
913
|
__metadata("design:type", String)
|