@rxdrag/website-lib-core 0.0.102 → 0.0.104

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.
Files changed (43) hide show
  1. package/package.json +7 -7
  2. package/src/component-logic/index.ts +1 -8
  3. package/src/global.d.ts +7 -0
  4. package/src/index.ts +1 -3
  5. package/src/react/components/BackgroundHlsVideoPlayer.tsx +30 -1
  6. package/src/react/components/ContactForm/ContactForm.tsx +3 -2
  7. package/src/react/components/ContactForm/types.ts +1 -0
  8. package/src/react/components/Scroller.tsx +32 -4
  9. package/src/react/components/Share/socials.tsx +1 -2
  10. package/src/react/components/all.ts +39 -0
  11. package/src/react/components/index.ts +1 -2
  12. package/src/react/index.ts +1 -2
  13. package/src/component-logic/collapse.ts +0 -61
  14. package/src/component-logic/gsap.d.ts +0 -4
  15. package/src/component-logic/modal.ts +0 -45
  16. package/src/component-logic/motion.ts +0 -272
  17. package/src/component-logic/number.ts +0 -45
  18. package/src/component-logic/popover.ts +0 -51
  19. package/src/component-logic/tabs.ts +0 -10
  20. package/src/controller/AnimateController.ts +0 -138
  21. package/src/controller/AosController.ts +0 -240
  22. package/src/controller/CollapseController.ts +0 -130
  23. package/src/controller/FlipController.ts +0 -339
  24. package/src/controller/ModalController.ts +0 -127
  25. package/src/controller/NumberController.ts +0 -161
  26. package/src/controller/OpenableController.ts +0 -367
  27. package/src/controller/PageLoader.ts +0 -154
  28. package/src/controller/PopoverController.ts +0 -116
  29. package/src/controller/TabsController.ts +0 -271
  30. package/src/controller/applyAnimation.ts +0 -86
  31. package/src/controller/applyInitialState.ts +0 -79
  32. package/src/controller/consts.ts +0 -33
  33. package/src/controller/index.ts +0 -10
  34. package/src/controller/utils.ts +0 -48
  35. package/src/motion/consts.ts +0 -428
  36. package/src/motion/convertToGsapVars.ts +0 -102
  37. package/src/motion/index.ts +0 -6
  38. package/src/motion/normalizeAnimation.ts +0 -28
  39. package/src/motion/normalizeAosAnimation.ts +0 -22
  40. package/src/motion/normalizePopupAnimation.ts +0 -24
  41. package/src/motion/types.ts +0 -133
  42. package/src/react/hooks/index.ts +0 -1
  43. package/src/react/hooks/useScroll.ts +0 -30
