@mintplayer/ng-bootstrap 21.12.12 → 21.14.0

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.
@@ -0,0 +1,235 @@
1
+ import { isPlatformServer, NgClass, NgTemplateOutlet } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, TemplateRef, input, Directive, PLATFORM_ID, ElementRef, output, contentChildren, viewChildren, viewChild, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { BsNoNoscriptDirective } from '@mintplayer/ng-bootstrap/no-noscript';
5
+ import { BsObserveSizeDirective } from '@mintplayer/ng-swiper/observe-size';
6
+
7
+ class BsPriorityNavItemDirective {
8
+ constructor() {
9
+ this.templateRef = inject(TemplateRef);
10
+ this.priority = input(null, { ...(ngDevMode ? { debugName: "priority" } : {}), alias: 'bsPriorityNavItem' });
11
+ this.hideBelow = input(null, { ...(ngDevMode ? { debugName: "hideBelow" } : {}), alias: 'bsPriorityNavItemHideBelow' });
12
+ this.id = ++BsPriorityNavItemDirective.idCounter;
13
+ }
14
+ static { this.idCounter = 0; }
15
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: BsPriorityNavItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
16
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.6", type: BsPriorityNavItemDirective, isStandalone: true, selector: "[bsPriorityNavItem]", inputs: { priority: { classPropertyName: "priority", publicName: "bsPriorityNavItem", isSignal: true, isRequired: false, transformFunction: null }, hideBelow: { classPropertyName: "hideBelow", publicName: "bsPriorityNavItemHideBelow", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
17
+ }
18
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: BsPriorityNavItemDirective, decorators: [{
19
+ type: Directive,
20
+ args: [{
21
+ selector: '[bsPriorityNavItem]',
22
+ }]
23
+ }], propDecorators: { priority: [{ type: i0.Input, args: [{ isSignal: true, alias: "bsPriorityNavItem", required: false }] }], hideBelow: [{ type: i0.Input, args: [{ isSignal: true, alias: "bsPriorityNavItemHideBelow", required: false }] }] } });
24
+
25
+ class BsPriorityNavComponent {
26
+ static { this.counter = 0; }
27
+ constructor() {
28
+ this.platformId = inject(PLATFORM_ID);
29
+ this.element = inject(ElementRef);
30
+ this.isServerSide = isPlatformServer(this.platformId);
31
+ this.uid = `pn-${++BsPriorityNavComponent.counter}`;
32
+ // Inputs
33
+ this.moreLabel = input('More', ...(ngDevMode ? [{ debugName: "moreLabel" }] : []));
34
+ this.moreLabelTemplate = input(null, ...(ngDevMode ? [{ debugName: "moreLabelTemplate" }] : []));
35
+ this.collapseAt = input(null, ...(ngDevMode ? [{ debugName: "collapseAt" }] : []));
36
+ this.overflowFrom = input('end', ...(ngDevMode ? [{ debugName: "overflowFrom" }] : []));
37
+ this.hideEmptyMore = input(true, ...(ngDevMode ? [{ debugName: "hideEmptyMore" }] : []));
38
+ // Outputs
39
+ this.overflowChange = output();
40
+ // Children
41
+ this.items = contentChildren(BsPriorityNavItemDirective, ...(ngDevMode ? [{ debugName: "items" }] : []));
42
+ // Per-item width measurements (from the off-screen measure strip)
43
+ this.measureSizers = viewChildren('measureItem', ...(ngDevMode ? [{ debugName: "measureSizers" }] : []));
44
+ // Visible strip width and its element (for reading computed `column-gap`)
45
+ this.stripSizer = viewChild('stripSize', ...(ngDevMode ? [{ debugName: "stripSizer" }] : []));
46
+ this.stripElement = viewChild('stripSize', { ...(ngDevMode ? { debugName: "stripElement" } : {}), read: ElementRef });
47
+ // More button width
48
+ this.moreSizer = viewChild('moreSize', ...(ngDevMode ? [{ debugName: "moreSizer" }] : []));
49
+ // Open/closed state for the More menu (JS path)
50
+ this.isMoreOpen = signal(false, ...(ngDevMode ? [{ debugName: "isMoreOpen" }] : []));
51
+ this.windowWidth = signal(0, ...(ngDevMode ? [{ debugName: "windowWidth" }] : []));
52
+ this.collapseAtPx = computed(() => {
53
+ switch (this.collapseAt()) {
54
+ case 'xxl': return 1400;
55
+ case 'xl': return 1200;
56
+ case 'lg': return 992;
57
+ case 'md': return 768;
58
+ case 'sm': return 576;
59
+ case 'xs': return 0;
60
+ default: return null;
61
+ }
62
+ }, ...(ngDevMode ? [{ debugName: "collapseAtPx" }] : []));
63
+ this.forceCollapse = computed(() => {
64
+ const bp = this.collapseAtPx();
65
+ if (bp === null)
66
+ return false;
67
+ const w = this.windowWidth();
68
+ return w > 0 && w < bp;
69
+ }, ...(ngDevMode ? [{ debugName: "forceCollapse" }] : []));
70
+ // Items in overflow order. Convention: a LOWER priority number means MORE
71
+ // important (priority: 1 stays visible longest). Items without a priority
72
+ // are treated as least important and overflow before any prioritized item.
73
+ // Tiebreaker uses declaration order (last-declared overflows first when
74
+ // overflowFrom='end').
75
+ this.overflowOrder = computed(() => {
76
+ const items = this.items();
77
+ const fromEnd = this.overflowFrom() === 'end';
78
+ return [...items]
79
+ .map((item, index) => ({ item, index, priority: item.priority() }))
80
+ .sort((a, b) => {
81
+ // Unprioritized items overflow first
82
+ if (a.priority === null && b.priority !== null)
83
+ return -1;
84
+ if (a.priority !== null && b.priority === null)
85
+ return 1;
86
+ // Both prioritized: higher number overflows first (less important)
87
+ if (a.priority !== null && b.priority !== null && a.priority !== b.priority) {
88
+ return b.priority - a.priority;
89
+ }
90
+ // Tiebreaker by declaration order
91
+ return fromEnd ? b.index - a.index : a.index - b.index;
92
+ })
93
+ .map(x => x.item);
94
+ }, ...(ngDevMode ? [{ debugName: "overflowOrder" }] : []));
95
+ // Per-item width map (from measure strip, indexed by item id, in items() order)
96
+ this.itemWidths = computed(() => {
97
+ if (this.isServerSide)
98
+ return new Map();
99
+ const sizers = this.measureSizers();
100
+ const items = this.items();
101
+ const map = new Map();
102
+ items.forEach((item, i) => {
103
+ const sizer = sizers[i];
104
+ if (!sizer)
105
+ return;
106
+ const w = sizer.width();
107
+ if (w !== undefined)
108
+ map.set(item.id, w);
109
+ });
110
+ return map;
111
+ }, ...(ngDevMode ? [{ debugName: "itemWidths" }] : []));
112
+ // The strip's `column-gap` (or `gap`) value in pixels. Read from computed
113
+ // style so consumers' `gap` declarations get factored into the overflow math
114
+ // — without this, items overflow late or layout-shift when a gap is set.
115
+ // Re-read whenever the strip width changes (covers media-query gap changes
116
+ // that piggy-back on the same breakpoint).
117
+ this.itemGap = computed(() => {
118
+ if (this.isServerSide)
119
+ return 0;
120
+ this.stripSizer()?.width();
121
+ const el = this.stripElement()?.nativeElement;
122
+ if (!el)
123
+ return 0;
124
+ const cs = getComputedStyle(el);
125
+ const raw = parseFloat(cs.columnGap || cs.gap || '0');
126
+ return Number.isFinite(raw) ? raw : 0;
127
+ }, ...(ngDevMode ? [{ debugName: "itemGap" }] : []));
128
+ this.overflowingIds = computed(() => {
129
+ if (this.isServerSide)
130
+ return new Set();
131
+ if (this.forceCollapse()) {
132
+ return new Set(this.items().map(i => i.id));
133
+ }
134
+ const stripWidth = this.stripSizer()?.width() ?? 0;
135
+ const moreWidth = this.moreSizer()?.width() ?? 0;
136
+ const widths = this.itemWidths();
137
+ const gap = this.itemGap();
138
+ if (stripWidth === 0 || widths.size === 0)
139
+ return new Set();
140
+ // Layout when all items fit (no More toggle): N items separated by N-1 gaps
141
+ const sumWidths = Array.from(widths.values()).reduce((a, b) => a + b, 0);
142
+ const allVisibleWidth = sumWidths + gap * Math.max(0, widths.size - 1);
143
+ if (allVisibleWidth <= stripWidth)
144
+ return new Set();
145
+ // Need overflow → More toggle is shown. Layout when K items are kicked:
146
+ // (N - K) items + 1 More toggle = (N - K + 1) elements with (N - K) gaps
147
+ const overflowing = new Set();
148
+ let visibleSum = sumWidths;
149
+ let visibleCount = widths.size;
150
+ for (const item of this.overflowOrder()) {
151
+ const totalWithMore = visibleSum + moreWidth + gap * visibleCount;
152
+ if (totalWithMore <= stripWidth)
153
+ break;
154
+ visibleSum -= widths.get(item.id) ?? 0;
155
+ visibleCount -= 1;
156
+ overflowing.add(item.id);
157
+ }
158
+ return overflowing;
159
+ }, ...(ngDevMode ? [{ debugName: "overflowingIds" }] : []));
160
+ this.hasAnyOverflow = computed(() => this.overflowingIds().size > 0, ...(ngDevMode ? [{ debugName: "hasAnyOverflow" }] : []));
161
+ this.showMoreButton = computed(() => !this.hideEmptyMore() || this.hasAnyOverflow(), ...(ngDevMode ? [{ debugName: "showMoreButton" }] : []));
162
+ // When every item is overflowing the toggle ends up at the start edge of
163
+ // the strip (no inline items push it). Anchor the dropdown to that side
164
+ // so it stays visually attached to the toggle.
165
+ this.fullyCollapsed = computed(() => {
166
+ const items = this.items();
167
+ return items.length > 0 && this.overflowingIds().size === items.length;
168
+ }, ...(ngDevMode ? [{ debugName: "fullyCollapsed" }] : []));
169
+ // Derived per-item view used by all three rendering passes (measure strip,
170
+ // inline strip, overflow menu). Pre-computes the breakpoint class string and
171
+ // the JS-mode-only hide flags so the template can stay purely declarative —
172
+ // no method calls, no inline `!isServerSide` guards. The SSR/noscript path
173
+ // relies on CSS media queries instead of these flags, so both `hideInline`
174
+ // and `hideInOverflow` are forced to false on the server.
175
+ this.itemsWithMeta = computed(() => {
176
+ const items = this.items();
177
+ const overflowing = this.overflowingIds();
178
+ const ssr = this.isServerSide;
179
+ return items.map(item => {
180
+ const bp = item.hideBelow();
181
+ const isOverflowing = overflowing.has(item.id);
182
+ return {
183
+ item,
184
+ hideBelowClass: bp ? `priority-nav-item-hide-below-${bp}` : '',
185
+ hideInline: !ssr && isOverflowing,
186
+ hideInOverflow: !ssr && !isOverflowing,
187
+ };
188
+ });
189
+ }, ...(ngDevMode ? [{ debugName: "itemsWithMeta" }] : []));
190
+ if (!this.isServerSide) {
191
+ this.windowWidth.set(window.innerWidth);
192
+ }
193
+ effect(() => {
194
+ const overflowing = this.overflowingIds();
195
+ const overflowingItems = this.items().filter(i => overflowing.has(i.id));
196
+ this.overflowChange.emit(overflowingItems);
197
+ });
198
+ }
199
+ onWindowResize() {
200
+ if (!this.isServerSide) {
201
+ this.windowWidth.set(window.innerWidth);
202
+ }
203
+ }
204
+ toggleMore() {
205
+ this.isMoreOpen.update(v => !v);
206
+ }
207
+ onEscape() {
208
+ if (this.isMoreOpen())
209
+ this.isMoreOpen.set(false);
210
+ }
211
+ onDocumentClick(event) {
212
+ if (event.button !== 0 || !this.isMoreOpen())
213
+ return;
214
+ if (!this.element.nativeElement.contains(event.target)) {
215
+ this.isMoreOpen.set(false);
216
+ }
217
+ }
218
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: BsPriorityNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
219
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: BsPriorityNavComponent, isStandalone: true, selector: "bs-priority-nav", inputs: { moreLabel: { classPropertyName: "moreLabel", publicName: "moreLabel", isSignal: true, isRequired: false, transformFunction: null }, moreLabelTemplate: { classPropertyName: "moreLabelTemplate", publicName: "moreLabelTemplate", isSignal: true, isRequired: false, transformFunction: null }, collapseAt: { classPropertyName: "collapseAt", publicName: "collapseAt", isSignal: true, isRequired: false, transformFunction: null }, overflowFrom: { classPropertyName: "overflowFrom", publicName: "overflowFrom", isSignal: true, isRequired: false, transformFunction: null }, hideEmptyMore: { classPropertyName: "hideEmptyMore", publicName: "hideEmptyMore", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { overflowChange: "overflowChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()", "window:resize": "onWindowResize()" } }, queries: [{ propertyName: "items", predicate: BsPriorityNavItemDirective, isSignal: true }], viewQueries: [{ propertyName: "measureSizers", predicate: ["measureItem"], descendants: true, isSignal: true }, { propertyName: "stripSizer", first: true, predicate: ["stripSize"], descendants: true, isSignal: true }, { propertyName: "stripElement", first: true, predicate: ["stripSize"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "moreSizer", first: true, predicate: ["moreSize"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"priority-nav\" [class.noscript]=\"isServerSide\" bsNoNoscript>\n @if (isServerSide) {\n <input type=\"checkbox\" [id]=\"uid + '-more'\" class=\"priority-nav-more-checkbox d-none\" bsNoNoscript>\n }\n\n @if (!isServerSide) {\n <div class=\"priority-nav-measure-wrapper\" aria-hidden=\"true\">\n <div class=\"priority-nav-measure\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span #measureItem=\"bsObserveSize\" bsObserveSize class=\"priority-nav-measure-item\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n </div>\n </div>\n }\n\n <div bsObserveSize #stripSize=\"bsObserveSize\" class=\"priority-nav-strip\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span class=\"priority-nav-item\"\n [class.priority-nav-hidden]=\"entry.hideInline\"\n [ngClass]=\"entry.hideBelowClass\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n\n @if (isServerSide) {\n <label [for]=\"uid + '-more'\" class=\"priority-nav-more-toggle priority-nav-more-toggle-noscript\"\n role=\"button\" tabindex=\"0\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"uid + '-overflow'\">\n <ng-container *ngTemplateOutlet=\"moreLabelTemplate() ?? defaultMoreLabel; context: { $implicit: false }\"></ng-container>\n </label>\n } @else {\n <button bsObserveSize #moreSize=\"bsObserveSize\" type=\"button\"\n class=\"priority-nav-more-toggle\"\n [class.priority-nav-hidden]=\"!showMoreButton()\"\n (click)=\"toggleMore()\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"uid + '-overflow'\"\n [attr.aria-expanded]=\"isMoreOpen()\">\n <ng-container *ngTemplateOutlet=\"moreLabelTemplate() ?? defaultMoreLabel; context: { $implicit: isMoreOpen() }\"></ng-container>\n </button>\n }\n </div>\n\n <div [id]=\"uid + '-overflow'\"\n class=\"priority-nav-overflow\"\n role=\"menu\"\n [class.priority-nav-overflow-open]=\"!isServerSide && isMoreOpen()\"\n [class.priority-nav-overflow-align-start]=\"!isServerSide && fullyCollapsed()\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span class=\"priority-nav-overflow-item\"\n role=\"menuitem\"\n [class.priority-nav-overflow-hidden]=\"entry.hideInOverflow\"\n [ngClass]=\"entry.hideBelowClass\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n </div>\n</div>\n\n<ng-template #defaultMoreLabel let-isOpen>\n <span class=\"priority-nav-more-label\">{{ moreLabel() }}</span>\n <span class=\"priority-nav-caret\" aria-hidden=\"true\">&#9662;</span>\n</ng-template>\n", styles: [":host{display:block}.priority-nav{position:relative}.priority-nav-measure-wrapper{position:absolute;top:0;left:0;width:0;height:0;overflow:hidden;pointer-events:none}.priority-nav-measure{visibility:hidden;display:flex;flex-wrap:nowrap;align-items:center}.priority-nav-measure .priority-nav-measure-item{display:inline-flex;align-items:center;flex-shrink:0}.priority-nav-strip{display:flex;flex-wrap:nowrap;align-items:center;overflow:hidden}.priority-nav-strip .priority-nav-item{display:inline-flex;align-items:center;flex-shrink:0}.priority-nav-hidden,.priority-nav-overflow-hidden{display:none!important}.priority-nav-more-toggle{flex-shrink:0;display:inline-flex;align-items:center;gap:.25rem;padding:.5rem .75rem;border:none;background:transparent;cursor:pointer;color:inherit;font:inherit}.priority-nav-more-toggle:focus-visible{outline:2px solid var(--bs-primary, #0d6efd);outline-offset:2px}.priority-nav-more-toggle .priority-nav-caret{font-size:.75em;line-height:1}.priority-nav-overflow{display:none;position:absolute;top:100%;right:0;z-index:1000;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;background-color:var(--bs-body-bg, #fff);border:var(--bs-border-width, 1px) solid var(--bs-border-color, rgba(0, 0, 0, .175));border-radius:var(--bs-border-radius, .375rem);box-shadow:0 .5rem 1rem #00000026}.priority-nav-overflow .priority-nav-overflow-item{display:block;padding:.25rem 1rem}.priority-nav-overflow-open{display:block}.priority-nav-overflow-align-start{left:0;right:auto}@media(max-width:575.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-sm{display:none}}@media(max-width:767.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-md{display:none}}@media(max-width:991.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-lg{display:none}}@media(max-width:1199.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-xl{display:none}}@media(max-width:1399.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-xxl{display:none}}.priority-nav.noscript .priority-nav-overflow .priority-nav-overflow-item{display:none}@media(max-width:575.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-sm{display:block}}@media(max-width:767.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-md{display:block}}@media(max-width:991.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-lg{display:block}}@media(max-width:1199.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-xl{display:block}}@media(max-width:1399.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-xxl{display:block}}.priority-nav.noscript>input.priority-nav-more-checkbox.noscript:checked~.priority-nav-overflow{display:block}.priority-nav.noscript .priority-nav-more-toggle-noscript{cursor:pointer;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: BsNoNoscriptDirective, selector: "[bsNoNoscript]" }, { kind: "directive", type: BsObserveSizeDirective, selector: "[bsObserveSize]", exportAs: ["bsObserveSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
220
+ }
221
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: BsPriorityNavComponent, decorators: [{
222
+ type: Component,
223
+ args: [{ selector: 'bs-priority-nav', imports: [NgClass, NgTemplateOutlet, BsNoNoscriptDirective, BsObserveSizeDirective], changeDetection: ChangeDetectionStrategy.OnPush, host: {
224
+ '(document:click)': 'onDocumentClick($event)',
225
+ '(document:keydown.escape)': 'onEscape()',
226
+ '(window:resize)': 'onWindowResize()',
227
+ }, template: "<div class=\"priority-nav\" [class.noscript]=\"isServerSide\" bsNoNoscript>\n @if (isServerSide) {\n <input type=\"checkbox\" [id]=\"uid + '-more'\" class=\"priority-nav-more-checkbox d-none\" bsNoNoscript>\n }\n\n @if (!isServerSide) {\n <div class=\"priority-nav-measure-wrapper\" aria-hidden=\"true\">\n <div class=\"priority-nav-measure\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span #measureItem=\"bsObserveSize\" bsObserveSize class=\"priority-nav-measure-item\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n </div>\n </div>\n }\n\n <div bsObserveSize #stripSize=\"bsObserveSize\" class=\"priority-nav-strip\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span class=\"priority-nav-item\"\n [class.priority-nav-hidden]=\"entry.hideInline\"\n [ngClass]=\"entry.hideBelowClass\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n\n @if (isServerSide) {\n <label [for]=\"uid + '-more'\" class=\"priority-nav-more-toggle priority-nav-more-toggle-noscript\"\n role=\"button\" tabindex=\"0\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"uid + '-overflow'\">\n <ng-container *ngTemplateOutlet=\"moreLabelTemplate() ?? defaultMoreLabel; context: { $implicit: false }\"></ng-container>\n </label>\n } @else {\n <button bsObserveSize #moreSize=\"bsObserveSize\" type=\"button\"\n class=\"priority-nav-more-toggle\"\n [class.priority-nav-hidden]=\"!showMoreButton()\"\n (click)=\"toggleMore()\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"uid + '-overflow'\"\n [attr.aria-expanded]=\"isMoreOpen()\">\n <ng-container *ngTemplateOutlet=\"moreLabelTemplate() ?? defaultMoreLabel; context: { $implicit: isMoreOpen() }\"></ng-container>\n </button>\n }\n </div>\n\n <div [id]=\"uid + '-overflow'\"\n class=\"priority-nav-overflow\"\n role=\"menu\"\n [class.priority-nav-overflow-open]=\"!isServerSide && isMoreOpen()\"\n [class.priority-nav-overflow-align-start]=\"!isServerSide && fullyCollapsed()\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span class=\"priority-nav-overflow-item\"\n role=\"menuitem\"\n [class.priority-nav-overflow-hidden]=\"entry.hideInOverflow\"\n [ngClass]=\"entry.hideBelowClass\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n </div>\n</div>\n\n<ng-template #defaultMoreLabel let-isOpen>\n <span class=\"priority-nav-more-label\">{{ moreLabel() }}</span>\n <span class=\"priority-nav-caret\" aria-hidden=\"true\">&#9662;</span>\n</ng-template>\n", styles: [":host{display:block}.priority-nav{position:relative}.priority-nav-measure-wrapper{position:absolute;top:0;left:0;width:0;height:0;overflow:hidden;pointer-events:none}.priority-nav-measure{visibility:hidden;display:flex;flex-wrap:nowrap;align-items:center}.priority-nav-measure .priority-nav-measure-item{display:inline-flex;align-items:center;flex-shrink:0}.priority-nav-strip{display:flex;flex-wrap:nowrap;align-items:center;overflow:hidden}.priority-nav-strip .priority-nav-item{display:inline-flex;align-items:center;flex-shrink:0}.priority-nav-hidden,.priority-nav-overflow-hidden{display:none!important}.priority-nav-more-toggle{flex-shrink:0;display:inline-flex;align-items:center;gap:.25rem;padding:.5rem .75rem;border:none;background:transparent;cursor:pointer;color:inherit;font:inherit}.priority-nav-more-toggle:focus-visible{outline:2px solid var(--bs-primary, #0d6efd);outline-offset:2px}.priority-nav-more-toggle .priority-nav-caret{font-size:.75em;line-height:1}.priority-nav-overflow{display:none;position:absolute;top:100%;right:0;z-index:1000;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;background-color:var(--bs-body-bg, #fff);border:var(--bs-border-width, 1px) solid var(--bs-border-color, rgba(0, 0, 0, .175));border-radius:var(--bs-border-radius, .375rem);box-shadow:0 .5rem 1rem #00000026}.priority-nav-overflow .priority-nav-overflow-item{display:block;padding:.25rem 1rem}.priority-nav-overflow-open{display:block}.priority-nav-overflow-align-start{left:0;right:auto}@media(max-width:575.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-sm{display:none}}@media(max-width:767.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-md{display:none}}@media(max-width:991.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-lg{display:none}}@media(max-width:1199.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-xl{display:none}}@media(max-width:1399.98px){.priority-nav.noscript .priority-nav-strip .priority-nav-item-hide-below-xxl{display:none}}.priority-nav.noscript .priority-nav-overflow .priority-nav-overflow-item{display:none}@media(max-width:575.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-sm{display:block}}@media(max-width:767.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-md{display:block}}@media(max-width:991.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-lg{display:block}}@media(max-width:1199.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-xl{display:block}}@media(max-width:1399.98px){.priority-nav.noscript .priority-nav-overflow .priority-nav-item-hide-below-xxl{display:block}}.priority-nav.noscript>input.priority-nav-more-checkbox.noscript:checked~.priority-nav-overflow{display:block}.priority-nav.noscript .priority-nav-more-toggle-noscript{cursor:pointer;-webkit-user-select:none;user-select:none}\n"] }]
228
+ }], ctorParameters: () => [], propDecorators: { moreLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "moreLabel", required: false }] }], moreLabelTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "moreLabelTemplate", required: false }] }], collapseAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseAt", required: false }] }], overflowFrom: [{ type: i0.Input, args: [{ isSignal: true, alias: "overflowFrom", required: false }] }], hideEmptyMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideEmptyMore", required: false }] }], overflowChange: [{ type: i0.Output, args: ["overflowChange"] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => BsPriorityNavItemDirective), { isSignal: true }] }], measureSizers: [{ type: i0.ViewChildren, args: ['measureItem', { isSignal: true }] }], stripSizer: [{ type: i0.ViewChild, args: ['stripSize', { isSignal: true }] }], stripElement: [{ type: i0.ViewChild, args: ['stripSize', { ...{ read: ElementRef }, isSignal: true }] }], moreSizer: [{ type: i0.ViewChild, args: ['moreSize', { isSignal: true }] }] } });
229
+
230
+ /**
231
+ * Generated bundle index. Do not edit.
232
+ */
233
+
234
+ export { BsPriorityNavComponent, BsPriorityNavItemDirective };
235
+ //# sourceMappingURL=mintplayer-ng-bootstrap-priority-nav.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mintplayer-ng-bootstrap-priority-nav.mjs","sources":["../../../../libs/mintplayer-ng-bootstrap/priority-nav/src/priority-nav-item/priority-nav-item.directive.ts","../../../../libs/mintplayer-ng-bootstrap/priority-nav/src/priority-nav/priority-nav.component.ts","../../../../libs/mintplayer-ng-bootstrap/priority-nav/src/priority-nav/priority-nav.component.html","../../../../libs/mintplayer-ng-bootstrap/priority-nav/mintplayer-ng-bootstrap-priority-nav.ts"],"sourcesContent":["import { Directive, inject, input, TemplateRef } from '@angular/core';\nimport { Breakpoint } from '@mintplayer/ng-bootstrap';\n\n@Directive({\n selector: '[bsPriorityNavItem]',\n})\nexport class BsPriorityNavItemDirective {\n templateRef = inject(TemplateRef);\n\n priority = input<number | null>(null, { alias: 'bsPriorityNavItem' });\n hideBelow = input<Breakpoint | null>(null, { alias: 'bsPriorityNavItemHideBelow' });\n\n readonly id: number = ++BsPriorityNavItemDirective.idCounter;\n private static idCounter = 0;\n}\n","import { isPlatformServer, NgClass, NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy, Component, computed, contentChildren, effect, ElementRef,\n inject, input, output, PLATFORM_ID, signal, TemplateRef, viewChild, viewChildren\n} from '@angular/core';\nimport { Breakpoint } from '@mintplayer/ng-bootstrap';\nimport { BsNoNoscriptDirective } from '@mintplayer/ng-bootstrap/no-noscript';\nimport { BsObserveSizeDirective } from '@mintplayer/ng-swiper/observe-size';\nimport { BsPriorityNavItemDirective } from '../priority-nav-item/priority-nav-item.directive';\n\n@Component({\n selector: 'bs-priority-nav',\n templateUrl: './priority-nav.component.html',\n styleUrls: ['./priority-nav.component.scss'],\n imports: [NgClass, NgTemplateOutlet, BsNoNoscriptDirective, BsObserveSizeDirective],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '(document:click)': 'onDocumentClick($event)',\n '(document:keydown.escape)': 'onEscape()',\n '(window:resize)': 'onWindowResize()',\n },\n})\nexport class BsPriorityNavComponent {\n private platformId = inject(PLATFORM_ID);\n private element = inject(ElementRef);\n\n isServerSide = isPlatformServer(this.platformId);\n\n private static counter = 0;\n uid = `pn-${++BsPriorityNavComponent.counter}`;\n\n // Inputs\n moreLabel = input('More');\n moreLabelTemplate = input<TemplateRef<{ $implicit: boolean }> | null>(null);\n collapseAt = input<Breakpoint | null>(null);\n overflowFrom = input<'start' | 'end'>('end');\n hideEmptyMore = input(true);\n\n // Outputs\n overflowChange = output<BsPriorityNavItemDirective[]>();\n\n // Children\n readonly items = contentChildren(BsPriorityNavItemDirective);\n\n // Per-item width measurements (from the off-screen measure strip)\n private measureSizers = viewChildren<BsObserveSizeDirective>('measureItem');\n // Visible strip width and its element (for reading computed `column-gap`)\n stripSizer = viewChild<BsObserveSizeDirective>('stripSize');\n private stripElement = viewChild('stripSize', { read: ElementRef });\n // More button width\n moreSizer = viewChild<BsObserveSizeDirective>('moreSize');\n\n // Open/closed state for the More menu (JS path)\n isMoreOpen = signal(false);\n windowWidth = signal<number>(0);\n\n collapseAtPx = computed(() => {\n switch (this.collapseAt()) {\n case 'xxl': return 1400;\n case 'xl': return 1200;\n case 'lg': return 992;\n case 'md': return 768;\n case 'sm': return 576;\n case 'xs': return 0;\n default: return null;\n }\n });\n\n forceCollapse = computed(() => {\n const bp = this.collapseAtPx();\n if (bp === null) return false;\n const w = this.windowWidth();\n return w > 0 && w < bp;\n });\n\n // Items in overflow order. Convention: a LOWER priority number means MORE\n // important (priority: 1 stays visible longest). Items without a priority\n // are treated as least important and overflow before any prioritized item.\n // Tiebreaker uses declaration order (last-declared overflows first when\n // overflowFrom='end').\n overflowOrder = computed(() => {\n const items = this.items();\n const fromEnd = this.overflowFrom() === 'end';\n return [...items]\n .map((item, index) => ({ item, index, priority: item.priority() }))\n .sort((a, b) => {\n // Unprioritized items overflow first\n if (a.priority === null && b.priority !== null) return -1;\n if (a.priority !== null && b.priority === null) return 1;\n // Both prioritized: higher number overflows first (less important)\n if (a.priority !== null && b.priority !== null && a.priority !== b.priority) {\n return b.priority - a.priority;\n }\n // Tiebreaker by declaration order\n return fromEnd ? b.index - a.index : a.index - b.index;\n })\n .map(x => x.item);\n });\n\n // Per-item width map (from measure strip, indexed by item id, in items() order)\n itemWidths = computed<Map<number, number>>(() => {\n if (this.isServerSide) return new Map();\n const sizers = this.measureSizers();\n const items = this.items();\n const map = new Map<number, number>();\n items.forEach((item, i) => {\n const sizer = sizers[i];\n if (!sizer) return;\n const w = sizer.width();\n if (w !== undefined) map.set(item.id, w);\n });\n return map;\n });\n\n // The strip's `column-gap` (or `gap`) value in pixels. Read from computed\n // style so consumers' `gap` declarations get factored into the overflow math\n // — without this, items overflow late or layout-shift when a gap is set.\n // Re-read whenever the strip width changes (covers media-query gap changes\n // that piggy-back on the same breakpoint).\n itemGap = computed(() => {\n if (this.isServerSide) return 0;\n this.stripSizer()?.width();\n const el = this.stripElement()?.nativeElement as HTMLElement | undefined;\n if (!el) return 0;\n const cs = getComputedStyle(el);\n const raw = parseFloat(cs.columnGap || cs.gap || '0');\n return Number.isFinite(raw) ? raw : 0;\n });\n\n overflowingIds = computed<Set<number>>(() => {\n if (this.isServerSide) return new Set();\n if (this.forceCollapse()) {\n return new Set(this.items().map(i => i.id));\n }\n\n const stripWidth = this.stripSizer()?.width() ?? 0;\n const moreWidth = this.moreSizer()?.width() ?? 0;\n const widths = this.itemWidths();\n const gap = this.itemGap();\n\n if (stripWidth === 0 || widths.size === 0) return new Set();\n\n // Layout when all items fit (no More toggle): N items separated by N-1 gaps\n const sumWidths = Array.from(widths.values()).reduce((a, b) => a + b, 0);\n const allVisibleWidth = sumWidths + gap * Math.max(0, widths.size - 1);\n if (allVisibleWidth <= stripWidth) return new Set();\n\n // Need overflow → More toggle is shown. Layout when K items are kicked:\n // (N - K) items + 1 More toggle = (N - K + 1) elements with (N - K) gaps\n const overflowing = new Set<number>();\n let visibleSum = sumWidths;\n let visibleCount = widths.size;\n\n for (const item of this.overflowOrder()) {\n const totalWithMore = visibleSum + moreWidth + gap * visibleCount;\n if (totalWithMore <= stripWidth) break;\n visibleSum -= widths.get(item.id) ?? 0;\n visibleCount -= 1;\n overflowing.add(item.id);\n }\n return overflowing;\n });\n\n hasAnyOverflow = computed(() => this.overflowingIds().size > 0);\n showMoreButton = computed(() => !this.hideEmptyMore() || this.hasAnyOverflow());\n\n // When every item is overflowing the toggle ends up at the start edge of\n // the strip (no inline items push it). Anchor the dropdown to that side\n // so it stays visually attached to the toggle.\n fullyCollapsed = computed(() => {\n const items = this.items();\n return items.length > 0 && this.overflowingIds().size === items.length;\n });\n\n // Derived per-item view used by all three rendering passes (measure strip,\n // inline strip, overflow menu). Pre-computes the breakpoint class string and\n // the JS-mode-only hide flags so the template can stay purely declarative —\n // no method calls, no inline `!isServerSide` guards. The SSR/noscript path\n // relies on CSS media queries instead of these flags, so both `hideInline`\n // and `hideInOverflow` are forced to false on the server.\n itemsWithMeta = computed(() => {\n const items = this.items();\n const overflowing = this.overflowingIds();\n const ssr = this.isServerSide;\n return items.map(item => {\n const bp = item.hideBelow();\n const isOverflowing = overflowing.has(item.id);\n return {\n item,\n hideBelowClass: bp ? `priority-nav-item-hide-below-${bp}` : '',\n hideInline: !ssr && isOverflowing,\n hideInOverflow: !ssr && !isOverflowing,\n };\n });\n });\n\n constructor() {\n if (!this.isServerSide) {\n this.windowWidth.set(window.innerWidth);\n }\n\n effect(() => {\n const overflowing = this.overflowingIds();\n const overflowingItems = this.items().filter(i => overflowing.has(i.id));\n this.overflowChange.emit(overflowingItems);\n });\n }\n\n onWindowResize() {\n if (!this.isServerSide) {\n this.windowWidth.set(window.innerWidth);\n }\n }\n\n toggleMore() {\n this.isMoreOpen.update(v => !v);\n }\n\n onEscape() {\n if (this.isMoreOpen()) this.isMoreOpen.set(false);\n }\n\n onDocumentClick(event: MouseEvent) {\n if (event.button !== 0 || !this.isMoreOpen()) return;\n if (!this.element.nativeElement.contains(event.target as Node)) {\n this.isMoreOpen.set(false);\n }\n }\n\n}\n","<div class=\"priority-nav\" [class.noscript]=\"isServerSide\" bsNoNoscript>\n @if (isServerSide) {\n <input type=\"checkbox\" [id]=\"uid + '-more'\" class=\"priority-nav-more-checkbox d-none\" bsNoNoscript>\n }\n\n @if (!isServerSide) {\n <div class=\"priority-nav-measure-wrapper\" aria-hidden=\"true\">\n <div class=\"priority-nav-measure\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span #measureItem=\"bsObserveSize\" bsObserveSize class=\"priority-nav-measure-item\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n </div>\n </div>\n }\n\n <div bsObserveSize #stripSize=\"bsObserveSize\" class=\"priority-nav-strip\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span class=\"priority-nav-item\"\n [class.priority-nav-hidden]=\"entry.hideInline\"\n [ngClass]=\"entry.hideBelowClass\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n\n @if (isServerSide) {\n <label [for]=\"uid + '-more'\" class=\"priority-nav-more-toggle priority-nav-more-toggle-noscript\"\n role=\"button\" tabindex=\"0\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"uid + '-overflow'\">\n <ng-container *ngTemplateOutlet=\"moreLabelTemplate() ?? defaultMoreLabel; context: { $implicit: false }\"></ng-container>\n </label>\n } @else {\n <button bsObserveSize #moreSize=\"bsObserveSize\" type=\"button\"\n class=\"priority-nav-more-toggle\"\n [class.priority-nav-hidden]=\"!showMoreButton()\"\n (click)=\"toggleMore()\"\n aria-haspopup=\"true\"\n [attr.aria-controls]=\"uid + '-overflow'\"\n [attr.aria-expanded]=\"isMoreOpen()\">\n <ng-container *ngTemplateOutlet=\"moreLabelTemplate() ?? defaultMoreLabel; context: { $implicit: isMoreOpen() }\"></ng-container>\n </button>\n }\n </div>\n\n <div [id]=\"uid + '-overflow'\"\n class=\"priority-nav-overflow\"\n role=\"menu\"\n [class.priority-nav-overflow-open]=\"!isServerSide && isMoreOpen()\"\n [class.priority-nav-overflow-align-start]=\"!isServerSide && fullyCollapsed()\">\n @for (entry of itemsWithMeta(); track entry.item.id) {\n <span class=\"priority-nav-overflow-item\"\n role=\"menuitem\"\n [class.priority-nav-overflow-hidden]=\"entry.hideInOverflow\"\n [ngClass]=\"entry.hideBelowClass\">\n <ng-container *ngTemplateOutlet=\"entry.item.templateRef\"></ng-container>\n </span>\n }\n </div>\n</div>\n\n<ng-template #defaultMoreLabel let-isOpen>\n <span class=\"priority-nav-more-label\">{{ moreLabel() }}</span>\n <span class=\"priority-nav-caret\" aria-hidden=\"true\">&#9662;</span>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -104,75 +104,88 @@ class BsResizeGlyphDirective {
104
104
  if (this.resizable.resizeAction && !this.isBusy) {
105
105
  ev.preventDefault();
106
106
  this.isBusy = true;
107
- const rct = this.resizable.element.nativeElement.getBoundingClientRect();
108
- if (this.resizable.resizeAction.start && this.positions()?.includes('end')) {
109
- // Right glyph
110
- const x = (ev.clientX < rct.left + 10) ? rct.left + 10 : ev.clientX;
107
+ const action = this.resizable.resizeAction;
108
+ // Note: the live bounding rect must NOT be used in the size/margin math.
109
+ // Reading it per-frame creates a feedback loop when content inside the
110
+ // host changes layout during the drag (e.g. a child component that
111
+ // shows/hides items in response to width). Use the captured `action`
112
+ // values from pointer-down — they're stable for the duration of the drag.
113
+ if (action.start && this.positions()?.includes('end')) {
114
+ // Right glyph — fixed left edge
115
+ const initialLeft = action.start.edge;
116
+ const initialRight = action.start.edge + action.start.size;
117
+ const x = (ev.clientX < initialLeft + 10) ? initialLeft + 10 : ev.clientX;
111
118
  switch (this.resizable.positioning()) {
112
119
  case 'inline':
113
120
  {
114
- const initalMargin = this.resizable.marginRight() ?? 0;
115
- this.resizable.marginRight.set(initalMargin - (x - rct.right));
121
+ const initialMargin = action.start.dragMargin ?? 0;
122
+ this.resizable.marginRight.set(initialMargin + (initialRight - x));
116
123
  }
117
124
  break;
118
125
  case 'absolute':
119
126
  {
120
- this.resizable.width.set(x - rct.left);
127
+ this.resizable.width.set(x - initialLeft);
121
128
  }
122
129
  break;
123
130
  }
124
131
  }
125
- else if (this.resizable.resizeAction.end && this.positions()?.includes('start')) {
126
- // Left glyph
127
- const x = (ev.clientX > rct.right - 10) ? rct.right - 10 : ev.clientX;
132
+ else if (action.end && this.positions()?.includes('start')) {
133
+ // Left glyph — fixed right edge
134
+ const initialRight = action.end.edge;
135
+ const initialLeft = action.end.edge - action.end.size;
136
+ const x = (ev.clientX > initialRight - 10) ? initialRight - 10 : ev.clientX;
128
137
  switch (this.resizable.positioning()) {
129
138
  case 'inline':
130
139
  {
131
- const initalMargin = this.resizable.marginLeft() ?? 0;
132
- this.resizable.marginLeft.set(initalMargin + x - rct.left);
140
+ const initialMargin = action.end.dragMargin ?? 0;
141
+ this.resizable.marginLeft.set(initialMargin + (x - initialLeft));
133
142
  }
134
143
  break;
135
144
  case 'absolute':
136
145
  {
137
146
  this.resizable.left.set(x);
138
- this.resizable.width.set(this.resizable.resizeAction.end.edge - x);
147
+ this.resizable.width.set(initialRight - x);
139
148
  }
140
149
  break;
141
150
  }
142
151
  }
143
- if (this.resizable.resizeAction.top && this.positions()?.includes('bottom')) {
144
- // Bottom glyph
145
- const y = (ev.clientY < rct.top + 10) ? rct.top + 10 : ev.clientY;
152
+ if (action.top && this.positions()?.includes('bottom')) {
153
+ // Bottom glyph — fixed top edge. action.top.edge = captured rect.top
154
+ const initialTop = action.top.edge;
155
+ const initialBottom = action.top.edge + action.top.size;
156
+ const y = (ev.clientY < initialTop + 10) ? initialTop + 10 : ev.clientY;
146
157
  switch (this.resizable.positioning()) {
147
158
  case 'inline':
148
159
  {
149
- const initalMargin = this.resizable.marginBottom() ?? 0;
150
- this.resizable.height.set(y - rct.top);
151
- this.resizable.marginBottom.set(initalMargin - (y - rct.bottom));
160
+ const initialMargin = action.top.dragMargin ?? 0;
161
+ this.resizable.height.set(y - initialTop);
162
+ this.resizable.marginBottom.set(initialMargin + (initialBottom - y));
152
163
  }
153
164
  break;
154
165
  case 'absolute':
155
166
  {
156
- this.resizable.height.set(y - rct.top);
167
+ this.resizable.height.set(y - initialTop);
157
168
  }
158
169
  break;
159
170
  }
160
171
  }
161
- else if (this.resizable.resizeAction.bottom && this.positions()?.includes('top')) {
162
- // Top glyph
163
- const y = (ev.clientY > rct.bottom - 10) ? rct.bottom - 10 : ev.clientY;
172
+ else if (action.bottom && this.positions()?.includes('top')) {
173
+ // Top glyph — fixed bottom edge. action.bottom.edge = captured rect.bottom
174
+ const initialBottom = action.bottom.edge;
175
+ const initialTop = action.bottom.edge - action.bottom.size;
176
+ const y = (ev.clientY > initialBottom - 10) ? initialBottom - 10 : ev.clientY;
164
177
  switch (this.resizable.positioning()) {
165
178
  case 'inline':
166
179
  {
167
- const initalMargin = this.resizable.marginTop() ?? 0;
168
- this.resizable.height.set(rct.bottom - y);
169
- this.resizable.marginTop.set(initalMargin + y - rct.top);
180
+ const initialMargin = action.bottom.dragMargin ?? 0;
181
+ this.resizable.height.set(initialBottom - y);
182
+ this.resizable.marginTop.set(initialMargin + (y - initialTop));
170
183
  }
171
184
  break;
172
185
  case 'absolute':
173
186
  {
174
187
  this.resizable.top.set(y);
175
- this.resizable.height.set(this.resizable.resizeAction.bottom.edge - y);
188
+ this.resizable.height.set(initialBottom - y);
176
189
  }
177
190
  break;
178
191
  }
@@ -209,6 +222,10 @@ class BsResizableComponent {
209
222
  constructor() {
210
223
  this.element = inject((ElementRef));
211
224
  this.positioning = input('inline', ...(ngDevMode ? [{ debugName: "positioning" }] : []));
225
+ this.horizontal = input(true, ...(ngDevMode ? [{ debugName: "horizontal" }] : []));
226
+ this.vertical = input(true, ...(ngDevMode ? [{ debugName: "vertical" }] : []));
227
+ this.corners = input(true, ...(ngDevMode ? [{ debugName: "corners" }] : []));
228
+ this.showCorners = computed(() => this.horizontal() && this.vertical() && this.corners(), ...(ngDevMode ? [{ debugName: "showCorners" }] : []));
212
229
  this.hostPosition = computed(() => {
213
230
  const positioning = this.positioning();
214
231
  switch (positioning) {
@@ -250,9 +267,9 @@ class BsResizableComponent {
250
267
  });
251
268
  }
252
269
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: BsResizableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
253
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.6", type: BsResizableComponent, isStandalone: true, selector: "bs-resizable", inputs: { positioning: { classPropertyName: "positioning", publicName: "positioning", isSignal: true, isRequired: false, transformFunction: null }, presetPosition: { classPropertyName: "presetPosition", publicName: "presetPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.margin-left.px": "marginLeft()", "style.margin-right.px": "marginRight()", "style.margin-top.px": "marginTop()", "style.margin-bottom.px": "marginBottom()", "style.width.px": "width()", "style.height.px": "height()", "style.left.px": "left()", "style.top.px": "top()", "class.d-block": "true", "class.border": "true", "class": "hostPosition()" } }, providers: [
270
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: BsResizableComponent, isStandalone: true, selector: "bs-resizable", inputs: { positioning: { classPropertyName: "positioning", publicName: "positioning", isSignal: true, isRequired: false, transformFunction: null }, horizontal: { classPropertyName: "horizontal", publicName: "horizontal", isSignal: true, isRequired: false, transformFunction: null }, vertical: { classPropertyName: "vertical", publicName: "vertical", isSignal: true, isRequired: false, transformFunction: null }, corners: { classPropertyName: "corners", publicName: "corners", isSignal: true, isRequired: false, transformFunction: null }, presetPosition: { classPropertyName: "presetPosition", publicName: "presetPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.margin-left.px": "marginLeft()", "style.margin-right.px": "marginRight()", "style.margin-top.px": "marginTop()", "style.margin-bottom.px": "marginBottom()", "style.width.px": "width()", "style.height.px": "height()", "style.left.px": "left()", "style.top.px": "top()", "class.d-block": "true", "class.border": "true", "class": "hostPosition()" } }, providers: [
254
271
  { provide: RESIZABLE, useExisting: forwardRef(() => BsResizableComponent) }
255
- ], ngImport: i0, template: "<div [class]=\"wrapperPosition()\" class=\"h-100\">\n <div class=\"cursor-nw-resize\" [bsResizeGlyph]=\"['top', 'start']\"></div>\n <div class=\"cursor-n-resize\" [bsResizeGlyph]=\"['top']\"></div>\n <div class=\"cursor-ne-resize\" [bsResizeGlyph]=\"['top', 'end']\"></div>\n <div class=\"cursor-e-resize\" [bsResizeGlyph]=\"['end']\"></div>\n <div class=\"cursor-se-resize\" [bsResizeGlyph]=\"['bottom', 'end']\"></div>\n <div class=\"cursor-s-resize\" [bsResizeGlyph]=\"['bottom']\"></div>\n <div class=\"cursor-sw-resize\" [bsResizeGlyph]=\"['bottom', 'start']\"></div>\n <div class=\"cursor-w-resize\" [bsResizeGlyph]=\"['start']\"></div>\n <ng-content></ng-content>\n</div>", styles: [".glyph:before{content:\"\";width:8px;height:8px;display:block;border-radius:4px;transition:background-color .2s ease-in-out}.glyph{position:absolute;width:14px;height:14px;z-index:20}.glyph.top{top:-7px}.glyph.start{left:-7px}.glyph.bottom{bottom:-7px}.glyph.end{right:-7px}.glyph.start:not(.top):not(.bottom),.glyph.end:not(.top):not(.bottom){top:4px;height:calc(100% - 8px)}.glyph.start:not(.top):not(.bottom):before,.glyph.end:not(.top):not(.bottom):before{display:block;height:100%}.glyph.start:before,.glyph.end:before{margin-left:3px;margin-right:3px}.glyph.top:not(.start):not(.end),.glyph.bottom:not(.start):not(.end){left:4px;width:calc(100% - 8px)}.glyph.top:not(.start):not(.end):before,.glyph.bottom:not(.start):not(.end):before{display:block;width:100%}.glyph.top:before,.glyph.bottom:before{margin-top:3px;margin-bottom:3px}.glyph:hover:before,.glyph.active:before{background-color:#1389fd}:host{min-width:2rem;min-height:2rem}\n"], dependencies: [{ kind: "directive", type: BsResizeGlyphDirective, selector: "[bsResizeGlyph]", inputs: ["bsResizeGlyph"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
272
+ ], ngImport: i0, template: "<div [class]=\"wrapperPosition()\" class=\"h-100\">\n @if (showCorners()) {\n <div class=\"cursor-nw-resize\" [bsResizeGlyph]=\"['top', 'start']\"></div>\n <div class=\"cursor-ne-resize\" [bsResizeGlyph]=\"['top', 'end']\"></div>\n <div class=\"cursor-se-resize\" [bsResizeGlyph]=\"['bottom', 'end']\"></div>\n <div class=\"cursor-sw-resize\" [bsResizeGlyph]=\"['bottom', 'start']\"></div>\n }\n @if (vertical()) {\n <div class=\"cursor-n-resize\" [bsResizeGlyph]=\"['top']\"></div>\n <div class=\"cursor-s-resize\" [bsResizeGlyph]=\"['bottom']\"></div>\n }\n @if (horizontal()) {\n <div class=\"cursor-e-resize\" [bsResizeGlyph]=\"['end']\"></div>\n <div class=\"cursor-w-resize\" [bsResizeGlyph]=\"['start']\"></div>\n }\n <ng-content></ng-content>\n</div>", styles: [".glyph:before{content:\"\";width:8px;height:8px;display:block;border-radius:4px;transition:background-color .2s ease-in-out}.glyph{position:absolute;width:14px;height:14px;z-index:20}.glyph.top{top:-7px}.glyph.start{left:-7px}.glyph.bottom{bottom:-7px}.glyph.end{right:-7px}.glyph.start:not(.top):not(.bottom),.glyph.end:not(.top):not(.bottom){top:4px;height:calc(100% - 8px)}.glyph.start:not(.top):not(.bottom):before,.glyph.end:not(.top):not(.bottom):before{display:block;height:100%}.glyph.start:before,.glyph.end:before{margin-left:3px;margin-right:3px}.glyph.top:not(.start):not(.end),.glyph.bottom:not(.start):not(.end){left:4px;width:calc(100% - 8px)}.glyph.top:not(.start):not(.end):before,.glyph.bottom:not(.start):not(.end):before{display:block;width:100%}.glyph.top:before,.glyph.bottom:before{margin-top:3px;margin-bottom:3px}.glyph:hover:before,.glyph.active:before{background-color:#1389fd}:host{min-width:2rem;min-height:2rem}\n"], dependencies: [{ kind: "directive", type: BsResizeGlyphDirective, selector: "[bsResizeGlyph]", inputs: ["bsResizeGlyph"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
256
273
  }
257
274
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: BsResizableComponent, decorators: [{
258
275
  type: Component,
@@ -270,8 +287,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
270
287
  '[class.d-block]': 'true',
271
288
  '[class.border]': 'true',
272
289
  '[class]': 'hostPosition()',
273
- }, template: "<div [class]=\"wrapperPosition()\" class=\"h-100\">\n <div class=\"cursor-nw-resize\" [bsResizeGlyph]=\"['top', 'start']\"></div>\n <div class=\"cursor-n-resize\" [bsResizeGlyph]=\"['top']\"></div>\n <div class=\"cursor-ne-resize\" [bsResizeGlyph]=\"['top', 'end']\"></div>\n <div class=\"cursor-e-resize\" [bsResizeGlyph]=\"['end']\"></div>\n <div class=\"cursor-se-resize\" [bsResizeGlyph]=\"['bottom', 'end']\"></div>\n <div class=\"cursor-s-resize\" [bsResizeGlyph]=\"['bottom']\"></div>\n <div class=\"cursor-sw-resize\" [bsResizeGlyph]=\"['bottom', 'start']\"></div>\n <div class=\"cursor-w-resize\" [bsResizeGlyph]=\"['start']\"></div>\n <ng-content></ng-content>\n</div>", styles: [".glyph:before{content:\"\";width:8px;height:8px;display:block;border-radius:4px;transition:background-color .2s ease-in-out}.glyph{position:absolute;width:14px;height:14px;z-index:20}.glyph.top{top:-7px}.glyph.start{left:-7px}.glyph.bottom{bottom:-7px}.glyph.end{right:-7px}.glyph.start:not(.top):not(.bottom),.glyph.end:not(.top):not(.bottom){top:4px;height:calc(100% - 8px)}.glyph.start:not(.top):not(.bottom):before,.glyph.end:not(.top):not(.bottom):before{display:block;height:100%}.glyph.start:before,.glyph.end:before{margin-left:3px;margin-right:3px}.glyph.top:not(.start):not(.end),.glyph.bottom:not(.start):not(.end){left:4px;width:calc(100% - 8px)}.glyph.top:not(.start):not(.end):before,.glyph.bottom:not(.start):not(.end):before{display:block;width:100%}.glyph.top:before,.glyph.bottom:before{margin-top:3px;margin-bottom:3px}.glyph:hover:before,.glyph.active:before{background-color:#1389fd}:host{min-width:2rem;min-height:2rem}\n"] }]
274
- }], ctorParameters: () => [], propDecorators: { positioning: [{ type: i0.Input, args: [{ isSignal: true, alias: "positioning", required: false }] }], presetPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "presetPosition", required: false }] }] } });
290
+ }, template: "<div [class]=\"wrapperPosition()\" class=\"h-100\">\n @if (showCorners()) {\n <div class=\"cursor-nw-resize\" [bsResizeGlyph]=\"['top', 'start']\"></div>\n <div class=\"cursor-ne-resize\" [bsResizeGlyph]=\"['top', 'end']\"></div>\n <div class=\"cursor-se-resize\" [bsResizeGlyph]=\"['bottom', 'end']\"></div>\n <div class=\"cursor-sw-resize\" [bsResizeGlyph]=\"['bottom', 'start']\"></div>\n }\n @if (vertical()) {\n <div class=\"cursor-n-resize\" [bsResizeGlyph]=\"['top']\"></div>\n <div class=\"cursor-s-resize\" [bsResizeGlyph]=\"['bottom']\"></div>\n }\n @if (horizontal()) {\n <div class=\"cursor-e-resize\" [bsResizeGlyph]=\"['end']\"></div>\n <div class=\"cursor-w-resize\" [bsResizeGlyph]=\"['start']\"></div>\n }\n <ng-content></ng-content>\n</div>", styles: [".glyph:before{content:\"\";width:8px;height:8px;display:block;border-radius:4px;transition:background-color .2s ease-in-out}.glyph{position:absolute;width:14px;height:14px;z-index:20}.glyph.top{top:-7px}.glyph.start{left:-7px}.glyph.bottom{bottom:-7px}.glyph.end{right:-7px}.glyph.start:not(.top):not(.bottom),.glyph.end:not(.top):not(.bottom){top:4px;height:calc(100% - 8px)}.glyph.start:not(.top):not(.bottom):before,.glyph.end:not(.top):not(.bottom):before{display:block;height:100%}.glyph.start:before,.glyph.end:before{margin-left:3px;margin-right:3px}.glyph.top:not(.start):not(.end),.glyph.bottom:not(.start):not(.end){left:4px;width:calc(100% - 8px)}.glyph.top:not(.start):not(.end):before,.glyph.bottom:not(.start):not(.end):before{display:block;width:100%}.glyph.top:before,.glyph.bottom:before{margin-top:3px;margin-bottom:3px}.glyph:hover:before,.glyph.active:before{background-color:#1389fd}:host{min-width:2rem;min-height:2rem}\n"] }]
291
+ }], ctorParameters: () => [], propDecorators: { positioning: [{ type: i0.Input, args: [{ isSignal: true, alias: "positioning", required: false }] }], horizontal: [{ type: i0.Input, args: [{ isSignal: true, alias: "horizontal", required: false }] }], vertical: [{ type: i0.Input, args: [{ isSignal: true, alias: "vertical", required: false }] }], corners: [{ type: i0.Input, args: [{ isSignal: true, alias: "corners", required: false }] }], presetPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "presetPosition", required: false }] }] } });
275
292
 
276
293
  /**
277
294
  * Generated bundle index. Do not edit.