@rxdrag/website-lib 0.0.105 → 0.0.107

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.
@@ -0,0 +1,374 @@
1
+ ---
2
+ interface Props {
3
+ dialogId: string;
4
+ dialogClass?: string | string[];
5
+ backdropClass?: string | string[];
6
+ closeSelector?: string;
7
+ closeAnimMs?: number;
8
+ forceFallback?: boolean;
9
+ preset?: "center" | "top";
10
+ openAnimMs?: number;
11
+ translateY?: number;
12
+ backdropOpacity?: number;
13
+ backdropBlurPx?: number;
14
+ topOffsetPx?: number;
15
+ baseTransform?: string;
16
+ left?: string;
17
+ right?: string;
18
+ top?: string;
19
+ bottom?: string;
20
+ openTransform?: string;
21
+ enterTransform?: string;
22
+ exitTransform?: string;
23
+ }
24
+
25
+ const {
26
+ dialogId,
27
+ dialogClass = "",
28
+ backdropClass = "",
29
+ closeSelector = "[data-dialog-close]",
30
+ closeAnimMs = 240,
31
+ forceFallback = false,
32
+ preset = "center",
33
+ openAnimMs = 320,
34
+ translateY = 64,
35
+ backdropOpacity = 0.35,
36
+ backdropBlurPx = 0,
37
+ topOffsetPx = 0,
38
+ baseTransform,
39
+ left,
40
+ right,
41
+ top,
42
+ bottom,
43
+ openTransform,
44
+ enterTransform,
45
+ exitTransform,
46
+ } = Astro.props;
47
+
48
+ const backdropClassString = Array.isArray(backdropClass)
49
+ ? backdropClass.join(" ")
50
+ : backdropClass;
51
+
52
+ const resolvedBaseTransform =
53
+ baseTransform ||
54
+ (preset === "center" ? "translate(-50%,-50%)" : "translateX(-50%)");
55
+
56
+ const resolvedLeft = left ?? (preset === "center" || preset === "top" ? "50%" : "auto");
57
+ const resolvedRight = right ?? "auto";
58
+ const resolvedTop = top ?? (preset === "center" ? "50%" : "0");
59
+ const resolvedBottom = bottom ?? "auto";
60
+
61
+ const resolvedOpenTransform = openTransform || resolvedBaseTransform;
62
+ const resolvedEnterTransform =
63
+ enterTransform || `${resolvedOpenTransform} translateY(${translateY}px)`;
64
+ const resolvedExitTransform =
65
+ exitTransform || `${resolvedOpenTransform} translateY(${translateY}px)`;
66
+ ---
67
+
68
+ <style is:global>
69
+ dialog[data-generic-dialog] {
70
+ margin: 0;
71
+ outline: none;
72
+ position: fixed;
73
+ left: var(--dialog-left);
74
+ right: var(--dialog-right);
75
+ top: var(--dialog-top);
76
+ bottom: var(--dialog-bottom);
77
+ transform: var(--dialog-open-transform);
78
+ }
79
+
80
+ @keyframes genericDialogIn {
81
+ from {
82
+ opacity: 0;
83
+ transform: var(--dialog-enter-transform);
84
+ }
85
+ to {
86
+ opacity: 1;
87
+ transform: var(--dialog-open-transform);
88
+ }
89
+ }
90
+
91
+ @keyframes genericDialogOut {
92
+ from {
93
+ opacity: 1;
94
+ transform: var(--dialog-open-transform);
95
+ }
96
+ to {
97
+ opacity: 0;
98
+ transform: var(--dialog-exit-transform);
99
+ }
100
+ }
101
+
102
+ @keyframes genericBackdropIn {
103
+ from {
104
+ opacity: 0;
105
+ }
106
+ to {
107
+ opacity: 1;
108
+ }
109
+ }
110
+
111
+ @keyframes genericBackdropOut {
112
+ from {
113
+ opacity: 1;
114
+ }
115
+ to {
116
+ opacity: 0;
117
+ }
118
+ }
119
+
120
+ dialog[data-generic-dialog][open] {
121
+ animation: genericDialogIn var(--dialog-open-ms) ease-out;
122
+ transform-origin: top center;
123
+ }
124
+
125
+ dialog[data-generic-dialog][data-dialog-state="closing"] {
126
+ animation: genericDialogOut var(--dialog-close-ms) ease-in;
127
+ animation-fill-mode: forwards;
128
+ transform-origin: top center;
129
+ }
130
+
131
+ dialog[data-generic-dialog]::backdrop {
132
+ background: rgba(0, 0, 0, var(--dialog-backdrop-opacity));
133
+ backdrop-filter: blur(var(--dialog-backdrop-blur));
134
+ animation: genericBackdropIn var(--dialog-open-ms) ease-out;
135
+ }
136
+
137
+ dialog[data-generic-dialog][data-dialog-state="closing"]::backdrop {
138
+ animation: genericBackdropOut var(--dialog-close-ms) ease-in;
139
+ }
140
+
141
+ dialog[data-generic-dialog] + .backdrop {
142
+ animation: genericBackdropIn var(--dialog-open-ms) ease-out;
143
+ }
144
+
145
+ dialog[data-generic-dialog] + .backdrop[data-dialog-state="closing"] {
146
+ animation: genericBackdropOut var(--dialog-close-ms) ease-in;
147
+ }
148
+ </style>
149
+
150
+ <dialog
151
+ id={dialogId}
152
+ data-generic-dialog
153
+ data-openable-key={dialogId}
154
+ data-dialog-preset={preset}
155
+ tabindex="-1"
156
+ class:list={[dialogClass]}
157
+ style={preset === "center"
158
+ ? `--dialog-left:${resolvedLeft};--dialog-right:${resolvedRight};--dialog-top:${resolvedTop};--dialog-bottom:${resolvedBottom};--dialog-open-transform:${resolvedOpenTransform};--dialog-enter-transform:${resolvedEnterTransform};--dialog-exit-transform:${resolvedExitTransform};--dialog-open-ms:${openAnimMs}ms;--dialog-close-ms:${closeAnimMs}ms;--dialog-ty:${translateY}px;--dialog-backdrop-opacity:${backdropOpacity};--dialog-backdrop-blur:${backdropBlurPx}px;`
159
+ : `--dialog-left:${resolvedLeft};--dialog-right:${resolvedRight};--dialog-top:${resolvedTop};--dialog-bottom:${resolvedBottom};--dialog-open-transform:${resolvedOpenTransform};--dialog-enter-transform:${resolvedEnterTransform};--dialog-exit-transform:${resolvedExitTransform};--dialog-open-ms:${openAnimMs}ms;--dialog-close-ms:${closeAnimMs}ms;--dialog-ty:${translateY}px;--dialog-backdrop-opacity:${backdropOpacity};--dialog-backdrop-blur:${backdropBlurPx}px;margin-top:${topOffsetPx}px;`}
160
+ >
161
+ <slot />
162
+ </dialog>
163
+
164
+ <script
165
+ is:inline
166
+ define:vars={{
167
+ openableKey: dialogId,
168
+ closeSelector,
169
+ closeAnimMs,
170
+ forceFallback,
171
+ backdropClassString,
172
+ openAnimMs,
173
+ backdropOpacity,
174
+ backdropBlurPx,
175
+ }}
176
+ >
177
+ (() => {
178
+ const globalKey = "__generic_dialog_open_bound__";
179
+ const w = window;
180
+ if (!w[globalKey]) w[globalKey] = new Set();
181
+
182
+ const logPrefix = `[Dialog:${openableKey}]`;
183
+
184
+ const backdropClass = backdropClassString || "";
185
+
186
+ const isDialogEl = (el) => {
187
+ if (!(el instanceof HTMLElement)) return false;
188
+ return el.tagName.toLowerCase() === "dialog";
189
+ };
190
+
191
+ const getDialog = () => {
192
+ const el = document.getElementById(openableKey);
193
+ if (!isDialogEl(el)) {
194
+ console.log(logPrefix, "getDialog: dialog not found", openableKey);
195
+ return null;
196
+ }
197
+ return el;
198
+ };
199
+
200
+ const isOpen = (dialog) => {
201
+ return dialog.open === true || dialog.hasAttribute("open");
202
+ };
203
+
204
+ const ensureBackdrop = (dialog) => {
205
+ if (dialog.nextElementSibling?.classList?.contains("backdrop")) return;
206
+ const backdrop = document.createElement("div");
207
+ backdrop.className = backdropClass
208
+ ? `backdrop ${backdropClass}`
209
+ : "backdrop";
210
+ backdrop.removeAttribute("data-dialog-state");
211
+ backdrop.style.background = `rgba(0, 0, 0, ${backdropOpacity})`;
212
+ backdrop.style.backdropFilter = backdropBlurPx
213
+ ? `blur(${backdropBlurPx}px)`
214
+ : "";
215
+ backdrop.style.animation = `genericBackdropIn ${openAnimMs}ms ease-out`;
216
+ console.log(logPrefix, "ensureBackdrop: create", {
217
+ backdropClass,
218
+ backdropOpacity,
219
+ backdropBlurPx,
220
+ openAnimMs,
221
+ });
222
+ backdrop.addEventListener("click", () =>
223
+ requestClose(dialog, "backdrop")
224
+ );
225
+ dialog.insertAdjacentElement("afterend", backdrop);
226
+ };
227
+
228
+ const getBackdrop = (dialog) => {
229
+ const next = dialog.nextElementSibling;
230
+ if (next && next.classList?.contains("backdrop")) return next;
231
+ return null;
232
+ };
233
+
234
+ const removeBackdrop = (dialog) => {
235
+ const next = dialog.nextElementSibling;
236
+ if (next && next.classList?.contains("backdrop")) {
237
+ console.log(logPrefix, "removeBackdrop");
238
+ next.remove();
239
+ }
240
+ };
241
+
242
+ const closeNow = (dialog) => {
243
+ console.log(logPrefix, "closeNow");
244
+ if (typeof dialog.close === "function") {
245
+ dialog.close();
246
+ } else {
247
+ dialog.removeAttribute("open");
248
+ }
249
+ removeBackdrop(dialog);
250
+ document.removeEventListener("keydown", dialog.__genericDialogEscHandler);
251
+ dialog.__genericDialogEscHandler = undefined;
252
+ };
253
+
254
+ const requestClose = (dialog, reason = "unknown") => {
255
+ console.log(logPrefix, "requestClose", {
256
+ reason,
257
+ open: isOpen(dialog),
258
+ state: dialog.getAttribute("data-dialog-state"),
259
+ });
260
+ if (!isOpen(dialog)) return;
261
+ if (dialog.getAttribute("data-dialog-state") === "closing") return;
262
+ dialog.setAttribute("data-dialog-state", "closing");
263
+ const backdrop = getBackdrop(dialog);
264
+ backdrop?.setAttribute?.("data-dialog-state", "closing");
265
+ if (backdrop) {
266
+ backdrop.style.animation = `genericBackdropOut ${closeAnimMs}ms ease-in`;
267
+ }
268
+ window.setTimeout(() => {
269
+ dialog.removeAttribute("data-dialog-state");
270
+ closeNow(dialog);
271
+ }, closeAnimMs);
272
+ };
273
+
274
+ const ensureDialogBound = (dialog) => {
275
+ if (dialog.dataset.genericDialogBound) return;
276
+ dialog.dataset.genericDialogBound = "1";
277
+
278
+ console.log(logPrefix, "ensureDialogBound", {
279
+ closeSelector,
280
+ });
281
+
282
+ dialog.addEventListener("click", (e) => {
283
+ if (e.target === dialog) requestClose(dialog, "dialog_blank_area");
284
+ });
285
+
286
+ if (typeof dialog.addEventListener === "function") {
287
+ dialog.addEventListener("cancel", (e) => {
288
+ e.preventDefault();
289
+ requestClose(dialog, "cancel");
290
+ });
291
+ }
292
+
293
+ dialog
294
+ .querySelector(closeSelector)
295
+ ?.addEventListener("click", () =>
296
+ requestClose(dialog, "close_selector")
297
+ );
298
+ };
299
+
300
+ const open = () => {
301
+ const dialog = getDialog();
302
+ if (!dialog) return;
303
+ ensureDialogBound(dialog);
304
+ if (isOpen(dialog)) return;
305
+
306
+ try {
307
+ console.log(logPrefix, "open: start", {
308
+ forceFallback,
309
+ __force_dialog_fallback__: window.__force_dialog_fallback__,
310
+ hasShowModal: typeof dialog.showModal === "function",
311
+ });
312
+ const { scrollX, scrollY } = window;
313
+ dialog.removeAttribute("data-dialog-state");
314
+
315
+ const effectiveForceFallback =
316
+ forceFallback === true || window.__force_dialog_fallback__ === true;
317
+
318
+ if (!effectiveForceFallback && typeof dialog.showModal === "function") {
319
+ console.log(logPrefix, "open: native showModal");
320
+ dialog.showModal();
321
+ } else {
322
+ console.log(logPrefix, "open: fallback open attr + backdrop + esc");
323
+ ensureBackdrop(dialog);
324
+ dialog.setAttribute("open", "");
325
+ dialog.__genericDialogEscHandler = (e) => {
326
+ if (e.key === "Escape") requestClose(dialog, "esc");
327
+ };
328
+ document.addEventListener(
329
+ "keydown",
330
+ dialog.__genericDialogEscHandler
331
+ );
332
+ }
333
+
334
+ requestAnimationFrame(() => {
335
+ window.scrollTo(scrollX, scrollY);
336
+ try {
337
+ dialog.focus({ preventScroll: true });
338
+ } catch {
339
+ dialog.focus();
340
+ }
341
+ console.log(logPrefix, "open: focus done");
342
+ });
343
+ } catch (err) {
344
+ console.log(logPrefix, "open failed", err);
345
+ }
346
+ };
347
+
348
+ const init = () => {
349
+ console.log(logPrefix, "init", {
350
+ alreadyBound: w[globalKey].has(openableKey),
351
+ });
352
+ if (!w[globalKey].has(openableKey)) {
353
+ w[globalKey].add(openableKey);
354
+ document.addEventListener("click", (e) => {
355
+ const target = e.target;
356
+ if (!(target instanceof Element)) return;
357
+ const opener = target.closest(`[data-modal-open="${openableKey}"]`);
358
+ if (!opener) return;
359
+ const cta = opener.getAttribute("data-call-to-action") || "";
360
+ window.lastCta = cta;
361
+ console.log(logPrefix, "opener click -> open", {
362
+ cta,
363
+ openerTag: opener.tagName,
364
+ });
365
+ open();
366
+ });
367
+ }
368
+ };
369
+
370
+ init();
371
+ document.addEventListener("astro:page-load", init);
372
+ document.addEventListener("astro:after-swap", init);
373
+ })();
374
+ </script>
@@ -0,0 +1,26 @@
1
+ ---
2
+ interface Props {
3
+ dialogId: string;
4
+ callToAction?: string;
5
+ class?: string;
6
+ className?: string;
7
+ }
8
+
9
+ const {
10
+ dialogId,
11
+ callToAction,
12
+ class: _class,
13
+ className,
14
+ ...rest
15
+ } = Astro.props;
16
+ ---
17
+
18
+ <button
19
+ type="button"
20
+ data-modal-open={dialogId}
21
+ data-call-to-action={callToAction}
22
+ class:list={[className, _class]}
23
+ {...rest}
24
+ >
25
+ <slot />
26
+ </button>
@@ -0,0 +1,43 @@
1
+ ---
2
+ import type {
3
+ AnimationConfig,
4
+ BackgroundConfig,
5
+ } from "@rxdrag/website-lib-core";
6
+ import BackgroundGroup from "./BackgroundGroup.astro";
7
+ import Container from "./Container.astro";
8
+
9
+ /**
10
+ * 区块
11
+ */
12
+
13
+ interface Props {
14
+ class?: string;
15
+ className?: string;
16
+ containerClassName?: string;
17
+ backgrounds?: BackgroundConfig[];
18
+ //动效
19
+ animation?: AnimationConfig;
20
+ disableContainer?: boolean;
21
+ }
22
+
23
+ const {
24
+ className,
25
+ containerClassName,
26
+ backgrounds,
27
+ disableContainer,
28
+ class: originalClass,
29
+ } = Astro.props;
30
+ ---
31
+
32
+ <footer class:list={["footer-block relative", className, originalClass]}>
33
+ <BackgroundGroup backgrounds={backgrounds} />
34
+ {
35
+ disableContainer ? (
36
+ <slot />
37
+ ) : (
38
+ <Container class:list={["w-full h-full", containerClassName]}>
39
+ <slot />
40
+ </Container>
41
+ )
42
+ }
43
+ </footer>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type {
3
+ AnimationConfig,
4
+ BackgroundConfig,
5
+ } from "@rxdrag/website-lib-core";
6
+ import BackgroundGroup from "./BackgroundGroup.astro";
7
+
8
+ interface Props {
9
+ //布局方案名称,设计qi'yong
10
+ patternName?: string;
11
+ class?: string;
12
+ className?: string;
13
+ backgrounds?: BackgroundConfig[];
14
+ //动效
15
+ animation?: AnimationConfig;
16
+ }
17
+
18
+ const { className, class: originalClass, backgrounds } = Astro.props;
19
+
20
+ //布局容器
21
+ ---
22
+
23
+ <div class:list={["relative grid gap-12", className, originalClass]}>
24
+ <BackgroundGroup backgrounds={backgrounds} />
25
+ <slot />
26
+ </div>
@@ -0,0 +1,22 @@
1
+ ---
2
+ import type {
3
+ AnimationConfig,
4
+ BackgroundConfig,
5
+ } from "@rxdrag/website-lib-core";
6
+ import BackgroundGroup from "./BackgroundGroup.astro";
7
+
8
+ interface Props {
9
+ class?: string;
10
+ className?: string;
11
+ backgrounds?: BackgroundConfig[];
12
+ //动效
13
+ animation?: AnimationConfig;
14
+ }
15
+
16
+ const { className, class: originalClass, backgrounds } = Astro.props;
17
+ ---
18
+
19
+ <div class:list={["w-full h-full flex flex-col", className, originalClass]}>
20
+ <BackgroundGroup backgrounds={backgrounds} />
21
+ <slot />
22
+ </div>
@@ -0,0 +1,43 @@
1
+ ---
2
+ import type {
3
+ AnimationConfig,
4
+ BackgroundConfig,
5
+ } from "@rxdrag/website-lib-core";
6
+ import BackgroundGroup from "./BackgroundGroup.astro";
7
+ import Container from "./Container.astro";
8
+
9
+ /**
10
+ * 区块
11
+ */
12
+
13
+ interface Props {
14
+ class?: string;
15
+ className?: string;
16
+ containerClassName?: string;
17
+ backgrounds?: BackgroundConfig[];
18
+ //动效
19
+ animation?: AnimationConfig;
20
+ disableContainer?: boolean;
21
+ }
22
+
23
+ const {
24
+ className,
25
+ containerClassName,
26
+ backgrounds,
27
+ disableContainer,
28
+ class: originalClass,
29
+ } = Astro.props;
30
+ ---
31
+
32
+ <header class:list={["header-block", className, originalClass]}>
33
+ <BackgroundGroup backgrounds={backgrounds} />
34
+ {
35
+ disableContainer ? (
36
+ <slot />
37
+ ) : (
38
+ <Container class:list={["w-full h-full", containerClassName]}>
39
+ <slot />
40
+ </Container>
41
+ )
42
+ }
43
+ </header>
@@ -0,0 +1,30 @@
1
+ ---
2
+ import {
3
+ Icon as CoreIcon,
4
+ Entify,
5
+ type Locals,
6
+ } from "@rxdrag/website-lib-core";
7
+
8
+ interface Props {
9
+ className?: string;
10
+ icon?: string;
11
+ svg?: string;
12
+ }
13
+ const { env, imageSizes } = Astro.locals as Locals;
14
+ const { className, icon, svg, ...rest } = Astro.props;
15
+
16
+ const localIconName = icon?.startsWith("local:") ? icon?.split(":")[1] : null;
17
+
18
+ const rx = Entify.getInstance(env, imageSizes);
19
+
20
+ const svgIcon =
21
+ !!rx && localIconName ? await rx.getIcon(localIconName) : undefined;
22
+ ---
23
+
24
+ <CoreIcon
25
+ className={className}
26
+ icon={localIconName ? undefined : icon}
27
+ svg={svgIcon?.code || svg}
28
+ {...rest}
29
+ client:only="react"
30
+ />
@@ -0,0 +1,18 @@
1
+ ---
2
+ import { Entify, type ImageProps, type Locals } from "@rxdrag/website-lib-core";
3
+ const { env, imageSizes } = Astro.locals as Locals;
4
+
5
+ interface Props extends ImageProps {}
6
+
7
+ const { mediaRef, fileField, resize, className, ...props } = Astro.props;
8
+
9
+ const rx = Entify.getInstance(env, imageSizes);
10
+
11
+ const media = rx ? await rx.getMedia(mediaRef, fileField, resize) : undefined;
12
+ ---
13
+
14
+ <img
15
+ src={fileField ? media?.file?.[fileField] : media?.file?.original || ""}
16
+ class={className}
17
+ {...props}
18
+ />
@@ -0,0 +1,71 @@
1
+ ---
2
+ import {
3
+ toHref,
4
+ type LinkType,
5
+ } from "@rxdrag/website-lib-core";
6
+
7
+ import type { HTMLAttributes } from "astro/types";
8
+
9
+ interface Props extends HTMLAttributes<"a"> {
10
+ type?: LinkType | string;
11
+ to?: string | undefined;
12
+ class?: string;
13
+ className?: string;
14
+ //用于active类名的传递
15
+ activeWhen?: string | true;
16
+
17
+ options?: {
18
+ productsSlug?: string;
19
+ postsSlug?: string;
20
+ };
21
+ }
22
+
23
+ const {
24
+ type,
25
+ to,
26
+ class: cls,
27
+ className,
28
+ activeWhen,
29
+ options,
30
+ ...props
31
+ } = Astro.props;
32
+ const href = toHref(type || "", to || "", options);
33
+ const hrefObj = href ? { href } : {};
34
+ ---
35
+
36
+ <a
37
+ data-actived-path={activeWhen}
38
+ {...hrefObj}
39
+ class:list={[cls, className]}
40
+ {...props}
41
+ >
42
+ <slot />
43
+ </a>
44
+
45
+ <script is:inline>
46
+ import { initLinks } from "@rxdrag/website-lib-core";
47
+
48
+ (() => {
49
+ const bindAstroLifecycle = (key, fn) => {
50
+ const w = window;
51
+ const bound = (w.__astro_lifecycle_bound__ ||= Object.create(null));
52
+ if (bound[key]) return;
53
+ bound[key] = true;
54
+
55
+ const boot = () => fn();
56
+
57
+ if (document.readyState === "loading") {
58
+ document.addEventListener("DOMContentLoaded", boot, { once: true });
59
+ } else {
60
+ boot();
61
+ }
62
+
63
+ document.addEventListener("astro:page-load", boot);
64
+ document.addEventListener("astro:after-swap", boot);
65
+ };
66
+
67
+ bindAstroLifecycle("website-lib:init-links", () => {
68
+ initLinks();
69
+ });
70
+ })();
71
+ </script>