@coopdigital/react 0.6.0 → 0.6.2
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/README.md +8 -3
- package/dist/components/AlertBanner/AlertBanner.d.ts +1 -1
- package/dist/components/AlertBanner/AlertBanner.js +1 -1
- package/dist/components/Button/Button.d.ts +26 -0
- package/dist/components/Button/index.d.ts +4 -0
- package/dist/components/EditorialCard/EditorialCard.d.ts +12 -10
- package/dist/components/EditorialCard/EditorialCard.js +6 -8
- package/dist/components/Image/Image.d.ts +8 -8
- package/dist/components/Image/Image.js +7 -7
- package/dist/components/Pill/Pill.d.ts +2 -2
- package/dist/components/SkipNav/SkipNav.js +3 -3
- package/package.json +15 -15
- package/src/components/AlertBanner/AlertBanner.tsx +2 -2
- package/src/components/Button/Button.tsx +64 -0
- package/src/components/Button/index.ts +5 -0
- package/src/components/EditorialCard/EditorialCard.tsx +25 -23
- package/src/components/Image/Image.tsx +13 -13
- package/src/components/Pill/Pill.tsx +3 -2
- package/src/components/SkipNav/SkipNav.tsx +3 -3
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# Experience Kit for React
|
|
8
8
|
|
|
9
9
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
10
|
-
[all_contributors_badge]: https://img.shields.io/badge/all_contributors-
|
|
10
|
+
[all_contributors_badge]: https://img.shields.io/badge/all_contributors-17-C08A00.svg ''
|
|
11
11
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
12
12
|
|
|
13
13
|
<a href="https://www.npmjs.com/package/@coopdigital/react"><img src="https://img.shields.io/npm/v/%40coopdigital%2Freact?color=E85A00" alt="npm version" /></a>
|
|
@@ -113,19 +113,24 @@ Thanks goes to these wonderful people:
|
|
|
113
113
|
<div><img src="https://secure.gravatar.com/avatar/faf90b70d749cf9460eb603fa1700add94fd7d3a32645b4be6fa12eb45c4ffa3?s=80&d=identicon" width="200px;" alt=""/></div>
|
|
114
114
|
<small>Omid Kashan</small>
|
|
115
115
|
<div><a href="#a11y-omid.kashan" title="Accessibility">️️️️♿️</a> <a href="#code-omid.kashan" title="Code">💻</a> <a href="#doc-omid.kashan" title="Documentation">📖</a> <a href="#test-omid.kashan" title="Tests">⚠️</a></div>
|
|
116
|
+
</a></td>
|
|
117
|
+
<td align="center" valign="top" width="14.28%"><a href="https://gitlab.com/phil.wolstenholme">
|
|
118
|
+
<div><img src="https://gitlab.com/uploads/-/system/user/avatar/25900363/avatar.png" width="200px;" alt=""/></div>
|
|
119
|
+
<small>Phil Wolstenholme</small>
|
|
120
|
+
<div><a href="#a11y-phil.wolstenholme" title="Accessibility">️️️️♿️</a></div>
|
|
116
121
|
</a></td>
|
|
117
122
|
<td align="center" valign="top" width="14.28%"><a href="https://gitlab.com/romain.chen">
|
|
118
123
|
<div><img src="https://s3.eu-west-1.amazonaws.com/assets.digital.coop.co.uk/oneweb/blank.jpg" width="200px;" alt=""/></div>
|
|
119
124
|
<small>Romain Chen</small>
|
|
120
125
|
<div><a href="#design-romain.chen" title="Design">🎨</a></div>
|
|
121
126
|
</a></td>
|
|
127
|
+
</tr><br />
|
|
128
|
+
<tr>
|
|
122
129
|
<td align="center" valign="top" width="14.28%"><a href="https://gitlab.com/sam.harden">
|
|
123
130
|
<div><img src="https://ca.slack-edge.com/T0C9E3ZF0-U03NT7D39L6-2fc82e7f7c6e-150" width="200px;" alt=""/></div>
|
|
124
131
|
<small>Sam Harden</small>
|
|
125
132
|
<div><a href="#a11y-sam.harden" title="Accessibility">️️️️♿️</a> <a href="#code-sam.harden" title="Code">💻</a> <a href="#doc-sam.harden" title="Documentation">📖</a> <a href="#test-sam.harden" title="Tests">⚠️</a></div>
|
|
126
133
|
</a></td>
|
|
127
|
-
</tr><br />
|
|
128
|
-
<tr>
|
|
129
134
|
<td align="center" valign="top" width="14.28%"><a href="">
|
|
130
135
|
<div><img src="https://s3.eu-west-1.amazonaws.com/assets.digital.coop.co.uk/oneweb/blank.jpg" width="200px;" alt=""/></div>
|
|
131
136
|
<small>Shweta Jaju</small>
|
|
@@ -16,7 +16,7 @@ const AlertBanner = ({ ariaLabel, children, className = "", title, variant = "de
|
|
|
16
16
|
className: `coop-alert-banner ${className}`,
|
|
17
17
|
"data-variant": variant,
|
|
18
18
|
};
|
|
19
|
-
return (jsx("aside", Object.assign({}, componentProps, { children: jsxs("div", { className: "coop-alert-banner--inner", children: [jsx("
|
|
19
|
+
return (jsx("aside", Object.assign({}, componentProps, { children: jsxs("div", { className: "coop-alert-banner--inner", children: [jsx("h2", { id: "coop-alert-banner--headline", children: title }), children] }) })));
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export { AlertBanner, AlertBanner as default };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, DetailedHTMLProps, ForwardRefExoticComponent, JSX } from "react";
|
|
2
|
+
export interface ButtonProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
|
3
|
+
/** **(Optional)** Specifies a custom aria-label. */
|
|
4
|
+
ariaLabel?: string;
|
|
5
|
+
/** **(Optional)** Specifies the custom element to override default `a` or `button`. */
|
|
6
|
+
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string;
|
|
7
|
+
/** **(Optional)** Represents the content inside the Button component. It can be any valid JSX or string. */
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
/** **(Optional)** Receives any className to be applied to Button component. */
|
|
10
|
+
className?: string;
|
|
11
|
+
/** **(Optional)** Specifies the URL that the Button component will link to when clicked. */
|
|
12
|
+
href?: string;
|
|
13
|
+
/** **(Optional)** Specifies whether the Button should be full width. */
|
|
14
|
+
isFullWidth?: boolean;
|
|
15
|
+
/** **(Optional)** Specifies whether the Button is loading. */
|
|
16
|
+
isLoading?: boolean;
|
|
17
|
+
/** **(Optional)** Specifies the Button size. */
|
|
18
|
+
size?: "sm" | "md" | "lg" | "xl";
|
|
19
|
+
/** **(Optional)** Specifies the Button variant. */
|
|
20
|
+
variant?: "primary" | "secondary" | "white" | "grey";
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The Button component is an interactive element that people can use to take an action.
|
|
24
|
+
*/
|
|
25
|
+
export declare const Button: ({ ariaLabel, as, children, className, href, isFullWidth, isLoading, size, variant, ...props }: ButtonProps) => JSX.Element;
|
|
26
|
+
export default Button;
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import { ImageProps } from "../Image";
|
|
2
1
|
import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react";
|
|
3
2
|
import React from "react";
|
|
3
|
+
import { ImageProps } from "../Image";
|
|
4
4
|
export interface EditorialCardProps {
|
|
5
|
-
/** Specifies the custom element to override default `a`
|
|
5
|
+
/** **(Optional)** Specifies the custom element to override default `a` */
|
|
6
6
|
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string;
|
|
7
|
-
/** **(Optional)** Represents the content inside the
|
|
7
|
+
/** **(Optional)** Represents the content inside the EditorialCard component. It can be any valid JSX or string. */
|
|
8
8
|
children?: React.ReactNode;
|
|
9
|
-
/** Specifies the
|
|
9
|
+
/** **(Optional)** Specifies the heading level of the card's title. */
|
|
10
|
+
headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6";
|
|
11
|
+
/** **(Optional)** Specifies the URL that the EditorialCard component will link to when clicked. */
|
|
10
12
|
href?: string;
|
|
11
|
-
/** Specifies the image URL and alt text of the
|
|
13
|
+
/** Specifies the image URL and alt text of the EditorialCard */
|
|
12
14
|
image: ImageProps;
|
|
13
|
-
/** Specifies the label of the
|
|
15
|
+
/** **(Optional)** Specifies the label of the EditorialCard */
|
|
14
16
|
label?: string;
|
|
15
|
-
/** Specifies the layout of the
|
|
16
|
-
layout?:
|
|
17
|
-
/** Specifies the title of the
|
|
17
|
+
/** **(Optional)** Specifies the layout of the EditorialCard */
|
|
18
|
+
layout?: "vertical" | "horizontal";
|
|
19
|
+
/** Specifies the title of the EditorialCard */
|
|
18
20
|
title: string;
|
|
19
21
|
}
|
|
20
|
-
export declare const EditorialCard: ({ as, children, href, label, layout,
|
|
22
|
+
export declare const EditorialCard: ({ as, children, headingLevel, href, image, label, layout, title, }: EditorialCardProps) => JSX.Element;
|
|
21
23
|
export default EditorialCard;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { jsxs,
|
|
2
|
-
import { Image } from '../Image/Image.js';
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
2
|
import React from 'react';
|
|
3
|
+
import { Image } from '../Image/Image.js';
|
|
4
4
|
|
|
5
|
-
function
|
|
5
|
+
function getCardLinkElement(as, href) {
|
|
6
6
|
let element = href ? "a" : "div";
|
|
7
7
|
if (as) {
|
|
8
8
|
element = as;
|
|
@@ -11,19 +11,17 @@ function getCardContainer(as, href) {
|
|
|
11
11
|
element,
|
|
12
12
|
props: {
|
|
13
13
|
href,
|
|
14
|
-
className: "coop-editorial-card--inner",
|
|
15
14
|
},
|
|
16
15
|
};
|
|
17
16
|
}
|
|
18
|
-
const EditorialCard = ({ as, children, href, label = "", layout
|
|
19
|
-
const
|
|
17
|
+
const EditorialCard = ({ as, children, headingLevel = "h3", href, image, label = "", layout = "vertical", title, }) => {
|
|
18
|
+
const linkElement = getCardLinkElement(as, href);
|
|
20
19
|
const imageProps = Object.assign({ crop: "wide" }, image);
|
|
21
20
|
const componentProps = {
|
|
22
21
|
className: "coop-editorial-card",
|
|
23
22
|
"data-layout": layout,
|
|
24
23
|
};
|
|
25
|
-
|
|
26
|
-
return (jsx("article", Object.assign({}, componentProps, { children: React.createElement(container.element, container.props, cardInner) })));
|
|
24
|
+
return (jsxs("article", Object.assign({}, componentProps, { children: [jsx(Image, Object.assign({}, imageProps)), jsxs("div", { className: "coop-editorial-card--content", children: [label && jsx("span", { children: label }), React.createElement(linkElement.element, linkElement.props, React.createElement(headingLevel, {}, title)), children] })] })));
|
|
27
25
|
};
|
|
28
26
|
|
|
29
27
|
export { EditorialCard, EditorialCard as default };
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { JSX } from "react";
|
|
2
2
|
export interface ImageProps {
|
|
3
|
-
/** Specifies text that can replace the
|
|
3
|
+
/** Specifies text that can replace the Image in the page */
|
|
4
4
|
alt: string;
|
|
5
|
-
/** Specifies the
|
|
5
|
+
/** **(Optional)** Specifies the Image crop mode */
|
|
6
|
+
crop?: "square" | "wide" | "none";
|
|
7
|
+
/** **(Optional)** Specifies height of the Image */
|
|
8
|
+
height?: string;
|
|
9
|
+
/** Specifies the Image URL */
|
|
6
10
|
src: string;
|
|
7
|
-
/** Specifies width of the
|
|
11
|
+
/** **(Optional)** Specifies width of the Image */
|
|
8
12
|
width?: string;
|
|
9
|
-
/** Specifies height of the image */
|
|
10
|
-
height?: string;
|
|
11
|
-
/** Specifies the image crop mode */
|
|
12
|
-
crop?: "square" | "wide" | "none";
|
|
13
13
|
}
|
|
14
|
-
export declare const Image: ({
|
|
14
|
+
export declare const Image: ({ alt, crop, height, src, width }: ImageProps) => JSX.Element;
|
|
15
15
|
export default Image;
|
|
@@ -15,22 +15,22 @@ const getContentfulParams = (src, width, height) => {
|
|
|
15
15
|
(_a = url.searchParams.get(k)) !== null && _a !== void 0 ? _a : url.searchParams.set(k, v);
|
|
16
16
|
});
|
|
17
17
|
return {
|
|
18
|
+
height: (_a = url.searchParams.get("h")) !== null && _a !== void 0 ? _a : height,
|
|
18
19
|
src: url.toString(),
|
|
19
|
-
width: (
|
|
20
|
-
height: (_b = url.searchParams.get("h")) !== null && _b !== void 0 ? _b : height,
|
|
20
|
+
width: (_b = url.searchParams.get("w")) !== null && _b !== void 0 ? _b : width,
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
|
-
const Image = ({
|
|
24
|
-
let params = { src, width
|
|
23
|
+
const Image = ({ alt, crop, height, src, width = "640" }) => {
|
|
24
|
+
let params = { height, src, width };
|
|
25
25
|
if (src.includes("images.ctfassets.net")) {
|
|
26
26
|
params = getContentfulParams(src, width, height);
|
|
27
27
|
}
|
|
28
28
|
const dimensions = {
|
|
29
|
-
width: params.width,
|
|
30
|
-
height: params.height,
|
|
31
29
|
"data-crop": crop,
|
|
30
|
+
height: params.height,
|
|
31
|
+
width: params.width,
|
|
32
32
|
};
|
|
33
|
-
return (jsx("picture", { children: jsx("img", Object.assign({ loading: "lazy",
|
|
33
|
+
return (jsx("picture", { children: jsx("img", Object.assign({ alt: alt, loading: "lazy", src: params.src }, dimensions)) }));
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export { Image, Image as default };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react";
|
|
2
2
|
import React from "react";
|
|
3
3
|
export interface PillProps {
|
|
4
|
-
/** **(Optional)** Specifies the custom element to override default `a` or `span`. */
|
|
5
|
-
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string;
|
|
6
4
|
/** **(Optional)** Specifies a custom aria-label. */
|
|
7
5
|
ariaLabel?: string;
|
|
6
|
+
/** **(Optional)** Specifies the custom element to override default `a` or `span`. */
|
|
7
|
+
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string;
|
|
8
8
|
/** **(Optional)** Specifies what text Pill should display on the badge. */
|
|
9
9
|
badge?: string;
|
|
10
10
|
/** **(Optional)** Specifies the badge background color from the available options. */
|
|
@@ -20,12 +20,12 @@ const defaultLinks = [{ href: "#main", title: "Skip to main content" }];
|
|
|
20
20
|
*/
|
|
21
21
|
const SkipNav = ({ ariaLabel = "", className = "", isVisible = false, links = defaultLinks, }) => {
|
|
22
22
|
const navLinks = links.length > 0 ? links : defaultLinks;
|
|
23
|
-
return (jsx("nav", { className: "coop-skip-nav",
|
|
23
|
+
return (jsx("nav", { "aria-label": ariaLabel, className: "coop-skip-nav", children: jsx("ul", { children: navLinks.map((link) => {
|
|
24
24
|
const linkProps = {
|
|
25
|
-
href: link.href,
|
|
26
|
-
title: link.title,
|
|
27
25
|
className: `${className}`,
|
|
28
26
|
"data-visible": isVisible,
|
|
27
|
+
href: link.href,
|
|
28
|
+
title: link.title,
|
|
29
29
|
};
|
|
30
30
|
return (jsx("li", { children: jsx("a", Object.assign({}, linkProps, { children: link.title })) }, link.href));
|
|
31
31
|
}) }) }));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coopdigital/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.2",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"private": false,
|
|
7
7
|
"publishConfig": {
|
|
@@ -39,31 +39,31 @@
|
|
|
39
39
|
"description": "",
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@axe-core/playwright": "^4.10.1",
|
|
42
|
-
"@coopdigital/styles": "^0.
|
|
42
|
+
"@coopdigital/styles": "^0.6.0",
|
|
43
43
|
"@playwright/test": "^1.51.1",
|
|
44
44
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
45
45
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
46
|
-
"@storybook/addon-a11y": "^8.6.
|
|
47
|
-
"@storybook/addon-essentials": "^8.6.
|
|
48
|
-
"@storybook/addon-interactions": "^8.6.
|
|
49
|
-
"@storybook/addon-mdx-gfm": "^8.6.
|
|
50
|
-
"@storybook/addon-onboarding": "^8.6.
|
|
51
|
-
"@storybook/blocks": "^8.6.
|
|
52
|
-
"@storybook/manager-api": "^8.6.
|
|
53
|
-
"@storybook/react": "^8.6.
|
|
54
|
-
"@storybook/react-vite": "^8.6.
|
|
55
|
-
"@storybook/test": "^8.6.
|
|
56
|
-
"@storybook/theming": "^8.6.
|
|
46
|
+
"@storybook/addon-a11y": "^8.6.7",
|
|
47
|
+
"@storybook/addon-essentials": "^8.6.7",
|
|
48
|
+
"@storybook/addon-interactions": "^8.6.7",
|
|
49
|
+
"@storybook/addon-mdx-gfm": "^8.6.7",
|
|
50
|
+
"@storybook/addon-onboarding": "^8.6.7",
|
|
51
|
+
"@storybook/blocks": "^8.6.7",
|
|
52
|
+
"@storybook/manager-api": "^8.6.7",
|
|
53
|
+
"@storybook/react": "^8.6.7",
|
|
54
|
+
"@storybook/react-vite": "^8.6.7",
|
|
55
|
+
"@storybook/test": "^8.6.7",
|
|
56
|
+
"@storybook/theming": "^8.6.7",
|
|
57
57
|
"@testing-library/jest-dom": "^6.6.3",
|
|
58
58
|
"@testing-library/react": "^16.2.0",
|
|
59
59
|
"@types/react": "^19.0.12",
|
|
60
60
|
"@types/react-dom": "^19.0.4",
|
|
61
61
|
"rollup": "^4.36.0",
|
|
62
|
-
"storybook": "^8.6.
|
|
62
|
+
"storybook": "^8.6.7"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"react": "^19.0.0",
|
|
66
66
|
"react-dom": "^19.0.0"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "45ad9af4a4579ff76f39806c7ae11cdbbc0e508f"
|
|
69
69
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { JSX, ReactNode } from "react"
|
|
2
2
|
|
|
3
3
|
export interface AlertBannerProps {
|
|
4
4
|
/** **(Optional)** Specifies a custom aria-label. */
|
|
@@ -38,7 +38,7 @@ export const AlertBanner = ({
|
|
|
38
38
|
return (
|
|
39
39
|
<aside {...componentProps}>
|
|
40
40
|
<div className="coop-alert-banner--inner">
|
|
41
|
-
<
|
|
41
|
+
<h2 id="coop-alert-banner--headline">{title}</h2>
|
|
42
42
|
{children}
|
|
43
43
|
</div>
|
|
44
44
|
</aside>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
AnchorHTMLAttributes,
|
|
3
|
+
ButtonHTMLAttributes,
|
|
4
|
+
DetailedHTMLProps,
|
|
5
|
+
ForwardRefExoticComponent,
|
|
6
|
+
JSX,
|
|
7
|
+
} from "react"
|
|
8
|
+
|
|
9
|
+
export interface ButtonProps
|
|
10
|
+
extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
|
11
|
+
/** **(Optional)** Specifies a custom aria-label. */
|
|
12
|
+
ariaLabel?: string
|
|
13
|
+
/** **(Optional)** Specifies the custom element to override default `a` or `button`. */
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string
|
|
16
|
+
/** **(Optional)** Represents the content inside the Button component. It can be any valid JSX or string. */
|
|
17
|
+
children?: React.ReactNode
|
|
18
|
+
/** **(Optional)** Receives any className to be applied to Button component. */
|
|
19
|
+
className?: string
|
|
20
|
+
/** **(Optional)** Specifies the URL that the Button component will link to when clicked. */
|
|
21
|
+
href?: string
|
|
22
|
+
/** **(Optional)** Specifies whether the Button should be full width. */
|
|
23
|
+
isFullWidth?: boolean
|
|
24
|
+
/** **(Optional)** Specifies whether the Button is loading. */
|
|
25
|
+
isLoading?: boolean
|
|
26
|
+
/** **(Optional)** Specifies the Button size. */
|
|
27
|
+
size?: "sm" | "md" | "lg" | "xl"
|
|
28
|
+
/** **(Optional)** Specifies the Button variant. */
|
|
29
|
+
variant?: "primary" | "secondary" | "white" | "grey"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The Button component is an interactive element that people can use to take an action.
|
|
34
|
+
*/
|
|
35
|
+
export const Button = ({
|
|
36
|
+
ariaLabel,
|
|
37
|
+
as,
|
|
38
|
+
children,
|
|
39
|
+
className = "",
|
|
40
|
+
href,
|
|
41
|
+
isFullWidth = false,
|
|
42
|
+
isLoading = false,
|
|
43
|
+
size = "md",
|
|
44
|
+
variant = "primary",
|
|
45
|
+
...props
|
|
46
|
+
}: ButtonProps): JSX.Element => {
|
|
47
|
+
let element: ButtonProps["as"] = href ? "a" : "button"
|
|
48
|
+
if (as) {
|
|
49
|
+
element = as
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const componentProps = {
|
|
53
|
+
"aria-label": ariaLabel,
|
|
54
|
+
className: `coop-button ${className}`,
|
|
55
|
+
"data-loading": isLoading ? true : undefined,
|
|
56
|
+
"data-size": size.length && size != "md" ? size : undefined,
|
|
57
|
+
"data-variant": variant,
|
|
58
|
+
"data-width": isFullWidth ? "full" : undefined,
|
|
59
|
+
href,
|
|
60
|
+
...props,
|
|
61
|
+
}
|
|
62
|
+
return React.createElement(element, { ...componentProps }, children)
|
|
63
|
+
}
|
|
64
|
+
export default Button
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
import { Image, ImageProps } from "../Image"
|
|
2
1
|
import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react"
|
|
2
|
+
|
|
3
3
|
import React from "react"
|
|
4
4
|
|
|
5
|
+
import { Image, ImageProps } from "../Image"
|
|
6
|
+
|
|
5
7
|
export interface EditorialCardProps {
|
|
6
|
-
/** Specifies the custom element to override default `a`
|
|
8
|
+
/** **(Optional)** Specifies the custom element to override default `a` */
|
|
7
9
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
10
|
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string
|
|
9
|
-
/** **(Optional)** Represents the content inside the
|
|
11
|
+
/** **(Optional)** Represents the content inside the EditorialCard component. It can be any valid JSX or string. */
|
|
10
12
|
children?: React.ReactNode
|
|
11
|
-
/** Specifies the
|
|
13
|
+
/** **(Optional)** Specifies the heading level of the card's title. */
|
|
14
|
+
headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6"
|
|
15
|
+
/** **(Optional)** Specifies the URL that the EditorialCard component will link to when clicked. */
|
|
12
16
|
href?: string
|
|
13
|
-
/** Specifies the image URL and alt text of the
|
|
17
|
+
/** Specifies the image URL and alt text of the EditorialCard */
|
|
14
18
|
image: ImageProps
|
|
15
|
-
/** Specifies the label of the
|
|
19
|
+
/** **(Optional)** Specifies the label of the EditorialCard */
|
|
16
20
|
label?: string
|
|
17
|
-
/** Specifies the layout of the
|
|
18
|
-
layout?:
|
|
19
|
-
/** Specifies the title of the
|
|
21
|
+
/** **(Optional)** Specifies the layout of the EditorialCard */
|
|
22
|
+
layout?: "vertical" | "horizontal"
|
|
23
|
+
/** Specifies the title of the EditorialCard */
|
|
20
24
|
title: string
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
function
|
|
27
|
+
function getCardLinkElement(as: EditorialCardProps["as"], href?: string) {
|
|
24
28
|
let element: EditorialCardProps["as"] = href ? "a" : "div"
|
|
25
29
|
|
|
26
30
|
if (as) {
|
|
@@ -31,7 +35,6 @@ function getCardContainer(as: EditorialCardProps["as"], href?: string) {
|
|
|
31
35
|
element,
|
|
32
36
|
props: {
|
|
33
37
|
href,
|
|
34
|
-
className: "coop-editorial-card--inner",
|
|
35
38
|
},
|
|
36
39
|
}
|
|
37
40
|
}
|
|
@@ -39,13 +42,14 @@ function getCardContainer(as: EditorialCardProps["as"], href?: string) {
|
|
|
39
42
|
export const EditorialCard = ({
|
|
40
43
|
as,
|
|
41
44
|
children,
|
|
45
|
+
headingLevel = "h3",
|
|
42
46
|
href,
|
|
43
|
-
label = "",
|
|
44
|
-
layout,
|
|
45
47
|
image,
|
|
48
|
+
label = "",
|
|
49
|
+
layout = "vertical",
|
|
46
50
|
title,
|
|
47
51
|
}: EditorialCardProps): JSX.Element => {
|
|
48
|
-
const
|
|
52
|
+
const linkElement = getCardLinkElement(as, href)
|
|
49
53
|
|
|
50
54
|
const imageProps: ImageProps = {
|
|
51
55
|
crop: "wide",
|
|
@@ -57,20 +61,18 @@ export const EditorialCard = ({
|
|
|
57
61
|
"data-layout": layout,
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
return (
|
|
65
|
+
<article {...componentProps}>
|
|
62
66
|
<Image {...imageProps} />
|
|
63
67
|
<div className="coop-editorial-card--content">
|
|
64
68
|
{label && <span>{label}</span>}
|
|
65
|
-
|
|
69
|
+
{React.createElement(
|
|
70
|
+
linkElement.element,
|
|
71
|
+
linkElement.props,
|
|
72
|
+
React.createElement(headingLevel, {}, title)
|
|
73
|
+
)}
|
|
66
74
|
{children}
|
|
67
75
|
</div>
|
|
68
|
-
</>
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<article {...componentProps}>
|
|
73
|
-
{React.createElement(container.element, container.props, cardInner)}
|
|
74
76
|
</article>
|
|
75
77
|
)
|
|
76
78
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { JSX } from "react"
|
|
2
2
|
|
|
3
3
|
export interface ImageProps {
|
|
4
|
-
/** Specifies text that can replace the
|
|
4
|
+
/** Specifies text that can replace the Image in the page */
|
|
5
5
|
alt: string
|
|
6
|
-
/** Specifies the
|
|
6
|
+
/** **(Optional)** Specifies the Image crop mode */
|
|
7
|
+
crop?: "square" | "wide" | "none"
|
|
8
|
+
/** **(Optional)** Specifies height of the Image */
|
|
9
|
+
height?: string
|
|
10
|
+
/** Specifies the Image URL */
|
|
7
11
|
src: string
|
|
8
|
-
/** Specifies width of the
|
|
12
|
+
/** **(Optional)** Specifies width of the Image */
|
|
9
13
|
width?: string
|
|
10
|
-
/** Specifies height of the image */
|
|
11
|
-
height?: string
|
|
12
|
-
/** Specifies the image crop mode */
|
|
13
|
-
crop?: "square" | "wide" | "none"
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const getContentfulParams = (src: string, width: string, height: string | undefined) => {
|
|
@@ -28,28 +28,28 @@ const getContentfulParams = (src: string, width: string, height: string | undefi
|
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
return {
|
|
31
|
+
height: url.searchParams.get("h") ?? height,
|
|
31
32
|
src: url.toString(),
|
|
32
33
|
width: url.searchParams.get("w") ?? width,
|
|
33
|
-
height: url.searchParams.get("h") ?? height,
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export const Image = ({
|
|
38
|
-
let params = { src, width
|
|
37
|
+
export const Image = ({ alt, crop, height, src, width = "640" }: ImageProps): JSX.Element => {
|
|
38
|
+
let params = { height, src, width }
|
|
39
39
|
|
|
40
40
|
if (src.includes("images.ctfassets.net")) {
|
|
41
41
|
params = getContentfulParams(src, width, height)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const dimensions = {
|
|
45
|
-
width: params.width,
|
|
46
|
-
height: params.height,
|
|
47
45
|
"data-crop": crop,
|
|
46
|
+
height: params.height,
|
|
47
|
+
width: params.width,
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
51
|
<picture>
|
|
52
|
-
<img loading="lazy"
|
|
52
|
+
<img alt={alt} loading="lazy" src={params.src} {...dimensions} />
|
|
53
53
|
</picture>
|
|
54
54
|
)
|
|
55
55
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react"
|
|
2
|
+
|
|
2
3
|
import React from "react"
|
|
3
4
|
|
|
4
5
|
export interface PillProps {
|
|
6
|
+
/** **(Optional)** Specifies a custom aria-label. */
|
|
7
|
+
ariaLabel?: string
|
|
5
8
|
/** **(Optional)** Specifies the custom element to override default `a` or `span`. */
|
|
6
9
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
10
|
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string
|
|
8
|
-
/** **(Optional)** Specifies a custom aria-label. */
|
|
9
|
-
ariaLabel?: string
|
|
10
11
|
/** **(Optional)** Specifies what text Pill should display on the badge. */
|
|
11
12
|
badge?: string
|
|
12
13
|
/** **(Optional)** Specifies the badge background color from the available options. */
|
|
@@ -46,14 +46,14 @@ export const SkipNav = ({
|
|
|
46
46
|
}: SkipNavProps): JSX.Element => {
|
|
47
47
|
const navLinks = links.length > 0 ? links : defaultLinks
|
|
48
48
|
return (
|
|
49
|
-
<nav className="coop-skip-nav"
|
|
49
|
+
<nav aria-label={ariaLabel} className="coop-skip-nav">
|
|
50
50
|
<ul>
|
|
51
51
|
{navLinks.map((link) => {
|
|
52
52
|
const linkProps = {
|
|
53
|
-
href: link.href,
|
|
54
|
-
title: link.title,
|
|
55
53
|
className: `${className}`,
|
|
56
54
|
"data-visible": isVisible,
|
|
55
|
+
href: link.href,
|
|
56
|
+
title: link.title,
|
|
57
57
|
}
|
|
58
58
|
return (
|
|
59
59
|
<li key={link.href}>
|