@coopdigital/react 0.10.0 → 0.12.0

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.
Files changed (34) hide show
  1. package/dist/components/AlertBanner/AlertBanner.d.ts +3 -3
  2. package/dist/components/AlertBanner/AlertBanner.js +4 -6
  3. package/dist/components/Author/Author.d.ts +17 -0
  4. package/dist/components/Author/Author.js +17 -0
  5. package/dist/components/Author/index.d.ts +4 -0
  6. package/dist/components/Card/Card.d.ts +1 -1
  7. package/dist/components/Card/Card.js +1 -1
  8. package/dist/components/Image/Image.d.ts +3 -3
  9. package/dist/components/Image/Image.js +4 -2
  10. package/dist/components/Pill/Pill.d.ts +3 -3
  11. package/dist/components/Pill/Pill.js +4 -10
  12. package/dist/components/RootSVG/RootSVG.d.ts +1 -0
  13. package/dist/components/RootSVG/RootSVG.js +7 -0
  14. package/dist/components/RootSVG/index.d.ts +4 -0
  15. package/dist/components/Signpost/Signpost.d.ts +20 -0
  16. package/dist/components/Signpost/Signpost.js +16 -0
  17. package/dist/components/Signpost/index.d.ts +4 -0
  18. package/dist/components/SkipNav/SkipNav.d.ts +3 -3
  19. package/dist/components/SkipNav/SkipNav.js +5 -3
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.js +3 -0
  22. package/package.json +14 -15
  23. package/src/components/AlertBanner/AlertBanner.tsx +4 -2
  24. package/src/components/Author/Author.tsx +49 -0
  25. package/src/components/Author/index.ts +5 -0
  26. package/src/components/Card/Card.tsx +2 -2
  27. package/src/components/Image/Image.tsx +11 -4
  28. package/src/components/Pill/Pill.tsx +4 -2
  29. package/src/components/RootSVG/RootSVG.tsx +11 -0
  30. package/src/components/RootSVG/index.ts +5 -0
  31. package/src/components/Signpost/Signpost.tsx +56 -0
  32. package/src/components/Signpost/index.ts +5 -0
  33. package/src/components/SkipNav/SkipNav.tsx +4 -3
  34. package/src/index.ts +3 -0
