quasar-ui-sellmate-ui-kit 3.14.9 → 3.14.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.common.js +2 -2
- package/dist/index.css +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.min.css +1 -1
- package/dist/index.rtl.css +1 -1
- package/dist/index.rtl.min.css +1 -1
- package/dist/index.umd.js +150 -198
- package/dist/index.umd.min.js +2 -2
- package/package.json +1 -1
- package/src/components/STable.vue +14 -45
- package/src/composables/table/use-resizable.js +128 -158
package/package.json
CHANGED
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
:class="{
|
|
14
14
|
's-select-table': $attrs.selection && $attrs.selection !== 'none',
|
|
15
15
|
'resizable-table': resizable,
|
|
16
|
-
'sticky-column-table': stickyColumn.
|
|
16
|
+
'sticky-column-table': stickyColumn.leftStickyCount > 0 || stickyColumn.rightStickyCount > 0,
|
|
17
17
|
'sticky-resizable-table': stickyResizable,
|
|
18
18
|
'sticky-header': stickyHeader,
|
|
19
19
|
'before-search': !rows.length,
|
|
20
20
|
's-table__hover': !noHover,
|
|
21
|
-
'sticky-left-table': stickyColumn.
|
|
22
|
-
'sticky-right-table': stickyColumn.
|
|
21
|
+
'sticky-left-table': stickyColumn.leftStickyCount > 0,
|
|
22
|
+
'sticky-right-table': stickyColumn.rightStickyCount > 0,
|
|
23
23
|
}"
|
|
24
24
|
@selection="updateSelected"
|
|
25
25
|
ref="sTableRef"
|
|
@@ -44,24 +44,7 @@
|
|
|
44
44
|
</template>
|
|
45
45
|
|
|
46
46
|
<template v-for="(column, index) in columns" :key="index" #[`body-cell-${column.name}`]="props">
|
|
47
|
-
<q-td
|
|
48
|
-
v-if="navigator"
|
|
49
|
-
:class="{
|
|
50
|
-
focused: isFocused(props),
|
|
51
|
-
'text-center': props.col.align === 'center',
|
|
52
|
-
'text-right': props.col.align === 'right',
|
|
53
|
-
[typeof props.col.classes === 'function'
|
|
54
|
-
? props.col.classes(props.row)
|
|
55
|
-
: props.col.classes]: true,
|
|
56
|
-
[typeof props.row.class === 'function'
|
|
57
|
-
? props.row.class(props.row)
|
|
58
|
-
: typeof props.row.class === 'string'
|
|
59
|
-
? props.row.class
|
|
60
|
-
: '']: true,
|
|
61
|
-
}"
|
|
62
|
-
:style="props.col.style"
|
|
63
|
-
@click.stop="focusCell(props)"
|
|
64
|
-
>
|
|
47
|
+
<q-td v-if="navigator" :props="props" @click.stop="focusCell(props)">
|
|
65
48
|
<slot :name="`body-cell-${column.name}-content`" v-bind="props">
|
|
66
49
|
<s-input
|
|
67
50
|
ref="inputRef"
|
|
@@ -82,24 +65,7 @@
|
|
|
82
65
|
</span>
|
|
83
66
|
</slot>
|
|
84
67
|
</q-td>
|
|
85
|
-
<q-td
|
|
86
|
-
v-else
|
|
87
|
-
v-bind="props"
|
|
88
|
-
auto-width
|
|
89
|
-
:class="{
|
|
90
|
-
'text-center': props.col.align === 'center',
|
|
91
|
-
'text-right': props.col.align === 'right',
|
|
92
|
-
[typeof props.col.classes === 'function'
|
|
93
|
-
? props.col.classes(props.row)
|
|
94
|
-
: props.col.classes]: true,
|
|
95
|
-
[typeof props.row.class === 'function'
|
|
96
|
-
? props.row.class(props.row)
|
|
97
|
-
: typeof props.row.class === 'string'
|
|
98
|
-
? props.row.class
|
|
99
|
-
: '']: true,
|
|
100
|
-
}"
|
|
101
|
-
:style="props.col.style"
|
|
102
|
-
>
|
|
68
|
+
<q-td v-else :props="props" auto-width>
|
|
103
69
|
<slot :name="`body-cell-${column.name}-content`" v-bind="props">
|
|
104
70
|
{{ props.value }}
|
|
105
71
|
</slot>
|
|
@@ -166,11 +132,13 @@
|
|
|
166
132
|
type: Boolean,
|
|
167
133
|
default: false,
|
|
168
134
|
},
|
|
135
|
+
useLastCellResizable: {
|
|
136
|
+
type: Boolean,
|
|
137
|
+
default: false,
|
|
138
|
+
},
|
|
169
139
|
stickyColumn: {
|
|
170
140
|
type: Object,
|
|
171
141
|
default: () => ({
|
|
172
|
-
isStickyLeft: false,
|
|
173
|
-
isStickyRight: false,
|
|
174
142
|
leftStickyCount: 0,
|
|
175
143
|
rightStickyCount: 0,
|
|
176
144
|
}),
|
|
@@ -299,12 +267,12 @@
|
|
|
299
267
|
const tableElement = () => sTableRef.value.$el;
|
|
300
268
|
|
|
301
269
|
if (props.resizable) {
|
|
302
|
-
addResizable(sTableRef, props.stickyColumn);
|
|
270
|
+
addResizable(sTableRef, props.stickyColumn, props.useLastCellResizable);
|
|
303
271
|
}
|
|
304
272
|
|
|
305
273
|
const { count, direction: stickyDirection } = props.stickyColumn;
|
|
306
|
-
const {
|
|
307
|
-
if (
|
|
274
|
+
const { leftStickyCount, rightStickyCount } = props.stickyColumn;
|
|
275
|
+
if (leftStickyCount > 0 || rightStickyCount > 0) {
|
|
308
276
|
addStickyColumn(sTableRef, props.stickyColumn);
|
|
309
277
|
observeScrollForStickyShadow(tableElement());
|
|
310
278
|
}
|
|
@@ -379,7 +347,8 @@
|
|
|
379
347
|
.q-table__middle {
|
|
380
348
|
.q-table {
|
|
381
349
|
overflow: auto;
|
|
382
|
-
|
|
350
|
+
width: 100%;
|
|
351
|
+
table-layout: auto;
|
|
383
352
|
tr {
|
|
384
353
|
th,
|
|
385
354
|
td {
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
const MIN_COL_WIDTH = 40; // 최소 너비 제한
|
|
2
|
+
const HANDLE_WIDTH = 4; // 리사이즈 핸들의 너비
|
|
3
|
+
const HANDLE_HEIGHT = 16; // 리사이즈 핸들의 높이
|
|
4
|
+
const HANDLE_Z_INDEX = 2; // 리사이즈 핸들의 z-index
|
|
5
|
+
|
|
1
6
|
function createDiv(val) {
|
|
2
7
|
// 기존의 resizable div 코드
|
|
3
8
|
const div = document.createElement('div');
|
|
@@ -5,23 +10,22 @@ function createDiv(val) {
|
|
|
5
10
|
div.style.top = '10px';
|
|
6
11
|
if (val === 'right') div.style.right = 0;
|
|
7
12
|
if (val === 'left') div.style.left = 0;
|
|
8
|
-
div.style.width =
|
|
13
|
+
div.style.width = `${HANDLE_WIDTH}px`;
|
|
9
14
|
div.style.position = 'absolute';
|
|
10
15
|
div.style.cursor = 'col-resize';
|
|
11
|
-
div.style.backgroundColor = '
|
|
16
|
+
div.style.backgroundColor = 'transparent';
|
|
12
17
|
div.style.border = '1px solid #CCCCCC';
|
|
13
18
|
div.style.borderTop = 'none';
|
|
14
19
|
div.style.borderBottom = 'none';
|
|
15
|
-
div.style.zIndex =
|
|
20
|
+
div.style.zIndex = HANDLE_Z_INDEX;
|
|
16
21
|
div.style.userSelect = 'none';
|
|
17
|
-
div.style.height =
|
|
22
|
+
div.style.height = `${HANDLE_HEIGHT}px`;
|
|
18
23
|
return div;
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
// TODO: 전역이 아니라 컴포넌트 단위로 제한된 최소 너비를 설정할 수 있도록 개선
|
|
22
|
-
let restrictedMinWidth;
|
|
23
|
-
|
|
24
26
|
function detectStickyWidth(tableElement, isStickyLeft) {
|
|
27
|
+
if (!tableElement) return;
|
|
28
|
+
|
|
25
29
|
const tableRow = Array.from(tableElement.getElementsByTagName('tr'));
|
|
26
30
|
const theadRow = tableRow[0];
|
|
27
31
|
const stickyTh = Array.from(theadRow.querySelectorAll('.sticky-cell'));
|
|
@@ -46,182 +50,148 @@ function detectStickyWidth(tableElement, isStickyLeft) {
|
|
|
46
50
|
});
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (isRestricted && curColWidth + diffX <= restrictedMinWidth) {
|
|
76
|
-
calcWidth = restrictedMinWidth; // 제한된 컬럼은 최소 너비로 설정
|
|
77
|
-
} else {
|
|
78
|
-
calcWidth = curColWidth + diffX;
|
|
53
|
+
export function useResizable() {
|
|
54
|
+
function setListeners(div, position, useSticky) {
|
|
55
|
+
// resizable 속성을 사용할 때에 이벤트
|
|
56
|
+
let curCol;
|
|
57
|
+
let pageX;
|
|
58
|
+
let curColWidth;
|
|
59
|
+
|
|
60
|
+
const onMouseMove = e => {
|
|
61
|
+
if (!curCol) return false;
|
|
62
|
+
|
|
63
|
+
const diffX = e.pageX - pageX;
|
|
64
|
+
const isStickyLeft = position === 'right';
|
|
65
|
+
let calcWidth = isStickyLeft ? curColWidth + diffX : curColWidth - diffX;
|
|
66
|
+
|
|
67
|
+
const computedStyles = window.getComputedStyle(curCol);
|
|
68
|
+
const min = parseInt(computedStyles.minWidth || `${MIN_COL_WIDTH}`, 10);
|
|
69
|
+
const max = parseInt(
|
|
70
|
+
computedStyles.maxWidth === 'none' ? '9999' : computedStyles.maxWidth || '9999',
|
|
71
|
+
10,
|
|
72
|
+
);
|
|
73
|
+
calcWidth = Math.max(min, Math.min(calcWidth, max));
|
|
74
|
+
curCol.style.width = `${calcWidth}px`;
|
|
75
|
+
|
|
76
|
+
if (useSticky && curCol) {
|
|
77
|
+
const table = curCol.closest('table').parentElement;
|
|
78
|
+
detectStickyWidth(table, position === 'right');
|
|
79
79
|
}
|
|
80
|
-
} else {
|
|
81
|
-
calcWidth = curColWidth - diffX;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (calcWidth < 40) {
|
|
85
|
-
calcWidth = 40; // 최소 너비 제한
|
|
86
|
-
}
|
|
87
80
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const onMouseUp = () => {
|
|
85
|
+
curCol = undefined;
|
|
86
|
+
pageX = undefined;
|
|
87
|
+
curColWidth = undefined;
|
|
88
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
89
|
+
document.removeEventListener('mouseup', onMouseUp);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const onMouseDown = e => {
|
|
93
|
+
curCol = e.target.parentElement;
|
|
94
|
+
pageX = e.pageX;
|
|
95
|
+
curColWidth = curCol.offsetWidth;
|
|
96
|
+
document.addEventListener('mousemove', onMouseMove, { passive: true });
|
|
97
|
+
document.addEventListener('mouseup', onMouseUp, { passive: true });
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
div.addEventListener('mousedown', onMouseDown, { passive: true });
|
|
101
|
+
}
|
|
107
102
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
document.addEventListener('mouseup', onMouseUp, { passive: true });
|
|
114
|
-
};
|
|
103
|
+
function appendResizableDiv(col, direction, useSticky) {
|
|
104
|
+
const div = createDiv(direction);
|
|
105
|
+
col.appendChild(div);
|
|
106
|
+
setListeners(div, direction, useSticky);
|
|
107
|
+
}
|
|
115
108
|
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
function getTableCols(tableEl) {
|
|
110
|
+
if (!tableEl) return [];
|
|
111
|
+
const tableElement = tableEl.getElementsByTagName('table')[0];
|
|
112
|
+
if (!tableElement) return [];
|
|
113
|
+
const firstRow = tableElement.getElementsByTagName('tr')[0];
|
|
114
|
+
return firstRow ? Array.from(firstRow.children) : [];
|
|
115
|
+
}
|
|
118
116
|
|
|
119
|
-
function
|
|
120
|
-
|
|
121
|
-
col.appendChild(div);
|
|
122
|
-
setListeners(div, direction, useSticky, restrictedColClass);
|
|
123
|
-
}
|
|
117
|
+
function applyStickyToColumn(tableEl, colIdx, isLeft, offsetPx) {
|
|
118
|
+
const rows = Array.from(tableEl.querySelectorAll('tr'));
|
|
124
119
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
120
|
+
rows.forEach(row => {
|
|
121
|
+
const cells = Array.from(row.children);
|
|
122
|
+
const targetCell = cells[colIdx];
|
|
123
|
+
if (!targetCell) return;
|
|
130
124
|
|
|
131
|
-
|
|
132
|
-
|
|
125
|
+
targetCell.classList.add('sticky-cell');
|
|
126
|
+
targetCell.classList.add(isLeft ? 'left' : 'right');
|
|
127
|
+
targetCell.style.position = 'sticky';
|
|
128
|
+
targetCell.style[isLeft ? 'left' : 'right'] = offsetPx;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
133
131
|
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
function addResizable(tableRef, stickyColumnsConfig = {}, useLastCellResizable = false) {
|
|
133
|
+
const cols = getTableCols(tableRef.value.$el);
|
|
134
|
+
const leftStickyCount = stickyColumnsConfig.leftStickyCount || 0;
|
|
135
|
+
const rightStickyCount = stickyColumnsConfig.rightStickyCount || 0;
|
|
136
136
|
|
|
137
|
-
cols.forEach((col, colIdx) => {
|
|
138
|
-
const isLastCol = colIdx >= cols.length - 1;
|
|
139
|
-
const isFirstCol = colIdx === 0;
|
|
140
137
|
const isSelectTable = tableRef.value.$el.classList.contains('s-select-table');
|
|
141
138
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
cols.forEach((col, colIdx) => {
|
|
140
|
+
const isFirstCol = colIdx === 0;
|
|
141
|
+
const isLastCol = colIdx === cols.length - 1;
|
|
142
|
+
const isLeftSticky = colIdx < leftStickyCount;
|
|
143
|
+
const isRightSticky = colIdx >= cols.length - rightStickyCount;
|
|
145
144
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
// 🔑 스티키 컬럼이라면 리사이즈 핸들 생성 금지!! appendResizableDiv 호출하지 않음
|
|
146
|
+
if (isLeftSticky || isRightSticky) return;
|
|
147
|
+
|
|
148
|
+
const shouldAddResizable = (() => {
|
|
149
|
+
if (isSelectTable) {
|
|
150
|
+
if (useLastCellResizable && isLastCol) return true;
|
|
151
|
+
return !isFirstCol && !isLastCol;
|
|
152
|
+
}
|
|
153
|
+
return useLastCellResizable ? !isLastCol : true;
|
|
154
|
+
})();
|
|
149
155
|
|
|
150
|
-
|
|
151
|
-
if (isSelectTable) {
|
|
152
|
-
if (!isFirstCol && !isLastCol) {
|
|
156
|
+
if (shouldAddResizable) {
|
|
153
157
|
appendResizableDiv(col, 'right', false);
|
|
154
158
|
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function applyStickyToColumn(tableEl, colIdx, isLeft, offsetPx) {
|
|
162
|
-
const rows = Array.from(tableEl.querySelectorAll('tr'));
|
|
163
|
-
|
|
164
|
-
rows.forEach(row => {
|
|
165
|
-
const cells = Array.from(row.children);
|
|
166
|
-
const targetCell = cells[colIdx];
|
|
167
|
-
if (!targetCell) return;
|
|
168
|
-
|
|
169
|
-
targetCell.classList.add('sticky-cell');
|
|
170
|
-
targetCell.classList.add(isLeft ? 'left' : 'right');
|
|
171
|
-
targetCell.classList.add(`sticky-col-${colIdx}`);
|
|
172
|
-
|
|
173
|
-
targetCell.style.position = 'sticky';
|
|
174
|
-
|
|
175
|
-
if (isLeft) {
|
|
176
|
-
targetCell.style.left = offsetPx;
|
|
177
|
-
} else {
|
|
178
|
-
targetCell.style.right = offsetPx;
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function addStickyColumn(tableRef, stickyColumnsConfig) {
|
|
184
|
-
const { isStickyLeft, isStickyRight, leftStickyCount, rightStickyCount } = stickyColumnsConfig;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
185
161
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const restrictedColClass = `sticky-col-${isSelectTable ? leftStickyCount : leftStickyCount - 1}`;
|
|
162
|
+
function addStickyColumn(tableRef, stickyColumnsConfig) {
|
|
163
|
+
const { leftStickyCount, rightStickyCount } = stickyColumnsConfig;
|
|
189
164
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// let i = isSelectTable ? 1 : 0; // Select Table일 경우 첫번째 컬럼은 스티키가 아님
|
|
193
|
-
const count = isSelectTable ? leftStickyCount + 1 : leftStickyCount; // Select Table일 경우 +1
|
|
165
|
+
const cols = getTableCols(tableRef.value.$el);
|
|
166
|
+
const isSelectTable = tableRef.value.$el.classList.contains('s-select-table');
|
|
194
167
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
168
|
+
// Left Sticky Columns
|
|
169
|
+
if (leftStickyCount > 0) {
|
|
170
|
+
// let i = isSelectTable ? 1 : 0; // Select Table일 경우 첫번째 컬럼은 스티키가 아님
|
|
171
|
+
const count = isSelectTable ? leftStickyCount + 1 : leftStickyCount; // Select Table일 경우 +1
|
|
172
|
+
|
|
173
|
+
for (let i = 0; i < count; i++) {
|
|
174
|
+
applyStickyToColumn(tableRef.value.$el, i, true, '0px');
|
|
175
|
+
if (isSelectTable && i > 0) {
|
|
176
|
+
appendResizableDiv(cols[i], 'right', true); // 오른쪽에 리사이즈 핸들 추가
|
|
177
|
+
} else {
|
|
178
|
+
appendResizableDiv(cols[i], 'right', true); // 오른쪽에 리사이즈 핸들 추가
|
|
206
179
|
}
|
|
207
180
|
}
|
|
181
|
+
|
|
182
|
+
detectStickyWidth(tableRef.value.$el, true); // 좌측 스티키 너비 재계산
|
|
208
183
|
}
|
|
209
184
|
|
|
210
|
-
|
|
211
|
-
|
|
185
|
+
// Right Sticky Columns
|
|
186
|
+
if (rightStickyCount > 0) {
|
|
187
|
+
for (let i = cols.length - rightStickyCount; i < cols.length; i++) {
|
|
188
|
+
applyStickyToColumn(tableRef.value.$el, i, false, '0px');
|
|
189
|
+
appendResizableDiv(cols[i], 'left', true); // 왼쪽에 리사이즈 핸들 추가 (우측 스티키)
|
|
190
|
+
}
|
|
212
191
|
|
|
213
|
-
|
|
214
|
-
if (isStickyRight && rightStickyCount > 0) {
|
|
215
|
-
for (let i = cols.length - rightStickyCount; i < cols.length; i++) {
|
|
216
|
-
applyStickyToColumn(tableRef.value.$el, i, false, '0px');
|
|
217
|
-
appendResizableDiv(cols[i], 'left', true); // 왼쪽에 리사이즈 핸들 추가 (우측 스티키)
|
|
192
|
+
detectStickyWidth(tableRef.value.$el, false); // 우측 스티키 너비 재계산
|
|
218
193
|
}
|
|
219
|
-
|
|
220
|
-
detectStickyWidth(tableRef.value.$el, false); // 우측 스티키 너비 재계산
|
|
221
194
|
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export function useResizable() {
|
|
225
195
|
return {
|
|
226
196
|
addResizable,
|
|
227
197
|
addStickyColumn,
|