@excom/data-table 0.1.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 (38) hide show
  1. package/.rush/temp/chunked-rush-logs/data-table.apply-exports.chunks.jsonl +1 -0
  2. package/.rush/temp/chunked-rush-logs/data-table.build_docs.chunks.jsonl +1 -0
  3. package/.rush/temp/chunked-rush-logs/data-table.build_package-metas.chunks.jsonl +1 -0
  4. package/.rush/temp/operation/apply-exports/all.log +1 -0
  5. package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
  6. package/.rush/temp/operation/apply-exports/state.json +3 -0
  7. package/.rush/temp/operation/build_docs/all.log +1 -0
  8. package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
  9. package/.rush/temp/operation/build_docs/state.json +3 -0
  10. package/.rush/temp/operation/build_package-metas/all.log +1 -0
  11. package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
  12. package/.rush/temp/operation/build_package-metas/state.json +3 -0
  13. package/.rush/temp/shrinkwrap-deps.json +3 -0
  14. package/config/rig.json +5 -0
  15. package/data-table.ts +396 -0
  16. package/data-th.ts +49 -0
  17. package/index.css +5 -0
  18. package/index.ts +23 -0
  19. package/package.json +44 -0
  20. package/rush-logs/data-table.apply-exports.cache.log +1 -0
  21. package/rush-logs/data-table.apply-exports.log +1 -0
  22. package/rush-logs/data-table.build_docs.cache.log +1 -0
  23. package/rush-logs/data-table.build_docs.log +1 -0
  24. package/rush-logs/data-table.build_package-metas.cache.log +1 -0
  25. package/rush-logs/data-table.build_package-metas.log +1 -0
  26. package/src/data-table.css +124 -0
  27. package/support/custom-elements.json +366 -0
  28. package/support/demos/filter.html +67 -0
  29. package/support/demos/simple.html +14 -0
  30. package/support/dist-docs/data-table.md +245 -0
  31. package/support/dist-docs/data-th.md +29 -0
  32. package/support/docs/INTERNAL.md +7 -0
  33. package/support/docs/README.md +74 -0
  34. package/support/package-meta.json +280 -0
  35. package/support/tests/data-table.test.ts +704 -0
  36. package/support/tests/filter.view.test.ts +33 -0
  37. package/support/tests/simple.view.test.ts +31 -0
  38. package/tsconfig.json +5 -0
