web/elements: render ak-seach-select dropdown correctly in modals
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		| @ -13,6 +13,7 @@ | |||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/page.css' %}"> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/page.css' %}"> | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/empty-state.css' %}"> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/empty-state.css' %}"> | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/spinner.css' %}"> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/spinner.css' %}"> | ||||||
|  |         <link rel="stylesheet" type="text/css" href="{% static 'dist/dropdown.css' %}"> | ||||||
|         {% block head_before %} |         {% block head_before %} | ||||||
|         {% endblock %} |         {% endblock %} | ||||||
|         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> |         <link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}"> | ||||||
|  | |||||||
| @ -24,6 +24,10 @@ export const resources = [ | |||||||
|         src: "node_modules/@patternfly/patternfly/patternfly-base.css", |         src: "node_modules/@patternfly/patternfly/patternfly-base.css", | ||||||
|         dest: "dist/", |         dest: "dist/", | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |         src: "node_modules/@patternfly/patternfly/components/Dropdown/dropdown.css", | ||||||
|  |         dest: "dist/", | ||||||
|  |     }, | ||||||
|     { |     { | ||||||
|         src: "node_modules/@patternfly/patternfly/components/Page/page.css", |         src: "node_modules/@patternfly/patternfly/components/Page/page.css", | ||||||
|         dest: "dist/", |         dest: "dist/", | ||||||
|  | |||||||
| @ -310,6 +310,18 @@ html > form > input { | |||||||
|     .pf-c-dropdown__toggle::before { |     .pf-c-dropdown__toggle::before { | ||||||
|         border-color: transparent; |         border-color: transparent; | ||||||
|     } |     } | ||||||
|  |     .pf-c-dropdown__menu { | ||||||
|  |         --pf-c-dropdown__menu--BackgroundColor: var(--ak-dark-background); | ||||||
|  |     } | ||||||
|  |     .pf-c-dropdown__menu-item { | ||||||
|  |         --pf-c-dropdown__menu-item--BackgroundColor: var(--ak-dark-background); | ||||||
|  |         --pf-c-dropdown__menu-item--Color: var(--ak-dark-foreground); | ||||||
|  |     } | ||||||
|  |     .pf-c-dropdown__menu-item:hover, | ||||||
|  |     .pf-c-dropdown__menu-item:focus { | ||||||
|  |         --pf-c-dropdown__menu-item--BackgroundColor: var(--ak-dark-background-light-ish); | ||||||
|  |         --pf-c-dropdown__menu-item--Color: var(--ak-dark-foreground); | ||||||
|  |     } | ||||||
|     .pf-c-toggle-group__button { |     .pf-c-toggle-group__button { | ||||||
|         color: var(--ak-dark-foreground) !important; |         color: var(--ak-dark-foreground) !important; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { AKElement } from "@goauthentik/elements/Base"; | |||||||
|  |  | ||||||
| import { t } from "@lingui/macro"; | import { t } from "@lingui/macro"; | ||||||
|  |  | ||||||
| import { CSSResult, TemplateResult, html } from "lit"; | import { CSSResult, TemplateResult, html, render } from "lit"; | ||||||
| import { customElement, property } from "lit/decorators.js"; | import { customElement, property } from "lit/decorators.js"; | ||||||
|  |  | ||||||
| import AKGlobal from "@goauthentik/common/styles/authentik.css"; | import AKGlobal from "@goauthentik/common/styles/authentik.css"; | ||||||
| @ -61,37 +61,45 @@ export class SearchSelect<T> extends AKElement { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     render(): TemplateResult { |     menuId: string; | ||||||
|         return html`<div class="pf-c-select"> |  | ||||||
|             <div class="pf-c-select__toggle pf-m-typeahead"> |  | ||||||
|                 <div class="pf-c-select__toggle-wrapper"> |  | ||||||
|                     <input |  | ||||||
|                         class="pf-c-form-control pf-c-select__toggle-typeahead" |  | ||||||
|                         type="text" |  | ||||||
|                         placeholder=${this.placeholder} |  | ||||||
|                         @input=${(ev: InputEvent) => { |  | ||||||
|                             this.query = (ev.target as HTMLInputElement).value; |  | ||||||
|                             this.firstUpdated(); |  | ||||||
|                         }} |  | ||||||
|                         @focus=${() => { |  | ||||||
|                             this.open = true; |  | ||||||
|                         }} |  | ||||||
|                         @blur=${() => { |  | ||||||
|                             setTimeout(() => { |  | ||||||
|                                 this.open = false; |  | ||||||
|                             }, 200); |  | ||||||
|                         }} |  | ||||||
|                         .value=${this.selectedObject ? this.renderElement(this.selectedObject) : ""} |  | ||||||
|                     /> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|             <ul class="pf-c-select__menu" role="listbox" ?hidden="${!this.open}"> |     constructor() { | ||||||
|  |         super(); | ||||||
|  |         this.menuId = btoa(Math.random().toString()).substring(10, 15); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     disconnectedCallback(): void { | ||||||
|  |         super.disconnectedCallback(); | ||||||
|  |         document.querySelectorAll(`#${this.menuId}`).forEach((e) => e.remove()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * This is a little bit hacky. Because we mainly want to use this field in modal-based forms, | ||||||
|  |      * rendering this menu inline makes the menu not overlay over top of the modal, and cause | ||||||
|  |      * the modal to scroll. | ||||||
|  |      * Hence, we render the menu into the document root, hide it when this menu isn't open | ||||||
|  |      * and remove it on disconnect | ||||||
|  |      * Also to move it to the correct position we're getting this elements's position and use that | ||||||
|  |      * to position the menu | ||||||
|  |      * The other downside this has is that, since we're rendering outside of a shadow root, | ||||||
|  |      * the pf-c-dropdown CSS needs to be loaded on the body. | ||||||
|  |      */ | ||||||
|  |     renderMenu(): void { | ||||||
|  |         const pos = this.getBoundingClientRect(); | ||||||
|  |         render( | ||||||
|  |             html`<div | ||||||
|  |                 class="pf-c-dropdown pf-m-expanded" | ||||||
|  |                 ?hidden=${!this.open} | ||||||
|  |                 id="${this.menuId}" | ||||||
|  |                 style="position: fixed; inset: 0px auto auto 0px; z-index: 9999; transform: translate(${pos.x}px, ${pos.y + | ||||||
|  |                 this.offsetHeight}px); width: ${pos.width}px;" | ||||||
|  |             > | ||||||
|  |                 <ul class="pf-c-dropdown__menu pf-m-static" role="listbox"> | ||||||
|                     ${this.blankable |                     ${this.blankable | ||||||
|                         ? html` |                         ? html` | ||||||
|                               <li role="presentation"> |                               <li role="presentation"> | ||||||
|                                   <button |                                   <button | ||||||
|                                   class="pf-c-select__menu-item" |                                       class="pf-c-dropdown__menu-item" | ||||||
|                                       role="option" |                                       role="option" | ||||||
|                                       @click=${() => { |                                       @click=${() => { | ||||||
|                                           this.selectedObject = undefined; |                                           this.selectedObject = undefined; | ||||||
| @ -107,7 +115,7 @@ export class SearchSelect<T> extends AKElement { | |||||||
|                         return html` |                         return html` | ||||||
|                             <li role="presentation"> |                             <li role="presentation"> | ||||||
|                                 <button |                                 <button | ||||||
|                                 class="pf-c-select__menu-item" |                                     class="pf-c-dropdown__menu-item" | ||||||
|                                     role="option" |                                     role="option" | ||||||
|                                     @click=${() => { |                                     @click=${() => { | ||||||
|                                         this.selectedObject = obj; |                                         this.selectedObject = obj; | ||||||
| @ -120,6 +128,39 @@ export class SearchSelect<T> extends AKElement { | |||||||
|                         `; |                         `; | ||||||
|                     })} |                     })} | ||||||
|                 </ul> |                 </ul> | ||||||
|  |             </div>`, | ||||||
|  |             document.body, | ||||||
|  |             { host: this }, | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     render(): TemplateResult { | ||||||
|  |         this.renderMenu(); | ||||||
|  |         return html`<div class="pf-c-select"> | ||||||
|  |             <div class="pf-c-select__toggle pf-m-typeahead"> | ||||||
|  |                 <div class="pf-c-select__toggle-wrapper"> | ||||||
|  |                     <input | ||||||
|  |                         class="pf-c-form-control pf-c-select__toggle-typeahead" | ||||||
|  |                         type="text" | ||||||
|  |                         placeholder=${this.placeholder} | ||||||
|  |                         @input=${(ev: InputEvent) => { | ||||||
|  |                             this.query = (ev.target as HTMLInputElement).value; | ||||||
|  |                             this.firstUpdated(); | ||||||
|  |                         }} | ||||||
|  |                         @focus=${() => { | ||||||
|  |                             this.open = true; | ||||||
|  |                             this.renderMenu(); | ||||||
|  |                         }} | ||||||
|  |                         @blur=${() => { | ||||||
|  |                             setTimeout(() => { | ||||||
|  |                                 this.open = false; | ||||||
|  |                                 this.renderMenu(); | ||||||
|  |                             }, 200); | ||||||
|  |                         }} | ||||||
|  |                         .value=${this.selectedObject ? this.renderElement(this.selectedObject) : ""} | ||||||
|  |                     /> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|         </div>`; |         </div>`; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer