@composy/log-viewer-core 0.0.1 → 0.0.2

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 (108) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +175 -37
  3. package/dist/index.js +614 -299
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.js +548 -1
  6. package/dist/index.min.js.map +1 -0
  7. package/es/.dts-output-manifest.json +1 -0
  8. package/es/.dts.tsbuildinfo +1 -0
  9. package/es/core/EventEmitter.d.ts +0 -1
  10. package/es/core/EventEmitter.js +13 -9
  11. package/es/core/EventEmitter.js.map +1 -1
  12. package/es/core/LogViewer.d.ts +14 -11
  13. package/es/core/LogViewer.js +243 -64
  14. package/es/core/LogViewer.js.map +1 -1
  15. package/es/filters/FilterEngine.d.ts +0 -1
  16. package/es/filters/FilterEngine.js +31 -26
  17. package/es/filters/FilterEngine.js.map +1 -1
  18. package/es/index.d.ts +7 -7
  19. package/es/index.js +3 -3
  20. package/es/index.js.map +1 -1
  21. package/es/renderers/DiffRenderer.d.ts +0 -1
  22. package/es/renderers/DiffRenderer.js +13 -3
  23. package/es/renderers/DiffRenderer.js.map +1 -1
  24. package/es/renderers/TimelineRenderer.d.ts +7 -3
  25. package/es/renderers/TimelineRenderer.js +56 -22
  26. package/es/renderers/TimelineRenderer.js.map +1 -1
  27. package/es/styles/index.d.ts +1 -5
  28. package/es/styles/index.js +167 -131
  29. package/es/styles/index.js.map +1 -1
  30. package/es/types/index.d.ts +4 -1
  31. package/es/types/index.js +1 -1
  32. package/es/types/index.js.map +1 -1
  33. package/es/utils/index.d.ts +1 -2
  34. package/es/utils/index.js +54 -6
  35. package/es/utils/index.js.map +1 -1
  36. package/esm/core/EventEmitter.js +13 -9
  37. package/esm/core/EventEmitter.js.map +1 -1
  38. package/esm/core/LogViewer.js +243 -64
  39. package/esm/core/LogViewer.js.map +1 -1
  40. package/esm/filters/FilterEngine.js +31 -26
  41. package/esm/filters/FilterEngine.js.map +1 -1
  42. package/esm/index.js +2 -2
  43. package/esm/index.js.map +1 -1
  44. package/esm/renderers/DiffRenderer.js +13 -3
  45. package/esm/renderers/DiffRenderer.js.map +1 -1
  46. package/esm/renderers/TimelineRenderer.js +56 -22
  47. package/esm/renderers/TimelineRenderer.js.map +1 -1
  48. package/esm/styles/index.js +167 -131
  49. package/esm/styles/index.js.map +1 -1
  50. package/esm/types/index.js +1 -1
  51. package/esm/types/index.js.map +1 -1
  52. package/esm/utils/index.js +54 -6
  53. package/esm/utils/index.js.map +1 -1
  54. package/lib/core/EventEmitter.cjs +13 -9
  55. package/lib/core/EventEmitter.cjs.map +1 -1
  56. package/{esm/core/EventEmitter.d.ts → lib/core/EventEmitter.d.cts} +0 -1
  57. package/lib/core/LogViewer.cjs +247 -68
  58. package/lib/core/LogViewer.cjs.map +1 -1
  59. package/{esm/core/LogViewer.d.ts → lib/core/LogViewer.d.cts} +14 -11
  60. package/lib/filters/FilterEngine.cjs +31 -26
  61. package/lib/filters/FilterEngine.cjs.map +1 -1
  62. package/lib/filters/{FilterEngine.d.ts → FilterEngine.d.cts} +0 -1
  63. package/lib/index.cjs +3 -3
  64. package/lib/index.cjs.map +1 -1
  65. package/{esm/index.d.ts → lib/index.d.cts} +7 -7
  66. package/lib/renderers/DiffRenderer.cjs +13 -3
  67. package/lib/renderers/DiffRenderer.cjs.map +1 -1
  68. package/lib/renderers/{DiffRenderer.d.ts → DiffRenderer.d.cts} +0 -1
  69. package/lib/renderers/TimelineRenderer.cjs +55 -21
  70. package/lib/renderers/TimelineRenderer.cjs.map +1 -1
  71. package/lib/renderers/{TimelineRenderer.d.ts → TimelineRenderer.d.cts} +7 -3
  72. package/lib/styles/index.cjs +167 -131
  73. package/lib/styles/index.cjs.map +1 -1
  74. package/{esm/styles/index.d.ts → lib/styles/index.d.cts} +1 -5
  75. package/lib/types/index.cjs +1 -1
  76. package/lib/types/index.cjs.map +1 -1
  77. package/{esm/types/index.d.ts → lib/types/index.d.cts} +4 -1
  78. package/lib/utils/index.cjs +54 -6
  79. package/lib/utils/index.cjs.map +1 -1
  80. package/{esm/utils/index.d.ts → lib/utils/index.d.cts} +1 -2
  81. package/package.json +15 -9
  82. package/es/core/EventEmitter.d.ts.map +0 -1
  83. package/es/core/LogViewer.d.ts.map +0 -1
  84. package/es/filters/FilterEngine.d.ts.map +0 -1
  85. package/es/index.d.ts.map +0 -1
  86. package/es/renderers/DiffRenderer.d.ts.map +0 -1
  87. package/es/renderers/TimelineRenderer.d.ts.map +0 -1
  88. package/es/styles/index.d.ts.map +0 -1
  89. package/es/types/index.d.ts.map +0 -1
  90. package/es/utils/index.d.ts.map +0 -1
  91. package/esm/core/EventEmitter.d.ts.map +0 -1
  92. package/esm/core/LogViewer.d.ts.map +0 -1
  93. package/esm/filters/FilterEngine.d.ts +0 -26
  94. package/esm/filters/FilterEngine.d.ts.map +0 -1
  95. package/esm/index.d.ts.map +0 -1
  96. package/esm/renderers/DiffRenderer.d.ts +0 -18
  97. package/esm/renderers/DiffRenderer.d.ts.map +0 -1
  98. package/esm/renderers/TimelineRenderer.d.ts +0 -22
  99. package/esm/renderers/TimelineRenderer.d.ts.map +0 -1
  100. package/esm/styles/index.d.ts.map +0 -1
  101. package/esm/types/index.d.ts.map +0 -1
  102. package/esm/utils/index.d.ts.map +0 -1
  103. package/lib/core/EventEmitter.d.ts +0 -11
  104. package/lib/core/LogViewer.d.ts +0 -46
  105. package/lib/index.d.ts +0 -26
  106. package/lib/styles/index.d.ts +0 -9
  107. package/lib/types/index.d.ts +0 -113
  108. package/lib/utils/index.d.ts +0 -18
