@tylertech/forge-ai 0.1.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 (200) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +3 -0
  3. package/custom-elements.json +4963 -0
  4. package/dist/ai-actions-toolbar/ai-actions-toolbar.d.ts +25 -0
  5. package/dist/ai-actions-toolbar/ai-actions-toolbar.mjs +74 -0
  6. package/dist/ai-actions-toolbar/ai-actions-toolbar.scss.mjs +4 -0
  7. package/dist/ai-actions-toolbar/index.d.ts +1 -0
  8. package/dist/ai-actions-toolbar/index.mjs +5 -0
  9. package/dist/ai-artifact/ai-artifact.d.ts +20 -0
  10. package/dist/ai-artifact/ai-artifact.mjs +39 -0
  11. package/dist/ai-artifact/ai-artifact.scss.mjs +4 -0
  12. package/dist/ai-artifact/index.d.ts +1 -0
  13. package/dist/ai-artifact/index.mjs +5 -0
  14. package/dist/ai-button/ai-button.d.ts +21 -0
  15. package/dist/ai-button/ai-button.mjs +67 -0
  16. package/dist/ai-button/ai-button.scss.mjs +4 -0
  17. package/dist/ai-button/index.d.ts +1 -0
  18. package/dist/ai-button/index.mjs +5 -0
  19. package/dist/ai-chain-of-thought/ai-chain-of-thought.d.ts +17 -0
  20. package/dist/ai-chain-of-thought/ai-chain-of-thought.mjs +45 -0
  21. package/dist/ai-chain-of-thought/ai-chain-of-thought.scss.mjs +4 -0
  22. package/dist/ai-chain-of-thought/index.d.ts +5 -0
  23. package/dist/ai-chain-of-thought/index.mjs +17 -0
  24. package/dist/ai-chain-of-thought/thought-base/index.d.ts +1 -0
  25. package/dist/ai-chain-of-thought/thought-base/index.mjs +5 -0
  26. package/dist/ai-chain-of-thought/thought-base/thought-base.d.ts +20 -0
  27. package/dist/ai-chain-of-thought/thought-base/thought-base.mjs +43 -0
  28. package/dist/ai-chain-of-thought/thought-base/thought-base.scss.mjs +4 -0
  29. package/dist/ai-chain-of-thought/thought-detail/index.d.ts +1 -0
  30. package/dist/ai-chain-of-thought/thought-detail/index.mjs +5 -0
  31. package/dist/ai-chain-of-thought/thought-detail/thought-detail.d.ts +14 -0
  32. package/dist/ai-chain-of-thought/thought-detail/thought-detail.mjs +34 -0
  33. package/dist/ai-chain-of-thought/thought-detail/thought-detail.scss.mjs +4 -0
  34. package/dist/ai-chain-of-thought/thought-image/index.d.ts +1 -0
  35. package/dist/ai-chain-of-thought/thought-image/index.mjs +5 -0
  36. package/dist/ai-chain-of-thought/thought-image/thought-image.d.ts +16 -0
  37. package/dist/ai-chain-of-thought/thought-image/thought-image.mjs +43 -0
  38. package/dist/ai-chain-of-thought/thought-image/thought-image.scss.mjs +4 -0
  39. package/dist/ai-chain-of-thought/thought-search-result/index.d.ts +1 -0
  40. package/dist/ai-chain-of-thought/thought-search-result/index.mjs +5 -0
  41. package/dist/ai-chain-of-thought/thought-search-result/thought-search-result.d.ts +22 -0
  42. package/dist/ai-chain-of-thought/thought-search-result/thought-search-result.mjs +62 -0
  43. package/dist/ai-chain-of-thought/thought-search-result/thought-search-result.scss.mjs +4 -0
  44. package/dist/ai-chat-header/ai-chat-header.d.ts +54 -0
  45. package/dist/ai-chat-header/ai-chat-header.mjs +198 -0
  46. package/dist/ai-chat-header/ai-chat-header.scss.mjs +4 -0
  47. package/dist/ai-chat-header/index.d.ts +1 -0
  48. package/dist/ai-chat-header/index.mjs +5 -0
  49. package/dist/ai-chat-interface/ai-chat-interface.d.ts +38 -0
  50. package/dist/ai-chat-interface/ai-chat-interface.mjs +117 -0
  51. package/dist/ai-chat-interface/ai-chat-interface.scss.mjs +4 -0
  52. package/dist/ai-chat-interface/index.d.ts +1 -0
  53. package/dist/ai-chat-interface/index.mjs +5 -0
  54. package/dist/ai-dialog/ai-dialog.d.ts +56 -0
  55. package/dist/ai-dialog/ai-dialog.mjs +270 -0
  56. package/dist/ai-dialog/ai-dialog.scss.mjs +4 -0
  57. package/dist/ai-dialog/index.d.ts +1 -0
  58. package/dist/ai-dialog/index.mjs +5 -0
  59. package/dist/ai-dropdown-menu/ai-dropdown-menu-item-group.d.ts +26 -0
  60. package/dist/ai-dropdown-menu/ai-dropdown-menu-item-group.mjs +80 -0
  61. package/dist/ai-dropdown-menu/ai-dropdown-menu-item-group.scss.mjs +4 -0
  62. package/dist/ai-dropdown-menu/ai-dropdown-menu-item.d.ts +133 -0
  63. package/dist/ai-dropdown-menu/ai-dropdown-menu-item.mjs +335 -0
  64. package/dist/ai-dropdown-menu/ai-dropdown-menu-item.scss.mjs +4 -0
  65. package/dist/ai-dropdown-menu/ai-dropdown-menu-separator.d.ts +18 -0
  66. package/dist/ai-dropdown-menu/ai-dropdown-menu-separator.mjs +26 -0
  67. package/dist/ai-dropdown-menu/ai-dropdown-menu-separator.scss.mjs +4 -0
  68. package/dist/ai-dropdown-menu/ai-dropdown-menu.d.ts +143 -0
  69. package/dist/ai-dropdown-menu/ai-dropdown-menu.mjs +327 -0
  70. package/dist/ai-dropdown-menu/ai-dropdown-menu.scss.mjs +4 -0
  71. package/dist/ai-dropdown-menu/index.d.ts +4 -0
  72. package/dist/ai-dropdown-menu/index.mjs +10 -0
  73. package/dist/ai-dropdown-menu/navigation-controller.d.ts +79 -0
  74. package/dist/ai-dropdown-menu/navigation-controller.mjs +205 -0
  75. package/dist/ai-dropdown-menu/selection-manager.d.ts +145 -0
  76. package/dist/ai-dropdown-menu/selection-manager.mjs +183 -0
  77. package/dist/ai-embedded-chat/ai-embedded-chat.d.ts +47 -0
  78. package/dist/ai-embedded-chat/ai-embedded-chat.mjs +139 -0
  79. package/dist/ai-embedded-chat/ai-embedded-chat.scss.mjs +4 -0
  80. package/dist/ai-embedded-chat/index.d.ts +1 -0
  81. package/dist/ai-embedded-chat/index.mjs +5 -0
  82. package/dist/ai-empty-state/ai-empty-state.d.ts +19 -0
  83. package/dist/ai-empty-state/ai-empty-state.mjs +136 -0
  84. package/dist/ai-empty-state/ai-empty-state.scss.mjs +4 -0
  85. package/dist/ai-empty-state/index.d.ts +1 -0
  86. package/dist/ai-empty-state/index.mjs +5 -0
  87. package/dist/ai-fab/ai-fab.d.ts +23 -0
  88. package/dist/ai-fab/ai-fab.mjs +75 -0
  89. package/dist/ai-fab/ai-fab.scss.mjs +4 -0
  90. package/dist/ai-fab/index.d.ts +1 -0
  91. package/dist/ai-fab/index.mjs +5 -0
  92. package/dist/ai-file-picker/ai-file-picker.d.ts +77 -0
  93. package/dist/ai-file-picker/ai-file-picker.mjs +176 -0
  94. package/dist/ai-file-picker/ai-file-picker.scss.mjs +4 -0
  95. package/dist/ai-file-picker/index.d.ts +1 -0
  96. package/dist/ai-file-picker/index.mjs +4 -0
  97. package/dist/ai-floating-chat/ai-floating-chat.d.ts +65 -0
  98. package/dist/ai-floating-chat/ai-floating-chat.mjs +153 -0
  99. package/dist/ai-floating-chat/ai-floating-chat.scss.mjs +4 -0
  100. package/dist/ai-floating-chat/index.d.ts +1 -0
  101. package/dist/ai-floating-chat/index.mjs +5 -0
  102. package/dist/ai-gradient-container/ai-gradient-container.d.ts +26 -0
  103. package/dist/ai-gradient-container/ai-gradient-container.mjs +61 -0
  104. package/dist/ai-gradient-container/ai-gradient-container.scss.mjs +4 -0
  105. package/dist/ai-gradient-container/index.d.ts +1 -0
  106. package/dist/ai-gradient-container/index.mjs +5 -0
  107. package/dist/ai-icon/ai-icon.d.ts +22 -0
  108. package/dist/ai-icon/ai-icon.mjs +71 -0
  109. package/dist/ai-icon/ai-icon.scss.mjs +4 -0
  110. package/dist/ai-icon/index.d.ts +1 -0
  111. package/dist/ai-icon/index.mjs +5 -0
  112. package/dist/ai-modal/ai-modal.d.ts +49 -0
  113. package/dist/ai-modal/ai-modal.mjs +132 -0
  114. package/dist/ai-modal/ai-modal.scss.mjs +4 -0
  115. package/dist/ai-modal/index.d.ts +1 -0
  116. package/dist/ai-modal/index.mjs +4 -0
  117. package/dist/ai-prompt/ai-prompt.d.ts +42 -0
  118. package/dist/ai-prompt/ai-prompt.mjs +123 -0
  119. package/dist/ai-prompt/ai-prompt.scss.mjs +4 -0
  120. package/dist/ai-prompt/index.d.ts +1 -0
  121. package/dist/ai-prompt/index.mjs +5 -0
  122. package/dist/ai-prompt/prompt-button/index.d.ts +1 -0
  123. package/dist/ai-prompt/prompt-button/index.mjs +5 -0
  124. package/dist/ai-prompt/prompt-button/prompt-button.d.ts +16 -0
  125. package/dist/ai-prompt/prompt-button/prompt-button.mjs +40 -0
  126. package/dist/ai-prompt/prompt-button/prompt-button.scss.mjs +4 -0
  127. package/dist/ai-reasoning/ai-reasoning.d.ts +17 -0
  128. package/dist/ai-reasoning/ai-reasoning.mjs +44 -0
  129. package/dist/ai-reasoning/ai-reasoning.scss.mjs +4 -0
  130. package/dist/ai-reasoning/index.d.ts +2 -0
  131. package/dist/ai-reasoning/index.mjs +8 -0
  132. package/dist/ai-reasoning/reasoning-content/index.d.ts +1 -0
  133. package/dist/ai-reasoning/reasoning-content/index.mjs +5 -0
  134. package/dist/ai-reasoning/reasoning-content/reasoning-content.d.ts +22 -0
  135. package/dist/ai-reasoning/reasoning-content/reasoning-content.mjs +90 -0
  136. package/dist/ai-reasoning/reasoning-content/reasoning-content.scss.mjs +4 -0
  137. package/dist/ai-reasoning-header/ai-reasoning-header.d.ts +24 -0
  138. package/dist/ai-reasoning-header/ai-reasoning-header.mjs +68 -0
  139. package/dist/ai-reasoning-header/ai-reasoning-header.scss.mjs +4 -0
  140. package/dist/ai-reasoning-header/index.d.ts +1 -0
  141. package/dist/ai-reasoning-header/index.mjs +5 -0
  142. package/dist/ai-response-message/ai-response-message.d.ts +40 -0
  143. package/dist/ai-response-message/ai-response-message.mjs +137 -0
  144. package/dist/ai-response-message/ai-response-message.scss.mjs +4 -0
  145. package/dist/ai-response-message/index.d.ts +1 -0
  146. package/dist/ai-response-message/index.mjs +5 -0
  147. package/dist/ai-sidebar/ai-sidebar.d.ts +44 -0
  148. package/dist/ai-sidebar/ai-sidebar.mjs +105 -0
  149. package/dist/ai-sidebar/ai-sidebar.scss.mjs +4 -0
  150. package/dist/ai-sidebar/index.d.ts +1 -0
  151. package/dist/ai-sidebar/index.mjs +5 -0
  152. package/dist/ai-sidebar-chat/ai-sidebar-chat.d.ts +64 -0
  153. package/dist/ai-sidebar-chat/ai-sidebar-chat.mjs +170 -0
  154. package/dist/ai-sidebar-chat/ai-sidebar-chat.scss.mjs +4 -0
  155. package/dist/ai-sidebar-chat/index.d.ts +1 -0
  156. package/dist/ai-sidebar-chat/index.mjs +5 -0
  157. package/dist/ai-suggestions/ai-suggestions.d.ts +39 -0
  158. package/dist/ai-suggestions/ai-suggestions.mjs +96 -0
  159. package/dist/ai-suggestions/ai-suggestions.scss.mjs +4 -0
  160. package/dist/ai-suggestions/index.d.ts +1 -0
  161. package/dist/ai-suggestions/index.mjs +5 -0
  162. package/dist/ai-threads/ai-threads.d.ts +48 -0
  163. package/dist/ai-threads/ai-threads.mjs +203 -0
  164. package/dist/ai-threads/ai-threads.scss.mjs +4 -0
  165. package/dist/ai-threads/index.d.ts +1 -0
  166. package/dist/ai-threads/index.mjs +5 -0
  167. package/dist/ai-user-message/ai-user-message.d.ts +15 -0
  168. package/dist/ai-user-message/ai-user-message.mjs +43 -0
  169. package/dist/ai-user-message/ai-user-message.scss.mjs +4 -0
  170. package/dist/ai-user-message/index.d.ts +1 -0
  171. package/dist/ai-user-message/index.mjs +5 -0
  172. package/dist/ai-voice-input/ai-voice-input.d.ts +68 -0
  173. package/dist/ai-voice-input/ai-voice-input.mjs +107 -0
  174. package/dist/ai-voice-input/ai-voice-input.scss.mjs +4 -0
  175. package/dist/ai-voice-input/index.d.ts +1 -0
  176. package/dist/ai-voice-input/index.mjs +5 -0
  177. package/dist/core/drag-controller.d.ts +66 -0
  178. package/dist/core/drag-controller.mjs +219 -0
  179. package/dist/core/index.d.ts +1 -0
  180. package/dist/core/index.mjs +4 -0
  181. package/dist/core/overlay/index.d.ts +1 -0
  182. package/dist/core/overlay/index.mjs +4 -0
  183. package/dist/core/overlay/overlay.d.ts +61 -0
  184. package/dist/core/overlay/overlay.mjs +142 -0
  185. package/dist/core/overlay/overlay.scss.mjs +4 -0
  186. package/dist/core/popover/index.d.ts +1 -0
  187. package/dist/core/popover/index.mjs +4 -0
  188. package/dist/core/popover/popover.d.ts +56 -0
  189. package/dist/core/popover/popover.mjs +71 -0
  190. package/dist/core/popover/popover.scss.mjs +4 -0
  191. package/dist/core/tooltip/index.d.ts +1 -0
  192. package/dist/core/tooltip/index.mjs +4 -0
  193. package/dist/core/tooltip/tooltip.d.ts +91 -0
  194. package/dist/core/tooltip/tooltip.mjs +243 -0
  195. package/dist/core/tooltip/tooltip.scss.mjs +4 -0
  196. package/dist/index.d.ts +27 -0
  197. package/dist/index.mjs +98 -0
  198. package/dist/utils.d.ts +14 -0
  199. package/dist/utils.mjs +22 -0
  200. package/package.json +122 -0
