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.
Files changed (145) hide show
  1. package/README.md +327 -44
  2. package/dist/css/braid-ui-variables.css +88 -0
  3. package/dist/css/braid-ui.css +4702 -0
  4. package/dist/css/braid-ui.min.css +1 -0
  5. package/dist/index.cjs +4 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +2027 -0
  8. package/dist/index.d.ts +2027 -0
  9. package/dist/index.js +4 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +115 -55
  12. package/src/styles-only.css +121 -0
  13. package/src/{index.css → styles.css} +4 -10
  14. package/components.json +0 -20
  15. package/eslint.config.js +0 -29
  16. package/index.html +0 -24
  17. package/postcss.config.js +0 -6
  18. package/public/favicon.ico +0 -0
  19. package/public/placeholder.svg +0 -1
  20. package/public/robots.txt +0 -14
  21. package/src/App.css +0 -42
  22. package/src/App.tsx +0 -94
  23. package/src/components/MainLayout.tsx +0 -15
  24. package/src/components/alerts/AlertDocuments.tsx +0 -320
  25. package/src/components/alerts/AlertNotes.tsx +0 -185
  26. package/src/components/alerts/AlertTimeline.tsx +0 -79
  27. package/src/components/alerts/ContextSection.tsx +0 -155
  28. package/src/components/app-sidebar.tsx +0 -341
  29. package/src/components/form-sections/ACHBankCard.tsx +0 -78
  30. package/src/components/form-sections/ACHBasicInfoCard.tsx +0 -100
  31. package/src/components/form-sections/ACHTransferSection.tsx +0 -64
  32. package/src/components/form-sections/AddressForm.tsx +0 -94
  33. package/src/components/form-sections/BankAddressCard.tsx +0 -95
  34. package/src/components/form-sections/BankingDetailsCard.tsx +0 -46
  35. package/src/components/form-sections/BasicInfoCard.tsx +0 -103
  36. package/src/components/form-sections/BasicInfoSection.tsx +0 -34
  37. package/src/components/form-sections/BeneficiaryAddress.tsx +0 -19
  38. package/src/components/form-sections/BeneficiaryCard.tsx +0 -41
  39. package/src/components/form-sections/BeneficiaryDomesticWire.tsx +0 -23
  40. package/src/components/form-sections/BusinessProfileCard.tsx +0 -131
  41. package/src/components/form-sections/BusinessStatusCard.tsx +0 -53
  42. package/src/components/form-sections/ContactInfoCard.tsx +0 -63
  43. package/src/components/form-sections/CounterpartyBasicInfo.tsx +0 -101
  44. package/src/components/form-sections/CounterpartyProfileCard.tsx +0 -104
  45. package/src/components/form-sections/CounterpartyRecordsCard.tsx +0 -41
  46. package/src/components/form-sections/IntermediaryCard.tsx +0 -77
  47. package/src/components/form-sections/IntermediaryFI.tsx +0 -41
  48. package/src/components/form-sections/IntermediaryFIAddress.tsx +0 -14
  49. package/src/components/form-sections/OriginatorCard.tsx +0 -49
  50. package/src/components/form-sections/OriginatorFI.tsx +0 -42
  51. package/src/components/form-sections/OriginatorFIAddress.tsx +0 -14
  52. package/src/components/form-sections/PaymentInformationSection.tsx +0 -163
  53. package/src/components/form-sections/ReceiverCard.tsx +0 -94
  54. package/src/components/form-sections/WireTransferSection.tsx +0 -75
  55. package/src/components/layouts/list-page.tsx +0 -103
  56. package/src/components/transaction/ACHDetailsSection.tsx +0 -95
  57. package/src/components/transaction/WireDetailsSection.tsx +0 -112
  58. package/src/components/ui/account-card.tsx +0 -94
  59. package/src/components/ui/badge.tsx +0 -75
  60. package/src/components/ui/breadcrumb.tsx +0 -78
  61. package/src/components/ui/business-type-badge.tsx +0 -42
  62. package/src/components/ui/button.tsx +0 -56
  63. package/src/components/ui/calendar.tsx +0 -49
  64. package/src/components/ui/card.tsx +0 -223
  65. package/src/components/ui/container.tsx +0 -45
  66. package/src/components/ui/counterparty-type-badge.tsx +0 -53
  67. package/src/components/ui/data-grid.tsx +0 -99
  68. package/src/components/ui/data-table.tsx +0 -152
  69. package/src/components/ui/detail-page-layout.tsx +0 -83
  70. package/src/components/ui/dialog.tsx +0 -120
  71. package/src/components/ui/dropdown-menu.tsx +0 -82
  72. package/src/components/ui/editable-form-card.tsx +0 -106
  73. package/src/components/ui/editable-info-field.tsx +0 -67
  74. package/src/components/ui/enhanced-input.tsx +0 -78
  75. package/src/components/ui/enhanced-select.tsx +0 -101
  76. package/src/components/ui/enhanced-textarea.tsx +0 -64
  77. package/src/components/ui/entity-card.tsx +0 -140
  78. package/src/components/ui/form-card.tsx +0 -40
  79. package/src/components/ui/form-field.tsx +0 -50
  80. package/src/components/ui/form-input.tsx +0 -29
  81. package/src/components/ui/form-provider.tsx +0 -18
  82. package/src/components/ui/form-section.tsx +0 -66
  83. package/src/components/ui/form-select.tsx +0 -35
  84. package/src/components/ui/info-field.tsx +0 -36
  85. package/src/components/ui/json-viewer.tsx +0 -146
  86. package/src/components/ui/label.tsx +0 -24
  87. package/src/components/ui/metric-card.tsx +0 -80
  88. package/src/components/ui/page-layout.tsx +0 -183
  89. package/src/components/ui/popover.tsx +0 -29
  90. package/src/components/ui/responsive-grid.tsx +0 -46
  91. package/src/components/ui/separator.tsx +0 -31
  92. package/src/components/ui/sheet.tsx +0 -140
  93. package/src/components/ui/sidebar.tsx +0 -775
  94. package/src/components/ui/sonner.tsx +0 -29
  95. package/src/components/ui/stack.tsx +0 -77
  96. package/src/components/ui/status-badge.tsx +0 -68
  97. package/src/components/ui/tabs.tsx +0 -52
  98. package/src/components/ui/toast.tsx +0 -127
  99. package/src/components/ui/toaster.tsx +0 -33
  100. package/src/components/ui/tooltip.tsx +0 -28
  101. package/src/components/ui/use-toast.ts +0 -3
  102. package/src/components/ui-kit/dashboard-demo.tsx +0 -156
  103. package/src/components/ui-kit/pattern-library.tsx +0 -248
  104. package/src/components/ui-kit/showcase.tsx +0 -211
  105. package/src/hooks/use-mobile.tsx +0 -19
  106. package/src/hooks/use-toast.ts +0 -191
  107. package/src/hooks/useEditState.ts +0 -70
  108. package/src/hooks/useFormWithEditState.ts +0 -115
  109. package/src/lib/constants.ts +0 -25
  110. package/src/lib/mock-data/alert-data.ts +0 -275
  111. package/src/lib/mock-data/banking-data.ts +0 -72
  112. package/src/lib/mock-data/business-data.ts +0 -71
  113. package/src/lib/mock-data/counterparty-data.ts +0 -70
  114. package/src/lib/mock-data/index.ts +0 -5
  115. package/src/lib/mock-data/transaction-data.ts +0 -283
  116. package/src/lib/mock-data/wire-data.ts +0 -103
  117. package/src/lib/mock-data.tsx +0 -180
  118. package/src/lib/schemas/banking-schemas.ts +0 -30
  119. package/src/lib/schemas/business-schemas.ts +0 -36
  120. package/src/lib/schemas/counterparty-schemas.ts +0 -43
  121. package/src/lib/schemas/index.ts +0 -5
  122. package/src/lib/schemas/wire-schemas.ts +0 -44
  123. package/src/lib/utils.ts +0 -6
  124. package/src/main.tsx +0 -10
  125. package/src/pages/Cases.tsx +0 -16
  126. package/src/pages/Dashboard.tsx +0 -16
  127. package/src/pages/NotFound.tsx +0 -27
  128. package/src/pages/TransactionHistory.tsx +0 -532
  129. package/src/pages/UIKit.tsx +0 -51
  130. package/src/pages/alerts/AlertDetail.tsx +0 -193
  131. package/src/pages/alerts/Alerts.tsx +0 -373
  132. package/src/pages/business/Business.tsx +0 -48
  133. package/src/pages/business/Create.tsx +0 -173
  134. package/src/pages/counterparty/Create.tsx +0 -48
  135. package/src/pages/counterparty/DomesticWire.tsx +0 -78
  136. package/src/pages/counterparty/Manage.tsx +0 -79
  137. package/src/pages/transactions/NewTransaction.tsx +0 -527
  138. package/src/pages/transactions/TransactionDetail.tsx +0 -192
  139. package/src/vite-env.d.ts +0 -1
  140. package/tailwind.config.ts +0 -124
  141. package/tsconfig.app.json +0 -30
  142. package/tsconfig.json +0 -19
  143. package/tsconfig.node.json +0 -22
  144. package/vite.config.ts +0 -22
  145. /package/{src/assets/braid-logo.png → dist/braid-logo-343BOQZ2.png} +0 -0
