@dxos/lit-grid 0.8.3 → 0.8.4-main.1068cf700f

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 (107) 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 +14 -8
  12. package/dist/src/dx-grid.d.ts.map +1 -1
  13. package/dist/src/dx-grid.js +251 -168
  14. package/dist/src/dx-grid.js.map +1 -1
  15. package/dist/src/dx-grid.lit-stories.d.ts +1 -0
  16. package/dist/src/dx-grid.lit-stories.d.ts.map +1 -1
  17. package/dist/src/dx-grid.lit-stories.js +21 -22
  18. package/dist/src/dx-grid.lit-stories.js.map +1 -1
  19. package/dist/src/playwright/dx-grid.spec.d.ts.map +1 -0
  20. package/dist/src/{testing/playwright → playwright}/dx-grid.spec.js +3 -3
  21. package/dist/src/playwright/dx-grid.spec.js.map +1 -0
  22. package/dist/src/playwright/playwright.config.d.ts +3 -0
  23. package/dist/src/playwright/playwright.config.d.ts.map +1 -0
  24. package/dist/src/playwright/playwright.config.js +15 -0
  25. package/dist/src/playwright/playwright.config.js.map +1 -0
  26. package/dist/src/testing/{playwright/dx-grid-manager.d.ts → dx-grid-manager.d.ts} +1 -1
  27. package/dist/src/testing/dx-grid-manager.d.ts.map +1 -0
  28. package/dist/src/testing/dx-grid-manager.js.map +1 -0
  29. package/dist/src/testing/index.d.ts +1 -1
  30. package/dist/src/testing/index.d.ts.map +1 -1
  31. package/dist/src/testing/index.js +1 -1
  32. package/dist/src/testing/index.js.map +1 -1
  33. package/dist/src/types.d.ts +9 -0
  34. package/dist/src/types.d.ts.map +1 -1
  35. package/dist/src/types.js.map +1 -1
  36. package/dist/src/util.d.ts +4 -1
  37. package/dist/src/util.d.ts.map +1 -1
  38. package/dist/src/util.js +11 -11
  39. package/dist/src/util.js.map +1 -1
  40. package/dist/tsconfig.tsbuildinfo +1 -1
  41. package/package.json +16 -8
  42. package/src/defs.ts +1 -0
  43. package/src/dx-grid-axis-resize-handle.pcss +7 -0
  44. package/src/dx-grid-axis-resize-handle.ts +1 -1
  45. package/src/dx-grid-multiselect-cell.pcss +2 -2
  46. package/src/dx-grid-multiselect-cell.ts +2 -1
  47. package/src/dx-grid.lit-stories.ts +6 -2
  48. package/src/dx-grid.pcss +135 -17
  49. package/src/dx-grid.ts +265 -119
  50. package/src/{testing/playwright → playwright}/dx-grid.spec.ts +5 -5
  51. package/src/playwright/playwright.config.ts +17 -0
  52. package/src/testing/{playwright/dx-grid-manager.ts → dx-grid-manager.ts} +2 -2
  53. package/src/testing/index.ts +1 -1
  54. package/src/types.ts +11 -0
  55. package/src/util.ts +13 -9
  56. package/dist/src/testing/playwright/dx-grid-manager.d.ts.map +0 -1
  57. package/dist/src/testing/playwright/dx-grid-manager.js.map +0 -1
  58. package/dist/src/testing/playwright/dx-grid.spec.d.ts.map +0 -1
  59. package/dist/src/testing/playwright/dx-grid.spec.js.map +0 -1
  60. package/dist/types/src/defs.d.ts +0 -3
  61. package/dist/types/src/defs.d.ts.map +0 -1
  62. package/dist/types/src/defs.js +0 -6
  63. package/dist/types/src/defs.js.map +0 -1
  64. package/dist/types/src/dx-grid-axis-resize-handle.d.ts +0 -16
  65. package/dist/types/src/dx-grid-axis-resize-handle.d.ts.map +0 -1
  66. package/dist/types/src/dx-grid-axis-resize-handle.js +0 -100
  67. package/dist/types/src/dx-grid-axis-resize-handle.js.map +0 -1
  68. package/dist/types/src/dx-grid-multiselect-cell.d.ts +0 -13
  69. package/dist/types/src/dx-grid-multiselect-cell.d.ts.map +0 -1
  70. package/dist/types/src/dx-grid-multiselect-cell.js +0 -56
  71. package/dist/types/src/dx-grid-multiselect-cell.js.map +0 -1
  72. package/dist/types/src/dx-grid.d.ts +0 -170
  73. package/dist/types/src/dx-grid.d.ts.map +0 -1
  74. package/dist/types/src/dx-grid.js +0 -1347
  75. package/dist/types/src/dx-grid.js.map +0 -1
  76. package/dist/types/src/dx-grid.lit-stories.d.ts +0 -46
  77. package/dist/types/src/dx-grid.lit-stories.d.ts.map +0 -1
  78. package/dist/types/src/dx-grid.lit-stories.js +0 -179
  79. package/dist/types/src/dx-grid.lit-stories.js.map +0 -1
  80. package/dist/types/src/index.d.ts +0 -5
  81. package/dist/types/src/index.d.ts.map +0 -1
  82. package/dist/types/src/index.js +0 -8
  83. package/dist/types/src/index.js.map +0 -1
  84. package/dist/types/src/testing/index.d.ts +0 -2
  85. package/dist/types/src/testing/index.d.ts.map +0 -1
  86. package/dist/types/src/testing/index.js +0 -5
  87. package/dist/types/src/testing/index.js.map +0 -1
  88. package/dist/types/src/testing/playwright/dx-grid-manager.d.ts +0 -24
  89. package/dist/types/src/testing/playwright/dx-grid-manager.d.ts.map +0 -1
  90. package/dist/types/src/testing/playwright/dx-grid-manager.js +0 -79
  91. package/dist/types/src/testing/playwright/dx-grid-manager.js.map +0 -1
  92. package/dist/types/src/testing/playwright/dx-grid.spec.d.ts +0 -2
  93. package/dist/types/src/testing/playwright/dx-grid.spec.d.ts.map +0 -1
  94. package/dist/types/src/testing/playwright/dx-grid.spec.js +0 -92
  95. package/dist/types/src/testing/playwright/dx-grid.spec.js.map +0 -1
  96. package/dist/types/src/types.d.ts +0 -137
  97. package/dist/types/src/types.d.ts.map +0 -1
  98. package/dist/types/src/types.js +0 -46
  99. package/dist/types/src/types.js.map +0 -1
  100. package/dist/types/src/util.d.ts +0 -39
  101. package/dist/types/src/util.d.ts.map +0 -1
  102. package/dist/types/src/util.js +0 -165
  103. package/dist/types/src/util.js.map +0 -1
  104. package/dist/types/tsconfig.tsbuildinfo +0 -1
  105. package/src/testing/playwright/playwright.config.cts +0 -18
  106. /package/dist/src/{testing/playwright → playwright}/dx-grid.spec.d.ts +0 -0
  107. /package/dist/src/testing/{playwright/dx-grid-manager.js → dx-grid-manager.js} +0 -0
