@appius-fr/apx 2.6.2 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/APX.mjs +2 -0
- package/README.md +226 -203
- package/dist/2ab50e700c8fbddb45e0.svg +10 -0
- package/dist/2e967d8dd752e0bed703.svg +10 -0
- package/dist/5ddaeefe5dfbc8e09652.svg +7 -0
- package/dist/6dc2907ba3bbb232601d.svg +10 -0
- package/dist/6e1e61dfca176a885b8d.svg +3 -0
- package/dist/6f3a0a27a260bb2c221b.svg +9 -0
- package/dist/8b07a8bf719a38262b7d.svg +10 -0
- package/dist/APX.dev.mjs +1167 -227
- package/dist/APX.mjs +1 -1
- package/dist/APX.prod.mjs +1 -1
- package/dist/APX.standalone.js +1119 -75
- package/dist/APX.standalone.js.map +1 -1
- package/dist/bdfa755a1cdb872368c7.svg +3 -0
- package/dist/c9da177f7663f9fcd023.svg +10 -0
- package/dist/ce9ef5fceb78e17e68c9.svg +8 -0
- package/dist/ed5af5163957b04bc6cc.svg +7 -0
- package/modules/listen/README.md +242 -235
- package/modules/listen/listen.mjs +1 -3
- package/modules/scrollableTable/CHANGELOG.md +37 -0
- package/modules/scrollableTable/README.md +108 -0
- package/modules/scrollableTable/css/scrollableTable.css +67 -0
- package/modules/scrollableTable/scrollableTable.mjs +577 -0
- package/modules/toast/README.md +186 -153
- package/modules/tristate/CHANGELOG.md +34 -0
- package/modules/tristate/README.md +157 -94
- package/modules/tristate/assets/tristate-checked.svg +3 -0
- package/modules/tristate/assets/tristate-cross.svg +10 -0
- package/modules/tristate/assets/tristate-crossed.svg +3 -0
- package/modules/tristate/assets/tristate-indeterminate-dash.svg +9 -0
- package/modules/tristate/assets/tristate-tick.svg +10 -0
- package/modules/tristate/assets/tristate-unchecked.svg +7 -0
- package/modules/tristate/css/tristate.css +91 -24
- package/modules/tristate/tristate.mjs +292 -171
- package/package.json +5 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# APX Scrollable Table Module
|
|
2
|
+
|
|
3
|
+
Makes the **tbody** of a table scrollable while keeping **thead** and **tfoot** fixed and column alignment consistent. Uses CSS Grid with subgrid so no JavaScript is needed for width syncing or scrollbar compensation.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Modern browsers with **CSS subgrid** support (Chrome 117+, Safari 16+, Firefox 71+). See [caniuse](https://caniuse.com/css-subgrid).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
The module is part of APX. Ensure the scrollableTable augment is applied (see `APX.mjs`).
|
|
12
|
+
|
|
13
|
+
CSS is loaded automatically when the module is imported.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Init
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
APX('table.my-table').scrollableTable({ maxHeight: 300 });
|
|
21
|
+
// or with a CSS length
|
|
22
|
+
APX('table.my-table').scrollableTable({ maxHeight: '50vh' });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Calling `scrollableTable(options)` again with no options or an empty object does nothing (idempotent). Passing new options (e.g. a different `maxHeight`) updates the stored options and re-applies the layout.
|
|
26
|
+
|
|
27
|
+
### Refresh
|
|
28
|
+
|
|
29
|
+
After changing the table DOM (adding/removing rows, changing colspan/rowspan), re-apply the layout with the same options:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
APX('table.my-table').scrollableTable('refresh');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Options
|
|
36
|
+
|
|
37
|
+
| Option | Type | Default | Description |
|
|
38
|
+
| ---------------------- | ---------------- | --------- | --------------------------------------------------------------------------- |
|
|
39
|
+
| `maxHeight` | `number` or `string` | `'200px'` | Max height of the tbody (content can be shorter). Number = pixels; string = any CSS length (e.g. `'50vh'`). Ignored when `height` or `bodyHeightDynamic` is set. |
|
|
40
|
+
| `height` | `number` or `string` | — | Fixed height of the tbody (same syntax as `maxHeight`). When set, the tbody row always uses this height even with few rows. Ignored when `bodyHeightDynamic` is set. |
|
|
41
|
+
| `bodyHeightDynamic` | `object` | — | **Dynamic body height:** `{ get: (table) => number|string, useAs: 'height'\|'maxHeight', updateOn?: { scroll?, resize?, scrollOn?, resizeOn? } }`. Re-resolves height when scroll/resize sources fire. See [Dynamic body height](#dynamic-body-height) below. |
|
|
42
|
+
| `gridTemplateColumns` | `string` | — | CSS value for column tracks (e.g. `'1fr 2fr 1fr'`). When set, measured widths are skipped and this value is used as-is. |
|
|
43
|
+
| `gridTemplateRows` | `object` | — | Per-section row tracks: `{ thead?: string, tbody?: string, tfoot?: string }` (e.g. `{ tbody: 'auto 40px 40px' }`). When set for a section, measured row heights are skipped for that section. |
|
|
44
|
+
| `rowOverrides` | `object` | — | **Hybrid mode (rows):** per-section row index → CSS value. E.g. `{ tbody: { 0: '48px', 2: '2fr' } }` or `{ thead: ['50px', null] }`. Rows not overridden keep the measured height. Ignored when `gridTemplateRows` is set for that section. |
|
|
45
|
+
| `columnOverrides` | `object` or `array` | — | **Hybrid mode:** column index → CSS value. Columns not overridden keep the measured width. E.g. `{ 0: '2fr', 2: '80px' }` or `['2fr', null, '80px']`. Ignored when `gridTemplateColumns` is set. |
|
|
46
|
+
| `resizeObserver` | `boolean` | `false` | When `true`, observes the table size and re-applies column widths proportionally on resize. (Ignored when `gridTemplateColumns` is set.) |
|
|
47
|
+
|
|
48
|
+
### Dynamic body height
|
|
49
|
+
|
|
50
|
+
When `bodyHeightDynamic` is set, the tbody size is computed by `get(table)` (returning a number or CSS length string) and applied as `height` or `maxHeight` according to `useAs`. The value is re-resolved when the sources in `updateOn` fire, so the table can adapt to viewport resize or scrollbar appearance.
|
|
51
|
+
|
|
52
|
+
**updateOn** (optional) controls where we listen:
|
|
53
|
+
|
|
54
|
+
- **Booleans:** `scroll` (default `false`) / `resize` (default `true` when omitted). When `scroll` is `true`, we listen to document/window scroll. When `resize` is `true`, we listen to window resize and observe `document.documentElement` (so scrollbar appearance triggers an update). Set to `false` to disable.
|
|
55
|
+
- **Explicit sources:** `scrollOn` / `resizeOn` — arrays of targets. Use sentinels `'document'` (scroll) and `'window'` (resize), or pass elements (we listen to `scroll` on them, or observe them with `ResizeObserver` for resize). When provided (non-empty), they override the boolean defaults.
|
|
56
|
+
|
|
57
|
+
Example: viewport-based max-height with default resize (scrollbar pop + window resize):
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
APX('table.my-table').scrollableTable({
|
|
61
|
+
bodyHeightDynamic: {
|
|
62
|
+
get: (table) => window.innerHeight - table.getBoundingClientRect().top - 40,
|
|
63
|
+
useAs: 'maxHeight',
|
|
64
|
+
// updateOn omitted => scroll: false, resize: true (window + ResizeObserver on document)
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Example: also react to a scrollable parent:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
APX('table.my-table').scrollableTable({
|
|
73
|
+
bodyHeightDynamic: {
|
|
74
|
+
get: (table) => ...,
|
|
75
|
+
useAs: 'maxHeight',
|
|
76
|
+
updateOn: { scrollOn: ['document', document.querySelector('#main')], resizeOn: ['window'] }
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Cleanup:** Tables removed from the DOM are removed from the update set on the next scroll/resize (lazy cleanup via `isConnected`). No MutationObserver is used.
|
|
82
|
+
|
|
83
|
+
## CSS variables (override)
|
|
84
|
+
|
|
85
|
+
You can override row tracks in CSS via custom properties (e.g. on the table or a parent):
|
|
86
|
+
|
|
87
|
+
- `--apx-scrollable-thead-template-rows` — thead row tracks (e.g. `50px 50px`)
|
|
88
|
+
- `--apx-scrollable-tbody-template-rows` — tbody row tracks
|
|
89
|
+
- `--apx-scrollable-tfoot-template-rows` — tfoot row tracks
|
|
90
|
+
|
|
91
|
+
If set, they override the measured or default row heights for that section.
|
|
92
|
+
|
|
93
|
+
A dedicated column is reserved for the vertical scrollbar so it does not overlap the last data column. Its width is controlled by:
|
|
94
|
+
|
|
95
|
+
- `--apx-scrollable-gutter-width` — default `17px`. Set to `0` if you want the scrollbar to overlap (e.g. with thin scrollbars).
|
|
96
|
+
|
|
97
|
+
## Colspan and rowspan
|
|
98
|
+
|
|
99
|
+
Tables with **colspan** and **rowspan** are supported. The module sets explicit grid placement on each cell so thead, tbody, and tfoot stay aligned. Complex headers or merged cells in the body/foot work as expected.
|
|
100
|
+
|
|
101
|
+
## Edge cases
|
|
102
|
+
|
|
103
|
+
- **Empty tbody:** The layout is still applied; the tbody area is scrollable with no content.
|
|
104
|
+
- **No thead or no tfoot:** Tables with only thead+tbody or tbody+tfoot are supported; grid rows adjust automatically.
|
|
105
|
+
|
|
106
|
+
## Browser support
|
|
107
|
+
|
|
108
|
+
Requires **CSS subgrid**. No fallback is provided in this module; for legacy browsers, consider a different approach or a separate fallback implementation.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* APX Scrollable Table: scrollable tbody with fixed thead/tfoot and aligned columns (CSS Grid + subgrid)
|
|
2
|
+
Use !important so page styles (e.g. display: table) do not override the grid layout. */
|
|
3
|
+
|
|
4
|
+
/* --apx-scrollable-template-columns: set by JS (measured widths + gutter); fallback = equal columns + gutter */
|
|
5
|
+
/* --apx-scrollable-gutter-width: space for vertical scrollbar so it does not overlap the last column (set to 0 to allow overlap) */
|
|
6
|
+
/* --apx-scrollable-body-height: when class apx-scrollable-table--body-height is set, tbody row uses fixed height instead of max-height */
|
|
7
|
+
.apx-scrollable-table {
|
|
8
|
+
display: grid !important;
|
|
9
|
+
grid-template-columns: var(--apx-scrollable-template-columns, repeat(var(--apx-scrollable-cols, 3), minmax(0, 1fr)) minmax(var(--apx-scrollable-gutter-width, 17px), var(--apx-scrollable-gutter-width, 17px)));
|
|
10
|
+
grid-template-rows: auto var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px))) auto;
|
|
11
|
+
width: 100%;
|
|
12
|
+
table-layout: unset !important;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.apx-scrollable-table--body-height {
|
|
16
|
+
--apx-scrollable-body-row-size: var(--apx-scrollable-body-max-height, 200px);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Table with no tfoot: thead + tbody only */
|
|
20
|
+
.apx-scrollable-table:not(.apx-scrollable-table--has-tfoot) {
|
|
21
|
+
grid-template-rows: auto var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px)));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Table with no thead: tbody + tfoot only */
|
|
25
|
+
.apx-scrollable-table.apx-scrollable-table--no-thead {
|
|
26
|
+
grid-template-rows: var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px))) auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Table with neither thead nor tfoot: tbody only */
|
|
30
|
+
.apx-scrollable-table.apx-scrollable-table--no-thead:not(.apx-scrollable-table--has-tfoot) {
|
|
31
|
+
grid-template-rows: var(--apx-scrollable-body-row-size, fit-content(var(--apx-scrollable-body-max-height, 200px)));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* --apx-scrollable-*-template-rows: set by JS (measured heights) or override in CSS / via options */
|
|
35
|
+
.apx-scrollable-table > thead,
|
|
36
|
+
.apx-scrollable-table > tbody,
|
|
37
|
+
.apx-scrollable-table > tfoot {
|
|
38
|
+
display: grid !important;
|
|
39
|
+
grid-template-columns: subgrid;
|
|
40
|
+
grid-column: 1 / -1;
|
|
41
|
+
min-height: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.apx-scrollable-table > thead {
|
|
45
|
+
grid-template-rows: var(--apx-scrollable-thead-template-rows, repeat(var(--apx-scrollable-thead-rows, 1), auto));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.apx-scrollable-table > tbody {
|
|
49
|
+
grid-template-rows: var(--apx-scrollable-tbody-template-rows, repeat(var(--apx-scrollable-tbody-rows, 1), auto));
|
|
50
|
+
overflow: auto;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.apx-scrollable-table > tfoot {
|
|
54
|
+
grid-template-rows: var(--apx-scrollable-tfoot-template-rows, repeat(var(--apx-scrollable-tfoot-rows, 1), auto));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.apx-scrollable-table > thead > tr,
|
|
58
|
+
.apx-scrollable-table > tbody > tr,
|
|
59
|
+
.apx-scrollable-table > tfoot > tr {
|
|
60
|
+
display: contents !important;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.apx-scrollable-table th,
|
|
64
|
+
.apx-scrollable-table td {
|
|
65
|
+
min-width: 0;
|
|
66
|
+
box-sizing: border-box;
|
|
67
|
+
}
|