argus-table 0.0.1 → 0.2.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.
Files changed (59) hide show
  1. package/README.md +25 -2
  2. package/dist/announce.js +27 -0
  3. package/dist/announce.js.map +1 -0
  4. package/dist/argus-column.js +121 -0
  5. package/dist/argus-column.js.map +1 -0
  6. package/dist/argus-table.js +618 -91
  7. package/dist/argus-table.js.map +1 -1
  8. package/dist/cdn/argus-table.js +87 -4715
  9. package/dist/cdn/argus-table.js.map +1 -1
  10. package/dist/controllers/auto-width.js +89 -0
  11. package/dist/controllers/auto-width.js.map +1 -0
  12. package/dist/controllers/column-children.js +41 -0
  13. package/dist/controllers/column-children.js.map +1 -0
  14. package/dist/controllers/data-controller.js +177 -0
  15. package/dist/controllers/data-controller.js.map +1 -0
  16. package/dist/controllers/pin-scroll-controller.js +78 -0
  17. package/dist/controllers/pin-scroll-controller.js.map +1 -0
  18. package/dist/controllers/reorder-drag.js +160 -0
  19. package/dist/controllers/reorder-drag.js.map +1 -0
  20. package/dist/controllers/resize-drag.js +3 -0
  21. package/dist/controllers/resize-drag.js.map +1 -1
  22. package/dist/controllers/table-controller.js +2 -1
  23. package/dist/controllers/table-controller.js.map +1 -1
  24. package/dist/controllers/virtual-controller.js +146 -9
  25. package/dist/controllers/virtual-controller.js.map +1 -1
  26. package/dist/core/src/columns/column-order.js +50 -0
  27. package/dist/core/src/columns/column-order.js.map +1 -0
  28. package/dist/core/src/columns/resolve-columns.js +5 -1
  29. package/dist/core/src/columns/resolve-columns.js.map +1 -1
  30. package/dist/core/src/data/page-cache.js +143 -0
  31. package/dist/core/src/data/page-cache.js.map +1 -0
  32. package/dist/core/src/grid/row-layout.js +58 -0
  33. package/dist/core/src/grid/row-layout.js.map +1 -0
  34. package/dist/core/src/table/create-table.js +112 -14
  35. package/dist/core/src/table/create-table.js.map +1 -1
  36. package/dist/core/src/table/sorted-row-model.js +86 -0
  37. package/dist/core/src/table/sorted-row-model.js.map +1 -0
  38. package/dist/core/src/virtual/scroll-scale.js +74 -0
  39. package/dist/core/src/virtual/scroll-scale.js.map +1 -0
  40. package/dist/custom-elements.json +1510 -49
  41. package/dist/events.js +5 -1
  42. package/dist/events.js.map +1 -1
  43. package/dist/index.d.ts +252 -27
  44. package/dist/index.js +3 -2
  45. package/dist/max-height.js +68 -0
  46. package/dist/max-height.js.map +1 -0
  47. package/dist/render/body.js +53 -21
  48. package/dist/render/body.js.map +1 -1
  49. package/dist/render/cells.js +21 -4
  50. package/dist/render/cells.js.map +1 -1
  51. package/dist/render/content.js +12 -5
  52. package/dist/render/content.js.map +1 -1
  53. package/dist/render/header.js +21 -5
  54. package/dist/render/header.js.map +1 -1
  55. package/dist/render/pinned-rows.js +29 -0
  56. package/dist/render/pinned-rows.js.map +1 -0
  57. package/dist/styles/base.js +1 -225
  58. package/dist/styles/base.js.map +1 -1
  59. package/package.json +3 -1
@@ -2,13 +2,357 @@
2
2
  "schemaVersion": "1.0.0",
3
3
  "readme": "",
