@things-factory/figure-ui 10.1.193 → 10.1.195
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/editor-styles.ts +10 -3
- package/client/modeller/editor.ts +61 -47
- package/client/modeller/figure-fasten-dialog.ts +11 -5
- package/client/modeller/refusal-teller.ts +8 -0
- package/client/pages/figure-list-page.ts +27 -40
- package/client/pages/figure-public-list-page.ts +21 -0
- package/client/route.ts +4 -0
- package/dist-client/modeller/editor-styles.js +10 -3
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +18 -9
- package/dist-client/modeller/editor.js +62 -46
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-fasten-dialog.d.ts +3 -3
- package/dist-client/modeller/figure-fasten-dialog.js +11 -5
- package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
- package/dist-client/modeller/refusal-teller.d.ts +8 -0
- package/dist-client/modeller/refusal-teller.js +7 -0
- package/dist-client/modeller/refusal-teller.js.map +1 -1
- package/dist-client/pages/figure-list-page.d.ts +6 -3
- package/dist-client/pages/figure-list-page.js +25 -42
- package/dist-client/pages/figure-list-page.js.map +1 -1
- package/dist-client/pages/figure-public-list-page.d.ts +16 -0
- package/dist-client/pages/figure-public-list-page.js +21 -0
- package/dist-client/pages/figure-public-list-page.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +3 -0
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/test/align.test.ts +13 -5
- package/test/browser/editing.check.mjs +9 -13
- package/test/browser/links.check.mjs +36 -22
- package/test/browser/list-page.js +35 -0
- package/test/browser/list.check.mjs +68 -0
- package/test/browser/modeller-page.js +48 -4
- package/test/browser/product-page.js +6 -0
- package/test/browser/props.check.mjs +2 -2
- package/test/figure-released.test.ts +1 -1
- package/things-factory.config.js +1 -0
- package/translations/en.json +4 -6
- package/translations/es.json +4 -6
- package/translations/ja.json +4 -6
- package/translations/ko.json +4 -6
- package/translations/ms.json +4 -6
- package/translations/zh.json +4 -6
|
@@ -80,8 +80,10 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
80
80
|
this.error = '';
|
|
81
81
|
this.tab = 'properties';
|
|
82
82
|
/**
|
|
83
|
-
* The fastening window open for the selected part (user 2026-10-17),
|
|
84
|
-
*
|
|
83
|
+
* The fastening window open for the selected part (user 2026-10-17): chosen there, applied once. It stands over the
|
|
84
|
+
* side panel, not over the canvas, so what is chosen is seen in 3D as it is chosen (user 2026-10-19: the standard
|
|
85
|
+
* popup, always modal, covered the preview). It closes with nothing written when the part, the tab, the middle or a
|
|
86
|
+
* bar panel changes under it.
|
|
85
87
|
*/
|
|
86
88
|
this.fastening = false;
|
|
87
89
|
/** Why the window's 「적용」 was refused, said in it. */
|
|
@@ -219,7 +221,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
219
221
|
aria-pressed=${String(this.gizmoMode === tool.mode)}
|
|
220
222
|
?disabled=${!tool.can}
|
|
221
223
|
aria-label=${i18next.t('figure.button.gizmo-' + tool.mode)}
|
|
222
|
-
title=${`${i18next.t('figure.button.gizmo-' + tool.mode)} (${tool.key})${tool.can || !this.selected ? '' : ' · ' +
|
|
224
|
+
title=${`${i18next.t('figure.button.gizmo-' + tool.mode)} (${tool.key})${tool.can || !this.selected ? '' : ' · ' + (tool.mode === 'scale' && this.sizeDragUnsure(this.asset(), this.selected) ? this.sizeDragRefusalOf(this.selected) : i18next.t('figure.text.gizmo-not-own'))}`}
|
|
223
225
|
@click=${() => this.useGizmo(tool.mode)}
|
|
224
226
|
>
|
|
225
227
|
<md-icon>${tool.icon}</md-icon>
|
|
@@ -261,7 +263,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
261
263
|
if (_changed.has('selected'))
|
|
262
264
|
this.gizmoMode = undefined;
|
|
263
265
|
/* The window is about the part chosen on the properties tab, being edited: it does not follow anywhere else. */
|
|
264
|
-
if (this.fastening && (_changed.has('selected') || !this.selected || this.tab !== 'properties' || this.middle !== 'edit'))
|
|
266
|
+
if (this.fastening && (_changed.has('selected') || !this.selected || this.tab !== 'properties' || this.middle !== 'edit' || this.overlay))
|
|
265
267
|
this.closeFastening();
|
|
266
268
|
/*
|
|
267
269
|
* The section editor is of one part: when the selection moves off it by any way -- another part picked, the scene's
|
|
@@ -295,7 +297,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
295
297
|
if (mode === 'scale' && this.selected && this.gizmoMode !== 'scale') {
|
|
296
298
|
const asset = this.asset();
|
|
297
299
|
if (asset && this.sizeDragUnsure(asset, this.selected)) {
|
|
298
|
-
this.
|
|
300
|
+
this.tellSizeByFields(this.selected);
|
|
299
301
|
return;
|
|
300
302
|
}
|
|
301
303
|
}
|
|
@@ -575,6 +577,28 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
575
577
|
return true;
|
|
576
578
|
}
|
|
577
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* Why this part's size is not dragged, in one line (user 2026-10-19: the reason told the faces kept, and was not
|
|
582
|
+
* understood): attached turned or twisted, or turned off its upright.
|
|
583
|
+
*/
|
|
584
|
+
sizeDragRefusalOf(id) {
|
|
585
|
+
const fastened = !!this.asset()?.joints?.some(j => j.body1.part === ownerOf(id));
|
|
586
|
+
return i18next.t(fastened ? 'figure.text.gizmo-size-turned-fastening' : 'figure.text.gizmo-size-tilted', { part: partLabelOf(id) });
|
|
587
|
+
}
|
|
588
|
+
/** The size drag refused, said as a notice with the way to the part's size fields. */
|
|
589
|
+
tellSizeByFields(id) {
|
|
590
|
+
this.refusals.point(this.sizeDragRefusalOf(id), { label: i18next.t('figure.button.to-size-fields'), run: () => this.toSizeFields(id) });
|
|
591
|
+
}
|
|
592
|
+
/** To the part's first size field it takes typed, on the properties tab, ready to type over. */
|
|
593
|
+
async toSizeFields(id) {
|
|
594
|
+
this.middle = 'edit';
|
|
595
|
+
this.tab = 'properties';
|
|
596
|
+
this.selected = id;
|
|
597
|
+
await this.updateComplete;
|
|
598
|
+
const field = this.renderRoot.querySelector('[slot="size"] input:not([disabled]):not([readonly])');
|
|
599
|
+
field?.focus();
|
|
600
|
+
field?.select();
|
|
601
|
+
}
|
|
578
602
|
/** A drag, written back as the part's own inputs — one step of the history, like typing the numbers. */
|
|
579
603
|
transformed(id, result) {
|
|
580
604
|
const view = this.session.read();
|
|
@@ -603,7 +627,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
603
627
|
const jointed = !!asset.joints?.some(j => j.body1.part === ownerOf(id));
|
|
604
628
|
/* A size drag this part cannot show truly is not written: it springs back, and the reason is said. */
|
|
605
629
|
if (result.scale && result.scale.some(k => Math.abs(k - 1) > 1e-4) && this.sizeDragUnsure(asset, id)) {
|
|
606
|
-
this.
|
|
630
|
+
this.tellSizeByFields(id);
|
|
607
631
|
return this.requestUpdate();
|
|
608
632
|
}
|
|
609
633
|
/*
|
|
@@ -681,10 +705,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
681
705
|
* fastened. Refused, it says why.
|
|
682
706
|
*/
|
|
683
707
|
/* What a tilted part's typed size keeps, by the figure's placement: not the floor's lowest point everywhere (designer 2026-09-27). */
|
|
684
|
-
keptExtremeWord() {
|
|
685
|
-
const placement = (this.asset())?.placement ?? 'floor';
|
|
686
|
-
return i18next.t(`figure.label.kept-extreme-${placement}`);
|
|
687
|
-
}
|
|
688
708
|
/* How the selected part would meet the plane, worked out once per version and part. */
|
|
689
709
|
planeContactOf(shown, part) {
|
|
690
710
|
return derivedOf(shown, `plane-contact|${part}`, () => {
|
|
@@ -886,6 +906,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
886
906
|
renderOverlay() {
|
|
887
907
|
const close = () => (this.overlay = undefined);
|
|
888
908
|
const panel = (which, label, body) => html `<div
|
|
909
|
+
side-overlay
|
|
889
910
|
bar-overlay-panel=${which}
|
|
890
911
|
role="dialog"
|
|
891
912
|
aria-label=${i18next.t(label)}
|
|
@@ -1458,50 +1479,46 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1458
1479
|
this.openFastening();
|
|
1459
1480
|
}
|
|
1460
1481
|
openFastening() {
|
|
1461
|
-
if (!this.selected || this.
|
|
1482
|
+
if (!this.selected || this.fastening)
|
|
1462
1483
|
return;
|
|
1463
1484
|
this.fastenError = '';
|
|
1464
1485
|
this.fastenHover = null;
|
|
1486
|
+
/* One panel over the side at a time: the view or the history gives way to the window. */
|
|
1487
|
+
this.overlay = undefined;
|
|
1465
1488
|
this.fastening = true;
|
|
1466
|
-
const content = document.createElement('figure-fasten-dialog');
|
|
1467
|
-
content.addEventListener('preview-command', e => this.commandPreview.ask(e.detail));
|
|
1468
|
-
content.addEventListener('fasten-hover', e => this.hoverFastening(e.detail));
|
|
1469
|
-
content.addEventListener('fasten-apply', e => this.applyFastening(e.detail.action));
|
|
1470
|
-
content.addEventListener('fasten-cancel', () => this.closeFastening());
|
|
1471
|
-
this.fastenWindow = content;
|
|
1472
|
-
this.tellFastening();
|
|
1473
|
-
const popup = openPopup(html `${content}`, { title: i18next.t('figure.label.fastening'), size: 'fit', backdrop: true, movable: true, closable: true, escapable: true });
|
|
1474
|
-
this.fastenPopup = popup;
|
|
1475
|
-
/* Closed by its own X or Esc as well: the editor lets go of it the same way. */
|
|
1476
|
-
popup.result.then(() => this.fastenPopup === popup && this.fastenClosed());
|
|
1477
1489
|
}
|
|
1478
1490
|
closeFastening() {
|
|
1479
|
-
const popup = this.fastenPopup;
|
|
1480
|
-
this.fastenClosed();
|
|
1481
|
-
popup?.close();
|
|
1482
|
-
}
|
|
1483
|
-
fastenClosed() {
|
|
1484
|
-
this.fastenPopup = undefined;
|
|
1485
|
-
this.fastenWindow = undefined;
|
|
1486
1491
|
this.fastening = false;
|
|
1487
1492
|
this.fastenError = '';
|
|
1488
1493
|
this.fastenHover = null;
|
|
1489
1494
|
}
|
|
1490
|
-
/**
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1495
|
+
/**
|
|
1496
|
+
* The fastening window over the side panel, as the bar's panels stand there: the figure on screen, the part, and what
|
|
1497
|
+
* the preview and a refusal said are the editor's. Its own Esc and 「취소」 close it, as its X does.
|
|
1498
|
+
*/
|
|
1499
|
+
renderFastening(unavailable) {
|
|
1500
|
+
if (!this.fastening || !this.selected)
|
|
1501
|
+
return nothing;
|
|
1502
|
+
return html `<div side-overlay fasten-panel>
|
|
1503
|
+
<div overlay-head>
|
|
1504
|
+
<h3>${i18next.t('figure.label.fastening')}</h3>
|
|
1505
|
+
<button quiet fasten-close aria-label=${i18next.t('figure.button.close')} title=${i18next.t('figure.button.close')} @click=${() => this.closeFastening()}>
|
|
1506
|
+
<md-icon>close</md-icon>
|
|
1507
|
+
</button>
|
|
1508
|
+
</div>
|
|
1509
|
+
<figure-fasten-dialog
|
|
1510
|
+
overlay-body
|
|
1511
|
+
.revision=${this.shown()}
|
|
1512
|
+
.partId=${this.selected}
|
|
1513
|
+
?locked=${unavailable}
|
|
1514
|
+
.previewWords=${this.commandPreview.words()}
|
|
1515
|
+
.error=${this.fastenError}
|
|
1516
|
+
@preview-command=${(e) => this.commandPreview.ask(e.detail)}
|
|
1517
|
+
@fasten-hover=${(e) => this.hoverFastening(e.detail)}
|
|
1518
|
+
@fasten-apply=${(e) => this.applyFastening(e.detail.action)}
|
|
1519
|
+
@fasten-cancel=${() => this.closeFastening()}
|
|
1520
|
+
></figure-fasten-dialog>
|
|
1521
|
+
</div>`;
|
|
1505
1522
|
}
|
|
1506
1523
|
/** 「적용」: the command, one step; refused, the window stays open and says why. */
|
|
1507
1524
|
applyFastening(action) {
|
|
@@ -1573,7 +1590,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1573
1590
|
}
|
|
1574
1591
|
updated(changed) {
|
|
1575
1592
|
super.updated?.(changed);
|
|
1576
|
-
this.tellFastening();
|
|
1577
1593
|
/* Nothing blocks release any more: the list under the bar closes, and opens fresh when something does again. */
|
|
1578
1594
|
if (changed.has('releaseBlockers') && !this.releaseBlockers.length && this.blockersOpen)
|
|
1579
1595
|
this.blockersOpen = false;
|
|
@@ -1964,7 +1980,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1964
1980
|
<div panel flush ?off=${tab !== 'verdict'}><slot name="verdict"></slot></div>
|
|
1965
1981
|
</aside>
|
|
1966
1982
|
</ox-three-pane>
|
|
1967
|
-
${this.renderOverlay()}`;
|
|
1983
|
+
${this.renderOverlay()} ${this.renderFastening(unavailable)}`;
|
|
1968
1984
|
}
|
|
1969
1985
|
/** Position, rotation and size as rows of three cells; the shape's own measures one to a line, under their title. */
|
|
1970
1986
|
renderGroups(groups, vectorTitle, singleTitle, unavailable, tools = null, held) {
|