@nice2dev/ui-3d 1.3.15 → 1.3.17
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 +13 -0
- package/dist/cjs/collaborative/collaborativeScene.js +160 -206
- package/dist/cjs/core/editorAsk.js +51 -41
- package/dist/cjs/core/i18n.js +13 -14
- package/dist/cjs/core/threeCompat.js +29 -42
- package/dist/cjs/dance/DanceBridge.js +148 -177
- package/dist/cjs/dance/DanceScoreEngine.js +209 -221
- package/dist/cjs/dance/PoseDetector.js +302 -275
- package/dist/cjs/index.js +110 -113
- package/dist/cjs/material/MaterialEditor.module.css.js +242 -5
- package/dist/cjs/material/NiceMaterialEditor.js +1213 -757
- package/dist/cjs/material/materialEditorTypes.js +35 -49
- package/dist/cjs/material/materialEditorUtils.js +684 -747
- package/dist/cjs/material/materialNodeDefinitions.js +1411 -1459
- package/dist/cjs/model/ModelEditor.js +90 -40
- package/dist/cjs/model/ModelEditor.module.css.js +257 -5
- package/dist/cjs/model/ModelEditorLeftPanel.js +126 -47
- package/dist/cjs/model/ModelEditorMenuBar.js +359 -32
- package/dist/cjs/model/ModelEditorRightPanel.js +647 -131
- package/dist/cjs/model/ModelEditorSubComponents.js +277 -112
- package/dist/cjs/model/ModelEditorTimeline.js +232 -34
- package/dist/cjs/model/ModelEditorToolbar.js +170 -14
- package/dist/cjs/model/ModelEditorViewport.js +231 -39
- package/dist/cjs/model/ModelViewer.js +388 -63
- package/dist/cjs/model/ModelViewer.module.css.js +77 -5
- package/dist/cjs/model/NiceArmatureEditor.js +473 -274
- package/dist/cjs/model/NiceMorphTargetEditor.js +333 -227
- package/dist/cjs/model/NiceOctree.js +372 -320
- package/dist/cjs/model/NicePhysicsSimulation.js +528 -298
- package/dist/cjs/model/NiceProceduralGeometry.js +673 -300
- package/dist/cjs/model/NiceTerrainEditor.js +595 -385
- package/dist/cjs/model/NiceWeightPainter.js +384 -261
- package/dist/cjs/model/NiceXRPreview.js +385 -308
- package/dist/cjs/model/cadModeUtils.js +103 -106
- package/dist/cjs/model/editorShortcuts.js +171 -194
- package/dist/cjs/model/modelEditorTypes.js +100 -118
- package/dist/cjs/model/modelEditorUtils.js +1061 -1146
- package/dist/cjs/model/simsModeUtils.js +1023 -1053
- package/dist/cjs/model/useModelEditor.js +1977 -1933
- package/dist/cjs/model/useModelViewer.js +633 -665
- package/dist/cjs/nice2dev-ui-3d.css +1 -1
- package/dist/cjs/particle/NiceParticleEditor.js +1186 -571
- package/dist/cjs/particle/ParticleEditor.module.css.js +122 -5
- package/dist/cjs/particle/particleEditorTypes.js +62 -70
- package/dist/cjs/particle/particleEditorUtils.js +998 -1013
- package/dist/cjs/rendering/NiceCascadedShadows.js +381 -259
- package/dist/cjs/rendering/NiceRenderExport.js +424 -337
- package/dist/cjs/rendering/NiceSSAO.js +454 -337
- package/dist/cjs/rendering/NiceSSR.js +387 -261
- package/dist/cjs/rendering/NiceWebGPURenderer.js +359 -230
- package/dist/cjs/uv/NiceUVEditor.js +787 -550
- package/dist/cjs/uv/UVEditor.module.css.js +53 -5
- package/dist/cjs/uv/uvEditorTypes.js +59 -76
- package/dist/cjs/uv/uvEditorUtils.js +501 -575
- package/dist/esm/collaborative/collaborativeScene.js +163 -205
- package/dist/esm/core/editorAsk.js +53 -40
- package/dist/esm/core/i18n.js +15 -13
- package/dist/esm/core/threeCompat.js +18 -26
- package/dist/esm/dance/DanceBridge.js +151 -176
- package/dist/esm/dance/DanceScoreEngine.js +211 -220
- package/dist/esm/dance/PoseDetector.js +304 -274
- package/dist/esm/index.js +258 -36
- package/dist/esm/material/MaterialEditor.module.css.js +242 -3
- package/dist/esm/material/NiceMaterialEditor.js +1215 -756
- package/dist/esm/material/materialEditorTypes.js +45 -48
- package/dist/esm/material/materialEditorUtils.js +713 -746
- package/dist/esm/material/materialNodeDefinitions.js +1415 -1458
- package/dist/esm/model/ModelEditor.js +91 -39
- package/dist/esm/model/ModelEditor.module.css.js +257 -3
- package/dist/esm/model/ModelEditorLeftPanel.js +126 -45
- package/dist/esm/model/ModelEditorMenuBar.js +359 -30
- package/dist/esm/model/ModelEditorRightPanel.js +634 -114
- package/dist/esm/model/ModelEditorSubComponents.js +265 -94
- package/dist/esm/model/ModelEditorTimeline.js +232 -32
- package/dist/esm/model/ModelEditorToolbar.js +170 -12
- package/dist/esm/model/ModelEditorViewport.js +231 -37
- package/dist/esm/model/ModelViewer.js +389 -62
- package/dist/esm/model/ModelViewer.module.css.js +77 -3
- package/dist/esm/model/NiceArmatureEditor.js +462 -258
- package/dist/esm/model/NiceMorphTargetEditor.js +322 -211
- package/dist/esm/model/NiceOctree.js +361 -304
- package/dist/esm/model/NicePhysicsSimulation.js +517 -282
- package/dist/esm/model/NiceProceduralGeometry.js +667 -284
- package/dist/esm/model/NiceTerrainEditor.js +584 -369
- package/dist/esm/model/NiceWeightPainter.js +373 -245
- package/dist/esm/model/NiceXRPreview.js +374 -292
- package/dist/esm/model/cadModeUtils.js +95 -88
- package/dist/esm/model/editorShortcuts.js +172 -193
- package/dist/esm/model/modelEditorTypes.js +90 -100
- package/dist/esm/model/modelEditorUtils.js +1056 -1128
- package/dist/esm/model/simsModeUtils.js +1021 -1035
- package/dist/esm/model/useModelEditor.js +1946 -1920
- package/dist/esm/model/useModelViewer.js +619 -647
- package/dist/esm/nice2dev-ui-3d.css +1 -1
- package/dist/esm/particle/NiceParticleEditor.js +1188 -570
- package/dist/esm/particle/ParticleEditor.module.css.js +122 -3
- package/dist/esm/particle/particleEditorTypes.js +69 -69
- package/dist/esm/particle/particleEditorUtils.js +1027 -1012
- package/dist/esm/rendering/NiceCascadedShadows.js +370 -243
- package/dist/esm/rendering/NiceRenderExport.js +413 -321
- package/dist/esm/rendering/NiceSSAO.js +450 -328
- package/dist/esm/rendering/NiceSSR.js +383 -252
- package/dist/esm/rendering/NiceWebGPURenderer.js +326 -214
- package/dist/esm/uv/NiceUVEditor.js +788 -549
- package/dist/esm/uv/UVEditor.module.css.js +53 -3
- package/dist/esm/uv/uvEditorTypes.js +68 -75
- package/dist/esm/uv/uvEditorUtils.js +515 -557
- package/package.json +7 -12
|
@@ -1,125 +1,122 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const THREE = require("three");
|
|
5
4
|
function _interopNamespaceDefault(e) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
5
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
6
|
+
if (e) {
|
|
7
|
+
for (const k in e) {
|
|
8
|
+
if (k !== "default") {
|
|
9
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
10
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: () => e[k]
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
n.default = e;
|
|
18
|
+
return Object.freeze(n);
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* cadModeUtils.ts — CAD-style design utilities for ModelEditor.
|
|
26
|
-
*
|
|
27
|
-
* Provides: wall/floor/room drawing, dimension annotations,
|
|
28
|
-
* snap-to-grid, measurement overlay, DXF import/export,
|
|
29
|
-
* floor plan tools — inspired by AutoCAD & ArchiCAD.
|
|
30
|
-
*/
|
|
31
|
-
/* ════════════════════════════════════════════════════════════════
|
|
32
|
-
CONSTANTS
|
|
33
|
-
════════════════════════════════════════════════════════════════ */
|
|
20
|
+
const THREE__namespace = /* @__PURE__ */ _interopNamespaceDefault(THREE);
|
|
34
21
|
const DEFAULT_CAD_SETTINGS = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
22
|
+
grid: {
|
|
23
|
+
enabled: true,
|
|
24
|
+
spacing: 1,
|
|
25
|
+
subdivisions: 10,
|
|
26
|
+
unit: "m",
|
|
27
|
+
showLabels: true,
|
|
28
|
+
color: "#444466",
|
|
29
|
+
subColor: "#333344"
|
|
30
|
+
},
|
|
31
|
+
snapModes: ["grid", "endpoint", "midpoint", "intersection"],
|
|
32
|
+
snapRadius: 0.15,
|
|
33
|
+
defaultWallHeight: 2.8,
|
|
34
|
+
defaultWallThickness: 0.2,
|
|
35
|
+
defaultDoorWidth: 0.9,
|
|
36
|
+
defaultDoorHeight: 2.1,
|
|
37
|
+
defaultWindowWidth: 1.2,
|
|
38
|
+
defaultWindowHeight: 1.4,
|
|
39
|
+
defaultWindowSill: 0.9,
|
|
40
|
+
unit: "m",
|
|
41
|
+
precision: 2,
|
|
42
|
+
orthogonalLock: false,
|
|
43
|
+
showDimensions: true,
|
|
44
|
+
currentFloor: 0
|
|
58
45
|
};
|
|
59
46
|
const UNIT_SCALES = {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
47
|
+
mm: 1e-3,
|
|
48
|
+
cm: 0.01,
|
|
49
|
+
m: 1,
|
|
50
|
+
in: 0.0254,
|
|
51
|
+
ft: 0.3048
|
|
65
52
|
};
|
|
66
53
|
const ROOM_COLORS = {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
54
|
+
living: "#e8d5b0",
|
|
55
|
+
bedroom: "#c5d8e8",
|
|
56
|
+
bathroom: "#b0dde8",
|
|
57
|
+
kitchen: "#e8d0b5",
|
|
58
|
+
dining: "#d8c8a8",
|
|
59
|
+
office: "#c8d5c0",
|
|
60
|
+
garage: "#c0c0c0",
|
|
61
|
+
hallway: "#d5d0c8",
|
|
62
|
+
closet: "#d8cbe8",
|
|
63
|
+
laundry: "#b8d8d0",
|
|
64
|
+
balcony: "#c0e0c0",
|
|
65
|
+
stairwell: "#d0c8b8",
|
|
66
|
+
custom: "#d0d0d0"
|
|
80
67
|
};
|
|
81
68
|
const WALL_MATERIALS = [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
69
|
+
{ id: "concrete", name: "Concrete", color: "#b8b8b8" },
|
|
70
|
+
{ id: "brick", name: "Brick", color: "#c07050" },
|
|
71
|
+
{ id: "drywall", name: "Drywall", color: "#f0e8d8" },
|
|
72
|
+
{ id: "glass", name: "Glass", color: "#c8e0f0" },
|
|
73
|
+
{ id: "wood", name: "Wood Panel", color: "#c8a060" },
|
|
74
|
+
{ id: "stone", name: "Stone", color: "#a0a098" },
|
|
75
|
+
{ id: "metal", name: "Metal Panel", color: "#b0b0b8" }
|
|
89
76
|
];
|
|
90
77
|
const FLOOR_MATERIALS = [
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
78
|
+
{ id: "hardwood", name: "Hardwood", color: "#c09050" },
|
|
79
|
+
{ id: "tile-white", name: "White Tile", color: "#f0f0f0" },
|
|
80
|
+
{ id: "tile-grey", name: "Grey Tile", color: "#b0b0b0" },
|
|
81
|
+
{ id: "carpet", name: "Carpet", color: "#908070" },
|
|
82
|
+
{ id: "marble", name: "Marble", color: "#e8e0d8" },
|
|
83
|
+
{ id: "concrete", name: "Polished Concrete", color: "#c0c0c0" },
|
|
84
|
+
{ id: "laminate", name: "Laminate", color: "#d0b080" },
|
|
85
|
+
{ id: "vinyl", name: "Vinyl", color: "#d0d0c8" }
|
|
99
86
|
];
|
|
100
|
-
/* ════════════════════════════════════════════════════════════════
|
|
101
|
-
GRID & SNAP
|
|
102
|
-
════════════════════════════════════════════════════════════════ */
|
|
103
87
|
function createCADGrid(settings) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
88
|
+
const group = new THREE__namespace.Group();
|
|
89
|
+
group.name = "__cadGrid";
|
|
90
|
+
const size = settings.spacing * 50;
|
|
91
|
+
const mainGrid = new THREE__namespace.GridHelper(
|
|
92
|
+
size * 2,
|
|
93
|
+
Math.floor(size * 2 / settings.spacing),
|
|
94
|
+
settings.color,
|
|
95
|
+
settings.subColor
|
|
96
|
+
);
|
|
97
|
+
mainGrid.position.y = 1e-3;
|
|
98
|
+
group.add(mainGrid);
|
|
99
|
+
if (settings.subdivisions > 1) {
|
|
100
|
+
const subSize = settings.spacing / settings.subdivisions;
|
|
101
|
+
const subGrid = new THREE__namespace.GridHelper(
|
|
102
|
+
size * 2,
|
|
103
|
+
Math.floor(size * 2 / subSize),
|
|
104
|
+
settings.subColor,
|
|
105
|
+
`${settings.subColor}44`
|
|
106
|
+
);
|
|
107
|
+
subGrid.position.y = 0;
|
|
108
|
+
group.add(subGrid);
|
|
109
|
+
}
|
|
110
|
+
return group;
|
|
117
111
|
}
|
|
118
112
|
function snapToCADGrid(point, settings) {
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
const snap = settings.grid.spacing / settings.grid.subdivisions;
|
|
114
|
+
return new THREE__namespace.Vector3(
|
|
115
|
+
Math.round(point.x / snap) * snap,
|
|
116
|
+
Math.round(point.y / snap) * snap,
|
|
117
|
+
Math.round(point.z / snap) * snap
|
|
118
|
+
);
|
|
121
119
|
}
|
|
122
|
-
|
|
123
120
|
exports.DEFAULT_CAD_SETTINGS = DEFAULT_CAD_SETTINGS;
|
|
124
121
|
exports.FLOOR_MATERIALS = FLOOR_MATERIALS;
|
|
125
122
|
exports.ROOM_COLORS = ROOM_COLORS;
|
|
@@ -1,220 +1,197 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* editorShortcuts.ts — Customizable keyboard shortcuts for the 3D ModelEditor.
|
|
5
|
-
*
|
|
6
|
-
* Features:
|
|
7
|
-
* - Pre-configured default shortcuts matching current ModelEditor
|
|
8
|
-
* - Rebindable keys with persistence support
|
|
9
|
-
* - Shortcut categories for organized display
|
|
10
|
-
* - Conflict detection
|
|
11
|
-
*/
|
|
12
|
-
/* ═══════════════════════════════════════════
|
|
13
|
-
Helpers
|
|
14
|
-
═══════════════════════════════════════════ */
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
15
3
|
function normalizeKey(key) {
|
|
16
|
-
|
|
4
|
+
return key.length === 1 ? key.toLowerCase() : key;
|
|
17
5
|
}
|
|
18
6
|
function bindingEquals(a, b) {
|
|
19
|
-
|
|
20
|
-
!!a.ctrl === !!b.ctrl &&
|
|
21
|
-
!!a.shift === !!b.shift &&
|
|
22
|
-
!!a.alt === !!b.alt &&
|
|
23
|
-
!!a.meta === !!b.meta);
|
|
7
|
+
return normalizeKey(a.key) === normalizeKey(b.key) && !!a.ctrl === !!b.ctrl && !!a.shift === !!b.shift && !!a.alt === !!b.alt && !!a.meta === !!b.meta;
|
|
24
8
|
}
|
|
25
9
|
function eventToBinding(e) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
10
|
+
return {
|
|
11
|
+
key: e.key,
|
|
12
|
+
ctrl: e.ctrlKey || e.metaKey,
|
|
13
|
+
shift: e.shiftKey,
|
|
14
|
+
alt: e.altKey
|
|
15
|
+
};
|
|
32
16
|
}
|
|
33
|
-
/* ═══════════════════════════════════════════
|
|
34
|
-
Default Shortcuts
|
|
35
|
-
═══════════════════════════════════════════ */
|
|
36
17
|
const DEFAULT_SHORTCUTS = [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
18
|
+
// Transform
|
|
19
|
+
{
|
|
20
|
+
id: "transform.translate",
|
|
21
|
+
label: "Move (Translate)",
|
|
22
|
+
category: "Transform",
|
|
23
|
+
binding: { key: "g" }
|
|
24
|
+
},
|
|
25
|
+
{ id: "transform.rotate", label: "Rotate", category: "Transform", binding: { key: "r" } },
|
|
26
|
+
{ id: "transform.scale", label: "Scale", category: "Transform", binding: { key: "s" } },
|
|
27
|
+
{
|
|
28
|
+
id: "transform.delete",
|
|
29
|
+
label: "Delete Selected",
|
|
30
|
+
category: "Transform",
|
|
31
|
+
binding: { key: "Delete" }
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "transform.deleteAlt",
|
|
35
|
+
label: "Delete (Ctrl+X)",
|
|
36
|
+
category: "Transform",
|
|
37
|
+
binding: { key: "x", ctrl: true }
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "transform.duplicate",
|
|
41
|
+
label: "Duplicate",
|
|
42
|
+
category: "Transform",
|
|
43
|
+
binding: { key: "d", shift: true }
|
|
44
|
+
},
|
|
45
|
+
// Camera
|
|
46
|
+
{ id: "camera.focus", label: "Focus on Object", category: "Camera", binding: { key: "f" } },
|
|
47
|
+
{ id: "camera.front", label: "Front View", category: "Camera", binding: { key: "1" } },
|
|
48
|
+
{ id: "camera.right", label: "Right View", category: "Camera", binding: { key: "3" } },
|
|
49
|
+
{ id: "camera.top", label: "Top View", category: "Camera", binding: { key: "7" } },
|
|
50
|
+
{ id: "camera.left", label: "Left View", category: "Camera", binding: { key: "4" } },
|
|
51
|
+
{ id: "camera.back", label: "Back View", category: "Camera", binding: { key: "9" } },
|
|
52
|
+
{ id: "camera.bottom", label: "Bottom View", category: "Camera", binding: { key: "2" } },
|
|
53
|
+
// Animation
|
|
54
|
+
{ id: "anim.playPause", label: "Play / Pause", category: "Animation", binding: { key: " " } },
|
|
55
|
+
// Edit
|
|
56
|
+
{ id: "edit.undo", label: "Undo", category: "Edit", binding: { key: "z", ctrl: true } },
|
|
57
|
+
{ id: "edit.redo", label: "Redo", category: "Edit", binding: { key: "y", ctrl: true } },
|
|
58
|
+
{
|
|
59
|
+
id: "edit.redoAlt",
|
|
60
|
+
label: "Redo (Ctrl+Shift+Z)",
|
|
61
|
+
category: "Edit",
|
|
62
|
+
binding: { key: "z", ctrl: true, shift: true }
|
|
63
|
+
},
|
|
64
|
+
// Mode
|
|
65
|
+
{ id: "mode.cycle", label: "Cycle Editor Mode", category: "Mode", binding: { key: "Tab" } },
|
|
66
|
+
{ id: "mode.escape", label: "Close/Cancel", category: "Mode", binding: { key: "Escape" } }
|
|
86
67
|
];
|
|
87
|
-
/* ═══════════════════════════════════════════
|
|
88
|
-
EditorShortcutManager
|
|
89
|
-
═══════════════════════════════════════════ */
|
|
90
68
|
class EditorShortcutManager {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
69
|
+
constructor() {
|
|
70
|
+
this.shortcuts = /* @__PURE__ */ new Map();
|
|
71
|
+
this.callbacks = /* @__PURE__ */ new Map();
|
|
72
|
+
for (const def of DEFAULT_SHORTCUTS) {
|
|
73
|
+
this.shortcuts.set(def.id, { ...def, enabled: true });
|
|
97
74
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
75
|
+
}
|
|
76
|
+
/** Register a callback for a shortcut ID. */
|
|
77
|
+
on(id, callback) {
|
|
78
|
+
this.callbacks.set(id, callback);
|
|
79
|
+
}
|
|
80
|
+
/** Unregister a callback. */
|
|
81
|
+
off(id) {
|
|
82
|
+
this.callbacks.delete(id);
|
|
83
|
+
}
|
|
84
|
+
/** Rebind a shortcut to a new key combination. */
|
|
85
|
+
rebind(id, binding) {
|
|
86
|
+
const shortcut = this.shortcuts.get(id);
|
|
87
|
+
if (shortcut) {
|
|
88
|
+
shortcut.binding = binding;
|
|
101
89
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
90
|
+
}
|
|
91
|
+
/** Enable/disable a shortcut. */
|
|
92
|
+
setEnabled(id, enabled) {
|
|
93
|
+
const shortcut = this.shortcuts.get(id);
|
|
94
|
+
if (shortcut) {
|
|
95
|
+
shortcut.enabled = enabled;
|
|
105
96
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
97
|
+
}
|
|
98
|
+
/** Reset all bindings to defaults. */
|
|
99
|
+
resetAll() {
|
|
100
|
+
this.shortcuts.clear();
|
|
101
|
+
for (const def of DEFAULT_SHORTCUTS) {
|
|
102
|
+
this.shortcuts.set(def.id, { ...def, enabled: true });
|
|
112
103
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
}
|
|
105
|
+
/** Get all shortcuts grouped by category. */
|
|
106
|
+
getGrouped() {
|
|
107
|
+
const groups = {};
|
|
108
|
+
for (const s of this.shortcuts.values()) {
|
|
109
|
+
if (!groups[s.category]) {
|
|
110
|
+
groups[s.category] = [];
|
|
111
|
+
}
|
|
112
|
+
groups[s.category].push(s);
|
|
119
113
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
114
|
+
return groups;
|
|
115
|
+
}
|
|
116
|
+
/** Get all shortcuts as a flat array. */
|
|
117
|
+
getAll() {
|
|
118
|
+
return [...this.shortcuts.values()];
|
|
119
|
+
}
|
|
120
|
+
/** Find conflicts (two shortcuts with the same binding). */
|
|
121
|
+
findConflicts() {
|
|
122
|
+
const conflicts = [];
|
|
123
|
+
const entries = [...this.shortcuts.values()];
|
|
124
|
+
for (let i = 0; i < entries.length; i++) {
|
|
125
|
+
for (let j = i + 1; j < entries.length; j++) {
|
|
126
|
+
if (bindingEquals(entries[i].binding, entries[j].binding)) {
|
|
127
|
+
conflicts.push([entries[i], entries[j]]);
|
|
125
128
|
}
|
|
129
|
+
}
|
|
126
130
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
return conflicts;
|
|
132
|
+
}
|
|
133
|
+
/** Export bindings for persistence. */
|
|
134
|
+
exportConfig() {
|
|
135
|
+
return [...this.shortcuts.values()].map((s) => ({
|
|
136
|
+
id: s.id,
|
|
137
|
+
binding: s.binding
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
/** Import bindings from saved config. */
|
|
141
|
+
importConfig(configs) {
|
|
142
|
+
for (const config of configs) {
|
|
143
|
+
this.rebind(config.id, config.binding);
|
|
137
144
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
}
|
|
146
|
+
/** Match a keyboard event to a shortcut and return its ID (or null). */
|
|
147
|
+
match(e) {
|
|
148
|
+
const evtBinding = eventToBinding(e);
|
|
149
|
+
for (const [id, shortcut] of this.shortcuts) {
|
|
150
|
+
if (!shortcut.enabled) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (bindingEquals(evtBinding, shortcut.binding)) {
|
|
154
|
+
return id;
|
|
155
|
+
}
|
|
141
156
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
conflicts.push([entries[i], entries[j]]);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return conflicts;
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
/** Handle a keyboard event — fires callback if matched. Returns true if handled. */
|
|
160
|
+
handleKeyDown(e) {
|
|
161
|
+
const id = this.match(e);
|
|
162
|
+
if (!id) {
|
|
163
|
+
return false;
|
|
154
164
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}));
|
|
165
|
+
const cb = this.callbacks.get(id);
|
|
166
|
+
if (cb) {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
cb();
|
|
169
|
+
return true;
|
|
161
170
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
/** Format a binding for UI display. */
|
|
174
|
+
formatBinding(id) {
|
|
175
|
+
const shortcut = this.shortcuts.get(id);
|
|
176
|
+
if (!shortcut) {
|
|
177
|
+
return "";
|
|
167
178
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (!shortcut.enabled) {
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
if (bindingEquals(evtBinding, shortcut.binding)) {
|
|
176
|
-
return id;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return null;
|
|
179
|
+
const b = shortcut.binding;
|
|
180
|
+
const parts = [];
|
|
181
|
+
if (b.ctrl) {
|
|
182
|
+
parts.push("Ctrl");
|
|
180
183
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const id = this.match(e);
|
|
184
|
-
if (!id) {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
const cb = this.callbacks.get(id);
|
|
188
|
-
if (cb) {
|
|
189
|
-
e.preventDefault();
|
|
190
|
-
cb();
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
|
-
return false;
|
|
184
|
+
if (b.shift) {
|
|
185
|
+
parts.push("Shift");
|
|
194
186
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
const b = shortcut.binding;
|
|
202
|
-
const parts = [];
|
|
203
|
-
if (b.ctrl) {
|
|
204
|
-
parts.push('Ctrl');
|
|
205
|
-
}
|
|
206
|
-
if (b.shift) {
|
|
207
|
-
parts.push('Shift');
|
|
208
|
-
}
|
|
209
|
-
if (b.alt) {
|
|
210
|
-
parts.push('Alt');
|
|
211
|
-
}
|
|
212
|
-
if (b.meta) {
|
|
213
|
-
parts.push('Meta');
|
|
214
|
-
}
|
|
215
|
-
parts.push(b.key === ' ' ? 'Space' : b.key.length === 1 ? b.key.toUpperCase() : b.key);
|
|
216
|
-
return parts.join('+');
|
|
187
|
+
if (b.alt) {
|
|
188
|
+
parts.push("Alt");
|
|
189
|
+
}
|
|
190
|
+
if (b.meta) {
|
|
191
|
+
parts.push("Meta");
|
|
217
192
|
}
|
|
193
|
+
parts.push(b.key === " " ? "Space" : b.key.length === 1 ? b.key.toUpperCase() : b.key);
|
|
194
|
+
return parts.join("+");
|
|
195
|
+
}
|
|
218
196
|
}
|
|
219
|
-
|
|
220
197
|
exports.EditorShortcutManager = EditorShortcutManager;
|