@things-factory/figure-ui 10.1.33 → 10.1.35

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.
@@ -143,6 +143,7 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
143
143
  * 미저장 표시(`dirty`)는 그대로 남으므로 데이터를 잃지는 않았다. 잃은 것은 **사유**다.
144
144
  */
145
145
  this.saveFailure = '';
146
+ this.sourceLoadFailure = '';
146
147
  this.showSaveModal = false;
147
148
  this.saveModalType = '';
148
149
  this.saveModalName = '';
@@ -837,6 +838,11 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
837
838
  };
838
839
  }
839
840
  render() {
841
+ if (this.sourceLoadFailure)
842
+ return html `<section role="alert" style="padding:24px">
843
+ <h2>Figure를 열지 못했습니다</h2><p>${this.sourceLoadFailure}</p>
844
+ <button @click=${() => navigate('figure-list')}>Figure 목록으로</button>
845
+ </section>`;
840
846
  const source = this.folded;
841
847
  return html `
842
848
  <div
@@ -850,6 +856,8 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
850
856
  @figure-reverted=${() => this.figure?.id && this.load(this.figure.id)}
851
857
  @preview-sizing-fix=${(e) => this.previewSizingFix(e.detail)}
852
858
  @apply-sizing-fix=${(e) => this.applySizingFix(e.detail)}
859
+ @apply-sizing-fix-plan=${(e) => this.applySizingFixPlan(e.detail)}
860
+ @restore-released-footprint=${(e) => this.restoreReleasedFootprint(e.detail)}
853
861
  @fit-base-to-parts=${() => this.fitBaseToParts()}
854
862
  @settle-parts-on-floor=${() => this.settlePartsOnFloor()}
855
863
  @add-part=${(e) => this.addPart(e.detail.primitive)}
@@ -937,6 +945,7 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
937
945
  .source=${source}
938
946
  .contract=${this.contract}
939
947
  .contractFailure=${this.contractFailure}
948
+ .releasedBase=${this.releasedSource?.base}
940
949
  .selected=${this.selected}
941
950
  .view=${this.view}
942
951
  @update-view=${(e) => (this.view = e.detail.view)}
@@ -1196,6 +1205,37 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
1196
1205
  return;
1197
1206
  this.take();
1198
1207
  }
1208
+ /**
1209
+ * The release gate may need several anchors to keep a connected assembly together. It has already
1210
+ * measured the complete set. Apply it directly to this unsaved work copy instead of making the
1211
+ * author accept a sequence of opaque mini-proposals.
1212
+ */
1213
+ applySizingFixPlan(plan) {
1214
+ if (!plan.safe || !this.folded || plan.fixes.length === 0)
1215
+ return;
1216
+ const fixes = new Map(plan.fixes.map(fix => [`${fix.part}:${fix.axis}`, fix]));
1217
+ const next = {
1218
+ ...this.folded,
1219
+ parts: this.folded.parts.map(part => {
1220
+ const anchor = { ...(part.anchor ?? {}) };
1221
+ let changed = false;
1222
+ for (const axis of ['x', 'y', 'z']) {
1223
+ const fix = fixes.get(`${part.name}:${axis}`);
1224
+ if (!fix)
1225
+ continue;
1226
+ anchor[axis] = fix.to;
1227
+ changed = true;
1228
+ }
1229
+ return changed ? { ...part, anchor } : part;
1230
+ })
1231
+ };
1232
+ this.recordHistory();
1233
+ const { draft, parts } = fromFigureSource(next);
1234
+ this.draft = draft;
1235
+ this.parts = parts;
1236
+ this.selected = parts.length ? 0 : -1;
1237
+ this.dirty = true;
1238
+ }
1199
1239
  /**
1200
1240
  * 고른 변경을 받아들인다.
1201
1241
  *
@@ -1331,6 +1371,17 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
1331
1371
  const figure = await fetchFigure(id);
1332
1372
  if (generation !== this.loadGeneration || !this.active)
1333
1373
  return;
1374
+ // Decode before assigning the target ID or generating a thumbnail. On failure the previous
1375
+ // editor snapshot remains internal, but is hidden and cannot be saved under the requested ID.
1376
+ let model;
1377
+ try {
1378
+ model = figure.source ? fromFigureSource(JSON.parse(figure.source)) : undefined;
1379
+ }
1380
+ catch (error) {
1381
+ this.sourceLoadFailure = error instanceof Error ? error.message : String(error);
1382
+ return;
1383
+ }
1384
+ this.sourceLoadFailure = '';
1334
1385
  this.proposalSession = undefined;
1335
1386
  this.proposalBaseSource = undefined;
1336
1387
  this.figure = figure;
@@ -1346,7 +1397,6 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
1346
1397
  }
1347
1398
  // 서버가 준 것을 그대로 쓴다. 읽지 못하면 오류보고없이 빈 상태로 바꾸지 않는다.
1348
1399
  // 그러면 사용자가 저장을 선택해 원본을 덮어쓴다.
1349
- const model = figure.source ? fromFigureSource(JSON.parse(figure.source)) : undefined;
1350
1400
  this.draft = model?.draft;
1351
1401
  this.parts = model?.parts ?? [];
1352
1402
  /*
@@ -1388,6 +1438,7 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
1388
1438
  }
1389
1439
  }
1390
1440
  startNew() {
1441
+ this.sourceLoadFailure = '';
1391
1442
  ++this.loadGeneration;
1392
1443
  this.proposalSession = undefined;
1393
1444
  this.proposalBaseSource = undefined;
@@ -1569,6 +1620,22 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
1569
1620
  this.parts = [...settled];
1570
1621
  this.dirty = true;
1571
1622
  }
1623
+ /** 이전 발행 X·Z만 복원한다. Y와 이번 리비전의 부품 편집은 건드리지 않는다. */
1624
+ restoreReleasedFootprint(base) {
1625
+ if (!this.draft || !this.releasedSource)
1626
+ return;
1627
+ const released = this.releasedSource.base;
1628
+ if (base.x !== released.x || base.z !== released.z)
1629
+ return;
1630
+ const next = resizedToFit(this.draft, this.parts, {
1631
+ width: released.x,
1632
+ depth: this.draft.depth,
1633
+ height: released.z
1634
+ });
1635
+ if (next.draft === this.draft)
1636
+ return;
1637
+ this.resizeBase(next.draft, [...next.parts]);
1638
+ }
1572
1639
  resizeBase(draft, parts) {
1573
1640
  this.recordHistory('base');
1574
1641
  this.draft = draft;
@@ -1729,7 +1796,7 @@ let FigureModellerPage = class FigureModellerPage extends FigureModellerPageBase
1729
1796
  }
1730
1797
  }
1731
1798
  save() {
1732
- if (!this.canSave || !this.folded || !this.figure) {
1799
+ if (this.sourceLoadFailure || !this.canSave || !this.folded || !this.figure) {
1733
1800
  return;
1734
1801
  }
1735
1802
  if (!this.figure.id) {
@@ -1925,6 +1992,10 @@ __decorate([
1925
1992
  state(),
1926
1993
  __metadata("design:type", Object)
1927
1994
  ], FigureModellerPage.prototype, "saveFailure", void 0);
1995
+ __decorate([
1996
+ state(),
1997
+ __metadata("design:type", Object)
1998
+ ], FigureModellerPage.prototype, "sourceLoadFailure", void 0);
1928
1999
  __decorate([
1929
2000
  state(),
1930
2001
  __metadata("design:type", Object)