package/es/index.d.ts CHANGED
@@ -2,6 +2,11 @@
2
2
  * @composy/log-viewer-core
3
3
  * 审计日志查看器 - 操作日志可视化与追溯
4
4
  */
5
+ /**
6
+ * 创建 LogViewer 实例 - 工厂函数
7
+ */
8
+ import type { LogViewerConfig } from './types';
9
+ import { LogViewer } from './core/LogViewer';
5
10
  export declare const VERSION = "0.1.0";
6
11
  export type { ActionType, ThemeMode, AnomalyType, DiffEntry, LogEntry, FilterConfig, PaginationConfig, LogViewerConfig, LogViewerInstance, LogViewerEvents, } from './types';
7
12
  export { ACTION_LABELS, ACTION_COLORS } from './types';
@@ -9,18 +14,13 @@ export { LogViewer } from './core/LogViewer';
9
14
  export { EventEmitter } from './core/EventEmitter';
10
15
  export { FilterEngine } from './filters/FilterEngine';
11
16
  export { TimelineRenderer } from './renderers/TimelineRenderer';
17
+ export type { TimelineRendererOptions } from './renderers/TimelineRenderer';
12
18
  export { DiffRenderer } from './renderers/DiffRenderer';
13
- export { formatDate, formatRelativeTime, escapeHtml, debounce, uid, formatValue, deepClone } from './utils';
19
+ export { formatDate, formatRelativeTime, escapeHtml, debounce, uid, formatValue, deepClone, } from './utils';
14
20
  export { injectStyles } from './styles';
15
- /**
16
- * 创建 LogViewer 实例 - 工厂函数
17
- */
18
- import type { LogViewerConfig } from './types';
19
- import { LogViewer } from './core/LogViewer';
20
21
  /**
21
22
  * createLogViewer - create Log Viewer function
22
23
  * @param config - 参数说明
23
24
  * @returns 返回值说明
24
25
  */
25
26
  export declare function createLogViewer(config: LogViewerConfig): LogViewer;
26
- //# sourceMappingURL=index.d.ts.map
package/es/index.js CHANGED
@@ -2,17 +2,17 @@
2
2
  * ***********************************
3
3
  * @composy/log-viewer-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:33:32 *
5
+ * Build time: 2024-10-12 17:29:20 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
9
9
  */
10
10
  import { EventEmitter } from "./core/EventEmitter.js";
11
- import { FilterEngine } from "./filters/FilterEngine.js";
12
11
  import { ACTION_COLORS, ACTION_LABELS } from "./types/index.js";
12
+ import { FilterEngine } from "./filters/FilterEngine.js";
13
13
  import { debounce, deepClone, escapeHtml, formatDate, formatRelativeTime, formatValue, uid } from "./utils/index.js";
14
- import { TimelineRenderer } from "./renderers/TimelineRenderer.js";
15
14
  import { DiffRenderer } from "./renderers/DiffRenderer.js";
15
+ import { TimelineRenderer } from "./renderers/TimelineRenderer.js";
16
16
  import { injectStyles } from "./styles/index.js";
17
17
  import { LogViewer } from "./core/LogViewer.js";
18
18
  //#region src/index.ts
