@windstream/react-shared-components 0.2.78 → 0.2.80
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/dist/contentful/index.d.ts +29 -3
- package/dist/contentful/index.esm.js +2 -2
- package/dist/contentful/index.esm.js.map +1 -1
- package/dist/contentful/index.js +2 -2
- package/dist/contentful/index.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/contentful/blocks/cards/product-card/index.tsx +11 -3
- package/src/contentful/blocks/cards/product-card/types.ts +11 -0
- package/src/contentful/blocks/carousel/helper.tsx +1 -0
- package/src/contentful/blocks/carousel/index.tsx +8 -1
- package/src/contentful/blocks/carousel/types.ts +15 -0
- package/src/contentful/blocks/links-block/index.test.tsx +79 -0
- package/src/contentful/blocks/links-block/index.tsx +52 -0
- package/src/contentful/blocks/links-block/types.ts +24 -0
- package/src/contentful/index.ts +7 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { ReactNode } from "react";
|
|
2
2
|
|
|
3
3
|
import { CheckPlansProps } from "@shared/types/micro-components";
|
|
4
|
+
import type { FieldProps } from "@shared/types/field-props";
|
|
4
5
|
|
|
5
6
|
export interface carouselFieldsInterface {
|
|
6
7
|
__typename: "ComponentCarousel";
|
|
@@ -85,6 +86,18 @@ export interface ProductCardFields {
|
|
|
85
86
|
url: string;
|
|
86
87
|
[key: string]: any;
|
|
87
88
|
};
|
|
89
|
+
/** Pre-computed per-field Inspector Mode / Live Preview DOM attributes for
|
|
90
|
+
* this item, supplied by the consumer and passed through to the rendered
|
|
91
|
+
* ProductCard unchanged. The library itself stays CMS-agnostic. */
|
|
92
|
+
fieldProps?: FieldProps<
|
|
93
|
+
| "planName"
|
|
94
|
+
| "planSubtext"
|
|
95
|
+
| "price"
|
|
96
|
+
| "priceSuffixBottom"
|
|
97
|
+
| "description"
|
|
98
|
+
| "bestValueText"
|
|
99
|
+
| "featuresTitle"
|
|
100
|
+
>;
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
export interface CardFields {
|
|
@@ -148,6 +161,8 @@ export type CarouselProps = {
|
|
|
148
161
|
event: React.MouseEvent<HTMLElement>
|
|
149
162
|
) => void;
|
|
150
163
|
enableBusinessSettings?: boolean;
|
|
164
|
+
/** Extra DOM attribute props, spread onto the respective rendered elements. */
|
|
165
|
+
fieldProps?: FieldProps<"title" | "subTitle" | "disclaimerText">;
|
|
151
166
|
};
|
|
152
167
|
|
|
153
168
|
export interface TabSwitchProps {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import { LinksBlock } from "./index";
|
|
5
|
+
import { LinksBlockLink } from "./types";
|
|
6
|
+
|
|
7
|
+
const links: LinksBlockLink[] = [
|
|
8
|
+
{
|
|
9
|
+
id: "1",
|
|
10
|
+
title: "Internet Plans",
|
|
11
|
+
href: "/internet",
|
|
12
|
+
target: "_self",
|
|
13
|
+
buttonVariant: "primary_brand",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "2",
|
|
17
|
+
title: "Help Center",
|
|
18
|
+
href: "https://help.example.com",
|
|
19
|
+
target: "_blank",
|
|
20
|
+
buttonVariant: "secondary",
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
describe("LinksBlock", () => {
|
|
25
|
+
it("renders nothing when there are no links", () => {
|
|
26
|
+
const { container } = render(<LinksBlock title="Quick Links" links={[]} />);
|
|
27
|
+
|
|
28
|
+
expect(container).toBeEmptyDOMElement();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("renders nothing when links is undefined", () => {
|
|
32
|
+
const { container } = render(<LinksBlock />);
|
|
33
|
+
|
|
34
|
+
expect(container).toBeEmptyDOMElement();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("renders the title", () => {
|
|
38
|
+
render(<LinksBlock title="Quick Links" links={links} />);
|
|
39
|
+
|
|
40
|
+
expect(
|
|
41
|
+
screen.getByRole("heading", { level: 3, name: "Quick Links" })
|
|
42
|
+
).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("renders a link for each item with its href and target", () => {
|
|
46
|
+
render(<LinksBlock links={links} />);
|
|
47
|
+
|
|
48
|
+
const internet = screen.getByRole("link", { name: "Internet Plans" });
|
|
49
|
+
expect(internet).toHaveAttribute("href", "/internet");
|
|
50
|
+
expect(internet).toHaveAttribute("target", "_self");
|
|
51
|
+
|
|
52
|
+
const help = screen.getByRole("link", { name: "Help Center" });
|
|
53
|
+
expect(help).toHaveAttribute("href", "https://help.example.com");
|
|
54
|
+
expect(help).toHaveAttribute("target", "_blank");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("defaults the target to _self when not provided", () => {
|
|
58
|
+
render(
|
|
59
|
+
<LinksBlock
|
|
60
|
+
links={[{ id: "3", title: "Pricing", href: "/pricing" }]}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
expect(screen.getByRole("link", { name: "Pricing" })).toHaveAttribute(
|
|
65
|
+
"target",
|
|
66
|
+
"_self"
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("calls onLinkClick with the clicked link", () => {
|
|
71
|
+
const onLinkClick = jest.fn();
|
|
72
|
+
render(<LinksBlock links={links} onLinkClick={onLinkClick} />);
|
|
73
|
+
|
|
74
|
+
fireEvent.click(screen.getByRole("link", { name: "Help Center" }));
|
|
75
|
+
|
|
76
|
+
expect(onLinkClick).toHaveBeenCalledTimes(1);
|
|
77
|
+
expect(onLinkClick.mock.calls[0][0]).toEqual(links[1]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
import { Button } from "@shared/contentful/blocks/button";
|
|
6
|
+
import { Text } from "@shared/components/text";
|
|
7
|
+
import { cx } from "@shared/utils";
|
|
8
|
+
|
|
9
|
+
import { LinksBlockProps } from "./types";
|
|
10
|
+
|
|
11
|
+
export const LinksBlock: React.FC<LinksBlockProps> = ({
|
|
12
|
+
title,
|
|
13
|
+
links,
|
|
14
|
+
onLinkClick,
|
|
15
|
+
className,
|
|
16
|
+
}) => {
|
|
17
|
+
if (!links || links.length === 0) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
data-section-name="Links Block"
|
|
24
|
+
className={cx(
|
|
25
|
+
"w-full rounded-[20px] px-6 py-7 lg:border-2 lg:border-secondary-gray300 lg:shadow-lg",
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
{title && (
|
|
30
|
+
<Text as="h3" className="heading6 mb-4">
|
|
31
|
+
{title}
|
|
32
|
+
</Text>
|
|
33
|
+
)}
|
|
34
|
+
<div className="flex flex-col gap-3">
|
|
35
|
+
{links.map(link => (
|
|
36
|
+
<Button
|
|
37
|
+
key={link.id}
|
|
38
|
+
showButtonAs="solid"
|
|
39
|
+
buttonVariant={link.buttonVariant ?? "secondary"}
|
|
40
|
+
buttonLabel={link.title?.trim() || link.href}
|
|
41
|
+
href={link.href}
|
|
42
|
+
target={link.target ?? "_self"}
|
|
43
|
+
fullWidth
|
|
44
|
+
onClick={event => onLinkClick?.(link, event)}
|
|
45
|
+
/>
|
|
46
|
+
))}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default LinksBlock;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
|
|
3
|
+
import type { ButtonProps } from "@shared/contentful/blocks/button/types";
|
|
4
|
+
|
|
5
|
+
export type LinksBlockButtonVariant = NonNullable<ButtonProps["buttonVariant"]>;
|
|
6
|
+
|
|
7
|
+
export type LinksBlockLink = {
|
|
8
|
+
id: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
href: string;
|
|
11
|
+
target?: "_self" | "_blank";
|
|
12
|
+
buttonVariant?: LinksBlockButtonVariant;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type LinksBlockProps = {
|
|
16
|
+
title?: string;
|
|
17
|
+
links?: LinksBlockLink[];
|
|
18
|
+
/** Fired when a link is clicked, e.g. to publish analytics events */
|
|
19
|
+
onLinkClick?: (
|
|
20
|
+
link: LinksBlockLink,
|
|
21
|
+
event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement>
|
|
22
|
+
) => void;
|
|
23
|
+
className?: string;
|
|
24
|
+
};
|
package/src/contentful/index.ts
CHANGED
|
@@ -45,6 +45,13 @@ export type { TextProps } from "./blocks/text/types";
|
|
|
45
45
|
export { Button } from "./blocks/button";
|
|
46
46
|
export type { ButtonProps } from "./blocks/button/types";
|
|
47
47
|
|
|
48
|
+
export { LinksBlock } from "./blocks/links-block";
|
|
49
|
+
export type {
|
|
50
|
+
LinksBlockProps,
|
|
51
|
+
LinksBlockLink,
|
|
52
|
+
LinksBlockButtonVariant,
|
|
53
|
+
} from "./blocks/links-block/types";
|
|
54
|
+
|
|
48
55
|
export { Modal } from "./blocks/modal";
|
|
49
56
|
export type { ModalProps } from "./blocks/modal/types";
|
|
50
57
|
|