@windstream/react-shared-components 0.1.77 → 0.1.79
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 +8 -2
- package/dist/contentful/index.esm.js +3 -3
- 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/styles.css +1 -1
- package/package.json +1 -1
- package/src/contentful/blocks/blogs-grid/BlogGrid.stories.mocks.tsx +144 -0
- package/src/contentful/blocks/blogs-grid/BlogGrid.stories.tsx +156 -0
- package/src/contentful/blocks/breadcrumbs/BreadcrumbNavigation.stories.tsx +147 -0
- package/src/contentful/blocks/breadcrumbs/index.tsx +30 -16
- package/src/contentful/blocks/breadcrumbs/types.ts +3 -1
- package/src/contentful/blocks/callout/index.tsx +54 -41
- package/src/contentful/blocks/callout/types.ts +5 -1
- package/src/contentful/blocks/navigation/index.tsx +2 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_ARTICLES,
|
|
3
|
+
ARTICLES_WITH_COVERS,
|
|
4
|
+
ARTICLES_WITHOUT_COVERS,
|
|
5
|
+
CATEGORY_OPTIONS,
|
|
6
|
+
} from "./BlogGrid.stories.mocks";
|
|
7
|
+
import { BlogGrid } from "./index";
|
|
8
|
+
import type { BlogGridProps } from "./types";
|
|
9
|
+
|
|
10
|
+
import { DocsPage } from "@shared/stories/DocsTemplate";
|
|
11
|
+
import type { ArgTypes, Meta, StoryObj } from "@storybook/react";
|
|
12
|
+
|
|
13
|
+
/* ------------
|
|
14
|
+
ArgTypes
|
|
15
|
+
--------------- */
|
|
16
|
+
|
|
17
|
+
const argTypes: ArgTypes<BlogGridProps> = {
|
|
18
|
+
paginatedArticles: {
|
|
19
|
+
control: { type: "object" as const },
|
|
20
|
+
description: "Array of blog articles to display on the current page",
|
|
21
|
+
},
|
|
22
|
+
totalArticles: {
|
|
23
|
+
control: { type: "number" as const },
|
|
24
|
+
description: "Total number of articles across all pages",
|
|
25
|
+
},
|
|
26
|
+
currentPage: {
|
|
27
|
+
control: { type: "number" as const },
|
|
28
|
+
description: "Current active page number",
|
|
29
|
+
},
|
|
30
|
+
totalPages: {
|
|
31
|
+
control: { type: "number" as const },
|
|
32
|
+
description: "Total number of pages",
|
|
33
|
+
},
|
|
34
|
+
selectedCategory: {
|
|
35
|
+
control: { type: "object" as const },
|
|
36
|
+
description: "Currently selected category option",
|
|
37
|
+
},
|
|
38
|
+
categoryOptions: {
|
|
39
|
+
control: { type: "object" as const },
|
|
40
|
+
description: "Available category filter options",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/* --------
|
|
45
|
+
Meta
|
|
46
|
+
----------- */
|
|
47
|
+
|
|
48
|
+
const meta: Meta<typeof BlogGrid> = {
|
|
49
|
+
title: "Contentful Blocks/BlogGrid",
|
|
50
|
+
component: BlogGrid,
|
|
51
|
+
tags: ["autodocs"],
|
|
52
|
+
argTypes,
|
|
53
|
+
parameters: {
|
|
54
|
+
layout: "fullscreen",
|
|
55
|
+
docs: {
|
|
56
|
+
page: DocsPage,
|
|
57
|
+
description: {
|
|
58
|
+
component:
|
|
59
|
+
"A paginated, filterable grid of blog article cards with a category dropdown, article count summary, and pagination controls.",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
args: {
|
|
64
|
+
paginatedArticles: ARTICLES_WITH_COVERS,
|
|
65
|
+
totalArticles: ALL_ARTICLES.length,
|
|
66
|
+
currentPage: 1,
|
|
67
|
+
totalPages: 2,
|
|
68
|
+
selectedCategory: CATEGORY_OPTIONS[0],
|
|
69
|
+
categoryOptions: CATEGORY_OPTIONS,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default meta;
|
|
74
|
+
type Story = StoryObj<typeof meta>;
|
|
75
|
+
|
|
76
|
+
/* --------
|
|
77
|
+
Stories
|
|
78
|
+
----------- */
|
|
79
|
+
|
|
80
|
+
export const Default: Story = {};
|
|
81
|
+
|
|
82
|
+
export const WithPagination: Story = {
|
|
83
|
+
args: {
|
|
84
|
+
paginatedArticles: ARTICLES_WITH_COVERS,
|
|
85
|
+
totalArticles: 18,
|
|
86
|
+
currentPage: 2,
|
|
87
|
+
totalPages: 3,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const SinglePage: Story = {
|
|
92
|
+
args: {
|
|
93
|
+
paginatedArticles: ARTICLES_WITH_COVERS,
|
|
94
|
+
totalArticles: 6,
|
|
95
|
+
currentPage: 1,
|
|
96
|
+
totalPages: 1,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const EmptyState: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
paginatedArticles: [],
|
|
103
|
+
totalArticles: 9,
|
|
104
|
+
currentPage: 1,
|
|
105
|
+
totalPages: 1,
|
|
106
|
+
selectedCategory: CATEGORY_OPTIONS[1],
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const CategoryFilterActive: Story = {
|
|
111
|
+
args: {
|
|
112
|
+
paginatedArticles: ALL_ARTICLES.filter(
|
|
113
|
+
(a) => a.category === "Technology",
|
|
114
|
+
),
|
|
115
|
+
totalArticles: 4,
|
|
116
|
+
currentPage: 1,
|
|
117
|
+
totalPages: 1,
|
|
118
|
+
selectedCategory: CATEGORY_OPTIONS[1],
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const WithCoverImages: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
paginatedArticles: ARTICLES_WITH_COVERS,
|
|
125
|
+
totalArticles: 6,
|
|
126
|
+
currentPage: 1,
|
|
127
|
+
totalPages: 1,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const WithoutCoverImages: Story = {
|
|
132
|
+
args: {
|
|
133
|
+
paginatedArticles: ARTICLES_WITHOUT_COVERS,
|
|
134
|
+
totalArticles: 3,
|
|
135
|
+
currentPage: 1,
|
|
136
|
+
totalPages: 1,
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export const MixedCoverImages: Story = {
|
|
141
|
+
args: {
|
|
142
|
+
paginatedArticles: [...ARTICLES_WITH_COVERS.slice(4), ...ARTICLES_WITHOUT_COVERS],
|
|
143
|
+
totalArticles: 5,
|
|
144
|
+
currentPage: 1,
|
|
145
|
+
totalPages: 1,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const SingleArticle: Story = {
|
|
150
|
+
args: {
|
|
151
|
+
paginatedArticles: [ARTICLES_WITH_COVERS[0]],
|
|
152
|
+
totalArticles: 1,
|
|
153
|
+
currentPage: 1,
|
|
154
|
+
totalPages: 1,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { BreadcrumbNavigation } from "./index";
|
|
2
|
+
|
|
3
|
+
import { DocsPage } from "@shared/stories/DocsTemplate";
|
|
4
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof BreadcrumbNavigation> = {
|
|
7
|
+
title: "Contentful Blocks/Breadcrumb",
|
|
8
|
+
component: BreadcrumbNavigation,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "fullscreen",
|
|
12
|
+
docs: {
|
|
13
|
+
page: DocsPage,
|
|
14
|
+
description: {
|
|
15
|
+
component:
|
|
16
|
+
"Breadcrumb navigation component used to display the user's location within the site hierarchy.",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
args: {
|
|
21
|
+
textColor: "dark",
|
|
22
|
+
mobileTextColor: undefined,
|
|
23
|
+
desktopTextColor: undefined,
|
|
24
|
+
maxWidth: true,
|
|
25
|
+
float: "desktop",
|
|
26
|
+
links: [
|
|
27
|
+
{ buttonLabel: "Home", href: "/" },
|
|
28
|
+
{ buttonLabel: "Category", href: "/category" },
|
|
29
|
+
{ buttonLabel: "Current Page" },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
argTypes: {
|
|
33
|
+
links: { control: "object" },
|
|
34
|
+
textColor: {
|
|
35
|
+
control: "radio",
|
|
36
|
+
options: ["dark", "light"],
|
|
37
|
+
},
|
|
38
|
+
mobileTextColor: {
|
|
39
|
+
control: "radio",
|
|
40
|
+
options: ["dark", "light"],
|
|
41
|
+
},
|
|
42
|
+
desktopTextColor: {
|
|
43
|
+
control: "radio",
|
|
44
|
+
options: ["dark", "light"],
|
|
45
|
+
},
|
|
46
|
+
maxWidth: { control: "boolean" },
|
|
47
|
+
float: {
|
|
48
|
+
control: "radio",
|
|
49
|
+
options: ["none", "mobile", "desktop", "always"],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default meta;
|
|
55
|
+
type Story = StoryObj<typeof meta>;
|
|
56
|
+
|
|
57
|
+
/* ---------------- Stories ---------------- */
|
|
58
|
+
|
|
59
|
+
export const Default: Story = {};
|
|
60
|
+
|
|
61
|
+
export const LightText: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
textColor: "light",
|
|
64
|
+
},
|
|
65
|
+
parameters: {
|
|
66
|
+
backgrounds: {
|
|
67
|
+
default: "dark",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const WithImages: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
links: [
|
|
75
|
+
{
|
|
76
|
+
buttonLabel: "Home",
|
|
77
|
+
href: "/",
|
|
78
|
+
|
|
79
|
+
image: {
|
|
80
|
+
url: "https://images.ctfassets.net/8d4yn2ywtegc/50Aef1sWZhzXKR0smBjFi8/e552eb0193b203822381f508babd51b3/Alabama.svg",
|
|
81
|
+
alt: "Home",
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
buttonLabel: "Category",
|
|
86
|
+
href: "/category",
|
|
87
|
+
|
|
88
|
+
image: {
|
|
89
|
+
url: "https://images.ctfassets.net/8d4yn2ywtegc/50Aef1sWZhzXKR0smBjFi8/e552eb0193b203822381f508babd51b3/Alabama.svg",
|
|
90
|
+
alt: "Category",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
buttonLabel: "Current Page",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const SingleLink: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
links: [{ buttonLabel: "Current Page" }],
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const EmptyLinks: Story = {
|
|
107
|
+
args: {
|
|
108
|
+
links: [],
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const FloatOnMobile: Story = {
|
|
113
|
+
args: {
|
|
114
|
+
float: "mobile",
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const FloatOnDesktop: Story = {
|
|
119
|
+
args: {
|
|
120
|
+
float: "desktop",
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const FloatAlways: Story = {
|
|
125
|
+
args: {
|
|
126
|
+
float: "always",
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const MaxWidthDisabled: Story = {
|
|
131
|
+
args: {
|
|
132
|
+
maxWidth: false,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const MixedTextColors: Story = {
|
|
137
|
+
args: {
|
|
138
|
+
mobileTextColor: "light",
|
|
139
|
+
desktopTextColor: "dark",
|
|
140
|
+
float: "mobile",
|
|
141
|
+
},
|
|
142
|
+
parameters: {
|
|
143
|
+
backgrounds: {
|
|
144
|
+
default: "dark",
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import Button from "../button";
|
|
3
2
|
import { BreadcrumbNavigationProps } from "./types";
|
|
4
3
|
|
|
5
4
|
import { MaterialIcon } from "@shared/components/material-icon";
|
|
@@ -11,24 +10,37 @@ export const BreadcrumbNavigation: React.FC<
|
|
|
11
10
|
const {
|
|
12
11
|
links = [],
|
|
13
12
|
textColor = "dark",
|
|
13
|
+
mobileTextColor,
|
|
14
|
+
desktopTextColor,
|
|
14
15
|
maxWidth = true,
|
|
15
|
-
|
|
16
|
+
float = "desktop",
|
|
16
17
|
} = props;
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
const resolvedMobile =
|
|
19
|
+
mobileTextColor ?? (float === "desktop" ? "dark" : textColor);
|
|
20
|
+
const resolvedDesktop =
|
|
21
|
+
desktopTextColor ?? (float === "mobile" ? "dark" : textColor);
|
|
22
|
+
const mobileColor = resolvedMobile === "dark" ? "text-text" : "text-white";
|
|
23
|
+
const desktopColor =
|
|
24
|
+
resolvedDesktop === "dark" ? "xl:text-text" : "xl:text-white";
|
|
25
|
+
const color = `${mobileColor} ${desktopColor}`;
|
|
26
|
+
|
|
27
|
+
const olPosition =
|
|
28
|
+
float === "always"
|
|
29
|
+
? "absolute"
|
|
30
|
+
: float === "mobile"
|
|
31
|
+
? "absolute xl:relative"
|
|
32
|
+
: float === "desktop"
|
|
33
|
+
? "relative xl:absolute"
|
|
34
|
+
: "relative";
|
|
35
|
+
|
|
24
36
|
if (!links.length) return null;
|
|
25
37
|
return (
|
|
26
38
|
<nav
|
|
27
39
|
aria-label="Breadcrumb"
|
|
28
|
-
className={`${maxWidth ? `${
|
|
40
|
+
className={`${maxWidth ? `${float === "none" && "mx-5"} max-w-120 xl:mx-auto` : "mx-auto"} relative`}
|
|
29
41
|
>
|
|
30
42
|
<ol
|
|
31
|
-
className={`right-0 z-10 mx-0 flex w-full flex-nowrap items-center gap-2 px-7 pb-0 pt-8 md:px-14 ${
|
|
43
|
+
className={`right-0 z-10 mx-0 flex w-full flex-nowrap items-center gap-2 px-7 pb-0 pt-8 md:px-14 ${olPosition} xl:mx-auto xl:flex-wrap xl:px-3`}
|
|
32
44
|
>
|
|
33
45
|
{links.map((link, index) => {
|
|
34
46
|
const { image, ...linkProps } = link;
|
|
@@ -49,11 +61,13 @@ export const BreadcrumbNavigation: React.FC<
|
|
|
49
61
|
className="mr-2 h-10 w-10"
|
|
50
62
|
/>
|
|
51
63
|
)}
|
|
52
|
-
<
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
<a
|
|
65
|
+
href={linkProps.href}
|
|
66
|
+
className={`label3 mr-2 whitespace-nowrap ${color} hover:underline`}
|
|
67
|
+
>
|
|
68
|
+
{linkProps.buttonLabel}
|
|
69
|
+
</a>
|
|
70
|
+
|
|
57
71
|
<MaterialIcon name="chevron_right" className={`${color} `} />
|
|
58
72
|
</li>
|
|
59
73
|
) : (
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export type BreadcrumbNavigationProps = {
|
|
2
2
|
links?: Array<any>;
|
|
3
3
|
textColor?: "dark" | "light";
|
|
4
|
+
mobileTextColor?: "dark" | "light";
|
|
5
|
+
desktopTextColor?: "dark" | "light";
|
|
4
6
|
maxWidth?: boolean;
|
|
5
|
-
|
|
7
|
+
float?: "none" | "mobile" | "desktop" | "always";
|
|
6
8
|
};
|
|
@@ -23,29 +23,20 @@ const backgroundClassMap: Record<string, string> = {
|
|
|
23
23
|
|
|
24
24
|
// Literal class strings (Tailwind JIT only picks up literal tokens; do not
|
|
25
25
|
// build these by concatenation at runtime).
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
6: "grid-cols-6",
|
|
26
|
+
// Per-card responsive width classes for the flex-wrap layout. Mobile is
|
|
27
|
+
// always full-width; md renders 1 or 2 columns; lg renders up to 6.
|
|
28
|
+
// The calc() values subtract a portion of the gap so cards fit cleanly.
|
|
29
|
+
const mdWidthMap: Record<number, string> = {
|
|
30
|
+
1: "md:w-full",
|
|
31
|
+
2: "md:w-[calc(50%-1rem)]",
|
|
33
32
|
};
|
|
34
|
-
const
|
|
35
|
-
1: "lg:
|
|
36
|
-
2: "lg:
|
|
37
|
-
3: "lg:
|
|
38
|
-
4: "lg:
|
|
39
|
-
5: "lg:
|
|
40
|
-
6: "lg:
|
|
41
|
-
};
|
|
42
|
-
const xlColMap: Record<number, string> = {
|
|
43
|
-
1: "xl:grid-cols-1",
|
|
44
|
-
2: "xl:grid-cols-2",
|
|
45
|
-
3: "xl:grid-cols-3",
|
|
46
|
-
4: "xl:grid-cols-4",
|
|
47
|
-
5: "xl:grid-cols-5",
|
|
48
|
-
6: "xl:grid-cols-6",
|
|
33
|
+
const lgWidthMap: Record<number, string> = {
|
|
34
|
+
1: "lg:w-full",
|
|
35
|
+
2: "lg:w-[calc(50%-0.75rem)]",
|
|
36
|
+
3: "lg:w-[calc(33.333%-1rem)]",
|
|
37
|
+
4: "lg:w-[calc(25%-1.125rem)]",
|
|
38
|
+
5: "lg:w-[calc(20%-1.2rem)]",
|
|
39
|
+
6: "lg:w-[calc(16.666%-1.25rem)]",
|
|
49
40
|
};
|
|
50
41
|
|
|
51
42
|
/**
|
|
@@ -95,32 +86,43 @@ export const Callout: React.FC<CalloutProps> = ({
|
|
|
95
86
|
);
|
|
96
87
|
const lgCols = clampCol(Math.min(desktopCols, itemCount || desktopCols));
|
|
97
88
|
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
|
|
89
|
+
// Layout selection:
|
|
90
|
+
// - cardsWidth === false → explicit vertical stack (single column)
|
|
91
|
+
// - any other value (true / undefined / string / etc.) → legacy
|
|
92
|
+
// flex-wrap layout that always renders multi-column on md+ and
|
|
93
|
+
// full-width on mobile. This matches the pre-0.1.79 DOM and keeps
|
|
94
|
+
// consumers like SMB-browse rendering correctly without changes.
|
|
95
|
+
const isStackMode = cardsWidth === false;
|
|
96
|
+
const gridClass = isStackMode
|
|
103
97
|
? cx(
|
|
104
|
-
"grid items-stretch self-stretch",
|
|
105
|
-
noGutter ? "gap-0" : "gap-6",
|
|
106
|
-
baseColMap[mobileCols],
|
|
107
|
-
lgColMap[lgCols],
|
|
108
|
-
xlColMap[desktopCols]
|
|
109
|
-
)
|
|
110
|
-
: cx(
|
|
111
98
|
"flex flex-col items-stretch self-stretch",
|
|
112
99
|
noGutter ? "gap-0" : "gap-6"
|
|
100
|
+
)
|
|
101
|
+
: cx(
|
|
102
|
+
"flex flex-wrap items-stretch justify-center self-stretch",
|
|
103
|
+
noGutter ? "gap-0" : "gap-6",
|
|
104
|
+
noGutter ? "md:gap-0" : "md:gap-6"
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Per-card width classes — only used for flex-wrap layout. Mobile is
|
|
108
|
+
// full-width; md respects `cardStackingMobile` (1 col when true, 2 cols
|
|
109
|
+
// when false); lg uses the optimal column count. Stack mode skips this.
|
|
110
|
+
const cardWidthClass = isStackMode
|
|
111
|
+
? ""
|
|
112
|
+
: cx(
|
|
113
|
+
"w-full",
|
|
114
|
+
mdWidthMap[clampCol(cardStackingMobile ? 1 : Math.min(2, desktopCols))],
|
|
115
|
+
lgWidthMap[lgCols]
|
|
113
116
|
);
|
|
114
117
|
|
|
115
118
|
const renderCard = (item: CalloutItem, index: number) => {
|
|
116
119
|
const itemCardType: CalloutCardType = item.cardType ?? cardType;
|
|
117
120
|
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
: { lgWidth: undefined, mdWidth: undefined };
|
|
121
|
+
// Stack mode preserves any legacy lgWidth/mdWidth on the card itself;
|
|
122
|
+
// flex-wrap mode controls width via the wrapper div, so strip them.
|
|
123
|
+
const widthProps = isStackMode
|
|
124
|
+
? { lgWidth: undefined, mdWidth: undefined }
|
|
125
|
+
: {};
|
|
124
126
|
|
|
125
127
|
switch (itemCardType) {
|
|
126
128
|
case "blog": {
|
|
@@ -223,7 +225,18 @@ export const Callout: React.FC<CalloutProps> = ({
|
|
|
223
225
|
)}
|
|
224
226
|
</div>
|
|
225
227
|
<div className={cx("card-holder", gridClass)}>
|
|
226
|
-
{items.map((item, index: number) =>
|
|
228
|
+
{items.map((item, index: number) =>
|
|
229
|
+
isStackMode ? (
|
|
230
|
+
renderCard(item, index)
|
|
231
|
+
) : (
|
|
232
|
+
<div
|
|
233
|
+
key={`callout-card-${index}`}
|
|
234
|
+
className={cx("callout-card", cardWidthClass)}
|
|
235
|
+
>
|
|
236
|
+
{renderCard(item, index)}
|
|
237
|
+
</div>
|
|
238
|
+
)
|
|
239
|
+
)}
|
|
227
240
|
</div>
|
|
228
241
|
{(cta || finePrint) && (
|
|
229
242
|
<div className="flex flex-col items-center gap-4">
|
|
@@ -35,8 +35,12 @@ export type CalloutProps = {
|
|
|
35
35
|
* When `true` (default) cards are laid out in a responsive Tailwind
|
|
36
36
|
* grid sized by `maxCardsPerRow`. When `false` the cards stretch
|
|
37
37
|
* full-width and stack vertically (no inner widths).
|
|
38
|
+
*
|
|
39
|
+
* Accepts a string for backward compatibility with legacy consumers
|
|
40
|
+
* that pass a Tailwind width class (e.g. "w-1/2"); any truthy value
|
|
41
|
+
* enables grid mode — the string itself is not applied.
|
|
38
42
|
*/
|
|
39
|
-
cardsWidth?: boolean;
|
|
43
|
+
cardsWidth?: boolean | string;
|
|
40
44
|
maxCardsPerRow?: number;
|
|
41
45
|
noGutter?: boolean;
|
|
42
46
|
items: CalloutItem[];
|
|
@@ -258,7 +258,8 @@ export const Navigation: React.FC<NavigationProps> = props => {
|
|
|
258
258
|
</div>
|
|
259
259
|
</div>
|
|
260
260
|
<div className="flex h-full items-center gap-10">
|
|
261
|
-
{showCallNowCtaInMainNav
|
|
261
|
+
{showCallNowCtaInMainNav &&
|
|
262
|
+
!(displayUtilityNavigation && displayCallNowCta)
|
|
262
263
|
? renderMainNavCallCta(onCallClickDesktop)
|
|
263
264
|
: null}
|
|
264
265
|
{displaySearchBar ? (
|