@rxdrag/website-lib-core 0.0.8 → 0.0.10
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/package.json +4 -4
- package/src/component-logic/collapse.ts +61 -0
- package/src/component-logic/index.ts +1 -0
- package/src/component-logic/modal.ts +14 -14
- package/src/component-logic/motion.ts +7 -7
- package/src/component-logic/popover.ts +9 -9
- package/src/controller/CollapseController.ts +130 -0
- package/src/controller/ModalController.ts +19 -19
- package/src/controller/{popup.ts → OpenableController.ts} +53 -37
- package/src/controller/PageLoader.ts +3 -13
- package/src/controller/PopoverController.ts +13 -13
- package/src/controller/TabsController.ts +1 -1
- package/src/controller/consts.ts +9 -6
- package/src/controller/index.ts +1 -0
- package/src/entify/IEntify.ts +1 -1
- package/src/entify/lib/newQueryProductOptions.ts +2 -11
- package/src/entify/lib/queryOneProductBySlug.ts +52 -10
- package/src/entify/lib/queryOneTheme.ts +1 -7
- package/src/entify/view-model/funcs.ts +0 -16
- package/src/lib/utils.ts +30 -14
- package/src/motion/consts.ts +3 -3
- package/src/motion/normalizePopupAnimation.ts +3 -3
- package/src/motion/types.ts +1 -1
- package/src/react/components/ContactForm/index.tsx +13 -5
- package/src/react/components/Icon/index.tsx +8 -4
- package/src/react/components/ProductCard/ProductCard.tsx +2 -1
- package/src/react/components/ProductCard/ProductCta/index.tsx +13 -12
- package/src/react/components/ProductCard/ProductView.tsx +3 -2
- package/src/react/components/ToTop/index.tsx +1 -1
- package/src/react/components/ToTop.tsx +1 -1
- package/src/react/hooks/useScroll.ts +12 -11
|
@@ -92,6 +92,13 @@ export type ContactFormProps = {
|
|
|
92
92
|
submitAlign?: "left" | "center" | "right";
|
|
93
93
|
actionUrl?: string;
|
|
94
94
|
formSalt: string;
|
|
95
|
+
labels?: {
|
|
96
|
+
name?: string;
|
|
97
|
+
email?: string;
|
|
98
|
+
company?: string;
|
|
99
|
+
message?: string;
|
|
100
|
+
submit?: string;
|
|
101
|
+
};
|
|
95
102
|
};
|
|
96
103
|
|
|
97
104
|
export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
@@ -100,6 +107,7 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
100
107
|
submitAlign = "right",
|
|
101
108
|
actionUrl = "/api/ask-for-quote",
|
|
102
109
|
formSalt,
|
|
110
|
+
labels = {},
|
|
103
111
|
} = props;
|
|
104
112
|
const [formData, setFormData] = useState<QuoteRequest>({
|
|
105
113
|
name: "",
|
|
@@ -256,7 +264,7 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
256
264
|
<Input
|
|
257
265
|
className="sm:col-span-1"
|
|
258
266
|
inputClassName="mt-2 block w-full rounded-md outline-none border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6"
|
|
259
|
-
label="Your Email *"
|
|
267
|
+
label={(labels?.email || "Your Email") + " *"}
|
|
260
268
|
labelClassName="block text-sm font-medium leading-6 text-gray-900"
|
|
261
269
|
name="email"
|
|
262
270
|
required={true}
|
|
@@ -269,7 +277,7 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
269
277
|
<Input
|
|
270
278
|
className="sm:col-span-1"
|
|
271
279
|
inputClassName="mt-2 block w-full rounded-md outline-none border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6"
|
|
272
|
-
label="Your Name"
|
|
280
|
+
label={(labels?.name || "Your Name") + " *"}
|
|
273
281
|
labelClassName="block text-sm font-medium leading-6 text-gray-900"
|
|
274
282
|
name="name"
|
|
275
283
|
value={formData.name}
|
|
@@ -279,7 +287,7 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
279
287
|
<Input
|
|
280
288
|
className="col-span-full"
|
|
281
289
|
inputClassName="mt-2 block w-full rounded-md outline-none border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6"
|
|
282
|
-
label="Company"
|
|
290
|
+
label={(labels?.company || "Company") + " *"}
|
|
283
291
|
labelClassName="block text-sm font-medium leading-6 text-gray-900"
|
|
284
292
|
name="company"
|
|
285
293
|
value={formData.company}
|
|
@@ -287,7 +295,7 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
287
295
|
/>
|
|
288
296
|
<Textarea
|
|
289
297
|
className="col-span-full"
|
|
290
|
-
label="Message *"
|
|
298
|
+
label={(labels?.message || "Message") + " *"}
|
|
291
299
|
labelClassName="block text-sm font-medium leading-6 text-gray-900"
|
|
292
300
|
name="message"
|
|
293
301
|
required={true}
|
|
@@ -325,7 +333,7 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
325
333
|
)}
|
|
326
334
|
<Submit
|
|
327
335
|
className="flex gap-2 items-center relative shadow-sm btn btn-primary btn-lg nowrap"
|
|
328
|
-
title="Send Message"
|
|
336
|
+
title={labels?.submit || "Send Message"}
|
|
329
337
|
spinner={
|
|
330
338
|
<div className="left-8 flex items-center justify-center">
|
|
331
339
|
<div className="animate-spin rounded-full h-5 w-5 border-t-2 border-b-2 border-white" />
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Icon as IconifyIcon,
|
|
3
|
+
IconProps as IconifyIconProps,
|
|
4
|
+
} from "@iconify/react";
|
|
5
|
+
import { forwardRef } from "react";
|
|
2
6
|
|
|
3
7
|
export type IconProps = Omit<IconifyIconProps, "icon"> & {
|
|
4
8
|
icon?: string;
|
|
5
9
|
};
|
|
6
10
|
|
|
7
|
-
export
|
|
11
|
+
export const Icon = forwardRef<SVGSVGElement, IconProps>((props, ref) => {
|
|
8
12
|
const { icon, ...rest } = props;
|
|
9
|
-
return icon ? <IconifyIcon {...rest} icon={icon} /> : null;
|
|
10
|
-
}
|
|
13
|
+
return icon ? <IconifyIcon ref={ref} {...rest} icon={icon} /> : null;
|
|
14
|
+
});
|
|
@@ -8,6 +8,7 @@ export type TSlateProduct = TSlateResizable & {
|
|
|
8
8
|
title?: string;
|
|
9
9
|
description?: string;
|
|
10
10
|
aspect?: string;
|
|
11
|
+
ctaTitle?: string;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
export const PRODUCT_KEY = "Product";
|
|
@@ -19,5 +20,5 @@ export type ProductCardProps = {
|
|
|
19
20
|
|
|
20
21
|
// Slate用的渲染组件
|
|
21
22
|
export const ProductCard = ({ node }: ProductCardProps) => {
|
|
22
|
-
return <ProductView product={node?.product} node={node} />;
|
|
23
|
+
return <ProductView product={node?.product} node={node} ctaTitle={node?.ctaTitle}/>;
|
|
23
24
|
};
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
import { Product } from "@rxdrag/rxcms-models";
|
|
2
2
|
import "./style.css";
|
|
3
3
|
import {
|
|
4
|
-
|
|
4
|
+
DATA_OPENABLE,
|
|
5
5
|
DATA_POPUP_CTA,
|
|
6
|
-
|
|
6
|
+
DATA_OPENABLE_ROLE,
|
|
7
7
|
popover,
|
|
8
|
-
|
|
8
|
+
OpenAble,
|
|
9
9
|
} from "../../../../controller";
|
|
10
10
|
import { useRef } from "react";
|
|
11
11
|
|
|
12
12
|
//TODO: 跟询盘触发器同样的实现原理,给询盘对话框发消息
|
|
13
|
-
export function ProductCta(props: {
|
|
14
|
-
|
|
13
|
+
export function ProductCta(props: {
|
|
14
|
+
product?: Product;
|
|
15
|
+
openableKey?: string;
|
|
16
|
+
children?: React.ReactNode;
|
|
17
|
+
}) {
|
|
18
|
+
const { product, openableKey = "enquiry-modal", children } = props;
|
|
15
19
|
const ref = useRef<HTMLButtonElement>(null);
|
|
16
20
|
const roleProps = {
|
|
17
21
|
[DATA_POPUP_CTA]: `From RichText ProductCard-${product?.title}-${product?.id}`,
|
|
18
|
-
[
|
|
19
|
-
[
|
|
22
|
+
[DATA_OPENABLE_ROLE]: OpenAble.ModalTrigger,
|
|
23
|
+
[DATA_OPENABLE]: openableKey,
|
|
20
24
|
};
|
|
21
25
|
|
|
22
26
|
const handleClick = () => {
|
|
23
27
|
if (ref.current) {
|
|
24
|
-
popover.open(
|
|
25
|
-
roleProps[DATA_POPUP_CTA] || popupKey,
|
|
26
|
-
ref.current
|
|
27
|
-
);
|
|
28
|
+
popover.open(roleProps[DATA_POPUP_CTA] || openableKey, ref.current);
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
31
|
|
|
@@ -36,7 +37,7 @@ export function ProductCta(props: { product?: Product; popupKey?: string }) {
|
|
|
36
37
|
className="product-cta-button relative flex-1 mt-2 flex items-center justify-center rounded-md border border-transparent bg-sky-600 text-md font-smibold text-white hover:bg-sky-700"
|
|
37
38
|
onClick={handleClick}
|
|
38
39
|
>
|
|
39
|
-
Get a quote
|
|
40
|
+
{children || "Get a quote"}
|
|
40
41
|
</button>
|
|
41
42
|
</div>
|
|
42
43
|
);
|
|
@@ -9,9 +9,10 @@ import { ProductCta } from "./ProductCta";
|
|
|
9
9
|
export function ProductView(
|
|
10
10
|
props: {
|
|
11
11
|
product?: Product;
|
|
12
|
+
ctaTitle?: string;
|
|
12
13
|
} & ProductCardProps
|
|
13
14
|
) {
|
|
14
|
-
const { product, node } = props;
|
|
15
|
+
const { product, ctaTitle, node } = props;
|
|
15
16
|
|
|
16
17
|
const title = node?.title || product?.title;
|
|
17
18
|
const description = node?.description || product?.description;
|
|
@@ -28,7 +29,7 @@ export function ProductView(
|
|
|
28
29
|
<ProductTitle>{title}</ProductTitle>
|
|
29
30
|
</a>
|
|
30
31
|
<ProductDescription>{description}</ProductDescription>
|
|
31
|
-
<ProductCta product={product}
|
|
32
|
+
<ProductCta product={product}>{ctaTitle}</ProductCta>
|
|
32
33
|
</Figcaption>
|
|
33
34
|
</Figure>
|
|
34
35
|
);
|
|
@@ -17,7 +17,7 @@ export const ToTop = forwardRef<HTMLDivElement, ToTopProps>((
|
|
|
17
17
|
ref={ref}
|
|
18
18
|
className={
|
|
19
19
|
clsx(
|
|
20
|
-
"fixed bottom-4 right-4 hidden user-select-none
|
|
20
|
+
"fixed bottom-4 right-4 hidden user-select-none scrolled:flex cursor-pointer transition duration-300 ease-in-out z-50",
|
|
21
21
|
className,
|
|
22
22
|
)
|
|
23
23
|
}
|
|
@@ -56,7 +56,7 @@ export const ToTop = forwardRef<HTMLDivElement, ToTopProps>((props, ref) => {
|
|
|
56
56
|
<div
|
|
57
57
|
ref={innerRef}
|
|
58
58
|
className={clsx(
|
|
59
|
-
"fixed bottom-4 right-4 hidden user-select-none shadow-lg
|
|
59
|
+
"fixed bottom-4 right-4 hidden user-select-none shadow-lg scrolled:flex cursor-pointer transition duration-300 ease-in-out z-50",
|
|
60
60
|
className
|
|
61
61
|
)}
|
|
62
62
|
{...rest}
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
import { useCallback, useEffect } from "react";
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const defaultThreshold = 10;
|
|
4
4
|
|
|
5
5
|
export function useScroll(
|
|
6
|
-
threshold: number =
|
|
7
|
-
win: Window | undefined = typeof window !==
|
|
8
|
-
doc: Document | undefined = typeof document !==
|
|
6
|
+
threshold: number = defaultThreshold,
|
|
7
|
+
win: Window | undefined = typeof window !== "undefined" ? window : undefined,
|
|
8
|
+
doc: Document | undefined = typeof document !== "undefined"
|
|
9
|
+
? document
|
|
10
|
+
: undefined
|
|
9
11
|
) {
|
|
10
|
-
|
|
11
12
|
const onScroll = useCallback(() => {
|
|
12
13
|
if (!win || !doc) return;
|
|
13
|
-
|
|
14
|
-
const scrolling = win.scrollY > threshold;
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const scrolled = win.scrollY > threshold;
|
|
16
|
+
|
|
17
|
+
if (scrolled) {
|
|
18
|
+
doc.body.classList.add("scrolled");
|
|
18
19
|
} else {
|
|
19
|
-
doc.body.classList.remove("
|
|
20
|
+
doc.body.classList.remove("scrolled");
|
|
20
21
|
}
|
|
21
22
|
}, [threshold, win, doc]);
|
|
22
23
|
|
|
23
24
|
useEffect(() => {
|
|
24
25
|
if (!win) return;
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
win.addEventListener("scroll", onScroll);
|
|
27
28
|
return () => win.removeEventListener("scroll", onScroll);
|
|
28
29
|
}, [onScroll, win]);
|