4
4
  "modules": [
5
+ {
6
+ "kind": "javascript-module",
7
+ "path": "src/announce.ts",
8
+ "declarations": [
9
+ {
10
+ "kind": "function",
11
+ "name": "announce",
12
+ "return": {
13
+ "type": {
14
+ "text": "void"
15
+ }
16
+ },
17
+ "parameters": [
18
+ {
19
+ "name": "doc",
20
+ "type": {
21
+ "text": "Document"
22
+ }
23
+ },
24
+ {
25
+ "name": "message",
26
+ "type": {
27
+ "text": "string"
28
+ }
29
+ }
30
+ ],
31
+ "description": "Says something to screen readers through a polite live region. The region\nlives in the document body, not in the table: a grid may only own rows, so a\nstatus element inside it would break the grid's structure. One region serves\nevery table on the page. It is visually hidden with inline styles, so page\nCSS can't reveal it."
32
+ }
33
+ ],
34
+ "exports": [
35
+ {
36
+ "kind": "js",
37
+ "name": "announce",
38
+ "declaration": {
39
+ "name": "announce",
40
+ "module": "src/announce.ts"
41
+ }
42
+ }
43
+ ]
44
+ },
45
+ {
46
+ "kind": "javascript-module",
47
+ "path": "src/argus-column.ts",
48
+ "declarations": [
49
+ {
50
+ "kind": "function",
51
+ "name": "watchColumns",
52
+ "return": {
53
+ "type": {
54
+ "text": "void"
55
+ }
56
+ },
57
+ "parameters": [
58
+ {
59
+ "name": "host",
60
+ "type": {
61
+ "text": "Element"
62
+ }
63
+ },
64
+ {
65
+ "name": "onChange",
66
+ "type": {
67
+ "text": "() => void"
68
+ }
69
+ }
70
+ ],
71
+ "description": "Calls `onChange` whenever an `<argus-column>` child of `host` is added, removed, moved or changed."
72
+ },
73
+ {
74
+ "kind": "function",
75
+ "name": "unwatchColumns",
76
+ "return": {
77
+ "type": {
78
+ "text": "void"
79
+ }
80
+ },
81
+ "parameters": [
82
+ {
83
+ "name": "host",
84
+ "type": {
85
+ "text": "Element"
86
+ }
87
+ }
88
+ ]
89
+ },
90
+ {
91
+ "kind": "class",
92
+ "description": "One column of the parent `<argus-table>`, written as markup instead of an entry in\nits `columns` property. It is data only and renders nothing.\n\nOnly direct children of the table count, in document order. A non-empty `columns`\nproperty wins over the children. Adding, removing, moving or changing a column\nupdates the table; sizes, order and sorting are kept by `column-id`.\n\nA `<template>` child is the content of every cell in the column (static: the same\nfor each row). Set the `cell` property for content that depends on the row.",
93
+ "name": "ArgusColumn",
94
+ "members": [
95
+ {
96
+ "kind": "field",
97
+ "name": "columnId",
98
+ "type": {
99
+ "text": "string"
100
+ },
101
+ "default": "''",
102
+ "description": "Stable key, used in state objects, events and persistence. Must be unique within the table.",
103
+ "attribute": "column-id"
104
+ },
105
+ {
106
+ "kind": "field",
107
+ "name": "header",
108
+ "type": {
109
+ "text": "CellContent | (() => CellContent) | undefined"
110
+ },
111
+ "description": "Header content: text as an attribute; a Lit template, a node or a function as a property.",
112
+ "attribute": "header"
113
+ },
114
+ {
115
+ "kind": "field",
116
+ "name": "accessor",
117
+ "type": {
118
+ "text": "string | ((row: T, index: number) => unknown) | undefined"
119
+ },
120
+ "description": "How to read the cell value: a property path such as `customer.name`, or (as a\nproperty) a function of the row and its index.",
121
+ "attribute": "accessor"
122
+ },
123
+ {
124
+ "kind": "field",
125
+ "name": "cell",
126
+ "type": {
127
+ "text": "(row: T, context: CellContext<T>) => CellContent | undefined"
128
+ },
129
+ "description": "Cell content from the row: `(row, context) => content`. Property only; wins over a `<template>` child."
130
+ },
131
+ {
132
+ "kind": "field",
133
+ "name": "width",
134
+ "type": {
135
+ "text": "ColumnWidth | undefined"
136
+ },
137
+ "description": "Width: `90` (px), `auto` to fit the content, or `2fr` for a share of the free space. Default: 150 px.",
138
+ "attribute": "width"
139
+ },
140
+ {
141
+ "kind": "field",
142
+ "name": "minWidth",
143
+ "type": {
144
+ "text": "number | undefined"
145
+ },
146
+ "description": "Lower bound for resizing and for flex columns, in px. Default: 40.",
147
+ "attribute": "min-width"
148
+ },
149
+ {
150
+ "kind": "field",
151
+ "name": "maxWidth",
152
+ "type": {
153
+ "text": "number | undefined"
154
+ },
155
+ "description": "Upper bound for resizing, in px. Default: no limit.",
156
+ "attribute": "max-width"
157
+ },
158
+ {
159
+ "kind": "field",
160
+ "name": "pin",
161
+ "type": {
162
+ "text": "ColumnPin | undefined"
163
+ },
164
+ "description": "Pins the column to the `start` or `end` side.",
165
+ "attribute": "pin"
166
+ },
167
+ {
168
+ "kind": "field",
169
+ "name": "align",
170
+ "type": {
171
+ "text": "ColumnAlign | undefined"
172
+ },
173
+ "description": "Text alignment: `start`, `center` or `end`. Default: `start`.",
174
+ "attribute": "align"
175
+ },
176
+ {
177
+ "kind": "field",
178
+ "name": "sortable",
179
+ "type": {
180
+ "text": "boolean | undefined"
181
+ },
182
+ "description": "Whether the header can be clicked to sort. Default: `false`.",
183
+ "attribute": "sortable"
184
+ },
185
+ {
186
+ "kind": "field",
187
+ "name": "resizable",
188
+ "type": {
189
+ "text": "boolean | undefined"
190
+ },
191
+ "description": "Whether the column can be resized. Default: `true`; `resizable=\"false\"` turns it off.",
192
+ "attribute": "resizable"
193
+ },
194
+ {
195
+ "kind": "field",
196
+ "name": "reorderable",
197
+ "type": {
198
+ "text": "boolean | undefined"
199
+ },
200
+ "description": "Whether the column can be moved. Default: `true`; `reorderable=\"false\"` turns it off.",
201
+ "attribute": "reorderable"
202
+ },
203
+ {
204
+ "kind": "method",
205
+ "name": "toColumnDef",
206
+ "return": {
207
+ "type": {
208
+ "text": "ColumnDef<T>"
209
+ }
210
+ },
211
+ "description": "The column as the table reads it. Unset fields stay `undefined`, which the\ntable reads as its defaults. An unknown `pin` is ignored and an unknown\n`align` falls back to `start`."
212
+ }
213
+ ],
214
+ "attributes": [
215
+ {
216
+ "name": "column-id",
217
+ "type": {
218
+ "text": "string"
219
+ },
220
+ "default": "''",
221
+ "description": "Stable key, used in state objects, events and persistence. Must be unique within the table.",
222
+ "fieldName": "columnId"
223
+ },
224
+ {
225
+ "name": "header",
226
+ "type": {
227
+ "text": "CellContent | (() => CellContent) | undefined"
228
+ },
229
+ "description": "Header content: text as an attribute; a Lit template, a node or a function as a property.",
230
+ "fieldName": "header"
231
+ },
232
+ {
233
+ "name": "accessor",
234
+ "type": {
235
+ "text": "string | ((row: T, index: number) => unknown) | undefined"
236
+ },
237
+ "description": "How to read the cell value: a property path such as `customer.name`, or (as a\nproperty) a function of the row and its index.",
238
+ "fieldName": "accessor"
239
+ },
240
+ {
241
+ "name": "width",
242
+ "type": {
243
+ "text": "ColumnWidth | undefined"
244
+ },
245
+ "description": "Width: `90` (px), `auto` to fit the content, or `2fr` for a share of the free space. Default: 150 px.",
246
+ "fieldName": "width"
247
+ },
248
+ {
249
+ "name": "min-width",
250
+ "type": {
251
+ "text": "number | undefined"
252
+ },
253
+ "description": "Lower bound for resizing and for flex columns, in px. Default: 40.",
254
+ "fieldName": "minWidth"
255
+ },
256
+ {
257
+ "name": "max-width",
258
+ "type": {
259
+ "text": "number | undefined"
260
+ },
261
+ "description": "Upper bound for resizing, in px. Default: no limit.",
262
+ "fieldName": "maxWidth"
263
+ },
264
+ {
265
+ "name": "pin",
266
+ "type": {
267
+ "text": "ColumnPin | undefined"
268
+ },
269
+ "description": "Pins the column to the `start` or `end` side.",
270
+ "fieldName": "pin"
271
+ },
272
+ {
273
+ "name": "align",
274
+ "type": {
275
+ "text": "ColumnAlign | undefined"
276
+ },
277
+ "description": "Text alignment: `start`, `center` or `end`. Default: `start`.",
278
+ "fieldName": "align"
279
+ },
280
+ {
281
+ "name": "sortable",
282
+ "type": {
283
+ "text": "boolean | undefined"
284
+ },
285
+ "description": "Whether the header can be clicked to sort. Default: `false`.",
286
+ "fieldName": "sortable"
287
+ },
288
+ {
289
+ "name": "resizable",
290
+ "type": {
291
+ "text": "boolean | undefined"
292
+ },
293
+ "description": "Whether the column can be resized. Default: `true`; `resizable=\"false\"` turns it off.",
294
+ "fieldName": "resizable"
295
+ },
296
+ {
297
+ "name": "reorderable",
298
+ "type": {
299
+ "text": "boolean | undefined"
300
+ },
301
+ "description": "Whether the column can be moved. Default: `true`; `reorderable=\"false\"` turns it off.",
302
+ "fieldName": "reorderable"
303
+ }
304
+ ],
305
+ "superclass": {
306
+ "name": "ReactiveElement",
307
+ "package": "lit"
308
+ },
309
+ "summary": "Declarative column of an `<argus-table>`.",
310
+ "tagName": "argus-column",
311
+ "customElement": true
312
+ }
313
+ ],
314
+ "exports": [
315
+ {
316
+ "kind": "js",
317
+ "name": "watchColumns",
318
+ "declaration": {
319
+ "name": "watchColumns",
320
+ "module": "src/argus-column.ts"
321
+ }
322
+ },
323
+ {
324
+ "kind": "js",
325
+ "name": "unwatchColumns",
326
+ "declaration": {
327
+ "name": "unwatchColumns",
328
+ "module": "src/argus-column.ts"
329
+ }
330
+ },
331
+ {
332
+ "kind": "js",
333
+ "name": "ArgusColumn",
334
+ "declaration": {
335
+ "name": "ArgusColumn",
336
+ "module": "src/argus-column.ts"
337
+ }
338
+ },
339
+ {
340
+ "kind": "custom-element-definition",
341
+ "name": "argus-column",
342
+ "declaration": {
343
+ "name": "ArgusColumn",
344
+ "module": "src/argus-column.ts"
345
+ }
346
+ }
347
+ ]
348
+ },
5
349
  {
6
350
  "kind": "javascript-module",
7
351
  "path": "src/argus-table.ts",
8
352
  "declarations": [
9
353
  {
10
354
  "kind": "class",
11
- "description": "A virtualized data table.\n\nSet `columns` and `data` as properties. Header and cell content is rendered\ninto the element's light DOM and slotted into the cells, so page CSS and the\npage's own components work inside cells.",
355
+ "description": "A virtualized data table.\n\nSet `columns`, and `data` or `dataSource`, as properties. Columns can also be\nwritten as `<argus-column>` children; a non-empty `columns` wins over them.\nHeader and cell content is rendered into the element's light DOM and slotted\ninto the cells, so page CSS and the page's own components work inside cells.\n\nAny number of rows scrolls to the end. Browsers limit an element's height\n(about 800k rows of 40 px in Chromium and Safari, 400k in Firefox), so a taller\nbody renders shorter and its scroll position is scaled onto the rows: the\nscrollbar still spans every row, and a wheel step covers a few more of them.\nUse `scrollToRow()` rather than setting the scroll container's `scrollTop`.",
12
356
  "name": "ArgusTable",
13
357
  "cssProperties": [
14
358
  {
@@ -44,6 +388,16 @@
44
388
  "name": "--argus-border-width",
45
389
  "default": "1px"
46
390
  },
391
+ {
392
+ "description": "Border around the whole table, as a `border` shorthand (`1px solid …`). Inside the element's size.",
393
+ "name": "--argus-outline",
394
+ "default": "none"
395
+ },
396
+ {
397
+ "description": "Corner radius of the table. Header, rows and pinned columns are clipped to it.",
398
+ "name": "--argus-radius",
399
+ "default": "0"
400
+ },
47
401
  {
48
402
  "description": "Height of a row. Default per density: 32px, 40px, 52px.",
49
403
  "name": "--argus-row-height"
@@ -69,10 +423,24 @@
69
423
  "name": "--argus-focus-ring",
70
424
  "default": "2px solid Highlight"
71
425
  },
426
+ {
427
+ "description": "Colour of the line that marks where a dragged column would land.",
428
+ "name": "--argus-drop-indicator-color",
429
+ "default": "Highlight"
430
+ },
72
431
  {
73
432
  "description": "Background of the hovered row. Default: no change.",
74
433
  "name": "--argus-row-hover-bg"
75
434
  },
435
+ {
436
+ "description": "Background of the pinned rows, pinned columns included.",
437
+ "name": "--argus-pinned-row-bg",
438
+ "default": "var(--argus-bg)"
439
+ },
440
+ {
441
+ "description": "Colour of the skeleton bars in rows still loading. Default: the text colour at low opacity.",
442
+ "name": "--argus-skeleton-bg"
443
+ },
76
444
  {
77
445
  "description": "Reserved for row selection, which comes after v0.1. The table doesn't read it yet.",
78
446
  "name": "--argus-row-selected-bg"
@@ -100,7 +468,15 @@
100
468
  "name": "header-cell-sorted"
101
469
  },
102
470
  {
103
- "description": "The drag handle on the inline-end edge of a resizable column's header.",
471
+ "description": "Added to `header-cell` on the header being dragged to a new position.",
472
+ "name": "header-cell-dragging"
473
+ },
474
+ {
475
+ "description": "The line on the edge of the header where a dragged column would land.",
476
+ "name": "drop-indicator"
477
+ },
478
+ {
479
+ "description": "The drag handle on the inline-end edge of a resizable column's header. A double-click fits the column to its content.",
104
480
  "name": "resize-handle"
105
481
  },
106
482
  {
@@ -119,6 +495,26 @@
119
495
  "description": "Body rows with an odd index.",
120
496
  "name": "row-odd"
121
497
  },
498
+ {
499
+ "description": "Body rows whose `dataSource` page hasn't loaded yet, or failed.",
500
+ "name": "row-loading"
501
+ },
502
+ {
503
+ "description": "Every row from `pinnedRows`, on either side. Also has `row`, but no `row-even`/`row-odd`.",
504
+ "name": "row-pinned"
505
+ },
506
+ {
507
+ "description": "The rows pinned below the header.",
508
+ "name": "row-pinned-top"
509
+ },
510
+ {
511
+ "description": "The rows pinned to the bottom.",
512
+ "name": "row-pinned-bottom"
513
+ },
514
+ {
515
+ "description": "Every cell of a pinned row (next to `cell`).",
516
+ "name": "cell-pinned-row"
517
+ },
122
518
  {
123
519
  "description": "Every body cell.",
124
520
  "name": "cell"
@@ -135,6 +531,18 @@
135
531
  "description": "The pinned body cell next to the scrolling columns (one per pinned side).",
136
532
  "name": "cell-pinned-edge"
137
533
  },
534
+ {
535
+ "description": "The placeholder bar in each cell of a row that is still loading.",
536
+ "name": "skeleton"
537
+ },
538
+ {
539
+ "description": "Added to `skeleton` in a row whose page failed to load.",
540
+ "name": "skeleton-error"
541
+ },
542
+ {
543
+ "description": "The Retry button in the first cell of a failed page's first visible row.",
544
+ "name": "retry"
545
+ },
138
546
  {
139
547
  "description": "The empty-state container.",
140
548
  "name": "empty"
@@ -153,8 +561,7 @@
153
561
  "type": {
154
562
  "text": "readonly ColumnDef<T>[]"
155
563
  },
156
- "default": "[]",
157
- "description": "Column definitions. Property only: functions can't be attributes."
564
+ "description": "Column definitions. Property only: functions can't be attributes. While empty,\nthe table reads its `<argus-column>` children instead. `null` or `undefined`\nmeans `[]`."
158
565
  },
159
566
  {
160
567
  "kind": "field",
@@ -162,25 +569,40 @@
162
569
  "type": {
163
570
  "text": "readonly T[]"
164
571
  },
165
- "default": "[]",
166
- "description": "The rows to show. Replace the array to update; changes inside it aren't detected."
572
+ "description": "The rows to show. Replace the array to update; changes inside it aren't\ndetected. `null` or `undefined` means `[]`."
167
573
  },
168
574
  {
169
575
  "kind": "field",
170
- "name": "getRowId",
576
+ "name": "dataSource",
171
577
  "type": {
172
- "text": "(row: T, index: number) => string | undefined"
578
+ "text": "DataSource<T> | undefined"
173
579
  },
174
- "description": "Returns a stable id for a row. Default: the row's index in `data`."
580
+ "description": "Loads rows page by page as they scroll into view, instead of `data`:\n`{ getRows({ start, end, sorting, signal }), pageSize? }`, where `end` is\nexclusive and `getRows` resolves to `{ rows, total? }`. Without a `total`,\nthe table grows as pages arrive and a short page marks the end. Sorting\nhappens on the server: a new order reloads from the top. While set, it wins\nover `data`. Replace the object to change `getRows` or `pageSize`."
175
581
  },
176
582
  {
177
583
  "kind": "field",
178
- "name": "rowHeight",
584
+ "name": "pinnedRows",
179
585
  "type": {
180
- "text": "number | undefined"
586
+ "text": "PinnedRows<T> | undefined"
181
587
  },
182
- "description": "Row height in px. Unset: the density (or the `--argus-row-height` token) decides.",
183
- "attribute": "row-height"
588
+ "description": "Rows fixed below the header (`top`) and at the bottom of the view (`bottom`),\nsuch as a totals row: `{ top?: T[], bottom?: T[] }`. They are separate\nobjects, not rows of `data`: columns read them the same way, but they are\nnever sorted and work the same with a `dataSource`. A `cell` function gets\n`pinned: 'top' | 'bottom'` in its context. Replace the object to update."
589
+ },
590
+ {
591
+ "kind": "field",
592
+ "name": "getRowId",
593
+ "type": {
594
+ "text": "(row: T, index: number) => string | undefined"
595
+ },
596
+ "description": "Returns a stable id for a row. Default: the row's index (in `data`, or among all `dataSource` rows)."
597
+ },
598
+ {
599
+ "kind": "field",
600
+ "name": "rowHeight",
601
+ "type": {
602
+ "text": "number | undefined"
603
+ },
604
+ "description": "Row height in px. Unset: the density (or the `--argus-row-height` token) decides.",
605
+ "attribute": "row-height"
184
606
  },
185
607
  {
186
608
  "kind": "field",
@@ -199,8 +621,7 @@
199
621
  "type": {
200
622
  "text": "number"
201
623
  },
202
- "default": "6",
203
- "description": "Rows rendered above and below the visible ones.",
624
+ "description": "Rows rendered above and below the visible ones. `null` or `undefined` means the default, 6.",
204
625
  "attribute": "overscan"
205
626
  },
206
627
  {
@@ -219,6 +640,43 @@
219
640
  },
220
641
  "description": "Resized widths in px by column id, e.g. `{ name: 240 }`. A resized flex column\nbecomes fixed. Uncontrolled until set, like `sorting`: once set, a resize only\nfires `argus-column-resize` with the proposed widths. `undefined` hands it back."
221
642
  },
643
+ {
644
+ "kind": "field",
645
+ "name": "columnOrder",
646
+ "type": {
647
+ "text": "ColumnOrderState"
648
+ },
649
+ "description": "The column order: column ids as the table shows them, e.g.\n`['id', 'total', 'customer']`. `[]` (the default) keeps the order of `columns`.\nEach pin group (start-pinned, scrolling, end-pinned) takes its columns in this\norder; unknown ids are ignored and columns it doesn't list follow the listed\nones of their group. After a move it holds every column id. Uncontrolled\nuntil set, like `sorting`: once set, a move only fires `argus-column-reorder`\nwith the proposed order. `undefined` hands it back."
650
+ },
651
+ {
652
+ "kind": "method",
653
+ "name": "refresh",
654
+ "return": {
655
+ "type": {
656
+ "text": "Promise<void>"
657
+ }
658
+ },
659
+ "description": "With a `dataSource`, drops every loaded page and loads the rows in view\nagain, keeping the scroll position. With `data`, re-renders the cells (after\nchanging row objects in place). Resolves once the table has re-rendered;\nreloaded rows arrive as their pages load."
660
+ },
661
+ {
662
+ "kind": "method",
663
+ "name": "autosizeColumns",
664
+ "return": {
665
+ "type": {
666
+ "text": "Promise<void>"
667
+ }
668
+ },
669
+ "parameters": [
670
+ {
671
+ "name": "ids",
672
+ "optional": true,
673
+ "type": {
674
+ "text": "readonly string[]"
675
+ }
676
+ }
677
+ ],
678
+ "description": "Fits columns to their content: the header, the pinned rows and the body rows\nrendered now (rows out of view aren't measured). It resizes them like a drag\nwould, so `argus-column-resize` fires for each column that changes, and with a\ncontrolled `columnSizing` nothing changes until you set it. Without `ids`, fits\nevery resizable column; columns with `resizable: false` keep their width.\nResolves once the table has re-rendered."
679
+ },
222
680
  {
223
681
  "kind": "method",
224
682
  "name": "scrollToRow",
@@ -240,24 +698,53 @@
240
698
  ],
241
699
  "events": [
242
700
  {
701
+ "type": {
702
+ "text": "CustomEvent<SortChangeDetail>"
703
+ },
243
704
  "description": "A sortable header was clicked, or activated with Enter or Space. `detail: { sorting }`: the new order, or the proposed one when `sorting` is controlled.",
244
705
  "name": "argus-sort-change"
245
706
  },
246
707
  {
247
- "description": "A column was resized by dragging its handle or with Alt+Arrow on its header. `detail: { columnId, width, sizing }`: the new widths, or the proposed ones when `columnSizing` is controlled. Fires on every frame of a drag.",
708
+ "type": {
709
+ "text": "CustomEvent<ColumnResizeDetail>"
710
+ },
711
+ "description": "A column was resized: by dragging its handle, with Alt+Arrow on its header, by a double-click on its handle (fit to content) or by `autosizeColumns()`. `detail: { columnId, width, sizing }`: the new widths, or the proposed ones when `columnSizing` is controlled. Fires on every frame of a drag, and once per column that `autosizeColumns()` changes.",
248
712
  "name": "argus-column-resize"
249
713
  },
250
714
  {
251
- "description": "A body cell was clicked, or Enter was pressed on it. `detail: { row, columnId, value }`. Fires before `argus-row-click`.",
715
+ "type": {
716
+ "text": "CustomEvent<ColumnReorderDetail>"
717
+ },
718
+ "description": "A column was moved: by dragging its header, or with Alt+Shift+Arrow on its focused header. Columns move within their own group (start-pinned, scrolling, end-pinned). `detail: { columnId, order }`: the new order, or the proposed one when `columnOrder` is controlled. Fires once per move, on drop.",
719
+ "name": "argus-column-reorder"
720
+ },
721
+ {
722
+ "type": {
723
+ "text": "CustomEvent<CellClickDetail<T>>"
724
+ },
725
+ "description": "A body or pinned-row cell was clicked, or Enter was pressed on it. `detail: { row, columnId, value, pinned? }`; `pinned` is `'top'` or `'bottom'` for a pinned row. Fires before `argus-row-click`.",
252
726
  "name": "argus-cell-click"
253
727
  },
254
728
  {
255
- "description": "A body row was clicked, or Enter was pressed on one of its cells. `detail: { row, rowId, index }`.",
729
+ "type": {
730
+ "text": "CustomEvent<RowClickDetail<T>>"
731
+ },
732
+ "description": "A body or pinned row was clicked, or Enter was pressed on one of its cells. `detail: { row, rowId, index, pinned? }`; for a pinned row, `index` is its index in its list.",
256
733
  "name": "argus-row-click"
257
734
  },
258
735
  {
736
+ "type": {
737
+ "text": "CustomEvent<RangeChangeDetail>"
738
+ },
259
739
  "description": "The visible rows changed. `detail: { start, end }` (row indices, inclusive).",
260
740
  "name": "argus-range-change"
741
+ },
742
+ {
743
+ "type": {
744
+ "text": "CustomEvent<LoadErrorDetail>"
745
+ },
746
+ "description": "A `dataSource` page failed to load: `getRows()` rejected or threw. `detail: { error, start, end }` (`end` exclusive). The rows show a Retry button.",
747
+ "name": "argus-load-error"
261
748
  }
262
749
  ],
263
750
  "attributes": [
@@ -283,8 +770,7 @@
283
770
  "type": {
284
771
  "text": "number"
285
772
  },
286
- "default": "6",
287
- "description": "Rows rendered above and below the visible ones.",
773
+ "description": "Rows rendered above and below the visible ones. `null` or `undefined` means the default, 6.",
288
774
  "fieldName": "overscan"
289
775
  }
290
776
  ],
@@ -347,6 +833,15 @@
347
833
  "default": "'argus-column-resize'",
348
834
  "description": "Fired when a column was resized (uncontrolled), or with the proposed widths (controlled)."
349
835
  },
836
+ {
837
+ "kind": "variable",
838
+ "name": "COLUMN_REORDER",
839
+ "type": {
840
+ "text": "string"
841
+ },
842
+ "default": "'argus-column-reorder'",
843
+ "description": "Fired when a column was moved (uncontrolled), or with the proposed order (controlled)."
844
+ },
350
845
  {
351
846
  "kind": "variable",
352
847
  "name": "ROW_CLICK",
@@ -365,6 +860,15 @@
365
860
  "default": "'argus-cell-click'",
366
861
  "description": "Fired when a body cell was clicked, before `argus-row-click`."
367
862
  },
863
+ {
864
+ "kind": "variable",
865
+ "name": "LOAD_ERROR",
866
+ "type": {
867
+ "text": "string"
868
+ },
869
+ "default": "'argus-load-error'",
870
+ "description": "Fired after the update when a `dataSource` page failed to load."
871
+ },
368
872
  {
369
873
  "kind": "function",
370
874
  "name": "fire",
@@ -421,6 +925,14 @@
421
925
  "module": "src/events.ts"
422
926
  }
423
927
  },
928
+ {
929
+ "kind": "js",
930
+ "name": "COLUMN_REORDER",
931
+ "declaration": {
932
+ "name": "COLUMN_REORDER",
933
+ "module": "src/events.ts"
934
+ }
935
+ },
424
936
  {
425
937
  "kind": "js",
426
938
  "name": "ROW_CLICK",
@@ -437,6 +949,14 @@
437
949
  "module": "src/events.ts"
438
950
  }
439
951
  },
