@aquera/nile-elements 1.2.8-beta-1.7 → 1.2.8-beta-1.9

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 (52) hide show
  1. package/demo/index.html +54 -51
  2. package/dist/index.cjs.js +1 -1
  3. package/dist/index.esm.js +1 -1
  4. package/dist/index.js +285 -274
  5. package/dist/nile-auto-complete/index.cjs.js +1 -1
  6. package/dist/nile-auto-complete/index.esm.js +1 -1
  7. package/dist/nile-auto-complete/nile-auto-complete.cjs.js +1 -1
  8. package/dist/nile-auto-complete/nile-auto-complete.cjs.js.map +1 -1
  9. package/dist/nile-auto-complete/nile-auto-complete.esm.js +17 -13
  10. package/dist/nile-auto-complete/nile-auto-complete.test.cjs.js +1 -1
  11. package/dist/nile-auto-complete/nile-auto-complete.test.cjs.js.map +1 -1
  12. package/dist/nile-auto-complete/nile-auto-complete.test.esm.js +1 -1
  13. package/dist/nile-auto-complete/portal-manager.cjs.js +2 -0
  14. package/dist/nile-auto-complete/portal-manager.cjs.js.map +1 -0
  15. package/dist/nile-auto-complete/portal-manager.esm.js +1 -0
  16. package/dist/nile-auto-complete/portal-utils.cjs.js +2 -0
  17. package/dist/nile-auto-complete/portal-utils.cjs.js.map +1 -0
  18. package/dist/nile-auto-complete/portal-utils.esm.js +1 -0
  19. package/dist/nile-chip/index.cjs.js +1 -1
  20. package/dist/nile-chip/index.esm.js +1 -1
  21. package/dist/nile-chip/nile-chip.cjs.js +1 -1
  22. package/dist/nile-chip/nile-chip.cjs.js.map +1 -1
  23. package/dist/nile-chip/nile-chip.esm.js +14 -7
  24. package/dist/nile-chip/nile-chip.test.cjs.js +1 -1
  25. package/dist/nile-chip/nile-chip.test.cjs.js.map +1 -1
  26. package/dist/nile-chip/nile-chip.test.esm.js +1 -1
  27. package/dist/nile-lite-tooltip/nile-lite-tooltip.cjs.js +1 -1
  28. package/dist/nile-lite-tooltip/nile-lite-tooltip.cjs.js.map +1 -1
  29. package/dist/nile-lite-tooltip/nile-lite-tooltip.esm.js +1 -1
  30. package/dist/src/nile-auto-complete/nile-auto-complete.d.ts +18 -1
  31. package/dist/src/nile-auto-complete/nile-auto-complete.js +131 -9
  32. package/dist/src/nile-auto-complete/nile-auto-complete.js.map +1 -1
  33. package/dist/src/nile-auto-complete/portal-manager.d.ts +41 -0
  34. package/dist/src/nile-auto-complete/portal-manager.js +308 -0
  35. package/dist/src/nile-auto-complete/portal-manager.js.map +1 -0
  36. package/dist/src/nile-auto-complete/portal-utils.d.ts +31 -0
  37. package/dist/src/nile-auto-complete/portal-utils.js +166 -0
  38. package/dist/src/nile-auto-complete/portal-utils.js.map +1 -0
  39. package/dist/src/nile-chip/nile-chip.d.ts +7 -0
  40. package/dist/src/nile-chip/nile-chip.js +53 -10
  41. package/dist/src/nile-chip/nile-chip.js.map +1 -1
  42. package/dist/src/nile-lite-tooltip/nile-lite-tooltip.js.map +1 -1
  43. package/dist/src/version.js +2 -2
  44. package/dist/src/version.js.map +1 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +1 -1
  47. package/src/nile-auto-complete/nile-auto-complete.ts +148 -13
  48. package/src/nile-auto-complete/portal-manager.ts +410 -0
  49. package/src/nile-auto-complete/portal-utils.ts +221 -0
  50. package/src/nile-chip/nile-chip.ts +54 -12
  51. package/src/nile-lite-tooltip/nile-lite-tooltip.ts +4 -3
  52. package/vscode-html-custom-data.json +17 -2
