wc-catalogue / blaze-elements

Web Component Blaze Elements
https://wc-catalogue.github.io/blaze-elements/
MIT License
10 stars 4 forks source link

feat(select,option): implement bl-select with bl-option #215

Closed Hotell closed 7 years ago

Hotell commented 7 years ago

I'm submitting a ... (check one with "x")

[ ] bug report => search github for a similar issue or PR before submitting
[x] feature request
[ ] support request => You can submit support request here, but we preffer to chat about it realtime at our [ngParty slack](https://ngparty.herokuapp.com/)

Current behavior we don't support custom select element

Expected behavior

we need something like this https://material.angular.io/components/component/select

POC:

Usage (within Preact):


const selectedState = 'CA';
const states = [{code: 'AL', name: 'Alabama'}...];

const App = () => (
<bl-select placeholder="Select state" value={selectedState} >
  { 
    states.map(state => {
       return ( 
          <bl-option value={state.code}>
            {option.name}
          </bl-option> 
       ) 
    }
   }
</bl-select>
)

bl-select API

bl-option API

Keyboard interaction:

Naive Implementation
type OptionProps = {}
@customElement('bl-option')
class Option extends Component<OptionProps>{

  @prop({type:Boolean}) disabled: boolean;
  @prop({type:Object}) value: any;   

  private _selected: boolean;
  get selected(){ return this._selected }
  private slot;

  get slotedValue(){
    return this.slot.assignedNodes({flatten: true});
  }
  get viewValue(){
    return this.slotedValue.textContent.trim();
  }

  select(){
    this._selected = true;
  }
  deselect(): void {
    this._selected = false;
  }
  renderCallback(){
     return (
       <div><ref={this.setSlot} slot/></div>
     )
  }

  @bind
  private setSlot(el: SlotHTMLElement ){
    this.slot = el;
  }
}

type SelectProps = {}
@customElement('bl-select')
class Select extends Component<SelectOptions>{
   @prop() value: any;

   get selected(): MdOption {
     return this._selected;
   }
   private _selected: Option;

   private slot;
   private options: Option[];

   get slotedValue(){
    return this.slot.assignedNodes({flatten: true});
  }

   connectedCallback(){
     setTimeout(()=>{
        this.options = this.slotedValue;
        this._setSelectionByValue(this.value)
     })
   }
   renderCallback(){
      return (
        <button onClick={...}>{this.selected.}</button>
        <div><slot ref={this.setSlot} /></div>
      )
   }

   @bind
   private setSlot(el: SlotHTMLElement ){
      this.slot = el;
   }

     /**
   * Sets the selected option based on a value. If no option can be
   * found with the designated value, the select trigger is cleared.
   */
  private _setSelectionByValue(value: any): void {
    const options = Array.from(this.options);

    for (let i = 0; i < this.options.length; i++) {
      if (options[i].value === value) {
        options[i].select();
        return;
      }
    }

    // Clear selection if no item was selected.
    this._clearSelection();
  }

  /** Clears the select trigger and deselects every option in the list. */
  private _clearSelection(): void {
    this._selected = null;
    this._updateOptions();
  }

  private _updateOptions(): void {
    this.options.forEach((option: MdOption) => {
      if (option !== this.selected) {
        option.deselect();
      }
    });
  }

}
Hotell commented 7 years ago

Closed by https://github.com/wc-catalogue/blaze-elements/pull/221