952
+ {
953
+ "kind": "js",
954
+ "name": "LOAD_ERROR",
955
+ "declaration": {
956
+ "name": "LOAD_ERROR",
957
+ "module": "src/events.ts"
958
+ }
959
+ },
440
960
  {
441
961
  "kind": "js",
442
962
  "name": "fire",
@@ -452,6 +972,14 @@
452
972
  "path": "src/index.ts",
453
973
  "declarations": [],
454
974
  "exports": [
975
+ {
976
+ "kind": "js",
977
+ "name": "ArgusColumn",
978
+ "declaration": {
979
+ "name": "ArgusColumn",
980
+ "module": "./argus-column.js"
981
+ }
982
+ },
455
983
  {
456
984
  "kind": "js",
457
985
  "name": "ArgusTable",
@@ -468,6 +996,14 @@
468
996
  "module": "./events.js"
469
997
  }
470
998
  },
999
+ {
1000
+ "kind": "js",
1001
+ "name": "COLUMN_REORDER",
1002
+ "declaration": {
1003
+ "name": "COLUMN_REORDER",
1004
+ "module": "./events.js"
1005
+ }
1006
+ },
471
1007
  {
472
1008
  "kind": "js",
473
1009
  "name": "COLUMN_RESIZE",
@@ -476,6 +1012,14 @@
476
1012
  "module": "./events.js"
477
1013
  }
478
1014
  },
