@acorex/cdk 22.1.0-next.31 → 22.1.0-next.33

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 (54) hide show
  1. package/fesm2022/acorex-cdk-accordion.mjs +19 -19
  2. package/fesm2022/acorex-cdk-carousel.mjs +25 -7
  3. package/fesm2022/acorex-cdk-carousel.mjs.map +1 -1
  4. package/fesm2022/acorex-cdk-clipboard.mjs +6 -6
  5. package/fesm2022/acorex-cdk-common.mjs +169 -93
  6. package/fesm2022/acorex-cdk-common.mjs.map +1 -1
  7. package/fesm2022/acorex-cdk-dom.mjs +3 -3
  8. package/fesm2022/acorex-cdk-drag-drop.mjs +210 -68
  9. package/fesm2022/acorex-cdk-drag-drop.mjs.map +1 -1
  10. package/fesm2022/acorex-cdk-drawer.mjs +10 -10
  11. package/fesm2022/acorex-cdk-focus-trap.mjs +3 -3
  12. package/fesm2022/acorex-cdk-full-screen.mjs +26 -147
  13. package/fesm2022/acorex-cdk-full-screen.mjs.map +1 -1
  14. package/fesm2022/acorex-cdk-gesture.mjs +36 -7
  15. package/fesm2022/acorex-cdk-gesture.mjs.map +1 -1
  16. package/fesm2022/acorex-cdk-highlight.mjs +108 -0
  17. package/fesm2022/acorex-cdk-highlight.mjs.map +1 -0
  18. package/fesm2022/acorex-cdk-horizontal-scroll.mjs +104 -44
  19. package/fesm2022/acorex-cdk-horizontal-scroll.mjs.map +1 -1
  20. package/fesm2022/acorex-cdk-input-mask.mjs +3 -3
  21. package/fesm2022/acorex-cdk-list-navigation.mjs +10 -10
  22. package/fesm2022/acorex-cdk-outline.mjs +277 -74
  23. package/fesm2022/acorex-cdk-outline.mjs.map +1 -1
  24. package/fesm2022/acorex-cdk-overlay.mjs +192 -18
  25. package/fesm2022/acorex-cdk-overlay.mjs.map +1 -1
  26. package/fesm2022/acorex-cdk-pan-view.mjs +3 -3
  27. package/fesm2022/acorex-cdk-resizable.mjs +475 -183
  28. package/fesm2022/acorex-cdk-resizable.mjs.map +1 -1
  29. package/fesm2022/acorex-cdk-selection.mjs +10 -10
  30. package/fesm2022/acorex-cdk-shimmer.mjs +220 -0
  31. package/fesm2022/acorex-cdk-shimmer.mjs.map +1 -0
  32. package/fesm2022/acorex-cdk-sliding-item.mjs +3 -3
  33. package/fesm2022/acorex-cdk-sticky.mjs +3 -3
  34. package/fesm2022/acorex-cdk-uploader.mjs +9 -9
  35. package/fesm2022/acorex-cdk-virtual-scroll.mjs +10 -10
  36. package/fesm2022/acorex-cdk-z-index.mjs +3 -3
  37. package/package.json +10 -6
  38. package/shimmer/README.md +11 -0
  39. package/types/acorex-cdk-carousel.d.ts +2 -0
  40. package/types/acorex-cdk-clipboard.d.ts +1 -1
  41. package/types/acorex-cdk-common.d.ts +36 -19
  42. package/types/acorex-cdk-drag-drop.d.ts +31 -4
  43. package/types/acorex-cdk-full-screen.d.ts +18 -43
  44. package/types/acorex-cdk-gesture.d.ts +13 -1
  45. package/types/acorex-cdk-highlight.d.ts +54 -0
  46. package/types/acorex-cdk-horizontal-scroll.d.ts +23 -9
  47. package/types/acorex-cdk-outline.d.ts +20 -0
  48. package/types/acorex-cdk-overlay.d.ts +47 -4
  49. package/types/acorex-cdk-resizable.d.ts +64 -30
  50. package/types/acorex-cdk-shimmer.d.ts +68 -0
  51. package/types/acorex-cdk-uploader.d.ts +1 -1
  52. package/fesm2022/acorex-cdk-double-click.mjs +0 -178
  53. package/fesm2022/acorex-cdk-double-click.mjs.map +0 -1
  54. package/types/acorex-cdk-double-click.d.ts +0 -66
