@ulu/frontend 0.1.0-beta.82 → 0.1.0-beta.84
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 +32 -3
- package/dist/ulu-frontend.min.css +1 -1
- package/dist/ulu-frontend.min.js +17 -17
- package/docs-dev/assets/main.js +494 -7738
- package/docs-dev/assets/style.css +166 -221
- package/docs-dev/changelog/index.html +294 -3
- package/docs-dev/changelog/updates-and-changes/index.html +5109 -0
- package/docs-dev/demos/accordion/index.html +240 -0
- package/docs-dev/demos/badge/index.html +240 -0
- package/docs-dev/demos/breakpoints-manager/index.html +240 -0
- package/docs-dev/demos/button/index.html +240 -0
- package/docs-dev/demos/button-group/index.html +5502 -0
- package/docs-dev/demos/button-verbose/index.html +240 -0
- package/docs-dev/demos/callout/index.html +240 -0
- package/docs-dev/demos/captioned-figure/index.html +240 -0
- package/docs-dev/demos/card/index.html +256 -16
- package/docs-dev/demos/card-grid/index.html +240 -0
- package/docs-dev/demos/card-new/index.html +5088 -0
- package/docs-dev/demos/card-old/index.html +5223 -0
- package/docs-dev/demos/card.1/index.html +5223 -0
- package/docs-dev/demos/card.TRASH/index.html +5541 -0
- package/docs-dev/demos/counter-list/index.html +240 -0
- package/docs-dev/demos/css-icons/index.html +240 -0
- package/docs-dev/demos/data-grid/index.html +240 -0
- package/docs-dev/demos/data-table/index.html +340 -100
- package/docs-dev/demos/details-group/index.html +240 -0
- package/docs-dev/demos/file-save/index.html +240 -0
- package/docs-dev/demos/flipcard/index.html +240 -0
- package/docs-dev/demos/form-theme/index.html +240 -0
- package/docs-dev/demos/headline-label/index.html +5472 -0
- package/docs-dev/demos/index.html +240 -0
- package/docs-dev/demos/list-inline/index.html +240 -0
- package/docs-dev/demos/list-inline.1/index.html +4727 -0
- package/docs-dev/demos/list-lines/index.html +240 -0
- package/docs-dev/demos/menu-stack/index.html +240 -0
- package/docs-dev/demos/modals/index.html +240 -0
- package/docs-dev/demos/nav-strip/index.html +240 -0
- package/docs-dev/demos/overlay-section/index.html +240 -0
- package/docs-dev/demos/panel/index.html +5532 -0
- package/docs-dev/demos/popovers/index.html +240 -0
- package/docs-dev/demos/print/index.html +240 -0
- package/docs-dev/demos/pull-quote/index.html +240 -0
- package/docs-dev/demos/rail/index.html +5568 -0
- package/docs-dev/demos/rule/index.html +240 -0
- package/docs-dev/demos/scrollpoints/index.html +240 -0
- package/docs-dev/demos/spoke-spinner/index.html +240 -0
- package/docs-dev/demos/sticky-list/index.html +240 -0
- package/docs-dev/demos/tabs/index.html +240 -0
- package/docs-dev/demos/tag/index.html +240 -0
- package/docs-dev/demos/theme-toggle/index.html +240 -0
- package/docs-dev/demos/tiles/index.html +240 -0
- package/docs-dev/demos/tooltip/index.html +240 -0
- package/docs-dev/guide/building-stylesheet/index.html +240 -0
- package/docs-dev/guide/developing-ulu-scss-module/index.html +240 -0
- package/docs-dev/guide/index.html +240 -0
- package/docs-dev/guide/updates-and-changes/index.html +5033 -0
- package/docs-dev/index.html +240 -0
- package/docs-dev/javascript/events/index.html +240 -0
- package/docs-dev/javascript/index.html +240 -0
- package/docs-dev/javascript/settings/index.html +240 -0
- package/docs-dev/javascript/ui-breakpoints/index.html +240 -0
- package/docs-dev/javascript/ui-collapsible/index.html +240 -0
- package/docs-dev/javascript/ui-details-group/index.html +240 -0
- package/docs-dev/javascript/ui-dialog/index.html +240 -0
- package/docs-dev/javascript/ui-flipcard/index.html +240 -0
- package/docs-dev/javascript/ui-grid/index.html +240 -0
- package/docs-dev/javascript/ui-modal-builder/index.html +240 -0
- package/docs-dev/javascript/ui-overflow-scroller/index.html +240 -0
- package/docs-dev/javascript/ui-overflow-scroller-pager/index.html +240 -0
- package/docs-dev/javascript/ui-page/index.html +240 -0
- package/docs-dev/javascript/ui-popover/index.html +240 -0
- package/docs-dev/javascript/ui-print/index.html +240 -0
- package/docs-dev/javascript/ui-print-details/index.html +240 -0
- package/docs-dev/javascript/ui-programmatic-modal/index.html +240 -0
- package/docs-dev/javascript/ui-proxy-click/index.html +240 -0
- package/docs-dev/javascript/ui-resizer/index.html +452 -16
- package/docs-dev/javascript/ui-scroll-slider/index.html +240 -0
- package/docs-dev/javascript/ui-scrollpoint/index.html +240 -0
- package/docs-dev/javascript/ui-slider/index.html +240 -0
- package/docs-dev/javascript/ui-tabs/index.html +240 -0
- package/docs-dev/javascript/ui-theme-toggle/index.html +240 -0
- package/docs-dev/javascript/ui-tooltip/index.html +240 -0
- package/docs-dev/javascript/utils-class-logger/index.html +240 -0
- package/docs-dev/javascript/utils-css/index.html +240 -0
- package/docs-dev/javascript/utils-dom/index.html +240 -0
- package/docs-dev/javascript/utils-file-save/index.html +240 -0
- package/docs-dev/javascript/utils-floating-ui/index.html +240 -0
- package/docs-dev/javascript/utils-id/index.html +240 -0
- package/docs-dev/javascript/utils-pause-youtube-video/index.html +240 -0
- package/docs-dev/javascript/utils-system/index.html +240 -0
- package/docs-dev/sass/base/color/index.html +240 -0
- package/docs-dev/sass/base/elements/index.html +240 -0
- package/docs-dev/sass/base/index/index.html +240 -0
- package/docs-dev/sass/base/index.html +240 -0
- package/docs-dev/sass/base/keyframes/index.html +240 -0
- package/docs-dev/sass/base/layout/index.html +240 -0
- package/docs-dev/sass/base/normalize/index.html +240 -0
- package/docs-dev/sass/base/print/index.html +240 -0
- package/docs-dev/sass/base/root/index.html +240 -0
- package/docs-dev/sass/base/typography/index.html +240 -0
- package/docs-dev/sass/components/accordion/index.html +240 -0
- package/docs-dev/sass/components/adaptive-spacing/index.html +240 -0
- package/docs-dev/sass/components/badge/index.html +240 -0
- package/docs-dev/sass/components/basic-hero/index.html +240 -0
- package/docs-dev/sass/components/button/index.html +240 -0
- package/docs-dev/sass/components/button-group/index.html +5653 -0
- package/docs-dev/sass/components/button-verbose/index.html +240 -0
- package/docs-dev/sass/components/callout/index.html +240 -0
- package/docs-dev/sass/components/captioned-figure/index.html +240 -0
- package/docs-dev/sass/components/card/index.html +240 -0
- package/docs-dev/sass/components/card-grid/index.html +240 -0
- package/docs-dev/sass/components/counter-list/index.html +240 -0
- package/docs-dev/sass/components/css-icon/index.html +240 -0
- package/docs-dev/sass/components/data-grid/index.html +254 -14
- package/docs-dev/sass/components/data-table/index.html +240 -0
- package/docs-dev/sass/components/fill-context/index.html +240 -0
- package/docs-dev/sass/components/flipcard/index.html +240 -0
- package/docs-dev/sass/components/flipcard-grid/index.html +240 -0
- package/docs-dev/sass/components/form-theme/index.html +240 -0
- package/docs-dev/sass/components/headline-label/index.html +5683 -0
- package/docs-dev/sass/components/hero/index.html +240 -0
- package/docs-dev/sass/components/horizontal-rule/index.html +240 -0
- package/docs-dev/sass/components/image-grid/index.html +240 -0
- package/docs-dev/sass/components/index/index.html +254 -10
- package/docs-dev/sass/components/index.html +240 -0
- package/docs-dev/sass/components/links/index.html +240 -0
- package/docs-dev/sass/components/list-inline/index.html +240 -0
- package/docs-dev/sass/components/list-lines/index.html +240 -0
- package/docs-dev/sass/components/list-ordered/index.html +240 -0
- package/docs-dev/sass/components/list-unordered/index.html +240 -0
- package/docs-dev/sass/components/menu-stack/index.html +240 -0
- package/docs-dev/sass/components/modal/index.html +240 -0
- package/docs-dev/sass/components/nav-strip/index.html +240 -0
- package/docs-dev/sass/components/overlay-section/index.html +240 -0
- package/docs-dev/sass/components/pager/index.html +240 -0
- package/docs-dev/sass/components/panel/index.html +5883 -0
- package/docs-dev/sass/components/placeholder-block/index.html +240 -0
- package/docs-dev/sass/components/popover/index.html +240 -0
- package/docs-dev/sass/components/pull-quote/index.html +240 -0
- package/docs-dev/sass/components/rail/index.html +5670 -0
- package/docs-dev/sass/components/ratio-box/index.html +240 -0
- package/docs-dev/sass/components/rule/index.html +240 -0
- package/docs-dev/sass/components/scroll-slider/index.html +240 -0
- package/docs-dev/sass/components/skip-link/index.html +240 -0
- package/docs-dev/sass/components/slider/index.html +240 -0
- package/docs-dev/sass/components/spoke-spinner/index.html +240 -0
- package/docs-dev/sass/components/sticky-list/index.html +240 -0
- package/docs-dev/sass/components/tabs/index.html +240 -0
- package/docs-dev/sass/components/tag/index.html +240 -0
- package/docs-dev/sass/components/tile-button/index.html +240 -0
- package/docs-dev/sass/components/tile-grid/index.html +240 -0
- package/docs-dev/sass/components/tile-grid-overlay/index.html +240 -0
- package/docs-dev/sass/components/vignette/index.html +240 -0
- package/docs-dev/sass/components/wysiwyg/index.html +240 -0
- package/docs-dev/sass/core/breakpoint/index.html +241 -1
- package/docs-dev/sass/core/button/index.html +272 -30
- package/docs-dev/sass/core/color/index.html +240 -0
- package/docs-dev/sass/core/cssvar/index.html +240 -0
- package/docs-dev/sass/core/element/index.html +346 -30
- package/docs-dev/sass/core/index.html +240 -0
- package/docs-dev/sass/core/layout/index.html +240 -0
- package/docs-dev/sass/core/path/index.html +240 -0
- package/docs-dev/sass/core/selector/index.html +240 -0
- package/docs-dev/sass/core/typography/index.html +240 -0
- package/docs-dev/sass/core/units/index.html +240 -0
- package/docs-dev/sass/core/utils/index.html +358 -76
- package/docs-dev/sass/helpers/color/index.html +240 -0
- package/docs-dev/sass/helpers/display/index.html +240 -0
- package/docs-dev/sass/helpers/index/index.html +240 -0
- package/docs-dev/sass/helpers/index.html +240 -0
- package/docs-dev/sass/helpers/typography/index.html +240 -0
- package/docs-dev/sass/helpers/units/index.html +240 -0
- package/docs-dev/sass/helpers/utilities/index.html +240 -0
- package/docs-dev/sass/index.html +240 -0
- 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/scss/_breakpoint.scss +1 -1
- package/scss/_button.scss +7 -5
- package/scss/_element.scss +16 -0
- package/scss/_utils.scss +7 -0
- package/scss/components/_button-group.scss +90 -0
- package/scss/components/_data-grid.scss +0 -3
- package/scss/components/_headline-label.scss +83 -0
- package/scss/components/_index.scss +24 -0
- package/scss/components/_panel.scss +246 -0
- package/scss/components/_rail.scss +120 -0
- package/types/ui/dialog.d.ts.map +1 -1
- package/types/ui/index.d.ts +1 -1
- package/types/ui/resizer.d.ts +85 -12
- package/types/ui/resizer.d.ts.map +1 -1
- package/types/utils/index.d.ts +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.84",
|
|
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/scss/_breakpoint.scss
CHANGED
|
@@ -224,7 +224,7 @@ $sizes: (
|
|
|
224
224
|
/// @include breakpoints.fromEach($breakpoints) using ($props) {
|
|
225
225
|
/// width: map.get($props, "width");
|
|
226
226
|
/// }
|
|
227
|
-
/// @param {String} $breakpoints A map with breakpoints direction will be pulled from each items "direction" property, if direction is missing
|
|
227
|
+
/// @param {String} $breakpoints A map with breakpoints direction will be pulled from each items "direction" property, if direction is missing no breakpoint will wrap the code (as convention we call the default non-breakpoint direction "default")
|
|
228
228
|
/// @param {String} $options A map with options to change the behavior
|
|
229
229
|
/// @param {Boolean} $options.directionRequired Require direction throw error if missing direction
|
|
230
230
|
|
package/scss/_button.scss
CHANGED
|
@@ -94,7 +94,7 @@ $config: (
|
|
|
94
94
|
|
|
95
95
|
$sizes: (
|
|
96
96
|
"small" : (
|
|
97
|
-
"padding": (0.35em
|
|
97
|
+
"padding": (0.35em 1em),
|
|
98
98
|
"min-width": 0,
|
|
99
99
|
"icon-size": 2rem,
|
|
100
100
|
"icon-font-size": 1rem
|
|
@@ -118,9 +118,9 @@ $styles: (
|
|
|
118
118
|
"border-color" : transparent,
|
|
119
119
|
"box-shadow" : none,
|
|
120
120
|
"hover" : (
|
|
121
|
-
"background-color" : "
|
|
122
|
-
"color" :
|
|
123
|
-
"border-color" :
|
|
121
|
+
"background-color" : "control-background",
|
|
122
|
+
"color" : "control",
|
|
123
|
+
"border-color" : "control-border",
|
|
124
124
|
)
|
|
125
125
|
),
|
|
126
126
|
"outline" : (
|
|
@@ -129,7 +129,9 @@ $styles: (
|
|
|
129
129
|
"border-color" : "rule-light",
|
|
130
130
|
"box-shadow" : none,
|
|
131
131
|
"hover" : (
|
|
132
|
-
"background-color" : "
|
|
132
|
+
"background-color" : "control-background",
|
|
133
|
+
"color" : "control",
|
|
134
|
+
"border-color" : "control-border",
|
|
133
135
|
)
|
|
134
136
|
),
|
|
135
137
|
) !default;
|
package/scss/_element.scss
CHANGED
|
@@ -124,11 +124,27 @@ $rule-margins: (
|
|
|
124
124
|
|
|
125
125
|
/// Get a rule style
|
|
126
126
|
/// @param {Map} $changes Map of changes
|
|
127
|
+
/// @return {CssValue} Rule style (css border value)
|
|
127
128
|
|
|
128
129
|
@function get-rule-style($name: "default") {
|
|
129
130
|
@return utils.require-map-get($rule-styles, $name, "element [rule style]");
|
|
130
131
|
}
|
|
131
132
|
|
|
133
|
+
/// Get an optional rule style (which is a border)
|
|
134
|
+
/// - If the value is a string we return the rule style, else we return the value
|
|
135
|
+
/// - Used for things where configuration for say a border can be a user defined border or a string (they want an existing rule-style)
|
|
136
|
+
/// - Except when passing "none"/none this will return as-is (since it's a border property)
|
|
137
|
+
/// @param {*} $value The value to check
|
|
138
|
+
/// @return {*} Rule style if string, else value
|
|
139
|
+
|
|
140
|
+
@function get-optional-rule-style($value) {
|
|
141
|
+
@if (meta.type-of($value) == "string") {
|
|
142
|
+
@return get-rule-style($value);
|
|
143
|
+
} @else {
|
|
144
|
+
@return $value;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
132
148
|
/// Sets rule margin
|
|
133
149
|
/// @param {Map} $changes Map of changes
|
|
134
150
|
|
package/scss/_utils.scss
CHANGED
|
@@ -438,6 +438,13 @@ $config: (
|
|
|
438
438
|
@return $value;
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
+
/// If the value passed is equal to true use the default, else return the value
|
|
442
|
+
/// @param {*} $value The value to check
|
|
443
|
+
/// @param {*} $default The value to return when true
|
|
444
|
+
@function default($value, $default) {
|
|
445
|
+
@return if($value == true, $default, $value);
|
|
446
|
+
}
|
|
447
|
+
|
|
441
448
|
/// Replaces all or one occurrence of a string within a string
|
|
442
449
|
/// @param {String} $string String to operate on
|
|
443
450
|
/// @param {String} $find String to find within string
|