1015
+ {
1016
+ "kind": "js",
1017
+ "name": "LOAD_ERROR",
1018
+ "declaration": {
1019
+ "name": "LOAD_ERROR",
1020
+ "module": "./events.js"
1021
+ }
1022
+ },
479
1023
  {
480
1024
  "kind": "js",
481
1025
  "name": "RANGE_CHANGE",
@@ -510,6 +1054,98 @@
510
1054
  }
511
1055
  ]
512
1056
  },
1057
+ {
1058
+ "kind": "javascript-module",
1059
+ "path": "src/max-height.ts",
1060
+ "declarations": [
1061
+ {
1062
+ "kind": "function",
1063
+ "name": "bodyCap",
1064
+ "return": {
1065
+ "type": {
1066
+ "text": "number"
1067
+ }
1068
+ },
1069
+ "parameters": [
1070
+ {
1071
+ "name": "logical",
1072
+ "type": {
1073
+ "text": "number"
1074
+ }
1075
+ },
1076
+ {
1077
+ "name": "extra",
1078
+ "type": {
1079
+ "text": "number"
1080
+ }
1081
+ }
1082
+ ],
1083
+ "description": "The tallest the body may render: the engine's maximum less what scrolls with\nit (`extra`: the header and pinned rows). `Infinity` for a body of `logical`\npx that is far from any limit, without measuring."
1084
+ },
1085
+ {
1086
+ "kind": "function",
1087
+ "name": "watchMaxElementHeight",
1088
+ "return": {
1089
+ "type": {
1090
+ "text": "() => void"
1091
+ }
1092
+ },
1093
+ "parameters": [
1094
+ {
1095
+ "name": "listener",
1096
+ "type": {
1097
+ "text": "() => void"
1098
+ }
1099
+ }
1100
+ ],
1101
+ "description": "Calls `listener` when the maximum may have changed (the page was zoomed). Returns the unsubscribe."
1102
+ },
1103
+ {
1104
+ "kind": "function",
1105
+ "name": "setMaxElementHeightForTests",
1106
+ "return": {
1107
+ "type": {
1108
+ "text": "void"
1109
+ }
1110
+ },
1111
+ "parameters": [
1112
+ {
1113
+ "name": "height",
1114
+ "type": {
1115
+ "text": "number | undefined"
1116
+ }
1117
+ }
1118
+ ],
1119
+ "description": "Tests: pretend the engine renders at most `height` px (`undefined` measures again)."
1120
+ }
1121
+ ],
1122
+ "exports": [
1123
+ {
1124
+ "kind": "js",
1125
+ "name": "bodyCap",
1126
+ "declaration": {
1127
+ "name": "bodyCap",
1128
+ "module": "src/max-height.ts"
1129
+ }
1130
+ },
1131
+ {
1132
+ "kind": "js",
1133
+ "name": "watchMaxElementHeight",
1134
+ "declaration": {
1135
+ "name": "watchMaxElementHeight",
1136
+ "module": "src/max-height.ts"
1137
+ }
1138
+ },
1139
+ {
1140
+ "kind": "js",
1141
+ "name": "setMaxElementHeightForTests",
1142
+ "declaration": {
1143
+ "name": "setMaxElementHeightForTests",
1144
+ "module": "src/max-height.ts"
1145
+ }
1146
+ }
1147
+ ]
1148
+ },
513
1149
  {
514
1150
  "kind": "javascript-module",
515
1151
  "path": "src/types.ts",
@@ -539,6 +1175,14 @@
539
1175
  "package": "@argus-table/core"
540
1176
  }
541
1177
  },
1178
+ {
1179
+ "kind": "js",
1180
+ "name": "ColumnOrderState",
1181
+ "declaration": {
1182
+ "name": "ColumnOrderState",
1183
+ "package": "@argus-table/core"
1184
+ }
1185
+ },
542
1186
  {
543
1187
  "kind": "js",
544
1188
  "name": "ColumnPin",
@@ -547,6 +1191,14 @@
547
1191
  "package": "@argus-table/core"
548
1192
  }
549
1193
  },
1194
+ {
1195
+ "kind": "js",
1196
+ "name": "ColumnReorderDetail",
1197
+ "declaration": {
1198
+ "name": "ColumnReorderDetail",
1199
+ "package": "@argus-table/core"
1200
+ }
1201
+ },
550
1202
  {
551
1203
  "kind": "js",
552
1204
  "name": "ColumnResizeDetail",
@@ -571,6 +1223,30 @@
571
1223
  "package": "@argus-table/core"
572
1224
  }
573
1225
  },
1226
+ {
1227
+ "kind": "js",
1228
+ "name": "DataSource",
1229
+ "declaration": {
1230
+ "name": "DataSource",
1231
+ "package": "@argus-table/core"
1232
+ }
1233
+ },
1234
+ {
1235
+ "kind": "js",
1236
+ "name": "LoadErrorDetail",
1237
+ "declaration": {
1238
+ "name": "LoadErrorDetail",
1239
+ "package": "@argus-table/core"
1240
+ }
1241
+ },
1242
+ {
1243
+ "kind": "js",
1244
+ "name": "PinnedRows",
1245
+ "declaration": {
1246
+ "name": "PinnedRows",
1247
+ "package": "@argus-table/core"
1248
+ }
1249
+ },
574
1250
  {
575
1251
  "kind": "js",
576
1252
  "name": "RangeChangeDetail",
@@ -580,35 +1256,593 @@
580
1256
  }
581
1257
  },
