@ulu/frontend 0.1.0-beta.81 → 0.1.0-beta.83
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/CHANGELOG.md +18 -2
- package/dist/ulu-frontend.min.js +17 -17
- package/docs-dev/changelog/index.html +16 -0
- package/docs-dev/demos/card/index.html +16 -16
- package/docs-dev/demos/data-table/index.html +100 -100
- package/docs-dev/javascript/ui-resizer/index.html +212 -16
- package/js/ui/dialog.js +16 -44
- package/js/ui/modal-builder.js +2 -2
- package/js/ui/resizer.js +331 -112
- package/js/utils/font-awesome.js +1 -1
- package/package.json +1 -1
- package/types/ui/dialog.d.ts.map +1 -1
- package/types/ui/resizer.d.ts +85 -12
- package/types/ui/resizer.d.ts.map +1 -1
package/js/ui/resizer.js
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* @module ui/resizer
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
// Note: Gzip Test = 1.6kb (7-28-25), which seems appropriate
|
|
6
|
+
// based on how many options/events it handles
|
|
7
|
+
|
|
5
8
|
import { createEvent } from "../events/index.js";
|
|
6
|
-
import { logError, log } from "../utils/class-logger.js";
|
|
9
|
+
import { logError, log } from "../utils/class-logger.js";
|
|
7
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Class for creating/controlling a container size with a handle/control
|
|
13
|
+
*/
|
|
8
14
|
export class Resizer {
|
|
9
15
|
static defaults = {
|
|
10
16
|
debug: false,
|
|
@@ -22,192 +28,405 @@ export class Resizer {
|
|
|
22
28
|
* `null` means no horizontal resizing.
|
|
23
29
|
* - Default null
|
|
24
30
|
*/
|
|
25
|
-
fromX: null,
|
|
31
|
+
fromX: null,
|
|
26
32
|
/**
|
|
27
33
|
* @type {"top"|"bottom"|null}
|
|
28
34
|
* Specifies the vertical edge from which resizing occurs.
|
|
29
35
|
* - `null` means no vertical resizing.
|
|
30
36
|
* - Default null
|
|
31
37
|
*/
|
|
32
|
-
fromY: null
|
|
38
|
+
fromY: null,
|
|
39
|
+
/**
|
|
40
|
+
* The step in pixels for keyboard resizing with arrow keys.
|
|
41
|
+
*/
|
|
42
|
+
keyboardStep: 10,
|
|
43
|
+
/**
|
|
44
|
+
* Debounce time in milliseconds for ending a keyboard resize.
|
|
45
|
+
*/
|
|
46
|
+
keyboardDebounceTime: 200,
|
|
47
|
+
/**
|
|
48
|
+
* If true, the Resizer instance will automatically bind its own DOM event listeners
|
|
49
|
+
* (pointerdown, keydown) to the control element. If `false`, the user is
|
|
50
|
+
* responsible for calling `resizerInstance.onPointerdown(event)` and
|
|
51
|
+
* `resizerInstance.onKeydown(event)` from their own listeners.
|
|
52
|
+
* Default: true
|
|
53
|
+
*/
|
|
54
|
+
manageEvents: true,
|
|
55
|
+
/**
|
|
56
|
+
* If true, the Resizer instance will automatically manage the `aria-label`
|
|
57
|
+
* attribute of the control element. If `false`, the user is responsible
|
|
58
|
+
* for setting this attribute.
|
|
59
|
+
* Default: false
|
|
60
|
+
*/
|
|
61
|
+
manageAriaLabel: false,
|
|
62
|
+
/**
|
|
63
|
+
* If true, pointer events (mouse/touch) will enable resizing.
|
|
64
|
+
* Default: true
|
|
65
|
+
*/
|
|
66
|
+
enablePointerResizing: true,
|
|
67
|
+
/**
|
|
68
|
+
* If true, keyboard events (arrow keys) will enable resizing.
|
|
69
|
+
* Default: true
|
|
70
|
+
*/
|
|
71
|
+
enableKeyboardResizing: true
|
|
33
72
|
};
|
|
34
73
|
|
|
35
|
-
// Declare
|
|
36
|
-
#
|
|
74
|
+
// Declare private fields without initial assignments
|
|
75
|
+
#handlerPointerdownInternal;
|
|
76
|
+
#handlerKeydownInternal;
|
|
77
|
+
#keyboardResizeTimeout;
|
|
78
|
+
#initialContainerDimensions;
|
|
79
|
+
#accumulatedKeyboardDeltaX;
|
|
80
|
+
#accumulatedKeyboardDeltaY;
|
|
81
|
+
#isResizingActive;
|
|
82
|
+
#pointerStartX;
|
|
83
|
+
#pointerStartY;
|
|
37
84
|
|
|
38
85
|
/**
|
|
39
86
|
* @param {Node} container Container to be resized
|
|
40
|
-
* @param {
|
|
41
|
-
* @param {Object}
|
|
42
|
-
* @param {Boolean}
|
|
43
|
-
* @param {Boolean}
|
|
44
|
-
* @param {
|
|
45
|
-
* @param {"
|
|
87
|
+
* @param {HTMLElement} control Resize handle element (should be focusable like a button)
|
|
88
|
+
* @param {Object} config Options to configure the resizer.
|
|
89
|
+
* @param {Boolean} [config.debug=false] Enable non-essential debugging logs.
|
|
90
|
+
* @param {Boolean} [config.multiplier=1] Amount to increase size by (ie. pointer movement * multiplier).
|
|
91
|
+
* @param {Boolean} [config.overrideMaxDimensions=false] When script is activated by handle, remove the element's max-width/max-height and allow the resize to exceed them.
|
|
92
|
+
* @param {"left"|"right"|null} [config.fromX=null] Horizontal resizing direction.
|
|
93
|
+
* @param {"top"|"bottom"|null} [config.fromY=null] Vertical resizing direction.
|
|
94
|
+
* @param {number} [config.keyboardStep=10] The step in pixels for keyboard resizing.
|
|
95
|
+
* @param {number} [config.keyboardDebounceTime=200] Debounce time for keyboard resize end.
|
|
96
|
+
* @param {boolean} [config.manageEvents=true] If true, the Resizer will automatically bind its own events.
|
|
97
|
+
* @param {boolean} [config.manageAriaLabel=false] If true, the Resizer will manage the control's aria-label.
|
|
98
|
+
* @param {boolean} [config.enablePointerResizing=true] If true, pointer events will enable resizing.
|
|
99
|
+
* @param {boolean} [config.enableKeyboardResizing=true] If true, keyboard events will enable resizing.
|
|
46
100
|
*/
|
|
47
|
-
constructor(container, control,
|
|
101
|
+
constructor(container, control, config) {
|
|
48
102
|
if (!control || !container) {
|
|
49
103
|
logError(this, "Missing required elements: control, container");
|
|
50
104
|
return;
|
|
51
105
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
106
|
+
const options = Object.assign({}, Resizer.defaults, config);
|
|
107
|
+
this.options = options;
|
|
55
108
|
this.container = container;
|
|
56
109
|
this.control = control;
|
|
57
|
-
this.debug =
|
|
110
|
+
this.debug = options.debug;
|
|
58
111
|
|
|
59
|
-
// Validate and normalize fromX/fromY
|
|
60
112
|
const validX = ["left", "right"];
|
|
61
113
|
const validY = ["top", "bottom"];
|
|
62
|
-
|
|
63
|
-
const { fromX, fromY } = this.options;
|
|
114
|
+
const { fromX, fromY } = options;
|
|
64
115
|
|
|
65
116
|
if (!validX.includes(fromX) && fromX !== null) {
|
|
66
117
|
logError(this, `Invalid fromX: ${ fromX } (left|right|null)`);
|
|
67
|
-
return;
|
|
118
|
+
return;
|
|
68
119
|
}
|
|
69
120
|
if (!validY.includes(fromY) && fromY !== null) {
|
|
70
121
|
logError(this, `Invalid fromY: ${ fromY } (top|bottom|null)`);
|
|
71
122
|
return;
|
|
72
123
|
}
|
|
73
|
-
|
|
74
124
|
if (!fromX && !fromY) {
|
|
75
|
-
logError(this, "Invalid fromX/fromY, failed to setup resizer");
|
|
125
|
+
logError(this, "Invalid fromX/fromY, failed to setup resizer (at least one of fromX or fromY must be set)");
|
|
76
126
|
return;
|
|
77
127
|
}
|
|
78
128
|
|
|
79
|
-
|
|
80
|
-
this.
|
|
81
|
-
|
|
129
|
+
this.resizeHorizontal = options.fromX !== null;
|
|
130
|
+
this.resizeVertical = options.fromY !== null;
|
|
131
|
+
|
|
132
|
+
// Bind internal listeners only if manageEvents is true AND the respective event type is enabled
|
|
133
|
+
if (options.manageEvents) {
|
|
134
|
+
this.#handlerPointerdownInternal = this.onPointerdown.bind(this);
|
|
135
|
+
this.#handlerKeydownInternal = this.onKeydown.bind(this);
|
|
136
|
+
|
|
137
|
+
if (options.enablePointerResizing) {
|
|
138
|
+
control.addEventListener("pointerdown", this.#handlerPointerdownInternal);
|
|
139
|
+
}
|
|
140
|
+
if (options.enableKeyboardResizing) {
|
|
141
|
+
control.addEventListener("keydown", this.#handlerKeydownInternal);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
82
144
|
|
|
83
|
-
|
|
84
|
-
this.#handlerPointerdown = this.#onPointerdown.bind(this);
|
|
145
|
+
this.#resetInternalState();
|
|
85
146
|
|
|
86
|
-
|
|
87
|
-
|
|
147
|
+
if (options.manageAriaLabel) {
|
|
148
|
+
control.setAttribute("aria-label", this.getAriaLabel());
|
|
149
|
+
}
|
|
88
150
|
}
|
|
89
151
|
|
|
90
152
|
/**
|
|
91
|
-
*
|
|
153
|
+
* Resets all internal state properties to their default/inactive values.
|
|
154
|
+
* This centralizes state cleanup and initial setup.
|
|
155
|
+
* @private
|
|
156
|
+
*/
|
|
157
|
+
#resetInternalState() {
|
|
158
|
+
this.#keyboardResizeTimeout = null;
|
|
159
|
+
this.#initialContainerDimensions = { width: 0, height: 0 };
|
|
160
|
+
this.#accumulatedKeyboardDeltaX = 0;
|
|
161
|
+
this.#accumulatedKeyboardDeltaY = 0;
|
|
162
|
+
this.#isResizingActive = false;
|
|
163
|
+
this.#pointerStartX = 0;
|
|
164
|
+
this.#pointerStartY = 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Cleans up event listeners and internal state to prevent memory leaks.
|
|
92
169
|
*/
|
|
93
170
|
destroy() {
|
|
94
|
-
|
|
171
|
+
const { control, options } = this;
|
|
172
|
+
|
|
173
|
+
if (options.manageEvents) {
|
|
174
|
+
if (options.enablePointerResizing) {
|
|
175
|
+
control.removeEventListener("pointerdown", this.#handlerPointerdownInternal);
|
|
176
|
+
}
|
|
177
|
+
if (options.enableKeyboardResizing) {
|
|
178
|
+
control.removeEventListener("keydown", this.#handlerKeydownInternal);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (this.#keyboardResizeTimeout) {
|
|
183
|
+
clearTimeout(this.#keyboardResizeTimeout);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this.#resetInternalState();
|
|
187
|
+
|
|
188
|
+
if (options.manageAriaLabel) {
|
|
189
|
+
control.removeAttribute("aria-label");
|
|
190
|
+
}
|
|
191
|
+
log(this, "Resizer destroyed.");
|
|
95
192
|
}
|
|
96
193
|
|
|
97
194
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
195
|
+
* Initiates a resize operation.
|
|
196
|
+
* This sets initial dimensions and dispatches the 'resizer:start' event.
|
|
197
|
+
* @param {Object} eventDetails Additional details about the initiating event.
|
|
100
198
|
* @private
|
|
101
199
|
*/
|
|
102
|
-
#
|
|
103
|
-
|
|
200
|
+
#startResize(eventDetails) {
|
|
201
|
+
const { container, options } = this;
|
|
104
202
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
203
|
+
if (this.#isResizingActive) {
|
|
204
|
+
if (options.overrideMaxDimensions) {
|
|
205
|
+
if (this.resizeHorizontal) {
|
|
206
|
+
container.style.maxWidth = "none";
|
|
207
|
+
}
|
|
208
|
+
if (this.resizeVertical) {
|
|
209
|
+
container.style.maxHeight = "none";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
113
214
|
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
const initialHeight = parseInt(containerStyle.height, 10);
|
|
215
|
+
const win = document.defaultView;
|
|
216
|
+
const containerStyle = win.getComputedStyle(container);
|
|
117
217
|
|
|
118
|
-
|
|
119
|
-
this.
|
|
218
|
+
this.#initialContainerDimensions.width = parseInt(containerStyle.width, 10);
|
|
219
|
+
this.#initialContainerDimensions.height = parseInt(containerStyle.height, 10);
|
|
120
220
|
|
|
121
|
-
|
|
122
|
-
if (overrideMaxDimensions) {
|
|
221
|
+
if (options.overrideMaxDimensions) {
|
|
123
222
|
if (this.resizeHorizontal) {
|
|
124
|
-
|
|
223
|
+
container.style.maxWidth = "none";
|
|
125
224
|
}
|
|
126
225
|
if (this.resizeVertical) {
|
|
127
|
-
|
|
226
|
+
container.style.maxHeight = "none";
|
|
128
227
|
}
|
|
129
228
|
}
|
|
130
229
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
pointerId: e.pointerId
|
|
140
|
-
};
|
|
230
|
+
this.#isResizingActive = true;
|
|
231
|
+
this.dispatchEvent("resizer:start", eventDetails);
|
|
232
|
+
log(this, "Resize started.", {
|
|
233
|
+
initialWidth: this.#initialContainerDimensions.width,
|
|
234
|
+
initialHeight: this.#initialContainerDimensions.height,
|
|
235
|
+
...eventDetails
|
|
236
|
+
});
|
|
237
|
+
}
|
|
141
238
|
|
|
142
|
-
|
|
143
|
-
|
|
239
|
+
/**
|
|
240
|
+
* Ends a resize operation.
|
|
241
|
+
* Dispatches 'resizer:end' event and resets internal state.
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
#endResize() {
|
|
245
|
+
if (!this.#isResizingActive) return;
|
|
144
246
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const pointermove = (event) => {
|
|
150
|
-
let newWidth = initialWidth;
|
|
151
|
-
let newHeight = initialHeight;
|
|
247
|
+
this.dispatchEvent("resizer:end");
|
|
248
|
+
this.#resetInternalState();
|
|
249
|
+
log(this, "Resize ended.");
|
|
250
|
+
}
|
|
152
251
|
|
|
153
|
-
|
|
154
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Core logic for calculating and applying the new size of the container.
|
|
254
|
+
* This method is called by both pointer and keyboard event handlers.
|
|
255
|
+
*
|
|
256
|
+
* @param {number} totalDeltaX The total horizontal displacement from the start of the resize.
|
|
257
|
+
* @param {number} totalDeltaY The total vertical displacement from the start of the resize.
|
|
258
|
+
* @param {Event} originalEvent The original DOM event (PointerEvent or KeyboardEvent) that triggered the update.
|
|
259
|
+
* @private
|
|
260
|
+
*/
|
|
261
|
+
#updateSize(totalDeltaX, totalDeltaY, originalEvent) {
|
|
262
|
+
let newWidth = this.#initialContainerDimensions.width;
|
|
263
|
+
let newHeight = this.#initialContainerDimensions.height;
|
|
264
|
+
const { fromX, fromY, multiplier } = this.options;
|
|
155
265
|
|
|
156
|
-
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
newWidth = (initialWidth - (deltaX * multiplier));
|
|
162
|
-
}
|
|
163
|
-
this.container.style.width = `${ Math.max(0, newWidth) }px`; // Ensure non-negative width
|
|
266
|
+
if (this.resizeHorizontal) {
|
|
267
|
+
if (fromX === "right") {
|
|
268
|
+
newWidth = (this.#initialContainerDimensions.width + (totalDeltaX * multiplier));
|
|
269
|
+
} else if (fromX === "left") {
|
|
270
|
+
newWidth = (this.#initialContainerDimensions.width - (totalDeltaX * multiplier));
|
|
164
271
|
}
|
|
272
|
+
this.container.style.width = `${ Math.max(0, newWidth) }px`;
|
|
273
|
+
}
|
|
165
274
|
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
newHeight = (initialHeight - (deltaY * multiplier));
|
|
172
|
-
}
|
|
173
|
-
this.container.style.height = `${ Math.max(0, newHeight) }px`; // Ensure non-negative height
|
|
275
|
+
if (this.resizeVertical) {
|
|
276
|
+
if (fromY === "bottom") {
|
|
277
|
+
newHeight = (this.#initialContainerDimensions.height + (totalDeltaY * multiplier));
|
|
278
|
+
} else if (fromY === "top") {
|
|
279
|
+
newHeight = (this.#initialContainerDimensions.height - (totalDeltaY * multiplier));
|
|
174
280
|
}
|
|
281
|
+
this.container.style.height = `${ Math.max(0, newHeight) }px`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const updateInfo = {
|
|
285
|
+
newWidth: newWidth,
|
|
286
|
+
newHeight: newHeight,
|
|
287
|
+
totalDeltaX: totalDeltaX,
|
|
288
|
+
totalDeltaY: totalDeltaY,
|
|
289
|
+
event: originalEvent
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
this.dispatchEvent("resizer:update", updateInfo);
|
|
293
|
+
log(this, "Resizing update.", updateInfo);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Public handler for pointerdown events. Call this method from your own event listeners
|
|
298
|
+
* if `manageEvents` is false. Its logic will only execute if `enablePointerResizing` is true.
|
|
299
|
+
* @param {PointerEvent} e The pointerdown event.
|
|
300
|
+
*/
|
|
301
|
+
onPointerdown(e) {
|
|
302
|
+
if (!this.options.enablePointerResizing) {
|
|
303
|
+
log(this, "Pointer resizing disabled. Ignoring pointerdown event.");
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
e.preventDefault();
|
|
308
|
+
const doc = document.documentElement;
|
|
175
309
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
310
|
+
this.#pointerStartX = e.clientX;
|
|
311
|
+
this.#pointerStartY = e.clientY;
|
|
312
|
+
|
|
313
|
+
this.#startResize({
|
|
314
|
+
inputType: 'pointer',
|
|
315
|
+
startX: e.clientX,
|
|
316
|
+
startY: e.clientY,
|
|
317
|
+
pointerId: e.pointerId
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
this.control.setPointerCapture(e.pointerId);
|
|
183
321
|
|
|
184
|
-
|
|
185
|
-
|
|
322
|
+
const pointermove = (event) => {
|
|
323
|
+
const totalDeltaX = event.clientX - this.#pointerStartX;
|
|
324
|
+
const totalDeltaY = event.clientY - this.#pointerStartY;
|
|
325
|
+
this.#updateSize(totalDeltaX, totalDeltaY, event);
|
|
186
326
|
};
|
|
187
327
|
|
|
188
|
-
/**
|
|
189
|
-
* Cleans up event listeners after the pointerup event.
|
|
190
|
-
* @param {PointerEvent} event The pointerup event.
|
|
191
|
-
*/
|
|
192
328
|
const cleanup = (event) => {
|
|
193
329
|
doc.removeEventListener("pointermove", pointermove, false);
|
|
194
330
|
doc.removeEventListener("pointerup", cleanup, { capture: true, once: true });
|
|
195
331
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
log(this, "Pointerup cleanup complete. Pointer released.", {
|
|
201
|
-
pointerId: event.pointerId
|
|
202
|
-
});
|
|
203
|
-
|
|
332
|
+
if (this.control.hasPointerCapture(event.pointerId)) {
|
|
333
|
+
this.control.releasePointerCapture(event.pointerId);
|
|
334
|
+
}
|
|
335
|
+
this.#endResize();
|
|
204
336
|
};
|
|
205
337
|
|
|
206
|
-
// Attach global event listeners for dragging
|
|
207
338
|
doc.addEventListener("pointermove", pointermove, false);
|
|
208
339
|
doc.addEventListener("pointerup", cleanup, { capture: true, once: true });
|
|
209
340
|
}
|
|
210
|
-
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Public handler for keydown events. Call this method from your own event listeners
|
|
344
|
+
* if `manageEvents` is false. Its logic will only execute if `enableKeyboardResizing` is true.
|
|
345
|
+
* @param {KeyboardEvent} e The keydown event.
|
|
346
|
+
*/
|
|
347
|
+
onKeydown(e) {
|
|
348
|
+
if (!this.options.enableKeyboardResizing) {
|
|
349
|
+
log(this, "Keyboard resizing disabled. Ignoring keydown event.");
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const { key } = e;
|
|
354
|
+
const { keyboardStep, keyboardDebounceTime } = this.options;
|
|
355
|
+
|
|
356
|
+
let stepDeltaX = 0;
|
|
357
|
+
let stepDeltaY = 0;
|
|
358
|
+
let isResizeKey = false;
|
|
359
|
+
|
|
360
|
+
if (this.resizeHorizontal) {
|
|
361
|
+
if (key === "ArrowLeft") {
|
|
362
|
+
// ArrowLeft should always move the active horizontal edge to the left
|
|
363
|
+
stepDeltaX = -keyboardStep;
|
|
364
|
+
isResizeKey = true;
|
|
365
|
+
} else if (key === "ArrowRight") {
|
|
366
|
+
// ArrowRight should always move the active horizontal edge to the right
|
|
367
|
+
stepDeltaX = keyboardStep;
|
|
368
|
+
isResizeKey = true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (this.resizeVertical) {
|
|
373
|
+
if (key === "ArrowUp") {
|
|
374
|
+
// ArrowUp should always move the active vertical edge up
|
|
375
|
+
stepDeltaY = -keyboardStep;
|
|
376
|
+
isResizeKey = true;
|
|
377
|
+
} else if (key === "ArrowDown") {
|
|
378
|
+
// ArrowDown should always move the active vertical edge down
|
|
379
|
+
stepDeltaY = keyboardStep;
|
|
380
|
+
isResizeKey = true;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (isResizeKey) {
|
|
385
|
+
e.preventDefault();
|
|
386
|
+
e.stopPropagation();
|
|
387
|
+
|
|
388
|
+
if (!this.#isResizingActive || this.#keyboardResizeTimeout === null) {
|
|
389
|
+
this.#startResize({ inputType: 'keyboard', keyboardKey: key });
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
this.#accumulatedKeyboardDeltaX += stepDeltaX;
|
|
393
|
+
this.#accumulatedKeyboardDeltaY += stepDeltaY;
|
|
394
|
+
|
|
395
|
+
this.#updateSize(this.#accumulatedKeyboardDeltaX, this.#accumulatedKeyboardDeltaY, e);
|
|
396
|
+
|
|
397
|
+
if (this.#keyboardResizeTimeout) {
|
|
398
|
+
clearTimeout(this.#keyboardResizeTimeout);
|
|
399
|
+
}
|
|
400
|
+
this.#keyboardResizeTimeout = setTimeout(() => {
|
|
401
|
+
this.#endResize();
|
|
402
|
+
this.#keyboardResizeTimeout = null;
|
|
403
|
+
}, keyboardDebounceTime);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Generates an accessible label for the resize control based on its configuration.
|
|
409
|
+
* This is a convenience function that can be used by the consumer if `manageAriaLabel` is false.
|
|
410
|
+
* @returns {string} The suggested aria-label for the control.
|
|
411
|
+
*/
|
|
412
|
+
getAriaLabel() {
|
|
413
|
+
const { fromY, fromX } = this.options;
|
|
414
|
+
const directions = [fromY, fromX].filter(v => v);
|
|
415
|
+
|
|
416
|
+
if (directions.length === 0) {
|
|
417
|
+
return "Resize control"; // Fallback for invalid configuration (should be caught by constructor)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Join all directions with a space and append " edge".
|
|
421
|
+
return `Resize from ${directions.join(' ')} edge`;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Dispatches a custom event on the container element.
|
|
426
|
+
* @param {string} type The event type (e.g., "resizer:start", "resizer:update", "resizer:end").
|
|
427
|
+
* @param {Object} [data={}] Optional data to attach to the event's detail property.
|
|
428
|
+
*/
|
|
429
|
+
dispatchEvent(type, data = {}) {
|
|
211
430
|
this.container.dispatchEvent(createEvent(type, data));
|
|
212
431
|
}
|
|
213
432
|
}
|
package/js/utils/font-awesome.js
CHANGED
|
@@ -12,7 +12,7 @@ export function configureIcons() {
|
|
|
12
12
|
updateSettings({
|
|
13
13
|
iconClassClose: "fas fa-xmark",
|
|
14
14
|
iconClassDragX: "fas fa-solid fa-grip-lines-vertical",
|
|
15
|
-
iconClassDragBoth: "fas fa-solid fa-grip", // Not really any good icons for this (no diagonal arrows, etc)
|
|
15
|
+
// iconClassDragBoth: "fas fa-solid fa-grip", // Not really any good icons for this (no diagonal arrows, etc)
|
|
16
16
|
iconClassPrevious: "fas fa-solid fa-chevron-left",
|
|
17
17
|
iconClassNext: "fas fa-solid fa-chevron-right"
|
|
18
18
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ulu/frontend",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.83",
|
|
4
4
|
"description": "A versatile SCSS and JavaScript component library offering configurable, accessible components and flexible integration into any project, with SCSS modules suitable for modern JS frameworks.",
|
|
5
5
|
"browser": "js/index.js",
|
|
6
6
|
"main": "index.js",
|
package/types/ui/dialog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../js/ui/dialog.js"],"names":[],"mappings":"AA6DA;;GAEG;AACH,gDAEC;AAED;;;GAGG;AACH,6BAqBC;AAED;;;;GAIG;AACH,sCAHW,IAAI,0BA2Bd;AAED;;;GAGG;AACH,oCAFW,IAAI,
|
|
1
|
+
{"version":3,"file":"dialog.d.ts","sourceRoot":"","sources":["../../js/ui/dialog.js"],"names":[],"mappings":"AA6DA;;GAEG;AACH,gDAEC;AAED;;;GAGG;AACH,6BAqBC;AAED;;;;GAIG;AACH,sCAHW,IAAI,0BA2Bd;AAED;;;GAGG;AACH,oCAFW,IAAI,0BA6Dd;AAED;;;;GAIG;AACH,yCAHW,IAAI,OAKd;AA7LD;;GAEG;AACH,8CAA+C;AAE/C;;GAEG;AACH,+CAAuF;AAEvF;;GAEG;AACH,oCAAgE;;;;;;;;;qCAjB3B,oBAAoB"}
|