@bsol-oss/react-datatable5 12.0.0-beta.95 → 13.0.1-beta.1
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 +1220 -652
- package/dist/index.mjs +1222 -655
- 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 +68 -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.js
CHANGED
|
@@ -9,7 +9,6 @@ var md = require('react-icons/md');
|
|
|
9
9
|
var fa6 = require('react-icons/fa6');
|
|
10
10
|
var bi = require('react-icons/bi');
|
|
11
11
|
var cg = require('react-icons/cg');
|
|
12
|
-
var Dayzed = require('@bsol-oss/dayzed-react19');
|
|
13
12
|
var hi2 = require('react-icons/hi2');
|
|
14
13
|
var io = require('react-icons/io');
|
|
15
14
|
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
|
|
@@ -25,7 +24,6 @@ var bs = require('react-icons/bs');
|
|
|
25
24
|
var hi = require('react-icons/hi');
|
|
26
25
|
var reactTable = require('@tanstack/react-table');
|
|
27
26
|
var gr = require('react-icons/gr');
|
|
28
|
-
var reactI18next = require('react-i18next');
|
|
29
27
|
var axios = require('axios');
|
|
30
28
|
var reactHookForm = require('react-hook-form');
|
|
31
29
|
var Ajv = require('ajv');
|
|
@@ -58,36 +56,35 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
|
58
56
|
|
|
59
57
|
const DataTableContext = React.createContext({
|
|
60
58
|
table: {},
|
|
61
|
-
globalFilter:
|
|
59
|
+
globalFilter: '',
|
|
62
60
|
setGlobalFilter: () => { },
|
|
63
|
-
type:
|
|
64
|
-
translate: {},
|
|
61
|
+
type: 'client',
|
|
65
62
|
data: [],
|
|
66
63
|
columns: [],
|
|
67
64
|
columnOrder: [],
|
|
68
65
|
columnFilters: [],
|
|
69
|
-
density:
|
|
66
|
+
density: 'sm',
|
|
70
67
|
sorting: [],
|
|
71
68
|
setPagination: function () {
|
|
72
|
-
throw new Error(
|
|
69
|
+
throw new Error('Function not implemented.');
|
|
73
70
|
},
|
|
74
71
|
setSorting: function () {
|
|
75
|
-
throw new Error(
|
|
72
|
+
throw new Error('Function not implemented.');
|
|
76
73
|
},
|
|
77
74
|
setColumnFilters: function () {
|
|
78
|
-
throw new Error(
|
|
75
|
+
throw new Error('Function not implemented.');
|
|
79
76
|
},
|
|
80
77
|
setRowSelection: function () {
|
|
81
|
-
throw new Error(
|
|
78
|
+
throw new Error('Function not implemented.');
|
|
82
79
|
},
|
|
83
80
|
setColumnOrder: function () {
|
|
84
|
-
throw new Error(
|
|
81
|
+
throw new Error('Function not implemented.');
|
|
85
82
|
},
|
|
86
83
|
setDensity: function () {
|
|
87
|
-
throw new Error(
|
|
84
|
+
throw new Error('Function not implemented.');
|
|
88
85
|
},
|
|
89
86
|
setColumnVisibility: function () {
|
|
90
|
-
throw new Error(
|
|
87
|
+
throw new Error('Function not implemented.');
|
|
91
88
|
},
|
|
92
89
|
pagination: {
|
|
93
90
|
pageIndex: 0,
|
|
@@ -96,21 +93,21 @@ const DataTableContext = React.createContext({
|
|
|
96
93
|
rowSelection: {},
|
|
97
94
|
columnVisibility: {},
|
|
98
95
|
tableLabel: {
|
|
99
|
-
view:
|
|
100
|
-
edit:
|
|
101
|
-
filterButtonText:
|
|
102
|
-
filterTitle:
|
|
103
|
-
filterReset:
|
|
104
|
-
filterClose:
|
|
105
|
-
reloadTooltip:
|
|
106
|
-
reloadButtonText:
|
|
107
|
-
resetSelection:
|
|
108
|
-
resetSorting:
|
|
109
|
-
rowCountText:
|
|
110
|
-
hasErrorText:
|
|
111
|
-
globalFilterPlaceholder:
|
|
112
|
-
trueLabel:
|
|
113
|
-
falseLabel:
|
|
96
|
+
view: 'View',
|
|
97
|
+
edit: 'Edit',
|
|
98
|
+
filterButtonText: 'Filter',
|
|
99
|
+
filterTitle: 'Filter',
|
|
100
|
+
filterReset: 'Reset',
|
|
101
|
+
filterClose: 'Close',
|
|
102
|
+
reloadTooltip: 'Reload',
|
|
103
|
+
reloadButtonText: 'Reload',
|
|
104
|
+
resetSelection: 'Reset Selection',
|
|
105
|
+
resetSorting: 'Reset Sorting',
|
|
106
|
+
rowCountText: '',
|
|
107
|
+
hasErrorText: 'Has Error',
|
|
108
|
+
globalFilterPlaceholder: 'Search',
|
|
109
|
+
trueLabel: 'True',
|
|
110
|
+
falseLabel: 'False',
|
|
114
111
|
},
|
|
115
112
|
});
|
|
116
113
|
|
|
@@ -187,6 +184,166 @@ const Radio = React__namespace.forwardRef(function Radio(props, ref) {
|
|
|
187
184
|
});
|
|
188
185
|
const RadioGroup = react.RadioGroup.Root;
|
|
189
186
|
|
|
187
|
+
// Helper function to check if two dates are the same day
|
|
188
|
+
function isSameDay(date1, date2) {
|
|
189
|
+
return (date1.getFullYear() === date2.getFullYear() &&
|
|
190
|
+
date1.getMonth() === date2.getMonth() &&
|
|
191
|
+
date1.getDate() === date2.getDate());
|
|
192
|
+
}
|
|
193
|
+
// Helper function to check if a date is today
|
|
194
|
+
function isToday(date) {
|
|
195
|
+
const today = new Date();
|
|
196
|
+
return isSameDay(date, today);
|
|
197
|
+
}
|
|
198
|
+
// Helper function to check if a date is selected
|
|
199
|
+
function isSelected(date, selected) {
|
|
200
|
+
if (!selected)
|
|
201
|
+
return false;
|
|
202
|
+
if (Array.isArray(selected)) {
|
|
203
|
+
return selected.some((d) => isSameDay(d, date));
|
|
204
|
+
}
|
|
205
|
+
return isSameDay(selected, date);
|
|
206
|
+
}
|
|
207
|
+
// Helper function to check if a date is selectable
|
|
208
|
+
function isSelectable(date, minDate, maxDate) {
|
|
209
|
+
if (minDate) {
|
|
210
|
+
// Normalize to start of day for comparison
|
|
211
|
+
const minDateStart = new Date(minDate);
|
|
212
|
+
minDateStart.setHours(0, 0, 0, 0);
|
|
213
|
+
const dateStart = new Date(date);
|
|
214
|
+
dateStart.setHours(0, 0, 0, 0);
|
|
215
|
+
if (dateStart < minDateStart)
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
if (maxDate) {
|
|
219
|
+
// Normalize to start of day for comparison
|
|
220
|
+
const maxDateStart = new Date(maxDate);
|
|
221
|
+
maxDateStart.setHours(0, 0, 0, 0);
|
|
222
|
+
const dateStart = new Date(date);
|
|
223
|
+
dateStart.setHours(0, 0, 0, 0);
|
|
224
|
+
if (dateStart > maxDateStart)
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
// Generate calendar weeks for a given month
|
|
230
|
+
function generateCalendarWeeks(year, month, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate) {
|
|
231
|
+
const weeks = [];
|
|
232
|
+
const firstDay = new Date(year, month, 1);
|
|
233
|
+
const lastDay = new Date(year, month + 1, 0);
|
|
234
|
+
// Get the first day of the week for the first day of the month
|
|
235
|
+
let firstDayWeekday = firstDay.getDay();
|
|
236
|
+
// Adjust for firstDayOfWeek
|
|
237
|
+
firstDayWeekday = (firstDayWeekday - firstDayOfWeek + 7) % 7;
|
|
238
|
+
// Start from the first day of the week that contains the first day of the month
|
|
239
|
+
const startDate = new Date(firstDay);
|
|
240
|
+
startDate.setDate(startDate.getDate() - firstDayWeekday);
|
|
241
|
+
let currentDate = new Date(startDate);
|
|
242
|
+
const endDate = new Date(lastDay);
|
|
243
|
+
// Find the last day of the week that contains the last day of the month
|
|
244
|
+
let lastDayWeekday = lastDay.getDay();
|
|
245
|
+
lastDayWeekday = (lastDayWeekday - firstDayOfWeek + 7) % 7;
|
|
246
|
+
endDate.setDate(endDate.getDate() + (6 - lastDayWeekday));
|
|
247
|
+
while (currentDate <= endDate) {
|
|
248
|
+
const week = [];
|
|
249
|
+
for (let i = 0; i < 7; i++) {
|
|
250
|
+
const date = new Date(currentDate);
|
|
251
|
+
const isCurrentMonth = date.getMonth() === month;
|
|
252
|
+
if (!showOutsideDays && !isCurrentMonth) {
|
|
253
|
+
week.push(null);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
const calendarDate = {
|
|
257
|
+
date,
|
|
258
|
+
selected: isSelected(date, selected),
|
|
259
|
+
selectable: isSelectable(date, minDate, maxDate) &&
|
|
260
|
+
(showOutsideDays || isCurrentMonth),
|
|
261
|
+
today: isToday(date),
|
|
262
|
+
isCurrentMonth,
|
|
263
|
+
};
|
|
264
|
+
week.push(calendarDate);
|
|
265
|
+
}
|
|
266
|
+
currentDate.setDate(currentDate.getDate() + 1);
|
|
267
|
+
}
|
|
268
|
+
weeks.push(week);
|
|
269
|
+
}
|
|
270
|
+
return weeks;
|
|
271
|
+
}
|
|
272
|
+
// Generate calendars for the given months
|
|
273
|
+
function generateCalendars(startDate, monthsToDisplay, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate) {
|
|
274
|
+
const calendars = [];
|
|
275
|
+
const currentDate = new Date(startDate);
|
|
276
|
+
for (let i = 0; i < monthsToDisplay; i++) {
|
|
277
|
+
const year = currentDate.getFullYear();
|
|
278
|
+
const month = currentDate.getMonth();
|
|
279
|
+
const weeks = generateCalendarWeeks(year, month, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate);
|
|
280
|
+
calendars.push({
|
|
281
|
+
month,
|
|
282
|
+
year,
|
|
283
|
+
weeks,
|
|
284
|
+
});
|
|
285
|
+
// Move to next month
|
|
286
|
+
currentDate.setMonth(month + 1);
|
|
287
|
+
}
|
|
288
|
+
return calendars;
|
|
289
|
+
}
|
|
290
|
+
function useCalendar({ selected, firstDayOfWeek = 0, showOutsideDays = true, date, minDate, maxDate, monthsToDisplay = 1, onDateSelected, }) {
|
|
291
|
+
const [currentDate, setCurrentDate] = React.useState(() => {
|
|
292
|
+
return date ? new Date(date) : new Date();
|
|
293
|
+
});
|
|
294
|
+
const calendars = React.useMemo(() => {
|
|
295
|
+
return generateCalendars(currentDate, monthsToDisplay, firstDayOfWeek, showOutsideDays, selected, minDate, maxDate);
|
|
296
|
+
}, [
|
|
297
|
+
currentDate,
|
|
298
|
+
monthsToDisplay,
|
|
299
|
+
firstDayOfWeek,
|
|
300
|
+
showOutsideDays,
|
|
301
|
+
selected,
|
|
302
|
+
minDate,
|
|
303
|
+
maxDate,
|
|
304
|
+
]);
|
|
305
|
+
const navigate = React.useCallback((offset) => {
|
|
306
|
+
setCurrentDate((prev) => {
|
|
307
|
+
const newDate = new Date(prev);
|
|
308
|
+
newDate.setMonth(prev.getMonth() + offset);
|
|
309
|
+
return newDate;
|
|
310
|
+
});
|
|
311
|
+
}, []);
|
|
312
|
+
const getBackProps = React.useCallback((props) => {
|
|
313
|
+
return {
|
|
314
|
+
onClick: () => {
|
|
315
|
+
navigate(-(props?.offset || 1));
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}, [navigate]);
|
|
319
|
+
const getForwardProps = React.useCallback((props) => {
|
|
320
|
+
return {
|
|
321
|
+
onClick: () => {
|
|
322
|
+
navigate(props?.offset || 1);
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
}, [navigate]);
|
|
326
|
+
const getDateProps = React.useCallback((props) => {
|
|
327
|
+
return {
|
|
328
|
+
onClick: () => {
|
|
329
|
+
if (props.dateObj.selectable && onDateSelected) {
|
|
330
|
+
onDateSelected({
|
|
331
|
+
date: props.dateObj.date,
|
|
332
|
+
selected: selected || props.dateObj.date,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
onMouseEnter: props.onMouseEnter,
|
|
337
|
+
};
|
|
338
|
+
}, [onDateSelected, selected]);
|
|
339
|
+
return {
|
|
340
|
+
calendars,
|
|
341
|
+
getBackProps,
|
|
342
|
+
getForwardProps,
|
|
343
|
+
getDateProps,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
190
347
|
const RangeDatePickerContext = React.createContext({
|
|
191
348
|
labels: {
|
|
192
349
|
monthNamesFull: [
|
|
@@ -252,7 +409,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
252
409
|
if (!dateObj) {
|
|
253
410
|
return jsxRuntime.jsx(react.Box, {}, key);
|
|
254
411
|
}
|
|
255
|
-
const { date, selected, selectable, today } = dateObj;
|
|
412
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
256
413
|
const getStyle = ({ selected, unavailable, today, isInRange, }) => {
|
|
257
414
|
if (unavailable) {
|
|
258
415
|
return {
|
|
@@ -290,7 +447,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
290
447
|
unavailable: !selectable,
|
|
291
448
|
today,
|
|
292
449
|
isInRange: isInRange(date),
|
|
293
|
-
}), children: selectable ? date.getDate() : 'X' }, key));
|
|
450
|
+
}), opacity: isCurrentMonth ? 1 : 0.4, children: selectable ? date.getDate() : 'X' }, key));
|
|
294
451
|
})) })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
295
452
|
}
|
|
296
453
|
return null;
|
|
@@ -313,10 +470,57 @@ const RangeDatePicker = ({ labels = {
|
|
|
313
470
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
314
471
|
backButtonLabel: 'Back',
|
|
315
472
|
forwardButtonLabel: 'Next',
|
|
316
|
-
}, selected = [], onDateSelected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay,
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
473
|
+
}, selected = [], onDateSelected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
|
|
474
|
+
const handleDateSelected = (obj) => {
|
|
475
|
+
if (onDateSelected) {
|
|
476
|
+
const dateObj = obj.date;
|
|
477
|
+
const currentSelected = Array.isArray(obj.selected)
|
|
478
|
+
? obj.selected
|
|
479
|
+
: [obj.selected];
|
|
480
|
+
// Range selection logic: if one date selected, add second; if two selected, replace with new date
|
|
481
|
+
let newSelected;
|
|
482
|
+
if (currentSelected.length === 0) {
|
|
483
|
+
newSelected = [dateObj];
|
|
484
|
+
}
|
|
485
|
+
else if (currentSelected.length === 1) {
|
|
486
|
+
const firstDate = currentSelected[0];
|
|
487
|
+
if (dateObj < firstDate) {
|
|
488
|
+
newSelected = [dateObj, firstDate];
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
newSelected = [firstDate, dateObj];
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
newSelected = [dateObj];
|
|
496
|
+
}
|
|
497
|
+
// Check if date is selectable
|
|
498
|
+
const selectable = !minDate || dateObj >= minDate;
|
|
499
|
+
if (maxDate) {
|
|
500
|
+
const isSelectable = dateObj <= maxDate;
|
|
501
|
+
if (!isSelectable)
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
onDateSelected({
|
|
505
|
+
selected: newSelected,
|
|
506
|
+
selectable,
|
|
507
|
+
date: dateObj,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
const calendarData = useCalendar({
|
|
512
|
+
onDateSelected: handleDateSelected,
|
|
513
|
+
selected,
|
|
514
|
+
firstDayOfWeek,
|
|
515
|
+
showOutsideDays,
|
|
516
|
+
date,
|
|
517
|
+
minDate,
|
|
518
|
+
maxDate,
|
|
519
|
+
monthsToDisplay,
|
|
520
|
+
});
|
|
521
|
+
return (jsxRuntime.jsx(RangeDatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsxRuntime.jsx(Calendar$1, { ...calendarData,
|
|
522
|
+
firstDayOfWeek,
|
|
523
|
+
selected: selected })) }));
|
|
320
524
|
};
|
|
321
525
|
|
|
322
526
|
const getRangeDates = ({ selectable, date, selectedDates, }) => {
|
|
@@ -552,7 +756,7 @@ const MenuTrigger = react.Menu.Trigger;
|
|
|
552
756
|
|
|
553
757
|
const PageSizeControl = ({ pageSizes = [10, 20, 30, 40, 50], }) => {
|
|
554
758
|
const { table } = useDataTableContext();
|
|
555
|
-
return (jsxRuntime.jsxs(MenuRoot, { children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.
|
|
759
|
+
return (jsxRuntime.jsxs(MenuRoot, { children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Button, { variant: 'ghost', gap: '0.5rem', children: table.getState().pagination.pageSize }) }), jsxRuntime.jsx(MenuContent, { children: pageSizes.map((pageSize) => (jsxRuntime.jsx(MenuItem, { value: `chakra-table-pageSize-${pageSize}`, onClick: () => {
|
|
556
760
|
table.setPageSize(Number(pageSize));
|
|
557
761
|
}, children: pageSize }, `chakra-table-pageSize-${pageSize}`))) })] }));
|
|
558
762
|
};
|
|
@@ -580,81 +784,149 @@ const PaginationRoot = React__namespace.forwardRef(function PaginationRoot(props
|
|
|
580
784
|
}
|
|
581
785
|
const container = containerRef.current;
|
|
582
786
|
let rafId = null;
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
787
|
+
let timeoutId = null;
|
|
788
|
+
const measureButtonWidth = () => {
|
|
789
|
+
// Try to measure actual rendered buttons for accuracy
|
|
790
|
+
// Look for page number buttons (they contain numeric text)
|
|
791
|
+
const allButtons = container.querySelectorAll('button');
|
|
792
|
+
const pageButtons = [];
|
|
793
|
+
allButtons.forEach((button) => {
|
|
794
|
+
const text = button.textContent?.trim();
|
|
795
|
+
// Page buttons contain numbers, prev/next buttons contain icons
|
|
796
|
+
if (text && /^\d+$/.test(text)) {
|
|
797
|
+
pageButtons.push(button);
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
if (pageButtons.length > 0) {
|
|
801
|
+
// Measure multiple buttons and take the average for accuracy
|
|
802
|
+
let totalWidth = 0;
|
|
803
|
+
let count = 0;
|
|
804
|
+
pageButtons.forEach((button) => {
|
|
805
|
+
const width = button.offsetWidth;
|
|
806
|
+
if (width > 0) {
|
|
807
|
+
totalWidth += width;
|
|
808
|
+
count++;
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
if (count > 0) {
|
|
812
|
+
return Math.ceil(totalWidth / count);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
// Fallback to estimated widths based on size
|
|
591
816
|
const buttonWidthMap = {
|
|
592
817
|
xs: 28,
|
|
593
818
|
sm: 36,
|
|
594
819
|
md: 40,
|
|
595
820
|
lg: 44,
|
|
596
821
|
};
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
822
|
+
return buttonWidthMap[size] || 36;
|
|
823
|
+
};
|
|
824
|
+
const measurePrevNextWidth = () => {
|
|
825
|
+
const allButtons = container.querySelectorAll('button');
|
|
826
|
+
let prevWidth = 0;
|
|
827
|
+
let nextWidth = 0;
|
|
828
|
+
allButtons.forEach((button) => {
|
|
829
|
+
const html = button.innerHTML;
|
|
830
|
+
// Check if it's a prev/next button by looking for chevron icons or SVG
|
|
831
|
+
if (html.includes('chevron') ||
|
|
832
|
+
html.includes('Chevron') ||
|
|
833
|
+
button.querySelector('svg')) {
|
|
834
|
+
const width = button.offsetWidth;
|
|
835
|
+
if (width > 0) {
|
|
836
|
+
// First icon button is likely prev, last is next
|
|
837
|
+
if (prevWidth === 0) {
|
|
838
|
+
prevWidth = width;
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
nextWidth = width;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
607
844
|
}
|
|
845
|
+
});
|
|
846
|
+
if (prevWidth > 0 && nextWidth > 0) {
|
|
847
|
+
return prevWidth + nextWidth;
|
|
608
848
|
}
|
|
609
|
-
//
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
849
|
+
// Fallback: use page button width estimate
|
|
850
|
+
return measureButtonWidth() * 2;
|
|
851
|
+
};
|
|
852
|
+
const calculateSiblingCount = () => {
|
|
853
|
+
if (!container)
|
|
854
|
+
return;
|
|
855
|
+
const width = container.offsetWidth;
|
|
856
|
+
if (width === 0)
|
|
857
|
+
return;
|
|
858
|
+
// Measure actual button widths
|
|
859
|
+
const pageButtonWidth = measureButtonWidth();
|
|
860
|
+
const prevNextWidth = measurePrevNextWidth();
|
|
861
|
+
// Get computed gap from container (HStack gap)
|
|
862
|
+
const containerStyles = window.getComputedStyle(container);
|
|
863
|
+
const gap = parseFloat(containerStyles.gap) || 8;
|
|
864
|
+
// Account for gaps: prev button + gap + page buttons + gap + next button
|
|
865
|
+
// We need at least 2 gaps (before and after page buttons)
|
|
866
|
+
const availableWidth = Math.max(0, width - prevNextWidth - gap * 2);
|
|
614
867
|
// Each page button takes buttonWidth + gap
|
|
615
|
-
const buttonWithGap =
|
|
616
|
-
const
|
|
617
|
-
// Calculate sibling count
|
|
618
|
-
//
|
|
619
|
-
//
|
|
620
|
-
//
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
const minRequired = 5;
|
|
624
|
-
const extraButtons = Math.max(0, maxButtons - minRequired);
|
|
625
|
-
// Calculate sibling count
|
|
626
|
-
// If we have enough space for ellipsis (2 buttons), account for that
|
|
868
|
+
const buttonWithGap = pageButtonWidth + gap;
|
|
869
|
+
const maxPageButtons = Math.floor(availableWidth / buttonWithGap);
|
|
870
|
+
// Calculate sibling count based on pagination structure
|
|
871
|
+
// Structure: [prev] [first] [ellipsis?] [siblings] [current] [siblings] [ellipsis?] [last] [next]
|
|
872
|
+
// Minimum: prev(1) + first(1) + current(1) + last(1) + next(1) = 5 buttons
|
|
873
|
+
// With siblings and ellipsis: 5 + siblings*2 + ellipsis*2
|
|
874
|
+
const minRequired = 5; // prev, first, current, last, next
|
|
875
|
+
const extraButtons = Math.max(0, maxPageButtons - minRequired);
|
|
627
876
|
let calculated = minSiblingCount;
|
|
628
877
|
if (extraButtons >= 4) {
|
|
629
|
-
//
|
|
878
|
+
// Enough space for ellipsis (2 buttons) + siblings on both sides
|
|
879
|
+
// Structure: [prev] [1] [...] [siblings] [current] [siblings] [...] [last] [next]
|
|
880
|
+
// Extra buttons = ellipsis(2) + siblings*2
|
|
630
881
|
calculated = Math.floor((extraButtons - 2) / 2);
|
|
631
882
|
}
|
|
632
883
|
else if (extraButtons >= 2) {
|
|
633
884
|
// Space for some siblings but not ellipsis
|
|
885
|
+
// Structure: [prev] [1] [siblings] [current] [siblings] [last] [next]
|
|
634
886
|
calculated = Math.floor(extraButtons / 2);
|
|
635
887
|
}
|
|
636
888
|
// Apply max limit if provided
|
|
637
889
|
if (maxSiblingCount !== undefined) {
|
|
638
890
|
calculated = Math.min(calculated, maxSiblingCount);
|
|
639
891
|
}
|
|
640
|
-
|
|
892
|
+
const finalSiblingCount = Math.max(minSiblingCount, calculated);
|
|
893
|
+
// Only update if value changed to avoid unnecessary re-renders
|
|
894
|
+
setCalculatedSiblingCount((prev) => {
|
|
895
|
+
if (prev !== finalSiblingCount) {
|
|
896
|
+
return finalSiblingCount;
|
|
897
|
+
}
|
|
898
|
+
return prev;
|
|
899
|
+
});
|
|
641
900
|
};
|
|
642
|
-
const
|
|
643
|
-
//
|
|
901
|
+
const scheduleCalculation = () => {
|
|
902
|
+
// Cancel any pending calculations
|
|
644
903
|
if (rafId !== null) {
|
|
645
904
|
cancelAnimationFrame(rafId);
|
|
646
905
|
}
|
|
647
|
-
|
|
648
|
-
|
|
906
|
+
if (timeoutId !== null) {
|
|
907
|
+
clearTimeout(timeoutId);
|
|
908
|
+
}
|
|
909
|
+
// Use requestAnimationFrame for smooth updates
|
|
910
|
+
rafId = requestAnimationFrame(() => {
|
|
911
|
+
// Small delay to ensure DOM is fully rendered
|
|
912
|
+
timeoutId = setTimeout(calculateSiblingCount, 50);
|
|
913
|
+
});
|
|
914
|
+
};
|
|
915
|
+
const resizeObserver = new ResizeObserver(scheduleCalculation);
|
|
649
916
|
resizeObserver.observe(container);
|
|
650
|
-
// Initial calculation
|
|
651
|
-
|
|
917
|
+
// Initial calculation - try multiple times to ensure buttons are rendered
|
|
918
|
+
scheduleCalculation();
|
|
919
|
+
// Also try after a longer delay as fallback
|
|
920
|
+
const fallbackTimeout = setTimeout(calculateSiblingCount, 200);
|
|
652
921
|
return () => {
|
|
653
922
|
resizeObserver.disconnect();
|
|
654
923
|
if (rafId !== null) {
|
|
655
924
|
cancelAnimationFrame(rafId);
|
|
656
925
|
}
|
|
657
|
-
|
|
926
|
+
if (timeoutId !== null) {
|
|
927
|
+
clearTimeout(timeoutId);
|
|
928
|
+
}
|
|
929
|
+
clearTimeout(fallbackTimeout);
|
|
658
930
|
};
|
|
659
931
|
}, [size, siblingCount, minSiblingCount, maxSiblingCount]);
|
|
660
932
|
const mergedRef = React__namespace.useCallback((node) => {
|
|
@@ -834,12 +1106,19 @@ const ResetSelectionButton = () => {
|
|
|
834
1106
|
const RowCountText = () => {
|
|
835
1107
|
const { table, type } = useDataTableContext();
|
|
836
1108
|
const getCount = () => {
|
|
837
|
-
if (type ===
|
|
1109
|
+
if (type === 'client') {
|
|
838
1110
|
return table.getFilteredRowModel().flatRows.length ?? 0;
|
|
839
1111
|
}
|
|
840
1112
|
return table.getRowCount();
|
|
841
1113
|
};
|
|
842
|
-
|
|
1114
|
+
const totalCount = getCount();
|
|
1115
|
+
const { pageIndex, pageSize } = table.getState().pagination;
|
|
1116
|
+
if (totalCount === 0) {
|
|
1117
|
+
return jsxRuntime.jsx(react.Text, { children: "0 of 0" });
|
|
1118
|
+
}
|
|
1119
|
+
const start = pageIndex * pageSize + 1;
|
|
1120
|
+
const end = Math.min((pageIndex + 1) * pageSize, totalCount);
|
|
1121
|
+
return jsxRuntime.jsx(react.Text, { children: `${start}-${end} / ${totalCount}` });
|
|
843
1122
|
};
|
|
844
1123
|
|
|
845
1124
|
// pulling this into a separate file so adapter(s) that don't
|
|
@@ -2948,17 +3227,17 @@ const TableFilterTags = () => {
|
|
|
2948
3227
|
|
|
2949
3228
|
const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsxRuntime.jsx(jsxRuntime.Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsxRuntime.jsx(jsxRuntime.Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
|
|
2950
3229
|
const { tableLabel, table } = useDataTableContext();
|
|
2951
|
-
const {
|
|
2952
|
-
return (jsxRuntime.jsxs(react.Grid, { templateRows:
|
|
3230
|
+
const { hasErrorText } = tableLabel;
|
|
3231
|
+
return (jsxRuntime.jsxs(react.Grid, { templateRows: 'auto 1fr', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: '0.5rem', p: 1, ...gridProps, children: [jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: 2, children: [jsxRuntime.jsxs(react.Flex, { justifyContent: 'space-between', children: [jsxRuntime.jsx(react.Box, { children: showView && jsxRuntime.jsx(ViewDialog, { icon: jsxRuntime.jsx(md.MdOutlineViewColumn, {}) }) }), jsxRuntime.jsxs(react.Flex, { gap: '0.5rem', alignItems: 'center', justifySelf: 'end', children: [loading && jsxRuntime.jsx(react.Spinner, { size: 'sm' }), hasError && (jsxRuntime.jsx(Tooltip, { content: hasErrorText, children: jsxRuntime.jsx(react.Icon, { as: bs.BsExclamationCircleFill, color: 'red.400' }) })), showGlobalFilter && jsxRuntime.jsx(GlobalFilter, {}), showFilter && jsxRuntime.jsx(FilterDialog, {}), showReload && jsxRuntime.jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: '0.5rem', children: filterTagsOptions.map((option) => {
|
|
2953
3232
|
const { column, options } = option;
|
|
2954
3233
|
const tableColumn = table.getColumn(column);
|
|
2955
|
-
return (jsxRuntime.jsxs(react.Flex, { alignItems:
|
|
3234
|
+
return (jsxRuntime.jsxs(react.Flex, { alignItems: 'center', flexFlow: 'wrap', gap: '0.5rem', children: [tableColumn?.columnDef.meta?.displayName && (jsxRuntime.jsx(react.Text, { children: tableColumn?.columnDef.meta?.displayName })), jsxRuntime.jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
|
|
2956
3235
|
if (tags.length === 0) {
|
|
2957
3236
|
return tableColumn?.setFilterValue(undefined);
|
|
2958
3237
|
}
|
|
2959
3238
|
tableColumn?.setFilterValue(tags);
|
|
2960
3239
|
} })] }, column));
|
|
2961
|
-
}) })), showFilterTags && (jsxRuntime.jsx(react.Flex, { children: jsxRuntime.jsx(TableFilterTags, {}) }))] }), jsxRuntime.jsx(react.Grid, {
|
|
3240
|
+
}) })), showFilterTags && (jsxRuntime.jsx(react.Flex, { children: jsxRuntime.jsx(TableFilterTags, {}) }))] }), jsxRuntime.jsx(react.Grid, { children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxRuntime.jsxs(react.Flex, { justifyContent: 'space-between', children: [jsxRuntime.jsxs(react.Flex, { gap: '1rem', alignItems: 'center', children: [showPageSizeControl && jsxRuntime.jsx(PageSizeControl, {}), showPageCountText && jsxRuntime.jsx(RowCountText, {})] }), jsxRuntime.jsx(react.Box, { justifySelf: 'end', children: showPagination && jsxRuntime.jsx(Pagination, {}) })] }))] }));
|
|
2962
3241
|
};
|
|
2963
3242
|
|
|
2964
3243
|
const EmptyState$1 = React__namespace.forwardRef(function EmptyState(props, ref) {
|
|
@@ -3120,7 +3399,7 @@ const Table = ({ children, emptyComponent = EmptyResult, canResize = true, showL
|
|
|
3120
3399
|
if (!showLoading && table.getRowModel().rows.length <= 0) {
|
|
3121
3400
|
return emptyComponent;
|
|
3122
3401
|
}
|
|
3123
|
-
return (jsxRuntime.jsx(react.Box, { ref: containerRef, width: "100%", overflow: "auto", children: jsxRuntime.jsx(react.Table.Root, { stickyHeader: true,
|
|
3402
|
+
return (jsxRuntime.jsx(react.Box, { ref: containerRef, width: "100%", overflow: "auto", children: jsxRuntime.jsx(react.Table.Root, { stickyHeader: true, width: canResize ? table.getCenterTotalSize() : undefined, display: 'grid', alignContent: 'start', ...props, children: children }) }));
|
|
3124
3403
|
};
|
|
3125
3404
|
|
|
3126
3405
|
const Checkbox = React__namespace.forwardRef(function Checkbox(props, ref) {
|
|
@@ -3166,11 +3445,7 @@ const TableBody = ({ showSelector = false, canResize = true, }) => {
|
|
|
3166
3445
|
// styling resize and pinning start
|
|
3167
3446
|
flex: `${canResize ? '0' : '1'} 0 ${cell.column.getSize()}px`,
|
|
3168
3447
|
// this is to avoid the cell from being too wide
|
|
3169
|
-
minWidth: `0`,
|
|
3170
|
-
base: 'colorPalette.900',
|
|
3171
|
-
_dark: 'colorPalette.100',
|
|
3172
|
-
},
|
|
3173
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...getTdProps(cell), children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
3448
|
+
minWidth: `0`, ...getTdProps(cell), children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
|
|
3174
3449
|
})] }, `chakra-table-row-${row.id}`));
|
|
3175
3450
|
}) }));
|
|
3176
3451
|
};
|
|
@@ -3180,11 +3455,7 @@ const TableRowSelector = ({ row }) => {
|
|
|
3180
3455
|
const isSelected = isRowSelected(row.id, rowSelection);
|
|
3181
3456
|
const canSelect = canRowSelect(row);
|
|
3182
3457
|
const toggleHandler = createRowToggleHandler(row, rowSelection, setRowSelection);
|
|
3183
|
-
return (jsxRuntime.jsx(react.Table.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid',
|
|
3184
|
-
base: 'colorPalette.900',
|
|
3185
|
-
_dark: 'colorPalette.100',
|
|
3186
|
-
},
|
|
3187
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: isSelected,
|
|
3458
|
+
return (jsxRuntime.jsx(react.Table.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid', justifyItems: 'center', alignItems: 'center', children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: isSelected,
|
|
3188
3459
|
disabled: !canSelect,
|
|
3189
3460
|
onCheckedChange: toggleHandler }) }));
|
|
3190
3461
|
};
|
|
@@ -3301,18 +3572,6 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3301
3572
|
const columnMeta = header.column.columnDef.meta;
|
|
3302
3573
|
return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
|
|
3303
3574
|
};
|
|
3304
|
-
const getThProps = (header) => {
|
|
3305
|
-
const thProps = header.column.getIsPinned()
|
|
3306
|
-
? {
|
|
3307
|
-
left: showSelector
|
|
3308
|
-
? `${header.getStart('left') + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
|
|
3309
|
-
: `${header.getStart('left')}px`,
|
|
3310
|
-
position: 'sticky',
|
|
3311
|
-
zIndex: 100 + 1,
|
|
3312
|
-
}
|
|
3313
|
-
: {};
|
|
3314
|
-
return thProps;
|
|
3315
|
-
};
|
|
3316
3575
|
const stickyProps = {
|
|
3317
3576
|
position: 'sticky',
|
|
3318
3577
|
top: 0,
|
|
@@ -3364,11 +3623,7 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3364
3623
|
[header.id]: finalWidth,
|
|
3365
3624
|
}));
|
|
3366
3625
|
};
|
|
3367
|
-
return (jsxRuntime.jsx(react.Table.Header, { ...(isSticky ? stickyProps : {}),
|
|
3368
|
-
base: 'colorPalette.900',
|
|
3369
|
-
_dark: 'colorPalette.100',
|
|
3370
|
-
},
|
|
3371
|
-
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: areAllRowsSelected(table, rowSelection),
|
|
3626
|
+
return (jsxRuntime.jsx(react.Table.Header, { ...(isSticky ? stickyProps : {}), ...tableHeaderProps, children: table.getHeaderGroups().map((headerGroup) => (jsxRuntime.jsxs(react.Table.Row, { display: 'flex', ...tableRowProps, children: [showSelector && (jsxRuntime.jsx(react.Table.ColumnHeader, { padding: `${table.getDensityValue()}px`, display: 'grid', justifyItems: 'center', alignItems: 'center', children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: areAllRowsSelected(table, rowSelection),
|
|
3372
3627
|
// indeterminate: areSomeRowsSelected(table, rowSelection),
|
|
3373
3628
|
onChange: createToggleAllRowsHandler(table, rowSelection, setRowSelection) }) })), headerGroup.headers.map((header) => {
|
|
3374
3629
|
const resizeProps = {
|
|
@@ -3378,30 +3633,11 @@ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true,
|
|
|
3378
3633
|
};
|
|
3379
3634
|
return (jsxRuntime.jsxs(react.Table.ColumnHeader, { padding: 0, columnSpan: `${header.colSpan}`,
|
|
3380
3635
|
// styling resize and pinning start
|
|
3381
|
-
flex: `${canResize ? '0' : '1'} 0 ${header.column.getSize()}px`, display: 'grid', gridTemplateColumns: '1fr auto', zIndex: 1500 + header.index,
|
|
3382
|
-
base: 'colorPalette.800',
|
|
3383
|
-
_dark: 'colorPalette.200',
|
|
3384
|
-
},
|
|
3385
|
-
bg: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, ...getThProps(header), children: [jsxRuntime.jsxs(MenuRoot, { children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Flex, { padding: `${table.getDensityValue()}px`, alignItems: 'center', justifyContent: 'start', borderRadius: '0rem', overflow: 'auto', color: {
|
|
3386
|
-
base: 'colorPalette.800',
|
|
3387
|
-
_dark: 'colorPalette.200',
|
|
3388
|
-
_hover: {
|
|
3389
|
-
base: 'colorPalette.700',
|
|
3390
|
-
_dark: 'colorPalette.300',
|
|
3391
|
-
},
|
|
3392
|
-
},
|
|
3393
|
-
bg: {
|
|
3394
|
-
base: 'colorPalette.100',
|
|
3395
|
-
_dark: 'colorPalette.900',
|
|
3396
|
-
_hover: {
|
|
3397
|
-
base: 'colorPalette.200',
|
|
3398
|
-
_dark: 'colorPalette.800',
|
|
3399
|
-
},
|
|
3400
|
-
}, children: jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: 'center', children: [header.isPlaceholder
|
|
3636
|
+
flex: `${canResize ? '0' : '1'} 0 ${header.column.getSize()}px`, display: 'grid', gridTemplateColumns: '1fr auto', zIndex: 1500 + header.index, children: [jsxRuntime.jsxs(MenuRoot, { children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Flex, { padding: `${table.getDensityValue()}px`, alignItems: 'center', justifyContent: 'start', borderRadius: '0rem', overflow: 'auto', children: jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: 'center', children: [header.isPlaceholder
|
|
3401
3637
|
? null
|
|
3402
3638
|
: reactTable.flexRender(header.column.columnDef.header, header.getContext()), jsxRuntime.jsx(react.Box, { children: header.column.getCanSort() && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [header.column.getIsSorted() === false && jsxRuntime.jsx(jsxRuntime.Fragment, {}), header.column.getIsSorted() === 'asc' && (jsxRuntime.jsx(bi.BiUpArrow, {})), header.column.getIsSorted() === 'desc' && (jsxRuntime.jsx(bi.BiDownArrow, {}))] })) }), jsxRuntime.jsx(react.Box, { children: header.column.getIsFiltered() && jsxRuntime.jsx(md.MdFilterListAlt, {}) })] }) }) }), jsxRuntime.jsxs(MenuContent, { children: [!header.column.getIsPinned() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "pin-column", children: jsxRuntime.jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3403
3639
|
header.column.pin('left');
|
|
3404
|
-
}, children: [jsxRuntime.jsx(md.MdPushPin, {}), getHeaderText(header, 'pinColumn')] }) })), header.column.getIsPinned() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxRuntime.jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3640
|
+
}, p: 1, children: [jsxRuntime.jsx(md.MdPushPin, {}), getHeaderText(header, 'pinColumn')] }) })), header.column.getIsPinned() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxRuntime.jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3405
3641
|
header.column.pin(false);
|
|
3406
3642
|
}, children: [jsxRuntime.jsx(md.MdCancel, {}), getHeaderText(header, 'cancelPin')] }) })), header.column.getCanSort() && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(MenuItem, { asChild: true, value: "sort-ascend", children: jsxRuntime.jsxs(Button, { variant: 'ghost', onClick: () => {
|
|
3407
3643
|
table.setSorting((state) => {
|
|
@@ -3601,7 +3837,7 @@ const ErrorAlert = ({ showMessage = true }) => {
|
|
|
3601
3837
|
const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: defaultPagination = {
|
|
3602
3838
|
pageIndex: 0, //initial page index
|
|
3603
3839
|
pageSize: 10, //default page size
|
|
3604
|
-
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter =
|
|
3840
|
+
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = '', density: defaultDensity = 'sm', } = {
|
|
3605
3841
|
sorting: [],
|
|
3606
3842
|
pagination: {
|
|
3607
3843
|
pageIndex: 0, //initial page index
|
|
@@ -3611,9 +3847,9 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3611
3847
|
columnFilters: [],
|
|
3612
3848
|
columnOrder: [],
|
|
3613
3849
|
columnVisibility: {},
|
|
3614
|
-
globalFilter:
|
|
3615
|
-
density:
|
|
3616
|
-
},
|
|
3850
|
+
globalFilter: '',
|
|
3851
|
+
density: 'sm',
|
|
3852
|
+
}, } = {
|
|
3617
3853
|
default: {
|
|
3618
3854
|
sorting: [],
|
|
3619
3855
|
pagination: {
|
|
@@ -3624,8 +3860,8 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3624
3860
|
columnFilters: [],
|
|
3625
3861
|
columnOrder: [],
|
|
3626
3862
|
columnVisibility: {},
|
|
3627
|
-
globalFilter:
|
|
3628
|
-
density:
|
|
3863
|
+
globalFilter: '',
|
|
3864
|
+
density: 'sm',
|
|
3629
3865
|
},
|
|
3630
3866
|
}) => {
|
|
3631
3867
|
const [sorting, setSorting] = React.useState(defaultSorting);
|
|
@@ -3636,7 +3872,6 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3636
3872
|
const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter);
|
|
3637
3873
|
const [density, setDensity] = React.useState(defaultDensity);
|
|
3638
3874
|
const [columnVisibility, setColumnVisibility] = React.useState(defaultColumnVisibility);
|
|
3639
|
-
const translate = reactI18next.useTranslation("", { keyPrefix });
|
|
3640
3875
|
return {
|
|
3641
3876
|
sorting,
|
|
3642
3877
|
setSorting,
|
|
@@ -3654,12 +3889,11 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3654
3889
|
setDensity,
|
|
3655
3890
|
columnVisibility,
|
|
3656
3891
|
setColumnVisibility,
|
|
3657
|
-
translate,
|
|
3658
3892
|
};
|
|
3659
3893
|
};
|
|
3660
3894
|
|
|
3661
3895
|
const useDataTableServer = (props) => {
|
|
3662
|
-
const { url, default: defaultProps,
|
|
3896
|
+
const { url, default: defaultProps, placeholderData, queryFn: customQueryFn, } = props;
|
|
3663
3897
|
const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
|
|
3664
3898
|
const [sorting, setSorting] = React.useState(defaultSorting || []);
|
|
3665
3899
|
const [columnFilters, setColumnFilters] = React.useState(defaultColumnFilters || []); // can set initial column filter state here
|
|
@@ -3669,8 +3903,8 @@ const useDataTableServer = (props) => {
|
|
|
3669
3903
|
});
|
|
3670
3904
|
const [rowSelection, setRowSelection] = React.useState(defaultRowSelection || {});
|
|
3671
3905
|
const [columnOrder, setColumnOrder] = React.useState(defaultColumnOrder || []);
|
|
3672
|
-
const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter ||
|
|
3673
|
-
const [density, setDensity] = React.useState(defaultDensity ||
|
|
3906
|
+
const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter || '');
|
|
3907
|
+
const [density, setDensity] = React.useState(defaultDensity || 'sm');
|
|
3674
3908
|
const [columnVisibility, setColumnVisibility] = React.useState(defaultColumnVisibility || {});
|
|
3675
3909
|
const { pageSize, pageIndex } = pagination;
|
|
3676
3910
|
const params = {
|
|
@@ -3682,7 +3916,7 @@ const useDataTableServer = (props) => {
|
|
|
3682
3916
|
};
|
|
3683
3917
|
const defaultQueryFn = async () => {
|
|
3684
3918
|
if (!url) {
|
|
3685
|
-
throw new Error(
|
|
3919
|
+
throw new Error('url is required');
|
|
3686
3920
|
}
|
|
3687
3921
|
const response = await axios.get(url, {
|
|
3688
3922
|
params,
|
|
@@ -3696,7 +3930,6 @@ const useDataTableServer = (props) => {
|
|
|
3696
3930
|
: defaultQueryFn,
|
|
3697
3931
|
placeholderData,
|
|
3698
3932
|
});
|
|
3699
|
-
const translate = reactI18next.useTranslation("", { keyPrefix });
|
|
3700
3933
|
return {
|
|
3701
3934
|
sorting,
|
|
3702
3935
|
setSorting,
|
|
@@ -3715,7 +3948,6 @@ const useDataTableServer = (props) => {
|
|
|
3715
3948
|
columnVisibility,
|
|
3716
3949
|
setColumnVisibility,
|
|
3717
3950
|
query,
|
|
3718
|
-
translate,
|
|
3719
3951
|
};
|
|
3720
3952
|
};
|
|
3721
3953
|
|
|
@@ -3734,11 +3966,8 @@ const snakeToLabel = (str) => {
|
|
|
3734
3966
|
.join(" "); // Join with space
|
|
3735
3967
|
};
|
|
3736
3968
|
|
|
3737
|
-
const RecordDisplay = ({ object, boxProps,
|
|
3969
|
+
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
3738
3970
|
const getColumn = ({ field }) => {
|
|
3739
|
-
if (translate !== undefined) {
|
|
3740
|
-
return translate.t(`${prefix}${field}`);
|
|
3741
|
-
}
|
|
3742
3971
|
return snakeToLabel(field);
|
|
3743
3972
|
};
|
|
3744
3973
|
if (object === null) {
|
|
@@ -3746,7 +3975,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = '', }) => {
|
|
|
3746
3975
|
}
|
|
3747
3976
|
return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
3748
3977
|
const uniqueKey = `${prefix}${field}-${index}`;
|
|
3749
|
-
return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsxRuntime.jsx(react.Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}
|
|
3978
|
+
return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsxRuntime.jsx(react.Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.` })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, uniqueKey));
|
|
3750
3979
|
}) }));
|
|
3751
3980
|
};
|
|
3752
3981
|
|
|
@@ -3760,15 +3989,12 @@ const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
|
3760
3989
|
throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
|
|
3761
3990
|
}
|
|
3762
3991
|
};
|
|
3763
|
-
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400,
|
|
3992
|
+
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
|
|
3764
3993
|
const { properties } = schema;
|
|
3765
|
-
idListSanityCheck(
|
|
3994
|
+
idListSanityCheck('ignore', ignore, properties);
|
|
3766
3995
|
widthSanityCheck(width, ignore, properties);
|
|
3767
|
-
idListSanityCheck(
|
|
3996
|
+
idListSanityCheck('meta', Object.keys(meta), properties);
|
|
3768
3997
|
const getColumn = ({ column }) => {
|
|
3769
|
-
if (translate !== undefined) {
|
|
3770
|
-
return translate.t(`${column}`);
|
|
3771
|
-
}
|
|
3772
3998
|
return snakeToLabel(column);
|
|
3773
3999
|
};
|
|
3774
4000
|
const keys = Object.keys(properties);
|
|
@@ -3777,15 +4003,15 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
|
|
|
3777
4003
|
return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
|
|
3778
4004
|
});
|
|
3779
4005
|
const columnHelper = reactTable.createColumnHelper();
|
|
3780
|
-
// @ts-expect-error find type for unknown
|
|
3781
4006
|
const columns = [
|
|
3782
4007
|
...ignored.map((column, index) => {
|
|
4008
|
+
// @ts-expect-error column accessor type issue with generic TData
|
|
3783
4009
|
return columnHelper.accessor(column, {
|
|
3784
4010
|
cell: (props) => {
|
|
3785
4011
|
// @ts-expect-error find type for unknown
|
|
3786
4012
|
const value = props.row.original[column];
|
|
3787
|
-
if (typeof value ===
|
|
3788
|
-
return (jsxRuntime.jsx(react.Grid, { overflow:
|
|
4013
|
+
if (typeof value === 'object') {
|
|
4014
|
+
return (jsxRuntime.jsx(react.Grid, { overflow: 'auto', children: jsxRuntime.jsx(RecordDisplay, { object: value }) }));
|
|
3789
4015
|
}
|
|
3790
4016
|
return jsxRuntime.jsx(TextCell, { children: value });
|
|
3791
4017
|
},
|
|
@@ -3817,6 +4043,11 @@ const SchemaFormContext = React.createContext({
|
|
|
3817
4043
|
include: [],
|
|
3818
4044
|
onSubmit: async () => { },
|
|
3819
4045
|
rowNumber: 0,
|
|
4046
|
+
/** Default translate fallback - returns key as-is */
|
|
4047
|
+
translate: {
|
|
4048
|
+
t: (key) => key,
|
|
4049
|
+
ready: true,
|
|
4050
|
+
},
|
|
3820
4051
|
requestOptions: {},
|
|
3821
4052
|
timezone: 'Asia/Hong_Kong',
|
|
3822
4053
|
displayConfig: {
|
|
@@ -4049,7 +4280,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4049
4280
|
showSubmitButton: true,
|
|
4050
4281
|
showResetButton: true,
|
|
4051
4282
|
showTitle: true,
|
|
4052
|
-
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, insideDialog = false, }) => {
|
|
4283
|
+
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
4053
4284
|
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
4054
4285
|
const [isError, setIsError] = React.useState(false);
|
|
4055
4286
|
const [isSubmiting, setIsSubmiting] = React.useState(false);
|
|
@@ -4140,6 +4371,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4140
4371
|
enumPickerLabels,
|
|
4141
4372
|
filePickerLabels,
|
|
4142
4373
|
formButtonLabels,
|
|
4374
|
+
timePickerLabels,
|
|
4143
4375
|
ajvResolver: ajvResolver(schema),
|
|
4144
4376
|
insideDialog,
|
|
4145
4377
|
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
@@ -4150,31 +4382,33 @@ function removeIndex(str) {
|
|
|
4150
4382
|
}
|
|
4151
4383
|
|
|
4152
4384
|
/**
|
|
4153
|
-
* Custom hook
|
|
4385
|
+
* Custom hook for form field labels and fallback text.
|
|
4154
4386
|
* Automatically handles colLabel construction and removeIndex logic.
|
|
4387
|
+
* Uses schema.title when available, otherwise falls back to translate function.
|
|
4155
4388
|
*
|
|
4156
4389
|
* @param column - The column name
|
|
4157
4390
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4158
|
-
* @
|
|
4391
|
+
* @param schema - Optional schema object with title property
|
|
4392
|
+
* @returns Object with label helper functions
|
|
4159
4393
|
*
|
|
4160
4394
|
* @example
|
|
4161
4395
|
* ```tsx
|
|
4162
|
-
* const formI18n = useFormI18n(column, prefix);
|
|
4396
|
+
* const formI18n = useFormI18n(column, prefix, schema);
|
|
4163
4397
|
*
|
|
4164
|
-
* // Get field label
|
|
4398
|
+
* // Get field label (prefers schema.title)
|
|
4165
4399
|
* <Field label={formI18n.label()} />
|
|
4166
4400
|
*
|
|
4167
|
-
* // Get error message
|
|
4401
|
+
* // Get required error message
|
|
4168
4402
|
* <Text>{formI18n.required()}</Text>
|
|
4169
4403
|
*
|
|
4170
|
-
* // Get custom
|
|
4404
|
+
* // Get custom text
|
|
4171
4405
|
* <Text>{formI18n.t('add_more')}</Text>
|
|
4172
4406
|
*
|
|
4173
4407
|
* // Access the raw colLabel
|
|
4174
4408
|
* const colLabel = formI18n.colLabel;
|
|
4175
4409
|
* ```
|
|
4176
4410
|
*/
|
|
4177
|
-
const useFormI18n
|
|
4411
|
+
const useFormI18n = (column, prefix = '', schema) => {
|
|
4178
4412
|
const { translate } = useSchemaContext();
|
|
4179
4413
|
const colLabel = `${prefix}${column}`;
|
|
4180
4414
|
return {
|
|
@@ -4183,7 +4417,7 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4183
4417
|
*/
|
|
4184
4418
|
colLabel,
|
|
4185
4419
|
/**
|
|
4186
|
-
* Get the field label from schema title prop, or fall back to
|
|
4420
|
+
* Get the field label from schema title prop, or fall back to translate function
|
|
4187
4421
|
* Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
4188
4422
|
*/
|
|
4189
4423
|
label: (options) => {
|
|
@@ -4193,18 +4427,18 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4193
4427
|
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
4194
4428
|
},
|
|
4195
4429
|
/**
|
|
4196
|
-
* Get the required error message
|
|
4430
|
+
* Get the required error message
|
|
4197
4431
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4198
4432
|
*/
|
|
4199
4433
|
required: (options) => {
|
|
4200
4434
|
return translate.t(removeIndex(`${colLabel}.field_required`), options);
|
|
4201
4435
|
},
|
|
4202
4436
|
/**
|
|
4203
|
-
* Get
|
|
4437
|
+
* Get text for any custom key relative to the field
|
|
4204
4438
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
4205
4439
|
*
|
|
4206
|
-
* @param key - The
|
|
4207
|
-
* @param options - Optional
|
|
4440
|
+
* @param key - The key suffix (e.g., 'add_more', 'total', etc.)
|
|
4441
|
+
* @param options - Optional options (e.g., defaultValue, interpolation variables)
|
|
4208
4442
|
*/
|
|
4209
4443
|
t: (key, options) => {
|
|
4210
4444
|
return translate.t(removeIndex(`${colLabel}.${key}`), options);
|
|
@@ -4222,8 +4456,9 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4222
4456
|
const { type } = items;
|
|
4223
4457
|
const colLabel = `${prefix}${column}`;
|
|
4224
4458
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4225
|
-
const formI18n = useFormI18n
|
|
4459
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4226
4460
|
const { formState: { errors }, setValue, watch, } = reactHookForm.useFormContext();
|
|
4461
|
+
const { formButtonLabels } = useSchemaContext();
|
|
4227
4462
|
const fields = (watch(colLabel) ?? []);
|
|
4228
4463
|
return (jsxRuntime.jsxs(react.Flex, { gridRow, gridColumn, flexFlow: 'column', gap: 2, children: [jsxRuntime.jsxs(react.Box, { as: "label", children: [formI18n.label(), isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 2, children: fields.map((field, index) => (jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: '1fr auto', gap: 2, bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
|
|
4229
4464
|
base: 'colorPalette.200',
|
|
@@ -4249,7 +4484,7 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4249
4484
|
return;
|
|
4250
4485
|
}
|
|
4251
4486
|
setValue(colLabel, [...fields, {}]);
|
|
4252
|
-
}, children:
|
|
4487
|
+
}, children: formButtonLabels?.add ?? 'Add' }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
4253
4488
|
};
|
|
4254
4489
|
|
|
4255
4490
|
const Field = React__namespace.forwardRef(function Field(props, ref) {
|
|
@@ -4263,7 +4498,7 @@ const BooleanPicker = ({ schema, column, prefix }) => {
|
|
|
4263
4498
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4264
4499
|
const colLabel = `${prefix}${column}`;
|
|
4265
4500
|
const value = watch(colLabel);
|
|
4266
|
-
const formI18n = useFormI18n
|
|
4501
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4267
4502
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4268
4503
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
|
|
4269
4504
|
setValue(colLabel, !value);
|
|
@@ -4284,50 +4519,50 @@ const CustomInput = ({ column, schema, prefix }) => {
|
|
|
4284
4519
|
|
|
4285
4520
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
4286
4521
|
const { labels } = React.useContext(DatePickerContext);
|
|
4287
|
-
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
4522
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
4288
4523
|
if (calendars.length) {
|
|
4289
|
-
return (jsxRuntime.jsxs(react.Grid, { children: [jsxRuntime.jsxs(react.Grid, { templateColumns:
|
|
4524
|
+
return (jsxRuntime.jsxs(react.Grid, { children: [jsxRuntime.jsxs(react.Grid, { templateColumns: 'repeat(4, auto)', justifyContent: 'center', children: [jsxRuntime.jsx(react.Button, { variant: 'ghost', ...getBackProps({
|
|
4290
4525
|
calendars,
|
|
4291
4526
|
offset: 12,
|
|
4292
|
-
}), children:
|
|
4527
|
+
}), children: '<<' }), jsxRuntime.jsx(react.Button, { variant: 'ghost', ...getBackProps({ calendars }), children: backButtonLabel }), jsxRuntime.jsx(react.Button, { variant: 'ghost', ...getForwardProps({ calendars }), children: forwardButtonLabel }), jsxRuntime.jsx(react.Button, { variant: 'ghost', ...getForwardProps({
|
|
4293
4528
|
calendars,
|
|
4294
4529
|
offset: 12,
|
|
4295
|
-
}), children:
|
|
4530
|
+
}), children: '>>' })] }), jsxRuntime.jsx(react.Grid, { templateColumns: 'repeat(2, auto)', justifyContent: 'center', children: calendars.map((calendar) => (jsxRuntime.jsxs(react.Grid, { gap: 4, children: [jsxRuntime.jsxs(react.Grid, { justifyContent: 'center', children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsxRuntime.jsxs(react.Grid, { templateColumns: 'repeat(7, auto)', justifyContent: 'center', children: [[0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
4296
4531
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
4297
|
-
return (jsxRuntime.jsx(react.Text, { textAlign:
|
|
4532
|
+
return (jsxRuntime.jsx(react.Text, { textAlign: 'center', children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
4298
4533
|
}), calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
4299
4534
|
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
4300
4535
|
if (!dateObj) {
|
|
4301
4536
|
return jsxRuntime.jsx(react.Grid, {}, key);
|
|
4302
4537
|
}
|
|
4303
|
-
const { date, selected, selectable, today } = dateObj;
|
|
4538
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
4304
4539
|
const getDateColor = ({ today, selected, selectable, }) => {
|
|
4305
4540
|
if (!selectable) {
|
|
4306
|
-
return
|
|
4541
|
+
return 'gray';
|
|
4307
4542
|
}
|
|
4308
4543
|
if (selected) {
|
|
4309
|
-
return
|
|
4544
|
+
return 'blue';
|
|
4310
4545
|
}
|
|
4311
4546
|
if (today) {
|
|
4312
|
-
return
|
|
4547
|
+
return 'green';
|
|
4313
4548
|
}
|
|
4314
|
-
return
|
|
4549
|
+
return '';
|
|
4315
4550
|
};
|
|
4316
4551
|
const getVariant = ({ today, selected, selectable, }) => {
|
|
4317
4552
|
if (!selectable) {
|
|
4318
|
-
return
|
|
4553
|
+
return 'surface';
|
|
4319
4554
|
}
|
|
4320
4555
|
if (selected) {
|
|
4321
|
-
return
|
|
4556
|
+
return 'solid';
|
|
4322
4557
|
}
|
|
4323
4558
|
if (today) {
|
|
4324
|
-
return
|
|
4559
|
+
return 'surface';
|
|
4325
4560
|
}
|
|
4326
|
-
return
|
|
4561
|
+
return 'ghost';
|
|
4327
4562
|
};
|
|
4328
4563
|
const color = getDateColor({ today, selected, selectable });
|
|
4329
4564
|
const variant = getVariant({ today, selected, selectable });
|
|
4330
|
-
return (jsxRuntime.jsx(react.Button, { variant: variant, colorPalette: color, ...getDateProps({ dateObj }), children: selectable ? date.getDate() :
|
|
4565
|
+
return (jsxRuntime.jsx(react.Button, { variant: variant, colorPalette: color, opacity: isCurrentMonth ? 1 : 0.4, ...getDateProps({ dateObj }), children: selectable ? date.getDate() : 'X' }, key));
|
|
4331
4566
|
}))] })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
4332
4567
|
}
|
|
4333
4568
|
return null;
|
|
@@ -4335,50 +4570,55 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
4335
4570
|
const DatePickerContext = React.createContext({
|
|
4336
4571
|
labels: {
|
|
4337
4572
|
monthNamesShort: [
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4573
|
+
'Jan',
|
|
4574
|
+
'Feb',
|
|
4575
|
+
'Mar',
|
|
4576
|
+
'Apr',
|
|
4577
|
+
'May',
|
|
4578
|
+
'Jun',
|
|
4579
|
+
'Jul',
|
|
4580
|
+
'Aug',
|
|
4581
|
+
'Sep',
|
|
4582
|
+
'Oct',
|
|
4583
|
+
'Nov',
|
|
4584
|
+
'Dec',
|
|
4350
4585
|
],
|
|
4351
|
-
weekdayNamesShort: [
|
|
4352
|
-
backButtonLabel:
|
|
4353
|
-
forwardButtonLabel:
|
|
4586
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4587
|
+
backButtonLabel: 'Back',
|
|
4588
|
+
forwardButtonLabel: 'Next',
|
|
4354
4589
|
},
|
|
4355
4590
|
});
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4591
|
+
const DatePicker$1 = ({ labels = {
|
|
4592
|
+
monthNamesShort: [
|
|
4593
|
+
'Jan',
|
|
4594
|
+
'Feb',
|
|
4595
|
+
'Mar',
|
|
4596
|
+
'Apr',
|
|
4597
|
+
'May',
|
|
4598
|
+
'Jun',
|
|
4599
|
+
'Jul',
|
|
4600
|
+
'Aug',
|
|
4601
|
+
'Sep',
|
|
4602
|
+
'Oct',
|
|
4603
|
+
'Nov',
|
|
4604
|
+
'Dec',
|
|
4605
|
+
],
|
|
4606
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4607
|
+
backButtonLabel: 'Back',
|
|
4608
|
+
forwardButtonLabel: 'Next',
|
|
4609
|
+
}, onDateSelected, selected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
|
|
4610
|
+
const calendarData = useCalendar({
|
|
4611
|
+
onDateSelected,
|
|
4612
|
+
selected,
|
|
4613
|
+
firstDayOfWeek,
|
|
4614
|
+
showOutsideDays,
|
|
4615
|
+
date,
|
|
4616
|
+
minDate,
|
|
4617
|
+
maxDate,
|
|
4618
|
+
monthsToDisplay,
|
|
4619
|
+
});
|
|
4620
|
+
return (jsxRuntime.jsx(DatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsxRuntime.jsx(Calendar, { ...calendarData,
|
|
4621
|
+
firstDayOfWeek })) }));
|
|
4382
4622
|
};
|
|
4383
4623
|
|
|
4384
4624
|
dayjs.extend(utc);
|
|
@@ -4386,7 +4626,7 @@ dayjs.extend(timezone);
|
|
|
4386
4626
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
4387
4627
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4388
4628
|
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
4389
|
-
const formI18n = useFormI18n
|
|
4629
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4390
4630
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4391
4631
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4392
4632
|
const colLabel = formI18n.colLabel;
|
|
@@ -4420,74 +4660,30 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4420
4660
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4421
4661
|
const datePickerLabels = {
|
|
4422
4662
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
formI18n.translate.t(`common.month_5`, {
|
|
4436
|
-
defaultValue: 'May',
|
|
4437
|
-
}),
|
|
4438
|
-
formI18n.translate.t(`common.month_6`, {
|
|
4439
|
-
defaultValue: 'June',
|
|
4440
|
-
}),
|
|
4441
|
-
formI18n.translate.t(`common.month_7`, {
|
|
4442
|
-
defaultValue: 'July',
|
|
4443
|
-
}),
|
|
4444
|
-
formI18n.translate.t(`common.month_8`, {
|
|
4445
|
-
defaultValue: 'August',
|
|
4446
|
-
}),
|
|
4447
|
-
formI18n.translate.t(`common.month_9`, {
|
|
4448
|
-
defaultValue: 'September',
|
|
4449
|
-
}),
|
|
4450
|
-
formI18n.translate.t(`common.month_10`, {
|
|
4451
|
-
defaultValue: 'October',
|
|
4452
|
-
}),
|
|
4453
|
-
formI18n.translate.t(`common.month_11`, {
|
|
4454
|
-
defaultValue: 'November',
|
|
4455
|
-
}),
|
|
4456
|
-
formI18n.translate.t(`common.month_12`, {
|
|
4457
|
-
defaultValue: 'December',
|
|
4458
|
-
}),
|
|
4663
|
+
'January',
|
|
4664
|
+
'February',
|
|
4665
|
+
'March',
|
|
4666
|
+
'April',
|
|
4667
|
+
'May',
|
|
4668
|
+
'June',
|
|
4669
|
+
'July',
|
|
4670
|
+
'August',
|
|
4671
|
+
'September',
|
|
4672
|
+
'October',
|
|
4673
|
+
'November',
|
|
4674
|
+
'December',
|
|
4459
4675
|
],
|
|
4460
4676
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
defaultValue: 'Tue',
|
|
4469
|
-
}),
|
|
4470
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
4471
|
-
defaultValue: 'Wed',
|
|
4472
|
-
}),
|
|
4473
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
4474
|
-
defaultValue: 'Thu',
|
|
4475
|
-
}),
|
|
4476
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
4477
|
-
defaultValue: 'Fri',
|
|
4478
|
-
}),
|
|
4479
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
4480
|
-
defaultValue: 'Sat',
|
|
4481
|
-
}),
|
|
4677
|
+
'Sun',
|
|
4678
|
+
'Mon',
|
|
4679
|
+
'Tue',
|
|
4680
|
+
'Wed',
|
|
4681
|
+
'Thu',
|
|
4682
|
+
'Fri',
|
|
4683
|
+
'Sat',
|
|
4482
4684
|
],
|
|
4483
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4484
|
-
|
|
4485
|
-
defaultValue: 'Back',
|
|
4486
|
-
}),
|
|
4487
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4488
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
4489
|
-
defaultValue: 'Forward',
|
|
4490
|
-
}),
|
|
4685
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
4686
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
4491
4687
|
};
|
|
4492
4688
|
const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4493
4689
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
@@ -4504,7 +4700,7 @@ dayjs.extend(timezone);
|
|
|
4504
4700
|
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4505
4701
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4506
4702
|
const { timezone, insideDialog } = useSchemaContext();
|
|
4507
|
-
const formI18n = useFormI18n
|
|
4703
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4508
4704
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4509
4705
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4510
4706
|
const colLabel = formI18n.colLabel;
|
|
@@ -4602,7 +4798,7 @@ const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
|
4602
4798
|
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
4603
4799
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4604
4800
|
const { enumPickerLabels, insideDialog } = useSchemaContext();
|
|
4605
|
-
const formI18n = useFormI18n
|
|
4801
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4606
4802
|
const { required, variant } = schema;
|
|
4607
4803
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4608
4804
|
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
@@ -5149,7 +5345,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
|
|
|
5149
5345
|
}) })) }))] }));
|
|
5150
5346
|
};
|
|
5151
5347
|
|
|
5152
|
-
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels,
|
|
5348
|
+
function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, colLabel, }) {
|
|
5153
5349
|
const [selectedFile, setSelectedFile] = React.useState(undefined);
|
|
5154
5350
|
const [activeTab, setActiveTab] = React.useState('browse');
|
|
5155
5351
|
const [uploadingFiles, setUploadingFiles] = React.useState(new Set());
|
|
@@ -5218,15 +5414,8 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5218
5414
|
const showTabs = enableUpload && !!onUploadFile && !!onFetchFiles;
|
|
5219
5415
|
if (!onFetchFiles && !onUploadFile)
|
|
5220
5416
|
return null;
|
|
5221
|
-
return (jsxRuntime.jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxRuntime.jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsxRuntime.jsx(DialogCloseTrigger, {})] }), jsxRuntime.jsx(DialogBody, { children: showTabs ? (jsxRuntime.jsxs(react.Tabs.Root, { value: activeTab, onValueChange: (e) => setActiveTab(e.value ?? 'browse'), children: [jsxRuntime.jsxs(react.Tabs.List, { children: [jsxRuntime.jsx(react.Tabs.Trigger, { value: "browse", children: labels?.browseTab ??
|
|
5222
|
-
|
|
5223
|
-
'Browse Library' }), jsxRuntime.jsx(react.Tabs.Trigger, { value: "upload", children: labels?.uploadTab ??
|
|
5224
|
-
translate(removeIndex(`${colLabel}.upload_tab`)) ??
|
|
5225
|
-
'Upload Files' })] }), jsxRuntime.jsx(react.Tabs.Content, { value: "browse", children: onFetchFiles && (jsxRuntime.jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFile: selectedFile, onFileSelect: setSelectedFile })) }), jsxRuntime.jsx(react.Tabs.Content, { value: "upload", children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 4, children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
5226
|
-
translate(removeIndex(`${colLabel}.fileDropzone`)) ??
|
|
5227
|
-
'Drop files here or click to upload' }), uploadingFiles.size > 0 && (jsxRuntime.jsx(react.Box, { children: Array.from(uploadingFiles).map((fileKey) => (jsxRuntime.jsx(react.Box, { py: 2, children: jsxRuntime.jsxs(react.HStack, { gap: 2, children: [jsxRuntime.jsx(react.Spinner, { size: "sm", colorPalette: "blue" }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", color: "fg.muted", children: [labels?.uploading ??
|
|
5228
|
-
translate(removeIndex(`${colLabel}.uploading`)) ??
|
|
5229
|
-
'Uploading...', ' ', fileKey.split('-')[0]] })] }) }, fileKey))) })), uploadErrors.size > 0 && (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: Array.from(uploadErrors.entries()).map(([fileKey, error]) => (jsxRuntime.jsx(react.Box, { bg: {
|
|
5417
|
+
return (jsxRuntime.jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxRuntime.jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsxRuntime.jsx(DialogCloseTrigger, {})] }), jsxRuntime.jsx(DialogBody, { children: showTabs ? (jsxRuntime.jsxs(react.Tabs.Root, { value: activeTab, onValueChange: (e) => setActiveTab(e.value ?? 'browse'), children: [jsxRuntime.jsxs(react.Tabs.List, { children: [jsxRuntime.jsx(react.Tabs.Trigger, { value: "browse", children: labels?.browseTab ?? 'Browse Library' }), jsxRuntime.jsx(react.Tabs.Trigger, { value: "upload", children: labels?.uploadTab ?? 'Upload Files' })] }), jsxRuntime.jsx(react.Tabs.Content, { value: "browse", children: onFetchFiles && (jsxRuntime.jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open && activeTab === 'browse', selectedFile: selectedFile, onFileSelect: setSelectedFile })) }), jsxRuntime.jsx(react.Tabs.Content, { value: "upload", children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 4, children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => handleFileUpload(files), placeholder: labels?.fileDropzone ??
|
|
5418
|
+
'Drop files here or click to upload' }), uploadingFiles.size > 0 && (jsxRuntime.jsx(react.Box, { children: Array.from(uploadingFiles).map((fileKey) => (jsxRuntime.jsx(react.Box, { py: 2, children: jsxRuntime.jsxs(react.HStack, { gap: 2, children: [jsxRuntime.jsx(react.Spinner, { size: "sm", colorPalette: "blue" }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", color: "fg.muted", children: [labels?.uploading ?? 'Uploading...', ' ', fileKey.split('-')[0]] })] }) }, fileKey))) })), uploadErrors.size > 0 && (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: Array.from(uploadErrors.entries()).map(([fileKey, error]) => (jsxRuntime.jsx(react.Box, { bg: {
|
|
5230
5419
|
base: 'colorPalette.50',
|
|
5231
5420
|
_dark: 'colorPalette.900/20',
|
|
5232
5421
|
}, border: "1px solid", borderColor: {
|
|
@@ -5235,18 +5424,12 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5235
5424
|
}, colorPalette: "red", borderRadius: "md", p: 3, children: jsxRuntime.jsxs(react.Text, { fontSize: "sm", color: {
|
|
5236
5425
|
base: 'colorPalette.600',
|
|
5237
5426
|
_dark: 'colorPalette.300',
|
|
5238
|
-
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ??
|
|
5239
|
-
translate(removeIndex(`${colLabel}.upload_failed`)) ??
|
|
5240
|
-
'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsxRuntime.jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFile: selectedFile, onFileSelect: setSelectedFile })) : null }), jsxRuntime.jsx(DialogFooter, { children: jsxRuntime.jsxs(react.HStack, { gap: 3, justify: "end", children: [jsxRuntime.jsx(react.Button, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
|
|
5241
|
-
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
5242
|
-
'Cancel' }), jsxRuntime.jsx(react.Button, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ??
|
|
5243
|
-
translate(removeIndex(`${colLabel}.select`)) ??
|
|
5244
|
-
'Select' })] }) })] }) }));
|
|
5427
|
+
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ?? 'Upload failed', error && ` - ${error}`] }) }, fileKey))) }))] }) })] })) : onFetchFiles ? (jsxRuntime.jsx(MediaLibraryBrowser, { onFetchFiles: onFetchFiles, filterImageOnly: filterImageOnly, labels: labels, enabled: open, selectedFile: selectedFile, onFileSelect: setSelectedFile })) : null }), jsxRuntime.jsx(DialogFooter, { children: jsxRuntime.jsxs(react.HStack, { gap: 3, justify: "end", children: [jsxRuntime.jsx(react.Button, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ?? 'Cancel' }), jsxRuntime.jsx(react.Button, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ?? 'Select' })] }) })] }) }));
|
|
5245
5428
|
}
|
|
5246
5429
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
5247
5430
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
5248
5431
|
const { filePickerLabels } = useSchemaContext();
|
|
5249
|
-
const formI18n = useFormI18n
|
|
5432
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5250
5433
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5251
5434
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5252
5435
|
const isSingleSelect = type === 'string';
|
|
@@ -5322,7 +5505,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5322
5505
|
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
5323
5506
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
5324
5507
|
const { filePickerLabels } = useSchemaContext();
|
|
5325
|
-
const formI18n = useFormI18n
|
|
5508
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5326
5509
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
5327
5510
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5328
5511
|
const isSingleSelect = type === 'string';
|
|
@@ -5418,8 +5601,8 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5418
5601
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
|
|
5419
5602
|
formI18n.t('browse_library') ??
|
|
5420
5603
|
'Browse from Library' }) }), jsxRuntime.jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5421
|
-
|
|
5422
|
-
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels,
|
|
5604
|
+
filePickerLabels?.dialogTitle ??
|
|
5605
|
+
'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
|
|
5423
5606
|
const file = fileMap.get(fileId);
|
|
5424
5607
|
const isImage = file
|
|
5425
5608
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5468,17 +5651,79 @@ const defaultRenderDisplay = (item) => {
|
|
|
5468
5651
|
return JSON.stringify(item);
|
|
5469
5652
|
};
|
|
5470
5653
|
|
|
5471
|
-
|
|
5654
|
+
/**
|
|
5655
|
+
* Load initial values for IdPicker fields into idMap
|
|
5656
|
+
* Uses customQueryFn if available, otherwise falls back to getTableData
|
|
5657
|
+
*
|
|
5658
|
+
* @param params - Configuration for loading initial values
|
|
5659
|
+
* @returns Promise with fetched data and idMap
|
|
5660
|
+
*/
|
|
5661
|
+
const loadInitialValues = async ({ ids, foreign_key, serverUrl, setIdMap, }) => {
|
|
5662
|
+
if (!ids || ids.length === 0) {
|
|
5663
|
+
return { data: { data: [], count: 0 }, idMap: {} };
|
|
5664
|
+
}
|
|
5665
|
+
const { table, column: column_ref, customQueryFn } = foreign_key;
|
|
5666
|
+
// Filter out IDs that are already in idMap (optional optimization)
|
|
5667
|
+
// For now, we'll fetch all requested IDs to ensure consistency
|
|
5668
|
+
if (customQueryFn) {
|
|
5669
|
+
const { data, idMap: returnedIdMap } = await customQueryFn({
|
|
5670
|
+
searching: '',
|
|
5671
|
+
limit: ids.length,
|
|
5672
|
+
offset: 0,
|
|
5673
|
+
where: [
|
|
5674
|
+
{
|
|
5675
|
+
id: column_ref,
|
|
5676
|
+
value: ids.length === 1 ? ids[0] : ids, // CustomQueryFn accepts string | string[]
|
|
5677
|
+
},
|
|
5678
|
+
],
|
|
5679
|
+
});
|
|
5680
|
+
// Update idMap with returned values
|
|
5681
|
+
if (returnedIdMap && Object.keys(returnedIdMap).length > 0) {
|
|
5682
|
+
setIdMap((state) => {
|
|
5683
|
+
return { ...state, ...returnedIdMap };
|
|
5684
|
+
});
|
|
5685
|
+
}
|
|
5686
|
+
return { data, idMap: returnedIdMap || {} };
|
|
5687
|
+
}
|
|
5688
|
+
// Fallback to default getTableData
|
|
5689
|
+
const data = await getTableData({
|
|
5690
|
+
serverUrl,
|
|
5691
|
+
searching: '',
|
|
5692
|
+
in_table: table,
|
|
5693
|
+
limit: ids.length,
|
|
5694
|
+
offset: 0,
|
|
5695
|
+
where: [
|
|
5696
|
+
{
|
|
5697
|
+
id: column_ref,
|
|
5698
|
+
value: ids, // Always pass as array
|
|
5699
|
+
},
|
|
5700
|
+
],
|
|
5701
|
+
});
|
|
5702
|
+
// Build idMap from fetched data
|
|
5703
|
+
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
5704
|
+
return [
|
|
5705
|
+
item[column_ref],
|
|
5706
|
+
{
|
|
5707
|
+
...item,
|
|
5708
|
+
},
|
|
5709
|
+
];
|
|
5710
|
+
}));
|
|
5711
|
+
// Update idMap state
|
|
5712
|
+
setIdMap((state) => {
|
|
5713
|
+
return { ...state, ...newMap };
|
|
5714
|
+
});
|
|
5715
|
+
return { data: data, idMap: newMap };
|
|
5716
|
+
};
|
|
5717
|
+
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5472
5718
|
const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5473
5719
|
const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5474
|
-
const
|
|
5475
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
5476
|
-
const isRequired = required?.some((columnId) => columnId === column);
|
|
5720
|
+
const { renderDisplay, foreign_key } = schema;
|
|
5477
5721
|
const { table, column: column_ref, customQueryFn, } = foreign_key;
|
|
5478
5722
|
const [searchText, setSearchText] = React.useState('');
|
|
5479
5723
|
const [debouncedSearchText, setDebouncedSearchText] = React.useState('');
|
|
5480
5724
|
const [limit] = React.useState(50); // Increased limit for combobox
|
|
5481
|
-
|
|
5725
|
+
// Get colLabel from schema context (we'll compute it here)
|
|
5726
|
+
const colLabel = `${prefix}${column}`;
|
|
5482
5727
|
const watchedValue = watch(colLabel);
|
|
5483
5728
|
const watchId = !isMultiple ? watchedValue : undefined;
|
|
5484
5729
|
const watchIds = isMultiple
|
|
@@ -5525,48 +5770,14 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5525
5770
|
if (missingIds.length === 0) {
|
|
5526
5771
|
return { data: [], count: 0 };
|
|
5527
5772
|
}
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
offset: 0,
|
|
5533
|
-
where: [
|
|
5534
|
-
{
|
|
5535
|
-
id: column_ref,
|
|
5536
|
-
value: missingIds.length === 1 ? missingIds[0] : missingIds,
|
|
5537
|
-
},
|
|
5538
|
-
],
|
|
5539
|
-
});
|
|
5540
|
-
setIdMap((state) => {
|
|
5541
|
-
return { ...state, ...idMap };
|
|
5542
|
-
});
|
|
5543
|
-
return data;
|
|
5544
|
-
}
|
|
5545
|
-
const data = await getTableData({
|
|
5773
|
+
// Use the reusable loadInitialValues function
|
|
5774
|
+
const result = await loadInitialValues({
|
|
5775
|
+
ids: missingIds,
|
|
5776
|
+
foreign_key: foreign_key,
|
|
5546
5777
|
serverUrl,
|
|
5547
|
-
|
|
5548
|
-
in_table: table,
|
|
5549
|
-
limit: missingIds.length,
|
|
5550
|
-
offset: 0,
|
|
5551
|
-
where: [
|
|
5552
|
-
{
|
|
5553
|
-
id: column_ref,
|
|
5554
|
-
value: missingIds.length === 1 ? missingIds[0] : missingIds,
|
|
5555
|
-
},
|
|
5556
|
-
],
|
|
5557
|
-
});
|
|
5558
|
-
const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
|
|
5559
|
-
return [
|
|
5560
|
-
item[column_ref],
|
|
5561
|
-
{
|
|
5562
|
-
...item,
|
|
5563
|
-
},
|
|
5564
|
-
];
|
|
5565
|
-
}));
|
|
5566
|
-
setIdMap((state) => {
|
|
5567
|
-
return { ...state, ...newMap };
|
|
5778
|
+
setIdMap,
|
|
5568
5779
|
});
|
|
5569
|
-
return data;
|
|
5780
|
+
return result.data;
|
|
5570
5781
|
},
|
|
5571
5782
|
enabled: missingIds.length > 0, // Only fetch if there are missing IDs
|
|
5572
5783
|
staleTime: 300000,
|
|
@@ -5677,20 +5888,6 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5677
5888
|
itemToValue: (item) => item.value,
|
|
5678
5889
|
filter: contains,
|
|
5679
5890
|
});
|
|
5680
|
-
// Handle input value change (search)
|
|
5681
|
-
const handleInputValueChange = (details) => {
|
|
5682
|
-
setSearchText(details.inputValue);
|
|
5683
|
-
// Filter will be applied after data is fetched
|
|
5684
|
-
};
|
|
5685
|
-
// Handle value change
|
|
5686
|
-
const handleValueChange = (details) => {
|
|
5687
|
-
if (isMultiple) {
|
|
5688
|
-
setValue(colLabel, details.value);
|
|
5689
|
-
}
|
|
5690
|
-
else {
|
|
5691
|
-
setValue(colLabel, details.value[0] || '');
|
|
5692
|
-
}
|
|
5693
|
-
};
|
|
5694
5891
|
// Track previous comboboxItems to avoid unnecessary updates
|
|
5695
5892
|
const prevComboboxItemsRef = React.useRef('');
|
|
5696
5893
|
const prevSearchTextRef = React.useRef('');
|
|
@@ -5720,8 +5917,106 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5720
5917
|
// comboboxItems and searchText are the only dependencies we care about
|
|
5721
5918
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5722
5919
|
}, [comboboxItems, searchText]);
|
|
5920
|
+
return {
|
|
5921
|
+
colLabel,
|
|
5922
|
+
currentValue,
|
|
5923
|
+
searchText,
|
|
5924
|
+
setSearchText,
|
|
5925
|
+
debouncedSearchText,
|
|
5926
|
+
isLoading,
|
|
5927
|
+
isFetching,
|
|
5928
|
+
isPending,
|
|
5929
|
+
isError,
|
|
5930
|
+
isSearching,
|
|
5931
|
+
isLoadingInitialValues,
|
|
5932
|
+
isFetchingInitialValues,
|
|
5933
|
+
missingIds,
|
|
5934
|
+
comboboxItems,
|
|
5935
|
+
collection,
|
|
5936
|
+
filter,
|
|
5937
|
+
set,
|
|
5938
|
+
idMap,
|
|
5939
|
+
idPickerLabels,
|
|
5940
|
+
insideDialog: insideDialog ?? false,
|
|
5941
|
+
renderDisplay,
|
|
5942
|
+
column_ref,
|
|
5943
|
+
errors,
|
|
5944
|
+
setValue,
|
|
5945
|
+
};
|
|
5946
|
+
};
|
|
5947
|
+
|
|
5948
|
+
const IdPickerSingle = ({ column, schema, prefix, }) => {
|
|
5949
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5950
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
5951
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5952
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
5953
|
+
column,
|
|
5954
|
+
schema,
|
|
5955
|
+
prefix,
|
|
5956
|
+
isMultiple: false,
|
|
5957
|
+
});
|
|
5958
|
+
const handleInputValueChange = (details) => {
|
|
5959
|
+
setSearchText(details.inputValue);
|
|
5960
|
+
};
|
|
5961
|
+
const handleValueChange = (details) => {
|
|
5962
|
+
setValue(colLabel, details.value[0] || '');
|
|
5963
|
+
};
|
|
5964
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
5723
5965
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5724
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [
|
|
5966
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsxRuntime.jsx(react.Flex, { mb: 2, children: (() => {
|
|
5967
|
+
const id = currentValue[0];
|
|
5968
|
+
const item = idMap[id];
|
|
5969
|
+
// Show loading skeleton while fetching initial values
|
|
5970
|
+
if (item === undefined &&
|
|
5971
|
+
(isLoadingInitialValues || isFetchingInitialValues) &&
|
|
5972
|
+
missingIds.includes(id)) {
|
|
5973
|
+
return jsxRuntime.jsx(react.Skeleton, { height: "24px", width: "100px", borderRadius: "md" });
|
|
5974
|
+
}
|
|
5975
|
+
// Only show "not found" if we're not loading and item is still missing
|
|
5976
|
+
if (item === undefined) {
|
|
5977
|
+
return (jsxRuntime.jsx(react.Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }));
|
|
5978
|
+
}
|
|
5979
|
+
return jsxRuntime.jsx(react.Text, { fontSize: "sm", children: renderDisplayFunction(item) });
|
|
5980
|
+
})() })), jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: false, closeOnSelect: true, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5981
|
+
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5982
|
+
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, { size: "xs" }), isError && (jsxRuntime.jsx(react.Icon, { color: "fg.error", children: jsxRuntime.jsx(bi.BiError, {}) })), currentValue.length > 0 && (jsxRuntime.jsx(react.Combobox.ClearTrigger, { onClick: () => {
|
|
5983
|
+
setValue(colLabel, '');
|
|
5984
|
+
} })), jsxRuntime.jsx(react.Combobox.Trigger, {})] })] }), insideDialog ? (jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5985
|
+
// Show skeleton items to prevent UI shift
|
|
5986
|
+
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
5987
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5988
|
+
: idPickerLabels?.initialResults ??
|
|
5989
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
5990
|
+
? renderDisplayFunction(item.raw)
|
|
5991
|
+
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5992
|
+
// Show skeleton items to prevent UI shift
|
|
5993
|
+
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
5994
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5995
|
+
: idPickerLabels?.initialResults ??
|
|
5996
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
5997
|
+
? renderDisplayFunction(item.raw)
|
|
5998
|
+
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5999
|
+
};
|
|
6000
|
+
|
|
6001
|
+
const IdPickerMultiple = ({ column, schema, prefix, }) => {
|
|
6002
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6003
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
6004
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
6005
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
6006
|
+
column,
|
|
6007
|
+
schema,
|
|
6008
|
+
prefix,
|
|
6009
|
+
isMultiple: true,
|
|
6010
|
+
});
|
|
6011
|
+
const handleInputValueChange = (details) => {
|
|
6012
|
+
setSearchText(details.inputValue);
|
|
6013
|
+
};
|
|
6014
|
+
const handleValueChange = (details) => {
|
|
6015
|
+
setValue(colLabel, details.value);
|
|
6016
|
+
};
|
|
6017
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
6018
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6019
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, mb: 2, children: currentValue.map((id) => {
|
|
5725
6020
|
const item = idMap[id];
|
|
5726
6021
|
// Show loading skeleton while fetching initial values
|
|
5727
6022
|
if (item === undefined &&
|
|
@@ -5731,34 +6026,28 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5731
6026
|
}
|
|
5732
6027
|
// Only show "not found" if we're not loading and item is still missing
|
|
5733
6028
|
if (item === undefined) {
|
|
5734
|
-
return (jsxRuntime.jsx(react.Text, { fontSize: "sm", children: idPickerLabels?.undefined ??
|
|
6029
|
+
return (jsxRuntime.jsx(react.Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
5735
6030
|
}
|
|
5736
6031
|
return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
|
|
5737
6032
|
const newValue = currentValue.filter((itemId) => itemId !== id);
|
|
5738
6033
|
setValue(colLabel, newValue);
|
|
5739
|
-
}, children:
|
|
5740
|
-
|
|
5741
|
-
: defaultRenderDisplay(item) }, id));
|
|
5742
|
-
}) })), jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: isMultiple, closeOnSelect: !isMultiple, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
6034
|
+
}, children: renderDisplayFunction(item) }, id));
|
|
6035
|
+
}) })), jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: true, closeOnSelect: false, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
|
|
5743
6036
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5744
|
-
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ??
|
|
5745
|
-
setValue(colLabel, '');
|
|
5746
|
-
} })), jsxRuntime.jsx(react.Combobox.Trigger, {})] })] }), insideDialog ? (jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: formI18n.t('loading_failed') })) : isFetching || isLoading || isPending || isSearching ? (
|
|
6037
|
+
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? 'Type to search' }), jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, { size: "xs" }), isError && (jsxRuntime.jsx(react.Icon, { color: "fg.error", children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsx(react.Combobox.Trigger, {})] })] }), insideDialog ? (jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5747
6038
|
// Show skeleton items to prevent UI shift
|
|
5748
6039
|
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
5749
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5750
|
-
formI18n.t('empty_search_result')
|
|
6040
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5751
6041
|
: idPickerLabels?.initialResults ??
|
|
5752
|
-
|
|
5753
|
-
?
|
|
5754
|
-
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children:
|
|
6042
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
6043
|
+
? renderDisplayFunction(item.raw)
|
|
6044
|
+
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: idPickerLabels?.emptySearchResult ?? 'Loading failed' })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5755
6045
|
// Show skeleton items to prevent UI shift
|
|
5756
6046
|
jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
|
|
5757
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5758
|
-
formI18n.t('empty_search_result')
|
|
6047
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5759
6048
|
: idPickerLabels?.initialResults ??
|
|
5760
|
-
|
|
5761
|
-
?
|
|
6049
|
+
'Start typing to search' })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: !!renderDisplayFunction === true
|
|
6050
|
+
? renderDisplayFunction(item.raw)
|
|
5762
6051
|
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5763
6052
|
};
|
|
5764
6053
|
|
|
@@ -5832,7 +6121,7 @@ const NumberInputField = ({ schema, column, prefix, }) => {
|
|
|
5832
6121
|
const colLabel = `${prefix}${column}`;
|
|
5833
6122
|
const value = watch(`${colLabel}`);
|
|
5834
6123
|
const fieldError = getFieldError(errors, colLabel);
|
|
5835
|
-
const formI18n = useFormI18n
|
|
6124
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5836
6125
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn, gridRow, errorText: fieldError
|
|
5837
6126
|
? fieldError.includes('required')
|
|
5838
6127
|
? formI18n.required()
|
|
@@ -5850,7 +6139,7 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5850
6139
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
5851
6140
|
const colLabel = `${prefix}${column}`;
|
|
5852
6141
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5853
|
-
const formI18n = useFormI18n
|
|
6142
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5854
6143
|
const { formState: { errors }, } = reactHookForm.useFormContext();
|
|
5855
6144
|
if (properties === undefined) {
|
|
5856
6145
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -5870,14 +6159,14 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5870
6159
|
|
|
5871
6160
|
const RecordInput = ({ column, schema, prefix }) => {
|
|
5872
6161
|
const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
|
|
5873
|
-
const {
|
|
6162
|
+
const { formButtonLabels } = useSchemaContext();
|
|
5874
6163
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5875
6164
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5876
6165
|
const entries = Object.entries(getValues(column) ?? {});
|
|
5877
6166
|
const [showNewEntries, setShowNewEntries] = React.useState(false);
|
|
5878
6167
|
const [newKey, setNewKey] = React.useState();
|
|
5879
6168
|
const [newValue, setNewValue] = React.useState();
|
|
5880
|
-
const formI18n = useFormI18n
|
|
6169
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5881
6170
|
return (jsxRuntime.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]) => {
|
|
5882
6171
|
return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
|
|
5883
6172
|
const filtered = entries.filter(([target]) => {
|
|
@@ -5914,11 +6203,11 @@ const RecordInput = ({ column, schema, prefix }) => {
|
|
|
5914
6203
|
setShowNewEntries(false);
|
|
5915
6204
|
setNewKey(undefined);
|
|
5916
6205
|
setNewValue(undefined);
|
|
5917
|
-
}, children:
|
|
6206
|
+
}, children: formButtonLabels?.save ?? 'Save' })] })] }) }), jsxRuntime.jsx(Button, { onClick: () => {
|
|
5918
6207
|
setShowNewEntries(true);
|
|
5919
6208
|
setNewKey(undefined);
|
|
5920
6209
|
setNewValue(undefined);
|
|
5921
|
-
}, children:
|
|
6210
|
+
}, children: formButtonLabels?.addNew ?? 'Add New' })] }));
|
|
5922
6211
|
};
|
|
5923
6212
|
|
|
5924
6213
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
@@ -5927,7 +6216,7 @@ const StringInputField = ({ column, schema, prefix, }) => {
|
|
|
5927
6216
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5928
6217
|
const colLabel = `${prefix}${column}`;
|
|
5929
6218
|
const fieldError = getFieldError(errors, colLabel);
|
|
5930
|
-
const formI18n = useFormI18n
|
|
6219
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5931
6220
|
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
|
|
5932
6221
|
};
|
|
5933
6222
|
|
|
@@ -6119,7 +6408,7 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6119
6408
|
const form = reactHookForm.useFormContext();
|
|
6120
6409
|
const { setValue, watch } = form;
|
|
6121
6410
|
const fieldError = getFieldError(errors, colLabel);
|
|
6122
|
-
const formI18n = useFormI18n
|
|
6411
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6123
6412
|
const watchValue = watch(colLabel);
|
|
6124
6413
|
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
|
|
6125
6414
|
? fieldError.includes('required')
|
|
@@ -6130,18 +6419,13 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6130
6419
|
|
|
6131
6420
|
dayjs.extend(utc);
|
|
6132
6421
|
dayjs.extend(timezone);
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
},
|
|
6139
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6140
|
-
onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, portalled = true, }) {
|
|
6141
|
-
// Generate time options (every 15 minutes)
|
|
6422
|
+
const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem, onChange = () => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6423
|
+
placeholder: 'hh:mm AM/PM',
|
|
6424
|
+
emptyMessage: 'No time found',
|
|
6425
|
+
}, }) => {
|
|
6426
|
+
// Generate time options (every 15 minutes in 12-hour format)
|
|
6142
6427
|
const timeOptions = React.useMemo(() => {
|
|
6143
6428
|
const options = [];
|
|
6144
|
-
const meridiemOptions = ['am', 'pm'];
|
|
6145
6429
|
// Get start time for comparison if provided
|
|
6146
6430
|
let startDateTime = null;
|
|
6147
6431
|
let shouldFilterByDate = false;
|
|
@@ -6156,14 +6440,16 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6156
6440
|
selectedDateObj.format('YYYY-MM-DD');
|
|
6157
6441
|
}
|
|
6158
6442
|
}
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
//
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6443
|
+
// Generate 12-hour format options (1-12 for hours, AM/PM)
|
|
6444
|
+
for (let h = 1; h <= 12; h++) {
|
|
6445
|
+
for (let m = 0; m < 60; m += 15) {
|
|
6446
|
+
for (const mer of ['am', 'pm']) {
|
|
6447
|
+
// Convert 12-hour to 24-hour for comparison
|
|
6448
|
+
let hour24 = h;
|
|
6449
|
+
if (mer === 'am' && h === 12)
|
|
6450
|
+
hour24 = 0;
|
|
6451
|
+
else if (mer === 'pm' && h < 12)
|
|
6452
|
+
hour24 = h + 12;
|
|
6167
6453
|
// Filter out times that would result in negative duration (only when dates are the same)
|
|
6168
6454
|
if (startDateTime && selectedDate && shouldFilterByDate) {
|
|
6169
6455
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
@@ -6206,20 +6492,23 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6206
6492
|
}
|
|
6207
6493
|
}
|
|
6208
6494
|
}
|
|
6495
|
+
const hourDisplay = h.toString();
|
|
6496
|
+
const minuteDisplay = m.toString().padStart(2, '0');
|
|
6497
|
+
const timeDisplay = `${hourDisplay}:${minuteDisplay} ${mer.toUpperCase()}`;
|
|
6209
6498
|
options.push({
|
|
6210
|
-
label:
|
|
6211
|
-
value: `${h}:${m
|
|
6499
|
+
label: timeDisplay,
|
|
6500
|
+
value: `${h}:${m}:${mer}`,
|
|
6212
6501
|
hour: h,
|
|
6213
6502
|
minute: m,
|
|
6214
6503
|
meridiem: mer,
|
|
6215
|
-
searchText:
|
|
6504
|
+
searchText: timeDisplay, // Use base time without duration for searching
|
|
6216
6505
|
durationText,
|
|
6217
6506
|
});
|
|
6218
6507
|
}
|
|
6219
6508
|
}
|
|
6220
6509
|
}
|
|
6221
6510
|
return options;
|
|
6222
|
-
}, [
|
|
6511
|
+
}, [startTime, selectedDate, timezone]);
|
|
6223
6512
|
const { contains } = react.useFilter({ sensitivity: 'base' });
|
|
6224
6513
|
const { collection, filter } = react.useListCollection({
|
|
6225
6514
|
initialItems: timeOptions,
|
|
@@ -6232,7 +6521,7 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6232
6521
|
if (hour === null || minute === null || meridiem === null) {
|
|
6233
6522
|
return '';
|
|
6234
6523
|
}
|
|
6235
|
-
return `${hour}:${minute
|
|
6524
|
+
return `${hour}:${minute}:${meridiem}`;
|
|
6236
6525
|
}, [hour, minute, meridiem]);
|
|
6237
6526
|
// Calculate duration difference
|
|
6238
6527
|
const durationDiff = React.useMemo(() => {
|
|
@@ -6243,15 +6532,14 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6243
6532
|
meridiem === null) {
|
|
6244
6533
|
return null;
|
|
6245
6534
|
}
|
|
6246
|
-
const hour24 = meridiem === 'am'
|
|
6247
|
-
? hour === 12
|
|
6248
|
-
? 0
|
|
6249
|
-
: hour
|
|
6250
|
-
: hour === 12
|
|
6251
|
-
? 12
|
|
6252
|
-
: hour + 12;
|
|
6253
6535
|
const startDateObj = dayjs(startTime).tz(timezone);
|
|
6254
6536
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
6537
|
+
// Convert 12-hour to 24-hour format
|
|
6538
|
+
let hour24 = hour;
|
|
6539
|
+
if (meridiem === 'am' && hour === 12)
|
|
6540
|
+
hour24 = 0;
|
|
6541
|
+
else if (meridiem === 'pm' && hour < 12)
|
|
6542
|
+
hour24 = hour + 12;
|
|
6255
6543
|
const currentDateTime = selectedDateObj
|
|
6256
6544
|
.hour(hour24)
|
|
6257
6545
|
.minute(minute)
|
|
@@ -6316,83 +6604,54 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6316
6604
|
if (!trimmedValue) {
|
|
6317
6605
|
return;
|
|
6318
6606
|
}
|
|
6319
|
-
//
|
|
6320
|
-
const
|
|
6321
|
-
|
|
6322
|
-
// Matches: 1-2 digits hour, optional colon, 2 digits minute, am/pm
|
|
6323
|
-
const pattern12HourWithMeridiem = /^(\d{1,2}):?(\d{2})(am|pm)$/;
|
|
6324
|
-
const match12Hour = normalized.match(pattern12HourWithMeridiem);
|
|
6607
|
+
// Parse formats like "1:30 PM", "1:30PM", "1:30 pm", "1:30pm"
|
|
6608
|
+
const timePattern12Hour = /^(\d{1,2}):(\d{1,2})\s*(am|pm|AM|PM)$/i;
|
|
6609
|
+
const match12Hour = trimmedValue.match(timePattern12Hour);
|
|
6325
6610
|
if (match12Hour) {
|
|
6326
6611
|
const parsedHour = parseInt(match12Hour[1], 10);
|
|
6327
6612
|
const parsedMinute = parseInt(match12Hour[2], 10);
|
|
6328
|
-
const parsedMeridiem = match12Hour[3];
|
|
6329
|
-
// Validate
|
|
6330
|
-
if (parsedHour
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6613
|
+
const parsedMeridiem = match12Hour[3].toLowerCase();
|
|
6614
|
+
// Validate ranges
|
|
6615
|
+
if (parsedHour >= 1 &&
|
|
6616
|
+
parsedHour <= 12 &&
|
|
6617
|
+
parsedMinute >= 0 &&
|
|
6618
|
+
parsedMinute <= 59) {
|
|
6619
|
+
setHour(parsedHour);
|
|
6620
|
+
setMinute(parsedMinute);
|
|
6621
|
+
setMeridiem(parsedMeridiem);
|
|
6622
|
+
onChange({
|
|
6623
|
+
hour: parsedHour,
|
|
6624
|
+
minute: parsedMinute,
|
|
6625
|
+
meridiem: parsedMeridiem,
|
|
6626
|
+
});
|
|
6339
6627
|
return;
|
|
6340
6628
|
}
|
|
6341
|
-
setHour(parsedHour);
|
|
6342
|
-
setMinute(parsedMinute);
|
|
6343
|
-
setMeridiem(parsedMeridiem);
|
|
6344
|
-
onChange({
|
|
6345
|
-
hour: parsedHour,
|
|
6346
|
-
minute: parsedMinute,
|
|
6347
|
-
meridiem: parsedMeridiem,
|
|
6348
|
-
});
|
|
6349
|
-
return;
|
|
6350
6629
|
}
|
|
6351
|
-
//
|
|
6352
|
-
|
|
6353
|
-
const
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
//
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
}
|
|
6376
|
-
else if (parsedHour === 12) {
|
|
6377
|
-
parsedHour = 12;
|
|
6378
|
-
parsedMeridiem = 'pm';
|
|
6379
|
-
}
|
|
6380
|
-
else if (parsedHour > 12) {
|
|
6381
|
-
parsedHour = parsedHour - 12;
|
|
6382
|
-
parsedMeridiem = 'pm';
|
|
6383
|
-
}
|
|
6384
|
-
else {
|
|
6385
|
-
parsedMeridiem = 'am';
|
|
6630
|
+
// Try to parse formats like "130pm" or "130 pm" (without colon)
|
|
6631
|
+
const timePatternNoColon = /^(\d{1,4})\s*(am|pm|AM|PM)$/i;
|
|
6632
|
+
const matchNoColon = trimmedValue.match(timePatternNoColon);
|
|
6633
|
+
if (matchNoColon) {
|
|
6634
|
+
const numbersOnly = matchNoColon[1];
|
|
6635
|
+
const parsedMeridiem = matchNoColon[2].toLowerCase();
|
|
6636
|
+
if (numbersOnly.length >= 3) {
|
|
6637
|
+
const parsedHour = parseInt(numbersOnly.slice(0, -2), 10);
|
|
6638
|
+
const parsedMinute = parseInt(numbersOnly.slice(-2), 10);
|
|
6639
|
+
// Validate ranges
|
|
6640
|
+
if (parsedHour >= 1 &&
|
|
6641
|
+
parsedHour <= 12 &&
|
|
6642
|
+
parsedMinute >= 0 &&
|
|
6643
|
+
parsedMinute <= 59) {
|
|
6644
|
+
setHour(parsedHour);
|
|
6645
|
+
setMinute(parsedMinute);
|
|
6646
|
+
setMeridiem(parsedMeridiem);
|
|
6647
|
+
onChange({
|
|
6648
|
+
hour: parsedHour,
|
|
6649
|
+
minute: parsedMinute,
|
|
6650
|
+
meridiem: parsedMeridiem,
|
|
6651
|
+
});
|
|
6652
|
+
return;
|
|
6653
|
+
}
|
|
6386
6654
|
}
|
|
6387
|
-
setHour(parsedHour);
|
|
6388
|
-
setMinute(parsedMinute);
|
|
6389
|
-
setMeridiem(parsedMeridiem);
|
|
6390
|
-
onChange({
|
|
6391
|
-
hour: parsedHour,
|
|
6392
|
-
minute: parsedMinute,
|
|
6393
|
-
meridiem: parsedMeridiem,
|
|
6394
|
-
});
|
|
6395
|
-
return;
|
|
6396
6655
|
}
|
|
6397
6656
|
// Parse failed, select first result
|
|
6398
6657
|
selectFirstResult();
|
|
@@ -6439,17 +6698,17 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6439
6698
|
e.currentTarget?.blur();
|
|
6440
6699
|
}
|
|
6441
6700
|
};
|
|
6442
|
-
return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { placeholder:
|
|
6443
|
-
}
|
|
6701
|
+
return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { placeholder: labels?.placeholder ?? 'hh:mm AM/PM', onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsxRuntime.jsx(react.Combobox.IndicatorGroup, { children: jsxRuntime.jsx(react.Combobox.Trigger, {}) })] }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [jsxRuntime.jsx(react.Combobox.Empty, { children: labels?.emptyMessage ?? 'No time found' }), collection.items.map((item) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsxRuntime.jsx(react.Text, { flex: 1, children: item.label }), item.durationText && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", children: jsxRuntime.jsx(react.Tag.Label, { children: item.durationText }) }))] }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", children: jsxRuntime.jsx(react.Tag.Label, { children: durationDiff }) })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(md.MdCancel, {}) }) })] }) }));
|
|
6702
|
+
};
|
|
6444
6703
|
|
|
6445
6704
|
dayjs.extend(timezone);
|
|
6446
6705
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
6447
6706
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
6448
|
-
const { timezone, insideDialog } = useSchemaContext();
|
|
6707
|
+
const { timezone, insideDialog, timePickerLabels } = useSchemaContext();
|
|
6449
6708
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
|
|
6450
6709
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6451
6710
|
const colLabel = `${prefix}${column}`;
|
|
6452
|
-
const formI18n = useFormI18n
|
|
6711
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6453
6712
|
const [open, setOpen] = React.useState(false);
|
|
6454
6713
|
const value = watch(colLabel);
|
|
6455
6714
|
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
@@ -6507,7 +6766,7 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
6507
6766
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6508
6767
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
6509
6768
|
setOpen(true);
|
|
6510
|
-
}, justifyContent: 'start', children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { maxH: "70vh", overflowY: "auto", children: jsxRuntime.jsx(react.Popover.Body, { overflow: "visible", children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange }) }) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { children: jsxRuntime.jsx(react.Popover.Body, { children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange }) }) }) }) }))] }) }));
|
|
6769
|
+
}, justifyContent: 'start', children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { maxH: "70vh", overflowY: "auto", children: jsxRuntime.jsx(react.Popover.Body, { overflow: "visible", children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, labels: timePickerLabels }) }) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { children: jsxRuntime.jsx(react.Popover.Body, { children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, labels: timePickerLabels }) }) }) }) }))] }) }));
|
|
6511
6770
|
};
|
|
6512
6771
|
|
|
6513
6772
|
dayjs.extend(utc);
|
|
@@ -6641,7 +6900,10 @@ dayjs.extend(utc);
|
|
|
6641
6900
|
dayjs.extend(timezone);
|
|
6642
6901
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
|
|
6643
6902
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6644
|
-
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true,
|
|
6903
|
+
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6904
|
+
placeholder: 'HH:mm:ss',
|
|
6905
|
+
emptyMessage: 'No time found',
|
|
6906
|
+
}, }) {
|
|
6645
6907
|
// Generate time options (every 15 minutes, seconds always 0)
|
|
6646
6908
|
const timeOptions = React.useMemo(() => {
|
|
6647
6909
|
const options = [];
|
|
@@ -6904,7 +7166,7 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6904
7166
|
e.currentTarget?.blur();
|
|
6905
7167
|
}
|
|
6906
7168
|
};
|
|
6907
|
-
return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { placeholder:
|
|
7169
|
+
return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { placeholder: labels.placeholder, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsxRuntime.jsx(react.Combobox.IndicatorGroup, { children: jsxRuntime.jsx(react.Combobox.Trigger, {}) })] }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [jsxRuntime.jsx(react.Combobox.Empty, { children: labels.emptyMessage }), collection.items.map((item) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsxRuntime.jsx(react.Text, { flex: 1, children: item.label }), item.durationText && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", children: jsxRuntime.jsx(react.Tag.Label, { children: item.durationText }) }))] }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", children: jsxRuntime.jsx(react.Tag.Label, { children: durationDiff }) })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(md.MdCancel, {}) }) })] }) }));
|
|
6908
7170
|
}
|
|
6909
7171
|
|
|
6910
7172
|
dayjs.extend(utc);
|
|
@@ -6927,7 +7189,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6927
7189
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
6928
7190
|
backButtonLabel: 'Back',
|
|
6929
7191
|
forwardButtonLabel: 'Next',
|
|
6930
|
-
}, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
7192
|
+
}, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
6931
7193
|
console.log('[DateTimePicker] Component initialized with props:', {
|
|
6932
7194
|
value,
|
|
6933
7195
|
format,
|
|
@@ -7373,7 +7635,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7373
7635
|
const dateObj = dayjs.tz(selectedDate, timezone);
|
|
7374
7636
|
return dateObj.isValid() ? dateObj.format('Z') : null;
|
|
7375
7637
|
}, [selectedDate, timezone]);
|
|
7376
|
-
return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4,
|
|
7638
|
+
return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4, children: [jsxRuntime.jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
|
|
7377
7639
|
if (date) {
|
|
7378
7640
|
handleDateChange(date);
|
|
7379
7641
|
}
|
|
@@ -7381,15 +7643,15 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7381
7643
|
setSelectedDate('');
|
|
7382
7644
|
onChange?.(undefined);
|
|
7383
7645
|
}
|
|
7384
|
-
}, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsxRuntime.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 })) : (jsxRuntime.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 })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsxRuntime.jsx(react.Icon, { as: fa6.FaTrash }) })] }), displayText && (jsxRuntime.jsxs(react.Flex, { gap: 2, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
|
|
7646
|
+
}, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsxRuntime.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 })) : (jsxRuntime.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 })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsxRuntime.jsx(react.Icon, { as: fa6.FaTrash }) })] }), displayText && (jsxRuntime.jsxs(react.Flex, { gap: 2, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
|
|
7385
7647
|
}
|
|
7386
7648
|
|
|
7387
7649
|
dayjs.extend(utc);
|
|
7388
7650
|
dayjs.extend(timezone);
|
|
7389
7651
|
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
7390
7652
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
7391
|
-
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
7392
|
-
const formI18n = useFormI18n
|
|
7653
|
+
const { timezone, dateTimePickerLabels, timePickerLabels, insideDialog } = useSchemaContext();
|
|
7654
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7393
7655
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
|
|
7394
7656
|
// with timezone
|
|
7395
7657
|
dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
|
|
@@ -7402,74 +7664,30 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7402
7664
|
: '';
|
|
7403
7665
|
const dateTimePickerLabelsConfig = {
|
|
7404
7666
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
formI18n.translate.t(`common.month_5`, {
|
|
7418
|
-
defaultValue: 'May',
|
|
7419
|
-
}),
|
|
7420
|
-
formI18n.translate.t(`common.month_6`, {
|
|
7421
|
-
defaultValue: 'June',
|
|
7422
|
-
}),
|
|
7423
|
-
formI18n.translate.t(`common.month_7`, {
|
|
7424
|
-
defaultValue: 'July',
|
|
7425
|
-
}),
|
|
7426
|
-
formI18n.translate.t(`common.month_8`, {
|
|
7427
|
-
defaultValue: 'August',
|
|
7428
|
-
}),
|
|
7429
|
-
formI18n.translate.t(`common.month_9`, {
|
|
7430
|
-
defaultValue: 'September',
|
|
7431
|
-
}),
|
|
7432
|
-
formI18n.translate.t(`common.month_10`, {
|
|
7433
|
-
defaultValue: 'October',
|
|
7434
|
-
}),
|
|
7435
|
-
formI18n.translate.t(`common.month_11`, {
|
|
7436
|
-
defaultValue: 'November',
|
|
7437
|
-
}),
|
|
7438
|
-
formI18n.translate.t(`common.month_12`, {
|
|
7439
|
-
defaultValue: 'December',
|
|
7440
|
-
}),
|
|
7667
|
+
'January',
|
|
7668
|
+
'February',
|
|
7669
|
+
'March',
|
|
7670
|
+
'April',
|
|
7671
|
+
'May',
|
|
7672
|
+
'June',
|
|
7673
|
+
'July',
|
|
7674
|
+
'August',
|
|
7675
|
+
'September',
|
|
7676
|
+
'October',
|
|
7677
|
+
'November',
|
|
7678
|
+
'December',
|
|
7441
7679
|
],
|
|
7442
7680
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
defaultValue: 'Tue',
|
|
7451
|
-
}),
|
|
7452
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
7453
|
-
defaultValue: 'Wed',
|
|
7454
|
-
}),
|
|
7455
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
7456
|
-
defaultValue: 'Thu',
|
|
7457
|
-
}),
|
|
7458
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
7459
|
-
defaultValue: 'Fri',
|
|
7460
|
-
}),
|
|
7461
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
7462
|
-
defaultValue: 'Sat',
|
|
7463
|
-
}),
|
|
7681
|
+
'Sun',
|
|
7682
|
+
'Mon',
|
|
7683
|
+
'Tue',
|
|
7684
|
+
'Wed',
|
|
7685
|
+
'Thu',
|
|
7686
|
+
'Fri',
|
|
7687
|
+
'Sat',
|
|
7464
7688
|
],
|
|
7465
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
7466
|
-
|
|
7467
|
-
defaultValue: 'Back',
|
|
7468
|
-
}),
|
|
7469
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
7470
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
7471
|
-
defaultValue: 'Forward',
|
|
7472
|
-
}),
|
|
7689
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
7690
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
7473
7691
|
};
|
|
7474
7692
|
const dateTimePickerContent = (jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
7475
7693
|
if (!date || date === null || date === undefined) {
|
|
@@ -7483,7 +7701,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7483
7701
|
else {
|
|
7484
7702
|
setValue(colLabel, undefined);
|
|
7485
7703
|
}
|
|
7486
|
-
}, timezone: timezone, labels: dateTimePickerLabelsConfig }));
|
|
7704
|
+
}, timezone: timezone, labels: dateTimePickerLabelsConfig, timePickerLabels: timePickerLabels }));
|
|
7487
7705
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7488
7706
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, autoFocus: false, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
7489
7707
|
setOpen(true);
|
|
@@ -7502,7 +7720,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7502
7720
|
}
|
|
7503
7721
|
if (variant === 'id-picker') {
|
|
7504
7722
|
idPickerSanityCheck(column, foreign_key);
|
|
7505
|
-
return jsxRuntime.jsx(
|
|
7723
|
+
return jsxRuntime.jsx(IdPickerSingle, { schema: colSchema, prefix, column });
|
|
7506
7724
|
}
|
|
7507
7725
|
if (format === 'date') {
|
|
7508
7726
|
return jsxRuntime.jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
@@ -7536,7 +7754,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7536
7754
|
if (type === 'array') {
|
|
7537
7755
|
if (variant === 'id-picker') {
|
|
7538
7756
|
idPickerSanityCheck(column, foreign_key);
|
|
7539
|
-
return
|
|
7757
|
+
return jsxRuntime.jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
|
|
7540
7758
|
}
|
|
7541
7759
|
if (variant === 'tag-picker') {
|
|
7542
7760
|
return jsxRuntime.jsx(TagPicker, { schema: colSchema, prefix, column });
|
|
@@ -7588,7 +7806,7 @@ const ArrayViewer = ({ schema, column, prefix }) => {
|
|
|
7588
7806
|
const { gridColumn = 'span 12', gridRow = 'span 1', required, items, } = schema;
|
|
7589
7807
|
const colLabel = `${prefix}${column}`;
|
|
7590
7808
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7591
|
-
const formI18n = useFormI18n
|
|
7809
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7592
7810
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
7593
7811
|
const values = watch(colLabel) ?? [];
|
|
7594
7812
|
return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: '1/span12', children: [formI18n.label(), isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: values.map((field, index) => (jsxRuntime.jsx(react.Flex, { flexFlow: 'column', bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: '2', borderRadius: 'md', borderWidth: 'thin', borderColor: {
|
|
@@ -7606,7 +7824,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
7606
7824
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7607
7825
|
const colLabel = `${prefix}${column}`;
|
|
7608
7826
|
const value = watch(colLabel);
|
|
7609
|
-
const formI18n = useFormI18n
|
|
7827
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7610
7828
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7611
7829
|
gridRow, children: [jsxRuntime.jsx(react.Text, { children: value ? formI18n.t('true') : formI18n.t('false') }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
7612
7830
|
};
|
|
@@ -7630,7 +7848,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7630
7848
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7631
7849
|
const colLabel = `${prefix}${column}`;
|
|
7632
7850
|
const selectedDate = watch(colLabel);
|
|
7633
|
-
const formI18n = useFormI18n
|
|
7851
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7634
7852
|
const displayDate = dayjs(selectedDate)
|
|
7635
7853
|
.tz(timezone)
|
|
7636
7854
|
.format(displayDateFormat);
|
|
@@ -7640,7 +7858,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7640
7858
|
|
|
7641
7859
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
7642
7860
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
7643
|
-
const formI18n = useFormI18n
|
|
7861
|
+
const formI18n = useFormI18n(column, prefix);
|
|
7644
7862
|
const { required } = schema;
|
|
7645
7863
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7646
7864
|
const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
|
|
@@ -7664,7 +7882,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7664
7882
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
|
|
7665
7883
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7666
7884
|
const currentFiles = (watch(column) ?? []);
|
|
7667
|
-
const formI18n = useFormI18n
|
|
7885
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7668
7886
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, display: 'grid', gridTemplateRows: 'auto 1fr auto', alignItems: 'stretch', children: jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file) => {
|
|
7669
7887
|
return (jsxRuntime.jsx(react.Card.Root, { variant: 'subtle', children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', children: [file.type.startsWith('image/') && (jsxRuntime.jsx(react.Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsxRuntime.jsx(react.Box, { children: file.name })] }) }, file.name));
|
|
7670
7888
|
}) }) }));
|
|
@@ -7672,7 +7890,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7672
7890
|
|
|
7673
7891
|
const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
7674
7892
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
7675
|
-
const { idMap,
|
|
7893
|
+
const { idMap, idPickerLabels, formButtonLabels } = useSchemaContext();
|
|
7676
7894
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
7677
7895
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7678
7896
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
@@ -7696,12 +7914,12 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
7696
7914
|
gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, children: watchIds.map((id) => {
|
|
7697
7915
|
const item = idMap[id];
|
|
7698
7916
|
if (item === undefined) {
|
|
7699
|
-
return (jsxRuntime.jsx(react.Text, { children:
|
|
7917
|
+
return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
7700
7918
|
}
|
|
7701
7919
|
return (jsxRuntime.jsx(Tag, { closable: true, children: renderDisplay
|
|
7702
7920
|
? renderDisplay(item)
|
|
7703
7921
|
: defaultRenderDisplay(item) }, id));
|
|
7704
|
-
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children:
|
|
7922
|
+
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formButtonLabels?.fieldRequired ?? formI18n.required() }))] }));
|
|
7705
7923
|
};
|
|
7706
7924
|
|
|
7707
7925
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
@@ -7710,7 +7928,7 @@ const NumberViewer = ({ schema, column, prefix, }) => {
|
|
|
7710
7928
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7711
7929
|
const colLabel = `${prefix}${column}`;
|
|
7712
7930
|
const value = watch(colLabel);
|
|
7713
|
-
const formI18n = useFormI18n
|
|
7931
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7714
7932
|
// Format the value for display if formatOptions are provided
|
|
7715
7933
|
const formatValue = (val) => {
|
|
7716
7934
|
if (val === undefined || val === null || val === '')
|
|
@@ -7736,7 +7954,7 @@ const ObjectViewer = ({ schema, column, prefix }) => {
|
|
|
7736
7954
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
7737
7955
|
const colLabel = `${prefix}${column}`;
|
|
7738
7956
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7739
|
-
const formI18n = useFormI18n
|
|
7957
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7740
7958
|
const { formState: { errors }, } = reactHookForm.useFormContext();
|
|
7741
7959
|
if (properties === undefined) {
|
|
7742
7960
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -7758,7 +7976,7 @@ const RecordViewer = ({ column, schema, prefix }) => {
|
|
|
7758
7976
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
7759
7977
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7760
7978
|
const entries = Object.entries(getValues(column) ?? {});
|
|
7761
|
-
const formI18n = useFormI18n
|
|
7979
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7762
7980
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn, gridRow, children: [entries.length === 0 ? (jsxRuntime.jsx(react.Text, { color: "gray.500", children: "No entries" })) : (jsxRuntime.jsx(react.Grid, { templateColumns: '1fr 1fr', gap: 2, children: entries.map(([key, value]) => {
|
|
7763
7981
|
return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr', gap: 2, children: [jsxRuntime.jsxs(react.Text, { fontWeight: "medium", children: [key, ":"] }), jsxRuntime.jsx(react.Text, { children: String(value ?? '') })] }, key));
|
|
7764
7982
|
}) })), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
@@ -7770,7 +7988,7 @@ const StringViewer = ({ column, schema, prefix, }) => {
|
|
|
7770
7988
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7771
7989
|
const colLabel = `${prefix}${column}`;
|
|
7772
7990
|
const value = watch(colLabel);
|
|
7773
|
-
const formI18n = useFormI18n
|
|
7991
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7774
7992
|
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', children: [jsxRuntime.jsx(react.Text, { children: value }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }) }));
|
|
7775
7993
|
};
|
|
7776
7994
|
|
|
@@ -7865,7 +8083,7 @@ const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
|
7865
8083
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7866
8084
|
const colLabel = `${prefix}${column}`;
|
|
7867
8085
|
const value = watch(colLabel);
|
|
7868
|
-
const formI18n = useFormI18n
|
|
8086
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7869
8087
|
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsxRuntime.jsx(react.Text, { whiteSpace: "pre-wrap", children: value }), ' ', errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }) }));
|
|
7870
8088
|
};
|
|
7871
8089
|
|
|
@@ -7876,7 +8094,7 @@ const TimeViewer = ({ column, schema, prefix }) => {
|
|
|
7876
8094
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7877
8095
|
const colLabel = `${prefix}${column}`;
|
|
7878
8096
|
const selectedDate = watch(colLabel);
|
|
7879
|
-
const formI18n = useFormI18n
|
|
8097
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7880
8098
|
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
7881
8099
|
.tz(timezone)
|
|
7882
8100
|
.isValid()
|
|
@@ -7893,7 +8111,7 @@ const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
|
7893
8111
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7894
8112
|
const colLabel = `${prefix}${column}`;
|
|
7895
8113
|
const selectedDate = watch(colLabel);
|
|
7896
|
-
const formI18n = useFormI18n
|
|
8114
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7897
8115
|
const displayDate = dayjs(selectedDate)
|
|
7898
8116
|
.tz(timezone)
|
|
7899
8117
|
.format(displayDateFormat);
|
|
@@ -7987,7 +8205,7 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
7987
8205
|
};
|
|
7988
8206
|
|
|
7989
8207
|
const SubmitButton = () => {
|
|
7990
|
-
const {
|
|
8208
|
+
const { setValidatedData, setIsError, setIsConfirming, requireConfirmation, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
7991
8209
|
const methods = reactHookForm.useFormContext();
|
|
7992
8210
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7993
8211
|
const onValid = (data) => {
|
|
@@ -8016,11 +8234,11 @@ const SubmitButton = () => {
|
|
|
8016
8234
|
};
|
|
8017
8235
|
return (jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8018
8236
|
methods.handleSubmit(onValid)();
|
|
8019
|
-
}, formNoValidate: true, children: formButtonLabels?.submit ??
|
|
8237
|
+
}, formNoValidate: true, children: formButtonLabels?.submit ?? 'Submit' }));
|
|
8020
8238
|
};
|
|
8021
8239
|
|
|
8022
8240
|
const FormBody = () => {
|
|
8023
|
-
const { schema, order, ignore, include,
|
|
8241
|
+
const { schema, order, ignore, include, isError, isSubmiting, isConfirming, setIsConfirming, validatedData, error, customErrorRenderer, displayConfig, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
8024
8242
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
8025
8243
|
const methods = reactHookForm.useFormContext();
|
|
8026
8244
|
const { properties } = schema;
|
|
@@ -8037,21 +8255,6 @@ const FormBody = () => {
|
|
|
8037
8255
|
ignore,
|
|
8038
8256
|
include,
|
|
8039
8257
|
});
|
|
8040
|
-
if (isSuccess) {
|
|
8041
|
-
const resetHandler = async () => {
|
|
8042
|
-
setIsError(false);
|
|
8043
|
-
setIsSubmiting(false);
|
|
8044
|
-
setIsSuccess(false);
|
|
8045
|
-
setIsConfirming(false);
|
|
8046
|
-
setValidatedData(undefined);
|
|
8047
|
-
const data = await getUpdatedData();
|
|
8048
|
-
methods.reset(data);
|
|
8049
|
-
};
|
|
8050
|
-
if (customSuccessRenderer) {
|
|
8051
|
-
return customSuccessRenderer(resetHandler);
|
|
8052
|
-
}
|
|
8053
|
-
return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Title, { children: translate.t('submit_success') }) })] }), jsxRuntime.jsx(react.Flex, { justifyContent: 'end', children: jsxRuntime.jsx(react.Button, { onClick: resetHandler, formNoValidate: true, children: formButtonLabels?.submitAgain ?? translate.t('submit_again') }) })] }));
|
|
8054
|
-
}
|
|
8055
8258
|
if (isConfirming) {
|
|
8056
8259
|
return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: 4, gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: 'repeat(12, max-content)', autoFlow: 'row', children: ordered.map((column) => {
|
|
8057
8260
|
return (jsxRuntime.jsx(ColumnViewer
|
|
@@ -8061,9 +8264,9 @@ const FormBody = () => {
|
|
|
8061
8264
|
properties: properties, prefix: ``, column }, `form-viewer-${column}`));
|
|
8062
8265
|
}) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: '2', children: [jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8063
8266
|
setIsConfirming(false);
|
|
8064
|
-
}, variant: 'subtle', children: formButtonLabels?.cancel ??
|
|
8267
|
+
}, variant: 'subtle', children: formButtonLabels?.cancel ?? 'Cancel' }), jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8065
8268
|
onFormSubmit(validatedData);
|
|
8066
|
-
}, children: formButtonLabels?.confirm ??
|
|
8269
|
+
}, children: formButtonLabels?.confirm ?? 'Confirm' })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8067
8270
|
}
|
|
8068
8271
|
return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
|
|
8069
8272
|
return (jsxRuntime.jsx(ColumnRenderer
|
|
@@ -8073,12 +8276,12 @@ const FormBody = () => {
|
|
|
8073
8276
|
properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
|
|
8074
8277
|
}) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8075
8278
|
methods.reset();
|
|
8076
|
-
}, variant: 'subtle', children: formButtonLabels?.reset ??
|
|
8279
|
+
}, variant: 'subtle', children: formButtonLabels?.reset ?? 'Reset' })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8077
8280
|
};
|
|
8078
8281
|
|
|
8079
8282
|
const FormTitle = () => {
|
|
8080
|
-
const {
|
|
8081
|
-
return jsxRuntime.jsx(react.Heading, { children:
|
|
8283
|
+
const { schema } = useSchemaContext();
|
|
8284
|
+
return jsxRuntime.jsx(react.Heading, { children: schema.title ?? 'Form' });
|
|
8082
8285
|
};
|
|
8083
8286
|
|
|
8084
8287
|
const DefaultForm = ({ formConfig, }) => {
|
|
@@ -8086,7 +8289,9 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
8086
8289
|
return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
|
|
8087
8290
|
};
|
|
8088
8291
|
|
|
8089
|
-
const useForm = ({ preLoadedValues, keyPrefix
|
|
8292
|
+
const useForm = ({ preLoadedValues, keyPrefix: _keyPrefix, // Deprecated: kept for backward compatibility
|
|
8293
|
+
namespace: _namespace, // Deprecated: kept for backward compatibility
|
|
8294
|
+
schema, }) => {
|
|
8090
8295
|
const form = reactHookForm.useForm({
|
|
8091
8296
|
values: preLoadedValues,
|
|
8092
8297
|
resolver: schema ? ajvResolver(schema) : undefined,
|
|
@@ -8094,12 +8299,16 @@ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
|
|
|
8094
8299
|
reValidateMode: 'onBlur',
|
|
8095
8300
|
});
|
|
8096
8301
|
const [idMap, setIdMap] = React.useState({});
|
|
8097
|
-
|
|
8302
|
+
// Fallback translate object - returns key as-is (no i18n required)
|
|
8303
|
+
const translate = {
|
|
8304
|
+
t: (key) => key,
|
|
8305
|
+
ready: true,
|
|
8306
|
+
};
|
|
8098
8307
|
return {
|
|
8099
8308
|
form,
|
|
8100
8309
|
idMap,
|
|
8101
8310
|
setIdMap,
|
|
8102
|
-
translate,
|
|
8311
|
+
translate, // Components prefer label objects over translate
|
|
8103
8312
|
};
|
|
8104
8313
|
};
|
|
8105
8314
|
|
|
@@ -8427,6 +8636,21 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
|
8427
8636
|
})] }));
|
|
8428
8637
|
};
|
|
8429
8638
|
|
|
8639
|
+
const MobileTableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsxRuntime.jsx(jsxRuntime.Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsxRuntime.jsx(jsxRuntime.Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
|
|
8640
|
+
const { tableLabel, table } = useDataTableContext();
|
|
8641
|
+
const { hasErrorText } = tableLabel;
|
|
8642
|
+
return (jsxRuntime.jsxs(react.Grid, { templateRows: 'auto 1fr auto', width: fitTableWidth ? 'fit-content' : '100%', height: fitTableHeight ? 'fit-content' : '100%', gap: 2, padding: 2, ...gridProps, children: [jsxRuntime.jsxs(react.Stack, { gap: 2, children: [jsxRuntime.jsxs(react.Flex, { justifyContent: 'space-between', alignItems: 'center', gap: 2, children: [jsxRuntime.jsxs(react.Flex, { gap: 1, alignItems: 'center', children: [showView && jsxRuntime.jsx(ViewDialog, { icon: jsxRuntime.jsx(md.MdOutlineViewColumn, {}) }), loading && jsxRuntime.jsx(react.Spinner, { size: 'sm' }), hasError && (jsxRuntime.jsx(Tooltip, { content: hasErrorText, children: jsxRuntime.jsx(react.Icon, { as: bs.BsExclamationCircleFill, color: 'red.400' }) }))] }), jsxRuntime.jsxs(react.Flex, { gap: 1, alignItems: 'center', children: [showGlobalFilter && jsxRuntime.jsx(GlobalFilter, {}), showFilter && jsxRuntime.jsx(FilterDialog, {}), showReload && jsxRuntime.jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsxRuntime.jsx(react.Stack, { gap: 2, children: filterTagsOptions.map((option) => {
|
|
8643
|
+
const { column, options } = option;
|
|
8644
|
+
const tableColumn = table.getColumn(column);
|
|
8645
|
+
return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: 1, width: '100%', children: [tableColumn?.columnDef.meta?.displayName && (jsxRuntime.jsx(react.Text, { fontSize: 'sm', fontWeight: 'medium', children: tableColumn?.columnDef.meta?.displayName })), jsxRuntime.jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
|
|
8646
|
+
if (tags.length === 0) {
|
|
8647
|
+
return tableColumn?.setFilterValue(undefined);
|
|
8648
|
+
}
|
|
8649
|
+
tableColumn?.setFilterValue(tags);
|
|
8650
|
+
} })] }, column));
|
|
8651
|
+
}) })), showFilterTags && (jsxRuntime.jsx(react.Box, { width: '100%', children: jsxRuntime.jsx(TableFilterTags, {}) }))] }), jsxRuntime.jsx(react.Box, { overflow: 'auto', width: '100%', bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, borderRadius: 'md', padding: 1, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxRuntime.jsxs(react.Stack, { gap: 2, width: '100%', children: [(showPageSizeControl || showPageCountText) && (jsxRuntime.jsxs(react.Flex, { justifyContent: 'space-between', alignItems: 'center', gap: 2, flexWrap: 'wrap', children: [showPageSizeControl && jsxRuntime.jsx(PageSizeControl, {}), showPageCountText && jsxRuntime.jsx(RowCountText, {})] })), showPagination && (jsxRuntime.jsx(react.Flex, { justifyContent: 'center', width: '100%', children: jsxRuntime.jsx(Pagination, {}) }))] }))] }));
|
|
8652
|
+
};
|
|
8653
|
+
|
|
8430
8654
|
const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
|
|
8431
8655
|
'use no memo';
|
|
8432
8656
|
const { table } = useDataTableContext();
|
|
@@ -8486,7 +8710,68 @@ const TableRowSelectorSkeleton = () => {
|
|
|
8486
8710
|
bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsxRuntime.jsx(react.Skeleton, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }) }));
|
|
8487
8711
|
};
|
|
8488
8712
|
|
|
8713
|
+
const MobileTableDisplay = ({ showSelector = false, isLoading = false, }) => {
|
|
8714
|
+
const { table, rowSelection, setRowSelection } = useDataTableContext();
|
|
8715
|
+
if (isLoading) {
|
|
8716
|
+
return jsxRuntime.jsx(MobileTableSkeleton, { showSelector: showSelector });
|
|
8717
|
+
}
|
|
8718
|
+
return (jsxRuntime.jsx(react.Stack, { gap: 4, padding: 2, children: table.getRowModel().rows.map((row) => {
|
|
8719
|
+
return (jsxRuntime.jsx(react.Card.Root, { width: "100%", children: jsxRuntime.jsxs(react.Card.Body, { padding: 4, children: [showSelector && (jsxRuntime.jsx(react.Flex, { marginBottom: 3, children: jsxRuntime.jsx(Checkbox, { checked: isRowSelected(row.id, rowSelection),
|
|
8720
|
+
disabled: !canRowSelect(row),
|
|
8721
|
+
onCheckedChange: createRowToggleHandler(row, rowSelection, setRowSelection) }) })), jsxRuntime.jsx(react.Stack, { gap: 3, children: row.getVisibleCells().map((cell) => {
|
|
8722
|
+
const displayName = cell.column.columnDef.meta?.displayName ?? cell.column.id;
|
|
8723
|
+
return (jsxRuntime.jsxs(react.Box, { children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "bold", color: { base: 'gray.600', _dark: 'gray.400' }, marginBottom: 1, children: displayName }), jsxRuntime.jsx(react.Box, { color: { base: 'gray.900', _dark: 'gray.100' }, fontSize: "sm", children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext()) })] }, `mobile-table-cell-${cell.id}`));
|
|
8724
|
+
}) })] }) }, `mobile-table-card-${row.id}`));
|
|
8725
|
+
}) }));
|
|
8726
|
+
};
|
|
8727
|
+
const MobileTableSkeleton = ({ showSelector = false, }) => {
|
|
8728
|
+
const { table } = useDataTableContext();
|
|
8729
|
+
const pageSize = table.getState().pagination.pageSize;
|
|
8730
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
8731
|
+
return (jsxRuntime.jsx(react.Stack, { gap: 4, padding: 2, children: Array.from({ length: pageSize }).map((_, rowIndex) => {
|
|
8732
|
+
return (jsxRuntime.jsx(react.Card.Root, { width: "100%", children: jsxRuntime.jsxs(react.Card.Body, { padding: 4, children: [showSelector && (jsxRuntime.jsx(react.Flex, { marginBottom: 3, children: jsxRuntime.jsx(react.Box, { width: "20px", height: "20px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "md" }) })), jsxRuntime.jsx(react.Stack, { gap: 3, children: visibleColumns.map((column) => {
|
|
8733
|
+
return (jsxRuntime.jsxs(react.Box, { children: [jsxRuntime.jsx(react.Box, { width: "40%", height: "16px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "sm", marginBottom: 2 }), jsxRuntime.jsx(react.Box, { width: "80%", height: "20px", bg: { base: 'gray.200', _dark: 'gray.700' }, borderRadius: "sm" })] }, `mobile-skeleton-cell-${column.id}`));
|
|
8734
|
+
}) })] }) }, `mobile-skeleton-${rowIndex}`));
|
|
8735
|
+
}) }));
|
|
8736
|
+
};
|
|
8737
|
+
|
|
8738
|
+
/**
|
|
8739
|
+
* Hook to detect if the current window width is mobile (< 768px)
|
|
8740
|
+
* @param breakpoint - The breakpoint in pixels to consider as mobile (default: 768)
|
|
8741
|
+
* @returns boolean indicating if the window is mobile
|
|
8742
|
+
*/
|
|
8743
|
+
const useIsMobile = (breakpoint = 768) => {
|
|
8744
|
+
const [isMobile, setIsMobile] = React.useState(() => {
|
|
8745
|
+
if (typeof window === 'undefined')
|
|
8746
|
+
return false;
|
|
8747
|
+
return window.innerWidth < breakpoint;
|
|
8748
|
+
});
|
|
8749
|
+
React.useEffect(() => {
|
|
8750
|
+
if (typeof window === 'undefined')
|
|
8751
|
+
return;
|
|
8752
|
+
const handleResize = () => {
|
|
8753
|
+
setIsMobile(window.innerWidth < breakpoint);
|
|
8754
|
+
};
|
|
8755
|
+
// Set initial value
|
|
8756
|
+
handleResize();
|
|
8757
|
+
// Add event listener
|
|
8758
|
+
window.addEventListener('resize', handleResize);
|
|
8759
|
+
// Cleanup
|
|
8760
|
+
return () => {
|
|
8761
|
+
window.removeEventListener('resize', handleResize);
|
|
8762
|
+
};
|
|
8763
|
+
}, [breakpoint]);
|
|
8764
|
+
return isMobile;
|
|
8765
|
+
};
|
|
8766
|
+
|
|
8489
8767
|
const DefaultTable = ({ showFooter = false, showHeader = true, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = 'greedy', isLoading = false, }) => {
|
|
8768
|
+
const isMobile = useIsMobile();
|
|
8769
|
+
// Early return for mobile display
|
|
8770
|
+
if (isMobile) {
|
|
8771
|
+
return (jsxRuntime.jsx(MobileTableControls, { ...controlProps, children: jsxRuntime.jsx(MobileTableDisplay, { showSelector: tableHeaderProps.showSelector ??
|
|
8772
|
+
tableBodyProps.showSelector ??
|
|
8773
|
+
false, isLoading: isLoading }) }));
|
|
8774
|
+
}
|
|
8490
8775
|
const isGreedy = variant === 'greedy';
|
|
8491
8776
|
const canResize = !isGreedy;
|
|
8492
8777
|
const bodyComponent = isLoading ? (jsxRuntime.jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: canResize })) : (jsxRuntime.jsx(TableBody, { ...tableBodyProps, canResize: canResize }));
|
|
@@ -8587,6 +8872,290 @@ const DataDisplay = ({ variant = '' }) => {
|
|
|
8587
8872
|
}) }));
|
|
8588
8873
|
};
|
|
8589
8874
|
|
|
8875
|
+
// Helper function to normalize date
|
|
8876
|
+
function normalizeDate(value) {
|
|
8877
|
+
if (!value)
|
|
8878
|
+
return null;
|
|
8879
|
+
if (value instanceof Date)
|
|
8880
|
+
return value;
|
|
8881
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
8882
|
+
const date = dayjs(value).toDate();
|
|
8883
|
+
return isNaN(date.getTime()) ? null : date;
|
|
8884
|
+
}
|
|
8885
|
+
return null;
|
|
8886
|
+
}
|
|
8887
|
+
// Component to conditionally render event title based on available width
|
|
8888
|
+
function ResponsiveEventTitle({ title, placeholder, minWidth, minChars, cellRef, }) {
|
|
8889
|
+
const [truncatedText, setTruncatedText] = React.useState('');
|
|
8890
|
+
const measureRef = React.useRef(null);
|
|
8891
|
+
React.useEffect(() => {
|
|
8892
|
+
const calculateTruncatedText = () => {
|
|
8893
|
+
if (!cellRef.current || !measureRef.current || !title) {
|
|
8894
|
+
setTruncatedText(title || 'Event');
|
|
8895
|
+
return;
|
|
8896
|
+
}
|
|
8897
|
+
const cellWidth = cellRef.current.clientWidth;
|
|
8898
|
+
// Account for padding (approximately 8px on each side)
|
|
8899
|
+
const availableWidth = cellWidth - 16;
|
|
8900
|
+
// If cell is too narrow, calculate how many characters can fit
|
|
8901
|
+
if (availableWidth < minWidth) {
|
|
8902
|
+
// Measure text width using canvas
|
|
8903
|
+
const canvas = document.createElement('canvas');
|
|
8904
|
+
const context = canvas.getContext('2d');
|
|
8905
|
+
if (!context) {
|
|
8906
|
+
setTruncatedText(placeholder);
|
|
8907
|
+
return;
|
|
8908
|
+
}
|
|
8909
|
+
// Get computed font style from the element
|
|
8910
|
+
const computedStyle = window.getComputedStyle(measureRef.current);
|
|
8911
|
+
context.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;
|
|
8912
|
+
const ellipsisWidth = context.measureText('...').width;
|
|
8913
|
+
const maxWidth = availableWidth - ellipsisWidth;
|
|
8914
|
+
// Try to show at least minChars characters before ellipsis
|
|
8915
|
+
let truncated = '';
|
|
8916
|
+
let charCount = 0;
|
|
8917
|
+
// Calculate how many characters can fit
|
|
8918
|
+
for (let i = 0; i < Math.min(title.length, 50); i++) {
|
|
8919
|
+
const testText = title.substring(0, i + 1);
|
|
8920
|
+
const textWidth = context.measureText(testText).width;
|
|
8921
|
+
if (textWidth <= maxWidth) {
|
|
8922
|
+
truncated = testText;
|
|
8923
|
+
charCount = i + 1;
|
|
8924
|
+
}
|
|
8925
|
+
else {
|
|
8926
|
+
break;
|
|
8927
|
+
}
|
|
8928
|
+
}
|
|
8929
|
+
// Ensure we show at least minChars characters if possible
|
|
8930
|
+
if (charCount < minChars && title.length >= minChars) {
|
|
8931
|
+
truncated = title.substring(0, minChars);
|
|
8932
|
+
}
|
|
8933
|
+
else if (charCount === 0 && title.length >= 1) {
|
|
8934
|
+
truncated = title.substring(0, 1);
|
|
8935
|
+
}
|
|
8936
|
+
// Only show ellipsis if we have at least minChars characters
|
|
8937
|
+
if (truncated && truncated.length >= minChars) {
|
|
8938
|
+
setTruncatedText(`${truncated}...`);
|
|
8939
|
+
}
|
|
8940
|
+
else {
|
|
8941
|
+
setTruncatedText(placeholder);
|
|
8942
|
+
}
|
|
8943
|
+
}
|
|
8944
|
+
else {
|
|
8945
|
+
// Full width available, show full title
|
|
8946
|
+
setTruncatedText(title);
|
|
8947
|
+
}
|
|
8948
|
+
};
|
|
8949
|
+
calculateTruncatedText();
|
|
8950
|
+
const resizeObserver = new ResizeObserver(calculateTruncatedText);
|
|
8951
|
+
if (cellRef.current) {
|
|
8952
|
+
resizeObserver.observe(cellRef.current);
|
|
8953
|
+
}
|
|
8954
|
+
// Also check on window resize
|
|
8955
|
+
window.addEventListener('resize', calculateTruncatedText);
|
|
8956
|
+
return () => {
|
|
8957
|
+
resizeObserver.disconnect();
|
|
8958
|
+
window.removeEventListener('resize', calculateTruncatedText);
|
|
8959
|
+
};
|
|
8960
|
+
}, [cellRef, minWidth, title, placeholder]);
|
|
8961
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { ref: measureRef, style: {
|
|
8962
|
+
visibility: 'hidden',
|
|
8963
|
+
position: 'absolute',
|
|
8964
|
+
whiteSpace: 'nowrap',
|
|
8965
|
+
}, children: title || 'Event' }), truncatedText || title || 'Event'] }));
|
|
8966
|
+
}
|
|
8967
|
+
function CalendarDisplay({ dateColumn, getDate, getEventTitle, getEventColor, renderEvent, firstDayOfWeek = 0, showOutsideDays = true, monthsToDisplay = 1, labels = {
|
|
8968
|
+
monthNamesShort: [
|
|
8969
|
+
'Jan',
|
|
8970
|
+
'Feb',
|
|
8971
|
+
'Mar',
|
|
8972
|
+
'Apr',
|
|
8973
|
+
'May',
|
|
8974
|
+
'Jun',
|
|
8975
|
+
'Jul',
|
|
8976
|
+
'Aug',
|
|
8977
|
+
'Sep',
|
|
8978
|
+
'Oct',
|
|
8979
|
+
'Nov',
|
|
8980
|
+
'Dec',
|
|
8981
|
+
],
|
|
8982
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
8983
|
+
backButtonLabel: 'Back',
|
|
8984
|
+
forwardButtonLabel: 'Next',
|
|
8985
|
+
}, onDateClick, onEventClick, maxEventsPerDay = 3, colorPalette = 'blue', eventPlaceholder = '...', minEventWidth = 80, minCharsBeforeEllipsis = 2, }) {
|
|
8986
|
+
const { data, table } = useDataTableContext();
|
|
8987
|
+
// Map table data to events
|
|
8988
|
+
const events = React.useMemo(() => {
|
|
8989
|
+
return data
|
|
8990
|
+
.map((row) => {
|
|
8991
|
+
let dateValue;
|
|
8992
|
+
if (getDate) {
|
|
8993
|
+
dateValue = getDate(row);
|
|
8994
|
+
}
|
|
8995
|
+
else {
|
|
8996
|
+
// Try to get date from column
|
|
8997
|
+
const rowData = table
|
|
8998
|
+
.getRowModel()
|
|
8999
|
+
.rows.find((r) => r.original === row);
|
|
9000
|
+
if (rowData) {
|
|
9001
|
+
const cell = rowData.getAllCells().find((c) => {
|
|
9002
|
+
const colId = c.column.id;
|
|
9003
|
+
const accessorKey = c.column.columnDef.accessorKey;
|
|
9004
|
+
return colId === dateColumn || accessorKey === dateColumn;
|
|
9005
|
+
});
|
|
9006
|
+
dateValue = cell?.getValue();
|
|
9007
|
+
}
|
|
9008
|
+
}
|
|
9009
|
+
const date = normalizeDate(dateValue);
|
|
9010
|
+
if (!date)
|
|
9011
|
+
return null;
|
|
9012
|
+
let title;
|
|
9013
|
+
if (getEventTitle) {
|
|
9014
|
+
title = getEventTitle(row);
|
|
9015
|
+
}
|
|
9016
|
+
else {
|
|
9017
|
+
// Use first column's value as title
|
|
9018
|
+
const rowData = table
|
|
9019
|
+
.getRowModel()
|
|
9020
|
+
.rows.find((r) => r.original === row);
|
|
9021
|
+
if (rowData) {
|
|
9022
|
+
const firstCell = rowData.getAllCells()[0];
|
|
9023
|
+
title = String(firstCell?.getValue() ?? '');
|
|
9024
|
+
}
|
|
9025
|
+
}
|
|
9026
|
+
const color = getEventColor?.(row);
|
|
9027
|
+
return {
|
|
9028
|
+
data: row,
|
|
9029
|
+
date,
|
|
9030
|
+
title,
|
|
9031
|
+
color,
|
|
9032
|
+
};
|
|
9033
|
+
})
|
|
9034
|
+
.filter((event) => event !== null);
|
|
9035
|
+
}, [data, table, dateColumn, getDate, getEventTitle, getEventColor]);
|
|
9036
|
+
// Group events by date
|
|
9037
|
+
const eventsByDate = React.useMemo(() => {
|
|
9038
|
+
const map = new Map();
|
|
9039
|
+
events.forEach((event) => {
|
|
9040
|
+
const dateKey = `${event.date.getFullYear()}-${event.date.getMonth()}-${event.date.getDate()}`;
|
|
9041
|
+
if (!map.has(dateKey)) {
|
|
9042
|
+
map.set(dateKey, []);
|
|
9043
|
+
}
|
|
9044
|
+
map.get(dateKey).push(event);
|
|
9045
|
+
});
|
|
9046
|
+
return map;
|
|
9047
|
+
}, [events]);
|
|
9048
|
+
// Get events for a specific date
|
|
9049
|
+
const getEventsForDate = React.useCallback((date) => {
|
|
9050
|
+
const dateKey = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
|
9051
|
+
return eventsByDate.get(dateKey) ?? [];
|
|
9052
|
+
}, [eventsByDate]);
|
|
9053
|
+
const calendarData = useCalendar({
|
|
9054
|
+
firstDayOfWeek,
|
|
9055
|
+
showOutsideDays,
|
|
9056
|
+
monthsToDisplay,
|
|
9057
|
+
});
|
|
9058
|
+
const getDateProps = React.useCallback((props) => {
|
|
9059
|
+
const dateEvents = getEventsForDate(props.dateObj.date);
|
|
9060
|
+
const baseProps = calendarData.getDateProps({ dateObj: props.dateObj });
|
|
9061
|
+
return {
|
|
9062
|
+
...baseProps,
|
|
9063
|
+
onClick: () => {
|
|
9064
|
+
baseProps.onClick?.();
|
|
9065
|
+
if (onDateClick) {
|
|
9066
|
+
onDateClick(props.dateObj.date, dateEvents);
|
|
9067
|
+
}
|
|
9068
|
+
},
|
|
9069
|
+
};
|
|
9070
|
+
}, [calendarData, getEventsForDate, onDateClick]);
|
|
9071
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
9072
|
+
if (!calendarData.calendars.length) {
|
|
9073
|
+
return null;
|
|
9074
|
+
}
|
|
9075
|
+
return (jsxRuntime.jsxs(react.VStack, { gap: 4, width: "100%", children: [jsxRuntime.jsxs(react.HStack, { gap: 2, justifyContent: "center", children: [jsxRuntime.jsx(react.Button, { variant: "ghost", ...calendarData.getBackProps({
|
|
9076
|
+
calendars: calendarData.calendars,
|
|
9077
|
+
offset: 12,
|
|
9078
|
+
}), children: '<<' }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...calendarData.getBackProps({ calendars: calendarData.calendars }), children: backButtonLabel }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9079
|
+
calendars: calendarData.calendars,
|
|
9080
|
+
}), children: forwardButtonLabel }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9081
|
+
calendars: calendarData.calendars,
|
|
9082
|
+
offset: 12,
|
|
9083
|
+
}), children: '>>' })] }), jsxRuntime.jsx(react.Grid, { templateColumns: {
|
|
9084
|
+
base: '1fr',
|
|
9085
|
+
md: monthsToDisplay >= 2 ? 'repeat(2, 1fr)' : '1fr',
|
|
9086
|
+
lg: monthsToDisplay >= 3
|
|
9087
|
+
? 'repeat(3, 1fr)'
|
|
9088
|
+
: monthsToDisplay === 2
|
|
9089
|
+
? 'repeat(2, 1fr)'
|
|
9090
|
+
: '1fr',
|
|
9091
|
+
xl: `repeat(${Math.min(monthsToDisplay, 4)}, 1fr)`,
|
|
9092
|
+
}, gap: { base: 4, md: 6 }, width: "100%", justifyContent: "center", children: calendarData.calendars.map((calendar) => (jsxRuntime.jsxs(react.VStack, { gap: 2, alignItems: "stretch", children: [jsxRuntime.jsxs(react.Text, { textAlign: "center", fontSize: { base: 'md', md: 'lg' }, fontWeight: "semibold", children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(7, 1fr)", gap: { base: 0.5, md: 1 }, children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
9093
|
+
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
9094
|
+
return (jsxRuntime.jsx(react.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}`));
|
|
9095
|
+
}) }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(7, 1fr)", gap: { base: 0.5, md: 1 }, children: calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
9096
|
+
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
9097
|
+
if (!dateObj) {
|
|
9098
|
+
return jsxRuntime.jsx(react.Box, {}, key);
|
|
9099
|
+
}
|
|
9100
|
+
const { date, today, isCurrentMonth } = dateObj;
|
|
9101
|
+
const dateEvents = getEventsForDate(date);
|
|
9102
|
+
const cellRef = React.useRef(null);
|
|
9103
|
+
return (jsxRuntime.jsxs(react.VStack, { ref: cellRef, gap: { base: 0.25, md: 0.5 }, alignItems: "stretch", minHeight: { base: '60px', md: '80px', lg: '100px' }, borderWidth: "1px", borderColor: {
|
|
9104
|
+
base: today ? `${colorPalette}.300` : 'gray.200',
|
|
9105
|
+
_dark: today ? `${colorPalette}.700` : 'gray.700',
|
|
9106
|
+
}, borderRadius: { base: 'sm', md: 'md' }, padding: { base: 0.5, md: 1 }, bgColor: {
|
|
9107
|
+
base: today ? `${colorPalette}.50` : 'white',
|
|
9108
|
+
_dark: today ? `${colorPalette}.950` : 'gray.900',
|
|
9109
|
+
}, opacity: isCurrentMonth ? 1 : 0.5, ...getDateProps({ dateObj }), cursor: onDateClick ? 'pointer' : 'default', _hover: onDateClick
|
|
9110
|
+
? {
|
|
9111
|
+
bgColor: {
|
|
9112
|
+
base: `${colorPalette}.100`,
|
|
9113
|
+
_dark: `${colorPalette}.900`,
|
|
9114
|
+
},
|
|
9115
|
+
}
|
|
9116
|
+
: {}, children: [jsxRuntime.jsx(react.Text, { fontSize: { base: 'xs', md: 'sm' }, fontWeight: today ? 'bold' : 'normal', color: {
|
|
9117
|
+
base: today ? `${colorPalette}.700` : 'gray.700',
|
|
9118
|
+
_dark: today ? `${colorPalette}.300` : 'gray.300',
|
|
9119
|
+
}, textAlign: "right", paddingRight: { base: 0.5, md: 1 }, children: date.getDate() }), jsxRuntime.jsxs(react.VStack, { gap: { base: 0.25, md: 0.5 }, alignItems: "stretch", flex: 1, overflow: "hidden", children: [dateEvents
|
|
9120
|
+
.slice(0, maxEventsPerDay)
|
|
9121
|
+
.map((event, eventIndex) => {
|
|
9122
|
+
const eventContent = renderEvent ? (renderEvent(event)) : (jsxRuntime.jsx(react.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: {
|
|
9123
|
+
base: event.color
|
|
9124
|
+
? `${event.color}.100`
|
|
9125
|
+
: `${colorPalette}.100`,
|
|
9126
|
+
_dark: event.color
|
|
9127
|
+
? `${event.color}.900`
|
|
9128
|
+
: `${colorPalette}.900`,
|
|
9129
|
+
}, color: {
|
|
9130
|
+
base: event.color
|
|
9131
|
+
? `${event.color}.800`
|
|
9132
|
+
: `${colorPalette}.800`,
|
|
9133
|
+
_dark: event.color
|
|
9134
|
+
? `${event.color}.200`
|
|
9135
|
+
: `${colorPalette}.200`,
|
|
9136
|
+
}, onClick: (e) => {
|
|
9137
|
+
e.stopPropagation();
|
|
9138
|
+
if (onEventClick) {
|
|
9139
|
+
onEventClick(event);
|
|
9140
|
+
}
|
|
9141
|
+
}, cursor: onEventClick ? 'pointer' : 'default', _hover: onEventClick
|
|
9142
|
+
? {
|
|
9143
|
+
opacity: 0.8,
|
|
9144
|
+
}
|
|
9145
|
+
: {}, children: jsxRuntime.jsx(ResponsiveEventTitle, { title: event.title, placeholder: eventPlaceholder, minWidth: minEventWidth, minChars: minCharsBeforeEllipsis, cellRef: cellRef }) }, eventIndex));
|
|
9146
|
+
return (jsxRuntime.jsx(react.Box, { onClick: (e) => e.stopPropagation(), children: eventContent }, eventIndex));
|
|
9147
|
+
}), dateEvents.length > maxEventsPerDay && (jsxRuntime.jsxs(react.Text, { fontSize: "xs", color: {
|
|
9148
|
+
base: `${colorPalette}.600`,
|
|
9149
|
+
_dark: `${colorPalette}.400`,
|
|
9150
|
+
}, paddingX: 1, onClick: (e) => {
|
|
9151
|
+
e.stopPropagation();
|
|
9152
|
+
if (onDateClick) {
|
|
9153
|
+
onDateClick(date, dateEvents);
|
|
9154
|
+
}
|
|
9155
|
+
}, cursor: onDateClick ? 'pointer' : 'default', children: ["+", dateEvents.length - maxEventsPerDay, " more"] }))] })] }, key));
|
|
9156
|
+
})) })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
9157
|
+
}
|
|
9158
|
+
|
|
8590
9159
|
// Reference: https://tanstack.com/table/latest/docs/framework/react/examples/custom-features
|
|
8591
9160
|
// TypeScript setup for our new feature with all of the same type-safety as stock TanStack Table features
|
|
8592
9161
|
// end of TS setup!
|
|
@@ -8687,7 +9256,7 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
|
|
|
8687
9256
|
*
|
|
8688
9257
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8689
9258
|
*/
|
|
8690
|
-
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,
|
|
9259
|
+
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 = {
|
|
8691
9260
|
view: 'View',
|
|
8692
9261
|
edit: 'Edit',
|
|
8693
9262
|
filterButtonText: 'Filter',
|
|
@@ -8698,7 +9267,7 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8698
9267
|
reloadButtonText: 'Reload',
|
|
8699
9268
|
resetSelection: 'Reset Selection',
|
|
8700
9269
|
resetSorting: 'Reset Sorting',
|
|
8701
|
-
rowCountText: '
|
|
9270
|
+
rowCountText: '',
|
|
8702
9271
|
hasErrorText: 'Has Error',
|
|
8703
9272
|
globalFilterPlaceholder: 'Search',
|
|
8704
9273
|
trueLabel: 'True',
|
|
@@ -8755,7 +9324,6 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8755
9324
|
globalFilter,
|
|
8756
9325
|
setGlobalFilter,
|
|
8757
9326
|
type: 'client',
|
|
8758
|
-
translate,
|
|
8759
9327
|
columns: columns,
|
|
8760
9328
|
sorting,
|
|
8761
9329
|
setSorting,
|
|
@@ -8787,22 +9355,22 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8787
9355
|
*
|
|
8788
9356
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8789
9357
|
*/
|
|
8790
|
-
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,
|
|
8791
|
-
view:
|
|
8792
|
-
edit:
|
|
8793
|
-
filterButtonText:
|
|
8794
|
-
filterTitle:
|
|
8795
|
-
filterReset:
|
|
8796
|
-
filterClose:
|
|
8797
|
-
reloadTooltip:
|
|
8798
|
-
reloadButtonText:
|
|
8799
|
-
resetSelection:
|
|
8800
|
-
resetSorting:
|
|
8801
|
-
rowCountText:
|
|
8802
|
-
hasErrorText:
|
|
8803
|
-
globalFilterPlaceholder:
|
|
8804
|
-
trueLabel:
|
|
8805
|
-
falseLabel:
|
|
9358
|
+
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 = {
|
|
9359
|
+
view: 'View',
|
|
9360
|
+
edit: 'Edit',
|
|
9361
|
+
filterButtonText: 'Filter',
|
|
9362
|
+
filterTitle: 'Filter',
|
|
9363
|
+
filterReset: 'Reset',
|
|
9364
|
+
filterClose: 'Close',
|
|
9365
|
+
reloadTooltip: 'Reload',
|
|
9366
|
+
reloadButtonText: 'Reload',
|
|
9367
|
+
resetSelection: 'Reset Selection',
|
|
9368
|
+
resetSorting: 'Reset Sorting',
|
|
9369
|
+
rowCountText: '',
|
|
9370
|
+
hasErrorText: 'Has Error',
|
|
9371
|
+
globalFilterPlaceholder: 'Search',
|
|
9372
|
+
trueLabel: 'True',
|
|
9373
|
+
falseLabel: 'False',
|
|
8806
9374
|
}, }) {
|
|
8807
9375
|
const table = reactTable.useReactTable({
|
|
8808
9376
|
_features: [DensityFeature],
|
|
@@ -8812,7 +9380,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8812
9380
|
getCoreRowModel: reactTable.getCoreRowModel(),
|
|
8813
9381
|
manualPagination: true,
|
|
8814
9382
|
manualSorting: true,
|
|
8815
|
-
columnResizeMode:
|
|
9383
|
+
columnResizeMode: 'onChange',
|
|
8816
9384
|
defaultColumn: {
|
|
8817
9385
|
size: 150, //starting column size
|
|
8818
9386
|
minSize: 10, //enforced during column resizing
|
|
@@ -8855,8 +9423,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8855
9423
|
table: table,
|
|
8856
9424
|
globalFilter,
|
|
8857
9425
|
setGlobalFilter,
|
|
8858
|
-
type:
|
|
8859
|
-
translate,
|
|
9426
|
+
type: 'server',
|
|
8860
9427
|
columns: columns,
|
|
8861
9428
|
sorting,
|
|
8862
9429
|
setSorting,
|
|
@@ -8874,9 +9441,10 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8874
9441
|
setColumnVisibility,
|
|
8875
9442
|
data: query.data?.data ?? [],
|
|
8876
9443
|
tableLabel,
|
|
8877
|
-
}, children: jsxRuntime.jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
9444
|
+
}, children: jsxRuntime.jsx(DataTableServerContext.Provider, { value: { url: url ?? '', query }, children: children }) }));
|
|
8878
9445
|
}
|
|
8879
9446
|
|
|
9447
|
+
exports.CalendarDisplay = CalendarDisplay;
|
|
8880
9448
|
exports.CardHeader = CardHeader;
|
|
8881
9449
|
exports.DataDisplay = DataDisplay;
|
|
8882
9450
|
exports.DataTable = DataTable;
|