@fmsim/board 2.0.0-beta.98 → 2.0.0
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/custom-elements.json +3317 -2710
- package/dist/src/board-i18n.d.ts +37 -0
- package/dist/src/board-i18n.js +121 -0
- package/dist/src/board-i18n.js.map +1 -0
- package/dist/src/config/flow-replay.d.ts +14 -0
- package/dist/src/config/flow-replay.js +20 -0
- package/dist/src/config/flow-replay.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/layers/mcs-mouse-event-handler.js +21 -4
- package/dist/src/layers/mcs-mouse-event-handler.js.map +1 -1
- package/dist/src/layers/movement-layer.d.ts +5 -2
- package/dist/src/layers/movement-layer.js +19 -2
- package/dist/src/layers/movement-layer.js.map +1 -1
- package/dist/src/modeller/bulk-create-dialog.d.ts +12 -1
- package/dist/src/modeller/bulk-create-dialog.js +67 -3
- package/dist/src/modeller/bulk-create-dialog.js.map +1 -1
- package/dist/src/modeller/bulk-create.d.ts +6 -0
- package/dist/src/modeller/bulk-create.js +3 -1
- package/dist/src/modeller/bulk-create.js.map +1 -1
- package/dist/src/modeller/component-toolbar/component-toolbar.d.ts +6 -0
- package/dist/src/modeller/component-toolbar/component-toolbar.js +18 -2
- package/dist/src/modeller/component-toolbar/component-toolbar.js.map +1 -1
- package/dist/src/modeller/edit-toolbar.js +10 -1
- package/dist/src/modeller/edit-toolbar.js.map +1 -1
- package/dist/src/modeller/property-sidebar/effects/effects.js +3 -2
- package/dist/src/modeller/property-sidebar/effects/effects.js.map +1 -1
- package/dist/src/modeller/property-sidebar/inspector/inspector-controller.d.ts +9 -1
- package/dist/src/modeller/property-sidebar/inspector/inspector-controller.js +34 -4
- package/dist/src/modeller/property-sidebar/inspector/inspector-controller.js.map +1 -1
- package/dist/src/modeller/property-sidebar/inspector/inspector-group-view.d.ts +2 -0
- package/dist/src/modeller/property-sidebar/inspector/inspector-group-view.js +23 -4
- package/dist/src/modeller/property-sidebar/inspector/inspector-group-view.js.map +1 -1
- package/dist/src/modeller/property-sidebar/inspector/inspector.js +28 -5
- package/dist/src/modeller/property-sidebar/inspector/inspector.js.map +1 -1
- package/dist/src/modeller/property-sidebar/shapes/ox-input-entity-id.js +12 -3
- package/dist/src/modeller/property-sidebar/shapes/ox-input-entity-id.js.map +1 -1
- package/dist/src/modeller/property-sidebar/shapes/shapes.js +40 -24
- package/dist/src/modeller/property-sidebar/shapes/shapes.js.map +1 -1
- package/dist/src/modeller/property-sidebar/specifics/parent-object.d.ts +29 -0
- package/dist/src/modeller/property-sidebar/specifics/parent-object.js +74 -0
- package/dist/src/modeller/property-sidebar/specifics/parent-object.js.map +1 -0
- package/dist/src/modeller/property-sidebar/specifics/specifics.d.ts +4 -2
- package/dist/src/modeller/property-sidebar/specifics/specifics.js +13 -31
- package/dist/src/modeller/property-sidebar/specifics/specifics.js.map +1 -1
- package/dist/src/ox-board-modeller.js +9 -2
- package/dist/src/ox-board-modeller.js.map +1 -1
- package/dist/src/ox-board-viewer.js +16 -6
- package/dist/src/ox-board-viewer.js.map +1 -1
- package/dist/src/ox-editor-board-selector.js +4 -2
- package/dist/src/ox-editor-board-selector.js.map +1 -1
- package/dist/src/ox-playback-controls.d.ts +9 -0
- package/dist/src/ox-playback-controls.js +24 -0
- package/dist/src/ox-playback-controls.js.map +1 -1
- package/dist/src/scene-monitor-renderer.d.ts +10 -0
- package/dist/src/scene-monitor-renderer.js +226 -0
- package/dist/src/scene-monitor-renderer.js.map +1 -0
- package/dist/src/selector/ox-board-selector.js +2 -1
- package/dist/src/selector/ox-board-selector.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -15
|
@@ -90,7 +90,8 @@ export class SceneInspector extends LitElement {
|
|
|
90
90
|
selected: this.controller.selected,
|
|
91
91
|
terms,
|
|
92
92
|
isGroupExpanded: (type) => this.controller.isGroupExpanded(type),
|
|
93
|
-
isTypeDimmed: (type) => this.controller.isTypeDimmed(type)
|
|
93
|
+
isTypeDimmed: (type) => this.controller.isTypeDimmed(type),
|
|
94
|
+
isTypeHidden: (type) => this.controller.isTypeHidden(type)
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
return renderInspectorTree(this.scene.root, {
|
|
@@ -163,19 +164,27 @@ export class SceneInspector extends LitElement {
|
|
|
163
164
|
return component;
|
|
164
165
|
}
|
|
165
166
|
_onclick(e) {
|
|
166
|
-
var _a, _b, _c;
|
|
167
|
+
var _a, _b, _c, _d, _e;
|
|
167
168
|
e.stopPropagation();
|
|
168
169
|
const target = e.target;
|
|
170
|
+
// 그룹 hidden 아이콘 클릭 → 그룹(타입) 전원 hidden 토글 (헤더 펼침보다 먼저 처리)
|
|
171
|
+
if (target.classList.contains('group-hidden')) {
|
|
172
|
+
const type = (_b = (_a = target.closest) === null || _a === void 0 ? void 0 : _a.call(target, '[data-group-type]')) === null || _b === void 0 ? void 0 : _b.getAttribute('data-group-type');
|
|
173
|
+
if (type != null)
|
|
174
|
+
this.controller.toggleTypeHidden(type);
|
|
175
|
+
this.requestUpdate();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
169
178
|
// 그룹 dim-out 아이콘 클릭 → 그룹(타입) 포커스 dim 토글 (헤더 펼침보다 먼저 처리)
|
|
170
179
|
if (target.classList.contains('group-dim')) {
|
|
171
|
-
const type = (
|
|
180
|
+
const type = (_d = (_c = target.closest) === null || _c === void 0 ? void 0 : _c.call(target, '[data-group-type]')) === null || _d === void 0 ? void 0 : _d.getAttribute('data-group-type');
|
|
172
181
|
if (type != null)
|
|
173
182
|
this.controller.toggleTypeDim(type);
|
|
174
183
|
this.requestUpdate();
|
|
175
184
|
return;
|
|
176
185
|
}
|
|
177
186
|
// 타입 그룹 헤더 클릭 → 그룹 펼침/접힘 (멤버 행은 헤더의 자손이 아니므로 여기 안 걸림)
|
|
178
|
-
const header = (
|
|
187
|
+
const header = (_e = target.closest) === null || _e === void 0 ? void 0 : _e.call(target, '[data-group-type]');
|
|
179
188
|
if (header) {
|
|
180
189
|
const type = header.getAttribute('data-group-type');
|
|
181
190
|
if (type != null)
|
|
@@ -397,15 +406,29 @@ SceneInspector.styles = [
|
|
|
397
406
|
border-radius: 999px;
|
|
398
407
|
padding: 0 6px;
|
|
399
408
|
}
|
|
409
|
+
.group-hidden,
|
|
400
410
|
.group-dim {
|
|
401
|
-
margin: 0 4px 0 6px;
|
|
402
411
|
font-size: 1em;
|
|
403
412
|
opacity: 0.35;
|
|
404
413
|
cursor: pointer;
|
|
414
|
+
/* 간격은 .group-header 의 flex gap 하나로만 관리 — 개별 마진 중복 금지. */
|
|
415
|
+
margin: 0;
|
|
405
416
|
}
|
|
417
|
+
.group-dim {
|
|
418
|
+
margin-right: 2px; /* 우측 끝 살짝 여백 */
|
|
419
|
+
}
|
|
420
|
+
.group-hidden:hover,
|
|
406
421
|
.group-dim:hover {
|
|
407
422
|
opacity: 0.8;
|
|
408
423
|
}
|
|
424
|
+
/* 토글 미지원 타입(group/Carrier)의 hidden/dim — 자리(정렬)만 유지하고 아이콘은 숨긴다. */
|
|
425
|
+
.group-hidden.placeholder,
|
|
426
|
+
.group-dim.placeholder {
|
|
427
|
+
visibility: hidden;
|
|
428
|
+
pointer-events: none;
|
|
429
|
+
cursor: default;
|
|
430
|
+
}
|
|
431
|
+
.group-header[hidden-group] .group-hidden,
|
|
409
432
|
.group-header[dimmed] .group-dim {
|
|
410
433
|
opacity: 0.95;
|
|
411
434
|
color: var(--md-sys-color-primary, #4a9eff);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/inspector/inspector.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * SceneInspector — 속성패널 inspector 탭 호스트.\n *\n * 얇은 호스트: 검색/뷰모드 상태 + 클릭 위임만 담당하고, scene 상호작용은 InspectorController,\n * 렌더는 뷰 렌더러(트리/타입그룹)로 위임한다.\n */\nimport '@operato/input/ox-input-search.js'\n\nimport { css, html, LitElement, nothing, PropertyValues, TemplateResult } from 'lit'\nimport { property, state } from 'lit/decorators.js'\n\nimport { i18next } from '@operato/i18n'\n\nimport { Component, Scene } from '@hatiolab/things-scene'\n\nimport { parseQuery } from './inspector-model.js'\nimport { InspectorController } from './inspector-controller.js'\nimport { countMatches, renderInspectorTree } from './inspector-tree-view.js'\nimport { renderInspectorGroupView } from './inspector-group-view.js'\n\ntype InspectorViewMode = 'tree' | 'group'\n\n/** 뷰 모드 선호를 세션 간 유지(localStorage). 전역 사용자 선호. */\nconst VIEW_MODE_STORAGE_KEY = 'scene-inspector.view-mode'\n\nfunction readStoredViewMode(): InspectorViewMode {\n try {\n const v = localStorage.getItem(VIEW_MODE_STORAGE_KEY)\n return v === 'group' || v === 'tree' ? v : 'tree'\n } catch {\n return 'tree'\n }\n}\n\nfunction writeStoredViewMode(mode: InspectorViewMode): void {\n try {\n localStorage.setItem(VIEW_MODE_STORAGE_KEY, mode)\n } catch {\n /* localStorage 미가용 — 무시 */\n }\n}\n\nexport class SceneInspector extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n color: var(--scene-inspector-color);\n }\n\n ox-input-search {\n --input-search-padding: 3px;\n --input-search-border-bottom: none;\n --input-search-focus-border-bottom: none;\n --input-search-font: normal 16px var(--theme-font);\n\n border-radius: 999px;\n box-sizing: border-box;\n border: 1px solid var(--secondary-color);\n padding: 0 10px;\n margin: 5px;\n }\n\n div[result] {\n flex: 1;\n\n display: flex;\n flex-direction: column;\n\n overflow-y: auto;\n }\n\n .component {\n display: block;\n overflow: hidden;\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n font-size: 14px;\n }\n\n .component[selected] {\n background-color: var(--scene-inspector-selected-background-color);\n border-top: var(--scene-inspector-selected-border);\n border-bottom: var(--scene-inspector-selected-border);\n }\n [selected] .type {\n font-weight: bold;\n }\n\n span,\n i {\n display: inline-block;\n }\n\n span.type {\n text-overflow: ellipses;\n }\n\n span.name {\n background-color: var(--scene-inspector-name-background-color);\n border-radius: var(--border-radius);\n padding: 0 4px;\n color: #fff;\n font-size: 0.8em;\n }\n\n .eye {\n margin: 0 0 0 4px;\n vertical-align: middle;\n opacity: 0.7;\n font-size: 1em;\n width: 1em;\n color: var(--scene-inspector-eye-icon-color);\n cursor: pointer;\n }\n\n .lock {\n margin: 0;\n vertical-align: middle;\n opacity: 0.3;\n font-size: 1em;\n width: 1em;\n cursor: pointer;\n }\n .lock[locked] {\n opacity: 0.9;\n color: var(--md-sys-color-error, #d9534f);\n }\n\n .collapsed::before,\n .extended::before,\n .collapsespace::before {\n background: var(--url-icon-shell-inspector) no-repeat;\n width: 16px;\n height: 18px;\n display: inline-block;\n content: '';\n opacity: 0.6;\n }\n\n .collapsed::before {\n background-position: 100% -195px;\n }\n\n .extended::before {\n background-position: 100% -295px;\n }\n\n .collapsespace::before {\n background-position: 100% -395px;\n opacity: 0.9;\n width: 16px;\n }\n .collapsed,\n .extended,\n .collapsespace {\n border-left: 1px dotted rgba(0, 0, 0, 0.1);\n }\n\n pre {\n display: inline;\n /* 트리 인덴트(수직라인까지의 간격) 최소화 — depth 당 좁은 폭 */\n font-size: 0.6em;\n margin: 0;\n }\n\n /* 뷰 모드 툴바 */\n div[toolbar] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px 4px;\n }\n div[toolbar] .spacer {\n flex: 1;\n }\n div[toolbar] md-icon {\n cursor: pointer;\n opacity: 0.5;\n font-size: 18px;\n border-radius: 4px;\n padding: 2px;\n }\n div[toolbar] md-icon:hover {\n opacity: 0.9;\n }\n div[toolbar] md-icon[selected] {\n opacity: 1;\n color: var(--md-sys-color-primary, #4a9eff);\n background: rgba(0, 0, 0, 0.05);\n }\n\n /* 타입 그룹 뷰 */\n .group-header {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n padding: 2px 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n }\n .group-header:hover {\n background: rgba(0, 0, 0, 0.03);\n }\n .group-count {\n margin-left: auto;\n font-size: 0.72em;\n font-weight: normal;\n background: var(--scene-inspector-name-background-color);\n color: #fff;\n border-radius: 999px;\n padding: 0 6px;\n }\n .group-dim {\n margin: 0 4px 0 6px;\n font-size: 1em;\n opacity: 0.35;\n cursor: pointer;\n }\n .group-dim:hover {\n opacity: 0.8;\n }\n .group-header[dimmed] .group-dim {\n opacity: 0.95;\n color: var(--md-sys-color-primary, #4a9eff);\n }\n .group-header[dimmed] .group-type {\n opacity: 0.45;\n }\n .group-member {\n padding-left: 8px;\n }\n .muted {\n opacity: 0.4;\n font-style: italic;\n }\n /* 검색 매치 하이라이트 */\n mark {\n background: var(--md-sys-color-tertiary-container, #ffe082);\n color: inherit;\n border-radius: 2px;\n padding: 0 1px;\n }\n `\n ]\n\n @property({ type: Object }) scene?: Scene\n\n @state() private searchText: string = ''\n @state() private viewMode: InspectorViewMode = readStoredViewMode()\n\n private controller = new InspectorController()\n private show: boolean = false\n /** reveal(스크롤) 판정용 직전 선택. */\n private _lastSelected: Component[] = []\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.controller.unbind()\n }\n\n render() {\n return html`\n <ox-input-search\n .placeholder=${i18next.t('text.search with type, id or tag')}\n autofocus\n @change=${(e: Event) => (this.searchText = ((e.target as HTMLInputElement).value || '').toLowerCase())}\n ></ox-input-search>\n\n <div toolbar>\n <md-icon class=\"view-btn\" ?selected=${this.viewMode === 'tree'} title=\"Tree view\" @click=${() => this._setViewMode('tree')}>account_tree</md-icon>\n <md-icon class=\"view-btn\" ?selected=${this.viewMode === 'group'} title=\"Group by type\" @click=${() => this._setViewMode('group')}>category</md-icon>\n <span class=\"spacer\"></span>\n ${this.viewMode === 'group'\n ? html`\n <md-icon title=\"Expand all groups\" @click=${this._expandGroups}>unfold_more</md-icon>\n <md-icon title=\"Collapse to group level\" @click=${this._collapseGroups}>unfold_less</md-icon>\n `\n : nothing}\n </div>\n\n <div result>${this._renderResult()}</div>\n `\n }\n\n private _renderResult(): TemplateResult {\n if (!this.scene) return html``\n\n const terms = parseQuery(this.searchText)\n\n if (this.viewMode === 'group') {\n return renderInspectorGroupView(this.controller.index, {\n selected: this.controller.selected,\n terms,\n isGroupExpanded: (type: string) => this.controller.isGroupExpanded(type),\n isTypeDimmed: (type: string) => this.controller.isTypeDimmed(type)\n })\n }\n\n return renderInspectorTree(this.scene.root, {\n selected: this.controller.selected,\n terms,\n count: countMatches(this.scene.root, terms),\n isExtended: (c: Component) => this.controller.isExtended(c),\n nodeHandleClass: (c: Component) => this.controller.nodeHandleClass(c)\n })\n }\n\n private _setViewMode(mode: InspectorViewMode) {\n if (this.viewMode === mode) return\n this.viewMode = mode\n writeStoredViewMode(mode) // 세션 간 유지\n }\n\n private _collapseGroups = () => {\n this.controller.collapseAllGroups()\n this.requestUpdate()\n }\n\n private _expandGroups = () => {\n const index = this.controller.index\n if (index) this.controller.expandAllGroups([...index.byType.keys()])\n this.requestUpdate()\n }\n\n firstUpdated() {\n dispatchEvent(new Event('resize'))\n\n this.renderRoot.addEventListener('click', this._onclick.bind(this) as EventListener)\n this.renderRoot.addEventListener('dblclick', this._ondblclick.bind(this) as EventListener)\n }\n\n /** 외부에서 강제 재렌더용. */\n refresh() {\n this.requestUpdate()\n }\n\n updated(change: PropertyValues<this>) {\n if (change.has('scene')) {\n this.controller.bind(this.scene, () => this.requestUpdate())\n }\n this._maybeReveal()\n }\n\n /**\n * 선택이 바뀌면(캔버스 등) 해당 항목을 리스트에 노출한다 — 그룹 뷰면 그룹을 펼친 뒤 스크롤.\n * scrollIntoView({block:'nearest'}) 라 이미 보이는 경우(인스펙터 클릭 등)엔 사실상 no-op.\n */\n private _maybeReveal() {\n const selected = this.controller.selected\n const changed =\n selected.length !== this._lastSelected.length || selected.some((c, i) => c !== this._lastSelected[i])\n if (!changed) return\n\n if (selected.length === 0) {\n this._lastSelected = selected\n return\n }\n\n if (this.viewMode === 'group') {\n const types = [...new Set(selected.map(c => c.state.type))]\n if (types.some(t => !this.controller.isGroupExpanded(t))) {\n this.controller.expandAllGroups(types)\n return // _lastSelected 미갱신 → 다음 updated 에서 changed 유지 → 그때 스크롤\n }\n }\n\n this._lastSelected = selected\n this.updateComplete.then(() => {\n const el = this.renderRoot.querySelector('.component[selected]') as HTMLElement | null\n el?.scrollIntoView({ block: 'nearest' })\n })\n }\n\n /** 이벤트 타겟에서 상위로 올라가며 `.component` 를 가진 요소를 찾는다. */\n private _resolveComponent(e: MouseEvent): Component | undefined {\n let targetElement = e.target as HTMLElement & { component: Component }\n let component: Component | undefined\n\n while (!component && targetElement) {\n component = targetElement.component\n\n if (component) break\n\n targetElement = targetElement.parentNode as HTMLElement & { component: Component }\n\n if (!targetElement || targetElement === this.renderRoot) break\n }\n\n return component\n }\n\n _onclick(e: MouseEvent) {\n e.stopPropagation()\n\n const target = e.target as HTMLElement\n\n // 그룹 dim-out 아이콘 클릭 → 그룹(타입) 포커스 dim 토글 (헤더 펼침보다 먼저 처리)\n if (target.classList.contains('group-dim')) {\n const type = target.closest?.('[data-group-type]')?.getAttribute('data-group-type')\n if (type != null) this.controller.toggleTypeDim(type)\n this.requestUpdate()\n return\n }\n\n // 타입 그룹 헤더 클릭 → 그룹 펼침/접힘 (멤버 행은 헤더의 자손이 아니므로 여기 안 걸림)\n const header = target.closest?.('[data-group-type]') as HTMLElement | null\n if (header) {\n const type = header.getAttribute('data-group-type')\n if (type != null) this.controller.toggleGroup(type)\n this.requestUpdate()\n return\n }\n\n const classList = (e.target as HTMLElement).classList\n const component = this._resolveComponent(e)\n\n if (component) {\n if (classList.contains('eye')) {\n this.controller.toggleHidden(component)\n } else if (classList.contains('lock')) {\n this.controller.toggleLocked(component)\n } else if (classList.contains('extended') || classList.contains('collapsed')) {\n this.controller.toggleExtended(component)\n }\n\n // shift = 범위(볼륨) 선택/블록 해제, ctrl/cmd = 개별 토글, 그 외 = 단일 선택\n if (e.shiftKey) {\n this.controller.selectRange(component, parseQuery(this.searchText))\n } else {\n this.controller.select(component, e.metaKey || e.ctrlKey)\n }\n } else {\n if (classList.contains('inspector')) {\n this.show = !this.show\n this.style.height = this.show ? '100%' : ''\n }\n }\n\n this.requestUpdate()\n }\n\n _ondblclick(e: MouseEvent) {\n e.stopPropagation()\n\n const component = this._resolveComponent(e)\n\n if (component) {\n if (component.isContainer()) {\n this.controller.toggleExtended(component)\n }\n // 캔버스를 해당 컴포넌트로 센터 이동(줌).\n this.controller.centerTo(component)\n }\n\n this.requestUpdate()\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"inspector.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/inspector/inspector.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * SceneInspector — 속성패널 inspector 탭 호스트.\n *\n * 얇은 호스트: 검색/뷰모드 상태 + 클릭 위임만 담당하고, scene 상호작용은 InspectorController,\n * 렌더는 뷰 렌더러(트리/타입그룹)로 위임한다.\n */\nimport '@operato/input/ox-input-search.js'\n\nimport { css, html, LitElement, nothing, PropertyValues, TemplateResult } from 'lit'\nimport { property, state } from 'lit/decorators.js'\n\nimport { i18next } from '@operato/i18n'\n\nimport { Component, Scene } from '@hatiolab/things-scene'\n\nimport { parseQuery } from './inspector-model.js'\nimport { InspectorController } from './inspector-controller.js'\nimport { countMatches, renderInspectorTree } from './inspector-tree-view.js'\nimport { renderInspectorGroupView } from './inspector-group-view.js'\n\ntype InspectorViewMode = 'tree' | 'group'\n\n/** 뷰 모드 선호를 세션 간 유지(localStorage). 전역 사용자 선호. */\nconst VIEW_MODE_STORAGE_KEY = 'scene-inspector.view-mode'\n\nfunction readStoredViewMode(): InspectorViewMode {\n try {\n const v = localStorage.getItem(VIEW_MODE_STORAGE_KEY)\n return v === 'group' || v === 'tree' ? v : 'tree'\n } catch {\n return 'tree'\n }\n}\n\nfunction writeStoredViewMode(mode: InspectorViewMode): void {\n try {\n localStorage.setItem(VIEW_MODE_STORAGE_KEY, mode)\n } catch {\n /* localStorage 미가용 — 무시 */\n }\n}\n\nexport class SceneInspector extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n color: var(--scene-inspector-color);\n }\n\n ox-input-search {\n --input-search-padding: 3px;\n --input-search-border-bottom: none;\n --input-search-focus-border-bottom: none;\n --input-search-font: normal 16px var(--theme-font);\n\n border-radius: 999px;\n box-sizing: border-box;\n border: 1px solid var(--secondary-color);\n padding: 0 10px;\n margin: 5px;\n }\n\n div[result] {\n flex: 1;\n\n display: flex;\n flex-direction: column;\n\n overflow-y: auto;\n }\n\n .component {\n display: block;\n overflow: hidden;\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n font-size: 14px;\n }\n\n .component[selected] {\n background-color: var(--scene-inspector-selected-background-color);\n border-top: var(--scene-inspector-selected-border);\n border-bottom: var(--scene-inspector-selected-border);\n }\n [selected] .type {\n font-weight: bold;\n }\n\n span,\n i {\n display: inline-block;\n }\n\n span.type {\n text-overflow: ellipses;\n }\n\n span.name {\n background-color: var(--scene-inspector-name-background-color);\n border-radius: var(--border-radius);\n padding: 0 4px;\n color: #fff;\n font-size: 0.8em;\n }\n\n .eye {\n margin: 0 0 0 4px;\n vertical-align: middle;\n opacity: 0.7;\n font-size: 1em;\n width: 1em;\n color: var(--scene-inspector-eye-icon-color);\n cursor: pointer;\n }\n\n .lock {\n margin: 0;\n vertical-align: middle;\n opacity: 0.3;\n font-size: 1em;\n width: 1em;\n cursor: pointer;\n }\n .lock[locked] {\n opacity: 0.9;\n color: var(--md-sys-color-error, #d9534f);\n }\n\n .collapsed::before,\n .extended::before,\n .collapsespace::before {\n background: var(--url-icon-shell-inspector) no-repeat;\n width: 16px;\n height: 18px;\n display: inline-block;\n content: '';\n opacity: 0.6;\n }\n\n .collapsed::before {\n background-position: 100% -195px;\n }\n\n .extended::before {\n background-position: 100% -295px;\n }\n\n .collapsespace::before {\n background-position: 100% -395px;\n opacity: 0.9;\n width: 16px;\n }\n .collapsed,\n .extended,\n .collapsespace {\n border-left: 1px dotted rgba(0, 0, 0, 0.1);\n }\n\n pre {\n display: inline;\n /* 트리 인덴트(수직라인까지의 간격) 최소화 — depth 당 좁은 폭 */\n font-size: 0.6em;\n margin: 0;\n }\n\n /* 뷰 모드 툴바 */\n div[toolbar] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px 4px;\n }\n div[toolbar] .spacer {\n flex: 1;\n }\n div[toolbar] md-icon {\n cursor: pointer;\n opacity: 0.5;\n font-size: 18px;\n border-radius: 4px;\n padding: 2px;\n }\n div[toolbar] md-icon:hover {\n opacity: 0.9;\n }\n div[toolbar] md-icon[selected] {\n opacity: 1;\n color: var(--md-sys-color-primary, #4a9eff);\n background: rgba(0, 0, 0, 0.05);\n }\n\n /* 타입 그룹 뷰 */\n .group-header {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n padding: 2px 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n }\n .group-header:hover {\n background: rgba(0, 0, 0, 0.03);\n }\n .group-count {\n margin-left: auto;\n font-size: 0.72em;\n font-weight: normal;\n background: var(--scene-inspector-name-background-color);\n color: #fff;\n border-radius: 999px;\n padding: 0 6px;\n }\n .group-hidden,\n .group-dim {\n font-size: 1em;\n opacity: 0.35;\n cursor: pointer;\n /* 간격은 .group-header 의 flex gap 하나로만 관리 — 개별 마진 중복 금지. */\n margin: 0;\n }\n .group-dim {\n margin-right: 2px; /* 우측 끝 살짝 여백 */\n }\n .group-hidden:hover,\n .group-dim:hover {\n opacity: 0.8;\n }\n /* 토글 미지원 타입(group/Carrier)의 hidden/dim — 자리(정렬)만 유지하고 아이콘은 숨긴다. */\n .group-hidden.placeholder,\n .group-dim.placeholder {\n visibility: hidden;\n pointer-events: none;\n cursor: default;\n }\n .group-header[hidden-group] .group-hidden,\n .group-header[dimmed] .group-dim {\n opacity: 0.95;\n color: var(--md-sys-color-primary, #4a9eff);\n }\n .group-header[dimmed] .group-type {\n opacity: 0.45;\n }\n .group-member {\n padding-left: 8px;\n }\n .muted {\n opacity: 0.4;\n font-style: italic;\n }\n /* 검색 매치 하이라이트 */\n mark {\n background: var(--md-sys-color-tertiary-container, #ffe082);\n color: inherit;\n border-radius: 2px;\n padding: 0 1px;\n }\n `\n ]\n\n @property({ type: Object }) scene?: Scene\n\n @state() private searchText: string = ''\n @state() private viewMode: InspectorViewMode = readStoredViewMode()\n\n private controller = new InspectorController()\n private show: boolean = false\n /** reveal(스크롤) 판정용 직전 선택. */\n private _lastSelected: Component[] = []\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.controller.unbind()\n }\n\n render() {\n return html`\n <ox-input-search\n .placeholder=${i18next.t('text.search with type, id or tag')}\n autofocus\n @change=${(e: Event) => (this.searchText = ((e.target as HTMLInputElement).value || '').toLowerCase())}\n ></ox-input-search>\n\n <div toolbar>\n <md-icon class=\"view-btn\" ?selected=${this.viewMode === 'tree'} title=\"Tree view\" @click=${() => this._setViewMode('tree')}>account_tree</md-icon>\n <md-icon class=\"view-btn\" ?selected=${this.viewMode === 'group'} title=\"Group by type\" @click=${() => this._setViewMode('group')}>category</md-icon>\n <span class=\"spacer\"></span>\n ${this.viewMode === 'group'\n ? html`\n <md-icon title=\"Expand all groups\" @click=${this._expandGroups}>unfold_more</md-icon>\n <md-icon title=\"Collapse to group level\" @click=${this._collapseGroups}>unfold_less</md-icon>\n `\n : nothing}\n </div>\n\n <div result>${this._renderResult()}</div>\n `\n }\n\n private _renderResult(): TemplateResult {\n if (!this.scene) return html``\n\n const terms = parseQuery(this.searchText)\n\n if (this.viewMode === 'group') {\n return renderInspectorGroupView(this.controller.index, {\n selected: this.controller.selected,\n terms,\n isGroupExpanded: (type: string) => this.controller.isGroupExpanded(type),\n isTypeDimmed: (type: string) => this.controller.isTypeDimmed(type),\n isTypeHidden: (type: string) => this.controller.isTypeHidden(type)\n })\n }\n\n return renderInspectorTree(this.scene.root, {\n selected: this.controller.selected,\n terms,\n count: countMatches(this.scene.root, terms),\n isExtended: (c: Component) => this.controller.isExtended(c),\n nodeHandleClass: (c: Component) => this.controller.nodeHandleClass(c)\n })\n }\n\n private _setViewMode(mode: InspectorViewMode) {\n if (this.viewMode === mode) return\n this.viewMode = mode\n writeStoredViewMode(mode) // 세션 간 유지\n }\n\n private _collapseGroups = () => {\n this.controller.collapseAllGroups()\n this.requestUpdate()\n }\n\n private _expandGroups = () => {\n const index = this.controller.index\n if (index) this.controller.expandAllGroups([...index.byType.keys()])\n this.requestUpdate()\n }\n\n firstUpdated() {\n dispatchEvent(new Event('resize'))\n\n this.renderRoot.addEventListener('click', this._onclick.bind(this) as EventListener)\n this.renderRoot.addEventListener('dblclick', this._ondblclick.bind(this) as EventListener)\n }\n\n /** 외부에서 강제 재렌더용. */\n refresh() {\n this.requestUpdate()\n }\n\n updated(change: PropertyValues<this>) {\n if (change.has('scene')) {\n this.controller.bind(this.scene, () => this.requestUpdate())\n }\n this._maybeReveal()\n }\n\n /**\n * 선택이 바뀌면(캔버스 등) 해당 항목을 리스트에 노출한다 — 그룹 뷰면 그룹을 펼친 뒤 스크롤.\n * scrollIntoView({block:'nearest'}) 라 이미 보이는 경우(인스펙터 클릭 등)엔 사실상 no-op.\n */\n private _maybeReveal() {\n const selected = this.controller.selected\n const changed =\n selected.length !== this._lastSelected.length || selected.some((c, i) => c !== this._lastSelected[i])\n if (!changed) return\n\n if (selected.length === 0) {\n this._lastSelected = selected\n return\n }\n\n if (this.viewMode === 'group') {\n const types = [...new Set(selected.map(c => c.state.type))]\n if (types.some(t => !this.controller.isGroupExpanded(t))) {\n this.controller.expandAllGroups(types)\n return // _lastSelected 미갱신 → 다음 updated 에서 changed 유지 → 그때 스크롤\n }\n }\n\n this._lastSelected = selected\n this.updateComplete.then(() => {\n const el = this.renderRoot.querySelector('.component[selected]') as HTMLElement | null\n el?.scrollIntoView({ block: 'nearest' })\n })\n }\n\n /** 이벤트 타겟에서 상위로 올라가며 `.component` 를 가진 요소를 찾는다. */\n private _resolveComponent(e: MouseEvent): Component | undefined {\n let targetElement = e.target as HTMLElement & { component: Component }\n let component: Component | undefined\n\n while (!component && targetElement) {\n component = targetElement.component\n\n if (component) break\n\n targetElement = targetElement.parentNode as HTMLElement & { component: Component }\n\n if (!targetElement || targetElement === this.renderRoot) break\n }\n\n return component\n }\n\n _onclick(e: MouseEvent) {\n e.stopPropagation()\n\n const target = e.target as HTMLElement\n\n // 그룹 hidden 아이콘 클릭 → 그룹(타입) 전원 hidden 토글 (헤더 펼침보다 먼저 처리)\n if (target.classList.contains('group-hidden')) {\n const type = target.closest?.('[data-group-type]')?.getAttribute('data-group-type')\n if (type != null) this.controller.toggleTypeHidden(type)\n this.requestUpdate()\n return\n }\n\n // 그룹 dim-out 아이콘 클릭 → 그룹(타입) 포커스 dim 토글 (헤더 펼침보다 먼저 처리)\n if (target.classList.contains('group-dim')) {\n const type = target.closest?.('[data-group-type]')?.getAttribute('data-group-type')\n if (type != null) this.controller.toggleTypeDim(type)\n this.requestUpdate()\n return\n }\n\n // 타입 그룹 헤더 클릭 → 그룹 펼침/접힘 (멤버 행은 헤더의 자손이 아니므로 여기 안 걸림)\n const header = target.closest?.('[data-group-type]') as HTMLElement | null\n if (header) {\n const type = header.getAttribute('data-group-type')\n if (type != null) this.controller.toggleGroup(type)\n this.requestUpdate()\n return\n }\n\n const classList = (e.target as HTMLElement).classList\n const component = this._resolveComponent(e)\n\n if (component) {\n if (classList.contains('eye')) {\n this.controller.toggleHidden(component)\n } else if (classList.contains('lock')) {\n this.controller.toggleLocked(component)\n } else if (classList.contains('extended') || classList.contains('collapsed')) {\n this.controller.toggleExtended(component)\n }\n\n // shift = 범위(볼륨) 선택/블록 해제, ctrl/cmd = 개별 토글, 그 외 = 단일 선택\n if (e.shiftKey) {\n this.controller.selectRange(component, parseQuery(this.searchText))\n } else {\n this.controller.select(component, e.metaKey || e.ctrlKey)\n }\n } else {\n if (classList.contains('inspector')) {\n this.show = !this.show\n this.style.height = this.show ? '100%' : ''\n }\n }\n\n this.requestUpdate()\n }\n\n _ondblclick(e: MouseEvent) {\n e.stopPropagation()\n\n const component = this._resolveComponent(e)\n\n if (component) {\n if (component.isContainer()) {\n this.controller.toggleExtended(component)\n }\n // 캔버스를 해당 컴포넌트로 센터 이동(줌).\n this.controller.centerTo(component)\n }\n\n this.requestUpdate()\n }\n}\n"]}
|
|
@@ -81,6 +81,7 @@ export class OxInputEntityId extends LitElement {
|
|
|
81
81
|
render() {
|
|
82
82
|
return html `
|
|
83
83
|
<input
|
|
84
|
+
part="input"
|
|
84
85
|
.value=${this.value || ''}
|
|
85
86
|
placeholder=${this.placeholder}
|
|
86
87
|
autocomplete="off"
|
|
@@ -148,21 +149,27 @@ export class OxInputEntityId extends LitElement {
|
|
|
148
149
|
this._open = false;
|
|
149
150
|
return;
|
|
150
151
|
}
|
|
152
|
+
// 드롭다운이 열린 상태에서 처리하는 키는 부모(다이얼로그 confirm/cancel 등)로
|
|
153
|
+
// 전파되지 않도록 stopPropagation 한다. (Enter 로 항목 선택 시 다이얼로그가 닫히던 버그.)
|
|
151
154
|
if (e.key === 'ArrowDown') {
|
|
152
155
|
e.preventDefault();
|
|
156
|
+
e.stopPropagation();
|
|
153
157
|
this._activeIndex = (this._activeIndex + 1) % ids.length;
|
|
154
158
|
}
|
|
155
159
|
else if (e.key === 'ArrowUp') {
|
|
156
160
|
e.preventDefault();
|
|
161
|
+
e.stopPropagation();
|
|
157
162
|
this._activeIndex = (this._activeIndex - 1 + ids.length) % ids.length;
|
|
158
163
|
}
|
|
159
164
|
else if (e.key === 'Enter') {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
e.stopPropagation();
|
|
160
167
|
if (this._activeIndex >= 0) {
|
|
161
|
-
e.preventDefault();
|
|
162
168
|
this._commitValue(ids[this._activeIndex]);
|
|
163
169
|
}
|
|
164
170
|
}
|
|
165
171
|
else if (e.key === 'Escape') {
|
|
172
|
+
e.stopPropagation();
|
|
166
173
|
this._open = false;
|
|
167
174
|
this._activeIndex = -1;
|
|
168
175
|
}
|
|
@@ -173,14 +180,16 @@ export class OxInputEntityId extends LitElement {
|
|
|
173
180
|
this._commitValue(id);
|
|
174
181
|
}
|
|
175
182
|
_commitValue(id) {
|
|
176
|
-
var _a;
|
|
177
183
|
this.value = id;
|
|
178
184
|
this._open = false;
|
|
179
185
|
this._activeIndex = -1;
|
|
180
186
|
if (this._input)
|
|
181
187
|
this._input.value = id;
|
|
182
188
|
this._emitChange();
|
|
183
|
-
|
|
189
|
+
// NOTE: blur() 하지 않는다. null 로 blur 하면 relatedTarget=null 이 되어, 팝업 안에서
|
|
190
|
+
// 쓰일 때 OxPopup 의 focusout(밖으로 나감) 판정에 걸려 팝업이 통째로 닫혔다.
|
|
191
|
+
// 드롭다운은 _open=false 로 이미 닫히므로 blur 는 불필요하고, 선택 후 입력창에
|
|
192
|
+
// 포커스가 남는 편이 자연스럽다.
|
|
184
193
|
}
|
|
185
194
|
_emitChange() {
|
|
186
195
|
// 같은 값 재발행 skip (예: 드롭다운 선택 직후 blur 의 native change 중복)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ox-input-entity-id.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/shapes/ox-input-entity-id.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { searchFigureIds, filterFigureIds } from '@fmsim/api'\n\n/**\n * 컴포넌트 ID 입력기 — 자유 입력 + 타입별 백엔드(MCS) 검색 선택을 함께 제공.\n *\n * - 기존처럼 자유롭게 텍스트로 ID 를 입력할 수 있다 (commit = blur/Enter).\n * - input 에 *포커스가 가면* 아래로 검색 드롭다운이 펼쳐진다. `entityType`\n * (컴포넌트 타입) 으로 MCS 에 정의된 ID 후보를 조회한다.\n * - machine 타입 → 머신 id 가 1레벨 평면으로 (선택 가능)\n * - unit 타입 → machine 이 그룹 헤더, 그 아래 unit id 가 자식 (선택 가능).\n * 컴포넌트가 부모 machine 을 알면(`machine` prop) 그 머신으로 좁혀 조회.\n *\n * value-key=\"id\" 와 함께 property-grid 안에 두면, 이 host 가 `change`(bubbles+\n * composed) 를 발행하므로 AbstractProperty 제너릭 핸들러가 `element.value` 를\n * 읽어 property-change 로 전파한다.\n *\n * 등록: 패널 자식 커스텀 엘리먼트 컨벤션에 따라 전역 `@customElement` 가 아니라\n * 부모 패널(PropertyShapes)의 `scopedElements` 로 등록한다 (@open-wc/scoped-elements).\n */\nexport class OxInputEntityId extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n position: relative;\n display: flex;\n align-items: stretch;\n width: 100%;\n height: 100%;\n }\n\n input {\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n margin: 0;\n padding: var(--input-padding, 2px 4px);\n font: inherit;\n border: var(--property-sidebar-fieldset-border, 1px solid #ccc);\n }\n\n .dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n z-index: 100;\n\n max-height: 220px;\n overflow-y: auto;\n\n margin-top: 2px;\n background: var(--md-sys-color-surface, #fff);\n border: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);\n border-radius: 4px;\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.18);\n }\n\n .group-header {\n padding: 3px 8px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--md-sys-color-on-surface-variant, #777);\n background: var(--md-sys-color-surface-variant, #eef0f3);\n position: sticky;\n top: 0;\n }\n\n .item {\n padding: 4px 8px;\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font: var(--property-sidebar-fieldset-label, 12px sans-serif);\n }\n\n /* unit 항목 (그룹 자식) 은 살짝 들여쓰기 */\n .item.child {\n padding-left: 18px;\n }\n\n .item:hover,\n .item.active {\n background: var(--md-sys-color-secondary-container, #d7e3ff);\n }\n\n .hint {\n padding: 6px 8px;\n color: var(--md-sys-color-on-surface-variant, #888);\n font-size: 11px;\n }\n `\n ]\n\n /** 현재 ID 값. */\n @property({ type: String }) value = ''\n /** 검색 조건 — 선택된 컴포넌트 타입 (예: 'STOCKER', 'AGV', 'Port'). */\n @property({ type: String }) entityType = ''\n /** 검색 조건 — 부모 machine id (unit 컴포넌트가 소속 machine 을 알 때). */\n @property({ type: String }) machine = ''\n /** machine 필수 타입(예: Port) — machine 없으면 조회하지 않는다 (후보 과다 방지). */\n @property({ type: Boolean }) requireMachine = false\n /** 백엔드 조회 대신 사용할 로컬 후보 리스트 (예: parentObject — 씬의 머신들). null 이면 백엔드 조회. */\n @property({ type: Array }) localItems: string[] | null = null\n @property({ type: String }) placeholder = ''\n\n @state() private _open = false\n /** 서버에서 받은 전체 후보 리스트 (포커스 시 1회 조회, 키워드 미적용). */\n @state() private _all: string[] = []\n @state() private _loading = false\n /** machine 필수인데 machine 미지정이라 조회를 보류한 상태. */\n @state() private _needMachine = false\n /** 선택 가능 항목 기준 active index. */\n @state() private _activeIndex = -1\n\n @query('input') private _input!: HTMLInputElement\n\n private _blurTimer?: ReturnType<typeof setTimeout>\n private _loadSeq = 0\n /** 마지막으로 발행한 값 — 같은 값 재발행(undo 중복) 방지. */\n private _lastEmitted?: string\n\n disconnectedCallback() {\n super.disconnectedCallback()\n clearTimeout(this._blurTimer)\n }\n\n updated(changed: PropertyValues) {\n // 열린 상태에서 조회 조건(타입/부모 머신)이 바뀌면 재조회 (예: 부모 머신을 방금 지정).\n if (this._open && (changed.has('entityType') || changed.has('machine') || changed.has('localItems'))) {\n this._load()\n }\n // 화살표 키로 active 항목 이동 시 항상 보이도록 드롭다운을 스크롤.\n if (changed.has('_activeIndex') && this._open && this._activeIndex >= 0) {\n const el = this.renderRoot.querySelector('.item.active') as HTMLElement | null\n el?.scrollIntoView({ block: 'nearest' })\n }\n }\n\n /**\n * 드롭다운 표시 항목 — 입력값(초기값 포함)으로 풀텍스트 로컬 필터.\n * 단, 매치가 0이면 전체 후보로 fallback (막다른 \"결과 없음\" 방지 — 예: committed\n * id 가 후보 형식과 달라 안 맞는 경우). 서버 재조회 없음.\n */\n private get _items(): string[] {\n if (!this._all.length) return []\n const filtered = filterFigureIds(this._all, this.value || '')\n return filtered.length ? filtered : this._all\n }\n\n /** 드롭다운에서 선택 가능한 id 들 (표시 순서). */\n private get _selectableIds(): string[] {\n return this._items\n }\n\n render() {\n return html`\n <input\n .value=${this.value || ''}\n placeholder=${this.placeholder}\n autocomplete=\"off\"\n @focus=${this._onFocus}\n @blur=${this._onBlur}\n @input=${this._onInput}\n @change=${this._onInputCommit}\n @keydown=${this._onKeydown}\n />\n ${this._open ? this._renderDropdown() : ''}\n `\n }\n\n private _renderDropdown() {\n if (this._needMachine) {\n return html`<div class=\"dropdown\">\n <div class=\"hint\"><ox-i18n msgid=\"text.need-parent-machine\">상위 머신을 먼저 지정하세요</ox-i18n></div>\n </div>`\n }\n if (this._loading) {\n return html`<div class=\"dropdown\"><div class=\"hint\"><ox-i18n msgid=\"text.searching\">searching…</ox-i18n></div></div>`\n }\n if (!this._items.length) {\n return html`<div class=\"dropdown\"><div class=\"hint\"><ox-i18n msgid=\"text.no-results\">no results</ox-i18n></div></div>`\n }\n\n return html`\n <div class=\"dropdown\">\n ${this._items.map(\n (id, idx) => html`\n <div\n class=\"item ${idx === this._activeIndex ? 'active' : ''}\"\n @mousedown=${(e: MouseEvent) => this._select(id, e)}\n >\n ${id}\n </div>\n `\n )}\n </div>\n `\n }\n\n private _onFocus() {\n clearTimeout(this._blurTimer)\n this._open = true\n this._activeIndex = -1\n this._load()\n }\n\n private _onBlur() {\n // 드롭다운 항목 mousedown 이 먼저 처리되도록 약간 지연 후 닫기\n this._blurTimer = setTimeout(() => {\n this._open = false\n this._activeIndex = -1\n }, 150)\n }\n\n private _onInput(e: Event) {\n this.value = (e.target as HTMLInputElement).value\n this._open = true\n this._activeIndex = -1\n }\n\n /** 자유 입력 commit (blur/Enter 의 native change) — 기존 free-text 동작 보존. */\n private _onInputCommit(e: Event) {\n this.value = (e.target as HTMLInputElement).value\n this._emitChange()\n }\n\n private _onKeydown(e: KeyboardEvent) {\n const ids = this._selectableIds\n if (!this._open || !ids.length) {\n if (e.key === 'Escape') this._open = false\n return\n }\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n this._activeIndex = (this._activeIndex + 1) % ids.length\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n this._activeIndex = (this._activeIndex - 1 + ids.length) % ids.length\n } else if (e.key === 'Enter') {\n if (this._activeIndex >= 0) {\n e.preventDefault()\n this._commitValue(ids[this._activeIndex])\n }\n } else if (e.key === 'Escape') {\n this._open = false\n this._activeIndex = -1\n }\n }\n\n private _select(id: string, e: MouseEvent) {\n // mousedown 기본동작(blur) 막아 흐름 제어\n e.preventDefault()\n this._commitValue(id)\n }\n\n private _commitValue(id: string) {\n this.value = id\n this._open = false\n this._activeIndex = -1\n if (this._input) this._input.value = id\n this._emitChange()\n this._input?.blur()\n }\n\n private _emitChange() {\n // 같은 값 재발행 skip (예: 드롭다운 선택 직후 blur 의 native change 중복)\n if (this.value === this._lastEmitted) return\n this._lastEmitted = this.value\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n }\n\n /**\n * 후보 전체를 1회 조회 (포커스 시). keyword 는 보내지 않으며, 표시 필터는 _items\n * 게터가 로컬에서 처리한다. entityType(+unit 이면 machine) 만 서버로 보낸다.\n */\n private async _load() {\n // 로컬 리스트 모드(예: parentObject) — 백엔드 조회 없이 주어진 리스트 사용.\n if (this.localItems != null) {\n this._needMachine = false\n this._loading = false\n this._all = this.localItems\n return\n }\n if (!this.entityType) {\n this._all = []\n return\n }\n // machine 필수 타입(Port 등)인데 부모 머신 미지정 → 조회 보류 (후보 과다 방지).\n if (this.requireMachine && !this.machine) {\n this._all = []\n this._needMachine = true\n return\n }\n this._needMachine = false\n const seq = ++this._loadSeq\n this._loading = true\n try {\n const ids = await searchFigureIds(this.entityType, '', this.machine ? { machine: this.machine } : {})\n if (seq !== this._loadSeq) return // 더 최신 조회가 있으면 폐기\n this._all = ids\n } catch {\n if (seq === this._loadSeq) this._all = []\n } finally {\n if (seq === this._loadSeq) this._loading = false\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ox-input-entity-id.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/shapes/ox-input-entity-id.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { property, query, state } from 'lit/decorators.js'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { searchFigureIds, filterFigureIds } from '@fmsim/api'\n\n/**\n * 컴포넌트 ID 입력기 — 자유 입력 + 타입별 백엔드(MCS) 검색 선택을 함께 제공.\n *\n * - 기존처럼 자유롭게 텍스트로 ID 를 입력할 수 있다 (commit = blur/Enter).\n * - input 에 *포커스가 가면* 아래로 검색 드롭다운이 펼쳐진다. `entityType`\n * (컴포넌트 타입) 으로 MCS 에 정의된 ID 후보를 조회한다.\n * - machine 타입 → 머신 id 가 1레벨 평면으로 (선택 가능)\n * - unit 타입 → machine 이 그룹 헤더, 그 아래 unit id 가 자식 (선택 가능).\n * 컴포넌트가 부모 machine 을 알면(`machine` prop) 그 머신으로 좁혀 조회.\n *\n * value-key=\"id\" 와 함께 property-grid 안에 두면, 이 host 가 `change`(bubbles+\n * composed) 를 발행하므로 AbstractProperty 제너릭 핸들러가 `element.value` 를\n * 읽어 property-change 로 전파한다.\n *\n * 등록: 패널 자식 커스텀 엘리먼트 컨벤션에 따라 전역 `@customElement` 가 아니라\n * 부모 패널(PropertyShapes)의 `scopedElements` 로 등록한다 (@open-wc/scoped-elements).\n */\nexport class OxInputEntityId extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n position: relative;\n display: flex;\n align-items: stretch;\n width: 100%;\n height: 100%;\n }\n\n input {\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n margin: 0;\n padding: var(--input-padding, 2px 4px);\n font: inherit;\n border: var(--property-sidebar-fieldset-border, 1px solid #ccc);\n }\n\n .dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n z-index: 100;\n\n max-height: 220px;\n overflow-y: auto;\n\n margin-top: 2px;\n background: var(--md-sys-color-surface, #fff);\n border: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);\n border-radius: 4px;\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.18);\n }\n\n .group-header {\n padding: 3px 8px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--md-sys-color-on-surface-variant, #777);\n background: var(--md-sys-color-surface-variant, #eef0f3);\n position: sticky;\n top: 0;\n }\n\n .item {\n padding: 4px 8px;\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font: var(--property-sidebar-fieldset-label, 12px sans-serif);\n }\n\n /* unit 항목 (그룹 자식) 은 살짝 들여쓰기 */\n .item.child {\n padding-left: 18px;\n }\n\n .item:hover,\n .item.active {\n background: var(--md-sys-color-secondary-container, #d7e3ff);\n }\n\n .hint {\n padding: 6px 8px;\n color: var(--md-sys-color-on-surface-variant, #888);\n font-size: 11px;\n }\n `\n ]\n\n /** 현재 ID 값. */\n @property({ type: String }) value = ''\n /** 검색 조건 — 선택된 컴포넌트 타입 (예: 'STOCKER', 'AGV', 'Port'). */\n @property({ type: String }) entityType = ''\n /** 검색 조건 — 부모 machine id (unit 컴포넌트가 소속 machine 을 알 때). */\n @property({ type: String }) machine = ''\n /** machine 필수 타입(예: Port) — machine 없으면 조회하지 않는다 (후보 과다 방지). */\n @property({ type: Boolean }) requireMachine = false\n /** 백엔드 조회 대신 사용할 로컬 후보 리스트 (예: parentObject — 씬의 머신들). null 이면 백엔드 조회. */\n @property({ type: Array }) localItems: string[] | null = null\n @property({ type: String }) placeholder = ''\n\n @state() private _open = false\n /** 서버에서 받은 전체 후보 리스트 (포커스 시 1회 조회, 키워드 미적용). */\n @state() private _all: string[] = []\n @state() private _loading = false\n /** machine 필수인데 machine 미지정이라 조회를 보류한 상태. */\n @state() private _needMachine = false\n /** 선택 가능 항목 기준 active index. */\n @state() private _activeIndex = -1\n\n @query('input') private _input!: HTMLInputElement\n\n private _blurTimer?: ReturnType<typeof setTimeout>\n private _loadSeq = 0\n /** 마지막으로 발행한 값 — 같은 값 재발행(undo 중복) 방지. */\n private _lastEmitted?: string\n\n disconnectedCallback() {\n super.disconnectedCallback()\n clearTimeout(this._blurTimer)\n }\n\n updated(changed: PropertyValues) {\n // 열린 상태에서 조회 조건(타입/부모 머신)이 바뀌면 재조회 (예: 부모 머신을 방금 지정).\n if (this._open && (changed.has('entityType') || changed.has('machine') || changed.has('localItems'))) {\n this._load()\n }\n // 화살표 키로 active 항목 이동 시 항상 보이도록 드롭다운을 스크롤.\n if (changed.has('_activeIndex') && this._open && this._activeIndex >= 0) {\n const el = this.renderRoot.querySelector('.item.active') as HTMLElement | null\n el?.scrollIntoView({ block: 'nearest' })\n }\n }\n\n /**\n * 드롭다운 표시 항목 — 입력값(초기값 포함)으로 풀텍스트 로컬 필터.\n * 단, 매치가 0이면 전체 후보로 fallback (막다른 \"결과 없음\" 방지 — 예: committed\n * id 가 후보 형식과 달라 안 맞는 경우). 서버 재조회 없음.\n */\n private get _items(): string[] {\n if (!this._all.length) return []\n const filtered = filterFigureIds(this._all, this.value || '')\n return filtered.length ? filtered : this._all\n }\n\n /** 드롭다운에서 선택 가능한 id 들 (표시 순서). */\n private get _selectableIds(): string[] {\n return this._items\n }\n\n render() {\n return html`\n <input\n part=\"input\"\n .value=${this.value || ''}\n placeholder=${this.placeholder}\n autocomplete=\"off\"\n @focus=${this._onFocus}\n @blur=${this._onBlur}\n @input=${this._onInput}\n @change=${this._onInputCommit}\n @keydown=${this._onKeydown}\n />\n ${this._open ? this._renderDropdown() : ''}\n `\n }\n\n private _renderDropdown() {\n if (this._needMachine) {\n return html`<div class=\"dropdown\">\n <div class=\"hint\"><ox-i18n msgid=\"text.need-parent-machine\">상위 머신을 먼저 지정하세요</ox-i18n></div>\n </div>`\n }\n if (this._loading) {\n return html`<div class=\"dropdown\"><div class=\"hint\"><ox-i18n msgid=\"text.searching\">searching…</ox-i18n></div></div>`\n }\n if (!this._items.length) {\n return html`<div class=\"dropdown\"><div class=\"hint\"><ox-i18n msgid=\"text.no-results\">no results</ox-i18n></div></div>`\n }\n\n return html`\n <div class=\"dropdown\">\n ${this._items.map(\n (id, idx) => html`\n <div\n class=\"item ${idx === this._activeIndex ? 'active' : ''}\"\n @mousedown=${(e: MouseEvent) => this._select(id, e)}\n >\n ${id}\n </div>\n `\n )}\n </div>\n `\n }\n\n private _onFocus() {\n clearTimeout(this._blurTimer)\n this._open = true\n this._activeIndex = -1\n this._load()\n }\n\n private _onBlur() {\n // 드롭다운 항목 mousedown 이 먼저 처리되도록 약간 지연 후 닫기\n this._blurTimer = setTimeout(() => {\n this._open = false\n this._activeIndex = -1\n }, 150)\n }\n\n private _onInput(e: Event) {\n this.value = (e.target as HTMLInputElement).value\n this._open = true\n this._activeIndex = -1\n }\n\n /** 자유 입력 commit (blur/Enter 의 native change) — 기존 free-text 동작 보존. */\n private _onInputCommit(e: Event) {\n this.value = (e.target as HTMLInputElement).value\n this._emitChange()\n }\n\n private _onKeydown(e: KeyboardEvent) {\n const ids = this._selectableIds\n if (!this._open || !ids.length) {\n if (e.key === 'Escape') this._open = false\n return\n }\n // 드롭다운이 열린 상태에서 처리하는 키는 부모(다이얼로그 confirm/cancel 등)로\n // 전파되지 않도록 stopPropagation 한다. (Enter 로 항목 선택 시 다이얼로그가 닫히던 버그.)\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n e.stopPropagation()\n this._activeIndex = (this._activeIndex + 1) % ids.length\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n e.stopPropagation()\n this._activeIndex = (this._activeIndex - 1 + ids.length) % ids.length\n } else if (e.key === 'Enter') {\n e.preventDefault()\n e.stopPropagation()\n if (this._activeIndex >= 0) {\n this._commitValue(ids[this._activeIndex])\n }\n } else if (e.key === 'Escape') {\n e.stopPropagation()\n this._open = false\n this._activeIndex = -1\n }\n }\n\n private _select(id: string, e: MouseEvent) {\n // mousedown 기본동작(blur) 막아 흐름 제어\n e.preventDefault()\n this._commitValue(id)\n }\n\n private _commitValue(id: string) {\n this.value = id\n this._open = false\n this._activeIndex = -1\n if (this._input) this._input.value = id\n this._emitChange()\n // NOTE: blur() 하지 않는다. null 로 blur 하면 relatedTarget=null 이 되어, 팝업 안에서\n // 쓰일 때 OxPopup 의 focusout(밖으로 나감) 판정에 걸려 팝업이 통째로 닫혔다.\n // 드롭다운은 _open=false 로 이미 닫히므로 blur 는 불필요하고, 선택 후 입력창에\n // 포커스가 남는 편이 자연스럽다.\n }\n\n private _emitChange() {\n // 같은 값 재발행 skip (예: 드롭다운 선택 직후 blur 의 native change 중복)\n if (this.value === this._lastEmitted) return\n this._lastEmitted = this.value\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n }\n\n /**\n * 후보 전체를 1회 조회 (포커스 시). keyword 는 보내지 않으며, 표시 필터는 _items\n * 게터가 로컬에서 처리한다. entityType(+unit 이면 machine) 만 서버로 보낸다.\n */\n private async _load() {\n // 로컬 리스트 모드(예: parentObject) — 백엔드 조회 없이 주어진 리스트 사용.\n if (this.localItems != null) {\n this._needMachine = false\n this._loading = false\n this._all = this.localItems\n return\n }\n if (!this.entityType) {\n this._all = []\n return\n }\n // machine 필수 타입(Port 등)인데 부모 머신 미지정 → 조회 보류 (후보 과다 방지).\n if (this.requireMachine && !this.machine) {\n this._all = []\n this._needMachine = true\n return\n }\n this._needMachine = false\n const seq = ++this._loadSeq\n this._loading = true\n try {\n const ids = await searchFigureIds(this.entityType, '', this.machine ? { machine: this.machine } : {})\n if (seq !== this._loadSeq) return // 더 최신 조회가 있으면 폐기\n this._all = ids\n } catch {\n if (seq === this._loadSeq) this._all = []\n } finally {\n if (seq === this._loadSeq) this._loading = false\n }\n }\n}\n"]}
|
|
@@ -9,6 +9,7 @@ import '@operato/i18n/ox-i18n.js';
|
|
|
9
9
|
import { css, html } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
11
11
|
import { keyed } from 'lit/directives/keyed.js';
|
|
12
|
+
import { isThreedEnabled } from '@hatiolab/things-scene';
|
|
12
13
|
import { ScopedElementsMixin } from '@open-wc/scoped-elements';
|
|
13
14
|
import { AbstractProperty } from '../abstract-property';
|
|
14
15
|
import { PropertySharedStyle } from '../property-shared-style';
|
|
@@ -104,11 +105,25 @@ export class PropertyShapes extends ScopedElementsMixin(AbstractProperty) {
|
|
|
104
105
|
${this.selected.length && this.selected[0].isRootModel()
|
|
105
106
|
? html ``
|
|
106
107
|
: html `
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
${isThreedEnabled()
|
|
109
|
+
? html `
|
|
110
|
+
<label class="depth"> <ox-i18n msgid="label.depth">depth</ox-i18n> </label>
|
|
111
|
+
<input
|
|
112
|
+
type="number"
|
|
113
|
+
value-key="depth"
|
|
114
|
+
.value=${String((_a = value.depth) !== null && _a !== void 0 ? _a : '')}
|
|
115
|
+
placeholder="auto"
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
<label class="zPos"> <ox-i18n msgid="label.zPos">zPos</ox-i18n> </label>
|
|
119
|
+
<input
|
|
120
|
+
type="number"
|
|
121
|
+
value-key="zPos"
|
|
122
|
+
.value=${String((_b = value.zPos) !== null && _b !== void 0 ? _b : '')}
|
|
123
|
+
placeholder="auto"
|
|
124
|
+
/>
|
|
125
|
+
`
|
|
126
|
+
: html ``}
|
|
112
127
|
|
|
113
128
|
<label class="rotate"> <ox-i18n msgid="label.rotate">rotate</ox-i18n> </label>
|
|
114
129
|
<ox-input-angle value-key="rotation" .value=${value.rotation}> </ox-input-angle>
|
|
@@ -202,25 +217,26 @@ export class PropertyShapes extends ScopedElementsMixin(AbstractProperty) {
|
|
|
202
217
|
<option value="height">height</option>
|
|
203
218
|
</select>
|
|
204
219
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
${isThreedEnabled()
|
|
221
|
+
? html `
|
|
222
|
+
<div class="checkbox-row">
|
|
223
|
+
<input id="cb-threed" type="checkbox" value-key="threed" .checked=${!!value.threed} />
|
|
224
|
+
<label for="cb-threed"><ox-i18n msgid="label.start-in-3d">Start in 3D</ox-i18n></label>
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
<div class="checkbox-row">
|
|
228
|
+
<input
|
|
229
|
+
id="cb-floor-constraint"
|
|
230
|
+
type="checkbox"
|
|
231
|
+
value-key="cameraFloorConstraint"
|
|
232
|
+
.checked=${!!value.cameraFloorConstraint}
|
|
233
|
+
/>
|
|
234
|
+
<label for="cb-floor-constraint">
|
|
235
|
+
<ox-i18n msgid="label.keep-above-ground">Keep Above Ground</ox-i18n>
|
|
236
|
+
</label>
|
|
237
|
+
</div>
|
|
238
|
+
`
|
|
239
|
+
: html ``}
|
|
224
240
|
|
|
225
241
|
<div class="checkbox-row">
|
|
226
242
|
<input id="cb-id-lookup" type="checkbox" value-key="idLookup" .checked=${value.idLookup !== false} />
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/shapes/shapes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-angle.js'\nimport '@operato/input/ox-buttons-radio.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\n\nimport { BOUNDS, Component, Properties } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { AbstractProperty } from '../abstract-property'\nimport { PropertySharedStyle } from '../property-shared-style'\nimport { BoxPaddingEditorStyles } from './box-padding-editor-styles'\nimport { OxInputEntityId } from './ox-input-entity-id'\n\nexport class PropertyShapes extends ScopedElementsMixin(AbstractProperty) {\n static get scopedElements() {\n return {\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n static styles = [\n PropertySharedStyle,\n BoxPaddingEditorStyles,\n css`\n fieldset[collapsable] legend {\n box-sizing: border-box;\n width: 100%;\n }\n\n fieldset[collapsable] legend md-icon {\n float: right;\n font-size: medium;\n margin: 0;\n cursor: pointer;\n }\n\n fieldset[collapsable][collapsed] > :not(legend) {\n display: none;\n }\n `,\n css`\n .icon-label label {\n background: var(--url-icon-properties-label) 7px -900px no-repeat;\n }\n\n .icon-label .checkbox-row label {\n background: none;\n }\n\n .icon-label label.width {\n background-position: 7px -96px;\n }\n\n .icon-label label.height {\n background-position: 7px 4px;\n }\n\n .icon-label label.rotate {\n background-position: 7px -198px;\n }\n\n .icon-label label.twidth {\n background-position: 7px -296px;\n }\n\n .icon-label label.theight {\n background-position: 7px -396px;\n }\n\n .icon-label label.zPos {\n background-position: 5px -1098px;\n }\n\n .icon-label label.depth {\n background-position: 5px -1198px;\n }\n\n .icon-label label.rotationX {\n background-position: 5px -1296px;\n }\n\n .icon-label label.rotationY {\n background-position: 5px -1396px;\n }\n\n .icon-label label.rotationZ {\n background-position: 5px -1496px;\n }\n\n ox-buttons-radio > * {\n width: 30px;\n height: 25px;\n min-width: initial;\n margin: 0 4px 0 0;\n padding: 0;\n border-radius: 0;\n display: inline-block;\n border-bottom: 2px solid #fff;\n }\n\n ox-buttons-radio div {\n background: var(--url-icon-properties) no-repeat;\n }\n\n ox-buttons-radio div[data-value='left'] {\n background-position: 50% 3px;\n }\n\n ox-buttons-radio div[data-value='center'] {\n background-position: 50% -47px;\n }\n\n ox-buttons-radio div[data-value='right'] {\n background-position: 50% -97px;\n }\n\n ox-buttons-radio div[data-value='justify'] {\n background-position: 50% -147px;\n }\n\n ox-buttons-radio div[data-value='top'] {\n background-position: 50% -197px;\n }\n\n ox-buttons-radio div[data-value='middle'] {\n background-position: 50% -193px;\n }\n\n ox-buttons-radio div[data-value='bottom'] {\n background-position: 50% -188px;\n }\n\n ox-buttons-radio div[active] {\n border-color: #f2471c;\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n @property({ type: Object }) bounds: BOUNDS | null = null\n @property({ type: Array }) selected: Component[] = []\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', this._onValueChange.bind(this))\n }\n\n render() {\n const value = this.value || {}\n const { width, height } = this.bounds || {}\n\n return html`\n <fieldset>\n <div class=\"property-grid\">\n ${this._isIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.id\">ID</ox-i18n> </label>\n ${this._idLookupType(this.selected)\n ? html`\n <ox-input-entity-id\n custom-editor\n value-key=\"id\"\n .value=${value.id || ''}\n .entityType=${this._idLookupType(this.selected)}\n .machine=${this._parentMachineId(this.selected)}\n .requireMachine=${!!(this.selected[0] as any).idLookupRequiresMachine}\n ></ox-input-entity-id>\n `\n : html`<input value-key=\"id\" .value=${value.id || ''} />`}\n `\n : html``}\n ${this._isClassIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.class\">Class</ox-i18n> </label>\n <input value-key=\"class\" .value=${value.class || ''} />\n `\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.text\">Text</ox-i18n> </label>\n <input value-key=\"text\" .value=${value.text || ''} />\n <label> <ox-i18n msgid=\"label.text-format\">Text Format</ox-i18n> </label>\n <input value-key=\"textFormat\" .value=${value.textFormat || ''} list=\"format-list\" />\n <datalist id=\"format-list\">\n <option value=\"#,###.\"></option>\n <option value=\"#,###.#\"></option>\n <option value=\"#,###.0\"></option>\n <option value=\"#,##0.#\"></option>\n <option value=\"#,##0.0\"></option>\n <option value=\"#,##0.0%\"></option>\n </datalist>\n `\n : html``}\n ${this._hasProperties(this.selected)\n ? html`\n <div class=\"checkbox-row\">\n <input id=\"checkbox-hidden\" value-key=\"hidden\" type=\"checkbox\" .checked=${value.hidden} />\n <label for=\"checkbox-hidden\"> <ox-i18n msgid=\"label.item-hidden\">Item Hidden</ox-i18n> </label>\n\n <input id=\"checkbox-locked\" value-key=\"locked\" type=\"checkbox\" .checked=${value.locked} />\n <label for=\"checkbox-locked\"> <ox-i18n msgid=\"label.locked\">Locked</ox-i18n> </label>\n </div>\n `\n : html``}\n </div>\n </fieldset>\n\n ${!this._isLine(this.selected)\n ? keyed(\n this.selected,\n html`\n <fieldset class=\"icon-label unit ratio\">\n <legend>\n <ox-i18n topic=\"board-modeller/shapes/size\" msgid=\"label.size\">size</ox-i18n>\n </legend>\n\n <div class=\"property-grid\">\n <label class=\"width\"> <ox-i18n msgid=\"label.width\">width</ox-i18n> </label>\n <input type=\"number\" value-key=\"bounds.width\" .value=${String(width)} />\n <label class=\"height\"> <ox-i18n msgid=\"label.height\">height</ox-i18n> </label>\n <input type=\"number\" value-key=\"bounds.height\" .value=${String(height)} />\n\n ${this.selected.length && this.selected[0].isRootModel()\n ? html``\n : html`\n <label class=\"depth\"> <ox-i18n msgid=\"label.depth\">depth</ox-i18n> </label>\n <input type=\"number\" value-key=\"depth\" .value=${String(value.depth ?? '')} placeholder=\"auto\" />\n\n <label class=\"zPos\"> <ox-i18n msgid=\"label.zPos\">zPos</ox-i18n> </label>\n <input type=\"number\" value-key=\"zPos\" .value=${String(value.zPos ?? '')} placeholder=\"auto\" />\n\n <label class=\"rotate\"> <ox-i18n msgid=\"label.rotate\">rotate</ox-i18n> </label>\n <ox-input-angle value-key=\"rotation\" .value=${value.rotation}> </ox-input-angle>\n `}\n </div>\n </fieldset>\n `\n )\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <fieldset>\n <legend>\n <ox-i18n topic=\"board-modeller/shapes/text-box\" msgid=\"label.text-box\">text box</ox-i18n>\n </legend>\n\n <div class=\"property-grid\">\n <label> <ox-i18n msgid=\"label.horizontal\">horizontal</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textAlign\" .value=${value.textAlign}>\n <div data-value=\"left\"></div>\n <div data-value=\"center\"></div>\n <div data-value=\"right\"></div>\n <div data-value=\"justify\"></div>\n </ox-buttons-radio>\n\n <label> <ox-i18n msgid=\"label.vertical\">vertical</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textBaseline\" .value=${value.textBaseline}>\n <div data-value=\"top\"></div>\n <div data-value=\"middle\"></div>\n <div data-value=\"bottom\"></div>\n </ox-buttons-radio>\n\n <div class=\"checkbox-row\">\n <input id=\"checkbox-textwrap\" type=\"checkbox\" value-key=\"textWrap\" .checked=${value.textWrap} />\n <label for=\"checkbox-textwrap\"> <ox-i18n msgid=\"label.text-wrap\">Text Wrap</ox-i18n> </label>\n </div>\n\n <div class=\"checkbox-row\">\n <input\n id=\"checkbox-keep-text-angle\"\n type=\"checkbox\"\n value-key=\"keepTextAngle\"\n .checked=${value.keepTextAngle}\n />\n <label for=\"checkbox-keep-text-angle\">\n <ox-i18n msgid=\"label.keep-text-angle\">Keep Text Angle</ox-i18n>\n </label>\n </div>\n\n <label> <ox-i18n msgid=\"label.padding\">padding</ox-i18n> </label>\n <table class=\"box-padding\">\n <tr>\n <td class=\"slide1\"></td>\n <td class=\"slide2\"></td>\n <td class=\"slide3\"></td>\n </tr>\n <tr>\n <td class=\"slide4\"></td>\n <td class=\"slide5\">\n <input type=\"number\" value-key=\"paddingTop\" .value=${value.paddingTop || 0} />\n <input type=\"number\" value-key=\"paddingLeft\" .value=${value.paddingLeft || 0} />\n <input type=\"number\" value-key=\"paddingRight\" .value=${value.paddingRight || 0} />\n <input type=\"number\" value-key=\"paddingBottom\" .value=${value.paddingBottom || 0} />\n </td>\n <td class=\"slide6\"></td>\n </tr>\n <tr>\n <td class=\"slide7\"></td>\n <td class=\"slide8\"></td>\n <td class=\"slide9\"></td>\n </tr>\n </table>\n </div>\n </fieldset>\n `\n : html``}\n ${this.selected.length && this.selected[0].isRootModel()\n ? html`\n <fieldset class=\"icon-label\">\n <legend>\n <ox-i18n topic=\"board-modeller/shapes/viewer-option\" msgid=\"label.viewer-option\">Viewer Option</ox-i18n>\n </legend>\n\n <div class=\"property-grid\">\n <label><ox-i18n msgid=\"label.fit\">Fit</ox-i18n></label>\n <select value-key=\"fitMode\" .value=${value.fitMode || 'ratio'}>\n <option value=\"none\">none</option>\n <option value=\"center\">center</option>\n <option value=\"ratio\" selected>ratio</option>\n <option value=\"both\">both</option>\n <option value=\"width\">width</option>\n <option value=\"height\">height</option>\n </select>\n\n <div class=\"checkbox-row\">\n <input\n id=\"cb-threed\"\n type=\"checkbox\"\n value-key=\"threed\"\n .checked=${!!value.threed}\n />\n <label for=\"cb-threed\"><ox-i18n msgid=\"label.start-in-3d\">Start in 3D</ox-i18n></label>\n </div>\n\n <div class=\"checkbox-row\">\n <input\n id=\"cb-floor-constraint\"\n type=\"checkbox\"\n value-key=\"cameraFloorConstraint\"\n .checked=${!!value.cameraFloorConstraint}\n />\n <label for=\"cb-floor-constraint\"><ox-i18n msgid=\"label.keep-above-ground\">Keep Above Ground</ox-i18n></label>\n </div>\n\n <div class=\"checkbox-row\">\n <input id=\"cb-id-lookup\" type=\"checkbox\" value-key=\"idLookup\" .checked=${value.idLookup !== false} />\n <label for=\"cb-id-lookup\"><ox-i18n msgid=\"label.id-lookup\">ID Lookup</ox-i18n></label>\n </div>\n </div>\n </fieldset>\n `\n : html``}\n `\n }\n\n _onValueChange(e: Event) {\n var element = e.target as HTMLElement\n var key = element.getAttribute('value-key')\n\n if (!key) {\n return\n }\n\n var value = this._getValueFromEventTarget(element)\n\n if (key.indexOf('bounds.') == 0) {\n if (isNaN(value)) return\n this.dispatchEvent(\n new CustomEvent('bounds-change', {\n bubbles: true,\n composed: true,\n detail: {\n [key.substring(7)]: value\n }\n })\n )\n } else {\n this._onAfterValueChange(key, value)\n }\n }\n\n _hasTextProperty(selected: Component[]) {\n for (let i = 0; i < selected.length; i++) {\n if (!selected[i].hasTextProperty) return false\n }\n\n return true\n }\n\n _hasProperties(selected: Component[]) {\n if (!selected || selected.length == 0 || (selected[0] && selected[0].isLayer && selected[0].isLayer())) return false\n\n return true\n }\n\n _isIdentifiable(selected: Component[]) {\n if (\n !selected ||\n selected.length == 0 ||\n selected.length > 1 ||\n !selected[0].isIdentifiable() ||\n (selected[0].isLayer && selected[0].isLayer())\n )\n return false\n\n return true\n }\n\n /**\n * 단일 선택 컴포넌트의 부모 machine id (unit 의 ID 검색 시 조회조건으로 전달).\n * 부모가 루트 모델/레이어가 아니고 id 를 가지면 그 id 를 반환 — unit 이 자신의\n * 소속 machine 을 특정할 수 있는 경우에 해당. 그 외엔 빈 문자열.\n */\n _parentMachineId(selected: Component[]): string {\n const target = selected?.length === 1 ? (selected[0] as any) : null\n if (!target) return ''\n // 명시적 parentObjectId(= 부모 머신 id) 우선, 없으면 실제 scene 부모의 id.\n const pid = target.state?.parentObjectId\n if (pid) return String(pid)\n const parent = target.parent\n if (!parent || parent.isRootModel?.() || (parent.isLayer && parent.isLayer())) return ''\n return parent.state?.id || ''\n }\n\n /**\n * 선택 컴포넌트의 id 조회용 타입명 (capability `idLookupType`). 값이 있으면 그 타입으로\n * 검색 에디터를 띄우고, 없으면(일반 도형·Carrier 등) plain input 으로 두어 불필요한 id\n * 리스트 요청을 보내지 않는다. 기본은 자기 타입이며 컴포넌트가 다른 타입으로 override 가능.\n * (머신/유닛 + Node 가 opt-in. isLVComponent 은 Carrier 포함·Node 제외라 부적합.)\n */\n _idLookupType(selected: Component[]): string | undefined {\n if (selected?.length !== 1) return undefined\n if (!this._idLookupEnabled(selected)) return undefined\n return (selected[0] as any).idLookupType\n }\n\n /** Board 루트 속성 state.idLookup 으로 id 룩업 전체 ON/OFF (기본 ON). */\n _idLookupEnabled(selected: Component[]): boolean {\n const root = (selected?.[0] as any)?.root\n return root?.state?.idLookup !== false\n }\n\n _isClassIdentifiable(selected: Component[]) {\n if (!selected || (selected[0] && selected[0].isLayer())) return false\n\n return true\n }\n\n _isLine(selected: Component[]) {\n if (!selected || !(selected[0] && selected[0].isLine())) return false\n\n return true\n }\n\n _is3dish(selected: Component[]) {\n if (!selected || !(selected[0] && selected[0].is3dish())) return false\n\n return true\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../../../../src/modeller/property-sidebar/shapes/shapes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@operato/input/ox-input-angle.js'\nimport '@operato/input/ox-buttons-radio.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/i18n/ox-i18n.js'\n\nimport { css, html } from 'lit'\nimport { property, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\n\nimport { BOUNDS, Component, Properties, isThreedEnabled } from '@hatiolab/things-scene'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { AbstractProperty } from '../abstract-property'\nimport { PropertySharedStyle } from '../property-shared-style'\nimport { BoxPaddingEditorStyles } from './box-padding-editor-styles'\nimport { OxInputEntityId } from './ox-input-entity-id'\n\nexport class PropertyShapes extends ScopedElementsMixin(AbstractProperty) {\n static get scopedElements() {\n return {\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n static styles = [\n PropertySharedStyle,\n BoxPaddingEditorStyles,\n css`\n fieldset[collapsable] legend {\n box-sizing: border-box;\n width: 100%;\n }\n\n fieldset[collapsable] legend md-icon {\n float: right;\n font-size: medium;\n margin: 0;\n cursor: pointer;\n }\n\n fieldset[collapsable][collapsed] > :not(legend) {\n display: none;\n }\n `,\n css`\n .icon-label label {\n background: var(--url-icon-properties-label) 7px -900px no-repeat;\n }\n\n .icon-label .checkbox-row label {\n background: none;\n }\n\n .icon-label label.width {\n background-position: 7px -96px;\n }\n\n .icon-label label.height {\n background-position: 7px 4px;\n }\n\n .icon-label label.rotate {\n background-position: 7px -198px;\n }\n\n .icon-label label.twidth {\n background-position: 7px -296px;\n }\n\n .icon-label label.theight {\n background-position: 7px -396px;\n }\n\n .icon-label label.zPos {\n background-position: 5px -1098px;\n }\n\n .icon-label label.depth {\n background-position: 5px -1198px;\n }\n\n .icon-label label.rotationX {\n background-position: 5px -1296px;\n }\n\n .icon-label label.rotationY {\n background-position: 5px -1396px;\n }\n\n .icon-label label.rotationZ {\n background-position: 5px -1496px;\n }\n\n ox-buttons-radio > * {\n width: 30px;\n height: 25px;\n min-width: initial;\n margin: 0 4px 0 0;\n padding: 0;\n border-radius: 0;\n display: inline-block;\n border-bottom: 2px solid #fff;\n }\n\n ox-buttons-radio div {\n background: var(--url-icon-properties) no-repeat;\n }\n\n ox-buttons-radio div[data-value='left'] {\n background-position: 50% 3px;\n }\n\n ox-buttons-radio div[data-value='center'] {\n background-position: 50% -47px;\n }\n\n ox-buttons-radio div[data-value='right'] {\n background-position: 50% -97px;\n }\n\n ox-buttons-radio div[data-value='justify'] {\n background-position: 50% -147px;\n }\n\n ox-buttons-radio div[data-value='top'] {\n background-position: 50% -197px;\n }\n\n ox-buttons-radio div[data-value='middle'] {\n background-position: 50% -193px;\n }\n\n ox-buttons-radio div[data-value='bottom'] {\n background-position: 50% -188px;\n }\n\n ox-buttons-radio div[active] {\n border-color: #f2471c;\n }\n `\n ]\n\n @property({ type: Object }) value?: Properties\n @property({ type: Object }) bounds: BOUNDS | null = null\n @property({ type: Array }) selected: Component[] = []\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', this._onValueChange.bind(this))\n }\n\n render() {\n const value = this.value || {}\n const { width, height } = this.bounds || {}\n\n return html`\n <fieldset>\n <div class=\"property-grid\">\n ${this._isIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.id\">ID</ox-i18n> </label>\n ${this._idLookupType(this.selected)\n ? html`\n <ox-input-entity-id\n custom-editor\n value-key=\"id\"\n .value=${value.id || ''}\n .entityType=${this._idLookupType(this.selected)}\n .machine=${this._parentMachineId(this.selected)}\n .requireMachine=${!!(this.selected[0] as any).idLookupRequiresMachine}\n ></ox-input-entity-id>\n `\n : html`<input value-key=\"id\" .value=${value.id || ''} />`}\n `\n : html``}\n ${this._isClassIdentifiable(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.class\">Class</ox-i18n> </label>\n <input value-key=\"class\" .value=${value.class || ''} />\n `\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <label> <ox-i18n msgid=\"label.text\">Text</ox-i18n> </label>\n <input value-key=\"text\" .value=${value.text || ''} />\n <label> <ox-i18n msgid=\"label.text-format\">Text Format</ox-i18n> </label>\n <input value-key=\"textFormat\" .value=${value.textFormat || ''} list=\"format-list\" />\n <datalist id=\"format-list\">\n <option value=\"#,###.\"></option>\n <option value=\"#,###.#\"></option>\n <option value=\"#,###.0\"></option>\n <option value=\"#,##0.#\"></option>\n <option value=\"#,##0.0\"></option>\n <option value=\"#,##0.0%\"></option>\n </datalist>\n `\n : html``}\n ${this._hasProperties(this.selected)\n ? html`\n <div class=\"checkbox-row\">\n <input id=\"checkbox-hidden\" value-key=\"hidden\" type=\"checkbox\" .checked=${value.hidden} />\n <label for=\"checkbox-hidden\"> <ox-i18n msgid=\"label.item-hidden\">Item Hidden</ox-i18n> </label>\n\n <input id=\"checkbox-locked\" value-key=\"locked\" type=\"checkbox\" .checked=${value.locked} />\n <label for=\"checkbox-locked\"> <ox-i18n msgid=\"label.locked\">Locked</ox-i18n> </label>\n </div>\n `\n : html``}\n </div>\n </fieldset>\n\n ${!this._isLine(this.selected)\n ? keyed(\n this.selected,\n html`\n <fieldset class=\"icon-label unit ratio\">\n <legend>\n <ox-i18n topic=\"board-modeller/shapes/size\" msgid=\"label.size\">size</ox-i18n>\n </legend>\n\n <div class=\"property-grid\">\n <label class=\"width\"> <ox-i18n msgid=\"label.width\">width</ox-i18n> </label>\n <input type=\"number\" value-key=\"bounds.width\" .value=${String(width)} />\n <label class=\"height\"> <ox-i18n msgid=\"label.height\">height</ox-i18n> </label>\n <input type=\"number\" value-key=\"bounds.height\" .value=${String(height)} />\n\n ${this.selected.length && this.selected[0].isRootModel()\n ? html``\n : html`\n ${isThreedEnabled()\n ? html`\n <label class=\"depth\"> <ox-i18n msgid=\"label.depth\">depth</ox-i18n> </label>\n <input\n type=\"number\"\n value-key=\"depth\"\n .value=${String(value.depth ?? '')}\n placeholder=\"auto\"\n />\n\n <label class=\"zPos\"> <ox-i18n msgid=\"label.zPos\">zPos</ox-i18n> </label>\n <input\n type=\"number\"\n value-key=\"zPos\"\n .value=${String(value.zPos ?? '')}\n placeholder=\"auto\"\n />\n `\n : html``}\n\n <label class=\"rotate\"> <ox-i18n msgid=\"label.rotate\">rotate</ox-i18n> </label>\n <ox-input-angle value-key=\"rotation\" .value=${value.rotation}> </ox-input-angle>\n `}\n </div>\n </fieldset>\n `\n )\n : html``}\n ${this._hasTextProperty(this.selected)\n ? html`\n <fieldset>\n <legend>\n <ox-i18n topic=\"board-modeller/shapes/text-box\" msgid=\"label.text-box\">text box</ox-i18n>\n </legend>\n\n <div class=\"property-grid\">\n <label> <ox-i18n msgid=\"label.horizontal\">horizontal</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textAlign\" .value=${value.textAlign}>\n <div data-value=\"left\"></div>\n <div data-value=\"center\"></div>\n <div data-value=\"right\"></div>\n <div data-value=\"justify\"></div>\n </ox-buttons-radio>\n\n <label> <ox-i18n msgid=\"label.vertical\">vertical</ox-i18n> </label>\n <ox-buttons-radio value-key=\"textBaseline\" .value=${value.textBaseline}>\n <div data-value=\"top\"></div>\n <div data-value=\"middle\"></div>\n <div data-value=\"bottom\"></div>\n </ox-buttons-radio>\n\n <div class=\"checkbox-row\">\n <input id=\"checkbox-textwrap\" type=\"checkbox\" value-key=\"textWrap\" .checked=${value.textWrap} />\n <label for=\"checkbox-textwrap\"> <ox-i18n msgid=\"label.text-wrap\">Text Wrap</ox-i18n> </label>\n </div>\n\n <div class=\"checkbox-row\">\n <input\n id=\"checkbox-keep-text-angle\"\n type=\"checkbox\"\n value-key=\"keepTextAngle\"\n .checked=${value.keepTextAngle}\n />\n <label for=\"checkbox-keep-text-angle\">\n <ox-i18n msgid=\"label.keep-text-angle\">Keep Text Angle</ox-i18n>\n </label>\n </div>\n\n <label> <ox-i18n msgid=\"label.padding\">padding</ox-i18n> </label>\n <table class=\"box-padding\">\n <tr>\n <td class=\"slide1\"></td>\n <td class=\"slide2\"></td>\n <td class=\"slide3\"></td>\n </tr>\n <tr>\n <td class=\"slide4\"></td>\n <td class=\"slide5\">\n <input type=\"number\" value-key=\"paddingTop\" .value=${value.paddingTop || 0} />\n <input type=\"number\" value-key=\"paddingLeft\" .value=${value.paddingLeft || 0} />\n <input type=\"number\" value-key=\"paddingRight\" .value=${value.paddingRight || 0} />\n <input type=\"number\" value-key=\"paddingBottom\" .value=${value.paddingBottom || 0} />\n </td>\n <td class=\"slide6\"></td>\n </tr>\n <tr>\n <td class=\"slide7\"></td>\n <td class=\"slide8\"></td>\n <td class=\"slide9\"></td>\n </tr>\n </table>\n </div>\n </fieldset>\n `\n : html``}\n ${this.selected.length && this.selected[0].isRootModel()\n ? html`\n <fieldset class=\"icon-label\">\n <legend>\n <ox-i18n topic=\"board-modeller/shapes/viewer-option\" msgid=\"label.viewer-option\">Viewer Option</ox-i18n>\n </legend>\n\n <div class=\"property-grid\">\n <label><ox-i18n msgid=\"label.fit\">Fit</ox-i18n></label>\n <select value-key=\"fitMode\" .value=${value.fitMode || 'ratio'}>\n <option value=\"none\">none</option>\n <option value=\"center\">center</option>\n <option value=\"ratio\" selected>ratio</option>\n <option value=\"both\">both</option>\n <option value=\"width\">width</option>\n <option value=\"height\">height</option>\n </select>\n\n ${isThreedEnabled()\n ? html`\n <div class=\"checkbox-row\">\n <input id=\"cb-threed\" type=\"checkbox\" value-key=\"threed\" .checked=${!!value.threed} />\n <label for=\"cb-threed\"><ox-i18n msgid=\"label.start-in-3d\">Start in 3D</ox-i18n></label>\n </div>\n\n <div class=\"checkbox-row\">\n <input\n id=\"cb-floor-constraint\"\n type=\"checkbox\"\n value-key=\"cameraFloorConstraint\"\n .checked=${!!value.cameraFloorConstraint}\n />\n <label for=\"cb-floor-constraint\">\n <ox-i18n msgid=\"label.keep-above-ground\">Keep Above Ground</ox-i18n>\n </label>\n </div>\n `\n : html``}\n\n <div class=\"checkbox-row\">\n <input id=\"cb-id-lookup\" type=\"checkbox\" value-key=\"idLookup\" .checked=${value.idLookup !== false} />\n <label for=\"cb-id-lookup\"><ox-i18n msgid=\"label.id-lookup\">ID Lookup</ox-i18n></label>\n </div>\n </div>\n </fieldset>\n `\n : html``}\n `\n }\n\n _onValueChange(e: Event) {\n var element = e.target as HTMLElement\n var key = element.getAttribute('value-key')\n\n if (!key) {\n return\n }\n\n var value = this._getValueFromEventTarget(element)\n\n if (key.indexOf('bounds.') == 0) {\n if (isNaN(value)) return\n this.dispatchEvent(\n new CustomEvent('bounds-change', {\n bubbles: true,\n composed: true,\n detail: {\n [key.substring(7)]: value\n }\n })\n )\n } else {\n this._onAfterValueChange(key, value)\n }\n }\n\n _hasTextProperty(selected: Component[]) {\n for (let i = 0; i < selected.length; i++) {\n if (!selected[i].hasTextProperty) return false\n }\n\n return true\n }\n\n _hasProperties(selected: Component[]) {\n if (!selected || selected.length == 0 || (selected[0] && selected[0].isLayer && selected[0].isLayer())) return false\n\n return true\n }\n\n _isIdentifiable(selected: Component[]) {\n if (\n !selected ||\n selected.length == 0 ||\n selected.length > 1 ||\n !selected[0].isIdentifiable() ||\n (selected[0].isLayer && selected[0].isLayer())\n )\n return false\n\n return true\n }\n\n /**\n * 단일 선택 컴포넌트의 부모 machine id (unit 의 ID 검색 시 조회조건으로 전달).\n * 부모가 루트 모델/레이어가 아니고 id 를 가지면 그 id 를 반환 — unit 이 자신의\n * 소속 machine 을 특정할 수 있는 경우에 해당. 그 외엔 빈 문자열.\n */\n _parentMachineId(selected: Component[]): string {\n const target = selected?.length === 1 ? (selected[0] as any) : null\n if (!target) return ''\n // 명시적 parentObjectId(= 부모 머신 id) 우선, 없으면 실제 scene 부모의 id.\n const pid = target.state?.parentObjectId\n if (pid) return String(pid)\n const parent = target.parent\n if (!parent || parent.isRootModel?.() || (parent.isLayer && parent.isLayer())) return ''\n return parent.state?.id || ''\n }\n\n /**\n * 선택 컴포넌트의 id 조회용 타입명 (capability `idLookupType`). 값이 있으면 그 타입으로\n * 검색 에디터를 띄우고, 없으면(일반 도형·Carrier 등) plain input 으로 두어 불필요한 id\n * 리스트 요청을 보내지 않는다. 기본은 자기 타입이며 컴포넌트가 다른 타입으로 override 가능.\n * (머신/유닛 + Node 가 opt-in. isLVComponent 은 Carrier 포함·Node 제외라 부적합.)\n */\n _idLookupType(selected: Component[]): string | undefined {\n if (selected?.length !== 1) return undefined\n if (!this._idLookupEnabled(selected)) return undefined\n return (selected[0] as any).idLookupType\n }\n\n /** Board 루트 속성 state.idLookup 으로 id 룩업 전체 ON/OFF (기본 ON). */\n _idLookupEnabled(selected: Component[]): boolean {\n const root = (selected?.[0] as any)?.root\n return root?.state?.idLookup !== false\n }\n\n _isClassIdentifiable(selected: Component[]) {\n if (!selected || (selected[0] && selected[0].isLayer())) return false\n\n return true\n }\n\n _isLine(selected: Component[]) {\n if (!selected || !(selected[0] && selected[0].isLine())) return false\n\n return true\n }\n\n _is3dish(selected: Component[]) {\n if (!selected || !(selected[0] && selected[0].is3dish())) return false\n\n return true\n }\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parentObject 후보 수집 — 속성창(단일 선택)과 bulk-paste 다이얼로그가 공유하는 로직.
|
|
3
|
+
*
|
|
4
|
+
* parentObjectId 는 ParentObjectMixin(capability `parentObjectTypes`) 컴포넌트에서만 의미가
|
|
5
|
+
* 있고, 후보 리스트는 컴포넌트 타입별로 다르다 (parentObjectTypes 로 씬을 훑어 수집).
|
|
6
|
+
* 이 함수들을 (types, root) 로 매개변수화해 두 소비처가 한 구현을 재사용한다.
|
|
7
|
+
*/
|
|
8
|
+
/** 대상이 ParentObjectMixin(= parentObjectTypes capability) 을 가졌는지. */
|
|
9
|
+
export declare function hasParentObject(target: any): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* template(모델)의 타입으로부터 parentObject 지원 여부 + 후보 리스트 계산 (bulk-paste 용).
|
|
12
|
+
* template 은 라이브 컴포넌트가 아니라 클립보드 모델이므로, 타입 클래스의 임시 인스턴스로
|
|
13
|
+
* parentObjectTypes(클래스 상수 capability)를 읽은 뒤 씬(root)에서 후보를 수집한다.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parentObjectForTemplate(template: any, root: any): {
|
|
16
|
+
has: boolean;
|
|
17
|
+
items: string[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* parentObject 후보 id 리스트.
|
|
21
|
+
* @param parentObjectTypes 대상 컴포넌트가 부모로 삼을 수 있는 타입들 (빈 배열이면 isMcsMachine 폴백).
|
|
22
|
+
* @param root 씬 루트 (여기서부터 재귀 수집).
|
|
23
|
+
* @param opts.exclude 후보에서 제외할 컴포넌트 (자기 자신 등).
|
|
24
|
+
* @param opts.knownParentId 이미 아는 부모 id — 있으면 후보 맨 앞으로.
|
|
25
|
+
*/
|
|
26
|
+
export declare function collectParentObjectItems(parentObjectTypes: string[] | undefined, root: any, opts?: {
|
|
27
|
+
exclude?: any;
|
|
28
|
+
knownParentId?: string;
|
|
29
|
+
}): string[];
|