@coopdigital/react 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AlertBanner/AlertBanner.d.ts +12 -2
- package/dist/components/AlertBanner/AlertBanner.js +3 -2
- package/dist/components/Author/Author.d.ts +7 -1
- package/dist/components/Author/Author.js +1 -0
- package/dist/components/Button/Button.d.ts +7 -1
- package/dist/components/Button/Button.js +1 -0
- package/dist/components/Card/Card.d.ts +40 -6
- package/dist/components/Card/Card.js +7 -6
- package/dist/components/Checkbox/Checkbox.d.ts +6 -4
- package/dist/components/Checkbox/Checkbox.js +9 -6
- package/dist/components/DatePicker/DatePicker.d.ts +8 -3
- package/dist/components/DatePicker/DatePicker.js +11 -11
- package/dist/components/Expandable/Expandable.d.ts +19 -3
- package/dist/components/Expandable/Expandable.js +4 -3
- package/dist/components/Field/Field.context.d.ts +14 -0
- package/dist/components/Field/Field.context.js +14 -0
- package/dist/components/Field/Field.d.ts +26 -4
- package/dist/components/Field/Field.js +33 -34
- package/dist/components/Field/index.js +1 -0
- package/dist/components/FieldMarkers/Label.js +4 -0
- package/dist/components/Fieldset/Fieldset.d.ts +33 -5
- package/dist/components/Fieldset/Fieldset.js +6 -5
- package/dist/components/Flourish/Flourish.d.ts +7 -1
- package/dist/components/Flourish/Flourish.js +1 -0
- package/dist/components/Form/Form.d.ts +7 -1
- package/dist/components/Form/Form.js +1 -0
- package/dist/components/Image/Image.d.ts +7 -1
- package/dist/components/Image/Image.js +1 -0
- package/dist/components/Pill/Pill.d.ts +12 -2
- package/dist/components/Pill/Pill.js +3 -2
- package/dist/components/Popover/Popover.d.ts +33 -5
- package/dist/components/Popover/Popover.js +6 -5
- package/dist/components/Popover/index.js +1 -0
- package/dist/components/Radio/Radio.d.ts +6 -4
- package/dist/components/Radio/Radio.js +9 -6
- package/dist/components/RootSVG/RootSVG.d.ts +7 -1
- package/dist/components/RootSVG/RootSVG.js +1 -0
- package/dist/components/Searchbox/Searchbox.context.d.ts +13 -0
- package/dist/components/Searchbox/Searchbox.context.js +11 -0
- package/dist/components/Searchbox/Searchbox.d.ts +15 -11
- package/dist/components/Searchbox/Searchbox.js +25 -28
- package/dist/components/Select/Select.d.ts +18 -5
- package/dist/components/Select/Select.js +9 -9
- package/dist/components/Signpost/Signpost.d.ts +7 -1
- package/dist/components/Signpost/Signpost.js +1 -0
- package/dist/components/SkipNav/SkipNav.d.ts +7 -1
- package/dist/components/SkipNav/SkipNav.js +1 -0
- package/dist/components/Squircle/Squircle.d.ts +7 -1
- package/dist/components/Squircle/Squircle.js +1 -0
- package/dist/components/Tag/Tag.d.ts +7 -1
- package/dist/components/Tag/Tag.js +1 -0
- package/dist/components/TextInput/TextInput.d.ts +4 -3
- package/dist/components/TextInput/TextInput.js +6 -6
- package/dist/components/Textarea/Textarea.d.ts +4 -3
- package/dist/components/Textarea/Textarea.js +4 -6
- package/dist/components/ValidationSummary/ValidationSummary.d.ts +26 -4
- package/dist/components/ValidationSummary/ValidationSummary.js +8 -6
- package/dist/hooks/useSlots.d.ts +4 -2
- package/dist/hooks/useSlots.js +33 -7
- package/dist/index.js +10 -10
- package/dist/types/index.d.ts +14 -14
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +9 -7
- package/package.json +4 -3
- package/src/components/AlertBanner/AlertBanner.tsx +5 -2
- package/src/components/Author/Author.tsx +4 -1
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Card/Card.tsx +8 -6
- package/src/components/Checkbox/Checkbox.tsx +13 -9
- package/src/components/DatePicker/DatePicker.tsx +15 -15
- package/src/components/Expandable/Expandable.tsx +5 -8
- package/src/components/Field/Field.context.ts +29 -0
- package/src/components/Field/Field.tsx +61 -56
- package/src/components/FieldMarkers/Label.tsx +4 -0
- package/src/components/Fieldset/Fieldset.tsx +7 -5
- package/src/components/Flourish/Flourish.tsx +4 -1
- package/src/components/Form/Form.tsx +4 -1
- package/src/components/Image/Image.tsx +4 -1
- package/src/components/Pill/Pill.tsx +4 -2
- package/src/components/Popover/Popover.tsx +7 -5
- package/src/components/Radio/Radio.tsx +12 -9
- package/src/components/RootSVG/RootSVG.tsx +4 -1
- package/src/components/Searchbox/Searchbox.context.tsx +20 -0
- package/src/components/Searchbox/Searchbox.tsx +55 -44
- package/src/components/Select/Select.tsx +11 -11
- package/src/components/Signpost/Signpost.tsx +4 -1
- package/src/components/SkipNav/SkipNav.tsx +4 -1
- package/src/components/Squircle/Squircle.tsx +4 -1
- package/src/components/Tag/Tag.tsx +4 -1
- package/src/components/TextInput/TextInput.tsx +8 -8
- package/src/components/Textarea/Textarea.tsx +7 -8
- package/src/components/ValidationSummary/ValidationSummary.tsx +12 -5
- package/src/hooks/useSlots.ts +37 -9
- package/src/types/index.ts +18 -14
- package/src/utils/index.ts +8 -6
- package/dist/node_modules/merge-refs/dist/index.js +0 -36
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import type { FormHTMLAttributes, JSX,
|
|
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?:
|
|
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
|
-
|
|
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 =
|
|
64
|
+
const slots = useSlots(componentSlots, children)
|
|
65
|
+
const uid = useId(id)
|
|
63
66
|
|
|
64
67
|
const [isPending, setIsPending] = useState(false)
|
|
65
|
-
|
|
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:
|
|
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
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
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 {
|
|
13
|
-
import {
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
6
|
-
import {
|
|
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
|
-
|
|
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
|
|
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:
|
|
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.
|
|
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 {
|
|
10
|
-
import {
|
|
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
|
-
|
|
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
|
|
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:
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
+
}
|
package/src/hooks/useSlots.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { LazyComponent, SlotConfig } from "../types"
|
|
4
4
|
|
|
5
5
|
type Slots<T> = Record<keyof T, React.ReactNode>
|
|
6
6
|
|
|
@@ -8,22 +8,50 @@ export function isKey<T extends object>(x: T, k: PropertyKey): k is keyof T {
|
|
|
8
8
|
return k in x
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
export function isLazy<T extends React.ComponentType<any>>(
|
|
13
|
+
type: unknown
|
|
14
|
+
): type is LazyComponent<T> {
|
|
15
|
+
return typeof type === "object" && type !== null && "_payload" in type && "_init" in type
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function resolveComponentName(child: React.ReactNode): string | null {
|
|
19
|
+
if (child && typeof child === "object" && "type" in child) {
|
|
20
|
+
const type = child.type
|
|
21
|
+
|
|
22
|
+
if (isLazy(type)) {
|
|
23
|
+
try {
|
|
24
|
+
const resolved = type._init(type._payload)
|
|
25
|
+
if ("slot" in resolved) return (resolved.slot as SlotConfig).name
|
|
26
|
+
return resolved.displayName ?? resolved.name ?? null
|
|
27
|
+
} catch {
|
|
28
|
+
// _init throws a Promise if the payload is still pending
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof type === "function") {
|
|
34
|
+
if ("slot" in type) return (type.slot as SlotConfig).name
|
|
35
|
+
return (type as React.FC).displayName ?? (type as React.FC).name ?? null
|
|
36
|
+
}
|
|
19
37
|
}
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getSlotName(node: React.ReactNode): string | false {
|
|
42
|
+
const slotName = resolveComponentName(node)
|
|
20
43
|
|
|
44
|
+
if (slotName) {
|
|
45
|
+
return slotName.replaceAll(".", "")
|
|
46
|
+
// return root && !safeName.startsWith(root) ? root + safeName : safeName
|
|
47
|
+
}
|
|
21
48
|
return false
|
|
22
49
|
}
|
|
23
50
|
|
|
24
51
|
export function useSlots<T>(
|
|
25
52
|
componentSlots: Slots<T>,
|
|
26
53
|
children: React.ReactNode,
|
|
54
|
+
|
|
27
55
|
options?: { collect?: string[] }
|
|
28
56
|
): Slots<T> {
|
|
29
57
|
return React.Children.toArray(children).reduce(
|
package/src/types/index.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
export type StandardSizes = "sm" | "md" | "lg"
|
|
2
2
|
|
|
3
|
-
export type FormFieldError = { message?: string; type?: string } | boolean | null | undefined
|
|
3
|
+
// export type FormFieldError = { message?: string; type?: string } | boolean | null | undefined
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
export interface SlotConfig {
|
|
6
|
+
field?: boolean
|
|
7
|
+
inline?: boolean
|
|
8
|
+
name: string
|
|
9
|
+
suffix?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface LazyPayload<T> {
|
|
13
|
+
default: T
|
|
14
|
+
}
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
export interface LazyComponent<T extends React.ComponentType<any>> {
|
|
18
|
+
_init: (payload: unknown) => T
|
|
19
|
+
_payload: Promise<LazyPayload<T>> | LazyPayload<T>
|
|
20
|
+
$$typeof: typeof REACT_LAZY_TYPE
|
|
19
21
|
}
|
|
22
|
+
|
|
23
|
+
export const REACT_LAZY_TYPE = Symbol.for("react.lazy")
|
package/src/utils/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isValidElement } from "react"
|
|
2
|
+
|
|
1
3
|
export const bgPropToClass = (color: string, userClasses?: string) =>
|
|
2
4
|
userClasses?.includes("bg-") ? "" : `bg-${color}`
|
|
3
5
|
|
|
@@ -11,11 +13,11 @@ export const hasUserBorder = (userClasses?: string) => {
|
|
|
11
13
|
|
|
12
14
|
export const bgClassToColor = (userClasses: string) => {
|
|
13
15
|
return /bg-([^\s]+)/.exec(userClasses)?.[1] ?? null
|
|
16
|
+
}
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// )
|
|
18
|
+
export function getSlotProp<R = unknown>(slot: React.ReactNode, prop: string): R | undefined {
|
|
19
|
+
if (isValidElement(slot) && prop in (slot.props as object)) {
|
|
20
|
+
return (slot.props as Record<string, unknown>)[prop] as R
|
|
21
|
+
}
|
|
22
|
+
return undefined
|
|
21
23
|
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A function that merges React refs into one.
|
|
3
|
-
* Supports both functions and ref objects created using createRef() and useRef().
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* ```tsx
|
|
7
|
-
* <div ref={mergeRefs(ref1, ref2, ref3)} />
|
|
8
|
-
* ```
|
|
9
|
-
*
|
|
10
|
-
* @param {(React.Ref<T> | undefined)[]} inputRefs Array of refs
|
|
11
|
-
* @returns {React.Ref<T> | React.RefCallback<T>} Merged refs
|
|
12
|
-
*/
|
|
13
|
-
function mergeRefs() {
|
|
14
|
-
var inputRefs = [];
|
|
15
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
16
|
-
inputRefs[_i] = arguments[_i];
|
|
17
|
-
}
|
|
18
|
-
var filteredInputRefs = inputRefs.filter(Boolean);
|
|
19
|
-
if (filteredInputRefs.length <= 1) {
|
|
20
|
-
var firstRef = filteredInputRefs[0];
|
|
21
|
-
return firstRef || null;
|
|
22
|
-
}
|
|
23
|
-
return function mergedRefs(ref) {
|
|
24
|
-
for (var _i = 0, filteredInputRefs_1 = filteredInputRefs; _i < filteredInputRefs_1.length; _i++) {
|
|
25
|
-
var inputRef = filteredInputRefs_1[_i];
|
|
26
|
-
if (typeof inputRef === 'function') {
|
|
27
|
-
inputRef(ref);
|
|
28
|
-
}
|
|
29
|
-
else if (inputRef) {
|
|
30
|
-
inputRef.current = ref;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { mergeRefs as default };
|