582
1258
  {
583
- "kind": "js",
584
- "name": "RowClickDetail",
585
- "declaration": {
586
- "name": "RowClickDetail",
587
- "package": "@argus-table/core"
588
- }
1259
+ "kind": "js",
1260
+ "name": "RowClickDetail",
1261
+ "declaration": {
1262
+ "name": "RowClickDetail",
1263
+ "package": "@argus-table/core"
1264
+ }
1265
+ },
1266
+ {
1267
+ "kind": "js",
1268
+ "name": "RowPin",
1269
+ "declaration": {
1270
+ "name": "RowPin",
1271
+ "package": "@argus-table/core"
1272
+ }
1273
+ },
1274
+ {
1275
+ "kind": "js",
1276
+ "name": "RowsRequest",
1277
+ "declaration": {
1278
+ "name": "RowsRequest",
1279
+ "package": "@argus-table/core"
1280
+ }
1281
+ },
1282
+ {
1283
+ "kind": "js",
1284
+ "name": "RowsResponse",
1285
+ "declaration": {
1286
+ "name": "RowsResponse",
1287
+ "package": "@argus-table/core"
1288
+ }
1289
+ },
1290
+ {
1291
+ "kind": "js",
1292
+ "name": "SortChangeDetail",
1293
+ "declaration": {
1294
+ "name": "SortChangeDetail",
1295
+ "package": "@argus-table/core"
1296
+ }
1297
+ },
1298
+ {
1299
+ "kind": "js",
1300
+ "name": "SortItem",
1301
+ "declaration": {
1302
+ "name": "SortItem",
1303
+ "package": "@argus-table/core"
1304
+ }
1305
+ },
1306
+ {
1307
+ "kind": "js",
1308
+ "name": "SortState",
1309
+ "declaration": {
1310
+ "name": "SortState",
1311
+ "package": "@argus-table/core"
1312
+ }
1313
+ }
1314
+ ]
1315
+ },
1316
+ {
1317
+ "kind": "javascript-module",
1318
+ "path": "src/controllers/auto-width.ts",
1319
+ "declarations": [
1320
+ {
1321
+ "kind": "function",
1322
+ "name": "measureColumns",
1323
+ "return": {
1324
+ "type": {
1325
+ "text": "Map<string, number>"
1326
+ }
1327
+ },
1328
+ "parameters": [
1329
+ {
1330
+ "name": "root",
1331
+ "type": {
1332
+ "text": "ParentNode"
1333
+ }
1334
+ },
1335
+ {
1336
+ "name": "ids",
1337
+ "type": {
1338
+ "text": "Iterable<string>"
1339
+ }
1340
+ }
1341
+ ],
1342
+ "description": "The width each column's content needs, in px, from the cells rendered now:\nthe header, the pinned rows and the rendered body rows. Rows that haven't\nloaded are skipped (their skeleton bars say nothing about the content).\n\nEvery cell of the columns gets `data-measure`, which sizes it to its\n`max-content` (base styles), so the browser accounts for padding, the sort\nindicator and whatever the content is. One forced layout, no paint: the\nattribute is gone before the frame ends. A column with nothing laid out\n(the table is hidden) is left out."
1343
+ },
1344
+ {
1345
+ "kind": "class",
1346
+ "description": "Widths of `width: 'auto'` columns. A column measures once its first loaded\nrows render, and before that fits the header and pinned rows. So each column\nis measured at most twice (three times if fonts were still loading), and a\ntable that stays empty doesn't measure on every update. State is keyed by\ncolumn id, so new `columns` arrays with the same ids don't measure again.",
1347
+ "name": "AutoWidths",
1348
+ "members": [
1349
+ {
1350
+ "kind": "field",
1351
+ "name": "widths",
1352
+ "type": {
1353
+ "text": "ColumnSizingState"
1354
+ },
1355
+ "default": "{}",
1356
+ "description": "Measured widths by column id; a new object whenever one changes."
1357
+ },
1358
+ {
1359
+ "kind": "method",
1360
+ "name": "sync",
1361
+ "return": {
1362
+ "type": {
1363
+ "text": "void"
1364
+ }
1365
+ },
1366
+ "parameters": [
1367
+ {
1368
+ "name": "ids",
1369
+ "type": {
1370
+ "text": "Iterable<string>"
1371
+ }
1372
+ }
1373
+ ],
1374
+ "description": "Forgets columns that are gone or no longer `'auto'`, given the ids of the auto columns."
1375
+ },
1376
+ {
1377
+ "kind": "method",
1378
+ "name": "measure",
1379
+ "return": {
1380
+ "type": {
1381
+ "text": "boolean"
1382
+ }
1383
+ },
1384
+ "parameters": [
1385
+ {
1386
+ "name": "root",
1387
+ "type": {
1388
+ "text": "ParentNode"
1389
+ }
1390
+ },
1391
+ {
1392
+ "name": "columns",
1393
+ "type": {
1394
+ "text": "readonly { id: string; auto: boolean }[]"
1395
+ }
1396
+ },
1397
+ {
1398
+ "name": "hasLoadedRows",
1399
+ "type": {
1400
+ "text": "boolean"
1401
+ }
1402
+ }
1403
+ ],
1404
+ "description": "Measures the auto columns that need it. Returns `true` if a width changed;\nthe caller then renders again (the one extra pass of the render cycle)."
1405
+ }
1406
+ ]
1407
+ }
1408
+ ],
1409
+ "exports": [
1410
+ {
1411
+ "kind": "js",
1412
+ "name": "measureColumns",
1413
+ "declaration": {
1414
+ "name": "measureColumns",
1415
+ "module": "src/controllers/auto-width.ts"
1416
+ }
1417
+ },
1418
+ {
1419
+ "kind": "js",
1420
+ "name": "AutoWidths",
1421
+ "declaration": {
1422
+ "name": "AutoWidths",
1423
+ "module": "src/controllers/auto-width.ts"
1424
+ }
1425
+ }
1426
+ ]
1427
+ },
1428
+ {
1429
+ "kind": "javascript-module",
1430
+ "path": "src/controllers/column-children.ts",
1431
+ "declarations": [
1432
+ {
1433
+ "kind": "class",
1434
+ "description": "Reads the host's `<argus-column>` children into `ColumnDef`s. The columns tell\nthe host when they change (`watchColumns`); the list is rebuilt only then, so\n`defs` keeps its identity between changes.",
1435
+ "name": "ColumnChildrenController",
1436
+ "members": [
1437
+ {
1438
+ "kind": "method",
1439
+ "name": "hostConnected",
1440
+ "return": {
1441
+ "type": {
1442
+ "text": "void"
1443
+ }
1444
+ }
1445
+ },
1446
+ {
1447
+ "kind": "method",
1448
+ "name": "hostDisconnected",
1449
+ "return": {
1450
+ "type": {
1451
+ "text": "void"
1452
+ }
1453
+ }
1454
+ },
1455
+ {
1456
+ "kind": "field",
1457
+ "name": "present",
1458
+ "type": {
1459
+ "text": "boolean"
1460
+ },
1461
+ "description": "Whether the host has any `<argus-column>` child.",
1462
+ "readonly": true
1463
+ },
1464
+ {
1465
+ "kind": "field",
1466
+ "name": "defs",
1467
+ "type": {
1468
+ "text": "readonly ColumnDef<T>[]"
1469
+ },
1470
+ "description": "The children's columns, in document order.",
1471
+ "readonly": true
1472
+ }
1473
+ ]
1474
+ }
1475
+ ],
1476
+ "exports": [
1477
+ {
1478
+ "kind": "js",
1479
+ "name": "ColumnChildrenController",
1480
+ "declaration": {
1481
+ "name": "ColumnChildrenController",
1482
+ "module": "src/controllers/column-children.ts"
1483
+ }
1484
+ }
1485
+ ]
1486
+ },
1487
+ {
1488
+ "kind": "javascript-module",
1489
+ "path": "src/controllers/data-controller.ts",
1490
+ "declarations": [
1491
+ {
1492
+ "kind": "variable",
1493
+ "name": "DEFAULT_PAGE_SIZE",
1494
+ "type": {
1495
+ "text": "number"
1496
+ },
1497
+ "default": "100",
1498
+ "description": "Rows per request when the data source sets no `pageSize`."
1499
+ },
1500
+ {
1501
+ "kind": "variable",
1502
+ "name": "LOAD_DEBOUNCE_MS",
1503
+ "type": {
1504
+ "text": "number"
1505
+ },
1506
+ "default": "50",
1507
+ "description": "Quiet time after the last range change before pages load, so fast scrolling loads only where it stops."
1508
+ },
1509
+ {
1510
+ "kind": "class",
1511
+ "description": "Loads `dataSource` pages for the rendered rows (infinite loading). It owns the\npage cache: a new source, sort order or row id function starts a fresh one, and\nanswers for an old cache are dropped. Requests wait until the range has been\nquiet for `LOAD_DEBOUNCE_MS`; pages that scrolled away are aborted.",
1512
+ "name": "DataController",
1513
+ "members": [
1514
+ {
1515
+ "kind": "method",
1516
+ "name": "hostDisconnected",
1517
+ "return": {
1518
+ "type": {
1519
+ "text": "void"
1520
+ }
1521
+ }
1522
+ },
1523
+ {
1524
+ "kind": "method",
1525
+ "name": "hostConnected",
1526
+ "return": {
1527
+ "type": {
1528
+ "text": "void"
1529
+ }
1530
+ }
1531
+ },
1532
+ {
1533
+ "kind": "field",
1534
+ "name": "rows",
1535
+ "type": {
1536
+ "text": "PageCache<T> | undefined"
1537
+ },
1538
+ "description": "The page cache, while a data source is set: the model reads rows from it.",
1539
+ "readonly": true
1540
+ },
1541
+ {
1542
+ "kind": "method",
1543
+ "name": "configure",
1544
+ "return": {
1545
+ "type": {
1546
+ "text": "void"
1547
+ }
1548
+ },
1549
+ "parameters": [
1550
+ {
1551
+ "name": "next",
1552
+ "type": {
1553
+ "text": "DataConfig<T>"
1554
+ }
1555
+ }
1556
+ ],
1557
+ "description": "Takes the source, sort order and row id function. Any change starts a fresh\ncache; a sort or row id change keeps the row count (the rows are the same)."
1558
+ },
1559
+ {
1560
+ "kind": "method",
1561
+ "name": "refresh",
1562
+ "return": {
1563
+ "type": {
1564
+ "text": "void"
1565
+ }
1566
+ },
1567
+ "description": "Drops every loaded page and loads the rendered ones again. The row count stays until pages answer."
1568
+ },
1569
+ {
1570
+ "kind": "method",
1571
+ "name": "stateAt",
1572
+ "return": {
1573
+ "type": {
1574
+ "text": "RowState"
1575
+ }
1576
+ },
1577
+ "parameters": [
1578
+ {
1579
+ "name": "index",
1580
+ "type": {
1581
+ "text": "number"
1582
+ }
1583
+ }
1584
+ ]
1585
+ },
1586
+ {
1587
+ "kind": "method",
1588
+ "name": "request",
1589
+ "return": {
1590
+ "type": {
1591
+ "text": "void"
1592
+ }
1593
+ },
1594
+ "parameters": [
1595
+ {
1596
+ "name": "start",
1597
+ "type": {
1598
+ "text": "number"
1599
+ }
1600
+ },
1601
+ {
1602
+ "name": "end",
1603
+ "type": {
1604
+ "text": "number"
1605
+ }
1606
+ }
1607
+ ],
1608
+ "description": "The rendered rows, `start` to `end` (exclusive). Loads what's missing once the\nrange has been quiet for a moment. Call after every update."
1609
+ },
1610
+ {
1611
+ "kind": "method",
1612
+ "name": "retry",
1613
+ "return": {
1614
+ "type": {
1615
+ "text": "void"
1616
+ }
1617
+ },
1618
+ "parameters": [
1619
+ {
1620
+ "name": "index",
1621
+ "type": {
1622
+ "text": "number"
1623
+ }
1624
+ }
1625
+ ],
1626
+ "description": "Requests the failed page holding row `index` again (the Retry button, or Enter on a failed row)."
1627
+ },
1628
+ {
1629
+ "kind": "method",
1630
+ "name": "takeErrors",
1631
+ "return": {
1632
+ "type": {
1633
+ "text": "LoadErrorDetail[]"
1634
+ }
1635
+ },
1636
+ "description": "Load errors since the last call, to fire as `argus-load-error` after the update."
1637
+ }
1638
+ ]
1639
+ }
1640
+ ],
1641
+ "exports": [
1642
+ {
1643
+ "kind": "js",
1644
+ "name": "DEFAULT_PAGE_SIZE",
1645
+ "declaration": {
1646
+ "name": "DEFAULT_PAGE_SIZE",
1647
+ "module": "src/controllers/data-controller.ts"
1648
+ }
1649
+ },
1650
+ {
1651
+ "kind": "js",
1652
+ "name": "LOAD_DEBOUNCE_MS",
1653
+ "declaration": {
1654
+ "name": "LOAD_DEBOUNCE_MS",
1655
+ "module": "src/controllers/data-controller.ts"
1656
+ }
1657
+ },
1658
+ {
1659
+ "kind": "js",
1660
+ "name": "DataController",
1661
+ "declaration": {
1662
+ "name": "DataController",
1663
+ "module": "src/controllers/data-controller.ts"
1664
+ }
1665
+ }
1666
+ ]
1667
+ },
1668
+ {
1669
+ "kind": "javascript-module",
1670
+ "path": "src/controllers/pin-scroll-controller.ts",
1671
+ "declarations": [
1672
+ {
1673
+ "kind": "class",
1674
+ "description": "Keeps pinned body cells in place without making them sticky while the table\nonly scrolls up and down.\n\nSafari gives every sticky element a compositing layer of its own and moves\neach one on every scroll frame; with a sticky cell per pinned column per row\nthat is dozens of layers, and vertical scrolling stutters (ADR 0001, \"Pinned\ncolumns in Safari\"). At rest, pinned body cells are plain cells shifted by the\nhorizontal scroll offset (`--_sx`, and `--_max-x` for the end side), which\nonly changes when the table scrolls sideways. While it does, the scroller\ncarries `data-hscroll` and the cells are sticky, so they don't lag behind\nthe scroll; once it settles they go back to the transform, at the same place.\nIt also sizes the pinned edges' shadow overlays (`.pin-shadow`) to the\nscroller's visible area.",
1675
+ "name": "PinScrollController",
1676
+ "members": [
1677
+ {
1678
+ "kind": "method",
1679
+ "name": "hostConnected",
1680
+ "return": {
1681
+ "type": {
1682
+ "text": "void"
1683
+ }
1684
+ }
1685
+ },
1686
+ {
1687
+ "kind": "method",
1688
+ "name": "hostUpdated",
1689
+ "return": {
1690
+ "type": {
1691
+ "text": "void"
1692
+ }
1693
+ }
1694
+ },
1695
+ {
1696
+ "kind": "method",
1697
+ "name": "hostDisconnected",
1698
+ "return": {
1699
+ "type": {
1700
+ "text": "void"
1701
+ }
1702
+ }
1703
+ },
1704
+ {
1705
+ "kind": "method",
1706
+ "name": "measure",
1707
+ "return": {
1708
+ "type": {
1709
+ "text": "void"
1710
+ }
1711
+ },
1712
+ "description": "Re-reads how far the table scrolls sideways: call when column widths change."
1713
+ }
1714
+ ]
1715
+ }
1716
+ ],
1717
+ "exports": [
1718
+ {
1719
+ "kind": "js",
1720
+ "name": "PinScrollController",
1721
+ "declaration": {
1722
+ "name": "PinScrollController",
1723
+ "module": "src/controllers/pin-scroll-controller.ts"
1724
+ }
1725
+ }
1726
+ ]
1727
+ },
1728
+ {
1729
+ "kind": "javascript-module",
1730
+ "path": "src/controllers/reorder-drag.ts",
1731
+ "declarations": [
1732
+ {
1733
+ "kind": "function",
1734
+ "name": "dropTarget",
1735
+ "return": {
1736
+ "type": {
1737
+ "text": "DropTarget | undefined"
1738
+ }
1739
+ },
1740
+ "parameters": [
1741
+ {
1742
+ "name": "slots",
1743
+ "type": {
1744
+ "text": "readonly DropSlot[]"
1745
+ }
1746
+ },
1747
+ {
1748
+ "name": "draggedId",
1749
+ "type": {
1750
+ "text": "string"
1751
+ }
1752
+ },
1753
+ {
1754
+ "name": "x",
1755
+ "type": {
1756
+ "text": "number"
1757
+ }
1758
+ },
1759
+ {
1760
+ "name": "direction",
1761
+ "type": {
1762
+ "text": "1 | -1"
1763
+ }
1764
+ }
1765
+ ],
1766
+ "description": "The drop target for a pointer at `x`: the gap between headers nearest to it,\ndecided by each header's midpoint. `undefined` where the column would stay\nput. `direction` is 1 in LTR and -1 in RTL, where the group runs right to left."
1767
+ },
1768
+ {
1769
+ "kind": "function",
1770
+ "name": "canStartReorder",
1771
+ "return": {
1772
+ "type": {
1773
+ "text": "boolean"
1774
+ }
1775
+ },
1776
+ "parameters": [
1777
+ {
1778
+ "name": "down",
1779
+ "type": {
1780
+ "text": "PointerEvent"
1781
+ }
1782
+ },
1783
+ {
1784
+ "name": "cell",
1785
+ "type": {
1786
+ "text": "HTMLElement"
1787
+ }
1788
+ }
1789
+ ],
1790
+ "description": "Whether a press on a header may start a reorder drag: the primary button of a\nmouse or pen (a touch pans the table instead), not on a resize handle, and not\nin interactive content slotted into the header."
589
1791
  },
1792
+ {
1793
+ "kind": "function",
1794
+ "name": "startReorderDrag",
1795
+ "return": {
1796
+ "type": {
1797
+ "text": "void"
1798
+ }
1799
+ },
1800
+ "parameters": [
1801
+ {
1802
+ "name": "cell",
1803
+ "type": {
1804
+ "text": "HTMLElement"
1805
+ }
1806
+ },
1807
+ {
1808
+ "name": "down",
1809
+ "type": {
1810
+ "text": "PointerEvent"
1811
+ }
1812
+ },
1813
+ {
1814
+ "name": "options",
1815
+ "type": {
1816
+ "text": "ReorderDragOptions"
1817
+ }
1818
+ }
1819
+ ],
1820
+ "description": "One pointer drag of a column header. It becomes a drag after a few pixels of\nmovement; until then the press is a click. While dragging, the pointer is\ncaptured by the header, the target follows the pointer once per frame, and the\nscroll area scrolls near its edges. Escape cancels. The click that ends a drag\nis swallowed, so it neither sorts nor counts as a cell click."
1821
+ }
1822
+ ],
1823
+ "exports": [
590
1824
  {
591
1825
  "kind": "js",
592
- "name": "SortChangeDetail",
1826
+ "name": "dropTarget",
593
1827
  "declaration": {
594
- "name": "SortChangeDetail",
595
- "package": "@argus-table/core"
1828
+ "name": "dropTarget",
1829
+ "module": "src/controllers/reorder-drag.ts"
596
1830
  }
597
1831
  },
598
1832
  {
599
1833
  "kind": "js",
600
- "name": "SortItem",
1834
+ "name": "canStartReorder",
601
1835
  "declaration": {
602
- "name": "SortItem",
603
- "package": "@argus-table/core"
1836
+ "name": "canStartReorder",
1837
+ "module": "src/controllers/reorder-drag.ts"
604
1838
  }
605
1839
  },
606
1840
  {
607
1841
  "kind": "js",
608
- "name": "SortState",
1842
+ "name": "startReorderDrag",
609
1843
  "declaration": {
610
- "name": "SortState",
611
- "package": "@argus-table/core"
1844
+ "name": "startReorderDrag",
1845
+ "module": "src/controllers/reorder-drag.ts"
612
1846
  }
613
1847
  }
614
1848
  ]
@@ -708,7 +1942,7 @@
708
1942
  "declarations": [
709
1943
  {
710
1944
  "kind": "class",
711
- "description": "Row virtualization (TanStack Virtual) plus the row pool: which rows render,\nwhere, and which pool slot's DOM each one uses. The virtualizer registers itself\nwith the host and requests updates on scroll.",
1945
+ "description": "Row virtualization (TanStack Virtual) plus the row pool: which rows render,\nwhere, and which pool slot's DOM each one uses. The virtualizer registers itself\nwith the host and requests updates on scroll.\n\nScroll scaling: engines limit an element's height, so a body taller than the\ncap renders at the cap and its scroll position maps linearly onto the rows\n(`ScrollScale`). The virtualizer works in logical offsets: it gets a stand-in\nfor the scroller whose `scrollTop`, `scrollHeight` and `scrollTo()` are\nlogical, and everything else passes through. Rows render relative to the\nscroll position (`start` minus the difference between the logical and the\nphysical offset). Scroll through this controller (`scrollBy`, `reveal`,\n`scrollToIndex`): physical px no longer match rows once the body is scaled.",
712
1946
  "name": "VirtualController",
713
1947
  "members": [
714
1948
  {
@@ -728,6 +1962,15 @@
728
1962
  }
729
1963
  ]
730
1964
  },
1965
+ {
1966
+ "kind": "method",
1967
+ "name": "hostUpdated",
1968
+ "return": {
1969
+ "type": {
1970
+ "text": "void"
1971
+ }
1972
+ }
1973
+ },
731
1974
  {
732
1975
  "kind": "method",
733
1976
  "name": "computeWindow",
@@ -747,6 +1990,15 @@
747
1990
  "description": "Number of pool slots created so far: bounded by the most rows rendered at once.",
748
1991
  "readonly": true
749
1992
  },
1993
+ {
1994
+ "kind": "field",
1995
+ "name": "scaled",
1996
+ "type": {
1997
+ "text": "boolean"
1998
+ },
1999
+ "description": "Whether the body is taller than the cap and scrolls scaled.",
2000
+ "readonly": true
2001
+ },
750
2002
  {
751
2003
  "kind": "method",
752
2004
  "name": "scrollToIndex",
@@ -771,6 +2023,54 @@
771
2023
  }
772
2024
  ],
773
2025
  "description": "`'start'` puts the row at the top; `'auto'` scrolls only as far as needed to show it."
2026
+ },
2027
+ {
2028
+ "kind": "method",
2029
+ "name": "scrollBy",
2030
+ "return": {
2031
+ "type": {
2032
+ "text": "void"
2033
+ }
2034
+ },
2035
+ "parameters": [
2036
+ {
2037
+ "name": "delta",
2038
+ "type": {
2039
+ "text": "number"
2040
+ }
2041
+ }
2042
+ ],
2043
+ "description": "Scrolls by `delta` px of rows (logical px)."
2044
+ },
2045
+ {
2046
+ "kind": "method",
2047
+ "name": "reveal",
2048
+ "return": {
2049
+ "type": {
2050
+ "text": "boolean"
2051
+ }
2052
+ },
2053
+ "parameters": [
2054
+ {
2055
+ "name": "index",
2056
+ "type": {
2057
+ "text": "number"
2058
+ }
2059
+ },
2060
+ {
2061
+ "name": "before",
2062
+ "type": {
2063
+ "text": "number"
2064
+ }
2065
+ },
2066
+ {
2067
+ "name": "after",
2068
+ "type": {
2069
+ "text": "number"
2070
+ }
2071
+ }
2072
+ ],
2073
+ "description": "Scrolls the least distance that shows row `index` in full, between the\ncontent above the body (`before` px: the header and top pinned rows) and\nbelow it (`after` px). Returns whether the rows are yet to move there (with\nthe update after the scroll event): until then the row's DOM isn't where it\nwill be."
774
2074
  }
