@_tc/template-core 0.2.0-bate.7 → 0.2.0-bate.9

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.
Files changed (33) hide show
  1. package/AGENT_README.md +5 -3
  2. package/README.md +8 -1
  3. package/cjs/packages/common/index.js +1 -1
  4. package/cjs/packages/common/rafTimer.js +1 -0
  5. package/esm/packages/common/index.js +3 -2
  6. package/esm/packages/common/rafTimer.js +47 -0
  7. package/fe/frontend/src/common/rafTimer.d.ts +1 -7
  8. package/fe/frontend/src/common/rafTimer.js +1 -143
  9. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaSearch/index.js +14 -12
  10. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/index.js +5 -11
  11. package/fe/frontend/src/defaultPages/SchemaPage/index.css +0 -4
  12. package/fe/frontend/src/defaultPages/SlotPage/index.js +6 -3
  13. package/fe/frontend/src/index.d.ts +2 -2
  14. package/fe/frontend/src/index.js +1 -1
  15. package/fe/packages/common/index.d.ts +1 -0
  16. package/fe/packages/common/rafTimer.d.ts +7 -0
  17. package/fe/packages/common/rafTimer.js +168 -0
  18. package/fe/packages/react/hooks/useRefState.d.ts +4 -12
  19. package/fe/packages/react/hooks/useRefState.js +18 -8
  20. package/fe/packages/react/ui/components/DataTable/dataTableWidth.d.ts +12 -0
  21. package/fe/packages/react/ui/components/DataTable/dataTableWidth.js +33 -0
  22. package/fe/packages/react/ui/components/DataTable/dataTableWidth.test.js +39 -0
  23. package/fe/packages/react/ui/components/DataTable/index.d.ts +1 -1
  24. package/fe/packages/react/ui/components/DataTable/index.js +12 -32
  25. package/fe/packages/react/ui/components/types/baseType.d.ts +2 -2
  26. package/model/packages/common/index.d.ts +1 -0
  27. package/model/packages/common/rafTimer.d.ts +7 -0
  28. package/model/packages/react/ui/components/DataTable/dataTableWidth.d.ts +12 -0
  29. package/model/packages/react/ui/components/DataTable/index.d.ts +1 -1
  30. package/model/packages/react/ui/components/types/baseType.d.ts +2 -2
  31. package/package.json +1 -1
  32. package/types/packages/common/index.d.ts +1 -0
  33. package/types/packages/common/rafTimer.d.ts +44 -0
package/AGENT_README.md CHANGED
@@ -19,9 +19,11 @@ TemplateCore 是一个 TypeScript + Koa + React 的后台框架包。它提供
19
19
  | --- | --- |
20
20
  | `@_tc/template-core` | `serverStart`、`baseFn`、Koa/Controller/Service 类型。 |
21
21
  | `@_tc/template-core/bundler` | `buildFE()`、`buildBE()`。 |
22
- | `@_tc/template-core/fe` | 前端初始化、动态组件渲染辅助、请求方法、Dashboard/Schema 类型、token 工具、共享状态、业务前端组件。 |
22
+ | `@_tc/template-core/fe` | 前端初始化、动态组件渲染辅助、请求方法、Dashboard/Schema 类型、token 工具、RAF 计时器、共享状态、业务前端组件。 |
23
+ | `@_tc/template-core/fe/main` | 前端初始化入口。 |
23
24
  | `@_tc/template-core/fe/common/request` | 请求实例、请求方法和请求类型的显式子路径。 |
24
25
  | `@_tc/template-core/fe/rc` | React UI 组件和 SchemaForm 组件。 |
26
+ | `@_tc/template-core/fe/rc/hooks` | React hooks 汇总入口。 |
25
27
  | `@_tc/template-core/fe/tailwind_ui.css` | 内置前端/UI 全局样式。 |
26
28
  | `@_tc/template-core/model` | `ModelDataType` 等 model 配置类型。 |
27
29
 
@@ -412,7 +414,7 @@ import { Button, DataTable, Form, Input, Modal, Select } from '@_tc/template-cor
412
414
  常用前端能力:
413
415
 
414
416
  - 请求方法:`api`、`request`、`get`、`post`、`put`、`patch`、`del`。
415
- - RAF 计时器:`rafSetTimeout`、`rafSetInterval`、`rafClearTimeout`、`rafClearInterval`、`clearRafTimer`。
417
+ - RAF 风格计时器:`rafSetTimeout`、`rafSetInterval`、`rafClearTimeout`、`rafClearInterval`、`clearRafTimer`,缺少 RAF 时自动降级到 `setTimeout`。
416
418
  - 请求类型:`BaseResponse`、`PageParams`、`PageResponse`、`RequestConfig`、`ResponseConfig`、`AxiosError`。
417
419
  - 请求 header:自动添加 `s_t`、`s_sign`、`projk`;存在短 token 时添加 `Authorization: Bearer ${token}`。
418
420
  - 默认会先设置 `Content-Type: application/json`;如果是上传文件、`FormData` 或其他内容类型,请在请求配置里显式覆盖。
@@ -424,7 +426,7 @@ import { Button, DataTable, Form, Input, Modal, Select } from '@_tc/template-cor
424
426
  - 多语言:`addLanguageResources()` / `addResources()` 追加某语种文案,`addLanguage()` 新增语种,`setLanguage()` 切换语言,配置文案可写 `$i18n::...`。
425
427
  - 主题:`ThemeSwitch` 会同步根节点 `dark` class 和 `localStorage`。
426
428
  - `Input type="password"` 会自动显示密码显隐按钮;`allowClear` 不作用于密码输入。
427
- - RAF 计时器只在浏览器环境可用,不适合 Node 侧调用。
429
+ - RAF 风格计时器由 `@tc/common/rafTimer` 提供,浏览器优先使用 RAF,Node/SSR 自动降级到 `setTimeout`。
428
430
 
429
431
  不要直接依赖 `frontend/src/...`、`packages/react/ui/...` 这类包内部路径。
430
432
 
package/README.md CHANGED
@@ -176,13 +176,15 @@ http://localhost:9000/dash?projk=demo
176
176
 
177
177
  ## 常用公开入口
178
178
 
179
- 完整 exports 以发布包内 `package.json` 为准,除下表外还包含 `./fe/main`、`./fe/*`、`./fe/rc/*`、`./fe/rc/hooks` 等子路径。
179
+ 完整 exports 以发布包内 `package.json` 为准,除下表外还包含 `./fe/main`、`./fe/common/request`、`./fe/*`、`./fe/rc/*`、`./fe/rc/hooks` 等子路径。
180
180
 
181
181
  | 入口 | 用途 |
182
182
  | --- | --- |
183
183
  | `@_tc/template-core` | 服务启动、基础 Controller/Service、Koa 类型 |
184
184
  | `@_tc/template-core/bundler` | 构建入口,提供前端资源构建 `buildFE` 和消费方 Node/backend 构建 `buildBE` |
185
185
  | `@_tc/template-core/fe` | 前端初始化、动态组件渲染辅助、Dash 路由扩展、请求方法、SchemaPage 事件、token 工具、共享状态和内置前端组件 |
186
+ | `@_tc/template-core/fe/main` | 前端初始化入口 |
187
+ | `@_tc/template-core/fe/common/request` | 请求实例、请求方法和请求类型的显式子路径 |
186
188
  | `@_tc/template-core/fe/rc` | UI/SchemaForm 组件和类型 |
187
189
  | `@_tc/template-core/fe/rc/hooks` | React hooks 汇总入口 |
188
190
  | `@_tc/template-core/fe/tailwind_ui.css` | 前端全局样式入口,源码对应 `frontend/src/main.css` |
