@operato/scene-storage 10.0.0-beta.50 → 10.0.0-beta.54

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/dist/rack-grid.js CHANGED
@@ -32,7 +32,7 @@ import { __decorate } from "tslib";
32
32
  */
33
33
  import { Component, ContainerAbstract, Layout, Model, sceneComponent } from '@hatiolab/things-scene';
34
34
  import * as THREE from 'three';
35
- import { CarrierHolder, Placeable, SlotTarget, componentBoundingBox } from '@operato/scene-base';
35
+ import { CarrierHolder, Placeable, RecordStorage, SlotTarget, componentBoundingBox } from '@operato/scene-base';
36
36
  import { RackGrid3D } from './rack-grid-3d.js';
37
37
  // RackGridCell 의 refid 충돌 회피 — load 시 동적 생성되는 cell 의 refid 가 *부모
38
38
  // RackGrid + 모델 안 다른 컴포넌트* refid 와 겹치지 않도록 *높은 시작값 + monotonic
@@ -156,7 +156,20 @@ const rowControlHandler = {
156
156
  // handler 안 `this` 가 *해당 RackGrid 인스턴스* 를 가리키도록 (화살표 함수가
157
157
  // getter 의 `this` 를 capture). rack-table-cell 의 동일 패턴.
158
158
  // ─── RackGrid ─────────────────────────────────────────────────────────────────
159
- let RackGrid = class RackGrid extends CarrierHolder(Placeable(ContainerAbstract)) {
159
+ let RackGrid = class RackGrid extends RecordStorage()(CarrierHolder(Placeable(ContainerAbstract))) {
160
+ // RecordStorage mixin hook overrides.
161
+ // record.cellId 가 slotId (3-segment '{col}-{row}-{shelf}' format).
162
+ _recordToSlotId(record) {
163
+ return record.cellId ?? '';
164
+ }
165
+ // 3D rebuild — rebuildStockMesh 우선, 없으면 mixin default.
166
+ _rebuildVisual() {
167
+ const ro = this._realObject;
168
+ if (ro?.rebuildStockMesh)
169
+ ro.rebuildStockMesh();
170
+ else if (ro?.update)
171
+ ro.update();
172
+ }
160
173
  // Phase Auto-Nav (AN-PR-2) — Obstacle 자격. AMR / mover 의 자동 path planning
161
174
  // 시 회피 대상. `state.isObstacle` 명시 false 시 override (예외 처리).
162
175
  get isObstacle() {
@@ -299,61 +312,7 @@ let RackGrid = class RackGrid extends CarrierHolder(Placeable(ContainerAbstract)
299
312
  ;
300
313
  this._realObject?.rebuildStockMesh?.();
301
314
  }
302
- /** state.data records Plan A stock 보관소. */
303
- get records() {
304
- return this.state.data ?? [];
305
- }
306
- // ── Legend integration ──────────────────────────────────
307
- _legendTarget;
308
- /**
309
- * Legend 컴포넌트 lookup. 우선순위:
310
- * 1) state.legendTarget id 명시
311
- * 2) scene 전체 의 type='legend' 첫 번째 컴포넌트 (자동 발견)
312
- */
313
- get legendTarget() {
314
- if (this._legendTarget)
315
- return this._legendTarget;
316
- const id = this.state.legendTarget;
317
- if (id) {
318
- const found = this.root?.findById?.(id);
319
- if (found) {
320
- this._legendTarget = found;
321
- found.on?.('change', this._onLegendChanged, this);
322
- return found;
323
- }
324
- }
325
- const visit = (node) => {
326
- if (!node)
327
- return undefined;
328
- if (node.state?.type === 'legend')
329
- return node;
330
- const children = node.components;
331
- if (children) {
332
- for (const c of children) {
333
- const r = visit(c);
334
- if (r)
335
- return r;
336
- }
337
- }
338
- return undefined;
339
- };
340
- const found = visit(this.root);
341
- if (found) {
342
- this._legendTarget = found;
343
- found.on?.('change', this._onLegendChanged, this);
344
- }
345
- return found;
346
- }
347
- _onLegendChanged = () => {
348
- ;
349
- this._realObject?.rebuildStockMesh?.();
350
- };
351
- /**
352
- * record 의 legend.field 값을 ranges 와 매칭해 색상 해석.
353
- * - `range.value === recordValue` (카테고리 일치)
354
- * - `range.min ≤ Number(v) < range.max` (수치 범위)
355
- * - 매칭 없으면 `defaultColor` 또는 undefined
356
- */
315
+ // records / legendTarget / _onLegendChanged / resolveLegendColor RecordStorage mixin 제공.
357
316
  // ── View-mode click → rack-grid-cell-click event + popup ──
358
317
  get eventMap() {
359
318
  return {
@@ -395,23 +354,12 @@ let RackGrid = class RackGrid extends CarrierHolder(Placeable(ContainerAbstract)
395
354
  }
396
355
  const payload = { cellId, record, hitPoint: hit.point, instanceId, isStock };
397
356
  this.trigger('rack-grid-cell-click', payload);
398
- this._invokePopup(cellId, record);
357
+ if (cellId)
358
+ this._invokePopup(cellId, record ?? { cellId });
399
359
  // popup 외부 click 으로 인식되어 자동 close 되는 회귀 차단
400
360
  mouseEvent.stopPropagation?.();
401
361
  };
402
- /** state.popupRef Popup 컴포넌트 invoke. anchor = 클릭된 cell 의 SlotTarget. */
403
- _invokePopup(cellId, record) {
404
- const popupRefId = this.state.popupRef;
405
- if (!popupRefId || !cellId)
406
- return;
407
- const popupComp = this.root?.findById?.(popupRefId);
408
- if (!popupComp || typeof popupComp.openPopup !== 'function') {
409
- console.warn(`[rack-grid] popupRef="${popupRefId}" 가 가리키는 컴포넌트 없거나 openPopup 미지원`);
410
- return;
411
- }
412
- const anchor = this.slotTargetAt(cellId);
413
- popupComp.openPopup(record ?? { cellId }, { anchor });
414
- }
362
+ // _invokePopup RecordStorage mixin 제공 (signature 동일: slotId=cellId, payload=record).
415
363
  /** raycast → 우리 RackGrid 의 어떤 mesh 가 closest hit 인지. */
416
364
  _raycastHit(mouseEvent) {
417
365
  const ro = this._realObject;
@@ -482,40 +430,7 @@ let RackGrid = class RackGrid extends CarrierHolder(Placeable(ContainerAbstract)
482
430
  }
483
431
  return `${col}-${row}-${shelf}`;
484
432
  }
485
- resolveLegendColor(record) {
486
- const legend = this.legendTarget;
487
- if (!legend)
488
- return undefined;
489
- const status = legend.getState?.('status') ?? legend.state?.status;
490
- if (!status)
491
- return undefined;
492
- const field = status.field;
493
- const ranges = status.ranges;
494
- if (!field || !Array.isArray(ranges))
495
- return undefined;
496
- const value = record?.[field];
497
- if (value === undefined || value === null)
498
- return status.defaultColor;
499
- for (const range of ranges) {
500
- if (!range)
501
- continue;
502
- if (range.value !== undefined) {
503
- if (range.value === value)
504
- return range.color;
505
- continue;
506
- }
507
- const num = Number(value);
508
- if (!Number.isFinite(num))
509
- continue;
510
- const min = range.min !== undefined && range.min !== '' ? Number(range.min) : undefined;
511
- const max = range.max !== undefined && range.max !== '' ? Number(range.max) : undefined;
512
- const minOk = min === undefined || num >= min;
513
- const maxOk = max === undefined || num < max;
514
- if (minOk && maxOk)
515
- return range.color;
516
- }
517
- return status.defaultColor;
518
- }
433
+ // resolveLegendColor — RecordStorage mixin 제공.
519
434
  /**
520
435
  * 새 (rows × columns) 에 맞춰 children 재구성. rack-table.buildCells 정확 클론.
521
436
  */
@@ -1114,7 +1029,7 @@ let RackGrid = class RackGrid extends CarrierHolder(Placeable(ContainerAbstract)
1114
1029
  return false;
1115
1030
  if (this._carrierChildAt(cellId))
1116
1031
  return true;
1117
- return this.records.some(r => r.cellId === cellId);
1032
+ return this.records.some((r) => r.cellId === cellId);
1118
1033
  }
1119
1034
  /**
1120
1035
  * carrier 를 obtain — 이미 child 면 그대로, 아니면 state.data record 로 transient