775
2075
  ]
776
2076
  }
@@ -786,6 +2086,28 @@
786
2086
  }
787
2087
  ]
788
2088
  },
2089
+ {
2090
+ "kind": "javascript-module",
2091
+ "path": "src/styles/base.ts",
2092
+ "declarations": [
2093
+ {
2094
+ "kind": "variable",
2095
+ "name": "baseStyles",
2096
+ "default": "css` @layer argus-base { :host { display: block; /* A table that virtualizes needs a bounded height; set your own on the element. */ block-size: 400px; box-sizing: border-box; contain: content; color-scheme: light dark; color: var(--argus-fg, CanvasText); background: var(--argus-bg, Canvas); font: var(--argus-font, inherit); /* contain: content clips the header, rows and pinned shadows to the rounded corners. */ border: var(--argus-outline, none); border-radius: var(--argus-radius, 0); --_row-height: var(--argus-row-height, 40px); --_pad: var(--argus-cell-padding-inline, 12px); --_border: var(--argus-border-width, 1px) solid var(--argus-border-color, light-dark(#e5e7eb, #374151)); /* 1 in LTR, -1 in RTL: mirrors the pinned-edge shadow. */ --_dir: 1; } :host(:dir(rtl)) { --_dir: -1; } :host([density='compact']) { --_row-height: var(--argus-row-height, 32px); --_pad: var(--argus-cell-padding-inline, 8px); } :host([density='spacious']) { --_row-height: var(--argus-row-height, 52px); --_pad: var(--argus-cell-padding-inline, 16px); } :host([hidden]) { display: none; } [part~='table'] { position: relative; block-size: 100%; overflow: auto; overscroll-behavior: contain; /* * A cell moved to by keyboard scrolls clear of the sticky header, the pinned * rows and the pinned columns. */ scroll-padding-block-start: calc((1 + var(--_pin-top-rows, 0)) * var(--_row-height)); scroll-padding-block-end: calc(var(--_pin-bottom-rows, 0) * var(--_row-height)); scroll-padding-inline: var(--_pin-start, 0) var(--_pin-end, 0); } .row { display: grid; grid-template-columns: var(--_cols); inline-size: var(--_width); min-inline-size: 100%; block-size: var(--_row-height); box-sizing: border-box; } [part~='header'] { position: sticky; inset-block-start: 0; z-index: 2; } [part~='body'] { position: relative; contain: layout; } [part~='body'] > .row { position: absolute; inset-block-start: 0; inset-inline-start: 0; } [part~='row'] { --_row-bg: var(--argus-bg, Canvas); --_row-surface: var(--_row-bg); background: var(--_row-surface); } [part~='row-odd'] { --_row-bg: var(--argus-row-stripe-bg, var(--argus-bg, Canvas)); } [part~='row']:hover { --_row-surface: var(--argus-row-hover-bg, var(--_row-bg)); } /* * Pinned rows: a sticky row group below the header and one at the bottom of * the view. The header is one row tall. They keep their place in the flow, * so body row i still starts i rows below the top group. */ .pinned { position: sticky; z-index: 2; } .pinned[data-side='top'] { inset-block-start: var(--_row-height); } .pinned[data-side='bottom'] { inset-block-end: 0; } [part~='row-pinned'] { --_row-bg: var(--argus-pinned-row-bg, var(--argus-bg, Canvas)); } [part~='cell'], [part~='header-cell'] { display: flex; align-items: center; min-inline-size: 0; box-sizing: border-box; padding-inline: var(--_pad); overflow: hidden; white-space: nowrap; border-block-end: var(--_border); } [part~='header-cell'] { background: var(--argus-header-bg, light-dark(#f9fafb, #111827)); color: var(--argus-header-fg, inherit); font-weight: 600; } [part~='header-cell'] { position: relative; } [part~='resize-handle'] { position: absolute; inset-block: 0; inset-inline-end: 0; inline-size: 8px; z-index: 1; cursor: col-resize; touch-action: none; } [part~='resize-handle']::after { content: ''; position: absolute; inset-block: 25%; inset-inline-end: 0; inline-size: 2px; background: var(--argus-resize-handle-color, light-dark(#9ca3af, #6b7280)); opacity: 0; } [part~='header-cell']:hover [part~='resize-handle']::after, [part~='header-cell']:focus-visible [part~='resize-handle']::after, [part~='resize-handle'][data-active]::after { opacity: 1; } [data-sort-col] { cursor: pointer; user-select: none; } /* A drag on a reorderable header moves the column, so its text isn't selectable. */ [data-move-col] { user-select: none; } [data-dragging], [data-dragging] [part~='header-cell'] { cursor: grabbing; } [part~='header-cell-dragging'] { opacity: 0.5; } /* The line where a dragged column would land, on the target header's logical edge. */ [part~='drop-indicator'] { position: absolute; inset-block: 0; inline-size: 2px; z-index: 2; background: var(--argus-drop-indicator-color, Highlight); pointer-events: none; } [part~='drop-indicator'][data-edge='start'] { inset-inline-start: 0; } [part~='drop-indicator'][data-edge='end'] { inset-inline-end: 0; } [part~='header-cell']:focus-visible, [part~='cell']:focus-visible { outline: var(--argus-focus-ring, 2px solid Highlight); outline-offset: -2px; } /* A small chevron after the header content; only the sorted column shows it. */ .sort-indicator { flex: none; inline-size: 0.35em; block-size: 0.35em; margin-inline-start: 0.4em; /* Physical sides on purpose: the chevron is rotated, so it must not mirror in RTL. */ border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; visibility: hidden; } [aria-sort] .sort-indicator { visibility: visible; } [aria-sort='ascending'] .sort-indicator { transform: translateY(0.1em) rotate(-135deg); } [aria-sort='descending'] .sort-indicator { transform: translateY(-0.1em) rotate(45deg); } [data-align='end'] .sort-indicator { order: -1; margin-inline: 0 0.4em; } /* * Pinned columns: sticky inside the scroll container, with offsets from the * table model. Logical insets make RTL work without extra rules. */ [data-pin] { position: sticky; z-index: 1; } [data-pin='start'] { inset-inline-start: var(--_pin-offset); } [data-pin='end'] { inset-inline-end: var(--_pin-offset); } /* * Pinned body cells are sticky only while the table scrolls sideways * (data-hscroll on the scroller). At rest they are plain cells shifted by the * horizontal scroll offset, which vertical scrolling never changes: a sticky * cell per row is a compositing layer each, and Safari stutters moving them * (PinScrollController). Both place the cells at the same spot. */ [part~='row'] > [data-pin] { position: relative; inset-inline: auto; } [part~='row'] > [data-pin='start'] { transform: translateX(var(--_sx, 0px)); } [part~='row'] > [data-pin='end'] { transform: translateX(calc(var(--_sx, 0px) - var(--_dir) * var(--_max-x, 0px))); } [data-hscroll] [part~='row'] > [data-pin] { position: sticky; transform: none; } [data-hscroll] [part~='row'] > [data-pin='start'] { inset-inline-start: var(--_pin-offset); } [data-hscroll] [part~='row'] > [data-pin='end'] { inset-inline-end: var(--_pin-offset); } [part~='cell-pinned'] { background: var(--_row-surface); } /* * The edge shadow, once per pinned side (.pin-shadow, beside the scroller). * --argus-pinned-shadow is written for a shadow falling toward the end side; * the start edge in RTL and the end edge in LTR mirror it. */ .pin-shadow { position: absolute; inset-block-start: 0; block-size: min(var(--_view-h, 100%), var(--_content-h, 100%)); z-index: 3; pointer-events: none; } .pin-shadow[data-side='start'] { inset-inline-start: 0; } .pin-shadow[data-side='end'] { inset-inline-end: var(--_sb-x, 0px); } .pin-shadow::after { content: ''; position: absolute; inset: 0; box-shadow: var( --argus-pinned-shadow, 4px 0 6px -4px light-dark(rgb(0 0 0 / 0.2), rgb(0 0 0 / 0.6)) ); transform: scaleX(var(--_dir)); } .pin-shadow[data-side='end']::after { transform: scaleX(calc(-1 * var(--_dir))); } [data-align='center'] { justify-content: center; text-align: center; } [data-align='end'] { justify-content: flex-end; text-align: end; } ::slotted(*) { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; } /* Fitting a column to its content: set for one synchronous measurement, never painted. */ [data-measure] { inline-size: max-content; } /* Rows of a data source that haven't loaded: a bar per cell, pulsing gently. */ [part~='skeleton'] { flex: none; inline-size: min(60%, 8em); block-size: 0.6em; border-radius: 0.3em; background: var(--argus-skeleton-bg, color-mix(in srgb, currentColor 12%, transparent)); animation: argus-skeleton-pulse 1.6s ease-in-out infinite; } [part~='skeleton-error'] { animation: none; opacity: 0.5; } @keyframes argus-skeleton-pulse { 50% { opacity: 0.45; } } @media (prefers-reduced-motion: reduce) { [part~='skeleton'] { animation: none; } } [part~='retry'] { font: inherit; color: inherit; cursor: pointer; } [part~='empty'] { display: flex; align-items: center; justify-content: center; min-block-size: calc( 100% - (1 + var(--_pin-top-rows, 0) + var(--_pin-bottom-rows, 0)) * var(--_row-height) ); padding: var(--_pad); box-sizing: border-box; } /* Measures the resolved row height in px for the virtualizer. */ .probe { position: absolute; inset-block-start: 0; inline-size: 0; block-size: var(--_row-height); visibility: hidden; pointer-events: none; } } `",
2097
+ "description": "Base styles. Everything sits in `@layer argus-base`, and every value reads a\npublic token with a neutral fallback, so themes and page CSS always win.\n`--_*` properties are private."
2098
+ }
2099
+ ],
2100
+ "exports": [
2101
+ {
2102
+ "kind": "js",
2103
+ "name": "baseStyles",
2104
+ "declaration": {
2105
+ "name": "baseStyles",
2106
+ "module": "src/styles/base.ts"
2107
+ }
2108
+ }
2109
+ ]
2110
+ },
789
2111
  {
790
2112
  "kind": "javascript-module",
791
2113
  "path": "src/render/body.ts",
@@ -817,9 +2139,60 @@
817
2139
  "type": {
818
2140
  "text": "ActiveCell | undefined"
819
2141
  }
2142
+ },
2143
+ {
2144
+ "name": "firstRowIndex",
2145
+ "type": {
2146
+ "text": "number"
2147
+ }
2148
+ },
2149
+ {
2150
+ "name": "loading",
2151
+ "optional": true,
2152
+ "type": {
2153
+ "text": "Loading"
2154
+ }
2155
+ }
2156
+ ],
2157
+ "description": "The virtualized body. Rows are keyed by pool slot, so a row entering the window\nreuses the DOM of one that left (ADR 0001), and they stay in pool order: screen\nreaders get the position from `aria-rowindex`. `firstRowIndex` is the\n`aria-rowindex` of row 0: after the header and the rows pinned to the top."
2158
+ },
2159
+ {
2160
+ "kind": "function",
2161
+ "name": "renderCell",
2162
+ "parameters": [
2163
+ {
2164
+ "name": "c",
2165
+ "type": {
2166
+ "text": "ColumnView<T, CellContent>"
2167
+ }
2168
+ },
2169
+ {
2170
+ "name": "tabStop",
2171
+ "type": {
2172
+ "text": "boolean"
2173
+ }
2174
+ },
2175
+ {
2176
+ "name": "slot",
2177
+ "type": {
2178
+ "text": "string"
2179
+ }
2180
+ },
2181
+ {
2182
+ "name": "pinnedRow",
2183
+ "type": {
2184
+ "text": "boolean"
2185
+ }
2186
+ },
2187
+ {
2188
+ "name": "before",
2189
+ "default": "nothing",
2190
+ "type": {
2191
+ "text": "unknown"
2192
+ }
820
2193
  }
821
2194
  ],
822
- "description": "The virtualized body. Rows are keyed by pool slot, so a row entering the window\nreuses the DOM of one that left (ADR 0001), and they stay in pool order: screen\nreaders get the position from `aria-rowindex` (the header row is 1)."
2195
+ "description": "A body or pinned-row cell. Every cell is focusable (`tabindex=-1`) so clicks\nfocus it; `tabStop` marks the grid's single tab stop. `before` goes ahead of\nthe slot (a loading row's skeleton bar or Retry button)."
823
2196
  }
