@dxos/lit-grid 0.6.10-main.bbdfaa4 → 0.6.10-staging.014d6d3

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.
@@ -2,26 +2,6 @@
2
2
  import { LitElement, html } from "lit";
3
3
  import { customElement, state, property } from "lit/decorators.js";
4
4
  import { ref, createRef } from "lit/directives/ref.js";
5
-
6
- // packages/ui/lit-grid/src/position.ts
7
- var colToA1Notation = (column) => {
8
- return (column >= 26 ? String.fromCharCode("A".charCodeAt(0) + Math.floor(column / 26) - 1) : "") + String.fromCharCode("A".charCodeAt(0) + column % 26);
9
- };
10
- var rowToA1Notation = (row) => {
11
- return `${row + 1}`;
12
- };
13
- var posFromNumericNotation = (notation) => {
14
- const [iStr, jStr] = notation.split(",");
15
- if (!iStr || !jStr) {
16
- throw Error("[posFromNumericNotation] Bad input");
17
- }
18
- return {
19
- i: parseInt(iStr),
20
- j: parseInt(jStr)
21
- };
22
- };
23
-
24
- // packages/ui/lit-grid/src/dx-grid.ts
25
5
  function _ts_decorate(decorators, target, key, desc) {
26
6
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
27
7
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
@@ -32,129 +12,241 @@ function _ts_decorate(decorators, target, key, desc) {
32
12
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
33
13
  return c > 3 && r && Object.defineProperty(target, key, r), r;
34
14
  }
35
- var colSize = 64;
36
- var rowSize = 20;
37
- var gap = 0;
15
+ var gap = 1;
16
+ var resizeTolerance = 8;
17
+ var overscanCol = 1;
18
+ var overscanRow = 1;
19
+ var sizeColMin = 32;
20
+ var sizeColMax = 1024;
21
+ var sizeRowMin = 16;
22
+ var sizeRowMax = 1024;
23
+ var separator = ",";
24
+ var colToA1Notation = (col) => {
25
+ return (col >= 26 ? String.fromCharCode("A".charCodeAt(0) + Math.floor(col / 26) - 1) : "") + String.fromCharCode("A".charCodeAt(0) + col % 26);
26
+ };
27
+ var rowToA1Notation = (row) => {
28
+ return `${row + 1}`;
29
+ };
30
+ var localChId = (c0) => `ch--${c0}`;
31
+ var localRhId = (r0) => `rh--${r0}`;
32
+ var getPage = (axis, event) => axis === "col" ? event.pageX : event.pageY;
38
33
  var DxGrid = class extends LitElement {
39
34
  constructor() {
40
35
  super(...arguments);
41
- this.values = {};
36
+ this.rowDefault = {
37
+ size: 32
38
+ };
39
+ this.columnDefault = {
40
+ size: 180
41
+ };
42
+ this.rows = {};
43
+ this.columns = {};
44
+ this.cells = {};
45
+ //
46
+ // `pos`, short for ‘position’, is the position in pixels of the viewport from the origin.
47
+ //
42
48
  this.posInline = 0;
43
49
  this.posBlock = 0;
50
+ //
51
+ // `size` (when not suffixed with ‘row’ or ‘col’, see above) is the size in pixels of the viewport.
52
+ //
44
53
  this.sizeInline = 0;
45
54
  this.sizeBlock = 0;
46
- this.cellByPosition = {};
55
+ //
56
+ // `overscan` is the amount in pixels to offset the grid content due to the number of overscanned columns or rows.
57
+ //
58
+ this.overscanInline = 0;
59
+ this.overscanBlock = 0;
60
+ //
61
+ // `bin`, not short for anything, is the range in pixels within which virtualization does not need to reassess.
62
+ //
63
+ this.binInlineMin = 0;
64
+ this.binInlineMax = this.colSize(0);
65
+ this.binBlockMin = 0;
66
+ this.binBlockMax = this.rowSize(0);
67
+ //
68
+ // `vis`, short for ‘visible’, is the range in numeric index of the columns or rows which should be rendered within
69
+ // the viewport. These start with naïve values that are updated before first contentful render.
70
+ //
71
+ this.visColMin = 0;
72
+ this.visColMax = 1;
73
+ this.visRowMin = 0;
74
+ this.visRowMax = 1;
75
+ //
76
+ // `template` is the rendered value of `grid-{axis}-template`.
77
+ //
78
+ this.templateColumns = `${this.colSize(0)}px`;
79
+ this.templateRows = `${this.rowSize(0)}px`;
80
+ //
81
+ // Resize state and handlers
82
+ //
83
+ this.colSizes = {};
84
+ this.rowSizes = {};
85
+ this.resizing = null;
86
+ this.handlePointerDown = (event) => {
87
+ const actionEl = event.target?.closest("[data-dx-grid-action]");
88
+ const action = actionEl?.getAttribute("data-dx-grid-action");
89
+ if (action) {
90
+ if (action.startsWith("resize")) {
91
+ const [resize, index] = action.split(",");
92
+ const [_, axis] = resize.split("-");
93
+ this.resizing = {
94
+ axis,
95
+ size: axis === "col" ? this.colSize(index) : this.rowSize(index),
96
+ page: getPage(axis, event),
97
+ index
98
+ };
99
+ }
100
+ }
101
+ };
102
+ this.handlePointerUp = (_event) => {
103
+ this.resizing = null;
104
+ };
105
+ this.handlePointerMove = (event) => {
106
+ if (this.resizing) {
107
+ const delta = getPage(this.resizing.axis, event) - this.resizing.page;
108
+ if (this.resizing.axis === "col") {
109
+ const nextSize = Math.max(sizeColMin, Math.min(sizeColMax, this.resizing.size + delta));
110
+ this.colSizes = {
111
+ ...this.colSizes,
112
+ [this.resizing.index]: nextSize
113
+ };
114
+ this.updateVisInline();
115
+ } else {
116
+ const nextSize = Math.max(sizeRowMin, Math.min(sizeRowMax, this.resizing.size + delta));
117
+ this.rowSizes = {
118
+ ...this.rowSizes,
119
+ [this.resizing.index]: nextSize
120
+ };
121
+ this.updateVisBlock();
122
+ }
123
+ }
124
+ };
125
+ //
126
+ // Resize & reposition handlers, observer, ref
127
+ //
47
128
  this.observer = new ResizeObserver((entries) => {
48
129
  const { inlineSize, blockSize } = entries?.[0]?.contentBoxSize?.[0] ?? {
49
130
  inlineSize: 0,
50
131
  blockSize: 0
51
132
  };
52
- this.sizeInline = inlineSize;
53
- this.sizeBlock = blockSize;
133
+ if (Math.abs(inlineSize - this.sizeInline) > resizeTolerance || Math.abs(blockSize - this.sizeBlock) > resizeTolerance) {
134
+ this.sizeInline = inlineSize;
135
+ this.sizeBlock = blockSize;
136
+ this.updateVis();
137
+ }
54
138
  });
55
139
  this.viewportRef = createRef();
56
140
  this.handleWheel = ({ deltaX, deltaY }) => {
57
141
  this.posInline = Math.max(0, this.posInline + deltaX);
58
142
  this.posBlock = Math.max(0, this.posBlock + deltaY);
143
+ if (this.posInline >= this.binInlineMin && this.posInline < this.binInlineMax && this.posBlock >= this.binBlockMin && this.posBlock < this.binBlockMax) {
144
+ } else {
145
+ this.updateVis();
146
+ }
59
147
  };
60
148
  }
61
- willUpdate(changed) {
62
- if (changed.has("values")) {
63
- this.cellByPosition = Object.entries(this.values).reduce((acc, [id, { pos, end }]) => {
64
- const { i: i1, j: j1 } = posFromNumericNotation(pos);
65
- if (end) {
66
- const { i: i2, j: j2 } = posFromNumericNotation(end);
67
- for (let ci = i1; ci <= i2; ci += 1) {
68
- for (let cj = j1; cj <= j2; cj += 1) {
69
- acc[`${ci},${cj}`] = id;
70
- }
71
- }
72
- } else {
73
- acc[`${i1},${j1}`] = id;
74
- }
75
- return acc;
76
- }, {});
77
- }
149
+ //
150
+ // Accessors
151
+ //
152
+ colSize(c) {
153
+ return this.colSizes?.[c] ?? this.columnDefault.size;
78
154
  }
79
- getCell(i, j) {
80
- const pos = `${i},${j}`;
81
- const cellId = this.cellByPosition[pos];
82
- return cellId ? this.values[cellId] : void 0;
155
+ rowSize(r) {
156
+ return this.rowSizes?.[r] ?? this.rowDefault.size;
83
157
  }
84
- computeExtrema() {
85
- const colVisMin = Math.floor(this.posInline / (colSize + gap));
86
- const colVisMax = Math.ceil((this.sizeInline + this.posInline) / (colSize + gap));
87
- const rowVisMin = Math.floor(this.posBlock / (rowSize + gap));
88
- const rowVisMax = Math.ceil((this.sizeBlock + this.posBlock) / (rowSize + gap));
89
- const { colExtMin, colExtMax } = [
90
- ...Array(rowVisMax - rowVisMin)
91
- ].reduce((acc, _, j) => {
92
- const colVisMinCell = this.getCell(colVisMin, j + rowVisMin);
93
- if (colVisMinCell?.end) {
94
- const { i: iStart } = posFromNumericNotation(colVisMinCell.pos);
95
- acc.colExtMin = Math.min(acc.colExtMin, iStart);
96
- }
97
- const colVisMaxCell = this.getCell(colVisMax, j + rowVisMin);
98
- if (colVisMaxCell?.end) {
99
- const { i: iEnd } = posFromNumericNotation(colVisMaxCell.end);
100
- acc.colExtMax = Math.max(acc.colExtMax, iEnd);
101
- }
158
+ getCell(c, r) {
159
+ return this.cells[`${c}${separator}${r}`];
160
+ }
161
+ updateVisInline() {
162
+ let colIndex = 0;
163
+ let pxInline = this.colSize(colIndex);
164
+ while (pxInline < this.posInline) {
165
+ colIndex += 1;
166
+ pxInline += this.colSize(colIndex) + gap;
167
+ }
168
+ this.visColMin = colIndex - overscanCol;
169
+ this.binInlineMin = pxInline - this.colSize(colIndex) - gap;
170
+ this.binInlineMax = pxInline + gap;
171
+ this.overscanInline = [
172
+ ...Array(overscanCol)
173
+ ].reduce((acc, _, c0) => {
174
+ acc += this.colSize(this.visColMin + c0);
102
175
  return acc;
103
- }, {
104
- colExtMin: colVisMin,
105
- colExtMax: colVisMax
106
- });
107
- const { rowExtMin, rowExtMax } = [
108
- ...Array(colVisMax - colVisMin)
109
- ].reduce((acc, _, i) => {
110
- const rowVisMinCell = this.getCell(i + colVisMin, rowVisMin);
111
- if (rowVisMinCell?.end) {
112
- const { j: jStart } = posFromNumericNotation(rowVisMinCell.pos);
113
- acc.rowExtMin = Math.min(acc.rowExtMin, jStart);
114
- }
115
- const rowVisMaxCell = this.getCell(i + colVisMin, rowVisMax);
116
- if (rowVisMaxCell?.end) {
117
- const { j: jEnd } = posFromNumericNotation(rowVisMaxCell.end);
118
- acc.rowExtMax = Math.max(acc.rowExtMax, jEnd);
119
- }
176
+ }, 0) + gap * (overscanCol - 1);
177
+ while (pxInline < this.binInlineMax + this.sizeInline) {
178
+ colIndex += 1;
179
+ pxInline += this.colSize(colIndex) + gap;
180
+ }
181
+ this.visColMax = colIndex + overscanCol + 1;
182
+ this.templateColumns = [
183
+ ...Array(this.visColMax - this.visColMin)
184
+ ].map((_, c0) => `${this.colSize(this.visColMin + c0)}px`).join(" ");
185
+ }
186
+ updateVisBlock() {
187
+ let rowIndex = 0;
188
+ let pxBlock = this.rowSize(rowIndex);
189
+ while (pxBlock < this.posBlock) {
190
+ rowIndex += 1;
191
+ pxBlock += this.rowSize(rowIndex) + gap;
192
+ }
193
+ this.visRowMin = rowIndex - overscanRow;
194
+ this.binBlockMin = pxBlock - this.rowSize(rowIndex) - gap;
195
+ this.binBlockMax = pxBlock + gap;
196
+ this.overscanBlock = [
197
+ ...Array(overscanRow)
198
+ ].reduce((acc, _, r0) => {
199
+ acc += this.rowSize(this.visRowMin + r0);
120
200
  return acc;
121
- }, {
122
- rowExtMin: rowVisMin,
123
- rowExtMax: rowVisMax
124
- });
125
- return {
126
- colVisMin,
127
- colExtMin,
128
- colVisMax,
129
- colExtMax,
130
- rowVisMin,
131
- rowExtMin,
132
- rowVisMax,
133
- rowExtMax
134
- };
201
+ }, 0) + gap * (overscanRow - 1);
202
+ while (pxBlock < this.binBlockMax + this.sizeBlock) {
203
+ rowIndex += 1;
204
+ pxBlock += this.rowSize(rowIndex) + gap;
205
+ }
206
+ this.visRowMax = rowIndex + overscanRow + 1;
207
+ this.templateRows = [
208
+ ...Array(this.visRowMax - this.visRowMin)
209
+ ].map((_, r0) => `${this.rowSize(this.visRowMin + r0)}px`).join(" ");
210
+ }
211
+ updateVis() {
212
+ this.updateVisInline();
213
+ this.updateVisBlock();
135
214
  }
215
+ //
216
+ // Render and other lifecycle methods
217
+ //
136
218
  render() {
137
- const { colVisMin, colVisMax, rowVisMin, rowVisMax } = this.computeExtrema();
138
- const visibleCols = colVisMax - colVisMin;
139
- const visibleRows = rowVisMax - rowVisMin;
140
- const offsetInline = colVisMin * colSize - this.posInline;
141
- const offsetBlock = rowVisMin * rowSize - this.posBlock;
142
- return html`<div role="none" class="dx-grid">
219
+ const visibleCols = this.visColMax - this.visColMin;
220
+ const visibleRows = this.visRowMax - this.visRowMin;
221
+ const offsetInline = this.binInlineMin - this.posInline - this.overscanInline;
222
+ const offsetBlock = this.binBlockMin - this.posBlock - this.overscanBlock;
223
+ return html`<div
224
+ role="none"
225
+ class="dx-grid"
226
+ @pointerdown=${this.handlePointerDown}
227
+ @pointerup=${this.handlePointerUp}
228
+ @pointermove=${this.handlePointerMove}
229
+ >
143
230
  <div role="none" class="dx-grid__corner"></div>
144
231
  <div role="none" class="dx-grid__columnheader">
145
232
  <div
146
233
  role="none"
147
234
  class="dx-grid__columnheader__content"
148
- style="transform:translate3d(${offsetInline}px,0,0);grid-template-columns:repeat(${visibleCols},${colSize}px);"
235
+ style="transform:translate3d(${offsetInline}px,0,0);grid-template-columns:${this.templateColumns};"
149
236
  >
150
237
  ${[
151
238
  ...Array(visibleCols)
152
- ].map((_, i) => {
239
+ ].map((_, c0) => {
240
+ const c = this.visColMin + c0;
153
241
  return html`<div
154
- role="gridcell"
155
- style="inline-size:${colSize}px;block-size:${rowSize}px;grid-column:${i + 1}/${i + 2};"
242
+ role="columnheader"
243
+ ?inert=${c < 0}
244
+ style="inline-size:${this.colSize(c)}px;block-size:${this.rowDefault.size}px;grid-column:${c0 + 1}/${c0 + 2};"
156
245
  >
157
- ${colToA1Notation(colVisMin + i)}
246
+ <span id=${localChId(c0)}>${colToA1Notation(c)}</span>
247
+ ${(this.columns[c]?.resizeable ?? this.columnDefault.resizeable) && html`<button class="dx-grid__resize-handle" data-dx-grid-action=${`resize-col,${c}`}>
248
+ <span class="sr-only">Resize</span>
249
+ </button>`}
158
250
  </div>`;
159
251
  })}
160
252
  </div>
@@ -164,9 +256,17 @@ var DxGrid = class extends LitElement {
164
256
  <div role="none" class="dx-grid__rowheader__content" style="transform:translate3d(0,${offsetBlock}px,0);">
165
257
  ${[
166
258
  ...Array(visibleRows)
167
- ].map((_, j) => {
168
- return html`<div role="gridcell" style="block-size:${rowSize}px;grid-row:${j + 1}/${j + 2}">
169
- ${rowToA1Notation(rowVisMin + j)}
259
+ ].map((_, r0) => {
260
+ const r = this.visRowMin + r0;
261
+ return html`<div
262
+ role="rowheader"
263
+ ?inert=${r < 0}
264
+ style="block-size:${this.rowSize(r)}px;grid-row:${r0 + 1}/${r0 + 2}"
265
+ >
266
+ <span id=${localRhId(r0)}>${rowToA1Notation(r)}</span>
267
+ ${(this.rows[r]?.resizeable ?? this.rowDefault.resizeable) && html`<button class="dx-grid__resize-handle" data-dx-grid-action=${`resize-row,${r}`}>
268
+ <span class="sr-only">Resize</span>
269
+ </button>`}
170
270
  </div>`;
171
271
  })}
172
272
  </div>
@@ -175,32 +275,27 @@ var DxGrid = class extends LitElement {
175
275
  <div
176
276
  role="grid"
177
277
  class="dx-grid__content"
178
- style="transform:translate3d(${offsetInline}px,${offsetBlock}px,0);grid-template-columns:repeat(${visibleCols},${colSize}px);grid-template-rows:repeat(${visibleRows},${rowSize}px);"
278
+ style="transform:translate3d(${offsetInline}px,${offsetBlock}px,0);grid-template-columns:${this.templateColumns};grid-template-rows:${this.templateRows};"
179
279
  >
180
280
  ${[
181
281
  ...Array(visibleCols)
182
- ].map((_, i) => {
282
+ ].map((_, c0) => {
183
283
  return [
184
284
  ...Array(visibleRows)
185
- ].map((_2, j) => {
186
- const posAbs = `${i + colVisMin},${j + rowVisMin}`;
187
- const cellId = this.cellByPosition[posAbs];
188
- const cell = cellId ? this.values[cellId] : void 0;
189
- if (cell?.end) {
190
- if (posAbs !== cell?.pos) {
191
- return null;
192
- } else {
193
- const { i: iEndAbs, j: jEndAbs } = posFromNumericNotation(cell.end);
194
- return html`<div
195
- role="gridcell"
196
- style="grid-column:${i + 1} / ${iEndAbs - colVisMin + 2};grid-row:${j + 1} / ${jEndAbs - rowVisMin + 2}"
197
- >
198
- ${cell?.value}
199
- </div>`;
200
- }
201
- } else {
202
- return html`<div role="gridcell" style="grid-column:${i + 1};grid-row:${j + 1}">${cell?.value}</div>`;
203
- }
285
+ ].map((_2, r0) => {
286
+ const c = c0 + this.visColMin;
287
+ const r = r0 + this.visRowMin;
288
+ const cell = this.getCell(c, r);
289
+ return html`<div
290
+ role="gridcell"
291
+ ?inert=${c < 0 || r < 0}
292
+ aria-rowindex=${r}
293
+ aria-colindex=${c}
294
+ data-dx-grid-action="cell"
295
+ style="grid-column:${c0 + 1};grid-row:${r0 + 1}"
296
+ >
297
+ ${cell?.value}
298
+ </div>`;
204
299
  });
205
300
  })}
206
301
  </div>
@@ -217,6 +312,18 @@ var DxGrid = class extends LitElement {
217
312
  }
218
313
  firstUpdated() {
219
314
  this.observer.observe(this.viewportRef.value);
315
+ this.colSizes = Object.entries(this.columns).reduce((acc, [colId, colMeta]) => {
316
+ if (colMeta?.size) {
317
+ acc[colId] = colMeta.size;
318
+ }
319
+ return acc;
320
+ }, {});
321
+ this.rowSizes = Object.entries(this.rows).reduce((acc, [rowId, rowMeta]) => {
322
+ if (rowMeta?.size) {
323
+ acc[rowId] = rowMeta.size;
324
+ }
325
+ return acc;
326
+ }, {});
220
327
  }
221
328
  disconnectedCallback() {
222
329
  super.disconnectedCallback();
@@ -232,7 +339,27 @@ _ts_decorate([
232
339
  property({
233
340
  type: Object
234
341
  })
235
- ], DxGrid.prototype, "values", void 0);
342
+ ], DxGrid.prototype, "rowDefault", void 0);
343
+ _ts_decorate([
344
+ property({
345
+ type: Object
346
+ })
347
+ ], DxGrid.prototype, "columnDefault", void 0);
348
+ _ts_decorate([
349
+ property({
350
+ type: Object
351
+ })
352
+ ], DxGrid.prototype, "rows", void 0);
353
+ _ts_decorate([
354
+ property({
355
+ type: Object
356
+ })
357
+ ], DxGrid.prototype, "columns", void 0);
358
+ _ts_decorate([
359
+ property({
360
+ type: Object
361
+ })
362
+ ], DxGrid.prototype, "cells", void 0);
236
363
  _ts_decorate([
237
364
  state()
238
365
  ], DxGrid.prototype, "posInline", void 0);
@@ -247,7 +374,49 @@ _ts_decorate([
247
374
  ], DxGrid.prototype, "sizeBlock", void 0);
248
375
  _ts_decorate([
249
376
  state()
250
- ], DxGrid.prototype, "cellByPosition", void 0);
377
+ ], DxGrid.prototype, "overscanInline", void 0);
378
+ _ts_decorate([
379
+ state()
380
+ ], DxGrid.prototype, "overscanBlock", void 0);
381
+ _ts_decorate([
382
+ state()
383
+ ], DxGrid.prototype, "binInlineMin", void 0);
384
+ _ts_decorate([
385
+ state()
386
+ ], DxGrid.prototype, "binInlineMax", void 0);
387
+ _ts_decorate([
388
+ state()
389
+ ], DxGrid.prototype, "binBlockMin", void 0);
390
+ _ts_decorate([
391
+ state()
392
+ ], DxGrid.prototype, "binBlockMax", void 0);
393
+ _ts_decorate([
394
+ state()
395
+ ], DxGrid.prototype, "visColMin", void 0);
396
+ _ts_decorate([
397
+ state()
398
+ ], DxGrid.prototype, "visColMax", void 0);
399
+ _ts_decorate([
400
+ state()
401
+ ], DxGrid.prototype, "visRowMin", void 0);
402
+ _ts_decorate([
403
+ state()
404
+ ], DxGrid.prototype, "visRowMax", void 0);
405
+ _ts_decorate([
406
+ state()
407
+ ], DxGrid.prototype, "templateColumns", void 0);
408
+ _ts_decorate([
409
+ state()
410
+ ], DxGrid.prototype, "templateRows", void 0);
411
+ _ts_decorate([
412
+ state()
413
+ ], DxGrid.prototype, "colSizes", void 0);
414
+ _ts_decorate([
415
+ state()
416
+ ], DxGrid.prototype, "rowSizes", void 0);
417
+ _ts_decorate([
418
+ state()
419
+ ], DxGrid.prototype, "resizing", void 0);
251
420
  _ts_decorate([
252
421
  state()
253
422
  ], DxGrid.prototype, "observer", void 0);