@fps-games/editor 0.1.1-beta.0 → 0.1.1-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/local-editor-harness.d.ts +113 -6
- package/dist/local-editor-harness.d.ts.map +1 -1
- package/dist/local-editor-harness.js +1253 -55
- package/dist/local-editor-harness.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts +33 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js +231 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts +3 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.js +8 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/index.d.ts +5 -0
- package/node_modules/@fps-games/editor-babylon/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/index.js +5 -0
- package/node_modules/@fps-games/editor-babylon/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.d.ts +40 -0
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.js +237 -0
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.d.ts +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.js +15 -50
- package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +27 -0
- package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection.js +368 -14
- package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.d.ts +25 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.js +176 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts +18 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js +142 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.d.ts +2 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.js +6 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-measurement-controller.d.ts +20 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-measurement-controller.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-measurement-controller.js +187 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-measurement-controller.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-spatial-overlay-controller.d.ts +20 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-spatial-overlay-controller.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-spatial-overlay-controller.js +188 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-spatial-overlay-controller.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts +22 -2
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js +469 -90
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/types.d.ts +20 -0
- package/node_modules/@fps-games/editor-babylon/dist/types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/package.json +4 -4
- package/node_modules/@fps-games/editor-browser/dist/index.d.ts +2 -0
- package/node_modules/@fps-games/editor-browser/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/index.js +1 -0
- package/node_modules/@fps-games/editor-browser/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.d.ts +3 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.js +103 -48
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.d.ts +17 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js +327 -33
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts +3 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js +143 -17
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js +0 -2
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js +27 -20
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts +10 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js +253 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts +8 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +403 -110
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts +13 -3
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js +107 -14
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.d.ts +20 -3
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js +127 -16
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.js +13 -4
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.d.ts +4 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.js +114 -9
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-tooltip.d.ts +11 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-tooltip.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-tooltip.js +148 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-tooltip.js.map +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +141 -3
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts +35 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js +376 -2
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +11 -6
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +1617 -110
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/package.json +4 -1
- package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts +4 -1
- package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/editor-session.js +13 -3
- package/node_modules/@fps-games/editor-core/dist/editor-session.js.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/index.d.ts +3 -0
- package/node_modules/@fps-games/editor-core/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/index.js +3 -0
- package/node_modules/@fps-games/editor-core/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/inspector.d.ts +6 -1
- package/node_modules/@fps-games/editor-core/dist/inspector.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/inspector.js +6 -1
- package/node_modules/@fps-games/editor-core/dist/inspector.js.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts +7 -0
- package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/scene-graph.js.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/scene-view-input.d.ts +1 -1
- package/node_modules/@fps-games/editor-core/dist/scene-view-input.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/selection-strategy.d.ts +12 -0
- package/node_modules/@fps-games/editor-core/dist/selection-strategy.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-core/dist/selection-strategy.js +52 -0
- package/node_modules/@fps-games/editor-core/dist/selection-strategy.js.map +1 -0
- package/node_modules/@fps-games/editor-core/dist/transform-gizmo.d.ts +78 -2
- package/node_modules/@fps-games/editor-core/dist/transform-gizmo.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/transform-gizmo.js +81 -1
- package/node_modules/@fps-games/editor-core/dist/transform-gizmo.js.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/transform-operations.d.ts +32 -0
- package/node_modules/@fps-games/editor-core/dist/transform-operations.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-core/dist/transform-operations.js +125 -0
- package/node_modules/@fps-games/editor-core/dist/transform-operations.js.map +1 -0
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts +94 -0
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.js +58 -0
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.js.map +1 -0
- package/node_modules/@fps-games/editor-core/package.json +2 -2
- package/node_modules/@fps-games/editor-forge-play/dist/index.d.ts +1 -1
- package/node_modules/@fps-games/editor-forge-play/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-forge-play/dist/index.js +5 -1
- package/node_modules/@fps-games/editor-forge-play/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-forge-play/package.json +2 -2
- package/node_modules/@fps-games/editor-protocol/dist/index.d.ts +4 -0
- package/node_modules/@fps-games/editor-protocol/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-protocol/dist/index.js +4 -0
- package/node_modules/@fps-games/editor-protocol/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-protocol/package.json +1 -1
- package/package.json +6 -6
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createLocalEditorIcon } from './local-editor-ui-icons';
|
|
2
|
+
import { createBadge, createAssetList, createDockTab, createEditorInputStyle, createEmptyState, createListItemBlock, createPanelHeader, createPropertyRow, createToolbarButton, createTreeView, createTreeViewItem, } from './local-editor-ui-primitives';
|
|
2
3
|
import { clearElement, toTitle } from './local-editor-ui-shared';
|
|
4
|
+
const DOCK_TAB_ICONS = {
|
|
5
|
+
assets: 'asset',
|
|
6
|
+
history: 'history',
|
|
7
|
+
};
|
|
3
8
|
export function renderHierarchyPanel(doc, panel, state, rename, drop) {
|
|
4
9
|
clearElement(panel);
|
|
5
|
-
const createGroupButton = createToolbarButton(doc, '+
|
|
10
|
+
const createGroupButton = createToolbarButton(doc, '+ Empty', 'object');
|
|
6
11
|
createGroupButton.dataset.editorHierarchyCreateGroup = 'true';
|
|
7
12
|
createGroupButton.style.padding = '3px 7px';
|
|
8
13
|
createGroupButton.style.fontSize = '11px';
|
|
9
|
-
panel.appendChild(createPanelHeader(doc, '
|
|
14
|
+
panel.appendChild(createPanelHeader(doc, 'Hierarchy', [createGroupButton], 'hierarchy'));
|
|
10
15
|
const list = createTreeView(doc);
|
|
11
16
|
for (const item of state.hierarchy) {
|
|
12
17
|
const isRenaming = rename?.id === item.id;
|
|
@@ -35,7 +40,7 @@ export function renderHierarchyPanel(doc, panel, state, rename, drop) {
|
|
|
35
40
|
'border:1px solid var(--fps-editor-accent-strong)',
|
|
36
41
|
'border-radius:2px',
|
|
37
42
|
'background:var(--fps-editor-field)',
|
|
38
|
-
'color
|
|
43
|
+
'color:var(--fps-editor-text-strong)',
|
|
39
44
|
'font-size:12px',
|
|
40
45
|
'font-weight:700',
|
|
41
46
|
'padding:2px 5px',
|
|
@@ -80,7 +85,7 @@ export function renderWorkbenchBottomDockPanel(doc, panel, state, activeTab, pan
|
|
|
80
85
|
{ id: 'history', title: '历史', area: 'bottom' },
|
|
81
86
|
];
|
|
82
87
|
for (const tabPanel of dockTabs) {
|
|
83
|
-
const button = createDockTab(doc, tabPanel.title, activeTab === tabPanel.id);
|
|
88
|
+
const button = createDockTab(doc, tabPanel.title, activeTab === tabPanel.id, DOCK_TAB_ICONS[tabPanel.id]);
|
|
84
89
|
button.dataset.editorDockTab = tabPanel.id;
|
|
85
90
|
tabHeader.appendChild(button);
|
|
86
91
|
}
|
|
@@ -107,30 +112,29 @@ function appendDockTabs(doc, panel, activeTab) {
|
|
|
107
112
|
history: '历史',
|
|
108
113
|
};
|
|
109
114
|
for (const tab of ['assets', 'history']) {
|
|
110
|
-
const button = doc.createElement('button');
|
|
111
|
-
button.type = 'button';
|
|
112
|
-
button.dataset.editorDockTab = tab;
|
|
113
|
-
button.textContent = labels[tab];
|
|
114
115
|
const active = activeTab === tab;
|
|
115
|
-
button
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
'font-weight:900',
|
|
123
|
-
'padding:0 8px 8px',
|
|
124
|
-
'cursor:pointer',
|
|
125
|
-
].join(';');
|
|
116
|
+
const button = createDockTab(doc, labels[tab], active, DOCK_TAB_ICONS[tab]);
|
|
117
|
+
button.dataset.editorDockTab = tab;
|
|
118
|
+
button.style.border = '0';
|
|
119
|
+
button.style.borderBottom = `2px solid ${active ? 'var(--fps-editor-accent-strong)' : 'transparent'}`;
|
|
120
|
+
button.style.background = 'transparent';
|
|
121
|
+
button.style.color = active ? 'var(--fps-editor-text-strong)' : 'var(--fps-editor-muted)';
|
|
122
|
+
button.style.padding = '0 8px 8px';
|
|
126
123
|
tabs.appendChild(button);
|
|
127
124
|
}
|
|
128
125
|
panel.appendChild(tabs);
|
|
129
126
|
}
|
|
127
|
+
function createHeadingLabel(doc, text) {
|
|
128
|
+
const label = doc.createElement('span');
|
|
129
|
+
label.textContent = text;
|
|
130
|
+
label.style.cssText = 'min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
|
|
131
|
+
return label;
|
|
132
|
+
}
|
|
130
133
|
function renderAssetBrowserContent(doc, panel, state, variant = 'list') {
|
|
131
134
|
const title = doc.createElement('h2');
|
|
132
|
-
title.
|
|
133
|
-
title.
|
|
135
|
+
title.style.cssText = 'display:flex;align-items:center;gap:6px;font-size:13px;margin:0 0 8px;font-weight:800;color:var(--fps-editor-text-strong)';
|
|
136
|
+
title.appendChild(createLocalEditorIcon(doc, 'asset'));
|
|
137
|
+
title.appendChild(createHeadingLabel(doc, '资产浏览器'));
|
|
134
138
|
panel.appendChild(title);
|
|
135
139
|
const filter = doc.createElement('input');
|
|
136
140
|
filter.type = 'search';
|
|
@@ -177,19 +181,27 @@ function renderAssetBrowserContent(doc, panel, state, variant = 'list') {
|
|
|
177
181
|
'padding:6px 8px',
|
|
178
182
|
'border:1px solid var(--fps-editor-border)',
|
|
179
183
|
'border-radius:3px',
|
|
180
|
-
'background
|
|
184
|
+
'background:var(--fps-editor-asset-card-bg)',
|
|
181
185
|
'color:var(--fps-editor-text)',
|
|
186
|
+
'display:flex',
|
|
187
|
+
'align-items:center',
|
|
188
|
+
'gap:8px',
|
|
182
189
|
'font-size:12px',
|
|
183
190
|
'cursor:pointer',
|
|
184
191
|
].join(';');
|
|
192
|
+
const icon = createLocalEditorIcon(doc, 'asset', { size: 16 });
|
|
193
|
+
const body = doc.createElement('div');
|
|
194
|
+
body.style.cssText = 'min-width:0;flex:1';
|
|
185
195
|
const label = doc.createElement('div');
|
|
186
196
|
label.textContent = asset.label;
|
|
187
197
|
label.style.cssText = 'font-weight:800;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
|
|
188
198
|
const meta = doc.createElement('div');
|
|
189
199
|
meta.textContent = asset.meta ?? asset.id;
|
|
190
200
|
meta.style.cssText = 'color:var(--fps-editor-muted);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
|
|
191
|
-
|
|
192
|
-
|
|
201
|
+
body.appendChild(label);
|
|
202
|
+
body.appendChild(meta);
|
|
203
|
+
button.appendChild(icon);
|
|
204
|
+
button.appendChild(body);
|
|
193
205
|
list.appendChild(button);
|
|
194
206
|
}
|
|
195
207
|
panel.appendChild(list);
|
|
@@ -197,36 +209,21 @@ function renderAssetBrowserContent(doc, panel, state, variant = 'list') {
|
|
|
197
209
|
function renderHistoryPanel(doc, panel, history) {
|
|
198
210
|
const title = doc.createElement('h2');
|
|
199
211
|
const entries = history?.entries ?? [];
|
|
200
|
-
title.
|
|
201
|
-
title.
|
|
212
|
+
title.style.cssText = 'display:flex;align-items:center;gap:6px;font-size:13px;margin:0 0 8px;font-weight:800;color:var(--fps-editor-text-strong)';
|
|
213
|
+
title.appendChild(createLocalEditorIcon(doc, 'history'));
|
|
214
|
+
title.appendChild(createHeadingLabel(doc, `历史记录 (${entries.length})`));
|
|
202
215
|
panel.appendChild(title);
|
|
203
216
|
appendHistoryEntries(doc, panel, entries);
|
|
204
217
|
}
|
|
205
218
|
function appendHistoryEntries(doc, panel, entries) {
|
|
206
219
|
if (entries.length === 0) {
|
|
207
|
-
|
|
208
|
-
empty.textContent = '暂无文档修改。';
|
|
209
|
-
empty.style.cssText = [
|
|
210
|
-
'padding:8px',
|
|
211
|
-
'border:1px solid var(--fps-editor-border-soft)',
|
|
212
|
-
'border-radius:3px',
|
|
213
|
-
'background:var(--fps-editor-field)',
|
|
214
|
-
'color:var(--fps-editor-muted)',
|
|
215
|
-
'font-size:11px',
|
|
216
|
-
].join(';');
|
|
217
|
-
panel.appendChild(empty);
|
|
220
|
+
panel.appendChild(createEmptyState(doc, '暂无文档修改。'));
|
|
218
221
|
return;
|
|
219
222
|
}
|
|
220
223
|
const list = doc.createElement('div');
|
|
221
224
|
list.style.cssText = 'display:flex;flex-direction:column;gap:4px';
|
|
222
225
|
for (const entry of entries) {
|
|
223
|
-
const item = doc
|
|
224
|
-
item.style.cssText = [
|
|
225
|
-
'padding:7px 8px',
|
|
226
|
-
'border:1px solid var(--fps-editor-border-soft)',
|
|
227
|
-
'border-radius:3px',
|
|
228
|
-
'background:var(--fps-editor-panel-soft)',
|
|
229
|
-
].join(';');
|
|
226
|
+
const item = createListItemBlock(doc);
|
|
230
227
|
const label = doc.createElement('div');
|
|
231
228
|
label.textContent = entry.label;
|
|
232
229
|
label.style.cssText = 'font-size:12px;font-weight:900;color:var(--fps-editor-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
|
|
@@ -259,10 +256,12 @@ function formatHistoryTimestamp(createdAt) {
|
|
|
259
256
|
].join('');
|
|
260
257
|
}
|
|
261
258
|
export function renderInspectorPanel(doc, panel, state, filter = '', options = {}) {
|
|
259
|
+
const renderSnapshot = captureInspectorPanelRenderSnapshot(doc, panel);
|
|
262
260
|
clearElement(panel);
|
|
263
261
|
const title = doc.createElement('h2');
|
|
264
|
-
title.
|
|
265
|
-
title.
|
|
262
|
+
title.style.cssText = 'display:flex;align-items:center;gap:6px;font-size:13px;margin:-8px -8px 8px;padding:7px 8px;border-bottom:1px solid var(--fps-editor-divider);background:var(--fps-editor-chrome-dark);font-weight:800;color:var(--fps-editor-text-strong)';
|
|
263
|
+
title.appendChild(createLocalEditorIcon(doc, 'inspector'));
|
|
264
|
+
title.appendChild(createHeadingLabel(doc, 'Inspector'));
|
|
266
265
|
panel.appendChild(title);
|
|
267
266
|
const search = createInspectorSearchInput(doc, filter);
|
|
268
267
|
panel.appendChild(search);
|
|
@@ -276,23 +275,45 @@ export function renderInspectorPanel(doc, panel, state, filter = '', options = {
|
|
|
276
275
|
empty.textContent = '请从层级树或 Scene View 中选择一个 GameObject。';
|
|
277
276
|
empty.style.cssText = 'color:var(--fps-editor-muted);line-height:1.45';
|
|
278
277
|
panel.appendChild(empty);
|
|
278
|
+
restoreInspectorPanelRenderSnapshot(panel, renderSnapshot);
|
|
279
279
|
return;
|
|
280
280
|
}
|
|
281
281
|
const controlRegistry = createLocalEditorBrowserInspectorControlRegistry(options.controls, options.controlConflict);
|
|
282
282
|
appendInspectorSummary(doc, panel, inspectorObject, selectionCount);
|
|
283
283
|
const visibleSections = filterInspectorSections(inspectorObject.sections.filter(section => section.placement !== 'summary'), filter);
|
|
284
284
|
if (visibleSections.length === 0) {
|
|
285
|
-
if (!filter.trim() && inspectorObject.sections.length === 0)
|
|
285
|
+
if (!filter.trim() && inspectorObject.sections.length === 0) {
|
|
286
|
+
restoreInspectorPanelRenderSnapshot(panel, renderSnapshot);
|
|
286
287
|
return;
|
|
288
|
+
}
|
|
287
289
|
const empty = doc.createElement('div');
|
|
288
290
|
empty.textContent = '没有匹配的 Inspector 字段。';
|
|
289
291
|
empty.style.cssText = 'color:var(--fps-editor-muted);line-height:1.45';
|
|
290
292
|
panel.appendChild(empty);
|
|
293
|
+
restoreInspectorPanelRenderSnapshot(panel, renderSnapshot);
|
|
291
294
|
return;
|
|
292
295
|
}
|
|
293
296
|
for (const section of visibleSections) {
|
|
294
297
|
panel.appendChild(createInspectorSectionBlock(doc, inspectorObject, section, controlRegistry));
|
|
295
298
|
}
|
|
299
|
+
restoreInspectorPanelRenderSnapshot(panel, renderSnapshot);
|
|
300
|
+
}
|
|
301
|
+
function captureInspectorPanelRenderSnapshot(doc, panel) {
|
|
302
|
+
const activeElement = doc.activeElement;
|
|
303
|
+
const elementConstructor = doc.defaultView?.HTMLElement;
|
|
304
|
+
return {
|
|
305
|
+
preserveScroll: !!activeElement
|
|
306
|
+
&& (elementConstructor ? activeElement instanceof elementConstructor : activeElement instanceof HTMLElement)
|
|
307
|
+
&& panel.contains(activeElement),
|
|
308
|
+
scrollTop: panel.scrollTop,
|
|
309
|
+
scrollLeft: panel.scrollLeft,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function restoreInspectorPanelRenderSnapshot(panel, snapshot) {
|
|
313
|
+
if (!snapshot.preserveScroll)
|
|
314
|
+
return;
|
|
315
|
+
panel.scrollTop = snapshot.scrollTop;
|
|
316
|
+
panel.scrollLeft = snapshot.scrollLeft;
|
|
296
317
|
}
|
|
297
318
|
function createInspectorSearchInput(doc, value) {
|
|
298
319
|
const input = doc.createElement('input');
|
|
@@ -300,26 +321,24 @@ function createInspectorSearchInput(doc, value) {
|
|
|
300
321
|
input.value = value;
|
|
301
322
|
input.placeholder = 'Search...';
|
|
302
323
|
input.style.cssText = [
|
|
324
|
+
createEditorInputStyle(),
|
|
303
325
|
'width:100%',
|
|
304
326
|
'height:30px',
|
|
305
|
-
'box-sizing:border-box',
|
|
306
327
|
'margin:0 0 8px',
|
|
307
|
-
'border:1px solid var(--fps-editor-border)',
|
|
308
|
-
'border-radius:3px',
|
|
309
|
-
'background:var(--fps-editor-field)',
|
|
310
|
-
'color:var(--fps-editor-text)',
|
|
311
|
-
'font-size:12px',
|
|
312
|
-
'padding:0 8px',
|
|
313
328
|
'outline:none',
|
|
314
329
|
].join(';');
|
|
315
330
|
return input;
|
|
316
331
|
}
|
|
317
332
|
function appendInspectorSummary(doc, panel, inspectorObject, selectionCount) {
|
|
318
333
|
const block = createInspectorComponentBlock(doc);
|
|
334
|
+
const header = doc.createElement('div');
|
|
335
|
+
header.style.cssText = 'display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0 0 8px';
|
|
319
336
|
const title = doc.createElement('h3');
|
|
320
337
|
title.textContent = selectionCount > 1 ? 'Selection' : 'GameObject';
|
|
321
|
-
title.style.cssText = 'font-size:12px;margin:0
|
|
322
|
-
|
|
338
|
+
title.style.cssText = 'font-size:12px;margin:0;font-weight:900;color:var(--fps-editor-text-strong)';
|
|
339
|
+
header.appendChild(title);
|
|
340
|
+
header.appendChild(createInspectorAccessBadge(doc, 'readonly'));
|
|
341
|
+
block.appendChild(header);
|
|
323
342
|
appendReadOnlyRow(doc, block, selectionCount > 1 ? 'Selected' : 'Name', inspectorObject.label ?? inspectorObject.activeId ?? inspectorObject.targetIds[0] ?? '无');
|
|
324
343
|
appendReadOnlyRow(doc, block, 'Active ID', inspectorObject.activeId ?? '无');
|
|
325
344
|
if (selectionCount > 1)
|
|
@@ -350,7 +369,11 @@ function createInspectorSectionBlock(doc, inspectorObject, section, controlRegis
|
|
|
350
369
|
const block = doc.createElement('details');
|
|
351
370
|
block.dataset.editorInspectorSection = section.id;
|
|
352
371
|
block.open = section.collapsedByDefault !== true;
|
|
353
|
-
|
|
372
|
+
const status = resolveLocalEditorBrowserInspectorSectionStatus(section);
|
|
373
|
+
const { access, effect } = status;
|
|
374
|
+
block.dataset.editorInspectorAccess = access;
|
|
375
|
+
block.dataset.editorInspectorEffect = effect;
|
|
376
|
+
block.style.cssText = createInspectorBlockStyle(access, effect);
|
|
354
377
|
const sectionTitle = doc.createElement('summary');
|
|
355
378
|
sectionTitle.style.cssText = [
|
|
356
379
|
'font-size:12px',
|
|
@@ -375,11 +398,13 @@ function createInspectorSectionBlock(doc, inspectorObject, section, controlRegis
|
|
|
375
398
|
summary.style.cssText = 'overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-transform:none;font-size:11px';
|
|
376
399
|
meta.appendChild(summary);
|
|
377
400
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
401
|
+
const badge = createInspectorAccessBadge(doc, access);
|
|
402
|
+
badge.style.flex = '0 0 auto';
|
|
403
|
+
meta.appendChild(badge);
|
|
404
|
+
const effectBadge = createInspectorEffectBadge(doc, effect, section.disabledReason);
|
|
405
|
+
if (effectBadge && status.showEffectBadge) {
|
|
406
|
+
effectBadge.style.flex = '0 0 auto';
|
|
407
|
+
meta.appendChild(effectBadge);
|
|
383
408
|
}
|
|
384
409
|
sectionTitle.appendChild(meta);
|
|
385
410
|
block.appendChild(sectionTitle);
|
|
@@ -396,18 +421,133 @@ function createInspectorSectionBlock(doc, inspectorObject, section, controlRegis
|
|
|
396
421
|
}
|
|
397
422
|
function createInspectorComponentBlock(doc) {
|
|
398
423
|
const block = doc.createElement('div');
|
|
399
|
-
block.
|
|
424
|
+
block.dataset.editorInspectorAccess = 'readonly';
|
|
425
|
+
block.dataset.editorInspectorEffect = 'active';
|
|
426
|
+
block.style.cssText = createInspectorBlockStyle('readonly', 'active');
|
|
400
427
|
return block;
|
|
401
428
|
}
|
|
402
|
-
function
|
|
429
|
+
export function resolveLocalEditorBrowserInspectorSectionStatus(section) {
|
|
430
|
+
const access = getInspectorSectionAccess(section);
|
|
431
|
+
const effect = getInspectorSectionEffect(section);
|
|
432
|
+
return {
|
|
433
|
+
access,
|
|
434
|
+
effect,
|
|
435
|
+
showEffectBadge: effect !== 'active'
|
|
436
|
+
&& !(access === 'runtime' && effect === 'runtime')
|
|
437
|
+
&& !(effect === 'default' && inspectorSummaryLooksDefault(section.summary)),
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
function createInspectorBlockStyle(_access, _effect = 'active') {
|
|
403
441
|
return [
|
|
404
442
|
'margin:0 0 8px',
|
|
405
443
|
'padding:9px',
|
|
406
|
-
'border:1px solid var(--fps-editor-border)',
|
|
444
|
+
'border:1px solid var(--fps-editor-inspector-section-border, var(--fps-editor-border))',
|
|
407
445
|
'border-radius:3px',
|
|
408
446
|
'background:var(--fps-editor-panel-soft)',
|
|
409
447
|
].join(';');
|
|
410
448
|
}
|
|
449
|
+
function isInspectorPropertyEditable(property) {
|
|
450
|
+
return property.readOnly !== true
|
|
451
|
+
&& property.persistence === 'document'
|
|
452
|
+
&& getInspectorPropertyEffect(property) === 'active';
|
|
453
|
+
}
|
|
454
|
+
function getInspectorPropertyAccess(property) {
|
|
455
|
+
if (property.persistence === 'runtime')
|
|
456
|
+
return 'runtime';
|
|
457
|
+
if (getInspectorPropertyEffect(property) === 'runtime')
|
|
458
|
+
return 'runtime';
|
|
459
|
+
return isInspectorPropertyEditable(property) ? 'editable' : 'readonly';
|
|
460
|
+
}
|
|
461
|
+
function getInspectorSectionAccess(section) {
|
|
462
|
+
if (section.runtimeOnly || section.persistence === 'runtime' || getInspectorSectionEffect(section) === 'runtime')
|
|
463
|
+
return 'runtime';
|
|
464
|
+
const editableCount = section.properties.filter(isInspectorPropertyEditable).length;
|
|
465
|
+
if (editableCount === 0)
|
|
466
|
+
return 'readonly';
|
|
467
|
+
if (editableCount === section.properties.length)
|
|
468
|
+
return 'editable';
|
|
469
|
+
return 'mixed';
|
|
470
|
+
}
|
|
471
|
+
function getInspectorPropertyEffect(property) {
|
|
472
|
+
if (property.effect)
|
|
473
|
+
return property.effect;
|
|
474
|
+
if (property.persistence === 'runtime')
|
|
475
|
+
return 'runtime';
|
|
476
|
+
return 'active';
|
|
477
|
+
}
|
|
478
|
+
function getInspectorSectionEffect(section) {
|
|
479
|
+
if (section.effect)
|
|
480
|
+
return section.effect;
|
|
481
|
+
if (section.runtimeOnly || section.persistence === 'runtime')
|
|
482
|
+
return 'runtime';
|
|
483
|
+
if (section.properties.some(isInspectorPropertyEditable))
|
|
484
|
+
return 'active';
|
|
485
|
+
const effects = new Set(section.properties.map(getInspectorPropertyEffect));
|
|
486
|
+
if (effects.size === 1)
|
|
487
|
+
return [...effects][0] ?? 'active';
|
|
488
|
+
if (effects.has('unsupported'))
|
|
489
|
+
return 'unsupported';
|
|
490
|
+
if (effects.has('default'))
|
|
491
|
+
return 'default';
|
|
492
|
+
if (effects.has('derived'))
|
|
493
|
+
return 'derived';
|
|
494
|
+
if (effects.has('runtime'))
|
|
495
|
+
return 'runtime';
|
|
496
|
+
return 'active';
|
|
497
|
+
}
|
|
498
|
+
function createInspectorAccessBadge(doc, access) {
|
|
499
|
+
const labels = {
|
|
500
|
+
editable: 'EDITABLE',
|
|
501
|
+
mixed: 'MIXED',
|
|
502
|
+
readonly: 'READONLY',
|
|
503
|
+
runtime: 'RUNTIME',
|
|
504
|
+
};
|
|
505
|
+
const badge = createBadge(doc, labels[access], {
|
|
506
|
+
compact: true,
|
|
507
|
+
tone: access === 'editable' ? 'success' : access === 'mixed' || access === 'runtime' ? 'warning' : 'default',
|
|
508
|
+
});
|
|
509
|
+
badge.title = access === 'editable'
|
|
510
|
+
? 'This section writes to the document.'
|
|
511
|
+
: access === 'mixed'
|
|
512
|
+
? 'This section contains both editable and read-only fields.'
|
|
513
|
+
: access === 'runtime'
|
|
514
|
+
? 'Runtime-only context, not saved to the document.'
|
|
515
|
+
: 'Read-only information.';
|
|
516
|
+
return badge;
|
|
517
|
+
}
|
|
518
|
+
function createInspectorEffectBadge(doc, effect, disabledReason) {
|
|
519
|
+
if (effect === 'active')
|
|
520
|
+
return null;
|
|
521
|
+
const labels = {
|
|
522
|
+
default: 'DEFAULTS',
|
|
523
|
+
derived: 'DERIVED',
|
|
524
|
+
runtime: 'RUNTIME',
|
|
525
|
+
unsupported: 'NO EFFECT',
|
|
526
|
+
};
|
|
527
|
+
const badge = createBadge(doc, labels[effect], {
|
|
528
|
+
compact: true,
|
|
529
|
+
tone: effect === 'unsupported' ? 'danger' : 'warning',
|
|
530
|
+
});
|
|
531
|
+
badge.title = disabledReason ?? createInspectorEffectTitle(effect);
|
|
532
|
+
return badge;
|
|
533
|
+
}
|
|
534
|
+
function createInspectorEffectTitle(effect) {
|
|
535
|
+
switch (effect) {
|
|
536
|
+
case 'default':
|
|
537
|
+
return 'Default values are being shown; edits do not affect this object until an override is configured.';
|
|
538
|
+
case 'derived':
|
|
539
|
+
return 'Derived from document or runtime state.';
|
|
540
|
+
case 'runtime':
|
|
541
|
+
return 'Runtime-only context, not saved to the document.';
|
|
542
|
+
case 'unsupported':
|
|
543
|
+
return 'This field is visible but editing is not supported for the current object.';
|
|
544
|
+
default:
|
|
545
|
+
return 'Editable field.';
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function inspectorSummaryLooksDefault(summary) {
|
|
549
|
+
return summary?.trim().toLowerCase() === 'defaults';
|
|
550
|
+
}
|
|
411
551
|
function groupInspectorProperties(properties) {
|
|
412
552
|
const groups = [];
|
|
413
553
|
const consumed = new Set();
|
|
@@ -436,7 +576,7 @@ function groupInspectorProperties(properties) {
|
|
|
436
576
|
for (const entry of vector)
|
|
437
577
|
consumed.add(entry.path);
|
|
438
578
|
const parts = basePath.split('.');
|
|
439
|
-
groups.push({ kind: 'vector', label:
|
|
579
|
+
groups.push({ kind: 'vector', label: resolveInspectorVectorGroupLabel(vector, parts[parts.length - 1] ?? basePath), properties: vector });
|
|
440
580
|
}
|
|
441
581
|
else {
|
|
442
582
|
groups.push({ kind: 'property', property });
|
|
@@ -445,6 +585,16 @@ function groupInspectorProperties(properties) {
|
|
|
445
585
|
}
|
|
446
586
|
return groups;
|
|
447
587
|
}
|
|
588
|
+
function resolveInspectorVectorGroupLabel(properties, fallback) {
|
|
589
|
+
const labels = properties.map(property => {
|
|
590
|
+
const match = property.label.match(/^(.*)\.(x|y|z|r|g|b)$/);
|
|
591
|
+
return match?.[1]?.trim() ?? '';
|
|
592
|
+
});
|
|
593
|
+
const first = labels[0];
|
|
594
|
+
if (first && labels.every(label => label === first))
|
|
595
|
+
return first;
|
|
596
|
+
return toTitle(fallback);
|
|
597
|
+
}
|
|
448
598
|
const builtinInspectorControlRegistrations = [
|
|
449
599
|
{
|
|
450
600
|
id: 'builtin.readonly',
|
|
@@ -515,7 +665,16 @@ const builtinInspectorControlRegistrations = [
|
|
|
515
665
|
];
|
|
516
666
|
function appendInspectorPropertyRow(doc, parent, inspectorObject, property, controlRegistry) {
|
|
517
667
|
const control = renderInspectorControl(doc, controlRegistry, inspectorObject, property);
|
|
518
|
-
|
|
668
|
+
const access = getInspectorPropertyAccess(property);
|
|
669
|
+
const effect = getInspectorPropertyEffect(property);
|
|
670
|
+
const row = createPropertyRow(doc, property.label, control);
|
|
671
|
+
row.dataset.editorInspectorAccess = access;
|
|
672
|
+
row.dataset.editorInspectorEffect = effect;
|
|
673
|
+
row.title = createInspectorStatusTitle(access, effect, property.tooltip ?? property.disabledReason);
|
|
674
|
+
const label = row.firstElementChild;
|
|
675
|
+
if (label)
|
|
676
|
+
label.style.cssText = createInspectorPropertyLabelStyle(access, effect);
|
|
677
|
+
parent.appendChild(row);
|
|
519
678
|
}
|
|
520
679
|
export function createLocalEditorBrowserInspectorControlRegistry(controls = [], conflict = 'error') {
|
|
521
680
|
const registrations = new Map();
|
|
@@ -544,7 +703,7 @@ function compareInspectorControlRegistrations(left, right) {
|
|
|
544
703
|
return (left.order ?? 0) - (right.order ?? 0) || left.id.localeCompare(right.id);
|
|
545
704
|
}
|
|
546
705
|
function renderInspectorControl(doc, registrations, target, property) {
|
|
547
|
-
if (property
|
|
706
|
+
if (!isInspectorPropertyEditable(property))
|
|
548
707
|
return createInspectorReadonlyControl(doc, target, property);
|
|
549
708
|
const context = {
|
|
550
709
|
doc,
|
|
@@ -576,18 +735,145 @@ function localEditorBrowserInspectorControlSupports(registration, context) {
|
|
|
576
735
|
function appendInspectorVectorInputs(doc, parent, inspectorObject, label, properties) {
|
|
577
736
|
const wrapper = doc.createElement('div');
|
|
578
737
|
wrapper.style.cssText = 'margin:8px 0';
|
|
738
|
+
const access = getInspectorPropertyGroupAccess(properties);
|
|
739
|
+
const effect = getInspectorPropertyGroupEffect(properties);
|
|
740
|
+
wrapper.dataset.editorInspectorAccess = access;
|
|
741
|
+
wrapper.dataset.editorInspectorEffect = effect;
|
|
579
742
|
const labelElement = doc.createElement('div');
|
|
580
|
-
labelElement.
|
|
581
|
-
|
|
743
|
+
labelElement.style.cssText = 'display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:5px';
|
|
744
|
+
const labelText = doc.createElement('span');
|
|
745
|
+
labelText.textContent = label;
|
|
746
|
+
labelText.style.cssText = createInspectorPropertyLabelStyle(access, effect);
|
|
747
|
+
labelElement.appendChild(labelText);
|
|
748
|
+
if (access !== 'editable') {
|
|
749
|
+
const badge = createInspectorAccessBadge(doc, access);
|
|
750
|
+
badge.style.flex = '0 0 auto';
|
|
751
|
+
labelElement.appendChild(badge);
|
|
752
|
+
}
|
|
753
|
+
const effectBadge = createInspectorEffectBadge(doc, effect, getInspectorPropertyGroupDisabledReason(properties));
|
|
754
|
+
if (effectBadge && !(access === 'runtime' && effect === 'runtime')) {
|
|
755
|
+
effectBadge.style.flex = '0 0 auto';
|
|
756
|
+
labelElement.appendChild(effectBadge);
|
|
757
|
+
}
|
|
582
758
|
wrapper.appendChild(labelElement);
|
|
583
759
|
const fields = doc.createElement('div');
|
|
584
760
|
fields.style.cssText = 'display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px';
|
|
585
761
|
for (const property of properties) {
|
|
586
|
-
fields.appendChild(
|
|
762
|
+
fields.appendChild(isInspectorPropertyEditable(property)
|
|
763
|
+
? createInspectorNumberControl(doc, inspectorObject, property)
|
|
764
|
+
: createInspectorReadonlyControl(doc, inspectorObject, property));
|
|
587
765
|
}
|
|
588
766
|
wrapper.appendChild(fields);
|
|
589
767
|
parent.appendChild(wrapper);
|
|
590
768
|
}
|
|
769
|
+
function getInspectorPropertyGroupAccess(properties) {
|
|
770
|
+
if (properties.some(property => property.persistence === 'runtime'))
|
|
771
|
+
return 'runtime';
|
|
772
|
+
const editableCount = properties.filter(isInspectorPropertyEditable).length;
|
|
773
|
+
if (editableCount === 0)
|
|
774
|
+
return 'readonly';
|
|
775
|
+
if (editableCount === properties.length)
|
|
776
|
+
return 'editable';
|
|
777
|
+
return 'mixed';
|
|
778
|
+
}
|
|
779
|
+
function getInspectorPropertyGroupEffect(properties) {
|
|
780
|
+
const effects = new Set(properties.map(getInspectorPropertyEffect));
|
|
781
|
+
if (effects.size === 1)
|
|
782
|
+
return [...effects][0] ?? 'active';
|
|
783
|
+
if (effects.has('unsupported'))
|
|
784
|
+
return 'unsupported';
|
|
785
|
+
if (effects.has('default'))
|
|
786
|
+
return 'default';
|
|
787
|
+
if (effects.has('derived'))
|
|
788
|
+
return 'derived';
|
|
789
|
+
if (effects.has('runtime'))
|
|
790
|
+
return 'runtime';
|
|
791
|
+
return 'active';
|
|
792
|
+
}
|
|
793
|
+
function getInspectorPropertyGroupDisabledReason(properties) {
|
|
794
|
+
return properties.find(property => property.disabledReason)?.disabledReason;
|
|
795
|
+
}
|
|
796
|
+
function createInspectorPropertyLabelStyle(access, effect = 'active') {
|
|
797
|
+
return [
|
|
798
|
+
`color:${effect === 'unsupported' ? 'var(--fps-editor-danger-text)' : effect === 'default' || effect === 'derived' || access === 'runtime' ? 'var(--fps-editor-warn)' : access === 'editable' ? 'var(--fps-editor-muted-strong)' : 'var(--fps-editor-muted)'}`,
|
|
799
|
+
'font-weight:800',
|
|
800
|
+
access === 'readonly' ? 'opacity:0.82' : '',
|
|
801
|
+
].filter(Boolean).join(';');
|
|
802
|
+
}
|
|
803
|
+
function createInspectorAccessTitle(access, tooltip) {
|
|
804
|
+
const accessLabel = access === 'editable'
|
|
805
|
+
? 'Editable'
|
|
806
|
+
: access === 'mixed'
|
|
807
|
+
? 'Mixed editable and read-only'
|
|
808
|
+
: access === 'runtime'
|
|
809
|
+
? 'Runtime-only'
|
|
810
|
+
: 'Read-only';
|
|
811
|
+
return tooltip ? `${accessLabel}: ${tooltip}` : accessLabel;
|
|
812
|
+
}
|
|
813
|
+
function createInspectorStatusTitle(access, effect, detail) {
|
|
814
|
+
const parts = [createInspectorAccessTitle(access)];
|
|
815
|
+
if (effect !== 'active')
|
|
816
|
+
parts.push(createInspectorEffectTitle(effect));
|
|
817
|
+
if (detail)
|
|
818
|
+
parts.push(detail);
|
|
819
|
+
return [...new Set(parts)].join(' ');
|
|
820
|
+
}
|
|
821
|
+
function createInspectorReadonlyValueShell(doc, access, effect = 'active', title) {
|
|
822
|
+
const valueElement = doc.createElement('div');
|
|
823
|
+
valueElement.dataset.editorInspectorAccess = access;
|
|
824
|
+
valueElement.dataset.editorInspectorEffect = effect;
|
|
825
|
+
valueElement.title = title ?? createInspectorStatusTitle(access, effect);
|
|
826
|
+
const warningLike = effect === 'default' || effect === 'derived' || access === 'runtime' || effect === 'runtime';
|
|
827
|
+
const unsupported = effect === 'unsupported';
|
|
828
|
+
valueElement.style.cssText = [
|
|
829
|
+
'min-width:0',
|
|
830
|
+
'min-height:24px',
|
|
831
|
+
'display:flex',
|
|
832
|
+
'align-items:center',
|
|
833
|
+
'gap:5px',
|
|
834
|
+
'padding:3px 6px',
|
|
835
|
+
`border:1px solid ${unsupported ? 'var(--fps-editor-danger-border)' : warningLike ? 'var(--fps-editor-warn-border)' : 'var(--fps-editor-readonly-border)'}`,
|
|
836
|
+
'border-radius:3px',
|
|
837
|
+
`background:${unsupported ? 'var(--fps-editor-danger-soft)' : warningLike ? 'var(--fps-editor-warn-soft)' : 'var(--fps-editor-readonly-bg)'}`,
|
|
838
|
+
`color:${unsupported ? 'var(--fps-editor-danger-text)' : warningLike ? 'var(--fps-editor-warn)' : 'var(--fps-editor-readonly-text)'}`,
|
|
839
|
+
warningLike ? 'font-style:italic' : '',
|
|
840
|
+
].filter(Boolean).join(';');
|
|
841
|
+
const icon = createLocalEditorIcon(doc, 'lock', { size: 11, strokeWidth: 2.3 });
|
|
842
|
+
icon.style.opacity = '0.78';
|
|
843
|
+
valueElement.appendChild(icon);
|
|
844
|
+
return valueElement;
|
|
845
|
+
}
|
|
846
|
+
function appendInspectorReadonlyTextValue(doc, parent, value, access, effect = 'active', title) {
|
|
847
|
+
const valueText = doc.createElement('span');
|
|
848
|
+
valueText.textContent = value;
|
|
849
|
+
valueText.style.cssText = 'min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
|
|
850
|
+
parent.appendChild(valueText);
|
|
851
|
+
parent.title = title ?? createInspectorStatusTitle(access, effect);
|
|
852
|
+
}
|
|
853
|
+
function createInspectorReadonlyScalarControl(doc, value, access, effect = 'active', title) {
|
|
854
|
+
const valueElement = createInspectorReadonlyValueShell(doc, access, effect, title);
|
|
855
|
+
appendInspectorReadonlyTextValue(doc, valueElement, value, access, effect, title);
|
|
856
|
+
return valueElement;
|
|
857
|
+
}
|
|
858
|
+
function createInspectorReadonlyDetailsShell(doc, property, access) {
|
|
859
|
+
const effect = getInspectorPropertyEffect(property);
|
|
860
|
+
const warningLike = effect === 'default' || effect === 'derived' || access === 'runtime' || effect === 'runtime';
|
|
861
|
+
const unsupported = effect === 'unsupported';
|
|
862
|
+
const details = doc.createElement('details');
|
|
863
|
+
details.dataset.editorInspectorAccess = access;
|
|
864
|
+
details.dataset.editorInspectorEffect = effect;
|
|
865
|
+
details.title = createInspectorStatusTitle(access, effect, property.tooltip ?? property.disabledReason);
|
|
866
|
+
details.style.cssText = [
|
|
867
|
+
'min-width:0',
|
|
868
|
+
'max-width:100%',
|
|
869
|
+
'padding:3px 6px',
|
|
870
|
+
`border:1px solid ${unsupported ? 'var(--fps-editor-danger-border)' : warningLike ? 'var(--fps-editor-warn-border)' : 'var(--fps-editor-readonly-border)'}`,
|
|
871
|
+
'border-radius:3px',
|
|
872
|
+
`background:${unsupported ? 'var(--fps-editor-danger-soft)' : warningLike ? 'var(--fps-editor-warn-soft)' : 'var(--fps-editor-readonly-bg)'}`,
|
|
873
|
+
`color:${unsupported ? 'var(--fps-editor-danger-text)' : warningLike ? 'var(--fps-editor-warn)' : 'var(--fps-editor-readonly-text)'}`,
|
|
874
|
+
].join(';');
|
|
875
|
+
return details;
|
|
876
|
+
}
|
|
591
877
|
function createInspectorInputBase(doc, target, property) {
|
|
592
878
|
const input = doc.createElement('input');
|
|
593
879
|
input.value = property.mixed ? '' : String(property.value);
|
|
@@ -615,7 +901,14 @@ function createInspectorBooleanControl(doc, target, property) {
|
|
|
615
901
|
const input = createInspectorInputBase(doc, target, property);
|
|
616
902
|
input.type = 'checkbox';
|
|
617
903
|
input.checked = property.mixed ? false : property.value === true;
|
|
618
|
-
input.style.cssText =
|
|
904
|
+
input.style.cssText = [
|
|
905
|
+
'width:16px',
|
|
906
|
+
'height:16px',
|
|
907
|
+
'accent-color:var(--fps-editor-accent)',
|
|
908
|
+
'justify-self:start',
|
|
909
|
+
'cursor:pointer',
|
|
910
|
+
'box-shadow:0 0 0 1px var(--fps-editor-editable-border)',
|
|
911
|
+
].join(';');
|
|
619
912
|
return input;
|
|
620
913
|
}
|
|
621
914
|
function createInspectorEnumControl(doc, target, property) {
|
|
@@ -664,36 +957,30 @@ function createInspectorColorControl(doc, target, property) {
|
|
|
664
957
|
const input = createInspectorInputBase(doc, target, property);
|
|
665
958
|
input.type = 'color';
|
|
666
959
|
input.value = colorValueToHex(property.value);
|
|
667
|
-
input.style.cssText = 'width:34px;height:26px;border:1px solid var(--fps-editor-border);border-radius:3px;background:
|
|
960
|
+
input.style.cssText = 'width:34px;height:26px;border:1px solid var(--fps-editor-editable-border);border-radius:3px;background:var(--fps-editor-editable-bg);padding:0;box-shadow:var(--fps-editor-editable-shadow)';
|
|
668
961
|
return input;
|
|
669
962
|
}
|
|
670
963
|
function createInspectorReadonlyControl(doc, _target, property) {
|
|
671
964
|
if (!property.mixed && isExpandableInspectorValue(property.value)) {
|
|
672
965
|
return createInspectorObjectReadonlyControl(doc, property);
|
|
673
966
|
}
|
|
674
|
-
const
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
`color:${property.persistence === 'runtime' ? 'var(--fps-editor-muted)' : 'var(--fps-editor-text)'}`,
|
|
678
|
-
'overflow:hidden',
|
|
679
|
-
'text-overflow:ellipsis',
|
|
680
|
-
'white-space:nowrap',
|
|
681
|
-
property.persistence === 'runtime' ? 'font-style:italic' : '',
|
|
682
|
-
].filter(Boolean).join(';');
|
|
683
|
-
if (property.persistence === 'runtime')
|
|
684
|
-
valueElement.title = 'Runtime-only context';
|
|
685
|
-
return valueElement;
|
|
967
|
+
const access = getInspectorPropertyAccess(property);
|
|
968
|
+
const effect = getInspectorPropertyEffect(property);
|
|
969
|
+
return createInspectorReadonlyScalarControl(doc, property.mixed ? '--' : formatLocalEditorBrowserInspectorValue(property.value), access, effect, createInspectorStatusTitle(access, effect, property.tooltip ?? property.disabledReason));
|
|
686
970
|
}
|
|
687
971
|
function createInspectorObjectReadonlyControl(doc, property) {
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
'max-width:100%',
|
|
692
|
-
`color:${property.persistence === 'runtime' ? 'var(--fps-editor-muted)' : 'var(--fps-editor-text)'}`,
|
|
693
|
-
].join(';');
|
|
972
|
+
const access = getInspectorPropertyAccess(property);
|
|
973
|
+
const effect = getInspectorPropertyEffect(property);
|
|
974
|
+
const details = createInspectorReadonlyDetailsShell(doc, property, access);
|
|
694
975
|
const summary = doc.createElement('summary');
|
|
695
|
-
summary.
|
|
696
|
-
|
|
976
|
+
summary.style.cssText = 'cursor:pointer;display:flex;align-items:center;gap:5px;overflow:hidden;white-space:nowrap';
|
|
977
|
+
const icon = createLocalEditorIcon(doc, 'lock', { size: 11, strokeWidth: 2.3 });
|
|
978
|
+
icon.style.opacity = '0.78';
|
|
979
|
+
summary.appendChild(icon);
|
|
980
|
+
const summaryText = doc.createElement('span');
|
|
981
|
+
summaryText.textContent = formatInspectorObjectSummary(property.value);
|
|
982
|
+
summaryText.style.cssText = 'min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap';
|
|
983
|
+
summary.appendChild(summaryText);
|
|
697
984
|
details.appendChild(summary);
|
|
698
985
|
const pre = doc.createElement('pre');
|
|
699
986
|
pre.textContent = formatLocalEditorBrowserInspectorValue(property.value);
|
|
@@ -704,15 +991,13 @@ function createInspectorObjectReadonlyControl(doc, property) {
|
|
|
704
991
|
'word-break:break-word',
|
|
705
992
|
'margin:6px 0 0',
|
|
706
993
|
'padding:7px',
|
|
707
|
-
|
|
994
|
+
`border:1px solid ${effect === 'unsupported' ? 'var(--fps-editor-danger-border)' : effect === 'default' || effect === 'derived' || effect === 'runtime' || access === 'runtime' ? 'var(--fps-editor-warn-border)' : 'var(--fps-editor-readonly-border)'}`,
|
|
708
995
|
'border-radius:3px',
|
|
709
996
|
'background:var(--fps-editor-field)',
|
|
710
997
|
'font-size:11px',
|
|
711
998
|
'line-height:1.45',
|
|
712
999
|
].join(';');
|
|
713
1000
|
details.appendChild(pre);
|
|
714
|
-
if (property.persistence === 'runtime')
|
|
715
|
-
details.title = 'Runtime-only context';
|
|
716
1001
|
return details;
|
|
717
1002
|
}
|
|
718
1003
|
export function applyLocalEditorBrowserInspectorControlBinding(element, target, property, options) {
|
|
@@ -724,30 +1009,38 @@ export function applyLocalEditorBrowserInspectorControlBinding(element, target,
|
|
|
724
1009
|
element.dataset.serializedValueType = property.valueType;
|
|
725
1010
|
element.dataset.serializedCommitMode = property.commitMode;
|
|
726
1011
|
element.dataset.serializedPersistence = property.persistence;
|
|
1012
|
+
element.dataset.serializedEffect = getInspectorPropertyEffect(property);
|
|
1013
|
+
if (property.disabledReason)
|
|
1014
|
+
element.dataset.serializedDisabledReason = property.disabledReason;
|
|
727
1015
|
if (options?.source)
|
|
728
1016
|
element.dataset.serializedEditSource = options.source;
|
|
729
|
-
|
|
1017
|
+
const access = getInspectorPropertyAccess(property);
|
|
1018
|
+
const effect = getInspectorPropertyEffect(property);
|
|
1019
|
+
element.title = access === 'editable' && effect === 'active'
|
|
1020
|
+
? property.tooltip ?? property.label
|
|
1021
|
+
: createInspectorStatusTitle(access, effect, property.tooltip ?? property.disabledReason ?? property.label);
|
|
730
1022
|
if ('disabled' in element) {
|
|
731
|
-
element.disabled = property
|
|
1023
|
+
element.disabled = !isInspectorPropertyEditable(property);
|
|
732
1024
|
}
|
|
733
1025
|
}
|
|
734
1026
|
function createInspectorInputStyle() {
|
|
735
1027
|
return [
|
|
736
|
-
|
|
737
|
-
'height:28px',
|
|
738
|
-
'border:1px solid var(--fps-editor-border)',
|
|
739
|
-
'border-radius:3px',
|
|
740
|
-
'background:var(--fps-editor-field)',
|
|
741
|
-
'color:var(--fps-editor-text)',
|
|
742
|
-
'font-size:12px',
|
|
1028
|
+
createEditorInputStyle(),
|
|
743
1029
|
'padding:0 6px',
|
|
1030
|
+
'background:var(--fps-editor-editable-bg)',
|
|
1031
|
+
'border-color:var(--fps-editor-editable-border)',
|
|
1032
|
+
'color:var(--fps-editor-text-strong)',
|
|
1033
|
+
'box-shadow:var(--fps-editor-editable-shadow)',
|
|
744
1034
|
].join(';');
|
|
745
1035
|
}
|
|
746
1036
|
function appendReadOnlyRow(doc, parent, label, value) {
|
|
747
|
-
const valueElement = doc
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
1037
|
+
const valueElement = createInspectorReadonlyScalarControl(doc, value, 'readonly', 'active', 'Read-only summary');
|
|
1038
|
+
const row = createPropertyRow(doc, label, valueElement);
|
|
1039
|
+
row.dataset.editorInspectorAccess = 'readonly';
|
|
1040
|
+
const labelElement = row.firstElementChild;
|
|
1041
|
+
if (labelElement)
|
|
1042
|
+
labelElement.style.cssText = createInspectorPropertyLabelStyle('readonly', 'active');
|
|
1043
|
+
parent.appendChild(row);
|
|
751
1044
|
}
|
|
752
1045
|
function createLegacyInspectorObject(serializedObject) {
|
|
753
1046
|
const targetIds = 'targetIds' in serializedObject ? serializedObject.targetIds : [serializedObject.targetId];
|