@ticatec/uniface-element 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/accordion/README.md +169 -0
  2. package/dist/accordion/README_CN.md +176 -0
  3. package/dist/action-bar/README.md +275 -0
  4. package/dist/action-bar/README_CN.md +285 -0
  5. package/dist/app-layout/README.md +374 -0
  6. package/dist/app-layout/README_CN.md +381 -0
  7. package/dist/app-top-bar/README.md +357 -0
  8. package/dist/app-top-bar/README_CN.md +365 -0
  9. package/dist/attachment-files/AttachmentFilesField.svelte +67 -1
  10. package/dist/attachment-files/AttachmentFilesField.svelte.d.ts +8 -1
  11. package/dist/base-calendar/CalendarBase.svelte +0 -3
  12. package/dist/box/README.md +385 -0
  13. package/dist/box/README_CN.md +393 -0
  14. package/dist/breadcrumbs/README.md +442 -0
  15. package/dist/breadcrumbs/README_CN.md +442 -0
  16. package/dist/button/Button.svelte +27 -7
  17. package/dist/button/Button.svelte.d.ts +3 -1
  18. package/dist/button/IconButton.svelte +26 -6
  19. package/dist/button/IconButton.svelte.d.ts +3 -1
  20. package/dist/button/IconButton_README.md +513 -0
  21. package/dist/button/IconButton_README_CN.md +513 -0
  22. package/dist/button/README.md +428 -0
  23. package/dist/button/README_CN.md +428 -0
  24. package/dist/button/TextButton.svelte +26 -6
  25. package/dist/button/TextButton.svelte.d.ts +3 -1
  26. package/dist/button/TextButton_README.md +571 -0
  27. package/dist/button/TextButton_README_CN.md +571 -0
  28. package/dist/card/README.md +666 -0
  29. package/dist/card/README_CN.md +666 -0
  30. package/dist/cascade-options-select/CascadeOptionSelect.svelte +43 -7
  31. package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +3 -4
  32. package/dist/cascade-options-select/README.md +663 -2
  33. package/dist/cascade-options-select/README_CN.md +664 -0
  34. package/dist/checkbox/CheckBox.svelte +20 -6
  35. package/dist/checkbox/CheckBox.svelte.d.ts +4 -2
  36. package/dist/checkbox/README.md +562 -0
  37. package/dist/checkbox/README_CN.md +727 -0
  38. package/dist/common-editor/NumberInput.svelte +39 -26
  39. package/dist/common-editor/NumberInput.svelte.d.ts +5 -1
  40. package/dist/concise-data-table/ConciseListTable.svelte +133 -36
  41. package/dist/concise-data-table/ConciseListTable.svelte.d.ts +8 -1
  42. package/dist/concise-data-table/DataCell.svelte +5 -6
  43. package/dist/concise-data-table/DataRow.svelte +22 -2
  44. package/dist/concise-data-table/DataRow.svelte.d.ts +1 -0
  45. package/dist/concise-data-table/README.md +606 -0
  46. package/dist/concise-data-table/README_CN.md +611 -0
  47. package/dist/context-menu/ContextMenu.svelte +138 -21
  48. package/dist/context-menu/ContextMenu.svelte.d.ts +5 -0
  49. package/dist/context-menu/ContextMenuItem.d.ts +20 -4
  50. package/dist/context-menu/README.md +551 -0
  51. package/dist/context-menu/README_CN.md +551 -0
  52. package/dist/criteria-field/CriteriaField.svelte +3 -5
  53. package/dist/criteria-field/README.md +532 -0
  54. package/dist/criteria-field/README_CN.md +532 -0
  55. package/dist/data-table/README.md +712 -0
  56. package/dist/data-table/README_CN.md +712 -0
  57. package/dist/date-picker/DatePicker.svelte +44 -7
  58. package/dist/date-picker/DatePicker.svelte.d.ts +3 -4
  59. package/dist/date-picker/DateTimePicker.svelte +32 -8
  60. package/dist/date-picker/DateTimePicker.svelte.d.ts +3 -4
  61. package/dist/date-picker/README.md +326 -0
  62. package/dist/date-picker/README_CN.md +316 -0
  63. package/dist/date-picker/ScrollBar.svelte +18 -8
  64. package/dist/date-picker/ScrollBar.svelte.d.ts +1 -1
  65. package/dist/date-picker/TimePanel.svelte +5 -5
  66. package/dist/date-picker/TimePanel.svelte.d.ts +1 -1
  67. package/dist/date-range/README.md +374 -0
  68. package/dist/date-range/README_CN.md +374 -0
  69. package/dist/dialog/README.md +596 -0
  70. package/dist/dialog/README_CN.md +596 -0
  71. package/dist/drawer/README.md +679 -1
  72. package/dist/drawer/README_CN.md +679 -0
  73. package/dist/group-box/group-check-box/GroupCheckBox.svelte +62 -5
  74. package/dist/group-box/group-check-box/GroupCheckBox.svelte.d.ts +7 -2
  75. package/dist/group-box/group-check-box/README.md +749 -0
  76. package/dist/group-box/group-check-box/README_CN.md +750 -0
  77. package/dist/group-box/group-radio-box/GroupRadioBox.svelte +69 -4
  78. package/dist/group-box/group-radio-box/GroupRadioBox.svelte.d.ts +8 -2
  79. package/dist/group-box/group-radio-box/README.md +920 -0
  80. package/dist/group-box/group-radio-box/README_CN.md +920 -0
  81. package/dist/image-files/README.md +1346 -0
  82. package/dist/image-files/README_CN.md +1346 -0
  83. package/dist/input-options-select/InputOptionsSelect.svelte +161 -65
  84. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +4 -1
  85. package/dist/lib/forwardAllEvents.d.ts +3 -0
  86. package/dist/lib/forwardAllEvents.js +24 -0
  87. package/dist/list-box/README.md +579 -0
  88. package/dist/list-box/README_CN.md +682 -0
  89. package/dist/lookup-editor/LookupEditor.svelte +15 -3
  90. package/dist/lookup-editor/LookupEditor.svelte.d.ts +3 -4
  91. package/dist/lookup-editor/README.md +684 -0
  92. package/dist/lookup-editor/README_CN.md +684 -0
  93. package/dist/memo-editor/MemoEditor.svelte +77 -27
  94. package/dist/memo-editor/MemoEditor.svelte.d.ts +6 -3
  95. package/dist/memo-editor/README.md +819 -0
  96. package/dist/memo-editor/README_CN.md +819 -0
  97. package/dist/message-box/README.md +398 -0
  98. package/dist/message-box/README_CN.md +398 -0
  99. package/dist/number-editor/NumberEditor.svelte +2 -2
  100. package/dist/number-editor/NumberEditor.svelte.d.ts +1 -1
  101. package/dist/number-editor/README.md +353 -22
  102. package/dist/number-editor/README_CN.md +357 -0
  103. package/dist/number-range/README.md +443 -0
  104. package/dist/number-range/README_CN.md +443 -0
  105. package/dist/options-multi-select/OptionsMultiSelect.svelte +87 -12
  106. package/dist/options-multi-select/OptionsMultiSelect.svelte.d.ts +3 -1
  107. package/dist/options-multi-select/README.md +480 -0
  108. package/dist/options-multi-select/README_CN.md +480 -0
  109. package/dist/options-select/OptionsSelect.svelte +36 -5
  110. package/dist/options-select/OptionsSelect.svelte.d.ts +3 -4
  111. package/dist/options-select/README.md +632 -0
  112. package/dist/options-select/README_CN.md +632 -0
  113. package/dist/page/README.md +605 -0
  114. package/dist/page/README_CN.md +605 -0
  115. package/dist/pagination/README.md +946 -0
  116. package/dist/pagination/README_CN.md +946 -0
  117. package/dist/pagination-panel/README.md +1075 -0
  118. package/dist/pagination-panel/README_CN.md +1075 -0
  119. package/dist/popup-hint/README.md +841 -0
  120. package/dist/popup-hint/README_CN.md +840 -0
  121. package/dist/progress-bar/README.md +242 -0
  122. package/dist/progress-bar/README_CN.md +242 -0
  123. package/dist/progress-step-bar/README.md +316 -0
  124. package/dist/progress-step-bar/README_CN.md +316 -0
  125. package/dist/prompts-text-editor/PromptsTextEditor.svelte +6 -3
  126. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +3 -1
  127. package/dist/prompts-text-editor/README.md +329 -0
  128. package/dist/prompts-text-editor/README_CN.md +329 -0
  129. package/dist/property-editor/README.md +969 -0
  130. package/dist/property-editor/README_CN.md +969 -0
  131. package/dist/radio-button/README.md +372 -0
  132. package/dist/radio-button/README_CN.md +372 -0
  133. package/dist/radio-button/RadioButton.svelte +32 -3
  134. package/dist/radio-button/RadioButton.svelte.d.ts +12 -1
  135. package/dist/search-box/README.md +425 -0
  136. package/dist/search-box/README_CN.md +424 -0
  137. package/dist/search-box/SearchBox.svelte +22 -6
  138. package/dist/search-box/SearchBox.svelte.d.ts +4 -1
  139. package/dist/tabs/README.md +919 -0
  140. package/dist/tabs/README_CN.md +920 -0
  141. package/dist/tag/README.md +922 -0
  142. package/dist/tag/README_CN.md +922 -0
  143. package/dist/text-editor/PasswordEditor.svelte +17 -2
  144. package/dist/text-editor/PasswordEditor.svelte.d.ts +3 -3
  145. package/dist/text-editor/PasswordEditor_README.md +551 -0
  146. package/dist/text-editor/PasswordEditor_README_CN.md +551 -0
  147. package/dist/text-editor/README.md +466 -0
  148. package/dist/text-editor/README_CN.md +466 -0
  149. package/dist/text-editor/TextEditor.svelte +51 -19
  150. package/dist/text-editor/TextEditor.svelte.d.ts +0 -1
  151. package/dist/time-editor/README.md +498 -24
  152. package/dist/time-editor/README_CN.md +498 -0
  153. package/dist/time-editor/TimeEditor.svelte +7 -3
  154. package/dist/time-editor/TimeEditor.svelte.d.ts +3 -1
  155. package/dist/toast/README.md +667 -0
  156. package/dist/toast/README_CN.md +667 -0
  157. package/dist/transfer/README.md +795 -0
  158. package/dist/transfer/Transfer.svelte +6 -4
  159. package/dist/transfer/Transfer.svelte.d.ts +3 -1
  160. package/dist/tree-view/README.md +761 -0
  161. package/dist/tree-view/README_CN.md +761 -0
  162. package/dist/tree-view/TreeView.svelte +5 -3
  163. package/dist/tree-view/TreeView.svelte.d.ts +3 -1
  164. package/dist/unit-number-editor/README.md +546 -20
  165. package/dist/unit-number-editor/README_CN.md +525 -0
  166. package/dist/unit-number-editor/UnitNumberEditor.svelte +62 -8
  167. package/dist/unit-number-editor/UnitNumberEditor.svelte.d.ts +5 -1
  168. package/docs/form-field/cn/README_CN.md +364 -0
  169. package/docs/form-field/en/README.md +364 -0
  170. package/docs/form-panel/flex-form/cn/README_CN.md +586 -0
  171. package/docs/form-panel/flex-form/en/README.md +586 -0
  172. package/docs/form-panel/flex-row-form/cn/README_CN.md +787 -0
  173. package/docs/form-panel/flex-row-form/en/README.md +787 -0
  174. package/docs/form-panel/grid-form/en/README.md +744 -0
  175. package/package.json +1 -1
  176. package/dist/drawer/README-CN.md +0 -1
