@rxdrag/website-lib-core 0.0.103 → 0.0.105

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 (42) hide show
  1. package/package.json +5 -5
  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/ProductCard/ProductCta/index.tsx +5 -21
  9. package/src/react/components/Scroller.tsx +32 -4
  10. package/src/react/components/Share/socials.tsx +1 -2
  11. package/src/react/index.ts +1 -2
  12. package/src/component-logic/collapse.ts +0 -61
  13. package/src/component-logic/gsap.d.ts +0 -4
  14. package/src/component-logic/modal.ts +0 -45
  15. package/src/component-logic/motion.ts +0 -272
  16. package/src/component-logic/number.ts +0 -45
  17. package/src/component-logic/popover.ts +0 -51
  18. package/src/component-logic/tabs.ts +0 -10
  19. package/src/controller/AnimateController.ts +0 -138
  20. package/src/controller/AosController.ts +0 -240
  21. package/src/controller/CollapseController.ts +0 -130
  22. package/src/controller/FlipController.ts +0 -339
  23. package/src/controller/ModalController.ts +0 -127
  24. package/src/controller/NumberController.ts +0 -161
  25. package/src/controller/OpenableController.ts +0 -367
  26. package/src/controller/PageLoader.ts +0 -154
  27. package/src/controller/PopoverController.ts +0 -116
  28. package/src/controller/TabsController.ts +0 -271
  29. package/src/controller/applyAnimation.ts +0 -86
  30. package/src/controller/applyInitialState.ts +0 -79
  31. package/src/controller/consts.ts +0 -33
  32. package/src/controller/index.ts +0 -10
  33. package/src/controller/utils.ts +0 -48
  34. package/src/motion/consts.ts +0 -428
  35. package/src/motion/convertToGsapVars.ts +0 -102
  36. package/src/motion/index.ts +0 -6
  37. package/src/motion/normalizeAnimation.ts +0 -28
  38. package/src/motion/normalizeAosAnimation.ts +0 -22
  39. package/src/motion/normalizePopupAnimation.ts +0 -24
  40. package/src/motion/types.ts +0 -133
  41. package/src/react/hooks/index.ts +0 -1
  42. package/src/react/hooks/useScroll.ts +0 -30