@@ -0,0 +1,308 @@
1
+ import { autoUpdate, computePosition, flip, offset, shift, size, platform } from '@floating-ui/dom';
2
+ import { PortalUtils, PortalContentUtils, PortalEventUtils } from './portal-utils';
3
+ export class AutoCompletePortalManager {
4
+ constructor(component) {
5
+ this.portalContainer = null;
6
+ this.originalMenuParent = null;
7
+ this.measuredMenuHeight = null;
8
+ this.clonedMenu = null;
9
+ this.cleanupAutoUpdate = null;
10
+ this.currentPlacement = 'bottom';
11
+ this.currentMiddlewareData = null;
12
+ this.component = component;
13
+ }
14
+ createPortalAppendContainer() {
15
+ const container = document.createElement('div');
16
+ container.style.position = 'absolute';
17
+ container.style.zIndex = '9999';
18
+ container.style.pointerEvents = 'none';
19
+ container.style.width = 'auto';
20
+ container.style.minWidth = 'auto';
21
+ container.className = 'nile-auto-complete-portal-append';
22
+ return container;
23
+ }
24
+ positionPortalAppend() {
25
+ if (!this.portalContainer || !this.component.dropdownElement)
26
+ return;
27
+ this.measureMenuHeight();
28
+ this.computeFloatingUIPosition();
29
+ }
30
+ measureMenuHeight() {
31
+ if (this.measuredMenuHeight || !this.portalContainer)
32
+ return;
33
+ this.portalContainer.style.position = 'absolute';
34
+ this.portalContainer.style.visibility = 'hidden';
35
+ this.portalContainer.style.top = '0px';
36
+ this.portalContainer.style.left = '0px';
37
+ this.portalContainer.offsetHeight;
38
+ this.measuredMenuHeight = this.portalContainer.offsetHeight;
39
+ this.portalContainer.style.visibility = '';
40
+ }
41
+ async computeFloatingUIPosition() {
42
+ if (!this.portalContainer)
43
+ return;
44
+ const referenceElement = this.component.inputElement || this.component;
45
+ const floatingElement = this.portalContainer;
46
+ try {
47
+ const { x, y, placement, middlewareData } = await this.calculateFloatingUIPosition(referenceElement, floatingElement);
48
+ this.applyFloatingUIPosition(floatingElement, referenceElement, x, y, placement, middlewareData);
49
+ }
50
+ catch (error) {
51
+ console.warn('Floating UI positioning failed, falling back to simple positioning:', error);
52
+ this.fallbackPositioning();
53
+ }
54
+ }
55
+ async calculateFloatingUIPosition(referenceElement, floatingElement) {
56
+ const boundary = PortalUtils.findBoundaryElements(referenceElement);
57
+ // Use 'bottom-start' or 'top-start' to align left edges for auto-width menu
58
+ const basePlacement = PortalUtils.getOptimalPlacement(referenceElement);
59
+ const initialPlacement = basePlacement === 'top' ? 'top-start' : 'bottom-start';
60
+ const middleware = this.createFloatingUIMiddleware(boundary);
61
+ return await computePosition(referenceElement, floatingElement, {
62
+ placement: initialPlacement,
63
+ strategy: 'fixed',
64
+ middleware,
65
+ platform: this.createCustomPlatform()
66
+ });
67
+ }
68
+ createFloatingUIMiddleware(boundary) {
69
+ return [
70
+ offset(4),
71
+ size({
72
+ apply: this.handleSizeMiddleware.bind(this),
73
+ padding: 10,
74
+ boundary: boundary
75
+ }),
76
+ flip({
77
+ fallbackPlacements: ['bottom-start', 'top-start', 'bottom', 'top', 'bottom-end', 'top-end'],
78
+ fallbackStrategy: 'bestFit',
79
+ padding: 10,
80
+ boundary: boundary
81
+ }),
82
+ shift({
83
+ padding: 10,
84
+ crossAxis: true,
85
+ boundary: boundary
86
+ })
87
+ ];
88
+ }
89
+ handleSizeMiddleware({ availableWidth, availableHeight, elements, rects }) {
90
+ const maxHeight = PortalUtils.calculateOptimalHeight(rects.reference, window.innerHeight, this.currentPlacement);
91
+ // elements.floating.style.maxWidth = `${availableWidth}px`;
92
+ elements.floating.style.maxHeight = `${maxHeight}px`;
93
+ elements.floating.style.setProperty('--auto-size-available-width', `${availableWidth}px`);
94
+ elements.floating.style.setProperty('--auto-size-available-height', `${maxHeight}px`);
95
+ }
96
+ createCustomPlatform() {
97
+ return platform;
98
+ }
99
+ applyFloatingUIPosition(floatingElement, referenceElement, x, y, placement, middlewareData) {
100
+ // For auto-complete, align left edge with input element
101
+ // Use reference element's left position, not Floating UI's x (which might shift)
102
+ const referenceRect = referenceElement.getBoundingClientRect();
103
+ Object.assign(floatingElement.style, {
104
+ left: `${referenceRect.left}px`,
105
+ top: `${y}px`,
106
+ position: 'fixed',
107
+ pointerEvents: 'auto',
108
+ width: 'auto',
109
+ minWidth: 'auto'
110
+ });
111
+ this.currentPlacement = placement;
112
+ this.currentMiddlewareData = middlewareData;
113
+ PortalUtils.applyCollisionData(floatingElement, middlewareData, placement);
114
+ const placementClass = placement.split('-')[0];
115
+ floatingElement.className = `nile-auto-complete-portal-append menu__listbox--${placementClass}`;
116
+ }
117
+ fallbackPositioning() {
118
+ if (!this.portalContainer)
119
+ return;
120
+ const referenceElement = this.component.inputElement || this.component;
121
+ const rect = referenceElement.getBoundingClientRect();
122
+ const viewportHeight = window.innerHeight;
123
+ const menuHeight = this.measuredMenuHeight || 200;
124
+ const spaceBelow = viewportHeight - rect.bottom;
125
+ const spaceAbove = rect.top;
126
+ let topPosition;
127
+ let placementClass;
128
+ let maxHeight;
129
+ if (spaceAbove > spaceBelow) {
130
+ maxHeight = Math.max(spaceAbove - 20, 100);
131
+ topPosition = Math.max(rect.top - maxHeight - 4, 10);
132
+ placementClass = 'top';
133
+ }
134
+ else {
135
+ maxHeight = Math.max(spaceBelow - 20, 100);
136
+ topPosition = rect.bottom + 4;
137
+ placementClass = 'bottom';
138
+ }
139
+ this.portalContainer.style.left = `${rect.left}px`;
140
+ this.portalContainer.style.top = `${topPosition}px`;
141
+ // Let the menu auto-size based on its content, don't force width to match input
142
+ this.portalContainer.style.width = 'auto';
143
+ this.portalContainer.style.minWidth = 'auto';
144
+ this.portalContainer.style.maxHeight = `${maxHeight}px`;
145
+ this.portalContainer.style.pointerEvents = 'auto';
146
+ this.portalContainer.className = `nile-auto-complete-portal-append menu__listbox--${placementClass}`;
147
+ this.calculateAndSetAutoSizeProperties(rect, topPosition, placementClass);
148
+ }
149
+ calculateAndSetAutoSizeProperties(rect, topPosition, placementClass) {
150
+ if (!this.portalContainer)
151
+ return;
152
+ const viewportHeight = window.innerHeight;
153
+ const viewportWidth = window.innerWidth;
154
+ let availableHeight;
155
+ if (placementClass === 'top') {
156
+ availableHeight = rect.top - 10;
157
+ }
158
+ else {
159
+ availableHeight = viewportHeight - rect.bottom - 10;
160
+ }
161
+ const availableWidth = Math.min(rect.width, viewportWidth - rect.left - 10);
162
+ this.portalContainer.style.setProperty('--auto-size-available-height', `${Math.max(availableHeight, 100)}px`);
163
+ this.portalContainer.style.setProperty('--auto-size-available-width', `${Math.max(availableWidth, 200)}px`);
164
+ }
165
+ updatePortalAppendPosition() {
166
+ if (this.component.portal && this.portalContainer) {
167
+ this.positionPortalAppend();
168
+ }
169
+ }
170
+ handleWindowResize() {
171
+ if (this.component.portal && this.portalContainer) {
172
+ this.positionPortalAppend();
173
+ }
174
+ }
175
+ setupAutoUpdatePositioning() {
176
+ if (!this.portalContainer || !this.component)
177
+ return;
178
+ this.cleanupAutoUpdatePositioning();
179
+ this.cleanupAutoUpdate = autoUpdate(this.component, this.portalContainer, () => {
180
+ this.computeFloatingUIPosition();
181
+ }, {
182
+ ancestorScroll: true,
183
+ ancestorResize: true,
184
+ elementResize: true,
185
+ layoutShift: true,
186
+ animationFrame: true
187
+ });
188
+ }
189
+ cleanupAutoUpdatePositioning() {
190
+ if (this.cleanupAutoUpdate) {
191
+ this.cleanupAutoUpdate();
192
+ this.cleanupAutoUpdate = null;
193
+ }
194
+ }
195
+ injectStylesToDocument() {
196
+ if (!this.portalContainer)
197
+ return;
198
+ const styleId = PortalUtils.generateStyleId();
199
+ if (document.getElementById(styleId))
200
+ return;
201
+ const componentStyles = this.component.constructor.styles;
202
+ if (!componentStyles)
203
+ return;
204
+ const styleElement = document.createElement('style');
205
+ styleElement.id = styleId;
206
+ styleElement.textContent = PortalUtils.extractStylesAsCSS(componentStyles);
207
+ document.head.appendChild(styleElement);
208
+ this.portalContainer.__injectedStyleId = styleId;
209
+ }
210
+ adoptStylesToPortalAppend() {
211
+ if (!this.portalContainer)
212
+ return;
213
+ this.injectStylesToDocument();
214
+ }
215
+ setupPortalAppend() {
216
+ if (!this.component.portal)
217
+ return;
218
+ this.component.updateComplete.then(() => {
219
+ setTimeout(() => {
220
+ // Try to find menu in shadow root first, then fallback to querySelector
221
+ const menu = this.component.shadowRoot?.querySelector('#content-menu') ||
222
+ this.component.querySelector('#content-menu');
223
+ if (menu && this.component.isDropdownOpen) {
224
+ this.originalMenuParent = menu.parentElement;
225
+ this.clonedMenu = this.createPortalMenu();
226
+ this.portalContainer = this.createPortalAppendContainer();
227
+ this.portalContainer.appendChild(this.clonedMenu);
228
+ document.body.appendChild(this.portalContainer);
229
+ this.adoptStylesToPortalAppend();
230
+ this.clonedMenu.style.display = '';
231
+ this.positionPortalAppend();
232
+ this.setupPortalEventListeners();
233
+ this.setupAutoUpdatePositioning();
234
+ window.addEventListener('resize', this.handleWindowResize.bind(this));
235
+ }
236
+ }, 10);
237
+ });
238
+ }
239
+ createPortalMenu() {
240
+ return PortalContentUtils.createPortalMenu(this.component);
241
+ }
242
+ setupPortalEventListeners() {
243
+ PortalEventUtils.setupPortalEventListeners(this.clonedMenu, this.component);
244
+ }
245
+ cleanupPortalAppend() {
246
+ this.cleanupAutoUpdatePositioning();
247
+ if (this.portalContainer && this.portalContainer.parentNode) {
248
+ const injectedStyleId = this.portalContainer.__injectedStyleId;
249
+ if (injectedStyleId) {
250
+ const styleElement = document.getElementById(injectedStyleId);
251
+ if (styleElement) {
252
+ styleElement.remove();
253
+ }
254
+ }
255
+ this.portalContainer.parentNode.removeChild(this.portalContainer);
256
+ }
257
+ window.removeEventListener('resize', this.handleWindowResize.bind(this));
258
+ this.portalContainer = null;
259
+ this.originalMenuParent = null;
260
+ this.clonedMenu = null;
261
+ this.measuredMenuHeight = null;
262
+ this.currentPlacement = 'bottom';
263
+ this.currentMiddlewareData = null;
264
+ }
265
+ get portalContainerElement() {
266
+ return this.portalContainer;
267
+ }
268
+ resetMeasuredHeight() {
269
+ this.measuredMenuHeight = null;
270
+ }
271
+ updatePortalOptions() {
272
+ if (this.portalContainer && this.clonedMenu) {
273
+ PortalContentUtils.updatePortalMenuItems(this.clonedMenu, this.component);
274
+ this.forceReposition();
275
+ }
276
+ }
277
+ forceReposition() {
278
+ if (this.portalContainer) {
279
+ this.computeFloatingUIPosition();
280
+ }
281
+ }
282
+ getCurrentPlacement() {
283
+ return this.currentPlacement;
284
+ }
285
+ getCurrentMiddlewareData() {
286
+ return this.currentMiddlewareData;
287
+ }
288
+ isUsingFloatingUI() {
289
+ return this.cleanupAutoUpdate !== null;
290
+ }
291
+ isPositioningOptimal() {
292
+ if (!this.portalContainer || !this.currentMiddlewareData)
293
+ return true;
294
+ const referenceElement = this.component.inputElement || this.component;
295
+ const rect = referenceElement.getBoundingClientRect();
296
+ const viewportHeight = window.innerHeight;
297
+ const spaceBelow = viewportHeight - rect.bottom;
298
+ const spaceAbove = rect.top;
299
+ const isAbove = this.currentPlacement.startsWith('top');
300
+ const isBelow = this.currentPlacement.startsWith('bottom');
301
+ if (isAbove && spaceBelow > spaceAbove)
302
+ return false;
303
+ if (isBelow && spaceAbove > spaceBelow)
304
+ return false;
305
+ return true;
306
+ }
307
+ }
308
+ //# sourceMappingURL=portal-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal-manager.js","sourceRoot":"","sources":["../../../src/nile-auto-complete/portal-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,eAAe,EACf,IAAI,EACJ,MAAM,EACN,KAAK,EACL,IAAI,EACJ,QAAQ,EAIT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEnF,MAAM,OAAO,yBAAyB;IAUpC,YAAY,SAAc;QATlB,oBAAe,GAAuB,IAAI,CAAC;QAC3C,uBAAkB,GAAuB,IAAI,CAAC;QAC9C,uBAAkB,GAAkB,IAAI,CAAC;QAEzC,eAAU,GAAuB,IAAI,CAAC;QACtC,sBAAiB,GAAwB,IAAI,CAAC;QAC9C,qBAAgB,GAAc,QAAQ,CAAC;QACvC,0BAAqB,GAA0B,IAAI,CAAC;QAG1D,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAEO,2BAA2B;QACjC,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAChD,SAAS,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC;QACtC,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QAChC,SAAS,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC;QACvC,SAAS,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC;QAC/B,SAAS,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC;QAClC,SAAS,CAAC,SAAS,GAAG,kCAAkC,CAAC;QACzD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,oBAAoB;QAClB,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe;YAAE,OAAO;QAErE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,yBAAyB,EAAE,CAAC;IACnC,CAAC;IAEO,iBAAiB;QACvB,IAAI,IAAI,CAAC,kBAAkB,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAE7D,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC;QACjD,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC;QACjD,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC;QACvC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;QAExC,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC;QAElC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC;QAE5D,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC;IAC7C,CAAC;IAEO,KAAK,CAAC,yBAAyB;QACrC,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAElC,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,CAAC;QACvE,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;QAE7C,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,MAAM,IAAI,CAAC,2BAA2B,CAChF,gBAAgB,EAChB,eAAe,CAChB,CAAC;YAEF,IAAI,CAAC,uBAAuB,CAAC,eAAe,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;QAEnG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,qEAAqE,EAAE,KAAK,CAAC,CAAC;YAC3F,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,2BAA2B,CACvC,gBAA6B,EAC7B,eAA4B;QAE5B,MAAM,QAAQ,GAAG,WAAW,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;QACpE,4EAA4E;QAC5E,MAAM,aAAa,GAAG,WAAW,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;QACxE,MAAM,gBAAgB,GAAG,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC;QAChF,MAAM,UAAU,GAAG,IAAI,CAAC,0BAA0B,CAAC,QAAQ,CAAC,CAAC;QAE7D,OAAO,MAAM,eAAe,CAAC,gBAAgB,EAAE,eAAe,EAAE;YAC9D,SAAS,EAAE,gBAAgB;YAC3B,QAAQ,EAAE,OAAO;YACjB,UAAU;YACV,QAAQ,EAAE,IAAI,CAAC,oBAAoB,EAAE;SACtC,CAAC,CAAC;IACL,CAAC;IAEO,0BAA0B,CAAC,QAA+B;QAChE,OAAO;YACL,MAAM,CAAC,CAAC,CAAC;YACT,IAAI,CAAC;gBACH,KAAK,EAAE,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC3C,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,QAAQ;aACnB,CAAC;YACF,IAAI,CAAC;gBACH,kBAAkB,EAAE,CAAC,cAAc,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,CAAC;gBAC3F,gBAAgB,EAAE,SAAS;gBAC3B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,QAAQ;aACnB,CAAC;YACF,KAAK,CAAC;gBACJ,OAAO,EAAE,EAAE;gBACX,SAAS,EAAE,IAAI;gBACf,QAAQ,EAAE,QAAQ;aACnB,CAAC;SACH,CAAC;IACJ,CAAC;IAEO,oBAAoB,CAAC,EAAE,cAAc,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAK9E;QACC,MAAM,SAAS,GAAG,WAAW,CAAC,sBAAsB,CAClD,KAAK,CAAC,SAAS,EACf,MAAM,CAAC,WAAW,EAClB,IAAI,CAAC,gBAAgB,CACtB,CAAC;QAEF,4DAA4D;QAC5D,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,SAAS,IAAI,CAAC;QAErD,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,6BAA6B,EAAE,GAAG,cAAc,IAAI,CAAC,CAAC;QAC1F,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,8BAA8B,EAAE,GAAG,SAAS,IAAI,CAAC,CAAC;IACxF,CAAC;IAEO,oBAAoB;QAC1B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,uBAAuB,CAC7B,eAA4B,EAC5B,gBAA6B,EAC7B,CAAS,EACT,CAAS,EACT,SAAoB,EACpB,cAA8B;QAE9B,wDAAwD;QACxD,iFAAiF;QACjF,MAAM,aAAa,GAAG,gBAAgB,CAAC,qBAAqB,EAAE,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE;YACnC,IAAI,EAAE,GAAG,aAAa,CAAC,IAAI,IAAI;YAC/B,GAAG,EAAE,GAAG,CAAC,IAAI;YACb,QAAQ,EAAE,OAAO;YACjB,aAAa,EAAE,MAAM;YACrB,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;QAEH,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAClC,IAAI,CAAC,qBAAqB,GAAG,cAAc,CAAC;QAE5C,WAAW,CAAC,kBAAkB,CAAC,eAAe,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;QAE3E,MAAM,cAAc,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,eAAe,CAAC,SAAS,GAAG,mDAAmD,cAAc,EAAE,CAAC;IAClG,CAAC;IAEO,mBAAmB;QACzB,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAElC,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,CAAC;QACvE,MAAM,IAAI,GAAG,gBAAgB,CAAC,qBAAqB,EAAE,CAAC;QACtD,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,IAAI,GAAG,CAAC;QAElD,MAAM,UAAU,GAAG,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC;QAE5B,IAAI,WAAmB,CAAC;QACxB,IAAI,cAAsB,CAAC;QAC3B,IAAI,SAAiB,CAAC;QAEtB,IAAI,UAAU,GAAG,UAAU,EAAE,CAAC;YAC5B,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;YAC3C,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,SAAS,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACrD,cAAc,GAAG,KAAK,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;YAC3C,WAAW,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;YAC9B,cAAc,GAAG,QAAQ,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC;QACnD,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,WAAW,IAAI,CAAC;QACpD,gFAAgF;QAChF,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC;QAC1C,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC;QAC7C,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,SAAS,IAAI,CAAC;QACxD,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC;QAClD,IAAI,CAAC,eAAe,CAAC,SAAS,GAAG,mDAAmD,cAAc,EAAE,CAAC;QAErG,IAAI,CAAC,iCAAiC,CAAC,IAAI,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;IAC5E,CAAC;IAEO,iCAAiC,CAAC,IAAa,EAAE,WAAmB,EAAE,cAAsB;QAClG,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAElC,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC;QAC1C,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC;QAExC,IAAI,eAAuB,CAAC;QAC5B,IAAI,cAAc,KAAK,KAAK,EAAE,CAAC;YAC7B,eAAe,GAAG,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,eAAe,GAAG,cAAc,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACtD,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QAE5E,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,8BAA8B,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9G,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,6BAA6B,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9G,CAAC;IAED,0BAA0B;QACxB,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAClD,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,kBAAkB;QAChB,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAClD,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IAEO,0BAA0B;QAChC,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAErD,IAAI,CAAC,4BAA4B,EAAE,CAAC;QAEpC,IAAI,CAAC,iBAAiB,GAAG,UAAU,CACjC,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,eAAe,EACpB,GAAG,EAAE;YACH,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACnC,CAAC,EACD;YACE,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;YACnB,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,IAAI;SACrB,CACF,CAAC;IACJ,CAAC;IAEO,4BAA4B;QAClC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAChC,CAAC;IACH,CAAC;IAEO,sBAAsB;QAC5B,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAElC,MAAM,OAAO,GAAG,WAAW,CAAC,eAAe,EAAE,CAAC;QAE9C,IAAI,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC;YAAE,OAAO;QAE7C,MAAM,eAAe,GAAI,IAAI,CAAC,SAAS,CAAC,WAAmB,CAAC,MAAM,CAAC;QACnE,IAAI,CAAC,eAAe;YAAE,OAAO;QAE7B,MAAM,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACrD,YAAY,CAAC,EAAE,GAAG,OAAO,CAAC;QAC1B,YAAY,CAAC,WAAW,GAAG,WAAW,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;QAE3E,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;QAEvC,IAAI,CAAC,eAAuB,CAAC,iBAAiB,GAAG,OAAO,CAAC;IAC5D,CAAC;IAEO,yBAAyB;QAC/B,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAClC,IAAI,CAAC,sBAAsB,EAAE,CAAC;IAChC,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM;YAAE,OAAO;QAEnC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE;YACtC,UAAU,CAAC,GAAG,EAAE;gBACd,wEAAwE;gBACxE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,aAAa,CAAC,eAAe,CAAgB;oBACxE,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,eAAe,CAAgB,CAAC;gBAC1E,IAAI,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;oBAC1C,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,aAA4B,CAAC;oBAE5D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBAE1C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,2BAA2B,EAAE,CAAC;oBAC1D,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAClD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;oBAEhD,IAAI,CAAC,yBAAyB,EAAE,CAAC;oBAEjC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;oBACnC,IAAI,CAAC,oBAAoB,EAAE,CAAC;oBAE5B,IAAI,CAAC,yBAAyB,EAAE,CAAC;oBAEjC,IAAI,CAAC,0BAA0B,EAAE,CAAC;oBAElC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC,EAAE,EAAE,CAAC,CAAC;QACT,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB;QACtB,OAAO,kBAAkB,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7D,CAAC;IAEO,yBAAyB;QAC/B,gBAAgB,CAAC,yBAAyB,CAAC,IAAI,CAAC,UAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/E,CAAC;IAED,mBAAmB;QACjB,IAAI,CAAC,4BAA4B,EAAE,CAAC;QAEpC,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,CAAC;YAC5D,MAAM,eAAe,GAAI,IAAI,CAAC,eAAuB,CAAC,iBAAiB,CAAC;YACxE,IAAI,eAAe,EAAE,CAAC;gBACpB,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;gBAC9D,IAAI,YAAY,EAAE,CAAC;oBACjB,YAAY,CAAC,MAAM,EAAE,CAAC;gBACxB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAEzE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAC/B,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC;IACpC,CAAC;IAED,IAAI,sBAAsB;QACxB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,mBAAmB;QACjB,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;IACjC,CAAC;IAED,mBAAmB;QACjB,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC5C,kBAAkB,CAAC,qBAAqB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1E,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACnC,CAAC;IACH,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED,wBAAwB;QACtB,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,iBAAiB,KAAK,IAAI,CAAC;IACzC,CAAC;IAED,oBAAoB;QAClB,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,qBAAqB;YAAE,OAAO,IAAI,CAAC;QAEtE,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,CAAC;QACvE,MAAM,IAAI,GAAG,gBAAgB,CAAC,qBAAqB,EAAE,CAAC;QACtD,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC;QAC1C,MAAM,UAAU,GAAG,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC;QAE5B,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAE3D,IAAI,OAAO,IAAI,UAAU,GAAG,UAAU;YAAE,OAAO,KAAK,CAAC;QACrD,IAAI,OAAO,IAAI,UAAU,GAAG,UAAU;YAAE,OAAO,KAAK,CAAC;QAErD,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import { \n autoUpdate, \n computePosition, \n flip, \n offset, \n shift, \n size, \n platform,\n type Placement,\n type MiddlewareData,\n type ComputePositionConfig\n} from '@floating-ui/dom';\nimport { PortalUtils, PortalContentUtils, PortalEventUtils } from './portal-utils';\n\nexport class AutoCompletePortalManager {\n private portalContainer: HTMLElement | null = null;\n private originalMenuParent: HTMLElement | null = null;\n private measuredMenuHeight: number | null = null;\n private component: any;\n private clonedMenu: HTMLElement | null = null;\n private cleanupAutoUpdate: (() => void) | null = null;\n private currentPlacement: Placement = 'bottom';\n private currentMiddlewareData: MiddlewareData | null = null;\n\n constructor(component: any) {\n this.component = component;\n }\n\n private createPortalAppendContainer(): HTMLElement {\n const container = document.createElement('div');\n container.style.position = 'absolute';\n container.style.zIndex = '9999';\n container.style.pointerEvents = 'none';\n container.style.width = 'auto';\n container.style.minWidth = 'auto';\n container.className = 'nile-auto-complete-portal-append';\n return container;\n }\n\n positionPortalAppend(): void {\n if (!this.portalContainer || !this.component.dropdownElement) return;\n\n this.measureMenuHeight();\n this.computeFloatingUIPosition();\n }\n\n private measureMenuHeight(): void {\n if (this.measuredMenuHeight || !this.portalContainer) return;\n\n this.portalContainer.style.position = 'absolute';\n this.portalContainer.style.visibility = 'hidden';\n this.portalContainer.style.top = '0px';\n this.portalContainer.style.left = '0px';\n \n this.portalContainer.offsetHeight;\n \n this.measuredMenuHeight = this.portalContainer.offsetHeight;\n \n this.portalContainer.style.visibility = '';\n }\n\n private async computeFloatingUIPosition(): Promise<void> {\n if (!this.portalContainer) return;\n\n const referenceElement = this.component.inputElement || this.component;\n const floatingElement = this.portalContainer;\n\n try {\n const { x, y, placement, middlewareData } = await this.calculateFloatingUIPosition(\n referenceElement,\n floatingElement\n );\n\n this.applyFloatingUIPosition(floatingElement, referenceElement, x, y, placement, middlewareData);\n\n } catch (error) {\n console.warn('Floating UI positioning failed, falling back to simple positioning:', error);\n this.fallbackPositioning();\n }\n }\n\n private async calculateFloatingUIPosition(\n referenceElement: HTMLElement,\n floatingElement: HTMLElement\n ): Promise<{ x: number; y: number; placement: Placement; middlewareData: MiddlewareData }> {\n const boundary = PortalUtils.findBoundaryElements(referenceElement);\n // Use 'bottom-start' or 'top-start' to align left edges for auto-width menu\n const basePlacement = PortalUtils.getOptimalPlacement(referenceElement);\n const initialPlacement = basePlacement === 'top' ? 'top-start' : 'bottom-start';\n const middleware = this.createFloatingUIMiddleware(boundary);\n\n return await computePosition(referenceElement, floatingElement, {\n placement: initialPlacement,\n strategy: 'fixed',\n middleware,\n platform: this.createCustomPlatform()\n });\n }\n\n private createFloatingUIMiddleware(boundary: Element[] | undefined): ComputePositionConfig['middleware'] {\n return [\n offset(4),\n size({\n apply: this.handleSizeMiddleware.bind(this),\n padding: 10,\n boundary: boundary\n }),\n flip({\n fallbackPlacements: ['bottom-start', 'top-start', 'bottom', 'top', 'bottom-end', 'top-end'],\n fallbackStrategy: 'bestFit',\n padding: 10,\n boundary: boundary\n }),\n shift({\n padding: 10,\n crossAxis: true,\n boundary: boundary\n })\n ];\n }\n\n private handleSizeMiddleware({ availableWidth, availableHeight, elements, rects }: {\n availableWidth: number;\n availableHeight: number;\n elements: { floating: HTMLElement };\n rects: { reference: { x: number; y: number; width: number; height: number } };\n }): void {\n const maxHeight = PortalUtils.calculateOptimalHeight(\n rects.reference,\n window.innerHeight,\n this.currentPlacement\n );\n\n // elements.floating.style.maxWidth = `${availableWidth}px`;\n elements.floating.style.maxHeight = `${maxHeight}px`;\n \n elements.floating.style.setProperty('--auto-size-available-width', `${availableWidth}px`);\n elements.floating.style.setProperty('--auto-size-available-height', `${maxHeight}px`);\n }\n\n private createCustomPlatform() {\n return platform;\n }\n\n private applyFloatingUIPosition(\n floatingElement: HTMLElement,\n referenceElement: HTMLElement,\n x: number,\n y: number,\n placement: Placement,\n middlewareData: MiddlewareData\n ): void {\n // For auto-complete, align left edge with input element\n // Use reference element's left position, not Floating UI's x (which might shift)\n const referenceRect = referenceElement.getBoundingClientRect();\n \n Object.assign(floatingElement.style, {\n left: `${referenceRect.left}px`,\n top: `${y}px`,\n position: 'fixed',\n pointerEvents: 'auto',\n width: 'auto',\n minWidth: 'auto'\n });\n\n this.currentPlacement = placement;\n this.currentMiddlewareData = middlewareData;\n \n PortalUtils.applyCollisionData(floatingElement, middlewareData, placement);\n \n const placementClass = placement.split('-')[0];\n floatingElement.className = `nile-auto-complete-portal-append menu__listbox--${placementClass}`;\n }\n\n private fallbackPositioning(): void {\n if (!this.portalContainer) return;\n\n const referenceElement = this.component.inputElement || this.component;\n const rect = referenceElement.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const menuHeight = this.measuredMenuHeight || 200;\n \n const spaceBelow = viewportHeight - rect.bottom;\n const spaceAbove = rect.top;\n \n let topPosition: number;\n let placementClass: string;\n let maxHeight: number;\n \n if (spaceAbove > spaceBelow) {\n maxHeight = Math.max(spaceAbove - 20, 100);\n topPosition = Math.max(rect.top - maxHeight - 4, 10);\n placementClass = 'top';\n } else {\n maxHeight = Math.max(spaceBelow - 20, 100);\n topPosition = rect.bottom + 4;\n placementClass = 'bottom';\n }\n\n this.portalContainer.style.left = `${rect.left}px`;\n this.portalContainer.style.top = `${topPosition}px`;\n // Let the menu auto-size based on its content, don't force width to match input\n this.portalContainer.style.width = 'auto';\n this.portalContainer.style.minWidth = 'auto';\n this.portalContainer.style.maxHeight = `${maxHeight}px`;\n this.portalContainer.style.pointerEvents = 'auto';\n this.portalContainer.className = `nile-auto-complete-portal-append menu__listbox--${placementClass}`;\n \n this.calculateAndSetAutoSizeProperties(rect, topPosition, placementClass);\n }\n\n private calculateAndSetAutoSizeProperties(rect: DOMRect, topPosition: number, placementClass: string): void {\n if (!this.portalContainer) return;\n\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n \n let availableHeight: number;\n if (placementClass === 'top') {\n availableHeight = rect.top - 10;\n } else {\n availableHeight = viewportHeight - rect.bottom - 10;\n }\n \n const availableWidth = Math.min(rect.width, viewportWidth - rect.left - 10);\n \n this.portalContainer.style.setProperty('--auto-size-available-height', `${Math.max(availableHeight, 100)}px`);\n this.portalContainer.style.setProperty('--auto-size-available-width', `${Math.max(availableWidth, 200)}px`);\n }\n\n updatePortalAppendPosition(): void {\n if (this.component.portal && this.portalContainer) {\n this.positionPortalAppend();\n }\n }\n\n handleWindowResize(): void {\n if (this.component.portal && this.portalContainer) {\n this.positionPortalAppend();\n }\n }\n\n private setupAutoUpdatePositioning(): void {\n if (!this.portalContainer || !this.component) return;\n\n this.cleanupAutoUpdatePositioning();\n\n this.cleanupAutoUpdate = autoUpdate(\n this.component,\n this.portalContainer,\n () => {\n this.computeFloatingUIPosition();\n },\n {\n ancestorScroll: true,\n ancestorResize: true,\n elementResize: true,\n layoutShift: true,\n animationFrame: true\n }\n );\n }\n\n private cleanupAutoUpdatePositioning(): void {\n if (this.cleanupAutoUpdate) {\n this.cleanupAutoUpdate();\n this.cleanupAutoUpdate = null;\n }\n }\n\n private injectStylesToDocument(): void {\n if (!this.portalContainer) return;\n\n const styleId = PortalUtils.generateStyleId();\n \n if (document.getElementById(styleId)) return;\n\n const componentStyles = (this.component.constructor as any).styles;\n if (!componentStyles) return;\n\n const styleElement = document.createElement('style');\n styleElement.id = styleId;\n styleElement.textContent = PortalUtils.extractStylesAsCSS(componentStyles);\n \n document.head.appendChild(styleElement);\n \n (this.portalContainer as any).__injectedStyleId = styleId;\n }\n\n private adoptStylesToPortalAppend(): void {\n if (!this.portalContainer) return;\n this.injectStylesToDocument();\n }\n\n setupPortalAppend(): void {\n if (!this.component.portal) return;\n\n this.component.updateComplete.then(() => {\n setTimeout(() => {\n // Try to find menu in shadow root first, then fallback to querySelector\n const menu = this.component.shadowRoot?.querySelector('#content-menu') as HTMLElement ||\n this.component.querySelector('#content-menu') as HTMLElement;\n if (menu && this.component.isDropdownOpen) {\n this.originalMenuParent = menu.parentElement as HTMLElement;\n \n this.clonedMenu = this.createPortalMenu();\n \n this.portalContainer = this.createPortalAppendContainer();\n this.portalContainer.appendChild(this.clonedMenu);\n document.body.appendChild(this.portalContainer);\n \n this.adoptStylesToPortalAppend();\n \n this.clonedMenu.style.display = '';\n this.positionPortalAppend();\n \n this.setupPortalEventListeners();\n \n this.setupAutoUpdatePositioning();\n \n window.addEventListener('resize', this.handleWindowResize.bind(this));\n }\n }, 10);\n });\n }\n\n private createPortalMenu(): HTMLElement {\n return PortalContentUtils.createPortalMenu(this.component);\n }\n\n private setupPortalEventListeners(): void {\n PortalEventUtils.setupPortalEventListeners(this.clonedMenu!, this.component);\n }\n\n cleanupPortalAppend(): void {\n this.cleanupAutoUpdatePositioning();\n \n if (this.portalContainer && this.portalContainer.parentNode) {\n const injectedStyleId = (this.portalContainer as any).__injectedStyleId;\n if (injectedStyleId) {\n const styleElement = document.getElementById(injectedStyleId);\n if (styleElement) {\n styleElement.remove();\n }\n }\n \n this.portalContainer.parentNode.removeChild(this.portalContainer);\n }\n \n window.removeEventListener('resize', this.handleWindowResize.bind(this));\n \n this.portalContainer = null;\n this.originalMenuParent = null;\n this.clonedMenu = null;\n this.measuredMenuHeight = null;\n this.currentPlacement = 'bottom';\n this.currentMiddlewareData = null;\n }\n\n get portalContainerElement(): HTMLElement | null {\n return this.portalContainer;\n }\n\n resetMeasuredHeight(): void {\n this.measuredMenuHeight = null;\n }\n\n updatePortalOptions(): void {\n if (this.portalContainer && this.clonedMenu) {\n PortalContentUtils.updatePortalMenuItems(this.clonedMenu, this.component);\n this.forceReposition();\n }\n }\n\n forceReposition(): void {\n if (this.portalContainer) {\n this.computeFloatingUIPosition();\n }\n }\n\n getCurrentPlacement(): Placement {\n return this.currentPlacement;\n }\n\n getCurrentMiddlewareData(): MiddlewareData | null {\n return this.currentMiddlewareData;\n }\n\n isUsingFloatingUI(): boolean {\n return this.cleanupAutoUpdate !== null;\n }\n\n isPositioningOptimal(): boolean {\n if (!this.portalContainer || !this.currentMiddlewareData) return true;\n\n const referenceElement = this.component.inputElement || this.component;\n const rect = referenceElement.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const spaceBelow = viewportHeight - rect.bottom;\n const spaceAbove = rect.top;\n \n const isAbove = this.currentPlacement.startsWith('top');\n const isBelow = this.currentPlacement.startsWith('bottom');\n \n if (isAbove && spaceBelow > spaceAbove) return false;\n if (isBelow && spaceAbove > spaceBelow) return false;\n \n return true;\n }\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import { type Placement, type MiddlewareData } from '@floating-ui/dom';
2
+ export declare class PortalUtils {
3
+ static calculateAvailableSpace(referenceElement: HTMLElement): {
4
+ spaceAbove: number;
5
+ spaceBelow: number;
6
+ viewportHeight: number;
7
+ };
8
+ static getOptimalPlacement(referenceElement: HTMLElement): Placement;
9
+ static findBoundaryElements(component: HTMLElement): Element[] | undefined;
10
+ static calculateOptimalHeight(referenceRect: {
11
+ x: number;
12
+ y: number;
13
+ width: number;
14
+ height: number;
15
+ }, viewportHeight: number, placement: Placement): number;
16
+ static extractStylesAsCSS(styles: any): string;
17
+ static generateStyleId(): string;
18
+ static isPositioningOptimal(placement: Placement, referenceElement: HTMLElement): boolean;
19
+ static applyCollisionData(element: HTMLElement, middlewareData: MiddlewareData, placement: Placement): void;
20
+ }
21
+ export declare class PortalContentUtils {
22
+ static createBaseMenu(component: any): HTMLElement;
23
+ static addMenuItems(menu: HTMLElement, component: any): void;
24
+ static createMenuItem(item: any, component: any): HTMLElement;
25
+ static createPortalMenu(component: any): HTMLElement;
26
+ static updatePortalMenuItems(clonedMenu: HTMLElement, component: any): void;
27
+ }
28
+ export declare class PortalEventUtils {
29
+ static setupPortalEventListeners(clonedMenu: HTMLElement, component: any): void;
30
+ static setupMenuSelectListeners(clonedMenu: HTMLElement, component: any): void;
31
+ }
@@ -0,0 +1,166 @@
1
+ export class PortalUtils {
2
+ static calculateAvailableSpace(referenceElement) {
3
+ const rect = referenceElement.getBoundingClientRect();
4
+ const viewportHeight = window.innerHeight;
5
+ const spaceBelow = viewportHeight - rect.bottom;
6
+ const spaceAbove = rect.top;
7
+ return { spaceAbove, spaceBelow, viewportHeight };
8
+ }
9
+ static getOptimalPlacement(referenceElement) {
10
+ const { spaceAbove, spaceBelow } = this.calculateAvailableSpace(referenceElement);
11
+ if (spaceBelow < 200 && spaceAbove > spaceBelow) {
12
+ return 'top';
13
+ }
14
+ return 'bottom';
15
+ }
16
+ static findBoundaryElements(component) {
17
+ const boundaryElements = [];
18
+ let currentElement = component.parentElement;
19
+ while (currentElement && currentElement !== document.body) {
20
+ const computedStyle = window.getComputedStyle(currentElement);
21
+ const overflow = computedStyle.overflow;
22
+ const overflowY = computedStyle.overflowY;
23
+ const overflowX = computedStyle.overflowX;
24
+ if (overflow === 'auto' || overflow === 'scroll' ||
25
+ overflowY === 'auto' || overflowY === 'scroll' ||
26
+ overflowX === 'auto' || overflowX === 'scroll') {
27
+ boundaryElements.push(currentElement);
28
+ }
29
+ if (currentElement.hasAttribute('data-floating-boundary') ||
30
+ currentElement.classList.contains('floating-boundary') ||
31
+ currentElement.classList.contains('scroll-container')) {
32
+ boundaryElements.push(currentElement);
33
+ }
34
+ currentElement = currentElement.parentElement;
35
+ }
36
+ return boundaryElements.length > 0 ? boundaryElements : undefined;
37
+ }
38
+ static calculateOptimalHeight(referenceRect, viewportHeight, placement) {
39
+ const spaceBelow = viewportHeight - (referenceRect.y + referenceRect.height);
40
+ const spaceAbove = referenceRect.y;
41
+ if (spaceAbove > spaceBelow) {
42
+ return Math.max(spaceAbove - 20, 100);
43
+ }
44
+ else if (spaceBelow > spaceAbove) {
45
+ return Math.max(spaceBelow - 20, 100);
46
+ }
47
+ return Math.max(Math.min(spaceAbove, spaceBelow) - 20, 100);
48
+ }
49
+ static extractStylesAsCSS(styles) {
50
+ if (typeof styles === 'string') {
51
+ return styles;
52
+ }
53
+ if (Array.isArray(styles)) {
54
+ return styles.map(style => this.extractStylesAsCSS(style)).join('\n');
55
+ }
56
+ if (styles && typeof styles === 'object' && styles.cssText) {
57
+ return styles.cssText;
58
+ }
59
+ return '';
60
+ }
61
+ static generateStyleId() {
62
+ return `nile-auto-complete-styles-${Math.random().toString(36).substring(2, 11)}`;
63
+ }
64
+ static isPositioningOptimal(placement, referenceElement) {
65
+ const { spaceAbove, spaceBelow } = this.calculateAvailableSpace(referenceElement);
66
+ const isAbove = placement.startsWith('top');
67
+ const isBelow = placement.startsWith('bottom');
68
+ if (isAbove && spaceBelow > spaceAbove)
69
+ return false;
70
+ if (isBelow && spaceAbove > spaceBelow)
71
+ return false;
72
+ return true;
73
+ }
74
+ static applyCollisionData(element, middlewareData, placement) {
75
+ if (middlewareData.flip) {
76
+ const { overflows } = middlewareData.flip;
77
+ element.setAttribute('data-placement', placement);
78
+ if (overflows && overflows.length > 0) {
79
+ const overflowPlacements = overflows.map(overflow => overflow.placement).join(',');
80
+ element.setAttribute('data-overflow', overflowPlacements);
81
+ }
82
+ else {
83
+ element.removeAttribute('data-overflow');
84
+ }
85
+ }
86
+ if (middlewareData.shift) {
87
+ const { x, y } = middlewareData.shift;
88
+ if (x !== undefined && y !== undefined && (x !== 0 || y !== 0)) {
89
+ element.setAttribute('data-shift', `${x},${y}`);
90
+ }
91
+ else {
92
+ element.removeAttribute('data-shift');
93
+ }
94
+ }
95
+ if (middlewareData.size) {
96
+ const { availableWidth, availableHeight } = middlewareData.size;
97
+ if (availableWidth !== undefined) {
98
+ element.setAttribute('data-available-width', availableWidth.toString());
99
+ }
100
+ if (availableHeight !== undefined) {
101
+ element.setAttribute('data-available-height', availableHeight.toString());
102
+ }
103
+ }
104
+ }
105
+ }
106
+ export class PortalContentUtils {
107
+ static createBaseMenu(component) {
108
+ const menu = document.createElement('nile-menu');
109
+ menu.id = 'content-menu';
110
+ menu.className = component.enableVirtualScroll ? 'virtualized__menu' : '';
111
+ if (component.enableVirtualScroll) {
112
+ menu.setAttribute('exportparts', 'menu__items-wrapper:options__wrapper');
113
+ }
114
+ else {
115
+ menu.setAttribute('exportparts', 'menu__items-wrapper:options__wrapper');
116
+ }
117
+ return menu;
118
+ }
119
+ static addMenuItems(menu, component) {
120
+ const menuItems = component.menuItems || [];
121
+ menuItems.forEach((item) => {
122
+ const menuItem = this.createMenuItem(item, component);
123
+ menu.appendChild(menuItem);
124
+ });
125
+ }
126
+ static createMenuItem(item, component) {
127
+ const menuItem = document.createElement('nile-menu-item');
128
+ const value = component.renderItemFunction ? component.renderItemFunction(item) : item;
129
+ menuItem.setAttribute('value', String(value));
130
+ menuItem.innerHTML = String(value);
131
+ return menuItem;
132
+ }
133
+ static createPortalMenu(component) {
134
+ const menu = this.createBaseMenu(component);
135
+ this.addMenuItems(menu, component);
136
+ return menu;
137
+ }
138
+ static updatePortalMenuItems(clonedMenu, component) {
139
+ if (!clonedMenu)
140
+ return;
141
+ // Remove existing items
142
+ const existingItems = clonedMenu.querySelectorAll('nile-menu-item');
143
+ existingItems.forEach(item => item.remove());
144
+ // Add updated items
145
+ this.addMenuItems(clonedMenu, component);
146
+ }
147
+ }
148
+ export class PortalEventUtils {
149
+ static setupPortalEventListeners(clonedMenu, component) {
150
+ if (!clonedMenu)
151
+ return;
152
+ this.setupMenuSelectListeners(clonedMenu, component);
153
+ }
154
+ static setupMenuSelectListeners(clonedMenu, component) {
155
+ if (!clonedMenu)
156
+ return;
157
+ clonedMenu.addEventListener('nile-select', (event) => {
158
+ const customEvent = event;
159
+ if (component.handleSelect) {
160
+ // Call the component's handleSelect method directly
161
+ component.handleSelect(customEvent);
162
+ }
163
+ });
164
+ }
165
+ }
166
+ //# sourceMappingURL=portal-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal-utils.js","sourceRoot":"","sources":["../../../src/nile-auto-complete/portal-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { \n type Placement,\n type MiddlewareData\n} from '@floating-ui/dom';\n\nexport class PortalUtils {\n static calculateAvailableSpace(referenceElement: HTMLElement): {\n spaceAbove: number;\n spaceBelow: number;\n viewportHeight: number;\n } {\n const rect = referenceElement.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const spaceBelow = viewportHeight - rect.bottom;\n const spaceAbove = rect.top;\n \n return { spaceAbove, spaceBelow, viewportHeight };\n }\n\n static getOptimalPlacement(referenceElement: HTMLElement): Placement {\n const { spaceAbove, spaceBelow } = this.calculateAvailableSpace(referenceElement);\n \n if (spaceBelow < 200 && spaceAbove > spaceBelow) {\n return 'top';\n }\n \n return 'bottom';\n }\n\n static findBoundaryElements(component: HTMLElement): Element[] | undefined {\n const boundaryElements: Element[] = [];\n \n let currentElement = component.parentElement;\n \n while (currentElement && currentElement !== document.body) {\n const computedStyle = window.getComputedStyle(currentElement);\n const overflow = computedStyle.overflow;\n const overflowY = computedStyle.overflowY;\n const overflowX = computedStyle.overflowX;\n \n if (overflow === 'auto' || overflow === 'scroll' || \n overflowY === 'auto' || overflowY === 'scroll' ||\n overflowX === 'auto' || overflowX === 'scroll') {\n boundaryElements.push(currentElement);\n }\n \n if (currentElement.hasAttribute('data-floating-boundary') ||\n currentElement.classList.contains('floating-boundary') ||\n currentElement.classList.contains('scroll-container')) {\n boundaryElements.push(currentElement);\n }\n \n currentElement = currentElement.parentElement;\n }\n \n return boundaryElements.length > 0 ? boundaryElements : undefined;\n }\n\n static calculateOptimalHeight(\n referenceRect: { x: number; y: number; width: number; height: number },\n viewportHeight: number,\n placement: Placement\n ): number {\n const spaceBelow = viewportHeight - (referenceRect.y + referenceRect.height);\n const spaceAbove = referenceRect.y;\n \n if (spaceAbove > spaceBelow) {\n return Math.max(spaceAbove - 20, 100);\n }\n else if (spaceBelow > spaceAbove) {\n return Math.max(spaceBelow - 20, 100);\n }\n \n return Math.max(Math.min(spaceAbove, spaceBelow) - 20, 100);\n }\n\n static extractStylesAsCSS(styles: any): string {\n if (typeof styles === 'string') {\n return styles;\n }\n \n if (Array.isArray(styles)) {\n return styles.map(style => this.extractStylesAsCSS(style)).join('\\n');\n }\n \n if (styles && typeof styles === 'object' && styles.cssText) {\n return styles.cssText;\n }\n \n return '';\n }\n\n static generateStyleId(): string {\n return `nile-auto-complete-styles-${Math.random().toString(36).substring(2, 11)}`;\n }\n\n static isPositioningOptimal(\n placement: Placement,\n referenceElement: HTMLElement\n ): boolean {\n const { spaceAbove, spaceBelow } = this.calculateAvailableSpace(referenceElement);\n \n const isAbove = placement.startsWith('top');\n const isBelow = placement.startsWith('bottom');\n \n if (isAbove && spaceBelow > spaceAbove) return false;\n if (isBelow && spaceAbove > spaceBelow) return false;\n \n return true;\n }\n\n static applyCollisionData(\n element: HTMLElement,\n middlewareData: MiddlewareData,\n placement: Placement\n ): void {\n if (middlewareData.flip) {\n const { overflows } = middlewareData.flip;\n \n element.setAttribute('data-placement', placement);\n \n if (overflows && overflows.length > 0) {\n const overflowPlacements = overflows.map(overflow => overflow.placement).join(',');\n element.setAttribute('data-overflow', overflowPlacements);\n } else {\n element.removeAttribute('data-overflow');\n }\n }\n\n if (middlewareData.shift) {\n const { x, y } = middlewareData.shift;\n \n if (x !== undefined && y !== undefined && (x !== 0 || y !== 0)) {\n element.setAttribute('data-shift', `${x},${y}`);\n } else {\n element.removeAttribute('data-shift');\n }\n }\n\n if (middlewareData.size) {\n const { availableWidth, availableHeight } = middlewareData.size;\n \n if (availableWidth !== undefined) {\n element.setAttribute('data-available-width', availableWidth.toString());\n }\n if (availableHeight !== undefined) {\n element.setAttribute('data-available-height', availableHeight.toString());\n }\n }\n }\n}\n\nexport class PortalContentUtils {\n static createBaseMenu(component: any): HTMLElement {\n const menu = document.createElement('nile-menu');\n menu.id = 'content-menu';\n menu.className = component.enableVirtualScroll ? 'virtualized__menu' : '';\n \n if (component.enableVirtualScroll) {\n menu.setAttribute('exportparts', 'menu__items-wrapper:options__wrapper');\n } else {\n menu.setAttribute('exportparts', 'menu__items-wrapper:options__wrapper');\n }\n \n return menu;\n }\n\n static addMenuItems(menu: HTMLElement, component: any): void {\n const menuItems = component.menuItems || [];\n \n menuItems.forEach((item: any) => {\n const menuItem = this.createMenuItem(item, component);\n menu.appendChild(menuItem);\n });\n }\n\n static createMenuItem(item: any, component: any): HTMLElement {\n const menuItem = document.createElement('nile-menu-item');\n const value = component.renderItemFunction ? component.renderItemFunction(item) : item;\n menuItem.setAttribute('value', String(value));\n menuItem.innerHTML = String(value);\n return menuItem;\n }\n\n static createPortalMenu(component: any): HTMLElement {\n const menu = this.createBaseMenu(component);\n this.addMenuItems(menu, component);\n return menu;\n }\n\n static updatePortalMenuItems(clonedMenu: HTMLElement, component: any): void {\n if (!clonedMenu) return;\n\n // Remove existing items\n const existingItems = clonedMenu.querySelectorAll('nile-menu-item');\n existingItems.forEach(item => item.remove());\n\n // Add updated items\n this.addMenuItems(clonedMenu, component);\n }\n}\n\nexport class PortalEventUtils {\n static setupPortalEventListeners(clonedMenu: HTMLElement, component: any): void {\n if (!clonedMenu) return;\n\n this.setupMenuSelectListeners(clonedMenu, component);\n }\n\n static setupMenuSelectListeners(clonedMenu: HTMLElement, component: any): void {\n if (!clonedMenu) return;\n\n clonedMenu.addEventListener('nile-select', (event: Event) => {\n const customEvent = event as CustomEvent;\n if (component.handleSelect) {\n // Call the component's handleSelect method directly\n component.handleSelect(customEvent);\n }\n });\n }\n}\n"]}
@@ -12,6 +12,7 @@ export declare class NileChip extends NileElement {
12
12
  tags: string[];
13
13
  inputValue: string;
14
14
  isDropdownOpen: boolean;
15
+ tooltips: (string | null)[];
15
16
  autoComplete: any;
16
17
  /** Sets the input to a warning state, changing its visual appearance. */
17
18
  warning: boolean;
@@ -35,6 +36,11 @@ export declare class NileChip extends NileElement {
35
36
  readonly: boolean;
36
37
  /** Disables the input. */
37
38
  disabled: boolean;
39
+ /**
40
+ * When true, the dropdown menu will be appended to the document body instead of the parent container.
41
+ * This is useful when the parent has overflow: hidden, clip-path, or transform applied.
42
+ */
43
+ portal: boolean;
38
44
  /** Virtual scroll in dropdown options. */
39
45
  enableVirtualScroll: boolean;
40
46
  autoCompleteOptions: any[];
@@ -47,6 +53,7 @@ export declare class NileChip extends NileElement {
47
53
  errorMessage: string;
48
54
  filterFunction: (item: string, searchedValue: string) => boolean;
49
55
  renderItemFunction: (item: any) => string;
56
+ showTooltip: boolean;
50
57
  protected updated(changedProperties: PropertyValues): void;
51
58
  private handleDocumentClick;
52
59
  connectedCallback(): void;