@@ -1,53 +0,0 @@
1
- import { Badge } from "@/components/ui/badge"
2
- import { Building2, User, Shield, Heart } from "lucide-react"
3
-
4
- interface CounterpartyTypeBadgeProps {
5
- type: "BUSINESS" | "INDIVIDUAL" | "GOVERNMENT" | "NONPROFIT"
6
- className?: string
7
- }
8
-
9
- const typeConfig = {
10
- BUSINESS: {
11
- variant: "business" as const,
12
- label: "Business",
13
- icon: Building2
14
- },
15
- INDIVIDUAL: {
16
- variant: "individual" as const,
17
- label: "Individual",
18
- icon: User
19
- },
20
- GOVERNMENT: {
21
- variant: "government" as const,
22
- label: "Government",
23
- icon: Shield
24
- },
25
- NONPROFIT: {
26
- variant: "nonprofit" as const,
27
- label: "Non-Profit",
28
- icon: Heart
29
- }
30
- }
31
-
32
- export const CounterpartyTypeBadge = ({ type, className }: CounterpartyTypeBadgeProps) => {
33
- const config = typeConfig[type]
34
-
35
- // Fallback if config is not found
36
- if (!config) {
37
- return (
38
- <Badge variant="secondary" className={className}>
39
- <Building2 className="w-3 h-3 mr-1" />
40
- {type || "Unknown"}
41
- </Badge>
42
- )
43
- }
44
-
45
- const Icon = config.icon
46
-
47
- return (
48
- <Badge variant={config.variant} className={className}>
49
- <Icon className="w-3 h-3 mr-1" />
50
- {config.label}
51
- </Badge>
52
- )
53
- }
@@ -1,99 +0,0 @@
1
- import * as React from "react"
2
- import { InfoField } from "@/components/ui/info-field"
3
- import { cn } from "@/lib/utils"
4
-
5
- export interface DataGridItem {
6
- label?: string
7
- value: string
8
- layout?: "vertical" | "horizontal"
9
- }
10
-
11
- export interface DataGridSection {
12
- title?: string
13
- items: DataGridItem[]
14
- className?: string
15
- }
16
-
17
- interface DataGridProps {
18
- data: DataGridItem[] | DataGridSection[]
19
- columns?: 1 | 2 | 3 | 4
20
- gap?: "sm" | "md" | "lg"
21
- className?: string
22
- }
23
-
24
- const gapClasses = {
25
- sm: "gap-2",
26
- md: "gap-4",
27
- lg: "gap-6"
28
- }
29
-
30
- const columnClasses = {
31
- 1: "grid-cols-1",
32
- 2: "grid-cols-1 md:grid-cols-2",
33
- 3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
34
- 4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4"
35
- }
36
-
37
- export const DataGrid = React.forwardRef<HTMLDivElement, DataGridProps>(
38
- ({ data, columns = 2, gap = "md", className }, ref) => {
39
- // Check if data is sections or simple items
40
- const isItemArray = data.length > 0 && 'label' in data[0]
41
-
42
- if (isItemArray) {
43
- // Simple items array
44
- const items = data as DataGridItem[]
45
- return (
46
- <div
47
- ref={ref}
48
- className={cn(
49
- "grid",
50
- columnClasses[columns],
51
- gapClasses[gap],
52
- className
53
- )}
54
- >
55
- {items.map((item, index) => (
56
- <InfoField
57
- key={index}
58
- label={item.label}
59
- value={item.value}
60
- layout={item.layout || "horizontal"}
61
- />
62
- ))}
63
- </div>
64
- )
65
- }
66
-
67
- // Sections array
68
- const sections = data as DataGridSection[]
69
- return (
70
- <div ref={ref} className={cn("space-y-4", className)}>
71
- {sections.map((section, sectionIndex) => (
72
- <div key={sectionIndex} className={section.className}>
73
- {section.title && (
74
- <h4 className="text-sm font-medium text-foreground mb-2">
75
- {section.title}
76
- </h4>
77
- )}
78
- <div className={cn(
79
- "grid",
80
- columnClasses[columns],
81
- gapClasses[gap]
82
- )}>
83
- {section.items.map((item, itemIndex) => (
84
- <InfoField
85
- key={itemIndex}
86
- label={item.label}
87
- value={item.value}
88
- layout={item.layout || "horizontal"}
89
- />
90
- ))}
91
- </div>
92
- </div>
93
- ))}
94
- </div>
95
- )
96
- }
97
- )
98
-
99
- DataGrid.displayName = "DataGrid"
@@ -1,152 +0,0 @@
1
- import * as React from "react"
2
- import { cn } from "@/lib/utils"
3
- import { Button } from "@/components/ui/button"
4
- import { Badge } from "@/components/ui/badge"
5
- import { ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react"
6
-
7
- export interface DataTableColumn<T = any> {
8
- key: string
9
- title: string
10
- sortable?: boolean
11
- render?: (value: any, row: T) => React.ReactNode
12
- width?: string
13
- align?: "left" | "center" | "right"
14
- }
15
-
16
- export interface DataTableProps<T = any> {
17
- columns: DataTableColumn<T>[]
18
- data: T[]
19
- sortBy?: string
20
- sortDirection?: "asc" | "desc"
21
- onSort?: (key: string) => void
22
- loading?: boolean
23
- emptyMessage?: string
24
- className?: string
25
- }
26
-
27
- export function DataTable<T extends Record<string, any>>({
28
- columns,
29
- data,
30
- sortBy,
31
- sortDirection,
32
- onSort,
33
- loading = false,
34
- emptyMessage = "No data available",
35
- className
36
- }: DataTableProps<T>) {
37
- const handleSort = (key: string) => {
38
- if (onSort) {
39
- onSort(key)
40
- }
41
- }
42
-
43
- const renderSortIcon = (column: DataTableColumn<T>) => {
44
- if (!column.sortable || !onSort) return null
45
-
46
- if (sortBy === column.key) {
47
- return sortDirection === "asc" ?
48
- <ChevronUp className="w-4 h-4 ml-1" /> :
49
- <ChevronDown className="w-4 h-4 ml-1" />
50
- }
51
-
52
- return <ChevronsUpDown className="w-4 h-4 ml-1 opacity-50" />
53
- }
54
-
55
- const renderCell = (column: DataTableColumn<T>, row: T) => {
56
- const value = row[column.key]
57
-
58
- if (column.render) {
59
- return column.render(value, row)
60
- }
61
-
62
- // Auto-render common types
63
- if (typeof value === "boolean") {
64
- return <Badge variant={value ? "success" : "secondary"}>{value ? "Yes" : "No"}</Badge>
65
- }
66
-
67
- if (Array.isArray(value)) {
68
- return value.join(", ")
69
- }
70
-
71
- return value?.toString() || "-"
72
- }
73
-
74
- if (loading) {
75
- return (
76
- <div className={cn("rounded-md border", className)}>
77
- <div className="p-8 text-center">
78
- <div className="animate-pulse text-muted-foreground">Loading...</div>
79
- </div>
80
- </div>
81
- )
82
- }
83
-
84
- return (
85
- <div className={cn("rounded-md border", className)}>
86
- <div className="overflow-x-auto">
87
- <table className="w-full">
88
- <thead>
89
- <tr className="border-b bg-muted/50">
90
- {columns.map((column) => (
91
- <th
92
- key={column.key}
93
- className={cn(
94
- "h-12 px-4 text-left align-middle font-medium text-muted-foreground",
95
- column.align === "center" && "text-center",
96
- column.align === "right" && "text-right",
97
- column.width && `w-[${column.width}]`
98
- )}
99
- >
100
- {column.sortable && onSort ? (
101
- <Button
102
- variant="ghost"
103
- size="sm"
104
- className="h-auto p-0 font-medium hover:bg-transparent"
105
- onClick={() => handleSort(column.key)}
106
- >
107
- <span className="flex items-center">
108
- {column.title}
109
- {renderSortIcon(column)}
110
- </span>
111
- </Button>
112
- ) : (
113
- column.title
114
- )}
115
- </th>
116
- ))}
117
- </tr>
118
- </thead>
119
- <tbody>
120
- {data.length === 0 ? (
121
- <tr>
122
- <td colSpan={columns.length} className="h-24 text-center text-muted-foreground">
123
- {emptyMessage}
124
- </td>
125
- </tr>
126
- ) : (
127
- data.map((row, index) => (
128
- <tr
129
- key={index}
130
- className="border-b transition-colors hover:bg-muted/50"
131
- >
132
- {columns.map((column) => (
133
- <td
134
- key={column.key}
135
- className={cn(
136
- "p-4 align-middle",
137
- column.align === "center" && "text-center",
138
- column.align === "right" && "text-right"
139
- )}
140
- >
141
- {renderCell(column, row)}
142
- </td>
143
- ))}
144
- </tr>
145
- ))
146
- )}
147
- </tbody>
148
- </table>
149
- </div>
150
- </div>
151
- )
152
- }
@@ -1,83 +0,0 @@
1
- import { ReactNode, useState } from "react"
2
- import { PageLayout } from "@/components/ui/page-layout"
3
- import { Button } from "@/components/ui/button"
4
-
5
- interface DetailPageCard {
6
- key: string
7
- component: (props: { isEditing: boolean; onToggleEdit: () => void; className?: string }) => ReactNode
8
- expandOnEdit?: boolean
9
- }
10
-
11
- interface DetailPageAction {
12
- label: string
13
- variant?: "default" | "outline" | "destructive" | "secondary" | "ghost"
14
- onClick?: () => void
15
- className?: string
16
- }
17
-
18
- interface DetailPageLayoutProps {
19
- title: string
20
- description: string
21
- cards: DetailPageCard[]
22
- actions?: DetailPageAction[]
23
- initialEditingState?: Record<string, boolean>
24
- }
25
-
26
- export const DetailPageLayout = ({
27
- title,
28
- description,
29
- cards,
30
- actions,
31
- initialEditingState = {}
32
- }: DetailPageLayoutProps) => {
33
- const [editingCards, setEditingCards] = useState<Record<string, boolean>>(
34
- initialEditingState
35
- )
36
-
37
- const toggleEdit = (cardKey: string) => {
38
- setEditingCards(prev => ({
39
- ...prev,
40
- [cardKey]: !prev[cardKey]
41
- }))
42
- }
43
-
44
- const isAnyCardEditing = Object.values(editingCards).some(Boolean)
45
-
46
- const isSingleCard = cards.length === 1
47
- const gridClasses = isSingleCard
48
- ? "space-y-4 mb-6 lg:space-y-6"
49
- : "grid gap-4 mb-6 grid-cols-1 lg:grid-cols-2 lg:gap-6"
50
-
51
- return (
52
- <PageLayout
53
- title={title}
54
- description={description}
55
- actions={actions?.map(action => ({
56
- label: action.label,
57
- variant: action.variant || "default",
58
- onClick: action.onClick || (() => {})
59
- }))}
60
- >
61
- {/* Cards - Full width for single card, max 2 per row for multiple */}
62
- <div className={gridClasses}>
63
- {cards.map((card) => {
64
- const isEditing = editingCards[card.key] || false
65
- const shouldExpand = !isSingleCard && card.expandOnEdit !== false && isEditing
66
-
67
- return (
68
- <div
69
- key={card.key}
70
- className={shouldExpand ? "col-span-full" : ""}
71
- >
72
- {card.component({
73
- isEditing,
74
- onToggleEdit: () => toggleEdit(card.key),
75
- className: shouldExpand ? "col-span-full" : ""
76
- })}
77
- </div>
78
- )
79
- })}
80
- </div>
81
- </PageLayout>
82
- )
83
- }
@@ -1,120 +0,0 @@
1
- import * as React from "react"
2
- import * as DialogPrimitive from "@radix-ui/react-dialog"
3
- import { X } from "lucide-react"
4
-
5
- import { cn } from "@/lib/utils"
6
-
7
- const Dialog = DialogPrimitive.Root
8
-
9
- const DialogTrigger = DialogPrimitive.Trigger
10
-
11
- const DialogPortal = DialogPrimitive.Portal
12
-
13
- const DialogClose = DialogPrimitive.Close
14
-
15
- const DialogOverlay = React.forwardRef<
16
- React.ElementRef<typeof DialogPrimitive.Overlay>,
17
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
18
- >(({ className, ...props }, ref) => (
19
- <DialogPrimitive.Overlay
20
- ref={ref}
21
- className={cn(
22
- "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
23
- className
24
- )}
25
- {...props}
26
- />
27
- ))
28
- DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
29
-
30
- const DialogContent = React.forwardRef<
31
- React.ElementRef<typeof DialogPrimitive.Content>,
32
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
33
- >(({ className, children, ...props }, ref) => (
34
- <DialogPortal>
35
- <DialogOverlay />
36
- <DialogPrimitive.Content
37
- ref={ref}
38
- className={cn(
39
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-4xl translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg max-h-[90vh] overflow-hidden",
40
- className
41
- )}
42
- {...props}
43
- >
44
- {children}
45
- <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
46
- <X className="h-4 w-4" />
47
- <span className="sr-only">Close</span>
48
- </DialogPrimitive.Close>
49
- </DialogPrimitive.Content>
50
- </DialogPortal>
51
- ))
52
- DialogContent.displayName = DialogPrimitive.Content.displayName
53
-
54
- const DialogHeader = ({
55
- className,
56
- ...props
57
- }: React.HTMLAttributes<HTMLDivElement>) => (
58
- <div
59
- className={cn(
60
- "flex flex-col space-y-1.5 text-center sm:text-left",
61
- className
62
- )}
63
- {...props}
64
- />
65
- )
66
- DialogHeader.displayName = "DialogHeader"
67
-
68
- const DialogFooter = ({
69
- className,
70
- ...props
71
- }: React.HTMLAttributes<HTMLDivElement>) => (
72
- <div
73
- className={cn(
74
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
75
- className
76
- )}
77
- {...props}
78
- />
79
- )
80
- DialogFooter.displayName = "DialogFooter"
81
-
82
- const DialogTitle = React.forwardRef<
83
- React.ElementRef<typeof DialogPrimitive.Title>,
84
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
85
- >(({ className, ...props }, ref) => (
86
- <DialogPrimitive.Title
87
- ref={ref}
88
- className={cn(
89
- "text-lg font-semibold leading-none tracking-tight",
90
- className
91
- )}
92
- {...props}
93
- />
94
- ))
95
- DialogTitle.displayName = DialogPrimitive.Title.displayName
96
-
97
- const DialogDescription = React.forwardRef<
98
- React.ElementRef<typeof DialogPrimitive.Description>,
99
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
100
- >(({ className, ...props }, ref) => (
101
- <DialogPrimitive.Description
102
- ref={ref}
103
- className={cn("text-sm text-muted-foreground", className)}
104
- {...props}
105
- />
106
- ))
107
- DialogDescription.displayName = DialogPrimitive.Description.displayName
108
-
109
- export {
110
- Dialog,
111
- DialogPortal,
112
- DialogOverlay,
113
- DialogClose,
114
- DialogTrigger,
115
- DialogContent,
116
- DialogHeader,
117
- DialogFooter,
118
- DialogTitle,
119
- DialogDescription,
120
- }
@@ -1,82 +0,0 @@
1
- import * as React from "react"
2
- import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
3
- import { cn } from "@/lib/utils"
4
-
5
- const DropdownMenu = DropdownMenuPrimitive.Root
6
-
7
- const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
8
-
9
- const DropdownMenuContent = React.forwardRef<
10
- React.ElementRef<typeof DropdownMenuPrimitive.Content>,
11
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
12
- >(({ className, sideOffset = 4, ...props }, ref) => (
13
- <DropdownMenuPrimitive.Portal>
14
- <DropdownMenuPrimitive.Content
15
- ref={ref}
16
- sideOffset={sideOffset}
17
- className={cn(
18
- "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 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",
19
- className
20
- )}
21
- {...props}
22
- />
23
- </DropdownMenuPrimitive.Portal>
24
- ))
25
- DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
26
-
27
- const DropdownMenuItem = React.forwardRef<
28
- React.ElementRef<typeof DropdownMenuPrimitive.Item>,
29
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
30
- inset?: boolean
31
- }
32
- >(({ className, inset, ...props }, ref) => (
33
- <DropdownMenuPrimitive.Item
34
- ref={ref}
35
- className={cn(
36
- "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
37
- inset && "pl-8",
38
- className
39
- )}
40
- {...props}
41
- />
42
- ))
43
- DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
44
-
45
- const DropdownMenuLabel = React.forwardRef<
46
- React.ElementRef<typeof DropdownMenuPrimitive.Label>,
47
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
48
- inset?: boolean
49
- }
50
- >(({ className, inset, ...props }, ref) => (
51
- <DropdownMenuPrimitive.Label
52
- ref={ref}
53
- className={cn(
54
- "px-2 py-1.5 text-sm font-semibold",
55
- inset && "pl-8",
56
- className
57
- )}
58
- {...props}
59
- />
60
- ))
61
- DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
62
-
63
- const DropdownMenuSeparator = React.forwardRef<
64
- React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
65
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
66
- >(({ className, ...props }, ref) => (
67
- <DropdownMenuPrimitive.Separator
68
- ref={ref}
69
- className={cn("-mx-1 my-1 h-px bg-muted", className)}
70
- {...props}
71
- />
72
- ))
73
- DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
74
-
75
- export {
76
- DropdownMenu,
77
- DropdownMenuTrigger,
78
- DropdownMenuContent,
79
- DropdownMenuItem,
80
- DropdownMenuLabel,
81
- DropdownMenuSeparator,
82
- }
@@ -1,106 +0,0 @@
1
- import * as React from "react"
2
- import { FormCard, type FormCardProps } from "@/components/ui/form-card"
3
- import { Button } from "@/components/ui/button"
4
- import { Edit } from "lucide-react"
5
- import { useEditState } from "@/hooks/useEditState"
6
- import { cn } from "@/lib/utils"
7
-
8
- interface EditableFormCardProps extends Omit<FormCardProps, 'headerActions' | 'children'> {
9
- title: string
10
- description?: string
11
- children?: React.ReactNode
12
- editContent: React.ReactNode
13
- viewContent: React.ReactNode
14
- isEditing?: boolean
15
- onToggleEdit?: () => void
16
- hideActions?: boolean
17
- onSave?: () => void | Promise<void>
18
- onCancel?: () => void
19
- className?: string
20
- isFormValid?: boolean
21
- isDirty?: boolean
22
- isSubmitting?: boolean
23
- }
24
-
25
- export const EditableFormCard = React.forwardRef<HTMLDivElement, EditableFormCardProps>(
26
- ({
27
- title,
28
- description,
29
- editContent,
30
- viewContent,
31
- isEditing,
32
- onToggleEdit,
33
- hideActions = false,
34
- onSave,
35
- onCancel,
36
- className,
37
- variant = "subtle",
38
- isFormValid = true,
39
- isDirty = false,
40
- isSubmitting = false,
41
- ...props
42
- }, ref) => {
43
- const { isEditing: currentlyEditing, handleToggleEdit, handleCancel } = useEditState({
44
- initialEditing: isEditing ?? false,
45
- onToggleEdit
46
- })
47
-
48
- const handleSaveAction = async () => {
49
- if (onSave) {
50
- await onSave()
51
- }
52
- }
53
-
54
- const handleCancelAction = () => {
55
- if (onCancel) {
56
- onCancel()
57
- } else {
58
- handleCancel()
59
- }
60
- }
61
-
62
- return (
63
- <FormCard
64
- ref={ref}
65
- title={title}
66
- description={description}
67
- variant={variant}
68
- className={className}
69
- headerActions={
70
- !hideActions ? (
71
- <div className="flex items-center gap-2">
72
- {currentlyEditing ? (
73
- <>
74
- <Button variant="outline" size="sm" onClick={handleCancelAction}>
75
- Cancel
76
- </Button>
77
- <Button
78
- size="sm"
79
- onClick={handleSaveAction}
80
- disabled={!isFormValid || isSubmitting}
81
- >
82
- {isSubmitting ? "Saving..." : "Save"}
83
- </Button>
84
- </>
85
- ) : (
86
- <Button
87
- variant="ghost"
88
- size="icon"
89
- onClick={handleToggleEdit}
90
- className="text-primary hover:text-primary/80 hover:bg-primary/10"
91
- >
92
- <Edit className="h-4 w-4" />
93
- </Button>
94
- )}
95
- </div>
96
- ) : undefined
97
- }
98
- {...props}
99
- >
100
- {currentlyEditing ? editContent : viewContent}
101
- </FormCard>
102
- )
103
- }
104
- )
105
-
106
- EditableFormCard.displayName = "EditableFormCard"