ngwr 7.1.0 → 7.3.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.
- package/LICENSE +1 -1
- package/README.md +5 -3
- package/alert/styles/_index.scss +2 -0
- package/back-top/styles/_index.scss +4 -2
- package/carousel/styles/_index.scss +2 -0
- package/cascader/styles/_index.scss +16 -0
- package/color-picker/styles/_index.scss +7 -0
- package/command-palette/styles/_index.scss +28 -0
- package/density/styles/_index.scss +10 -0
- package/descriptions/styles/_index.scss +59 -0
- package/dialog/styles/_index.scss +2 -0
- package/drawer/styles/_index.scss +2 -0
- package/dropdown/styles/_index.scss +1 -0
- package/fesm2022/ngwr-carousel.mjs +45 -4
- package/fesm2022/ngwr-carousel.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +2 -2
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette.mjs +17 -3
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +77 -5
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-density.mjs +3 -3
- package/fesm2022/ngwr-density.mjs.map +1 -1
- package/fesm2022/ngwr-descriptions.mjs +11 -2
- package/fesm2022/ngwr-descriptions.mjs.map +1 -1
- package/fesm2022/ngwr-dialog.mjs +11 -4
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +13 -3
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +66 -5
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +35 -11
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-lightbox.mjs +45 -2
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-overlay.mjs +70 -1
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-page-header.mjs +11 -3
- package/fesm2022/ngwr-page-header.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +11 -3
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +36 -10
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text.mjs +15 -4
- package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +35 -14
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-stepper.mjs +11 -2
- package/fesm2022/ngwr-stepper.mjs.map +1 -1
- package/fesm2022/ngwr-table.mjs +10 -4
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +38 -6
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-toast.mjs +54 -2
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-toolbar.mjs +11 -4
- package/fesm2022/ngwr-toolbar.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/lightbox/styles/_index.scss +4 -0
- package/llms-full.txt +673 -0
- package/llms.txt +106 -0
- package/overlay/styles/_index.scss +31 -0
- package/package.json +6 -5
- package/page-header/styles/_index.scss +16 -0
- package/pagination/styles/_index.scss +34 -0
- package/popover/styles/_index.scss +1 -0
- package/select/styles/_index.scss +27 -0
- package/slider/styles/_index.scss +3 -0
- package/splitter/styles/_index.scss +3 -0
- package/stepper/styles/_index.scss +30 -0
- package/styles.scss +1 -0
- package/table/styles/_index.scss +61 -0
- package/tabs/styles/_index.scss +24 -0
- package/theme/styles/_mixins.scss +47 -0
- package/toast/styles/_index.scss +32 -1
- package/toolbar/styles/_index.scss +29 -0
- package/tree/styles/_index.scss +15 -0
- package/types/ngwr-carousel.d.ts +8 -1
- package/types/ngwr-command-palette.d.ts +13 -1
- package/types/ngwr-context-menu.d.ts +25 -3
- package/types/ngwr-density.d.ts +2 -2
- package/types/ngwr-descriptions.d.ts +8 -1
- package/types/ngwr-dialog.d.ts +7 -0
- package/types/ngwr-drag-drop.d.ts +13 -1
- package/types/ngwr-drawer.d.ts +11 -3
- package/types/ngwr-dropdown.d.ts +10 -1
- package/types/ngwr-lightbox.d.ts +5 -0
- package/types/ngwr-overlay.d.ts +69 -1
- package/types/ngwr-page-header.d.ts +8 -1
- package/types/ngwr-pagination.d.ts +7 -1
- package/types/ngwr-popover.d.ts +10 -1
- package/types/ngwr-rotating-text.d.ts +1 -0
- package/types/ngwr-select.d.ts +10 -1
- package/types/ngwr-stepper.d.ts +8 -1
- package/types/ngwr-table.d.ts +7 -1
- package/types/ngwr-tabs.d.ts +6 -0
- package/types/ngwr-toolbar.d.ts +7 -1
- package/types/ngwr-version.d.ts +1 -1
|
@@ -6,6 +6,7 @@ import { input, model, output, signal, viewChild, computed, inject, DestroyRef,
|
|
|
6
6
|
import { WrHotkey } from 'ngwr/hotkey';
|
|
7
7
|
import { useI18nText } from 'ngwr/i18n';
|
|
8
8
|
import { WrIcon } from 'ngwr/icon';
|
|
9
|
+
import { WR_RESPONSIVE_OVERLAYS, wrPresentAsSheet } from 'ngwr/overlay';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @license
|
|
@@ -76,12 +77,23 @@ class WrCommandPalette {
|
|
|
76
77
|
resolvedEmpty = useI18nText(this.emptyText, 'commandPalette.noResults', 'No results');
|
|
77
78
|
/** Auto-close on `(picked)`. Set false to keep open. @default true */
|
|
78
79
|
closeOnPick = input(true, { ...(ngDevMode ? { debugName: "closeOnPick" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
80
|
+
/**
|
|
81
|
+
* Present the palette full-screen on small viewports instead of a centred
|
|
82
|
+
* modal. `undefined` follows the app-wide `provideWrResponsiveOverlays()`
|
|
83
|
+
* setting; `true`/`false` overrides it. The palette docks to the top (it
|
|
84
|
+
* auto-focuses its input, so the on-screen keyboard stays clear).
|
|
85
|
+
* @default undefined
|
|
86
|
+
*/
|
|
87
|
+
responsive = input(undefined, { ...(ngDevMode ? { debugName: "responsive" } : /* istanbul ignore next */ {}), transform: (v) => (v == null ? undefined : coerceBooleanProperty(v)) });
|
|
79
88
|
/** Fires when the user commits an item (Enter / click). */
|
|
80
89
|
picked = output();
|
|
81
90
|
query = signal('', /* @ts-ignore */
|
|
82
91
|
...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
|
|
83
92
|
activeIndex = signal(0, /* @ts-ignore */
|
|
84
93
|
...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
94
|
+
/** Whether the current opening is presented full-screen. Decided on open. */
|
|
95
|
+
presentAsSheet = signal(false, /* @ts-ignore */
|
|
96
|
+
...(ngDevMode ? [{ debugName: "presentAsSheet" }] : /* istanbul ignore next */ []));
|
|
85
97
|
inputEl = viewChild('input', /* @ts-ignore */
|
|
86
98
|
...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
|
|
87
99
|
panelEl = viewChild('panel', /* @ts-ignore */
|
|
@@ -99,6 +111,7 @@ class WrCommandPalette {
|
|
|
99
111
|
}, /* @ts-ignore */
|
|
100
112
|
...(ngDevMode ? [{ debugName: "activeOptionId" }] : /* istanbul ignore next */ []));
|
|
101
113
|
hotkeys = inject(WrHotkey);
|
|
114
|
+
responsiveConfig = inject(WR_RESPONSIVE_OVERLAYS);
|
|
102
115
|
destroyRef = inject(DestroyRef);
|
|
103
116
|
focusTrapFactory = inject(ConfigurableFocusTrapFactory);
|
|
104
117
|
isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
@@ -126,6 +139,7 @@ class WrCommandPalette {
|
|
|
126
139
|
return;
|
|
127
140
|
this.query.set('');
|
|
128
141
|
this.activeIndex.set(0);
|
|
142
|
+
this.presentAsSheet.set(wrPresentAsSheet(this.responsive(), this.responsiveConfig));
|
|
129
143
|
});
|
|
130
144
|
// Focus trap + restore.
|
|
131
145
|
effect(() => {
|
|
@@ -244,12 +258,12 @@ class WrCommandPalette {
|
|
|
244
258
|
this.close();
|
|
245
259
|
}
|
|
246
260
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: WrCommandPalette, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
247
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: WrCommandPalette, isStandalone: true, selector: "wr-command-palette", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, closeOnPick: { classPropertyName: "closeOnPick", publicName: "closeOnPick", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", picked: "picked" }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "panelEl", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <div
|
|
261
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: WrCommandPalette, isStandalone: true, selector: "wr-command-palette", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, trigger: { classPropertyName: "trigger", publicName: "trigger", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, closeOnPick: { classPropertyName: "closeOnPick", publicName: "closeOnPick", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", picked: "picked" }, viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "panelEl", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <div\n class=\"wr-command-palette\"\n [class.wr-command-palette--sheet]=\"presentAsSheet()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n >\n <!-- Backdrop captures clicks to close. Not focusable \u2014 keyboard users use\n Esc on the panel below. -->\n\n <div class=\"wr-command-palette__backdrop\" aria-hidden=\"true\" (click)=\"onBackdropClick()\"></div>\n\n <!-- Keydown is delegated from the search input; tabindex enables Esc when\n the input is unfocused. -->\n <div #panel class=\"wr-command-palette__panel\" tabindex=\"-1\" (keydown)=\"onKeydown($event)\">\n <div class=\"wr-command-palette__search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M11 11 L14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n <input\n #input\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-expanded]=\"true\"\n [attr.aria-activedescendant]=\"activeOptionId() || null\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"query()\"\n (input)=\"onQueryInput($event)\"\n />\n <kbd class=\"wr-command-palette__hint\">esc</kbd>\n </div>\n\n <div class=\"wr-command-palette__body\" role=\"listbox\" [attr.id]=\"listboxId\">\n @if (filtered().length === 0) {\n <div class=\"wr-command-palette__empty\">{{ resolvedEmpty() }}</div>\n } @else {\n @for (bucket of buckets(); track bucket.title) {\n <div class=\"wr-command-palette__group\">\n @if (bucket.title) {\n <div class=\"wr-command-palette__group-title\">{{ bucket.title }}</div>\n }\n @for (item of bucket.items; track item.id) {\n <div\n class=\"wr-command-palette__option\"\n role=\"option\"\n [attr.id]=\"optionId(indexOf(item))\"\n [class.wr-command-palette__option--active]=\"indexOf(item) === activeIndex()\"\n [attr.aria-selected]=\"indexOf(item) === activeIndex()\"\n (mouseenter)=\"onItemHover(item)\"\n (mousedown)=\"onItemClick(item, $event)\"\n >\n @if (item.icon) {\n <wr-icon class=\"wr-command-palette__option-icon\" [name]=\"item.icon\" size=\"16\" />\n } @else {\n <span class=\"wr-command-palette__option-icon\" aria-hidden=\"true\"></span>\n }\n <div class=\"wr-command-palette__option-body\">\n <div class=\"wr-command-palette__option-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"wr-command-palette__option-description\">{{ item.description }}</div>\n }\n </div>\n @if (item.shortcut) {\n <kbd class=\"wr-command-palette__option-shortcut\">{{ item.shortcut }}</kbd>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n </div>\n}\n", dependencies: [{ kind: "component", type: WrIcon, selector: "wr-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
248
262
|
}
|
|
249
263
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: WrCommandPalette, decorators: [{
|
|
250
264
|
type: Component,
|
|
251
|
-
args: [{ selector: 'wr-command-palette', encapsulation: ViewEncapsulation.None, imports: [WrIcon], template: "@if (open()) {\n <div
|
|
252
|
-
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], closeOnPick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnPick", required: false }] }], picked: [{ type: i0.Output, args: ["picked"] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], panelEl: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
|
|
265
|
+
args: [{ selector: 'wr-command-palette', encapsulation: ViewEncapsulation.None, imports: [WrIcon], template: "@if (open()) {\n <div\n class=\"wr-command-palette\"\n [class.wr-command-palette--sheet]=\"presentAsSheet()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n >\n <!-- Backdrop captures clicks to close. Not focusable \u2014 keyboard users use\n Esc on the panel below. -->\n\n <div class=\"wr-command-palette__backdrop\" aria-hidden=\"true\" (click)=\"onBackdropClick()\"></div>\n\n <!-- Keydown is delegated from the search input; tabindex enables Esc when\n the input is unfocused. -->\n <div #panel class=\"wr-command-palette__panel\" tabindex=\"-1\" (keydown)=\"onKeydown($event)\">\n <div class=\"wr-command-palette__search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M11 11 L14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n <input\n #input\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-expanded]=\"true\"\n [attr.aria-activedescendant]=\"activeOptionId() || null\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"query()\"\n (input)=\"onQueryInput($event)\"\n />\n <kbd class=\"wr-command-palette__hint\">esc</kbd>\n </div>\n\n <div class=\"wr-command-palette__body\" role=\"listbox\" [attr.id]=\"listboxId\">\n @if (filtered().length === 0) {\n <div class=\"wr-command-palette__empty\">{{ resolvedEmpty() }}</div>\n } @else {\n @for (bucket of buckets(); track bucket.title) {\n <div class=\"wr-command-palette__group\">\n @if (bucket.title) {\n <div class=\"wr-command-palette__group-title\">{{ bucket.title }}</div>\n }\n @for (item of bucket.items; track item.id) {\n <div\n class=\"wr-command-palette__option\"\n role=\"option\"\n [attr.id]=\"optionId(indexOf(item))\"\n [class.wr-command-palette__option--active]=\"indexOf(item) === activeIndex()\"\n [attr.aria-selected]=\"indexOf(item) === activeIndex()\"\n (mouseenter)=\"onItemHover(item)\"\n (mousedown)=\"onItemClick(item, $event)\"\n >\n @if (item.icon) {\n <wr-icon class=\"wr-command-palette__option-icon\" [name]=\"item.icon\" size=\"16\" />\n } @else {\n <span class=\"wr-command-palette__option-icon\" aria-hidden=\"true\"></span>\n }\n <div class=\"wr-command-palette__option-body\">\n <div class=\"wr-command-palette__option-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"wr-command-palette__option-description\">{{ item.description }}</div>\n }\n </div>\n @if (item.shortcut) {\n <kbd class=\"wr-command-palette__option-shortcut\">{{ item.shortcut }}</kbd>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n </div>\n}\n" }]
|
|
266
|
+
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], trigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "trigger", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], closeOnPick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnPick", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], picked: [{ type: i0.Output, args: ["picked"] }], inputEl: [{ type: i0.ViewChild, args: ['input', { isSignal: true }] }], panelEl: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
|
|
253
267
|
|
|
254
268
|
/**
|
|
255
269
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-command-palette.mjs","sources":["../../../projects/lib/command-palette/command-palette.ts","../../../projects/lib/command-palette/command-palette.html","../../../projects/lib/command-palette/ngwr-command-palette.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from '@angular/cdk/a11y';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n type ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\n\nimport { WrHotkey, type WrHotkeyHandle, type WrHotkeySpec } from 'ngwr/hotkey';\nimport { useI18nText } from 'ngwr/i18n';\nimport { WrIcon } from 'ngwr/icon';\n\nimport type { WrCommandItem } from './interfaces';\n\ninterface Bucket {\n readonly title: string | null;\n readonly items: readonly WrCommandItem[];\n}\n\nlet listboxUid = 0;\n\nfunction bucketize(items: readonly WrCommandItem[]): readonly Bucket[] {\n const map = new Map<string | null, WrCommandItem[]>();\n for (const item of items) {\n const key = item.group ?? null;\n const bucket = map.get(key);\n if (bucket) bucket.push(item);\n else map.set(key, [item]);\n }\n return [...map.entries()].map(([title, items]) => ({ title, items }));\n}\n\nfunction matches(item: WrCommandItem, query: string): boolean {\n if (!query) return true;\n const q = query.toLowerCase();\n if (item.label.toLowerCase().includes(q)) return true;\n if (item.description?.toLowerCase().includes(q)) return true;\n if (item.group?.toLowerCase().includes(q)) return true;\n if (item.keywords?.some(k => k.toLowerCase().includes(q))) return true;\n return false;\n}\n\n/**\n * `⌘K`-style command palette — a centred modal with a search input and\n * filtered list of actions. Items can be grouped, have icons, descriptions,\n * and visual shortcut hints.\n *\n * Drop one at the root of the app, pass it the list of commands, and bind\n * a global hotkey (default `'mod+k'`). Use `[(open)]` for controlled\n * visibility, or let it manage itself.\n *\n * @example\n * ```html\n * <wr-command-palette [items]=\"commands\" trigger=\"mod+k\" (picked)=\"onPicked($event)\" />\n * ```\n *\n * @see https://ngwr.dev/components/command-palette\n */\n@Component({\n selector: 'wr-command-palette',\n templateUrl: './command-palette.html',\n encapsulation: ViewEncapsulation.None,\n imports: [WrIcon],\n})\nexport class WrCommandPalette {\n /** Items shown in the palette. */\n readonly items = input<readonly WrCommandItem[]>([]);\n\n /** Controlled open state (two-way bindable). @default false */\n readonly open = model(false);\n\n /** Global hotkey that opens the palette. `null` disables auto-binding. @default 'mod+k' */\n readonly trigger = input<WrHotkeySpec | null>('mod+k');\n\n /** Search input placeholder. Falls back to `commandPalette.placeholder`. */\n readonly placeholder = input<string | null>(null);\n\n /** Text shown when no items match. Falls back to `commandPalette.noResults`. */\n readonly emptyText = input<string | null>(null);\n\n protected readonly resolvedPlaceholder = useI18nText(\n this.placeholder,\n 'commandPalette.placeholder',\n 'Type a command or search…'\n );\n protected readonly resolvedEmpty = useI18nText(this.emptyText, 'commandPalette.noResults', 'No results');\n\n /** Auto-close on `(picked)`. Set false to keep open. @default true */\n readonly closeOnPick = input(true, { transform: coerceBooleanProperty });\n\n /** Fires when the user commits an item (Enter / click). */\n readonly picked = output<WrCommandItem>();\n\n protected readonly query = signal('');\n protected readonly activeIndex = signal(0);\n protected readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('input');\n protected readonly panelEl = viewChild<ElementRef<HTMLElement>>('panel');\n\n /** Listbox id (referenced by the input's `aria-controls`). */\n protected readonly listboxId = `wr-command-palette-listbox-${++listboxUid}`;\n\n /** @internal Build a stable option id for a given flat index. */\n protected optionId(i: number): string {\n return `${this.listboxId}-opt-${i}`;\n }\n\n /** Id of the active option for `aria-activedescendant`. */\n protected readonly activeOptionId = computed<string | null>(() => {\n const i = this.activeIndex();\n return i >= 0 && i < this.filtered().length ? this.optionId(i) : null;\n });\n\n private readonly hotkeys = inject(WrHotkey);\n private readonly destroyRef = inject(DestroyRef);\n private readonly focusTrapFactory = inject(ConfigurableFocusTrapFactory);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private bindingHandle: WrHotkeyHandle | null = null;\n private focusTrap: ConfigurableFocusTrap | null = null;\n private previouslyFocused: HTMLElement | null = null;\n\n /** Flat filtered list — what keyboard navigation walks. */\n protected readonly filtered = computed<readonly WrCommandItem[]>(() =>\n this.items().filter(item => matches(item, this.query()))\n );\n\n /** Grouped view — what the template renders. */\n protected readonly buckets = computed<readonly Bucket[]>(() => bucketize(this.filtered()));\n\n constructor() {\n // Bind / re-bind the global trigger whenever the spec changes.\n effect(() => {\n this.bindingHandle?.unbind();\n const spec = this.trigger();\n if (!spec) return;\n this.bindingHandle = this.hotkeys.bind(spec, () => this.open.update(v => !v), { allowInInput: true });\n });\n\n // Reset query + active index whenever we open; focus the input.\n effect(() => {\n if (!this.open()) return;\n this.query.set('');\n this.activeIndex.set(0);\n });\n\n // Focus trap + restore.\n effect(() => {\n if (!this.isBrowser) return;\n if (this.open()) {\n const active = document.activeElement;\n this.previouslyFocused = active instanceof HTMLElement ? active : null;\n queueMicrotask(() => {\n const host = this.panelEl()?.nativeElement;\n if (!host) return;\n this.focusTrap?.destroy();\n this.focusTrap = this.focusTrapFactory.create(host);\n void this.focusTrap.focusInitialElementWhenReady();\n });\n } else {\n this.focusTrap?.destroy();\n this.focusTrap = null;\n const restore = this.previouslyFocused;\n this.previouslyFocused = null;\n if (restore && typeof restore.focus === 'function') restore.focus();\n }\n });\n\n afterNextRender(() => {\n if (this.open()) this.inputEl()?.nativeElement.focus();\n });\n\n // Auto-focus the input when opened.\n effect(() => {\n if (!this.open()) return;\n queueMicrotask(() => this.inputEl()?.nativeElement.focus());\n });\n\n // Clamp the active index when the filtered list shrinks.\n effect(() => {\n const max = Math.max(0, this.filtered().length - 1);\n if (this.activeIndex() > max) this.activeIndex.set(max);\n });\n\n this.destroyRef.onDestroy(() => this.bindingHandle?.unbind());\n }\n\n // Template handlers\n\n protected onQueryInput(event: Event): void {\n this.query.set((event.target as HTMLInputElement).value);\n this.activeIndex.set(0);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const list = this.filtered();\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n if (list.length > 0) this.activeIndex.set((this.activeIndex() + 1) % list.length);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (list.length > 0) this.activeIndex.set((this.activeIndex() - 1 + list.length) % list.length);\n break;\n case 'Home':\n event.preventDefault();\n this.activeIndex.set(0);\n break;\n case 'End':\n event.preventDefault();\n this.activeIndex.set(Math.max(0, list.length - 1));\n break;\n case 'Enter': {\n event.preventDefault();\n const item = list[this.activeIndex()];\n if (item) this.commit(item);\n break;\n }\n case 'Escape':\n event.preventDefault();\n this.close();\n break;\n default:\n break;\n }\n }\n\n protected onBackdropClick(): void {\n this.close();\n }\n\n protected onItemClick(item: WrCommandItem, event: MouseEvent): void {\n event.preventDefault();\n this.commit(item);\n }\n\n protected onItemHover(item: WrCommandItem): void {\n const i = this.filtered().indexOf(item);\n if (i >= 0) this.activeIndex.set(i);\n }\n\n /** Flat index of an item within the filtered list — for highlight checks. */\n protected indexOf(item: WrCommandItem): number {\n return this.filtered().indexOf(item);\n }\n\n // Public API\n\n /** Open the palette. */\n show(): void {\n this.open.set(true);\n }\n\n /** Close the palette. */\n close(): void {\n this.open.set(false);\n }\n\n // Internals\n\n private commit(item: WrCommandItem): void {\n item.action?.();\n this.picked.emit(item);\n if (this.closeOnPick()) this.close();\n }\n}\n","@if (open()) {\n <div class=\"wr-command-palette\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Command palette\">\n <!-- Backdrop captures clicks to close. Not focusable — keyboard users use\n Esc on the panel below. -->\n\n <div class=\"wr-command-palette__backdrop\" aria-hidden=\"true\" (click)=\"onBackdropClick()\"></div>\n\n <!-- Keydown is delegated from the search input; tabindex enables Esc when\n the input is unfocused. -->\n <div #panel class=\"wr-command-palette__panel\" tabindex=\"-1\" (keydown)=\"onKeydown($event)\">\n <div class=\"wr-command-palette__search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M11 11 L14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n <input\n #input\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-expanded]=\"true\"\n [attr.aria-activedescendant]=\"activeOptionId() || null\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"query()\"\n (input)=\"onQueryInput($event)\"\n />\n <kbd class=\"wr-command-palette__hint\">esc</kbd>\n </div>\n\n <div class=\"wr-command-palette__body\" role=\"listbox\" [attr.id]=\"listboxId\">\n @if (filtered().length === 0) {\n <div class=\"wr-command-palette__empty\">{{ resolvedEmpty() }}</div>\n } @else {\n @for (bucket of buckets(); track bucket.title) {\n <div class=\"wr-command-palette__group\">\n @if (bucket.title) {\n <div class=\"wr-command-palette__group-title\">{{ bucket.title }}</div>\n }\n @for (item of bucket.items; track item.id) {\n <div\n class=\"wr-command-palette__option\"\n role=\"option\"\n [attr.id]=\"optionId(indexOf(item))\"\n [class.wr-command-palette__option--active]=\"indexOf(item) === activeIndex()\"\n [attr.aria-selected]=\"indexOf(item) === activeIndex()\"\n (mouseenter)=\"onItemHover(item)\"\n (mousedown)=\"onItemClick(item, $event)\"\n >\n @if (item.icon) {\n <wr-icon class=\"wr-command-palette__option-icon\" [name]=\"item.icon\" size=\"16\" />\n } @else {\n <span class=\"wr-command-palette__option-icon\" aria-hidden=\"true\"></span>\n }\n <div class=\"wr-command-palette__option-body\">\n <div class=\"wr-command-palette__option-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"wr-command-palette__option-description\">{{ item.description }}</div>\n }\n </div>\n @if (item.shortcut) {\n <kbd class=\"wr-command-palette__option-shortcut\">{{ item.shortcut }}</kbd>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;AAAA;;;;;AAKG;AAiCH,IAAI,UAAU,GAAG,CAAC;AAElB,SAAS,SAAS,CAAC,KAA+B,EAAA;AAChD,IAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkC;AACrD,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI;QAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;AAC3B,QAAA,IAAI,MAAM;AAAE,YAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;;YACxB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3B;IACA,OAAO,CAAC,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AACvE;AAEA,SAAS,OAAO,CAAC,IAAmB,EAAE,KAAa,EAAA;AACjD,IAAA,IAAI,CAAC,KAAK;AAAE,QAAA,OAAO,IAAI;AACvB,IAAA,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE;IAC7B,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAE,QAAA,OAAO,IAAI;IACrD,IAAI,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAE,QAAA,OAAO,IAAI;IAC5D,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;AAAE,QAAA,OAAO,IAAI;AACtD,IAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAAE,QAAA,OAAO,IAAI;AACtE,IAAA,OAAO,KAAK;AACd;AAEA;;;;;;;;;;;;;;;AAeG;MAOU,gBAAgB,CAAA;;IAElB,KAAK,GAAG,KAAK,CAA2B,EAAE;8EAAC;;IAG3C,IAAI,GAAG,KAAK,CAAC,KAAK;6EAAC;;IAGnB,OAAO,GAAG,KAAK,CAAsB,OAAO;gFAAC;;IAG7C,WAAW,GAAG,KAAK,CAAgB,IAAI;oFAAC;;IAGxC,SAAS,GAAG,KAAK,CAAgB,IAAI;kFAAC;IAE5B,mBAAmB,GAAG,WAAW,CAClD,IAAI,CAAC,WAAW,EAChB,4BAA4B,EAC5B,2BAA2B,CAC5B;IACkB,aAAa,GAAG,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,EAAE,YAAY,CAAC;;IAG/F,WAAW,GAAG,KAAK,CAAC,IAAI,mFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;IAG/D,MAAM,GAAG,MAAM,EAAiB;IAEtB,KAAK,GAAG,MAAM,CAAC,EAAE;8EAAC;IAClB,WAAW,GAAG,MAAM,CAAC,CAAC;oFAAC;IACvB,OAAO,GAAG,SAAS,CAA+B,OAAO;gFAAC;IAC1D,OAAO,GAAG,SAAS,CAA0B,OAAO;gFAAC;;AAGrD,IAAA,SAAS,GAAG,CAAA,2BAAA,EAA8B,EAAE,UAAU,EAAE;;AAGjE,IAAA,QAAQ,CAAC,CAAS,EAAA;AAC1B,QAAA,OAAO,GAAG,IAAI,CAAC,SAAS,CAAA,KAAA,EAAQ,CAAC,EAAE;IACrC;;AAGmB,IAAA,cAAc,GAAG,QAAQ,CAAgB,MAAK;AAC/D,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE;QAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IACvE,CAAC;uFAAC;AAEe,IAAA,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC1B,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAC/B,IAAA,gBAAgB,GAAG,MAAM,CAAC,4BAA4B,CAAC;IACvD,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC3D,aAAa,GAA0B,IAAI;IAC3C,SAAS,GAAiC,IAAI;IAC9C,iBAAiB,GAAuB,IAAI;;IAGjC,QAAQ,GAAG,QAAQ,CAA2B,MAC/D,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;iFACzD;;AAGkB,IAAA,OAAO,GAAG,QAAQ,CAAoB,MAAM,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gFAAC;AAE1F,IAAA,WAAA,GAAA;;QAEE,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE;AAC5B,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE;AAC3B,YAAA,IAAI,CAAC,IAAI;gBAAE;AACX,YAAA,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AACvG,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE;AAClB,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;AAClB,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AACzB,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,IAAI,CAAC,SAAS;gBAAE;AACrB,YAAA,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE;AACf,gBAAA,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa;AACrC,gBAAA,IAAI,CAAC,iBAAiB,GAAG,MAAM,YAAY,WAAW,GAAG,MAAM,GAAG,IAAI;gBACtE,cAAc,CAAC,MAAK;oBAClB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa;AAC1C,oBAAA,IAAI,CAAC,IAAI;wBAAE;AACX,oBAAA,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE;oBACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC;AACnD,oBAAA,KAAK,IAAI,CAAC,SAAS,CAAC,4BAA4B,EAAE;AACpD,gBAAA,CAAC,CAAC;YACJ;iBAAO;AACL,gBAAA,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE;AACzB,gBAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,gBAAA,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB;AACtC,gBAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI;AAC7B,gBAAA,IAAI,OAAO,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,UAAU;oBAAE,OAAO,CAAC,KAAK,EAAE;YACrE;AACF,QAAA,CAAC,CAAC;QAEF,eAAe,CAAC,MAAK;YACnB,IAAI,IAAI,CAAC,IAAI,EAAE;gBAAE,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,KAAK,EAAE;AACxD,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE;AAClB,YAAA,cAAc,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC;AAC7D,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AACnD,YAAA,IAAI,IAAI,CAAC,WAAW,EAAE,GAAG,GAAG;AAAE,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;AACzD,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAC/D;;AAIU,IAAA,YAAY,CAAC,KAAY,EAAA;QACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAE,KAAK,CAAC,MAA2B,CAAC,KAAK,CAAC;AACxD,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB;AAEU,IAAA,SAAS,CAAC,KAAoB,EAAA;AACtC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC5B,QAAA,QAAQ,KAAK,CAAC,GAAG;AACf,YAAA,KAAK,WAAW;gBACd,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;AAAE,oBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC;gBACjF;AACF,YAAA,KAAK,SAAS;gBACZ,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;oBAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;gBAC/F;AACF,YAAA,KAAK,MAAM;gBACT,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;gBACvB;AACF,YAAA,KAAK,KAAK;gBACR,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAClD;YACF,KAAK,OAAO,EAAE;gBACZ,KAAK,CAAC,cAAc,EAAE;gBACtB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;AACrC,gBAAA,IAAI,IAAI;AAAE,oBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBAC3B;YACF;AACA,YAAA,KAAK,QAAQ;gBACX,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,KAAK,EAAE;gBACZ;AACF,YAAA;gBACE;;IAEN;IAEU,eAAe,GAAA;QACvB,IAAI,CAAC,KAAK,EAAE;IACd;IAEU,WAAW,CAAC,IAAmB,EAAE,KAAiB,EAAA;QAC1D,KAAK,CAAC,cAAc,EAAE;AACtB,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IACnB;AAEU,IAAA,WAAW,CAAC,IAAmB,EAAA;QACvC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC;AAAE,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC;;AAGU,IAAA,OAAO,CAAC,IAAmB,EAAA;QACnC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACtC;;;IAKA,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACrB;;IAGA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;IACtB;;AAIQ,IAAA,MAAM,CAAC,IAAmB,EAAA;AAChC,QAAA,IAAI,CAAC,MAAM,IAAI;AACf,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,IAAI,CAAC,WAAW,EAAE;YAAE,IAAI,CAAC,KAAK,EAAE;IACtC;uGAvMW,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAhB,gBAAgB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,IAAA,EAAA,YAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,SAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,OAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,SAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,OAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECnF7B,u5GA0EA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDOY,MAAM,EAAA,QAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAEL,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAN5B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oBAAoB,iBAEf,iBAAiB,CAAC,IAAI,EAAA,OAAA,EAC5B,CAAC,MAAM,CAAC,EAAA,QAAA,EAAA,u5GAAA,EAAA;AAiCoD,SAAA,CAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,EAAA,KAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,OAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,YAAA,CAAA,EAAA,CAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,SAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,aAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,SAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,WAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,aAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,QAAA,CAAA,EAAA,CAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,IAAA,EAAA,CAAA,OAAO,iEACZ,OAAO,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AEnHzE;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ngwr-command-palette.mjs","sources":["../../../projects/lib/command-palette/command-palette.ts","../../../projects/lib/command-palette/command-palette.html","../../../projects/lib/command-palette/ngwr-command-palette.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from '@angular/cdk/a11y';\nimport { type BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n type ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\n\nimport { WrHotkey, type WrHotkeyHandle, type WrHotkeySpec } from 'ngwr/hotkey';\nimport { useI18nText } from 'ngwr/i18n';\nimport { WrIcon } from 'ngwr/icon';\nimport { WR_RESPONSIVE_OVERLAYS, wrPresentAsSheet } from 'ngwr/overlay';\n\nimport type { WrCommandItem } from './interfaces';\n\ninterface Bucket {\n readonly title: string | null;\n readonly items: readonly WrCommandItem[];\n}\n\nlet listboxUid = 0;\n\nfunction bucketize(items: readonly WrCommandItem[]): readonly Bucket[] {\n const map = new Map<string | null, WrCommandItem[]>();\n for (const item of items) {\n const key = item.group ?? null;\n const bucket = map.get(key);\n if (bucket) bucket.push(item);\n else map.set(key, [item]);\n }\n return [...map.entries()].map(([title, items]) => ({ title, items }));\n}\n\nfunction matches(item: WrCommandItem, query: string): boolean {\n if (!query) return true;\n const q = query.toLowerCase();\n if (item.label.toLowerCase().includes(q)) return true;\n if (item.description?.toLowerCase().includes(q)) return true;\n if (item.group?.toLowerCase().includes(q)) return true;\n if (item.keywords?.some(k => k.toLowerCase().includes(q))) return true;\n return false;\n}\n\n/**\n * `⌘K`-style command palette — a centred modal with a search input and\n * filtered list of actions. Items can be grouped, have icons, descriptions,\n * and visual shortcut hints.\n *\n * Drop one at the root of the app, pass it the list of commands, and bind\n * a global hotkey (default `'mod+k'`). Use `[(open)]` for controlled\n * visibility, or let it manage itself.\n *\n * @example\n * ```html\n * <wr-command-palette [items]=\"commands\" trigger=\"mod+k\" (picked)=\"onPicked($event)\" />\n * ```\n *\n * @see https://ngwr.dev/components/command-palette\n */\n@Component({\n selector: 'wr-command-palette',\n templateUrl: './command-palette.html',\n encapsulation: ViewEncapsulation.None,\n imports: [WrIcon],\n})\nexport class WrCommandPalette {\n /** Items shown in the palette. */\n readonly items = input<readonly WrCommandItem[]>([]);\n\n /** Controlled open state (two-way bindable). @default false */\n readonly open = model(false);\n\n /** Global hotkey that opens the palette. `null` disables auto-binding. @default 'mod+k' */\n readonly trigger = input<WrHotkeySpec | null>('mod+k');\n\n /** Search input placeholder. Falls back to `commandPalette.placeholder`. */\n readonly placeholder = input<string | null>(null);\n\n /** Text shown when no items match. Falls back to `commandPalette.noResults`. */\n readonly emptyText = input<string | null>(null);\n\n protected readonly resolvedPlaceholder = useI18nText(\n this.placeholder,\n 'commandPalette.placeholder',\n 'Type a command or search…'\n );\n protected readonly resolvedEmpty = useI18nText(this.emptyText, 'commandPalette.noResults', 'No results');\n\n /** Auto-close on `(picked)`. Set false to keep open. @default true */\n readonly closeOnPick = input(true, { transform: coerceBooleanProperty });\n\n /**\n * Present the palette full-screen on small viewports instead of a centred\n * modal. `undefined` follows the app-wide `provideWrResponsiveOverlays()`\n * setting; `true`/`false` overrides it. The palette docks to the top (it\n * auto-focuses its input, so the on-screen keyboard stays clear).\n * @default undefined\n */\n readonly responsive = input<boolean | undefined, BooleanInput>(undefined, {\n transform: (v: BooleanInput): boolean | undefined => (v == null ? undefined : coerceBooleanProperty(v)),\n });\n\n /** Fires when the user commits an item (Enter / click). */\n readonly picked = output<WrCommandItem>();\n\n protected readonly query = signal('');\n protected readonly activeIndex = signal(0);\n\n /** Whether the current opening is presented full-screen. Decided on open. */\n protected readonly presentAsSheet = signal(false);\n protected readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('input');\n protected readonly panelEl = viewChild<ElementRef<HTMLElement>>('panel');\n\n /** Listbox id (referenced by the input's `aria-controls`). */\n protected readonly listboxId = `wr-command-palette-listbox-${++listboxUid}`;\n\n /** @internal Build a stable option id for a given flat index. */\n protected optionId(i: number): string {\n return `${this.listboxId}-opt-${i}`;\n }\n\n /** Id of the active option for `aria-activedescendant`. */\n protected readonly activeOptionId = computed<string | null>(() => {\n const i = this.activeIndex();\n return i >= 0 && i < this.filtered().length ? this.optionId(i) : null;\n });\n\n private readonly hotkeys = inject(WrHotkey);\n private readonly responsiveConfig = inject(WR_RESPONSIVE_OVERLAYS);\n private readonly destroyRef = inject(DestroyRef);\n private readonly focusTrapFactory = inject(ConfigurableFocusTrapFactory);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private bindingHandle: WrHotkeyHandle | null = null;\n private focusTrap: ConfigurableFocusTrap | null = null;\n private previouslyFocused: HTMLElement | null = null;\n\n /** Flat filtered list — what keyboard navigation walks. */\n protected readonly filtered = computed<readonly WrCommandItem[]>(() =>\n this.items().filter(item => matches(item, this.query()))\n );\n\n /** Grouped view — what the template renders. */\n protected readonly buckets = computed<readonly Bucket[]>(() => bucketize(this.filtered()));\n\n constructor() {\n // Bind / re-bind the global trigger whenever the spec changes.\n effect(() => {\n this.bindingHandle?.unbind();\n const spec = this.trigger();\n if (!spec) return;\n this.bindingHandle = this.hotkeys.bind(spec, () => this.open.update(v => !v), { allowInInput: true });\n });\n\n // Reset query + active index whenever we open; focus the input.\n effect(() => {\n if (!this.open()) return;\n this.query.set('');\n this.activeIndex.set(0);\n this.presentAsSheet.set(wrPresentAsSheet(this.responsive(), this.responsiveConfig));\n });\n\n // Focus trap + restore.\n effect(() => {\n if (!this.isBrowser) return;\n if (this.open()) {\n const active = document.activeElement;\n this.previouslyFocused = active instanceof HTMLElement ? active : null;\n queueMicrotask(() => {\n const host = this.panelEl()?.nativeElement;\n if (!host) return;\n this.focusTrap?.destroy();\n this.focusTrap = this.focusTrapFactory.create(host);\n void this.focusTrap.focusInitialElementWhenReady();\n });\n } else {\n this.focusTrap?.destroy();\n this.focusTrap = null;\n const restore = this.previouslyFocused;\n this.previouslyFocused = null;\n if (restore && typeof restore.focus === 'function') restore.focus();\n }\n });\n\n afterNextRender(() => {\n if (this.open()) this.inputEl()?.nativeElement.focus();\n });\n\n // Auto-focus the input when opened.\n effect(() => {\n if (!this.open()) return;\n queueMicrotask(() => this.inputEl()?.nativeElement.focus());\n });\n\n // Clamp the active index when the filtered list shrinks.\n effect(() => {\n const max = Math.max(0, this.filtered().length - 1);\n if (this.activeIndex() > max) this.activeIndex.set(max);\n });\n\n this.destroyRef.onDestroy(() => this.bindingHandle?.unbind());\n }\n\n // Template handlers\n\n protected onQueryInput(event: Event): void {\n this.query.set((event.target as HTMLInputElement).value);\n this.activeIndex.set(0);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const list = this.filtered();\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n if (list.length > 0) this.activeIndex.set((this.activeIndex() + 1) % list.length);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (list.length > 0) this.activeIndex.set((this.activeIndex() - 1 + list.length) % list.length);\n break;\n case 'Home':\n event.preventDefault();\n this.activeIndex.set(0);\n break;\n case 'End':\n event.preventDefault();\n this.activeIndex.set(Math.max(0, list.length - 1));\n break;\n case 'Enter': {\n event.preventDefault();\n const item = list[this.activeIndex()];\n if (item) this.commit(item);\n break;\n }\n case 'Escape':\n event.preventDefault();\n this.close();\n break;\n default:\n break;\n }\n }\n\n protected onBackdropClick(): void {\n this.close();\n }\n\n protected onItemClick(item: WrCommandItem, event: MouseEvent): void {\n event.preventDefault();\n this.commit(item);\n }\n\n protected onItemHover(item: WrCommandItem): void {\n const i = this.filtered().indexOf(item);\n if (i >= 0) this.activeIndex.set(i);\n }\n\n /** Flat index of an item within the filtered list — for highlight checks. */\n protected indexOf(item: WrCommandItem): number {\n return this.filtered().indexOf(item);\n }\n\n // Public API\n\n /** Open the palette. */\n show(): void {\n this.open.set(true);\n }\n\n /** Close the palette. */\n close(): void {\n this.open.set(false);\n }\n\n // Internals\n\n private commit(item: WrCommandItem): void {\n item.action?.();\n this.picked.emit(item);\n if (this.closeOnPick()) this.close();\n }\n}\n","@if (open()) {\n <div\n class=\"wr-command-palette\"\n [class.wr-command-palette--sheet]=\"presentAsSheet()\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Command palette\"\n >\n <!-- Backdrop captures clicks to close. Not focusable — keyboard users use\n Esc on the panel below. -->\n\n <div class=\"wr-command-palette__backdrop\" aria-hidden=\"true\" (click)=\"onBackdropClick()\"></div>\n\n <!-- Keydown is delegated from the search input; tabindex enables Esc when\n the input is unfocused. -->\n <div #panel class=\"wr-command-palette__panel\" tabindex=\"-1\" (keydown)=\"onKeydown($event)\">\n <div class=\"wr-command-palette__search\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n <path d=\"M11 11 L14 14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n <input\n #input\n type=\"text\"\n role=\"combobox\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-expanded]=\"true\"\n [attr.aria-activedescendant]=\"activeOptionId() || null\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"query()\"\n (input)=\"onQueryInput($event)\"\n />\n <kbd class=\"wr-command-palette__hint\">esc</kbd>\n </div>\n\n <div class=\"wr-command-palette__body\" role=\"listbox\" [attr.id]=\"listboxId\">\n @if (filtered().length === 0) {\n <div class=\"wr-command-palette__empty\">{{ resolvedEmpty() }}</div>\n } @else {\n @for (bucket of buckets(); track bucket.title) {\n <div class=\"wr-command-palette__group\">\n @if (bucket.title) {\n <div class=\"wr-command-palette__group-title\">{{ bucket.title }}</div>\n }\n @for (item of bucket.items; track item.id) {\n <div\n class=\"wr-command-palette__option\"\n role=\"option\"\n [attr.id]=\"optionId(indexOf(item))\"\n [class.wr-command-palette__option--active]=\"indexOf(item) === activeIndex()\"\n [attr.aria-selected]=\"indexOf(item) === activeIndex()\"\n (mouseenter)=\"onItemHover(item)\"\n (mousedown)=\"onItemClick(item, $event)\"\n >\n @if (item.icon) {\n <wr-icon class=\"wr-command-palette__option-icon\" [name]=\"item.icon\" size=\"16\" />\n } @else {\n <span class=\"wr-command-palette__option-icon\" aria-hidden=\"true\"></span>\n }\n <div class=\"wr-command-palette__option-body\">\n <div class=\"wr-command-palette__option-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"wr-command-palette__option-description\">{{ item.description }}</div>\n }\n </div>\n @if (item.shortcut) {\n <kbd class=\"wr-command-palette__option-shortcut\">{{ item.shortcut }}</kbd>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -329,9 +329,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
329
329
|
*/
|
|
330
330
|
/**
|
|
331
331
|
* Attach to any element to show a `<wr-context-menu>` at the pointer
|
|
332
|
-
* position when the user right-clicks
|
|
333
|
-
*
|
|
334
|
-
*
|
|
332
|
+
* position when the user right-clicks, long-presses on touch, or otherwise
|
|
333
|
+
* sends a `contextmenu` event (Shift+F10, etc.). The native browser menu is
|
|
334
|
+
* suppressed for the host element.
|
|
335
335
|
*
|
|
336
336
|
* @example
|
|
337
337
|
* ```html
|
|
@@ -388,13 +388,30 @@ class WrContextMenu {
|
|
|
388
388
|
* on a deliberate hover-out.
|
|
389
389
|
*/
|
|
390
390
|
static LEAVE_DELAY = 240;
|
|
391
|
+
/** Hold duration (ms) before a stationary touch press opens the menu. */
|
|
392
|
+
static LONG_PRESS_MS = 500;
|
|
393
|
+
/** Movement (px) that reclassifies a press as a scroll and cancels it. */
|
|
394
|
+
static LONG_PRESS_MOVE_TOLERANCE = 10;
|
|
395
|
+
longPressTimer = null;
|
|
396
|
+
touchStartX = 0;
|
|
397
|
+
touchStartY = 0;
|
|
398
|
+
longPressFired = false;
|
|
399
|
+
suppressContextMenuUntil = 0;
|
|
391
400
|
constructor() {
|
|
392
|
-
this.destroyRef.onDestroy(() =>
|
|
401
|
+
this.destroyRef.onDestroy(() => {
|
|
402
|
+
this.clearLongPress();
|
|
403
|
+
this.closeOverlay();
|
|
404
|
+
});
|
|
393
405
|
}
|
|
394
406
|
/** @internal Right-click handler — opens at the pointer (or re-positions if already open). */
|
|
395
407
|
onContextMenu(event) {
|
|
396
408
|
event.preventDefault();
|
|
397
409
|
event.stopPropagation();
|
|
410
|
+
// A touch long-press just opened the menu; ignore the synthetic
|
|
411
|
+
// `contextmenu` some platforms (Android) fire at the same threshold so we
|
|
412
|
+
// don't close-and-reopen with a flicker.
|
|
413
|
+
if (performance.now() < this.suppressContextMenuUntil)
|
|
414
|
+
return;
|
|
398
415
|
// Re-open at the new position even if it was already open.
|
|
399
416
|
// Use page coords (document-relative) so the menu anchors to the
|
|
400
417
|
// zone it was opened over — scrolling the page carries the menu
|
|
@@ -402,6 +419,57 @@ class WrContextMenu {
|
|
|
402
419
|
this.closeOverlay();
|
|
403
420
|
this.openOverlay(event.pageX, event.pageY);
|
|
404
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* @internal Touch long-press → open the menu. Native `contextmenu` is
|
|
424
|
+
* unreliable on touch (iOS doesn't fire it, Android's timing varies), so we
|
|
425
|
+
* detect the press ourselves: a stationary hold for `LONG_PRESS_MS` opens
|
|
426
|
+
* the menu at the touch point; moving the finger reclassifies it as a
|
|
427
|
+
* scroll and cancels.
|
|
428
|
+
*/
|
|
429
|
+
onTouchStart(event) {
|
|
430
|
+
const touch = event.touches[0];
|
|
431
|
+
if (!touch)
|
|
432
|
+
return;
|
|
433
|
+
this.touchStartX = touch.pageX;
|
|
434
|
+
this.touchStartY = touch.pageY;
|
|
435
|
+
this.longPressFired = false;
|
|
436
|
+
this.clearLongPress();
|
|
437
|
+
this.longPressTimer = setTimeout(() => {
|
|
438
|
+
this.longPressTimer = null;
|
|
439
|
+
this.longPressFired = true;
|
|
440
|
+
this.suppressContextMenuUntil = performance.now() + 700;
|
|
441
|
+
this.closeOverlay();
|
|
442
|
+
this.openOverlay(this.touchStartX, this.touchStartY);
|
|
443
|
+
}, WrContextMenu.LONG_PRESS_MS);
|
|
444
|
+
}
|
|
445
|
+
/** @internal Cancel a pending long-press once the finger travels (a scroll). */
|
|
446
|
+
onTouchMove(event) {
|
|
447
|
+
if (this.longPressTimer === null)
|
|
448
|
+
return;
|
|
449
|
+
const touch = event.touches[0];
|
|
450
|
+
if (!touch)
|
|
451
|
+
return;
|
|
452
|
+
const moved = Math.abs(touch.pageX - this.touchStartX) > WrContextMenu.LONG_PRESS_MOVE_TOLERANCE ||
|
|
453
|
+
Math.abs(touch.pageY - this.touchStartY) > WrContextMenu.LONG_PRESS_MOVE_TOLERANCE;
|
|
454
|
+
if (moved)
|
|
455
|
+
this.clearLongPress();
|
|
456
|
+
}
|
|
457
|
+
/** @internal Release — drop a pending press; swallow the synthetic click a fired press would emit. */
|
|
458
|
+
onTouchEnd(event) {
|
|
459
|
+
this.clearLongPress();
|
|
460
|
+
if (this.longPressFired) {
|
|
461
|
+
this.longPressFired = false;
|
|
462
|
+
// Stop the browser turning this long-press into a synthetic click that
|
|
463
|
+
// would land outside the freshly-opened menu and dismiss it.
|
|
464
|
+
event.preventDefault();
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
clearLongPress() {
|
|
468
|
+
if (this.longPressTimer !== null) {
|
|
469
|
+
clearTimeout(this.longPressTimer);
|
|
470
|
+
this.longPressTimer = null;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
405
473
|
/** Close the menu. */
|
|
406
474
|
close() {
|
|
407
475
|
this.closeOverlay();
|
|
@@ -557,7 +625,7 @@ class WrContextMenu {
|
|
|
557
625
|
}, WrContextMenu.LEAVE_DELAY);
|
|
558
626
|
}
|
|
559
627
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: WrContextMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
560
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: WrContextMenu, isStandalone: true, selector: "[wrContextMenu]", inputs: { menu: { classPropertyName: "menu", publicName: "wrContextMenu", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "contextmenu": "onContextMenu($event)" } }, ngImport: i0 });
|
|
628
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.2", type: WrContextMenu, isStandalone: true, selector: "[wrContextMenu]", inputs: { menu: { classPropertyName: "menu", publicName: "wrContextMenu", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "contextmenu": "onContextMenu($event)", "touchstart": "onTouchStart($event)", "touchmove": "onTouchMove($event)", "touchend": "onTouchEnd($event)", "touchcancel": "onTouchEnd($event)" } }, ngImport: i0 });
|
|
561
629
|
}
|
|
562
630
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: WrContextMenu, decorators: [{
|
|
563
631
|
type: Directive,
|
|
@@ -565,6 +633,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
565
633
|
selector: '[wrContextMenu]',
|
|
566
634
|
host: {
|
|
567
635
|
'(contextmenu)': 'onContextMenu($event)',
|
|
636
|
+
'(touchstart)': 'onTouchStart($event)',
|
|
637
|
+
'(touchmove)': 'onTouchMove($event)',
|
|
638
|
+
'(touchend)': 'onTouchEnd($event)',
|
|
639
|
+
'(touchcancel)': 'onTouchEnd($event)',
|
|
568
640
|
},
|
|
569
641
|
}]
|
|
570
642
|
}], ctorParameters: () => [], propDecorators: { menu: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrContextMenu", required: true }] }] } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-context-menu.mjs","sources":["../../../projects/lib/context-menu/context-menu-item.ts","../../../projects/lib/context-menu/context-menu-item.html","../../../projects/lib/context-menu/context-menu.ts","../../../projects/lib/context-menu/context-menu-panel.ts","../../../projects/lib/context-menu/context-menu-divider.ts","../../../projects/lib/context-menu/ngwr-context-menu.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { type ConnectedPosition, type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n ViewContainerRef,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { WR_OVERLAY } from 'ngwr/overlay';\n\nimport { WrContextMenu } from './context-menu';\nimport type { WrContextMenuPanel } from './context-menu-panel';\n\n/** Hover delay (ms) before a submenu opens. */\nconst SUBMENU_OPEN_DELAY = 120;\n/** Grace window (ms) before a submenu closes when the cursor leaves it. */\nconst SUBMENU_CLOSE_DELAY = 240;\n/** Animation duration of the submenu — mirrors the root menu CSS. */\nconst SUBMENU_TRANSITION_MS = 220;\n\n/**\n * Single row inside a `<wr-context-menu>`. Mirrors `<wr-dropdown-item>` —\n * rendered as a menu item with an optional leading icon and an optional\n * nested `[submenu]` that opens to the right on hover.\n *\n * @example\n * ```html\n * <wr-context-menu #menu>\n * <wr-context-menu-item icon=\"copy\" (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item icon=\"more\" [submenu]=\"extras\">More…</wr-context-menu-item>\n * </wr-context-menu>\n *\n * <wr-context-menu #extras>\n * <wr-context-menu-item (click)=\"duplicate()\">Duplicate</wr-context-menu-item>\n * <wr-context-menu-item (click)=\"archive()\">Archive</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n */\n@Component({\n selector: 'wr-context-menu-item',\n templateUrl: './context-menu-item.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n role: 'menuitem',\n '[class]': 'classes()',\n '[attr.tabindex]': '-1',\n '[attr.aria-disabled]': 'disabled() ? true : null',\n '[attr.aria-haspopup]': 'submenu() ? \"menu\" : null',\n '[attr.aria-expanded]': 'submenu() ? (submenuOpen ? \"true\" : \"false\") : null',\n '(mouseenter)': 'onMouseEnter()',\n '(mouseleave)': 'onMouseLeave($event)',\n '(keydown.enter)': 'activate($event)',\n '(keydown.space)': 'activate($event)',\n '(keydown.arrowRight)': 'onArrowRight($event)',\n '(keydown.arrowLeft)': 'onArrowLeft($event)',\n },\n imports: [WrIcon],\n})\nexport class WrContextMenuItem {\n /** Optional leading icon name. @default null */\n readonly icon = input<WrIconName | null>(null);\n\n /** Disable interaction (suppresses pointer + keyboard). @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Optional nested `<wr-context-menu>`. When set, hovering the item\n * (or pressing →) opens it to the right with a chevron indicator.\n */\n readonly submenu = input<WrContextMenuPanel | null>(null);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-context-menu-item'];\n if (this.disabled()) parts.push('wr-context-menu-item--disabled');\n if (this.submenu()) parts.push('wr-context-menu-item--has-submenu');\n return parts.join(' ');\n });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n\n private submenuRef: OverlayRef | null = null;\n private openTimer: ReturnType<typeof setTimeout> | null = null;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n protected submenuOpen = false;\n\n /**\n * Global registry of open submenus keyed by the host element of the\n * item that owns them. Used to cascade-close descendants when a\n * parent submenu is disposed — Angular's onDestroy on detached\n * portals doesn't always tear down the deepest grand-children's\n * overlays in the right order, leaving orphaned floating panes.\n */\n private static readonly openSubmenus = new Map<HTMLElement, WrContextMenuItem>();\n\n /**\n * Dispose every open submenu pane on the page. Called by the root\n * `WrContextMenu` when its own overlay closes — destroyRef cascade\n * isn't reliable across separate overlay panes (each pane lives in\n * the CDK overlay container, not inside the parent pane's view).\n */\n static disposeAll(immediate: boolean): void {\n for (const [, owner] of [...WrContextMenuItem.openSubmenus]) {\n owner.disposeSubmenu(immediate);\n }\n }\n\n constructor() {\n this.destroyRef.onDestroy(() => this.disposeSubmenu(true));\n }\n\n /** @internal Keyboard activation — Enter / Space. */\n protected activate(event: Event): void {\n if (this.disabled()) return;\n if (this.submenu()) {\n event.preventDefault();\n this.scheduleOpen(0);\n return;\n }\n event.preventDefault();\n this.host.nativeElement.click();\n }\n\n /** @internal Right-arrow opens the submenu. */\n protected onArrowRight(event: Event): void {\n if (this.disabled() || !this.submenu()) return;\n event.preventDefault();\n this.scheduleOpen(0);\n }\n\n /** @internal Left-arrow closes the submenu (if open). */\n protected onArrowLeft(event: Event): void {\n if (!this.submenu() || !this.submenuOpen) return;\n event.preventDefault();\n this.scheduleClose(0);\n }\n\n /** @internal Hover schedules a submenu open after a small delay. */\n protected onMouseEnter(): void {\n if (this.disabled() || !this.submenu()) return;\n this.cancelClose();\n this.scheduleOpen(SUBMENU_OPEN_DELAY);\n }\n\n /** @internal Hover-out schedules a close with a grace window. */\n protected onMouseLeave(event: MouseEvent): void {\n if (!this.submenu()) return;\n this.cancelOpen();\n // Only skip the close when the cursor is moving into MY OWN submenu\n // (the user is drilling further down). Moving elsewhere — sibling\n // item, ancestor menu, or completely off the chain — should close\n // this item's submenu and let the cascade-on-dispose tear down any\n // descendants.\n if (this.relatedTargetIsInsideOwnSubmenu(event)) return;\n this.scheduleClose(SUBMENU_CLOSE_DELAY);\n }\n\n // Submenu lifecycle\n\n private scheduleOpen(delay: number): void {\n if (this.submenuRef) return;\n this.cancelOpen();\n if (delay === 0) {\n this.openSubmenu();\n return;\n }\n this.openTimer = setTimeout(() => {\n this.openTimer = null;\n this.openSubmenu();\n }, delay);\n }\n\n private scheduleClose(delay: number): void {\n this.cancelClose();\n if (delay === 0) {\n this.disposeSubmenu(false);\n return;\n }\n this.closeTimer = setTimeout(() => {\n this.closeTimer = null;\n this.disposeSubmenu(false);\n }, delay);\n }\n\n private cancelOpen(): void {\n if (this.openTimer !== null) {\n clearTimeout(this.openTimer);\n this.openTimer = null;\n }\n }\n\n private cancelClose(): void {\n if (this.closeTimer !== null) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private openSubmenu(): void {\n const panel = this.submenu();\n if (!panel || this.submenuRef) return;\n\n // Position to the right of the item, vertically aligned with the\n // item's top. Falls back to opening to the LEFT if there's no room.\n const positions: ConnectedPosition[] = [\n { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top', offsetX: 4 },\n { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top', offsetX: -4 },\n ];\n\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(this.host)\n .withPositions(positions)\n .withPush(true);\n\n this.submenuRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.scrollStrategies.reposition(),\n panelClass: ['wr-context-menu-overlay', 'wr-context-menu-overlay--submenu'],\n });\n\n const portal = new TemplatePortal(panel.contentTpl(), this.vcr);\n this.submenuRef.attach(portal);\n\n // Mirror the open animation pattern from the root menu directive.\n const pane = this.submenuRef.overlayElement;\n requestAnimationFrame(() => pane.classList.add('wr-context-menu-overlay--open'));\n\n // Track mouse entering / leaving the submenu so we don't auto-close\n // when the cursor crosses the gap between item and submenu pane.\n pane.addEventListener('mouseenter', this.onSubmenuEnter);\n pane.addEventListener('mouseleave', this.onSubmenuLeave);\n\n this.submenuOpen = true;\n WrContextMenuItem.openSubmenus.set(this.host.nativeElement, this);\n }\n\n /** Bound handlers (= preserves identity for removeEventListener). */\n private readonly onSubmenuEnter = (): void => {\n this.cancelClose();\n // Cursor is inside our pane — keep the whole chain (root + every\n // ancestor submenu) alive.\n WrContextMenu.keepChainAlive();\n };\n private readonly onSubmenuLeave = (event: MouseEvent): void => {\n // Only stay open if the cursor is moving into a DESCENDANT submenu\n // of ours (an item inside our pane opening its own submenu). Moving\n // back up to an ancestor menu, sideways to a sibling, or completely\n // off-chain should dismiss this submenu (cascade-on-dispose then\n // tears down any deeper levels we own).\n if (this.relatedTargetIsInsideDescendantSubmenu(event)) return;\n this.scheduleClose(SUBMENU_CLOSE_DELAY);\n // If the cursor left ALL menu panes (root + every submenu), tear\n // down the whole chain. Otherwise just close this pane and let the\n // user continue navigating ancestors.\n if (!this.relatedTargetIsInsideAnyMenu(event)) {\n WrContextMenu.scheduleChainClose();\n }\n };\n\n private relatedTargetIsInsideAnyMenu(event: MouseEvent): boolean {\n const related = event.relatedTarget;\n if (!(related instanceof Element)) return false;\n return !!related.closest('.wr-context-menu-overlay');\n }\n\n /**\n * `true` when the cursor moved from this item directly into the pane\n * of its own (just-opening) submenu — drilling down. Sibling items\n * and ancestor menus do NOT count.\n */\n private relatedTargetIsInsideOwnSubmenu(event: MouseEvent): boolean {\n const related = event.relatedTarget;\n if (!(related instanceof Element) || !this.submenuRef) return false;\n return this.submenuRef.overlayElement.contains(related);\n }\n\n /**\n * `true` when the cursor moved from our submenu pane into another\n * submenu pane whose owner-item lives INSIDE ours — the user is\n * drilling further down the chain (e.g., from the Share submenu into\n * the Export-as submenu). Moving back up the chain returns false so\n * we close.\n */\n private relatedTargetIsInsideDescendantSubmenu(event: MouseEvent): boolean {\n const related = event.relatedTarget;\n if (!(related instanceof Element) || !this.submenuRef) return false;\n const targetPane = related.closest('.wr-context-menu-overlay');\n if (!targetPane) return false;\n const myPane = this.submenuRef.overlayElement;\n if (targetPane === myPane) return true;\n // Find the owner-item of the pane the cursor is heading into. If\n // that owner-item is inside our own pane, the destination is a\n // descendant submenu.\n for (const [ownerEl, owner] of WrContextMenuItem.openSubmenus) {\n if (owner.submenuRef?.overlayElement === targetPane) {\n return myPane.contains(ownerEl);\n }\n }\n return false;\n }\n\n private disposeSubmenu(immediate: boolean): void {\n this.cancelOpen();\n this.cancelClose();\n const ref = this.submenuRef;\n if (!ref) return;\n this.submenuRef = null;\n this.submenuOpen = false;\n WrContextMenuItem.openSubmenus.delete(this.host.nativeElement);\n\n const pane = ref.overlayElement;\n pane.removeEventListener('mouseenter', this.onSubmenuEnter);\n pane.removeEventListener('mouseleave', this.onSubmenuLeave);\n\n // Cascade-close any descendant submenus whose owner-item lives inside\n // the pane we're about to dispose. Without this, when a parent submenu\n // closes (via hover-out grace timer), a grandchild submenu whose owner\n // is rendered inside the parent's portal is orphaned — its OverlayRef\n // stays alive in the DOM with no parent to reach it from.\n for (const [ownerEl, owner] of WrContextMenuItem.openSubmenus) {\n if (pane.contains(ownerEl)) owner.disposeSubmenu(immediate);\n }\n\n if (immediate) {\n ref.dispose();\n return;\n }\n pane.classList.remove('wr-context-menu-overlay--open');\n setTimeout(() => ref.dispose(), SUBMENU_TRANSITION_MS);\n }\n}\n","@if (icon(); as name) {\n <wr-icon class=\"wr-context-menu-item__icon\" [name]=\"name\" size=\"14\" />\n}\n<span class=\"wr-context-menu-item__label\"><ng-content /></span>\n@if (submenu()) {\n <svg\n class=\"wr-icon__svg wr-context-menu-item__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { DestroyRef, Directive, ElementRef, ViewContainerRef, inject, input } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { WR_OVERLAY } from 'ngwr/overlay';\n\nimport { WrContextMenuItem } from './context-menu-item';\nimport type { WrContextMenuPanel } from './context-menu-panel';\n\n/**\n * Attach to any element to show a `<wr-context-menu>` at the pointer\n * position when the user right-clicks (or sends a `contextmenu` event by\n * any means — long-press on touch, Shift+F10, etc.). The native browser\n * menu is suppressed for the host element.\n *\n * @example\n * ```html\n * <div [wrContextMenu]=\"menu\">Right-click me</div>\n * <wr-context-menu #menu>\n * <wr-context-menu-item (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item (click)=\"remove()\">Delete</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n *\n * @see https://ngwr.dev/components/context-menu\n */\n@Directive({\n selector: '[wrContextMenu]',\n host: {\n '(contextmenu)': 'onContextMenu($event)',\n },\n})\nexport class WrContextMenu {\n /** Menu to open. Pass a `<wr-context-menu>` template reference. */\n readonly menu = input.required<WrContextMenuPanel>({ alias: 'wrContextMenu' });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n\n private overlayRef: OverlayRef | null = null;\n private closingTimer: ReturnType<typeof setTimeout> | null = null;\n private leaveTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Single open root menu at a time. Submenu items use this to signal\n * chain-level hover state: when the cursor enters ANY pane in the\n * chain (root or submenu) `keepChainAlive()` cancels the close timer;\n * when the cursor leaves ALL panes `scheduleChainClose()` starts it.\n * The whole chain (root → submenus) tears down through the root's\n * close (submenus react to their owner-item destroyRef + the static\n * registry in `WrContextMenuItem`).\n */\n private static activeRoot: WrContextMenu | null = null;\n\n /** Called from a submenu pane's mouseenter — keep the whole chain alive. */\n static keepChainAlive(): void {\n WrContextMenu.activeRoot?.cancelLeaveTimer();\n }\n\n /** Called from a submenu pane's mouseleave when the cursor left ALL menus. */\n static scheduleChainClose(): void {\n WrContextMenu.activeRoot?.scheduleLeave();\n }\n\n /**\n * Open/close animation duration in ms. Matches the longest SCSS\n * transition on `.wr-context-menu-overlay` (the spring-scale curve).\n * The directive holds the overlay alive for this long during close\n * so the exit animation can play before the pane is removed from\n * the DOM.\n */\n private static readonly TRANSITION_MS = 220;\n /**\n * Grace window after the cursor leaves the root pane. Long enough\n * for the user to dip momentarily into the gap between the root and\n * a submenu (or back from a submenu), short enough to feel snappy\n * on a deliberate hover-out.\n */\n private static readonly LEAVE_DELAY = 240;\n\n constructor() {\n this.destroyRef.onDestroy(() => this.closeOverlay());\n }\n\n /** @internal Right-click handler — opens at the pointer (or re-positions if already open). */\n protected onContextMenu(event: MouseEvent): void {\n event.preventDefault();\n event.stopPropagation();\n // Re-open at the new position even if it was already open.\n // Use page coords (document-relative) so the menu anchors to the\n // zone it was opened over — scrolling the page carries the menu\n // along with the content, matching native + PrimeNG behavior.\n this.closeOverlay();\n this.openOverlay(event.pageX, event.pageY);\n }\n\n /** Close the menu. */\n close(): void {\n this.closeOverlay();\n }\n\n // Overlay\n\n private openOverlay(x: number, y: number): void {\n // GlobalPositionStrategy uses margins, which led to flaky positioning\n // (`position: static` inline overridden by our `!important`, etc.).\n // Use it just to create the overlay, then write the coords directly to\n // the pane element via `top`/`left` so the menu sits exactly where the\n // user clicked and never moves until we close it.\n this.overlayRef = this.overlay.create({\n positionStrategy: this.overlay.position().global(),\n // `noop` so scroll doesn't dismiss the menu. With absolute coords\n // pinned to viewport (`position: fixed` in the panel CSS), the menu\n // visually stays put as the page scrolls underneath.\n scrollStrategy: this.scrollStrategies.noop(),\n panelClass: ['wr-context-menu-overlay'],\n });\n\n const portal = new TemplatePortal(this.menu().contentTpl(), this.vcr);\n this.overlayRef.attach(portal);\n\n // Position model: the pane uses `position: fixed` (panel CSS) but we\n // want the menu to anchor to the DOCUMENT — when the user scrolls,\n // the menu should travel with the content it was opened over (native\n // browser + PrimeNG behavior). Strategy:\n //\n // - Record the page coords (pageX/pageY = document-relative).\n // - Each frame the user scrolls, set top/left to (pageX/Y minus the\n // current scroll offset). At scroll 0 this matches clientX/Y; as\n // scroll grows the menu shifts up/left visually, which is exactly\n // what `position: absolute` inside an un-fixed container would do\n // naturally — we just have to emulate it manually because CDK's\n // overlay container is `position: fixed`.\n const pane = this.overlayRef.overlayElement;\n pane.style.right = 'auto';\n pane.style.bottom = 'auto';\n pane.style.margin = '0';\n\n const sync = (): void => {\n pane.style.top = `${y - window.scrollY}px`;\n pane.style.left = `${x - window.scrollX}px`;\n };\n sync();\n\n // Trigger the open transition on the next frame — adding the class\n // synchronously with attach would skip the initial 0→1 frame and\n // the menu would just appear without animating.\n requestAnimationFrame(() => pane.classList.add('wr-context-menu-overlay--open'));\n\n // Hover-out closes the menu after a grace window, unless the\n // cursor moved INTO a descendant submenu (any other\n // `.wr-context-menu-overlay`). Re-entering the root cancels the\n // scheduled close so the user can dip out and back without losing\n // the menu.\n const onPaneLeave = (event: MouseEvent): void => {\n const related = event.relatedTarget;\n // Moving into ANY other menu pane (a submenu) keeps the chain\n // alive — the submenu's own mouseenter will cancel any pending\n // chain-close. Only schedule when the cursor genuinely left the\n // chain.\n if (related instanceof Element && related.closest('.wr-context-menu-overlay')) return;\n this.scheduleLeave();\n };\n const onPaneEnter = (): void => this.cancelLeaveTimer();\n pane.addEventListener('mouseleave', onPaneLeave);\n pane.addEventListener('mouseenter', onPaneEnter);\n WrContextMenu.activeRoot = this;\n this.overlayRef.detachments().subscribe(() => {\n pane.removeEventListener('mouseleave', onPaneLeave);\n pane.removeEventListener('mouseenter', onPaneEnter);\n });\n // Capture-phase listener on document catches scroll events from ANY\n // ancestor (window, html, body, custom scroll containers), so the\n // menu stays anchored to the click position even inside scrollable\n // layouts.\n document.addEventListener('scroll', sync, { capture: true, passive: true });\n // On resize the page layout reflows — the original pageX/pageY no\n // longer points at whatever the user right-clicked. Dismiss the menu\n // rather than dragging it across a now-stale coordinate (matches\n // PrimeNG / native behavior).\n const onResize = (): void => this.closeOverlay();\n window.addEventListener('resize', onResize, { passive: true });\n this.overlayRef.detachments().subscribe(() => {\n document.removeEventListener('scroll', sync, { capture: true });\n window.removeEventListener('resize', onResize);\n });\n\n // The right-click that opens the menu still has `mouseup` + `auxclick`\n // events pending. CDK's `outsidePointerEvents()` listens to pointerdown\n // / auxclick and would fire on those — closing the menu the instant\n // the user lifts their finger. Two-part guard:\n // 1. Track the open timestamp.\n // 2. Ignore any outside events that arrive within a short window\n // after the open (long enough to cover the original mouseup +\n // auxclick, short enough that a deliberate second click is\n // still respected).\n const openedAt = performance.now();\n const ref = this.overlayRef;\n ref\n .outsidePointerEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n if (performance.now() - openedAt < 200) return;\n this.closeOverlay();\n });\n\n this.overlayRef\n .keydownEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closeOverlay();\n this.host.nativeElement.focus();\n }\n });\n }\n\n private closeOverlay(): void {\n if (!this.overlayRef) return;\n this.cancelLeaveTimer();\n if (WrContextMenu.activeRoot === this) WrContextMenu.activeRoot = null;\n // Submenu panes live in the CDK overlay container, not inside the\n // root pane's view — destroyRef cascade through portal detach\n // doesn't reach them. Close them all explicitly first so they\n // don't float when the root is dismissed (outside-click, Esc, etc).\n WrContextMenuItem.disposeAll(false);\n const ref = this.overlayRef;\n const pane = ref.overlayElement;\n // Detach immediately would skip the exit animation. Remove the open\n // class first so the SCSS transition runs back to the default\n // (faded + scaled-down) state, then dispose after the transition.\n pane.classList.remove('wr-context-menu-overlay--open');\n if (this.closingTimer !== null) clearTimeout(this.closingTimer);\n this.closingTimer = setTimeout(() => {\n ref.dispose();\n this.closingTimer = null;\n }, WrContextMenu.TRANSITION_MS);\n // Mark immediately so a subsequent right-click opens a fresh menu\n // rather than landing on the disposing one.\n this.overlayRef = null;\n }\n\n private cancelLeaveTimer(): void {\n if (this.leaveTimer !== null) {\n clearTimeout(this.leaveTimer);\n this.leaveTimer = null;\n }\n }\n\n private scheduleLeave(): void {\n this.cancelLeaveTimer();\n this.leaveTimer = setTimeout(() => {\n this.leaveTimer = null;\n this.closeOverlay();\n }, WrContextMenu.LEAVE_DELAY);\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, TemplateRef, ViewEncapsulation, viewChild } from '@angular/core';\n\n/**\n * Container for the rows shown when a {@link WrContextMenu} opens.\n * The component itself doesn't render; the directive portals the inner\n * template into an overlay positioned at the pointer.\n *\n * @example\n * ```html\n * <div [wrContextMenu]=\"menu\">Right-click me</div>\n * <wr-context-menu #menu>\n * <wr-context-menu-item icon=\"copy\" (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item icon=\"trash\" (click)=\"remove()\">Delete</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n */\n@Component({\n selector: 'wr-context-menu',\n template: '<ng-template><div class=\"wr-context-menu\" role=\"menu\"><ng-content /></div></ng-template>',\n exportAs: 'wrContextMenu',\n encapsulation: ViewEncapsulation.None,\n host: { style: 'display:none' },\n})\nexport class WrContextMenuPanel {\n /** The internal template the directive portals into the overlay. @internal */\n readonly contentTpl = viewChild.required(TemplateRef);\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation } from '@angular/core';\n\n/**\n * Thin horizontal separator inside a `<wr-context-menu>`. Use it to\n * group related items (e.g., a destructive action below a divider, or\n * a \"More\" section below the primary items).\n *\n * @example\n * ```html\n * <wr-context-menu #menu>\n * <wr-context-menu-item (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item (click)=\"paste()\">Paste</wr-context-menu-item>\n * <wr-context-menu-divider />\n * <wr-context-menu-item (click)=\"remove()\">Delete</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n */\n@Component({\n selector: 'wr-context-menu-divider',\n template: '',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-context-menu-divider',\n role: 'separator',\n 'aria-orientation': 'horizontal',\n },\n})\nexport class WrContextMenuDivider {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-context-menu.mjs","sources":["../../../projects/lib/context-menu/context-menu-item.ts","../../../projects/lib/context-menu/context-menu-item.html","../../../projects/lib/context-menu/context-menu.ts","../../../projects/lib/context-menu/context-menu-panel.ts","../../../projects/lib/context-menu/context-menu-divider.ts","../../../projects/lib/context-menu/ngwr-context-menu.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { type ConnectedPosition, type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n ViewContainerRef,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\nimport { WR_OVERLAY } from 'ngwr/overlay';\n\nimport { WrContextMenu } from './context-menu';\nimport type { WrContextMenuPanel } from './context-menu-panel';\n\n/** Hover delay (ms) before a submenu opens. */\nconst SUBMENU_OPEN_DELAY = 120;\n/** Grace window (ms) before a submenu closes when the cursor leaves it. */\nconst SUBMENU_CLOSE_DELAY = 240;\n/** Animation duration of the submenu — mirrors the root menu CSS. */\nconst SUBMENU_TRANSITION_MS = 220;\n\n/**\n * Single row inside a `<wr-context-menu>`. Mirrors `<wr-dropdown-item>` —\n * rendered as a menu item with an optional leading icon and an optional\n * nested `[submenu]` that opens to the right on hover.\n *\n * @example\n * ```html\n * <wr-context-menu #menu>\n * <wr-context-menu-item icon=\"copy\" (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item icon=\"more\" [submenu]=\"extras\">More…</wr-context-menu-item>\n * </wr-context-menu>\n *\n * <wr-context-menu #extras>\n * <wr-context-menu-item (click)=\"duplicate()\">Duplicate</wr-context-menu-item>\n * <wr-context-menu-item (click)=\"archive()\">Archive</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n */\n@Component({\n selector: 'wr-context-menu-item',\n templateUrl: './context-menu-item.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n role: 'menuitem',\n '[class]': 'classes()',\n '[attr.tabindex]': '-1',\n '[attr.aria-disabled]': 'disabled() ? true : null',\n '[attr.aria-haspopup]': 'submenu() ? \"menu\" : null',\n '[attr.aria-expanded]': 'submenu() ? (submenuOpen ? \"true\" : \"false\") : null',\n '(mouseenter)': 'onMouseEnter()',\n '(mouseleave)': 'onMouseLeave($event)',\n '(keydown.enter)': 'activate($event)',\n '(keydown.space)': 'activate($event)',\n '(keydown.arrowRight)': 'onArrowRight($event)',\n '(keydown.arrowLeft)': 'onArrowLeft($event)',\n },\n imports: [WrIcon],\n})\nexport class WrContextMenuItem {\n /** Optional leading icon name. @default null */\n readonly icon = input<WrIconName | null>(null);\n\n /** Disable interaction (suppresses pointer + keyboard). @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Optional nested `<wr-context-menu>`. When set, hovering the item\n * (or pressing →) opens it to the right with a chevron indicator.\n */\n readonly submenu = input<WrContextMenuPanel | null>(null);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-context-menu-item'];\n if (this.disabled()) parts.push('wr-context-menu-item--disabled');\n if (this.submenu()) parts.push('wr-context-menu-item--has-submenu');\n return parts.join(' ');\n });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n\n private submenuRef: OverlayRef | null = null;\n private openTimer: ReturnType<typeof setTimeout> | null = null;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n protected submenuOpen = false;\n\n /**\n * Global registry of open submenus keyed by the host element of the\n * item that owns them. Used to cascade-close descendants when a\n * parent submenu is disposed — Angular's onDestroy on detached\n * portals doesn't always tear down the deepest grand-children's\n * overlays in the right order, leaving orphaned floating panes.\n */\n private static readonly openSubmenus = new Map<HTMLElement, WrContextMenuItem>();\n\n /**\n * Dispose every open submenu pane on the page. Called by the root\n * `WrContextMenu` when its own overlay closes — destroyRef cascade\n * isn't reliable across separate overlay panes (each pane lives in\n * the CDK overlay container, not inside the parent pane's view).\n */\n static disposeAll(immediate: boolean): void {\n for (const [, owner] of [...WrContextMenuItem.openSubmenus]) {\n owner.disposeSubmenu(immediate);\n }\n }\n\n constructor() {\n this.destroyRef.onDestroy(() => this.disposeSubmenu(true));\n }\n\n /** @internal Keyboard activation — Enter / Space. */\n protected activate(event: Event): void {\n if (this.disabled()) return;\n if (this.submenu()) {\n event.preventDefault();\n this.scheduleOpen(0);\n return;\n }\n event.preventDefault();\n this.host.nativeElement.click();\n }\n\n /** @internal Right-arrow opens the submenu. */\n protected onArrowRight(event: Event): void {\n if (this.disabled() || !this.submenu()) return;\n event.preventDefault();\n this.scheduleOpen(0);\n }\n\n /** @internal Left-arrow closes the submenu (if open). */\n protected onArrowLeft(event: Event): void {\n if (!this.submenu() || !this.submenuOpen) return;\n event.preventDefault();\n this.scheduleClose(0);\n }\n\n /** @internal Hover schedules a submenu open after a small delay. */\n protected onMouseEnter(): void {\n if (this.disabled() || !this.submenu()) return;\n this.cancelClose();\n this.scheduleOpen(SUBMENU_OPEN_DELAY);\n }\n\n /** @internal Hover-out schedules a close with a grace window. */\n protected onMouseLeave(event: MouseEvent): void {\n if (!this.submenu()) return;\n this.cancelOpen();\n // Only skip the close when the cursor is moving into MY OWN submenu\n // (the user is drilling further down). Moving elsewhere — sibling\n // item, ancestor menu, or completely off the chain — should close\n // this item's submenu and let the cascade-on-dispose tear down any\n // descendants.\n if (this.relatedTargetIsInsideOwnSubmenu(event)) return;\n this.scheduleClose(SUBMENU_CLOSE_DELAY);\n }\n\n // Submenu lifecycle\n\n private scheduleOpen(delay: number): void {\n if (this.submenuRef) return;\n this.cancelOpen();\n if (delay === 0) {\n this.openSubmenu();\n return;\n }\n this.openTimer = setTimeout(() => {\n this.openTimer = null;\n this.openSubmenu();\n }, delay);\n }\n\n private scheduleClose(delay: number): void {\n this.cancelClose();\n if (delay === 0) {\n this.disposeSubmenu(false);\n return;\n }\n this.closeTimer = setTimeout(() => {\n this.closeTimer = null;\n this.disposeSubmenu(false);\n }, delay);\n }\n\n private cancelOpen(): void {\n if (this.openTimer !== null) {\n clearTimeout(this.openTimer);\n this.openTimer = null;\n }\n }\n\n private cancelClose(): void {\n if (this.closeTimer !== null) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private openSubmenu(): void {\n const panel = this.submenu();\n if (!panel || this.submenuRef) return;\n\n // Position to the right of the item, vertically aligned with the\n // item's top. Falls back to opening to the LEFT if there's no room.\n const positions: ConnectedPosition[] = [\n { originX: 'end', originY: 'top', overlayX: 'start', overlayY: 'top', offsetX: 4 },\n { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top', offsetX: -4 },\n ];\n\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(this.host)\n .withPositions(positions)\n .withPush(true);\n\n this.submenuRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.scrollStrategies.reposition(),\n panelClass: ['wr-context-menu-overlay', 'wr-context-menu-overlay--submenu'],\n });\n\n const portal = new TemplatePortal(panel.contentTpl(), this.vcr);\n this.submenuRef.attach(portal);\n\n // Mirror the open animation pattern from the root menu directive.\n const pane = this.submenuRef.overlayElement;\n requestAnimationFrame(() => pane.classList.add('wr-context-menu-overlay--open'));\n\n // Track mouse entering / leaving the submenu so we don't auto-close\n // when the cursor crosses the gap between item and submenu pane.\n pane.addEventListener('mouseenter', this.onSubmenuEnter);\n pane.addEventListener('mouseleave', this.onSubmenuLeave);\n\n this.submenuOpen = true;\n WrContextMenuItem.openSubmenus.set(this.host.nativeElement, this);\n }\n\n /** Bound handlers (= preserves identity for removeEventListener). */\n private readonly onSubmenuEnter = (): void => {\n this.cancelClose();\n // Cursor is inside our pane — keep the whole chain (root + every\n // ancestor submenu) alive.\n WrContextMenu.keepChainAlive();\n };\n private readonly onSubmenuLeave = (event: MouseEvent): void => {\n // Only stay open if the cursor is moving into a DESCENDANT submenu\n // of ours (an item inside our pane opening its own submenu). Moving\n // back up to an ancestor menu, sideways to a sibling, or completely\n // off-chain should dismiss this submenu (cascade-on-dispose then\n // tears down any deeper levels we own).\n if (this.relatedTargetIsInsideDescendantSubmenu(event)) return;\n this.scheduleClose(SUBMENU_CLOSE_DELAY);\n // If the cursor left ALL menu panes (root + every submenu), tear\n // down the whole chain. Otherwise just close this pane and let the\n // user continue navigating ancestors.\n if (!this.relatedTargetIsInsideAnyMenu(event)) {\n WrContextMenu.scheduleChainClose();\n }\n };\n\n private relatedTargetIsInsideAnyMenu(event: MouseEvent): boolean {\n const related = event.relatedTarget;\n if (!(related instanceof Element)) return false;\n return !!related.closest('.wr-context-menu-overlay');\n }\n\n /**\n * `true` when the cursor moved from this item directly into the pane\n * of its own (just-opening) submenu — drilling down. Sibling items\n * and ancestor menus do NOT count.\n */\n private relatedTargetIsInsideOwnSubmenu(event: MouseEvent): boolean {\n const related = event.relatedTarget;\n if (!(related instanceof Element) || !this.submenuRef) return false;\n return this.submenuRef.overlayElement.contains(related);\n }\n\n /**\n * `true` when the cursor moved from our submenu pane into another\n * submenu pane whose owner-item lives INSIDE ours — the user is\n * drilling further down the chain (e.g., from the Share submenu into\n * the Export-as submenu). Moving back up the chain returns false so\n * we close.\n */\n private relatedTargetIsInsideDescendantSubmenu(event: MouseEvent): boolean {\n const related = event.relatedTarget;\n if (!(related instanceof Element) || !this.submenuRef) return false;\n const targetPane = related.closest('.wr-context-menu-overlay');\n if (!targetPane) return false;\n const myPane = this.submenuRef.overlayElement;\n if (targetPane === myPane) return true;\n // Find the owner-item of the pane the cursor is heading into. If\n // that owner-item is inside our own pane, the destination is a\n // descendant submenu.\n for (const [ownerEl, owner] of WrContextMenuItem.openSubmenus) {\n if (owner.submenuRef?.overlayElement === targetPane) {\n return myPane.contains(ownerEl);\n }\n }\n return false;\n }\n\n private disposeSubmenu(immediate: boolean): void {\n this.cancelOpen();\n this.cancelClose();\n const ref = this.submenuRef;\n if (!ref) return;\n this.submenuRef = null;\n this.submenuOpen = false;\n WrContextMenuItem.openSubmenus.delete(this.host.nativeElement);\n\n const pane = ref.overlayElement;\n pane.removeEventListener('mouseenter', this.onSubmenuEnter);\n pane.removeEventListener('mouseleave', this.onSubmenuLeave);\n\n // Cascade-close any descendant submenus whose owner-item lives inside\n // the pane we're about to dispose. Without this, when a parent submenu\n // closes (via hover-out grace timer), a grandchild submenu whose owner\n // is rendered inside the parent's portal is orphaned — its OverlayRef\n // stays alive in the DOM with no parent to reach it from.\n for (const [ownerEl, owner] of WrContextMenuItem.openSubmenus) {\n if (pane.contains(ownerEl)) owner.disposeSubmenu(immediate);\n }\n\n if (immediate) {\n ref.dispose();\n return;\n }\n pane.classList.remove('wr-context-menu-overlay--open');\n setTimeout(() => ref.dispose(), SUBMENU_TRANSITION_MS);\n }\n}\n","@if (icon(); as name) {\n <wr-icon class=\"wr-context-menu-item__icon\" [name]=\"name\" size=\"14\" />\n}\n<span class=\"wr-context-menu-item__label\"><ng-content /></span>\n@if (submenu()) {\n <svg\n class=\"wr-icon__svg wr-context-menu-item__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { DestroyRef, Directive, ElementRef, ViewContainerRef, inject, input } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { WR_OVERLAY } from 'ngwr/overlay';\n\nimport { WrContextMenuItem } from './context-menu-item';\nimport type { WrContextMenuPanel } from './context-menu-panel';\n\n/**\n * Attach to any element to show a `<wr-context-menu>` at the pointer\n * position when the user right-clicks, long-presses on touch, or otherwise\n * sends a `contextmenu` event (Shift+F10, etc.). The native browser menu is\n * suppressed for the host element.\n *\n * @example\n * ```html\n * <div [wrContextMenu]=\"menu\">Right-click me</div>\n * <wr-context-menu #menu>\n * <wr-context-menu-item (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item (click)=\"remove()\">Delete</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n *\n * @see https://ngwr.dev/components/context-menu\n */\n@Directive({\n selector: '[wrContextMenu]',\n host: {\n '(contextmenu)': 'onContextMenu($event)',\n '(touchstart)': 'onTouchStart($event)',\n '(touchmove)': 'onTouchMove($event)',\n '(touchend)': 'onTouchEnd($event)',\n '(touchcancel)': 'onTouchEnd($event)',\n },\n})\nexport class WrContextMenu {\n /** Menu to open. Pass a `<wr-context-menu>` template reference. */\n readonly menu = input.required<WrContextMenuPanel>({ alias: 'wrContextMenu' });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n\n private overlayRef: OverlayRef | null = null;\n private closingTimer: ReturnType<typeof setTimeout> | null = null;\n private leaveTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Single open root menu at a time. Submenu items use this to signal\n * chain-level hover state: when the cursor enters ANY pane in the\n * chain (root or submenu) `keepChainAlive()` cancels the close timer;\n * when the cursor leaves ALL panes `scheduleChainClose()` starts it.\n * The whole chain (root → submenus) tears down through the root's\n * close (submenus react to their owner-item destroyRef + the static\n * registry in `WrContextMenuItem`).\n */\n private static activeRoot: WrContextMenu | null = null;\n\n /** Called from a submenu pane's mouseenter — keep the whole chain alive. */\n static keepChainAlive(): void {\n WrContextMenu.activeRoot?.cancelLeaveTimer();\n }\n\n /** Called from a submenu pane's mouseleave when the cursor left ALL menus. */\n static scheduleChainClose(): void {\n WrContextMenu.activeRoot?.scheduleLeave();\n }\n\n /**\n * Open/close animation duration in ms. Matches the longest SCSS\n * transition on `.wr-context-menu-overlay` (the spring-scale curve).\n * The directive holds the overlay alive for this long during close\n * so the exit animation can play before the pane is removed from\n * the DOM.\n */\n private static readonly TRANSITION_MS = 220;\n /**\n * Grace window after the cursor leaves the root pane. Long enough\n * for the user to dip momentarily into the gap between the root and\n * a submenu (or back from a submenu), short enough to feel snappy\n * on a deliberate hover-out.\n */\n private static readonly LEAVE_DELAY = 240;\n\n /** Hold duration (ms) before a stationary touch press opens the menu. */\n private static readonly LONG_PRESS_MS = 500;\n /** Movement (px) that reclassifies a press as a scroll and cancels it. */\n private static readonly LONG_PRESS_MOVE_TOLERANCE = 10;\n\n private longPressTimer: ReturnType<typeof setTimeout> | null = null;\n private touchStartX = 0;\n private touchStartY = 0;\n private longPressFired = false;\n private suppressContextMenuUntil = 0;\n\n constructor() {\n this.destroyRef.onDestroy(() => {\n this.clearLongPress();\n this.closeOverlay();\n });\n }\n\n /** @internal Right-click handler — opens at the pointer (or re-positions if already open). */\n protected onContextMenu(event: MouseEvent): void {\n event.preventDefault();\n event.stopPropagation();\n // A touch long-press just opened the menu; ignore the synthetic\n // `contextmenu` some platforms (Android) fire at the same threshold so we\n // don't close-and-reopen with a flicker.\n if (performance.now() < this.suppressContextMenuUntil) return;\n // Re-open at the new position even if it was already open.\n // Use page coords (document-relative) so the menu anchors to the\n // zone it was opened over — scrolling the page carries the menu\n // along with the content, matching native + PrimeNG behavior.\n this.closeOverlay();\n this.openOverlay(event.pageX, event.pageY);\n }\n\n /**\n * @internal Touch long-press → open the menu. Native `contextmenu` is\n * unreliable on touch (iOS doesn't fire it, Android's timing varies), so we\n * detect the press ourselves: a stationary hold for `LONG_PRESS_MS` opens\n * the menu at the touch point; moving the finger reclassifies it as a\n * scroll and cancels.\n */\n protected onTouchStart(event: TouchEvent): void {\n const touch = event.touches[0];\n if (!touch) return;\n this.touchStartX = touch.pageX;\n this.touchStartY = touch.pageY;\n this.longPressFired = false;\n this.clearLongPress();\n this.longPressTimer = setTimeout(() => {\n this.longPressTimer = null;\n this.longPressFired = true;\n this.suppressContextMenuUntil = performance.now() + 700;\n this.closeOverlay();\n this.openOverlay(this.touchStartX, this.touchStartY);\n }, WrContextMenu.LONG_PRESS_MS);\n }\n\n /** @internal Cancel a pending long-press once the finger travels (a scroll). */\n protected onTouchMove(event: TouchEvent): void {\n if (this.longPressTimer === null) return;\n const touch = event.touches[0];\n if (!touch) return;\n const moved =\n Math.abs(touch.pageX - this.touchStartX) > WrContextMenu.LONG_PRESS_MOVE_TOLERANCE ||\n Math.abs(touch.pageY - this.touchStartY) > WrContextMenu.LONG_PRESS_MOVE_TOLERANCE;\n if (moved) this.clearLongPress();\n }\n\n /** @internal Release — drop a pending press; swallow the synthetic click a fired press would emit. */\n protected onTouchEnd(event: TouchEvent): void {\n this.clearLongPress();\n if (this.longPressFired) {\n this.longPressFired = false;\n // Stop the browser turning this long-press into a synthetic click that\n // would land outside the freshly-opened menu and dismiss it.\n event.preventDefault();\n }\n }\n\n private clearLongPress(): void {\n if (this.longPressTimer !== null) {\n clearTimeout(this.longPressTimer);\n this.longPressTimer = null;\n }\n }\n\n /** Close the menu. */\n close(): void {\n this.closeOverlay();\n }\n\n // Overlay\n\n private openOverlay(x: number, y: number): void {\n // GlobalPositionStrategy uses margins, which led to flaky positioning\n // (`position: static` inline overridden by our `!important`, etc.).\n // Use it just to create the overlay, then write the coords directly to\n // the pane element via `top`/`left` so the menu sits exactly where the\n // user clicked and never moves until we close it.\n this.overlayRef = this.overlay.create({\n positionStrategy: this.overlay.position().global(),\n // `noop` so scroll doesn't dismiss the menu. With absolute coords\n // pinned to viewport (`position: fixed` in the panel CSS), the menu\n // visually stays put as the page scrolls underneath.\n scrollStrategy: this.scrollStrategies.noop(),\n panelClass: ['wr-context-menu-overlay'],\n });\n\n const portal = new TemplatePortal(this.menu().contentTpl(), this.vcr);\n this.overlayRef.attach(portal);\n\n // Position model: the pane uses `position: fixed` (panel CSS) but we\n // want the menu to anchor to the DOCUMENT — when the user scrolls,\n // the menu should travel with the content it was opened over (native\n // browser + PrimeNG behavior). Strategy:\n //\n // - Record the page coords (pageX/pageY = document-relative).\n // - Each frame the user scrolls, set top/left to (pageX/Y minus the\n // current scroll offset). At scroll 0 this matches clientX/Y; as\n // scroll grows the menu shifts up/left visually, which is exactly\n // what `position: absolute` inside an un-fixed container would do\n // naturally — we just have to emulate it manually because CDK's\n // overlay container is `position: fixed`.\n const pane = this.overlayRef.overlayElement;\n pane.style.right = 'auto';\n pane.style.bottom = 'auto';\n pane.style.margin = '0';\n\n const sync = (): void => {\n pane.style.top = `${y - window.scrollY}px`;\n pane.style.left = `${x - window.scrollX}px`;\n };\n sync();\n\n // Trigger the open transition on the next frame — adding the class\n // synchronously with attach would skip the initial 0→1 frame and\n // the menu would just appear without animating.\n requestAnimationFrame(() => pane.classList.add('wr-context-menu-overlay--open'));\n\n // Hover-out closes the menu after a grace window, unless the\n // cursor moved INTO a descendant submenu (any other\n // `.wr-context-menu-overlay`). Re-entering the root cancels the\n // scheduled close so the user can dip out and back without losing\n // the menu.\n const onPaneLeave = (event: MouseEvent): void => {\n const related = event.relatedTarget;\n // Moving into ANY other menu pane (a submenu) keeps the chain\n // alive — the submenu's own mouseenter will cancel any pending\n // chain-close. Only schedule when the cursor genuinely left the\n // chain.\n if (related instanceof Element && related.closest('.wr-context-menu-overlay')) return;\n this.scheduleLeave();\n };\n const onPaneEnter = (): void => this.cancelLeaveTimer();\n pane.addEventListener('mouseleave', onPaneLeave);\n pane.addEventListener('mouseenter', onPaneEnter);\n WrContextMenu.activeRoot = this;\n this.overlayRef.detachments().subscribe(() => {\n pane.removeEventListener('mouseleave', onPaneLeave);\n pane.removeEventListener('mouseenter', onPaneEnter);\n });\n // Capture-phase listener on document catches scroll events from ANY\n // ancestor (window, html, body, custom scroll containers), so the\n // menu stays anchored to the click position even inside scrollable\n // layouts.\n document.addEventListener('scroll', sync, { capture: true, passive: true });\n // On resize the page layout reflows — the original pageX/pageY no\n // longer points at whatever the user right-clicked. Dismiss the menu\n // rather than dragging it across a now-stale coordinate (matches\n // PrimeNG / native behavior).\n const onResize = (): void => this.closeOverlay();\n window.addEventListener('resize', onResize, { passive: true });\n this.overlayRef.detachments().subscribe(() => {\n document.removeEventListener('scroll', sync, { capture: true });\n window.removeEventListener('resize', onResize);\n });\n\n // The right-click that opens the menu still has `mouseup` + `auxclick`\n // events pending. CDK's `outsidePointerEvents()` listens to pointerdown\n // / auxclick and would fire on those — closing the menu the instant\n // the user lifts their finger. Two-part guard:\n // 1. Track the open timestamp.\n // 2. Ignore any outside events that arrive within a short window\n // after the open (long enough to cover the original mouseup +\n // auxclick, short enough that a deliberate second click is\n // still respected).\n const openedAt = performance.now();\n const ref = this.overlayRef;\n ref\n .outsidePointerEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n if (performance.now() - openedAt < 200) return;\n this.closeOverlay();\n });\n\n this.overlayRef\n .keydownEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.closeOverlay();\n this.host.nativeElement.focus();\n }\n });\n }\n\n private closeOverlay(): void {\n if (!this.overlayRef) return;\n this.cancelLeaveTimer();\n if (WrContextMenu.activeRoot === this) WrContextMenu.activeRoot = null;\n // Submenu panes live in the CDK overlay container, not inside the\n // root pane's view — destroyRef cascade through portal detach\n // doesn't reach them. Close them all explicitly first so they\n // don't float when the root is dismissed (outside-click, Esc, etc).\n WrContextMenuItem.disposeAll(false);\n const ref = this.overlayRef;\n const pane = ref.overlayElement;\n // Detach immediately would skip the exit animation. Remove the open\n // class first so the SCSS transition runs back to the default\n // (faded + scaled-down) state, then dispose after the transition.\n pane.classList.remove('wr-context-menu-overlay--open');\n if (this.closingTimer !== null) clearTimeout(this.closingTimer);\n this.closingTimer = setTimeout(() => {\n ref.dispose();\n this.closingTimer = null;\n }, WrContextMenu.TRANSITION_MS);\n // Mark immediately so a subsequent right-click opens a fresh menu\n // rather than landing on the disposing one.\n this.overlayRef = null;\n }\n\n private cancelLeaveTimer(): void {\n if (this.leaveTimer !== null) {\n clearTimeout(this.leaveTimer);\n this.leaveTimer = null;\n }\n }\n\n private scheduleLeave(): void {\n this.cancelLeaveTimer();\n this.leaveTimer = setTimeout(() => {\n this.leaveTimer = null;\n this.closeOverlay();\n }, WrContextMenu.LEAVE_DELAY);\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, TemplateRef, ViewEncapsulation, viewChild } from '@angular/core';\n\n/**\n * Container for the rows shown when a {@link WrContextMenu} opens.\n * The component itself doesn't render; the directive portals the inner\n * template into an overlay positioned at the pointer.\n *\n * @example\n * ```html\n * <div [wrContextMenu]=\"menu\">Right-click me</div>\n * <wr-context-menu #menu>\n * <wr-context-menu-item icon=\"copy\" (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item icon=\"trash\" (click)=\"remove()\">Delete</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n */\n@Component({\n selector: 'wr-context-menu',\n template: '<ng-template><div class=\"wr-context-menu\" role=\"menu\"><ng-content /></div></ng-template>',\n exportAs: 'wrContextMenu',\n encapsulation: ViewEncapsulation.None,\n host: { style: 'display:none' },\n})\nexport class WrContextMenuPanel {\n /** The internal template the directive portals into the overlay. @internal */\n readonly contentTpl = viewChild.required(TemplateRef);\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation } from '@angular/core';\n\n/**\n * Thin horizontal separator inside a `<wr-context-menu>`. Use it to\n * group related items (e.g., a destructive action below a divider, or\n * a \"More\" section below the primary items).\n *\n * @example\n * ```html\n * <wr-context-menu #menu>\n * <wr-context-menu-item (click)=\"copy()\">Copy</wr-context-menu-item>\n * <wr-context-menu-item (click)=\"paste()\">Paste</wr-context-menu-item>\n * <wr-context-menu-divider />\n * <wr-context-menu-item (click)=\"remove()\">Delete</wr-context-menu-item>\n * </wr-context-menu>\n * ```\n */\n@Component({\n selector: 'wr-context-menu-divider',\n template: '',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-context-menu-divider',\n role: 'separator',\n 'aria-orientation': 'horizontal',\n },\n})\nexport class WrContextMenuDivider {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -24,7 +24,7 @@ const WR_DENSITY_CONFIG = new InjectionToken('WR_DENSITY_CONFIG', {
|
|
|
24
24
|
* Use of this source code is governed by an MIT-style license that can be
|
|
25
25
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
26
26
|
*/
|
|
27
|
-
const VALID = ['compact', 'default', 'comfortable'];
|
|
27
|
+
const VALID = ['compact', 'default', 'comfortable', 'touch'];
|
|
28
28
|
function isDensity(v) {
|
|
29
29
|
return typeof v === 'string' && VALID.includes(v);
|
|
30
30
|
}
|
|
@@ -71,9 +71,9 @@ class WrDensity {
|
|
|
71
71
|
return;
|
|
72
72
|
this._current.set(density);
|
|
73
73
|
}
|
|
74
|
-
/** Cycle compact → default → comfortable → compact … */
|
|
74
|
+
/** Cycle compact → default → comfortable → touch → compact … */
|
|
75
75
|
cycle() {
|
|
76
|
-
const order = ['compact', 'default', 'comfortable'];
|
|
76
|
+
const order = ['compact', 'default', 'comfortable', 'touch'];
|
|
77
77
|
const i = order.indexOf(this._current());
|
|
78
78
|
this._current.set(order[(i + 1) % order.length]);
|
|
79
79
|
}
|