@aquera/nile-elements 1.4.8-beta-1.0 → 1.4.8-beta-1.2

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 (65) hide show
  1. package/README.md +4 -0
  2. package/demo/index.html +133 -33
  3. package/dist/index.cjs.js +1 -1
  4. package/dist/index.esm.js +1 -1
  5. package/dist/index.js +98 -71
  6. package/dist/nile-file-preview/nile-file-preview.css.cjs.js +1 -1
  7. package/dist/nile-file-preview/nile-file-preview.css.cjs.js.map +1 -1
  8. package/dist/nile-file-preview/nile-file-preview.css.esm.js +7 -3
  9. package/dist/nile-file-preview/nile-file-preview.template.cjs.js +1 -1
  10. package/dist/nile-file-preview/nile-file-preview.template.cjs.js.map +1 -1
  11. package/dist/nile-file-preview/nile-file-preview.template.esm.js +73 -64
  12. package/dist/nile-lite-tooltip/nile-lite-tooltip.cjs.js +1 -1
  13. package/dist/nile-lite-tooltip/nile-lite-tooltip.cjs.js.map +1 -1
  14. package/dist/nile-lite-tooltip/nile-lite-tooltip.esm.js +1 -1
  15. package/dist/nile-option/nile-option.cjs.js +1 -1
  16. package/dist/nile-option/nile-option.cjs.js.map +1 -1
  17. package/dist/nile-option/nile-option.css.cjs.js +1 -1
  18. package/dist/nile-option/nile-option.css.cjs.js.map +1 -1
  19. package/dist/nile-option/nile-option.css.esm.js +10 -0
  20. package/dist/nile-option/nile-option.esm.js +10 -7
  21. package/dist/nile-side-bar-action/index.cjs.js +1 -1
  22. package/dist/nile-side-bar-action/index.esm.js +1 -1
  23. package/dist/nile-side-bar-action/nile-side-bar-action.cjs.js +1 -1
  24. package/dist/nile-side-bar-action/nile-side-bar-action.cjs.js.map +1 -1
  25. package/dist/nile-side-bar-action/nile-side-bar-action.esm.js +4 -3
  26. package/dist/nile-side-bar-action/portal-manager.cjs.js +2 -0
  27. package/dist/nile-side-bar-action/portal-manager.cjs.js.map +1 -0
  28. package/dist/nile-side-bar-action/portal-manager.esm.js +1 -0
  29. package/dist/nile-side-bar-action/portal-utils.cjs.js +2 -0
  30. package/dist/nile-side-bar-action/portal-utils.cjs.js.map +1 -0
  31. package/dist/nile-side-bar-action/portal-utils.esm.js +1 -0
  32. package/dist/src/nile-file-preview/nile-file-preview.css.js +7 -3
  33. package/dist/src/nile-file-preview/nile-file-preview.css.js.map +1 -1
  34. package/dist/src/nile-file-preview/nile-file-preview.template.js +46 -37
  35. package/dist/src/nile-file-preview/nile-file-preview.template.js.map +1 -1
  36. package/dist/src/nile-lite-tooltip/nile-lite-tooltip.d.ts +2 -0
  37. package/dist/src/nile-lite-tooltip/nile-lite-tooltip.js +15 -0
  38. package/dist/src/nile-lite-tooltip/nile-lite-tooltip.js.map +1 -1
  39. package/dist/src/nile-option/nile-option.css.js +10 -0
  40. package/dist/src/nile-option/nile-option.css.js.map +1 -1
  41. package/dist/src/nile-option/nile-option.d.ts +1 -0
  42. package/dist/src/nile-option/nile-option.js +13 -5
  43. package/dist/src/nile-option/nile-option.js.map +1 -1
  44. package/dist/src/nile-side-bar-action/nile-side-bar-action.d.ts +8 -1
  45. package/dist/src/nile-side-bar-action/nile-side-bar-action.js +66 -12
  46. package/dist/src/nile-side-bar-action/nile-side-bar-action.js.map +1 -1
  47. package/dist/src/nile-side-bar-action/portal-manager.d.ts +43 -0
  48. package/dist/src/nile-side-bar-action/portal-manager.js +374 -0
  49. package/dist/src/nile-side-bar-action/portal-manager.js.map +1 -0
  50. package/dist/src/nile-side-bar-action/portal-utils.d.ts +32 -0
  51. package/dist/src/nile-side-bar-action/portal-utils.js +212 -0
  52. package/dist/src/nile-side-bar-action/portal-utils.js.map +1 -0
  53. package/dist/src/version.js +1 -1
  54. package/dist/src/version.js.map +1 -1
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +1 -1
  57. package/src/nile-file-preview/nile-file-preview.css.ts +7 -3
  58. package/src/nile-file-preview/nile-file-preview.template.ts +46 -37
  59. package/src/nile-lite-tooltip/nile-lite-tooltip.ts +15 -0
  60. package/src/nile-option/nile-option.css.ts +10 -0
  61. package/src/nile-option/nile-option.ts +11 -5
  62. package/src/nile-side-bar-action/nile-side-bar-action.ts +74 -15
  63. package/src/nile-side-bar-action/portal-manager.ts +489 -0
  64. package/src/nile-side-bar-action/portal-utils.ts +270 -0
  65. package/vscode-html-custom-data.json +22 -3
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent nile-elements following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "nile-elements",
6
- "version": "1.4.8-beta-1.0",
6
+ "version": "1.4.8-beta-1.2",
7
7
  "main": "dist/src/index.js",
