본문 바로가기
공부하기

[Stencil]토글가능한 Expander UI만들기

by 날아라못난 2024. 1. 4.
728x90
반응형

 

출처 : PIXABAY

Watch 를 이용해  isOpen의 값 변화를 주어 Expander 를 만들어 보겠습니다.

button 마크업에 onclick  이벤트로 expanderClick  함수를 호출하였고,

isOpen의 값을 변경하였습니다. 

Watch에서 값 변경을 인식하여 현재 컴포넌트의  상태값을 변경해주는 로직입니다.

import { Component, Host, h, Prop, Watch, Element } from '@stencil/core';

@Component({
  tag: 'td-expander',
  styleUrl: 'td-expander.less',
  shadow: true,
})
export class TdExpander {
  @Prop() itemType: string;
  @Prop() panelId: string;

  @Element() el!: HTMLKcLoadingElement;
  
  @Prop() isOpen = false;
  @Watch('isOpen')
  onIsOpenChange(newValue: boolean, oldValue: boolean) {
    const { el } = this;
    if (newValue === true && oldValue === false) {
      this.activeMode(el, 'true');
    } else if (newValue === false && oldValue === true) {
      this.activeMode(el, 'false');
    }
  }
  private activeMode = (el, value) => {
    let ele = el as HTMLElement;
    if (value === 'true') {
      ele.setAttribute('is-open', 'true');
    } else if (value === 'false') {
      ele.setAttribute('is-open', 'false');
    }
  };
  
  private expanderClick = (ev?: Event) => {
    if (ev) {
      ev.preventDefault();
      ev.stopPropagation();
    }

    const icon = ev.currentTarget as HTMLElement;
    const button = this.el.shadowRoot.querySelector('button');

    if (this.isOpen == false) {
      this.isOpen = true;
      button.setAttribute('aria-expanded', 'true');
      button.nextElementSibling.setAttribute('aria-hidden', 'false');
    } else {
      this.isOpen = false;
      button.setAttribute('aria-expanded', 'false');
      button.nextElementSibling.setAttribute('aria-hidden', 'true');
    }
  };
  render() {
    const { itemType, iconType, size, panelId } = this;
    let classArray = ['expander', itemType == null ? '' : itemType];
    let classes = classArray.join(' ');

    return (
      <Host class={classes} is-open="false">
        <button
          type="button"
          class="btn-expander"}
          slot="header"
          item-type={itemType}
          onClick={this.expanderClick}
          expanded="false"
          aria-controls={panelId}>
          <slot name="header"></slot>
        </button>
        <div id={panelId}>
          <div class="expander__contents">
            <slot name="content"></slot>
          </div>
        </div>
      </Host>
    );
  }
}

 

css는 다음과 같아요~

:host(isOpen=true){
	::slotted(.expander__content) {
    	display:block;
	}
}
:host(isOpen=false){
	::slotted(.expander__content) {
    	display:none;
	}
}
728x90
반응형

'공부하기' 카테고리의 다른 글

Node.js 설치하기  (1) 2024.01.08
특수문자  (1) 2024.01.04
[Stencil]컴포넌트 구성 셋  (0) 2024.01.03
[Stencil]Web components API  (0) 2024.01.03
web components :part()  (0) 2024.01.03