@netless/forge-slide 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.mjs +31 -0
- package/dist/FoorerView.d.ts +23 -0
- package/dist/FoorerView.d.ts.map +1 -0
- package/dist/ForgeSlidePermession.d.ts +80 -0
- package/dist/ForgeSlidePermession.d.ts.map +1 -0
- package/dist/SiderBarView.d.ts +17 -0
- package/dist/SiderBarView.d.ts.map +1 -0
- package/dist/Slide.d.ts +33 -0
- package/dist/Slide.d.ts.map +1 -0
- package/dist/SlideApplication.d.ts +36 -0
- package/dist/SlideApplication.d.ts.map +1 -0
- package/dist/icons.d.ts +8 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +67391 -0
- package/dist/index.esm.js.map +7 -0
- package/dist/index.js +67395 -0
- package/dist/index.js.map +7 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +25 -0
- package/src/FoorerView.ts +109 -0
- package/src/ForgeSlidePermession.ts +159 -0
- package/src/SiderBarView.ts +91 -0
- package/src/Slide.ts +39 -0
- package/src/SlideApplication.ts +313 -0
- package/src/icons.ts +26 -0
- package/src/index.ts +5 -0
- package/src/utils.ts +62 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {Whiteboard, WhiteboardApplication, WhiteboardPermissionFlag} from "@netless/forge-whiteboard";
|
|
2
|
+
import {ISlideConfig, Slide, SLIDE_EVENTS} from "@netless/slide";
|
|
3
|
+
import {AbstractApplication} from "@netless/forge-room";
|
|
4
|
+
import {SlideForge} from "./Slide";
|
|
5
|
+
import {ForgeSlidePermissionFlag, ForgeSlidePermissions} from "./ForgeSlidePermession";
|
|
6
|
+
import {FooterView} from "./FoorerView";
|
|
7
|
+
import * as Y from "yjs";
|
|
8
|
+
import {SideBarView} from "./SiderBarView";
|
|
9
|
+
import {deepEqual, delay} from "./utils";
|
|
10
|
+
|
|
11
|
+
export interface SlideApplicationOption {
|
|
12
|
+
prefix: string;
|
|
13
|
+
taskId: string;
|
|
14
|
+
options?: ISlideConfig;
|
|
15
|
+
/**
|
|
16
|
+
* 从指定的白板 id 继承白板权限以及工具栏配置
|
|
17
|
+
*/
|
|
18
|
+
inheritWhiteboardId?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const Slide_APP_NAME = "forge_slide";
|
|
22
|
+
|
|
23
|
+
export class SlideApplication extends AbstractApplication<SlideApplicationOption, SlideForge> {
|
|
24
|
+
|
|
25
|
+
static applicationName = Slide_APP_NAME;
|
|
26
|
+
|
|
27
|
+
public readonly name: string = Slide_APP_NAME;
|
|
28
|
+
|
|
29
|
+
private whiteboardApp!: WhiteboardApplication;
|
|
30
|
+
private whiteboard!: Whiteboard;
|
|
31
|
+
private rootView: HTMLDivElement = document.createElement("div");
|
|
32
|
+
private contentContainer: HTMLDivElement = document.createElement("div");
|
|
33
|
+
private whiteboardContainer: HTMLDivElement = document.createElement("div");
|
|
34
|
+
private slideContainer: HTMLDivElement = document.createElement("div");
|
|
35
|
+
private permissions!: ForgeSlidePermissions;
|
|
36
|
+
private footer: FooterView;
|
|
37
|
+
private sideBar: SideBarView;
|
|
38
|
+
private slide!: Slide;
|
|
39
|
+
private currentSlideIndex: number = 0;
|
|
40
|
+
|
|
41
|
+
constructor() {
|
|
42
|
+
super();
|
|
43
|
+
this.rootView.setAttribute("data-forge-app", Slide_APP_NAME);
|
|
44
|
+
this.rootView.style.background = "#f0f0f0f0";
|
|
45
|
+
this.rootView.style.overflow = "hidden";
|
|
46
|
+
|
|
47
|
+
this.contentContainer.style.width = "100%";
|
|
48
|
+
this.contentContainer.style.height = "100%";
|
|
49
|
+
this.contentContainer.style.display = "flex";
|
|
50
|
+
this.contentContainer.style.flexDirection = "column";
|
|
51
|
+
|
|
52
|
+
this.slideContainer.style.width = "100%";
|
|
53
|
+
this.slideContainer.style.height = "100%";
|
|
54
|
+
// this.slideContainer.style.height = "calc(100% - 24px)";
|
|
55
|
+
|
|
56
|
+
this.footer = new FooterView();
|
|
57
|
+
this.sideBar = new SideBarView();
|
|
58
|
+
this.sideBar.on("pageChange", index => {
|
|
59
|
+
this.slide.renderSlide(index);
|
|
60
|
+
});
|
|
61
|
+
this.footer.on("prevStep", () => {
|
|
62
|
+
if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changeStep)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (this.slide.mainSeqStep > 0 || this.slide.mainSeqState !== "idle") {
|
|
66
|
+
this.slide.prevStep();
|
|
67
|
+
} else if (this.currentSlideIndex > 1){
|
|
68
|
+
if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.slide.renderSlide(this.currentSlideIndex - 1)
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
this.footer.on("nextStep", () => {
|
|
75
|
+
if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changeStep)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (this.slide.mainSeqStep < this.slide.mainSeqLength) {
|
|
79
|
+
this.slide.nextStep()
|
|
80
|
+
} else {
|
|
81
|
+
if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.slide.renderSlide(this.currentSlideIndex + 1)
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
this.footer.on("prevPage", () => {
|
|
88
|
+
if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (this.currentSlideIndex > 1) {
|
|
92
|
+
this.slide.renderSlide(this.currentSlideIndex - 1);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
this.footer.on("nextPage", () => {
|
|
96
|
+
if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (this.currentSlideIndex < this.slide.slideCount) {
|
|
100
|
+
this.slide.renderSlide(this.currentSlideIndex + 1);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.footer.on("sideBarToggle", () => {
|
|
105
|
+
if (!this.permissions.hasPermission(ForgeSlidePermissionFlag.changePage)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (this.sideBar.root.style.left === "0px") {
|
|
109
|
+
this.sideBar.root.style.left = "-240px";
|
|
110
|
+
} else {
|
|
111
|
+
this.sideBar.root.style.left = "0px";
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
this.rootView.appendChild(this.contentContainer);
|
|
116
|
+
|
|
117
|
+
this.emitter.on("renderStart", pageIndex => {
|
|
118
|
+
this.footer.prevPageState(pageIndex !== 0);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const that = this;
|
|
122
|
+
Object.defineProperty(this.emitter, "view", {
|
|
123
|
+
get(): any {
|
|
124
|
+
return that.rootView;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
Object.defineProperty(this.emitter, "permissions", {
|
|
128
|
+
get(): any {
|
|
129
|
+
return that.permissions;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
Object.defineProperty(this.emitter, "pageIndex", {
|
|
133
|
+
get(): any {
|
|
134
|
+
return that.currentSlideIndex;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
Object.defineProperty(this.emitter, "goto", {
|
|
138
|
+
get(): any {
|
|
139
|
+
return (index: number) => {
|
|
140
|
+
if (index > 0 && index < this.slide.slideCount) {
|
|
141
|
+
this.slide.renderSlide(index);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
emitter: SlideForge = new SlideForge();
|
|
149
|
+
|
|
150
|
+
private applySlideState = async (slideState: any, lastDispatch: any) => {
|
|
151
|
+
// console.log('%cstate', 'color: blue; font-size: 20px;');
|
|
152
|
+
// console.log(slideStateFromServer);
|
|
153
|
+
// console.log('%cevent', 'color: blue; font-size: 20px;');
|
|
154
|
+
// console.log(dispatchFromServer);
|
|
155
|
+
if (this.slide.slideState.currentSlideIndex < 0) {
|
|
156
|
+
this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
console.log('%cisEqual', 'color: blue; font-size: 20px;', deepEqual(this.slide.slideState, slideState));
|
|
160
|
+
if (this.slide.slideState.currentSlideIndex > 0 && deepEqual(this.slide.slideState, slideState)) {
|
|
161
|
+
this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
|
|
162
|
+
} else {
|
|
163
|
+
await this.slide.setSlideState(slideState);
|
|
164
|
+
await delay(200);
|
|
165
|
+
this.slide.emit(SLIDE_EVENTS.syncReceive, lastDispatch);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private onSlideEventHandler = async (event: Y.YMapEvent<any>) => {
|
|
170
|
+
for (const [key, value] of event.changes.keys.entries()) {
|
|
171
|
+
if (key === "syncSlide") {
|
|
172
|
+
if (value.action === "add" || value.action === "update") {
|
|
173
|
+
const { slideState: slideStateFromServer, dispatch: dispatchFromServer } = this.getMap(this.name).get("syncSlide");
|
|
174
|
+
this.applySlideState(slideStateFromServer, dispatchFromServer);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public async initialize(option: SlideApplicationOption): Promise<void> {
|
|
181
|
+
const whiteboardApp = new WhiteboardApplication();
|
|
182
|
+
// @ts-ignore
|
|
183
|
+
whiteboardApp.roomDoc = this.roomDoc;
|
|
184
|
+
// @ts-ignore
|
|
185
|
+
whiteboardApp.appId = `${option.taskId}_wb`;
|
|
186
|
+
// @ts-ignore
|
|
187
|
+
whiteboardApp.userId = this.userId;
|
|
188
|
+
// @ts-ignore
|
|
189
|
+
whiteboardApp.userManager = this.userManager;
|
|
190
|
+
// @ts-ignore
|
|
191
|
+
whiteboardApp.applicationManager = this.applicationManager;
|
|
192
|
+
|
|
193
|
+
const json = await fetch(`${option.prefix}/${option.taskId}/jsonOutput/slide-1.json`).then(res => res.json())
|
|
194
|
+
|
|
195
|
+
await whiteboardApp.initialize({
|
|
196
|
+
width: json.width,
|
|
197
|
+
height: json.height,
|
|
198
|
+
});
|
|
199
|
+
this.whiteboardApp = whiteboardApp;
|
|
200
|
+
this.whiteboard = whiteboardApp.emitter;
|
|
201
|
+
this.whiteboard.enableCameraByMouse = false;
|
|
202
|
+
this.whiteboard.enableCameraByTouch = false;
|
|
203
|
+
this.whiteboard.view.style.width = "100%";
|
|
204
|
+
this.whiteboard.view.style.height = "100%";
|
|
205
|
+
this.whiteboard.view.style.position = "absolute";
|
|
206
|
+
this.whiteboard.view.style.top = "0";
|
|
207
|
+
this.whiteboard.view.style.left = "0";
|
|
208
|
+
this.whiteboard.view.style.zIndex = "4";
|
|
209
|
+
this.whiteboard.permissions.addPermission(WhiteboardPermissionFlag.all);
|
|
210
|
+
this.whiteboard.setCanvasBackgroundColor("#f0f0f000");
|
|
211
|
+
this.whiteboardContainer.style.position = "relative";
|
|
212
|
+
this.whiteboardContainer.style.flex = "0 0 auto";
|
|
213
|
+
this.whiteboardContainer.style.height = "calc(100% - 24px)";
|
|
214
|
+
this.whiteboardContainer.appendChild(this.whiteboard.view);
|
|
215
|
+
this.whiteboardContainer.appendChild(this.slideContainer);
|
|
216
|
+
|
|
217
|
+
this.contentContainer.appendChild(this.whiteboardContainer);
|
|
218
|
+
this.contentContainer.appendChild(this.footer.root);
|
|
219
|
+
this.contentContainer.appendChild(this.sideBar.root);
|
|
220
|
+
|
|
221
|
+
if (option.inheritWhiteboardId) {
|
|
222
|
+
whiteboardApp.linkToWhiteboard(option.inheritWhiteboardId);
|
|
223
|
+
console.log("inheritWhiteboardId", option.inheritWhiteboardId);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
this.whiteboard.setViewModeToMain();
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
this.slideContainer.setAttribute("builder", "slide-builder")
|
|
230
|
+
this.slide = new Slide({
|
|
231
|
+
...option.options,
|
|
232
|
+
interactive: true,
|
|
233
|
+
anchor: this.slideContainer,
|
|
234
|
+
mode: "interactive",
|
|
235
|
+
// logger: {
|
|
236
|
+
// info: console.log,
|
|
237
|
+
// warn: console.warn,
|
|
238
|
+
// error: console.error,
|
|
239
|
+
// },
|
|
240
|
+
})
|
|
241
|
+
this.slide.setResource(option.taskId, option.prefix);
|
|
242
|
+
this.sideBar.initialize(json.slideCount, option);
|
|
243
|
+
|
|
244
|
+
this.slide.on("syncDispatch", event => {
|
|
245
|
+
this.getMap(this.name).set("syncSlide", {
|
|
246
|
+
slideState: this.slide.slideState,
|
|
247
|
+
dispatch: event,
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
this.slide.on("renderStart", (slideIndex) => {
|
|
252
|
+
this.whiteboardApp.emitter.view.style.opacity = "0";
|
|
253
|
+
this.whiteboardApp.emitter.addPage(`${slideIndex}`);
|
|
254
|
+
this.whiteboardApp.emitter.gotoPage(`${slideIndex}`);
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
this.slide.on("renderEnd", (slideIndex) => {
|
|
258
|
+
this.currentSlideIndex = slideIndex;
|
|
259
|
+
this.whiteboardApp.emitter.view.style.opacity = "1";
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
this.slide.on("stateChange", (state) => {
|
|
263
|
+
this.getMap(this.name).set("slideState", state)
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
this.getMap(this.name).observe(this.onSlideEventHandler);
|
|
267
|
+
|
|
268
|
+
(window as any).slide = this.slide;
|
|
269
|
+
(window as any).slideWhiteboard = this.whiteboardApp;
|
|
270
|
+
|
|
271
|
+
const syncSlide = this.getMap(this.name).get("slideState");
|
|
272
|
+
if (syncSlide && syncSlide.taskId === option.taskId) {
|
|
273
|
+
await this.slide.setSlideState(syncSlide)
|
|
274
|
+
} else {
|
|
275
|
+
this.slide.renderSlide(1);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
this.permissions = new ForgeSlidePermissions(this.userManager, (userId: string) => {
|
|
279
|
+
return this.userMap(userId);
|
|
280
|
+
});
|
|
281
|
+
this.permissions.on("change", (userId, flags, value) => {
|
|
282
|
+
console.log(userId, flags, value);
|
|
283
|
+
if (this.userId === userId) {
|
|
284
|
+
if (flags.includes(ForgeSlidePermissionFlag.clickAnim)) {
|
|
285
|
+
this.slideContainer.style.pointerEvents = "auto";
|
|
286
|
+
} else {
|
|
287
|
+
this.slideContainer.style.pointerEvents = "none";
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
this.permissions.addPermission(ForgeSlidePermissionFlag.all);
|
|
292
|
+
this.whiteboardApp.disableViewModel();
|
|
293
|
+
// @ts-ignore
|
|
294
|
+
window.__forge_slide = this;
|
|
295
|
+
// @ts-ignore
|
|
296
|
+
window.slidePermissions = this.permissions;
|
|
297
|
+
return Promise.resolve(undefined);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private userMap(userId: string): Y.Map<any> {
|
|
301
|
+
return this.getMap(`user/${userId}`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
public async dispose(): Promise<void> {
|
|
305
|
+
await this.whiteboardApp.dispose();
|
|
306
|
+
this.rootView.parentElement?.removeChild(this.rootView);
|
|
307
|
+
this.slide.destroy();
|
|
308
|
+
this.sideBar.dispose();
|
|
309
|
+
this.getMap(this.name).unobserve(this.onSlideEventHandler)
|
|
310
|
+
return Promise.resolve(undefined);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
}
|
package/src/icons.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
const prevPage = (color: string) => `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none">
|
|
3
|
+
<rect opacity="0.01" width="24" height="24" fill="white"/>
|
|
4
|
+
<path d="M15 4L15.4419 3.55806C15.3247 3.44085 15.1658 3.375 15 3.375V4ZM19 8H19.625C19.625 7.83424 19.5592 7.67527 19.4419 7.55806L19 8ZM6 4.625H15V3.375H6V4.625ZM14.5581 4.44194L18.5581 8.44194L19.4419 7.55806L15.4419 3.55806L14.5581 4.44194ZM18.375 8V13H19.625V8H18.375ZM18.375 13V19H19.625V13H18.375ZM18 19.375H12V20.625H18V19.375ZM5.625 13V5H4.375V13H5.625ZM18.375 19C18.375 19.2071 18.2071 19.375 18 19.375V20.625C18.8975 20.625 19.625 19.8975 19.625 19H18.375ZM6 3.375C5.10254 3.375 4.375 4.10254 4.375 5H5.625C5.625 4.79289 5.79289 4.625 6 4.625V3.375Z" fill="${color}" />
|
|
5
|
+
<path d="M14.375 4V7H15.625V4H14.375ZM16 8.625H19V7.375H16V8.625ZM14.375 7C14.375 7.89746 15.1025 8.625 16 8.625V7.375C15.7929 7.375 15.625 7.20711 15.625 7H14.375Z" fill="${color}"/>
|
|
6
|
+
<path d="M13 16H5" stroke="${color}" stroke-width="1.25" stroke-linejoin="round"/>
|
|
7
|
+
<path d="M9 12L7 14L5 16L7 18L9 20" stroke="${color}" stroke-width="1.25" stroke-linejoin="round"/>
|
|
8
|
+
</svg>`
|
|
9
|
+
|
|
10
|
+
const nextPage = (color: string) => `
|
|
11
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none">
|
|
12
|
+
<rect opacity="0.01" width="24" height="24" fill="white"/>
|
|
13
|
+
<path d="M15 4L15.4419 3.55806C15.3247 3.44085 15.1658 3.375 15 3.375V4ZM19 8H19.625C19.625 7.83424 19.5592 7.67527 19.4419 7.55806L19 8ZM6 4.625H15V3.375H6V4.625ZM14.5581 4.44194L18.5581 8.44194L19.4419 7.55806L15.4419 3.55806L14.5581 4.44194ZM5.625 19V5H4.375V19H5.625ZM12 19.375H6V20.625H12V19.375ZM18.375 8V13H19.625V8H18.375ZM4.375 19C4.375 19.8975 5.10254 20.625 6 20.625V19.375C5.79289 19.375 5.625 19.2071 5.625 19H4.375ZM6 3.375C5.10254 3.375 4.375 4.10254 4.375 5H5.625C5.625 4.79289 5.79289 4.625 6 4.625V3.375Z" fill="${color}"/>
|
|
14
|
+
<path d="M14.375 4V7H15.625V4H14.375ZM16 8.625H19V7.375H16V8.625ZM14.375 7C14.375 7.89746 15.1025 8.625 16 8.625V7.375C15.7929 7.375 15.625 7.20711 15.625 7H14.375Z" fill="${color}"/>
|
|
15
|
+
<path d="M11 16H19" stroke="${color}" stroke-width="1.25" stroke-linejoin="round"/>
|
|
16
|
+
<path d="M15 12L17 14L19 16L17 18L15 20" stroke="${color}" stroke-width="1.25" stroke-linejoin="round"/>
|
|
17
|
+
</svg>`
|
|
18
|
+
const prevStep = (color: string) => `<svg style="width:100%;height:100%;padding:2px;box-sizing:border-box;" viewBox="0 0 12.3926 16.9629"><g><rect height="16.9629" opacity="0" width="12.3926" x="0" y="0"/><path d="M0 8.47656C0 8.7207 0.0878906 8.93555 0.273438 9.12109L8.01758 16.6895C8.18359 16.8652 8.39844 16.9531 8.65234 16.9531C9.16016 16.9531 9.55078 16.5723 9.55078 16.0645C9.55078 15.8105 9.44336 15.5957 9.28711 15.4297L2.17773 8.47656L9.28711 1.52344C9.44336 1.35742 9.55078 1.13281 9.55078 0.888672C9.55078 0.380859 9.16016 0 8.65234 0C8.39844 0 8.18359 0.0878906 8.01758 0.253906L0.273438 7.83203C0.0878906 8.00781 0 8.23242 0 8.47656Z" fill="${color}"/></g></svg>`;
|
|
19
|
+
const nextStep = (color: string) => `<svg style="width:100%;height:100%;padding:2px;box-sizing:border-box;" viewBox="0 0 11.6895 16.9629"><g><rect height="16.9629" opacity="0" width="11.6895" x="0" y="0"/><path d="M11.6895 8.47656C11.6895 8.23242 11.5918 8.00781 11.4062 7.83203L3.67188 0.253906C3.49609 0.0878906 3.28125 0 3.02734 0C2.5293 0 2.13867 0.380859 2.13867 0.888672C2.13867 1.13281 2.23633 1.35742 2.39258 1.52344L9.50195 8.47656L2.39258 15.4297C2.23633 15.5957 2.13867 15.8105 2.13867 16.0645C2.13867 16.5723 2.5293 16.9531 3.02734 16.9531C3.28125 16.9531 3.49609 16.8652 3.67188 16.6895L11.4062 9.12109C11.5918 8.93555 11.6895 8.7207 11.6895 8.47656Z" fill="${color}"/></g></svg>`;
|
|
20
|
+
const sideBar = (color: string) => `<svg style="width:100%;height:100%;padding:2px;box-sizing:border-box;" viewBox="0 0 23.3887 17.998"><g><rect height="17.998" opacity="0" width="23.3887" x="0" y="0"/><path d="M3.06641 17.998L19.9609 17.998C22.0117 17.998 23.0273 16.9824 23.0273 14.9707L23.0273 3.04688C23.0273 1.03516 22.0117 0.0195312 19.9609 0.0195312L3.06641 0.0195312C1.02539 0.0195312 0 1.02539 0 3.04688L0 14.9707C0 16.9922 1.02539 17.998 3.06641 17.998ZM3.08594 16.4258C2.10938 16.4258 1.57227 15.9082 1.57227 14.8926L1.57227 3.125C1.57227 2.10938 2.10938 1.5918 3.08594 1.5918L19.9414 1.5918C20.9082 1.5918 21.4551 2.10938 21.4551 3.125L21.4551 14.8926C21.4551 15.9082 20.9082 16.4258 19.9414 16.4258ZM7.44141 16.7285L8.97461 16.7285L8.97461 1.29883L7.44141 1.29883ZM5.56641 5.21484C5.85938 5.21484 6.12305 4.95117 6.12305 4.66797C6.12305 4.375 5.85938 4.12109 5.56641 4.12109L3.4668 4.12109C3.17383 4.12109 2.91992 4.375 2.91992 4.66797C2.91992 4.95117 3.17383 5.21484 3.4668 5.21484ZM5.56641 7.74414C5.85938 7.74414 6.12305 7.48047 6.12305 7.1875C6.12305 6.89453 5.85938 6.65039 5.56641 6.65039L3.4668 6.65039C3.17383 6.65039 2.91992 6.89453 2.91992 7.1875C2.91992 7.48047 3.17383 7.74414 3.4668 7.74414ZM5.56641 10.2637C5.85938 10.2637 6.12305 10.0195 6.12305 9.72656C6.12305 9.43359 5.85938 9.17969 5.56641 9.17969L3.4668 9.17969C3.17383 9.17969 2.91992 9.43359 2.91992 9.72656C2.91992 10.0195 3.17383 10.2637 3.4668 10.2637Z" fill="${color}"/></g></svg>`;
|
|
21
|
+
|
|
22
|
+
export const Icons = {
|
|
23
|
+
prevPage, nextPage,
|
|
24
|
+
prevStep, nextStep,
|
|
25
|
+
sideBar,
|
|
26
|
+
};
|
package/src/index.ts
ADDED
package/src/utils.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export function deepEqual(a: any, b: any, excludeKeys: string[] = ["time"]) {
|
|
2
|
+
// 严格相等检查
|
|
3
|
+
if (a === b) return true;
|
|
4
|
+
|
|
5
|
+
// 非对象类型检查
|
|
6
|
+
if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) return false;
|
|
7
|
+
|
|
8
|
+
// 构造函数检查
|
|
9
|
+
if (a.constructor !== b.constructor) return false;
|
|
10
|
+
|
|
11
|
+
// 特殊对象处理
|
|
12
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
|
|
13
|
+
if (a instanceof RegExp && b instanceof RegExp) return a.toString() === b.toString();
|
|
14
|
+
|
|
15
|
+
// 获取并过滤属性键(核心修改点)
|
|
16
|
+
const filterKeys = (obj: any) =>
|
|
17
|
+
Reflect.ownKeys(obj).filter(k => typeof k === "string" ? !excludeKeys.includes(k) : false);
|
|
18
|
+
|
|
19
|
+
const keysA = filterKeys(a);
|
|
20
|
+
const keysB = filterKeys(b);
|
|
21
|
+
|
|
22
|
+
// 属性数量检查
|
|
23
|
+
if (keysA.length !== keysB.length) return false;
|
|
24
|
+
|
|
25
|
+
// 分类型处理属性名
|
|
26
|
+
const processKeys = (keys: (string | symbol)[]) => ({
|
|
27
|
+
strings: keys.filter(k => typeof k === 'string').sort(),
|
|
28
|
+
symbols: keys.filter(k => typeof k === 'symbol')
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const { strings: strA, symbols: symA } = processKeys(keysA);
|
|
32
|
+
const { strings: strB, symbols: symB } = processKeys(keysB);
|
|
33
|
+
|
|
34
|
+
// 字符串键顺序敏感比较
|
|
35
|
+
if (!arrayEqual(strA, strB)) return false;
|
|
36
|
+
|
|
37
|
+
// Symbol键存在性检查
|
|
38
|
+
if (symA.length !== symB.length) return false;
|
|
39
|
+
const symSet = new Set(symB);
|
|
40
|
+
if (!symA.every(k => symSet.has(k))) return false;
|
|
41
|
+
|
|
42
|
+
// 合并所有需比较的键
|
|
43
|
+
const allKeys = [...strA, ...symA];
|
|
44
|
+
|
|
45
|
+
// 递归比较属性值(传递排除键)
|
|
46
|
+
for (const key of allKeys) {
|
|
47
|
+
if (!deepEqual(a[key], b[key], excludeKeys)) return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 辅助函数:比较数组是否严格相等
|
|
54
|
+
function arrayEqual(arr1: any[], arr2: any[]) {
|
|
55
|
+
if (arr1.length !== arr2.length) return false;
|
|
56
|
+
for (let i = 0; i < arr1.length; i++) {
|
|
57
|
+
if (arr1[i] !== arr2[i]) return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function delay(time: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, time)); }
|