package/src/dx-grid.ts CHANGED
@@ -3,74 +3,75 @@
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')
65
66
  export class DxGrid extends LitElement {
66
67
  constructor() {
67
68
  super();
68
- // Wheel, top-level and element-level
69
+ // Wheel, top-level and element-level.
69
70
  document.defaultView?.addEventListener('wheel', this.handleTopLevelWheel, { passive: false });
70
71
  this.addEventListener('wheel', this.handleWheel);
71
- // Custom event(s)
72
+ // Custom event(s).
72
73
  this.addEventListener('dx-axis-resize-internal', this.handleAxisResizeInternal as EventListener);
73
- // Standard events
74
+ // Standard events.
74
75
  this.addEventListener('pointerdown', this.handlePointerDown);
75
76
  this.addEventListener('pointermove', this.handlePointerMove);
76
77
  this.addEventListener('pointerup', this.handlePointerUp);
@@ -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`.
@@ -195,6 +199,7 @@ export class DxGrid extends LitElement {
195
199
  //
196
200
  // `template` is the rendered value of `grid-{axis}-template`.
197
201
  //
202
+
198
203
  @state()
199
204
  private templateGridColumns = '0';
200
205
 
@@ -213,6 +218,16 @@ export class DxGrid extends LitElement {
213
218
  @state()
214
219
  private templatefrozenRowsEnd = '';
215
220
 
221
+ //
222
+ // `frozen…Size` is used to measure space available for the non-fixed planes
223
+ //
224
+
225
+ @state()
226
+ private frozenColsSize = 0;
227
+
228
+ @state()
229
+ private frozenRowsSize = 0;
230
+
216
231
  //
217
232
  // Focus, selection, and resize states
218
233
  //
@@ -308,7 +323,7 @@ export class DxGrid extends LitElement {
308
323
  this.dispatchSelectionChange();
309
324
  }
310
325
  if (this.mode === 'edit-select') {
311
- // Prevent focus moving when editing while selection is possible
326
+ // Prevent focus moving when editing while selection is possible.
312
327
  event.preventDefault();
313
328
  } else if (this.focusActive && isSameCell(this.focusedCell, cellCoords)) {
314
329
  this.dispatchEditRequest();
@@ -416,15 +431,13 @@ export class DxGrid extends LitElement {
416
431
  }
417
432
 
418
433
  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
- }
434
+ const colPlane = resolveColPlane(plane);
435
+ const rowPlane = resolveRowPlane(plane);
436
+ this.focusedCell = {
437
+ plane,
438
+ col: colPlane === 'grid' ? this.visColMin : 0,
439
+ row: rowPlane === 'grid' ? this.visRowMin : 0,
440
+ };
428
441
  this.focusedCellElement()?.focus({ preventScroll: true });
429
442
  }
430
443
 
@@ -481,6 +494,13 @@ export class DxGrid extends LitElement {
481
494
  event.preventDefault();
482
495
  this.dispatchEditRequest();
483
496
  break;
497
+ case 'Backspace':
498
+ case 'Delete':
499
+ if (!event.defaultPrevented) {
500
+ event.preventDefault();
501
+ this.dispatchEditRequest('');
502
+ }
503
+ break;
484
504
  default:
485
505
  if (event.key.length === 1 && event.key.match(/\P{Cc}/u) && !(event.metaKey || event.ctrlKey)) {
486
506
  this.dispatchEditRequest(event.key);
@@ -574,7 +594,7 @@ export class DxGrid extends LitElement {
574
594
  }
575
595
 
576
596
  //
577
- // Resize & reposition handlers, observer, ref
597
+ // Resize & reposition handlers, observer, ref.
578
598
  //
579
599
 
580
600
  @state()
@@ -584,19 +604,18 @@ export class DxGrid extends LitElement {
584
604
  blockSize: 0,
585
605
  };
586
606
  if (
587
- Math.abs(inlineSize - this.sizeInline) > resizeTolerance ||
588
- Math.abs(blockSize - this.sizeBlock) > resizeTolerance
607
+ Math.abs(inlineSize - this.frozenColsSize - this.sizeInline) > resizeTolerance ||
608
+ Math.abs(blockSize - this.frozenRowsSize - this.sizeBlock) > resizeTolerance
589
609
  ) {
590
610
  // console.info('[updating bounds]', 'resize', [inlineSize - this.sizeInline, blockSize - this.sizeBlock]);
591
- this.sizeInline = inlineSize;
592
- this.sizeBlock = blockSize;
611
+ this.sizeInline = inlineSize - this.frozenColsSize;
612
+ this.sizeBlock = blockSize - this.frozenRowsSize;
593
613
  this.updateVis();
594
614
  queueMicrotask(() => this.updatePos());
595
615
  }
596
616
  });
597
617
 
598
618
  private gridRef: Ref<HTMLDivElement> = createRef();
599
- private viewportRef: Ref<HTMLDivElement> = createRef();
600
619
 
601
620
  private maybeUpdateVisInline = () => {
602
621
  if (this.posInline < this.binInlineMin || this.posInline >= this.binInlineMax) {
@@ -640,16 +659,29 @@ export class DxGrid extends LitElement {
640
659
  (this.overscroll === 'inline' && event.overscrollInline === 0) ||
641
660
  (this.overscroll === 'block' && event.overscrollBlock === 0)
642
661
  ) {
643
- event.preventDefault();
644
- event.stopPropagation();
662
+ const element = event.target as HTMLElement;
663
+ const activeCell = element.closest('[data-dx-active]');
664
+ const contentEl = element.closest('.dx-grid__cell__content');
665
+ if (
666
+ !(
667
+ element &&
668
+ activeCell &&
669
+ contentEl &&
670
+ (contentEl.scrollWidth > contentEl.clientWidth || contentEl.scrollHeight > contentEl.clientHeight)
671
+ )
672
+ ) {
673
+ event.preventDefault();
674
+ event.stopPropagation();
675
+ }
645
676
  }
646
677
  }
647
678
  };
648
679
 
649
680
  private handleWheel = (event: DxGridAnnotatedPanEvent) => {
650
681
  if (this.mode === 'browse') {
651
- const nextPosInline = this.posInline + event.deltaX;
652
- const nextPosBlock = this.posBlock + event.deltaY;
682
+ const { deltaX, deltaY } = this.getOverflowingCellModifiedDeltas(event);
683
+ const nextPosInline = this.posInline + deltaX;
684
+ const nextPosBlock = this.posBlock + deltaY;
653
685
  const maxPosInline = this.maxPosInline();
654
686
  const maxPosBlock = this.maxPosBlock();
655
687
  this.updatePos(nextPosInline, nextPosBlock, maxPosInline, maxPosBlock);
@@ -662,7 +694,7 @@ export class DxGrid extends LitElement {
662
694
  };
663
695
 
664
696
  private updateVisInline(): void {
665
- // todo: avoid starting from zero
697
+ // todo: avoid starting from zero.
666
698
  let axisCursor = 0;
667
699
  let pxCursor = this.colSize(axisCursor, 'grid');
668
700
 
@@ -708,10 +740,19 @@ export class DxGrid extends LitElement {
708
740
  this.templatefrozenColsEnd = [...Array(this.frozen.frozenColsEnd ?? 0)]
709
741
  .map((_, c0) => `${this.colSize(c0, 'frozenColsEnd')}px`)
710
742
  .join(' ');
743
+
744
+ this.frozenColsSize =
745
+ [...Array(this.frozen.frozenColsStart ?? 0)].reduce(
746
+ (sum, _, c0) => sum + this.colSize(c0, 'frozenColsStart'),
747
+ 0,
748
+ ) +
749
+ gap * Math.max(0, this.frozen.frozenColsStart ?? 0 - 1) +
750
+ [...Array(this.frozen.frozenColsEnd ?? 0)].reduce((sum, _, c0) => sum + this.colSize(c0, 'frozenColsEnd'), 0) +
751
+ gap * Math.max(0, this.frozen.frozenColsEnd ?? 0 - 1);
711
752
  }
712
753
 
713
754
  private updateVisBlock(): void {
714
- // todo: avoid starting from zero
755
+ // todo: avoid starting from zero.
715
756
  let axisCursor = 0;
716
757
  let pxCursor = this.rowSize(axisCursor, 'grid');
717
758
 
@@ -757,6 +798,15 @@ export class DxGrid extends LitElement {
757
798
  this.templatefrozenRowsEnd = [...Array(this.frozen.frozenRowsEnd ?? 0)]
758
799
  .map((_, r0) => `${this.rowSize(r0, 'frozenRowsEnd')}px`)
759
800
  .join(' ');
801
+
802
+ this.frozenRowsSize =
803
+ [...Array(this.frozen.frozenRowsStart ?? 0)].reduce(
804
+ (sum, _, r0) => sum + this.rowSize(r0, 'frozenRowsStart'),
805
+ 0,
806
+ ) +
807
+ gap * Math.max(0, this.frozen.frozenRowsStart ?? 0 - 1) +
808
+ [...Array(this.frozen.frozenRowsEnd ?? 0)].reduce((sum, _, r0) => sum + this.rowSize(r0, 'frozenRowsEnd'), 0) +
809
+ gap * Math.max(0, this.frozen.frozenRowsEnd ?? 0 - 1);
760
810
  }
761
811
 
762
812
  private updateVis(): void {
@@ -978,7 +1028,7 @@ export class DxGrid extends LitElement {
978
1028
  }
979
1029
 
980
1030
  /**
981
- * Updates `pos` so that a cell in focus is fully within the viewport
1031
+ * Updates `pos` so that a cell in focus is fully within the viewport.
982
1032
  */
983
1033
  snapPosToFocusedCell(): void {
984
1034
  const outOfVis = this.focusedCellOutOfVis();
@@ -1055,16 +1105,40 @@ export class DxGrid extends LitElement {
1055
1105
  : !!(this.rows[plane]?.[index]?.resizeable ?? this.rowDefault[plane as DxGridFrozenRowsPlane]?.resizeable);
1056
1106
  }
1057
1107
 
1108
+ private clampAxisSize(
1109
+ plane: 'grid' | DxGridFrozenPlane,
1110
+ axis: DxGridAxis,
1111
+ index: number | string,
1112
+ requestedSize: number,
1113
+ ): number {
1114
+ const minSize =
1115
+ axis === 'col'
1116
+ ? (this.columns[plane]?.[index]?.minSize ??
1117
+ this.columnDefault[plane as DxGridFrozenColsPlane]?.minSize ??
1118
+ sizeColMin)
1119
+ : (this.rows[plane]?.[index]?.minSize ??
1120
+ this.rowDefault[plane as DxGridFrozenRowsPlane]?.minSize ??
1121
+ sizeRowMin);
1122
+ const maxSize =
1123
+ axis === 'col'
1124
+ ? (this.columns[plane]?.[index]?.maxSize ??
1125
+ this.columnDefault[plane as DxGridFrozenColsPlane]?.maxSize ??
1126
+ sizeColMax)
1127
+ : (this.rows[plane]?.[index]?.maxSize ??
1128
+ this.rowDefault[plane as DxGridFrozenRowsPlane]?.maxSize ??
1129
+ sizeRowMax);
1130
+ return Math.max(minSize, Math.min(maxSize, requestedSize));
1131
+ }
1132
+
1058
1133
  private handleAxisResizeInternal(event: DxAxisResizeInternal): void {
1059
1134
  event.stopPropagation();
1060
1135
  const { plane, axis, delta, size, index, state } = event;
1136
+ const nextSize = this.clampAxisSize(plane, axis, index, size + delta);
1061
1137
  if (axis === 'col') {
1062
- const nextSize = Math.max(sizeColMin, Math.min(sizeColMax, size + delta));
1063
1138
  this.colSizes = { ...this.colSizes, [plane]: { ...this.colSizes[plane], [index]: nextSize } };
1064
1139
  this.updateVisInline();
1065
1140
  this.updateIntrinsicInlineSize();
1066
1141
  } else {
1067
- const nextSize = Math.max(sizeRowMin, Math.min(sizeRowMax, size + delta));
1068
1142
  this.rowSizes = { ...this.colSizes, [plane]: { ...this.rowSizes[plane], [index]: nextSize } };
1069
1143
  this.updateVisBlock();
1070
1144
  this.updateIntrinsicBlockSize();
@@ -1082,7 +1156,7 @@ export class DxGrid extends LitElement {
1082
1156
  }
1083
1157
 
1084
1158
  //
1085
- // Render and other lifecycle methods
1159
+ // Render and other lifecycle methods.
1086
1160
  //
1087
1161
 
1088
1162
  // TODO(thure): This is for rendering presentational objects superimposed onto the canonical grid (e.g. DnD drop line for #8108).
@@ -1165,7 +1239,7 @@ export class DxGrid extends LitElement {
1165
1239
  ) {
1166
1240
  const rowPlane = resolveRowPlane(plane) as DxGridFrozenPlane;
1167
1241
  const rows = this.frozen[rowPlane];
1168
- return (rows ?? 0) > 0
1242
+ return (rows ?? 0) > 0 && this.limitColumns > 0
1169
1243
  ? html`<div
1170
1244
  role="none"
1171
1245
  class="dx-grid__plane--frozen-row"
@@ -1199,7 +1273,7 @@ export class DxGrid extends LitElement {
1199
1273
  ) {
1200
1274
  const colPlane = resolveColPlane(plane) as DxGridFrozenPlane;
1201
1275
  const cols = this.frozen[colPlane];
1202
- return (cols ?? 0) > 0
1276
+ return (cols ?? 0) > 0 && this.limitRows > 0
1203
1277
  ? html`<div
1204
1278
  role="none"
1205
1279
  class="dx-grid__plane--frozen-col"
@@ -1225,6 +1299,40 @@ export class DxGrid extends LitElement {
1225
1299
  : null;
1226
1300
  }
1227
1301
 
1302
+ private renderMainGrid(
1303
+ visibleCols: number,
1304
+ visibleRows: number,
1305
+ offsetInline: number,
1306
+ offsetBlock: number,
1307
+ selection: DxGridSelectionProps,
1308
+ ) {
1309
+ return this.limitRows > 0 && this.limitColumns > 0
1310
+ ? html`<div
1311
+ role="grid"
1312
+ class="dx-grid__plane--grid"
1313
+ tabindex="0"
1314
+ data-dx-grid-plane="grid"
1315
+ data-dx-grid-plane-row="1"
1316
+ data-dx-grid-plane-col="1"
1317
+ >
1318
+ <div
1319
+ role="none"
1320
+ class="dx-grid__plane--grid__content"
1321
+ style="transform:translate3d(${offsetInline}px,${offsetBlock}px,0);grid-template-columns:${this
1322
+ .templateGridColumns};grid-template-rows:${this.templateGridRows};"
1323
+ >
1324
+ ${[...Array(visibleRows)].map((_, r0) => {
1325
+ return [...Array(visibleCols)].map((_, c0) => {
1326
+ const c = c0 + this.visColMin;
1327
+ const r = r0 + this.visRowMin;
1328
+ return this.renderCell(c, r, 'grid', cellSelected(c, r, 'grid', selection), c0, r0);
1329
+ });
1330
+ })}
1331
+ </div>
1332
+ </div>`
1333
+ : null;
1334
+ }
1335
+
1228
1336
  private cellReadonly(col: number, row: number, plane: DxGridPlane): boolean {
1229
1337
  const colPlane = resolveColPlane(plane);
1230
1338
  const rowPlane = resolveRowPlane(plane);
@@ -1242,6 +1350,23 @@ export class DxGrid extends LitElement {
1242
1350
  return isReadonly(colReadOnly) || isReadonly(rowReadOnly);
1243
1351
  }
1244
1352
 
1353
+ private cellFocusUnfurl(col: number, row: number, plane: DxGridPlane): boolean {
1354
+ const colPlane = resolveColPlane(plane);
1355
+ const rowPlane = resolveRowPlane(plane);
1356
+
1357
+ // Check cell-specific setting first.
1358
+ const cellUnfurl = this.cell(col, row, plane)?.focusUnfurl;
1359
+ if (cellUnfurl !== undefined) {
1360
+ return cellUnfurl;
1361
+ }
1362
+
1363
+ // Check column/row defaults.
1364
+ const colUnfurl = this.columns?.[colPlane]?.[col]?.focusUnfurl ?? this.columnDefault?.[colPlane]?.focusUnfurl;
1365
+ const rowUnfurl = this.rows?.[rowPlane]?.[row]?.focusUnfurl ?? this.rowDefault?.[rowPlane]?.focusUnfurl;
1366
+
1367
+ return colUnfurl ?? rowUnfurl ?? focusUnfurlDefault;
1368
+ }
1369
+
1245
1370
  /**
1246
1371
  * Determines if the cell's text content should be selectable based on its readonly value.
1247
1372
  * @returns true if the cells text content is selectable, false otherwise.
@@ -1262,10 +1387,49 @@ export class DxGrid extends LitElement {
1262
1387
  return colReadonly === 'text-select' || rowReadonly === 'text-select';
1263
1388
  }
1264
1389
 
1390
+ private getOverflowingCellModifiedDeltas(
1391
+ event: DxGridAnnotatedPanEvent,
1392
+ ): Pick<DxGridAnnotatedPanEvent, 'deltaX' | 'deltaY'> {
1393
+ if (!event.target) {
1394
+ return event;
1395
+ }
1396
+ const element = event.target as HTMLElement;
1397
+ const activeCell = element.closest('[data-dx-active]');
1398
+ const contentEl = element.closest('.dx-grid__cell__content');
1399
+
1400
+ if (!activeCell || !contentEl || !document.activeElement?.contains(element)) {
1401
+ return event;
1402
+ }
1403
+
1404
+ // Commented-out code will let the event delta through unmodified if the cell can scroll but is scrolled to the end
1405
+ // in the same direction as the wheel event, a.k.a. “overscroll”; this is probably undesirable, though.
1406
+
1407
+ const { scrollWidth, clientWidth, scrollHeight, clientHeight /*, scrollLeft, scrollTop */ } = contentEl;
1408
+
1409
+ if (scrollWidth <= clientWidth && scrollHeight <= clientHeight) {
1410
+ return event;
1411
+ }
1412
+
1413
+ const deltaX =
1414
+ scrollWidth > clientWidth /* &&
1415
+ ((event.deltaX < 0 && scrollLeft > 0) || (event.deltaX > 0 && scrollLeft < scrollWidth - clientWidth)) */
1416
+ ? 0
1417
+ : event.deltaX;
1418
+
1419
+ const deltaY =
1420
+ scrollHeight > clientHeight /* &&
1421
+ ((event.deltaY < 0 && scrollTop > 0) || (event.deltaY > 0 && scrollTop < scrollHeight - clientHeight)) */
1422
+ ? 0
1423
+ : event.deltaY;
1424
+
1425
+ return { deltaX, deltaY };
1426
+ }
1427
+
1265
1428
  private renderCell(col: number, row: number, plane: DxGridPlane, selected?: boolean, visCol = col, visRow = row) {
1266
1429
  const cell = this.cell(col, row, plane);
1267
1430
  const active = this.cellActive(col, row, plane);
1268
1431
  const readonly = this.cellReadonly(col, row, plane);
1432
+ const focusUnfurl = this.cellFocusUnfurl(col, row, plane);
1269
1433
  const textSelectable = this.cellTextSelectable(col, row, plane);
1270
1434
  const resizeIndex = cell?.resizeHandle ? (cell.resizeHandle === 'col' ? col : row) : undefined;
1271
1435
  const resizePlane = cell?.resizeHandle ? resolveFrozenPlane(cell.resizeHandle, plane) : undefined;
@@ -1277,16 +1441,17 @@ export class DxGrid extends LitElement {
1277
1441
  aria-readonly=${readonly ? 'true' : nothing}
1278
1442
  class=${cell?.className ?? nothing}
1279
1443
  data-refs=${cell?.dataRefs ?? nothing}
1444
+ data-focus-unfurl=${focusUnfurl ? nothing : 'false'}
1280
1445
  ?data-dx-active=${active}
1281
1446
  data-text-selectable=${textSelectable ? 'true' : 'false'}
1282
1447
  data-dx-grid-action="cell"
1283
1448
  aria-colindex=${col}
1284
1449
  aria-rowindex=${row}
1450
+ data-testid=${`${plane}.${col}.${row}`}
1285
1451
  style="grid-column:${visCol + 1};grid-row:${visRow + 1}"
1286
1452
  >
1287
- ${this.mode !== 'browse' && active ? null : cell?.value}${this.mode !== 'browse' && active
1288
- ? null
1289
- : accessory}${cell?.resizeHandle &&
1453
+ <div role="none" class="dx-grid__cell__content">${cell?.value}${accessory}</div>
1454
+ ${cell?.resizeHandle &&
1290
1455
  this.mode === 'browse' &&
1291
1456
  this.axisResizeable(resizePlane!, cell.resizeHandle, resizeIndex!)
1292
1457
  ? html`<dx-grid-axis-resize-handle
@@ -1320,13 +1485,24 @@ export class DxGrid extends LitElement {
1320
1485
  <div
1321
1486
  role="none"
1322
1487
  class="dx-grid"
1488
+ data-arrow-keys="all"
1323
1489
  style=${styleMap({
1324
- 'grid-template-columns': `${this.templatefrozenColsStart ? 'min-content ' : ''}minmax(0, ${
1325
- Number.isFinite(this.limitColumns) ? `${Math.max(0, this.intrinsicInlineSize)}px` : '1fr'
1326
- })${this.templatefrozenColsEnd ? ' min-content' : ''}`,
1327
- 'grid-template-rows': `${this.templatefrozenRowsStart ? 'min-content ' : ''}minmax(0, ${
1328
- Number.isFinite(this.limitRows) ? `${Math.max(0, this.intrinsicBlockSize)}px` : '1fr'
1329
- })${this.templatefrozenRowsEnd ? ' min-content' : ''}`,
1490
+ 'grid-template-columns': [
1491
+ this.templatefrozenColsStart ? 'min-content' : false,
1492
+ this.limitColumns > 0 &&
1493
+ `minmax(0, ${Number.isFinite(this.limitColumns) ? `${Math.max(0, this.intrinsicInlineSize)}px` : '1fr'})`,
1494
+ this.templatefrozenColsEnd ? 'min-content' : false,
1495
+ ]
1496
+ .filter(Boolean)
1497
+ .join(' '),
1498
+ 'grid-template-rows': [
1499
+ this.templatefrozenRowsStart ? 'min-content' : false,
1500
+ this.limitRows > 0 &&
1501
+ `minmax(0, ${Number.isFinite(this.limitRows) ? `${Math.max(0, this.intrinsicBlockSize)}px` : '1fr'})`,
1502
+ this.templatefrozenRowsEnd ? ' min-content' : false,
1503
+ ]
1504
+ .filter(Boolean)
1505
+ .join(' '),
1330
1506
  '--dx-grid-content-inline-size': Number.isFinite(this.limitColumns)
1331
1507
  ? `${Math.max(0, this.totalIntrinsicInlineSize)}px`
1332
1508
  : 'max-content',
@@ -1336,6 +1512,7 @@ export class DxGrid extends LitElement {
1336
1512
  })}
1337
1513
  data-grid=${this.gridId}
1338
1514
  data-grid-mode=${this.mode}
1515
+ data-grid-focus-indicator-variant=${this.focusIndicatorVariant}
1339
1516
  ?data-grid-select=${selection.visible}
1340
1517
  ${ref(this.gridRef)}
1341
1518
  >
@@ -1350,30 +1527,7 @@ export class DxGrid extends LitElement {
1350
1527
  offsetBlock,
1351
1528
  selection,
1352
1529
  )}
1353
- <div
1354
- role="grid"
1355
- class="dx-grid__plane--grid"
1356
- tabindex="0"
1357
- data-dx-grid-plane="grid"
1358
- data-dx-grid-plane-row="1"
1359
- data-dx-grid-plane-col="1"
1360
- ${ref(this.viewportRef)}
1361
- >
1362
- <div
1363
- role="none"
1364
- class="dx-grid__plane--grid__content"
1365
- style="transform:translate3d(${offsetInline}px,${offsetBlock}px,0);grid-template-columns:${this
1366
- .templateGridColumns};grid-template-rows:${this.templateGridRows};"
1367
- >
1368
- ${[...Array(visibleRows)].map((_, r0) => {
1369
- return [...Array(visibleCols)].map((_, c0) => {
1370
- const c = c0 + this.visColMin;
1371
- const r = r0 + this.visRowMin;
1372
- return this.renderCell(c, r, 'grid', cellSelected(c, r, 'grid', selection), c0, r0);
1373
- });
1374
- })}
1375
- </div>
1376
- </div>
1530
+ ${this.renderMainGrid(visibleCols, visibleRows, offsetInline, offsetBlock, selection)}
1377
1531
  ${this.renderFrozenColumns('frozenColsEnd', visibleRows, offsetBlock, selection)}${this.renderFixed(
1378
1532
  'fixedEndStart',
1379
1533
  selection,
@@ -1387,37 +1541,19 @@ export class DxGrid extends LitElement {
1387
1541
  private updateIntrinsicInlineSize(): void {
1388
1542
  this.intrinsicInlineSize = Number.isFinite(this.limitColumns)
1389
1543
  ? [...Array(this.limitColumns)].reduce((acc, _, c0) => acc + this.colSize(c0, 'grid'), 0) +
1390
- gap * (this.limitColumns - 1)
1544
+ gap * Math.max(0, this.limitColumns - 1)
1391
1545
  : Infinity;
1392
1546
  this.totalIntrinsicInlineSize =
1393
- this.intrinsicInlineSize +
1394
- (Number.isFinite(this.frozen.frozenColsStart)
1395
- ? [...Array(this.frozen.frozenColsStart)].reduce(
1396
- (acc, _, c0) => acc + gap + this.colSize(c0, 'frozenColsStart'),
1397
- 0,
1398
- )
1399
- : 0) +
1400
- (Number.isFinite(this.frozen.frozenColsEnd)
1401
- ? [...Array(this.frozen.frozenColsEnd)].reduce((acc, _, c0) => acc + gap + this.colSize(c0, 'frozenColsEnd'), 0)
1402
- : 0);
1547
+ this.limitColumns > 0 ? this.intrinsicInlineSize + this.frozenColsSize : this.frozenColsSize - gap;
1403
1548
  }
1404
1549
 
1405
1550
  private updateIntrinsicBlockSize(): void {
1406
1551
  this.intrinsicBlockSize = Number.isFinite(this.limitRows)
1407
1552
  ? [...Array(this.limitRows)].reduce((acc, _, r0) => acc + this.rowSize(r0, 'grid'), 0) +
1408
- gap * (this.limitRows - 1)
1553
+ gap * Math.max(0, this.limitRows - 1)
1409
1554
  : Infinity;
1410
1555
  this.totalIntrinsicBlockSize =
1411
- this.intrinsicBlockSize +
1412
- (Number.isFinite(this.frozen.frozenRowsStart)
1413
- ? [...Array(this.frozen.frozenRowsStart)].reduce(
1414
- (acc, _, r0) => acc + gap + this.rowSize(r0, 'frozenRowsStart'),
1415
- 0,
1416
- )
1417
- : 0) +
1418
- (Number.isFinite(this.frozen.frozenRowsEnd)
1419
- ? [...Array(this.frozen.frozenRowsEnd)].reduce((acc, _, r0) => acc + gap + this.rowSize(r0, 'frozenRowsEnd'), 0)
1420
- : 0);
1556
+ this.limitRows > 0 ? this.intrinsicBlockSize + this.frozenRowsSize : this.frozenRowsSize - gap;
1421
1557
  }
1422
1558
 
1423
1559
  private updateIntrinsicSizes(): void {
@@ -1465,7 +1601,7 @@ export class DxGrid extends LitElement {
1465
1601
  if (this.getCells) {
1466
1602
  this.updateCells(true);
1467
1603
  }
1468
- this.observer.observe(this.viewportRef.value!);
1604
+ this.observer.observe(this.gridRef.value!);
1469
1605
  this.computeColSizes();
1470
1606
  this.computeRowSizes();
1471
1607
  this.updateIntrinsicSizes();
@@ -1490,6 +1626,13 @@ export class DxGrid extends LitElement {
1490
1626
  this.updateVisInline();
1491
1627
  }
1492
1628
 
1629
+ if (changedProperties.has('frozen')) {
1630
+ this.updateIntrinsicBlockSize();
1631
+ this.updateIntrinsicInlineSize();
1632
+ this.updateVisBlock();
1633
+ this.updateVisInline();
1634
+ }
1635
+
1493
1636
  if (
1494
1637
  this.getCells &&
1495
1638
  (changedProperties.has('initialCells') ||
@@ -1500,7 +1643,8 @@ export class DxGrid extends LitElement {
1500
1643
  changedProperties.has('columns') ||
1501
1644
  changedProperties.has('rows') ||
1502
1645
  changedProperties.has('limitColumns') ||
1503
- changedProperties.has('limitRows'))
1646
+ changedProperties.has('limitRows') ||
1647
+ changedProperties.has('frozen'))
1504
1648
  ) {
1505
1649
  this.updateCells(true);
1506
1650
  }
@@ -1520,8 +1664,9 @@ export class DxGrid extends LitElement {
1520
1664
  }
1521
1665
  }
1522
1666
 
1523
- public updateIfWithinBounds({ col, row }: { col: number; row: number }): boolean {
1667
+ public updateIfWithinBounds({ col, row }: { col: number; row: number }, includeFixed?: boolean): boolean {
1524
1668
  if (col >= this.visColMin && col <= this.visColMax && row >= this.visRowMin && row <= this.visRowMax) {
1669
+ this.updateCells(includeFixed);
1525
1670
  this.requestUpdate();
1526
1671
  return true;
1527
1672
  }
@@ -1530,8 +1675,8 @@ export class DxGrid extends LitElement {
1530
1675
 
1531
1676
  override disconnectedCallback(): void {
1532
1677
  super.disconnectedCallback();
1533
- if (this.viewportRef.value) {
1534
- this.observer.unobserve(this.viewportRef.value);
1678
+ if (this.gridRef.value) {
1679
+ this.observer.unobserve(this.gridRef.value);
1535
1680
  }
1536
1681
  document.defaultView?.removeEventListener('wheel', this.handleTopLevelWheel);
1537
1682
  }
@@ -1549,6 +1694,7 @@ export {
1549
1694
  parseCellIndex,
1550
1695
  toPlaneCellIndex,
1551
1696
  cellQuery,
1697
+ accessoryHandlesPointerdownAttrs,
1552
1698
  } from './util';
1553
1699
 
1554
1700
  export const commentedClassName = 'dx-grid__cell--commented';