@fusion.dev/helix-headless 0.184.0 → 0.185.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.
@@ -46797,7 +46797,7 @@
46797
46797
  "declarations": [
46798
46798
  {
46799
46799
  "kind": "class",
46800
- "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`.\n\n**The columns are an import of their own.** A column is the Table family's\n`TableColumn`, which the data table does not register, so a page that writes\none imports the Table entry beside the data table:\n\n```js\nimport '@fusion.dev/helix/data-table'\nimport '@fusion.dev/helix/table'\n```\n\nIn development, a data table holding a column nobody registered says so once\nthe page has loaded, with the line to add.",
46800
+ "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\nSize a column with its own `width`, or every column at once with `columns`,\na track list dealt out one track to a column in the order they are written,\nas `Table` deals it. A column's `width` wins in its place. **A table that\nserves its first page takes its widths from `columns`**: a server and a\nstylesheet can read the table's own attributes and not its columns', so the\nserved rows are laid out at the widths the table draws.\n\n**The columns are an import of their own.** A column is the Table family's\n`TableColumn`, which the data table does not register, so a page that writes\none imports the Table entry beside the data table:\n\n```js\nimport '@fusion.dev/helix/data-table'\nimport '@fusion.dev/helix/table'\n```\n\nIn development, a data table holding a column nobody registered says so once\nthe page has loaded, with the line to add.",
46801
46801
  "name": "HelixHeadlessDataTable",
46802
46802
  "cssProperties": [
46803
46803
  {
@@ -47151,6 +47151,16 @@
47151
47151
  "attribute": "child-field",
47152
47152
  "reflects": true
47153
47153
  },
47154
+ {
47155
+ "kind": "field",
47156
+ "name": "columns",
47157
+ "type": {
47158
+ "text": "string"
47159
+ },
47160
+ "default": "''",
47161
+ "description": "The column tracks, as a grid track list such as `2fr 1fr max-content`,\ndealt out one track to a column in the order the columns are written. A\ncolumn's own `width` wins in its place, and a column it does not reach\ntakes the track a column with no `width` takes.\n\n**The one track list a server can send.** A server rendering this element\nhas no columns to read a `width` from, and neither has a stylesheet laying\nout the rows a page served before the table upgrades, so a table sized here\nlays those rows out at the widths it draws.",
47162
+ "attribute": "columns"
47163
+ },
47154
47164
  {
47155
47165
  "kind": "field",
47156
47166
  "name": "defaultExpanded",
@@ -48225,7 +48235,7 @@
48225
48235
  "text": "string"
48226
48236
  },
48227
48237
  "privacy": "private",
48228
- "description": "The track list, from the columns if there are any.",
48238
+ "description": "The track list: each column's `width`, or its track in `columns`, or the\ntrack a column with neither takes.\n\nA render that knows no columns, on a server or hydrating what one sent,\nhas `columns` alone, and sends it as it is.",
48229
48239
  "readonly": true
48230
48240
  },
48231
48241
  {
@@ -50274,6 +50284,15 @@
50274
50284
  "description": "The field that holds a row's child rows, as an array. Set it, and `row-key`,\nand the grid becomes a tree grid.\n\nReflected, because the styled tier indents a tree grid's row headers by\nit. No default, so a table that sets none writes nothing onto its host.",
50275
50285
  "fieldName": "childField"
50276
50286
  },
50287
+ {
50288
+ "name": "columns",
50289
+ "type": {
50290
+ "text": "string"
50291
+ },
50292
+ "default": "''",
50293
+ "description": "The column tracks, as a grid track list such as `2fr 1fr max-content`,\ndealt out one track to a column in the order the columns are written. A\ncolumn's own `width` wins in its place, and a column it does not reach\ntakes the track a column with no `width` takes.\n\n**The one track list a server can send.** A server rendering this element\nhas no columns to read a `width` from, and neither has a stylesheet laying\nout the rows a page served before the table upgrades, so a table sized here\nlays those rows out at the widths it draws.",
50294
+ "fieldName": "columns"
50295
+ },
50277
50296
  {
50278
50297
  "name": "default-expanded",
50279
50298
  "type": {
@@ -162849,7 +162868,7 @@
162849
162868
  "text": "string"
162850
162869
  },
162851
162870
  "default": "''",
162852
- "description": "The column widths as one track list, written once on the table.\n\nWith `TableColumn` children, each track sizes the column in its place, a\nhidden column counted, so hiding one takes its track with it and the rest\nkeep theirs. The columns decide how many tracks there are and this list\nonly how wide: a track past the last column is dropped, and a column past\nthe last track shares what is left. With no columns declared it is the\nwhole track list. Tracks count as the grid counts them, so `minmax(0, 1fr)`\nis one and `repeat(2, 8rem)` is two, and one the grid would refuse leaves\nits column at the default rather than taking the table down to one column.\n\n**A column's own `width` wins over its track here.** The width is written\non the column it sizes, which is the more particular statement, and it is\nwhere a resize lands: a reader dragging a column's edge writes `width`, so\nwere this list to win, the drag would move the separator and leave the\ntrack where the list put it. This is the table's default for its columns,\nand each column may say otherwise.\n\n**It is also the only track list a server can send.** The shim has no tree\nto walk, so a render there knows of no columns and this attribute is the\nwhole answer: a table given one lays its grid out in the first paint, and a\ntable sized only by its columns is one track wide until it upgrades.\n\n**Data Table has none of this, and should not.** Its columns are its schema\nrather than an option, so there is always a column to write a `width` on\nand a list here would be a second way to say what that says. This table's\ncells are markup, and a table written as rows of cells with no column\ndeclared in it has nowhere else to be sized from.",
162871
+ "description": "The column widths as one track list, written once on the table.\n\nWith `TableColumn` children, each track sizes the column in its place, a\nhidden column counted, so hiding one takes its track with it and the rest\nkeep theirs. The columns decide how many tracks there are and this list\nonly how wide: a track past the last column is dropped, and a column past\nthe last track shares what is left. With no columns declared it is the\nwhole track list. Tracks count as the grid counts them, so `minmax(0, 1fr)`\nis one and `repeat(2, 8rem)` is two, and one the grid would refuse leaves\nits column at the default rather than taking the table down to one column.\n\n**A column's own `width` wins over its track here.** The width is written\non the column it sizes, which is the more particular statement, and it is\nwhere a resize lands: a reader dragging a column's edge writes `width`, so\nwere this list to win, the drag would move the separator and leave the\ntrack where the list put it. This is the table's default for its columns,\nand each column may say otherwise.\n\n**It is also the only track list a server can send.** The shim has no tree\nto walk, so a render there knows of no columns and this attribute is the\nwhole answer: a table given one lays its grid out in the first paint, and a\ntable sized only by its columns takes, until it upgrades, a track for each\ncolumn at the width a column with no `width` takes (`helix.css`).\n\nData Table takes the same list, for the same reason: a data table that\nserves its first page as rows is laid out by it before it upgrades.",
162853
162872
  "attribute": "columns"
162854
162873
  },
162855
162874
  {
@@ -164785,7 +164804,7 @@
164785
164804
  "text": "string"
164786
164805
  },
164787
164806
  "default": "''",
164788
- "description": "The column widths as one track list, written once on the table.\n\nWith `TableColumn` children, each track sizes the column in its place, a\nhidden column counted, so hiding one takes its track with it and the rest\nkeep theirs. The columns decide how many tracks there are and this list\nonly how wide: a track past the last column is dropped, and a column past\nthe last track shares what is left. With no columns declared it is the\nwhole track list. Tracks count as the grid counts them, so `minmax(0, 1fr)`\nis one and `repeat(2, 8rem)` is two, and one the grid would refuse leaves\nits column at the default rather than taking the table down to one column.\n\n**A column's own `width` wins over its track here.** The width is written\non the column it sizes, which is the more particular statement, and it is\nwhere a resize lands: a reader dragging a column's edge writes `width`, so\nwere this list to win, the drag would move the separator and leave the\ntrack where the list put it. This is the table's default for its columns,\nand each column may say otherwise.\n\n**It is also the only track list a server can send.** The shim has no tree\nto walk, so a render there knows of no columns and this attribute is the\nwhole answer: a table given one lays its grid out in the first paint, and a\ntable sized only by its columns is one track wide until it upgrades.\n\n**Data Table has none of this, and should not.** Its columns are its schema\nrather than an option, so there is always a column to write a `width` on\nand a list here would be a second way to say what that says. This table's\ncells are markup, and a table written as rows of cells with no column\ndeclared in it has nowhere else to be sized from.",
164807
+ "description": "The column widths as one track list, written once on the table.\n\nWith `TableColumn` children, each track sizes the column in its place, a\nhidden column counted, so hiding one takes its track with it and the rest\nkeep theirs. The columns decide how many tracks there are and this list\nonly how wide: a track past the last column is dropped, and a column past\nthe last track shares what is left. With no columns declared it is the\nwhole track list. Tracks count as the grid counts them, so `minmax(0, 1fr)`\nis one and `repeat(2, 8rem)` is two, and one the grid would refuse leaves\nits column at the default rather than taking the table down to one column.\n\n**A column's own `width` wins over its track here.** The width is written\non the column it sizes, which is the more particular statement, and it is\nwhere a resize lands: a reader dragging a column's edge writes `width`, so\nwere this list to win, the drag would move the separator and leave the\ntrack where the list put it. This is the table's default for its columns,\nand each column may say otherwise.\n\n**It is also the only track list a server can send.** The shim has no tree\nto walk, so a render there knows of no columns and this attribute is the\nwhole answer: a table given one lays its grid out in the first paint, and a\ntable sized only by its columns takes, until it upgrades, a track for each\ncolumn at the width a column with no `width` takes (`helix.css`).\n\nData Table takes the same list, for the same reason: a data table that\nserves its first page as rows is laid out by it before it upgrades.",
164789
164808
  "fieldName": "columns"
164790
164809
  },
164791
164810
  {
@@ -165893,6 +165912,46 @@
165893
165912
  }
165894
165913
  ]