8
8
  "type": "module",
9
9
  "module": "dist/src/index.js",
@@ -13,6 +13,7 @@ import {css} from 'lit';
13
13
  export const styles = css`
14
14
  :host {
15
15
  display: inline-block;
16
+ width: 100%;
16
17
  }
17
18
 
18
19
  * {
@@ -36,7 +37,7 @@ export const styles = css`
36
37
 
37
38
  .horizontal-div {
38
39
  max-height: 62px;
39
- width: 648px;
40
+ width: 100%;
40
41
  min-width: 230px;
41
42
  padding: 12px;
42
43
  display: flex;
@@ -263,7 +264,7 @@ export const styles = css`
263
264
  white-space: nowrap;
264
265
  text-overflow: ellipsis;
265
266
  overflow: hidden;
266
- width: 500px;
267
+ width: 100%;
267
268
  }
268
269
 
269
270
  .preview-file-info p:last-of-type{
@@ -274,7 +275,7 @@ export const styles = css`
274
275
  white-space: nowrap;
275
276
  text-overflow: ellipsis;
276
277
  overflow: hidden;
277
- width: 500px;
278
+ width: 100%;
278
279
  }
279
280
 
280
281
  .no-preview > nile-icon:hover {
@@ -584,6 +585,9 @@ export const styles = css`
584
585
  li {
585
586
  list-style-type: none;
586
587
  }
588
+ .preview-file-info p {
589
+ width: 100%;
590
+ }
587
591
  `;
588
592
 
589
593
  export default [styles];
@@ -16,16 +16,16 @@ import { NileFilePreview } from './nile-file-preview';
16
16
  return html`
17
17
  <div class="uploading" part="horizontal-uploading-state">
18
18
  <nile-loader width="24" height="24"></nile-loader>
19
- <div class="progress-bar-container">
20
- <div class="progress-bar-percent">
21
- <p>Uploading File...</p>
22
- <p>${uploadStatus}%</p>
19
+ <div class="progress-bar-container" part="horizontal-progress-bar-container">
20
+ <div class="progress-bar-percent" part="horizontal-progress-bar-percent">
21
+ <p part="horizontal-progress-bar-percent-text">Uploading File...</p>
22
+ <p part="horizontal-progress-bar-percent-value">${uploadStatus}%</p>
23
23
  </div>
24
24
  <nile-progress-bar
25
25
  part="horizontal-progress-bar"
26
26
  value="${uploadStatus}"
27
27
  ></nile-progress-bar>
28
- <p class="horizontal-file-name">${file.name}</p>
28
+ <p class="horizontal-file-name" part="horizontal-file-name">${file.name}</p>
29
29
  </div>
30
30
  <slot @click=${(e: CustomEvent<RemoveFileDetail>) => cancelFileUpload(file, e)} name="cancelIcon">
31
31
  <nile-icon
@@ -45,25 +45,27 @@ export function getHorizontalPreviewState(
45
45
  ): TemplateResult {
46
46
  return html`
47
47
  <div class="preview horizontal-div" part="horizontal-preview-state">
48
- <div class="preview-inner">
49
- <div class="preview-image-container">
48
+ <div class="preview-inner" part="horizontal-preview-inner">
49
+ <div class="preview-image-container" part="horizontal-preview-image-container">
50
50
  <img
51
51
  class="image-preview"
52
52
  src=${url}
53
53
  alt=${file.name}
54
+ part="horizontal-preview-image"
54
55
  />
55
56
  </div>
56
- <div class="preview-file-info">
57
- <p>${file.name}</p>
58
- <p>${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
57
+ <div class="preview-file-info" part="horizontal-preview-file-info">
58
+ <p part="horizontal-preview-file-info-name">${file.name}</p>
59
+ <p part="horizontal-preview-file-info-type">${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
59
60
  </div>
60
61
  </div>
61
- <div class="preview-actions">
62
+ <div class="preview-actions" part="horizontal-preview-actions">
62
63
  <slot @click=${(e: CustomEvent<RemoveFileDetail>) => removeFile(file, e, originalUrl)} name="cancel-icon">
63
64
  <nile-icon
64
65
  name="trash"
65
66
  size="14"
66
67
  class="icon"
68
+ part="horizontal-preview-actions-icon"
67
69
  ></nile-icon>
68
70
  </slot>
69
71
  </div>
@@ -77,13 +79,13 @@ export function getHorizontalNoPreviewState(
77
79
  ): TemplateResult {
78
80
  return html`
79
81
  <div class="no-preview horizontal-div" part="horizontal-no-preview-state">
80
- <div class="no-preview-container">
81
- <div class="document-icon">
82
+ <div class="no-preview-container" part="horizontal-no-preview-container">
83
+ <div class="document-icon" part="horizontal-no-preview-document-icon">
82
84
  <nile-icon name="general" size="20" color="var(--nile-colors-blue-500)"></nile-icon>
83
85
  </div>
84
- <div class="preview-file-info">
85
- <p>${file.name}</p>
86
- <p>${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
86
+ <div class="preview-file-info" part="horizontal-no-preview-file-info">
87
+ <p part="horizontal-no-preview-file-info-name">${file.name}</p>
88
+ <p part="horizontal-no-preview-file-info-type">${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
87
89
  </div>
88
90
  </div>
89
91
  <div>
@@ -92,6 +94,7 @@ export function getHorizontalNoPreviewState(
92
94
  name="trash"
93
95
  size="14"
94
96
  class="icon"
97
+ part="horizontal-no-preview-actions-icon"
95
98
  ></nile-icon>
96
99
  </slot>
97
100
  </div>
@@ -108,12 +111,12 @@ export function getHorizontalErrorState(
108
111
  truncateString(nileFilePreview);
109
112
  return html`
110
113
  <div class="error horizontal-div" part="horizontal-error-state">
111
- <div class="error-container">
112
- <div class="error-icon">
114
+ <div class="error-container" part="horizontal-error-container">
115
+ <div class="error-icon" part="horizontal-error-icon">
113
116
  <nile-icon name="info-icon" size="20" color="var(--nile-colors-red-700)"></nile-icon>
114
117
  </div>
115
- <div class="file-info">
116
- <p class="horizontal-file-name">${file.name}</p>
118
+ <div class="file-info" part="horizontal-error-file-info">
119
+ <p class="horizontal-file-name" part="horizontal-error-file-info-name">${file.name}</p>
117
120
  ${
118
121
  nileFilePreview.isStringTruncated
119
122
  ? html`<nile-tooltip content=${errorMessage}>
@@ -128,6 +131,7 @@ export function getHorizontalErrorState(
128
131
  name="close"
129
132
  size="14"
130
133
  class="icon"
134
+ part="horizontal-error-actions-icon"
131
135
  ></nile-icon>
132
136
  </slot>
133
137
  </div>
@@ -141,17 +145,17 @@ export function getVerticalUploadingState(
141
145
  ): TemplateResult {
142
146
  return html`
143
147
  <div class="vertical-div vertical-uploading" part="vertical-uploading-state">
144
- <div class="loading">
148
+ <div class="loading" part="vertical-loading">
145
149
  <nile-loader width="24" height="24"></nile-loader>
146
150
  </div>
147
151
 
148
- <div class="progress-bar-container">
149
- <div class="progress-bar-percent">
150
- <p>Uploading...</p>
151
- <p>${uploadStatus}%</p>
152
+ <div class="progress-bar-container" part="vertical-progress-bar-container">
153
+ <div class="progress-bar-percent" part="vertical-progress-bar-percent">
154
+ <p part="vertical-progress-bar-percent-text">Uploading...</p>
155
+ <p part="vertical-progress-bar-percent-value">${uploadStatus}%</p>
152
156
  </div>
153
157
  <nile-progress-bar value=${uploadStatus}></nile-progress-bar>
154
- <p class="vertical-file-name">${file.name}</p>
158
+ <p class="vertical-file-name" part="vertical-file-name">${file.name}</p>
155
159
  </div>
156
160
 
157
161
  <slot @click=${(e: CustomEvent<RemoveFileDetail>) => cancelFileUpload(file, e)} name="cancelIcon">
@@ -159,6 +163,7 @@ export function getVerticalUploadingState(
159
163
  name="close"
160
164
  size="14"
161
165
  class="icon corner-icon"
166
+ part="vertical-uploading-actions-icon"
162
167
  ></nile-icon>
163
168
  </slot>
164
169
  </div>
@@ -173,17 +178,18 @@ export function getVerticalPreviewState(
173
178
  ): TemplateResult {
174
179
  return html`
175
180
  <div class="vertical-div vertical-preview" part="vertical-preview-state">
176
- <div>
181
+ <div part="vertical-preview-image-container">
177
182
  <img
178
183
  class="image-preview"
184
+ part="vertical-preview-image"
179
185
  src=${url}
180
186
  alt=${file.name}
181
187
  />
182
188
  </div>
183
189
 
184
- <div class="content-container">
185
- <p>${file.name}</p>
186
- <p>${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
190
+ <div class="content-container" part="vertical-preview-file-info">
191
+ <p part="vertical-preview-file-info-name">${file.name}</p>
192
+ <p part="vertical-preview-file-info-type">${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
187
193
  </div>
188
194
 
189
195
  <slot @click=${(e: CustomEvent<RemoveFileDetail>) => removeFile(file, e, originalUrl)} name="cancelIcon">
@@ -191,6 +197,7 @@ export function getVerticalPreviewState(
191
197
  name="trash"
192
198
  size="14"
193
199
  class="icon corner-icon"
200
+ part="vertical-preview-actions-icon"
194
201
  ></nile-icon>
195
202
  </slot>
196
203
  </div>
@@ -203,13 +210,13 @@ export function getVerticalNoPreviewState(
203
210
  ): TemplateResult {
204
211
  return html`
205
212
  <div class="vertical-div vertical-no-preview" part="vertical-no-preview-state">
206
- <div class="vertical-document-icon">
213
+ <div class="vertical-document-icon" part="vertical-no-preview-document-icon">
207
214
  <nile-icon name="general" size="20" color="var(--nile-colors-blue-500)"></nile-icon>
208
215
  </div>
209
216
 
210
- <div class="content-container">
211
- <p>${file.name}</p>
212
- <p>${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
217
+ <div class="content-container" part="vertical-no-preview-file-info">
218
+ <p part="vertical-no-preview-file-info-name">${file.name}</p>
219
+ <p part="vertical-no-preview-file-info-type">${getFileType(file.type)} &#8226; ${formatFileSize(Number(file.size))}</p>
213
220
  </div>
214
221
 
215
222
  <slot @click=${(e: CustomEvent<RemoveFileDetail>) => removeFile(file, e, originalUrl)} name="cancelIcon">
@@ -217,6 +224,7 @@ export function getVerticalNoPreviewState(
217
224
  name="trash"
218
225
  size="14"
219
226
  class="icon corner-icon"
227
+ part="vertical-no-preview-actions-icon"
220
228
  ></nile-icon>
221
229
  </slot>
222
230
  </div>
@@ -232,12 +240,12 @@ export function getVerticalErrorState(
232
240
  truncateString(nileFilePreview);
233
241
  return html`
234
242
  <div class="vertical-div vertical-error" part="vertical-error-state">
235
- <div class="vertical-document-icon error-bg">
243
+ <div class="vertical-document-icon error-bg" part="vertical-error-document-icon">
236
244
  <nile-icon name="info-icon" size="20" color="var(--nile-colors-red-700)"></nile-icon>
237
245
  </div>
238
246
 
239
- <div class="file-info-vertical-state">
240
- <p class="vertical-file-name">${file.name}</p>
247
+ <div class="file-info-vertical-state" part="vertical-error-file-info">
248
+ <p class="vertical-file-name" part="vertical-error-file-info-name">${file.name}</p>
241
249
  ${
242
250
  nileFilePreview.isStringTruncated
243
251
  ? html`<nile-tooltip content=${errorMessage}>
@@ -252,6 +260,7 @@ export function getVerticalErrorState(
252
260
  name="close"
253
261
  size="14"
254
262
  class="icon corner-icon"
263
+ part="vertical-error-actions-icon"
255
264
  ></nile-icon>
256
265
  </slot>
257
266
  </div>
@@ -122,6 +122,10 @@ export class NileliteTooltip extends NileElement {
122
122
 
123
123
  @property({ type: Boolean, reflect: true }) enableTabClose = false;
124
124
 
125
+ @property({ type: String, reflect: true }) width?: string;
126
+ @property({ type: String, reflect: true }) height?: string;
127
+
128
+
125
129
  private tooltipInstances?: Instance[];
126
130
  private singleInstance?: Instance;
127
131
  private singletonInstance?: Instance;
@@ -208,6 +212,17 @@ export class NileliteTooltip extends NileElement {
208
212
  plugins: parseFollowCursor(this.followCursor) ? [followCursor] : [],
209
213
  onShow: instance => {
210
214
  this.open = true;
215
+ const content = instance.popper.querySelector(
216
+ '.tippy-content'
217
+ ) as HTMLElement | null;
218
+ if (content) {
219
+ if (this.width) content.style.width = this.width;
220
+ if (this.height) {
221
+ content.style.height = this.height;
222
+ content.style.overflow = 'auto';
223
+ }
224
+ }
225
+
211
226
  this.dispatchEvent(
212
227
  new CustomEvent('nile-show', {
213
228
  detail: { instance, target: instance.reference },
@@ -117,6 +117,16 @@ export const styles = css`
117
117
  outline-offset: -1px;
118
118
  }
119
119
  }
120
+
121
+ .option__label-container {
122
+ display: flex;
123
+ flex-direction: column;
124
+ }
125
+
126
+ .option__description {
127
+ font-size: var(--nile-type-scale-2, var(--ng-font-size-text-sm));
128
+ color: var(--nile-colors-dark-500, var(--ng-colors-text-tertiary-600));
129
+ }
120
130
  `;
121
131
 
122
132
  export default [styles];
@@ -71,6 +71,9 @@ export class NileOption extends NileElement {
71
71
  /* used to pass group name to the option, so that grouped options can be shown */
72
72
  @property({ type: String, reflect: true, attribute: true }) groupName: string = '';
73
73
 
74
+ /* used to pass description to the option, so that description can be shown */
75
+ @property({ type: String, reflect: true, attribute: true }) description: string = '';
76
+
74
77
  connectedCallback() {
75
78
  super.connectedCallback();
76
79
  this.setAttribute('role', 'option');
@@ -186,11 +189,14 @@ export class NileOption extends NileElement {
186
189
  ${this.isMultipleSelect ? html`<nile-checkbox part="checkbox" class="option--checkbox" .checked=${this.selected}></nile-checkbox>` : ''}
187
190
 
188
191
  <slot part="prefix" name="prefix" class="option__prefix"></slot>
189
- <slot
190
- part="label"
191
- class="option__label"
192
- @slotchange=${this.handleDefaultSlotChange}
193
- ></slot>
192
+ <div class="option__label-container" part="option_label_container">
193
+ <slot
194
+ part="label"
195
+ class="option__label"
196
+ @slotchange=${this.handleDefaultSlotChange}
197
+ ></slot>
198
+ ${this.description ? html`<span part="option_description" class="option__description">${this.description}</span>` : ''}
199
+ </div>
194
200
  <slot part="suffix" name="suffix" class="option__suffix"></slot>
195
201
  </div>`
196
202
  : ''}
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import { html, CSSResultArray, TemplateResult } from 'lit';
8
+ import { html, CSSResultArray, TemplateResult, PropertyValues } from 'lit';
9
9
  import { customElement, property, query } from 'lit/decorators.js';
10
10
  import { classMap } from 'lit/directives/class-map.js';
11
11
  import { styles } from './nile-side-bar-action.css';
@@ -22,6 +22,8 @@ import type NileIconButton from '../nile-icon-button/nile-icon-button';
22
22
  import type { NileMenu } from '../nile-menu';
23
23
  import type { NilePopup } from '../nile-popup';
24
24
  import '../nile-popup';
25
+ import { DropdownPortalManager } from './portal-manager';
26
+
25
27
 
26
28
  /**
27
29
  * Nile side-bar-action component.
@@ -82,6 +84,14 @@ export class NileSideBarAction extends NileElement {
82
84
  /** Hoist above scroll containers */
83
85
  @property({ type: Boolean }) hoist = false;
84
86
 
87
+ /**
88
+ * Enable portal mode to render the dropdown panel in a portal outside the component's DOM tree.
89
+ * This provides better positioning control and prevents clipping issues in complex layouts.
90
+ */
91
+ @property({ type: Boolean, reflect: true }) portal = false;
92
+
93
+ private portalManager: DropdownPortalManager | null = null;
94
+
85
95
  @property({ reflect: true }) triggerDropdown: 'click' | 'hover' = 'click';
86
96
  private hoverTimeout: number | undefined;
87
97
 
@@ -98,6 +108,12 @@ export class NileSideBarAction extends NileElement {
98
108
  this.containingElement = this;
99
109
  }
100
110
  this.emit('nile-init');
111
+
112
+ requestAnimationFrame(() => {
113
+ if (this.portal && !this.portalManager) {
114
+ this.portalManager = new DropdownPortalManager(this);
115
+ }
116
+ });
101
117
  }
102
118
 
103
119
 
@@ -139,6 +155,10 @@ export class NileSideBarAction extends NileElement {
139
155
  this.removeOpenListeners();
140
156
  this.hide();
141
157
  this.emit('nile-destroy');
158
+ if (this.portalManager) {
159
+ this.portalManager.cleanupPortalAppend();
160
+ this.portalManager = null;
161
+ }
142
162
  }
143
163
 
144
164
  focusOnTrigger() {
@@ -176,11 +196,12 @@ export class NileSideBarAction extends NileElement {
176
196
  ? document.activeElement?.shadowRoot?.activeElement
177
197
  : document.activeElement;
178
198
 
179
- if (
180
- !this.containingElement ||
181
- activeElement?.closest(this.containingElement.tagName.toLowerCase()) !==
182
- this.containingElement
183
- ) {
199
+ const hitSelf = this.containingElement && activeElement?.closest(this.containingElement.tagName.toLowerCase()) === this.containingElement;
200
+ const hitPortalAppend = this.portal && this.portalManager?.portalContainerElement &&
201
+ (activeElement === this.portalManager.portalContainerElement ||
202
+ activeElement?.closest('.nile-dropdown-portal-append') === this.portalManager.portalContainerElement);
203
+
204
+ if (!hitSelf && !hitPortalAppend) {
184
205
  this.hide();
185
206
  }
186
207
  });
@@ -189,7 +210,10 @@ export class NileSideBarAction extends NileElement {
189
210
 
190
211
  handleDocumentMouseDown(event: MouseEvent) {
191
212
  const path = event.composedPath();
192
- if (this.containingElement && !path.includes(this.containingElement)) {
213
+ const hitSelf = this.containingElement && path.includes(this.containingElement);
214
+ const hitPortalAppend = this.portal && this.portalManager?.portalContainerElement && path.includes(this.portalManager.portalContainerElement);
215
+
216
+ if (!hitSelf && !hitPortalAppend) {
193
217
  this.hide();
194
218
  }
195
219
  }
@@ -300,6 +324,23 @@ export class NileSideBarAction extends NileElement {
300
324
  document.removeEventListener('mousedown', this.handleDocumentMouseDown);
301
325
  }
302
326
 
327
+ protected updated(changedProperties: PropertyValues): void {
328
+ super.updated(changedProperties);
329
+
330
+ if (changedProperties.has('portal')) {
331
+ if (this.portal && !this.portalManager) {
332
+ this.portalManager = new DropdownPortalManager(this);
333
+ if (this.open) {
334
+ this.portalManager.setupPortalAppend();
335
+ }
336
+ } else if (!this.portal && this.portalManager) {
337
+ this.portalManager.cleanupPortalAppend();
338
+ this.portalManager = null;
339
+ }
340
+ }
341
+ }
342
+
343
+
303
344
  @watch('open', { waitUntilFirstUpdate: true })
304
345
  async handleOpenChange() {
305
346
  if (this.disabled) {
@@ -312,21 +353,38 @@ export class NileSideBarAction extends NileElement {
312
353
  this.emit('nile-show');
313
354
  this.addOpenListeners();
314
355
 
356
+ if (this.portal && this.portalManager) {
357
+ this.portalManager.setupPortalAppend();
358
+ } else if (this.portal && !this.portalManager) {
359
+ this.portalManager = new DropdownPortalManager(this);
360
+ this.portalManager.setupPortalAppend();
361
+ }
362
+
315
363
  await stopAnimations(this);
316
- this.panel.hidden = false;
317
- this.popup.active = true;
318
- const { keyframes, options } = getAnimation(this, 'dropdown.show', { dir: '' });
319
- await animateTo(this.popup.popup, keyframes, options);
364
+ // Only show panel and animate if not using portal
365
+ if (!this.portal) {
366
+ this.panel.hidden = false;
367
+ this.popup.active = true;
368
+ const { keyframes, options } = getAnimation(this, 'dropdown.show', { dir: '' });
369
+ await animateTo(this.popup.popup, keyframes, options);
370
+ }
320
371
  this.emit('nile-after-show');
321
372
  } else {
322
373
  this.emit('nile-hide');
323
374
  this.removeOpenListeners();
324
375
 
376
+ if (this.portal && this.portalManager) {
377
+ this.portalManager.cleanupPortalAppend();
378
+ }
379
+
325
380
  await stopAnimations(this);
326
- const { keyframes, options } = getAnimation(this, 'dropdown.hide', { dir: '' });
327
- await animateTo(this.popup.popup, keyframes, options);
328
- this.panel.hidden = true;
329
- this.popup.active = false;
381
+ if (!this.portal) {
382
+ const { keyframes, options } = getAnimation(this, 'dropdown.hide', { dir: '' });
383
+ await animateTo(this.popup.popup, keyframes, options);
384
+ this.panel.hidden = true;
385
+ this.popup.active = false;
386
+ }
387
+
330
388
  this.emit('nile-after-hide');
331
389
  }
332
390
  }
@@ -366,6 +424,7 @@ export class NileSideBarAction extends NileElement {
366
424
  class="dropdown__panel"
367
425
  aria-hidden=${this.open ? 'false' : 'true'}
368
426
  aria-labelledby="sidebar-action-dropdown"
427
+ style=${this.portal && this.portalManager ? 'display: none;' : ''}
369
428
  ></slot>
370
429
  </nile-popup>
371
430
  `;