stk-table-vue 0.8.13 → 0.9.0-beta.1

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 (38) hide show
  1. package/README.md +172 -180
  2. package/lib/src/StkTable/StkTable.vue.d.ts +22 -2
  3. package/lib/src/StkTable/useScrollbar.d.ts +57 -0
  4. package/lib/src/StkTable/utils/index.d.ts +10 -0
  5. package/lib/stk-table-vue.js +563 -294
  6. package/lib/style.css +49 -2
  7. package/package.json +74 -72
  8. package/src/StkTable/StkTable.vue +1730 -1653
  9. package/src/StkTable/components/DragHandle.vue +9 -9
  10. package/src/StkTable/components/SortIcon.vue +6 -6
  11. package/src/StkTable/components/TriangleIcon.vue +3 -3
  12. package/src/StkTable/const.ts +50 -50
  13. package/src/StkTable/index.ts +4 -4
  14. package/src/StkTable/style.less +627 -580
  15. package/src/StkTable/types/highlightDimOptions.ts +26 -26
  16. package/src/StkTable/types/index.ts +297 -297
  17. package/src/StkTable/useAutoResize.ts +91 -91
  18. package/src/StkTable/useColResize.ts +216 -216
  19. package/src/StkTable/useFixedCol.ts +150 -148
  20. package/src/StkTable/useFixedStyle.ts +75 -75
  21. package/src/StkTable/useGetFixedColPosition.ts +65 -65
  22. package/src/StkTable/useHighlight.ts +257 -257
  23. package/src/StkTable/useKeyboardArrowScroll.ts +112 -112
  24. package/src/StkTable/useMaxRowSpan.ts +55 -55
  25. package/src/StkTable/useMergeCells.ts +120 -123
  26. package/src/StkTable/useRowExpand.ts +88 -88
  27. package/src/StkTable/useScrollRowByRow.ts +114 -79
  28. package/src/StkTable/useScrollbar.ts +187 -0
  29. package/src/StkTable/useThDrag.ts +102 -102
  30. package/src/StkTable/useTrDrag.ts +113 -118
  31. package/src/StkTable/useTree.ts +161 -161
  32. package/src/StkTable/useVirtualScroll.ts +494 -494
  33. package/src/StkTable/utils/constRefUtils.ts +29 -29
  34. package/src/StkTable/utils/index.ts +287 -242
  35. package/src/StkTable/utils/useTriggerRef.ts +33 -33
  36. package/src/VirtualTree.vue +622 -622
  37. package/src/VirtualTreeSelect.vue +367 -367
  38. package/src/vite-env.d.ts +10 -10