@@ -13,33 +13,50 @@
13
13
  export let allowNegative: boolean = false;
14
14
  export let max: number | null = null;
15
15
  export let min: number | null = null;
16
- export let onChange: OnChangeHandler<number | null> = null as unknown as OnChangeHandler<number | null>;
16
+ export let onchange: OnChangeHandler<number | null> = null as unknown as OnChangeHandler<number | null>;
17
+ export let onfocus: (() => void) | null = null;
18
+ export let onblur: (() => void) | null = null;
17
19
  export let textValue: string = '';
20
+
18
21
  export const focus = () => {
19
22
  editor.focus();
20
23
  }
24
+
25
+ export const setFocus = () => {
26
+ setTimeout(() => {
27
+ editor && editor.focus();
28
+ }, 50);
29
+ }
21
30
 
22
31
  let regex: RegExp;
32
+ let editor: HTMLInputElement;
33
+ let composing: boolean = false;
34
+ let currentText: string;
35
+ let isFocused = false;
23
36
 
24
- let editor: any;
37
+ const handleFocusEvent = (e: FocusEvent) => {
38
+ isFocused = true;
39
+ onfocus?.();
40
+ }
25
41
 
26
42
  const handleBlurEvent = (e: FocusEvent) => {
27
43
  isFocused = false;
44
+ onblur?.();
28
45
  if (!readonly) {
29
46
  value = parseFloat(textValue);
30
47
  if (isNaN(value)) {
31
48
  value = null;
32
49
  }
33
50
  if (value != null) {
34
- if (min != null && value != null && value < min) {
51
+ if (min != null && value < min) {
35
52
  value = min;
36
53
  }
37
- if (max != null && value != null && value > max) {
54
+ if (max != null && value > max) {
38
55
  value = max;
39
56
  }
40
57
  textValue = utils.formatNumber(value, precision);
41
58
  }
42
- onChange?.(value);
59
+ onchange?.(value);
43
60
  } else {
44
61
  e.stopPropagation();
45
62
  }
@@ -47,21 +64,17 @@
47
64
 
48
65
  const checkNewInputText = (s: string): boolean => {
49
66
  const currentValue = editor.value;
50
- const cursorStart = editor.selectionStart; // 光标起始位置
51
- const cursorEnd = editor.selectionEnd; // 光标结束位置
67
+ const cursorStart = editor.selectionStart; // cursor start position
68
+ const cursorEnd = editor.selectionEnd; // cursor end position
52
69
  let resultingString = currentValue.slice(0, cursorStart) + s + currentValue.slice(cursorEnd);
53
- if (/[^0-9.\-]/.test(resultingString)) {
70
+ if (/[^0-9\.\-]/.test(resultingString)) {
54
71
  return false;
55
72
  } else {
56
- return regex.test(resultingString) && utils.isValidNumber(parseFloat(resultingString), precision, allowNegative, max, min);
73
+ return regex.test(resultingString) &&
74
+ utils.isValidNumber(parseFloat(resultingString), precision, allowNegative, max, min);
57
75
  }
58
76
  }
59
77
 
60
-
61
- let composing: boolean = false;
62
- let currentText: string;
63
- let isFocused = false;
64
-
65
78
  const handlePaste = (event: ClipboardEvent) => {
66
79
  const pasteData = event.clipboardData?.getData('text') || '';
67
80
  if (!checkNewInputText(pasteData)) {
@@ -70,32 +83,32 @@
70
83
  }
71
84
 
72
85
  const handleKeyDown = (event: KeyboardEvent) => {
73
- // 检查是否是全角字符或中文等(非 ASCII
86
+ // Check for full-width characters or non-ASCII characters
74
87
  if (/[^\x00-\x7F]/.test(event.key)) {
75
88
  event.preventDefault();
76
89
  event.stopPropagation();
77
90
  return;
78
91
  }
79
92
 
80
- // 保留 ctrl 等特殊键
93
+ // Allow special keys like ctrl
81
94
  const allowKeys = ['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
82
95
  if (allowKeys.includes(event.key)) return;
83
96
 
84
- // 如果是数字或小数点、负号等,可允许(你可根据 precision 精度自定义更严格规则)
97
+ // Allow numbers, decimal points, negative signs (can customize based on precision)
85
98
  if (/[\d\.\-]/.test(event.key)) return;
86
99
 
87
- // 拦截其他非法字符
100
+ // Block other invalid characters
88
101
  event.preventDefault();
89
102
  event.stopPropagation();
90
103
  };
91
104
  const handleInput = () => {
92
- if (composing) return; // 正在输入拼音等,忽略
105
+ if (composing) return; // Ignore during composition (e.g., pinyin input)
93
106
 
94
- // 校验是否为合法数字字符串
107
+ // Validate if it's a valid number string
95
108
  const raw = editor.value;
96
109
  if (/[^\x00-\x7F]/.test(raw)) {
97
- // 包含中文、日文、韩文、全角字符、表情等
98
- editor.value = textValue; // 恢复输入前状态
110
+ // Contains Chinese, Japanese, Korean, full-width characters, emojis, etc.
111
+ editor.value = textValue; // Restore previous state
99
112
  return;
100
113
  }
101
114
  if (regex.test(raw)) {
@@ -105,7 +118,7 @@
105
118
  }
106
119
  }
107
120
 
108
- // 不合法时可以不更新 value,只更新 textValue(允许用户继续输)
121
+ // When invalid, don't update value, only update textValue (allow user to continue typing)
109
122
  textValue = raw;
110
123
  }
111
124
 
@@ -118,10 +131,10 @@
118
131
  const handleCompositionEnd = (event: CompositionEvent) => {
119
132
  composing = false;
120
133
  if (/[^\x00-\x7F]/.test(editor.value)) {
121
- editor.value = currentText; // 恢复输入前内容
134
+ editor.value = currentText; // Restore previous content
122
135
  textValue = currentText;
123
136
  } else {
124
- handleInput(); // 正常输入
137
+ handleInput(); // Normal input
125
138
  }
126
139
  };
127
140
 
@@ -135,7 +148,7 @@
135
148
  </script>
136
149
  <input class="number-editor" bind:this={editor} type="text" {readonly} {style} {disabled} placeholder={readonly || disabled ? '' : placeholder}
137
150
  bind:value={textValue}
138
- on:focus={() => isFocused = true}
151
+ on:focus={handleFocusEvent}
139
152
  on:blur={handleBlurEvent}
140
153
  on:compositionstart={handleCompositionStart}
141
154
  on:input={handleInput}
@@ -22,13 +22,17 @@ declare const NumberInput: $$__sveltets_2_IsomorphicComponent<{
22
22
  allowNegative?: boolean;
23
23
  max?: number | null;
24
24
  min?: number | null;
25
- onChange?: OnChangeHandler<number | null>;
25
+ onchange?: OnChangeHandler<number | null>;
26
+ onfocus?: (() => void) | null;
27
+ onblur?: (() => void) | null;
26
28
  textValue?: string;
27
29
  focus?: () => void;
30
+ setFocus?: () => void;
28
31
  }, {
29
32
  [evt: string]: CustomEvent<any>;
30
33
  }, {}, {
31
34
  focus: () => void;
35
+ setFocus: () => void;
32
36
  }, string>;
33
37
  type NumberInput = InstanceType<typeof NumberInput>;
34
38
  export default NumberInput;
@@ -15,11 +15,15 @@
15
15
  // Milliseconds between each scroll step
16
16
  export let scrollInterval: number = 2000;
17
17
  export let rowClickHandler: RowClickHandler | null = null;
18
- //行高
19
-
20
- // Height of the component in pixels
21
- //table background color
18
+ // Table styling and behavior options
22
19
  export let options: TableOptions;
20
+ // Custom CSS styles for the table container
21
+ export let style: string = '';
22
+ // Additional CSS classes
23
+ export let className: string = '';
24
+ // Focus/blur event handlers
25
+ export let onfocus: ((event: FocusEvent) => void) | null = null;
26
+ export let onblur: ((event: FocusEvent) => void) | null = null;
23
27
 
24
28
  let tabOptions: TableOptions;
25
29
 
@@ -66,7 +70,11 @@
66
70
  rowHeight = tableBody.children[0].offsetHeight;
67
71
  visibleRowCount = Math.floor((tableContainer.offsetHeight - headerRow.offsetHeight) / rowHeight);
68
72
  if (list.length <= visibleRowCount) return;
69
- clonedRows = [...list];
73
+
74
+ // 为无缝滚动准备足够的克隆数据
75
+ const duplicateCount = Math.ceil(visibleRowCount / list.length) + 1;
76
+ clonedRows = Array(duplicateCount).fill(list).flat();
77
+
70
78
  startAutoScroll();
71
79
  }
72
80
  }
@@ -76,27 +84,40 @@
76
84
  // Clear any existing timer
77
85
  if (scrollTimer) clearInterval(scrollTimer);
78
86
 
79
- currentScrollIndex = 0;
80
-
81
- scrollTimer = setInterval(() => {
82
- currentScrollIndex++;
83
- const tableBody = tableContainer.querySelector('.table-body');
84
- if (tableBody) {
85
- tableBody.style.transform = `translateY(-${currentScrollIndex * rowHeight}px)`;
86
- if (currentScrollIndex >= list.length) {
87
- setTimeout(() => {
88
- tableBody.style.transition = 'none';
89
- tableBody.style.transform = `translateY(0)`;
90
- currentScrollIndex = 0;
91
-
92
- // 恢复过渡效果
93
- setTimeout(() => {
94
- tableBody.style.transition = 'transform 2s ease';
95
- }, 50);
96
- }, 50);
97
- }
87
+ const originalDataHeight = list.length * rowHeight;
88
+
89
+ // 使用连续动画,通过动态创建style元素实现真正的无缝循环
90
+ const tableBody = tableContainer.querySelector('.table-body');
91
+ if (tableBody) {
92
+ // 创建CSS动画
93
+ const animationDuration = scrollInterval * list.length / 1000; // 总动画时长(秒)
94
+
95
+ // 移除之前的动画
96
+ tableBody.style.animation = 'none';
97
+
98
+ // 删除之前的style元素(如果存在)
99
+ const existingStyle = document.getElementById(`marqueeStyle_${id}`);
100
+ if (existingStyle) {
101
+ existingStyle.remove();
98
102
  }
99
- }, scrollInterval);
103
+
104
+ // 创建新的style元素
105
+ const styleElement = document.createElement('style');
106
+ styleElement.id = `marqueeStyle_${id}`;
107
+ styleElement.textContent = `
108
+ @keyframes marqueeScroll_${id} {
109
+ 0% { transform: translateY(0px); }
110
+ 100% { transform: translateY(-${originalDataHeight}px); }
111
+ }
112
+ `;
113
+ document.head.appendChild(styleElement);
114
+
115
+ // 强制浏览器重新计算样式
116
+ tableBody.offsetHeight;
117
+
118
+ // 应用新的动画
119
+ tableBody.style.animation = `marqueeScroll_${id} ${animationDuration}s linear infinite`;
120
+ }
100
121
  }
101
122
 
102
123
  const stopAutoScroll = () => {
@@ -104,6 +125,13 @@
104
125
  clearInterval(scrollTimer);
105
126
  scrollTimer = null;
106
127
  }
128
+
129
+ // 停止CSS动画
130
+ const tableBody = tableContainer?.querySelector('.table-body');
131
+ if (tableBody) {
132
+ tableBody.style.animation = 'none';
133
+ tableBody.style.transform = 'translateY(0px)';
134
+ }
107
135
  }
108
136
 
109
137
  onMount(async () => {
@@ -112,6 +140,11 @@
112
140
 
113
141
  onDestroy(() => {
114
142
  stopAutoScroll();
143
+ // 清理动态创建的style元素
144
+ const existingStyle = document.getElementById(`marqueeStyle_${id}`);
145
+ if (existingStyle) {
146
+ existingStyle.remove();
147
+ }
115
148
  });
116
149
 
117
150
  $: if (list || autoScroll || scrollInterval) {
@@ -125,17 +158,39 @@
125
158
  rowClickHandler?.(row)
126
159
  }
127
160
 
161
+ const handleTableFocus = (event: FocusEvent) => {
162
+ onfocus?.(event);
163
+ }
164
+
165
+ const handleTableBlur = (event: FocusEvent) => {
166
+ onblur?.(event);
167
+ }
168
+
169
+ export const setFocus = () => {
170
+ const firstRow = tableContainer?.querySelector('.table-body .table-row');
171
+ if (firstRow) {
172
+ setTimeout(() => {
173
+ (firstRow as HTMLElement).focus();
174
+ }, 50);
175
+ }
176
+ }
128
177
 
129
178
  </script>
130
179
 
131
- <div id="tab_{id}" class="uniface-concise-datatable">
180
+ <div
181
+ id="tab_{id}"
182
+ class="uniface-concise-datatable {className}"
183
+ {style}
184
+ on:focusin={handleTableFocus}
185
+ on:focusout={handleTableBlur}
186
+ >
132
187
  {@html tableStyle}
133
188
  <div class="table-container" bind:this={tableContainer}>
134
189
  <!-- Fixed header -->
135
190
  <div class="table-header">
136
- <div class="table-row" bind:this={headerRow}>
191
+ <div class="table-row" bind:this={headerRow} role="row">
137
192
  {#each columns as column, idx}
138
- <div class="data-cell col_{idx}">
193
+ <div class="data-cell col_{idx}" role="columnheader">
139
194
  {column.title ?? ''}
140
195
  </div>
141
196
  {/each}
@@ -143,14 +198,56 @@
143
198
  </div>
144
199
 
145
200
  <!-- Scrollable body -->
146
- <div class="table-body-container" bind:this={viewPanel} class:auto-scroll={autoScroll}>
147
- <div class="table-body" style="transition: transform {autoScroll ? '2s' : '0s'} ease;">
148
- {#each list as row, rowIndex}
149
- <DataRow data={row} {columns} showAlternative={rowIndex % 2 == 1} on:click={handleRowClick(row)}/>
150
- {/each}
151
- {#if autoScroll && list.length > visibleRowCount}
152
- {#each list.slice(0, visibleRowCount) as row, rowIndex}
153
- <DataRow data={row} {columns} showAlternative={rowIndex % 2 == 1} on:click={handleRowClick(row)}/>
201
+ <div
202
+ class="table-body-container"
203
+ bind:this={viewPanel}
204
+ class:auto-scroll={autoScroll}
205
+ role="table"
206
+ aria-label="Data table"
207
+ aria-rowcount={list.length + 1}
208
+ >
209
+ <div class="table-body">
210
+ {#if autoScroll}
211
+ <!-- 无缝滚动模式:渲染原始数据 + 足够的重复数据确保无缝滚动 -->
212
+ {#each list as row, rowIndex}
213
+ <DataRow
214
+ data={row}
215
+ {columns}
216
+ {rowIndex}
217
+ showAlternative={rowIndex % 2 == 1}
218
+ on:click={handleRowClick(row)}
219
+ />
220
+ {/each}
221
+ <!-- 渲染第二份数据,确保无缝滚动 -->
222
+ {#each list as row, rowIndex}
223
+ <DataRow
224
+ data={row}
225
+ {columns}
226
+ rowIndex={rowIndex + list.length}
227
+ showAlternative={(rowIndex + list.length) % 2 == 1}
228
+ on:click={handleRowClick(row)}
229
+ />
230
+ {/each}
231
+ <!-- 渲染第三份数据,确保视窗始终有足够内容 -->
232
+ {#each list as row, rowIndex}
233
+ <DataRow
234
+ data={row}
235
+ {columns}
236
+ rowIndex={rowIndex + list.length * 2}
237
+ showAlternative={(rowIndex + list.length * 2) % 2 == 1}
238
+ on:click={handleRowClick(row)}
239
+ />
240
+ {/each}
241
+ {:else}
242
+ <!-- 正常模式:只渲染原始数据 -->
243
+ {#each list as row, rowIndex}
244
+ <DataRow
245
+ data={row}
246
+ {columns}
247
+ {rowIndex}
248
+ showAlternative={rowIndex % 2 == 1}
249
+ on:click={handleRowClick(row)}
250
+ />
154
251
  {/each}
155
252
  {/if}
156
253
  </div>
@@ -20,8 +20,15 @@ declare const ConciseListTable: $$__sveltets_2_IsomorphicComponent<{
20
20
  scrollInterval?: number;
21
21
  rowClickHandler?: RowClickHandler | null;
22
22
  options: TableOptions;
23
+ style?: string;
24
+ className?: string;
25
+ onfocus?: ((event: FocusEvent) => void) | null;
26
+ onblur?: ((event: FocusEvent) => void) | null;
27
+ setFocus?: () => void;
23
28
  }, {
24
29
  [evt: string]: CustomEvent<any>;
25
- }, {}, {}, string>;
30
+ }, {}, {
31
+ setFocus: () => void;
32
+ }, string>;
26
33
  type ConciseListTable = InstanceType<typeof ConciseListTable>;
27
34
  export default ConciseListTable;
@@ -3,20 +3,19 @@
3
3
 
4
4
  export let column: Column;
5
5
  export let idx: number;
6
-
7
6
  export let data: any;
8
7
 
9
8
  let text: string;
10
9
  let escapeHTML: boolean = false;
11
10
 
12
- $: text = column.formatter ? column.formatter(data[column.field]) : data[column.field];
13
-
11
+ $: text = column.formatter ? column.formatter(data[column.field]) : (data[column.field] ?? '');
12
+ $: escapeHTML = column.escapeHTML ?? false;
14
13
  </script>
15
14
 
16
- <div class="data-cell col_{idx}">
15
+ <div class="data-cell col_{idx}" role="cell">
17
16
  {#if escapeHTML}
18
- {@html text}
19
- {:else }
20
17
  <span>{text}</span>
18
+ {:else }
19
+ {@html text}
21
20
  {/if}
22
21
  </div>
@@ -4,11 +4,31 @@
4
4
 
5
5
  export let columns: Array<Column>;
6
6
  export let data: any;
7
-
8
7
  export let showAlternative: boolean;
8
+ export let rowIndex: number = 0;
9
+
10
+ const handleRowKeyDown = (event: KeyboardEvent) => {
11
+ if (event.key === 'Enter' || event.key === ' ') {
12
+ event.preventDefault();
13
+ // Trigger click event for keyboard users
14
+ const clickEvent = new MouseEvent('click', {
15
+ bubbles: true,
16
+ cancelable: true
17
+ });
18
+ event.currentTarget?.dispatchEvent(clickEvent);
19
+ }
20
+ };
9
21
  </script>
10
22
 
11
- <div class="table-row" class:alternative={showAlternative} aria-hidden="true" on:click>
23
+ <div
24
+ class="table-row"
25
+ class:alternative={showAlternative}
26
+ role="row"
27
+ tabindex="0"
28
+ aria-rowindex={rowIndex + 2}
29
+ on:click
30
+ on:keydown={handleRowKeyDown}
31
+ >
12
32
  {#each columns as column, idx}
13
33
  <DataCell {idx} {column} {data}/>
14
34
  {/each}
@@ -16,6 +16,7 @@ declare const DataRow: $$__sveltets_2_IsomorphicComponent<{
16
16
  columns: Array<Column>;
17
17
  data: any;
18
18
  showAlternative: boolean;
19
+ rowIndex?: number;
19
20
  }, {
20
21
  click: MouseEvent;
21
22
  } & {