@coopdigital/react 0.44.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 (85) 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/Checkbox/Checkbox.d.ts +4 -24
  5. package/dist/components/Checkbox/Checkbox.js +7 -14
  6. package/dist/components/Checkbox/index.d.ts +1 -2
  7. package/dist/components/Expandable/Expandable.js +2 -2
  8. package/dist/components/Field/Field.d.ts +44 -5
  9. package/dist/components/Field/Field.js +68 -5
  10. package/dist/components/FieldMarkers/Error.d.ts +9 -0
  11. package/dist/components/{FieldError/FieldError.js → FieldMarkers/Error.js} +2 -2
  12. package/dist/components/FieldMarkers/Hint.d.ts +9 -0
  13. package/dist/components/{FieldHint/FieldHint.js → FieldMarkers/Hint.js} +2 -2
  14. package/dist/components/FieldMarkers/Label.d.ts +11 -0
  15. package/dist/components/FieldMarkers/Label.js +8 -0
  16. package/dist/components/FieldMarkers/Legend.d.ts +11 -0
  17. package/dist/components/FieldMarkers/Legend.js +13 -0
  18. package/dist/components/Fieldset/Fieldset.d.ts +54 -0
  19. package/dist/components/Fieldset/Fieldset.js +44 -0
  20. package/dist/components/Fieldset/index.d.ts +4 -0
  21. package/dist/components/Pill/Pill.js +2 -2
  22. package/dist/components/Radio/Radio.d.ts +18 -0
  23. package/dist/components/Radio/Radio.js +22 -0
  24. package/dist/components/Radio/index.d.ts +4 -0
  25. package/dist/components/{SearchBox/SearchBox.d.ts → Searchbox/Searchbox.d.ts} +7 -7
  26. package/dist/components/{SearchBox/SearchBox.js → Searchbox/Searchbox.js} +6 -6
  27. package/dist/components/Searchbox/index.d.ts +4 -0
  28. package/dist/components/TextInput/TextInput.d.ts +5 -19
  29. package/dist/components/TextInput/TextInput.js +7 -11
  30. package/dist/components/Textarea/Textarea.d.ts +4 -18
  31. package/dist/components/Textarea/Textarea.js +8 -9
  32. package/dist/hooks/useId.d.ts +2 -0
  33. package/dist/hooks/useId.js +8 -0
  34. package/dist/{utils/slots.d.ts → hooks/useSlots.d.ts} +3 -1
  35. package/dist/{utils/slots.js → hooks/useSlots.js} +9 -3
  36. package/dist/index.d.ts +3 -5
  37. package/dist/index.js +4 -8
  38. package/package.json +10 -10
  39. package/src/components/Button/Button.tsx +10 -14
  40. package/src/components/Card/Card.tsx +2 -3
  41. package/src/components/Checkbox/Checkbox.tsx +8 -64
  42. package/src/components/Checkbox/index.ts +1 -2
  43. package/src/components/Expandable/Expandable.tsx +2 -2
  44. package/src/components/Field/Field.tsx +144 -8
  45. package/src/components/{FieldError/FieldError.tsx → FieldMarkers/Error.tsx} +4 -4
  46. package/src/components/{FieldHint/FieldHint.tsx → FieldMarkers/Hint.tsx} +5 -9
  47. package/src/components/FieldMarkers/Label.tsx +21 -0
  48. package/src/components/FieldMarkers/Legend.tsx +28 -0
  49. package/src/components/Fieldset/Fieldset.tsx +98 -0
  50. package/src/components/Fieldset/index.ts +5 -0
  51. package/src/components/Pill/Pill.tsx +2 -2
  52. package/src/components/Radio/Radio.tsx +47 -0
  53. package/src/components/Radio/index.ts +5 -0
  54. package/src/components/{SearchBox/SearchBox.tsx → Searchbox/Searchbox.tsx} +15 -13
  55. package/src/components/Searchbox/index.ts +5 -0
  56. package/src/components/TextInput/TextInput.tsx +25 -46
  57. package/src/components/Textarea/Textarea.tsx +12 -40
  58. package/src/hooks/useId.ts +9 -0
  59. package/src/{utils/slots.ts → hooks/useSlots.ts} +10 -2
  60. package/src/index.ts +3 -5
  61. package/dist/components/Checkbox/CheckboxGroup.d.ts +0 -32
  62. package/dist/components/Checkbox/CheckboxGroup.js +0 -21
  63. package/dist/components/FieldError/FieldError.d.ts +0 -9
  64. package/dist/components/FieldError/index.d.ts +0 -4
  65. package/dist/components/FieldHint/FieldHint.d.ts +0 -9
  66. package/dist/components/FieldHint/index.d.ts +0 -4
  67. package/dist/components/FieldLabel/FieldLabel.d.ts +0 -13
  68. package/dist/components/FieldLabel/FieldLabel.js +0 -13
  69. package/dist/components/FieldLabel/index.d.ts +0 -4
  70. package/dist/components/RadioButton/RadioButton.d.ts +0 -36
  71. package/dist/components/RadioButton/RadioButton.js +0 -26
  72. package/dist/components/RadioButton/RadioButtonGroup.d.ts +0 -32
  73. package/dist/components/RadioButton/RadioButtonGroup.js +0 -21
  74. package/dist/components/RadioButton/index.d.ts +0 -5
  75. package/dist/components/SearchBox/index.d.ts +0 -4
  76. package/dist/components/Tag/index.js +0 -5
  77. package/src/components/Checkbox/CheckboxGroup.tsx +0 -73
  78. package/src/components/FieldError/index.ts +0 -5
  79. package/src/components/FieldHint/index.ts +0 -5
  80. package/src/components/FieldLabel/FieldLabel.tsx +0 -31
  81. package/src/components/FieldLabel/index.ts +0 -5
  82. package/src/components/RadioButton/RadioButton.tsx +0 -97
  83. package/src/components/RadioButton/RadioButtonGroup.tsx +0 -73
  84. package/src/components/RadioButton/index.ts +0 -6
  85. package/src/components/SearchBox/index.ts +0 -5