@@ -376,6 +378,7 @@ import type {
376
378
  | SchemaForm 类型 | `FormFieldSchema`、`SchemaFormComponentsMap`、`SchemaFormNamespace`、`SelectProps` |
377
379
  | 请求方法 | `api`、`request`、`get`、`post`、`put`、`patch`、`del` |
378
380
  | 请求类型 | `BaseResponse`、`PageParams`、`PageResponse`、`RequestConfig`、`ResponseConfig`、`AxiosError` |
381
+ | RAF 风格计时器 | `rafSetTimeout`、`rafSetInterval`、`rafClearTimeout`、`rafClearInterval`、`clearRafTimer`、`RafTimerId`、`RafTimerCallback` |
379
382
  | Token 工具 | `getAuthToken`、`setAuthToken`、`clearAuthToken`、`localKeyMap` |
380
383
  | 多语言工具 | `getText`、`t`、`addLanguage`、`addLanguageResources`、`addResources`、`setLanguage`、`setFallbackLanguage`、`setResources`、`getCurrentLanguage`、`getFallbackLanguage`、`getSupportedLanguages` |
381
384
  | 请求冻结 | `apiFreezerStore`、`useApiFreezer`、`FreezeState`、`ApiFreezerRequestMatcher` |
@@ -564,8 +567,12 @@ initThemeMode()
564
567
  applyThemeMode('dark', true)
565
568
  ```
566
569
 
570
+ RAF 风格计时器由 `@tc/common/rafTimer` 提供,浏览器优先使用 `requestAnimationFrame`,缺少 RAF 时自动降级到 `setTimeout`。
571
+
567
572
  `@_tc/template-core/fe/rc` 和 `@_tc/template-core/fe/rc/hooks` 也会随发布包提供对应 UI 与 hooks 入口;hooks 汇总入口包含 `useBreadcrumb`、`useExecuteOnce`、`useInit`、`useLanguage`、`usePagination`、`useRefState`、`useWatch`。
568
573
 
574
+ `useRefState` 支持可选的 `delayTiming` 参数,传入大于 0 的值时会延迟 state 提交,并复用 `@tc/common/rafTimer` 的浏览器优先、Node/SSR 自动降级计时器实现。
575
+
569
576
  ### 前端请求封装详解
570
577
 
571
578
  框架内置的请求封装基于 `@tc/common/http`,底层使用原生 `fetch` API,实现了类似 Axios 的接口和拦截器机制,提供了签名、鉴权、错误处理等能力。
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./guards/index.js`),t=require(`./array/index.js`),n=require(`./cache/LRUCache.js`),r=require(`./http/index.js`),i=require(`./i18n/default.js`),a=require(`./i18n/en-US.js`),o=require(`./i18n/locales.js`),s=require(`./i18n/index.js`),c=require(`./log/index.js`),l=require(`./number/index.js`),u=require(`./object/filterEmpty.js`),d=require(`./object/index.js`),f=require(`./string/index.js`);exports.ANSI_RESET=c.ANSI_RESET,exports.FetchAxios=r.FetchAxios,exports.LRUCache=n.LRUCache,exports.ansiColors=c.ansiColors,exports.axios=r.axios,exports.capitalize=f.capitalize,exports.chunk=t.chunk,exports.clamp=l.clamp,exports.colorLog=c.colorLog,exports.colorize=c.colorize,exports.compact=t.compact,exports.createInstance=r.createInstance,exports.defaultEnglishResources=a.defaultEnglishResources,exports.defaultLanguage=o.defaultLanguage,exports.defaultLanguageResources=i.defaultLanguageResources,exports.filterEmpty=u.filterEmpty,exports.filtereEmpty=u.filtereEmpty,exports.getI18nPathValue=s.getI18nPathValue,exports.getLanguage=s.getLanguage,exports.groupBy=t.groupBy,exports.i18n=s.i18n,exports.i18nStore=s.i18nStore,exports.interpolateI18nMessage=s.interpolateI18nMessage,exports.isBlank=f.isBlank,exports.isBoolean=e.isBoolean,exports.isFunction=e.isFunction,exports.isNil=e.isNil,exports.isNonNullable=e.isNonNullable,exports.isNumber=e.isNumber,exports.isPlainI18nDictionary=s.isPlainI18nDictionary,exports.isPlainObject=e.isPlainObject,exports.isString=e.isString,exports.joinColorized=c.joinColorized,exports.joinStr=f.joinStr,exports.kebabCase=f.kebabCase,exports.languageLocalKey=o.languageLocalKey,exports.logColor=c.logColor,exports.logColorized=c.logColorized,exports.logGreen=c.logGreen,exports.logJoinColorized=c.logJoinColorized,exports.logPink=c.logPink,exports.logRed=c.logRed,exports.logWhite=c.logWhite,exports.logYellow=c.logYellow,exports.mapValues=d.mapValues,exports.mergeI18nDictionary=s.mergeI18nDictionary,exports.mergeI18nResources=s.mergeI18nResources,exports.omit=d.omit,exports.pick=d.pick,exports.t=s.t,exports.toArray=t.toArray,exports.toFiniteNumber=l.toFiniteNumber,exports.translate=s.translate,exports.translations=o.translations,exports.uniqueBy=t.uniqueBy;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./guards/index.js`),t=require(`./array/index.js`),n=require(`./cache/LRUCache.js`),r=require(`./http/index.js`),i=require(`./i18n/default.js`),a=require(`./i18n/en-US.js`),o=require(`./i18n/locales.js`),s=require(`./i18n/index.js`),c=require(`./log/index.js`),l=require(`./number/index.js`),u=require(`./object/filterEmpty.js`),d=require(`./object/index.js`),f=require(`./rafTimer.js`),p=require(`./string/index.js`);exports.ANSI_RESET=c.ANSI_RESET,exports.FetchAxios=r.FetchAxios,exports.LRUCache=n.LRUCache,exports.ansiColors=c.ansiColors,exports.axios=r.axios,exports.capitalize=p.capitalize,exports.chunk=t.chunk,exports.clamp=l.clamp,exports.clearRafTimer=f.clearRafTimer,exports.colorLog=c.colorLog,exports.colorize=c.colorize,exports.compact=t.compact,exports.createInstance=r.createInstance,exports.defaultEnglishResources=a.defaultEnglishResources,exports.defaultLanguage=o.defaultLanguage,exports.defaultLanguageResources=i.defaultLanguageResources,exports.filterEmpty=u.filterEmpty,exports.filtereEmpty=u.filtereEmpty,exports.getI18nPathValue=s.getI18nPathValue,exports.getLanguage=s.getLanguage,exports.groupBy=t.groupBy,exports.i18n=s.i18n,exports.i18nStore=s.i18nStore,exports.interpolateI18nMessage=s.interpolateI18nMessage,exports.isBlank=p.isBlank,exports.isBoolean=e.isBoolean,exports.isFunction=e.isFunction,exports.isNil=e.isNil,exports.isNonNullable=e.isNonNullable,exports.isNumber=e.isNumber,exports.isPlainI18nDictionary=s.isPlainI18nDictionary,exports.isPlainObject=e.isPlainObject,exports.isString=e.isString,exports.joinColorized=c.joinColorized,exports.joinStr=p.joinStr,exports.kebabCase=p.kebabCase,exports.languageLocalKey=o.languageLocalKey,exports.logColor=c.logColor,exports.logColorized=c.logColorized,exports.logGreen=c.logGreen,exports.logJoinColorized=c.logJoinColorized,exports.logPink=c.logPink,exports.logRed=c.logRed,exports.logWhite=c.logWhite,exports.logYellow=c.logYellow,exports.mapValues=d.mapValues,exports.mergeI18nDictionary=s.mergeI18nDictionary,exports.mergeI18nResources=s.mergeI18nResources,exports.omit=d.omit,exports.pick=d.pick,exports.rafClearInterval=f.rafClearInterval,exports.rafClearTimeout=f.rafClearTimeout,exports.rafSetInterval=f.rafSetInterval,exports.rafSetTimeout=f.rafSetTimeout,exports.t=s.t,exports.toArray=t.toArray,exports.toFiniteNumber=l.toFiniteNumber,exports.translate=s.translate,exports.translations=o.translations,exports.uniqueBy=t.uniqueBy;
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=16,t=globalThis,n=new Map,r=0,i=e=>Math.max(0,e??0),a=()=>t.performance?.now?.()??Date.now(),o=()=>{let n=t.requestAnimationFrame,r=t.cancelAnimationFrame;if(typeof n==`function`&&typeof r==`function`)return{scheduleFrame:e=>n.call(t,e),cancelFrame:e=>r.call(t,e)};let i=t.setTimeout,o=t.clearTimeout;if(typeof i!=`function`||typeof o!=`function`)throw Error(`raf timer requires requestAnimationFrame or setTimeout/clearTimeout.`);return{scheduleFrame:n=>i.call(t,()=>n(a()),e),cancelFrame:e=>o.call(t,e)}},s,c=()=>(s??=o(),s),l=()=>(r+=1,r),u=e=>{let t=n.get(e);t&&(c().cancelFrame(t.frameId),n.delete(e))},d=(e,t)=>{let r=n.get(e);if(r){if(r.type===`timeout`?t-r.startTime>=r.delay:t-r.lastRunTime>=r.delay){if(r.type===`timeout`){n.delete(e),r.callback();return}r.lastRunTime=t,r.callback()}n.has(e)&&(r.frameId=c().scheduleFrame(t=>d(e,t)))}},f=(e,t,r,o)=>{let s=l(),u=a(),f={type:e,delay:i(r),callback:()=>t(...o??[]),startTime:u,lastRunTime:u,frameId:0};return n.set(s,f),f.frameId=c().scheduleFrame(e=>d(s,e)),s},p=(e,t,...n)=>f(`timeout`,e,t,n),m=e=>{u(e)},h=(e,t,...n)=>f(`interval`,e,t,n),g=e=>{u(e)},_=e=>{u(e)};exports.clearRafTimer=_,exports.rafClearInterval=g,exports.rafClearTimeout=m,exports.rafSetInterval=h,exports.rafSetTimeout=p;
@@ -10,5 +10,6 @@ import { ANSI_RESET as j, ansiColors as M, colorLog as N, colorize as P, joinCol
10
10
  import { clamp as W, toFiniteNumber as G } from "./number/index.js";
11
11
  import { filterEmpty as K, filtereEmpty as q } from "./object/filterEmpty.js";
12
12
  import { mapValues as J, omit as Y, pick as X } from "./object/index.js";
13
- import { capitalize as Z, isBlank as Q, joinStr as $, kebabCase as ee } from "./string/index.js";
14
- export { j as ANSI_RESET, p as FetchAxios, f as LRUCache, M as ansiColors, m as axios, Z as capitalize, s as chunk, W as clamp, N as colorLog, P as colorize, c as compact, h as createInstance, _ as defaultEnglishResources, v as defaultLanguage, g as defaultLanguageResources, K as filterEmpty, q as filtereEmpty, x as getI18nPathValue, S as getLanguage, l as groupBy, C as i18n, w as i18nStore, T as interpolateI18nMessage, Q as isBlank, e as isBoolean, t as isFunction, n as isNil, r as isNonNullable, i as isNumber, E as isPlainI18nDictionary, a as isPlainObject, o as isString, F as joinColorized, $ as joinStr, ee as kebabCase, y as languageLocalKey, I as logColor, L as logColorized, R as logGreen, z as logJoinColorized, B as logPink, V as logRed, H as logWhite, U as logYellow, J as mapValues, D as mergeI18nDictionary, O as mergeI18nResources, Y as omit, X as pick, k as t, u as toArray, G as toFiniteNumber, A as translate, b as translations, d as uniqueBy };
13
+ import { clearRafTimer as Z, rafClearInterval as Q, rafClearTimeout as $, rafSetInterval as ee, rafSetTimeout as te } from "./rafTimer.js";
14
+ import { capitalize as ne, isBlank as re, joinStr as ie, kebabCase as ae } from "./string/index.js";
15
+ export { j as ANSI_RESET, p as FetchAxios, f as LRUCache, M as ansiColors, m as axios, ne as capitalize, s as chunk, W as clamp, Z as clearRafTimer, N as colorLog, P as colorize, c as compact, h as createInstance, _ as defaultEnglishResources, v as defaultLanguage, g as defaultLanguageResources, K as filterEmpty, q as filtereEmpty, x as getI18nPathValue, S as getLanguage, l as groupBy, C as i18n, w as i18nStore, T as interpolateI18nMessage, re as isBlank, e as isBoolean, t as isFunction, n as isNil, r as isNonNullable, i as isNumber, E as isPlainI18nDictionary, a as isPlainObject, o as isString, F as joinColorized, ie as joinStr, ae as kebabCase, y as languageLocalKey, I as logColor, L as logColorized, R as logGreen, z as logJoinColorized, B as logPink, V as logRed, H as logWhite, U as logYellow, J as mapValues, D as mergeI18nDictionary, O as mergeI18nResources, Y as omit, X as pick, Q as rafClearInterval, $ as rafClearTimeout, ee as rafSetInterval, te as rafSetTimeout, k as t, u as toArray, G as toFiniteNumber, A as translate, b as translations, d as uniqueBy };
@@ -0,0 +1,47 @@
1
+ //#region packages/common/rafTimer.ts
2
+ var e = 16, t = globalThis, n = /* @__PURE__ */ new Map(), r = 0, i = (e) => Math.max(0, e ?? 0), a = () => t.performance?.now?.() ?? Date.now(), o = () => {
3
+ let n = t.requestAnimationFrame, r = t.cancelAnimationFrame;
4
+ if (typeof n == "function" && typeof r == "function") return {
5
+ scheduleFrame: (e) => n.call(t, e),
6
+ cancelFrame: (e) => r.call(t, e)
7
+ };
8
+ let i = t.setTimeout, o = t.clearTimeout;
9
+ if (typeof i != "function" || typeof o != "function") throw Error("raf timer requires requestAnimationFrame or setTimeout/clearTimeout.");
10
+ return {
11
+ scheduleFrame: (n) => i.call(t, () => n(a()), e),
12
+ cancelFrame: (e) => o.call(t, e)
13
+ };
14
+ }, s, c = () => (s ??= o(), s), l = () => (r += 1, r), u = (e) => {
15
+ let t = n.get(e);
16
+ t && (c().cancelFrame(t.frameId), n.delete(e));
17
+ }, d = (e, t) => {
18
+ let r = n.get(e);
19
+ if (r) {
20
+ if (r.type === "timeout" ? t - r.startTime >= r.delay : t - r.lastRunTime >= r.delay) {
21
+ if (r.type === "timeout") {
22
+ n.delete(e), r.callback();
23
+ return;
24
+ }
25
+ r.lastRunTime = t, r.callback();
26
+ }
27
+ n.has(e) && (r.frameId = c().scheduleFrame((t) => d(e, t)));
28
+ }
29
+ }, f = (e, t, r, o) => {
30
+ let s = l(), u = a(), f = {
31
+ type: e,
32
+ delay: i(r),
33
+ callback: () => t(...o ?? []),
34
+ startTime: u,
35
+ lastRunTime: u,
36
+ frameId: 0
37
+ };
38
+ return n.set(s, f), f.frameId = c().scheduleFrame((e) => d(s, e)), s;
39
+ }, p = (e, t, ...n) => f("timeout", e, t, n), m = (e) => {
40
+ u(e);
41
+ }, h = (e, t, ...n) => f("interval", e, t, n), g = (e) => {
42
+ u(e);
43
+ }, _ = (e) => {
44
+ u(e);
45
+ };
46
+ //#endregion
47
+ export { _ as clearRafTimer, g as rafClearInterval, m as rafClearTimeout, h as rafSetInterval, p as rafSetTimeout };
@@ -1,7 +1 @@
1
- export type RafTimerId = number;
2
- export type RafTimerCallback<Args extends unknown[] = []> = (...args: Args) => void;
3
- export declare const rafSetTimeout: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
4
- export declare const rafClearTimeout: (timerId: RafTimerId) => void;
5
- export declare const rafSetInterval: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
6
- export declare const rafClearInterval: (timerId: RafTimerId) => void;
7
- export declare const clearRafTimer: (timerId: RafTimerId) => void;
1
+ export * from "../../../packages/common/rafTimer";
@@ -1,144 +1,2 @@
1
- //#region frontend/src/common/rafTimer.ts
2
- var rafTimers = /* @__PURE__ */ new Map();
3
- var rafTimerSeed = 0;
4
- /**
5
- * 统一修正延迟时间,避免传入 undefined 或负数。
6
- *
7
- * @param delay 原始延迟时间。
8
- * @returns 不小于 0 的延迟时间。
9
- */
10
- var normalizeDelay = (delay) => Math.max(0, delay ?? 0);
11
- /**
12
- * 确认当前环境支持 requestAnimationFrame。
13
- */
14
- var assertRafAvailable = () => {
15
- if (typeof requestAnimationFrame === "undefined" || typeof cancelAnimationFrame === "undefined") throw new Error("raf timer requires requestAnimationFrame and can only run in a browser environment.");
16
- };
17
- /**
18
- * 创建唯一的计时器 id。
19
- *
20
- * @returns 新的计时器 id。
21
- */
22
- var createTimerId = () => {
23
- rafTimerSeed += 1;
24
- return rafTimerSeed;
25
- };
26
- /**
27
- * 删除并取消指定计时器。
28
- *
29
- * 步骤:
30
- * 1. 根据 id 查找计时器状态。
31
- * 2. 如果计时器不存在,直接结束。
32
- * 3. 取消下一帧回调,并从缓存中移除计时器。
33
- *
34
- * @param timerId 要取消的计时器 id。
35
- */
36
- var deleteTimer = (timerId) => {
37
- const timer = rafTimers.get(timerId);
38
- if (!timer) return;
39
- cancelAnimationFrame(timer.frameId);
40
- rafTimers.delete(timerId);
41
- };
42
- /**
43
- * 每一帧执行一次的调度函数。
44
- *
45
- * 步骤:
46
- * 1. 读取当前计时器状态。
47
- * 2. 对比当前时间和起始时间/上次执行时间,判断是否到达延迟。
48
- * 3. timeout 到点后执行一次并删除计时器。
49
- * 4. interval 到点后执行回调,并更新上次执行时间。
50
- * 5. 如果计时器仍然存在,继续注册下一帧。
51
- *
52
- * @param timerId 当前计时器 id。
53
- * @param currentTime requestAnimationFrame 传入的当前时间戳。
54
- */
55
- var tick = (timerId, currentTime) => {
56
- const timer = rafTimers.get(timerId);
57
- if (!timer) return;
58
- if (timer.type === "timeout" ? currentTime - timer.startTime >= timer.delay : currentTime - timer.lastRunTime >= timer.delay) {
59
- if (timer.type === "timeout") {
60
- rafTimers.delete(timerId);
61
- timer.callback();
62
- return;
63
- }
64
- timer.lastRunTime = currentTime;
65
- timer.callback();
66
- }
67
- if (rafTimers.has(timerId)) timer.frameId = requestAnimationFrame((nextTime) => tick(timerId, nextTime));
68
- };
69
- /**
70
- * 创建 requestAnimationFrame 计时器。
71
- *
72
- * 步骤:
73
- * 1. 检查当前运行环境是否支持 requestAnimationFrame。
74
- * 2. 创建计时器 id,并记录起始时间。
75
- * 3. 保存计时器类型、延迟、回调和帧 id 等状态。
76
- * 4. 注册第一帧调度。
77
- * 5. 将计时器状态写入缓存,并返回计时器 id。
78
- *
79
- * @param type 计时器类型。
80
- * @param callback 到点后执行的回调函数。
81
- * @param delay 延迟或间隔时间,单位毫秒。
82
- * @param args 传给回调函数的参数。
83
- * @returns 计时器 id。
84
- */
85
- var createRafTimer = (type, callback, delay, args) => {
86
- assertRafAvailable();
87
- const timerId = createTimerId();
88
- const startTime = performance.now();
89
- const timer = {
90
- type,
91
- delay: normalizeDelay(delay),
92
- callback: () => callback(...args ?? []),
93
- startTime,
94
- lastRunTime: startTime,
95
- frameId: 0
96
- };
97
- timer.frameId = requestAnimationFrame((currentTime) => tick(timerId, currentTime));
98
- rafTimers.set(timerId, timer);
99
- return timerId;
100
- };
101
- /**
102
- * 使用 requestAnimationFrame 驱动,在指定延迟后执行一次回调。
103
- *
104
- * @param callback 延迟结束后执行的回调函数。
105
- * @param delay 延迟时间,单位毫秒,默认 0。
106
- * @param args 传给回调函数的参数。
107
- * @returns 计时器 id,可通过 rafClearTimeout 或 clearRafTimer 取消。
108
- */
109
- var rafSetTimeout = (callback, delay, ...args) => createRafTimer("timeout", callback, delay, args);
110
- /**
111
- * 取消 rafSetTimeout 创建的计时器。
112
- *
113
- * @param timerId rafSetTimeout 返回的计时器 id。
114
- */
115
- var rafClearTimeout = (timerId) => {
116
- deleteTimer(timerId);
117
- };
118
- /**
119
- * 使用 requestAnimationFrame 驱动,按指定间隔重复执行回调。
120
- *
121
- * @param callback 每次间隔结束后执行的回调函数。
122
- * @param delay 间隔时间,单位毫秒,默认 0。
123
- * @param args 传给回调函数的参数。
124
- * @returns 计时器 id,可通过 rafClearInterval 或 clearRafTimer 取消。
125
- */
126
- var rafSetInterval = (callback, delay, ...args) => createRafTimer("interval", callback, delay, args);
127
- /**
128
- * 取消 rafSetInterval 创建的计时器。
129
- *
130
- * @param timerId rafSetInterval 返回的计时器 id。
131
- */
132
- var rafClearInterval = (timerId) => {
133
- deleteTimer(timerId);
134
- };
135
- /**
136
- * 取消本模块创建的任意 requestAnimationFrame 计时器。
137
- *
138
- * @param timerId rafSetTimeout 或 rafSetInterval 返回的计时器 id。
139
- */
140
- var clearRafTimer = (timerId) => {
141
- deleteTimer(timerId);
142
- };
143
- //#endregion
1
+ import { clearRafTimer, rafClearInterval, rafClearTimeout, rafSetInterval, rafSetTimeout } from "../../../packages/common/rafTimer.js";
144
2
  export { clearRafTimer, rafClearInterval, rafClearTimeout, rafSetInterval, rafSetTimeout };
@@ -42,19 +42,21 @@ var SchemaSearch = memo(() => {
42
42
  setSchemas(schemas);
43
43
  setSchemaDefaultValue(defaultValue);
44
44
  });
45
+ const tsProps = {
46
+ schemas,
47
+ defaultValue,
48
+ onSearch(values) {
49
+ schemaEventBus.getState().emitSearch(filterEmpty(values));
50
+ },
51
+ onReset() {
52
+ schemaEventBus.getState().emitSearch(void 0);
53
+ },
54
+ renderActionBtnArea: () => {}
55
+ };
45
56
  return /* @__PURE__ */ jsx("div", {
46
- className: "schema-search",
47
- children: /* @__PURE__ */ jsx(TableSearch, {
48
- schemas,
49
- defaultValue,
50
- onSearch(values) {
51
- schemaEventBus.getState().emitSearch(filterEmpty(values));
52
- },
53
- onReset() {
54
- schemaEventBus.getState().emitSearch(void 0);
55
- },
56
- renderActionBtnArea: () => {}
57
- })
57
+ className: "schema-search pb-2",
58
+ style: { display: schemas.length ? "block" : "none" },
59
+ children: /* @__PURE__ */ jsx(TableSearch, { ...tsProps })
58
60
  });
59
61
  });
60
62
  SchemaSearch.displayName = "SchemaSearch";
@@ -15,7 +15,7 @@ import { merge } from "../../utils/permissions.js";
15
15
  import { schemaTableRenderComponentMap } from "./data.js";
16
16
  import useRefState from "../../../../../../packages/react/hooks/useRefState.js";
17
17
  import useWatch from "../../../../../../packages/react/hooks/useWatch.js";
18
- import { Suspense, memo, useCallback, useImperativeHandle, useMemo, useState, useTransition } from "react";
18
+ import { Suspense, memo, useCallback, useImperativeHandle, useMemo, useState } from "react";
19
19
  import { jsx, jsxs } from "react/jsx-runtime";
20
20
  import { useShallow } from "zustand/react/shallow";
21
21
  import { produce } from "immer";
@@ -109,19 +109,16 @@ var SchemaTable = memo(({ ref }) => {
109
109
  })));
110
110
  const [data, uData] = useState([]);
111
111
  const [columns, uColumns] = useState([]);
112
- const [loading, uLoading, loadingRef] = useRefState(false);
112
+ const [loading, uLoading, loadingRef] = useRefState(false, 25);
113
113
  const [pagination, setPagination, paginationRef] = useRefState({
114
114
  current: 1,
115
115
  pageSize: 10,
116
116
  total: 0
117
117
  });
118
- const [lazyLoading, startTransition] = useTransition();
119
118
  const [handleBtn, setHandleBtn] = useState([]);
120
119
  const init = useCallback(async (query) => {
121
120
  if (loadingRef.current.data) return;
122
- startTransition(async () => {
123
- uLoading(true);
124
- });
121
+ uLoading(true);
125
122
  try {
126
123
  const res = await handlingRequestErrors(get(params.api ? `${params.api}/list` : "", {
127
124
  ...query,
@@ -134,9 +131,7 @@ var SchemaTable = memo(({ ref }) => {
134
131
  }));
135
132
  }
136
133
  } finally {
137
- startTransition(async () => {
138
- uLoading(false);
139
- });
134
+ uLoading(false);
140
135
  }
141
136
  }, [
142
137
  loadingRef,
@@ -178,7 +173,7 @@ var SchemaTable = memo(({ ref }) => {
178
173
  return {
179
174
  columns,
180
175
  data,
181
- loading: lazyLoading || loading,
176
+ loading,
182
177
  pagination: {
183
178
  ...pagination,
184
179
  onPageSizeChange(pageSize) {
@@ -197,7 +192,6 @@ var SchemaTable = memo(({ ref }) => {
197
192
  columns,
198
193
  data,
199
194
  loading,
200
- lazyLoading,
201
195
  pagination,
202
196
  setPagination
203
197
  ]);
@@ -8,10 +8,6 @@
8
8
  linear-gradient(180deg, hsl(var(--background) / 0.62), hsl(var(--background) / 0.3)), hsl(var(--theme-bg));
9
9
  }
10
10
 
11
- .schema-search-region {
12
- padding-bottom: 12px;
13
- }
14
-
15
11
  .schema-search .tc-ui-search {
16
12
  align-items: flex-end;
17
13
  gap: 10px 16px;
@@ -4,18 +4,21 @@ import Iframe from "../Iframe/index.js";
4
4
  import NotFoundPage from "../NotFoundPage/index.js";
5
5
  import Schema from "../SchemaPage/index.js";
6
6
  import { memo, useMemo } from "react";
7
+ import { useParams } from "react-router-dom";
7
8
  import { jsx } from "react/jsx-runtime";
8
9
  //#region frontend/src/defaultPages/SlotPage/index.tsx
9
10
  var SlotPage = memo(() => {
10
11
  const { menu } = useCurrentMenuData(true);
12
+ const params = useParams();
13
+ const sidek = params.sidek;
11
14
  return useMemo(() => {
12
- if (menu?.moduleType === "iframe") return /* @__PURE__ */ jsx(Iframe, {});
13
- else if (menu?.moduleType === "schema") return /* @__PURE__ */ jsx(Schema, {});
15
+ if (menu?.moduleType === "iframe") return /* @__PURE__ */ jsx(Iframe, {}, sidek);
16
+ else if (menu?.moduleType === "schema") return /* @__PURE__ */ jsx(Schema, {}, sidek);
14
17
  else {
15
18
  logPageNotFound();
16
19
  return /* @__PURE__ */ jsx(NotFoundPage, {});
17
20
  }
18
- }, [menu?.moduleType]);
21
+ }, [menu?.moduleType, params.sidek]);
19
22
  });
20
23
  SlotPage.displayName = "SlotPage";
21
24
  //#endregion
@@ -6,8 +6,8 @@ export type { SchemaTableRenderComponent, SchemaTableRenderComponentsMap, } from
6
6
  export * from "./components/index";
7
7
  export type { FormFieldSchema, SchemaFormComponentsMap, SchemaFormNamespace, SelectProps } from "../../packages/react/ui/index";
8
8
  export { renderImportComponent } from "./common/importComponent";
9
- export { clearRafTimer, rafClearInterval, rafClearTimeout, rafSetInterval, rafSetTimeout } from "./common/rafTimer";
10
- export type { RafTimerCallback, RafTimerId } from "./common/rafTimer";
9
+ export { clearRafTimer, rafClearInterval, rafClearTimeout, rafSetInterval, rafSetTimeout } from "../../packages/common/rafTimer";
10
+ export type { RafTimerCallback, RafTimerId } from "../../packages/common/rafTimer";
11
11
  export { api, del, FetchAxios, get, patch, post, put, request } from "./common/request";
12
12
  export type { AxiosError, BaseResponse, PageParams, PageResponse, RequestConfig, ResponseConfig, } from "./common/request";
13
13
  export { applyThemeMode, getCurrentThemeMode, getStoredThemeMode, initThemeMode, persistThemeMode, themeSwitchStorageKey, } from "./common/theme";
@@ -11,10 +11,10 @@ import { renderImportComponent } from "./common/importComponent.js";
11
11
  import { applyThemeMode, getCurrentThemeMode, getStoredThemeMode, initThemeMode, persistThemeMode, themeSwitchStorageKey } from "./common/theme.js";
12
12
  import { generateRouter } from "./components/Router/index.js";
13
13
  import { schemaEventBus } from "./stores/schemaEventBus.js";
14
+ import { clearRafTimer, rafClearInterval, rafClearTimeout, rafSetInterval, rafSetTimeout } from "../../packages/common/rafTimer.js";
14
15
  import { schemaStore, useSchemaStore } from "./stores/schemaStore.js";
15
16
  import "./exportStore.js";
16
17
  import { initApp } from "./main.js";
17
- import { clearRafTimer, rafClearInterval, rafClearTimeout, rafSetInterval, rafSetTimeout } from "./common/rafTimer.js";
18
18
  import AsyncSelect_default from "./components/AsyncSelect/index.js";
19
19
  import LanguageSwitch_default from "./components/LanguageSwitch/index.js";
20
20
  import ThemeSwitch_default from "./components/ThemeSwitch/index.js";
@@ -6,5 +6,6 @@ export * from "./i18n";
6
6
  export * from "./log";
7
7
  export * from "./number";
8
8
  export * from "./object";
9
+ export * from "./rafTimer";
9
10
  export * from "./string";
10
11
  export * from "./types";
@@ -0,0 +1,7 @@
1
+ export type RafTimerId = number;
2
+ export type RafTimerCallback<Args extends unknown[] = []> = (...args: Args) => void;
3
+ export declare const rafSetTimeout: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
4
+ export declare const rafClearTimeout: (timerId: RafTimerId) => void;
5
+ export declare const rafSetInterval: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
6
+ export declare const rafClearInterval: (timerId: RafTimerId) => void;
7
+ export declare const clearRafTimer: (timerId: RafTimerId) => void;
@@ -0,0 +1,168 @@
1
+ //#region packages/common/rafTimer.ts
2
+ var FRAME_FALLBACK_DELAY = 16;
3
+ var timerHost = globalThis;
4
+ var rafTimers = /* @__PURE__ */ new Map();
5
+ var rafTimerSeed = 0;
6
+ /**
7
+ * 统一修正延迟时间,避免传入 undefined 或负数。
8
+ *
9
+ * @param delay 原始延迟时间。
10
+ * @returns 不小于 0 的延迟时间。
11
+ */
12
+ var normalizeDelay = (delay) => Math.max(0, delay ?? 0);
13
+ /**
14
+ * 获取当前时间戳。
15
+ */
16
+ var getNow = () => timerHost.performance?.now?.() ?? Date.now();
17
+ /**
18
+ * 创建帧调度器。
19
+ *
20
+ * 浏览器优先使用 requestAnimationFrame;否则回退到 setTimeout。
21
+ */
22
+ var createFrameScheduler = () => {
23
+ const requestAnimationFrameRef = timerHost.requestAnimationFrame;
24
+ const cancelAnimationFrameRef = timerHost.cancelAnimationFrame;
25
+ if (typeof requestAnimationFrameRef === "function" && typeof cancelAnimationFrameRef === "function") return {
26
+ scheduleFrame: (callback) => requestAnimationFrameRef.call(timerHost, callback),
27
+ cancelFrame: (handle) => cancelAnimationFrameRef.call(timerHost, handle)
28
+ };
29
+ const setTimeoutRef = timerHost.setTimeout;
30
+ const clearTimeoutRef = timerHost.clearTimeout;
31
+ if (typeof setTimeoutRef !== "function" || typeof clearTimeoutRef !== "function") throw new Error("raf timer requires requestAnimationFrame or setTimeout/clearTimeout.");
32
+ return {
33
+ scheduleFrame: (callback) => setTimeoutRef.call(timerHost, () => callback(getNow()), FRAME_FALLBACK_DELAY),
34
+ cancelFrame: (handle) => clearTimeoutRef.call(timerHost, handle)
35
+ };
36
+ };
37
+ var frameScheduler;
38
+ var getFrameScheduler = () => {
39
+ frameScheduler ??= createFrameScheduler();
40
+ return frameScheduler;
41
+ };
42
+ /**
43
+ * 创建唯一的计时器 id。
44
+ *
45
+ * @returns 新的计时器 id。
46
+ */
47
+ var createTimerId = () => {
48
+ rafTimerSeed += 1;
49
+ return rafTimerSeed;
50
+ };
51
+ /**
52
+ * 删除并取消指定计时器。
53
+ *
54
+ * 步骤:
55
+ * 1. 根据 id 查找计时器状态。
56
+ * 2. 如果计时器不存在,直接结束。
57
+ * 3. 取消下一帧回调,并从缓存中移除计时器。
58
+ *
59
+ * @param timerId 要取消的计时器 id。
60
+ */
61
+ var deleteTimer = (timerId) => {
62
+ const timer = rafTimers.get(timerId);
63
+ if (!timer) return;
64
+ getFrameScheduler().cancelFrame(timer.frameId);
65
+ rafTimers.delete(timerId);
66
+ };
67
+ /**
68
+ * 每一帧执行一次的调度函数。
69
+ *
70
+ * 步骤:
71
+ * 1. 读取当前计时器状态。
72
+ * 2. 对比当前时间和起始时间/上次执行时间,判断是否到达延迟。
73
+ * 3. timeout 到点后执行一次并删除计时器。
74
+ * 4. interval 到点后执行回调,并更新上次执行时间。
75
+ * 5. 如果计时器仍然存在,继续注册下一帧。
76
+ *
77
+ * @param timerId 当前计时器 id。
78
+ * @param currentTime requestAnimationFrame 或 fallback 传入的当前时间戳。
79
+ */
80
+ var tick = (timerId, currentTime) => {
81
+ const timer = rafTimers.get(timerId);
82
+ if (!timer) return;
83
+ if (timer.type === "timeout" ? currentTime - timer.startTime >= timer.delay : currentTime - timer.lastRunTime >= timer.delay) {
84
+ if (timer.type === "timeout") {
85
+ rafTimers.delete(timerId);
86
+ timer.callback();
87
+ return;
88
+ }
89
+ timer.lastRunTime = currentTime;
90
+ timer.callback();
91
+ }
92
+ if (rafTimers.has(timerId)) timer.frameId = getFrameScheduler().scheduleFrame((nextTime) => tick(timerId, nextTime));
93
+ };
94
+ /**
95
+ * 创建 requestAnimationFrame 计时器。
96
+ *
97
+ * 步骤:
98
+ * 1. 检查当前运行环境是否支持 requestAnimationFrame。
99
+ * 2. 创建计时器 id,并记录起始时间。
100
+ * 3. 保存计时器类型、延迟、回调和帧 id 等状态。
101
+ * 4. 注册第一帧调度。
102
+ * 5. 将计时器状态写入缓存,并返回计时器 id。
103
+ *
104
+ * @param type 计时器类型。
105
+ * @param callback 到点后执行的回调函数。
106
+ * @param delay 延迟或间隔时间,单位毫秒。
107
+ * @param args 传给回调函数的参数。
108
+ * @returns 计时器 id。
109
+ */
110
+ var createRafTimer = (type, callback, delay, args) => {
111
+ const timerId = createTimerId();
112
+ const startTime = getNow();
113
+ const timer = {
114
+ type,
115
+ delay: normalizeDelay(delay),
116
+ callback: () => callback(...args ?? []),
117
+ startTime,
118
+ lastRunTime: startTime,
119
+ frameId: 0
120
+ };
121
+ rafTimers.set(timerId, timer);
122
+ timer.frameId = getFrameScheduler().scheduleFrame((currentTime) => tick(timerId, currentTime));
123
+ return timerId;
124
+ };
125
+ /**
126
+ * 使用 requestAnimationFrame 驱动,在指定延迟后执行一次回调。
127
+ *
128
+ * @param callback 延迟结束后执行的回调函数。
129
+ * @param delay 延迟时间,单位毫秒,默认 0。
130
+ * @param args 传给回调函数的参数。
131
+ * @returns 计时器 id,可通过 rafClearTimeout 或 clearRafTimer 取消。
132
+ */
133
+ var rafSetTimeout = (callback, delay, ...args) => createRafTimer("timeout", callback, delay, args);
134
+ /**
135
+ * 取消 rafSetTimeout 创建的计时器。
136
+ *
137
+ * @param timerId rafSetTimeout 返回的计时器 id。
138
+ */
139
+ var rafClearTimeout = (timerId) => {
140
+ deleteTimer(timerId);
141
+ };
142
+ /**
143
+ * 使用 requestAnimationFrame 驱动,按指定间隔重复执行回调。
144
+ *
145
+ * @param callback 每次间隔结束后执行的回调函数。
146
+ * @param delay 间隔时间,单位毫秒,默认 0。
147
+ * @param args 传给回调函数的参数。
148
+ * @returns 计时器 id,可通过 rafClearInterval 或 clearRafTimer 取消。
149
+ */
150
+ var rafSetInterval = (callback, delay, ...args) => createRafTimer("interval", callback, delay, args);
151
+ /**
152
+ * 取消 rafSetInterval 创建的计时器。
153
+ *
154
+ * @param timerId rafSetInterval 返回的计时器 id。
155
+ */
156
+ var rafClearInterval = (timerId) => {
157
+ deleteTimer(timerId);
158
+ };
159
+ /**
160
+ * 取消本模块创建的任意 requestAnimationFrame 计时器。
161
+ *
162
+ * @param timerId rafSetTimeout 或 rafSetInterval 返回的计时器 id。
163
+ */
164
+ var clearRafTimer = (timerId) => {
165
+ deleteTimer(timerId);
166
+ };
167
+ //#endregion
168
+ export { clearRafTimer, rafClearInterval, rafClearTimeout, rafSetInterval, rafSetTimeout };
@@ -1,17 +1,9 @@
1
1
  import { RefObject } from "react";
2
- type SetState<S> = (value: S | ((preValue: S) => S), callback?: CallBackFN<S>) => void;
3
- type CallBackFN<T> = (value: T) => void;
2
+ type SetState<S> = (value: S | ((preValue: S) => S)) => void;
4
3
  type RefState<T> = RefObject<{
5
4
  data: T;
6
5
  }>;
7
- export default function useRefState<S>(initialState: S | (() => S)): [
8
- S,
9
- SetState<S>,
10
- RefState<S>
11
- ];
12
- export default function useRefState<S = undefined>(): [
13
- S | undefined,
14
- SetState<S | undefined>,
15
- RefState<S | undefined>
16
- ];
6
+ type DelayTiming = number | undefined;
7
+ export default function useRefState<S>(initialState: S | (() => S), delayTiming?: DelayTiming): [S, SetState<S>, RefState<S>];
8
+ export default function useRefState<S = undefined>(): [S | undefined, SetState<S | undefined>, RefState<S | undefined>];
17
9
  export {};
@@ -1,23 +1,33 @@
1
1
  import useInit from "./useInit.js";
2
+ import { rafClearTimeout, rafSetTimeout } from "../../common/rafTimer.js";
2
3
  import { useCallback, useLayoutEffect, useRef, useState } from "react";
3
4
  //#region packages/react/hooks/useRefState.ts
4
- function useRefState(initialState) {
5
+ var delayedCall = (call, delayTiming) => {
6
+ if (delayTiming) return rafSetTimeout(call, delayTiming);
7
+ call();
8
+ };
9
+ function useRefState(initialState, delayTiming) {
5
10
  const [v, setValue] = useState(initialState);
6
11
  const data = useRef({ data: void 0 });
7
12
  const callbackRef = useRef(null);
8
13
  const [callbackVersion, setCallbackVersion] = useState(0);
14
+ const refdelayTimer = useRef(void 0);
9
15
  useInit(() => {
10
16
  data.current.data = v;
11
17
  });
12
- const setData = useCallback((action, callback) => {
18
+ const setData = useCallback((action) => {
19
+ if (refdelayTimer.current) {
20
+ rafClearTimeout(refdelayTimer.current);
21
+ refdelayTimer.current = void 0;
22
+ }
13
23
  const value = typeof action === "function" ? action(data.current.data) : action;
14
- setValue(value);
24
+ refdelayTimer.current = delayedCall(() => setValue(value), delayTiming);
15
25
  data.current.data = value;
16
- if (callback) {
17
- callbackRef.current = callback;
18
- setCallbackVersion((version) => version + 1);
19
- }
20
- }, [setCallbackVersion, setValue]);
26
+ }, [
27
+ setCallbackVersion,
28
+ setValue,
29
+ delayTiming
30
+ ]);
21
31
  useLayoutEffect(() => {
22
32
  if (callbackRef.current) {
23
33
  const callback = callbackRef.current;
@@ -0,0 +1,12 @@
1
+ import type { CSSProperties } from "react";
2
+ export type DataTableWidth = number | string;
3
+ export declare const normalizeTableWidth: (value: DataTableWidth | undefined) => string | undefined;
4
+ type TableColumnWidthLike = {
5
+ key?: PropertyKey;
6
+ width?: DataTableWidth;
7
+ isAction?: boolean;
8
+ };
9
+ export declare const getDataTableColumnWidth: <T extends TableColumnWidthLike>(column: T, defaultColumnWidth: DataTableWidth, actionColumnWidth?: number) => string;
10
+ export declare const getDataTableColumnStyle: <T extends TableColumnWidthLike>(column: T, defaultColumnWidth: DataTableWidth, actionColumnWidth?: number) => CSSProperties;
11
+ export declare const getDataTableFixedOffset: (widths: string[]) => string;
12
+ export {};
@@ -0,0 +1,33 @@
1
+ //#region packages/react/ui/components/DataTable/dataTableWidth.ts
2
+ var numericWidthPattern = /^-?(?:\d+|\d*\.\d+)$/;
3
+ var hasWidthValue = (value) => value !== void 0 && value !== null && value !== "";
4
+ var normalizeTableWidth = (value) => {
5
+ if (!hasWidthValue(value)) return;
6
+ if (typeof value === "number") return Number.isFinite(value) ? `${value}px` : void 0;
7
+ const trimmed = value.trim();
8
+ if (trimmed === "") return;
9
+ return numericWidthPattern.test(trimmed) ? `${trimmed}px` : trimmed;
10
+ };
11
+ var hasExplicitWidth = (value) => value !== void 0 && value !== null && value !== "";
12
+ var getDataTableColumnWidth = (column, defaultColumnWidth, actionColumnWidth = 96) => {
13
+ const hasAction = column.isAction ?? column.key === "action";
14
+ return normalizeTableWidth(hasExplicitWidth(column.width) ? column.width : hasAction ? actionColumnWidth : defaultColumnWidth) ?? "0px";
15
+ };
16
+ var getDataTableColumnStyle = (column, defaultColumnWidth, actionColumnWidth = 96) => {
17
+ const hasAction = column.isAction ?? column.key === "action";
18
+ if (hasExplicitWidth(column.width) || hasAction) {
19
+ const width = getDataTableColumnWidth(column, defaultColumnWidth, actionColumnWidth);
20
+ return {
21
+ width,
22
+ minWidth: width
23
+ };
24
+ }
25
+ return { minWidth: normalizeTableWidth(defaultColumnWidth) ?? "0px" };
26
+ };
27
+ var getDataTableFixedOffset = (widths) => {
28
+ if (widths.length === 0) return "0px";
29
+ if (widths.length === 1) return widths[0];
30
+ return `calc(${widths.join(" + ")})`;
31
+ };
32
+ //#endregion
33
+ export { getDataTableColumnStyle, getDataTableColumnWidth, getDataTableFixedOffset, normalizeTableWidth };
@@ -0,0 +1,39 @@
1
+ import { getDataTableColumnStyle, getDataTableColumnWidth, getDataTableFixedOffset, normalizeTableWidth } from "./dataTableWidth.js";
2
+ import assert from "node:assert/strict";
3
+ import test from "node:test";
4
+ //#region packages/react/ui/components/DataTable/dataTableWidth.test.ts
5
+ test("normalizeTableWidth converts numeric widths to px", () => {
6
+ assert.equal(normalizeTableWidth(160), "160px");
7
+ assert.equal(normalizeTableWidth("160"), "160px");
8
+ assert.equal(normalizeTableWidth("160px"), "160px");
9
+ assert.equal(normalizeTableWidth("calc(100% - 20px)"), "calc(100% - 20px)");
10
+ assert.equal(normalizeTableWidth(""), void 0);
11
+ });
12
+ test("getDataTableColumnWidth falls back to default and action widths", () => {
13
+ assert.equal(getDataTableColumnWidth({ key: "name" }, 120), "120px");
14
+ assert.equal(getDataTableColumnWidth({ key: "action" }, 120), "96px");
15
+ assert.equal(getDataTableColumnWidth({
16
+ key: "name",
17
+ width: "180"
18
+ }, 120), "180px");
19
+ assert.equal(getDataTableColumnWidth({
20
+ key: "name",
21
+ isAction: true
22
+ }, 120), "96px");
23
+ });
24
+ test("getDataTableColumnStyle keeps width and minWidth aligned", () => {
25
+ assert.deepEqual(getDataTableColumnStyle({
26
+ key: "name",
27
+ width: "240"
28
+ }, 120), {
29
+ width: "240px",
30
+ minWidth: "240px"
31
+ });
32
+ assert.deepEqual(getDataTableColumnStyle({ key: "name" }, 120), { minWidth: "120px" });
33
+ });
34
+ test("getDataTableFixedOffset combines widths in order", () => {
35
+ assert.equal(getDataTableFixedOffset([]), "0px");
36
+ assert.equal(getDataTableFixedOffset(["48px"]), "48px");
37
+ assert.equal(getDataTableFixedOffset(["48px", "120px"]), "calc(48px + 120px)");
38
+ });
39
+ //#endregion
@@ -24,7 +24,7 @@ interface DataTableProps<T = Record<string, unknown>> {
24
24
  rowSelection?: RowSelection<T>;
25
25
  pagination?: PaginationProps;
26
26
  loading?: boolean;
27
- defaultColumnWidth?: number;
27
+ defaultColumnWidth?: number | string;
28
28
  }
29
29
  export declare function DataTable<T = Record<string, unknown>>({ columns, data: pData, loading, rowKey, rowSelection, defaultColumnWidth, pagination: pPagination, }: DataTableProps<T>): import("react/jsx-runtime").JSX.Element;
30
30
  export { ActionBtn } from "./ActionBtn";
@@ -10,13 +10,14 @@ import "../table/index.js";
10
10
  import { Skeleton } from "../Skeleton/Skeleton.js";
11
11
  import "../Skeleton/index.js";
12
12
  import { ActionBtn } from "./ActionBtn.js";
13
+ import { getDataTableColumnStyle, getDataTableColumnWidth, getDataTableFixedOffset, normalizeTableWidth } from "./dataTableWidth.js";
13
14
  import { useMemo, useState } from "react";
14
15
  import { jsx, jsxs } from "react/jsx-runtime";
15
16
  //#region packages/react/ui/components/DataTable/index.tsx
16
17
  var defaultRowKey = "id";
17
18
  var rowSelectionColumnWidth = 48;
18
19
  var actionColumnWidth = 96;
19
- var zeroOffset = "0px";
20
+ var rowSelectionColumnWidthStyle = normalizeTableWidth(rowSelectionColumnWidth) ?? "48px";
20
21
  var getRowKey = (record, index, rowKey = defaultRowKey) => {
21
22
  if (typeof rowKey === "function") return rowKey(record, index);
22
23
  const key = record[rowKey];
@@ -32,27 +33,6 @@ var renderCellContent = (column, value, record, rowIndex, hasAction) => {
32
33
  });
33
34
  return column.render ? column.render(value, record, rowIndex) : value;
34
35
  };
35
- var getColumnWidth = (column, defaultColumnWidth) => {
36
- const hasAction = column.isAction ?? column.key === "action";
37
- if (column.width) return column.width;
38
- return `${hasAction ? actionColumnWidth : defaultColumnWidth}px`;
39
- };
40
- var getColumnStyle = (column, defaultColumnWidth) => {
41
- const hasAction = column.isAction ?? column.key === "action";
42
- if (column.width || hasAction) {
43
- const width = getColumnWidth(column, defaultColumnWidth);
44
- return {
45
- width,
46
- minWidth: width
47
- };
48
- }
49
- return { minWidth: defaultColumnWidth };
50
- };
51
- var getFixedOffset = (widths) => {
52
- if (widths.length === 0) return zeroOffset;
53
- if (widths.length === 1) return widths[0];
54
- return `calc(${widths.join(" + ")})`;
55
- };
56
36
  function DataTable({ columns, data: pData, loading, rowKey = defaultRowKey, rowSelection, defaultColumnWidth = 100, pagination: pPagination }) {
57
37
  const t = useI18n();
58
38
  const getCellValue = (record, column) => record[column.dataIndex || column.key];
@@ -127,21 +107,21 @@ function DataTable({ columns, data: pData, loading, rowKey = defaultRowKey, rowS
127
107
  column,
128
108
  index,
129
109
  fixed: column.fixed ?? (hasAction ? "right" : void 0),
130
- width: getColumnWidth(column, defaultColumnWidth)
110
+ width: getDataTableColumnWidth(column, defaultColumnWidth, actionColumnWidth)
131
111
  };
132
112
  });
133
- const leftOffsetWidths = rowSelection ? [`${rowSelectionColumnWidth}px`] : [];
113
+ const leftOffsetWidths = rowSelection ? [rowSelectionColumnWidthStyle] : [];
134
114
  const leftOffsets = /* @__PURE__ */ new Map();
135
115
  for (const item of columnsWithFixed) {
136
116
  if (item.fixed !== "left") continue;
137
- leftOffsets.set(item.index, getFixedOffset(leftOffsetWidths));
117
+ leftOffsets.set(item.index, getDataTableFixedOffset(leftOffsetWidths));
138
118
  leftOffsetWidths.push(item.width);
139
119
  }
140
120
  const rightOffsetWidths = [];
141
121
  const rightOffsets = /* @__PURE__ */ new Map();
142
122
  for (const item of [...columnsWithFixed].reverse()) {
143
123
  if (item.fixed !== "right") continue;
144
- rightOffsets.set(item.index, getFixedOffset(rightOffsetWidths));
124
+ rightOffsets.set(item.index, getDataTableFixedOffset(rightOffsetWidths));
145
125
  rightOffsetWidths.push(item.width);
146
126
  }
147
127
  return columnsWithFixed.map((item) => ({
@@ -162,8 +142,8 @@ function DataTable({ columns, data: pData, loading, rowKey = defaultRowKey, rowS
162
142
  fixed: "left",
163
143
  showSeparator: false,
164
144
  style: {
165
- width: "48px",
166
- minWidth: "48px"
145
+ width: rowSelectionColumnWidthStyle,
146
+ minWidth: rowSelectionColumnWidthStyle
167
147
  },
168
148
  children: [rowSelection.beforeCheckboxNode, /* @__PURE__ */ jsx(Checkbox, {
169
149
  checked: allChecked,
@@ -177,7 +157,7 @@ function DataTable({ columns, data: pData, loading, rowKey = defaultRowKey, rowS
177
157
  fixed,
178
158
  fixedOffset,
179
159
  hideSeparatorWhenFixedActive: fixed === "right",
180
- style: getColumnStyle(column, defaultColumnWidth),
160
+ style: getDataTableColumnStyle(column, defaultColumnWidth, actionColumnWidth),
181
161
  children: column.title
182
162
  }, column.key);
183
163
  })] }) }), /* @__PURE__ */ jsx(TableBody, { children: data.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
@@ -196,8 +176,8 @@ function DataTable({ columns, data: pData, loading, rowKey = defaultRowKey, rowS
196
176
  return /* @__PURE__ */ jsxs(TableRow, { children: [rowSelection && /* @__PURE__ */ jsx(TableCell, {
197
177
  fixed: "left",
198
178
  style: {
199
- width: "48px",
200
- minWidth: "48px"
179
+ width: rowSelectionColumnWidthStyle,
180
+ minWidth: rowSelectionColumnWidthStyle
201
181
  },
202
182
  children: /* @__PURE__ */ jsx(Checkbox, {
203
183
  checked: selectedKeySet.has(recordKey),
@@ -211,7 +191,7 @@ function DataTable({ columns, data: pData, loading, rowKey = defaultRowKey, rowS
211
191
  isAction: hasAction,
212
192
  fixed,
213
193
  fixedOffset,
214
- style: getColumnStyle(column, defaultColumnWidth),
194
+ style: getDataTableColumnStyle(column, defaultColumnWidth, actionColumnWidth),
215
195
  children: renderCellContent(column, value, record, rowIndex, hasAction)
216
196
  }, column.key);
217
197
  })] }, recordKey);
@@ -3,7 +3,7 @@ export type ColumnDefForKey<T> = {
3
3
  key: K;
4
4
  title: string;
5
5
  dataIndex?: string;
6
- width?: string;
6
+ width?: number | string;
7
7
  isAction?: boolean;
8
8
  render?: (value: T[K], record: T, index: number) => React.ReactNode;
9
9
  renderExport?: (value: T[K], record: T, index: number) => React.ReactNode;
@@ -13,7 +13,7 @@ export type ColumnDefAction<T> = {
13
13
  key: 'action';
14
14
  title: string;
15
15
  dataIndex?: string;
16
- width?: string;
16
+ width?: number | string;
17
17
  isAction?: boolean;
18
18
  render?: (value: unknown, record: T, index: number) => React.ReactNode;
19
19
  renderExport?: (value: unknown, record: T, index: number) => React.ReactNode;
@@ -6,5 +6,6 @@ export * from "./i18n";
6
6
  export * from "./log";
7
7
  export * from "./number";
8
8
  export * from "./object";
9
+ export * from "./rafTimer";
9
10
  export * from "./string";
10
11
  export * from "./types";
@@ -0,0 +1,7 @@
1
+ export type RafTimerId = number;
2
+ export type RafTimerCallback<Args extends unknown[] = []> = (...args: Args) => void;
3
+ export declare const rafSetTimeout: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
4
+ export declare const rafClearTimeout: (timerId: RafTimerId) => void;
5
+ export declare const rafSetInterval: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
6
+ export declare const rafClearInterval: (timerId: RafTimerId) => void;
7
+ export declare const clearRafTimer: (timerId: RafTimerId) => void;
@@ -0,0 +1,12 @@
1
+ import type { CSSProperties } from "react";
2
+ export type DataTableWidth = number | string;
3
+ export declare const normalizeTableWidth: (value: DataTableWidth | undefined) => string | undefined;
4
+ type TableColumnWidthLike = {
5
+ key?: PropertyKey;
6
+ width?: DataTableWidth;
7
+ isAction?: boolean;
8
+ };
9
+ export declare const getDataTableColumnWidth: <T extends TableColumnWidthLike>(column: T, defaultColumnWidth: DataTableWidth, actionColumnWidth?: number) => string;
10
+ export declare const getDataTableColumnStyle: <T extends TableColumnWidthLike>(column: T, defaultColumnWidth: DataTableWidth, actionColumnWidth?: number) => CSSProperties;
11
+ export declare const getDataTableFixedOffset: (widths: string[]) => string;
12
+ export {};
@@ -24,7 +24,7 @@ interface DataTableProps<T = Record<string, unknown>> {
24
24
  rowSelection?: RowSelection<T>;
25
25
  pagination?: PaginationProps;
26
26
  loading?: boolean;
27
- defaultColumnWidth?: number;
27
+ defaultColumnWidth?: number | string;
28
28
  }
29
29
  export declare function DataTable<T = Record<string, unknown>>({ columns, data: pData, loading, rowKey, rowSelection, defaultColumnWidth, pagination: pPagination, }: DataTableProps<T>): import("react/jsx-runtime").JSX.Element;
30
30
  export { ActionBtn } from "./ActionBtn";
@@ -3,7 +3,7 @@ export type ColumnDefForKey<T> = {
3
3
  key: K;
4
4
  title: string;
5
5
  dataIndex?: string;
6
- width?: string;
6
+ width?: number | string;
7
7
  isAction?: boolean;
8
8
  render?: (value: T[K], record: T, index: number) => React.ReactNode;
9
9
  renderExport?: (value: T[K], record: T, index: number) => React.ReactNode;
@@ -13,7 +13,7 @@ export type ColumnDefAction<T> = {
13
13
  key: 'action';
14
14
  title: string;
15
15
  dataIndex?: string;
16
- width?: string;
16
+ width?: number | string;
17
17
  isAction?: boolean;
18
18
  render?: (value: unknown, record: T, index: number) => React.ReactNode;
19
19
  renderExport?: (value: unknown, record: T, index: number) => React.ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_tc/template-core",
3
- "version": "0.2.0-bate.7",
3
+ "version": "0.2.0-bate.9",
4
4
  "description": "A full-stack TypeScript admin framework powered by Koa, React, and Vite - monorepo root",
5
5
  "types": "./types/index.d.ts",
6
6
  "exports": {
@@ -6,5 +6,6 @@ export * from "./i18n";
6
6
  export * from "./log";
7
7
  export * from "./number";
8
8
  export * from "./object";
9
+ export * from "./rafTimer";
9
10
  export * from "./string";
10
11
  export * from "./types";
@@ -0,0 +1,44 @@
1
+ /**
2
+ * rafSetTimeout 和 rafSetInterval 返回的计时器 id。
3
+ */
4
+ export type RafTimerId = number;
5
+ /**
6
+ * 基于 requestAnimationFrame 的计时器回调类型。
7
+ */
8
+ export type RafTimerCallback<Args extends unknown[] = []> = (...args: Args) => void;
9
+ /**
10
+ * 使用 requestAnimationFrame 驱动,在指定延迟后执行一次回调。
11
+ *
12
+ * @param callback 延迟结束后执行的回调函数。
13
+ * @param delay 延迟时间,单位毫秒,默认 0。
14
+ * @param args 传给回调函数的参数。
15
+ * @returns 计时器 id,可通过 rafClearTimeout 或 clearRafTimer 取消。
16
+ */
17
+ export declare const rafSetTimeout: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
18
+ /**
19
+ * 取消 rafSetTimeout 创建的计时器。
20
+ *
21
+ * @param timerId rafSetTimeout 返回的计时器 id。
22
+ */
23
+ export declare const rafClearTimeout: (timerId: RafTimerId) => void;
24
+ /**
25
+ * 使用 requestAnimationFrame 驱动,按指定间隔重复执行回调。
26
+ *
27
+ * @param callback 每次间隔结束后执行的回调函数。
28
+ * @param delay 间隔时间,单位毫秒,默认 0。
29
+ * @param args 传给回调函数的参数。
30
+ * @returns 计时器 id,可通过 rafClearInterval 或 clearRafTimer 取消。
31
+ */
32
+ export declare const rafSetInterval: <Args extends unknown[]>(callback: RafTimerCallback<Args>, delay?: number, ...args: Args) => RafTimerId;
33
+ /**
34
+ * 取消 rafSetInterval 创建的计时器。
35
+ *
36
+ * @param timerId rafSetInterval 返回的计时器 id。
37
+ */
38
+ export declare const rafClearInterval: (timerId: RafTimerId) => void;
39
+ /**
40
+ * 取消本模块创建的任意 requestAnimationFrame 计时器。
41
+ *
42
+ * @param timerId rafSetTimeout 或 rafSetInterval 返回的计时器 id。
43
+ */
44
+ export declare const clearRafTimer: (timerId: RafTimerId) => void;