@operato/scene-visualizer 10.0.0-beta.1 → 10.0.0-beta.10

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.
Files changed (232) hide show
  1. package/dist/editors/index.d.ts +2 -0
  2. package/dist/editors/index.js +10 -0
  3. package/dist/editors/index.js.map +1 -1
  4. package/dist/editors/property-editor-gltf-fill-targets.d.ts +5 -2
  5. package/dist/editors/property-editor-gltf-fill-targets.js +179 -77
  6. package/dist/editors/property-editor-gltf-fill-targets.js.map +1 -1
  7. package/dist/editors/property-editor-gltf-info.d.ts +25 -3
  8. package/dist/editors/property-editor-gltf-info.js +324 -73
  9. package/dist/editors/property-editor-gltf-info.js.map +1 -1
  10. package/dist/editors/property-editor-gltf-play-targets.d.ts +25 -0
  11. package/dist/editors/property-editor-gltf-play-targets.js +388 -0
  12. package/dist/editors/property-editor-gltf-play-targets.js.map +1 -0
  13. package/dist/editors/property-editor-location-increase-pattern.js +0 -4
  14. package/dist/editors/property-editor-location-increase-pattern.js.map +1 -1
  15. package/dist/editors/property-editor-stocker-location.d.ts +13 -0
  16. package/dist/editors/property-editor-stocker-location.js +151 -0
  17. package/dist/editors/property-editor-stocker-location.js.map +1 -0
  18. package/dist/editors/property-editor-stocker-ports.d.ts +8 -0
  19. package/dist/editors/property-editor-stocker-ports.js +112 -0
  20. package/dist/editors/property-editor-stocker-ports.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.js +3 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/rack-table-3d.js +1 -0
  25. package/dist/rack-table-3d.js.map +1 -1
  26. package/dist/rack-table.js +13 -0
  27. package/dist/rack-table.js.map +1 -1
  28. package/dist/rack.d.ts +13 -0
  29. package/dist/rack.js +100 -11
  30. package/dist/rack.js.map +1 -1
  31. package/dist/stock-hub.d.ts +25 -0
  32. package/dist/stock-hub.js +147 -0
  33. package/dist/stock-hub.js.map +1 -0
  34. package/dist/stock.d.ts +32 -0
  35. package/dist/stock.js +170 -73
  36. package/dist/stock.js.map +1 -1
  37. package/dist/stocker-3d.d.ts +23 -0
  38. package/dist/stocker-3d.js +352 -0
  39. package/dist/stocker-3d.js.map +1 -0
  40. package/dist/stocker-port-3d.d.ts +14 -0
  41. package/dist/stocker-port-3d.js +80 -0
  42. package/dist/stocker-port-3d.js.map +1 -0
  43. package/dist/{banner.d.ts → stocker-port.d.ts} +35 -25
  44. package/dist/stocker-port.js +123 -0
  45. package/dist/stocker-port.js.map +1 -0
  46. package/dist/{camera.d.ts → stocker.d.ts} +121 -30
  47. package/dist/stocker.js +370 -0
  48. package/dist/stocker.js.map +1 -0
  49. package/dist/templates/index.d.ts +37 -38
  50. package/dist/templates/index.js +7 -1
  51. package/dist/templates/index.js.map +1 -1
  52. package/dist/templates/rack-table.d.ts +2 -0
  53. package/dist/templates/rack-table.js +4 -2
  54. package/dist/templates/rack-table.js.map +1 -1
  55. package/dist/templates/stock-hub.d.ts +14 -0
  56. package/dist/templates/stock-hub.js +15 -0
  57. package/dist/templates/stock-hub.js.map +1 -0
  58. package/dist/templates/stocker-port.d.ts +17 -0
  59. package/dist/templates/stocker-port.js +17 -0
  60. package/dist/templates/stocker-port.js.map +1 -0
  61. package/dist/templates/stocker.d.ts +27 -0
  62. package/dist/templates/stocker.js +38 -0
  63. package/dist/templates/stocker.js.map +1 -0
  64. package/dist/templates/visualizer.js +1 -1
  65. package/dist/templates/visualizer.js.map +1 -1
  66. package/dist/visualizer.d.ts +2 -1
  67. package/dist/visualizer.js +63 -46
  68. package/dist/visualizer.js.map +1 -1
  69. package/icons/stock-hub.png +0 -0
  70. package/package.json +2 -2
  71. package/translations/en.json +6 -0
  72. package/translations/ja.json +5 -0
  73. package/translations/ko.json +6 -1
  74. package/translations/ms.json +5 -0
  75. package/translations/zh.json +5 -0
  76. package/dist/banner.js +0 -75
  77. package/dist/banner.js.map +0 -1
  78. package/dist/camera.js +0 -107
  79. package/dist/camera.js.map +0 -1
  80. package/dist/cube.d.ts +0 -241
  81. package/dist/cube.js +0 -37
  82. package/dist/cube.js.map +0 -1
  83. package/dist/cylinder.d.ts +0 -9
  84. package/dist/cylinder.js +0 -37
  85. package/dist/cylinder.js.map +0 -1
  86. package/dist/ellipse.d.ts +0 -5
  87. package/dist/ellipse.js +0 -20
  88. package/dist/ellipse.js.map +0 -1
  89. package/dist/gltf-object.d.ts +0 -249
  90. package/dist/gltf-object.js +0 -103
  91. package/dist/gltf-object.js.map +0 -1
  92. package/dist/html-overlay-element.d.ts +0 -1
  93. package/dist/html-overlay-element.js +0 -8
  94. package/dist/html-overlay-element.js.map +0 -1
  95. package/dist/light.d.ts +0 -14
  96. package/dist/light.js +0 -134
  97. package/dist/light.js.map +0 -1
  98. package/dist/polygon.d.ts +0 -17
  99. package/dist/polygon.js +0 -62
  100. package/dist/polygon.js.map +0 -1
  101. package/dist/rect.d.ts +0 -5
  102. package/dist/rect.js +0 -34
  103. package/dist/rect.js.map +0 -1
  104. package/dist/scene/component.d.ts +0 -1
  105. package/dist/scene/component.js +0 -29
  106. package/dist/scene/component.js.map +0 -1
  107. package/dist/sphere.d.ts +0 -9
  108. package/dist/sphere.js +0 -37
  109. package/dist/sphere.js.map +0 -1
  110. package/dist/sprite.d.ts +0 -238
  111. package/dist/sprite.js +0 -27
  112. package/dist/sprite.js.map +0 -1
  113. package/dist/text.d.ts +0 -1
  114. package/dist/text.js +0 -7
  115. package/dist/text.js.map +0 -1
  116. package/dist/three-container-editor.d.ts +0 -22
  117. package/dist/three-container-editor.js +0 -132
  118. package/dist/three-container-editor.js.map +0 -1
  119. package/dist/three-container.d.ts +0 -61
  120. package/dist/three-container.js +0 -371
  121. package/dist/three-container.js.map +0 -1
  122. package/dist/three-controls.d.ts +0 -111
  123. package/dist/three-controls.js +0 -414
  124. package/dist/three-controls.js.map +0 -1
  125. package/dist/three-layout.d.ts +0 -8
  126. package/dist/three-layout.js +0 -20
  127. package/dist/three-layout.js.map +0 -1
  128. package/dist/three-space.d.ts +0 -8
  129. package/dist/three-space.js +0 -58
  130. package/dist/three-space.js.map +0 -1
  131. package/dist/threed/common.d.ts +0 -22
  132. package/dist/threed/common.js +0 -19
  133. package/dist/threed/common.js.map +0 -1
  134. package/dist/threed/floor/floor.d.ts +0 -3
  135. package/dist/threed/floor/floor.js +0 -51
  136. package/dist/threed/floor/floor.js.map +0 -1
  137. package/dist/threed/html/elements.d.ts +0 -2
  138. package/dist/threed/html/elements.js +0 -21
  139. package/dist/threed/html/elements.js.map +0 -1
  140. package/dist/threed/index.d.ts +0 -16
  141. package/dist/threed/index.js +0 -17
  142. package/dist/threed/index.js.map +0 -1
  143. package/dist/threed/interfaces.d.ts +0 -15
  144. package/dist/threed/interfaces.js +0 -5
  145. package/dist/threed/interfaces.js.map +0 -1
  146. package/dist/threed/managers/camera-manager.d.ts +0 -14
  147. package/dist/threed/managers/camera-manager.js +0 -60
  148. package/dist/threed/managers/camera-manager.js.map +0 -1
  149. package/dist/threed/managers/controls-manager.d.ts +0 -50
  150. package/dist/threed/managers/controls-manager.js +0 -249
  151. package/dist/threed/managers/controls-manager.js.map +0 -1
  152. package/dist/threed/managers/event-manager3d.d.ts +0 -19
  153. package/dist/threed/managers/event-manager3d.js +0 -76
  154. package/dist/threed/managers/event-manager3d.js.map +0 -1
  155. package/dist/threed/managers/index.d.ts +0 -7
  156. package/dist/threed/managers/index.js +0 -7
  157. package/dist/threed/managers/index.js.map +0 -1
  158. package/dist/threed/managers/light-manager.d.ts +0 -7
  159. package/dist/threed/managers/light-manager.js +0 -37
  160. package/dist/threed/managers/light-manager.js.map +0 -1
  161. package/dist/threed/managers/renderer-manager.d.ts +0 -30
  162. package/dist/threed/managers/renderer-manager.js +0 -120
  163. package/dist/threed/managers/renderer-manager.js.map +0 -1
  164. package/dist/threed/managers/scene-manager.d.ts +0 -15
  165. package/dist/threed/managers/scene-manager.js +0 -48
  166. package/dist/threed/managers/scene-manager.js.map +0 -1
  167. package/dist/threed/managers/types.d.ts +0 -36
  168. package/dist/threed/managers/types.js +0 -2
  169. package/dist/threed/managers/types.js.map +0 -1
  170. package/dist/threed/real-object-camera-meshed.d.ts +0 -12
  171. package/dist/threed/real-object-camera-meshed.js +0 -49
  172. package/dist/threed/real-object-camera-meshed.js.map +0 -1
  173. package/dist/threed/real-object-camera.d.ts +0 -9
  174. package/dist/threed/real-object-camera.js +0 -31
  175. package/dist/threed/real-object-camera.js.map +0 -1
  176. package/dist/threed/real-object-dom-element.d.ts +0 -9
  177. package/dist/threed/real-object-dom-element.js +0 -48
  178. package/dist/threed/real-object-dom-element.js.map +0 -1
  179. package/dist/threed/real-object-dummy.d.ts +0 -6
  180. package/dist/threed/real-object-dummy.js +0 -11
  181. package/dist/threed/real-object-dummy.js.map +0 -1
  182. package/dist/threed/real-object-extrude.d.ts +0 -22
  183. package/dist/threed/real-object-extrude.js +0 -180
  184. package/dist/threed/real-object-extrude.js.map +0 -1
  185. package/dist/threed/real-object-gltf.d.ts +0 -16
  186. package/dist/threed/real-object-gltf.js +0 -105
  187. package/dist/threed/real-object-gltf.js.map +0 -1
  188. package/dist/threed/real-object-group.d.ts +0 -5
  189. package/dist/threed/real-object-group.js +0 -11
  190. package/dist/threed/real-object-group.js.map +0 -1
  191. package/dist/threed/real-object-mesh.d.ts +0 -13
  192. package/dist/threed/real-object-mesh.js +0 -73
  193. package/dist/threed/real-object-mesh.js.map +0 -1
  194. package/dist/threed/real-object-plane.d.ts +0 -5
  195. package/dist/threed/real-object-plane.js +0 -22
  196. package/dist/threed/real-object-plane.js.map +0 -1
  197. package/dist/threed/real-object-registry.d.ts +0 -7
  198. package/dist/threed/real-object-registry.js +0 -32
  199. package/dist/threed/real-object-registry.js.map +0 -1
  200. package/dist/threed/real-object-scene.d.ts +0 -21
  201. package/dist/threed/real-object-scene.js +0 -72
  202. package/dist/threed/real-object-scene.js.map +0 -1
  203. package/dist/threed/real-object-sprite-2d.d.ts +0 -14
  204. package/dist/threed/real-object-sprite-2d.js +0 -45
  205. package/dist/threed/real-object-sprite-2d.js.map +0 -1
  206. package/dist/threed/real-object-sprite.d.ts +0 -11
  207. package/dist/threed/real-object-sprite.js +0 -52
  208. package/dist/threed/real-object-sprite.js.map +0 -1
  209. package/dist/threed/real-object-text.d.ts +0 -15
  210. package/dist/threed/real-object-text.js +0 -66
  211. package/dist/threed/real-object-text.js.map +0 -1
  212. package/dist/threed/real-object.d.ts +0 -65
  213. package/dist/threed/real-object.js +0 -251
  214. package/dist/threed/real-object.js.map +0 -1
  215. package/dist/threed/texture/canvas-texture.d.ts +0 -4
  216. package/dist/threed/texture/canvas-texture.js +0 -49
  217. package/dist/threed/texture/canvas-texture.js.map +0 -1
  218. package/dist/threed/texture/text-texture.d.ts +0 -8
  219. package/dist/threed/texture/text-texture.js +0 -79
  220. package/dist/threed/texture/text-texture.js.map +0 -1
  221. package/dist/threed/three-dimensional-container.d.ts +0 -7
  222. package/dist/threed/three-dimensional-container.js +0 -2
  223. package/dist/threed/three-dimensional-container.js.map +0 -1
  224. package/dist/threed/utils/bound-uv-generator.d.ts +0 -16
  225. package/dist/threed/utils/bound-uv-generator.js +0 -42
  226. package/dist/threed/utils/bound-uv-generator.js.map +0 -1
  227. package/dist/threed/utils/dispose.d.ts +0 -2
  228. package/dist/threed/utils/dispose.js +0 -32
  229. package/dist/threed/utils/dispose.js.map +0 -1
  230. package/dist/wall.d.ts +0 -241
  231. package/dist/wall.js +0 -44
  232. package/dist/wall.js.map +0 -1
