@windstream/react-shared-components 0.2.68 → 0.2.70
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 +13 -2
- package/dist/contentful/index.esm.js +4 -4
- 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 +31 -2
- package/dist/index.d.ts +35 -6
- package/dist/index.esm.js +8 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/index.esm.js +1 -1
- package/dist/utils/index.esm.js.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/rich-text-basic/index.test.tsx +172 -0
- package/src/components/rich-text-basic/index.tsx +102 -0
- package/src/components/rich-text-basic/types.ts +34 -0
- package/src/components/select-plan-button/index.test.tsx +27 -0
- package/src/components/select-plan-button/index.tsx +6 -1
- package/src/components/video-link/index.tsx +2 -2
- package/src/contentful/blocks/cards/product-card/index.test.tsx +36 -0
- package/src/contentful/blocks/cards/product-card/index.tsx +23 -24
- package/src/contentful/blocks/carousel/index.tsx +1 -1
- package/src/contentful/blocks/dynamic-form/field-map.tsx +1 -1
- package/src/contentful/blocks/dynamic-form/index.test.tsx +96 -0
- package/src/contentful/blocks/dynamic-form/index.tsx +24 -1
- package/src/contentful/blocks/dynamic-form/types.ts +13 -2
- package/src/contentful/blocks/navigation/index.tsx +4 -1
- package/src/contentful/blocks/primary-hero/index.test.tsx +11 -2
- package/src/contentful/blocks/primary-hero/index.tsx +3 -2
- package/src/hooks/contentful/use-contentful-rich-text.tsx +39 -2
- package/src/index.ts +7 -0
|
@@ -180,6 +180,15 @@ export interface DynamicFormProps {
|
|
|
180
180
|
emailSubject?: string;
|
|
181
181
|
emailTemplateName?: string;
|
|
182
182
|
toEmail?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Test recipient(s) for the `email` action in non-production environments.
|
|
185
|
+
* When `isProduction === false` and the `email` action runs, the payload's
|
|
186
|
+
* `toEmail` is rerouted here so real recipients never receive non-prod
|
|
187
|
+
* submissions. Supports multiple comma-separated addresses (each is trimmed);
|
|
188
|
+
* when empty, the `email` action is skipped. Mirrors the residential form's
|
|
189
|
+
* `testEmail`.
|
|
190
|
+
*/
|
|
191
|
+
testEmail?: string;
|
|
183
192
|
segmentEventId?: string;
|
|
184
193
|
|
|
185
194
|
/** Injected per-action async submit handlers. */
|
|
@@ -212,8 +221,10 @@ export interface DynamicFormProps {
|
|
|
212
221
|
metadata?: Record<string, any>;
|
|
213
222
|
}) => void;
|
|
214
223
|
|
|
215
|
-
/** Whether the current environment is production
|
|
216
|
-
*
|
|
224
|
+
/** Whether the current environment is production. When explicitly `false`,
|
|
225
|
+
* the `email` action is rerouted to `testEmail` (or skipped when `testEmail`
|
|
226
|
+
* is empty) so non-prod submissions never reach real recipients. Leaving it
|
|
227
|
+
* `undefined` preserves the prior behavior (no rerouting). */
|
|
217
228
|
isProduction?: boolean;
|
|
218
229
|
|
|
219
230
|
/** Field customization + async data. */
|
|
@@ -130,7 +130,10 @@ export const Navigation: React.FC<NavigationProps> = props => {
|
|
|
130
130
|
)}
|
|
131
131
|
>
|
|
132
132
|
<div className="mx-auto flex max-w-120 justify-between">
|
|
133
|
-
<ul
|
|
133
|
+
<ul
|
|
134
|
+
className="flex min-h-11 gap-5"
|
|
135
|
+
aria-label="Utility Navigation"
|
|
136
|
+
>
|
|
134
137
|
{utilityNavigationLinks?.map((links, index) => {
|
|
135
138
|
return (
|
|
136
139
|
<li key={`main-menu-items-${index}`}>
|
|
@@ -4,8 +4,8 @@ import { PrimaryHero } from "./index";
|
|
|
4
4
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
5
5
|
|
|
6
6
|
jest.mock("@shared/components/checklist", () => ({
|
|
7
|
-
Checklist: ({ items }: any) => (
|
|
8
|
-
<ul data-testid="checklist">
|
|
7
|
+
Checklist: ({ items, iconSize }: any) => (
|
|
8
|
+
<ul data-testid="checklist" data-icon-size={iconSize}>
|
|
9
9
|
{items?.map((i: string, idx: number) => (
|
|
10
10
|
<li key={idx}>{i}</li>
|
|
11
11
|
))}
|
|
@@ -128,6 +128,15 @@ describe("PrimaryHero", () => {
|
|
|
128
128
|
expect(screen.getByText("Free install")).toBeInTheDocument();
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
+
it("passes iconSize of 24 to the checklist", () => {
|
|
132
|
+
const checklist = [{ title: "No data caps" }, { title: "Free install" }];
|
|
133
|
+
render(<PrimaryHero {...baseProps} checklist={checklist} />);
|
|
134
|
+
expect(screen.getByTestId("checklist")).toHaveAttribute(
|
|
135
|
+
"data-icon-size",
|
|
136
|
+
"24"
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
131
140
|
it("does not render checklist when not provided", () => {
|
|
132
141
|
render(<PrimaryHero {...baseProps} />);
|
|
133
142
|
expect(screen.queryByTestId("checklist")).not.toBeInTheDocument();
|
|
@@ -171,6 +171,7 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
|
|
|
171
171
|
{/* checklist */}
|
|
172
172
|
{checklist && (
|
|
173
173
|
<Checklist
|
|
174
|
+
iconSize={24}
|
|
174
175
|
listItemClassName={`body2 text-left ${textColorClass}`}
|
|
175
176
|
items={checklist.map(item =>
|
|
176
177
|
item.iconUrl
|
|
@@ -230,7 +231,7 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
|
|
|
230
231
|
{...primaryCta1}
|
|
231
232
|
renderCheckPlans={renderCheckPlans}
|
|
232
233
|
onModalButtonClick={onModalButtonClick}
|
|
233
|
-
fullWidth={true}
|
|
234
|
+
// fullWidth={true}
|
|
234
235
|
buttonClassName="lg:w-auto text-center"
|
|
235
236
|
/>
|
|
236
237
|
</div>
|
|
@@ -243,7 +244,7 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
|
|
|
243
244
|
{...primaryCta2}
|
|
244
245
|
renderCheckPlans={renderCheckPlans}
|
|
245
246
|
onModalButtonClick={onModalButtonClick}
|
|
246
|
-
fullWidth={true}
|
|
247
|
+
// fullWidth={true}
|
|
247
248
|
buttonClassName="lg:w-auto text-center"
|
|
248
249
|
/>
|
|
249
250
|
</div>
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { Checklist } from "@shared/components/checklist";
|
|
14
14
|
import { Link } from "@shared/components/link";
|
|
15
15
|
import { MaterialIcon } from "@shared/components/material-icon";
|
|
16
|
+
import type { IconName } from "@shared/components/material-icon";
|
|
16
17
|
import { Text } from "@shared/components/text";
|
|
17
18
|
import { VideoLink } from "@shared/components/video-link";
|
|
18
19
|
import type { VideoLinkProps } from "@shared/components/video-link";
|
|
@@ -53,7 +54,10 @@ const toVideoLinkProps = (fields: any): VideoLinkProps => ({
|
|
|
53
54
|
fields?.image?.fields?.file?.url ??
|
|
54
55
|
fields?.image?.url ??
|
|
55
56
|
fields?.image,
|
|
56
|
-
link:
|
|
57
|
+
link:
|
|
58
|
+
typeof fields?.link === "string"
|
|
59
|
+
? fields.link
|
|
60
|
+
: (fields?.link?.fields?.href ?? fields?.link?.href),
|
|
57
61
|
videoPopup: Boolean(fields?.videoPopup),
|
|
58
62
|
videoSourceType: fields?.videoSourceType,
|
|
59
63
|
videoAssetUrl:
|
|
@@ -125,7 +129,40 @@ const isExternalUrl = (url: string): boolean => {
|
|
|
125
129
|
}
|
|
126
130
|
};
|
|
127
131
|
|
|
132
|
+
// Renders "[icon_name]" tokens (e.g. "look [star] here") as MaterialIcon glyphs.
|
|
133
|
+
const renderInlineIcons = (text: string): ReactNode[] => {
|
|
134
|
+
const iconPattern = /\[([a-zA-Z0-9_-]+)\]/g;
|
|
135
|
+
const parts: ReactNode[] = [];
|
|
136
|
+
let lastIndex = 0;
|
|
137
|
+
let match: RegExpExecArray | null;
|
|
138
|
+
|
|
139
|
+
while ((match = iconPattern.exec(text)) !== null) {
|
|
140
|
+
if (match.index > lastIndex) {
|
|
141
|
+
parts.push(text.substring(lastIndex, match.index));
|
|
142
|
+
}
|
|
143
|
+
parts.push(
|
|
144
|
+
<MaterialIcon
|
|
145
|
+
key={`icon-${match.index}-${match[1]}`}
|
|
146
|
+
name={match[1] as IconName}
|
|
147
|
+
size={20}
|
|
148
|
+
className="inline-block align-middle"
|
|
149
|
+
/>
|
|
150
|
+
);
|
|
151
|
+
lastIndex = match.index + match[0].length;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (lastIndex < text.length) {
|
|
155
|
+
parts.push(text.substring(lastIndex));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return parts.length > 0 ? parts : [text];
|
|
159
|
+
};
|
|
160
|
+
|
|
128
161
|
const getDefaultOptions = (links?: any): Options => ({
|
|
162
|
+
renderText: children =>
|
|
163
|
+
children.includes("[") && children.includes("]")
|
|
164
|
+
? renderInlineIcons(children)
|
|
165
|
+
: children,
|
|
129
166
|
renderMark: {
|
|
130
167
|
[MARKS.BOLD]: text => <strong className="font-black">{text}</strong>,
|
|
131
168
|
[MARKS.ITALIC]: text => <em>{text}</em>,
|
|
@@ -467,4 +504,4 @@ export function renderContentfulRichTextTable(
|
|
|
467
504
|
};
|
|
468
505
|
|
|
469
506
|
return documentToReactComponents(doc, options);
|
|
470
|
-
}
|
|
507
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -94,6 +94,13 @@ export type { SkeletonProps } from "./components/skeleton";
|
|
|
94
94
|
export { Tooltip } from "./components/tooltip";
|
|
95
95
|
export type { ToolTipProps } from "./components/tooltip";
|
|
96
96
|
|
|
97
|
+
export { RichTextBasic } from "./components/rich-text-basic";
|
|
98
|
+
export type {
|
|
99
|
+
RichTextBasicProps,
|
|
100
|
+
RichTextBasicOptions,
|
|
101
|
+
RichTextBasicTextProps,
|
|
102
|
+
} from "./components/rich-text-basic/types";
|
|
103
|
+
|
|
97
104
|
export {
|
|
98
105
|
FiberForm,
|
|
99
106
|
fiberFormAddressCollectionFormSchema,
|