165895
165914
  },
165915
+ {
165916
+ "kind": "javascript-module",
165917
+ "path": "src/table/tracks.ts",
165918
+ "declarations": [
165919
+ {
165920
+ "kind": "function",
165921
+ "name": "tracksOf",
165922
+ "return": {
165923
+ "type": {
165924
+ "text": "string[]"
165925
+ }
165926
+ },
165927
+ "parameters": [
165928
+ {
165929
+ "name": "list",
165930
+ "type": {
165931
+ "text": "string"
165932
+ }
165933
+ },
165934
+ {
165935
+ "name": "wanted",
165936
+ "type": {
165937
+ "text": "number"
165938
+ }
165939
+ }
165940
+ ],
165941
+ "description": "The first `wanted` tracks of a track list, one entry each, so every declared\ncolumn can take the one in its place.\n\nSplit on the spaces between tracks and never inside a function, so\n`minmax(0, 1fr)` stays one track. A `repeat()` with a count is that many\ntracks, written out; an automatic one names no count and yields none. Line\nnames go with the track after them.\n\nEverything above the split is a fact about a grid track list rather than\nabout a value list, which is why only the split itself is shared.\n\n**A track the grid would refuse yields nothing either**, where the platform\ncan say. One invalid track makes the whole `grid-template-columns` invalid,\nwhich a grid ignores in silence and draws as one column. That is the failure\nthat once had `columns` deprecated, a list of headings handed over as widths,\nand dealt out a track at a time it costs the one column its width and no\nmore."
165942
+ }
165943
+ ],
165944
+ "exports": [
165945
+ {
165946
+ "kind": "js",
165947
+ "name": "tracksOf",
165948
+ "declaration": {
165949
+ "name": "tracksOf",
165950
+ "module": "src/table/tracks.ts"
165951
+ }
165952
+ }
165953
+ ]
165954
+ },
165896
165955
  {
165897
165956
  "kind": "javascript-module",
165898
165957
  "path": "src/tabs/index.ts",
@@ -202555,6 +202614,6 @@
202555
202614
  ],
