@bsol-oss/react-datatable5 12.0.0-beta.56 → 12.0.0-beta.58
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 +192 -0
- package/dist/index.d.ts +76 -2
- package/dist/index.js +676 -60
- package/dist/index.mjs +674 -62
- package/dist/types/components/DatePicker/DatePicker.d.ts +23 -0
- package/dist/types/components/DatePicker/DateTimePicker.d.ts +11 -0
- package/dist/types/components/DatePicker/DurationPicker.d.ts +12 -0
- package/dist/types/components/DatePicker/IsoTimePicker.d.ts +16 -0
- package/dist/types/components/DatePicker/PickerDemo.d.ts +1 -0
- package/dist/types/components/DatePicker/UniversalPicker.d.ts +9 -0
- package/dist/types/components/DatePicker/index.d.ts +7 -0
- package/dist/types/components/Form/SchemaFormContext.d.ts +3 -0
- package/dist/types/components/Form/components/core/FormRoot.d.ts +3 -1
- package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +2 -0
- package/dist/types/components/Form/components/viewers/DateTimeViewer.d.ts +7 -0
- package/dist/types/components/Form/components/viewers/TimeViewer.d.ts +1 -1
- package/dist/types/components/Form/utils/validation.d.ts +49 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -29,8 +29,13 @@ var gr = require('react-icons/gr');
|
|
|
29
29
|
var reactI18next = require('react-i18next');
|
|
30
30
|
var axios = require('axios');
|
|
31
31
|
var reactHookForm = require('react-hook-form');
|
|
32
|
+
var Ajv = require('ajv');
|
|
33
|
+
var addFormats = require('ajv-formats');
|
|
34
|
+
var zh_TW = require('ajv-i18n/localize/zh-TW');
|
|
35
|
+
var zh_CN = require('ajv-i18n/localize/zh');
|
|
32
36
|
var dayjs = require('dayjs');
|
|
33
37
|
var utc = require('dayjs/plugin/utc');
|
|
38
|
+
var timezone = require('dayjs/plugin/timezone');
|
|
34
39
|
var ti = require('react-icons/ti');
|
|
35
40
|
|
|
36
41
|
function _interopNamespaceDefault(e) {
|
|
@@ -197,7 +202,7 @@ const monthNamesFull = [
|
|
|
197
202
|
"November",
|
|
198
203
|
"December",
|
|
199
204
|
];
|
|
200
|
-
const weekdayNamesShort
|
|
205
|
+
const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
201
206
|
function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, selected = [], firstDayOfWeek = 0, }) {
|
|
202
207
|
const [hoveredDate, setHoveredDate] = React.useState();
|
|
203
208
|
const onMouseLeave = () => {
|
|
@@ -232,7 +237,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
232
237
|
offset: 12,
|
|
233
238
|
}), children: ">>" })] }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", gap: 4, children: calendars.map((calendar) => (jsxRuntime.jsxs(react.Grid, { gap: 4, children: [jsxRuntime.jsxs(react.Grid, { justifyContent: "center", children: [monthNamesFull[calendar.month], " ", calendar.year] }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
234
239
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
235
|
-
return (jsxRuntime.jsx(react.Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort
|
|
240
|
+
return (jsxRuntime.jsx(react.Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
236
241
|
}) }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: calendar.weeks.map((week, windex) => week.map((dateObj, index) => {
|
|
237
242
|
const key = `${calendar.month}${calendar.year}${windex}${index}`;
|
|
238
243
|
if (!dateObj) {
|
|
@@ -3688,6 +3693,8 @@ const SchemaFormContext = React.createContext({
|
|
|
3688
3693
|
onSubmit: async () => { },
|
|
3689
3694
|
rowNumber: 0,
|
|
3690
3695
|
requestOptions: {},
|
|
3696
|
+
validationLocale: 'en',
|
|
3697
|
+
timezone: 'Asia/Hong_Kong',
|
|
3691
3698
|
});
|
|
3692
3699
|
|
|
3693
3700
|
const useSchemaContext = () => {
|
|
@@ -3698,6 +3705,179 @@ const clearEmptyString = (object) => {
|
|
|
3698
3705
|
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
3699
3706
|
};
|
|
3700
3707
|
|
|
3708
|
+
// AJV i18n support
|
|
3709
|
+
const localize = {
|
|
3710
|
+
en: () => { }, // English is default, no localization needed
|
|
3711
|
+
'zh-HK': zh_TW, // Use zh-TW for Hong Kong Traditional Chinese
|
|
3712
|
+
'zh-TW': zh_TW, // Traditional Chinese (Taiwan)
|
|
3713
|
+
'zh-CN': zh_CN, // Simplified Chinese
|
|
3714
|
+
'zh': zh_CN, // Simplified Chinese (short form)
|
|
3715
|
+
};
|
|
3716
|
+
// Create AJV instance with format support
|
|
3717
|
+
const createValidator = () => {
|
|
3718
|
+
const ajv = new Ajv({
|
|
3719
|
+
allErrors: true,
|
|
3720
|
+
verbose: true,
|
|
3721
|
+
removeAdditional: false,
|
|
3722
|
+
strict: false,
|
|
3723
|
+
messages: false, // Disable default messages for i18n
|
|
3724
|
+
});
|
|
3725
|
+
// Add format validation support (date, time, email, etc.)
|
|
3726
|
+
addFormats(ajv);
|
|
3727
|
+
return ajv;
|
|
3728
|
+
};
|
|
3729
|
+
/**
|
|
3730
|
+
* Validates data against a JSON Schema using AJV with i18n support
|
|
3731
|
+
* @param data - The data to validate
|
|
3732
|
+
* @param schema - The JSON Schema to validate against
|
|
3733
|
+
* @param options - Validation options including locale
|
|
3734
|
+
* @returns ValidationResult containing validation status and errors
|
|
3735
|
+
*/
|
|
3736
|
+
const validateData = (data, schema, options = {}) => {
|
|
3737
|
+
const { locale = 'en' } = options;
|
|
3738
|
+
const ajv = createValidator();
|
|
3739
|
+
try {
|
|
3740
|
+
const validate = ajv.compile(schema);
|
|
3741
|
+
const isValid = validate(data);
|
|
3742
|
+
if (isValid) {
|
|
3743
|
+
return {
|
|
3744
|
+
isValid: true,
|
|
3745
|
+
errors: [],
|
|
3746
|
+
};
|
|
3747
|
+
}
|
|
3748
|
+
// Apply localization if not English
|
|
3749
|
+
if (locale !== 'en' && validate.errors && localize[locale]) {
|
|
3750
|
+
try {
|
|
3751
|
+
localize[locale](validate.errors);
|
|
3752
|
+
}
|
|
3753
|
+
catch (error) {
|
|
3754
|
+
console.warn(`Failed to localize validation errors to ${locale}:`, error);
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
const errors = (validate.errors || []).map((error) => {
|
|
3758
|
+
const field = error.instancePath?.replace(/^\//, '') || error.schemaPath?.split('/').pop() || 'root';
|
|
3759
|
+
let message = error.message || 'Validation error';
|
|
3760
|
+
// Enhanced error messages for better UX (only if using English or localization failed)
|
|
3761
|
+
if (locale === 'en' || !error.message) {
|
|
3762
|
+
switch (error.keyword) {
|
|
3763
|
+
case 'required':
|
|
3764
|
+
message = `${error.params?.missingProperty || 'Field'} is required`;
|
|
3765
|
+
break;
|
|
3766
|
+
case 'format':
|
|
3767
|
+
message = `Invalid ${error.params?.format} format`;
|
|
3768
|
+
break;
|
|
3769
|
+
case 'type':
|
|
3770
|
+
message = `Expected ${error.params?.type}, got ${typeof error.data}`;
|
|
3771
|
+
break;
|
|
3772
|
+
case 'minLength':
|
|
3773
|
+
message = `Must be at least ${error.params?.limit} characters`;
|
|
3774
|
+
break;
|
|
3775
|
+
case 'maxLength':
|
|
3776
|
+
message = `Must be no more than ${error.params?.limit} characters`;
|
|
3777
|
+
break;
|
|
3778
|
+
case 'minimum':
|
|
3779
|
+
message = `Must be at least ${error.params?.limit}`;
|
|
3780
|
+
break;
|
|
3781
|
+
case 'maximum':
|
|
3782
|
+
message = `Must be no more than ${error.params?.limit}`;
|
|
3783
|
+
break;
|
|
3784
|
+
case 'pattern':
|
|
3785
|
+
message = `Does not match required pattern`;
|
|
3786
|
+
break;
|
|
3787
|
+
case 'enum':
|
|
3788
|
+
message = `Must be one of: ${error.params?.allowedValues?.join(', ')}`;
|
|
3789
|
+
break;
|
|
3790
|
+
default:
|
|
3791
|
+
message = error.message || 'Validation error';
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
return {
|
|
3795
|
+
field: field || error.instancePath || 'unknown',
|
|
3796
|
+
message,
|
|
3797
|
+
value: error.data,
|
|
3798
|
+
schemaPath: error.schemaPath,
|
|
3799
|
+
};
|
|
3800
|
+
});
|
|
3801
|
+
return {
|
|
3802
|
+
isValid: false,
|
|
3803
|
+
errors,
|
|
3804
|
+
};
|
|
3805
|
+
}
|
|
3806
|
+
catch (error) {
|
|
3807
|
+
// Handle AJV compilation errors
|
|
3808
|
+
const errorMessage = locale === 'zh-HK' || locale === 'zh-TW'
|
|
3809
|
+
? `架構驗證錯誤: ${error instanceof Error ? error.message : '未知錯誤'}`
|
|
3810
|
+
: locale === 'zh-CN' || locale === 'zh'
|
|
3811
|
+
? `模式验证错误: ${error instanceof Error ? error.message : '未知错误'}`
|
|
3812
|
+
: `Schema validation error: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
|
3813
|
+
return {
|
|
3814
|
+
isValid: false,
|
|
3815
|
+
errors: [
|
|
3816
|
+
{
|
|
3817
|
+
field: 'schema',
|
|
3818
|
+
message: errorMessage,
|
|
3819
|
+
},
|
|
3820
|
+
],
|
|
3821
|
+
};
|
|
3822
|
+
}
|
|
3823
|
+
};
|
|
3824
|
+
/**
|
|
3825
|
+
* Creates a reusable validator function for a specific schema with i18n support
|
|
3826
|
+
* @param schema - The JSON Schema to create validator for
|
|
3827
|
+
* @param locale - The locale to use for error messages
|
|
3828
|
+
* @returns A function that validates data against the schema
|
|
3829
|
+
*/
|
|
3830
|
+
const createSchemaValidator = (schema, locale = 'en') => {
|
|
3831
|
+
const ajv = createValidator();
|
|
3832
|
+
const validate = ajv.compile(schema);
|
|
3833
|
+
return (data) => {
|
|
3834
|
+
const isValid = validate(data);
|
|
3835
|
+
if (isValid) {
|
|
3836
|
+
return {
|
|
3837
|
+
isValid: true,
|
|
3838
|
+
errors: [],
|
|
3839
|
+
};
|
|
3840
|
+
}
|
|
3841
|
+
// Apply localization if not English
|
|
3842
|
+
if (locale !== 'en' && validate.errors && localize[locale]) {
|
|
3843
|
+
try {
|
|
3844
|
+
localize[locale](validate.errors);
|
|
3845
|
+
}
|
|
3846
|
+
catch (error) {
|
|
3847
|
+
console.warn(`Failed to localize validation errors to ${locale}:`, error);
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
const errors = (validate.errors || []).map((error) => {
|
|
3851
|
+
const field = error.instancePath?.replace(/^\//, '') || 'root';
|
|
3852
|
+
return {
|
|
3853
|
+
field,
|
|
3854
|
+
message: error.message || 'Validation error',
|
|
3855
|
+
value: error.data,
|
|
3856
|
+
schemaPath: error.schemaPath,
|
|
3857
|
+
};
|
|
3858
|
+
});
|
|
3859
|
+
return {
|
|
3860
|
+
isValid: false,
|
|
3861
|
+
errors,
|
|
3862
|
+
};
|
|
3863
|
+
};
|
|
3864
|
+
};
|
|
3865
|
+
/**
|
|
3866
|
+
* Get available locales for validation error messages
|
|
3867
|
+
* @returns Array of supported locale codes
|
|
3868
|
+
*/
|
|
3869
|
+
const getSupportedLocales = () => {
|
|
3870
|
+
return Object.keys(localize);
|
|
3871
|
+
};
|
|
3872
|
+
/**
|
|
3873
|
+
* Check if a locale is supported
|
|
3874
|
+
* @param locale - The locale to check
|
|
3875
|
+
* @returns Boolean indicating if the locale is supported
|
|
3876
|
+
*/
|
|
3877
|
+
const isLocaleSupported = (locale) => {
|
|
3878
|
+
return locale in localize;
|
|
3879
|
+
};
|
|
3880
|
+
|
|
3701
3881
|
const idPickerSanityCheck = (column, foreign_key) => {
|
|
3702
3882
|
if (!!foreign_key == false) {
|
|
3703
3883
|
throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
|
|
@@ -3713,7 +3893,7 @@ const idPickerSanityCheck = (column, foreign_key) => {
|
|
|
3713
3893
|
throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
|
|
3714
3894
|
}
|
|
3715
3895
|
};
|
|
3716
|
-
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, }) => {
|
|
3896
|
+
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, validationLocale = 'en', }) => {
|
|
3717
3897
|
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
3718
3898
|
const [isError, setIsError] = React.useState(false);
|
|
3719
3899
|
const [isSubmiting, setIsSubmiting] = React.useState(false);
|
|
@@ -3747,6 +3927,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3747
3927
|
setError,
|
|
3748
3928
|
getUpdatedData,
|
|
3749
3929
|
customErrorRenderer,
|
|
3930
|
+
validationLocale,
|
|
3750
3931
|
}, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
|
|
3751
3932
|
};
|
|
3752
3933
|
|
|
@@ -3820,27 +4001,14 @@ const CustomInput = ({ column, schema, prefix }) => {
|
|
|
3820
4001
|
}));
|
|
3821
4002
|
};
|
|
3822
4003
|
|
|
3823
|
-
const monthNamesShort = [
|
|
3824
|
-
"Jan",
|
|
3825
|
-
"Feb",
|
|
3826
|
-
"Mar",
|
|
3827
|
-
"Apr",
|
|
3828
|
-
"May",
|
|
3829
|
-
"Jun",
|
|
3830
|
-
"Jul",
|
|
3831
|
-
"Aug",
|
|
3832
|
-
"Sep",
|
|
3833
|
-
"Oct",
|
|
3834
|
-
"Nov",
|
|
3835
|
-
"Dec",
|
|
3836
|
-
];
|
|
3837
|
-
const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
3838
4004
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
4005
|
+
const { labels } = React.useContext(DatePickerContext);
|
|
4006
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
3839
4007
|
if (calendars.length) {
|
|
3840
4008
|
return (jsxRuntime.jsxs(react.Grid, { children: [jsxRuntime.jsxs(react.Grid, { templateColumns: "repeat(4, auto)", justifyContent: "center", children: [jsxRuntime.jsx(react.Button, { variant: "ghost", ...getBackProps({
|
|
3841
4009
|
calendars,
|
|
3842
4010
|
offset: 12,
|
|
3843
|
-
}), children: "<<" }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...getBackProps({ calendars }), children:
|
|
4011
|
+
}), 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({
|
|
3844
4012
|
calendars,
|
|
3845
4013
|
offset: 12,
|
|
3846
4014
|
}), 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) => {
|
|
@@ -3883,9 +4051,52 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
3883
4051
|
}
|
|
3884
4052
|
return null;
|
|
3885
4053
|
};
|
|
4054
|
+
const DatePickerContext = React.createContext({
|
|
4055
|
+
labels: {
|
|
4056
|
+
monthNamesShort: [
|
|
4057
|
+
"Jan",
|
|
4058
|
+
"Feb",
|
|
4059
|
+
"Mar",
|
|
4060
|
+
"Apr",
|
|
4061
|
+
"May",
|
|
4062
|
+
"Jun",
|
|
4063
|
+
"Jul",
|
|
4064
|
+
"Aug",
|
|
4065
|
+
"Sep",
|
|
4066
|
+
"Oct",
|
|
4067
|
+
"Nov",
|
|
4068
|
+
"Dec",
|
|
4069
|
+
],
|
|
4070
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
4071
|
+
backButtonLabel: "Back",
|
|
4072
|
+
forwardButtonLabel: "Next",
|
|
4073
|
+
},
|
|
4074
|
+
});
|
|
3886
4075
|
let DatePicker$1 = class DatePicker extends React.Component {
|
|
3887
4076
|
render() {
|
|
3888
|
-
|
|
4077
|
+
const { labels = {
|
|
4078
|
+
monthNamesShort: [
|
|
4079
|
+
"Jan",
|
|
4080
|
+
"Feb",
|
|
4081
|
+
"Mar",
|
|
4082
|
+
"Apr",
|
|
4083
|
+
"May",
|
|
4084
|
+
"Jun",
|
|
4085
|
+
"Jul",
|
|
4086
|
+
"Aug",
|
|
4087
|
+
"Sep",
|
|
4088
|
+
"Oct",
|
|
4089
|
+
"Nov",
|
|
4090
|
+
"Dec",
|
|
4091
|
+
],
|
|
4092
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
4093
|
+
backButtonLabel: "Back",
|
|
4094
|
+
forwardButtonLabel: "Next",
|
|
4095
|
+
}, } = this.props;
|
|
4096
|
+
return (jsxRuntime.jsx(DatePickerContext.Provider, { value: { labels }, children: jsxRuntime.jsx(Dayzed, { onDateSelected: this.props.onDateSelected, selected: this.props.selected, firstDayOfWeek: this.props.firstDayOfWeek, showOutsideDays: this.props.showOutsideDays, date: this.props.date, minDate: this.props.minDate, maxDate: this.props.maxDate, monthsToDisplay: this.props.monthsToDisplay, render:
|
|
4097
|
+
// @ts-expect-error - Dayzed types need to be fixed
|
|
4098
|
+
(dayzedData) => (jsxRuntime.jsx(Calendar, { ...dayzedData,
|
|
4099
|
+
firstDayOfWeek: this.props.firstDayOfWeek })) }) }));
|
|
3889
4100
|
}
|
|
3890
4101
|
};
|
|
3891
4102
|
|
|
@@ -3907,24 +4118,27 @@ const PopoverRoot = react.Popover.Root;
|
|
|
3907
4118
|
const PopoverBody = react.Popover.Body;
|
|
3908
4119
|
const PopoverTrigger = react.Popover.Trigger;
|
|
3909
4120
|
|
|
4121
|
+
function translateWrapper({ prefix, column, label, translate, }) {
|
|
4122
|
+
return translate.t(removeIndex(`${prefix}${column}.${label}`));
|
|
4123
|
+
}
|
|
4124
|
+
|
|
3910
4125
|
dayjs.extend(utc);
|
|
4126
|
+
dayjs.extend(timezone);
|
|
3911
4127
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
3912
4128
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
3913
|
-
const { translate } = useSchemaContext();
|
|
3914
|
-
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD
|
|
4129
|
+
const { translate, timezone } = useSchemaContext();
|
|
4130
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD", } = schema;
|
|
3915
4131
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3916
4132
|
const colLabel = `${prefix}${column}`;
|
|
3917
4133
|
const [open, setOpen] = React.useState(false);
|
|
3918
4134
|
const selectedDate = watch(colLabel);
|
|
3919
|
-
const displayDate = dayjs
|
|
4135
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
3920
4136
|
React.useEffect(() => {
|
|
3921
4137
|
try {
|
|
3922
4138
|
if (selectedDate) {
|
|
3923
4139
|
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
3924
4140
|
// For example, parse as UTC:
|
|
3925
|
-
const parsedDate = dayjs
|
|
3926
|
-
// Or if you want to parse in local timezone without shifting:
|
|
3927
|
-
// const parsedDate = dayjs.tz(selectedDate, dayjs.tz.guess());
|
|
4141
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
3928
4142
|
if (!parsedDate.isValid())
|
|
3929
4143
|
return;
|
|
3930
4144
|
// Format according to dateFormat from schema
|
|
@@ -3942,19 +4156,48 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
3942
4156
|
console.error(e);
|
|
3943
4157
|
}
|
|
3944
4158
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
3945
|
-
|
|
4159
|
+
const customTranslate = (label) => {
|
|
4160
|
+
return translateWrapper({ prefix, column, label, translate });
|
|
4161
|
+
};
|
|
4162
|
+
return (jsxRuntime.jsxs(Field, { label: `${customTranslate(`field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
3946
4163
|
gridRow, children: [jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
3947
4164
|
setOpen(true);
|
|
3948
|
-
}, justifyContent: "start", children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DatePicker$1
|
|
3949
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3950
|
-
, {
|
|
3951
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3952
|
-
selected: new Date(selectedDate),
|
|
3953
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3954
|
-
onDateSelected: ({ date }) => {
|
|
4165
|
+
}, justifyContent: "start", children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
3955
4166
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
3956
4167
|
setOpen(false);
|
|
3957
|
-
}
|
|
4168
|
+
}, labels: {
|
|
4169
|
+
monthNamesShort: [
|
|
4170
|
+
translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
4171
|
+
translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
4172
|
+
translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
4173
|
+
translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
4174
|
+
translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
4175
|
+
translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
4176
|
+
translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
4177
|
+
translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
4178
|
+
translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
4179
|
+
translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
4180
|
+
translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
4181
|
+
translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
4182
|
+
],
|
|
4183
|
+
weekdayNamesShort: [
|
|
4184
|
+
translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
4185
|
+
translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
4186
|
+
translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
4187
|
+
translate.t(`common.weekday_4`, {
|
|
4188
|
+
defaultValue: "Wed",
|
|
4189
|
+
}),
|
|
4190
|
+
translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
4191
|
+
translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
4192
|
+
translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
4193
|
+
],
|
|
4194
|
+
backButtonLabel: translate.t(`common.back_button`, {
|
|
4195
|
+
defaultValue: "Back",
|
|
4196
|
+
}),
|
|
4197
|
+
forwardButtonLabel: translate.t(`common.forward_button`, {
|
|
4198
|
+
defaultValue: "Forward",
|
|
4199
|
+
}),
|
|
4200
|
+
} })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: customTranslate(`field_required`) }))] }));
|
|
3958
4201
|
};
|
|
3959
4202
|
|
|
3960
4203
|
function filterArray(array, searchTerm) {
|
|
@@ -4642,7 +4885,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4642
4885
|
|
|
4643
4886
|
const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
|
|
4644
4887
|
const { children, ...rest } = props;
|
|
4645
|
-
return (jsxRuntime.
|
|
4888
|
+
return (jsxRuntime.jsx(react.NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: children }));
|
|
4646
4889
|
});
|
|
4647
4890
|
const NumberInputField$1 = react.NumberInput.Input;
|
|
4648
4891
|
react.NumberInput.Scrubber;
|
|
@@ -4937,22 +5180,23 @@ function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem,
|
|
|
4937
5180
|
return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 90px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsxRuntime.jsx(react.Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), placeholder: "HH", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Text, { children: ":" }), jsxRuntime.jsx(react.Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), placeholder: "MM", maxLength: 2, textAlign: "center" }), jsxRuntime.jsxs(react.Flex, { gap: "1", children: [jsxRuntime.jsx(react.Button, { size: "sm", colorScheme: meridiem === "am" ? "blue" : "gray", variant: meridiem === "am" ? "solid" : "outline", onClick: () => handleMeridiemClick("am"), width: "40px", children: meridiemLabel.am }), jsxRuntime.jsx(react.Button, { size: "sm", colorScheme: meridiem === "pm" ? "blue" : "gray", variant: meridiem === "pm" ? "solid" : "outline", onClick: () => handleMeridiemClick("pm"), width: "40px", children: meridiemLabel.pm })] }), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(md.MdCancel, {}) })] }) }));
|
|
4938
5181
|
}
|
|
4939
5182
|
|
|
5183
|
+
dayjs.extend(timezone);
|
|
4940
5184
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
4941
5185
|
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
4942
|
-
const { translate } = useSchemaContext();
|
|
4943
|
-
const { required, gridColumn = "span 4", gridRow = "span 1", timeFormat = "HH:mm:
|
|
5186
|
+
const { translate, timezone } = useSchemaContext();
|
|
5187
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
|
|
4944
5188
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4945
5189
|
const colLabel = `${prefix}${column}`;
|
|
4946
5190
|
const [open, setOpen] = React.useState(false);
|
|
4947
5191
|
const value = watch(colLabel);
|
|
4948
|
-
const displayedTime = dayjs(`1970-01-01T${value}
|
|
4949
|
-
? dayjs(`1970-01-01T${value}
|
|
5192
|
+
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
5193
|
+
? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
|
|
4950
5194
|
: "";
|
|
4951
5195
|
// Parse the initial time parts from the ISO time string (HH:mm:ss)
|
|
4952
5196
|
const parseTime = (isoTime) => {
|
|
4953
5197
|
if (!isoTime)
|
|
4954
5198
|
return { hour: 12, minute: 0, meridiem: "am" };
|
|
4955
|
-
const parsed = dayjs(`1970-01-01T${isoTime}
|
|
5199
|
+
const parsed = dayjs(`1970-01-01T${isoTime}`).tz(timezone);
|
|
4956
5200
|
if (!parsed.isValid())
|
|
4957
5201
|
return { hour: 12, minute: 0, meridiem: "am" };
|
|
4958
5202
|
let hour = parsed.hour();
|
|
@@ -4983,8 +5227,8 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
4983
5227
|
h = 0;
|
|
4984
5228
|
else if (meridiem === "pm" && hour < 12)
|
|
4985
5229
|
h = hour + 12;
|
|
4986
|
-
return dayjs(`1970-01-01T${h.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:
|
|
4987
|
-
.
|
|
5230
|
+
return dayjs(`1970-01-01T${h.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:00`)
|
|
5231
|
+
.tz(timezone)
|
|
4988
5232
|
.format(timeFormat);
|
|
4989
5233
|
};
|
|
4990
5234
|
// Handle changes to time parts
|
|
@@ -5000,11 +5244,289 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
5000
5244
|
gridRow, 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: () => {
|
|
5001
5245
|
setOpen(true);
|
|
5002
5246
|
}, justifyContent: "start", children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ""] }) }), jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { ref: containerRef, 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: {
|
|
5003
|
-
am: translate.t(
|
|
5004
|
-
pm: translate.t(
|
|
5247
|
+
am: translate.t(`common.am`, { defaultValue: "AM" }),
|
|
5248
|
+
pm: translate.t(`common.pm`, { defaultValue: "PM" }),
|
|
5005
5249
|
} }) }) }) }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
5006
5250
|
};
|
|
5007
5251
|
|
|
5252
|
+
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
|
|
5253
|
+
// Refs for focus management
|
|
5254
|
+
const hourInputRef = React.useRef(null);
|
|
5255
|
+
const minuteInputRef = React.useRef(null);
|
|
5256
|
+
const secondInputRef = React.useRef(null);
|
|
5257
|
+
// Centralized handler for key events, value changes, and focus management
|
|
5258
|
+
const handleKeyDown = (e, field) => {
|
|
5259
|
+
const input = e.target;
|
|
5260
|
+
const value = input.value;
|
|
5261
|
+
// Handle navigation between fields
|
|
5262
|
+
if (e.key === "Tab") {
|
|
5263
|
+
return;
|
|
5264
|
+
}
|
|
5265
|
+
if (e.key === ":" && field === "hour") {
|
|
5266
|
+
e.preventDefault();
|
|
5267
|
+
minuteInputRef.current?.focus();
|
|
5268
|
+
return;
|
|
5269
|
+
}
|
|
5270
|
+
if (e.key === ":" && field === "minute") {
|
|
5271
|
+
e.preventDefault();
|
|
5272
|
+
secondInputRef.current?.focus();
|
|
5273
|
+
return;
|
|
5274
|
+
}
|
|
5275
|
+
if (e.key === "Backspace" && value === "") {
|
|
5276
|
+
e.preventDefault();
|
|
5277
|
+
if (field === "minute") {
|
|
5278
|
+
hourInputRef.current?.focus();
|
|
5279
|
+
}
|
|
5280
|
+
else if (field === "second") {
|
|
5281
|
+
minuteInputRef.current?.focus();
|
|
5282
|
+
}
|
|
5283
|
+
return;
|
|
5284
|
+
}
|
|
5285
|
+
// Handle number inputs
|
|
5286
|
+
if (field === "hour") {
|
|
5287
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5288
|
+
const newValue = value + e.key;
|
|
5289
|
+
const numValue = parseInt(newValue, 10);
|
|
5290
|
+
if (numValue > 23) {
|
|
5291
|
+
const digitValue = parseInt(e.key, 10);
|
|
5292
|
+
setHour(digitValue);
|
|
5293
|
+
onChange({ hour: digitValue, minute, second });
|
|
5294
|
+
return;
|
|
5295
|
+
}
|
|
5296
|
+
if (numValue >= 0 && numValue <= 23) {
|
|
5297
|
+
setHour(numValue);
|
|
5298
|
+
onChange({ hour: numValue, minute, second });
|
|
5299
|
+
e.preventDefault();
|
|
5300
|
+
minuteInputRef.current?.focus();
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
else if (field === "minute") {
|
|
5305
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5306
|
+
const newValue = value + e.key;
|
|
5307
|
+
const numValue = parseInt(newValue, 10);
|
|
5308
|
+
if (numValue > 59) {
|
|
5309
|
+
const digitValue = parseInt(e.key, 10);
|
|
5310
|
+
setMinute(digitValue);
|
|
5311
|
+
onChange({ hour, minute: digitValue, second });
|
|
5312
|
+
return;
|
|
5313
|
+
}
|
|
5314
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5315
|
+
setMinute(numValue);
|
|
5316
|
+
onChange({ hour, minute: numValue, second });
|
|
5317
|
+
e.preventDefault();
|
|
5318
|
+
secondInputRef.current?.focus();
|
|
5319
|
+
}
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
else if (field === "second") {
|
|
5323
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5324
|
+
const newValue = value + e.key;
|
|
5325
|
+
const numValue = parseInt(newValue, 10);
|
|
5326
|
+
if (numValue > 59) {
|
|
5327
|
+
const digitValue = parseInt(e.key, 10);
|
|
5328
|
+
setSecond(digitValue);
|
|
5329
|
+
onChange({ hour, minute, second: digitValue });
|
|
5330
|
+
return;
|
|
5331
|
+
}
|
|
5332
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5333
|
+
setSecond(numValue);
|
|
5334
|
+
onChange({ hour, minute, second: numValue });
|
|
5335
|
+
}
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
};
|
|
5339
|
+
const handleClear = () => {
|
|
5340
|
+
setHour(null);
|
|
5341
|
+
setMinute(null);
|
|
5342
|
+
setSecond(null);
|
|
5343
|
+
onChange({ hour: null, minute: null, second: null });
|
|
5344
|
+
hourInputRef.current?.focus();
|
|
5345
|
+
};
|
|
5346
|
+
return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 10px 60px auto", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsx(react.Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), placeholder: "HH", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Text, { children: ":" }), jsxRuntime.jsx(react.Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), placeholder: "MM", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Text, { children: ":" }), jsxRuntime.jsx(react.Input, { ref: secondInputRef, type: "text", value: second === null ? "" : second.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "second"), placeholder: "SS", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(md.MdCancel, {}) })] }) }));
|
|
5347
|
+
}
|
|
5348
|
+
|
|
5349
|
+
function DateTimePicker$1({ value, onChange, format = "date-time", showSeconds = false, labels = {
|
|
5350
|
+
monthNamesShort: [
|
|
5351
|
+
"Jan",
|
|
5352
|
+
"Feb",
|
|
5353
|
+
"Mar",
|
|
5354
|
+
"Apr",
|
|
5355
|
+
"May",
|
|
5356
|
+
"Jun",
|
|
5357
|
+
"Jul",
|
|
5358
|
+
"Aug",
|
|
5359
|
+
"Sep",
|
|
5360
|
+
"Oct",
|
|
5361
|
+
"Nov",
|
|
5362
|
+
"Dec",
|
|
5363
|
+
],
|
|
5364
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
5365
|
+
backButtonLabel: "Back",
|
|
5366
|
+
forwardButtonLabel: "Next",
|
|
5367
|
+
}, timezone = "Asia/Hong_Kong", }) {
|
|
5368
|
+
const [selectedDate, setSelectedDate] = React.useState(value || "");
|
|
5369
|
+
// Time state for 12-hour format
|
|
5370
|
+
const [hour12, setHour12] = React.useState(value ? dayjs(value).hour() % 12 || 12 : null);
|
|
5371
|
+
const [minute, setMinute] = React.useState(value ? dayjs(value).minute() : null);
|
|
5372
|
+
const [meridiem, setMeridiem] = React.useState(value ? (dayjs(value).hour() >= 12 ? "pm" : "am") : null);
|
|
5373
|
+
// Time state for 24-hour format
|
|
5374
|
+
const [hour24, setHour24] = React.useState(value ? dayjs(value).hour() : null);
|
|
5375
|
+
const [second, setSecond] = React.useState(value ? dayjs(value).second() : null);
|
|
5376
|
+
const handleDateChange = (date) => {
|
|
5377
|
+
setSelectedDate(date);
|
|
5378
|
+
updateDateTime(dayjs(date).tz(timezone).toISOString());
|
|
5379
|
+
};
|
|
5380
|
+
const handleTimeChange = (timeData) => {
|
|
5381
|
+
if (format === "iso-date-time") {
|
|
5382
|
+
setHour24(timeData.hour);
|
|
5383
|
+
setMinute(timeData.minute);
|
|
5384
|
+
if (showSeconds)
|
|
5385
|
+
setSecond(timeData.second);
|
|
5386
|
+
}
|
|
5387
|
+
else {
|
|
5388
|
+
setHour12(timeData.hour);
|
|
5389
|
+
setMinute(timeData.minute);
|
|
5390
|
+
setMeridiem(timeData.meridiem);
|
|
5391
|
+
}
|
|
5392
|
+
updateDateTime(dayjs(selectedDate).tz(timezone).toISOString(), timeData);
|
|
5393
|
+
};
|
|
5394
|
+
const updateDateTime = (date, timeData) => {
|
|
5395
|
+
if (!date) {
|
|
5396
|
+
onChange?.(undefined);
|
|
5397
|
+
return;
|
|
5398
|
+
}
|
|
5399
|
+
// use dayjs to convert the date to the timezone
|
|
5400
|
+
const newDate = dayjs(date).tz(timezone).toDate();
|
|
5401
|
+
if (format === "iso-date-time") {
|
|
5402
|
+
const h = timeData?.hour ?? hour24;
|
|
5403
|
+
const m = timeData?.minute ?? minute;
|
|
5404
|
+
const s = showSeconds ? timeData?.second ?? second : 0;
|
|
5405
|
+
if (h !== null)
|
|
5406
|
+
newDate.setHours(h);
|
|
5407
|
+
if (m !== null)
|
|
5408
|
+
newDate.setMinutes(m);
|
|
5409
|
+
if (s !== null)
|
|
5410
|
+
newDate.setSeconds(s);
|
|
5411
|
+
}
|
|
5412
|
+
else {
|
|
5413
|
+
const h = timeData?.hour ?? hour12;
|
|
5414
|
+
const m = timeData?.minute ?? minute;
|
|
5415
|
+
const mer = timeData?.meridiem ?? meridiem;
|
|
5416
|
+
if (h !== null && mer !== null) {
|
|
5417
|
+
let hour24 = h;
|
|
5418
|
+
if (mer === "am" && h === 12)
|
|
5419
|
+
hour24 = 0;
|
|
5420
|
+
else if (mer === "pm" && h < 12)
|
|
5421
|
+
hour24 = h + 12;
|
|
5422
|
+
newDate.setHours(hour24);
|
|
5423
|
+
}
|
|
5424
|
+
if (m !== null)
|
|
5425
|
+
newDate.setMinutes(m);
|
|
5426
|
+
newDate.setSeconds(0);
|
|
5427
|
+
}
|
|
5428
|
+
onChange?.(dayjs(newDate).tz(timezone).toISOString());
|
|
5429
|
+
};
|
|
5430
|
+
const handleClear = () => {
|
|
5431
|
+
setSelectedDate("");
|
|
5432
|
+
setHour12(null);
|
|
5433
|
+
setHour24(null);
|
|
5434
|
+
setMinute(null);
|
|
5435
|
+
setSecond(null);
|
|
5436
|
+
setMeridiem(null);
|
|
5437
|
+
onChange?.(undefined);
|
|
5438
|
+
};
|
|
5439
|
+
const isISO = format === "iso-date-time";
|
|
5440
|
+
return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsxRuntime.jsx(DatePicker$1, { selected: selectedDate
|
|
5441
|
+
? dayjs(selectedDate).tz(timezone).toDate()
|
|
5442
|
+
: new Date(), onDateSelected: ({ date }) => handleDateChange(dayjs(date).tz(timezone).toISOString()), monthsToDisplay: 1, labels: labels }), 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: second, setSecond: setSecond, onChange: handleTimeChange })) : (jsxRuntime.jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsxRuntime.jsx(react.Icon, { as: fa6.FaTrash }) })] }), selectedDate && (jsxRuntime.jsxs(react.Flex, { gap: 2, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).format(isISO
|
|
5443
|
+
? showSeconds
|
|
5444
|
+
? "YYYY-MM-DD HH:mm:ss"
|
|
5445
|
+
: "YYYY-MM-DD HH:mm"
|
|
5446
|
+
: "YYYY-MM-DD hh:mm A ") }), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).tz(timezone).format("Z") }), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: timezone })] }))] }));
|
|
5447
|
+
}
|
|
5448
|
+
|
|
5449
|
+
dayjs.extend(utc);
|
|
5450
|
+
dayjs.extend(timezone);
|
|
5451
|
+
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
5452
|
+
const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
|
|
5453
|
+
const { translate, timezone } = useSchemaContext();
|
|
5454
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
|
|
5455
|
+
// with timezone
|
|
5456
|
+
dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
|
|
5457
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5458
|
+
const colLabel = `${prefix}${column}`;
|
|
5459
|
+
const [open, setOpen] = React.useState(false);
|
|
5460
|
+
const selectedDate = watch(colLabel);
|
|
5461
|
+
const displayDate = dayjs(selectedDate)
|
|
5462
|
+
.tz(timezone)
|
|
5463
|
+
.format(displayDateFormat);
|
|
5464
|
+
React.useEffect(() => {
|
|
5465
|
+
try {
|
|
5466
|
+
if (selectedDate) {
|
|
5467
|
+
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
5468
|
+
// For example, parse as UTC:
|
|
5469
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
5470
|
+
if (!parsedDate.isValid())
|
|
5471
|
+
return;
|
|
5472
|
+
// Format according to dateFormat from schema
|
|
5473
|
+
const formatted = parsedDate.format(dateFormat);
|
|
5474
|
+
// Update the form value only if different to avoid loops
|
|
5475
|
+
if (formatted !== selectedDate) {
|
|
5476
|
+
setValue(colLabel, formatted, {
|
|
5477
|
+
shouldValidate: true,
|
|
5478
|
+
shouldDirty: true,
|
|
5479
|
+
});
|
|
5480
|
+
}
|
|
5481
|
+
}
|
|
5482
|
+
}
|
|
5483
|
+
catch (e) {
|
|
5484
|
+
console.error(e);
|
|
5485
|
+
}
|
|
5486
|
+
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
5487
|
+
const customTranslate = (label) => {
|
|
5488
|
+
return translateWrapper({ prefix, column, label, translate });
|
|
5489
|
+
};
|
|
5490
|
+
return (jsxRuntime.jsxs(Field, { label: `${customTranslate(`field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5491
|
+
gridRow, children: [jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
5492
|
+
setOpen(true);
|
|
5493
|
+
}, justifyContent: "start", children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsxRuntime.jsx(PopoverContent, { minW: "450px", children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
5494
|
+
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
5495
|
+
}, timezone: timezone, labels: {
|
|
5496
|
+
monthNamesShort: [
|
|
5497
|
+
translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
5498
|
+
translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
5499
|
+
translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
5500
|
+
translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
5501
|
+
translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
5502
|
+
translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
5503
|
+
translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
5504
|
+
translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
5505
|
+
translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
5506
|
+
translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
5507
|
+
translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
5508
|
+
translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
5509
|
+
],
|
|
5510
|
+
weekdayNamesShort: [
|
|
5511
|
+
translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
5512
|
+
translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
5513
|
+
translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
5514
|
+
translate.t(`common.weekday_4`, {
|
|
5515
|
+
defaultValue: "Wed",
|
|
5516
|
+
}),
|
|
5517
|
+
translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
5518
|
+
translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
5519
|
+
translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
5520
|
+
],
|
|
5521
|
+
backButtonLabel: translate.t(`common.back_button`, {
|
|
5522
|
+
defaultValue: "Back",
|
|
5523
|
+
}),
|
|
5524
|
+
forwardButtonLabel: translate.t(`common.forward_button`, {
|
|
5525
|
+
defaultValue: "Forward",
|
|
5526
|
+
}),
|
|
5527
|
+
} })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: customTranslate(`field_required`) }))] }));
|
|
5528
|
+
};
|
|
5529
|
+
|
|
5008
5530
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
5009
5531
|
const colSchema = schema;
|
|
5010
5532
|
const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
|
|
@@ -5025,6 +5547,9 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
5025
5547
|
if (format === "time") {
|
|
5026
5548
|
return jsxRuntime.jsx(TimePicker, { schema: colSchema, prefix, column });
|
|
5027
5549
|
}
|
|
5550
|
+
if (format === "date-time") {
|
|
5551
|
+
return jsxRuntime.jsx(DateTimePicker, { schema: colSchema, prefix, column });
|
|
5552
|
+
}
|
|
5028
5553
|
if (variant === "text-area") {
|
|
5029
5554
|
return jsxRuntime.jsx(TextAreaInput, { schema: colSchema, prefix, column });
|
|
5030
5555
|
}
|
|
@@ -5116,20 +5641,16 @@ const CustomViewer = ({ column, schema, prefix }) => {
|
|
|
5116
5641
|
|
|
5117
5642
|
const DateViewer = ({ column, schema, prefix }) => {
|
|
5118
5643
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
5119
|
-
const { translate } = useSchemaContext();
|
|
5644
|
+
const { translate, timezone } = useSchemaContext();
|
|
5120
5645
|
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", } = schema;
|
|
5121
5646
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5122
5647
|
const colLabel = `${prefix}${column}`;
|
|
5123
5648
|
const selectedDate = watch(colLabel);
|
|
5124
|
-
const displayDate = dayjs
|
|
5649
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5125
5650
|
return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5126
5651
|
gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5127
5652
|
};
|
|
5128
5653
|
|
|
5129
|
-
function translateWrapper({ prefix, column, label, translate, }) {
|
|
5130
|
-
return translate.t(removeIndex(`${prefix}${column}.${label}`));
|
|
5131
|
-
}
|
|
5132
|
-
|
|
5133
5654
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
5134
5655
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
5135
5656
|
const { translate } = useSchemaContext();
|
|
@@ -5385,20 +5906,34 @@ const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
|
5385
5906
|
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_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: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
|
|
5386
5907
|
};
|
|
5387
5908
|
|
|
5388
|
-
const TimeViewer = ({ column, schema, prefix
|
|
5909
|
+
const TimeViewer = ({ column, schema, prefix }) => {
|
|
5389
5910
|
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
5390
|
-
const { translate } = useSchemaContext();
|
|
5391
|
-
const { required, gridColumn = "span 4", gridRow = "span 1", displayTimeFormat = "hh:mm A" } = schema;
|
|
5911
|
+
const { translate, timezone } = useSchemaContext();
|
|
5912
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayTimeFormat = "hh:mm A", } = schema;
|
|
5392
5913
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5393
5914
|
const colLabel = `${prefix}${column}`;
|
|
5394
5915
|
const selectedDate = watch(colLabel);
|
|
5395
|
-
const displayedTime = dayjs(`1970-01-01T${selectedDate}
|
|
5396
|
-
|
|
5916
|
+
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
5917
|
+
.tz(timezone)
|
|
5918
|
+
.isValid()
|
|
5919
|
+
? dayjs(`1970-01-01T${selectedDate}`).tz(timezone).format(displayTimeFormat)
|
|
5397
5920
|
: "";
|
|
5398
5921
|
return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5399
5922
|
gridRow, children: [jsxRuntime.jsx(react.Text, { children: displayedTime }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5400
5923
|
};
|
|
5401
5924
|
|
|
5925
|
+
const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
5926
|
+
const { watch, formState: { errors }, } = reactHookForm.useFormContext();
|
|
5927
|
+
const { translate, timezone } = useSchemaContext();
|
|
5928
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss", } = schema;
|
|
5929
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5930
|
+
const colLabel = `${prefix}${column}`;
|
|
5931
|
+
const selectedDate = watch(colLabel);
|
|
5932
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5933
|
+
return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5934
|
+
gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5935
|
+
};
|
|
5936
|
+
|
|
5402
5937
|
const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
5403
5938
|
const colSchema = schema;
|
|
5404
5939
|
const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
|
|
@@ -5419,6 +5954,9 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
5419
5954
|
if (format === "date") {
|
|
5420
5955
|
return jsxRuntime.jsx(DateViewer, { schema: colSchema, prefix, column });
|
|
5421
5956
|
}
|
|
5957
|
+
if (format === "date-time") {
|
|
5958
|
+
return jsxRuntime.jsx(DateTimeViewer, { schema: colSchema, prefix, column });
|
|
5959
|
+
}
|
|
5422
5960
|
if (variant === "text-area") {
|
|
5423
5961
|
return jsxRuntime.jsx(TextAreaViewer, { schema: colSchema, prefix, column });
|
|
5424
5962
|
}
|
|
@@ -5470,10 +6008,28 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
5470
6008
|
};
|
|
5471
6009
|
|
|
5472
6010
|
const SubmitButton = () => {
|
|
5473
|
-
const { translate, setValidatedData, setIsError, setIsConfirming } = useSchemaContext();
|
|
6011
|
+
const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, validationLocale } = useSchemaContext();
|
|
5474
6012
|
const methods = reactHookForm.useFormContext();
|
|
5475
6013
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5476
6014
|
const onValid = (data) => {
|
|
6015
|
+
// Validate data using AJV before proceeding to confirmation
|
|
6016
|
+
const validationResult = validateData(data, schema, { locale: validationLocale });
|
|
6017
|
+
if (!validationResult.isValid) {
|
|
6018
|
+
// Set validation errors with i18n support
|
|
6019
|
+
const validationErrorMessage = {
|
|
6020
|
+
type: 'validation',
|
|
6021
|
+
errors: validationResult.errors,
|
|
6022
|
+
message: validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6023
|
+
? '表單驗證失敗'
|
|
6024
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6025
|
+
? '表单验证失败'
|
|
6026
|
+
: 'Form validation failed'
|
|
6027
|
+
};
|
|
6028
|
+
setError(validationErrorMessage);
|
|
6029
|
+
setIsError(true);
|
|
6030
|
+
return;
|
|
6031
|
+
}
|
|
6032
|
+
// If validation passes, proceed to confirmation
|
|
5477
6033
|
setValidatedData(data);
|
|
5478
6034
|
setIsError(false);
|
|
5479
6035
|
setIsConfirming(true);
|
|
@@ -5484,7 +6040,7 @@ const SubmitButton = () => {
|
|
|
5484
6040
|
};
|
|
5485
6041
|
|
|
5486
6042
|
const FormBody = () => {
|
|
5487
|
-
const { schema, requestUrl, order, ignore, include, onSubmit, rowNumber, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, } = useSchemaContext();
|
|
6043
|
+
const { schema, requestUrl, order, ignore, include, onSubmit, rowNumber, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, validationLocale, } = useSchemaContext();
|
|
5488
6044
|
const methods = reactHookForm.useFormContext();
|
|
5489
6045
|
const { properties } = schema;
|
|
5490
6046
|
const onBeforeSubmit = () => {
|
|
@@ -5500,6 +6056,27 @@ const FormBody = () => {
|
|
|
5500
6056
|
const onSubmitSuccess = () => {
|
|
5501
6057
|
setIsSuccess(true);
|
|
5502
6058
|
};
|
|
6059
|
+
// Enhanced validation function using AJV with i18n support
|
|
6060
|
+
const validateFormData = (data) => {
|
|
6061
|
+
try {
|
|
6062
|
+
const validationResult = validateData(data, schema, { locale: validationLocale });
|
|
6063
|
+
return validationResult;
|
|
6064
|
+
}
|
|
6065
|
+
catch (error) {
|
|
6066
|
+
const errorMessage = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6067
|
+
? `驗證錯誤: ${error instanceof Error ? error.message : '未知驗證錯誤'}`
|
|
6068
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6069
|
+
? `验证错误: ${error instanceof Error ? error.message : '未知验证错误'}`
|
|
6070
|
+
: `Validation error: ${error instanceof Error ? error.message : 'Unknown validation error'}`;
|
|
6071
|
+
return {
|
|
6072
|
+
isValid: false,
|
|
6073
|
+
errors: [{
|
|
6074
|
+
field: 'validation',
|
|
6075
|
+
message: errorMessage
|
|
6076
|
+
}]
|
|
6077
|
+
};
|
|
6078
|
+
}
|
|
6079
|
+
};
|
|
5503
6080
|
const defaultOnSubmit = async (promise) => {
|
|
5504
6081
|
try {
|
|
5505
6082
|
onBeforeSubmit();
|
|
@@ -5524,12 +6101,47 @@ const FormBody = () => {
|
|
|
5524
6101
|
};
|
|
5525
6102
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5526
6103
|
const onFormSubmit = async (data) => {
|
|
6104
|
+
// Validate data using AJV before submission
|
|
6105
|
+
const validationResult = validateFormData(data);
|
|
6106
|
+
if (!validationResult.isValid) {
|
|
6107
|
+
// Set validation errors
|
|
6108
|
+
const validationErrorMessage = {
|
|
6109
|
+
type: 'validation',
|
|
6110
|
+
errors: validationResult.errors,
|
|
6111
|
+
message: validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6112
|
+
? '表單驗證失敗'
|
|
6113
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6114
|
+
? '表单验证失败'
|
|
6115
|
+
: 'Form validation failed'
|
|
6116
|
+
};
|
|
6117
|
+
onSubmitError(validationErrorMessage);
|
|
6118
|
+
return;
|
|
6119
|
+
}
|
|
5527
6120
|
if (onSubmit === undefined) {
|
|
5528
6121
|
await defaultOnSubmit(defaultSubmitPromise(data));
|
|
5529
6122
|
return;
|
|
5530
6123
|
}
|
|
5531
6124
|
await defaultOnSubmit(onSubmit(data));
|
|
5532
6125
|
};
|
|
6126
|
+
// Custom error renderer for validation errors with i18n support
|
|
6127
|
+
const renderValidationErrors = (validationErrors) => {
|
|
6128
|
+
const title = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6129
|
+
? `表單驗證失敗 (${validationErrors.length} 個錯誤${validationErrors.length > 1 ? '' : ''})`
|
|
6130
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6131
|
+
? `表单验证失败 (${validationErrors.length} 个错误${validationErrors.length > 1 ? '' : ''})`
|
|
6132
|
+
: `Form Validation Failed (${validationErrors.length} error${validationErrors.length > 1 ? 's' : ''})`;
|
|
6133
|
+
const formLabel = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6134
|
+
? '表單'
|
|
6135
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6136
|
+
? '表单'
|
|
6137
|
+
: 'Form';
|
|
6138
|
+
const currentValueLabel = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6139
|
+
? '目前值:'
|
|
6140
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6141
|
+
? '当前值:'
|
|
6142
|
+
: 'Current value:';
|
|
6143
|
+
return (jsxRuntime.jsxs(react.Alert.Root, { status: "error", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Title, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: "validation-errors", children: [jsxRuntime.jsx(AccordionItemTrigger, { children: title }), jsxRuntime.jsx(AccordionItemContent, { children: jsxRuntime.jsx(react.Box, { mt: 2, children: validationErrors.map((err, index) => (jsxRuntime.jsxs(react.Box, { mb: 2, p: 2, bg: "red.50", borderLeft: "4px solid", borderColor: "red.500", children: [jsxRuntime.jsxs(react.Text, { fontWeight: "bold", color: "red.700", children: [err.field === 'root' ? formLabel : err.field, ":"] }), jsxRuntime.jsx(react.Text, { color: "red.600", children: err.message }), err.value !== undefined && (jsxRuntime.jsxs(react.Text, { fontSize: "sm", color: "red.500", mt: 1, children: [currentValueLabel, " ", JSON.stringify(err.value)] }))] }, index))) }) })] }) }) })] }));
|
|
6144
|
+
};
|
|
5533
6145
|
const renderColumns = ({ order, keys, ignore, include, }) => {
|
|
5534
6146
|
const included = include.length > 0 ? include : keys;
|
|
5535
6147
|
const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
|
|
@@ -5565,7 +6177,7 @@ const FormBody = () => {
|
|
|
5565
6177
|
setIsConfirming(false);
|
|
5566
6178
|
}, variant: "subtle", children: translate.t("cancel") }), jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
5567
6179
|
onFormSubmit(validatedData);
|
|
5568
|
-
}, children: translate.t("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 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsxRuntime.jsx(react.Alert.Root, { status: "error", children: jsxRuntime.jsx(react.Alert.Title, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: "b", children: [jsxRuntime.jsxs(AccordionItemTrigger, { children: [jsxRuntime.jsx(react.Alert.Indicator, {}), `${error}`] }), jsxRuntime.jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) }) })) }))] }));
|
|
6180
|
+
}, children: translate.t("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 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: error?.type === 'validation' && error?.errors ? (renderValidationErrors(error.errors)) : (jsxRuntime.jsx(react.Alert.Root, { status: "error", children: jsxRuntime.jsx(react.Alert.Title, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: "b", children: [jsxRuntime.jsxs(AccordionItemTrigger, { children: [jsxRuntime.jsx(react.Alert.Indicator, {}), `${error}`] }), jsxRuntime.jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) }) })) })) }))] }));
|
|
5569
6181
|
}
|
|
5570
6182
|
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) => {
|
|
5571
6183
|
return (jsxRuntime.jsx(ColumnRenderer
|
|
@@ -5575,7 +6187,7 @@ const FormBody = () => {
|
|
|
5575
6187
|
properties: properties, prefix: ``, column }, `form-input-${column}`));
|
|
5576
6188
|
}) }), jsxRuntime.jsxs(react.Flex, { justifyContent: "end", gap: "2", children: [jsxRuntime.jsx(react.Button, { onClick: () => {
|
|
5577
6189
|
methods.reset();
|
|
5578
|
-
}, variant: "subtle", children: translate.t("reset") }), jsxRuntime.jsx(SubmitButton, {})] })] }));
|
|
6190
|
+
}, variant: "subtle", children: translate.t("reset") }), jsxRuntime.jsx(SubmitButton, {})] }), isError && error?.type === 'validation' && (jsxRuntime.jsx(react.Box, { mt: 4, children: error?.errors && renderValidationErrors(error.errors) }))] }));
|
|
5579
6191
|
};
|
|
5580
6192
|
|
|
5581
6193
|
const FormTitle = () => {
|
|
@@ -5658,12 +6270,16 @@ exports.TableSorter = TableSorter;
|
|
|
5658
6270
|
exports.TableViewer = TableViewer;
|
|
5659
6271
|
exports.TextCell = TextCell;
|
|
5660
6272
|
exports.ViewDialog = ViewDialog;
|
|
6273
|
+
exports.createSchemaValidator = createSchemaValidator;
|
|
5661
6274
|
exports.getColumns = getColumns;
|
|
5662
6275
|
exports.getMultiDates = getMultiDates;
|
|
5663
6276
|
exports.getRangeDates = getRangeDates;
|
|
6277
|
+
exports.getSupportedLocales = getSupportedLocales;
|
|
5664
6278
|
exports.idPickerSanityCheck = idPickerSanityCheck;
|
|
6279
|
+
exports.isLocaleSupported = isLocaleSupported;
|
|
5665
6280
|
exports.useDataTable = useDataTable;
|
|
5666
6281
|
exports.useDataTableContext = useDataTableContext;
|
|
5667
6282
|
exports.useDataTableServer = useDataTableServer;
|
|
5668
6283
|
exports.useForm = useForm;
|
|
6284
|
+
exports.validateData = validateData;
|
|
5669
6285
|
exports.widthSanityCheck = widthSanityCheck;
|