@wordrhyme/auto-crud 1.1.7 → 1.2.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/dist/index.cjs +255 -19
- package/dist/index.d.cts +57 -2
- package/dist/index.d.ts +73 -18
- package/dist/index.js +254 -22
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -5232,6 +5232,67 @@ function createEditFormSchema(schema, options) {
|
|
|
5232
5232
|
});
|
|
5233
5233
|
}
|
|
5234
5234
|
|
|
5235
|
+
//#endregion
|
|
5236
|
+
//#region src/lib/registries.ts
|
|
5237
|
+
function createRegistry(label) {
|
|
5238
|
+
const entries = /* @__PURE__ */ new Map();
|
|
5239
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
5240
|
+
const notify = () => {
|
|
5241
|
+
queueMicrotask(() => {
|
|
5242
|
+
for (const listener of listeners) listener();
|
|
5243
|
+
});
|
|
5244
|
+
};
|
|
5245
|
+
return {
|
|
5246
|
+
register(name, value) {
|
|
5247
|
+
if (entries.has(name)) {
|
|
5248
|
+
console.warn(`[AutoCrud] ${label} "${name}" is already registered.`);
|
|
5249
|
+
return;
|
|
5250
|
+
}
|
|
5251
|
+
entries.set(name, value);
|
|
5252
|
+
notify();
|
|
5253
|
+
},
|
|
5254
|
+
unregister(name) {
|
|
5255
|
+
if (!entries.delete(name)) return;
|
|
5256
|
+
notify();
|
|
5257
|
+
},
|
|
5258
|
+
get(name) {
|
|
5259
|
+
return entries.get(name);
|
|
5260
|
+
},
|
|
5261
|
+
all() {
|
|
5262
|
+
return Object.fromEntries(entries);
|
|
5263
|
+
},
|
|
5264
|
+
subscribe(listener) {
|
|
5265
|
+
listeners.add(listener);
|
|
5266
|
+
return () => listeners.delete(listener);
|
|
5267
|
+
}
|
|
5268
|
+
};
|
|
5269
|
+
}
|
|
5270
|
+
const formComponents = createRegistry("form component");
|
|
5271
|
+
const dataSources = createRegistry("data source");
|
|
5272
|
+
function normalizeDataSourceConfig(config) {
|
|
5273
|
+
if (typeof config === "string") return config.length > 0 ? {
|
|
5274
|
+
key: config,
|
|
5275
|
+
dependsOn: [],
|
|
5276
|
+
resetOnChange: false
|
|
5277
|
+
} : void 0;
|
|
5278
|
+
if (!config?.key) return void 0;
|
|
5279
|
+
return {
|
|
5280
|
+
key: config.key,
|
|
5281
|
+
dependsOn: Array.isArray(config.dependsOn) ? config.dependsOn : [],
|
|
5282
|
+
resetOnChange: config.resetOnChange === true
|
|
5283
|
+
};
|
|
5284
|
+
}
|
|
5285
|
+
function normalizeOptions(result) {
|
|
5286
|
+
const options = Array.isArray(result) ? result : result?.options;
|
|
5287
|
+
if (!Array.isArray(options)) return [];
|
|
5288
|
+
return options.filter((option) => {
|
|
5289
|
+
return typeof option === "object" && option !== null && typeof option.value === "string" && typeof option.label === "string";
|
|
5290
|
+
}).map((option) => ({
|
|
5291
|
+
...option,
|
|
5292
|
+
value: String(option.value)
|
|
5293
|
+
}));
|
|
5294
|
+
}
|
|
5295
|
+
|
|
5235
5296
|
//#endregion
|
|
5236
5297
|
//#region src/components/auto-crud/auto-form.tsx
|
|
5237
5298
|
const COMBOBOX_LIST_CLASS = "[&_[cmdk-list]]:max-h-[360px] [&_[cmdk-list]]:overflow-x-hidden [&_[cmdk-list]]:overflow-y-auto";
|
|
@@ -5266,6 +5327,104 @@ function AutoCrudMultiCombobox({ options = [],...props }) {
|
|
|
5266
5327
|
options
|
|
5267
5328
|
});
|
|
5268
5329
|
}
|
|
5330
|
+
const defaultFieldComponents = {
|
|
5331
|
+
Combobox: {
|
|
5332
|
+
component: FormilyCombobox,
|
|
5333
|
+
decorator: "FormItem"
|
|
5334
|
+
},
|
|
5335
|
+
MultiCombobox: {
|
|
5336
|
+
component: FormilyMultiCombobox,
|
|
5337
|
+
decorator: "FormItem"
|
|
5338
|
+
},
|
|
5339
|
+
Switch: {
|
|
5340
|
+
component: FormilySwitch,
|
|
5341
|
+
decorator: "FormItem"
|
|
5342
|
+
}
|
|
5343
|
+
};
|
|
5344
|
+
function useRegistryVersion$1(subscribe) {
|
|
5345
|
+
const [version, setVersion] = (0, react.useState)(0);
|
|
5346
|
+
(0, react.useEffect)(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
|
|
5347
|
+
return version;
|
|
5348
|
+
}
|
|
5349
|
+
function isDataSourceConfig(value) {
|
|
5350
|
+
if (typeof value === "string") return value.length > 0;
|
|
5351
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
5352
|
+
return typeof value.key === "string";
|
|
5353
|
+
}
|
|
5354
|
+
function collectDataSourceConfigs(schema, result = {}) {
|
|
5355
|
+
const properties = schema.properties;
|
|
5356
|
+
if (!properties || typeof properties !== "object") return result;
|
|
5357
|
+
for (const [key, property] of Object.entries(properties)) {
|
|
5358
|
+
if (!property || typeof property !== "object" || Array.isArray(property)) continue;
|
|
5359
|
+
const record = property;
|
|
5360
|
+
const customDataSource = record["x-data-source"];
|
|
5361
|
+
const schemaDataSource = record.dataSource;
|
|
5362
|
+
const dataSourceConfig = isDataSourceConfig(customDataSource) ? customDataSource : isDataSourceConfig(schemaDataSource) ? schemaDataSource : void 0;
|
|
5363
|
+
if (dataSourceConfig) result[key] = dataSourceConfig;
|
|
5364
|
+
collectDataSourceConfigs(record, result);
|
|
5365
|
+
}
|
|
5366
|
+
return result;
|
|
5367
|
+
}
|
|
5368
|
+
function useFormDataSources(form, schema) {
|
|
5369
|
+
(0, react.useEffect)(() => {
|
|
5370
|
+
const sourceEntries = Object.entries(collectDataSourceConfigs(schema)).map(([fieldName, config]) => {
|
|
5371
|
+
const normalized = normalizeDataSourceConfig(config);
|
|
5372
|
+
return normalized ? [fieldName, normalized] : void 0;
|
|
5373
|
+
}).filter((entry) => entry !== void 0);
|
|
5374
|
+
if (sourceEntries.length === 0) return;
|
|
5375
|
+
let active = true;
|
|
5376
|
+
const effectId = Symbol("autoCrudDataSources");
|
|
5377
|
+
const loadVersions = /* @__PURE__ */ new Map();
|
|
5378
|
+
const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
|
|
5379
|
+
const loadFieldOptions = async (fieldName, source) => {
|
|
5380
|
+
const version = (loadVersions.get(fieldName) ?? 0) + 1;
|
|
5381
|
+
loadVersions.set(fieldName, version);
|
|
5382
|
+
const loader = dataSources.get(source.key);
|
|
5383
|
+
if (!loader) {
|
|
5384
|
+
form.setFieldState(fieldName, (state) => {
|
|
5385
|
+
state.dataSource = [];
|
|
5386
|
+
});
|
|
5387
|
+
return;
|
|
5388
|
+
}
|
|
5389
|
+
try {
|
|
5390
|
+
const options = normalizeOptions(await loader({
|
|
5391
|
+
field: fieldName,
|
|
5392
|
+
values: Object.fromEntries(source.dependsOn.map((dependency) => [dependency, form.getValuesIn(dependency)])),
|
|
5393
|
+
signal: controller?.signal
|
|
5394
|
+
}));
|
|
5395
|
+
if (!active || loadVersions.get(fieldName) !== version) return;
|
|
5396
|
+
form.setFieldState(fieldName, (state) => {
|
|
5397
|
+
state.dataSource = options;
|
|
5398
|
+
});
|
|
5399
|
+
} catch (error) {
|
|
5400
|
+
if (!active || controller?.signal.aborted) return;
|
|
5401
|
+
console.warn(`[AutoCrud] Failed to load data source "${source.key}".`, error);
|
|
5402
|
+
form.setFieldState(fieldName, (state) => {
|
|
5403
|
+
state.dataSource = [];
|
|
5404
|
+
});
|
|
5405
|
+
}
|
|
5406
|
+
};
|
|
5407
|
+
for (const [fieldName, source] of sourceEntries) loadFieldOptions(fieldName, source);
|
|
5408
|
+
form.addEffects(effectId, () => {
|
|
5409
|
+
for (const dependency of new Set(sourceEntries.flatMap(([, source]) => source.dependsOn))) (0, __formily_core.onFieldValueChange)(dependency, () => {
|
|
5410
|
+
for (const [fieldName, source] of sourceEntries) {
|
|
5411
|
+
if (!source.dependsOn.includes(dependency)) continue;
|
|
5412
|
+
if (source.resetOnChange) form.setValuesIn(fieldName, void 0);
|
|
5413
|
+
loadFieldOptions(fieldName, source);
|
|
5414
|
+
}
|
|
5415
|
+
});
|
|
5416
|
+
});
|
|
5417
|
+
return () => {
|
|
5418
|
+
active = false;
|
|
5419
|
+
controller?.abort();
|
|
5420
|
+
form.removeEffects(effectId);
|
|
5421
|
+
};
|
|
5422
|
+
}, [
|
|
5423
|
+
form,
|
|
5424
|
+
schema,
|
|
5425
|
+
useRegistryVersion$1(dataSources.subscribe)
|
|
5426
|
+
]);
|
|
5427
|
+
}
|
|
5269
5428
|
function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
|
|
5270
5429
|
const form = (0, react.useMemo)(() => (0, __formily_core.createForm)({ initialValues }), [JSON.stringify(initialValues)]);
|
|
5271
5430
|
const formSchema = (0, react.useMemo)(() => createEditFormSchema(zodSchema, {
|
|
@@ -5281,6 +5440,11 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
5281
5440
|
labelAlign,
|
|
5282
5441
|
labelWidth
|
|
5283
5442
|
]);
|
|
5443
|
+
const fieldComponents = (0, react.useMemo)(() => ({ fields: {
|
|
5444
|
+
...defaultFieldComponents,
|
|
5445
|
+
...formComponents.all()
|
|
5446
|
+
} }), [useRegistryVersion$1(formComponents.subscribe)]);
|
|
5447
|
+
useFormDataSources(form, formSchema);
|
|
5284
5448
|
const handleSubmit = async () => {
|
|
5285
5449
|
await form.validate();
|
|
5286
5450
|
if (form.valid) await onSubmit(form.values);
|
|
@@ -5290,20 +5454,7 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
5290
5454
|
form,
|
|
5291
5455
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_formily_shadcn.JsonSchemaField, {
|
|
5292
5456
|
schema: formSchema,
|
|
5293
|
-
components:
|
|
5294
|
-
Combobox: {
|
|
5295
|
-
component: FormilyCombobox,
|
|
5296
|
-
decorator: "FormItem"
|
|
5297
|
-
},
|
|
5298
|
-
MultiCombobox: {
|
|
5299
|
-
component: FormilyMultiCombobox,
|
|
5300
|
-
decorator: "FormItem"
|
|
5301
|
-
},
|
|
5302
|
-
Switch: {
|
|
5303
|
-
component: FormilySwitch,
|
|
5304
|
-
decorator: "FormItem"
|
|
5305
|
-
}
|
|
5306
|
-
} }
|
|
5457
|
+
components: fieldComponents
|
|
5307
5458
|
}), showSubmitButton && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5308
5459
|
className: "flex justify-end gap-2 mt-6",
|
|
5309
5460
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.Button, {
|
|
@@ -6117,6 +6268,7 @@ function mergeFieldConfig(base, override) {
|
|
|
6117
6268
|
...base,
|
|
6118
6269
|
...override,
|
|
6119
6270
|
enum: override?.enum ?? base?.enum,
|
|
6271
|
+
dataSource: override?.dataSource ?? base?.dataSource,
|
|
6120
6272
|
table: mergeFieldPart(base?.table, override?.table),
|
|
6121
6273
|
filter: mergeFieldPart(base?.filter, override?.filter),
|
|
6122
6274
|
form: mergeFieldPart(base?.form, override?.form)
|
|
@@ -6149,6 +6301,69 @@ function toBatchOptions(options) {
|
|
|
6149
6301
|
value
|
|
6150
6302
|
}));
|
|
6151
6303
|
}
|
|
6304
|
+
function getFilterDataSource(config) {
|
|
6305
|
+
if (config.filter && typeof config.filter === "object") return config.filter.dataSource ?? config.dataSource;
|
|
6306
|
+
return config.dataSource;
|
|
6307
|
+
}
|
|
6308
|
+
function shouldLoadDynamicFilterOptions(config) {
|
|
6309
|
+
if (config.filter === false) return false;
|
|
6310
|
+
if (normalizeFieldOptions(config.enum)) return false;
|
|
6311
|
+
if (config.filter && typeof config.filter === "object") {
|
|
6312
|
+
if (config.filter.enabled === false || config.filter.hidden === true) return false;
|
|
6313
|
+
if (normalizeFieldOptions(config.filter.options)) return false;
|
|
6314
|
+
}
|
|
6315
|
+
return normalizeDataSourceConfig(getFilterDataSource(config)) !== void 0;
|
|
6316
|
+
}
|
|
6317
|
+
function useRegistryVersion(subscribe) {
|
|
6318
|
+
const [version, setVersion] = react.useState(0);
|
|
6319
|
+
react.useEffect(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
|
|
6320
|
+
return version;
|
|
6321
|
+
}
|
|
6322
|
+
function useDynamicFilterOptions(fields) {
|
|
6323
|
+
const registryVersion = useRegistryVersion(dataSources.subscribe);
|
|
6324
|
+
const [optionsByField, setOptionsByField] = react.useState({});
|
|
6325
|
+
const sourceEntries = react.useMemo(() => {
|
|
6326
|
+
if (!fields) return [];
|
|
6327
|
+
return Object.entries(fields).flatMap(([field, config]) => {
|
|
6328
|
+
if (!shouldLoadDynamicFilterOptions(config)) return [];
|
|
6329
|
+
const source = normalizeDataSourceConfig(getFilterDataSource(config));
|
|
6330
|
+
return source ? [{
|
|
6331
|
+
field,
|
|
6332
|
+
source
|
|
6333
|
+
}] : [];
|
|
6334
|
+
});
|
|
6335
|
+
}, [fields]);
|
|
6336
|
+
react.useEffect(() => {
|
|
6337
|
+
if (sourceEntries.length === 0) {
|
|
6338
|
+
setOptionsByField({});
|
|
6339
|
+
return;
|
|
6340
|
+
}
|
|
6341
|
+
let active = true;
|
|
6342
|
+
const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
|
|
6343
|
+
Promise.all(sourceEntries.map(async ({ field, source }) => {
|
|
6344
|
+
const loader = dataSources.get(source.key);
|
|
6345
|
+
if (!loader) return [field, []];
|
|
6346
|
+
try {
|
|
6347
|
+
return [field, normalizeOptions(await loader({
|
|
6348
|
+
field,
|
|
6349
|
+
values: {},
|
|
6350
|
+
signal: controller?.signal
|
|
6351
|
+
}))];
|
|
6352
|
+
} catch (error) {
|
|
6353
|
+
if (!controller?.signal.aborted) console.warn(`[AutoCrud] Failed to load filter data source "${source.key}".`, error);
|
|
6354
|
+
return [field, []];
|
|
6355
|
+
}
|
|
6356
|
+
})).then((entries) => {
|
|
6357
|
+
if (!active) return;
|
|
6358
|
+
setOptionsByField(Object.fromEntries(entries));
|
|
6359
|
+
});
|
|
6360
|
+
return () => {
|
|
6361
|
+
active = false;
|
|
6362
|
+
controller?.abort();
|
|
6363
|
+
};
|
|
6364
|
+
}, [sourceEntries, registryVersion]);
|
|
6365
|
+
return optionsByField;
|
|
6366
|
+
}
|
|
6152
6367
|
function getOptionLabel(value, options) {
|
|
6153
6368
|
const stringValue = String(value);
|
|
6154
6369
|
return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
|
|
@@ -6157,15 +6372,21 @@ function getOptionLabel(value, options) {
|
|
|
6157
6372
|
* 从统一配置生成表格 overrides
|
|
6158
6373
|
* 当 filter 配置存在时,合并到 meta 中(不影响列隐藏)
|
|
6159
6374
|
*/
|
|
6160
|
-
function buildTableOverrides(fields, legacyOverrides) {
|
|
6375
|
+
function buildTableOverrides(fields, legacyOverrides, dynamicFilterOptions) {
|
|
6161
6376
|
const result = { ...legacyOverrides };
|
|
6162
6377
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6163
|
-
const
|
|
6378
|
+
const fieldOptions = normalizeFieldOptions(config.enum);
|
|
6379
|
+
const tableOptions = toTableOptions(fieldOptions);
|
|
6380
|
+
const dynamicOptions = !fieldOptions ? toTableOptions(normalizeFieldOptions(dynamicFilterOptions?.[key])) : void 0;
|
|
6164
6381
|
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
6165
6382
|
const fieldEnumMeta = tableOptions ? {
|
|
6166
6383
|
options: tableOptions,
|
|
6167
6384
|
variant: "multiSelect"
|
|
6168
6385
|
} : void 0;
|
|
6386
|
+
const fieldDataSourceMeta = dynamicOptions ? {
|
|
6387
|
+
options: dynamicOptions,
|
|
6388
|
+
variant: "multiSelect"
|
|
6389
|
+
} : void 0;
|
|
6169
6390
|
let filterMeta;
|
|
6170
6391
|
if (config.filter && typeof config.filter === "object") {
|
|
6171
6392
|
if (config.filter.enabled !== false && config.filter.hidden !== true) {
|
|
@@ -6183,11 +6404,12 @@ function buildTableOverrides(fields, legacyOverrides) {
|
|
|
6183
6404
|
enableColumnFilter: false
|
|
6184
6405
|
};
|
|
6185
6406
|
}
|
|
6186
|
-
if (fieldEnumMeta || tableMeta || filterMeta) result[key] = {
|
|
6407
|
+
if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || filterMeta) result[key] = {
|
|
6187
6408
|
...result[key],
|
|
6188
6409
|
meta: {
|
|
6189
6410
|
...result[key]?.meta ?? {},
|
|
6190
6411
|
...fieldEnumMeta ?? {},
|
|
6412
|
+
...fieldDataSourceMeta ?? {},
|
|
6191
6413
|
...tableMeta ?? {},
|
|
6192
6414
|
...filterMeta ?? {}
|
|
6193
6415
|
}
|
|
@@ -6225,7 +6447,8 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
6225
6447
|
"x-hidden": true
|
|
6226
6448
|
};
|
|
6227
6449
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6228
|
-
const fieldOptions = normalizeFieldOptions(config.enum);
|
|
6450
|
+
const fieldOptions = normalizeFieldOptions((config.form && typeof config.form === "object" ? config.form : void 0)?.enum) ?? normalizeFieldOptions(config.enum);
|
|
6451
|
+
const fieldDataSource = fieldOptions || !config.dataSource ? void 0 : normalizeDataSourceConfig(config.dataSource);
|
|
6229
6452
|
if (config.label) result[key] = {
|
|
6230
6453
|
...result[key],
|
|
6231
6454
|
title: config.label
|
|
@@ -6238,6 +6461,10 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
6238
6461
|
...result[key],
|
|
6239
6462
|
enum: fieldOptions
|
|
6240
6463
|
};
|
|
6464
|
+
if (fieldDataSource) result[key] = {
|
|
6465
|
+
...result[key],
|
|
6466
|
+
"x-data-source": config.dataSource
|
|
6467
|
+
};
|
|
6241
6468
|
if (config.form === false) result[key] = {
|
|
6242
6469
|
...result[key],
|
|
6243
6470
|
"x-hidden": true
|
|
@@ -6495,6 +6722,7 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6495
6722
|
const [selectedCount, setSelectedCount] = react.useState(0);
|
|
6496
6723
|
const [exporting, setExporting] = react.useState(false);
|
|
6497
6724
|
const getSelectedRowsRef = react.useRef(null);
|
|
6725
|
+
const dynamicFilterOptions = useDynamicFilterOptions(resolvedFields);
|
|
6498
6726
|
const importColumns = react.useMemo(() => {
|
|
6499
6727
|
const shape = resolvedSchema.shape;
|
|
6500
6728
|
const denySet = new Set(denyFields ?? []);
|
|
@@ -6531,7 +6759,11 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6531
6759
|
setExporting(false);
|
|
6532
6760
|
}
|
|
6533
6761
|
}, [selectedCount, handleExport]);
|
|
6534
|
-
const tableOverrides = react.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides), [
|
|
6762
|
+
const tableOverrides = react.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides, dynamicFilterOptions), [
|
|
6763
|
+
resolvedFields,
|
|
6764
|
+
tableConfig?.overrides,
|
|
6765
|
+
dynamicFilterOptions
|
|
6766
|
+
]);
|
|
6535
6767
|
const formOverrides = react.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
|
|
6536
6768
|
resolvedFields,
|
|
6537
6769
|
formConfig?.overrides,
|
|
@@ -8104,6 +8336,7 @@ exports.createMemoryDataSource = createMemoryDataSource;
|
|
|
8104
8336
|
exports.createSelectColumn = createSelectColumn;
|
|
8105
8337
|
exports.createTRPCDataSource = createTRPCDataSource;
|
|
8106
8338
|
exports.createTableSchema = createTableSchema;
|
|
8339
|
+
exports.dataSources = dataSources;
|
|
8107
8340
|
exports.dataToCSV = dataToCSV;
|
|
8108
8341
|
exports.deDE = deDE;
|
|
8109
8342
|
exports.downloadCSVTemplate = downloadCSVTemplate;
|
|
@@ -8111,6 +8344,7 @@ exports.enUS = enUS;
|
|
|
8111
8344
|
exports.esES = esES;
|
|
8112
8345
|
exports.exportAllToCSV = exportAllToCSV;
|
|
8113
8346
|
exports.exportTableToCSV = exportTableToCSV;
|
|
8347
|
+
exports.formComponents = formComponents;
|
|
8114
8348
|
exports.formatDate = formatDate;
|
|
8115
8349
|
exports.frFR = frFR;
|
|
8116
8350
|
exports.generateCSVTemplate = generateCSVTemplate;
|
|
@@ -8119,6 +8353,8 @@ exports.humanize = humanize;
|
|
|
8119
8353
|
exports.jaJP = jaJP;
|
|
8120
8354
|
exports.koKR = koKR;
|
|
8121
8355
|
exports.noopToastAdapter = noopToastAdapter;
|
|
8356
|
+
exports.normalizeDataSourceConfig = normalizeDataSourceConfig;
|
|
8357
|
+
exports.normalizeOptions = normalizeOptions;
|
|
8122
8358
|
exports.parseAsArrayOf = parseAsArrayOf;
|
|
8123
8359
|
exports.parseAsInteger = parseAsInteger;
|
|
8124
8360
|
exports.parseAsString = parseAsString;
|
package/dist/index.d.cts
CHANGED
|
@@ -622,6 +622,57 @@ type LocaleProp = string | DeepPartial<AutoCrudLocale>;
|
|
|
622
622
|
*/
|
|
623
623
|
declare function resolveLocale(localeProp?: LocaleProp): AutoCrudLocale;
|
|
624
624
|
//#endregion
|
|
625
|
+
//#region src/lib/registries.d.ts
|
|
626
|
+
type AutoCrudFormComponentConfig = {
|
|
627
|
+
component: React$1.ComponentType<any>;
|
|
628
|
+
decorator?: string | React$1.ComponentType<any>;
|
|
629
|
+
[key: string]: unknown;
|
|
630
|
+
};
|
|
631
|
+
type AutoCrudOption = {
|
|
632
|
+
value: string;
|
|
633
|
+
label: string;
|
|
634
|
+
searchText?: string | string[];
|
|
635
|
+
keywords?: string[];
|
|
636
|
+
count?: number;
|
|
637
|
+
disabled?: boolean;
|
|
638
|
+
};
|
|
639
|
+
type AutoCrudDataSourceContext = {
|
|
640
|
+
field: string;
|
|
641
|
+
search?: string;
|
|
642
|
+
values?: Record<string, unknown>;
|
|
643
|
+
signal?: AbortSignal;
|
|
644
|
+
};
|
|
645
|
+
type AutoCrudDataSourceResult = AutoCrudOption[] | {
|
|
646
|
+
options?: AutoCrudOption[];
|
|
647
|
+
};
|
|
648
|
+
type AutoCrudDataSourceLoader = (context: AutoCrudDataSourceContext) => AutoCrudDataSourceResult | Promise<AutoCrudDataSourceResult>;
|
|
649
|
+
type AutoCrudDataSourceConfig = string | {
|
|
650
|
+
key: string;
|
|
651
|
+
dependsOn?: string[];
|
|
652
|
+
resetOnChange?: boolean;
|
|
653
|
+
};
|
|
654
|
+
type RegistryListener = () => void;
|
|
655
|
+
declare const formComponents: {
|
|
656
|
+
register(name: string, value: AutoCrudFormComponentConfig): void;
|
|
657
|
+
unregister(name: string): void;
|
|
658
|
+
get(name: string): AutoCrudFormComponentConfig | undefined;
|
|
659
|
+
all(): Record<string, AutoCrudFormComponentConfig>;
|
|
660
|
+
subscribe(listener: RegistryListener): () => void;
|
|
661
|
+
};
|
|
662
|
+
declare const dataSources: {
|
|
663
|
+
register(name: string, value: AutoCrudDataSourceLoader): void;
|
|
664
|
+
unregister(name: string): void;
|
|
665
|
+
get(name: string): AutoCrudDataSourceLoader | undefined;
|
|
666
|
+
all(): Record<string, AutoCrudDataSourceLoader>;
|
|
667
|
+
subscribe(listener: RegistryListener): () => void;
|
|
668
|
+
};
|
|
669
|
+
declare function normalizeDataSourceConfig(config: AutoCrudDataSourceConfig | undefined): {
|
|
670
|
+
key: string;
|
|
671
|
+
dependsOn: string[];
|
|
672
|
+
resetOnChange: boolean;
|
|
673
|
+
} | undefined;
|
|
674
|
+
declare function normalizeOptions(result: AutoCrudDataSourceResult | undefined): AutoCrudOption[];
|
|
675
|
+
//#endregion
|
|
625
676
|
//#region src/components/auto-crud/auto-crud-table.d.ts
|
|
626
677
|
/**
|
|
627
678
|
* 筛选器独立配置
|
|
@@ -634,6 +685,8 @@ interface FilterConfig {
|
|
|
634
685
|
variant?: 'text' | 'number' | 'range' | 'date' | 'dateRange' | 'boolean' | 'select' | 'multiSelect';
|
|
635
686
|
/** select/multiSelect 的选项列表 */
|
|
636
687
|
options?: FieldOption[];
|
|
688
|
+
/** select/multiSelect 的动态选项源 */
|
|
689
|
+
dataSource?: AutoCrudDataSourceConfig;
|
|
637
690
|
/** range 的最小/最大值 */
|
|
638
691
|
range?: [number, number];
|
|
639
692
|
/** number 的单位 */
|
|
@@ -664,6 +717,8 @@ interface Field {
|
|
|
664
717
|
label?: string;
|
|
665
718
|
/** 字段级静态选项(表单、筛选、展示共用) */
|
|
666
719
|
enum?: FieldOption[];
|
|
720
|
+
/** 字段级动态选项源(表单、筛选、展示共用) */
|
|
721
|
+
dataSource?: AutoCrudDataSourceConfig;
|
|
667
722
|
/** 是否隐藏(表格和表单都隐藏) */
|
|
668
723
|
hidden?: boolean;
|
|
669
724
|
/** 是否参与 AutoCrud 全局搜索 */
|
|
@@ -1404,7 +1459,7 @@ interface MultiComboboxTriggerRenderProps {
|
|
|
1404
1459
|
disabled?: boolean;
|
|
1405
1460
|
readOnly?: boolean;
|
|
1406
1461
|
}
|
|
1407
|
-
interface MultiComboboxProps extends Omit<ComponentProps<typeof Command>, 'value' | 'onChange' | 'onValueChange'> {
|
|
1462
|
+
interface MultiComboboxProps extends Omit<ComponentProps<typeof Command>, 'value' | 'defaultValue' | 'onChange' | 'onValueChange'> {
|
|
1408
1463
|
value?: string[];
|
|
1409
1464
|
defaultValue?: string[];
|
|
1410
1465
|
onChange?: (value: string[]) => void;
|
|
@@ -1759,4 +1814,4 @@ declare function exportAllToCSV<T extends Record<string, unknown>>(data: T[], op
|
|
|
1759
1814
|
*/
|
|
1760
1815
|
declare function downloadCSVTemplate(headers: string[], filename?: string): void;
|
|
1761
1816
|
//#endregion
|
|
1762
|
-
export { type ActionItem, type ActionsColumnConfig, type AutoCrudLocale, AutoCrudTable, type AutoCrudTableProps, AutoForm, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, SchemaAdapter, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|
|
1817
|
+
export { type ActionItem, type ActionsColumnConfig, type AutoCrudDataSourceConfig, type AutoCrudDataSourceContext, type AutoCrudDataSourceLoader, type AutoCrudFormComponentConfig, type AutoCrudLocale, type AutoCrudOption, AutoCrudTable, type AutoCrudTableProps, AutoForm, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, SchemaAdapter, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as _tanstack_react_table0 from "@tanstack/react-table";
|
|
|
4
4
|
import { Column, ColumnDef, ColumnSort, Row, RowData, Table, TableOptions, TableState } from "@tanstack/react-table";
|
|
5
5
|
import { Command, DropdownMenuTrigger, PopoverContent } from "@pixpilot/shadcn";
|
|
6
6
|
import { ClassValue } from "clsx";
|
|
7
|
-
import * as
|
|
7
|
+
import * as react_jsx_runtime3 from "react/jsx-runtime";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { ISchema } from "@formily/json-schema";
|
|
10
10
|
|
|
@@ -362,7 +362,7 @@ declare function AutoTableActionBar<TData>({
|
|
|
362
362
|
enableDelete,
|
|
363
363
|
extraActions,
|
|
364
364
|
actions
|
|
365
|
-
}: AutoTableActionBarProps<TData>):
|
|
365
|
+
}: AutoTableActionBarProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
366
366
|
//#endregion
|
|
367
367
|
//#region src/lib/schema-bridge/types.d.ts
|
|
368
368
|
/**
|
|
@@ -530,7 +530,7 @@ declare function AutoTable<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
530
530
|
showDefaultExport,
|
|
531
531
|
onSelectedCountChange,
|
|
532
532
|
getSelectedRows
|
|
533
|
-
}: AutoTableProps<T>):
|
|
533
|
+
}: AutoTableProps<T>): react_jsx_runtime3.JSX.Element;
|
|
534
534
|
//#endregion
|
|
535
535
|
//#region src/i18n/locale.d.ts
|
|
536
536
|
/**
|
|
@@ -622,6 +622,57 @@ type LocaleProp = string | DeepPartial<AutoCrudLocale>;
|
|
|
622
622
|
*/
|
|
623
623
|
declare function resolveLocale(localeProp?: LocaleProp): AutoCrudLocale;
|
|
624
624
|
//#endregion
|
|
625
|
+
//#region src/lib/registries.d.ts
|
|
626
|
+
type AutoCrudFormComponentConfig = {
|
|
627
|
+
component: React$1.ComponentType<any>;
|
|
628
|
+
decorator?: string | React$1.ComponentType<any>;
|
|
629
|
+
[key: string]: unknown;
|
|
630
|
+
};
|
|
631
|
+
type AutoCrudOption = {
|
|
632
|
+
value: string;
|
|
633
|
+
label: string;
|
|
634
|
+
searchText?: string | string[];
|
|
635
|
+
keywords?: string[];
|
|
636
|
+
count?: number;
|
|
637
|
+
disabled?: boolean;
|
|
638
|
+
};
|
|
639
|
+
type AutoCrudDataSourceContext = {
|
|
640
|
+
field: string;
|
|
641
|
+
search?: string;
|
|
642
|
+
values?: Record<string, unknown>;
|
|
643
|
+
signal?: AbortSignal;
|
|
644
|
+
};
|
|
645
|
+
type AutoCrudDataSourceResult = AutoCrudOption[] | {
|
|
646
|
+
options?: AutoCrudOption[];
|
|
647
|
+
};
|
|
648
|
+
type AutoCrudDataSourceLoader = (context: AutoCrudDataSourceContext) => AutoCrudDataSourceResult | Promise<AutoCrudDataSourceResult>;
|
|
649
|
+
type AutoCrudDataSourceConfig = string | {
|
|
650
|
+
key: string;
|
|
651
|
+
dependsOn?: string[];
|
|
652
|
+
resetOnChange?: boolean;
|
|
653
|
+
};
|
|
654
|
+
type RegistryListener = () => void;
|
|
655
|
+
declare const formComponents: {
|
|
656
|
+
register(name: string, value: AutoCrudFormComponentConfig): void;
|
|
657
|
+
unregister(name: string): void;
|
|
658
|
+
get(name: string): AutoCrudFormComponentConfig | undefined;
|
|
659
|
+
all(): Record<string, AutoCrudFormComponentConfig>;
|
|
660
|
+
subscribe(listener: RegistryListener): () => void;
|
|
661
|
+
};
|
|
662
|
+
declare const dataSources: {
|
|
663
|
+
register(name: string, value: AutoCrudDataSourceLoader): void;
|
|
664
|
+
unregister(name: string): void;
|
|
665
|
+
get(name: string): AutoCrudDataSourceLoader | undefined;
|
|
666
|
+
all(): Record<string, AutoCrudDataSourceLoader>;
|
|
667
|
+
subscribe(listener: RegistryListener): () => void;
|
|
668
|
+
};
|
|
669
|
+
declare function normalizeDataSourceConfig(config: AutoCrudDataSourceConfig | undefined): {
|
|
670
|
+
key: string;
|
|
671
|
+
dependsOn: string[];
|
|
672
|
+
resetOnChange: boolean;
|
|
673
|
+
} | undefined;
|
|
674
|
+
declare function normalizeOptions(result: AutoCrudDataSourceResult | undefined): AutoCrudOption[];
|
|
675
|
+
//#endregion
|
|
625
676
|
//#region src/components/auto-crud/auto-crud-table.d.ts
|
|
626
677
|
/**
|
|
627
678
|
* 筛选器独立配置
|
|
@@ -634,6 +685,8 @@ interface FilterConfig {
|
|
|
634
685
|
variant?: 'text' | 'number' | 'range' | 'date' | 'dateRange' | 'boolean' | 'select' | 'multiSelect';
|
|
635
686
|
/** select/multiSelect 的选项列表 */
|
|
636
687
|
options?: FieldOption[];
|
|
688
|
+
/** select/multiSelect 的动态选项源 */
|
|
689
|
+
dataSource?: AutoCrudDataSourceConfig;
|
|
637
690
|
/** range 的最小/最大值 */
|
|
638
691
|
range?: [number, number];
|
|
639
692
|
/** number 的单位 */
|
|
@@ -664,6 +717,8 @@ interface Field {
|
|
|
664
717
|
label?: string;
|
|
665
718
|
/** 字段级静态选项(表单、筛选、展示共用) */
|
|
666
719
|
enum?: FieldOption[];
|
|
720
|
+
/** 字段级动态选项源(表单、筛选、展示共用) */
|
|
721
|
+
dataSource?: AutoCrudDataSourceConfig;
|
|
667
722
|
/** 是否隐藏(表格和表单都隐藏) */
|
|
668
723
|
hidden?: boolean;
|
|
669
724
|
/** 是否参与 AutoCrud 全局搜索 */
|
|
@@ -880,7 +935,7 @@ declare function AutoCrudTable<TSchema extends z.ZodObject<z.ZodRawShape>>({
|
|
|
880
935
|
toolbarActions,
|
|
881
936
|
locale: localeProp,
|
|
882
937
|
onCreate
|
|
883
|
-
}: AutoCrudTableProps<TSchema>):
|
|
938
|
+
}: AutoCrudTableProps<TSchema>): react_jsx_runtime3.JSX.Element;
|
|
884
939
|
//#endregion
|
|
885
940
|
//#region src/components/auto-crud/auto-form.d.ts
|
|
886
941
|
interface AutoFormProps<T extends z.ZodObject<z.ZodRawShape>> {
|
|
@@ -912,7 +967,7 @@ declare function AutoFormInner<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
912
967
|
labelAlign,
|
|
913
968
|
labelWidth,
|
|
914
969
|
showSubmitButton
|
|
915
|
-
}: AutoFormProps<T>, ref: React.Ref<AutoFormRef>):
|
|
970
|
+
}: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime3.JSX.Element;
|
|
916
971
|
declare const AutoForm: <T extends z.ZodObject<z.ZodRawShape>>(props: AutoFormProps<T> & {
|
|
917
972
|
ref?: React.Ref<AutoFormRef>;
|
|
918
973
|
}) => ReturnType<typeof AutoFormInner>;
|
|
@@ -1214,7 +1269,7 @@ declare function AutoTableSimpleFilters<TData>({
|
|
|
1214
1269
|
filters: externalFilters,
|
|
1215
1270
|
onFiltersChange,
|
|
1216
1271
|
leading
|
|
1217
|
-
}: AutoTableSimpleFiltersProps<TData>):
|
|
1272
|
+
}: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime3.JSX.Element | null;
|
|
1218
1273
|
//#endregion
|
|
1219
1274
|
//#region src/components/auto-crud/form-modal.d.ts
|
|
1220
1275
|
type ModalVariant = "dialog" | "sheet";
|
|
@@ -1256,7 +1311,7 @@ declare function CrudFormModal<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
1256
1311
|
labelAlign,
|
|
1257
1312
|
labelWidth,
|
|
1258
1313
|
className
|
|
1259
|
-
}: CrudFormModalProps<T>):
|
|
1314
|
+
}: CrudFormModalProps<T>): react_jsx_runtime3.JSX.Element;
|
|
1260
1315
|
//#endregion
|
|
1261
1316
|
//#region src/components/auto-crud/import-dialog.d.ts
|
|
1262
1317
|
interface ImportDialogProps {
|
|
@@ -1278,7 +1333,7 @@ declare function ImportDialog({
|
|
|
1278
1333
|
columns,
|
|
1279
1334
|
title,
|
|
1280
1335
|
locale
|
|
1281
|
-
}: ImportDialogProps):
|
|
1336
|
+
}: ImportDialogProps): react_jsx_runtime3.JSX.Element;
|
|
1282
1337
|
//#endregion
|
|
1283
1338
|
//#region src/components/auto-crud/export-dialog.d.ts
|
|
1284
1339
|
type ExportMode = "selected" | "filtered";
|
|
@@ -1298,7 +1353,7 @@ declare function ExportDialog({
|
|
|
1298
1353
|
selectedCount,
|
|
1299
1354
|
onExport,
|
|
1300
1355
|
canExportFiltered
|
|
1301
|
-
}: ExportDialogProps):
|
|
1356
|
+
}: ExportDialogProps): react_jsx_runtime3.JSX.Element;
|
|
1302
1357
|
//#endregion
|
|
1303
1358
|
//#region src/components/data-table/data-table.d.ts
|
|
1304
1359
|
interface DataTableProps<TData> extends React$1.ComponentProps<"div"> {
|
|
@@ -1311,7 +1366,7 @@ declare function DataTable<TData>({
|
|
|
1311
1366
|
children,
|
|
1312
1367
|
className,
|
|
1313
1368
|
...props
|
|
1314
|
-
}: DataTableProps<TData>):
|
|
1369
|
+
}: DataTableProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1315
1370
|
//#endregion
|
|
1316
1371
|
//#region src/components/data-table/data-table-advanced-toolbar.d.ts
|
|
1317
1372
|
interface DataTableAdvancedToolbarProps<TData> extends React$1.ComponentProps<"div"> {
|
|
@@ -1322,7 +1377,7 @@ declare function DataTableAdvancedToolbar<TData>({
|
|
|
1322
1377
|
children,
|
|
1323
1378
|
className,
|
|
1324
1379
|
...props
|
|
1325
|
-
}: DataTableAdvancedToolbarProps<TData>):
|
|
1380
|
+
}: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1326
1381
|
//#endregion
|
|
1327
1382
|
//#region src/components/data-table/data-table-column-header.d.ts
|
|
1328
1383
|
interface DataTableColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {
|
|
@@ -1334,7 +1389,7 @@ declare function DataTableColumnHeader<TData, TValue>({
|
|
|
1334
1389
|
label,
|
|
1335
1390
|
className,
|
|
1336
1391
|
...props
|
|
1337
|
-
}: DataTableColumnHeaderProps<TData, TValue>):
|
|
1392
|
+
}: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
|
|
1338
1393
|
//#endregion
|
|
1339
1394
|
//#region src/components/data-table/data-table-faceted-filter.d.ts
|
|
1340
1395
|
interface DataTableFacetedFilterProps<TData, TValue> {
|
|
@@ -1348,7 +1403,7 @@ declare function DataTableFacetedFilter<TData, TValue>({
|
|
|
1348
1403
|
title,
|
|
1349
1404
|
options,
|
|
1350
1405
|
multiple
|
|
1351
|
-
}: DataTableFacetedFilterProps<TData, TValue>):
|
|
1406
|
+
}: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
|
|
1352
1407
|
//#endregion
|
|
1353
1408
|
//#region src/components/data-table/data-table-pagination.d.ts
|
|
1354
1409
|
interface DataTablePaginationProps<TData> extends React.ComponentProps<"div"> {
|
|
@@ -1360,7 +1415,7 @@ declare function DataTablePagination<TData>({
|
|
|
1360
1415
|
pageSizeOptions,
|
|
1361
1416
|
className,
|
|
1362
1417
|
...props
|
|
1363
|
-
}: DataTablePaginationProps<TData>):
|
|
1418
|
+
}: DataTablePaginationProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1364
1419
|
//#endregion
|
|
1365
1420
|
//#region src/components/data-table/data-table-toolbar.d.ts
|
|
1366
1421
|
interface DataTableToolbarProps<TData> extends React$1.ComponentProps<"div"> {
|
|
@@ -1371,7 +1426,7 @@ declare function DataTableToolbar<TData>({
|
|
|
1371
1426
|
children,
|
|
1372
1427
|
className,
|
|
1373
1428
|
...props
|
|
1374
|
-
}: DataTableToolbarProps<TData>):
|
|
1429
|
+
}: DataTableToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1375
1430
|
//#endregion
|
|
1376
1431
|
//#region src/components/data-table/data-table-view-options.d.ts
|
|
1377
1432
|
interface DataTableViewOptionsProps<TData> extends React$1.ComponentProps<typeof PopoverContent> {
|
|
@@ -1382,7 +1437,7 @@ declare function DataTableViewOptions<TData>({
|
|
|
1382
1437
|
table,
|
|
1383
1438
|
disabled,
|
|
1384
1439
|
...props
|
|
1385
|
-
}: DataTableViewOptionsProps<TData>):
|
|
1440
|
+
}: DataTableViewOptionsProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1386
1441
|
//#endregion
|
|
1387
1442
|
//#region src/components/ui/multi-combobox.d.ts
|
|
1388
1443
|
interface MultiComboboxOption {
|
|
@@ -1404,7 +1459,7 @@ interface MultiComboboxTriggerRenderProps {
|
|
|
1404
1459
|
disabled?: boolean;
|
|
1405
1460
|
readOnly?: boolean;
|
|
1406
1461
|
}
|
|
1407
|
-
interface MultiComboboxProps extends Omit<ComponentProps<typeof Command>, 'value' | 'onChange' | 'onValueChange'> {
|
|
1462
|
+
interface MultiComboboxProps extends Omit<ComponentProps<typeof Command>, 'value' | 'defaultValue' | 'onChange' | 'onValueChange'> {
|
|
1408
1463
|
value?: string[];
|
|
1409
1464
|
defaultValue?: string[];
|
|
1410
1465
|
onChange?: (value: string[]) => void;
|
|
@@ -1759,4 +1814,4 @@ declare function exportAllToCSV<T extends Record<string, unknown>>(data: T[], op
|
|
|
1759
1814
|
*/
|
|
1760
1815
|
declare function downloadCSVTemplate(headers: string[], filename?: string): void;
|
|
1761
1816
|
//#endregion
|
|
1762
|
-
export { type ActionItem, type ActionsColumnConfig, type AutoCrudLocale, AutoCrudTable, type AutoCrudTableProps, AutoForm, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, SchemaAdapter, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|
|
1817
|
+
export { type ActionItem, type ActionsColumnConfig, type AutoCrudDataSourceConfig, type AutoCrudDataSourceContext, type AutoCrudDataSourceLoader, type AutoCrudFormComponentConfig, type AutoCrudLocale, type AutoCrudOption, AutoCrudTable, type AutoCrudTableProps, AutoForm, type AutoQueryParams, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, type BatchActionConfig, type BatchActionContext, type BatchActionItem, type BatchBuiltinActionItem, type BatchBuiltinActionType, type BatchCustomActionItem, type BatchUpdateField, type ColumnOverrides, type CreateFormSchemaOptions, type CreateTableSchemaOptions, CrudFormModal, type CrudHooks, type CrudOperationPermissions, type CrudPermissions, type DataSource, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableRowAction, DataTableToolbar, DataTableViewOptions, type EnumOption, ExportDialog, type ExportDialogProps, type ExportMode, ExtendedColumnFilter, ExtendedColumnSort, type Field, type FieldOption, type FieldType, type Fields, type FilterConfig, FilterOperator, type FilterVariant, type FormSchemaOverrides, ImportDialog, type ImportDialogProps, type ImportResult, type JSONSchema, type JSONSchemaProperty, JoinOperator, type ListParams, type ListResult, type LocaleProp, MultiCombobox, type MultiComboboxOption, type MultiComboboxProps, type MultiComboboxTriggerRenderProps, Option, type ParsedImportData, type ParsedZodField, type Parser, QueryKeys, SchemaAdapter, type SimpleFieldConfig, type SimpleFieldsConfig, type ToastAdapter, type ToolbarActionItem, type ToolbarBuiltinActionItem, type ToolbarCustomActionItem, type UnifiedField, type UnifiedSchema, type UrlStateOptions, type UseAutoCrudResourceOptions, type UseAutoCrudResourceParams, type UseAutoCrudResourceReturn, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useReducer, useRef } from "react";
|
|
2
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useReducer, useRef, useState } from "react";
|
|
3
3
|
import { ArrowDownUp, BadgeCheck, CalendarIcon, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, ChevronsLeft, ChevronsRight, ChevronsUpDown, CommandIcon, Download, Ellipsis, EyeOff, FileDown, FileSpreadsheetIcon, GripVertical, ListFilter, ListFilterIcon, Loader2, PlusCircle, Settings2, Text, Trash2, Upload, X, XCircle } from "lucide-react";
|
|
4
4
|
import { flexRender, getCoreRowModel, getFacetedMinMaxValues, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
|
5
5
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Calendar, Checkbox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, Input, Label, Popover, PopoverContent, PopoverTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, Slider, Switch, cn as cn$1 } from "@pixpilot/shadcn";
|
|
@@ -15,7 +15,7 @@ import { Slot } from "@radix-ui/react-slot";
|
|
|
15
15
|
import * as ReactDOM from "react-dom";
|
|
16
16
|
import { useDirection } from "@radix-ui/react-direction";
|
|
17
17
|
import { z } from "zod";
|
|
18
|
-
import { createForm } from "@formily/core";
|
|
18
|
+
import { createForm, onFieldValueChange } from "@formily/core";
|
|
19
19
|
import { Form, JsonSchemaField } from "@pixpilot/formily-shadcn";
|
|
20
20
|
import { connect, mapProps } from "@formily/react";
|
|
21
21
|
import { toast } from "sonner";
|
|
@@ -5190,6 +5190,67 @@ function createEditFormSchema(schema, options) {
|
|
|
5190
5190
|
});
|
|
5191
5191
|
}
|
|
5192
5192
|
|
|
5193
|
+
//#endregion
|
|
5194
|
+
//#region src/lib/registries.ts
|
|
5195
|
+
function createRegistry(label) {
|
|
5196
|
+
const entries = /* @__PURE__ */ new Map();
|
|
5197
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
5198
|
+
const notify = () => {
|
|
5199
|
+
queueMicrotask(() => {
|
|
5200
|
+
for (const listener of listeners) listener();
|
|
5201
|
+
});
|
|
5202
|
+
};
|
|
5203
|
+
return {
|
|
5204
|
+
register(name, value) {
|
|
5205
|
+
if (entries.has(name)) {
|
|
5206
|
+
console.warn(`[AutoCrud] ${label} "${name}" is already registered.`);
|
|
5207
|
+
return;
|
|
5208
|
+
}
|
|
5209
|
+
entries.set(name, value);
|
|
5210
|
+
notify();
|
|
5211
|
+
},
|
|
5212
|
+
unregister(name) {
|
|
5213
|
+
if (!entries.delete(name)) return;
|
|
5214
|
+
notify();
|
|
5215
|
+
},
|
|
5216
|
+
get(name) {
|
|
5217
|
+
return entries.get(name);
|
|
5218
|
+
},
|
|
5219
|
+
all() {
|
|
5220
|
+
return Object.fromEntries(entries);
|
|
5221
|
+
},
|
|
5222
|
+
subscribe(listener) {
|
|
5223
|
+
listeners.add(listener);
|
|
5224
|
+
return () => listeners.delete(listener);
|
|
5225
|
+
}
|
|
5226
|
+
};
|
|
5227
|
+
}
|
|
5228
|
+
const formComponents = createRegistry("form component");
|
|
5229
|
+
const dataSources = createRegistry("data source");
|
|
5230
|
+
function normalizeDataSourceConfig(config) {
|
|
5231
|
+
if (typeof config === "string") return config.length > 0 ? {
|
|
5232
|
+
key: config,
|
|
5233
|
+
dependsOn: [],
|
|
5234
|
+
resetOnChange: false
|
|
5235
|
+
} : void 0;
|
|
5236
|
+
if (!config?.key) return void 0;
|
|
5237
|
+
return {
|
|
5238
|
+
key: config.key,
|
|
5239
|
+
dependsOn: Array.isArray(config.dependsOn) ? config.dependsOn : [],
|
|
5240
|
+
resetOnChange: config.resetOnChange === true
|
|
5241
|
+
};
|
|
5242
|
+
}
|
|
5243
|
+
function normalizeOptions(result) {
|
|
5244
|
+
const options = Array.isArray(result) ? result : result?.options;
|
|
5245
|
+
if (!Array.isArray(options)) return [];
|
|
5246
|
+
return options.filter((option) => {
|
|
5247
|
+
return typeof option === "object" && option !== null && typeof option.value === "string" && typeof option.label === "string";
|
|
5248
|
+
}).map((option) => ({
|
|
5249
|
+
...option,
|
|
5250
|
+
value: String(option.value)
|
|
5251
|
+
}));
|
|
5252
|
+
}
|
|
5253
|
+
|
|
5193
5254
|
//#endregion
|
|
5194
5255
|
//#region src/components/auto-crud/auto-form.tsx
|
|
5195
5256
|
const COMBOBOX_LIST_CLASS = "[&_[cmdk-list]]:max-h-[360px] [&_[cmdk-list]]:overflow-x-hidden [&_[cmdk-list]]:overflow-y-auto";
|
|
@@ -5224,6 +5285,104 @@ function AutoCrudMultiCombobox({ options = [],...props }) {
|
|
|
5224
5285
|
options
|
|
5225
5286
|
});
|
|
5226
5287
|
}
|
|
5288
|
+
const defaultFieldComponents = {
|
|
5289
|
+
Combobox: {
|
|
5290
|
+
component: FormilyCombobox,
|
|
5291
|
+
decorator: "FormItem"
|
|
5292
|
+
},
|
|
5293
|
+
MultiCombobox: {
|
|
5294
|
+
component: FormilyMultiCombobox,
|
|
5295
|
+
decorator: "FormItem"
|
|
5296
|
+
},
|
|
5297
|
+
Switch: {
|
|
5298
|
+
component: FormilySwitch,
|
|
5299
|
+
decorator: "FormItem"
|
|
5300
|
+
}
|
|
5301
|
+
};
|
|
5302
|
+
function useRegistryVersion$1(subscribe) {
|
|
5303
|
+
const [version, setVersion] = useState(0);
|
|
5304
|
+
useEffect(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
|
|
5305
|
+
return version;
|
|
5306
|
+
}
|
|
5307
|
+
function isDataSourceConfig(value) {
|
|
5308
|
+
if (typeof value === "string") return value.length > 0;
|
|
5309
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
5310
|
+
return typeof value.key === "string";
|
|
5311
|
+
}
|
|
5312
|
+
function collectDataSourceConfigs(schema, result = {}) {
|
|
5313
|
+
const properties = schema.properties;
|
|
5314
|
+
if (!properties || typeof properties !== "object") return result;
|
|
5315
|
+
for (const [key, property] of Object.entries(properties)) {
|
|
5316
|
+
if (!property || typeof property !== "object" || Array.isArray(property)) continue;
|
|
5317
|
+
const record = property;
|
|
5318
|
+
const customDataSource = record["x-data-source"];
|
|
5319
|
+
const schemaDataSource = record.dataSource;
|
|
5320
|
+
const dataSourceConfig = isDataSourceConfig(customDataSource) ? customDataSource : isDataSourceConfig(schemaDataSource) ? schemaDataSource : void 0;
|
|
5321
|
+
if (dataSourceConfig) result[key] = dataSourceConfig;
|
|
5322
|
+
collectDataSourceConfigs(record, result);
|
|
5323
|
+
}
|
|
5324
|
+
return result;
|
|
5325
|
+
}
|
|
5326
|
+
function useFormDataSources(form, schema) {
|
|
5327
|
+
useEffect(() => {
|
|
5328
|
+
const sourceEntries = Object.entries(collectDataSourceConfigs(schema)).map(([fieldName, config]) => {
|
|
5329
|
+
const normalized = normalizeDataSourceConfig(config);
|
|
5330
|
+
return normalized ? [fieldName, normalized] : void 0;
|
|
5331
|
+
}).filter((entry) => entry !== void 0);
|
|
5332
|
+
if (sourceEntries.length === 0) return;
|
|
5333
|
+
let active = true;
|
|
5334
|
+
const effectId = Symbol("autoCrudDataSources");
|
|
5335
|
+
const loadVersions = /* @__PURE__ */ new Map();
|
|
5336
|
+
const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
|
|
5337
|
+
const loadFieldOptions = async (fieldName, source) => {
|
|
5338
|
+
const version = (loadVersions.get(fieldName) ?? 0) + 1;
|
|
5339
|
+
loadVersions.set(fieldName, version);
|
|
5340
|
+
const loader = dataSources.get(source.key);
|
|
5341
|
+
if (!loader) {
|
|
5342
|
+
form.setFieldState(fieldName, (state) => {
|
|
5343
|
+
state.dataSource = [];
|
|
5344
|
+
});
|
|
5345
|
+
return;
|
|
5346
|
+
}
|
|
5347
|
+
try {
|
|
5348
|
+
const options = normalizeOptions(await loader({
|
|
5349
|
+
field: fieldName,
|
|
5350
|
+
values: Object.fromEntries(source.dependsOn.map((dependency) => [dependency, form.getValuesIn(dependency)])),
|
|
5351
|
+
signal: controller?.signal
|
|
5352
|
+
}));
|
|
5353
|
+
if (!active || loadVersions.get(fieldName) !== version) return;
|
|
5354
|
+
form.setFieldState(fieldName, (state) => {
|
|
5355
|
+
state.dataSource = options;
|
|
5356
|
+
});
|
|
5357
|
+
} catch (error) {
|
|
5358
|
+
if (!active || controller?.signal.aborted) return;
|
|
5359
|
+
console.warn(`[AutoCrud] Failed to load data source "${source.key}".`, error);
|
|
5360
|
+
form.setFieldState(fieldName, (state) => {
|
|
5361
|
+
state.dataSource = [];
|
|
5362
|
+
});
|
|
5363
|
+
}
|
|
5364
|
+
};
|
|
5365
|
+
for (const [fieldName, source] of sourceEntries) loadFieldOptions(fieldName, source);
|
|
5366
|
+
form.addEffects(effectId, () => {
|
|
5367
|
+
for (const dependency of new Set(sourceEntries.flatMap(([, source]) => source.dependsOn))) onFieldValueChange(dependency, () => {
|
|
5368
|
+
for (const [fieldName, source] of sourceEntries) {
|
|
5369
|
+
if (!source.dependsOn.includes(dependency)) continue;
|
|
5370
|
+
if (source.resetOnChange) form.setValuesIn(fieldName, void 0);
|
|
5371
|
+
loadFieldOptions(fieldName, source);
|
|
5372
|
+
}
|
|
5373
|
+
});
|
|
5374
|
+
});
|
|
5375
|
+
return () => {
|
|
5376
|
+
active = false;
|
|
5377
|
+
controller?.abort();
|
|
5378
|
+
form.removeEffects(effectId);
|
|
5379
|
+
};
|
|
5380
|
+
}, [
|
|
5381
|
+
form,
|
|
5382
|
+
schema,
|
|
5383
|
+
useRegistryVersion$1(dataSources.subscribe)
|
|
5384
|
+
]);
|
|
5385
|
+
}
|
|
5227
5386
|
function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides, mode = "create", loading = false, gridColumns = 1, labelAlign = "top", labelWidth, showSubmitButton = true }, ref) {
|
|
5228
5387
|
const form = useMemo(() => createForm({ initialValues }), [JSON.stringify(initialValues)]);
|
|
5229
5388
|
const formSchema = useMemo(() => createEditFormSchema(zodSchema, {
|
|
@@ -5239,6 +5398,11 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
5239
5398
|
labelAlign,
|
|
5240
5399
|
labelWidth
|
|
5241
5400
|
]);
|
|
5401
|
+
const fieldComponents = useMemo(() => ({ fields: {
|
|
5402
|
+
...defaultFieldComponents,
|
|
5403
|
+
...formComponents.all()
|
|
5404
|
+
} }), [useRegistryVersion$1(formComponents.subscribe)]);
|
|
5405
|
+
useFormDataSources(form, formSchema);
|
|
5242
5406
|
const handleSubmit = async () => {
|
|
5243
5407
|
await form.validate();
|
|
5244
5408
|
if (form.valid) await onSubmit(form.values);
|
|
@@ -5248,20 +5412,7 @@ function AutoFormInner({ schema: zodSchema, initialValues, onSubmit, overrides,
|
|
|
5248
5412
|
form,
|
|
5249
5413
|
children: [/* @__PURE__ */ jsx(JsonSchemaField, {
|
|
5250
5414
|
schema: formSchema,
|
|
5251
|
-
components:
|
|
5252
|
-
Combobox: {
|
|
5253
|
-
component: FormilyCombobox,
|
|
5254
|
-
decorator: "FormItem"
|
|
5255
|
-
},
|
|
5256
|
-
MultiCombobox: {
|
|
5257
|
-
component: FormilyMultiCombobox,
|
|
5258
|
-
decorator: "FormItem"
|
|
5259
|
-
},
|
|
5260
|
-
Switch: {
|
|
5261
|
-
component: FormilySwitch,
|
|
5262
|
-
decorator: "FormItem"
|
|
5263
|
-
}
|
|
5264
|
-
} }
|
|
5415
|
+
components: fieldComponents
|
|
5265
5416
|
}), showSubmitButton && /* @__PURE__ */ jsx("div", {
|
|
5266
5417
|
className: "flex justify-end gap-2 mt-6",
|
|
5267
5418
|
children: /* @__PURE__ */ jsx(Button, {
|
|
@@ -6075,6 +6226,7 @@ function mergeFieldConfig(base, override) {
|
|
|
6075
6226
|
...base,
|
|
6076
6227
|
...override,
|
|
6077
6228
|
enum: override?.enum ?? base?.enum,
|
|
6229
|
+
dataSource: override?.dataSource ?? base?.dataSource,
|
|
6078
6230
|
table: mergeFieldPart(base?.table, override?.table),
|
|
6079
6231
|
filter: mergeFieldPart(base?.filter, override?.filter),
|
|
6080
6232
|
form: mergeFieldPart(base?.form, override?.form)
|
|
@@ -6107,6 +6259,69 @@ function toBatchOptions(options) {
|
|
|
6107
6259
|
value
|
|
6108
6260
|
}));
|
|
6109
6261
|
}
|
|
6262
|
+
function getFilterDataSource(config) {
|
|
6263
|
+
if (config.filter && typeof config.filter === "object") return config.filter.dataSource ?? config.dataSource;
|
|
6264
|
+
return config.dataSource;
|
|
6265
|
+
}
|
|
6266
|
+
function shouldLoadDynamicFilterOptions(config) {
|
|
6267
|
+
if (config.filter === false) return false;
|
|
6268
|
+
if (normalizeFieldOptions(config.enum)) return false;
|
|
6269
|
+
if (config.filter && typeof config.filter === "object") {
|
|
6270
|
+
if (config.filter.enabled === false || config.filter.hidden === true) return false;
|
|
6271
|
+
if (normalizeFieldOptions(config.filter.options)) return false;
|
|
6272
|
+
}
|
|
6273
|
+
return normalizeDataSourceConfig(getFilterDataSource(config)) !== void 0;
|
|
6274
|
+
}
|
|
6275
|
+
function useRegistryVersion(subscribe) {
|
|
6276
|
+
const [version, setVersion] = React.useState(0);
|
|
6277
|
+
React.useEffect(() => subscribe(() => setVersion((current) => current + 1)), [subscribe]);
|
|
6278
|
+
return version;
|
|
6279
|
+
}
|
|
6280
|
+
function useDynamicFilterOptions(fields) {
|
|
6281
|
+
const registryVersion = useRegistryVersion(dataSources.subscribe);
|
|
6282
|
+
const [optionsByField, setOptionsByField] = React.useState({});
|
|
6283
|
+
const sourceEntries = React.useMemo(() => {
|
|
6284
|
+
if (!fields) return [];
|
|
6285
|
+
return Object.entries(fields).flatMap(([field, config]) => {
|
|
6286
|
+
if (!shouldLoadDynamicFilterOptions(config)) return [];
|
|
6287
|
+
const source = normalizeDataSourceConfig(getFilterDataSource(config));
|
|
6288
|
+
return source ? [{
|
|
6289
|
+
field,
|
|
6290
|
+
source
|
|
6291
|
+
}] : [];
|
|
6292
|
+
});
|
|
6293
|
+
}, [fields]);
|
|
6294
|
+
React.useEffect(() => {
|
|
6295
|
+
if (sourceEntries.length === 0) {
|
|
6296
|
+
setOptionsByField({});
|
|
6297
|
+
return;
|
|
6298
|
+
}
|
|
6299
|
+
let active = true;
|
|
6300
|
+
const controller = typeof AbortController === "undefined" ? void 0 : new AbortController();
|
|
6301
|
+
Promise.all(sourceEntries.map(async ({ field, source }) => {
|
|
6302
|
+
const loader = dataSources.get(source.key);
|
|
6303
|
+
if (!loader) return [field, []];
|
|
6304
|
+
try {
|
|
6305
|
+
return [field, normalizeOptions(await loader({
|
|
6306
|
+
field,
|
|
6307
|
+
values: {},
|
|
6308
|
+
signal: controller?.signal
|
|
6309
|
+
}))];
|
|
6310
|
+
} catch (error) {
|
|
6311
|
+
if (!controller?.signal.aborted) console.warn(`[AutoCrud] Failed to load filter data source "${source.key}".`, error);
|
|
6312
|
+
return [field, []];
|
|
6313
|
+
}
|
|
6314
|
+
})).then((entries) => {
|
|
6315
|
+
if (!active) return;
|
|
6316
|
+
setOptionsByField(Object.fromEntries(entries));
|
|
6317
|
+
});
|
|
6318
|
+
return () => {
|
|
6319
|
+
active = false;
|
|
6320
|
+
controller?.abort();
|
|
6321
|
+
};
|
|
6322
|
+
}, [sourceEntries, registryVersion]);
|
|
6323
|
+
return optionsByField;
|
|
6324
|
+
}
|
|
6110
6325
|
function getOptionLabel(value, options) {
|
|
6111
6326
|
const stringValue = String(value);
|
|
6112
6327
|
return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
|
|
@@ -6115,15 +6330,21 @@ function getOptionLabel(value, options) {
|
|
|
6115
6330
|
* 从统一配置生成表格 overrides
|
|
6116
6331
|
* 当 filter 配置存在时,合并到 meta 中(不影响列隐藏)
|
|
6117
6332
|
*/
|
|
6118
|
-
function buildTableOverrides(fields, legacyOverrides) {
|
|
6333
|
+
function buildTableOverrides(fields, legacyOverrides, dynamicFilterOptions) {
|
|
6119
6334
|
const result = { ...legacyOverrides };
|
|
6120
6335
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6121
|
-
const
|
|
6336
|
+
const fieldOptions = normalizeFieldOptions(config.enum);
|
|
6337
|
+
const tableOptions = toTableOptions(fieldOptions);
|
|
6338
|
+
const dynamicOptions = !fieldOptions ? toTableOptions(normalizeFieldOptions(dynamicFilterOptions?.[key])) : void 0;
|
|
6122
6339
|
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
6123
6340
|
const fieldEnumMeta = tableOptions ? {
|
|
6124
6341
|
options: tableOptions,
|
|
6125
6342
|
variant: "multiSelect"
|
|
6126
6343
|
} : void 0;
|
|
6344
|
+
const fieldDataSourceMeta = dynamicOptions ? {
|
|
6345
|
+
options: dynamicOptions,
|
|
6346
|
+
variant: "multiSelect"
|
|
6347
|
+
} : void 0;
|
|
6127
6348
|
let filterMeta;
|
|
6128
6349
|
if (config.filter && typeof config.filter === "object") {
|
|
6129
6350
|
if (config.filter.enabled !== false && config.filter.hidden !== true) {
|
|
@@ -6141,11 +6362,12 @@ function buildTableOverrides(fields, legacyOverrides) {
|
|
|
6141
6362
|
enableColumnFilter: false
|
|
6142
6363
|
};
|
|
6143
6364
|
}
|
|
6144
|
-
if (fieldEnumMeta || tableMeta || filterMeta) result[key] = {
|
|
6365
|
+
if (fieldEnumMeta || fieldDataSourceMeta || tableMeta || filterMeta) result[key] = {
|
|
6145
6366
|
...result[key],
|
|
6146
6367
|
meta: {
|
|
6147
6368
|
...result[key]?.meta ?? {},
|
|
6148
6369
|
...fieldEnumMeta ?? {},
|
|
6370
|
+
...fieldDataSourceMeta ?? {},
|
|
6149
6371
|
...tableMeta ?? {},
|
|
6150
6372
|
...filterMeta ?? {}
|
|
6151
6373
|
}
|
|
@@ -6183,7 +6405,8 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
6183
6405
|
"x-hidden": true
|
|
6184
6406
|
};
|
|
6185
6407
|
if (fields) for (const [key, config] of Object.entries(fields)) {
|
|
6186
|
-
const fieldOptions = normalizeFieldOptions(config.enum);
|
|
6408
|
+
const fieldOptions = normalizeFieldOptions((config.form && typeof config.form === "object" ? config.form : void 0)?.enum) ?? normalizeFieldOptions(config.enum);
|
|
6409
|
+
const fieldDataSource = fieldOptions || !config.dataSource ? void 0 : normalizeDataSourceConfig(config.dataSource);
|
|
6187
6410
|
if (config.label) result[key] = {
|
|
6188
6411
|
...result[key],
|
|
6189
6412
|
title: config.label
|
|
@@ -6196,6 +6419,10 @@ function buildFormOverrides(fields, legacyOverrides, denyFields) {
|
|
|
6196
6419
|
...result[key],
|
|
6197
6420
|
enum: fieldOptions
|
|
6198
6421
|
};
|
|
6422
|
+
if (fieldDataSource) result[key] = {
|
|
6423
|
+
...result[key],
|
|
6424
|
+
"x-data-source": config.dataSource
|
|
6425
|
+
};
|
|
6199
6426
|
if (config.form === false) result[key] = {
|
|
6200
6427
|
...result[key],
|
|
6201
6428
|
"x-hidden": true
|
|
@@ -6453,6 +6680,7 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6453
6680
|
const [selectedCount, setSelectedCount] = React.useState(0);
|
|
6454
6681
|
const [exporting, setExporting] = React.useState(false);
|
|
6455
6682
|
const getSelectedRowsRef = React.useRef(null);
|
|
6683
|
+
const dynamicFilterOptions = useDynamicFilterOptions(resolvedFields);
|
|
6456
6684
|
const importColumns = React.useMemo(() => {
|
|
6457
6685
|
const shape = resolvedSchema.shape;
|
|
6458
6686
|
const denySet = new Set(denyFields ?? []);
|
|
@@ -6489,7 +6717,11 @@ function AutoCrudTable({ title, description, schema, resource, fields, table: ta
|
|
|
6489
6717
|
setExporting(false);
|
|
6490
6718
|
}
|
|
6491
6719
|
}, [selectedCount, handleExport]);
|
|
6492
|
-
const tableOverrides = React.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides), [
|
|
6720
|
+
const tableOverrides = React.useMemo(() => buildTableOverrides(resolvedFields, tableConfig?.overrides, dynamicFilterOptions), [
|
|
6721
|
+
resolvedFields,
|
|
6722
|
+
tableConfig?.overrides,
|
|
6723
|
+
dynamicFilterOptions
|
|
6724
|
+
]);
|
|
6493
6725
|
const formOverrides = React.useMemo(() => buildFormOverrides(resolvedFields, formConfig?.overrides, denyFields), [
|
|
6494
6726
|
resolvedFields,
|
|
6495
6727
|
formConfig?.overrides,
|
|
@@ -8036,4 +8268,4 @@ function createMemoryDataSource(initialData = []) {
|
|
|
8036
8268
|
}
|
|
8037
8269
|
|
|
8038
8270
|
//#endregion
|
|
8039
|
-
export { AutoCrudTable, AutoForm, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, CrudFormModal, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableViewOptions, ExportDialog, ImportDialog, MultiCombobox, SchemaAdapter, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|
|
8271
|
+
export { AutoCrudTable, AutoForm, AutoTable, AutoTableActionBar, AutoTableSimpleFilters, CrudFormModal, DataTable, DataTableAdvancedToolbar, DataTableColumnHeader, DataTableFacetedFilter, DataTablePagination, DataTableToolbar, DataTableViewOptions, ExportDialog, ImportDialog, MultiCombobox, SchemaAdapter, cn, coerceRowValues, createActionsColumn, createEditFormSchema, createFormSchema, createMemoryDataSource, createSelectColumn, createTRPCDataSource, createTableSchema, dataSources, dataToCSV, deDE, downloadCSVTemplate, enUS, esES, exportAllToCSV, exportTableToCSV, formComponents, formatDate, frFR, generateCSVTemplate, getUrlParams, humanize, jaJP, koKR, noopToastAdapter, normalizeDataSourceConfig, normalizeOptions, parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseCSV, parseImportFile, parseJSON, parseZodField, resolveLocale, setSearchParams, useAutoCrudResource, useDataTable, useQueryState, useQueryStates, useReadableFilters, useUrlState, useUrlStates, zhCN };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordrhyme/auto-crud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "Schema-first CRUD components with auto-generated tables and forms",
|
|
6
6
|
"author": "wordrhyme",
|
|
7
7
|
"license": "MIT",
|
|
@@ -65,9 +65,9 @@
|
|
|
65
65
|
"nanoid": "^5.1.6",
|
|
66
66
|
"tailwind-merge": "^3.5.0",
|
|
67
67
|
"vaul": "^1.1.2",
|
|
68
|
-
"@pixpilot/shadcn": "1.2.7",
|
|
69
68
|
"@pixpilot/formily-shadcn": "1.11.20",
|
|
70
|
-
"@pixpilot/shadcn-ui": "1.21.1"
|
|
69
|
+
"@pixpilot/shadcn-ui": "1.21.1",
|
|
70
|
+
"@pixpilot/shadcn": "1.2.7"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@tanstack/react-query": "^5.90.15",
|
|
@@ -82,11 +82,11 @@
|
|
|
82
82
|
"react-dom": "19.2.4",
|
|
83
83
|
"tsdown": "^0.15.12",
|
|
84
84
|
"typescript": "^5.9.3",
|
|
85
|
-
"@internal/prettier-config": "0.0.1",
|
|
86
85
|
"@internal/eslint-config": "0.3.0",
|
|
87
|
-
"@internal/
|
|
86
|
+
"@internal/prettier-config": "0.0.1",
|
|
87
|
+
"@internal/tsdown-config": "0.1.0",
|
|
88
88
|
"@internal/vitest-config": "0.1.0",
|
|
89
|
-
"@internal/
|
|
89
|
+
"@internal/tsconfig": "0.1.0"
|
|
90
90
|
},
|
|
91
91
|
"prettier": "@internal/prettier-config",
|
|
92
92
|
"scripts": {
|