202556
202615
  "helix": {
202557
202616
  "package": "@fusion.dev/helix-headless",
202558
- "version": "0.184.0"
202617
+ "version": "0.185.0"
202559
202618
  }
202560
202619
  }
@@ -125,11 +125,12 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
125
125
  * `csv()` returns the result as text: every row that passes the filter, in the
126
126
  * order and the columns on screen. Saving the file is up to you.
127
127
  *
128
- * `DataTable` has no `columns` attribute. Each `TableColumn` is part of the
129
- * schema, so you size a column with its own `width`. `Table` has `columns`
130
- * because its cells are markup you write and it can have no columns at all.
131
- * Written on `DataTable`, `columns` has no effect, so watch for it when you
132
- * move a table from `Table` to `DataTable`.
128
+ * Size a column with its own `width`, or every column at once with `columns`,
129
+ * a track list dealt out one track to a column in the order they are written,
130
+ * as `Table` deals it. A column's `width` wins in its place. **A table that
131
+ * serves its first page takes its widths from `columns`**: a server and a
132
+ * stylesheet can read the table's own attributes and not its columns', so the
133
+ * served rows are laid out at the widths the table draws.
133
134
  *
134
135
  * **The columns are an import of their own.** A column is the Table family's
135
136
  * `TableColumn`, which the data table does not register, so a page that writes
