@neural-ui/core 1.2.1 → 1.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.
Files changed (239) hide show
  1. package/README.md +56 -88
  2. package/accordion/package.json +4 -0
  3. package/alert/package.json +4 -0
  4. package/autocomplete/package.json +4 -0
  5. package/avatar/package.json +4 -0
  6. package/badge/package.json +4 -0
  7. package/block-ui/package.json +4 -0
  8. package/breadcrumb/package.json +4 -0
  9. package/button/package.json +4 -0
  10. package/card/package.json +4 -0
  11. package/chart/package.json +4 -0
  12. package/checkbox/package.json +4 -0
  13. package/chip/package.json +4 -0
  14. package/code-block/package.json +4 -0
  15. package/color-picker/package.json +4 -0
  16. package/command-palette/package.json +4 -0
  17. package/confirm-dialog/package.json +4 -0
  18. package/context-menu/package.json +4 -0
  19. package/dashboard-grid/package.json +4 -0
  20. package/date-input/package.json +4 -0
  21. package/divider/package.json +4 -0
  22. package/empty-state/package.json +4 -0
  23. package/fesm2022/neural-ui-core-accordion.mjs +162 -0
  24. package/fesm2022/neural-ui-core-accordion.mjs.map +1 -0
  25. package/fesm2022/neural-ui-core-alert.mjs +116 -0
  26. package/fesm2022/neural-ui-core-alert.mjs.map +1 -0
  27. package/fesm2022/neural-ui-core-autocomplete.mjs +332 -0
  28. package/fesm2022/neural-ui-core-autocomplete.mjs.map +1 -0
  29. package/fesm2022/neural-ui-core-avatar.mjs +109 -0
  30. package/fesm2022/neural-ui-core-avatar.mjs.map +1 -0
  31. package/fesm2022/neural-ui-core-badge.mjs +54 -0
  32. package/fesm2022/neural-ui-core-badge.mjs.map +1 -0
  33. package/fesm2022/neural-ui-core-block-ui.mjs +95 -0
  34. package/fesm2022/neural-ui-core-block-ui.mjs.map +1 -0
  35. package/fesm2022/neural-ui-core-breadcrumb.mjs +84 -0
  36. package/fesm2022/neural-ui-core-breadcrumb.mjs.map +1 -0
  37. package/fesm2022/neural-ui-core-button.mjs +125 -0
  38. package/fesm2022/neural-ui-core-button.mjs.map +1 -0
  39. package/fesm2022/neural-ui-core-card.mjs +69 -0
  40. package/fesm2022/neural-ui-core-card.mjs.map +1 -0
  41. package/fesm2022/neural-ui-core-chart.mjs +287 -0
  42. package/fesm2022/neural-ui-core-chart.mjs.map +1 -0
  43. package/fesm2022/neural-ui-core-checkbox.mjs +138 -0
  44. package/fesm2022/neural-ui-core-checkbox.mjs.map +1 -0
  45. package/fesm2022/neural-ui-core-chip.mjs +130 -0
  46. package/fesm2022/neural-ui-core-chip.mjs.map +1 -0
  47. package/fesm2022/neural-ui-core-code-block.mjs +250 -0
  48. package/fesm2022/neural-ui-core-code-block.mjs.map +1 -0
  49. package/fesm2022/neural-ui-core-color-picker.mjs +435 -0
  50. package/fesm2022/neural-ui-core-color-picker.mjs.map +1 -0
  51. package/fesm2022/neural-ui-core-command-palette.mjs +235 -0
  52. package/fesm2022/neural-ui-core-command-palette.mjs.map +1 -0
  53. package/fesm2022/neural-ui-core-confirm-dialog.mjs +118 -0
  54. package/fesm2022/neural-ui-core-confirm-dialog.mjs.map +1 -0
  55. package/fesm2022/neural-ui-core-context-menu.mjs +158 -0
  56. package/fesm2022/neural-ui-core-context-menu.mjs.map +1 -0
  57. package/fesm2022/neural-ui-core-dashboard-grid.mjs +144 -0
  58. package/fesm2022/neural-ui-core-dashboard-grid.mjs.map +1 -0
  59. package/fesm2022/neural-ui-core-date-input.mjs +1332 -0
  60. package/fesm2022/neural-ui-core-date-input.mjs.map +1 -0
  61. package/fesm2022/neural-ui-core-divider.mjs +54 -0
  62. package/fesm2022/neural-ui-core-divider.mjs.map +1 -0
  63. package/fesm2022/neural-ui-core-empty-state.mjs +84 -0
  64. package/fesm2022/neural-ui-core-empty-state.mjs.map +1 -0
  65. package/fesm2022/neural-ui-core-filter-bar.mjs +118 -0
  66. package/fesm2022/neural-ui-core-filter-bar.mjs.map +1 -0
  67. package/fesm2022/neural-ui-core-icon.mjs +50 -0
  68. package/fesm2022/neural-ui-core-icon.mjs.map +1 -0
  69. package/fesm2022/neural-ui-core-image-viewer.mjs +309 -0
  70. package/fesm2022/neural-ui-core-image-viewer.mjs.map +1 -0
  71. package/fesm2022/neural-ui-core-input-otp.mjs +192 -0
  72. package/fesm2022/neural-ui-core-input-otp.mjs.map +1 -0
  73. package/fesm2022/neural-ui-core-input.mjs +320 -0
  74. package/fesm2022/neural-ui-core-input.mjs.map +1 -0
  75. package/fesm2022/neural-ui-core-knob.mjs +323 -0
  76. package/fesm2022/neural-ui-core-knob.mjs.map +1 -0
  77. package/fesm2022/neural-ui-core-meter-group.mjs +122 -0
  78. package/fesm2022/neural-ui-core-meter-group.mjs.map +1 -0
  79. package/fesm2022/neural-ui-core-modal.mjs +156 -0
  80. package/fesm2022/neural-ui-core-modal.mjs.map +1 -0
  81. package/fesm2022/neural-ui-core-multiselect.mjs +748 -0
  82. package/fesm2022/neural-ui-core-multiselect.mjs.map +1 -0
  83. package/fesm2022/neural-ui-core-nav.mjs +952 -0
  84. package/fesm2022/neural-ui-core-nav.mjs.map +1 -0
  85. package/fesm2022/neural-ui-core-notification-center.mjs +264 -0
  86. package/fesm2022/neural-ui-core-notification-center.mjs.map +1 -0
  87. package/fesm2022/neural-ui-core-number-input.mjs +331 -0
  88. package/fesm2022/neural-ui-core-number-input.mjs.map +1 -0
  89. package/fesm2022/neural-ui-core-pagination.mjs +198 -0
  90. package/fesm2022/neural-ui-core-pagination.mjs.map +1 -0
  91. package/fesm2022/neural-ui-core-popover.mjs +207 -0
  92. package/fesm2022/neural-ui-core-popover.mjs.map +1 -0
  93. package/fesm2022/neural-ui-core-progress-bar.mjs +105 -0
  94. package/fesm2022/neural-ui-core-progress-bar.mjs.map +1 -0
  95. package/fesm2022/neural-ui-core-radio.mjs +171 -0
  96. package/fesm2022/neural-ui-core-radio.mjs.map +1 -0
  97. package/fesm2022/neural-ui-core-rating.mjs +151 -0
  98. package/fesm2022/neural-ui-core-rating.mjs.map +1 -0
  99. package/fesm2022/neural-ui-core-select.mjs +638 -0
  100. package/fesm2022/neural-ui-core-select.mjs.map +1 -0
  101. package/fesm2022/neural-ui-core-sidebar.mjs +214 -0
  102. package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -0
  103. package/fesm2022/neural-ui-core-skeleton.mjs +40 -0
  104. package/fesm2022/neural-ui-core-skeleton.mjs.map +1 -0
  105. package/fesm2022/neural-ui-core-slider.mjs +146 -0
  106. package/fesm2022/neural-ui-core-slider.mjs.map +1 -0
  107. package/fesm2022/neural-ui-core-spinner.mjs +113 -0
  108. package/fesm2022/neural-ui-core-spinner.mjs.map +1 -0
  109. package/fesm2022/neural-ui-core-split-button.mjs +252 -0
  110. package/fesm2022/neural-ui-core-split-button.mjs.map +1 -0
  111. package/fesm2022/neural-ui-core-splitter.mjs +174 -0
  112. package/fesm2022/neural-ui-core-splitter.mjs.map +1 -0
  113. package/fesm2022/neural-ui-core-stats-card.mjs +163 -0
  114. package/fesm2022/neural-ui-core-stats-card.mjs.map +1 -0
  115. package/fesm2022/neural-ui-core-stepper.mjs +204 -0
  116. package/fesm2022/neural-ui-core-stepper.mjs.map +1 -0
  117. package/fesm2022/neural-ui-core-switch.mjs +111 -0
  118. package/fesm2022/neural-ui-core-switch.mjs.map +1 -0
  119. package/fesm2022/neural-ui-core-table.mjs +1860 -0
  120. package/fesm2022/neural-ui-core-table.mjs.map +1 -0
  121. package/fesm2022/neural-ui-core-tabs.mjs +246 -0
  122. package/fesm2022/neural-ui-core-tabs.mjs.map +1 -0
  123. package/fesm2022/neural-ui-core-textarea.mjs +188 -0
  124. package/fesm2022/neural-ui-core-textarea.mjs.map +1 -0
  125. package/fesm2022/neural-ui-core-timeline.mjs +117 -0
  126. package/fesm2022/neural-ui-core-timeline.mjs.map +1 -0
  127. package/fesm2022/neural-ui-core-toast.mjs +171 -0
  128. package/fesm2022/neural-ui-core-toast.mjs.map +1 -0
  129. package/fesm2022/neural-ui-core-toggle-button-group.mjs +162 -0
  130. package/fesm2022/neural-ui-core-toggle-button-group.mjs.map +1 -0
  131. package/fesm2022/neural-ui-core-toolbar.mjs +67 -0
  132. package/fesm2022/neural-ui-core-toolbar.mjs.map +1 -0
  133. package/fesm2022/neural-ui-core-tooltip.mjs +151 -0
  134. package/fesm2022/neural-ui-core-tooltip.mjs.map +1 -0
  135. package/fesm2022/neural-ui-core-url-state.mjs +96 -0
  136. package/fesm2022/neural-ui-core-url-state.mjs.map +1 -0
  137. package/fesm2022/neural-ui-core-virtual-list.mjs +126 -0
  138. package/fesm2022/neural-ui-core-virtual-list.mjs.map +1 -0
  139. package/fesm2022/neural-ui-core.mjs +11 -8544
  140. package/fesm2022/neural-ui-core.mjs.map +1 -1
  141. package/filter-bar/package.json +4 -0
  142. package/icon/package.json +4 -0
  143. package/image-viewer/package.json +4 -0
  144. package/input/package.json +4 -0
  145. package/input-otp/package.json +4 -0
  146. package/knob/package.json +4 -0
  147. package/meter-group/package.json +4 -0
  148. package/modal/package.json +4 -0
  149. package/multiselect/package.json +4 -0
  150. package/nav/package.json +4 -0
  151. package/notification-center/package.json +4 -0
  152. package/number-input/package.json +4 -0
  153. package/package.json +252 -5
  154. package/pagination/package.json +4 -0
  155. package/popover/package.json +4 -0
  156. package/progress-bar/package.json +4 -0
  157. package/radio/package.json +4 -0
  158. package/rating/package.json +4 -0
  159. package/select/package.json +4 -0
  160. package/sidebar/package.json +4 -0
  161. package/skeleton/package.json +4 -0
  162. package/slider/package.json +4 -0
  163. package/spinner/package.json +4 -0
  164. package/split-button/package.json +4 -0
  165. package/splitter/package.json +4 -0
  166. package/stats-card/package.json +4 -0
  167. package/stepper/package.json +4 -0
  168. package/styles/_tokens.scss +202 -0
  169. package/styles.scss +1 -0
  170. package/switch/package.json +4 -0
  171. package/table/package.json +4 -0
  172. package/tabs/package.json +4 -0
  173. package/textarea/package.json +4 -0
  174. package/timeline/package.json +4 -0
  175. package/toast/package.json +4 -0
  176. package/toggle-button-group/package.json +4 -0
  177. package/toolbar/package.json +4 -0
  178. package/tooltip/package.json +4 -0
  179. package/types/neural-ui-core-accordion.d.ts +55 -0
  180. package/types/neural-ui-core-alert.d.ts +47 -0
  181. package/types/neural-ui-core-autocomplete.d.ts +69 -0
  182. package/types/neural-ui-core-avatar.d.ts +39 -0
  183. package/types/neural-ui-core-badge.d.ts +36 -0
  184. package/types/neural-ui-core-block-ui.d.ts +46 -0
  185. package/types/neural-ui-core-breadcrumb.d.ts +38 -0
  186. package/types/neural-ui-core-button.d.ts +55 -0
  187. package/types/neural-ui-core-card.d.ts +37 -0
  188. package/types/neural-ui-core-chart.d.ts +236 -0
  189. package/types/neural-ui-core-checkbox.d.ts +33 -0
  190. package/types/neural-ui-core-chip.d.ts +53 -0
  191. package/types/neural-ui-core-code-block.d.ts +55 -0
  192. package/types/neural-ui-core-color-picker.d.ts +55 -0
  193. package/types/neural-ui-core-command-palette.d.ts +56 -0
  194. package/types/neural-ui-core-confirm-dialog.d.ts +50 -0
  195. package/types/neural-ui-core-context-menu.d.ts +66 -0
  196. package/types/neural-ui-core-dashboard-grid.d.ts +41 -0
  197. package/types/neural-ui-core-date-input.d.ts +178 -0
  198. package/types/neural-ui-core-divider.d.ts +20 -0
  199. package/types/neural-ui-core-empty-state.d.ts +32 -0
  200. package/types/neural-ui-core-filter-bar.d.ts +49 -0
  201. package/types/neural-ui-core-icon.d.ts +33 -0
  202. package/types/neural-ui-core-image-viewer.d.ts +67 -0
  203. package/types/neural-ui-core-input-otp.d.ts +49 -0
  204. package/types/neural-ui-core-input.d.ts +86 -0
  205. package/types/neural-ui-core-knob.d.ts +68 -0
  206. package/types/neural-ui-core-meter-group.d.ts +52 -0
  207. package/types/neural-ui-core-modal.d.ts +54 -0
  208. package/types/neural-ui-core-multiselect.d.ts +129 -0
  209. package/types/neural-ui-core-nav.d.ts +69 -0
  210. package/types/neural-ui-core-notification-center.d.ts +60 -0
  211. package/types/neural-ui-core-number-input.d.ts +63 -0
  212. package/types/neural-ui-core-pagination.d.ts +30 -0
  213. package/types/neural-ui-core-popover.d.ts +73 -0
  214. package/types/neural-ui-core-progress-bar.d.ts +35 -0
  215. package/types/neural-ui-core-radio.d.ts +51 -0
  216. package/types/neural-ui-core-rating.d.ts +34 -0
  217. package/types/neural-ui-core-select.d.ts +161 -0
  218. package/types/neural-ui-core-sidebar.d.ts +57 -0
  219. package/types/neural-ui-core-skeleton.d.ts +22 -0
  220. package/types/neural-ui-core-slider.d.ts +42 -0
  221. package/types/neural-ui-core-spinner.d.ts +38 -0
  222. package/types/neural-ui-core-split-button.d.ts +65 -0
  223. package/types/neural-ui-core-splitter.d.ts +28 -0
  224. package/types/neural-ui-core-stats-card.d.ts +39 -0
  225. package/types/neural-ui-core-stepper.d.ts +51 -0
  226. package/types/neural-ui-core-switch.d.ts +34 -0
  227. package/types/neural-ui-core-table.d.ts +282 -0
  228. package/types/neural-ui-core-tabs.d.ts +76 -0
  229. package/types/neural-ui-core-textarea.d.ts +52 -0
  230. package/types/neural-ui-core-timeline.d.ts +33 -0
  231. package/types/neural-ui-core-toast.d.ts +70 -0
  232. package/types/neural-ui-core-toggle-button-group.d.ts +63 -0
  233. package/types/neural-ui-core-toolbar.d.ts +36 -0
  234. package/types/neural-ui-core-tooltip.d.ts +48 -0
  235. package/types/neural-ui-core-url-state.d.ts +58 -0
  236. package/types/neural-ui-core-virtual-list.d.ts +60 -0
  237. package/types/neural-ui-core.d.ts +3 -2105
  238. package/url-state/package.json +4 -0
  239. package/virtual-list/package.json +4 -0
