@opensaas/stack-ui 0.1.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/.turbo/turbo-build.log +8 -0
- package/README.md +286 -0
- package/dist/components/AdminUI.d.ts +24 -0
- package/dist/components/AdminUI.d.ts.map +1 -0
- package/dist/components/AdminUI.js +48 -0
- package/dist/components/ConfirmDialog.d.ts +16 -0
- package/dist/components/ConfirmDialog.d.ts.map +1 -0
- package/dist/components/ConfirmDialog.js +11 -0
- package/dist/components/Dashboard.d.ts +12 -0
- package/dist/components/Dashboard.d.ts.map +1 -0
- package/dist/components/Dashboard.js +30 -0
- package/dist/components/ItemForm.d.ts +17 -0
- package/dist/components/ItemForm.d.ts.map +1 -0
- package/dist/components/ItemForm.js +97 -0
- package/dist/components/ItemFormClient.d.ts +22 -0
- package/dist/components/ItemFormClient.d.ts.map +1 -0
- package/dist/components/ItemFormClient.js +127 -0
- package/dist/components/ListView.d.ts +17 -0
- package/dist/components/ListView.d.ts.map +1 -0
- package/dist/components/ListView.js +76 -0
- package/dist/components/ListViewClient.d.ts +19 -0
- package/dist/components/ListViewClient.d.ts.map +1 -0
- package/dist/components/ListViewClient.js +108 -0
- package/dist/components/LoadingSpinner.d.ts +10 -0
- package/dist/components/LoadingSpinner.d.ts.map +1 -0
- package/dist/components/LoadingSpinner.js +14 -0
- package/dist/components/Navigation.d.ts +13 -0
- package/dist/components/Navigation.d.ts.map +1 -0
- package/dist/components/Navigation.js +20 -0
- package/dist/components/SkeletonLoader.d.ts +22 -0
- package/dist/components/SkeletonLoader.d.ts.map +1 -0
- package/dist/components/SkeletonLoader.js +25 -0
- package/dist/components/fields/CheckboxField.d.ts +11 -0
- package/dist/components/fields/CheckboxField.d.ts.map +1 -0
- package/dist/components/fields/CheckboxField.js +10 -0
- package/dist/components/fields/ComboboxField.d.ts +18 -0
- package/dist/components/fields/ComboboxField.d.ts.map +1 -0
- package/dist/components/fields/ComboboxField.js +32 -0
- package/dist/components/fields/FieldRenderer.d.ts +22 -0
- package/dist/components/fields/FieldRenderer.d.ts.map +1 -0
- package/dist/components/fields/FieldRenderer.js +81 -0
- package/dist/components/fields/IntegerField.d.ts +15 -0
- package/dist/components/fields/IntegerField.d.ts.map +1 -0
- package/dist/components/fields/IntegerField.js +14 -0
- package/dist/components/fields/PasswordField.d.ts +18 -0
- package/dist/components/fields/PasswordField.d.ts.map +1 -0
- package/dist/components/fields/PasswordField.js +42 -0
- package/dist/components/fields/RelationshipField.d.ts +20 -0
- package/dist/components/fields/RelationshipField.d.ts.map +1 -0
- package/dist/components/fields/RelationshipField.js +11 -0
- package/dist/components/fields/RelationshipManager.d.ts +19 -0
- package/dist/components/fields/RelationshipManager.d.ts.map +1 -0
- package/dist/components/fields/RelationshipManager.js +37 -0
- package/dist/components/fields/SelectField.d.ts +16 -0
- package/dist/components/fields/SelectField.d.ts.map +1 -0
- package/dist/components/fields/SelectField.js +11 -0
- package/dist/components/fields/TextField.d.ts +13 -0
- package/dist/components/fields/TextField.d.ts.map +1 -0
- package/dist/components/fields/TextField.js +11 -0
- package/dist/components/fields/TimestampField.d.ts +12 -0
- package/dist/components/fields/TimestampField.d.ts.map +1 -0
- package/dist/components/fields/TimestampField.js +12 -0
- package/dist/components/fields/index.d.ts +23 -0
- package/dist/components/fields/index.d.ts.map +1 -0
- package/dist/components/fields/index.js +13 -0
- package/dist/components/fields/registry.d.ts +43 -0
- package/dist/components/fields/registry.d.ts.map +1 -0
- package/dist/components/fields/registry.js +42 -0
- package/dist/components/standalone/DeleteButton.d.ts +35 -0
- package/dist/components/standalone/DeleteButton.d.ts.map +1 -0
- package/dist/components/standalone/DeleteButton.js +46 -0
- package/dist/components/standalone/ItemCreateForm.d.ts +34 -0
- package/dist/components/standalone/ItemCreateForm.d.ts.map +1 -0
- package/dist/components/standalone/ItemCreateForm.js +91 -0
- package/dist/components/standalone/ItemEditForm.d.ts +37 -0
- package/dist/components/standalone/ItemEditForm.d.ts.map +1 -0
- package/dist/components/standalone/ItemEditForm.js +112 -0
- package/dist/components/standalone/ListTable.d.ts +33 -0
- package/dist/components/standalone/ListTable.d.ts.map +1 -0
- package/dist/components/standalone/ListTable.js +94 -0
- package/dist/components/standalone/SearchBar.d.ts +29 -0
- package/dist/components/standalone/SearchBar.d.ts.map +1 -0
- package/dist/components/standalone/SearchBar.js +43 -0
- package/dist/components/standalone/index.d.ts +11 -0
- package/dist/components/standalone/index.d.ts.map +1 -0
- package/dist/components/standalone/index.js +6 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/lib/serializeFieldConfig.d.ts +43 -0
- package/dist/lib/serializeFieldConfig.d.ts.map +1 -0
- package/dist/lib/serializeFieldConfig.js +48 -0
- package/dist/lib/theme.d.ts +17 -0
- package/dist/lib/theme.d.ts.map +1 -0
- package/dist/lib/theme.js +192 -0
- package/dist/lib/utils.d.ts +18 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +76 -0
- package/dist/primitives/button.d.ts +12 -0
- package/dist/primitives/button.d.ts.map +1 -0
- package/dist/primitives/button.js +33 -0
- package/dist/primitives/calendar.d.ts +9 -0
- package/dist/primitives/calendar.d.ts.map +1 -0
- package/dist/primitives/calendar.js +48 -0
- package/dist/primitives/card.d.ts +9 -0
- package/dist/primitives/card.d.ts.map +1 -0
- package/dist/primitives/card.js +16 -0
- package/dist/primitives/checkbox.d.ts +5 -0
- package/dist/primitives/checkbox.d.ts.map +1 -0
- package/dist/primitives/checkbox.js +7 -0
- package/dist/primitives/combobox.d.ts +14 -0
- package/dist/primitives/combobox.d.ts.map +1 -0
- package/dist/primitives/combobox.js +20 -0
- package/dist/primitives/datetime-picker.d.ts +9 -0
- package/dist/primitives/datetime-picker.d.ts.map +1 -0
- package/dist/primitives/datetime-picker.js +42 -0
- package/dist/primitives/dialog.d.ts +20 -0
- package/dist/primitives/dialog.d.ts.map +1 -0
- package/dist/primitives/dialog.js +21 -0
- package/dist/primitives/index.d.ts +14 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/index.js +14 -0
- package/dist/primitives/input.d.ts +5 -0
- package/dist/primitives/input.d.ts.map +1 -0
- package/dist/primitives/input.js +8 -0
- package/dist/primitives/label.d.ts +6 -0
- package/dist/primitives/label.d.ts.map +1 -0
- package/dist/primitives/label.js +9 -0
- package/dist/primitives/popover.d.ts +7 -0
- package/dist/primitives/popover.d.ts.map +1 -0
- package/dist/primitives/popover.js +10 -0
- package/dist/primitives/select.d.ts +14 -0
- package/dist/primitives/select.d.ts.map +1 -0
- package/dist/primitives/select.js +24 -0
- package/dist/primitives/table.d.ts +11 -0
- package/dist/primitives/table.d.ts.map +1 -0
- package/dist/primitives/table.js +20 -0
- package/dist/primitives/time-picker.d.ts +8 -0
- package/dist/primitives/time-picker.d.ts.map +1 -0
- package/dist/primitives/time-picker.js +27 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/types.d.ts +15 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +1 -0
- package/dist/styles/globals.css +1896 -0
- package/package.json +91 -0
- package/postcss.config.cjs +5 -0
- package/src/components/AdminUI.tsx +112 -0
- package/src/components/ConfirmDialog.tsx +56 -0
- package/src/components/Dashboard.tsx +134 -0
- package/src/components/ItemForm.tsx +195 -0
- package/src/components/ItemFormClient.tsx +237 -0
- package/src/components/ListView.tsx +153 -0
- package/src/components/ListViewClient.tsx +282 -0
- package/src/components/LoadingSpinner.tsx +32 -0
- package/src/components/Navigation.tsx +117 -0
- package/src/components/SkeletonLoader.tsx +82 -0
- package/src/components/fields/CheckboxField.tsx +54 -0
- package/src/components/fields/ComboboxField.tsx +127 -0
- package/src/components/fields/FieldRenderer.tsx +132 -0
- package/src/components/fields/IntegerField.tsx +68 -0
- package/src/components/fields/PasswordField.tsx +159 -0
- package/src/components/fields/RelationshipField.tsx +71 -0
- package/src/components/fields/RelationshipManager.tsx +189 -0
- package/src/components/fields/SelectField.tsx +71 -0
- package/src/components/fields/TextField.tsx +59 -0
- package/src/components/fields/TimestampField.tsx +49 -0
- package/src/components/fields/index.ts +27 -0
- package/src/components/fields/registry.ts +72 -0
- package/src/components/standalone/DeleteButton.tsx +114 -0
- package/src/components/standalone/ItemCreateForm.tsx +161 -0
- package/src/components/standalone/ItemEditForm.tsx +193 -0
- package/src/components/standalone/ListTable.tsx +211 -0
- package/src/components/standalone/SearchBar.tsx +86 -0
- package/src/components/standalone/index.ts +13 -0
- package/src/index.ts +74 -0
- package/src/lib/serializeFieldConfig.ts +88 -0
- package/src/lib/theme.ts +202 -0
- package/src/lib/utils.ts +81 -0
- package/src/primitives/button.tsx +49 -0
- package/src/primitives/calendar.tsx +160 -0
- package/src/primitives/card.tsx +58 -0
- package/src/primitives/checkbox.tsx +27 -0
- package/src/primitives/combobox.tsx +159 -0
- package/src/primitives/datetime-picker.tsx +130 -0
- package/src/primitives/dialog.tsx +108 -0
- package/src/primitives/index.ts +54 -0
- package/src/primitives/input.tsx +24 -0
- package/src/primitives/label.tsx +19 -0
- package/src/primitives/popover.tsx +31 -0
- package/src/primitives/select.tsx +158 -0
- package/src/primitives/table.tsx +91 -0
- package/src/primitives/time-picker.tsx +65 -0
- package/src/server/index.ts +3 -0
- package/src/server/types.ts +15 -0
- package/src/styles/globals.css +123 -0
- package/tailwind.config.ts +3 -0
- package/tests/components/TextField.test.tsx +94 -0
- package/tests/setup.ts +11 -0
- package/tsconfig.json +26 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../lib/utils.js'
|
|
4
|
+
|
|
5
|
+
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>
|
|
6
|
+
|
|
7
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
8
|
+
({ className, type, ...props }, ref) => {
|
|
9
|
+
return (
|
|
10
|
+
<input
|
|
11
|
+
type={type}
|
|
12
|
+
className={cn(
|
|
13
|
+
'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
|
|
14
|
+
className,
|
|
15
|
+
)}
|
|
16
|
+
ref={ref}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
)
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
Input.displayName = 'Input'
|
|
23
|
+
|
|
24
|
+
export { Input }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import * as LabelPrimitive from '@radix-ui/react-label'
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
|
+
|
|
5
|
+
import { cn } from '../lib/utils.js'
|
|
6
|
+
|
|
7
|
+
const labelVariants = cva(
|
|
8
|
+
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const Label = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
|
|
16
|
+
))
|
|
17
|
+
Label.displayName = LabelPrimitive.Root.displayName
|
|
18
|
+
|
|
19
|
+
export { Label }
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
|
5
|
+
|
|
6
|
+
import { cn } from '../lib/utils.js'
|
|
7
|
+
|
|
8
|
+
const Popover = PopoverPrimitive.Root
|
|
9
|
+
|
|
10
|
+
const PopoverTrigger = PopoverPrimitive.Trigger
|
|
11
|
+
|
|
12
|
+
const PopoverContent = React.forwardRef<
|
|
13
|
+
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
14
|
+
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
|
15
|
+
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
|
16
|
+
<PopoverPrimitive.Portal>
|
|
17
|
+
<PopoverPrimitive.Content
|
|
18
|
+
ref={ref}
|
|
19
|
+
align={align}
|
|
20
|
+
sideOffset={sideOffset}
|
|
21
|
+
className={cn(
|
|
22
|
+
'z-50 w-72 rounded-md border bg-card p-4 text-card-foreground shadow-lg outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
23
|
+
className,
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
</PopoverPrimitive.Portal>
|
|
28
|
+
))
|
|
29
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
|
30
|
+
|
|
31
|
+
export { Popover, PopoverTrigger, PopoverContent }
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import * as SelectPrimitive from '@radix-ui/react-select'
|
|
3
|
+
|
|
4
|
+
import { cn } from '../lib/utils.js'
|
|
5
|
+
|
|
6
|
+
const Select = SelectPrimitive.Root
|
|
7
|
+
|
|
8
|
+
const SelectGroup = SelectPrimitive.Group
|
|
9
|
+
|
|
10
|
+
const SelectValue = SelectPrimitive.Value
|
|
11
|
+
|
|
12
|
+
const SelectTrigger = React.forwardRef<
|
|
13
|
+
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
|
14
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
|
15
|
+
>(({ className, children, ...props }, ref) => (
|
|
16
|
+
<SelectPrimitive.Trigger
|
|
17
|
+
ref={ref}
|
|
18
|
+
className={cn(
|
|
19
|
+
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
<SelectPrimitive.Icon asChild>
|
|
26
|
+
<svg className="h-4 w-4 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
27
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
28
|
+
</svg>
|
|
29
|
+
</SelectPrimitive.Icon>
|
|
30
|
+
</SelectPrimitive.Trigger>
|
|
31
|
+
))
|
|
32
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
|
33
|
+
|
|
34
|
+
const SelectScrollUpButton = React.forwardRef<
|
|
35
|
+
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
|
36
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
|
37
|
+
>(({ className, ...props }, ref) => (
|
|
38
|
+
<SelectPrimitive.ScrollUpButton
|
|
39
|
+
ref={ref}
|
|
40
|
+
className={cn('flex cursor-default items-center justify-center py-1', className)}
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
44
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 15l7-7 7 7" />
|
|
45
|
+
</svg>
|
|
46
|
+
</SelectPrimitive.ScrollUpButton>
|
|
47
|
+
))
|
|
48
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
|
49
|
+
|
|
50
|
+
const SelectScrollDownButton = React.forwardRef<
|
|
51
|
+
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
|
52
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
|
53
|
+
>(({ className, ...props }, ref) => (
|
|
54
|
+
<SelectPrimitive.ScrollDownButton
|
|
55
|
+
ref={ref}
|
|
56
|
+
className={cn('flex cursor-default items-center justify-center py-1', className)}
|
|
57
|
+
{...props}
|
|
58
|
+
>
|
|
59
|
+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
60
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
61
|
+
</svg>
|
|
62
|
+
</SelectPrimitive.ScrollDownButton>
|
|
63
|
+
))
|
|
64
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName
|
|
65
|
+
|
|
66
|
+
const SelectContent = React.forwardRef<
|
|
67
|
+
React.ElementRef<typeof SelectPrimitive.Content>,
|
|
68
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
|
69
|
+
>(({ className, children, position = 'popper', ...props }, ref) => (
|
|
70
|
+
<SelectPrimitive.Portal>
|
|
71
|
+
<SelectPrimitive.Content
|
|
72
|
+
ref={ref}
|
|
73
|
+
className={cn(
|
|
74
|
+
'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
75
|
+
position === 'popper' &&
|
|
76
|
+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
|
77
|
+
className,
|
|
78
|
+
)}
|
|
79
|
+
position={position}
|
|
80
|
+
{...props}
|
|
81
|
+
>
|
|
82
|
+
<SelectScrollUpButton />
|
|
83
|
+
<SelectPrimitive.Viewport
|
|
84
|
+
className={cn(
|
|
85
|
+
'p-1',
|
|
86
|
+
position === 'popper' &&
|
|
87
|
+
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
|
|
88
|
+
)}
|
|
89
|
+
>
|
|
90
|
+
{children}
|
|
91
|
+
</SelectPrimitive.Viewport>
|
|
92
|
+
<SelectScrollDownButton />
|
|
93
|
+
</SelectPrimitive.Content>
|
|
94
|
+
</SelectPrimitive.Portal>
|
|
95
|
+
))
|
|
96
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName
|
|
97
|
+
|
|
98
|
+
const SelectLabel = React.forwardRef<
|
|
99
|
+
React.ElementRef<typeof SelectPrimitive.Label>,
|
|
100
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
|
101
|
+
>(({ className, ...props }, ref) => (
|
|
102
|
+
<SelectPrimitive.Label
|
|
103
|
+
ref={ref}
|
|
104
|
+
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
))
|
|
108
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
|
109
|
+
|
|
110
|
+
const SelectItem = React.forwardRef<
|
|
111
|
+
React.ElementRef<typeof SelectPrimitive.Item>,
|
|
112
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
|
113
|
+
>(({ className, children, ...props }, ref) => (
|
|
114
|
+
<SelectPrimitive.Item
|
|
115
|
+
ref={ref}
|
|
116
|
+
className={cn(
|
|
117
|
+
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
|
118
|
+
className,
|
|
119
|
+
)}
|
|
120
|
+
{...props}
|
|
121
|
+
>
|
|
122
|
+
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
123
|
+
<SelectPrimitive.ItemIndicator>
|
|
124
|
+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
125
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
126
|
+
</svg>
|
|
127
|
+
</SelectPrimitive.ItemIndicator>
|
|
128
|
+
</span>
|
|
129
|
+
|
|
130
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
131
|
+
</SelectPrimitive.Item>
|
|
132
|
+
))
|
|
133
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName
|
|
134
|
+
|
|
135
|
+
const SelectSeparator = React.forwardRef<
|
|
136
|
+
React.ElementRef<typeof SelectPrimitive.Separator>,
|
|
137
|
+
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
|
138
|
+
>(({ className, ...props }, ref) => (
|
|
139
|
+
<SelectPrimitive.Separator
|
|
140
|
+
ref={ref}
|
|
141
|
+
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
|
142
|
+
{...props}
|
|
143
|
+
/>
|
|
144
|
+
))
|
|
145
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
|
146
|
+
|
|
147
|
+
export {
|
|
148
|
+
Select,
|
|
149
|
+
SelectGroup,
|
|
150
|
+
SelectValue,
|
|
151
|
+
SelectTrigger,
|
|
152
|
+
SelectContent,
|
|
153
|
+
SelectLabel,
|
|
154
|
+
SelectItem,
|
|
155
|
+
SelectSeparator,
|
|
156
|
+
SelectScrollUpButton,
|
|
157
|
+
SelectScrollDownButton,
|
|
158
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import { cn } from '../lib/utils.js'
|
|
4
|
+
|
|
5
|
+
const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
|
|
6
|
+
({ className, ...props }, ref) => (
|
|
7
|
+
<div className="relative w-full overflow-auto">
|
|
8
|
+
<table ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} />
|
|
9
|
+
</div>
|
|
10
|
+
),
|
|
11
|
+
)
|
|
12
|
+
Table.displayName = 'Table'
|
|
13
|
+
|
|
14
|
+
const TableHeader = React.forwardRef<
|
|
15
|
+
HTMLTableSectionElement,
|
|
16
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
17
|
+
>(({ className, ...props }, ref) => (
|
|
18
|
+
<thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
|
|
19
|
+
))
|
|
20
|
+
TableHeader.displayName = 'TableHeader'
|
|
21
|
+
|
|
22
|
+
const TableBody = React.forwardRef<
|
|
23
|
+
HTMLTableSectionElement,
|
|
24
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
25
|
+
>(({ className, ...props }, ref) => (
|
|
26
|
+
<tbody ref={ref} className={cn('[&_tr:last-child]:border-0', className)} {...props} />
|
|
27
|
+
))
|
|
28
|
+
TableBody.displayName = 'TableBody'
|
|
29
|
+
|
|
30
|
+
const TableFooter = React.forwardRef<
|
|
31
|
+
HTMLTableSectionElement,
|
|
32
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<tfoot
|
|
35
|
+
ref={ref}
|
|
36
|
+
className={cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
))
|
|
40
|
+
TableFooter.displayName = 'TableFooter'
|
|
41
|
+
|
|
42
|
+
const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
|
|
43
|
+
({ className, ...props }, ref) => (
|
|
44
|
+
<tr
|
|
45
|
+
ref={ref}
|
|
46
|
+
className={cn(
|
|
47
|
+
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
TableRow.displayName = 'TableRow'
|
|
55
|
+
|
|
56
|
+
const TableHead = React.forwardRef<
|
|
57
|
+
HTMLTableCellElement,
|
|
58
|
+
React.ThHTMLAttributes<HTMLTableCellElement>
|
|
59
|
+
>(({ className, ...props }, ref) => (
|
|
60
|
+
<th
|
|
61
|
+
ref={ref}
|
|
62
|
+
className={cn(
|
|
63
|
+
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
|
|
64
|
+
className,
|
|
65
|
+
)}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
))
|
|
69
|
+
TableHead.displayName = 'TableHead'
|
|
70
|
+
|
|
71
|
+
const TableCell = React.forwardRef<
|
|
72
|
+
HTMLTableCellElement,
|
|
73
|
+
React.TdHTMLAttributes<HTMLTableCellElement>
|
|
74
|
+
>(({ className, ...props }, ref) => (
|
|
75
|
+
<td
|
|
76
|
+
ref={ref}
|
|
77
|
+
className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
))
|
|
81
|
+
TableCell.displayName = 'TableCell'
|
|
82
|
+
|
|
83
|
+
const TableCaption = React.forwardRef<
|
|
84
|
+
HTMLTableCaptionElement,
|
|
85
|
+
React.HTMLAttributes<HTMLTableCaptionElement>
|
|
86
|
+
>(({ className, ...props }, ref) => (
|
|
87
|
+
<caption ref={ref} className={cn('mt-4 text-sm text-muted-foreground', className)} {...props} />
|
|
88
|
+
))
|
|
89
|
+
TableCaption.displayName = 'TableCaption'
|
|
90
|
+
|
|
91
|
+
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption }
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '../lib/utils.js'
|
|
5
|
+
import { Input } from './input.js'
|
|
6
|
+
|
|
7
|
+
export interface TimePickerProps {
|
|
8
|
+
value?: Date
|
|
9
|
+
onChange?: (date: Date) => void
|
|
10
|
+
disabled?: boolean
|
|
11
|
+
className?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function TimePicker({ value, onChange, disabled, className }: TimePickerProps) {
|
|
15
|
+
const hours = value ? value.getHours() : 12
|
|
16
|
+
const minutes = value ? value.getMinutes() : 30
|
|
17
|
+
|
|
18
|
+
const handleHourChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
19
|
+
const newHours = parseInt(e.target.value) || 0
|
|
20
|
+
const clampedHours = Math.max(0, Math.min(23, newHours))
|
|
21
|
+
|
|
22
|
+
if (onChange) {
|
|
23
|
+
const newDate = value ? new Date(value) : new Date()
|
|
24
|
+
newDate.setHours(clampedHours)
|
|
25
|
+
onChange(newDate)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const handleMinuteChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
30
|
+
const newMinutes = parseInt(e.target.value) || 0
|
|
31
|
+
const clampedMinutes = Math.max(0, Math.min(59, newMinutes))
|
|
32
|
+
|
|
33
|
+
if (onChange) {
|
|
34
|
+
const newDate = value ? new Date(value) : new Date()
|
|
35
|
+
newDate.setMinutes(clampedMinutes)
|
|
36
|
+
onChange(newDate)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className={cn('flex items-center gap-2', className)}>
|
|
42
|
+
<div className="flex items-center">
|
|
43
|
+
<Input
|
|
44
|
+
type="number"
|
|
45
|
+
min={0}
|
|
46
|
+
max={23}
|
|
47
|
+
value={hours.toString().padStart(2, '0')}
|
|
48
|
+
onChange={handleHourChange}
|
|
49
|
+
disabled={disabled}
|
|
50
|
+
className="w-14 text-center"
|
|
51
|
+
/>
|
|
52
|
+
<span className="mx-1 text-lg">:</span>
|
|
53
|
+
<Input
|
|
54
|
+
type="number"
|
|
55
|
+
min={0}
|
|
56
|
+
max={59}
|
|
57
|
+
value={minutes.toString().padStart(2, '0')}
|
|
58
|
+
onChange={handleMinuteChange}
|
|
59
|
+
disabled={disabled}
|
|
60
|
+
className="w-14 text-center"
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input for the generic server action
|
|
3
|
+
* Re-exported from @opensaas/stack-core for convenience
|
|
4
|
+
*/
|
|
5
|
+
export type { ServerActionProps as ServerActionInput } from '@opensaas/stack-core'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Result of a server action
|
|
9
|
+
*/
|
|
10
|
+
export interface ActionResult<T = Record<string, unknown>> {
|
|
11
|
+
success: boolean
|
|
12
|
+
data?: T
|
|
13
|
+
error?: string
|
|
14
|
+
fieldErrors?: Record<string, string>
|
|
15
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
@import 'tailwindcss';
|
|
2
|
+
|
|
3
|
+
@theme inline {
|
|
4
|
+
/* Light mode colors */
|
|
5
|
+
--color-background-light: oklch(0.97 0.01 264);
|
|
6
|
+
--color-foreground-light: oklch(0.2 0.02 264);
|
|
7
|
+
--color-card-light: oklch(1 0 0);
|
|
8
|
+
--color-card-foreground-light: oklch(0.2 0.02 264);
|
|
9
|
+
--color-popover-light: oklch(1 0 0);
|
|
10
|
+
--color-popover-foreground-light: oklch(0.2 0.02 264);
|
|
11
|
+
|
|
12
|
+
--color-primary-light: oklch(0.68 0.19 210);
|
|
13
|
+
--color-primary-foreground-light: oklch(0.2 0.02 264);
|
|
14
|
+
|
|
15
|
+
--color-secondary-light: oklch(0.95 0.01 264);
|
|
16
|
+
--color-secondary-foreground-light: oklch(0.2 0.02 264);
|
|
17
|
+
--color-muted-light: oklch(0.95 0.01 264);
|
|
18
|
+
--color-muted-foreground-light: oklch(0.5 0.01 264);
|
|
19
|
+
--color-accent-light: oklch(0.7 0.21 320);
|
|
20
|
+
--color-accent-foreground-light: oklch(1 0 0);
|
|
21
|
+
|
|
22
|
+
--color-destructive-light: oklch(0.65 0.23 25);
|
|
23
|
+
--color-destructive-foreground-light: oklch(1 0 0);
|
|
24
|
+
--color-border-light: oklch(0.9 0.01 264);
|
|
25
|
+
--color-input-light: oklch(0.9 0.01 264);
|
|
26
|
+
--color-ring-light: oklch(0.68 0.19 210);
|
|
27
|
+
|
|
28
|
+
/* Dark mode colors */
|
|
29
|
+
--color-background-dark: oklch(0.15 0.02 264);
|
|
30
|
+
--color-foreground-dark: oklch(0.95 0.01 264);
|
|
31
|
+
--color-card-dark: oklch(0.18 0.02 264);
|
|
32
|
+
--color-card-foreground-dark: oklch(0.95 0.01 264);
|
|
33
|
+
--color-popover-dark: oklch(0.18 0.02 264);
|
|
34
|
+
--color-popover-foreground-dark: oklch(0.95 0.01 264);
|
|
35
|
+
|
|
36
|
+
--color-primary-dark: oklch(0.72 0.2 210);
|
|
37
|
+
--color-primary-foreground-dark: oklch(0.2 0.02 264);
|
|
38
|
+
|
|
39
|
+
--color-secondary-dark: oklch(0.25 0.02 264);
|
|
40
|
+
--color-secondary-foreground-dark: oklch(0.95 0.01 264);
|
|
41
|
+
--color-muted-dark: oklch(0.25 0.02 264);
|
|
42
|
+
--color-muted-foreground-dark: oklch(0.6 0.01 264);
|
|
43
|
+
--color-accent-dark: oklch(0.75 0.22 320);
|
|
44
|
+
--color-accent-foreground-dark: oklch(0.2 0.02 264);
|
|
45
|
+
|
|
46
|
+
--color-destructive-dark: oklch(0.68 0.24 25);
|
|
47
|
+
--color-destructive-foreground-dark: oklch(1 0 0);
|
|
48
|
+
--color-border-dark: oklch(0.3 0.02 264);
|
|
49
|
+
--color-input-dark: oklch(0.3 0.02 264);
|
|
50
|
+
--color-ring-dark: oklch(0.72 0.2 210);
|
|
51
|
+
|
|
52
|
+
/* Semantic tokens using light-dark() */
|
|
53
|
+
--color-background: light-dark(var(--color-background-light), var(--color-background-dark));
|
|
54
|
+
--color-foreground: light-dark(var(--color-foreground-light), var(--color-foreground-dark));
|
|
55
|
+
--color-card: light-dark(var(--color-card-light), var(--color-card-dark));
|
|
56
|
+
--color-card-foreground: light-dark(
|
|
57
|
+
var(--color-card-foreground-light),
|
|
58
|
+
var(--color-card-foreground-dark)
|
|
59
|
+
);
|
|
60
|
+
--color-popover: light-dark(var(--color-popover-light), var(--color-popover-dark));
|
|
61
|
+
--color-popover-foreground: light-dark(
|
|
62
|
+
var(--color-popover-foreground-light),
|
|
63
|
+
var(--color-popover-foreground-dark)
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
--color-primary: light-dark(var(--color-primary-light), var(--color-primary-dark));
|
|
67
|
+
--color-primary-foreground: light-dark(
|
|
68
|
+
var(--color-primary-foreground-light),
|
|
69
|
+
var(--color-primary-foreground-dark)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
--color-secondary: light-dark(var(--color-secondary-light), var(--color-secondary-dark));
|
|
73
|
+
--color-secondary-foreground: light-dark(
|
|
74
|
+
var(--color-secondary-foreground-light),
|
|
75
|
+
var(--color-secondary-foreground-dark)
|
|
76
|
+
);
|
|
77
|
+
--color-muted: light-dark(var(--color-muted-light), var(--color-muted-dark));
|
|
78
|
+
--color-muted-foreground: light-dark(
|
|
79
|
+
var(--color-muted-foreground-light),
|
|
80
|
+
var(--color-muted-foreground-dark)
|
|
81
|
+
);
|
|
82
|
+
--color-accent: light-dark(var(--color-accent-light), var(--color-accent-dark));
|
|
83
|
+
--color-accent-foreground: light-dark(
|
|
84
|
+
var(--color-accent-foreground-light),
|
|
85
|
+
var(--color-accent-foreground-dark)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
--color-destructive: light-dark(var(--color-destructive-light), var(--color-destructive-dark));
|
|
89
|
+
--color-destructive-foreground: light-dark(
|
|
90
|
+
var(--color-destructive-foreground-light),
|
|
91
|
+
var(--color-destructive-foreground-dark)
|
|
92
|
+
);
|
|
93
|
+
--color-border: light-dark(var(--color-border-light), var(--color-border-dark));
|
|
94
|
+
--color-input: light-dark(var(--color-input-light), var(--color-input-dark));
|
|
95
|
+
--color-ring: light-dark(var(--color-ring-light), var(--color-ring-dark));
|
|
96
|
+
|
|
97
|
+
--radius: 0.75rem;
|
|
98
|
+
|
|
99
|
+
/* Gradient colors for modern effects */
|
|
100
|
+
--gradient-from-light: oklch(0.68 0.19 210);
|
|
101
|
+
--gradient-to-light: oklch(0.7 0.21 320);
|
|
102
|
+
--gradient-from-dark: oklch(0.72 0.2 210);
|
|
103
|
+
--gradient-to-dark: oklch(0.75 0.22 320);
|
|
104
|
+
--gradient-from: light-dark(var(--gradient-from-light), var(--gradient-from-dark));
|
|
105
|
+
--gradient-to: light-dark(var(--gradient-to-light), var(--gradient-to-dark));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
:root {
|
|
109
|
+
color-scheme: light dark;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
* {
|
|
113
|
+
border-color: var(--color-border);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
body {
|
|
117
|
+
background-color: var(--color-background);
|
|
118
|
+
color: var(--color-foreground);
|
|
119
|
+
font-family:
|
|
120
|
+
system-ui,
|
|
121
|
+
-apple-system,
|
|
122
|
+
sans-serif;
|
|
123
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { render, screen } from '@testing-library/react'
|
|
3
|
+
import userEvent from '@testing-library/user-event'
|
|
4
|
+
import { TextField } from '../../src/components/fields/TextField.js'
|
|
5
|
+
|
|
6
|
+
describe('TextField', () => {
|
|
7
|
+
describe('edit mode', () => {
|
|
8
|
+
it('should render text input with label', () => {
|
|
9
|
+
render(<TextField name="username" value="" onChange={vi.fn()} label="Username" />)
|
|
10
|
+
|
|
11
|
+
expect(screen.getByLabelText('Username')).toBeInTheDocument()
|
|
12
|
+
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should display current value', () => {
|
|
16
|
+
render(<TextField name="username" value="john" onChange={vi.fn()} label="Username" />)
|
|
17
|
+
|
|
18
|
+
const input = screen.getByRole('textbox')
|
|
19
|
+
expect(input).toHaveValue('john')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should call onChange when user types', async () => {
|
|
23
|
+
const onChange = vi.fn()
|
|
24
|
+
const user = userEvent.setup()
|
|
25
|
+
|
|
26
|
+
render(<TextField name="username" value="" onChange={onChange} label="Username" />)
|
|
27
|
+
|
|
28
|
+
const input = screen.getByRole('textbox')
|
|
29
|
+
await user.type(input, 't')
|
|
30
|
+
|
|
31
|
+
expect(onChange).toHaveBeenCalled()
|
|
32
|
+
expect(onChange).toHaveBeenCalledWith('t')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should show required indicator when required', () => {
|
|
36
|
+
render(<TextField name="username" value="" onChange={vi.fn()} label="Username" required />)
|
|
37
|
+
|
|
38
|
+
expect(screen.getByText('*')).toBeInTheDocument()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should display error message', () => {
|
|
42
|
+
render(
|
|
43
|
+
<TextField
|
|
44
|
+
name="username"
|
|
45
|
+
value=""
|
|
46
|
+
onChange={vi.fn()}
|
|
47
|
+
label="Username"
|
|
48
|
+
error="Username is required"
|
|
49
|
+
/>,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
expect(screen.getByText('Username is required')).toBeInTheDocument()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should be disabled when disabled prop is true', () => {
|
|
56
|
+
render(<TextField name="username" value="" onChange={vi.fn()} label="Username" disabled />)
|
|
57
|
+
|
|
58
|
+
const input = screen.getByRole('textbox')
|
|
59
|
+
expect(input).toBeDisabled()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should show placeholder text', () => {
|
|
63
|
+
render(
|
|
64
|
+
<TextField
|
|
65
|
+
name="username"
|
|
66
|
+
value=""
|
|
67
|
+
onChange={vi.fn()}
|
|
68
|
+
label="Username"
|
|
69
|
+
placeholder="Enter your username"
|
|
70
|
+
/>,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
expect(screen.getByPlaceholderText('Enter your username')).toBeInTheDocument()
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe('read mode', () => {
|
|
78
|
+
it('should render value as text', () => {
|
|
79
|
+
render(
|
|
80
|
+
<TextField name="username" value="john" onChange={vi.fn()} label="Username" mode="read" />,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
expect(screen.getByText('Username')).toBeInTheDocument()
|
|
84
|
+
expect(screen.getByText('john')).toBeInTheDocument()
|
|
85
|
+
expect(screen.queryByRole('textbox')).not.toBeInTheDocument()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('should show dash when value is empty', () => {
|
|
89
|
+
render(<TextField name="username" value="" onChange={vi.fn()} label="Username" mode="read" />)
|
|
90
|
+
|
|
91
|
+
expect(screen.getByText('-')).toBeInTheDocument()
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
})
|
package/tests/setup.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { expect, afterEach } from 'vitest'
|
|
2
|
+
import { cleanup } from '@testing-library/react'
|
|
3
|
+
import * as matchers from '@testing-library/jest-dom/matchers'
|
|
4
|
+
|
|
5
|
+
// Extend Vitest matchers with jest-dom
|
|
6
|
+
expect.extend(matchers)
|
|
7
|
+
|
|
8
|
+
// Cleanup after each test
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
cleanup()
|
|
11
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"resolveJsonModule": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"noEmit": false,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationMap": true,
|
|
13
|
+
"outDir": "./dist",
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
"allowImportingTsExtensions": false,
|
|
19
|
+
"isolatedModules": true,
|
|
20
|
+
"paths": {
|
|
21
|
+
"@/*": ["./src/*"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"include": ["src/**/*"],
|
|
25
|
+
"exclude": ["node_modules", "dist", "tests"]
|
|
26
|
+
}
|