@dxos/lit-grid 0.8.4-main.84f28bd → 0.8.4-main.a4bbb77

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 (38) hide show
  1. package/dist/src/defs.d.ts +1 -0
  2. package/dist/src/defs.d.ts.map +1 -1
  3. package/dist/src/defs.js +1 -0
  4. package/dist/src/defs.js.map +1 -1
  5. package/dist/src/dx-grid-axis-resize-handle.d.ts.map +1 -1
  6. package/dist/src/dx-grid-axis-resize-handle.js +3 -5
  7. package/dist/src/dx-grid-axis-resize-handle.js.map +1 -1
  8. package/dist/src/dx-grid-multiselect-cell.d.ts.map +1 -1
  9. package/dist/src/dx-grid-multiselect-cell.js +2 -1
  10. package/dist/src/dx-grid-multiselect-cell.js.map +1 -1
  11. package/dist/src/dx-grid.d.ts +12 -7
  12. package/dist/src/dx-grid.d.ts.map +1 -1
  13. package/dist/src/dx-grid.js +195 -157
  14. package/dist/src/dx-grid.js.map +1 -1
  15. package/dist/src/dx-grid.lit-stories.js +15 -18
  16. package/dist/src/dx-grid.lit-stories.js.map +1 -1
  17. package/dist/src/playwright/dx-grid.spec.js.map +1 -1
  18. package/dist/src/testing/dx-grid-manager.d.ts.map +1 -1
  19. package/dist/src/testing/dx-grid-manager.js.map +1 -1
  20. package/dist/src/types.d.ts +9 -0
  21. package/dist/src/types.d.ts.map +1 -1
  22. package/dist/src/types.js.map +1 -1
  23. package/dist/src/util.d.ts +4 -1
  24. package/dist/src/util.d.ts.map +1 -1
  25. package/dist/src/util.js +11 -11
  26. package/dist/src/util.js.map +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +4 -4
  29. package/src/defs.ts +1 -0
  30. package/src/dx-grid-axis-resize-handle.pcss +6 -0
  31. package/src/dx-grid-axis-resize-handle.ts +1 -1
  32. package/src/dx-grid-multiselect-cell.ts +2 -1
  33. package/src/dx-grid.pcss +47 -31
  34. package/src/dx-grid.ts +189 -105
  35. package/src/playwright/dx-grid.spec.ts +1 -1
  36. package/src/testing/dx-grid-manager.ts +1 -1
  37. package/src/types.ts +11 -0
  38. package/src/util.ts +13 -9
package/src/dx-grid.ts CHANGED
@@ -3,62 +3,63 @@
3
3
  //
4
4
 
5
5
  import { LitElement, html, nothing } from 'lit';
6
- import { customElement, state, property } from 'lit/decorators.js';
7
- import { ref, createRef, type Ref } from 'lit/directives/ref.js';
6
+ import { customElement, property, state } from 'lit/decorators.js';
7
+ import { type Ref, createRef, ref } from 'lit/directives/ref.js';
8
8
  import { styleMap } from 'lit/directives/style-map.js';
9
- import { unsafeStatic, html as staticHtml } from 'lit/static-html.js';
9
+ import { html as staticHtml, unsafeStatic } from 'lit/static-html.js';
10
10
 
11
- import { defaultColSize, defaultRowSize } from './defs';
12
- // eslint-disable-next-line unused-imports/no-unused-imports
11
+ import { defaultColSize, defaultRowSize, focusUnfurlDefault } from './defs';
13
12
  import './dx-grid-axis-resize-handle';
14
13
  import {
15
- type DxGridAxisMetaProps,
16
- type DxGridAxisSizes,
17
- type DxGridPlaneCellIndex,
18
- type DxGridCellValue,
19
14
  DxAxisResize,
20
15
  type DxAxisResizeInternal,
21
16
  DxEditRequest,
17
+ type DxGridAnnotatedPanEvent,
18
+ type DxGridAxis,
22
19
  type DxGridAxisMeta,
20
+ type DxGridAxisMetaProps,
21
+ type DxGridAxisSizes,
22
+ type DxGridCellValue,
23
23
  type DxGridCells,
24
24
  DxGridCellsSelect,
25
25
  type DxGridFixedPlane,
26
+ type DxGridFocusIndicatorVariant,
26
27
  type DxGridFrozenAxes,
27
28
  type DxGridFrozenColsPlane,
28
29
  type DxGridFrozenPlane,
29
30
  type DxGridFrozenRowsPlane,
30
31
  type DxGridMode,
32
+ type DxGridOverscroll,
31
33
  type DxGridPlane,
34
+ type DxGridPlaneCellIndex,
32
35
  type DxGridPlaneCells,
33
36
  type DxGridPlaneRange,
34
37
  type DxGridPlaneRecord,
35
38
  type DxGridPointer,
36
39
  type DxGridPosition,
37
- type DxGridAxis,
38
- type DxGridSelectionProps,
39
- type DxGridAnnotatedPanEvent,
40
40
  type DxGridRange,
41
+ type DxGridSelectionProps,
41
42
  separator,
42
43
  } from './types';
