@cryptlex/web-components 5.3.0 → 5.4.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/dist/components/{ui/alert.d.ts → alert.d.ts} +3 -3
- package/dist/components/alert.js +2 -0
- package/dist/components/alert.js.map +1 -0
- package/dist/components/{ui/avatar.d.ts → avatar.d.ts} +0 -1
- package/dist/components/avatar.js +2 -0
- package/dist/components/avatar.js.map +1 -0
- package/dist/components/{ui/badge.d.ts → badge.d.ts} +0 -1
- package/dist/components/badge.js +2 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/{ui/breadcrumbs.d.ts → breadcrumbs.d.ts} +1 -1
- package/dist/components/breadcrumbs.js +2 -0
- package/dist/components/breadcrumbs.js.map +1 -0
- package/dist/components/{ui/button.d.ts → button.d.ts} +5 -5
- package/dist/components/button.js +2 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/{ui/calendar.d.ts → calendar.d.ts} +2 -3
- package/dist/components/calendar.js +2 -0
- package/dist/components/calendar.js.map +1 -0
- package/dist/components/card.js +2 -0
- package/dist/components/card.js.map +1 -0
- package/dist/components/{inputs/checkbox.d.ts → checkbox.d.ts} +3 -3
- package/dist/components/checkbox.js +2 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/{data-table/table-commons.d.ts → data-table-commons.d.ts} +8 -8
- package/dist/components/data-table-commons.js +2 -0
- package/dist/components/data-table-commons.js.map +1 -0
- package/dist/components/{data-table/data-table-filter.d.ts → data-table-filter.d.ts} +3 -3
- package/dist/components/data-table-filter.js +2 -0
- package/dist/components/data-table-filter.js.map +1 -0
- package/dist/components/{data-table/data-table.d.ts → data-table.d.ts} +24 -25
- package/dist/components/data-table.js +2 -0
- package/dist/components/data-table.js.map +1 -0
- package/dist/components/{inputs/date-picker.d.ts → date-picker.d.ts} +3 -3
- package/dist/components/date-picker.js +2 -0
- package/dist/components/date-picker.js.map +1 -0
- package/dist/components/{inputs/datefield.d.ts → datefield.d.ts} +3 -3
- package/dist/components/datefield.js +2 -0
- package/dist/components/datefield.js.map +1 -0
- package/dist/components/{ui/dialog.d.ts → dialog.d.ts} +3 -4
- package/dist/components/dialog.js +2 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/{ui/disclosure.d.ts → disclosure.d.ts} +1 -2
- package/dist/components/disclosure.js +2 -0
- package/dist/components/disclosure.js.map +1 -0
- package/dist/components/{inputs/field.d.ts → field.d.ts} +5 -6
- package/dist/components/field.js +2 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/id-search.js +2 -0
- package/dist/components/id-search.js.map +1 -0
- package/dist/components/{inputs/input-otp.d.ts → input-otp.d.ts} +1 -2
- package/dist/components/input-otp.js +2 -0
- package/dist/components/input-otp.js.map +1 -0
- package/dist/components/key-value-card.js +2 -0
- package/dist/components/key-value-card.js.map +1 -0
- package/dist/components/{ui/list-box.d.ts → list-box.d.ts} +1 -1
- package/dist/components/list-box.js +2 -0
- package/dist/components/list-box.js.map +1 -0
- package/dist/components/loader.js +2 -0
- package/dist/components/loader.js.map +1 -0
- package/dist/components/{ui/menu.d.ts → menu.d.ts} +5 -6
- package/dist/components/menu.js +2 -0
- package/dist/components/menu.js.map +1 -0
- package/dist/components/{inputs/multi-select.d.ts → multi-select.d.ts} +3 -4
- package/dist/components/multi-select.js +2 -0
- package/dist/components/multi-select.js.map +1 -0
- package/dist/components/{inputs/numberfield.d.ts → numberfield.d.ts} +2 -3
- package/dist/components/numberfield.js +2 -0
- package/dist/components/numberfield.js.map +1 -0
- package/dist/components/{ui/popover.d.ts → popover.d.ts} +1 -1
- package/dist/components/popover.js +2 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/{inputs/searchfield.d.ts → searchfield.d.ts} +2 -2
- package/dist/components/searchfield.js +2 -0
- package/dist/components/searchfield.js.map +1 -0
- package/dist/components/select-options.js +2 -0
- package/dist/components/select-options.js.map +1 -0
- package/dist/components/{inputs/select.d.ts → select.d.ts} +5 -5
- package/dist/components/select.js +2 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/{ui/sidebar.d.ts → sidebar.d.ts} +4 -5
- package/dist/components/sidebar.js +2 -0
- package/dist/components/sidebar.js.map +1 -0
- package/dist/components/skeleton.js +2 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/{ui/sonner.d.ts → sonner.d.ts} +1 -1
- package/dist/components/sonner.js +2 -0
- package/dist/components/sonner.js.map +1 -0
- package/dist/components/table-of-contents.d.ts +9 -0
- package/dist/components/table-of-contents.js +2 -0
- package/dist/components/table-of-contents.js.map +1 -0
- package/dist/components/{ui/table.d.ts → table.d.ts} +0 -1
- package/dist/components/table.js +2 -0
- package/dist/components/table.js.map +1 -0
- package/dist/components/{ui/tabs.d.ts → tabs.d.ts} +1 -1
- package/dist/components/tabs.js +2 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/{inputs/textfield.d.ts → textfield.d.ts} +2 -2
- package/dist/components/textfield.js +2 -0
- package/dist/components/textfield.js.map +1 -0
- package/dist/components/{ui/timeline.d.ts → timeline.d.ts} +3 -3
- package/dist/components/timeline.js +2 -0
- package/dist/components/timeline.js.map +1 -0
- package/dist/components/{ui/tooltip.d.ts → tooltip.d.ts} +1 -1
- package/dist/components/tooltip.js +2 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/utils/form-context.d.ts +1 -1
- package/dist/utils/form-context.js +2 -5
- package/dist/utils/form-context.js.map +1 -0
- package/dist/utils/form-hook.d.ts +9 -11
- package/dist/utils/form-hook.js +2 -30
- package/dist/utils/form-hook.js.map +1 -0
- package/dist/utils/primitives.d.ts +16 -2
- package/dist/utils/primitives.js +2 -39
- package/dist/utils/primitives.js.map +1 -0
- package/dist/utils/resource-names.d.ts +1 -13
- package/dist/utils/resource-names.js +2 -212
- package/dist/utils/resource-names.js.map +1 -0
- package/dist/utils/use-mobile.js +2 -15
- package/dist/utils/use-mobile.js.map +1 -0
- package/lib/utilities.css +1 -1
- package/package.json +13 -12
- package/dist/components/data-table/data-table-filter.js +0 -112
- package/dist/components/data-table/data-table.js +0 -265
- package/dist/components/data-table/table-commons.js +0 -137
- package/dist/components/inputs/checkbox.js +0 -25
- package/dist/components/inputs/date-picker.js +0 -22
- package/dist/components/inputs/datefield.js +0 -25
- package/dist/components/inputs/field.js +0 -48
- package/dist/components/inputs/id-search.js +0 -40
- package/dist/components/inputs/input-otp.js +0 -19
- package/dist/components/inputs/multi-select.js +0 -18
- package/dist/components/inputs/numberfield.js +0 -25
- package/dist/components/inputs/searchfield.js +0 -24
- package/dist/components/inputs/select-options.js +0 -286
- package/dist/components/inputs/select.js +0 -34
- package/dist/components/inputs/textfield.js +0 -28
- package/dist/components/key-value-card/key-value-card.js +0 -40
- package/dist/components/ui/alert.js +0 -18
- package/dist/components/ui/avatar.js +0 -5
- package/dist/components/ui/badge.js +0 -5
- package/dist/components/ui/breadcrumbs.js +0 -28
- package/dist/components/ui/button.js +0 -34
- package/dist/components/ui/calendar.js +0 -63
- package/dist/components/ui/card.js +0 -20
- package/dist/components/ui/dialog.js +0 -42
- package/dist/components/ui/disclosure.js +0 -20
- package/dist/components/ui/list-box.js +0 -24
- package/dist/components/ui/loader.js +0 -6
- package/dist/components/ui/menu.js +0 -38
- package/dist/components/ui/popover.js +0 -14
- package/dist/components/ui/sidebar.js +0 -177
- package/dist/components/ui/skeleton.js +0 -5
- package/dist/components/ui/sonner.js +0 -14
- package/dist/components/ui/table.js +0 -26
- package/dist/components/ui/tabs.js +0 -25
- package/dist/components/ui/timeline.js +0 -31
- package/dist/components/ui/tooltip.js +0 -12
- /package/dist/components/{ui/card.d.ts → card.d.ts} +0 -0
- /package/dist/components/{inputs/id-search.d.ts → id-search.d.ts} +0 -0
- /package/dist/components/{key-value-card/key-value-card.d.ts → key-value-card.d.ts} +0 -0
- /package/dist/components/{ui/loader.d.ts → loader.d.ts} +0 -0
- /package/dist/components/{inputs/select-options.d.ts → select-options.d.ts} +0 -0
- /package/dist/components/{ui/skeleton.d.ts → skeleton.d.ts} +0 -0
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { keepPreviousData, useQuery } from "@tanstack/react-query";
|
|
4
|
-
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
|
5
|
-
import { ArrowDownNarrowWide, ArrowDownWideNarrow, ArrowUpDown, Columns3, GripVertical, Info } from "lucide-react";
|
|
6
|
-
import { createContext, useContext, useEffect, useId, useMemo, useState } from "react";
|
|
7
|
-
/** Reserved name for actions column */
|
|
8
|
-
export const ACTIONS_COLUMN_ID = "tableActions";
|
|
9
|
-
/**
|
|
10
|
-
* Hook for handling all data-table state. Used in DataTableContext
|
|
11
|
-
*/
|
|
12
|
-
export function useDataTableState({ columns, fetchFn, columnsToHideByDefault = {}, allowSelection = false, filterConfig }) {
|
|
13
|
-
const id = useId();
|
|
14
|
-
// TODO: Would it be better for this state to be more granular?
|
|
15
|
-
const [tableState, _setTableState] = useState({
|
|
16
|
-
/** TODO Reflect in URL */
|
|
17
|
-
pagination: { pageIndex: 0, pageSize: 20 }, // Pagination state
|
|
18
|
-
sorting: [], // Sorting state
|
|
19
|
-
/** Ephemeral */
|
|
20
|
-
rowSelection: {}, // Row selection state
|
|
21
|
-
});
|
|
22
|
-
/** TODO Reflect in URL */
|
|
23
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
24
|
-
/** TODO Store on browser as preference */
|
|
25
|
-
const [columnOrder, setColumnOrder] = useState([]);
|
|
26
|
-
// TODO Store on browser
|
|
27
|
-
const [columnVisibility, setColumnVisibility] = useState({
|
|
28
|
-
id: false,
|
|
29
|
-
updatedAt: false,
|
|
30
|
-
...columnsToHideByDefault,
|
|
31
|
-
});
|
|
32
|
-
const [filters, setFilters] = useState([]);
|
|
33
|
-
const mergedFilters = useMemo(() => {
|
|
34
|
-
return filters.reduce((acc, current) => {
|
|
35
|
-
return merge(acc, current);
|
|
36
|
-
}, {});
|
|
37
|
-
}, [filters]);
|
|
38
|
-
// Update table state with new values
|
|
39
|
-
const updateTableState = (updates) => {
|
|
40
|
-
_setTableState((prev) => ({ ...prev, ...updates }));
|
|
41
|
-
};
|
|
42
|
-
const { sorting, rowSelection, pagination, } = tableState;
|
|
43
|
-
const query = useQuery({
|
|
44
|
-
queryKey: [id, pagination, sorting, searchQuery],
|
|
45
|
-
queryFn: () => fetchFn(pagination, sorting, searchQuery, mergedFilters),
|
|
46
|
-
placeholderData: keepPreviousData, // Keep previous data while loading new data
|
|
47
|
-
retry: 0,
|
|
48
|
-
refetchOnWindowFocus: false,
|
|
49
|
-
});
|
|
50
|
-
useEffect(() => {
|
|
51
|
-
// TODO, store in localStorage
|
|
52
|
-
}, [columnVisibility]);
|
|
53
|
-
const columnHelper = useMemo(() => createColumnHelper(), []);
|
|
54
|
-
const metadataColumns = useMemo(() => {
|
|
55
|
-
const data = query.data?.data;
|
|
56
|
-
if (!data?.length)
|
|
57
|
-
return [];
|
|
58
|
-
const rowHasMetadata = (row) => row != null &&
|
|
59
|
-
typeof row === 'object' &&
|
|
60
|
-
'metadata' in row &&
|
|
61
|
-
Array.isArray((row).metadata);
|
|
62
|
-
const rowsWithMeta = data.filter(rowHasMetadata);
|
|
63
|
-
if (rowsWithMeta.length === 0)
|
|
64
|
-
return [];
|
|
65
|
-
const keys = Array.from(new Set(rowsWithMeta.flatMap(r => r.metadata?.map(m => m.key) ?? [])));
|
|
66
|
-
return keys.map(key => columnHelper.accessor((row) => {
|
|
67
|
-
if (rowHasMetadata(row)) {
|
|
68
|
-
return row?.metadata?.find(m => m.key === key)?.value ?? '';
|
|
69
|
-
}
|
|
70
|
-
return '';
|
|
71
|
-
}, {
|
|
72
|
-
id: key,
|
|
73
|
-
header: key, // tooltip header
|
|
74
|
-
enableSorting: false,
|
|
75
|
-
cell: (info) => {
|
|
76
|
-
const value = info.getValue();
|
|
77
|
-
// Handle null/undefined values
|
|
78
|
-
if (value === null || value === undefined)
|
|
79
|
-
return "";
|
|
80
|
-
// For primitive types, return the string representation
|
|
81
|
-
return String(value);
|
|
82
|
-
},
|
|
83
|
-
}));
|
|
84
|
-
}, [query.data?.data]);
|
|
85
|
-
/**
|
|
86
|
-
* ID,createdAt and updatedAt will be added by default for all tables
|
|
87
|
-
* If selection is allowed, checkbox will be added
|
|
88
|
-
* If the dto has metadata, dynamics columns for all the metadata key-value will be added(particular for a view)
|
|
89
|
-
* If there are actions for the table, they will be placed fixed at the right side of table.
|
|
90
|
-
*/
|
|
91
|
-
const cols = [
|
|
92
|
-
...(allowSelection ? TABLE_CHECK_BOX_COLUMN : []),
|
|
93
|
-
...TABLE_ID_COLUMN,
|
|
94
|
-
...columns.filter((col) => col.id !== ACTIONS_COLUMN_ID),
|
|
95
|
-
...(metadataColumns.length ? metadataColumns : []),
|
|
96
|
-
...TABLE_DEFAULT_DATE_COLUMNS,
|
|
97
|
-
// Actions column
|
|
98
|
-
...columns.filter((col) => col.id === ACTIONS_COLUMN_ID),
|
|
99
|
-
];
|
|
100
|
-
// Type-guard for updater
|
|
101
|
-
function isUpdaterFunction(updater) {
|
|
102
|
-
return typeof updater === "function";
|
|
103
|
-
}
|
|
104
|
-
// Utility function to resolve updater
|
|
105
|
-
function resolveUpdater(updater, currentValue) {
|
|
106
|
-
if (isUpdaterFunction(updater)) {
|
|
107
|
-
return updater(currentValue);
|
|
108
|
-
}
|
|
109
|
-
return updater;
|
|
110
|
-
}
|
|
111
|
-
// Use react-table's hook to create the table instance
|
|
112
|
-
const tanTable = useReactTable({
|
|
113
|
-
data: query.data?.data ?? [],
|
|
114
|
-
columns: cols,
|
|
115
|
-
getCoreRowModel: getCoreRowModel(),
|
|
116
|
-
rowCount: query.data?.total,
|
|
117
|
-
manualPagination: true, // Handle pagination manually since pagination is done server side for data tables
|
|
118
|
-
onPaginationChange: (updater) => {
|
|
119
|
-
updateTableState({ pagination: resolveUpdater(updater, pagination) });
|
|
120
|
-
},
|
|
121
|
-
manualSorting: true, // Handle sorting manually since sorting is done server side for data tables
|
|
122
|
-
onSortingChange: (updater) => {
|
|
123
|
-
updateTableState({ sorting: [...resolveUpdater(updater, sorting)], rowSelection: {} }); // Reset selection when sorting.
|
|
124
|
-
},
|
|
125
|
-
manualFiltering: true, // Handle filtering manually since filtering is done server side for data tables
|
|
126
|
-
onColumnVisibilityChange: (updater) => {
|
|
127
|
-
setColumnVisibility(resolveUpdater(updater, columnVisibility));
|
|
128
|
-
},
|
|
129
|
-
onRowSelectionChange: (updater) => {
|
|
130
|
-
updateTableState({ rowSelection: resolveUpdater(updater, rowSelection) });
|
|
131
|
-
},
|
|
132
|
-
onColumnOrderChange: (updater) => {
|
|
133
|
-
setColumnOrder(resolveUpdater(updater, columnOrder));
|
|
134
|
-
},
|
|
135
|
-
state: {
|
|
136
|
-
sorting: sorting,
|
|
137
|
-
columnVisibility: columnVisibility,
|
|
138
|
-
pagination: pagination,
|
|
139
|
-
rowSelection: rowSelection,
|
|
140
|
-
columnOrder: columnOrder
|
|
141
|
-
},
|
|
142
|
-
meta: {
|
|
143
|
-
refetch: query.refetch,
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
// By default, ColumnDef does not give guarantees of column.id existing. Once useReactTable is called, all columns are assigned IDs.
|
|
147
|
-
// This populates the columnIds in the columnOrder state
|
|
148
|
-
// TODO, add localStorage access layer for this.
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
setColumnOrder([...tanTable.getAllLeafColumns().map(c => c.id)]);
|
|
151
|
-
}, []);
|
|
152
|
-
return { tableState, updateTableState, query, setSearchQuery, searchQuery, tanTable, mergedFilters, filters, setFilters, filterConfig };
|
|
153
|
-
}
|
|
154
|
-
export const DataTableContext = createContext(null);
|
|
155
|
-
export const useDataTable = () => {
|
|
156
|
-
const ctx = useContext(DataTableContext);
|
|
157
|
-
if (!ctx) {
|
|
158
|
-
throw Error("DataTable should be used within DataTableProvider.");
|
|
159
|
-
}
|
|
160
|
-
return ctx;
|
|
161
|
-
};
|
|
162
|
-
export function DataTableProvider({ children, ...props }) {
|
|
163
|
-
return (_jsx(DataTableContext.Provider, { value: props, children: children }));
|
|
164
|
-
}
|
|
165
|
-
export function DataTable({ tableActions, className, ...props
|
|
166
|
-
// filterableFields,
|
|
167
|
-
}) {
|
|
168
|
-
// State for managing table data and filters
|
|
169
|
-
const { query, tanTable } = useDataTable();
|
|
170
|
-
return (_jsx(_Fragment, { children: _jsxs("section", { ...props, className: cn("flex flex-col bg-card", className), children: [_jsx(Actions, { tableActions: tableActions }), _jsxs("div", { className: "w-full overflow-auto border-x grow min-h-table relative", tabIndex: 0, children: [query.isLoading && (_jsx(TableOverlay, { className: "cursor-wait", children: _jsx(Loader, {}) })), !query.isLoading && tanTable.getRowModel().rows.length === 0 && (
|
|
171
|
-
// Empty table
|
|
172
|
-
_jsx(TableOverlay, { className: "cursor-not-allowed", children: !query.isFetching &&
|
|
173
|
-
(query.isError ? (_jsxs("span", { className: "flex gap-3 justify-center items-center", children: [_jsx(Info, {}), _jsx("span", { children: "You don't have the required permissions. Please contact your admin." })] })) : !query.data?.data ? (_jsx(_Fragment, { children: "No results found." })) : (_jsx(_Fragment, { children: "Unknown error. Please contact customer support." }))) })), !query.isLoading && tanTable.getRowModel().rows.length !== 0 &&
|
|
174
|
-
_jsx(TableContent, { className: "size-full" })] }), _jsxs("div", { className: "flex w-full justify-between border gap-icon p-icon overflow-x-auto", children: [_jsxs("div", { className: "flex gap-icon", children: [_jsx(ColumnPicker, {}), _jsx(PageSize, {})] }), _jsx(Paginator, {})] })] }) }));
|
|
175
|
-
}
|
|
176
|
-
/** Table overlay to be shown for loaders or other messages */
|
|
177
|
-
function TableOverlay({ children, className, }) {
|
|
178
|
-
return (_jsxs(_Fragment, { children: [_jsx("span", { className: cn(className, "absolute top-0 bg-card z-20 size-full text-sm flex items-center justify-center"), children: children }), _jsx("span", { className: "relative h-full w-0 block" })] }));
|
|
179
|
-
}
|
|
180
|
-
import { arrayMove, SortableContext, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
181
|
-
function ColumnPicker() {
|
|
182
|
-
const { tanTable } = useDataTable();
|
|
183
|
-
const [activeId, setActiveId] = useState(null);
|
|
184
|
-
const resourceFormatter = useResourceFormatter();
|
|
185
|
-
const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
|
|
186
|
-
coordinateGetter: sortableKeyboardCoordinates,
|
|
187
|
-
}));
|
|
188
|
-
return (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragStart: (event) => {
|
|
189
|
-
const { active } = event;
|
|
190
|
-
setActiveId(active.id.toString());
|
|
191
|
-
}, onDragEnd: (event) => {
|
|
192
|
-
const { active, over } = event;
|
|
193
|
-
if (over && active.id !== over.id) {
|
|
194
|
-
const columnOrder = tanTable.getState().columnOrder;
|
|
195
|
-
const oldIndex = columnOrder.indexOf(active.id.toString());
|
|
196
|
-
const newIndex = columnOrder.indexOf(over.id.toString());
|
|
197
|
-
tanTable.setColumnOrder([...arrayMove(columnOrder, oldIndex, newIndex)]);
|
|
198
|
-
}
|
|
199
|
-
setActiveId(null);
|
|
200
|
-
}, children: _jsxs(SortableContext, { items: tanTable.getState().columnOrder, strategy: verticalListSortingStrategy, children: [_jsxs(EasyMenu, { label: _jsxs(_Fragment, { children: [_jsx(Columns3, {}), "Columns"] }), selectionMode: "multiple", items: tanTable.getAllFlatColumns(), selectedKeys: tanTable.getIsAllColumnsVisible() ? 'all' : tanTable.getVisibleFlatColumns().map(c => c.id), children: [_jsx(MenuItem, { onAction: () => tanTable.toggleAllColumnsVisible(), className: 'italic', children: "(select all)" }), tanTable.getState().columnOrder.map(colId => {
|
|
201
|
-
const col = tanTable.getAllFlatColumns().find(c => c.id === colId);
|
|
202
|
-
if (!col)
|
|
203
|
-
return null;
|
|
204
|
-
return _jsx(SortableItem, { column: col }, col.id);
|
|
205
|
-
})] }), _jsx(DragOverlay, { children: activeId ? _jsx("div", { className: "dropdown-item opacity-70 border-2 border-primary", children: resourceFormatter(activeId) }) : null })] }) }));
|
|
206
|
-
function SortableItem({ column }) {
|
|
207
|
-
const { attributes, listeners, setNodeRef, transform, transition, } = useSortable({ id: column.id });
|
|
208
|
-
const style = {
|
|
209
|
-
transform: CSS.Transform.toString(transform),
|
|
210
|
-
transition,
|
|
211
|
-
zIndex: '999'
|
|
212
|
-
};
|
|
213
|
-
return _jsxs(MenuItem, { ref: setNodeRef, style: style, ...attributes, id: column.id, onAction: () => column.toggleVisibility(), isDisabled: !column.getCanHide(), className: "flex items-center", children: [_jsx(GripVertical, { ...listeners, className: "size-icon cursor-grab" }), resourceFormatter(column.id), column.getIsSorted() && _jsx(SortIcon, { className: "size-icon", direction: column.getIsSorted() })] });
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
import { ChevronFirst, ChevronLast, ChevronLeft, ChevronRight, } from "lucide-react";
|
|
217
|
-
function Paginator() {
|
|
218
|
-
const { tanTable, query } = useDataTable();
|
|
219
|
-
const rowCount = query.data?.total ?? 0;
|
|
220
|
-
return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "whitespace-nowrap caption text-muted", children: `${tanTable.getState().pagination.pageIndex * tanTable.getState().pagination.pageSize + 1} - ${Math.min((tanTable.getState().pagination.pageIndex + 1) *
|
|
221
|
-
tanTable.getState().pagination.pageSize, rowCount)} of ${rowCount?.toLocaleString()}` }), _jsx(Button, { onPress: () => tanTable.firstPage(), isDisabled: !tanTable.getCanPreviousPage(), variant: "neutral", size: "icon", children: _jsx(ChevronFirst, {}) }), _jsx(Button, { onPress: () => tanTable.previousPage(), isDisabled: !tanTable.getCanPreviousPage(), variant: "neutral", size: "icon", children: _jsx(ChevronLeft, {}) }), _jsx(Button, { onPress: () => tanTable.nextPage(), isDisabled: !tanTable.getCanNextPage(), variant: "neutral", size: "icon", children: _jsx(ChevronRight, {}) }), _jsx(Button, { onClick: () => tanTable.lastPage(), isDisabled: !tanTable.getCanNextPage(), variant: "neutral", size: "icon", children: _jsx(ChevronLast, {}) })] }));
|
|
222
|
-
}
|
|
223
|
-
function PageSize() {
|
|
224
|
-
const { tanTable } = useDataTable();
|
|
225
|
-
const PAGE_SIZES = [10, 20, 30, 40, 50];
|
|
226
|
-
return (_jsx(EasyMenu, { label: tanTable.getState().pagination.pageSize.toString(), selectionMode: "single", selectedKeys: [tanTable.getState().pagination.pageSize.toString()], items: PAGE_SIZES.map(s => ({ id: s.toString(), value: s })), children: (items) => _jsx(MenuItem, { onAction: () => tanTable.setPageSize(items.value), children: items.value }) }));
|
|
227
|
-
}
|
|
228
|
-
import { RotateCw } from "lucide-react";
|
|
229
|
-
function Actions({ tableActions }) {
|
|
230
|
-
const { query, tanTable, searchQuery, setSearchQuery } = useDataTable();
|
|
231
|
-
return (_jsxs("section", { className: "flex bg-card justify-between my-0 p-icon border gap-icon overflow-auto", children: [_jsxs("div", { className: "flex gap-icon", children: [_jsx(Button, { isPending: query.isFetching, onClick: () => query.refetch(), variant: "neutral", size: "icon", children: _jsx(RotateCw, {}) }), tableActions
|
|
232
|
-
.filter(ta => ta.bulk === tanTable.getSelectedRowModel().rows.length > 0)
|
|
233
|
-
.map((ta, i) => {
|
|
234
|
-
const Icon = ta.icon;
|
|
235
|
-
return (_jsx(Button, { type: "button", isDisabled: query.isFetching, className: "animate-in fade-in slide-in-from-left-15 duration-300 transition-transform", onPress: (e) => { ta.onClick(e, tanTable); }, size: 'icon', children: _jsx(Icon, {}) }, `${i}-${ta.bulk}`));
|
|
236
|
-
})] }), _jsxs("div", { className: "flex gap-icon", children: [_jsx(DataTableFilter, {}), (_jsx(SearchField, { value: searchQuery, onChange: setSearchQuery }))] })] }));
|
|
237
|
-
}
|
|
238
|
-
import { closestCenter, DndContext, DragOverlay, KeyboardSensor, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
|
|
239
|
-
import { CSS } from "@dnd-kit/utilities";
|
|
240
|
-
import { flexRender } from "@tanstack/react-table";
|
|
241
|
-
import { DataTableFilter } from "lib/components/data-table/data-table-filter";
|
|
242
|
-
import { TABLE_CHECK_BOX_COLUMN, TABLE_DEFAULT_DATE_COLUMNS, TABLE_ID_COLUMN } from "lib/components/data-table/table-commons";
|
|
243
|
-
import { SearchField } from "lib/components/inputs/searchfield";
|
|
244
|
-
import { Button } from "lib/components/ui/button";
|
|
245
|
-
import { Loader } from "lib/components/ui/loader";
|
|
246
|
-
import { EasyMenu, MenuItem } from "lib/components/ui/menu";
|
|
247
|
-
import { TableBody, TableCell, Table as TableComponent, TableHead, TableHeader, TableRow, } from "lib/components/ui/table";
|
|
248
|
-
import { cn } from "lib/utils/primitives";
|
|
249
|
-
import { useResourceFormatter } from "lib/utils/resource-names";
|
|
250
|
-
import { merge } from "lodash-es";
|
|
251
|
-
function SortIcon({ direction, ...props }) {
|
|
252
|
-
if (direction === 'asc')
|
|
253
|
-
return _jsx(ArrowDownNarrowWide, { ...props });
|
|
254
|
-
else if (direction === 'desc')
|
|
255
|
-
return _jsx(ArrowDownWideNarrow, { ...props });
|
|
256
|
-
else
|
|
257
|
-
return _jsx(ArrowUpDown, { ...props });
|
|
258
|
-
}
|
|
259
|
-
// TODO, automate checking valid HTML
|
|
260
|
-
function TableContent({ className }) {
|
|
261
|
-
const { tanTable } = useDataTable();
|
|
262
|
-
const tableCellStyle = (isSticky, className) => cn("animate-in fade-in slide-in-from-top-10", "px-icon py-2 text-left text-sm font-medium whitespace-nowrap", isSticky && "bg-card sticky right-0 z-50 text-center", className);
|
|
263
|
-
return (_jsxs(TableComponent, { className: cn(className), children: [_jsx(TableHeader, { className: "sticky top-0 z-10", children: tanTable.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { className: cn("h-input"), children: headerGroup.headers.map((header) => (_jsxs(TableHead, { className: tableCellStyle(false, "bg-card"), children: [!header.column.getCanSort() && !header.isPlaceholder
|
|
264
|
-
&& _jsx(_Fragment, { children: flexRender(header.column.columnDef.header, header.getContext()) }), header.column.getCanSort() && (_jsxs(Button, { variant: "ghost", className: "w-full !justify-start !px-1.5", onPress: header.column.getToggleSortingHandler(), children: [flexRender(header.column.columnDef.header, header.getContext()), _jsx(SortIcon, { direction: header.column.getIsSorted() })] }))] }, header.id))) }, headerGroup.id))) }), _jsx(TableBody, { className: "flex-1 overflow-y-auto relative", children: tanTable.getRowModel().rows.map((row) => (_jsx(TableRow, { className: cn("h-input transition-colors data-[selected=true]:bg-primary/10 hover:bg-muted-foreground/20"), "data-selected": row.getIsSelected(), children: row.getVisibleCells().map((cell) => (_jsx(TableCell, { className: tableCellStyle(cell.column.id === ACTIONS_COLUMN_ID), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id))) })] }));
|
|
265
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createColumnHelper } from "@tanstack/react-table";
|
|
3
|
-
import { Checkbox } from "lib/components/inputs/checkbox";
|
|
4
|
-
const cH = createColumnHelper();
|
|
5
|
-
export const TABLE_CHECK_BOX_COLUMN = [
|
|
6
|
-
cH.accessor("checkbox", {
|
|
7
|
-
header: ({ table }) => (_jsx(Checkbox, { isIndeterminate: table.getIsSomeRowsSelected() && !table.getIsAllPageRowsSelected(), isSelected: table.getIsAllPageRowsSelected() || table.getIsSomePageRowsSelected(), onChange: () => table.toggleAllPageRowsSelected(), "aria-label": "Select all" })),
|
|
8
|
-
cell: ({ row }) => (_jsx(Checkbox, { isSelected: row.getIsSelected(), onChange: () => row.toggleSelected(), "aria-label": "Select row" })),
|
|
9
|
-
enableSorting: false,
|
|
10
|
-
enableHiding: false,
|
|
11
|
-
}),
|
|
12
|
-
];
|
|
13
|
-
export const TABLE_ID_COLUMN = [
|
|
14
|
-
cH.accessor("id", {
|
|
15
|
-
header: () => "ID",
|
|
16
|
-
}),
|
|
17
|
-
];
|
|
18
|
-
export const TABLE_DEFAULT_DATE_COLUMNS = [
|
|
19
|
-
cH.accessor("createdAt", {
|
|
20
|
-
header: () => "Creation Date",
|
|
21
|
-
cell: ({ row }) => {
|
|
22
|
-
const date = row.getValue("createdAt");
|
|
23
|
-
return formatDate(date);
|
|
24
|
-
},
|
|
25
|
-
enableHiding: false,
|
|
26
|
-
}),
|
|
27
|
-
cH.accessor("updatedAt", {
|
|
28
|
-
header: () => "Last Updated",
|
|
29
|
-
cell: ({ row }) => {
|
|
30
|
-
const date = row.getValue("updatedAt");
|
|
31
|
-
return formatDate(date);
|
|
32
|
-
},
|
|
33
|
-
enableHiding: false,
|
|
34
|
-
}),
|
|
35
|
-
];
|
|
36
|
-
// TODO, i18n
|
|
37
|
-
export function formatDate(date) {
|
|
38
|
-
if (!date)
|
|
39
|
-
return null;
|
|
40
|
-
const _date = new Date(date);
|
|
41
|
-
return new Intl.DateTimeFormat(undefined, {
|
|
42
|
-
dateStyle: "medium",
|
|
43
|
-
timeStyle: "short",
|
|
44
|
-
}).format(_date);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Format multiple license parameters (expired, suspended, revoked) into a single status
|
|
48
|
-
*/
|
|
49
|
-
export function getLicenseStatus(license) {
|
|
50
|
-
const licenseExpired = license.expiresAt && new Date(license.expiresAt) < new Date();
|
|
51
|
-
// Status Column
|
|
52
|
-
switch (true) {
|
|
53
|
-
case license.revoked && license.suspended && licenseExpired:
|
|
54
|
-
return "Revoked, Suspended, Expired";
|
|
55
|
-
case license.revoked && license.suspended:
|
|
56
|
-
return "Revoked, Suspended";
|
|
57
|
-
case license.revoked && licenseExpired:
|
|
58
|
-
return "Revoked, Expired";
|
|
59
|
-
case license.suspended && licenseExpired:
|
|
60
|
-
return "Suspended, Expired";
|
|
61
|
-
case license.suspended:
|
|
62
|
-
return "Suspended";
|
|
63
|
-
case license.revoked:
|
|
64
|
-
return "Revoked";
|
|
65
|
-
case licenseExpired:
|
|
66
|
-
return "Expired";
|
|
67
|
-
default:
|
|
68
|
-
return "Active";
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
export function getValidityDisplay(validity) {
|
|
72
|
-
if (validity === 0 || !validity) {
|
|
73
|
-
return "Lifetime";
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
return secondsToDuration(validity);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
export function secondsToDuration(seconds) {
|
|
80
|
-
//@ts-ignore
|
|
81
|
-
const duration = intervalToDuration({
|
|
82
|
-
start: 0,
|
|
83
|
-
end: seconds * 1000,
|
|
84
|
-
});
|
|
85
|
-
const parts = [
|
|
86
|
-
duration.years && `${duration.years}y`,
|
|
87
|
-
duration.months && `${duration.months}m`,
|
|
88
|
-
duration.days && `${duration.days}d`,
|
|
89
|
-
duration.hours && `${duration.hours}h`,
|
|
90
|
-
];
|
|
91
|
-
// Filter out undefined values and join
|
|
92
|
-
return parts.filter(Boolean).join(" ").trim();
|
|
93
|
-
}
|
|
94
|
-
export function getValueFromData(data, accessor) {
|
|
95
|
-
const accessors = accessor.toString().split(".");
|
|
96
|
-
let value = data;
|
|
97
|
-
for (const acc of accessors) {
|
|
98
|
-
value = value?.[acc];
|
|
99
|
-
}
|
|
100
|
-
return value;
|
|
101
|
-
}
|
|
102
|
-
export const ALL_OS = {
|
|
103
|
-
windows: "Windows",
|
|
104
|
-
macos: "macOS",
|
|
105
|
-
linux: "Linux",
|
|
106
|
-
ios: "iOS",
|
|
107
|
-
android: "Android",
|
|
108
|
-
};
|
|
109
|
-
export function createTableFetchFn(ctxclient, path) {
|
|
110
|
-
return async (pagination, sorting, searching, filters) => {
|
|
111
|
-
const query = {
|
|
112
|
-
...filters,
|
|
113
|
-
page: pagination.pageIndex + 1,
|
|
114
|
-
limit: pagination.pageSize,
|
|
115
|
-
sort: generateSortParam(sorting[0]),
|
|
116
|
-
search: searching,
|
|
117
|
-
};
|
|
118
|
-
// const pathParams = merge(_baseQueryObject, params);
|
|
119
|
-
return ctxclient.GET(path, { query }).then((value) => {
|
|
120
|
-
const rowCount = Number.parseInt(value.response.headers.get("Pagination-Count") || "0");
|
|
121
|
-
return { total: rowCount, data: value.data };
|
|
122
|
-
});
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
function generateSortParam(sort) {
|
|
126
|
-
if (sort) {
|
|
127
|
-
if (sort.desc) {
|
|
128
|
-
return `-${sort.id}`;
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
return `+${sort.id}`;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
return "-createdAt";
|
|
136
|
-
}
|
|
137
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Checkbox as AriaCheckbox, CheckboxGroup as AriaCheckboxGroup, composeRenderProps } from "react-aria-components";
|
|
3
|
-
import { FormField, labelVariants } from "lib/components/inputs/field";
|
|
4
|
-
import { useFieldContext } from "lib/utils/form-context";
|
|
5
|
-
import { cn } from "lib/utils/primitives";
|
|
6
|
-
import { Check, Minus } from "lucide-react";
|
|
7
|
-
export const CheckboxGroup = AriaCheckboxGroup;
|
|
8
|
-
export function Checkbox({ className, label, description, errorMessage, ...props }) {
|
|
9
|
-
return (_jsx("div", { className: "group form-field", children: _jsx(FormField, { label: label, description: description, errorMessage: errorMessage, children: _jsx(AriaCheckbox, { className: composeRenderProps(className, (className) => cn("group/checkbox cursor-pointer focus-ring flex items-center gap-x-2",
|
|
10
|
-
/* Disabled */
|
|
11
|
-
"disabled-muted", labelVariants, className)), ...props, children: composeRenderProps(_jsx(_Fragment, {}), (_, renderProps) => (_jsx(_Fragment, { children: _jsx("div", { className: cn("flex size-input shrink-0 items-center bg-card justify-center border border-input text-current ring-offset-background",
|
|
12
|
-
/* Selected */
|
|
13
|
-
"group-data-[indeterminate]/checkbox:bg-primary group-data-[selected]/checkbox:bg-primary group-data-[indeterminate]/checkbox:text-primary-foreground group-data-[selected]/checkbox:text-primary-foreground",
|
|
14
|
-
/* Disabled */
|
|
15
|
-
"group-data-[disabled]/checkbox:cursor-not-allowed group-data-[disabled]/checkbox:opacity-50",
|
|
16
|
-
/* Invalid */
|
|
17
|
-
"group-data-[invalid]/checkbox:border-destructive group-data-[invalid]/checkbox:group-data-[selected]/checkbox:bg-destructive group-data-[invalid]/checkbox:group-data-[selected]/checkbox:text-destructive-foreground",
|
|
18
|
-
/* Resets */
|
|
19
|
-
"focus:outline-none focus-visible:outline-none"), children: renderProps.isIndeterminate ? (_jsx(Minus, { className: "size-icon" })) : renderProps.isSelected ? (_jsx(Check, { className: "size-icon" })) : null }) }))) }) }) }));
|
|
20
|
-
}
|
|
21
|
-
export function TfCheckbox({ ...props }) {
|
|
22
|
-
const field = useFieldContext();
|
|
23
|
-
return (_jsx(Checkbox, { isSelected: field.state.value, isDisabled: field.form.state.isSubmitting || props.isDisabled, onChange: () => field.handleChange(!field.state.value), onBlur: field.handleBlur, ...props }));
|
|
24
|
-
}
|
|
25
|
-
;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { CalendarIcon } from "lucide-react";
|
|
3
|
-
import { DatePicker as AriaDatePicker, DateRangePicker as AriaDateRangePicker, Dialog as AriaDialog, composeRenderProps, Popover } from "react-aria-components";
|
|
4
|
-
import { getLocalTimeZone, parseAbsolute } from "@internationalized/date";
|
|
5
|
-
import { DateInput } from "lib/components/inputs/datefield";
|
|
6
|
-
import { FieldGroup, FormField } from "lib/components/inputs/field";
|
|
7
|
-
import { Button } from "lib/components/ui/button";
|
|
8
|
-
import { Calendar, RangeCalendar } from "lib/components/ui/calendar";
|
|
9
|
-
import { useFieldContext } from "lib/utils/form-context";
|
|
10
|
-
import { getFieldErrorMessage } from "lib/utils/form-hook";
|
|
11
|
-
import { cn } from "lib/utils/primitives";
|
|
12
|
-
const DatePickerContent = ({ className, popoverClassName, ...props }) => (_jsx(Popover, { className: composeRenderProps(popoverClassName, (className) => cn("w-auto p-3", className)), children: _jsx(AriaDialog, { className: cn("flex w-full flex-col gap-y-2 outline-none sm:flex-row sm:gap-x-icon sm:gap-y-0", className), ...props }) }));
|
|
13
|
-
export function DatePicker({ label, description, errorMessage, className, ...props }) {
|
|
14
|
-
return (_jsxs(AriaDatePicker, { className: composeRenderProps(className, (className) => cn("group flex flex-col gap-2", className)), ...props, children: [_jsx(FormField, { label: label, description: description, errorMessage: errorMessage, children: _jsxs(FieldGroup, { "aria-label": label, children: [_jsx(DateInput, { className: "flex-1", variant: "ghost" }), _jsx(Button, { variant: "ghost", size: "icon", className: '-me-2 ms-2', children: _jsx(CalendarIcon, { "aria-hidden": true }) })] }) }), _jsx(DatePickerContent, { children: _jsx(Calendar, {}) })] }));
|
|
15
|
-
}
|
|
16
|
-
export function TfDatePicker({ ...props }) {
|
|
17
|
-
const field = useFieldContext();
|
|
18
|
-
return (_jsx(DatePicker, { hideTimeZone: true, value: field.state.value ? parseAbsolute(field.state.value, getLocalTimeZone()) : null, onChange: (v) => v ? field.handleChange(v.toAbsoluteString()) : field.handleChange(null), onBlur: field.handleBlur, isInvalid: !!getFieldErrorMessage(field), errorMessage: getFieldErrorMessage(field), ...props }));
|
|
19
|
-
}
|
|
20
|
-
export function DateRangePicker({ label, description, errorMessage, className, ...props }) {
|
|
21
|
-
return (_jsxs(AriaDateRangePicker, { className: composeRenderProps(className, (className) => cn("group flex flex-col gap-2", className)), ...props, children: [_jsx(FormField, { label: label, errorMessage: errorMessage, description: description, children: _jsxs(FieldGroup, { children: [_jsx(DateInput, { variant: "ghost", slot: "start" }), _jsx("span", { "aria-hidden": true, className: "px-2 text-sm text-muted-foreground", children: "-" }), _jsx(DateInput, { className: "flex-1", variant: "ghost", slot: "end" }), _jsx(Button, { variant: "ghost", size: "icon", className: "mr-1 data-[focus-visible]:ring-offset-0", children: _jsx(CalendarIcon, { "aria-hidden": true }) })] }) }), _jsx(DatePickerContent, { children: _jsx(RangeCalendar, {}) })] }));
|
|
22
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { DateField as AriaDateField, DateInput as AriaDateInput, DateSegment as AriaDateSegment, TimeField as AriaTimeField, composeRenderProps } from "react-aria-components";
|
|
4
|
-
import { cn } from "lib/utils/primitives";
|
|
5
|
-
import { fieldGroupVariants, FormField } from "./field";
|
|
6
|
-
export function DateSegment({ className, ...props }) {
|
|
7
|
-
return (_jsx(AriaDateSegment, { className: composeRenderProps(className, (className) => cn("inline caret-transparent outline-0",
|
|
8
|
-
/* Placeholder */
|
|
9
|
-
"data-[placeholder]:text-muted-foreground",
|
|
10
|
-
/* Disabled */
|
|
11
|
-
"disabled-muted",
|
|
12
|
-
/* Focused */
|
|
13
|
-
"data-[focused]:bg-accent data-[focused]:text-accent-foreground",
|
|
14
|
-
/* Invalid */
|
|
15
|
-
"data-[invalid]:data-[focused]:bg-destructive data-[invalid]:data-[focused]:data-[placeholder]:text-destructive-foreground data-[invalid]:data-[focused]:text-destructive-foreground data-[invalid]:data-[placeholder]:text-destructive data-[invalid]:text-destructive", className)), ...props }));
|
|
16
|
-
}
|
|
17
|
-
export function DateInput({ className, variant, ...props }) {
|
|
18
|
-
return (_jsx(AriaDateInput, { className: composeRenderProps(className, (className) => cn(fieldGroupVariants({ variant }), "text-sm", className)), ...props, children: (segment) => _jsx(DateSegment, { segment: segment }) }));
|
|
19
|
-
}
|
|
20
|
-
export function DateField({ label, description, className, errorMessage, ...props }) {
|
|
21
|
-
return (_jsx(AriaDateField, { className: composeRenderProps(className, (className) => cn("group form-field", className)), ...props, children: _jsx(FormField, { label: label, description: description, errorMessage: errorMessage, children: _jsx(DateInput, {}) }) }));
|
|
22
|
-
}
|
|
23
|
-
export function TimeField({ label, description, errorMessage, className, ...props }) {
|
|
24
|
-
return (_jsx(AriaTimeField, { className: composeRenderProps(className, (className) => cn("group form-field", className)), ...props, children: _jsx(FormField, { label: label, description: description, errorMessage: errorMessage, children: _jsx(DateInput, {}) }) }));
|
|
25
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { cva } from "class-variance-authority";
|
|
4
|
-
import { Group as AriaGroup, Label as AriaLabel, Text as AriaText, composeRenderProps } from "react-aria-components";
|
|
5
|
-
import { cn } from "lib/utils/primitives";
|
|
6
|
-
import { CircleX, Info } from "lucide-react";
|
|
7
|
-
export const labelVariants = cva([
|
|
8
|
-
"select-none text-sm font-medium leading-none",
|
|
9
|
-
/* Disabled */
|
|
10
|
-
"disabled-muted",
|
|
11
|
-
/* Invalid */
|
|
12
|
-
"group-data-[invalid]:text-destructive",
|
|
13
|
-
]);
|
|
14
|
-
export function FieldLabel({ className, ...props }) {
|
|
15
|
-
return (_jsx(AriaLabel, { className: cn(labelVariants(), className), ...props }));
|
|
16
|
-
}
|
|
17
|
-
export function FieldDescription({ className, children, ...props }) {
|
|
18
|
-
return (_jsxs(AriaText, { className: cn("text-sm text-muted leading-tight", className), ...props, slot: "description", children: [children, _jsx(Info, { className: "inline size-2 align-text-top ms-0.5" })] }));
|
|
19
|
-
}
|
|
20
|
-
// TODO, if we were to use AriaFieldError, it would use the internal ValidationState Context object, which might be useful for composing inputs but
|
|
21
|
-
// this would have significant overlap with what Tanstack Form is already doing for us. It has pros and cons, needs to be discussed and explored.
|
|
22
|
-
export function FieldError({ className, children, ...props }) {
|
|
23
|
-
return (_jsxs("div", { className: cn("text-sm leading-tight text-destructive duration-150 animate-in transition-transform slide-in-from-top-5 fade-in", className), ...props, children: [children, _jsx(CircleX, { className: "inline size-2 align-text-top ms-0.5" })] }));
|
|
24
|
-
}
|
|
25
|
-
export const fieldGroupVariants = cva("", {
|
|
26
|
-
variants: {
|
|
27
|
-
variant: {
|
|
28
|
-
default: [
|
|
29
|
-
// TODO standardize the padding here
|
|
30
|
-
"relative flex h-input w-full items-center overflow-hidden border border-input bg-card px-2 py-2 text-sm ring-offset-background",
|
|
31
|
-
/* Focus Within */
|
|
32
|
-
"focus-ring",
|
|
33
|
-
/* Disabled */
|
|
34
|
-
"disabled-muted",
|
|
35
|
-
],
|
|
36
|
-
ghost: "",
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
defaultVariants: {
|
|
40
|
-
variant: "default",
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
export function FieldGroup({ className, variant, ...props }) {
|
|
44
|
-
return (_jsx(AriaGroup, { className: composeRenderProps(className, (className) => cn(fieldGroupVariants({ variant }), className)), ...props }));
|
|
45
|
-
}
|
|
46
|
-
export function FormField({ label, description, errorMessage, children }) {
|
|
47
|
-
return _jsxs(_Fragment, { children: [label && _jsx(FieldLabel, { children: label }), children, description && (_jsx(FieldDescription, { children: description })), errorMessage && _jsx(FieldError, { children: errorMessage })] });
|
|
48
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useQuery } from "@tanstack/react-query";
|
|
3
|
-
import { SearchField } from "lib/components/inputs/searchfield";
|
|
4
|
-
import { Button } from "lib/components/ui/button";
|
|
5
|
-
import { Loader } from "lib/components/ui/loader";
|
|
6
|
-
import { Menu, MenuItem } from "lib/components/ui/menu";
|
|
7
|
-
import { Popover, PopoverTrigger } from "lib/components/ui/popover";
|
|
8
|
-
import { useFieldContext } from "lib/utils/form-context";
|
|
9
|
-
import { useId, useState } from "react";
|
|
10
|
-
import { Autocomplete } from 'react-aria-components';
|
|
11
|
-
export function IdSearchInput({ value, disabled = false, searchFn, multiple, onChange, onBlur, accessor = 'id', idLookup }) {
|
|
12
|
-
const id = useId();
|
|
13
|
-
const [search, _setSearch] = useState('');
|
|
14
|
-
const { data, isError, isFetching, error } = useQuery({
|
|
15
|
-
queryKey: [id, search],
|
|
16
|
-
queryFn: () => searchFn(search)
|
|
17
|
-
});
|
|
18
|
-
const namesQuery = useQuery({
|
|
19
|
-
queryKey: [id, value],
|
|
20
|
-
queryFn: () => idLookup(Array.from(value.keys()).map(id => id.toString())),
|
|
21
|
-
enabled: idLookup && value.size > 0
|
|
22
|
-
});
|
|
23
|
-
const renderButtonLabel = () => {
|
|
24
|
-
return namesQuery.data?.join(',');
|
|
25
|
-
};
|
|
26
|
-
return _jsx(_Fragment, { children: _jsxs(PopoverTrigger, { onOpenChange: (o) => {
|
|
27
|
-
if (!o) {
|
|
28
|
-
// searchInputRef.current?.focus();
|
|
29
|
-
onBlur?.(value);
|
|
30
|
-
}
|
|
31
|
-
}, children: [_jsx(Button, { className: 'min-w-3xs', isDisabled: disabled, children: renderButtonLabel() }), _jsx(Popover, { className: 'p-2', children: _jsxs(Autocomplete, { inputValue: search, onInputChange: _setSearch, children: [_jsx(SearchField, { className: 'mb-icon', autoFocus: true }), isFetching && _jsx(Loader, { className: "p-input" }), !isFetching && !isError && _jsx(Menu, { selectedKeys: value, selectionMode: multiple ? "multiple" : 'single', onSelectionChange: (s) => {
|
|
32
|
-
if (typeof (s) === 'string')
|
|
33
|
-
return;
|
|
34
|
-
onChange(s);
|
|
35
|
-
}, className: 'text-sm', items: data, renderEmptyState: () => 'No results found.', children: (item) => (_jsx(MenuItem, { id: item[accessor], children: item.name }, item['id'])) }), isError && _jsx("div", { className: "text-destructive p-icon", children: error.message })] }) })] }) });
|
|
36
|
-
}
|
|
37
|
-
export function TfIdSearchInput({ disabled, ...props }) {
|
|
38
|
-
const field = useFieldContext();
|
|
39
|
-
return (_jsx(IdSearchInput, { ...props, disabled: disabled || field.form.state.isSubmitting, value: field.state.value, onBlur: _ => field.handleBlur(), onChange: (e) => field.handleChange(e) }));
|
|
40
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { OTPInput, OTPInputContext } from "input-otp";
|
|
3
|
-
import { cn } from "lib/utils/primitives";
|
|
4
|
-
import { Minus } from "lucide-react";
|
|
5
|
-
import * as React from "react";
|
|
6
|
-
export function InputOTP({ className, containerClassName, ...props }) {
|
|
7
|
-
return (_jsx(OTPInput, { containerClassName: cn("flex items-center gap-2 has-disabled:opacity-50", containerClassName), className: cn("disabled:cursor-not-allowed", className), ...props }));
|
|
8
|
-
}
|
|
9
|
-
export function InputOTPGroup({ className, ...props }) {
|
|
10
|
-
return _jsx("div", { className: cn("flex items-center", className), ...props });
|
|
11
|
-
}
|
|
12
|
-
export function InputOTPSlot({ index, className, ...props }) {
|
|
13
|
-
const inputOTPContext = React.use(OTPInputContext);
|
|
14
|
-
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
|
|
15
|
-
return (_jsxs("div", { className: cn("relative flex h-input w-9 items-center justify-center border-2 border-input body transition-all", isActive ? "z-10 border-2 border-primary" : "", className), ...props, children: [char, hasFakeCaret && (_jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "h-icon w-px animate-caret-blink bg-foreground duration-1000" }) }))] }));
|
|
16
|
-
}
|
|
17
|
-
export function InputOTPSeparator({ ...props }) {
|
|
18
|
-
return (_jsx("div", { role: "separator", ...props, children: _jsx(Minus, {}) }));
|
|
19
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { FormField } from "lib/components/inputs/field";
|
|
3
|
-
import { EasyMenu, MenuItem } from "lib/components/ui/menu";
|
|
4
|
-
import { useFieldContext } from "lib/utils/form-context";
|
|
5
|
-
import { getFieldErrorMessage } from "lib/utils/form-hook";
|
|
6
|
-
export function MultiSelect({ items, value, onChange: setValue, label, errorMessage, description, ...props }) {
|
|
7
|
-
return (_jsx("div", { className: "group form-field", children: _jsx(FormField, { label, description, errorMessage, children: _jsx(EasyMenu, { selectionMode: "multiple", selectedKeys: value, onSelectionChange: (v) => {
|
|
8
|
-
if (typeof (v) === 'string')
|
|
9
|
-
return;
|
|
10
|
-
setValue(v);
|
|
11
|
-
}, items: items, label: value.size, ...props, children: (item) => _jsx(MenuItem, { id: item.id, isDisabled: item?.disabled, children: item.label }, item.id) }) }) }));
|
|
12
|
-
}
|
|
13
|
-
;
|
|
14
|
-
export function TfMultiSelect({ ...props }) {
|
|
15
|
-
const field = useFieldContext();
|
|
16
|
-
return (_jsx(MultiSelect, { value: field.state.value, onChange: field.setValue, onClose: field.handleBlur, errorMessage: getFieldErrorMessage(field), ...props }));
|
|
17
|
-
}
|
|
18
|
-
;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Input as AriaInput, NumberField as AriaNumberField, composeRenderProps } from "react-aria-components";
|
|
3
|
-
import { Button } from "lib/components/ui/button";
|
|
4
|
-
import { useFieldContext } from "lib/utils/form-context";
|
|
5
|
-
import { getFieldErrorMessage } from "lib/utils/form-hook";
|
|
6
|
-
import { cn } from "lib/utils/primitives";
|
|
7
|
-
import { ChevronDown, ChevronUp } from "lucide-react";
|
|
8
|
-
import { FieldGroup, FormField } from "./field";
|
|
9
|
-
const ANumberField = AriaNumberField;
|
|
10
|
-
function NumberFieldInput({ className, ...props }) {
|
|
11
|
-
return (_jsx(AriaInput, { className: composeRenderProps(className, (className) => cn("w-fit min-w-0 flex-1 border-r border-transparent bg-card pr-2 outline-0 placeholder:text-muted-foreground [&::-webkit-search-cancel-button]:hidden", className)), ...props }));
|
|
12
|
-
}
|
|
13
|
-
function NumberFieldSteppers({ className, ...props }) {
|
|
14
|
-
return (_jsxs("div", { className: cn("absolute right-0 flex h-full flex-col border-l", className), ...props, children: [_jsx(NumberFieldStepper, { slot: "increment", children: _jsx(ChevronUp, { "aria-hidden": true, className: "size-icon" }) }), _jsx("div", { className: "border-b" }), _jsx(NumberFieldStepper, { slot: "decrement", children: _jsx(ChevronDown, { "aria-hidden": true, className: "size-icon" }) })] }));
|
|
15
|
-
}
|
|
16
|
-
function NumberFieldStepper({ className, ...props }) {
|
|
17
|
-
return (_jsx(Button, { className: composeRenderProps(className, (className) => cn("w-auto grow h-3 px-0.5 text-muted-foreground", className)), variant: "ghost", size: "none", ...props }));
|
|
18
|
-
}
|
|
19
|
-
export function NumberField({ label, description, errorMessage, className, ...props }) {
|
|
20
|
-
return (_jsx(ANumberField, { className: composeRenderProps(className, (className) => cn("group form-field", className)), ...props, children: _jsx(FormField, { label: label, description: description, errorMessage: errorMessage, children: _jsxs(FieldGroup, { children: [_jsx(NumberFieldInput, {}), _jsx(NumberFieldSteppers, {})] }) }) }));
|
|
21
|
-
}
|
|
22
|
-
export function TfNumberField({ isDisabled, ...props }) {
|
|
23
|
-
const field = useFieldContext();
|
|
24
|
-
return (_jsx(NumberField, { isInvalid: !!getFieldErrorMessage(field), isDisabled: isDisabled || field.form.state.isSubmitting, value: field.state.value, id: field.name, onChange: field.handleChange, onBlur: field.handleBlur, errorMessage: getFieldErrorMessage(field), ...props }));
|
|
25
|
-
}
|