@@ -0,0 +1,245 @@
1
+ # data-table
2
+
3
+ Sortable, filterable tables from plain custom tags — one behavior owner
4
+ (`<data-table>` + `<data-th>`), everything else is CSS.
5
+
6
+
7
+ ```html
8
+ <data-table>
9
+ <data-thead>
10
+ <data-tr>
11
+ <data-th column-type="string" sort-direction="asc">Name</data-th>
12
+ <data-th column-type="number">Age</data-th>
13
+ </data-tr>
14
+ </data-thead>
15
+ <data-tbody>
16
+ <data-tr><data-td>Beatrice</data-td><data-td>44</data-td></data-tr>
17
+ <data-tr><data-td>Cynthia</data-td><data-td>41</data-td></data-tr>
18
+ <data-tr><data-td>Beau</data-td><data-td>29</data-td></data-tr>
19
+ <data-tr><data-td>Adam</data-td><data-td>36</data-td></data-tr>
20
+ </data-tbody>
21
+ </data-table>
22
+ ```
23
+
24
+
25
+ ## Features
26
+
27
+ - **Sort** Click a `<data-th>` to visually sort by string, number, or date
28
+ - **Filter** `filter-value` hides non-matching rows
29
+ - **Export** The `--export` command downloads visible / all rows as CSV / JSON
30
+ - **DOM-stable** Sort / filter via CSS only. Does not conflict with DOM owners, such as Quark.
31
+ - **Bindable counts** `.provision` is `{ totalRows, visibleRows, sortColumnIndex, sortDirection, filterValue }` — a "12 of 40 rows" readout is one Quark rule
32
+ - **Plain structural tags** `<data-thead>` / `<data-tbody>` / `<data-tr>` /
33
+ `<data-td>` are CSS-only — no registration cost
34
+
35
+ ## Installation
36
+
37
+
38
+ `@excom/data-table` v0.1.0
39
+
40
+ ```bash
41
+ pnpm add @excom/data-table
42
+ ```
43
+
44
+ ```bash
45
+ npm install @excom/data-table
46
+ ```
47
+
48
+ ```bash
49
+ yarn add @excom/data-table
50
+ ```
51
+
52
+ ### Import
53
+
54
+ ```ts
55
+ import "@excom/data-table";
56
+ ```
57
+
58
+
59
+
60
+ ## Usage
61
+
62
+ Only `<data-table>` and `<data-th>` are registered custom elements.
63
+ `<data-thead>`, `<data-tbody>`, `<data-tr>`, `<data-td>`, `<data-tfoot>`, and `<data-tf>` are plain tags — this package's CSS styles them as a table (or apply the equivalent `.tag-data-*` classes).
64
+
65
+ Sort and filter are visual only (CSS `order` / `display`).
66
+ Row nodes never move or leave the DOM, so Quark bindings and `iterate()` tables keep working.
67
+
68
+ ```html
69
+ <data-table>
70
+ <data-thead>
71
+ <data-tr>
72
+ <data-th column-type="string" sort-direction="asc">Name</data-th>
73
+ <data-th column-type="number">Age</data-th>
74
+ </data-tr>
75
+ </data-thead>
76
+ <data-tbody>
77
+ <data-tr><data-td>Adam</data-td><data-td>36</data-td></data-tr>
78
+ <data-tr><data-td>Beau</data-td><data-td>29</data-td></data-tr>
79
+ </data-tbody>
80
+ </data-table>
81
+ ```
82
+
83
+ `<data-tbody>` is required — sorting and filtering both operate on its
84
+ `<data-tr>` children.
85
+
86
+ `.provision` reports the row counts and the active sort / filter, recomputed after connect, after a sort, and after every filter change.
87
+ Read it from a rule matching the table:
88
+
89
+ ```quark
90
+ data-table {
91
+ $visible: prop("provision").visibleRows;
92
+ $total: prop("provision").totalRows;
93
+ [bind-count] { content: "#{$visible} of #{$total} rows"; }
94
+ }
95
+ ```
96
+
97
+ ### API Reference
98
+
99
+
100
+ #### Attributes
101
+
102
+ | Name | Surface | Type | Default | Values | Description |
103
+ | --- | --- | --- | --- | --- | --- |
104
+ | `filter-value` | option | `string` | | | Hides `data-tr` rows (via `--data-tr-display: none`) whose text content doesn't include this value. Case-insensitive unless `filter-casing` is set. Unset / empty clears the filter. Rows stay in the DOM so Quark bindings survive. |
105
+ | `filter-casing` | option | `boolean` | | | Match `filter-value` case-sensitively instead of the default case-insensitive comparison. |
106
+
107
+ #### Provision
108
+
109
+ | Name | Type | Description |
110
+ | --- | --- | --- |
111
+ | `provision` | `DataTableProvision` (`{ totalRows: number; visibleRows: number; sortColumnIndex: number \| null; sortDirection: "asc" \| "desc" \| null; filterValue: string \| null; }`) | `{ totalRows, visibleRows, sortColumnIndex, sortDirection, filterValue }` — recomputed after connect, after the `data-table-sort` default action, and after every filter change. Not reflected as an attribute. |
112
+
113
+ #### Recognized Elements
114
+
115
+ | Relationship | Selector | Required | Description |
116
+ | --- | --- | --- | --- |
117
+ | `data-th` | descendant | yes | Sortable column header. Clicking toggles its `sort-direction` and fires `data-th-sort`, which becomes the active column. |
118
+ | `data-tbody` | descendant | yes | Required row container. Sorting and filtering both operate on its `data-tr` children. |
119
+ | `data-tr` | descendant | yes | Row, direct child of `data-tbody`. Gets `--data-tr-order` on sort and `--data-tr-display` on filter. DOM order is unchanged. |
120
+ | `data-td` | descendant | yes | Cell within a `data-tr`, read as sortable / export cell content. |
121
+
122
+ #### Fires
123
+
124
+ | Name | Type | Description |
125
+ | --- | --- | --- |
126
+ | `data-table-sort` | `DataTableSortEvent` (`CustomEvent & { type: "data-table-sort"; detail: { sortDirection: "asc" \| "desc"; columnType: "string" \| "number" \| "date"; columnIndex: number; sortFn: (a: string, b: string) => number; rows: HTMLElement[]; }; bubbles: true; cancelable: true; composed: true }`) | Cancelable. Dispatched when the active sort column / direction changes: on connect (if a `data-th` already has `sort-direction`) and after every `data-th-sort`. Call `preventDefault()` to take over sorting yourself. |
127
+
128
+ #### Listens for
129
+
130
+ | Name | Type | Description |
131
+ | --- | --- | --- |
132
+ | `data-th-sort` | `DataThSortEvent` (`CustomEvent & { type: "data-th-sort"; detail: void; bubbles: true; cancelable: true; composed: true }`) | Bubbled up from a descendant `data-th` when its `sort-direction` changes. Sets that header as the active sort column (clearing `sort-direction` from the previously active one) and emits `data-table-sort`. |
133
+
134
+ #### Commands
135
+
136
+ | Command | Action |
137
+ | --- | --- |
138
+ | `--export` | Builds a file from the table's `data-tr` / `data-td` / `data-th` text content and downloads it. Options are `data-*` on the invoker: `data-file-type` (`csv`, the default, or `json`), `data-file-name` (default `export_table_<locale-date>`), and `data-full` to download every row in DOM order instead of only the visible rows in visual sort order. Filtering needs no command: write `filter-value` / `filter-casing`. |
139
+
140
+ #### Default actions
141
+
142
+ | Event | Default behavior (unless preventDefault() is called) |
143
+ | --- | --- |
144
+ | `data-table-sort` | Sorts `event.detail.rows` by `columnIndex` with `sortFn` and sets `--data-tr-order` on each row (visual CSS `order` — DOM order is unchanged). |
145
+
146
+ #### CSS Custom Properties
147
+
148
+ | Name | Syntax | Default | Description |
149
+ | --- | --- | --- | --- |
150
+ | `--data-table-cols` | `<integer>` | `1` | Column count for shared subgrid tracks. Auto-detected from the widest row; set on the host to override. |
151
+
152
+ #### CSS Aliases
153
+
154
+ | Alias | Kind | Matches | Description |
155
+ | --- | --- | --- | --- |
156
+ | `:--data-table` | element | `data-table`, `.tag-data-table` | |
157
+ | `:--data-thead` | element | `data-thead`, `.tag-data-thead` | |
158
+ | `:--data-tbody` | element | `data-tbody`, `.tag-data-tbody` | |
159
+ | `:--data-tfoot` | element | `data-tfoot`, `.tag-data-tfoot` | |
160
+ | `:--data-tr` | element | `data-tr`, `.tag-data-tr` | |
161
+ | `:--data-td` | element | `data-td`, `.tag-data-td` | |
162
+ | `:--data-tf` | element | `data-tf`, `.tag-data-tf` | |
163
+
164
+
165
+
166
+ ### Examples
167
+
168
+ #### Filter rows + export as CSV
169
+
170
+ Filtering is State: write `filter-value` / `filter-casing` on the table — here a Quark `@on input` block copies the search field into them. Matching is case-insensitive unless `filter-casing` is set.
171
+
172
+ Invoke `--export` on the table (`<button command="--export" commandfor="…">`) to download its visible rows (visual sort order). The button's `data-file-type` is `csv` (default) or `json`; `data-file-name` sets the download name; `data-full` downloads every row in DOM order, regardless of filtering / sorting.
173
+
174
+ The first export button is the happy path (the table as you see it, including active filter / sort). The form below it writes `data-file-type` / `data-file-name` / `data-full` onto its button.
175
+
176
+
177
+ ```html
178
+ <div>
179
+ <quark-sheet>
180
+ :scope {
181
+ @on input (target: "form[data-filter]") {
182
+ data-table { filter-value: target.elements.filterValue.value; }
183
+ }
184
+ @on change (target: "form[data-filter]") {
185
+ data-table { filter-casing: target.elements.filterCasing.checked; }
186
+ }
187
+ @on change (target: "form[data-export]") {
188
+ form[data-export] [command="--export"] {
189
+ data-file-type: target.elements.fileType.value;
190
+ data-file-name: target.elements.fileName.value;
191
+ data-full: target.elements.full.checked;
192
+ }
193
+ }
194
+ }
195
+ </quark-sheet>
196
+ <form data-filter>
197
+ <fieldset role="group">
198
+ <input name="filterValue" placeholder="Filter table…" />
199
+ <label>
200
+ Case-sensitive
201
+ <input name="filterCasing" role="switch" type="checkbox" />
202
+ </label>
203
+ </fieldset>
204
+ </form>
205
+ <data-table id="demo-data-table-filter">
206
+ <data-thead>
207
+ <data-tr>
208
+ <data-th column-type="string">Name</data-th>
209
+ <data-th column-type="number">Age</data-th>
210
+ </data-tr>
211
+ </data-thead>
212
+ <data-tbody>
213
+ <data-tr><data-td>Beatrice</data-td><data-td>44</data-td></data-tr>
214
+ <data-tr><data-td>Cynthia</data-td><data-td>41</data-td></data-tr>
215
+ <data-tr><data-td>Beau</data-td><data-td>29</data-td></data-tr>
216
+ <data-tr><data-td>Adam</data-td><data-td>36</data-td></data-tr>
217
+ </data-tbody>
218
+ </data-table>
219
+ <hr />
220
+ <button type="button" command="--export" commandfor="demo-data-table-filter">
221
+ Export as-is
222
+ </button>
223
+ <hr />
224
+ <form data-export class="tag-article">
225
+ <header>
226
+ <h4>Export with options</h4>
227
+ </header>
228
+ <label>
229
+ <select name="fileType">
230
+ <option value="csv" selected>CSV</option>
231
+ <option value="json">JSON</option>
232
+ </select>
233
+ </label>
234
+ <label>
235
+ File name
236
+ <input name="fileName" placeholder="File name" />
237
+ </label>
238
+ <label>
239
+ <input name="full" type="checkbox" role="switch" />
240
+ Full table (ignores active filter/sort)
241
+ </label>
242
+ <button type="button" command="--export" commandfor="demo-data-table-filter">Export</button>
243
+ </form>
244
+ </div>
245
+ ```
@@ -0,0 +1,29 @@
1
+ # `<data-th>`
2
+
3
+ > Sortable column header — click toggles sort direction.
4
+
5
+ **Tag:** `<data-th>`
6
+
7
+ ## API
8
+
9
+ ### Attributes
10
+
11
+ | Name | Surface | Type | Default | Values | Description |
12
+ | --- | --- | --- | --- | --- | --- |
13
+ | `column-type` | option | `string` | | `"string"` \| `"number"` \| `"date"` | Sort comparator to use for this column's cell values. `data-table` treats `null` as "string". |
14
+ | `sort-direction` | hybrid | `string` | | `"asc"` \| `"desc"` | Current sort direction. A click toggles between `asc` / `desc`; setting it (by any means) fires `data-th-sort`. Only one `data-th` per table should carry this at a time — the parent `<data-table>` clears the previously active header when a new one is set. |
15
+
16
+ ### Fires
17
+
18
+ | Name | Type | Description |
19
+ | --- | --- | --- |
20
+ | `data-th-sort` | `DataThSortEvent` (`CustomEvent & { type: "data-th-sort"; detail: void; bubbles: true; cancelable: true; composed: true }`) | Dispatched whenever `sort-direction` is set, whether by a click or programmatically. Bubbles to the parent `<data-table>`. |
21
+
22
+ ### CSS Aliases
23
+
24
+ | Alias | Kind | Matches | Description |
25
+ | --- | --- | --- | --- |
26
+ | `:--data-th` | element | `data-th`, `.tag-data-th` | |
27
+ | `:--data-th--sort` | state | `:is(:--data-th)` | |
28
+ | `:--data-th--sort-asc` | state | `[sort-direction="asc"]`, `[aria-sort="ascending"]` | |
29
+ | `:--data-th--sort-desc` | state | `[sort-direction="desc"]`, `[aria-sort="descending"]` | |
@@ -0,0 +1,7 @@
1
+ Leftover TODOs:
2
+
3
+ - Pagination. Not implemented — would need its own attribute(s)
4
+ (e.g. `page-size` / `page`) and likely a `data-tfoot` slot for controls.
5
+ - `column-type` only supports `string` | `number` | `date` (see
6
+ `CELL_SORTER_MAP` in `data-table.ts`). Don't add `boolean` without a
7
+ comparator.
@@ -0,0 +1,74 @@
1
+ # data-table
2
+
3
+ Sortable, filterable tables from plain custom tags — one behavior owner
4
+ (`<data-table>` + `<data-th>`), everything else is CSS.
5
+
6
+ <include-content data-demo="simple"></include-content>
7
+
8
+ ## Features
9
+
10
+ - **Sort** Click a `<data-th>` to visually sort by string, number, or date
11
+ - **Filter** `filter-value` hides non-matching rows
12
+ - **Export** The `--export` command downloads visible / all rows as CSV / JSON
13
+ - **DOM-stable** Sort / filter via CSS only. Does not conflict with DOM owners, such as Quark.
14
+ - **Bindable counts** `.provision` is `{ totalRows, visibleRows, sortColumnIndex, sortDirection, filterValue }` — a "12 of 40 rows" readout is one Quark rule
15
+ - **Plain structural tags** `<data-thead>` / `<data-tbody>` / `<data-tr>` /
16
+ `<data-td>` are CSS-only — no registration cost
17
+
18
+ ## Installation
19
+
20
+ <include-content is-active template-ref="/views/install-section/install-section.html"></include-content>
21
+
22
+ ## Usage
23
+
24
+ Only `<data-table>` and `<data-th>` are registered custom elements.
25
+ `<data-thead>`, `<data-tbody>`, `<data-tr>`, `<data-td>`, `<data-tfoot>`, and `<data-tf>` are plain tags — this package's CSS styles them as a table (or apply the equivalent `.tag-data-*` classes).
26
+
27
+ Sort and filter are visual only (CSS `order` / `display`).
28
+ Row nodes never move or leave the DOM, so Quark bindings and `iterate()` tables keep working.
29
+
30
+ ```html
31
+ <data-table>
32
+ <data-thead>
33
+ <data-tr>
34
+ <data-th column-type="string" sort-direction="asc">Name</data-th>
35
+ <data-th column-type="number">Age</data-th>
36
+ </data-tr>
37
+ </data-thead>
38
+ <data-tbody>
39
+ <data-tr><data-td>Adam</data-td><data-td>36</data-td></data-tr>
40
+ <data-tr><data-td>Beau</data-td><data-td>29</data-td></data-tr>
41
+ </data-tbody>
42
+ </data-table>
43
+ ```
44
+
45
+ `<data-tbody>` is required — sorting and filtering both operate on its
46
+ `<data-tr>` children.
47
+
48
+ `.provision` reports the row counts and the active sort / filter, recomputed after connect, after a sort, and after every filter change.
49
+ Read it from a rule matching the table:
50
+
51
+ ```quark
52
+ data-table {
53
+ $visible: prop("provision").visibleRows;
54
+ $total: prop("provision").totalRows;
55
+ [bind-count] { content: "#{$visible} of #{$total} rows"; }
56
+ }
57
+ ```
58
+
59
+ ### API Reference
60
+
61
+ <include-content is-active template-ref="/views/api-reference/api-reference.html"></include-content>
62
+
63
+ ### Examples
64
+
65
+ #### Filter rows + export as CSV
66
+
67
+ Filtering is State: write `filter-value` / `filter-casing` on the table — here a Quark `@on input` block copies the search field into them. Matching is case-insensitive unless `filter-casing` is set.
68
+
69
+ Invoke `--export` on the table (`<button command="--export" commandfor="…">`) to download its visible rows (visual sort order). The button's `data-file-type` is `csv` (default) or `json`; `data-file-name` sets the download name; `data-full` downloads every row in DOM order, regardless of filtering / sorting.
70
+
71
+ The first export button is the happy path (the table as you see it, including active filter / sort). The form below it writes `data-file-type` / `data-file-name` / `data-full` onto its button.
72
+
73
+ <include-content data-demo="filter"></include-content>
74
+