@wordrhyme/auto-crud 1.14.2 → 1.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -357,6 +357,8 @@ const resource = useAutoCrudResource({
357
357
 
358
358
  未配置的参数名保留默认值。搜索仍使用共享的 `search` 参数,字段筛选仍使用字段名;`queryKeys` 不隔离这些值。筛选或搜索变化时,仅重置该表格对应的页码。直接使用 `AutoTable` 时传入相同的 `queryKeys`;`table.queryKeys` 可覆盖资源提供的整组配置。
359
359
 
360
+ 全局搜索输入立即显示,停止输入 200ms 后提交查询并回到第一页;清空立即提交,中文输入法组词期间不查询。可以通过 `table.search: { debounceMs: 0 }` 恢复即时查询,或指定其他延时;直接使用 `AutoTable` 时配置 `search.debounceMs`。浏览器导航或其他 URL 状态变化会取消尚未提交的搜索,并按 URL 恢复输入框。
361
+
360
362
  `enableRowSelection` 默认 `true`,设为 `false` 后关闭行选择并隐藏选择列和批量操作栏。`initialColumnVisibility` 只设置首次显示的列,用户仍可通过列设置切换;它不同于 `table.hidden` 对列的排除。
361
363
 
362
364
  ### `useAutoCrudResource()`
package/dist/index.cjs CHANGED
@@ -1166,11 +1166,15 @@ function useCallbackRef(callback) {
1166
1166
  function useDebouncedCallback(callback, delay) {
1167
1167
  const handleCallback = useCallbackRef(callback);
1168
1168
  const debounceTimerRef = react.useRef(0);
1169
- react.useEffect(() => () => window.clearTimeout(debounceTimerRef.current), []);
1170
- return react.useCallback((...args) => {
1169
+ const cancel = react.useCallback(() => {
1170
+ window.clearTimeout(debounceTimerRef.current);
1171
+ }, []);
1172
+ react.useEffect(() => cancel, [cancel, delay]);
1173
+ const setValue = react.useCallback((...args) => {
1171
1174
  window.clearTimeout(debounceTimerRef.current);
1172
1175
  debounceTimerRef.current = window.setTimeout(() => handleCallback(...args), delay);
1173
1176
  }, [handleCallback, delay]);
1177
+ return Object.assign(setValue, { cancel });
1174
1178
  }
1175
1179
 
1176
1180
  //#endregion
@@ -4015,6 +4019,57 @@ function SimpleDateFilter({ title, maxDate, multiple, value, onChange }) {
4015
4019
  });
4016
4020
  }
4017
4021
 
4022
+ //#endregion
4023
+ //#region src/components/auto-crud/auto-table-search.tsx
4024
+ function AutoTableSearch({ placeholder = "搜索", debounceMs = 200, pageKey = "page" }) {
4025
+ const [value, setValue] = (0, react.useState)(() => getUrlParams().get("search") ?? "");
4026
+ const composing = (0, react.useRef)(false);
4027
+ const commit = (0, react.useCallback)((next) => {
4028
+ const params = getUrlParams();
4029
+ if ((params.get("search") ?? "") === next) return;
4030
+ if (next) params.set("search", next);
4031
+ else params.delete("search");
4032
+ params.delete(pageKey);
4033
+ setSearchParams(params);
4034
+ }, [pageKey]);
4035
+ const debouncedCommit = useDebouncedCallback(commit, debounceMs);
4036
+ const { cancel } = debouncedCommit;
4037
+ (0, react.useEffect)(() => {
4038
+ const sync = () => {
4039
+ cancel();
4040
+ setValue(getUrlParams().get("search") ?? "");
4041
+ };
4042
+ window.addEventListener("popstate", sync);
4043
+ window.addEventListener("urlchange", sync);
4044
+ return () => {
4045
+ cancel();
4046
+ window.removeEventListener("popstate", sync);
4047
+ window.removeEventListener("urlchange", sync);
4048
+ };
4049
+ }, [cancel, pageKey]);
4050
+ const change = (next) => {
4051
+ setValue(next);
4052
+ cancel();
4053
+ if (composing.current) return;
4054
+ if (!next || debounceMs <= 0) commit(next);
4055
+ else debouncedCommit(next);
4056
+ };
4057
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Input, {
4058
+ value,
4059
+ onChange: (event) => change(event.target.value),
4060
+ onCompositionStart: () => {
4061
+ composing.current = true;
4062
+ cancel();
4063
+ },
4064
+ onCompositionEnd: (event) => {
4065
+ composing.current = false;
4066
+ change(event.currentTarget.value);
4067
+ },
4068
+ placeholder,
4069
+ className: "h-8 w-48 shrink-0"
4070
+ });
4071
+ }
4072
+
4018
4073
  //#endregion
4019
4074
  //#region src/components/data-table/data-table-column-header.tsx
4020
4075
  function DataTableColumnHeader({ column, label, className,...props }) {
@@ -5194,14 +5249,6 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5194
5249
  const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
5195
5250
  const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
5196
5251
  const showToggle = modes.length > 1;
5197
- const [searchValue, setSearchValue] = useUrlState("search", parseAsString.withDefault(""), {
5198
- shallow: false,
5199
- clearOnDefault: true
5200
- });
5201
- const [, setSearchPage] = useUrlState(queryKeys?.page ?? "page", parseAsInteger.withDefault(1), {
5202
- shallow: false,
5203
- clearOnDefault: true
5204
- });
5205
5252
  const searchConfig = search && typeof search === "object" ? search : {};
5206
5253
  const enableAdvancedFilter = true;
5207
5254
  const { columns, expandColumnId } = (0, react.useMemo)(() => {
@@ -5363,14 +5410,9 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5363
5410
  })
5364
5411
  })
5365
5412
  })] }) : null;