43
44
  import {
44
- toCellIndex,
45
- gap,
46
- resizeTolerance,
47
- sizeColMin,
48
- sizeColMax,
49
- sizeRowMin,
50
- sizeRowMax,
51
- shouldSelect,
52
- selectionProps,
53
45
  cellSelected,
54
46
  closestAction,
55
47
  closestCell,
56
- targetIsPlane,
57
- resolveRowPlane,
48
+ gap,
49
+ isReadonly,
50
+ isSameCell,
51
+ resizeTolerance,
58
52
  resolveColPlane,
59
53
  resolveFrozenPlane,
60
- isSameCell,
61
- isReadonly,
54
+ resolveRowPlane,
55
+ selectionProps,
56
+ shouldSelect,
57
+ sizeColMax,
58
+ sizeColMin,
59
+ sizeRowMax,
60
+ sizeRowMin,
61
+ targetIsPlane,
62
+ toCellIndex,
62
63
  } from './util';
63
64
 
64
65
  @customElement('dx-grid')
@@ -84,12 +85,12 @@ export class DxGrid extends LitElement {
84
85
  gridId: string = 'default-grid-id';
85
86
 
86
87
  @property({ type: Object })
87
- rowDefault: DxGridPlaneRecord<DxGridFrozenRowsPlane, DxGridAxisMetaProps> = {
88
+ rowDefault: Partial<DxGridPlaneRecord<DxGridFrozenRowsPlane, Partial<DxGridAxisMetaProps>>> = {
88
89
  grid: { size: defaultRowSize },
89
90
  };
90
91
 
91
92
  @property({ type: Object })
92
- columnDefault: DxGridPlaneRecord<DxGridFrozenColsPlane, DxGridAxisMetaProps> = {
93
+ columnDefault: Partial<DxGridPlaneRecord<DxGridFrozenColsPlane, Partial<DxGridAxisMetaProps>>> = {
93
94
  grid: { size: defaultColSize },
94
95
  };
95
96
 
@@ -115,11 +116,14 @@ export class DxGrid extends LitElement {
115
116
  frozen: DxGridFrozenAxes = {};
116
117
 
117
118
  @property({ type: String })
118
- overscroll: 'inline' | 'block' | 'trap' | undefined = undefined;
119
+ overscroll: DxGridOverscroll = undefined;
119
120
 
120
121
  @property({ type: String })
121
122
  activeRefs = '';
122
123
 
124
+ @property({ type: String })
125
+ focusIndicatorVariant: DxGridFocusIndicatorVariant = 'sheet';
126
+
123
127
  /**
124
128
  * When this function is defined, it is used first to try to get a value for a cell,
125
129
  * and otherwise will fall back to `cells`.
@@ -213,6 +217,16 @@ export class DxGrid extends LitElement {
213
217
  @state()
214
218
  private templatefrozenRowsEnd = '';
215
219
 
220
+ //
221
+ // `frozen…Size` is used to measure space available for the non-fixed planes
222
+ //
223
+
224
+ @state()
225
+ private frozenColsSize = 0;
226
+
227
+ @state()
228
+ private frozenRowsSize = 0;
229
+
216
230
  //
217
231
  // Focus, selection, and resize states
218
232
  //
@@ -416,15 +430,13 @@ export class DxGrid extends LitElement {
416
430
  }
417
431
 
418
432
  private moveFocusIntoPlane(plane: DxGridPlane): void {
419
- if (this.focusedCell.plane !== plane) {
420
- const colPlane = resolveColPlane(plane);
421
- const rowPlane = resolveRowPlane(plane);
422
- this.focusedCell = {
423
- plane,
424
- col: colPlane === 'grid' ? this.visColMin : 0,
425
- row: rowPlane === 'grid' ? this.visRowMin : 0,
426
- };
427
- }
433
+ const colPlane = resolveColPlane(plane);
434
+ const rowPlane = resolveRowPlane(plane);
435
+ this.focusedCell = {
436
+ plane,
437
+ col: colPlane === 'grid' ? this.visColMin : 0,
438
+ row: rowPlane === 'grid' ? this.visRowMin : 0,
439
+ };
428
440
  this.focusedCellElement()?.focus({ preventScroll: true });
429
441
  }
430
442
 
@@ -481,6 +493,13 @@ export class DxGrid extends LitElement {
481
493
  event.preventDefault();
482
494
  this.dispatchEditRequest();
483
495
  break;
496
+ case 'Backspace':
497
+ case 'Delete':
498
+ if (!event.defaultPrevented) {
499
+ event.preventDefault();
500
+ this.dispatchEditRequest('');
501
+ }
502
+ break;
484
503
  default:
485
504
  if (event.key.length === 1 && event.key.match(/\P{Cc}/u) && !(event.metaKey || event.ctrlKey)) {
486
505
  this.dispatchEditRequest(event.key);
@@ -584,19 +603,18 @@ export class DxGrid extends LitElement {
584
603
  blockSize: 0,
585
604
  };
586
605
  if (
587
- Math.abs(inlineSize - this.sizeInline) > resizeTolerance ||
588
- Math.abs(blockSize - this.sizeBlock) > resizeTolerance
606
+ Math.abs(inlineSize - this.frozenColsSize - this.sizeInline) > resizeTolerance ||
607
+ Math.abs(blockSize - this.frozenRowsSize - this.sizeBlock) > resizeTolerance
589
608
  ) {
590
609
  // console.info('[updating bounds]', 'resize', [inlineSize - this.sizeInline, blockSize - this.sizeBlock]);
591
- this.sizeInline = inlineSize;
592
- this.sizeBlock = blockSize;
610
+ this.sizeInline = inlineSize - this.frozenColsSize;
611
+ this.sizeBlock = blockSize - this.frozenRowsSize;
593
612
  this.updateVis();
594
613
  queueMicrotask(() => this.updatePos());
595
614
  }
596
615
  });
597
616
 
598
617
  private gridRef: Ref<HTMLDivElement> = createRef();
599
- private viewportRef: Ref<HTMLDivElement> = createRef();
600
618
 
601
619
  private maybeUpdateVisInline = () => {
602
620
  if (this.posInline < this.binInlineMin || this.posInline >= this.binInlineMax) {
@@ -721,6 +739,15 @@ export class DxGrid extends LitElement {
721
739
  this.templatefrozenColsEnd = [...Array(this.frozen.frozenColsEnd ?? 0)]
722
740
  .map((_, c0) => `${this.colSize(c0, 'frozenColsEnd')}px`)
723
741
  .join(' ');
742
+
743
+ this.frozenColsSize =
744
+ [...Array(this.frozen.frozenColsStart ?? 0)].reduce(
745
+ (sum, _, c0) => sum + this.colSize(c0, 'frozenColsStart'),
746
+ 0,
747
+ ) +
748
+ gap * Math.max(0, this.frozen.frozenColsStart ?? 0 - 1) +
749
+ [...Array(this.frozen.frozenColsEnd ?? 0)].reduce((sum, _, c0) => sum + this.colSize(c0, 'frozenColsEnd'), 0) +
750
+ gap * Math.max(0, this.frozen.frozenColsEnd ?? 0 - 1);
724
751
  }
725
752
 
726
753
  private updateVisBlock(): void {
@@ -770,6 +797,15 @@ export class DxGrid extends LitElement {
770
797
  this.templatefrozenRowsEnd = [...Array(this.frozen.frozenRowsEnd ?? 0)]
771
798
  .map((_, r0) => `${this.rowSize(r0, 'frozenRowsEnd')}px`)
772
799
  .join(' ');
800
+
801
+ this.frozenRowsSize =
802
+ [...Array(this.frozen.frozenRowsStart ?? 0)].reduce(
803
+ (sum, _, r0) => sum + this.rowSize(r0, 'frozenRowsStart'),
804
+ 0,
805
+ ) +
806
+ gap * Math.max(0, this.frozen.frozenRowsStart ?? 0 - 1) +
807
+ [...Array(this.frozen.frozenRowsEnd ?? 0)].reduce((sum, _, r0) => sum + this.rowSize(r0, 'frozenRowsEnd'), 0) +
808
+ gap * Math.max(0, this.frozen.frozenRowsEnd ?? 0 - 1);
773
809
  }
774
810
 
775
811
  private updateVis(): void {
@@ -1068,16 +1104,40 @@ export class DxGrid extends LitElement {
1068
1104
  : !!(this.rows[plane]?.[index]?.resizeable ?? this.rowDefault[plane as DxGridFrozenRowsPlane]?.resizeable);
1069
1105
  }
1070
1106
 
1107
+ private clampAxisSize(
1108
+ plane: 'grid' | DxGridFrozenPlane,
1109
+ axis: DxGridAxis,
1110
+ index: number | string,
1111
+ requestedSize: number,
1112
+ ): number {
1113
+ const minSize =
1114
+ axis === 'col'
1115
+ ? (this.columns[plane]?.[index]?.minSize ??
1116
+ this.columnDefault[plane as DxGridFrozenColsPlane]?.minSize ??
1117
+ sizeColMin)
1118
+ : (this.rows[plane]?.[index]?.minSize ??
1119
+ this.rowDefault[plane as DxGridFrozenRowsPlane]?.minSize ??
1120
+ sizeRowMin);
1121
+ const maxSize =
1122
+ axis === 'col'
1123
+ ? (this.columns[plane]?.[index]?.maxSize ??
1124
+ this.columnDefault[plane as DxGridFrozenColsPlane]?.maxSize ??
1125
+ sizeColMax)
1126
+ : (this.rows[plane]?.[index]?.maxSize ??
1127
+ this.rowDefault[plane as DxGridFrozenRowsPlane]?.maxSize ??
1128
+ sizeRowMax);
1129
+ return Math.max(minSize, Math.min(maxSize, requestedSize));
1130
+ }
1131
+
1071
1132
  private handleAxisResizeInternal(event: DxAxisResizeInternal): void {
1072
1133
  event.stopPropagation();
1073
1134
  const { plane, axis, delta, size, index, state } = event;
1135
+ const nextSize = this.clampAxisSize(plane, axis, index, size + delta);
1074
1136
  if (axis === 'col') {
1075
- const nextSize = Math.max(sizeColMin, Math.min(sizeColMax, size + delta));
1076
1137
  this.colSizes = { ...this.colSizes, [plane]: { ...this.colSizes[plane], [index]: nextSize } };
1077
1138
  this.updateVisInline();
1078
1139
  this.updateIntrinsicInlineSize();
1079
1140
  } else {
1080
- const nextSize = Math.max(sizeRowMin, Math.min(sizeRowMax, size + delta));
1081
1141
  this.rowSizes = { ...this.colSizes, [plane]: { ...this.rowSizes[plane], [index]: nextSize } };
1082
1142
  this.updateVisBlock();
1083
1143
  this.updateIntrinsicBlockSize();
@@ -1178,7 +1238,7 @@ export class DxGrid extends LitElement {
1178
1238
  ) {
1179
1239
  const rowPlane = resolveRowPlane(plane) as DxGridFrozenPlane;
1180
1240
  const rows = this.frozen[rowPlane];
1181
- return (rows ?? 0) > 0
1241
+ return (rows ?? 0) > 0 && this.limitColumns > 0
1182
1242
  ? html`<div
1183
1243
  role="none"
1184
1244
  class="dx-grid__plane--frozen-row"
@@ -1212,7 +1272,7 @@ export class DxGrid extends LitElement {
1212
1272
  ) {
1213
1273
  const colPlane = resolveColPlane(plane) as DxGridFrozenPlane;
1214
1274
  const cols = this.frozen[colPlane];
1215
- return (cols ?? 0) > 0
1275
+ return (cols ?? 0) > 0 && this.limitRows > 0
1216
1276
  ? html`<div
1217
1277
  role="none"
1218
1278
  class="dx-grid__plane--frozen-col"
@@ -1238,6 +1298,40 @@ export class DxGrid extends LitElement {
1238
1298
  : null;
1239
1299
  }
1240
1300
 
1301
+ private renderMainGrid(
1302
+ visibleCols: number,
1303
+ visibleRows: number,
1304
+ offsetInline: number,
1305
+ offsetBlock: number,
1306
+ selection: DxGridSelectionProps,
1307
+ ) {
1308
+ return this.limitRows > 0 && this.limitColumns > 0
1309
+ ? html`<div
1310
+ role="grid"
1311
+ class="dx-grid__plane--grid"
1312
+ tabindex="0"
1313
+ data-dx-grid-plane="grid"
1314
+ data-dx-grid-plane-row="1"
1315
+ data-dx-grid-plane-col="1"
1316
+ >
1317
+ <div
1318
+ role="none"
1319
+ class="dx-grid__plane--grid__content"
1320
+ style="transform:translate3d(${offsetInline}px,${offsetBlock}px,0);grid-template-columns:${this
1321
+ .templateGridColumns};grid-template-rows:${this.templateGridRows};"
1322
+ >
1323
+ ${[...Array(visibleRows)].map((_, r0) => {
1324
+ return [...Array(visibleCols)].map((_, c0) => {
1325
+ const c = c0 + this.visColMin;
1326
+ const r = r0 + this.visRowMin;
1327
+ return this.renderCell(c, r, 'grid', cellSelected(c, r, 'grid', selection), c0, r0);
1328
+ });
1329
+ })}
1330
+ </div>
1331
+ </div>`
1332
+ : null;
1333
+ }
1334
+
1241
1335
  private cellReadonly(col: number, row: number, plane: DxGridPlane): boolean {
1242
1336
  const colPlane = resolveColPlane(plane);
1243
1337
  const rowPlane = resolveRowPlane(plane);
@@ -1255,6 +1349,23 @@ export class DxGrid extends LitElement {
1255
1349
  return isReadonly(colReadOnly) || isReadonly(rowReadOnly);
1256
1350
  }
1257
1351
 
1352
+ private cellFocusUnfurl(col: number, row: number, plane: DxGridPlane): boolean {
1353
+ const colPlane = resolveColPlane(plane);
1354
+ const rowPlane = resolveRowPlane(plane);
1355
+
1356
+ // Check cell-specific setting first.
1357
+ const cellUnfurl = this.cell(col, row, plane)?.focusUnfurl;
1358
+ if (cellUnfurl !== undefined) {
1359
+ return cellUnfurl;
1360
+ }
1361
+
1362
+ // Check column/row defaults.
1363
+ const colUnfurl = this.columns?.[colPlane]?.[col]?.focusUnfurl ?? this.columnDefault?.[colPlane]?.focusUnfurl;
1364
+ const rowUnfurl = this.rows?.[rowPlane]?.[row]?.focusUnfurl ?? this.rowDefault?.[rowPlane]?.focusUnfurl;
1365
+
1366
+ return colUnfurl ?? rowUnfurl ?? focusUnfurlDefault;
1367
+ }
1368
+
1258
1369
  /**
1259
1370
  * Determines if the cell's text content should be selectable based on its readonly value.
1260
1371
  * @returns true if the cells text content is selectable, false otherwise.
@@ -1317,6 +1428,7 @@ export class DxGrid extends LitElement {
1317
1428
  const cell = this.cell(col, row, plane);
1318
1429
  const active = this.cellActive(col, row, plane);
1319
1430
  const readonly = this.cellReadonly(col, row, plane);
1431
+ const focusUnfurl = this.cellFocusUnfurl(col, row, plane);
1320
1432
  const textSelectable = this.cellTextSelectable(col, row, plane);
1321
1433
  const resizeIndex = cell?.resizeHandle ? (cell.resizeHandle === 'col' ? col : row) : undefined;
1322
1434
  const resizePlane = cell?.resizeHandle ? resolveFrozenPlane(cell.resizeHandle, plane) : undefined;
@@ -1328,6 +1440,7 @@ export class DxGrid extends LitElement {
1328
1440
  aria-readonly=${readonly ? 'true' : nothing}
1329
1441
  class=${cell?.className ?? nothing}
1330
1442
  data-refs=${cell?.dataRefs ?? nothing}
1443
+ data-focus-unfurl=${focusUnfurl ? nothing : 'false'}
1331
1444
  ?data-dx-active=${active}
1332
1445
  data-text-selectable=${textSelectable ? 'true' : 'false'}
1333
1446
  data-dx-grid-action="cell"
@@ -1335,9 +1448,7 @@ export class DxGrid extends LitElement {
1335
1448
  aria-rowindex=${row}
1336
1449
  style="grid-column:${visCol + 1};grid-row:${visRow + 1}"
1337
1450
  >
1338
- <div role="none" class="dx-grid__cell__content">
1339
- ${this.mode !== 'browse' && active ? null : cell?.value}${this.mode !== 'browse' && active ? null : accessory}
1340
- </div>
1451
+ <div role="none" class="dx-grid__cell__content">${cell?.value}${accessory}</div>
1341
1452
  ${cell?.resizeHandle &&
1342
1453
  this.mode === 'browse' &&
1343
1454
  this.axisResizeable(resizePlane!, cell.resizeHandle, resizeIndex!)
@@ -1372,13 +1483,24 @@ export class DxGrid extends LitElement {
1372
1483
  <div
1373
1484
  role="none"
1374
1485
  class="dx-grid"
1486
+ data-arrow-keys="all"
1375
1487
  style=${styleMap({
1376
- 'grid-template-columns': `${this.templatefrozenColsStart ? 'min-content ' : ''}minmax(0, ${
1377
- Number.isFinite(this.limitColumns) ? `${Math.max(0, this.intrinsicInlineSize)}px` : '1fr'
1378
- })${this.templatefrozenColsEnd ? ' min-content' : ''}`,
1379
- 'grid-template-rows': `${this.templatefrozenRowsStart ? 'min-content ' : ''}minmax(0, ${
1380
- Number.isFinite(this.limitRows) ? `${Math.max(0, this.intrinsicBlockSize)}px` : '1fr'
1381
- })${this.templatefrozenRowsEnd ? ' min-content' : ''}`,
1488
+ 'grid-template-columns': [
1489
+ this.templatefrozenColsStart ? 'min-content' : false,
1490
+ this.limitColumns > 0 &&
1491
+ `minmax(0, ${Number.isFinite(this.limitColumns) ? `${Math.max(0, this.intrinsicInlineSize)}px` : '1fr'})`,
1492
+ this.templatefrozenColsEnd ? 'min-content' : false,
1493
+ ]
1494
+ .filter(Boolean)
1495
+ .join(' '),
1496
+ 'grid-template-rows': [
1497
+ this.templatefrozenRowsStart ? 'min-content' : false,
1498
+ this.limitRows > 0 &&
1499
+ `minmax(0, ${Number.isFinite(this.limitRows) ? `${Math.max(0, this.intrinsicBlockSize)}px` : '1fr'})`,
1500
+ this.templatefrozenRowsEnd ? ' min-content' : false,
1501
+ ]
1502
+ .filter(Boolean)
1503
+ .join(' '),
1382
1504
  '--dx-grid-content-inline-size': Number.isFinite(this.limitColumns)
1383
1505
  ? `${Math.max(0, this.totalIntrinsicInlineSize)}px`
1384
1506
  : 'max-content',
@@ -1388,6 +1510,7 @@ export class DxGrid extends LitElement {
1388
1510
  })}
1389
1511
  data-grid=${this.gridId}
1390
1512
  data-grid-mode=${this.mode}
1513
+ data-grid-focus-indicator-variant=${this.focusIndicatorVariant}
1391
1514
  ?data-grid-select=${selection.visible}
1392
1515
  ${ref(this.gridRef)}
1393
1516
  >
@@ -1402,30 +1525,7 @@ export class DxGrid extends LitElement {
1402
1525
  offsetBlock,
1403
1526
  selection,
1404
1527
  )}
1405
- <div
1406
- role="grid"
1407
- class="dx-grid__plane--grid"
1408
- tabindex="0"
1409
- data-dx-grid-plane="grid"
1410
- data-dx-grid-plane-row="1"
1411
- data-dx-grid-plane-col="1"
1412
- ${ref(this.viewportRef)}
1413
- >
1414
- <div
1415
- role="none"
1416
- class="dx-grid__plane--grid__content"
1417
- style="transform:translate3d(${offsetInline}px,${offsetBlock}px,0);grid-template-columns:${this
1418
- .templateGridColumns};grid-template-rows:${this.templateGridRows};"
1419
- >
1420
- ${[...Array(visibleRows)].map((_, r0) => {
1421
- return [...Array(visibleCols)].map((_, c0) => {
1422
- const c = c0 + this.visColMin;
1423
- const r = r0 + this.visRowMin;
1424
- return this.renderCell(c, r, 'grid', cellSelected(c, r, 'grid', selection), c0, r0);
1425
- });
1426
- })}
1427
- </div>
1428
- </div>
1528
+ ${this.renderMainGrid(visibleCols, visibleRows, offsetInline, offsetBlock, selection)}
1429
1529
  ${this.renderFrozenColumns('frozenColsEnd', visibleRows, offsetBlock, selection)}${this.renderFixed(
1430
1530
  'fixedEndStart',
1431
1531
  selection,
@@ -1439,37 +1539,19 @@ export class DxGrid extends LitElement {
1439
1539
  private updateIntrinsicInlineSize(): void {
1440
1540
  this.intrinsicInlineSize = Number.isFinite(this.limitColumns)
1441
1541
  ? [...Array(this.limitColumns)].reduce((acc, _, c0) => acc + this.colSize(c0, 'grid'), 0) +
1442
- gap * (this.limitColumns - 1)
1542
+ gap * Math.max(0, this.limitColumns - 1)
1443
1543
  : Infinity;
1444
1544
  this.totalIntrinsicInlineSize =
1445
- this.intrinsicInlineSize +
1446
- (Number.isFinite(this.frozen.frozenColsStart)
1447
- ? [...Array(this.frozen.frozenColsStart)].reduce(
1448
- (acc, _, c0) => acc + gap + this.colSize(c0, 'frozenColsStart'),
1449
- 0,
1450
- )
1451
- : 0) +
1452
- (Number.isFinite(this.frozen.frozenColsEnd)
1453
- ? [...Array(this.frozen.frozenColsEnd)].reduce((acc, _, c0) => acc + gap + this.colSize(c0, 'frozenColsEnd'), 0)
1454
- : 0);
1545
+ this.limitColumns > 0 ? this.intrinsicInlineSize + this.frozenColsSize : this.frozenColsSize - gap;
1455
1546
  }
1456
1547
 
1457
1548
  private updateIntrinsicBlockSize(): void {
1458
1549
  this.intrinsicBlockSize = Number.isFinite(this.limitRows)
1459
1550
  ? [...Array(this.limitRows)].reduce((acc, _, r0) => acc + this.rowSize(r0, 'grid'), 0) +
1460
- gap * (this.limitRows - 1)
1551
+ gap * Math.max(0, this.limitRows - 1)
1461
1552
  : Infinity;
1462
1553
  this.totalIntrinsicBlockSize =
1463
- this.intrinsicBlockSize +
1464
- (Number.isFinite(this.frozen.frozenRowsStart)
1465
- ? [...Array(this.frozen.frozenRowsStart)].reduce(
1466
- (acc, _, r0) => acc + gap + this.rowSize(r0, 'frozenRowsStart'),
1467
- 0,
1468
- )
1469
- : 0) +
1470
- (Number.isFinite(this.frozen.frozenRowsEnd)
1471
- ? [...Array(this.frozen.frozenRowsEnd)].reduce((acc, _, r0) => acc + gap + this.rowSize(r0, 'frozenRowsEnd'), 0)
1472
- : 0);
1554
+ this.limitRows > 0 ? this.intrinsicBlockSize + this.frozenRowsSize : this.frozenRowsSize - gap;
1473
1555
  }
1474
1556
 
1475
1557
  private updateIntrinsicSizes(): void {
@@ -1517,7 +1599,7 @@ export class DxGrid extends LitElement {
1517
1599
  if (this.getCells) {
1518
1600
  this.updateCells(true);
1519
1601
  }
1520
- this.observer.observe(this.viewportRef.value!);
1602
+ this.observer.observe(this.gridRef.value!);
1521
1603
  this.computeColSizes();
1522
1604
  this.computeRowSizes();
1523
1605
  this.updateIntrinsicSizes();
@@ -1580,8 +1662,9 @@ export class DxGrid extends LitElement {
1580
1662
  }
1581
1663
  }
1582
1664
 
1583
- public updateIfWithinBounds({ col, row }: { col: number; row: number }): boolean {
1665
+ public updateIfWithinBounds({ col, row }: { col: number; row: number }, includeFixed?: boolean): boolean {
1584
1666
  if (col >= this.visColMin && col <= this.visColMax && row >= this.visRowMin && row <= this.visRowMax) {
1667
+ this.updateCells(includeFixed);
1585
1668
  this.requestUpdate();
1586
1669
  return true;
1587
1670
  }
@@ -1590,8 +1673,8 @@ export class DxGrid extends LitElement {
1590
1673
 
1591
1674
  override disconnectedCallback(): void {
1592
1675
  super.disconnectedCallback();
1593
- if (this.viewportRef.value) {
1594
- this.observer.unobserve(this.viewportRef.value);
1676
+ if (this.gridRef.value) {
1677
+ this.observer.unobserve(this.gridRef.value);
1595
1678
  }
1596
1679
  document.defaultView?.removeEventListener('wheel', this.handleTopLevelWheel);
1597
1680
  }
@@ -1609,6 +1692,7 @@ export {
1609
1692
  parseCellIndex,
1610
1693
  toPlaneCellIndex,
1611
1694
  cellQuery,
1695
+ accessoryHandlesPointerdownAttrs,
1612
1696
  } from './util';
1613
1697
 
1614
1698
  export const commentedClassName = 'dx-grid__cell--commented';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2021 DXOS.org
3
3
  //
4
4
 
5
- import { expect, test, type Page } from '@playwright/test';
5
+ import { type Page, expect, test } from '@playwright/test';
6
6
 
7
7
  import { setupPage, storybookUrl } from '@dxos/test-utils/playwright';
8
8
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { expect, type Locator, type Page } from '@playwright/test';
5
+ import { type Locator, type Page, expect } from '@playwright/test';
6
6
 
7
7
  import type { DxGridPlanePosition } from '../types';
8
8
 
package/src/types.ts CHANGED
@@ -83,6 +83,10 @@ export type DxGridCellValue = {
83
83
  * Controls the read-only state of the cell.
84
84
  */
85
85
  readonly?: DxGridReadonlyValue;
86
+ /**
87
+ * Controls whether the cell content should unfurl when the cell has focus.
88
+ */
89
+ focusUnfurl?: boolean;
86
90
  };
87
91
 
88
92
  export type DxGridAxisMetaProps = {
@@ -90,6 +94,9 @@ export type DxGridAxisMetaProps = {
90
94
  description?: string;
91
95
  resizeable?: boolean;
92
96
  readonly?: DxGridReadonlyValue;
97
+ focusUnfurl?: boolean;
98
+ minSize?: number;
99
+ maxSize?: number;
93
100
  };
94
101
 
95
102
  export type DxGridAxisSizes = DxGridPlaneRecord<DxGridFrozenPlane, Record<string, number>>;
@@ -121,6 +128,10 @@ export type DxGridSelectionProps = {
121
128
  visible?: boolean;
122
129
  };
123
130
 
131
+ export type DxGridFocusIndicatorVariant = 'sheet' | 'stack';
132
+
133
+ export type DxGridOverscroll = 'inline' | 'block' | 'trap' | undefined;
134
+
124
135
  export class DxAxisResize extends Event {
125
136
  public readonly axis: DxGridAxis;
126
137
  public readonly plane: 'grid' | DxGridFrozenPlane;
package/src/util.ts CHANGED
@@ -4,19 +4,19 @@
4
4
 
5
5
  import { defaultRowSize } from './defs';
6
6
  import {
7
- type DxGridPlaneCellIndex,
7
+ type DxGridAxis,
8
8
  type DxGridCellIndex,
9
- type DxGridPosition,
10
- type DxGridPointer,
11
- type DxGridSelectionProps,
12
- type DxGridPositionNullable,
13
- type DxGridPlane,
14
- type DxGridFrozenRowsPlane,
15
9
  type DxGridFrozenColsPlane,
16
10
  type DxGridFrozenPlane,
17
- type DxGridAxis,
11
+ type DxGridFrozenRowsPlane,
12
+ type DxGridPlane,
13
+ type DxGridPlaneCellIndex,
18
14
  type DxGridPlanePosition,
15
+ type DxGridPointer,
16
+ type DxGridPosition,
17
+ type DxGridPositionNullable,
19
18
  type DxGridReadonlyValue,
19
+ type DxGridSelectionProps,
20
20
  separator,
21
21
  } from './types';
22
22
 
@@ -25,7 +25,7 @@ export const toPlaneCellIndex = (cellCoords: Partial<DxGridPosition> & DxGridPla
25
25
 
26
26
  export function parseCellIndex(index: DxGridCellIndex): DxGridPosition;
27
27
  export function parseCellIndex(index: DxGridPlaneCellIndex): DxGridPlanePosition;
28
- // eslint-disable-next-line @stayradiated/prefer-arrow-functions/prefer-arrow-functions
28
+
29
29
  export function parseCellIndex(index: DxGridPlaneCellIndex | DxGridCellIndex): DxGridPlanePosition | DxGridPosition {
30
30
  const coords = index.split(separator);
31
31
  if (coords.length === 3) {
@@ -123,6 +123,10 @@ export const closestAction = (target: EventTarget | null): { action: string | nu
123
123
  return { actionEl, action: actionEl?.getAttribute('data-dx-grid-action') ?? null };
124
124
  };
125
125
 
126
+ export const accessoryHandlesPointerdownAttrs = {
127
+ 'data-dx-grid-action': 'accessory',
128
+ };
129
+
126
130
  export const closestCell = (target: EventTarget | null, actionEl?: HTMLElement | null): DxGridPositionNullable => {
127
131
  let cellElement = actionEl;
128
132
  if (!cellElement) {