@@ -12,39 +12,45 @@ class AXResizableDirective {
12
12
  this.zone = inject(NgZone);
13
13
  this.document = inject(DOCUMENT);
14
14
  this.platformID = inject(PLATFORM_ID);
15
+ this.resizeHandles = new Map();
15
16
  this.isResizing = signal(false, /* @ts-ignore */
16
17
  ...(ngDevMode ? [{ debugName: "isResizing" }] : /* istanbul ignore next */ []));
18
+ this.activeHandle = null;
17
19
  this.initialElementWidth = 0;
18
- this.startMoveWidth = 0;
20
+ this.initialElementHeight = 0;
21
+ this.startX = 0;
22
+ this.startY = 0;
23
+ this.startWidth = 0;
24
+ this.startHeight = 0;
25
+ this.startRatio = 1;
19
26
  this.subscriptions = new Subscription();
20
- // Bound event handlers to maintain reference for cleanup
21
- this.boundMouseDown = this.onMouseDown.bind(this);
22
- this.boundMouseMove = this.onMouseMove.bind(this);
23
- this.boundMouseUp = this.onMouseUp.bind(this);
24
- this.boundMouseEnter = this.onMouseEnter.bind(this);
25
- this.boundMouseLeave = this.onMouseLeave.bind(this);
27
+ this.boundPointerDown = this.onPointerDown.bind(this);
28
+ this.boundPointerMove = this.onPointerMove.bind(this);
29
+ this.boundPointerUp = this.onPointerUp.bind(this);
30
+ this.boundPointerEnter = this.onPointerEnter.bind(this);
31
+ this.boundPointerLeave = this.onPointerLeave.bind(this);
26
32
  this.boundDoubleClick = this.onDoubleClick.bind(this);
27
- this.resizeObserver = new ResizeObserver((entries) => {
28
- const parentElement = this.hostElement.parentElement;
29
- if (!parentElement)
30
- return;
31
- for (const entry of entries) {
32
- if (entry.target === parentElement && this.maxWidth() === Infinity) {
33
- this.maxWidth.set(entry.contentRect.width);
34
- break;
35
- }
36
- }
37
- });
33
+ this.isRTL = signal(false, /* @ts-ignore */
34
+ ...(ngDevMode ? [{ debugName: "isRTL" }] : /* istanbul ignore next */ []));
38
35
  /** Define if directive is active or not */
39
36
  this.axResizable = model(true, /* @ts-ignore */
40
37
  ...(ngDevMode ? [{ debugName: "axResizable" }] : /* istanbul ignore next */ []));
38
+ /** Logical handles to render. Defaults to the inline-end edge. */
39
+ this.handles = model(['end'], /* @ts-ignore */
40
+ ...(ngDevMode ? [{ debugName: "handles" }] : /* istanbul ignore next */ []));
41
41
  /** Minimum width for the resizable element. */
42
42
  this.minWidth = model(100, /* @ts-ignore */
43
43
  ...(ngDevMode ? [{ debugName: "minWidth" }] : /* istanbul ignore next */ []));
44
44
  /** Maximum width for the resizable element. Defaults to parent width if not provided. */
45
45
  this.maxWidth = model(Infinity, /* @ts-ignore */
46
46
  ...(ngDevMode ? [{ debugName: "maxWidth" }] : /* istanbul ignore next */ []));
47
- /** Behavior on double-click: 'reset' or 'maximize'. */
47
+ /** Minimum height for the resizable element. */
48
+ this.minHeight = model(100, /* @ts-ignore */
49
+ ...(ngDevMode ? [{ debugName: "minHeight" }] : /* istanbul ignore next */ []));
50
+ /** Maximum height for the resizable element. Defaults to parent height if not provided. */
51
+ this.maxHeight = model(Infinity, /* @ts-ignore */
52
+ ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
53
+ /** Behavior on double-click: 'reset', 'maximize', or 'fit'. */
48
54
  this.dblClickAction = model('reset', /* @ts-ignore */
49
55
  ...(ngDevMode ? [{ debugName: "dblClickAction" }] : /* istanbul ignore next */ []));
50
56
  /** Define initial width for the element. */
@@ -53,227 +59,365 @@ class AXResizableDirective {
53
59
  /** Define reset width for the element. */
54
60
  this.defaultWidth = model(null, /* @ts-ignore */
55
61
  ...(ngDevMode ? [{ debugName: "defaultWidth" }] : /* istanbul ignore next */ []));
62
+ /** Define initial height for the element. */
63
+ this.height = model(null, /* @ts-ignore */
64
+ ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
65
+ /** Define reset height for the element. */
66
+ this.defaultHeight = model(null, /* @ts-ignore */
67
+ ...(ngDevMode ? [{ debugName: "defaultHeight" }] : /* istanbul ignore next */ []));
68
+ /** Lock the element's aspect ratio from the size captured at pointer-down. */
69
+ this.lockAspectRatio = model(false, /* @ts-ignore */
70
+ ...(ngDevMode ? [{ debugName: "lockAspectRatio" }] : /* istanbul ignore next */ []));
56
71
  /** Event emitted when resizing starts. */
57
72
  this.onResizingStarted = output();
58
73
  /** Event emitted when resizing ends. */
59
74
  this.onResizingEnded = output();
60
75
  /** Event emitted on double-click. */
61
76
  this.onResizingDblClick = output();
62
- this.isRTL = signal(AXHtmlUtil.isRtl(this.document.documentElement), /* @ts-ignore */
63
- ...(ngDevMode ? [{ debugName: "isRTL" }] : /* istanbul ignore next */ []));
64
77
  this.isBrowser = isPlatformBrowser(this.platformID);
65
78
  this.hostElement = this.el.nativeElement;
79
+ this.isRTL.set(AXHtmlUtil.isRtl(this.document.documentElement));
66
80
  this.subscriptions.add(this.platformService.directionChange.subscribe((i) => {
67
81
  this.isRTL.set(i.data === 'rtl');
68
- if (this.resizeHandle) {
69
- this.updateHandlePosition();
70
- }
71
82
  }));
72
- if (this.isBrowser) {
73
- effect(() => {
74
- if (this.isResizing()) {
75
- return;
83
+ if (!this.isBrowser) {
84
+ return;
85
+ }
86
+ this.resizeObserver = new ResizeObserver((entries) => {
87
+ const parentElement = this.hostElement.parentElement;
88
+ if (!parentElement) {
89
+ return;
90
+ }
91
+ for (const entry of entries) {
92
+ if (entry.target !== parentElement) {
93
+ continue;
76
94
  }
77
- const resolvedWidth = this.width() ?? this.defaultWidth();
78
- if (resolvedWidth !== null) {
79
- this.applyElementWidth(resolvedWidth);
95
+ if (this.maxWidth() === Infinity) {
96
+ this.maxWidth.set(entry.contentRect.width);
80
97
  }
81
- });
82
- }
98
+ if (this.maxHeight() === Infinity) {
99
+ this.maxHeight.set(entry.contentRect.height);
100
+ }
101
+ }
102
+ });
103
+ effect(() => {
104
+ const isActive = this.axResizable();
105
+ const handles = this.handles();
106
+ this.reconcileHandles(isActive, handles);
107
+ });
108
+ effect(() => {
109
+ this.isRTL();
110
+ this.updateAllHandlePositions();
111
+ });
112
+ effect(() => {
113
+ if (this.isResizing()) {
114
+ return;
115
+ }
116
+ this.applySizeFromModel();
117
+ });
83
118
  }
84
119
  ngAfterViewInit() {
85
- if (!this.isBrowser)
120
+ if (!this.isBrowser) {
86
121
  return;
122
+ }
87
123
  this.initialElementWidth = this.hostElement.offsetWidth;
88
- this.applyWidthFromModel();
124
+ this.initialElementHeight = this.hostElement.offsetHeight;
125
+ this.applySizeFromModel();
126
+ const parentElement = this.hostElement.parentElement;
89
127
  if (this.maxWidth() === Infinity) {
90
- const parentWidth = this.hostElement.parentElement?.offsetWidth;
128
+ const parentWidth = parentElement?.offsetWidth;
91
129
  if (parentWidth) {
92
130
  this.maxWidth.set(parentWidth);
93
131
  }
94
132
  }
95
- const parentElement = this.hostElement.parentElement;
133
+ if (this.maxHeight() === Infinity) {
134
+ const parentHeight = parentElement?.offsetHeight;
135
+ if (parentHeight) {
136
+ this.maxHeight.set(parentHeight);
137
+ }
138
+ }
96
139
  if (parentElement) {
97
- this.resizeObserver.observe(parentElement);
140
+ this.resizeObserver?.observe(parentElement);
98
141
  }
99
- this.createResizeHandle();
100
- this.setupResizableState();
101
142
  }
102
143
  ngOnDestroy() {
103
144
  this.subscriptions.unsubscribe();
104
- this.resizeObserver.disconnect();
105
- this.cleanupEventListeners();
106
- }
107
- setupResizableState() {
108
- this.subscriptions.add(this.axResizable.subscribe((isActive) => {
109
- if (!isActive) {
110
- this.applyWidthFromModel();
111
- this.cleanupEventListeners();
112
- }
113
- else {
114
- this.applyWidthFromModel();
115
- this.createResizeHandle();
116
- }
117
- }));
145
+ this.resizeObserver?.disconnect();
146
+ this.destroyAllHandles();
147
+ this.document.body.style.cursor = '';
118
148
  }
119
- applyWidthFromModel() {
120
- const width = this.width();
121
- if (width !== null) {
122
- this.applyElementWidth(width);
149
+ reconcileHandles(isActive, handles) {
150
+ if (!this.isBrowser) {
123
151
  return;
124
152
  }
125
- const defaultWidth = this.defaultWidth();
126
- if (defaultWidth !== null) {
127
- this.applyElementWidth(defaultWidth);
153
+ if (!isActive) {
154
+ this.stopResizing();
155
+ this.destroyAllHandles();
156
+ this.applySizeFromModel();
157
+ return;
158
+ }
159
+ this.hostElement.style.position = 'relative';
160
+ const unique = [...new Set(handles)];
161
+ const desired = new Set(unique);
162
+ for (const [type, element] of this.resizeHandles) {
163
+ if (!desired.has(type)) {
164
+ this.destroyHandle(type, element);
165
+ }
166
+ }
167
+ for (const type of unique) {
168
+ if (!this.resizeHandles.has(type)) {
169
+ this.createHandle(type);
170
+ }
128
171
  }
129
172
  }
130
- applyElementWidth(width) {
131
- this.hostElement.style.width = `${width}px`;
173
+ createHandle(type) {
174
+ const handle = this.document.createElement('div');
175
+ handle.classList.add('ax-resizable-handler', `ax-resizable-handler--${type}`);
176
+ handle.dataset['axResizeHandle'] = type;
177
+ this.hostElement.appendChild(handle);
178
+ this.applyHandleStyles(handle, type);
179
+ this.attachHandleListeners(handle);
180
+ this.resizeHandles.set(type, handle);
132
181
  }
133
- createResizeHandle() {
134
- if (!this.axResizable() || this.resizeHandle)
135
- return;
136
- this.hostElement.style.position = 'relative';
137
- this.resizeHandle = this.document.createElement('div');
138
- this.resizeHandle.classList.add('ax-resizable-handler');
139
- this.hostElement.appendChild(this.resizeHandle);
140
- this.applyHandleStyles();
141
- this.attachEventListeners();
182
+ attachHandleListeners(handle) {
183
+ this.zone.runOutsideAngular(() => {
184
+ handle.addEventListener('pointerdown', this.boundPointerDown);
185
+ handle.addEventListener('pointermove', this.boundPointerMove);
186
+ handle.addEventListener('pointerup', this.boundPointerUp);
187
+ handle.addEventListener('pointercancel', this.boundPointerUp);
188
+ handle.addEventListener('pointerenter', this.boundPointerEnter);
189
+ handle.addEventListener('pointerleave', this.boundPointerLeave);
190
+ handle.addEventListener('dblclick', this.boundDoubleClick);
191
+ });
142
192
  }
143
- applyHandleStyles() {
144
- if (!this.resizeHandle)
145
- return;
146
- Object.assign(this.resizeHandle.style, {
147
- width: STYLES.handlerWidth,
148
- backgroundColor: STYLES.backgroundColor,
193
+ destroyHandle(type, handle) {
194
+ handle.removeEventListener('pointerdown', this.boundPointerDown);
195
+ handle.removeEventListener('pointermove', this.boundPointerMove);
196
+ handle.removeEventListener('pointerup', this.boundPointerUp);
197
+ handle.removeEventListener('pointercancel', this.boundPointerUp);
198
+ handle.removeEventListener('pointerenter', this.boundPointerEnter);
199
+ handle.removeEventListener('pointerleave', this.boundPointerLeave);
200
+ handle.removeEventListener('dblclick', this.boundDoubleClick);
201
+ handle.remove();
202
+ this.resizeHandles.delete(type);
203
+ }
204
+ destroyAllHandles() {
205
+ for (const [type, handle] of [...this.resizeHandles]) {
206
+ this.destroyHandle(type, handle);
207
+ }
208
+ }
209
+ applyHandleStyles(handle, type) {
210
+ const isCorner = type.includes('-');
211
+ Object.assign(handle.style, {
149
212
  position: 'absolute',
150
- top: '0',
151
- bottom: '0',
152
- cursor: STYLES.cursor,
153
- zIndex: STYLES.zIndex,
213
+ backgroundColor: STYLES.backgroundColor,
214
+ zIndex: isCorner ? STYLES.zIndexCorner : STYLES.zIndex,
154
215
  transition: STYLES.transition,
155
216
  borderRadius: STYLES.borderRadius,
156
217
  userSelect: 'none',
218
+ touchAction: 'none',
219
+ cursor: this.getCursorForHandle(type),
220
+ left: '',
221
+ right: '',
222
+ top: '',
223
+ bottom: '',
224
+ width: '',
225
+ height: '',
157
226
  });
158
- this.updateHandlePosition();
227
+ this.positionHandle(handle, type);
159
228
  }
160
- updateHandlePosition() {
161
- if (!this.resizeHandle)
162
- return;
163
- const isRTL = this.isRTL();
164
- if (isRTL) {
165
- this.resizeHandle.style.left = '0';
166
- this.resizeHandle.style.right = '';
229
+ updateAllHandlePositions() {
230
+ for (const [type, handle] of this.resizeHandles) {
231
+ handle.style.cursor = this.getCursorForHandle(type);
232
+ this.positionHandle(handle, type);
233
+ }
234
+ }
235
+ positionHandle(handle, type) {
236
+ const rtl = this.isRTL();
237
+ switch (type) {
238
+ case 'start':
239
+ case 'end':
240
+ handle.style.top = '0';
241
+ handle.style.bottom = '0';
242
+ handle.style.width = STYLES.handlerWidth;
243
+ this.applyInlineSide(handle, type, rtl);
244
+ break;
245
+ case 'top':
246
+ case 'bottom':
247
+ handle.style.left = '0';
248
+ handle.style.right = '0';
249
+ handle.style.height = STYLES.handlerHeight;
250
+ if (type === 'top') {
251
+ handle.style.top = '0';
252
+ handle.style.bottom = '';
253
+ }
254
+ else {
255
+ handle.style.bottom = '0';
256
+ handle.style.top = '';
257
+ }
258
+ break;
259
+ default: {
260
+ const [vertical, horizontal] = type.split('-');
261
+ handle.style.width = STYLES.cornerSize;
262
+ handle.style.height = STYLES.cornerSize;
263
+ if (vertical === 'top') {
264
+ handle.style.top = '0';
265
+ handle.style.bottom = '';
266
+ }
267
+ else {
268
+ handle.style.bottom = '0';
269
+ handle.style.top = '';
270
+ }
271
+ this.applyInlineSide(handle, horizontal, rtl);
272
+ break;
273
+ }
274
+ }
275
+ }
276
+ applyInlineSide(element, side, rtl) {
277
+ const physicalLeft = (side === 'start' && !rtl) || (side === 'end' && rtl);
278
+ if (physicalLeft) {
279
+ element.style.left = '0';
280
+ element.style.right = '';
167
281
  }
168
282
  else {
169
- this.resizeHandle.style.right = '0';
170
- this.resizeHandle.style.left = '';
283
+ element.style.right = '0';
284
+ element.style.left = '';
171
285
  }
172
286
  }
173
- attachEventListeners() {
174
- if (!this.resizeHandle)
175
- return;
176
- const handle = this.resizeHandle;
177
- this.zone.runOutsideAngular(() => {
178
- handle.addEventListener('mousedown', this.boundMouseDown);
179
- handle.addEventListener('mouseenter', this.boundMouseEnter);
180
- handle.addEventListener('mouseleave', this.boundMouseLeave);
181
- handle.addEventListener('dblclick', this.boundDoubleClick);
182
- this.document.addEventListener('mousemove', this.boundMouseMove);
183
- this.document.addEventListener('mouseup', this.boundMouseUp);
184
- });
287
+ applySizeFromModel() {
288
+ const width = this.width() ?? this.defaultWidth();
289
+ const height = this.height() ?? this.defaultHeight();
290
+ this.applySize(width, height);
185
291
  }
186
- cleanupEventListeners() {
187
- if (this.resizeHandle) {
188
- this.resizeHandle.removeEventListener('mousedown', this.boundMouseDown);
189
- this.resizeHandle.removeEventListener('mouseenter', this.boundMouseEnter);
190
- this.resizeHandle.removeEventListener('mouseleave', this.boundMouseLeave);
191
- this.resizeHandle.removeEventListener('dblclick', this.boundDoubleClick);
192
- this.resizeHandle.remove();
193
- this.resizeHandle = undefined;
194
- }
195
- this.document.removeEventListener('mousemove', this.boundMouseMove);
196
- this.document.removeEventListener('mouseup', this.boundMouseUp);
197
- this.document.body.style.cursor = '';
292
+ applySize(width, height) {
293
+ if (width !== null) {
294
+ this.hostElement.style.width = `${width}px`;
295
+ }
296
+ if (height !== null) {
297
+ this.hostElement.style.height = `${height}px`;
298
+ }
198
299
  }
199
- onMouseDown(event) {
200
- if (!this.resizeHandle)
201
- return;
202
- const handleRect = this.resizeHandle.getBoundingClientRect();
203
- if (event.clientX < handleRect.left || event.clientX > handleRect.right)
300
+ onPointerDown(event) {
301
+ const handleType = this.getHandleType(event);
302
+ const handle = event.currentTarget;
303
+ if (!handleType || !handle) {
204
304
  return;
305
+ }
205
306
  event.preventDefault();
307
+ event.stopPropagation();
308
+ try {
309
+ handle.setPointerCapture?.(event.pointerId);
310
+ }
311
+ catch {
312
+ // Pointer capture can throw for synthetic or inactive pointers.
313
+ }
314
+ this.activeHandle = handleType;
206
315
  this.isResizing.set(true);
207
- this.document.body.style.cursor = STYLES.cursorActive;
208
- this.resizeHandle.style.backgroundColor = STYLES.backgroundColorActive;
209
- this.startMoveWidth = this.hostElement.offsetWidth;
316
+ this.startX = event.clientX;
317
+ this.startY = event.clientY;
318
+ this.startWidth = this.hostElement.offsetWidth;
319
+ this.startHeight = this.hostElement.offsetHeight;
320
+ this.startRatio = this.startHeight > 0 ? this.startWidth / this.startHeight : 1;
321
+ this.document.body.style.cursor = this.getActiveCursor(handleType);
322
+ handle.style.backgroundColor = STYLES.backgroundColorActive;
323
+ const size = { width: this.startWidth, height: this.startHeight };
210
324
  this.zone.run(() => {
211
325
  this.onResizingStarted.emit({
212
326
  component: this,
213
327
  htmlElement: this.hostElement,
214
328
  isUserInteraction: true,
215
329
  name: 'resizingStarted',
216
- value: this.startMoveWidth,
217
- oldValue: this.startMoveWidth,
330
+ value: size,
331
+ oldValue: size,
218
332
  });
219
333
  });
220
334
  }
221
- onMouseMove(event) {
222
- if (!this.isResizing())
335
+ onPointerMove(event) {
336
+ if (!this.isResizing() || !this.activeHandle) {
223
337
  return;
224
- const rect = this.hostElement.getBoundingClientRect();
225
- const isRTL = this.isRTL();
226
- let newWidth = isRTL ? rect.right - event.clientX : event.clientX - rect.left;
227
- newWidth = Math.max(this.minWidth(), Math.min(newWidth, this.maxWidth()));
228
- if (newWidth !== this.hostElement.offsetWidth) {
229
- this.hostElement.style.width = `${newWidth}px`;
230
338
  }
339
+ const axes = getHandleAxes(this.activeHandle);
340
+ const lock = this.lockAspectRatio();
341
+ const next = this.computeSize(event, this.activeHandle);
342
+ event.preventDefault();
343
+ this.applySize(axes.horizontal || lock ? next.width : null, axes.vertical || lock ? next.height : null);
231
344
  }
232
- onMouseUp() {
233
- if (!this.isResizing() || !this.resizeHandle)
345
+ onPointerUp(event) {
346
+ if (!this.isResizing()) {
234
347
  return;
348
+ }
349
+ const handle = event.currentTarget;
350
+ try {
351
+ handle?.releasePointerCapture?.(event.pointerId);
352
+ }
353
+ catch {
354
+ // Pointer capture may already have been released.
355
+ }
356
+ const axes = this.activeHandle ? getHandleAxes(this.activeHandle) : null;
357
+ const current = this.getCurrentSize();
358
+ const oldValue = { width: this.startWidth, height: this.startHeight };
235
359
  this.document.body.style.cursor = '';
236
- this.resizeHandle.style.backgroundColor = STYLES.backgroundColor;
237
- const currentWidth = this.hostElement.offsetWidth;
360
+ if (handle) {
361
+ handle.style.backgroundColor = STYLES.backgroundColor;
362
+ }
238
363
  this.zone.run(() => {
239
- this.width.set(currentWidth);
364
+ if (axes?.horizontal) {
365
+ this.width.set(current.width);
366
+ }
367
+ if (axes?.vertical) {
368
+ this.height.set(current.height);
369
+ }
240
370
  this.onResizingEnded.emit({
241
371
  component: this,
242
372
  htmlElement: this.hostElement,
243
373
  isUserInteraction: true,
244
374
  name: 'resizingEnded',
245
- value: currentWidth,
246
- oldValue: this.startMoveWidth,
375
+ value: current,
376
+ oldValue,
247
377
  });
248
378
  });
249
- this.isResizing.set(false);
379
+ this.stopResizing();
250
380
  }
251
- onMouseEnter() {
252
- if (!this.isResizing() && this.resizeHandle) {
253
- this.resizeHandle.style.backgroundColor = STYLES.backgroundColorHover;
381
+ onPointerEnter(event) {
382
+ if (this.isResizing()) {
383
+ return;
384
+ }
385
+ const handle = event.currentTarget;
386
+ if (handle) {
387
+ handle.style.backgroundColor = STYLES.backgroundColorHover;
254
388
  }
255
389
  }
256
- onMouseLeave() {
257
- if (!this.isResizing() && this.resizeHandle) {
258
- this.resizeHandle.style.backgroundColor = STYLES.backgroundColor;
390
+ onPointerLeave(event) {
391
+ if (this.isResizing()) {
392
+ return;
393
+ }
394
+ const handle = event.currentTarget;
395
+ if (handle) {
396
+ handle.style.backgroundColor = STYLES.backgroundColor;
259
397
  }
260
398
  }
261
- onDoubleClick() {
262
- const elementWidth = this.hostElement.offsetWidth;
399
+ onDoubleClick(event) {
400
+ const handleType = this.getHandleType(event);
401
+ if (!handleType) {
402
+ return;
403
+ }
404
+ event.preventDefault();
405
+ const axes = getHandleAxes(handleType);
406
+ const oldValue = this.getCurrentSize();
263
407
  const action = this.dblClickAction();
264
- let newWidth;
408
+ let value;
265
409
  switch (action) {
266
410
  case 'reset':
267
- newWidth = this.resetToInitialWidth();
411
+ value = this.resetToInitialSize(axes);
268
412
  break;
269
413
  case 'maximize':
270
- newWidth = this.maximizeToMaxWidth();
414
+ value = this.maximizeToMaxSize(axes);
271
415
  break;
272
416
  case 'fit':
273
- newWidth = this.fitToContent();
417
+ value = this.fitToContent(axes);
274
418
  break;
275
419
  default:
276
- newWidth = elementWidth;
420
+ value = oldValue;
277
421
  }
278
422
  this.zone.run(() => {
279
423
  this.onResizingDblClick.emit({
@@ -281,53 +425,201 @@ class AXResizableDirective {
281
425
  htmlElement: this.hostElement,
282
426
  isUserInteraction: true,
283
427
  name: 'onResizingDblClick',
284
- oldValue: elementWidth,
285
- value: newWidth,
428
+ oldValue,
429
+ value,
286
430
  });
287
431
  });
288
432
  }
289
- resetToInitialWidth() {
290
- const defaultWidth = this.defaultWidth();
291
- if (defaultWidth !== null) {
292
- this.applyElementWidth(defaultWidth);
293
- return defaultWidth;
294
- }
295
- const initialWidth = this.width();
296
- if (initialWidth !== null) {
297
- this.applyElementWidth(initialWidth);
298
- return initialWidth;
299
- }
300
- this.applyElementWidth(this.initialElementWidth);
301
- return this.initialElementWidth;
433
+ computeSize(event, handle) {
434
+ const dx = event.clientX - this.startX;
435
+ const dy = event.clientY - this.startY;
436
+ const rtl = this.isRTL();
437
+ const axes = getHandleAxes(handle);
438
+ const lock = this.lockAspectRatio();
439
+ let width = this.startWidth;
440
+ let height = this.startHeight;
441
+ if (axes.horizontal === 'end') {
442
+ width = this.startWidth + (rtl ? -dx : dx);
443
+ }
444
+ else if (axes.horizontal === 'start') {
445
+ width = this.startWidth + (rtl ? dx : -dx);
446
+ }
447
+ if (axes.vertical === 'bottom') {
448
+ height = this.startHeight + dy;
449
+ }
450
+ else if (axes.vertical === 'top') {
451
+ height = this.startHeight - dy;
452
+ }
453
+ if (lock) {
454
+ const ratio = this.startRatio > 0 ? this.startRatio : 1;
455
+ if (axes.horizontal && axes.vertical) {
456
+ const widthDelta = Math.abs(width - this.startWidth);
457
+ const heightDelta = Math.abs(height - this.startHeight);
458
+ if (widthDelta >= heightDelta) {
459
+ height = width / ratio;
460
+ }
461
+ else {
462
+ width = height * ratio;
463
+ }
464
+ }
465
+ else if (axes.horizontal) {
466
+ height = width / ratio;
467
+ }
468
+ else if (axes.vertical) {
469
+ width = height * ratio;
470
+ }
471
+ }
472
+ return this.clampSize(width, height, lock);
473
+ }
474
+ clampSize(width, height, lock) {
475
+ const minW = this.minWidth();
476
+ const maxW = this.maxWidth();
477
+ const minH = this.minHeight();
478
+ const maxH = this.maxHeight();
479
+ if (!lock) {
480
+ return {
481
+ width: Math.max(minW, Math.min(width, maxW)),
482
+ height: Math.max(minH, Math.min(height, maxH)),
483
+ };
484
+ }
485
+ const ratio = this.startRatio > 0 ? this.startRatio : 1;
486
+ width = Math.max(minW, width);
487
+ height = width / ratio;
488
+ if (height < minH) {
489
+ height = minH;
490
+ width = height * ratio;
491
+ }
492
+ if (width > maxW) {
493
+ width = maxW;
494
+ height = width / ratio;
495
+ }
496
+ if (height > maxH) {
497
+ height = maxH;
498
+ width = height * ratio;
499
+ }
500
+ if (width < minW) {
501
+ width = minW;
502
+ height = width / ratio;
503
+ }
504
+ if (height < minH) {
505
+ height = minH;
506
+ width = height * ratio;
507
+ }
508
+ return {
509
+ width: Math.max(minW, Math.min(width, maxW)),
510
+ height: Math.max(minH, Math.min(height, maxH)),
511
+ };
512
+ }
513
+ resetToInitialSize(axes) {
514
+ const size = this.getCurrentSize();
515
+ if (axes.horizontal) {
516
+ const next = this.defaultWidth() ?? this.width() ?? this.initialElementWidth;
517
+ this.applySize(next, null);
518
+ size.width = next;
519
+ }
520
+ if (axes.vertical) {
521
+ const next = this.defaultHeight() ?? this.height() ?? this.initialElementHeight;
522
+ this.applySize(null, next);
523
+ size.height = next;
524
+ }
525
+ return size;
526
+ }
527
+ maximizeToMaxSize(axes) {
528
+ const size = this.getCurrentSize();
529
+ if (axes.horizontal && this.maxWidth() !== Infinity) {
530
+ this.applySize(this.maxWidth(), null);
531
+ size.width = this.maxWidth();
532
+ }
533
+ if (axes.vertical && this.maxHeight() !== Infinity) {
534
+ this.applySize(null, this.maxHeight());
535
+ size.height = this.maxHeight();
536
+ }
537
+ return size;
538
+ }
539
+ fitToContent(axes) {
540
+ if (axes.horizontal) {
541
+ this.hostElement.style.width = 'fit-content';
542
+ }
543
+ if (axes.vertical) {
544
+ this.hostElement.style.height = 'fit-content';
545
+ }
546
+ return this.getCurrentSize();
302
547
  }
303
- maximizeToMaxWidth() {
304
- const maxWidth = this.maxWidth();
305
- if (maxWidth !== Infinity) {
306
- this.applyElementWidth(maxWidth);
548
+ getCurrentSize() {
549
+ return {
550
+ width: this.hostElement.offsetWidth,
551
+ height: this.hostElement.offsetHeight,
552
+ };
553
+ }
554
+ getHandleType(event) {
555
+ const target = event.currentTarget;
556
+ const value = target?.dataset['axResizeHandle'];
557
+ return value ?? null;
558
+ }
559
+ getCursorForHandle(type) {
560
+ if (type === 'start' || type === 'end') {
561
+ return STYLES.cursorHorizontal;
562
+ }
563
+ if (type === 'top' || type === 'bottom') {
564
+ return STYLES.cursorVertical;
565
+ }
566
+ const nwseInLtr = type === 'bottom-end' || type === 'top-start';
567
+ const useNwse = this.isRTL() ? !nwseInLtr : nwseInLtr;
568
+ return useNwse ? STYLES.cursorCorner : STYLES.cursorCornerAlt;
569
+ }
570
+ getActiveCursor(type) {
571
+ if (type === 'start' || type === 'end') {
572
+ return STYLES.cursorActive;
307
573
  }
308
- return maxWidth;
574
+ return this.getCursorForHandle(type);
309
575
  }
310
- fitToContent() {
311
- this.hostElement.style.width = 'fit-content';
312
- return this.hostElement.clientWidth;
576
+ stopResizing() {
577
+ this.activeHandle = null;
578
+ this.isResizing.set(false);
313
579
  }
314
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXResizableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
315
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.8", type: AXResizableDirective, isStandalone: true, selector: "[axResizable]", inputs: { axResizable: { classPropertyName: "axResizable", publicName: "axResizable", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, dblClickAction: { classPropertyName: "dblClickAction", publicName: "dblClickAction", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, defaultWidth: { classPropertyName: "defaultWidth", publicName: "defaultWidth", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { axResizable: "axResizableChange", minWidth: "minWidthChange", maxWidth: "maxWidthChange", dblClickAction: "dblClickActionChange", width: "widthChange", defaultWidth: "defaultWidthChange", onResizingStarted: "onResizingStarted", onResizingEnded: "onResizingEnded", onResizingDblClick: "onResizingDblClick" }, ngImport: i0 }); }
580
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: AXResizableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
581
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: AXResizableDirective, isStandalone: true, selector: "[axResizable]", inputs: { axResizable: { classPropertyName: "axResizable", publicName: "axResizable", isSignal: true, isRequired: false, transformFunction: null }, handles: { classPropertyName: "handles", publicName: "handles", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, dblClickAction: { classPropertyName: "dblClickAction", publicName: "dblClickAction", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, defaultWidth: { classPropertyName: "defaultWidth", publicName: "defaultWidth", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, defaultHeight: { classPropertyName: "defaultHeight", publicName: "defaultHeight", isSignal: true, isRequired: false, transformFunction: null }, lockAspectRatio: { classPropertyName: "lockAspectRatio", publicName: "lockAspectRatio", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { axResizable: "axResizableChange", handles: "handlesChange", minWidth: "minWidthChange", maxWidth: "maxWidthChange", minHeight: "minHeightChange", maxHeight: "maxHeightChange", dblClickAction: "dblClickActionChange", width: "widthChange", defaultWidth: "defaultWidthChange", height: "heightChange", defaultHeight: "defaultHeightChange", lockAspectRatio: "lockAspectRatioChange", onResizingStarted: "onResizingStarted", onResizingEnded: "onResizingEnded", onResizingDblClick: "onResizingDblClick" }, ngImport: i0 }); }
316
582
  }
317
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: AXResizableDirective, decorators: [{
583
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: AXResizableDirective, decorators: [{
318
584
  type: Directive,
319
585
  args: [{
320
586
  selector: '[axResizable]',
321
587
  }]
322
- }], ctorParameters: () => [], propDecorators: { axResizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "axResizable", required: false }] }, { type: i0.Output, args: ["axResizableChange"] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }, { type: i0.Output, args: ["minWidthChange"] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }, { type: i0.Output, args: ["maxWidthChange"] }], dblClickAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "dblClickAction", required: false }] }, { type: i0.Output, args: ["dblClickActionChange"] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }, { type: i0.Output, args: ["widthChange"] }], defaultWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultWidth", required: false }] }, { type: i0.Output, args: ["defaultWidthChange"] }], onResizingStarted: [{ type: i0.Output, args: ["onResizingStarted"] }], onResizingEnded: [{ type: i0.Output, args: ["onResizingEnded"] }], onResizingDblClick: [{ type: i0.Output, args: ["onResizingDblClick"] }] } });
588
+ }], ctorParameters: () => [], propDecorators: { axResizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "axResizable", required: false }] }, { type: i0.Output, args: ["axResizableChange"] }], handles: [{ type: i0.Input, args: [{ isSignal: true, alias: "handles", required: false }] }, { type: i0.Output, args: ["handlesChange"] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }, { type: i0.Output, args: ["minWidthChange"] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }, { type: i0.Output, args: ["maxWidthChange"] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }, { type: i0.Output, args: ["minHeightChange"] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }, { type: i0.Output, args: ["maxHeightChange"] }], dblClickAction: [{ type: i0.Input, args: [{ isSignal: true, alias: "dblClickAction", required: false }] }, { type: i0.Output, args: ["dblClickActionChange"] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }, { type: i0.Output, args: ["widthChange"] }], defaultWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultWidth", required: false }] }, { type: i0.Output, args: ["defaultWidthChange"] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }, { type: i0.Output, args: ["heightChange"] }], defaultHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultHeight", required: false }] }, { type: i0.Output, args: ["defaultHeightChange"] }], lockAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockAspectRatio", required: false }] }, { type: i0.Output, args: ["lockAspectRatioChange"] }], onResizingStarted: [{ type: i0.Output, args: ["onResizingStarted"] }], onResizingEnded: [{ type: i0.Output, args: ["onResizingEnded"] }], onResizingDblClick: [{ type: i0.Output, args: ["onResizingDblClick"] }] } });
589
+ function getHandleAxes(handle) {
590
+ switch (handle) {
591
+ case 'start':
592
+ return { horizontal: 'start', vertical: null };
593
+ case 'end':
594
+ return { horizontal: 'end', vertical: null };
595
+ case 'top':
596
+ return { horizontal: null, vertical: 'top' };
597
+ case 'bottom':
598
+ return { horizontal: null, vertical: 'bottom' };
599
+ case 'top-start':
600
+ return { horizontal: 'start', vertical: 'top' };
601
+ case 'top-end':
602
+ return { horizontal: 'end', vertical: 'top' };
603
+ case 'bottom-start':
604
+ return { horizontal: 'start', vertical: 'bottom' };
605
+ case 'bottom-end':
606
+ return { horizontal: 'end', vertical: 'bottom' };
607
+ }
608
+ }
323
609
  const STYLES = {
324
610
  handlerWidth: 'var(--ax-comp-resizable-handler-width, 4px)',
611
+ handlerHeight: 'var(--ax-comp-resizable-handler-height, 4px)',
612
+ cornerSize: 'var(--ax-comp-resizable-corner-size, 10px)',
325
613
  backgroundColor: 'rgba(var(--ax-comp-resizable-background-color))',
326
614
  backgroundColorActive: 'rgba(var(--ax-comp-resizable-background-color-active, var(--ax-sys-color-primary-surface)))',
327
615
  backgroundColorHover: 'rgba(var(--ax-comp-resizable-background-color-hover, var(--ax-sys-color-primary-light-surface)))',
328
- cursor: 'var(--ax-comp-resizable-cursor, ew-resize)',
616
+ cursorHorizontal: 'var(--ax-comp-resizable-cursor, ew-resize)',
617
+ cursorVertical: 'var(--ax-comp-resizable-cursor-vertical, ns-resize)',
618
+ cursorCorner: 'var(--ax-comp-resizable-cursor-corner, nwse-resize)',
619
+ cursorCornerAlt: 'var(--ax-comp-resizable-cursor-corner-alt, nesw-resize)',
329
620
  cursorActive: 'var(--ax-comp-resizable-cursor-active, ew-resize)',
330
621
  zIndex: 'var(--ax-comp-resizable-z-index, 999)',
622
+ zIndexCorner: 'var(--ax-comp-resizable-z-index-corner, 1000)',
331
623
  transition: 'var(--ax-comp-resizable-transition, background-color --ax-sys-transition-duration --ax-sys-transition-timing-function)',
332
624
  borderRadius: 'var(--ax-comp-resizable-border-radius, --ax-sys-border-radius)',
333
625
  };