@dxos/lit-grid 0.14.0 → 0.15.0
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.
- package/dist/src/dx-grid.d.ts.map +1 -1
- package/dist/src/dx-grid.js +9 -6
- package/dist/src/dx-grid.js.map +1 -1
- package/dist/src/util.d.ts +5 -0
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +16 -0
- package/dist/src/util.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/dx-grid.pcss +74 -7
- package/src/dx-grid.ts +16 -5
- package/src/util.ts +23 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/lit-grid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "A grid Web Component using Lit",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"lit": "^3.3.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@dxos/random": "0.
|
|
43
|
-
"@dxos/test-utils": "0.
|
|
42
|
+
"@dxos/random": "0.15.0",
|
|
43
|
+
"@dxos/test-utils": "0.15.0"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
package/src/dx-grid.pcss
CHANGED
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
position: absolute;
|
|
62
62
|
inset: 0;
|
|
63
63
|
pointer-events: none;
|
|
64
|
-
border: var(--dx-grid-focus-indicator-width) solid var(--color-focus-ring);
|
|
64
|
+
border: var(--dx-grid-focus-indicator-width) solid var(--color-grid-focus-ring);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -158,9 +158,47 @@
|
|
|
158
158
|
[role='columnheader'],
|
|
159
159
|
[role='rowheader'] {
|
|
160
160
|
&[aria-selected] {
|
|
161
|
-
|
|
161
|
+
/* The selection tint is translucent, so it is layered over the grid surface rather than the host behind it. */
|
|
162
|
+
--grid-cell-surface:
|
|
163
|
+
linear-gradient(var(--color-grid-selection-surface), var(--color-grid-selection-surface)),
|
|
164
|
+
var(--color-grid-surface);
|
|
162
165
|
--grid-cell-fg: var(--color-grid-selection-fg);
|
|
163
166
|
|
|
167
|
+
/*
|
|
168
|
+
* Outline the selected range: each edge cell draws its outer sides. Like the focus ring it reaches
|
|
169
|
+
* back over the neighbours' right/bottom lines, so the outline sits on grid lines on all four sides.
|
|
170
|
+
*/
|
|
171
|
+
&[data-selection-edge]::before {
|
|
172
|
+
content: '';
|
|
173
|
+
position: absolute;
|
|
174
|
+
inset-inline-start: calc(-1 * var(--dx-grid-focus-indicator-width));
|
|
175
|
+
inset-block-start: calc(-1 * var(--dx-grid-focus-indicator-width));
|
|
176
|
+
inset-inline-end: 0;
|
|
177
|
+
inset-block-end: 0;
|
|
178
|
+
z-index: 1;
|
|
179
|
+
pointer-events: none;
|
|
180
|
+
border: 0 solid var(--color-grid-focus-ring);
|
|
181
|
+
}
|
|
182
|
+
&[data-selection-edge~='top']::before {
|
|
183
|
+
border-block-start-width: var(--dx-grid-focus-indicator-width);
|
|
184
|
+
}
|
|
185
|
+
&[data-selection-edge~='bottom']::before {
|
|
186
|
+
border-block-end-width: var(--dx-grid-focus-indicator-width);
|
|
187
|
+
}
|
|
188
|
+
&[data-selection-edge~='start']::before {
|
|
189
|
+
border-inline-start-width: var(--dx-grid-focus-indicator-width);
|
|
190
|
+
}
|
|
191
|
+
&[data-selection-edge~='end']::before {
|
|
192
|
+
border-inline-end-width: var(--dx-grid-focus-indicator-width);
|
|
193
|
+
}
|
|
194
|
+
/* The plane clips at its first column and row, where there is no neighbour line to reach over. */
|
|
195
|
+
&[aria-colindex='0']::before {
|
|
196
|
+
inset-inline-start: 0;
|
|
197
|
+
}
|
|
198
|
+
&[aria-rowindex='0']::before {
|
|
199
|
+
inset-block-start: 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
164
202
|
&:focus:not([aria-readonly='true']),
|
|
165
203
|
&:focus-visible,
|
|
166
204
|
&:focus-within {
|
|
@@ -203,10 +241,23 @@
|
|
|
203
241
|
* border) exceeds the cell track size by even a fraction of a
|
|
204
242
|
* pixel, pushing the focus ring's bottom edge below the grid line.
|
|
205
243
|
*/
|
|
206
|
-
min-inline-size: 100
|
|
244
|
+
min-inline-size: calc(100% + var(--dx-grid-focus-indicator-width));
|
|
207
245
|
inline-size: min-content;
|
|
208
246
|
max-inline-size: min(60ch, 90vw);
|
|
209
247
|
|
|
248
|
+
/*
|
|
249
|
+
* A cell draws only its right/bottom lines; its left/top lines belong to its neighbours.
|
|
250
|
+
* Reaching back over them puts all four ring edges on grid lines; the extra start padding
|
|
251
|
+
* keeps the text where it sits unfocused.
|
|
252
|
+
*/
|
|
253
|
+
inset-inline-start: calc(-1 * var(--dx-grid-focus-indicator-width));
|
|
254
|
+
inset-block-start: calc(-1 * var(--dx-grid-focus-indicator-width));
|
|
255
|
+
block-size: calc(100% + var(--dx-grid-focus-indicator-width));
|
|
256
|
+
padding-inline-start: calc(
|
|
257
|
+
var(--dx-grid-cell-content-padding-inline) + var(--dx-grid-focus-indicator-width)
|
|
258
|
+
);
|
|
259
|
+
padding-block-start: calc(var(--dx-grid-cell-content-padding-block) + var(--dx-grid-focus-indicator-width));
|
|
260
|
+
|
|
210
261
|
overflow: auto;
|
|
211
262
|
scrollbar-width: thin;
|
|
212
263
|
overscroll-behavior: contain;
|
|
@@ -217,14 +268,27 @@
|
|
|
217
268
|
color: var(--grid-cell-fg);
|
|
218
269
|
}
|
|
219
270
|
|
|
271
|
+
/* The plane clips at its first column and row, where there is no neighbour line to reach over. */
|
|
272
|
+
&[aria-colindex='0'] > .dx-grid__cell__content {
|
|
273
|
+
inset-inline-start: 0;
|
|
274
|
+
min-inline-size: 100%;
|
|
275
|
+
padding-inline-start: var(--dx-grid-cell-content-padding-inline);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
&[aria-rowindex='0'] > .dx-grid__cell__content {
|
|
279
|
+
inset-block-start: 0;
|
|
280
|
+
block-size: 100%;
|
|
281
|
+
padding-block-start: var(--dx-grid-cell-content-padding-block);
|
|
282
|
+
}
|
|
283
|
+
|
|
220
284
|
&:not([aria-readonly='true']) > .dx-grid__cell__content {
|
|
221
|
-
border-color: var(--color-focus-ring);
|
|
285
|
+
border-color: var(--color-grid-focus-ring);
|
|
222
286
|
}
|
|
223
287
|
}
|
|
224
288
|
}
|
|
225
289
|
|
|
226
290
|
&:focus-visible > .dx-grid__cell__content {
|
|
227
|
-
border-color: var(--color-focus-ring);
|
|
291
|
+
border-color: var(--color-grid-focus-ring);
|
|
228
292
|
}
|
|
229
293
|
}
|
|
230
294
|
}
|
|
@@ -236,8 +300,11 @@
|
|
|
236
300
|
overflow-wrap: break-word;
|
|
237
301
|
|
|
238
302
|
background: var(--dx-grid-base, var(--color-base-surface));
|
|
239
|
-
border: var(--dx-grid-focus-indicator-width) solid var(--color-focus-ring);
|
|
303
|
+
border: var(--dx-grid-focus-indicator-width) solid var(--color-grid-focus-ring);
|
|
240
304
|
border-radius: 2px;
|
|
305
|
+
/* Matches the focused cell: the box reaches over the neighbours' lines, the text stays put. */
|
|
306
|
+
padding-inline-start: var(--dx-grid-focus-indicator-width);
|
|
307
|
+
padding-block-start: var(--dx-grid-focus-indicator-width);
|
|
241
308
|
|
|
242
309
|
--dx-grid-cell-editor-max-block-size: min(12em, 50vh);
|
|
243
310
|
--dx-grid-cell-editor-max-inline-size: min(60ch, 90vw);
|
|
@@ -262,7 +329,7 @@
|
|
|
262
329
|
[role='columnheader'],
|
|
263
330
|
[role='rowheader'] {
|
|
264
331
|
&[data-dx-active]:not([aria-readonly='true']) > .dx-grid__cell__content {
|
|
265
|
-
border-color: var(--color-focus-ring);
|
|
332
|
+
border-color: var(--color-grid-focus-ring);
|
|
266
333
|
}
|
|
267
334
|
}
|
|
268
335
|
}
|
package/src/dx-grid.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
} from './types.ts';
|
|
45
45
|
import {
|
|
46
46
|
cellSelected,
|
|
47
|
+
cellSelectionEdges,
|
|
47
48
|
closestAction,
|
|
48
49
|
closestCell,
|
|
49
50
|
gap,
|
|
@@ -1225,7 +1226,7 @@ export class DxGrid extends LitElement {
|
|
|
1225
1226
|
>
|
|
1226
1227
|
${[...Array(rows)].map((_, r) => {
|
|
1227
1228
|
return [...Array(cols)].map((_, c) => {
|
|
1228
|
-
return this.renderCell(c, r, plane,
|
|
1229
|
+
return this.renderCell(c, r, plane, selection);
|
|
1229
1230
|
});
|
|
1230
1231
|
})}
|
|
1231
1232
|
</div>`
|
|
@@ -1259,7 +1260,7 @@ export class DxGrid extends LitElement {
|
|
|
1259
1260
|
${[...Array(rows)].map((_, r) => {
|
|
1260
1261
|
return [...Array(visibleCols)].map((_, c0) => {
|
|
1261
1262
|
const c = this.visColMin + c0;
|
|
1262
|
-
return this.renderCell(c, r, plane,
|
|
1263
|
+
return this.renderCell(c, r, plane, selection, c0, r);
|
|
1263
1264
|
});
|
|
1264
1265
|
})}
|
|
1265
1266
|
</div>
|
|
@@ -1294,7 +1295,7 @@ export class DxGrid extends LitElement {
|
|
|
1294
1295
|
${[...Array(visibleRows)].map((_, r0) => {
|
|
1295
1296
|
return [...Array(cols)].map((_, c) => {
|
|
1296
1297
|
const r = this.visRowMin + r0;
|
|
1297
|
-
return this.renderCell(c, r, plane,
|
|
1298
|
+
return this.renderCell(c, r, plane, selection, c, r0);
|
|
1298
1299
|
});
|
|
1299
1300
|
})}
|
|
1300
1301
|
</div>
|
|
@@ -1329,7 +1330,7 @@ export class DxGrid extends LitElement {
|
|
|
1329
1330
|
return [...Array(visibleCols)].map((_, c0) => {
|
|
1330
1331
|
const c = c0 + this.visColMin;
|
|
1331
1332
|
const r = r0 + this.visRowMin;
|
|
1332
|
-
return this.renderCell(c, r, 'grid',
|
|
1333
|
+
return this.renderCell(c, r, 'grid', selection, c0, r0);
|
|
1333
1334
|
});
|
|
1334
1335
|
})}
|
|
1335
1336
|
</div>
|
|
@@ -1429,7 +1430,16 @@ export class DxGrid extends LitElement {
|
|
|
1429
1430
|
return { deltaX, deltaY };
|
|
1430
1431
|
}
|
|
1431
1432
|
|
|
1432
|
-
private renderCell(
|
|
1433
|
+
private renderCell(
|
|
1434
|
+
col: number,
|
|
1435
|
+
row: number,
|
|
1436
|
+
plane: DxGridPlane,
|
|
1437
|
+
selection?: DxGridSelectionProps,
|
|
1438
|
+
visCol = col,
|
|
1439
|
+
visRow = row,
|
|
1440
|
+
) {
|
|
1441
|
+
const selected = selection ? cellSelected(col, row, plane, selection) : false;
|
|
1442
|
+
const selectionEdge = selection ? cellSelectionEdges(col, row, plane, selection) : undefined;
|
|
1433
1443
|
const cell = this.cell(col, row, plane);
|
|
1434
1444
|
const active = this.cellActive(col, row, plane);
|
|
1435
1445
|
const readonly = this.cellReadonly(col, row, plane);
|
|
@@ -1442,6 +1452,7 @@ export class DxGrid extends LitElement {
|
|
|
1442
1452
|
role="gridcell"
|
|
1443
1453
|
tabindex="0"
|
|
1444
1454
|
aria-selected=${selected ? 'true' : nothing}
|
|
1455
|
+
data-selection-edge=${selectionEdge ?? nothing}
|
|
1445
1456
|
aria-readonly=${readonly ? 'true' : nothing}
|
|
1446
1457
|
class=${cell?.className ?? nothing}
|
|
1447
1458
|
data-refs=${cell?.dataRefs ?? nothing}
|
package/src/util.ts
CHANGED
|
@@ -120,6 +120,29 @@ export const cellSelected = (
|
|
|
120
120
|
);
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
+
/**
|
|
124
|
+
* The sides of a multi-cell selection that `col`/`row` sits on (`top`, `bottom`, `start`, `end`), space-separated
|
|
125
|
+
* for an attribute's `~=` selector; undefined for cells inside it, outside it, or a single-cell selection.
|
|
126
|
+
*/
|
|
127
|
+
export const cellSelectionEdges = (
|
|
128
|
+
col: number,
|
|
129
|
+
row: number,
|
|
130
|
+
plane: DxGridPlane,
|
|
131
|
+
selection: DxGridSelectionProps,
|
|
132
|
+
): string | undefined => {
|
|
133
|
+
if (!selection.visible || !cellSelected(col, row, plane, selection)) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const edges = [
|
|
138
|
+
row === selection.rowMin && 'top',
|
|
139
|
+
row === selection.rowMax && 'bottom',
|
|
140
|
+
col === selection.colMin && 'start',
|
|
141
|
+
col === selection.colMax && 'end',
|
|
142
|
+
].filter((edge) => edge !== false);
|
|
143
|
+
return edges.length > 0 ? edges.join(' ') : undefined;
|
|
144
|
+
};
|
|
145
|
+
|
|
123
146
|
export const closestAction = (target: EventTarget | null): { action: string | null; actionEl: HTMLElement | null } => {
|
|
124
147
|
const actionEl: HTMLElement | null = (target as HTMLElement | null)?.closest('[data-dx-grid-action]') ?? null;
|
|
125
148
|
return { actionEl, action: actionEl?.getAttribute('data-dx-grid-action') ?? null };
|