@@ -0,0 +1,235 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, computed, Injectable, inject, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+
4
+ /**
5
+ * NeuralUI CommandPaletteService
6
+ *
7
+ * Gestiona los comandos registrados y la apertura/cierre del pallete.
8
+ *
9
+ * Uso:
10
+ * inject(NeuCommandPaletteService).register({ id: 'goto-home', label: 'Ir al inicio', action: () => router.navigate(['/']) });
11
+ * inject(NeuCommandPaletteService).open();
12
+ */
13
+ class NeuCommandPaletteService {
14
+ _commands = signal([], ...(ngDevMode ? [{ debugName: "_commands" }] : /* istanbul ignore next */ []));
15
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
16
+ query = signal('', ...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
17
+ filteredCommands = computed(() => {
18
+ const q = this.query().toLowerCase().trim();
19
+ const cmds = this._commands();
20
+ if (!q)
21
+ return cmds;
22
+ return cmds.filter((c) => c.label.toLowerCase().includes(q) || (c.group?.toLowerCase().includes(q) ?? false));
23
+ }, ...(ngDevMode ? [{ debugName: "filteredCommands" }] : /* istanbul ignore next */ []));
24
+ register(...commands) {
25
+ this._commands.update((list) => {
26
+ const ids = new Set(commands.map((c) => c.id));
27
+ return [...list.filter((c) => !ids.has(c.id)), ...commands];
28
+ });
29
+ }
30
+ unregister(...ids) {
31
+ const set = new Set(ids);
32
+ this._commands.update((list) => list.filter((c) => !set.has(c.id)));
33
+ }
34
+ open() {
35
+ this.query.set('');
36
+ this.isOpen.set(true);
37
+ }
38
+ close() {
39
+ this.isOpen.set(false);
40
+ this.query.set('');
41
+ }
42
+ execute(id) {
43
+ const cmd = this._commands().find((c) => c.id === id);
44
+ cmd?.action();
45
+ this.close();
46
+ }
47
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuCommandPaletteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
48
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuCommandPaletteService, providedIn: 'root' });
49
+ }
50
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuCommandPaletteService, decorators: [{
51
+ type: Injectable,
52
+ args: [{ providedIn: 'root' }]
53
+ }] });
54
+ /**
55
+ * NeuralUI CommandPalette Component
56
+ *
57
+ * Paleta de comandos activada con Cmd+K / Ctrl+K.
58
+ * Registra el atajos globalmente mientras el componente está montado.
59
+ *
60
+ * Uso:
61
+ * <neu-command-palette /> <!-- colócalo una vez en el root layout -->
62
+ */
63
+ class NeuCommandPaletteComponent {
64
+ _svc = inject(NeuCommandPaletteService);
65
+ _activeIndex = signal(0, ...(ngDevMode ? [{ debugName: "_activeIndex" }] : /* istanbul ignore next */ []));
66
+ _onDocKey(e) {
67
+ if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
68
+ e.preventDefault();
69
+ this._svc.isOpen() ? this._svc.close() : this._svc.open();
70
+ }
71
+ }
72
+ _onInputKey(e) {
73
+ const total = this._svc.filteredCommands().length;
74
+ switch (e.key) {
75
+ case 'ArrowDown':
76
+ e.preventDefault();
77
+ this._activeIndex.update((i) => Math.min(i + 1, total - 1));
78
+ break;
79
+ case 'ArrowUp':
80
+ e.preventDefault();
81
+ this._activeIndex.update((i) => Math.max(i - 1, 0));
82
+ break;
83
+ case 'Enter': {
84
+ const cmd = this._svc.filteredCommands()[this._activeIndex()];
85
+ if (cmd)
86
+ this._svc.execute(cmd.id);
87
+ break;
88
+ }
89
+ case 'Escape':
90
+ this._svc.close();
91
+ break;
92
+ }
93
+ }
94
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuCommandPaletteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
95
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuCommandPaletteComponent, isStandalone: true, selector: "neu-command-palette", host: { listeners: { "document:keydown": "_onDocKey($event)" } }, ngImport: i0, template: `
96
+ @if (_svc.isOpen()) {
97
+ <!-- Backdrop -->
98
+ <div class="neu-cp-backdrop" aria-hidden="true" (click)="_svc.close()"></div>
99
+
100
+ <!-- Dialog -->
101
+ <div class="neu-cmd" role="dialog" aria-modal="true" aria-label="Paleta de comandos">
102
+ <div class="neu-cmd__search-wrap">
103
+ <span class="neu-cmd__search-icon" aria-hidden="true">🔍</span>
104
+ <input
105
+ class="neu-cmd__input"
106
+ type="text"
107
+ placeholder="Buscar comandos…"
108
+ autocomplete="off"
109
+ role="combobox"
110
+ aria-expanded="true"
111
+ aria-autocomplete="list"
112
+ aria-controls="neu-cmd-list"
113
+ [value]="_svc.query()"
114
+ (input)="_svc.query.set($any($event.target).value)"
115
+ (keydown)="_onInputKey($event)"
116
+ #searchInput
117
+ />
118
+ <kbd class="neu-cmd__esc-hint">ESC</kbd>
119
+ </div>
120
+
121
+ <ul id="neu-cmd-list" class="neu-cmd__list" role="listbox" aria-label="Comandos">
122
+ @if (!_svc.filteredCommands().length) {
123
+ <li class="neu-cmd__empty" role="option" aria-selected="false">
124
+ Sin resultados para "{{ _svc.query() }}"
125
+ </li>
126
+ }
127
+ @for (cmd of _svc.filteredCommands(); track cmd.id; let i = $index) {
128
+ <li
129
+ class="neu-cmd__item"
130
+ role="option"
131
+ [class.neu-cmd__item--active]="_activeIndex() === i"
132
+ [id]="'neu-cmd-opt-' + i"
133
+ [attr.aria-selected]="_activeIndex() === i"
134
+ (click)="_svc.execute(cmd.id)"
135
+ (mouseenter)="_activeIndex.set(i)"
136
+ >
137
+ @if (cmd.icon) {
138
+ <span class="neu-cmd__item-icon" aria-hidden="true">{{ cmd.icon }}</span>
139
+ }
140
+ <span class="neu-cmd__item-label">{{ cmd.label }}</span>
141
+ @if (cmd.group) {
142
+ <span class="neu-cmd__item-group">{{ cmd.group }}</span>
143
+ }
144
+ @if (cmd.shortcut) {
145
+ <kbd class="neu-cmd__item-shortcut">{{ cmd.shortcut }}</kbd>
146
+ }
147
+ </li>
148
+ }
149
+ </ul>
150
+
151
+ <div class="neu-cmd__footer">
152
+ <span><kbd>↑↓</kbd> navegar</span>
153
+ <span><kbd>↵</kbd> ejecutar</span>
154
+ <span><kbd>ESC</kbd> cerrar</span>
155
+ </div>
156
+ </div>
157
+ }
158
+ `, isInline: true, styles: ["@charset \"UTF-8\";.neu-cp-backdrop{position:fixed;inset:0;background:var(--neu-overlay-bg);z-index:1200;animation:neu-cp-fade-in 80ms ease}@keyframes neu-cp-fade-in{0%{opacity:0}to{opacity:1}}.neu-cmd{position:fixed;top:20%;left:50%;transform:translate(-50%);width:560px;max-width:calc(100vw - 32px);background:var(--neu-surface);border:1px solid var(--neu-border);border-radius:var(--neu-radius-xl);box-shadow:var(--neu-cmd-shadow);z-index:1201;display:flex;flex-direction:column;overflow:hidden;animation:neu-cmd-in .1s ease}@keyframes neu-cmd-in{0%{opacity:0;transform:translate(-50%) translateY(-8px) scale(.97)}to{opacity:1;transform:translate(-50%) translateY(0) scale(1)}}.neu-cmd__search-wrap{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--neu-border)}.neu-cmd__search-icon{font-size:1rem;flex-shrink:0}.neu-cmd__input{flex:1;border:none;outline:none;background:transparent;font-size:1rem;color:var(--neu-text)}.neu-cmd__input::placeholder{color:var(--neu-text-muted)}.neu-cmd__esc-hint{font-size:.6875rem;padding:2px 6px;background:var(--neu-surface-2);border:1px solid var(--neu-border);border-radius:4px;color:var(--neu-text-muted)}.neu-cmd__list{list-style:none;margin:0;padding:6px;max-height:320px;overflow-y:auto}.neu-cmd__empty{padding:14px 12px;font-size:.875rem;color:var(--neu-text-muted);text-align:center}.neu-cmd__item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:var(--neu-radius-lg, 12px);cursor:pointer;transition:background 80ms}.neu-cmd__item--active,.neu-cmd__item:hover{background:var(--neu-primary-50)}.neu-cmd__item-icon{font-size:1rem;flex-shrink:0;width:20px;text-align:center}.neu-cmd__item-label{flex:1;font-size:.9375rem;color:var(--neu-text)}.neu-cmd__item-group{font-size:.75rem;color:var(--neu-text-muted)}.neu-cmd__item-shortcut{font-size:.6875rem;padding:2px 5px;background:var(--neu-surface-2);border:1px solid var(--neu-border);border-radius:4px;color:var(--neu-text-muted)}.neu-cmd__footer{display:flex;gap:16px;align-items:center;padding:8px 14px;border-top:1px solid var(--neu-border);font-size:.6875rem;color:var(--neu-text-muted)}.neu-cmd__footer kbd{margin-right:3px;padding:1px 4px;background:var(--neu-surface-2);border:1px solid var(--neu-border);border-radius:3px;color:var(--neu-text-muted)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
159
+ }
160
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuCommandPaletteComponent, decorators: [{
161
+ type: Component,
162
+ args: [{ selector: 'neu-command-palette', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
163
+ '(document:keydown)': '_onDocKey($event)',
164
+ }, template: `
165
+ @if (_svc.isOpen()) {
166
+ <!-- Backdrop -->
167
+ <div class="neu-cp-backdrop" aria-hidden="true" (click)="_svc.close()"></div>
168
+
169
+ <!-- Dialog -->
170
+ <div class="neu-cmd" role="dialog" aria-modal="true" aria-label="Paleta de comandos">
171
+ <div class="neu-cmd__search-wrap">
172
+ <span class="neu-cmd__search-icon" aria-hidden="true">🔍</span>
173
+ <input
174
+ class="neu-cmd__input"
175
+ type="text"
176
+ placeholder="Buscar comandos…"
177
+ autocomplete="off"
178
+ role="combobox"
179
+ aria-expanded="true"
180
+ aria-autocomplete="list"
181
+ aria-controls="neu-cmd-list"
182
+ [value]="_svc.query()"
183
+ (input)="_svc.query.set($any($event.target).value)"
184
+ (keydown)="_onInputKey($event)"
185
+ #searchInput
186
+ />
187
+ <kbd class="neu-cmd__esc-hint">ESC</kbd>
188
+ </div>
189
+
190
+ <ul id="neu-cmd-list" class="neu-cmd__list" role="listbox" aria-label="Comandos">
191
+ @if (!_svc.filteredCommands().length) {
192
+ <li class="neu-cmd__empty" role="option" aria-selected="false">
193
+ Sin resultados para "{{ _svc.query() }}"
194
+ </li>
195
+ }
196
+ @for (cmd of _svc.filteredCommands(); track cmd.id; let i = $index) {
197
+ <li
198
+ class="neu-cmd__item"
199
+ role="option"
200
+ [class.neu-cmd__item--active]="_activeIndex() === i"
201
+ [id]="'neu-cmd-opt-' + i"
202
+ [attr.aria-selected]="_activeIndex() === i"
203
+ (click)="_svc.execute(cmd.id)"
204
+ (mouseenter)="_activeIndex.set(i)"
205
+ >
206
+ @if (cmd.icon) {
207
+ <span class="neu-cmd__item-icon" aria-hidden="true">{{ cmd.icon }}</span>
208
+ }
209
+ <span class="neu-cmd__item-label">{{ cmd.label }}</span>
210
+ @if (cmd.group) {
211
+ <span class="neu-cmd__item-group">{{ cmd.group }}</span>
212
+ }
213
+ @if (cmd.shortcut) {
214
+ <kbd class="neu-cmd__item-shortcut">{{ cmd.shortcut }}</kbd>
215
+ }
216
+ </li>
217
+ }
218
+ </ul>
219
+
220
+ <div class="neu-cmd__footer">
221
+ <span><kbd>↑↓</kbd> navegar</span>
222
+ <span><kbd>↵</kbd> ejecutar</span>
223
+ <span><kbd>ESC</kbd> cerrar</span>
224
+ </div>
225
+ </div>
226
+ }
227
+ `, styles: ["@charset \"UTF-8\";.neu-cp-backdrop{position:fixed;inset:0;background:var(--neu-overlay-bg);z-index:1200;animation:neu-cp-fade-in 80ms ease}@keyframes neu-cp-fade-in{0%{opacity:0}to{opacity:1}}.neu-cmd{position:fixed;top:20%;left:50%;transform:translate(-50%);width:560px;max-width:calc(100vw - 32px);background:var(--neu-surface);border:1px solid var(--neu-border);border-radius:var(--neu-radius-xl);box-shadow:var(--neu-cmd-shadow);z-index:1201;display:flex;flex-direction:column;overflow:hidden;animation:neu-cmd-in .1s ease}@keyframes neu-cmd-in{0%{opacity:0;transform:translate(-50%) translateY(-8px) scale(.97)}to{opacity:1;transform:translate(-50%) translateY(0) scale(1)}}.neu-cmd__search-wrap{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--neu-border)}.neu-cmd__search-icon{font-size:1rem;flex-shrink:0}.neu-cmd__input{flex:1;border:none;outline:none;background:transparent;font-size:1rem;color:var(--neu-text)}.neu-cmd__input::placeholder{color:var(--neu-text-muted)}.neu-cmd__esc-hint{font-size:.6875rem;padding:2px 6px;background:var(--neu-surface-2);border:1px solid var(--neu-border);border-radius:4px;color:var(--neu-text-muted)}.neu-cmd__list{list-style:none;margin:0;padding:6px;max-height:320px;overflow-y:auto}.neu-cmd__empty{padding:14px 12px;font-size:.875rem;color:var(--neu-text-muted);text-align:center}.neu-cmd__item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:var(--neu-radius-lg, 12px);cursor:pointer;transition:background 80ms}.neu-cmd__item--active,.neu-cmd__item:hover{background:var(--neu-primary-50)}.neu-cmd__item-icon{font-size:1rem;flex-shrink:0;width:20px;text-align:center}.neu-cmd__item-label{flex:1;font-size:.9375rem;color:var(--neu-text)}.neu-cmd__item-group{font-size:.75rem;color:var(--neu-text-muted)}.neu-cmd__item-shortcut{font-size:.6875rem;padding:2px 5px;background:var(--neu-surface-2);border:1px solid var(--neu-border);border-radius:4px;color:var(--neu-text-muted)}.neu-cmd__footer{display:flex;gap:16px;align-items:center;padding:8px 14px;border-top:1px solid var(--neu-border);font-size:.6875rem;color:var(--neu-text-muted)}.neu-cmd__footer kbd{margin-right:3px;padding:1px 4px;background:var(--neu-surface-2);border:1px solid var(--neu-border);border-radius:3px;color:var(--neu-text-muted)}\n"] }]
228
+ }] });
229
+
230
+ /**
231
+ * Generated bundle index. Do not edit.
232
+ */
233
+
234
+ export { NeuCommandPaletteComponent, NeuCommandPaletteService };
235
+ //# sourceMappingURL=neural-ui-core-command-palette.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-command-palette.mjs","sources":["../../../../projects/ui-core/command-palette/neu-command-palette.component.ts","../../../../projects/ui-core/command-palette/neural-ui-core-command-palette.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n Injectable,\n OnDestroy,\n ViewEncapsulation,\n computed,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n\nexport interface NeuCommand {\n id: string;\n label: string;\n /** Grupo / Category */\n group?: string;\n /** Icono (emoji / texto) / Icon */\n icon?: string;\n /** Shortcut display (e.g. '⌘K') */\n shortcut?: string;\n /** Handler invocado al seleccionar / Handler called on select */\n action: () => void;\n}\n\n/**\n * NeuralUI CommandPaletteService\n *\n * Gestiona los comandos registrados y la apertura/cierre del pallete.\n *\n * Uso:\n * inject(NeuCommandPaletteService).register({ id: 'goto-home', label: 'Ir al inicio', action: () => router.navigate(['/']) });\n * inject(NeuCommandPaletteService).open();\n */\n@Injectable({ providedIn: 'root' })\nexport class NeuCommandPaletteService {\n private readonly _commands = signal<NeuCommand[]>([]);\n readonly isOpen = signal(false);\n readonly query = signal('');\n\n readonly filteredCommands = computed(() => {\n const q = this.query().toLowerCase().trim();\n const cmds = this._commands();\n if (!q) return cmds;\n return cmds.filter(\n (c) => c.label.toLowerCase().includes(q) || (c.group?.toLowerCase().includes(q) ?? false),\n );\n });\n\n register(...commands: NeuCommand[]): void {\n this._commands.update((list) => {\n const ids = new Set(commands.map((c) => c.id));\n return [...list.filter((c) => !ids.has(c.id)), ...commands];\n });\n }\n\n unregister(...ids: string[]): void {\n const set = new Set(ids);\n this._commands.update((list) => list.filter((c) => !set.has(c.id)));\n }\n\n open(): void {\n this.query.set('');\n this.isOpen.set(true);\n }\n\n close(): void {\n this.isOpen.set(false);\n this.query.set('');\n }\n\n execute(id: string): void {\n const cmd = this._commands().find((c) => c.id === id);\n cmd?.action();\n this.close();\n }\n}\n\n/**\n * NeuralUI CommandPalette Component\n *\n * Paleta de comandos activada con Cmd+K / Ctrl+K.\n * Registra el atajos globalmente mientras el componente está montado.\n *\n * Uso:\n * <neu-command-palette /> <!-- colócalo una vez en el root layout -->\n */\n@Component({\n selector: 'neu-command-palette',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '(document:keydown)': '_onDocKey($event)',\n },\n template: `\n @if (_svc.isOpen()) {\n <!-- Backdrop -->\n <div class=\"neu-cp-backdrop\" aria-hidden=\"true\" (click)=\"_svc.close()\"></div>\n\n <!-- Dialog -->\n <div class=\"neu-cmd\" role=\"dialog\" aria-modal=\"true\" aria-label=\"Paleta de comandos\">\n <div class=\"neu-cmd__search-wrap\">\n <span class=\"neu-cmd__search-icon\" aria-hidden=\"true\">🔍</span>\n <input\n class=\"neu-cmd__input\"\n type=\"text\"\n placeholder=\"Buscar comandos…\"\n autocomplete=\"off\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-autocomplete=\"list\"\n aria-controls=\"neu-cmd-list\"\n [value]=\"_svc.query()\"\n (input)=\"_svc.query.set($any($event.target).value)\"\n (keydown)=\"_onInputKey($event)\"\n #searchInput\n />\n <kbd class=\"neu-cmd__esc-hint\">ESC</kbd>\n </div>\n\n <ul id=\"neu-cmd-list\" class=\"neu-cmd__list\" role=\"listbox\" aria-label=\"Comandos\">\n @if (!_svc.filteredCommands().length) {\n <li class=\"neu-cmd__empty\" role=\"option\" aria-selected=\"false\">\n Sin resultados para \"{{ _svc.query() }}\"\n </li>\n }\n @for (cmd of _svc.filteredCommands(); track cmd.id; let i = $index) {\n <li\n class=\"neu-cmd__item\"\n role=\"option\"\n [class.neu-cmd__item--active]=\"_activeIndex() === i\"\n [id]=\"'neu-cmd-opt-' + i\"\n [attr.aria-selected]=\"_activeIndex() === i\"\n (click)=\"_svc.execute(cmd.id)\"\n (mouseenter)=\"_activeIndex.set(i)\"\n >\n @if (cmd.icon) {\n <span class=\"neu-cmd__item-icon\" aria-hidden=\"true\">{{ cmd.icon }}</span>\n }\n <span class=\"neu-cmd__item-label\">{{ cmd.label }}</span>\n @if (cmd.group) {\n <span class=\"neu-cmd__item-group\">{{ cmd.group }}</span>\n }\n @if (cmd.shortcut) {\n <kbd class=\"neu-cmd__item-shortcut\">{{ cmd.shortcut }}</kbd>\n }\n </li>\n }\n </ul>\n\n <div class=\"neu-cmd__footer\">\n <span><kbd>↑↓</kbd> navegar</span>\n <span><kbd>↵</kbd> ejecutar</span>\n <span><kbd>ESC</kbd> cerrar</span>\n </div>\n </div>\n }\n `,\n styleUrl: './neu-command-palette.component.scss',\n})\nexport class NeuCommandPaletteComponent {\n readonly _svc = inject(NeuCommandPaletteService);\n readonly _activeIndex = signal(0);\n\n _onDocKey(e: KeyboardEvent): void {\n if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n e.preventDefault();\n this._svc.isOpen() ? this._svc.close() : this._svc.open();\n }\n }\n\n _onInputKey(e: KeyboardEvent): void {\n const total = this._svc.filteredCommands().length;\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this._activeIndex.update((i) => Math.min(i + 1, total - 1));\n break;\n case 'ArrowUp':\n e.preventDefault();\n this._activeIndex.update((i) => Math.max(i - 1, 0));\n break;\n case 'Enter': {\n const cmd = this._svc.filteredCommands()[this._activeIndex()];\n if (cmd) this._svc.execute(cmd.id);\n break;\n }\n case 'Escape':\n this._svc.close();\n break;\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, ChangeDetectionStrategy, ViewEncapsulation, Component, Injectable } from '@angular/core';
3
+ import { DIALOG_DATA, DialogRef, Dialog } from '@angular/cdk/dialog';
4
+
5
+ /**
6
+ * NeuralUI ConfirmDialog Component (internal — usado por NeuConfirmDialogService)
7
+ */
8
+ class NeuConfirmDialogComponent {
9
+ data = inject(DIALOG_DATA);
10
+ _dialogRef = inject((DialogRef));
11
+ accept() {
12
+ this._dialogRef.close(true);
13
+ }
14
+ reject() {
15
+ this._dialogRef.close(false);
16
+ }
17
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuConfirmDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
18
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuConfirmDialogComponent, isStandalone: true, selector: "neu-confirm-dialog", host: { attributes: { "role": "alertdialog", "aria-modal": "true" }, properties: { "attr.aria-labelledby": "\"neu-confirm-title\"", "attr.aria-describedby": "\"neu-confirm-msg\"" }, classAttribute: "neu-confirm-dialog" }, ngImport: i0, template: `
19
+ @if (data.title) {
20
+ <h2 class="neu-confirm-dialog__title" id="neu-confirm-title">{{ data.title }}</h2>
21
+ }
22
+ <p class="neu-confirm-dialog__message" id="neu-confirm-msg">{{ data.message }}</p>
23
+ <div class="neu-confirm-dialog__actions">
24
+ <button
25
+ type="button"
26
+ class="neu-confirm-dialog__btn neu-confirm-dialog__btn--reject"
27
+ [class.neu-confirm-dialog__btn--danger]="data.rejectVariant === 'danger'"
28
+ (click)="reject()"
29
+ >
30
+ {{ data.rejectLabel ?? 'Cancelar' }}
31
+ </button>
32
+ <button
33
+ type="button"
34
+ class="neu-confirm-dialog__btn"
35
+ [class.neu-confirm-dialog__btn--primary]="(data.acceptVariant ?? 'primary') === 'primary'"
36
+ [class.neu-confirm-dialog__btn--danger]="data.acceptVariant === 'danger'"
37
+ (click)="accept()"
38
+ >
39
+ {{ data.acceptLabel ?? 'Aceptar' }}
40
+ </button>
41
+ </div>
42
+ `, isInline: true, styles: ["@charset \"UTF-8\";.neu-confirm-dialog{display:flex;flex-direction:column;gap:16px;background:var(--neu-surface-1, #ffffff);border:1px solid var(--neu-border-color, #e5e7eb);border-radius:var(--neu-radius-xl, 16px);box-shadow:0 20px 40px -8px #0000002e;padding:24px;width:clamp(280px,90vw,420px);animation:neu-confirm-in .14s ease}@keyframes neu-confirm-in{0%{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.neu-confirm-dialog__title{margin:0;font-size:1.125rem;font-weight:600;color:var(--neu-text-primary, #111)}.neu-confirm-dialog__message{margin:0;font-size:.9375rem;color:var(--neu-text-secondary, #4b5563);line-height:1.55}.neu-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:8px;padding-top:4px}.neu-confirm-dialog__btn{all:unset;box-sizing:border-box;padding:8px 18px;border-radius:var(--neu-radius-md, 8px);font-size:.875rem;font-weight:500;cursor:pointer;transition:background .12s,color .12s}.neu-confirm-dialog__btn:focus-visible{outline:2px solid var(--neu-focus-ring, #0ea5e9);outline-offset:2px}.neu-confirm-dialog__btn--reject{color:var(--neu-text-secondary, #4b5563);background:var(--neu-surface-2, #f3f4f6)}.neu-confirm-dialog__btn--reject:hover{background:var(--neu-surface-3, #e5e7eb)}.neu-confirm-dialog__btn--reject.neu-confirm-dialog__btn--danger{background:var(--neu-color-danger, #ef4444);color:var(--neu-primary-fg)}.neu-confirm-dialog__btn--reject.neu-confirm-dialog__btn--danger:hover{filter:brightness(1.08)}.neu-confirm-dialog__btn--primary{background:var(--neu-color-primary, #0ea5e9);color:var(--neu-primary-fg)}.neu-confirm-dialog__btn--primary:hover{filter:brightness(1.08)}.neu-confirm-dialog__btn--danger{background:var(--neu-color-danger, #ef4444);color:var(--neu-primary-fg)}.neu-confirm-dialog__btn--danger:hover{filter:brightness(1.08)}.neu-confirm-dialog-backdrop{background:var(--neu-overlay-bg);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
43
+ }
44
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuConfirmDialogComponent, decorators: [{
45
+ type: Component,
46
+ args: [{ selector: 'neu-confirm-dialog', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
47
+ class: 'neu-confirm-dialog',
48
+ role: 'alertdialog',
49
+ 'aria-modal': 'true',
50
+ '[attr.aria-labelledby]': '"neu-confirm-title"',
51
+ '[attr.aria-describedby]': '"neu-confirm-msg"',
52
+ }, template: `
53
+ @if (data.title) {
54
+ <h2 class="neu-confirm-dialog__title" id="neu-confirm-title">{{ data.title }}</h2>
55
+ }
56
+ <p class="neu-confirm-dialog__message" id="neu-confirm-msg">{{ data.message }}</p>
57
+ <div class="neu-confirm-dialog__actions">
58
+ <button
59
+ type="button"
60
+ class="neu-confirm-dialog__btn neu-confirm-dialog__btn--reject"
61
+ [class.neu-confirm-dialog__btn--danger]="data.rejectVariant === 'danger'"
62
+ (click)="reject()"
63
+ >
64
+ {{ data.rejectLabel ?? 'Cancelar' }}
65
+ </button>
66
+ <button
67
+ type="button"
68
+ class="neu-confirm-dialog__btn"
69
+ [class.neu-confirm-dialog__btn--primary]="(data.acceptVariant ?? 'primary') === 'primary'"
70
+ [class.neu-confirm-dialog__btn--danger]="data.acceptVariant === 'danger'"
71
+ (click)="accept()"
72
+ >
73
+ {{ data.acceptLabel ?? 'Aceptar' }}
74
+ </button>
75
+ </div>
76
+ `, styles: ["@charset \"UTF-8\";.neu-confirm-dialog{display:flex;flex-direction:column;gap:16px;background:var(--neu-surface-1, #ffffff);border:1px solid var(--neu-border-color, #e5e7eb);border-radius:var(--neu-radius-xl, 16px);box-shadow:0 20px 40px -8px #0000002e;padding:24px;width:clamp(280px,90vw,420px);animation:neu-confirm-in .14s ease}@keyframes neu-confirm-in{0%{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.neu-confirm-dialog__title{margin:0;font-size:1.125rem;font-weight:600;color:var(--neu-text-primary, #111)}.neu-confirm-dialog__message{margin:0;font-size:.9375rem;color:var(--neu-text-secondary, #4b5563);line-height:1.55}.neu-confirm-dialog__actions{display:flex;justify-content:flex-end;gap:8px;padding-top:4px}.neu-confirm-dialog__btn{all:unset;box-sizing:border-box;padding:8px 18px;border-radius:var(--neu-radius-md, 8px);font-size:.875rem;font-weight:500;cursor:pointer;transition:background .12s,color .12s}.neu-confirm-dialog__btn:focus-visible{outline:2px solid var(--neu-focus-ring, #0ea5e9);outline-offset:2px}.neu-confirm-dialog__btn--reject{color:var(--neu-text-secondary, #4b5563);background:var(--neu-surface-2, #f3f4f6)}.neu-confirm-dialog__btn--reject:hover{background:var(--neu-surface-3, #e5e7eb)}.neu-confirm-dialog__btn--reject.neu-confirm-dialog__btn--danger{background:var(--neu-color-danger, #ef4444);color:var(--neu-primary-fg)}.neu-confirm-dialog__btn--reject.neu-confirm-dialog__btn--danger:hover{filter:brightness(1.08)}.neu-confirm-dialog__btn--primary{background:var(--neu-color-primary, #0ea5e9);color:var(--neu-primary-fg)}.neu-confirm-dialog__btn--primary:hover{filter:brightness(1.08)}.neu-confirm-dialog__btn--danger{background:var(--neu-color-danger, #ef4444);color:var(--neu-primary-fg)}.neu-confirm-dialog__btn--danger:hover{filter:brightness(1.08)}.neu-confirm-dialog-backdrop{background:var(--neu-overlay-bg);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}\n"] }]
77
+ }] });
78
+ /**
79
+ * NeuralUI ConfirmDialog Service
80
+ *
81
+ * Abre un diálogo de confirmación y retorna una promesa con el resultado.
82
+ *
83
+ * Uso:
84
+ * inject(NeuConfirmDialogService)
85
+ * .confirm({ message: '¿Eliminar este registro?', acceptVariant: 'danger' })
86
+ * .then(ok => ok && doDelete());
87
+ */
88
+ class NeuConfirmDialogService {
89
+ _dialog = inject(Dialog);
90
+ /**
91
+ * Abre el diálogo y resuelve con `true` si el usuario acepta,
92
+ * `false` si cancela o cierra el diálogo.
93
+ */
94
+ confirm(data) {
95
+ const ref = this._dialog.open(NeuConfirmDialogComponent, {
96
+ data,
97
+ panelClass: 'neu-confirm-dialog-panel',
98
+ backdropClass: 'neu-confirm-dialog-backdrop',
99
+ disableClose: true,
100
+ });
101
+ return new Promise((resolve) => {
102
+ ref.closed.subscribe((result) => resolve(result ?? false));
103
+ });
104
+ }
105
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuConfirmDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
106
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuConfirmDialogService, providedIn: 'root' });
107
+ }
108
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuConfirmDialogService, decorators: [{
109
+ type: Injectable,
110
+ args: [{ providedIn: 'root' }]
111
+ }] });
112
+
113
+ /**
114
+ * Generated bundle index. Do not edit.
115
+ */
116
+
117
+ export { NeuConfirmDialogComponent, NeuConfirmDialogService };
118
+ //# sourceMappingURL=neural-ui-core-confirm-dialog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-confirm-dialog.mjs","sources":["../../../../projects/ui-core/confirm-dialog/neu-confirm-dialog.component.ts","../../../../projects/ui-core/confirm-dialog/neural-ui-core-confirm-dialog.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n Injectable,\n ViewEncapsulation,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { Dialog, DialogRef, DIALOG_DATA } from '@angular/cdk/dialog';\n\nexport interface NeuConfirmDialogData {\n /** Título del diálogo / Dialog title */\n title?: string;\n /** Mensaje principal / Main message */\n message: string;\n /** Etiqueta botón aceptar / Accept button label */\n acceptLabel?: string;\n /** Etiqueta botón cancelar / Cancel button label */\n rejectLabel?: string;\n /** Variante del botón cancelar / Reject button variant */\n rejectVariant?: 'secondary' | 'danger';\n /** Variante del botón aceptar / Accept button variant */\n acceptVariant?: 'primary' | 'danger';\n}\n\n/**\n * NeuralUI ConfirmDialog Component (internal — usado por NeuConfirmDialogService)\n */\n@Component({\n selector: 'neu-confirm-dialog',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'neu-confirm-dialog',\n role: 'alertdialog',\n 'aria-modal': 'true',\n '[attr.aria-labelledby]': '\"neu-confirm-title\"',\n '[attr.aria-describedby]': '\"neu-confirm-msg\"',\n },\n template: `\n @if (data.title) {\n <h2 class=\"neu-confirm-dialog__title\" id=\"neu-confirm-title\">{{ data.title }}</h2>\n }\n <p class=\"neu-confirm-dialog__message\" id=\"neu-confirm-msg\">{{ data.message }}</p>\n <div class=\"neu-confirm-dialog__actions\">\n <button\n type=\"button\"\n class=\"neu-confirm-dialog__btn neu-confirm-dialog__btn--reject\"\n [class.neu-confirm-dialog__btn--danger]=\"data.rejectVariant === 'danger'\"\n (click)=\"reject()\"\n >\n {{ data.rejectLabel ?? 'Cancelar' }}\n </button>\n <button\n type=\"button\"\n class=\"neu-confirm-dialog__btn\"\n [class.neu-confirm-dialog__btn--primary]=\"(data.acceptVariant ?? 'primary') === 'primary'\"\n [class.neu-confirm-dialog__btn--danger]=\"data.acceptVariant === 'danger'\"\n (click)=\"accept()\"\n >\n {{ data.acceptLabel ?? 'Aceptar' }}\n </button>\n </div>\n `,\n styleUrl: './neu-confirm-dialog.component.scss',\n})\nexport class NeuConfirmDialogComponent {\n readonly data: NeuConfirmDialogData = inject(DIALOG_DATA);\n private readonly _dialogRef = inject(DialogRef<boolean>);\n\n accept(): void {\n this._dialogRef.close(true);\n }\n\n reject(): void {\n this._dialogRef.close(false);\n }\n}\n\n/**\n * NeuralUI ConfirmDialog Service\n *\n * Abre un diálogo de confirmación y retorna una promesa con el resultado.\n *\n * Uso:\n * inject(NeuConfirmDialogService)\n * .confirm({ message: '¿Eliminar este registro?', acceptVariant: 'danger' })\n * .then(ok => ok && doDelete());\n */\n@Injectable({ providedIn: 'root' })\nexport class NeuConfirmDialogService {\n private readonly _dialog = inject(Dialog);\n\n /**\n * Abre el diálogo y resuelve con `true` si el usuario acepta,\n * `false` si cancela o cierra el diálogo.\n */\n confirm(data: NeuConfirmDialogData): Promise<boolean> {\n const ref = this._dialog.open<boolean, NeuConfirmDialogData>(NeuConfirmDialogComponent, {\n data,\n panelClass: 'neu-confirm-dialog-panel',\n backdropClass: 'neu-confirm-dialog-backdrop',\n disableClose: true,\n });\n return new Promise<boolean>((resolve) => {\n ref.closed.subscribe((result) => resolve(result ?? false));\n });\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, ChangeDetectionStrategy, ViewEncapsulation, Component, input, output, inject, ElementRef, Injector, ViewContainerRef, HostListener, Directive } from '@angular/core';
3
+ import { Overlay } from '@angular/cdk/overlay';
4
+ import { ComponentPortal } from '@angular/cdk/portal';
5
+
6
+ let _seq = 0;
7
+ /**
8
+ * NeuralUI ContextMenu Overlay Component (internal)
9
+ */
10
+ class NeuContextMenuOverlayComponent {
11
+ _items = signal([], ...(ngDevMode ? [{ debugName: "_items" }] : /* istanbul ignore next */ []));
12
+ _selectFn = null;
13
+ _escapeFn = null;
14
+ select(item) {
15
+ if (!item.disabled)
16
+ this._selectFn?.(item);
17
+ }
18
+ _onEscape() {
19
+ this._escapeFn?.();
20
+ }
21
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuContextMenuOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
22
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuContextMenuOverlayComponent, isStandalone: true, selector: "neu-context-menu-overlay", host: { attributes: { "role": "menu", "tabindex": "-1" }, listeners: { "keydown.escape": "_onEscape()" }, classAttribute: "neu-context-menu" }, ngImport: i0, template: `
23
+ @for (item of _items(); track item.key) {
24
+ @if (item.separator && !$first) {
25
+ <hr class="neu-context-menu__separator" role="separator" />
26
+ }
27
+ <button
28
+ type="button"
29
+ role="menuitem"
30
+ class="neu-context-menu__item"
31
+ [class.neu-context-menu__item--danger]="item.variant === 'danger'"
32
+ [class.neu-context-menu__item--disabled]="item.disabled"
33
+ [disabled]="item.disabled ?? false"
34
+ [attr.aria-disabled]="item.disabled ?? false"
35
+ (click)="select(item)"
36
+ >
37
+ @if (item.icon) {
38
+ <span class="neu-context-menu__icon" aria-hidden="true">{{ item.icon }}</span>
39
+ }
40
+ {{ item.label }}
41
+ </button>
42
+ }
43
+ `, isInline: true, styles: ["@charset \"UTF-8\";.neu-context-menu{background:var(--neu-context-menu-bg, var(--neu-surface-1, #ffffff));border:1px solid var(--neu-context-menu-border, var(--neu-border-color, #e5e7eb));border-radius:var(--neu-radius-lg, 12px);box-shadow:0 8px 24px -4px #00000024;padding:6px;min-width:180px;max-width:260px;z-index:2000;outline:none;animation:neu-ctx-in 80ms ease}@keyframes neu-ctx-in{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}.neu-context-menu__item{all:unset;display:flex;align-items:center;gap:8px;width:100%;box-sizing:border-box;padding:7px 10px;border-radius:var(--neu-radius-md, 8px);font-size:.875rem;color:var(--neu-context-menu-color, var(--neu-text, var(--neu-text-primary, #111827)));cursor:pointer;transition:background .1s}.neu-context-menu__item:hover:not(.neu-context-menu__item--disabled){background:var(--neu-context-menu-hover, var(--neu-surface-2, #f3f4f6))}.neu-context-menu__item:focus-visible{background:var(--neu-context-menu-hover, var(--neu-surface-2, #f3f4f6));outline:2px solid var(--neu-focus-ring, #0ea5e9);outline-offset:-2px}.neu-context-menu__item.neu-context-menu__item--danger{color:var(--neu-color-danger, #ef4444)}.neu-context-menu__item.neu-context-menu__item--disabled{color:var(--neu-context-menu-disabled-color, var(--neu-text-muted, #6b7280));opacity:.56;cursor:not-allowed;pointer-events:none}.neu-context-menu__icon{flex-shrink:0;font-style:normal;font-size:1em}.neu-context-menu__separator{all:unset;display:block;height:1px;background:var(--neu-context-menu-border, var(--neu-border-color, #e5e7eb));margin:4px 0}.neu-context-menu-backdrop{background:transparent}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
44
+ }
45
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuContextMenuOverlayComponent, decorators: [{
46
+ type: Component,
47
+ args: [{ selector: 'neu-context-menu-overlay', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
48
+ class: 'neu-context-menu',
49
+ role: 'menu',
50
+ tabindex: '-1',
51
+ '(keydown.escape)': '_onEscape()',
52
+ }, template: `
53
+ @for (item of _items(); track item.key) {
54
+ @if (item.separator && !$first) {
55
+ <hr class="neu-context-menu__separator" role="separator" />
56
+ }
57
+ <button
58
+ type="button"
59
+ role="menuitem"
60
+ class="neu-context-menu__item"
61
+ [class.neu-context-menu__item--danger]="item.variant === 'danger'"
62
+ [class.neu-context-menu__item--disabled]="item.disabled"
63
+ [disabled]="item.disabled ?? false"
64
+ [attr.aria-disabled]="item.disabled ?? false"
65
+ (click)="select(item)"
66
+ >
67
+ @if (item.icon) {
68
+ <span class="neu-context-menu__icon" aria-hidden="true">{{ item.icon }}</span>
69
+ }
70
+ {{ item.label }}
71
+ </button>
72
+ }
73
+ `, styles: ["@charset \"UTF-8\";.neu-context-menu{background:var(--neu-context-menu-bg, var(--neu-surface-1, #ffffff));border:1px solid var(--neu-context-menu-border, var(--neu-border-color, #e5e7eb));border-radius:var(--neu-radius-lg, 12px);box-shadow:0 8px 24px -4px #00000024;padding:6px;min-width:180px;max-width:260px;z-index:2000;outline:none;animation:neu-ctx-in 80ms ease}@keyframes neu-ctx-in{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}.neu-context-menu__item{all:unset;display:flex;align-items:center;gap:8px;width:100%;box-sizing:border-box;padding:7px 10px;border-radius:var(--neu-radius-md, 8px);font-size:.875rem;color:var(--neu-context-menu-color, var(--neu-text, var(--neu-text-primary, #111827)));cursor:pointer;transition:background .1s}.neu-context-menu__item:hover:not(.neu-context-menu__item--disabled){background:var(--neu-context-menu-hover, var(--neu-surface-2, #f3f4f6))}.neu-context-menu__item:focus-visible{background:var(--neu-context-menu-hover, var(--neu-surface-2, #f3f4f6));outline:2px solid var(--neu-focus-ring, #0ea5e9);outline-offset:-2px}.neu-context-menu__item.neu-context-menu__item--danger{color:var(--neu-color-danger, #ef4444)}.neu-context-menu__item.neu-context-menu__item--disabled{color:var(--neu-context-menu-disabled-color, var(--neu-text-muted, #6b7280));opacity:.56;cursor:not-allowed;pointer-events:none}.neu-context-menu__icon{flex-shrink:0;font-style:normal;font-size:1em}.neu-context-menu__separator{all:unset;display:block;height:1px;background:var(--neu-context-menu-border, var(--neu-border-color, #e5e7eb));margin:4px 0}.neu-context-menu-backdrop{background:transparent}\n"] }]
74
+ }] });
75
+ /**
76
+ * NeuralUI ContextMenu Directive
77
+ *
78
+ * Muestra un menú contextual al hacer clic derecho sobre el elemento host.
79
+ *
80
+ * Uso:
81
+ * <div [neuContextMenu]="menuItems" (menuItemClick)="onItem($event)">
82
+ * Clic derecho aquí
83
+ * </div>
84
+ */
85
+ class NeuContextMenuDirective {
86
+ /** Ítems del menú / Menu items */
87
+ neuContextMenu = input([], ...(ngDevMode ? [{ debugName: "neuContextMenu" }] : /* istanbul ignore next */ []));
88
+ /** Desactiva el menú / Disables the menu */
89
+ neuContextMenuDisabled = input(false, ...(ngDevMode ? [{ debugName: "neuContextMenuDisabled" }] : /* istanbul ignore next */ []));
90
+ /** Emitido al seleccionar un ítem / Emitted when an item is selected */
91
+ menuItemClick = output();
92
+ /** Emitido al abrir / Emitted on open */
93
+ menuOpened = output();
94
+ /** Emitido al cerrar / Emitted on close */
95
+ menuClosed = output();
96
+ _overlay = inject(Overlay);
97
+ _el = inject((ElementRef));
98
+ _injector = inject(Injector);
99
+ _vcr = inject(ViewContainerRef);
100
+ _overlayRef = null;
101
+ _compRef = null;
102
+ onContextMenu(event) {
103
+ event.preventDefault();
104
+ if (this.neuContextMenuDisabled())
105
+ return;
106
+ this._open(event.clientX, event.clientY);
107
+ }
108
+ _open(x, y) {
109
+ this._close();
110
+ this._overlayRef = this._overlay.create({
111
+ hasBackdrop: true,
112
+ backdropClass: 'neu-context-menu-backdrop',
113
+ positionStrategy: this._overlay.position().global().left(`${x}px`).top(`${y}px`),
114
+ scrollStrategy: this._overlay.scrollStrategies.close(),
115
+ });
116
+ const portal = new ComponentPortal(NeuContextMenuOverlayComponent, this._vcr, this._injector);
117
+ this._compRef = this._overlayRef.attach(portal);
118
+ this._compRef.instance._items.set(this.neuContextMenu());
119
+ this._compRef.instance._selectFn = (item) => {
120
+ this.menuItemClick.emit(item);
121
+ this._close();
122
+ };
123
+ this._compRef.instance._escapeFn = () => this._close();
124
+ this._overlayRef.backdropClick().subscribe(() => this._close());
125
+ this.menuOpened.emit();
126
+ }
127
+ _close() {
128
+ if (this._overlayRef?.hasAttached()) {
129
+ this._overlayRef.detach();
130
+ this.menuClosed.emit();
131
+ }
132
+ this._overlayRef?.dispose();
133
+ this._overlayRef = null;
134
+ this._compRef = null;
135
+ }
136
+ ngOnDestroy() {
137
+ this._close();
138
+ }
139
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuContextMenuDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
140
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.8", type: NeuContextMenuDirective, isStandalone: true, selector: "[neuContextMenu]", inputs: { neuContextMenu: { classPropertyName: "neuContextMenu", publicName: "neuContextMenu", isSignal: true, isRequired: false, transformFunction: null }, neuContextMenuDisabled: { classPropertyName: "neuContextMenuDisabled", publicName: "neuContextMenuDisabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuItemClick: "menuItemClick", menuOpened: "menuOpened", menuClosed: "menuClosed" }, host: { listeners: { "contextmenu": "onContextMenu($event)" } }, exportAs: ["neuContextMenu"], ngImport: i0 });
141
+ }
142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuContextMenuDirective, decorators: [{
143
+ type: Directive,
144
+ args: [{
145
+ selector: '[neuContextMenu]',
146
+ exportAs: 'neuContextMenu',
147
+ }]
148
+ }], propDecorators: { neuContextMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "neuContextMenu", required: false }] }], neuContextMenuDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "neuContextMenuDisabled", required: false }] }], menuItemClick: [{ type: i0.Output, args: ["menuItemClick"] }], menuOpened: [{ type: i0.Output, args: ["menuOpened"] }], menuClosed: [{ type: i0.Output, args: ["menuClosed"] }], onContextMenu: [{
149
+ type: HostListener,
150
+ args: ['contextmenu', ['$event']]
151
+ }] } });
152
+
153
+ /**
154
+ * Generated bundle index. Do not edit.
155
+ */
156
+
157
+ export { NeuContextMenuDirective, NeuContextMenuOverlayComponent };
158
+ //# sourceMappingURL=neural-ui-core-context-menu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-context-menu.mjs","sources":["../../../../projects/ui-core/context-menu/neu-context-menu.component.ts","../../../../projects/ui-core/context-menu/neural-ui-core-context-menu.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ComponentRef,\n Directive,\n ElementRef,\n HostListener,\n Injector,\n OnDestroy,\n ViewContainerRef,\n ViewEncapsulation,\n computed,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { Overlay, OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\n\nexport interface NeuContextMenuItem {\n /** Key para identificar la acción / Key to identify the action */\n key: string;\n /** Texto visible / Visible text */\n label: string;\n /** Icono opcional (texto/emoji) / Optional icon (text/emoji) */\n icon?: string;\n /** Separador antes de este item / Separator before this item */\n separator?: boolean;\n /** Desactiva el item / Disables the item */\n disabled?: boolean;\n /** Variante de color / Color variant */\n variant?: 'default' | 'danger';\n}\n\nlet _seq = 0;\n\n/**\n * NeuralUI ContextMenu Overlay Component (internal)\n */\n@Component({\n selector: 'neu-context-menu-overlay',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'neu-context-menu',\n role: 'menu',\n tabindex: '-1',\n '(keydown.escape)': '_onEscape()',\n },\n template: `\n @for (item of _items(); track item.key) {\n @if (item.separator && !$first) {\n <hr class=\"neu-context-menu__separator\" role=\"separator\" />\n }\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"neu-context-menu__item\"\n [class.neu-context-menu__item--danger]=\"item.variant === 'danger'\"\n [class.neu-context-menu__item--disabled]=\"item.disabled\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-disabled]=\"item.disabled ?? false\"\n (click)=\"select(item)\"\n >\n @if (item.icon) {\n <span class=\"neu-context-menu__icon\" aria-hidden=\"true\">{{ item.icon }}</span>\n }\n {{ item.label }}\n </button>\n }\n `,\n styleUrl: './neu-context-menu.component.scss',\n})\nexport class NeuContextMenuOverlayComponent {\n readonly _items = signal<NeuContextMenuItem[]>([]);\n _selectFn: ((item: NeuContextMenuItem) => void) | null = null;\n _escapeFn: (() => void) | null = null;\n\n select(item: NeuContextMenuItem): void {\n if (!item.disabled) this._selectFn?.(item);\n }\n\n _onEscape(): void {\n this._escapeFn?.();\n }\n}\n\n/**\n * NeuralUI ContextMenu Directive\n *\n * Muestra un menú contextual al hacer clic derecho sobre el elemento host.\n *\n * Uso:\n * <div [neuContextMenu]=\"menuItems\" (menuItemClick)=\"onItem($event)\">\n * Clic derecho aquí\n * </div>\n */\n@Directive({\n selector: '[neuContextMenu]',\n exportAs: 'neuContextMenu',\n})\nexport class NeuContextMenuDirective implements OnDestroy {\n /** Ítems del menú / Menu items */\n readonly neuContextMenu = input<NeuContextMenuItem[]>([]);\n\n /** Desactiva el menú / Disables the menu */\n readonly neuContextMenuDisabled = input<boolean>(false);\n\n /** Emitido al seleccionar un ítem / Emitted when an item is selected */\n readonly menuItemClick = output<NeuContextMenuItem>();\n\n /** Emitido al abrir / Emitted on open */\n readonly menuOpened = output<void>();\n\n /** Emitido al cerrar / Emitted on close */\n readonly menuClosed = output<void>();\n\n private readonly _overlay = inject(Overlay);\n private readonly _el = inject(ElementRef<HTMLElement>);\n private readonly _injector = inject(Injector);\n private readonly _vcr = inject(ViewContainerRef);\n private _overlayRef: OverlayRef | null = null;\n private _compRef: ComponentRef<NeuContextMenuOverlayComponent> | null = null;\n\n @HostListener('contextmenu', ['$event'])\n onContextMenu(event: MouseEvent): void {\n event.preventDefault();\n if (this.neuContextMenuDisabled()) return;\n this._open(event.clientX, event.clientY);\n }\n\n private _open(x: number, y: number): void {\n this._close();\n this._overlayRef = this._overlay.create({\n hasBackdrop: true,\n backdropClass: 'neu-context-menu-backdrop',\n positionStrategy: this._overlay.position().global().left(`${x}px`).top(`${y}px`),\n scrollStrategy: this._overlay.scrollStrategies.close(),\n });\n\n const portal = new ComponentPortal(NeuContextMenuOverlayComponent, this._vcr, this._injector);\n this._compRef = this._overlayRef.attach(portal);\n this._compRef.instance._items.set(this.neuContextMenu());\n this._compRef.instance._selectFn = (item) => {\n this.menuItemClick.emit(item);\n this._close();\n };\n this._compRef.instance._escapeFn = () => this._close();\n\n this._overlayRef.backdropClick().subscribe(() => this._close());\n this.menuOpened.emit();\n }\n\n private _close(): void {\n if (this._overlayRef?.hasAttached()) {\n this._overlayRef.detach();\n this.menuClosed.emit();\n }\n this._overlayRef?.dispose();\n this._overlayRef = null;\n this._compRef = null;\n }\n\n ngOnDestroy(): void {\n this._close();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}