package/es/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["LogViewer"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @composy/log-viewer-core\n * 审计日志查看器 - 操作日志可视化与追溯\n */\n\nexport const VERSION = '0.1.0'\n\n// 类型\nexport type {\n ActionType,\n ThemeMode,\n AnomalyType,\n DiffEntry,\n LogEntry,\n FilterConfig,\n PaginationConfig,\n LogViewerConfig,\n LogViewerInstance,\n LogViewerEvents,\n} from './types'\nexport { ACTION_LABELS, ACTION_COLORS } from './types'\n\n// 核心\nexport { LogViewer } from './core/LogViewer'\nexport { EventEmitter } from './core/EventEmitter'\n\n// 筛选\nexport { FilterEngine } from './filters/FilterEngine'\n\n// 渲染器\nexport { TimelineRenderer } from './renderers/TimelineRenderer'\nexport { DiffRenderer } from './renderers/DiffRenderer'\n\n// 工具\nexport { formatDate, formatRelativeTime, escapeHtml, debounce, uid, formatValue, deepClone } from './utils'\n\n// 样式\nexport { injectStyles } from './styles'\n\n/**\n * 创建 LogViewer 实例 - 工厂函数\n */\nimport type { LogViewerConfig } from './types'\nimport { LogViewer } from './core/LogViewer'\n\n/**\n * createLogViewer - create Log Viewer function\n * @param config - 参数说明\n * @returns 返回值说明\n */\nexport function createLogViewer(config: LogViewerConfig): LogViewer {\n return new LogViewer(config)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAKO,MAAM,UAAU;AA6ChB,SAAS,gBAAgB,QAAoC;CAClE,OAAO,IAAIA,UAAU,MAAM;AAC7B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @composy/log-viewer-core\r\n * 审计日志查看器 - 操作日志可视化与追溯\r\n */\r\n\r\n/**\r\n * 创建 LogViewer 实例 - 工厂函数\r\n */\r\nimport type { LogViewerConfig } from './types'\r\nimport { LogViewer } from './core/LogViewer'\r\n\r\nexport const VERSION = '0.1.0'\r\n\r\n// 类型\r\nexport type {\r\n ActionType,\r\n ThemeMode,\r\n AnomalyType,\r\n DiffEntry,\r\n LogEntry,\r\n FilterConfig,\r\n PaginationConfig,\r\n LogViewerConfig,\r\n LogViewerInstance,\r\n LogViewerEvents,\r\n} from './types'\r\nexport { ACTION_LABELS, ACTION_COLORS } from './types'\r\n\r\n// 核心\r\nexport { LogViewer } from './core/LogViewer'\r\nexport { EventEmitter } from './core/EventEmitter'\r\n\r\n// 筛选\r\nexport { FilterEngine } from './filters/FilterEngine'\r\n\r\n// 渲染器\r\nexport { TimelineRenderer } from './renderers/TimelineRenderer'\r\nexport type { TimelineRendererOptions } from './renderers/TimelineRenderer'\r\nexport { DiffRenderer } from './renderers/DiffRenderer'\r\n\r\n// 工具\r\nexport {\r\n formatDate,\r\n formatRelativeTime,\r\n escapeHtml,\r\n debounce,\r\n uid,\r\n formatValue,\r\n deepClone,\r\n} from './utils'\r\n\r\n// 样式\r\nexport { injectStyles } from './styles'\r\n\r\n/**\r\n * createLogViewer - create Log Viewer function\r\n * @param config - 参数说明\r\n * @returns 返回值说明\r\n */\r\nexport function createLogViewer(config: LogViewerConfig): LogViewer {\r\n return new LogViewer(config)\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;AAWO,MAAM,UAAU;AAgDhB,SAAS,gBAAgB,QAAoC;CAClE,OAAO,IAAI,UAAU,MAAM;AAC7B"}
@@ -15,4 +15,3 @@ export declare class DiffRenderer {
15
15
  */
16
16
  renderDiffTable(changes: DiffEntry[]): HTMLElement;
17
17
  }
18
- //# sourceMappingURL=DiffRenderer.d.ts.map
@@ -2,7 +2,7 @@
2
2
  * ***********************************
3
3
  * @composy/log-viewer-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:33:32 *
5
+ * Build time: 2024-10-12 17:29:20 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
@@ -20,7 +20,7 @@ var DiffRenderer = class {
20
20
  if (entry.metadata && Object.keys(entry.metadata).length > 0) {
21
21
  const meta = document.createElement("div");
22
22
  meta.className = "lv-metadata";
23
- meta.textContent = JSON.stringify(entry.metadata, null, 2);
23
+ meta.textContent = formatValue(entry.metadata);
24
24
  container.appendChild(meta);
25
25
  }
26
26
  return container;
@@ -32,7 +32,17 @@ var DiffRenderer = class {
32
32
  const table = document.createElement("table");
33
33
  table.className = "lv-diff-table";
34
34
  const thead = document.createElement("thead");
35
- thead.innerHTML = `<tr><th>\u5B57\u6BB5</th><th>\u53D8\u66F4\u524D</th><th>\u53D8\u66F4\u540E</th></tr>`;
35
+ const headerRow = document.createElement("tr");
36
+ for (const label of [
37
+ "字段",
38
+ "变更前",
39
+ "变更后"
40
+ ]) {
41
+ const th = document.createElement("th");
42
+ th.textContent = label;
43
+ headerRow.appendChild(th);
44
+ }
45
+ thead.appendChild(headerRow);
36
46
  table.appendChild(thead);
37
47
  const tbody = document.createElement("tbody");
38
48
  for (const change of changes) {
@@ -1 +1 @@
1
- {"version":3,"file":"DiffRenderer.js","names":[],"sources":["../../src/renderers/DiffRenderer.ts"],"sourcesContent":["/**\n * 变更对比渲染器 - 渲染字段变更前后的 Diff 表格\n */\n\nimport type { DiffEntry, LogEntry } from '../types'\nimport { escapeHtml, formatValue } from '../utils'\n\n/**\n * DiffRenderer - Diff Renderer class\n */\nexport class DiffRenderer {\n /**\n * 渲染详情面板(包含 diff 表格和 metadata)\n */\n renderDetail(entry: LogEntry): HTMLElement {\n const container = document.createElement('div')\n container.className = 'lv-detail'\n\n if (entry.changes && entry.changes.length > 0) {\n container.appendChild(this.renderDiffTable(entry.changes))\n }\n\n if (entry.metadata && Object.keys(entry.metadata).length > 0) {\n const meta = document.createElement('div')\n meta.className = 'lv-metadata'\n meta.textContent = JSON.stringify(entry.metadata, null, 2)\n container.appendChild(meta)\n }\n\n return container\n }\n\n /**\n * 渲染 Diff 表格\n */\n renderDiffTable(changes: DiffEntry[]): HTMLElement {\n const table = document.createElement('table')\n table.className = 'lv-diff-table'\n\n // Header\n const thead = document.createElement('thead')\n thead.innerHTML = `<tr><th>字段</th><th>变更前</th><th>变更后</th></tr>`\n table.appendChild(thead)\n\n // Body\n const tbody = document.createElement('tbody')\n for (const change of changes) {\n const tr = document.createElement('tr')\n\n const tdField = document.createElement('td')\n tdField.textContent = change.label || change.field\n tr.appendChild(tdField)\n\n const tdOld = document.createElement('td')\n tdOld.className = 'lv-diff-old'\n tdOld.textContent = formatValue(change.oldValue)\n tr.appendChild(tdOld)\n\n const tdNew = document.createElement('td')\n tdNew.className = 'lv-diff-new'\n tdNew.textContent = formatValue(change.newValue)\n tr.appendChild(tdNew)\n\n tbody.appendChild(tr)\n }\n table.appendChild(tbody)\n\n return table\n }\n}\n"],"mappings":";;;;;;;;;;;AAUO,IAAM,eAAN,MAAmB;;;;CAIxB,aAAa,OAA8B;EACzC,MAAM,YAAY,SAAS,cAAc,KAAK;EAC9C,UAAU,YAAY;EAEtB,IAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAC1C,UAAU,YAAY,KAAK,gBAAgB,MAAM,OAAO,CAAC;EAG3D,IAAI,MAAM,YAAY,OAAO,KAAK,MAAM,QAAQ,CAAA,CAAE,SAAS,GAAG;GAC5D,MAAM,OAAO,SAAS,cAAc,KAAK;GACzC,KAAK,YAAY;GACjB,KAAK,cAAc,KAAK,UAAU,MAAM,UAAU,MAAM,CAAC;GACzD,UAAU,YAAY,IAAI;EAC5B;EAEA,OAAO;CACT;;;;CAKA,gBAAgB,SAAmC;EACjD,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,YAAY;EAGlB,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,YAAY;EAClB,MAAM,YAAY,KAAK;EAGvB,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,KAAA,MAAW,UAAU,SAAS;GAC5B,MAAM,KAAK,SAAS,cAAc,IAAI;GAEtC,MAAM,UAAU,SAAS,cAAc,IAAI;GAC3C,QAAQ,cAAc,OAAO,SAAS,OAAO;GAC7C,GAAG,YAAY,OAAO;GAEtB,MAAM,QAAQ,SAAS,cAAc,IAAI;GACzC,MAAM,YAAY;GAClB,MAAM,cAAc,YAAY,OAAO,QAAQ;GAC/C,GAAG,YAAY,KAAK;GAEpB,MAAM,QAAQ,SAAS,cAAc,IAAI;GACzC,MAAM,YAAY;GAClB,MAAM,cAAc,YAAY,OAAO,QAAQ;GAC/C,GAAG,YAAY,KAAK;GAEpB,MAAM,YAAY,EAAE;EACtB;EACA,MAAM,YAAY,KAAK;EAEvB,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"DiffRenderer.js","names":[],"sources":["../../src/renderers/DiffRenderer.ts"],"sourcesContent":["/**\r\n * 变更对比渲染器 - 渲染字段变更前后的 Diff 表格\r\n */\r\n\r\nimport type { DiffEntry, LogEntry } from '../types'\r\nimport { formatValue } from '../utils'\r\n\r\n/**\r\n * DiffRenderer - Diff Renderer class\r\n */\r\nexport class DiffRenderer {\r\n /**\r\n * 渲染详情面板(包含 diff 表格和 metadata)\r\n */\r\n renderDetail(entry: LogEntry): HTMLElement {\r\n const container = document.createElement('div')\r\n container.className = 'lv-detail'\r\n\r\n if (entry.changes && entry.changes.length > 0) {\r\n container.appendChild(this.renderDiffTable(entry.changes))\r\n }\r\n\r\n if (entry.metadata && Object.keys(entry.metadata).length > 0) {\r\n const meta = document.createElement('div')\r\n meta.className = 'lv-metadata'\r\n meta.textContent = formatValue(entry.metadata)\r\n container.appendChild(meta)\r\n }\r\n\r\n return container\r\n }\r\n\r\n /**\r\n * 渲染 Diff 表格\r\n */\r\n renderDiffTable(changes: DiffEntry[]): HTMLElement {\r\n const table = document.createElement('table')\r\n table.className = 'lv-diff-table'\r\n\r\n // Header\r\n const thead = document.createElement('thead')\r\n const headerRow = document.createElement('tr')\r\n for (const label of ['字段', '变更前', '变更后']) {\r\n const th = document.createElement('th')\r\n th.textContent = label\r\n headerRow.appendChild(th)\r\n }\r\n thead.appendChild(headerRow)\r\n table.appendChild(thead)\r\n\r\n // Body\r\n const tbody = document.createElement('tbody')\r\n for (const change of changes) {\r\n const tr = document.createElement('tr')\r\n\r\n const tdField = document.createElement('td')\r\n tdField.textContent = change.label || change.field\r\n tr.appendChild(tdField)\r\n\r\n const tdOld = document.createElement('td')\r\n tdOld.className = 'lv-diff-old'\r\n tdOld.textContent = formatValue(change.oldValue)\r\n tr.appendChild(tdOld)\r\n\r\n const tdNew = document.createElement('td')\r\n tdNew.className = 'lv-diff-new'\r\n tdNew.textContent = formatValue(change.newValue)\r\n tr.appendChild(tdNew)\r\n\r\n tbody.appendChild(tr)\r\n }\r\n table.appendChild(tbody)\r\n\r\n return table\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;AAUO,IAAM,eAAN,MAAmB;;;;CAIxB,aAAa,OAA8B;EACzC,MAAM,YAAY,SAAS,cAAc,KAAK;EAC9C,UAAU,YAAY;EAEtB,IAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAC1C,UAAU,YAAY,KAAK,gBAAgB,MAAM,OAAO,CAAC;EAG3D,IAAI,MAAM,YAAY,OAAO,KAAK,MAAM,QAAQ,CAAA,CAAE,SAAS,GAAG;GAC5D,MAAM,OAAO,SAAS,cAAc,KAAK;GACzC,KAAK,YAAY;GACjB,KAAK,cAAc,YAAY,MAAM,QAAQ;GAC7C,UAAU,YAAY,IAAI;EAC5B;EAEA,OAAO;CACT;;;;CAKA,gBAAgB,SAAmC;EACjD,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,YAAY;EAGlB,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,YAAY,SAAS,cAAc,IAAI;EAC7C,KAAA,MAAW,SAAS;GAAC;GAAM;GAAO;EAAK,GAAG;GACxC,MAAM,KAAK,SAAS,cAAc,IAAI;GACtC,GAAG,cAAc;GACjB,UAAU,YAAY,EAAE;EAC1B;EACA,MAAM,YAAY,SAAS;EAC3B,MAAM,YAAY,KAAK;EAGvB,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,KAAA,MAAW,UAAU,SAAS;GAC5B,MAAM,KAAK,SAAS,cAAc,IAAI;GAEtC,MAAM,UAAU,SAAS,cAAc,IAAI;GAC3C,QAAQ,cAAc,OAAO,SAAS,OAAO;GAC7C,GAAG,YAAY,OAAO;GAEtB,MAAM,QAAQ,SAAS,cAAc,IAAI;GACzC,MAAM,YAAY;GAClB,MAAM,cAAc,YAAY,OAAO,QAAQ;GAC/C,GAAG,YAAY,KAAK;GAEpB,MAAM,QAAQ,SAAS,cAAc,IAAI;GACzC,MAAM,YAAY;GAClB,MAAM,cAAc,YAAY,OAAO,QAAQ;GAC/C,GAAG,YAAY,KAAK;GAEpB,MAAM,YAAY,EAAE;EACtB;EACA,MAAM,YAAY,KAAK;EAEvB,OAAO;CACT;AACF"}
@@ -2,6 +2,11 @@
2
2
  * 时间线渲染器 - 将日志条目渲染为时间线 DOM
3
3
  */
4
4
  import type { LogEntry } from '../types';
5
+ export interface TimelineRendererOptions {
6
+ showDiff?: boolean;
7
+ showAnomalyBadge?: boolean;
8
+ locale?: 'zh-CN' | 'en-US';
9
+ }
5
10
  /**
6
11
  * TimelineRenderer - Timeline Renderer class
7
12
  */
@@ -9,14 +14,13 @@ export declare class TimelineRenderer {
9
14
  /**
10
15
  * 渲染时间线
11
16
  */
12
- render(entries: LogEntry[], expandedIds: Set<string>): HTMLElement;
17
+ render(entries: LogEntry[], expandedIds: Set<string>, options?: TimelineRendererOptions): HTMLElement;
13
18
  /**
14
19
  * 渲染单条时间线条目
15
20
  */
16
- renderItem(entry: LogEntry, expanded: boolean): HTMLElement;
21
+ renderItem(entry: LogEntry, expanded: boolean, options?: TimelineRendererOptions): HTMLElement;
17
22
  /**
18
23
  * 渲染分页
19
24
  */
20
25
  renderPagination(page: number, pageSize: number, total: number): HTMLElement;
21
26
  }
22
- //# sourceMappingURL=TimelineRenderer.d.ts.map
@@ -2,12 +2,12 @@
2
2
  * ***********************************
3
3
  * @composy/log-viewer-core v0.0.1 *
4
4
  * Built with rollup *
5
- * Build time: 2024-08-17 11:33:32 *
5
+ * Build time: 2024-10-12 17:29:20 *
6
6
  * Build mode: production *
7
7
  * Minified: No *
8
8
  * ***********************************
9
9
  */
10
- import { ACTION_COLORS, ACTION_LABELS } from "../types/index.js";
10
+ import { ACTION_LABELS } from "../types/index.js";
11
11
  import { formatDate } from "../utils/index.js";
12
12
  //#region src/renderers/TimelineRenderer.ts
13
13
  const ANOMALY_LABELS = {
@@ -16,29 +16,53 @@ const ANOMALY_LABELS = {
16
16
  "high-frequency": "高频操作",
17
17
  none: ""
18
18
  };
19
+ const ANOMALY_LABELS_EN = {
20
+ "off-hours": "Off hours",
21
+ sensitive: "Sensitive",
22
+ "high-frequency": "High frequency",
23
+ none: ""
24
+ };
25
+ const ACTION_LABELS_EN = {
26
+ create: "Create",
27
+ update: "Update",
28
+ delete: "Delete",
29
+ query: "Query",
30
+ login: "Login",
31
+ logout: "Logout",
32
+ export: "Export",
33
+ import: "Import",
34
+ approve: "Approve",
35
+ reject: "Reject",
36
+ other: "Other"
37
+ };
19
38
  var TimelineRenderer = class {
20
39
  /**
21
40
  * 渲染时间线
22
41
  */
23
- render(entries, expandedIds) {
42
+ render(entries, expandedIds, options = {}) {
24
43
  const container = document.createElement("div");
25
44
  container.className = "lv-timeline";
26
45
  if (entries.length === 0) {
27
- container.innerHTML = `<div class="lv-empty"><div class="lv-empty-icon">--</div><div>\u6682\u65E0\u65E5\u5FD7\u8BB0\u5F55</div></div>`;
46
+ const emptyIcon = document.createElement("div");
47
+ emptyIcon.className = "lv-empty-icon";
48
+ emptyIcon.textContent = "--";
49
+ const emptyText = document.createElement("div");
50
+ emptyText.textContent = options.locale === "en-US" ? "No log entries" : "暂无日志记录";
51
+ container.append(emptyIcon, emptyText);
28
52
  container.className = "";
29
53
  return container;
30
54
  }
31
- for (const entry of entries) container.appendChild(this.renderItem(entry, expandedIds.has(entry.id)));
55
+ for (const entry of entries) container.appendChild(this.renderItem(entry, expandedIds.has(entry.id), options));
32
56
  return container;
33
57
  }
34
58
  /**
35
59
  * 渲染单条时间线条目
36
60
  */
37
- renderItem(entry, expanded) {
61
+ renderItem(entry, expanded, options = {}) {
38
62
  const item = document.createElement("div");
39
63
  item.className = "lv-timeline-item";
40
64
  item.setAttribute("data-id", entry.id);
41
- const isAnomaly = entry.anomaly && entry.anomaly !== "none";
65
+ const isAnomaly = options.showAnomalyBadge !== false && entry.anomaly && entry.anomaly !== "none";
42
66
  const dot = document.createElement("div");
43
67
  dot.className = `lv-timeline-dot${isAnomaly ? " lv-timeline-dot--anomaly" : ""}`;
44
68
  item.appendChild(dot);
@@ -55,9 +79,8 @@ var TimelineRenderer = class {
55
79
  user.textContent = entry.user;
56
80
  header.appendChild(user);
57
81
  const actionTag = document.createElement("span");
58
- actionTag.className = "lv-action-tag";
59
- actionTag.textContent = ACTION_LABELS[entry.action] || entry.action;
60
- actionTag.style.backgroundColor = ACTION_COLORS[entry.action] || "#8c8c8c";
82
+ actionTag.className = `lv-action-tag lv-action-tag--${Object.keys(ACTION_LABELS).includes(entry.action) ? entry.action : "other"}`;
83
+ actionTag.textContent = (options.locale === "en-US" ? ACTION_LABELS_EN[entry.action] : ACTION_LABELS[entry.action]) || entry.action;
61
84
  header.appendChild(actionTag);
62
85
  const moduleBadge = document.createElement("span");
63
86
  moduleBadge.className = "lv-timeline-module";
@@ -69,10 +92,10 @@ var TimelineRenderer = class {
69
92
  ip.textContent = entry.ip;
70
93
  header.appendChild(ip);
71
94
  }
72
- if (isAnomaly) {
95
+ if (options.showAnomalyBadge !== false && isAnomaly) {
73
96
  const badge = document.createElement("span");
74
97
  badge.className = "lv-anomaly-badge";
75
- badge.textContent = ANOMALY_LABELS[entry.anomaly];
98
+ badge.textContent = (options.locale === "en-US" ? ANOMALY_LABELS_EN[entry.anomaly] : ANOMALY_LABELS)[entry.anomaly] || entry.anomaly;
76
99
  header.appendChild(badge);
77
100
  }
78
101
  card.appendChild(header);
@@ -82,9 +105,11 @@ var TimelineRenderer = class {
82
105
  detail.textContent = entry.detail;
83
106
  card.appendChild(detail);
84
107
  }
85
- if (entry.changes && entry.changes.length > 0) {
86
- const hint = document.createElement("div");
108
+ if (options.showDiff !== false && entry.changes && entry.changes.length > 0) {
109
+ const hint = document.createElement("button");
110
+ hint.type = "button";
87
111
  hint.className = "lv-timeline-expand-hint";
112
+ hint.setAttribute("aria-expanded", String(expanded));
88
113
  hint.textContent = expanded ? "[ 收起变更详情 ]" : `[ \u67E5\u770B\u53D8\u66F4\u8BE6\u60C5 (${entry.changes.length} \u4E2A\u5B57\u6BB5) ]`;
89
114
  card.appendChild(hint);
90
115
  }
@@ -97,34 +122,43 @@ var TimelineRenderer = class {
97
122
  renderPagination(page, pageSize, total) {
98
123
  const container = document.createElement("div");
99
124
  container.className = "lv-pagination";
100
- const totalPages = Math.ceil(total / pageSize);
125
+ const safePageSize = Number.isFinite(pageSize) && pageSize > 0 ? Math.floor(pageSize) : 1;
126
+ const safeTotal = Number.isFinite(total) && total > 0 ? Math.floor(total) : 0;
127
+ const safePage = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1;
128
+ const totalPages = Math.ceil(safeTotal / safePageSize);
101
129
  if (totalPages <= 1) return container;
102
130
  const prev = document.createElement("button");
131
+ prev.type = "button";
103
132
  prev.className = "lv-pagination-btn";
104
133
  prev.textContent = "<";
105
- prev.disabled = page <= 1;
106
- prev.setAttribute("data-page", String(page - 1));
134
+ prev.disabled = safePage <= 1;
135
+ prev.setAttribute("aria-label", "Previous page");
136
+ prev.setAttribute("data-page", String(safePage - 1));
107
137
  container.appendChild(prev);
108
138
  const maxVisible = 7;
109
- let startPage = Math.max(1, page - Math.floor(maxVisible / 2));
139
+ let startPage = Math.max(1, safePage - Math.floor(maxVisible / 2));
110
140
  const endPage = Math.min(totalPages, startPage + maxVisible - 1);
111
141
  if (endPage - startPage < maxVisible - 1) startPage = Math.max(1, endPage - maxVisible + 1);
112
142
  for (let i = startPage; i <= endPage; i++) {
113
143
  const btn = document.createElement("button");
114
- btn.className = `lv-pagination-btn${i === page ? " lv-pagination-btn--active" : ""}`;
144
+ btn.type = "button";
145
+ btn.className = `lv-pagination-btn${i === safePage ? " lv-pagination-btn--active" : ""}`;
115
146
  btn.textContent = String(i);
116
147
  btn.setAttribute("data-page", String(i));
148
+ if (i === safePage) btn.setAttribute("aria-current", "page");
117
149
  container.appendChild(btn);
118
150
  }
119
151
  const next = document.createElement("button");
152
+ next.type = "button";
120
153
  next.className = "lv-pagination-btn";
121
154
  next.textContent = ">";
122
- next.disabled = page >= totalPages;
123
- next.setAttribute("data-page", String(page + 1));
155
+ next.disabled = safePage >= totalPages;
156
+ next.setAttribute("aria-label", "Next page");
157
+ next.setAttribute("data-page", String(safePage + 1));
124
158
  container.appendChild(next);
125
159
  const info = document.createElement("span");
126
160
  info.className = "lv-pagination-info";
127
- info.textContent = `\u5171 ${total} \u6761`;
161
+ info.textContent = `\u5171 ${safeTotal} \u6761`;
128
162
  container.appendChild(info);
129
163
  return container;
130
164
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TimelineRenderer.js","names":[],"sources":["../../src/renderers/TimelineRenderer.ts"],"sourcesContent":["/**\n * 时间线渲染器 - 将日志条目渲染为时间线 DOM\n */\n\nimport type { LogEntry, AnomalyType } from '../types'\nimport { ACTION_LABELS, ACTION_COLORS } from '../types'\nimport { formatDate, escapeHtml } from '../utils'\n\nconst ANOMALY_LABELS: Record<AnomalyType, string> = {\n 'off-hours': '非工作时间',\n sensitive: '敏感操作',\n 'high-frequency': '高频操作',\n none: '',\n}\n\n/**\n * TimelineRenderer - Timeline Renderer class\n */\nexport class TimelineRenderer {\n /**\n * 渲染时间线\n */\n render(entries: LogEntry[], expandedIds: Set<string>): HTMLElement {\n const container = document.createElement('div')\n container.className = 'lv-timeline'\n\n if (entries.length === 0) {\n container.innerHTML = `<div class=\"lv-empty\"><div class=\"lv-empty-icon\">--</div><div>暂无日志记录</div></div>`\n container.className = ''\n return container\n }\n\n for (const entry of entries) {\n container.appendChild(this.renderItem(entry, expandedIds.has(entry.id)))\n }\n\n return container\n }\n\n /**\n * 渲染单条时间线条目\n */\n renderItem(entry: LogEntry, expanded: boolean): HTMLElement {\n const item = document.createElement('div')\n item.className = 'lv-timeline-item'\n item.setAttribute('data-id', entry.id)\n\n const isAnomaly = entry.anomaly && entry.anomaly !== 'none'\n\n // Dot\n const dot = document.createElement('div')\n dot.className = `lv-timeline-dot${isAnomaly ? ' lv-timeline-dot--anomaly' : ''}`\n item.appendChild(dot)\n\n // Card\n const card = document.createElement('div')\n card.className = `lv-timeline-card${isAnomaly ? ' lv-timeline-card--anomaly' : ''}`\n\n // Header\n const header = document.createElement('div')\n header.className = 'lv-timeline-header'\n\n const time = document.createElement('span')\n time.className = 'lv-timeline-time'\n time.textContent = formatDate(entry.timestamp)\n header.appendChild(time)\n\n const user = document.createElement('span')\n user.className = 'lv-timeline-user'\n user.textContent = entry.user\n header.appendChild(user)\n\n const actionTag = document.createElement('span')\n actionTag.className = 'lv-action-tag'\n actionTag.textContent = ACTION_LABELS[entry.action] || entry.action\n actionTag.style.backgroundColor = ACTION_COLORS[entry.action] || '#8c8c8c'\n header.appendChild(actionTag)\n\n const moduleBadge = document.createElement('span')\n moduleBadge.className = 'lv-timeline-module'\n moduleBadge.textContent = entry.module\n header.appendChild(moduleBadge)\n\n if (entry.ip) {\n const ip = document.createElement('span')\n ip.className = 'lv-timeline-ip'\n ip.textContent = entry.ip\n header.appendChild(ip)\n }\n\n if (isAnomaly) {\n const badge = document.createElement('span')\n badge.className = 'lv-anomaly-badge'\n badge.textContent = ANOMALY_LABELS[entry.anomaly!]\n header.appendChild(badge)\n }\n\n card.appendChild(header)\n\n // Detail text\n if (entry.detail) {\n const detail = document.createElement('div')\n detail.className = 'lv-timeline-detail'\n detail.textContent = entry.detail\n card.appendChild(detail)\n }\n\n // Expand hint\n if (entry.changes && entry.changes.length > 0) {\n const hint = document.createElement('div')\n hint.className = 'lv-timeline-expand-hint'\n hint.textContent = expanded ? '[ 收起变更详情 ]' : `[ 查看变更详情 (${entry.changes.length} 个字段) ]`\n card.appendChild(hint)\n }\n\n item.appendChild(card)\n\n return item\n }\n\n /**\n * 渲染分页\n */\n renderPagination(page: number, pageSize: number, total: number): HTMLElement {\n const container = document.createElement('div')\n container.className = 'lv-pagination'\n\n const totalPages = Math.ceil(total / pageSize)\n if (totalPages <= 1) return container\n\n // Prev\n const prev = document.createElement('button')\n prev.className = 'lv-pagination-btn'\n prev.textContent = '<'\n prev.disabled = page <= 1\n prev.setAttribute('data-page', String(page - 1))\n container.appendChild(prev)\n\n // Page buttons\n const maxVisible = 7\n let startPage = Math.max(1, page - Math.floor(maxVisible / 2))\n const endPage = Math.min(totalPages, startPage + maxVisible - 1)\n if (endPage - startPage < maxVisible - 1) {\n startPage = Math.max(1, endPage - maxVisible + 1)\n }\n\n for (let i = startPage; i <= endPage; i++) {\n const btn = document.createElement('button')\n btn.className = `lv-pagination-btn${i === page ? ' lv-pagination-btn--active' : ''}`\n btn.textContent = String(i)\n btn.setAttribute('data-page', String(i))\n container.appendChild(btn)\n }\n\n // Next\n const next = document.createElement('button')\n next.className = 'lv-pagination-btn'\n next.textContent = '>'\n next.disabled = page >= totalPages\n next.setAttribute('data-page', String(page + 1))\n container.appendChild(next)\n\n // Info\n const info = document.createElement('span')\n info.className = 'lv-pagination-info'\n info.textContent = `共 ${total} 条`\n container.appendChild(info)\n\n return container\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TimelineRenderer.js","names":[],"sources":["../../src/renderers/TimelineRenderer.ts"],"sourcesContent":["/**\r\n * 时间线渲染器 - 将日志条目渲染为时间线 DOM\r\n */\r\n\r\nimport type { LogEntry, AnomalyType } from '../types'\r\nimport { ACTION_LABELS } from '../types'\r\nimport { formatDate } from '../utils'\r\n\r\nexport interface TimelineRendererOptions {\r\n showDiff?: boolean\r\n showAnomalyBadge?: boolean\r\n locale?: 'zh-CN' | 'en-US'\r\n}\r\n\r\nconst ANOMALY_LABELS: Record<AnomalyType, string> = {\r\n 'off-hours': '非工作时间',\r\n sensitive: '敏感操作',\r\n 'high-frequency': '高频操作',\r\n none: '',\r\n}\r\n\r\nconst ANOMALY_LABELS_EN: Record<AnomalyType, string> = {\r\n 'off-hours': 'Off hours',\r\n sensitive: 'Sensitive',\r\n 'high-frequency': 'High frequency',\r\n none: '',\r\n}\r\n\r\nconst ACTION_LABELS_EN: Record<string, string> = {\r\n create: 'Create',\r\n update: 'Update',\r\n delete: 'Delete',\r\n query: 'Query',\r\n login: 'Login',\r\n logout: 'Logout',\r\n export: 'Export',\r\n import: 'Import',\r\n approve: 'Approve',\r\n reject: 'Reject',\r\n other: 'Other',\r\n}\r\n\r\n/**\r\n * TimelineRenderer - Timeline Renderer class\r\n */\r\nexport class TimelineRenderer {\r\n /**\r\n * 渲染时间线\r\n */\r\n render(\r\n entries: LogEntry[],\r\n expandedIds: Set<string>,\r\n options: TimelineRendererOptions = {}\r\n ): HTMLElement {\r\n const container = document.createElement('div')\r\n container.className = 'lv-timeline'\r\n\r\n if (entries.length === 0) {\r\n const emptyIcon = document.createElement('div')\r\n emptyIcon.className = 'lv-empty-icon'\r\n emptyIcon.textContent = '--'\r\n const emptyText = document.createElement('div')\r\n emptyText.textContent =\r\n options.locale === 'en-US' ? 'No log entries' : '暂无日志记录'\r\n container.append(emptyIcon, emptyText)\r\n container.className = ''\r\n return container\r\n }\r\n\r\n for (const entry of entries) {\r\n container.appendChild(\r\n this.renderItem(entry, expandedIds.has(entry.id), options)\r\n )\r\n }\r\n\r\n return container\r\n }\r\n\r\n /**\r\n * 渲染单条时间线条目\r\n */\r\n renderItem(\r\n entry: LogEntry,\r\n expanded: boolean,\r\n options: TimelineRendererOptions = {}\r\n ): HTMLElement {\r\n const item = document.createElement('div')\r\n item.className = 'lv-timeline-item'\r\n item.setAttribute('data-id', entry.id)\r\n\r\n const isAnomaly =\r\n options.showAnomalyBadge !== false &&\r\n entry.anomaly &&\r\n entry.anomaly !== 'none'\r\n\r\n // Dot\r\n const dot = document.createElement('div')\r\n dot.className = `lv-timeline-dot${isAnomaly ? ' lv-timeline-dot--anomaly' : ''}`\r\n item.appendChild(dot)\r\n\r\n // Card\r\n const card = document.createElement('div')\r\n card.className = `lv-timeline-card${isAnomaly ? ' lv-timeline-card--anomaly' : ''}`\r\n\r\n // Header\r\n const header = document.createElement('div')\r\n header.className = 'lv-timeline-header'\r\n\r\n const time = document.createElement('span')\r\n time.className = 'lv-timeline-time'\r\n time.textContent = formatDate(entry.timestamp)\r\n header.appendChild(time)\r\n\r\n const user = document.createElement('span')\r\n user.className = 'lv-timeline-user'\r\n user.textContent = entry.user\r\n header.appendChild(user)\r\n\r\n const actionTag = document.createElement('span')\r\n const actionKey = Object.keys(ACTION_LABELS).includes(entry.action)\r\n ? entry.action\r\n : 'other'\r\n actionTag.className = `lv-action-tag lv-action-tag--${actionKey}`\r\n actionTag.textContent =\r\n (options.locale === 'en-US'\r\n ? ACTION_LABELS_EN[entry.action]\r\n : ACTION_LABELS[entry.action]) || entry.action\r\n header.appendChild(actionTag)\r\n\r\n const moduleBadge = document.createElement('span')\r\n moduleBadge.className = 'lv-timeline-module'\r\n moduleBadge.textContent = entry.module\r\n header.appendChild(moduleBadge)\r\n\r\n if (entry.ip) {\r\n const ip = document.createElement('span')\r\n ip.className = 'lv-timeline-ip'\r\n ip.textContent = entry.ip\r\n header.appendChild(ip)\r\n }\r\n\r\n if (options.showAnomalyBadge !== false && isAnomaly) {\r\n const badge = document.createElement('span')\r\n badge.className = 'lv-anomaly-badge'\r\n badge.textContent =\r\n (options.locale === 'en-US'\r\n ? ANOMALY_LABELS_EN[entry.anomaly!]\r\n : ANOMALY_LABELS)[entry.anomaly!] || entry.anomaly\r\n header.appendChild(badge)\r\n }\r\n\r\n card.appendChild(header)\r\n\r\n // Detail text\r\n if (entry.detail) {\r\n const detail = document.createElement('div')\r\n detail.className = 'lv-timeline-detail'\r\n detail.textContent = entry.detail\r\n card.appendChild(detail)\r\n }\r\n\r\n // Expand hint\r\n if (\r\n options.showDiff !== false &&\r\n entry.changes &&\r\n entry.changes.length > 0\r\n ) {\r\n const hint = document.createElement('button')\r\n hint.type = 'button'\r\n hint.className = 'lv-timeline-expand-hint'\r\n hint.setAttribute('aria-expanded', String(expanded))\r\n hint.textContent = expanded\r\n ? '[ 收起变更详情 ]'\r\n : `[ 查看变更详情 (${entry.changes.length} 个字段) ]`\r\n card.appendChild(hint)\r\n }\r\n\r\n item.appendChild(card)\r\n\r\n return item\r\n }\r\n\r\n /**\r\n * 渲染分页\r\n */\r\n renderPagination(page: number, pageSize: number, total: number): HTMLElement {\r\n const container = document.createElement('div')\r\n container.className = 'lv-pagination'\r\n\r\n const safePageSize =\r\n Number.isFinite(pageSize) && pageSize > 0 ? Math.floor(pageSize) : 1\r\n const safeTotal =\r\n Number.isFinite(total) && total > 0 ? Math.floor(total) : 0\r\n const safePage = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1\r\n const totalPages = Math.ceil(safeTotal / safePageSize)\r\n if (totalPages <= 1) return container\r\n\r\n // Prev\r\n const prev = document.createElement('button')\r\n prev.type = 'button'\r\n prev.className = 'lv-pagination-btn'\r\n prev.textContent = '<'\r\n prev.disabled = safePage <= 1\r\n prev.setAttribute('aria-label', 'Previous page')\r\n prev.setAttribute('data-page', String(safePage - 1))\r\n container.appendChild(prev)\r\n\r\n // Page buttons\r\n const maxVisible = 7\r\n let startPage = Math.max(1, safePage - Math.floor(maxVisible / 2))\r\n const endPage = Math.min(totalPages, startPage + maxVisible - 1)\r\n if (endPage - startPage < maxVisible - 1) {\r\n startPage = Math.max(1, endPage - maxVisible + 1)\r\n }\r\n\r\n for (let i = startPage; i <= endPage; i++) {\r\n const btn = document.createElement('button')\r\n btn.type = 'button'\r\n btn.className = `lv-pagination-btn${i === safePage ? ' lv-pagination-btn--active' : ''}`\r\n btn.textContent = String(i)\r\n btn.setAttribute('data-page', String(i))\r\n if (i === safePage) btn.setAttribute('aria-current', 'page')\r\n container.appendChild(btn)\r\n }\r\n\r\n // Next\r\n const next = document.createElement('button')\r\n next.type = 'button'\r\n next.className = 'lv-pagination-btn'\r\n next.textContent = '>'\r\n next.disabled = safePage >= totalPages\r\n next.setAttribute('aria-label', 'Next page')\r\n next.setAttribute('data-page', String(safePage + 1))\r\n container.appendChild(next)\r\n\r\n // Info\r\n const info = document.createElement('span')\r\n info.className = 'lv-pagination-info'\r\n info.textContent = `共 ${safeTotal} 条`\r\n container.appendChild(info)\r\n\r\n return container\r\n }\r\n}\r\n"],"mappings":"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"}
@@ -1,9 +1,5 @@
1
1
  /**
2
2
  * 样式注入 - 通过 CSS 变量支持亮色/暗色主题
3
3
  */
4
- /**
5
- * injectStyles - inject Styles function
6
- * @returns 返回值说明
7
- */
4
+ /** injectStyles - inject Styles function. */
8
5
  export declare function injectStyles(): void;
9
- //# sourceMappingURL=index.d.ts.map