@things-factory/figure-ui 10.1.206 → 10.1.208
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.ts +11 -97
- package/client/modeller/figure-facts.ts +1 -1
- package/client/modeller/figure-history-panel.ts +1 -29
- package/client/modeller/figure-preview.ts +5 -7
- package/client/modeller/figure-verdict.ts +2 -17
- package/client/modeller/maturity.ts +11 -27
- package/client/modeller/refusals.ts +1 -7
- package/client/pages/figure-modeller-page.ts +7 -22
- package/dist-client/modeller/editor.d.ts +1 -8
- package/dist-client/modeller/editor.js +12 -98
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-facts.js +1 -1
- package/dist-client/modeller/figure-facts.js.map +1 -1
- package/dist-client/modeller/figure-fasten-dialog.d.ts +1 -1
- package/dist-client/modeller/figure-history-panel.d.ts +0 -16
- package/dist-client/modeller/figure-history-panel.js +1 -27
- package/dist-client/modeller/figure-history-panel.js.map +1 -1
- package/dist-client/modeller/figure-links.d.ts +1 -1
- package/dist-client/modeller/figure-preview.js +5 -8
- package/dist-client/modeller/figure-preview.js.map +1 -1
- package/dist-client/modeller/figure-verdict.d.ts +0 -5
- package/dist-client/modeller/figure-verdict.js +2 -21
- package/dist-client/modeller/figure-verdict.js.map +1 -1
- package/dist-client/modeller/maturity.d.ts +2 -4
- package/dist-client/modeller/maturity.js +12 -26
- package/dist-client/modeller/maturity.js.map +1 -1
- package/dist-client/modeller/refusals.d.ts +1 -3
- package/dist-client/modeller/refusals.js +1 -7
- package/dist-client/modeller/refusals.js.map +1 -1
- package/dist-client/pages/figure-modeller-page.d.ts +1 -3
- package/dist-client/pages/figure-modeller-page.js +7 -23
- package/dist-client/pages/figure-modeller-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/test/browser/acceptance-page.js +3 -3
- package/test/browser/detail-page.js +1 -3
- package/test/browser/detail-tabs-page.js +1 -2
- package/test/browser/links.check.mjs +2 -37
- package/test/browser/modeller.check.mjs +1 -3
- package/test/browser/parts-page.js +2 -2
- package/test/browser/parts.check.mjs +2 -12
- package/test/browser/product-page.check.mjs +6 -9
- package/test/browser/product-page.js +1 -2
- package/test/browser/screen-page.js +2 -6
- package/test/browser/screen.check.mjs +8 -65
- package/test/first-minute.test.ts +2 -3
- package/test/fixtures/joint-column.json +1 -66
- package/test/fixtures/joint-roller.json +1 -66
- package/test/fixtures/robot-arm-6dof.json +2 -67
- package/test/harness-serve.test.ts +1 -1
- package/test/heading-scale-guard.test.ts +3 -3
- package/test/links.test.ts +1 -1
- package/test/parts-wiring.test.ts +1 -1
- package/test/properties.test.ts +9 -12
- package/test/refusals.test.ts +3 -21
- package/test/resize-with-placement.test.ts +13 -15
- package/test/revision.test.ts +1 -2
- package/test/verdict.test.ts +1 -15
- package/translations/en.json +0 -19
- package/translations/es.json +0 -19
- package/translations/ja.json +0 -19
- package/translations/ko.json +9 -28
- package/translations/ms.json +0 -19
- package/translations/zh.json +0 -19
- package/client/modeller/occupancy.ts +0 -51
- package/dist-client/modeller/occupancy.d.ts +0 -31
- package/dist-client/modeller/occupancy.js +0 -36
- package/dist-client/modeller/occupancy.js.map +0 -1
- package/test/release-panel.test.ts +0 -53
|
@@ -4,10 +4,9 @@ import { LitElement, html, nothing } from 'lit';
|
|
|
4
4
|
import { i18next } from '@operato/i18n';
|
|
5
5
|
import '@operato/layout';
|
|
6
6
|
import { openPopup } from '@operato/layout';
|
|
7
|
-
import { OxPrompt } from '@operato/popup';
|
|
8
7
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
9
8
|
import { live } from 'lit/directives/live.js';
|
|
10
|
-
import { figurePartFaceOf, PART_LIMIT, parseFigureRecipe, resolveFigureRecipe, figurePartCountOf, figurePartIdFor, figureRecipeIdFor, figureSizeEditOf, figureSizeEditorOf, figureSectionMeasuresOf, figurePlaneAlignChanges, figureRowOf, figureFaceOverhangOf
|
|
9
|
+
import { figurePartFaceOf, PART_LIMIT, parseFigureRecipe, resolveFigureRecipe, figurePartCountOf, figurePartIdFor, figureRecipeIdFor, figureSizeEditOf, figureSizeEditorOf, figureSectionMeasuresOf, figurePlaneAlignChanges, figureRowOf, figureFaceOverhangOf } from '@hatiolab/figure-model';
|
|
11
10
|
import './figure-recipe-catalog.js';
|
|
12
11
|
import { captureFigureThumbnail } from './thumbnail.js';
|
|
13
12
|
import { drawableFigureParts } from './renderer.js';
|
|
@@ -48,11 +47,10 @@ const NO_MARKS = [];
|
|
|
48
47
|
import { apexOver, drawnOf } from './section-drawing.js';
|
|
49
48
|
import { END_FACE } from './section-controls.js';
|
|
50
49
|
import { nudgeOf, placementOf } from './stage-model.js';
|
|
51
|
-
import { occupancyFromParts, roomRefitRowsOf } from './occupancy.js';
|
|
52
50
|
import { gateFindingStyles, renderGateFinding } from './gate-findings.js';
|
|
53
|
-
import { editRefusalOf,
|
|
51
|
+
import { editRefusalOf, partNameRefusalOf, sizeRangeFitsOf, partRefusalOf, placedRefusalOf, recipeRefusalOf, removalNoticeOf } from './refusals.js';
|
|
54
52
|
import { HelpToggles } from './help.js';
|
|
55
|
-
import { endPlaceKeyOf,
|
|
53
|
+
import { endPlaceKeyOf, followOf, sizeFollowersOf, measureNow, partSummaryOf, instanceRangeOf, instanceSizeToDeclare, proportionToFollow, rangeWith, turnsAboutAJoint, valueNow } from './links.js';
|
|
56
54
|
import { jointFanOf } from './joint-fan.js';
|
|
57
55
|
import { derivedOf } from './revision.js';
|
|
58
56
|
import { jointDragOf } from './joint-drag.js';
|
|
@@ -508,9 +506,9 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
508
506
|
movePart(id, to) {
|
|
509
507
|
this.run(() => this.session.edit({ kind: 'move-part', target: id, to }));
|
|
510
508
|
}
|
|
511
|
-
removePart(id
|
|
509
|
+
removePart(id) {
|
|
512
510
|
try {
|
|
513
|
-
const view = this.session.edit({ kind: 'remove-part', target: id
|
|
511
|
+
const view = this.session.edit({ kind: 'remove-part', target: id });
|
|
514
512
|
this.error = '';
|
|
515
513
|
/* What else the removal let go of, named (chief architect, 2026-09-27); undo brings it back. */
|
|
516
514
|
this.notice = removalNoticeOf(view.removal, (key, params) => i18next.t(key, params)) ?? '';
|
|
@@ -519,19 +517,8 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
519
517
|
this.changed();
|
|
520
518
|
}
|
|
521
519
|
catch (error) {
|
|
522
|
-
if (this.refusals.askClipLoss(error, () => this.removePart(id
|
|
520
|
+
if (this.refusals.askClipLoss(error, () => this.removePart(id)))
|
|
523
521
|
return;
|
|
524
|
-
/*
|
|
525
|
-
A part in the declared space goes, and the space is fitted to the parts left, in the same click: every space
|
|
526
|
-
this product declares is fitted to the parts (「부품에 맞추기」, the AI's fit-room -- no padding), so fitting it
|
|
527
|
-
again keeps what it says, and there is nothing to ask (user, 2026-09-27: 「이 확인이 꼭 필요한가 ?」).
|
|
528
|
-
*/
|
|
529
|
-
if (!refitRoom && inDeclaredRoom(error)) {
|
|
530
|
-
this.removePart(id, true);
|
|
531
|
-
if (!this.error)
|
|
532
|
-
this.notice = [this.notice, i18next.t('figure.text.removal-space-refitted')].filter(Boolean).join(' ');
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
522
|
this.error = partRefusalOf(error, id, (key, params) => i18next.t(key, params)) ?? this.said(error);
|
|
536
523
|
}
|
|
537
524
|
}
|
|
@@ -989,7 +976,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
989
976
|
this.holdAction(null);
|
|
990
977
|
this.notice = '';
|
|
991
978
|
const hadSize = this.hasSize();
|
|
992
|
-
const hadSpace = !!this.shown()?.asset.occupancy;
|
|
993
979
|
try {
|
|
994
980
|
this.session.command(action);
|
|
995
981
|
this.error = '';
|
|
@@ -997,9 +983,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
997
983
|
/* What the command did besides what was asked, in one line: the figure's size declared to follow (ADR ruling Q1). */
|
|
998
984
|
if (action.kind === 'follow-size' && !hadSize) {
|
|
999
985
|
const size = this.designValues();
|
|
1000
|
-
|
|
1001
|
-
const spaceToo = !hadSpace && !!this.shown()?.asset.occupancy;
|
|
1002
|
-
this.notice = i18next.t(spaceToo ? 'figure.text.size-and-space-declared-to-follow' : 'figure.text.size-declared-to-follow', {
|
|
986
|
+
this.notice = i18next.t('figure.text.size-declared-to-follow', {
|
|
1003
987
|
x: Math.round(size['size.x'] ?? 0).toLocaleString(),
|
|
1004
988
|
y: Math.round(size['size.y'] ?? 0).toLocaleString(),
|
|
1005
989
|
z: Math.round(size['size.z'] ?? 0).toLocaleString()
|
|
@@ -1440,18 +1424,13 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1440
1424
|
return i18next.t('figure.text.release-state-released', { version: String(version) });
|
|
1441
1425
|
return version > 0 ? i18next.t('figure.text.release-state-draft-over', { version: String(version) }) : i18next.t('figure.text.release-state-draft-new');
|
|
1442
1426
|
}
|
|
1443
|
-
/** The findings that block release, under the bar beside
|
|
1444
|
-
renderReleaseBlockers(blockers, asset
|
|
1427
|
+
/** The findings that block release, under the bar beside 「발행」. */
|
|
1428
|
+
renderReleaseBlockers(blockers, asset) {
|
|
1445
1429
|
const parts = (asset?.appearance ?? []).map(look => look.target);
|
|
1446
|
-
const way = (code) => (code === 'occupancy-undeclared' || code === 'part-outside-occupancy') && asset && parts.length
|
|
1447
|
-
? html `<button act ?disabled=${unavailable} @click=${() => this.linkCommand(occupancyFromParts(asset))}>
|
|
1448
|
-
<md-icon>fit_screen</md-icon>${i18next.t('figure.button.fit-base-to-parts')}
|
|
1449
|
-
</button>`
|
|
1450
|
-
: nothing;
|
|
1451
1430
|
return html `<div release-blockers role="dialog" aria-label=${i18next.t('figure.text.must-fix-to-release')} @keydown=${(e) => e.key === 'Escape' && (this.blockersOpen = false)}>
|
|
1452
1431
|
<ul gate>
|
|
1453
1432
|
<li head>${i18next.t('figure.text.must-fix-to-release')}</li>
|
|
1454
|
-
${blockers.map(finding => renderGateFinding(finding, true,
|
|
1433
|
+
${blockers.map(finding => renderGateFinding(finding, true, nothing, parts))}
|
|
1455
1434
|
</ul>
|
|
1456
1435
|
</div>`;
|
|
1457
1436
|
}
|
|
@@ -1786,20 +1765,9 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1786
1765
|
/* A repeat's own row values (its pitch) have their own section, not the shape's. */
|
|
1787
1766
|
const own = design.filter(i => this.selected && i.id.startsWith(this.selected + '.') && !i.id.startsWith(this.selected + '.repeat.'));
|
|
1788
1767
|
const common = design.filter(i => !view.geometry.some(g => i.id.startsWith(ownerOf(g.id) + '.')));
|
|
1789
|
-
/*
|
|
1790
|
-
A part's field only the declared room still reads -- its old height position once the floor holds it -- moves
|
|
1791
|
-
nothing; it is shown apart as what it is, not as a position (ADR-0097, designer 2026-09-27).
|
|
1792
|
-
*/
|
|
1793
1768
|
const shown = this.shown();
|
|
1794
1769
|
const asset = shown?.asset;
|
|
1795
|
-
|
|
1796
|
-
try {
|
|
1797
|
-
roomOnly = this.selected && asset ? figureRoomOnlyInputsOf(asset, this.selected) : [];
|
|
1798
|
-
}
|
|
1799
|
-
catch {
|
|
1800
|
-
roomOnly = [];
|
|
1801
|
-
}
|
|
1802
|
-
const partFields = own.filter(i => !roomOnly.includes(i.id));
|
|
1770
|
+
const partFields = own;
|
|
1803
1771
|
/* The numbers a rule gives the axes that have no field of their own -- shown read-only, never as a blank. */
|
|
1804
1772
|
let held;
|
|
1805
1773
|
try {
|
|
@@ -1817,7 +1785,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1817
1785
|
catch {
|
|
1818
1786
|
held = undefined;
|
|
1819
1787
|
}
|
|
1820
|
-
const roomFields = own.filter(i => roomOnly.includes(i.id));
|
|
1821
1788
|
/*
|
|
1822
1789
|
Only what is under way is said. Saved or not is the save button's: filled and pressable when there is something
|
|
1823
1790
|
to save, dimmed when not -- the saved and unsaved words beside it said the same thing again in the primary
|
|
@@ -1868,7 +1835,7 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1868
1835
|
</button>
|
|
1869
1836
|
<button slot="commit" save ?disabled=${unavailable || (!view.dirty && !!view.id)} @click=${this.save}><md-icon>save</md-icon>${i18next.t('figure.button.save')}</button>
|
|
1870
1837
|
</ox-canvas-bar>
|
|
1871
|
-
${this.blockersOpen && blockers.length ? this.renderReleaseBlockers(blockers, asset
|
|
1838
|
+
${this.blockersOpen && blockers.length ? this.renderReleaseBlockers(blockers, asset) : nothing}
|
|
1872
1839
|
${this.catalogOpen
|
|
1873
1840
|
? html `<figure-recipe-catalog
|
|
1874
1841
|
.templates=${this.templates}
|
|
@@ -1976,7 +1943,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
1976
1943
|
${this.renderRepeatNote(view.geometry)}
|
|
1977
1944
|
</section>
|
|
1978
1945
|
${this.renderPartGroups(shown, view.geometry, partFields, unavailable, held)}
|
|
1979
|
-
${roomFields.length ? this.renderRoomOnly(roomFields, unavailable) : nothing}
|
|
1980
1946
|
<figure-material-panel
|
|
1981
1947
|
.body=${{ ...part, id: this.selected }}
|
|
1982
1948
|
.palette=${view.palette ?? {}}
|
|
@@ -2118,58 +2084,6 @@ let FigureEditor = class FigureEditor extends LitElement {
|
|
|
2118
2084
|
return html `<p hint held-axes>${i18next.t('figure.text.held-by-fastening')}</p>`;
|
|
2119
2085
|
return html `<p hint held-axes>${i18next.t('figure.text.held-worked-out', { group: held.map(g => i18next.t('figure.label.group-' + g.name)).join(' · ') })}</p>`;
|
|
2120
2086
|
}
|
|
2121
|
-
/**
|
|
2122
|
-
* A part's fields only the declared room still reads (ADR-0097, designer 2026-09-27): shown as what they are and not
|
|
2123
|
-
* typed into -- they move nothing. Declaring the room again is offered; nothing is deleted or widened on the way.
|
|
2124
|
-
*/
|
|
2125
|
-
renderRoomOnly(fields, unavailable) {
|
|
2126
|
-
return html `<section room-only>
|
|
2127
|
-
<h3>${i18next.t('figure.label.room-only-inputs')}</h3>
|
|
2128
|
-
<p hint>${i18next.t('figure.text.room-only-inputs')}</p>
|
|
2129
|
-
<div form>
|
|
2130
|
-
${fields.map(f => html `<span>${fieldWordsOf(f.id, key => i18next.t(key))} (${f.unit})</span><input aria-label=${f.id} type="number" .value=${String(f.value)} disabled />`)}
|
|
2131
|
-
</div>
|
|
2132
|
-
<button act room-refit ?disabled=${unavailable} @click=${() => this.askRoomRefit()}><md-icon>fit_screen</md-icon>${i18next.t('figure.button.room-refit')}</button>
|
|
2133
|
-
</section>`;
|
|
2134
|
-
}
|
|
2135
|
-
/** The room as declared and as proposed, and what lies outside each as measured, before the author confirms. */
|
|
2136
|
-
async askRoomRefit() {
|
|
2137
|
-
let refit;
|
|
2138
|
-
try {
|
|
2139
|
-
refit = figureRoomRefitOf(this.shown().asset);
|
|
2140
|
-
}
|
|
2141
|
-
catch (error) {
|
|
2142
|
-
this.error = this.said(error);
|
|
2143
|
-
return;
|
|
2144
|
-
}
|
|
2145
|
-
if (!refit)
|
|
2146
|
-
return;
|
|
2147
|
-
const rows = roomRefitRowsOf(refit);
|
|
2148
|
-
const outside = (list) => list.length
|
|
2149
|
-
? list.map(o => i18next.t('figure.text.room-part-outside', { part: partLabelOf(o.part), axis: o.axis.toUpperCase(), mm: String(o.mm) })).join(' · ')
|
|
2150
|
-
: i18next.t('figure.text.room-nothing-outside');
|
|
2151
|
-
const agreed = await OxPrompt.open({
|
|
2152
|
-
type: 'question',
|
|
2153
|
-
title: i18next.t('figure.label.room-refit'),
|
|
2154
|
-
template: html `<table room-refit>
|
|
2155
|
-
<tr><th></th><th>${i18next.t('figure.label.room-declared')}</th><th>${i18next.t('figure.label.room-proposed')}</th></tr>
|
|
2156
|
-
${rows.map(r => html `<tr>
|
|
2157
|
-
<td>${i18next.t(`figure.label.room-at-${r.at}`)} ${r.axis.toUpperCase()}</td>
|
|
2158
|
-
<td>${r.declared}</td>
|
|
2159
|
-
<td>${r.same ? i18next.t('figure.text.room-same') : r.proposed}</td>
|
|
2160
|
-
</tr>`)}
|
|
2161
|
-
</table>
|
|
2162
|
-
<p>${i18next.t('figure.label.room-declared')}: ${outside(refit.outside.declared)}</p>
|
|
2163
|
-
<p>${i18next.t('figure.label.room-proposed')}: ${outside(refit.outside.proposed)}</p>
|
|
2164
|
-
${refit.drops.length
|
|
2165
|
-
? html `<p>${i18next.t('figure.text.room-drops', { fields: [...new Set(refit.drops.map(id => `${partLabelOf(id.split('.')[0])} ${fieldWordsOf(id, key => i18next.t(key))}`))].join(' · ') })}</p>`
|
|
2166
|
-
: nothing}`,
|
|
2167
|
-
confirmButton: { text: i18next.t('figure.button.room-refit-confirm') },
|
|
2168
|
-
cancelButton: { text: i18next.t('figure.button.keep-editing') }
|
|
2169
|
-
});
|
|
2170
|
-
if (agreed)
|
|
2171
|
-
this.linkCommand(refit.step);
|
|
2172
|
-
}
|
|
2173
2087
|
renderSingle(name, field, unavailable) {
|
|
2174
2088
|
const words = name.split('.').map(part => i18next.t('figure.label.field-' + part, { defaultValue: part }));
|
|
2175
2089
|
return html `<span ?scrub=${!unavailable} @pointerdown=${(e) => this.scrub(field, e, unavailable)}>${words.join(' · ')} (${field.unit})</span
|