@@ -275,6 +276,18 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
275
276
  * it. No default, so a table that sets none writes nothing onto its host.
276
277
  */
277
278
  childField?: string;
279
+ /**
280
+ * The column tracks, as a grid track list such as `2fr 1fr max-content`,
281
+ * dealt out one track to a column in the order the columns are written. A
282
+ * column's own `width` wins in its place, and a column it does not reach
283
+ * takes the track a column with no `width` takes.
284
+ *
285
+ * **The one track list a server can send.** A server rendering this element
286
+ * has no columns to read a `width` from, and neither has a stylesheet laying
287
+ * out the rows a page served before the table upgrades, so a table sized here
288
+ * lays those rows out at the widths it draws.
289
+ */
290
+ columns: string;
278
291
  /**
279
292
  * The keys of the rows open at the start, separated by commas. Used until
280
293
  * `expanded` is set.
@@ -786,7 +799,13 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
786
799
  private get shownFields();
787
800
  /** The columns reduced to what the ordering needs. */
788
801
  private get axes();
789
- /** The track list, from the columns if there are any. */
802
+ /**
803
+ * The track list: each column's `width`, or its track in `columns`, or the
804
+ * track a column with neither takes.
805
+ *
806
+ * A render that knows no columns, on a server or hydrating what one sent,
807
+ * has `columns` alone, and sends it as it is.
808
+ */
790
809
  private get template();
