@sneat/ui 0.27.25 → 0.27.27
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/esm2022/lib/components/index.js +1 -0
- package/esm2022/lib/components/index.js.map +1 -1
- package/esm2022/lib/components/resizable-menu.directive.js +219 -0
- package/esm2022/lib/components/resizable-menu.directive.js.map +1 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/components/resizable-menu.directive.d.ts +45 -0
- package/package.json +1 -1
- package/tsconfig.lib.prod.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/ui/src/lib/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC","sourcesContent":["export * from './sneat-base.component';\nexport * from './sneat-base-modal.component';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/ui/src/lib/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC","sourcesContent":["export * from './sneat-base.component';\nexport * from './sneat-base-modal.component';\nexport * from './resizable-menu.directive';\n"]}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { Directive, ElementRef, Input, Renderer2, } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export const RESIZABLE_MENU_DEFAULT_WIDTH = 280;
|
|
4
|
+
export const RESIZABLE_MENU_MIN_WIDTH = 220;
|
|
5
|
+
export const RESIZABLE_MENU_MAX_WIDTH = 600;
|
|
6
|
+
export const RESIZABLE_MENU_KEYBOARD_STEP = 10;
|
|
7
|
+
export const RESIZABLE_MENU_STORAGE_KEY = 'sneat.resizable-menu.width';
|
|
8
|
+
export function clampResizableMenuWidth(width, min = RESIZABLE_MENU_MIN_WIDTH, max = RESIZABLE_MENU_MAX_WIDTH) {
|
|
9
|
+
return Math.round(Math.min(max, Math.max(min, width)));
|
|
10
|
+
}
|
|
11
|
+
export function parseResizableMenuWidth(value, min = RESIZABLE_MENU_MIN_WIDTH, max = RESIZABLE_MENU_MAX_WIDTH) {
|
|
12
|
+
if (value == null || value.trim() === '')
|
|
13
|
+
return undefined;
|
|
14
|
+
const parsed = Number(value);
|
|
15
|
+
return Number.isFinite(parsed) ? clampResizableMenuWidth(parsed, min, max) : undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Attach to an existing ion-menu inside ion-split-pane to enable desktop resizing. */
|
|
18
|
+
export class ResizableMenuDirective {
|
|
19
|
+
constructor(elementRef, renderer) {
|
|
20
|
+
this.renderer = renderer;
|
|
21
|
+
this.sneatResizableMenuMin = RESIZABLE_MENU_MIN_WIDTH;
|
|
22
|
+
this.sneatResizableMenuMax = RESIZABLE_MENU_MAX_WIDTH;
|
|
23
|
+
this.sneatResizableMenuDefault = RESIZABLE_MENU_DEFAULT_WIDTH;
|
|
24
|
+
this.sneatResizableMenuStorageKey = RESIZABLE_MENU_STORAGE_KEY;
|
|
25
|
+
this.visible = false;
|
|
26
|
+
this.width = RESIZABLE_MENU_DEFAULT_WIDTH;
|
|
27
|
+
this.dragStartX = 0;
|
|
28
|
+
this.dragStartWidth = 0;
|
|
29
|
+
this.previousUserSelect = '';
|
|
30
|
+
this.onSplitPaneVisible = (event) => {
|
|
31
|
+
if (event.target !== this.splitPane)
|
|
32
|
+
return;
|
|
33
|
+
const visible = !!event.detail?.visible;
|
|
34
|
+
this.setVisible(visible);
|
|
35
|
+
};
|
|
36
|
+
this.onPointerMove = (event) => {
|
|
37
|
+
if (event.pointerId !== this.dragPointerId || !this.visible)
|
|
38
|
+
return;
|
|
39
|
+
this.setWidth(this.dragStartWidth + event.clientX - this.dragStartX);
|
|
40
|
+
};
|
|
41
|
+
this.onPointerEnd = (event) => {
|
|
42
|
+
if (event.pointerId !== this.dragPointerId)
|
|
43
|
+
return;
|
|
44
|
+
this.finishDrag(true);
|
|
45
|
+
};
|
|
46
|
+
this.onLostPointerCapture = (event) => {
|
|
47
|
+
if (event.pointerId === this.dragPointerId)
|
|
48
|
+
this.finishDrag(true);
|
|
49
|
+
};
|
|
50
|
+
this.onPointerDown = (event) => {
|
|
51
|
+
if (!this.visible || !this.handle || event.button !== 0)
|
|
52
|
+
return;
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
this.dragPointerId = event.pointerId;
|
|
55
|
+
this.dragStartX = event.clientX;
|
|
56
|
+
this.dragStartWidth = this.width;
|
|
57
|
+
this.previousUserSelect = document.body.style.userSelect;
|
|
58
|
+
document.body.style.userSelect = 'none';
|
|
59
|
+
try {
|
|
60
|
+
this.handle.setPointerCapture(event.pointerId);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Pointer capture may be unavailable in test DOMs or older embedded browsers.
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
this.onKeyDown = (event) => {
|
|
67
|
+
if (!this.visible)
|
|
68
|
+
return;
|
|
69
|
+
const direction = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;
|
|
70
|
+
if (!direction)
|
|
71
|
+
return;
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
this.setWidth(this.width + direction * RESIZABLE_MENU_KEYBOARD_STEP);
|
|
74
|
+
this.persistWidth();
|
|
75
|
+
};
|
|
76
|
+
this.menu = elementRef.nativeElement;
|
|
77
|
+
this.splitPane = this.menu.closest('ion-split-pane');
|
|
78
|
+
}
|
|
79
|
+
ngAfterViewInit() {
|
|
80
|
+
if (!this.splitPane)
|
|
81
|
+
return;
|
|
82
|
+
this.width = this.readStoredWidth();
|
|
83
|
+
this.applyWidth();
|
|
84
|
+
this.createHandle();
|
|
85
|
+
this.setVisible(this.splitPane.classList.contains('split-pane-visible'));
|
|
86
|
+
this.splitPane.addEventListener('ionSplitPaneVisible', this.onSplitPaneVisible);
|
|
87
|
+
}
|
|
88
|
+
ngOnDestroy() {
|
|
89
|
+
this.finishDrag(false);
|
|
90
|
+
this.splitPane?.removeEventListener('ionSplitPaneVisible', this.onSplitPaneVisible);
|
|
91
|
+
this.handle?.remove();
|
|
92
|
+
this.handle = undefined;
|
|
93
|
+
}
|
|
94
|
+
createHandle() {
|
|
95
|
+
const handle = this.renderer.createElement('button');
|
|
96
|
+
handle.type = 'button';
|
|
97
|
+
handle.className = 'sneat-resizable-menu-handle';
|
|
98
|
+
handle.setAttribute('aria-label', 'Resize navigation menu');
|
|
99
|
+
handle.setAttribute('role', 'separator');
|
|
100
|
+
handle.setAttribute('aria-orientation', 'vertical');
|
|
101
|
+
handle.setAttribute('aria-valuemin', String(this.sneatResizableMenuMin));
|
|
102
|
+
handle.setAttribute('aria-valuemax', String(this.sneatResizableMenuMax));
|
|
103
|
+
handle.setAttribute('aria-valuenow', String(this.width));
|
|
104
|
+
handle.tabIndex = 0;
|
|
105
|
+
Object.assign(handle.style, {
|
|
106
|
+
position: 'absolute',
|
|
107
|
+
top: '0',
|
|
108
|
+
right: '-3px',
|
|
109
|
+
bottom: '0',
|
|
110
|
+
width: '7px',
|
|
111
|
+
height: '100%',
|
|
112
|
+
padding: '0',
|
|
113
|
+
border: '0',
|
|
114
|
+
background: 'transparent',
|
|
115
|
+
cursor: 'col-resize',
|
|
116
|
+
touchAction: 'none',
|
|
117
|
+
zIndex: '10',
|
|
118
|
+
});
|
|
119
|
+
handle.addEventListener('pointerdown', this.onPointerDown);
|
|
120
|
+
handle.addEventListener('pointermove', this.onPointerMove);
|
|
121
|
+
handle.addEventListener('pointerup', this.onPointerEnd);
|
|
122
|
+
handle.addEventListener('pointercancel', this.onPointerEnd);
|
|
123
|
+
handle.addEventListener('lostpointercapture', this.onLostPointerCapture);
|
|
124
|
+
handle.addEventListener('keydown', this.onKeyDown);
|
|
125
|
+
this.renderer.appendChild(this.menu, handle);
|
|
126
|
+
this.handle = handle;
|
|
127
|
+
}
|
|
128
|
+
setVisible(visible) {
|
|
129
|
+
this.visible = visible;
|
|
130
|
+
if (this.handle)
|
|
131
|
+
this.handle.hidden = !visible;
|
|
132
|
+
if (visible) {
|
|
133
|
+
this.applyWidth();
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.finishDrag(true);
|
|
137
|
+
this.clearWidthOverrides();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
setWidth(width) {
|
|
141
|
+
this.width = clampResizableMenuWidth(width, this.sneatResizableMenuMin, this.sneatResizableMenuMax);
|
|
142
|
+
this.applyWidth();
|
|
143
|
+
}
|
|
144
|
+
applyWidth() {
|
|
145
|
+
const cssWidth = `${this.width}px`;
|
|
146
|
+
this.menu.style.setProperty('--width', cssWidth);
|
|
147
|
+
this.menu.style.setProperty('--min-width', `${this.sneatResizableMenuMin}px`);
|
|
148
|
+
this.menu.style.setProperty('--max-width', `${this.sneatResizableMenuMax}px`);
|
|
149
|
+
this.splitPane?.style.setProperty('--side-width', cssWidth);
|
|
150
|
+
this.splitPane?.style.setProperty('--side-min-width', `${this.sneatResizableMenuMin}px`);
|
|
151
|
+
this.splitPane?.style.setProperty('--side-max-width', `${this.sneatResizableMenuMax}px`);
|
|
152
|
+
this.handle?.setAttribute('aria-valuenow', String(this.width));
|
|
153
|
+
}
|
|
154
|
+
clearWidthOverrides() {
|
|
155
|
+
this.menu.style.removeProperty('--width');
|
|
156
|
+
this.menu.style.removeProperty('--min-width');
|
|
157
|
+
this.menu.style.removeProperty('--max-width');
|
|
158
|
+
this.splitPane?.style.removeProperty('--side-width');
|
|
159
|
+
this.splitPane?.style.removeProperty('--side-min-width');
|
|
160
|
+
this.splitPane?.style.removeProperty('--side-max-width');
|
|
161
|
+
}
|
|
162
|
+
readStoredWidth() {
|
|
163
|
+
try {
|
|
164
|
+
if (typeof localStorage === 'undefined')
|
|
165
|
+
return this.sneatResizableMenuDefault;
|
|
166
|
+
const stored = parseResizableMenuWidth(localStorage.getItem(this.sneatResizableMenuStorageKey), this.sneatResizableMenuMin, this.sneatResizableMenuMax);
|
|
167
|
+
return stored ?? clampResizableMenuWidth(this.sneatResizableMenuDefault, this.sneatResizableMenuMin, this.sneatResizableMenuMax);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return clampResizableMenuWidth(this.sneatResizableMenuDefault, this.sneatResizableMenuMin, this.sneatResizableMenuMax);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
persistWidth() {
|
|
174
|
+
try {
|
|
175
|
+
if (typeof localStorage !== 'undefined') {
|
|
176
|
+
localStorage.setItem(this.sneatResizableMenuStorageKey, String(this.width));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Storage can be disabled by browser policy; resizing remains available for this session.
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
finishDrag(persist) {
|
|
184
|
+
if (this.dragPointerId === undefined)
|
|
185
|
+
return;
|
|
186
|
+
const pointerId = this.dragPointerId;
|
|
187
|
+
this.dragPointerId = undefined;
|
|
188
|
+
if (this.handle?.hasPointerCapture(pointerId)) {
|
|
189
|
+
try {
|
|
190
|
+
this.handle.releasePointerCapture(pointerId);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Capture can already have been released by the browser.
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (typeof document !== 'undefined')
|
|
197
|
+
document.body.style.userSelect = this.previousUserSelect;
|
|
198
|
+
if (persist)
|
|
199
|
+
this.persistWidth();
|
|
200
|
+
}
|
|
201
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResizableMenuDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
202
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: ResizableMenuDirective, isStandalone: true, selector: "ion-menu[sneatResizableMenu]", inputs: { sneatResizableMenuMin: "sneatResizableMenuMin", sneatResizableMenuMax: "sneatResizableMenuMax", sneatResizableMenuDefault: "sneatResizableMenuDefault", sneatResizableMenuStorageKey: "sneatResizableMenuStorageKey" }, ngImport: i0 }); }
|
|
203
|
+
}
|
|
204
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResizableMenuDirective, decorators: [{
|
|
205
|
+
type: Directive,
|
|
206
|
+
args: [{
|
|
207
|
+
selector: 'ion-menu[sneatResizableMenu]',
|
|
208
|
+
standalone: true,
|
|
209
|
+
}]
|
|
210
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { sneatResizableMenuMin: [{
|
|
211
|
+
type: Input
|
|
212
|
+
}], sneatResizableMenuMax: [{
|
|
213
|
+
type: Input
|
|
214
|
+
}], sneatResizableMenuDefault: [{
|
|
215
|
+
type: Input
|
|
216
|
+
}], sneatResizableMenuStorageKey: [{
|
|
217
|
+
type: Input
|
|
218
|
+
}] } });
|
|
219
|
+
//# sourceMappingURL=resizable-menu.directive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizable-menu.directive.js","sourceRoot":"","sources":["../../../../../../libs/ui/src/lib/components/resizable-menu.directive.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AfterViewInit,\n Directive,\n ElementRef,\n Input,\n OnDestroy,\n Renderer2,\n} from '@angular/core';\n\nexport const RESIZABLE_MENU_DEFAULT_WIDTH = 280;\nexport const RESIZABLE_MENU_MIN_WIDTH = 220;\nexport const RESIZABLE_MENU_MAX_WIDTH = 600;\nexport const RESIZABLE_MENU_KEYBOARD_STEP = 10;\nexport const RESIZABLE_MENU_STORAGE_KEY = 'sneat.resizable-menu.width';\n\nexport function clampResizableMenuWidth(\n width: number,\n min: number = RESIZABLE_MENU_MIN_WIDTH,\n max: number = RESIZABLE_MENU_MAX_WIDTH,\n): number {\n return Math.round(Math.min(max, Math.max(min, width)));\n}\n\nexport function parseResizableMenuWidth(\n value: string | null | undefined,\n min: number = RESIZABLE_MENU_MIN_WIDTH,\n max: number = RESIZABLE_MENU_MAX_WIDTH,\n): number | undefined {\n if (value == null || value.trim() === '') return undefined;\n const parsed = Number(value);\n return Number.isFinite(parsed) ? clampResizableMenuWidth(parsed, min, max) : undefined;\n}\n\n/** Attach to an existing ion-menu inside ion-split-pane to enable desktop resizing. */\n@Directive({\n selector: 'ion-menu[sneatResizableMenu]',\n standalone: true,\n})\nexport class ResizableMenuDirective implements AfterViewInit, OnDestroy {\n @Input() sneatResizableMenuMin = RESIZABLE_MENU_MIN_WIDTH;\n @Input() sneatResizableMenuMax = RESIZABLE_MENU_MAX_WIDTH;\n @Input() sneatResizableMenuDefault = RESIZABLE_MENU_DEFAULT_WIDTH;\n @Input() sneatResizableMenuStorageKey = RESIZABLE_MENU_STORAGE_KEY;\n\n private readonly menu: HTMLElement;\n private readonly splitPane: HTMLElement | null;\n private handle?: HTMLButtonElement;\n private visible = false;\n private width = RESIZABLE_MENU_DEFAULT_WIDTH;\n private dragPointerId?: number;\n private dragStartX = 0;\n private dragStartWidth = 0;\n private previousUserSelect = '';\n private readonly onSplitPaneVisible = (event: Event): void => {\n if (event.target !== this.splitPane) return;\n const visible = !!(event as CustomEvent<{ visible?: boolean }>).detail?.visible;\n this.setVisible(visible);\n };\n private readonly onPointerMove = (event: PointerEvent): void => {\n if (event.pointerId !== this.dragPointerId || !this.visible) return;\n this.setWidth(this.dragStartWidth + event.clientX - this.dragStartX);\n };\n private readonly onPointerEnd = (event: PointerEvent): void => {\n if (event.pointerId !== this.dragPointerId) return;\n this.finishDrag(true);\n };\n private readonly onLostPointerCapture = (event: PointerEvent): void => {\n if (event.pointerId === this.dragPointerId) this.finishDrag(true);\n };\n\n constructor(\n elementRef: ElementRef<HTMLElement>,\n private readonly renderer: Renderer2,\n ) {\n this.menu = elementRef.nativeElement;\n this.splitPane = this.menu.closest('ion-split-pane');\n }\n\n ngAfterViewInit(): void {\n if (!this.splitPane) return;\n this.width = this.readStoredWidth();\n this.applyWidth();\n this.createHandle();\n this.setVisible(this.splitPane.classList.contains('split-pane-visible'));\n this.splitPane.addEventListener('ionSplitPaneVisible', this.onSplitPaneVisible);\n }\n\n ngOnDestroy(): void {\n this.finishDrag(false);\n this.splitPane?.removeEventListener('ionSplitPaneVisible', this.onSplitPaneVisible);\n this.handle?.remove();\n this.handle = undefined;\n }\n\n private createHandle(): void {\n const handle = this.renderer.createElement('button') as HTMLButtonElement;\n handle.type = 'button';\n handle.className = 'sneat-resizable-menu-handle';\n handle.setAttribute('aria-label', 'Resize navigation menu');\n handle.setAttribute('role', 'separator');\n handle.setAttribute('aria-orientation', 'vertical');\n handle.setAttribute('aria-valuemin', String(this.sneatResizableMenuMin));\n handle.setAttribute('aria-valuemax', String(this.sneatResizableMenuMax));\n handle.setAttribute('aria-valuenow', String(this.width));\n handle.tabIndex = 0;\n Object.assign(handle.style, {\n position: 'absolute',\n top: '0',\n right: '-3px',\n bottom: '0',\n width: '7px',\n height: '100%',\n padding: '0',\n border: '0',\n background: 'transparent',\n cursor: 'col-resize',\n touchAction: 'none',\n zIndex: '10',\n });\n handle.addEventListener('pointerdown', this.onPointerDown);\n handle.addEventListener('pointermove', this.onPointerMove);\n handle.addEventListener('pointerup', this.onPointerEnd);\n handle.addEventListener('pointercancel', this.onPointerEnd);\n handle.addEventListener('lostpointercapture', this.onLostPointerCapture);\n handle.addEventListener('keydown', this.onKeyDown);\n this.renderer.appendChild(this.menu, handle);\n this.handle = handle;\n }\n\n private readonly onPointerDown = (event: PointerEvent): void => {\n if (!this.visible || !this.handle || event.button !== 0) return;\n event.preventDefault();\n this.dragPointerId = event.pointerId;\n this.dragStartX = event.clientX;\n this.dragStartWidth = this.width;\n this.previousUserSelect = document.body.style.userSelect;\n document.body.style.userSelect = 'none';\n try {\n this.handle.setPointerCapture(event.pointerId);\n } catch {\n // Pointer capture may be unavailable in test DOMs or older embedded browsers.\n }\n };\n\n private readonly onKeyDown = (event: KeyboardEvent): void => {\n if (!this.visible) return;\n const direction = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;\n if (!direction) return;\n event.preventDefault();\n this.setWidth(this.width + direction * RESIZABLE_MENU_KEYBOARD_STEP);\n this.persistWidth();\n };\n\n private setVisible(visible: boolean): void {\n this.visible = visible;\n if (this.handle) this.handle.hidden = !visible;\n if (visible) {\n this.applyWidth();\n } else {\n this.finishDrag(true);\n this.clearWidthOverrides();\n }\n }\n\n private setWidth(width: number): void {\n this.width = clampResizableMenuWidth(width, this.sneatResizableMenuMin, this.sneatResizableMenuMax);\n this.applyWidth();\n }\n\n private applyWidth(): void {\n const cssWidth = `${this.width}px`;\n this.menu.style.setProperty('--width', cssWidth);\n this.menu.style.setProperty('--min-width', `${this.sneatResizableMenuMin}px`);\n this.menu.style.setProperty('--max-width', `${this.sneatResizableMenuMax}px`);\n this.splitPane?.style.setProperty('--side-width', cssWidth);\n this.splitPane?.style.setProperty('--side-min-width', `${this.sneatResizableMenuMin}px`);\n this.splitPane?.style.setProperty('--side-max-width', `${this.sneatResizableMenuMax}px`);\n this.handle?.setAttribute('aria-valuenow', String(this.width));\n }\n\n private clearWidthOverrides(): void {\n this.menu.style.removeProperty('--width');\n this.menu.style.removeProperty('--min-width');\n this.menu.style.removeProperty('--max-width');\n this.splitPane?.style.removeProperty('--side-width');\n this.splitPane?.style.removeProperty('--side-min-width');\n this.splitPane?.style.removeProperty('--side-max-width');\n }\n\n private readStoredWidth(): number {\n try {\n if (typeof localStorage === 'undefined') return this.sneatResizableMenuDefault;\n const stored = parseResizableMenuWidth(\n localStorage.getItem(this.sneatResizableMenuStorageKey),\n this.sneatResizableMenuMin,\n this.sneatResizableMenuMax,\n );\n return stored ?? clampResizableMenuWidth(\n this.sneatResizableMenuDefault,\n this.sneatResizableMenuMin,\n this.sneatResizableMenuMax,\n );\n } catch {\n return clampResizableMenuWidth(this.sneatResizableMenuDefault, this.sneatResizableMenuMin, this.sneatResizableMenuMax);\n }\n }\n\n private persistWidth(): void {\n try {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(this.sneatResizableMenuStorageKey, String(this.width));\n }\n } catch {\n // Storage can be disabled by browser policy; resizing remains available for this session.\n }\n }\n\n private finishDrag(persist: boolean): void {\n if (this.dragPointerId === undefined) return;\n const pointerId = this.dragPointerId;\n this.dragPointerId = undefined;\n if (this.handle?.hasPointerCapture(pointerId)) {\n try {\n this.handle.releasePointerCapture(pointerId);\n } catch {\n // Capture can already have been released by the browser.\n }\n }\n if (typeof document !== 'undefined') document.body.style.userSelect = this.previousUserSelect;\n if (persist) this.persistWidth();\n }\n}\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { AfterViewInit, ElementRef, OnDestroy, Renderer2 } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare const RESIZABLE_MENU_DEFAULT_WIDTH = 280;
|
|
4
|
+
export declare const RESIZABLE_MENU_MIN_WIDTH = 220;
|
|
5
|
+
export declare const RESIZABLE_MENU_MAX_WIDTH = 600;
|
|
6
|
+
export declare const RESIZABLE_MENU_KEYBOARD_STEP = 10;
|
|
7
|
+
export declare const RESIZABLE_MENU_STORAGE_KEY = "sneat.resizable-menu.width";
|
|
8
|
+
export declare function clampResizableMenuWidth(width: number, min?: number, max?: number): number;
|
|
9
|
+
export declare function parseResizableMenuWidth(value: string | null | undefined, min?: number, max?: number): number | undefined;
|
|
10
|
+
/** Attach to an existing ion-menu inside ion-split-pane to enable desktop resizing. */
|
|
11
|
+
export declare class ResizableMenuDirective implements AfterViewInit, OnDestroy {
|
|
12
|
+
private readonly renderer;
|
|
13
|
+
sneatResizableMenuMin: number;
|
|
14
|
+
sneatResizableMenuMax: number;
|
|
15
|
+
sneatResizableMenuDefault: number;
|
|
16
|
+
sneatResizableMenuStorageKey: string;
|
|
17
|
+
private readonly menu;
|
|
18
|
+
private readonly splitPane;
|
|
19
|
+
private handle?;
|
|
20
|
+
private visible;
|
|
21
|
+
private width;
|
|
22
|
+
private dragPointerId?;
|
|
23
|
+
private dragStartX;
|
|
24
|
+
private dragStartWidth;
|
|
25
|
+
private previousUserSelect;
|
|
26
|
+
private readonly onSplitPaneVisible;
|
|
27
|
+
private readonly onPointerMove;
|
|
28
|
+
private readonly onPointerEnd;
|
|
29
|
+
private readonly onLostPointerCapture;
|
|
30
|
+
constructor(elementRef: ElementRef<HTMLElement>, renderer: Renderer2);
|
|
31
|
+
ngAfterViewInit(): void;
|
|
32
|
+
ngOnDestroy(): void;
|
|
33
|
+
private createHandle;
|
|
34
|
+
private readonly onPointerDown;
|
|
35
|
+
private readonly onKeyDown;
|
|
36
|
+
private setVisible;
|
|
37
|
+
private setWidth;
|
|
38
|
+
private applyWidth;
|
|
39
|
+
private clearWidthOverrides;
|
|
40
|
+
private readStoredWidth;
|
|
41
|
+
private persistWidth;
|
|
42
|
+
private finishDrag;
|
|
43
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ResizableMenuDirective, never>;
|
|
44
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<ResizableMenuDirective, "ion-menu[sneatResizableMenu]", never, { "sneatResizableMenuMin": { "alias": "sneatResizableMenuMin"; "required": false; }; "sneatResizableMenuMax": { "alias": "sneatResizableMenuMax"; "required": false; }; "sneatResizableMenuDefault": { "alias": "sneatResizableMenuDefault"; "required": false; }; "sneatResizableMenuStorageKey": { "alias": "sneatResizableMenuStorageKey"; "required": false; }; }, {}, never, never, true, never>;
|
|
45
|
+
}
|