@rivinia/menu 0.1.0 → 0.3.2
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/README.md +688 -47
- package/fesm2022/rivinia-menu-ui.mjs +247 -23
- package/fesm2022/rivinia-menu-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/rivinia-menu-ui.d.ts +108 -4
- package/types/rivinia-menu.d.ts +13 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { Component, Directive, ElementRef, ViewEncapsulation, afterRenderEffect, computed, effect, inject, input, output, signal } from "@angular/core";
|
|
2
|
+
import { Component, Directive, ElementRef, ViewEncapsulation, afterRenderEffect, computed, contentChildren, effect, inject, input, output, signal } from "@angular/core";
|
|
3
3
|
import { RiviniaMenu } from "@rivinia/menu";
|
|
4
4
|
const MENU_GAP = 6;
|
|
5
5
|
const EDGE = 8;
|
|
@@ -31,6 +31,7 @@ function computeMenuPosition(trigger, panel, placement, viewport, rtl, gap = 6)
|
|
|
31
31
|
flipped
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
let nextPanelId = 0;
|
|
34
35
|
var RiviniaMenuItem = class RiviniaMenuItem {
|
|
35
36
|
id = input.required(...ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []);
|
|
36
37
|
disabled = input(false, {
|
|
@@ -38,6 +39,8 @@ var RiviniaMenuItem = class RiviniaMenuItem {
|
|
|
38
39
|
transform: (v) => v === "" || v === true
|
|
39
40
|
});
|
|
40
41
|
checked = input(null, ...ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []);
|
|
42
|
+
label = input(null, ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
43
|
+
host = inject(ElementRef, { optional: true });
|
|
41
44
|
menu = inject(RiviniaMenuComponent, {
|
|
42
45
|
optional: true,
|
|
43
46
|
skipSelf: true
|
|
@@ -53,20 +56,41 @@ var RiviniaMenuItem = class RiviniaMenuItem {
|
|
|
53
56
|
const checked = this.checked();
|
|
54
57
|
return checked === null ? null : String(checked);
|
|
55
58
|
}
|
|
59
|
+
isDisabled() {
|
|
60
|
+
if (this.disabled()) return true;
|
|
61
|
+
return this.host?.nativeElement?.disabled === true;
|
|
62
|
+
}
|
|
56
63
|
pick() {
|
|
57
64
|
this.menu?.pickItem(this.id());
|
|
58
65
|
}
|
|
59
66
|
hover() {
|
|
60
67
|
this.menu?.hoverItem(this.id());
|
|
61
68
|
}
|
|
69
|
+
registeredId = null;
|
|
70
|
+
constructor() {
|
|
71
|
+
effect(() => {
|
|
72
|
+
const id = this.id();
|
|
73
|
+
const menu = this.menu;
|
|
74
|
+
if (this.registeredId === null) return;
|
|
75
|
+
if (this.registeredId !== id) menu?.unregisterItem(this.registeredId);
|
|
76
|
+
menu?.registerItem({
|
|
77
|
+
id,
|
|
78
|
+
disabled: this.isDisabled()
|
|
79
|
+
});
|
|
80
|
+
this.registeredId = id;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
62
83
|
ngOnInit() {
|
|
84
|
+
this.registeredId = this.id();
|
|
63
85
|
this.menu?.registerItem({
|
|
64
86
|
id: this.id(),
|
|
65
|
-
disabled: this.
|
|
87
|
+
disabled: this.isDisabled()
|
|
66
88
|
});
|
|
67
89
|
}
|
|
68
90
|
ngOnDestroy() {
|
|
69
|
-
|
|
91
|
+
if (this.registeredId === null) return;
|
|
92
|
+
this.menu?.unregisterItem(this.registeredId);
|
|
93
|
+
this.registeredId = null;
|
|
70
94
|
}
|
|
71
95
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
72
96
|
minVersion: "12.0.0",
|
|
@@ -103,6 +127,13 @@ var RiviniaMenuItem = class RiviniaMenuItem {
|
|
|
103
127
|
isSignal: true,
|
|
104
128
|
isRequired: false,
|
|
105
129
|
transformFunction: null
|
|
130
|
+
},
|
|
131
|
+
label: {
|
|
132
|
+
classPropertyName: "label",
|
|
133
|
+
publicName: "label",
|
|
134
|
+
isSignal: true,
|
|
135
|
+
isRequired: false,
|
|
136
|
+
transformFunction: null
|
|
106
137
|
}
|
|
107
138
|
},
|
|
108
139
|
host: {
|
|
@@ -113,8 +144,9 @@ var RiviniaMenuItem = class RiviniaMenuItem {
|
|
|
113
144
|
properties: {
|
|
114
145
|
"attr.role": "computedRole()",
|
|
115
146
|
"attr.data-rv-id": "id()",
|
|
147
|
+
"attr.data-rv-label": "label()",
|
|
116
148
|
"attr.tabindex": "tab()",
|
|
117
|
-
"attr.aria-disabled": "
|
|
149
|
+
"attr.aria-disabled": "isDisabled()",
|
|
118
150
|
"attr.data-active": "active()",
|
|
119
151
|
"attr.aria-checked": "checkedAttr()"
|
|
120
152
|
}
|
|
@@ -135,8 +167,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
135
167
|
host: {
|
|
136
168
|
"[attr.role]": "computedRole()",
|
|
137
169
|
"[attr.data-rv-id]": "id()",
|
|
170
|
+
"[attr.data-rv-label]": "label()",
|
|
138
171
|
"[attr.tabindex]": "tab()",
|
|
139
|
-
"[attr.aria-disabled]": "
|
|
172
|
+
"[attr.aria-disabled]": "isDisabled()",
|
|
140
173
|
"[attr.data-active]": "active()",
|
|
141
174
|
"[attr.aria-checked]": "checkedAttr()",
|
|
142
175
|
"(click)": "pick()",
|
|
@@ -144,6 +177,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
144
177
|
}
|
|
145
178
|
}]
|
|
146
179
|
}],
|
|
180
|
+
ctorParameters: () => [],
|
|
147
181
|
propDecorators: {
|
|
148
182
|
id: [{
|
|
149
183
|
type: i0.Input,
|
|
@@ -168,18 +202,36 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
168
202
|
alias: "checked",
|
|
169
203
|
required: false
|
|
170
204
|
}]
|
|
205
|
+
}],
|
|
206
|
+
label: [{
|
|
207
|
+
type: i0.Input,
|
|
208
|
+
args: [{
|
|
209
|
+
isSignal: true,
|
|
210
|
+
alias: "label",
|
|
211
|
+
required: false
|
|
212
|
+
}]
|
|
171
213
|
}]
|
|
172
214
|
}
|
|
173
215
|
});
|
|
174
216
|
var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
175
217
|
menu = input(null, ...ngDevMode ? [{ debugName: "menu" }] : /* istanbul ignore next */ []);
|
|
176
218
|
placement = input("bottom-start", ...ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []);
|
|
219
|
+
menuLabel = input(null, ...ngDevMode ? [{ debugName: "menuLabel" }] : /* istanbul ignore next */ []);
|
|
220
|
+
items = input(null, ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
|
|
221
|
+
panelClass = input(null, ...ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []);
|
|
222
|
+
itemClass = input(null, ...ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []);
|
|
177
223
|
picked = output();
|
|
178
224
|
opened = output();
|
|
179
225
|
closed = output();
|
|
180
226
|
owned = new RiviniaMenu();
|
|
181
227
|
self = inject(ElementRef);
|
|
228
|
+
projectedItems = contentChildren(RiviniaMenuItem, {
|
|
229
|
+
...ngDevMode ? { debugName: "projectedItems" } : /* istanbul ignore next */ {},
|
|
230
|
+
descendants: true
|
|
231
|
+
});
|
|
232
|
+
panelId = `rv-menu-panel-${++nextPanelId}`;
|
|
182
233
|
focusPending = false;
|
|
234
|
+
pendingActivation = false;
|
|
183
235
|
topLayerSupported = typeof HTMLElement !== "undefined" && "showPopover" in HTMLElement.prototype;
|
|
184
236
|
positioned = signal(false, ...ngDevMode ? [{ debugName: "positioned" }] : /* istanbul ignore next */ []);
|
|
185
237
|
flipped = signal(false, ...ngDevMode ? [{ debugName: "flipped" }] : /* istanbul ignore next */ []);
|
|
@@ -188,19 +240,38 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
188
240
|
controller() {
|
|
189
241
|
return this.menu() ?? this.owned;
|
|
190
242
|
}
|
|
243
|
+
dataItems() {
|
|
244
|
+
return this.ambiguous() ? [] : this.items() ?? [];
|
|
245
|
+
}
|
|
246
|
+
checkedFor(id) {
|
|
247
|
+
const c = this.controller();
|
|
248
|
+
return typeof c.isSelected === "function" ? c.isSelected(id) : null;
|
|
249
|
+
}
|
|
250
|
+
ambiguous() {
|
|
251
|
+
return this.items() !== null && this.projectedItems().length > 0;
|
|
252
|
+
}
|
|
191
253
|
registerItem(item) {
|
|
192
|
-
this.controller()
|
|
254
|
+
const c = this.controller();
|
|
255
|
+
c.register(item);
|
|
256
|
+
if (this.pendingActivation && c.open() && c.activeId() === null && !item.disabled) {
|
|
257
|
+
c.activateFirst();
|
|
258
|
+
this.pendingActivation = false;
|
|
259
|
+
}
|
|
193
260
|
}
|
|
194
261
|
unregisterItem(id) {
|
|
195
262
|
this.controller().unregister(id);
|
|
196
263
|
}
|
|
197
264
|
constructor() {
|
|
265
|
+
effect(() => {
|
|
266
|
+
if (!this.ambiguous()) return;
|
|
267
|
+
throw new Error("rv-menu: `[items]` cannot be combined with projected `rvMenuItem` children — pick one way to populate the panel.");
|
|
268
|
+
});
|
|
198
269
|
effect((onCleanup) => {
|
|
199
270
|
if (typeof window === "undefined") return;
|
|
200
271
|
if (!this.controller().open()) return;
|
|
201
272
|
const onPointer = (event) => {
|
|
202
273
|
const host = this.self.nativeElement;
|
|
203
|
-
if (host && !host.contains(event.target)) this.doClose(
|
|
274
|
+
if (host && !host.contains(event.target)) this.doClose(false);
|
|
204
275
|
};
|
|
205
276
|
document.addEventListener("pointerdown", onPointer);
|
|
206
277
|
const onScroll = (event) => {
|
|
@@ -222,6 +293,7 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
222
293
|
const trigger = this.triggerEl();
|
|
223
294
|
trigger?.setAttribute("aria-haspopup", "menu");
|
|
224
295
|
trigger?.setAttribute("aria-expanded", String(open));
|
|
296
|
+
trigger?.setAttribute("aria-controls", this.panelId);
|
|
225
297
|
});
|
|
226
298
|
afterRenderEffect(() => {
|
|
227
299
|
if (this.controller().open() && !this.positioned()) this.showAndPosition();
|
|
@@ -279,10 +351,9 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
279
351
|
}
|
|
280
352
|
markOpening() {
|
|
281
353
|
this.focusPending = true;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
354
|
+
this.pendingActivation = true;
|
|
355
|
+
this.flipped.set(false);
|
|
356
|
+
this.positioned.set(false);
|
|
286
357
|
}
|
|
287
358
|
onTriggerClick() {
|
|
288
359
|
const c = this.controller();
|
|
@@ -347,12 +418,23 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
347
418
|
event.preventDefault();
|
|
348
419
|
this.pickFocused();
|
|
349
420
|
break;
|
|
350
|
-
case "Tab":
|
|
421
|
+
case "Tab": {
|
|
422
|
+
event.preventDefault();
|
|
423
|
+
const backwards = event.shiftKey;
|
|
351
424
|
this.doClose(false);
|
|
425
|
+
this.focusAdjacentToTrigger(backwards);
|
|
352
426
|
break;
|
|
427
|
+
}
|
|
353
428
|
default: this.onTypeahead(event);
|
|
354
429
|
}
|
|
355
430
|
}
|
|
431
|
+
resetTypeahead() {
|
|
432
|
+
this.typeBuffer = "";
|
|
433
|
+
if (this.typeTimer !== null) {
|
|
434
|
+
clearTimeout(this.typeTimer);
|
|
435
|
+
this.typeTimer = null;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
356
438
|
onTypeahead(event) {
|
|
357
439
|
if (event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey) return;
|
|
358
440
|
const ch = event.key.toLocaleLowerCase();
|
|
@@ -371,7 +453,7 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
371
453
|
const enabled = new Set(this.controller().items().filter((i) => !i.disabled).map((i) => i.id));
|
|
372
454
|
const rows = [...root.querySelectorAll("[data-rv-id]")].map((el) => ({
|
|
373
455
|
id: el.getAttribute("data-rv-id") ?? "",
|
|
374
|
-
text: (el.textContent ?? "").trim().toLocaleLowerCase()
|
|
456
|
+
text: (el.getAttribute("data-rv-label") ?? el.textContent ?? "").trim().toLocaleLowerCase()
|
|
375
457
|
})).filter((r) => enabled.has(r.id) && r.text.startsWith(buffer));
|
|
376
458
|
if (rows.length === 0) return null;
|
|
377
459
|
if (new Set(buffer).size === 1) {
|
|
@@ -381,8 +463,11 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
381
463
|
return rows[0].id;
|
|
382
464
|
}
|
|
383
465
|
pickFocused() {
|
|
384
|
-
const
|
|
466
|
+
const c = this.controller();
|
|
467
|
+
const id = c.pickActive();
|
|
385
468
|
if (id === null) return;
|
|
469
|
+
const item = c.items().find((i) => i.id === id);
|
|
470
|
+
if (!item || item.disabled) return;
|
|
386
471
|
this.doClose(false);
|
|
387
472
|
this.picked.emit({ id });
|
|
388
473
|
}
|
|
@@ -396,16 +481,22 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
396
481
|
}
|
|
397
482
|
doClose(restoreFocus) {
|
|
398
483
|
const was = this.controller().open();
|
|
484
|
+
this.resetTypeahead();
|
|
399
485
|
this.controller().closeMenu();
|
|
400
486
|
if (was) this.closed.emit();
|
|
401
487
|
if (restoreFocus) this.focusTrigger();
|
|
402
488
|
}
|
|
403
489
|
consumePendingFocus() {
|
|
404
|
-
if (!this.controller().open() || !this.focusPending) return;
|
|
405
|
-
this.focusPending = false;
|
|
490
|
+
if (!this.positioned() || !this.controller().open() || !this.focusPending) return;
|
|
406
491
|
const root = this.self.nativeElement.querySelector(".rv-menu-panel");
|
|
492
|
+
if (!root) return;
|
|
407
493
|
const active = this.activeDocumentElement();
|
|
408
|
-
if (
|
|
494
|
+
if (active && root.contains(active)) {
|
|
495
|
+
this.focusPending = false;
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
this.focusPending = false;
|
|
499
|
+
this.focusActive();
|
|
409
500
|
}
|
|
410
501
|
focusActive() {
|
|
411
502
|
const id = this.controller().activeId();
|
|
@@ -428,6 +519,22 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
428
519
|
if (!wrap) return null;
|
|
429
520
|
return wrap.querySelector("button, a, [tabindex]") ?? wrap;
|
|
430
521
|
}
|
|
522
|
+
focusAdjacentToTrigger(backwards) {
|
|
523
|
+
try {
|
|
524
|
+
const trigger = this.triggerEl();
|
|
525
|
+
const doc = trigger?.ownerDocument;
|
|
526
|
+
if (!trigger || !doc) return;
|
|
527
|
+
const stops = [...doc.querySelectorAll("a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])")].filter((el) => {
|
|
528
|
+
if (el.hasAttribute("disabled") || el.getAttribute("aria-hidden") === "true") return false;
|
|
529
|
+
if (el.closest(".rv-menu-panel")) return false;
|
|
530
|
+
return el.getClientRects().length > 0;
|
|
531
|
+
});
|
|
532
|
+
stops.sort((a, b) => a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
|
|
533
|
+
const at = stops.indexOf(trigger);
|
|
534
|
+
if (at === -1) return;
|
|
535
|
+
stops[backwards ? at - 1 : at + 1]?.focus({ preventScroll: true });
|
|
536
|
+
} catch {}
|
|
537
|
+
}
|
|
431
538
|
focusTrigger() {
|
|
432
539
|
try {
|
|
433
540
|
this.triggerEl()?.focus({ preventScroll: true });
|
|
@@ -461,6 +568,34 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
461
568
|
isSignal: true,
|
|
462
569
|
isRequired: false,
|
|
463
570
|
transformFunction: null
|
|
571
|
+
},
|
|
572
|
+
menuLabel: {
|
|
573
|
+
classPropertyName: "menuLabel",
|
|
574
|
+
publicName: "menuLabel",
|
|
575
|
+
isSignal: true,
|
|
576
|
+
isRequired: false,
|
|
577
|
+
transformFunction: null
|
|
578
|
+
},
|
|
579
|
+
items: {
|
|
580
|
+
classPropertyName: "items",
|
|
581
|
+
publicName: "items",
|
|
582
|
+
isSignal: true,
|
|
583
|
+
isRequired: false,
|
|
584
|
+
transformFunction: null
|
|
585
|
+
},
|
|
586
|
+
panelClass: {
|
|
587
|
+
classPropertyName: "panelClass",
|
|
588
|
+
publicName: "panelClass",
|
|
589
|
+
isSignal: true,
|
|
590
|
+
isRequired: false,
|
|
591
|
+
transformFunction: null
|
|
592
|
+
},
|
|
593
|
+
itemClass: {
|
|
594
|
+
classPropertyName: "itemClass",
|
|
595
|
+
publicName: "itemClass",
|
|
596
|
+
isSignal: true,
|
|
597
|
+
isRequired: false,
|
|
598
|
+
transformFunction: null
|
|
464
599
|
}
|
|
465
600
|
},
|
|
466
601
|
outputs: {
|
|
@@ -468,16 +603,25 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
468
603
|
opened: "opened",
|
|
469
604
|
closed: "closed"
|
|
470
605
|
},
|
|
606
|
+
queries: [{
|
|
607
|
+
propertyName: "projectedItems",
|
|
608
|
+
predicate: RiviniaMenuItem,
|
|
609
|
+
descendants: true,
|
|
610
|
+
isSignal: true
|
|
611
|
+
}],
|
|
471
612
|
ngImport: i0,
|
|
472
613
|
template: `
|
|
473
614
|
<div class="rv-menu-trigger" (click)="onTriggerClick()" (keydown)="onTriggerKey($event)">
|
|
474
|
-
<ng-content select="[rv-menu-trigger]"></ng-content>
|
|
615
|
+
<ng-content select="[rv-menu-trigger], [rvMenuTrigger]"></ng-content>
|
|
475
616
|
</div>
|
|
476
617
|
@if (controller().open()) {
|
|
477
618
|
<div
|
|
478
619
|
#panel
|
|
479
620
|
class="rv-menu-panel"
|
|
621
|
+
[class]="panelClass()"
|
|
480
622
|
role="menu"
|
|
623
|
+
[attr.id]="panelId"
|
|
624
|
+
[attr.aria-label]="menuLabel()"
|
|
481
625
|
[attr.popover]="topLayerSupported ? 'manual' : null"
|
|
482
626
|
[attr.data-placement]="placement()"
|
|
483
627
|
[attr.data-flipped]="flipped()"
|
|
@@ -485,12 +629,36 @@ var RiviniaMenuComponent = class RiviniaMenuComponent {
|
|
|
485
629
|
[attr.data-top-layer]="topLayerSupported"
|
|
486
630
|
(keydown)="onPanelKey($event)"
|
|
487
631
|
>
|
|
488
|
-
|
|
632
|
+
@if (dataItems().length > 0) {
|
|
633
|
+
@for (item of dataItems(); track item.id) {
|
|
634
|
+
<button
|
|
635
|
+
rvMenuItem
|
|
636
|
+
[id]="item.id"
|
|
637
|
+
[disabled]="item.disabled ?? false"
|
|
638
|
+
[checked]="checkedFor(item.id)"
|
|
639
|
+
[class]="itemClass()"
|
|
640
|
+
>
|
|
641
|
+
{{ item.label }}
|
|
642
|
+
</button>
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
<ng-content select="[rv-menu-panel], [rvMenuPanel]"></ng-content>
|
|
489
646
|
</div>
|
|
490
647
|
}
|
|
491
648
|
`,
|
|
492
649
|
isInline: true,
|
|
493
|
-
styles: [".rv-menu-trigger{display:inline-flex;align-items:center}.rv-menu-panel{display:flex;flex-direction:column;gap:2px}.rv-menu-panel hr{border:0;border-top:1px solid var(--rv-menu-border);margin:6px 4px}rv-menu{position:relative;display:inline-block}.rv-menu-panel[data-top-layer=true]{position:fixed;inset:auto;margin:0}.rv-menu-panel[data-positioned=false]{animation:none}.rv-menu-panel[data-top-layer=true][data-placement^=bottom][data-flipped=true]{transform-origin:bottom center}.rv-menu-panel[data-top-layer=true][data-placement^=top][data-flipped=true]{transform-origin:top center}.rv-menu-panel{
|
|
650
|
+
styles: [".rv-menu-trigger{display:inline-flex;align-items:center}.rv-menu-panel{display:flex;flex-direction:column;gap:2px}.rv-menu-panel hr{border:0;border-top:1px solid var(--rv-menu-border, #e0e0e0);margin:6px 4px}rv-menu{position:relative;display:inline-block}.rv-menu-panel[data-top-layer=true]{position:fixed;inset:auto;margin:0}.rv-menu-panel[data-positioned=false]{animation:none}.rv-menu-panel[data-top-layer=true][data-placement^=bottom][data-flipped=true]{transform-origin:bottom center}.rv-menu-panel[data-top-layer=true][data-placement^=top][data-flipped=true]{transform-origin:top center}.rv-menu-panel{position:absolute;z-index:var(--rv-menu-z, 500);min-width:var(--rv-menu-width, 16rem);max-width:calc(100dvw - 2rem);max-height:min(20rem,calc(100dvh - 2rem));overflow-y:auto;background:var(--rv-menu-bg, #ffffff);color:var(--rv-menu-fg, #111111);font-family:var(--rv-menu-font, system-ui, -apple-system, \"Segoe UI\", sans-serif);border:1px solid var(--rv-menu-border, #e0e0e0);border-radius:var(--rv-menu-radius, 12px);box-shadow:var(--rv-menu-shadow, 0 16px 48px rgba(0, 0, 0, .22));padding:var(--rv-menu-pad, 6px)}.rv-menu-panel[data-placement=bottom-start]{inset-block-start:calc(100% + 6px);inset-inline-start:0}.rv-menu-panel[data-placement=bottom-end]{inset-block-start:calc(100% + 6px);inset-inline-end:0}.rv-menu-panel[data-placement=top-start]{inset-block-end:calc(100% + 6px);inset-inline-start:0}.rv-menu-panel[data-placement=top-end]{inset-block-end:calc(100% + 6px);inset-inline-end:0}.rv-menu-panel [rvmenuitem]{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;border:0;border-radius:8px;background:transparent;color:inherit;font:inherit;font-size:14px;line-height:1.4;text-align:start;padding:8px 10px;cursor:pointer}.rv-menu-panel [rvmenuitem][data-active=true]{background:color-mix(in srgb,currentColor 10%,transparent)}.rv-menu-panel [rvmenuitem]:hover{background:color-mix(in srgb,currentColor 8%,transparent)}.rv-menu-panel [rvmenuitem]:focus-visible{outline:2px solid currentColor;outline-offset:-2px}.rv-menu-panel [rvmenuitem][aria-disabled=true]{opacity:.45;cursor:default}.rv-menu-panel [rvmenuitem] svg,.rv-menu-panel [rvmenuitem] [data-icon]{width:16px;height:16px;flex:none;color:var(--rv-menu-muted)}.rv-menu-panel [rvmenuitem][data-active=true] svg,.rv-menu-panel [rvmenuitem][data-active=true] [data-icon]{color:inherit}.rv-menu-panel{transform-origin:top center;animation:rv-menu-in var(--rv-menu-duration, .16s) var(--rv-menu-easing, cubic-bezier(.16, 1, .3, 1))}.rv-menu-panel[data-placement=top-start],.rv-menu-panel[data-placement=top-end]{--rv-menu-from-y: 6px;transform-origin:bottom center}@media(prefers-reduced-motion:reduce){.rv-menu-panel{animation:none}}@keyframes rv-menu-in{0%{opacity:0;transform:translateY(var(--rv-menu-from-y, -6px)) scale(.96)}}\n"],
|
|
651
|
+
dependencies: [{
|
|
652
|
+
kind: "directive",
|
|
653
|
+
type: RiviniaMenuItem,
|
|
654
|
+
selector: "[rvMenuItem]",
|
|
655
|
+
inputs: [
|
|
656
|
+
"id",
|
|
657
|
+
"disabled",
|
|
658
|
+
"checked",
|
|
659
|
+
"label"
|
|
660
|
+
]
|
|
661
|
+
}],
|
|
494
662
|
encapsulation: i0.ViewEncapsulation.None
|
|
495
663
|
});
|
|
496
664
|
};
|
|
@@ -505,15 +673,19 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
505
673
|
selector: "rv-menu",
|
|
506
674
|
standalone: true,
|
|
507
675
|
encapsulation: ViewEncapsulation.None,
|
|
676
|
+
imports: [RiviniaMenuItem],
|
|
508
677
|
template: `
|
|
509
678
|
<div class="rv-menu-trigger" (click)="onTriggerClick()" (keydown)="onTriggerKey($event)">
|
|
510
|
-
<ng-content select="[rv-menu-trigger]"></ng-content>
|
|
679
|
+
<ng-content select="[rv-menu-trigger], [rvMenuTrigger]"></ng-content>
|
|
511
680
|
</div>
|
|
512
681
|
@if (controller().open()) {
|
|
513
682
|
<div
|
|
514
683
|
#panel
|
|
515
684
|
class="rv-menu-panel"
|
|
685
|
+
[class]="panelClass()"
|
|
516
686
|
role="menu"
|
|
687
|
+
[attr.id]="panelId"
|
|
688
|
+
[attr.aria-label]="menuLabel()"
|
|
517
689
|
[attr.popover]="topLayerSupported ? 'manual' : null"
|
|
518
690
|
[attr.data-placement]="placement()"
|
|
519
691
|
[attr.data-flipped]="flipped()"
|
|
@@ -521,11 +693,24 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
521
693
|
[attr.data-top-layer]="topLayerSupported"
|
|
522
694
|
(keydown)="onPanelKey($event)"
|
|
523
695
|
>
|
|
524
|
-
|
|
696
|
+
@if (dataItems().length > 0) {
|
|
697
|
+
@for (item of dataItems(); track item.id) {
|
|
698
|
+
<button
|
|
699
|
+
rvMenuItem
|
|
700
|
+
[id]="item.id"
|
|
701
|
+
[disabled]="item.disabled ?? false"
|
|
702
|
+
[checked]="checkedFor(item.id)"
|
|
703
|
+
[class]="itemClass()"
|
|
704
|
+
>
|
|
705
|
+
{{ item.label }}
|
|
706
|
+
</button>
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
<ng-content select="[rv-menu-panel], [rvMenuPanel]"></ng-content>
|
|
525
710
|
</div>
|
|
526
711
|
}
|
|
527
712
|
`,
|
|
528
|
-
styles: [".rv-menu-trigger{display:inline-flex;align-items:center}.rv-menu-panel{display:flex;flex-direction:column;gap:2px}.rv-menu-panel hr{border:0;border-top:1px solid var(--rv-menu-border);margin:6px 4px}rv-menu{position:relative;display:inline-block}.rv-menu-panel[data-top-layer=true]{position:fixed;inset:auto;margin:0}.rv-menu-panel[data-positioned=false]{animation:none}.rv-menu-panel[data-top-layer=true][data-placement^=bottom][data-flipped=true]{transform-origin:bottom center}.rv-menu-panel[data-top-layer=true][data-placement^=top][data-flipped=true]{transform-origin:top center}.rv-menu-panel{
|
|
713
|
+
styles: [".rv-menu-trigger{display:inline-flex;align-items:center}.rv-menu-panel{display:flex;flex-direction:column;gap:2px}.rv-menu-panel hr{border:0;border-top:1px solid var(--rv-menu-border, #e0e0e0);margin:6px 4px}rv-menu{position:relative;display:inline-block}.rv-menu-panel[data-top-layer=true]{position:fixed;inset:auto;margin:0}.rv-menu-panel[data-positioned=false]{animation:none}.rv-menu-panel[data-top-layer=true][data-placement^=bottom][data-flipped=true]{transform-origin:bottom center}.rv-menu-panel[data-top-layer=true][data-placement^=top][data-flipped=true]{transform-origin:top center}.rv-menu-panel{position:absolute;z-index:var(--rv-menu-z, 500);min-width:var(--rv-menu-width, 16rem);max-width:calc(100dvw - 2rem);max-height:min(20rem,calc(100dvh - 2rem));overflow-y:auto;background:var(--rv-menu-bg, #ffffff);color:var(--rv-menu-fg, #111111);font-family:var(--rv-menu-font, system-ui, -apple-system, \"Segoe UI\", sans-serif);border:1px solid var(--rv-menu-border, #e0e0e0);border-radius:var(--rv-menu-radius, 12px);box-shadow:var(--rv-menu-shadow, 0 16px 48px rgba(0, 0, 0, .22));padding:var(--rv-menu-pad, 6px)}.rv-menu-panel[data-placement=bottom-start]{inset-block-start:calc(100% + 6px);inset-inline-start:0}.rv-menu-panel[data-placement=bottom-end]{inset-block-start:calc(100% + 6px);inset-inline-end:0}.rv-menu-panel[data-placement=top-start]{inset-block-end:calc(100% + 6px);inset-inline-start:0}.rv-menu-panel[data-placement=top-end]{inset-block-end:calc(100% + 6px);inset-inline-end:0}.rv-menu-panel [rvmenuitem]{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;border:0;border-radius:8px;background:transparent;color:inherit;font:inherit;font-size:14px;line-height:1.4;text-align:start;padding:8px 10px;cursor:pointer}.rv-menu-panel [rvmenuitem][data-active=true]{background:color-mix(in srgb,currentColor 10%,transparent)}.rv-menu-panel [rvmenuitem]:hover{background:color-mix(in srgb,currentColor 8%,transparent)}.rv-menu-panel [rvmenuitem]:focus-visible{outline:2px solid currentColor;outline-offset:-2px}.rv-menu-panel [rvmenuitem][aria-disabled=true]{opacity:.45;cursor:default}.rv-menu-panel [rvmenuitem] svg,.rv-menu-panel [rvmenuitem] [data-icon]{width:16px;height:16px;flex:none;color:var(--rv-menu-muted)}.rv-menu-panel [rvmenuitem][data-active=true] svg,.rv-menu-panel [rvmenuitem][data-active=true] [data-icon]{color:inherit}.rv-menu-panel{transform-origin:top center;animation:rv-menu-in var(--rv-menu-duration, .16s) var(--rv-menu-easing, cubic-bezier(.16, 1, .3, 1))}.rv-menu-panel[data-placement=top-start],.rv-menu-panel[data-placement=top-end]{--rv-menu-from-y: 6px;transform-origin:bottom center}@media(prefers-reduced-motion:reduce){.rv-menu-panel{animation:none}}@keyframes rv-menu-in{0%{opacity:0;transform:translateY(var(--rv-menu-from-y, -6px)) scale(.96)}}\n"]
|
|
529
714
|
}]
|
|
530
715
|
}],
|
|
531
716
|
ctorParameters: () => [],
|
|
@@ -546,6 +731,38 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
546
731
|
required: false
|
|
547
732
|
}]
|
|
548
733
|
}],
|
|
734
|
+
menuLabel: [{
|
|
735
|
+
type: i0.Input,
|
|
736
|
+
args: [{
|
|
737
|
+
isSignal: true,
|
|
738
|
+
alias: "menuLabel",
|
|
739
|
+
required: false
|
|
740
|
+
}]
|
|
741
|
+
}],
|
|
742
|
+
items: [{
|
|
743
|
+
type: i0.Input,
|
|
744
|
+
args: [{
|
|
745
|
+
isSignal: true,
|
|
746
|
+
alias: "items",
|
|
747
|
+
required: false
|
|
748
|
+
}]
|
|
749
|
+
}],
|
|
750
|
+
panelClass: [{
|
|
751
|
+
type: i0.Input,
|
|
752
|
+
args: [{
|
|
753
|
+
isSignal: true,
|
|
754
|
+
alias: "panelClass",
|
|
755
|
+
required: false
|
|
756
|
+
}]
|
|
757
|
+
}],
|
|
758
|
+
itemClass: [{
|
|
759
|
+
type: i0.Input,
|
|
760
|
+
args: [{
|
|
761
|
+
isSignal: true,
|
|
762
|
+
alias: "itemClass",
|
|
763
|
+
required: false
|
|
764
|
+
}]
|
|
765
|
+
}],
|
|
549
766
|
picked: [{
|
|
550
767
|
type: i0.Output,
|
|
551
768
|
args: ["picked"]
|
|
@@ -557,6 +774,13 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
557
774
|
closed: [{
|
|
558
775
|
type: i0.Output,
|
|
559
776
|
args: ["closed"]
|
|
777
|
+
}],
|
|
778
|
+
projectedItems: [{
|
|
779
|
+
type: i0.ContentChildren,
|
|
780
|
+
args: [i0.forwardRef(() => RiviniaMenuItem), {
|
|
781
|
+
descendants: true,
|
|
782
|
+
isSignal: true
|
|
783
|
+
}]
|
|
560
784
|
}]
|
|
561
785
|
}
|
|
562
786
|
});
|