@aquera/nile-elements 1.9.4 → 1.9.6

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 (198) hide show
  1. package/README.md +13 -0
  2. package/dist/index-5fef1a0d.esm.js +1 -0
  3. package/dist/index-8f38fae3.cjs.js +2 -0
  4. package/dist/index-8f38fae3.cjs.js.map +1 -0
  5. package/dist/index.cjs.js +1 -1
  6. package/dist/index.esm.js +1 -1
  7. package/dist/index.js +1527 -804
  8. package/dist/nile-chip/nile-chip.css.cjs.js +1 -1
  9. package/dist/nile-chip/nile-chip.css.cjs.js.map +1 -1
  10. package/dist/nile-chip/nile-chip.css.esm.js +8 -1
  11. package/dist/nile-code-editor/nile-code-editor.cjs.js +1 -1
  12. package/dist/nile-code-editor/nile-code-editor.cjs.js.map +1 -1
  13. package/dist/nile-code-editor/nile-code-editor.esm.js +3 -3
  14. package/dist/nile-combobox/index.cjs.js +1 -1
  15. package/dist/nile-combobox/index.esm.js +1 -1
  16. package/dist/nile-combobox/nile-combobox.cjs.js +1 -1
  17. package/dist/nile-combobox/nile-combobox.esm.js +1 -1
  18. package/dist/nile-command-menu/index.cjs.js +2 -0
  19. package/dist/nile-command-menu/index.cjs.js.map +1 -0
  20. package/dist/nile-command-menu/index.esm.js +1 -0
  21. package/dist/nile-command-menu/nile-command-menu.cjs.js +2 -0
  22. package/dist/nile-command-menu/nile-command-menu.cjs.js.map +1 -0
  23. package/dist/nile-command-menu/nile-command-menu.css.cjs.js +2 -0
  24. package/dist/nile-command-menu/nile-command-menu.css.cjs.js.map +1 -0
  25. package/dist/nile-command-menu/nile-command-menu.css.esm.js +182 -0
  26. package/dist/nile-command-menu/nile-command-menu.esm.js +97 -0
  27. package/dist/nile-command-menu-group/index.cjs.js +2 -0
  28. package/dist/nile-command-menu-group/index.cjs.js.map +1 -0
  29. package/dist/nile-command-menu-group/index.esm.js +1 -0
  30. package/dist/nile-command-menu-group/nile-command-menu-group.cjs.js +2 -0
  31. package/dist/nile-command-menu-group/nile-command-menu-group.cjs.js.map +1 -0
  32. package/dist/nile-command-menu-group/nile-command-menu-group.css.cjs.js +2 -0
  33. package/dist/nile-command-menu-group/nile-command-menu-group.css.cjs.js.map +1 -0
  34. package/dist/nile-command-menu-group/nile-command-menu-group.css.esm.js +33 -0
  35. package/dist/nile-command-menu-group/nile-command-menu-group.esm.js +11 -0
  36. package/dist/nile-command-menu-item/index.cjs.js +2 -0
  37. package/dist/nile-command-menu-item/index.cjs.js.map +1 -0
  38. package/dist/nile-command-menu-item/index.esm.js +1 -0
  39. package/dist/nile-command-menu-item/nile-command-menu-item.cjs.js +2 -0
  40. package/dist/nile-command-menu-item/nile-command-menu-item.cjs.js.map +1 -0
  41. package/dist/nile-command-menu-item/nile-command-menu-item.css.cjs.js +2 -0
  42. package/dist/nile-command-menu-item/nile-command-menu-item.css.cjs.js.map +1 -0
  43. package/dist/nile-command-menu-item/nile-command-menu-item.css.esm.js +115 -0
  44. package/dist/nile-command-menu-item/nile-command-menu-item.esm.js +21 -0
  45. package/dist/nile-detail/index.cjs.js +1 -1
  46. package/dist/nile-detail/index.esm.js +1 -1
  47. package/dist/nile-detail/nile-detail.cjs.js +1 -1
  48. package/dist/nile-detail/nile-detail.esm.js +1 -1
  49. package/dist/nile-dialog/nile-dialog.cjs.js +1 -1
  50. package/dist/nile-dialog/nile-dialog.cjs.js.map +1 -1
  51. package/dist/nile-dialog/nile-dialog.esm.js +1 -1
  52. package/dist/nile-dot-stepper/index.cjs.js +2 -0
  53. package/dist/nile-dot-stepper/index.cjs.js.map +1 -0
  54. package/dist/nile-dot-stepper/index.esm.js +1 -0
  55. package/dist/nile-dot-stepper/nile-dot-stepper.cjs.js +2 -0
  56. package/dist/nile-dot-stepper/nile-dot-stepper.cjs.js.map +1 -0
  57. package/dist/nile-dot-stepper/nile-dot-stepper.css.cjs.js +2 -0
  58. package/dist/nile-dot-stepper/nile-dot-stepper.css.cjs.js.map +1 -0
  59. package/dist/nile-dot-stepper/nile-dot-stepper.css.esm.js +77 -0
  60. package/dist/nile-dot-stepper/nile-dot-stepper.esm.js +24 -0
  61. package/dist/nile-hero/nile-hero.cjs.js +1 -1
  62. package/dist/nile-hero/nile-hero.cjs.js.map +1 -1
  63. package/dist/nile-hero/nile-hero.css.cjs.js +1 -1
  64. package/dist/nile-hero/nile-hero.css.cjs.js.map +1 -1
  65. package/dist/nile-hero/nile-hero.css.esm.js +14 -14
  66. package/dist/nile-hero/nile-hero.esm.js +1 -1
  67. package/dist/nile-hero-header/nile-hero-header.cjs.js +1 -1
  68. package/dist/nile-hero-header/nile-hero-header.cjs.js.map +1 -1
  69. package/dist/nile-hero-header/nile-hero-header.css.cjs.js +1 -1
  70. package/dist/nile-hero-header/nile-hero-header.css.cjs.js.map +1 -1
  71. package/dist/nile-hero-header/nile-hero-header.css.esm.js +11 -11
  72. package/dist/nile-hero-header/nile-hero-header.esm.js +3 -3
  73. package/dist/nile-rich-text-editor/index.cjs.js +1 -1
  74. package/dist/nile-rich-text-editor/index.esm.js +1 -1
  75. package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js +1 -1
  76. package/dist/nile-rich-text-editor/nile-rich-text-editor.cjs.js.map +1 -1
  77. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js +1 -1
  78. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.cjs.js.map +1 -1
  79. package/dist/nile-rich-text-editor/nile-rich-text-editor.css.esm.js +70 -0
  80. package/dist/nile-rich-text-editor/nile-rich-text-editor.esm.js +1 -1
  81. package/dist/nile-rich-text-editor/nile-rte-image.cjs.js +3 -0
  82. package/dist/nile-rich-text-editor/nile-rte-image.cjs.js.map +1 -0
  83. package/dist/nile-rich-text-editor/nile-rte-image.esm.js +96 -0
  84. package/dist/nile-section-message/nile-section-message.css.cjs.js +1 -1
  85. package/dist/nile-section-message/nile-section-message.css.cjs.js.map +1 -1
  86. package/dist/nile-section-message/nile-section-message.css.esm.js +7 -8
  87. package/dist/src/index.d.ts +4 -0
  88. package/dist/src/index.js +4 -0
  89. package/dist/src/index.js.map +1 -1
  90. package/dist/src/nile-chip/nile-chip.css.js +8 -1
  91. package/dist/src/nile-chip/nile-chip.css.js.map +1 -1
  92. package/dist/src/nile-code-editor/nile-code-editor.js +3 -3
  93. package/dist/src/nile-code-editor/nile-code-editor.js.map +1 -1
  94. package/dist/src/nile-command-menu/index.d.ts +1 -0
  95. package/dist/src/nile-command-menu/index.js +2 -0
  96. package/dist/src/nile-command-menu/index.js.map +1 -0
  97. package/dist/src/nile-command-menu/nile-command-menu.css.d.ts +12 -0
  98. package/dist/src/nile-command-menu/nile-command-menu.css.js +194 -0
  99. package/dist/src/nile-command-menu/nile-command-menu.css.js.map +1 -0
  100. package/dist/src/nile-command-menu/nile-command-menu.d.ts +137 -0
  101. package/dist/src/nile-command-menu/nile-command-menu.js +557 -0
  102. package/dist/src/nile-command-menu/nile-command-menu.js.map +1 -0
  103. package/dist/src/nile-command-menu/nile-command-menu.test.d.ts +3 -0
  104. package/dist/src/nile-command-menu/nile-command-menu.test.js +268 -0
  105. package/dist/src/nile-command-menu/nile-command-menu.test.js.map +1 -0
  106. package/dist/src/nile-command-menu-group/index.d.ts +1 -0
  107. package/dist/src/nile-command-menu-group/index.js +2 -0
  108. package/dist/src/nile-command-menu-group/index.js.map +1 -0
  109. package/dist/src/nile-command-menu-group/nile-command-menu-group.css.d.ts +12 -0
  110. package/dist/src/nile-command-menu-group/nile-command-menu-group.css.js +45 -0
  111. package/dist/src/nile-command-menu-group/nile-command-menu-group.css.js.map +1 -0
  112. package/dist/src/nile-command-menu-group/nile-command-menu-group.d.ts +38 -0
  113. package/dist/src/nile-command-menu-group/nile-command-menu-group.js +68 -0
  114. package/dist/src/nile-command-menu-group/nile-command-menu-group.js.map +1 -0
  115. package/dist/src/nile-command-menu-group/nile-command-menu-group.test.d.ts +2 -0
  116. package/dist/src/nile-command-menu-group/nile-command-menu-group.test.js +22 -0
  117. package/dist/src/nile-command-menu-group/nile-command-menu-group.test.js.map +1 -0
  118. package/dist/src/nile-command-menu-item/index.d.ts +1 -0
  119. package/dist/src/nile-command-menu-item/index.js +2 -0
  120. package/dist/src/nile-command-menu-item/index.js.map +1 -0
  121. package/dist/src/nile-command-menu-item/nile-command-menu-item.css.d.ts +12 -0
  122. package/dist/src/nile-command-menu-item/nile-command-menu-item.css.js +127 -0
  123. package/dist/src/nile-command-menu-item/nile-command-menu-item.css.js.map +1 -0
  124. package/dist/src/nile-command-menu-item/nile-command-menu-item.d.ts +73 -0
  125. package/dist/src/nile-command-menu-item/nile-command-menu-item.js +174 -0
  126. package/dist/src/nile-command-menu-item/nile-command-menu-item.js.map +1 -0
  127. package/dist/src/nile-command-menu-item/nile-command-menu-item.test.d.ts +1 -0
  128. package/dist/src/nile-command-menu-item/nile-command-menu-item.test.js +35 -0
  129. package/dist/src/nile-command-menu-item/nile-command-menu-item.test.js.map +1 -0
  130. package/dist/src/nile-dialog/nile-dialog.js +1 -1
  131. package/dist/src/nile-dialog/nile-dialog.js.map +1 -1
  132. package/dist/src/nile-dot-stepper/index.d.ts +1 -0
  133. package/dist/src/nile-dot-stepper/index.js +2 -0
  134. package/dist/src/nile-dot-stepper/index.js.map +1 -0
  135. package/dist/src/nile-dot-stepper/nile-dot-stepper.css.d.ts +12 -0
  136. package/dist/src/nile-dot-stepper/nile-dot-stepper.css.js +89 -0
  137. package/dist/src/nile-dot-stepper/nile-dot-stepper.css.js.map +1 -0
  138. package/dist/src/nile-dot-stepper/nile-dot-stepper.d.ts +48 -0
  139. package/dist/src/nile-dot-stepper/nile-dot-stepper.js +153 -0
  140. package/dist/src/nile-dot-stepper/nile-dot-stepper.js.map +1 -0
  141. package/dist/src/nile-dot-stepper/nile-dot-stepper.test.d.ts +1 -0
  142. package/dist/src/nile-dot-stepper/nile-dot-stepper.test.js +319 -0
  143. package/dist/src/nile-dot-stepper/nile-dot-stepper.test.js.map +1 -0
  144. package/dist/src/nile-hero/nile-hero.css.js +12 -12
  145. package/dist/src/nile-hero/nile-hero.css.js.map +1 -1
  146. package/dist/src/nile-hero/nile-hero.js +1 -1
  147. package/dist/src/nile-hero/nile-hero.js.map +1 -1
  148. package/dist/src/nile-hero-header/nile-hero-header.css.js +9 -9
  149. package/dist/src/nile-hero-header/nile-hero-header.css.js.map +1 -1
  150. package/dist/src/nile-hero-header/nile-hero-header.js +1 -1
  151. package/dist/src/nile-hero-header/nile-hero-header.js.map +1 -1
  152. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js +70 -0
  153. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.css.js.map +1 -1
  154. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.d.ts +3 -0
  155. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js +81 -3
  156. package/dist/src/nile-rich-text-editor/nile-rich-text-editor.js.map +1 -1
  157. package/dist/src/nile-rich-text-editor/nile-rte-image.d.ts +87 -0
  158. package/dist/src/nile-rich-text-editor/nile-rte-image.js +1073 -0
  159. package/dist/src/nile-rich-text-editor/nile-rte-image.js.map +1 -0
  160. package/dist/src/nile-section-message/nile-section-message.css.js +7 -8
  161. package/dist/src/nile-section-message/nile-section-message.css.js.map +1 -1
  162. package/dist/src/version.js +1 -1
  163. package/dist/src/version.js.map +1 -1
  164. package/dist/tsconfig.tsbuildinfo +1 -1
  165. package/package.json +2 -1
  166. package/src/index.ts +4 -0
  167. package/src/nile-chip/nile-chip.css.ts +8 -1
  168. package/src/nile-code-editor/nile-code-editor.ts +3 -3
  169. package/src/nile-command-menu/index.ts +1 -0
  170. package/src/nile-command-menu/nile-command-menu.css.ts +196 -0
  171. package/src/nile-command-menu/nile-command-menu.test.ts +289 -0
  172. package/src/nile-command-menu/nile-command-menu.ts +601 -0
  173. package/src/nile-command-menu-group/index.ts +1 -0
  174. package/src/nile-command-menu-group/nile-command-menu-group.css.ts +47 -0
  175. package/src/nile-command-menu-group/nile-command-menu-group.test.ts +23 -0
  176. package/src/nile-command-menu-group/nile-command-menu-group.ts +72 -0
  177. package/src/nile-command-menu-item/index.ts +1 -0
  178. package/src/nile-command-menu-item/nile-command-menu-item.css.ts +129 -0
  179. package/src/nile-command-menu-item/nile-command-menu-item.test.ts +36 -0
  180. package/src/nile-command-menu-item/nile-command-menu-item.ts +172 -0
  181. package/src/nile-dialog/nile-dialog.ts +1 -1
  182. package/src/nile-dot-stepper/index.ts +1 -0
  183. package/src/nile-dot-stepper/nile-dot-stepper.css.ts +90 -0
  184. package/src/nile-dot-stepper/nile-dot-stepper.test.ts +493 -0
  185. package/src/nile-dot-stepper/nile-dot-stepper.ts +159 -0
  186. package/src/nile-hero/nile-hero.css.ts +12 -12
  187. package/src/nile-hero/nile-hero.ts +1 -1
  188. package/src/nile-hero-header/nile-hero-header.css.ts +9 -9
  189. package/src/nile-hero-header/nile-hero-header.ts +1 -1
  190. package/src/nile-rich-text-editor/nile-rich-text-editor.css.ts +70 -0
  191. package/src/nile-rich-text-editor/nile-rich-text-editor.ts +89 -3
  192. package/src/nile-rich-text-editor/nile-rte-image.ts +1132 -0
  193. package/src/nile-section-message/nile-section-message.css.ts +7 -8
  194. package/stories/dot-stepper.stories.ts +67 -0
  195. package/vscode-html-custom-data.json +220 -1
  196. package/dist/index-c0b5232c.cjs.js +0 -2
  197. package/dist/index-c0b5232c.cjs.js.map +0 -1
  198. package/dist/index-e43a18eb.esm.js +0 -1
