@bsol-oss/react-datatable5 12.0.0-beta.94 → 13.0.1-beta.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/README.md +1 -0
- package/dist/index.d.ts +170 -43
- package/dist/index.js +1166 -637
- package/dist/index.mjs +1168 -640
- package/dist/types/components/DataTable/DataTable.d.ts +1 -3
- package/dist/types/components/DataTable/DataTableServer.d.ts +7 -9
- package/dist/types/components/DataTable/DefaultTable.d.ts +2 -1
- package/dist/types/components/DataTable/context/DataTableContext.d.ts +4 -6
- package/dist/types/components/DataTable/controls/MobileTableControls.d.ts +29 -0
- package/dist/types/components/DataTable/controls/TableControls.d.ts +2 -2
- package/dist/types/components/DataTable/display/CalendarDisplay.d.ts +84 -0
- package/dist/types/components/DataTable/display/DataDisplay.d.ts +0 -2
- package/dist/types/components/DataTable/display/MobileTableDisplay.d.ts +5 -0
- package/dist/types/components/DataTable/display/RecordDisplay.d.ts +1 -3
- package/dist/types/components/DataTable/display/TextCell.d.ts +2 -1
- package/dist/types/components/DataTable/hooks/useIsMobile.d.ts +6 -0
- package/dist/types/components/DataTable/useDataTable.d.ts +3 -6
- package/dist/types/components/DataTable/useDataTableServer.d.ts +4 -4
- package/dist/types/components/DataTable/utils/getColumns.d.ts +3 -5
- package/dist/types/components/DatePicker/DatePicker.d.ts +7 -8
- package/dist/types/components/DatePicker/DateTimePicker.d.ts +3 -1
- package/dist/types/components/DatePicker/IsoTimePicker.d.ts +5 -1
- package/dist/types/components/DatePicker/RangeDatePicker.d.ts +4 -4
- package/dist/types/components/DatePicker/useCalendar.d.ts +48 -0
- package/dist/types/components/Form/SchemaFormContext.d.ts +5 -3
- package/dist/types/components/Form/components/core/FormBody.d.ts +1 -2
- package/dist/types/components/Form/components/core/FormRoot.d.ts +6 -4
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +1 -2
- package/dist/types/components/Form/components/fields/IdPicker.d.ts +8 -0
- package/dist/types/components/Form/components/fields/IdPickerMultiple.d.ts +7 -0
- package/dist/types/components/Form/components/fields/IdPickerSingle.d.ts +7 -0
- package/dist/types/components/Form/components/fields/useIdPickerData.d.ts +46 -0
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +9 -0
- package/dist/types/components/Form/useForm.d.ts +7 -2
- package/dist/types/components/Form/utils/useFormI18n.d.ts +14 -12
- package/dist/types/components/TimePicker/TimePicker.d.ts +4 -6
- package/dist/types/components/ui/provider.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -3
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, Skeleton, NumberInput, Show, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading } from '@chakra-ui/react';
|
|
2
|
+
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, Skeleton, NumberInput, Show, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading, Stack } from '@chakra-ui/react';
|
|
3
3
|
import { AiOutlineColumnWidth } from 'react-icons/ai';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import
|
|
5
|
+
import { createContext, useContext, useState, useMemo, useCallback, useEffect, useRef, forwardRef } from 'react';
|
|
6
6
|
import { LuX, LuCheck, LuChevronRight, LuCopy, LuExternalLink, LuSearch, LuImage, LuFile } from 'react-icons/lu';
|
|
7
7
|
import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineChecklist, MdClear, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdDateRange } from 'react-icons/md';
|
|
8
8
|
import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
|
|
9
9
|
import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
|
|
10
10
|
import { CgClose, CgTrash } from 'react-icons/cg';
|
|
11
|
-
import Dayzed from '@bsol-oss/dayzed-react19';
|
|
12
11
|
import { HiMiniEllipsisHorizontal, HiChevronLeft, HiChevronRight } from 'react-icons/hi2';
|
|
13
12
|
import { IoMdEye, IoMdCheckbox, IoMdClock } from 'react-icons/io';
|
|
14
13
|
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
@@ -24,7 +23,6 @@ import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
|
|
|
24
23
|
import { HiColorSwatch } from 'react-icons/hi';
|
|
25
24
|
import { flexRender, createColumnHelper, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel } from '@tanstack/react-table';
|
|
26
25
|
import { GrAscend, GrDescend } from 'react-icons/gr';
|
|
27
|
-
import { useTranslation } from 'react-i18next';
|
|
28
26
|
import axios from 'axios';
|
|
29
27
|
import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
|
|
30
28
|
import Ajv from 'ajv';
|
|
@@ -38,36 +36,35 @@ import { rankItem } from '@tanstack/match-sorter-utils';
|
|
|
38
36
|
|
|
39
37
|
const DataTableContext = createContext({
|
|
40
38
|
table: {},
|
|
41
|
-
globalFilter:
|
|
39
|
+
globalFilter: '',
|
|
42
40
|
setGlobalFilter: () => { },
|
|
43
|
-
type:
|
|
44
|
-
translate: {},
|
|
41
|
+
type: 'client',
|
|
45
42
|
data: [],
|
|
46
43
|
columns: [],
|
|
47
44
|
columnOrder: [],
|
|
48
45
|
columnFilters: [],
|
|
49
|
-
density:
|
|
46
|
+
density: 'sm',
|
|
50
47
|
sorting: [],
|
|
51
48
|
setPagination: function () {
|
|
52
|
-
throw new Error(
|
|
49
|
+
throw new Error('Function not implemented.');
|
|
53
50
|
},
|
|
54
51
|
setSorting: function () {
|
|
55
|
-
throw new Error(
|
|
52
|
+
throw new Error('Function not implemented.');
|
|
56
53
|
},
|
|
57
54
|
setColumnFilters: function () {
|
|
58
|
-
throw new Error(
|
|
55
|
+
throw new Error('Function not implemented.');
|
|
59
56
|
},
|
|
60
57
|
setRowSelection: function () {
|
|
61
|
-
throw new Error(
|
|
58
|
+
throw new Error('Function not implemented.');
|
|
62
59
|
},
|
|
63
60
|
setColumnOrder: function () {
|
|
64
|
-
throw new Error(
|
|
61
|
+
throw new Error('Function not implemented.');
|
|
65
62
|
},
|
|
66
63
|
setDensity: function () {
|
|
67
|
-
throw new Error(
|
|
64
|
+
throw new Error('Function not implemented.');
|
|
68
65
|
},
|
|
69
66
|
setColumnVisibility: function () {
|
|
70
|
-
throw new Error(
|
|
67
|
+
throw new Error('Function not implemented.');
|
|
71
68
|
},
|
|
72
69
|
pagination: {
|
|
73
70
|
pageIndex: 0,
|
|
@@ -76,21 +73,21 @@ const DataTableContext = createContext({
|
|
|
76
73
|
rowSelection: {},
|
|
77
74
|
columnVisibility: {},
|
|
78
75
|
tableLabel: {
|
|
79
|
-
view:
|
|
80
|
-
edit:
|
|
81
|
-
filterButtonText:
|
|
82
|
-
filterTitle:
|
|
83
|
-
filterReset:
|
|
84
|
-
filterClose:
|
|
85
|
-
reloadTooltip:
|
|
86
|
-
reloadButtonText:
|
|
87
|
-
resetSelection:
|
|
88
|
-
resetSorting:
|
|
89
|
-
rowCountText:
|
|
90
|
-
hasErrorText:
|
|
91
|
-
globalFilterPlaceholder:
|
|
92
|
-
trueLabel:
|
|
93
|
-
falseLabel:
|
|
76
|
+
view: 'View',
|
|
77
|
+
edit: 'Edit',
|
|
78
|
+
filterButtonText: 'Filter',
|
|
79
|
+
filterTitle: 'Filter',
|
|
80
|
+
filterReset: 'Reset',
|
|
81
|
+
filterClose: 'Close',
|
|
82
|
+
reloadTooltip: 'Reload',
|
|
83
|
+
reloadButtonText: 'Reload',
|
|
84
|
+
resetSelection: 'Reset Selection',
|
|
85
|
+
resetSorting: 'Reset Sorting',
|
|
86
|
+
rowCountText: '',
|
|
87
|
+
hasErrorText: 'Has Error',
|
|
88
|
+
globalFilterPlaceholder: 'Search',
|
|
89
|
+
trueLabel: 'True',
|
|
90
|
+
falseLabel: 'False',
|
|
94
91
|
},
|
|
95
92
|
});
|
|
96
93
|
|
|
@@ -167,6 +164,166 @@ const Radio = React.forwardRef(function Radio(props, ref) {
|
|
|
167
164
|
});
|
|
168
165
|
const RadioGroup = RadioGroup$1.Root;
|
|
169
166
|
|
|
167
|
+
// Helper function to check if two dates are the same day
|
|
168
|
+
function isSameDay(date1, date2) {
|
|
169
|
+
return (date1.getFullYear() === date2.getFullYear() &&
|
|
170
|
+
date1.getMonth() === date2.getMonth() &&
|
|
171
|
+
date1.getDate() === date2.getDate());
|
|
172
|
+
}
|
|
173
|
+
// Helper function to check if a date is today
|
|
174
|
+
function isToday(date) {
|
|
175
|
+
const today = new Date();
|
|
176
|
+
return isSameDay(date, today);
|
|
177
|
+
}
|
|
178
|
+
// Helper function to check if a date is selected
|
|
179
|
+
function isSelected(date, selected) {
|
|
180
|
+
if (!selected)
|
|
181
|
+
return false;
|
|
182
|
+
if (Array.isArray(selected)) {
|
|
183
|
+
return selected.some((d) => isSameDay(d, date));
|
|
184
|
+
}
|
|
185
|
+
return isSameDay(selected, date);
|
|
186
|
+
}
|
|
187
|
+
// Helper function to check if a date is selectable
|
|
188
|
+
function isSelectable(date, minDate, maxDate) {
|
|
189
|
+
if (minDate) {
|
|
190
|
+
// Normalize to start of day for comparison
|
|
191
|
+
const minDateStart = new Date(minDate);
|
|
192
|
+
minDateStart.setHours(0, 0, 0, 0);
|
|
193
|
+
const dateStart = new Date(date);
|
|
194
|
+
dateStart.setHours(0, 0, 0, 0);
|
|
195
|
+
if (dateStart < minDateStart)
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
if (maxDate) {
|
|
199
|
+
// Normalize to start of day for comparison
|
|
200
|
+
const maxDateStart = new Date(maxDate);
|
|
201
|
+
maxDateStart.setHours(0, 0, 0, 0);
|
|
202
|
+
const dateStart = new Date(date);
|
|
203
|
+
dateStart.setHours(0, 0, 0, 0);
|
|
204
|
+
if (dateStart > maxDateStart)
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
// Generate calendar weeks for a given month
|
|
210
|
+
function generateCalendarWeeks(year, month, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate) {
|
|
211
|
+
const weeks = [];
|
|
212
|
+
const firstDay = new Date(year, month, 1);
|
|
213
|
+
const lastDay = new Date(year, month + 1, 0);
|
|
214
|
+
// Get the first day of the week for the first day of the month
|
|
215
|
+
let firstDayWeekday = firstDay.getDay();
|
|
216
|
+
// Adjust for firstDayOfWeek
|
|
217
|
+
firstDayWeekday = (firstDayWeekday - firstDayOfWeek + 7) % 7;
|
|
218
|
+
// Start from the first day of the week that contains the first day of the month
|
|
219
|
+
const startDate = new Date(firstDay);
|
|
220
|
+
startDate.setDate(startDate.getDate() - firstDayWeekday);
|
|
221
|
+
let currentDate = new Date(startDate);
|
|
222
|
+
const endDate = new Date(lastDay);
|
|
223
|
+
// Find the last day of the week that contains the last day of the month
|
|
224
|
+
let lastDayWeekday = lastDay.getDay();
|
|
225
|
+
lastDayWeekday = (lastDayWeekday - firstDayOfWeek + 7) % 7;
|
|
226
|
+
endDate.setDate(endDate.getDate() + (6 - lastDayWeekday));
|
|
227
|
+
while (currentDate <= endDate) {
|
|
228
|
+
const week = [];
|
|
229
|
+
for (let i = 0; i < 7; i++) {
|
|
230
|
+
const date = new Date(currentDate);
|
|
231
|
+
const isCurrentMonth = date.getMonth() === month;
|
|
232
|
+
if (!showOutsideDays && !isCurrentMonth) {
|
|
233
|
+
week.push(null);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
const calendarDate = {
|
|
237
|
+
date,
|
|
238
|
+
selected: isSelected(date, selected),
|
|
239
|
+
selectable: isSelectable(date, minDate, maxDate) &&
|
|
240
|
+
(showOutsideDays || isCurrentMonth),
|
|
241
|
+
today: isToday(date),
|
|
242
|
+
isCurrentMonth,
|
|
243
|
+
};
|
|
244
|
+
week.push(calendarDate);
|
|
245
|
+
}
|
|
246
|
+
currentDate.setDate(currentDate.getDate() + 1);
|
|
247
|
+
}
|
|
248
|
+
weeks.push(week);
|
|
249
|
+
}
|
|
250
|
+
return weeks;
|
|
251
|
+
}
|
|
252
|
+
// Generate calendars for the given months
|
|
253
|
+
function generateCalendars(startDate, monthsToDisplay, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate) {
|
|
254
|
+
const calendars = [];
|
|
255
|
+
const currentDate = new Date(startDate);
|
|
256
|
+
for (let i = 0; i < monthsToDisplay; i++) {
|
|
257
|
+
const year = currentDate.getFullYear();
|
|
258
|
+
const month = currentDate.getMonth();
|
|
259
|
+
const weeks = generateCalendarWeeks(year, month, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate);
|
|
260
|
+
calendars.push({
|
|
261
|
+
month,
|
|
262
|
+
year,
|
|
263
|
+
weeks,
|
|
264
|
+
});
|
|
265
|
+
// Move to next month
|
|
266
|
+
currentDate.setMonth(month + 1);
|
|
267
|
+
}
|
|
268
|
+
return calendars;
|
|
269
|
+
}
|
|
270
|
+
function useCalendar({ selected, firstDayOfWeek = 0, showOutsideDays = true, date, minDate, maxDate, monthsToDisplay = 1, onDateSelected, }) {
|
|
271
|
+
const [currentDate, setCurrentDate] = useState(() => {
|
|
272
|
+
return date ? new Date(date) : new Date();
|
|
273
|
+
});
|
|
274
|
+
const calendars = useMemo(() => {
|
|
275
|
+
return generateCalendars(currentDate, monthsToDisplay, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate);
|
|
276
|
+
}, [
|
|
277
|
+
currentDate,
|
|
278
|
+
monthsToDisplay,
|
|
279
|
+
firstDayOfWeek,
|
|
280
|
+
showOutsideDays,
|
|
281
|
+
selected,
|
|
282
|
+
minDate,
|
|
283
|
+
maxDate,
|
|
284
|
+
]);
|
|
285
|
+
const navigate = useCallback((offset) => {
|
|
286
|
+
setCurrentDate((prev) => {
|
|
287
|
+
const newDate = new Date(prev);
|
|
288
|
+
newDate.setMonth(prev.getMonth() + offset);
|
|
289
|
+
return newDate;
|
|
290
|
+
});
|
|
291
|
+
}, []);
|
|
292
|
+
const getBackProps = useCallback((props) => {
|
|
293
|
+
return {
|
|
294
|
+
onClick: () => {
|
|
295
|
+
navigate(-(props?.offset || 1));
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}, [navigate]);
|
|
299
|
+
const getForwardProps = useCallback((props) => {
|
|
300
|
+
return {
|
|
301
|
+
onClick: () => {
|
|
302
|
+
navigate(props?.offset || 1);
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}, [navigate]);
|
|
306
|
+
const getDateProps = useCallback((props) => {
|
|
307
|
+
return {
|
|
308
|
+
onClick: () => {
|
|
309
|
+
if (props.dateObj.selectable && onDateSelected) {
|
|
310
|
+
onDateSelected({
|
|
311
|
+
date: props.dateObj.date,
|
|
312
|
+
selected: selected || props.dateObj.date,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
onMouseEnter: props.onMouseEnter,
|
|
317
|
+
};
|
|
318
|
+
}, [onDateSelected, selected]);
|
|
319
|
+
return {
|
|
320
|
+
calendars,
|
|
321
|
+
getBackProps,
|
|
322
|
+
getForwardProps,
|
|
323
|
+
getDateProps,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
170
327
|
const RangeDatePickerContext = createContext({
|
|
171
328
|
labels: {
|
|
172
329
|
monthNamesFull: [
|
|
@@ -232,7 +389,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
232
389
|
if (!dateObj) {
|
|
233
390
|
return jsx(Box, {}, key);
|
|
234
391
|
}
|
|
235
|
-
const { date, selected, selectable, today } = dateObj;
|
|
392
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
236
393
|
const getStyle = ({ selected, unavailable, today, isInRange, }) => {
|
|
237
394
|
if (unavailable) {
|
|
238
395
|
return {
|
|
@@ -270,7 +427,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
270
427
|
unavailable: !selectable,
|
|
271
428
|
today,
|
|
272
429
|
isInRange: isInRange(date),
|
|
273
|
-
}), children: selectable ? date.getDate() : 'X' }, key));
|
|
430
|
+
}), opacity: isCurrentMonth ? 1 : 0.4, children: selectable ? date.getDate() : 'X' }, key));
|
|
274
431
|
})) })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
275
432
|
}
|
|
276
433
|
return null;
|
|
@@ -293,10 +450,57 @@ const RangeDatePicker = ({ labels = {
|
|
|
293
450
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
294
451
|
backButtonLabel: 'Back',
|
|
295
452
|
forwardButtonLabel: 'Next',
|
|
296
|
-
}, selected = [], onDateSelected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay,
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
453
|
+
}, selected = [], onDateSelected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
|
|
454
|
+
const handleDateSelected = (obj) => {
|
|
455
|
+
if (onDateSelected) {
|
|
456
|
+
const dateObj = obj.date;
|
|
457
|
+
const currentSelected = Array.isArray(obj.selected)
|
|
458
|
+
? obj.selected
|
|
459
|
+
: [obj.selected];
|
|
460
|
+
// Range selection logic: if one date selected, add second; if two selected, replace with new date
|
|
461
|
+
let newSelected;
|
|
462
|
+
if (currentSelected.length === 0) {
|
|
463
|
+
newSelected = [dateObj];
|
|
464
|
+
}
|
|
465
|
+
else if (currentSelected.length === 1) {
|
|
466
|
+
const firstDate = currentSelected[0];
|
|
467
|
+
if (dateObj < firstDate) {
|
|
468
|
+
newSelected = [dateObj, firstDate];
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
newSelected = [firstDate, dateObj];
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
newSelected = [dateObj];
|
|
476
|
+
}
|
|
477
|
+
// Check if date is selectable
|
|
478
|
+
const selectable = !minDate || dateObj >= minDate;
|
|
479
|
+
if (maxDate) {
|
|
480
|
+
const isSelectable = dateObj <= maxDate;
|
|
481
|
+
if (!isSelectable)
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
onDateSelected({
|
|
485
|
+
selected: newSelected,
|
|
486
|
+
selectable,
|
|
487
|
+
date: dateObj,
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
const calendarData = useCalendar({
|
|
492
|
+
onDateSelected: handleDateSelected,
|
|
493
|
+
selected,
|
|
494
|
+
firstDayOfWeek,
|
|
495
|
+
showOutsideDays,
|
|
496
|
+
date,
|
|
497
|
+
minDate,
|
|
498
|
+
maxDate,
|
|
499
|
+
monthsToDisplay,
|
|
500
|
+
});
|
|
501
|
+
return (jsx(RangeDatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsx(Calendar$1, { ...calendarData,
|
|
502
|
+
firstDayOfWeek,
|
|
503
|
+
selected: selected })) }));
|
|
300
504
|
};
|
|
301
505
|
|
|
302
506
|
const getRangeDates = ({ selectable, date, selectedDates, }) => {
|
|
@@ -532,7 +736,7 @@ const MenuTrigger = Menu.Trigger;
|
|
|
532
736
|
|
|
533
737
|
const PageSizeControl = ({ pageSizes = [10, 20, 30, 40, 50], }) => {
|
|
534
738
|
const { table } = useDataTableContext();
|
|
535
|
-
return (jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children:
|
|
739
|
+
return (jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Button$1, { variant: 'ghost', gap: '0.5rem', children: table.getState().pagination.pageSize }) }), jsx(MenuContent, { children: pageSizes.map((pageSize) => (jsx(MenuItem, { value: `chakra-table-pageSize-${pageSize}`, onClick: () => {
|
|
536
740
|
table.setPageSize(Number(pageSize));
|
|
537
741
|
}, children: pageSize }, `chakra-table-pageSize-${pageSize}`))) })] }));
|
|
538
742
|
};
|
|
@@ -560,81 +764,149 @@ const PaginationRoot = React.forwardRef(function PaginationRoot(props, ref) {
|
|
|
560
764
|
}
|
|
561
765
|
const container = containerRef.current;
|
|
562
766
|
let rafId = null;
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
767
|
+
let timeoutId = null;
|
|
768
|
+
const measureButtonWidth = () => {
|
|
769
|
+
// Try to measure actual rendered buttons for accuracy
|
|
770
|
+
// Look for page number buttons (they contain numeric text)
|
|
771
|
+
const allButtons = container.querySelectorAll('button');
|
|
772
|
+
const pageButtons = [];
|
|
773
|
+
allButtons.forEach((button) => {
|
|
774
|
+
const text = button.textContent?.trim();
|
|
775
|
+
// Page buttons contain numbers, prev/next buttons contain icons
|
|
776
|
+
if (text && /^\d+$/.test(text)) {
|
|
777
|
+
pageButtons.push(button);
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
if (pageButtons.length > 0) {
|
|
781
|
+
// Measure multiple buttons and take the average for accuracy
|
|
782
|
+
let totalWidth = 0;
|
|
783
|
+
let count = 0;
|
|
784
|
+
pageButtons.forEach((button) => {
|
|
785
|
+
const width = button.offsetWidth;
|
|
786
|
+
if (width > 0) {
|
|
787
|
+
totalWidth += width;
|
|
788
|
+
count++;
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
if (count > 0) {
|
|
792
|
+
return Math.ceil(totalWidth / count);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
// Fallback to estimated widths based on size
|
|
571
796
|
const buttonWidthMap = {
|
|
572
797
|
xs: 28,
|
|
573
798
|
sm: 36,
|
|
574
799
|
md: 40,
|
|
575
800
|
lg: 44,
|
|
576
801
|
};
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
802
|
+
return buttonWidthMap[size] || 36;
|
|
803
|
+
};
|
|
804
|
+
const measurePrevNextWidth = () => {
|
|
805
|
+
const allButtons = container.querySelectorAll('button');
|
|
806
|
+
let prevWidth = 0;
|
|
807
|
+
let nextWidth = 0;
|
|
808
|
+
allButtons.forEach((button) => {
|
|
809
|
+
const html = button.innerHTML;
|
|
810
|
+
// Check if it's a prev/next button by looking for chevron icons or SVG
|
|
811
|
+
if (html.includes('chevron') ||
|
|
812
|
+
html.includes('Chevron') ||
|
|
813
|
+
button.querySelector('svg')) {
|
|
814
|
+
const width = button.offsetWidth;
|
|
815
|
+
if (width > 0) {
|
|
816
|
+
// First icon button is likely prev, last is next
|
|
817
|
+
if (prevWidth === 0) {
|
|
818
|
+
prevWidth = width;
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
nextWidth = width;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
587
824
|
}
|
|
825
|
+
});
|
|
826
|
+
if (prevWidth > 0 && nextWidth > 0) {
|
|
827
|
+
return prevWidth + nextWidth;
|
|
588
828
|
}
|
|
589
|
-
//
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
829
|
+
// Fallback: use page button width estimate
|
|
830
|
+
return measureButtonWidth() * 2;
|
|
831
|
+
};
|
|
832
|
+
const calculateSiblingCount = () => {
|
|
833
|
+
if (!container)
|
|
834
|
+
return;
|
|
835
|
+
const width = container.offsetWidth;
|
|
836
|
+
if (width === 0)
|
|
837
|
+
return;
|
|
838
|
+
// Measure actual button widths
|
|
839
|
+
const pageButtonWidth = measureButtonWidth();
|
|
840
|
+
const prevNextWidth = measurePrevNextWidth();
|
|
841
|
+
// Get computed gap from container (HStack gap)
|
|
842
|
+
const containerStyles = window.getComputedStyle(container);
|
|
843
|
+
const gap = parseFloat(containerStyles.gap) || 8;
|
|
844
|
+
// Account for gaps: prev button + gap + page buttons + gap + next button
|
|
845
|
+
// We need at least 2 gaps (before and after page buttons)
|
|
846
|
+
const availableWidth = Math.max(0, width - prevNextWidth - gap * 2);
|
|
594
847
|
// Each page button takes buttonWidth + gap
|
|
595
|
-
const buttonWithGap =
|
|
596
|
-
const
|
|
597
|
-
// Calculate sibling count
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const minRequired = 5;
|
|
604
|
-
const extraButtons = Math.max(0, maxButtons - minRequired);
|
|
605
|
-
// Calculate sibling count
|
|
606
|
-
// If we have enough space for ellipsis (2 buttons), account for that
|
|
848
|
+
const buttonWithGap = pageButtonWidth + gap;
|
|
849
|
+
const maxPageButtons = Math.floor(availableWidth / buttonWithGap);
|
|
850
|
+
// Calculate sibling count based on pagination structure
|
|
851
|
+
// Structure: [prev] [first] [ellipsis?] [siblings] [current] [siblings] [ellipsis?] [last] [next]
|
|
852
|
+
// Minimum: prev(1) + first(1) + current(1) + last(1) + next(1) = 5 buttons
|
|
853
|
+
// With siblings and ellipsis: 5 + siblings*2 + ellipsis*2
|
|
854
|
+
const minRequired = 5; // prev, first, current, last, next
|
|
855
|
+
const extraButtons = Math.max(0, maxPageButtons - minRequired);
|
|
607
856
|
let calculated = minSiblingCount;
|
|
608
857
|
if (extraButtons >= 4) {
|
|
609
|
-
//
|
|
858
|
+
// Enough space for ellipsis (2 buttons) + siblings on both sides
|
|
859
|
+
// Structure: [prev] [1] [...] [siblings] [current] [siblings] [...] [last] [next]
|
|
860
|
+
// Extra buttons = ellipsis(2) + siblings*2
|
|
610
861
|
calculated = Math.floor((extraButtons - 2) / 2);
|
|
611
862
|
}
|
|
612
863
|
else if (extraButtons >= 2) {
|
|
613
864
|
// Space for some siblings but not ellipsis
|
|
865
|
+
// Structure: [prev] [1] [siblings] [current] [siblings] [last] [next]
|
|
614
866
|
calculated = Math.floor(extraButtons / 2);
|
|
615
867
|
}
|
|
616
868
|
// Apply max limit if provided
|
|
617
869
|
if (maxSiblingCount !== undefined) {
|
|
618
870
|
calculated = Math.min(calculated, maxSiblingCount);
|
|
619
871
|
}
|
|
620
|
-
|
|
872
|
+
const finalSiblingCount = Math.max(minSiblingCount, calculated);
|
|
873
|
+
// Only update if value changed to avoid unnecessary re-renders
|
|
874
|
+
setCalculatedSiblingCount((prev) => {
|
|
875
|
+
if (prev !== finalSiblingCount) {
|
|
876
|
+
return finalSiblingCount;
|
|
877
|
+
}
|
|
878
|
+
return prev;
|
|
879
|
+
});
|
|
621
880
|
};
|
|
622
|
-
const
|
|
623
|
-
//
|
|
881
|
+
const scheduleCalculation = () => {
|
|
882
|
+
// Cancel any pending calculations
|
|
624
883
|
if (rafId !== null) {
|
|
625
884
|
cancelAnimationFrame(rafId);
|
|
626
885
|
}
|
|
627
|
-
|
|
628
|
-
|
|
886
|
+
if (timeoutId !== null) {
|
|
887
|
+
clearTimeout(timeoutId);
|
|
888
|
+
}
|
|
889
|
+
// Use requestAnimationFrame for smooth updates
|
|
890
|
+
rafId = requestAnimationFrame(() => {
|
|
891
|
+
// Small delay to ensure DOM is fully rendered
|
|
892
|
+
timeoutId = setTimeout(calculateSiblingCount, 50);
|
|
893
|
+
});
|
|
894
|
+
};
|
|
895
|
+
const resizeObserver = new ResizeObserver(scheduleCalculation);
|
|
629
896
|
resizeObserver.observe(container);
|
|
630
|
-
// Initial calculation
|
|
631
|
-
|
|
897
|
+
// Initial calculation - try multiple times to ensure buttons are rendered
|
|
898
|
+
scheduleCalculation();
|
|
899
|
+
// Also try after a longer delay as fallback
|
|
900
|
+
const fallbackTimeout = setTimeout(calculateSiblingCount, 200);
|
|
632
901
|
return () => {
|
|
633
902
|
resizeObserver.disconnect();
|
|
634
903
|
if (rafId !== null) {
|
|
635
904
|
cancelAnimationFrame(rafId);
|
|
636
905
|
}
|
|
637
|
-
|
|
906
|
+
if (timeoutId !== null) {
|
|
907
|
+
clearTimeout(timeoutId);
|
|
908
|
+
}
|
|
909
|
+
clearTimeout(fallbackTimeout);
|
|
638
910
|
};
|
|
639
911
|
}, [size, siblingCount, minSiblingCount, maxSiblingCount]);
|
|
640
912
|
const mergedRef = React.useCallback((node) => {
|
|
@@ -814,12 +1086,19 @@ const ResetSelectionButton = () => {
|
|
|
814
1086
|
const RowCountText = () => {
|
|
815
1087
|
const { table, type } = useDataTableContext();
|
|
816
1088
|
const getCount = () => {
|
|
817
|
-
if (type ===
|
|
1089
|
+
if (type === 'client') {
|
|
818
1090
|
return table.getFilteredRowModel().flatRows.length ?? 0;
|
|
819
1091
|
}
|
|
820
1092
|
return table.getRowCount();
|
|
821
1093
|
};
|
|
822
|
-
|
|
1094
|
+
const totalCount = getCount();
|
|
1095
|
+
const { pageIndex, pageSize } = table.getState().pagination;
|
|
1096
|
+
if (totalCount === 0) {
|
|
1097
|
+
return jsx(Text, { children: "0 of 0" });
|
|
1098
|
+
}
|
|
1099
|
+
const start = pageIndex * pageSize + 1;
|
|
1100
|
+
const end = Math.min((pageIndex + 1) * pageSize, totalCount);
|
|
1101
|
+
return jsx(Text, { children: `${start}-${end} / ${totalCount}` });
|
|
823
1102
|
};
|
|
824
1103
|
|
|
825
1104
|
// pulling this into a separate file so adapter(s) that don't
|
|
@@ -2928,17 +3207,17 @@ const TableFilterTags = () => {
|
|
|
2928
3207
|
|
|
2929
3208
|
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsx(Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
|
|
2930
3209
|
const { tableLabel, table } = useDataTableContext();
|
|
2931
|
-
const {
|
|
2932
|
-
return (jsxs(Grid, { templateRows:
|
|
3210
|
+
const { hasErrorText } = tableLabel;
|
|
3211
|
+
return (jsxs(Grid, { templateRows: 'auto 1fr', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: '0.5rem', p: 1, ...gridProps, children: [jsxs(Flex, { flexFlow: 'column', gap: 2, children: [jsxs(Flex, { justifyContent: 'space-between', children: [jsx(Box, { children: showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }) }), jsxs(Flex, { gap: '0.5rem', alignItems: 'center', justifySelf: 'end', children: [loading && jsx(Spinner, { size: 'sm' }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: 'red.400' }) })), showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsx(Flex, { flexFlow: 'column', gap: '0.5rem', children: filterTagsOptions.map((option) => {
|
|
2933
3212
|
const { column, options } = option;
|
|
2934
3213
|
const tableColumn = table.getColumn(column);
|
|
2935
|
-
return (jsxs(Flex, { alignItems:
|
|
3214
|
+
return (jsxs(Flex, { alignItems: 'center', flexFlow: 'wrap', gap: '0.5rem', children: [tableColumn?.columnDef.meta?.displayName && (jsx(Text, { children: tableColumn?.columnDef.meta?.displayName })), jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
|
|
2936
3215
|
if (tags.length === 0) {
|
|
2937
3216
|
return tableColumn?.setFilterValue(undefined);
|
|
2938
3217
|
}
|
|
2939
3218
|
tableColumn?.setFilterValue(tags);
|
|
2940
3219
|
} })] }, column));
|
|
2941
|
-
}) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, {
|
|
3220
|
+
}) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, { children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Flex, { justifyContent: 'space-between', children: [jsxs(Flex, { gap: '1rem', alignItems: 'center', children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && jsx(RowCountText, {})] }), jsx(Box, { justifySelf: 'end', children: showPagination && jsx(Pagination, {}) })] }))] }));
|
|
2942
3221
|
};
|
|
2943
3222
|
|
|
2944
3223
|
const EmptyState$1 = React.forwardRef(function EmptyState(props, ref) {
|
|
@@ -3100,7 +3379,7 @@ const Table = ({ children, emptyComponent = EmptyResult, canResize = true, showL
|
|
|
3100
3379
|
if (!showLoading && table.getRowModel().rows.length <= 0) {
|
|
3101
3380
|
return emptyComponent;
|
|
3102
3381
|
}
|
|
3103
|
-
return (jsx(Box, { ref: containerRef, width: "100%", overflow: "auto", children: jsx(Table$1.Root, { stickyHeader: true,
|
|
3382
|
+
return (jsx(Box, { ref: containerRef, width: "100%", overflow: "auto", children: jsx(Table$1.Root, { stickyHeader: true, width: canResize ? table.getCenterTotalSize() : undefined, display: 'grid', alignContent: 'start', ...props, children: children }) }));
|
|
3104
3383
|
};
|
|
3105
3384
|
|
|
3106
3385
|
const Checkbox = React.forwardRef(function Checkbox(props, ref) {
|
|
@@ -3146,11 +3425,7 @@ const TableBody = ({ showSelector = false, canResize = true, }) => {
|
|
|
3146
3425
|
// styling resize and pinning start
|
|
3147
3426
|
flex: `${canResize ? '0' : '1'} 0 ${cell.column.getSize()}px`,
|
|
3148
3427
|
// this is to avoid the cell from being too wide
|
|
3149
|
-
minWidth: `0`,
|
|
3150
|
-
base: 'colorPalette.900',
|
|
3151
|
-
_dark: 'colorPalette.100',
|
|
3152
|
-
},
|
|
3153
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...getTdProps(cell), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
3428
|
+
minWidth: `0`, ...getTdProps(cell), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
3154
3429
|
})] }, `chakra-table-row-${row.id}`));
|
|
3155
3430
|
}) }));
|
|
3156
3431
|
};
|
|
@@ -3160,11 +3435,7 @@ const TableRowSelector = ({ row }) => {
|
|
|
3160
3435
|
const isSelected = isRowSelected(row.id, rowSelection);
|
|
3161
3436
|
const canSelect = canRowSelect(row);
|
|
3162
3437
|
const toggleHandler = createRowToggleHandler(row, rowSelection, setRowSelection);
|
|
3163
|
-
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid',
|
|
3164
|
-
base: 'colorPalette.900',
|
|
3165
|
-
_dark: 'colorPalette.100',
|
|
3166
|
-
},
|
|
3167
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: isSelected,
|
|
3438
|
+
return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid', justifyItems: 'center', alignItems: 'center', children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: isSelected,
|
|
3168
3439
|
disabled: !canSelect,
|
|
3169
3440
|
onCheckedChange: toggleHandler }) }));
|
|
3170
3441
|
};
|
|
@@ -3281,18 +3552,6 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3281
3552
|
const columnMeta = header.column.columnDef.meta;
|
|
3282
3553
|
return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
|
|
3283
3554
|
};
|
|
3284
|
-
const getThProps = (header) => {
|
|
3285
|
-
const thProps = header.column.getIsPinned()
|
|
3286
|
-
? {
|
|
3287
|
-
left: showSelector
|
|
3288
|
-
? `${header.getStart('left') + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3289
|
-
: `${header.getStart('left')}px`,
|
|
3290
|
-
position: 'sticky',
|
|
3291
|
-
zIndex: 100 + 1,
|
|
3292
|
-
}
|
|
3293
|
-
: {};
|
|
3294
|
-
return thProps;
|
|
3295
|
-
};
|
|
3296
3555
|
const stickyProps = {
|
|
3297
3556
|
position: 'sticky',
|
|
3298
3557
|
top: 0,
|
|
@@ -3344,11 +3603,7 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3344
3603
|
[header.id]: finalWidth,
|
|
3345
3604
|
}));
|
|
3346
3605
|
};
|
|
3347
|
-
return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}),
|
|
3348
|
-
base: 'colorPalette.900',
|
|
3349
|
-
_dark: 'colorPalette.100',
|
|
3350
|
-
},
|
|
3351
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: areAllRowsSelected(table, rowSelection),
|
|
3606
|
+
return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}), ...tableHeaderProps, children: table.getHeaderGroups().map((headerGroup) => (jsxs(Table$1.Row, { display: 'flex', ...tableRowProps, children: [showSelector && (jsx(Table$1.ColumnHeader, { padding: `${table.getDensityValue()}px`, display: 'grid', justifyItems: 'center', alignItems: 'center', children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: areAllRowsSelected(table, rowSelection),
|
|
3352
3607
|
// indeterminate: areSomeRowsSelected(table, rowSelection),
|
|
3353
3608
|
onChange: createToggleAllRowsHandler(table, rowSelection, setRowSelection) }) })), headerGroup.headers.map((header) => {
|
|
3354
3609
|
const resizeProps = {
|
|
@@ -3358,30 +3613,11 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3358
3613
|
};
|
|
3359
3614
|
return (jsxs(Table$1.ColumnHeader, { padding: 0, columnSpan: `${header.colSpan}`,
|
|
3360
3615
|
// styling resize and pinning start
|
|
3361
|
-
flex: `${canResize ? '0' : '1'} 0 ${header.column.getSize()}px`, display: 'grid', gridTemplateColumns: '1fr auto', zIndex: 1500 + header.index,
|
|
3362
|
-
base: 'colorPalette.800',
|
|
3363
|
-
_dark: 'colorPalette.200',
|
|
3364
|
-
},
|
|
3365
|
-
bg: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, ...getThProps(header), children: [jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Flex, { padding: `${table.getDensityValue()}px`, alignItems: 'center', justifyContent: 'start', borderRadius: '0rem', overflow: 'auto', color: {
|
|
3366
|
-
base: 'colorPalette.800',
|
|
3367
|
-
_dark: 'colorPalette.200',
|
|
3368
|
-
_hover: {
|
|
3369
|
-
base: 'colorPalette.700',
|
|
3370
|
-
_dark: 'colorPalette.300',
|
|
3371
|
-
},
|
|
3372
|
-
},
|
|
3373
|
-
bg: {
|
|
3374
|
-
base: 'colorPalette.100',
|
|
3375
|
-
_dark: 'colorPalette.900',
|
|
3376
|
-
_hover: {
|
|
3377
|
-
base: 'colorPalette.200',
|
|
3378
|
-
_dark: 'colorPalette.800',
|
|
3379
|
-
},
|
|
3380
|
-
}, children: jsxs(Flex, { gap: "0.5rem", alignItems: 'center', children: [header.isPlaceholder
|
|
3616
|
+
flex: `${canResize ? '0' : '1'} 0 ${header.column.getSize()}px`, display: 'grid', gridTemplateColumns: '1fr auto', zIndex: 1500 + header.index, children: [jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Flex, { padding: `${table.getDensityValue()}px`, alignItems: 'center', justifyContent: 'start', borderRadius: '0rem', overflow: 'auto', children: jsxs(Flex, { gap: "0.5rem", alignItems: 'center', children: [header.isPlaceholder
|
|
3381
3617
|
? null
|
|
3382
3618
|
: flexRender(header.column.columnDef.header, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && jsx(Fragment, {}), header.column.getIsSorted() === 'asc' && (jsx(BiUpArrow, {})), header.column.getIsSorted() === 'desc' && (jsx(BiDownArrow, {}))] })) }), jsx(Box, { children: header.column.getIsFiltered() && jsx(MdFilterListAlt, {}) })] }) }) }), jsxs(MenuContent, { children: [!header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "pin-column", children: jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3383
3619
|
header.column.pin('left');
|
|
3384
|
-
}, children: [jsx(MdPushPin, {}), getHeaderText(header, 'pinColumn')] }) })), header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3620
|
+
}, p: 1, children: [jsx(MdPushPin, {}), getHeaderText(header, 'pinColumn')] }) })), header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3385
3621
|
header.column.pin(false);
|
|
3386
3622
|
}, children: [jsx(MdCancel, {}), getHeaderText(header, 'cancelPin')] }) })), header.column.getCanSort() && (jsxs(Fragment, { children: [jsx(MenuItem, { asChild: true, value: "sort-ascend", children: jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3387
3623
|
table.setSorting((state) => {
|
|
@@ -3494,14 +3730,14 @@ const highlightText = (text, searchTerm) => {
|
|
|
3494
3730
|
}
|
|
3495
3731
|
return parts.length > 0 ? jsx(Fragment, { children: parts }) : textStr;
|
|
3496
3732
|
};
|
|
3497
|
-
const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, globalFilter, }) => {
|
|
3733
|
+
const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, globalFilter, alignEnd = false, }) => {
|
|
3498
3734
|
const highlightedText = useMemo(() => highlightText(text ?? '', globalFilter), [text, globalFilter]);
|
|
3499
3735
|
if (isBadge) {
|
|
3500
3736
|
return (jsx(Badge, { colorPalette: colorPalette || badgeColor, children: highlightedText }));
|
|
3501
3737
|
}
|
|
3502
3738
|
// onClick takes precedence over href
|
|
3503
3739
|
if (onClick) {
|
|
3504
|
-
return (jsx(Box, { as: "button", onClick: onClick, cursor: "pointer", textAlign:
|
|
3740
|
+
return (jsx(Box, { as: "button", onClick: onClick, cursor: "pointer", textAlign: alignEnd ? 'right' : 'left', _hover: {
|
|
3505
3741
|
textDecoration: 'underline',
|
|
3506
3742
|
color: {
|
|
3507
3743
|
base: 'blue.500',
|
|
@@ -3519,7 +3755,7 @@ const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, col
|
|
|
3519
3755
|
}
|
|
3520
3756
|
return jsx(Fragment, { children: highlightedText });
|
|
3521
3757
|
};
|
|
3522
|
-
const TextCell = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette,
|
|
3758
|
+
const TextCell = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, alignEnd = false,
|
|
3523
3759
|
// Legacy props
|
|
3524
3760
|
label, containerProps = {}, textProps = {}, children, }) => {
|
|
3525
3761
|
// Get globalFilter from context
|
|
@@ -3533,23 +3769,25 @@ label, containerProps = {}, textProps = {}, children, }) => {
|
|
|
3533
3769
|
const highlightedDisplayText = typeof displayText === 'string' || typeof displayText === 'number'
|
|
3534
3770
|
? highlightText(displayText, globalFilter)
|
|
3535
3771
|
: displayText;
|
|
3772
|
+
const flexJustifyContent = alignEnd ? 'flex-end' : undefined;
|
|
3773
|
+
const textAlign = alignEnd ? 'right' : undefined;
|
|
3536
3774
|
if (label) {
|
|
3537
|
-
return (jsx(Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsx(Tooltip, { content: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', children: label }), children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }) }));
|
|
3775
|
+
return (jsx(Flex, { alignItems: 'center', justifyContent: flexJustifyContent, height: '100%', ...containerProps, children: jsx(Tooltip, { content: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', children: label }), children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', textAlign: textAlign, ...textProps, children: highlightedDisplayText }) }) }));
|
|
3538
3776
|
}
|
|
3539
|
-
return (jsx(Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }));
|
|
3777
|
+
return (jsx(Flex, { alignItems: 'center', justifyContent: flexJustifyContent, height: '100%', ...containerProps, children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', textAlign: textAlign, ...textProps, children: highlightedDisplayText }) }));
|
|
3540
3778
|
}
|
|
3541
3779
|
// New API: use text prop
|
|
3542
3780
|
const displayValue = text ?? children;
|
|
3543
3781
|
if (Array.isArray(displayValue)) {
|
|
3544
|
-
return (jsx(Flex, { gap: 2, flexWrap: "wrap", children: displayValue.map((item, index) => {
|
|
3782
|
+
return (jsx(Flex, { gap: 2, flexWrap: "wrap", justifyContent: alignEnd ? 'flex-end' : undefined, children: displayValue.map((item, index) => {
|
|
3545
3783
|
const highlightedItem = highlightText(item, globalFilter);
|
|
3546
3784
|
return (jsx(Badge, { colorPalette: colorPalette || badgeColor, children: highlightedItem }, index));
|
|
3547
3785
|
}) }));
|
|
3548
3786
|
}
|
|
3549
3787
|
if (!!displayValue === false) {
|
|
3550
|
-
return (jsx(Text, { textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden", wordBreak: "break-all", display: "flex", alignItems: "center", height: "100%", children: "-" }));
|
|
3788
|
+
return (jsx(Text, { textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden", wordBreak: "break-all", display: "flex", alignItems: "center", justifyContent: alignEnd ? 'flex-end' : undefined, height: "100%", textAlign: alignEnd ? 'right' : undefined, children: "-" }));
|
|
3551
3789
|
}
|
|
3552
|
-
return (jsx(Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", height: "100%", children: jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter }) }));
|
|
3790
|
+
return (jsx(Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", justifyContent: alignEnd ? 'flex-end' : undefined, height: "100%", textAlign: alignEnd ? 'right' : undefined, children: jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter, alignEnd: alignEnd }) }));
|
|
3553
3791
|
};
|
|
3554
3792
|
|
|
3555
3793
|
const Tag = React.forwardRef(function Tag(props, ref) {
|
|
@@ -3579,7 +3817,7 @@ const ErrorAlert = ({ showMessage = true }) => {
|
|
|
3579
3817
|
const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: defaultPagination = {
|
|
3580
3818
|
pageIndex: 0, //initial page index
|
|
3581
3819
|
pageSize: 10, //default page size
|
|
3582
|
-
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter =
|
|
3820
|
+
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = '', density: defaultDensity = 'sm', } = {
|
|
3583
3821
|
sorting: [],
|
|
3584
3822
|
pagination: {
|
|
3585
3823
|
pageIndex: 0, //initial page index
|
|
@@ -3589,9 +3827,9 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3589
3827
|
columnFilters: [],
|
|
3590
3828
|
columnOrder: [],
|
|
3591
3829
|
columnVisibility: {},
|
|
3592
|
-
globalFilter:
|
|
3593
|
-
density:
|
|
3594
|
-
},
|
|
3830
|
+
globalFilter: '',
|
|
3831
|
+
density: 'sm',
|
|
3832
|
+
}, } = {
|
|
3595
3833
|
default: {
|
|
3596
3834
|
sorting: [],
|
|
3597
3835
|
pagination: {
|
|
@@ -3602,8 +3840,8 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3602
3840
|
columnFilters: [],
|
|
3603
3841
|
columnOrder: [],
|
|
3604
3842
|
columnVisibility: {},
|
|
3605
|
-
globalFilter:
|
|
3606
|
-
density:
|
|
3843
|
+
globalFilter: '',
|
|
3844
|
+
density: 'sm',
|
|
3607
3845
|
},
|
|
3608
3846
|
}) => {
|
|
3609
3847
|
const [sorting, setSorting] = useState(defaultSorting);
|
|
@@ -3614,7 +3852,6 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3614
3852
|
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter);
|
|
3615
3853
|
const [density, setDensity] = useState(defaultDensity);
|
|
3616
3854
|
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility);
|
|
3617
|
-
const translate = useTranslation("", { keyPrefix });
|
|
3618
3855
|
return {
|
|
3619
3856
|
sorting,
|
|
3620
3857
|
setSorting,
|
|
@@ -3632,12 +3869,11 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3632
3869
|
setDensity,
|
|
3633
3870
|
columnVisibility,
|
|
3634
3871
|
setColumnVisibility,
|
|
3635
|
-
translate,
|
|
3636
3872
|
};
|
|
3637
3873
|
};
|
|
3638
3874
|
|
|
3639
3875
|
const useDataTableServer = (props) => {
|
|
3640
|
-
const { url, default: defaultProps,
|
|
3876
|
+
const { url, default: defaultProps, placeholderData, queryFn: customQueryFn, } = props;
|
|
3641
3877
|
const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
|
|
3642
3878
|
const [sorting, setSorting] = useState(defaultSorting || []);
|
|
3643
3879
|
const [columnFilters, setColumnFilters] = useState(defaultColumnFilters || []); // can set initial column filter state here
|
|
@@ -3647,8 +3883,8 @@ const useDataTableServer = (props) => {
|
|
|
3647
3883
|
});
|
|
3648
3884
|
const [rowSelection, setRowSelection] = useState(defaultRowSelection || {});
|
|
3649
3885
|
const [columnOrder, setColumnOrder] = useState(defaultColumnOrder || []);
|
|
3650
|
-
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter ||
|
|
3651
|
-
const [density, setDensity] = useState(defaultDensity ||
|
|
3886
|
+
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter || '');
|
|
3887
|
+
const [density, setDensity] = useState(defaultDensity || 'sm');
|
|
3652
3888
|
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility || {});
|
|
3653
3889
|
const { pageSize, pageIndex } = pagination;
|
|
3654
3890
|
const params = {
|
|
@@ -3660,7 +3896,7 @@ const useDataTableServer = (props) => {
|
|
|
3660
3896
|
};
|
|
3661
3897
|
const defaultQueryFn = async () => {
|
|
3662
3898
|
if (!url) {
|
|
3663
|
-
throw new Error(
|
|
3899
|
+
throw new Error('url is required');
|
|
3664
3900
|
}
|
|
3665
3901
|
const response = await axios.get(url, {
|
|
3666
3902
|
params,
|
|
@@ -3674,7 +3910,6 @@ const useDataTableServer = (props) => {
|
|
|
3674
3910
|
: defaultQueryFn,
|
|
3675
3911
|
placeholderData,
|
|
3676
3912
|
});
|
|
3677
|
-
const translate = useTranslation("", { keyPrefix });
|
|
3678
3913
|
return {
|
|
3679
3914
|
sorting,
|
|
3680
3915
|
setSorting,
|
|
@@ -3693,7 +3928,6 @@ const useDataTableServer = (props) => {
|
|
|
3693
3928
|
columnVisibility,
|
|
3694
3929
|
setColumnVisibility,
|
|
3695
3930
|
query,
|
|
3696
|
-
translate,
|
|
3697
3931
|
};
|
|
3698
3932
|
};
|
|
3699
3933
|
|
|
@@ -3712,11 +3946,8 @@ const snakeToLabel = (str) => {
|
|
|
3712
3946
|
.join(" "); // Join with space
|
|
3713
3947
|
};
|
|
3714
3948
|
|
|
3715
|
-
const RecordDisplay = ({ object, boxProps,
|
|
3949
|
+
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
3716
3950
|
const getColumn = ({ field }) => {
|
|
3717
|
-
if (translate !== undefined) {
|
|
3718
|
-
return translate.t(`${prefix}${field}`);
|
|
3719
|
-
}
|
|
3720
3951
|
return snakeToLabel(field);
|
|
3721
3952
|
};
|
|
3722
3953
|
if (object === null) {
|
|
@@ -3724,7 +3955,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = '', }) => {
|
|
|
3724
3955
|
}
|
|
3725
3956
|
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
3726
3957
|
const uniqueKey = `${prefix}${field}-${index}`;
|
|
3727
|
-
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}
|
|
3958
|
+
return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsx(Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsx(Text, { children: JSON.stringify(value) }))] }, uniqueKey));
|
|
3728
3959
|
}) }));
|
|
3729
3960
|
};
|
|
3730
3961
|
|
|
@@ -3738,15 +3969,12 @@ const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
|
3738
3969
|
throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
|
|
3739
3970
|
}
|
|
3740
3971
|
};
|
|
3741
|
-
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400,
|
|
3972
|
+
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
|
|
3742
3973
|
const { properties } = schema;
|
|
3743
|
-
idListSanityCheck(
|
|
3974
|
+
idListSanityCheck('ignore', ignore, properties);
|
|
3744
3975
|
widthSanityCheck(width, ignore, properties);
|
|
3745
|
-
idListSanityCheck(
|
|
3976
|
+
idListSanityCheck('meta', Object.keys(meta), properties);
|
|
3746
3977
|
const getColumn = ({ column }) => {
|
|
3747
|
-
if (translate !== undefined) {
|
|
3748
|
-
return translate.t(`${column}`);
|
|
3749
|
-
}
|
|
3750
3978
|
return snakeToLabel(column);
|
|
3751
3979
|
};
|
|
3752
3980
|
const keys = Object.keys(properties);
|
|
@@ -3755,15 +3983,15 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
|
|
|
3755
3983
|
return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
|
|
3756
3984
|
});
|
|
3757
3985
|
const columnHelper = createColumnHelper();
|
|
3758
|
-
// @ts-expect-error find type for unknown
|
|
3759
3986
|
const columns = [
|
|
3760
3987
|
...ignored.map((column, index) => {
|
|
3988
|
+
// @ts-expect-error column accessor type issue with generic TData
|
|
3761
3989
|
return columnHelper.accessor(column, {
|
|
3762
3990
|
cell: (props) => {
|
|
3763
3991
|
// @ts-expect-error find type for unknown
|
|
3764
3992
|
const value = props.row.original[column];
|
|
3765
|
-
if (typeof value ===
|
|
3766
|
-
return (jsx(Grid, { overflow:
|
|
3993
|
+
if (typeof value === 'object') {
|
|
3994
|
+
return (jsx(Grid, { overflow: 'auto', children: jsx(RecordDisplay, { object: value }) }));
|
|
3767
3995
|
}
|
|
3768
3996
|
return jsx(TextCell, { children: value });
|
|
3769
3997
|
},
|
|
@@ -3795,6 +4023,11 @@ const SchemaFormContext = createContext({
|
|
|
3795
4023
|
include: [],
|
|
3796
4024
|
onSubmit: async () => { },
|
|
3797
4025
|
rowNumber: 0,
|
|
4026
|
+
/** Default translate fallback - returns key as-is */
|
|
4027
|
+
translate: {
|
|
4028
|
+
t: (key) => key,
|
|
4029
|
+
ready: true,
|
|
4030
|
+
},
|
|
3798
4031
|
requestOptions: {},
|
|
3799
4032
|
timezone: 'Asia/Hong_Kong',
|
|
3800
4033
|
displayConfig: {
|
|
@@ -4027,7 +4260,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4027
4260
|
showSubmitButton: true,
|
|
4028
4261
|
showResetButton: true,
|
|
4029
4262
|
showTitle: true,
|
|
4030
|
-
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, insideDialog = false, }) => {
|
|
4263
|
+
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
4031
4264
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
4032
4265
|
const [isError, setIsError] = useState(false);
|
|
4033
4266
|
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
@@ -4118,6 +4351,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4118
4351
|
enumPickerLabels,
|
|
4119
4352
|
filePickerLabels,
|
|
4120
4353
|
formButtonLabels,
|
|
4354
|
+
timePickerLabels,
|
|
4121
4355
|
ajvResolver: ajvResolver(schema),
|
|
4122
4356
|
insideDialog,
|
|
4123
4357
|
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
@@ -4128,31 +4362,33 @@ function removeIndex(str) {
|
|
|
4128
4362
|
}
|
|
4129
4363
|
|
|
4130
4364
|
/**
|
|
4131
|
-
* Custom hook
|
|
4365
|
+
* Custom hook for form field labels and fallback text.
|
|
4132
4366
|
* Automatically handles colLabel construction and removeIndex logic.
|
|
4367
|
+
* Uses schema.title when available, otherwise falls back to translate function.
|
|
4133
4368
|
*
|
|
4134
4369
|
* @param column - The column name
|
|
4135
4370
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4136
|
-
* @
|
|
4371
|
+
* @param schema - Optional schema object with title property
|
|
4372
|
+
* @returns Object with label helper functions
|
|
4137
4373
|
*
|
|
4138
4374
|
* @example
|
|
4139
4375
|
* ```tsx
|
|
4140
|
-
* const formI18n = useFormI18n(column, prefix);
|
|
4376
|
+
* const formI18n = useFormI18n(column, prefix, schema);
|
|
4141
4377
|
*
|
|
4142
|
-
* // Get field label
|
|
4378
|
+
* // Get field label (prefers schema.title)
|
|
4143
4379
|
* <Field label={formI18n.label()} />
|
|
4144
4380
|
*
|
|
4145
|
-
* // Get error message
|
|
4381
|
+
* // Get required error message
|
|
4146
4382
|
* <Text>{formI18n.required()}</Text>
|
|
4147
4383
|
*
|
|
4148
|
-
* // Get custom
|
|
4384
|
+
* // Get custom text
|
|
4149
4385
|
* <Text>{formI18n.t('add_more')}</Text>
|
|
4150
4386
|
*
|
|
4151
4387
|
* // Access the raw colLabel
|
|
4152
4388
|
* const colLabel = formI18n.colLabel;
|
|
4153
4389
|
* ```
|
|
4154
4390
|
*/
|
|
4155
|
-
const useFormI18n
|
|
4391
|
+
const useFormI18n = (column, prefix = '', schema) => {
|
|
4156
4392
|
const { translate } = useSchemaContext();
|
|
4157
4393
|
const colLabel = `${prefix}${column}`;
|
|
4158
4394
|
return {
|
|
@@ -4161,7 +4397,7 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4161
4397
|
*/
|
|
4162
4398
|
colLabel,
|
|
4163
4399
|
/**
|
|
4164
|
-
* Get the field label from schema title prop, or fall back to
|
|
4400
|
+
* Get the field label from schema title prop, or fall back to translate function
|
|
4165
4401
|
* Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
4166
4402
|
*/
|
|
4167
4403
|
label: (options) => {
|
|
@@ -4171,18 +4407,18 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4171
4407
|
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
4172
4408
|
},
|
|
4173
4409
|
/**
|
|
4174
|
-
* Get the required error message
|
|
4410
|
+
* Get the required error message
|
|
4175
4411
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4176
4412
|
*/
|
|
4177
4413
|
required: (options) => {
|
|
4178
4414
|
return translate.t(removeIndex(`${colLabel}.field_required`), options);
|
|
4179
4415
|
},
|
|
4180
4416
|
/**
|
|
4181
|
-
* Get
|
|
4417
|
+
* Get text for any custom key relative to the field
|
|
4182
4418
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
4183
4419
|
*
|
|
4184
|
-
* @param key - The
|
|
4185
|
-
* @param options - Optional
|
|
4420
|
+
* @param key - The key suffix (e.g., 'add_more', 'total', etc.)
|
|
4421
|
+
* @param options - Optional options (e.g., defaultValue, interpolation variables)
|
|
4186
4422
|
*/
|
|
4187
4423
|
t: (key, options) => {
|
|
4188
4424
|
return translate.t(removeIndex(`${colLabel}.${key}`), options);
|
|
@@ -4200,8 +4436,9 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4200
4436
|
const { type } = items;
|
|
4201
4437
|
const colLabel = `${prefix}${column}`;
|
|
4202
4438
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4203
|
-
const formI18n = useFormI18n
|
|
4439
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4204
4440
|
const { formState: { errors }, setValue, watch, } = useFormContext();
|
|
4441
|
+
const { formButtonLabels } = useSchemaContext();
|
|
4205
4442
|
const fields = (watch(colLabel) ?? []);
|
|
4206
4443
|
return (jsxs(Flex, { gridRow, gridColumn, flexFlow: 'column', gap: 2, children: [jsxs(Box, { as: "label", children: [formI18n.label(), isRequired && jsx("span", { children: "*" })] }), jsx(Flex, { flexFlow: 'column', gap: 2, children: fields.map((field, index) => (jsxs(Grid, { gridTemplateColumns: '1fr auto', gap: 2, bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
|
|
4207
4444
|
base: 'colorPalette.200',
|
|
@@ -4227,7 +4464,7 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4227
4464
|
return;
|
|
4228
4465
|
}
|
|
4229
4466
|
setValue(colLabel, [...fields, {}]);
|
|
4230
|
-
}, children:
|
|
4467
|
+
}, children: formButtonLabels?.add ?? 'Add' }) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
4231
4468
|
};
|
|
4232
4469
|
|
|
4233
4470
|
const Field = React.forwardRef(function Field(props, ref) {
|
|
@@ -4241,7 +4478,7 @@ const BooleanPicker = ({ schema, column, prefix }) => {
|
|
|
4241
4478
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4242
4479
|
const colLabel = `${prefix}${column}`;
|
|
4243
4480
|
const value = watch(colLabel);
|
|
4244
|
-
const formI18n = useFormI18n
|
|
4481
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4245
4482
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4246
4483
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
|
|
4247
4484
|
setValue(colLabel, !value);
|
|
@@ -4262,50 +4499,50 @@ const CustomInput = ({ column, schema, prefix }) => {
|
|
|
4262
4499
|
|
|
4263
4500
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
4264
4501
|
const { labels } = useContext(DatePickerContext);
|
|
4265
|
-
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
4502
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
4266
4503
|
if (calendars.length) {
|
|
4267
|
-
return (jsxs(Grid, { children: [jsxs(Grid, { templateColumns:
|
|
4504
|
+
return (jsxs(Grid, { children: [jsxs(Grid, { templateColumns: 'repeat(4, auto)', justifyContent: 'center', children: [jsx(Button$1, { variant: 'ghost', ...getBackProps({
|
|
4268
4505
|
calendars,
|
|
4269
4506
|
offset: 12,
|
|
4270
|
-
}), children:
|
|
4507
|
+
}), children: '<<' }), jsx(Button$1, { variant: 'ghost', ...getBackProps({ calendars }), children: backButtonLabel }), jsx(Button$1, { variant: 'ghost', ...getForwardProps({ calendars }), children: forwardButtonLabel }), jsx(Button$1, { variant: 'ghost', ...getForwardProps({
|
|
4271
4508
|
calendars,
|
|
4272
4509
|
offset: 12,
|
|
4273
|
-
}), children:
|
|
4510
|
+
}), children: '>>' })] }), jsx(Grid, { templateColumns: 'repeat(2, auto)', justifyContent: 'center', children: calendars.map((calendar) => (jsxs(Grid, { gap: 4, children: [jsxs(Grid, { justifyContent: 'center', children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsxs(Grid, { templateColumns: 'repeat(7, auto)', justifyContent: 'center', children: [[0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
4274
4511
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
4275
|
-
return (jsx(Text, { textAlign:
|
|
4512
|
+
return (jsx(Text, { textAlign: 'center', children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
4276
4513
|
}), calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
4277
4514
|
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
4278
4515
|
if (!dateObj) {
|
|
4279
4516
|
return jsx(Grid, {}, key);
|
|
4280
4517
|
}
|
|
4281
|
-
const { date, selected, selectable, today } = dateObj;
|
|
4518
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
4282
4519
|
const getDateColor = ({ today, selected, selectable, }) => {
|
|
4283
4520
|
if (!selectable) {
|
|
4284
|
-
return
|
|
4521
|
+
return 'gray';
|
|
4285
4522
|
}
|
|
4286
4523
|
if (selected) {
|
|
4287
|
-
return
|
|
4524
|
+
return 'blue';
|
|
4288
4525
|
}
|
|
4289
4526
|
if (today) {
|
|
4290
|
-
return
|
|
4527
|
+
return 'green';
|
|
4291
4528
|
}
|
|
4292
|
-
return
|
|
4529
|
+
return '';
|
|
4293
4530
|
};
|
|
4294
4531
|
const getVariant = ({ today, selected, selectable, }) => {
|
|
4295
4532
|
if (!selectable) {
|
|
4296
|
-
return
|
|
4533
|
+
return 'surface';
|
|
4297
4534
|
}
|
|
4298
4535
|
if (selected) {
|
|
4299
|
-
return
|
|
4536
|
+
return 'solid';
|
|
4300
4537
|
}
|
|
4301
4538
|
if (today) {
|
|
4302
|
-
return
|
|
4539
|
+
return 'surface';
|
|
4303
4540
|
}
|
|
4304
|
-
return
|
|
4541
|
+
return 'ghost';
|
|
4305
4542
|
};
|
|
4306
4543
|
const color = getDateColor({ today, selected, selectable });
|
|
4307
4544
|
const variant = getVariant({ today, selected, selectable });
|
|
4308
|
-
return (jsx(Button$1, { variant: variant, colorPalette: color, ...getDateProps({ dateObj }), children: selectable ? date.getDate() :
|
|
4545
|
+
return (jsx(Button$1, { variant: variant, colorPalette: color, opacity: isCurrentMonth ? 1 : 0.4, ...getDateProps({ dateObj }), children: selectable ? date.getDate() : 'X' }, key));
|
|
4309
4546
|
}))] })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
4310
4547
|
}
|
|
4311
4548
|
return null;
|
|
@@ -4313,50 +4550,55 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
4313
4550
|
const DatePickerContext = createContext({
|
|
4314
4551
|
labels: {
|
|
4315
4552
|
monthNamesShort: [
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4553
|
+
'Jan',
|
|
4554
|
+
'Feb',
|
|
4555
|
+
'Mar',
|
|
4556
|
+
'Apr',
|
|
4557
|
+
'May',
|
|
4558
|
+
'Jun',
|
|
4559
|
+
'Jul',
|
|
4560
|
+
'Aug',
|
|
4561
|
+
'Sep',
|
|
4562
|
+
'Oct',
|
|
4563
|
+
'Nov',
|
|
4564
|
+
'Dec',
|
|
4328
4565
|
],
|
|
4329
|
-
weekdayNamesShort: [
|
|
4330
|
-
backButtonLabel:
|
|
4331
|
-
forwardButtonLabel:
|
|
4566
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4567
|
+
backButtonLabel: 'Back',
|
|
4568
|
+
forwardButtonLabel: 'Next',
|
|
4332
4569
|
},
|
|
4333
4570
|
});
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4571
|
+
const DatePicker$1 = ({ labels = {
|
|
4572
|
+
monthNamesShort: [
|
|
4573
|
+
'Jan',
|
|
4574
|
+
'Feb',
|
|
4575
|
+
'Mar',
|
|
4576
|
+
'Apr',
|
|
4577
|
+
'May',
|
|
4578
|
+
'Jun',
|
|
4579
|
+
'Jul',
|
|
4580
|
+
'Aug',
|
|
4581
|
+
'Sep',
|
|
4582
|
+
'Oct',
|
|
4583
|
+
'Nov',
|
|
4584
|
+
'Dec',
|
|
4585
|
+
],
|
|
4586
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4587
|
+
backButtonLabel: 'Back',
|
|
4588
|
+
forwardButtonLabel: 'Next',
|
|
4589
|
+
}, onDateSelected, selected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
|
|
4590
|
+
const calendarData = useCalendar({
|
|
4591
|
+
onDateSelected,
|
|
4592
|
+
selected,
|
|
4593
|
+
firstDayOfWeek,
|
|
4594
|
+
showOutsideDays,
|
|
4595
|
+
date,
|
|
4596
|
+
minDate,
|
|
4597
|
+
maxDate,
|
|
4598
|
+
monthsToDisplay,
|
|
4599
|
+
});
|
|
4600
|
+
return (jsx(DatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsx(Calendar, { ...calendarData,
|
|
4601
|
+
firstDayOfWeek })) }));
|
|
4360
4602
|
};
|
|
4361
4603
|
|
|
4362
4604
|
dayjs.extend(utc);
|
|
@@ -4364,7 +4606,7 @@ dayjs.extend(timezone);
|
|
|
4364
4606
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
4365
4607
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4366
4608
|
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
4367
|
-
const formI18n = useFormI18n
|
|
4609
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4368
4610
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4369
4611
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4370
4612
|
const colLabel = formI18n.colLabel;
|
|
@@ -4398,74 +4640,30 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4398
4640
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4399
4641
|
const datePickerLabels = {
|
|
4400
4642
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
formI18n.translate.t(`common.month_5`, {
|
|
4414
|
-
defaultValue: 'May',
|
|
4415
|
-
}),
|
|
4416
|
-
formI18n.translate.t(`common.month_6`, {
|
|
4417
|
-
defaultValue: 'June',
|
|
4418
|
-
}),
|
|
4419
|
-
formI18n.translate.t(`common.month_7`, {
|
|
4420
|
-
defaultValue: 'July',
|
|
4421
|
-
}),
|
|
4422
|
-
formI18n.translate.t(`common.month_8`, {
|
|
4423
|
-
defaultValue: 'August',
|
|
4424
|
-
}),
|
|
4425
|
-
formI18n.translate.t(`common.month_9`, {
|
|
4426
|
-
defaultValue: 'September',
|
|
4427
|
-
}),
|
|
4428
|
-
formI18n.translate.t(`common.month_10`, {
|
|
4429
|
-
defaultValue: 'October',
|
|
4430
|
-
}),
|
|
4431
|
-
formI18n.translate.t(`common.month_11`, {
|
|
4432
|
-
defaultValue: 'November',
|
|
4433
|
-
}),
|
|
4434
|
-
formI18n.translate.t(`common.month_12`, {
|
|
4435
|
-
defaultValue: 'December',
|
|
4436
|
-
}),
|
|
4643
|
+
'January',
|
|
4644
|
+
'February',
|
|
4645
|
+
'March',
|
|
4646
|
+
'April',
|
|
4647
|
+
'May',
|
|
4648
|
+
'June',
|
|
4649
|
+
'July',
|
|
4650
|
+
'August',
|
|
4651
|
+
'September',
|
|
4652
|
+
'October',
|
|
4653
|
+
'November',
|
|
4654
|
+
'December',
|
|
4437
4655
|
],
|
|
4438
4656
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
defaultValue: 'Tue',
|
|
4447
|
-
}),
|
|
4448
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
4449
|
-
defaultValue: 'Wed',
|
|
4450
|
-
}),
|
|
4451
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
4452
|
-
defaultValue: 'Thu',
|
|
4453
|
-
}),
|
|
4454
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
4455
|
-
defaultValue: 'Fri',
|
|
4456
|
-
}),
|
|
4457
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
4458
|
-
defaultValue: 'Sat',
|
|
4459
|
-
}),
|
|
4657
|
+
'Sun',
|
|
4658
|
+
'Mon',
|
|
4659
|
+
'Tue',
|
|
4660
|
+
'Wed',
|
|
4661
|
+
'Thu',
|
|
4662
|
+
'Fri',
|
|
4663
|
+
'Sat',
|
|
4460
4664
|
],
|
|
4461
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4462
|
-
|
|
4463
|
-
defaultValue: 'Back',
|
|
4464
|
-
}),
|
|
4465
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4466
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
4467
|
-
defaultValue: 'Forward',
|
|
4468
|
-
}),
|
|
4665
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
4666
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
4469
4667
|
};
|
|
4470
4668
|
const datePickerContent = (jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4471
4669
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
@@ -4482,7 +4680,7 @@ dayjs.extend(timezone);
|
|
|
4482
4680
|
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4483
4681
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4484
4682
|
const { timezone, insideDialog } = useSchemaContext();
|
|
4485
|
-
const formI18n = useFormI18n
|
|
4683
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4486
4684
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4487
4685
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4488
4686
|
const colLabel = formI18n.colLabel;
|
|
@@ -4580,7 +4778,7 @@ const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
|
4580
4778
|
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
4581
4779
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4582
4780
|
const { enumPickerLabels, insideDialog } = useSchemaContext();
|
|
4583
|
-
const formI18n = useFormI18n
|
|
4781
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4584
4782
|
const { required, variant } = schema;
|
|
4585
4783
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4586
4784
|
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
@@ -5127,7 +5325,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
|
|
|
5127
5325
|
}) })) }))] }));
|
|
5128
5326
|
};
|
|
5129
5327
|
|
|
5130
|
-
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels,
|
|
5328
|
+
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, colLabel, }) {
|
|
5131
5329
|
const [selectedFile, setSelectedFile] = useState(undefined);
|
|
5132
5330
|
const [activeTab, setActiveTab] = useState('browse');
|
|
5133
5331
|
const [uploadingFiles, setUploadingFiles] = useState(new Set());
|
|
@@ -5196,15 +5394,8 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5196
5394
|
const showTabs = enableUpload && !!onUploadFile && !!onFetchFiles;
|
|
5197
5395
|
if (!onFetchFiles && !onUploadFile)
|
|
5198
5396
|
return null;
|
|
5199
|
-
return (jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsx(DialogCloseTrigger, {})] }), jsx(DialogBody, { children: showTabs ? (jsxs(Tabs.Root, { value: activeTab, onValueChange: (e) => setActiveTab(e.value ?? 'browse'), children: [jsxs(Tabs.List, { children: [jsx(Tabs.Trigger, { value: "browse", children: labels?.browseTab ??
|
|
5200
|
-
|
|
5201
|
-
'Browse Library' }), jsx(Tabs.Trigger, { value: "upload", children: labels?.uploadTab ??
|
|
5202
|
-
translate(removeIndex(`${colLabel}.upload_tab`)) ??
|
|
5203
|
-
'Upload Files' })] }), jsx(Tabs.Content, { value: "browse", children: onFetchFiles && (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFile: selectedFile, onFileSelect: setSelectedFile })) }), jsx(Tabs.Content, { value: "upload", children: jsxs(VStack, { align: "stretch", gap: 4, children: [jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
5204
|
-
translate(removeIndex(`${colLabel}.fileDropzone`)) ??
|
|
5205
|
-
'Drop files here or click to upload' }), uploadingFiles.size > 0 && (jsx(Box, { children: Array.from(uploadingFiles).map((fileKey) => (jsx(Box, { py: 2, children: jsxs(HStack, { gap: 2, children: [jsx(Spinner, { size: "sm", colorPalette: "blue" }), jsxs(Text, { fontSize: "sm", color: "fg.muted", children: [labels?.uploading ??
|
|
5206
|
-
translate(removeIndex(`${colLabel}.uploading`)) ??
|
|
5207
|
-
'Uploading...', ' ', fileKey.split('-')[0]] })] }) }, fileKey))) })), uploadErrors.size > 0 && (jsx(VStack, { align: "stretch", gap: 2, children: Array.from(uploadErrors.entries()).map(([fileKey, error]) => (jsx(Box, { bg: {
|
|
5397
|
+
return (jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsx(DialogCloseTrigger, {})] }), jsx(DialogBody, { children: showTabs ? (jsxs(Tabs.Root, { value: activeTab, onValueChange: (e) => setActiveTab(e.value ?? 'browse'), children: [jsxs(Tabs.List, { children: [jsx(Tabs.Trigger, { value: "browse", children: labels?.browseTab ?? 'Browse Library' }), jsx(Tabs.Trigger, { value: "upload", children: labels?.uploadTab ?? 'Upload Files' })] }), jsx(Tabs.Content, { value: "browse", children: onFetchFiles && (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFile: selectedFile, onFileSelect: setSelectedFile })) }), jsx(Tabs.Content, { value: "upload", children: jsxs(VStack, { align: "stretch", gap: 4, children: [jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
5398
|
+
'Drop files here or click to upload' }), uploadingFiles.size > 0 && (jsx(Box, { children: Array.from(uploadingFiles).map((fileKey) => (jsx(Box, { py: 2, children: jsxs(HStack, { gap: 2, children: [jsx(Spinner, { size: "sm", colorPalette: "blue" }), jsxs(Text, { fontSize: "sm", color: "fg.muted", children: [labels?.uploading ?? 'Uploading...', ' ', fileKey.split('-')[0]] })] }) }, fileKey))) })), uploadErrors.size > 0 && (jsx(VStack, { align: "stretch", gap: 2, children: Array.from(uploadErrors.entries()).map(([fileKey, error]) => (jsx(Box, { bg: {
|
|
5208
5399
|
base: 'colorPalette.50',
|
|
5209
5400
|
_dark: 'colorPalette.900/20',
|
|
5210
5401
|
}, border: "1px solid", borderColor: {
|
|
@@ -5213,18 +5404,12 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5213
5404
|
}, colorPalette: "red", borderRadius: "md", p: 3, children: jsxs(Text, { fontSize: "sm", color: {
|
|
5214
5405
|
base: 'colorPalette.600',
|
|
5215
5406
|
_dark: 'colorPalette.300',
|
|
5216
|
-
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ??
|
|
5217
|
-
translate(removeIndex(`${colLabel}.upload_failed`)) ??
|
|
5218
|
-
'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFile: selectedFile, onFileSelect: setSelectedFile })) : null }), jsx(DialogFooter, { children: jsxs(HStack, { gap: 3, justify: "end", children: [jsx(Button$1, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
|
|
5219
|
-
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
5220
|
-
'Cancel' }), jsx(Button$1, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ??
|
|
5221
|
-
translate(removeIndex(`${colLabel}.select`)) ??
|
|
5222
|
-
'Select' })] }) })] }) }));
|
|
5407
|
+
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ?? 'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFile: selectedFile, onFileSelect: setSelectedFile })) : null }), jsx(DialogFooter, { children: jsxs(HStack, { gap: 3, justify: "end", children: [jsx(Button$1, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ?? 'Cancel' }), jsx(Button$1, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ?? 'Select' })] }) })] }) }));
|
|
5223
5408
|
}
|
|
5224
5409
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
5225
5410
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5226
5411
|
const { filePickerLabels } = useSchemaContext();
|
|
5227
|
-
const formI18n = useFormI18n
|
|
5412
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5228
5413
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5229
5414
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5230
5415
|
const isSingleSelect = type === 'string';
|
|
@@ -5300,7 +5485,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5300
5485
|
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
5301
5486
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5302
5487
|
const { filePickerLabels } = useSchemaContext();
|
|
5303
|
-
const formI18n = useFormI18n
|
|
5488
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5304
5489
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
5305
5490
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5306
5491
|
const isSingleSelect = type === 'string';
|
|
@@ -5396,8 +5581,8 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5396
5581
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsx(VStack, { align: "stretch", gap: 2, children: jsx(Button$1, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
5397
5582
|
formI18n.t('browse_library') ??
|
|
5398
5583
|
'Browse from Library' }) }), jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5399
|
-
|
|
5400
|
-
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels,
|
|
5584
|
+
filePickerLabels?.dialogTitle ??
|
|
5585
|
+
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5401
5586
|
const file = fileMap.get(fileId);
|
|
5402
5587
|
const isImage = file
|
|
5403
5588
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5446,17 +5631,16 @@ const defaultRenderDisplay = (item) => {
|
|
|
5446
5631
|
return JSON.stringify(item);
|
|
5447
5632
|
};
|
|
5448
5633
|
|
|
5449
|
-
const
|
|
5634
|
+
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5450
5635
|
const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
|
|
5451
5636
|
const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5452
|
-
const
|
|
5453
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
5454
|
-
const isRequired = required?.some((columnId) => columnId === column);
|
|
5637
|
+
const { renderDisplay, foreign_key } = schema;
|
|
5455
5638
|
const { table, column: column_ref, customQueryFn, } = foreign_key;
|
|
5456
5639
|
const [searchText, setSearchText] = useState('');
|
|
5457
5640
|
const [debouncedSearchText, setDebouncedSearchText] = useState('');
|
|
5458
5641
|
const [limit] = useState(50); // Increased limit for combobox
|
|
5459
|
-
|
|
5642
|
+
// Get colLabel from schema context (we'll compute it here)
|
|
5643
|
+
const colLabel = `${prefix}${column}`;
|
|
5460
5644
|
const watchedValue = watch(colLabel);
|
|
5461
5645
|
const watchId = !isMultiple ? watchedValue : undefined;
|
|
5462
5646
|
const watchIds = isMultiple
|
|
@@ -5655,20 +5839,6 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5655
5839
|
itemToValue: (item) => item.value,
|
|
5656
5840
|
filter: contains,
|
|
5657
5841
|
});
|
|
5658
|
-
// Handle input value change (search)
|
|
5659
|
-
const handleInputValueChange = (details) => {
|
|
5660
|
-
setSearchText(details.inputValue);
|
|
5661
|
-
// Filter will be applied after data is fetched
|
|
5662
|
-
};
|
|
5663
|
-
// Handle value change
|
|
5664
|
-
const handleValueChange = (details) => {
|
|
5665
|
-
if (isMultiple) {
|
|
5666
|
-
setValue(colLabel, details.value);
|
|
5667
|
-
}
|
|
5668
|
-
else {
|
|
5669
|
-
setValue(colLabel, details.value[0] || '');
|
|
5670
|
-
}
|
|
5671
|
-
};
|
|
5672
5842
|
// Track previous comboboxItems to avoid unnecessary updates
|
|
5673
5843
|
const prevComboboxItemsRef = useRef('');
|
|
5674
5844
|
const prevSearchTextRef = useRef('');
|
|
@@ -5698,8 +5868,106 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5698
5868
|
// comboboxItems and searchText are the only dependencies we care about
|
|
5699
5869
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5700
5870
|
}, [comboboxItems, searchText]);
|
|
5871
|
+
return {
|
|
5872
|
+
colLabel,
|
|
5873
|
+
currentValue,
|
|
5874
|
+
searchText,
|
|
5875
|
+
setSearchText,
|
|
5876
|
+
debouncedSearchText,
|
|
5877
|
+
isLoading,
|
|
5878
|
+
isFetching,
|
|
5879
|
+
isPending,
|
|
5880
|
+
isError,
|
|
5881
|
+
isSearching,
|
|
5882
|
+
isLoadingInitialValues,
|
|
5883
|
+
isFetchingInitialValues,
|
|
5884
|
+
missingIds,
|
|
5885
|
+
comboboxItems,
|
|
5886
|
+
collection,
|
|
5887
|
+
filter,
|
|
5888
|
+
set,
|
|
5889
|
+
idMap,
|
|
5890
|
+
idPickerLabels,
|
|
5891
|
+
insideDialog: insideDialog ?? false,
|
|
5892
|
+
renderDisplay,
|
|
5893
|
+
column_ref,
|
|
5894
|
+
errors,
|
|
5895
|
+
setValue,
|
|
5896
|
+
};
|
|
5897
|
+
};
|
|
5898
|
+
|
|
5899
|
+
const IdPickerSingle = ({ column, schema, prefix, }) => {
|
|
5900
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5901
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
5902
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5903
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
5904
|
+
column,
|
|
5905
|
+
schema,
|
|
5906
|
+
prefix,
|
|
5907
|
+
isMultiple: false,
|
|
5908
|
+
});
|
|
5909
|
+
const handleInputValueChange = (details) => {
|
|
5910
|
+
setSearchText(details.inputValue);
|
|
5911
|
+
};
|
|
5912
|
+
const handleValueChange = (details) => {
|
|
5913
|
+
setValue(colLabel, details.value[0] || '');
|
|
5914
|
+
};
|
|
5915
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
5916
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5917
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsx(Flex, { mb: 2, children: (() => {
|
|
5918
|
+
const id = currentValue[0];
|
|
5919
|
+
const item = idMap[id];
|
|
5920
|
+
// Show loading skeleton while fetching initial values
|
|
5921
|
+
if (item === undefined &&
|
|
5922
|
+
(isLoadingInitialValues || isFetchingInitialValues) &&
|
|
5923
|
+
missingIds.includes(id)) {
|
|
5924
|
+
return jsx(Skeleton, { height: "24px", width: "100px", borderRadius: "md" });
|
|
5925
|
+
}
|
|
5926
|
+
// Only show "not found" if we're not loading and item is still missing
|
|
5927
|
+
if (item === undefined) {
|
|
5928
|
+
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }));
|
|
5929
|
+
}
|
|
5930
|
+
return jsx(Text, { fontSize: "sm", children: renderDisplayFunction(item) });
|
|
5931
|
+
})() })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: false, closeOnSelect: true, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5932
|
+
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5933
|
+
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxs(Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, { size: "xs" }), isError && (jsx(Icon, { color: "fg.error", children: jsx(BiError, {}) })), currentValue.length > 0 && (jsx(Combobox.ClearTrigger, { onClick: () => {
|
|
5934
|
+
setValue(colLabel, '');
|
|
5935
|
+
} })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5936
|
+
// Show skeleton items to prevent UI shift
|
|
5937
|
+
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5938
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5939
|
+
: idPickerLabels?.initialResults ??
|
|
5940
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
5941
|
+
? renderDisplayFunction(item.raw)
|
|
5942
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5943
|
+
// Show skeleton items to prevent UI shift
|
|
5944
|
+
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5945
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5946
|
+
: idPickerLabels?.initialResults ??
|
|
5947
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
5948
|
+
? renderDisplayFunction(item.raw)
|
|
5949
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5950
|
+
};
|
|
5951
|
+
|
|
5952
|
+
const IdPickerMultiple = ({ column, schema, prefix, }) => {
|
|
5953
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5954
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
5955
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5956
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
5957
|
+
column,
|
|
5958
|
+
schema,
|
|
5959
|
+
prefix,
|
|
5960
|
+
isMultiple: true,
|
|
5961
|
+
});
|
|
5962
|
+
const handleInputValueChange = (details) => {
|
|
5963
|
+
setSearchText(details.inputValue);
|
|
5964
|
+
};
|
|
5965
|
+
const handleValueChange = (details) => {
|
|
5966
|
+
setValue(colLabel, details.value);
|
|
5967
|
+
};
|
|
5968
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
5701
5969
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5702
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [
|
|
5970
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsx(Flex, { flexFlow: 'wrap', gap: 1, mb: 2, children: currentValue.map((id) => {
|
|
5703
5971
|
const item = idMap[id];
|
|
5704
5972
|
// Show loading skeleton while fetching initial values
|
|
5705
5973
|
if (item === undefined &&
|
|
@@ -5709,34 +5977,28 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5709
5977
|
}
|
|
5710
5978
|
// Only show "not found" if we're not loading and item is still missing
|
|
5711
5979
|
if (item === undefined) {
|
|
5712
|
-
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ??
|
|
5980
|
+
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
5713
5981
|
}
|
|
5714
5982
|
return (jsx(Tag, { closable: true, onClick: () => {
|
|
5715
5983
|
const newValue = currentValue.filter((itemId) => itemId !== id);
|
|
5716
5984
|
setValue(colLabel, newValue);
|
|
5717
|
-
}, children:
|
|
5718
|
-
|
|
5719
|
-
: defaultRenderDisplay(item) }, id));
|
|
5720
|
-
}) })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: isMultiple, closeOnSelect: !isMultiple, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5985
|
+
}, children: renderDisplayFunction(item) }, id));
|
|
5986
|
+
}) })), jsxs(Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: true, closeOnSelect: false, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5721
5987
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5722
|
-
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ??
|
|
5723
|
-
setValue(colLabel, '');
|
|
5724
|
-
} })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: formI18n.t('loading_failed') })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5988
|
+
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxs(Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, { size: "xs" }), isError && (jsx(Icon, { color: "fg.error", children: jsx(BiError, {}) })), jsx(Combobox.Trigger, {})] })] }), insideDialog ? (jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5725
5989
|
// Show skeleton items to prevent UI shift
|
|
5726
5990
|
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5727
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5728
|
-
formI18n.t('empty_search_result')
|
|
5991
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5729
5992
|
: idPickerLabels?.initialResults ??
|
|
5730
|
-
|
|
5731
|
-
?
|
|
5732
|
-
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children:
|
|
5993
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
5994
|
+
? renderDisplayFunction(item.raw)
|
|
5995
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5733
5996
|
// Show skeleton items to prevent UI shift
|
|
5734
5997
|
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5735
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5736
|
-
formI18n.t('empty_search_result')
|
|
5998
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5737
5999
|
: idPickerLabels?.initialResults ??
|
|
5738
|
-
|
|
5739
|
-
?
|
|
6000
|
+
'Start typing to search' })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
6001
|
+
? renderDisplayFunction(item.raw)
|
|
5740
6002
|
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5741
6003
|
};
|
|
5742
6004
|
|
|
@@ -5810,7 +6072,7 @@ const NumberInputField = ({ schema, column, prefix, }) => {
|
|
|
5810
6072
|
const colLabel = `${prefix}${column}`;
|
|
5811
6073
|
const value = watch(`${colLabel}`);
|
|
5812
6074
|
const fieldError = getFieldError(errors, colLabel);
|
|
5813
|
-
const formI18n = useFormI18n
|
|
6075
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5814
6076
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn, gridRow, errorText: fieldError
|
|
5815
6077
|
? fieldError.includes('required')
|
|
5816
6078
|
? formI18n.required()
|
|
@@ -5828,7 +6090,7 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5828
6090
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
5829
6091
|
const colLabel = `${prefix}${column}`;
|
|
5830
6092
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5831
|
-
const formI18n = useFormI18n
|
|
6093
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5832
6094
|
const { formState: { errors }, } = useFormContext();
|
|
5833
6095
|
if (properties === undefined) {
|
|
5834
6096
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -5848,14 +6110,14 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5848
6110
|
|
|
5849
6111
|
const RecordInput = ({ column, schema, prefix }) => {
|
|
5850
6112
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
5851
|
-
const {
|
|
6113
|
+
const { formButtonLabels } = useSchemaContext();
|
|
5852
6114
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5853
6115
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5854
6116
|
const entries = Object.entries(getValues(column) ?? {});
|
|
5855
6117
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
5856
6118
|
const [newKey, setNewKey] = useState();
|
|
5857
6119
|
const [newValue, setNewValue] = useState();
|
|
5858
|
-
const formI18n = useFormI18n
|
|
6120
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5859
6121
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`] ? formI18n.required() : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
|
|
5860
6122
|
return (jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
5861
6123
|
const filtered = entries.filter(([target]) => {
|
|
@@ -5892,11 +6154,11 @@ const RecordInput = ({ column, schema, prefix }) => {
|
|
|
5892
6154
|
setShowNewEntries(false);
|
|
5893
6155
|
setNewKey(undefined);
|
|
5894
6156
|
setNewValue(undefined);
|
|
5895
|
-
}, children:
|
|
6157
|
+
}, children: formButtonLabels?.save ?? 'Save' })] })] }) }), jsx(Button, { onClick: () => {
|
|
5896
6158
|
setShowNewEntries(true);
|
|
5897
6159
|
setNewKey(undefined);
|
|
5898
6160
|
setNewValue(undefined);
|
|
5899
|
-
}, children:
|
|
6161
|
+
}, children: formButtonLabels?.addNew ?? 'Add New' })] }));
|
|
5900
6162
|
};
|
|
5901
6163
|
|
|
5902
6164
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
@@ -5905,7 +6167,7 @@ const StringInputField = ({ column, schema, prefix, }) => {
|
|
|
5905
6167
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5906
6168
|
const colLabel = `${prefix}${column}`;
|
|
5907
6169
|
const fieldError = getFieldError(errors, colLabel);
|
|
5908
|
-
const formI18n = useFormI18n
|
|
6170
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5909
6171
|
return (jsx(Fragment, { children: jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
|
|
5910
6172
|
};
|
|
5911
6173
|
|
|
@@ -6097,7 +6359,7 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6097
6359
|
const form = useFormContext();
|
|
6098
6360
|
const { setValue, watch } = form;
|
|
6099
6361
|
const fieldError = getFieldError(errors, colLabel);
|
|
6100
|
-
const formI18n = useFormI18n
|
|
6362
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6101
6363
|
const watchValue = watch(colLabel);
|
|
6102
6364
|
return (jsx(Fragment, { children: jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
|
|
6103
6365
|
? fieldError.includes('required')
|
|
@@ -6108,18 +6370,13 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6108
6370
|
|
|
6109
6371
|
dayjs.extend(utc);
|
|
6110
6372
|
dayjs.extend(timezone);
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
},
|
|
6117
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6118
|
-
onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, portalled = true, }) {
|
|
6119
|
-
// Generate time options (every 15 minutes)
|
|
6373
|
+
const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem, onChange = () => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6374
|
+
placeholder: 'hh:mm AM/PM',
|
|
6375
|
+
emptyMessage: 'No time found',
|
|
6376
|
+
}, }) => {
|
|
6377
|
+
// Generate time options (every 15 minutes in 12-hour format)
|
|
6120
6378
|
const timeOptions = useMemo(() => {
|
|
6121
6379
|
const options = [];
|
|
6122
|
-
const meridiemOptions = ['am', 'pm'];
|
|
6123
6380
|
// Get start time for comparison if provided
|
|
6124
6381
|
let startDateTime = null;
|
|
6125
6382
|
let shouldFilterByDate = false;
|
|
@@ -6134,14 +6391,16 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6134
6391
|
selectedDateObj.format('YYYY-MM-DD');
|
|
6135
6392
|
}
|
|
6136
6393
|
}
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
//
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6394
|
+
// Generate 12-hour format options (1-12 for hours, AM/PM)
|
|
6395
|
+
for (let h = 1; h <= 12; h++) {
|
|
6396
|
+
for (let m = 0; m < 60; m += 15) {
|
|
6397
|
+
for (const mer of ['am', 'pm']) {
|
|
6398
|
+
// Convert 12-hour to 24-hour for comparison
|
|
6399
|
+
let hour24 = h;
|
|
6400
|
+
if (mer === 'am' && h === 12)
|
|
6401
|
+
hour24 = 0;
|
|
6402
|
+
else if (mer === 'pm' && h < 12)
|
|
6403
|
+
hour24 = h + 12;
|
|
6145
6404
|
// Filter out times that would result in negative duration (only when dates are the same)
|
|
6146
6405
|
if (startDateTime && selectedDate && shouldFilterByDate) {
|
|
6147
6406
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
@@ -6184,20 +6443,23 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6184
6443
|
}
|
|
6185
6444
|
}
|
|
6186
6445
|
}
|
|
6446
|
+
const hourDisplay = h.toString();
|
|
6447
|
+
const minuteDisplay = m.toString().padStart(2, '0');
|
|
6448
|
+
const timeDisplay = `${hourDisplay}:${minuteDisplay} ${mer.toUpperCase()}`;
|
|
6187
6449
|
options.push({
|
|
6188
|
-
label:
|
|
6189
|
-
value: `${h}:${m
|
|
6450
|
+
label: timeDisplay,
|
|
6451
|
+
value: `${h}:${m}:${mer}`,
|
|
6190
6452
|
hour: h,
|
|
6191
6453
|
minute: m,
|
|
6192
6454
|
meridiem: mer,
|
|
6193
|
-
searchText:
|
|
6455
|
+
searchText: timeDisplay, // Use base time without duration for searching
|
|
6194
6456
|
durationText,
|
|
6195
6457
|
});
|
|
6196
6458
|
}
|
|
6197
6459
|
}
|
|
6198
6460
|
}
|
|
6199
6461
|
return options;
|
|
6200
|
-
}, [
|
|
6462
|
+
}, [startTime, selectedDate, timezone]);
|
|
6201
6463
|
const { contains } = useFilter({ sensitivity: 'base' });
|
|
6202
6464
|
const { collection, filter } = useListCollection({
|
|
6203
6465
|
initialItems: timeOptions,
|
|
@@ -6210,7 +6472,7 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6210
6472
|
if (hour === null || minute === null || meridiem === null) {
|
|
6211
6473
|
return '';
|
|
6212
6474
|
}
|
|
6213
|
-
return `${hour}:${minute
|
|
6475
|
+
return `${hour}:${minute}:${meridiem}`;
|
|
6214
6476
|
}, [hour, minute, meridiem]);
|
|
6215
6477
|
// Calculate duration difference
|
|
6216
6478
|
const durationDiff = useMemo(() => {
|
|
@@ -6221,15 +6483,14 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6221
6483
|
meridiem === null) {
|
|
6222
6484
|
return null;
|
|
6223
6485
|
}
|
|
6224
|
-
const hour24 = meridiem === 'am'
|
|
6225
|
-
? hour === 12
|
|
6226
|
-
? 0
|
|
6227
|
-
: hour
|
|
6228
|
-
: hour === 12
|
|
6229
|
-
? 12
|
|
6230
|
-
: hour + 12;
|
|
6231
6486
|
const startDateObj = dayjs(startTime).tz(timezone);
|
|
6232
6487
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
6488
|
+
// Convert 12-hour to 24-hour format
|
|
6489
|
+
let hour24 = hour;
|
|
6490
|
+
if (meridiem === 'am' && hour === 12)
|
|
6491
|
+
hour24 = 0;
|
|
6492
|
+
else if (meridiem === 'pm' && hour < 12)
|
|
6493
|
+
hour24 = hour + 12;
|
|
6233
6494
|
const currentDateTime = selectedDateObj
|
|
6234
6495
|
.hour(hour24)
|
|
6235
6496
|
.minute(minute)
|
|
@@ -6294,83 +6555,54 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6294
6555
|
if (!trimmedValue) {
|
|
6295
6556
|
return;
|
|
6296
6557
|
}
|
|
6297
|
-
//
|
|
6298
|
-
const
|
|
6299
|
-
|
|
6300
|
-
// Matches: 1-2 digits hour, optional colon, 2 digits minute, am/pm
|
|
6301
|
-
const pattern12HourWithMeridiem = /^(\d{1,2}):?(\d{2})(am|pm)$/;
|
|
6302
|
-
const match12Hour = normalized.match(pattern12HourWithMeridiem);
|
|
6558
|
+
// Parse formats like "1:30 PM", "1:30PM", "1:30 pm", "1:30pm"
|
|
6559
|
+
const timePattern12Hour = /^(\d{1,2}):(\d{1,2})\s*(am|pm|AM|PM)$/i;
|
|
6560
|
+
const match12Hour = trimmedValue.match(timePattern12Hour);
|
|
6303
6561
|
if (match12Hour) {
|
|
6304
6562
|
const parsedHour = parseInt(match12Hour[1], 10);
|
|
6305
6563
|
const parsedMinute = parseInt(match12Hour[2], 10);
|
|
6306
|
-
const parsedMeridiem = match12Hour[3];
|
|
6307
|
-
// Validate
|
|
6308
|
-
if (parsedHour
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6564
|
+
const parsedMeridiem = match12Hour[3].toLowerCase();
|
|
6565
|
+
// Validate ranges
|
|
6566
|
+
if (parsedHour >= 1 &&
|
|
6567
|
+
parsedHour <= 12 &&
|
|
6568
|
+
parsedMinute >= 0 &&
|
|
6569
|
+
parsedMinute <= 59) {
|
|
6570
|
+
setHour(parsedHour);
|
|
6571
|
+
setMinute(parsedMinute);
|
|
6572
|
+
setMeridiem(parsedMeridiem);
|
|
6573
|
+
onChange({
|
|
6574
|
+
hour: parsedHour,
|
|
6575
|
+
minute: parsedMinute,
|
|
6576
|
+
meridiem: parsedMeridiem,
|
|
6577
|
+
});
|
|
6317
6578
|
return;
|
|
6318
6579
|
}
|
|
6319
|
-
setHour(parsedHour);
|
|
6320
|
-
setMinute(parsedMinute);
|
|
6321
|
-
setMeridiem(parsedMeridiem);
|
|
6322
|
-
onChange({
|
|
6323
|
-
hour: parsedHour,
|
|
6324
|
-
minute: parsedMinute,
|
|
6325
|
-
meridiem: parsedMeridiem,
|
|
6326
|
-
});
|
|
6327
|
-
return;
|
|
6328
6580
|
}
|
|
6329
|
-
//
|
|
6330
|
-
|
|
6331
|
-
const
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
//
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
}
|
|
6354
|
-
else if (parsedHour === 12) {
|
|
6355
|
-
parsedHour = 12;
|
|
6356
|
-
parsedMeridiem = 'pm';
|
|
6357
|
-
}
|
|
6358
|
-
else if (parsedHour > 12) {
|
|
6359
|
-
parsedHour = parsedHour - 12;
|
|
6360
|
-
parsedMeridiem = 'pm';
|
|
6361
|
-
}
|
|
6362
|
-
else {
|
|
6363
|
-
parsedMeridiem = 'am';
|
|
6581
|
+
// Try to parse formats like "130pm" or "130 pm" (without colon)
|
|
6582
|
+
const timePatternNoColon = /^(\d{1,4})\s*(am|pm|AM|PM)$/i;
|
|
6583
|
+
const matchNoColon = trimmedValue.match(timePatternNoColon);
|
|
6584
|
+
if (matchNoColon) {
|
|
6585
|
+
const numbersOnly = matchNoColon[1];
|
|
6586
|
+
const parsedMeridiem = matchNoColon[2].toLowerCase();
|
|
6587
|
+
if (numbersOnly.length >= 3) {
|
|
6588
|
+
const parsedHour = parseInt(numbersOnly.slice(0, -2), 10);
|
|
6589
|
+
const parsedMinute = parseInt(numbersOnly.slice(-2), 10);
|
|
6590
|
+
// Validate ranges
|
|
6591
|
+
if (parsedHour >= 1 &&
|
|
6592
|
+
parsedHour <= 12 &&
|
|
6593
|
+
parsedMinute >= 0 &&
|
|
6594
|
+
parsedMinute <= 59) {
|
|
6595
|
+
setHour(parsedHour);
|
|
6596
|
+
setMinute(parsedMinute);
|
|
6597
|
+
setMeridiem(parsedMeridiem);
|
|
6598
|
+
onChange({
|
|
6599
|
+
hour: parsedHour,
|
|
6600
|
+
minute: parsedMinute,
|
|
6601
|
+
meridiem: parsedMeridiem,
|
|
6602
|
+
});
|
|
6603
|
+
return;
|
|
6604
|
+
}
|
|
6364
6605
|
}
|
|
6365
|
-
setHour(parsedHour);
|
|
6366
|
-
setMinute(parsedMinute);
|
|
6367
|
-
setMeridiem(parsedMeridiem);
|
|
6368
|
-
onChange({
|
|
6369
|
-
hour: parsedHour,
|
|
6370
|
-
minute: parsedMinute,
|
|
6371
|
-
meridiem: parsedMeridiem,
|
|
6372
|
-
});
|
|
6373
|
-
return;
|
|
6374
6606
|
}
|
|
6375
6607
|
// Parse failed, select first result
|
|
6376
6608
|
selectFirstResult();
|
|
@@ -6417,17 +6649,17 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6417
6649
|
e.currentTarget?.blur();
|
|
6418
6650
|
}
|
|
6419
6651
|
};
|
|
6420
|
-
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder:
|
|
6421
|
-
}
|
|
6652
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder: labels?.placeholder ?? 'hh:mm AM/PM', onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsx(Combobox.IndicatorGroup, { children: jsx(Combobox.Trigger, {}) })] }), jsx(Portal, { disabled: !portalled, children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [jsx(Combobox.Empty, { children: labels?.emptyMessage ?? 'No time found' }), collection.items.map((item) => (jsxs(Combobox.Item, { item: item, children: [jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsx(Text, { flex: 1, children: item.label }), item.durationText && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: item.durationText }) }))] }), jsx(Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: durationDiff }) })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(Icon, { children: jsx(MdCancel, {}) }) })] }) }));
|
|
6653
|
+
};
|
|
6422
6654
|
|
|
6423
6655
|
dayjs.extend(timezone);
|
|
6424
6656
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
6425
6657
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
6426
|
-
const { timezone, insideDialog } = useSchemaContext();
|
|
6658
|
+
const { timezone, insideDialog, timePickerLabels } = useSchemaContext();
|
|
6427
6659
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
|
|
6428
6660
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6429
6661
|
const colLabel = `${prefix}${column}`;
|
|
6430
|
-
const formI18n = useFormI18n
|
|
6662
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6431
6663
|
const [open, setOpen] = useState(false);
|
|
6432
6664
|
const value = watch(colLabel);
|
|
6433
6665
|
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
@@ -6485,13 +6717,7 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
6485
6717
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6486
6718
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
6487
6719
|
setOpen(true);
|
|
6488
|
-
}, justifyContent: 'start', children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), insideDialog ? (jsx(Popover.Positioner, { children: jsx(Popover.Content, { maxH: "70vh", overflowY: "auto", children: jsx(Popover.Body, { overflow: "visible", children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange,
|
|
6489
|
-
am: translate.t(`common.am`, { defaultValue: 'AM' }),
|
|
6490
|
-
pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
|
|
6491
|
-
} }) }) }) })) : (jsx(Portal, { children: jsx(Popover.Positioner, { children: jsx(Popover.Content, { children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
|
|
6492
|
-
am: translate.t(`common.am`, { defaultValue: 'AM' }),
|
|
6493
|
-
pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
|
|
6494
|
-
} }) }) }) }) }))] }) }));
|
|
6720
|
+
}, justifyContent: 'start', children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), insideDialog ? (jsx(Popover.Positioner, { children: jsx(Popover.Content, { maxH: "70vh", overflowY: "auto", children: jsx(Popover.Body, { overflow: "visible", children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, labels: timePickerLabels }) }) }) })) : (jsx(Portal, { children: jsx(Popover.Positioner, { children: jsx(Popover.Content, { children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, labels: timePickerLabels }) }) }) }) }))] }) }));
|
|
6495
6721
|
};
|
|
6496
6722
|
|
|
6497
6723
|
dayjs.extend(utc);
|
|
@@ -6625,7 +6851,10 @@ dayjs.extend(utc);
|
|
|
6625
6851
|
dayjs.extend(timezone);
|
|
6626
6852
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
|
|
6627
6853
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6628
|
-
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true,
|
|
6854
|
+
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6855
|
+
placeholder: 'HH:mm:ss',
|
|
6856
|
+
emptyMessage: 'No time found',
|
|
6857
|
+
}, }) {
|
|
6629
6858
|
// Generate time options (every 15 minutes, seconds always 0)
|
|
6630
6859
|
const timeOptions = useMemo(() => {
|
|
6631
6860
|
const options = [];
|
|
@@ -6888,7 +7117,7 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6888
7117
|
e.currentTarget?.blur();
|
|
6889
7118
|
}
|
|
6890
7119
|
};
|
|
6891
|
-
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder:
|
|
7120
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder: labels.placeholder, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsx(Combobox.IndicatorGroup, { children: jsx(Combobox.Trigger, {}) })] }), jsx(Portal, { disabled: !portalled, children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [jsx(Combobox.Empty, { children: labels.emptyMessage }), collection.items.map((item) => (jsxs(Combobox.Item, { item: item, children: [jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsx(Text, { flex: 1, children: item.label }), item.durationText && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: item.durationText }) }))] }), jsx(Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: durationDiff }) })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(Icon, { children: jsx(MdCancel, {}) }) })] }) }));
|
|
6892
7121
|
}
|
|
6893
7122
|
|
|
6894
7123
|
dayjs.extend(utc);
|
|
@@ -6911,7 +7140,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6911
7140
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
6912
7141
|
backButtonLabel: 'Back',
|
|
6913
7142
|
forwardButtonLabel: 'Next',
|
|
6914
|
-
}, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
7143
|
+
}, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
6915
7144
|
console.log('[DateTimePicker] Component initialized with props:', {
|
|
6916
7145
|
value,
|
|
6917
7146
|
format,
|
|
@@ -7357,7 +7586,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7357
7586
|
const dateObj = dayjs.tz(selectedDate, timezone);
|
|
7358
7587
|
return dateObj.isValid() ? dateObj.format('Z') : null;
|
|
7359
7588
|
}, [selectedDate, timezone]);
|
|
7360
|
-
return (jsxs(Flex, { direction: "column", gap: 4,
|
|
7589
|
+
return (jsxs(Flex, { direction: "column", gap: 4, children: [jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
|
|
7361
7590
|
if (date) {
|
|
7362
7591
|
handleDateChange(date);
|
|
7363
7592
|
}
|
|
@@ -7365,15 +7594,15 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7365
7594
|
setSelectedDate('');
|
|
7366
7595
|
onChange?.(undefined);
|
|
7367
7596
|
}
|
|
7368
|
-
}, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: showSeconds ? second : null, setSecond: showSeconds ? setSecond : () => { }, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled })) : (jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), displayText && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
|
|
7597
|
+
}, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: showSeconds ? second : null, setSecond: showSeconds ? setSecond : () => { }, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled, labels: timePickerLabels })) : (jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled, labels: timePickerLabels })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), displayText && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
|
|
7369
7598
|
}
|
|
7370
7599
|
|
|
7371
7600
|
dayjs.extend(utc);
|
|
7372
7601
|
dayjs.extend(timezone);
|
|
7373
7602
|
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
7374
7603
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
7375
|
-
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
7376
|
-
const formI18n = useFormI18n
|
|
7604
|
+
const { timezone, dateTimePickerLabels, timePickerLabels, insideDialog } = useSchemaContext();
|
|
7605
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7377
7606
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
|
|
7378
7607
|
// with timezone
|
|
7379
7608
|
dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
|
|
@@ -7386,74 +7615,30 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7386
7615
|
: '';
|
|
7387
7616
|
const dateTimePickerLabelsConfig = {
|
|
7388
7617
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
formI18n.translate.t(`common.month_5`, {
|
|
7402
|
-
defaultValue: 'May',
|
|
7403
|
-
}),
|
|
7404
|
-
formI18n.translate.t(`common.month_6`, {
|
|
7405
|
-
defaultValue: 'June',
|
|
7406
|
-
}),
|
|
7407
|
-
formI18n.translate.t(`common.month_7`, {
|
|
7408
|
-
defaultValue: 'July',
|
|
7409
|
-
}),
|
|
7410
|
-
formI18n.translate.t(`common.month_8`, {
|
|
7411
|
-
defaultValue: 'August',
|
|
7412
|
-
}),
|
|
7413
|
-
formI18n.translate.t(`common.month_9`, {
|
|
7414
|
-
defaultValue: 'September',
|
|
7415
|
-
}),
|
|
7416
|
-
formI18n.translate.t(`common.month_10`, {
|
|
7417
|
-
defaultValue: 'October',
|
|
7418
|
-
}),
|
|
7419
|
-
formI18n.translate.t(`common.month_11`, {
|
|
7420
|
-
defaultValue: 'November',
|
|
7421
|
-
}),
|
|
7422
|
-
formI18n.translate.t(`common.month_12`, {
|
|
7423
|
-
defaultValue: 'December',
|
|
7424
|
-
}),
|
|
7618
|
+
'January',
|
|
7619
|
+
'February',
|
|
7620
|
+
'March',
|
|
7621
|
+
'April',
|
|
7622
|
+
'May',
|
|
7623
|
+
'June',
|
|
7624
|
+
'July',
|
|
7625
|
+
'August',
|
|
7626
|
+
'September',
|
|
7627
|
+
'October',
|
|
7628
|
+
'November',
|
|
7629
|
+
'December',
|
|
7425
7630
|
],
|
|
7426
7631
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
defaultValue: 'Tue',
|
|
7435
|
-
}),
|
|
7436
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
7437
|
-
defaultValue: 'Wed',
|
|
7438
|
-
}),
|
|
7439
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
7440
|
-
defaultValue: 'Thu',
|
|
7441
|
-
}),
|
|
7442
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
7443
|
-
defaultValue: 'Fri',
|
|
7444
|
-
}),
|
|
7445
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
7446
|
-
defaultValue: 'Sat',
|
|
7447
|
-
}),
|
|
7632
|
+
'Sun',
|
|
7633
|
+
'Mon',
|
|
7634
|
+
'Tue',
|
|
7635
|
+
'Wed',
|
|
7636
|
+
'Thu',
|
|
7637
|
+
'Fri',
|
|
7638
|
+
'Sat',
|
|
7448
7639
|
],
|
|
7449
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
7450
|
-
|
|
7451
|
-
defaultValue: 'Back',
|
|
7452
|
-
}),
|
|
7453
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
7454
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
7455
|
-
defaultValue: 'Forward',
|
|
7456
|
-
}),
|
|
7640
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
7641
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
7457
7642
|
};
|
|
7458
7643
|
const dateTimePickerContent = (jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
7459
7644
|
if (!date || date === null || date === undefined) {
|
|
@@ -7467,7 +7652,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7467
7652
|
else {
|
|
7468
7653
|
setValue(colLabel, undefined);
|
|
7469
7654
|
}
|
|
7470
|
-
}, timezone: timezone, labels: dateTimePickerLabelsConfig }));
|
|
7655
|
+
}, timezone: timezone, labels: dateTimePickerLabelsConfig, timePickerLabels: timePickerLabels }));
|
|
7471
7656
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7472
7657
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, autoFocus: false, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
7473
7658
|
setOpen(true);
|
|
@@ -7486,7 +7671,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7486
7671
|
}
|
|
7487
7672
|
if (variant === 'id-picker') {
|
|
7488
7673
|
idPickerSanityCheck(column, foreign_key);
|
|
7489
|
-
return jsx(
|
|
7674
|
+
return jsx(IdPickerSingle, { schema: colSchema, prefix, column });
|
|
7490
7675
|
}
|
|
7491
7676
|
if (format === 'date') {
|
|
7492
7677
|
return jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
@@ -7520,7 +7705,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7520
7705
|
if (type === 'array') {
|
|
7521
7706
|
if (variant === 'id-picker') {
|
|
7522
7707
|
idPickerSanityCheck(column, foreign_key);
|
|
7523
|
-
return
|
|
7708
|
+
return jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
|
|
7524
7709
|
}
|
|
7525
7710
|
if (variant === 'tag-picker') {
|
|
7526
7711
|
return jsx(TagPicker, { schema: colSchema, prefix, column });
|
|
@@ -7572,7 +7757,7 @@ const ArrayViewer = ({ schema, column, prefix }) => {
|
|
|
7572
7757
|
const { gridColumn = 'span 12', gridRow = 'span 1', required, items, } = schema;
|
|
7573
7758
|
const colLabel = `${prefix}${column}`;
|
|
7574
7759
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7575
|
-
const formI18n = useFormI18n
|
|
7760
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7576
7761
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7577
7762
|
const values = watch(colLabel) ?? [];
|
|
7578
7763
|
return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: '1/span12', children: [formI18n.label(), isRequired && jsx("span", { children: "*" })] }), jsx(Flex, { flexFlow: 'column', gap: 1, children: values.map((field, index) => (jsx(Flex, { flexFlow: 'column', bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: '2', borderRadius: 'md', borderWidth: 'thin', borderColor: {
|
|
@@ -7590,7 +7775,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
7590
7775
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7591
7776
|
const colLabel = `${prefix}${column}`;
|
|
7592
7777
|
const value = watch(colLabel);
|
|
7593
|
-
const formI18n = useFormI18n
|
|
7778
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7594
7779
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7595
7780
|
gridRow, children: [jsx(Text, { children: value ? formI18n.t('true') : formI18n.t('false') }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
7596
7781
|
};
|
|
@@ -7614,7 +7799,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7614
7799
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7615
7800
|
const colLabel = `${prefix}${column}`;
|
|
7616
7801
|
const selectedDate = watch(colLabel);
|
|
7617
|
-
const formI18n = useFormI18n
|
|
7802
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7618
7803
|
const displayDate = dayjs(selectedDate)
|
|
7619
7804
|
.tz(timezone)
|
|
7620
7805
|
.format(displayDateFormat);
|
|
@@ -7624,7 +7809,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7624
7809
|
|
|
7625
7810
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
7626
7811
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7627
|
-
const formI18n = useFormI18n
|
|
7812
|
+
const formI18n = useFormI18n(column, prefix);
|
|
7628
7813
|
const { required } = schema;
|
|
7629
7814
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7630
7815
|
const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
|
|
@@ -7648,7 +7833,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7648
7833
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
|
|
7649
7834
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7650
7835
|
const currentFiles = (watch(column) ?? []);
|
|
7651
|
-
const formI18n = useFormI18n
|
|
7836
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7652
7837
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, display: 'grid', gridTemplateRows: 'auto 1fr auto', alignItems: 'stretch', children: jsx(Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file) => {
|
|
7653
7838
|
return (jsx(Card.Root, { variant: 'subtle', children: jsxs(Card.Body, { gap: "2", display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', children: [file.type.startsWith('image/') && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name })] }) }, file.name));
|
|
7654
7839
|
}) }) }));
|
|
@@ -7656,7 +7841,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7656
7841
|
|
|
7657
7842
|
const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
7658
7843
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7659
|
-
const { idMap,
|
|
7844
|
+
const { idMap, idPickerLabels, formButtonLabels } = useSchemaContext();
|
|
7660
7845
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
7661
7846
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7662
7847
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
@@ -7680,12 +7865,12 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
7680
7865
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: 'wrap', gap: 1, children: watchIds.map((id) => {
|
|
7681
7866
|
const item = idMap[id];
|
|
7682
7867
|
if (item === undefined) {
|
|
7683
|
-
return (jsx(Text, { children:
|
|
7868
|
+
return (jsx(Text, { children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
7684
7869
|
}
|
|
7685
7870
|
return (jsx(Tag, { closable: true, children: renderDisplay
|
|
7686
7871
|
? renderDisplay(item)
|
|
7687
7872
|
: defaultRenderDisplay(item) }, id));
|
|
7688
|
-
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children:
|
|
7873
|
+
}) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: 'red.400', children: formButtonLabels?.fieldRequired ?? formI18n.required() }))] }));
|
|
7689
7874
|
};
|
|
7690
7875
|
|
|
7691
7876
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
@@ -7694,7 +7879,7 @@ const NumberViewer = ({ schema, column, prefix, }) => {
|
|
|
7694
7879
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7695
7880
|
const colLabel = `${prefix}${column}`;
|
|
7696
7881
|
const value = watch(colLabel);
|
|
7697
|
-
const formI18n = useFormI18n
|
|
7882
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7698
7883
|
// Format the value for display if formatOptions are provided
|
|
7699
7884
|
const formatValue = (val) => {
|
|
7700
7885
|
if (val === undefined || val === null || val === '')
|
|
@@ -7720,7 +7905,7 @@ const ObjectViewer = ({ schema, column, prefix }) => {
|
|
|
7720
7905
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
7721
7906
|
const colLabel = `${prefix}${column}`;
|
|
7722
7907
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7723
|
-
const formI18n = useFormI18n
|
|
7908
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7724
7909
|
const { formState: { errors }, } = useFormContext();
|
|
7725
7910
|
if (properties === undefined) {
|
|
7726
7911
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -7742,7 +7927,7 @@ const RecordViewer = ({ column, schema, prefix }) => {
|
|
|
7742
7927
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
7743
7928
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7744
7929
|
const entries = Object.entries(getValues(column) ?? {});
|
|
7745
|
-
const formI18n = useFormI18n
|
|
7930
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7746
7931
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn, gridRow, children: [entries.length === 0 ? (jsx(Text, { color: "gray.500", children: "No entries" })) : (jsx(Grid, { templateColumns: '1fr 1fr', gap: 2, children: entries.map(([key, value]) => {
|
|
7747
7932
|
return (jsxs(Grid, { templateColumns: '1fr 1fr', gap: 2, children: [jsxs(Text, { fontWeight: "medium", children: [key, ":"] }), jsx(Text, { children: String(value ?? '') })] }, key));
|
|
7748
7933
|
}) })), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
@@ -7754,7 +7939,7 @@ const StringViewer = ({ column, schema, prefix, }) => {
|
|
|
7754
7939
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7755
7940
|
const colLabel = `${prefix}${column}`;
|
|
7756
7941
|
const value = watch(colLabel);
|
|
7757
|
-
const formI18n = useFormI18n
|
|
7942
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7758
7943
|
return (jsx(Fragment, { children: jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', children: [jsx(Text, { children: value }), errors[colLabel] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }) }));
|
|
7759
7944
|
};
|
|
7760
7945
|
|
|
@@ -7849,7 +8034,7 @@ const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
|
7849
8034
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7850
8035
|
const colLabel = `${prefix}${column}`;
|
|
7851
8036
|
const value = watch(colLabel);
|
|
7852
|
-
const formI18n = useFormI18n
|
|
8037
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7853
8038
|
return (jsx(Fragment, { children: jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Text, { whiteSpace: "pre-wrap", children: value }), ' ', errors[colLabel] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }) }));
|
|
7854
8039
|
};
|
|
7855
8040
|
|
|
@@ -7860,7 +8045,7 @@ const TimeViewer = ({ column, schema, prefix }) => {
|
|
|
7860
8045
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7861
8046
|
const colLabel = `${prefix}${column}`;
|
|
7862
8047
|
const selectedDate = watch(colLabel);
|
|
7863
|
-
const formI18n = useFormI18n
|
|
8048
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7864
8049
|
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
7865
8050
|
.tz(timezone)
|
|
7866
8051
|
.isValid()
|
|
@@ -7877,7 +8062,7 @@ const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
|
7877
8062
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7878
8063
|
const colLabel = `${prefix}${column}`;
|
|
7879
8064
|
const selectedDate = watch(colLabel);
|
|
7880
|
-
const formI18n = useFormI18n
|
|
8065
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7881
8066
|
const displayDate = dayjs(selectedDate)
|
|
7882
8067
|
.tz(timezone)
|
|
7883
8068
|
.format(displayDateFormat);
|
|
@@ -7971,7 +8156,7 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
7971
8156
|
};
|
|
7972
8157
|
|
|
7973
8158
|
const SubmitButton = () => {
|
|
7974
|
-
const {
|
|
8159
|
+
const { setValidatedData, setIsError, setIsConfirming, requireConfirmation, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
7975
8160
|
const methods = useFormContext();
|
|
7976
8161
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7977
8162
|
const onValid = (data) => {
|
|
@@ -8000,11 +8185,11 @@ const SubmitButton = () => {
|
|
|
8000
8185
|
};
|
|
8001
8186
|
return (jsx(Button$1, { onClick: () => {
|
|
8002
8187
|
methods.handleSubmit(onValid)();
|
|
8003
|
-
}, formNoValidate: true, children: formButtonLabels?.submit ??
|
|
8188
|
+
}, formNoValidate: true, children: formButtonLabels?.submit ?? 'Submit' }));
|
|
8004
8189
|
};
|
|
8005
8190
|
|
|
8006
8191
|
const FormBody = () => {
|
|
8007
|
-
const { schema, order, ignore, include,
|
|
8192
|
+
const { schema, order, ignore, include, isError, isSubmiting, isConfirming, setIsConfirming, validatedData, error, customErrorRenderer, displayConfig, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
8008
8193
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
8009
8194
|
const methods = useFormContext();
|
|
8010
8195
|
const { properties } = schema;
|
|
@@ -8021,21 +8206,6 @@ const FormBody = () => {
|
|
|
8021
8206
|
ignore,
|
|
8022
8207
|
include,
|
|
8023
8208
|
});
|
|
8024
|
-
if (isSuccess) {
|
|
8025
|
-
const resetHandler = async () => {
|
|
8026
|
-
setIsError(false);
|
|
8027
|
-
setIsSubmiting(false);
|
|
8028
|
-
setIsSuccess(false);
|
|
8029
|
-
setIsConfirming(false);
|
|
8030
|
-
setValidatedData(undefined);
|
|
8031
|
-
const data = await getUpdatedData();
|
|
8032
|
-
methods.reset(data);
|
|
8033
|
-
};
|
|
8034
|
-
if (customSuccessRenderer) {
|
|
8035
|
-
return customSuccessRenderer(resetHandler);
|
|
8036
|
-
}
|
|
8037
|
-
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t('submit_success') }) })] }), jsx(Flex, { justifyContent: 'end', children: jsx(Button$1, { onClick: resetHandler, formNoValidate: true, children: formButtonLabels?.submitAgain ?? translate.t('submit_again') }) })] }));
|
|
8038
|
-
}
|
|
8039
8209
|
if (isConfirming) {
|
|
8040
8210
|
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: 'repeat(12, max-content)', autoFlow: 'row', children: ordered.map((column) => {
|
|
8041
8211
|
return (jsx(ColumnViewer
|
|
@@ -8045,9 +8215,9 @@ const FormBody = () => {
|
|
|
8045
8215
|
properties: properties, prefix: ``, column }, `form-viewer-${column}`));
|
|
8046
8216
|
}) }), jsxs(Flex, { justifyContent: 'end', gap: '2', children: [jsx(Button$1, { onClick: () => {
|
|
8047
8217
|
setIsConfirming(false);
|
|
8048
|
-
}, variant: 'subtle', children: formButtonLabels?.cancel ??
|
|
8218
|
+
}, variant: 'subtle', children: formButtonLabels?.cancel ?? 'Cancel' }), jsx(Button$1, { onClick: () => {
|
|
8049
8219
|
onFormSubmit(validatedData);
|
|
8050
|
-
}, children: formButtonLabels?.confirm ??
|
|
8220
|
+
}, children: formButtonLabels?.confirm ?? 'Confirm' })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8051
8221
|
}
|
|
8052
8222
|
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
|
|
8053
8223
|
return (jsx(ColumnRenderer
|
|
@@ -8057,12 +8227,12 @@ const FormBody = () => {
|
|
|
8057
8227
|
properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
|
|
8058
8228
|
}) }), jsxs(Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
|
|
8059
8229
|
methods.reset();
|
|
8060
|
-
}, variant: 'subtle', children: formButtonLabels?.reset ??
|
|
8230
|
+
}, variant: 'subtle', children: formButtonLabels?.reset ?? 'Reset' })), showSubmitButton && jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8061
8231
|
};
|
|
8062
8232
|
|
|
8063
8233
|
const FormTitle = () => {
|
|
8064
|
-
const {
|
|
8065
|
-
return jsx(Heading, { children:
|
|
8234
|
+
const { schema } = useSchemaContext();
|
|
8235
|
+
return jsx(Heading, { children: schema.title ?? 'Form' });
|
|
8066
8236
|
};
|
|
8067
8237
|
|
|
8068
8238
|
const DefaultForm = ({ formConfig, }) => {
|
|
@@ -8070,7 +8240,9 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
8070
8240
|
return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
|
|
8071
8241
|
};
|
|
8072
8242
|
|
|
8073
|
-
const useForm = ({ preLoadedValues, keyPrefix
|
|
8243
|
+
const useForm = ({ preLoadedValues, keyPrefix: _keyPrefix, // Deprecated: kept for backward compatibility
|
|
8244
|
+
namespace: _namespace, // Deprecated: kept for backward compatibility
|
|
8245
|
+
schema, }) => {
|
|
8074
8246
|
const form = useForm$1({
|
|
8075
8247
|
values: preLoadedValues,
|
|
8076
8248
|
resolver: schema ? ajvResolver(schema) : undefined,
|
|
@@ -8078,12 +8250,16 @@ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
|
|
|
8078
8250
|
reValidateMode: 'onBlur',
|
|
8079
8251
|
});
|
|
8080
8252
|
const [idMap, setIdMap] = useState({});
|
|
8081
|
-
|
|
8253
|
+
// Fallback translate object - returns key as-is (no i18n required)
|
|
8254
|
+
const translate = {
|
|
8255
|
+
t: (key) => key,
|
|
8256
|
+
ready: true,
|
|
8257
|
+
};
|
|
8082
8258
|
return {
|
|
8083
8259
|
form,
|
|
8084
8260
|
idMap,
|
|
8085
8261
|
setIdMap,
|
|
8086
|
-
translate,
|
|
8262
|
+
translate, // Components prefer label objects over translate
|
|
8087
8263
|
};
|
|
8088
8264
|
};
|
|
8089
8265
|
|
|
@@ -8411,6 +8587,21 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
|
8411
8587
|
})] }));
|
|
8412
8588
|
};
|
|
8413
8589
|
|
|
8590
|
+
const MobileTableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsx(Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
|
|
8591
|
+
const { tableLabel, table } = useDataTableContext();
|
|
8592
|
+
const { hasErrorText } = tableLabel;
|
|
8593
|
+
return (jsxs(Grid, { templateRows: 'auto 1fr auto', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: 2, padding: 2, ...gridProps, children: [jsxs(Stack, { gap: 2, children: [jsxs(Flex, { justifyContent: 'space-between', alignItems: 'center', gap: 2, children: [jsxs(Flex, { gap: 1, alignItems: 'center', children: [showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }), loading && jsx(Spinner, { size: 'sm' }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: 'red.400' }) }))] }), jsxs(Flex, { gap: 1, alignItems: 'center', children: [showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsx(Stack, { gap: 2, children: filterTagsOptions.map((option) => {
|
|
8594
|
+
const { column, options } = option;
|
|
8595
|
+
const tableColumn = table.getColumn(column);
|
|
8596
|
+
return (jsxs(Flex, { flexFlow: 'column', gap: 1, width: '100%', children: [tableColumn?.columnDef.meta?.displayName && (jsx(Text, { fontSize: 'sm', fontWeight: 'medium', children: tableColumn?.columnDef.meta?.displayName })), jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
|
|
8597
|
+
if (tags.length === 0) {
|
|
8598
|
+
return tableColumn?.setFilterValue(undefined);
|
|
8599
|
+
}
|
|
8600
|
+
tableColumn?.setFilterValue(tags);
|
|
8601
|
+
} })] }, column));
|
|
8602
|
+
}) })), showFilterTags && (jsx(Box, { width: '100%', children: jsx(TableFilterTags, {}) }))] }), jsx(Box, { overflow: 'auto', width: '100%', bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, borderRadius: 'md', padding: 1, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Stack, { gap: 2, width: '100%', children: [(showPageSizeControl || showPageCountText) && (jsxs(Flex, { justifyContent: 'space-between', alignItems: 'center', gap: 2, flexWrap: 'wrap', children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && jsx(RowCountText, {})] })), showPagination && (jsx(Flex, { justifyContent: 'center', width: '100%', children: jsx(Pagination, {}) }))] }))] }));
|
|
8603
|
+
};
|
|
8604
|
+
|
|
8414
8605
|
const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
|
|
8415
8606
|
'use no memo';
|
|
8416
8607
|
const { table } = useDataTableContext();
|
|
@@ -8470,22 +8661,77 @@ const TableRowSelectorSkeleton = () => {
|
|
|
8470
8661
|
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsx(Skeleton, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }) }));
|
|
8471
8662
|
};
|
|
8472
8663
|
|
|
8473
|
-
const
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
return
|
|
8477
|
-
|
|
8478
|
-
|
|
8664
|
+
const MobileTableDisplay = ({ showSelector = false, isLoading = false, }) => {
|
|
8665
|
+
const { table, rowSelection, setRowSelection } = useDataTableContext();
|
|
8666
|
+
if (isLoading) {
|
|
8667
|
+
return jsx(MobileTableSkeleton, { showSelector: showSelector });
|
|
8668
|
+
}
|
|
8669
|
+
return (jsx(Stack, { gap: 4, padding: 2, children: table.getRowModel().rows.map((row) => {
|
|
8670
|
+
return (jsx(Card.Root, { width: "100%", children: jsxs(Card.Body, { padding: 4, children: [showSelector && (jsx(Flex, { marginBottom: 3, children: jsx(Checkbox, { checked: isRowSelected(row.id, rowSelection),
|
|
8671
|
+
disabled: !canRowSelect(row),
|
|
8672
|
+
onCheckedChange: createRowToggleHandler(row, rowSelection, setRowSelection) }) })), jsx(Stack, { gap: 3, children: row.getVisibleCells().map((cell) => {
|
|
8673
|
+
const displayName = cell.column.columnDef.meta?.displayName ?? cell.column.id;
|
|
8674
|
+
return (jsxs(Box, { children: [jsx(Text, { fontSize: "sm", fontWeight: "bold", color: { base: 'gray.600', _dark: 'gray.400' }, marginBottom: 1, children: displayName }), jsx(Box, { color: { base: 'gray.900', _dark: 'gray.100' }, fontSize: "sm", children: flexRender(cell.column.columnDef.cell, cell.getContext()) })] }, `mobile-table-cell-${cell.id}`));
|
|
8675
|
+
}) })] }) }, `mobile-table-card-${row.id}`));
|
|
8676
|
+
}) }));
|
|
8677
|
+
};
|
|
8678
|
+
const MobileTableSkeleton = ({ showSelector = false, }) => {
|
|
8679
|
+
const { table } = useDataTableContext();
|
|
8680
|
+
const pageSize = table.getState().pagination.pageSize;
|
|
8681
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
8682
|
+
return (jsx(Stack, { gap: 4, padding: 2, children: Array.from({ length: pageSize }).map((_, rowIndex) => {
|
|
8683
|
+
return (jsx(Card.Root, { width: "100%", children: jsxs(Card.Body, { padding: 4, children: [showSelector && (jsx(Flex, { marginBottom: 3, children: jsx(Box, { width: "20px", height: "20px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "md" }) })), jsx(Stack, { gap: 3, children: visibleColumns.map((column) => {
|
|
8684
|
+
return (jsxs(Box, { children: [jsx(Box, { width: "40%", height: "16px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "sm", marginBottom: 2 }), jsx(Box, { width: "80%", height: "20px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "sm" })] }, `mobile-skeleton-cell-${column.id}`));
|
|
8685
|
+
}) })] }) }, `mobile-skeleton-${rowIndex}`));
|
|
8686
|
+
}) }));
|
|
8687
|
+
};
|
|
8688
|
+
|
|
8689
|
+
/**
|
|
8690
|
+
* Hook to detect if the current window width is mobile (< 768px)
|
|
8691
|
+
* @param breakpoint - The breakpoint in pixels to consider as mobile (default: 768)
|
|
8692
|
+
* @returns boolean indicating if the window is mobile
|
|
8693
|
+
*/
|
|
8694
|
+
const useIsMobile = (breakpoint = 768) => {
|
|
8695
|
+
const [isMobile, setIsMobile] = useState(() => {
|
|
8696
|
+
if (typeof window === 'undefined')
|
|
8697
|
+
return false;
|
|
8698
|
+
return window.innerWidth < breakpoint;
|
|
8699
|
+
});
|
|
8700
|
+
useEffect(() => {
|
|
8701
|
+
if (typeof window === 'undefined')
|
|
8702
|
+
return;
|
|
8703
|
+
const handleResize = () => {
|
|
8704
|
+
setIsMobile(window.innerWidth < breakpoint);
|
|
8705
|
+
};
|
|
8706
|
+
// Set initial value
|
|
8707
|
+
handleResize();
|
|
8708
|
+
// Add event listener
|
|
8709
|
+
window.addEventListener('resize', handleResize);
|
|
8710
|
+
// Cleanup
|
|
8711
|
+
return () => {
|
|
8712
|
+
window.removeEventListener('resize', handleResize);
|
|
8713
|
+
};
|
|
8714
|
+
}, [breakpoint]);
|
|
8715
|
+
return isMobile;
|
|
8716
|
+
};
|
|
8717
|
+
|
|
8718
|
+
const DefaultTable = ({ showFooter = false, showHeader = true, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = 'greedy', isLoading = false, }) => {
|
|
8719
|
+
const isMobile = useIsMobile();
|
|
8720
|
+
// Early return for mobile display
|
|
8721
|
+
if (isMobile) {
|
|
8722
|
+
return (jsx(MobileTableControls, { ...controlProps, children: jsx(MobileTableDisplay, { showSelector: tableHeaderProps.showSelector ??
|
|
8479
8723
|
tableBodyProps.showSelector ??
|
|
8480
|
-
false,
|
|
8481
|
-
...tableProps, children: [jsx(TableHeader, { canResize: false, ...tableHeaderProps }), bodyComponent, showFooter && (jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
|
|
8724
|
+
false, isLoading: isLoading }) }));
|
|
8482
8725
|
}
|
|
8483
|
-
const
|
|
8484
|
-
|
|
8726
|
+
const isGreedy = variant === 'greedy';
|
|
8727
|
+
const canResize = !isGreedy;
|
|
8728
|
+
const bodyComponent = isLoading ? (jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: canResize })) : (jsx(TableBody, { ...tableBodyProps, canResize: canResize }));
|
|
8729
|
+
return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { canResize,
|
|
8730
|
+
showLoading: isLoading,
|
|
8485
8731
|
showSelector: tableHeaderProps.showSelector ??
|
|
8486
8732
|
tableBodyProps.showSelector ??
|
|
8487
8733
|
false,
|
|
8488
|
-
...tableProps, children: [jsx(TableHeader, { ...tableHeaderProps }), bodyComponent, showFooter && jsx(TableFooter, { ...tableFooterProps })] }) }));
|
|
8734
|
+
...tableProps, children: [showHeader && jsx(TableHeader, { canResize, ...tableHeaderProps }), bodyComponent, showFooter && jsx(TableFooter, { canResize, ...tableFooterProps })] }) }));
|
|
8489
8735
|
};
|
|
8490
8736
|
|
|
8491
8737
|
/**
|
|
@@ -8577,6 +8823,290 @@ const DataDisplay = ({ variant = '' }) => {
|
|
|
8577
8823
|
}) }));
|
|
8578
8824
|
};
|
|
8579
8825
|
|
|
8826
|
+
// Helper function to normalize date
|
|
8827
|
+
function normalizeDate(value) {
|
|
8828
|
+
if (!value)
|
|
8829
|
+
return null;
|
|
8830
|
+
if (value instanceof Date)
|
|
8831
|
+
return value;
|
|
8832
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
8833
|
+
const date = dayjs(value).toDate();
|
|
8834
|
+
return isNaN(date.getTime()) ? null : date;
|
|
8835
|
+
}
|
|
8836
|
+
return null;
|
|
8837
|
+
}
|
|
8838
|
+
// Component to conditionally render event title based on available width
|
|
8839
|
+
function ResponsiveEventTitle({ title, placeholder, minWidth, minChars, cellRef, }) {
|
|
8840
|
+
const [truncatedText, setTruncatedText] = useState('');
|
|
8841
|
+
const measureRef = useRef(null);
|
|
8842
|
+
useEffect(() => {
|
|
8843
|
+
const calculateTruncatedText = () => {
|
|
8844
|
+
if (!cellRef.current || !measureRef.current || !title) {
|
|
8845
|
+
setTruncatedText(title || 'Event');
|
|
8846
|
+
return;
|
|
8847
|
+
}
|
|
8848
|
+
const cellWidth = cellRef.current.clientWidth;
|
|
8849
|
+
// Account for padding (approximately 8px on each side)
|
|
8850
|
+
const availableWidth = cellWidth - 16;
|
|
8851
|
+
// If cell is too narrow, calculate how many characters can fit
|
|
8852
|
+
if (availableWidth < minWidth) {
|
|
8853
|
+
// Measure text width using canvas
|
|
8854
|
+
const canvas = document.createElement('canvas');
|
|
8855
|
+
const context = canvas.getContext('2d');
|
|
8856
|
+
if (!context) {
|
|
8857
|
+
setTruncatedText(placeholder);
|
|
8858
|
+
return;
|
|
8859
|
+
}
|
|
8860
|
+
// Get computed font style from the element
|
|
8861
|
+
const computedStyle = window.getComputedStyle(measureRef.current);
|
|
8862
|
+
context.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;
|
|
8863
|
+
const ellipsisWidth = context.measureText('...').width;
|
|
8864
|
+
const maxWidth = availableWidth - ellipsisWidth;
|
|
8865
|
+
// Try to show at least minChars characters before ellipsis
|
|
8866
|
+
let truncated = '';
|
|
8867
|
+
let charCount = 0;
|
|
8868
|
+
// Calculate how many characters can fit
|
|
8869
|
+
for (let i = 0; i < Math.min(title.length, 50); i++) {
|
|
8870
|
+
const testText = title.substring(0, i + 1);
|
|
8871
|
+
const textWidth = context.measureText(testText).width;
|
|
8872
|
+
if (textWidth <= maxWidth) {
|
|
8873
|
+
truncated = testText;
|
|
8874
|
+
charCount = i + 1;
|
|
8875
|
+
}
|
|
8876
|
+
else {
|
|
8877
|
+
break;
|
|
8878
|
+
}
|
|
8879
|
+
}
|
|
8880
|
+
// Ensure we show at least minChars characters if possible
|
|
8881
|
+
if (charCount < minChars && title.length >= minChars) {
|
|
8882
|
+
truncated = title.substring(0, minChars);
|
|
8883
|
+
}
|
|
8884
|
+
else if (charCount === 0 && title.length >= 1) {
|
|
8885
|
+
truncated = title.substring(0, 1);
|
|
8886
|
+
}
|
|
8887
|
+
// Only show ellipsis if we have at least minChars characters
|
|
8888
|
+
if (truncated && truncated.length >= minChars) {
|
|
8889
|
+
setTruncatedText(`${truncated}...`);
|
|
8890
|
+
}
|
|
8891
|
+
else {
|
|
8892
|
+
setTruncatedText(placeholder);
|
|
8893
|
+
}
|
|
8894
|
+
}
|
|
8895
|
+
else {
|
|
8896
|
+
// Full width available, show full title
|
|
8897
|
+
setTruncatedText(title);
|
|
8898
|
+
}
|
|
8899
|
+
};
|
|
8900
|
+
calculateTruncatedText();
|
|
8901
|
+
const resizeObserver = new ResizeObserver(calculateTruncatedText);
|
|
8902
|
+
if (cellRef.current) {
|
|
8903
|
+
resizeObserver.observe(cellRef.current);
|
|
8904
|
+
}
|
|
8905
|
+
// Also check on window resize
|
|
8906
|
+
window.addEventListener('resize', calculateTruncatedText);
|
|
8907
|
+
return () => {
|
|
8908
|
+
resizeObserver.disconnect();
|
|
8909
|
+
window.removeEventListener('resize', calculateTruncatedText);
|
|
8910
|
+
};
|
|
8911
|
+
}, [cellRef, minWidth, title, placeholder]);
|
|
8912
|
+
return (jsxs(Fragment, { children: [jsx("span", { ref: measureRef, style: {
|
|
8913
|
+
visibility: 'hidden',
|
|
8914
|
+
position: 'absolute',
|
|
8915
|
+
whiteSpace: 'nowrap',
|
|
8916
|
+
}, children: title || 'Event' }), truncatedText || title || 'Event'] }));
|
|
8917
|
+
}
|
|
8918
|
+
function CalendarDisplay({ dateColumn, getDate, getEventTitle, getEventColor, renderEvent, firstDayOfWeek = 0, showOutsideDays = true, monthsToDisplay = 1, labels = {
|
|
8919
|
+
monthNamesShort: [
|
|
8920
|
+
'Jan',
|
|
8921
|
+
'Feb',
|
|
8922
|
+
'Mar',
|
|
8923
|
+
'Apr',
|
|
8924
|
+
'May',
|
|
8925
|
+
'Jun',
|
|
8926
|
+
'Jul',
|
|
8927
|
+
'Aug',
|
|
8928
|
+
'Sep',
|
|
8929
|
+
'Oct',
|
|
8930
|
+
'Nov',
|
|
8931
|
+
'Dec',
|
|
8932
|
+
],
|
|
8933
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
8934
|
+
backButtonLabel: 'Back',
|
|
8935
|
+
forwardButtonLabel: 'Next',
|
|
8936
|
+
}, onDateClick, onEventClick, maxEventsPerDay = 3, colorPalette = 'blue', eventPlaceholder = '...', minEventWidth = 80, minCharsBeforeEllipsis = 2, }) {
|
|
8937
|
+
const { data, table } = useDataTableContext();
|
|
8938
|
+
// Map table data to events
|
|
8939
|
+
const events = useMemo(() => {
|
|
8940
|
+
return data
|
|
8941
|
+
.map((row) => {
|
|
8942
|
+
let dateValue;
|
|
8943
|
+
if (getDate) {
|
|
8944
|
+
dateValue = getDate(row);
|
|
8945
|
+
}
|
|
8946
|
+
else {
|
|
8947
|
+
// Try to get date from column
|
|
8948
|
+
const rowData = table
|
|
8949
|
+
.getRowModel()
|
|
8950
|
+
.rows.find((r) => r.original === row);
|
|
8951
|
+
if (rowData) {
|
|
8952
|
+
const cell = rowData.getAllCells().find((c) => {
|
|
8953
|
+
const colId = c.column.id;
|
|
8954
|
+
const accessorKey = c.column.columnDef.accessorKey;
|
|
8955
|
+
return colId === dateColumn || accessorKey === dateColumn;
|
|
8956
|
+
});
|
|
8957
|
+
dateValue = cell?.getValue();
|
|
8958
|
+
}
|
|
8959
|
+
}
|
|
8960
|
+
const date = normalizeDate(dateValue);
|
|
8961
|
+
if (!date)
|
|
8962
|
+
return null;
|
|
8963
|
+
let title;
|
|
8964
|
+
if (getEventTitle) {
|
|
8965
|
+
title = getEventTitle(row);
|
|
8966
|
+
}
|
|
8967
|
+
else {
|
|
8968
|
+
// Use first column's value as title
|
|
8969
|
+
const rowData = table
|
|
8970
|
+
.getRowModel()
|
|
8971
|
+
.rows.find((r) => r.original === row);
|
|
8972
|
+
if (rowData) {
|
|
8973
|
+
const firstCell = rowData.getAllCells()[0];
|
|
8974
|
+
title = String(firstCell?.getValue() ?? '');
|
|
8975
|
+
}
|
|
8976
|
+
}
|
|
8977
|
+
const color = getEventColor?.(row);
|
|
8978
|
+
return {
|
|
8979
|
+
data: row,
|
|
8980
|
+
date,
|
|
8981
|
+
title,
|
|
8982
|
+
color,
|
|
8983
|
+
};
|
|
8984
|
+
})
|
|
8985
|
+
.filter((event) => event !== null);
|
|
8986
|
+
}, [data, table, dateColumn, getDate, getEventTitle, getEventColor]);
|
|
8987
|
+
// Group events by date
|
|
8988
|
+
const eventsByDate = useMemo(() => {
|
|
8989
|
+
const map = new Map();
|
|
8990
|
+
events.forEach((event) => {
|
|
8991
|
+
const dateKey = `${event.date.getFullYear()}-${event.date.getMonth()}-${event.date.getDate()}`;
|
|
8992
|
+
if (!map.has(dateKey)) {
|
|
8993
|
+
map.set(dateKey, []);
|
|
8994
|
+
}
|
|
8995
|
+
map.get(dateKey).push(event);
|
|
8996
|
+
});
|
|
8997
|
+
return map;
|
|
8998
|
+
}, [events]);
|
|
8999
|
+
// Get events for a specific date
|
|
9000
|
+
const getEventsForDate = useCallback((date) => {
|
|
9001
|
+
const dateKey = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
|
9002
|
+
return eventsByDate.get(dateKey) ?? [];
|
|
9003
|
+
}, [eventsByDate]);
|
|
9004
|
+
const calendarData = useCalendar({
|
|
9005
|
+
firstDayOfWeek,
|
|
9006
|
+
showOutsideDays,
|
|
9007
|
+
monthsToDisplay,
|
|
9008
|
+
});
|
|
9009
|
+
const getDateProps = useCallback((props) => {
|
|
9010
|
+
const dateEvents = getEventsForDate(props.dateObj.date);
|
|
9011
|
+
const baseProps = calendarData.getDateProps({ dateObj: props.dateObj });
|
|
9012
|
+
return {
|
|
9013
|
+
...baseProps,
|
|
9014
|
+
onClick: () => {
|
|
9015
|
+
baseProps.onClick?.();
|
|
9016
|
+
if (onDateClick) {
|
|
9017
|
+
onDateClick(props.dateObj.date, dateEvents);
|
|
9018
|
+
}
|
|
9019
|
+
},
|
|
9020
|
+
};
|
|
9021
|
+
}, [calendarData, getEventsForDate, onDateClick]);
|
|
9022
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
9023
|
+
if (!calendarData.calendars.length) {
|
|
9024
|
+
return null;
|
|
9025
|
+
}
|
|
9026
|
+
return (jsxs(VStack, { gap: 4, width: "100%", children: [jsxs(HStack, { gap: 2, justifyContent: "center", children: [jsx(Button$1, { variant: "ghost", ...calendarData.getBackProps({
|
|
9027
|
+
calendars: calendarData.calendars,
|
|
9028
|
+
offset: 12,
|
|
9029
|
+
}), children: '<<' }), jsx(Button$1, { variant: "ghost", ...calendarData.getBackProps({ calendars: calendarData.calendars }), children: backButtonLabel }), jsx(Button$1, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9030
|
+
calendars: calendarData.calendars,
|
|
9031
|
+
}), children: forwardButtonLabel }), jsx(Button$1, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9032
|
+
calendars: calendarData.calendars,
|
|
9033
|
+
offset: 12,
|
|
9034
|
+
}), children: '>>' })] }), jsx(Grid, { templateColumns: {
|
|
9035
|
+
base: '1fr',
|
|
9036
|
+
md: monthsToDisplay >= 2 ? 'repeat(2, 1fr)' : '1fr',
|
|
9037
|
+
lg: monthsToDisplay >= 3
|
|
9038
|
+
? 'repeat(3, 1fr)'
|
|
9039
|
+
: monthsToDisplay === 2
|
|
9040
|
+
? 'repeat(2, 1fr)'
|
|
9041
|
+
: '1fr',
|
|
9042
|
+
xl: `repeat(${Math.min(monthsToDisplay, 4)}, 1fr)`,
|
|
9043
|
+
}, gap: { base: 4, md: 6 }, width: "100%", justifyContent: "center", children: calendarData.calendars.map((calendar) => (jsxs(VStack, { gap: 2, alignItems: "stretch", children: [jsxs(Text, { textAlign: "center", fontSize: { base: 'md', md: 'lg' }, fontWeight: "semibold", children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsx(Grid, { templateColumns: "repeat(7, 1fr)", gap: { base: 0.5, md: 1 }, children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
9044
|
+
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
9045
|
+
return (jsx(Text, { textAlign: "center", fontSize: { base: 'xs', md: 'sm' }, fontWeight: "medium", color: { base: 'gray.600', _dark: 'gray.400' }, children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
9046
|
+
}) }), jsx(Grid, { templateColumns: "repeat(7, 1fr)", gap: { base: 0.5, md: 1 }, children: calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
9047
|
+
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
9048
|
+
if (!dateObj) {
|
|
9049
|
+
return jsx(Box, {}, key);
|
|
9050
|
+
}
|
|
9051
|
+
const { date, today, isCurrentMonth } = dateObj;
|
|
9052
|
+
const dateEvents = getEventsForDate(date);
|
|
9053
|
+
const cellRef = useRef(null);
|
|
9054
|
+
return (jsxs(VStack, { ref: cellRef, gap: { base: 0.25, md: 0.5 }, alignItems: "stretch", minHeight: { base: '60px', md: '80px', lg: '100px' }, borderWidth: "1px", borderColor: {
|
|
9055
|
+
base: today ? `${colorPalette}.300` : 'gray.200',
|
|
9056
|
+
_dark: today ? `${colorPalette}.700` : 'gray.700',
|
|
9057
|
+
}, borderRadius: { base: 'sm', md: 'md' }, padding: { base: 0.5, md: 1 }, bgColor: {
|
|
9058
|
+
base: today ? `${colorPalette}.50` : 'white',
|
|
9059
|
+
_dark: today ? `${colorPalette}.950` : 'gray.900',
|
|
9060
|
+
}, opacity: isCurrentMonth ? 1 : 0.5, ...getDateProps({ dateObj }), cursor: onDateClick ? 'pointer' : 'default', _hover: onDateClick
|
|
9061
|
+
? {
|
|
9062
|
+
bgColor: {
|
|
9063
|
+
base: `${colorPalette}.100`,
|
|
9064
|
+
_dark: `${colorPalette}.900`,
|
|
9065
|
+
},
|
|
9066
|
+
}
|
|
9067
|
+
: {}, children: [jsx(Text, { fontSize: { base: 'xs', md: 'sm' }, fontWeight: today ? 'bold' : 'normal', color: {
|
|
9068
|
+
base: today ? `${colorPalette}.700` : 'gray.700',
|
|
9069
|
+
_dark: today ? `${colorPalette}.300` : 'gray.300',
|
|
9070
|
+
}, textAlign: "right", paddingRight: { base: 0.5, md: 1 }, children: date.getDate() }), jsxs(VStack, { gap: { base: 0.25, md: 0.5 }, alignItems: "stretch", flex: 1, overflow: "hidden", children: [dateEvents
|
|
9071
|
+
.slice(0, maxEventsPerDay)
|
|
9072
|
+
.map((event, eventIndex) => {
|
|
9073
|
+
const eventContent = renderEvent ? (renderEvent(event)) : (jsx(Box, { fontSize: { base: '2xs', md: 'xs' }, paddingX: { base: 0.5, md: 1 }, paddingY: { base: 0.25, md: 0.5 }, borderRadius: { base: 'xs', md: 'sm' }, bgColor: {
|
|
9074
|
+
base: event.color
|
|
9075
|
+
? `${event.color}.100`
|
|
9076
|
+
: `${colorPalette}.100`,
|
|
9077
|
+
_dark: event.color
|
|
9078
|
+
? `${event.color}.900`
|
|
9079
|
+
: `${colorPalette}.900`,
|
|
9080
|
+
}, color: {
|
|
9081
|
+
base: event.color
|
|
9082
|
+
? `${event.color}.800`
|
|
9083
|
+
: `${colorPalette}.800`,
|
|
9084
|
+
_dark: event.color
|
|
9085
|
+
? `${event.color}.200`
|
|
9086
|
+
: `${colorPalette}.200`,
|
|
9087
|
+
}, onClick: (e) => {
|
|
9088
|
+
e.stopPropagation();
|
|
9089
|
+
if (onEventClick) {
|
|
9090
|
+
onEventClick(event);
|
|
9091
|
+
}
|
|
9092
|
+
}, cursor: onEventClick ? 'pointer' : 'default', _hover: onEventClick
|
|
9093
|
+
? {
|
|
9094
|
+
opacity: 0.8,
|
|
9095
|
+
}
|
|
9096
|
+
: {}, children: jsx(ResponsiveEventTitle, { title: event.title, placeholder: eventPlaceholder, minWidth: minEventWidth, minChars: minCharsBeforeEllipsis, cellRef: cellRef }) }, eventIndex));
|
|
9097
|
+
return (jsx(Box, { onClick: (e) => e.stopPropagation(), children: eventContent }, eventIndex));
|
|
9098
|
+
}), dateEvents.length > maxEventsPerDay && (jsxs(Text, { fontSize: "xs", color: {
|
|
9099
|
+
base: `${colorPalette}.600`,
|
|
9100
|
+
_dark: `${colorPalette}.400`,
|
|
9101
|
+
}, paddingX: 1, onClick: (e) => {
|
|
9102
|
+
e.stopPropagation();
|
|
9103
|
+
if (onDateClick) {
|
|
9104
|
+
onDateClick(date, dateEvents);
|
|
9105
|
+
}
|
|
9106
|
+
}, cursor: onDateClick ? 'pointer' : 'default', children: ["+", dateEvents.length - maxEventsPerDay, " more"] }))] })] }, key));
|
|
9107
|
+
})) })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
9108
|
+
}
|
|
9109
|
+
|
|
8580
9110
|
// Reference: https://tanstack.com/table/latest/docs/framework/react/examples/custom-features
|
|
8581
9111
|
// TypeScript setup for our new feature with all of the same type-safety as stock TanStack Table features
|
|
8582
9112
|
// end of TS setup!
|
|
@@ -8677,7 +9207,7 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
|
|
|
8677
9207
|
*
|
|
8678
9208
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8679
9209
|
*/
|
|
8680
|
-
function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility,
|
|
9210
|
+
function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, children, tableLabel = {
|
|
8681
9211
|
view: 'View',
|
|
8682
9212
|
edit: 'Edit',
|
|
8683
9213
|
filterButtonText: 'Filter',
|
|
@@ -8688,7 +9218,7 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8688
9218
|
reloadButtonText: 'Reload',
|
|
8689
9219
|
resetSelection: 'Reset Selection',
|
|
8690
9220
|
resetSorting: 'Reset Sorting',
|
|
8691
|
-
rowCountText: '
|
|
9221
|
+
rowCountText: '',
|
|
8692
9222
|
hasErrorText: 'Has Error',
|
|
8693
9223
|
globalFilterPlaceholder: 'Search',
|
|
8694
9224
|
trueLabel: 'True',
|
|
@@ -8745,7 +9275,6 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8745
9275
|
globalFilter,
|
|
8746
9276
|
setGlobalFilter,
|
|
8747
9277
|
type: 'client',
|
|
8748
|
-
translate,
|
|
8749
9278
|
columns: columns,
|
|
8750
9279
|
sorting,
|
|
8751
9280
|
setSorting,
|
|
@@ -8777,22 +9306,22 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8777
9306
|
*
|
|
8778
9307
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8779
9308
|
*/
|
|
8780
|
-
function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url,
|
|
8781
|
-
view:
|
|
8782
|
-
edit:
|
|
8783
|
-
filterButtonText:
|
|
8784
|
-
filterTitle:
|
|
8785
|
-
filterReset:
|
|
8786
|
-
filterClose:
|
|
8787
|
-
reloadTooltip:
|
|
8788
|
-
reloadButtonText:
|
|
8789
|
-
resetSelection:
|
|
8790
|
-
resetSorting:
|
|
8791
|
-
rowCountText:
|
|
8792
|
-
hasErrorText:
|
|
8793
|
-
globalFilterPlaceholder:
|
|
8794
|
-
trueLabel:
|
|
8795
|
-
falseLabel:
|
|
9309
|
+
function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url, children, tableLabel = {
|
|
9310
|
+
view: 'View',
|
|
9311
|
+
edit: 'Edit',
|
|
9312
|
+
filterButtonText: 'Filter',
|
|
9313
|
+
filterTitle: 'Filter',
|
|
9314
|
+
filterReset: 'Reset',
|
|
9315
|
+
filterClose: 'Close',
|
|
9316
|
+
reloadTooltip: 'Reload',
|
|
9317
|
+
reloadButtonText: 'Reload',
|
|
9318
|
+
resetSelection: 'Reset Selection',
|
|
9319
|
+
resetSorting: 'Reset Sorting',
|
|
9320
|
+
rowCountText: '',
|
|
9321
|
+
hasErrorText: 'Has Error',
|
|
9322
|
+
globalFilterPlaceholder: 'Search',
|
|
9323
|
+
trueLabel: 'True',
|
|
9324
|
+
falseLabel: 'False',
|
|
8796
9325
|
}, }) {
|
|
8797
9326
|
const table = useReactTable({
|
|
8798
9327
|
_features: [DensityFeature],
|
|
@@ -8802,7 +9331,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8802
9331
|
getCoreRowModel: getCoreRowModel(),
|
|
8803
9332
|
manualPagination: true,
|
|
8804
9333
|
manualSorting: true,
|
|
8805
|
-
columnResizeMode:
|
|
9334
|
+
columnResizeMode: 'onChange',
|
|
8806
9335
|
defaultColumn: {
|
|
8807
9336
|
size: 150, //starting column size
|
|
8808
9337
|
minSize: 10, //enforced during column resizing
|
|
@@ -8845,8 +9374,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8845
9374
|
table: table,
|
|
8846
9375
|
globalFilter,
|
|
8847
9376
|
setGlobalFilter,
|
|
8848
|
-
type:
|
|
8849
|
-
translate,
|
|
9377
|
+
type: 'server',
|
|
8850
9378
|
columns: columns,
|
|
8851
9379
|
sorting,
|
|
8852
9380
|
setSorting,
|
|
@@ -8864,7 +9392,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8864
9392
|
setColumnVisibility,
|
|
8865
9393
|
data: query.data?.data ?? [],
|
|
8866
9394
|
tableLabel,
|
|
8867
|
-
}, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
9395
|
+
}, children: jsx(DataTableServerContext.Provider, { value: { url: url ?? '', query }, children: children }) }));
|
|
8868
9396
|
}
|
|
8869
9397
|
|
|
8870
|
-
export { CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|
|
9398
|
+
export { CalendarDisplay, CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, defaultRenderDisplay, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|