@fusion.dev/helix-headless 0.168.0 → 0.170.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.
@@ -5613,7 +5613,7 @@
5613
5613
  "text": "'error' | 'loaded' | 'loading'"
5614
5614
  },
5615
5615
  "default": "'loading'",
5616
- "description": "The image's state: `loading` while it is on its way, `loaded` once it\narrives, or `error` when it fails and the initials replace it. An avatar\nwith no `src` has no image to wait for, and reports `error` as well, since\nthe initials are what it shows.\n\nRead-only to a consumer: it is a report rather than a setting, and the same\nreport `Image` gives, for the same reason. `load` and `error` fire once, so\na listener bound after the picture settled hears neither, which is the\nplatform on an `<img>` too, and this is what that listener asks instead.\nMirrored to `data-status` rather than reflected, as `Image` explains."
5616
+ "description": "The image's state: `loading` while it is on its way, `loaded` once it\narrives, or `error` when it fails and the initials replace it. An avatar\nwith no `src` has no image to wait for, and reports `error` as well, since\nthe initials are what it shows.\n\nRead-only to a consumer: it is a report rather than a setting, and the same\nreport `Image` gives, for the same reason. `load` and `error` fire once, so\na listener bound after the picture settled hears neither, which is the\nplatform on an `<img>` too, and this is what that listener asks instead.\nMirrored to `data-status` rather than reflected, as `Image` explains, once a\npicture has loaded or failed. An avatar with no `src` reports `error` here\nand as `:state(error)`, and writes no `data-status`."
5617
5617
  },
