@sellmate/design-system-vue 1.28.0 → 1.31.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.
- package/README.md +0 -20
- package/dist/components.d.ts +5 -5
- package/dist/components.js +118 -93
- package/dist/define-custom-elements.js +0 -10
- package/dist/index.d.ts +1 -3
- package/dist/index.js +0 -1
- package/lib/components.ts +128 -102
- package/lib/define-custom-elements.ts +0 -10
- package/lib/index.ts +0 -11
- package/package.json +2 -2
- package/dist/SdTable.d.ts +0 -241
- package/dist/SdTable.js +0 -191
- package/dist/composables/useSdTableVirtualScroll.d.ts +0 -11
- package/dist/composables/useSdTableVirtualScroll.js +0 -58
- package/lib/composables/useSdTableVirtualScroll.ts +0 -84
package/dist/SdTable.js
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { computed, defineComponent, h, ref, useAttrs, useSlots, watch, } from 'vue';
|
|
2
|
-
const SLOT_WRAPPER_STYLE = {
|
|
3
|
-
display: 'contents',
|
|
4
|
-
};
|
|
5
|
-
const getCellValue = (column, row) => {
|
|
6
|
-
const { field, format, name } = column;
|
|
7
|
-
const value = typeof field === 'function' ? field(row) : field ? row[field] : row[name];
|
|
8
|
-
return format ? format(value, row) : value;
|
|
9
|
-
};
|
|
10
|
-
export default defineComponent({
|
|
11
|
-
name: 'SdTable',
|
|
12
|
-
inheritAttrs: false,
|
|
13
|
-
props: {
|
|
14
|
-
columns: {
|
|
15
|
-
type: Array,
|
|
16
|
-
required: true,
|
|
17
|
-
},
|
|
18
|
-
rows: {
|
|
19
|
-
type: Array,
|
|
20
|
-
required: true,
|
|
21
|
-
},
|
|
22
|
-
modelValue: {
|
|
23
|
-
type: Array,
|
|
24
|
-
default: undefined,
|
|
25
|
-
},
|
|
26
|
-
selected: {
|
|
27
|
-
type: Array,
|
|
28
|
-
default: undefined,
|
|
29
|
-
},
|
|
30
|
-
rowKey: {
|
|
31
|
-
type: String,
|
|
32
|
-
default: 'id',
|
|
33
|
-
},
|
|
34
|
-
selectable: {
|
|
35
|
-
type: Boolean,
|
|
36
|
-
default: false,
|
|
37
|
-
},
|
|
38
|
-
resizable: {
|
|
39
|
-
type: Boolean,
|
|
40
|
-
default: false,
|
|
41
|
-
},
|
|
42
|
-
width: {
|
|
43
|
-
type: String,
|
|
44
|
-
default: undefined,
|
|
45
|
-
},
|
|
46
|
-
height: {
|
|
47
|
-
type: String,
|
|
48
|
-
default: undefined,
|
|
49
|
-
},
|
|
50
|
-
stickyHeader: {
|
|
51
|
-
type: Boolean,
|
|
52
|
-
default: false,
|
|
53
|
-
},
|
|
54
|
-
stickyColumn: {
|
|
55
|
-
type: Object,
|
|
56
|
-
default: () => ({ left: 0, right: 0 }),
|
|
57
|
-
},
|
|
58
|
-
noDataLabel: {
|
|
59
|
-
type: String,
|
|
60
|
-
default: '데이터가 없습니다.',
|
|
61
|
-
},
|
|
62
|
-
isLoading: {
|
|
63
|
-
type: Boolean,
|
|
64
|
-
default: false,
|
|
65
|
-
},
|
|
66
|
-
pagination: {
|
|
67
|
-
type: Object,
|
|
68
|
-
default: undefined,
|
|
69
|
-
},
|
|
70
|
-
useInternalPagination: {
|
|
71
|
-
type: Boolean,
|
|
72
|
-
default: false,
|
|
73
|
-
},
|
|
74
|
-
useRowsPerPageSelect: {
|
|
75
|
-
type: Boolean,
|
|
76
|
-
default: false,
|
|
77
|
-
},
|
|
78
|
-
rowsPerPageOption: {
|
|
79
|
-
type: Array,
|
|
80
|
-
default: () => [
|
|
81
|
-
{ label: '10개씩 보기', value: 10 },
|
|
82
|
-
{ label: '25개씩 보기', value: 25 },
|
|
83
|
-
{ label: '50개씩 보기', value: 50 },
|
|
84
|
-
{ label: '100개씩 보기', value: 100 },
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
useVirtualScroll: {
|
|
88
|
-
type: Object,
|
|
89
|
-
default: () => ({}),
|
|
90
|
-
},
|
|
91
|
-
virtualRowHeight: {
|
|
92
|
-
type: Number,
|
|
93
|
-
default: 44,
|
|
94
|
-
},
|
|
95
|
-
virtualColumnWidth: {
|
|
96
|
-
type: Number,
|
|
97
|
-
default: 120,
|
|
98
|
-
},
|
|
99
|
-
virtualBufferSize: {
|
|
100
|
-
type: Object,
|
|
101
|
-
default: () => ({
|
|
102
|
-
vertical: 5,
|
|
103
|
-
horizontal: 5,
|
|
104
|
-
}),
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
emits: ['update:modelValue', 'sdSelectChange', 'sdPageChange', 'sdRowsPerPageChange'],
|
|
108
|
-
setup(props, { emit }) {
|
|
109
|
-
const attrs = useAttrs();
|
|
110
|
-
const slots = useSlots();
|
|
111
|
-
const normalizedRows = computed(() => props.rows ?? []);
|
|
112
|
-
const currentPage = ref(props.pagination?.page || 1);
|
|
113
|
-
const currentRowsPerPage = ref(props.pagination?.rowsPerPage || normalizedRows.value.length || 0);
|
|
114
|
-
watch(() => props.pagination, pagination => {
|
|
115
|
-
currentPage.value = pagination?.page || 1;
|
|
116
|
-
currentRowsPerPage.value = pagination?.rowsPerPage || normalizedRows.value.length || 0;
|
|
117
|
-
}, { immediate: true, deep: true });
|
|
118
|
-
watch(() => normalizedRows.value.length, rowLength => {
|
|
119
|
-
if (!currentRowsPerPage.value) {
|
|
120
|
-
currentRowsPerPage.value = rowLength;
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
const renderedRows = computed(() => {
|
|
124
|
-
if (!props.useInternalPagination || !currentRowsPerPage.value) {
|
|
125
|
-
return normalizedRows.value;
|
|
126
|
-
}
|
|
127
|
-
const startIndex = (currentPage.value - 1) * currentRowsPerPage.value;
|
|
128
|
-
return normalizedRows.value.slice(startIndex, startIndex + currentRowsPerPage.value);
|
|
129
|
-
});
|
|
130
|
-
return () => {
|
|
131
|
-
const slotChildren = [];
|
|
132
|
-
const noDataSlot = slots['no-data'];
|
|
133
|
-
if (noDataSlot) {
|
|
134
|
-
slotChildren.push(h('span', {
|
|
135
|
-
key: 'no-data',
|
|
136
|
-
slot: 'no-data',
|
|
137
|
-
style: SLOT_WRAPPER_STYLE,
|
|
138
|
-
}, noDataSlot()));
|
|
139
|
-
}
|
|
140
|
-
props.columns.forEach(column => {
|
|
141
|
-
const headerSlot = slots[`header-${column.name}`] || slots.header;
|
|
142
|
-
if (headerSlot) {
|
|
143
|
-
slotChildren.push(h('span', {
|
|
144
|
-
key: `header-${column.name}`,
|
|
145
|
-
slot: `header-cell-${column.name}`,
|
|
146
|
-
style: SLOT_WRAPPER_STYLE,
|
|
147
|
-
}, headerSlot({ column })));
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
renderedRows.value.forEach((row, rowIndex) => {
|
|
151
|
-
props.columns.forEach(column => {
|
|
152
|
-
const cellSlot = slots[`cell-${column.name}`] || slots.cell;
|
|
153
|
-
if (!cellSlot)
|
|
154
|
-
return;
|
|
155
|
-
slotChildren.push(h('span', {
|
|
156
|
-
key: `cell-${column.name}-${rowIndex}`,
|
|
157
|
-
slot: `body-cell-${column.name}-${rowIndex}`,
|
|
158
|
-
style: SLOT_WRAPPER_STYLE,
|
|
159
|
-
}, cellSlot({
|
|
160
|
-
column,
|
|
161
|
-
row,
|
|
162
|
-
rowIndex,
|
|
163
|
-
value: getCellValue(column, row),
|
|
164
|
-
})));
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
return h('sd-table', {
|
|
168
|
-
...attrs,
|
|
169
|
-
...props,
|
|
170
|
-
rows: normalizedRows.value,
|
|
171
|
-
selected: props.modelValue ?? props.selected,
|
|
172
|
-
onSdSelectChange: (event) => {
|
|
173
|
-
emit('update:modelValue', event.detail);
|
|
174
|
-
emit('sdSelectChange', event);
|
|
175
|
-
},
|
|
176
|
-
onSdPageChange: (event) => {
|
|
177
|
-
currentPage.value = event.detail;
|
|
178
|
-
emit('sdPageChange', event);
|
|
179
|
-
},
|
|
180
|
-
onSdRowsPerPageChange: (event) => {
|
|
181
|
-
currentRowsPerPage.value = event.detail;
|
|
182
|
-
const lastPage = Math.max(1, Math.ceil(normalizedRows.value.length / event.detail));
|
|
183
|
-
currentPage.value = Math.min(currentPage.value, lastPage);
|
|
184
|
-
emit('sdRowsPerPageChange', event);
|
|
185
|
-
},
|
|
186
|
-
}, {
|
|
187
|
-
default: () => slotChildren,
|
|
188
|
-
});
|
|
189
|
-
};
|
|
190
|
-
},
|
|
191
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type Ref } from 'vue';
|
|
2
|
-
export interface VirtualRow<T = Record<string, any>> {
|
|
3
|
-
/** 전체 rows 기준 절대 인덱스 — sd-tr의 rowKey로 사용 */
|
|
4
|
-
index: number;
|
|
5
|
-
row: T;
|
|
6
|
-
}
|
|
7
|
-
export declare function useSdTableVirtualScroll<T extends Record<string, any>>(tableRef: Ref<any>, rows: Ref<T[]>): {
|
|
8
|
-
virtualRows: import("vue").ComputedRef<VirtualRow<T>[]>;
|
|
9
|
-
from: import("vue").ComputedRef<number>;
|
|
10
|
-
to: import("vue").ComputedRef<number>;
|
|
11
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
|
2
|
-
export function useSdTableVirtualScroll(tableRef, rows) {
|
|
3
|
-
const range = ref(null);
|
|
4
|
-
let targetEl = null;
|
|
5
|
-
let rafId = 0;
|
|
6
|
-
const onVirtualUpdate = (e) => {
|
|
7
|
-
const { from, to } = e.detail;
|
|
8
|
-
range.value = { from, to };
|
|
9
|
-
};
|
|
10
|
-
const syncRange = (el) => {
|
|
11
|
-
const currentRange = el.getVirtualScrollRangeSync?.();
|
|
12
|
-
if (currentRange &&
|
|
13
|
-
typeof currentRange.from === 'number' &&
|
|
14
|
-
typeof currentRange.to === 'number') {
|
|
15
|
-
range.value = { from: currentRange.from, to: currentRange.to };
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
return false;
|
|
19
|
-
};
|
|
20
|
-
const attachWhenReady = () => {
|
|
21
|
-
// Stencil Vue 래퍼는 expose()를 사용하지 않으므로 $el로 실제 custom element에 접근
|
|
22
|
-
const raw = tableRef.value?.$el ?? tableRef.value;
|
|
23
|
-
const el = raw instanceof HTMLElement ? raw : null;
|
|
24
|
-
if (!el) {
|
|
25
|
-
rafId = requestAnimationFrame(attachWhenReady);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
targetEl = el;
|
|
29
|
-
targetEl.addEventListener('sdVirtualUpdate', onVirtualUpdate);
|
|
30
|
-
const trySync = () => {
|
|
31
|
-
if (!targetEl)
|
|
32
|
-
return;
|
|
33
|
-
if (!syncRange(targetEl)) {
|
|
34
|
-
rafId = requestAnimationFrame(trySync);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
trySync();
|
|
38
|
-
};
|
|
39
|
-
onMounted(() => {
|
|
40
|
-
attachWhenReady();
|
|
41
|
-
});
|
|
42
|
-
onUnmounted(() => {
|
|
43
|
-
cancelAnimationFrame(rafId);
|
|
44
|
-
targetEl?.removeEventListener('sdVirtualUpdate', onVirtualUpdate);
|
|
45
|
-
targetEl = null;
|
|
46
|
-
});
|
|
47
|
-
const virtualRows = computed(() => {
|
|
48
|
-
if (!range.value)
|
|
49
|
-
return [];
|
|
50
|
-
const { from, to } = range.value;
|
|
51
|
-
return rows.value.slice(from, to).map((row, i) => ({ index: from + i, row }));
|
|
52
|
-
});
|
|
53
|
-
return {
|
|
54
|
-
virtualRows,
|
|
55
|
-
from: computed(() => range.value?.from ?? 0),
|
|
56
|
-
to: computed(() => range.value?.to ?? 0),
|
|
57
|
-
};
|
|
58
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { ref, computed, onMounted, onUnmounted, type Ref } from 'vue';
|
|
2
|
-
|
|
3
|
-
export interface VirtualRow<T = Record<string, any>> {
|
|
4
|
-
/** 전체 rows 기준 절대 인덱스 — sd-tr의 rowKey로 사용 */
|
|
5
|
-
index: number;
|
|
6
|
-
row: T;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface SdVirtualUpdateDetail {
|
|
10
|
-
from: number;
|
|
11
|
-
to: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function useSdTableVirtualScroll<T extends Record<string, any>>(
|
|
15
|
-
tableRef: Ref<any>,
|
|
16
|
-
rows: Ref<T[]>,
|
|
17
|
-
) {
|
|
18
|
-
const range = ref<{ from: number; to: number } | null>(null);
|
|
19
|
-
|
|
20
|
-
let targetEl: HTMLElement | null = null;
|
|
21
|
-
let rafId = 0;
|
|
22
|
-
|
|
23
|
-
const onVirtualUpdate = (e: Event) => {
|
|
24
|
-
const { from, to } = (e as CustomEvent<SdVirtualUpdateDetail>).detail;
|
|
25
|
-
range.value = { from, to };
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const syncRange = (el: HTMLElement): boolean => {
|
|
29
|
-
const currentRange = (el as any).getVirtualScrollRangeSync?.();
|
|
30
|
-
if (
|
|
31
|
-
currentRange &&
|
|
32
|
-
typeof currentRange.from === 'number' &&
|
|
33
|
-
typeof currentRange.to === 'number'
|
|
34
|
-
) {
|
|
35
|
-
range.value = { from: currentRange.from, to: currentRange.to };
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
return false;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const attachWhenReady = () => {
|
|
42
|
-
// Stencil Vue 래퍼는 expose()를 사용하지 않으므로 $el로 실제 custom element에 접근
|
|
43
|
-
const raw = (tableRef.value as any)?.$el ?? tableRef.value;
|
|
44
|
-
const el: HTMLElement | null = raw instanceof HTMLElement ? raw : null;
|
|
45
|
-
if (!el) {
|
|
46
|
-
rafId = requestAnimationFrame(attachWhenReady);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
targetEl = el;
|
|
51
|
-
targetEl.addEventListener('sdVirtualUpdate', onVirtualUpdate);
|
|
52
|
-
|
|
53
|
-
const trySync = () => {
|
|
54
|
-
if (!targetEl) return;
|
|
55
|
-
if (!syncRange(targetEl)) {
|
|
56
|
-
rafId = requestAnimationFrame(trySync);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
trySync();
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
onMounted(() => {
|
|
64
|
-
attachWhenReady();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
onUnmounted(() => {
|
|
68
|
-
cancelAnimationFrame(rafId);
|
|
69
|
-
targetEl?.removeEventListener('sdVirtualUpdate', onVirtualUpdate);
|
|
70
|
-
targetEl = null;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const virtualRows = computed<VirtualRow<T>[]>(() => {
|
|
74
|
-
if (!range.value) return [];
|
|
75
|
-
const { from, to } = range.value;
|
|
76
|
-
return rows.value.slice(from, to).map((row, i) => ({ index: from + i, row }));
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
virtualRows,
|
|
81
|
-
from: computed(() => range.value?.from ?? 0),
|
|
82
|
-
to: computed(() => range.value?.to ?? 0),
|
|
83
|
-
};
|
|
84
|
-
}
|