@iyulab/data-components 0.7.1 → 0.9.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/CHANGELOG.md +218 -0
- package/README.md +36 -2
- package/dist/components/data-view/UDataView.styles.js +33 -106
- package/dist/components/simple-sheet/USimpleSheet.d.ts +2 -0
- package/dist/components/simple-sheet/USimpleSheet.js +3 -1
- package/dist/components/simple-sheet/USimpleSheet.styles.js +54 -150
- package/dist/components/u-rich-table/URichTable.d.ts +25 -0
- package/dist/components/u-rich-table/URichTable.js +47 -15
- package/dist/components/u-rich-table/styles.js +77 -206
- package/dist/init.js +1 -0
- package/package.json +2 -2
|
@@ -12,14 +12,14 @@ var baseStyles = css`
|
|
|
12
12
|
height: 100%;
|
|
13
13
|
overflow: hidden;
|
|
14
14
|
outline: none;
|
|
15
|
-
border: 1px solid var(--u-border-color, #
|
|
15
|
+
border: 1px solid var(--u-border-color, #E0E0E0);
|
|
16
16
|
border-radius: 4px;
|
|
17
|
-
background: var(--u-bg-color, #
|
|
17
|
+
background: var(--u-bg-color, #FFFFFF);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.sheet-container:focus-within {
|
|
21
|
-
border-color: var(--u-blue-500, #
|
|
22
|
-
box-shadow: 0 0 0 2px var(--u-blue-100, #
|
|
21
|
+
border-color: var(--u-blue-500, #2196F3);
|
|
22
|
+
box-shadow: 0 0 0 2px var(--u-blue-100, #BBDEFB);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
.sheet-scroll {
|
|
@@ -43,15 +43,15 @@ var baseStyles = css`
|
|
|
43
43
|
z-index: 4;
|
|
44
44
|
width: 48px;
|
|
45
45
|
min-width: 48px;
|
|
46
|
-
background: var(--u-neutral-100, #
|
|
47
|
-
border-right: 1px solid var(--u-border-color, #
|
|
48
|
-
border-bottom: 2px solid var(--u-border-color, #
|
|
46
|
+
background: var(--u-neutral-100, #F5F5F5);
|
|
47
|
+
border-right: 1px solid var(--u-border-color, #E0E0E0);
|
|
48
|
+
border-bottom: 2px solid var(--u-border-color, #E0E0E0);
|
|
49
49
|
cursor: pointer;
|
|
50
50
|
user-select: none;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
.corner:hover {
|
|
54
|
-
background: var(--u-neutral-200, #
|
|
54
|
+
background: var(--u-neutral-200, #EEEEEE);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/* Column headers (A, B, C...) */
|
|
@@ -59,14 +59,14 @@ var baseStyles = css`
|
|
|
59
59
|
position: sticky;
|
|
60
60
|
top: 0;
|
|
61
61
|
z-index: 2;
|
|
62
|
-
background: var(--u-neutral-100, #
|
|
62
|
+
background: var(--u-neutral-100, #F5F5F5);
|
|
63
63
|
padding: 4px 8px;
|
|
64
64
|
text-align: center;
|
|
65
65
|
font-size: 12px;
|
|
66
66
|
font-weight: 600;
|
|
67
|
-
color: var(--u-txt-color-weak, #
|
|
68
|
-
border-right: 1px solid var(--u-border-color, #
|
|
69
|
-
border-bottom: 2px solid var(--u-border-color, #
|
|
67
|
+
color: var(--u-txt-color-weak, #757575);
|
|
68
|
+
border-right: 1px solid var(--u-border-color, #E0E0E0);
|
|
69
|
+
border-bottom: 2px solid var(--u-border-color, #E0E0E0);
|
|
70
70
|
white-space: nowrap;
|
|
71
71
|
min-width: 80px;
|
|
72
72
|
cursor: pointer;
|
|
@@ -75,8 +75,8 @@ var baseStyles = css`
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
.col-header.col-selected {
|
|
78
|
-
background: var(--u-blue-200, #
|
|
79
|
-
color: var(--u-blue-800, #
|
|
78
|
+
background: var(--u-blue-200, #90CAF9);
|
|
79
|
+
color: var(--u-blue-800, #1565C0);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
.resize-handle {
|
|
@@ -102,7 +102,7 @@ var baseStyles = css`
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
.resize-handle:hover::after {
|
|
105
|
-
background: var(--u-blue-500, #
|
|
105
|
+
background: var(--u-blue-500, #2196F3);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
.sheet-container.is-resizing {
|
|
@@ -124,28 +124,31 @@ var baseStyles = css`
|
|
|
124
124
|
text-align: right;
|
|
125
125
|
padding: 0 6px;
|
|
126
126
|
font-size: 11px;
|
|
127
|
-
color: var(--u-txt-color-weak, #
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
color: var(--u-txt-color-weak, #757575);
|
|
128
|
+
/* 예외 — 표면 높이 축이 없다. 행번호 여백은 "비활성"이 아니라 시트 바탕보다
|
|
129
|
+
한 단 내려간 면이다. --u-bg-color-disabled 를 쓰면 다크에서 바탕(neutral-100)과
|
|
130
|
+
같은 값이 되어 여백 구분이 사라진다 — 스냅샷이 그것을 잡았다. */
|
|
131
|
+
background: var(--u-neutral-50, #FAFAFA);
|
|
132
|
+
border-right: 1px solid var(--u-border-color, #E0E0E0);
|
|
133
|
+
border-bottom: 1px solid var(--u-border-color-weak, #EEEEEE);
|
|
131
134
|
cursor: pointer;
|
|
132
135
|
user-select: none;
|
|
133
136
|
vertical-align: middle;
|
|
134
137
|
}
|
|
135
138
|
|
|
136
139
|
.row-num.row-selected {
|
|
137
|
-
background: var(--u-blue-100, #
|
|
138
|
-
color: var(--u-blue-800, #
|
|
140
|
+
background: var(--u-blue-100, #BBDEFB);
|
|
141
|
+
color: var(--u-blue-800, #1565C0);
|
|
139
142
|
font-weight: 600;
|
|
140
143
|
}
|
|
141
144
|
|
|
142
145
|
/* Data cells */
|
|
143
146
|
.cell {
|
|
144
147
|
padding: 0 6px;
|
|
145
|
-
border-right: 1px solid var(--u-border-color-weak, #
|
|
146
|
-
border-bottom: 1px solid var(--u-border-color-weak, #
|
|
148
|
+
border-right: 1px solid var(--u-border-color-weak, #EEEEEE);
|
|
149
|
+
border-bottom: 1px solid var(--u-border-color-weak, #EEEEEE);
|
|
147
150
|
font-size: 13px;
|
|
148
|
-
color: var(--u-txt-color, #
|
|
151
|
+
color: var(--u-txt-color, #212121);
|
|
149
152
|
min-width: 80px;
|
|
150
153
|
overflow: hidden;
|
|
151
154
|
text-overflow: ellipsis;
|
|
@@ -159,13 +162,13 @@ var baseStyles = css`
|
|
|
159
162
|
}
|
|
160
163
|
|
|
161
164
|
.cell.selected {
|
|
162
|
-
background: var(--u-
|
|
165
|
+
background: var(--u-primary-bg-color, #E3F2FD);
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
/* The anchor cell (top-left of selection) */
|
|
166
169
|
.cell.anchor {
|
|
167
|
-
background: var(--u-bg-color, #
|
|
168
|
-
outline: 2px solid var(--u-blue-500, #
|
|
170
|
+
background: var(--u-bg-color, #FFFFFF);
|
|
171
|
+
outline: 2px solid var(--u-blue-500, #2196F3);
|
|
169
172
|
outline-offset: -2px;
|
|
170
173
|
overflow: visible;
|
|
171
174
|
z-index: 1;
|
|
@@ -185,16 +188,16 @@ var baseStyles = css`
|
|
|
185
188
|
min-width: 100%;
|
|
186
189
|
height: calc(100% + 2px);
|
|
187
190
|
border: none;
|
|
188
|
-
outline: 2px solid var(--u-blue-500, #
|
|
191
|
+
outline: 2px solid var(--u-blue-500, #2196F3);
|
|
189
192
|
outline-offset: -1px;
|
|
190
193
|
padding: 0 6px;
|
|
191
194
|
font-size: 13px;
|
|
192
195
|
font-family: inherit;
|
|
193
|
-
color: var(--u-txt-color, #
|
|
194
|
-
background: var(--u-bg-color, #
|
|
196
|
+
color: var(--u-txt-color, #212121);
|
|
197
|
+
background: var(--u-bg-color, #FFFFFF);
|
|
195
198
|
box-sizing: border-box;
|
|
196
199
|
z-index: 10;
|
|
197
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.
|
|
200
|
+
box-shadow: 0 2px 8px var(--u-shadow-color-strong, rgba(0, 0, 0, 0.16));
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
/* Dropdown overlay */
|
|
@@ -206,18 +209,18 @@ var baseStyles = css`
|
|
|
206
209
|
min-width: 120px;
|
|
207
210
|
max-height: 200px;
|
|
208
211
|
overflow-y: auto;
|
|
209
|
-
background: var(--u-bg-color, #
|
|
210
|
-
border: 1px solid var(--u-border-color, #
|
|
212
|
+
background: var(--u-bg-color, #FFFFFF);
|
|
213
|
+
border: 1px solid var(--u-border-color, #E0E0E0);
|
|
211
214
|
border-top: none;
|
|
212
215
|
border-radius: 0 0 4px 4px;
|
|
213
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
216
|
+
box-shadow: 0 4px 12px var(--u-shadow-color-normal, rgba(0, 0, 0, 0.12));
|
|
214
217
|
z-index: 20;
|
|
215
218
|
}
|
|
216
219
|
|
|
217
220
|
.dropdown-item {
|
|
218
221
|
padding: 4px 8px;
|
|
219
222
|
font-size: 13px;
|
|
220
|
-
color: var(--u-txt-color, #
|
|
223
|
+
color: var(--u-txt-color, #212121);
|
|
221
224
|
cursor: pointer;
|
|
222
225
|
white-space: nowrap;
|
|
223
226
|
overflow: hidden;
|
|
@@ -225,18 +228,18 @@ var baseStyles = css`
|
|
|
225
228
|
}
|
|
226
229
|
|
|
227
230
|
.dropdown-item:hover {
|
|
228
|
-
background: var(--u-neutral-100, #
|
|
231
|
+
background: var(--u-neutral-100, #F5F5F5);
|
|
229
232
|
}
|
|
230
233
|
|
|
231
234
|
.dropdown-item.highlighted {
|
|
232
|
-
background: var(--u-
|
|
233
|
-
color: var(--u-blue-800, #
|
|
235
|
+
background: var(--u-primary-bg-color, #E3F2FD);
|
|
236
|
+
color: var(--u-blue-800, #1565C0);
|
|
234
237
|
}
|
|
235
238
|
|
|
236
239
|
.dropdown-empty {
|
|
237
240
|
padding: 6px 8px;
|
|
238
241
|
font-size: 12px;
|
|
239
|
-
color: var(--u-txt-color-weak, #
|
|
242
|
+
color: var(--u-txt-color-weak, #757575);
|
|
240
243
|
font-style: italic;
|
|
241
244
|
}
|
|
242
245
|
|
|
@@ -247,33 +250,33 @@ var baseStyles = css`
|
|
|
247
250
|
|
|
248
251
|
/* Readonly column/cell */
|
|
249
252
|
.cell.cell-readonly {
|
|
250
|
-
background: var(--u-
|
|
251
|
-
color: var(--u-txt-color-weak, #
|
|
253
|
+
background: var(--u-bg-color-disabled, #FAFAFA);
|
|
254
|
+
color: var(--u-txt-color-weak, #757575);
|
|
252
255
|
cursor: default;
|
|
253
256
|
}
|
|
254
257
|
|
|
255
258
|
.cell.cell-readonly.selected {
|
|
256
|
-
background: var(--u-neutral-100, #
|
|
259
|
+
background: var(--u-neutral-100, #F5F5F5);
|
|
257
260
|
}
|
|
258
261
|
|
|
259
262
|
.cell.cell-readonly.anchor {
|
|
260
|
-
background: var(--u-
|
|
263
|
+
background: var(--u-bg-color-disabled, #FAFAFA);
|
|
261
264
|
}
|
|
262
265
|
|
|
263
266
|
/* Computed column/cell */
|
|
264
267
|
.cell.cell-computed {
|
|
265
|
-
background: var(--u-
|
|
266
|
-
color: var(--u-txt-color, #
|
|
268
|
+
background: var(--u-primary-bg-color, #E3F2FD);
|
|
269
|
+
color: var(--u-txt-color, #212121);
|
|
267
270
|
font-style: italic;
|
|
268
271
|
cursor: default;
|
|
269
272
|
}
|
|
270
273
|
|
|
271
274
|
.cell.cell-computed.selected {
|
|
272
|
-
background: var(--u-blue-100, #
|
|
275
|
+
background: var(--u-blue-100, #BBDEFB);
|
|
273
276
|
}
|
|
274
277
|
|
|
275
278
|
.cell.cell-computed.anchor {
|
|
276
|
-
background: var(--u-
|
|
279
|
+
background: var(--u-primary-bg-color, #E3F2FD);
|
|
277
280
|
}
|
|
278
281
|
|
|
279
282
|
/* Readonly mode (whole sheet) */
|
|
@@ -288,122 +291,23 @@ var DARK_PREFIXES = [
|
|
|
288
291
|
":host-context([data-theme=\"dark\"])"
|
|
289
292
|
];
|
|
290
293
|
var darkRules = (host) => `
|
|
291
|
-
${host} .sheet-container {
|
|
292
|
-
background: var(--u-bg-color, #121212);
|
|
293
|
-
border-color: var(--u-border-color, #3D3D3D);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
${host} .sheet-container:focus-within {
|
|
297
|
-
border-color: var(--u-blue-500, #6ba3e3);
|
|
298
|
-
box-shadow: 0 0 0 2px var(--u-blue-100, #1e3a5f);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
${host} .corner {
|
|
302
|
-
background: var(--u-neutral-100, #121212);
|
|
303
|
-
border-color: var(--u-border-color, #3D3D3D);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
${host} .corner:hover {
|
|
307
|
-
background: var(--u-neutral-200, #1E1E1E);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
${host} .col-header {
|
|
311
|
-
background: var(--u-neutral-100, #121212);
|
|
312
|
-
color: var(--u-txt-color-weak, #8A8A8A);
|
|
313
|
-
border-color: var(--u-border-color, #3D3D3D);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
294
|
${host} .col-header.col-selected {
|
|
317
|
-
background: var(--u-blue-100, #
|
|
318
|
-
color: var(--u-blue-800, #c2deff);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
${host} .row-num {
|
|
322
|
-
background: var(--u-neutral-50, #0A0A0A);
|
|
323
|
-
color: var(--u-txt-color-weak, #8A8A8A);
|
|
324
|
-
border-right-color: var(--u-border-color, #3D3D3D);
|
|
325
|
-
border-bottom-color: var(--u-border-color-weak, #2A2A2A);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
${host} .row-num.row-selected {
|
|
329
|
-
background: var(--u-blue-100, #1e3a5f);
|
|
330
|
-
color: var(--u-blue-800, #c2deff);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
${host} .cell {
|
|
334
|
-
color: var(--u-txt-color, #D4D4D4);
|
|
335
|
-
border-right-color: var(--u-border-color-weak, #2A2A2A);
|
|
336
|
-
border-bottom-color: var(--u-border-color-weak, #2A2A2A);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
${host} .cell.cell-readonly {
|
|
340
|
-
background: var(--u-neutral-100, #1E1E1E);
|
|
341
|
-
color: var(--u-txt-color-weak, #8A8A8A);
|
|
295
|
+
background: var(--u-blue-100, #BBDEFB);
|
|
342
296
|
}
|
|
343
297
|
|
|
344
298
|
${host} .cell.cell-readonly.selected {
|
|
345
|
-
background: var(--u-neutral-200, #
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
${host} .cell.cell-readonly.anchor {
|
|
349
|
-
background: var(--u-neutral-100, #1E1E1E);
|
|
299
|
+
background: var(--u-neutral-200, #EEEEEE);
|
|
350
300
|
}
|
|
351
301
|
|
|
352
|
-
${host} .cell.cell-computed {
|
|
353
|
-
background: var(--u-blue-100, #1e3a5f);
|
|
354
|
-
color: var(--u-txt-color, #D4D4D4);
|
|
355
|
-
}
|
|
356
302
|
|
|
357
303
|
${host} .cell.cell-computed.selected {
|
|
358
|
-
background: var(--u-blue-200, #
|
|
304
|
+
background: var(--u-blue-200, #90CAF9);
|
|
359
305
|
}
|
|
360
306
|
|
|
361
307
|
${host} .cell.cell-computed.anchor {
|
|
362
|
-
background: var(--u-blue-100, #
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
${host} .cell.selected {
|
|
366
|
-
background: var(--u-blue-0, #0a1e3d);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
${host} .cell.anchor {
|
|
370
|
-
background: var(--u-bg-color, #121212);
|
|
371
|
-
outline-color: var(--u-blue-500, #6ba3e3);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
${host} .resize-handle:hover::after {
|
|
375
|
-
background: var(--u-blue-500, #6ba3e3);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
${host} .cell-input {
|
|
379
|
-
background: var(--u-bg-color, #121212);
|
|
380
|
-
color: var(--u-txt-color, #D4D4D4);
|
|
381
|
-
outline-color: var(--u-blue-500, #6ba3e3);
|
|
382
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
|
308
|
+
background: var(--u-blue-100, #BBDEFB);
|
|
383
309
|
}
|
|
384
310
|
|
|
385
|
-
${host} .cell-dropdown {
|
|
386
|
-
background: var(--u-bg-color, #121212);
|
|
387
|
-
border-color: var(--u-border-color, #3D3D3D);
|
|
388
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
${host} .dropdown-item {
|
|
392
|
-
color: var(--u-txt-color, #D4D4D4);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
${host} .dropdown-item:hover {
|
|
396
|
-
background: var(--u-neutral-100, #1E1E1E);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
${host} .dropdown-item.highlighted {
|
|
400
|
-
background: var(--u-blue-100, #1e3a5f);
|
|
401
|
-
color: var(--u-blue-800, #c2deff);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
${host} .dropdown-empty {
|
|
405
|
-
color: var(--u-txt-color-weak, #8A8A8A);
|
|
406
|
-
}
|
|
407
311
|
`;
|
|
408
312
|
var styles = [baseStyles, unsafeCSS(DARK_PREFIXES.map(darkRules).join("\n"))];
|
|
409
313
|
//#endregion
|
|
@@ -9,6 +9,19 @@ export declare class URichTable extends LitElement {
|
|
|
9
9
|
currentPage: number;
|
|
10
10
|
loading: boolean;
|
|
11
11
|
emptyMessage: string;
|
|
12
|
+
/** 로딩 표시 문구 */
|
|
13
|
+
loadingMessage: string;
|
|
14
|
+
/** 필터 입력 placeholder */
|
|
15
|
+
filterPlaceholder: string;
|
|
16
|
+
/** 필터 select 의 "전체" 항목 문구 */
|
|
17
|
+
filterAllLabel: string;
|
|
18
|
+
/** 새 행 추가 버튼 문구 */
|
|
19
|
+
addRowLabel: string;
|
|
20
|
+
/**
|
|
21
|
+
* 페이지 정보 문구. (전체, 시작, 끝) 을 받아 문자열을 만든다.
|
|
22
|
+
* 언어마다 어순이 달라 템플릿 문자열이 아니라 함수로 연다.
|
|
23
|
+
*/
|
|
24
|
+
pageInfoFormatter: (total: number, start: number, end: number) => string;
|
|
12
25
|
selectable: boolean;
|
|
13
26
|
editable: boolean;
|
|
14
27
|
addable: boolean;
|
|
@@ -27,6 +40,18 @@ export declare class URichTable extends LitElement {
|
|
|
27
40
|
revertRow(_rowId: string): void;
|
|
28
41
|
setRowError(rowId: string, message: string): void;
|
|
29
42
|
clearRowError(rowId: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* 행의 식별자. 선택·확장·행 오류 상태가 전부 이 값으로 추적된다.
|
|
45
|
+
*
|
|
46
|
+
* ⚠`_id` 는 이 컴포넌트가 **부여하지 않는다.** 소비자가 넣어 주지 않으면 모든 행의
|
|
47
|
+
* `_id` 가 `undefined` 가 되고, Set 은 그 하나만 담으므로 **한 행을 고르면 전부
|
|
48
|
+
* 골라진다.** 그래서 없을 때는 위치를 대신 쓴다 — 다만 위치 기반 식별은 데이터가
|
|
49
|
+
* 재정렬·재페이징되면 **선택이 다른 행으로 옮겨간다.** 정렬/필터/페이지가 소비자
|
|
50
|
+
* 책임인 컴포넌트이므로, 실제 사용에서는 `_id` 를 주는 것이 옳다.
|
|
51
|
+
*/
|
|
52
|
+
private _rowId;
|
|
53
|
+
private _warnedMissingRowId;
|
|
54
|
+
private _warnMissingRowId;
|
|
30
55
|
getSelectedRows(): Record<string, unknown>[];
|
|
31
56
|
render(): TemplateResult;
|
|
32
57
|
private _renderToolbar;
|
|
@@ -15,6 +15,11 @@ var URichTable = class URichTable extends LitElement {
|
|
|
15
15
|
this.currentPage = 1;
|
|
16
16
|
this.loading = false;
|
|
17
17
|
this.emptyMessage = "데이터가 없습니다";
|
|
18
|
+
this.loadingMessage = "로딩 중...";
|
|
19
|
+
this.filterPlaceholder = "필터...";
|
|
20
|
+
this.filterAllLabel = "전체";
|
|
21
|
+
this.addRowLabel = "+ 새 행";
|
|
22
|
+
this.pageInfoFormatter = (total, start, end) => `전체 ${total.toLocaleString()}건 중 ${start}-${end} 표시`;
|
|
18
23
|
this.selectable = false;
|
|
19
24
|
this.editable = false;
|
|
20
25
|
this.addable = false;
|
|
@@ -29,6 +34,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
29
34
|
this.filters = {};
|
|
30
35
|
this.validationErrors = /* @__PURE__ */ new Map();
|
|
31
36
|
this.rowErrors = /* @__PURE__ */ new Map();
|
|
37
|
+
this._warnedMissingRowId = false;
|
|
32
38
|
this._lastSelectedIndex = -1;
|
|
33
39
|
this._onGlobalKeyDown = (e) => {
|
|
34
40
|
if (e.ctrlKey || e.metaKey) {
|
|
@@ -65,7 +71,8 @@ var URichTable = class URichTable extends LitElement {
|
|
|
65
71
|
}
|
|
66
72
|
if (e.key === " " && this.selectable) {
|
|
67
73
|
e.preventDefault();
|
|
68
|
-
const
|
|
74
|
+
const r = this.data[this.focusedCell.rowIndex];
|
|
75
|
+
const rowId = r ? this._rowId(r, this.focusedCell.rowIndex) : void 0;
|
|
69
76
|
if (rowId) this._onRowSelect(rowId);
|
|
70
77
|
}
|
|
71
78
|
if (e.key === "Delete" && this.selectedIds.size > 0) for (const row of this.getSelectedRows()) this.dispatchEvent(new CustomEvent("row-delete", {
|
|
@@ -88,8 +95,28 @@ var URichTable = class URichTable extends LitElement {
|
|
|
88
95
|
next.delete(rowId);
|
|
89
96
|
this.rowErrors = next;
|
|
90
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* 행의 식별자. 선택·확장·행 오류 상태가 전부 이 값으로 추적된다.
|
|
100
|
+
*
|
|
101
|
+
* ⚠`_id` 는 이 컴포넌트가 **부여하지 않는다.** 소비자가 넣어 주지 않으면 모든 행의
|
|
102
|
+
* `_id` 가 `undefined` 가 되고, Set 은 그 하나만 담으므로 **한 행을 고르면 전부
|
|
103
|
+
* 골라진다.** 그래서 없을 때는 위치를 대신 쓴다 — 다만 위치 기반 식별은 데이터가
|
|
104
|
+
* 재정렬·재페이징되면 **선택이 다른 행으로 옮겨간다.** 정렬/필터/페이지가 소비자
|
|
105
|
+
* 책임인 컴포넌트이므로, 실제 사용에서는 `_id` 를 주는 것이 옳다.
|
|
106
|
+
*/
|
|
107
|
+
_rowId(row, index) {
|
|
108
|
+
const id = row._id;
|
|
109
|
+
if (id !== void 0 && id !== null) return String(id);
|
|
110
|
+
this._warnMissingRowId();
|
|
111
|
+
return `#${index}`;
|
|
112
|
+
}
|
|
113
|
+
_warnMissingRowId() {
|
|
114
|
+
if (this._warnedMissingRowId) return;
|
|
115
|
+
this._warnedMissingRowId = true;
|
|
116
|
+
console.warn("[@iyulab/data-components] u-rich-table: 행에 `_id` 가 없어 **위치**로 식별합니다. 데이터가 재정렬·재페이징되면 선택 상태가 다른 행으로 옮겨갑니다. 각 행에 고유한 `_id` 를 부여하세요.");
|
|
117
|
+
}
|
|
91
118
|
getSelectedRows() {
|
|
92
|
-
return this.data.filter((row) => this.selectedIds.has(row
|
|
119
|
+
return this.data.filter((row, i) => this.selectedIds.has(this._rowId(row, i)));
|
|
93
120
|
}
|
|
94
121
|
render() {
|
|
95
122
|
return html`
|
|
@@ -122,7 +149,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
122
149
|
<div style="flex:1"></div>
|
|
123
150
|
<slot name="toolbar-end"></slot>
|
|
124
151
|
${this.addable ? html`
|
|
125
|
-
<button class="btn btn-success" @click=${this._onAddRowClick}
|
|
152
|
+
<button class="btn btn-success" @click=${this._onAddRowClick}>${this.addRowLabel}</button>
|
|
126
153
|
` : ""}
|
|
127
154
|
</div>
|
|
128
155
|
`;
|
|
@@ -157,10 +184,10 @@ var URichTable = class URichTable extends LitElement {
|
|
|
157
184
|
${this.columns.map((col) => html`
|
|
158
185
|
<td>
|
|
159
186
|
${col.filterable !== false ? col.filterType === "select" && col.options ? html`<select @change=${(e) => this._onFilterChange(col.key, e.target.value)}>
|
|
160
|
-
<option value=""
|
|
187
|
+
<option value="">${this.filterAllLabel}</option>
|
|
161
188
|
${col.options.map((o) => html`<option value=${o.value}>${o.label}</option>`)}
|
|
162
189
|
</select>` : html`<input
|
|
163
|
-
placeholder
|
|
190
|
+
placeholder=${this.filterPlaceholder}
|
|
164
191
|
@input=${(e) => this._onFilterChange(col.key, e.target.value)} />` : ""}
|
|
165
192
|
</td>
|
|
166
193
|
`)}
|
|
@@ -169,10 +196,10 @@ var URichTable = class URichTable extends LitElement {
|
|
|
169
196
|
`;
|
|
170
197
|
}
|
|
171
198
|
_renderBody() {
|
|
172
|
-
if (this.loading) return html`<tr><td colspan=${this._colSpan()}><div class="loading-overlay"
|
|
199
|
+
if (this.loading) return html`<tr><td colspan=${this._colSpan()}><div class="loading-overlay">${this.loadingMessage}</div></td></tr>`;
|
|
173
200
|
if (this.data.length === 0) return html`<tr><td colspan=${this._colSpan()}><div class="empty-message">${this.emptyMessage}</div></td></tr>`;
|
|
174
201
|
return this.data.map((row, rowIdx) => {
|
|
175
|
-
const rowId = row
|
|
202
|
+
const rowId = this._rowId(row, rowIdx);
|
|
176
203
|
const isSelected = this.selectedIds.has(rowId);
|
|
177
204
|
const isExpanded = this.expandedIds.has(rowId);
|
|
178
205
|
const hasError = this.rowErrors.has(rowId);
|
|
@@ -192,7 +219,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
192
219
|
` : ""}
|
|
193
220
|
${this.columns.map((col, colIdx) => this._renderCell(row, rowIdx, col, colIdx))}
|
|
194
221
|
<td class="actions-cell">
|
|
195
|
-
<span
|
|
222
|
+
<span class="row-menu" @click=${() => this._onRowMenu(row)}>⋯</span>
|
|
196
223
|
</td>
|
|
197
224
|
</tr>
|
|
198
225
|
${isExpanded && this.detailRenderer ? html`
|
|
@@ -201,7 +228,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
201
228
|
</tr>
|
|
202
229
|
` : ""}
|
|
203
230
|
${hasError ? html`
|
|
204
|
-
<tr><td colspan=${this._colSpan()}
|
|
231
|
+
<tr><td colspan=${this._colSpan()} class="row-error-cell">
|
|
205
232
|
${this.rowErrors.get(rowId)}
|
|
206
233
|
</td></tr>
|
|
207
234
|
` : ""}
|
|
@@ -264,7 +291,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
264
291
|
_renderNewRow() {
|
|
265
292
|
return html`
|
|
266
293
|
<tr class="new-row">
|
|
267
|
-
${this.selectable ? html`<td class="checkbox-cell"><span
|
|
294
|
+
${this.selectable ? html`<td class="checkbox-cell"><span class="new-row-marker">+</span></td>` : ""}
|
|
268
295
|
${this.expandable ? html`<td></td>` : ""}
|
|
269
296
|
${this.columns.map((col, colIdx) => html`
|
|
270
297
|
<td>
|
|
@@ -287,7 +314,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
287
314
|
const end = Math.min(this.currentPage * this.pageSize, this.totalCount);
|
|
288
315
|
return html`
|
|
289
316
|
<div class="pagination">
|
|
290
|
-
<span
|
|
317
|
+
<span>${this.pageInfoFormatter(this.totalCount, start, end)}</span>
|
|
291
318
|
<div class="page-buttons">
|
|
292
319
|
<button ?disabled=${this.currentPage <= 1} @click=${() => this._onPageChange(this.currentPage - 1)}>◀</button>
|
|
293
320
|
${this._getPageNumbers(totalPages).map((p) => html`
|
|
@@ -306,7 +333,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
306
333
|
`;
|
|
307
334
|
}
|
|
308
335
|
_onSelectAll(e) {
|
|
309
|
-
if (e.target.checked) this.selectedIds = new Set(this.data.map((r) => r
|
|
336
|
+
if (e.target.checked) this.selectedIds = new Set(this.data.map((r, i) => this._rowId(r, i)));
|
|
310
337
|
else this.selectedIds = /* @__PURE__ */ new Set();
|
|
311
338
|
this._fireSelectionChange();
|
|
312
339
|
}
|
|
@@ -322,7 +349,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
322
349
|
const start = Math.min(this._lastSelectedIndex, rowIdx);
|
|
323
350
|
const end = Math.max(this._lastSelectedIndex, rowIdx);
|
|
324
351
|
const next = new Set(this.selectedIds);
|
|
325
|
-
for (let i = start; i <= end; i++) next.add(this.data[i]
|
|
352
|
+
for (let i = start; i <= end; i++) next.add(this._rowId(this.data[i], i));
|
|
326
353
|
this.selectedIds = next;
|
|
327
354
|
this._fireSelectionChange();
|
|
328
355
|
}
|
|
@@ -445,7 +472,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
445
472
|
this.expandedIds = next;
|
|
446
473
|
this.dispatchEvent(new CustomEvent("row-expand", {
|
|
447
474
|
detail: {
|
|
448
|
-
row: this.data.find((r) => r
|
|
475
|
+
row: this.data.find((r, i) => this._rowId(r, i) === rowId),
|
|
449
476
|
expanded
|
|
450
477
|
},
|
|
451
478
|
bubbles: true,
|
|
@@ -588,7 +615,7 @@ var URichTable = class URichTable extends LitElement {
|
|
|
588
615
|
};
|
|
589
616
|
}
|
|
590
617
|
_selectAll() {
|
|
591
|
-
this.selectedIds = new Set(this.data.map((r) => r
|
|
618
|
+
this.selectedIds = new Set(this.data.map((r, i) => this._rowId(r, i)));
|
|
592
619
|
this._fireSelectionChange();
|
|
593
620
|
}
|
|
594
621
|
static define(tagName = "u-rich-table") {
|
|
@@ -602,6 +629,11 @@ __decorate([property({ type: Number }), __decorateMetadata("design:type", Object
|
|
|
602
629
|
__decorate([property({ type: Number }), __decorateMetadata("design:type", Object)], URichTable.prototype, "currentPage", void 0);
|
|
603
630
|
__decorate([property({ type: Boolean }), __decorateMetadata("design:type", Object)], URichTable.prototype, "loading", void 0);
|
|
604
631
|
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], URichTable.prototype, "emptyMessage", void 0);
|
|
632
|
+
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], URichTable.prototype, "loadingMessage", void 0);
|
|
633
|
+
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], URichTable.prototype, "filterPlaceholder", void 0);
|
|
634
|
+
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], URichTable.prototype, "filterAllLabel", void 0);
|
|
635
|
+
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], URichTable.prototype, "addRowLabel", void 0);
|
|
636
|
+
__decorate([property({ attribute: false }), __decorateMetadata("design:type", Function)], URichTable.prototype, "pageInfoFormatter", void 0);
|
|
605
637
|
__decorate([property({ type: Boolean }), __decorateMetadata("design:type", Object)], URichTable.prototype, "selectable", void 0);
|
|
606
638
|
__decorate([property({ type: Boolean }), __decorateMetadata("design:type", Object)], URichTable.prototype, "editable", void 0);
|
|
607
639
|
__decorate([property({ type: Boolean }), __decorateMetadata("design:type", Object)], URichTable.prototype, "addable", void 0);
|