@cryptlex/web-components 5.2.0 → 5.3.0-alpha01
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/data-table/data-table-filter.d.ts +27 -0
- package/dist/components/data-table/data-table-filter.js +2 -0
- package/dist/components/data-table/data-table-filter.js.map +1 -0
- package/dist/components/data-table/data-table.d.ts +72 -0
- package/dist/components/data-table/data-table.js +2 -0
- package/dist/components/data-table/data-table.js.map +1 -0
- package/dist/components/data-table/table-commons.d.ts +56 -0
- package/dist/components/data-table/table-commons.js +2 -0
- package/dist/components/data-table/table-commons.js.map +1 -0
- package/dist/components/inputs/checkbox.d.ts +8 -0
- package/dist/components/inputs/checkbox.js +2 -0
- package/dist/components/inputs/checkbox.js.map +1 -0
- package/dist/components/inputs/date-picker.d.ts +11 -0
- package/dist/components/inputs/date-picker.js +2 -0
- package/dist/components/inputs/date-picker.js.map +1 -0
- package/dist/components/inputs/datefield.d.ts +14 -0
- package/dist/components/inputs/datefield.js +2 -0
- package/dist/components/inputs/datefield.js.map +1 -0
- package/dist/components/inputs/field.d.ts +20 -0
- package/dist/components/inputs/field.js +2 -0
- package/dist/components/inputs/field.js.map +1 -0
- package/dist/components/inputs/id-search.d.ts +20 -0
- package/dist/components/inputs/id-search.js +2 -0
- package/dist/components/inputs/id-search.js.map +1 -0
- package/dist/components/inputs/input-otp.d.ts +7 -0
- package/dist/components/inputs/input-otp.js +2 -0
- package/dist/components/inputs/input-otp.js.map +1 -0
- package/dist/components/inputs/multi-select.d.ts +16 -0
- package/dist/components/inputs/multi-select.js +2 -0
- package/dist/components/inputs/multi-select.js.map +1 -0
- package/dist/components/inputs/numberfield.d.ts +6 -0
- package/dist/components/inputs/numberfield.js +2 -0
- package/dist/components/inputs/numberfield.js.map +1 -0
- package/dist/components/inputs/searchfield.d.ts +5 -0
- package/dist/components/inputs/searchfield.js +2 -0
- package/dist/components/inputs/searchfield.js.map +1 -0
- package/dist/components/inputs/select-options.d.ts +8 -0
- package/dist/components/inputs/select-options.js +2 -0
- package/dist/components/inputs/select-options.js.map +1 -0
- package/dist/components/inputs/select.d.ts +17 -0
- package/dist/components/inputs/select.js +2 -0
- package/dist/components/inputs/select.js.map +1 -0
- package/dist/components/inputs/textfield.d.ts +7 -0
- package/dist/components/inputs/textfield.js +2 -0
- package/dist/components/inputs/textfield.js.map +1 -0
- package/dist/components/key-value-card/key-value-card.d.ts +17 -0
- package/dist/components/key-value-card/key-value-card.js +2 -0
- package/dist/components/key-value-card/key-value-card.js.map +1 -0
- package/dist/components/ui/alert.d.ts +8 -0
- package/dist/components/ui/alert.js +2 -0
- package/dist/components/ui/alert.js.map +1 -0
- package/dist/components/ui/avatar.d.ts +7 -0
- package/dist/components/ui/avatar.js +2 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/badge.d.ts +1 -0
- package/dist/components/ui/badge.js +2 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/breadcrumbs.d.ts +10 -0
- package/dist/components/ui/breadcrumbs.js +2 -0
- package/dist/components/ui/breadcrumbs.js.map +1 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/button.js +2 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/calendar.d.ts +16 -0
- package/dist/components/ui/calendar.js +2 -0
- package/dist/components/ui/calendar.js.map +1 -0
- package/dist/components/ui/card.d.ts +7 -0
- package/dist/components/ui/card.js +2 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/ui/dialog.d.ts +18 -0
- package/dist/components/ui/dialog.js +2 -0
- package/dist/components/ui/dialog.js.map +1 -0
- package/dist/components/ui/disclosure.d.ts +18 -0
- package/dist/components/ui/disclosure.js +2 -0
- package/dist/components/ui/disclosure.js.map +1 -0
- package/dist/components/ui/list-box.d.ts +5 -0
- package/dist/components/ui/list-box.js +2 -0
- package/dist/components/ui/list-box.js.map +1 -0
- package/dist/components/ui/loader.d.ts +5 -0
- package/dist/components/ui/loader.js +2 -0
- package/dist/components/ui/loader.js.map +1 -0
- package/dist/components/ui/menu.d.ts +24 -0
- package/dist/components/ui/menu.js +2 -0
- package/dist/components/ui/menu.js.map +1 -0
- package/dist/components/ui/popover.d.ts +4 -0
- package/dist/components/ui/popover.js +2 -0
- package/dist/components/ui/popover.js.map +1 -0
- package/dist/components/ui/sidebar.d.ts +52 -0
- package/dist/components/ui/sidebar.js +2 -0
- package/dist/components/ui/sidebar.js.map +1 -0
- package/dist/components/ui/skeleton.d.ts +1 -0
- package/dist/components/ui/skeleton.js +2 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/components/ui/sonner.d.ts +4 -0
- package/dist/components/ui/sonner.js +2 -0
- package/dist/components/ui/sonner.js.map +1 -0
- package/dist/components/ui/table.d.ts +8 -0
- package/dist/components/ui/table.js +2 -0
- package/dist/components/ui/table.js.map +1 -0
- package/dist/components/ui/tabs.d.ts +5 -0
- package/dist/components/ui/tabs.js +2 -0
- package/dist/components/ui/tabs.js.map +1 -0
- package/dist/components/ui/timeline.d.ts +15 -0
- package/dist/components/ui/timeline.js +2 -0
- package/dist/components/ui/timeline.js.map +1 -0
- package/dist/components/ui/tooltip.d.ts +4 -0
- package/dist/components/ui/tooltip.js +2 -0
- package/dist/components/ui/tooltip.js.map +1 -0
- package/dist/utils/form-context.d.ts +4 -0
- package/dist/utils/form-context.js +2 -0
- package/dist/utils/form-context.js.map +1 -0
- package/dist/utils/form-hook.d.ts +23 -0
- package/dist/utils/form-hook.js +2 -0
- package/dist/utils/form-hook.js.map +1 -0
- package/dist/utils/primitives.d.ts +44 -0
- package/dist/utils/primitives.js +2 -0
- package/dist/utils/primitives.js.map +1 -0
- package/dist/utils/resource-names.d.ts +11 -0
- package/dist/utils/resource-names.js +2 -0
- package/dist/utils/resource-names.js.map +1 -0
- package/dist/utils/use-mobile.d.ts +1 -0
- package/dist/utils/use-mobile.js +2 -0
- package/dist/utils/use-mobile.js.map +1 -0
- package/package.json +16 -8
- package/lib/components/data-table/data-table-filter.tsx +0 -220
- package/lib/components/data-table/data-table.tsx +0 -593
- package/lib/components/data-table/table-commons.tsx +0 -233
- package/lib/components/inputs/checkbox.tsx +0 -72
- package/lib/components/inputs/date-picker.tsx +0 -130
- package/lib/components/inputs/datefield.tsx +0 -109
- package/lib/components/inputs/field.tsx +0 -106
- package/lib/components/inputs/id-search.tsx +0 -83
- package/lib/components/inputs/input-otp.tsx +0 -63
- package/lib/components/inputs/multi-select.tsx +0 -62
- package/lib/components/inputs/numberfield.tsx +0 -110
- package/lib/components/inputs/searchfield.tsx +0 -87
- package/lib/components/inputs/select-options.tsx +0 -303
- package/lib/components/inputs/select.tsx +0 -140
- package/lib/components/inputs/textfield.tsx +0 -96
- package/lib/components/key-value-card/key-value-card.tsx +0 -115
- package/lib/components/ui/alert.tsx +0 -32
- package/lib/components/ui/avatar.tsx +0 -22
- package/lib/components/ui/badge.tsx +0 -19
- package/lib/components/ui/breadcrumbs.tsx +0 -104
- package/lib/components/ui/button.tsx +0 -66
- package/lib/components/ui/calendar.tsx +0 -220
- package/lib/components/ui/card.tsx +0 -58
- package/lib/components/ui/dialog.tsx +0 -172
- package/lib/components/ui/disclosure.tsx +0 -113
- package/lib/components/ui/list-box.tsx +0 -86
- package/lib/components/ui/loader.tsx +0 -10
- package/lib/components/ui/menu.tsx +0 -168
- package/lib/components/ui/popover.tsx +0 -37
- package/lib/components/ui/sidebar.tsx +0 -552
- package/lib/components/ui/skeleton.tsx +0 -7
- package/lib/components/ui/sonner.tsx +0 -26
- package/lib/components/ui/table.tsx +0 -79
- package/lib/components/ui/tabs.tsx +0 -82
- package/lib/components/ui/timeline.tsx +0 -52
- package/lib/components/ui/tooltip.tsx +0 -30
- package/lib/tokens.scss +0 -89
- package/lib/utils/form-context.tsx +0 -7
- package/lib/utils/form-hook.tsx +0 -33
- package/lib/utils/primitives.ts +0 -68
- package/lib/utils/resource-names.tsx +0 -245
- package/lib/utils/use-mobile.tsx +0 -21
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import type { components, operations, paths } from "@cryptlex/web-api-types";
|
|
3
|
-
import type { PaginationState, SortingState, Table } from "@tanstack/react-table";
|
|
4
|
-
import { createColumnHelper } from "@tanstack/react-table";
|
|
5
|
-
import { intervalToDuration } from "date-fns";
|
|
6
|
-
import { Checkbox } from "lib/components/inputs/checkbox";
|
|
7
|
-
import type { LucideIcon } from "lucide-react";
|
|
8
|
-
import type createClient from "openapi-fetch";
|
|
9
|
-
import type { PressEvent } from "react-aria-components";
|
|
10
|
-
|
|
11
|
-
const cH = createColumnHelper<any>();
|
|
12
|
-
export const TABLE_CHECK_BOX_COLUMN = [
|
|
13
|
-
cH.accessor("checkbox", {
|
|
14
|
-
header: ({ table }) => (
|
|
15
|
-
<Checkbox
|
|
16
|
-
isIndeterminate={table.getIsSomeRowsSelected() && !table.getIsAllPageRowsSelected()}
|
|
17
|
-
isSelected={
|
|
18
|
-
table.getIsAllPageRowsSelected() || table.getIsSomePageRowsSelected()
|
|
19
|
-
}
|
|
20
|
-
onChange={() => table.toggleAllPageRowsSelected()}
|
|
21
|
-
aria-label="Select all"
|
|
22
|
-
/>
|
|
23
|
-
),
|
|
24
|
-
|
|
25
|
-
cell: ({ row }) => (
|
|
26
|
-
<Checkbox
|
|
27
|
-
isSelected={row.getIsSelected()}
|
|
28
|
-
onChange={() => row.toggleSelected()}
|
|
29
|
-
aria-label="Select row"
|
|
30
|
-
/>
|
|
31
|
-
),
|
|
32
|
-
enableSorting: false,
|
|
33
|
-
enableHiding: false,
|
|
34
|
-
}),
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
export const TABLE_ID_COLUMN = [
|
|
38
|
-
cH.accessor("id", {
|
|
39
|
-
header: () => "ID",
|
|
40
|
-
}),
|
|
41
|
-
];
|
|
42
|
-
export const TABLE_DEFAULT_DATE_COLUMNS = [
|
|
43
|
-
cH.accessor("createdAt", {
|
|
44
|
-
header: () => "Creation Date",
|
|
45
|
-
cell: ({ row }) => {
|
|
46
|
-
const date = row.getValue("createdAt") satisfies
|
|
47
|
-
| string
|
|
48
|
-
| null
|
|
49
|
-
| undefined;
|
|
50
|
-
return formatDate(date);
|
|
51
|
-
},
|
|
52
|
-
enableHiding: false,
|
|
53
|
-
}),
|
|
54
|
-
cH.accessor("updatedAt", {
|
|
55
|
-
header: () => "Last Updated",
|
|
56
|
-
cell: ({ row }) => {
|
|
57
|
-
const date = row.getValue("updatedAt") satisfies
|
|
58
|
-
| string
|
|
59
|
-
| null
|
|
60
|
-
| undefined;
|
|
61
|
-
return formatDate(date);
|
|
62
|
-
},
|
|
63
|
-
enableHiding: false,
|
|
64
|
-
}),
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
// TODO, i18n
|
|
68
|
-
export function formatDate(date: string | null | undefined) {
|
|
69
|
-
if (!date) return null;
|
|
70
|
-
const _date = new Date(date);
|
|
71
|
-
return new Intl.DateTimeFormat(undefined, {
|
|
72
|
-
dateStyle: "medium",
|
|
73
|
-
timeStyle: "short",
|
|
74
|
-
}).format(_date);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Format multiple license parameters (expired, suspended, revoked) into a single status
|
|
78
|
-
*/
|
|
79
|
-
export function getLicenseStatus(license: any): string {
|
|
80
|
-
const licenseExpired =
|
|
81
|
-
license.expiresAt && new Date(license.expiresAt) < new Date();
|
|
82
|
-
// Status Column
|
|
83
|
-
switch (true) {
|
|
84
|
-
case license.revoked && license.suspended && licenseExpired:
|
|
85
|
-
return "Revoked, Suspended, Expired";
|
|
86
|
-
case license.revoked && license.suspended:
|
|
87
|
-
return "Revoked, Suspended";
|
|
88
|
-
case license.revoked && licenseExpired:
|
|
89
|
-
return "Revoked, Expired";
|
|
90
|
-
case license.suspended && licenseExpired:
|
|
91
|
-
return "Suspended, Expired";
|
|
92
|
-
case license.suspended:
|
|
93
|
-
return "Suspended";
|
|
94
|
-
case license.revoked:
|
|
95
|
-
return "Revoked";
|
|
96
|
-
case licenseExpired:
|
|
97
|
-
return "Expired";
|
|
98
|
-
default:
|
|
99
|
-
return "Active";
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function getValidityDisplay(validity: number | undefined) {
|
|
104
|
-
if (validity === 0 || !validity) {
|
|
105
|
-
return "Lifetime";
|
|
106
|
-
} else {
|
|
107
|
-
return secondsToDuration(validity);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
export function secondsToDuration(seconds: number): string {
|
|
111
|
-
//@ts-ignore
|
|
112
|
-
const duration = intervalToDuration({
|
|
113
|
-
start: 0,
|
|
114
|
-
end: seconds * 1000,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const parts = [
|
|
118
|
-
duration.years && `${duration.years}y`,
|
|
119
|
-
duration.months && `${duration.months}m`,
|
|
120
|
-
duration.days && `${duration.days}d`,
|
|
121
|
-
duration.hours && `${duration.hours}h`,
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
// Filter out undefined values and join
|
|
125
|
-
return parts.filter(Boolean).join(" ").trim();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function getValueFromData(
|
|
129
|
-
data: any,
|
|
130
|
-
accessor: string | number | symbol,
|
|
131
|
-
) {
|
|
132
|
-
const accessors = accessor.toString().split(".");
|
|
133
|
-
let value = data;
|
|
134
|
-
for (const acc of accessors) {
|
|
135
|
-
value = value?.[acc];
|
|
136
|
-
}
|
|
137
|
-
return value;
|
|
138
|
-
}
|
|
139
|
-
export const ALL_OS: { [key: string]: string } = {
|
|
140
|
-
windows: "Windows",
|
|
141
|
-
macos: "macOS",
|
|
142
|
-
linux: "Linux",
|
|
143
|
-
ios: "iOS",
|
|
144
|
-
android: "Android",
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
export type VisibilityState<T> = {
|
|
148
|
-
[K in keyof T]?: boolean;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
export type TableActions = ({
|
|
152
|
-
onClick: (e: PressEvent, t: Table<any>) => void
|
|
153
|
-
bulk: boolean;
|
|
154
|
-
icon: LucideIcon
|
|
155
|
-
tooltip?: string;
|
|
156
|
-
})[]
|
|
157
|
-
|
|
158
|
-
export type TableFetchFn<TData, TOperation extends keyof operations> = (
|
|
159
|
-
p: PaginationState,
|
|
160
|
-
s: SortingState,
|
|
161
|
-
q: string,
|
|
162
|
-
f: ApiFilters<TOperation>
|
|
163
|
-
) => Promise<{
|
|
164
|
-
total: number;
|
|
165
|
-
data: TData[] | undefined;
|
|
166
|
-
}>;
|
|
167
|
-
/*** Type for hide some of the columns based on the dto of the particular page
|
|
168
|
-
** `id`, `updatedAt` are by default hidden
|
|
169
|
-
*/
|
|
170
|
-
export type DefaultVisibilityState<T> = {
|
|
171
|
-
[K in keyof T]?: boolean;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
type Client = ReturnType<typeof createClient<paths>>;
|
|
176
|
-
|
|
177
|
-
// Helper type to extract valid GET paths
|
|
178
|
-
type GetPaths = {
|
|
179
|
-
[P in keyof paths]: paths[P] extends { get: any } ? P : never;
|
|
180
|
-
}[keyof paths];
|
|
181
|
-
|
|
182
|
-
export type ApiSchema<T extends keyof components['schemas']> = components['schemas'][T];
|
|
183
|
-
export type ApiQuery<T extends keyof operations> = NonNullable<operations[T]['parameters']['query']>;
|
|
184
|
-
export type ApiGetAllParameters = {
|
|
185
|
-
page: number;
|
|
186
|
-
limit: number;
|
|
187
|
-
search?: string;
|
|
188
|
-
sort?: string;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
export type ApiFilter<T extends keyof operations> = Omit<ApiQuery<T>, 'page' | 'limit' | 'sort' | 'search'>
|
|
193
|
-
export type ApiFilters<T extends keyof operations> = NonNullable<Omit<ApiQuery<T>, 'page' | 'limit' | 'sort' | 'search'>>
|
|
194
|
-
|
|
195
|
-
export function createTableFetchFn<Return, Operation extends keyof operations>(
|
|
196
|
-
ctxclient: Client,
|
|
197
|
-
path: GetPaths,
|
|
198
|
-
): TableFetchFn<Return, Operation> {
|
|
199
|
-
return async (pagination, sorting, searching, filters) => {
|
|
200
|
-
const query: ApiQuery<Operation> = {
|
|
201
|
-
...filters,
|
|
202
|
-
page: pagination.pageIndex + 1,
|
|
203
|
-
limit: pagination.pageSize,
|
|
204
|
-
sort: generateSortParam(sorting[0]),
|
|
205
|
-
search: searching,
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
// const pathParams = merge(_baseQueryObject, params);
|
|
209
|
-
|
|
210
|
-
return ctxclient.GET(path, { query }).then((value) => {
|
|
211
|
-
const rowCount = Number.parseInt(
|
|
212
|
-
value.response.headers.get("Pagination-Count") || "0",
|
|
213
|
-
);
|
|
214
|
-
return { total: rowCount, data: value.data };
|
|
215
|
-
});
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function generateSortParam(
|
|
220
|
-
sort: { id: string; desc: boolean } | undefined,
|
|
221
|
-
): string {
|
|
222
|
-
if (sort) {
|
|
223
|
-
if (sort.desc) {
|
|
224
|
-
return `-${sort.id}`;
|
|
225
|
-
} else {
|
|
226
|
-
return `+${sort.id}`;
|
|
227
|
-
}
|
|
228
|
-
} else {
|
|
229
|
-
return "-createdAt";
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Checkbox as AriaCheckbox,
|
|
3
|
-
CheckboxGroup as AriaCheckboxGroup,
|
|
4
|
-
composeRenderProps,
|
|
5
|
-
type CheckboxProps as AriaCheckboxProps
|
|
6
|
-
} from "react-aria-components";
|
|
7
|
-
|
|
8
|
-
import { FormField, labelVariants, type FormFieldProps } from "lib/components/inputs/field";
|
|
9
|
-
import { useFieldContext } from "lib/utils/form-context";
|
|
10
|
-
import { cn } from "lib/utils/primitives";
|
|
11
|
-
import { Check, Minus } from "lucide-react";
|
|
12
|
-
|
|
13
|
-
export const CheckboxGroup = AriaCheckboxGroup
|
|
14
|
-
type CheckboxProps = AriaCheckboxProps & FormFieldProps;
|
|
15
|
-
export function Checkbox({ className, label, description, errorMessage, ...props }: Omit<CheckboxProps, 'children'>) {
|
|
16
|
-
return (
|
|
17
|
-
<div className="group form-field">
|
|
18
|
-
<FormField label={label} description={description} errorMessage={errorMessage}>
|
|
19
|
-
<AriaCheckbox
|
|
20
|
-
className={composeRenderProps(className, (className) =>
|
|
21
|
-
cn(
|
|
22
|
-
"group/checkbox cursor-pointer focus-ring flex items-center gap-x-2",
|
|
23
|
-
/* Disabled */
|
|
24
|
-
"disabled-muted",
|
|
25
|
-
labelVariants,
|
|
26
|
-
className
|
|
27
|
-
)
|
|
28
|
-
)}
|
|
29
|
-
{...props}
|
|
30
|
-
>
|
|
31
|
-
{composeRenderProps(<></>, (_, renderProps) => (
|
|
32
|
-
<>
|
|
33
|
-
<div
|
|
34
|
-
className={cn(
|
|
35
|
-
"flex size-input shrink-0 items-center bg-card justify-center border border-input text-current ring-offset-background",
|
|
36
|
-
/* Selected */
|
|
37
|
-
"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",
|
|
38
|
-
/* Disabled */
|
|
39
|
-
"group-data-[disabled]/checkbox:cursor-not-allowed group-data-[disabled]/checkbox:opacity-50",
|
|
40
|
-
/* Invalid */
|
|
41
|
-
"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",
|
|
42
|
-
/* Resets */
|
|
43
|
-
"focus:outline-none focus-visible:outline-none"
|
|
44
|
-
)}
|
|
45
|
-
>
|
|
46
|
-
{renderProps.isIndeterminate ? (
|
|
47
|
-
<Minus className="size-icon" />
|
|
48
|
-
) : renderProps.isSelected ? (
|
|
49
|
-
<Check className="size-icon" />
|
|
50
|
-
) : null}
|
|
51
|
-
</div>
|
|
52
|
-
</>
|
|
53
|
-
))}
|
|
54
|
-
</AriaCheckbox>
|
|
55
|
-
</FormField>
|
|
56
|
-
</div>
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export type TfCheckboxProps = Omit<React.ComponentProps<typeof Checkbox>, "onChange" | "onBlur" | "isChecked">
|
|
61
|
-
export function TfCheckbox({ ...props }: TfCheckboxProps) {
|
|
62
|
-
const field = useFieldContext<boolean>();
|
|
63
|
-
return (
|
|
64
|
-
<Checkbox
|
|
65
|
-
isSelected={field.state.value}
|
|
66
|
-
isDisabled={field.form.state.isSubmitting || props.isDisabled}
|
|
67
|
-
onChange={() => field.handleChange(!field.state.value)}
|
|
68
|
-
onBlur={field.handleBlur}
|
|
69
|
-
{...props}
|
|
70
|
-
/>
|
|
71
|
-
);
|
|
72
|
-
};
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { CalendarIcon } from "lucide-react"
|
|
2
|
-
import {
|
|
3
|
-
DatePicker as AriaDatePicker,
|
|
4
|
-
DatePickerProps as AriaDatePickerProps,
|
|
5
|
-
DateRangePicker as AriaDateRangePicker,
|
|
6
|
-
DateRangePickerProps as AriaDateRangePickerProps,
|
|
7
|
-
DateValue as AriaDateValue,
|
|
8
|
-
Dialog as AriaDialog,
|
|
9
|
-
DialogProps as AriaDialogProps,
|
|
10
|
-
PopoverProps as AriaPopoverProps,
|
|
11
|
-
composeRenderProps,
|
|
12
|
-
Popover
|
|
13
|
-
} from "react-aria-components"
|
|
14
|
-
|
|
15
|
-
import { getLocalTimeZone, parseAbsolute, type ZonedDateTime } from "@internationalized/date"
|
|
16
|
-
import { DateInput } from "lib/components/inputs/datefield"
|
|
17
|
-
import { FieldGroup, FormField, type FormFieldProps } from "lib/components/inputs/field"
|
|
18
|
-
import { Button } from "lib/components/ui/button"
|
|
19
|
-
import { Calendar, RangeCalendar } from "lib/components/ui/calendar"
|
|
20
|
-
import { useFieldContext } from "lib/utils/form-context"
|
|
21
|
-
import { getFieldErrorMessage } from "lib/utils/form-hook"
|
|
22
|
-
import { cn } from "lib/utils/primitives"
|
|
23
|
-
|
|
24
|
-
const DatePickerContent = ({
|
|
25
|
-
className,
|
|
26
|
-
popoverClassName,
|
|
27
|
-
...props
|
|
28
|
-
}: AriaDialogProps & { popoverClassName?: AriaPopoverProps["className"] }) => (
|
|
29
|
-
<Popover
|
|
30
|
-
className={composeRenderProps(popoverClassName, (className) =>
|
|
31
|
-
cn("w-auto p-3", className)
|
|
32
|
-
)}
|
|
33
|
-
>
|
|
34
|
-
<AriaDialog
|
|
35
|
-
className={cn(
|
|
36
|
-
"flex w-full flex-col gap-y-2 outline-none sm:flex-row sm:gap-x-icon sm:gap-y-0",
|
|
37
|
-
className
|
|
38
|
-
)}
|
|
39
|
-
{...props}
|
|
40
|
-
/>
|
|
41
|
-
</Popover>
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
interface DatePickerProps<T extends AriaDateValue> extends AriaDatePickerProps<T>, FormFieldProps { }
|
|
45
|
-
|
|
46
|
-
export function DatePicker<T extends AriaDateValue>({
|
|
47
|
-
label,
|
|
48
|
-
description,
|
|
49
|
-
errorMessage,
|
|
50
|
-
className,
|
|
51
|
-
...props
|
|
52
|
-
}: DatePickerProps<T>) {
|
|
53
|
-
return (
|
|
54
|
-
<AriaDatePicker
|
|
55
|
-
className={composeRenderProps(className, (className) =>
|
|
56
|
-
cn("group flex flex-col gap-2", className)
|
|
57
|
-
)}
|
|
58
|
-
{...props}
|
|
59
|
-
>
|
|
60
|
-
<FormField label={label} description={description} errorMessage={errorMessage}>
|
|
61
|
-
<FieldGroup aria-label={label}>
|
|
62
|
-
<DateInput className="flex-1" variant="ghost" />
|
|
63
|
-
<Button
|
|
64
|
-
variant="ghost"
|
|
65
|
-
size="icon"
|
|
66
|
-
className={'-me-2 ms-2'}
|
|
67
|
-
>
|
|
68
|
-
<CalendarIcon aria-hidden />
|
|
69
|
-
</Button>
|
|
70
|
-
</FieldGroup>
|
|
71
|
-
</FormField>
|
|
72
|
-
<DatePickerContent>
|
|
73
|
-
<Calendar />
|
|
74
|
-
</DatePickerContent>
|
|
75
|
-
</AriaDatePicker>
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function TfDatePicker({ ...props }: Omit<DatePickerProps<ZonedDateTime>, 'value' | 'onChange' | 'onBlur' | 'isInvalid' | 'errorMessage'>) {
|
|
80
|
-
const field = useFieldContext<string | null>();
|
|
81
|
-
return (
|
|
82
|
-
<DatePicker
|
|
83
|
-
hideTimeZone
|
|
84
|
-
value={field.state.value ? parseAbsolute(field.state.value, getLocalTimeZone()) : null}
|
|
85
|
-
onChange={(v) => v ? field.handleChange(v.toAbsoluteString()) : field.handleChange(null)}
|
|
86
|
-
onBlur={field.handleBlur}
|
|
87
|
-
isInvalid={!!getFieldErrorMessage(field)}
|
|
88
|
-
errorMessage={getFieldErrorMessage(field)}
|
|
89
|
-
{...props}
|
|
90
|
-
/>)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
interface DateRangePickerProps<T extends AriaDateValue> extends AriaDateRangePickerProps<T>, FormFieldProps { }
|
|
94
|
-
export function DateRangePicker<T extends AriaDateValue>({
|
|
95
|
-
label,
|
|
96
|
-
description,
|
|
97
|
-
errorMessage,
|
|
98
|
-
className,
|
|
99
|
-
...props
|
|
100
|
-
}: DateRangePickerProps<T>) {
|
|
101
|
-
return (
|
|
102
|
-
<AriaDateRangePicker
|
|
103
|
-
className={composeRenderProps(className, (className) =>
|
|
104
|
-
cn("group flex flex-col gap-2", className)
|
|
105
|
-
)}
|
|
106
|
-
{...props}
|
|
107
|
-
>
|
|
108
|
-
<FormField label={label} errorMessage={errorMessage} description={description}>
|
|
109
|
-
<FieldGroup>
|
|
110
|
-
<DateInput variant="ghost" slot={"start"} />
|
|
111
|
-
<span aria-hidden className="px-2 text-sm text-muted-foreground">
|
|
112
|
-
-
|
|
113
|
-
</span>
|
|
114
|
-
<DateInput className="flex-1" variant="ghost" slot={"end"} />
|
|
115
|
-
<Button
|
|
116
|
-
variant="ghost"
|
|
117
|
-
size="icon"
|
|
118
|
-
className="mr-1 data-[focus-visible]:ring-offset-0"
|
|
119
|
-
>
|
|
120
|
-
<CalendarIcon aria-hidden />
|
|
121
|
-
</Button>
|
|
122
|
-
</FieldGroup>
|
|
123
|
-
</FormField>
|
|
124
|
-
<DatePickerContent>
|
|
125
|
-
<RangeCalendar />
|
|
126
|
-
</DatePickerContent>
|
|
127
|
-
</AriaDateRangePicker>
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { VariantProps } from "class-variance-authority"
|
|
4
|
-
import {
|
|
5
|
-
DateField as AriaDateField,
|
|
6
|
-
DateFieldProps as AriaDateFieldProps,
|
|
7
|
-
DateInput as AriaDateInput,
|
|
8
|
-
DateInputProps as AriaDateInputProps,
|
|
9
|
-
DateSegment as AriaDateSegment,
|
|
10
|
-
DateSegmentProps as AriaDateSegmentProps,
|
|
11
|
-
DateValue as AriaDateValue,
|
|
12
|
-
TimeField as AriaTimeField,
|
|
13
|
-
TimeFieldProps as AriaTimeFieldProps,
|
|
14
|
-
TimeValue as AriaTimeValue,
|
|
15
|
-
composeRenderProps
|
|
16
|
-
} from "react-aria-components"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import { cn } from "lib/utils/primitives"
|
|
20
|
-
import { fieldGroupVariants, FormField, type FormFieldProps } from "./field"
|
|
21
|
-
|
|
22
|
-
export function DateSegment({ className, ...props }: AriaDateSegmentProps) {
|
|
23
|
-
return (
|
|
24
|
-
<AriaDateSegment
|
|
25
|
-
className={composeRenderProps(className, (className) =>
|
|
26
|
-
cn(
|
|
27
|
-
"inline caret-transparent outline-0",
|
|
28
|
-
/* Placeholder */
|
|
29
|
-
"data-[placeholder]:text-muted-foreground",
|
|
30
|
-
/* Disabled */
|
|
31
|
-
"disabled-muted",
|
|
32
|
-
/* Focused */
|
|
33
|
-
"data-[focused]:bg-accent data-[focused]:text-accent-foreground",
|
|
34
|
-
/* Invalid */
|
|
35
|
-
"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",
|
|
36
|
-
className
|
|
37
|
-
)
|
|
38
|
-
)}
|
|
39
|
-
{...props}
|
|
40
|
-
/>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface DateInputProps
|
|
45
|
-
extends AriaDateInputProps,
|
|
46
|
-
VariantProps<typeof fieldGroupVariants> { }
|
|
47
|
-
|
|
48
|
-
export function DateInput({
|
|
49
|
-
className,
|
|
50
|
-
variant,
|
|
51
|
-
...props
|
|
52
|
-
}: Omit<DateInputProps, "children">) {
|
|
53
|
-
return (
|
|
54
|
-
<AriaDateInput
|
|
55
|
-
className={composeRenderProps(className, (className) =>
|
|
56
|
-
cn(fieldGroupVariants({ variant }), "text-sm", className)
|
|
57
|
-
)}
|
|
58
|
-
{...props}
|
|
59
|
-
>
|
|
60
|
-
{(segment) => <DateSegment segment={segment} />}
|
|
61
|
-
</AriaDateInput>
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface DateFieldProps<T extends AriaDateValue> extends AriaDateFieldProps<T>, FormFieldProps { }
|
|
66
|
-
|
|
67
|
-
export function DateField<T extends AriaDateValue>({
|
|
68
|
-
label,
|
|
69
|
-
description,
|
|
70
|
-
className,
|
|
71
|
-
errorMessage,
|
|
72
|
-
...props
|
|
73
|
-
}: DateFieldProps<T>) {
|
|
74
|
-
return (
|
|
75
|
-
<AriaDateField
|
|
76
|
-
className={composeRenderProps(className, (className) =>
|
|
77
|
-
cn("group form-field", className)
|
|
78
|
-
)}
|
|
79
|
-
{...props}
|
|
80
|
-
>
|
|
81
|
-
<FormField label={label} description={description} errorMessage={errorMessage}>
|
|
82
|
-
<DateInput />
|
|
83
|
-
</FormField>
|
|
84
|
-
</AriaDateField>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
interface TimeFieldProps<T extends AriaTimeValue> extends AriaTimeFieldProps<T>, FormFieldProps { }
|
|
89
|
-
|
|
90
|
-
export function TimeField<T extends AriaTimeValue>({
|
|
91
|
-
label,
|
|
92
|
-
description,
|
|
93
|
-
errorMessage,
|
|
94
|
-
className,
|
|
95
|
-
...props
|
|
96
|
-
}: TimeFieldProps<T>) {
|
|
97
|
-
return (
|
|
98
|
-
<AriaTimeField
|
|
99
|
-
className={composeRenderProps(className, (className) =>
|
|
100
|
-
cn("group form-field", className)
|
|
101
|
-
)}
|
|
102
|
-
{...props}
|
|
103
|
-
>
|
|
104
|
-
<FormField label={label} description={description} errorMessage={errorMessage}>
|
|
105
|
-
<DateInput />
|
|
106
|
-
</FormField>
|
|
107
|
-
</AriaTimeField>
|
|
108
|
-
)
|
|
109
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
-
import {
|
|
5
|
-
Group as AriaGroup,
|
|
6
|
-
GroupProps as AriaGroupProps,
|
|
7
|
-
Label as AriaLabel,
|
|
8
|
-
LabelProps as AriaLabelProps,
|
|
9
|
-
Text as AriaText,
|
|
10
|
-
TextProps as AriaTextProps,
|
|
11
|
-
composeRenderProps
|
|
12
|
-
} from "react-aria-components"
|
|
13
|
-
|
|
14
|
-
import { cn } from "lib/utils/primitives"
|
|
15
|
-
import { CircleX, Info } from "lucide-react"
|
|
16
|
-
import type React from "react"
|
|
17
|
-
|
|
18
|
-
export const labelVariants = cva([
|
|
19
|
-
"select-none text-sm font-medium leading-none",
|
|
20
|
-
/* Disabled */
|
|
21
|
-
"disabled-muted",
|
|
22
|
-
/* Invalid */
|
|
23
|
-
"group-data-[invalid]:text-destructive",
|
|
24
|
-
])
|
|
25
|
-
|
|
26
|
-
export function FieldLabel({ className, ...props }: AriaLabelProps) {
|
|
27
|
-
return (
|
|
28
|
-
<AriaLabel className={cn(labelVariants(), className)} {...props} />
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function FieldDescription({ className, children, ...props }: AriaTextProps) {
|
|
33
|
-
return (
|
|
34
|
-
<AriaText
|
|
35
|
-
className={cn("text-sm text-muted leading-tight", className)}
|
|
36
|
-
{...props}
|
|
37
|
-
slot="description"
|
|
38
|
-
>
|
|
39
|
-
{children}<Info className="inline size-2 align-text-top ms-0.5" />
|
|
40
|
-
</AriaText>
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
// TODO, if we were to use AriaFieldError, it would use the internal ValidationState Context object, which might be useful for composing inputs but
|
|
44
|
-
// 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.
|
|
45
|
-
export function FieldError({ className, children, ...props }: React.ComponentPropsWithRef<'div'>) {
|
|
46
|
-
return (
|
|
47
|
-
<div
|
|
48
|
-
className={cn("text-sm leading-tight text-destructive duration-150 animate-in transition-transform slide-in-from-top-5 fade-in", className)}
|
|
49
|
-
{...props}
|
|
50
|
-
>
|
|
51
|
-
{children}<CircleX className="inline size-2 align-text-top ms-0.5" />
|
|
52
|
-
</div>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export const fieldGroupVariants = cva("", {
|
|
57
|
-
variants: {
|
|
58
|
-
variant: {
|
|
59
|
-
default: [
|
|
60
|
-
// TODO standardize the padding here
|
|
61
|
-
"relative flex h-input w-full items-center overflow-hidden border border-input bg-card px-2 py-2 text-sm ring-offset-background",
|
|
62
|
-
/* Focus Within */
|
|
63
|
-
"focus-ring",
|
|
64
|
-
/* Disabled */
|
|
65
|
-
"disabled-muted",
|
|
66
|
-
],
|
|
67
|
-
ghost: "",
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
defaultVariants: {
|
|
71
|
-
variant: "default",
|
|
72
|
-
},
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
export interface GroupProps
|
|
76
|
-
extends AriaGroupProps,
|
|
77
|
-
VariantProps<typeof fieldGroupVariants> { }
|
|
78
|
-
|
|
79
|
-
export function FieldGroup({ className, variant, ...props }: GroupProps) {
|
|
80
|
-
return (
|
|
81
|
-
<AriaGroup
|
|
82
|
-
className={composeRenderProps(className, (className) =>
|
|
83
|
-
cn(fieldGroupVariants({ variant }), className)
|
|
84
|
-
)}
|
|
85
|
-
{...props}
|
|
86
|
-
/>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export type FormFieldProps = {
|
|
91
|
-
label?: string
|
|
92
|
-
description?: React.ReactNode
|
|
93
|
-
errorMessage?: string
|
|
94
|
-
// | ((validation: AriaValidationResult) => string)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function FormField({ label, description, errorMessage, children }: FormFieldProps & {
|
|
98
|
-
children: React.ReactNode
|
|
99
|
-
}) {
|
|
100
|
-
return <>
|
|
101
|
-
{label && <FieldLabel>{label}</FieldLabel>}
|
|
102
|
-
{children}
|
|
103
|
-
{description && (<FieldDescription>{description}</FieldDescription>)}
|
|
104
|
-
{errorMessage && <FieldError>{errorMessage}</FieldError>}
|
|
105
|
-
</>
|
|
106
|
-
}
|