@@ -0,0 +1,557 @@
1
+ /**
2
+ * Copyright Aquera Inc 2023
3
+ *
4
+ * This source code is licensed under the BSD-3-Clause license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { __decorate } from "tslib";
8
+ import { html, nothing } from 'lit';
9
+ import { customElement, property, query, state } from 'lit/decorators.js';
10
+ import { classMap } from 'lit/directives/class-map.js';
11
+ import { animateTo, stopAnimations } from '../internal/animate';
12
+ import { getAnimation, setDefaultAnimation } from '../utilities/animation-registry';
13
+ import { HasSlotController } from '../internal/slot';
14
+ import { lockBodyScrolling, unlockBodyScrolling } from '../internal/scroll';
15
+ import { waitForEvent } from '../internal/event';
16
+ import { watch } from '../internal/watch';
17
+ import Modal from '../internal/modal';
18
+ import NileElement from '../internal/nile-element';
19
+ import { styles } from './nile-command-menu.css';
20
+ import '../nile-tag/nile-tag';
21
+ let commandMenuItemId = 0;
22
+ function scopeFromValue(entry) {
23
+ if (typeof entry === 'string') {
24
+ return { label: entry, value: entry.toLowerCase() };
25
+ }
26
+ return { label: entry.label, value: entry.value ?? entry.label.toLowerCase() };
27
+ }
28
+ /** Normalises the `scopes` attribute (comma-separated string or JSON array) into scope objects. */
29
+ const scopesConverter = {
30
+ fromAttribute(value) {
31
+ if (!value) {
32
+ return [];
33
+ }
34
+ const trimmed = value.trim();
35
+ if (trimmed.startsWith('[')) {
36
+ try {
37
+ const parsed = JSON.parse(trimmed);
38
+ return (Array.isArray(parsed) ? parsed : []).map(scopeFromValue);
39
+ }
40
+ catch {
41
+ // fall through to comma-separated parsing
42
+ }
43
+ }
44
+ return trimmed
45
+ .split(',')
46
+ .map(part => part.trim())
47
+ .filter(Boolean)
48
+ .map(scopeFromValue);
49
+ },
50
+ toAttribute(value) {
51
+ return (value ?? []).map(scope => scope.label).join(', ');
52
+ },
53
+ };
54
+ /**
55
+ * A keyboard-driven command palette for fast, page-wide search and action execution.
56
+ *
57
+ * @tag nile-command-menu
58
+ *
59
+ * @summary A modal command menu (command palette) with built-in search, grouping and keyboard navigation.
60
+ * @status stable
61
+ * @since 2.0
62
+ *
63
+ * @dependency nile-glyph
64
+ * @dependency nile-tag
65
+ *
66
+ * @slot - The command content: `nile-command-menu-group` and/or `nile-command-menu-item` elements.
67
+ * @slot empty - Custom content shown when no items match the current query.
68
+ * @slot footer - Optional footer content. When empty, a built-in keyboard-hint row is shown (unless `nofooterhints`).
69
+ *
70
+ * @event nile-show - Emitted when the menu opens.
71
+ * @event nile-after-show - Emitted after the menu opens and the animation completes.
72
+ * @event nile-hide - Emitted when the menu starts to close.
73
+ * @event nile-after-hide - Emitted after the menu closes and the animation completes.
74
+ * @event nile-request-close - Emitted when the user attempts to close the menu (overlay click / Escape). Cancelable.
75
+ * @event nile-search - Emitted when the search value changes. `detail: { value }`.
76
+ * @event nile-select - Emitted when an item is selected. `detail: { value, item }`.
77
+ * @event nile-scope-remove - Emitted when a scope tag is removed. `detail: { scope, scopes }`.
78
+ *
79
+ * @csspart base - The component's outer wrapper.
80
+ * @csspart overlay - The overlay behind the panel.
81
+ * @csspart panel - The command panel.
82
+ * @csspart header - The search header.
83
+ * @csspart input - The search input.
84
+ * @csspart scopes - The "Searching for" scopes row.
85
+ * @csspart scope-tag - Each scope tag in the scopes row.
86
+ * @csspart list - The scrollable results list.
87
+ * @csspart empty - The empty state shown when nothing matches.
88
+ * @csspart footer - The footer.
89
+ * @csspart hints - The built-in keyboard-hint row inside the footer.
90
+ *
91
+ * @cssproperty --width - The maximum width of the panel.
92
+ * @cssproperty --max-height - The maximum height of the panel.
93
+ */
94
+ let NileCommandMenu = class NileCommandMenu extends NileElement {
95
+ constructor() {
96
+ super(...arguments);
97
+ this.hasSlotController = new HasSlotController(this, 'footer');
98
+ /** Indicates whether the menu is open. Toggle this attribute, or use `show()` / `hide()`. */
99
+ this.open = false;
100
+ /** Placeholder text shown in the search input. */
101
+ this.placeholder = 'Search commands...';
102
+ /** Accessible label for the dialog and the search input. */
103
+ this.label = 'Command menu';
104
+ /** Message shown when no items match the current query. Ignored when the `empty` slot is used. */
105
+ this.noResultsMessage = 'No results found';
106
+ /** The current search value. */
107
+ this.value = '';
108
+ /**
109
+ * When set, the menu does not filter items itself; instead it emits `nile-search` so the host can
110
+ * manage results. Useful for async/server-side search.
111
+ */
112
+ this.customSearch = false;
113
+ /** Keeps the menu open after an item is selected instead of closing it. */
114
+ this.keepOpenOnSelect = false;
115
+ /** Prevents the menu from closing when the overlay is clicked. */
116
+ this.preventOverlayClose = false;
117
+ /** Hides the built-in keyboard-hint footer (navigate / select / close). The `footer` slot always overrides it. */
118
+ this.noFooterHints = false;
119
+ /**
120
+ * Active search scopes shown as removable tags in the "Searching for" row. Items are filtered so that
121
+ * only those with no `scope` or whose `scope` matches an active scope are shown. Set via the `scopes`
122
+ * attribute (comma-separated labels or a JSON array) or the property (array of `{ label, value }`).
123
+ */
124
+ this.scopes = [];
125
+ /** Label shown before the scope tags. */
126
+ this.scopesLabel = 'Searching for';
127
+ /** True when the current query matches no items. */
128
+ this.hasResults = true;
129
+ }
130
+ connectedCallback() {
131
+ super.connectedCallback();
132
+ this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
133
+ this.modal = new Modal(this);
134
+ }
135
+ firstUpdated() {
136
+ this.command.hidden = !this.open;
137
+ if (this.open) {
138
+ this.addOpenListeners();
139
+ this.modal.activate();
140
+ lockBodyScrolling(this);
141
+ }
142
+ }
143
+ disconnectedCallback() {
144
+ super.disconnectedCallback();
145
+ unlockBodyScrolling(this);
146
+ }
147
+ /** Gets all command items in the menu (across groups), in document order. */
148
+ getAllItems() {
149
+ return [...this.querySelectorAll('nile-command-menu-item')];
150
+ }
151
+ /** Gets the items that are currently visible (matching the query) and not disabled. */
152
+ getVisibleItems() {
153
+ return this.getAllItems().filter(item => !item.hidden && !item.disabled);
154
+ }
155
+ getActiveItem() {
156
+ return this.getVisibleItems().find(item => item.active);
157
+ }
158
+ setActiveItem(item) {
159
+ this.getAllItems().forEach(i => {
160
+ i.active = i === item;
161
+ });
162
+ if (item) {
163
+ if (!item.id) {
164
+ item.id = `nile-command-menu-item-${++commandMenuItemId}`;
165
+ }
166
+ this.input?.setAttribute('aria-activedescendant', item.id);
167
+ item.scrollIntoView({ block: 'nearest' });
168
+ }
169
+ else {
170
+ this.input?.removeAttribute('aria-activedescendant');
171
+ }
172
+ }
173
+ /** Applies the current query to the items, hiding non-matching items and empty groups. */
174
+ filterItems() {
175
+ const items = this.getAllItems();
176
+ if (this.customSearch) {
177
+ // The host owns visibility; just refresh the empty state and active item.
178
+ this.hasResults = this.getVisibleItems().length > 0;
179
+ this.updateGroupVisibility();
180
+ this.ensureActiveItem();
181
+ return;
182
+ }
183
+ const query = this.value.trim().toLowerCase();
184
+ const activeScopes = this.scopes.map(scope => scope.value);
185
+ items.forEach(item => {
186
+ const matchesQuery = query.length === 0 || item.getFilterText().includes(query);
187
+ const matchesScope = activeScopes.length === 0 || !item.scope || activeScopes.includes(item.scope);
188
+ item.hidden = !(matchesQuery && matchesScope);
189
+ });
190
+ this.updateGroupVisibility();
191
+ this.hasResults = this.getVisibleItems().length > 0;
192
+ this.ensureActiveItem();
193
+ }
194
+ /** Hides groups that have no visible items. */
195
+ updateGroupVisibility() {
196
+ const groups = [...this.querySelectorAll('nile-command-menu-group')];
197
+ groups.forEach(group => {
198
+ const hasVisibleItem = [
199
+ ...group.querySelectorAll('nile-command-menu-item'),
200
+ ].some(item => !item.hidden);
201
+ group.hidden = !hasVisibleItem;
202
+ });
203
+ }
204
+ /** Ensures exactly one visible item is active, defaulting to the first. */
205
+ ensureActiveItem() {
206
+ const visible = this.getVisibleItems();
207
+ const current = this.getActiveItem();
208
+ if (visible.length === 0) {
209
+ this.setActiveItem(undefined);
210
+ return;
211
+ }
212
+ if (!current || !visible.includes(current)) {
213
+ this.setActiveItem(visible[0]);
214
+ }
215
+ }
216
+ handleInput(event) {
217
+ this.value = event.target.value;
218
+ this.emit('nile-search', { value: this.value });
219
+ this.filterItems();
220
+ }
221
+ handleScopesChange() {
222
+ this.filterItems();
223
+ }
224
+ handleScopeRemove(scope) {
225
+ this.scopes = this.scopes.filter(s => s.value !== scope.value);
226
+ this.emit('nile-scope-remove', { scope, scopes: this.scopes });
227
+ this.filterItems();
228
+ }
229
+ handleSlotChange() {
230
+ this.filterItems();
231
+ }
232
+ handlePanelKeyDown(event) {
233
+ const visible = this.getVisibleItems();
234
+ if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {
235
+ if (visible.length === 0) {
236
+ return;
237
+ }
238
+ event.preventDefault();
239
+ const current = this.getActiveItem();
240
+ let index = current ? visible.indexOf(current) : -1;
241
+ if (event.key === 'ArrowDown')
242
+ index++;
243
+ else if (event.key === 'ArrowUp')
244
+ index--;
245
+ else if (event.key === 'Home')
246
+ index = 0;
247
+ else if (event.key === 'End')
248
+ index = visible.length - 1;
249
+ if (index < 0)
250
+ index = visible.length - 1;
251
+ if (index > visible.length - 1)
252
+ index = 0;
253
+ this.setActiveItem(visible[index]);
254
+ return;
255
+ }
256
+ if (event.key === 'Enter') {
257
+ const current = this.getActiveItem();
258
+ if (current) {
259
+ event.preventDefault();
260
+ this.selectItem(current);
261
+ }
262
+ }
263
+ }
264
+ handleListClick(event) {
265
+ const item = event.target.closest('nile-command-menu-item');
266
+ if (item && !item.disabled) {
267
+ this.selectItem(item);
268
+ }
269
+ }
270
+ selectItem(item) {
271
+ this.emit('nile-select', { value: item.value, item });
272
+ if (!this.keepOpenOnSelect) {
273
+ this.hide();
274
+ }
275
+ }
276
+ requestClose(source) {
277
+ const requestClose = this.emit('nile-request-close', { source }, undefined, undefined, true);
278
+ if (requestClose.defaultPrevented) {
279
+ return;
280
+ }
281
+ if (source === 'overlay' && this.preventOverlayClose) {
282
+ return;
283
+ }
284
+ this.hide();
285
+ }
286
+ addOpenListeners() {
287
+ document.addEventListener('keydown', this.handleDocumentKeyDown);
288
+ }
289
+ removeOpenListeners() {
290
+ document.removeEventListener('keydown', this.handleDocumentKeyDown);
291
+ }
292
+ handleDocumentKeyDown(event) {
293
+ if (this.open && event.key === 'Escape') {
294
+ event.stopPropagation();
295
+ this.requestClose('keyboard');
296
+ }
297
+ }
298
+ async handleOpenChange() {
299
+ if (this.open) {
300
+ this.emit('nile-show');
301
+ this.addOpenListeners();
302
+ this.originalTrigger = document.activeElement;
303
+ this.modal.activate();
304
+ lockBodyScrolling(this);
305
+ await stopAnimations(this.command);
306
+ this.command.hidden = false;
307
+ // Reset query and selection each time the menu opens.
308
+ this.value = '';
309
+ this.filterItems();
310
+ requestAnimationFrame(() => {
311
+ this.input?.focus({ preventScroll: true });
312
+ });
313
+ const panelAnimation = getAnimation(this, 'command.show', { dir: 'ltr' });
314
+ const overlayAnimation = getAnimation(this, 'command.overlay.show', { dir: 'ltr' });
315
+ await Promise.all([
316
+ animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options),
317
+ animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options),
318
+ ]);
319
+ this.emit('nile-after-show');
320
+ }
321
+ else {
322
+ this.emit('nile-hide');
323
+ this.removeOpenListeners();
324
+ this.modal.deactivate();
325
+ await stopAnimations(this.command);
326
+ const panelAnimation = getAnimation(this, 'command.hide', { dir: 'ltr' });
327
+ const overlayAnimation = getAnimation(this, 'command.overlay.hide', { dir: 'ltr' });
328
+ await Promise.all([
329
+ animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options),
330
+ animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options),
331
+ ]);
332
+ this.command.hidden = true;
333
+ unlockBodyScrolling(this);
334
+ const trigger = this.originalTrigger;
335
+ if (typeof trigger?.focus === 'function') {
336
+ setTimeout(() => trigger.focus());
337
+ }
338
+ this.emit('nile-after-hide');
339
+ }
340
+ }
341
+ /** Renders the "Searching for" scopes row when scopes are active. */
342
+ renderScopes() {
343
+ if (this.scopes.length === 0) {
344
+ return nothing;
345
+ }
346
+ return html `
347
+ <div part="scopes" class="command__scopes">
348
+ <span class="command__scopes-label">${this.scopesLabel}</span>
349
+ <div class="command__scopes-tags">
350
+ ${this.scopes.map(scope => html `
351
+ <nile-tag
352
+ part="scope-tag"
353
+ exportparts="base:scope-tag__base"
354
+ size="medium"
355
+ variant="normal"
356
+ pill
357
+ removable
358
+ .value=${scope.value}
359
+ @nile-remove=${() => this.handleScopeRemove(scope)}
360
+ >
361
+ ${scope.label}
362
+ </nile-tag>
363
+ `)}
364
+ </div>
365
+ </div>
366
+ `;
367
+ }
368
+ /** Renders the built-in keyboard-hint footer (used as the `footer` slot's fallback content). */
369
+ renderHints() {
370
+ return html `
371
+ <div part="hints" class="command__hints">
372
+ <span class="command__hint"><kbd>↑</kbd><kbd>↓</kbd> to navigate</span>
373
+ <span class="command__hint"><kbd>↵</kbd> to select</span>
374
+ <span class="command__hint"><kbd>esc</kbd> to close</span>
375
+ </div>
376
+ `;
377
+ }
378
+ /** Shows the command menu. */
379
+ async show() {
380
+ if (this.open) {
381
+ return undefined;
382
+ }
383
+ this.open = true;
384
+ return waitForEvent(this, 'nile-after-show');
385
+ }
386
+ /** Hides the command menu. */
387
+ async hide() {
388
+ if (!this.open) {
389
+ return undefined;
390
+ }
391
+ this.open = false;
392
+ return waitForEvent(this, 'nile-after-hide');
393
+ }
394
+ render() {
395
+ return html `
396
+ <div
397
+ part="base"
398
+ class=${classMap({
399
+ command: true,
400
+ 'command--open': this.open,
401
+ 'command--has-footer': this.hasSlotController.test('footer') || !this.noFooterHints,
402
+ })}
403
+ >
404
+ <div
405
+ part="overlay"
406
+ class="command__overlay"
407
+ tabindex="-1"
408
+ @click=${() => this.requestClose('overlay')}
409
+ ></div>
410
+
411
+ <div
412
+ part="panel"
413
+ class="command__panel"
414
+ role="dialog"
415
+ aria-modal="true"
416
+ aria-label=${this.label}
417
+ aria-hidden=${this.open ? 'false' : 'true'}
418
+ @keydown=${this.handlePanelKeyDown}
419
+ >
420
+ <div part="header" class="command__header">
421
+ <span class="command__search-icon" aria-hidden="true">
422
+ <nile-glyph name="search" size="20" method="stroke"></nile-glyph>
423
+ </span>
424
+ <input
425
+ part="input"
426
+ class="command__input"
427
+ type="text"
428
+ role="combobox"
429
+ aria-expanded="true"
430
+ aria-controls="command-list"
431
+ aria-label=${this.label}
432
+ autocomplete="off"
433
+ autocorrect="off"
434
+ autocapitalize="off"
435
+ spellcheck="false"
436
+ .value=${this.value}
437
+ placeholder=${this.placeholder}
438
+ @input=${this.handleInput}
439
+ />
440
+ </div>
441
+
442
+ ${this.renderScopes()}
443
+
444
+ <div
445
+ part="list"
446
+ id="command-list"
447
+ class="command__list"
448
+ role="listbox"
449
+ aria-label=${this.label}
450
+ @click=${this.handleListClick}
451
+ >
452
+ <slot @slotchange=${this.handleSlotChange}></slot>
453
+
454
+ <div
455
+ part="empty"
456
+ class=${classMap({
457
+ command__empty: true,
458
+ 'command__empty--visible': !this.hasResults,
459
+ })}
460
+ >
461
+ <slot name="empty">${!this.hasResults ? this.noResultsMessage : nothing}</slot>
462
+ </div>
463
+ </div>
464
+
465
+ <footer part="footer" class="command__footer">
466
+ <slot name="footer">
467
+ ${this.noFooterHints ? nothing : this.renderHints()}
468
+ </slot>
469
+ </footer>
470
+ </div>
471
+ </div>
472
+ `;
473
+ }
474
+ };
475
+ NileCommandMenu.styles = styles;
476
+ __decorate([
477
+ query('.command')
478
+ ], NileCommandMenu.prototype, "command", void 0);
479
+ __decorate([
480
+ query('.command__panel')
481
+ ], NileCommandMenu.prototype, "panel", void 0);
482
+ __decorate([
483
+ query('.command__overlay')
484
+ ], NileCommandMenu.prototype, "overlay", void 0);
485
+ __decorate([
486
+ query('.command__input')
487
+ ], NileCommandMenu.prototype, "input", void 0);
488
+ __decorate([
489
+ property({ type: Boolean, reflect: true })
490
+ ], NileCommandMenu.prototype, "open", void 0);
491
+ __decorate([
492
+ property()
493
+ ], NileCommandMenu.prototype, "placeholder", void 0);
494
+ __decorate([
495
+ property()
496
+ ], NileCommandMenu.prototype, "label", void 0);
497
+ __decorate([
498
+ property({ attribute: true })
499
+ ], NileCommandMenu.prototype, "noResultsMessage", void 0);
500
+ __decorate([
501
+ property()
502
+ ], NileCommandMenu.prototype, "value", void 0);
503
+ __decorate([
504
+ property({ type: Boolean, attribute: true })
505
+ ], NileCommandMenu.prototype, "customSearch", void 0);
506
+ __decorate([
507
+ property({ type: Boolean, attribute: true })
508
+ ], NileCommandMenu.prototype, "keepOpenOnSelect", void 0);
509
+ __decorate([
510
+ property({ type: Boolean, attribute: true })
511
+ ], NileCommandMenu.prototype, "preventOverlayClose", void 0);
512
+ __decorate([
513
+ property({ type: Boolean, attribute: true })
514
+ ], NileCommandMenu.prototype, "noFooterHints", void 0);
515
+ __decorate([
516
+ property({ converter: scopesConverter })
517
+ ], NileCommandMenu.prototype, "scopes", void 0);
518
+ __decorate([
519
+ property({ attribute: true })
520
+ ], NileCommandMenu.prototype, "scopesLabel", void 0);
521
+ __decorate([
522
+ state()
523
+ ], NileCommandMenu.prototype, "hasResults", void 0);
524
+ __decorate([
525
+ watch('scopes', { waitUntilFirstUpdate: true })
526
+ ], NileCommandMenu.prototype, "handleScopesChange", null);
527
+ __decorate([
528
+ watch('open', { waitUntilFirstUpdate: true })
529
+ ], NileCommandMenu.prototype, "handleOpenChange", null);
530
+ NileCommandMenu = __decorate([
531
+ customElement('nile-command-menu')
532
+ ], NileCommandMenu);
533
+ export { NileCommandMenu };
534
+ setDefaultAnimation('command.show', {
535
+ keyframes: [
536
+ { opacity: 0, scale: 0.95 },
537
+ { opacity: 1, scale: 1 },
538
+ ],
539
+ options: { duration: 200, easing: 'ease' },
540
+ });
541
+ setDefaultAnimation('command.hide', {
542
+ keyframes: [
543
+ { opacity: 1, scale: 1 },
544
+ { opacity: 0, scale: 0.95 },
545
+ ],
546
+ options: { duration: 200, easing: 'ease' },
547
+ });
548
+ setDefaultAnimation('command.overlay.show', {
549
+ keyframes: [{ opacity: 0 }, { opacity: 1 }],
550
+ options: { duration: 200 },
551
+ });
552
+ setDefaultAnimation('command.overlay.hide', {
553
+ keyframes: [{ opacity: 1 }, { opacity: 0 }],
554
+ options: { duration: 200 },
555
+ });
556
+ export default NileCommandMenu;
557
+ //# sourceMappingURL=nile-command-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nile-command-menu.js","sourceRoot":"","sources":["../../../src/nile-command-menu/nile-command-menu.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright Aquera Inc 2023\n *\n * This source code is licensed under the BSD-3-Clause license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { html, nothing } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { animateTo, stopAnimations } from '../internal/animate';\nimport { getAnimation, setDefaultAnimation } from '../utilities/animation-registry';\nimport { HasSlotController } from '../internal/slot';\nimport { lockBodyScrolling, unlockBodyScrolling } from '../internal/scroll';\nimport { waitForEvent } from '../internal/event';\nimport { watch } from '../internal/watch';\nimport Modal from '../internal/modal';\nimport NileElement from '../internal/nile-element';\nimport { styles } from './nile-command-menu.css';\nimport '../nile-tag/nile-tag';\nimport type { CSSResultGroup } from 'lit';\nimport type { NileCommandMenuItem } from '../nile-command-menu-item/nile-command-menu-item';\nimport type { NileCommandMenuGroup } from '../nile-command-menu-group/nile-command-menu-group';\n\nlet commandMenuItemId = 0;\n\n/** A removable search scope shown in the \"Searching for\" row. */\nexport interface CommandMenuScope {\n label: string;\n value: string;\n}\n\nfunction scopeFromValue(entry: CommandMenuScope | string): CommandMenuScope {\n if (typeof entry === 'string') {\n return { label: entry, value: entry.toLowerCase() };\n }\n return { label: entry.label, value: entry.value ?? entry.label.toLowerCase() };\n}\n\n/** Normalises the `scopes` attribute (comma-separated string or JSON array) into scope objects. */\nconst scopesConverter = {\n fromAttribute(value: string | null): CommandMenuScope[] {\n if (!value) {\n return [];\n }\n const trimmed = value.trim();\n if (trimmed.startsWith('[')) {\n try {\n const parsed = JSON.parse(trimmed);\n return (Array.isArray(parsed) ? parsed : []).map(scopeFromValue);\n } catch {\n // fall through to comma-separated parsing\n }\n }\n return trimmed\n .split(',')\n .map(part => part.trim())\n .filter(Boolean)\n .map(scopeFromValue);\n },\n toAttribute(value: CommandMenuScope[]): string {\n return (value ?? []).map(scope => scope.label).join(', ');\n },\n};\n\n/**\n * A keyboard-driven command palette for fast, page-wide search and action execution.\n *\n * @tag nile-command-menu\n *\n * @summary A modal command menu (command palette) with built-in search, grouping and keyboard navigation.\n * @status stable\n * @since 2.0\n *\n * @dependency nile-glyph\n * @dependency nile-tag\n *\n * @slot - The command content: `nile-command-menu-group` and/or `nile-command-menu-item` elements.\n * @slot empty - Custom content shown when no items match the current query.\n * @slot footer - Optional footer content. When empty, a built-in keyboard-hint row is shown (unless `nofooterhints`).\n *\n * @event nile-show - Emitted when the menu opens.\n * @event nile-after-show - Emitted after the menu opens and the animation completes.\n * @event nile-hide - Emitted when the menu starts to close.\n * @event nile-after-hide - Emitted after the menu closes and the animation completes.\n * @event nile-request-close - Emitted when the user attempts to close the menu (overlay click / Escape). Cancelable.\n * @event nile-search - Emitted when the search value changes. `detail: { value }`.\n * @event nile-select - Emitted when an item is selected. `detail: { value, item }`.\n * @event nile-scope-remove - Emitted when a scope tag is removed. `detail: { scope, scopes }`.\n *\n * @csspart base - The component's outer wrapper.\n * @csspart overlay - The overlay behind the panel.\n * @csspart panel - The command panel.\n * @csspart header - The search header.\n * @csspart input - The search input.\n * @csspart scopes - The \"Searching for\" scopes row.\n * @csspart scope-tag - Each scope tag in the scopes row.\n * @csspart list - The scrollable results list.\n * @csspart empty - The empty state shown when nothing matches.\n * @csspart footer - The footer.\n * @csspart hints - The built-in keyboard-hint row inside the footer.\n *\n * @cssproperty --width - The maximum width of the panel.\n * @cssproperty --max-height - The maximum height of the panel.\n */\n@customElement('nile-command-menu')\nexport class NileCommandMenu extends NileElement {\n static styles: CSSResultGroup = styles;\n\n private readonly hasSlotController = new HasSlotController(this, 'footer');\n private modal: Modal;\n private originalTrigger: HTMLElement | null;\n\n @query('.command') command: HTMLElement;\n @query('.command__panel') panel: HTMLElement;\n @query('.command__overlay') overlay: HTMLElement;\n @query('.command__input') input: HTMLInputElement;\n\n /** Indicates whether the menu is open. Toggle this attribute, or use `show()` / `hide()`. */\n @property({ type: Boolean, reflect: true }) open = false;\n\n /** Placeholder text shown in the search input. */\n @property() placeholder = 'Search commands...';\n\n /** Accessible label for the dialog and the search input. */\n @property() label = 'Command menu';\n\n /** Message shown when no items match the current query. Ignored when the `empty` slot is used. */\n @property({ attribute: true }) noResultsMessage = 'No results found';\n\n /** The current search value. */\n @property() value = '';\n\n /**\n * When set, the menu does not filter items itself; instead it emits `nile-search` so the host can\n * manage results. Useful for async/server-side search.\n */\n @property({ type: Boolean, attribute: true }) customSearch = false;\n\n /** Keeps the menu open after an item is selected instead of closing it. */\n @property({ type: Boolean, attribute: true }) keepOpenOnSelect = false;\n\n /** Prevents the menu from closing when the overlay is clicked. */\n @property({ type: Boolean, attribute: true }) preventOverlayClose = false;\n\n /** Hides the built-in keyboard-hint footer (navigate / select / close). The `footer` slot always overrides it. */\n @property({ type: Boolean, attribute: true }) noFooterHints = false;\n\n /**\n * Active search scopes shown as removable tags in the \"Searching for\" row. Items are filtered so that\n * only those with no `scope` or whose `scope` matches an active scope are shown. Set via the `scopes`\n * attribute (comma-separated labels or a JSON array) or the property (array of `{ label, value }`).\n */\n @property({ converter: scopesConverter }) scopes: CommandMenuScope[] = [];\n\n /** Label shown before the scope tags. */\n @property({ attribute: true }) scopesLabel = 'Searching for';\n\n /** True when the current query matches no items. */\n @state() private hasResults = true;\n\n connectedCallback() {\n super.connectedCallback();\n this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);\n this.modal = new Modal(this);\n }\n\n firstUpdated() {\n this.command.hidden = !this.open;\n\n if (this.open) {\n this.addOpenListeners();\n this.modal.activate();\n lockBodyScrolling(this);\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n unlockBodyScrolling(this);\n }\n\n /** Gets all command items in the menu (across groups), in document order. */\n private getAllItems(): NileCommandMenuItem[] {\n return [...this.querySelectorAll<NileCommandMenuItem>('nile-command-menu-item')];\n }\n\n /** Gets the items that are currently visible (matching the query) and not disabled. */\n private getVisibleItems(): NileCommandMenuItem[] {\n return this.getAllItems().filter(item => !item.hidden && !item.disabled);\n }\n\n private getActiveItem(): NileCommandMenuItem | undefined {\n return this.getVisibleItems().find(item => item.active);\n }\n\n private setActiveItem(item: NileCommandMenuItem | undefined) {\n this.getAllItems().forEach(i => {\n i.active = i === item;\n });\n\n if (item) {\n if (!item.id) {\n item.id = `nile-command-menu-item-${++commandMenuItemId}`;\n }\n this.input?.setAttribute('aria-activedescendant', item.id);\n item.scrollIntoView({ block: 'nearest' });\n } else {\n this.input?.removeAttribute('aria-activedescendant');\n }\n }\n\n /** Applies the current query to the items, hiding non-matching items and empty groups. */\n private filterItems() {\n const items = this.getAllItems();\n\n if (this.customSearch) {\n // The host owns visibility; just refresh the empty state and active item.\n this.hasResults = this.getVisibleItems().length > 0;\n this.updateGroupVisibility();\n this.ensureActiveItem();\n return;\n }\n\n const query = this.value.trim().toLowerCase();\n const activeScopes = this.scopes.map(scope => scope.value);\n\n items.forEach(item => {\n const matchesQuery = query.length === 0 || item.getFilterText().includes(query);\n const matchesScope =\n activeScopes.length === 0 || !item.scope || activeScopes.includes(item.scope);\n item.hidden = !(matchesQuery && matchesScope);\n });\n\n this.updateGroupVisibility();\n this.hasResults = this.getVisibleItems().length > 0;\n this.ensureActiveItem();\n }\n\n /** Hides groups that have no visible items. */\n private updateGroupVisibility() {\n const groups = [...this.querySelectorAll<NileCommandMenuGroup>('nile-command-menu-group')];\n groups.forEach(group => {\n const hasVisibleItem = [\n ...group.querySelectorAll<NileCommandMenuItem>('nile-command-menu-item'),\n ].some(item => !item.hidden);\n group.hidden = !hasVisibleItem;\n });\n }\n\n /** Ensures exactly one visible item is active, defaulting to the first. */\n private ensureActiveItem() {\n const visible = this.getVisibleItems();\n const current = this.getActiveItem();\n\n if (visible.length === 0) {\n this.setActiveItem(undefined);\n return;\n }\n\n if (!current || !visible.includes(current)) {\n this.setActiveItem(visible[0]);\n }\n }\n\n private handleInput(event: Event) {\n this.value = (event.target as HTMLInputElement).value;\n this.emit('nile-search', { value: this.value });\n this.filterItems();\n }\n\n @watch('scopes', { waitUntilFirstUpdate: true })\n handleScopesChange() {\n this.filterItems();\n }\n\n private handleScopeRemove(scope: CommandMenuScope) {\n this.scopes = this.scopes.filter(s => s.value !== scope.value);\n this.emit('nile-scope-remove', { scope, scopes: this.scopes });\n this.filterItems();\n }\n\n private handleSlotChange() {\n this.filterItems();\n }\n\n private handlePanelKeyDown(event: KeyboardEvent) {\n const visible = this.getVisibleItems();\n\n if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {\n if (visible.length === 0) {\n return;\n }\n event.preventDefault();\n\n const current = this.getActiveItem();\n let index = current ? visible.indexOf(current) : -1;\n\n if (event.key === 'ArrowDown') index++;\n else if (event.key === 'ArrowUp') index--;\n else if (event.key === 'Home') index = 0;\n else if (event.key === 'End') index = visible.length - 1;\n\n if (index < 0) index = visible.length - 1;\n if (index > visible.length - 1) index = 0;\n\n this.setActiveItem(visible[index]);\n return;\n }\n\n if (event.key === 'Enter') {\n const current = this.getActiveItem();\n if (current) {\n event.preventDefault();\n this.selectItem(current);\n }\n }\n }\n\n private handleListClick(event: MouseEvent) {\n const item = (event.target as HTMLElement).closest<NileCommandMenuItem>(\n 'nile-command-menu-item'\n );\n if (item && !item.disabled) {\n this.selectItem(item);\n }\n }\n\n private selectItem(item: NileCommandMenuItem) {\n this.emit('nile-select', { value: item.value, item });\n if (!this.keepOpenOnSelect) {\n this.hide();\n }\n }\n\n private requestClose(source: 'overlay' | 'keyboard') {\n const requestClose = this.emit(\n 'nile-request-close',\n { source },\n undefined,\n undefined,\n true\n );\n\n if (requestClose.defaultPrevented) {\n return;\n }\n\n if (source === 'overlay' && this.preventOverlayClose) {\n return;\n }\n\n this.hide();\n }\n\n private addOpenListeners() {\n document.addEventListener('keydown', this.handleDocumentKeyDown);\n }\n\n private removeOpenListeners() {\n document.removeEventListener('keydown', this.handleDocumentKeyDown);\n }\n\n private handleDocumentKeyDown(event: KeyboardEvent) {\n if (this.open && event.key === 'Escape') {\n event.stopPropagation();\n this.requestClose('keyboard');\n }\n }\n\n @watch('open', { waitUntilFirstUpdate: true })\n async handleOpenChange() {\n if (this.open) {\n this.emit('nile-show');\n this.addOpenListeners();\n this.originalTrigger = document.activeElement as HTMLElement;\n this.modal.activate();\n lockBodyScrolling(this);\n\n await stopAnimations(this.command);\n this.command.hidden = false;\n\n // Reset query and selection each time the menu opens.\n this.value = '';\n this.filterItems();\n\n requestAnimationFrame(() => {\n this.input?.focus({ preventScroll: true });\n });\n\n const panelAnimation = getAnimation(this, 'command.show', { dir: 'ltr' });\n const overlayAnimation = getAnimation(this, 'command.overlay.show', { dir: 'ltr' });\n await Promise.all([\n animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options),\n animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options),\n ]);\n\n this.emit('nile-after-show');\n } else {\n this.emit('nile-hide');\n this.removeOpenListeners();\n this.modal.deactivate();\n\n await stopAnimations(this.command);\n const panelAnimation = getAnimation(this, 'command.hide', { dir: 'ltr' });\n const overlayAnimation = getAnimation(this, 'command.overlay.hide', { dir: 'ltr' });\n await Promise.all([\n animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options),\n animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options),\n ]);\n\n this.command.hidden = true;\n unlockBodyScrolling(this);\n\n const trigger = this.originalTrigger;\n if (typeof trigger?.focus === 'function') {\n setTimeout(() => trigger.focus());\n }\n\n this.emit('nile-after-hide');\n }\n }\n\n /** Renders the \"Searching for\" scopes row when scopes are active. */\n private renderScopes() {\n if (this.scopes.length === 0) {\n return nothing;\n }\n\n return html`\n <div part=\"scopes\" class=\"command__scopes\">\n <span class=\"command__scopes-label\">${this.scopesLabel}</span>\n <div class=\"command__scopes-tags\">\n ${this.scopes.map(\n scope => html`\n <nile-tag\n part=\"scope-tag\"\n exportparts=\"base:scope-tag__base\"\n size=\"medium\"\n variant=\"normal\"\n pill\n removable\n .value=${scope.value}\n @nile-remove=${() => this.handleScopeRemove(scope)}\n >\n ${scope.label}\n </nile-tag>\n `\n )}\n </div>\n </div>\n `;\n }\n\n /** Renders the built-in keyboard-hint footer (used as the `footer` slot's fallback content). */\n private renderHints() {\n return html`\n <div part=\"hints\" class=\"command__hints\">\n <span class=\"command__hint\"><kbd>↑</kbd><kbd>↓</kbd> to navigate</span>\n <span class=\"command__hint\"><kbd>↵</kbd> to select</span>\n <span class=\"command__hint\"><kbd>esc</kbd> to close</span>\n </div>\n `;\n }\n\n /** Shows the command menu. */\n async show() {\n if (this.open) {\n return undefined;\n }\n\n this.open = true;\n return waitForEvent(this, 'nile-after-show');\n }\n\n /** Hides the command menu. */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n\n this.open = false;\n return waitForEvent(this, 'nile-after-hide');\n }\n\n render() {\n return html`\n <div\n part=\"base\"\n class=${classMap({\n command: true,\n 'command--open': this.open,\n 'command--has-footer':\n this.hasSlotController.test('footer') || !this.noFooterHints,\n })}\n >\n <div\n part=\"overlay\"\n class=\"command__overlay\"\n tabindex=\"-1\"\n @click=${() => this.requestClose('overlay')}\n ></div>\n\n <div\n part=\"panel\"\n class=\"command__panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=${this.label}\n aria-hidden=${this.open ? 'false' : 'true'}\n @keydown=${this.handlePanelKeyDown}\n >\n <div part=\"header\" class=\"command__header\">\n <span class=\"command__search-icon\" aria-hidden=\"true\">\n <nile-glyph name=\"search\" size=\"20\" method=\"stroke\"></nile-glyph>\n </span>\n <input\n part=\"input\"\n class=\"command__input\"\n type=\"text\"\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls=\"command-list\"\n aria-label=${this.label}\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n spellcheck=\"false\"\n .value=${this.value}\n placeholder=${this.placeholder}\n @input=${this.handleInput}\n />\n </div>\n\n ${this.renderScopes()}\n\n <div\n part=\"list\"\n id=\"command-list\"\n class=\"command__list\"\n role=\"listbox\"\n aria-label=${this.label}\n @click=${this.handleListClick}\n >\n <slot @slotchange=${this.handleSlotChange}></slot>\n\n <div\n part=\"empty\"\n class=${classMap({\n command__empty: true,\n 'command__empty--visible': !this.hasResults,\n })}\n >\n <slot name=\"empty\">${!this.hasResults ? this.noResultsMessage : nothing}</slot>\n </div>\n </div>\n\n <footer part=\"footer\" class=\"command__footer\">\n <slot name=\"footer\">\n ${this.noFooterHints ? nothing : this.renderHints()}\n </slot>\n </footer>\n </div>\n </div>\n `;\n }\n}\n\nsetDefaultAnimation('command.show', {\n keyframes: [\n { opacity: 0, scale: 0.95 },\n { opacity: 1, scale: 1 },\n ],\n options: { duration: 200, easing: 'ease' },\n});\n\nsetDefaultAnimation('command.hide', {\n keyframes: [\n { opacity: 1, scale: 1 },\n { opacity: 0, scale: 0.95 },\n ],\n options: { duration: 200, easing: 'ease' },\n});\n\nsetDefaultAnimation('command.overlay.show', {\n keyframes: [{ opacity: 0 }, { opacity: 1 }],\n options: { duration: 200 },\n});\n\nsetDefaultAnimation('command.overlay.hide', {\n keyframes: [{ opacity: 1 }, { opacity: 0 }],\n options: { duration: 200 },\n});\n\nexport default NileCommandMenu;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nile-command-menu': NileCommandMenu;\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import './nile-command-menu';
2
+ import '../nile-command-menu-group/nile-command-menu-group';
3
+ import '../nile-command-menu-item/nile-command-menu-item';