@wealthx/shadcn 1.2.1 → 1.3.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 +203 -150
- package/CHANGELOG.md +29 -0
- package/dist/{chunk-4Y6R4WEC.mjs → chunk-2A5RRQGG.mjs} +9 -22
- package/dist/{chunk-TS2ZX2VS.mjs → chunk-2UM72RJ7.mjs} +11 -15
- package/dist/{chunk-A56YQQHG.mjs → chunk-3NCUZIFP.mjs} +2 -2
- package/dist/chunk-3OYFOX3X.mjs +79 -0
- package/dist/{chunk-RP3SQYA3.mjs → chunk-3TTACBDP.mjs} +9 -4
- package/dist/chunk-4GAWMKMI.mjs +710 -0
- package/dist/{chunk-SYOD63OZ.mjs → chunk-5FQIKDKP.mjs} +6 -6
- package/dist/{chunk-K3JYD4IU.mjs → chunk-5IS7G74I.mjs} +11 -4
- package/dist/chunk-6AW4KJHE.mjs +235 -0
- package/dist/chunk-6CR5N2JW.mjs +302 -0
- package/dist/{chunk-XIRTEFKH.mjs → chunk-6DZEXFNB.mjs} +36 -8
- package/dist/chunk-6O6KD7CE.mjs +271 -0
- package/dist/chunk-7PV3IWCN.mjs +33 -0
- package/dist/{chunk-SPJ5KXW7.mjs → chunk-7S5AESZO.mjs} +5 -5
- package/dist/{chunk-RYCLWMZ7.mjs → chunk-ABFDMHOR.mjs} +9 -7
- package/dist/{chunk-SWGT756Z.mjs → chunk-AMQZRHEZ.mjs} +10 -4
- package/dist/{chunk-WOEHFRGB.mjs → chunk-BDYZCBRT.mjs} +4 -4
- package/dist/{chunk-WAZD7NFU.mjs → chunk-BKNFWEH2.mjs} +6 -6
- package/dist/{chunk-CLIN5525.mjs → chunk-C7CQJNMR.mjs} +1 -1
- package/dist/{chunk-D4ILTPOG.mjs → chunk-CFMQP5QS.mjs} +5 -4
- package/dist/{chunk-VPBN3WOO.mjs → chunk-DGHAXJBN.mjs} +9 -7
- package/dist/chunk-DOEO3CDL.mjs +27 -0
- package/dist/{chunk-KUDCQ4FI.mjs → chunk-DUJTAXMH.mjs} +9 -4
- package/dist/{chunk-GGM2UYGG.mjs → chunk-EBXQWIYG.mjs} +10 -4
- package/dist/{chunk-PMB3A7V3.mjs → chunk-EI5F6FMT.mjs} +1 -1
- package/dist/chunk-EWRB4PAD.mjs +468 -0
- package/dist/chunk-FAKPBKLT.mjs +253 -0
- package/dist/chunk-FNQXOAYJ.mjs +169 -0
- package/dist/{chunk-4CX4SBRO.mjs → chunk-GHC7LLUX.mjs} +14 -5
- package/dist/chunk-HBZLGDIN.mjs +507 -0
- package/dist/{chunk-SIZMLSRU.mjs → chunk-HISNT2MG.mjs} +8 -6
- package/dist/{chunk-PR6V5XKM.mjs → chunk-HVY6KCCF.mjs} +7 -4
- package/dist/chunk-I3RZS7V2.mjs +136 -0
- package/dist/chunk-IAE3F7DR.mjs +1962 -0
- package/dist/{chunk-ZRO5JO3H.mjs → chunk-IHMFS7NZ.mjs} +81 -84
- package/dist/{chunk-PCPLO5HT.mjs → chunk-IOJRDS6V.mjs} +96 -14
- package/dist/{chunk-LHYCMLVA.mjs → chunk-JKGDCQTZ.mjs} +11 -4
- package/dist/{chunk-H45TKD34.mjs → chunk-JMHR3YGZ.mjs} +1 -1
- package/dist/{chunk-4MN6UQHG.mjs → chunk-K5A5L6T2.mjs} +17 -39
- package/dist/{chunk-CSDO6VBW.mjs → chunk-LBMRIB3G.mjs} +10 -10
- package/dist/chunk-LV35NGVG.mjs +272 -0
- package/dist/{chunk-FZIXGLMV.mjs → chunk-M3FV7LOK.mjs} +5 -12
- package/dist/{chunk-FMAXJ2SI.mjs → chunk-MBON7YRJ.mjs} +1 -1
- package/dist/chunk-MIZQHHUO.mjs +441 -0
- package/dist/chunk-MN5NYQCL.mjs +29 -0
- package/dist/chunk-NL3ZO62D.mjs +31 -0
- package/dist/{chunk-Q76O3RIQ.mjs → chunk-NMOI6CQD.mjs} +1 -1
- package/dist/{chunk-P6AM5V7O.mjs → chunk-OODBHKG7.mjs} +1 -1
- package/dist/chunk-PBL4OQV2.mjs +283 -0
- package/dist/{chunk-3WMX6KWS.mjs → chunk-PU4YZQXV.mjs} +11 -12
- package/dist/chunk-QMY3AZJH.mjs +80 -0
- package/dist/{chunk-BL3DXM2X.mjs → chunk-QZ4RE6NA.mjs} +11 -4
- package/dist/{chunk-VACKZOMY.mjs → chunk-R3VSPKNP.mjs} +3 -3
- package/dist/{chunk-OPNQAVVH.mjs → chunk-RJI6GKVF.mjs} +8 -6
- package/dist/{chunk-WG6JGJXB.mjs → chunk-T4BJLT57.mjs} +1 -1
- package/dist/chunk-U4NDAF2P.mjs +207 -0
- package/dist/{chunk-DOH3EHX7.mjs → chunk-U5X52X37.mjs} +1 -1
- package/dist/chunk-UMTOX62O.mjs +415 -0
- package/dist/{chunk-7MMXNK3C.mjs → chunk-VLARHE5V.mjs} +8 -6
- package/dist/{chunk-2I5S2AMY.mjs → chunk-XREGSKX3.mjs} +2 -2
- package/dist/{chunk-JNQORUPP.mjs → chunk-YJG55G2H.mjs} +14 -11
- package/dist/chunk-ZC45IGZO.mjs +388 -0
- package/dist/components/ui/add-column-modal.js +42 -14
- package/dist/components/ui/add-column-modal.mjs +4 -4
- package/dist/components/ui/add-lead-modal.js +42 -11
- package/dist/components/ui/add-lead-modal.mjs +3 -3
- package/dist/components/ui/advisor-card.js +497 -0
- package/dist/components/ui/advisor-card.mjs +13 -0
- package/dist/components/ui/ai-assistant-drawer.js +11 -10
- package/dist/components/ui/ai-assistant-drawer.mjs +3 -3
- package/dist/components/ui/alert-dialog.js +2 -2
- package/dist/components/ui/alert-dialog.mjs +2 -2
- package/dist/components/ui/appointment-action-dialogs.js +1160 -0
- package/dist/components/ui/appointment-action-dialogs.mjs +23 -0
- package/dist/components/ui/appointment-availability-settings.js +1590 -0
- package/dist/components/ui/appointment-availability-settings.mjs +23 -0
- package/dist/components/ui/appointment-book-dialog.js +1744 -0
- package/dist/components/ui/appointment-book-dialog.mjs +27 -0
- package/dist/components/ui/appointment-calendar-view.js +833 -0
- package/dist/components/ui/appointment-calendar-view.mjs +14 -0
- package/dist/components/ui/appointment-detail-sheet.js +1517 -0
- package/dist/components/ui/appointment-detail-sheet.mjs +24 -0
- package/dist/components/ui/appointment-gmail-connect.js +467 -0
- package/dist/components/ui/appointment-gmail-connect.mjs +14 -0
- package/dist/components/ui/appointment-mini-card.js +345 -0
- package/dist/components/ui/appointment-mini-card.mjs +11 -0
- package/dist/components/ui/appointment-time-slot-picker.js +311 -0
- package/dist/components/ui/appointment-time-slot-picker.mjs +13 -0
- package/dist/components/ui/appointment-upcoming-card.js +1268 -0
- package/dist/components/ui/appointment-upcoming-card.mjs +21 -0
- package/dist/components/ui/backoffice-alert-history-chart.js +11 -5
- package/dist/components/ui/backoffice-alert-history-chart.mjs +5 -4
- package/dist/components/ui/backoffice-alerts-chart.js +786 -0
- package/dist/components/ui/backoffice-alerts-chart.mjs +19 -0
- package/dist/components/ui/backoffice-connections-chart.js +817 -0
- package/dist/components/ui/backoffice-connections-chart.mjs +19 -0
- package/dist/components/ui/backoffice-contact-history-chart.js +11 -5
- package/dist/components/ui/backoffice-contact-history-chart.mjs +5 -4
- package/dist/components/ui/badge.js +6 -6
- package/dist/components/ui/badge.mjs +1 -1
- package/dist/components/ui/borrowing-capacity-line-chart.js +30 -21
- package/dist/components/ui/borrowing-capacity-line-chart.mjs +5 -4
- package/dist/components/ui/button.js +2 -2
- package/dist/components/ui/button.mjs +1 -1
- package/dist/components/ui/calendar.js +2 -2
- package/dist/components/ui/calendar.mjs +2 -2
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/card.mjs +1 -1
- package/dist/components/ui/cash-balance-line-chart.js +31 -23
- package/dist/components/ui/cash-balance-line-chart.mjs +5 -4
- package/dist/components/ui/cashflow-bar-chart.js +12 -5
- package/dist/components/ui/cashflow-bar-chart.mjs +5 -4
- package/dist/components/ui/chip.js +97 -18
- package/dist/components/ui/chip.mjs +3 -2
- package/dist/components/ui/color-picker.js +547 -0
- package/dist/components/ui/color-picker.mjs +24 -0
- package/dist/components/ui/data-table.js +182 -129
- package/dist/components/ui/data-table.mjs +3 -2
- package/dist/components/ui/date-picker.js +48 -27
- package/dist/components/ui/date-picker.mjs +4 -3
- package/dist/components/ui/dialog.js +37 -9
- package/dist/components/ui/dialog.mjs +2 -2
- package/dist/components/ui/expense-bar-chart.js +12 -5
- package/dist/components/ui/expense-bar-chart.mjs +5 -4
- package/dist/components/ui/field.mjs +2 -2
- package/dist/components/ui/financial-cards.js +322 -155
- package/dist/components/ui/financial-cards.mjs +5 -3
- package/dist/components/ui/financial-drawers.js +2 -2
- package/dist/components/ui/financial-drawers.mjs +3 -3
- package/dist/components/ui/financial-sections.js +14 -10
- package/dist/components/ui/financial-sections.mjs +6 -5
- package/dist/components/ui/form-primitives.js +4 -4
- package/dist/components/ui/form-primitives.mjs +3 -3
- package/dist/components/ui/income-bar-chart.js +12 -5
- package/dist/components/ui/income-bar-chart.mjs +5 -4
- package/dist/components/ui/input-group.js +2 -2
- package/dist/components/ui/input-group.mjs +2 -2
- package/dist/components/ui/kanban-column.js +52 -44
- package/dist/components/ui/kanban-column.mjs +7 -5
- package/dist/components/ui/opportunity-card.js +52 -44
- package/dist/components/ui/opportunity-card.mjs +6 -4
- package/dist/components/ui/opportunity-edit-modals.js +1371 -1267
- package/dist/components/ui/opportunity-edit-modals.mjs +10 -10
- package/dist/components/ui/opportunity-summary-tab.js +2748 -2161
- package/dist/components/ui/opportunity-summary-tab.mjs +16 -16
- package/dist/components/ui/page-header.js +92 -0
- package/dist/components/ui/page-header.mjs +8 -0
- package/dist/components/ui/page-top-bar.js +88 -0
- package/dist/components/ui/page-top-bar.mjs +8 -0
- package/dist/components/ui/pagination.js +303 -19
- package/dist/components/ui/pagination.mjs +11 -4
- package/dist/components/ui/pipeline-board.js +209 -195
- package/dist/components/ui/pipeline-board.mjs +10 -8
- package/dist/components/ui/pipeline-dialogs.js +118 -69
- package/dist/components/ui/pipeline-dialogs.mjs +8 -7
- package/dist/components/ui/pipeline-primitives.js +6 -6
- package/dist/components/ui/pipeline-primitives.mjs +2 -2
- package/dist/components/ui/property-cashflow-doughnut-chart.js +14 -12
- package/dist/components/ui/property-cashflow-doughnut-chart.mjs +5 -4
- package/dist/components/ui/property-debt-equity-doughnut-chart.js +14 -12
- package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +5 -4
- package/dist/components/ui/property-mobile-estimate-line-chart.js +16 -14
- package/dist/components/ui/property-mobile-estimate-line-chart.mjs +5 -4
- package/dist/components/ui/sidebar-nav.js +679 -0
- package/dist/components/ui/sidebar-nav.mjs +14 -0
- package/dist/components/ui/stage-timeline.js +6 -6
- package/dist/components/ui/stage-timeline.mjs +3 -3
- package/dist/components/ui/stepper.js +283 -0
- package/dist/components/ui/stepper.mjs +18 -0
- package/dist/components/ui/toggle-group.js +4 -4
- package/dist/components/ui/toggle-group.mjs +2 -2
- package/dist/components/ui/toggle.js +4 -4
- package/dist/components/ui/toggle.mjs +1 -1
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +18 -16
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +5 -4
- package/dist/components/ui/transactions-income-expense-bar-chart.js +28 -12
- package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -4
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +18 -16
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +5 -4
- package/dist/index.js +12927 -8522
- package/dist/index.mjs +288 -190
- package/dist/lib/typography.js +10 -10
- package/dist/lib/typography.mjs +1 -1
- package/dist/styles.css +1 -1
- package/package.json +86 -1
- package/src/components/index.tsx +146 -0
- package/src/components/ui/add-column-modal.tsx +7 -7
- package/src/components/ui/add-lead-modal.tsx +6 -3
- package/src/components/ui/advisor-card.tsx +227 -0
- package/src/components/ui/ai-assistant-drawer.tsx +4 -3
- package/src/components/ui/appointment-action-dialogs.tsx +297 -0
- package/src/components/ui/appointment-availability-settings.tsx +645 -0
- package/src/components/ui/appointment-book-dialog.tsx +618 -0
- package/src/components/ui/appointment-calendar-view.tsx +510 -0
- package/src/components/ui/appointment-detail-sheet.tsx +415 -0
- package/src/components/ui/appointment-gmail-connect.tsx +188 -0
- package/src/components/ui/appointment-mini-card.tsx +104 -0
- package/src/components/ui/appointment-time-slot-picker.tsx +123 -0
- package/src/components/ui/appointment-upcoming-card.tsx +635 -0
- package/src/components/ui/backoffice-alert-history-chart.tsx +10 -2
- package/src/components/ui/backoffice-alerts-chart.tsx +312 -0
- package/src/components/ui/backoffice-connections-chart.tsx +339 -0
- package/src/components/ui/backoffice-contact-history-chart.tsx +10 -2
- package/src/components/ui/badge.tsx +12 -6
- package/src/components/ui/borrowing-capacity-line-chart.tsx +4 -11
- package/src/components/ui/button.tsx +2 -2
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/cash-balance-line-chart.tsx +4 -23
- package/src/components/ui/cashflow-bar-chart.tsx +9 -2
- package/src/components/ui/chart-shared.tsx +4 -11
- package/src/components/ui/chip.tsx +23 -19
- package/src/components/ui/color-picker.tsx +309 -0
- package/src/components/ui/data-table.tsx +117 -83
- package/src/components/ui/date-picker.tsx +42 -37
- package/src/components/ui/dialog.tsx +72 -6
- package/src/components/ui/expense-bar-chart.tsx +11 -2
- package/src/components/ui/financial-cards.tsx +99 -10
- package/src/components/ui/income-bar-chart.tsx +11 -2
- package/src/components/ui/opportunity-card.tsx +10 -39
- package/src/components/ui/opportunity-edit-modals.tsx +98 -36
- package/src/components/ui/opportunity-summary-tab.tsx +548 -232
- package/src/components/ui/page-header.tsx +57 -0
- package/src/components/ui/page-top-bar.tsx +48 -0
- package/src/components/ui/pagination.tsx +171 -22
- package/src/components/ui/pipeline-board.tsx +12 -5
- package/src/components/ui/property-cashflow-doughnut-chart.tsx +3 -1
- package/src/components/ui/property-debt-equity-doughnut-chart.tsx +3 -1
- package/src/components/ui/property-mobile-estimate-line-chart.tsx +3 -1
- package/src/components/ui/sidebar-nav.tsx +516 -0
- package/src/components/ui/stepper.tsx +347 -0
- package/src/components/ui/toggle.tsx +4 -4
- package/src/components/ui/transactions-expense-categories-doughnut-chart.tsx +3 -1
- package/src/components/ui/transactions-income-expense-bar-chart.tsx +12 -9
- package/src/components/ui/transactions-liabilities-breakdown-doughnut-chart.tsx +3 -1
- package/src/lib/format-currency.ts +44 -0
- package/src/lib/format-date.ts +50 -0
- package/src/lib/opportunity-constants.ts +12 -0
- package/src/lib/typography.ts +11 -11
- package/src/styles/globals.css +36 -34
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +17 -0
- package/dist/chunk-PG6K5XEC.mjs +0 -475
- package/dist/chunk-WA6O6EUR.mjs +0 -1885
- package/dist/chunk-WNGWBVLV.mjs +0 -148
- package/dist/{chunk-LLVQKSU3.mjs → chunk-GD4BJDJR.mjs} +3 -3
|
@@ -19,6 +19,7 @@ import * as React from "react";
|
|
|
19
19
|
import {
|
|
20
20
|
type ColumnDef,
|
|
21
21
|
type ColumnFiltersState,
|
|
22
|
+
type PaginationState,
|
|
22
23
|
type SortingState,
|
|
23
24
|
type VisibilityState,
|
|
24
25
|
type RowSelectionState,
|
|
@@ -34,10 +35,6 @@ import {
|
|
|
34
35
|
ArrowUpDown,
|
|
35
36
|
ArrowUp,
|
|
36
37
|
ArrowDown,
|
|
37
|
-
ChevronLeftIcon,
|
|
38
|
-
ChevronRightIcon,
|
|
39
|
-
ChevronsLeftIcon,
|
|
40
|
-
ChevronsRightIcon,
|
|
41
38
|
SlidersHorizontal,
|
|
42
39
|
} from "lucide-react";
|
|
43
40
|
import { cn } from "@/lib/utils";
|
|
@@ -59,6 +56,7 @@ import {
|
|
|
59
56
|
SelectTrigger,
|
|
60
57
|
SelectValue,
|
|
61
58
|
} from "@/components/ui/select";
|
|
59
|
+
import { PaginationNavButtons } from "@/components/ui/pagination";
|
|
62
60
|
import {
|
|
63
61
|
DropdownMenu,
|
|
64
62
|
DropdownMenuCheckboxItem,
|
|
@@ -74,7 +72,7 @@ import { Skeleton } from "@/components/ui/skeleton";
|
|
|
74
72
|
// Types
|
|
75
73
|
// ---------------------------------------------------------------------------
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
interface DataTableProps<TData, TValue> {
|
|
78
76
|
/** Column definitions — pass ColumnDef[] from \@tanstack/react-table */
|
|
79
77
|
columns: ColumnDef<TData, TValue>[];
|
|
80
78
|
/** Row data */
|
|
@@ -101,13 +99,35 @@ export interface DataTableProps<TData, TValue> {
|
|
|
101
99
|
toolbar?: (table: TanstackTable<TData>) => React.ReactNode;
|
|
102
100
|
/** Text shown when no results found */
|
|
103
101
|
emptyText?: string;
|
|
102
|
+
/** Enable server-side pagination (disables client-side pagination model) */
|
|
103
|
+
manualPagination?: boolean;
|
|
104
|
+
/** Enable server-side sorting (disables client-side sorting model) */
|
|
105
|
+
manualSorting?: boolean;
|
|
106
|
+
/** Enable server-side filtering (disables client-side filtering model) */
|
|
107
|
+
manualFiltering?: boolean;
|
|
108
|
+
/** Total page count (required for server-side pagination) */
|
|
109
|
+
pageCount?: number;
|
|
110
|
+
/** Total row count (alternative to pageCount for server-side pagination) */
|
|
111
|
+
rowCount?: number;
|
|
112
|
+
/** Controlled sorting state */
|
|
113
|
+
sorting?: SortingState;
|
|
114
|
+
/** Controlled pagination state */
|
|
115
|
+
pagination?: PaginationState;
|
|
116
|
+
/** Controlled column filters state */
|
|
117
|
+
columnFilters?: ColumnFiltersState;
|
|
118
|
+
/** Callback when sorting state changes */
|
|
119
|
+
onSortingChange?: (sorting: SortingState) => void;
|
|
120
|
+
/** Callback when pagination state changes */
|
|
121
|
+
onPaginationChange?: (pagination: PaginationState) => void;
|
|
122
|
+
/** Callback when column filters state changes */
|
|
123
|
+
onColumnFiltersChange?: (filters: ColumnFiltersState) => void;
|
|
104
124
|
}
|
|
105
125
|
|
|
106
126
|
// ---------------------------------------------------------------------------
|
|
107
127
|
// Helper: sortable header
|
|
108
128
|
// ---------------------------------------------------------------------------
|
|
109
129
|
|
|
110
|
-
|
|
130
|
+
function DataTableColumnHeader({
|
|
111
131
|
column,
|
|
112
132
|
title,
|
|
113
133
|
className,
|
|
@@ -157,7 +177,7 @@ export function DataTableColumnHeader({
|
|
|
157
177
|
// Helper: selection column
|
|
158
178
|
// ---------------------------------------------------------------------------
|
|
159
179
|
|
|
160
|
-
|
|
180
|
+
function getSelectionColumn<TData>(): ColumnDef<TData> {
|
|
161
181
|
return {
|
|
162
182
|
id: "select",
|
|
163
183
|
header: ({ table }) => (
|
|
@@ -268,32 +288,30 @@ function DataTablePagination<TData>({
|
|
|
268
288
|
}): ReactElement {
|
|
269
289
|
return (
|
|
270
290
|
<div
|
|
271
|
-
className="flex items-center
|
|
291
|
+
className="flex items-center gap-4 py-4"
|
|
272
292
|
data-slot="data-table-pagination"
|
|
273
293
|
>
|
|
274
|
-
{
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
</>
|
|
281
|
-
)}
|
|
282
|
-
</p>
|
|
294
|
+
{table.getFilteredSelectedRowModel().rows.length > 0 && (
|
|
295
|
+
<span className="text-body-small text-muted-foreground">
|
|
296
|
+
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
|
297
|
+
{table.getFilteredRowModel().rows.length} row(s) selected.
|
|
298
|
+
</span>
|
|
299
|
+
)}
|
|
283
300
|
|
|
284
|
-
<div className="flex items-center gap-6">
|
|
285
|
-
{/* Page size selector */}
|
|
301
|
+
<div className="ml-auto flex items-center gap-6">
|
|
286
302
|
<div className="flex items-center gap-2">
|
|
287
|
-
<
|
|
303
|
+
<span className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
288
304
|
Rows per page
|
|
289
|
-
</
|
|
305
|
+
</span>
|
|
290
306
|
<Select
|
|
291
|
-
onValueChange={(value) =>
|
|
292
|
-
table.setPageSize(Number(value));
|
|
293
|
-
}}
|
|
307
|
+
onValueChange={(value) => table.setPageSize(Number(value))}
|
|
294
308
|
value={`${table.getState().pagination.pageSize}`}
|
|
295
309
|
>
|
|
296
|
-
<SelectTrigger
|
|
310
|
+
<SelectTrigger
|
|
311
|
+
aria-label="Rows per page"
|
|
312
|
+
className="w-[70px]"
|
|
313
|
+
size="sm"
|
|
314
|
+
>
|
|
297
315
|
<SelectValue
|
|
298
316
|
placeholder={`${table.getState().pagination.pageSize}`}
|
|
299
317
|
/>
|
|
@@ -308,59 +326,19 @@ function DataTablePagination<TData>({
|
|
|
308
326
|
</Select>
|
|
309
327
|
</div>
|
|
310
328
|
|
|
311
|
-
|
|
312
|
-
<p className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
329
|
+
<span className="text-body-small text-muted-foreground whitespace-nowrap">
|
|
313
330
|
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
|
314
331
|
{table.getPageCount()}
|
|
315
|
-
</
|
|
332
|
+
</span>
|
|
316
333
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
size="icon-sm"
|
|
326
|
-
variant="outline"
|
|
327
|
-
>
|
|
328
|
-
<ChevronsLeftIcon className="size-4" />
|
|
329
|
-
</Button>
|
|
330
|
-
<Button
|
|
331
|
-
aria-label="Go to previous page"
|
|
332
|
-
disabled={!table.getCanPreviousPage()}
|
|
333
|
-
onClick={() => {
|
|
334
|
-
table.previousPage();
|
|
335
|
-
}}
|
|
336
|
-
size="icon-sm"
|
|
337
|
-
variant="outline"
|
|
338
|
-
>
|
|
339
|
-
<ChevronLeftIcon className="size-4" />
|
|
340
|
-
</Button>
|
|
341
|
-
<Button
|
|
342
|
-
aria-label="Go to next page"
|
|
343
|
-
disabled={!table.getCanNextPage()}
|
|
344
|
-
onClick={() => {
|
|
345
|
-
table.nextPage();
|
|
346
|
-
}}
|
|
347
|
-
size="icon-sm"
|
|
348
|
-
variant="outline"
|
|
349
|
-
>
|
|
350
|
-
<ChevronRightIcon className="size-4" />
|
|
351
|
-
</Button>
|
|
352
|
-
<Button
|
|
353
|
-
aria-label="Go to last page"
|
|
354
|
-
disabled={!table.getCanNextPage()}
|
|
355
|
-
onClick={() => {
|
|
356
|
-
table.setPageIndex(table.getPageCount() - 1);
|
|
357
|
-
}}
|
|
358
|
-
size="icon-sm"
|
|
359
|
-
variant="outline"
|
|
360
|
-
>
|
|
361
|
-
<ChevronsRightIcon className="size-4" />
|
|
362
|
-
</Button>
|
|
363
|
-
</div>
|
|
334
|
+
<PaginationNavButtons
|
|
335
|
+
hasNext={table.getCanNextPage()}
|
|
336
|
+
hasPrev={table.getCanPreviousPage()}
|
|
337
|
+
onFirst={() => table.setPageIndex(0)}
|
|
338
|
+
onLast={() => table.setPageIndex(table.getPageCount() - 1)}
|
|
339
|
+
onNext={() => table.nextPage()}
|
|
340
|
+
onPrev={() => table.previousPage()}
|
|
341
|
+
/>
|
|
364
342
|
</div>
|
|
365
343
|
</div>
|
|
366
344
|
);
|
|
@@ -412,15 +390,38 @@ function DataTable<TData, TValue>({
|
|
|
412
390
|
className,
|
|
413
391
|
toolbar,
|
|
414
392
|
emptyText = "No results.",
|
|
393
|
+
manualPagination = false,
|
|
394
|
+
manualSorting = false,
|
|
395
|
+
manualFiltering = false,
|
|
396
|
+
pageCount,
|
|
397
|
+
rowCount,
|
|
398
|
+
sorting: controlledSorting,
|
|
399
|
+
pagination: controlledPagination,
|
|
400
|
+
columnFilters: controlledColumnFilters,
|
|
401
|
+
onSortingChange: onSortingChangeProp,
|
|
402
|
+
onPaginationChange: onPaginationChangeProp,
|
|
403
|
+
onColumnFiltersChange: onColumnFiltersChangeProp,
|
|
415
404
|
}: DataTableProps<TData, TValue>): ReactElement {
|
|
416
|
-
|
|
417
|
-
const [
|
|
405
|
+
// Internal state (used when not externally controlled)
|
|
406
|
+
const [internalSorting, setInternalSorting] = React.useState<SortingState>(
|
|
418
407
|
[],
|
|
419
408
|
);
|
|
409
|
+
const [internalColumnFilters, setInternalColumnFilters] =
|
|
410
|
+
React.useState<ColumnFiltersState>([]);
|
|
411
|
+
const [internalPagination, setInternalPagination] =
|
|
412
|
+
React.useState<PaginationState>({
|
|
413
|
+
pageIndex: 0,
|
|
414
|
+
pageSize: pageSizeOptions[0] ?? 10,
|
|
415
|
+
});
|
|
420
416
|
const [columnVisibility, setColumnVisibility] =
|
|
421
417
|
React.useState<VisibilityState>({});
|
|
422
418
|
const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({});
|
|
423
419
|
|
|
420
|
+
// Resolve controlled vs uncontrolled
|
|
421
|
+
const sorting = controlledSorting ?? internalSorting;
|
|
422
|
+
const columnFilters = controlledColumnFilters ?? internalColumnFilters;
|
|
423
|
+
const pagination = controlledPagination ?? internalPagination;
|
|
424
|
+
|
|
424
425
|
// Prepend selection column if enabled
|
|
425
426
|
const resolvedColumns = React.useMemo(() => {
|
|
426
427
|
if (!enableRowSelection) return userColumns;
|
|
@@ -438,9 +439,25 @@ function DataTable<TData, TValue>({
|
|
|
438
439
|
columnFilters,
|
|
439
440
|
columnVisibility,
|
|
440
441
|
rowSelection,
|
|
442
|
+
pagination,
|
|
443
|
+
},
|
|
444
|
+
onSortingChange: (updater) => {
|
|
445
|
+
const next = typeof updater === "function" ? updater(sorting) : updater;
|
|
446
|
+
if (controlledSorting === undefined) setInternalSorting(next);
|
|
447
|
+
onSortingChangeProp?.(next);
|
|
448
|
+
},
|
|
449
|
+
onColumnFiltersChange: (updater) => {
|
|
450
|
+
const next =
|
|
451
|
+
typeof updater === "function" ? updater(columnFilters) : updater;
|
|
452
|
+
if (controlledColumnFilters === undefined) setInternalColumnFilters(next);
|
|
453
|
+
onColumnFiltersChangeProp?.(next);
|
|
454
|
+
},
|
|
455
|
+
onPaginationChange: (updater) => {
|
|
456
|
+
const next =
|
|
457
|
+
typeof updater === "function" ? updater(pagination) : updater;
|
|
458
|
+
if (controlledPagination === undefined) setInternalPagination(next);
|
|
459
|
+
onPaginationChangeProp?.(next);
|
|
441
460
|
},
|
|
442
|
-
onSortingChange: setSorting,
|
|
443
|
-
onColumnFiltersChange: setColumnFilters,
|
|
444
461
|
onColumnVisibilityChange: setColumnVisibility,
|
|
445
462
|
onRowSelectionChange: (updater) => {
|
|
446
463
|
const next =
|
|
@@ -449,9 +466,17 @@ function DataTable<TData, TValue>({
|
|
|
449
466
|
onRowSelectionChange?.(next);
|
|
450
467
|
},
|
|
451
468
|
getCoreRowModel: getCoreRowModel(),
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
469
|
+
...(manualFiltering
|
|
470
|
+
? { manualFiltering: true as const }
|
|
471
|
+
: { getFilteredRowModel: getFilteredRowModel() }),
|
|
472
|
+
...(manualPagination
|
|
473
|
+
? { manualPagination: true as const }
|
|
474
|
+
: { getPaginationRowModel: getPaginationRowModel() }),
|
|
475
|
+
...(manualSorting
|
|
476
|
+
? { manualSorting: true as const }
|
|
477
|
+
: { getSortedRowModel: getSortedRowModel() }),
|
|
478
|
+
...(pageCount !== undefined && { pageCount }),
|
|
479
|
+
...(rowCount !== undefined && { rowCount }),
|
|
455
480
|
enableRowSelection,
|
|
456
481
|
});
|
|
457
482
|
|
|
@@ -539,11 +564,20 @@ function DataTable<TData, TValue>({
|
|
|
539
564
|
);
|
|
540
565
|
}
|
|
541
566
|
|
|
542
|
-
export {
|
|
567
|
+
export {
|
|
568
|
+
DataTable,
|
|
569
|
+
DataTableToolbar,
|
|
570
|
+
DataTablePagination,
|
|
571
|
+
DataTableSkeleton,
|
|
572
|
+
DataTableColumnHeader,
|
|
573
|
+
getSelectionColumn,
|
|
574
|
+
};
|
|
543
575
|
|
|
544
576
|
// Re-export tanstack types for consumer convenience
|
|
545
577
|
export type {
|
|
578
|
+
DataTableProps,
|
|
546
579
|
ColumnDef,
|
|
580
|
+
PaginationState,
|
|
547
581
|
SortingState,
|
|
548
582
|
ColumnFiltersState,
|
|
549
583
|
VisibilityState,
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { type ReactElement } from "react"
|
|
2
|
-
import * as React from "react"
|
|
3
|
-
import { format } from "date-fns"
|
|
4
|
-
import { CalendarIcon } from "lucide-react"
|
|
5
|
-
import { cn } from "@/lib/utils"
|
|
6
|
-
import { Button } from "@/components/ui/button"
|
|
7
|
-
import {
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { format } from "date-fns";
|
|
4
|
+
import { CalendarIcon } from "lucide-react";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { Input } from "@/components/ui/input";
|
|
8
|
+
import { Calendar } from "@/components/ui/calendar";
|
|
8
9
|
import {
|
|
9
10
|
Popover,
|
|
10
11
|
PopoverContent,
|
|
11
12
|
PopoverTrigger,
|
|
12
|
-
} from "@/components/ui/popover"
|
|
13
|
+
} from "@/components/ui/popover";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* DatePicker — WealthX Design System
|
|
@@ -22,18 +23,18 @@ import {
|
|
|
22
23
|
*/
|
|
23
24
|
|
|
24
25
|
export interface DatePickerProps {
|
|
25
|
-
value?: Date
|
|
26
|
-
onChange?: (date: Date | undefined) => void
|
|
27
|
-
placeholder?: string
|
|
26
|
+
value?: Date;
|
|
27
|
+
onChange?: (date: Date | undefined) => void;
|
|
28
|
+
placeholder?: string;
|
|
28
29
|
/** Show a time input below the calendar */
|
|
29
|
-
showTimePicker?: boolean
|
|
30
|
-
disabled?: boolean
|
|
31
|
-
className?: string
|
|
30
|
+
showTimePicker?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
className?: string;
|
|
32
33
|
/** Passed through to Calendar (e.g. fromYear, toYear, captionLayout) */
|
|
33
34
|
calendarProps?: Omit<
|
|
34
35
|
React.ComponentProps<typeof Calendar>,
|
|
35
36
|
"mode" | "selected" | "onSelect"
|
|
36
|
-
|
|
37
|
+
>;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
function DatePicker({
|
|
@@ -45,37 +46,37 @@ function DatePicker({
|
|
|
45
46
|
className,
|
|
46
47
|
calendarProps,
|
|
47
48
|
}: DatePickerProps): ReactElement {
|
|
48
|
-
const [open, setOpen] = React.useState(false)
|
|
49
|
+
const [open, setOpen] = React.useState(false);
|
|
49
50
|
|
|
50
51
|
function handleDaySelect(day: Date | undefined): void {
|
|
51
52
|
if (!day) {
|
|
52
|
-
onChange?.(undefined)
|
|
53
|
-
return
|
|
53
|
+
onChange?.(undefined);
|
|
54
|
+
return;
|
|
54
55
|
}
|
|
55
56
|
// Preserve existing time when selecting a new day
|
|
56
57
|
if (showTimePicker && value) {
|
|
57
|
-
day.setHours(value.getHours(), value.getMinutes())
|
|
58
|
+
day.setHours(value.getHours(), value.getMinutes());
|
|
58
59
|
}
|
|
59
|
-
onChange?.(day)
|
|
60
|
-
if (!showTimePicker) setOpen(false)
|
|
60
|
+
onChange?.(day);
|
|
61
|
+
if (!showTimePicker) setOpen(false);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
function handleTimeChange(e: React.ChangeEvent<HTMLInputElement>): void {
|
|
64
|
-
const [hours, minutes] = e.target.value.split(":").map(Number)
|
|
65
|
-
const next = value ? new Date(value) : new Date()
|
|
66
|
-
next.setHours(hours, minutes, 0, 0)
|
|
67
|
-
onChange?.(next)
|
|
65
|
+
const [hours, minutes] = e.target.value.split(":").map(Number);
|
|
66
|
+
const next = value ? new Date(value) : new Date();
|
|
67
|
+
next.setHours(hours, minutes, 0, 0);
|
|
68
|
+
onChange?.(next);
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
const timeValue = value
|
|
71
72
|
? `${String(value.getHours()).padStart(2, "0")}:${String(value.getMinutes()).padStart(2, "0")}`
|
|
72
|
-
: ""
|
|
73
|
+
: "";
|
|
73
74
|
|
|
74
|
-
let displayValue: string | undefined
|
|
75
|
+
let displayValue: string | undefined;
|
|
75
76
|
if (value && showTimePicker) {
|
|
76
|
-
displayValue = format(value, "dd/MM/yyyy HH:mm")
|
|
77
|
+
displayValue = format(value, "dd/MM/yyyy HH:mm");
|
|
77
78
|
} else if (value) {
|
|
78
|
-
displayValue = format(value, "dd/MM/yyyy")
|
|
79
|
+
displayValue = format(value, "dd/MM/yyyy");
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
return (
|
|
@@ -85,7 +86,9 @@ function DatePicker({
|
|
|
85
86
|
<Button
|
|
86
87
|
className={cn(
|
|
87
88
|
"w-full justify-start rounded-none font-normal data-[empty=true]:text-muted-foreground",
|
|
88
|
-
|
|
89
|
+
// Show open/focus state when the popover is expanded
|
|
90
|
+
"aria-expanded:border-ring aria-expanded:ring-2 aria-expanded:ring-ring/20",
|
|
91
|
+
className,
|
|
89
92
|
)}
|
|
90
93
|
data-empty={!value}
|
|
91
94
|
data-slot="date-picker-trigger"
|
|
@@ -109,23 +112,25 @@ function DatePicker({
|
|
|
109
112
|
{...calendarProps}
|
|
110
113
|
className={cn(
|
|
111
114
|
"rounded-none border-0 shadow-none",
|
|
112
|
-
calendarProps?.className
|
|
115
|
+
calendarProps?.className,
|
|
113
116
|
)}
|
|
114
117
|
/>
|
|
115
|
-
{showTimePicker ?
|
|
118
|
+
{showTimePicker ? (
|
|
119
|
+
<div className="border-t border-border px-3 pb-3 pt-2">
|
|
116
120
|
<label className="mb-1.5 block text-xs font-medium text-muted-foreground">
|
|
117
121
|
Time
|
|
118
|
-
<
|
|
119
|
-
className="mt-1.5 h-8
|
|
122
|
+
<Input
|
|
123
|
+
className="mt-1.5 h-8"
|
|
120
124
|
onChange={handleTimeChange}
|
|
121
125
|
type="time"
|
|
122
126
|
value={timeValue}
|
|
123
127
|
/>
|
|
124
128
|
</label>
|
|
125
|
-
</div>
|
|
129
|
+
</div>
|
|
130
|
+
) : null}
|
|
126
131
|
</PopoverContent>
|
|
127
132
|
</Popover>
|
|
128
|
-
)
|
|
133
|
+
);
|
|
129
134
|
}
|
|
130
135
|
|
|
131
|
-
export { DatePicker }
|
|
136
|
+
export { DatePicker };
|
|
@@ -68,10 +68,55 @@ function DialogOverlay({
|
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Maps the `size` prop to an exact CSS max-width value.
|
|
73
|
+
* Applied via inline style — bypasses Tailwind v4 class scanning entirely.
|
|
74
|
+
*/
|
|
75
|
+
const DIALOG_MAX_WIDTHS: Record<string, string> = {
|
|
76
|
+
sm: "24rem",
|
|
77
|
+
md: "28rem",
|
|
78
|
+
lg: "32rem",
|
|
79
|
+
xl: "36rem",
|
|
80
|
+
"2xl": "42rem",
|
|
81
|
+
"3xl": "48rem",
|
|
82
|
+
"4xl": "56rem",
|
|
83
|
+
full: "100%",
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Default minimum width for size="auto" dialogs.
|
|
88
|
+
* Prevents the dialog from collapsing too narrow when hugging content.
|
|
89
|
+
* Override per-instance via the `minWidth` prop.
|
|
90
|
+
*/
|
|
91
|
+
const DIALOG_AUTO_MIN_WIDTH = "20rem"; // 320px
|
|
92
|
+
|
|
71
93
|
export type DialogContentProps = React.ComponentProps<
|
|
72
94
|
typeof DialogPrimitive.Popup
|
|
73
95
|
> & {
|
|
74
96
|
showCloseButton?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Optional container element to render the Dialog portal into.
|
|
99
|
+
* Pass a ref'd element to scope the overlay inside a parent (e.g. a Sheet drawer)
|
|
100
|
+
* instead of appending to document.body.
|
|
101
|
+
*/
|
|
102
|
+
container?: HTMLElement | null;
|
|
103
|
+
/** Vertical alignment of the dialog. "top" anchors to top-4; "center" (default) vertically centers. */
|
|
104
|
+
align?: "center" | "top";
|
|
105
|
+
/**
|
|
106
|
+
* Width behaviour of the dialog panel.
|
|
107
|
+
* - Fixed sizes ("sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "full"):
|
|
108
|
+
* dialog fills width up to that maximum (applied via inline style — reliable in Tailwind v4).
|
|
109
|
+
* - "auto": dialog shrinks to fit its content (hug-content). Has a built-in minimum
|
|
110
|
+
* width of `DIALOG_AUTO_MIN_WIDTH` (20rem / 320px) to avoid collapsing too narrow.
|
|
111
|
+
* Defaults to "lg".
|
|
112
|
+
*/
|
|
113
|
+
size?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "full" | "auto";
|
|
114
|
+
/**
|
|
115
|
+
* Override the minimum width for `size="auto"` dialogs.
|
|
116
|
+
* Accepts any valid CSS length value (e.g. "24rem", "400px").
|
|
117
|
+
* Ignored when using a fixed size.
|
|
118
|
+
*/
|
|
119
|
+
minWidth?: string;
|
|
75
120
|
};
|
|
76
121
|
|
|
77
122
|
function DialogContent({
|
|
@@ -79,28 +124,47 @@ function DialogContent({
|
|
|
79
124
|
children,
|
|
80
125
|
showCloseButton = true,
|
|
81
126
|
style,
|
|
127
|
+
container,
|
|
128
|
+
align = "center",
|
|
129
|
+
size = "lg",
|
|
130
|
+
minWidth,
|
|
82
131
|
...props
|
|
83
132
|
}: DialogContentProps): ReactElement {
|
|
84
133
|
const themeVars = useThemeVars();
|
|
134
|
+
const isAuto = size === "auto";
|
|
135
|
+
|
|
136
|
+
const sizeStyle = isAuto
|
|
137
|
+
? { minWidth: minWidth ?? DIALOG_AUTO_MIN_WIDTH }
|
|
138
|
+
: { maxWidth: DIALOG_MAX_WIDTHS[size] };
|
|
139
|
+
|
|
85
140
|
return (
|
|
86
|
-
<DialogPortal>
|
|
141
|
+
<DialogPortal container={container ?? undefined}>
|
|
87
142
|
<DialogOverlay style={themeVars as React.CSSProperties} />
|
|
88
143
|
<DialogPrimitive.Popup
|
|
89
144
|
className={cn(
|
|
90
|
-
// WealthX: removed rounded-lg (sharp corners), shadow-lg (flat panels)
|
|
91
|
-
|
|
145
|
+
// WealthX: removed rounded-lg (sharp corners), shadow-lg (flat panels)
|
|
146
|
+
// max-w-[calc(100%-2rem)] acts as a viewport-edge guard on all sizes.
|
|
147
|
+
// Fixed max-width is applied via inline style (sizeStyle) to avoid
|
|
148
|
+
// Tailwind v4 class-scanning gaps with dynamic class lookups.
|
|
149
|
+
"fixed left-[50%] z-50 grid max-w-[calc(100%-2rem)] translate-x-[-50%] gap-4 border bg-background p-6 duration-200 outline-none data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-ending-style:fill-mode-forwards data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95",
|
|
150
|
+
// "auto" → hug content (with min-width floor); fixed sizes → fill to max-width
|
|
151
|
+
isAuto ? "w-auto" : "w-full",
|
|
152
|
+
align === "center"
|
|
153
|
+
? "top-[50%] translate-y-[-50%]"
|
|
154
|
+
: "top-4 translate-y-0",
|
|
92
155
|
className,
|
|
93
156
|
)}
|
|
94
157
|
data-slot="dialog-content"
|
|
95
|
-
style={{ ...themeVars, ...style } as React.CSSProperties}
|
|
158
|
+
style={{ ...themeVars, ...sizeStyle, ...style } as React.CSSProperties}
|
|
96
159
|
{...props}
|
|
97
160
|
>
|
|
98
161
|
{children}
|
|
99
162
|
{showCloseButton ? (
|
|
100
163
|
<DialogPrimitive.Close
|
|
101
|
-
className="absolute top-4 right-4 transition-colors hover:bg-foreground/5 focus:outline-hidden focus:ring-2 focus:ring-border focus:ring-offset-0 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
164
|
+
className="absolute top-4 right-4 inline-flex size-7 items-center justify-center transition-colors hover:bg-foreground/5 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border focus-visible:ring-offset-0 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
102
165
|
// WealthX: removed rounded-xs (sharp), replaced opacity fade with hover:bg-foreground/5,
|
|
103
|
-
// focus ring uses border color (subtle, matches Figma DialogClose focus state)
|
|
166
|
+
// focus ring uses border color (subtle, matches Figma DialogClose focus state).
|
|
167
|
+
// size-7 = 28px hit area (icon is size-4=16px, centered via inline-flex).
|
|
104
168
|
data-slot="dialog-close"
|
|
105
169
|
>
|
|
106
170
|
<XIcon />
|
|
@@ -152,6 +216,8 @@ function DialogFooter({
|
|
|
152
216
|
{showCloseButton ? (
|
|
153
217
|
<DialogPrimitive.Close
|
|
154
218
|
className={cn(buttonVariants({ variant: "outline" }))}
|
|
219
|
+
// type="button" prevents accidental form submission inside Dialog forms
|
|
220
|
+
type="button"
|
|
155
221
|
>
|
|
156
222
|
Close
|
|
157
223
|
</DialogPrimitive.Close>
|
|
@@ -30,7 +30,14 @@ import {
|
|
|
30
30
|
type ChartGranularity,
|
|
31
31
|
} from "./chart-shared";
|
|
32
32
|
|
|
33
|
-
ChartJS.register(
|
|
33
|
+
ChartJS.register(
|
|
34
|
+
CategoryScale,
|
|
35
|
+
LinearScale,
|
|
36
|
+
BarController,
|
|
37
|
+
BarElement,
|
|
38
|
+
Tooltip,
|
|
39
|
+
Legend,
|
|
40
|
+
);
|
|
34
41
|
|
|
35
42
|
// ---------------------------------------------------------------------------
|
|
36
43
|
// Types
|
|
@@ -234,7 +241,9 @@ export function ExpenseBarChart({
|
|
|
234
241
|
style={{ maxWidth: width, fontFamily }}
|
|
235
242
|
>
|
|
236
243
|
<CardHeader className="px-3 sm:px-6">
|
|
237
|
-
<CardTitle className="text-
|
|
244
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
245
|
+
{title}
|
|
246
|
+
</CardTitle>
|
|
238
247
|
<CardAction>
|
|
239
248
|
<div className="flex gap-0.5 sm:gap-1">
|
|
240
249
|
{periods.map((p) => (
|