layplux 0.0.1
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/cjs/components/center-view/index.cjs +41 -0
- package/dist/cjs/components/corner-glow/index.cjs +31 -0
- package/dist/cjs/components/dropdown/index.cjs +162 -0
- package/dist/cjs/components/icon/index.cjs +59 -0
- package/dist/cjs/components/index.cjs +25 -0
- package/dist/cjs/components/panel-view/index.cjs +166 -0
- package/dist/cjs/components/popup/index.cjs +280 -0
- package/dist/cjs/components/title/index.cjs +76 -0
- package/dist/cjs/components/tooltip/index.cjs +68 -0
- package/dist/cjs/components/widget/index.cjs +104 -0
- package/dist/cjs/index.cjs +40 -0
- package/dist/cjs/layout/glass-overlay.cjs +31 -0
- package/dist/cjs/layout/layered-manager.cjs +35 -0
- package/dist/cjs/layout/layplux.cjs +41 -0
- package/dist/cjs/layout/root-pane.cjs +46 -0
- package/dist/cjs/layout/skeleton/bottom-area.cjs +64 -0
- package/dist/cjs/layout/skeleton/bottom-left-area.cjs +42 -0
- package/dist/cjs/layout/skeleton/bottom-right-area.cjs +38 -0
- package/dist/cjs/layout/skeleton/center-area.cjs +467 -0
- package/dist/cjs/layout/skeleton/index.cjs +24 -0
- package/dist/cjs/layout/skeleton/left-bottom-area.cjs +42 -0
- package/dist/cjs/layout/skeleton/left-top-area.cjs +42 -0
- package/dist/cjs/layout/skeleton/right-bottom-area.cjs +38 -0
- package/dist/cjs/layout/skeleton/right-top-area.cjs +38 -0
- package/dist/cjs/layout/skeleton/skeleton.cjs +66 -0
- package/dist/cjs/layout/skeleton/top-area.cjs +64 -0
- package/dist/cjs/locales/en-US.cjs +34 -0
- package/dist/cjs/locales/index.cjs +39 -0
- package/dist/cjs/locales/zh-CN.cjs +34 -0
- package/dist/cjs/managers/area.cjs +32 -0
- package/dist/cjs/managers/index.cjs +20 -0
- package/dist/cjs/managers/pane.cjs +34 -0
- package/dist/cjs/managers/skeleton.cjs +208 -0
- package/dist/cjs/managers/theme.cjs +37 -0
- package/dist/cjs/managers/widget-container.cjs +96 -0
- package/dist/cjs/managers/widget.cjs +103 -0
- package/dist/cjs/types/config.cjs +16 -0
- package/dist/cjs/types/index.cjs +18 -0
- package/dist/cjs/types/locale.cjs +16 -0
- package/dist/cjs/utils/event-bus.cjs +154 -0
- package/dist/cjs/utils/focus-tracker.cjs +154 -0
- package/dist/cjs/utils/index.cjs +31 -0
- package/dist/cjs/utils/unique-id.cjs +27 -0
- package/dist/cjs/utils/vue.cjs +37 -0
- package/dist/esm/components/center-view/index.mjs +21 -0
- package/dist/esm/components/corner-glow/index.mjs +11 -0
- package/dist/esm/components/dropdown/index.mjs +146 -0
- package/dist/esm/components/icon/index.mjs +39 -0
- package/dist/esm/components/index.mjs +8 -0
- package/dist/esm/components/panel-view/index.mjs +152 -0
- package/dist/esm/components/popup/index.mjs +268 -0
- package/dist/esm/components/title/index.mjs +56 -0
- package/dist/esm/components/tooltip/index.mjs +48 -0
- package/dist/esm/components/widget/index.mjs +84 -0
- package/dist/esm/index.mjs +10 -0
- package/dist/esm/layout/glass-overlay.mjs +11 -0
- package/dist/esm/layout/layered-manager.mjs +15 -0
- package/dist/esm/layout/layplux.mjs +21 -0
- package/dist/esm/layout/root-pane.mjs +26 -0
- package/dist/esm/layout/skeleton/bottom-area.mjs +44 -0
- package/dist/esm/layout/skeleton/bottom-left-area.mjs +22 -0
- package/dist/esm/layout/skeleton/bottom-right-area.mjs +18 -0
- package/dist/esm/layout/skeleton/center-area.mjs +454 -0
- package/dist/esm/layout/skeleton/index.mjs +4 -0
- package/dist/esm/layout/skeleton/left-bottom-area.mjs +22 -0
- package/dist/esm/layout/skeleton/left-top-area.mjs +22 -0
- package/dist/esm/layout/skeleton/right-bottom-area.mjs +18 -0
- package/dist/esm/layout/skeleton/right-top-area.mjs +18 -0
- package/dist/esm/layout/skeleton/skeleton.mjs +46 -0
- package/dist/esm/layout/skeleton/top-area.mjs +44 -0
- package/dist/esm/locales/en-US.mjs +14 -0
- package/dist/esm/locales/index.mjs +19 -0
- package/dist/esm/locales/zh-CN.mjs +14 -0
- package/dist/esm/managers/area.mjs +12 -0
- package/dist/esm/managers/index.mjs +3 -0
- package/dist/esm/managers/pane.mjs +14 -0
- package/dist/esm/managers/skeleton.mjs +192 -0
- package/dist/esm/managers/theme.mjs +17 -0
- package/dist/esm/managers/widget-container.mjs +76 -0
- package/dist/esm/managers/widget.mjs +83 -0
- package/dist/esm/types/config.mjs +0 -0
- package/dist/esm/types/index.mjs +1 -0
- package/dist/esm/types/locale.mjs +0 -0
- package/dist/esm/utils/event-bus.mjs +124 -0
- package/dist/esm/utils/focus-tracker.mjs +135 -0
- package/dist/esm/utils/index.mjs +10 -0
- package/dist/esm/utils/unique-id.mjs +7 -0
- package/dist/esm/utils/vue.mjs +17 -0
- package/dist/style/base/_tokens-dark.scss +51 -0
- package/dist/style/base/_tokens.scss +56 -0
- package/dist/style/components/_bottom-area.scss +30 -0
- package/dist/style/components/_bottom-left-area.scss +8 -0
- package/dist/style/components/_bottom-right-area.scss +8 -0
- package/dist/style/components/_center-area.scss +162 -0
- package/dist/style/components/_corner-glow.scss +17 -0
- package/dist/style/components/_dropdown.scss +91 -0
- package/dist/style/components/_glass-pane.scss +6 -0
- package/dist/style/components/_layered-manager.scss +6 -0
- package/dist/style/components/_left-bottom-area.scss +8 -0
- package/dist/style/components/_left-top-area.scss +9 -0
- package/dist/style/components/_pane-view.scss +79 -0
- package/dist/style/components/_popup.scss +19 -0
- package/dist/style/components/_right-bottom-area.scss +8 -0
- package/dist/style/components/_right-top-area.scss +8 -0
- package/dist/style/components/_root-pane.scss +17 -0
- package/dist/style/components/_skeleton.scss +38 -0
- package/dist/style/components/_title-view.scss +176 -0
- package/dist/style/components/_tooltip.scss +65 -0
- package/dist/style/components/_top-area.scss +25 -0
- package/dist/style/index.css +768 -0
- package/dist/style/layplux.scss +21 -0
- package/dist/types/components/center-view/index.d.ts +16 -0
- package/dist/types/components/center-view/index.d.ts.map +1 -0
- package/dist/types/components/corner-glow/index.d.ts +2 -0
- package/dist/types/components/corner-glow/index.d.ts.map +1 -0
- package/dist/types/components/dropdown/index.d.ts +116 -0
- package/dist/types/components/dropdown/index.d.ts.map +1 -0
- package/dist/types/components/icon/index.d.ts +22 -0
- package/dist/types/components/icon/index.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +9 -0
- package/dist/types/components/index.d.ts.map +1 -0
- package/dist/types/components/panel-view/index.d.ts +22 -0
- package/dist/types/components/panel-view/index.d.ts.map +1 -0
- package/dist/types/components/popup/index.d.ts +99 -0
- package/dist/types/components/popup/index.d.ts.map +1 -0
- package/dist/types/components/title/index.d.ts +57 -0
- package/dist/types/components/title/index.d.ts.map +1 -0
- package/dist/types/components/tooltip/index.d.ts +69 -0
- package/dist/types/components/tooltip/index.d.ts.map +1 -0
- package/dist/types/components/widget/index.d.ts +15 -0
- package/dist/types/components/widget/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/layout/glass-overlay.d.ts +2 -0
- package/dist/types/layout/glass-overlay.d.ts.map +1 -0
- package/dist/types/layout/layered-manager.d.ts +8 -0
- package/dist/types/layout/layered-manager.d.ts.map +1 -0
- package/dist/types/layout/layplux.d.ts +25 -0
- package/dist/types/layout/layplux.d.ts.map +1 -0
- package/dist/types/layout/root-pane.d.ts +8 -0
- package/dist/types/layout/root-pane.d.ts.map +1 -0
- package/dist/types/layout/skeleton/bottom-area.d.ts +9 -0
- package/dist/types/layout/skeleton/bottom-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/bottom-left-area.d.ts +9 -0
- package/dist/types/layout/skeleton/bottom-left-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/bottom-right-area.d.ts +9 -0
- package/dist/types/layout/skeleton/bottom-right-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/center-area.d.ts +11 -0
- package/dist/types/layout/skeleton/center-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/index.d.ts +2 -0
- package/dist/types/layout/skeleton/index.d.ts.map +1 -0
- package/dist/types/layout/skeleton/left-bottom-area.d.ts +9 -0
- package/dist/types/layout/skeleton/left-bottom-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/left-top-area.d.ts +9 -0
- package/dist/types/layout/skeleton/left-top-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/right-bottom-area.d.ts +9 -0
- package/dist/types/layout/skeleton/right-bottom-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/right-top-area.d.ts +9 -0
- package/dist/types/layout/skeleton/right-top-area.d.ts.map +1 -0
- package/dist/types/layout/skeleton/skeleton.d.ts +8 -0
- package/dist/types/layout/skeleton/skeleton.d.ts.map +1 -0
- package/dist/types/layout/skeleton/top-area.d.ts +9 -0
- package/dist/types/layout/skeleton/top-area.d.ts.map +1 -0
- package/dist/types/locales/en-US.d.ts +3 -0
- package/dist/types/locales/en-US.d.ts.map +1 -0
- package/dist/types/locales/index.d.ts +7 -0
- package/dist/types/locales/index.d.ts.map +1 -0
- package/dist/types/locales/zh-CN.d.ts +3 -0
- package/dist/types/locales/zh-CN.d.ts.map +1 -0
- package/dist/types/managers/area.d.ts +10 -0
- package/dist/types/managers/area.d.ts.map +1 -0
- package/dist/types/managers/index.d.ts +5 -0
- package/dist/types/managers/index.d.ts.map +1 -0
- package/dist/types/managers/pane.d.ts +8 -0
- package/dist/types/managers/pane.d.ts.map +1 -0
- package/dist/types/managers/skeleton.d.ts +38 -0
- package/dist/types/managers/skeleton.d.ts.map +1 -0
- package/dist/types/managers/theme.d.ts +2 -0
- package/dist/types/managers/theme.d.ts.map +1 -0
- package/dist/types/managers/widget-container.d.ts +21 -0
- package/dist/types/managers/widget-container.d.ts.map +1 -0
- package/dist/types/managers/widget.d.ts +26 -0
- package/dist/types/managers/widget.d.ts.map +1 -0
- package/dist/types/types/config.d.ts +54 -0
- package/dist/types/types/config.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +2 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/types/locale.d.ts +12 -0
- package/dist/types/types/locale.d.ts.map +1 -0
- package/dist/types/utils/event-bus.d.ts +18 -0
- package/dist/types/utils/event-bus.d.ts.map +1 -0
- package/dist/types/utils/focus-tracker.d.ts +37 -0
- package/dist/types/utils/focus-tracker.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +6 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/unique-id.d.ts +2 -0
- package/dist/types/utils/unique-id.d.ts.map +1 -0
- package/dist/types/utils/vue.d.ts +5 -0
- package/dist/types/utils/vue.d.ts.map +1 -0
- package/dist/umd/index.js +4000 -0
- package/package.json +46 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {} from "./widget-container";
|
|
2
|
+
function useArea(skeleton, name, handle) {
|
|
3
|
+
const container = skeleton.createContainer(name, handle);
|
|
4
|
+
function add(config) {
|
|
5
|
+
const item = container.add(config);
|
|
6
|
+
return item;
|
|
7
|
+
}
|
|
8
|
+
return { add, container };
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
useArea
|
|
12
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
function usePane(defaultViewMode = "DockPinned") {
|
|
3
|
+
const viewMode = ref(defaultViewMode);
|
|
4
|
+
function setViewMode(mode) {
|
|
5
|
+
viewMode.value = mode;
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
viewMode,
|
|
9
|
+
setViewMode
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
usePane
|
|
14
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import { useArea } from "./area";
|
|
3
|
+
import { isWidget, useWidget } from "./widget";
|
|
4
|
+
import { useWidgetContainer } from "./widget-container";
|
|
5
|
+
import {
|
|
6
|
+
FocusTracker,
|
|
7
|
+
createPluginEventBus,
|
|
8
|
+
getBuiltInLocale
|
|
9
|
+
} from "../utils";
|
|
10
|
+
import { injectThemeCSS } from "./theme";
|
|
11
|
+
function useSkeleton() {
|
|
12
|
+
const widgets = [];
|
|
13
|
+
const self = {};
|
|
14
|
+
const containers = /* @__PURE__ */ new Map();
|
|
15
|
+
const focusTracker = new FocusTracker();
|
|
16
|
+
const event = createPluginEventBus("skeleton");
|
|
17
|
+
const locale = ref(getBuiltInLocale("zh-CN"));
|
|
18
|
+
function setLocale(name) {
|
|
19
|
+
locale.value = getBuiltInLocale(name);
|
|
20
|
+
}
|
|
21
|
+
const theme = ref("system");
|
|
22
|
+
const systemDark = ref(
|
|
23
|
+
typeof window !== "undefined" ? window.matchMedia("(prefers-color-scheme: dark)").matches : false
|
|
24
|
+
);
|
|
25
|
+
function resolveTheme() {
|
|
26
|
+
if (theme.value === "system") {
|
|
27
|
+
return systemDark.value ? "dark" : "light";
|
|
28
|
+
}
|
|
29
|
+
return theme.value;
|
|
30
|
+
}
|
|
31
|
+
function isDark() {
|
|
32
|
+
return resolveTheme() === "dark";
|
|
33
|
+
}
|
|
34
|
+
function setTheme(t) {
|
|
35
|
+
theme.value = t;
|
|
36
|
+
}
|
|
37
|
+
const themeName = ref("default");
|
|
38
|
+
function setThemeName(name) {
|
|
39
|
+
themeName.value = name;
|
|
40
|
+
}
|
|
41
|
+
function registerTheme(name, vars) {
|
|
42
|
+
injectThemeCSS(name, vars);
|
|
43
|
+
}
|
|
44
|
+
if (typeof window !== "undefined") {
|
|
45
|
+
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
|
|
46
|
+
systemDark.value = e.matches;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const topArea = useArea(
|
|
50
|
+
{
|
|
51
|
+
createContainer
|
|
52
|
+
},
|
|
53
|
+
"topArea",
|
|
54
|
+
(config, container) => createWidget(config, container)
|
|
55
|
+
);
|
|
56
|
+
const bottomArea = useArea(
|
|
57
|
+
{
|
|
58
|
+
createContainer
|
|
59
|
+
},
|
|
60
|
+
"bottomArea",
|
|
61
|
+
(config, container) => createWidget(config, container)
|
|
62
|
+
);
|
|
63
|
+
const leftTopArea = useArea(
|
|
64
|
+
{
|
|
65
|
+
createContainer
|
|
66
|
+
},
|
|
67
|
+
"leftTopArea",
|
|
68
|
+
(config, container) => createWidget(config, container)
|
|
69
|
+
);
|
|
70
|
+
const leftBottomArea = useArea(
|
|
71
|
+
{
|
|
72
|
+
createContainer
|
|
73
|
+
},
|
|
74
|
+
"leftBottomArea",
|
|
75
|
+
(config, container) => createWidget(config, container)
|
|
76
|
+
);
|
|
77
|
+
const rightTopArea = useArea(
|
|
78
|
+
{ createContainer },
|
|
79
|
+
"rightTopArea",
|
|
80
|
+
(config, container) => createWidget(config, container)
|
|
81
|
+
);
|
|
82
|
+
const rightBottomArea = useArea(
|
|
83
|
+
{ createContainer },
|
|
84
|
+
"rightBottomArea",
|
|
85
|
+
(config, container) => createWidget(config, container)
|
|
86
|
+
);
|
|
87
|
+
const bottomRightArea = useArea(
|
|
88
|
+
{ createContainer },
|
|
89
|
+
"bottomRightArea",
|
|
90
|
+
(config, container) => createWidget(config, container)
|
|
91
|
+
);
|
|
92
|
+
const bottomLeftArea = useArea(
|
|
93
|
+
{
|
|
94
|
+
createContainer
|
|
95
|
+
},
|
|
96
|
+
"bottomLeftArea",
|
|
97
|
+
(config, container) => createWidget(config, container)
|
|
98
|
+
);
|
|
99
|
+
const centerArea = useArea(
|
|
100
|
+
{ createContainer },
|
|
101
|
+
"centerArea",
|
|
102
|
+
(config, container) => createWidget(config, container)
|
|
103
|
+
);
|
|
104
|
+
function createWidget(config, container) {
|
|
105
|
+
if (isWidget(config)) {
|
|
106
|
+
return config;
|
|
107
|
+
}
|
|
108
|
+
const widget = useWidget(config, container, self);
|
|
109
|
+
widgets.push(widget);
|
|
110
|
+
event.emitGlobal("skeleton:widget-added", { widget });
|
|
111
|
+
return widget;
|
|
112
|
+
}
|
|
113
|
+
const focusedId = ref(null);
|
|
114
|
+
function toggleFocus(id) {
|
|
115
|
+
if (focusedId.value === id) {
|
|
116
|
+
blur();
|
|
117
|
+
} else {
|
|
118
|
+
focus(id);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function focus(id) {
|
|
122
|
+
focusedId.value = id;
|
|
123
|
+
event.emitGlobal("skeleton:focus-changed", { focusedId: id });
|
|
124
|
+
}
|
|
125
|
+
function blur() {
|
|
126
|
+
focusedId.value = null;
|
|
127
|
+
event.emitGlobal("skeleton:focus-changed", { focusedId: null });
|
|
128
|
+
}
|
|
129
|
+
function add(config, extraConfig) {
|
|
130
|
+
if (extraConfig) {
|
|
131
|
+
config = { ...config, ...extraConfig };
|
|
132
|
+
}
|
|
133
|
+
const { area } = config;
|
|
134
|
+
if (area === "topArea") {
|
|
135
|
+
topArea.add(config);
|
|
136
|
+
} else if (area === "bottomArea") {
|
|
137
|
+
bottomArea.add(config);
|
|
138
|
+
} else if (area === "leftTopArea") {
|
|
139
|
+
leftTopArea.add(config);
|
|
140
|
+
} else if (area === "leftBottomArea") {
|
|
141
|
+
leftBottomArea.add(config);
|
|
142
|
+
} else if (area === "bottomLeftArea") {
|
|
143
|
+
bottomLeftArea.add(config);
|
|
144
|
+
} else if (area === "rightTopArea") {
|
|
145
|
+
rightTopArea.add(config);
|
|
146
|
+
} else if (area === "rightBottomArea") {
|
|
147
|
+
rightBottomArea.add(config);
|
|
148
|
+
} else if (area === "bottomRightArea") {
|
|
149
|
+
bottomRightArea.add(config);
|
|
150
|
+
} else if (area === "centerArea") {
|
|
151
|
+
centerArea.add(config);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function createContainer(name, handle) {
|
|
155
|
+
const container = useWidgetContainer(handle, self);
|
|
156
|
+
containers.set(name, container);
|
|
157
|
+
return container;
|
|
158
|
+
}
|
|
159
|
+
Object.assign(self, {
|
|
160
|
+
widgets,
|
|
161
|
+
topArea,
|
|
162
|
+
bottomArea,
|
|
163
|
+
leftTopArea,
|
|
164
|
+
leftBottomArea,
|
|
165
|
+
rightTopArea,
|
|
166
|
+
rightBottomArea,
|
|
167
|
+
bottomRightArea,
|
|
168
|
+
bottomLeftArea,
|
|
169
|
+
centerArea,
|
|
170
|
+
focusedId,
|
|
171
|
+
focusTracker,
|
|
172
|
+
event,
|
|
173
|
+
locale,
|
|
174
|
+
setLocale,
|
|
175
|
+
theme,
|
|
176
|
+
resolveTheme,
|
|
177
|
+
isDark,
|
|
178
|
+
setTheme,
|
|
179
|
+
themeName,
|
|
180
|
+
setThemeName,
|
|
181
|
+
registerTheme,
|
|
182
|
+
toggleFocus,
|
|
183
|
+
focus,
|
|
184
|
+
blur,
|
|
185
|
+
add,
|
|
186
|
+
createContainer
|
|
187
|
+
});
|
|
188
|
+
return self;
|
|
189
|
+
}
|
|
190
|
+
export {
|
|
191
|
+
useSkeleton
|
|
192
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function injectThemeCSS(name, vars) {
|
|
2
|
+
const styleId = `layplux-theme-${name}`;
|
|
3
|
+
let styleEl = document.getElementById(styleId);
|
|
4
|
+
if (!styleEl) {
|
|
5
|
+
styleEl = document.createElement("style");
|
|
6
|
+
styleEl.id = styleId;
|
|
7
|
+
document.head.appendChild(styleEl);
|
|
8
|
+
}
|
|
9
|
+
const varLines = Object.entries(vars).map(([key, value]) => ` ${key}: ${value};`).join("\n");
|
|
10
|
+
styleEl.textContent = `.layplux-root[data-theme='${name}'] {
|
|
11
|
+
${varLines}
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
injectThemeCSS
|
|
17
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
function useWidgetContainer(handle, skeleton) {
|
|
3
|
+
const maps = {};
|
|
4
|
+
const items = ref([]);
|
|
5
|
+
const activeId = ref(null);
|
|
6
|
+
const self = {
|
|
7
|
+
items,
|
|
8
|
+
activeId,
|
|
9
|
+
add,
|
|
10
|
+
get,
|
|
11
|
+
getAt,
|
|
12
|
+
indexOf,
|
|
13
|
+
remove,
|
|
14
|
+
activate,
|
|
15
|
+
deactivate,
|
|
16
|
+
toggleActive
|
|
17
|
+
};
|
|
18
|
+
function add(item) {
|
|
19
|
+
const nItem = handle(item, self);
|
|
20
|
+
const origin = get(nItem.name);
|
|
21
|
+
if (origin === nItem) return origin;
|
|
22
|
+
const i = origin ? items.value.indexOf(origin) : -1;
|
|
23
|
+
if (i > -1) {
|
|
24
|
+
items.value.splice(i, 1, nItem);
|
|
25
|
+
} else {
|
|
26
|
+
items.value.push(nItem);
|
|
27
|
+
}
|
|
28
|
+
maps[nItem.name] = nItem;
|
|
29
|
+
return nItem;
|
|
30
|
+
}
|
|
31
|
+
function get(name) {
|
|
32
|
+
return maps[name] || null;
|
|
33
|
+
}
|
|
34
|
+
function getAt(index) {
|
|
35
|
+
return items.value[index] || null;
|
|
36
|
+
}
|
|
37
|
+
function indexOf(item) {
|
|
38
|
+
return items.value.indexOf(item);
|
|
39
|
+
}
|
|
40
|
+
function remove(name) {
|
|
41
|
+
const item = maps[name];
|
|
42
|
+
if (!item) return null;
|
|
43
|
+
const i = items.value.indexOf(item);
|
|
44
|
+
if (i > -1) items.value.splice(i, 1);
|
|
45
|
+
delete maps[name];
|
|
46
|
+
skeleton.event.emitGlobal("skeleton:widget-removed", { name });
|
|
47
|
+
return item;
|
|
48
|
+
}
|
|
49
|
+
function activate(id) {
|
|
50
|
+
if (!maps[id]) return;
|
|
51
|
+
activeId.value = id;
|
|
52
|
+
skeleton.focus(id);
|
|
53
|
+
maps[id].focusable.active();
|
|
54
|
+
skeleton.event.emitGlobal(`widget:${id}:activated`, { widget: maps[id] });
|
|
55
|
+
}
|
|
56
|
+
function deactivate() {
|
|
57
|
+
const current = activeId.value;
|
|
58
|
+
activeId.value = null;
|
|
59
|
+
skeleton.blur();
|
|
60
|
+
if (current && maps[current]) {
|
|
61
|
+
maps[current].focusable.suspense();
|
|
62
|
+
skeleton.event.emitGlobal(`widget:${current}:deactivated`, { widget: maps[current] });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function toggleActive(id) {
|
|
66
|
+
if (activeId.value === id) {
|
|
67
|
+
deactivate();
|
|
68
|
+
} else {
|
|
69
|
+
activate(id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return self;
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
useWidgetContainer
|
|
76
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { computed, h, watch } from "vue";
|
|
2
|
+
import { createContent, uniqueId } from "../utils";
|
|
3
|
+
import { WidgetTitleView, WidgetView } from "../components";
|
|
4
|
+
import { usePane } from "./pane";
|
|
5
|
+
function useWidget(config, container, skeleton) {
|
|
6
|
+
const { name, props, type } = config;
|
|
7
|
+
const active = computed(() => container?.activeId.value === name);
|
|
8
|
+
const focused = computed(() => skeleton?.focusedId.value === name);
|
|
9
|
+
const id = uniqueId(type);
|
|
10
|
+
const align = props?.align ?? "left";
|
|
11
|
+
const pane = usePane();
|
|
12
|
+
const focusable = skeleton.focusTracker.create({
|
|
13
|
+
range: (e) => {
|
|
14
|
+
const target = e.target;
|
|
15
|
+
if (!target) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
const el = document.getElementById(id);
|
|
19
|
+
if (el?.contains(target)) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (target.classList.contains("layplux-resize-handle")) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
},
|
|
27
|
+
onActive: () => {
|
|
28
|
+
widget.container?.activate(name);
|
|
29
|
+
skeleton.event?.emitGlobal(`widget:${name}:focus`, { widget });
|
|
30
|
+
},
|
|
31
|
+
onBlur: () => {
|
|
32
|
+
skeleton.blur();
|
|
33
|
+
skeleton.event?.emitGlobal(`widget:${name}:blur`, { widget });
|
|
34
|
+
if (pane.viewMode.value === "DockUnpinned" || pane.viewMode.value === "Undock") {
|
|
35
|
+
container?.deactivate();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
function renderBody() {
|
|
40
|
+
const { content, contentProps } = config;
|
|
41
|
+
return createContent(content, { ...contentProps, config, event: widget.event });
|
|
42
|
+
}
|
|
43
|
+
function renderContent() {
|
|
44
|
+
return h(WidgetView, { key: id, widget });
|
|
45
|
+
}
|
|
46
|
+
function renderTitle() {
|
|
47
|
+
return h(WidgetTitleView, { key: id, widget });
|
|
48
|
+
}
|
|
49
|
+
const widget = {
|
|
50
|
+
id,
|
|
51
|
+
type,
|
|
52
|
+
isWidget: true,
|
|
53
|
+
name,
|
|
54
|
+
align,
|
|
55
|
+
config,
|
|
56
|
+
active,
|
|
57
|
+
focused,
|
|
58
|
+
container,
|
|
59
|
+
pane,
|
|
60
|
+
focusable,
|
|
61
|
+
event: skeleton.event,
|
|
62
|
+
renderBody,
|
|
63
|
+
renderContent,
|
|
64
|
+
renderTitle
|
|
65
|
+
};
|
|
66
|
+
props?.onInit?.(widget);
|
|
67
|
+
if (skeleton?.event) {
|
|
68
|
+
watch(
|
|
69
|
+
() => pane.viewMode.value,
|
|
70
|
+
(mode) => {
|
|
71
|
+
skeleton.event.emitGlobal(`widget:${name}:view-mode-changed`, { widget, mode });
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return widget;
|
|
76
|
+
}
|
|
77
|
+
function isWidget(obj) {
|
|
78
|
+
return obj && obj.isWidget;
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
isWidget,
|
|
82
|
+
useWidget
|
|
83
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./config";
|
|
File without changes
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import EventEmitter2, {} from "eventemitter2";
|
|
2
|
+
const globalEmitter = new EventEmitter2({
|
|
3
|
+
wildcard: true,
|
|
4
|
+
// 开启通配符
|
|
5
|
+
delimiter: ":",
|
|
6
|
+
// 命名空间分隔符,与原版 createModuleEventBus 保持一致
|
|
7
|
+
newListener: false,
|
|
8
|
+
// 不触发 newListener 事件,减少不必要开销
|
|
9
|
+
maxListeners: 200,
|
|
10
|
+
// 对标原版 createModuleEventBus(pluginName, 200) 的容量参数
|
|
11
|
+
verboseMemoryLeak: true
|
|
12
|
+
// 超出 maxListeners 时打印详细的内存泄漏警告
|
|
13
|
+
});
|
|
14
|
+
function createPluginEventBus(namespace) {
|
|
15
|
+
const privateEmitter = new EventEmitter2({
|
|
16
|
+
wildcard: true,
|
|
17
|
+
delimiter: ":",
|
|
18
|
+
newListener: false,
|
|
19
|
+
maxListeners: 200,
|
|
20
|
+
verboseMemoryLeak: true
|
|
21
|
+
});
|
|
22
|
+
const prefixed = (event) => `${namespace}:${event}`;
|
|
23
|
+
return {
|
|
24
|
+
// ── 私有事件(自动加 namespace 前缀)──────────────────────────
|
|
25
|
+
emit(event, payload) {
|
|
26
|
+
privateEmitter.emit(prefixed(event), payload);
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* 订阅私有事件,返回取消订阅函数。
|
|
30
|
+
* 利用 EventEmitter2 的 Listener 对象的 .off() 方法,
|
|
31
|
+
* 无需调用方保存 handler 引用。
|
|
32
|
+
*/
|
|
33
|
+
on(event, handler) {
|
|
34
|
+
const listener = privateEmitter.on(
|
|
35
|
+
prefixed(event),
|
|
36
|
+
handler,
|
|
37
|
+
{ objectify: true }
|
|
38
|
+
// 返回 Listener 对象而非 emitter 本身
|
|
39
|
+
);
|
|
40
|
+
return () => listener.off();
|
|
41
|
+
},
|
|
42
|
+
off(event, handler) {
|
|
43
|
+
privateEmitter.off(prefixed(event), handler);
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* 订阅一次后自动取消
|
|
47
|
+
*/
|
|
48
|
+
once(event, handler) {
|
|
49
|
+
const listener = privateEmitter.once(prefixed(event), handler, {
|
|
50
|
+
objectify: true
|
|
51
|
+
});
|
|
52
|
+
return () => listener.off();
|
|
53
|
+
},
|
|
54
|
+
// ── 全局事件(跨插件通信,走 globalEmitter)────────────────────
|
|
55
|
+
emitGlobal(event, payload) {
|
|
56
|
+
globalEmitter.emit(event, payload);
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* 订阅全局事件,支持通配符:
|
|
60
|
+
* onGlobal('layout:*', fn) → 订阅所有 layout 事件
|
|
61
|
+
* onGlobal('layout:panel-**', fn)→ 订阅所有 layout:panel 开头的事件
|
|
62
|
+
* onGlobal('**', fn) → 订阅所有全局事件(慎用)
|
|
63
|
+
*/
|
|
64
|
+
onGlobal(event, handler) {
|
|
65
|
+
const listener = globalEmitter.on(event, handler, {
|
|
66
|
+
objectify: true
|
|
67
|
+
});
|
|
68
|
+
return () => listener.off();
|
|
69
|
+
},
|
|
70
|
+
offGlobal(event, handler) {
|
|
71
|
+
globalEmitter.off(event, handler);
|
|
72
|
+
},
|
|
73
|
+
onGlobalOnce(event, handler) {
|
|
74
|
+
const listener = globalEmitter.once(event, handler, {
|
|
75
|
+
objectify: true
|
|
76
|
+
});
|
|
77
|
+
return () => listener.off();
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* 等待某个全局事件触发,返回 Promise(EventEmitter2 原生支持)
|
|
81
|
+
* 适合插件 setup 中等待其他插件就绪的场景:
|
|
82
|
+
* await ctx.event.waitForGlobal('explorer:ready', 5000)
|
|
83
|
+
*/
|
|
84
|
+
waitForGlobal(event, timeoutMs) {
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
const timer = timeoutMs ? setTimeout(() => {
|
|
87
|
+
globalEmitter.off(event, onEvent);
|
|
88
|
+
reject(new Error(`[EventBus] Timeout waiting for "${event}" after ${timeoutMs}ms`));
|
|
89
|
+
}, timeoutMs) : null;
|
|
90
|
+
function onEvent(payload) {
|
|
91
|
+
if (timer) clearTimeout(timer);
|
|
92
|
+
resolve(payload);
|
|
93
|
+
}
|
|
94
|
+
globalEmitter.once(event, onEvent);
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
// ── 清理(插件 destroy 时调用)─────────────────────────────────
|
|
98
|
+
/**
|
|
99
|
+
* 移除该插件私有 emitter 上的所有监听器。
|
|
100
|
+
* 全局监听器需要单独 offGlobal(插件应在 teardown 中手动清理)。
|
|
101
|
+
*/
|
|
102
|
+
removeAllListeners() {
|
|
103
|
+
privateEmitter.removeAllListeners();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function emitSystemEvent(event, payload) {
|
|
108
|
+
globalEmitter.emit(event, payload);
|
|
109
|
+
}
|
|
110
|
+
function onSystemEvent(event, handler) {
|
|
111
|
+
const listener = globalEmitter.on(event, handler, {
|
|
112
|
+
objectify: true
|
|
113
|
+
});
|
|
114
|
+
return () => listener.off();
|
|
115
|
+
}
|
|
116
|
+
function getGlobalEmitter() {
|
|
117
|
+
return globalEmitter;
|
|
118
|
+
}
|
|
119
|
+
export {
|
|
120
|
+
createPluginEventBus,
|
|
121
|
+
emitSystemEvent,
|
|
122
|
+
getGlobalEmitter,
|
|
123
|
+
onSystemEvent
|
|
124
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
class FocusTracker {
|
|
5
|
+
constructor() {
|
|
6
|
+
/** 焦点栈,栈顶为当前聚焦项 */
|
|
7
|
+
__publicField(this, "actives", []);
|
|
8
|
+
/** modal 弹层注册表,用于检查是否有 modal 正在打开 */
|
|
9
|
+
__publicField(this, "modals", []);
|
|
10
|
+
}
|
|
11
|
+
/** 当前焦点栈顶 */
|
|
12
|
+
get first() {
|
|
13
|
+
return this.actives[0];
|
|
14
|
+
}
|
|
15
|
+
/** 注册一个 modal 弹层,用于 execSave 等时判断是否跳过 */
|
|
16
|
+
addModal(checkDown, checkOpen) {
|
|
17
|
+
this.modals.push({ checkDown, checkOpen });
|
|
18
|
+
}
|
|
19
|
+
/** 是否有 modal 弹层正在打开 */
|
|
20
|
+
checkModalOpen() {
|
|
21
|
+
return this.modals.some((item) => item.checkOpen());
|
|
22
|
+
}
|
|
23
|
+
/** 触发保存操作,有 modal 时跳过 */
|
|
24
|
+
execSave() {
|
|
25
|
+
if (this.checkModalOpen()) return;
|
|
26
|
+
if (this.first) this.first.internalTriggerSave();
|
|
27
|
+
}
|
|
28
|
+
/** 触发 ESC — 挂起栈顶并调用其 onEsc */
|
|
29
|
+
execEsc() {
|
|
30
|
+
const { first } = this;
|
|
31
|
+
if (first) {
|
|
32
|
+
this.internalSuspenseItem(first);
|
|
33
|
+
first.internalTriggerEsc();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 挂载全局点击监听
|
|
38
|
+
* 点击 document 时,如果点击目标不在 first 的 range 内,则挂起 first 并触发 blur
|
|
39
|
+
* @returns 卸载函数
|
|
40
|
+
*/
|
|
41
|
+
mount(win) {
|
|
42
|
+
const checkDown = (e) => {
|
|
43
|
+
const { first } = this;
|
|
44
|
+
if (first && !first.internalCheckInRange(e)) {
|
|
45
|
+
this.internalSuspenseItem(first);
|
|
46
|
+
first.internalTriggerBlur();
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
win.document.addEventListener("click", checkDown, true);
|
|
50
|
+
return () => win.document.removeEventListener("click", checkDown, true);
|
|
51
|
+
}
|
|
52
|
+
/** 创建一个 Focusable 实例并绑定到当前 tracker */
|
|
53
|
+
create(config) {
|
|
54
|
+
return new Focusable(this, config);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 激活一个 Focusable — 将其推到栈顶
|
|
58
|
+
* 如果栈顶已有其他 Focusable 且新项不是 modal,则先触发旧栈顶的 blur
|
|
59
|
+
*/
|
|
60
|
+
internalActiveItem(item) {
|
|
61
|
+
const first = this.actives[0];
|
|
62
|
+
if (first === item) return;
|
|
63
|
+
const i = this.actives.indexOf(item);
|
|
64
|
+
if (i > -1) this.actives.splice(i, 1);
|
|
65
|
+
this.actives.unshift(item);
|
|
66
|
+
if (!item.isModal && first) first.internalTriggerBlur();
|
|
67
|
+
item.internalTriggerActive();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 挂起一个 Focusable — 将其从栈中移除
|
|
71
|
+
* 移除后如果还有剩余项,激活新的栈顶
|
|
72
|
+
*/
|
|
73
|
+
internalSuspenseItem(item) {
|
|
74
|
+
const i = this.actives.indexOf(item);
|
|
75
|
+
if (i > -1) {
|
|
76
|
+
this.actives.splice(i, 1);
|
|
77
|
+
this.first?.internalTriggerActive();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
class Focusable {
|
|
82
|
+
constructor(tracker, config) {
|
|
83
|
+
this.tracker = tracker;
|
|
84
|
+
this.config = config;
|
|
85
|
+
__publicField(this, "isModal");
|
|
86
|
+
this.isModal = config.modal ?? false;
|
|
87
|
+
}
|
|
88
|
+
/** 激活当前 Focusable,推入焦点栈顶 */
|
|
89
|
+
active() {
|
|
90
|
+
this.tracker.internalActiveItem(this);
|
|
91
|
+
}
|
|
92
|
+
/** 挂起当前 Focusable,从焦点栈移除 */
|
|
93
|
+
suspense() {
|
|
94
|
+
this.tracker.internalSuspenseItem(this);
|
|
95
|
+
}
|
|
96
|
+
/** 销毁当前 Focusable(同 suspense,语义化别名) */
|
|
97
|
+
purge() {
|
|
98
|
+
this.tracker.internalSuspenseItem(this);
|
|
99
|
+
}
|
|
100
|
+
/** 挂载后把真实 DOM 注入,使 range 的 contains 判断生效 */
|
|
101
|
+
setRange(range) {
|
|
102
|
+
this.config.range = range;
|
|
103
|
+
}
|
|
104
|
+
/** 检查点击事件是否在 range 范围内 */
|
|
105
|
+
internalCheckInRange(e) {
|
|
106
|
+
const { range } = this.config;
|
|
107
|
+
if (!range) return false;
|
|
108
|
+
if (typeof range === "function") return range(e);
|
|
109
|
+
return range.contains(e.target);
|
|
110
|
+
}
|
|
111
|
+
/** 触发失焦回调 */
|
|
112
|
+
internalTriggerBlur() {
|
|
113
|
+
this.config.onBlur?.();
|
|
114
|
+
}
|
|
115
|
+
/** 触发保存回调,返回 true 表示已处理 */
|
|
116
|
+
internalTriggerSave() {
|
|
117
|
+
if (this.config.onSave) {
|
|
118
|
+
this.config.onSave();
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
/** 触发 ESC 回调 */
|
|
124
|
+
internalTriggerEsc() {
|
|
125
|
+
this.config.onEsc?.();
|
|
126
|
+
}
|
|
127
|
+
/** 触发激活回调 */
|
|
128
|
+
internalTriggerActive() {
|
|
129
|
+
this.config.onActive?.();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
FocusTracker,
|
|
134
|
+
Focusable
|
|
135
|
+
};
|