@rxdrag/website-lib 0.0.5 → 0.0.8
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/index.ts +4 -0
- package/package.json +13 -14
- package/src/components/AnimationNumber.astro +104 -0
- package/src/components/AttachmentIcon.astro +45 -0
- package/src/components/Flip.astro +53 -0
- package/src/components/FlipLogic.ts +242 -0
- package/src/components/Link.astro +81 -0
- package/src/components/LinkLogic.ts +51 -0
- package/src/components/Meta.astro +66 -0
- package/src/components/Modal.astro +69 -0
- package/src/components/ModalCloser.astro +22 -0
- package/src/components/ModalPanel.astro +22 -0
- package/src/components/ModalTrigger.astro +30 -0
- package/src/components/Motion.astro +333 -0
- package/src/components/MotionTypes.ts +71 -0
- package/src/components/Popover.astro +57 -0
- package/src/components/Popup.astro +19 -0
- package/src/components/PopverPanel.astro +22 -0
- package/src/components/RichTextView.astro +34 -0
- package/src/components/Tabs.astro +124 -0
- package/src/components/TabsBody.astro +19 -0
- package/src/components/TabsHeader.astro +19 -0
- package/src/components/TabsLogic.ts +10 -0
- package/src/components/TabsPanel.astro +17 -0
- package/src/components/TabsTab.astro +18 -0
- package/src/components/index.ts +19 -0
- package/src/env.d.ts +1 -0
- package/src/index.ts +2 -0
- package/src/lib/formatDate.ts +15 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/pagination.ts +114 -0
- package/dist/_astro/client.D-vx6DWE.js +0 -170
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { PageMeta } from "@rxdrag/rxcms-models";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
content?: PageMeta;
|
|
6
|
+
title?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { content, title: propTitle } = Astro.props;
|
|
10
|
+
|
|
11
|
+
// 从content中提取SEO相关属性
|
|
12
|
+
const {
|
|
13
|
+
// SeoMeta属性
|
|
14
|
+
seoTitle,
|
|
15
|
+
seoKeywords,
|
|
16
|
+
seoDescription,
|
|
17
|
+
seoAuthor,
|
|
18
|
+
publisher,
|
|
19
|
+
seoRobots,
|
|
20
|
+
// OgMeta属性
|
|
21
|
+
ogTitle,
|
|
22
|
+
ogDescription,
|
|
23
|
+
ogUrl,
|
|
24
|
+
ogSiteName,
|
|
25
|
+
ogType,
|
|
26
|
+
xCard,
|
|
27
|
+
xSite,
|
|
28
|
+
xTitle,
|
|
29
|
+
xDescription,
|
|
30
|
+
xUrl,
|
|
31
|
+
// 其他属性
|
|
32
|
+
ogImage,
|
|
33
|
+
} = content || {};
|
|
34
|
+
|
|
35
|
+
const title = propTitle || seoTitle || "YiZhanFei";
|
|
36
|
+
|
|
37
|
+
const canonicalURL = Astro.url.href;
|
|
38
|
+
const imageUrl = ogImage?.file?.url || "";
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
<title>{seoTitle || title}</title>
|
|
42
|
+
<meta name="description" content={seoDescription} />
|
|
43
|
+
<meta name="keywords" content={seoKeywords} />
|
|
44
|
+
<meta name="author" content={seoAuthor} />
|
|
45
|
+
<meta name="publisher" content={publisher} />
|
|
46
|
+
<meta name="robots" content={seoRobots || "index, follow"} />
|
|
47
|
+
<link rel="canonical" href={canonicalURL} />
|
|
48
|
+
|
|
49
|
+
<!-- Open Graph / Facebook -->
|
|
50
|
+
<meta property="og:type" content={ogType || "website"} />
|
|
51
|
+
<meta property="og:url" content={ogUrl || canonicalURL} />
|
|
52
|
+
<meta property="og:title" content={ogTitle || title} />
|
|
53
|
+
<meta property="og:description" content={ogDescription || seoDescription} />
|
|
54
|
+
<meta property="og:image" content={imageUrl} />
|
|
55
|
+
{ogSiteName && <meta property="og:site_name" content={ogSiteName} />}
|
|
56
|
+
|
|
57
|
+
<!-- Twitter -->
|
|
58
|
+
<meta property="twitter:card" content={xCard || "summary_large_image"} />
|
|
59
|
+
<meta property="twitter:url" content={xUrl || ogUrl || canonicalURL} />
|
|
60
|
+
<meta property="twitter:title" content={xTitle || ogTitle || title} />
|
|
61
|
+
<meta
|
|
62
|
+
property="twitter:description"
|
|
63
|
+
content={xDescription || ogDescription || seoDescription}
|
|
64
|
+
/>
|
|
65
|
+
<meta property="twitter:image" content={imageUrl} />
|
|
66
|
+
{xSite && <meta property="twitter:site" content={xSite} />}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { CSSProperties } from "react";
|
|
3
|
+
import Popup from "./Popup.astro";
|
|
4
|
+
import { DATA_POPUP_ROLE, PopupRole } from "@rxdrag/website-lib-core";
|
|
5
|
+
import type { IMotionProps } from "./MotionTypes";
|
|
6
|
+
|
|
7
|
+
interface Props extends IMotionProps {
|
|
8
|
+
popupKey: string;
|
|
9
|
+
class?: string;
|
|
10
|
+
style?: string | CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const roleProps = {
|
|
14
|
+
[DATA_POPUP_ROLE]: PopupRole.ModalContainer,
|
|
15
|
+
};
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<Popup {...roleProps} {...Astro.props}>
|
|
19
|
+
<slot />
|
|
20
|
+
</Popup>
|
|
21
|
+
|
|
22
|
+
<script>
|
|
23
|
+
import {
|
|
24
|
+
initModal,
|
|
25
|
+
initModalCloser,
|
|
26
|
+
onEverySwap,
|
|
27
|
+
onPageLoaded,
|
|
28
|
+
} from "@rxdrag/website-lib-core";
|
|
29
|
+
import {
|
|
30
|
+
DATA_POPUP,
|
|
31
|
+
DATA_POPUP_ROLE,
|
|
32
|
+
PopupRole,
|
|
33
|
+
} from "@rxdrag/website-lib-core";
|
|
34
|
+
|
|
35
|
+
const initModals = () => {
|
|
36
|
+
// 获取所有的 Modal 实例
|
|
37
|
+
const popups = document.querySelectorAll(`[${DATA_POPUP}]`);
|
|
38
|
+
popups.forEach((popup) => {
|
|
39
|
+
const popupKey = popup.getAttribute(DATA_POPUP);
|
|
40
|
+
//处理鼠标交互事件
|
|
41
|
+
if (popupKey && popup) {
|
|
42
|
+
if (popup.getAttribute(DATA_POPUP_ROLE) === PopupRole.ModalTrigger) {
|
|
43
|
+
initModal(popupKey, popup as HTMLElement);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//获取所有 ModalCloser 实例,并处理点击事件
|
|
47
|
+
//TODO:未处理嵌套跟Modal外部关闭的情况
|
|
48
|
+
const closers = popup.querySelectorAll(
|
|
49
|
+
`[${DATA_POPUP_ROLE}="${PopupRole.ModalCloser}"]`
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
closers.forEach((closer) => {
|
|
53
|
+
// 使用initModalCloser函数处理关闭按钮事件
|
|
54
|
+
if (popupKey) {
|
|
55
|
+
initModalCloser(popupKey, closer as HTMLElement);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// 在页面加载和每次页面转场后都初始化Modal
|
|
62
|
+
onPageLoaded(() => {
|
|
63
|
+
initModals();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
onEverySwap(() => {
|
|
67
|
+
initModals();
|
|
68
|
+
});
|
|
69
|
+
</script>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { CSSProperties } from "react";
|
|
3
|
+
import { DATA_POPUP_ROLE, PopupRole } from "@rxdrag/website-lib-core";
|
|
4
|
+
import Popup from "./Popup.astro";
|
|
5
|
+
import { IMotionProps } from "./MotionTypes";
|
|
6
|
+
|
|
7
|
+
interface Props extends IMotionProps {
|
|
8
|
+
popupKey?: string;
|
|
9
|
+
class?: string;
|
|
10
|
+
style?: string | CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const roleProps = {
|
|
14
|
+
[DATA_POPUP_ROLE]: PopupRole.ModalCloser,
|
|
15
|
+
};
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<Popup {...roleProps} {...Astro.props}>
|
|
19
|
+
<slot />
|
|
20
|
+
</Popup>
|
|
21
|
+
|
|
22
|
+
<script></script>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { CSSProperties } from "react";
|
|
3
|
+
import { DATA_POPUP_ROLE, PopupRole } from "@rxdrag/website-lib-core";
|
|
4
|
+
import Popup from "./Popup.astro";
|
|
5
|
+
import { IMotionProps } from "./MotionTypes";
|
|
6
|
+
|
|
7
|
+
interface Props extends IMotionProps {
|
|
8
|
+
popupKey?: string;
|
|
9
|
+
class?: string;
|
|
10
|
+
style?: string | CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const roleProps = {
|
|
14
|
+
[DATA_POPUP_ROLE]: PopupRole.ModalPanel,
|
|
15
|
+
};
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<Popup {...roleProps} {...Astro.props}>
|
|
19
|
+
<slot />
|
|
20
|
+
</Popup>
|
|
21
|
+
|
|
22
|
+
<script></script>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { CSSProperties } from "react";
|
|
3
|
+
import {
|
|
4
|
+
DATA_POPUP_CTA,
|
|
5
|
+
DATA_POPUP_ROLE,
|
|
6
|
+
PopupRole,
|
|
7
|
+
} from "@rxdrag/website-lib-core";
|
|
8
|
+
import Popup from "./Popup.astro";
|
|
9
|
+
import { HTMLElementsWithChildren, IMotionProps } from "./MotionTypes";
|
|
10
|
+
|
|
11
|
+
interface Props extends IMotionProps {
|
|
12
|
+
popupKey: string;
|
|
13
|
+
callToAction?: string;
|
|
14
|
+
as?: HTMLElementsWithChildren;
|
|
15
|
+
class?: string;
|
|
16
|
+
style?: string | CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const { callToAction, ...rest } = Astro.props;
|
|
20
|
+
const roleProps = {
|
|
21
|
+
[DATA_POPUP_CTA]: callToAction,
|
|
22
|
+
[DATA_POPUP_ROLE]: PopupRole.ModalTrigger,
|
|
23
|
+
};
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
<Popup {...roleProps} {...rest}>
|
|
27
|
+
<slot />
|
|
28
|
+
</Popup>
|
|
29
|
+
|
|
30
|
+
<script></script>
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
---
|
|
2
|
+
import {
|
|
3
|
+
DATA_MOTION_ANIMATE,
|
|
4
|
+
DATA_MOTION_CLOSE,
|
|
5
|
+
DATA_MOTION_HOVER,
|
|
6
|
+
DATA_MOTION_INVIEW,
|
|
7
|
+
DATA_MOTION_OPEN,
|
|
8
|
+
DATA_MOTION_SCROLL,
|
|
9
|
+
DATA_MOTION_TAP,
|
|
10
|
+
} from "@rxdrag/website-lib-core";
|
|
11
|
+
import { cssPropertyUnits } from "./MotionTypes";
|
|
12
|
+
import type { HTMLElementsWithChildren, IMotionProps } from "./MotionTypes";
|
|
13
|
+
import { DATA_MOTION_FLIP, DATA_MOTION_SELECTION } from "./TabsLogic";
|
|
14
|
+
|
|
15
|
+
interface Props extends IMotionProps {
|
|
16
|
+
as?: HTMLElementsWithChildren;
|
|
17
|
+
class?: string;
|
|
18
|
+
style?: string | Record<string, string | number>;
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
as = "div",
|
|
24
|
+
animate,
|
|
25
|
+
whileHover,
|
|
26
|
+
whileInView,
|
|
27
|
+
whileTap,
|
|
28
|
+
whileScroll,
|
|
29
|
+
whileOpen,
|
|
30
|
+
whileClose,
|
|
31
|
+
whileSelection,
|
|
32
|
+
flipTransition,
|
|
33
|
+
class: className,
|
|
34
|
+
style,
|
|
35
|
+
...rest
|
|
36
|
+
} = Astro.props;
|
|
37
|
+
|
|
38
|
+
const Element = as;
|
|
39
|
+
const dataWhileHover = JSON.stringify(whileHover);
|
|
40
|
+
const dataWhileInView = JSON.stringify(whileInView);
|
|
41
|
+
const dataWhileTap = JSON.stringify(whileTap);
|
|
42
|
+
const dataWhileScroll = JSON.stringify(whileScroll);
|
|
43
|
+
const dataWhileOpen = JSON.stringify(whileOpen);
|
|
44
|
+
const dataWhileClose = JSON.stringify(whileClose);
|
|
45
|
+
const dataWhileSelection = JSON.stringify(whileSelection);
|
|
46
|
+
const motions: Record<string, string> = {
|
|
47
|
+
[DATA_MOTION_ANIMATE]: JSON.stringify(animate),
|
|
48
|
+
[DATA_MOTION_HOVER]: dataWhileHover,
|
|
49
|
+
[DATA_MOTION_INVIEW]: dataWhileInView,
|
|
50
|
+
[DATA_MOTION_TAP]: dataWhileTap,
|
|
51
|
+
[DATA_MOTION_SCROLL]: dataWhileScroll,
|
|
52
|
+
[DATA_MOTION_OPEN]: dataWhileOpen,
|
|
53
|
+
[DATA_MOTION_CLOSE]: dataWhileClose,
|
|
54
|
+
[DATA_MOTION_SELECTION]: dataWhileSelection,
|
|
55
|
+
[DATA_MOTION_FLIP]: JSON.stringify(flipTransition),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const props = { ...motions, ...rest };
|
|
59
|
+
const mergedStyle = { ...style };
|
|
60
|
+
|
|
61
|
+
if (animate?.keyframes) {
|
|
62
|
+
// 从keyframes中提取初始值
|
|
63
|
+
const initialValues = Object.entries(animate.keyframes).reduce(
|
|
64
|
+
(acc, [key, value]) => {
|
|
65
|
+
// 如果值是数组,取第一个值作为初始值
|
|
66
|
+
const initialValue = Array.isArray(value) ? value[0] : value;
|
|
67
|
+
|
|
68
|
+
if (key in cssPropertyUnits) {
|
|
69
|
+
const unit = cssPropertyUnits[key as keyof typeof cssPropertyUnits];
|
|
70
|
+
if (unit === "transform") {
|
|
71
|
+
acc.transform = (acc.transform || "") as string;
|
|
72
|
+
acc.transform += ` translate${key.toUpperCase()}(${typeof initialValue === "number" ? `${initialValue}px` : initialValue})`;
|
|
73
|
+
} else if (typeof initialValue === "number") {
|
|
74
|
+
acc[key] = `${initialValue}${unit}`;
|
|
75
|
+
} else {
|
|
76
|
+
acc[key] = initialValue;
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
// 对于未定义的属性,保持原样
|
|
80
|
+
acc[key] = initialValue.toString();
|
|
81
|
+
}
|
|
82
|
+
return acc;
|
|
83
|
+
},
|
|
84
|
+
{} as Record<string, string>
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
Object.assign(mergedStyle, initialValues);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 将 styleProp 的定义移到条件块外部,确保它始终被定义
|
|
91
|
+
const styleProp =
|
|
92
|
+
Object.keys(mergedStyle).length > 0
|
|
93
|
+
? {
|
|
94
|
+
style: mergedStyle,
|
|
95
|
+
}
|
|
96
|
+
: undefined;
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
<Element class={className} {...props} {...styleProp}>
|
|
100
|
+
<slot />
|
|
101
|
+
</Element>
|
|
102
|
+
|
|
103
|
+
<script>
|
|
104
|
+
import { animate, inView } from "motion";
|
|
105
|
+
|
|
106
|
+
import {
|
|
107
|
+
DATA_MOTION_ANIMATE,
|
|
108
|
+
DATA_MOTION_CLOSE,
|
|
109
|
+
DATA_MOTION_INVIEW,
|
|
110
|
+
DATA_MOTION_OPEN,
|
|
111
|
+
DATA_MOTION_TAP,
|
|
112
|
+
onEverySwap,
|
|
113
|
+
onPageLoaded,
|
|
114
|
+
onSelected,
|
|
115
|
+
onUnSelected,
|
|
116
|
+
} from "@rxdrag/website-lib-core";
|
|
117
|
+
import type {
|
|
118
|
+
DualAnimation,
|
|
119
|
+
SelectionEvent,
|
|
120
|
+
SimpleAnimation,
|
|
121
|
+
ViewportAnimation,
|
|
122
|
+
} from "@rxdrag/website-lib-core";
|
|
123
|
+
import {
|
|
124
|
+
getPopupContainer,
|
|
125
|
+
normalizeSimpleAnimation,
|
|
126
|
+
normalizeDualAnimation,
|
|
127
|
+
onPopupOpen,
|
|
128
|
+
} from "@rxdrag/website-lib-core";
|
|
129
|
+
import { DATA_MOTION_SELECTION, DATA_TABS } from "./TabsLogic";
|
|
130
|
+
|
|
131
|
+
// 初始化动画
|
|
132
|
+
function initAnimation() {
|
|
133
|
+
// 查找所有带有 data-motion-animate 属性的元素
|
|
134
|
+
const elements = document.querySelectorAll(`[${DATA_MOTION_ANIMATE}]`);
|
|
135
|
+
elements.forEach((element) => {
|
|
136
|
+
if (element instanceof HTMLElement) {
|
|
137
|
+
if (element.dataset.motionAnimate) {
|
|
138
|
+
const animation = normalizeSimpleAnimation(
|
|
139
|
+
JSON.parse(element.dataset.motionAnimate) as
|
|
140
|
+
| SimpleAnimation
|
|
141
|
+
| undefined
|
|
142
|
+
);
|
|
143
|
+
if (animation?.keyframes) {
|
|
144
|
+
animate(element, animation.keyframes, animation.transition);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
console.log("initAnimation: Not an HTMLElement somehow?");
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function initPopups() {
|
|
154
|
+
onPopupOpen((event) => {
|
|
155
|
+
const openResponseElements = document.querySelectorAll(
|
|
156
|
+
`[${DATA_MOTION_OPEN}]`
|
|
157
|
+
);
|
|
158
|
+
const containerElement = getPopupContainer(event.key);
|
|
159
|
+
|
|
160
|
+
//响应open事件
|
|
161
|
+
openResponseElements.forEach((element) => {
|
|
162
|
+
if (
|
|
163
|
+
element instanceof HTMLElement &&
|
|
164
|
+
containerElement?.contains(element)
|
|
165
|
+
) {
|
|
166
|
+
if (element.dataset.motionOpen) {
|
|
167
|
+
const animation = normalizeSimpleAnimation(
|
|
168
|
+
JSON.parse(element.dataset.motionOpen) as
|
|
169
|
+
| SimpleAnimation
|
|
170
|
+
| undefined
|
|
171
|
+
);
|
|
172
|
+
if (animation?.keyframes) {
|
|
173
|
+
animate(element, animation.keyframes, animation.transition);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return () => {
|
|
180
|
+
const closeResponseElements = document.querySelectorAll(
|
|
181
|
+
`[${DATA_MOTION_CLOSE}]`
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
//响应close事件
|
|
185
|
+
closeResponseElements.forEach((element) => {
|
|
186
|
+
if (element instanceof HTMLElement) {
|
|
187
|
+
if (
|
|
188
|
+
element.dataset.motionClose &&
|
|
189
|
+
containerElement?.contains(element)
|
|
190
|
+
) {
|
|
191
|
+
const animation = normalizeSimpleAnimation(
|
|
192
|
+
JSON.parse(element.dataset.motionClose) as
|
|
193
|
+
| SimpleAnimation
|
|
194
|
+
| undefined
|
|
195
|
+
);
|
|
196
|
+
if (animation && animation.keyframes) {
|
|
197
|
+
animate(element, animation.keyframes, animation.transition);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
console.log("===Not an HTMLElement somehow?");
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 初始化AOS(Animate On Scroll)动画
|
|
209
|
+
function initAos() {
|
|
210
|
+
//查找所有的data-motion-inview元素
|
|
211
|
+
const inviewElements = document.querySelectorAll(`[${DATA_MOTION_INVIEW}]`);
|
|
212
|
+
inviewElements.forEach((element) => {
|
|
213
|
+
if (element instanceof HTMLElement && element.dataset.motionInview) {
|
|
214
|
+
const animation = normalizeDualAnimation(
|
|
215
|
+
JSON.parse(element.dataset.motionInview) as
|
|
216
|
+
| ViewportAnimation
|
|
217
|
+
| undefined
|
|
218
|
+
) as ViewportAnimation;
|
|
219
|
+
|
|
220
|
+
inView(element, (target) => {
|
|
221
|
+
const newElement = target as HTMLElement;
|
|
222
|
+
const needAction =
|
|
223
|
+
(!newElement.dataset.motionViewportEnter && animation.once) ||
|
|
224
|
+
!animation.once;
|
|
225
|
+
|
|
226
|
+
if (animation?.in?.keyframes && needAction) {
|
|
227
|
+
newElement.dataset.motionViewportEnter = "true";
|
|
228
|
+
animate(target, animation.in.keyframes, animation.in.transition);
|
|
229
|
+
}
|
|
230
|
+
// 返回清理函数
|
|
231
|
+
return () => {
|
|
232
|
+
// 如果需要在元素离开视图时执行某些操作
|
|
233
|
+
if (animation?.out?.keyframes && needAction && !animation.once) {
|
|
234
|
+
animate(
|
|
235
|
+
target,
|
|
236
|
+
animation.out.keyframes,
|
|
237
|
+
animation.out.transition
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
//TODO 初始化Taps
|
|
247
|
+
function initTaps() {
|
|
248
|
+
//查找所有的data-motion-tap元素
|
|
249
|
+
const tapElements = document.querySelectorAll(`[${DATA_MOTION_TAP}]`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
//初始化选项卡Selection动画
|
|
253
|
+
function initTabsMotion() {
|
|
254
|
+
onSelected((event: SelectionEvent) => {
|
|
255
|
+
//查找对应的data-motion-selection元素
|
|
256
|
+
const tabsElement = document.querySelector(`[${DATA_TABS}=${event.key}]`);
|
|
257
|
+
|
|
258
|
+
if (tabsElement instanceof HTMLElement) {
|
|
259
|
+
//该容器下,所有带有选中动画的元素
|
|
260
|
+
tabsElement
|
|
261
|
+
.querySelectorAll(`[${DATA_MOTION_SELECTION}]`)
|
|
262
|
+
.forEach((element) => {
|
|
263
|
+
const motions = (element as HTMLElement).dataset.motionSelection;
|
|
264
|
+
if (motions) {
|
|
265
|
+
const animation = normalizeDualAnimation(
|
|
266
|
+
JSON.parse(motions) as DualAnimation | undefined
|
|
267
|
+
);
|
|
268
|
+
if (animation?.in?.keyframes) {
|
|
269
|
+
animate(
|
|
270
|
+
element,
|
|
271
|
+
animation.in.keyframes,
|
|
272
|
+
animation.in.transition
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
onUnSelected((event: SelectionEvent) => {
|
|
281
|
+
//查找对应的data-motion-selection元素
|
|
282
|
+
const tabsElement = document.querySelector(`[${DATA_TABS}=${event.key}]`);
|
|
283
|
+
|
|
284
|
+
if (tabsElement instanceof HTMLElement) {
|
|
285
|
+
//该容器下,所有带有选中动画的元素
|
|
286
|
+
tabsElement
|
|
287
|
+
.querySelectorAll(`[${DATA_MOTION_SELECTION}]`)
|
|
288
|
+
.forEach((element) => {
|
|
289
|
+
const motions = (element as HTMLElement).dataset.motionSelection;
|
|
290
|
+
if (motions) {
|
|
291
|
+
const animation = normalizeDualAnimation(
|
|
292
|
+
JSON.parse(motions) as DualAnimation | undefined
|
|
293
|
+
);
|
|
294
|
+
if (animation?.out?.keyframes) {
|
|
295
|
+
animate(
|
|
296
|
+
element,
|
|
297
|
+
animation.out.keyframes,
|
|
298
|
+
animation.out.transition
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const initMotion = () => {
|
|
308
|
+
initAnimation();
|
|
309
|
+
initPopups();
|
|
310
|
+
initAos();
|
|
311
|
+
initTaps();
|
|
312
|
+
initTabsMotion();
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
onEverySwap(() => {
|
|
316
|
+
initMotion();
|
|
317
|
+
});
|
|
318
|
+
onPageLoaded(() => {
|
|
319
|
+
initMotion();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// if (!(window as any).__motionInitialized) {
|
|
323
|
+
// (window as any).__motionInitialized = true;
|
|
324
|
+
// // 当DOM加载完成时初始化动画
|
|
325
|
+
// document.addEventListener("astro:after-swap", () => {
|
|
326
|
+
// initAnimation();
|
|
327
|
+
// initPopups();
|
|
328
|
+
// initAos();
|
|
329
|
+
// initTaps();
|
|
330
|
+
// initTabsMotion();
|
|
331
|
+
// });
|
|
332
|
+
// }
|
|
333
|
+
</script>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { SimpleAnimation, HoverAnimation, ViewportAnimation, TapAnimation, ScrollAnimation, SelectionAnimation } from "@rxdrag/website-lib-core";
|
|
2
|
+
import type { AnimationOptions } from "motion";
|
|
3
|
+
|
|
4
|
+
// 排除不能包含子元素的标签
|
|
5
|
+
export type ExcludedElements =
|
|
6
|
+
| "img"
|
|
7
|
+
| "input"
|
|
8
|
+
| "br"
|
|
9
|
+
| "hr"
|
|
10
|
+
| "area"
|
|
11
|
+
| "base"
|
|
12
|
+
| "col"
|
|
13
|
+
| "embed"
|
|
14
|
+
| "link"
|
|
15
|
+
| "meta"
|
|
16
|
+
| "param"
|
|
17
|
+
| "source"
|
|
18
|
+
| "track"
|
|
19
|
+
| "wbr";
|
|
20
|
+
|
|
21
|
+
export type HTMLElementsWithChildren = Exclude<
|
|
22
|
+
keyof HTMLElementTagNameMap,
|
|
23
|
+
ExcludedElements
|
|
24
|
+
>;
|
|
25
|
+
|
|
26
|
+
// CSS 属性的单位处理映射
|
|
27
|
+
export const cssPropertyUnits = {
|
|
28
|
+
// 无单位的属性
|
|
29
|
+
opacity: "",
|
|
30
|
+
scale: "",
|
|
31
|
+
fontWeight: "",
|
|
32
|
+
lineHeight: "",
|
|
33
|
+
zIndex: "",
|
|
34
|
+
flex: "",
|
|
35
|
+
flexGrow: "",
|
|
36
|
+
flexShrink: "",
|
|
37
|
+
order: "",
|
|
38
|
+
// 使用px的属性
|
|
39
|
+
width: "px",
|
|
40
|
+
height: "px",
|
|
41
|
+
minWidth: "px",
|
|
42
|
+
minHeight: "px",
|
|
43
|
+
maxWidth: "px",
|
|
44
|
+
maxHeight: "px",
|
|
45
|
+
padding: "px",
|
|
46
|
+
margin: "px",
|
|
47
|
+
top: "px",
|
|
48
|
+
right: "px",
|
|
49
|
+
bottom: "px",
|
|
50
|
+
left: "px",
|
|
51
|
+
gap: "px",
|
|
52
|
+
columnGap: "px",
|
|
53
|
+
rowGap: "px",
|
|
54
|
+
// transform 相关的属性
|
|
55
|
+
x: "transform",
|
|
56
|
+
y: "transform",
|
|
57
|
+
z: "transform",
|
|
58
|
+
} as const;
|
|
59
|
+
|
|
60
|
+
export interface IMotionProps {
|
|
61
|
+
animate?: SimpleAnimation;
|
|
62
|
+
whileHover?: HoverAnimation;
|
|
63
|
+
whileInView?: ViewportAnimation;
|
|
64
|
+
whileTap?: TapAnimation;
|
|
65
|
+
whileScroll?: ScrollAnimation;
|
|
66
|
+
whileOpen?: SimpleAnimation;
|
|
67
|
+
whileClose?: SimpleAnimation;
|
|
68
|
+
whileSelection?: SelectionAnimation;
|
|
69
|
+
// 在flip的父元素中使用
|
|
70
|
+
flipTransition?: AnimationOptions;
|
|
71
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { CSSProperties } from "react";
|
|
3
|
+
import { DATA_POPUP_ROLE, PopupRole } from "@rxdrag/website-lib-core";
|
|
4
|
+
import Popup from "./Popup.astro";
|
|
5
|
+
import { IMotionProps } from "./MotionTypes";
|
|
6
|
+
|
|
7
|
+
interface Props extends IMotionProps {
|
|
8
|
+
popupKey: string;
|
|
9
|
+
class?: string;
|
|
10
|
+
style?: string | CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const roleProps = {
|
|
14
|
+
[DATA_POPUP_ROLE]: PopupRole.PopoverContainer,
|
|
15
|
+
};
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<Popup {...roleProps} {...Astro.props}>
|
|
19
|
+
<slot />
|
|
20
|
+
</Popup>
|
|
21
|
+
|
|
22
|
+
<script>
|
|
23
|
+
import {
|
|
24
|
+
initPopover,
|
|
25
|
+
onEverySwap,
|
|
26
|
+
onPageLoaded,
|
|
27
|
+
} from "@rxdrag/website-lib-core";
|
|
28
|
+
import {
|
|
29
|
+
DATA_POPUP,
|
|
30
|
+
DATA_POPUP_ROLE,
|
|
31
|
+
PopupRole,
|
|
32
|
+
} from "@rxdrag/website-lib-core";
|
|
33
|
+
|
|
34
|
+
const initPopoverActions = () => {
|
|
35
|
+
// 获取所有的 Popover 实例
|
|
36
|
+
const popups = document.querySelectorAll(`[${DATA_POPUP}]`);
|
|
37
|
+
|
|
38
|
+
popups.forEach((popup) => {
|
|
39
|
+
const popupKey = popup.getAttribute(DATA_POPUP);
|
|
40
|
+
//处理鼠标交互事件
|
|
41
|
+
if (popupKey && popup) {
|
|
42
|
+
if (
|
|
43
|
+
popup.getAttribute(DATA_POPUP_ROLE) === PopupRole.PopoverContainer
|
|
44
|
+
) {
|
|
45
|
+
initPopover(popupKey, popup as HTMLElement);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
onPageLoaded(() => {
|
|
52
|
+
initPopoverActions();
|
|
53
|
+
});
|
|
54
|
+
onEverySwap(() => {
|
|
55
|
+
initPopoverActions();
|
|
56
|
+
});
|
|
57
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { DATA_POPUP } from "@rxdrag/website-lib-core";
|
|
3
|
+
import Motion from "./Motion.astro";
|
|
4
|
+
import { IMotionProps } from "./MotionTypes";
|
|
5
|
+
|
|
6
|
+
interface Props extends IMotionProps {
|
|
7
|
+
popupKey?: string;
|
|
8
|
+
}
|
|
9
|
+
const { popupKey, ...rest } = Astro.props;
|
|
10
|
+
const popupProps = {
|
|
11
|
+
[DATA_POPUP]: popupKey,
|
|
12
|
+
};
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<Motion {...popupProps} {...rest}>
|
|
16
|
+
<slot />
|
|
17
|
+
</Motion>
|
|
18
|
+
|
|
19
|
+
<script></script>
|