{"mappings":"AAGA,cAAc,sBAAiC;AAG/C,SAAS,mBAAmB;;;;;;;;;;;AAkB5B,cA6CM,iBAAiB,YAAY;;;;CAIjC,AACA;;;;CAKA,AACA;CAEA,UACU,WAAW;CAErB;CAEA,QAAQ;CAER,QAAQ;CAER,UAAU;CAEV,UAAU,UAAU,eAAe;CAuBnC;CAgBA,UAAgB,gBAAgB;CAKhC,yBAAyB,cAAc,qBAAqB;CAO5D,KAAK,WAAW;CAgBhB;CASA;CASA,UAAU,cAAc,gBAAgB;CAKxC,UAAU;CASV,eAAe;;AAWjB,eAAe;AACf,SAAS","names":[],"sources":["../../../../src/web-components/carousel/component.ts"],"sourcesContent":["import { attr, godown, htmlSlot, styles } from \"@godown/element\";\nimport iconCaretLeft from \"../../internal/icons/caret-left.js\";\nimport iconCaretRight from \"../../internal/icons/caret-right.js\";\nimport { type TemplateResult, css, html } from \"lit\";\nimport { property, query } from \"lit/decorators.js\";\n\nimport { GlobalStyle } from \"../../internal/global-style.js\";\n\nconst protoName = \"carousel\";\n\nfunction getWidth(e) {\n  return e.getBoundingClientRect().width;\n}\n\n/**\n * {@linkcode Carousel} make the content display as a carousel.\n *\n * When this component is `firstUpdated`,\n * clone the first and last element and make the matching element visible when switching index.\n *\n * @slot - Carousel items, should maintain the same size.\n * @fires change - Fires when the index changes.\n * @category display\n */\n@godown(protoName)\n@styles(css`\n  :host {\n    display: block;\n    transition: 0.3s;\n  }\n\n  [part=\"root\"] {\n    direction: ltr;\n    overflow: hidden;\n  }\n\n  [part=\"root\"],\n  [part=\"move-root\"] {\n    height: 100%;\n    width: 100%;\n    display: flex;\n    position: relative;\n    transition: inherit;\n  }\n\n  [part=\"prev\"],\n  [part=\"next\"] {\n    height: 100%;\n    width: 1.5em;\n    z-index: 1;\n    position: absolute;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    user-select: none;\n  }\n\n  [part=\"prev\"] {\n    left: 0;\n  }\n\n  [part=\"next\"] {\n    right: 0;\n  }\n\n  slot::slotted(*) {\n    flex-shrink: 0 !important;\n  }\n`)\nclass Carousel extends GlobalStyle {\n  /**\n   * The index of the current item.\n   */\n  @property({ type: Number })\n  index = 0;\n\n  /**\n   * The duration of the transition.\n   */\n  @property({ type: Number })\n  autoChange = 0;\n\n  @query(\"[part=move-root]\")\n  protected _moveRoot: HTMLElement;\n\n  intervalID: number;\n\n  private __cloneFirst: HTMLElement | undefined;\n\n  private __cloneLast: HTMLElement | undefined;\n\n  protected _offset: number;\n\n  protected render(): TemplateResult<1> {\n    return html`\n      <div\n        part=\"root\"\n        ${attr(this.observedRecord)}\n      >\n        <i\n          part=\"prev\"\n          @click=\"${this.prev}\"\n        >\n          ${iconCaretLeft()}\n        </i>\n        <div part=\"move-root\">${htmlSlot()}</div>\n        <i\n          part=\"next\"\n          @click=\"${this.next}\"\n        >\n          ${iconCaretRight()}\n        </i>\n      </div>\n    `;\n  }\n\n  connectedCallback(): void {\n    super.connectedCallback();\n    if (this.children.length) {\n      this.__cloneFirst?.remove();\n      this.__cloneLast?.remove();\n      this.__cloneLast = this.firstElementChild.cloneNode(true) as HTMLElement;\n      this.__cloneFirst = this.lastElementChild.cloneNode(true) as HTMLElement;\n      this.appendChild(this.__cloneLast);\n      this.insertBefore(this.__cloneFirst, this.firstElementChild);\n    }\n    this.observers.add(this, ResizeObserver, () => {\n      this._offset = this._computeOffset();\n      this._doTranslateX(`${this._offset}px`, true);\n    });\n  }\n\n  protected async firstUpdated(): Promise<void> {\n    await this.updateComplete;\n    this.show(this.index, true);\n  }\n\n  attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n    super.attributeChangedCallback(name, _old, value);\n    if (name === \"index\" && this.isConnected) {\n      this.show(this.index);\n    }\n  }\n\n  show(i: number, n?: boolean): void {\n    i = this.normalizeIndex(i);\n    this.index = i;\n    this._offset = this._computeOffset();\n    this._doTranslateX(`${this._offset}px`, n);\n    this.dispatchCustomEvent(\"change\", i);\n    this.timeouts.remove(this.intervalID);\n    if (this.autoChange > 0) {\n      this.intervalID = this.timeouts.add(\n        setInterval(() => {\n          this.next();\n        }, this.autoChange),\n      );\n    }\n  }\n\n  next(): void {\n    if (this.index === this.childElementCount - 3) {\n      this._doTranslateX(\"0\", true);\n      this.show(0);\n    } else {\n      this.show(this.index + 1);\n    }\n  }\n\n  prev(): void {\n    if (this.index === 0) {\n      this._doTranslateX(`-${this.childElementCount - 1}00%`, true);\n      this.show(this.children.length - 3);\n    } else {\n      this.show(this.index - 1);\n    }\n  }\n\n  protected _doTranslateX(xValue: string, noTransition?: boolean): void {\n    this._moveRoot.style.transform = `translateX(${xValue})`;\n    this._moveRoot.style.transition = noTransition ? \"none\" : \"\";\n  }\n\n  protected _computeOffset(): number {\n    let offset = 0;\n    for (let childIndex = 0; childIndex <= this.index; childIndex++) {\n      offset -= getWidth(this.children[childIndex]);\n    }\n    offset += (getWidth(this) - getWidth(this.children[this.index + 1])) / 2;\n    return offset;\n  }\n\n  normalizeIndex(i: number): number {\n    if (i < 0) {\n      return 0;\n    }\n    if (i > this.children.length - 3) {\n      return this.children.length - 3;\n    }\n    return i;\n  }\n}\n\nexport default Carousel;\nexport { Carousel };\n"],"version":3,"file":"component.d.ts"}