@@ -1,20 +1,156 @@
1
- import type { HTMLAttributes, JSX, ReactNode } from "react"
1
+ import type { HTMLAttributes, HTMLProps, JSX } from "react"
2
2
 
3
3
  import clsx from "clsx"
4
+ import React from "react"
4
5
 
5
- export interface FieldProps extends HTMLAttributes<HTMLDivElement> {
6
- /** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
7
- children?: string | ReactNode
6
+ import { useId } from "../../hooks/useId"
7
+ import { useSlots } from "../../hooks/useSlots"
8
+ import { Error as BaseError, type ErrorProps } from "../FieldMarkers/Error"
9
+ import { Hint as BaseHint, type HintProps } from "../FieldMarkers/Hint"
10
+ import { Label as BaseLabel, type LabelProps } from "../FieldMarkers/Label"
11
+
12
+ const componentSlots = {
13
+ Checkbox: null,
14
+ Children: null,
15
+ Control: null,
16
+ FieldError: null,
17
+ FieldHint: null,
18
+ FieldLabel: null,
19
+ Radio: null,
20
+ Textarea: null,
21
+ TextInput: null,
22
+ }
23
+
24
+ const standardFields = ["Children", "FieldError", "FieldHint", "FieldLabel"]
25
+ const inlineFields = ["Checkbox", "Radio"]
26
+
27
+ interface FieldProps extends HTMLAttributes<HTMLDivElement> {
28
+ /** **(Optional)** Specify whether the Field should render inside a box. */
29
+ boxed?: boolean
30
+ /** Form elements inside the Field.
31
+ *
32
+ * Usually this will be a combination of `Field.Label`, `Field.Hint`, `Field.Error` and an associated control such as `TextInput` or `Checkbox`. */
33
+ children: React.ReactNode
8
34
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
9
- className?: string
35
+ classname?: string
36
+ /** **(Optional)** Specify the Field error state. Use this to apply visual styling to the field control. */
37
+ error?: boolean
38
+ /** **(Optional)** Specify whether the Field should show the left-hand error bar if it is in an error state. */
39
+ hideErrorBar?: boolean
10
40
  }
11
41
 