@@ -1,5 +1,5 @@
1
- import type { JSX, ReactNode } from "react";
2
- export interface AlertBannerProps {
1
+ import type { HTMLAttributes, JSX, ReactNode } from "react";
2
+ export interface AlertBannerProps extends HTMLAttributes<HTMLDivElement> {
3
3
  /** **(Optional)** Specifies a custom aria-label. */
4
4
  ariaLabel?: string;
5
5
  /** **(Optional)** Represents the content inside the AlertBanner component. It can be any valid JSX or string. */
@@ -21,5 +21,5 @@ export interface AlertBannerProps {
21
21
  * <p>Only use alert notifications when absolutely necessary. Using them too often could make the problem worse.<p/>
22
22
  *
23
23
  */
24
- export declare const AlertBanner: ({ ariaLabel, children, className, title, variant, }: AlertBannerProps) => JSX.Element;
24
+ export declare const AlertBanner: ({ ariaLabel, children, className, title, variant, ...props }: AlertBannerProps) => JSX.Element;
25
25
  export default AlertBanner;
@@ -1,3 +1,4 @@
1
+ import { __rest } from '../../node_modules/tslib/tslib.es6.js';
1
2
  import { jsx, jsxs } from 'react/jsx-runtime';
2
3
 
3
4
  /**
@@ -10,12 +11,9 @@ import { jsx, jsxs } from 'react/jsx-runtime';
10
11
  * <p>Only use alert notifications when absolutely necessary. Using them too often could make the problem worse.<p/>
11
12
  *
12
13
  */
13
- const AlertBanner = ({ ariaLabel, children, className = "", title, variant = "default", }) => {
14
- const componentProps = {
15
- "aria-label": ariaLabel,
16
- className: `coop-alert-banner ${className}`,
17
- "data-variant": variant,
18
- };
14
+ const AlertBanner = (_a) => {
15
+ var { ariaLabel, children, className = "", title, variant = "default" } = _a, props = __rest(_a, ["ariaLabel", "children", "className", "title", "variant"]);
16
+ const componentProps = Object.assign({ "aria-label": ariaLabel, className: `coop-alert-banner ${className}`, "data-variant": variant }, props);
19
17
  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
18
  };
21
19
 
@@ -0,0 +1,17 @@
1
+ import type { HTMLAttributes, JSX } from "react";
2
+ import { ImageProps } from "../Image";
3
+ export interface AuthorProps extends HTMLAttributes<HTMLDivElement> {
4
+ /** **(Optional)** Specifies the content author */
5
+ author?: string;
6
+ /** **(Optional)** Specifies the date. Refer to Experience Library guidance on date formats. We advise using the following format (dd mmmm yyyy) eg: 1 January 2000. */
7
+ date?: string;
8
+ /** **(Optional)** Specifies the text that will prefix the date, e.g. "Published" */
9
+ datePrefix?: string;
10
+ /** **(Optional)** Specifies the image properties of Author */
11
+ image?: ImageProps;
12
+ }
13
+ /**
14
+ * Author is a component that can be used inside any article or Card component to communicate respective author and date of publication.
15
+ */
16
+ export declare const Author: ({ author, date, datePrefix, image, ...props }: AuthorProps) => JSX.Element;
17
+ export default Author;
@@ -0,0 +1,17 @@
1
+ import { __rest } from '../../node_modules/tslib/tslib.es6.js';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { Image } from '../Image/Image.js';
4
+
5
+ /**
6
+ * Author is a component that can be used inside any article or Card component to communicate respective author and date of publication.
7
+ */
8
+ const Author = (_a) => {
9
+ var { author = "Co-op team", date, datePrefix = "", image = {
10
+ alt: "",
11
+ src: "https://s3.eu-west-1.amazonaws.com/assets.digital.coop.co.uk/oneweb/coop-logo-inverted.svg",
12
+ } } = _a, props = __rest(_a, ["author", "date", "datePrefix", "image"]);
13
+ const imageProps = Object.assign({ width: "56px" }, image);
14
+ return (jsxs("div", Object.assign({ className: "coop-author" }, props, { children: [image && jsx(Image, Object.assign({}, imageProps)), jsxs("div", { className: "coop-author--content", children: [jsxs("span", { children: [datePrefix ? datePrefix + " " : "", date] }), jsxs("span", { children: ["by ", author] })] })] })));
15
+ };
16
+
17
+ export { Author, Author as default };
@@ -0,0 +1,4 @@
1
+ import Author from "./Author";
2
+ export default Author;
3
+ export { Author };
4
+ export * from "./Author";
@@ -18,7 +18,7 @@ export interface CardProps extends HTMLAttributes<HTMLDivElement> {
18
18
  headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6";
19
19
  /** **(Optional)** Specifies the URL that the Card component will link to when clicked. */
20
20
  href?: string;
21
- /** Specifies the image URL and alt text of the Card */
21
+ /** Specifies the image properties of the Card */
22
22
  image: ImageProps;
23
23
  /** **(Optional)** Specifies the position of the image in the Card */
24
24
  imagePosition?: "left" | "right";
@@ -23,7 +23,7 @@ const Card = (_a) => {
23
23
  const linkElement = getCardLinkElement(as, href);
24
24
  const imageProps = Object.assign({ crop: "wide" }, image);
25
25
  const componentProps = Object.assign({ className: "coop-card", "data-badge-pos": badgePosition, "data-bg": background, "data-image-pos": imagePosition, "data-label-bg": labelBackground, "data-layout": layout }, props);
26
- return (jsxs("article", Object.assign({}, componentProps, { children: [image && jsx(Image, Object.assign({}, imageProps)), badge && jsx("div", { className: "coop-card--badge", children: badge }), jsxs("div", { className: "coop-card--inner", children: [jsxs("div", { className: "coop-card--content", children: [label && jsx("span", { className: "coop-card--label", children: label }), React.createElement(linkElement.element, linkElement.props, React.createElement(headingLevel, {}, title)), children] }), chevron && (jsx("span", { "aria-hidden": "true", className: "coop-card--icon", role: "presentation", children: jsx("svg", { viewBox: "0 0 16 29", children: jsx("path", { d: "M2 28.1a1.6 1.6 0 0 1-1.2-2.7l11-10.9-11-11A1.6 1.6 0 1 1 3 1.5l12 12a1.6 1.6 0 0 1 0 2.2l-12 12c-.3.4-.7.5-1 .5z" }) }) }))] })] })));
26
+ return (jsxs("article", Object.assign({}, componentProps, { children: [image && jsx(Image, Object.assign({}, imageProps)), badge && jsx("div", { className: "coop-card--badge", children: badge }), jsxs("div", { className: "coop-card--inner", children: [jsxs("div", { className: "coop-card--content", children: [label && jsx("span", { className: "coop-card--label", children: label }), React.createElement(linkElement.element, linkElement.props, React.createElement(headingLevel, { className: "coop-card--heading" }, title)), children] }), chevron && (jsx("span", { "aria-hidden": "true", className: "coop-card--icon", role: "presentation", children: jsx("svg", { viewBox: "0 0 16 29", children: jsx("path", { d: "M2 28.1a1.6 1.6 0 0 1-1.2-2.7l11-10.9-11-11A1.6 1.6 0 1 1 3 1.5l12 12a1.6 1.6 0 0 1 0 2.2l-12 12c-.3.4-.7.5-1 .5z" }) }) }))] })] })));
27
27
  };
28
28
 
29
29
  export { Card, Card as default };
@@ -1,5 +1,5 @@
1
- import type { JSX } from "react";
2
- export interface ImageProps {
1
+ import type { HTMLAttributes, JSX } from "react";
2
+ export interface ImageProps extends HTMLAttributes<HTMLImageElement> {
3
3
  /** Specifies text that can replace the Image in the page */
4
4
  alt: string;
5
5
  /** **(Optional)** Specifies the Image crop mode */
@@ -14,5 +14,5 @@ export interface ImageProps {
14
14
  /**
15
15
  * A wrapper around the image HTML tag, to help implement best practices like lazy loading, and assist with cropping and sizing images.
16
16
  */
17
- export declare const Image: ({ alt, crop, height, src, width }: ImageProps) => JSX.Element;
17
+ export declare const Image: ({ alt, crop, height, src, width, ...props }: ImageProps) => JSX.Element;
18
18
  export default Image;
@@ -1,3 +1,4 @@
1
+ import { __rest } from '../../node_modules/tslib/tslib.es6.js';
1
2
  import { jsx } from 'react/jsx-runtime';
2
3
 
3
4
  const getContentfulParams = (src, width, height) => {
@@ -23,7 +24,8 @@ const getContentfulParams = (src, width, height) => {
23
24
  /**
24
25
  * A wrapper around the image HTML tag, to help implement best practices like lazy loading, and assist with cropping and sizing images.
25
26
  */
26
- const Image = ({ alt, crop, height, src, width = "640" }) => {
27
+ const Image = (_a) => {
28
+ var { alt, crop, height, src, width = "640" } = _a, props = __rest(_a, ["alt", "crop", "height", "src", "width"]);
27
29
  let params = { height, src, width };
28
30
  if (src.includes("images.ctfassets.net")) {
29
31
  params = getContentfulParams(src, width, height);
@@ -33,7 +35,7 @@ const Image = ({ alt, crop, height, src, width = "640" }) => {
33
35
  height: params.height,
34
36
  width: params.width,
35
37
  };
36
- return (jsx("picture", { children: jsx("img", Object.assign({ alt: alt, loading: "lazy", src: params.src }, dimensions)) }));
38
+ return (jsx("picture", { children: jsx("img", Object.assign({ alt: alt, loading: "lazy", src: params.src }, dimensions, props)) }));
37
39
  };
38
40
 
39
41
  export { Image, Image as default };
@@ -1,6 +1,6 @@
1
- import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react";
1
+ import type { AnchorHTMLAttributes, ForwardRefExoticComponent, HTMLAttributes, JSX } from "react";
2
2
  import React from "react";
3
- export interface PillProps {
3
+ export interface PillProps extends HTMLAttributes<HTMLAnchorElement> {
4
4
  /** **(Optional)** Specifies a custom aria-label. */
5
5
  ariaLabel?: string;
6
6
  /** **(Optional)** Specifies the custom element to override default `a` or `span`. */
@@ -23,5 +23,5 @@ export interface PillProps {
23
23
  /**
24
24
  * The Pill component is a small, rounded label used to link and highlight information such as categories or articles. It can be customised with different content and styles to suit various use cases.
25
25
  */
26
- export declare const Pill: ({ ariaLabel, as, badge, badgeColor, children, className, href, pillColor, size, }: PillProps) => JSX.Element;
26
+ export declare const Pill: ({ ariaLabel, as, badge, badgeColor, children, className, href, pillColor, size, ...props }: PillProps) => JSX.Element;
27
27
  export default Pill;
@@ -1,22 +1,16 @@
1
+ import { __rest } from '../../node_modules/tslib/tslib.es6.js';
1
2
  import React from 'react';
2
3
 
3
4
  /**
4
5
  * The Pill component is a small, rounded label used to link and highlight information such as categories or articles. It can be customised with different content and styles to suit various use cases.
5
6
  */
6
- const Pill = ({ ariaLabel, as, badge, badgeColor = "red", children, className = "", href, pillColor = "blue", size = "md", }) => {
7
+ const Pill = (_a) => {
8
+ var { ariaLabel, as, badge, badgeColor = "red", children, className = "", href, pillColor = "blue", size = "md" } = _a, props = __rest(_a, ["ariaLabel", "as", "badge", "badgeColor", "children", "className", "href", "pillColor", "size"]);
7
9
  let element = href ? "a" : "span";
8
10
  if (as) {
9
11
  element = as;
10
12
  }
11
- const componentProps = {
12
- "aria-label": ariaLabel,
13
- className: `coop-pill ${className}`,
14
- "data-badge": (badge === null || badge === void 0 ? void 0 : badge.length) ? badge : undefined,
15
- "data-badge-color": badgeColor,
16
- "data-pill-color": pillColor,
17
- "data-size": size.length && size != "md" ? size : undefined,
18
- href,
19
- };
13
+ const componentProps = Object.assign({ "aria-label": ariaLabel, className: `coop-pill ${className}`, "data-badge": (badge === null || badge === void 0 ? void 0 : badge.length) ? badge : undefined, "data-badge-color": badgeColor, "data-pill-color": pillColor, "data-size": size.length && size != "md" ? size : undefined, href }, props);
20
14
  return React.createElement(element, Object.assign({}, componentProps), children);
21
15
  };
22
16
 
@@ -0,0 +1 @@
1
+ export default function RootSVG(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+
3
+ function RootSVG() {
4
+ return (jsx("svg", { height: "0", width: "0", xmlns: "http://www.w3.org/2000/svg", children: jsx("defs", { children: jsx("clipPath", { clipPathUnits: "objectBoundingBox", id: "squircle", children: jsx("path", { d: "M0,0.5 C0,0.165,0.165,0,0.5,0 S1,0.165,1,0.5 S0.835,1,0.5,1 S0,0.835,0,0.5" }) }) }) }));
5
+ }
6
+
7
+ export { RootSVG as default };
@@ -0,0 +1,4 @@
1
+ import RootSVG from "./RootSVG";
2
+ export default RootSVG;
3
+ export { RootSVG };
4
+ export * from "./RootSVG";
@@ -0,0 +1,20 @@
1
+ import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react";
2
+ import React from "react";
3
+ import { ImageProps } from "../Image";
4
+ export interface SignpostProps {
5
+ /** **(Optional)** Specifies the custom element to override default `a` */
6
+ as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string;
7
+ /** Represents the title inside the Signpost component. It can be any valid JSX or string. */
8
+ children: React.ReactNode;
9
+ /** **(Optional)** Specifies the heading level of the signpost's title. */
10
+ headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6";
11
+ /** Specifies the URL that the Signpost component will link to when clicked. */
12
+ href: string;
13
+ /** **(Optional)** Specifies the image URL and alt text of the Signpost */
14
+ image?: ImageProps;
15
+ }
16
+ /**
17
+ * Signposts allow you to create links to permanent content you think people are looking for.
18
+ */
19
+ export declare const Signpost: ({ as, children, headingLevel, href, image, }: SignpostProps) => JSX.Element;
20
+ export default Signpost;
@@ -0,0 +1,16 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { Image } from '../Image/Image.js';
4
+
5
+ /**
6
+ * Signposts allow you to create links to permanent content you think people are looking for.
7
+ */
8
+ const Signpost = ({ as, children, headingLevel = "h3", href, image, }) => {
9
+ let element = "a";
10
+ if (as) {
11
+ element = as;
12
+ }
13
+ return (jsxs("div", { className: "coop-signpost", children: [image && jsx(Image, Object.assign({ crop: "wide" }, image)), React.createElement(element, { href }, jsxs("div", { className: "coop-signpost--content", children: [React.createElement(headingLevel, { className: "coop-signpost--heading" }, children), jsx("span", { "aria-hidden": "true", className: "coop-signpost--icon", role: "presentation", children: jsx("svg", { viewBox: "0 0 16 29", children: jsx("path", { d: "M2 28.1a1.6 1.6 0 0 1-1.2-2.7l11-10.9-11-11A1.6 1.6 0 1 1 3 1.5l12 12a1.6 1.6 0 0 1 0 2.2l-12 12c-.3.4-.7.5-1 .5z" }) }) })] }))] }));
14
+ };
15
+
16
+ export { Signpost, Signpost as default };
@@ -0,0 +1,4 @@
1
+ import Signpost from "./Signpost";
2
+ export default Signpost;
3
+ export { Signpost };
4
+ export * from "./Signpost";
@@ -1,9 +1,9 @@
1
- import type { JSX } from "react";
1
+ import type { AnchorHTMLAttributes, JSX } from "react";
2
2
  interface SkipNavLink {
3
3
  href: string;
4
4
  title: string;
5
5
  }
6
- export interface SkipNavProps {
6
+ export interface SkipNavProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
7
7
  /** **(Optional)** Specifies a custom aria-label. */
8
8
  ariaLabel?: string;
9
9
  /** **(Optional)** Receives any className to be applied to Skip Nav component. */
@@ -33,5 +33,5 @@ export interface SkipNavProps {
33
33
  * - Pressing enter will take the user to the correct part of the page and apply the focus ring to the first interactive element in that section.
34
34
  * - If the user tabs through the skip navigation without selecting an option the Co‑op logo should be the next element that has the focus ring applied.
35
35
  */
36
- export declare const SkipNav: ({ ariaLabel, className, isVisible, links, }: SkipNavProps) => JSX.Element;
36
+ export declare const SkipNav: ({ ariaLabel, className, isVisible, links, ...props }: SkipNavProps) => JSX.Element;
37
37
  export default SkipNav;
@@ -1,3 +1,4 @@
1
+ import { __rest } from '../../node_modules/tslib/tslib.es6.js';
1
2
  import { jsx } from 'react/jsx-runtime';
2
3
 
3
4
  const defaultLinks = [{ href: "#main", title: "Skip to main content" }];
@@ -18,9 +19,10 @@ const defaultLinks = [{ href: "#main", title: "Skip to main content" }];
18
19
  * - Pressing enter will take the user to the correct part of the page and apply the focus ring to the first interactive element in that section.
19
20
  * - If the user tabs through the skip navigation without selecting an option the Co‑op logo should be the next element that has the focus ring applied.
20
21
  */
21
- const SkipNav = ({ ariaLabel = "", className = "", isVisible = false, links = defaultLinks, }) => {
22
+ const SkipNav = (_a) => {
23
+ var { ariaLabel = "", className = "", isVisible = false, links = defaultLinks } = _a, props = __rest(_a, ["ariaLabel", "className", "isVisible", "links"]);
22
24
  const navLinks = links.length > 0 ? links : defaultLinks;
23
- return (jsx("nav", { "aria-label": ariaLabel, className: "coop-skip-nav", children: jsx("ul", { children: navLinks.map((link) => {
25
+ return (jsx("nav", Object.assign({ "aria-label": ariaLabel, className: "coop-skip-nav" }, props, { children: jsx("ul", { children: navLinks.map((link) => {
24
26
  const linkProps = {
25
27
  className: `${className}`,
26
28
  "data-visible": isVisible,
@@ -28,7 +30,7 @@ const SkipNav = ({ ariaLabel = "", className = "", isVisible = false, links = de
28
30
  title: link.title,
29
31
  };
30
32
  return (jsx("li", { children: jsx("a", Object.assign({}, linkProps, { children: link.title })) }, link.href));
31
- }) }) }));
33
+ }) }) })));
32
34
  };
33
35
 
34
36
  export { SkipNav, SkipNav as default };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export * from "./components/AlertBanner";
2
+ export * from "./components/Author";
2
3
  export * from "./components/Button";
3
4
  export * from "./components/Card";
4
5
  export * from "./components/Image";
5
6
  export * from "./components/Pill";
7
+ export * from "./components/RootSVG";
8
+ export * from "./components/Signpost";
6
9
  export * from "./components/SkipNav";
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  export { AlertBanner } from './components/AlertBanner/AlertBanner.js';
2
+ export { Author } from './components/Author/Author.js';
2
3
  export { Button } from './components/Button/Button.js';
3
4
  export { Card } from './components/Card/Card.js';
4
5
  export { Image } from './components/Image/Image.js';
5
6
  export { Pill } from './components/Pill/Pill.js';
7
+ export { default as RootSVG } from './components/RootSVG/RootSVG.js';
8
+ export { Signpost } from './components/Signpost/Signpost.js';
6
9
  export { SkipNav } from './components/SkipNav/SkipNav.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coopdigital/react",
3
3
  "type": "module",
4
- "version": "0.10.0",
4
+ "version": "0.12.0",
5
5
  "private": false,
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -44,28 +44,27 @@
44
44
  "description": "",
45
45
  "devDependencies": {
46
46
  "@axe-core/playwright": "^4.10.1",
47
- "@coopdigital/styles": "^0.10.0",
47
+ "@coopdigital/styles": "^0.11.0",
48
48
  "@playwright/test": "^1.51.1",
49
- "@storybook/addon-a11y": "^8.6.11",
50
- "@storybook/addon-essentials": "^8.6.11",
51
- "@storybook/addon-interactions": "^8.6.11",
52
- "@storybook/addon-mdx-gfm": "^8.6.11",
53
- "@storybook/addon-onboarding": "^8.6.11",
54
- "@storybook/blocks": "^8.6.11",
55
- "@storybook/manager-api": "^8.6.11",
56
- "@storybook/react": "^8.6.11",
57
- "@storybook/react-vite": "^8.6.11",
58
- "@storybook/test": "^8.6.11",
59
- "@storybook/theming": "^8.6.11",
49
+ "@storybook/addon-a11y": "^8.6.12",
50
+ "@storybook/addon-essentials": "^8.6.12",
51
+ "@storybook/addon-interactions": "^8.6.12",
52
+ "@storybook/addon-onboarding": "^8.6.12",
53
+ "@storybook/blocks": "^8.6.12",
54
+ "@storybook/manager-api": "^8.6.12",
55
+ "@storybook/react": "^8.6.12",
56
+ "@storybook/react-vite": "^8.6.12",
57
+ "@storybook/test": "^8.6.12",
58
+ "@storybook/theming": "^8.6.12",
60
59
  "@testing-library/jest-dom": "^6.6.3",
61
60
  "@testing-library/react": "^16.2.0",
62
61
  "@types/react": "^19.0.12",
63
62
  "@types/react-dom": "^19.0.4",
64
- "storybook": "^8.6.11"
63
+ "storybook": "^8.6.12"
65
64
  },
66
65
  "peerDependencies": {
67
66
  "react": "^19.0.0",
68
67
  "react-dom": "^19.0.0"
69
68
  },
70
- "gitHead": "a5c63ef95571bbc32cf93d44b561f7050866dbce"
69
+ "gitHead": "02effb2492f1d3ee2c0772ee19e6c49bd057dab3"
71
70
  }
@@ -1,6 +1,6 @@
1
- import type { JSX, ReactNode } from "react"
1
+ import type { HTMLAttributes, JSX, ReactNode } from "react"
2
2
 
3
- export interface AlertBannerProps {
3
+ export interface AlertBannerProps extends HTMLAttributes<HTMLDivElement> {
4
4
  /** **(Optional)** Specifies a custom aria-label. */
5
5
  ariaLabel?: string
6
6
  /** **(Optional)** Represents the content inside the AlertBanner component. It can be any valid JSX or string. */
@@ -29,11 +29,13 @@ export const AlertBanner = ({
29
29
  className = "",
30
30
  title,
31
31
  variant = "default",
32
+ ...props
32
33
  }: AlertBannerProps): JSX.Element => {
33
34
  const componentProps = {
34
35
  "aria-label": ariaLabel,
35
36
  className: `coop-alert-banner ${className}`,
36
37
  "data-variant": variant,
38
+ ...props,
37
39
  }
38
40
  return (
39
41
  <aside {...componentProps}>
@@ -0,0 +1,49 @@
1
+ import type { HTMLAttributes, JSX } from "react"
2
+
3
+ import { Image, ImageProps } from "../Image"
4
+
5
+ export interface AuthorProps extends HTMLAttributes<HTMLDivElement> {
6
+ /** **(Optional)** Specifies the content author */
7
+ author?: string
8
+ /** **(Optional)** Specifies the date. Refer to Experience Library guidance on date formats. We advise using the following format (dd mmmm yyyy) eg: 1 January 2000. */
9
+ date?: string
10
+ /** **(Optional)** Specifies the text that will prefix the date, e.g. "Published" */
11
+ datePrefix?: string
12
+ /** **(Optional)** Specifies the image properties of Author */
13
+ image?: ImageProps
14
+ }
15
+
16
+ /**
17
+ * Author is a component that can be used inside any article or Card component to communicate respective author and date of publication.
18
+ */
19
+
20
+ export const Author = ({
21
+ author = "Co-op team",
22
+ date,
23
+ datePrefix = "",
24
+ image = {
25
+ alt: "",
26
+ src: "https://s3.eu-west-1.amazonaws.com/assets.digital.coop.co.uk/oneweb/coop-logo-inverted.svg",
27
+ },
28
+ ...props
29
+ }: AuthorProps): JSX.Element => {
30
+ const imageProps: ImageProps = {
31
+ width: "56px",
32
+ ...image,
33
+ }
34
+
35
+ return (
36
+ <div className="coop-author" {...props}>
37
+ {image && <Image {...imageProps} />}
38
+ <div className="coop-author--content">
39
+ <span>
40
+ {datePrefix ? datePrefix + " " : ""}
41
+ {date}
42
+ </span>
43
+ <span>by {author}</span>
44
+ </div>
45
+ </div>
46
+ )
47
+ }
48
+
49
+ export default Author
@@ -0,0 +1,5 @@
1
+ import Author from "./Author"
2
+
3
+ export default Author
4
+ export { Author }
5
+ export * from "./Author"
@@ -23,7 +23,7 @@ export interface CardProps extends HTMLAttributes<HTMLDivElement> {
23
23
  headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6"
24
24
  /** **(Optional)** Specifies the URL that the Card component will link to when clicked. */
25
25
  href?: string
26
- /** Specifies the image URL and alt text of the Card */
26
+ /** Specifies the image properties of the Card */
27
27
  image: ImageProps
28
28
  /** **(Optional)** Specifies the position of the image in the Card */
29
29
  imagePosition?: "left" | "right"
@@ -99,7 +99,7 @@ export const Card = ({
99
99
  {React.createElement(
100
100
  linkElement.element,
101
101
  linkElement.props,
102
- React.createElement(headingLevel, {}, title)
102
+ React.createElement(headingLevel, { className: "coop-card--heading" }, title)
103
103
  )}
104
104
  {children}
105
105
  </div>
@@ -1,6 +1,6 @@
1
- import type { JSX } from "react"
1
+ import type { HTMLAttributes, JSX } from "react"
2
2
 
3
- export interface ImageProps {
3
+ export interface ImageProps extends HTMLAttributes<HTMLImageElement> {
4
4
  /** Specifies text that can replace the Image in the page */
5
5
  alt: string
6
6
  /** **(Optional)** Specifies the Image crop mode */
@@ -37,7 +37,14 @@ const getContentfulParams = (src: string, width: string, height: string | undefi
37
37
  /**
38
38
  * A wrapper around the image HTML tag, to help implement best practices like lazy loading, and assist with cropping and sizing images.
39
39
  */
40
- export const Image = ({ alt, crop, height, src, width = "640" }: ImageProps): JSX.Element => {
40
+ export const Image = ({
41
+ alt,
42
+ crop,
43
+ height,
44
+ src,
45
+ width = "640",
46
+ ...props
47
+ }: ImageProps): JSX.Element => {
41
48
  let params = { height, src, width }
42
49
 
43
50
  if (src.includes("images.ctfassets.net")) {
@@ -52,7 +59,7 @@ export const Image = ({ alt, crop, height, src, width = "640" }: ImageProps): JS
52
59
 
53
60
  return (
54
61
  <picture>
55
- <img alt={alt} loading="lazy" src={params.src} {...dimensions} />
62
+ <img alt={alt} loading="lazy" src={params.src} {...dimensions} {...props} />
56
63
  </picture>
57
64
  )
58
65
  }
@@ -1,8 +1,8 @@
1
- import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react"
1
+ import type { AnchorHTMLAttributes, ForwardRefExoticComponent, HTMLAttributes, JSX } from "react"
2
2
 
3
3
  import React from "react"
4
4
 
5
- export interface PillProps {
5
+ export interface PillProps extends HTMLAttributes<HTMLAnchorElement> {
6
6
  /** **(Optional)** Specifies a custom aria-label. */
7
7
  ariaLabel?: string
8
8
  /** **(Optional)** Specifies the custom element to override default `a` or `span`. */
@@ -37,6 +37,7 @@ export const Pill = ({
37
37
  href,
38
38
  pillColor = "blue",
39
39
  size = "md",
40
+ ...props
40
41
  }: PillProps): JSX.Element => {
41
42
  let element: PillProps["as"] = href ? "a" : "span"
42
43
 
@@ -52,6 +53,7 @@ export const Pill = ({
52
53
  "data-pill-color": pillColor,
53
54
  "data-size": size.length && size != "md" ? size : undefined,
54
55
  href,
56
+ ...props,
55
57
  }
56
58
 
57
59
  return React.createElement(element, { ...componentProps }, children)
@@ -0,0 +1,11 @@
1
+ export default function RootSVG() {
2
+ return (
3
+ <svg height="0" width="0" xmlns="http://www.w3.org/2000/svg">
4
+ <defs>
5
+ <clipPath clipPathUnits="objectBoundingBox" id="squircle">
6
+ <path d="M0,0.5 C0,0.165,0.165,0,0.5,0 S1,0.165,1,0.5 S0.835,1,0.5,1 S0,0.835,0,0.5"></path>
7
+ </clipPath>
8
+ </defs>
9
+ </svg>
10
+ )
11
+ }
@@ -0,0 +1,5 @@
1
+ import RootSVG from "./RootSVG"
2
+
3
+ export default RootSVG
4
+ export { RootSVG }
5
+ export * from "./RootSVG"
@@ -0,0 +1,56 @@
1
+ import type { AnchorHTMLAttributes, ForwardRefExoticComponent, JSX } from "react"
2
+
3
+ import React from "react"
4
+
5
+ import { Image, ImageProps } from "../Image"
6
+
7
+ export interface SignpostProps {
8
+ /** **(Optional)** Specifies the custom element to override default `a` */
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string
11
+ /** Represents the title inside the Signpost component. It can be any valid JSX or string. */
12
+ children: React.ReactNode
13
+ /** **(Optional)** Specifies the heading level of the signpost's title. */
14
+ headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6"
15
+ /** Specifies the URL that the Signpost component will link to when clicked. */
16
+ href: string
17
+ /** **(Optional)** Specifies the image URL and alt text of the Signpost */
18
+ image?: ImageProps
19
+ }
20
+
21
+ /**
22
+ * Signposts allow you to create links to permanent content you think people are looking for.
23
+ */
24
+
25
+ export const Signpost = ({
26
+ as,
27
+ children,
28
+ headingLevel = "h3",
29
+ href,
30
+ image,
31
+ }: SignpostProps): JSX.Element => {
32
+ let element: SignpostProps["as"] = "a"
33
+ if (as) {
34
+ element = as
35
+ }
36
+
37
+ return (
38
+ <div className="coop-signpost">
39
+ {image && <Image crop="wide" {...image} />}
40
+ {React.createElement(
41
+ element,
42
+ { href },
43
+ <div className="coop-signpost--content">
44
+ {React.createElement(headingLevel, { className: "coop-signpost--heading" }, children)}
45
+ <span aria-hidden="true" className="coop-signpost--icon" role="presentation">
46
+ <svg viewBox="0 0 16 29">
47
+ <path d="M2 28.1a1.6 1.6 0 0 1-1.2-2.7l11-10.9-11-11A1.6 1.6 0 1 1 3 1.5l12 12a1.6 1.6 0 0 1 0 2.2l-12 12c-.3.4-.7.5-1 .5z" />
48
+ </svg>
49
+ </span>
50
+ </div>
51
+ )}
52
+ </div>
53
+ )
54
+ }
55
+
56
+ export default Signpost
@@ -0,0 +1,5 @@
1
+ import Signpost from "./Signpost"
2
+
3
+ export default Signpost
4
+ export { Signpost }
5
+ export * from "./Signpost"
@@ -1,11 +1,11 @@
1
- import type { JSX } from "react"
1
+ import type { AnchorHTMLAttributes, JSX } from "react"
2
2
 
3
3
  interface SkipNavLink {
4
4
  href: string
5
5
  title: string
6
6
  }
7
7
 
8
- export interface SkipNavProps {
8
+ export interface SkipNavProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
9
9
  /** **(Optional)** Specifies a custom aria-label. */
10
10
  ariaLabel?: string
11
11
  /** **(Optional)** Receives any className to be applied to Skip Nav component. */
@@ -43,10 +43,11 @@ export const SkipNav = ({
43
43
  className = "",
44
44
  isVisible = false,
45
45
  links = defaultLinks,
46
+ ...props
46
47
  }: SkipNavProps): JSX.Element => {
47
48
  const navLinks = links.length > 0 ? links : defaultLinks
48
49
  return (
49
- <nav aria-label={ariaLabel} className="coop-skip-nav">
50
+ <nav aria-label={ariaLabel} className="coop-skip-nav" {...props}>
50
51
  <ul>
51
52
  {navLinks.map((link) => {
52
53
  const linkProps = {
package/src/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export * from "./components/AlertBanner"
2
+ export * from "./components/Author"
2
3
  export * from "./components/Button"
3
4
  export * from "./components/Card"
4
5
  export * from "./components/Image"
5
6
  export * from "./components/Pill"
7
+ export * from "./components/RootSVG"
8
+ export * from "./components/Signpost"
6
9
  export * from "./components/SkipNav"