@@ -1,367 +0,0 @@
1
- import { DATA_MOTION_OPENABLE, OpenableAnimationConfig } from "../motion";
2
- import { applyAnimation } from "./applyAnimation";
3
- import { gsap } from "gsap/dist/gsap";
4
- import {
5
- EVENT_OPEN,
6
- EVENT_CLOSE,
7
- DATA_OPENABLE,
8
- DATA_OPENABLE_ROLE,
9
- OpenAble,
10
- EVENT_SELECT,
11
- EVENT_UNSELECT,
12
- DATA_POPUP_CTA,
13
- } from "./consts";
14
- import { applyInitialState } from "./applyInitialState";
15
-
16
- export type PopupEvent = {
17
- //控件组的唯一标识
18
- key: string;
19
- //发出事件的element,popover对应Container,modal对应Trigger
20
- target?: HTMLElement;
21
- };
22
-
23
- export type SelectionEvent = {
24
- //控件组的唯一标识
25
- key: string;
26
- //发出事件的element
27
- target: HTMLElement;
28
- selection: string;
29
- };
30
-
31
- // 事件类型映射,用于类型安全的事件处理
32
- type EventMap = {
33
- [EVENT_OPEN]: PopupEvent;
34
- [EVENT_CLOSE]: PopupEvent;
35
- [EVENT_SELECT]: SelectionEvent;
36
- [EVENT_UNSELECT]: SelectionEvent;
37
- };
38
-
39
- export class EventBus {
40
- // 事件监听器存储,使用类型安全的映射
41
- private eventListeners: {
42
- [K in keyof EventMap]?: Array<(data: EventMap[K]) => void>;
43
- } & {
44
- [key: string]: Array<(data: unknown) => void>;
45
- } = {};
46
-
47
- /**
48
- * 触发自定义事件
49
- * @param event - 事件名称
50
- * @param options - 事件数据
51
- */
52
- emit = <K extends keyof EventMap>(event: K, options?: EventMap[K]): void => {
53
- try {
54
- // 获取该事件的所有监听器
55
- const listeners = this.eventListeners[event] || [];
56
-
57
- // 调用所有监听器
58
- listeners.forEach((callback) => {
59
- try {
60
- // 使用类型断言,因为我们知道监听器期望的类型与发送的类型匹配
61
- if (event in this.eventListeners) {
62
- // 对于已知的事件类型,我们可以安全地断言类型
63
- (callback as (data: typeof options) => void)(options);
64
- } else {
65
- // 对于未知的事件类型,我们使用更通用的类型
66
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
- callback(options as any);
68
- }
69
- } catch (error) {
70
- console.error(`处理事件回调失败: ${event}`, error);
71
- }
72
- });
73
- } catch (error) {
74
- console.error(`触发事件失败: ${event}`, error);
75
- }
76
- };
77
-
78
- /**
79
- * 监听自定义事件
80
- * @param event - 事件名称
81
- * @param callback - 事件回调函数
82
- * @returns 取消监听的函数
83
- */
84
-
85
- public on = <T = PopupEvent | SelectionEvent>(
86
- event: string,
87
- callback: (options: T) => void
88
- ): (() => void) => {
89
- try {
90
- // 确保事件监听器数组已初始化
91
- if (!this.eventListeners[event]) {
92
- this.eventListeners[event] = [];
93
- }
94
- //console.log("===$on", event, this.eventListeners);
95
-
96
- // 将回调函数转换为适当的类型并添加到监听器列表中
97
- const typedCallback = callback as unknown as (data: unknown) => void;
98
- this.eventListeners[event].push(typedCallback);
99
-
100
- // 返回取消监听的函数
101
- return () => {
102
- try {
103
- if (this.eventListeners[event]) {
104
- // 找到并移除监听器
105
- const index = this.eventListeners[event].indexOf(typedCallback);
106
- if (index !== -1) {
107
- this.eventListeners[event].splice(index, 1);
108
-
109
- // 如果没有更多监听器,清理数组
110
- if (this.eventListeners[event].length === 0) {
111
- delete this.eventListeners[event];
112
- }
113
- }
114
- }
115
- } catch (error) {
116
- console.error(`解除事件监听失败: ${event}`, error);
117
- }
118
- };
119
- } catch (error) {
120
- console.error(`注册事件监听失败: ${event}`, error);
121
- return () => {};
122
- }
123
- };
124
-
125
- destroy() {
126
- this.eventListeners = {};
127
- }
128
- }
129
-
130
- export class OpenableController {
131
- constructor(protected doc: Document | undefined) {}
132
- protected unmountHandlers: (() => void)[] = [];
133
- protected eventBus = new EventBus();
134
- public lastCta?: string | null;
135
-
136
- mount() {
137
- this.unmount();
138
- this.initOpenableAnimations();
139
- }
140
-
141
- unmount() {
142
- this.unmountHandlers.forEach((handler) => handler());
143
- this.unmountHandlers = [];
144
- }
145
- /**
146
- * 打开弹出层
147
- * @param openableKey - 弹出层的唯一标识
148
- * @param target - 触发打开的目标元素
149
- */
150
- open = (openableKey: string, target: HTMLElement): void => {
151
- if (!this.doc) return;
152
-
153
- try {
154
- // 查找 Modal 容器
155
- const modalContainer = this.getOpenableContainer(openableKey);
156
- if (modalContainer) {
157
- if (target.getAttribute(DATA_POPUP_CTA)) {
158
- this.lastCta = target.getAttribute(DATA_POPUP_CTA);
159
- }
160
- modalContainer.classList.add("open");
161
- this.eventBus.emit(EVENT_OPEN, { key: openableKey, target });
162
- } else {
163
- console.warn(`未找到弹出层: ${openableKey}`);
164
- }
165
- } catch (error) {
166
- console.error(`打开弹出层失败: ${openableKey}`, error);
167
- }
168
- };
169
-
170
- /**
171
- * 关闭弹出层
172
- * @param openableKey - 弹出层的唯一标识
173
- * @param target - 可选的目标元素,如果提供则使用该元素,否则查找容器
174
- */
175
- close = (openableKey: string, target?: HTMLElement): void => {
176
- if (!this.doc) return;
177
-
178
- try {
179
- const container = target || this.getOpenableContainer(openableKey);
180
- if (!container) {
181
- console.warn(`找不到弹出层容器: ${openableKey}`);
182
- return;
183
- }
184
-
185
- // 移除open类
186
- container.classList.remove("open");
187
-
188
- // 触发关闭事件
189
- this.eventBus.emit(EVENT_CLOSE, {
190
- key: openableKey,
191
- target: container,
192
- });
193
- } catch (error) {
194
- console.error(`关闭弹出层失败: ${openableKey}`, error);
195
- }
196
- };
197
-
198
- /**
199
- * 获取弹出层容器元素
200
- * @param openableKey - 弹出层的唯一标识
201
- * @returns 弹出层容器元素,如果未找到则返回undefined
202
- */
203
- getOpenableContainer = (openableKey: string): HTMLElement | undefined => {
204
- if (!this.doc) return undefined;
205
-
206
- try {
207
- return this.doc.querySelector(
208
- `[${DATA_OPENABLE}="${openableKey}"][${DATA_OPENABLE_ROLE}="${OpenAble.ModalContainer}"],
209
- [${DATA_OPENABLE}="${openableKey}"][${DATA_OPENABLE_ROLE}="${OpenAble.PopoverContainer}"],
210
- [${DATA_OPENABLE}="${openableKey}"][${DATA_OPENABLE_ROLE}="${OpenAble.CollapseContainer}"]`
211
- ) as HTMLElement | undefined;
212
- } catch (error) {
213
- console.error(`获取弹出层容器失败: ${openableKey}`, error);
214
- return undefined;
215
- }
216
- };
217
-
218
- /**
219
- * 初始化弹窗动画
220
- * @returns 清理函数
221
- */
222
- initOpenableAnimations = () => {
223
- const unsubscribe = this.onOpenAll((event) => {
224
- const openResponseElements = this.doc?.querySelectorAll(
225
- `[${DATA_MOTION_OPENABLE}]`
226
- );
227
- const containerElement = this.getOpenableContainer(event.key);
228
- //处理循环嵌套的情况
229
- const subContainers = containerElement?.querySelectorAll(
230
- `[${DATA_OPENABLE_ROLE}="${OpenAble.CollapseContainer}"],
231
- [${DATA_OPENABLE_ROLE}="${OpenAble.ModalContainer}"],
232
- [${DATA_OPENABLE_ROLE}="${OpenAble.PopoverContainer}"]`
233
- );
234
- //响应open事件
235
- openResponseElements?.forEach((element) => {
236
- let isInSubContainer = false;
237
- subContainers?.forEach((subContainer) => {
238
- if (subContainer.contains(element)) {
239
- isInSubContainer = true;
240
- return;
241
- }
242
- });
243
- if (
244
- this.doc?.defaultView &&
245
- element instanceof this.doc.defaultView?.HTMLElement &&
246
- containerElement?.contains(element) &&
247
- !isInSubContainer
248
- ) {
249
- if (element.dataset.motionOpenable) {
250
- const animation = JSON.parse(element.dataset.motionOpenable) as
251
- | OpenableAnimationConfig
252
- | undefined;
253
- if (animation?.initial) {
254
- applyInitialState(element, animation.initial);
255
- }
256
- if (animation?.open) {
257
- applyAnimation(element, animation.open);
258
- }
259
- }
260
- }
261
- });
262
-
263
- return () => {
264
- const closeResponseElements = this.doc?.querySelectorAll(
265
- `[${DATA_MOTION_OPENABLE}]`
266
- );
267
-
268
- //响应close事件
269
- closeResponseElements?.forEach((element) => {
270
- if (
271
- this.doc?.defaultView &&
272
- element instanceof this.doc?.defaultView.HTMLElement
273
- ) {
274
- if (
275
- element.dataset.motionOpenable &&
276
- containerElement?.contains(element)
277
- ) {
278
- const animation = JSON.parse(element.dataset.motionOpenable) as
279
- | OpenableAnimationConfig
280
- | undefined;
281
- if (animation?.close) {
282
- // 首先终止该元素上可能正在进行的所有动画(包括open动画)
283
- gsap.killTweensOf(element);
284
-
285
- // 然后应用close动画
286
- applyAnimation(element, animation.close);
287
- }
288
- }
289
- } else {
290
- console.log("===Not an HTMLElement somehow?");
291
- }
292
- });
293
- };
294
- });
295
-
296
- this.unmountHandlers.push(() => {
297
- unsubscribe();
298
- });
299
- };
300
-
301
- public onOpen = (
302
- openableKey: string,
303
- callback: (event: PopupEvent) => VoidFunction | void
304
- ): (() => void) => {
305
- return this.onOpenAll((event) => {
306
- if (event.key === openableKey) {
307
- return callback(event);
308
- }
309
- });
310
- };
311
-
312
- public onClose = (
313
- openableKey: string,
314
- callback: (event: PopupEvent) => void
315
- ) => {
316
- return this.onCloseAll((event) => {
317
- if (event.key === openableKey) {
318
- callback(event);
319
- }
320
- });
321
- };
322
-
323
- public onCloseAll = (callback: (event: PopupEvent) => void) => {
324
- return this.eventBus.on(EVENT_CLOSE, callback);
325
- };
326
-
327
- /**
328
- * 用于在脚本中监听弹出层的打开/关闭事件,并处理相关动画效果
329
- * 注意:此函数主要用于脚本中的事件处理,组件内部已有相应实现,无需使用
330
- *
331
- * @param callback - 弹出层打开时的回调函数,可返回关闭时的清理函数
332
- * @returns 取消监听的函数
333
- */
334
- public onOpenAll = (
335
- callback: (event: PopupEvent) => VoidFunction | void
336
- ): (() => void) => {
337
- let unsubscribe: ((event: PopupEvent) => void) | void;
338
-
339
- const handleOpen = (event: PopupEvent) => {
340
- try {
341
- unsubscribe = callback?.(event);
342
- } catch (error) {
343
- console.error("处理弹出层打开事件失败", error);
344
- }
345
- };
346
-
347
- const unsubscribeOpen = this.eventBus.on(EVENT_OPEN, handleOpen);
348
-
349
- const handleClose = (event: PopupEvent) => {
350
- try {
351
- unsubscribe?.(event);
352
- } catch (error) {
353
- console.error("处理弹出层关闭事件失败", error);
354
- }
355
- };
356
- const unsubscribeClose = this.eventBus.on(EVENT_CLOSE, handleClose);
357
-
358
- return () => {
359
- unsubscribeOpen();
360
- unsubscribeClose();
361
- };
362
- };
363
-
364
- destroy = () => {
365
- this.eventBus.destroy();
366
- };
367
- }
@@ -1,154 +0,0 @@
1
- export interface IPageLoader {
2
- onLoaded: (callback: () => void) => () => void;
3
- destroy: () => void;
4
- }
5
-
6
- export type PageLoaderKey = "runtime" | "preview" | "design";
7
- export class PageLoader implements IPageLoader {
8
- private static instances: Record<string, PageLoader> = {};
9
- private doc?: Document;
10
- private key: string;
11
- private callbacks: Set<() => void> = new Set();
12
- private isSwapEventRegistered = false;
13
-
14
- private constructor(key: PageLoaderKey, doc?: Document) {
15
- this.key = key;
16
- this.doc = doc;
17
- if (doc) {
18
- this.registerMainEventListeners();
19
- }
20
- }
21
-
22
- /**
23
- * 获取 PageLoader 实例
24
- * @param key 实例的唯一标识,默认为 "preview"
25
- * @param doc 文档对象
26
- * @returns PageLoader 实例
27
- */
28
- public static getInstance(
29
- key: PageLoaderKey = "preview",
30
- doc?: Document
31
- ): PageLoader {
32
- if (!PageLoader.instances[key]) {
33
- PageLoader.instances[key] = new PageLoader(key, doc);
34
- } else if (doc) {
35
- PageLoader.instances[key].setDoc(doc);
36
- }
37
- return PageLoader.instances[key];
38
- }
39
-
40
- /**
41
- * 销毁指定 key 的实例
42
- * @param key 实例的唯一标识
43
- */
44
- public static destroyInstance(key: PageLoaderKey = "preview"): void {
45
- if (PageLoader.instances[key]) {
46
- PageLoader.instances[key].destroy();
47
- delete PageLoader.instances[key];
48
- }
49
- }
50
-
51
- /**
52
- * 设置文档对象
53
- * @param doc 文档对象
54
- */
55
- private setDoc(doc?: Document) {
56
- if (this.doc !== doc) {
57
- this.doc = doc;
58
- if (doc) {
59
- this.registerMainEventListeners();
60
- }
61
- }
62
- }
63
-
64
- private registerMainEventListeners() {
65
- if (!this.doc || this.isSwapEventRegistered) return;
66
-
67
- try {
68
- // 使用标志来确保回调只执行一次
69
- //let hasExecuted = false;
70
-
71
- // 主事件处理函数,调用所有注册的回调
72
- const handleEvent = () => {
73
- console.log("===>页面转场事件触发,执行回调");
74
- // 如果已经执行过,则不再执行
75
- //if (hasExecuted) return;
76
-
77
- //hasExecuted = true;
78
-
79
- // 执行所有回调
80
- this.callbacks.forEach((callback) => {
81
- try {
82
- callback();
83
- } catch (error) {
84
- console.error("执行回调失败", error);
85
- }
86
- });
87
-
88
- // 重置执行标志,允许下一次页面转场时再次执行
89
- // setTimeout(() => {
90
- // hasExecuted = false;
91
- // }, 100);
92
- };
93
-
94
- // 只监听一个事件,优先使用 astro:page-load
95
- if (typeof window !== "undefined") {
96
- // 在客户端环境中
97
- this.doc.addEventListener("astro:page-load", handleEvent, {
98
- //once: true,
99
- });
100
- // 只监听页面转场事件
101
- this.doc.addEventListener("astro:after-swap", handleEvent);
102
- }
103
-
104
- this.isSwapEventRegistered = true;
105
- } catch (error) {
106
- console.error("注册事件监听器失败", error);
107
- }
108
- }
109
-
110
- public onLoaded = (callback: () => void): (() => void) => {
111
- // 如果不是 runtime,直接执行回调
112
- if (this.key && this.key !== "runtime") {
113
- callback();
114
- return () => {};
115
- }
116
- // 检查回调是否已经注册过
117
- if (this.callbacks.has(callback)) {
118
- // 如果已注册,直接返回清理函数
119
- return () => {
120
- this.callbacks.delete(callback);
121
- };
122
- }
123
-
124
- // 添加回调到集合
125
- this.callbacks.add(callback);
126
-
127
- // 不再在这里立即执行回调,而是完全依赖事件系统
128
-
129
- // 返回清理函数
130
- return () => {
131
- this.callbacks.delete(callback);
132
- };
133
- };
134
-
135
- public destroy(): void {
136
- if (this.doc && this.isSwapEventRegistered) {
137
- // 移除所有事件监听器
138
- const noop = () => {};
139
- this.doc.removeEventListener("astro:after-swap", noop);
140
- this.doc.removeEventListener("astro:page-load", noop);
141
-
142
- // 清空回调集合
143
- this.callbacks.clear();
144
- this.isSwapEventRegistered = false;
145
- }
146
- this.doc = undefined;
147
- }
148
- }
149
-
150
- // 导出单例实例,方便直接使用
151
- export const pageLoader = PageLoader.getInstance(
152
- "runtime",
153
- typeof document !== "undefined" ? document : undefined
154
- );
@@ -1,116 +0,0 @@
1
- import { DATA_OPENABLE, DATA_OPENABLE_ROLE, OpenAble } from "./consts";
2
- import { OpenableController } from "./OpenableController";
3
-
4
- export class PopoverController extends OpenableController {
5
- private static instances: Record<string, PopoverController> = {};
6
- private constructor(doc?: Document) {
7
- super(doc);
8
- }
9
- /**
10
- * 获取 PopoverController 实例
11
- * @param key 实例的唯一标识,默认为 "runtime"
12
- * @param doc 文档对象
13
- * @returns PopoverController 实例
14
- */
15
- public static getInstance(
16
- key: string = "runtime",
17
- doc?: Document
18
- ): PopoverController {
19
- if (!PopoverController.instances[key]) {
20
- PopoverController.instances[key] = new PopoverController(doc);
21
- } else if (doc) {
22
- PopoverController.instances[key].setDoc(doc);
23
- }
24
- return PopoverController.instances[key];
25
- }
26
-
27
- /**
28
- * 销毁指定 key 的实例
29
- * @param key 实例的唯一标识
30
- */
31
- public static destroyInstance(key: string = "runtime"): void {
32
- if (PopoverController.instances[key]) {
33
- PopoverController.instances[key].destroy();
34
- delete PopoverController.instances[key];
35
- }
36
- }
37
-
38
- private setDoc(doc?: Document) {
39
- this.doc = doc;
40
- }
41
-
42
- public getDocument(): Document | null {
43
- return this.doc ?? null;
44
- }
45
-
46
- mount() {
47
- //console.log("====> mount popover", this.doc);
48
- super.mount();
49
- // 获取所有的 Popover 实例
50
- const popups = this.doc?.querySelectorAll(`[${DATA_OPENABLE}]`);
51
- popups?.forEach((popup) => {
52
- const openableKey = popup.getAttribute(DATA_OPENABLE);
53
- //处理鼠标交互事件
54
- if (openableKey && popup) {
55
- if (
56
- popup.getAttribute(DATA_OPENABLE_ROLE) === OpenAble.PopoverContainer
57
- ) {
58
- const unsub = this.initPopover(openableKey, popup as HTMLElement);
59
- this.unmountHandlers.push(unsub);
60
- }
61
- }
62
- });
63
- }
64
-
65
- unmount(): void {
66
- super.unmount();
67
- }
68
-
69
- /**
70
- * 初始化Popover的鼠标交互事件
71
- * @param openableKey - 弹出层的唯一标识
72
- * @param element - 弹出层的 DOM 元素
73
- * @returns 清理函数,用于移除事件监听器
74
- */
75
- public initPopover = (
76
- openableKey: string,
77
- element: HTMLElement
78
- ): (() => void) => {
79
- if (!this.doc) return () => {};
80
-
81
- try {
82
- // 创建新的事件处理函数
83
- const handleMouseEnter = () => {
84
- this.open(openableKey, element);
85
- };
86
-
87
- const handleMouseLeave = () => {
88
- this.close(openableKey);
89
- };
90
-
91
- // 添加新的事件监听器
92
- element.addEventListener("mouseenter", handleMouseEnter);
93
- element.addEventListener("mouseleave", handleMouseLeave);
94
-
95
- // 使用类型断言来解决 TypeScript 类型问题
96
- const options = { passive: true };
97
- element.addEventListener("touchstart", handleMouseEnter, options as EventListenerOptions);
98
- element.addEventListener("touchend", handleMouseLeave, options as EventListenerOptions);
99
-
100
- return () => {
101
- element.removeEventListener("mouseenter", handleMouseEnter);
102
- element.removeEventListener("mouseleave", handleMouseLeave);
103
- element.removeEventListener("touchstart", handleMouseEnter, options as EventListenerOptions);
104
- element.removeEventListener("touchend", handleMouseLeave, options as EventListenerOptions);
105
- };
106
- } catch (error) {
107
- console.error(`初始化Popover事件失败: ${openableKey}`, error);
108
- return () => {};
109
- }
110
- };
111
- }
112
-
113
- export const popover = PopoverController.getInstance(
114
- "runtime",
115
- typeof document !== "undefined" ? document : undefined
116
- );