824
2197
  ],
825
2198
  "exports": [
@@ -830,6 +2203,14 @@
830
2203
  "name": "renderBody",
831
2204
  "module": "src/render/body.ts"
832
2205
  }
2206
+ },
2207
+ {
2208
+ "kind": "js",
2209
+ "name": "renderCell",
2210
+ "declaration": {
2211
+ "name": "renderCell",
2212
+ "module": "src/render/body.ts"
2213
+ }
833
2214
  }
834
2215
  ]
835
2216
  },
@@ -863,9 +2244,15 @@
863
2244
  "type": {
864
2245
  "text": "readonly WindowRow[]"
865
2246
  }
2247
+ },
2248
+ {
2249
+ "name": "renderBefore",
2250
+ "type": {
2251
+ "text": "ChildNode"
2252
+ }
866
2253
  }
867
2254
  ],
868
- "description": "Renders header and cell content into the host's light DOM, as direct children\n(a slot only takes the host's own children). Keyed and ordered by pool slot,\nso recycled content updates in place instead of moving (ADR 0001)."
2255
+ "description": "Renders header and cell content into the host's light DOM, as direct children\n(a slot only takes the host's own children). Keyed and ordered by pool slot,\nso recycled content updates in place instead of moving (ADR 0001). The part\nends at `renderBefore`, so the host's other children (`<argus-column>`) stay\noutside it, wherever they are added."
869
2256
  }
870
2257
  ],
871
2258
  "exports": [
@@ -936,7 +2323,7 @@
936
2323
  }
937
2324
  }
938
2325
  ],
939
- "description": "Private slot names (ADR 0001): cells by pool slot and column, headers by column."
2326
+ "description": "Private slot names (ADR 0001): cells by pool slot and column, headers by\ncolumn, pinned rows by side, index and column."
940
2327
  },
941
2328
  {
942
2329
  "kind": "function",
@@ -950,6 +2337,30 @@
950
2337
  }
951
2338
  ]
952
2339
  },
