@coopdigital/react 0.45.0 → 0.46.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 (35) hide show
  1. package/dist/components/Button/Button.d.ts +6 -4
  2. package/dist/components/Button/Button.js +4 -6
  3. package/dist/components/Card/Card.js +2 -2
  4. package/dist/components/Expandable/Expandable.js +2 -2
  5. package/dist/components/Field/Field.js +4 -4
  6. package/dist/components/Pill/Pill.js +2 -2
  7. package/dist/components/Radio/Radio.d.ts +18 -0
  8. package/dist/components/{RadioButton/RadioButton.js → Radio/Radio.js} +3 -3
  9. package/dist/components/Radio/index.d.ts +4 -0
  10. package/dist/components/{SearchBox/SearchBox.d.ts → Searchbox/Searchbox.d.ts} +7 -7
  11. package/dist/components/{SearchBox/SearchBox.js → Searchbox/Searchbox.js} +4 -4
  12. package/dist/components/Searchbox/index.d.ts +4 -0
  13. package/dist/components/TextInput/TextInput.d.ts +1 -1
  14. package/dist/{utils/slots.d.ts → hooks/useSlots.d.ts} +1 -1
  15. package/dist/{utils/slots.js → hooks/useSlots.js} +2 -2
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +2 -2
  18. package/package.json +3 -3
  19. package/src/components/Button/Button.tsx +10 -14
  20. package/src/components/Card/Card.tsx +2 -3
  21. package/src/components/Expandable/Expandable.tsx +2 -2
  22. package/src/components/Field/Field.tsx +4 -4
  23. package/src/components/Pill/Pill.tsx +2 -2
  24. package/src/components/{RadioButton/RadioButton.tsx → Radio/Radio.tsx} +10 -11
  25. package/src/components/Radio/index.ts +5 -0
  26. package/src/components/{SearchBox/SearchBox.tsx → Searchbox/Searchbox.tsx} +11 -11
  27. package/src/components/Searchbox/index.ts +5 -0
  28. package/src/components/TextInput/TextInput.tsx +13 -1
  29. package/src/{utils/slots.ts → hooks/useSlots.ts} +1 -1
  30. package/src/index.ts +2 -2
  31. package/dist/components/RadioButton/RadioButton.d.ts +0 -18
  32. package/dist/components/RadioButton/index.d.ts +0 -4
  33. package/dist/components/SearchBox/index.d.ts +0 -4
  34. package/src/components/RadioButton/index.ts +0 -5
  35. package/src/components/SearchBox/index.ts +0 -5
@@ -1,8 +1,8 @@
1
- import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ForwardRefExoticComponent, JSX } from "react";
1
+ import type { ButtonHTMLAttributes, ForwardRefExoticComponent, JSX, Ref } from "react";
2
2
  import React from "react";
3
3
  export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
4
4
  /** **(Optional)** Specify a custom element to override default `a` or `button`. */
5
- as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string;
5
+ as?: React.FC<any> | ForwardRefExoticComponent<any> | string;
6
6
  /** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
7
7
  children?: React.ReactNode;
8
8
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
@@ -18,11 +18,13 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
18
18
  /** **(Optional)** Specify text to show when the Button is in a loading state. */
19
19
  loadingText?: string;
20
20
  /** **(Optional)** Callback to run when the button is pressed. If this is an async function, it will be awaited and the button will be in a pending state until the promise is resolved. */
21
- onClick?: (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
21
+ onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
22
+ /** **(Optional)** Specify a custom React ref for this component. */
23
+ ref?: Ref<HTMLButtonElement | HTMLAnchorElement>;
22
24
  /** **(Optional)** Specify the Button size. */
23
25
  size?: "sm" | "md" | "lg";
24
26
  /** **(Optional)** Specify the Button variant. */
25
27
  variant?: "green" | "blue" | "white" | "grey" | "green-ghost" | "blue-ghost" | "white-ghost" | "grey-ghost" | "text";
26
28
  }
27
- export declare const Button: ({ as, children, className, href, isDisabled, isFullWidth, isLoading, loadingText, onClick, size, variant, ...props }: ButtonProps) => JSX.Element;
29
+ export declare const Button: ({ as, children, className, href, isDisabled, isFullWidth, isLoading, loadingText, onClick, ref, size, variant, ...props }: ButtonProps) => JSX.Element;
28
30
  export default Button;
@@ -5,11 +5,8 @@ import clsx from 'clsx';
5
5
  import React, { useState, useCallback } from 'react';
6
6
  import { LoadingIcon } from '../Icon/LoadingIcon.js';
7
7
 
