@maestro-js/components 1.0.0-alpha.19 → 1.0.0-alpha.2
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/commands/add.ts +1 -16
- package/dist/components.json +1 -1
- package/dist/index.js +1 -14
- package/package.json +5 -5
- package/registry.json +790 -598
- package/scripts/build.ts +4 -11
- package/src/components/alert-dialog.tsx +3 -3
- package/src/components/avatar.tsx +1 -1
- package/src/components/button-link.tsx +0 -3
- package/src/components/button.tsx +0 -4
- package/src/components/checkbox.tsx +7 -7
- package/src/components/chip.tsx +7 -7
- package/src/components/container.tsx +3 -3
- package/src/components/dialog.tsx +7 -21
- package/src/components/disclosure.tsx +1 -1
- package/src/components/drawer.tsx +5 -19
- package/src/components/form.tsx +5 -27
- package/src/components/helpers/form-field.tsx +8 -7
- package/src/components/helpers/get-button-classes.ts +23 -23
- package/src/components/helpers/headless-button.tsx +1 -1
- package/src/components/inline-alert.tsx +3 -3
- package/src/components/labeled-value.tsx +2 -2
- package/src/components/menu.tsx +26 -60
- package/src/components/month-day-input.tsx +1 -2
- package/src/components/multiselect.tsx +70 -74
- package/src/components/radio.tsx +8 -8
- package/src/components/select.tsx +8 -9
- package/src/components/stepper.tsx +6 -6
- package/src/components/switch.tsx +7 -7
- package/src/components/tabs.tsx +1 -1
- package/src/components/tag-field.tsx +3 -3
- package/src/components/text-area.tsx +1 -1
- package/src/components/text-field.tsx +1 -4
- package/src/components/toast.tsx +6 -6
- package/src/components/toggle-button-group.tsx +2 -2
- package/src/utils/icons.d.ts +1 -2
- package/src/utils/use-tab-indicator.ts +9 -9
- package/src/components/date-range.tsx +0 -138
- package/src/components/optional-link.tsx +0 -15
- package/src/components/table/headless-templated-row-table.ts +0 -550
- package/src/components/table/index.tsx +0 -41
- package/src/components/table/server-table.ts +0 -143
- package/src/components/table/table-actions.tsx +0 -76
- package/src/components/table/table-container.tsx +0 -173
- package/src/components/table/table-container.type-test.ts +0 -155
- package/src/components/table/table-filters/date-range-filter.tsx +0 -227
- package/src/components/table/table-filters/select-filter.tsx +0 -211
- package/src/components/table/table-filters/sort.tsx +0 -85
- package/src/components/table/table-primitives.tsx +0 -226
- package/src/components/table/table-toolbar.tsx +0 -300
- package/src/components/table/table-types.ts +0 -61
- package/src/components/table/use-client-table.ts +0 -157
- package/src/components/table/use-client-table.type-test.ts +0 -217
- package/src/components/table/use-server-table.ts +0 -192
- package/src/components/table/use-server-table.type-test.ts +0 -174
- package/src/utils/use-query-state.ts +0 -626
package/scripts/build.ts
CHANGED
|
@@ -9,7 +9,6 @@ interface RegistryFile {
|
|
|
9
9
|
|
|
10
10
|
interface RegistryEntry {
|
|
11
11
|
name: string
|
|
12
|
-
dependencies?: string[]
|
|
13
12
|
files: RegistryFile[]
|
|
14
13
|
}
|
|
15
14
|
|
|
@@ -20,7 +19,6 @@ interface OutputFile {
|
|
|
20
19
|
|
|
21
20
|
interface OutputEntry {
|
|
22
21
|
name: string
|
|
23
|
-
dependencies?: string[]
|
|
24
22
|
files: OutputFile[]
|
|
25
23
|
}
|
|
26
24
|
|
|
@@ -31,19 +29,14 @@ const registry: RegistryEntry[] = JSON.parse(await readFile(resolve(packageRoot,
|
|
|
31
29
|
const output: OutputEntry[] = await Promise.all(
|
|
32
30
|
registry.map(async (entry) => {
|
|
33
31
|
const files = await Promise.all(
|
|
34
|
-
entry.files.map(async (file) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
name: `${file.type}/${basename(file.path)}`,
|
|
39
|
-
content: header + content
|
|
40
|
-
}
|
|
41
|
-
})
|
|
32
|
+
entry.files.map(async (file) => ({
|
|
33
|
+
name: `${file.type}/${basename(file.path)}`,
|
|
34
|
+
content: await readFile(resolve(packageRoot, file.path), 'utf-8')
|
|
35
|
+
}))
|
|
42
36
|
)
|
|
43
37
|
|
|
44
38
|
return {
|
|
45
39
|
name: entry.name,
|
|
46
|
-
...(entry.dependencies?.length && { dependencies: entry.dependencies }),
|
|
47
40
|
files
|
|
48
41
|
}
|
|
49
42
|
})
|
|
@@ -86,7 +86,7 @@ function AlertDialog_({
|
|
|
86
86
|
isDismissable={isDismissable}
|
|
87
87
|
isKeyboardDismissDisabled={!isDismissable}
|
|
88
88
|
className={tw(
|
|
89
|
-
'fixed inset-0 z-[4000] flex items-center justify-center
|
|
89
|
+
'fixed inset-0 z-[4000] flex items-center justify-center bg-black/70 backdrop-blur-lg',
|
|
90
90
|
'transition-opacity duration-200 ease-out',
|
|
91
91
|
'data-[entering]:opacity-0',
|
|
92
92
|
'data-[exiting]:opacity-0'
|
|
@@ -100,14 +100,14 @@ function AlertDialog_({
|
|
|
100
100
|
'data-[exiting]:scale-95 data-[exiting]:opacity-0 data-[exiting]:translate-y-2'
|
|
101
101
|
)}
|
|
102
102
|
>
|
|
103
|
-
<Dialog className={tw('outline-none bg-white rounded-
|
|
103
|
+
<Dialog className={tw('outline-none bg-white rounded-lg shadow-2xl w-full', className)} role="alertdialog">
|
|
104
104
|
{({ close }) => (
|
|
105
105
|
<AlertDialogContext.Provider value={{ close }}>
|
|
106
106
|
<ButtonGroupContext.Provider
|
|
107
107
|
value={{ orientation: 'horizontal', alignment: 'center', fullWidth: true, className: 'flex-nowrap' }}
|
|
108
108
|
>
|
|
109
109
|
<ButtonContext.Provider value={{ shape: 'rectangle', variant: 'soft', fullWidth: true }}>
|
|
110
|
-
<div className={tw('border rounded-
|
|
110
|
+
<div className={tw('border rounded-lg p-6', styles.container)}>
|
|
111
111
|
<div className="flex flex-col items-center text-center">
|
|
112
112
|
{displayIcon && (
|
|
113
113
|
<div className={tw('w-12 h-12 rounded-xl flex items-center justify-center mb-4', styles.iconBg)}>
|
|
@@ -22,7 +22,7 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|
|
22
22
|
<div
|
|
23
23
|
ref={ref}
|
|
24
24
|
className={tw(
|
|
25
|
-
'size-10 relative inline-flex items-center justify-center overflow-hidden font-medium text-white select-none
|
|
25
|
+
'size-10 relative inline-flex items-center justify-center overflow-hidden font-medium text-white select-none',
|
|
26
26
|
!showImage && 'bg-neutral-300',
|
|
27
27
|
shape === 'circle' && 'rounded-full',
|
|
28
28
|
shape === 'rounded' && 'rounded',
|
|
@@ -56,9 +56,6 @@ export const ButtonLink = React.forwardRef<HTMLAnchorElement, ButtonLinkProps>(
|
|
|
56
56
|
className: tw(fullWidth && 'w-full', className)
|
|
57
57
|
})}
|
|
58
58
|
>
|
|
59
|
-
{(size === 'xs' || size === 'sm' || shape === 'circle') && (
|
|
60
|
-
<span className="absolute left-1/2 top-1/2 size-12 -translate-x-1/2 -translate-y-1/2" aria-hidden="true" />
|
|
61
|
-
)}
|
|
62
59
|
<span className={tw('inline-flex items-center gap-2', showSpinner && 'opacity-0')}>{children}</span>
|
|
63
60
|
<span
|
|
64
61
|
aria-hidden={!showSpinner ? true : undefined}
|
|
@@ -74,7 +74,6 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
74
74
|
ref={ref}
|
|
75
75
|
data-pending={isPending}
|
|
76
76
|
onClick={onClick}
|
|
77
|
-
{...(isToggled != null ? { 'aria-pressed': isToggled } : {})}
|
|
78
77
|
className={composeTailwindRenderProps(
|
|
79
78
|
props.className,
|
|
80
79
|
tw(getButtonClasses({ variant, color, size, shape, isToggled }), fullWidth && 'w-full')
|
|
@@ -82,9 +81,6 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
82
81
|
>
|
|
83
82
|
{composeRenderProps(props.children, (children) => (
|
|
84
83
|
<>
|
|
85
|
-
{(size === 'xs' || size === 'sm' || shape === 'circle') && (
|
|
86
|
-
<span className="absolute left-1/2 top-1/2 size-12 -translate-x-1/2 -translate-y-1/2" aria-hidden="true" />
|
|
87
|
-
)}
|
|
88
84
|
<span className={tw('inline-flex items-center gap-2', showSpinner && 'opacity-0')}>{children}</span>
|
|
89
85
|
<span
|
|
90
86
|
aria-hidden={!showSpinner ? true : undefined}
|
|
@@ -78,7 +78,7 @@ export function PlainCheckbox(props: PlainCheckboxProps) {
|
|
|
78
78
|
isDisabled={props.isDisabled}
|
|
79
79
|
isInvalid={props.isInvalid || validationInvalid}
|
|
80
80
|
aria-label={props['aria-label']}
|
|
81
|
-
className="group inline-flex items-center focus:outline-none focus-visible:
|
|
81
|
+
className="group inline-flex items-center focus:outline-none [&>div]:focus-visible:ring-2 [&>div]:focus-visible:ring-primary-500/20 [&>div]:focus-visible:ring-offset-2"
|
|
82
82
|
>
|
|
83
83
|
{({ isSelected, isIndeterminate, isDisabled }) => (
|
|
84
84
|
<>
|
|
@@ -139,7 +139,7 @@ export function LabeledCheckbox(props: LabeledCheckboxProps) {
|
|
|
139
139
|
isDisabled={props.isDisabled}
|
|
140
140
|
isInvalid={isInvalid}
|
|
141
141
|
aria-describedby={helpTextId}
|
|
142
|
-
className="group relative flex items-start gap-3 select-none focus:outline-none focus-visible:
|
|
142
|
+
className="group relative flex items-start gap-3 select-none focus:outline-none [&>div:first-child>div]:focus-visible:ring-2 [&>div:first-child>div]:focus-visible:ring-primary-500/20 [&>div:first-child>div]:focus-visible:ring-offset-2"
|
|
143
143
|
>
|
|
144
144
|
{({ isSelected, isIndeterminate, isDisabled }) => (
|
|
145
145
|
<>
|
|
@@ -191,16 +191,16 @@ function CheckboxBox({
|
|
|
191
191
|
return (
|
|
192
192
|
<div
|
|
193
193
|
className={tw(
|
|
194
|
-
'relative
|
|
195
|
-
isSelected || isIndeterminate ? 'bg-primary-
|
|
194
|
+
'relative h-5 w-5 rounded border transition-all duration-50',
|
|
195
|
+
isSelected || isIndeterminate ? 'bg-primary-500 border-primary-500' : 'bg-white border-neutral-300',
|
|
196
196
|
!isDisabled && !(isSelected || isIndeterminate) && 'group-hovered:border-neutral-400',
|
|
197
|
-
isDisabled && 'cursor-not-allowed
|
|
197
|
+
isDisabled && 'opacity-50 cursor-not-allowed'
|
|
198
198
|
)}
|
|
199
199
|
>
|
|
200
200
|
{isIndeterminate ? (
|
|
201
|
-
<Icon name="minus" className="h-5/6 absolute inset-0 m-auto aspect-square
|
|
201
|
+
<Icon name="minus" className="h-5/6 absolute inset-0 m-auto aspect-square text-white" />
|
|
202
202
|
) : (
|
|
203
|
-
<Icon name="check" className="h-5/6 absolute inset-0 m-auto aspect-square
|
|
203
|
+
<Icon name="check" className="h-5/6 absolute inset-0 m-auto aspect-square text-white" />
|
|
204
204
|
)}
|
|
205
205
|
</div>
|
|
206
206
|
)
|
package/src/components/chip.tsx
CHANGED
|
@@ -60,7 +60,7 @@ export function Chip(props: ChipProps) {
|
|
|
60
60
|
className={tw(
|
|
61
61
|
'inline-flex items-center justify-center rounded-full transition-colors translate-x-1',
|
|
62
62
|
removeBtnSizeClasses[size],
|
|
63
|
-
!isDisabled && 'hover:bg-
|
|
63
|
+
!isDisabled && 'hover:bg-black/10',
|
|
64
64
|
isDisabled && 'cursor-not-allowed'
|
|
65
65
|
)}
|
|
66
66
|
aria-label="Remove"
|
|
@@ -146,13 +146,13 @@ const darkHoverColorClasses = {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
const removeBtnSizeClasses = {
|
|
149
|
-
sm: '
|
|
150
|
-
md: '
|
|
151
|
-
lg: '
|
|
149
|
+
sm: 'h-4 w-4 -m-0.5 p-0.5',
|
|
150
|
+
md: 'h-5 w-5 -m-1 p-1',
|
|
151
|
+
lg: 'h-6 w-6 -m-1.5 p-1.5'
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
const removeIconSizeClasses = {
|
|
155
|
-
sm: '
|
|
156
|
-
md: '
|
|
157
|
-
lg: '
|
|
155
|
+
sm: 'h-2 w-2',
|
|
156
|
+
md: 'h-3 w-3',
|
|
157
|
+
lg: 'h-4 w-4'
|
|
158
158
|
}
|
|
@@ -71,9 +71,9 @@ const sizeClasses: Record<ContainerSize, string> = {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const elevationClasses: Record<string, string> = {
|
|
74
|
-
'0': 'bg-white
|
|
75
|
-
'-1': 'bg-neutral-50
|
|
76
|
-
'-2': 'bg-neutral-100
|
|
74
|
+
'0': 'bg-white border border-neutral-200',
|
|
75
|
+
'-1': 'bg-neutral-50 border border-neutral-200',
|
|
76
|
+
'-2': 'bg-neutral-100 border border-neutral-300',
|
|
77
77
|
inherit: ''
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import type { To, RelativeRoutingType } from 'react-router'
|
|
3
|
-
import { useNavigate } from 'react-router'
|
|
4
2
|
import { Modal, ModalOverlay, Dialog as AriaDialog, Heading } from 'react-aria-components'
|
|
5
3
|
import { tw } from '../utils/tw'
|
|
6
4
|
import { Button } from './button'
|
|
@@ -9,10 +7,8 @@ export type DialogProps = {
|
|
|
9
7
|
children?: React.ReactNode
|
|
10
8
|
title?: React.ReactNode
|
|
11
9
|
isOpen?: boolean
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
| { to: To; replace?: boolean; relative?: RelativeRoutingType; reloadDocument?: boolean }
|
|
15
|
-
size?: 'xs' | 'sm' | 'lg'
|
|
10
|
+
onOpenChange?: (isOpen: boolean) => void
|
|
11
|
+
size?: 'sm' | 'lg'
|
|
16
12
|
className?: string
|
|
17
13
|
isDismissable?: boolean
|
|
18
14
|
actions?: React.ReactNode
|
|
@@ -28,22 +24,12 @@ function Dialog_({
|
|
|
28
24
|
children,
|
|
29
25
|
title,
|
|
30
26
|
isOpen = false,
|
|
31
|
-
|
|
27
|
+
onOpenChange,
|
|
32
28
|
size = 'sm',
|
|
33
29
|
className,
|
|
34
30
|
isDismissable = false,
|
|
35
31
|
actions
|
|
36
32
|
}: DialogProps) {
|
|
37
|
-
const navigate = useNavigate()
|
|
38
|
-
|
|
39
|
-
const onOpenChange = close
|
|
40
|
-
? typeof close === 'function'
|
|
41
|
-
? close
|
|
42
|
-
: (open: boolean) => {
|
|
43
|
-
if (!open) navigate(close.to, { replace: close.replace, relative: close.relative })
|
|
44
|
-
}
|
|
45
|
-
: undefined
|
|
46
|
-
|
|
47
33
|
return (
|
|
48
34
|
<ModalOverlay
|
|
49
35
|
isOpen={isOpen}
|
|
@@ -51,7 +37,7 @@ function Dialog_({
|
|
|
51
37
|
isDismissable={isDismissable}
|
|
52
38
|
isKeyboardDismissDisabled={!isDismissable}
|
|
53
39
|
className={tw(
|
|
54
|
-
'fixed inset-0 z-[2000] flex items-center justify-center bg-black/
|
|
40
|
+
'fixed inset-0 z-[2000] flex items-center justify-center bg-black/70 backdrop-blur-lg',
|
|
55
41
|
'transition-opacity duration-300 ease-in-out',
|
|
56
42
|
'data-[entering]:opacity-0',
|
|
57
43
|
'data-[exiting]:opacity-0'
|
|
@@ -60,7 +46,7 @@ function Dialog_({
|
|
|
60
46
|
<Modal
|
|
61
47
|
className={tw(
|
|
62
48
|
'w-[calc(100%-4rem)] m-auto',
|
|
63
|
-
size === 'lg' ? 'max-w-[1080px]' :
|
|
49
|
+
size === 'lg' ? 'max-w-[1080px]' : 'max-w-[640px]',
|
|
64
50
|
'transition-all duration-300 ease-in-out',
|
|
65
51
|
'data-[entering]:scale-95 data-[entering]:opacity-0',
|
|
66
52
|
'data-[exiting]:scale-95 data-[exiting]:opacity-0'
|
|
@@ -68,7 +54,7 @@ function Dialog_({
|
|
|
68
54
|
>
|
|
69
55
|
<AriaDialog
|
|
70
56
|
className={tw(
|
|
71
|
-
'w-full max-h-[calc(100vh-6rem)] bg-white shadow-xl
|
|
57
|
+
'w-full max-h-[calc(100vh-6rem)] bg-white shadow-xl outline-none rounded-lg',
|
|
72
58
|
'flex flex-col overflow-x-hidden overflow-y-auto',
|
|
73
59
|
className
|
|
74
60
|
)}
|
|
@@ -77,7 +63,7 @@ function Dialog_({
|
|
|
77
63
|
<DialogContext.Provider value={{ close }}>
|
|
78
64
|
<div className="flex items-start justify-between gap-4 pt-6 px-6">
|
|
79
65
|
{title ? (
|
|
80
|
-
<Heading slot="title" className="flex-1 text-
|
|
66
|
+
<Heading slot="title" className="flex-1 text-xl font-semibold text-neutral-900">
|
|
81
67
|
{title}
|
|
82
68
|
</Heading>
|
|
83
69
|
) : (
|
|
@@ -85,7 +85,7 @@ function DisclosureHeader({
|
|
|
85
85
|
name="chevron-right"
|
|
86
86
|
className={tw(
|
|
87
87
|
'shrink-0 transition-transform duration-200 ease-in-out',
|
|
88
|
-
size === 'md' || size === 'lg' ? '
|
|
88
|
+
size === 'md' || size === 'lg' ? 'w-4 h-4' : 'w-3 h-3',
|
|
89
89
|
isExpanded && 'rotate-90',
|
|
90
90
|
isDisabled ? 'text-neutral-300' : 'text-neutral-500'
|
|
91
91
|
)}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import type { To, RelativeRoutingType } from 'react-router'
|
|
3
|
-
import { useNavigate } from 'react-router'
|
|
4
2
|
import { Drawer as VaulDrawer } from 'vaul'
|
|
5
3
|
import { tw } from '../utils/tw'
|
|
6
4
|
|
|
@@ -8,9 +6,7 @@ export type DrawerProps = {
|
|
|
8
6
|
children?: React.ReactNode
|
|
9
7
|
title?: React.ReactNode
|
|
10
8
|
isOpen?: boolean
|
|
11
|
-
|
|
12
|
-
| ((isOpen: boolean) => void)
|
|
13
|
-
| { to: To; replace?: boolean; relative?: RelativeRoutingType; reloadDocument?: boolean }
|
|
9
|
+
onOpenChange?: (isOpen: boolean) => void
|
|
14
10
|
size?: 'sm' | 'md' | 'lg'
|
|
15
11
|
className?: string
|
|
16
12
|
isDismissable?: boolean
|
|
@@ -23,7 +19,7 @@ export function Drawer({
|
|
|
23
19
|
children,
|
|
24
20
|
title,
|
|
25
21
|
isOpen = false,
|
|
26
|
-
|
|
22
|
+
onOpenChange,
|
|
27
23
|
size = 'md',
|
|
28
24
|
className,
|
|
29
25
|
isDismissable = true,
|
|
@@ -31,20 +27,10 @@ export function Drawer({
|
|
|
31
27
|
actions,
|
|
32
28
|
contentsContainerClassName
|
|
33
29
|
}: DrawerProps) {
|
|
34
|
-
const navigate = useNavigate()
|
|
35
|
-
|
|
36
|
-
const onOpenChange = close
|
|
37
|
-
? typeof close === 'function'
|
|
38
|
-
? close
|
|
39
|
-
: (open: boolean) => {
|
|
40
|
-
if (!open) navigate(close.to, { replace: close.replace, relative: close.relative })
|
|
41
|
-
}
|
|
42
|
-
: undefined
|
|
43
|
-
|
|
44
30
|
return (
|
|
45
31
|
<VaulDrawer.Root open={isOpen} onOpenChange={onOpenChange} direction={position} dismissible={isDismissable}>
|
|
46
32
|
<VaulDrawer.Portal>
|
|
47
|
-
<VaulDrawer.Overlay className="fixed inset-0 z-49 bg-black/
|
|
33
|
+
<VaulDrawer.Overlay className="fixed inset-0 z-49 bg-black/70 backdrop-blur-lg" />
|
|
48
34
|
<VaulDrawer.Content
|
|
49
35
|
className={tw(
|
|
50
36
|
'flex h-auto flex-col text-sm group/drawer-content fixed z-50',
|
|
@@ -64,7 +50,7 @@ export function Drawer({
|
|
|
64
50
|
{isDismissable ? (
|
|
65
51
|
<div
|
|
66
52
|
className={tw(
|
|
67
|
-
'absolute bg-neutral-
|
|
53
|
+
'absolute bg-neutral-200 rounded-full shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block',
|
|
68
54
|
'group-data-[vaul-drawer-direction=left]/drawer-content:h-25 group-data-[vaul-drawer-direction=left]/drawer-content:w-1 group-data-[vaul-drawer-direction=left]/drawer-content:right-2 group-data-[vaul-drawer-direction=left]/drawer-content:top-[calc(50%-50px)]',
|
|
69
55
|
'group-data-[vaul-drawer-direction=right]/drawer-content:h-25 group-data-[vaul-drawer-direction=right]/drawer-content:w-1 group-data-[vaul-drawer-direction=right]/drawer-content:left-2 group-data-[vaul-drawer-direction=right]/drawer-content:top-[calc(50%-50px)]',
|
|
70
56
|
'group-data-[vaul-drawer-direction=top]/drawer-content:w-25 group-data-[vaul-drawer-direction=top]/drawer-content:h-1 group-data-[vaul-drawer-direction=top]/drawer-content:bottom-2 group-data-[vaul-drawer-direction=top]/drawer-content:left-[calc(50%-50px)]',
|
|
@@ -73,7 +59,7 @@ export function Drawer({
|
|
|
73
59
|
/>
|
|
74
60
|
) : null}
|
|
75
61
|
|
|
76
|
-
<div className="bg-white size-full pt-6 px-6 pb-6 rounded-
|
|
62
|
+
<div className="bg-white size-full pt-6 px-6 pb-6 rounded-md shadow-xl">
|
|
77
63
|
<div className="flex items-start justify-between gap-4 pb-5">
|
|
78
64
|
{title ? (
|
|
79
65
|
<VaulDrawer.Title className="flex-1 text-xl font-semibold text-neutral-900">{title}</VaulDrawer.Title>
|
package/src/components/form.tsx
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import { forwardRef } from 'react'
|
|
2
1
|
import {
|
|
3
2
|
type FormProps as ReactRouterFormProps,
|
|
4
3
|
Form as ReactRouterForm,
|
|
5
4
|
data,
|
|
6
5
|
type ClientActionFunctionArgs
|
|
7
6
|
} from 'react-router'
|
|
8
|
-
import { HeadlessForm
|
|
7
|
+
import { HeadlessForm } from '@maestro-js/form'
|
|
9
8
|
import { serverOnly$ } from 'vite-env-only/macros'
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
function _Form({ children, ...props }: ReactRouterFormProps) {
|
|
12
11
|
return (
|
|
13
|
-
<HeadlessForm as={ReactRouterForm}
|
|
12
|
+
<HeadlessForm as={ReactRouterForm} {...props}>
|
|
14
13
|
{children}
|
|
15
14
|
</HeadlessForm>
|
|
16
15
|
)
|
|
17
|
-
}
|
|
16
|
+
}
|
|
18
17
|
|
|
19
18
|
export const Form = Object.assign(_Form, {
|
|
20
19
|
HiddenInput: HeadlessForm.HiddenInput,
|
|
@@ -24,28 +23,7 @@ export const Form = Object.assign(_Form, {
|
|
|
24
23
|
useTopLevelFormValidation: HeadlessForm.useTopLevelFormValidation,
|
|
25
24
|
useReset: HeadlessForm.useReset,
|
|
26
25
|
clientSafeParse: HeadlessForm.parseFormDataClientSide,
|
|
27
|
-
serverSafeParse
|
|
28
|
-
schema: StandardSchema<T, T>,
|
|
29
|
-
formData: FormData | Promise<FormData>,
|
|
30
|
-
options?: {
|
|
31
|
-
handleFile: ParseFormDataOptions<T>['handleFile']
|
|
32
|
-
}
|
|
33
|
-
): Promise<ParseFormDataResult<T>> {
|
|
34
|
-
return HeadlessForm.parseFormData(schema, formData, {
|
|
35
|
-
...options,
|
|
36
|
-
jsonSchemaLibraryOptions: {
|
|
37
|
-
unrepresentable: 'any',
|
|
38
|
-
override: (ctx) => {
|
|
39
|
-
const meta = ctx.zodSchema.meta()
|
|
40
|
-
const custom = meta?.jsonSchema
|
|
41
|
-
|
|
42
|
-
if (custom && typeof custom === 'object') {
|
|
43
|
-
Object.assign(ctx.jsonSchema, custom)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
},
|
|
26
|
+
serverSafeParse: HeadlessForm.parseFormData,
|
|
49
27
|
validationError: serverOnly$(validationError) as typeof validationError,
|
|
50
28
|
customValidationError: serverOnly$(customValidationError) as typeof customValidationError,
|
|
51
29
|
composeValidators: HeadlessForm.composeValidators,
|
|
@@ -85,16 +85,17 @@ const FieldGroup = React.forwardRef<HTMLDivElement, FieldGroupProps>(
|
|
|
85
85
|
<Group
|
|
86
86
|
ref={ref}
|
|
87
87
|
className={tw(
|
|
88
|
-
'relative overflow-hidden
|
|
89
|
-
'focus-within:
|
|
88
|
+
'relative overflow-hidden border transition-all duration-200 max-w-96',
|
|
89
|
+
'focus-within:ring-1',
|
|
90
90
|
shape,
|
|
91
|
-
disabled && '
|
|
92
|
-
opts.isInvalid && '
|
|
93
|
-
opts.hasWarning &&
|
|
91
|
+
disabled && 'border-neutral-100 bg-neutral-50 text-neutral-400 cursor-not-allowed',
|
|
92
|
+
opts.isInvalid && 'border-negative-200 bg-negative-50 focus-within:border-negative-500 focus-within:ring-negative-500/20',
|
|
93
|
+
opts.hasWarning &&
|
|
94
|
+
'border-notice-200 bg-notice-50 focus-within:border-notice-500 focus-within:ring-notice-500/20',
|
|
94
95
|
!opts.isInvalid &&
|
|
95
96
|
!opts.hasWarning &&
|
|
96
97
|
!disabled &&
|
|
97
|
-
'
|
|
98
|
+
'border-neutral-200 hover:border-neutral-300 focus-within:border-primary-500 focus-within:ring-primary-500/20',
|
|
98
99
|
className
|
|
99
100
|
)}
|
|
100
101
|
onClick={onClick}
|
|
@@ -113,7 +114,7 @@ const FieldInput = React.forwardRef<HTMLInputElement, InputProps>((props, ref) =
|
|
|
113
114
|
className={composeTailwindRenderProps(
|
|
114
115
|
props.className,
|
|
115
116
|
tw(
|
|
116
|
-
'flex-1 bg-transparent px-3 py-2 border-0 focus:ring-0 focus:outline-none text-sm
|
|
117
|
+
'flex-1 bg-transparent px-3 py-2 border-0 focus:ring-0 focus:outline-none text-sm text-neutral-900 placeholder:text-neutral-400',
|
|
117
118
|
(props.disabled || props.readOnly) && 'cursor-not-allowed'
|
|
118
119
|
)
|
|
119
120
|
)}
|
|
@@ -6,19 +6,19 @@ export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
|
6
6
|
export type ButtonShape = 'rectangle' | 'circle' | 'oval'
|
|
7
7
|
|
|
8
8
|
const base =
|
|
9
|
-
'relative inline-flex items-center justify-center gap-2 font-medium whitespace-nowrap transition-
|
|
9
|
+
'relative inline-flex items-center justify-center gap-2 font-medium whitespace-nowrap transition-all cursor-default select-none [&_svg]:pointer-events-none [&_svg:not([class*=size-])]:size-4 [&_svg]:shrink-0 data-[disabled]:cursor-not-allowed'
|
|
10
10
|
|
|
11
11
|
const sizeClasses: Record<ButtonSize, string> = {
|
|
12
|
-
xs: 'h-7 min-w-14 px-2 text-xs',
|
|
13
|
-
sm: 'h-8 min-w-16 px-
|
|
14
|
-
md: 'h-9 min-w-20 px-
|
|
15
|
-
lg: 'h-10 min-w-24 px-
|
|
16
|
-
xl: 'h-12 min-w-28 px-
|
|
12
|
+
xs: 'h-7 min-w-14 px-2.5 text-xs',
|
|
13
|
+
sm: 'h-8 min-w-16 px-3 text-sm',
|
|
14
|
+
md: 'h-9 min-w-20 px-4 text-sm',
|
|
15
|
+
lg: 'h-10 min-w-24 px-5 text-base',
|
|
16
|
+
xl: 'h-12 min-w-28 px-6 text-base'
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const shapeClasses: Record<ButtonShape, string> = {
|
|
20
20
|
rectangle: 'rounded',
|
|
21
|
-
circle: 'rounded-full aspect-square px-0
|
|
21
|
+
circle: 'rounded-full aspect-square px-0',
|
|
22
22
|
oval: 'rounded-full'
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -37,39 +37,39 @@ const variantColorClasses: Record<ButtonVariant, Record<ButtonColor, string>> =
|
|
|
37
37
|
},
|
|
38
38
|
outlined: {
|
|
39
39
|
primary:
|
|
40
|
-
'bg-white ring-1 ring-inset ring-primary-300 text-primary-700 data-[hovered]:bg-primary-50 data-[hovered]:ring-primary-400 data-[pressed]:bg-primary-100 data-[pressed]:ring-primary-500 data-[disabled]:bg-neutral-
|
|
40
|
+
'bg-white ring-1 ring-inset ring-primary-300 text-primary-700 data-[hovered]:bg-primary-50 data-[hovered]:ring-primary-400 data-[pressed]:bg-primary-100 data-[pressed]:ring-primary-500 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400 data-[disabled]:ring-neutral-200 data-[disabled]:shadow-none',
|
|
41
41
|
negative:
|
|
42
|
-
'bg-white ring-1 ring-inset ring-negative-300 text-negative-700 data-[hovered]:bg-negative-50 data-[hovered]:ring-negative-400 data-[pressed]:bg-negative-100 data-[pressed]:ring-negative-500 data-[disabled]:bg-neutral-
|
|
42
|
+
'bg-white ring-1 ring-inset ring-negative-300 text-negative-700 data-[hovered]:bg-negative-50 data-[hovered]:ring-negative-400 data-[pressed]:bg-negative-100 data-[pressed]:ring-negative-500 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400 data-[disabled]:ring-neutral-200 data-[disabled]:shadow-none',
|
|
43
43
|
positive:
|
|
44
|
-
'bg-white ring-1 ring-inset ring-positive-300 text-positive-700 data-[hovered]:bg-positive-50 data-[hovered]:ring-positive-400 data-[pressed]:bg-positive-100 data-[pressed]:ring-positive-500 data-[disabled]:bg-neutral-
|
|
44
|
+
'bg-white ring-1 ring-inset ring-positive-300 text-positive-700 data-[hovered]:bg-positive-50 data-[hovered]:ring-positive-400 data-[pressed]:bg-positive-100 data-[pressed]:ring-positive-500 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400 data-[disabled]:ring-neutral-200 data-[disabled]:shadow-none',
|
|
45
45
|
notice:
|
|
46
|
-
'bg-white ring-1 ring-inset ring-notice-300 text-notice-700 data-[hovered]:bg-notice-50 data-[hovered]:ring-notice-400 data-[pressed]:bg-notice-100 data-[pressed]:ring-notice-500 data-[disabled]:bg-neutral-
|
|
46
|
+
'bg-white ring-1 ring-inset ring-notice-300 text-notice-700 data-[hovered]:bg-notice-50 data-[hovered]:ring-notice-400 data-[pressed]:bg-notice-100 data-[pressed]:ring-notice-500 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400 data-[disabled]:ring-neutral-200 data-[disabled]:shadow-none',
|
|
47
47
|
neutral:
|
|
48
|
-
'bg-white ring-1 ring-inset ring-neutral-300 text-neutral-700 data-[hovered]:bg-neutral-50 data-[hovered]:ring-neutral-400 data-[pressed]:bg-neutral-100 data-[pressed]:ring-neutral-500 data-[disabled]:bg-neutral-
|
|
48
|
+
'bg-white ring-1 ring-inset ring-neutral-300 text-neutral-700 data-[hovered]:bg-neutral-50 data-[hovered]:ring-neutral-400 data-[pressed]:bg-neutral-100 data-[pressed]:ring-neutral-500 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400 data-[disabled]:ring-neutral-200 data-[disabled]:shadow-none'
|
|
49
49
|
},
|
|
50
50
|
soft: {
|
|
51
51
|
primary:
|
|
52
|
-
'bg-primary-100 text-primary-800 data-[hovered]:bg-primary-200 data-[pressed]:bg-primary-300 data-[disabled]:bg-neutral-
|
|
52
|
+
'bg-primary-100 text-primary-800 data-[hovered]:bg-primary-200 data-[pressed]:bg-primary-300 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400',
|
|
53
53
|
negative:
|
|
54
|
-
'bg-negative-100 text-negative-800 data-[hovered]:bg-negative-200 data-[pressed]:bg-negative-300 data-[disabled]:bg-neutral-
|
|
54
|
+
'bg-negative-100 text-negative-800 data-[hovered]:bg-negative-200 data-[pressed]:bg-negative-300 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400',
|
|
55
55
|
positive:
|
|
56
|
-
'bg-positive-100 text-positive-800 data-[hovered]:bg-positive-200 data-[pressed]:bg-positive-300 data-[disabled]:bg-neutral-
|
|
56
|
+
'bg-positive-100 text-positive-800 data-[hovered]:bg-positive-200 data-[pressed]:bg-positive-300 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400',
|
|
57
57
|
notice:
|
|
58
|
-
'bg-notice-100 text-notice-800 data-[hovered]:bg-notice-200 data-[pressed]:bg-notice-300 data-[disabled]:bg-neutral-
|
|
58
|
+
'bg-notice-100 text-notice-800 data-[hovered]:bg-notice-200 data-[pressed]:bg-notice-300 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400',
|
|
59
59
|
neutral:
|
|
60
|
-
'bg-neutral-200 text-neutral-800 data-[hovered]:bg-neutral-300 data-[pressed]:bg-neutral-400 data-[disabled]:bg-neutral-
|
|
60
|
+
'bg-neutral-200 text-neutral-800 data-[hovered]:bg-neutral-300 data-[pressed]:bg-neutral-400 data-[disabled]:bg-neutral-50 data-[disabled]:text-neutral-400'
|
|
61
61
|
},
|
|
62
62
|
plain: {
|
|
63
63
|
primary:
|
|
64
|
-
'bg-transparent text-primary-700 data-[hovered]:bg-primary-50 data-[pressed]:bg-primary-100 data-[disabled]:bg-
|
|
64
|
+
'bg-transparent text-primary-700 data-[hovered]:bg-primary-50 data-[pressed]:bg-primary-100 data-[disabled]:bg-transparent data-[disabled]:text-neutral-400',
|
|
65
65
|
negative:
|
|
66
|
-
'bg-transparent text-negative-700 data-[hovered]:bg-negative-50 data-[pressed]:bg-negative-100 data-[disabled]:bg-
|
|
66
|
+
'bg-transparent text-negative-700 data-[hovered]:bg-negative-50 data-[pressed]:bg-negative-100 data-[disabled]:bg-transparent data-[disabled]:text-neutral-400',
|
|
67
67
|
positive:
|
|
68
|
-
'bg-transparent text-positive-700 data-[hovered]:bg-positive-50 data-[pressed]:bg-positive-100 data-[disabled]:bg-
|
|
68
|
+
'bg-transparent text-positive-700 data-[hovered]:bg-positive-50 data-[pressed]:bg-positive-100 data-[disabled]:bg-transparent data-[disabled]:text-neutral-400',
|
|
69
69
|
notice:
|
|
70
|
-
'bg-transparent text-notice-700 data-[hovered]:bg-notice-50 data-[pressed]:bg-notice-100 data-[disabled]:bg-
|
|
70
|
+
'bg-transparent text-notice-700 data-[hovered]:bg-notice-50 data-[pressed]:bg-notice-100 data-[disabled]:bg-transparent data-[disabled]:text-neutral-400',
|
|
71
71
|
neutral:
|
|
72
|
-
'bg-transparent text-neutral-700 data-[hovered]:bg-neutral-50 data-[pressed]:bg-neutral-100 data-[disabled]:bg-
|
|
72
|
+
'bg-transparent text-neutral-700 data-[hovered]:bg-neutral-50 data-[pressed]:bg-neutral-100 data-[disabled]:bg-transparent data-[disabled]:text-neutral-400'
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -105,7 +105,7 @@ const toggledVariantColorClasses: Record<ButtonVariant, Record<ButtonColor, stri
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
const focusClasses =
|
|
108
|
-
'
|
|
108
|
+
'data-[focus-visible]:outline-2 data-[focus-visible]:outline-offset-2 data-[focus-visible]:outline-primary-600'
|
|
109
109
|
|
|
110
110
|
export function getButtonClasses({
|
|
111
111
|
variant = 'contained',
|
|
@@ -27,7 +27,7 @@ export const HeadlessButton = React.forwardRef<
|
|
|
27
27
|
{...props}
|
|
28
28
|
{...(props.disabled || props['data-disabled'] ? { ['data-disabled']: true } : {})}
|
|
29
29
|
{...((isPressed && !props.disabled) || props['data-pressed'] ? { ['data-pressed']: true } : {})}
|
|
30
|
-
aria-pressed={
|
|
30
|
+
aria-pressed={isPressed && !props.disabled}
|
|
31
31
|
ref={ref}
|
|
32
32
|
/>
|
|
33
33
|
)
|
|
@@ -13,11 +13,11 @@ export type InlineAlertProps = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const variantClasses = {
|
|
16
|
-
info: 'bg-info-
|
|
16
|
+
info: 'bg-info-500/10 text-info-500 border-info-500/20',
|
|
17
17
|
positive: 'bg-positive-50 text-positive-800 border-positive-200',
|
|
18
18
|
notice: 'bg-notice-50 text-notice-800 border-notice-200',
|
|
19
19
|
negative: 'bg-negative-50 text-negative-800 border-negative-200',
|
|
20
|
-
neutral: 'bg-neutral-
|
|
20
|
+
neutral: 'bg-neutral-100 text-neutral-700 border-neutral-200'
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const defaultIconNames = {
|
|
@@ -34,7 +34,7 @@ export function InlineAlert({ children, actions, variant, icon, className, title
|
|
|
34
34
|
return (
|
|
35
35
|
<div
|
|
36
36
|
className={tw(
|
|
37
|
-
'rounded-
|
|
37
|
+
'rounded-md border px-4 py-3 flex gap-3 items-start justify-between text-left',
|
|
38
38
|
variantClasses[variant],
|
|
39
39
|
className
|
|
40
40
|
)}
|
|
@@ -158,7 +158,7 @@ export const LabeledValue = React.forwardRef<HTMLDivElement, LabeledValueProps>(
|
|
|
158
158
|
<LabeledValueLabel
|
|
159
159
|
id={actualLabelId}
|
|
160
160
|
className={tw(
|
|
161
|
-
orientation === 'horizontal' ? 'shrink-0' : 'mb-1',
|
|
161
|
+
orientation === 'horizontal' ? 'flex-shrink-0' : 'mb-1',
|
|
162
162
|
labelAlign === 'end' && 'text-right',
|
|
163
163
|
labelClassName
|
|
164
164
|
)}
|
|
@@ -474,7 +474,7 @@ export function LabeledValueLabel(props: React.ComponentProps<'label'>) {
|
|
|
474
474
|
return (
|
|
475
475
|
<label
|
|
476
476
|
{...props}
|
|
477
|
-
className={tw('block uppercase text-xs tracking-
|
|
477
|
+
className={tw('block uppercase text-xs tracking-widest font-normal text-neutral-400', props.className)}
|
|
478
478
|
/>
|
|
479
479
|
)
|
|
480
480
|
}
|