5366
- const searchInput = search ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__wordrhyme_shadcn.Input, {
5367
- value: searchValue,
5368
- onChange: (event) => {
5369
- setSearchValue(event.target.value);
5370
- setSearchPage(1);
5371
- },
5372
- placeholder: searchConfig.placeholder ?? "搜索",
5373
- className: "h-8 w-48 shrink-0"
5413
+ const searchInput = search ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoTableSearch, {
5414
+ ...searchConfig,
5415
+ pageKey: queryKeys?.page
5374
5416
  }) : null;
5375
5417
  const filtersContent = (0, react.useMemo)(() => {
5376
5418
  switch (currentMode) {
package/dist/index.d.cts CHANGED
@@ -1042,6 +1042,8 @@ interface AutoTableProps<T extends z.ZodObject<z.ZodRawShape>> extends Pick<Data
1042
1042
  /** 全局搜索框 */
1043
1043
  search?: boolean | {
1044
1044
  placeholder?: string;
1045
+ /** Search delay in milliseconds. Defaults to 200; use 0 for immediate queries. */
1046
+ debounceMs?: number;
1045
1047
  };
1046
1048
  /** Extra table controls rendered between sorting and column visibility. */
1047
1049
  toolbarExtra?: React.ReactNode;
@@ -1515,9 +1517,7 @@ interface AutoCrudTableProps<TSchema extends z.ZodObject<z.ZodRawShape>> {
1515
1517
  */
1516
1518
  filterModes?: FilterMode | FilterMode[];
1517
1519
  /** 全局搜索框;默认在存在 search: true 字段时显示 */
1518
- search?: boolean | {
1519
- placeholder?: string;
1520
- };
1520
+ search?: AutoTableProps<TSchema>['search'];
1521
1521
  /**
1522
1522
  * 批量更新字段配置
1523
1523
  * - 只需传字段名数组,options 自动从 schema enum 推导
package/dist/index.d.ts CHANGED
@@ -1042,6 +1042,8 @@ interface AutoTableProps<T extends z.ZodObject<z.ZodRawShape>> extends Pick<Data
1042
1042
  /** 全局搜索框 */
1043
1043
  search?: boolean | {
1044
1044
  placeholder?: string;
1045
+ /** Search delay in milliseconds. Defaults to 200; use 0 for immediate queries. */
1046
+ debounceMs?: number;
1045
1047
  };
1046
1048
  /** Extra table controls rendered between sorting and column visibility. */
1047
1049
  toolbarExtra?: React.ReactNode;
@@ -1515,9 +1517,7 @@ interface AutoCrudTableProps<TSchema extends z.ZodObject<z.ZodRawShape>> {
1515
1517
  */
1516
1518
  filterModes?: FilterMode | FilterMode[];
1517
1519
  /** 全局搜索框;默认在存在 search: true 字段时显示 */
1518
- search?: boolean | {
1519
- placeholder?: string;
1520
- };
1520
+ search?: AutoTableProps<TSchema>['search'];
1521
1521
  /**
1522
1522
  * 批量更新字段配置
1523
1523
  * - 只需传字段名数组,options 自动从 schema enum 推导
package/dist/index.js CHANGED
@@ -1150,11 +1150,15 @@ function useCallbackRef(callback) {
1150
1150
  function useDebouncedCallback(callback, delay) {
1151
1151
  const handleCallback = useCallbackRef(callback);
1152
1152
  const debounceTimerRef = React.useRef(0);
1153
- React.useEffect(() => () => window.clearTimeout(debounceTimerRef.current), []);
1154
- return React.useCallback((...args) => {
1153
+ const cancel = React.useCallback(() => {
1154
+ window.clearTimeout(debounceTimerRef.current);
1155
+ }, []);
1156
+ React.useEffect(() => cancel, [cancel, delay]);
1157
+ const setValue = React.useCallback((...args) => {
1155
1158
  window.clearTimeout(debounceTimerRef.current);
1156
1159
  debounceTimerRef.current = window.setTimeout(() => handleCallback(...args), delay);
1157
1160
  }, [handleCallback, delay]);
1161
+ return Object.assign(setValue, { cancel });
1158
1162
  }
1159
1163
 
1160
1164
  //#endregion
@@ -3999,6 +4003,57 @@ function SimpleDateFilter({ title, maxDate, multiple, value, onChange }) {
3999
4003
  });
4000
4004
  }
4001
4005
 
4006
+ //#endregion
4007
+ //#region src/components/auto-crud/auto-table-search.tsx
4008
+ function AutoTableSearch({ placeholder = "搜索", debounceMs = 200, pageKey = "page" }) {
4009
+ const [value, setValue] = useState(() => getUrlParams().get("search") ?? "");
4010
+ const composing = useRef(false);
4011
+ const commit = useCallback((next) => {
4012
+ const params = getUrlParams();
4013
+ if ((params.get("search") ?? "") === next) return;
4014
+ if (next) params.set("search", next);
4015
+ else params.delete("search");
4016
+ params.delete(pageKey);
4017
+ setSearchParams(params);
4018
+ }, [pageKey]);
4019
+ const debouncedCommit = useDebouncedCallback(commit, debounceMs);
4020
+ const { cancel } = debouncedCommit;
4021
+ useEffect(() => {
4022
+ const sync = () => {
4023
+ cancel();
4024
+ setValue(getUrlParams().get("search") ?? "");
4025
+ };
4026
+ window.addEventListener("popstate", sync);
4027
+ window.addEventListener("urlchange", sync);
4028
+ return () => {
4029
+ cancel();
4030
+ window.removeEventListener("popstate", sync);
4031
+ window.removeEventListener("urlchange", sync);
4032
+ };
4033
+ }, [cancel, pageKey]);
4034
+ const change = (next) => {
4035
+ setValue(next);
4036
+ cancel();
4037
+ if (composing.current) return;
4038
+ if (!next || debounceMs <= 0) commit(next);
4039
+ else debouncedCommit(next);
4040
+ };
4041
+ return /* @__PURE__ */ jsx(Input, {
4042
+ value,
4043
+ onChange: (event) => change(event.target.value),
4044
+ onCompositionStart: () => {
4045
+ composing.current = true;
4046
+ cancel();
4047
+ },
4048
+ onCompositionEnd: (event) => {
4049
+ composing.current = false;
4050
+ change(event.currentTarget.value);
4051
+ },
4052
+ placeholder,
4053
+ className: "h-8 w-48 shrink-0"
4054
+ });
4055
+ }
4056
+
4002
4057
  //#endregion
4003
4058
  //#region src/components/data-table/data-table-column-header.tsx
4004
4059
  function DataTableColumnHeader({ column, label, className,...props }) {
@@ -5178,14 +5233,6 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5178
5233
  const modes = filterMode ? Array.isArray(filterMode) ? filterMode : [filterMode] : DEFAULT_MODES;
5179
5234
  const [currentMode, setCurrentMode] = useQueryState("filterMode", parseAsStringEnum(modes).withDefault(modes[0] ?? "simple"));
5180
5235
  const showToggle = modes.length > 1;
5181
- const [searchValue, setSearchValue] = useUrlState("search", parseAsString.withDefault(""), {
5182
- shallow: false,
5183
- clearOnDefault: true
5184
- });
5185
- const [, setSearchPage] = useUrlState(queryKeys?.page ?? "page", parseAsInteger.withDefault(1), {
5186
- shallow: false,
5187
- clearOnDefault: true
5188
- });
5189
5236
  const searchConfig = search && typeof search === "object" ? search : {};
5190
5237
  const enableAdvancedFilter = true;
5191
5238
  const { columns, expandColumnId } = useMemo(() => {
@@ -5347,14 +5394,9 @@ function AutoTable({ schema, data, getRowId, expandedRow, defaultExpanded = fals
5347
5394
  })
5348
5395
  })
5349
5396
  })] }) : null;
