@bsol-oss/react-datatable5 12.0.0-beta.95 → 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 +166 -41
- package/dist/index.js +1151 -612
- package/dist/index.mjs +1153 -615
- 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/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/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) => {
|
|
@@ -3581,7 +3817,7 @@ const ErrorAlert = ({ showMessage = true }) => {
|
|
|
3581
3817
|
const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: defaultPagination = {
|
|
3582
3818
|
pageIndex: 0, //initial page index
|
|
3583
3819
|
pageSize: 10, //default page size
|
|
3584
|
-
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter =
|
|
3820
|
+
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = '', density: defaultDensity = 'sm', } = {
|
|
3585
3821
|
sorting: [],
|
|
3586
3822
|
pagination: {
|
|
3587
3823
|
pageIndex: 0, //initial page index
|
|
@@ -3591,9 +3827,9 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3591
3827
|
columnFilters: [],
|
|
3592
3828
|
columnOrder: [],
|
|
3593
3829
|
columnVisibility: {},
|
|
3594
|
-
globalFilter:
|
|
3595
|
-
density:
|
|
3596
|
-
},
|
|
3830
|
+
globalFilter: '',
|
|
3831
|
+
density: 'sm',
|
|
3832
|
+
}, } = {
|
|
3597
3833
|
default: {
|
|
3598
3834
|
sorting: [],
|
|
3599
3835
|
pagination: {
|
|
@@ -3604,8 +3840,8 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3604
3840
|
columnFilters: [],
|
|
3605
3841
|
columnOrder: [],
|
|
3606
3842
|
columnVisibility: {},
|
|
3607
|
-
globalFilter:
|
|
3608
|
-
density:
|
|
3843
|
+
globalFilter: '',
|
|
3844
|
+
density: 'sm',
|
|
3609
3845
|
},
|
|
3610
3846
|
}) => {
|
|
3611
3847
|
const [sorting, setSorting] = useState(defaultSorting);
|
|
@@ -3616,7 +3852,6 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3616
3852
|
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter);
|
|
3617
3853
|
const [density, setDensity] = useState(defaultDensity);
|
|
3618
3854
|
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility);
|
|
3619
|
-
const translate = useTranslation("", { keyPrefix });
|
|
3620
3855
|
return {
|
|
3621
3856
|
sorting,
|
|
3622
3857
|
setSorting,
|
|
@@ -3634,12 +3869,11 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3634
3869
|
setDensity,
|
|
3635
3870
|
columnVisibility,
|
|
3636
3871
|
setColumnVisibility,
|
|
3637
|
-
translate,
|
|
3638
3872
|
};
|
|
3639
3873
|
};
|
|
3640
3874
|
|
|
3641
3875
|
const useDataTableServer = (props) => {
|
|
3642
|
-
const { url, default: defaultProps,
|
|
3876
|
+
const { url, default: defaultProps, placeholderData, queryFn: customQueryFn, } = props;
|
|
3643
3877
|
const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
|
|
3644
3878
|
const [sorting, setSorting] = useState(defaultSorting || []);
|
|
3645
3879
|
const [columnFilters, setColumnFilters] = useState(defaultColumnFilters || []); // can set initial column filter state here
|
|
@@ -3649,8 +3883,8 @@ const useDataTableServer = (props) => {
|
|
|
3649
3883
|
});
|
|
3650
3884
|
const [rowSelection, setRowSelection] = useState(defaultRowSelection || {});
|
|
3651
3885
|
const [columnOrder, setColumnOrder] = useState(defaultColumnOrder || []);
|
|
3652
|
-
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter ||
|
|
3653
|
-
const [density, setDensity] = useState(defaultDensity ||
|
|
3886
|
+
const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter || '');
|
|
3887
|
+
const [density, setDensity] = useState(defaultDensity || 'sm');
|
|
3654
3888
|
const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility || {});
|
|
3655
3889
|
const { pageSize, pageIndex } = pagination;
|
|
3656
3890
|
const params = {
|
|
@@ -3662,7 +3896,7 @@ const useDataTableServer = (props) => {
|
|
|
3662
3896
|
};
|
|
3663
3897
|
const defaultQueryFn = async () => {
|
|
3664
3898
|
if (!url) {
|
|
3665
|
-
throw new Error(
|
|
3899
|
+
throw new Error('url is required');
|
|
3666
3900
|
}
|
|
3667
3901
|
const response = await axios.get(url, {
|
|
3668
3902
|
params,
|
|
@@ -3676,7 +3910,6 @@ const useDataTableServer = (props) => {
|
|
|
3676
3910
|
: defaultQueryFn,
|
|
3677
3911
|
placeholderData,
|
|
3678
3912
|
});
|
|
3679
|
-
const translate = useTranslation("", { keyPrefix });
|
|
3680
3913
|
return {
|
|
3681
3914
|
sorting,
|
|
3682
3915
|
setSorting,
|
|
@@ -3695,7 +3928,6 @@ const useDataTableServer = (props) => {
|
|
|
3695
3928
|
columnVisibility,
|
|
3696
3929
|
setColumnVisibility,
|
|
3697
3930
|
query,
|
|
3698
|
-
translate,
|
|
3699
3931
|
};
|
|
3700
3932
|
};
|
|
3701
3933
|
|
|
@@ -3714,11 +3946,8 @@ const snakeToLabel = (str) => {
|
|
|
3714
3946
|
.join(" "); // Join with space
|
|
3715
3947
|
};
|
|
3716
3948
|
|
|
3717
|
-
const RecordDisplay = ({ object, boxProps,
|
|
3949
|
+
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
3718
3950
|
const getColumn = ({ field }) => {
|
|
3719
|
-
if (translate !== undefined) {
|
|
3720
|
-
return translate.t(`${prefix}${field}`);
|
|
3721
|
-
}
|
|
3722
3951
|
return snakeToLabel(field);
|
|
3723
3952
|
};
|
|
3724
3953
|
if (object === null) {
|
|
@@ -3726,7 +3955,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = '', }) => {
|
|
|
3726
3955
|
}
|
|
3727
3956
|
return (jsx(Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
3728
3957
|
const uniqueKey = `${prefix}${field}-${index}`;
|
|
3729
|
-
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));
|
|
3730
3959
|
}) }));
|
|
3731
3960
|
};
|
|
3732
3961
|
|
|
@@ -3740,15 +3969,12 @@ const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
|
3740
3969
|
throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
|
|
3741
3970
|
}
|
|
3742
3971
|
};
|
|
3743
|
-
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400,
|
|
3972
|
+
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
|
|
3744
3973
|
const { properties } = schema;
|
|
3745
|
-
idListSanityCheck(
|
|
3974
|
+
idListSanityCheck('ignore', ignore, properties);
|
|
3746
3975
|
widthSanityCheck(width, ignore, properties);
|
|
3747
|
-
idListSanityCheck(
|
|
3976
|
+
idListSanityCheck('meta', Object.keys(meta), properties);
|
|
3748
3977
|
const getColumn = ({ column }) => {
|
|
3749
|
-
if (translate !== undefined) {
|
|
3750
|
-
return translate.t(`${column}`);
|
|
3751
|
-
}
|
|
3752
3978
|
return snakeToLabel(column);
|
|
3753
3979
|
};
|
|
3754
3980
|
const keys = Object.keys(properties);
|
|
@@ -3757,15 +3983,15 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
|
|
|
3757
3983
|
return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
|
|
3758
3984
|
});
|
|
3759
3985
|
const columnHelper = createColumnHelper();
|
|
3760
|
-
// @ts-expect-error find type for unknown
|
|
3761
3986
|
const columns = [
|
|
3762
3987
|
...ignored.map((column, index) => {
|
|
3988
|
+
// @ts-expect-error column accessor type issue with generic TData
|
|
3763
3989
|
return columnHelper.accessor(column, {
|
|
3764
3990
|
cell: (props) => {
|
|
3765
3991
|
// @ts-expect-error find type for unknown
|
|
3766
3992
|
const value = props.row.original[column];
|
|
3767
|
-
if (typeof value ===
|
|
3768
|
-
return (jsx(Grid, { overflow:
|
|
3993
|
+
if (typeof value === 'object') {
|
|
3994
|
+
return (jsx(Grid, { overflow: 'auto', children: jsx(RecordDisplay, { object: value }) }));
|
|
3769
3995
|
}
|
|
3770
3996
|
return jsx(TextCell, { children: value });
|
|
3771
3997
|
},
|
|
@@ -3797,6 +4023,11 @@ const SchemaFormContext = createContext({
|
|
|
3797
4023
|
include: [],
|
|
3798
4024
|
onSubmit: async () => { },
|
|
3799
4025
|
rowNumber: 0,
|
|
4026
|
+
/** Default translate fallback - returns key as-is */
|
|
4027
|
+
translate: {
|
|
4028
|
+
t: (key) => key,
|
|
4029
|
+
ready: true,
|
|
4030
|
+
},
|
|
3800
4031
|
requestOptions: {},
|
|
3801
4032
|
timezone: 'Asia/Hong_Kong',
|
|
3802
4033
|
displayConfig: {
|
|
@@ -4029,7 +4260,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4029
4260
|
showSubmitButton: true,
|
|
4030
4261
|
showResetButton: true,
|
|
4031
4262
|
showTitle: true,
|
|
4032
|
-
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, insideDialog = false, }) => {
|
|
4263
|
+
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
4033
4264
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
4034
4265
|
const [isError, setIsError] = useState(false);
|
|
4035
4266
|
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
@@ -4120,6 +4351,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4120
4351
|
enumPickerLabels,
|
|
4121
4352
|
filePickerLabels,
|
|
4122
4353
|
formButtonLabels,
|
|
4354
|
+
timePickerLabels,
|
|
4123
4355
|
ajvResolver: ajvResolver(schema),
|
|
4124
4356
|
insideDialog,
|
|
4125
4357
|
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
@@ -4130,31 +4362,33 @@ function removeIndex(str) {
|
|
|
4130
4362
|
}
|
|
4131
4363
|
|
|
4132
4364
|
/**
|
|
4133
|
-
* Custom hook
|
|
4365
|
+
* Custom hook for form field labels and fallback text.
|
|
4134
4366
|
* Automatically handles colLabel construction and removeIndex logic.
|
|
4367
|
+
* Uses schema.title when available, otherwise falls back to translate function.
|
|
4135
4368
|
*
|
|
4136
4369
|
* @param column - The column name
|
|
4137
4370
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4138
|
-
* @
|
|
4371
|
+
* @param schema - Optional schema object with title property
|
|
4372
|
+
* @returns Object with label helper functions
|
|
4139
4373
|
*
|
|
4140
4374
|
* @example
|
|
4141
4375
|
* ```tsx
|
|
4142
|
-
* const formI18n = useFormI18n(column, prefix);
|
|
4376
|
+
* const formI18n = useFormI18n(column, prefix, schema);
|
|
4143
4377
|
*
|
|
4144
|
-
* // Get field label
|
|
4378
|
+
* // Get field label (prefers schema.title)
|
|
4145
4379
|
* <Field label={formI18n.label()} />
|
|
4146
4380
|
*
|
|
4147
|
-
* // Get error message
|
|
4381
|
+
* // Get required error message
|
|
4148
4382
|
* <Text>{formI18n.required()}</Text>
|
|
4149
4383
|
*
|
|
4150
|
-
* // Get custom
|
|
4384
|
+
* // Get custom text
|
|
4151
4385
|
* <Text>{formI18n.t('add_more')}</Text>
|
|
4152
4386
|
*
|
|
4153
4387
|
* // Access the raw colLabel
|
|
4154
4388
|
* const colLabel = formI18n.colLabel;
|
|
4155
4389
|
* ```
|
|
4156
4390
|
*/
|
|
4157
|
-
const useFormI18n
|
|
4391
|
+
const useFormI18n = (column, prefix = '', schema) => {
|
|
4158
4392
|
const { translate } = useSchemaContext();
|
|
4159
4393
|
const colLabel = `${prefix}${column}`;
|
|
4160
4394
|
return {
|
|
@@ -4163,7 +4397,7 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4163
4397
|
*/
|
|
4164
4398
|
colLabel,
|
|
4165
4399
|
/**
|
|
4166
|
-
* 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
|
|
4167
4401
|
* Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
4168
4402
|
*/
|
|
4169
4403
|
label: (options) => {
|
|
@@ -4173,18 +4407,18 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4173
4407
|
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
4174
4408
|
},
|
|
4175
4409
|
/**
|
|
4176
|
-
* Get the required error message
|
|
4410
|
+
* Get the required error message
|
|
4177
4411
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4178
4412
|
*/
|
|
4179
4413
|
required: (options) => {
|
|
4180
4414
|
return translate.t(removeIndex(`${colLabel}.field_required`), options);
|
|
4181
4415
|
},
|
|
4182
4416
|
/**
|
|
4183
|
-
* Get
|
|
4417
|
+
* Get text for any custom key relative to the field
|
|
4184
4418
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
4185
4419
|
*
|
|
4186
|
-
* @param key - The
|
|
4187
|
-
* @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)
|
|
4188
4422
|
*/
|
|
4189
4423
|
t: (key, options) => {
|
|
4190
4424
|
return translate.t(removeIndex(`${colLabel}.${key}`), options);
|
|
@@ -4202,8 +4436,9 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4202
4436
|
const { type } = items;
|
|
4203
4437
|
const colLabel = `${prefix}${column}`;
|
|
4204
4438
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4205
|
-
const formI18n = useFormI18n
|
|
4439
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4206
4440
|
const { formState: { errors }, setValue, watch, } = useFormContext();
|
|
4441
|
+
const { formButtonLabels } = useSchemaContext();
|
|
4207
4442
|
const fields = (watch(colLabel) ?? []);
|
|
4208
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: {
|
|
4209
4444
|
base: 'colorPalette.200',
|
|
@@ -4229,7 +4464,7 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4229
4464
|
return;
|
|
4230
4465
|
}
|
|
4231
4466
|
setValue(colLabel, [...fields, {}]);
|
|
4232
|
-
}, children:
|
|
4467
|
+
}, children: formButtonLabels?.add ?? 'Add' }) }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
4233
4468
|
};
|
|
4234
4469
|
|
|
4235
4470
|
const Field = React.forwardRef(function Field(props, ref) {
|
|
@@ -4243,7 +4478,7 @@ const BooleanPicker = ({ schema, column, prefix }) => {
|
|
|
4243
4478
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4244
4479
|
const colLabel = `${prefix}${column}`;
|
|
4245
4480
|
const value = watch(colLabel);
|
|
4246
|
-
const formI18n = useFormI18n
|
|
4481
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4247
4482
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4248
4483
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
|
|
4249
4484
|
setValue(colLabel, !value);
|
|
@@ -4264,50 +4499,50 @@ const CustomInput = ({ column, schema, prefix }) => {
|
|
|
4264
4499
|
|
|
4265
4500
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
4266
4501
|
const { labels } = useContext(DatePickerContext);
|
|
4267
|
-
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
4502
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
4268
4503
|
if (calendars.length) {
|
|
4269
|
-
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({
|
|
4270
4505
|
calendars,
|
|
4271
4506
|
offset: 12,
|
|
4272
|
-
}), 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({
|
|
4273
4508
|
calendars,
|
|
4274
4509
|
offset: 12,
|
|
4275
|
-
}), 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) => {
|
|
4276
4511
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
4277
|
-
return (jsx(Text, { textAlign:
|
|
4512
|
+
return (jsx(Text, { textAlign: 'center', children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
4278
4513
|
}), calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
4279
4514
|
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
4280
4515
|
if (!dateObj) {
|
|
4281
4516
|
return jsx(Grid, {}, key);
|
|
4282
4517
|
}
|
|
4283
|
-
const { date, selected, selectable, today } = dateObj;
|
|
4518
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
4284
4519
|
const getDateColor = ({ today, selected, selectable, }) => {
|
|
4285
4520
|
if (!selectable) {
|
|
4286
|
-
return
|
|
4521
|
+
return 'gray';
|
|
4287
4522
|
}
|
|
4288
4523
|
if (selected) {
|
|
4289
|
-
return
|
|
4524
|
+
return 'blue';
|
|
4290
4525
|
}
|
|
4291
4526
|
if (today) {
|
|
4292
|
-
return
|
|
4527
|
+
return 'green';
|
|
4293
4528
|
}
|
|
4294
|
-
return
|
|
4529
|
+
return '';
|
|
4295
4530
|
};
|
|
4296
4531
|
const getVariant = ({ today, selected, selectable, }) => {
|
|
4297
4532
|
if (!selectable) {
|
|
4298
|
-
return
|
|
4533
|
+
return 'surface';
|
|
4299
4534
|
}
|
|
4300
4535
|
if (selected) {
|
|
4301
|
-
return
|
|
4536
|
+
return 'solid';
|
|
4302
4537
|
}
|
|
4303
4538
|
if (today) {
|
|
4304
|
-
return
|
|
4539
|
+
return 'surface';
|
|
4305
4540
|
}
|
|
4306
|
-
return
|
|
4541
|
+
return 'ghost';
|
|
4307
4542
|
};
|
|
4308
4543
|
const color = getDateColor({ today, selected, selectable });
|
|
4309
4544
|
const variant = getVariant({ today, selected, selectable });
|
|
4310
|
-
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));
|
|
4311
4546
|
}))] })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
4312
4547
|
}
|
|
4313
4548
|
return null;
|
|
@@ -4315,50 +4550,55 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
4315
4550
|
const DatePickerContext = createContext({
|
|
4316
4551
|
labels: {
|
|
4317
4552
|
monthNamesShort: [
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4553
|
+
'Jan',
|
|
4554
|
+
'Feb',
|
|
4555
|
+
'Mar',
|
|
4556
|
+
'Apr',
|
|
4557
|
+
'May',
|
|
4558
|
+
'Jun',
|
|
4559
|
+
'Jul',
|
|
4560
|
+
'Aug',
|
|
4561
|
+
'Sep',
|
|
4562
|
+
'Oct',
|
|
4563
|
+
'Nov',
|
|
4564
|
+
'Dec',
|
|
4330
4565
|
],
|
|
4331
|
-
weekdayNamesShort: [
|
|
4332
|
-
backButtonLabel:
|
|
4333
|
-
forwardButtonLabel:
|
|
4566
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4567
|
+
backButtonLabel: 'Back',
|
|
4568
|
+
forwardButtonLabel: 'Next',
|
|
4334
4569
|
},
|
|
4335
4570
|
});
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
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 })) }));
|
|
4362
4602
|
};
|
|
4363
4603
|
|
|
4364
4604
|
dayjs.extend(utc);
|
|
@@ -4366,7 +4606,7 @@ dayjs.extend(timezone);
|
|
|
4366
4606
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
4367
4607
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4368
4608
|
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
4369
|
-
const formI18n = useFormI18n
|
|
4609
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4370
4610
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4371
4611
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4372
4612
|
const colLabel = formI18n.colLabel;
|
|
@@ -4400,74 +4640,30 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4400
4640
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4401
4641
|
const datePickerLabels = {
|
|
4402
4642
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
formI18n.translate.t(`common.month_5`, {
|
|
4416
|
-
defaultValue: 'May',
|
|
4417
|
-
}),
|
|
4418
|
-
formI18n.translate.t(`common.month_6`, {
|
|
4419
|
-
defaultValue: 'June',
|
|
4420
|
-
}),
|
|
4421
|
-
formI18n.translate.t(`common.month_7`, {
|
|
4422
|
-
defaultValue: 'July',
|
|
4423
|
-
}),
|
|
4424
|
-
formI18n.translate.t(`common.month_8`, {
|
|
4425
|
-
defaultValue: 'August',
|
|
4426
|
-
}),
|
|
4427
|
-
formI18n.translate.t(`common.month_9`, {
|
|
4428
|
-
defaultValue: 'September',
|
|
4429
|
-
}),
|
|
4430
|
-
formI18n.translate.t(`common.month_10`, {
|
|
4431
|
-
defaultValue: 'October',
|
|
4432
|
-
}),
|
|
4433
|
-
formI18n.translate.t(`common.month_11`, {
|
|
4434
|
-
defaultValue: 'November',
|
|
4435
|
-
}),
|
|
4436
|
-
formI18n.translate.t(`common.month_12`, {
|
|
4437
|
-
defaultValue: 'December',
|
|
4438
|
-
}),
|
|
4643
|
+
'January',
|
|
4644
|
+
'February',
|
|
4645
|
+
'March',
|
|
4646
|
+
'April',
|
|
4647
|
+
'May',
|
|
4648
|
+
'June',
|
|
4649
|
+
'July',
|
|
4650
|
+
'August',
|
|
4651
|
+
'September',
|
|
4652
|
+
'October',
|
|
4653
|
+
'November',
|
|
4654
|
+
'December',
|
|
4439
4655
|
],
|
|
4440
4656
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
defaultValue: 'Tue',
|
|
4449
|
-
}),
|
|
4450
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
4451
|
-
defaultValue: 'Wed',
|
|
4452
|
-
}),
|
|
4453
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
4454
|
-
defaultValue: 'Thu',
|
|
4455
|
-
}),
|
|
4456
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
4457
|
-
defaultValue: 'Fri',
|
|
4458
|
-
}),
|
|
4459
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
4460
|
-
defaultValue: 'Sat',
|
|
4461
|
-
}),
|
|
4657
|
+
'Sun',
|
|
4658
|
+
'Mon',
|
|
4659
|
+
'Tue',
|
|
4660
|
+
'Wed',
|
|
4661
|
+
'Thu',
|
|
4662
|
+
'Fri',
|
|
4663
|
+
'Sat',
|
|
4462
4664
|
],
|
|
4463
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4464
|
-
|
|
4465
|
-
defaultValue: 'Back',
|
|
4466
|
-
}),
|
|
4467
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4468
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
4469
|
-
defaultValue: 'Forward',
|
|
4470
|
-
}),
|
|
4665
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
4666
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
4471
4667
|
};
|
|
4472
4668
|
const datePickerContent = (jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4473
4669
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
@@ -4484,7 +4680,7 @@ dayjs.extend(timezone);
|
|
|
4484
4680
|
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4485
4681
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4486
4682
|
const { timezone, insideDialog } = useSchemaContext();
|
|
4487
|
-
const formI18n = useFormI18n
|
|
4683
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4488
4684
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4489
4685
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4490
4686
|
const colLabel = formI18n.colLabel;
|
|
@@ -4582,7 +4778,7 @@ const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
|
4582
4778
|
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
4583
4779
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4584
4780
|
const { enumPickerLabels, insideDialog } = useSchemaContext();
|
|
4585
|
-
const formI18n = useFormI18n
|
|
4781
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4586
4782
|
const { required, variant } = schema;
|
|
4587
4783
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4588
4784
|
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
@@ -5129,7 +5325,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
|
|
|
5129
5325
|
}) })) }))] }));
|
|
5130
5326
|
};
|
|
5131
5327
|
|
|
5132
|
-
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, }) {
|
|
5133
5329
|
const [selectedFile, setSelectedFile] = useState(undefined);
|
|
5134
5330
|
const [activeTab, setActiveTab] = useState('browse');
|
|
5135
5331
|
const [uploadingFiles, setUploadingFiles] = useState(new Set());
|
|
@@ -5198,15 +5394,8 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5198
5394
|
const showTabs = enableUpload && !!onUploadFile && !!onFetchFiles;
|
|
5199
5395
|
if (!onFetchFiles && !onUploadFile)
|
|
5200
5396
|
return null;
|
|
5201
|
-
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 ??
|
|
5202
|
-
|
|
5203
|
-
'Browse Library' }), jsx(Tabs.Trigger, { value: "upload", children: labels?.uploadTab ??
|
|
5204
|
-
translate(removeIndex(`${colLabel}.upload_tab`)) ??
|
|
5205
|
-
'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 ??
|
|
5206
|
-
translate(removeIndex(`${colLabel}.fileDropzone`)) ??
|
|
5207
|
-
'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 ??
|
|
5208
|
-
translate(removeIndex(`${colLabel}.uploading`)) ??
|
|
5209
|
-
'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: {
|
|
5210
5399
|
base: 'colorPalette.50',
|
|
5211
5400
|
_dark: 'colorPalette.900/20',
|
|
5212
5401
|
}, border: "1px solid", borderColor: {
|
|
@@ -5215,18 +5404,12 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5215
5404
|
}, colorPalette: "red", borderRadius: "md", p: 3, children: jsxs(Text, { fontSize: "sm", color: {
|
|
5216
5405
|
base: 'colorPalette.600',
|
|
5217
5406
|
_dark: 'colorPalette.300',
|
|
5218
|
-
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ??
|
|
5219
|
-
translate(removeIndex(`${colLabel}.upload_failed`)) ??
|
|
5220
|
-
'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 ??
|
|
5221
|
-
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
5222
|
-
'Cancel' }), jsx(Button$1, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ??
|
|
5223
|
-
translate(removeIndex(`${colLabel}.select`)) ??
|
|
5224
|
-
'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' })] }) })] }) }));
|
|
5225
5408
|
}
|
|
5226
5409
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
5227
5410
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5228
5411
|
const { filePickerLabels } = useSchemaContext();
|
|
5229
|
-
const formI18n = useFormI18n
|
|
5412
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5230
5413
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5231
5414
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5232
5415
|
const isSingleSelect = type === 'string';
|
|
@@ -5302,7 +5485,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5302
5485
|
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
5303
5486
|
const { setValue, formState: { errors }, watch, } = useFormContext();
|
|
5304
5487
|
const { filePickerLabels } = useSchemaContext();
|
|
5305
|
-
const formI18n = useFormI18n
|
|
5488
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5306
5489
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
5307
5490
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5308
5491
|
const isSingleSelect = type === 'string';
|
|
@@ -5398,8 +5581,8 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5398
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 ??
|
|
5399
5582
|
formI18n.t('browse_library') ??
|
|
5400
5583
|
'Browse from Library' }) }), jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5401
|
-
|
|
5402
|
-
'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) => {
|
|
5403
5586
|
const file = fileMap.get(fileId);
|
|
5404
5587
|
const isImage = file
|
|
5405
5588
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5448,17 +5631,16 @@ const defaultRenderDisplay = (item) => {
|
|
|
5448
5631
|
return JSON.stringify(item);
|
|
5449
5632
|
};
|
|
5450
5633
|
|
|
5451
|
-
const
|
|
5634
|
+
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5452
5635
|
const { watch, getValues, formState: { errors }, setValue, } = useFormContext();
|
|
5453
5636
|
const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5454
|
-
const
|
|
5455
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
5456
|
-
const isRequired = required?.some((columnId) => columnId === column);
|
|
5637
|
+
const { renderDisplay, foreign_key } = schema;
|
|
5457
5638
|
const { table, column: column_ref, customQueryFn, } = foreign_key;
|
|
5458
5639
|
const [searchText, setSearchText] = useState('');
|
|
5459
5640
|
const [debouncedSearchText, setDebouncedSearchText] = useState('');
|
|
5460
5641
|
const [limit] = useState(50); // Increased limit for combobox
|
|
5461
|
-
|
|
5642
|
+
// Get colLabel from schema context (we'll compute it here)
|
|
5643
|
+
const colLabel = `${prefix}${column}`;
|
|
5462
5644
|
const watchedValue = watch(colLabel);
|
|
5463
5645
|
const watchId = !isMultiple ? watchedValue : undefined;
|
|
5464
5646
|
const watchIds = isMultiple
|
|
@@ -5657,20 +5839,6 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5657
5839
|
itemToValue: (item) => item.value,
|
|
5658
5840
|
filter: contains,
|
|
5659
5841
|
});
|
|
5660
|
-
// Handle input value change (search)
|
|
5661
|
-
const handleInputValueChange = (details) => {
|
|
5662
|
-
setSearchText(details.inputValue);
|
|
5663
|
-
// Filter will be applied after data is fetched
|
|
5664
|
-
};
|
|
5665
|
-
// Handle value change
|
|
5666
|
-
const handleValueChange = (details) => {
|
|
5667
|
-
if (isMultiple) {
|
|
5668
|
-
setValue(colLabel, details.value);
|
|
5669
|
-
}
|
|
5670
|
-
else {
|
|
5671
|
-
setValue(colLabel, details.value[0] || '');
|
|
5672
|
-
}
|
|
5673
|
-
};
|
|
5674
5842
|
// Track previous comboboxItems to avoid unnecessary updates
|
|
5675
5843
|
const prevComboboxItemsRef = useRef('');
|
|
5676
5844
|
const prevSearchTextRef = useRef('');
|
|
@@ -5700,8 +5868,106 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5700
5868
|
// comboboxItems and searchText are the only dependencies we care about
|
|
5701
5869
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5702
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;
|
|
5703
5916
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5704
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [
|
|
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;
|
|
5969
|
+
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
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) => {
|
|
5705
5971
|
const item = idMap[id];
|
|
5706
5972
|
// Show loading skeleton while fetching initial values
|
|
5707
5973
|
if (item === undefined &&
|
|
@@ -5711,34 +5977,28 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5711
5977
|
}
|
|
5712
5978
|
// Only show "not found" if we're not loading and item is still missing
|
|
5713
5979
|
if (item === undefined) {
|
|
5714
|
-
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ??
|
|
5980
|
+
return (jsx(Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
5715
5981
|
}
|
|
5716
5982
|
return (jsx(Tag, { closable: true, onClick: () => {
|
|
5717
5983
|
const newValue = currentValue.filter((itemId) => itemId !== id);
|
|
5718
5984
|
setValue(colLabel, newValue);
|
|
5719
|
-
}, children:
|
|
5720
|
-
|
|
5721
|
-
: defaultRenderDisplay(item) }, id));
|
|
5722
|
-
}) })), 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
|
|
5723
5987
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5724
|
-
: undefined, children: [jsxs(Combobox.Control, { children: [jsx(Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ??
|
|
5725
|
-
setValue(colLabel, '');
|
|
5726
|
-
} })), 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 ? (
|
|
5727
5989
|
// Show skeleton items to prevent UI shift
|
|
5728
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
|
|
5729
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5730
|
-
formI18n.t('empty_search_result')
|
|
5991
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5731
5992
|
: idPickerLabels?.initialResults ??
|
|
5732
|
-
|
|
5733
|
-
?
|
|
5734
|
-
: 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 ? (
|
|
5735
5996
|
// Show skeleton items to prevent UI shift
|
|
5736
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
|
|
5737
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5738
|
-
formI18n.t('empty_search_result')
|
|
5998
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5739
5999
|
: idPickerLabels?.initialResults ??
|
|
5740
|
-
|
|
5741
|
-
?
|
|
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)
|
|
5742
6002
|
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5743
6003
|
};
|
|
5744
6004
|
|
|
@@ -5812,7 +6072,7 @@ const NumberInputField = ({ schema, column, prefix, }) => {
|
|
|
5812
6072
|
const colLabel = `${prefix}${column}`;
|
|
5813
6073
|
const value = watch(`${colLabel}`);
|
|
5814
6074
|
const fieldError = getFieldError(errors, colLabel);
|
|
5815
|
-
const formI18n = useFormI18n
|
|
6075
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5816
6076
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn, gridRow, errorText: fieldError
|
|
5817
6077
|
? fieldError.includes('required')
|
|
5818
6078
|
? formI18n.required()
|
|
@@ -5830,7 +6090,7 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5830
6090
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
5831
6091
|
const colLabel = `${prefix}${column}`;
|
|
5832
6092
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5833
|
-
const formI18n = useFormI18n
|
|
6093
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5834
6094
|
const { formState: { errors }, } = useFormContext();
|
|
5835
6095
|
if (properties === undefined) {
|
|
5836
6096
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -5850,14 +6110,14 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5850
6110
|
|
|
5851
6111
|
const RecordInput = ({ column, schema, prefix }) => {
|
|
5852
6112
|
const { formState: { errors }, setValue, getValues, } = useFormContext();
|
|
5853
|
-
const {
|
|
6113
|
+
const { formButtonLabels } = useSchemaContext();
|
|
5854
6114
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5855
6115
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5856
6116
|
const entries = Object.entries(getValues(column) ?? {});
|
|
5857
6117
|
const [showNewEntries, setShowNewEntries] = useState(false);
|
|
5858
6118
|
const [newKey, setNewKey] = useState();
|
|
5859
6119
|
const [newValue, setNewValue] = useState();
|
|
5860
|
-
const formI18n = useFormI18n
|
|
6120
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5861
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]) => {
|
|
5862
6122
|
return (jsxs(Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
|
|
5863
6123
|
const filtered = entries.filter(([target]) => {
|
|
@@ -5894,11 +6154,11 @@ const RecordInput = ({ column, schema, prefix }) => {
|
|
|
5894
6154
|
setShowNewEntries(false);
|
|
5895
6155
|
setNewKey(undefined);
|
|
5896
6156
|
setNewValue(undefined);
|
|
5897
|
-
}, children:
|
|
6157
|
+
}, children: formButtonLabels?.save ?? 'Save' })] })] }) }), jsx(Button, { onClick: () => {
|
|
5898
6158
|
setShowNewEntries(true);
|
|
5899
6159
|
setNewKey(undefined);
|
|
5900
6160
|
setNewValue(undefined);
|
|
5901
|
-
}, children:
|
|
6161
|
+
}, children: formButtonLabels?.addNew ?? 'Add New' })] }));
|
|
5902
6162
|
};
|
|
5903
6163
|
|
|
5904
6164
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
@@ -5907,7 +6167,7 @@ const StringInputField = ({ column, schema, prefix, }) => {
|
|
|
5907
6167
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5908
6168
|
const colLabel = `${prefix}${column}`;
|
|
5909
6169
|
const fieldError = getFieldError(errors, colLabel);
|
|
5910
|
-
const formI18n = useFormI18n
|
|
6170
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5911
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" }) }) }));
|
|
5912
6172
|
};
|
|
5913
6173
|
|
|
@@ -6099,7 +6359,7 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6099
6359
|
const form = useFormContext();
|
|
6100
6360
|
const { setValue, watch } = form;
|
|
6101
6361
|
const fieldError = getFieldError(errors, colLabel);
|
|
6102
|
-
const formI18n = useFormI18n
|
|
6362
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6103
6363
|
const watchValue = watch(colLabel);
|
|
6104
6364
|
return (jsx(Fragment, { children: jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
|
|
6105
6365
|
? fieldError.includes('required')
|
|
@@ -6110,18 +6370,13 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6110
6370
|
|
|
6111
6371
|
dayjs.extend(utc);
|
|
6112
6372
|
dayjs.extend(timezone);
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
},
|
|
6119
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6120
|
-
onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, portalled = true, }) {
|
|
6121
|
-
// 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)
|
|
6122
6378
|
const timeOptions = useMemo(() => {
|
|
6123
6379
|
const options = [];
|
|
6124
|
-
const meridiemOptions = ['am', 'pm'];
|
|
6125
6380
|
// Get start time for comparison if provided
|
|
6126
6381
|
let startDateTime = null;
|
|
6127
6382
|
let shouldFilterByDate = false;
|
|
@@ -6136,14 +6391,16 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6136
6391
|
selectedDateObj.format('YYYY-MM-DD');
|
|
6137
6392
|
}
|
|
6138
6393
|
}
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
//
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
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;
|
|
6147
6404
|
// Filter out times that would result in negative duration (only when dates are the same)
|
|
6148
6405
|
if (startDateTime && selectedDate && shouldFilterByDate) {
|
|
6149
6406
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
@@ -6186,20 +6443,23 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6186
6443
|
}
|
|
6187
6444
|
}
|
|
6188
6445
|
}
|
|
6446
|
+
const hourDisplay = h.toString();
|
|
6447
|
+
const minuteDisplay = m.toString().padStart(2, '0');
|
|
6448
|
+
const timeDisplay = `${hourDisplay}:${minuteDisplay} ${mer.toUpperCase()}`;
|
|
6189
6449
|
options.push({
|
|
6190
|
-
label:
|
|
6191
|
-
value: `${h}:${m
|
|
6450
|
+
label: timeDisplay,
|
|
6451
|
+
value: `${h}:${m}:${mer}`,
|
|
6192
6452
|
hour: h,
|
|
6193
6453
|
minute: m,
|
|
6194
6454
|
meridiem: mer,
|
|
6195
|
-
searchText:
|
|
6455
|
+
searchText: timeDisplay, // Use base time without duration for searching
|
|
6196
6456
|
durationText,
|
|
6197
6457
|
});
|
|
6198
6458
|
}
|
|
6199
6459
|
}
|
|
6200
6460
|
}
|
|
6201
6461
|
return options;
|
|
6202
|
-
}, [
|
|
6462
|
+
}, [startTime, selectedDate, timezone]);
|
|
6203
6463
|
const { contains } = useFilter({ sensitivity: 'base' });
|
|
6204
6464
|
const { collection, filter } = useListCollection({
|
|
6205
6465
|
initialItems: timeOptions,
|
|
@@ -6212,7 +6472,7 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6212
6472
|
if (hour === null || minute === null || meridiem === null) {
|
|
6213
6473
|
return '';
|
|
6214
6474
|
}
|
|
6215
|
-
return `${hour}:${minute
|
|
6475
|
+
return `${hour}:${minute}:${meridiem}`;
|
|
6216
6476
|
}, [hour, minute, meridiem]);
|
|
6217
6477
|
// Calculate duration difference
|
|
6218
6478
|
const durationDiff = useMemo(() => {
|
|
@@ -6223,15 +6483,14 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6223
6483
|
meridiem === null) {
|
|
6224
6484
|
return null;
|
|
6225
6485
|
}
|
|
6226
|
-
const hour24 = meridiem === 'am'
|
|
6227
|
-
? hour === 12
|
|
6228
|
-
? 0
|
|
6229
|
-
: hour
|
|
6230
|
-
: hour === 12
|
|
6231
|
-
? 12
|
|
6232
|
-
: hour + 12;
|
|
6233
6486
|
const startDateObj = dayjs(startTime).tz(timezone);
|
|
6234
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;
|
|
6235
6494
|
const currentDateTime = selectedDateObj
|
|
6236
6495
|
.hour(hour24)
|
|
6237
6496
|
.minute(minute)
|
|
@@ -6296,83 +6555,54 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6296
6555
|
if (!trimmedValue) {
|
|
6297
6556
|
return;
|
|
6298
6557
|
}
|
|
6299
|
-
//
|
|
6300
|
-
const
|
|
6301
|
-
|
|
6302
|
-
// Matches: 1-2 digits hour, optional colon, 2 digits minute, am/pm
|
|
6303
|
-
const pattern12HourWithMeridiem = /^(\d{1,2}):?(\d{2})(am|pm)$/;
|
|
6304
|
-
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);
|
|
6305
6561
|
if (match12Hour) {
|
|
6306
6562
|
const parsedHour = parseInt(match12Hour[1], 10);
|
|
6307
6563
|
const parsedMinute = parseInt(match12Hour[2], 10);
|
|
6308
|
-
const parsedMeridiem = match12Hour[3];
|
|
6309
|
-
// Validate
|
|
6310
|
-
if (parsedHour
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
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
|
+
});
|
|
6319
6578
|
return;
|
|
6320
6579
|
}
|
|
6321
|
-
setHour(parsedHour);
|
|
6322
|
-
setMinute(parsedMinute);
|
|
6323
|
-
setMeridiem(parsedMeridiem);
|
|
6324
|
-
onChange({
|
|
6325
|
-
hour: parsedHour,
|
|
6326
|
-
minute: parsedMinute,
|
|
6327
|
-
meridiem: parsedMeridiem,
|
|
6328
|
-
});
|
|
6329
|
-
return;
|
|
6330
6580
|
}
|
|
6331
|
-
//
|
|
6332
|
-
|
|
6333
|
-
const
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
//
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
}
|
|
6356
|
-
else if (parsedHour === 12) {
|
|
6357
|
-
parsedHour = 12;
|
|
6358
|
-
parsedMeridiem = 'pm';
|
|
6359
|
-
}
|
|
6360
|
-
else if (parsedHour > 12) {
|
|
6361
|
-
parsedHour = parsedHour - 12;
|
|
6362
|
-
parsedMeridiem = 'pm';
|
|
6363
|
-
}
|
|
6364
|
-
else {
|
|
6365
|
-
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
|
+
}
|
|
6366
6605
|
}
|
|
6367
|
-
setHour(parsedHour);
|
|
6368
|
-
setMinute(parsedMinute);
|
|
6369
|
-
setMeridiem(parsedMeridiem);
|
|
6370
|
-
onChange({
|
|
6371
|
-
hour: parsedHour,
|
|
6372
|
-
minute: parsedMinute,
|
|
6373
|
-
meridiem: parsedMeridiem,
|
|
6374
|
-
});
|
|
6375
|
-
return;
|
|
6376
6606
|
}
|
|
6377
6607
|
// Parse failed, select first result
|
|
6378
6608
|
selectFirstResult();
|
|
@@ -6419,17 +6649,17 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6419
6649
|
e.currentTarget?.blur();
|
|
6420
6650
|
}
|
|
6421
6651
|
};
|
|
6422
|
-
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:
|
|
6423
|
-
}
|
|
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
|
+
};
|
|
6424
6654
|
|
|
6425
6655
|
dayjs.extend(timezone);
|
|
6426
6656
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
6427
6657
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
6428
|
-
const { timezone, insideDialog } = useSchemaContext();
|
|
6658
|
+
const { timezone, insideDialog, timePickerLabels } = useSchemaContext();
|
|
6429
6659
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
|
|
6430
6660
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6431
6661
|
const colLabel = `${prefix}${column}`;
|
|
6432
|
-
const formI18n = useFormI18n
|
|
6662
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6433
6663
|
const [open, setOpen] = useState(false);
|
|
6434
6664
|
const value = watch(colLabel);
|
|
6435
6665
|
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
@@ -6487,7 +6717,7 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
6487
6717
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6488
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: () => {
|
|
6489
6719
|
setOpen(true);
|
|
6490
|
-
}, 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 }) }) }) })) : (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 }) }) }) }) }))] }) }));
|
|
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 }) }) }) }) }))] }) }));
|
|
6491
6721
|
};
|
|
6492
6722
|
|
|
6493
6723
|
dayjs.extend(utc);
|
|
@@ -6621,7 +6851,10 @@ dayjs.extend(utc);
|
|
|
6621
6851
|
dayjs.extend(timezone);
|
|
6622
6852
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
|
|
6623
6853
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6624
|
-
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
|
+
}, }) {
|
|
6625
6858
|
// Generate time options (every 15 minutes, seconds always 0)
|
|
6626
6859
|
const timeOptions = useMemo(() => {
|
|
6627
6860
|
const options = [];
|
|
@@ -6884,7 +7117,7 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6884
7117
|
e.currentTarget?.blur();
|
|
6885
7118
|
}
|
|
6886
7119
|
};
|
|
6887
|
-
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, {}) }) })] }) }));
|
|
6888
7121
|
}
|
|
6889
7122
|
|
|
6890
7123
|
dayjs.extend(utc);
|
|
@@ -6907,7 +7140,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6907
7140
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
6908
7141
|
backButtonLabel: 'Back',
|
|
6909
7142
|
forwardButtonLabel: 'Next',
|
|
6910
|
-
}, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
7143
|
+
}, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
6911
7144
|
console.log('[DateTimePicker] Component initialized with props:', {
|
|
6912
7145
|
value,
|
|
6913
7146
|
format,
|
|
@@ -7353,7 +7586,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7353
7586
|
const dateObj = dayjs.tz(selectedDate, timezone);
|
|
7354
7587
|
return dateObj.isValid() ? dateObj.format('Z') : null;
|
|
7355
7588
|
}, [selectedDate, timezone]);
|
|
7356
|
-
return (jsxs(Flex, { direction: "column", gap: 4,
|
|
7589
|
+
return (jsxs(Flex, { direction: "column", gap: 4, children: [jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
|
|
7357
7590
|
if (date) {
|
|
7358
7591
|
handleDateChange(date);
|
|
7359
7592
|
}
|
|
@@ -7361,15 +7594,15 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7361
7594
|
setSelectedDate('');
|
|
7362
7595
|
onChange?.(undefined);
|
|
7363
7596
|
}
|
|
7364
|
-
}, 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 })] }))] }));
|
|
7365
7598
|
}
|
|
7366
7599
|
|
|
7367
7600
|
dayjs.extend(utc);
|
|
7368
7601
|
dayjs.extend(timezone);
|
|
7369
7602
|
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
7370
7603
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
7371
|
-
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
7372
|
-
const formI18n = useFormI18n
|
|
7604
|
+
const { timezone, dateTimePickerLabels, timePickerLabels, insideDialog } = useSchemaContext();
|
|
7605
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7373
7606
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
|
|
7374
7607
|
// with timezone
|
|
7375
7608
|
dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
|
|
@@ -7382,74 +7615,30 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7382
7615
|
: '';
|
|
7383
7616
|
const dateTimePickerLabelsConfig = {
|
|
7384
7617
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
formI18n.translate.t(`common.month_5`, {
|
|
7398
|
-
defaultValue: 'May',
|
|
7399
|
-
}),
|
|
7400
|
-
formI18n.translate.t(`common.month_6`, {
|
|
7401
|
-
defaultValue: 'June',
|
|
7402
|
-
}),
|
|
7403
|
-
formI18n.translate.t(`common.month_7`, {
|
|
7404
|
-
defaultValue: 'July',
|
|
7405
|
-
}),
|
|
7406
|
-
formI18n.translate.t(`common.month_8`, {
|
|
7407
|
-
defaultValue: 'August',
|
|
7408
|
-
}),
|
|
7409
|
-
formI18n.translate.t(`common.month_9`, {
|
|
7410
|
-
defaultValue: 'September',
|
|
7411
|
-
}),
|
|
7412
|
-
formI18n.translate.t(`common.month_10`, {
|
|
7413
|
-
defaultValue: 'October',
|
|
7414
|
-
}),
|
|
7415
|
-
formI18n.translate.t(`common.month_11`, {
|
|
7416
|
-
defaultValue: 'November',
|
|
7417
|
-
}),
|
|
7418
|
-
formI18n.translate.t(`common.month_12`, {
|
|
7419
|
-
defaultValue: 'December',
|
|
7420
|
-
}),
|
|
7618
|
+
'January',
|
|
7619
|
+
'February',
|
|
7620
|
+
'March',
|
|
7621
|
+
'April',
|
|
7622
|
+
'May',
|
|
7623
|
+
'June',
|
|
7624
|
+
'July',
|
|
7625
|
+
'August',
|
|
7626
|
+
'September',
|
|
7627
|
+
'October',
|
|
7628
|
+
'November',
|
|
7629
|
+
'December',
|
|
7421
7630
|
],
|
|
7422
7631
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
defaultValue: 'Tue',
|
|
7431
|
-
}),
|
|
7432
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
7433
|
-
defaultValue: 'Wed',
|
|
7434
|
-
}),
|
|
7435
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
7436
|
-
defaultValue: 'Thu',
|
|
7437
|
-
}),
|
|
7438
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
7439
|
-
defaultValue: 'Fri',
|
|
7440
|
-
}),
|
|
7441
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
7442
|
-
defaultValue: 'Sat',
|
|
7443
|
-
}),
|
|
7632
|
+
'Sun',
|
|
7633
|
+
'Mon',
|
|
7634
|
+
'Tue',
|
|
7635
|
+
'Wed',
|
|
7636
|
+
'Thu',
|
|
7637
|
+
'Fri',
|
|
7638
|
+
'Sat',
|
|
7444
7639
|
],
|
|
7445
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
7446
|
-
|
|
7447
|
-
defaultValue: 'Back',
|
|
7448
|
-
}),
|
|
7449
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
7450
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
7451
|
-
defaultValue: 'Forward',
|
|
7452
|
-
}),
|
|
7640
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
7641
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
7453
7642
|
};
|
|
7454
7643
|
const dateTimePickerContent = (jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
7455
7644
|
if (!date || date === null || date === undefined) {
|
|
@@ -7463,7 +7652,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7463
7652
|
else {
|
|
7464
7653
|
setValue(colLabel, undefined);
|
|
7465
7654
|
}
|
|
7466
|
-
}, timezone: timezone, labels: dateTimePickerLabelsConfig }));
|
|
7655
|
+
}, timezone: timezone, labels: dateTimePickerLabelsConfig, timePickerLabels: timePickerLabels }));
|
|
7467
7656
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7468
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: () => {
|
|
7469
7658
|
setOpen(true);
|
|
@@ -7482,7 +7671,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7482
7671
|
}
|
|
7483
7672
|
if (variant === 'id-picker') {
|
|
7484
7673
|
idPickerSanityCheck(column, foreign_key);
|
|
7485
|
-
return jsx(
|
|
7674
|
+
return jsx(IdPickerSingle, { schema: colSchema, prefix, column });
|
|
7486
7675
|
}
|
|
7487
7676
|
if (format === 'date') {
|
|
7488
7677
|
return jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
@@ -7516,7 +7705,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7516
7705
|
if (type === 'array') {
|
|
7517
7706
|
if (variant === 'id-picker') {
|
|
7518
7707
|
idPickerSanityCheck(column, foreign_key);
|
|
7519
|
-
return
|
|
7708
|
+
return jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
|
|
7520
7709
|
}
|
|
7521
7710
|
if (variant === 'tag-picker') {
|
|
7522
7711
|
return jsx(TagPicker, { schema: colSchema, prefix, column });
|
|
@@ -7568,7 +7757,7 @@ const ArrayViewer = ({ schema, column, prefix }) => {
|
|
|
7568
7757
|
const { gridColumn = 'span 12', gridRow = 'span 1', required, items, } = schema;
|
|
7569
7758
|
const colLabel = `${prefix}${column}`;
|
|
7570
7759
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7571
|
-
const formI18n = useFormI18n
|
|
7760
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7572
7761
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7573
7762
|
const values = watch(colLabel) ?? [];
|
|
7574
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: {
|
|
@@ -7586,7 +7775,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
7586
7775
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7587
7776
|
const colLabel = `${prefix}${column}`;
|
|
7588
7777
|
const value = watch(colLabel);
|
|
7589
|
-
const formI18n = useFormI18n
|
|
7778
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7590
7779
|
return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7591
7780
|
gridRow, children: [jsx(Text, { children: value ? formI18n.t('true') : formI18n.t('false') }), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
7592
7781
|
};
|
|
@@ -7610,7 +7799,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7610
7799
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7611
7800
|
const colLabel = `${prefix}${column}`;
|
|
7612
7801
|
const selectedDate = watch(colLabel);
|
|
7613
|
-
const formI18n = useFormI18n
|
|
7802
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7614
7803
|
const displayDate = dayjs(selectedDate)
|
|
7615
7804
|
.tz(timezone)
|
|
7616
7805
|
.format(displayDateFormat);
|
|
@@ -7620,7 +7809,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7620
7809
|
|
|
7621
7810
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
7622
7811
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7623
|
-
const formI18n = useFormI18n
|
|
7812
|
+
const formI18n = useFormI18n(column, prefix);
|
|
7624
7813
|
const { required } = schema;
|
|
7625
7814
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7626
7815
|
const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
|
|
@@ -7644,7 +7833,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7644
7833
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
|
|
7645
7834
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7646
7835
|
const currentFiles = (watch(column) ?? []);
|
|
7647
|
-
const formI18n = useFormI18n
|
|
7836
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7648
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) => {
|
|
7649
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));
|
|
7650
7839
|
}) }) }));
|
|
@@ -7652,7 +7841,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7652
7841
|
|
|
7653
7842
|
const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
7654
7843
|
const { watch, formState: { errors }, } = useFormContext();
|
|
7655
|
-
const { idMap,
|
|
7844
|
+
const { idMap, idPickerLabels, formButtonLabels } = useSchemaContext();
|
|
7656
7845
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
7657
7846
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7658
7847
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
@@ -7676,12 +7865,12 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
7676
7865
|
gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: 'wrap', gap: 1, children: watchIds.map((id) => {
|
|
7677
7866
|
const item = idMap[id];
|
|
7678
7867
|
if (item === undefined) {
|
|
7679
|
-
return (jsx(Text, { children:
|
|
7868
|
+
return (jsx(Text, { children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
7680
7869
|
}
|
|
7681
7870
|
return (jsx(Tag, { closable: true, children: renderDisplay
|
|
7682
7871
|
? renderDisplay(item)
|
|
7683
7872
|
: defaultRenderDisplay(item) }, id));
|
|
7684
|
-
}) })), !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() }))] }));
|
|
7685
7874
|
};
|
|
7686
7875
|
|
|
7687
7876
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
@@ -7690,7 +7879,7 @@ const NumberViewer = ({ schema, column, prefix, }) => {
|
|
|
7690
7879
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7691
7880
|
const colLabel = `${prefix}${column}`;
|
|
7692
7881
|
const value = watch(colLabel);
|
|
7693
|
-
const formI18n = useFormI18n
|
|
7882
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7694
7883
|
// Format the value for display if formatOptions are provided
|
|
7695
7884
|
const formatValue = (val) => {
|
|
7696
7885
|
if (val === undefined || val === null || val === '')
|
|
@@ -7716,7 +7905,7 @@ const ObjectViewer = ({ schema, column, prefix }) => {
|
|
|
7716
7905
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
7717
7906
|
const colLabel = `${prefix}${column}`;
|
|
7718
7907
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7719
|
-
const formI18n = useFormI18n
|
|
7908
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7720
7909
|
const { formState: { errors }, } = useFormContext();
|
|
7721
7910
|
if (properties === undefined) {
|
|
7722
7911
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -7738,7 +7927,7 @@ const RecordViewer = ({ column, schema, prefix }) => {
|
|
|
7738
7927
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
7739
7928
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7740
7929
|
const entries = Object.entries(getValues(column) ?? {});
|
|
7741
|
-
const formI18n = useFormI18n
|
|
7930
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7742
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]) => {
|
|
7743
7932
|
return (jsxs(Grid, { templateColumns: '1fr 1fr', gap: 2, children: [jsxs(Text, { fontWeight: "medium", children: [key, ":"] }), jsx(Text, { children: String(value ?? '') })] }, key));
|
|
7744
7933
|
}) })), errors[`${column}`] && (jsx(Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
@@ -7750,7 +7939,7 @@ const StringViewer = ({ column, schema, prefix, }) => {
|
|
|
7750
7939
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7751
7940
|
const colLabel = `${prefix}${column}`;
|
|
7752
7941
|
const value = watch(colLabel);
|
|
7753
|
-
const formI18n = useFormI18n
|
|
7942
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7754
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() }))] }) }));
|
|
7755
7944
|
};
|
|
7756
7945
|
|
|
@@ -7845,7 +8034,7 @@ const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
|
7845
8034
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7846
8035
|
const colLabel = `${prefix}${column}`;
|
|
7847
8036
|
const value = watch(colLabel);
|
|
7848
|
-
const formI18n = useFormI18n
|
|
8037
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7849
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() }))] }) }));
|
|
7850
8039
|
};
|
|
7851
8040
|
|
|
@@ -7856,7 +8045,7 @@ const TimeViewer = ({ column, schema, prefix }) => {
|
|
|
7856
8045
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7857
8046
|
const colLabel = `${prefix}${column}`;
|
|
7858
8047
|
const selectedDate = watch(colLabel);
|
|
7859
|
-
const formI18n = useFormI18n
|
|
8048
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7860
8049
|
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
7861
8050
|
.tz(timezone)
|
|
7862
8051
|
.isValid()
|
|
@@ -7873,7 +8062,7 @@ const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
|
7873
8062
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7874
8063
|
const colLabel = `${prefix}${column}`;
|
|
7875
8064
|
const selectedDate = watch(colLabel);
|
|
7876
|
-
const formI18n = useFormI18n
|
|
8065
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7877
8066
|
const displayDate = dayjs(selectedDate)
|
|
7878
8067
|
.tz(timezone)
|
|
7879
8068
|
.format(displayDateFormat);
|
|
@@ -7967,7 +8156,7 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
7967
8156
|
};
|
|
7968
8157
|
|
|
7969
8158
|
const SubmitButton = () => {
|
|
7970
|
-
const {
|
|
8159
|
+
const { setValidatedData, setIsError, setIsConfirming, requireConfirmation, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
7971
8160
|
const methods = useFormContext();
|
|
7972
8161
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7973
8162
|
const onValid = (data) => {
|
|
@@ -7996,11 +8185,11 @@ const SubmitButton = () => {
|
|
|
7996
8185
|
};
|
|
7997
8186
|
return (jsx(Button$1, { onClick: () => {
|
|
7998
8187
|
methods.handleSubmit(onValid)();
|
|
7999
|
-
}, formNoValidate: true, children: formButtonLabels?.submit ??
|
|
8188
|
+
}, formNoValidate: true, children: formButtonLabels?.submit ?? 'Submit' }));
|
|
8000
8189
|
};
|
|
8001
8190
|
|
|
8002
8191
|
const FormBody = () => {
|
|
8003
|
-
const { schema, order, ignore, include,
|
|
8192
|
+
const { schema, order, ignore, include, isError, isSubmiting, isConfirming, setIsConfirming, validatedData, error, customErrorRenderer, displayConfig, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
8004
8193
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
8005
8194
|
const methods = useFormContext();
|
|
8006
8195
|
const { properties } = schema;
|
|
@@ -8017,21 +8206,6 @@ const FormBody = () => {
|
|
|
8017
8206
|
ignore,
|
|
8018
8207
|
include,
|
|
8019
8208
|
});
|
|
8020
|
-
if (isSuccess) {
|
|
8021
|
-
const resetHandler = async () => {
|
|
8022
|
-
setIsError(false);
|
|
8023
|
-
setIsSubmiting(false);
|
|
8024
|
-
setIsSuccess(false);
|
|
8025
|
-
setIsConfirming(false);
|
|
8026
|
-
setValidatedData(undefined);
|
|
8027
|
-
const data = await getUpdatedData();
|
|
8028
|
-
methods.reset(data);
|
|
8029
|
-
};
|
|
8030
|
-
if (customSuccessRenderer) {
|
|
8031
|
-
return customSuccessRenderer(resetHandler);
|
|
8032
|
-
}
|
|
8033
|
-
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') }) })] }));
|
|
8034
|
-
}
|
|
8035
8209
|
if (isConfirming) {
|
|
8036
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) => {
|
|
8037
8211
|
return (jsx(ColumnViewer
|
|
@@ -8041,9 +8215,9 @@ const FormBody = () => {
|
|
|
8041
8215
|
properties: properties, prefix: ``, column }, `form-viewer-${column}`));
|
|
8042
8216
|
}) }), jsxs(Flex, { justifyContent: 'end', gap: '2', children: [jsx(Button$1, { onClick: () => {
|
|
8043
8217
|
setIsConfirming(false);
|
|
8044
|
-
}, variant: 'subtle', children: formButtonLabels?.cancel ??
|
|
8218
|
+
}, variant: 'subtle', children: formButtonLabels?.cancel ?? 'Cancel' }), jsx(Button$1, { onClick: () => {
|
|
8045
8219
|
onFormSubmit(validatedData);
|
|
8046
|
-
}, 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)] }));
|
|
8047
8221
|
}
|
|
8048
8222
|
return (jsxs(Flex, { flexFlow: 'column', gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
|
|
8049
8223
|
return (jsx(ColumnRenderer
|
|
@@ -8053,12 +8227,12 @@ const FormBody = () => {
|
|
|
8053
8227
|
properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
|
|
8054
8228
|
}) }), jsxs(Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
|
|
8055
8229
|
methods.reset();
|
|
8056
|
-
}, variant: 'subtle', children: formButtonLabels?.reset ??
|
|
8230
|
+
}, variant: 'subtle', children: formButtonLabels?.reset ?? 'Reset' })), showSubmitButton && jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8057
8231
|
};
|
|
8058
8232
|
|
|
8059
8233
|
const FormTitle = () => {
|
|
8060
|
-
const {
|
|
8061
|
-
return jsx(Heading, { children:
|
|
8234
|
+
const { schema } = useSchemaContext();
|
|
8235
|
+
return jsx(Heading, { children: schema.title ?? 'Form' });
|
|
8062
8236
|
};
|
|
8063
8237
|
|
|
8064
8238
|
const DefaultForm = ({ formConfig, }) => {
|
|
@@ -8066,7 +8240,9 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
8066
8240
|
return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
|
|
8067
8241
|
};
|
|
8068
8242
|
|
|
8069
|
-
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, }) => {
|
|
8070
8246
|
const form = useForm$1({
|
|
8071
8247
|
values: preLoadedValues,
|
|
8072
8248
|
resolver: schema ? ajvResolver(schema) : undefined,
|
|
@@ -8074,12 +8250,16 @@ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
|
|
|
8074
8250
|
reValidateMode: 'onBlur',
|
|
8075
8251
|
});
|
|
8076
8252
|
const [idMap, setIdMap] = useState({});
|
|
8077
|
-
|
|
8253
|
+
// Fallback translate object - returns key as-is (no i18n required)
|
|
8254
|
+
const translate = {
|
|
8255
|
+
t: (key) => key,
|
|
8256
|
+
ready: true,
|
|
8257
|
+
};
|
|
8078
8258
|
return {
|
|
8079
8259
|
form,
|
|
8080
8260
|
idMap,
|
|
8081
8261
|
setIdMap,
|
|
8082
|
-
translate,
|
|
8262
|
+
translate, // Components prefer label objects over translate
|
|
8083
8263
|
};
|
|
8084
8264
|
};
|
|
8085
8265
|
|
|
@@ -8407,6 +8587,21 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
|
8407
8587
|
})] }));
|
|
8408
8588
|
};
|
|
8409
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
|
+
|
|
8410
8605
|
const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
|
|
8411
8606
|
'use no memo';
|
|
8412
8607
|
const { table } = useDataTableContext();
|
|
@@ -8466,7 +8661,68 @@ const TableRowSelectorSkeleton = () => {
|
|
|
8466
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` }) }));
|
|
8467
8662
|
};
|
|
8468
8663
|
|
|
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
|
+
|
|
8469
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 ??
|
|
8723
|
+
tableBodyProps.showSelector ??
|
|
8724
|
+
false, isLoading: isLoading }) }));
|
|
8725
|
+
}
|
|
8470
8726
|
const isGreedy = variant === 'greedy';
|
|
8471
8727
|
const canResize = !isGreedy;
|
|
8472
8728
|
const bodyComponent = isLoading ? (jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: canResize })) : (jsx(TableBody, { ...tableBodyProps, canResize: canResize }));
|
|
@@ -8567,6 +8823,290 @@ const DataDisplay = ({ variant = '' }) => {
|
|
|
8567
8823
|
}) }));
|
|
8568
8824
|
};
|
|
8569
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
|
+
|
|
8570
9110
|
// Reference: https://tanstack.com/table/latest/docs/framework/react/examples/custom-features
|
|
8571
9111
|
// TypeScript setup for our new feature with all of the same type-safety as stock TanStack Table features
|
|
8572
9112
|
// end of TS setup!
|
|
@@ -8667,7 +9207,7 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
|
|
|
8667
9207
|
*
|
|
8668
9208
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8669
9209
|
*/
|
|
8670
|
-
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 = {
|
|
8671
9211
|
view: 'View',
|
|
8672
9212
|
edit: 'Edit',
|
|
8673
9213
|
filterButtonText: 'Filter',
|
|
@@ -8678,7 +9218,7 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8678
9218
|
reloadButtonText: 'Reload',
|
|
8679
9219
|
resetSelection: 'Reset Selection',
|
|
8680
9220
|
resetSorting: 'Reset Sorting',
|
|
8681
|
-
rowCountText: '
|
|
9221
|
+
rowCountText: '',
|
|
8682
9222
|
hasErrorText: 'Has Error',
|
|
8683
9223
|
globalFilterPlaceholder: 'Search',
|
|
8684
9224
|
trueLabel: 'True',
|
|
@@ -8735,7 +9275,6 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8735
9275
|
globalFilter,
|
|
8736
9276
|
setGlobalFilter,
|
|
8737
9277
|
type: 'client',
|
|
8738
|
-
translate,
|
|
8739
9278
|
columns: columns,
|
|
8740
9279
|
sorting,
|
|
8741
9280
|
setSorting,
|
|
@@ -8767,22 +9306,22 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8767
9306
|
*
|
|
8768
9307
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8769
9308
|
*/
|
|
8770
|
-
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,
|
|
8771
|
-
view:
|
|
8772
|
-
edit:
|
|
8773
|
-
filterButtonText:
|
|
8774
|
-
filterTitle:
|
|
8775
|
-
filterReset:
|
|
8776
|
-
filterClose:
|
|
8777
|
-
reloadTooltip:
|
|
8778
|
-
reloadButtonText:
|
|
8779
|
-
resetSelection:
|
|
8780
|
-
resetSorting:
|
|
8781
|
-
rowCountText:
|
|
8782
|
-
hasErrorText:
|
|
8783
|
-
globalFilterPlaceholder:
|
|
8784
|
-
trueLabel:
|
|
8785
|
-
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',
|
|
8786
9325
|
}, }) {
|
|
8787
9326
|
const table = useReactTable({
|
|
8788
9327
|
_features: [DensityFeature],
|
|
@@ -8792,7 +9331,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8792
9331
|
getCoreRowModel: getCoreRowModel(),
|
|
8793
9332
|
manualPagination: true,
|
|
8794
9333
|
manualSorting: true,
|
|
8795
|
-
columnResizeMode:
|
|
9334
|
+
columnResizeMode: 'onChange',
|
|
8796
9335
|
defaultColumn: {
|
|
8797
9336
|
size: 150, //starting column size
|
|
8798
9337
|
minSize: 10, //enforced during column resizing
|
|
@@ -8835,8 +9374,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8835
9374
|
table: table,
|
|
8836
9375
|
globalFilter,
|
|
8837
9376
|
setGlobalFilter,
|
|
8838
|
-
type:
|
|
8839
|
-
translate,
|
|
9377
|
+
type: 'server',
|
|
8840
9378
|
columns: columns,
|
|
8841
9379
|
sorting,
|
|
8842
9380
|
setSorting,
|
|
@@ -8854,7 +9392,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8854
9392
|
setColumnVisibility,
|
|
8855
9393
|
data: query.data?.data ?? [],
|
|
8856
9394
|
tableLabel,
|
|
8857
|
-
}, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
9395
|
+
}, children: jsx(DataTableServerContext.Provider, { value: { url: url ?? '', query }, children: children }) }));
|
|
8858
9396
|
}
|
|
8859
9397
|
|
|
8860
|
-
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 };
|