@coreui/data-grid 0.1.0-rc.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 (101) hide show
  1. package/LICENSE +3 -0
  2. package/README.md +37 -0
  3. package/dist/css/data-grid.css +444 -0
  4. package/dist/css/data-grid.css.map +1 -0
  5. package/dist/css/data-grid.min.css +5 -0
  6. package/dist/css/data-grid.min.css.map +1 -0
  7. package/dist/js/csv.cjs +68 -0
  8. package/dist/js/csv.cjs.map +1 -0
  9. package/dist/js/csv.mjs +63 -0
  10. package/dist/js/csv.mjs.map +1 -0
  11. package/dist/js/data-grid.esm.js +9618 -0
  12. package/dist/js/data-grid.esm.js.map +1 -0
  13. package/dist/js/data-grid.esm.min.js +8 -0
  14. package/dist/js/data-grid.esm.min.js.map +1 -0
  15. package/dist/js/data-grid.js +9635 -0
  16. package/dist/js/data-grid.js.map +1 -0
  17. package/dist/js/data-grid.min.js +8 -0
  18. package/dist/js/data-grid.min.js.map +1 -0
  19. package/dist/js/data-grid.mjs +9618 -0
  20. package/dist/js/data-grid.mjs.map +1 -0
  21. package/dist/js/filters.cjs +143 -0
  22. package/dist/js/filters.cjs.map +1 -0
  23. package/dist/js/filters.mjs +137 -0
  24. package/dist/js/filters.mjs.map +1 -0
  25. package/dist/js/labels.cjs +76 -0
  26. package/dist/js/labels.cjs.map +1 -0
  27. package/dist/js/labels.mjs +71 -0
  28. package/dist/js/labels.mjs.map +1 -0
  29. package/dist/types/base-component.d.ts +19 -0
  30. package/dist/types/data-grid.d.ts +128 -0
  31. package/dist/types/dom/event-handler.d.ts +11 -0
  32. package/dist/types/dom/manipulator.d.ts +9 -0
  33. package/dist/types/engine/active-cell.d.ts +32 -0
  34. package/dist/types/engine/data-source.d.ts +19 -0
  35. package/dist/types/engine/scheduler.d.ts +11 -0
  36. package/dist/types/engine/table.d.ts +9 -0
  37. package/dist/types/engine/virtualizer.d.ts +21 -0
  38. package/dist/types/filters.d.mts +1 -0
  39. package/dist/types/filters.d.ts +13 -0
  40. package/dist/types/icons.d.ts +21 -0
  41. package/dist/types/index.d.mts +1 -0
  42. package/dist/types/index.d.ts +12 -0
  43. package/dist/types/labels.d.mts +1 -0
  44. package/dist/types/labels.d.ts +9 -0
  45. package/dist/types/types.d.ts +262 -0
  46. package/dist/types/ui/body.d.ts +34 -0
  47. package/dist/types/ui/column-chooser.d.ts +27 -0
  48. package/dist/types/ui/editor.d.ts +8 -0
  49. package/dist/types/ui/filter-menu.d.ts +21 -0
  50. package/dist/types/ui/header.d.ts +50 -0
  51. package/dist/types/ui/loading.d.ts +12 -0
  52. package/dist/types/ui/menu.d.ts +17 -0
  53. package/dist/types/ui/pagination.d.ts +17 -0
  54. package/dist/types/ui/pinning.d.ts +17 -0
  55. package/dist/types/ui/toolbar.d.ts +34 -0
  56. package/dist/types/ui/tooltip.d.ts +10 -0
  57. package/dist/types/util/config.d.ts +11 -0
  58. package/dist/types/util/csv.d.mts +1 -0
  59. package/dist/types/util/csv.d.ts +19 -0
  60. package/dist/types/util/debounce.d.ts +7 -0
  61. package/dist/types/util/index.d.ts +10 -0
  62. package/dist/types/util/sanitizer.d.ts +11 -0
  63. package/package.json +147 -0
  64. package/scss/data-grid.scss +559 -0
  65. package/src/base-component.d.ts +19 -0
  66. package/src/base-component.js +90 -0
  67. package/src/data-grid.ts +2208 -0
  68. package/src/dom/data.js +59 -0
  69. package/src/dom/event-handler.d.ts +11 -0
  70. package/src/dom/event-handler.js +331 -0
  71. package/src/dom/manipulator.d.ts +9 -0
  72. package/src/dom/manipulator.js +75 -0
  73. package/src/engine/active-cell.ts +195 -0
  74. package/src/engine/data-source.ts +63 -0
  75. package/src/engine/scheduler.ts +42 -0
  76. package/src/engine/table.ts +122 -0
  77. package/src/engine/virtualizer.ts +57 -0
  78. package/src/filters.ts +176 -0
  79. package/src/icons.ts +60 -0
  80. package/src/index.ts +56 -0
  81. package/src/labels.ts +70 -0
  82. package/src/types.ts +334 -0
  83. package/src/ui/body.ts +348 -0
  84. package/src/ui/column-chooser.ts +183 -0
  85. package/src/ui/editor.ts +98 -0
  86. package/src/ui/filter-menu.ts +398 -0
  87. package/src/ui/header.ts +441 -0
  88. package/src/ui/loading.ts +39 -0
  89. package/src/ui/menu.ts +218 -0
  90. package/src/ui/pagination.ts +150 -0
  91. package/src/ui/pinning.ts +53 -0
  92. package/src/ui/toolbar.ts +144 -0
  93. package/src/ui/tooltip.ts +113 -0
  94. package/src/util/config.d.ts +11 -0
  95. package/src/util/config.js +69 -0
  96. package/src/util/csv.ts +85 -0
  97. package/src/util/debounce.ts +18 -0
  98. package/src/util/index.d.ts +10 -0
  99. package/src/util/index.js +310 -0
  100. package/src/util/sanitizer.d.ts +11 -0
  101. package/src/util/sanitizer.js +162 -0
