@wordrhyme/auto-crud 1.5.5 → 1.5.7
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 +131 -105
- package/dist/index.d.cts +19 -17
- package/dist/index.d.ts +3 -1
- package/dist/index.js +131 -105
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -525,104 +525,6 @@ function DataTable({ table, actionBar, children, className,...props }) {
|
|
|
525
525
|
});
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
-
//#endregion
|
|
529
|
-
//#region src/lib/id.ts
|
|
530
|
-
const prefixes = {};
|
|
531
|
-
function generateId(prefixOrOptions, inputOptions = {}) {
|
|
532
|
-
const finalOptions = typeof prefixOrOptions === "object" ? prefixOrOptions : inputOptions;
|
|
533
|
-
const prefix = typeof prefixOrOptions === "object" ? void 0 : prefixOrOptions;
|
|
534
|
-
const { length = 12, separator = "_" } = finalOptions;
|
|
535
|
-
const id = (0, nanoid.customAlphabet)("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", length)();
|
|
536
|
-
return prefix && prefix in prefixes ? `${prefixes[prefix]}${separator}${id}` : id;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
//#endregion
|
|
540
|
-
//#region src/lib/readable-filters.ts
|
|
541
|
-
const OP_SUFFIX = "__op";
|
|
542
|
-
const INDEX_SEPARATOR = "__";
|
|
543
|
-
const RANGE_VARIANTS = new Set(["range", "dateRange"]);
|
|
544
|
-
function getColumnId(column) {
|
|
545
|
-
if ("id" in column && column.id) return String(column.id);
|
|
546
|
-
if ("accessorKey" in column && column.accessorKey) return String(column.accessorKey);
|
|
547
|
-
return null;
|
|
548
|
-
}
|
|
549
|
-
function getColumnVariant(column) {
|
|
550
|
-
if ("columnDef" in column) return column.columnDef.meta?.variant;
|
|
551
|
-
return column.meta?.variant;
|
|
552
|
-
}
|
|
553
|
-
function splitKey(key) {
|
|
554
|
-
const match = key.match(/^(.*?)(?:__(\d+))?$/);
|
|
555
|
-
if (!match) return { base: key };
|
|
556
|
-
const index$1 = match[2] ? Number(match[2]) : void 0;
|
|
557
|
-
return {
|
|
558
|
-
base: match[1] ?? key,
|
|
559
|
-
index: index$1
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
function isFilterKey(key, columnIds) {
|
|
563
|
-
const { base } = splitKey(key.endsWith(OP_SUFFIX) ? key.slice(0, -4) : key);
|
|
564
|
-
return columnIds.has(base);
|
|
565
|
-
}
|
|
566
|
-
function parseValueByVariant(value, variant) {
|
|
567
|
-
if (variant === "multiSelect") return value ? value.split(",").filter(Boolean) : [];
|
|
568
|
-
if (RANGE_VARIANTS.has(variant)) {
|
|
569
|
-
const parts = value.split(",");
|
|
570
|
-
return [parts[0] ?? "", parts[1] ?? ""];
|
|
571
|
-
}
|
|
572
|
-
if (variant === "select") return value.split(",").filter(Boolean)[0] ?? "";
|
|
573
|
-
return value;
|
|
574
|
-
}
|
|
575
|
-
function serializeValue(value, variant) {
|
|
576
|
-
if (Array.isArray(value)) {
|
|
577
|
-
if (RANGE_VARIANTS.has(variant)) return [value[0] ?? "", value[1] ?? ""].join(",");
|
|
578
|
-
return value.join(",");
|
|
579
|
-
}
|
|
580
|
-
return value;
|
|
581
|
-
}
|
|
582
|
-
function parseReadableFilters(params, columns) {
|
|
583
|
-
const columnsById = /* @__PURE__ */ new Map();
|
|
584
|
-
for (const column of columns) {
|
|
585
|
-
const id = getColumnId(column);
|
|
586
|
-
if (id) columnsById.set(id, column);
|
|
587
|
-
}
|
|
588
|
-
const filters = [];
|
|
589
|
-
for (const [key, rawValue] of params.entries()) {
|
|
590
|
-
if (key.endsWith(OP_SUFFIX)) continue;
|
|
591
|
-
const { base } = splitKey(key);
|
|
592
|
-
const column = columnsById.get(base);
|
|
593
|
-
if (!column) continue;
|
|
594
|
-
const variant = getColumnVariant(column) ?? "text";
|
|
595
|
-
const opKey = `${key}${OP_SUFFIX}`;
|
|
596
|
-
const operator = params.get(opKey) ?? getDefaultFilterOperator(variant);
|
|
597
|
-
const parsedValue = operator === "isEmpty" || operator === "isNotEmpty" ? "" : parseValueByVariant(rawValue, variant);
|
|
598
|
-
filters.push({
|
|
599
|
-
id: base,
|
|
600
|
-
value: parsedValue,
|
|
601
|
-
variant,
|
|
602
|
-
operator,
|
|
603
|
-
filterId: key || generateId({ length: 8 })
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
return filters;
|
|
607
|
-
}
|
|
608
|
-
function applyReadableFilters(params, columns, filters) {
|
|
609
|
-
const columnIds = new Set(columns.map((column) => getColumnId(column)).filter(Boolean));
|
|
610
|
-
for (const key of Array.from(params.keys())) if (isFilterKey(key, columnIds)) params.delete(key);
|
|
611
|
-
const counters = /* @__PURE__ */ new Map();
|
|
612
|
-
for (const filter of filters) {
|
|
613
|
-
const columnId = String(filter.id);
|
|
614
|
-
const count = (counters.get(columnId) ?? 0) + 1;
|
|
615
|
-
counters.set(columnId, count);
|
|
616
|
-
const key = count === 1 ? columnId : `${columnId}${INDEX_SEPARATOR}${count}`;
|
|
617
|
-
const variant = filter.variant ?? "text";
|
|
618
|
-
const value = serializeValue(filter.value, variant);
|
|
619
|
-
params.set(key, filter.operator === "isEmpty" || filter.operator === "isNotEmpty" ? "" : value);
|
|
620
|
-
const defaultOperator = getDefaultFilterOperator(variant);
|
|
621
|
-
if (filter.operator !== defaultOperator) params.set(`${key}${OP_SUFFIX}`, filter.operator);
|
|
622
|
-
}
|
|
623
|
-
return params;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
528
|
//#endregion
|
|
627
529
|
//#region src/hooks/use-url-state.ts
|
|
628
530
|
const parseAsInteger = {
|
|
@@ -873,15 +775,120 @@ function useQueryStates(parsers, options = {}) {
|
|
|
873
775
|
}, [setValues])];
|
|
874
776
|
}
|
|
875
777
|
|
|
778
|
+
//#endregion
|
|
779
|
+
//#region src/lib/id.ts
|
|
780
|
+
const prefixes = {};
|
|
781
|
+
function generateId(prefixOrOptions, inputOptions = {}) {
|
|
782
|
+
const finalOptions = typeof prefixOrOptions === "object" ? prefixOrOptions : inputOptions;
|
|
783
|
+
const prefix = typeof prefixOrOptions === "object" ? void 0 : prefixOrOptions;
|
|
784
|
+
const { length = 12, separator = "_" } = finalOptions;
|
|
785
|
+
const id = (0, nanoid.customAlphabet)("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", length)();
|
|
786
|
+
return prefix && prefix in prefixes ? `${prefixes[prefix]}${separator}${id}` : id;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
//#endregion
|
|
790
|
+
//#region src/lib/readable-filters.ts
|
|
791
|
+
const OP_SUFFIX = "__op";
|
|
792
|
+
const INDEX_SEPARATOR = "__";
|
|
793
|
+
const RANGE_VARIANTS = new Set(["range", "dateRange"]);
|
|
794
|
+
function getColumnId(column) {
|
|
795
|
+
if ("id" in column && column.id) return String(column.id);
|
|
796
|
+
if ("accessorKey" in column && column.accessorKey) return String(column.accessorKey);
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
function getColumnVariant(column) {
|
|
800
|
+
if ("columnDef" in column) return column.columnDef.meta?.variant;
|
|
801
|
+
return column.meta?.variant;
|
|
802
|
+
}
|
|
803
|
+
function splitKey(key) {
|
|
804
|
+
const match = key.match(/^(.*?)(?:__(\d+))?$/);
|
|
805
|
+
if (!match) return { base: key };
|
|
806
|
+
const index$1 = match[2] ? Number(match[2]) : void 0;
|
|
807
|
+
return {
|
|
808
|
+
base: match[1] ?? key,
|
|
809
|
+
index: index$1
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
function isFilterKey(key, columnIds) {
|
|
813
|
+
const { base } = splitKey(key.endsWith(OP_SUFFIX) ? key.slice(0, -4) : key);
|
|
814
|
+
return columnIds.has(base);
|
|
815
|
+
}
|
|
816
|
+
function parseValueByVariant(value, variant) {
|
|
817
|
+
if (variant === "multiSelect") return value ? value.split(",").filter(Boolean) : [];
|
|
818
|
+
if (RANGE_VARIANTS.has(variant)) {
|
|
819
|
+
const parts = value.split(",");
|
|
820
|
+
return [parts[0] ?? "", parts[1] ?? ""];
|
|
821
|
+
}
|
|
822
|
+
if (variant === "select") return value.split(",").filter(Boolean)[0] ?? "";
|
|
823
|
+
return value;
|
|
824
|
+
}
|
|
825
|
+
function serializeValue(value, variant) {
|
|
826
|
+
if (Array.isArray(value)) {
|
|
827
|
+
if (RANGE_VARIANTS.has(variant)) return [value[0] ?? "", value[1] ?? ""].join(",");
|
|
828
|
+
return value.join(",");
|
|
829
|
+
}
|
|
830
|
+
return value;
|
|
831
|
+
}
|
|
832
|
+
function parseReadableFilters(params, columns) {
|
|
833
|
+
const columnsById = /* @__PURE__ */ new Map();
|
|
834
|
+
for (const column of columns) {
|
|
835
|
+
const id = getColumnId(column);
|
|
836
|
+
if (id) columnsById.set(id, column);
|
|
837
|
+
}
|
|
838
|
+
const filters = [];
|
|
839
|
+
for (const [key, rawValue] of params.entries()) {
|
|
840
|
+
if (key.endsWith(OP_SUFFIX)) continue;
|
|
841
|
+
const { base } = splitKey(key);
|
|
842
|
+
const column = columnsById.get(base);
|
|
843
|
+
if (!column) continue;
|
|
844
|
+
const variant = getColumnVariant(column) ?? "text";
|
|
845
|
+
const opKey = `${key}${OP_SUFFIX}`;
|
|
846
|
+
const operator = params.get(opKey) ?? getDefaultFilterOperator(variant);
|
|
847
|
+
const parsedValue = operator === "isEmpty" || operator === "isNotEmpty" ? "" : parseValueByVariant(rawValue, variant);
|
|
848
|
+
filters.push({
|
|
849
|
+
id: base,
|
|
850
|
+
value: parsedValue,
|
|
851
|
+
variant,
|
|
852
|
+
operator,
|
|
853
|
+
filterId: key || generateId({ length: 8 })
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
return filters;
|
|
857
|
+
}
|
|
858
|
+
function applyReadableFilters(params, columns, filters) {
|
|
859
|
+
const columnIds = new Set(columns.map((column) => getColumnId(column)).filter(Boolean));
|
|
860
|
+
for (const key of Array.from(params.keys())) if (isFilterKey(key, columnIds)) params.delete(key);
|
|
861
|
+
const counters = /* @__PURE__ */ new Map();
|
|
862
|
+
for (const filter of filters) {
|
|
863
|
+
const columnId = String(filter.id);
|
|
864
|
+
const count = (counters.get(columnId) ?? 0) + 1;
|
|
865
|
+
counters.set(columnId, count);
|
|
866
|
+
const key = count === 1 ? columnId : `${columnId}${INDEX_SEPARATOR}${count}`;
|
|
867
|
+
const variant = filter.variant ?? "text";
|
|
868
|
+
const value = serializeValue(filter.value, variant);
|
|
869
|
+
params.set(key, filter.operator === "isEmpty" || filter.operator === "isNotEmpty" ? "" : value);
|
|
870
|
+
const defaultOperator = getDefaultFilterOperator(variant);
|
|
871
|
+
if (filter.operator !== defaultOperator) params.set(`${key}${OP_SUFFIX}`, filter.operator);
|
|
872
|
+
}
|
|
873
|
+
return params;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
876
|
//#endregion
|
|
877
877
|
//#region src/hooks/use-readable-filters.ts
|
|
878
878
|
const URL_CHANGE_EVENT = "urlchange";
|
|
879
879
|
function toSearchString(params) {
|
|
880
|
-
const queryString = params.toString().replace(/%2C/
|
|
880
|
+
const queryString = params.toString().replace(/%2C/gu, ",");
|
|
881
881
|
return queryString ? `?${queryString}` : "";
|
|
882
882
|
}
|
|
883
|
+
function filterSignature(filters) {
|
|
884
|
+
return JSON.stringify(filters.map(({ id, operator, value, variant }) => JSON.stringify([
|
|
885
|
+
id,
|
|
886
|
+
operator,
|
|
887
|
+
variant === "multiSelect" && Array.isArray(value) ? [...value].sort() : value
|
|
888
|
+
])).sort());
|
|
889
|
+
}
|
|
883
890
|
function useReadableFilters(columns, options = {}) {
|
|
884
|
-
const { history = "replace", scroll = false } = options;
|
|
891
|
+
const { history = "replace", scroll = false, resetPageKey = "page" } = options;
|
|
885
892
|
const columnSnapshot = react.useMemo(() => columns, [columns]);
|
|
886
893
|
const lastWrittenUrlRef = react.useRef(null);
|
|
887
894
|
const filtersRef = react.useRef(null);
|
|
@@ -909,7 +916,10 @@ function useReadableFilters(columns, options = {}) {
|
|
|
909
916
|
}, [columnSnapshot]);
|
|
910
917
|
const writeToUrl = react.useCallback((next) => {
|
|
911
918
|
const params = getUrlParams();
|
|
919
|
+
const previousFilters = parseReadableFilters(params, columnSnapshot);
|
|
912
920
|
applyReadableFilters(params, columnSnapshot, next);
|
|
921
|
+
const nextFilters = parseReadableFilters(params, columnSnapshot);
|
|
922
|
+
if (resetPageKey !== false && resetPageKey.length > 0 && filterSignature(previousFilters) !== filterSignature(nextFilters)) params.delete(resetPageKey);
|
|
913
923
|
lastWrittenUrlRef.current = toSearchString(params);
|
|
914
924
|
setSearchParams(params, {
|
|
915
925
|
history,
|
|
@@ -918,6 +928,7 @@ function useReadableFilters(columns, options = {}) {
|
|
|
918
928
|
}, [
|
|
919
929
|
columnSnapshot,
|
|
920
930
|
history,
|
|
931
|
+
resetPageKey,
|
|
921
932
|
scroll
|
|
922
933
|
]);
|
|
923
934
|
return [filters, react.useCallback((updater) => {
|
|
@@ -1053,7 +1064,10 @@ function DataTableFilterList({ table, debounceMs = DEBOUNCE_MS$2, throttleMs = T
|
|
|
1053
1064
|
return true;
|
|
1054
1065
|
});
|
|
1055
1066
|
}, [table, columnDefs]);
|
|
1056
|
-
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1067
|
+
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1068
|
+
debounceMs,
|
|
1069
|
+
resetPageKey: table.options.meta?.queryKeys?.page ?? "page"
|
|
1070
|
+
});
|
|
1057
1071
|
const debouncedSetFilters = useDebouncedCallback(setFilters, debounceMs);
|
|
1058
1072
|
const [joinOperator, setJoinOperator] = useQueryState(table.options.meta?.queryKeys?.joinOperator ?? "", parseAsStringEnum(["and", "or"]).withDefault("and"));
|
|
1059
1073
|
const onFilterAdd = react.useCallback(() => {
|
|
@@ -1591,7 +1605,10 @@ function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = T
|
|
|
1591
1605
|
setSelectedColumn(null);
|
|
1592
1606
|
}
|
|
1593
1607
|
}, [inputValue, selectedColumn]);
|
|
1594
|
-
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1608
|
+
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1609
|
+
debounceMs,
|
|
1610
|
+
resetPageKey: table.options.meta?.queryKeys?.page ?? "page"
|
|
1611
|
+
});
|
|
1595
1612
|
const debouncedSetFilters = useDebouncedCallback(setFilters, debounceMs);
|
|
1596
1613
|
const onFilterAdd = react.useCallback((column, value) => {
|
|
1597
1614
|
if (!value.trim() && column.columnDef.meta?.variant !== "boolean") return;
|
|
@@ -2397,6 +2414,7 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2397
2414
|
const queryStateOptions = table.options.meta?.queryStateOptions;
|
|
2398
2415
|
const [queryFilters, setQueryFilters] = useReadableFilters(columns, {
|
|
2399
2416
|
...queryStateOptions,
|
|
2417
|
+
resetPageKey: table.options.meta?.queryKeys?.page ?? "page",
|
|
2400
2418
|
shallow
|
|
2401
2419
|
});
|
|
2402
2420
|
const filters = externalFilters ?? queryFilters;
|
|
@@ -3236,6 +3254,10 @@ function renderCell(value, type, options) {
|
|
|
3236
3254
|
className: "text-muted-foreground",
|
|
3237
3255
|
children: "-"
|
|
3238
3256
|
});
|
|
3257
|
+
if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3258
|
+
className: "text-muted-foreground",
|
|
3259
|
+
children: "-"
|
|
3260
|
+
});
|
|
3239
3261
|
const formatOptionValue = (optionValue) => {
|
|
3240
3262
|
const stringValue = String(optionValue);
|
|
3241
3263
|
return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
|
|
@@ -6124,7 +6146,7 @@ function mergeOptionsByField(left, right) {
|
|
|
6124
6146
|
function shouldResolveOptions(field, config, hiddenColumns) {
|
|
6125
6147
|
if (!config) return false;
|
|
6126
6148
|
if (hiddenColumns.has(field)) return false;
|
|
6127
|
-
if (getTableOptions(config)) return false;
|
|
6149
|
+
if (getTableOptions(config) && !getTableConfig(config)?.dataSource) return false;
|
|
6128
6150
|
return normalizeDataSourceConfig(getTableDataSource(config)) !== void 0;
|
|
6129
6151
|
}
|
|
6130
6152
|
function useRegistryVersion(subscribe) {
|
|
@@ -6474,7 +6496,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
6474
6496
|
const filterDataSourceSearchable = dynamicFilterState?.searchableByField[key];
|
|
6475
6497
|
const currentDynamicOptions = !fieldOptions && filterDataSourceRegistered ? toTableOptions(dynamicFilterState?.optionsByField[key] ?? []) : void 0;
|
|
6476
6498
|
const dynamicFilterLabelOptions = !fieldOptions && filterDataSourceRegistered ? dynamicFilterState?.labelOptionsByField[key] ?? dynamicFilterState?.optionsByField[key] ?? [] : void 0;
|
|
6477
|
-
const dynamicResolveOptions =
|
|
6499
|
+
const dynamicResolveOptions = dynamicResolveState?.optionsByField[key];
|
|
6478
6500
|
const mergedSharedDynamicOptions = mergeFieldOptions(dynamicFilterLabelOptions, tableConfig?.dataSource ? void 0 : dynamicResolveOptions);
|
|
6479
6501
|
const dynamicOptions = !fieldOptions && mergedSharedDynamicOptions ? toTableOptions(mergedSharedDynamicOptions) : void 0;
|
|
6480
6502
|
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
@@ -6549,7 +6571,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
6549
6571
|
};
|
|
6550
6572
|
const hasTableLabels = config.table.options !== void 0 || config.table.dataSource !== void 0;
|
|
6551
6573
|
if (display && display !== "auto" || hasTableLabels) {
|
|
6552
|
-
const options =
|
|
6574
|
+
const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
|
|
6553
6575
|
result[key] = {
|
|
6554
6576
|
...result[key],
|
|
6555
6577
|
cell: ({ row }) => renderFieldValue(row.getValue(key), "string", {
|
|
@@ -6662,6 +6684,10 @@ function renderFieldValue(value, type, booleanLocale, options, display = "auto")
|
|
|
6662
6684
|
className: "text-muted-foreground",
|
|
6663
6685
|
children: "-"
|
|
6664
6686
|
});
|
|
6687
|
+
if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6688
|
+
className: "text-muted-foreground",
|
|
6689
|
+
children: "-"
|
|
6690
|
+
});
|
|
6665
6691
|
const renderText = (item) => getOptionLabel(item, options);
|
|
6666
6692
|
if (display === "text") return Array.isArray(value) ? value.map(renderText).join(", ") : renderText(value);
|
|
6667
6693
|
if (display === "date" || display === "datetime") return formatDate(value, {}, display);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime3 from "react/jsx-runtime";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { JsonSchemaFormScope } from "@wordrhyme/formily-shadcn";
|
|
4
4
|
import * as _tanstack_react_table0 from "@tanstack/react-table";
|
|
@@ -413,7 +413,7 @@ declare function AutoTableActionBar<TData>({
|
|
|
413
413
|
extraActions,
|
|
414
414
|
actions,
|
|
415
415
|
deleteConfirmation
|
|
416
|
-
}: AutoTableActionBarProps<TData>):
|
|
416
|
+
}: AutoTableActionBarProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
417
417
|
//#endregion
|
|
418
418
|
//#region src/lib/schema-bridge/types.d.ts
|
|
419
419
|
/**
|
|
@@ -592,7 +592,7 @@ declare function AutoTable<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
592
592
|
onSelectedCountChange,
|
|
593
593
|
onSelectedRowsChange,
|
|
594
594
|
getSelectedRows
|
|
595
|
-
}: AutoTableProps<T>):
|
|
595
|
+
}: AutoTableProps<T>): react_jsx_runtime3.JSX.Element;
|
|
596
596
|
//#endregion
|
|
597
597
|
//#region src/i18n/locale.d.ts
|
|
598
598
|
/**
|
|
@@ -843,7 +843,7 @@ interface Field {
|
|
|
843
843
|
label?: string;
|
|
844
844
|
/** 排序权重,数值越小越靠前 */
|
|
845
845
|
index?: number;
|
|
846
|
-
/**
|
|
846
|
+
/** 仅用于表格展示的静态值标签;与 dataSource 同时配置时覆盖同值的动态标签 */
|
|
847
847
|
options?: FieldOption[];
|
|
848
848
|
/** 仅用于表格展示的动态值标签源 */
|
|
849
849
|
dataSource?: AutoCrudDataSourceConfig;
|
|
@@ -1093,7 +1093,7 @@ declare function AutoCrudTable<TSchema extends z.ZodObject<z.ZodRawShape>>({
|
|
|
1093
1093
|
toolbarActions,
|
|
1094
1094
|
locale: localeProp,
|
|
1095
1095
|
onCreate
|
|
1096
|
-
}: AutoCrudTableProps<TSchema>):
|
|
1096
|
+
}: AutoCrudTableProps<TSchema>): react_jsx_runtime3.JSX.Element;
|
|
1097
1097
|
//#endregion
|
|
1098
1098
|
//#region src/components/auto-crud/auto-form.d.ts
|
|
1099
1099
|
interface AutoFormProps<T extends z.ZodObject<z.ZodRawShape>> {
|
|
@@ -1132,7 +1132,7 @@ declare function AutoFormInner<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
1132
1132
|
labelAlign,
|
|
1133
1133
|
labelWidth,
|
|
1134
1134
|
showSubmitButton
|
|
1135
|
-
}: AutoFormProps<T>, ref: React.Ref<AutoFormRef>):
|
|
1135
|
+
}: AutoFormProps<T>, ref: React.Ref<AutoFormRef>): react_jsx_runtime3.JSX.Element;
|
|
1136
1136
|
declare const AutoForm: <T extends z.ZodObject<z.ZodRawShape>>(props: AutoFormProps<T> & {
|
|
1137
1137
|
ref?: React.Ref<AutoFormRef>;
|
|
1138
1138
|
}) => ReturnType<typeof AutoFormInner>;
|
|
@@ -1448,7 +1448,7 @@ declare function AutoTableSimpleFilters<TData>({
|
|
|
1448
1448
|
filters: externalFilters,
|
|
1449
1449
|
onFiltersChange,
|
|
1450
1450
|
leading
|
|
1451
|
-
}: AutoTableSimpleFiltersProps<TData>):
|
|
1451
|
+
}: AutoTableSimpleFiltersProps<TData>): react_jsx_runtime3.JSX.Element | null;
|
|
1452
1452
|
//#endregion
|
|
1453
1453
|
//#region src/components/auto-crud/form-modal.d.ts
|
|
1454
1454
|
type ModalVariant = 'dialog' | 'sheet';
|
|
@@ -1492,7 +1492,7 @@ declare function CrudFormModal<T extends z.ZodObject<z.ZodRawShape>>({
|
|
|
1492
1492
|
labelAlign,
|
|
1493
1493
|
labelWidth,
|
|
1494
1494
|
className
|
|
1495
|
-
}: CrudFormModalProps<T>):
|
|
1495
|
+
}: CrudFormModalProps<T>): react_jsx_runtime3.JSX.Element;
|
|
1496
1496
|
//#endregion
|
|
1497
1497
|
//#region src/components/auto-crud/import-dialog.d.ts
|
|
1498
1498
|
interface ImportDialogProps {
|
|
@@ -1514,7 +1514,7 @@ declare function ImportDialog({
|
|
|
1514
1514
|
columns,
|
|
1515
1515
|
title,
|
|
1516
1516
|
locale
|
|
1517
|
-
}: ImportDialogProps):
|
|
1517
|
+
}: ImportDialogProps): react_jsx_runtime3.JSX.Element;
|
|
1518
1518
|
//#endregion
|
|
1519
1519
|
//#region src/components/auto-crud/export-dialog.d.ts
|
|
1520
1520
|
type ExportMode = 'selected' | 'filtered';
|
|
@@ -1534,7 +1534,7 @@ declare function ExportDialog({
|
|
|
1534
1534
|
selectedCount,
|
|
1535
1535
|
onExport,
|
|
1536
1536
|
canExportFiltered
|
|
1537
|
-
}: ExportDialogProps):
|
|
1537
|
+
}: ExportDialogProps): react_jsx_runtime3.JSX.Element;
|
|
1538
1538
|
//#endregion
|
|
1539
1539
|
//#region src/components/data-table/data-table.d.ts
|
|
1540
1540
|
interface DataTableProps<TData> extends React$1.ComponentProps<'div'> {
|
|
@@ -1547,7 +1547,7 @@ declare function DataTable<TData>({
|
|
|
1547
1547
|
children,
|
|
1548
1548
|
className,
|
|
1549
1549
|
...props
|
|
1550
|
-
}: DataTableProps<TData>):
|
|
1550
|
+
}: DataTableProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1551
1551
|
//#endregion
|
|
1552
1552
|
//#region src/components/data-table/data-table-advanced-toolbar.d.ts
|
|
1553
1553
|
interface DataTableAdvancedToolbarProps<TData> extends React$1.ComponentProps<'div'> {
|
|
@@ -1558,7 +1558,7 @@ declare function DataTableAdvancedToolbar<TData>({
|
|
|
1558
1558
|
children,
|
|
1559
1559
|
className,
|
|
1560
1560
|
...props
|
|
1561
|
-
}: DataTableAdvancedToolbarProps<TData>):
|
|
1561
|
+
}: DataTableAdvancedToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1562
1562
|
//#endregion
|
|
1563
1563
|
//#region src/components/data-table/data-table-column-header.d.ts
|
|
1564
1564
|
interface DataTableColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {
|
|
@@ -1570,7 +1570,7 @@ declare function DataTableColumnHeader<TData, TValue>({
|
|
|
1570
1570
|
label,
|
|
1571
1571
|
className,
|
|
1572
1572
|
...props
|
|
1573
|
-
}: DataTableColumnHeaderProps<TData, TValue>):
|
|
1573
|
+
}: DataTableColumnHeaderProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
|
|
1574
1574
|
//#endregion
|
|
1575
1575
|
//#region src/components/data-table/data-table-faceted-filter.d.ts
|
|
1576
1576
|
interface DataTableFacetedFilterProps<TData, TValue> {
|
|
@@ -1584,7 +1584,7 @@ declare function DataTableFacetedFilter<TData, TValue>({
|
|
|
1584
1584
|
title,
|
|
1585
1585
|
options,
|
|
1586
1586
|
multiple
|
|
1587
|
-
}: DataTableFacetedFilterProps<TData, TValue>):
|
|
1587
|
+
}: DataTableFacetedFilterProps<TData, TValue>): react_jsx_runtime3.JSX.Element;
|
|
1588
1588
|
//#endregion
|
|
1589
1589
|
//#region src/components/data-table/data-table-pagination.d.ts
|
|
1590
1590
|
interface DataTablePaginationProps<TData> extends React.ComponentProps<'div'> {
|
|
@@ -1596,7 +1596,7 @@ declare function DataTablePagination<TData>({
|
|
|
1596
1596
|
pageSizeOptions,
|
|
1597
1597
|
className,
|
|
1598
1598
|
...props
|
|
1599
|
-
}: DataTablePaginationProps<TData>):
|
|
1599
|
+
}: DataTablePaginationProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1600
1600
|
//#endregion
|
|
1601
1601
|
//#region src/components/data-table/data-table-toolbar.d.ts
|
|
1602
1602
|
interface DataTableToolbarProps<TData> extends React$1.ComponentProps<'div'> {
|
|
@@ -1607,7 +1607,7 @@ declare function DataTableToolbar<TData>({
|
|
|
1607
1607
|
children,
|
|
1608
1608
|
className,
|
|
1609
1609
|
...props
|
|
1610
|
-
}: DataTableToolbarProps<TData>):
|
|
1610
|
+
}: DataTableToolbarProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1611
1611
|
//#endregion
|
|
1612
1612
|
//#region src/components/data-table/data-table-view-options.d.ts
|
|
1613
1613
|
interface DataTableViewOptionsProps<TData> extends React$1.ComponentProps<typeof PopoverContent> {
|
|
@@ -1618,7 +1618,7 @@ declare function DataTableViewOptions<TData>({
|
|
|
1618
1618
|
table,
|
|
1619
1619
|
disabled,
|
|
1620
1620
|
...props
|
|
1621
|
-
}: DataTableViewOptionsProps<TData>):
|
|
1621
|
+
}: DataTableViewOptionsProps<TData>): react_jsx_runtime3.JSX.Element;
|
|
1622
1622
|
//#endregion
|
|
1623
1623
|
//#region src/lib/crud-actions.d.ts
|
|
1624
1624
|
type CrudActionZone = 'toolbar' | 'row' | 'batch';
|
|
@@ -1691,6 +1691,8 @@ type ColumnLike<TData> = Column<TData> | ColumnDef<TData, unknown> | {
|
|
|
1691
1691
|
};
|
|
1692
1692
|
interface UseReadableFiltersOptions extends UrlStateOptions {
|
|
1693
1693
|
debounceMs?: number;
|
|
1694
|
+
/** Reset server-side pagination when effective filters change. */
|
|
1695
|
+
resetPageKey?: string | false;
|
|
1694
1696
|
}
|
|
1695
1697
|
declare function useReadableFilters<TData>(columns: ColumnLike<TData>[], options?: UseReadableFiltersOptions): [ExtendedColumnFilter<TData>[], (value: ExtendedColumnFilter<TData>[] | ((prev: ExtendedColumnFilter<TData>[]) => ExtendedColumnFilter<TData>[])) => void];
|
|
1696
1698
|
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -843,7 +843,7 @@ interface Field {
|
|
|
843
843
|
label?: string;
|
|
844
844
|
/** 排序权重,数值越小越靠前 */
|
|
845
845
|
index?: number;
|
|
846
|
-
/**
|
|
846
|
+
/** 仅用于表格展示的静态值标签;与 dataSource 同时配置时覆盖同值的动态标签 */
|
|
847
847
|
options?: FieldOption[];
|
|
848
848
|
/** 仅用于表格展示的动态值标签源 */
|
|
849
849
|
dataSource?: AutoCrudDataSourceConfig;
|
|
@@ -1691,6 +1691,8 @@ type ColumnLike<TData> = Column<TData> | ColumnDef<TData, unknown> | {
|
|
|
1691
1691
|
};
|
|
1692
1692
|
interface UseReadableFiltersOptions extends UrlStateOptions {
|
|
1693
1693
|
debounceMs?: number;
|
|
1694
|
+
/** Reset server-side pagination when effective filters change. */
|
|
1695
|
+
resetPageKey?: string | false;
|
|
1694
1696
|
}
|
|
1695
1697
|
declare function useReadableFilters<TData>(columns: ColumnLike<TData>[], options?: UseReadableFiltersOptions): [ExtendedColumnFilter<TData>[], (value: ExtendedColumnFilter<TData>[] | ((prev: ExtendedColumnFilter<TData>[]) => ExtendedColumnFilter<TData>[])) => void];
|
|
1696
1698
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -488,104 +488,6 @@ function DataTable({ table, actionBar, children, className,...props }) {
|
|
|
488
488
|
});
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
//#endregion
|
|
492
|
-
//#region src/lib/id.ts
|
|
493
|
-
const prefixes = {};
|
|
494
|
-
function generateId(prefixOrOptions, inputOptions = {}) {
|
|
495
|
-
const finalOptions = typeof prefixOrOptions === "object" ? prefixOrOptions : inputOptions;
|
|
496
|
-
const prefix = typeof prefixOrOptions === "object" ? void 0 : prefixOrOptions;
|
|
497
|
-
const { length = 12, separator = "_" } = finalOptions;
|
|
498
|
-
const id = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", length)();
|
|
499
|
-
return prefix && prefix in prefixes ? `${prefixes[prefix]}${separator}${id}` : id;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
//#endregion
|
|
503
|
-
//#region src/lib/readable-filters.ts
|
|
504
|
-
const OP_SUFFIX = "__op";
|
|
505
|
-
const INDEX_SEPARATOR = "__";
|
|
506
|
-
const RANGE_VARIANTS = new Set(["range", "dateRange"]);
|
|
507
|
-
function getColumnId(column) {
|
|
508
|
-
if ("id" in column && column.id) return String(column.id);
|
|
509
|
-
if ("accessorKey" in column && column.accessorKey) return String(column.accessorKey);
|
|
510
|
-
return null;
|
|
511
|
-
}
|
|
512
|
-
function getColumnVariant(column) {
|
|
513
|
-
if ("columnDef" in column) return column.columnDef.meta?.variant;
|
|
514
|
-
return column.meta?.variant;
|
|
515
|
-
}
|
|
516
|
-
function splitKey(key) {
|
|
517
|
-
const match = key.match(/^(.*?)(?:__(\d+))?$/);
|
|
518
|
-
if (!match) return { base: key };
|
|
519
|
-
const index$1 = match[2] ? Number(match[2]) : void 0;
|
|
520
|
-
return {
|
|
521
|
-
base: match[1] ?? key,
|
|
522
|
-
index: index$1
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
function isFilterKey(key, columnIds) {
|
|
526
|
-
const { base } = splitKey(key.endsWith(OP_SUFFIX) ? key.slice(0, -4) : key);
|
|
527
|
-
return columnIds.has(base);
|
|
528
|
-
}
|
|
529
|
-
function parseValueByVariant(value, variant) {
|
|
530
|
-
if (variant === "multiSelect") return value ? value.split(",").filter(Boolean) : [];
|
|
531
|
-
if (RANGE_VARIANTS.has(variant)) {
|
|
532
|
-
const parts = value.split(",");
|
|
533
|
-
return [parts[0] ?? "", parts[1] ?? ""];
|
|
534
|
-
}
|
|
535
|
-
if (variant === "select") return value.split(",").filter(Boolean)[0] ?? "";
|
|
536
|
-
return value;
|
|
537
|
-
}
|
|
538
|
-
function serializeValue(value, variant) {
|
|
539
|
-
if (Array.isArray(value)) {
|
|
540
|
-
if (RANGE_VARIANTS.has(variant)) return [value[0] ?? "", value[1] ?? ""].join(",");
|
|
541
|
-
return value.join(",");
|
|
542
|
-
}
|
|
543
|
-
return value;
|
|
544
|
-
}
|
|
545
|
-
function parseReadableFilters(params, columns) {
|
|
546
|
-
const columnsById = /* @__PURE__ */ new Map();
|
|
547
|
-
for (const column of columns) {
|
|
548
|
-
const id = getColumnId(column);
|
|
549
|
-
if (id) columnsById.set(id, column);
|
|
550
|
-
}
|
|
551
|
-
const filters = [];
|
|
552
|
-
for (const [key, rawValue] of params.entries()) {
|
|
553
|
-
if (key.endsWith(OP_SUFFIX)) continue;
|
|
554
|
-
const { base } = splitKey(key);
|
|
555
|
-
const column = columnsById.get(base);
|
|
556
|
-
if (!column) continue;
|
|
557
|
-
const variant = getColumnVariant(column) ?? "text";
|
|
558
|
-
const opKey = `${key}${OP_SUFFIX}`;
|
|
559
|
-
const operator = params.get(opKey) ?? getDefaultFilterOperator(variant);
|
|
560
|
-
const parsedValue = operator === "isEmpty" || operator === "isNotEmpty" ? "" : parseValueByVariant(rawValue, variant);
|
|
561
|
-
filters.push({
|
|
562
|
-
id: base,
|
|
563
|
-
value: parsedValue,
|
|
564
|
-
variant,
|
|
565
|
-
operator,
|
|
566
|
-
filterId: key || generateId({ length: 8 })
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
return filters;
|
|
570
|
-
}
|
|
571
|
-
function applyReadableFilters(params, columns, filters) {
|
|
572
|
-
const columnIds = new Set(columns.map((column) => getColumnId(column)).filter(Boolean));
|
|
573
|
-
for (const key of Array.from(params.keys())) if (isFilterKey(key, columnIds)) params.delete(key);
|
|
574
|
-
const counters = /* @__PURE__ */ new Map();
|
|
575
|
-
for (const filter of filters) {
|
|
576
|
-
const columnId = String(filter.id);
|
|
577
|
-
const count = (counters.get(columnId) ?? 0) + 1;
|
|
578
|
-
counters.set(columnId, count);
|
|
579
|
-
const key = count === 1 ? columnId : `${columnId}${INDEX_SEPARATOR}${count}`;
|
|
580
|
-
const variant = filter.variant ?? "text";
|
|
581
|
-
const value = serializeValue(filter.value, variant);
|
|
582
|
-
params.set(key, filter.operator === "isEmpty" || filter.operator === "isNotEmpty" ? "" : value);
|
|
583
|
-
const defaultOperator = getDefaultFilterOperator(variant);
|
|
584
|
-
if (filter.operator !== defaultOperator) params.set(`${key}${OP_SUFFIX}`, filter.operator);
|
|
585
|
-
}
|
|
586
|
-
return params;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
491
|
//#endregion
|
|
590
492
|
//#region src/hooks/use-url-state.ts
|
|
591
493
|
const parseAsInteger = {
|
|
@@ -836,15 +738,120 @@ function useQueryStates(parsers, options = {}) {
|
|
|
836
738
|
}, [setValues])];
|
|
837
739
|
}
|
|
838
740
|
|
|
741
|
+
//#endregion
|
|
742
|
+
//#region src/lib/id.ts
|
|
743
|
+
const prefixes = {};
|
|
744
|
+
function generateId(prefixOrOptions, inputOptions = {}) {
|
|
745
|
+
const finalOptions = typeof prefixOrOptions === "object" ? prefixOrOptions : inputOptions;
|
|
746
|
+
const prefix = typeof prefixOrOptions === "object" ? void 0 : prefixOrOptions;
|
|
747
|
+
const { length = 12, separator = "_" } = finalOptions;
|
|
748
|
+
const id = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", length)();
|
|
749
|
+
return prefix && prefix in prefixes ? `${prefixes[prefix]}${separator}${id}` : id;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
//#endregion
|
|
753
|
+
//#region src/lib/readable-filters.ts
|
|
754
|
+
const OP_SUFFIX = "__op";
|
|
755
|
+
const INDEX_SEPARATOR = "__";
|
|
756
|
+
const RANGE_VARIANTS = new Set(["range", "dateRange"]);
|
|
757
|
+
function getColumnId(column) {
|
|
758
|
+
if ("id" in column && column.id) return String(column.id);
|
|
759
|
+
if ("accessorKey" in column && column.accessorKey) return String(column.accessorKey);
|
|
760
|
+
return null;
|
|
761
|
+
}
|
|
762
|
+
function getColumnVariant(column) {
|
|
763
|
+
if ("columnDef" in column) return column.columnDef.meta?.variant;
|
|
764
|
+
return column.meta?.variant;
|
|
765
|
+
}
|
|
766
|
+
function splitKey(key) {
|
|
767
|
+
const match = key.match(/^(.*?)(?:__(\d+))?$/);
|
|
768
|
+
if (!match) return { base: key };
|
|
769
|
+
const index$1 = match[2] ? Number(match[2]) : void 0;
|
|
770
|
+
return {
|
|
771
|
+
base: match[1] ?? key,
|
|
772
|
+
index: index$1
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
function isFilterKey(key, columnIds) {
|
|
776
|
+
const { base } = splitKey(key.endsWith(OP_SUFFIX) ? key.slice(0, -4) : key);
|
|
777
|
+
return columnIds.has(base);
|
|
778
|
+
}
|
|
779
|
+
function parseValueByVariant(value, variant) {
|
|
780
|
+
if (variant === "multiSelect") return value ? value.split(",").filter(Boolean) : [];
|
|
781
|
+
if (RANGE_VARIANTS.has(variant)) {
|
|
782
|
+
const parts = value.split(",");
|
|
783
|
+
return [parts[0] ?? "", parts[1] ?? ""];
|
|
784
|
+
}
|
|
785
|
+
if (variant === "select") return value.split(",").filter(Boolean)[0] ?? "";
|
|
786
|
+
return value;
|
|
787
|
+
}
|
|
788
|
+
function serializeValue(value, variant) {
|
|
789
|
+
if (Array.isArray(value)) {
|
|
790
|
+
if (RANGE_VARIANTS.has(variant)) return [value[0] ?? "", value[1] ?? ""].join(",");
|
|
791
|
+
return value.join(",");
|
|
792
|
+
}
|
|
793
|
+
return value;
|
|
794
|
+
}
|
|
795
|
+
function parseReadableFilters(params, columns) {
|
|
796
|
+
const columnsById = /* @__PURE__ */ new Map();
|
|
797
|
+
for (const column of columns) {
|
|
798
|
+
const id = getColumnId(column);
|
|
799
|
+
if (id) columnsById.set(id, column);
|
|
800
|
+
}
|
|
801
|
+
const filters = [];
|
|
802
|
+
for (const [key, rawValue] of params.entries()) {
|
|
803
|
+
if (key.endsWith(OP_SUFFIX)) continue;
|
|
804
|
+
const { base } = splitKey(key);
|
|
805
|
+
const column = columnsById.get(base);
|
|
806
|
+
if (!column) continue;
|
|
807
|
+
const variant = getColumnVariant(column) ?? "text";
|
|
808
|
+
const opKey = `${key}${OP_SUFFIX}`;
|
|
809
|
+
const operator = params.get(opKey) ?? getDefaultFilterOperator(variant);
|
|
810
|
+
const parsedValue = operator === "isEmpty" || operator === "isNotEmpty" ? "" : parseValueByVariant(rawValue, variant);
|
|
811
|
+
filters.push({
|
|
812
|
+
id: base,
|
|
813
|
+
value: parsedValue,
|
|
814
|
+
variant,
|
|
815
|
+
operator,
|
|
816
|
+
filterId: key || generateId({ length: 8 })
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
return filters;
|
|
820
|
+
}
|
|
821
|
+
function applyReadableFilters(params, columns, filters) {
|
|
822
|
+
const columnIds = new Set(columns.map((column) => getColumnId(column)).filter(Boolean));
|
|
823
|
+
for (const key of Array.from(params.keys())) if (isFilterKey(key, columnIds)) params.delete(key);
|
|
824
|
+
const counters = /* @__PURE__ */ new Map();
|
|
825
|
+
for (const filter of filters) {
|
|
826
|
+
const columnId = String(filter.id);
|
|
827
|
+
const count = (counters.get(columnId) ?? 0) + 1;
|
|
828
|
+
counters.set(columnId, count);
|
|
829
|
+
const key = count === 1 ? columnId : `${columnId}${INDEX_SEPARATOR}${count}`;
|
|
830
|
+
const variant = filter.variant ?? "text";
|
|
831
|
+
const value = serializeValue(filter.value, variant);
|
|
832
|
+
params.set(key, filter.operator === "isEmpty" || filter.operator === "isNotEmpty" ? "" : value);
|
|
833
|
+
const defaultOperator = getDefaultFilterOperator(variant);
|
|
834
|
+
if (filter.operator !== defaultOperator) params.set(`${key}${OP_SUFFIX}`, filter.operator);
|
|
835
|
+
}
|
|
836
|
+
return params;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
839
|
//#endregion
|
|
840
840
|
//#region src/hooks/use-readable-filters.ts
|
|
841
841
|
const URL_CHANGE_EVENT = "urlchange";
|
|
842
842
|
function toSearchString(params) {
|
|
843
|
-
const queryString = params.toString().replace(/%2C/
|
|
843
|
+
const queryString = params.toString().replace(/%2C/gu, ",");
|
|
844
844
|
return queryString ? `?${queryString}` : "";
|
|
845
845
|
}
|
|
846
|
+
function filterSignature(filters) {
|
|
847
|
+
return JSON.stringify(filters.map(({ id, operator, value, variant }) => JSON.stringify([
|
|
848
|
+
id,
|
|
849
|
+
operator,
|
|
850
|
+
variant === "multiSelect" && Array.isArray(value) ? [...value].sort() : value
|
|
851
|
+
])).sort());
|
|
852
|
+
}
|
|
846
853
|
function useReadableFilters(columns, options = {}) {
|
|
847
|
-
const { history = "replace", scroll = false } = options;
|
|
854
|
+
const { history = "replace", scroll = false, resetPageKey = "page" } = options;
|
|
848
855
|
const columnSnapshot = React.useMemo(() => columns, [columns]);
|
|
849
856
|
const lastWrittenUrlRef = React.useRef(null);
|
|
850
857
|
const filtersRef = React.useRef(null);
|
|
@@ -872,7 +879,10 @@ function useReadableFilters(columns, options = {}) {
|
|
|
872
879
|
}, [columnSnapshot]);
|
|
873
880
|
const writeToUrl = React.useCallback((next) => {
|
|
874
881
|
const params = getUrlParams();
|
|
882
|
+
const previousFilters = parseReadableFilters(params, columnSnapshot);
|
|
875
883
|
applyReadableFilters(params, columnSnapshot, next);
|
|
884
|
+
const nextFilters = parseReadableFilters(params, columnSnapshot);
|
|
885
|
+
if (resetPageKey !== false && resetPageKey.length > 0 && filterSignature(previousFilters) !== filterSignature(nextFilters)) params.delete(resetPageKey);
|
|
876
886
|
lastWrittenUrlRef.current = toSearchString(params);
|
|
877
887
|
setSearchParams(params, {
|
|
878
888
|
history,
|
|
@@ -881,6 +891,7 @@ function useReadableFilters(columns, options = {}) {
|
|
|
881
891
|
}, [
|
|
882
892
|
columnSnapshot,
|
|
883
893
|
history,
|
|
894
|
+
resetPageKey,
|
|
884
895
|
scroll
|
|
885
896
|
]);
|
|
886
897
|
return [filters, React.useCallback((updater) => {
|
|
@@ -1016,7 +1027,10 @@ function DataTableFilterList({ table, debounceMs = DEBOUNCE_MS$2, throttleMs = T
|
|
|
1016
1027
|
return true;
|
|
1017
1028
|
});
|
|
1018
1029
|
}, [table, columnDefs]);
|
|
1019
|
-
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1030
|
+
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1031
|
+
debounceMs,
|
|
1032
|
+
resetPageKey: table.options.meta?.queryKeys?.page ?? "page"
|
|
1033
|
+
});
|
|
1020
1034
|
const debouncedSetFilters = useDebouncedCallback(setFilters, debounceMs);
|
|
1021
1035
|
const [joinOperator, setJoinOperator] = useQueryState(table.options.meta?.queryKeys?.joinOperator ?? "", parseAsStringEnum(["and", "or"]).withDefault("and"));
|
|
1022
1036
|
const onFilterAdd = React.useCallback(() => {
|
|
@@ -1554,7 +1568,10 @@ function DataTableFilterMenu({ table, debounceMs = DEBOUNCE_MS$1, throttleMs = T
|
|
|
1554
1568
|
setSelectedColumn(null);
|
|
1555
1569
|
}
|
|
1556
1570
|
}, [inputValue, selectedColumn]);
|
|
1557
|
-
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1571
|
+
const [filters, setFilters] = useReadableFilters(columns, {
|
|
1572
|
+
debounceMs,
|
|
1573
|
+
resetPageKey: table.options.meta?.queryKeys?.page ?? "page"
|
|
1574
|
+
});
|
|
1558
1575
|
const debouncedSetFilters = useDebouncedCallback(setFilters, debounceMs);
|
|
1559
1576
|
const onFilterAdd = React.useCallback((column, value) => {
|
|
1560
1577
|
if (!value.trim() && column.columnDef.meta?.variant !== "boolean") return;
|
|
@@ -2360,6 +2377,7 @@ function AutoTableSimpleFilters({ table, shallow = false, filters: externalFilte
|
|
|
2360
2377
|
const queryStateOptions = table.options.meta?.queryStateOptions;
|
|
2361
2378
|
const [queryFilters, setQueryFilters] = useReadableFilters(columns, {
|
|
2362
2379
|
...queryStateOptions,
|
|
2380
|
+
resetPageKey: table.options.meta?.queryKeys?.page ?? "page",
|
|
2363
2381
|
shallow
|
|
2364
2382
|
});
|
|
2365
2383
|
const filters = externalFilters ?? queryFilters;
|
|
@@ -3199,6 +3217,10 @@ function renderCell(value, type, options) {
|
|
|
3199
3217
|
className: "text-muted-foreground",
|
|
3200
3218
|
children: "-"
|
|
3201
3219
|
});
|
|
3220
|
+
if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ jsx("span", {
|
|
3221
|
+
className: "text-muted-foreground",
|
|
3222
|
+
children: "-"
|
|
3223
|
+
});
|
|
3202
3224
|
const formatOptionValue = (optionValue) => {
|
|
3203
3225
|
const stringValue = String(optionValue);
|
|
3204
3226
|
return options?.find((option) => option.value === stringValue)?.label ?? stringValue;
|
|
@@ -6087,7 +6109,7 @@ function mergeOptionsByField(left, right) {
|
|
|
6087
6109
|
function shouldResolveOptions(field, config, hiddenColumns) {
|
|
6088
6110
|
if (!config) return false;
|
|
6089
6111
|
if (hiddenColumns.has(field)) return false;
|
|
6090
|
-
if (getTableOptions(config)) return false;
|
|
6112
|
+
if (getTableOptions(config) && !getTableConfig(config)?.dataSource) return false;
|
|
6091
6113
|
return normalizeDataSourceConfig(getTableDataSource(config)) !== void 0;
|
|
6092
6114
|
}
|
|
6093
6115
|
function useRegistryVersion(subscribe) {
|
|
@@ -6437,7 +6459,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
6437
6459
|
const filterDataSourceSearchable = dynamicFilterState?.searchableByField[key];
|
|
6438
6460
|
const currentDynamicOptions = !fieldOptions && filterDataSourceRegistered ? toTableOptions(dynamicFilterState?.optionsByField[key] ?? []) : void 0;
|
|
6439
6461
|
const dynamicFilterLabelOptions = !fieldOptions && filterDataSourceRegistered ? dynamicFilterState?.labelOptionsByField[key] ?? dynamicFilterState?.optionsByField[key] ?? [] : void 0;
|
|
6440
|
-
const dynamicResolveOptions =
|
|
6462
|
+
const dynamicResolveOptions = dynamicResolveState?.optionsByField[key];
|
|
6441
6463
|
const mergedSharedDynamicOptions = mergeFieldOptions(dynamicFilterLabelOptions, tableConfig?.dataSource ? void 0 : dynamicResolveOptions);
|
|
6442
6464
|
const dynamicOptions = !fieldOptions && mergedSharedDynamicOptions ? toTableOptions(mergedSharedDynamicOptions) : void 0;
|
|
6443
6465
|
const tableMeta = config.table !== false && typeof config.table === "object" ? config.table.meta : void 0;
|
|
@@ -6512,7 +6534,7 @@ function buildTableOverrides(fields, legacyOverrides, dynamicFilterState, dynami
|
|
|
6512
6534
|
};
|
|
6513
6535
|
const hasTableLabels = config.table.options !== void 0 || config.table.dataSource !== void 0;
|
|
6514
6536
|
if (display && display !== "auto" || hasTableLabels) {
|
|
6515
|
-
const options =
|
|
6537
|
+
const options = tableConfig?.dataSource ? mergeFieldOptions(dynamicResolveOptions, presentationOptions) : presentationOptions ?? mergedSharedDynamicOptions;
|
|
6516
6538
|
result[key] = {
|
|
6517
6539
|
...result[key],
|
|
6518
6540
|
cell: ({ row }) => renderFieldValue(row.getValue(key), "string", {
|
|
@@ -6625,6 +6647,10 @@ function renderFieldValue(value, type, booleanLocale, options, display = "auto")
|
|
|
6625
6647
|
className: "text-muted-foreground",
|
|
6626
6648
|
children: "-"
|
|
6627
6649
|
});
|
|
6650
|
+
if (Array.isArray(value) && value.length === 0) return /* @__PURE__ */ jsx("span", {
|
|
6651
|
+
className: "text-muted-foreground",
|
|
6652
|
+
children: "-"
|
|
6653
|
+
});
|
|
6628
6654
|
const renderText = (item) => getOptionLabel(item, options);
|
|
6629
6655
|
if (display === "text") return Array.isArray(value) ? value.map(renderText).join(", ") : renderText(value);
|
|
6630
6656
|
if (display === "date" || display === "datetime") return formatDate(value, {}, display);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordrhyme/auto-crud",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.7",
|
|
5
5
|
"description": "Schema-first CRUD components with auto-generated tables and forms",
|
|
6
6
|
"author": "wordrhyme",
|
|
7
7
|
"license": "MIT",
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
"nanoid": "^5.1.6",
|
|
63
63
|
"tailwind-merge": "^3.5.0",
|
|
64
64
|
"vaul": "^1.1.2",
|
|
65
|
-
"@wordrhyme/
|
|
65
|
+
"@wordrhyme/shadcn": "1.3.4",
|
|
66
66
|
"@wordrhyme/shadcn-ui": "1.32.9",
|
|
67
|
-
"@wordrhyme/shadcn": "1.
|
|
67
|
+
"@wordrhyme/formily-shadcn": "1.13.4"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@storybook/react": "^8.6.18",
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
"typescript": "^5.9.3",
|
|
86
86
|
"vitest": "^3.2.4",
|
|
87
87
|
"@internal/eslint-config": "0.3.0",
|
|
88
|
-
"@internal/tsconfig": "0.1.0",
|
|
89
88
|
"@internal/prettier-config": "0.0.1",
|
|
89
|
+
"@internal/tsconfig": "0.1.0",
|
|
90
90
|
"@internal/tsdown-config": "0.1.0",
|
|
91
91
|
"@internal/vitest-config": "0.1.0"
|
|
92
92
|
},
|