@ioca/react 1.5.15 → 1.5.17
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 +5 -0
- package/lib/cjs/components/datagrid/datagrid.js +1 -1
- package/lib/cjs/components/datagrid/datagrid.js.map +1 -1
- package/lib/cjs/components/drawer/drawer.js +4 -1
- package/lib/cjs/components/drawer/drawer.js.map +1 -1
- package/lib/cjs/components/form/field.js +9 -5
- package/lib/cjs/components/form/field.js.map +1 -1
- package/lib/cjs/components/form/form.js +16 -8
- package/lib/cjs/components/form/form.js.map +1 -1
- package/lib/cjs/components/form/useConfig.js +1 -1
- package/lib/cjs/components/form/useConfig.js.map +1 -1
- package/lib/cjs/components/form/useForm.js +43 -58
- package/lib/cjs/components/form/useForm.js.map +1 -1
- package/lib/cjs/components/form/utils.js +33 -0
- package/lib/cjs/components/form/utils.js.map +1 -0
- package/lib/cjs/components/picker/time/index.js +1 -0
- package/lib/cjs/components/picker/time/index.js.map +1 -1
- package/lib/css/colors.css +1 -1
- package/lib/css/index.css +1 -1
- package/lib/css/index.css.map +1 -1
- package/lib/css/tokens.css +11 -10
- package/lib/es/components/datagrid/datagrid.js +1 -1
- package/lib/es/components/datagrid/datagrid.js.map +1 -1
- package/lib/es/components/drawer/drawer.js +4 -1
- package/lib/es/components/drawer/drawer.js.map +1 -1
- package/lib/es/components/form/field.js +9 -5
- package/lib/es/components/form/field.js.map +1 -1
- package/lib/es/components/form/form.js +17 -9
- package/lib/es/components/form/form.js.map +1 -1
- package/lib/es/components/form/useConfig.js +1 -1
- package/lib/es/components/form/useConfig.js.map +1 -1
- package/lib/es/components/form/useForm.js +43 -58
- package/lib/es/components/form/useForm.js.map +1 -1
- package/lib/es/components/form/utils.js +29 -0
- package/lib/es/components/form/utils.js.map +1 -0
- package/lib/es/components/picker/time/index.js +1 -0
- package/lib/es/components/picker/time/index.js.map +1 -1
- package/lib/index.js +101 -75
- package/lib/types/components/form/useForm.d.ts +3 -3
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import { debounce, uid, throttle } from 'radash';
|
|
3
|
+
import { debounce, uid, crush, throttle } from 'radash';
|
|
4
4
|
import { useState, useRef, useEffect, useCallback, useMemo, Children, cloneElement, createElement, isValidElement, memo, Fragment as Fragment$1, useTransition, forwardRef, useLayoutEffect, useContext, createContext, useImperativeHandle } from 'react';
|
|
5
5
|
import { SkipPreviousRound, CloseRound, MinusRound, PlusRound, InboxTwotone, UndoRound, RedoRound, FormatBoldRound, FormatItalicRound, FormatUnderlinedRound, StrikethroughSRound, ClearAllRound, PlayArrowRound, PauseRound, StopRound, VolumeDownRound, VolumeOffRound, FullscreenRound, FullscreenExitRound, FeedOutlined, AspectRatioRound, OpenInNewRound, FileDownloadOutlined, RotateRightRound, RotateLeftRound, KeyboardArrowLeftRound, KeyboardArrowRightRound, KeyboardDoubleArrowUpRound, SyncAltRound, VisibilityRound, VisibilityOffRound, MoreHorizRound, SearchRound, CheckRound, UnfoldMoreRound, CalendarMonthTwotone, AccessTimeRound, InfoOutlined, KeyboardArrowDownRound, MoveToInboxTwotone, OutboxTwotone, FilePresentOutlined, DriveFolderUploadOutlined } from '@ricons/material';
|
|
6
6
|
import { createRoot } from 'react-dom/client';
|
|
@@ -1478,7 +1478,7 @@ function VirtualDatagrid(props) {
|
|
|
1478
1478
|
}
|
|
1479
1479
|
|
|
1480
1480
|
const Datagrid = (props) => {
|
|
1481
|
-
const { data = [], columns = [], border, striped, header = true, resizable, cellPadding = ".5em", cellEllipsis, empty = jsx(Empty, {}), loading, height = "unset", style, className, rowKey, virtual, renderLoading = () =>
|
|
1481
|
+
const { data = [], columns = [], border, striped, header = true, resizable, cellPadding = ".5em", cellEllipsis, empty = jsx(Empty, {}), loading, height = "unset", style, className, rowKey, virtual, renderLoading = () => jsx(Loading, { className: "color-3", absolute: true }), onCellClick, onRowClick, onCellDoubleClick, onHeaderClick, onSort, onScroll, onResize, } = props;
|
|
1482
1482
|
const container = useRef(null);
|
|
1483
1483
|
const wrapRef = useRef(null);
|
|
1484
1484
|
const state = useReactive({
|
|
@@ -1749,9 +1749,12 @@ function Drawer(props) {
|
|
|
1749
1749
|
});
|
|
1750
1750
|
if (!state.show)
|
|
1751
1751
|
return null;
|
|
1752
|
+
const container = typeof document === "undefined" ? null : document.body;
|
|
1753
|
+
if (!container)
|
|
1754
|
+
return null;
|
|
1752
1755
|
return createPortal(jsx("div", { className: classNames("i-backdrop-drawer", className, {
|
|
1753
1756
|
"i-active": state.active,
|
|
1754
|
-
}), onClick: handleBackdropClick, ...restProps, children: jsxs("div", { className: classNames("i-drawer", `i-drawer-${position}`), onClick: (e) => e.stopPropagation(), children: [header && (jsxs("header", { className: 'i-drawer-header', children: [header, !hideCloseButton && (jsx(Helpericon, { className: 'i-drawer-close', onClick: handleHide }))] })), jsx("div", { className: 'i-drawer-content', children: children }), footer && jsx("div", { className: 'i-drawer-footer', children: footer })] }) }),
|
|
1757
|
+
}), onClick: handleBackdropClick, ...restProps, children: jsxs("div", { className: classNames("i-drawer", `i-drawer-${position}`), onClick: (e) => e.stopPropagation(), children: [header && (jsxs("header", { className: 'i-drawer-header', children: [header, !hideCloseButton && (jsx(Helpericon, { className: 'i-drawer-close', onClick: handleHide }))] })), jsx("div", { className: 'i-drawer-content', children: children }), footer && jsx("div", { className: 'i-drawer-footer', children: footer })] }) }), container);
|
|
1755
1758
|
}
|
|
1756
1759
|
|
|
1757
1760
|
const Item$4 = (props) => {
|
|
@@ -3010,10 +3013,10 @@ function Field(props) {
|
|
|
3010
3013
|
useEffect(() => {
|
|
3011
3014
|
if (!name)
|
|
3012
3015
|
return;
|
|
3013
|
-
PubSub.subscribe(`${id}:set:${name}`, (
|
|
3016
|
+
PubSub.subscribe(`${id}:set:${name}`, (_evt, v) => {
|
|
3014
3017
|
setFieldValue(v);
|
|
3015
3018
|
});
|
|
3016
|
-
PubSub.subscribe(`${id}:invalid:${name}`, (
|
|
3019
|
+
PubSub.subscribe(`${id}:invalid:${name}`, (_evt, v) => {
|
|
3017
3020
|
if (v?.value !== undefined)
|
|
3018
3021
|
setFieldValue(v.value);
|
|
3019
3022
|
if (v?.status)
|
|
@@ -3022,121 +3025,136 @@ function Field(props) {
|
|
|
3022
3025
|
setFieldMessage(v.message);
|
|
3023
3026
|
});
|
|
3024
3027
|
Promise.resolve().then(() => {
|
|
3025
|
-
|
|
3028
|
+
if (name in form.cacheData) {
|
|
3029
|
+
form.set(name, form.cacheData[name]);
|
|
3030
|
+
}
|
|
3026
3031
|
});
|
|
3027
3032
|
return () => {
|
|
3028
3033
|
PubSub.unsubscribe(`${id}:set:${name}`);
|
|
3029
3034
|
PubSub.unsubscribe(`${id}:invalid:${name}`);
|
|
3030
|
-
|
|
3035
|
+
if (name && !name.includes(".")) {
|
|
3036
|
+
form.data[name] = undefined;
|
|
3037
|
+
}
|
|
3031
3038
|
};
|
|
3032
|
-
}, [name
|
|
3039
|
+
}, [name]);
|
|
3033
3040
|
if (!name)
|
|
3034
3041
|
return children;
|
|
3035
3042
|
return hijackChildren;
|
|
3036
3043
|
}
|
|
3037
3044
|
|
|
3045
|
+
function getDeep(obj, path) {
|
|
3046
|
+
if (!path.includes("."))
|
|
3047
|
+
return obj[path];
|
|
3048
|
+
return path.split(".").reduce((acc, key) => (acc != null ? acc[key] : undefined), obj);
|
|
3049
|
+
}
|
|
3050
|
+
function setDeep(obj, path, value) {
|
|
3051
|
+
const parts = path.split(".");
|
|
3052
|
+
let current = obj;
|
|
3053
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
3054
|
+
const key = parts[i];
|
|
3055
|
+
if (current[key] == null || typeof current[key] !== "object") {
|
|
3056
|
+
current[key] = {};
|
|
3057
|
+
}
|
|
3058
|
+
current = current[key];
|
|
3059
|
+
}
|
|
3060
|
+
current[parts[parts.length - 1]] = value;
|
|
3061
|
+
}
|
|
3062
|
+
function deleteDeep(obj, path) {
|
|
3063
|
+
const parts = path.split(".");
|
|
3064
|
+
const parent = parts
|
|
3065
|
+
.slice(0, -1)
|
|
3066
|
+
.reduce((acc, key) => (acc != null ? acc[key] : undefined), obj);
|
|
3067
|
+
if (parent != null) {
|
|
3068
|
+
delete parent[parts[parts.length - 1]];
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3038
3072
|
class IFormInstance {
|
|
3039
3073
|
id;
|
|
3040
3074
|
data = {};
|
|
3041
3075
|
cacheData = {};
|
|
3042
|
-
rules
|
|
3076
|
+
rules;
|
|
3043
3077
|
constructor() {
|
|
3044
3078
|
this.id = uid(8);
|
|
3045
3079
|
this.data = {};
|
|
3046
3080
|
}
|
|
3047
3081
|
get(field) {
|
|
3048
|
-
return field ? this.data
|
|
3082
|
+
return field ? getDeep(this.data, field) : this.data;
|
|
3049
3083
|
}
|
|
3050
3084
|
set(field, value) {
|
|
3051
3085
|
const id = this.id;
|
|
3052
3086
|
if (!this.data)
|
|
3053
3087
|
return;
|
|
3054
3088
|
if (typeof field === "string") {
|
|
3055
|
-
|
|
3089
|
+
if (field.includes(".")) {
|
|
3090
|
+
const parts = field.split(".");
|
|
3091
|
+
for (let i = 1; i < parts.length; i++) {
|
|
3092
|
+
const ancestor = parts.slice(0, i).join(".");
|
|
3093
|
+
if (ancestor in this.data) {
|
|
3094
|
+
console.warn(`[ioca-form] Field "${field}" conflicts with "${ancestor}". ` +
|
|
3095
|
+
"Nested representation in form.get() may be inconsistent.");
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
setDeep(this.data, field, value);
|
|
3099
|
+
}
|
|
3100
|
+
else {
|
|
3101
|
+
this.data[field] = value;
|
|
3102
|
+
}
|
|
3056
3103
|
this.cacheData[field] = value;
|
|
3057
3104
|
PubSub.publish(`${id}:set:${field}`, value);
|
|
3058
3105
|
return;
|
|
3059
3106
|
}
|
|
3060
|
-
Object.keys(field).
|
|
3061
|
-
|
|
3107
|
+
Object.keys(field).forEach((name) => {
|
|
3108
|
+
if (name.includes("."))
|
|
3109
|
+
setDeep(this.data, name, field[name]);
|
|
3110
|
+
else
|
|
3111
|
+
this.data[name] = field[name];
|
|
3062
3112
|
this.cacheData[name] = field[name];
|
|
3063
3113
|
PubSub.publish(`${id}:set:${name}`, field[name]);
|
|
3064
3114
|
});
|
|
3065
3115
|
}
|
|
3066
3116
|
delete(field) {
|
|
3067
|
-
delete this.
|
|
3117
|
+
delete this.cacheData[field];
|
|
3118
|
+
if (field.includes("."))
|
|
3119
|
+
deleteDeep(this.data, field);
|
|
3120
|
+
else
|
|
3121
|
+
delete this.data[field];
|
|
3068
3122
|
}
|
|
3069
3123
|
clear() {
|
|
3070
3124
|
if (!this.data)
|
|
3071
3125
|
return;
|
|
3126
|
+
const names = Object.keys(this.cacheData);
|
|
3072
3127
|
this.cacheData = {};
|
|
3073
|
-
|
|
3128
|
+
names.forEach((name) => {
|
|
3129
|
+
if (name.includes("."))
|
|
3130
|
+
deleteDeep(this.data, name);
|
|
3131
|
+
else
|
|
3132
|
+
this.data[name] = undefined;
|
|
3074
3133
|
PubSub.publish(`${this.id}:set:${name}`, undefined);
|
|
3075
|
-
this.data[name] = undefined;
|
|
3076
3134
|
});
|
|
3077
3135
|
}
|
|
3078
3136
|
async validate(field) {
|
|
3079
3137
|
const { id, rules, data } = this;
|
|
3080
3138
|
if (!rules)
|
|
3081
3139
|
return data;
|
|
3082
|
-
|
|
3083
|
-
const o = rules[field];
|
|
3084
|
-
const rule = {
|
|
3085
|
-
validator: (v) => Array.isArray(v)
|
|
3086
|
-
? v.length > 0
|
|
3087
|
-
: ![undefined, null, ""].includes(v),
|
|
3088
|
-
message: undefined,
|
|
3089
|
-
};
|
|
3090
|
-
if (typeof o === "function") {
|
|
3091
|
-
rule.validator = o;
|
|
3092
|
-
}
|
|
3093
|
-
else if (o === true) {
|
|
3094
|
-
rule.validator = (v) => ![undefined, null, ""].includes(v);
|
|
3095
|
-
rule.message = "required";
|
|
3096
|
-
}
|
|
3097
|
-
else {
|
|
3098
|
-
Object.assign(rule, o);
|
|
3099
|
-
}
|
|
3100
|
-
const isValid = rule.validator?.(data[field], this);
|
|
3101
|
-
if (typeof isValid === "string") {
|
|
3102
|
-
rule.message = isValid;
|
|
3103
|
-
}
|
|
3104
|
-
if (isValid !== true) {
|
|
3105
|
-
PubSub.publish(`${id}:invalid:${field}`, {
|
|
3106
|
-
message: rule.message,
|
|
3107
|
-
status: "error",
|
|
3108
|
-
});
|
|
3109
|
-
return false;
|
|
3110
|
-
}
|
|
3111
|
-
PubSub.publish(`${id}:invalid:${name}`, {
|
|
3112
|
-
message: null,
|
|
3113
|
-
status: "normal",
|
|
3114
|
-
});
|
|
3115
|
-
return true;
|
|
3116
|
-
}
|
|
3140
|
+
const names = field ? [field] : Object.keys(this.cacheData);
|
|
3117
3141
|
let isAllValid = true;
|
|
3118
|
-
|
|
3142
|
+
names.forEach((name) => {
|
|
3119
3143
|
const o = rules[name];
|
|
3120
|
-
if (o === undefined)
|
|
3144
|
+
if (!field && o === undefined)
|
|
3121
3145
|
return;
|
|
3122
3146
|
const rule = {
|
|
3123
|
-
validator: (v) =>
|
|
3124
|
-
message: undefined,
|
|
3147
|
+
validator: (v) => Array.isArray(v) ? v.length > 0 : ![undefined, null, ""].includes(v),
|
|
3125
3148
|
};
|
|
3126
|
-
if (typeof o === "function")
|
|
3149
|
+
if (typeof o === "function")
|
|
3127
3150
|
rule.validator = o;
|
|
3128
|
-
|
|
3129
|
-
else if (o === true) {
|
|
3130
|
-
rule.validator = (v) => ![undefined, null, ""].includes(v);
|
|
3151
|
+
else if (o === true)
|
|
3131
3152
|
rule.message = "required";
|
|
3132
|
-
|
|
3133
|
-
else {
|
|
3153
|
+
else if (o)
|
|
3134
3154
|
Object.assign(rule, o);
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
if (typeof isValid === "string") {
|
|
3155
|
+
const isValid = rule.validator?.(getDeep(data, name), this);
|
|
3156
|
+
if (typeof isValid === "string")
|
|
3138
3157
|
rule.message = isValid;
|
|
3139
|
-
}
|
|
3140
3158
|
if (isValid !== true) {
|
|
3141
3159
|
PubSub.publish(`${id}:invalid:${name}`, {
|
|
3142
3160
|
message: rule.message,
|
|
@@ -3151,7 +3169,7 @@ class IFormInstance {
|
|
|
3151
3169
|
});
|
|
3152
3170
|
}
|
|
3153
3171
|
});
|
|
3154
|
-
return isAllValid ?
|
|
3172
|
+
return field ? isAllValid : isAllValid ? data : false;
|
|
3155
3173
|
}
|
|
3156
3174
|
}
|
|
3157
3175
|
function useForm(form) {
|
|
@@ -3172,7 +3190,7 @@ function useConfig(configs, formProps) {
|
|
|
3172
3190
|
};
|
|
3173
3191
|
const node = useMemo(() => {
|
|
3174
3192
|
return (jsx(Form, { ...formProps, onChange: handleChange, form: form, children: configs.map((config) => {
|
|
3175
|
-
const { name, label, required, component: El, componentProps = {}, colspan = 1, render,
|
|
3193
|
+
const { name, label, required, component: El, componentProps = {}, colspan = 1, render, shouldRender, } = config;
|
|
3176
3194
|
const { className, style } = componentProps;
|
|
3177
3195
|
if (shouldRender && !shouldRender(values, form)) {
|
|
3178
3196
|
return jsx(Fragment$1, {}, name);
|
|
@@ -3207,20 +3225,27 @@ const Form = (props) => {
|
|
|
3207
3225
|
}
|
|
3208
3226
|
return columns;
|
|
3209
3227
|
}, [columns]);
|
|
3228
|
+
const initialAppliedRef = useRef(false);
|
|
3210
3229
|
useEffect(() => {
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3230
|
+
if (!initialAppliedRef.current && initialValues) {
|
|
3231
|
+
const flat = crush(initialValues);
|
|
3232
|
+
Object.keys(flat).forEach((key) => {
|
|
3233
|
+
form.set(key, flat[key]);
|
|
3234
|
+
});
|
|
3235
|
+
initialAppliedRef.current = true;
|
|
3236
|
+
}
|
|
3237
|
+
if (rules) {
|
|
3238
|
+
form.rules = rules;
|
|
3239
|
+
}
|
|
3240
|
+
}, [initialValues, rules, form]);
|
|
3216
3241
|
useEffect(() => {
|
|
3217
|
-
PubSub.subscribe(`${form.id}:change`, (
|
|
3242
|
+
const token = PubSub.subscribe(`${form.id}:change`, (_evt, v) => {
|
|
3218
3243
|
onChange?.(v.name, v.value);
|
|
3219
3244
|
});
|
|
3220
3245
|
return () => {
|
|
3221
|
-
PubSub.unsubscribe(
|
|
3246
|
+
PubSub.unsubscribe(token);
|
|
3222
3247
|
};
|
|
3223
|
-
}, []);
|
|
3248
|
+
}, [form.id, onChange]);
|
|
3224
3249
|
return (jsx(Context, { value: form, children: jsx("form", { style: {
|
|
3225
3250
|
...style,
|
|
3226
3251
|
width,
|
|
@@ -5002,6 +5027,7 @@ function TimePicker(props) {
|
|
|
5002
5027
|
const [active, setActive] = useState(false);
|
|
5003
5028
|
const handleChange = (v) => {
|
|
5004
5029
|
setTimeValue(v);
|
|
5030
|
+
onChange?.(v);
|
|
5005
5031
|
};
|
|
5006
5032
|
const handleFallback = (v) => {
|
|
5007
5033
|
setSafeValue(v);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TValidator, TRule } from './type.js';
|
|
2
2
|
|
|
3
3
|
declare class IFormInstance {
|
|
4
4
|
readonly id?: string;
|
|
5
5
|
data: Record<string, any>;
|
|
6
6
|
cacheData: Record<string, any>;
|
|
7
|
-
rules?:
|
|
7
|
+
rules?: Record<string, boolean | TValidator | TRule>;
|
|
8
8
|
constructor();
|
|
9
9
|
get(field?: string): any;
|
|
10
10
|
set(field: any, value?: any): void;
|
|
11
|
-
delete(field:
|
|
11
|
+
delete(field: string): void;
|
|
12
12
|
clear(): void;
|
|
13
13
|
validate(field?: string): Promise<boolean | Record<string, any>>;
|
|
14
14
|
}
|