tosijs-ui 1.0.0 → 1.0.2

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 (94) hide show
  1. package/README.md +4 -2
  2. package/dist/iife.js +70 -60
  3. package/dist/iife.js.map +42 -42
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +15 -37
  6. package/dist/index.js.map +39 -39
  7. package/dist/version.d.ts +1 -1
  8. package/package.json +2 -2
  9. package/dist/ab-test.js +0 -116
  10. package/dist/babylon-3d.js +0 -292
  11. package/dist/bodymovin-player.js +0 -172
  12. package/dist/bp-loader.js +0 -26
  13. package/dist/carousel.js +0 -308
  14. package/dist/code-editor.js +0 -102
  15. package/dist/color-input.js +0 -112
  16. package/dist/data-table.js +0 -774
  17. package/dist/drag-and-drop.js +0 -386
  18. package/dist/editable-rect.js +0 -450
  19. package/dist/filter-builder.js +0 -468
  20. package/dist/float.js +0 -170
  21. package/dist/form.js +0 -466
  22. package/dist/gamepad.js +0 -115
  23. package/dist/icon-data.js +0 -308
  24. package/dist/icon-types.js +0 -1
  25. package/dist/icons.js +0 -374
  26. package/dist/index-iife.js +0 -4
  27. package/dist/live-example.js +0 -611
  28. package/dist/localize.js +0 -381
  29. package/dist/make-sorter.js +0 -119
  30. package/dist/make-sorter.test.d.ts +0 -1
  31. package/dist/make-sorter.test.js +0 -48
  32. package/dist/mapbox.js +0 -161
  33. package/dist/markdown-viewer.js +0 -173
  34. package/dist/match-shortcut.js +0 -13
  35. package/dist/match-shortcut.test.d.ts +0 -1
  36. package/dist/match-shortcut.test.js +0 -194
  37. package/dist/menu.js +0 -614
  38. package/dist/notifications.js +0 -308
  39. package/dist/password-strength.js +0 -302
  40. package/dist/playwright.config.d.ts +0 -9
  41. package/dist/playwright.config.js +0 -73
  42. package/dist/pop-float.js +0 -231
  43. package/dist/rating.js +0 -192
  44. package/dist/rich-text.js +0 -296
  45. package/dist/segmented.js +0 -298
  46. package/dist/select.js +0 -427
  47. package/dist/side-nav.js +0 -106
  48. package/dist/size-break.js +0 -118
  49. package/dist/sizer.js +0 -92
  50. package/dist/src/ab-test.d.ts +0 -14
  51. package/dist/src/babylon-3d.d.ts +0 -53
  52. package/dist/src/bodymovin-player.d.ts +0 -32
  53. package/dist/src/bp-loader.d.ts +0 -0
  54. package/dist/src/carousel.d.ts +0 -113
  55. package/dist/src/code-editor.d.ts +0 -27
  56. package/dist/src/color-input.d.ts +0 -41
  57. package/dist/src/data-table.d.ts +0 -79
  58. package/dist/src/drag-and-drop.d.ts +0 -2
  59. package/dist/src/editable-rect.d.ts +0 -97
  60. package/dist/src/filter-builder.d.ts +0 -64
  61. package/dist/src/float.d.ts +0 -18
  62. package/dist/src/form.d.ts +0 -68
  63. package/dist/src/gamepad.d.ts +0 -34
  64. package/dist/src/icon-data.d.ts +0 -309
  65. package/dist/src/icon-types.d.ts +0 -7
  66. package/dist/src/icons.d.ts +0 -17
  67. package/dist/src/index.d.ts +0 -37
  68. package/dist/src/live-example.d.ts +0 -51
  69. package/dist/src/localize.d.ts +0 -30
  70. package/dist/src/make-sorter.d.ts +0 -3
  71. package/dist/src/mapbox.d.ts +0 -24
  72. package/dist/src/markdown-viewer.d.ts +0 -15
  73. package/dist/src/match-shortcut.d.ts +0 -9
  74. package/dist/src/menu.d.ts +0 -60
  75. package/dist/src/notifications.d.ts +0 -106
  76. package/dist/src/password-strength.d.ts +0 -35
  77. package/dist/src/pop-float.d.ts +0 -10
  78. package/dist/src/rating.d.ts +0 -62
  79. package/dist/src/rich-text.d.ts +0 -28
  80. package/dist/src/segmented.d.ts +0 -80
  81. package/dist/src/select.d.ts +0 -43
  82. package/dist/src/side-nav.d.ts +0 -36
  83. package/dist/src/size-break.d.ts +0 -18
  84. package/dist/src/sizer.d.ts +0 -34
  85. package/dist/src/tab-selector.d.ts +0 -91
  86. package/dist/src/tag-list.d.ts +0 -37
  87. package/dist/src/track-drag.d.ts +0 -5
  88. package/dist/src/version.d.ts +0 -1
  89. package/dist/src/via-tag.d.ts +0 -2
  90. package/dist/tab-selector.js +0 -326
  91. package/dist/tag-list.js +0 -375
  92. package/dist/track-drag.js +0 -143
  93. package/dist/version.js +0 -1
  94. package/dist/via-tag.js +0 -102