5350
- const searchInput = search ? /* @__PURE__ */ jsx(Input, {
5351
- value: searchValue,
5352
- onChange: (event) => {
5353
- setSearchValue(event.target.value);
5354
- setSearchPage(1);
5355
- },
5356
- placeholder: searchConfig.placeholder ?? "搜索",
5357
- className: "h-8 w-48 shrink-0"
5397
+ const searchInput = search ? /* @__PURE__ */ jsx(AutoTableSearch, {
5398
+ ...searchConfig,
5399
+ pageKey: queryKeys?.page
5358
5400
  }) : null;
5359
5401
  const filtersContent = useMemo(() => {
5360
5402
  switch (currentMode) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wordrhyme/auto-crud",
3
3
  "type": "module",
4
- "version": "1.14.2",
4
+ "version": "1.14.3",
5
5
  "description": "Schema-first CRUD components with auto-generated tables and forms",
6
6
  "author": "wordrhyme",
7
7
  "license": "MIT",
@@ -95,10 +95,10 @@
95
95
  "typescript": "^5.9.3",
96
96
  "vitest": "^3.2.4",
97
97
  "@internal/eslint-config": "0.3.0",
98
+ "@internal/prettier-config": "0.0.1",
98
99
  "@internal/tsconfig": "0.1.0",
99
- "@internal/tsdown-config": "0.1.0",
100
100
  "@internal/vitest-config": "0.1.0",
101
- "@internal/prettier-config": "0.0.1"
101
+ "@internal/tsdown-config": "0.1.0"
102
102
  },
103
103
  "prettier": "@internal/prettier-config",
104
104
  "scripts": {