@operato/property-panel 10.0.0-beta.7 → 10.1.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/CHANGELOG.md +486 -0
- package/dist/src/graphql/data-subscription.js +5 -1
- package/dist/src/graphql/data-subscription.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/ox-property-panel.d.ts +17 -0
- package/dist/src/ox-property-panel.js +105 -39
- package/dist/src/ox-property-panel.js.map +1 -1
- package/dist/src/property-panel/abstract-property.js +11 -2
- package/dist/src/property-panel/abstract-property.js.map +1 -1
- package/dist/src/property-panel/data-binding/data-binding-mapper.js +11 -3
- package/dist/src/property-panel/data-binding/data-binding-mapper.js.map +1 -1
- package/dist/src/property-panel/data-binding/data-binding-popup.d.ts +63 -0
- package/dist/src/property-panel/data-binding/data-binding-popup.js +1414 -0
- package/dist/src/property-panel/data-binding/data-binding-popup.js.map +1 -0
- package/dist/src/property-panel/data-binding/data-binding-value-map.d.ts +1 -1
- package/dist/src/property-panel/data-binding/data-binding-value-range.d.ts +1 -1
- package/dist/src/property-panel/data-binding/data-binding.d.ts +1 -0
- package/dist/src/property-panel/data-binding/data-binding.js +37 -5
- package/dist/src/property-panel/data-binding/data-binding.js.map +1 -1
- package/dist/src/property-panel/effects/effects.js +1 -1
- package/dist/src/property-panel/effects/effects.js.map +1 -1
- package/dist/src/property-panel/effects/property-event-tap.js +21 -1
- package/dist/src/property-panel/effects/property-event-tap.js.map +1 -1
- package/dist/src/property-panel/effects/property-event.d.ts +15 -7
- package/dist/src/property-panel/effects/property-event.js +17 -38
- package/dist/src/property-panel/effects/property-event.js.map +1 -1
- package/dist/src/property-panel/effects/property-shadow.js +14 -5
- package/dist/src/property-panel/effects/property-shadow.js.map +1 -1
- package/dist/src/property-panel/event-handlers/event-handlers-help.d.ts +23 -0
- package/dist/src/property-panel/event-handlers/event-handlers-help.js +356 -0
- package/dist/src/property-panel/event-handlers/event-handlers-help.js.map +1 -0
- package/dist/src/property-panel/event-handlers/event-handlers-mapper.d.ts +31 -0
- package/dist/src/property-panel/event-handlers/event-handlers-mapper.js +238 -0
- package/dist/src/property-panel/event-handlers/event-handlers-mapper.js.map +1 -0
- package/dist/src/property-panel/event-handlers/event-handlers-popup.d.ts +42 -0
- package/dist/src/property-panel/event-handlers/event-handlers-popup.js +375 -0
- package/dist/src/property-panel/event-handlers/event-handlers-popup.js.map +1 -0
- package/dist/src/property-panel/event-handlers/event-handlers.d.ts +54 -0
- package/dist/src/property-panel/event-handlers/event-handlers.js +410 -0
- package/dist/src/property-panel/event-handlers/event-handlers.js.map +1 -0
- package/dist/src/property-panel/inspector/inspector-controller.d.ts +66 -0
- package/dist/src/property-panel/inspector/inspector-controller.js +288 -0
- package/dist/src/property-panel/inspector/inspector-controller.js.map +1 -0
- package/dist/src/property-panel/inspector/inspector-group-view.d.ts +15 -0
- package/dist/src/property-panel/inspector/inspector-group-view.js +59 -0
- package/dist/src/property-panel/inspector/inspector-group-view.js.map +1 -0
- package/dist/src/property-panel/inspector/inspector-highlight.d.ts +7 -0
- package/dist/src/property-panel/inspector/inspector-highlight.js +25 -0
- package/dist/src/property-panel/inspector/inspector-highlight.js.map +1 -0
- package/dist/src/property-panel/inspector/inspector-model.d.ts +44 -0
- package/dist/src/property-panel/inspector/inspector-model.js +72 -0
- package/dist/src/property-panel/inspector/inspector-model.js.map +1 -0
- package/dist/src/property-panel/inspector/inspector-tree-view.d.ts +18 -0
- package/dist/src/property-panel/inspector/inspector-tree-view.js +61 -0
- package/dist/src/property-panel/inspector/inspector-tree-view.js.map +1 -0
- package/dist/src/property-panel/inspector/inspector.d.ts +17 -12
- package/dist/src/property-panel/inspector/inspector.js +281 -179
- package/dist/src/property-panel/inspector/inspector.js.map +1 -1
- package/dist/src/property-panel/shapes/ox-placeholder-convert-editor.d.ts +20 -0
- package/dist/src/property-panel/shapes/ox-placeholder-convert-editor.js +125 -0
- package/dist/src/property-panel/shapes/ox-placeholder-convert-editor.js.map +1 -0
- package/dist/src/property-panel/shapes/placeholder-convert.d.ts +34 -0
- package/dist/src/property-panel/shapes/placeholder-convert.js +117 -0
- package/dist/src/property-panel/shapes/placeholder-convert.js.map +1 -0
- package/dist/src/property-panel/shapes/shapes.js +28 -10
- package/dist/src/property-panel/shapes/shapes.js.map +1 -1
- package/dist/src/property-panel/specifics/specifics.d.ts +1 -0
- package/dist/src/property-panel/specifics/specifics.js +2 -1
- package/dist/src/property-panel/specifics/specifics.js.map +1 -1
- package/dist/src/property-panel/threed/property-material3d.js +8 -1
- package/dist/src/property-panel/threed/property-material3d.js.map +1 -1
- package/dist/src/property-panel/threed/property-scene3d.d.ts +34 -6
- package/dist/src/property-panel/threed/property-scene3d.js +332 -201
- package/dist/src/property-panel/threed/property-scene3d.js.map +1 -1
- package/dist/src/property-panel/threed/threed.js +8 -0
- package/dist/src/property-panel/threed/threed.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/themes/grist-theme.css +1 -1
- package/translations/en.json +34 -1
- package/translations/ja.json +34 -1
- package/translations/ko.json +34 -1
- package/translations/ms.json +34 -1
- package/translations/zh.json +34 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { html, nothing } from 'lit';
|
|
2
|
+
import { matchesQuery } from './inspector-model.js';
|
|
3
|
+
import { highlight } from './inspector-highlight.js';
|
|
4
|
+
/** 컴포넌트 자신 또는 자손 중 검색 매치가 있으면 표시 대상. */
|
|
5
|
+
function shouldBeShown(component, terms) {
|
|
6
|
+
if (matchesQuery(component, terms))
|
|
7
|
+
return true;
|
|
8
|
+
const children = component.isContainer() ? component.components : [];
|
|
9
|
+
return children.some(child => shouldBeShown(child, terms));
|
|
10
|
+
}
|
|
11
|
+
/** 검색 매치 개수(루트 포함, 전체 트리) — ROOT 노드 count 표시용. */
|
|
12
|
+
export function countMatches(component, terms) {
|
|
13
|
+
let n = matchesQuery(component, terms) ? 1 : 0;
|
|
14
|
+
const children = component.isContainer() ? component.components : [];
|
|
15
|
+
for (const child of children)
|
|
16
|
+
n += countMatches(child, terms);
|
|
17
|
+
return n;
|
|
18
|
+
}
|
|
19
|
+
function renderNode(component, depth, ctx) {
|
|
20
|
+
if (!component || !shouldBeShown(component, ctx.terms)) {
|
|
21
|
+
return html ``;
|
|
22
|
+
}
|
|
23
|
+
const children = component.isContainer() ? component.components : [];
|
|
24
|
+
const extended = ctx.isExtended(component) ? children.filter(child => shouldBeShown(child, ctx.terms)) : [];
|
|
25
|
+
const { type, id, tag, class: clazz } = component.state;
|
|
26
|
+
const label = (id ? `#${id}` : '') + (tag ? `@${tag}` : '') + (clazz ? `.(${clazz})` : '');
|
|
27
|
+
return html `
|
|
28
|
+
<div
|
|
29
|
+
class="component"
|
|
30
|
+
?selected=${ctx.selected.indexOf(component) > -1}
|
|
31
|
+
.component=${component}
|
|
32
|
+
?sortable=${component.isContainer()}
|
|
33
|
+
>
|
|
34
|
+
<span>
|
|
35
|
+
${depth > 0
|
|
36
|
+
? html `
|
|
37
|
+
<md-icon class="eye">${component.get('hidden') ? 'visibility_off' : 'visibility'}</md-icon>
|
|
38
|
+
<md-icon class="lock" ?locked=${!!component.get('locked')}
|
|
39
|
+
>${component.get('locked') ? 'lock' : 'lock_open'}</md-icon
|
|
40
|
+
>
|
|
41
|
+
<pre>${' '.repeat(Math.max(0, depth - 1))}</pre>
|
|
42
|
+
`
|
|
43
|
+
: html ` <pre>${' '.repeat(depth + 1)}</pre> `}
|
|
44
|
+
|
|
45
|
+
<span class=${ctx.nodeHandleClass(component)}> </span>
|
|
46
|
+
|
|
47
|
+
<span class="type">${depth == 0 ? html `ROOT(count: ${ctx.count})` : highlight(type, ctx.terms)}</span>
|
|
48
|
+
${label ? html ` <span class="name">${highlight(label, ctx.terms)}</span> ` : nothing}
|
|
49
|
+
</span>
|
|
50
|
+
|
|
51
|
+
${extended.map(child => renderNode(child, depth + 1, ctx))}
|
|
52
|
+
</div>
|
|
53
|
+
`;
|
|
54
|
+
}
|
|
55
|
+
/** scene.root 부터 트리를 렌더한다. */
|
|
56
|
+
export function renderInspectorTree(root, ctx) {
|
|
57
|
+
if (!root)
|
|
58
|
+
return html ``;
|
|
59
|
+
return renderNode(root, 0, ctx);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=inspector-tree-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspector-tree-view.js","sourceRoot":"","sources":["../../../../src/property-panel/inspector/inspector-tree-view.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Scene Inspector 트리 뷰 렌더러.\n *\n * 계층(Container/Group) 구조를 재귀로 그린다. SceneInspector 의 shadow root 에 직접 렌더되며\n * (클릭 위임이 `.component` 프로퍼티/classList 에 의존하므로 별도 커스텀엘리먼트로 분리하지 않는다),\n * 순수 렌더 함수로 컨트롤러/상태를 주입받는다.\n */\nimport { Component, Container } from '@hatiolab/things-scene'\nimport { html, nothing, TemplateResult } from 'lit'\n\nimport { matchesQuery, SearchTerm } from './inspector-model.js'\nimport { highlight } from './inspector-highlight.js'\n\n/** 트리 렌더에 필요한 컨텍스트(호스트/컨트롤러가 주입). */\nexport interface TreeViewContext {\n /** 현재 선택 컴포넌트 목록. */\n selected: Component[]\n /** 파싱된 검색어(AND). */\n terms: SearchTerm[]\n /** ROOT 노드에 표시할 매치 개수. */\n count: number\n isExtended: (c: Component) => boolean\n nodeHandleClass: (c: Component) => string\n}\n\n/** 컴포넌트 자신 또는 자손 중 검색 매치가 있으면 표시 대상. */\nfunction shouldBeShown(component: Component, terms: SearchTerm[]): boolean {\n if (matchesQuery(component, terms)) return true\n const children = component.isContainer() ? (component as Container).components : []\n return children.some(child => shouldBeShown(child, terms))\n}\n\n/** 검색 매치 개수(루트 포함, 전체 트리) — ROOT 노드 count 표시용. */\nexport function countMatches(component: Component, terms: SearchTerm[]): number {\n let n = matchesQuery(component, terms) ? 1 : 0\n const children = component.isContainer() ? (component as Container).components : []\n for (const child of children) n += countMatches(child, terms)\n return n\n}\n\nfunction renderNode(component: Component, depth: number, ctx: TreeViewContext): TemplateResult {\n if (!component || !shouldBeShown(component, ctx.terms)) {\n return html``\n }\n\n const children = component.isContainer() ? (component as Container).components : []\n const extended = ctx.isExtended(component) ? children.filter(child => shouldBeShown(child, ctx.terms)) : []\n const { type, id, tag, class: clazz } = component.state\n const label = (id ? `#${id}` : '') + (tag ? `@${tag}` : '') + (clazz ? `.(${clazz})` : '')\n\n return html`\n <div\n class=\"component\"\n ?selected=${ctx.selected.indexOf(component) > -1}\n .component=${component}\n ?sortable=${component.isContainer()}\n >\n <span>\n ${depth > 0\n ? html`\n <md-icon class=\"eye\">${component.get('hidden') ? 'visibility_off' : 'visibility'}</md-icon>\n <md-icon class=\"lock\" ?locked=${!!component.get('locked')}\n >${component.get('locked') ? 'lock' : 'lock_open'}</md-icon\n >\n <pre>${' '.repeat(Math.max(0, depth - 1))}</pre>\n `\n : html` <pre>${' '.repeat(depth + 1)}</pre> `}\n\n <span class=${ctx.nodeHandleClass(component)}> </span>\n\n <span class=\"type\">${depth == 0 ? html`ROOT(count: ${ctx.count})` : highlight(type, ctx.terms)}</span>\n ${label ? html` <span class=\"name\">${highlight(label, ctx.terms)}</span> ` : nothing}\n </span>\n\n ${extended.map(child => renderNode(child, depth + 1, ctx))}\n </div>\n `\n}\n\n/** scene.root 부터 트리를 렌더한다. */\nexport function renderInspectorTree(root: Component | undefined, ctx: TreeViewContext): TemplateResult {\n if (!root) return html``\n return renderNode(root, 0, ctx)\n}\n"]}
|
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
import '@operato/input/ox-input-search.js';
|
|
2
2
|
import { LitElement, PropertyValues, TemplateResult } from 'lit';
|
|
3
|
-
import {
|
|
3
|
+
import { Scene } from '@hatiolab/things-scene';
|
|
4
4
|
export declare class SceneInspector extends LitElement {
|
|
5
5
|
static styles: import("lit").CSSResult[];
|
|
6
6
|
scene?: Scene;
|
|
7
7
|
private searchText;
|
|
8
|
-
private
|
|
8
|
+
private viewMode;
|
|
9
|
+
private controller;
|
|
9
10
|
private show;
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
/** reveal(스크롤) 판정용 직전 선택. */
|
|
12
|
+
private _lastSelected;
|
|
12
13
|
disconnectedCallback(): void;
|
|
13
14
|
render(): TemplateResult<1>;
|
|
15
|
+
private _renderResult;
|
|
16
|
+
private _setViewMode;
|
|
17
|
+
private _collapseGroups;
|
|
18
|
+
private _expandGroups;
|
|
14
19
|
firstUpdated(): void;
|
|
20
|
+
/** 외부에서 강제 재렌더용(기존 공개 메쏘드 유지). */
|
|
15
21
|
refresh(): void;
|
|
16
22
|
updated(change: PropertyValues<this>): void;
|
|
23
|
+
/**
|
|
24
|
+
* 선택이 바뀌면(캔버스 등) 해당 항목을 리스트에 노출한다 — 그룹 뷰면 그룹을 펼친 뒤 스크롤.
|
|
25
|
+
* scrollIntoView({block:'nearest'}) 라 이미 보이는 경우(인스펙터 클릭 등)엔 사실상 no-op.
|
|
26
|
+
*/
|
|
27
|
+
private _maybeReveal;
|
|
28
|
+
/** 이벤트 타겟에서 상위로 올라가며 `.component` 를 가진 요소를 찾는다. */
|
|
29
|
+
private _resolveComponent;
|
|
17
30
|
_onclick(e: MouseEvent): void;
|
|
18
31
|
_ondblclick(e: MouseEvent): void;
|
|
19
|
-
get extendedMap(): any;
|
|
20
|
-
getNodeHandleClass(component: Component): "extended" | "collapsed" | "collapsespace";
|
|
21
|
-
isExtended(component: Component): boolean;
|
|
22
|
-
toggleExtended(component: Component): void;
|
|
23
|
-
toggleHidden(component: Component): void;
|
|
24
|
-
selectComponent(component: Component, append?: boolean): void;
|
|
25
|
-
shouldBeShown(component: Component, counting?: boolean): boolean;
|
|
26
|
-
renderComponent(component: Component, depth: number): TemplateResult;
|
|
27
32
|
}
|
|
@@ -1,33 +1,65 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* SceneInspector — 속성패널 inspector 탭 호스트.
|
|
6
|
+
*
|
|
7
|
+
* 얇은 호스트: 검색 상태 + 클릭 위임만 담당하고, scene 상호작용은 InspectorController,
|
|
8
|
+
* 렌더는 뷰 렌더러(현재 트리)로 위임한다. (아키텍처 리팩터 P0 — 동작은 기존과 동일)
|
|
9
|
+
*/
|
|
2
10
|
import '@operato/input/ox-input-search.js';
|
|
3
|
-
import { css, html, LitElement } from 'lit';
|
|
11
|
+
import { css, html, LitElement, nothing } from 'lit';
|
|
4
12
|
import { property, state } from 'lit/decorators.js';
|
|
5
|
-
// TODO test Sortable
|
|
6
|
-
// import Sortable from 'sortablejs'
|
|
7
13
|
import { i18next } from '@operato/i18n';
|
|
8
14
|
import { InspectorStyles } from '@operato/styles/inspector-styles.js';
|
|
15
|
+
import { parseQuery } from './inspector-model.js';
|
|
16
|
+
import { InspectorController } from './inspector-controller.js';
|
|
17
|
+
import { countMatches, renderInspectorTree } from './inspector-tree-view.js';
|
|
18
|
+
import { renderInspectorGroupView } from './inspector-group-view.js';
|
|
19
|
+
/** 뷰 모드 선호를 세션 간 유지(localStorage). 전역 사용자 선호. */
|
|
20
|
+
const VIEW_MODE_STORAGE_KEY = 'scene-inspector.view-mode';
|
|
21
|
+
function readStoredViewMode() {
|
|
22
|
+
try {
|
|
23
|
+
const v = localStorage.getItem(VIEW_MODE_STORAGE_KEY);
|
|
24
|
+
return v === 'group' || v === 'tree' ? v : 'tree';
|
|
25
|
+
}
|
|
26
|
+
catch (_a) {
|
|
27
|
+
return 'tree';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function writeStoredViewMode(mode) {
|
|
31
|
+
try {
|
|
32
|
+
localStorage.setItem(VIEW_MODE_STORAGE_KEY, mode);
|
|
33
|
+
}
|
|
34
|
+
catch (_a) {
|
|
35
|
+
/* localStorage 미가용(SSR/프라이빗 등) — 무시 */
|
|
36
|
+
}
|
|
37
|
+
}
|
|
9
38
|
export class SceneInspector extends LitElement {
|
|
10
39
|
constructor() {
|
|
11
40
|
super(...arguments);
|
|
12
41
|
this.searchText = '';
|
|
42
|
+
this.viewMode = readStoredViewMode();
|
|
43
|
+
this.controller = new InspectorController();
|
|
13
44
|
this.show = false;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
45
|
+
/** reveal(스크롤) 판정용 직전 선택. */
|
|
46
|
+
this._lastSelected = [];
|
|
47
|
+
this._collapseGroups = () => {
|
|
48
|
+
this.controller.collapseAllGroups();
|
|
49
|
+
this.requestUpdate();
|
|
50
|
+
};
|
|
51
|
+
this._expandGroups = () => {
|
|
52
|
+
const index = this.controller.index;
|
|
53
|
+
if (index)
|
|
54
|
+
this.controller.expandAllGroups([...index.byType.keys()]);
|
|
55
|
+
this.requestUpdate();
|
|
56
|
+
};
|
|
23
57
|
}
|
|
24
58
|
disconnectedCallback() {
|
|
25
59
|
super.disconnectedCallback();
|
|
26
|
-
this.
|
|
27
|
-
delete this._extendedMap;
|
|
60
|
+
this.controller.unbind();
|
|
28
61
|
}
|
|
29
62
|
render() {
|
|
30
|
-
this.count = 0;
|
|
31
63
|
return html `
|
|
32
64
|
<ox-input-search
|
|
33
65
|
.placeholder=${i18next.t('text.search with type, id or tag')}
|
|
@@ -35,73 +67,93 @@ export class SceneInspector extends LitElement {
|
|
|
35
67
|
@change=${(e) => (this.searchText = (e.target.value || '').toLowerCase())}
|
|
36
68
|
></ox-input-search>
|
|
37
69
|
|
|
38
|
-
<div
|
|
70
|
+
<div toolbar>
|
|
71
|
+
<md-icon class="view-btn" ?selected=${this.viewMode === 'tree'} title="Tree view" @click=${() => this._setViewMode('tree')}>account_tree</md-icon>
|
|
72
|
+
<md-icon class="view-btn" ?selected=${this.viewMode === 'group'} title="Group by type" @click=${() => this._setViewMode('group')}>category</md-icon>
|
|
73
|
+
<span class="spacer"></span>
|
|
74
|
+
${this.viewMode === 'group'
|
|
75
|
+
? html `
|
|
76
|
+
<md-icon title="Expand all groups" @click=${this._expandGroups}>unfold_more</md-icon>
|
|
77
|
+
<md-icon title="Collapse to group level" @click=${this._collapseGroups}>unfold_less</md-icon>
|
|
78
|
+
`
|
|
79
|
+
: nothing}
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div result>${this._renderResult()}</div>
|
|
39
83
|
`;
|
|
40
84
|
}
|
|
85
|
+
_renderResult() {
|
|
86
|
+
if (!this.scene)
|
|
87
|
+
return html ``;
|
|
88
|
+
const terms = parseQuery(this.searchText);
|
|
89
|
+
if (this.viewMode === 'group') {
|
|
90
|
+
return renderInspectorGroupView(this.controller.index, {
|
|
91
|
+
selected: this.controller.selected,
|
|
92
|
+
terms,
|
|
93
|
+
isGroupExpanded: (type) => this.controller.isGroupExpanded(type),
|
|
94
|
+
isTypeDimmed: (type) => this.controller.isTypeDimmed(type),
|
|
95
|
+
isTypeHidden: (type) => this.controller.isTypeHidden(type)
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return renderInspectorTree(this.scene.root, {
|
|
99
|
+
selected: this.controller.selected,
|
|
100
|
+
terms,
|
|
101
|
+
count: countMatches(this.scene.root, terms),
|
|
102
|
+
isExtended: (c) => this.controller.isExtended(c),
|
|
103
|
+
nodeHandleClass: (c) => this.controller.nodeHandleClass(c)
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
_setViewMode(mode) {
|
|
107
|
+
if (this.viewMode === mode)
|
|
108
|
+
return;
|
|
109
|
+
this.viewMode = mode;
|
|
110
|
+
writeStoredViewMode(mode); // 세션 간 유지
|
|
111
|
+
}
|
|
41
112
|
firstUpdated() {
|
|
42
113
|
dispatchEvent(new Event('resize'));
|
|
43
114
|
this.renderRoot.addEventListener('click', this._onclick.bind(this));
|
|
44
115
|
this.renderRoot.addEventListener('dblclick', this._ondblclick.bind(this));
|
|
45
116
|
}
|
|
117
|
+
/** 외부에서 강제 재렌더용(기존 공개 메쏘드 유지). */
|
|
46
118
|
refresh() {
|
|
47
|
-
var _a;
|
|
48
|
-
let selected = ((_a = this.scene) === null || _a === void 0 ? void 0 : _a.selected) || [];
|
|
49
|
-
selected.forEach((component) => {
|
|
50
|
-
let parent = component.parent;
|
|
51
|
-
while (parent && !this.extendedMap.get(parent)) {
|
|
52
|
-
this.extendedMap.set(parent, true);
|
|
53
|
-
parent = parent.parent;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
119
|
this.requestUpdate();
|
|
57
120
|
}
|
|
58
121
|
updated(change) {
|
|
59
122
|
if (change.has('scene')) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
123
|
+
this.controller.bind(this.scene, () => this.requestUpdate());
|
|
124
|
+
}
|
|
125
|
+
this._maybeReveal();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 선택이 바뀌면(캔버스 등) 해당 항목을 리스트에 노출한다 — 그룹 뷰면 그룹을 펼친 뒤 스크롤.
|
|
129
|
+
* scrollIntoView({block:'nearest'}) 라 이미 보이는 경우(인스펙터 클릭 등)엔 사실상 no-op.
|
|
130
|
+
*/
|
|
131
|
+
_maybeReveal() {
|
|
132
|
+
const selected = this.controller.selected;
|
|
133
|
+
const changed = selected.length !== this._lastSelected.length || selected.some((c, i) => c !== this._lastSelected[i]);
|
|
134
|
+
if (!changed)
|
|
135
|
+
return;
|
|
136
|
+
if (selected.length === 0) {
|
|
137
|
+
this._lastSelected = selected;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (this.viewMode === 'group') {
|
|
141
|
+
const types = [...new Set(selected.map(c => c.state.type))];
|
|
142
|
+
if (types.some(t => !this.controller.isGroupExpanded(t))) {
|
|
143
|
+
this.controller.expandAllGroups(types);
|
|
144
|
+
return; // _lastSelected 미갱신 → 다음 updated 에서 changed 유지 → 그때 스크롤
|
|
71
145
|
}
|
|
72
146
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// })
|
|
147
|
+
this._lastSelected = selected;
|
|
148
|
+
this.updateComplete.then(() => {
|
|
149
|
+
const el = this.renderRoot.querySelector('.component[selected]');
|
|
150
|
+
el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest' });
|
|
151
|
+
});
|
|
79
152
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// draggable: '.component',
|
|
85
|
-
// swapThreshold: 1,
|
|
86
|
-
// onSort: this.onSort.bind(this)
|
|
87
|
-
// }
|
|
88
|
-
// TODO test Sortable
|
|
89
|
-
// onSort(e: Sortable.SortableEvent) {
|
|
90
|
-
// if (!this.scene) return
|
|
91
|
-
// var component = (e.item as HTMLElement & { component: Component }).component
|
|
92
|
-
// var to_container = (e.to as HTMLElement & { component: Component }).component as Container
|
|
93
|
-
// var to_index = e.newIndex! - 1
|
|
94
|
-
// this.scene.move(component, to_container, to_index)
|
|
95
|
-
// this.show = false
|
|
96
|
-
// this.updateComplete.then(() => {
|
|
97
|
-
// this.show = true
|
|
98
|
-
// })
|
|
99
|
-
// }
|
|
100
|
-
_onclick(e) {
|
|
101
|
-
e.stopPropagation();
|
|
102
|
-
var targetElement = e.target;
|
|
103
|
-
var classList = targetElement.classList;
|
|
104
|
-
var component;
|
|
153
|
+
/** 이벤트 타겟에서 상위로 올라가며 `.component` 를 가진 요소를 찾는다. */
|
|
154
|
+
_resolveComponent(e) {
|
|
155
|
+
let targetElement = e.target;
|
|
156
|
+
let component;
|
|
105
157
|
while (!component && targetElement) {
|
|
106
158
|
component = targetElement.component;
|
|
107
159
|
if (component)
|
|
@@ -110,14 +162,56 @@ export class SceneInspector extends LitElement {
|
|
|
110
162
|
if (!targetElement || targetElement === this.renderRoot)
|
|
111
163
|
break;
|
|
112
164
|
}
|
|
165
|
+
return component;
|
|
166
|
+
}
|
|
167
|
+
_onclick(e) {
|
|
168
|
+
var _a, _b, _c, _d, _e;
|
|
169
|
+
e.stopPropagation();
|
|
170
|
+
const target = e.target;
|
|
171
|
+
// 그룹 hidden 아이콘 클릭 → 그룹(타입) 전원 hidden 토글 (헤더 펼침보다 먼저 처리)
|
|
172
|
+
if (target.classList.contains('group-hidden')) {
|
|
173
|
+
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');
|
|
174
|
+
if (type != null)
|
|
175
|
+
this.controller.toggleTypeHidden(type);
|
|
176
|
+
this.requestUpdate();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// 그룹 dim-out 아이콘 클릭 → 그룹(타입) 포커스 dim 토글 (헤더 펼침보다 먼저 처리)
|
|
180
|
+
if (target.classList.contains('group-dim')) {
|
|
181
|
+
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');
|
|
182
|
+
if (type != null)
|
|
183
|
+
this.controller.toggleTypeDim(type);
|
|
184
|
+
this.requestUpdate();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// 타입 그룹 헤더 클릭 → 그룹 펼침/접힘 (멤버 행은 헤더의 자손이 아니므로 여기 안 걸림)
|
|
188
|
+
const header = (_e = target.closest) === null || _e === void 0 ? void 0 : _e.call(target, '[data-group-type]');
|
|
189
|
+
if (header) {
|
|
190
|
+
const type = header.getAttribute('data-group-type');
|
|
191
|
+
if (type != null)
|
|
192
|
+
this.controller.toggleGroup(type);
|
|
193
|
+
this.requestUpdate();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const classList = e.target.classList;
|
|
197
|
+
const component = this._resolveComponent(e);
|
|
113
198
|
if (component) {
|
|
114
199
|
if (classList.contains('eye')) {
|
|
115
|
-
this.toggleHidden(component);
|
|
200
|
+
this.controller.toggleHidden(component);
|
|
201
|
+
}
|
|
202
|
+
else if (classList.contains('lock')) {
|
|
203
|
+
this.controller.toggleLocked(component);
|
|
116
204
|
}
|
|
117
205
|
else if (classList.contains('extended') || classList.contains('collapsed')) {
|
|
118
|
-
this.toggleExtended(component);
|
|
206
|
+
this.controller.toggleExtended(component);
|
|
207
|
+
}
|
|
208
|
+
// shift = 범위(볼륨) 선택/블록 해제, ctrl/cmd = 개별 토글, 그 외 = 단일 선택
|
|
209
|
+
if (e.shiftKey) {
|
|
210
|
+
this.controller.selectRange(component, parseQuery(this.searchText));
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
this.controller.select(component, e.metaKey || e.ctrlKey);
|
|
119
214
|
}
|
|
120
|
-
this.selectComponent(component, e.shiftKey);
|
|
121
215
|
}
|
|
122
216
|
else {
|
|
123
217
|
if (classList.contains('inspector')) {
|
|
@@ -129,117 +223,16 @@ export class SceneInspector extends LitElement {
|
|
|
129
223
|
}
|
|
130
224
|
_ondblclick(e) {
|
|
131
225
|
e.stopPropagation();
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (component)
|
|
137
|
-
break;
|
|
138
|
-
targetElement = targetElement.parentNode;
|
|
139
|
-
if (!targetElement || targetElement === this.renderRoot)
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
if (component && component.isContainer()) {
|
|
143
|
-
this.toggleExtended(component);
|
|
144
|
-
}
|
|
145
|
-
this.requestUpdate();
|
|
146
|
-
}
|
|
147
|
-
get extendedMap() {
|
|
148
|
-
if (!this._extendedMap) {
|
|
149
|
-
this._extendedMap = new WeakMap();
|
|
150
|
-
}
|
|
151
|
-
return this._extendedMap;
|
|
152
|
-
}
|
|
153
|
-
getNodeHandleClass(component) {
|
|
154
|
-
if (component.isContainer() && component.components.length > 0) {
|
|
155
|
-
return !!this.extendedMap.get(component) ? 'extended' : 'collapsed';
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
return 'collapsespace';
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
isExtended(component) {
|
|
162
|
-
return !!this.extendedMap.get(component);
|
|
163
|
-
}
|
|
164
|
-
toggleExtended(component) {
|
|
165
|
-
var extended = this.isExtended(component);
|
|
166
|
-
if (extended) {
|
|
167
|
-
this.extendedMap.delete(component);
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
this.extendedMap.set(component, !extended);
|
|
171
|
-
}
|
|
172
|
-
this.requestUpdate();
|
|
173
|
-
}
|
|
174
|
-
toggleHidden(component) {
|
|
175
|
-
component.set('hidden', !component.hidden);
|
|
176
|
-
this.requestUpdate();
|
|
177
|
-
}
|
|
178
|
-
selectComponent(component, append = false) {
|
|
179
|
-
const selected = this.scene.selected;
|
|
180
|
-
if (append) {
|
|
181
|
-
const idx = selected.findIndex((s) => s === component);
|
|
182
|
-
if (idx != -1) {
|
|
183
|
-
selected.splice(idx, 1);
|
|
184
|
-
this.scene.selected = [...selected];
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
this.scene.selected = [...selected, component];
|
|
226
|
+
const component = this._resolveComponent(e);
|
|
227
|
+
if (component) {
|
|
228
|
+
if (component.isContainer()) {
|
|
229
|
+
this.controller.toggleExtended(component);
|
|
188
230
|
}
|
|
231
|
+
// 캔버스를 해당 컴포넌트로 센터 이동(줌).
|
|
232
|
+
this.controller.centerTo(component);
|
|
189
233
|
}
|
|
190
|
-
else {
|
|
191
|
-
this.scene.selected = [component];
|
|
192
|
-
}
|
|
193
|
-
component.trigger('reactionreset');
|
|
194
|
-
component.trigger('reaction');
|
|
195
234
|
this.requestUpdate();
|
|
196
235
|
}
|
|
197
|
-
shouldBeShown(component, counting = false) {
|
|
198
|
-
const { type, name, id, tag } = component.state;
|
|
199
|
-
const found = !this.searchText || `${type} ${name || ''} ${id || ''} ${tag || ''}`.toLowerCase().search(this.searchText) > -1;
|
|
200
|
-
if (counting && found) {
|
|
201
|
-
this.count++;
|
|
202
|
-
}
|
|
203
|
-
const foundChildren = (component.isContainer() ? component.components : []).filter((child) => this.shouldBeShown(child, counting)).length;
|
|
204
|
-
return !!(found || foundChildren > 0);
|
|
205
|
-
}
|
|
206
|
-
renderComponent(component, depth) {
|
|
207
|
-
var _a;
|
|
208
|
-
if (!component) {
|
|
209
|
-
return html ``;
|
|
210
|
-
}
|
|
211
|
-
if (!this.shouldBeShown(component, depth == 0)) {
|
|
212
|
-
return html ``;
|
|
213
|
-
}
|
|
214
|
-
const children = component.isContainer() ? component.components : [];
|
|
215
|
-
const extended = this.isExtended(component) ? children.filter((child) => this.shouldBeShown(child)) : [];
|
|
216
|
-
const { type, id, tag, class: clazz } = component.state;
|
|
217
|
-
const name = (id ? `#${id}` : '') + (tag ? `@${tag}` : '') + (clazz ? `.(${clazz})` : '');
|
|
218
|
-
return html `
|
|
219
|
-
<div
|
|
220
|
-
class="component"
|
|
221
|
-
?selected=${(((_a = this.scene) === null || _a === void 0 ? void 0 : _a.selected) || []).indexOf(component) > -1}
|
|
222
|
-
.component=${component}
|
|
223
|
-
?sortable=${component.isContainer()}
|
|
224
|
-
>
|
|
225
|
-
<span>
|
|
226
|
-
${depth > 0
|
|
227
|
-
? html `
|
|
228
|
-
<md-icon class="eye">${component.get('hidden') ? 'visibility_off' : 'visibility'}</md-icon>
|
|
229
|
-
<pre>${' '.repeat(depth)}</pre>
|
|
230
|
-
`
|
|
231
|
-
: html ` <pre>${' '.repeat(depth + 2)}</pre> `}
|
|
232
|
-
|
|
233
|
-
<span class=${this.getNodeHandleClass(component)}> </span>
|
|
234
|
-
|
|
235
|
-
<span class="type">${depth == 0 ? html `ROOT(count: ${this.count})` : type}</span>
|
|
236
|
-
${name ? html ` <span class="name">${name}</span> ` : html ``}
|
|
237
|
-
</span>
|
|
238
|
-
|
|
239
|
-
${extended.map((child) => this.renderComponent(child, depth + 1))}
|
|
240
|
-
</div>
|
|
241
|
-
`;
|
|
242
|
-
}
|
|
243
236
|
}
|
|
244
237
|
SceneInspector.styles = [
|
|
245
238
|
InspectorStyles,
|
|
@@ -306,15 +299,121 @@ SceneInspector.styles = [
|
|
|
306
299
|
}
|
|
307
300
|
|
|
308
301
|
.eye {
|
|
309
|
-
margin: 0 0 0
|
|
302
|
+
margin: 0 0 0 4px;
|
|
310
303
|
vertical-align: middle;
|
|
311
304
|
opacity: 0.7;
|
|
312
|
-
font-size:
|
|
305
|
+
font-size: 1em;
|
|
306
|
+
width: 1em;
|
|
313
307
|
color: var(--scene-inspector-eye-icon-color);
|
|
308
|
+
cursor: pointer;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.lock {
|
|
312
|
+
margin: 0;
|
|
313
|
+
vertical-align: middle;
|
|
314
|
+
opacity: 0.3;
|
|
315
|
+
font-size: 1em;
|
|
316
|
+
width: 1em;
|
|
317
|
+
cursor: pointer;
|
|
318
|
+
}
|
|
319
|
+
.lock[locked] {
|
|
320
|
+
opacity: 0.9;
|
|
321
|
+
color: var(--md-sys-color-error, #d9534f);
|
|
314
322
|
}
|
|
315
323
|
|
|
316
324
|
pre {
|
|
317
325
|
display: inline;
|
|
326
|
+
/* 트리 인덴트(수직라인까지의 간격) 최소화 — depth 당 좁은 폭 */
|
|
327
|
+
font-size: 0.6em;
|
|
328
|
+
margin: 0;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* 뷰 모드 툴바 */
|
|
332
|
+
div[toolbar] {
|
|
333
|
+
display: flex;
|
|
334
|
+
align-items: center;
|
|
335
|
+
gap: 4px;
|
|
336
|
+
padding: 2px 8px 4px;
|
|
337
|
+
}
|
|
338
|
+
div[toolbar] .spacer {
|
|
339
|
+
flex: 1;
|
|
340
|
+
}
|
|
341
|
+
div[toolbar] md-icon {
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
opacity: 0.5;
|
|
344
|
+
font-size: 18px;
|
|
345
|
+
border-radius: 4px;
|
|
346
|
+
padding: 2px;
|
|
347
|
+
}
|
|
348
|
+
div[toolbar] md-icon:hover {
|
|
349
|
+
opacity: 0.9;
|
|
350
|
+
}
|
|
351
|
+
div[toolbar] md-icon[selected] {
|
|
352
|
+
opacity: 1;
|
|
353
|
+
color: var(--md-sys-color-primary, #4a9eff);
|
|
354
|
+
background: rgba(0, 0, 0, 0.05);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* 타입 그룹 뷰 */
|
|
358
|
+
.group-header {
|
|
359
|
+
display: flex;
|
|
360
|
+
align-items: center;
|
|
361
|
+
gap: 4px;
|
|
362
|
+
font-size: 14px;
|
|
363
|
+
font-weight: 600;
|
|
364
|
+
cursor: pointer;
|
|
365
|
+
padding: 2px 0;
|
|
366
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
|
367
|
+
}
|
|
368
|
+
.group-header:hover {
|
|
369
|
+
background: rgba(0, 0, 0, 0.03);
|
|
370
|
+
}
|
|
371
|
+
.group-count {
|
|
372
|
+
margin-left: auto;
|
|
373
|
+
font-size: 0.72em;
|
|
374
|
+
font-weight: normal;
|
|
375
|
+
background: var(--scene-inspector-name-background-color);
|
|
376
|
+
color: #fff;
|
|
377
|
+
border-radius: 999px;
|
|
378
|
+
padding: 0 6px;
|
|
379
|
+
}
|
|
380
|
+
.group-hidden,
|
|
381
|
+
.group-dim {
|
|
382
|
+
font-size: 1em;
|
|
383
|
+
opacity: 0.35;
|
|
384
|
+
cursor: pointer;
|
|
385
|
+
}
|
|
386
|
+
.group-hidden {
|
|
387
|
+
margin: 0 2px 0 6px;
|
|
388
|
+
}
|
|
389
|
+
.group-dim {
|
|
390
|
+
margin: 0 4px 0 2px;
|
|
391
|
+
}
|
|
392
|
+
.group-hidden:hover,
|
|
393
|
+
.group-dim:hover {
|
|
394
|
+
opacity: 0.8;
|
|
395
|
+
}
|
|
396
|
+
.group-header[hidden-group] .group-hidden,
|
|
397
|
+
.group-header[dimmed] .group-dim {
|
|
398
|
+
opacity: 0.95;
|
|
399
|
+
color: var(--md-sys-color-primary, #4a9eff);
|
|
400
|
+
}
|
|
401
|
+
.group-header[dimmed] .group-type {
|
|
402
|
+
opacity: 0.45;
|
|
403
|
+
}
|
|
404
|
+
.group-member {
|
|
405
|
+
padding-left: 8px;
|
|
406
|
+
}
|
|
407
|
+
.muted {
|
|
408
|
+
opacity: 0.4;
|
|
409
|
+
font-style: italic;
|
|
410
|
+
}
|
|
411
|
+
/* 검색 매치 하이라이트 */
|
|
412
|
+
mark {
|
|
413
|
+
background: var(--md-sys-color-tertiary-container, #ffe082);
|
|
414
|
+
color: inherit;
|
|
415
|
+
border-radius: 2px;
|
|
416
|
+
padding: 0 1px;
|
|
318
417
|
}
|
|
319
418
|
`
|
|
320
419
|
];
|
|
@@ -324,4 +423,7 @@ __decorate([
|
|
|
324
423
|
__decorate([
|
|
325
424
|
state()
|
|
326
425
|
], SceneInspector.prototype, "searchText", void 0);
|
|
426
|
+
__decorate([
|
|
427
|
+
state()
|
|
428
|
+
], SceneInspector.prototype, "viewMode", void 0);
|
|
327
429
|
//# sourceMappingURL=inspector.js.map
|