braid-ui 1.0.99 → 1.0.100
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/README.md +327 -44
- package/dist/css/braid-ui-variables.css +88 -0
- package/dist/css/braid-ui.css +4702 -0
- package/dist/css/braid-ui.min.css +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2027 -0
- package/dist/index.d.ts +2027 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/package.json +115 -55
- package/src/styles-only.css +121 -0
- package/src/{index.css → styles.css} +4 -10
- package/components.json +0 -20
- package/eslint.config.js +0 -29
- package/index.html +0 -24
- package/postcss.config.js +0 -6
- package/public/favicon.ico +0 -0
- package/public/placeholder.svg +0 -1
- package/public/robots.txt +0 -14
- package/src/App.css +0 -42
- package/src/App.tsx +0 -94
- package/src/components/MainLayout.tsx +0 -15
- package/src/components/alerts/AlertDocuments.tsx +0 -320
- package/src/components/alerts/AlertNotes.tsx +0 -185
- package/src/components/alerts/AlertTimeline.tsx +0 -79
- package/src/components/alerts/ContextSection.tsx +0 -155
- package/src/components/app-sidebar.tsx +0 -341
- package/src/components/form-sections/ACHBankCard.tsx +0 -78
- package/src/components/form-sections/ACHBasicInfoCard.tsx +0 -100
- package/src/components/form-sections/ACHTransferSection.tsx +0 -64
- package/src/components/form-sections/AddressForm.tsx +0 -94
- package/src/components/form-sections/BankAddressCard.tsx +0 -95
- package/src/components/form-sections/BankingDetailsCard.tsx +0 -46
- package/src/components/form-sections/BasicInfoCard.tsx +0 -103
- package/src/components/form-sections/BasicInfoSection.tsx +0 -34
- package/src/components/form-sections/BeneficiaryAddress.tsx +0 -19
- package/src/components/form-sections/BeneficiaryCard.tsx +0 -41
- package/src/components/form-sections/BeneficiaryDomesticWire.tsx +0 -23
- package/src/components/form-sections/BusinessProfileCard.tsx +0 -131
- package/src/components/form-sections/BusinessStatusCard.tsx +0 -53
- package/src/components/form-sections/ContactInfoCard.tsx +0 -63
- package/src/components/form-sections/CounterpartyBasicInfo.tsx +0 -101
- package/src/components/form-sections/CounterpartyProfileCard.tsx +0 -104
- package/src/components/form-sections/CounterpartyRecordsCard.tsx +0 -41
- package/src/components/form-sections/IntermediaryCard.tsx +0 -77
- package/src/components/form-sections/IntermediaryFI.tsx +0 -41
- package/src/components/form-sections/IntermediaryFIAddress.tsx +0 -14
- package/src/components/form-sections/OriginatorCard.tsx +0 -49
- package/src/components/form-sections/OriginatorFI.tsx +0 -42
- package/src/components/form-sections/OriginatorFIAddress.tsx +0 -14
- package/src/components/form-sections/PaymentInformationSection.tsx +0 -163
- package/src/components/form-sections/ReceiverCard.tsx +0 -94
- package/src/components/form-sections/WireTransferSection.tsx +0 -75
- package/src/components/layouts/list-page.tsx +0 -103
- package/src/components/transaction/ACHDetailsSection.tsx +0 -95
- package/src/components/transaction/WireDetailsSection.tsx +0 -112
- package/src/components/ui/account-card.tsx +0 -94
- package/src/components/ui/badge.tsx +0 -75
- package/src/components/ui/breadcrumb.tsx +0 -78
- package/src/components/ui/business-type-badge.tsx +0 -42
- package/src/components/ui/button.tsx +0 -56
- package/src/components/ui/calendar.tsx +0 -49
- package/src/components/ui/card.tsx +0 -223
- package/src/components/ui/container.tsx +0 -45
- package/src/components/ui/counterparty-type-badge.tsx +0 -53
- package/src/components/ui/data-grid.tsx +0 -99
- package/src/components/ui/data-table.tsx +0 -152
- package/src/components/ui/detail-page-layout.tsx +0 -83
- package/src/components/ui/dialog.tsx +0 -120
- package/src/components/ui/dropdown-menu.tsx +0 -82
- package/src/components/ui/editable-form-card.tsx +0 -106
- package/src/components/ui/editable-info-field.tsx +0 -67
- package/src/components/ui/enhanced-input.tsx +0 -78
- package/src/components/ui/enhanced-select.tsx +0 -101
- package/src/components/ui/enhanced-textarea.tsx +0 -64
- package/src/components/ui/entity-card.tsx +0 -140
- package/src/components/ui/form-card.tsx +0 -40
- package/src/components/ui/form-field.tsx +0 -50
- package/src/components/ui/form-input.tsx +0 -29
- package/src/components/ui/form-provider.tsx +0 -18
- package/src/components/ui/form-section.tsx +0 -66
- package/src/components/ui/form-select.tsx +0 -35
- package/src/components/ui/info-field.tsx +0 -36
- package/src/components/ui/json-viewer.tsx +0 -146
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/metric-card.tsx +0 -80
- package/src/components/ui/page-layout.tsx +0 -183
- package/src/components/ui/popover.tsx +0 -29
- package/src/components/ui/responsive-grid.tsx +0 -46
- package/src/components/ui/separator.tsx +0 -31
- package/src/components/ui/sheet.tsx +0 -140
- package/src/components/ui/sidebar.tsx +0 -775
- package/src/components/ui/sonner.tsx +0 -29
- package/src/components/ui/stack.tsx +0 -77
- package/src/components/ui/status-badge.tsx +0 -68
- package/src/components/ui/tabs.tsx +0 -52
- package/src/components/ui/toast.tsx +0 -127
- package/src/components/ui/toaster.tsx +0 -33
- package/src/components/ui/tooltip.tsx +0 -28
- package/src/components/ui/use-toast.ts +0 -3
- package/src/components/ui-kit/dashboard-demo.tsx +0 -156
- package/src/components/ui-kit/pattern-library.tsx +0 -248
- package/src/components/ui-kit/showcase.tsx +0 -211
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/hooks/use-toast.ts +0 -191
- package/src/hooks/useEditState.ts +0 -70
- package/src/hooks/useFormWithEditState.ts +0 -115
- package/src/lib/constants.ts +0 -25
- package/src/lib/mock-data/alert-data.ts +0 -275
- package/src/lib/mock-data/banking-data.ts +0 -72
- package/src/lib/mock-data/business-data.ts +0 -71
- package/src/lib/mock-data/counterparty-data.ts +0 -70
- package/src/lib/mock-data/index.ts +0 -5
- package/src/lib/mock-data/transaction-data.ts +0 -283
- package/src/lib/mock-data/wire-data.ts +0 -103
- package/src/lib/mock-data.tsx +0 -180
- package/src/lib/schemas/banking-schemas.ts +0 -30
- package/src/lib/schemas/business-schemas.ts +0 -36
- package/src/lib/schemas/counterparty-schemas.ts +0 -43
- package/src/lib/schemas/index.ts +0 -5
- package/src/lib/schemas/wire-schemas.ts +0 -44
- package/src/lib/utils.ts +0 -6
- package/src/main.tsx +0 -10
- package/src/pages/Cases.tsx +0 -16
- package/src/pages/Dashboard.tsx +0 -16
- package/src/pages/NotFound.tsx +0 -27
- package/src/pages/TransactionHistory.tsx +0 -532
- package/src/pages/UIKit.tsx +0 -51
- package/src/pages/alerts/AlertDetail.tsx +0 -193
- package/src/pages/alerts/Alerts.tsx +0 -373
- package/src/pages/business/Business.tsx +0 -48
- package/src/pages/business/Create.tsx +0 -173
- package/src/pages/counterparty/Create.tsx +0 -48
- package/src/pages/counterparty/DomesticWire.tsx +0 -78
- package/src/pages/counterparty/Manage.tsx +0 -79
- package/src/pages/transactions/NewTransaction.tsx +0 -527
- package/src/pages/transactions/TransactionDetail.tsx +0 -192
- package/src/vite-env.d.ts +0 -1
- package/tailwind.config.ts +0 -124
- package/tsconfig.app.json +0 -30
- package/tsconfig.json +0 -19
- package/tsconfig.node.json +0 -22
- package/vite.config.ts +0 -22
- /package/{src/assets/braid-logo.png → dist/braid-logo-343BOQZ2.png} +0 -0
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { useState } from "react"
|
|
2
|
-
import { InfoField } from "./info-field"
|
|
3
|
-
import { EnhancedSelect } from "./enhanced-select"
|
|
4
|
-
import { Badge } from "./badge"
|
|
5
|
-
import { cn } from "@/lib/utils"
|
|
6
|
-
|
|
7
|
-
interface EditableInfoFieldProps {
|
|
8
|
-
label: string
|
|
9
|
-
value: string | null | undefined
|
|
10
|
-
options: { value: string; label: string }[]
|
|
11
|
-
onChange: (value: string) => void
|
|
12
|
-
placeholder?: string
|
|
13
|
-
renderValue?: (value: string) => React.ReactNode
|
|
14
|
-
className?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const EditableInfoField = ({
|
|
18
|
-
label,
|
|
19
|
-
value,
|
|
20
|
-
options,
|
|
21
|
-
onChange,
|
|
22
|
-
placeholder = "Select...",
|
|
23
|
-
renderValue,
|
|
24
|
-
className
|
|
25
|
-
}: EditableInfoFieldProps) => {
|
|
26
|
-
const [isEditing, setIsEditing] = useState(false)
|
|
27
|
-
|
|
28
|
-
const handleChange = (newValue: string) => {
|
|
29
|
-
onChange(newValue)
|
|
30
|
-
setIsEditing(false)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (isEditing) {
|
|
34
|
-
return (
|
|
35
|
-
<div className={className}>
|
|
36
|
-
<EnhancedSelect
|
|
37
|
-
label={label}
|
|
38
|
-
value={value || ""}
|
|
39
|
-
onValueChange={handleChange}
|
|
40
|
-
options={options}
|
|
41
|
-
placeholder={placeholder}
|
|
42
|
-
/>
|
|
43
|
-
</div>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const displayValue = value
|
|
48
|
-
? (renderValue ? renderValue(value) : value)
|
|
49
|
-
: placeholder
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<div
|
|
53
|
-
className={cn("cursor-pointer transition-colors hover:bg-muted/50 rounded-md -mx-2 px-2 -my-1 py-1", className)}
|
|
54
|
-
onClick={() => setIsEditing(true)}
|
|
55
|
-
role="button"
|
|
56
|
-
tabIndex={0}
|
|
57
|
-
onKeyDown={(e) => {
|
|
58
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
59
|
-
e.preventDefault()
|
|
60
|
-
setIsEditing(true)
|
|
61
|
-
}
|
|
62
|
-
}}
|
|
63
|
-
>
|
|
64
|
-
<InfoField label={label} value={displayValue} />
|
|
65
|
-
</div>
|
|
66
|
-
)
|
|
67
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { cn } from "@/lib/utils"
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
-
|
|
5
|
-
const inputVariants = cva(
|
|
6
|
-
"flex w-full rounded-md bg-form-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground transition-form",
|
|
7
|
-
{
|
|
8
|
-
variants: {
|
|
9
|
-
variant: {
|
|
10
|
-
default: "border border-form-border focus-visible:border-form-border-focus focus-visible:outline-none focus-visible:shadow-form-focus",
|
|
11
|
-
error: "border border-form-border-error focus-visible:border-form-border-error focus-visible:outline-none focus-visible:shadow-form-error",
|
|
12
|
-
success: "border border-form-border-success focus-visible:border-form-border-success focus-visible:outline-none",
|
|
13
|
-
disabled: "border border-form-border bg-muted cursor-not-allowed opacity-50",
|
|
14
|
-
readonly: "border border-form-border bg-muted/50 cursor-default"
|
|
15
|
-
},
|
|
16
|
-
size: {
|
|
17
|
-
default: "h-10",
|
|
18
|
-
sm: "h-9",
|
|
19
|
-
lg: "h-11"
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
defaultVariants: {
|
|
23
|
-
variant: "default",
|
|
24
|
-
size: "default"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
export interface InputProps
|
|
30
|
-
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>,
|
|
31
|
-
VariantProps<typeof inputVariants> {
|
|
32
|
-
label?: string
|
|
33
|
-
hint?: string
|
|
34
|
-
error?: string
|
|
35
|
-
success?: string
|
|
36
|
-
isLoading?: boolean
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const EnhancedInput = React.forwardRef<HTMLInputElement, InputProps>(
|
|
40
|
-
({ className, variant, size, label, hint, error, success, isLoading, ...props }, ref) => {
|
|
41
|
-
const inputVariant = error ? "error" : success ? "success" : props.disabled ? "disabled" : props.readOnly ? "readonly" : variant
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<div className="space-y-2">
|
|
45
|
-
{label && (
|
|
46
|
-
<label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
|
47
|
-
{label}
|
|
48
|
-
{props.required && <span className="text-destructive ml-1">*</span>}
|
|
49
|
-
</label>
|
|
50
|
-
)}
|
|
51
|
-
<div className="relative">
|
|
52
|
-
<input
|
|
53
|
-
className={cn(inputVariants({ variant: inputVariant, size, className }))}
|
|
54
|
-
ref={ref}
|
|
55
|
-
{...props}
|
|
56
|
-
/>
|
|
57
|
-
{isLoading && (
|
|
58
|
-
<div className="absolute right-3 top-1/2 transform -translate-y-1/2">
|
|
59
|
-
<div className="animate-spin rounded-full h-4 w-4 border-2 border-primary border-t-transparent"></div>
|
|
60
|
-
</div>
|
|
61
|
-
)}
|
|
62
|
-
</div>
|
|
63
|
-
{hint && !error && !success && (
|
|
64
|
-
<p className="text-xs text-muted-foreground">{hint}</p>
|
|
65
|
-
)}
|
|
66
|
-
{error && (
|
|
67
|
-
<p className="text-xs text-destructive">{error}</p>
|
|
68
|
-
)}
|
|
69
|
-
{success && (
|
|
70
|
-
<p className="text-xs text-success">{success}</p>
|
|
71
|
-
)}
|
|
72
|
-
</div>
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
)
|
|
76
|
-
EnhancedInput.displayName = "EnhancedInput"
|
|
77
|
-
|
|
78
|
-
export { EnhancedInput, inputVariants }
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import * as SelectPrimitive from "@radix-ui/react-select"
|
|
3
|
-
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
|
4
|
-
import { cn } from "@/lib/utils"
|
|
5
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
-
|
|
7
|
-
const selectVariants = cva(
|
|
8
|
-
"flex h-10 w-full items-center justify-between rounded-md bg-form-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none transition-form",
|
|
9
|
-
{
|
|
10
|
-
variants: {
|
|
11
|
-
variant: {
|
|
12
|
-
default: "border border-form-border focus:border-form-border-focus focus:shadow-form-focus",
|
|
13
|
-
error: "border border-form-border-error focus:border-form-border-error focus:shadow-form-error",
|
|
14
|
-
success: "border border-form-border-success focus:border-form-border-success",
|
|
15
|
-
disabled: "border border-form-border bg-muted cursor-not-allowed opacity-50",
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
defaultVariants: {
|
|
19
|
-
variant: "default"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
interface EnhancedSelectProps extends VariantProps<typeof selectVariants> {
|
|
25
|
-
label?: string
|
|
26
|
-
hint?: string
|
|
27
|
-
error?: string
|
|
28
|
-
success?: string
|
|
29
|
-
placeholder?: string
|
|
30
|
-
options: { value: string; label: string; disabled?: boolean }[]
|
|
31
|
-
value?: string
|
|
32
|
-
onValueChange?: (value: string) => void
|
|
33
|
-
disabled?: boolean
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const EnhancedSelect = React.forwardRef<
|
|
37
|
-
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
|
38
|
-
EnhancedSelectProps
|
|
39
|
-
>(({ variant, label, hint, error, success, placeholder, options, disabled, ...props }, ref) => {
|
|
40
|
-
const selectVariant = error ? "error" : success ? "success" : disabled ? "disabled" : variant
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div className="space-y-2">
|
|
44
|
-
{label && (
|
|
45
|
-
<label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
|
46
|
-
{label}
|
|
47
|
-
</label>
|
|
48
|
-
)}
|
|
49
|
-
<SelectPrimitive.Root {...props} disabled={disabled}>
|
|
50
|
-
<SelectPrimitive.Trigger
|
|
51
|
-
ref={ref}
|
|
52
|
-
className={cn(selectVariants({ variant: selectVariant }))}
|
|
53
|
-
>
|
|
54
|
-
<SelectPrimitive.Value placeholder={placeholder} />
|
|
55
|
-
<SelectPrimitive.Icon asChild>
|
|
56
|
-
<ChevronDown className="h-4 w-4 opacity-50" />
|
|
57
|
-
</SelectPrimitive.Icon>
|
|
58
|
-
</SelectPrimitive.Trigger>
|
|
59
|
-
<SelectPrimitive.Portal>
|
|
60
|
-
<SelectPrimitive.Content className="relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md 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">
|
|
61
|
-
<SelectPrimitive.ScrollUpButton className="flex cursor-default items-center justify-center py-1">
|
|
62
|
-
<ChevronUp className="h-4 w-4" />
|
|
63
|
-
</SelectPrimitive.ScrollUpButton>
|
|
64
|
-
<SelectPrimitive.Viewport className="p-1">
|
|
65
|
-
{options.map((option) => (
|
|
66
|
-
<SelectPrimitive.Item
|
|
67
|
-
key={option.value}
|
|
68
|
-
value={option.value}
|
|
69
|
-
disabled={option.disabled}
|
|
70
|
-
className="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"
|
|
71
|
-
>
|
|
72
|
-
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
73
|
-
<SelectPrimitive.ItemIndicator>
|
|
74
|
-
<Check className="h-4 w-4" />
|
|
75
|
-
</SelectPrimitive.ItemIndicator>
|
|
76
|
-
</span>
|
|
77
|
-
<SelectPrimitive.ItemText>{option.label}</SelectPrimitive.ItemText>
|
|
78
|
-
</SelectPrimitive.Item>
|
|
79
|
-
))}
|
|
80
|
-
</SelectPrimitive.Viewport>
|
|
81
|
-
<SelectPrimitive.ScrollDownButton className="flex cursor-default items-center justify-center py-1">
|
|
82
|
-
<ChevronDown className="h-4 w-4" />
|
|
83
|
-
</SelectPrimitive.ScrollDownButton>
|
|
84
|
-
</SelectPrimitive.Content>
|
|
85
|
-
</SelectPrimitive.Portal>
|
|
86
|
-
</SelectPrimitive.Root>
|
|
87
|
-
{hint && !error && !success && (
|
|
88
|
-
<p className="text-xs text-muted-foreground">{hint}</p>
|
|
89
|
-
)}
|
|
90
|
-
{error && (
|
|
91
|
-
<p className="text-xs text-destructive">{error}</p>
|
|
92
|
-
)}
|
|
93
|
-
{success && (
|
|
94
|
-
<p className="text-xs text-success">{success}</p>
|
|
95
|
-
)}
|
|
96
|
-
</div>
|
|
97
|
-
)
|
|
98
|
-
})
|
|
99
|
-
EnhancedSelect.displayName = "EnhancedSelect"
|
|
100
|
-
|
|
101
|
-
export { EnhancedSelect }
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { cn } from "@/lib/utils"
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
-
|
|
5
|
-
const textareaVariants = cva(
|
|
6
|
-
"flex min-h-[80px] w-full rounded-md bg-form-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground transition-form resize-y",
|
|
7
|
-
{
|
|
8
|
-
variants: {
|
|
9
|
-
variant: {
|
|
10
|
-
default: "border border-form-border focus-visible:border-form-border-focus focus-visible:outline-none focus-visible:shadow-form-focus",
|
|
11
|
-
error: "border border-form-border-error focus-visible:border-form-border-error focus-visible:outline-none focus-visible:shadow-form-error",
|
|
12
|
-
success: "border border-form-border-success focus-visible:border-form-border-success focus-visible:outline-none",
|
|
13
|
-
disabled: "border border-form-border bg-muted cursor-not-allowed opacity-50 resize-none",
|
|
14
|
-
readonly: "border border-form-border bg-muted/50 cursor-default resize-none"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
defaultVariants: {
|
|
18
|
-
variant: "default"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
export interface TextareaProps
|
|
24
|
-
extends React.TextareaHTMLAttributes<HTMLTextAreaElement>,
|
|
25
|
-
VariantProps<typeof textareaVariants> {
|
|
26
|
-
label?: string
|
|
27
|
-
hint?: string
|
|
28
|
-
error?: string
|
|
29
|
-
success?: string
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const EnhancedTextarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
33
|
-
({ className, variant, label, hint, error, success, ...props }, ref) => {
|
|
34
|
-
const textareaVariant = error ? "error" : success ? "success" : props.disabled ? "disabled" : props.readOnly ? "readonly" : variant
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<div className="space-y-2">
|
|
38
|
-
{label && (
|
|
39
|
-
<label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
|
40
|
-
{label}
|
|
41
|
-
{props.required && <span className="text-destructive ml-1">*</span>}
|
|
42
|
-
</label>
|
|
43
|
-
)}
|
|
44
|
-
<textarea
|
|
45
|
-
className={cn(textareaVariants({ variant: textareaVariant, className }))}
|
|
46
|
-
ref={ref}
|
|
47
|
-
{...props}
|
|
48
|
-
/>
|
|
49
|
-
{hint && !error && !success && (
|
|
50
|
-
<p className="text-xs text-muted-foreground">{hint}</p>
|
|
51
|
-
)}
|
|
52
|
-
{error && (
|
|
53
|
-
<p className="text-xs text-destructive">{error}</p>
|
|
54
|
-
)}
|
|
55
|
-
{success && (
|
|
56
|
-
<p className="text-xs text-success">{success}</p>
|
|
57
|
-
)}
|
|
58
|
-
</div>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
)
|
|
62
|
-
EnhancedTextarea.displayName = "EnhancedTextarea"
|
|
63
|
-
|
|
64
|
-
export { EnhancedTextarea, textareaVariants }
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
3
|
-
import { Badge } from "@/components/ui/badge"
|
|
4
|
-
import { Button } from "@/components/ui/button"
|
|
5
|
-
import { DataGrid } from "@/components/ui/data-grid"
|
|
6
|
-
import { cn } from "@/lib/utils"
|
|
7
|
-
import { MoreVertical, Edit, Trash2, Eye } from "lucide-react"
|
|
8
|
-
import {
|
|
9
|
-
DropdownMenu,
|
|
10
|
-
DropdownMenuContent,
|
|
11
|
-
DropdownMenuItem,
|
|
12
|
-
DropdownMenuSeparator,
|
|
13
|
-
DropdownMenuTrigger
|
|
14
|
-
} from "@/components/ui/dropdown-menu"
|
|
15
|
-
|
|
16
|
-
interface EntityAction {
|
|
17
|
-
label: string
|
|
18
|
-
icon: React.ReactNode
|
|
19
|
-
onClick: () => void
|
|
20
|
-
variant?: "default" | "destructive"
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface EntityCardProps {
|
|
24
|
-
entity: {
|
|
25
|
-
id: string
|
|
26
|
-
name: string
|
|
27
|
-
type: string
|
|
28
|
-
status: string
|
|
29
|
-
description?: string
|
|
30
|
-
metadata?: Record<string, any>
|
|
31
|
-
}
|
|
32
|
-
actions?: EntityAction[]
|
|
33
|
-
showDefaultActions?: boolean
|
|
34
|
-
onView?: (id: string) => void
|
|
35
|
-
onEdit?: (id: string) => void
|
|
36
|
-
onDelete?: (id: string) => void
|
|
37
|
-
className?: string
|
|
38
|
-
children?: React.ReactNode
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const EntityCard = React.forwardRef<HTMLDivElement, EntityCardProps>(
|
|
42
|
-
({
|
|
43
|
-
entity,
|
|
44
|
-
actions,
|
|
45
|
-
showDefaultActions = true,
|
|
46
|
-
onView,
|
|
47
|
-
onEdit,
|
|
48
|
-
onDelete,
|
|
49
|
-
className,
|
|
50
|
-
children
|
|
51
|
-
}, ref) => {
|
|
52
|
-
const defaultActions: EntityAction[] = [
|
|
53
|
-
...(onView ? [{
|
|
54
|
-
label: "View Details",
|
|
55
|
-
icon: <Eye className="w-4 h-4" />,
|
|
56
|
-
onClick: () => onView(entity.id)
|
|
57
|
-
}] : []),
|
|
58
|
-
...(onEdit ? [{
|
|
59
|
-
label: "Edit",
|
|
60
|
-
icon: <Edit className="w-4 h-4" />,
|
|
61
|
-
onClick: () => onEdit(entity.id)
|
|
62
|
-
}] : []),
|
|
63
|
-
...(onDelete ? [{
|
|
64
|
-
label: "Delete",
|
|
65
|
-
icon: <Trash2 className="w-4 h-4" />,
|
|
66
|
-
onClick: () => onDelete(entity.id),
|
|
67
|
-
variant: "destructive" as const
|
|
68
|
-
}] : [])
|
|
69
|
-
]
|
|
70
|
-
|
|
71
|
-
const allActions = showDefaultActions ? [...defaultActions, ...(actions || [])] : (actions || [])
|
|
72
|
-
|
|
73
|
-
const entityData = entity.metadata ? Object.entries(entity.metadata)
|
|
74
|
-
.filter(([_, value]) => value !== null && value !== undefined)
|
|
75
|
-
.map(([key, value]) => ({
|
|
76
|
-
label: key.charAt(0).toUpperCase() + key.slice(1).replace(/([A-Z])/g, ' $1'),
|
|
77
|
-
value: typeof value === 'object' ? JSON.stringify(value) : String(value)
|
|
78
|
-
})) : []
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<Card ref={ref} className={cn("relative", className)}>
|
|
82
|
-
<CardHeader>
|
|
83
|
-
<div className="flex items-start justify-between">
|
|
84
|
-
<div className="flex-1 min-w-0">
|
|
85
|
-
<CardTitle className="text-lg truncate">{entity.name}</CardTitle>
|
|
86
|
-
<div className="flex items-center space-x-2 mt-2">
|
|
87
|
-
<Badge variant={entity.status as any}>{entity.status}</Badge>
|
|
88
|
-
<Badge variant="outline">{entity.type}</Badge>
|
|
89
|
-
</div>
|
|
90
|
-
{entity.description && (
|
|
91
|
-
<p className="text-sm text-muted-foreground mt-2 line-clamp-2">
|
|
92
|
-
{entity.description}
|
|
93
|
-
</p>
|
|
94
|
-
)}
|
|
95
|
-
</div>
|
|
96
|
-
|
|
97
|
-
{allActions.length > 0 && (
|
|
98
|
-
<DropdownMenu>
|
|
99
|
-
<DropdownMenuTrigger asChild>
|
|
100
|
-
<Button variant="ghost" size="icon" className="h-8 w-8">
|
|
101
|
-
<MoreVertical className="w-4 h-4" />
|
|
102
|
-
</Button>
|
|
103
|
-
</DropdownMenuTrigger>
|
|
104
|
-
<DropdownMenuContent align="end">
|
|
105
|
-
{allActions.map((action, index) => (
|
|
106
|
-
<React.Fragment key={index}>
|
|
107
|
-
<DropdownMenuItem
|
|
108
|
-
onClick={action.onClick}
|
|
109
|
-
className={cn(
|
|
110
|
-
action.variant === "destructive" && "text-destructive focus:text-destructive"
|
|
111
|
-
)}
|
|
112
|
-
>
|
|
113
|
-
{action.icon}
|
|
114
|
-
{action.label}
|
|
115
|
-
</DropdownMenuItem>
|
|
116
|
-
{index < allActions.length - 1 && action.variant === "destructive" && (
|
|
117
|
-
<DropdownMenuSeparator />
|
|
118
|
-
)}
|
|
119
|
-
</React.Fragment>
|
|
120
|
-
))}
|
|
121
|
-
</DropdownMenuContent>
|
|
122
|
-
</DropdownMenu>
|
|
123
|
-
)}
|
|
124
|
-
</div>
|
|
125
|
-
</CardHeader>
|
|
126
|
-
|
|
127
|
-
{(entityData.length > 0 || children) && (
|
|
128
|
-
<CardContent>
|
|
129
|
-
{entityData.length > 0 && (
|
|
130
|
-
<DataGrid data={entityData} columns={2} gap="sm" />
|
|
131
|
-
)}
|
|
132
|
-
{children}
|
|
133
|
-
</CardContent>
|
|
134
|
-
)}
|
|
135
|
-
</Card>
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
EntityCard.displayName = "EntityCard"
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { Card, CardContent, CardHeader, CardTitle, CardDescription, type CardProps } from "@/components/ui/card"
|
|
3
|
-
import { cn } from "@/lib/utils"
|
|
4
|
-
|
|
5
|
-
export interface FormCardProps extends Omit<CardProps, 'children'> {
|
|
6
|
-
title: string
|
|
7
|
-
description?: string
|
|
8
|
-
children: React.ReactNode
|
|
9
|
-
headerActions?: React.ReactNode
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const FormCard = React.forwardRef<HTMLDivElement, FormCardProps>(
|
|
13
|
-
({ title, description, children, headerActions, className, variant = "default", ...props }, ref) => (
|
|
14
|
-
<Card
|
|
15
|
-
ref={ref}
|
|
16
|
-
variant={variant}
|
|
17
|
-
fullHeight
|
|
18
|
-
className={cn("", className)}
|
|
19
|
-
{...props}
|
|
20
|
-
>
|
|
21
|
-
<CardHeader
|
|
22
|
-
direction={headerActions ? "row" : "column"}
|
|
23
|
-
size="md"
|
|
24
|
-
>
|
|
25
|
-
<div className="space-y-1">
|
|
26
|
-
<CardTitle size="md">{title}</CardTitle>
|
|
27
|
-
</div>
|
|
28
|
-
{headerActions && (
|
|
29
|
-
<div className="flex items-center gap-2">
|
|
30
|
-
{headerActions}
|
|
31
|
-
</div>
|
|
32
|
-
)}
|
|
33
|
-
</CardHeader>
|
|
34
|
-
<CardContent size="md" fullHeight>
|
|
35
|
-
{children}
|
|
36
|
-
</CardContent>
|
|
37
|
-
</Card>
|
|
38
|
-
)
|
|
39
|
-
)
|
|
40
|
-
FormCard.displayName = "FormCard"
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { cn } from "@/lib/utils"
|
|
3
|
-
|
|
4
|
-
interface FormFieldProps {
|
|
5
|
-
label?: string
|
|
6
|
-
description?: string
|
|
7
|
-
error?: string
|
|
8
|
-
required?: boolean
|
|
9
|
-
children: React.ReactNode
|
|
10
|
-
className?: string
|
|
11
|
-
layout?: "vertical" | "horizontal"
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>(
|
|
15
|
-
({ label, description, error, required, children, className, layout = "vertical" }, ref) => {
|
|
16
|
-
const isHorizontal = layout === "horizontal"
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div
|
|
20
|
-
ref={ref}
|
|
21
|
-
className={cn(
|
|
22
|
-
"space-y-2",
|
|
23
|
-
isHorizontal && "grid grid-cols-1 md:grid-cols-3 gap-4 items-start space-y-0",
|
|
24
|
-
className
|
|
25
|
-
)}
|
|
26
|
-
>
|
|
27
|
-
{label && (
|
|
28
|
-
<div className={cn("space-y-1", isHorizontal && "pt-2")}>
|
|
29
|
-
<label className="text-sm font-medium text-foreground">
|
|
30
|
-
{label}
|
|
31
|
-
{required && <span className="text-destructive ml-1">*</span>}
|
|
32
|
-
</label>
|
|
33
|
-
{description && (
|
|
34
|
-
<p className="text-xs text-muted-foreground">{description}</p>
|
|
35
|
-
)}
|
|
36
|
-
</div>
|
|
37
|
-
)}
|
|
38
|
-
|
|
39
|
-
<div className={cn(isHorizontal && "md:col-span-2")}>
|
|
40
|
-
{children}
|
|
41
|
-
{error && (
|
|
42
|
-
<p className="text-xs text-destructive mt-1">{error}</p>
|
|
43
|
-
)}
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
FormField.displayName = "FormField"
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { Controller, useFormContext, FieldPath, FieldValues } from "react-hook-form"
|
|
3
|
-
import { EnhancedInput, type InputProps } from "@/components/ui/enhanced-input"
|
|
4
|
-
|
|
5
|
-
interface FormInputProps<T extends FieldValues = FieldValues> extends Omit<InputProps, 'error' | 'name'> {
|
|
6
|
-
name: FieldPath<T>
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const FormInput = <T extends FieldValues = FieldValues>({
|
|
10
|
-
name,
|
|
11
|
-
...props
|
|
12
|
-
}: FormInputProps<T>) => {
|
|
13
|
-
const { control, formState } = useFormContext<T>()
|
|
14
|
-
const error = formState.errors[name]?.message as string | undefined
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<Controller
|
|
18
|
-
name={name}
|
|
19
|
-
control={control}
|
|
20
|
-
render={({ field }) => (
|
|
21
|
-
<EnhancedInput
|
|
22
|
-
{...props}
|
|
23
|
-
{...field}
|
|
24
|
-
error={error}
|
|
25
|
-
/>
|
|
26
|
-
)}
|
|
27
|
-
/>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { FormProvider as RHFFormProvider, UseFormReturn, FieldValues } from "react-hook-form"
|
|
3
|
-
|
|
4
|
-
interface FormProviderProps<T extends FieldValues> {
|
|
5
|
-
form: UseFormReturn<T>
|
|
6
|
-
children: React.ReactNode
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const FormProvider = <T extends FieldValues>({
|
|
10
|
-
form,
|
|
11
|
-
children
|
|
12
|
-
}: FormProviderProps<T>) => {
|
|
13
|
-
return (
|
|
14
|
-
<RHFFormProvider {...form}>
|
|
15
|
-
{children}
|
|
16
|
-
</RHFFormProvider>
|
|
17
|
-
)
|
|
18
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { cn } from "@/lib/utils"
|
|
3
|
-
|
|
4
|
-
interface FormSectionProps {
|
|
5
|
-
title?: string
|
|
6
|
-
description?: string
|
|
7
|
-
children: React.ReactNode
|
|
8
|
-
className?: string
|
|
9
|
-
spacing?: "sm" | "md" | "lg"
|
|
10
|
-
layout?: "vertical" | "grid"
|
|
11
|
-
columns?: 1 | 2 | 3 | 4
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const spacingClasses = {
|
|
15
|
-
sm: "space-y-3",
|
|
16
|
-
md: "space-y-4",
|
|
17
|
-
lg: "space-y-6"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const gridClasses = {
|
|
21
|
-
1: "grid-cols-1",
|
|
22
|
-
2: "grid-cols-1 md:grid-cols-2",
|
|
23
|
-
3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
|
24
|
-
4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4"
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const FormSection = React.forwardRef<HTMLDivElement, FormSectionProps>(
|
|
28
|
-
({
|
|
29
|
-
title,
|
|
30
|
-
description,
|
|
31
|
-
children,
|
|
32
|
-
className,
|
|
33
|
-
spacing = "md",
|
|
34
|
-
layout = "vertical",
|
|
35
|
-
columns = 2
|
|
36
|
-
}, ref) => {
|
|
37
|
-
return (
|
|
38
|
-
<div ref={ref} className={cn("space-y-4", className)}>
|
|
39
|
-
{(title || description) && (
|
|
40
|
-
<div className="space-y-1">
|
|
41
|
-
{title && (
|
|
42
|
-
<h3 className="text-lg font-semibold text-foreground">
|
|
43
|
-
{title}
|
|
44
|
-
</h3>
|
|
45
|
-
)}
|
|
46
|
-
{description && (
|
|
47
|
-
<p className="text-sm text-muted-foreground">
|
|
48
|
-
{description}
|
|
49
|
-
</p>
|
|
50
|
-
)}
|
|
51
|
-
</div>
|
|
52
|
-
)}
|
|
53
|
-
|
|
54
|
-
<div className={cn(
|
|
55
|
-
layout === "grid"
|
|
56
|
-
? `grid gap-4 ${gridClasses[columns]}`
|
|
57
|
-
: spacingClasses[spacing]
|
|
58
|
-
)}>
|
|
59
|
-
{children}
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
FormSection.displayName = "FormSection"
|