@@ -0,0 +1,79 @@
1
+ import { ForgeAiDropdownMenuItemComponent } from './ai-dropdown-menu-item.js';
2
+ /**
3
+ * Controller class to handle keyboard navigation for dropdown menus.
4
+ *
5
+ * This controller manages all aspects of keyboard navigation within dropdown menus,
6
+ * including focus management, selection state, and keyboard event delegation.
7
+ * It supports both parent dropdown menus and nested submenus with proper
8
+ * navigation isolation and event bubbling control.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const controller = new DropdownNavigationController(
13
+ * hostElement,
14
+ * () => getMenuItems(),
15
+ * (index) => selectItem(index),
16
+ * () => closeDropdown(),
17
+ * () => openDropdown(),
18
+ * () => isSubmenu()
19
+ * );
20
+ *
21
+ * // Handle keyboard events
22
+ * controller.handleKeyDown(keyboardEvent, isOpen, triggerButton);
23
+ * ```
24
+ */
25
+ export declare class DropdownNavigationController {
26
+ private _host;
27
+ private _getMenuItems;
28
+ private _onItemSelect;
29
+ private _onClose;
30
+ private _onOpen;
31
+ private _isSubmenu;
32
+ private _selectedIndex;
33
+ private _openedViaKeyboard;
34
+ constructor(_host: HTMLElement, _getMenuItems: () => ForgeAiDropdownMenuItemComponent[], _onItemSelect: (index: number) => void, _onClose: () => void, _onOpen: () => void, _isSubmenu: () => boolean);
35
+ /**
36
+ * Gets the current selected index
37
+ */
38
+ get selectedIndex(): number;
39
+ /**
40
+ * Sets the selected index
41
+ */
42
+ set selectedIndex(value: number);
43
+ /**
44
+ * Gets whether the dropdown was opened via keyboard
45
+ */
46
+ get openedViaKeyboard(): boolean;
47
+ /**
48
+ * Sets whether the dropdown was opened via keyboard
49
+ */
50
+ set openedViaKeyboard(value: boolean);
51
+ /**
52
+ * Handles keyboard events for the dropdown menu
53
+ */
54
+ handleKeyDown(event: KeyboardEvent, isOpen: boolean, triggerButton: HTMLElement): boolean;
55
+ /**
56
+ * Moves the selection by the specified direction
57
+ */
58
+ private _moveSelection;
59
+ /**
60
+ * Updates the focus state of menu items
61
+ */
62
+ private _updateItemFocus;
63
+ /**
64
+ * Focuses the first item in the menu
65
+ */
66
+ focusFirstItem(): void;
67
+ /**
68
+ * Clears focus from all menu items
69
+ */
70
+ clearItemFocus(): void;
71
+ /**
72
+ * Resets the navigation state when dropdown opens
73
+ */
74
+ onOpen(): void;
75
+ /**
76
+ * Resets the navigation state
77
+ */
78
+ reset(): void;
79
+ }
@@ -0,0 +1,205 @@
1
+ class DropdownNavigationController {
2
+ constructor(_host, _getMenuItems, _onItemSelect, _onClose, _onOpen, _isSubmenu) {
3
+ this._host = _host;
4
+ this._getMenuItems = _getMenuItems;
5
+ this._onItemSelect = _onItemSelect;
6
+ this._onClose = _onClose;
7
+ this._onOpen = _onOpen;
8
+ this._isSubmenu = _isSubmenu;
9
+ this._selectedIndex = -1;
10
+ this._openedViaKeyboard = false;
11
+ }
12
+ /**
13
+ * Gets the current selected index
14
+ */
15
+ get selectedIndex() {
16
+ return this._selectedIndex;
17
+ }
18
+ /**
19
+ * Sets the selected index
20
+ */
21
+ set selectedIndex(value) {
22
+ this._selectedIndex = value;
23
+ }
24
+ /**
25
+ * Gets whether the dropdown was opened via keyboard
26
+ */
27
+ get openedViaKeyboard() {
28
+ return this._openedViaKeyboard;
29
+ }
30
+ /**
31
+ * Sets whether the dropdown was opened via keyboard
32
+ */
33
+ set openedViaKeyboard(value) {
34
+ this._openedViaKeyboard = value;
35
+ }
36
+ /**
37
+ * Handles keyboard events for the dropdown menu
38
+ */
39
+ handleKeyDown(event, isOpen, triggerButton) {
40
+ const target = event.target;
41
+ if (target && target !== this._host) {
42
+ const nestedDropdown = target.closest('forge-ai-dropdown-menu[data-submenu="true"]');
43
+ if (nestedDropdown && nestedDropdown !== this._host) {
44
+ return false;
45
+ }
46
+ }
47
+ switch (event.key) {
48
+ case "Enter":
49
+ case " ":
50
+ if (event.target === triggerButton) {
51
+ event.preventDefault();
52
+ this._onOpen();
53
+ return true;
54
+ } else if (isOpen && this._selectedIndex >= 0) {
55
+ event.preventDefault();
56
+ this._onItemSelect(this._selectedIndex);
57
+ return true;
58
+ }
59
+ break;
60
+ case "Escape":
61
+ if (isOpen) {
62
+ event.preventDefault();
63
+ this._onClose();
64
+ triggerButton.focus();
65
+ return true;
66
+ }
67
+ break;
68
+ case "ArrowDown":
69
+ if (isOpen) {
70
+ event.preventDefault();
71
+ this._moveSelection(1);
72
+ return true;
73
+ } else if (event.target === triggerButton) {
74
+ event.preventDefault();
75
+ this._openedViaKeyboard = true;
76
+ this._onOpen();
77
+ return true;
78
+ }
79
+ break;
80
+ case "ArrowUp":
81
+ if (isOpen) {
82
+ event.preventDefault();
83
+ this._moveSelection(-1);
84
+ return true;
85
+ }
86
+ break;
87
+ case "ArrowRight":
88
+ if (isOpen && this._selectedIndex >= 0) {
89
+ const items = this._getMenuItems();
90
+ const selectedItem = items[this._selectedIndex];
91
+ if (selectedItem) {
92
+ selectedItem.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowRight", bubbles: false }));
93
+ }
94
+ return true;
95
+ }
96
+ break;
97
+ case "ArrowLeft":
98
+ if (isOpen && this._isSubmenu()) {
99
+ event.preventDefault();
100
+ this._onClose();
101
+ const parentItem = this._host.parentElement;
102
+ if (parentItem && parentItem.tagName.toLowerCase() === "forge-ai-dropdown-menu-item") {
103
+ parentItem.focus();
104
+ }
105
+ return true;
106
+ }
107
+ break;
108
+ case "Home":
109
+ if (isOpen) {
110
+ event.preventDefault();
111
+ this._selectedIndex = 0;
112
+ this._updateItemFocus();
113
+ return true;
114
+ }
115
+ break;
116
+ case "End":
117
+ if (isOpen) {
118
+ event.preventDefault();
119
+ this._selectedIndex = Math.max(0, this._getMenuItems().length - 1);
120
+ this._updateItemFocus();
121
+ return true;
122
+ }
123
+ break;
124
+ }
125
+ return false;
126
+ }
127
+ /**
128
+ * Moves the selection by the specified direction
129
+ */
130
+ _moveSelection(direction) {
131
+ const items = this._getMenuItems();
132
+ if (items.length === 0) {
133
+ return;
134
+ }
135
+ if (this._selectedIndex === -1) {
136
+ if (direction > 0) {
137
+ this._selectedIndex = 0;
138
+ } else {
139
+ this._selectedIndex = items.length - 1;
140
+ }
141
+ } else {
142
+ let newIndex = this._selectedIndex + direction;
143
+ if (newIndex < 0) {
144
+ newIndex = items.length - 1;
145
+ } else if (newIndex >= items.length) {
146
+ newIndex = 0;
147
+ }
148
+ this._selectedIndex = newIndex;
149
+ }
150
+ this._updateItemFocus();
151
+ }
152
+ /**
153
+ * Updates the focus state of menu items
154
+ */
155
+ _updateItemFocus() {
156
+ const items = this._getMenuItems();
157
+ items.forEach((item, index) => {
158
+ item.setAttribute("tabindex", index === this._selectedIndex ? "0" : "-1");
159
+ if (index === this._selectedIndex) {
160
+ item.focus();
161
+ }
162
+ });
163
+ }
164
+ /**
165
+ * Focuses the first item in the menu
166
+ */
167
+ focusFirstItem() {
168
+ const items = this._getMenuItems();
169
+ if (items.length > 0) {
170
+ this._selectedIndex = 0;
171
+ this._updateItemFocus();
172
+ }
173
+ }
174
+ /**
175
+ * Clears focus from all menu items
176
+ */
177
+ clearItemFocus() {
178
+ const items = this._getMenuItems();
179
+ items.forEach((item) => {
180
+ item.setAttribute("tabindex", "-1");
181
+ });
182
+ }
183
+ /**
184
+ * Resets the navigation state when dropdown opens
185
+ */
186
+ onOpen() {
187
+ this._selectedIndex = -1;
188
+ if (this._openedViaKeyboard) {
189
+ this.focusFirstItem();
190
+ this._openedViaKeyboard = false;
191
+ } else {
192
+ this.clearItemFocus();
193
+ }
194
+ }
195
+ /**
196
+ * Resets the navigation state
197
+ */
198
+ reset() {
199
+ this._selectedIndex = -1;
200
+ this._openedViaKeyboard = false;
201
+ }
202
+ }
203
+ export {
204
+ DropdownNavigationController
205
+ };
@@ -0,0 +1,145 @@
1
+ import { ForgeAiDropdownMenuItemComponent } from './ai-dropdown-menu-item.js';
2
+ export type DropdownMenuSelectionMode = 'none' | 'single' | 'multi';
3
+ /**
4
+ * Base interface for dropdown menu selection change events
5
+ */
6
+ export interface BaseDropdownChangeEventDetail {
7
+ selectionMode: DropdownMenuSelectionMode;
8
+ timestamp: number;
9
+ }
10
+ /**
11
+ * Event detail for 'none' selection mode (actions only)
12
+ */
13
+ export interface ActionEventDetail extends BaseDropdownChangeEventDetail {
14
+ selectionMode: 'none';
15
+ value: string;
16
+ selectedItem: ForgeAiDropdownMenuItemComponent;
17
+ }
18
+ /**
19
+ * Event detail for 'single' selection mode
20
+ */
21
+ export interface SingleSelectionEventDetail extends BaseDropdownChangeEventDetail {
22
+ selectionMode: 'single';
23
+ value: string | null;
24
+ selectedItem: ForgeAiDropdownMenuItemComponent | null;
25
+ previousValue?: string | null;
26
+ }
27
+ /**
28
+ * Event detail for 'multi' selection mode
29
+ */
30
+ export interface MultiSelectionEventDetail extends BaseDropdownChangeEventDetail {
31
+ selectionMode: 'multi';
32
+ value: string[];
33
+ selectedItem: ForgeAiDropdownMenuItemComponent[];
34
+ addedItems?: ForgeAiDropdownMenuItemComponent[];
35
+ removedItems?: ForgeAiDropdownMenuItemComponent[];
36
+ }
37
+ /**
38
+ * Union type for all dropdown change event details
39
+ */
40
+ export type DropdownChangeEventDetail = ActionEventDetail | SingleSelectionEventDetail | MultiSelectionEventDetail;
41
+ /**
42
+ * Configuration options for selection behavior
43
+ */
44
+ export interface SelectionConfig {
45
+ mode: DropdownMenuSelectionMode;
46
+ closeOnSingleSelect?: boolean;
47
+ showSelectionCount?: boolean;
48
+ }
49
+ /**
50
+ * Manages selection state and behavior for dropdown menus.
51
+ *
52
+ * The SelectionManager is responsible for handling all aspects of item selection
53
+ * within dropdown menus, supporting three distinct modes:
54
+ *
55
+ * - **none**: Items act as actions only, no persistent selection state
56
+ * - **single**: Single selection with radio button behavior
57
+ * - **multi**: Multiple selection with checkbox behavior
58
+ *
59
+ * It provides type-safe event dispatching with mode-specific event details
60
+ * and maintains consistent selection state across all menu items.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const manager = new SelectionManager(
65
+ * () => getAllMenuItems(),
66
+ * (detail) => handleSelectionChange(detail),
67
+ * { mode: 'single', closeOnSingleSelect: true }
68
+ * );
69
+ *
70
+ * // Handle item selection
71
+ * const result = manager.selectItem(menuItem);
72
+ * if (result.shouldClose) {
73
+ * closeDropdown();
74
+ * }
75
+ * ```
76
+ */
77
+ export declare class SelectionManager {
78
+ private _getMenuItems;
79
+ private _onSelectionChange;
80
+ private _value;
81
+ private _config;
82
+ constructor(_getMenuItems: () => ForgeAiDropdownMenuItemComponent[], _onSelectionChange: (detail: DropdownChangeEventDetail) => void, config: SelectionConfig);
83
+ /**
84
+ * Gets the current selection value
85
+ */
86
+ get value(): string | string[] | null;
87
+ /**
88
+ * Sets the selection value and updates item states
89
+ */
90
+ set value(newValue: string | string[] | null);
91
+ /**
92
+ * Gets the current selection mode
93
+ */
94
+ get selectionMode(): DropdownMenuSelectionMode;
95
+ /**
96
+ * Updates the selection mode and reconfigures items
97
+ */
98
+ set selectionMode(mode: DropdownMenuSelectionMode);
99
+ /**
100
+ * Updates the selection configuration
101
+ */
102
+ updateConfig(config: Partial<SelectionConfig>): void;
103
+ /**
104
+ * Handles item selection based on the current mode
105
+ */
106
+ selectItem(item: ForgeAiDropdownMenuItemComponent): {
107
+ shouldClose: boolean;
108
+ };
109
+ /**
110
+ * Gets the currently selected items
111
+ */
112
+ getSelectedItems(): ForgeAiDropdownMenuItemComponent[];
113
+ /**
114
+ * Gets text representation of the current selection
115
+ */
116
+ getSelectedText(): string;
117
+ /**
118
+ * Checks if selection text should be displayed
119
+ */
120
+ shouldShowSelectedText(): boolean;
121
+ /**
122
+ * Updates the selection state of all menu items
123
+ */
124
+ private _updateItemSelectionState;
125
+ /**
126
+ * Handles action-only selection (no state change)
127
+ */
128
+ private _handleActionSelection;
129
+ /**
130
+ * Handles single selection mode
131
+ */
132
+ private _handleSingleSelection;
133
+ /**
134
+ * Handles multi-selection mode
135
+ */
136
+ private _handleMultiSelection;
137
+ /**
138
+ * Gets the selected values as an array
139
+ */
140
+ private _getSelectedValuesArray;
141
+ /**
142
+ * Resets the selection state
143
+ */
144
+ reset(): void;
145
+ }
@@ -0,0 +1,183 @@
1
+ class SelectionManager {
2
+ constructor(_getMenuItems, _onSelectionChange, config) {
3
+ this._getMenuItems = _getMenuItems;
4
+ this._onSelectionChange = _onSelectionChange;
5
+ this._value = null;
6
+ this._config = { closeOnSingleSelect: true, showSelectionCount: true, ...config };
7
+ }
8
+ /**
9
+ * Gets the current selection value
10
+ */
11
+ get value() {
12
+ return this._value;
13
+ }
14
+ /**
15
+ * Sets the selection value and updates item states
16
+ */
17
+ set value(newValue) {
18
+ this._value = newValue;
19
+ this._updateItemSelectionState();
20
+ }
21
+ /**
22
+ * Gets the current selection mode
23
+ */
24
+ get selectionMode() {
25
+ return this._config.mode;
26
+ }
27
+ /**
28
+ * Updates the selection mode and reconfigures items
29
+ */
30
+ set selectionMode(mode) {
31
+ this._config.mode = mode;
32
+ this._updateItemSelectionState();
33
+ }
34
+ /**
35
+ * Updates the selection configuration
36
+ */
37
+ updateConfig(config) {
38
+ this._config = { ...this._config, ...config };
39
+ this._updateItemSelectionState();
40
+ }
41
+ /**
42
+ * Handles item selection based on the current mode
43
+ */
44
+ selectItem(item) {
45
+ const itemValue = item.getAttribute("value") || "";
46
+ switch (this._config.mode) {
47
+ case "none":
48
+ return this._handleActionSelection(item, itemValue);
49
+ case "single":
50
+ return this._handleSingleSelection(item, itemValue);
51
+ case "multi":
52
+ return this._handleMultiSelection(item, itemValue);
53
+ default:
54
+ return { shouldClose: false };
55
+ }
56
+ }
57
+ /**
58
+ * Gets the currently selected items
59
+ */
60
+ getSelectedItems() {
61
+ const items = this._getMenuItems();
62
+ const selectedValues = this._getSelectedValuesArray();
63
+ return items.filter((item) => {
64
+ const itemValue = item.getAttribute("value") || "";
65
+ return selectedValues.includes(itemValue);
66
+ });
67
+ }
68
+ /**
69
+ * Gets text representation of the current selection
70
+ */
71
+ getSelectedText() {
72
+ if (this._config.mode === "none") {
73
+ return "";
74
+ }
75
+ const selectedItems = this.getSelectedItems();
76
+ if (selectedItems.length === 0) {
77
+ return "";
78
+ }
79
+ if (this._config.mode === "single") {
80
+ return selectedItems[0].labelText || "";
81
+ }
82
+ if (this._config.mode === "multi" && this._config.showSelectionCount) {
83
+ return selectedItems.length === 1 ? "1 option selected" : `${selectedItems.length} options selected`;
84
+ }
85
+ return "";
86
+ }
87
+ /**
88
+ * Checks if selection text should be displayed
89
+ */
90
+ shouldShowSelectedText() {
91
+ return (this._config.mode === "single" || this._config.mode === "multi") && this.getSelectedText() !== "";
92
+ }
93
+ /**
94
+ * Updates the selection state of all menu items
95
+ */
96
+ _updateItemSelectionState() {
97
+ const items = this._getMenuItems();
98
+ const selectedValues = this._getSelectedValuesArray();
99
+ items.forEach((item) => {
100
+ item.selectionMode = this._config.mode;
101
+ const itemValue = item.getAttribute("value") || "";
102
+ item.selected = selectedValues.includes(itemValue);
103
+ });
104
+ }
105
+ /**
106
+ * Handles action-only selection (no state change)
107
+ */
108
+ _handleActionSelection(item, itemValue) {
109
+ const eventDetail = {
110
+ selectionMode: "none",
111
+ value: itemValue,
112
+ selectedItem: item,
113
+ timestamp: Date.now()
114
+ };
115
+ this._onSelectionChange(eventDetail);
116
+ return { shouldClose: true };
117
+ }
118
+ /**
119
+ * Handles single selection mode
120
+ */
121
+ _handleSingleSelection(item, itemValue) {
122
+ const previousValue = typeof this._value === "string" ? this._value : null;
123
+ this._value = itemValue;
124
+ this._updateItemSelectionState();
125
+ const eventDetail = {
126
+ selectionMode: "single",
127
+ value: this._value,
128
+ selectedItem: item,
129
+ previousValue,
130
+ timestamp: Date.now()
131
+ };
132
+ this._onSelectionChange(eventDetail);
133
+ return { shouldClose: !!this._config.closeOnSingleSelect };
134
+ }
135
+ /**
136
+ * Handles multi-selection mode
137
+ */
138
+ _handleMultiSelection(item, itemValue) {
139
+ const currentValues = this._getSelectedValuesArray();
140
+ const itemIndex = currentValues.indexOf(itemValue);
141
+ let addedItems = [];
142
+ let removedItems = [];
143
+ if (itemIndex >= 0) {
144
+ currentValues.splice(itemIndex, 1);
145
+ removedItems = [item];
146
+ } else {
147
+ currentValues.push(itemValue);
148
+ addedItems = [item];
149
+ }
150
+ this._value = currentValues;
151
+ this._updateItemSelectionState();
152
+ const selectedItems = this.getSelectedItems();
153
+ const eventDetail = {
154
+ selectionMode: "multi",
155
+ value: currentValues,
156
+ selectedItem: selectedItems,
157
+ addedItems: addedItems.length > 0 ? addedItems : void 0,
158
+ removedItems: removedItems.length > 0 ? removedItems : void 0,
159
+ timestamp: Date.now()
160
+ };
161
+ this._onSelectionChange(eventDetail);
162
+ return { shouldClose: false };
163
+ }
164
+ /**
165
+ * Gets the selected values as an array
166
+ */
167
+ _getSelectedValuesArray() {
168
+ if (Array.isArray(this._value)) {
169
+ return [...this._value];
170
+ }
171
+ return this._value ? [this._value] : [];
172
+ }
173
+ /**
174
+ * Resets the selection state
175
+ */
176
+ reset() {
177
+ this._value = null;
178
+ this._updateItemSelectionState();
179
+ }
180
+ }
181
+ export {
182
+ SelectionManager
183
+ };
@@ -0,0 +1,47 @@
1
+ import { LitElement, TemplateResult } from 'lit';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'forge-ai-embedded-chat': AiEmbeddedChatComponent;
5
+ }
6
+ interface HTMLElementEventMap {
7
+ 'forge-ai-embedded-chat-expand': CustomEvent<void>;
8
+ 'forge-ai-embedded-chat-collapse': CustomEvent<void>;
9
+ }
10
+ }
11
+ export declare const AiEmbeddedChatComponentTagName: keyof HTMLElementTagNameMap;
12
+ /**
13
+ * @tag forge-ai-embedded-chat
14
+ *
15
+ * @slot - Default slot for messages (ai-user-message, ai-response-message components)
16
+ * @slot suggestions - Slot for AI suggestions component
17
+ * @slot prompt - Slot for custom AI prompt component. If not provided, a default forge-ai-prompt will be used.
18
+ *
19
+ * @event {CustomEvent<void>} forge-ai-embedded-chat-expand - Fired when the chat is expanded to modal view
20
+ * @event {CustomEvent<void>} forge-ai-embedded-chat-collapse - Fired when the chat is collapsed from modal view
21
+ *
22
+ * @description A form factor component that embeds ai-chat-interface within ai-gradient-container
23
+ * for inline page usage with optional modal expansion functionality.
24
+ */
25
+ export declare class AiEmbeddedChatComponent extends LitElement {
26
+ #private;
27
+ static styles: import('lit').CSSResult;
28
+ /**
29
+ * Controls whether the modal view is open when expanded.
30
+ */
31
+ expanded: boolean;
32
+ /**
33
+ * Controls the gradient variant applied to the container.
34
+ */
35
+ gradientVariant: 'low' | 'medium' | 'high';
36
+ private _isModalFullscreen;
37
+ updated(): void;
38
+ render(): TemplateResult;
39
+ /**
40
+ * Expands the chat to modal view.
41
+ */
42
+ expand(): void;
43
+ /**
44
+ * Collapses the chat from modal view back to embedded view.
45
+ */
46
+ collapse(): void;
47
+ }