@bsol-oss/react-datatable5 12.0.0-beta.94 → 13.0.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.d.ts +170 -43
- package/dist/index.js +1166 -637
- package/dist/index.mjs +1168 -640
- package/dist/types/components/DataTable/DataTable.d.ts +1 -3
- package/dist/types/components/DataTable/DataTableServer.d.ts +7 -9
- package/dist/types/components/DataTable/DefaultTable.d.ts +2 -1
- package/dist/types/components/DataTable/context/DataTableContext.d.ts +4 -6
- package/dist/types/components/DataTable/controls/MobileTableControls.d.ts +29 -0
- package/dist/types/components/DataTable/controls/TableControls.d.ts +2 -2
- package/dist/types/components/DataTable/display/CalendarDisplay.d.ts +84 -0
- package/dist/types/components/DataTable/display/DataDisplay.d.ts +0 -2
- package/dist/types/components/DataTable/display/MobileTableDisplay.d.ts +5 -0
- package/dist/types/components/DataTable/display/RecordDisplay.d.ts +1 -3
- package/dist/types/components/DataTable/display/TextCell.d.ts +2 -1
- package/dist/types/components/DataTable/hooks/useIsMobile.d.ts +6 -0
- package/dist/types/components/DataTable/useDataTable.d.ts +3 -6
- package/dist/types/components/DataTable/useDataTableServer.d.ts +4 -4
- package/dist/types/components/DataTable/utils/getColumns.d.ts +3 -5
- package/dist/types/components/DatePicker/DatePicker.d.ts +7 -8
- package/dist/types/components/DatePicker/DateTimePicker.d.ts +3 -1
- package/dist/types/components/DatePicker/IsoTimePicker.d.ts +5 -1
- package/dist/types/components/DatePicker/RangeDatePicker.d.ts +4 -4
- package/dist/types/components/DatePicker/useCalendar.d.ts +48 -0
- package/dist/types/components/Form/SchemaFormContext.d.ts +5 -3
- package/dist/types/components/Form/components/core/FormBody.d.ts +1 -2
- package/dist/types/components/Form/components/core/FormRoot.d.ts +6 -4
- package/dist/types/components/Form/components/fields/FilePicker.d.ts +1 -2
- package/dist/types/components/Form/components/fields/IdPicker.d.ts +8 -0
- package/dist/types/components/Form/components/fields/IdPickerMultiple.d.ts +7 -0
- package/dist/types/components/Form/components/fields/IdPickerSingle.d.ts +7 -0
- package/dist/types/components/Form/components/fields/useIdPickerData.d.ts +46 -0
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +9 -0
- package/dist/types/components/Form/useForm.d.ts +7 -2
- package/dist/types/components/Form/utils/useFormI18n.d.ts +14 -12
- package/dist/types/components/TimePicker/TimePicker.d.ts +4 -6
- package/dist/types/components/ui/provider.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -3
package/dist/index.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) => {
|
|
@@ -3514,14 +3750,14 @@ const highlightText = (text, searchTerm) => {
|
|
|
3514
3750
|
}
|
|
3515
3751
|
return parts.length > 0 ? jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts }) : textStr;
|
|
3516
3752
|
};
|
|
3517
|
-
const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, globalFilter, }) => {
|
|
3753
|
+
const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, globalFilter, alignEnd = false, }) => {
|
|
3518
3754
|
const highlightedText = React.useMemo(() => highlightText(text ?? '', globalFilter), [text, globalFilter]);
|
|
3519
3755
|
if (isBadge) {
|
|
3520
3756
|
return (jsxRuntime.jsx(react.Badge, { colorPalette: colorPalette || badgeColor, children: highlightedText }));
|
|
3521
3757
|
}
|
|
3522
3758
|
// onClick takes precedence over href
|
|
3523
3759
|
if (onClick) {
|
|
3524
|
-
return (jsxRuntime.jsx(react.Box, { as: "button", onClick: onClick, cursor: "pointer", textAlign:
|
|
3760
|
+
return (jsxRuntime.jsx(react.Box, { as: "button", onClick: onClick, cursor: "pointer", textAlign: alignEnd ? 'right' : 'left', _hover: {
|
|
3525
3761
|
textDecoration: 'underline',
|
|
3526
3762
|
color: {
|
|
3527
3763
|
base: 'blue.500',
|
|
@@ -3539,7 +3775,7 @@ const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, col
|
|
|
3539
3775
|
}
|
|
3540
3776
|
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: highlightedText });
|
|
3541
3777
|
};
|
|
3542
|
-
const TextCell = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette,
|
|
3778
|
+
const TextCell = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, alignEnd = false,
|
|
3543
3779
|
// Legacy props
|
|
3544
3780
|
label, containerProps = {}, textProps = {}, children, }) => {
|
|
3545
3781
|
// Get globalFilter from context
|
|
@@ -3553,23 +3789,25 @@ label, containerProps = {}, textProps = {}, children, }) => {
|
|
|
3553
3789
|
const highlightedDisplayText = typeof displayText === 'string' || typeof displayText === 'number'
|
|
3554
3790
|
? highlightText(displayText, globalFilter)
|
|
3555
3791
|
: displayText;
|
|
3792
|
+
const flexJustifyContent = alignEnd ? 'flex-end' : undefined;
|
|
3793
|
+
const textAlign = alignEnd ? 'right' : undefined;
|
|
3556
3794
|
if (label) {
|
|
3557
|
-
return (jsxRuntime.jsx(react.Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsxRuntime.jsx(Tooltip, { content: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', children: label }), children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }) }));
|
|
3795
|
+
return (jsxRuntime.jsx(react.Flex, { alignItems: 'center', justifyContent: flexJustifyContent, height: '100%', ...containerProps, children: jsxRuntime.jsx(Tooltip, { content: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', children: label }), children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', textAlign: textAlign, ...textProps, children: highlightedDisplayText }) }) }));
|
|
3558
3796
|
}
|
|
3559
|
-
return (jsxRuntime.jsx(react.Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }));
|
|
3797
|
+
return (jsxRuntime.jsx(react.Flex, { alignItems: 'center', justifyContent: flexJustifyContent, height: '100%', ...containerProps, children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', textAlign: textAlign, ...textProps, children: highlightedDisplayText }) }));
|
|
3560
3798
|
}
|
|
3561
3799
|
// New API: use text prop
|
|
3562
3800
|
const displayValue = text ?? children;
|
|
3563
3801
|
if (Array.isArray(displayValue)) {
|
|
3564
|
-
return (jsxRuntime.jsx(react.Flex, { gap: 2, flexWrap: "wrap", children: displayValue.map((item, index) => {
|
|
3802
|
+
return (jsxRuntime.jsx(react.Flex, { gap: 2, flexWrap: "wrap", justifyContent: alignEnd ? 'flex-end' : undefined, children: displayValue.map((item, index) => {
|
|
3565
3803
|
const highlightedItem = highlightText(item, globalFilter);
|
|
3566
3804
|
return (jsxRuntime.jsx(react.Badge, { colorPalette: colorPalette || badgeColor, children: highlightedItem }, index));
|
|
3567
3805
|
}) }));
|
|
3568
3806
|
}
|
|
3569
3807
|
if (!!displayValue === false) {
|
|
3570
|
-
return (jsxRuntime.jsx(react.Text, { textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden", wordBreak: "break-all", display: "flex", alignItems: "center", height: "100%", children: "-" }));
|
|
3808
|
+
return (jsxRuntime.jsx(react.Text, { textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden", wordBreak: "break-all", display: "flex", alignItems: "center", justifyContent: alignEnd ? 'flex-end' : undefined, height: "100%", textAlign: alignEnd ? 'right' : undefined, children: "-" }));
|
|
3571
3809
|
}
|
|
3572
|
-
return (jsxRuntime.jsx(react.Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", height: "100%", children: jsxRuntime.jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter }) }));
|
|
3810
|
+
return (jsxRuntime.jsx(react.Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", justifyContent: alignEnd ? 'flex-end' : undefined, height: "100%", textAlign: alignEnd ? 'right' : undefined, children: jsxRuntime.jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter, alignEnd: alignEnd }) }));
|
|
3573
3811
|
};
|
|
3574
3812
|
|
|
3575
3813
|
const Tag = React__namespace.forwardRef(function Tag(props, ref) {
|
|
@@ -3599,7 +3837,7 @@ const ErrorAlert = ({ showMessage = true }) => {
|
|
|
3599
3837
|
const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: defaultPagination = {
|
|
3600
3838
|
pageIndex: 0, //initial page index
|
|
3601
3839
|
pageSize: 10, //default page size
|
|
3602
|
-
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter =
|
|
3840
|
+
}, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = '', density: defaultDensity = 'sm', } = {
|
|
3603
3841
|
sorting: [],
|
|
3604
3842
|
pagination: {
|
|
3605
3843
|
pageIndex: 0, //initial page index
|
|
@@ -3609,9 +3847,9 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3609
3847
|
columnFilters: [],
|
|
3610
3848
|
columnOrder: [],
|
|
3611
3849
|
columnVisibility: {},
|
|
3612
|
-
globalFilter:
|
|
3613
|
-
density:
|
|
3614
|
-
},
|
|
3850
|
+
globalFilter: '',
|
|
3851
|
+
density: 'sm',
|
|
3852
|
+
}, } = {
|
|
3615
3853
|
default: {
|
|
3616
3854
|
sorting: [],
|
|
3617
3855
|
pagination: {
|
|
@@ -3622,8 +3860,8 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3622
3860
|
columnFilters: [],
|
|
3623
3861
|
columnOrder: [],
|
|
3624
3862
|
columnVisibility: {},
|
|
3625
|
-
globalFilter:
|
|
3626
|
-
density:
|
|
3863
|
+
globalFilter: '',
|
|
3864
|
+
density: 'sm',
|
|
3627
3865
|
},
|
|
3628
3866
|
}) => {
|
|
3629
3867
|
const [sorting, setSorting] = React.useState(defaultSorting);
|
|
@@ -3634,7 +3872,6 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3634
3872
|
const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter);
|
|
3635
3873
|
const [density, setDensity] = React.useState(defaultDensity);
|
|
3636
3874
|
const [columnVisibility, setColumnVisibility] = React.useState(defaultColumnVisibility);
|
|
3637
|
-
const translate = reactI18next.useTranslation("", { keyPrefix });
|
|
3638
3875
|
return {
|
|
3639
3876
|
sorting,
|
|
3640
3877
|
setSorting,
|
|
@@ -3652,12 +3889,11 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
|
|
|
3652
3889
|
setDensity,
|
|
3653
3890
|
columnVisibility,
|
|
3654
3891
|
setColumnVisibility,
|
|
3655
|
-
translate,
|
|
3656
3892
|
};
|
|
3657
3893
|
};
|
|
3658
3894
|
|
|
3659
3895
|
const useDataTableServer = (props) => {
|
|
3660
|
-
const { url, default: defaultProps,
|
|
3896
|
+
const { url, default: defaultProps, placeholderData, queryFn: customQueryFn, } = props;
|
|
3661
3897
|
const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
|
|
3662
3898
|
const [sorting, setSorting] = React.useState(defaultSorting || []);
|
|
3663
3899
|
const [columnFilters, setColumnFilters] = React.useState(defaultColumnFilters || []); // can set initial column filter state here
|
|
@@ -3667,8 +3903,8 @@ const useDataTableServer = (props) => {
|
|
|
3667
3903
|
});
|
|
3668
3904
|
const [rowSelection, setRowSelection] = React.useState(defaultRowSelection || {});
|
|
3669
3905
|
const [columnOrder, setColumnOrder] = React.useState(defaultColumnOrder || []);
|
|
3670
|
-
const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter ||
|
|
3671
|
-
const [density, setDensity] = React.useState(defaultDensity ||
|
|
3906
|
+
const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter || '');
|
|
3907
|
+
const [density, setDensity] = React.useState(defaultDensity || 'sm');
|
|
3672
3908
|
const [columnVisibility, setColumnVisibility] = React.useState(defaultColumnVisibility || {});
|
|
3673
3909
|
const { pageSize, pageIndex } = pagination;
|
|
3674
3910
|
const params = {
|
|
@@ -3680,7 +3916,7 @@ const useDataTableServer = (props) => {
|
|
|
3680
3916
|
};
|
|
3681
3917
|
const defaultQueryFn = async () => {
|
|
3682
3918
|
if (!url) {
|
|
3683
|
-
throw new Error(
|
|
3919
|
+
throw new Error('url is required');
|
|
3684
3920
|
}
|
|
3685
3921
|
const response = await axios.get(url, {
|
|
3686
3922
|
params,
|
|
@@ -3694,7 +3930,6 @@ const useDataTableServer = (props) => {
|
|
|
3694
3930
|
: defaultQueryFn,
|
|
3695
3931
|
placeholderData,
|
|
3696
3932
|
});
|
|
3697
|
-
const translate = reactI18next.useTranslation("", { keyPrefix });
|
|
3698
3933
|
return {
|
|
3699
3934
|
sorting,
|
|
3700
3935
|
setSorting,
|
|
@@ -3713,7 +3948,6 @@ const useDataTableServer = (props) => {
|
|
|
3713
3948
|
columnVisibility,
|
|
3714
3949
|
setColumnVisibility,
|
|
3715
3950
|
query,
|
|
3716
|
-
translate,
|
|
3717
3951
|
};
|
|
3718
3952
|
};
|
|
3719
3953
|
|
|
@@ -3732,11 +3966,8 @@ const snakeToLabel = (str) => {
|
|
|
3732
3966
|
.join(" "); // Join with space
|
|
3733
3967
|
};
|
|
3734
3968
|
|
|
3735
|
-
const RecordDisplay = ({ object, boxProps,
|
|
3969
|
+
const RecordDisplay = ({ object, boxProps, prefix = '', }) => {
|
|
3736
3970
|
const getColumn = ({ field }) => {
|
|
3737
|
-
if (translate !== undefined) {
|
|
3738
|
-
return translate.t(`${prefix}${field}`);
|
|
3739
|
-
}
|
|
3740
3971
|
return snakeToLabel(field);
|
|
3741
3972
|
};
|
|
3742
3973
|
if (object === null) {
|
|
@@ -3744,7 +3975,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = '', }) => {
|
|
|
3744
3975
|
}
|
|
3745
3976
|
return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
|
|
3746
3977
|
const uniqueKey = `${prefix}${field}-${index}`;
|
|
3747
|
-
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));
|
|
3748
3979
|
}) }));
|
|
3749
3980
|
};
|
|
3750
3981
|
|
|
@@ -3758,15 +3989,12 @@ const widthSanityCheck = (widthList, ignoreList, properties) => {
|
|
|
3758
3989
|
throw new Error(`The width list is too long given from the number of remaining properties after ignore some.`);
|
|
3759
3990
|
}
|
|
3760
3991
|
};
|
|
3761
|
-
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400,
|
|
3992
|
+
const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {}, defaultWidth = 400, }) => {
|
|
3762
3993
|
const { properties } = schema;
|
|
3763
|
-
idListSanityCheck(
|
|
3994
|
+
idListSanityCheck('ignore', ignore, properties);
|
|
3764
3995
|
widthSanityCheck(width, ignore, properties);
|
|
3765
|
-
idListSanityCheck(
|
|
3996
|
+
idListSanityCheck('meta', Object.keys(meta), properties);
|
|
3766
3997
|
const getColumn = ({ column }) => {
|
|
3767
|
-
if (translate !== undefined) {
|
|
3768
|
-
return translate.t(`${column}`);
|
|
3769
|
-
}
|
|
3770
3998
|
return snakeToLabel(column);
|
|
3771
3999
|
};
|
|
3772
4000
|
const keys = Object.keys(properties);
|
|
@@ -3775,15 +4003,15 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
|
|
|
3775
4003
|
return !ignore.some((shouldIgnoreKey) => key === shouldIgnoreKey);
|
|
3776
4004
|
});
|
|
3777
4005
|
const columnHelper = reactTable.createColumnHelper();
|
|
3778
|
-
// @ts-expect-error find type for unknown
|
|
3779
4006
|
const columns = [
|
|
3780
4007
|
...ignored.map((column, index) => {
|
|
4008
|
+
// @ts-expect-error column accessor type issue with generic TData
|
|
3781
4009
|
return columnHelper.accessor(column, {
|
|
3782
4010
|
cell: (props) => {
|
|
3783
4011
|
// @ts-expect-error find type for unknown
|
|
3784
4012
|
const value = props.row.original[column];
|
|
3785
|
-
if (typeof value ===
|
|
3786
|
-
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 }) }));
|
|
3787
4015
|
}
|
|
3788
4016
|
return jsxRuntime.jsx(TextCell, { children: value });
|
|
3789
4017
|
},
|
|
@@ -3815,6 +4043,11 @@ const SchemaFormContext = React.createContext({
|
|
|
3815
4043
|
include: [],
|
|
3816
4044
|
onSubmit: async () => { },
|
|
3817
4045
|
rowNumber: 0,
|
|
4046
|
+
/** Default translate fallback - returns key as-is */
|
|
4047
|
+
translate: {
|
|
4048
|
+
t: (key) => key,
|
|
4049
|
+
ready: true,
|
|
4050
|
+
},
|
|
3818
4051
|
requestOptions: {},
|
|
3819
4052
|
timezone: 'Asia/Hong_Kong',
|
|
3820
4053
|
displayConfig: {
|
|
@@ -4047,7 +4280,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4047
4280
|
showSubmitButton: true,
|
|
4048
4281
|
showResetButton: true,
|
|
4049
4282
|
showTitle: true,
|
|
4050
|
-
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, insideDialog = false, }) => {
|
|
4283
|
+
}, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, timePickerLabels, insideDialog = false, }) => {
|
|
4051
4284
|
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
4052
4285
|
const [isError, setIsError] = React.useState(false);
|
|
4053
4286
|
const [isSubmiting, setIsSubmiting] = React.useState(false);
|
|
@@ -4138,6 +4371,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
4138
4371
|
enumPickerLabels,
|
|
4139
4372
|
filePickerLabels,
|
|
4140
4373
|
formButtonLabels,
|
|
4374
|
+
timePickerLabels,
|
|
4141
4375
|
ajvResolver: ajvResolver(schema),
|
|
4142
4376
|
insideDialog,
|
|
4143
4377
|
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
@@ -4148,31 +4382,33 @@ function removeIndex(str) {
|
|
|
4148
4382
|
}
|
|
4149
4383
|
|
|
4150
4384
|
/**
|
|
4151
|
-
* Custom hook
|
|
4385
|
+
* Custom hook for form field labels and fallback text.
|
|
4152
4386
|
* Automatically handles colLabel construction and removeIndex logic.
|
|
4387
|
+
* Uses schema.title when available, otherwise falls back to translate function.
|
|
4153
4388
|
*
|
|
4154
4389
|
* @param column - The column name
|
|
4155
4390
|
* @param prefix - The prefix for the field (usually empty string or parent path)
|
|
4156
|
-
* @
|
|
4391
|
+
* @param schema - Optional schema object with title property
|
|
4392
|
+
* @returns Object with label helper functions
|
|
4157
4393
|
*
|
|
4158
4394
|
* @example
|
|
4159
4395
|
* ```tsx
|
|
4160
|
-
* const formI18n = useFormI18n(column, prefix);
|
|
4396
|
+
* const formI18n = useFormI18n(column, prefix, schema);
|
|
4161
4397
|
*
|
|
4162
|
-
* // Get field label
|
|
4398
|
+
* // Get field label (prefers schema.title)
|
|
4163
4399
|
* <Field label={formI18n.label()} />
|
|
4164
4400
|
*
|
|
4165
|
-
* // Get error message
|
|
4401
|
+
* // Get required error message
|
|
4166
4402
|
* <Text>{formI18n.required()}</Text>
|
|
4167
4403
|
*
|
|
4168
|
-
* // Get custom
|
|
4404
|
+
* // Get custom text
|
|
4169
4405
|
* <Text>{formI18n.t('add_more')}</Text>
|
|
4170
4406
|
*
|
|
4171
4407
|
* // Access the raw colLabel
|
|
4172
4408
|
* const colLabel = formI18n.colLabel;
|
|
4173
4409
|
* ```
|
|
4174
4410
|
*/
|
|
4175
|
-
const useFormI18n
|
|
4411
|
+
const useFormI18n = (column, prefix = '', schema) => {
|
|
4176
4412
|
const { translate } = useSchemaContext();
|
|
4177
4413
|
const colLabel = `${prefix}${column}`;
|
|
4178
4414
|
return {
|
|
@@ -4181,7 +4417,7 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4181
4417
|
*/
|
|
4182
4418
|
colLabel,
|
|
4183
4419
|
/**
|
|
4184
|
-
* 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
|
|
4185
4421
|
* Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
|
|
4186
4422
|
*/
|
|
4187
4423
|
label: (options) => {
|
|
@@ -4191,18 +4427,18 @@ const useFormI18n$1 = (column, prefix = '', schema) => {
|
|
|
4191
4427
|
return translate.t(removeIndex(`${colLabel}.field_label`), options);
|
|
4192
4428
|
},
|
|
4193
4429
|
/**
|
|
4194
|
-
* Get the required error message
|
|
4430
|
+
* Get the required error message
|
|
4195
4431
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
|
|
4196
4432
|
*/
|
|
4197
4433
|
required: (options) => {
|
|
4198
4434
|
return translate.t(removeIndex(`${colLabel}.field_required`), options);
|
|
4199
4435
|
},
|
|
4200
4436
|
/**
|
|
4201
|
-
* Get
|
|
4437
|
+
* Get text for any custom key relative to the field
|
|
4202
4438
|
* Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
|
|
4203
4439
|
*
|
|
4204
|
-
* @param key - The
|
|
4205
|
-
* @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)
|
|
4206
4442
|
*/
|
|
4207
4443
|
t: (key, options) => {
|
|
4208
4444
|
return translate.t(removeIndex(`${colLabel}.${key}`), options);
|
|
@@ -4220,8 +4456,9 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4220
4456
|
const { type } = items;
|
|
4221
4457
|
const colLabel = `${prefix}${column}`;
|
|
4222
4458
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4223
|
-
const formI18n = useFormI18n
|
|
4459
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4224
4460
|
const { formState: { errors }, setValue, watch, } = reactHookForm.useFormContext();
|
|
4461
|
+
const { formButtonLabels } = useSchemaContext();
|
|
4225
4462
|
const fields = (watch(colLabel) ?? []);
|
|
4226
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: {
|
|
4227
4464
|
base: 'colorPalette.200',
|
|
@@ -4247,7 +4484,7 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
|
|
|
4247
4484
|
return;
|
|
4248
4485
|
}
|
|
4249
4486
|
setValue(colLabel, [...fields, {}]);
|
|
4250
|
-
}, children:
|
|
4487
|
+
}, children: formButtonLabels?.add ?? 'Add' }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
4251
4488
|
};
|
|
4252
4489
|
|
|
4253
4490
|
const Field = React__namespace.forwardRef(function Field(props, ref) {
|
|
@@ -4261,7 +4498,7 @@ const BooleanPicker = ({ schema, column, prefix }) => {
|
|
|
4261
4498
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4262
4499
|
const colLabel = `${prefix}${column}`;
|
|
4263
4500
|
const value = watch(colLabel);
|
|
4264
|
-
const formI18n = useFormI18n
|
|
4501
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4265
4502
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
4266
4503
|
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
|
|
4267
4504
|
setValue(colLabel, !value);
|
|
@@ -4282,50 +4519,50 @@ const CustomInput = ({ column, schema, prefix }) => {
|
|
|
4282
4519
|
|
|
4283
4520
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
4284
4521
|
const { labels } = React.useContext(DatePickerContext);
|
|
4285
|
-
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
4522
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
4286
4523
|
if (calendars.length) {
|
|
4287
|
-
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({
|
|
4288
4525
|
calendars,
|
|
4289
4526
|
offset: 12,
|
|
4290
|
-
}), 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({
|
|
4291
4528
|
calendars,
|
|
4292
4529
|
offset: 12,
|
|
4293
|
-
}), 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) => {
|
|
4294
4531
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
4295
|
-
return (jsxRuntime.jsx(react.Text, { textAlign:
|
|
4532
|
+
return (jsxRuntime.jsx(react.Text, { textAlign: 'center', children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
4296
4533
|
}), calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
4297
4534
|
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
4298
4535
|
if (!dateObj) {
|
|
4299
4536
|
return jsxRuntime.jsx(react.Grid, {}, key);
|
|
4300
4537
|
}
|
|
4301
|
-
const { date, selected, selectable, today } = dateObj;
|
|
4538
|
+
const { date, selected, selectable, today, isCurrentMonth, } = dateObj;
|
|
4302
4539
|
const getDateColor = ({ today, selected, selectable, }) => {
|
|
4303
4540
|
if (!selectable) {
|
|
4304
|
-
return
|
|
4541
|
+
return 'gray';
|
|
4305
4542
|
}
|
|
4306
4543
|
if (selected) {
|
|
4307
|
-
return
|
|
4544
|
+
return 'blue';
|
|
4308
4545
|
}
|
|
4309
4546
|
if (today) {
|
|
4310
|
-
return
|
|
4547
|
+
return 'green';
|
|
4311
4548
|
}
|
|
4312
|
-
return
|
|
4549
|
+
return '';
|
|
4313
4550
|
};
|
|
4314
4551
|
const getVariant = ({ today, selected, selectable, }) => {
|
|
4315
4552
|
if (!selectable) {
|
|
4316
|
-
return
|
|
4553
|
+
return 'surface';
|
|
4317
4554
|
}
|
|
4318
4555
|
if (selected) {
|
|
4319
|
-
return
|
|
4556
|
+
return 'solid';
|
|
4320
4557
|
}
|
|
4321
4558
|
if (today) {
|
|
4322
|
-
return
|
|
4559
|
+
return 'surface';
|
|
4323
4560
|
}
|
|
4324
|
-
return
|
|
4561
|
+
return 'ghost';
|
|
4325
4562
|
};
|
|
4326
4563
|
const color = getDateColor({ today, selected, selectable });
|
|
4327
4564
|
const variant = getVariant({ today, selected, selectable });
|
|
4328
|
-
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));
|
|
4329
4566
|
}))] })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
4330
4567
|
}
|
|
4331
4568
|
return null;
|
|
@@ -4333,50 +4570,55 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
4333
4570
|
const DatePickerContext = React.createContext({
|
|
4334
4571
|
labels: {
|
|
4335
4572
|
monthNamesShort: [
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4573
|
+
'Jan',
|
|
4574
|
+
'Feb',
|
|
4575
|
+
'Mar',
|
|
4576
|
+
'Apr',
|
|
4577
|
+
'May',
|
|
4578
|
+
'Jun',
|
|
4579
|
+
'Jul',
|
|
4580
|
+
'Aug',
|
|
4581
|
+
'Sep',
|
|
4582
|
+
'Oct',
|
|
4583
|
+
'Nov',
|
|
4584
|
+
'Dec',
|
|
4348
4585
|
],
|
|
4349
|
-
weekdayNamesShort: [
|
|
4350
|
-
backButtonLabel:
|
|
4351
|
-
forwardButtonLabel:
|
|
4586
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
4587
|
+
backButtonLabel: 'Back',
|
|
4588
|
+
forwardButtonLabel: 'Next',
|
|
4352
4589
|
},
|
|
4353
4590
|
});
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
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 })) }));
|
|
4380
4622
|
};
|
|
4381
4623
|
|
|
4382
4624
|
dayjs.extend(utc);
|
|
@@ -4384,7 +4626,7 @@ dayjs.extend(timezone);
|
|
|
4384
4626
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
4385
4627
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4386
4628
|
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
4387
|
-
const formI18n = useFormI18n
|
|
4629
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4388
4630
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4389
4631
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4390
4632
|
const colLabel = formI18n.colLabel;
|
|
@@ -4418,74 +4660,30 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
4418
4660
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
4419
4661
|
const datePickerLabels = {
|
|
4420
4662
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
formI18n.translate.t(`common.month_5`, {
|
|
4434
|
-
defaultValue: 'May',
|
|
4435
|
-
}),
|
|
4436
|
-
formI18n.translate.t(`common.month_6`, {
|
|
4437
|
-
defaultValue: 'June',
|
|
4438
|
-
}),
|
|
4439
|
-
formI18n.translate.t(`common.month_7`, {
|
|
4440
|
-
defaultValue: 'July',
|
|
4441
|
-
}),
|
|
4442
|
-
formI18n.translate.t(`common.month_8`, {
|
|
4443
|
-
defaultValue: 'August',
|
|
4444
|
-
}),
|
|
4445
|
-
formI18n.translate.t(`common.month_9`, {
|
|
4446
|
-
defaultValue: 'September',
|
|
4447
|
-
}),
|
|
4448
|
-
formI18n.translate.t(`common.month_10`, {
|
|
4449
|
-
defaultValue: 'October',
|
|
4450
|
-
}),
|
|
4451
|
-
formI18n.translate.t(`common.month_11`, {
|
|
4452
|
-
defaultValue: 'November',
|
|
4453
|
-
}),
|
|
4454
|
-
formI18n.translate.t(`common.month_12`, {
|
|
4455
|
-
defaultValue: 'December',
|
|
4456
|
-
}),
|
|
4663
|
+
'January',
|
|
4664
|
+
'February',
|
|
4665
|
+
'March',
|
|
4666
|
+
'April',
|
|
4667
|
+
'May',
|
|
4668
|
+
'June',
|
|
4669
|
+
'July',
|
|
4670
|
+
'August',
|
|
4671
|
+
'September',
|
|
4672
|
+
'October',
|
|
4673
|
+
'November',
|
|
4674
|
+
'December',
|
|
4457
4675
|
],
|
|
4458
4676
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
defaultValue: 'Tue',
|
|
4467
|
-
}),
|
|
4468
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
4469
|
-
defaultValue: 'Wed',
|
|
4470
|
-
}),
|
|
4471
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
4472
|
-
defaultValue: 'Thu',
|
|
4473
|
-
}),
|
|
4474
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
4475
|
-
defaultValue: 'Fri',
|
|
4476
|
-
}),
|
|
4477
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
4478
|
-
defaultValue: 'Sat',
|
|
4479
|
-
}),
|
|
4677
|
+
'Sun',
|
|
4678
|
+
'Mon',
|
|
4679
|
+
'Tue',
|
|
4680
|
+
'Wed',
|
|
4681
|
+
'Thu',
|
|
4682
|
+
'Fri',
|
|
4683
|
+
'Sat',
|
|
4480
4684
|
],
|
|
4481
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
4482
|
-
|
|
4483
|
-
defaultValue: 'Back',
|
|
4484
|
-
}),
|
|
4485
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
4486
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
4487
|
-
defaultValue: 'Forward',
|
|
4488
|
-
}),
|
|
4685
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
4686
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
4489
4687
|
};
|
|
4490
4688
|
const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
4491
4689
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
@@ -4502,7 +4700,7 @@ dayjs.extend(timezone);
|
|
|
4502
4700
|
const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
4503
4701
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4504
4702
|
const { timezone, insideDialog } = useSchemaContext();
|
|
4505
|
-
const formI18n = useFormI18n
|
|
4703
|
+
const formI18n = useFormI18n(column, prefix);
|
|
4506
4704
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
|
|
4507
4705
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4508
4706
|
const colLabel = formI18n.colLabel;
|
|
@@ -4600,7 +4798,7 @@ const DateRangePicker = ({ column, schema, prefix, }) => {
|
|
|
4600
4798
|
const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
|
|
4601
4799
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4602
4800
|
const { enumPickerLabels, insideDialog } = useSchemaContext();
|
|
4603
|
-
const formI18n = useFormI18n
|
|
4801
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
4604
4802
|
const { required, variant } = schema;
|
|
4605
4803
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4606
4804
|
const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
|
|
@@ -5147,7 +5345,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
|
|
|
5147
5345
|
}) })) }))] }));
|
|
5148
5346
|
};
|
|
5149
5347
|
|
|
5150
|
-
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, }) {
|
|
5151
5349
|
const [selectedFile, setSelectedFile] = React.useState(undefined);
|
|
5152
5350
|
const [activeTab, setActiveTab] = React.useState('browse');
|
|
5153
5351
|
const [uploadingFiles, setUploadingFiles] = React.useState(new Set());
|
|
@@ -5216,15 +5414,8 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5216
5414
|
const showTabs = enableUpload && !!onUploadFile && !!onFetchFiles;
|
|
5217
5415
|
if (!onFetchFiles && !onUploadFile)
|
|
5218
5416
|
return null;
|
|
5219
|
-
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 ??
|
|
5220
|
-
|
|
5221
|
-
'Browse Library' }), jsxRuntime.jsx(react.Tabs.Trigger, { value: "upload", children: labels?.uploadTab ??
|
|
5222
|
-
translate(removeIndex(`${colLabel}.upload_tab`)) ??
|
|
5223
|
-
'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 ??
|
|
5224
|
-
translate(removeIndex(`${colLabel}.fileDropzone`)) ??
|
|
5225
|
-
'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 ??
|
|
5226
|
-
translate(removeIndex(`${colLabel}.uploading`)) ??
|
|
5227
|
-
'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: {
|
|
5228
5419
|
base: 'colorPalette.50',
|
|
5229
5420
|
_dark: 'colorPalette.900/20',
|
|
5230
5421
|
}, border: "1px solid", borderColor: {
|
|
@@ -5233,18 +5424,12 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
|
|
|
5233
5424
|
}, colorPalette: "red", borderRadius: "md", p: 3, children: jsxRuntime.jsxs(react.Text, { fontSize: "sm", color: {
|
|
5234
5425
|
base: 'colorPalette.600',
|
|
5235
5426
|
_dark: 'colorPalette.300',
|
|
5236
|
-
}, children: [fileKey.split('-')[0], ":", ' ', labels?.uploadFailed ??
|
|
5237
|
-
translate(removeIndex(`${colLabel}.upload_failed`)) ??
|
|
5238
|
-
'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 ??
|
|
5239
|
-
translate(removeIndex(`${colLabel}.cancel`)) ??
|
|
5240
|
-
'Cancel' }), jsxRuntime.jsx(react.Button, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFile, children: labels?.select ??
|
|
5241
|
-
translate(removeIndex(`${colLabel}.select`)) ??
|
|
5242
|
-
'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' })] }) })] }) }));
|
|
5243
5428
|
}
|
|
5244
5429
|
const FilePicker = ({ column, schema, prefix }) => {
|
|
5245
5430
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
5246
5431
|
const { filePickerLabels } = useSchemaContext();
|
|
5247
|
-
const formI18n = useFormI18n
|
|
5432
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5248
5433
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
|
|
5249
5434
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5250
5435
|
const isSingleSelect = type === 'string';
|
|
@@ -5320,7 +5505,7 @@ const FilePicker = ({ column, schema, prefix }) => {
|
|
|
5320
5505
|
const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
5321
5506
|
const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
|
|
5322
5507
|
const { filePickerLabels } = useSchemaContext();
|
|
5323
|
-
const formI18n = useFormI18n
|
|
5508
|
+
const formI18n = useFormI18n(column, prefix);
|
|
5324
5509
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
|
|
5325
5510
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5326
5511
|
const isSingleSelect = type === 'string';
|
|
@@ -5416,8 +5601,8 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
|
|
|
5416
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 ??
|
|
5417
5602
|
formI18n.t('browse_library') ??
|
|
5418
5603
|
'Browse from Library' }) }), jsxRuntime.jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
|
|
5419
|
-
|
|
5420
|
-
'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) => {
|
|
5421
5606
|
const file = fileMap.get(fileId);
|
|
5422
5607
|
const isImage = file
|
|
5423
5608
|
? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
|
|
@@ -5466,17 +5651,16 @@ const defaultRenderDisplay = (item) => {
|
|
|
5466
5651
|
return JSON.stringify(item);
|
|
5467
5652
|
};
|
|
5468
5653
|
|
|
5469
|
-
const
|
|
5654
|
+
const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
|
|
5470
5655
|
const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5471
5656
|
const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
|
|
5472
|
-
const
|
|
5473
|
-
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
5474
|
-
const isRequired = required?.some((columnId) => columnId === column);
|
|
5657
|
+
const { renderDisplay, foreign_key } = schema;
|
|
5475
5658
|
const { table, column: column_ref, customQueryFn, } = foreign_key;
|
|
5476
5659
|
const [searchText, setSearchText] = React.useState('');
|
|
5477
5660
|
const [debouncedSearchText, setDebouncedSearchText] = React.useState('');
|
|
5478
5661
|
const [limit] = React.useState(50); // Increased limit for combobox
|
|
5479
|
-
|
|
5662
|
+
// Get colLabel from schema context (we'll compute it here)
|
|
5663
|
+
const colLabel = `${prefix}${column}`;
|
|
5480
5664
|
const watchedValue = watch(colLabel);
|
|
5481
5665
|
const watchId = !isMultiple ? watchedValue : undefined;
|
|
5482
5666
|
const watchIds = isMultiple
|
|
@@ -5675,20 +5859,6 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5675
5859
|
itemToValue: (item) => item.value,
|
|
5676
5860
|
filter: contains,
|
|
5677
5861
|
});
|
|
5678
|
-
// Handle input value change (search)
|
|
5679
|
-
const handleInputValueChange = (details) => {
|
|
5680
|
-
setSearchText(details.inputValue);
|
|
5681
|
-
// Filter will be applied after data is fetched
|
|
5682
|
-
};
|
|
5683
|
-
// Handle value change
|
|
5684
|
-
const handleValueChange = (details) => {
|
|
5685
|
-
if (isMultiple) {
|
|
5686
|
-
setValue(colLabel, details.value);
|
|
5687
|
-
}
|
|
5688
|
-
else {
|
|
5689
|
-
setValue(colLabel, details.value[0] || '');
|
|
5690
|
-
}
|
|
5691
|
-
};
|
|
5692
5862
|
// Track previous comboboxItems to avoid unnecessary updates
|
|
5693
5863
|
const prevComboboxItemsRef = React.useRef('');
|
|
5694
5864
|
const prevSearchTextRef = React.useRef('');
|
|
@@ -5718,8 +5888,106 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5718
5888
|
// comboboxItems and searchText are the only dependencies we care about
|
|
5719
5889
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
5720
5890
|
}, [comboboxItems, searchText]);
|
|
5891
|
+
return {
|
|
5892
|
+
colLabel,
|
|
5893
|
+
currentValue,
|
|
5894
|
+
searchText,
|
|
5895
|
+
setSearchText,
|
|
5896
|
+
debouncedSearchText,
|
|
5897
|
+
isLoading,
|
|
5898
|
+
isFetching,
|
|
5899
|
+
isPending,
|
|
5900
|
+
isError,
|
|
5901
|
+
isSearching,
|
|
5902
|
+
isLoadingInitialValues,
|
|
5903
|
+
isFetchingInitialValues,
|
|
5904
|
+
missingIds,
|
|
5905
|
+
comboboxItems,
|
|
5906
|
+
collection,
|
|
5907
|
+
filter,
|
|
5908
|
+
set,
|
|
5909
|
+
idMap,
|
|
5910
|
+
idPickerLabels,
|
|
5911
|
+
insideDialog: insideDialog ?? false,
|
|
5912
|
+
renderDisplay,
|
|
5913
|
+
column_ref,
|
|
5914
|
+
errors,
|
|
5915
|
+
setValue,
|
|
5916
|
+
};
|
|
5917
|
+
};
|
|
5918
|
+
|
|
5919
|
+
const IdPickerSingle = ({ column, schema, prefix, }) => {
|
|
5920
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5921
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
5922
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5923
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
5924
|
+
column,
|
|
5925
|
+
schema,
|
|
5926
|
+
prefix,
|
|
5927
|
+
isMultiple: false,
|
|
5928
|
+
});
|
|
5929
|
+
const handleInputValueChange = (details) => {
|
|
5930
|
+
setSearchText(details.inputValue);
|
|
5931
|
+
};
|
|
5932
|
+
const handleValueChange = (details) => {
|
|
5933
|
+
setValue(colLabel, details.value[0] || '');
|
|
5934
|
+
};
|
|
5935
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
5936
|
+
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5937
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [currentValue.length > 0 && (jsxRuntime.jsx(react.Flex, { mb: 2, children: (() => {
|
|
5938
|
+
const id = currentValue[0];
|
|
5939
|
+
const item = idMap[id];
|
|
5940
|
+
// Show loading skeleton while fetching initial values
|
|
5941
|
+
if (item === undefined &&
|
|
5942
|
+
(isLoadingInitialValues || isFetchingInitialValues) &&
|
|
5943
|
+
missingIds.includes(id)) {
|
|
5944
|
+
return jsxRuntime.jsx(react.Skeleton, { height: "24px", width: "100px", borderRadius: "md" });
|
|
5945
|
+
}
|
|
5946
|
+
// Only show "not found" if we're not loading and item is still missing
|
|
5947
|
+
if (item === undefined) {
|
|
5948
|
+
return (jsxRuntime.jsx(react.Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }));
|
|
5949
|
+
}
|
|
5950
|
+
return jsxRuntime.jsx(react.Text, { fontSize: "sm", children: renderDisplayFunction(item) });
|
|
5951
|
+
})() })), 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
|
|
5952
|
+
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5953
|
+
: 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: () => {
|
|
5954
|
+
setValue(colLabel, '');
|
|
5955
|
+
} })), 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 ? (
|
|
5956
|
+
// Show skeleton items to prevent UI shift
|
|
5957
|
+
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
|
|
5958
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5959
|
+
: idPickerLabels?.initialResults ??
|
|
5960
|
+
'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
|
|
5961
|
+
? renderDisplayFunction(item.raw)
|
|
5962
|
+
: 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 ? (
|
|
5963
|
+
// Show skeleton items to prevent UI shift
|
|
5964
|
+
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
|
|
5965
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5966
|
+
: idPickerLabels?.initialResults ??
|
|
5967
|
+
'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
|
|
5968
|
+
? renderDisplayFunction(item.raw)
|
|
5969
|
+
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5970
|
+
};
|
|
5971
|
+
|
|
5972
|
+
const IdPickerMultiple = ({ column, schema, prefix, }) => {
|
|
5973
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5974
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, } = schema;
|
|
5975
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5976
|
+
const { colLabel, currentValue, searchText, setSearchText, isLoading, isFetching, isPending, isError, isSearching, isLoadingInitialValues, isFetchingInitialValues, missingIds, collection, idMap, idPickerLabels, insideDialog, renderDisplay: renderDisplayFn, errors, setValue, } = useIdPickerData({
|
|
5977
|
+
column,
|
|
5978
|
+
schema,
|
|
5979
|
+
prefix,
|
|
5980
|
+
isMultiple: true,
|
|
5981
|
+
});
|
|
5982
|
+
const handleInputValueChange = (details) => {
|
|
5983
|
+
setSearchText(details.inputValue);
|
|
5984
|
+
};
|
|
5985
|
+
const handleValueChange = (details) => {
|
|
5986
|
+
setValue(colLabel, details.value);
|
|
5987
|
+
};
|
|
5988
|
+
const renderDisplayFunction = renderDisplayFn || renderDisplay || defaultRenderDisplay;
|
|
5721
5989
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
5722
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [
|
|
5990
|
+
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) => {
|
|
5723
5991
|
const item = idMap[id];
|
|
5724
5992
|
// Show loading skeleton while fetching initial values
|
|
5725
5993
|
if (item === undefined &&
|
|
@@ -5729,34 +5997,28 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5729
5997
|
}
|
|
5730
5998
|
// Only show "not found" if we're not loading and item is still missing
|
|
5731
5999
|
if (item === undefined) {
|
|
5732
|
-
return (jsxRuntime.jsx(react.Text, { fontSize: "sm", children: idPickerLabels?.undefined ??
|
|
6000
|
+
return (jsxRuntime.jsx(react.Text, { fontSize: "sm", children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
5733
6001
|
}
|
|
5734
6002
|
return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
|
|
5735
6003
|
const newValue = currentValue.filter((itemId) => itemId !== id);
|
|
5736
6004
|
setValue(colLabel, newValue);
|
|
5737
|
-
}, children:
|
|
5738
|
-
|
|
5739
|
-
: defaultRenderDisplay(item) }, id));
|
|
5740
|
-
}) })), 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
|
|
6005
|
+
}, children: renderDisplayFunction(item) }, id));
|
|
6006
|
+
}) })), 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
|
|
5741
6007
|
? { strategy: 'fixed', hideWhenDetached: true }
|
|
5742
|
-
: undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ??
|
|
5743
|
-
setValue(colLabel, '');
|
|
5744
|
-
} })), 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 ? (
|
|
6008
|
+
: 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 ? (
|
|
5745
6009
|
// Show skeleton items to prevent UI shift
|
|
5746
6010
|
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
|
|
5747
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5748
|
-
formI18n.t('empty_search_result')
|
|
6011
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5749
6012
|
: idPickerLabels?.initialResults ??
|
|
5750
|
-
|
|
5751
|
-
?
|
|
5752
|
-
: 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:
|
|
6013
|
+
'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
|
|
6014
|
+
? renderDisplayFunction(item.raw)
|
|
6015
|
+
: 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 ? (
|
|
5753
6016
|
// Show skeleton items to prevent UI shift
|
|
5754
6017
|
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
|
|
5755
|
-
? idPickerLabels?.emptySearchResult ??
|
|
5756
|
-
formI18n.t('empty_search_result')
|
|
6018
|
+
? idPickerLabels?.emptySearchResult ?? 'No results found'
|
|
5757
6019
|
: idPickerLabels?.initialResults ??
|
|
5758
|
-
|
|
5759
|
-
?
|
|
6020
|
+
'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
|
|
6021
|
+
? renderDisplayFunction(item.raw)
|
|
5760
6022
|
: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5761
6023
|
};
|
|
5762
6024
|
|
|
@@ -5830,7 +6092,7 @@ const NumberInputField = ({ schema, column, prefix, }) => {
|
|
|
5830
6092
|
const colLabel = `${prefix}${column}`;
|
|
5831
6093
|
const value = watch(`${colLabel}`);
|
|
5832
6094
|
const fieldError = getFieldError(errors, colLabel);
|
|
5833
|
-
const formI18n = useFormI18n
|
|
6095
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5834
6096
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn, gridRow, errorText: fieldError
|
|
5835
6097
|
? fieldError.includes('required')
|
|
5836
6098
|
? formI18n.required()
|
|
@@ -5848,7 +6110,7 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5848
6110
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
5849
6111
|
const colLabel = `${prefix}${column}`;
|
|
5850
6112
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5851
|
-
const formI18n = useFormI18n
|
|
6113
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5852
6114
|
const { formState: { errors }, } = reactHookForm.useFormContext();
|
|
5853
6115
|
if (properties === undefined) {
|
|
5854
6116
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -5868,14 +6130,14 @@ const ObjectInput = ({ schema, column, prefix }) => {
|
|
|
5868
6130
|
|
|
5869
6131
|
const RecordInput = ({ column, schema, prefix }) => {
|
|
5870
6132
|
const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
|
|
5871
|
-
const {
|
|
6133
|
+
const { formButtonLabels } = useSchemaContext();
|
|
5872
6134
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
5873
6135
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5874
6136
|
const entries = Object.entries(getValues(column) ?? {});
|
|
5875
6137
|
const [showNewEntries, setShowNewEntries] = React.useState(false);
|
|
5876
6138
|
const [newKey, setNewKey] = React.useState();
|
|
5877
6139
|
const [newValue, setNewValue] = React.useState();
|
|
5878
|
-
const formI18n = useFormI18n
|
|
6140
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5879
6141
|
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]) => {
|
|
5880
6142
|
return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
|
|
5881
6143
|
const filtered = entries.filter(([target]) => {
|
|
@@ -5912,11 +6174,11 @@ const RecordInput = ({ column, schema, prefix }) => {
|
|
|
5912
6174
|
setShowNewEntries(false);
|
|
5913
6175
|
setNewKey(undefined);
|
|
5914
6176
|
setNewValue(undefined);
|
|
5915
|
-
}, children:
|
|
6177
|
+
}, children: formButtonLabels?.save ?? 'Save' })] })] }) }), jsxRuntime.jsx(Button, { onClick: () => {
|
|
5916
6178
|
setShowNewEntries(true);
|
|
5917
6179
|
setNewKey(undefined);
|
|
5918
6180
|
setNewValue(undefined);
|
|
5919
|
-
}, children:
|
|
6181
|
+
}, children: formButtonLabels?.addNew ?? 'Add New' })] }));
|
|
5920
6182
|
};
|
|
5921
6183
|
|
|
5922
6184
|
const StringInputField = ({ column, schema, prefix, }) => {
|
|
@@ -5925,7 +6187,7 @@ const StringInputField = ({ column, schema, prefix, }) => {
|
|
|
5925
6187
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5926
6188
|
const colLabel = `${prefix}${column}`;
|
|
5927
6189
|
const fieldError = getFieldError(errors, colLabel);
|
|
5928
|
-
const formI18n = useFormI18n
|
|
6190
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
5929
6191
|
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" }) }) }));
|
|
5930
6192
|
};
|
|
5931
6193
|
|
|
@@ -6117,7 +6379,7 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6117
6379
|
const form = reactHookForm.useFormContext();
|
|
6118
6380
|
const { setValue, watch } = form;
|
|
6119
6381
|
const fieldError = getFieldError(errors, colLabel);
|
|
6120
|
-
const formI18n = useFormI18n
|
|
6382
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6121
6383
|
const watchValue = watch(colLabel);
|
|
6122
6384
|
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
|
|
6123
6385
|
? fieldError.includes('required')
|
|
@@ -6128,18 +6390,13 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
|
|
|
6128
6390
|
|
|
6129
6391
|
dayjs.extend(utc);
|
|
6130
6392
|
dayjs.extend(timezone);
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
},
|
|
6137
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6138
|
-
onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, portalled = true, }) {
|
|
6139
|
-
// Generate time options (every 15 minutes)
|
|
6393
|
+
const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem, onChange = () => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6394
|
+
placeholder: 'hh:mm AM/PM',
|
|
6395
|
+
emptyMessage: 'No time found',
|
|
6396
|
+
}, }) => {
|
|
6397
|
+
// Generate time options (every 15 minutes in 12-hour format)
|
|
6140
6398
|
const timeOptions = React.useMemo(() => {
|
|
6141
6399
|
const options = [];
|
|
6142
|
-
const meridiemOptions = ['am', 'pm'];
|
|
6143
6400
|
// Get start time for comparison if provided
|
|
6144
6401
|
let startDateTime = null;
|
|
6145
6402
|
let shouldFilterByDate = false;
|
|
@@ -6154,14 +6411,16 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6154
6411
|
selectedDateObj.format('YYYY-MM-DD');
|
|
6155
6412
|
}
|
|
6156
6413
|
}
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
//
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6414
|
+
// Generate 12-hour format options (1-12 for hours, AM/PM)
|
|
6415
|
+
for (let h = 1; h <= 12; h++) {
|
|
6416
|
+
for (let m = 0; m < 60; m += 15) {
|
|
6417
|
+
for (const mer of ['am', 'pm']) {
|
|
6418
|
+
// Convert 12-hour to 24-hour for comparison
|
|
6419
|
+
let hour24 = h;
|
|
6420
|
+
if (mer === 'am' && h === 12)
|
|
6421
|
+
hour24 = 0;
|
|
6422
|
+
else if (mer === 'pm' && h < 12)
|
|
6423
|
+
hour24 = h + 12;
|
|
6165
6424
|
// Filter out times that would result in negative duration (only when dates are the same)
|
|
6166
6425
|
if (startDateTime && selectedDate && shouldFilterByDate) {
|
|
6167
6426
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
@@ -6204,20 +6463,23 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6204
6463
|
}
|
|
6205
6464
|
}
|
|
6206
6465
|
}
|
|
6466
|
+
const hourDisplay = h.toString();
|
|
6467
|
+
const minuteDisplay = m.toString().padStart(2, '0');
|
|
6468
|
+
const timeDisplay = `${hourDisplay}:${minuteDisplay} ${mer.toUpperCase()}`;
|
|
6207
6469
|
options.push({
|
|
6208
|
-
label:
|
|
6209
|
-
value: `${h}:${m
|
|
6470
|
+
label: timeDisplay,
|
|
6471
|
+
value: `${h}:${m}:${mer}`,
|
|
6210
6472
|
hour: h,
|
|
6211
6473
|
minute: m,
|
|
6212
6474
|
meridiem: mer,
|
|
6213
|
-
searchText:
|
|
6475
|
+
searchText: timeDisplay, // Use base time without duration for searching
|
|
6214
6476
|
durationText,
|
|
6215
6477
|
});
|
|
6216
6478
|
}
|
|
6217
6479
|
}
|
|
6218
6480
|
}
|
|
6219
6481
|
return options;
|
|
6220
|
-
}, [
|
|
6482
|
+
}, [startTime, selectedDate, timezone]);
|
|
6221
6483
|
const { contains } = react.useFilter({ sensitivity: 'base' });
|
|
6222
6484
|
const { collection, filter } = react.useListCollection({
|
|
6223
6485
|
initialItems: timeOptions,
|
|
@@ -6230,7 +6492,7 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6230
6492
|
if (hour === null || minute === null || meridiem === null) {
|
|
6231
6493
|
return '';
|
|
6232
6494
|
}
|
|
6233
|
-
return `${hour}:${minute
|
|
6495
|
+
return `${hour}:${minute}:${meridiem}`;
|
|
6234
6496
|
}, [hour, minute, meridiem]);
|
|
6235
6497
|
// Calculate duration difference
|
|
6236
6498
|
const durationDiff = React.useMemo(() => {
|
|
@@ -6241,15 +6503,14 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6241
6503
|
meridiem === null) {
|
|
6242
6504
|
return null;
|
|
6243
6505
|
}
|
|
6244
|
-
const hour24 = meridiem === 'am'
|
|
6245
|
-
? hour === 12
|
|
6246
|
-
? 0
|
|
6247
|
-
: hour
|
|
6248
|
-
: hour === 12
|
|
6249
|
-
? 12
|
|
6250
|
-
: hour + 12;
|
|
6251
6506
|
const startDateObj = dayjs(startTime).tz(timezone);
|
|
6252
6507
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
6508
|
+
// Convert 12-hour to 24-hour format
|
|
6509
|
+
let hour24 = hour;
|
|
6510
|
+
if (meridiem === 'am' && hour === 12)
|
|
6511
|
+
hour24 = 0;
|
|
6512
|
+
else if (meridiem === 'pm' && hour < 12)
|
|
6513
|
+
hour24 = hour + 12;
|
|
6253
6514
|
const currentDateTime = selectedDateObj
|
|
6254
6515
|
.hour(hour24)
|
|
6255
6516
|
.minute(minute)
|
|
@@ -6314,83 +6575,54 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6314
6575
|
if (!trimmedValue) {
|
|
6315
6576
|
return;
|
|
6316
6577
|
}
|
|
6317
|
-
//
|
|
6318
|
-
const
|
|
6319
|
-
|
|
6320
|
-
// Matches: 1-2 digits hour, optional colon, 2 digits minute, am/pm
|
|
6321
|
-
const pattern12HourWithMeridiem = /^(\d{1,2}):?(\d{2})(am|pm)$/;
|
|
6322
|
-
const match12Hour = normalized.match(pattern12HourWithMeridiem);
|
|
6578
|
+
// Parse formats like "1:30 PM", "1:30PM", "1:30 pm", "1:30pm"
|
|
6579
|
+
const timePattern12Hour = /^(\d{1,2}):(\d{1,2})\s*(am|pm|AM|PM)$/i;
|
|
6580
|
+
const match12Hour = trimmedValue.match(timePattern12Hour);
|
|
6323
6581
|
if (match12Hour) {
|
|
6324
6582
|
const parsedHour = parseInt(match12Hour[1], 10);
|
|
6325
6583
|
const parsedMinute = parseInt(match12Hour[2], 10);
|
|
6326
|
-
const parsedMeridiem = match12Hour[3];
|
|
6327
|
-
// Validate
|
|
6328
|
-
if (parsedHour
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6584
|
+
const parsedMeridiem = match12Hour[3].toLowerCase();
|
|
6585
|
+
// Validate ranges
|
|
6586
|
+
if (parsedHour >= 1 &&
|
|
6587
|
+
parsedHour <= 12 &&
|
|
6588
|
+
parsedMinute >= 0 &&
|
|
6589
|
+
parsedMinute <= 59) {
|
|
6590
|
+
setHour(parsedHour);
|
|
6591
|
+
setMinute(parsedMinute);
|
|
6592
|
+
setMeridiem(parsedMeridiem);
|
|
6593
|
+
onChange({
|
|
6594
|
+
hour: parsedHour,
|
|
6595
|
+
minute: parsedMinute,
|
|
6596
|
+
meridiem: parsedMeridiem,
|
|
6597
|
+
});
|
|
6337
6598
|
return;
|
|
6338
6599
|
}
|
|
6339
|
-
setHour(parsedHour);
|
|
6340
|
-
setMinute(parsedMinute);
|
|
6341
|
-
setMeridiem(parsedMeridiem);
|
|
6342
|
-
onChange({
|
|
6343
|
-
hour: parsedHour,
|
|
6344
|
-
minute: parsedMinute,
|
|
6345
|
-
meridiem: parsedMeridiem,
|
|
6346
|
-
});
|
|
6347
|
-
return;
|
|
6348
6600
|
}
|
|
6349
|
-
//
|
|
6350
|
-
|
|
6351
|
-
const
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
//
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
}
|
|
6374
|
-
else if (parsedHour === 12) {
|
|
6375
|
-
parsedHour = 12;
|
|
6376
|
-
parsedMeridiem = 'pm';
|
|
6377
|
-
}
|
|
6378
|
-
else if (parsedHour > 12) {
|
|
6379
|
-
parsedHour = parsedHour - 12;
|
|
6380
|
-
parsedMeridiem = 'pm';
|
|
6381
|
-
}
|
|
6382
|
-
else {
|
|
6383
|
-
parsedMeridiem = 'am';
|
|
6601
|
+
// Try to parse formats like "130pm" or "130 pm" (without colon)
|
|
6602
|
+
const timePatternNoColon = /^(\d{1,4})\s*(am|pm|AM|PM)$/i;
|
|
6603
|
+
const matchNoColon = trimmedValue.match(timePatternNoColon);
|
|
6604
|
+
if (matchNoColon) {
|
|
6605
|
+
const numbersOnly = matchNoColon[1];
|
|
6606
|
+
const parsedMeridiem = matchNoColon[2].toLowerCase();
|
|
6607
|
+
if (numbersOnly.length >= 3) {
|
|
6608
|
+
const parsedHour = parseInt(numbersOnly.slice(0, -2), 10);
|
|
6609
|
+
const parsedMinute = parseInt(numbersOnly.slice(-2), 10);
|
|
6610
|
+
// Validate ranges
|
|
6611
|
+
if (parsedHour >= 1 &&
|
|
6612
|
+
parsedHour <= 12 &&
|
|
6613
|
+
parsedMinute >= 0 &&
|
|
6614
|
+
parsedMinute <= 59) {
|
|
6615
|
+
setHour(parsedHour);
|
|
6616
|
+
setMinute(parsedMinute);
|
|
6617
|
+
setMeridiem(parsedMeridiem);
|
|
6618
|
+
onChange({
|
|
6619
|
+
hour: parsedHour,
|
|
6620
|
+
minute: parsedMinute,
|
|
6621
|
+
meridiem: parsedMeridiem,
|
|
6622
|
+
});
|
|
6623
|
+
return;
|
|
6624
|
+
}
|
|
6384
6625
|
}
|
|
6385
|
-
setHour(parsedHour);
|
|
6386
|
-
setMinute(parsedMinute);
|
|
6387
|
-
setMeridiem(parsedMeridiem);
|
|
6388
|
-
onChange({
|
|
6389
|
-
hour: parsedHour,
|
|
6390
|
-
minute: parsedMinute,
|
|
6391
|
-
meridiem: parsedMeridiem,
|
|
6392
|
-
});
|
|
6393
|
-
return;
|
|
6394
6626
|
}
|
|
6395
6627
|
// Parse failed, select first result
|
|
6396
6628
|
selectFirstResult();
|
|
@@ -6437,17 +6669,17 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6437
6669
|
e.currentTarget?.blur();
|
|
6438
6670
|
}
|
|
6439
6671
|
};
|
|
6440
|
-
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:
|
|
6441
|
-
}
|
|
6672
|
+
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, {}) }) })] }) }));
|
|
6673
|
+
};
|
|
6442
6674
|
|
|
6443
6675
|
dayjs.extend(timezone);
|
|
6444
6676
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
6445
6677
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
6446
|
-
const { timezone, insideDialog } = useSchemaContext();
|
|
6678
|
+
const { timezone, insideDialog, timePickerLabels } = useSchemaContext();
|
|
6447
6679
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
|
|
6448
6680
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6449
6681
|
const colLabel = `${prefix}${column}`;
|
|
6450
|
-
const formI18n = useFormI18n
|
|
6682
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
6451
6683
|
const [open, setOpen] = React.useState(false);
|
|
6452
6684
|
const value = watch(colLabel);
|
|
6453
6685
|
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
@@ -6505,13 +6737,7 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
6505
6737
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6506
6738
|
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: () => {
|
|
6507
6739
|
setOpen(true);
|
|
6508
|
-
}, 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,
|
|
6509
|
-
am: translate.t(`common.am`, { defaultValue: 'AM' }),
|
|
6510
|
-
pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
|
|
6511
|
-
} }) }) }) })) : (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, meridiemLabel: {
|
|
6512
|
-
am: translate.t(`common.am`, { defaultValue: 'AM' }),
|
|
6513
|
-
pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
|
|
6514
|
-
} }) }) }) }) }))] }) }));
|
|
6740
|
+
}, 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 }) }) }) }) }))] }) }));
|
|
6515
6741
|
};
|
|
6516
6742
|
|
|
6517
6743
|
dayjs.extend(utc);
|
|
@@ -6645,7 +6871,10 @@ dayjs.extend(utc);
|
|
|
6645
6871
|
dayjs.extend(timezone);
|
|
6646
6872
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
|
|
6647
6873
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6648
|
-
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true,
|
|
6874
|
+
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, labels = {
|
|
6875
|
+
placeholder: 'HH:mm:ss',
|
|
6876
|
+
emptyMessage: 'No time found',
|
|
6877
|
+
}, }) {
|
|
6649
6878
|
// Generate time options (every 15 minutes, seconds always 0)
|
|
6650
6879
|
const timeOptions = React.useMemo(() => {
|
|
6651
6880
|
const options = [];
|
|
@@ -6908,7 +7137,7 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6908
7137
|
e.currentTarget?.blur();
|
|
6909
7138
|
}
|
|
6910
7139
|
};
|
|
6911
|
-
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:
|
|
7140
|
+
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, {}) }) })] }) }));
|
|
6912
7141
|
}
|
|
6913
7142
|
|
|
6914
7143
|
dayjs.extend(utc);
|
|
@@ -6931,7 +7160,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6931
7160
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
6932
7161
|
backButtonLabel: 'Back',
|
|
6933
7162
|
forwardButtonLabel: 'Next',
|
|
6934
|
-
}, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
7163
|
+
}, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
6935
7164
|
console.log('[DateTimePicker] Component initialized with props:', {
|
|
6936
7165
|
value,
|
|
6937
7166
|
format,
|
|
@@ -7377,7 +7606,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7377
7606
|
const dateObj = dayjs.tz(selectedDate, timezone);
|
|
7378
7607
|
return dateObj.isValid() ? dateObj.format('Z') : null;
|
|
7379
7608
|
}, [selectedDate, timezone]);
|
|
7380
|
-
return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4,
|
|
7609
|
+
return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4, children: [jsxRuntime.jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
|
|
7381
7610
|
if (date) {
|
|
7382
7611
|
handleDateChange(date);
|
|
7383
7612
|
}
|
|
@@ -7385,15 +7614,15 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
7385
7614
|
setSelectedDate('');
|
|
7386
7615
|
onChange?.(undefined);
|
|
7387
7616
|
}
|
|
7388
|
-
}, 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 })] }))] }));
|
|
7617
|
+
}, 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 })] }))] }));
|
|
7389
7618
|
}
|
|
7390
7619
|
|
|
7391
7620
|
dayjs.extend(utc);
|
|
7392
7621
|
dayjs.extend(timezone);
|
|
7393
7622
|
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
7394
7623
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
7395
|
-
const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
|
|
7396
|
-
const formI18n = useFormI18n
|
|
7624
|
+
const { timezone, dateTimePickerLabels, timePickerLabels, insideDialog } = useSchemaContext();
|
|
7625
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7397
7626
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
|
|
7398
7627
|
// with timezone
|
|
7399
7628
|
dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
|
|
@@ -7406,74 +7635,30 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7406
7635
|
: '';
|
|
7407
7636
|
const dateTimePickerLabelsConfig = {
|
|
7408
7637
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
formI18n.translate.t(`common.month_5`, {
|
|
7422
|
-
defaultValue: 'May',
|
|
7423
|
-
}),
|
|
7424
|
-
formI18n.translate.t(`common.month_6`, {
|
|
7425
|
-
defaultValue: 'June',
|
|
7426
|
-
}),
|
|
7427
|
-
formI18n.translate.t(`common.month_7`, {
|
|
7428
|
-
defaultValue: 'July',
|
|
7429
|
-
}),
|
|
7430
|
-
formI18n.translate.t(`common.month_8`, {
|
|
7431
|
-
defaultValue: 'August',
|
|
7432
|
-
}),
|
|
7433
|
-
formI18n.translate.t(`common.month_9`, {
|
|
7434
|
-
defaultValue: 'September',
|
|
7435
|
-
}),
|
|
7436
|
-
formI18n.translate.t(`common.month_10`, {
|
|
7437
|
-
defaultValue: 'October',
|
|
7438
|
-
}),
|
|
7439
|
-
formI18n.translate.t(`common.month_11`, {
|
|
7440
|
-
defaultValue: 'November',
|
|
7441
|
-
}),
|
|
7442
|
-
formI18n.translate.t(`common.month_12`, {
|
|
7443
|
-
defaultValue: 'December',
|
|
7444
|
-
}),
|
|
7638
|
+
'January',
|
|
7639
|
+
'February',
|
|
7640
|
+
'March',
|
|
7641
|
+
'April',
|
|
7642
|
+
'May',
|
|
7643
|
+
'June',
|
|
7644
|
+
'July',
|
|
7645
|
+
'August',
|
|
7646
|
+
'September',
|
|
7647
|
+
'October',
|
|
7648
|
+
'November',
|
|
7649
|
+
'December',
|
|
7445
7650
|
],
|
|
7446
7651
|
weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
defaultValue: 'Tue',
|
|
7455
|
-
}),
|
|
7456
|
-
formI18n.translate.t(`common.weekday_4`, {
|
|
7457
|
-
defaultValue: 'Wed',
|
|
7458
|
-
}),
|
|
7459
|
-
formI18n.translate.t(`common.weekday_5`, {
|
|
7460
|
-
defaultValue: 'Thu',
|
|
7461
|
-
}),
|
|
7462
|
-
formI18n.translate.t(`common.weekday_6`, {
|
|
7463
|
-
defaultValue: 'Fri',
|
|
7464
|
-
}),
|
|
7465
|
-
formI18n.translate.t(`common.weekday_7`, {
|
|
7466
|
-
defaultValue: 'Sat',
|
|
7467
|
-
}),
|
|
7652
|
+
'Sun',
|
|
7653
|
+
'Mon',
|
|
7654
|
+
'Tue',
|
|
7655
|
+
'Wed',
|
|
7656
|
+
'Thu',
|
|
7657
|
+
'Fri',
|
|
7658
|
+
'Sat',
|
|
7468
7659
|
],
|
|
7469
|
-
backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
|
|
7470
|
-
|
|
7471
|
-
defaultValue: 'Back',
|
|
7472
|
-
}),
|
|
7473
|
-
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
|
|
7474
|
-
formI18n.translate.t(`common.forward_button`, {
|
|
7475
|
-
defaultValue: 'Forward',
|
|
7476
|
-
}),
|
|
7660
|
+
backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
|
|
7661
|
+
forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
|
|
7477
7662
|
};
|
|
7478
7663
|
const dateTimePickerContent = (jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
7479
7664
|
if (!date || date === null || date === undefined) {
|
|
@@ -7487,7 +7672,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
7487
7672
|
else {
|
|
7488
7673
|
setValue(colLabel, undefined);
|
|
7489
7674
|
}
|
|
7490
|
-
}, timezone: timezone, labels: dateTimePickerLabelsConfig }));
|
|
7675
|
+
}, timezone: timezone, labels: dateTimePickerLabelsConfig, timePickerLabels: timePickerLabels }));
|
|
7491
7676
|
return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7492
7677
|
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: () => {
|
|
7493
7678
|
setOpen(true);
|
|
@@ -7506,7 +7691,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7506
7691
|
}
|
|
7507
7692
|
if (variant === 'id-picker') {
|
|
7508
7693
|
idPickerSanityCheck(column, foreign_key);
|
|
7509
|
-
return jsxRuntime.jsx(
|
|
7694
|
+
return jsxRuntime.jsx(IdPickerSingle, { schema: colSchema, prefix, column });
|
|
7510
7695
|
}
|
|
7511
7696
|
if (format === 'date') {
|
|
7512
7697
|
return jsxRuntime.jsx(DatePicker, { schema: colSchema, prefix, column });
|
|
@@ -7540,7 +7725,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
7540
7725
|
if (type === 'array') {
|
|
7541
7726
|
if (variant === 'id-picker') {
|
|
7542
7727
|
idPickerSanityCheck(column, foreign_key);
|
|
7543
|
-
return
|
|
7728
|
+
return jsxRuntime.jsx(IdPickerMultiple, { schema: colSchema, prefix, column });
|
|
7544
7729
|
}
|
|
7545
7730
|
if (variant === 'tag-picker') {
|
|
7546
7731
|
return jsxRuntime.jsx(TagPicker, { schema: colSchema, prefix, column });
|
|
@@ -7592,7 +7777,7 @@ const ArrayViewer = ({ schema, column, prefix }) => {
|
|
|
7592
7777
|
const { gridColumn = 'span 12', gridRow = 'span 1', required, items, } = schema;
|
|
7593
7778
|
const colLabel = `${prefix}${column}`;
|
|
7594
7779
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7595
|
-
const formI18n = useFormI18n
|
|
7780
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7596
7781
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
7597
7782
|
const values = watch(colLabel) ?? [];
|
|
7598
7783
|
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: {
|
|
@@ -7610,7 +7795,7 @@ const BooleanViewer = ({ schema, column, prefix, }) => {
|
|
|
7610
7795
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7611
7796
|
const colLabel = `${prefix}${column}`;
|
|
7612
7797
|
const value = watch(colLabel);
|
|
7613
|
-
const formI18n = useFormI18n
|
|
7798
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7614
7799
|
return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
7615
7800
|
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() }))] }));
|
|
7616
7801
|
};
|
|
@@ -7634,7 +7819,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7634
7819
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7635
7820
|
const colLabel = `${prefix}${column}`;
|
|
7636
7821
|
const selectedDate = watch(colLabel);
|
|
7637
|
-
const formI18n = useFormI18n
|
|
7822
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7638
7823
|
const displayDate = dayjs(selectedDate)
|
|
7639
7824
|
.tz(timezone)
|
|
7640
7825
|
.format(displayDateFormat);
|
|
@@ -7644,7 +7829,7 @@ const DateViewer = ({ column, schema, prefix }) => {
|
|
|
7644
7829
|
|
|
7645
7830
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
7646
7831
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
7647
|
-
const formI18n = useFormI18n
|
|
7832
|
+
const formI18n = useFormI18n(column, prefix);
|
|
7648
7833
|
const { required } = schema;
|
|
7649
7834
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7650
7835
|
const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
|
|
@@ -7668,7 +7853,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7668
7853
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
|
|
7669
7854
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7670
7855
|
const currentFiles = (watch(column) ?? []);
|
|
7671
|
-
const formI18n = useFormI18n
|
|
7856
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7672
7857
|
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) => {
|
|
7673
7858
|
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));
|
|
7674
7859
|
}) }) }));
|
|
@@ -7676,7 +7861,7 @@ const FileViewer = ({ column, schema, prefix }) => {
|
|
|
7676
7861
|
|
|
7677
7862
|
const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
7678
7863
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
7679
|
-
const { idMap,
|
|
7864
|
+
const { idMap, idPickerLabels, formButtonLabels } = useSchemaContext();
|
|
7680
7865
|
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
7681
7866
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7682
7867
|
const formI18n = useFormI18n(column, prefix, schema);
|
|
@@ -7700,12 +7885,12 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
7700
7885
|
gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, children: watchIds.map((id) => {
|
|
7701
7886
|
const item = idMap[id];
|
|
7702
7887
|
if (item === undefined) {
|
|
7703
|
-
return (jsxRuntime.jsx(react.Text, { children:
|
|
7888
|
+
return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? 'Undefined' }, id));
|
|
7704
7889
|
}
|
|
7705
7890
|
return (jsxRuntime.jsx(Tag, { closable: true, children: renderDisplay
|
|
7706
7891
|
? renderDisplay(item)
|
|
7707
7892
|
: defaultRenderDisplay(item) }, id));
|
|
7708
|
-
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children:
|
|
7893
|
+
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formButtonLabels?.fieldRequired ?? formI18n.required() }))] }));
|
|
7709
7894
|
};
|
|
7710
7895
|
|
|
7711
7896
|
const NumberViewer = ({ schema, column, prefix, }) => {
|
|
@@ -7714,7 +7899,7 @@ const NumberViewer = ({ schema, column, prefix, }) => {
|
|
|
7714
7899
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7715
7900
|
const colLabel = `${prefix}${column}`;
|
|
7716
7901
|
const value = watch(colLabel);
|
|
7717
|
-
const formI18n = useFormI18n
|
|
7902
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7718
7903
|
// Format the value for display if formatOptions are provided
|
|
7719
7904
|
const formatValue = (val) => {
|
|
7720
7905
|
if (val === undefined || val === null || val === '')
|
|
@@ -7740,7 +7925,7 @@ const ObjectViewer = ({ schema, column, prefix }) => {
|
|
|
7740
7925
|
const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
|
|
7741
7926
|
const colLabel = `${prefix}${column}`;
|
|
7742
7927
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7743
|
-
const formI18n = useFormI18n
|
|
7928
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7744
7929
|
const { formState: { errors }, } = reactHookForm.useFormContext();
|
|
7745
7930
|
if (properties === undefined) {
|
|
7746
7931
|
throw new Error(`properties is undefined when using ObjectInput`);
|
|
@@ -7762,7 +7947,7 @@ const RecordViewer = ({ column, schema, prefix }) => {
|
|
|
7762
7947
|
const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
|
|
7763
7948
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7764
7949
|
const entries = Object.entries(getValues(column) ?? {});
|
|
7765
|
-
const formI18n = useFormI18n
|
|
7950
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7766
7951
|
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]) => {
|
|
7767
7952
|
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));
|
|
7768
7953
|
}) })), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
@@ -7774,7 +7959,7 @@ const StringViewer = ({ column, schema, prefix, }) => {
|
|
|
7774
7959
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7775
7960
|
const colLabel = `${prefix}${column}`;
|
|
7776
7961
|
const value = watch(colLabel);
|
|
7777
|
-
const formI18n = useFormI18n
|
|
7962
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7778
7963
|
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() }))] }) }));
|
|
7779
7964
|
};
|
|
7780
7965
|
|
|
@@ -7869,7 +8054,7 @@ const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
|
7869
8054
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7870
8055
|
const colLabel = `${prefix}${column}`;
|
|
7871
8056
|
const value = watch(colLabel);
|
|
7872
|
-
const formI18n = useFormI18n
|
|
8057
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7873
8058
|
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() }))] }) }));
|
|
7874
8059
|
};
|
|
7875
8060
|
|
|
@@ -7880,7 +8065,7 @@ const TimeViewer = ({ column, schema, prefix }) => {
|
|
|
7880
8065
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7881
8066
|
const colLabel = `${prefix}${column}`;
|
|
7882
8067
|
const selectedDate = watch(colLabel);
|
|
7883
|
-
const formI18n = useFormI18n
|
|
8068
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7884
8069
|
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
7885
8070
|
.tz(timezone)
|
|
7886
8071
|
.isValid()
|
|
@@ -7897,7 +8082,7 @@ const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
|
7897
8082
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
7898
8083
|
const colLabel = `${prefix}${column}`;
|
|
7899
8084
|
const selectedDate = watch(colLabel);
|
|
7900
|
-
const formI18n = useFormI18n
|
|
8085
|
+
const formI18n = useFormI18n(column, prefix, schema);
|
|
7901
8086
|
const displayDate = dayjs(selectedDate)
|
|
7902
8087
|
.tz(timezone)
|
|
7903
8088
|
.format(displayDateFormat);
|
|
@@ -7991,7 +8176,7 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
7991
8176
|
};
|
|
7992
8177
|
|
|
7993
8178
|
const SubmitButton = () => {
|
|
7994
|
-
const {
|
|
8179
|
+
const { setValidatedData, setIsError, setIsConfirming, requireConfirmation, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
7995
8180
|
const methods = reactHookForm.useFormContext();
|
|
7996
8181
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7997
8182
|
const onValid = (data) => {
|
|
@@ -8020,11 +8205,11 @@ const SubmitButton = () => {
|
|
|
8020
8205
|
};
|
|
8021
8206
|
return (jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8022
8207
|
methods.handleSubmit(onValid)();
|
|
8023
|
-
}, formNoValidate: true, children: formButtonLabels?.submit ??
|
|
8208
|
+
}, formNoValidate: true, children: formButtonLabels?.submit ?? 'Submit' }));
|
|
8024
8209
|
};
|
|
8025
8210
|
|
|
8026
8211
|
const FormBody = () => {
|
|
8027
|
-
const { schema, order, ignore, include,
|
|
8212
|
+
const { schema, order, ignore, include, isError, isSubmiting, isConfirming, setIsConfirming, validatedData, error, customErrorRenderer, displayConfig, onFormSubmit, formButtonLabels, } = useSchemaContext();
|
|
8028
8213
|
const { showSubmitButton, showResetButton } = displayConfig;
|
|
8029
8214
|
const methods = reactHookForm.useFormContext();
|
|
8030
8215
|
const { properties } = schema;
|
|
@@ -8041,21 +8226,6 @@ const FormBody = () => {
|
|
|
8041
8226
|
ignore,
|
|
8042
8227
|
include,
|
|
8043
8228
|
});
|
|
8044
|
-
if (isSuccess) {
|
|
8045
|
-
const resetHandler = async () => {
|
|
8046
|
-
setIsError(false);
|
|
8047
|
-
setIsSubmiting(false);
|
|
8048
|
-
setIsSuccess(false);
|
|
8049
|
-
setIsConfirming(false);
|
|
8050
|
-
setValidatedData(undefined);
|
|
8051
|
-
const data = await getUpdatedData();
|
|
8052
|
-
methods.reset(data);
|
|
8053
|
-
};
|
|
8054
|
-
if (customSuccessRenderer) {
|
|
8055
|
-
return customSuccessRenderer(resetHandler);
|
|
8056
|
-
}
|
|
8057
|
-
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') }) })] }));
|
|
8058
|
-
}
|
|
8059
8229
|
if (isConfirming) {
|
|
8060
8230
|
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) => {
|
|
8061
8231
|
return (jsxRuntime.jsx(ColumnViewer
|
|
@@ -8065,9 +8235,9 @@ const FormBody = () => {
|
|
|
8065
8235
|
properties: properties, prefix: ``, column }, `form-viewer-${column}`));
|
|
8066
8236
|
}) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: '2', children: [jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8067
8237
|
setIsConfirming(false);
|
|
8068
|
-
}, variant: 'subtle', children: formButtonLabels?.cancel ??
|
|
8238
|
+
}, variant: 'subtle', children: formButtonLabels?.cancel ?? 'Cancel' }), jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8069
8239
|
onFormSubmit(validatedData);
|
|
8070
|
-
}, children: formButtonLabels?.confirm ??
|
|
8240
|
+
}, 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)] }));
|
|
8071
8241
|
}
|
|
8072
8242
|
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) => {
|
|
8073
8243
|
return (jsxRuntime.jsx(ColumnRenderer
|
|
@@ -8077,12 +8247,12 @@ const FormBody = () => {
|
|
|
8077
8247
|
properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
|
|
8078
8248
|
}) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
8079
8249
|
methods.reset();
|
|
8080
|
-
}, variant: 'subtle', children: formButtonLabels?.reset ??
|
|
8250
|
+
}, variant: 'subtle', children: formButtonLabels?.reset ?? 'Reset' })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
|
|
8081
8251
|
};
|
|
8082
8252
|
|
|
8083
8253
|
const FormTitle = () => {
|
|
8084
|
-
const {
|
|
8085
|
-
return jsxRuntime.jsx(react.Heading, { children:
|
|
8254
|
+
const { schema } = useSchemaContext();
|
|
8255
|
+
return jsxRuntime.jsx(react.Heading, { children: schema.title ?? 'Form' });
|
|
8086
8256
|
};
|
|
8087
8257
|
|
|
8088
8258
|
const DefaultForm = ({ formConfig, }) => {
|
|
@@ -8090,7 +8260,9 @@ const DefaultForm = ({ formConfig, }) => {
|
|
|
8090
8260
|
return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
|
|
8091
8261
|
};
|
|
8092
8262
|
|
|
8093
|
-
const useForm = ({ preLoadedValues, keyPrefix
|
|
8263
|
+
const useForm = ({ preLoadedValues, keyPrefix: _keyPrefix, // Deprecated: kept for backward compatibility
|
|
8264
|
+
namespace: _namespace, // Deprecated: kept for backward compatibility
|
|
8265
|
+
schema, }) => {
|
|
8094
8266
|
const form = reactHookForm.useForm({
|
|
8095
8267
|
values: preLoadedValues,
|
|
8096
8268
|
resolver: schema ? ajvResolver(schema) : undefined,
|
|
@@ -8098,12 +8270,16 @@ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
|
|
|
8098
8270
|
reValidateMode: 'onBlur',
|
|
8099
8271
|
});
|
|
8100
8272
|
const [idMap, setIdMap] = React.useState({});
|
|
8101
|
-
|
|
8273
|
+
// Fallback translate object - returns key as-is (no i18n required)
|
|
8274
|
+
const translate = {
|
|
8275
|
+
t: (key) => key,
|
|
8276
|
+
ready: true,
|
|
8277
|
+
};
|
|
8102
8278
|
return {
|
|
8103
8279
|
form,
|
|
8104
8280
|
idMap,
|
|
8105
8281
|
setIdMap,
|
|
8106
|
-
translate,
|
|
8282
|
+
translate, // Components prefer label objects over translate
|
|
8107
8283
|
};
|
|
8108
8284
|
};
|
|
8109
8285
|
|
|
@@ -8431,6 +8607,21 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
|
|
|
8431
8607
|
})] }));
|
|
8432
8608
|
};
|
|
8433
8609
|
|
|
8610
|
+
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 = {}, }) => {
|
|
8611
|
+
const { tableLabel, table } = useDataTableContext();
|
|
8612
|
+
const { hasErrorText } = tableLabel;
|
|
8613
|
+
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) => {
|
|
8614
|
+
const { column, options } = option;
|
|
8615
|
+
const tableColumn = table.getColumn(column);
|
|
8616
|
+
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) => {
|
|
8617
|
+
if (tags.length === 0) {
|
|
8618
|
+
return tableColumn?.setFilterValue(undefined);
|
|
8619
|
+
}
|
|
8620
|
+
tableColumn?.setFilterValue(tags);
|
|
8621
|
+
} })] }, column));
|
|
8622
|
+
}) })), 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, {}) }))] }))] }));
|
|
8623
|
+
};
|
|
8624
|
+
|
|
8434
8625
|
const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
|
|
8435
8626
|
'use no memo';
|
|
8436
8627
|
const { table } = useDataTableContext();
|
|
@@ -8490,22 +8681,77 @@ const TableRowSelectorSkeleton = () => {
|
|
|
8490
8681
|
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` }) }));
|
|
8491
8682
|
};
|
|
8492
8683
|
|
|
8493
|
-
const
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
return
|
|
8497
|
-
|
|
8498
|
-
|
|
8684
|
+
const MobileTableDisplay = ({ showSelector = false, isLoading = false, }) => {
|
|
8685
|
+
const { table, rowSelection, setRowSelection } = useDataTableContext();
|
|
8686
|
+
if (isLoading) {
|
|
8687
|
+
return jsxRuntime.jsx(MobileTableSkeleton, { showSelector: showSelector });
|
|
8688
|
+
}
|
|
8689
|
+
return (jsxRuntime.jsx(react.Stack, { gap: 4, padding: 2, children: table.getRowModel().rows.map((row) => {
|
|
8690
|
+
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),
|
|
8691
|
+
disabled: !canRowSelect(row),
|
|
8692
|
+
onCheckedChange: createRowToggleHandler(row, rowSelection, setRowSelection) }) })), jsxRuntime.jsx(react.Stack, { gap: 3, children: row.getVisibleCells().map((cell) => {
|
|
8693
|
+
const displayName = cell.column.columnDef.meta?.displayName ?? cell.column.id;
|
|
8694
|
+
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}`));
|
|
8695
|
+
}) })] }) }, `mobile-table-card-${row.id}`));
|
|
8696
|
+
}) }));
|
|
8697
|
+
};
|
|
8698
|
+
const MobileTableSkeleton = ({ showSelector = false, }) => {
|
|
8699
|
+
const { table } = useDataTableContext();
|
|
8700
|
+
const pageSize = table.getState().pagination.pageSize;
|
|
8701
|
+
const visibleColumns = table.getVisibleLeafColumns();
|
|
8702
|
+
return (jsxRuntime.jsx(react.Stack, { gap: 4, padding: 2, children: Array.from({ length: pageSize }).map((_, rowIndex) => {
|
|
8703
|
+
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) => {
|
|
8704
|
+
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}`));
|
|
8705
|
+
}) })] }) }, `mobile-skeleton-${rowIndex}`));
|
|
8706
|
+
}) }));
|
|
8707
|
+
};
|
|
8708
|
+
|
|
8709
|
+
/**
|
|
8710
|
+
* Hook to detect if the current window width is mobile (< 768px)
|
|
8711
|
+
* @param breakpoint - The breakpoint in pixels to consider as mobile (default: 768)
|
|
8712
|
+
* @returns boolean indicating if the window is mobile
|
|
8713
|
+
*/
|
|
8714
|
+
const useIsMobile = (breakpoint = 768) => {
|
|
8715
|
+
const [isMobile, setIsMobile] = React.useState(() => {
|
|
8716
|
+
if (typeof window === 'undefined')
|
|
8717
|
+
return false;
|
|
8718
|
+
return window.innerWidth < breakpoint;
|
|
8719
|
+
});
|
|
8720
|
+
React.useEffect(() => {
|
|
8721
|
+
if (typeof window === 'undefined')
|
|
8722
|
+
return;
|
|
8723
|
+
const handleResize = () => {
|
|
8724
|
+
setIsMobile(window.innerWidth < breakpoint);
|
|
8725
|
+
};
|
|
8726
|
+
// Set initial value
|
|
8727
|
+
handleResize();
|
|
8728
|
+
// Add event listener
|
|
8729
|
+
window.addEventListener('resize', handleResize);
|
|
8730
|
+
// Cleanup
|
|
8731
|
+
return () => {
|
|
8732
|
+
window.removeEventListener('resize', handleResize);
|
|
8733
|
+
};
|
|
8734
|
+
}, [breakpoint]);
|
|
8735
|
+
return isMobile;
|
|
8736
|
+
};
|
|
8737
|
+
|
|
8738
|
+
const DefaultTable = ({ showFooter = false, showHeader = true, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = 'greedy', isLoading = false, }) => {
|
|
8739
|
+
const isMobile = useIsMobile();
|
|
8740
|
+
// Early return for mobile display
|
|
8741
|
+
if (isMobile) {
|
|
8742
|
+
return (jsxRuntime.jsx(MobileTableControls, { ...controlProps, children: jsxRuntime.jsx(MobileTableDisplay, { showSelector: tableHeaderProps.showSelector ??
|
|
8499
8743
|
tableBodyProps.showSelector ??
|
|
8500
|
-
false,
|
|
8501
|
-
...tableProps, children: [jsxRuntime.jsx(TableHeader, { canResize: false, ...tableHeaderProps }), bodyComponent, showFooter && (jsxRuntime.jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
|
|
8744
|
+
false, isLoading: isLoading }) }));
|
|
8502
8745
|
}
|
|
8503
|
-
const
|
|
8504
|
-
|
|
8746
|
+
const isGreedy = variant === 'greedy';
|
|
8747
|
+
const canResize = !isGreedy;
|
|
8748
|
+
const bodyComponent = isLoading ? (jsxRuntime.jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: canResize })) : (jsxRuntime.jsx(TableBody, { ...tableBodyProps, canResize: canResize }));
|
|
8749
|
+
return (jsxRuntime.jsx(TableControls, { ...controlProps, children: jsxRuntime.jsxs(Table, { canResize,
|
|
8750
|
+
showLoading: isLoading,
|
|
8505
8751
|
showSelector: tableHeaderProps.showSelector ??
|
|
8506
8752
|
tableBodyProps.showSelector ??
|
|
8507
8753
|
false,
|
|
8508
|
-
...tableProps, children: [jsxRuntime.jsx(TableHeader, { ...tableHeaderProps }), bodyComponent, showFooter && jsxRuntime.jsx(TableFooter, { ...tableFooterProps })] }) }));
|
|
8754
|
+
...tableProps, children: [showHeader && jsxRuntime.jsx(TableHeader, { canResize, ...tableHeaderProps }), bodyComponent, showFooter && jsxRuntime.jsx(TableFooter, { canResize, ...tableFooterProps })] }) }));
|
|
8509
8755
|
};
|
|
8510
8756
|
|
|
8511
8757
|
/**
|
|
@@ -8597,6 +8843,290 @@ const DataDisplay = ({ variant = '' }) => {
|
|
|
8597
8843
|
}) }));
|
|
8598
8844
|
};
|
|
8599
8845
|
|
|
8846
|
+
// Helper function to normalize date
|
|
8847
|
+
function normalizeDate(value) {
|
|
8848
|
+
if (!value)
|
|
8849
|
+
return null;
|
|
8850
|
+
if (value instanceof Date)
|
|
8851
|
+
return value;
|
|
8852
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
8853
|
+
const date = dayjs(value).toDate();
|
|
8854
|
+
return isNaN(date.getTime()) ? null : date;
|
|
8855
|
+
}
|
|
8856
|
+
return null;
|
|
8857
|
+
}
|
|
8858
|
+
// Component to conditionally render event title based on available width
|
|
8859
|
+
function ResponsiveEventTitle({ title, placeholder, minWidth, minChars, cellRef, }) {
|
|
8860
|
+
const [truncatedText, setTruncatedText] = React.useState('');
|
|
8861
|
+
const measureRef = React.useRef(null);
|
|
8862
|
+
React.useEffect(() => {
|
|
8863
|
+
const calculateTruncatedText = () => {
|
|
8864
|
+
if (!cellRef.current || !measureRef.current || !title) {
|
|
8865
|
+
setTruncatedText(title || 'Event');
|
|
8866
|
+
return;
|
|
8867
|
+
}
|
|
8868
|
+
const cellWidth = cellRef.current.clientWidth;
|
|
8869
|
+
// Account for padding (approximately 8px on each side)
|
|
8870
|
+
const availableWidth = cellWidth - 16;
|
|
8871
|
+
// If cell is too narrow, calculate how many characters can fit
|
|
8872
|
+
if (availableWidth < minWidth) {
|
|
8873
|
+
// Measure text width using canvas
|
|
8874
|
+
const canvas = document.createElement('canvas');
|
|
8875
|
+
const context = canvas.getContext('2d');
|
|
8876
|
+
if (!context) {
|
|
8877
|
+
setTruncatedText(placeholder);
|
|
8878
|
+
return;
|
|
8879
|
+
}
|
|
8880
|
+
// Get computed font style from the element
|
|
8881
|
+
const computedStyle = window.getComputedStyle(measureRef.current);
|
|
8882
|
+
context.font = `${computedStyle.fontWeight} ${computedStyle.fontSize} ${computedStyle.fontFamily}`;
|
|
8883
|
+
const ellipsisWidth = context.measureText('...').width;
|
|
8884
|
+
const maxWidth = availableWidth - ellipsisWidth;
|
|
8885
|
+
// Try to show at least minChars characters before ellipsis
|
|
8886
|
+
let truncated = '';
|
|
8887
|
+
let charCount = 0;
|
|
8888
|
+
// Calculate how many characters can fit
|
|
8889
|
+
for (let i = 0; i < Math.min(title.length, 50); i++) {
|
|
8890
|
+
const testText = title.substring(0, i + 1);
|
|
8891
|
+
const textWidth = context.measureText(testText).width;
|
|
8892
|
+
if (textWidth <= maxWidth) {
|
|
8893
|
+
truncated = testText;
|
|
8894
|
+
charCount = i + 1;
|
|
8895
|
+
}
|
|
8896
|
+
else {
|
|
8897
|
+
break;
|
|
8898
|
+
}
|
|
8899
|
+
}
|
|
8900
|
+
// Ensure we show at least minChars characters if possible
|
|
8901
|
+
if (charCount < minChars && title.length >= minChars) {
|
|
8902
|
+
truncated = title.substring(0, minChars);
|
|
8903
|
+
}
|
|
8904
|
+
else if (charCount === 0 && title.length >= 1) {
|
|
8905
|
+
truncated = title.substring(0, 1);
|
|
8906
|
+
}
|
|
8907
|
+
// Only show ellipsis if we have at least minChars characters
|
|
8908
|
+
if (truncated && truncated.length >= minChars) {
|
|
8909
|
+
setTruncatedText(`${truncated}...`);
|
|
8910
|
+
}
|
|
8911
|
+
else {
|
|
8912
|
+
setTruncatedText(placeholder);
|
|
8913
|
+
}
|
|
8914
|
+
}
|
|
8915
|
+
else {
|
|
8916
|
+
// Full width available, show full title
|
|
8917
|
+
setTruncatedText(title);
|
|
8918
|
+
}
|
|
8919
|
+
};
|
|
8920
|
+
calculateTruncatedText();
|
|
8921
|
+
const resizeObserver = new ResizeObserver(calculateTruncatedText);
|
|
8922
|
+
if (cellRef.current) {
|
|
8923
|
+
resizeObserver.observe(cellRef.current);
|
|
8924
|
+
}
|
|
8925
|
+
// Also check on window resize
|
|
8926
|
+
window.addEventListener('resize', calculateTruncatedText);
|
|
8927
|
+
return () => {
|
|
8928
|
+
resizeObserver.disconnect();
|
|
8929
|
+
window.removeEventListener('resize', calculateTruncatedText);
|
|
8930
|
+
};
|
|
8931
|
+
}, [cellRef, minWidth, title, placeholder]);
|
|
8932
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { ref: measureRef, style: {
|
|
8933
|
+
visibility: 'hidden',
|
|
8934
|
+
position: 'absolute',
|
|
8935
|
+
whiteSpace: 'nowrap',
|
|
8936
|
+
}, children: title || 'Event' }), truncatedText || title || 'Event'] }));
|
|
8937
|
+
}
|
|
8938
|
+
function CalendarDisplay({ dateColumn, getDate, getEventTitle, getEventColor, renderEvent, firstDayOfWeek = 0, showOutsideDays = true, monthsToDisplay = 1, labels = {
|
|
8939
|
+
monthNamesShort: [
|
|
8940
|
+
'Jan',
|
|
8941
|
+
'Feb',
|
|
8942
|
+
'Mar',
|
|
8943
|
+
'Apr',
|
|
8944
|
+
'May',
|
|
8945
|
+
'Jun',
|
|
8946
|
+
'Jul',
|
|
8947
|
+
'Aug',
|
|
8948
|
+
'Sep',
|
|
8949
|
+
'Oct',
|
|
8950
|
+
'Nov',
|
|
8951
|
+
'Dec',
|
|
8952
|
+
],
|
|
8953
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
8954
|
+
backButtonLabel: 'Back',
|
|
8955
|
+
forwardButtonLabel: 'Next',
|
|
8956
|
+
}, onDateClick, onEventClick, maxEventsPerDay = 3, colorPalette = 'blue', eventPlaceholder = '...', minEventWidth = 80, minCharsBeforeEllipsis = 2, }) {
|
|
8957
|
+
const { data, table } = useDataTableContext();
|
|
8958
|
+
// Map table data to events
|
|
8959
|
+
const events = React.useMemo(() => {
|
|
8960
|
+
return data
|
|
8961
|
+
.map((row) => {
|
|
8962
|
+
let dateValue;
|
|
8963
|
+
if (getDate) {
|
|
8964
|
+
dateValue = getDate(row);
|
|
8965
|
+
}
|
|
8966
|
+
else {
|
|
8967
|
+
// Try to get date from column
|
|
8968
|
+
const rowData = table
|
|
8969
|
+
.getRowModel()
|
|
8970
|
+
.rows.find((r) => r.original === row);
|
|
8971
|
+
if (rowData) {
|
|
8972
|
+
const cell = rowData.getAllCells().find((c) => {
|
|
8973
|
+
const colId = c.column.id;
|
|
8974
|
+
const accessorKey = c.column.columnDef.accessorKey;
|
|
8975
|
+
return colId === dateColumn || accessorKey === dateColumn;
|
|
8976
|
+
});
|
|
8977
|
+
dateValue = cell?.getValue();
|
|
8978
|
+
}
|
|
8979
|
+
}
|
|
8980
|
+
const date = normalizeDate(dateValue);
|
|
8981
|
+
if (!date)
|
|
8982
|
+
return null;
|
|
8983
|
+
let title;
|
|
8984
|
+
if (getEventTitle) {
|
|
8985
|
+
title = getEventTitle(row);
|
|
8986
|
+
}
|
|
8987
|
+
else {
|
|
8988
|
+
// Use first column's value as title
|
|
8989
|
+
const rowData = table
|
|
8990
|
+
.getRowModel()
|
|
8991
|
+
.rows.find((r) => r.original === row);
|
|
8992
|
+
if (rowData) {
|
|
8993
|
+
const firstCell = rowData.getAllCells()[0];
|
|
8994
|
+
title = String(firstCell?.getValue() ?? '');
|
|
8995
|
+
}
|
|
8996
|
+
}
|
|
8997
|
+
const color = getEventColor?.(row);
|
|
8998
|
+
return {
|
|
8999
|
+
data: row,
|
|
9000
|
+
date,
|
|
9001
|
+
title,
|
|
9002
|
+
color,
|
|
9003
|
+
};
|
|
9004
|
+
})
|
|
9005
|
+
.filter((event) => event !== null);
|
|
9006
|
+
}, [data, table, dateColumn, getDate, getEventTitle, getEventColor]);
|
|
9007
|
+
// Group events by date
|
|
9008
|
+
const eventsByDate = React.useMemo(() => {
|
|
9009
|
+
const map = new Map();
|
|
9010
|
+
events.forEach((event) => {
|
|
9011
|
+
const dateKey = `${event.date.getFullYear()}-${event.date.getMonth()}-${event.date.getDate()}`;
|
|
9012
|
+
if (!map.has(dateKey)) {
|
|
9013
|
+
map.set(dateKey, []);
|
|
9014
|
+
}
|
|
9015
|
+
map.get(dateKey).push(event);
|
|
9016
|
+
});
|
|
9017
|
+
return map;
|
|
9018
|
+
}, [events]);
|
|
9019
|
+
// Get events for a specific date
|
|
9020
|
+
const getEventsForDate = React.useCallback((date) => {
|
|
9021
|
+
const dateKey = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
|
9022
|
+
return eventsByDate.get(dateKey) ?? [];
|
|
9023
|
+
}, [eventsByDate]);
|
|
9024
|
+
const calendarData = useCalendar({
|
|
9025
|
+
firstDayOfWeek,
|
|
9026
|
+
showOutsideDays,
|
|
9027
|
+
monthsToDisplay,
|
|
9028
|
+
});
|
|
9029
|
+
const getDateProps = React.useCallback((props) => {
|
|
9030
|
+
const dateEvents = getEventsForDate(props.dateObj.date);
|
|
9031
|
+
const baseProps = calendarData.getDateProps({ dateObj: props.dateObj });
|
|
9032
|
+
return {
|
|
9033
|
+
...baseProps,
|
|
9034
|
+
onClick: () => {
|
|
9035
|
+
baseProps.onClick?.();
|
|
9036
|
+
if (onDateClick) {
|
|
9037
|
+
onDateClick(props.dateObj.date, dateEvents);
|
|
9038
|
+
}
|
|
9039
|
+
},
|
|
9040
|
+
};
|
|
9041
|
+
}, [calendarData, getEventsForDate, onDateClick]);
|
|
9042
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
|
|
9043
|
+
if (!calendarData.calendars.length) {
|
|
9044
|
+
return null;
|
|
9045
|
+
}
|
|
9046
|
+
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({
|
|
9047
|
+
calendars: calendarData.calendars,
|
|
9048
|
+
offset: 12,
|
|
9049
|
+
}), children: '<<' }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...calendarData.getBackProps({ calendars: calendarData.calendars }), children: backButtonLabel }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9050
|
+
calendars: calendarData.calendars,
|
|
9051
|
+
}), children: forwardButtonLabel }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...calendarData.getForwardProps({
|
|
9052
|
+
calendars: calendarData.calendars,
|
|
9053
|
+
offset: 12,
|
|
9054
|
+
}), children: '>>' })] }), jsxRuntime.jsx(react.Grid, { templateColumns: {
|
|
9055
|
+
base: '1fr',
|
|
9056
|
+
md: monthsToDisplay >= 2 ? 'repeat(2, 1fr)' : '1fr',
|
|
9057
|
+
lg: monthsToDisplay >= 3
|
|
9058
|
+
? 'repeat(3, 1fr)'
|
|
9059
|
+
: monthsToDisplay === 2
|
|
9060
|
+
? 'repeat(2, 1fr)'
|
|
9061
|
+
: '1fr',
|
|
9062
|
+
xl: `repeat(${Math.min(monthsToDisplay, 4)}, 1fr)`,
|
|
9063
|
+
}, 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) => {
|
|
9064
|
+
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
9065
|
+
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}`));
|
|
9066
|
+
}) }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(7, 1fr)", gap: { base: 0.5, md: 1 }, children: calendar.weeks.map((week, weekIndex) => week.map((dateObj, index) => {
|
|
9067
|
+
const key = `${calendar.month}${calendar.year}${weekIndex}${index}`;
|
|
9068
|
+
if (!dateObj) {
|
|
9069
|
+
return jsxRuntime.jsx(react.Box, {}, key);
|
|
9070
|
+
}
|
|
9071
|
+
const { date, today, isCurrentMonth } = dateObj;
|
|
9072
|
+
const dateEvents = getEventsForDate(date);
|
|
9073
|
+
const cellRef = React.useRef(null);
|
|
9074
|
+
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: {
|
|
9075
|
+
base: today ? `${colorPalette}.300` : 'gray.200',
|
|
9076
|
+
_dark: today ? `${colorPalette}.700` : 'gray.700',
|
|
9077
|
+
}, borderRadius: { base: 'sm', md: 'md' }, padding: { base: 0.5, md: 1 }, bgColor: {
|
|
9078
|
+
base: today ? `${colorPalette}.50` : 'white',
|
|
9079
|
+
_dark: today ? `${colorPalette}.950` : 'gray.900',
|
|
9080
|
+
}, opacity: isCurrentMonth ? 1 : 0.5, ...getDateProps({ dateObj }), cursor: onDateClick ? 'pointer' : 'default', _hover: onDateClick
|
|
9081
|
+
? {
|
|
9082
|
+
bgColor: {
|
|
9083
|
+
base: `${colorPalette}.100`,
|
|
9084
|
+
_dark: `${colorPalette}.900`,
|
|
9085
|
+
},
|
|
9086
|
+
}
|
|
9087
|
+
: {}, children: [jsxRuntime.jsx(react.Text, { fontSize: { base: 'xs', md: 'sm' }, fontWeight: today ? 'bold' : 'normal', color: {
|
|
9088
|
+
base: today ? `${colorPalette}.700` : 'gray.700',
|
|
9089
|
+
_dark: today ? `${colorPalette}.300` : 'gray.300',
|
|
9090
|
+
}, 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
|
|
9091
|
+
.slice(0, maxEventsPerDay)
|
|
9092
|
+
.map((event, eventIndex) => {
|
|
9093
|
+
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: {
|
|
9094
|
+
base: event.color
|
|
9095
|
+
? `${event.color}.100`
|
|
9096
|
+
: `${colorPalette}.100`,
|
|
9097
|
+
_dark: event.color
|
|
9098
|
+
? `${event.color}.900`
|
|
9099
|
+
: `${colorPalette}.900`,
|
|
9100
|
+
}, color: {
|
|
9101
|
+
base: event.color
|
|
9102
|
+
? `${event.color}.800`
|
|
9103
|
+
: `${colorPalette}.800`,
|
|
9104
|
+
_dark: event.color
|
|
9105
|
+
? `${event.color}.200`
|
|
9106
|
+
: `${colorPalette}.200`,
|
|
9107
|
+
}, onClick: (e) => {
|
|
9108
|
+
e.stopPropagation();
|
|
9109
|
+
if (onEventClick) {
|
|
9110
|
+
onEventClick(event);
|
|
9111
|
+
}
|
|
9112
|
+
}, cursor: onEventClick ? 'pointer' : 'default', _hover: onEventClick
|
|
9113
|
+
? {
|
|
9114
|
+
opacity: 0.8,
|
|
9115
|
+
}
|
|
9116
|
+
: {}, children: jsxRuntime.jsx(ResponsiveEventTitle, { title: event.title, placeholder: eventPlaceholder, minWidth: minEventWidth, minChars: minCharsBeforeEllipsis, cellRef: cellRef }) }, eventIndex));
|
|
9117
|
+
return (jsxRuntime.jsx(react.Box, { onClick: (e) => e.stopPropagation(), children: eventContent }, eventIndex));
|
|
9118
|
+
}), dateEvents.length > maxEventsPerDay && (jsxRuntime.jsxs(react.Text, { fontSize: "xs", color: {
|
|
9119
|
+
base: `${colorPalette}.600`,
|
|
9120
|
+
_dark: `${colorPalette}.400`,
|
|
9121
|
+
}, paddingX: 1, onClick: (e) => {
|
|
9122
|
+
e.stopPropagation();
|
|
9123
|
+
if (onDateClick) {
|
|
9124
|
+
onDateClick(date, dateEvents);
|
|
9125
|
+
}
|
|
9126
|
+
}, cursor: onDateClick ? 'pointer' : 'default', children: ["+", dateEvents.length - maxEventsPerDay, " more"] }))] })] }, key));
|
|
9127
|
+
})) })] }, `${calendar.month}${calendar.year}`))) })] }));
|
|
9128
|
+
}
|
|
9129
|
+
|
|
8600
9130
|
// Reference: https://tanstack.com/table/latest/docs/framework/react/examples/custom-features
|
|
8601
9131
|
// TypeScript setup for our new feature with all of the same type-safety as stock TanStack Table features
|
|
8602
9132
|
// end of TS setup!
|
|
@@ -8697,7 +9227,7 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
|
|
|
8697
9227
|
*
|
|
8698
9228
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8699
9229
|
*/
|
|
8700
|
-
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,
|
|
9230
|
+
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 = {
|
|
8701
9231
|
view: 'View',
|
|
8702
9232
|
edit: 'Edit',
|
|
8703
9233
|
filterButtonText: 'Filter',
|
|
@@ -8708,7 +9238,7 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8708
9238
|
reloadButtonText: 'Reload',
|
|
8709
9239
|
resetSelection: 'Reset Selection',
|
|
8710
9240
|
resetSorting: 'Reset Sorting',
|
|
8711
|
-
rowCountText: '
|
|
9241
|
+
rowCountText: '',
|
|
8712
9242
|
hasErrorText: 'Has Error',
|
|
8713
9243
|
globalFilterPlaceholder: 'Search',
|
|
8714
9244
|
trueLabel: 'True',
|
|
@@ -8765,7 +9295,6 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8765
9295
|
globalFilter,
|
|
8766
9296
|
setGlobalFilter,
|
|
8767
9297
|
type: 'client',
|
|
8768
|
-
translate,
|
|
8769
9298
|
columns: columns,
|
|
8770
9299
|
sorting,
|
|
8771
9300
|
setSorting,
|
|
@@ -8797,22 +9326,22 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
|
|
|
8797
9326
|
*
|
|
8798
9327
|
* @link https://tanstack.com/table/latest/docs/guide/column-defs
|
|
8799
9328
|
*/
|
|
8800
|
-
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,
|
|
8801
|
-
view:
|
|
8802
|
-
edit:
|
|
8803
|
-
filterButtonText:
|
|
8804
|
-
filterTitle:
|
|
8805
|
-
filterReset:
|
|
8806
|
-
filterClose:
|
|
8807
|
-
reloadTooltip:
|
|
8808
|
-
reloadButtonText:
|
|
8809
|
-
resetSelection:
|
|
8810
|
-
resetSorting:
|
|
8811
|
-
rowCountText:
|
|
8812
|
-
hasErrorText:
|
|
8813
|
-
globalFilterPlaceholder:
|
|
8814
|
-
trueLabel:
|
|
8815
|
-
falseLabel:
|
|
9329
|
+
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 = {
|
|
9330
|
+
view: 'View',
|
|
9331
|
+
edit: 'Edit',
|
|
9332
|
+
filterButtonText: 'Filter',
|
|
9333
|
+
filterTitle: 'Filter',
|
|
9334
|
+
filterReset: 'Reset',
|
|
9335
|
+
filterClose: 'Close',
|
|
9336
|
+
reloadTooltip: 'Reload',
|
|
9337
|
+
reloadButtonText: 'Reload',
|
|
9338
|
+
resetSelection: 'Reset Selection',
|
|
9339
|
+
resetSorting: 'Reset Sorting',
|
|
9340
|
+
rowCountText: '',
|
|
9341
|
+
hasErrorText: 'Has Error',
|
|
9342
|
+
globalFilterPlaceholder: 'Search',
|
|
9343
|
+
trueLabel: 'True',
|
|
9344
|
+
falseLabel: 'False',
|
|
8816
9345
|
}, }) {
|
|
8817
9346
|
const table = reactTable.useReactTable({
|
|
8818
9347
|
_features: [DensityFeature],
|
|
@@ -8822,7 +9351,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8822
9351
|
getCoreRowModel: reactTable.getCoreRowModel(),
|
|
8823
9352
|
manualPagination: true,
|
|
8824
9353
|
manualSorting: true,
|
|
8825
|
-
columnResizeMode:
|
|
9354
|
+
columnResizeMode: 'onChange',
|
|
8826
9355
|
defaultColumn: {
|
|
8827
9356
|
size: 150, //starting column size
|
|
8828
9357
|
minSize: 10, //enforced during column resizing
|
|
@@ -8865,8 +9394,7 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8865
9394
|
table: table,
|
|
8866
9395
|
globalFilter,
|
|
8867
9396
|
setGlobalFilter,
|
|
8868
|
-
type:
|
|
8869
|
-
translate,
|
|
9397
|
+
type: 'server',
|
|
8870
9398
|
columns: columns,
|
|
8871
9399
|
sorting,
|
|
8872
9400
|
setSorting,
|
|
@@ -8884,9 +9412,10 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8884
9412
|
setColumnVisibility,
|
|
8885
9413
|
data: query.data?.data ?? [],
|
|
8886
9414
|
tableLabel,
|
|
8887
|
-
}, children: jsxRuntime.jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
9415
|
+
}, children: jsxRuntime.jsx(DataTableServerContext.Provider, { value: { url: url ?? '', query }, children: children }) }));
|
|
8888
9416
|
}
|
|
8889
9417
|
|
|
9418
|
+
exports.CalendarDisplay = CalendarDisplay;
|
|
8890
9419
|
exports.CardHeader = CardHeader;
|
|
8891
9420
|
exports.DataDisplay = DataDisplay;
|
|
8892
9421
|
exports.DataTable = DataTable;
|