@coopdigital/react 1.4.1 → 1.5.1

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 (205) hide show
  1. package/dist/components/AlertBanner/AlertBanner.d.ts +12 -2
  2. package/dist/components/AlertBanner/AlertBanner.js +3 -2
  3. package/dist/components/Author/Author.d.ts +7 -1
  4. package/dist/components/Author/Author.js +1 -0
  5. package/dist/components/Button/Button.d.ts +7 -1
  6. package/dist/components/Button/Button.js +1 -1
  7. package/dist/components/Card/Card.d.ts +41 -7
  8. package/dist/components/Card/Card.js +7 -6
  9. package/dist/components/Checkbox/Checkbox.d.ts +6 -4
  10. package/dist/components/Checkbox/Checkbox.js +8 -6
  11. package/dist/components/DatePicker/DatePicker.d.ts +8 -3
  12. package/dist/components/DatePicker/DatePicker.js +11 -12
  13. package/dist/components/Expandable/Expandable.d.ts +21 -5
  14. package/dist/components/Expandable/Expandable.js +4 -3
  15. package/dist/components/Field/Field.context.d.ts +14 -0
  16. package/dist/components/Field/Field.context.js +13 -0
  17. package/dist/components/Field/Field.d.ts +30 -8
  18. package/dist/components/Field/Field.js +32 -34
  19. package/dist/components/Field/index.js +1 -0
  20. package/dist/components/FieldMarkers/Label.d.ts +1 -1
  21. package/dist/components/FieldMarkers/Label.js +4 -0
  22. package/dist/components/FieldMarkers/Legend.d.ts +1 -1
  23. package/dist/components/Fieldset/Fieldset.d.ts +36 -8
  24. package/dist/components/Fieldset/Fieldset.js +6 -5
  25. package/dist/components/Flourish/Flourish.d.ts +7 -1
  26. package/dist/components/Flourish/Flourish.js +1 -0
  27. package/dist/components/Form/Form.d.ts +7 -1
  28. package/dist/components/Form/Form.js +1 -0
  29. package/dist/components/Image/Image.d.ts +7 -1
  30. package/dist/components/Image/Image.js +1 -0
  31. package/dist/components/Pill/Pill.d.ts +13 -3
  32. package/dist/components/Pill/Pill.js +3 -2
  33. package/dist/components/Popover/Popover.d.ts +33 -5
  34. package/dist/components/Popover/Popover.js +6 -5
  35. package/dist/components/Popover/index.js +1 -0
  36. package/dist/components/Radio/Radio.d.ts +6 -4
  37. package/dist/components/Radio/Radio.js +8 -6
  38. package/dist/components/RootSVG/RootSVG.d.ts +7 -1
  39. package/dist/components/RootSVG/RootSVG.js +1 -0
  40. package/dist/components/Searchbox/Searchbox.context.d.ts +13 -0
  41. package/dist/components/Searchbox/Searchbox.context.js +11 -0
  42. package/dist/components/Searchbox/Searchbox.d.ts +16 -12
  43. package/dist/components/Searchbox/Searchbox.js +25 -29
  44. package/dist/components/Select/Select.d.ts +18 -5
  45. package/dist/components/Select/Select.js +8 -9
  46. package/dist/components/Signpost/Signpost.d.ts +7 -1
  47. package/dist/components/Signpost/Signpost.js +1 -0
  48. package/dist/components/SkipNav/SkipNav.d.ts +7 -1
  49. package/dist/components/SkipNav/SkipNav.js +1 -0
  50. package/dist/components/Squircle/Squircle.d.ts +7 -1
  51. package/dist/components/Squircle/Squircle.js +1 -0
  52. package/dist/components/Tag/Tag.d.ts +7 -1
  53. package/dist/components/Tag/Tag.js +1 -0
  54. package/dist/components/TextInput/TextInput.d.ts +4 -3
  55. package/dist/components/TextInput/TextInput.js +5 -6
  56. package/dist/components/Textarea/Textarea.d.ts +4 -3
  57. package/dist/components/Textarea/Textarea.js +4 -7
  58. package/dist/components/ValidationSummary/ValidationSummary.d.ts +26 -4
  59. package/dist/components/ValidationSummary/ValidationSummary.js +7 -6
  60. package/dist/components/icons/AccountCircleFilledIcon.d.ts +1 -1
  61. package/dist/components/icons/AccountCircleIcon.d.ts +1 -1
  62. package/dist/components/icons/AccountFilledIcon.d.ts +1 -1
  63. package/dist/components/icons/AccountIcon.d.ts +1 -1
  64. package/dist/components/icons/AddIcon.d.ts +1 -1
  65. package/dist/components/icons/AppsFilledIcon.d.ts +1 -1
  66. package/dist/components/icons/AppsIcon.d.ts +1 -1
  67. package/dist/components/icons/ArrowDownIcon.d.ts +1 -1
  68. package/dist/components/icons/ArrowLeftIcon.d.ts +1 -1
  69. package/dist/components/icons/ArrowRightIcon.d.ts +1 -1
  70. package/dist/components/icons/ArrowUpIcon.d.ts +1 -1
  71. package/dist/components/icons/BackspaceFilledIcon.d.ts +1 -1
  72. package/dist/components/icons/BackspaceIcon.d.ts +1 -1
  73. package/dist/components/icons/BasketFilledIcon.d.ts +1 -1
  74. package/dist/components/icons/BasketIcon.d.ts +1 -1
  75. package/dist/components/icons/BellFilledIcon.d.ts +1 -1
  76. package/dist/components/icons/BellIcon.d.ts +1 -1
  77. package/dist/components/icons/BroomIcon.d.ts +1 -1
  78. package/dist/components/icons/CalendarFilledIcon.d.ts +1 -1
  79. package/dist/components/icons/CalendarIcon.d.ts +1 -1
  80. package/dist/components/icons/CashFilledIcon.d.ts +1 -1
  81. package/dist/components/icons/CashIcon.d.ts +1 -1
  82. package/dist/components/icons/ChevronDownIcon.d.ts +1 -1
  83. package/dist/components/icons/ChevronLeftIcon.d.ts +1 -1
  84. package/dist/components/icons/ChevronRightIcon.d.ts +1 -1
  85. package/dist/components/icons/ChevronUpIcon.d.ts +1 -1
  86. package/dist/components/icons/CircleBurgerFilledIcon.d.ts +1 -1
  87. package/dist/components/icons/CircleBurgerIcon.d.ts +1 -1
  88. package/dist/components/icons/ClipboardFilledIcon.d.ts +1 -1
  89. package/dist/components/icons/ClipboardIcon.d.ts +1 -1
  90. package/dist/components/icons/ClockFilledIcon.d.ts +1 -1
  91. package/dist/components/icons/ClockIcon.d.ts +1 -1
  92. package/dist/components/icons/CloseAltFilledIcon.d.ts +1 -1
  93. package/dist/components/icons/CloseAltIcon.d.ts +1 -1
  94. package/dist/components/icons/CogIcon.d.ts +1 -1
  95. package/dist/components/icons/CommunityFilledIcon.d.ts +1 -1
  96. package/dist/components/icons/CommunityIcon.d.ts +1 -1
  97. package/dist/components/icons/ComputerIcon.d.ts +1 -1
  98. package/dist/components/icons/ContactFilledIcon.d.ts +1 -1
  99. package/dist/components/icons/ContactIcon.d.ts +1 -1
  100. package/dist/components/icons/ContactlessFilledIcon.d.ts +1 -1
  101. package/dist/components/icons/ContactlessIcon.d.ts +1 -1
  102. package/dist/components/icons/CoopLiveIcon.d.ts +1 -1
  103. package/dist/components/icons/CoopLocationFilledIcon.d.ts +1 -1
  104. package/dist/components/icons/CoopLogoIcon.d.ts +1 -1
  105. package/dist/components/icons/CoopMembershipCardFilledIcon.d.ts +1 -1
  106. package/dist/components/icons/CreditCardFilledIcon.d.ts +1 -1
  107. package/dist/components/icons/CreditCardIcon.d.ts +1 -1
  108. package/dist/components/icons/CrossIcon.d.ts +1 -1
  109. package/dist/components/icons/DocumentIcon.d.ts +1 -1
  110. package/dist/components/icons/DownloadIcon.d.ts +1 -1
  111. package/dist/components/icons/EnterStoreIcon.d.ts +1 -1
  112. package/dist/components/icons/ExitStoreIcon.d.ts +1 -1
  113. package/dist/components/icons/EyeFilledIcon.d.ts +1 -1
  114. package/dist/components/icons/EyeIcon.d.ts +1 -1
  115. package/dist/components/icons/EyeStrikeFilledIcon.d.ts +1 -1
  116. package/dist/components/icons/EyeStrikeIcon.d.ts +1 -1
  117. package/dist/components/icons/FeedbackFilledIcon.d.ts +1 -1
  118. package/dist/components/icons/FeedbackIcon.d.ts +1 -1
  119. package/dist/components/icons/FilterIcon.d.ts +1 -1
  120. package/dist/components/icons/GiftCardFilledIcon.d.ts +1 -1
  121. package/dist/components/icons/GiftCardIcon.d.ts +1 -1
  122. package/dist/components/icons/GiftFilledIcon.d.ts +1 -1
  123. package/dist/components/icons/GiftIcon.d.ts +1 -1
  124. package/dist/components/icons/HelpFilledIcon.d.ts +1 -1
  125. package/dist/components/icons/HelpIcon.d.ts +1 -1
  126. package/dist/components/icons/HomeFilledIcon.d.ts +1 -1
  127. package/dist/components/icons/HomeIcon.d.ts +1 -1
  128. package/dist/components/icons/HowDoIAssistantIcon.d.ts +1 -1
  129. package/dist/components/icons/InfoIcon.d.ts +1 -1
  130. package/dist/components/icons/KebabIcon.d.ts +1 -1
  131. package/dist/components/icons/LoadingIcon.d.ts +1 -1
  132. package/dist/components/icons/LocationFilledIcon.d.ts +1 -1
  133. package/dist/components/icons/LocationIcon.d.ts +1 -1
  134. package/dist/components/icons/LogoutIcon.d.ts +1 -1
  135. package/dist/components/icons/MailIcon.d.ts +1 -1
  136. package/dist/components/icons/MenuIcon.d.ts +1 -1
  137. package/dist/components/icons/MessageIcon.d.ts +1 -1
  138. package/dist/components/icons/MinusIcon.d.ts +1 -1
  139. package/dist/components/icons/NotesFilledIcon.d.ts +1 -1
  140. package/dist/components/icons/NotesIcon.d.ts +1 -1
  141. package/dist/components/icons/OpenNewIcon.d.ts +1 -1
  142. package/dist/components/icons/OwnBagIcon.d.ts +1 -1
  143. package/dist/components/icons/PadlockIcon.d.ts +1 -1
  144. package/dist/components/icons/PencilIcon.d.ts +1 -1
  145. package/dist/components/icons/PhoneIcon.d.ts +1 -1
  146. package/dist/components/icons/PowerIcon.d.ts +1 -1
  147. package/dist/components/icons/SaveFilledIcon.d.ts +1 -1
  148. package/dist/components/icons/SaveIcon.d.ts +1 -1
  149. package/dist/components/icons/ScooterIcon.d.ts +1 -1
  150. package/dist/components/icons/SearchFilledIcon.d.ts +1 -1
  151. package/dist/components/icons/SearchIcon.d.ts +1 -1
  152. package/dist/components/icons/SendIcon.d.ts +1 -1
  153. package/dist/components/icons/SpannerIcon.d.ts +1 -1
  154. package/dist/components/icons/StarFilledIcon.d.ts +1 -1
  155. package/dist/components/icons/StarIcon.d.ts +1 -1
  156. package/dist/components/icons/TickAltFilledIcon.d.ts +1 -1
  157. package/dist/components/icons/TickAltIcon.d.ts +1 -1
  158. package/dist/components/icons/TickIcon.d.ts +1 -1
  159. package/dist/components/icons/TruckIcon.d.ts +1 -1
  160. package/dist/components/icons/UserWipeIcon.d.ts +1 -1
  161. package/dist/components/icons/VoucherFilledIcon.d.ts +1 -1
  162. package/dist/components/icons/VoucherIcon.d.ts +1 -1
  163. package/dist/components/icons/WarningFilledIcon.d.ts +1 -1
  164. package/dist/components/icons/WarningIcon.d.ts +1 -1
  165. package/dist/components/icons/WifiIcon.d.ts +1 -1
  166. package/dist/components/icons/WriteIcon.d.ts +1 -1
  167. package/dist/hooks/useSlots.d.ts +4 -2
  168. package/dist/hooks/useSlots.js +33 -7
  169. package/dist/index.js +10 -10
  170. package/dist/types/index.d.ts +14 -14
  171. package/dist/utils/index.d.ts +1 -0
  172. package/dist/utils/index.js +9 -7
  173. package/package.json +12 -11
  174. package/src/components/AlertBanner/AlertBanner.tsx +5 -2
  175. package/src/components/Author/Author.tsx +4 -1
  176. package/src/components/Button/Button.tsx +5 -1
  177. package/src/components/Card/Card.tsx +8 -6
  178. package/src/components/Checkbox/Checkbox.tsx +13 -9
  179. package/src/components/DatePicker/DatePicker.tsx +15 -15
  180. package/src/components/Expandable/Expandable.tsx +5 -8
  181. package/src/components/Field/Field.context.ts +29 -0
  182. package/src/components/Field/Field.tsx +61 -56
  183. package/src/components/FieldMarkers/Label.tsx +4 -0
  184. package/src/components/Fieldset/Fieldset.tsx +7 -5
  185. package/src/components/Flourish/Flourish.tsx +4 -1
  186. package/src/components/Form/Form.tsx +4 -1
  187. package/src/components/Image/Image.tsx +4 -1
  188. package/src/components/Pill/Pill.tsx +4 -2
  189. package/src/components/Popover/Popover.tsx +7 -5
  190. package/src/components/Radio/Radio.tsx +12 -9
  191. package/src/components/RootSVG/RootSVG.tsx +4 -1
  192. package/src/components/Searchbox/Searchbox.context.tsx +20 -0
  193. package/src/components/Searchbox/Searchbox.tsx +55 -44
  194. package/src/components/Select/Select.tsx +11 -11
  195. package/src/components/Signpost/Signpost.tsx +4 -1
  196. package/src/components/SkipNav/SkipNav.tsx +4 -1
  197. package/src/components/Squircle/Squircle.tsx +4 -1
  198. package/src/components/Tag/Tag.tsx +4 -1
  199. package/src/components/TextInput/TextInput.tsx +8 -8
  200. package/src/components/Textarea/Textarea.tsx +7 -8
  201. package/src/components/ValidationSummary/ValidationSummary.tsx +12 -5
  202. package/src/hooks/useSlots.ts +37 -9
  203. package/src/types/index.ts +18 -14
  204. package/src/utils/index.ts +8 -6
  205. package/dist/node_modules/merge-refs/dist/index.js +0 -36