791
810
  /**
792
811
  * How many rows this draws before it is worth saying something, and why 2,000.
@@ -8,6 +8,7 @@ import { repeat } from 'lit/directives/repeat.js';
8
8
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
9
9
  import { html } from 'lit/static-html.js';
10
10
  import { edgeOf } from '../../table/edge.js';
11
+ import { tracksOf } from '../../table/tracks.js';
11
12
  import '../../checkbox/index.js';
12
13
  import '../../pagination/index.js';
13
14
  import { toggledOpen } from '../keys.js';
@@ -28,6 +29,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
28
29
  this.statusSlots = true;
29
30
  this.ascendingLabel = 'ascending';
30
31
  this.canceledLabel = 'Canceled';
32
+ this.columns = '';
31
33
  this.defaultExpanded = '';
32
34
  this.defaultFilter = '';
33
35
  this.defaultOrder = '';
@@ -573,11 +575,16 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
573
575
  }
574
576
  get template() {
575
577
  const declared = this.shownColumns;
576
- if (declared.length === 0) {
577
- return '';
578
- }
579
- const tracks = declared.map((column) => column.track).join(' ');
580
- return [...Array.from({ length: this.lead }, () => 'max-content'), tracks].join(' ');
578
+ const written = this.tableColumns;
579
+ const listed = tracksOf(this.columns, written.length);
580
+ const tracks = written.length === 0
581
+ ? this.columns
582
+ : declared
583
+ .map((column) => column.width ? column.track : listed[written.indexOf(column)] || column.track)
584
+ .join(' ');
585
+ return tracks
586
+ ? [...Array.from({ length: this.lead }, () => 'max-content'), tracks].join(' ')
587
+ : '';
581
588
  }
582
589
  static { this.COMFORTABLE = 2_000; }
583
590
  warnIfCrowded(drawn) {
@@ -1217,6 +1224,10 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
1217
1224
  const pagination = this.tag('pagination');
1218
1225
  const counted = this.mode === 'server' ? Math.max(this.total, available) : matched;
1219
1226
  const countKnown = counted > 0 || (this.sourceKnown && !serving);
1227
+ const held = serving &&
1228
+ this.paginated &&
1229
+ !countKnown &&
1230
+ (!this.sourceKnown || this.servedRows.length >= this.pageSize);
1220
1231
  this.counts = {
1221
1232
  columns: columns.length ? columns.length + this.lead : undefined,
1222
1233
  rows: countKnown ? counted + 1 + (this.moreDrawn ? 1 : 0) : undefined,
@@ -1231,9 +1242,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
1231
1242
  @scroll=${this.handleScroll}
1232
1243
  >
1233
1244
  <div part="head" role="row" aria-rowindex="1">
1234
- ${this.rowGrips && this.sourceKnown
1235
- ? this.renderGripHead(headStop && this.currentColumn === 0)
1236
- : nothing}${this.selectable && this.sourceKnown
1245
+ ${this.rowGrips ? this.renderGripHead(headStop && this.currentColumn === 0) : nothing}${this.selectable
1237
1246
  ? this.renderSelectAll(headStop && this.currentColumn === this.selectAt)
1238
1247
  : nothing}${this.assignsByName && !this.hydrating
1239
1248
  ? this.orderedColumns.map((_, index) => html `<slot name=${`column-${index + 1}`} @slotchange=${this.handleSlotChange}></slot>`)
@@ -1247,7 +1256,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
1247
1256
  ${this.renderMore(page)}${this.errorText === '' ? this.renderStatus(filled, 'gridcell') : this.renderError()}
1248
1257
  </div>
1249
1258
  ${this.errorText === '' ? this.renderLive(filled) : html `<span part="live" role="status">${this.errorText}</span>`}
1250
- <div part="footer">
1259
+ <div part="footer" ?data-held=${held}>
1251
1260
  <slot name="footer"></slot>
1252
1261
  ${this.paginated
1253
1262
  ? html `<${pagination}
@@ -1557,6 +1566,9 @@ __decorate([
1557
1566
  __decorate([
1558
1567
  property({ attribute: 'child-field', reflect: true })
1559
1568
  ], HelixHeadlessDataTable.prototype, "childField", void 0);
1569
+ __decorate([
1570
+ property()
1571
+ ], HelixHeadlessDataTable.prototype, "columns", void 0);
1560
1572
  __decorate([
1561
1573
  property({ attribute: 'default-expanded' })
1562
1574
  ], HelixHeadlessDataTable.prototype, "defaultExpanded", void 0);
@@ -243,13 +243,11 @@ export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
243
243
  * **It is also the only track list a server can send.** The shim has no tree
244
244
  * to walk, so a render there knows of no columns and this attribute is the
245
245
  * whole answer: a table given one lays its grid out in the first paint, and a
246
- * table sized only by its columns is one track wide until it upgrades.
246
+ * table sized only by its columns takes, until it upgrades, a track for each
247
+ * column at the width a column with no `width` takes (`helix.css`).
247
248
  *
248
- * **Data Table has none of this, and should not.** Its columns are its schema
249
- * rather than an option, so there is always a column to write a `width` on
250
- * and a list here would be a second way to say what that says. This table's
251
- * cells are markup, and a table written as rows of cells with no column
252
- * declared in it has nowhere else to be sized from.
249
+ * Data Table takes the same list, for the same reason: a data table that
250
+ * serves its first page as rows is laid out by it before it upgrades.
253
251
  */
254
252
  columns: string;
