@coopdigital/react 0.40.1 → 0.41.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.
- package/dist/components/Card/Card.d.ts +59 -20
- package/dist/components/Card/Card.js +46 -14
- package/dist/components/TextInput/TextInput.d.ts +4 -4
- package/dist/utils/slots.d.ts +6 -0
- package/dist/utils/slots.js +24 -0
- package/package.json +3 -3
- package/src/components/Card/Card.tsx +132 -65
- package/src/components/TextInput/TextInput.tsx +4 -4
- package/src/utils/slots.ts +30 -0
|
@@ -1,38 +1,77 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ForwardRefExoticComponent, HTMLAttributes, JSX } from "react";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Lights, Tints, White } from "../../types/colors";
|
|
4
4
|
import { ImageProps } from "../Image";
|
|
5
5
|
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
-
/** **(Optional)** Specify a custom element to override default `a`. */
|
|
7
|
-
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string;
|
|
8
6
|
/** **(Optional)** Specify the Card background color. */
|
|
9
7
|
background?: Tints | White;
|
|
10
|
-
/** **(Optional)** Specify text to display inside the badge. */
|
|
11
|
-
badge?: React.ReactNode;
|
|
12
|
-
/** **(Optional)** Specify badge position relative to top right corner. */
|
|
13
|
-
badgePosition?: "inset" | "popout";
|
|
14
8
|
/** **(Optional)** Specify whether chevron is visible. */
|
|
15
9
|
chevron?: boolean;
|
|
16
|
-
/** **(Optional)**
|
|
10
|
+
/** **(Optional)** Content inside the component. Children that are not assigned to a slot will be grouped together and rendered under the main Card content. */
|
|
17
11
|
children?: React.ReactNode;
|
|
18
12
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
19
13
|
className?: string;
|
|
20
|
-
/** Specify the Card
|
|
21
|
-
heading: string;
|
|
22
|
-
/** **(Optional)** Specify the level of the Card heading. */
|
|
23
|
-
headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6";
|
|
24
|
-
/** **(Optional)** Specify the URL that the Card component will link to when clicked. */
|
|
14
|
+
/** **(Optional)** Specify the URL that the Card will link to. */
|
|
25
15
|
href?: string;
|
|
26
|
-
/** Specify
|
|
27
|
-
|
|
16
|
+
/** **(Optional)** Specify a custom element to use instead of `a`. */
|
|
17
|
+
hrefAs?: React.FC<any> | ForwardRefExoticComponent<any> | string;
|
|
28
18
|
/** **(Optional)** Specify the position of the image in the Card. */
|
|
29
19
|
imagePosition?: "left" | "right";
|
|
30
|
-
/** **(Optional)** Specify the Card label. */
|
|
31
|
-
label?: string;
|
|
32
|
-
/** **(Optional)** Specify the background color of the Card label. */
|
|
33
|
-
labelBackground?: Lights;
|
|
34
20
|
/** **(Optional)** Specify the orientation of the Card. */
|
|
35
21
|
orientation?: "vertical" | "horizontal";
|
|
36
22
|
}
|
|
37
|
-
|
|
23
|
+
interface CardLabelProps extends HTMLAttributes<HTMLSpanElement> {
|
|
24
|
+
/** **(Optional)** Specify the Label background color. */
|
|
25
|
+
background?: Lights;
|
|
26
|
+
/** **(Optional)** Content inside the Label. */
|
|
27
|
+
children?: React.ReactNode;
|
|
28
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the Label. */
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
interface CardHeadingProps extends HTMLAttributes<HTMLDivElement> {
|
|
32
|
+
/** **(Optional)** Specify a custom element to use instead of `h3`. */
|
|
33
|
+
as?: "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div";
|
|
34
|
+
/** **(Optional)** Content inside the Heading. */
|
|
35
|
+
children?: React.ReactNode;
|
|
36
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the Heading. */
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {
|
|
40
|
+
/** **(Optional)** Content inside the Body. */
|
|
41
|
+
children?: React.ReactNode;
|
|
42
|
+
}
|
|
43
|
+
interface CardBadgeProps extends HTMLAttributes<HTMLDivElement> {
|
|
44
|
+
/** **(Optional)** Specify on which side the Badge should appear. */
|
|
45
|
+
align?: "left" | "right";
|
|
46
|
+
/** **(Optional)** Content inside the Badge. */
|
|
47
|
+
children?: React.ReactNode;
|
|
48
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the Badge. */
|
|
49
|
+
className?: string;
|
|
50
|
+
/** **(Optional)** Specify badge position relative to top right corner. */
|
|
51
|
+
position?: "inset" | "popout";
|
|
52
|
+
}
|
|
53
|
+
type CardImageProps = ImageProps;
|
|
54
|
+
export declare const Card: {
|
|
55
|
+
({ background, chevron, children, className, href, hrefAs, imagePosition, orientation, ...props }: CardProps): JSX.Element;
|
|
56
|
+
Label: {
|
|
57
|
+
({ background, children, className }: CardLabelProps): JSX.Element;
|
|
58
|
+
displayName: string;
|
|
59
|
+
};
|
|
60
|
+
Heading: {
|
|
61
|
+
({ as, children, className }: CardHeadingProps): JSX.Element;
|
|
62
|
+
displayName: string;
|
|
63
|
+
};
|
|
64
|
+
Badge: {
|
|
65
|
+
({ align, children, position, ...props }: CardBadgeProps): JSX.Element;
|
|
66
|
+
displayName: string;
|
|
67
|
+
};
|
|
68
|
+
Body: {
|
|
69
|
+
({ children }: CardBodyProps): JSX.Element;
|
|
70
|
+
displayName: string;
|
|
71
|
+
};
|
|
72
|
+
Image: {
|
|
73
|
+
(props: CardImageProps): import("react/jsx-runtime").JSX.Element;
|
|
74
|
+
displayName: string;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
38
77
|
export default Card;
|
|
@@ -1,37 +1,69 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { bgPropToClass } from '../../utils/index.js';
|
|
5
|
+
import { getSlots } from '../../utils/slots.js';
|
|
5
6
|
import { ChevronRightIcon } from '../Icon/ChevronRightIcon.js';
|
|
6
7
|
import { Image } from '../Image/Image.js';
|
|
7
8
|
|
|
9
|
+
const componentSlots = {
|
|
10
|
+
CardBadge: null,
|
|
11
|
+
CardBody: null,
|
|
12
|
+
CardHeading: null,
|
|
13
|
+
CardImage: null,
|
|
14
|
+
CardLabel: null,
|
|
15
|
+
Children: null,
|
|
16
|
+
};
|
|
8
17
|
function getCardLinkElement(as, href) {
|
|
9
|
-
let element = href ? "a" : "div";
|
|
10
|
-
if (as) {
|
|
11
|
-
element = as;
|
|
12
|
-
}
|
|
13
18
|
return {
|
|
14
|
-
element,
|
|
19
|
+
element: as !== null && as !== void 0 ? as : "a",
|
|
15
20
|
props: {
|
|
16
21
|
className: "coop-card--link",
|
|
17
22
|
href,
|
|
18
23
|
},
|
|
19
24
|
};
|
|
20
25
|
}
|
|
21
|
-
const Card = ({
|
|
22
|
-
const linkElement = getCardLinkElement(
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
26
|
+
const Card = ({ background = "white", chevron = false, children, className, href, hrefAs, imagePosition = "left", orientation = "vertical", ...props }) => {
|
|
27
|
+
const { element: linkElement, props: linkProps } = getCardLinkElement(hrefAs, href);
|
|
28
|
+
const slots = getSlots(componentSlots, children);
|
|
29
|
+
const innerProps = { className: "coop-card--inner" };
|
|
30
|
+
const hasLinkWrapper = href && !slots.CardHeading;
|
|
27
31
|
const componentProps = {
|
|
28
32
|
className: clsx("coop-card", background && bgPropToClass(background, className), className),
|
|
29
|
-
"data-badge-pos": badgePosition,
|
|
30
33
|
"data-image-pos": imagePosition,
|
|
31
34
|
"data-orientation": orientation !== "vertical" ? orientation : undefined,
|
|
32
35
|
...props,
|
|
33
36
|
};
|
|
34
|
-
|
|
37
|
+
if (href && slots.CardHeading) {
|
|
38
|
+
slots.CardHeading = React.createElement(linkElement, linkProps, slots.CardHeading);
|
|
39
|
+
}
|
|
40
|
+
return (jsxs("article", { ...componentProps, children: [slots.CardImage, slots.CardBadge, React.createElement(hasLinkWrapper ? linkElement : "div", hasLinkWrapper ? { href, ...innerProps } : innerProps, jsxs("div", { className: "coop-card--content", children: [slots.CardLabel, slots.CardHeading, slots.CardBody, slots.Children] }), chevron && (jsx("span", { "aria-hidden": "true", className: "coop-card--icon", role: "presentation", children: jsx(ChevronRightIcon, {}) })))] }));
|
|
41
|
+
};
|
|
42
|
+
const CardHeading = ({ as = "h3", children, className }) => {
|
|
43
|
+
return React.createElement(as, { className: clsx("coop-card--heading", className) }, children);
|
|
44
|
+
};
|
|
45
|
+
CardHeading.displayName = "Card.Heading";
|
|
46
|
+
const CardLabel = ({ background, children, className }) => {
|
|
47
|
+
return (jsx("span", { className: clsx("coop-card--label", className, background && bgPropToClass(background, className)), children: children }));
|
|
48
|
+
};
|
|
49
|
+
CardLabel.displayName = "Card.Label";
|
|
50
|
+
const CardBadge = ({ align = "right", children, position = "popout", ...props }) => {
|
|
51
|
+
return (jsx("div", { className: "coop-card--badge", "data-align": align, "data-position": position, ...props, children: children }));
|
|
52
|
+
};
|
|
53
|
+
CardBadge.displayName = "Card.Badge";
|
|
54
|
+
const CardBody = ({ children }) => {
|
|
55
|
+
return jsx(Fragment, { children: children });
|
|
56
|
+
};
|
|
57
|
+
CardBody.displayName = "Card.Body";
|
|
58
|
+
const CardImage = (props) => {
|
|
59
|
+
var _a;
|
|
60
|
+
return jsx(Image, { ...props, crop: (_a = props.crop) !== null && _a !== void 0 ? _a : "wide" });
|
|
35
61
|
};
|
|
62
|
+
CardImage.displayName = "Card.Image";
|
|
63
|
+
Card.Label = CardLabel;
|
|
64
|
+
Card.Heading = CardHeading;
|
|
65
|
+
Card.Badge = CardBadge;
|
|
66
|
+
Card.Body = CardBody;
|
|
67
|
+
Card.Image = CardImage;
|
|
36
68
|
|
|
37
69
|
export { Card, Card as default };
|
|
@@ -27,12 +27,12 @@ export interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElemen
|
|
|
27
27
|
name: string;
|
|
28
28
|
/** **(Optional)** Specify the TextInput placeholder text. Do not use in place of a form label. */
|
|
29
29
|
placeholder?: string;
|
|
30
|
-
/** **(Optional)** Specify the prefix. */
|
|
31
|
-
prefix?:
|
|
30
|
+
/** **(Optional)** Specify the prefix. It can be any valid JSX or string. */
|
|
31
|
+
prefix?: React.ReactNode;
|
|
32
32
|
/** **(Optional)** Specify the TextInput size. */
|
|
33
33
|
size?: StandardSizes;
|
|
34
|
-
/** **(Optional)** Specify the suffix. */
|
|
35
|
-
suffix?:
|
|
34
|
+
/** **(Optional)** Specify the suffix. It can be any valid JSX or string. */
|
|
35
|
+
suffix?: React.ReactNode;
|
|
36
36
|
/** **(Optional)** Specify the TextInput type. */
|
|
37
37
|
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url";
|
|
38
38
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
type Slots<T> = Record<keyof T, React.ReactNode>;
|
|
3
|
+
export declare function isKey<T extends object>(x: T, k: PropertyKey): k is keyof T;
|
|
4
|
+
export declare function getSlotName(node: React.ReactNode): string | false;
|
|
5
|
+
export declare function getSlots<T>(componentSlots: Slots<T>, children: React.ReactNode): Slots<T>;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
function isKey(x, k) {
|
|
4
|
+
return k in x;
|
|
5
|
+
}
|
|
6
|
+
function getSlotName(node) {
|
|
7
|
+
return React.isValidElement(node) && node.type && typeof node.type !== "string"
|
|
8
|
+
? node.type.name
|
|
9
|
+
: false;
|
|
10
|
+
}
|
|
11
|
+
function getSlots(componentSlots, children) {
|
|
12
|
+
return React.Children.toArray(children).reduce((slots, child) => {
|
|
13
|
+
const slotName = getSlotName(child);
|
|
14
|
+
if (child && slotName && isKey(componentSlots, slotName)) {
|
|
15
|
+
slots[slotName] = child;
|
|
16
|
+
}
|
|
17
|
+
else if ("Children" in slots) {
|
|
18
|
+
slots.Children = slots.Children ? [...[slots.Children].flat(), child] : [child];
|
|
19
|
+
}
|
|
20
|
+
return slots;
|
|
21
|
+
}, { ...componentSlots });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { getSlotName, getSlots, isKey };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coopdigital/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.41.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"storybook": "$storybook"
|
|
79
79
|
},
|
|
80
80
|
"dependencies": {
|
|
81
|
-
"@coopdigital/styles": "^0.
|
|
81
|
+
"@coopdigital/styles": "^0.36.0",
|
|
82
82
|
"clsx": "^2.1.1"
|
|
83
83
|
},
|
|
84
|
-
"gitHead": "
|
|
84
|
+
"gitHead": "b8ae0361154729b858c7c62e965cc188ca7f34eb"
|
|
85
85
|
}
|
|
@@ -1,57 +1,83 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ForwardRefExoticComponent, HTMLAttributes, JSX } from "react"
|
|
2
2
|
|
|
3
3
|
import clsx from "clsx"
|
|
4
4
|
import React from "react"
|
|
5
5
|
|
|
6
6
|
import { bgPropToClass } from "../../../src/utils"
|
|
7
7
|
import { Lights, Tints, White } from "../../types/colors"
|
|
8
|
-
import {
|
|
8
|
+
import { getSlots } from "../../utils/slots"
|
|
9
|
+
import { ChevronRightIcon } from "../Icon/ChevronRightIcon"
|
|
9
10
|
import { Image, ImageProps } from "../Image"
|
|
10
11
|
|
|
11
12
|
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
12
|
-
//export interface CardProps {
|
|
13
|
-
/** **(Optional)** Specify a custom element to override default `a`. */
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
-
as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string
|
|
16
13
|
/** **(Optional)** Specify the Card background color. */
|
|
17
14
|
background?: Tints | White
|
|
18
|
-
/** **(Optional)** Specify text to display inside the badge. */
|
|
19
|
-
badge?: React.ReactNode
|
|
20
|
-
/** **(Optional)** Specify badge position relative to top right corner. */
|
|
21
|
-
badgePosition?: "inset" | "popout"
|
|
22
15
|
/** **(Optional)** Specify whether chevron is visible. */
|
|
23
16
|
chevron?: boolean
|
|
24
|
-
/** **(Optional)**
|
|
17
|
+
/** **(Optional)** Content inside the component. Children that are not assigned to a slot will be grouped together and rendered under the main Card content. */
|
|
25
18
|
children?: React.ReactNode
|
|
26
19
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
27
20
|
className?: string
|
|
28
|
-
/** Specify the Card
|
|
29
|
-
heading: string
|
|
30
|
-
/** **(Optional)** Specify the level of the Card heading. */
|
|
31
|
-
headingLevel?: "h2" | "h3" | "h4" | "h5" | "h6"
|
|
32
|
-
/** **(Optional)** Specify the URL that the Card component will link to when clicked. */
|
|
21
|
+
/** **(Optional)** Specify the URL that the Card will link to. */
|
|
33
22
|
href?: string
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
24
|
+
/** **(Optional)** Specify a custom element to use instead of `a`. */
|
|
25
|
+
hrefAs?: React.FC<any> | ForwardRefExoticComponent<any> | string
|
|
26
|
+
/* eslint-enable */
|
|
36
27
|
/** **(Optional)** Specify the position of the image in the Card. */
|
|
37
28
|
imagePosition?: "left" | "right"
|
|
38
|
-
/** **(Optional)** Specify the Card label. */
|
|
39
|
-
label?: string
|
|
40
|
-
/** **(Optional)** Specify the background color of the Card label. */
|
|
41
|
-
labelBackground?: Lights
|
|
42
29
|
/** **(Optional)** Specify the orientation of the Card. */
|
|
43
30
|
orientation?: "vertical" | "horizontal"
|
|
44
31
|
}
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
interface CardLabelProps extends HTMLAttributes<HTMLSpanElement> {
|
|
34
|
+
/** **(Optional)** Specify the Label background color. */
|
|
35
|
+
background?: Lights
|
|
36
|
+
/** **(Optional)** Content inside the Label. */
|
|
37
|
+
children?: React.ReactNode
|
|
38
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the Label. */
|
|
39
|
+
className?: string
|
|
40
|
+
}
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
interface CardHeadingProps extends HTMLAttributes<HTMLDivElement> {
|
|
43
|
+
/** **(Optional)** Specify a custom element to use instead of `h3`. */
|
|
44
|
+
as?: "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div"
|
|
45
|
+
/** **(Optional)** Content inside the Heading. */
|
|
46
|
+
children?: React.ReactNode
|
|
47
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the Heading. */
|
|
48
|
+
className?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {
|
|
52
|
+
/** **(Optional)** Content inside the Body. */
|
|
53
|
+
children?: React.ReactNode
|
|
54
|
+
}
|
|
52
55
|
|
|
56
|
+
interface CardBadgeProps extends HTMLAttributes<HTMLDivElement> {
|
|
57
|
+
/** **(Optional)** Specify on which side the Badge should appear. */
|
|
58
|
+
align?: "left" | "right"
|
|
59
|
+
/** **(Optional)** Content inside the Badge. */
|
|
60
|
+
children?: React.ReactNode
|
|
61
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the Badge. */
|
|
62
|
+
className?: string
|
|
63
|
+
/** **(Optional)** Specify badge position relative to top right corner. */
|
|
64
|
+
position?: "inset" | "popout"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type CardImageProps = ImageProps
|
|
68
|
+
|
|
69
|
+
const componentSlots = {
|
|
70
|
+
CardBadge: null,
|
|
71
|
+
CardBody: null,
|
|
72
|
+
CardHeading: null,
|
|
73
|
+
CardImage: null,
|
|
74
|
+
CardLabel: null,
|
|
75
|
+
Children: null,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getCardLinkElement(as: CardProps["hrefAs"], href?: string) {
|
|
53
79
|
return {
|
|
54
|
-
element,
|
|
80
|
+
element: as ?? "a",
|
|
55
81
|
props: {
|
|
56
82
|
className: "coop-card--link",
|
|
57
83
|
href,
|
|
@@ -60,69 +86,110 @@ function getCardLinkElement(as: CardProps["as"], href?: string) {
|
|
|
60
86
|
}
|
|
61
87
|
|
|
62
88
|
export const Card = ({
|
|
63
|
-
as,
|
|
64
89
|
background = "white",
|
|
65
|
-
badge,
|
|
66
|
-
badgePosition = "inset",
|
|
67
90
|
chevron = false,
|
|
68
91
|
children,
|
|
69
92
|
className,
|
|
70
|
-
heading,
|
|
71
|
-
headingLevel = "h3",
|
|
72
93
|
href,
|
|
73
|
-
|
|
94
|
+
hrefAs,
|
|
74
95
|
imagePosition = "left",
|
|
75
|
-
label = "",
|
|
76
|
-
labelBackground,
|
|
77
96
|
orientation = "vertical",
|
|
78
97
|
...props
|
|
79
98
|
}: CardProps): JSX.Element => {
|
|
80
|
-
const linkElement = getCardLinkElement(
|
|
99
|
+
const { element: linkElement, props: linkProps } = getCardLinkElement(hrefAs, href)
|
|
81
100
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
101
|
+
const slots = getSlots(componentSlots, children)
|
|
102
|
+
|
|
103
|
+
const innerProps = { className: "coop-card--inner" }
|
|
104
|
+
const hasLinkWrapper = href && !slots.CardHeading
|
|
86
105
|
|
|
87
106
|
const componentProps = {
|
|
88
107
|
className: clsx("coop-card", background && bgPropToClass(background, className), className),
|
|
89
|
-
"data-badge-pos": badgePosition,
|
|
90
108
|
"data-image-pos": imagePosition,
|
|
91
109
|
"data-orientation": orientation !== "vertical" ? orientation : undefined,
|
|
92
110
|
...props,
|
|
93
111
|
}
|
|
94
112
|
|
|
113
|
+
if (href && slots.CardHeading) {
|
|
114
|
+
slots.CardHeading = React.createElement(linkElement, linkProps, slots.CardHeading)
|
|
115
|
+
}
|
|
116
|
+
|
|
95
117
|
return (
|
|
96
118
|
<article {...componentProps}>
|
|
97
|
-
{
|
|
98
|
-
{
|
|
99
|
-
|
|
119
|
+
{slots.CardImage}
|
|
120
|
+
{slots.CardBadge}
|
|
121
|
+
{React.createElement(
|
|
122
|
+
hasLinkWrapper ? linkElement : "div",
|
|
123
|
+
hasLinkWrapper ? { href, ...innerProps } : innerProps,
|
|
100
124
|
<div className="coop-card--content">
|
|
101
|
-
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
>
|
|
108
|
-
{label}
|
|
109
|
-
</span>
|
|
110
|
-
)}
|
|
111
|
-
{React.createElement(
|
|
112
|
-
linkElement.element,
|
|
113
|
-
linkElement.props,
|
|
114
|
-
React.createElement(headingLevel, { className: "coop-card--heading" }, heading)
|
|
115
|
-
)}
|
|
116
|
-
{children}
|
|
117
|
-
</div>
|
|
118
|
-
{chevron && (
|
|
125
|
+
{slots.CardLabel}
|
|
126
|
+
{slots.CardHeading}
|
|
127
|
+
{slots.CardBody}
|
|
128
|
+
{slots.Children}
|
|
129
|
+
</div>,
|
|
130
|
+
chevron && (
|
|
119
131
|
<span aria-hidden="true" className="coop-card--icon" role="presentation">
|
|
120
132
|
<ChevronRightIcon />
|
|
121
133
|
</span>
|
|
122
|
-
)
|
|
123
|
-
|
|
134
|
+
)
|
|
135
|
+
)}
|
|
124
136
|
</article>
|
|
125
137
|
)
|
|
126
138
|
}
|
|
127
139
|
|
|
140
|
+
const CardHeading = ({ as = "h3", children, className }: CardHeadingProps): JSX.Element => {
|
|
141
|
+
return React.createElement(as, { className: clsx("coop-card--heading", className) }, children)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
CardHeading.displayName = "Card.Heading"
|
|
145
|
+
|
|
146
|
+
const CardLabel = ({ background, children, className }: CardLabelProps): JSX.Element => {
|
|
147
|
+
return (
|
|
148
|
+
<span
|
|
149
|
+
className={clsx(
|
|
150
|
+
"coop-card--label",
|
|
151
|
+
className,
|
|
152
|
+
background && bgPropToClass(background, className)
|
|
153
|
+
)}
|
|
154
|
+
>
|
|
155
|
+
{children}
|
|
156
|
+
</span>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
CardLabel.displayName = "Card.Label"
|
|
161
|
+
|
|
162
|
+
const CardBadge = ({
|
|
163
|
+
align = "right",
|
|
164
|
+
children,
|
|
165
|
+
position = "popout",
|
|
166
|
+
...props
|
|
167
|
+
}: CardBadgeProps): JSX.Element => {
|
|
168
|
+
return (
|
|
169
|
+
<div className="coop-card--badge" data-align={align} data-position={position} {...props}>
|
|
170
|
+
{children}
|
|
171
|
+
</div>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
CardBadge.displayName = "Card.Badge"
|
|
176
|
+
|
|
177
|
+
const CardBody = ({ children }: CardBodyProps): JSX.Element => {
|
|
178
|
+
return <>{children}</>
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
CardBody.displayName = "Card.Body"
|
|
182
|
+
|
|
183
|
+
const CardImage = (props: CardImageProps) => {
|
|
184
|
+
return <Image {...{ ...props, crop: props.crop ?? "wide" }} />
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
CardImage.displayName = "Card.Image"
|
|
188
|
+
|
|
189
|
+
Card.Label = CardLabel
|
|
190
|
+
Card.Heading = CardHeading
|
|
191
|
+
Card.Badge = CardBadge
|
|
192
|
+
Card.Body = CardBody
|
|
193
|
+
Card.Image = CardImage
|
|
194
|
+
|
|
128
195
|
export default Card
|
|
@@ -36,12 +36,12 @@ export interface TextInputProps
|
|
|
36
36
|
name: string
|
|
37
37
|
/** **(Optional)** Specify the TextInput placeholder text. Do not use in place of a form label. */
|
|
38
38
|
placeholder?: string
|
|
39
|
-
/** **(Optional)** Specify the prefix. */
|
|
40
|
-
prefix?:
|
|
39
|
+
/** **(Optional)** Specify the prefix. It can be any valid JSX or string. */
|
|
40
|
+
prefix?: React.ReactNode
|
|
41
41
|
/** **(Optional)** Specify the TextInput size. */
|
|
42
42
|
size?: StandardSizes
|
|
43
|
-
/** **(Optional)** Specify the suffix. */
|
|
44
|
-
suffix?:
|
|
43
|
+
/** **(Optional)** Specify the suffix. It can be any valid JSX or string. */
|
|
44
|
+
suffix?: React.ReactNode
|
|
45
45
|
/** **(Optional)** Specify the TextInput type. */
|
|
46
46
|
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url"
|
|
47
47
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
|
|
3
|
+
type Slots<T> = Record<keyof T, React.ReactNode>
|
|
4
|
+
|
|
5
|
+
export function isKey<T extends object>(x: T, k: PropertyKey): k is keyof T {
|
|
6
|
+
return k in x
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getSlotName(node: React.ReactNode): string | false {
|
|
10
|
+
return React.isValidElement(node) && node.type && typeof node.type !== "string"
|
|
11
|
+
? node.type.name
|
|
12
|
+
: false
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getSlots<T>(componentSlots: Slots<T>, children: React.ReactNode): Slots<T> {
|
|
16
|
+
return React.Children.toArray(children).reduce(
|
|
17
|
+
(slots, child: React.ReactNode) => {
|
|
18
|
+
const slotName = getSlotName(child)
|
|
19
|
+
|
|
20
|
+
if (child && slotName && isKey(componentSlots, slotName)) {
|
|
21
|
+
slots[slotName] = child
|
|
22
|
+
} else if ("Children" in slots) {
|
|
23
|
+
slots.Children = slots.Children ? [...[slots.Children].flat(), child] : [child]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return slots
|
|
27
|
+
},
|
|
28
|
+
{ ...componentSlots }
|
|
29
|
+
)
|
|
30
|
+
}
|