@@ -1,774 +0,0 @@
1
- /*#
2
- # table
3
-
4
- A virtual data-table, configurable via a `columns` array (which will automatically be generated if not provided),
5
- that displays gigantic tables with fixed headers (and live column-resizing) using a minimum of resources and cpu.
6
-
7
- ```js
8
- const { dataTable } = xinjsui
9
- const { input } = xinjs.elements
10
-
11
- const emojiRequest = await fetch('https://raw.githubusercontent.com/tonioloewald/emoji-metadata/master/emoji-metadata.json')
12
- const emojiData = await emojiRequest.json()
13
-
14
- const columns = [
15
- {
16
- name: "emoji",
17
- prop: "chars",
18
- align: "center",
19
- width: 80,
20
- sort: false,
21
- visible: true
22
- },
23
- {
24
- prop: "name",
25
- width: 300,
26
- // custom cell using xinjs bindings to make the field editable
27
- dataCell() {
28
- return input({
29
- class: 'td',
30
- bindValue: '^.name',
31
- title: 'name',
32
- onMouseup: (event) => { event.stopPropagation() },
33
- onTouchend: (event) => { event.stopPropagation() },
34
- })
35
- },
36
- },
37
- {
38
- prop: "category",
39
- sort: "ascending",
40
- width: 150
41
- },
42
- {
43
- prop: "subcategory",
44
- width: 150
45
- },
46
- ]
47
-
48
- preview.append(dataTable({
49
- multiple: true,
50
- array: emojiData,
51
- localized: true,
52
- columns,
53
- rowHeight: 40,
54
- pinnedBottom: 2
55
- }))
56
- ```
57
- ```css
58
- .preview input.td {
59
- margin: 0;
60
- border-radius: 0;
61
- box-shadow: none !important;
62
- background: #fff4;
63
- }
64
-
65
- .preview xin-table {
66
- height: 100%;
67
- }
68
-
69
- .preview xin-table [part="pinnedTopRows"],
70
- .preview xin-table [part="pinnedBottomRows"] {
71
- background: #ddd;
72
- }
73
- ```
74
-
75
- > In the preceding example, the `name` column is *editable* (and *bound*, try editing something and scrolling
76
- > it out of view and back) and `multiple` select is enabled. In the console, you can try `$('xin-table').visibleRows`
77
- > and $('xin-table').selectedRows`.
78
-
79
- You can set the `<xin-table>`'s `array`, `columns`, and `filter` properties directly, or set its `value` to:
80
-
81
- ```
82
- {
83
- array: any[],
84
- columns: ColumnOptions[] | null,
85
- filter?: ArrayFilter
86
- }
87
- ```
88
-
89
- ## `ColumnOptions`
90
-
91
- You can configure the table's columns by providing it an array of `ColumnOptions`:
92
-
93
- ```
94
- export interface ColumnOptions {
95
- name?: string
96
- prop: string
97
- width: number
98
- visible?: boolean
99
- align?: string
100
- sort?: false | 'ascending' | 'descending'
101
- headerCell?: (options: ColumnOptions) => HTMLElement
102
- dataCell?: (options: ColumnOptions) => HTMLElement
103
- }
104
- ```
105
-
106
- ## Selection
107
-
108
- `<xin-table>` supports `select` and `multiple` boolean properties allowing rows to be selectable. Selected rows will
109
- be given the `[aria-selected]` attribute, so style them as you wish.
110
-
111
- `multiple` select supports shift-clicking and command/meta-clicking.
112
-
113
- `<xin-table>` provides an `selectionChanged(visibleSelectedRows: any[]): void` callback property allowing you to respond to changes
114
- in the selection, and also `selectedRows` and `visibleSelectedRows` properties.
115
-
116
- The following methods are also provided:
117
-
118
- - `<xin-table>.selectRow(row: any, select = true)` (de)selects specified row
119
- - `<xin-table>.selectRows(rows?: any[], select = true)` (de)selects specified rows
120
- - `<xin-table>.deSelect(rows?: any[])` deselects all or specified rows.
121
-
122
- These are rather fine-grained but they're used internally by the selection code so they may as well be documented.
123
-
124
- ## Sorting
125
-
126
- By default, the user can sort the table by any column which doesn't have a `sort === false`.
127
-
128
- You can set the initial sort by setting the `sort` value of a specific column to `ascending`
129
- or `descending`.
130
-
131
- You can override this by setting the table's sort function (it's an `Array.sort()` callback)
132
- to whatever you like, and you can replace the `headerCell` or set the `sort` of each column
133
- to `false` if you have some specific sorting in mind.
134
-
135
- You can disable sorting controls by adding the `nosort` attribute to the `<xin-table>`.
136
-
137
- ## Hiding (and Showing) Columns
138
-
139
- By default, the user can show / hide columns by clicking via the column header menu.
140
- You can remove this option by adding the `nohide` attribute to the `<xin-table>`
141
-
142
- ## Reordering Columns
143
-
144
- By default, the user can reorder columns by dragging them around. You can disable this
145
- by adding the `noreorder` attribute to the `<xin-table>`.
146
-
147
- ## Row Height
148
-
149
- If you set the `<xin-table>`'s `rowHeight` to `0` it will render all its elements (i.e. not be virtual). This is
150
- useful for smaller tables, or tables with variable row-heights.
151
-
152
- ## Styling
153
-
154
- Aside from row height (see previous) the component doesn't use the shadowDOM, so it's easy to override
155
- its styles.
156
-
157
- ## Pinned Rows
158
-
159
- The table supports two attributes, `pinnedTop` and `pinnedBottom` that let you pin the specified number
160
- of top and bottom rows.
161
-
162
- ## Localization
163
-
164
- `<xin-table>` supports the `localized` attribute which simply causes its default `headerCell`
165
- to render a `<xin-localized>` element instead of a span for its caption, and localize its
166
- popup menu.
167
-
168
- You'll need to make sure your localized strings include:
169
-
170
- - Sort
171
- - Show
172
- - Hide
173
- - Column
174
- - Ascending
175
- - Descending
176
-
177
- As well as any column names you want localized.
178
- */
179
- import { Component as WebComponent, elements, vars, varDefault, xinValue, getListItem, boxedProxy, } from 'xinjs';
180
- import { trackDrag } from './track-drag';
181
- import { icons } from './icons';
182
- import { popMenu } from './menu';
183
- import * as dragAndDrop from './drag-and-drop';
184
- import { xinLocalized, localize } from './localize';
185
- function defaultWidth(array, prop, charWidth) {
186
- const example = array.find((item) => item[prop] !== undefined && item[prop] !== null);
187
- if (example !== undefined) {
188
- const value = example[prop];
189
- switch (typeof value) {
190
- case 'string':
191
- if (value.match(/^\d+(\.\d+)?$/)) {
192
- return 6 * charWidth;
193
- }
194
- else if (value.includes(' ')) {
195
- return 20 * charWidth;
196
- }
197
- else {
198
- return 12 * charWidth;
199
- }
200
- case 'number':
201
- return 6 * charWidth;
202
- case 'boolean':
203
- return 5 * charWidth;
204
- case 'object':
205
- return false;
206
- default:
207
- return 8 * charWidth;
208
- }
209
- }
210
- return false;
211
- }
212
- const { div, span, button, template } = elements;
213
- const passThru = (array) => array;
214
- export class DataTable extends WebComponent {
215
- select = false;
216
- multiple = false;
217
- nosort = false;
218
- nohide = false;
219
- noreorder = false;
220
- selectionChanged = () => {
221
- /* do not care */
222
- };
223
- localized = false;
224
- selectedKey = Symbol('selected');
225
- selectBinding = (elt, obj) => {
226
- elt.toggleAttribute('aria-selected', obj[this.selectedKey] === true);
227
- };
228
- pinnedTop = 0;
229
- pinnedBottom = 0;
230
- maxVisibleRows = 10000;
231
- get value() {
232
- return {
233
- array: this.array,
234
- filter: this.filter,
235
- columns: this.columns,
236
- };
237
- }
238
- set value(data) {
239
- const { array, columns, filter } = xinValue(data);
240
- if (this._array !== array ||
241
- this._columns !== columns ||
242
- this._filter !== filter) {
243
- this.queueRender();
244
- }
245
- this._array = array || [];
246
- this._columns = columns || null;
247
- this._filter = filter || passThru;
248
- }
249
- rowData = {
250
- visible: [],
251
- pinnedTop: [],
252
- pinnedBottom: [],
253
- };
254
- _array = [];
255
- _columns = null;
256
- _filter = passThru;
257
- charWidth = 15;
258
- rowHeight = 30;
259
- minColumnWidth = 30;
260
- get virtual() {
261
- return this.rowHeight > 0 ? { height: this.rowHeight } : undefined;
262
- }
263
- constructor() {
264
- super();
265
- this.rowData = boxedProxy({
266
- [this.instanceId]: this.rowData,
267
- })[this.instanceId];
268
- this.initAttributes('rowHeight', 'charWidth', 'minColumnWidth', 'select', 'multiple', 'pinnedTop', 'pinnedBottom', 'nosort', 'nohide', 'noreorder', 'localized');
269
- }
270
- get array() {
271
- return this._array;
272
- }
273
- set array(newArray) {
274
- this._array = xinValue(newArray);
275
- this.queueRender();
276
- }
277
- get filter() {
278
- return this._filter;
279
- }
280
- set filter(filterFunc) {
281
- if (this._filter !== filterFunc) {
282
- this._filter = filterFunc;
283
- this.queueRender();
284
- }
285
- }
286
- get sort() {
287
- if (this._sort) {
288
- return this._sort;
289
- }
290
- const sortColumn = this._columns?.find((c) => c.sort === 'ascending' || c.sort === 'descending');
291
- if (!sortColumn) {
292
- return undefined;
293
- }
294
- const { prop } = sortColumn;
295
- return sortColumn.sort === 'ascending'
296
- ? (a, b) => (a[prop] > b[prop] ? 1 : -1)
297
- : (a, b) => (a[prop] > b[prop] ? -1 : 1);
298
- }
299
- set sort(sortFunc) {
300
- if (this._sort !== sortFunc) {
301
- this._sort = sortFunc;
302
- this.queueRender();
303
- }
304
- }
305
- get columns() {
306
- if (!Array.isArray(this._columns)) {
307
- const { _array } = this;
308
- this._columns = Object.keys(_array[0] || {}).map((prop) => {
309
- const width = defaultWidth(_array, prop, this.charWidth);
310
- return {
311
- name: prop.replace(/([a-z])([A-Z])/g, '$1 $2').toLocaleLowerCase(),
312
- prop,
313
- align: typeof _array[0][prop] === 'number' ||
314
- (_array[0][prop] !== '' && !isNaN(_array[0][prop]))
315
- ? 'right'
316
- : 'left',
317
- visible: width !== false,
318
- width: width ? width : 0,
319
- };
320
- });
321
- }
322
- return this._columns;
323
- }
324
- set columns(newColumns) {
325
- this._columns = newColumns;
326
- this.queueRender();
327
- }
328
- get visibleColumns() {
329
- return this.columns.filter((c) => c.visible !== false);
330
- }
331
- content = null;
332
- getColumn(event) {
333
- const x = (event.touches !== undefined ? event.touches[0].clientX : event.clientX) -
334
- this.getBoundingClientRect().x;
335
- const epsilon = event.touches !== undefined ? 20 : 5;
336
- let boundaryX = 0;
337
- const log = [];
338
- const column = this.visibleColumns.find((options) => {
339
- if (options.visible !== false) {
340
- boundaryX += options.width;
341
- log.push(boundaryX);
342
- return Math.abs(x - boundaryX) < epsilon;
343
- }
344
- });
345
- return column;
346
- }
347
- setCursor = (event) => {
348
- const column = this.getColumn(event);
349
- if (column !== undefined) {
350
- this.style.cursor = 'col-resize';
351
- }
352
- else {
353
- this.style.cursor = '';
354
- }
355
- };
356
- resizeColumn = (event) => {
357
- const column = this.getColumn(event);
358
- if (column !== undefined) {
359
- const origWidth = Number(column.width);
360
- const isTouchEvent = event.touches !== undefined;
361
- const touchIdentifier = isTouchEvent
362
- ? event.touches[0].identifier
363
- : undefined;
364
- trackDrag(event, (dx, _dy, event) => {
365
- const touch = isTouchEvent
366
- ? [...event.touches].find((touch) => touch.identifier === touchIdentifier)
367
- : true;
368
- if (touch === undefined) {
369
- return true;
370
- }
371
- const width = origWidth + dx;
372
- column.width =
373
- width > this.minColumnWidth ? width : this.minColumnWidth;
374
- this.setColumnWidths();
375
- if (event.type === 'mouseup') {
376
- return true;
377
- }
378
- }, 'col-resize');
379
- }
380
- };
381
- selectRow(row, select = true) {
382
- if (select) {
383
- row[this.selectedKey] = true;
384
- }
385
- else {
386
- delete row[this.selectedKey];
387
- }
388
- }
389
- selectRows(rows, select = true) {
390
- for (const row of rows || this.array) {
391
- this.selectRow(row, select);
392
- }
393
- }
394
- deSelect(rows) {
395
- this.selectRows(rows, false);
396
- }
397
- // tracking click / shift-click
398
- rangeStart;
399
- updateSelection = (event) => {
400
- if (!this.select && !this.multiple) {
401
- return;
402
- }
403
- const { target } = event;
404
- if (!(target instanceof HTMLElement)) {
405
- return;
406
- }
407
- const tr = target.closest('.tr');
408
- if (!(tr instanceof HTMLElement)) {
409
- return;
410
- }
411
- const pickedItem = getListItem(tr);
412
- if (pickedItem === false) {
413
- return;
414
- }
415
- const mouseEvent = event;
416
- // prevent ugly selection artifacts
417
- const selection = window.getSelection();
418
- if (selection !== null) {
419
- selection.removeAllRanges();
420
- }
421
- const rows = this.visibleRows;
422
- if (this.multiple &&
423
- mouseEvent.shiftKey &&
424
- rows.length > 0 &&
425
- this.rangeStart !== pickedItem) {
426
- const mode = this.rangeStart === undefined ||
427
- this.rangeStart[this.selectedKey] === true;
428
- const [start, finish] = [
429
- this.rangeStart !== undefined ? rows.indexOf(this.rangeStart) : 0,
430
- rows.indexOf(pickedItem),
431
- ].sort((a, b) => a - b);
432
- // if start is -1 then one of the items is no longer visible
433
- if (start > -1) {
434
- for (let idx = start; idx <= finish; idx++) {
435
- const row = rows[idx];
436
- this.selectRow(row, mode);
437
- }
438
- }
439
- }
440
- else if (this.multiple && mouseEvent.metaKey) {
441
- this.selectRow(pickedItem, !pickedItem[this.selectedKey]);
442
- const pickedIndex = rows.indexOf(pickedItem);
443
- const nextItem = rows[pickedIndex + 1];
444
- const previousItem = pickedIndex > 0 ? rows[pickedIndex - 1] : undefined;
445
- if (nextItem !== undefined && nextItem[this.selectedKey] === true) {
446
- this.rangeStart = nextItem;
447
- }
448
- else if (previousItem !== undefined &&
449
- previousItem[this.selectedKey] === true) {
450
- this.rangeStart = previousItem;
451
- }
452
- else {
453
- this.rangeStart = undefined;
454
- }
455
- }
456
- else {
457
- this.rangeStart = pickedItem;
458
- this.deSelect();
459
- this.selectRow(pickedItem, true);
460
- }
461
- this.selectionChanged(this.visibleSelectedRows);
462
- for (const row of Array.from(this.querySelectorAll('.tr'))) {
463
- const item = getListItem(row);
464
- this.selectBinding(row, item);
465
- }
466
- };
467
- connectedCallback() {
468
- super.connectedCallback();
469
- this.addEventListener('mousemove', this.setCursor);
470
- this.addEventListener('mousedown', this.resizeColumn);
471
- this.addEventListener('touchstart', this.resizeColumn, { passive: true });
472
- this.addEventListener('mouseup', this.updateSelection);
473
- this.addEventListener('touchend', this.updateSelection);
474
- }
475
- setColumnWidths() {
476
- this.style.setProperty('--grid-columns', this.visibleColumns.map((c) => c.width + 'px').join(' '));
477
- this.style.setProperty('--grid-row-width', this.visibleColumns.reduce((w, c) => w + c.width, 0) + 'px');
478
- }
479
- sortByColumn = (columnOptions, direction = 'auto') => {
480
- for (const column of this.columns.filter((c) => xinValue(c.sort) !== false)) {
481
- if (xinValue(column) === columnOptions) {
482
- if (direction === 'auto') {
483
- column.sort = column.sort === 'ascending' ? 'descending' : 'ascending';
484
- }
485
- else {
486
- column.sort = direction;
487
- }
488
- this.queueRender();
489
- }
490
- else {
491
- delete column.sort;
492
- }
493
- }
494
- };
495
- popColumnMenu = (target, options) => {
496
- const { sortByColumn } = this;
497
- const hiddenColumns = this.columns.filter((column) => column.visible === false);
498
- const queueRender = this.queueRender.bind(this);
499
- const menu = [];
500
- if (!this.nosort && options.sort !== false) {
501
- menu.push({
502
- caption: this.localized
503
- ? `${localize('Sort')} ${localize('Ascending')}`
504
- : 'Sort Ascending',
505
- icon: 'sortAscending',
506
- action() {
507
- sortByColumn(options);
508
- },
509
- }, {
510
- caption: this.localized
511
- ? `${localize('Sort')} ${localize('Descending')}`
512
- : 'Sort Ascending',
513
- icon: 'sortDescending',
514
- action() {
515
- sortByColumn(options, 'descending');
516
- },
517
- });
518
- }
519
- if (!this.nohide) {
520
- if (menu.length) {
521
- menu.push(null);
522
- }
523
- menu.push({
524
- caption: this.localized
525
- ? `${localize('Hide')} ${localize('Column')}`
526
- : 'Hide Column',
527
- icon: 'eyeOff',
528
- enabled: () => options.visible !== true,
529
- action() {
530
- options.visible = false;
531
- queueRender();
532
- },
533
- }, {
534
- caption: this.localized
535
- ? `${localize('Show')} ${localize('Column')}`
536
- : 'Show Column',
537
- icon: 'eye',
538
- enabled: () => hiddenColumns.length > 0,
539
- menuItems: hiddenColumns.map((column) => {
540
- return {
541
- caption: column.name || column.prop,
542
- action() {
543
- delete column.visible;
544
- queueRender();
545
- },
546
- };
547
- }),
548
- });
549
- }
550
- popMenu({
551
- target,
552
- localized: this.localized,
553
- menuItems: menu,
554
- });
555
- };
556
- get captionSpan() {
557
- return this.localized ? xinLocalized : span;
558
- }
559
- headerCell = (options) => {
560
- const { popColumnMenu } = this;
561
- let ariaSort = 'none';
562
- let sortIcon;
563
- switch (options.sort) {
564
- case 'ascending':
565
- sortIcon = icons.sortAscending();
566
- ariaSort = 'descending';
567
- break;
568
- case false:
569
- break;
570
- default:
571
- break;
572
- case 'descending':
573
- ariaSort = 'ascending';
574
- sortIcon = icons.sortDescending();
575
- }
576
- const menuButton = !(this.nosort && this.nohide)
577
- ? button({
578
- class: 'menu-trigger',
579
- onClick(event) {
580
- popColumnMenu(event.target, options);
581
- event.stopPropagation();
582
- },
583
- }, sortIcon || icons.moreVertical())
584
- : {};
585
- return options.headerCell !== undefined
586
- ? options.headerCell(options)
587
- : span({
588
- class: 'th',
589
- role: 'columnheader',
590
- ariaSort,
591
- style: {
592
- ...this.cellStyle,
593
- textAlign: options.align || 'left',
594
- },
595
- }, this.captionSpan(typeof options.name === 'string' ? options.name : options.prop), span({ style: { flex: '1' } }), menuButton);
596
- };
597
- dataCell = (options) => {
598
- if (options.dataCell !== undefined) {
599
- return options.dataCell(options);
600
- }
601
- return span({
602
- class: 'td',
603
- role: 'cell',
604
- style: {
605
- ...this.cellStyle,
606
- textAlign: options.align || 'left',
607
- },
608
- bindText: `^.${options.prop}`,
609
- });
610
- };
611
- get visibleRows() {
612
- return xinValue(this.rowData.visible);
613
- }
614
- get visibleSelectedRows() {
615
- return this.visibleRows.filter((obj) => obj[this.selectedKey]);
616
- }
617
- get selectedRows() {
618
- return this.array.filter((obj) => obj[this.selectedKey]);
619
- }
620
- rowTemplate(columns) {
621
- return template(div({
622
- class: 'tr',
623
- role: 'row',
624
- bind: {
625
- value: '^',
626
- binding: { toDOM: this.selectBinding },
627
- },
628
- }, ...columns.map(this.dataCell)));
629
- }
630
- draggedColumn;
631
- dropColumn = (event) => {
632
- const target = event.target.closest('.drag-over');
633
- const targetIndex = Array.from(target.parentElement.children).indexOf(target);
634
- const dropped = this.visibleColumns[targetIndex];
635
- const draggedIndex = this.columns.indexOf(this.draggedColumn);
636
- const droppedIndex = this.columns.indexOf(dropped);
637
- this.columns.splice(draggedIndex, 1);
638
- this.columns.splice(droppedIndex, 0, this.draggedColumn);
639
- console.log({ event, target, targetIndex, draggedIndex, droppedIndex });
640
- this.queueRender();
641
- event.preventDefault();
642
- event.stopPropagation();
643
- };
644
- render() {
645
- super.render();
646
- this.rowData.pinnedTop =
647
- this.pinnedTop > 0 ? this._array.slice(0, this.pinnedTop) : [];
648
- this.rowData.pinnedBottom =
649
- this.pinnedBottom > 0
650
- ? this._array.slice(this._array.length - this.pinnedBottom)
651
- : [];
652
- this.rowData.visible = this.filter(this._array.slice(this.pinnedTop, Math.min(this.maxVisibleRows, this._array.length - this.pinnedTop - this.pinnedBottom)));
653
- const { sort } = this;
654
- if (sort) {
655
- this.rowData.visible.sort(sort);
656
- }
657
- this.textContent = '';
658
- this.style.display = 'flex';
659
- this.style.flexDirection = 'column';
660
- const { visibleColumns } = this;
661
- this.style.setProperty('--row-height', `${this.rowHeight}px`);
662
- this.setColumnWidths();
663
- if (!this.noreorder) {
664
- dragAndDrop.init();
665
- }
666
- const dragId = this.instanceId + '-column-header';
667
- const columnHeaders = visibleColumns.map((column) => {
668
- const header = this.headerCell(column);
669
- if (!this.noreorder) {
670
- header.setAttribute('draggable', 'true');
671
- header.dataset.drag = dragId;
672
- header.dataset.drop = dragId;
673
- header.addEventListener('dragstart', () => {
674
- this.draggedColumn = column;
675
- });
676
- header.addEventListener('drop', this.dropColumn);
677
- }
678
- return header;
679
- });
680
- this.append(div({ class: 'thead', role: 'rowgroup', style: { touchAction: 'none' } }, div({
681
- class: 'tr',
682
- role: 'row',
683
- }, ...columnHeaders)));
684
- if (this.pinnedTop > 0) {
685
- this.append(div({
686
- part: 'pinnedTopRows',
687
- class: 'tbody',
688
- role: 'rowgroup',
689
- style: {
690
- flex: '0 0 auto',
691
- overflow: 'hidden',
692
- height: `${this.rowHeight * this.pinnedTop}px`,
693
- },
694
- bindList: {
695
- value: this.rowData.pinnedTop,
696
- virtual: this.virtual,
697
- },
698
- }, this.rowTemplate(visibleColumns)));
699
- }
700
- this.append(div({
701
- part: 'visibleRows',
702
- class: 'tbody',
703
- role: 'rowgroup',
704
- style: {
705
- content: ' ',
706
- minHeight: '100px',
707
- flex: '1 1 100px',
708
- overflow: 'hidden auto',
709
- },
710
- bindList: {
711
- value: this.rowData.visible,
712
- virtual: this.virtual,
713
- },
714
- }, this.rowTemplate(visibleColumns)));
715
- if (this.pinnedBottom > 0) {
716
- this.append(div({
717
- part: 'pinnedBottomRows',
718
- class: 'tbody',
719
- role: 'rowgroup',
720
- style: {
721
- flex: '0 0 auto',
722
- overflow: 'hidden',
723
- height: `${this.rowHeight * this.pinnedBottom}px`,
724
- },
725
- bindList: {
726
- value: this.rowData.pinnedBottom,
727
- virtual: this.virtual,
728
- },
729
- }, this.rowTemplate(visibleColumns)));
730
- }
731
- }
732
- }
733
- export const dataTable = DataTable.elementCreator({
734
- tag: 'xin-table',
735
- styleSpec: {
736
- ':host': {
737
- overflow: 'auto hidden',
738
- },
739
- ':host .thead, :host .tbody': {
740
- width: vars.gridRowWidth,
741
- },
742
- ':host .tr': {
743
- display: 'grid',
744
- gridTemplateColumns: vars.gridColumns,
745
- height: vars.rowHeight,
746
- lineHeight: vars.rowHeight,
747
- },
748
- ':host .td, :host .th': {
749
- overflow: 'hidden',
750
- whiteSpace: 'nowrap',
751
- textOverflow: 'ellipsis',
752
- display: 'flex',
753
- alignItems: 'center',
754
- },
755
- ':host .th .menu-trigger': {
756
- color: 'currentColor',
757
- background: 'none',
758
- padding: 0,
759
- lineHeight: vars.touchSize,
760
- height: vars.touchSize,
761
- width: vars.touchSize,
762
- },
763
- ':host [draggable="true"]': {
764
- cursor: 'ew-resize',
765
- },
766
- ':host [draggable="true"]:active': {
767
- background: varDefault.draggedHeaderBg('#0004'),
768
- color: varDefault.draggedHeaderColor('#fff'),
769
- },
770
- ':host .drag-over': {
771
- background: varDefault.dropHeaderBg('#fff4'),
772
- },
773
- },
774
- });