255
253
  /**
@@ -1,38 +1,12 @@
1
1
  import { __decorate } from "tslib";
2
- import { AriaForwardController, anchorAt, assignSlots, auditName, commaList, customElement, cycle, everyState, followLink, format, formatWords, HelixBeforeToggleEvent, HelixElement, HelixLoadMoreEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, HelixToggleEvent, inRowOrder, MixinCollection, onAndroid, parse, ReorderController, rangeAdd, reflectElements, requestChange, scrollingAncestor, sort, splitValues, toggleEvery, treeArrow, VIRTUAL_RULE, VirtualizeController, whenHydrated, words, } from '@fusion.dev/helix-core';
2
+ import { AriaForwardController, anchorAt, assignSlots, auditName, commaList, customElement, cycle, everyState, followLink, format, formatWords, HelixBeforeToggleEvent, HelixElement, HelixLoadMoreEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, HelixToggleEvent, inRowOrder, MixinCollection, onAndroid, parse, ReorderController, rangeAdd, reflectElements, requestChange, scrollingAncestor, sort, toggleEvery, treeArrow, VIRTUAL_RULE, VirtualizeController, whenHydrated, words, } from '@fusion.dev/helix-core';
3
3
  import { nothing } from 'lit';
4
4
  import { property, state } from 'lit/decorators.js';
5
5
  import { html } from 'lit/static-html.js';
6
6
  import '../../checkbox/index.js';
7
7
  import { edgeOf } from '../column/table-column.js';
8
8
  import { TableGridController } from '../grid-controller.js';
9
- const tracksOf = (list, wanted) => {
10
- const words = splitValues(list, ' ');
11
- const valid = (track) => typeof CSS === 'undefined' || CSS.supports('grid-template-columns', track);
12
- const tracks = [];
13
- let names = '';
14
- for (const one of words) {
15
- if (tracks.length >= wanted) {
16
- break;
17
- }
18
- if (one.startsWith('[')) {
19
- names += `${one} `;
20
- continue;
21
- }
22
- const repeat = /^repeat\(\s*(\d+)\s*,(.*)\)$/is.exec(one);
23
- if (repeat) {
24
- const inner = tracksOf(repeat[2] ?? '', wanted);
25
- for (let time = 0; time < Number(repeat[1]) && tracks.length < wanted; time += 1) {
26
- tracks.push(...inner.map((track, index) => (time === 0 && index === 0 ? names + track : track)));
27
- }
28
- }
29
- else if (!/^repeat\(/i.test(one)) {
30
- tracks.push(valid(names + one) ? names + one : '');
31
- }
32
- names = '';
33
- }
34
- return tracks.slice(0, wanted);
35
- };
9
+ import { tracksOf } from '../tracks.js';
36
10
  const SHORT = 32;
37
11
  const FLOOR = '14ch';
38
12
  const SAMPLE = 200;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The first `wanted` tracks of a track list, one entry each, so every declared
3
+ * column can take the one in its place.
4
+ *
5
+ * Split on the spaces between tracks and never inside a function, so
6
+ * `minmax(0, 1fr)` stays one track. A `repeat()` with a count is that many
7
+ * tracks, written out; an automatic one names no count and yields none. Line
8
+ * names go with the track after them.
9
+ *
10
+ * Everything above the split is a fact about a grid track list rather than
11
+ * about a value list, which is why only the split itself is shared.
12
+ *
13
+ * **A track the grid would refuse yields nothing either**, where the platform
14
+ * can say. One invalid track makes the whole `grid-template-columns` invalid,
15
+ * which a grid ignores in silence and draws as one column. That is the failure
16
+ * that once had `columns` deprecated, a list of headings handed over as widths,
17
+ * and dealt out a track at a time it costs the one column its width and no
18
+ * more.
19
+ */
20
+ export declare const tracksOf: (list: string, wanted: number) => string[];
@@ -0,0 +1,28 @@
1
+ import { splitValues } from '@fusion.dev/helix-core';
2
+ export const tracksOf = (list, wanted) => {
3
+ const words = splitValues(list, ' ');
4
+ const valid = (track) => typeof CSS === 'undefined' || CSS.supports('grid-template-columns', track);
5
+ const tracks = [];
6
+ let names = '';
7
+ for (const one of words) {
8
+ if (tracks.length >= wanted) {
9
+ break;
10
+ }
11
+ if (one.startsWith('[')) {
12
+ names += `${one} `;
13
+ continue;
14
+ }
15
+ const repeat = /^repeat\(\s*(\d+)\s*,(.*)\)$/is.exec(one);
16
+ if (repeat) {
17
+ const inner = tracksOf(repeat[2] ?? '', wanted);
18
+ for (let time = 0; time < Number(repeat[1]) && tracks.length < wanted; time += 1) {
19
+ tracks.push(...inner.map((track, index) => (time === 0 && index === 0 ? names + track : track)));
20
+ }
21
+ }
22
+ else if (!/^repeat\(/i.test(one)) {
23
+ tracks.push(valid(names + one) ? names + one : '');
24
+ }
25
+ names = '';
26
+ }
27
+ return tracks.slice(0, wanted);
28
+ };