8
- const Button = ({ as, children, className, href, isDisabled = false, isFullWidth = false, isLoading = false, loadingText = "Loading", onClick, size = "md", variant = "green", ...props }) => {
9
- let element = href ? "a" : "button";
10
- if (as) {
11
- element = as;
12
- }
8
+ const Button = ({ as, children, className, href, isDisabled = false, isFullWidth = false, isLoading = false, loadingText = "Loading", onClick, ref, size = "md", variant = "green", ...props }) => {
9
+ const element = as !== null && as !== void 0 ? as : (href ? "a" : "button");
13
10
  const [isPending, setIsPending] = useState(false);
14
11
  const handleClick = useCallback(async (event) => {
15
12
  if (isPending || !onClick)
@@ -31,7 +28,8 @@ const Button = ({ as, children, className, href, isDisabled = false, isFullWidth
31
28
  "data-variant": variant !== "text" ? variant : undefined,
32
29
  "data-width": isFullWidth ? "full" : undefined,
33
30
  href,
34
- onClick: handleClick,
31
+ onClick: onClick ? handleClick : undefined,
32
+ ref,
35
33
  ...props,
36
34
  };
37
35
  const finalChildren = isPending || isLoading ? (jsxs(Fragment, { children: [loadingText, jsx(LoadingIcon, {})] })) : (children);
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import React from 'react';
4
- import { getSlots } from '../../utils/slots.js';
4
+ import { useSlots } from '../../hooks/useSlots.js';
5
5
  import { ChevronRightIcon } from '../Icon/ChevronRightIcon.js';
6
6
  import { Image } from '../Image/Image.js';
7
7
 
@@ -24,7 +24,7 @@ function getCardLinkElement(as, href) {
24
24
  }
25
25
  const Card = ({ chevron = false, children, className, href, hrefAs, imagePosition = "left", orientation = "vertical", ...props }) => {
26
26
  const { element: linkElement, props: linkProps } = getCardLinkElement(hrefAs, href);
27
- const slots = getSlots(componentSlots, children);
27
+ const slots = { ...useSlots(componentSlots, children) };
28
28
  const innerProps = { className: "coop-card--inner" };
29
29
  const hasLinkWrapper = href && !slots.CardHeading;
30
30
  const componentProps = {
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { clsx } from 'clsx';
3
+ import { useSlots } from '../../hooks/useSlots.js';
3
4
  import { hasUserBg, bgClassToColor } from '../../utils/index.js';
4
- import { getSlots } from '../../utils/slots.js';
5
5
  import 'react';
6
6
  import { ChevronDownIcon } from '../Icon/ChevronDownIcon.js';
7
7
 
@@ -10,7 +10,7 @@ const componentSlots = {
10
10
  ExpandableSummary: null,
11
11
  };
12
12
  const Expandable = ({ children, className, ...props }) => {
13
- const slots = getSlots(componentSlots, children);
13
+ const slots = useSlots(componentSlots, children);
14
14
  const componentProps = {
15
15
  className: clsx("coop-expandable", !hasUserBg(className) && "bg-tint-grey", className),
16
16
  ...props,
@@ -2,7 +2,7 @@ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import React from 'react';
4
4
  import { useId } from '../../hooks/useId.js';
5
- import { getSlots } from '../../utils/slots.js';
5
+ import { useSlots } from '../../hooks/useSlots.js';
6
6
  import { Error } from '../FieldMarkers/Error.js';
7
7
  import { Hint } from '../FieldMarkers/Hint.js';
8
8
  import { Label } from '../FieldMarkers/Label.js';
@@ -14,15 +14,15 @@ const componentSlots = {
14
14
  FieldError: null,
15
15
  FieldHint: null,
16
16
  FieldLabel: null,
17
- RadioButton: null,
17
+ Radio: null,
18
18
  Textarea: null,
19
19
  TextInput: null,
20
20
  };
21
21
  const standardFields = ["Children", "FieldError", "FieldHint", "FieldLabel"];
22
- const inlineFields = ["Checkbox", "RadioButton"];
22
+ const inlineFields = ["Checkbox", "Radio"];
23
23
  const Root = ({ boxed = false, children, className, error = false, hideErrorBar = false, ...props }) => {
24
24
  var _a, _b, _c, _d, _e, _f;
25
- const slots = getSlots(componentSlots, children);
25
+ const slots = { ...useSlots(componentSlots, children) };
26
26
  const slotsArray = Object.entries(slots);
27
27
  const uid = useId();
28
28
  const isInlineControl = slotsArray.some((s) => s[1] !== null && inlineFields.includes(s[0]));
@@ -1,8 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import React from 'react';
4
+ import { useSlots } from '../../hooks/useSlots.js';
4
5
  import { hasUserBg } from '../../utils/index.js';
5
- import { getSlots } from '../../utils/slots.js';
6
6
 
7
7
  const componentSlots = {
8
8
  Children: null,
@@ -10,7 +10,7 @@ const componentSlots = {
10
10
  };
11
11
  const Pill = ({ as, children, className, href, size = "md", ...props }) => {
12
12
  let element = href ? "a" : "span";
13
- const slots = getSlots(componentSlots, children);
13
+ const slots = useSlots(componentSlots, children);
14
14
  if (as) {
15
15
  element = as;
16
16
  }
@@ -0,0 +1,18 @@
1
+ import { type InputHTMLAttributes, type JSX } from "react";
2
+ import { StandardSizes } from "src/types";
3
+ export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
4
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
5
+ className?: string;
6
+ /** **(Optional)** Specify whether the Radio should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
7
+ disabled?: boolean;
8
+ /** **(Optional)** Specify the Radio error state. */
9
+ error?: boolean;
10
+ /** **(Optional)** Specify the Radio id. Will be auto-generated if not set. */
11
+ id?: string;
12
+ /** Specify the Radio name. */
13
+ name: string;
14
+ /** **(Optional)** Specify the Radio size. */
15
+ size?: StandardSizes;
16
+ }
17
+ export declare const Radio: ({ className, disabled, error, id, name, size, ...props }: RadioProps) => JSX.Element;
18
+ export default Radio;
@@ -2,11 +2,11 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import { useId } from 'react';
4
4
 
5
- const RadioButton = ({ className, disabled, error = false, id, name, size = "md", ...props }) => {
5
+ const Radio = ({ className, disabled, error = false, id, name, size = "md", ...props }) => {
6
6
  const internalId = useId();
7
7
  id = id !== null && id !== void 0 ? id : internalId;
8
8
  const componentProps = {
9
- className: clsx("coop-radio-button", className),
9
+ className: clsx("coop-radio", className),
10
10
  "data-error": error || undefined,
11
11
  "data-size": size.length && size !== "md" ? size : undefined,
12
12
  disabled,
@@ -19,4 +19,4 @@ const RadioButton = ({ className, disabled, error = false, id, name, size = "md"
19
19
  return jsx("input", { ...componentProps });
20
20
  };
21
21
 
22
- export { RadioButton, RadioButton as default };
22
+ export { Radio, Radio as default };
@@ -0,0 +1,4 @@
1
+ import Radio from "./Radio";
2
+ export default Radio;
3
+ export { Radio };
4
+ export * from "./Radio";
@@ -1,8 +1,8 @@
1
1
  import type { InputHTMLAttributes, JSX } from "react";
2
2
  import React from "react";
3
- import { StandardSizes } from "../../../src/types";
3
+ import { StandardSizes } from "../../types";
4
4
  import { type ButtonProps } from "../Button";
5
- export interface SearchBoxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
5
+ export interface SearchboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
6
6
  /** **(Optional)** Specify a server endpoint to submit the form. Will be ignored if onSubmit is also set. */
7
7
  action?: string;
8
8
  /** **(Optional)** Specify props to forward to the Button element. Use `label` to set Button text. */
@@ -19,14 +19,14 @@ export interface SearchBoxProps extends Omit<InputHTMLAttributes<HTMLInputElemen
19
19
  labelVisible?: boolean;
20
20
  /** **(Optional)** Specify the TextInput name, also used as the URL search parameter. Defaults to `query`. */
21
21
  name?: string;
22
- /** **(Optional)** Callback to run when the form is submitted. If this is an async function, it will be awaited and the SearchBox will be in a pending state until the promise is resolved. */
22
+ /** **(Optional)** Callback to run when the form is submitted. If this is an async function, it will be awaited and the Searchbox will be in a pending state until the promise is resolved. */
23
23
  onSubmit?: React.FormEventHandler<HTMLElement> | undefined;
24
24
  /** **(Optional)** Specify the TextInput placeholder text Do not use in place of a form label. */
25
25
  placeholder?: string;
26
- /** **(Optional)** Specify the SearchBox size. */
26
+ /** **(Optional)** Specify the Searchbox size. */
27
27
  size?: StandardSizes;
28
- /** **(Optional)** Specify the SearchBox variant. */
28
+ /** **(Optional)** Specify the Searchbox variant. */
29
29
  variant?: "green" | "blue" | "white" | "grey" | "green-ghost" | "blue-ghost" | "white-ghost" | "grey-ghost";
30
30
  }
31
- export declare const SearchBox: ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize, autoComplete, button, className, id, label, labelVisible, name, onSubmit, placeholder, size, variant, ...props }: SearchBoxProps) => JSX.Element;
32
- export default SearchBox;
31
+ export declare const Searchbox: ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize, autoComplete, button, className, id, label, labelVisible, name, onSubmit, placeholder, size, variant, ...props }: SearchboxProps) => JSX.Element;
32
+ export default Searchbox;
@@ -12,7 +12,7 @@ const defaultButtonProps = {
12
12
  label: React.createElement(SearchIcon, { alt: "Search", stroke: "currentColor", strokeWidth: 2 }),
13
13
  loadingText: "",
14
14
  };
15
- const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize = "off", autoComplete = "off", button = defaultButtonProps, className, id, label, labelVisible = false, name = "query", onSubmit, placeholder, size = "md", variant = "green", ...props }) => {
15
+ const Searchbox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize = "off", autoComplete = "off", button = defaultButtonProps, className, id, label, labelVisible = false, name = "query", onSubmit, placeholder, size = "md", variant = "green", ...props }) => {
16
16
  var _a, _b;
17
17
  const [isPending, setIsPending] = useState(false);
18
18
  const internalId = useId();
@@ -31,7 +31,7 @@ const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize
31
31
  }, [onSubmit, isPending]);
32
32
  const formProps = {
33
33
  action: action !== null && action !== void 0 ? action : undefined,
34
- className: clsx("coop-search-box", className),
34
+ className: clsx("coop-searchbox", className),
35
35
  "data-size": size && size !== "md" ? size : undefined,
36
36
  "data-variant": variant.length && variant !== "green" ? variant : undefined,
37
37
  onSubmit: onSubmit ? handleSubmit : undefined,
@@ -54,7 +54,7 @@ const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize
54
54
  type: "search",
55
55
  ...props,
56
56
  };
57
- return (jsxs("form", { ...formProps, children: [label && (jsx(Label, { htmlFor: id, isVisible: labelVisible, children: label })), jsxs("div", { className: "coop-search-box--inner", children: [jsx(TextInput, { ...inputProps }), jsx(Button, { ...buttonProps, children: button.label })] })] }));
57
+ return (jsxs("form", { ...formProps, children: [label && (jsx(Label, { htmlFor: id, isVisible: labelVisible, children: label })), jsxs("div", { className: "coop-searchbox--inner", children: [jsx(TextInput, { ...inputProps }), jsx(Button, { ...buttonProps, children: button.label })] })] }));
58
58
  };
59
59
 
60
- export { SearchBox, SearchBox as default };
60
+ export { Searchbox, Searchbox as default };
@@ -0,0 +1,4 @@
1
+ import Searchbox from "./Searchbox";
2
+ export default Searchbox;
3
+ export { Searchbox };
4
+ export * from "./Searchbox";
@@ -20,7 +20,7 @@ export interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElemen
20
20
  /** **(Optional)** Specify the suffix. It can be any valid JSX or string. */
21
21
  suffix?: React.ReactNode;
22
22
  /** **(Optional)** Specify the TextInput type. */
23
- type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url";
23
+ type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url" | "date" | "datetime-local" | "week" | "month" | "time";
24
24
  }
25
25
  export declare const TextInput: ({ "aria-placeholder": ariaPlaceholder, className, disabled, error, id, name, placeholder, prefix, size, suffix, type, ...props }: TextInputProps) => JSX.Element;
26
26
  export default TextInput;
@@ -2,7 +2,7 @@ import React from "react";
2
2
  type Slots<T> = Record<keyof T, React.ReactNode>;
3
3
  export declare function isKey<T extends object>(x: T, k: PropertyKey): k is keyof T;
4
4
  export declare function getSlotName(node: React.ReactNode): string | false;
5
- export declare function getSlots<T>(componentSlots: Slots<T>, children: React.ReactNode, options?: {
5
+ export declare function useSlots<T>(componentSlots: Slots<T>, children: React.ReactNode, options?: {
6
6
  collect?: string[];
7
7
  }): Slots<T>;
8
8
  export {};
@@ -8,7 +8,7 @@ function getSlotName(node) {
8
8
  ? node.type.name
9
9
  : false;
10
10
  }
11
- function getSlots(componentSlots, children, options) {
11
+ function useSlots(componentSlots, children, options) {
12
12
  return React.Children.toArray(children).reduce((slots, child) => {
13
13
  var _a;
14
14
  const slotName = getSlotName(child);
@@ -27,4 +27,4 @@ function getSlots(componentSlots, children, options) {
27
27
  }, { ...componentSlots });
28
28
  }
29
29
 
30
- export { getSlotName, getSlots, isKey };
30
+ export { getSlotName, isKey, useSlots };
package/dist/index.d.ts CHANGED
@@ -9,9 +9,9 @@ export * from "./components/Fieldset";
9
9
  export * from "./components/Flourish";
10
10
  export * from "./components/Image";
11
11
  export * from "./components/Pill";
12
- export * from "./components/RadioButton";
12
+ export * from "./components/Radio";
13
13
  export * from "./components/RootSVG";
14
- export * from "./components/SearchBox";
14
+ export * from "./components/Searchbox";
15
15
  export * from "./components/Signpost";
16
16
  export * from "./components/SkipNav";
17
17
  export * from "./components/Squircle";
package/dist/index.js CHANGED
@@ -9,9 +9,9 @@ export { Fieldset, FieldsetFields } from './components/Fieldset/Fieldset.js';
9
9
  export { Flourish } from './components/Flourish/Flourish.js';
10
10
  export { Image } from './components/Image/Image.js';
11
11
  export { Pill } from './components/Pill/Pill.js';
12
- export { RadioButton } from './components/RadioButton/RadioButton.js';
12
+ export { Radio } from './components/Radio/Radio.js';
13
13
  export { RootSVG } from './components/RootSVG/RootSVG.js';
14
- export { SearchBox } from './components/SearchBox/SearchBox.js';
14
+ export { Searchbox } from './components/Searchbox/Searchbox.js';
15
15
  export { Signpost } from './components/Signpost/Signpost.js';
16
16
  export { SkipNav } from './components/SkipNav/SkipNav.js';
17
17
  export { Squircle } from './components/Squircle/Squircle.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coopdigital/react",
3
3
  "type": "module",
4
- "version": "0.45.0",
4
+ "version": "0.46.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.39.0",
81
+ "@coopdigital/styles": "^0.40.0",
82
82
  "clsx": "^2.1.1"
83
83
  },
84
- "gitHead": "113b5fc44feee8b4e899c75c303f1ed26f9f2629"
84
+ "gitHead": "9020e79195ead8270e9a2c39209142a02160bae5"
85
85
  }
@@ -1,11 +1,6 @@
1
1
  "use client"
2
2
 
3
- import type {
4
- AnchorHTMLAttributes,
5
- ButtonHTMLAttributes,
6
- ForwardRefExoticComponent,
7
- JSX,
8
- } from "react"
3
+ import type { ButtonHTMLAttributes, ForwardRefExoticComponent, JSX, Ref } from "react"
9
4
 
10
5
  import clsx from "clsx"
11
6
  import React, { useCallback, useState } from "react"
@@ -15,7 +10,7 @@ import { LoadingIcon } from "../Icon"
15
10
  export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
16
11
  /** **(Optional)** Specify a custom element to override default `a` or `button`. */
17
12
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
- as?: React.FC<AnchorHTMLAttributes<HTMLElement>> | ForwardRefExoticComponent<any> | string
13
+ as?: React.FC<any> | ForwardRefExoticComponent<any> | string
19
14
  /** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
20
15
  children?: React.ReactNode
21
16
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
@@ -31,7 +26,9 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
31
26
  /** **(Optional)** Specify text to show when the Button is in a loading state. */
32
27
  loadingText?: string
33
28
  /** **(Optional)** Callback to run when the button is pressed. If this is an async function, it will be awaited and the button will be in a pending state until the promise is resolved. */
34
- onClick?: (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void
29
+ onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>
30
+ /** **(Optional)** Specify a custom React ref for this component. */
31
+ ref?: Ref<HTMLButtonElement | HTMLAnchorElement>
35
32
  /** **(Optional)** Specify the Button size. */
36
33
  size?: "sm" | "md" | "lg"
37
34
  /** **(Optional)** Specify the Button variant. */
@@ -61,14 +58,12 @@ export const Button = ({
61
58
  isLoading = false,
62
59
  loadingText = "Loading",
63
60
  onClick,
61
+ ref,
64
62
  size = "md",
65
63
  variant = "green",
66
64
  ...props
67
65
  }: ButtonProps): JSX.Element => {
68
- let element: ButtonProps["as"] = href ? "a" : "button"
69
- if (as) {
70
- element = as
71
- }
66
+ const element: ButtonProps["as"] = as ?? (href ? "a" : "button")
72
67
 
73
68
  const [isPending, setIsPending] = useState(false)
74
69
 
@@ -79,7 +74,7 @@ export const Button = ({
79
74
  setIsPending(true)
80
75
 
81
76
  try {
82
- await Promise.resolve(onClick(event as React.MouseEvent<HTMLButtonElement>))
77
+ await Promise.resolve(onClick(event))
83
78
  } finally {
84
79
  setIsPending(false)
85
80
  }
@@ -96,7 +91,8 @@ export const Button = ({
96
91
  "data-variant": variant !== "text" ? variant : undefined,
97
92
  "data-width": isFullWidth ? "full" : undefined,
98
93
  href,
99
- onClick: handleClick,
94
+ onClick: onClick ? handleClick : undefined,
95
+ ref,
100
96
  ...props,
101
97
  }
102
98
 
@@ -3,7 +3,7 @@ import type { ForwardRefExoticComponent, HTMLAttributes, JSX } from "react"
3
3
  import clsx from "clsx"
4
4
  import React from "react"
5
5
 
6
- import { getSlots } from "../../utils/slots"
6
+ import { useSlots } from "../../hooks/useSlots"
7
7
  import { ChevronRightIcon } from "../Icon/ChevronRightIcon"
8
8
  import { Image, ImageProps } from "../Image"
9
9
 
@@ -91,8 +91,7 @@ export const Card = ({
91
91
  }: CardProps): JSX.Element => {
92
92
  const { element: linkElement, props: linkProps } = getCardLinkElement(hrefAs, href)
93
93
 
94
- const slots = getSlots(componentSlots, children)
95
-
94
+ const slots = { ...useSlots(componentSlots, children) }
96
95
  const innerProps = { className: "coop-card--inner" }
97
96
  const hasLinkWrapper = href && !slots.CardHeading
98
97
 
@@ -2,8 +2,8 @@ import type { DetailsHTMLAttributes, HTMLAttributes, JSX } from "react"
2
2
 
3
3
  import { clsx } from "clsx"
4
4
 
5
+ import { useSlots } from "../../hooks/useSlots"
5
6
  import { bgClassToColor, hasUserBg } from "../../utils"
6
- import { getSlots } from "../../utils/slots"
7
7
  import { ChevronDownIcon } from "../Icon"
8
8
 
9
9
  export interface ExpandableProps extends DetailsHTMLAttributes<HTMLDetailsElement> {
@@ -26,7 +26,7 @@ const componentSlots = {
26
26
  }
27
27
 
28
28
  export const Expandable = ({ children, className, ...props }: ExpandableProps): JSX.Element => {
29
- const slots = getSlots(componentSlots, children)
29
+ const slots = useSlots(componentSlots, children)
30
30
 
31
31
  const componentProps = {
32
32
  className: clsx("coop-expandable", !hasUserBg(className) && "bg-tint-grey", className),
@@ -4,7 +4,7 @@ import clsx from "clsx"
4
4
  import React from "react"
5
5
 
6
6
  import { useId } from "../../hooks/useId"
7
- import { getSlots } from "../../utils/slots"
7
+ import { useSlots } from "../../hooks/useSlots"
8
8
  import { Error as BaseError, type ErrorProps } from "../FieldMarkers/Error"
9
9
  import { Hint as BaseHint, type HintProps } from "../FieldMarkers/Hint"
10
10
  import { Label as BaseLabel, type LabelProps } from "../FieldMarkers/Label"
@@ -16,13 +16,13 @@ const componentSlots = {
16
16
  FieldError: null,
17
17
  FieldHint: null,
18
18
  FieldLabel: null,
19
- RadioButton: null,
19
+ Radio: null,
20
20
  Textarea: null,
21
21
  TextInput: null,
22
22
  }
23
23
 
24
24
  const standardFields = ["Children", "FieldError", "FieldHint", "FieldLabel"]
25
- const inlineFields = ["Checkbox", "RadioButton"]
25
+ const inlineFields = ["Checkbox", "Radio"]
26
26
 
27
27
  interface FieldProps extends HTMLAttributes<HTMLDivElement> {
28
28
  /** **(Optional)** Specify whether the Field should render inside a box. */
@@ -47,7 +47,7 @@ const Root = ({
47
47
  hideErrorBar = false,
48
48
  ...props
49
49
  }: FieldProps) => {
50
- const slots = getSlots(componentSlots, children)
50
+ const slots = { ...useSlots(componentSlots, children) }
51
51
  const slotsArray = Object.entries(slots)
52
52
 
53
53
  const uid = useId()
@@ -4,8 +4,8 @@ import clsx from "clsx"
4
4
  import React from "react"
5
5
  import { StandardSizes } from "src/types"
6
6
 
7
+ import { useSlots } from "../../hooks/useSlots"
7
8
  import { hasUserBg } from "../../utils"
8
- import { getSlots } from "../../utils/slots"
9
9
 
10
10
  export interface PillProps extends HTMLAttributes<HTMLAnchorElement> {
11
11
  /** **(Optional)** Specify a custom element to override default `a` or `span`. */
@@ -43,7 +43,7 @@ export const Pill = ({
43
43
  }: PillProps): JSX.Element => {
44
44
  let element: PillProps["as"] = href ? "a" : "span"
45
45
 
46
- const slots = getSlots(componentSlots, children)
46
+ const slots = useSlots(componentSlots, children)
47
47
 
48
48
  if (as) {
49
49
  element = as
@@ -2,23 +2,22 @@ import clsx from "clsx"
2
2
  import { type InputHTMLAttributes, type JSX, useId } from "react"
3
3
  import { StandardSizes } from "src/types"
4
4
 
5
- export interface RadioButtonProps
6
- extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
5
+ export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
7
6
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
8
7
  className?: string
9
- /** **(Optional)** Specify whether the RadioButton should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
8
+ /** **(Optional)** Specify whether the Radio should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
10
9
  disabled?: boolean
11
- /** **(Optional)** Specify the RadioButton error state. */
10
+ /** **(Optional)** Specify the Radio error state. */
12
11
  error?: boolean
13
- /** **(Optional)** Specify the RadioButton id. Will be auto-generated if not set. */
12
+ /** **(Optional)** Specify the Radio id. Will be auto-generated if not set. */
14
13
  id?: string
15
- /** Specify the RadioButton name. */
14
+ /** Specify the Radio name. */
16
15
  name: string
17
- /** **(Optional)** Specify the RadioButton size. */
16
+ /** **(Optional)** Specify the Radio size. */
18
17
  size?: StandardSizes
19
18
  }
20
19
 
21
- export const RadioButton = ({
20
+ export const Radio = ({
22
21
  className,
23
22
  disabled,
24
23
  error = false,
@@ -26,13 +25,13 @@ export const RadioButton = ({
26
25
  name,
27
26
  size = "md",
28
27
  ...props
29
- }: RadioButtonProps): JSX.Element => {
28
+ }: RadioProps): JSX.Element => {
30
29
  const internalId = useId()
31
30
 
32
31
  id = id ?? internalId
33
32
 
34
33
  const componentProps = {
35
- className: clsx("coop-radio-button", className),
34
+ className: clsx("coop-radio", className),
36
35
  "data-error": error || undefined,
37
36
  "data-size": size.length && size !== "md" ? size : undefined,
38
37
  disabled,
@@ -45,4 +44,4 @@ export const RadioButton = ({
45
44
  return <input {...componentProps} />
46
45
  }
47
46
 
48
- export default RadioButton
47
+ export default Radio
@@ -0,0 +1,5 @@
1
+ import Radio from "./Radio"
2
+
3
+ export default Radio
4
+ export { Radio }
5
+ export * from "./Radio"
@@ -5,13 +5,13 @@ import type { InputHTMLAttributes, JSX } from "react"
5
5
  import clsx from "clsx"
6
6
  import React, { useCallback, useId, useState } from "react"
7
7
 
8
- import { StandardSizes } from "../../../src/types"
8
+ import { StandardSizes } from "../../types"
9
9
  import { Button, type ButtonProps } from "../Button"
10
10
  import { Label as FieldLabel } from "../FieldMarkers/Label"
11
11
  import { SearchIcon } from "../Icon"
12
12
  import TextInput, { TextInputProps } from "../TextInput"
13
13
 
14
- export interface SearchBoxProps
14
+ export interface SearchboxProps
15
15
  extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
16
16
  /** **(Optional)** Specify a server endpoint to submit the form. Will be ignored if onSubmit is also set. */
17
17
  action?: string
@@ -27,13 +27,13 @@ export interface SearchBoxProps
27
27
  labelVisible?: boolean
28
28
  /** **(Optional)** Specify the TextInput name, also used as the URL search parameter. Defaults to `query`. */
29
29
  name?: string
30
- /** **(Optional)** Callback to run when the form is submitted. If this is an async function, it will be awaited and the SearchBox will be in a pending state until the promise is resolved. */
30
+ /** **(Optional)** Callback to run when the form is submitted. If this is an async function, it will be awaited and the Searchbox will be in a pending state until the promise is resolved. */
31
31
  onSubmit?: React.FormEventHandler<HTMLElement> | undefined
32
32
  /** **(Optional)** Specify the TextInput placeholder text Do not use in place of a form label. */
33
33
  placeholder?: string
34
- /** **(Optional)** Specify the SearchBox size. */
34
+ /** **(Optional)** Specify the Searchbox size. */
35
35
  size?: StandardSizes
36
- /** **(Optional)** Specify the SearchBox variant. */
36
+ /** **(Optional)** Specify the Searchbox variant. */
37
37
  variant?:
38
38
  | "green"
39
39
  | "blue"
@@ -45,12 +45,12 @@ export interface SearchBoxProps
45
45
  | "grey-ghost"
46
46
  }
47
47
 
48
- const defaultButtonProps: SearchBoxProps["button"] = {
48
+ const defaultButtonProps: SearchboxProps["button"] = {
49
49
  label: React.createElement(SearchIcon, { alt: "Search", stroke: "currentColor", strokeWidth: 2 }),
50
50
  loadingText: "",
51
51
  }
52
52
 
53
- export const SearchBox = ({
53
+ export const Searchbox = ({
54
54
  action,
55
55
  "aria-placeholder": ariaPlaceholder,
56
56
  autoCapitalize = "off",
@@ -67,7 +67,7 @@ export const SearchBox = ({
67
67
  size = "md",
68
68
  variant = "green",
69
69
  ...props
70
- }: SearchBoxProps): JSX.Element => {
70
+ }: SearchboxProps): JSX.Element => {
71
71
  const [isPending, setIsPending] = useState(false)
72
72
  const internalId = useId()
73
73
 
@@ -92,7 +92,7 @@ export const SearchBox = ({
92
92
 
93
93
  const formProps = {
94
94
  action: action ?? undefined,
95
- className: clsx("coop-search-box", className),
95
+ className: clsx("coop-searchbox", className),
96
96
  "data-size": size && size !== "md" ? size : undefined,
97
97
  "data-variant": variant.length && variant !== "green" ? variant : undefined,
98
98
  onSubmit: onSubmit ? handleSubmit : undefined,
@@ -125,7 +125,7 @@ export const SearchBox = ({
125
125
  {label}
126
126
  </FieldLabel>
127
127
  )}
128
- <div className="coop-search-box--inner">
128
+ <div className="coop-searchbox--inner">
129
129
  <TextInput {...inputProps} />
130
130
 
131
131
  <Button {...buttonProps}>{button.label}</Button>
@@ -134,4 +134,4 @@ export const SearchBox = ({
134
134
  )
135
135
  }
136
136
 
137
- export default SearchBox
137
+ export default Searchbox
@@ -0,0 +1,5 @@
1
+ import Searchbox from "./Searchbox"
2
+
3
+ export default Searchbox
4
+ export { Searchbox }
5
+ export * from "./Searchbox"
@@ -26,7 +26,19 @@ export interface TextInputProps
26
26
  /** **(Optional)** Specify the suffix. It can be any valid JSX or string. */
27
27
  suffix?: React.ReactNode
28
28
  /** **(Optional)** Specify the TextInput type. */
29
- type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url"
29
+ type?:
30
+ | "text"
31
+ | "email"
32
+ | "number"
33
+ | "password"
34
+ | "search"
35
+ | "tel"
36
+ | "url"
37
+ | "date"
38
+ | "datetime-local"
39
+ | "week"
40
+ | "month"
41
+ | "time"
30
42
  }
31
43
 
32
44
  export const TextInput = ({
@@ -12,7 +12,7 @@ export function getSlotName(node: React.ReactNode): string | false {
12
12
  : false
13
13
  }
14
14
 
15
- export function getSlots<T>(
15
+ export function useSlots<T>(
16
16
  componentSlots: Slots<T>,
17
17
  children: React.ReactNode,
18
18
  options?: { collect?: string[] }
package/src/index.ts CHANGED
@@ -9,9 +9,9 @@ export * from "./components/Fieldset"
9
9
  export * from "./components/Flourish"
10
10
  export * from "./components/Image"
11
11
  export * from "./components/Pill"
12
- export * from "./components/RadioButton"
12
+ export * from "./components/Radio"
13
13
  export * from "./components/RootSVG"
14
- export * from "./components/SearchBox"
14
+ export * from "./components/Searchbox"
15
15
  export * from "./components/Signpost"
16
16
  export * from "./components/SkipNav"
17
17
  export * from "./components/Squircle"
@@ -1,18 +0,0 @@
1
- import { type InputHTMLAttributes, type JSX } from "react";
2
- import { StandardSizes } from "src/types";
3
- export interface RadioButtonProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
4
- /** **(Optional)** Specify additional CSS classes to be applied to the component. */
5
- className?: string;
6
- /** **(Optional)** Specify whether the RadioButton should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
7
- disabled?: boolean;
8
- /** **(Optional)** Specify the RadioButton error state. */
9
- error?: boolean;
10
- /** **(Optional)** Specify the RadioButton id. Will be auto-generated if not set. */
11
- id?: string;
12
- /** Specify the RadioButton name. */
13
- name: string;
14
- /** **(Optional)** Specify the RadioButton size. */
15
- size?: StandardSizes;
16
- }
17
- export declare const RadioButton: ({ className, disabled, error, id, name, size, ...props }: RadioButtonProps) => JSX.Element;
18
- export default RadioButton;
@@ -1,4 +0,0 @@
1
- import RadioButton from "./RadioButton";
2
- export default RadioButton;
3
- export { RadioButton };
4
- export * from "./RadioButton";
@@ -1,4 +0,0 @@
1
- import SearchBox from "./SearchBox";
2
- export default SearchBox;
3
- export { SearchBox };
4
- export * from "./SearchBox";
@@ -1,5 +0,0 @@
1
- import RadioButton from "./RadioButton"
2
-
3
- export default RadioButton
4
- export { RadioButton }
5
- export * from "./RadioButton"
@@ -1,5 +0,0 @@
1
- import SearchBox from "./SearchBox"
2
-
3
- export default SearchBox
4
- export { SearchBox }
5
- export * from "./SearchBox"