@@ -0,0 +1,151 @@
1
+ /*
2
+ * Copyright © HatioLab Inc. All rights reserved.
3
+ *
4
+ * Stocker Location Rule Editor
5
+ */
6
+ import { __decorate } from "tslib";
7
+ import { css, html } from 'lit';
8
+ import { customElement, state } from 'lit/decorators.js';
9
+ import { OxPropertyEditor } from '@operato/property-editor';
10
+ import { DEFAULT_LOCATION_RULE, buildLocationId } from '../stocker.js';
11
+ let StockerLocationEditor = class StockerLocationEditor extends OxPropertyEditor {
12
+ static styles = [
13
+ ...OxPropertyEditor.styles,
14
+ css `
15
+ .loc-grid { display: grid; grid-template-columns: 80px 1fr; gap: 3px 6px; font-size: 11px; align-items: center; }
16
+ .loc-grid label { color: #555; font-weight: 500; font-size: 10px; }
17
+ .loc-grid input, .loc-grid select {
18
+ width: 100%; box-sizing: border-box; font-size: 11px; padding: 3px 4px;
19
+ border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #fff; color: #1c1b1f;
20
+ }
21
+ .loc-grid input[type="number"] { width: 50px; }
22
+ .side-labels { display: flex; gap: 4px; align-items: center; font-size: 10px; }
23
+ .side-labels input { width: 30px; text-align: center; }
24
+ .section-title { grid-column: 1 / -1; font-weight: 600; font-size: 10px; color: #6750a4; margin-top: 6px; padding-bottom: 2px; border-bottom: 1px solid rgba(0,0,0,0.08); }
25
+ .preview { grid-column: 1 / -1; margin-top: 6px; padding: 6px 8px; background: #f3edf7; border-radius: 6px; font-family: monospace; font-size: 11px; }
26
+ .preview-title { font-size: 9px; font-weight: 600; color: #555; margin-bottom: 3px; }
27
+ .preview-samples { display: flex; flex-wrap: wrap; gap: 4px; }
28
+ .preview-sample { padding: 1px 5px; background: #fff; border-radius: 3px; font-size: 10px; }
29
+ `
30
+ ];
31
+ _lastExternalValue = undefined;
32
+ constructor() {
33
+ super();
34
+ this._rule = { ...DEFAULT_LOCATION_RULE };
35
+ }
36
+ _parseValue(value) {
37
+ if (!value)
38
+ return { ...DEFAULT_LOCATION_RULE };
39
+ if (typeof value === 'string') {
40
+ try {
41
+ return { ...DEFAULT_LOCATION_RULE, ...JSON.parse(value) };
42
+ }
43
+ catch {
44
+ return { ...DEFAULT_LOCATION_RULE };
45
+ }
46
+ }
47
+ return { ...DEFAULT_LOCATION_RULE, ...value };
48
+ }
49
+ editorTemplate(value, _spec) {
50
+ const serialized = typeof value === 'string' ? value : JSON.stringify(value);
51
+ if (serialized !== this._lastExternalValue) {
52
+ this._lastExternalValue = serialized;
53
+ this._rule = this._parseValue(value);
54
+ }
55
+ const r = this._rule;
56
+ const rackConfig = { bays: 10, levels: 5, depthCount: 1 };
57
+ const samples = [
58
+ buildLocationId(r, 'L', 1, 1, 1, rackConfig),
59
+ buildLocationId(r, 'L', 5, 3, 1, rackConfig),
60
+ buildLocationId(r, 'R', 10, 5, 1, rackConfig)
61
+ ];
62
+ return html `
63
+ <fieldset fullwidth>
64
+ <div class="loc-grid">
65
+ <div class="section-title">Pattern</div>
66
+ <label>Format</label>
67
+ <input type="text" .value=${r.pattern} placeholder="{side}{bay}-{level}-{depth}"
68
+ @change=${(e) => { e.stopPropagation(); this._set('pattern', e.target.value); }} />
69
+
70
+ <label>Side labels</label>
71
+ <div class="side-labels">
72
+ L=<input type="text" .value=${r.sideLabels.L}
73
+ @change=${(e) => { e.stopPropagation(); this._setSideLabel('L', e.target.value); }} />
74
+ R=<input type="text" .value=${r.sideLabels.R}
75
+ @change=${(e) => { e.stopPropagation(); this._setSideLabel('R', e.target.value); }} />
76
+ </div>
77
+
78
+ <div class="section-title">Direction</div>
79
+ <label>Bay</label>
80
+ <select .value=${r.bayDir}
81
+ @change=${(e) => { e.stopPropagation(); this._set('bayDir', e.target.value); }}>
82
+ <option value="ltr">Left → Right</option>
83
+ <option value="rtl">Right → Left</option>
84
+ </select>
85
+
86
+ <label>Level</label>
87
+ <select .value=${r.levelDir}
88
+ @change=${(e) => { e.stopPropagation(); this._set('levelDir', e.target.value); }}>
89
+ <option value="btt">Bottom → Top</option>
90
+ <option value="ttb">Top → Bottom</option>
91
+ </select>
92
+
93
+ <div class="section-title">Start number</div>
94
+ <label>Bay start</label>
95
+ <input type="number" .value=${String(r.bayStart)} min="0" step="1"
96
+ @change=${(e) => { e.stopPropagation(); this._set('bayStart', Number(e.target.value)); }} />
97
+ <label>Level start</label>
98
+ <input type="number" .value=${String(r.levelStart)} min="0" step="1"
99
+ @change=${(e) => { e.stopPropagation(); this._set('levelStart', Number(e.target.value)); }} />
100
+ <label>Depth start</label>
101
+ <input type="number" .value=${String(r.depthStart)} min="0" step="1"
102
+ @change=${(e) => { e.stopPropagation(); this._set('depthStart', Number(e.target.value)); }} />
103
+
104
+ <div class="section-title">Digit padding</div>
105
+ <label>Bay digits</label>
106
+ <input type="number" .value=${String(r.bayDigits)} min="0" max="4" step="1"
107
+ @change=${(e) => { e.stopPropagation(); this._set('bayDigits', Number(e.target.value)); }} />
108
+ <label>Level digits</label>
109
+ <input type="number" .value=${String(r.levelDigits)} min="0" max="4" step="1"
110
+ @change=${(e) => { e.stopPropagation(); this._set('levelDigits', Number(e.target.value)); }} />
111
+ <label>Depth digits</label>
112
+ <input type="number" .value=${String(r.depthDigits)} min="0" max="4" step="1"
113
+ @change=${(e) => { e.stopPropagation(); this._set('depthDigits', Number(e.target.value)); }} />
114
+
115
+ <div class="preview">
116
+ <div class="preview-title">Preview (10 bays, 5 levels)</div>
117
+ <div class="preview-samples">
118
+ ${samples.map(s => html `<span class="preview-sample">${s}</span>`)}
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </fieldset>
123
+ `;
124
+ }
125
+ _set(field, value) {
126
+ this._rule = { ...this._rule, [field]: value };
127
+ this._apply();
128
+ }
129
+ _setSideLabel(side, value) {
130
+ this._rule = { ...this._rule, sideLabels: { ...this._rule.sideLabels, [side]: value || side } };
131
+ this._apply();
132
+ }
133
+ _apply() {
134
+ const jsonValue = JSON.stringify(this._rule);
135
+ this.value = jsonValue;
136
+ this._lastExternalValue = jsonValue;
137
+ this.requestUpdate();
138
+ this.dispatchEvent(new CustomEvent('i-need-selected', {
139
+ bubbles: true, composed: true,
140
+ detail: { callback: (selected) => { selected[0]?.set('locationRule', jsonValue); } }
141
+ }));
142
+ }
143
+ };
144
+ __decorate([
145
+ state()
146
+ ], StockerLocationEditor.prototype, "_rule", void 0);
147
+ StockerLocationEditor = __decorate([
148
+ customElement('property-editor-stocker-location')
149
+ ], StockerLocationEditor);
150
+ export default StockerLocationEditor;
151
+ //# sourceMappingURL=property-editor-stocker-location.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-editor-stocker-location.js","sourceRoot":"","sources":["../../src/editors/property-editor-stocker-location.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Stocker Location Rule Editor\n */\n\nimport { css, html, TemplateResult } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { OxPropertyEditor, PropertySpec } from '@operato/property-editor'\nimport type { LocationRule } from '../stocker.js'\nimport { DEFAULT_LOCATION_RULE, buildLocationId } from '../stocker.js'\n\n@customElement('property-editor-stocker-location')\nexport default class StockerLocationEditor extends OxPropertyEditor {\n static styles = [\n ...OxPropertyEditor.styles,\n css`\n .loc-grid { display: grid; grid-template-columns: 80px 1fr; gap: 3px 6px; font-size: 11px; align-items: center; }\n .loc-grid label { color: #555; font-weight: 500; font-size: 10px; }\n .loc-grid input, .loc-grid select {\n width: 100%; box-sizing: border-box; font-size: 11px; padding: 3px 4px;\n border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #fff; color: #1c1b1f;\n }\n .loc-grid input[type=\"number\"] { width: 50px; }\n .side-labels { display: flex; gap: 4px; align-items: center; font-size: 10px; }\n .side-labels input { width: 30px; text-align: center; }\n .section-title { grid-column: 1 / -1; font-weight: 600; font-size: 10px; color: #6750a4; margin-top: 6px; padding-bottom: 2px; border-bottom: 1px solid rgba(0,0,0,0.08); }\n .preview { grid-column: 1 / -1; margin-top: 6px; padding: 6px 8px; background: #f3edf7; border-radius: 6px; font-family: monospace; font-size: 11px; }\n .preview-title { font-size: 9px; font-weight: 600; color: #555; margin-bottom: 3px; }\n .preview-samples { display: flex; flex-wrap: wrap; gap: 4px; }\n .preview-sample { padding: 1px 5px; background: #fff; border-radius: 3px; font-size: 10px; }\n `\n ]\n\n @state() private declare _rule: LocationRule\n private _lastExternalValue: any = undefined\n\n constructor() {\n super()\n this._rule = { ...DEFAULT_LOCATION_RULE }\n }\n\n private _parseValue(value: any): LocationRule {\n if (!value) return { ...DEFAULT_LOCATION_RULE }\n if (typeof value === 'string') {\n try { return { ...DEFAULT_LOCATION_RULE, ...JSON.parse(value) } } catch { return { ...DEFAULT_LOCATION_RULE } }\n }\n return { ...DEFAULT_LOCATION_RULE, ...value }\n }\n\n editorTemplate(value: any, _spec: PropertySpec): TemplateResult {\n const serialized = typeof value === 'string' ? value : JSON.stringify(value)\n if (serialized !== this._lastExternalValue) {\n this._lastExternalValue = serialized\n this._rule = this._parseValue(value)\n }\n\n const r = this._rule\n const rackConfig = { bays: 10, levels: 5, depthCount: 1 }\n const samples = [\n buildLocationId(r, 'L', 1, 1, 1, rackConfig),\n buildLocationId(r, 'L', 5, 3, 1, rackConfig),\n buildLocationId(r, 'R', 10, 5, 1, rackConfig)\n ]\n\n return html`\n <fieldset fullwidth>\n <div class=\"loc-grid\">\n <div class=\"section-title\">Pattern</div>\n <label>Format</label>\n <input type=\"text\" .value=${r.pattern} placeholder=\"{side}{bay}-{level}-{depth}\"\n @change=${(e: Event) => { e.stopPropagation(); this._set('pattern', (e.target as HTMLInputElement).value) }} />\n\n <label>Side labels</label>\n <div class=\"side-labels\">\n L=<input type=\"text\" .value=${r.sideLabels.L}\n @change=${(e: Event) => { e.stopPropagation(); this._setSideLabel('L', (e.target as HTMLInputElement).value) }} />\n R=<input type=\"text\" .value=${r.sideLabels.R}\n @change=${(e: Event) => { e.stopPropagation(); this._setSideLabel('R', (e.target as HTMLInputElement).value) }} />\n </div>\n\n <div class=\"section-title\">Direction</div>\n <label>Bay</label>\n <select .value=${r.bayDir}\n @change=${(e: Event) => { e.stopPropagation(); this._set('bayDir', (e.target as HTMLSelectElement).value) }}>\n <option value=\"ltr\">Left → Right</option>\n <option value=\"rtl\">Right → Left</option>\n </select>\n\n <label>Level</label>\n <select .value=${r.levelDir}\n @change=${(e: Event) => { e.stopPropagation(); this._set('levelDir', (e.target as HTMLSelectElement).value) }}>\n <option value=\"btt\">Bottom → Top</option>\n <option value=\"ttb\">Top → Bottom</option>\n </select>\n\n <div class=\"section-title\">Start number</div>\n <label>Bay start</label>\n <input type=\"number\" .value=${String(r.bayStart)} min=\"0\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set('bayStart', Number((e.target as HTMLInputElement).value)) }} />\n <label>Level start</label>\n <input type=\"number\" .value=${String(r.levelStart)} min=\"0\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set('levelStart', Number((e.target as HTMLInputElement).value)) }} />\n <label>Depth start</label>\n <input type=\"number\" .value=${String(r.depthStart)} min=\"0\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set('depthStart', Number((e.target as HTMLInputElement).value)) }} />\n\n <div class=\"section-title\">Digit padding</div>\n <label>Bay digits</label>\n <input type=\"number\" .value=${String(r.bayDigits)} min=\"0\" max=\"4\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set('bayDigits', Number((e.target as HTMLInputElement).value)) }} />\n <label>Level digits</label>\n <input type=\"number\" .value=${String(r.levelDigits)} min=\"0\" max=\"4\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set('levelDigits', Number((e.target as HTMLInputElement).value)) }} />\n <label>Depth digits</label>\n <input type=\"number\" .value=${String(r.depthDigits)} min=\"0\" max=\"4\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set('depthDigits', Number((e.target as HTMLInputElement).value)) }} />\n\n <div class=\"preview\">\n <div class=\"preview-title\">Preview (10 bays, 5 levels)</div>\n <div class=\"preview-samples\">\n ${samples.map(s => html`<span class=\"preview-sample\">${s}</span>`)}\n </div>\n </div>\n </div>\n </fieldset>\n `\n }\n\n private _set(field: string, value: any) {\n this._rule = { ...this._rule, [field]: value }\n this._apply()\n }\n\n private _setSideLabel(side: 'L' | 'R', value: string) {\n this._rule = { ...this._rule, sideLabels: { ...this._rule.sideLabels, [side]: value || side } }\n this._apply()\n }\n\n private _apply() {\n const jsonValue = JSON.stringify(this._rule)\n this.value = jsonValue\n this._lastExternalValue = jsonValue\n this.requestUpdate()\n\n this.dispatchEvent(new CustomEvent('i-need-selected', {\n bubbles: true, composed: true,\n detail: { callback: (selected: any[]) => { selected[0]?.set('locationRule', jsonValue) } }\n }))\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { TemplateResult } from 'lit';
2
+ import { OxPropertyEditor, PropertySpec } from '@operato/property-editor';
3
+ export default class StockerPortsEditor extends OxPropertyEditor {
4
+ static styles: import("lit").CSSResult[];
5
+ editorTemplate(value: any, _spec: PropertySpec): TemplateResult;
6
+ private _set;
7
+ private _applyPorts;
8
+ }
@@ -0,0 +1,112 @@
1
+ /*
2
+ * Copyright © HatioLab Inc. All rights reserved.
3
+ *
4
+ * Stocker Port Configuration Editor
5
+ *
6
+ * 주의: OxPropertyEditor base class가 모든 change 이벤트를 잡아서
7
+ * this.value를 덮어쓰므로, 내부 input/select의 change 이벤트 버블링을 차단해야 함.
8
+ */
9
+ import { __decorate } from "tslib";
10
+ import { css, html } from 'lit';
11
+ import { customElement } from 'lit/decorators.js';
12
+ import { OxPropertyEditor } from '@operato/property-editor';
13
+ function parsePorts(value) {
14
+ if (!value)
15
+ return [];
16
+ if (Array.isArray(value))
17
+ return value;
18
+ if (typeof value === 'string') {
19
+ try {
20
+ const parsed = JSON.parse(value);
21
+ return Array.isArray(parsed) ? parsed : [];
22
+ }
23
+ catch {
24
+ return [];
25
+ }
26
+ }
27
+ return [];
28
+ }
29
+ let StockerPortsEditor = class StockerPortsEditor extends OxPropertyEditor {
30
+ static styles = [
31
+ ...OxPropertyEditor.styles,
32
+ css `
33
+ .port-table { width: 100%; font-size: 11px; border-collapse: collapse; }
34
+ .port-table th { text-align: left; padding: 3px 4px; font-weight: 600; color: #555; border-bottom: 1px solid rgba(0,0,0,0.12); font-size: 10px; }
35
+ .port-table td { padding: 2px 3px; vertical-align: middle; }
36
+ .port-table select, .port-table input {
37
+ width: 100%; box-sizing: border-box; font-size: 11px; padding: 3px 4px;
38
+ border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #fff; color: #1c1b1f;
39
+ }
40
+ .port-table input[type="number"] { width: 50px; }
41
+ .port-table input[type="text"] { width: 60px; }
42
+ .btn-row { display: flex; gap: 4px; margin-top: 4px; }
43
+ .btn {
44
+ padding: 3px 8px; font-size: 10px; cursor: pointer;
45
+ border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #f3edf7; color: #1c1b1f;
46
+ }
47
+ .btn:hover { background: #ece6f0; }
48
+ .btn-remove { color: #b3261e; cursor: pointer; font-size: 14px; padding: 0 4px; background: none; border: none; }
49
+ `
50
+ ];
51
+ editorTemplate(value, _spec) {
52
+ const ports = Array.isArray(this.value) ? this.value : parsePorts(value);
53
+ return html `
54
+ <fieldset fullwidth>
55
+ ${ports.length > 0 ? html `
56
+ <table class="port-table">
57
+ <thead><tr><th>Type</th><th>Side</th><th>Pos</th><th>Label</th><th></th></tr></thead>
58
+ <tbody>
59
+ ${ports.map((port, i) => html `
60
+ <tr>
61
+ <td><select @change=${(e) => { e.stopPropagation(); this._set(ports, i, 'type', e.target.value); }}>
62
+ <option value="in" ?selected=${port.type === 'in'}>IN</option>
63
+ <option value="out" ?selected=${port.type === 'out'}>OUT</option>
64
+ </select></td>
65
+ <td><select @change=${(e) => { e.stopPropagation(); this._set(ports, i, 'side', e.target.value); }}>
66
+ <option value="front" ?selected=${port.side === 'front'}>Front</option>
67
+ <option value="back" ?selected=${port.side === 'back'}>Back</option>
68
+ </select></td>
69
+ <td><input type="number" .value=${String(port.position)} min="1" step="1"
70
+ @change=${(e) => { e.stopPropagation(); this._set(ports, i, 'position', Number(e.target.value)); }} /></td>
71
+ <td><input type="text" .value=${port.label || ''} placeholder="auto"
72
+ @change=${(e) => { e.stopPropagation(); this._set(ports, i, 'label', e.target.value || undefined); }} /></td>
73
+ <td><button class="btn-remove" @click=${() => this._applyPorts(ports.filter((_, j) => j !== i))}>&times;</button></td>
74
+ </tr>
75
+ `)}
76
+ </tbody>
77
+ </table>
78
+ ` : html `<div style="font-size:11px;color:#888;padding:4px">No ports</div>`}
79
+ <div class="btn-row">
80
+ <button class="btn" @click=${() => {
81
+ const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0;
82
+ this._applyPorts([...ports, { type: 'in', side: 'front', position: maxPos + 1 }]);
83
+ }}>+ IN</button>
84
+ <button class="btn" @click=${() => {
85
+ const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0;
86
+ this._applyPorts([...ports, { type: 'out', side: 'front', position: maxPos + 1 }]);
87
+ }}>+ OUT</button>
88
+ </div>
89
+ </fieldset>
90
+ `;
91
+ }
92
+ _set(ports, index, field, val) {
93
+ this._applyPorts(ports.map((p, i) => i === index ? { ...p, [field]: val } : p));
94
+ }
95
+ _applyPorts(ports) {
96
+ this.value = ports;
97
+ this.requestUpdate();
98
+ this.dispatchEvent(new CustomEvent('i-need-selected', {
99
+ bubbles: true, composed: true,
100
+ detail: {
101
+ callback: (selected) => {
102
+ selected[0]?.set('ports', JSON.stringify(ports));
103
+ }
104
+ }
105
+ }));
106
+ }
107
+ };
108
+ StockerPortsEditor = __decorate([
109
+ customElement('property-editor-stocker-ports')
110
+ ], StockerPortsEditor);
111
+ export default StockerPortsEditor;
112
+ //# sourceMappingURL=property-editor-stocker-ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"property-editor-stocker-ports.js","sourceRoot":"","sources":["../../src/editors/property-editor-stocker-ports.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;;AAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAkB,MAAM,KAAK,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAgB,MAAM,0BAA0B,CAAA;AASzE,SAAS,UAAU,CAAC,KAAU;IAC5B,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAA;IACrB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAChC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;QAC5C,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,EAAE,CAAA;QAAC,CAAC;IACvB,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC;AAGc,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,gBAAgB;IAC9D,MAAM,CAAC,MAAM,GAAG;QACd,GAAG,gBAAgB,CAAC,MAAM;QAC1B,GAAG,CAAA;;;;;;;;;;;;;;;;;KAiBF;KACF,CAAA;IAED,cAAc,CAAC,KAAU,EAAE,KAAmB;QAC5C,MAAM,KAAK,GAAgB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QAErF,OAAO,IAAI,CAAA;;UAEL,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;;;;gBAIjB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;;wCAEH,CAAC,CAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAG,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC;mDAC9F,IAAI,CAAC,IAAI,KAAK,IAAI;oDACjB,IAAI,CAAC,IAAI,KAAK,KAAK;;wCAE/B,CAAC,CAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAG,CAAC,CAAC,MAA4B,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC;sDAC3F,IAAI,CAAC,IAAI,KAAK,OAAO;qDACtB,IAAI,CAAC,IAAI,KAAK,MAAM;;oDAErB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;8BAC3C,CAAC,CAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,CAAC,CAAA,CAAC,CAAC;kDAChG,IAAI,CAAC,KAAK,IAAI,EAAE;8BACpC,CAAC,CAAQ,EAAE,EAAE,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK,IAAI,SAAS,CAAC,CAAA,CAAC,CAAC;0DAC1F,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;;eAElG,CAAC;;;SAGP,CAAC,CAAC,CAAC,IAAI,CAAA,mEAAmE;;uCAE5C,GAAG,EAAE;YAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC7E,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,IAAa,EAAE,IAAI,EAAE,OAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QACrG,CAAC;uCAC4B,GAAG,EAAE;YAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC7E,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,KAAc,EAAE,IAAI,EAAE,OAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QACtG,CAAC;;;KAGN,CAAA;IACH,CAAC;IAEO,IAAI,CAAC,KAAkB,EAAE,KAAa,EAAE,KAAa,EAAE,GAAQ;QACrE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACjF,CAAC;IAEO,WAAW,CAAC,KAAkB;QACpC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,aAAa,EAAE,CAAA;QAEpB,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,iBAAiB,EAAE;YACpD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI;YAC7B,MAAM,EAAE;gBACN,QAAQ,EAAE,CAAC,QAAe,EAAE,EAAE;oBAC5B,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;gBAClD,CAAC;aACF;SACF,CAAC,CAAC,CAAA;IACL,CAAC;;AAlFkB,kBAAkB;IADtC,aAAa,CAAC,+BAA+B,CAAC;GAC1B,kBAAkB,CAmFtC;eAnFoB,kBAAkB","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Stocker Port Configuration Editor\n *\n * 주의: OxPropertyEditor base class가 모든 change 이벤트를 잡아서\n * this.value를 덮어쓰므로, 내부 input/select의 change 이벤트 버블링을 차단해야 함.\n */\n\nimport { css, html, TemplateResult } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport { OxPropertyEditor, PropertySpec } from '@operato/property-editor'\n\ninterface PortEntry {\n type: 'in' | 'out'\n side: 'front' | 'back'\n position: number\n label?: string\n}\n\nfunction parsePorts(value: any): PortEntry[] {\n if (!value) return []\n if (Array.isArray(value)) return value\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value)\n return Array.isArray(parsed) ? parsed : []\n } catch { return [] }\n }\n return []\n}\n\n@customElement('property-editor-stocker-ports')\nexport default class StockerPortsEditor extends OxPropertyEditor {\n static styles = [\n ...OxPropertyEditor.styles,\n css`\n .port-table { width: 100%; font-size: 11px; border-collapse: collapse; }\n .port-table th { text-align: left; padding: 3px 4px; font-weight: 600; color: #555; border-bottom: 1px solid rgba(0,0,0,0.12); font-size: 10px; }\n .port-table td { padding: 2px 3px; vertical-align: middle; }\n .port-table select, .port-table input {\n width: 100%; box-sizing: border-box; font-size: 11px; padding: 3px 4px;\n border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #fff; color: #1c1b1f;\n }\n .port-table input[type=\"number\"] { width: 50px; }\n .port-table input[type=\"text\"] { width: 60px; }\n .btn-row { display: flex; gap: 4px; margin-top: 4px; }\n .btn {\n padding: 3px 8px; font-size: 10px; cursor: pointer;\n border: 1px solid rgba(0,0,0,0.15); border-radius: 4px; background: #f3edf7; color: #1c1b1f;\n }\n .btn:hover { background: #ece6f0; }\n .btn-remove { color: #b3261e; cursor: pointer; font-size: 14px; padding: 0 4px; background: none; border: none; }\n `\n ]\n\n editorTemplate(value: any, _spec: PropertySpec): TemplateResult {\n const ports: PortEntry[] = Array.isArray(this.value) ? this.value : parsePorts(value)\n\n return html`\n <fieldset fullwidth>\n ${ports.length > 0 ? html`\n <table class=\"port-table\">\n <thead><tr><th>Type</th><th>Side</th><th>Pos</th><th>Label</th><th></th></tr></thead>\n <tbody>\n ${ports.map((port, i) => html`\n <tr>\n <td><select @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'type', (e.target as HTMLSelectElement).value) }}>\n <option value=\"in\" ?selected=${port.type === 'in'}>IN</option>\n <option value=\"out\" ?selected=${port.type === 'out'}>OUT</option>\n </select></td>\n <td><select @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'side', (e.target as HTMLSelectElement).value) }}>\n <option value=\"front\" ?selected=${port.side === 'front'}>Front</option>\n <option value=\"back\" ?selected=${port.side === 'back'}>Back</option>\n </select></td>\n <td><input type=\"number\" .value=${String(port.position)} min=\"1\" step=\"1\"\n @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'position', Number((e.target as HTMLInputElement).value)) }} /></td>\n <td><input type=\"text\" .value=${port.label || ''} placeholder=\"auto\"\n @change=${(e: Event) => { e.stopPropagation(); this._set(ports, i, 'label', (e.target as HTMLInputElement).value || undefined) }} /></td>\n <td><button class=\"btn-remove\" @click=${() => this._applyPorts(ports.filter((_, j) => j !== i))}>&times;</button></td>\n </tr>\n `)}\n </tbody>\n </table>\n ` : html`<div style=\"font-size:11px;color:#888;padding:4px\">No ports</div>`}\n <div class=\"btn-row\">\n <button class=\"btn\" @click=${() => {\n const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0\n this._applyPorts([...ports, { type: 'in' as const, side: 'front' as const, position: maxPos + 1 }])\n }}>+ IN</button>\n <button class=\"btn\" @click=${() => {\n const maxPos = ports.length > 0 ? Math.max(...ports.map(p => p.position)) : 0\n this._applyPorts([...ports, { type: 'out' as const, side: 'front' as const, position: maxPos + 1 }])\n }}>+ OUT</button>\n </div>\n </fieldset>\n `\n }\n\n private _set(ports: PortEntry[], index: number, field: string, val: any) {\n this._applyPorts(ports.map((p, i) => i === index ? { ...p, [field]: val } : p))\n }\n\n private _applyPorts(ports: PortEntry[]) {\n this.value = ports\n this.requestUpdate()\n\n this.dispatchEvent(new CustomEvent('i-need-selected', {\n bubbles: true, composed: true,\n detail: {\n callback: (selected: any[]) => {\n selected[0]?.set('ports', JSON.stringify(ports))\n }\n }\n }))\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -5,6 +5,9 @@ export * from './rack-table-cell.js';
5
5
  export * from './visualizer.js';
