1- import { LitElement , html , type TemplateResult } from 'lit' ;
1+ import { LitElement , html , isServer , type TemplateResult } from 'lit' ;
22import { customElement } from 'lit/decorators/custom-element.js' ;
33import { ComboboxController } from '@patternfly/pfe-core/controllers/combobox-controller.js' ;
44import { query } from 'lit/decorators/query.js' ;
55import { property } from 'lit/decorators/property.js' ;
66import { observes } from '@patternfly/pfe-core/decorators/observes.js' ;
7+ import { styleMap } from 'lit/directives/style-map.js' ;
78import {
89 FloatingDOMController ,
910 type Placement ,
1011} from '@patternfly/pfe-core/controllers/floating-dom-controller.js' ;
12+ import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js' ;
13+ import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js' ;
1114import '@patternfly/elements/pf-text-input/pf-text-input.js' ;
1215import { arraysAreEquivalent } from '@patternfly/pfe-core/functions/arraysAreEquivalent.js' ;
1316import '@patternfly/elements/pf-icon/pf-icon.js' ;
17+ import { PfSearchInputOption } from './pf-search-input-option.js' ;
18+ import { ifDefined } from 'lit/directives/if-defined.js' ;
1419import styles from './pf-search-input.css' ;
1520
21+ export class PfSelectChangeEvent extends Event {
22+ constructor ( ) {
23+ super ( 'change' , { bubbles : true } ) ;
24+ }
25+ }
26+
1627/**
1728 * Search Input
1829 * @slot - Place element content here
@@ -24,24 +35,33 @@ export class PfSearchInput extends LitElement {
2435 @property ( { type : Boolean , reflect : true } ) expanded = false ;
2536 @property ( { reflect : true } ) position : Placement = 'bottom' ;
2637 @property ( { attribute : 'enable-flip' , type : Boolean } ) enableFlip = false ;
27-
38+ /** Current form value */
39+ @property ( ) value ?: string ;
40+ @property ( ) variant : 'single' | 'checkbox' | 'typeahead' | 'typeaheadmulti' = 'single' ;
2841 @query ( '#listbox' ) listbox ! : HTMLElement ;
2942 @query ( '#button' ) button ! : HTMLButtonElement ;
3043 @query ( '#combobox' ) combobox ! : HTMLInputElement ;
31- @query ( '#placeholder' ) placeholder ! : HTMLOptionElement ;
44+ @query ( '#placeholder' ) placeholder ! : PfSearchInputOption ;
3245 @query ( '#listbox-container' ) private _listboxContainer ?: HTMLElement ;
3346
47+ #isNotPlaceholderOption = ( option : PfSearchInputOption ) => option !== this . placeholder ;
48+
3449
3550 #float = new FloatingDOMController ( this , { content : ( ) => this . _listboxContainer } ) ;
3651
52+ #internals = InternalsController . of ( this ) ;
53+
54+ #slots = new SlotController ( this , null , 'placeholder' ) ;
55+
56+
3757
3858 // static template: TemplateResult<1> = html`
3959 // <pf-text-input-autocomplete></pf-text-input-autocomplete>`;
4060
41- #combobox: ComboboxController < HTMLOptionElement > = ComboboxController . of ( this , {
42- multi : false ,
61+ #combobox = ComboboxController . of ( this , {
62+ multi : this . variant === 'typeaheadmulti' || this . variant === 'checkbox' ,
4363 getItems : ( ) => this . options ,
44- isItem : item => item instanceof HTMLOptionElement ,
64+ isItem : item => item instanceof PfSearchInputOption ,
4565 getFallbackLabel : ( ) => 'options' ,
4666 getListboxElement : ( ) => this . listbox ?? null ,
4767 getToggleButton : ( ) => this . combobox ?? null ,
@@ -51,6 +71,7 @@ export class PfSearchInput extends LitElement {
5171 requestHideListbox : ( ) => void ( this . expanded &&= false ) ,
5272 setItemActive : ( item , active ) => item . classList . toggle ( 'active' , active ) ,
5373 setItemSelected : ( item , selected ) => item . selected = selected ,
74+ setItemHidden : ( item , hidden ) => ( item . id !== 'placeholder' ) && void ( item . hidden = hidden )
5475 } ) ;
5576
5677 /**
@@ -63,27 +84,39 @@ export class PfSearchInput extends LitElement {
6384 this . #combobox. selected = list ;
6485 }
6586
87+
88+
6689 /** List of options */
67- get options ( ) : HTMLOptionElement [ ] {
68- return [
69- ...new Set ( [
90+ get options ( ) : PfSearchInputOption [ ] {
91+ if ( isServer ) {
92+ return [ ] ; // TODO: expose a DOM property to allow setting options in SSR scenarios
93+ } else {
94+ return [
7095 this . placeholder ,
71- ...this . querySelectorAll ( 'option' ) ,
72- ...this . renderRoot . querySelectorAll ( 'option' ) ,
73- ] ) ,
74- ] . filter ( x => ! ! x ) ;
96+ ...Array . from ( this . querySelectorAll ( 'pf-search-input-option' ) ) ,
97+ ] . filter ( ( x ) : x is PfSearchInputOption => ! ! x && ! x . hidden ) ;
98+ }
7599 }
76100
77- get selected ( ) : HTMLOptionElement [ ] {
78- return this . options . filter ( x => x . selected ) ;
101+ get selected ( ) : PfSearchInputOption [ ] {
102+ return this . #combobox . selected ;
79103 }
80104
81- get activeOption ( ) : HTMLOptionElement | undefined {
82- return this . options . find ( x => x . classList . contains ( 'active' ) ) ;
83- }
105+ // get activeOption(): HTMLOptionElement | undefined {
106+ // return this.options.find(x => x.classList.contains('active'));
107+ // }
84108
85109 //<input id="combobox">
86110 render ( ) : TemplateResult < 1 > {
111+
112+ const { expanded, placeholder, variant } = this ;
113+ const { anchor = 'bottom' , alignment = 'start' , styles = { } } = this . #float;
114+ const { height, width } = this . getBoundingClientRect ?.( ) || { } ;
115+ const placeholderIsInert = ! placeholder && this . #slots. isEmpty ( 'placeholder' ) ;
116+ const hasSelection = ! ! ( Array . isArray ( this . selected ) ? this . selected . length : this . selected ) ;
117+ const typeahead = variant . startsWith ( 'typeahead' ) ;
118+ const hideLightDomItems = typeahead && ! ComboboxController . supportsCrossRootActiveDescendant ;
119+
87120 return html `
88121 < pf-text-input id ="combobox " type ="text " placeholder ="Placeholder "> </ pf-text-input >
89122 < pf-button disabled plain label ="Close ">
@@ -113,22 +146,34 @@ export class PfSearchInput extends LitElement {
113146 </ path >
114147 </ svg >
115148 </ pf-button >
116- < div id ="listbox-container ">
117- < div id ="listbox " ?hidden ="${ ! this . expanded } ">
118- < option id ="placeholder " aria-disabled ="true "> Select an Option</ option >
119- < optgroup label ="Swedish Cars ">
120- < option value ="volvo "> Volvo</ option >
121- < option value ="saab "> Saab</ option >
122- </ optgroup >
123- < optgroup label ="German Cars ">
124- < option value ="mercedes "> Mercedes</ option >
125- < option value ="audi "> Audi</ option >
126- </ optgroup >
149+ < div id ="listbox-container " ?hidden ="${ ! expanded } "
150+ style ="${ styleMap ( {
151+ marginTop : `${ height || 0 } px` ,
152+ width : width ? `${ width } px` : 'auto' ,
153+ } ) } ">
154+ < div id ="listbox ">
155+ < pf-search-input-option id ="placeholder "
156+ disabled
157+ ?inert ="${ placeholderIsInert } "
158+ aria-hidden ="${ ifDefined ( placeholderIsInert ? undefined : String ( ! ! hasSelection ) ) } "
159+ ?hidden ="${ ! placeholder && this . #slots. isEmpty ( 'placeholder' ) } "
160+ > < slot name ="placeholder "> ${ placeholder ?? '' } </ slot > </ pf-search-input-option >
161+ ${ this . #combobox. renderItemsToShadowRoot ( ) }
162+ < slot ?hidden ="${ hideLightDomItems } "> </ slot >
127163 </ div >
128164 </ div >
129165 ` ;
130166 }
131167
168+ @observes ( 'selected' )
169+ private async selectedChanged ( _ : PfSearchInputOption [ ] , selected : PfSearchInputOption [ ] ) {
170+ this . value = selected . map ( x => x . value ) . join ( ) ;
171+ await this . updateComplete ;
172+ this . hide ( ) ;
173+ // this._toggleButton?.focus();
174+
175+ }
176+
132177 @observes ( 'expanded' )
133178 private async expandedChanged ( old : boolean , expanded : boolean ) {
134179 if ( this . dispatchEvent ( new Event ( this . expanded ? 'close' : 'open' ) ) ) {
@@ -184,6 +229,12 @@ export class PfSearchInput extends LitElement {
184229 await this . show ( ) ;
185230 }
186231 }
232+
233+ @observes ( 'value' )
234+ private valueChanged ( ) {
235+ // this.#internals.setFormValue(this.value ?? '');
236+ this . dispatchEvent ( new PfSelectChangeEvent ( ) ) ;
237+ }
187238}
188239
189240declare global {
0 commit comments