2340
+ {
2341
+ "kind": "function",
2342
+ "name": "pinnedSlot",
2343
+ "parameters": [
2344
+ {
2345
+ "name": "side",
2346
+ "type": {
2347
+ "text": "'top' | 'bottom'"
2348
+ }
2349
+ },
2350
+ {
2351
+ "name": "index",
2352
+ "type": {
2353
+ "text": "number"
2354
+ }
2355
+ },
2356
+ {
2357
+ "name": "colIndex",
2358
+ "type": {
2359
+ "text": "number"
2360
+ }
2361
+ }
2362
+ ]
2363
+ },
953
2364
  {
954
2365
  "kind": "function",
955
2366
  "name": "cellParts",
@@ -964,9 +2375,13 @@
964
2375
  "type": {
965
2376
  "text": "Pinnable & { sorted: 'asc' | 'desc' | false }"
966
2377
  }
2378
+ },
2379
+ {
2380
+ "name": "pinnedRow",
2381
+ "default": "false"
967
2382
  }
968
2383
  ],
969
- "description": "Part list of a body cell: state is in the part name (`::part()` can't take attribute selectors)."
2384
+ "description": "Part list of a body or pinned-row cell: state is in the part name (`::part()`\ncan't take attribute selectors)."
970
2385
  },
971
2386
  {
972
2387
  "kind": "function",
@@ -1038,6 +2453,14 @@
1038
2453
  "module": "src/render/content.ts"
1039
2454
  }
1040
2455
  },
2456
+ {
2457
+ "kind": "js",
2458
+ "name": "pinnedSlot",
2459
+ "declaration": {
2460
+ "name": "pinnedSlot",
2461
+ "module": "src/render/content.ts"
2462
+ }
2463
+ },
1041
2464
  {
1042
2465
  "kind": "js",
1043
2466
  "name": "cellParts",
@@ -1089,9 +2512,16 @@
1089
2512
  "type": {
1090
2513
  "text": "string | undefined"
1091
2514
  }
2515
+ },
2516
+ {
2517
+ "name": "drag",
2518
+ "optional": true,
2519
+ "type": {
2520
+ "text": "HeaderDrag"
2521
+ }
1092
2522
  }
1093
2523
  ],
1094
- "description": "The sticky header row. Header content is slotted from the light DOM. Pinned\nheader cells use the same private `data-pin` hooks as body cells, but no parts.\nEvery header carries `data-col` (its column id) and sortable ones also\n`data-sort-col`; the element's delegated handlers read them. Headers take part\nin the grid's roving tabindex: the active one is the tab stop (`activeCol`).\nResizable columns get a `resize-handle` on the header's inline-end edge. It is\nnot focusable: the focused header resizes with Alt+Arrow."
2524
+ "description": "The sticky header row. Header content is slotted from the light DOM. Pinned\nheader cells use the same private `data-pin` hooks as body cells, but no parts.\nEvery header carries `data-col` (its column id) and sortable ones also\n`data-sort-col`; the element's delegated handlers read them. Headers take part\nin the grid's roving tabindex: the active one is the tab stop (`activeCol`).\nResizable columns get a `resize-handle` on the header's inline-end edge; a\ndouble-click on it fits the column to its content. It is not focusable: the\nfocused header resizes with Alt+Arrow.\n\nReorderable columns carry `data-move-col`: a drag on the header moves the\ncolumn. While one is dragged (`drag`), its header adds `header-cell-dragging`\nand the target header shows a `drop-indicator` on the edge it would land at."
1095
2525
  }
1096
2526
  ],
1097
2527
  "exports": [
@@ -1107,22 +2537,53 @@
1107
2537
  },
1108
2538
  {
1109
2539
  "kind": "javascript-module",
1110
- "path": "src/styles/base.ts",
2540
+ "path": "src/render/pinned-rows.ts",
1111
2541
  "declarations": [
1112
2542
  {
1113
- "kind": "variable",
1114
- "name": "baseStyles",
1115
- "default": "css` @layer argus-base { :host { display: block; /* A table that virtualizes needs a bounded height; set your own on the element. */ block-size: 400px; box-sizing: border-box; contain: content; color-scheme: light dark; color: var(--argus-fg, CanvasText); background: var(--argus-bg, Canvas); font: var(--argus-font, inherit); --_row-height: var(--argus-row-height, 40px); --_pad: var(--argus-cell-padding-inline, 12px); --_border: var(--argus-border-width, 1px) solid var(--argus-border-color, light-dark(#e5e7eb, #374151)); /* 1 in LTR, -1 in RTL: mirrors the pinned-edge shadow. */ --_dir: 1; } :host(:dir(rtl)) { --_dir: -1; } :host([density='compact']) { --_row-height: var(--argus-row-height, 32px); --_pad: var(--argus-cell-padding-inline, 8px); } :host([density='spacious']) { --_row-height: var(--argus-row-height, 52px); --_pad: var(--argus-cell-padding-inline, 16px); } :host([hidden]) { display: none; } [part~='table'] { position: relative; block-size: 100%; overflow: auto; overscroll-behavior: contain; /* A cell moved to by keyboard scrolls clear of the sticky header and pinned columns. */ scroll-padding-block-start: var(--_row-height); scroll-padding-inline: var(--_pin-start, 0) var(--_pin-end, 0); } .row { display: grid; grid-template-columns: var(--_cols); inline-size: var(--_width); min-inline-size: 100%; block-size: var(--_row-height); box-sizing: border-box; } [part~='header'] { position: sticky; inset-block-start: 0; z-index: 2; } [part~='body'] { position: relative; contain: layout; } [part~='row'] { position: absolute; inset-block-start: 0; inset-inline-start: 0; --_row-bg: var(--argus-bg, Canvas); --_row-surface: var(--_row-bg); background: var(--_row-surface); } [part~='row-odd'] { --_row-bg: var(--argus-row-stripe-bg, var(--argus-bg, Canvas)); } [part~='row']:hover { --_row-surface: var(--argus-row-hover-bg, var(--_row-bg)); } [part~='cell'], [part~='header-cell'] { display: flex; align-items: center; min-inline-size: 0; box-sizing: border-box; padding-inline: var(--_pad); overflow: hidden; white-space: nowrap; border-block-end: var(--_border); } [part~='header-cell'] { background: var(--argus-header-bg, light-dark(#f9fafb, #111827)); color: var(--argus-header-fg, inherit); font-weight: 600; } [part~='header-cell'] { position: relative; } [part~='resize-handle'] { position: absolute; inset-block: 0; inset-inline-end: 0; inline-size: 8px; z-index: 1; cursor: col-resize; touch-action: none; } [part~='resize-handle']::after { content: ''; position: absolute; inset-block: 25%; inset-inline-end: 0; inline-size: 2px; background: var(--argus-resize-handle-color, light-dark(#9ca3af, #6b7280)); opacity: 0; } [part~='header-cell']:hover [part~='resize-handle']::after, [part~='header-cell']:focus-visible [part~='resize-handle']::after, [part~='resize-handle'][data-active]::after { opacity: 1; } [data-sort-col] { cursor: pointer; user-select: none; } [part~='header-cell']:focus-visible, [part~='cell']:focus-visible { outline: var(--argus-focus-ring, 2px solid Highlight); outline-offset: -2px; } /* A small chevron after the header content; only the sorted column shows it. */ .sort-indicator { flex: none; inline-size: 0.35em; block-size: 0.35em; margin-inline-start: 0.4em; /* Physical sides on purpose: the chevron is rotated, so it must not mirror in RTL. */ border-right: 0.12em solid currentColor; border-bottom: 0.12em solid currentColor; visibility: hidden; } [aria-sort] .sort-indicator { visibility: visible; } [aria-sort='ascending'] .sort-indicator { transform: translateY(0.1em) rotate(-135deg); } [aria-sort='descending'] .sort-indicator { transform: translateY(-0.1em) rotate(45deg); } [data-align='end'] .sort-indicator { order: -1; margin-inline: 0 0.4em; } /* * Pinned columns: sticky inside the scroll container, with offsets from the * table model. Logical insets make RTL work without extra rules. */ [data-pin] { position: sticky; z-index: 1; /* Visible so the edge shadow isn't clipped; slotted content still clips itself. */ overflow: visible; } [data-pin='start'] { inset-inline-start: var(--_pin-offset); } [data-pin='end'] { inset-inline-end: var(--_pin-offset); } [part~='cell-pinned'] { background: var(--_row-surface); } /* * The edge shadow. --argus-pinned-shadow is written for a shadow falling * toward the end side; the start edge in RTL and the end edge in LTR mirror it. */ [data-pin-edge]::after { content: ''; position: absolute; inset: 0; pointer-events: none; box-shadow: var( --argus-pinned-shadow, 4px 0 6px -4px light-dark(rgb(0 0 0 / 0.2), rgb(0 0 0 / 0.6)) ); transform: scaleX(var(--_dir)); } [data-pin='end'][data-pin-edge]::after { transform: scaleX(calc(-1 * var(--_dir))); } [data-align='center'] { justify-content: center; text-align: center; } [data-align='end'] { justify-content: flex-end; text-align: end; } ::slotted(*) { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; } [part~='empty'] { display: flex; align-items: center; justify-content: center; min-block-size: calc(100% - var(--_row-height)); padding: var(--_pad); box-sizing: border-box; } /* Measures the resolved row height in px for the virtualizer. */ .probe { position: absolute; inset-block-start: 0; inline-size: 0; block-size: var(--_row-height); visibility: hidden; pointer-events: none; } } `",
1116
- "description": "Base styles. Everything sits in `@layer argus-base`, and every value reads a\npublic token with a neutral fallback, so themes and page CSS always win.\n`--_*` properties are private."
2543
+ "kind": "function",
2544
+ "name": "renderPinnedRows",
2545
+ "parameters": [
2546
+ {
2547
+ "name": "side",
2548
+ "type": {
2549
+ "text": "RowPin"
2550
+ }
2551
+ },
2552
+ {
2553
+ "name": "count",
2554
+ "type": {
2555
+ "text": "number"
2556
+ }
2557
+ },
2558
+ {
2559
+ "name": "columns",
2560
+ "type": {
2561
+ "text": "readonly ColumnView<T, CellContent>[]"
2562
+ }
2563
+ },
2564
+ {
2565
+ "name": "firstRowIndex",
2566
+ "type": {
2567
+ "text": "number"
2568
+ }
2569
+ },
2570
+ {
2571
+ "name": "active",
2572
+ "type": {
2573
+ "text": "ActiveCell | undefined"
2574
+ }
2575
+ }
2576
+ ],
2577
+ "description": "The rows pinned to one side: a sticky row group below the header (`top`) or\nat the bottom of the view (`bottom`). They are few and never recycled, so\nthey aren't pooled; content is slotted from the light DOM like body cells.\nCells take part in the grid's roving tabindex (`active.index` is the row's\nindex in its list). `firstRowIndex` is the `aria-rowindex` of the first row."
1117
2578
  }
1118
2579
  ],
1119
2580
  "exports": [
1120
2581
  {
1121
2582
  "kind": "js",
1122
- "name": "baseStyles",
2583
+ "name": "renderPinnedRows",
1123
2584
  "declaration": {
1124
- "name": "baseStyles",
1125
- "module": "src/styles/base.ts"
2585
+ "name": "renderPinnedRows",
2586
+ "module": "src/render/pinned-rows.ts"
1126
2587
  }
1127
2588
  }
1128
2589
  ]