6
6
  export * from './stock.js';
7
7
  export * from './signal-tower.js';
8
+ export * from './stock-hub.js';
8
9
  export * from './tank.js';
9
10
  export * from './vehicle.js';
10
11
  export * from './carrier.js';
12
+ export * from './stocker.js';
13
+ export * from './stocker-port.js';
package/dist/index.js CHANGED
@@ -10,7 +10,10 @@ export * from './rack-table-cell.js';
10
10
  export * from './visualizer.js';
11
11
  export * from './stock.js';
12
12
  export * from './signal-tower.js';
13
+ export * from './stock-hub.js';
13
14
  export * from './tank.js';
14
15
  export * from './vehicle.js';
15
16
  export * from './carrier.js';
17
+ export * from './stocker.js';
18
+ export * from './stocker-port.js';
16
19
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6CAA6C;AAC7C,2BAA2B;AAE3B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\n// threed 인프라 + 범용 3D 컴포넌트는 things-scene에서 제공\n// 여기서는 도메인 특화 컴포넌트만 export\n\nexport * from './desk.js'\nexport * from './rack.js'\nexport * from './rack-table.js'\nexport * from './rack-table-cell.js'\nexport * from './visualizer.js'\nexport * from './stock.js'\nexport * from './signal-tower.js'\nexport * from './tank.js'\nexport * from './vehicle.js'\nexport * from './carrier.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,6CAA6C;AAC7C,2BAA2B;AAE3B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\n// threed 인프라 + 범용 3D 컴포넌트는 things-scene에서 제공\n// 여기서는 도메인 특화 컴포넌트만 export\n\nexport * from './desk.js'\nexport * from './rack.js'\nexport * from './rack-table.js'\nexport * from './rack-table-cell.js'\nexport * from './visualizer.js'\nexport * from './stock.js'\nexport * from './signal-tower.js'\nexport * from './stock-hub.js'\nexport * from './tank.js'\nexport * from './vehicle.js'\nexport * from './carrier.js'\nexport * from './stocker.js'\nexport * from './stocker-port.js'\n"]}
@@ -40,6 +40,7 @@ export class RackTable3d extends RealObjectGroup {
40
40
  if (!isEmpty) {
41
41
  cell.setState('shelfLocations', shelfLoc);
42
42
  const rack = new Rack(cell);
43
+ cell._realObject = rack; // 중복 생성 방지: addObject 재귀에서 skip
43
44
  rack.update();
44
45
  this.object3d.add(rack.object3d);
45
46
  return rack;
@@ -1 +1 @@
1
- {"version":3,"file":"rack-table-3d.js","sourceRoot":"","sources":["../src/rack-table-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { Component, RealObjectGroup } from '@hatiolab/things-scene'\n\nimport { Rack } from './rack.js'\nimport type { RackTable } from './rack-table.js'\n\nconst DEFAULT_FRAME_COLOR = 0x8a8a8a\n\nexport class RackTable3d extends RealObjectGroup {\n private _frameMaterial?: THREE.MeshStandardMaterial\n\n build() {\n super.build()\n\n this.createRacks()\n }\n\n get position() {\n const { zPos = 0 } = this.component.state\n\n return {\n x: this.cx || 0,\n y: zPos,\n z: this.cy || 0\n }\n }\n\n private createFrameMaterial(): THREE.MeshStandardMaterial {\n this._frameMaterial?.dispose()\n\n const { strokeStyle } = this.component.state\n const color = strokeStyle && typeof strokeStyle === 'string' ? strokeStyle : DEFAULT_FRAME_COLOR\n\n this._frameMaterial = new THREE.MeshStandardMaterial({\n color,\n roughness: 0.35,\n metalness: 0.85\n })\n\n return this._frameMaterial\n }\n\n createRacks() {\n const { rotation = 0, shelfLocations, shelves = 1 } = this.component.state\n\n this.object3d.rotation.y = -rotation\n\n const racks = (this.component as unknown as RackTable).components\n .map((cell: Component) => {\n const { shelfLocations: shelfLoc = shelfLocations, isEmpty } = cell.state\n\n if (!isEmpty) {\n cell.setState('shelfLocations', shelfLoc)\n\n const rack = new Rack(cell)\n\n rack.update()\n this.object3d.add(rack.object3d)\n\n return rack\n }\n return\n })\n .filter((rack): rack is Rack => !!rack)\n\n this.mergeAndAddRackCommonObjects(racks)\n }\n\n mergeAndAddRackCommonObjects(racks: Rack[]) {\n const framesGeometries: THREE.BufferGeometry[] = []\n const boardsGeometries: THREE.BufferGeometry[] = []\n\n if (racks.length > 0) {\n racks.forEach(rack => {\n const geometry = rack.frame\n\n if (!geometry) {\n return\n }\n\n geometry.translate(rack.position.x, rack.position.y, rack.position.z)\n geometry.scale(rack.scale.x, rack.scale.y, rack.scale.z)\n framesGeometries.push(geometry)\n })\n\n if (framesGeometries.length > 0) {\n const frameMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(framesGeometries), this.createFrameMaterial())\n this.object3d.add(frameMesh)\n }\n\n racks.forEach(rack => {\n const geometry = rack.board\n\n if (!geometry) {\n return\n }\n\n geometry.translate(rack.position.x, rack.position.y, rack.position.z)\n geometry.scale(rack.scale.x, rack.scale.y, rack.scale.z)\n boardsGeometries.push(geometry)\n })\n\n if (boardsGeometries.length > 0) {\n const material = Rack.boardMaterial\n material.opacity = 0.5\n material.transparent = true\n\n const boardMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(boardsGeometries), material)\n\n this.object3d.add(boardMesh)\n }\n }\n }\n\n dispose() {\n this._frameMaterial?.dispose()\n this._frameMaterial = undefined\n\n super.dispose()\n }\n\n updateAlpha() {}\n}\n"]}
1
+ {"version":3,"file":"rack-table-3d.js","sourceRoot":"","sources":["../src/rack-table-3d.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,mBAAmB,MAAM,iDAAiD,CAAA;AACtF,OAAO,EAAa,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAEnE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,MAAM,mBAAmB,GAAG,QAAQ,CAAA;AAEpC,MAAM,OAAO,WAAY,SAAQ,eAAe;IACtC,cAAc,CAA6B;IAEnD,KAAK;QACH,KAAK,CAAC,KAAK,EAAE,CAAA;QAEb,IAAI,CAAC,WAAW,EAAE,CAAA;IACpB,CAAC;IAED,IAAI,QAAQ;QACV,MAAM,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;QAEzC,OAAO;YACL,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;YACf,CAAC,EAAE,IAAI;YACP,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;SAChB,CAAA;IACH,CAAC;IAEO,mBAAmB;QACzB,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,CAAA;QAE9B,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;QAC5C,MAAM,KAAK,GAAG,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAA;QAEhG,IAAI,CAAC,cAAc,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC;YACnD,KAAK;YACL,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,IAAI;SAChB,CAAC,CAAA;QAEF,OAAO,IAAI,CAAC,cAAc,CAAA;IAC5B,CAAC;IAED,WAAW;QACT,MAAM,EAAE,QAAQ,GAAG,CAAC,EAAE,cAAc,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;QAE1E,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAA;QAEpC,MAAM,KAAK,GAAI,IAAI,CAAC,SAAkC,CAAC,UAAU;aAC9D,GAAG,CAAC,CAAC,IAAe,EAAE,EAAE;YACvB,MAAM,EAAE,cAAc,EAAE,QAAQ,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;YAEzE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAA;gBAEzC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAA;gBAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA,CAAC,gCAAgC;gBAExD,IAAI,CAAC,MAAM,EAAE,CAAA;gBACb,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;gBAEhC,OAAO,IAAI,CAAA;YACb,CAAC;YACD,OAAM;QACR,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,IAAI,EAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAEzC,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC,CAAA;IAC1C,CAAC;IAED,4BAA4B,CAAC,KAAa;QACxC,MAAM,gBAAgB,GAA2B,EAAE,CAAA;QACnD,MAAM,gBAAgB,GAA2B,EAAE,CAAA;QAEnD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;gBACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAA;gBAE3B,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,OAAM;gBACR,CAAC;gBAED,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;gBACrE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBACxD,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACjC,CAAC,CAAC,CAAA;YAEF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAA;gBACnH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAC9B,CAAC;YAED,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;gBACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAA;gBAE3B,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,OAAM;gBACR,CAAC;gBAED,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;gBACrE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBACxD,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACjC,CAAC,CAAC,CAAA;YAEF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAA;gBACnC,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAA;gBACtB,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAA;gBAE3B,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,gBAAgB,CAAC,EAAE,QAAQ,CAAC,CAAA;gBAEjG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,CAAA;QAC9B,IAAI,CAAC,cAAc,GAAG,SAAS,CAAA;QAE/B,KAAK,CAAC,OAAO,EAAE,CAAA;IACjB,CAAC;IAED,WAAW,KAAI,CAAC;CACjB","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { Component, RealObjectGroup } from '@hatiolab/things-scene'\n\nimport { Rack } from './rack.js'\nimport type { RackTable } from './rack-table.js'\n\nconst DEFAULT_FRAME_COLOR = 0x8a8a8a\n\nexport class RackTable3d extends RealObjectGroup {\n private _frameMaterial?: THREE.MeshStandardMaterial\n\n build() {\n super.build()\n\n this.createRacks()\n }\n\n get position() {\n const { zPos = 0 } = this.component.state\n\n return {\n x: this.cx || 0,\n y: zPos,\n z: this.cy || 0\n }\n }\n\n private createFrameMaterial(): THREE.MeshStandardMaterial {\n this._frameMaterial?.dispose()\n\n const { strokeStyle } = this.component.state\n const color = strokeStyle && typeof strokeStyle === 'string' ? strokeStyle : DEFAULT_FRAME_COLOR\n\n this._frameMaterial = new THREE.MeshStandardMaterial({\n color,\n roughness: 0.35,\n metalness: 0.85\n })\n\n return this._frameMaterial\n }\n\n createRacks() {\n const { rotation = 0, shelfLocations, shelves = 1 } = this.component.state\n\n this.object3d.rotation.y = -rotation\n\n const racks = (this.component as unknown as RackTable).components\n .map((cell: Component) => {\n const { shelfLocations: shelfLoc = shelfLocations, isEmpty } = cell.state\n\n if (!isEmpty) {\n cell.setState('shelfLocations', shelfLoc)\n\n const rack = new Rack(cell)\n cell._realObject = rack // 중복 생성 방지: addObject 재귀에서 skip\n\n rack.update()\n this.object3d.add(rack.object3d)\n\n return rack\n }\n return\n })\n .filter((rack): rack is Rack => !!rack)\n\n this.mergeAndAddRackCommonObjects(racks)\n }\n\n mergeAndAddRackCommonObjects(racks: Rack[]) {\n const framesGeometries: THREE.BufferGeometry[] = []\n const boardsGeometries: THREE.BufferGeometry[] = []\n\n if (racks.length > 0) {\n racks.forEach(rack => {\n const geometry = rack.frame\n\n if (!geometry) {\n return\n }\n\n geometry.translate(rack.position.x, rack.position.y, rack.position.z)\n geometry.scale(rack.scale.x, rack.scale.y, rack.scale.z)\n framesGeometries.push(geometry)\n })\n\n if (framesGeometries.length > 0) {\n const frameMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(framesGeometries), this.createFrameMaterial())\n this.object3d.add(frameMesh)\n }\n\n racks.forEach(rack => {\n const geometry = rack.board\n\n if (!geometry) {\n return\n }\n\n geometry.translate(rack.position.x, rack.position.y, rack.position.z)\n geometry.scale(rack.scale.x, rack.scale.y, rack.scale.z)\n boardsGeometries.push(geometry)\n })\n\n if (boardsGeometries.length > 0) {\n const material = Rack.boardMaterial\n material.opacity = 0.5\n material.transparent = true\n\n const boardMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(boardsGeometries), material)\n\n this.object3d.add(boardMesh)\n }\n }\n }\n\n dispose() {\n this._frameMaterial?.dispose()\n this._frameMaterial = undefined\n\n super.dispose()\n }\n\n updateAlpha() {}\n}\n"]}
@@ -245,6 +245,19 @@ let RackTable = class RackTable extends ContainerAbstract {
245
245
  this._legendTarget = this.root.findById?.(legendTarget);
246
246
  this._legendTarget?.on('change', this._onLegendChanged, this);
247
247
  }
248
+ // 하위호환: 자체 legendTarget이 없으면 부모(Visualizer)의 legendTarget 폴백
249
+ if (!this._legendTarget) {
250
+ let ancestor = this.parent;
251
+ while (ancestor) {
252
+ if (ancestor.legendTarget)
253
+ return ancestor.legendTarget;
254
+ ancestor = ancestor.parent;
255
+ }
256
+ // 서비스 레지스트리 폴백: stock-hub의 legendTarget
257
+ const stockHub = this.root?.getService?.('stock');
258
+ if (stockHub?.legendTarget)
259
+ return stockHub.legendTarget;
260
+ }
248
261
  return this._legendTarget;
249
262
  }
250
263
  get hideEmptyStock() {