12
- export const Field = ({ children, className, ...props }: FieldProps): JSX.Element => {
42
+ const Root = ({
43
+ boxed = false,
44
+ children,
45
+ className,
46
+ error = false,
47
+ hideErrorBar = false,
48
+ ...props
49
+ }: FieldProps) => {
50
+ const slots = { ...useSlots(componentSlots, children) }
51
+ const slotsArray = Object.entries(slots)
52
+
53
+ const uid = useId()
54
+
55
+ const isInlineControl = slotsArray.some((s) => s[1] !== null && inlineFields.includes(s[0]))
56
+ const hasFieldMarkers = !!(slots.FieldLabel ?? slots.FieldError ?? slots.FieldHint)
57
+ const [, control] =
58
+ slotsArray.find((s) => (!standardFields.includes(s[0]) && s[1] !== null ? s : null)) ?? []
59
+
60
+ let controlId = uid
61
+ let controlDisabled = false
62
+
63
+ if (control) {
64
+ if (typeof control === "object" && "props" in control) {
65
+ const controlProps = control.props as HTMLProps<HTMLElement>
66
+ controlId = controlProps.id ?? controlId
67
+ controlDisabled = controlProps.disabled ?? false
68
+ }
69
+
70
+ slots.Control = React.cloneElement(control as React.ReactElement<HTMLInputElement>, {
71
+ id: controlId,
72
+ })
73
+ }
74
+
75
+ if (slots.FieldLabel && React.isValidElement(slots.FieldLabel)) {
76
+ slots.FieldLabel = React.cloneElement(slots.FieldLabel as React.ReactElement<LabelProps>, {
77
+ htmlFor: (slots.FieldLabel.props as LabelProps).htmlFor ?? controlId,
78
+ })
79
+ }
80
+
13
81
  const componentProps = {
14
- className: clsx("coop-form-item ", className),
15
82
  ...props,
83
+ "aria-disabled": controlDisabled || undefined,
84
+ className: clsx("coop-field", isInlineControl && "coop-field-inline", className),
85
+ "data-boxed": boxed || undefined,
86
+ "data-error": error || undefined,
87
+ "data-hide-error": hideErrorBar || undefined,
16
88
  }
17
- return <div {...componentProps}>{children}</div>
89
+
90
+ return (
91
+ <div {...componentProps}>
92
+ {!isInlineControl && hasFieldMarkers && (
93
+ <div className="coop-field-markers">
94
+ {slots.FieldLabel}
95
+ {slots.FieldHint}
96
+ {slots.FieldError}
97
+ </div>
98
+ )}
99
+ {slots.Control && (
100
+ <div className="coop-field-control">
101
+ {slots.Control}
102
+ {isInlineControl && hasFieldMarkers && (
103
+ <div className="coop-field-markers">
104
+ {slots.FieldLabel}
105
+ {slots.FieldHint}
106
+ {slots.FieldError}
107
+ </div>
108
+ )}
109
+ </div>
110
+ )}
111
+ {slots.Children}
112
+ </div>
113
+ )
18
114
  }
19
115
 
116
+ interface ControlProps extends HTMLAttributes<HTMLDivElement> {
117
+ /** **(Optional)** Elements inside the form control. */
118
+ children?: string | React.ReactNode
119
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
120
+ className?: string
121
+ }
122
+
123
+ export const FieldControl = ({ children, className, ...props }: ControlProps): JSX.Element => {
124
+ return (
125
+ <div className={clsx("coop-field-control ", className)} {...props}>
126
+ {children}
127
+ </div>
128
+ )
129
+ }
130
+
131
+ FieldControl.displayName = "Field.Control"
132
+
133
+ const FieldLabel = (props: LabelProps) => <BaseLabel {...props} />
134
+
135
+ FieldLabel.displayName = "Field.Label"
136
+
137
+ const FieldHint = (props: HintProps) => <BaseHint {...props} />
138
+
139
+ FieldHint.displayName = "Field.Hint"
140
+
141
+ const FieldError = (props: ErrorProps) => <BaseError {...props} />
142
+
143
+ FieldError.displayName = "Field.Error"
144
+
145
+ export const Field = Object.assign(Root, {
146
+ Control: FieldControl,
147
+ Error: FieldError,
148
+ Hint: FieldHint,
149
+ Label: FieldLabel,
150
+ })
151
+
152
+ // Field.Label = FieldLabel
153
+ // Field.Hint = FieldHint
154
+ // Field.Error = FieldError
155
+
20
156
  export default Field
@@ -2,14 +2,14 @@ import type { HTMLAttributes, JSX, ReactNode } from "react"
2
2
 
3
3
  import clsx from "clsx"
4
4
 
5
- export interface FieldErrorProps extends HTMLAttributes<HTMLSpanElement> {
6
- /** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
5
+ export interface ErrorProps extends HTMLAttributes<HTMLSpanElement> {
6
+ /** **(Optional)** Error text for the form element. Accepts any valid JSX or string. */
7
7
  children?: string | ReactNode
8
8
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
9
9
  className?: string
10
10
  }
11
11
 
12
- export const FieldError = ({ children, className, ...props }: FieldErrorProps): JSX.Element => {
12
+ export const Error = ({ children, className, ...props }: ErrorProps): JSX.Element => {
13
13
  const componentProps = {
14
14
  className: clsx("coop-field-error ", className),
15
15
  ...props,
@@ -17,4 +17,4 @@ export const FieldError = ({ children, className, ...props }: FieldErrorProps):
17
17
  return <span {...componentProps}>{children}</span>
18
18
  }
19
19
 
20
- export default FieldError
20
+ export default Error
@@ -2,18 +2,14 @@ import type { HTMLAttributes, JSX, ReactNode } from "react"
2
2
 
3
3
  import clsx from "clsx"
4
4
 
5
- export interface FieldHintProps extends HTMLAttributes<HTMLParagraphElement> {
6
- /** Main content inside the component. It can be any valid JSX or string. */
7
- children: string | ReactNode
5
+ export interface HintProps extends HTMLAttributes<HTMLParagraphElement> {
6
+ /** **(Optional)** Hint text for the form element. Accepts any valid JSX or string. */
7
+ children?: string | ReactNode
8
8
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
9
9
  className?: string
10
10
  }
11
11
 
12
- export const FieldHint = ({
13
- children,
14
- className,
15
- ...props
16
- }: FieldHintProps): JSX.Element | null => {
12
+ export const Hint = ({ children, className, ...props }: HintProps): JSX.Element | null => {
17
13
  const componentProps = {
18
14
  className: clsx("coop-field-hint ", className),
19
15
  ...props,
@@ -22,4 +18,4 @@ export const FieldHint = ({
22
18
  return children ? <div {...componentProps}>{children}</div> : null
23
19
  }
24
20
 
25
- export default FieldHint
21
+ export default Hint
@@ -0,0 +1,21 @@
1
+ import clsx from "clsx"
2
+ import { LabelHTMLAttributes } from "react"
3
+
4
+ export interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
5
+ /** **(Optional)** Main label for the form element. Accepts any valid JSX or string. */
6
+ children?: string | React.ReactNode
7
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
8
+ className?: string
9
+ /** **(Optional)** Specify whether the label is visible for humans or only for screen readers. */
10
+ isVisible?: boolean
11
+ }
12
+
13
+ export const Label = ({ children, className, isVisible = true, ...props }: LabelProps) => {
14
+ return (
15
+ <label {...props} className={clsx("coop-field-label", !isVisible && "sr-only", className)}>
16
+ <span>{children}</span>
17
+ </label>
18
+ )
19
+ }
20
+
21
+ export default Label
@@ -0,0 +1,28 @@
1
+ import clsx from "clsx"
2
+ import { HTMLAttributes } from "react"
3
+
4
+ export interface LegendProps extends HTMLAttributes<HTMLLegendElement> {
5
+ /** **(Optional)** Main legend for the fieldset. Accepts any valid JSX or string. */
6
+ children?: string | React.ReactNode
7
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
8
+ className?: string
9
+ /** **(Optional)** Specify whether the legend should be visible to humans or screen readers. */
10
+ isVisible?: boolean
11
+ }
12
+
13
+ export const Legend = ({ children, className, isVisible = true, ...props }: LegendProps) => {
14
+ const componentProps = {
15
+ "aria-hidden": true,
16
+ className: clsx("coop-field-label", !isVisible && "sr-only", className),
17
+ ...props,
18
+ }
19
+
20
+ return (
21
+ <>
22
+ <legend className="sr-only">{children}</legend>
23
+ {isVisible && <div {...componentProps}>{children}</div>}
24
+ </>
25
+ )
26
+ }
27
+
28
+ export default Legend
@@ -0,0 +1,98 @@
1
+ import clsx from "clsx"
2
+ import { type FieldsetHTMLAttributes, type JSX } from "react"
3
+
4
+ import { StandardSizes } from "../../../src/types"
5
+ import { Error as BaseError, type ErrorProps } from "../FieldMarkers/Error"
6
+ import { Hint as BaseHint, type HintProps } from "../FieldMarkers/Hint"
7
+ import { Legend as BaseLegend, type LegendProps } from "../FieldMarkers/Legend"
8
+
9
+ export interface FieldsetProps extends FieldsetHTMLAttributes<HTMLFieldSetElement> {
10
+ /** Form elements inside the Fieldset.
11
+ *
12
+ * Usually this will be a combination of `Fieldset.Legend` and `Fieldset.Fields`. */
13
+ children: React.ReactNode
14
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
15
+ className?: string
16
+ /** **(Optional)** Specify whether the Fieldset, and all of its descendents, should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
17
+ disabled?: boolean
18
+ /** **(Optional)** Specify the Fieldset error state. Use this to apply visual styling to the field control. */
19
+ error?: boolean
20
+ /** **(Optional)** Specify whether the Fieldset should show the left-hand error bar if it is in an error state. */
21
+ hideErrorBar?: boolean
22
+ /** **(Optional)** Specify the size of the Fieldset and all its descendents. */
23
+ size?: StandardSizes
24
+ }
25
+ const Root = ({
26
+ children,
27
+ className,
28
+ disabled,
29
+ error = false,
30
+ hideErrorBar = false,
31
+ size = "md",
32
+ ...props
33
+ }: FieldsetProps): JSX.Element => {
34
+ const componentProps = {
35
+ "aria-disabled": disabled,
36
+ className: clsx("coop-fieldset", className),
37
+ "data-error": error || undefined,
38
+ //"data-variant": variant !== "default" ? variant : undefined,
39
+ "data-hide-error": hideErrorBar || undefined,
40
+ // "data-orientation": orientation !== "vertical" ? orientation : undefined,
41
+ "data-size": size.length && size !== "md" ? size : undefined,
42
+ disabled,
43
+ ...props,
44
+ }
45
+
46
+ return <fieldset {...componentProps}>{children}</fieldset>
47
+ }
48
+
49
+ interface FieldsetFieldsProps {
50
+ /** **(Optional)** Specify whether all descendent Fields should render inside a box. */
51
+ boxed?: boolean
52
+ /** **(Optional)** Form elements inside the Fieldset.Fields container. */
53
+ children?: string | React.ReactNode
54
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
55
+ className?: string
56
+ /** **(Optional)** Specify the CheckboxGroup orientation. */
57
+ orientation?: "horizontal" | "vertical"
58
+ }
59
+
60
+ export const FieldsetFields = ({
61
+ boxed = false,
62
+ children,
63
+ className,
64
+ orientation = "vertical",
65
+ ...props
66
+ }: FieldsetFieldsProps): JSX.Element => {
67
+ const componentProps = {
68
+ className: clsx("coop-fieldset-fields", className),
69
+ "data-boxed": boxed || undefined,
70
+ "data-orientation": orientation !== "vertical" ? orientation : undefined,
71
+ ...props,
72
+ }
73
+
74
+ return <div {...componentProps}>{children}</div>
75
+ }
76
+
77
+ FieldsetFields.displayName = "Fieldset.Fields"
78
+
79
+ const FieldsetLegend = (props: LegendProps) => <BaseLegend {...props} />
80
+
81
+ FieldsetLegend.displayName = "Fieldset.Legend"
82
+
83
+ const FieldsetHint = (props: HintProps) => <BaseHint {...props} />
84
+
85
+ FieldsetHint.displayName = "Fieldset.Hint"
86
+
87
+ const FieldsetError = (props: ErrorProps) => <BaseError {...props} />
88
+
89
+ FieldsetError.displayName = "Fieldset.Error"
90
+
91
+ export const Fieldset = Object.assign(Root, {
92
+ Error: FieldsetError,
93
+ Fields: FieldsetFields,
94
+ Hint: FieldsetHint,
95
+ Legend: FieldsetLegend,
96
+ })
97
+
98
+ export default Fieldset
@@ -0,0 +1,5 @@
1
+ import Fieldset from "./Fieldset"
2
+
3
+ export default Fieldset
4
+ export { Fieldset }
5
+ export * from "./Fieldset"
@@ -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
@@ -0,0 +1,47 @@
1
+ import clsx from "clsx"
2
+ import { type InputHTMLAttributes, type JSX, useId } from "react"
3
+ import { StandardSizes } from "src/types"
4
+
5
+ export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
6
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
7
+ className?: string
8
+ /** **(Optional)** Specify whether the Radio should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
9
+ disabled?: boolean
10
+ /** **(Optional)** Specify the Radio error state. */
11
+ error?: boolean
12
+ /** **(Optional)** Specify the Radio id. Will be auto-generated if not set. */
13
+ id?: string
14
+ /** Specify the Radio name. */
15
+ name: string
16
+ /** **(Optional)** Specify the Radio size. */
17
+ size?: StandardSizes
18
+ }
19
+
20
+ export const Radio = ({
21
+ className,
22
+ disabled,
23
+ error = false,
24
+ id,
25
+ name,
26
+ size = "md",
27
+ ...props
28
+ }: RadioProps): JSX.Element => {
29
+ const internalId = useId()
30
+
31
+ id = id ?? internalId
32
+
33
+ const componentProps = {
34
+ className: clsx("coop-radio", className),
35
+ "data-error": error || undefined,
36
+ "data-size": size.length && size !== "md" ? size : undefined,
37
+ disabled,
38
+ id,
39
+ name,
40
+ type: "radio",
41
+ ...props,
42
+ }
43
+ //const formItemProps = { "aria-disabled": disabled ? true : undefined }
44
+ return <input {...componentProps} />
45
+ }
46
+
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
- import { FieldLabel } from "../FieldLabel"
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,18 +45,19 @@ 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",
57
57
  autoComplete = "off",
58
58
  button = defaultButtonProps,
59
59
  className,
60
+
60
61
  id,
61
62
  label,
62
63
  labelVisible = false,
@@ -66,7 +67,7 @@ export const SearchBox = ({
66
67
  size = "md",
67
68
  variant = "green",
68
69
  ...props
69
- }: SearchBoxProps): JSX.Element => {
70
+ }: SearchboxProps): JSX.Element => {
70
71
  const [isPending, setIsPending] = useState(false)
71
72
  const internalId = useId()
72
73
 
@@ -91,8 +92,8 @@ export const SearchBox = ({
91
92
 
92
93
  const formProps = {
93
94
  action: action ?? undefined,
94
- className: clsx("coop-search-box", className),
95
- //"data-size": size && size !== "md" ? size : undefined,
95
+ className: clsx("coop-searchbox", className),
96
+ "data-size": size && size !== "md" ? size : undefined,
96
97
  "data-variant": variant.length && variant !== "green" ? variant : undefined,
97
98
  onSubmit: onSubmit ? handleSubmit : undefined,
98
99
  }
@@ -124,12 +125,13 @@ export const SearchBox = ({
124
125
  {label}
125
126
  </FieldLabel>
126
127
  )}
127
- <div className="coop-search-box--inner">
128
+ <div className="coop-searchbox--inner">
128
129
  <TextInput {...inputProps} />
130
+
129
131
  <Button {...buttonProps}>{button.label}</Button>
130
132
  </div>
131
133
  </form>
132
134
  )
133
135
  }
134
136
 
135
- 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"
@@ -1,12 +1,9 @@
1
1
  import type { InputHTMLAttributes, JSX } from "react"
2
2
 
3
3
  import clsx from "clsx"
4
- import { useId } from "react"
5
4
 
6
- import { FormFieldError, StandardSizes } from "../../../src/types"
7
- import { FieldError } from "../FieldError"
8
- import { FieldHint } from "../FieldHint"
9
- import { FieldLabel } from "../FieldLabel"
5
+ import { StandardSizes } from "../../../src/types"
6
+ import { useId } from "../../hooks/useId"
10
7
 
11
8
  export interface TextInputProps
12
9
  extends Omit<InputHTMLAttributes<HTMLInputElement>, "prefix" | "size" | "type"> {
@@ -14,24 +11,10 @@ export interface TextInputProps
14
11
  className?: string
15
12
  /** **(Optional)** Specify whether the TextInput should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
16
13
  disabled?: boolean
17
- /** **(Optional)** Specify the TextInput error state.
18
- *
19
- * This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
20
- */
21
- error?: FormFieldError
22
- /** **(Optional)** Specify the TextInput hint.
23
- *
24
- * This text is rendered under the label to provide further guidance for users.
25
- */
26
- hint?: string
14
+ /** **(Optional)** Specify the TextInput error state. */
15
+ error?: boolean
27
16
  /** **(Optional)** Specify the TextInput id. Will be auto-generated if not set. */
28
17
  id?: string
29
- /** **(Optional)** Specify the TextInput label.
30
- *
31
- * This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
32
- label?: string
33
- /** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
34
- labelVisible?: boolean
35
18
  /** Specify the TextInput name. */
36
19
  name: string
37
20
  /** **(Optional)** Specify the TextInput placeholder text. Do not use in place of a form label. */
@@ -43,7 +26,19 @@ export interface TextInputProps
43
26
  /** **(Optional)** Specify the suffix. It can be any valid JSX or string. */
44
27
  suffix?: React.ReactNode
45
28
  /** **(Optional)** Specify the TextInput type. */
46
- 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"
47
42
  }
48
43
 
49
44
  export const TextInput = ({
@@ -51,10 +46,7 @@ export const TextInput = ({
51
46
  className,
52
47
  disabled,
53
48
  error = false,
54
- hint,
55
49
  id,
56
- label,
57
- labelVisible = true,
58
50
  name,
59
51
  placeholder,
60
52
  prefix,
@@ -63,39 +55,26 @@ export const TextInput = ({
63
55
  type = "text",
64
56
  ...props
65
57
  }: TextInputProps): JSX.Element => {
66
- const internalId = useId()
67
-
68
- id = id ?? internalId
58
+ const uid = useId(id)
69
59
 
70
60
  const componentProps = {
71
61
  "aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
72
62
  className: clsx("coop-text-input", className),
73
- "data-error": error ? "" : undefined,
63
+ "data-error": error || undefined,
74
64
  "data-size": size.length && size !== "md" ? size : undefined,
75
65
  disabled,
76
- id,
66
+ id: uid,
77
67
  name,
78
68
  placeholder,
79
69
  type,
80
70
  ...props,
81
71
  }
82
- const formItemProps = { "aria-disabled": disabled ? true : undefined }
72
+ //const formItemProps = { "aria-disabled": disabled ? true : undefined }
83
73
  return (
84
- <div className="coop-form-item" {...formItemProps}>
85
- {label && (
86
- <FieldLabel htmlFor={id} isVisible={labelVisible}>
87
- {label}
88
- </FieldLabel>
89
- )}
90
-
91
- {hint && <FieldHint>{hint}</FieldHint>}
92
-
93
- {typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
94
- <div className="coop-text-input-wrapper">
95
- {prefix && <span className="coop-text-input--prefix">{prefix}</span>}
96
- <input {...componentProps} />
97
- {suffix && <span className="coop-text-input--suffix">{suffix}</span>}
98
- </div>
74
+ <div className="coop-text-input-wrapper">
75
+ {prefix && <span className="coop-text-input--prefix">{prefix}</span>}
76
+ <input {...componentProps} />
77
+ {suffix && <span className="coop-text-input--suffix">{suffix}</span>}
99
78
  </div>
100
79
  )
101
80
  }