5618
5618
  {
5619
5619
  "kind": "field",
@@ -45780,7 +45780,7 @@
45780
45780
  "declarations": [
45781
45781
  {
45782
45782
  "kind": "class",
45783
- "description": "Declare the columns as `TableColumn` children and pass the rows as an array.\nThe schema stays readable in the HTML, and the rows can be windowed, which\nten thousand row elements cannot be.\n\n```html\n<helix-headless-data-table .rows=${rows} sort=\"name:asc\" page-size=\"20\">\n <helix-headless-table-column field=\"name\" sortable>Name</helix-headless-table-column>\n <helix-headless-table-column field=\"size\" text-align=\"end\" sortable .cell=${bytes}>Size</helix-headless-table-column>\n</helix-headless-data-table>\n```\n\nFor a short table written out by hand, use `Table`, which takes rows as\nmarkup.\n\nSort and filter apply to the whole set, including the rows on other pages.\n\n**The cell values do not server-render.** The headings and the row elements\ndo. Reading a cell needs the columns, and Lit SSR does not pass the column\nchildren to this element, so a crawler sees an empty table of the right\nshape. Use `Table` when the served HTML has to carry the values.\n\n`selectable` adds a column of checkboxes, keyed on `row-key`:\n\n- A row is selected by its key, so the selection survives a sort, a filter,\n and a page change.\n- `selected` holds the chosen keys, comma separated, the same shape `Listbox`\n uses for a multiple choice. As with `sort`, writing it applies the\n selection, and `default-selected` holds what the markup declared.\n- The checkbox in the heading selects every row in the result, across pages,\n and shows a dash while only some are chosen.\n- Shift with a press on a checkbox selects every row between it and the row\n last chosen.\n- `selection-behavior=\"replace\"` makes a press or a move select the row\n alone, as a file list does. Control or Command with a press adds or takes\n out one row, and Shift with a press selects every row from the one last\n chosen.\n\nTo act on a single row, such as opening it, put a link or a button in a cell.\n\n**Keyboard.** The grid is one tab stop, and the arrow keys move between its\ncells, the headings included.\n\n| Key | What it does |\n|---|---|\n| Right, Left | Moves one cell along the row. Left moves on, on a right-to-left page. |\n| Down, Up | Moves one row, the heading row and the `load-more` row included. |\n| Home, End | Moves to the first or the last cell of the row. |\n| Control with Home or End | Moves to the first or the last cell of the grid. |\n| Page Down, Page Up | Moves by the rows that fit in view. |\n| Enter, F2 | Moves into the cell's controls. Escape moves back to the cell, and Tab moves between the controls of one cell. |\n| Enter, Space on a sortable heading | Sorts by the column. |\n| Enter, Space on the `load-more` row | Sends `helix-load-more`. |\n| Space on a row | Selects the row, in a `selectable` table. Under `selection-behavior=\"replace\"`, selects it alone, and Control or Command with Space adds or takes out the row. |\n| Down, Up, Page Down, Page Up under `selection-behavior=\"replace\"` | Selects the row it moves to alone. Control or Command with the key moves without selecting. |\n| Shift with Down or Up | Selects the rows it moves across, in a `selectable` table. |\n| Shift with Space | Selects every row from the one last chosen, in a `selectable` table. |\n| Control or Command with A | Selects every row, in a `selectable` table. |\n| Right on a row header in a tree grid | Opens a closed row, and moves one cell along an open one. |\n| Left on a row header in a tree grid | Closes an open row, and moves to the parent of a closed one. |\n| A letter or a word | Moves to the next row whose row header starts with what you typed. |\n\n`selected` and `expanded` hold their keys in the order of the rows, as do\n`helix-select`, `helix-selected` and `helix-expand`.\n\nEach row is named by its row header, the column marked `row-header`, or the\nfirst column with a `field` where none is. A screen reader says it as a reader\nmoves between rows.\n\n**Rows that hold rows.** `child-field` names the field that holds a row's\nchild rows, and the grid becomes a tree grid. The row header column draws a\nmark that a press opens and closes a row by, and `expanded` holds the keys of the open\nrows, which `row-key` names. Right on a closed row's header opens it, Left on\nan open one closes it, and Left on a child moves to its parent. A sort orders\nthe rows under each parent, and a search shows the rows that lead to each\nmatch, open.\n\n`load-more` adds a row after the last one with a button that sends\n`helix-load-more`. A `windowed` table also sends it by itself once a reader\nscrolls within one screen of the end, once for each number of rows. Add the\nnext rows to `rows`, and set `loading` while they are on their way.\n\nWhen a fetch fails, set `error-text`, such as \"The files did not load\", and\nput a button that tries again in the `error` slot. The line shows after the\nrows in place of the empty and loading lines, the live region says it, and\nthe table takes the `error` state. Clear it once you try again.\n\nThe controls inside the cells leave the tab order, so Tab moves past the\nwhole grid. A windowed table keeps the row holding focus drawn while the\nrest scroll away.\n\nPeople can resize and reorder the columns. `resizable` on a column puts a\nseparator on its edge. `reorderable` on the table puts a grip on each heading\nthat has a `field`, moved by dragging or with the arrow keys. The new order\nis written to `order` as a list of fields. Your markup is not rewritten: the\ntable assigns the headings to its header in that order.\n\n**`reorderable-rows` lets people move rows.** A column of grips leads each\nrow, named by `move-row-label`. Drag a grip to move its row, and the table\nscrolls near an edge. Or press Space or Enter on a grip, or click it, to pick\nup its row, move it with Down and Up, Home and End, and press Space or Enter\nagain to drop it. A click on another row drops it there, and Escape puts it\nback. The table says each step in its `live` region. A drop sends\n`helix-before-reorder`, which you can refuse, and then `helix-reorder` with\n`kind` set to `row`, whose `keys` hold every key of `rows` in the new order.\n**You move the rows**: set `rows` to the new order, and the table draws it.\nSet `row-key`, so a row is known by its key once it has moved. The grips do\nnothing while a `sort` is set, since the sort decides the order, and a tree\ngrid draws none.\n\n`csv()` returns the result as text: every row that passes the filter, in the\norder and the columns on screen. Saving the file is up to you.\n\n`DataTable` has no `columns` attribute. Each `TableColumn` is part of the\nschema, so you size a column with its own `width`. `Table` has `columns`\nbecause its cells are markup you write and it can have no columns at all.\nWritten on `DataTable`, `columns` has no effect, so watch for it when you\nmove a table from `Table` to `DataTable`.",
45783
+ "description": "Declare the columns as `TableColumn` children and pass the rows as an array.\nThe schema stays readable in the HTML, and the rows can be windowed, which\nten thousand row elements cannot be.\n\n```html\n<helix-headless-data-table .rows=${rows} sort=\"name:asc\" page-size=\"20\">\n <helix-headless-table-column field=\"name\" sortable>Name</helix-headless-table-column>\n <helix-headless-table-column field=\"size\" text-align=\"end\" sortable .cell=${bytes}>Size</helix-headless-table-column>\n</helix-headless-data-table>\n```\n\nFor a short table written out by hand, use `Table`, which takes rows as\nmarkup.\n\nSort and filter apply to the whole set, including the rows on other pages.\n\n**Write the first page as rows, so the served HTML carries the values.** The\ntable reads each cell from its column, and a server does not pass the column\nchildren to this element, so on its own it serves the headings and no values.\nWrite the first page under the columns as `TableRow` and `TableCell`\nelements, in the table's sort and page size and formatted as its columns draw\nthem. The table shows your rows until `rows` holds a row, then draws its own\nin their place and leaves yours in the page, unshown. A development build\nwarns when the two differ. In React, map the first page of the same array in\nthe same server component.\n\n`selectable` adds a column of checkboxes, keyed on `row-key`:\n\n- A row is selected by its key, so the selection survives a sort, a filter,\n and a page change.\n- `selected` holds the chosen keys, comma separated, the same shape `Listbox`\n uses for a multiple choice. As with `sort`, writing it applies the\n selection, and `default-selected` holds what the markup declared.\n- The checkbox in the heading selects every row in the result, across pages,\n and shows a dash while only some are chosen.\n- Shift with a press on a checkbox selects every row between it and the row\n last chosen.\n- `selection-behavior=\"replace\"` makes a press or a move select the row\n alone, as a file list does. Control or Command with a press adds or takes\n out one row, and Shift with a press selects every row from the one last\n chosen.\n\nTo act on a single row, such as opening it, put a link or a button in a cell.\n\n**Keyboard.** The grid is one tab stop, and the arrow keys move between its\ncells, the headings included.\n\n| Key | What it does |\n|---|---|\n| Right, Left | Moves one cell along the row. Left moves on, on a right-to-left page. |\n| Down, Up | Moves one row, the heading row and the `load-more` row included. |\n| Home, End | Moves to the first or the last cell of the row. |\n| Control with Home or End | Moves to the first or the last cell of the grid. |\n| Page Down, Page Up | Moves by the rows that fit in view. |\n| Enter, F2 | Moves into the cell's controls. Escape moves back to the cell, and Tab moves between the controls of one cell. |\n| Enter, Space on a sortable heading | Sorts by the column. |\n| Enter, Space on the `load-more` row | Sends `helix-load-more`. |\n| Space on a row | Selects the row, in a `selectable` table. Under `selection-behavior=\"replace\"`, selects it alone, and Control or Command with Space adds or takes out the row. |\n| Down, Up, Page Down, Page Up under `selection-behavior=\"replace\"` | Selects the row it moves to alone. Control or Command with the key moves without selecting. |\n| Shift with Down or Up | Selects the rows it moves across, in a `selectable` table. |\n| Shift with Space | Selects every row from the one last chosen, in a `selectable` table. |\n| Control or Command with A | Selects every row, in a `selectable` table. |\n| Right on a row header in a tree grid | Opens a closed row, and moves one cell along an open one. |\n| Left on a row header in a tree grid | Closes an open row, and moves to the parent of a closed one. |\n| A letter or a word | Moves to the next row whose row header starts with what you typed. |\n\n`selected` and `expanded` hold their keys in the order of the rows, as do\n`helix-select`, `helix-selected` and `helix-expand`.\n\nEach row is named by its row header, the column marked `row-header`, or the\nfirst column with a `field` where none is. A screen reader says it as a reader\nmoves between rows.\n\n**Rows that hold rows.** `child-field` names the field that holds a row's\nchild rows, and the grid becomes a tree grid. The row header column draws a\nmark that a press opens and closes a row by, and `expanded` holds the keys of the open\nrows, which `row-key` names. Right on a closed row's header opens it, Left on\nan open one closes it, and Left on a child moves to its parent. A sort orders\nthe rows under each parent, and a search shows the rows that lead to each\nmatch, open.\n\n`load-more` adds a row after the last one with a button that sends\n`helix-load-more`. A `windowed` table also sends it by itself once a reader\nscrolls within one screen of the end, once for each number of rows. Add the\nnext rows to `rows`, and set `loading` while they are on their way.\n\nWhen a fetch fails, set `error-text`, such as \"The files did not load\", and\nput a button that tries again in the `error` slot. The line shows after the\nrows in place of the empty and loading lines, the live region says it, and\nthe table takes the `error` state. Clear it once you try again.\n\nThe controls inside the cells leave the tab order, so Tab moves past the\nwhole grid. A windowed table keeps the row holding focus drawn while the\nrest scroll away.\n\nPeople can resize and reorder the columns. `resizable` on a column puts a\nseparator on its edge. `reorderable` on the table puts a grip on each heading\nthat has a `field`, moved by dragging or with the arrow keys. The new order\nis written to `order` as a list of fields. Your markup is not rewritten: the\ntable assigns the headings to its header in that order.\n\n**`reorderable-rows` lets people move rows.** A column of grips leads each\nrow, named by `move-row-label`. Drag a grip to move its row, and the table\nscrolls near an edge. Or press Space or Enter on a grip, or click it, to pick\nup its row, move it with Down and Up, Home and End, and press Space or Enter\nagain to drop it. A click on another row drops it there, and Escape puts it\nback. The table says each step in its `live` region. A drop sends\n`helix-before-reorder`, which you can refuse, and then `helix-reorder` with\n`kind` set to `row`, whose `keys` hold every key of `rows` in the new order.\n**You move the rows**: set `rows` to the new order, and the table draws it.\nSet `row-key`, so a row is known by its key once it has moved. The grips do\nnothing while a `sort` is set, since the sort decides the order, and a tree\ngrid draws none.\n\n`csv()` returns the result as text: every row that passes the filter, in the\norder and the columns on screen. Saving the file is up to you.\n\n`DataTable` has no `columns` attribute. Each `TableColumn` is part of the\nschema, so you size a column with its own `width`. `Table` has `columns`\nbecause its cells are markup you write and it can have no columns at all.\nWritten on `DataTable`, `columns` has no effect, so watch for it when you\nmove a table from `Table` to `DataTable`.",
45784
45784
  "name": "HelixHeadlessDataTable",
45785
45785
  "cssProperties": [
45786
45786
  {
@@ -46020,7 +46020,7 @@
46020
46020
  ],
46021
46021
  "slots": [
46022
46022
  {
46023
- "description": "The columns, as `TableColumn` elements.",
46023
+ "description": "The columns, as `TableColumn` elements, and the first page served as `TableRow` elements, which show until `rows` holds a row.",
46024
46024
  "name": ""
46025
46025
  },
46026
46026
  {
@@ -46776,6 +46776,36 @@
46776
46776
  "default": "false",
46777
46777
  "description": "Whether the last render drew the `more` row, which follows the page's rows."
46778
46778
  },
46779
+ {
46780
+ "kind": "field",
46781
+ "name": "drewRows",
46782
+ "type": {
46783
+ "text": "boolean"
46784
+ },
46785
+ "privacy": "private",
46786
+ "default": "false",
46787
+ "description": "Whether `rows` has held a row, after which the rows the page served are\nnever shown again, whatever `rows` holds later."
46788
+ },
46789
+ {
46790
+ "kind": "field",
46791
+ "name": "serving",
46792
+ "type": {
46793
+ "text": "boolean"
46794
+ },
46795
+ "privacy": "private",
46796
+ "default": "false",
46797
+ "description": "Whether the last render showed the rows the page served."
46798
+ },
46799
+ {
46800
+ "kind": "field",
46801
+ "name": "servedLast",
46802
+ "type": {
46803
+ "text": "boolean"
46804
+ },
46805
+ "privacy": "private",
46806
+ "default": "false",
46807
+ "description": "Whether the render before the last showed them, so the change is checked once."
46808
+ },
46779
46809
  {
46780
46810
  "kind": "field",
46781
46811
  "name": "typeahead",
@@ -47251,6 +47281,27 @@
47251
47281
  "module": "src/mixins/mixin-collection/mixin-collection.ts"
47252
47282
  }
47253
47283
  },
47284
+ {
47285
+ "kind": "field",
47286
+ "name": "servedRows",
47287
+ "type": {
47288
+ "text": "Element[]"
47289
+ },
47290
+ "privacy": "private",
47291
+ "description": "The rows the page served: the first page, written as `TableRow` children.\n\nBy tag, because the page may not register `Table`, and an element that is\nnot defined has no `isTableRow` to find it by.",
47292
+ "readonly": true
47293
+ },
47294
+ {
47295
+ "kind": "method",
47296
+ "name": "serves",
47297
+ "privacy": "private",
47298
+ "return": {
47299
+ "type": {
47300
+ "text": "boolean"
47301
+ }
47302
+ },
47303
+ "description": "Whether this render shows the rows the page served in place of drawing its\nown.\n\n**Until `rows` has held a row, and never after.** A server cannot tell\nwhether the page served any, and a render hydrating what one sent has to\nrender the same, so both show the slot that would hold them. In a browser\nthe rows are shown while `rows` is empty, which is how a framework that\nrenders on a server leaves the property until it hydrates. Once the table\nhas drawn its own rows it stops showing the served ones and never removes\nthem: they are the page's markup, and a framework that rendered them owns\nthem."
47304
+ },
47254
47305
  {
47255
47306
  "kind": "field",
47256
47307
  "name": "sourceKnown",
@@ -113053,6 +113104,16 @@
113053
113104
  "attribute": "orientation",
113054
113105
  "reflects": true
113055
113106
  },
113107
+ {
113108
+ "kind": "field",
113109
+ "name": "variant",
113110
+ "type": {
113111
+ "text": "'segmented' | 'underlined' | undefined"
113112
+ },
113113
+ "description": "How the destinations are drawn, with `Tabs`' three values and for the same\nreasons.\n\nUnset is a pill under the current destination with nothing behind the row,\nfor a bar inside other chrome. `underlined` is a rule under the row and a\nthicker one under the current destination, for a bar that heads a page, as\na repository's or a project's sections do. `segmented` puts the pill in a\nframed, sunken track, for a short set that reads as one control.\n\n**The same words as `Tabs`, because a reader cannot tell the two apart.**\nNavigation moves between pages and tabs between the panels of one page,\nand the bar looks the same either way. A console whose sections are pages\ncould not draw them the way its underlined tabs were drawn.\n\nDown a column, `underlined` stands the rule and the mark along the\ncolumn's inline end.\n\nReflected and left unset by default, so the host carries nothing a\nconsumer's server markup does not already have.",
113114
+ "attribute": "variant",
113115
+ "reflects": true
113116
+ },
113056
113117
  {
113057
113118
  "kind": "field",
113058
113119
  "name": "current",
@@ -113484,6 +113545,14 @@
113484
113545
  },
113485
113546
  "description": "Stacks the destinations in a column, for a sidebar, where unset is a row\nfor a header or a footer. The marker follows the current destination down\nthe column as it does along the row.",
113486
113547
  "fieldName": "orientation"
113548
+ },
113549
+ {
113550
+ "name": "variant",
113551
+ "type": {
113552
+ "text": "'segmented' | 'underlined' | undefined"
113553
+ },
113554
+ "description": "How the destinations are drawn, with `Tabs`' three values and for the same\nreasons.\n\nUnset is a pill under the current destination with nothing behind the row,\nfor a bar inside other chrome. `underlined` is a rule under the row and a\nthicker one under the current destination, for a bar that heads a page, as\na repository's or a project's sections do. `segmented` puts the pill in a\nframed, sunken track, for a short set that reads as one control.\n\n**The same words as `Tabs`, because a reader cannot tell the two apart.**\nNavigation moves between pages and tabs between the panels of one page,\nand the bar looks the same either way. A console whose sections are pages\ncould not draw them the way its underlined tabs were drawn.\n\nDown a column, `underlined` stands the rule and the mark along the\ncolumn's inline end.\n\nReflected and left unset by default, so the host carries nothing a\nconsumer's server markup does not already have.",
113555
+ "fieldName": "variant"
113487
113556
  }
113488
113557
  ],
113489
113558
  "cssStates": [
@@ -196364,6 +196433,6 @@
196364
196433
  ],
196365
196434
  "helix": {
196366
196435
  "package": "@fusion.dev/helix-headless",
196367
- "version": "0.168.0"
196436
+ "version": "0.170.0"
196368
196437
  }
196369
196438
  }
@@ -95,7 +95,9 @@ export declare class HelixHeadlessAvatar extends HelixElement {
95
95
  * report `Image` gives, for the same reason. `load` and `error` fire once, so
96
96
  * a listener bound after the picture settled hears neither, which is the
97
97
  * platform on an `<img>` too, and this is what that listener asks instead.
98
- * Mirrored to `data-status` rather than reflected, as `Image` explains.
98
+ * Mirrored to `data-status` rather than reflected, as `Image` explains, once a
99
+ * picture has loaded or failed. An avatar with no `src` reports `error` here
100
+ * and as `:state(error)`, and writes no `data-status`.
99
101
  */
100
102
  status: 'error' | 'loaded' | 'loading';
101
103
  /**
@@ -78,8 +78,8 @@ let HelixHeadlessAvatar = class HelixHeadlessAvatar extends HelixElement {
78
78
  if (changed.has('src') || changed.has('fallbackDelay')) {
79
79
  this.startWait();
80
80
  }
81
- if (changed.has('status')) {
82
- if (this.status === 'loading') {
81
+ if (changed.has('status') || changed.has('src')) {
82
+ if (this.status === 'loading' || this.src === '') {
83
83
  this.removeAttribute('data-status');
84
84
  }
85
85
  else {
@@ -24,10 +24,15 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
24
24
  *
25
25
  * Sort and filter apply to the whole set, including the rows on other pages.
26
26
  *
27
- * **The cell values do not server-render.** The headings and the row elements
28
- * do. Reading a cell needs the columns, and Lit SSR does not pass the column
29
- * children to this element, so a crawler sees an empty table of the right
30
- * shape. Use `Table` when the served HTML has to carry the values.
27
+ * **Write the first page as rows, so the served HTML carries the values.** The
28
+ * table reads each cell from its column, and a server does not pass the column
29
+ * children to this element, so on its own it serves the headings and no values.
30
+ * Write the first page under the columns as `TableRow` and `TableCell`
31
+ * elements, in the table's sort and page size and formatted as its columns draw
32
+ * them. The table shows your rows until `rows` holds a row, then draws its own
33
+ * in their place and leaves yours in the page, unshown. A development build
34
+ * warns when the two differ. In React, map the first page of the same array in
35
+ * the same server component.
31
36
  *
32
37
  * `selectable` adds a column of checkboxes, keyed on `row-key`:
33
38
  *
@@ -132,7 +137,7 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
132
137
  * @aliases Grid, Result table, Data grid
133
138
  * @documentation https://fusion.dev/helix/components/data-table
134
139
  *
135
- * @slot - The columns, as `TableColumn` elements.
140
+ * @slot - The columns, as `TableColumn` elements, and the first page served as `TableRow` elements, which show until `rows` holds a row.
136
141
  * @slot empty - Content shown when there are no rows to show and none are loading, such as a picture and a link. Falls back to `empty-text`, which the live region still says.
137
142
  * @slot error - Content shown while `error-text` is set, such as a button that tries again. Falls back to `error-text`, which the live region still says.
138
143
  * @slot footer - Content below the grid. It replaces the built-in pagination.
@@ -610,6 +615,15 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
610
615
  private drawnPage;
611
616
  /** Whether the last render drew the `more` row, which follows the page's rows. */
612
617
  private moreDrawn;
618
+ /**
619
+ * Whether `rows` has held a row, after which the rows the page served are
620
+ * never shown again, whatever `rows` holds later.
621
+ */
622
+ private drewRows;
623
+ /** Whether the last render showed the rows the page served. */
624
+ private serving;
625
+ /** Whether the render before the last showed them, so the change is checked once. */
626
+ private servedLast;
613
627
  /** The letters typed at the grid, which move to the row whose header they start. */
614
628
  private readonly typeahead;
615
629
  /**
@@ -841,6 +855,27 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
841
855
  * what this replaced.
842
856
  */
843
857
  protected get hasRows(): boolean;
858
+ /**
859
+ * The rows the page served: the first page, written as `TableRow` children.
860
+ *
861
+ * By tag, because the page may not register `Table`, and an element that is
862
+ * not defined has no `isTableRow` to find it by.
863
+ */
864
+ private get servedRows();
865
+ /**
866
+ * Whether this render shows the rows the page served in place of drawing its
867
+ * own.
868
+ *
869
+ * **Until `rows` has held a row, and never after.** A server cannot tell
870
+ * whether the page served any, and a render hydrating what one sent has to
871
+ * render the same, so both show the slot that would hold them. In a browser
872
+ * the rows are shown while `rows` is empty, which is how a framework that
873
+ * renders on a server leaves the property until it hydrates. Once the table
874
+ * has drawn its own rows it stops showing the served ones and never removes
875
+ * them: they are the page's markup, and a framework that rendered them owns
876
+ * them.
877
+ */
878
+ private serves;
844
879
  /**
845
880
  * Whether this render can tell a result with no rows from one not yet handed
846
881
  * over.
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessDataTable_1;
8
- import { anchorAt, arranged, commaList, countLabel, customElement, cycle, deepActiveElement, deepContains, everyState, format, formatWords, gridMove, HelixActivateEvent, HelixElement, HelixExpandEvent, HelixFilterEvent, HelixFilteredEvent, HelixLoadMoreEvent, HelixNavigateEvent, HelixReorderEvent, HelixReorderedEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, handedLocale, hostAria, inlineStep, inRowOrder, MixinCollection, markRegion, onAndroid, ordered, pageRows, parse, placeKey, ReorderController, rangeAdd, reportRuntime, requestChange, requestReorder, scrollingAncestor, scrollRoom, selectsAll, Typeahead, toggleEvery, treeArrow, typesCharacter, VirtualizeController, valueAt, window_, words, wordsLocale, writtenList, } from '@fusion.dev/helix-core';
8
+ import { anchorAt, arranged, auditServed, commaList, countLabel, customElement, cycle, deepActiveElement, deepContains, everyState, format, formatWords, gridMove, HelixActivateEvent, HelixElement, HelixExpandEvent, HelixFilterEvent, HelixFilteredEvent, HelixLoadMoreEvent, HelixNavigateEvent, HelixReorderEvent, HelixReorderedEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, handedLocale, hostAria, inlineStep, inRowOrder, MixinCollection, markRegion, onAndroid, ordered, pageRows, parse, placeKey, ReorderController, rangeAdd, reportRuntime, requestChange, requestReorder, scrollingAncestor, scrollRoom, selectsAll, Typeahead, toggleEvery, treeArrow, typesCharacter, VirtualizeController, valueAt, window_, words, wordsLocale, writtenList, } from '@fusion.dev/helix-core';
9
9
  import { caretDown, caretRight, dotsSixVertical } from '@fusion.dev/helix-icons';
10
10
  import { nothing } from 'lit';
11
11
  import { property, state } from 'lit/decorators.js';
@@ -86,6 +86,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
86
86
  this.focusWanted = false;
87
87
  this.drawnPage = [];
88
88
  this.moreDrawn = false;
89
+ this.drewRows = false;
90
+ this.serving = false;
91
+ this.servedLast = false;
89
92
  this.typeahead = new Typeahead();
90
93
  this.anchorKey = undefined;
91
94
  this.shiftPressed = false;
@@ -656,7 +659,17 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
656
659
  })).length;
657
660
  }
658
661
  get hasRows() {
659
- return this.view.available > 0 || !this.sourceKnown;
662
+ return this.view.available > 0 || !this.sourceKnown || this.serving;
663
+ }
664
+ get servedRows() {
665
+ return this.knownChildren.filter((child) => /^helix-(headless-)?table-row$/.test(child.localName));
666
+ }
667
+ serves() {
668
+ if (!this.sourceKnown) {
669
+ return true;
670
+ }
671
+ this.drewRows ||= this.rows.length > 0;
672
+ return !this.drewRows && this.servedRows.length > 0;
660
673
  }
661
674
  get sourceKnown() {
662
675
  return this.childrenKnown;
@@ -909,6 +922,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
909
922
  }
910
923
  const columns = this.orderedColumns;
911
924
  head.assign(...columns);
925
+ root
926
+ .querySelector('[part="table"] > slot:not([name])')
927
+ ?.assign(...(this.serving ? this.servedRows : []));
912
928
  const rest = [...this.children].filter((child) => !columns.includes(child));
913
929
  for (const [name, wanted] of [
914
930
  ['toolbar', true],
@@ -986,6 +1002,10 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
986
1002
  this.toggleState('empty', !this.loading && !this.hasRows);
987
1003
  this.toggleState('loading', this.loading);
988
1004
  this.assign();
1005
+ if (this.servedLast && !this.serving) {
1006
+ auditServed(this, this.servedRows, [...this.renderRoot.querySelectorAll('[part~="row"]')], this.drawnPage.length);
1007
+ }
1008
+ this.servedLast = this.serving;
989
1009
  this.announceSort();
990
1010
  this.quietControls();
991
1011
  this.placeFocus();
@@ -1186,7 +1206,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
1186
1206
  }
1187
1207
  render() {
1188
1208
  const { available, matched, page } = this.view;
1189
- this.drawnPage = page;
1209
+ const serving = this.serves();
1210
+ this.serving = serving;
1211
+ this.drawnPage = serving ? [] : page;
1190
1212
  this.moreDrawn = this.loadMore && !this.loading && this.errorText === '' && page.length > 0;
1191
1213
  const rows = this.windowOf(page);
1192
1214
  const kept = this.keptRow(page);
@@ -1196,7 +1218,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
1196
1218
  const columns = this.shownColumns;
1197
1219
  const pagination = this.tag('pagination');
1198
1220
  const counted = this.mode === 'server' ? Math.max(this.total, available) : matched;
1199
- const countKnown = counted > 0 || this.sourceKnown;
1221
+ const countKnown = counted > 0 || (this.sourceKnown && !serving);
1200
1222
  this.counts = {
1201
1223
  columns: columns.length ? columns.length + this.lead : undefined,
1202
1224
  rows: countKnown ? counted + 1 + (this.moreDrawn ? 1 : 0) : undefined,
@@ -1210,13 +1232,19 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
1210
1232
  @scroll=${this.handleScroll}
1211
1233
  >
1212
1234
  <div part="head" role="row" aria-rowindex="1">
1213
- ${this.rowGrips ? this.renderGripHead(headStop && this.currentColumn === 0) : nothing}${this.selectable
1235
+ ${this.rowGrips && this.sourceKnown
1236
+ ? this.renderGripHead(headStop && this.currentColumn === 0)
1237
+ : nothing}${this.selectable && this.sourceKnown
1214
1238
  ? this.renderSelectAll(headStop && this.currentColumn === this.selectAt)
1215
1239
  : nothing}${this.assignsByName && !this.hydrating
1216
1240
  ? this.orderedColumns.map((_, index) => html `<slot name=${`column-${index + 1}`} @slotchange=${this.handleSlotChange}></slot>`)
1217
- : html `<slot name="columns" @slotchange=${this.handleSlotChange}></slot>`}
1241
+ : html `<slot name="columns" @slotchange=${this.handleSlotChange}></slot>`}${this.sourceKnown ? nothing : html `<slot @slotchange=${this.handleSlotChange}></slot>`}
1218
1242
  </div>
1219
- ${this.renderSpacer('before', kept)}${this.renderRows(rows, page)}${this.renderSpacer('after', kept)}
1243
+ ${serving
1244
+ ? this.sourceKnown
1245
+ ? html `<slot @slotchange=${this.handleSlotChange}></slot>`
1246
+ : nothing
1247
+ : html `${this.renderSpacer('before', kept)}${this.renderRows(rows, page)}${this.renderSpacer('after', kept)}`}
1220
1248
  ${this.renderMore(page)}${this.errorText === '' ? this.renderStatus(filled, 'gridcell') : this.renderError()}
1221
1249
  </div>
1222
1250
  ${this.errorText === '' ? this.renderLive(filled) : html `<span part="live" role="status">${this.errorText}</span>`}
@@ -90,6 +90,28 @@ export declare class HelixHeadlessNavigation extends HelixElement {
90
90
  * the column as it does along the row.
91
91
  */
92
92
  orientation?: 'vertical';
93
+ /**
94
+ * How the destinations are drawn, with `Tabs`' three values and for the same
95
+ * reasons.
96
+ *
97
+ * Unset is a pill under the current destination with nothing behind the row,
98
+ * for a bar inside other chrome. `underlined` is a rule under the row and a
99
+ * thicker one under the current destination, for a bar that heads a page, as
100
+ * a repository's or a project's sections do. `segmented` puts the pill in a
101
+ * framed, sunken track, for a short set that reads as one control.
102
+ *
103
+ * **The same words as `Tabs`, because a reader cannot tell the two apart.**
104
+ * Navigation moves between pages and tabs between the panels of one page,
105
+ * and the bar looks the same either way. A console whose sections are pages
106
+ * could not draw them the way its underlined tabs were drawn.
107
+ *
108
+ * Down a column, `underlined` stands the rule and the mark along the
109
+ * column's inline end.
110
+ *
111
+ * Reflected and left unset by default, so the host carries nothing a
112
+ * consumer's server markup does not already have.
113
+ */
114
+ variant?: 'segmented' | 'underlined';
93
115
  private current;
94
116
  /** The disclosures among the destinations that are open. */
95
117
  private readonly opened;
@@ -155,6 +155,9 @@ __decorate([
155
155
  __decorate([
156
156
  property({ reflect: true })
157
157
  ], HelixHeadlessNavigation.prototype, "orientation", void 0);
158
+ __decorate([
159
+ property({ reflect: true })
160
+ ], HelixHeadlessNavigation.prototype, "variant", void 0);
158
161
  HelixHeadlessNavigation = __decorate([
159
162
  customElement('helix-headless-navigation')
160
163
  ], HelixHeadlessNavigation);