@@ -1,88 +1,88 @@
1
- import { ShallowRef } from 'vue';
2
- import { EXPANDED_ROW_KEY_PREFIX } from './const';
3
- import { PrivateRowDT, RowKeyGen, StkTableColumn, UniqKey } from './types';
4
- type DT = PrivateRowDT;
5
- type Option<DT extends Record<string, any>> = {
6
- rowKeyGen: RowKeyGen;
7
- dataSourceCopy: ShallowRef<DT[]>;
8
- emits: any;
9
- };
10
-
11
- export function useRowExpand({ dataSourceCopy, rowKeyGen, emits }: Option<DT>) {
12
- const expandedKey = '__EXP__';
13
-
14
- function isExpanded(row: DT, col?: StkTableColumn<DT>) {
15
- return row?.[expandedKey] === col ? !row?.[expandedKey] : true;
16
- }
17
- /** click expended icon to toggle expand row */
18
- function toggleExpandRow(row: DT, col: StkTableColumn<DT>) {
19
- const isExpand = isExpanded(row, col);
20
- setRowExpand(row, isExpand, { col });
21
- }
22
-
23
- /**
24
- *
25
- * @param rowKeyOrRow rowKey or row
26
- * @param expand expand or collapse, if set null, toggle expand
27
- * @param data { col?: StkTableColumn<DT> }
28
- * @param data.silent if set true, not emit `toggle-row-expand`, default:false
29
- */
30
- function setRowExpand(rowKeyOrRow: string | undefined | DT, expand?: boolean | null, data?: { col?: StkTableColumn<DT>; silent?: boolean }) {
31
- let rowKey: UniqKey;
32
- if (typeof rowKeyOrRow === 'string') {
33
- rowKey = rowKeyOrRow;
34
- } else {
35
- rowKey = rowKeyGen(rowKeyOrRow);
36
- }
37
-
38
- const tempData = dataSourceCopy.value.slice();
39
- const index = tempData.findIndex(it => rowKeyGen(it) === rowKey);
40
- if (index === -1) {
41
- console.warn('expandRow failed.rowKey:', rowKey);
42
- return;
43
- }
44
-
45
- // delete other expanded row below the target row
46
- for (let i = index + 1; i < tempData.length; i++) {
47
- const item: PrivateRowDT = tempData[i];
48
- const rowKey = item.__ROW_K__;
49
- if (rowKey?.startsWith(EXPANDED_ROW_KEY_PREFIX)) {
50
- tempData.splice(i, 1);
51
- i--;
52
- } else {
53
- break;
54
- }
55
- }
56
-
57
- const row = tempData[index];
58
- const col = data?.col;
59
-
60
- if (expand == null) {
61
- expand = isExpanded(row, col);
62
- }
63
-
64
- if (expand) {
65
- // insert new expanded row
66
- const newExpandRow: PrivateRowDT = {
67
- __ROW_K__: EXPANDED_ROW_KEY_PREFIX + rowKey,
68
- __EXP_R__: row,
69
- __EXP_C__: col,
70
- };
71
- tempData.splice(index + 1, 0, newExpandRow);
72
- }
73
-
74
- if (row) {
75
- row[expandedKey] = expand ? col : void 0;
76
- }
77
-
78
- dataSourceCopy.value = tempData;
79
- if (!data?.silent) {
80
- emits('toggle-row-expand', { expanded: Boolean(expand), row, col });
81
- }
82
- }
83
-
84
- return {
85
- toggleExpandRow,
86
- setRowExpand,
87
- };
88
- }
1
+ import { ShallowRef } from 'vue';
2
+ import { EXPANDED_ROW_KEY_PREFIX } from './const';
3
+ import { PrivateRowDT, RowKeyGen, StkTableColumn, UniqKey } from './types';
4
+ type DT = PrivateRowDT;
5
+ type Option<DT extends Record<string, any>> = {
6
+ rowKeyGen: RowKeyGen;
7
+ dataSourceCopy: ShallowRef<DT[]>;
8
+ emits: any;
9
+ };
10
+
11
+ export function useRowExpand({ dataSourceCopy, rowKeyGen, emits }: Option<DT>) {
12
+ const expandedKey = '__EXP__';
13
+
14
+ function isExpanded(row: DT, col?: StkTableColumn<DT>) {
15
+ return row?.[expandedKey] === col ? !row?.[expandedKey] : true;
16
+ }
17
+ /** click expended icon to toggle expand row */
18
+ function toggleExpandRow(row: DT, col: StkTableColumn<DT>) {
19
+ const isExpand = isExpanded(row, col);
20
+ setRowExpand(row, isExpand, { col });
21
+ }
22
+
23
+ /**
24
+ *
25
+ * @param rowKeyOrRow rowKey or row
26
+ * @param expand expand or collapse, if set null, toggle expand
27
+ * @param data { col?: StkTableColumn<DT> }
28
+ * @param data.silent if set true, not emit `toggle-row-expand`, default:false
29
+ */
30
+ function setRowExpand(rowKeyOrRow: string | undefined | DT, expand?: boolean | null, data?: { col?: StkTableColumn<DT>; silent?: boolean }) {
31
+ let rowKey: UniqKey;
32
+ if (typeof rowKeyOrRow === 'string') {
33
+ rowKey = rowKeyOrRow;
34
+ } else {
35
+ rowKey = rowKeyGen(rowKeyOrRow);
36
+ }
37
+
38
+ const tempData = dataSourceCopy.value.slice();
39
+ const index = tempData.findIndex(it => rowKeyGen(it) === rowKey);
40
+ if (index === -1) {
41
+ console.warn('expandRow failed.rowKey:', rowKey);
42
+ return;
43
+ }
44
+
45
+ // delete other expanded row below the target row
46
+ for (let i = index + 1; i < tempData.length; i++) {
47
+ const item: PrivateRowDT = tempData[i];
48
+ const rowKey = item.__ROW_K__;
49
+ if (rowKey?.startsWith(EXPANDED_ROW_KEY_PREFIX)) {
50
+ tempData.splice(i, 1);
51
+ i--;
52
+ } else {
53
+ break;
54
+ }
55
+ }
56
+
57
+ const row = tempData[index];
58
+ const col = data?.col;
59
+
60
+ if (expand == null) {
61
+ expand = isExpanded(row, col);
62
+ }
63
+
64
+ if (expand) {
65
+ // insert new expanded row
66
+ const newExpandRow: PrivateRowDT = {
67
+ __ROW_K__: EXPANDED_ROW_KEY_PREFIX + rowKey,
68
+ __EXP_R__: row,
69
+ __EXP_C__: col,
70
+ };
71
+ tempData.splice(index + 1, 0, newExpandRow);
72
+ }
73
+
74
+ if (row) {
75
+ row[expandedKey] = expand ? col : void 0;
76
+ }
77
+
78
+ dataSourceCopy.value = tempData;
79
+ if (!data?.silent) {
80
+ emits('toggle-row-expand', { expanded: Boolean(expand), row, col });
81
+ }
82
+ }
83
+
84
+ return {
85
+ toggleExpandRow,
86
+ setRowExpand,
87
+ };
88
+ }
@@ -1,79 +1,114 @@
1
- import { computed, Ref, ref, onMounted, onUnmounted, watch } from 'vue';
2
-
3
- type Params = {
4
- props: any;
5
- tableContainerRef: Ref<HTMLElement | undefined>;
6
- };
7
-
8
- export function useScrollRowByRow({ props, tableContainerRef }: Params) {
9
- let isMouseDown = false;
10
- let isAddListeners = false;
11
- /** record the last scroll bar position */
12
- let lastScrollTop = 0;
13
-
14
- /** record is the scroll bar is dragging */
15
- const isDragScroll = ref(false);
16
- const onlyDragScroll = computed(() => props.scrollRowByRow === 'scrollbar');
17
-
18
- /** is ScrollRowByRow active */
19
- const isSRBRActive = computed(() => {
20
- if (onlyDragScroll.value) {
21
- return isDragScroll.value;
22
- }
23
- return props.scrollRowByRow;
24
- });
25
-
26
- watch(onlyDragScroll, v => {
27
- if (v) {
28
- addEventListener();
29
- } else {
30
- removeEventListener();
31
- }
32
- });
33
-
34
- onMounted(() => {
35
- addEventListener();
36
- });
37
-
38
- onUnmounted(() => {
39
- removeEventListener();
40
- });
41
-
42
- function addEventListener() {
43
- if (isAddListeners || !onlyDragScroll.value) return;
44
- const container = tableContainerRef.value;
45
- if (!container) return;
46
- container.addEventListener('mousedown', handleMouseDown);
47
- container.addEventListener('mouseup', handleMouseUp);
48
- container.addEventListener('scroll', handleScroll);
49
- isAddListeners = true;
50
- }
51
-
52
- function removeEventListener() {
53
- const container = tableContainerRef.value;
54
- if (!container) return;
55
- container.removeEventListener('mousedown', handleMouseDown);
56
- container.removeEventListener('mouseup', handleMouseUp);
57
- container.removeEventListener('scroll', handleScroll);
58
- isAddListeners = false;
59
- }
60
-
61
- function handleMouseDown(e: Event) {
62
- isMouseDown = true;
63
- lastScrollTop = (e.target as HTMLElement).scrollTop;
64
- }
65
-
66
- function handleMouseUp() {
67
- isMouseDown = false;
68
- isDragScroll.value = false;
69
- lastScrollTop = 0;
70
- }
71
-
72
- function handleScroll(e: Event) {
73
- const scrollTop = (e.target as HTMLElement).scrollTop;
74
- // if scrollTop === lastScrollTop means horizontal scroll
75
- if (!isMouseDown || scrollTop === lastScrollTop) return;
76
- isDragScroll.value = true;
77
- }
78
- return { isSRBRActive, isDragScroll };
79
- }
1
+ import { computed, customRef, onMounted, onUnmounted, Ref, watch } from 'vue';
2
+
3
+ type Params = {
4
+ props: any;
5
+ tableContainerRef: Ref<HTMLElement | undefined>;
6
+ };
7
+
8
+ export function useScrollRowByRow({ props, tableContainerRef }: Params) {
9
+ // let isMouseDown = false;
10
+ let isAddListeners = false;
11
+ /** record the last scroll bar position */
12
+ // let lastScrollTop = 0;
13
+
14
+ /** record is the scroll bar is dragging.debounce true to false */
15
+ const isDragScroll = customRef((track, trigger) => {
16
+ let value = false;
17
+ let debounceTimer = 0;
18
+
19
+ return {
20
+ get() {
21
+ track();
22
+ return value;
23
+ },
24
+ set(newValue) {
25
+ // Add debounce when change from true to false
26
+ if (value && !newValue) {
27
+ if (debounceTimer) {
28
+ window.clearTimeout(debounceTimer);
29
+ }
30
+ debounceTimer = window.setTimeout(() => {
31
+ value = newValue;
32
+ trigger();
33
+ debounceTimer = 0;
34
+ }, 300);
35
+ } else {
36
+ if (debounceTimer) {
37
+ window.clearTimeout(debounceTimer);
38
+ debounceTimer = 0;
39
+ }
40
+ value = newValue;
41
+ trigger();
42
+ }
43
+ }
44
+ }
45
+ });
46
+ const onlyDragScroll = computed(() => props.scrollRowByRow === 'scrollbar');
47
+
48
+ /** is ScrollRowByRow active */
49
+ const isSRBRActive = computed(() => {
50
+ if (onlyDragScroll.value) {
51
+ return isDragScroll.value;
52
+ }
53
+ return props.scrollRowByRow;
54
+ });
55
+
56
+ watch(onlyDragScroll, v => {
57
+ if (v) {
58
+ addEventListener();
59
+ } else {
60
+ removeEventListener();
61
+ }
62
+ });
63
+
64
+ onMounted(() => {
65
+ addEventListener();
66
+ });
67
+
68
+ onUnmounted(() => {
69
+ removeEventListener();
70
+ });
71
+
72
+ function addEventListener() {
73
+ if (isAddListeners || !onlyDragScroll.value) return;
74
+ const container = tableContainerRef.value;
75
+ if (!container) return;
76
+ container.addEventListener('mousedown', handleMouseDown);
77
+ container.addEventListener('mouseup', handleMouseUp);
78
+ // container.addEventListener('scroll', handleScroll);
79
+ isAddListeners = true;
80
+ }
81
+
82
+ function removeEventListener() {
83
+ const container = tableContainerRef.value;
84
+ if (!container) return;
85
+ container.removeEventListener('mousedown', handleMouseDown);
86
+ container.removeEventListener('mouseup', handleMouseUp);
87
+ // container.removeEventListener('scroll', handleScroll);
88
+ isAddListeners = false;
89
+ }
90
+
91
+ function handleMouseDown(e: Event) {
92
+ // console.log('mousedown target:', e.target)
93
+ const el = e.target as HTMLElement;
94
+ if(el.classList.contains('stk-table')){
95
+ isDragScroll.value = true;
96
+ }
97
+ // isMouseDown = true;
98
+ // lastScrollTop = (e.target as HTMLElement).scrollTop;
99
+ }
100
+
101
+ function handleMouseUp() {
102
+ // isMouseDown = false;
103
+ isDragScroll.value = false;
104
+ // lastScrollTop = 0;
105
+ }
106
+
107
+ // function handleScroll(e: Event) {
108
+ // const scrollTop = (e.target as HTMLElement).scrollTop;
109
+ // // if scrollTop === lastScrollTop means horizontal scroll
110
+ // if (!isMouseDown || scrollTop === lastScrollTop) return;
111
+ // isDragScroll.value = true;
112
+ // }
113
+ return { isSRBRActive, isDragScroll };
114
+ }
@@ -0,0 +1,187 @@
1
+ import { ref, onMounted, onUnmounted, nextTick, Ref } from 'vue';
2
+ import { throttle } from './utils/index';
3
+
4
+ export type ScrollbarOptions = {
5
+ enabled?: boolean;
6
+ /** scroll-y width */
7
+ width?: number;
8
+ /** scroll-x height */
9
+ height?: number;
10
+ /** min scroll-y width */
11
+ minWidth?: number;
12
+ /** min scroll-x height */
13
+ minHeight?: number;
14
+ };
15
+
16
+ /**
17
+ * 自定义滚动条hooks
18
+ * @param containerRef 滚动容器的ref
19
+ * @param options 滚动条配置选项
20
+ * @returns 滚动条相关状态和方法
21
+ */
22
+ export function useScrollbar(containerRef: Ref<HTMLDivElement | undefined>, options: boolean | ScrollbarOptions = false) {
23
+ const defaultOptions: Required<ScrollbarOptions> = {
24
+ enabled: true,
25
+ minHeight: 20,
26
+ minWidth: 20,
27
+ width: 8,
28
+ height: 8,
29
+ };
30
+
31
+ const mergedOptions = {
32
+ ...defaultOptions,
33
+ ...(typeof options === 'boolean' ? { enabled: options } : options),
34
+ };
35
+
36
+ const showScrollbar = ref({ x: false, y: false });
37
+
38
+ const scrollbar = ref({ h: 0, w: 0, top: 0, left: 0 });
39
+
40
+ let isDraggingVertical = false;
41
+ let isDraggingHorizontal = false;
42
+ let dragStartY = 0;
43
+ let dragStartX = 0;
44
+ let dragStartTop = 0;
45
+ let dragStartLeft = 0;
46
+
47
+ let resizeObserver: ResizeObserver | null = null;
48
+
49
+ const throttledUpdateScrollbar = throttle(() => {
50
+ updateCustomScrollbar();
51
+ }, 200);
52
+
53
+ onMounted(() => {
54
+ if (mergedOptions.enabled && containerRef.value) {
55
+ resizeObserver = new ResizeObserver(throttledUpdateScrollbar);
56
+ resizeObserver.observe(containerRef.value);
57
+ }
58
+ // if (tableMainRef.value) {
59
+ // resizeObserver.observe(tableMainRef.value);
60
+ // }
61
+ initScrollbar();
62
+ });
63
+
64
+ onUnmounted(() => {
65
+ if (resizeObserver) {
66
+ resizeObserver.disconnect();
67
+ resizeObserver = null;
68
+ }
69
+ });
70
+
71
+ function updateCustomScrollbar() {
72
+ if (!mergedOptions.enabled || !containerRef.value) return;
73
+
74
+ const container = containerRef.value;
75
+ const { scrollHeight, clientHeight, scrollWidth, clientWidth, scrollTop, scrollLeft } = container;
76
+
77
+ const needVertical = scrollHeight > clientHeight;
78
+ const needHorizontal = scrollWidth > clientWidth;
79
+ showScrollbar.value = { x: needHorizontal, y: needVertical };
80
+
81
+ if (needVertical) {
82
+ const ratio = clientHeight / scrollHeight;
83
+ scrollbar.value.h = Math.max(mergedOptions.minHeight, ratio * clientHeight);
84
+ scrollbar.value.top = (scrollTop / (scrollHeight - clientHeight)) * (clientHeight - scrollbar.value.h);
85
+ }
86
+
87
+ if (needHorizontal) {
88
+ const ratio = clientWidth / scrollWidth;
89
+ scrollbar.value.w = Math.max(mergedOptions.minWidth, ratio * clientWidth);
90
+ scrollbar.value.left = (scrollLeft / (scrollWidth - clientWidth)) * (clientWidth - scrollbar.value.w);
91
+ }
92
+ }
93
+
94
+ function onVerticalScrollbarMouseDown(e: MouseEvent | TouchEvent) {
95
+ e.preventDefault();
96
+ isDraggingVertical = true;
97
+
98
+ const container = containerRef.value;
99
+ if (!container) return;
100
+
101
+ dragStartTop = container.scrollTop;
102
+ dragStartY = e instanceof MouseEvent ? e.clientY : e.touches[0].clientY;
103
+
104
+ document.addEventListener('mousemove', onVerticalDrag);
105
+ document.addEventListener('mouseup', onDragEnd);
106
+ document.addEventListener('touchmove', onVerticalDrag, { passive: false });
107
+ document.addEventListener('touchend', onDragEnd);
108
+ }
109
+
110
+ function onHorizontalScrollbarMouseDown(e: MouseEvent | TouchEvent) {
111
+ e.preventDefault();
112
+ isDraggingHorizontal = true;
113
+
114
+ const container = containerRef.value;
115
+ if (!container) return;
116
+
117
+ dragStartLeft = container.scrollLeft;
118
+
119
+ dragStartX = e instanceof MouseEvent ? e.clientX : e.touches[0].clientX;
120
+
121
+ document.addEventListener('mousemove', onHorizontalDrag);
122
+ document.addEventListener('mouseup', onDragEnd);
123
+ document.addEventListener('touchmove', onHorizontalDrag, { passive: false });
124
+ document.addEventListener('touchend', onDragEnd);
125
+ }
126
+
127
+ function onVerticalDrag(e: MouseEvent | TouchEvent) {
128
+ if (!isDraggingVertical || !containerRef.value) return;
129
+
130
+ e.preventDefault();
131
+
132
+ const clientY = e instanceof MouseEvent ? e.clientY : e.touches[0].clientY;
133
+
134
+ const deltaY = clientY - dragStartY;
135
+ const container = containerRef.value;
136
+ const { scrollHeight, clientHeight } = container;
137
+
138
+ const scrollRange = scrollHeight - clientHeight;
139
+ const trackRange = clientHeight - scrollbar.value.h;
140
+ const scrollDelta = (deltaY / trackRange) * scrollRange;
141
+ container.scrollTop = dragStartTop + scrollDelta;
142
+ }
143
+
144
+ function onHorizontalDrag(e: MouseEvent | TouchEvent) {
145
+ if (!isDraggingHorizontal || !containerRef.value) return;
146
+
147
+ e.preventDefault();
148
+
149
+ const clientX = e instanceof MouseEvent ? e.clientX : e.touches[0].clientX;
150
+
151
+ const deltaX = clientX - dragStartX;
152
+ const container = containerRef.value;
153
+ const { scrollWidth, clientWidth } = container;
154
+
155
+ const scrollRange = scrollWidth - clientWidth;
156
+ const trackRange = clientWidth - scrollbar.value.w;
157
+ const scrollDelta = (deltaX / trackRange) * scrollRange;
158
+ container.scrollLeft = dragStartLeft + scrollDelta;
159
+ }
160
+
161
+ function onDragEnd() {
162
+ isDraggingVertical = false;
163
+ isDraggingHorizontal = false;
164
+
165
+ document.removeEventListener('mousemove', onVerticalDrag);
166
+ document.removeEventListener('mousemove', onHorizontalDrag);
167
+ document.removeEventListener('mouseup', onDragEnd);
168
+ document.removeEventListener('touchmove', onVerticalDrag);
169
+ document.removeEventListener('touchmove', onHorizontalDrag);
170
+ document.removeEventListener('touchend', onDragEnd);
171
+ }
172
+
173
+ function initScrollbar() {
174
+ nextTick(() => {
175
+ updateCustomScrollbar();
176
+ });
177
+ }
178
+
179
+ return {
180
+ scrollbarOptions: mergedOptions,
181
+ scrollbar,
182
+ showScrollbar,
183
+ onVerticalScrollbarMouseDown,
184
+ onHorizontalScrollbarMouseDown,
185
+ updateCustomScrollbar,
186
+ };
187
+ }