@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.
Files changed (36) hide show
  1. package/APX.mjs +2 -0
  2. package/README.md +226 -203
  3. package/dist/2ab50e700c8fbddb45e0.svg +10 -0
  4. package/dist/2e967d8dd752e0bed703.svg +10 -0
  5. package/dist/5ddaeefe5dfbc8e09652.svg +7 -0
  6. package/dist/6dc2907ba3bbb232601d.svg +10 -0
  7. package/dist/6e1e61dfca176a885b8d.svg +3 -0
  8. package/dist/6f3a0a27a260bb2c221b.svg +9 -0
  9. package/dist/8b07a8bf719a38262b7d.svg +10 -0
  10. package/dist/APX.dev.mjs +1167 -227
  11. package/dist/APX.mjs +1 -1
  12. package/dist/APX.prod.mjs +1 -1
  13. package/dist/APX.standalone.js +1119 -75
  14. package/dist/APX.standalone.js.map +1 -1
  15. package/dist/bdfa755a1cdb872368c7.svg +3 -0
  16. package/dist/c9da177f7663f9fcd023.svg +10 -0
  17. package/dist/ce9ef5fceb78e17e68c9.svg +8 -0
  18. package/dist/ed5af5163957b04bc6cc.svg +7 -0
  19. package/modules/listen/README.md +242 -235
  20. package/modules/listen/listen.mjs +1 -3
  21. package/modules/scrollableTable/CHANGELOG.md +37 -0
  22. package/modules/scrollableTable/README.md +108 -0
  23. package/modules/scrollableTable/css/scrollableTable.css +67 -0
  24. package/modules/scrollableTable/scrollableTable.mjs +577 -0
  25. package/modules/toast/README.md +186 -153
  26. package/modules/tristate/CHANGELOG.md +34 -0
  27. package/modules/tristate/README.md +157 -94
  28. package/modules/tristate/assets/tristate-checked.svg +3 -0
  29. package/modules/tristate/assets/tristate-cross.svg +10 -0
  30. package/modules/tristate/assets/tristate-crossed.svg +3 -0
  31. package/modules/tristate/assets/tristate-indeterminate-dash.svg +9 -0
  32. package/modules/tristate/assets/tristate-tick.svg +10 -0
  33. package/modules/tristate/assets/tristate-unchecked.svg +7 -0
  34. package/modules/tristate/css/tristate.css +91 -24
  35. package/modules/tristate/tristate.mjs +292 -171
  36. package/package.json +5 -1
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
2
+ <rect width="32" height="32" fill="#0654ba" />
3
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
2
+ <path
3
+ d="M6 17L12 23L26 9"
4
+ fill="none"
5
+ stroke="#000"
6
+ stroke-width="3"
7
+ stroke-linecap="round"
8
+ stroke-linejoin="round"
9
+ />
10
+ </svg>
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
2
+ <mask id="cross-cutout">
3
+ <rect width="32" height="32" fill="#fff" />
4
+ <path d="M8 8L24 24" stroke="#000" stroke-width="2" />
5
+ <path d="M24 8L8 24" stroke="#000" stroke-width="2" />
6
+ </mask>
7
+ <rect width="32" height="32" fill="#f00" mask="url(#cross-cutout)" />
8
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
2
+ <mask id="frame-cutout">
3
+ <rect width="32" height="32" fill="#fff" />
4
+ <rect x="3" y="3" width="26" height="26" rx="3" ry="3" fill="#000" />
5
+ </mask>
6
+ <rect width="32" height="32" fill="#cccccc" mask="url(#frame-cutout)" />
7
+ </svg>
@@ -1,235 +1,242 @@
1
- # APX Listen Module
2
-
3
- The `listen` module provides a powerful event handling system for APX objects. It enables event delegation, multiple callback chaining, debouncing via timeouts, and manual event triggering.
4
-
5
- ---
6
-
7
- ## Installation
8
-
9
- The `listen` module is automatically included when you import APX. It augments all APX objects with the `.listen()` and `.trigger()` methods.
10
-
11
- ```javascript
12
- import APX from './APX.mjs';
13
- // .listen() and .trigger() are now available on all APX objects
14
- ```
15
-
16
- ---
17
-
18
- ## Usage
19
-
20
- ### Basic Event Listening
21
-
22
- ```javascript
23
- // Listen to a single event type
24
- APX('.my-button').listen('click').do((event) => {
25
- console.log('Button clicked!', event.target);
26
- });
27
-
28
- // Listen to multiple event types
29
- APX('.my-input').listen(['input', 'change']).do((event) => {
30
- console.log('Input changed:', event.target.value);
31
- });
32
- ```
33
-
34
- ### Event Delegation
35
-
36
- Use event delegation to handle events on dynamically added elements:
37
-
38
- ```javascript
39
- // Listen for clicks on any button inside the container (even if added later)
40
- APX('#container').listen('click', '.button').do((event) => {
41
- console.log('Button clicked:', event.target);
42
- });
43
- ```
44
-
45
- ### Multiple Callbacks (Chaining)
46
-
47
- Chain multiple callbacks that execute sequentially:
48
-
49
- ```javascript
50
- APX('.my-button').listen('click').do((event) => {
51
- console.log('First callback');
52
- return fetch('/api/data'); // Can return promises
53
- }).do((event) => {
54
- console.log('Second callback (runs after first completes)');
55
- }).do((event) => {
56
- console.log('Third callback');
57
- });
58
- ```
59
-
60
- ### Debouncing with Timeout
61
-
62
- Add a delay before executing callbacks:
63
-
64
- ```javascript
65
- // Wait 300ms after the last event before executing callbacks
66
- APX('.search-input').listen('input', { timeout: 300 }).do((event) => {
67
- console.log('Searching for:', event.target.value);
68
- // This will only fire 300ms after the user stops typing
69
- });
70
- ```
71
-
72
- ### Manual Event Triggering
73
-
74
- Manually trigger events and their registered callbacks:
75
-
76
- ```javascript
77
- // Trigger a click event
78
- APX('.my-button').trigger('click');
79
-
80
- // Or trigger with an actual Event object
81
- const customEvent = new CustomEvent('myevent', { detail: { data: 'value' } });
82
- APX('.my-element').trigger(customEvent);
83
- ```
84
-
85
- ---
86
-
87
- ## API
88
-
89
- ### `.listen(eventTypes, selector?, options?)`
90
-
91
- Adds event listeners to the APX-wrapped elements.
92
-
93
- **Parameters:**
94
- - `eventTypes` (string | string[]): The event type(s) to listen for (e.g., `'click'`, `['input', 'change']`)
95
- - `selector` (string, optional): CSS selector for event delegation
96
- - `options` (object, optional): Configuration options
97
- - `timeout` (number): Delay in milliseconds before executing callbacks (default: `0`)
98
-
99
- **Returns:** An object with a `.do()` method for chaining callbacks.
100
-
101
- **Example:**
102
- ```javascript
103
- APX('.element')
104
- .listen('click', '.button', { timeout: 100 })
105
- .do((event) => { /* callback 1 */ })
106
- .do((event) => { /* callback 2 */ });
107
- ```
108
-
109
- ### `.do(callback)`
110
-
111
- Adds a callback function to the event listener chain. Callbacks execute sequentially, and each callback can return a Promise to delay the next callback.
112
-
113
- **Parameters:**
114
- - `callback` (Function): The callback function that receives the event object
115
-
116
- **Returns:** The same object (for chaining)
117
-
118
- **Example:**
119
- ```javascript
120
- APX('.button').listen('click').do((event) => {
121
- // Callback is bound to the matched element
122
- console.log(this); // The matched element
123
- return fetch('/api').then(res => res.json());
124
- }).do((event) => {
125
- // This runs after the fetch completes
126
- console.log('Fetch completed');
127
- });
128
- ```
129
-
130
- ### `.trigger(event)`
131
-
132
- Manually triggers an event on all wrapped elements and executes registered callbacks.
133
-
134
- **Parameters:**
135
- - `event` (string | Event): Event type string or an Event object
136
-
137
- **Example:**
138
- ```javascript
139
- // Trigger with string
140
- APX('.button').trigger('click');
141
-
142
- // Trigger with Event object
143
- const event = new CustomEvent('custom', { detail: { foo: 'bar' } });
144
- APX('.element').trigger(event);
145
- ```
146
-
147
- ---
148
-
149
- ## Examples
150
-
151
- ### Form Validation with Debouncing
152
-
153
- ```javascript
154
- APX('#email-input').listen('input', { timeout: 500 }).do((event) => {
155
- const email = event.target.value;
156
- if (email.includes('@')) {
157
- validateEmail(email);
158
- }
159
- });
160
- ```
161
-
162
- ### Dynamic Content with Event Delegation
163
-
164
- ```javascript
165
- // Handle clicks on buttons added dynamically
166
- APX('#dynamic-container').listen('click', '.action-button').do((event) => {
167
- const button = event.target;
168
- const action = button.dataset.action;
169
- handleAction(action);
170
- });
171
- ```
172
-
173
- ### Sequential Async Operations
174
-
175
- ```javascript
176
- APX('#submit-button').listen('click').do(async (event) => {
177
- // First: Validate form
178
- const isValid = await validateForm();
179
- if (!isValid) throw new Error('Validation failed');
180
- }).do(async (event) => {
181
- // Second: Submit form (only if validation passed)
182
- const result = await submitForm();
183
- return result;
184
- }).do((event) => {
185
- // Third: Show success message
186
- showSuccessMessage();
187
- });
188
- ```
189
-
190
- ### Multiple Event Types
191
-
192
- ```javascript
193
- APX('.input-field').listen(['focus', 'blur', 'input']).do((event) => {
194
- switch (event.type) {
195
- case 'focus':
196
- highlightField(event.target);
197
- break;
198
- case 'blur':
199
- validateField(event.target);
200
- break;
201
- case 'input':
202
- updatePreview(event.target.value);
203
- break;
204
- }
205
- });
206
- ```
207
-
208
- ---
209
-
210
- ## Features
211
-
212
- - ✅ **Event Delegation**: Handle events on dynamically added elements
213
- - ✅ **Multiple Callbacks**: Chain multiple callbacks that execute sequentially
214
- - ✅ **Promise Support**: Callbacks can return Promises for async operations
215
- - ✅ **Debouncing**: Add timeouts to delay callback execution
216
- - ✅ **Multiple Event Types**: Listen to multiple event types at once
217
- - ✅ **Manual Triggering**: Programmatically trigger events and callbacks
218
- - ✅ **Context Binding**: Callbacks are bound to the matched element (`this`)
219
-
220
- ---
221
-
222
- ## Notes
223
-
224
- - Callbacks execute sequentially; if a callback returns a Promise, the next callback waits for it to resolve
225
- - Event delegation uses `closest()` to find the matching element, so it works with nested elements
226
- - Timeouts are cleared and reset on each event, making it perfect for debouncing
227
- - The `trigger()` method respects event delegation selectors when executing callbacks
228
-
229
- ---
230
-
231
- ## License
232
-
233
- Author : Thibault SAELEN
234
- Copyright Appius SARL.
235
-
1
+ # APX Listen Module
2
+
3
+ The `listen` module provides a powerful event handling system for APX objects. It enables event delegation, multiple callback chaining, debouncing via timeouts, and manual event triggering.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ The `listen` module is automatically included when you import APX. It augments all APX objects with the `.listen()` and `.trigger()` methods.
10
+
11
+ ```javascript
12
+ import APX from './APX.mjs';
13
+ // .listen() and .trigger() are now available on all APX objects
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Usage
19
+
20
+ ### Basic Event Listening
21
+
22
+ ```javascript
23
+ // Listen to a single event type
24
+ APX('.my-button').listen('click').do((event) => {
25
+ console.log('Button clicked!', event.target);
26
+ });
27
+
28
+ // Listen to multiple event types
29
+ APX('.my-input').listen(['input', 'change']).do((event) => {
30
+ console.log('Input changed:', event.target.value);
31
+ });
32
+ ```
33
+
34
+ ### Event Delegation
35
+
36
+ Use event delegation to handle events on dynamically added elements:
37
+
38
+ ```javascript
39
+ // Listen for clicks on any button inside the container (even if added later)
40
+ APX('#container').listen('click', '.button').do((event) => {
41
+ console.log('Button clicked:', event.target);
42
+ });
43
+ ```
44
+
45
+ ### Multiple Callbacks (Chaining)
46
+
47
+ Chain multiple callbacks that execute sequentially:
48
+
49
+ ```javascript
50
+ APX('.my-button').listen('click').do((event) => {
51
+ console.log('First callback');
52
+ return fetch('/api/data'); // Can return promises
53
+ }).do((event) => {
54
+ console.log('Second callback (runs after first completes)');
55
+ }).do((event) => {
56
+ console.log('Third callback');
57
+ });
58
+ ```
59
+
60
+ ### Debouncing with Timeout
61
+
62
+ Add a delay before executing callbacks:
63
+
64
+ ```javascript
65
+ // Wait 300ms after the last event before executing callbacks
66
+ APX('.search-input').listen('input', { timeout: 300 }).do((event) => {
67
+ console.log('Searching for:', event.target.value);
68
+ // This will only fire 300ms after the user stops typing
69
+ });
70
+ ```
71
+
72
+ ### Manual Event Triggering
73
+
74
+ Manually trigger events and their registered callbacks:
75
+
76
+ ```javascript
77
+ // Trigger a click event
78
+ APX('.my-button').trigger('click');
79
+
80
+ // Or trigger with an actual Event object
81
+ const customEvent = new CustomEvent('myevent', { detail: { data: 'value' } });
82
+ APX('.my-element').trigger(customEvent);
83
+ ```
84
+
85
+ ---
86
+
87
+ ## API
88
+
89
+ ### `.listen(eventTypes, selector?, options?)`
90
+
91
+ Adds event listeners to the APX-wrapped elements.
92
+
93
+ **Parameters:**
94
+ - `eventTypes` (string | string[]): The event type(s) to listen for (e.g., `'click'`, `['input', 'change']`)
95
+ - `selector` (string, optional): CSS selector for event delegation
96
+ - `options` (object, optional): Configuration options
97
+ - `timeout` (number): Delay in milliseconds before executing callbacks (default: `0`)
98
+
99
+ **Returns:** An object with a `.do()` method for chaining callbacks.
100
+
101
+ **Example:**
102
+ ```javascript
103
+ APX('.element')
104
+ .listen('click', '.button', { timeout: 100 })
105
+ .do((event) => { /* callback 1 */ })
106
+ .do((event) => { /* callback 2 */ });
107
+ ```
108
+
109
+ ### `.do(callback)`
110
+
111
+ Adds a callback function to the event listener chain. Callbacks execute sequentially, and each callback can return a Promise to delay the next callback.
112
+
113
+ **Parameters:**
114
+ - `callback` (Function): The callback function that receives the event object
115
+
116
+ **Returns:** The same object (for chaining)
117
+
118
+ **Example:**
119
+ ```javascript
120
+ APX('.button').listen('click').do((event) => {
121
+ // Callback is bound to the matched element
122
+ console.log(this); // The matched element
123
+ return fetch('/api').then(res => res.json());
124
+ }).do((event) => {
125
+ // This runs after the fetch completes
126
+ console.log('Fetch completed');
127
+ });
128
+ ```
129
+
130
+ ### `.trigger(event)`
131
+
132
+ Manually triggers an event on all wrapped elements and executes registered callbacks.
133
+
134
+ **Parameters:**
135
+ - `event` (string | Event): Event type string or an Event object
136
+
137
+ **Example:**
138
+ ```javascript
139
+ // Trigger with string
140
+ APX('.button').trigger('click');
141
+
142
+ // Trigger with Event object
143
+ const event = new CustomEvent('custom', { detail: { foo: 'bar' } });
144
+ APX('.element').trigger(event);
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Examples
150
+
151
+ ### Form Validation with Debouncing
152
+
153
+ ```javascript
154
+ APX('#email-input').listen('input', { timeout: 500 }).do((event) => {
155
+ const email = event.target.value;
156
+ if (email.includes('@')) {
157
+ validateEmail(email);
158
+ }
159
+ });
160
+ ```
161
+
162
+ ### Dynamic Content with Event Delegation
163
+
164
+ ```javascript
165
+ // Handle clicks on buttons added dynamically
166
+ APX('#dynamic-container').listen('click', '.action-button').do((event) => {
167
+ const button = event.target;
168
+ const action = button.dataset.action;
169
+ handleAction(action);
170
+ });
171
+ ```
172
+
173
+ ### Sequential Async Operations
174
+
175
+ ```javascript
176
+ APX('#submit-button').listen('click').do(async (event) => {
177
+ // First: Validate form
178
+ const isValid = await validateForm();
179
+ if (!isValid) throw new Error('Validation failed');
180
+ }).do(async (event) => {
181
+ // Second: Submit form (only if validation passed)
182
+ const result = await submitForm();
183
+ return result;
184
+ }).do((event) => {
185
+ // Third: Show success message
186
+ showSuccessMessage();
187
+ });
188
+ ```
189
+
190
+ ### Multiple Event Types
191
+
192
+ ```javascript
193
+ APX('.input-field').listen(['focus', 'blur', 'input']).do((event) => {
194
+ switch (event.type) {
195
+ case 'focus':
196
+ highlightField(event.target);
197
+ break;
198
+ case 'blur':
199
+ validateField(event.target);
200
+ break;
201
+ case 'input':
202
+ updatePreview(event.target.value);
203
+ break;
204
+ }
205
+ });
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Features
211
+
212
+ - ✅ **Event Delegation**: Handle events on dynamically added elements
213
+ - ✅ **Multiple Callbacks**: Chain multiple callbacks that execute sequentially
214
+ - ✅ **Promise Support**: Callbacks can return Promises for async operations
215
+ - ✅ **Debouncing**: Add timeouts to delay callback execution
216
+ - ✅ **Multiple Event Types**: Listen to multiple event types at once
217
+ - ✅ **Manual Triggering**: Programmatically trigger events and callbacks
218
+ - ✅ **Context Binding**: Callbacks are bound to the matched element (`this`)
219
+
220
+ ---
221
+
222
+ ## Notes
223
+
224
+ - Callbacks execute sequentially; if a callback returns a Promise, the next callback waits for it to resolve
225
+ - Event delegation uses `closest()` to find the matching element, so it works with nested elements
226
+ - Timeouts are cleared and reset on each event, making it perfect for debouncing
227
+ - The `trigger()` method respects event delegation selectors when executing callbacks
228
+
229
+ ---
230
+
231
+ ## Demos
232
+
233
+ - Demo landing page: `demo/index.html`
234
+ - Related module demo: `demo/modules/tristate/index.html` (tri-state visual states and interaction)
235
+
236
+ ---
237
+
238
+ ## License
239
+
240
+ Author : Thibault SAELEN
241
+ Copyright Appius SARL.
242
+
@@ -132,9 +132,7 @@ function executeCallbacks(event, uniqueId, timeoutDuration, selector = '', eleme
132
132
  }
133
133
  });
134
134
  });
135
- }, Promise.resolve()).catch(error => {
136
- console.error('Error in callback chain:', error);
137
- });
135
+ }, Promise.resolve()).catch(() => {});
138
136
  }
139
137
  }
140
138
 
@@ -0,0 +1,37 @@
1
+ # Changelog — Scrollable Table module
2
+
3
+ All notable changes to this module are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
+
7
+ ## [2.7.1] - 2025-02-16
8
+
9
+ ### Added
10
+ - Option **`height`**: fixed body height (number or CSS length). When set, the tbody row always uses this height; `maxHeight` is ignored. Class `apx-scrollable-table--body-height` is applied.
11
+ - Option **`bodyHeightDynamic`**: dynamic body height — `{ get: (table) => number|string, useAs: 'height'|'maxHeight', updateOn?: { scroll?, resize?, scrollOn?, resizeOn? } }`. Re-resolves body size when scroll/resize sources fire (viewport, scrollbar appearance, or custom elements). **updateOn** uses booleans `scroll`/`resize` (default true = document scroll + window resize) or explicit `scrollOn`/`resizeOn` arrays with sentinels `'document'`/`'window'` or elements (ResizeObserver for resize elements). Lazy cleanup: tables removed from the DOM are dropped from updates on the next event (no MutationObserver).
12
+ - Option **`gridTemplateColumns`**: full override for column tracks (e.g. `'1fr 2fr 1fr'`). Skips width measurement.
13
+ - Option **`gridTemplateRows`**: per-section override `{ thead?, tbody?, tfoot? }` for row tracks.
14
+ - Option **`columnOverrides`**: hybrid mode — column index → CSS value (object or array). Columns not overridden keep measured width.
15
+ - Option **`rowOverrides`**: hybrid mode — per-section row index → CSS value. Rows not overridden keep measured height.
16
+ - **Column width preservation**: widths are measured from the table’s natural layout (before applying the module) and applied as `grid-template-columns`; stored in ref for refresh.
17
+ - **Row height preservation**: each `<tr>` height is measured and applied so rowspan cells keep correct proportions.
18
+ - **Scrollbar gutter**: dedicated grid column for the vertical scrollbar so it does not overlap the last data column. CSS variable `--apx-scrollable-gutter-width` (default 17px); set to `0` to allow overlap.
19
+ - CSS variables **`--apx-scrollable-thead-template-rows`**, **`--apx-scrollable-tbody-template-rows`**, **`--apx-scrollable-tfoot-template-rows`** for row track overrides.
20
+
21
+ ### Fixed
22
+ - **Horizontal scrollbar on init**: the grid class and template-columns were applied in the same layout pass, causing the tbody to overflow horizontally. The grid is now established first (with a forced reflow) before setting the measured template-columns.
23
+ - Measured column widths now use `fr` units instead of `px` so they remain flexible alongside the fixed gutter column.
24
+
25
+ ### Changed
26
+ - Removed `scrollbar-gutter: stable` from tbody; scrollbar space is now the dedicated gutter column.
27
+ - Grid template columns: value is set via `--apx-scrollable-template-columns` (with gutter suffix). Fallback in CSS includes gutter.
28
+ - Body size: when `height` is set, grid row uses fixed size; otherwise `fit-content(max-height)` as before. With `bodyHeightDynamic`, body size is resolved from `get(table)` at init and on scroll/resize (throttled).
29
+
30
+ ## [2.7.0] - 2025-02-16
31
+
32
+ ### Added
33
+ - Initial release: scrollable tbody with fixed thead/tfoot, CSS Grid + subgrid.
34
+ - `APX('table').scrollableTable(options)` and `scrollableTable('refresh')`.
35
+ - Option `maxHeight` (number or CSS length).
36
+ - Full colspan/rowspan support via explicit grid placement.
37
+ - Demo: `demo/modules/scrollableTable/index.html`.