@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.
@@ -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
+ };
@@ -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