@@ -1,51 +0,0 @@
1
- import { DATA_OPENABLE, DATA_OPENABLE_ROLE, OpenAble } from "../controller";
2
- import { AnimationConfig, OpenableAnimationConfig } from "../motion";
3
-
4
- export const defaultPopoverPanelOpen: AnimationConfig = {
5
- fromTo: {
6
- from: {
7
- height: 0,
8
- opacity: 0,
9
- },
10
- to: {
11
- height: "auto",
12
- opacity: 1,
13
- },
14
- },
15
- duration: 0.6,
16
- ease: "spring",
17
- };
18
-
19
- export const defaultPopoverPanelClose: AnimationConfig = {
20
- fromTo: {
21
- from: {
22
- height: "auto",
23
- opacity: 1,
24
- },
25
- to: {
26
- height: 0,
27
- opacity: 0,
28
- },
29
- },
30
- duration: 0.25,
31
- ease: "cubic-bezier(0.4, 0.0, 0.2, 1)",
32
- };
33
-
34
- export const defaultPopoverPanelAnimation: OpenableAnimationConfig = {
35
- open: defaultPopoverPanelOpen,
36
- close: defaultPopoverPanelClose,
37
- };
38
-
39
- export function getPopoverDataAttrs(openableKey?: string) {
40
- return {
41
- [DATA_OPENABLE]: openableKey || crypto.randomUUID(),
42
- [DATA_OPENABLE_ROLE]: OpenAble.PopoverContainer,
43
- };
44
- }
45
-
46
- export function getPopoverPanelDataAttrs(openableKey?: string) {
47
- return {
48
- [DATA_OPENABLE]: openableKey || "",
49
- [DATA_OPENABLE_ROLE]: OpenAble.PopoverPanel,
50
- };
51
- }
@@ -1,10 +0,0 @@
1
- export const DATA_TABS = "data-tabs";
2
- export const DATA_TABS_HEADER = "data-tabs-header";
3
- export const DATA_TABS_PANEL = "data-tabs-panel";
4
- export const DATA_TABS_TAB = "data-tabs-tab";
5
- export const DATA_TABS_BODY = "data-tabs-body";
6
- //当前选中的选项卡
7
- export const DATA_TABS_SELECTION = "data-tabs-selection";
8
- //选中动画,存动画数据
9
- export const DATA_MOTION_SELECTION = "data-motion-selection";
10
- export const DATA_MOTION_FLIP = "data-motion-flip";
@@ -1,138 +0,0 @@
1
- import { AnimationConfig, DATA_MOTION } from "../motion";
2
- import { applyAnimation } from "./applyAnimation";
3
- import { applyInitialState } from "./applyInitialState";
4
-
5
- export class AnimateController {
6
- private static instance: Record<string, AnimateController> = {};
7
- private animations: gsap.core.Tween[] = [];
8
- private unmountHandlers: Array<() => void> = [];
9
- private registeredElements: WeakSet<Element> = new WeakSet();
10
-
11
- /**
12
- * 私有构造函数,防止外部直接创建实例
13
- * @param clientDoc - 可选的Document对象,在SSR环境中可能为undefined
14
- */
15
- private constructor(private clientDoc?: Document) {}
16
-
17
- /**
18
- * 获取单例实例
19
- * @param key - 实例的唯一标识,默认为"default"
20
- * @param clientDoc - 可选的Document对象
21
- * @returns AnimateController 实例
22
- */
23
- public static getInstance(
24
- key: string = "runtime",
25
- clientDoc?: Document
26
- ): AnimateController {
27
- if (!AnimateController.instance[key]) {
28
- // 在服务器端渲染时,document 不存在,传入 undefined
29
- const doc =
30
- clientDoc || (typeof document !== "undefined" ? document : undefined);
31
- AnimateController.instance[key] = new AnimateController(doc);
32
- }
33
- // 这个代码很有必要,需要替换掉旧doc,因为react不确定刷新的问题
34
- if (clientDoc) {
35
- AnimateController.instance[key].destroy();
36
- AnimateController.instance[key].setClientDoc(clientDoc);
37
- }
38
- return AnimateController.instance[key];
39
- }
40
-
41
- /**
42
- * 销毁指定的实例
43
- * @param key - 实例的唯一标识
44
- */
45
- public static destroyInstance(key: string = "runtime"): void {
46
- if (AnimateController.instance[key]) {
47
- AnimateController.instance[key].destroy();
48
- delete AnimateController.instance[key];
49
- }
50
- }
51
-
52
- /**
53
- * 重置所有实例(主要用于测试)
54
- */
55
- public static resetAll(): void {
56
- Object.keys(AnimateController.instance).forEach((key) => {
57
- AnimateController.instance[key].destroy();
58
- });
59
- AnimateController.instance = {};
60
- }
61
-
62
- /**
63
- * 设置客户端文档对象
64
- * @param clientDoc - Document对象
65
- */
66
- public setClientDoc(clientDoc: Document): void {
67
- this.clientDoc = clientDoc;
68
- }
69
-
70
- /**
71
- * 挂载动画控制器,初始化所有动画
72
- * @param clientDoc - 可选的Document对象,如果未提供则使用构造函数中的文档
73
- */
74
- public mount(clientDoc?: Document): void {
75
- const doc = clientDoc || this.clientDoc;
76
- if (!doc) return;
77
-
78
- // 查找所有带有 data-motion 属性的元素
79
- const elements = doc.querySelectorAll(`[${DATA_MOTION}]`);
80
- // 初始化新的动画
81
- elements.forEach((element) => {
82
- // 检查元素是否已经被注册过
83
- if (this.registeredElements.has(element)) {
84
- return; // 如果已经注册过,则跳过
85
- }
86
-
87
- if (
88
- doc.defaultView &&
89
- element instanceof doc.defaultView.HTMLElement &&
90
- element.dataset.motion
91
- ) {
92
- try {
93
- const animation = JSON.parse(element.dataset.motion) as
94
- | AnimationConfig
95
- | undefined;
96
- if (animation) {
97
- if (animation.initial) {
98
- applyInitialState(element, animation.initial);
99
- }
100
- // 执行动画
101
- const tween = applyAnimation(element, animation);
102
- if (tween) {
103
- this.animations.push(tween);
104
- // 将元素添加到已注册集合中
105
- this.registeredElements.add(element);
106
- }
107
- }
108
- } catch (error) {
109
- console.error("解析动画配置失败", error);
110
- }
111
- }
112
- });
113
- }
114
-
115
- /**
116
- * 销毁动画控制器,清理所有动画和事件监听器
117
- */
118
- public destroy(): void {
119
- // 停止所有动画
120
- this.animations.forEach((tween) => {
121
- tween.kill();
122
- });
123
- this.animations = [];
124
-
125
- // 执行所有卸载处理函数
126
- this.unmountHandlers.forEach((handler) => handler());
127
- this.unmountHandlers = [];
128
-
129
- // 创建新的 WeakSet 来清理已注册元素的跟踪
130
- this.registeredElements = new WeakSet();
131
- }
132
- }
133
-
134
- // 导出默认实例,方便直接使用
135
- export const animate = AnimateController.getInstance(
136
- "runtime",
137
- typeof document !== "undefined" ? document : undefined
138
- );
@@ -1,240 +0,0 @@
1
- import { merge } from "lodash-es";
2
- import {
3
- AnimationConfig,
4
- AosAnimationConfig,
5
- DATA_MOTION_INVIEW,
6
- } from "../motion";
7
- import { applyAnimation } from "./applyAnimation";
8
-
9
- export class AosController {
10
- private static instances: Record<string, AosController> = {};
11
- private doc?: Document;
12
- private unmountHandlers: Array<() => void> = [];
13
- private intersectionObserver?: IntersectionObserver;
14
-
15
- private constructor(doc?: Document) {
16
- this.doc = doc;
17
- }
18
-
19
- /**
20
- * 获取 AosController 实例
21
- * @param key 实例的唯一标识,默认为 "runtime"
22
- * @param doc 文档对象
23
- * @returns AosController 实例
24
- */
25
- public static getInstance(
26
- key: string = "runtime",
27
- doc?: Document
28
- ): AosController {
29
- if (!AosController.instances[key]) {
30
- AosController.instances[key] = new AosController(doc);
31
- } else if (doc) {
32
- AosController.instances[key].setDoc(doc);
33
- }
34
- return AosController.instances[key];
35
- }
36
-
37
- /**
38
- * 销毁指定 key 的实例
39
- * @param key 实例的唯一标识
40
- */
41
- public static destroyInstance(key: string = "runtime"): void {
42
- if (AosController.instances[key]) {
43
- AosController.instances[key].destroy();
44
- delete AosController.instances[key];
45
- }
46
- }
47
-
48
- /**
49
- * 重置所有实例
50
- */
51
- public static resetAll(): void {
52
- Object.keys(AosController.instances).forEach((key) => {
53
- AosController.destroyInstance(key);
54
- });
55
- }
56
-
57
- /**
58
- * 设置文档对象
59
- * @param doc 文档对象
60
- */
61
- private setDoc(doc?: Document) {
62
- this.doc = doc;
63
- }
64
-
65
- /**
66
- * 挂载 AOS 动画控制器
67
- * @param clientDoc 文档对象,默认为 document
68
- */
69
- public mount(): void {
70
- // 如果没有可用的文档对象,则直接返回
71
- if (!this.doc) return;
72
-
73
- // 清理之前的观察器和处理函数
74
- this.destroy();
75
-
76
- // 创建 IntersectionObserver 用于检测元素进入视口
77
- this.intersectionObserver = new IntersectionObserver(
78
- (entries) => {
79
- entries.forEach((entry) => {
80
- if (entry.isIntersecting) {
81
- const element = entry.target as HTMLElement;
82
- this.handleElementEnterViewport(element);
83
- } else {
84
- const element = entry.target as HTMLElement;
85
- this.handleElementLeaveViewport(element);
86
- }
87
- });
88
- },
89
- {
90
- threshold: 0.1, // 元素10%可见时触发
91
- root: null, // 使用视口作为根
92
- }
93
- );
94
-
95
- // 查找所有的data-motion-inview元素
96
- const inviewElements = this.doc.querySelectorAll(`[${DATA_MOTION_INVIEW}]`);
97
-
98
- inviewElements.forEach((element) => {
99
- if (
100
- this.doc?.defaultView &&
101
- element instanceof this.doc.defaultView.HTMLElement &&
102
- element.dataset.motionInview
103
- ) {
104
- try {
105
- // 初始化元素样式
106
- this.initElementStyle(element as HTMLElement);
107
-
108
- // 添加到观察器
109
- this.intersectionObserver?.observe(element);
110
-
111
- // 添加清理函数
112
- this.unmountHandlers.push(() => {
113
- this.intersectionObserver?.unobserve(element);
114
- });
115
- } catch (error) {
116
- console.error("初始化元素AOS动画时出错:", element, error);
117
- }
118
- }
119
- });
120
- }
121
-
122
- /**
123
- * 初始化元素样式
124
- * @param element 要初始化的元素
125
- */
126
- private initElementStyle(element: HTMLElement): void {
127
- try {
128
- const inViewAnimation = element.dataset.motionInview
129
- ? (JSON.parse(element.dataset.motionInview) as
130
- | AosAnimationConfig
131
- | undefined)
132
- : undefined;
133
-
134
- if (!inViewAnimation) return;
135
-
136
- // 如果设置了once属性,初始化时可能需要设置元素透明度为0
137
- if (
138
- inViewAnimation.once &&
139
- inViewAnimation.enter &&
140
- !element.dataset.motionViewportEnter
141
- ) {
142
- // 如果是淡入动画,初始透明度可能需要设置为0
143
- if (!element.style.opacity && inViewAnimation.enter.opacity === 1) {
144
- element.style.opacity = "0";
145
- }
146
- }
147
- } catch (error) {
148
- console.error("初始化元素样式时出错:", element, error);
149
- }
150
- }
151
-
152
- /**
153
- * 处理元素进入视口
154
- * @param element 进入视口的元素
155
- */
156
- private handleElementEnterViewport(element: HTMLElement): void {
157
- try {
158
- const animation = element.dataset.motion
159
- ? (JSON.parse(element.dataset.motion) as AnimationConfig | undefined)
160
- : undefined;
161
- const inViewAnimation = element.dataset.motionInview
162
- ? (JSON.parse(element.dataset.motionInview) as
163
- | AosAnimationConfig
164
- | undefined)
165
- : undefined;
166
-
167
- if (!inViewAnimation) return;
168
-
169
- const needAction =
170
- (!element.dataset.motionViewportEnter && inViewAnimation.once) ||
171
- !inViewAnimation.once;
172
-
173
- if (inViewAnimation.enter && needAction) {
174
- element.dataset.motionViewportEnter = "true";
175
- applyAnimation(element, merge(animation, inViewAnimation.enter), {
176
- ensureVisibleOnComplete: inViewAnimation.once,
177
- });
178
-
179
- // 如果是一次性动画,不再观察
180
- if (inViewAnimation.once) {
181
- this.intersectionObserver?.unobserve(element);
182
- }
183
- }
184
- } catch (error) {
185
- console.error("处理元素进入视口时出错:", element, error);
186
- }
187
- }
188
-
189
- /**
190
- * 处理元素离开视口
191
- * @param element 离开视口的元素
192
- */
193
- private handleElementLeaveViewport(element: HTMLElement): void {
194
- try {
195
- const animation = element.dataset.motion
196
- ? (JSON.parse(element.dataset.motion) as AnimationConfig | undefined)
197
- : undefined;
198
- const inViewAnimation = element.dataset.motionInview
199
- ? (JSON.parse(element.dataset.motionInview) as
200
- | AosAnimationConfig
201
- | undefined)
202
- : undefined;
203
-
204
- if (!inViewAnimation || inViewAnimation.once) return;
205
-
206
- if (inViewAnimation.exit) {
207
- applyAnimation(element, merge(animation, inViewAnimation.exit));
208
- }
209
- } catch (error) {
210
- console.error("处理元素离开视口时出错:", element, error);
211
- }
212
- }
213
-
214
- /**
215
- * 销毁 AOS 动画控制器
216
- */
217
- public destroy(): void {
218
- // 断开所有观察
219
- if (this.intersectionObserver) {
220
- this.intersectionObserver.disconnect();
221
- this.intersectionObserver = undefined;
222
- }
223
-
224
- // 执行所有卸载处理函数
225
- this.unmountHandlers.forEach((handler) => {
226
- try {
227
- handler();
228
- } catch (error) {
229
- console.error("执行卸载处理函数失败", error);
230
- }
231
- });
232
- this.unmountHandlers = [];
233
- }
234
- }
235
-
236
- // 导出默认实例,方便直接使用
237
- export const aos = AosController.getInstance(
238
- "runtime",
239
- typeof document !== "undefined" ? document : undefined
240
- );
@@ -1,130 +0,0 @@
1
- import { DATA_OPENABLE, DATA_OPENABLE_ROLE, OpenAble } from "./consts";
2
- import { OpenableController } from "./OpenableController";
3
-
4
- export class CollapseController extends OpenableController {
5
- private static instances: Record<string, CollapseController> = {};
6
-
7
- private constructor(doc?: Document) {
8
- super(doc);
9
- }
10
-
11
- public static getInstance(
12
- key: string = "runtime",
13
- doc?: Document
14
- ): CollapseController {
15
- if (!CollapseController.instances[key]) {
16
- CollapseController.instances[key] = new CollapseController(doc);
17
- } else if (doc) {
18
- CollapseController.instances[key].setDoc(doc);
19
- }
20
- return CollapseController.instances[key];
21
- }
22
-
23
- /**
24
- * 销毁指定 key 的实例
25
- * @param key 实例的唯一标识
26
- */
27
- public static destroyInstance(key: string = "runtime"): void {
28
- if (CollapseController.instances[key]) {
29
- CollapseController.instances[key].destroy();
30
- delete CollapseController.instances[key];
31
- }
32
- }
33
-
34
- private setDoc(doc?: Document) {
35
- this.doc = doc;
36
- }
37
-
38
- mount() {
39
- super.mount();
40
- const openables = this.doc?.querySelectorAll(`[${DATA_OPENABLE}]`);
41
- openables?.forEach((openable) => {
42
- const openableKey = openable.getAttribute(DATA_OPENABLE);
43
-
44
- // 获取所有触发器
45
- const allTriggers = openable?.querySelectorAll(
46
- `[${DATA_OPENABLE_ROLE}="${OpenAble.CollapseTrigger}"]`
47
- );
48
-
49
- // 获取所有嵌套容器
50
- const nestedContainers = openable?.querySelectorAll(
51
- `[${DATA_OPENABLE_ROLE}="${OpenAble.PopoverContainer}"],
52
- [${DATA_OPENABLE_ROLE}="${OpenAble.ModalContainer}"],
53
- [${DATA_OPENABLE_ROLE}="${OpenAble.CollapseContainer}"]`
54
- );
55
-
56
- // 过滤出不在嵌套容器内的触发器
57
- const filteredTriggers: Element[] = [];
58
- allTriggers?.forEach((trigger) => {
59
- let isInNestedContainer = false;
60
-
61
- nestedContainers?.forEach((container) => {
62
- if (container.contains(trigger) && container !== openable) {
63
- isInNestedContainer = true;
64
- }
65
- });
66
-
67
- if (!isInNestedContainer) {
68
- filteredTriggers.push(trigger);
69
- }
70
- });
71
-
72
- // 为过滤后的触发器添加事件处理
73
- filteredTriggers.forEach((trigger) => {
74
- if (openableKey) {
75
- const unsub = this.initCollapseTrigger(
76
- openableKey,
77
- trigger as HTMLElement
78
- );
79
- this.unmountHandlers.push(unsub);
80
- }
81
- });
82
- });
83
- }
84
- /**
85
- * 初始化Modal的点击交互事件
86
- * @param openableKey - 弹出层的唯一标识
87
- * @param trigger - 触发器元素
88
- * @returns 清理函数,用于移除事件监听器
89
- */
90
- public initCollapseTrigger(
91
- openableKey: string,
92
- trigger: HTMLElement
93
- ): () => void {
94
- if (!this.doc) return () => {};
95
-
96
- try {
97
- // 创建新的事件处理函数
98
- const handleTriggerClick = () => {
99
- const container = this.getOpenableContainer(openableKey);
100
- if (container) {
101
- if (container.classList.contains("open")) {
102
- // 传递容器元素而不是触发器,确保正确移除open类
103
- this.close(openableKey, container);
104
- } else {
105
- this.open(openableKey, trigger);
106
- }
107
- }
108
- };
109
-
110
- // 添加新的事件监听器
111
- trigger.addEventListener("click", handleTriggerClick);
112
-
113
- return () => {
114
- trigger.removeEventListener("click", handleTriggerClick);
115
- };
116
- } catch (error) {
117
- console.error(`初始化Modal事件失败: ${openableKey}`, error);
118
- return () => {};
119
- }
120
- }
121
-
122
- unmount(): void {
123
- super.unmount();
124
- }
125
- }
126
-
127
- export const collapse = CollapseController.getInstance(
128
- "runtime",
129
- typeof document !== "undefined" ? document : undefined
130
- );