tosijs-ui 1.0.1 → 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 (93) 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.js +15 -37
  5. package/dist/index.js.map +39 -39
  6. package/dist/version.d.ts +1 -1
  7. package/package.json +2 -2
  8. package/dist/ab-test.js +0 -116
  9. package/dist/babylon-3d.js +0 -292
  10. package/dist/bodymovin-player.js +0 -172
  11. package/dist/bp-loader.js +0 -26
  12. package/dist/carousel.js +0 -308
  13. package/dist/code-editor.js +0 -102
  14. package/dist/color-input.js +0 -112
  15. package/dist/data-table.js +0 -774
  16. package/dist/drag-and-drop.js +0 -386
  17. package/dist/editable-rect.js +0 -450
  18. package/dist/filter-builder.js +0 -468
  19. package/dist/float.js +0 -170
  20. package/dist/form.js +0 -466
  21. package/dist/gamepad.js +0 -115
  22. package/dist/icon-data.js +0 -308
  23. package/dist/icon-types.js +0 -1
  24. package/dist/icons.js +0 -374
  25. package/dist/index-iife.js +0 -4
  26. package/dist/live-example.js +0 -611
  27. package/dist/localize.js +0 -381
  28. package/dist/make-sorter.js +0 -119
  29. package/dist/make-sorter.test.d.ts +0 -1
  30. package/dist/make-sorter.test.js +0 -48
  31. package/dist/mapbox.js +0 -161
  32. package/dist/markdown-viewer.js +0 -173
  33. package/dist/match-shortcut.js +0 -13
  34. package/dist/match-shortcut.test.d.ts +0 -1
  35. package/dist/match-shortcut.test.js +0 -194
  36. package/dist/menu.js +0 -614
  37. package/dist/notifications.js +0 -308
  38. package/dist/password-strength.js +0 -302
  39. package/dist/playwright.config.d.ts +0 -9
  40. package/dist/playwright.config.js +0 -73
  41. package/dist/pop-float.js +0 -231
  42. package/dist/rating.js +0 -192
  43. package/dist/rich-text.js +0 -296
  44. package/dist/segmented.js +0 -298
  45. package/dist/select.js +0 -427
  46. package/dist/side-nav.js +0 -106
  47. package/dist/size-break.js +0 -118
  48. package/dist/sizer.js +0 -92
  49. package/dist/src/ab-test.d.ts +0 -14
  50. package/dist/src/babylon-3d.d.ts +0 -53
  51. package/dist/src/bodymovin-player.d.ts +0 -32
  52. package/dist/src/bp-loader.d.ts +0 -0
  53. package/dist/src/carousel.d.ts +0 -113
  54. package/dist/src/code-editor.d.ts +0 -27
  55. package/dist/src/color-input.d.ts +0 -41
  56. package/dist/src/data-table.d.ts +0 -79
  57. package/dist/src/drag-and-drop.d.ts +0 -2
  58. package/dist/src/editable-rect.d.ts +0 -97
  59. package/dist/src/filter-builder.d.ts +0 -64
  60. package/dist/src/float.d.ts +0 -18
  61. package/dist/src/form.d.ts +0 -68
  62. package/dist/src/gamepad.d.ts +0 -34
  63. package/dist/src/icon-data.d.ts +0 -309
  64. package/dist/src/icon-types.d.ts +0 -7
  65. package/dist/src/icons.d.ts +0 -17
  66. package/dist/src/index.d.ts +0 -37
  67. package/dist/src/live-example.d.ts +0 -51
  68. package/dist/src/localize.d.ts +0 -30
  69. package/dist/src/make-sorter.d.ts +0 -3
  70. package/dist/src/mapbox.d.ts +0 -24
  71. package/dist/src/markdown-viewer.d.ts +0 -15
  72. package/dist/src/match-shortcut.d.ts +0 -9
  73. package/dist/src/menu.d.ts +0 -60
  74. package/dist/src/notifications.d.ts +0 -106
  75. package/dist/src/password-strength.d.ts +0 -35
  76. package/dist/src/pop-float.d.ts +0 -10
  77. package/dist/src/rating.d.ts +0 -62
  78. package/dist/src/rich-text.d.ts +0 -28
  79. package/dist/src/segmented.d.ts +0 -80
  80. package/dist/src/select.d.ts +0 -43
  81. package/dist/src/side-nav.d.ts +0 -36
  82. package/dist/src/size-break.d.ts +0 -18
  83. package/dist/src/sizer.d.ts +0 -34
  84. package/dist/src/tab-selector.d.ts +0 -91
  85. package/dist/src/tag-list.d.ts +0 -37
  86. package/dist/src/track-drag.d.ts +0 -5
  87. package/dist/src/version.d.ts +0 -1
  88. package/dist/src/via-tag.d.ts +0 -2
  89. package/dist/tab-selector.js +0 -326
  90. package/dist/tag-list.js +0 -375
  91. package/dist/track-drag.js +0 -143
  92. package/dist/version.js +0 -1
  93. 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
- });