@@ -24,7 +24,7 @@ export interface FieldsetProps extends FieldsetHTMLAttributes<HTMLFieldSetElemen
24
24
  /** **(Optional)** Specify the size of the Fieldset and all its descendents. */
25
25
  size?: StandardSizes
26
26
  }
27
- export const Fieldset = ({
27
+ const Fieldset = ({
28
28
  children,
29
29
  className,
30
30
  disabled,
@@ -83,10 +83,11 @@ const FieldsetLegend = (props: LegendProps) => <BaseLegend {...props} />
83
83
  const FieldsetHint = (props: HintProps) => <BaseHint {...props} />
84
84
  const FieldsetError = (props: ErrorProps) => <BaseError {...props} />
85
85
 
86
- FieldsetFields.config = { name: "FieldsetField" }
87
- FieldsetLegend.config = { name: "FieldsetLegend" }
88
- FieldsetHint.config = { name: "FieldsetHint" }
89
- FieldsetError.config = { name: "FieldsetError" }
86
+ Fieldset.slot = { name: "Fieldset" }
87
+ FieldsetFields.slot = { name: "FieldsetField" }
88
+ FieldsetLegend.slot = { name: "FieldsetLegend" }
89
+ FieldsetHint.slot = { name: "FieldsetHint" }
90
+ FieldsetError.slot = { name: "FieldsetError" }
90
91
 
91
92
  Fieldset.Error = FieldsetError
92
93
  Fieldset.Fields = FieldsetFields
@@ -94,3 +95,4 @@ Fieldset.Hint = FieldsetHint
94
95
  Fieldset.Legend = FieldsetLegend
95
96
 
96
97
  export default Fieldset
98
+ export { Fieldset, FieldsetError, FieldsetFields, FieldsetHint, FieldsetLegend }
@@ -15,7 +15,7 @@ export interface FlourishProps extends SVGProps<SVGSVGElement> {
15
15
  ref?: Ref<SVGSVGElement>
16
16
  }
17
17
 
18
- export const Flourish = ({
18
+ const Flourish = ({
19
19
  children,
20
20
  className,
21
21
  fill = "brand-blue",
@@ -38,4 +38,7 @@ export const Flourish = ({
38
38
  )
39
39
  }
40
40
 
41
+ Flourish.slot = { name: "Flourish" }
42
+
41
43
  export default Flourish
44
+ export { Flourish }
@@ -11,7 +11,7 @@ export interface FormProps extends FormHTMLAttributes<HTMLFormElement> {
11
11
  ref?: Ref<HTMLFormElement>
12
12
  }
13
13
 
14
- export const Form = ({ children, className, ref, ...props }: FormProps): JSX.Element => {
14
+ const Form = ({ children, className, ref, ...props }: FormProps): JSX.Element => {
15
15
  const componentProps = {
16
16
  className: clsx("coop-form ", className),
17
17
  ...props,
@@ -24,4 +24,7 @@ export const Form = ({ children, className, ref, ...props }: FormProps): JSX.Ele
24
24
  )
25
25
  }
26
26
 
27
+ Form.slot = { name: "Form" }
28
+
27
29
  export default Form
30
+ export { Form }
@@ -36,7 +36,7 @@ const getContentfulParams = (src: string, width: string, height: string | undefi
36
36
  }
37
37
  }
38
38
 
39
- export const Image = ({
39
+ const Image = ({
40
40
  alt,
41
41
  crop,
42
42
  height,
@@ -64,4 +64,7 @@ export const Image = ({
64
64
  )
65
65
  }
66
66
 
67
+ Image.slot = { name: "Image" }
68
+
67
69
  export default Image
70
+ export { Image }
@@ -35,7 +35,7 @@ const componentSlots = {
35
35
  PillBadge: null,
36
36
  }
37
37
 
38
- export const Pill = ({
38
+ const Pill = ({
39
39
  as,
40
40
  children,
41
41
  className,
@@ -66,8 +66,10 @@ const PillBadge = ({ children, className }: PillBadgeProps) => {
66
66
  )
67
67
  }
68
68
 
69
- PillBadge.config = { name: "PillBadge" }
69
+ Pill.slot = { name: "Pill" }
70
+ PillBadge.slot = { name: "PillBadge" }
70
71
 
71
72
  Pill.Badge = PillBadge
72
73
 
73
74
  export default Pill
75
+ export { Pill, PillBadge }
@@ -76,7 +76,7 @@ const componentSlots = {
76
76
  PopoverTrigger: null,
77
77
  }
78
78
 
79
- export const Popover = ({ children, ...props }: PopoverProps): JSX.Element => {
79
+ const Popover = ({ children, ...props }: PopoverProps): JSX.Element => {
80
80
  const slots = useSlots(componentSlots, children)
81
81
 
82
82
  return (
@@ -182,10 +182,11 @@ const PopoverAnchor = ({
182
182
  return <RadixPopover.Anchor {...componentProps}>{children}</RadixPopover.Anchor>
183
183
  }
184
184
 
185
- PopoverTrigger.config = { name: "PopoverTrigger" }
186
- PopoverContent.config = { name: "PopoverContent" }
187
- PopoverClose.config = { name: "PopoverClose" }
188
- PopoverAnchor.config = { name: "PopoverAnchor" }
185
+ Popover.slot = { name: "Popover" }
186
+ PopoverTrigger.slot = { name: "PopoverTrigger" }
187
+ PopoverContent.slot = { name: "PopoverContent" }
188
+ PopoverClose.slot = { name: "PopoverClose" }
189
+ PopoverAnchor.slot = { name: "PopoverAnchor" }
189
190
 
190
191
  Popover.Trigger = PopoverTrigger
191
192
  Popover.Content = PopoverContent
@@ -193,3 +194,4 @@ Popover.Close = PopoverClose
193
194
  Popover.Anchor = PopoverAnchor
194
195
 
195
196
  export default Popover
197
+ export { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger }
@@ -1,8 +1,9 @@
1
+ "use client"
1
2
  import clsx from "clsx"
2
3
  import { type InputHTMLAttributes, type JSX, Ref } from "react"
3
4
 
4
- import { useId } from "../../hooks/useId"
5
- import { ComponentConfig, StandardSizes } from "../../types"
5
+ import { StandardSizes } from "../../types"
6
+ import { useField } from "../Field/Field.context"
6
7
 
7
8
  export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
8
9
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
@@ -21,7 +22,7 @@ export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
21
22
  size?: StandardSizes
22
23
  }
23
24
 
24
- export const Radio = ({
25
+ const Radio = ({
25
26
  className,
26
27
  disabled,
27
28
  error = false,
@@ -31,14 +32,14 @@ export const Radio = ({
31
32
  size,
32
33
  ...props
33
34
  }: RadioProps): JSX.Element => {
34
- const uid = useId(id)
35
+ const field = useField()
35
36
 
36
37
  const componentProps = {
37
38
  className: clsx("coop-radio", "coop-field-element", className),
38
39
  "data-error": error || undefined,
39
40
  "data-size": size ?? undefined,
40
41
  disabled,
41
- id: uid,
42
+ id: id ?? field?.id,
42
43
  name,
43
44
  type: "radio",
44
45
  ...props,
@@ -47,9 +48,11 @@ export const Radio = ({
47
48
  return <input {...componentProps} ref={ref} />
48
49
  }
49
50
 
50
- Radio.config = {
51
- isField: true,
52
- isInline: true,
53
- } satisfies ComponentConfig
51
+ Radio.slot = {
52
+ field: true,
53
+ inline: true,
54
+ name: "Radio",
55
+ }
54
56
 
55
57
  export default Radio
58
+ export { Radio }
@@ -1,4 +1,4 @@
1
- export const RootSVG = () => {
1
+ const RootSVG = () => {
2
2
  return (
3
3
  <svg
4
4
  height="0"
@@ -20,4 +20,7 @@ export const RootSVG = () => {
20
20
  )
21
21
  }
22
22
 
23
+ RootSVG.slot = { name: "RootSVG" }
24
+
23
25
  export default RootSVG
26
+ export { RootSVG }
@@ -0,0 +1,20 @@
1
+ import { createContext, RefObject, useContext } from "react"
2
+
3
+ import { StandardSizes } from "../../types"
4
+
5
+ interface SearchboxContextValue {
6
+ buttonId?: string
7
+ id?: string
8
+ inputId?: string
9
+ isLoading?: boolean
10
+ ref?: RefObject<HTMLFormElement | null> | null
11
+ size?: StandardSizes
12
+ }
13
+
14
+ export const SearchboxContext = createContext<SearchboxContextValue>({})
15
+
16
+ export const useSearchbox = () => {
17
+ const context = useContext(SearchboxContext)
18
+ if (!context) throw new Error("Searchbox components must be used inside <Searchbox>")
19
+ return context
20
+ }
@@ -1,6 +1,6 @@
1
1
  "use client"
2
2
 
3
- import type { FormHTMLAttributes, JSX, Ref } from "react"
3
+ import type { FormHTMLAttributes, JSX, RefObject } from "react"
4
4
 
5
5
  import clsx from "clsx"
6
6
  import React, { useCallback, useState } from "react"
@@ -8,11 +8,13 @@ import React, { useCallback, useState } from "react"
8
8
  import { useId } from "../../hooks/useId"
9
9
  import { useSlots } from "../../hooks/useSlots"
10
10
  import { StandardSizes } from "../../types"
11
- import { hasUserBorder } from "../../utils"
11
+ import { getSlotProp, hasUserBorder } from "../../utils"
12
12
  import { Button, type ButtonProps } from "../Button"
13
13
  import Field from "../Field"
14
+ import { FieldLabel } from "../Field/Field"
14
15
  import { SearchIcon } from "../icons"
15
16
  import TextInput, { TextInputProps } from "../TextInput"
17
+ import { SearchboxContext, useSearchbox } from "./Searchbox.context"
16
18
 
17
19
  export interface SearchboxProps extends FormHTMLAttributes<HTMLFormElement> {
18
20
  /** **(Optional)** Specify a server endpoint to submit the form. Will be ignored if onSubmit is also set. */
@@ -34,7 +36,7 @@ export interface SearchboxProps extends FormHTMLAttributes<HTMLFormElement> {
34
36
  /** **(Optional)** Specify the TextInput placeholder text Do not use in place of a form label. */
35
37
  placeholder?: string
36
38
  /** **(Optional)** Specify a custom React ref for this component. */
37
- ref?: Ref<HTMLFormElement>
39
+ ref?: RefObject<HTMLFormElement | null>
38
40
  /** **(Optional)** Specify the Searchbox size. */
39
41
  size?: StandardSizes
40
42
  /** **(Optional)** Specify the Searchbox variant. */
@@ -46,7 +48,7 @@ const componentSlots = {
46
48
  SearchboxInput: null,
47
49
  }
48
50
 
49
- export const Searchbox = ({
51
+ const Searchbox = ({
50
52
  action,
51
53
  children,
52
54
  className,
@@ -59,10 +61,13 @@ export const Searchbox = ({
59
61
  variant = "solid",
60
62
  ...props
61
63
  }: SearchboxProps): JSX.Element => {
62
- const slots = { ...useSlots(componentSlots, children) }
64
+ const slots = useSlots(componentSlots, children)
65
+ const uid = useId(id)
63
66
 
64
67
  const [isPending, setIsPending] = useState(false)
65
- const uid = useId(id)
68
+
69
+ const inputId = getSlotProp<string>(slots.SearchboxInput, "id") ?? uid + "__input"
70
+ const buttonId = getSlotProp<string>(slots.SearchboxButton, "id") ?? uid + "__button"
66
71
 
67
72
  const handleSubmit = useCallback(
68
73
  async (event: React.SubmitEvent<HTMLFormElement>) => {
@@ -91,63 +96,69 @@ export const Searchbox = ({
91
96
  className: clsx("coop-searchbox", borderClass, className),
92
97
  "data-size": size ?? undefined,
93
98
  "data-variant": variant.length && variant !== "solid" ? variant : undefined,
94
- id: uid + "__form",
99
+ id: id ?? undefined,
95
100
  onSubmit: onSubmit ? handleSubmit : undefined,
96
101
  ...props,
97
102
  }
98
103
 
99
- slots.SearchboxButton = React.cloneElement(
100
- slots.SearchboxButton as React.ReactElement<ButtonProps>,
101
- {
102
- isLoading: isPending,
103
- size,
104
- }
105
- )
106
-
107
- slots.SearchboxInput = React.cloneElement(
108
- slots.SearchboxInput as React.ReactElement<TextInputProps>,
109
- {
110
- autoCapitalize: "off",
111
- id: uid,
112
- size,
113
- type: "search",
114
- }
115
- )
116
-
117
- const labelProps = {
118
- htmlFor: uid,
119
- isVisible: labelVisible,
120
- }
121
-
122
104
  return (
123
- <form {...formProps} ref={ref}>
124
- {label && <Field.Label {...labelProps}>{label}</Field.Label>}
125
- <div className={clsx("coop-searchbox--inner")}>
126
- <Field>{slots.SearchboxInput}</Field>
127
- {slots.SearchboxButton}
128
- </div>
129
- </form>
105
+ <SearchboxContext.Provider value={{ buttonId, inputId, isLoading: isPending, ref, size }}>
106
+ <form {...formProps} ref={ref}>
107
+ {label && (
108
+ <FieldLabel htmlFor={inputId ?? uid} isVisible={labelVisible}>
109
+ {label}
110
+ </FieldLabel>
111
+ )}
112
+ <div className={clsx("coop-searchbox--inner")}>
113
+ <Field>{slots.SearchboxInput}</Field>
114
+ {slots.SearchboxButton}
115
+ </div>
116
+ </form>
117
+ </SearchboxContext.Provider>
130
118
  )
131
119
  }
132
120
 
133
- const SearchboxButton = ({ children, id, ...props }: ButtonProps) => {
134
- const uid = useId(id)
121
+ const SearchboxButton = ({ children, ...props }: ButtonProps) => {
122
+ // const uid = useId(id)
123
+ const searchbox = useSearchbox()
135
124
  const buttonProps = {
136
125
  children: children ?? (
137
- <SearchIcon alt="Search" id={uid + "__icon"} stroke="currentColor" width="24" />
126
+ <SearchIcon
127
+ alt="Search"
128
+ id={searchbox.buttonId + "__icon"}
129
+ stroke="currentColor"
130
+ width="24"
131
+ />
138
132
  ),
133
+ id: searchbox.buttonId,
134
+ isLoading: searchbox.isLoading,
135
+ size: searchbox.size,
139
136
  ...props,
140
137
  }
141
138
 
142
139
  return <Button {...buttonProps} />
143
140
  }
144
141
 
145
- const SearchboxInput = (props: TextInputProps) => <TextInput {...props} />
142
+ SearchboxButton.displayName = "Searchbox.Button"
143
+
144
+ const SearchboxInput = (props: TextInputProps) => {
145
+ const searchbox = useSearchbox()
146
+
147
+ return (
148
+ <TextInput
149
+ autoCapitalize="off"
150
+ id={searchbox.inputId}
151
+ size={searchbox.size}
152
+ type="search"
153
+ {...props}
154
+ />
155
+ )
156
+ }
157
+
158
+ SearchboxInput.displayName = "Searchbox.Input"
146
159
 
147
160
  Searchbox.Button = SearchboxButton
148
161
  Searchbox.Input = SearchboxInput
149
162
 
150
- SearchboxButton.config = { name: "SearchboxButton" }
151
- SearchboxInput.config = { isField: true, name: "SearchboxInput" }
152
-
153
163
  export default Searchbox
164
+ export { Searchbox, SearchboxButton, SearchboxInput }
@@ -1,3 +1,4 @@
1
+ "use client"
1
2
  import type {
2
3
  JSX,
3
4
  OptgroupHTMLAttributes,
@@ -9,8 +10,8 @@ import type {
9
10
 
10
11
  import clsx from "clsx"
11
12
 
12
- import { ComponentConfig, StandardSizes } from "../../../src/types"
13
- import { useId } from "../../hooks/useId"
13
+ import { StandardSizes } from "../../../src/types"
14
+ import { useField } from "../Field/Field.context"
14
15
 
15
16
  export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "size"> {
16
17
  /** **(Optional)** Options inside the Select. This should be a set of `Select.Option` or `Select.OptionGroup` components. */
@@ -47,7 +48,7 @@ interface SelectOptionProps extends OptionHTMLAttributes<HTMLOptionElement> {
47
48
  value: string
48
49
  }
49
50
 
50
- export const Select = ({
51
+ const Select = ({
51
52
  children,
52
53
  className,
53
54
  disabled,
@@ -58,13 +59,14 @@ export const Select = ({
58
59
  size,
59
60
  ...props
60
61
  }: SelectProps): JSX.Element => {
61
- const uid = useId(id)
62
+ const field = useField()
63
+
62
64
  const componentProps = {
63
65
  className: clsx("coop-select", "coop-field-element", className),
64
66
  "data-error": error ?? undefined,
65
67
  "data-size": size ?? undefined,
66
68
  disabled,
67
- id: uid,
69
+ id: id ?? field?.id,
68
70
  name,
69
71
  ...props,
70
72
  }
@@ -88,14 +90,12 @@ const SelectOption = ({ children, className, ...props }: SelectOptionProps): JSX
88
90
  )
89
91
  }
90
92
 
91
- SelectOption.config = { name: "SelectOption" }
92
- SelectOptionGroup.config = { name: "SelectOptionGroup" }
93
+ Select.slot = { name: "Select" }
94
+ SelectOption.slot = { name: "SelectOption" }
95
+ SelectOptionGroup.slot = { name: "SelectOptionGroup" }
93
96
 
94
97
  Select.OptionGroup = SelectOptionGroup
95
98
  Select.Option = SelectOption
96
99
 
97
- Select.config = {
98
- isField: true,
99
- } satisfies ComponentConfig
100
-
101
100
  export default Select
101
+ export { Select, SelectOption, SelectOptionGroup }
@@ -24,7 +24,7 @@ export interface SignpostProps extends HTMLAttributes<HTMLDivElement> {
24
24
  ref?: Ref<HTMLDivElement>
25
25
  }
26
26
 
27
- export const Signpost = ({
27
+ const Signpost = ({
28
28
  as,
29
29
  children,
30
30
  className,
@@ -58,4 +58,7 @@ export const Signpost = ({
58
58
  )
59
59
  }
60
60
 
61
+ Signpost.slot = { name: "Signpost" }
62
+
61
63
  export default Signpost
64
+ export { Signpost }
@@ -21,7 +21,7 @@ export interface SkipNavProps extends HTMLAttributes<HTMLDivElement> {
21
21
 
22
22
  const defaultLinks = [{ href: "#main", label: "Skip to main content" }]
23
23
 
24
- export const SkipNav = ({
24
+ const SkipNav = ({
25
25
  className,
26
26
  isVisible = false,
27
27
  links = defaultLinks,
@@ -53,4 +53,7 @@ export const SkipNav = ({
53
53
  )
54
54
  }
55
55
 
56
+ SkipNav.slot = { name: "SkipNav" }
57
+
56
58
  export default SkipNav
59
+ export { SkipNav }
@@ -14,7 +14,7 @@ export interface SquircleProps extends HTMLAttributes<HTMLDivElement> {
14
14
  size?: "sm" | "md" | "lg"
15
15
  }
16
16
 
17
- export const Squircle = ({
17
+ const Squircle = ({
18
18
  children,
19
19
  className,
20
20
  ref,
@@ -34,4 +34,7 @@ export const Squircle = ({
34
34
  )
35
35
  }
36
36
 
37
+ Squircle.slot = { name: "Squircle" }
38
+
37
39
  export default Squircle
40
+ export { Squircle }
@@ -21,7 +21,7 @@ export interface TagProps extends HTMLAttributes<HTMLAnchorElement> {
21
21
  size?: "sm" | "md"
22
22
  }
23
23
 
24
- export const Tag = ({
24
+ const Tag = ({
25
25
  as,
26
26
  children,
27
27
  className,
@@ -42,4 +42,7 @@ export const Tag = ({
42
42
  return React.createElement(element, { ...componentProps, ref }, children)
43
43
  }
44
44
 
45
+ Tag.slot = { name: "Tag" }
46
+
45
47
  export default Tag
48
+ export { Tag }
@@ -1,9 +1,10 @@
1
+ "use client"
1
2
  import type { InputHTMLAttributes, JSX, Ref } from "react"
2
3
 
3
4
  import clsx from "clsx"
4
5
 
5
- import { ComponentConfig, StandardSizes } from "../../../src/types"
6
- import { useId } from "../../hooks/useId"
6
+ import { StandardSizes } from "../../../src/types"
7
+ import { useField } from "../Field/Field.context"
7
8
 
8
9
  export interface TextInputProps extends Omit<
9
10
  InputHTMLAttributes<HTMLInputElement>,
@@ -49,7 +50,7 @@ export interface TextInputProps extends Omit<
49
50
  | "time"
50
51
  }
51
52
 
52
- export const TextInput = ({
53
+ const TextInput = ({
53
54
  "aria-placeholder": ariaPlaceholder,
54
55
  className,
55
56
  disabled,
@@ -66,7 +67,7 @@ export const TextInput = ({
66
67
  type = "text",
67
68
  ...props
68
69
  }: TextInputProps): JSX.Element => {
69
- const uid = useId(id)
70
+ const field = useField()
70
71
 
71
72
  const componentProps = {
72
73
  "aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
@@ -74,7 +75,7 @@ export const TextInput = ({
74
75
  "data-error": error || undefined,
75
76
  "data-size": size?.length ? size : undefined,
76
77
  disabled,
77
- id: uid,
78
+ id: id ?? field?.id,
78
79
  name,
79
80
  placeholder,
80
81
  type,
@@ -100,8 +101,7 @@ export const TextInput = ({
100
101
  )
101
102
  }
102
103
 
103
- TextInput.config = {
104
- isField: true,
105
- } satisfies ComponentConfig
104
+ TextInput.slot = { name: "TextInput" }
106
105
 
107
106
  export default TextInput
107
+ export { TextInput }
@@ -6,8 +6,8 @@ import clsx from "clsx"
6
6
  import { useState } from "react"
7
7
 
8
8
  import { useDebounce } from "../../hooks/useDebounce"
9
- import { useId } from "../../hooks/useId"
10
- import { ComponentConfig, StandardSizes } from "../../types"
9
+ import { StandardSizes } from "../../types"
10
+ import { useField } from "../Field/Field.context"
11
11
 
12
12
  const DEBOUNCE_DELAY = 750
13
13
 
@@ -47,7 +47,7 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
47
47
  size?: StandardSizes
48
48
  }
49
49
 
50
- export const Textarea = ({
50
+ const Textarea = ({
51
51
  "aria-placeholder": ariaPlaceholder,
52
52
  className,
53
53
  cols = 30,
@@ -65,7 +65,7 @@ export const Textarea = ({
65
65
  size,
66
66
  ...props
67
67
  }: TextareaProps): JSX.Element => {
68
- const uid = useId(id)
68
+ const field = useField()
69
69
 
70
70
  const componentProps = {
71
71
  "aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
@@ -74,7 +74,7 @@ export const Textarea = ({
74
74
  "data-error": error ?? undefined,
75
75
  "data-size": size ?? undefined,
76
76
  disabled,
77
- id: uid,
77
+ id: id ?? field?.id,
78
78
  maxLength: cutoff ? maxLength : undefined,
79
79
  name,
80
80
  placeholder,
@@ -113,8 +113,7 @@ export const Textarea = ({
113
113
  )
114
114
  }
115
115
 
116
- Textarea.config = {
117
- isField: true,
118
- } satisfies ComponentConfig
116
+ Textarea.slot = { name: "Textarea" }
119
117
 
120
118
  export default Textarea
119
+ export { Textarea }
@@ -1,5 +1,5 @@
1
- /* eslint-disable jsx-a11y/anchor-is-valid */
2
1
  "use client"
2
+ /* eslint-disable jsx-a11y/anchor-is-valid */
3
3
 
4
4
  import type { HTMLAttributes, JSX, ReactNode, Ref } from "react"
5
5
 
@@ -70,7 +70,7 @@ const componentSlots = {
70
70
  ValidationSummaryPrompt: null,
71
71
  }
72
72
 
73
- export const ValidationSummary = ({
73
+ const ValidationSummary = ({
74
74
  autoScroll = true,
75
75
  children,
76
76
  className,
@@ -178,12 +178,19 @@ const ValidationSummaryErrors = ({ errors }: ValidationSummaryErrorsProps): JSX.
178
178
  ) : null
179
179
  }
180
180
 
181
- ValidationSummaryHeading.config = { name: "ValidationSummaryHeading" }
182
- ValidationSummaryPrompt.config = { name: "ValidationSummaryPrompt" }
183
- ValidationSummaryErrors.config = { name: "ValidationSummaryErrors" }
181
+ ValidationSummary.slot = { name: "ValidationSummary" }
182
+ ValidationSummaryHeading.slot = { name: "ValidationSummaryHeading" }
183
+ ValidationSummaryPrompt.slot = { name: "ValidationSummaryPrompt" }
184
+ ValidationSummaryErrors.slot = { name: "ValidationSummaryErrors" }
184
185
 
185
186
  ValidationSummary.Heading = ValidationSummaryHeading
186
187
  ValidationSummary.Prompt = ValidationSummaryPrompt
187
188
  ValidationSummary.Errors = ValidationSummaryErrors
188
189
 
189
190
  export default ValidationSummary
191
+ export {
192
+ ValidationSummary,
193
+ ValidationSummaryErrors,
194
+ ValidationSummaryHeading,
195
+ ValidationSummaryPrompt,
196
+ }