@@ -0,0 +1,559 @@
1
+ /*!
2
+ * CoreUI PRO data-grid.scss v0.1.0
3
+ * License (https://coreui.io/pro/license/)
4
+ */
5
+
6
+ .data-grid {
7
+ // The column menu is positioned against the grid root (it must escape the
8
+ // viewport's overflow while staying inside the token scope).
9
+ position: relative;
10
+
11
+ // Component tokens. Everything resolves through CoreUI semantic variables,
12
+ // so light/dark theming via [data-coreui-theme] works with no extra rules.
13
+ --cui-data-grid-viewport-max-height: 30rem;
14
+ --cui-data-grid-header-bg: var(--cui-body-bg, #fff);
15
+ --cui-data-grid-header-shadow: inset 0 calc(-1 * var(--cui-border-width, 1px)) 0 var(--cui-border-color, #dee2e6);
16
+ --cui-data-grid-select-cell-width: 2.5rem;
17
+ --cui-data-grid-sorter-margin: .25rem;
18
+ --cui-data-grid-sorter-opacity: .3;
19
+ --cui-data-grid-spacing: .5rem;
20
+ --cui-data-grid-resizer-width: .625rem;
21
+ --cui-data-grid-resizer-grip-height: 60%;
22
+ --cui-data-grid-resizer-grip-color: var(--cui-border-color, #dee2e6);
23
+ --cui-data-grid-resizer-grip-color-hover: var(--cui-secondary-color, #6c757d);
24
+ --cui-data-grid-pinned-border-width: var(--cui-border-width);
25
+ --cui-data-grid-pinned-border-color: var(--cui-border-color, #dee2e6);
26
+ --cui-data-grid-drop-indicator: var(--cui-primary, #321fdb);
27
+ --cui-data-grid-menu-bg: var(--cui-body-bg, #fff);
28
+ --cui-data-grid-menu-border-color: var(--cui-border-color, #dee2e6);
29
+ --cui-data-grid-menu-shadow: var(--cui-box-shadow, 0 .5rem 1rem rgba(0, 0, 0, .15));
30
+ --cui-data-grid-menu-min-width: 10rem;
31
+ --cui-data-grid-menu-item-hover-bg: var(--cui-tertiary-bg, #f8f9fa);
32
+ --cui-data-grid-loading-bg: rgba(var(--cui-body-bg-rgb, 255, 255, 255), .6);
33
+ --cui-data-grid-pinned-bg: var(--cui-body-bg, #fff);
34
+ --cui-data-grid-focus-ring-width: 2px;
35
+ --cui-data-grid-focus-ring-color: var(--cui-primary, #321fdb);
36
+
37
+ .data-grid-toolbar {
38
+ display: flex;
39
+ flex-wrap: wrap;
40
+ gap: var(--cui-data-grid-spacing);
41
+ align-items: center;
42
+ min-height: 48px;
43
+ padding: var(--cui-data-grid-spacing);
44
+ border-bottom: var(--cui-border-width, 1px) solid var(--cui-border-color, #dee2e6);
45
+ }
46
+
47
+ .data-grid-toolbar-actions {
48
+ display: flex;
49
+ gap: .25rem;
50
+ align-items: center;
51
+ }
52
+
53
+ .data-grid-toolbar-search {
54
+ margin-inline-start: auto;
55
+ }
56
+
57
+ .data-grid-viewport {
58
+ position: relative;
59
+ max-height: var(--cui-data-grid-viewport-max-height);
60
+ overflow-y: auto;
61
+ // Windowed rendering resizes the spacer rows and recycles row elements on
62
+ // every frame; browser scroll anchoring chases those mutations and keeps
63
+ // adjusting scrollTop, which turns wheel scrolling into a feedback loop.
64
+ overflow-anchor: none;
65
+ }
66
+
67
+ // Inline editing: the in-cell editor fills the cell; the popup layer hosts
68
+ // rich editors (date pickers, selects) anchored over the cell.
69
+ .data-grid-cell-editor {
70
+ width: 100%;
71
+ min-width: 4rem;
72
+ }
73
+
74
+ .data-grid-editor-popup {
75
+ position: absolute;
76
+ z-index: 4;
77
+ padding: .25rem;
78
+ background-color: var(--cui-data-grid-menu-bg);
79
+ border: var(--cui-border-width, 1px) solid var(--cui-data-grid-menu-border-color);
80
+ border-radius: var(--cui-border-radius, .375rem);
81
+ box-shadow: var(--cui-data-grid-menu-shadow);
82
+ }
83
+
84
+ // cellNavigation: the roving-tabindex active cell. The ring is inset so the
85
+ // sticky header and pinned columns don't clip it.
86
+ [role="grid"] :is(td, th):focus-visible {
87
+ outline: var(--cui-data-grid-focus-ring-width) solid var(--cui-data-grid-focus-ring-color);
88
+ outline-offset: calc(-1 * var(--cui-data-grid-focus-ring-width));
89
+ }
90
+
91
+ .data-grid-viewport:focus-visible {
92
+ outline: 0;
93
+ }
94
+
95
+ .data-grid-header {
96
+ position: sticky;
97
+ top: 0;
98
+ z-index: 2;
99
+ background-color: var(--cui-data-grid-header-bg);
100
+ box-shadow: var(--cui-data-grid-header-shadow);
101
+ }
102
+
103
+ // Header label row: fixed 48px with vertically centered content (height on a
104
+ // table cell acts as a min; min-height is ignored on table-cell).
105
+ .data-grid-header tr:not(.data-grid-filter-row) > th {
106
+ height: 48px;
107
+ vertical-align: middle;
108
+ }
109
+
110
+ .data-grid-filter-row > th {
111
+ padding-top: 0;
112
+ font-weight: normal;
113
+ }
114
+
115
+ .data-grid-header th[data-coreui-draggable] {
116
+ cursor: grab;
117
+ }
118
+
119
+ .data-grid-header-cell {
120
+ display: flex;
121
+ align-items: center;
122
+ gap: .25rem;
123
+ }
124
+
125
+ .data-grid-header-label {
126
+ overflow: hidden;
127
+ text-overflow: ellipsis;
128
+ white-space: nowrap;
129
+ }
130
+
131
+ // Icon-only ghost buttons: square them by matching horizontal padding to
132
+ // vertical (follows .btn / .btn-sm automatically) and collapsing the text
133
+ // line-height so height follows the icon, not a 1.5em text line.
134
+ .btn-ghost {
135
+ --cui-btn-padding-x: var(--cui-btn-padding-y);
136
+ --cui-btn-line-height: 1;
137
+ }
138
+
139
+ .data-grid-menu-button {
140
+ margin-inline-start: auto;
141
+ }
142
+
143
+ .data-grid-menu {
144
+ position: absolute;
145
+ z-index: 4;
146
+ min-width: var(--cui-data-grid-menu-min-width);
147
+ padding: .25rem 0;
148
+ background-color: var(--cui-data-grid-menu-bg);
149
+ border: var(--cui-border-width, 1px) solid var(--cui-data-grid-menu-border-color);
150
+ border-radius: var(--cui-border-radius, .375rem);
151
+ box-shadow: var(--cui-data-grid-menu-shadow);
152
+ }
153
+
154
+ .data-grid-menu-item {
155
+ display: flex;
156
+ align-items: center;
157
+ gap: .5rem;
158
+ width: 100%;
159
+ padding: .25rem .75rem;
160
+ font: inherit;
161
+ color: inherit;
162
+ text-align: start;
163
+ cursor: pointer;
164
+ background: none;
165
+ border: 0;
166
+
167
+ &:hover,
168
+ &:focus-visible {
169
+ background-color: var(--cui-data-grid-menu-item-hover-bg);
170
+ }
171
+
172
+ // Disabled items stay focusable (aria-disabled, APG menu pattern) so the
173
+ // roving arrow cycle can reach them.
174
+ &[aria-disabled="true"] {
175
+ color: var(--cui-secondary-color, #6c757d);
176
+ cursor: default;
177
+ background: none;
178
+ }
179
+ }
180
+
181
+ .data-grid-filter-menu {
182
+ position: absolute;
183
+ z-index: 4;
184
+ display: flex;
185
+ flex-direction: column;
186
+ gap: .5rem;
187
+ min-width: var(--cui-data-grid-menu-min-width);
188
+ max-width: 18rem;
189
+ padding: .75rem;
190
+ background-color: var(--cui-data-grid-menu-bg);
191
+ border: var(--cui-border-width, 1px) solid var(--cui-data-grid-menu-border-color);
192
+ border-radius: var(--cui-border-radius, .375rem);
193
+ box-shadow: var(--cui-data-grid-menu-shadow);
194
+
195
+ > div {
196
+ display: flex;
197
+ flex-direction: column;
198
+ gap: .5rem;
199
+ }
200
+ }
201
+
202
+ .data-grid-filter-menu-condition {
203
+ display: flex;
204
+ flex-direction: column;
205
+ gap: .25rem;
206
+ }
207
+
208
+ .data-grid-filter-menu-join {
209
+ display: flex;
210
+ gap: 1rem;
211
+
212
+ label {
213
+ display: flex;
214
+ gap: .375rem;
215
+ align-items: center;
216
+ }
217
+ }
218
+
219
+ .data-grid-filter-menu-values {
220
+ display: flex;
221
+ flex-direction: column;
222
+ gap: .25rem;
223
+ max-height: 14rem;
224
+ overflow-y: auto;
225
+ }
226
+
227
+ .data-grid-filter-menu-footer {
228
+ display: flex;
229
+ gap: .5rem;
230
+ justify-content: flex-end;
231
+ }
232
+
233
+ .data-grid-column-chooser {
234
+ position: absolute;
235
+ z-index: 4;
236
+ display: flex;
237
+ flex-direction: column;
238
+ gap: .5rem;
239
+ min-width: var(--cui-data-grid-menu-min-width);
240
+ max-width: 18rem;
241
+ max-height: 20rem;
242
+ padding: .75rem;
243
+ overflow-y: auto;
244
+ background-color: var(--cui-data-grid-menu-bg);
245
+ border: var(--cui-border-width, 1px) solid var(--cui-data-grid-menu-border-color);
246
+ border-radius: var(--cui-border-radius, .375rem);
247
+ box-shadow: var(--cui-data-grid-menu-shadow);
248
+ }
249
+
250
+ .data-grid-column-chooser-option {
251
+ display: flex;
252
+ gap: .375rem;
253
+ align-items: center;
254
+ margin-bottom: 0;
255
+ }
256
+
257
+ .data-grid-column-chooser-footer {
258
+ display: flex;
259
+ gap: .5rem;
260
+ justify-content: flex-end;
261
+ padding-top: .25rem;
262
+ margin-top: .25rem;
263
+ border-top: var(--cui-border-width, 1px) solid var(--cui-data-grid-menu-border-color);
264
+ }
265
+
266
+ .data-grid-filter-button {
267
+ position: relative;
268
+ // Right-align the trailing controls as a group: the filter button takes the
269
+ // auto margin (menu drops its own below) so filter and menu sit together at
270
+ // the end, matching a menu-only header.
271
+ margin-inline-start: auto;
272
+
273
+ ~ .data-grid-menu-button {
274
+ margin-inline-start: 0;
275
+ }
276
+ }
277
+
278
+ // Active-filter indicator dot on the filter button.
279
+ .data-grid-filter-button-filtered::after {
280
+ position: absolute;
281
+ inset-block-start: .125rem;
282
+ inset-inline-end: .125rem;
283
+ width: .375rem;
284
+ height: .375rem;
285
+ content: "";
286
+ background-color: var(--cui-primary, #321fdb);
287
+ border-radius: 50%;
288
+ }
289
+
290
+ .data-grid-menu-item-icon {
291
+ display: inline-flex;
292
+ opacity: .75;
293
+
294
+ svg {
295
+ width: 1em;
296
+ height: 1em;
297
+ }
298
+ }
299
+
300
+ .data-grid-menu-divider {
301
+ height: var(--cui-border-width, 1px);
302
+ margin: .25rem 0;
303
+ background-color: var(--cui-data-grid-menu-border-color);
304
+ }
305
+
306
+ .data-grid-header .data-grid-dragging {
307
+ opacity: .5;
308
+ }
309
+
310
+ .data-grid-header .data-grid-drop-target {
311
+ box-shadow: inset .125rem 0 0 var(--cui-data-grid-drop-indicator);
312
+ }
313
+
314
+ .data-grid-select-cell {
315
+ width: var(--cui-data-grid-select-cell-width);
316
+ text-align: center;
317
+ }
318
+
319
+ .data-grid-sort-button {
320
+ display: inline-flex;
321
+ align-items: center;
322
+ gap: var(--cui-data-grid-sorter-margin);
323
+ padding: 0;
324
+ font: inherit;
325
+ color: inherit;
326
+ cursor: pointer;
327
+ user-select: none;
328
+ background: none;
329
+ border: 0;
330
+ }
331
+
332
+ .data-grid-sort-icon {
333
+ display: inline-flex;
334
+ font-size: .875em;
335
+ opacity: 0;
336
+
337
+ svg {
338
+ width: 1em;
339
+ height: 1em;
340
+ }
341
+ }
342
+
343
+ // The active sort direction is always visible; the neutral (unsorted) icon is
344
+ // hidden unless `sorterVisibility` opts it in (steadily via "always", or on
345
+ // header hover/focus via "hover").
346
+ .data-grid-sortable[aria-sort] .data-grid-sort-icon {
347
+ opacity: 1;
348
+ }
349
+
350
+ &[data-coreui-sorter-visibility="always"] .data-grid-sortable:not([aria-sort]) .data-grid-sort-icon {
351
+ opacity: var(--cui-data-grid-sorter-opacity);
352
+ }
353
+
354
+ &[data-coreui-sorter-visibility="hover"] .data-grid-sortable:not([aria-sort]):hover .data-grid-sort-icon,
355
+ &[data-coreui-sorter-visibility="hover"] .data-grid-sortable:not([aria-sort]):focus-within .data-grid-sort-icon {
356
+ opacity: var(--cui-data-grid-sorter-opacity);
357
+ }
358
+
359
+ .data-grid-viewport > .table {
360
+ margin-bottom: 0;
361
+ table-layout: fixed;
362
+ }
363
+
364
+ // Body cells render on a single line and truncate with an ellipsis instead of
365
+ // spilling their content across the fixed-layout column boundary onto the next
366
+ // column. Matches the default of AG Grid / MUI X Data Grid and TanStack's
367
+ // virtualized-table guidance, and keeps every row a uniform height for the
368
+ // fixed-height virtualizer (wrapping would desync `estimateSize`). Pinned cells
369
+ // are excluded so their shadow pseudo-element (painted outside the box via a
370
+ // translate) isn't clipped; the select cell holds only a checkbox.
371
+ .data-grid-viewport > .table > tbody > tr:not(.data-grid-empty) > td:not(.data-grid-select-cell):not(.data-grid-cell-pinned-left):not(.data-grid-cell-pinned-right) {
372
+ overflow: hidden;
373
+ text-overflow: ellipsis;
374
+ white-space: nowrap;
375
+ }
376
+
377
+ // Widths applied to each header cell drive the column layout; letting the
378
+ // table grow to its content (min-width keeps it filling a wide viewport)
379
+ // turns a resize or a pin into horizontal scroll rather than squeezing
380
+ // neighbours. Both features share this layout mode.
381
+ &.data-grid-resizable,
382
+ &.data-grid-pinned {
383
+ .data-grid-viewport {
384
+ overflow-x: auto;
385
+ }
386
+
387
+ .table {
388
+ width: max-content;
389
+ min-width: 100%;
390
+ }
391
+ }
392
+
393
+ // A pinned th is already sticky (a positioned containing block for the
394
+ // resizer), so only non-pinned header cells need explicit relative here.
395
+ &.data-grid-resizable .data-grid-header th:not(.data-grid-cell-pinned-left):not(.data-grid-cell-pinned-right) {
396
+ position: relative;
397
+ }
398
+
399
+ &.data-grid-pinned .table {
400
+ // position: sticky is unreliable on collapsed-border tables; the grid opts
401
+ // into separate borders so pinned cells stay put on horizontal scroll.
402
+ border-collapse: separate;
403
+ border-spacing: 0;
404
+ }
405
+
406
+ .data-grid-cell-pinned-left,
407
+ .data-grid-cell-pinned-right {
408
+ position: sticky;
409
+ z-index: 1;
410
+ background-color: var(--cui-data-grid-pinned-bg);
411
+ }
412
+
413
+ .data-grid-header .data-grid-cell-pinned-left,
414
+ .data-grid-header .data-grid-cell-pinned-right {
415
+ z-index: 3;
416
+ }
417
+
418
+ // Edge cells cast a shadow over the scrolling content. A pseudo-element is
419
+ // used because the cell's own box-shadow carries the table striping accent.
420
+ .data-grid-cell-pinned-left-last,
421
+ .data-grid-cell-pinned-right-first {
422
+ position: sticky;
423
+
424
+ &::after {
425
+ position: absolute;
426
+ top: 0;
427
+ bottom: 0;
428
+ width: var(--cui-data-grid-pinned-border-width);
429
+ pointer-events: none;
430
+ content: "";
431
+ }
432
+ }
433
+
434
+ .data-grid-cell-pinned-left-last::after {
435
+ right: 0;
436
+ background: var(--cui-data-grid-pinned-border-color);
437
+ }
438
+
439
+ .data-grid-cell-pinned-right-first::after {
440
+ left: 0;
441
+ background: var(--cui-data-grid-pinned-border-color);
442
+ }
443
+
444
+ .data-grid-resizer {
445
+ position: absolute;
446
+ top: 0;
447
+ right: calc(-.5 * var(--cui-data-grid-resizer-width));
448
+ z-index: 1;
449
+ display: flex;
450
+ align-items: center;
451
+ justify-content: center;
452
+ width: var(--cui-data-grid-resizer-width);
453
+ height: 100%;
454
+ cursor: col-resize;
455
+ touch-action: none;
456
+ user-select: none;
457
+
458
+ // Always-visible grip so the resizable edge is discoverable, not just a
459
+ // bare hover target.
460
+ &::after {
461
+ width: 2px;
462
+ height: var(--cui-data-grid-resizer-grip-height);
463
+ content: "";
464
+ background-color: var(--cui-data-grid-resizer-grip-color);
465
+ transition: background-color .15s ease;
466
+ }
467
+
468
+ &:hover::after,
469
+ &.data-grid-resizer-active::after {
470
+ background-color: var(--cui-data-grid-resizer-grip-color-hover);
471
+ }
472
+ }
473
+
474
+ .data-grid-spacer > td {
475
+ padding: 0;
476
+ border: 0;
477
+ }
478
+
479
+ // Spacer rows break `nth-of-type` striping, so striping inside the grid is
480
+ // driven by the absolute row index (.data-grid-row-odd) instead.
481
+ .data-grid-viewport > .table-striped > tbody > tr:nth-of-type(odd) > * {
482
+ --cui-table-color-type: initial;
483
+ --cui-table-bg-type: initial;
484
+ }
485
+
486
+ .data-grid-viewport > .table-striped > tbody > tr.data-grid-row-odd > * {
487
+ --cui-table-color-type: var(--cui-table-striped-color);
488
+ --cui-table-bg-type: var(--cui-table-striped-bg);
489
+ }
490
+
491
+ // The last row closes on the viewport edge (or the pagination border), so it
492
+ // doesn't need its own separator line.
493
+ .data-grid-viewport > .table > tbody > tr:last-child > * {
494
+ border-bottom-width: 0;
495
+ }
496
+
497
+ .data-grid-loading {
498
+ position: absolute;
499
+ inset: 0;
500
+ z-index: 3;
501
+ display: flex;
502
+ align-items: center;
503
+ justify-content: center;
504
+ background-color: var(--cui-data-grid-loading-bg);
505
+ }
506
+
507
+ // Shared icon-button tooltip. position: fixed (set in JS) so it escapes the
508
+ // viewport overflow; theme-inverted like CoreUI's own tooltip.
509
+ .data-grid-tooltip {
510
+ position: fixed;
511
+ z-index: 1080;
512
+ max-width: 12rem;
513
+ padding: .25rem .5rem;
514
+ font-size: .875rem;
515
+ line-height: 1.4;
516
+ color: var(--cui-body-bg, #fff);
517
+ text-align: center;
518
+ pointer-events: none;
519
+ background-color: var(--cui-emphasis-color, #000);
520
+ border-radius: var(--cui-border-radius, .375rem);
521
+ }
522
+
523
+ .data-grid-empty > td {
524
+ padding: 2rem 1rem;
525
+ color: var(--cui-secondary-color, #6c757d);
526
+ text-align: center;
527
+ }
528
+
529
+ .data-grid-pagination {
530
+ display: flex;
531
+ // Wrap the page controls, count and page-size select onto multiple rows on
532
+ // narrow viewports; without this the fixed row overflows and scrolls the page
533
+ // instead of staying inside the grid.
534
+ flex-wrap: wrap;
535
+ gap: var(--cui-data-grid-spacing);
536
+ align-items: center;
537
+ min-height: 48px;
538
+ padding: var(--cui-data-grid-spacing);
539
+ border-top: var(--cui-border-width, 1px) solid var(--cui-border-color, #dee2e6);
540
+
541
+ &.data-grid-pagination-top {
542
+ border-top: 0;
543
+ border-bottom: var(--cui-border-width, 1px) solid var(--cui-border-color, #dee2e6);
544
+ }
545
+
546
+ .pagination {
547
+ margin-bottom: 0;
548
+ }
549
+
550
+ .data-grid-pagination-info {
551
+ margin-inline-start: auto;
552
+ color: var(--cui-secondary-color, #6c757d);
553
+ }
554
+
555
+ .form-select {
556
+ width: auto;
557
+ }
558
+ }
559
+ }
@@ -0,0 +1,19 @@
1
+ // Hand-written types for the vendored base-component.js (see the provenance header there)
2
+ import Config from './util/config.js'
3
+
4
+ export default class BaseComponent extends Config {
5
+ constructor(element: Element | string, config?: unknown)
6
+
7
+ _element: HTMLElement
8
+ _config: any
9
+
10
+ dispose(): void
11
+ _queueCallback(callback: () => void, element: Element, isAnimated?: boolean): void
12
+
13
+ static getInstance(element: Element | string | null): any
14
+ static getOrCreateInstance(element: Element | string, config?: unknown): any
15
+ static get VERSION(): string
16
+ static get DATA_KEY(): string
17
+ static get EVENT_KEY(): string
18
+ static eventName(name: string): string
19
+ }
@@ -0,0 +1,90 @@
1
+ // Vendored from https://github.com/coreui/coreui-pro/blob/bc4daf1cd79d527bf665d615c0a31f53ab0c3d4e/js/src/base-component.js — sync manually
2
+ /**
3
+ * --------------------------------------------------------------------------
4
+ * CoreUI base-component.js
5
+ * Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
6
+ *
7
+ * This component is a modified version of the Bootstrap's base-component.js
8
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
9
+ * --------------------------------------------------------------------------
10
+ */
11
+
12
+ import Data from './dom/data.js'
13
+ import EventHandler from './dom/event-handler.js'
14
+ import Config from './util/config.js'
15
+ import { executeAfterTransition, getElement } from './util/index.js'
16
+
17
+ /**
18
+ * Constants
19
+ */
20
+
21
+ const VERSION = '0.1.0'
22
+
23
+ /**
24
+ * Class definition
25
+ */
26
+
27
+ class BaseComponent extends Config {
28
+ constructor(element, config) {
29
+ super()
30
+
31
+ element = getElement(element)
32
+ if (!element) {
33
+ return
34
+ }
35
+
36
+ this._element = element
37
+ this._config = this._getConfig(config)
38
+
39
+ Data.set(this._element, this.constructor.DATA_KEY, this)
40
+ }
41
+
42
+ // Public
43
+ dispose() {
44
+ Data.remove(this._element, this.constructor.DATA_KEY)
45
+ EventHandler.off(this._element, this.constructor.EVENT_KEY)
46
+
47
+ for (const propertyName of Object.getOwnPropertyNames(this)) {
48
+ this[propertyName] = null
49
+ }
50
+ }
51
+
52
+ // Private
53
+ _queueCallback(callback, element, isAnimated = true) {
54
+ executeAfterTransition(callback, element, isAnimated)
55
+ }
56
+
57
+ _getConfig(config) {
58
+ config = this._mergeConfigObj(config, this._element)
59
+ config = this._configAfterMerge(config)
60
+ this._typeCheckConfig(config)
61
+ return config
62
+ }
63
+
64
+ // Static
65
+ static getInstance(element) {
66
+ return Data.get(getElement(element), this.DATA_KEY)
67
+ }
68
+
69
+ static getOrCreateInstance(element, config = {}) {
70
+ return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)
71
+ }
72
+
73
+ static get VERSION() {
74
+ return VERSION
75
+ }
76
+
77
+ static get DATA_KEY() {
78
+ return `coreui.${this.NAME}`
79
+ }
80
+
81
+ static get EVENT_KEY() {
82
+ return `.${this.DATA_KEY}`
83
+ }
84
+
85
+ static eventName(name) {
86
+ return `${name}${this.EVENT_KEY}`
87
+ }
88
+ }
89
+
90
+ export default BaseComponent