| 
          /** | 
        
        
           | 
           * Implements the x-select directive | 
        
        
           | 
           * @param {import('alpinejs').default} Alpine | 
        
        
           | 
           */ | 
        
        
           | 
          export default Alpine => { | 
        
        
           | 
            Alpine.data('_selectImplementation', () => { | 
        
        
           | 
              return { | 
        
        
           | 
                $select: null, | 
        
        
           | 
          
 | 
        
        
           | 
                // Props | 
        
        
           | 
                get props() { | 
        
        
           | 
                  return this.$data.$select?.props ?? {} | 
        
        
           | 
                }, | 
        
        
           | 
          
 | 
        
        
           | 
                // Data | 
        
        
           | 
                touched: false, | 
        
        
           | 
                activatedIndex: undefined, | 
        
        
           | 
                keyPressed: false, | 
        
        
           | 
                expanded: false, | 
        
        
           | 
                positioningStyles: {}, | 
        
        
           | 
                positionClasses: [], | 
        
        
           | 
                listboxOverlapsTrigger: false, | 
        
        
           | 
                valueOnOpen: undefined, | 
        
        
           | 
                //animatingListbox: false, | 
        
        
           | 
          
 | 
        
        
           | 
                // Computed | 
        
        
           | 
                get listboxVisible() { | 
        
        
           | 
                  return this.$data.expanded // || this.$data.animatingListbox | 
        
        
           | 
                }, | 
        
        
           | 
                get valueArray() { | 
        
        
           | 
                  return this.$data.props.multiple | 
        
        
           | 
                    ? this.$data.props.modelValue | 
        
        
           | 
                    : [this.$data.props.modelValue] | 
        
        
           | 
                }, | 
        
        
           | 
                get idPrefix() { | 
        
        
           | 
                  return this.$data.props.id | 
        
        
           | 
                }, | 
        
        
           | 
                get idListbox() { | 
        
        
           | 
                  return `${this.$data.idPrefix}-listbox` | 
        
        
           | 
                }, | 
        
        
           | 
                get idTrigger() { | 
        
        
           | 
                  return `${this.$data.idPrefix}-trigger` | 
        
        
           | 
                }, | 
        
        
           | 
                get hasSelected() { | 
        
        
           | 
                  return this.$data.props.multiple | 
        
        
           | 
                    ? this.$data.props.selectedOption.length > 0 | 
        
        
           | 
                    : typeof this.$data.props.selectedOption !== 'undefined' | 
        
        
           | 
                }, | 
        
        
           | 
                get firstSelectedOptionIndex() { | 
        
        
           | 
                  return this.$data.hasSelected | 
        
        
           | 
                    ? this.$data.props.options.indexOf( | 
        
        
           | 
                        this.$data.props.multiple | 
        
        
           | 
                          ? this.$data.props.selectedOption[0] | 
        
        
           | 
                          : this.$data.props.selectedOption, | 
        
        
           | 
                      ) | 
        
        
           | 
                    : undefined | 
        
        
           | 
                }, | 
        
        
           | 
                getPlaceholder(option) { | 
        
        
           | 
                  const placeholderValue = this.$data.props.placeholder | 
        
        
           | 
                  if (!this.$data.hasSelected) return placeholderValue.trim() || '\u00A0' | 
        
        
           | 
          
 | 
        
        
           | 
                  if (this.$data.props.multiple) { | 
        
        
           | 
                    return this.$data.props.selectedOption.map(option => option.label).join(', ') | 
        
        
           | 
                  } else { | 
        
        
           | 
                    return this.$data.props.selectedOption.label | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                get hasActivatedItem() { | 
        
        
           | 
                  return typeof this.$data.activatedIndex === 'number' | 
        
        
           | 
                }, | 
        
        
           | 
                get activatedOption() { | 
        
        
           | 
                  return !this.$data.hasActivatedItem | 
        
        
           | 
                    ? undefined | 
        
        
           | 
                    : this.$data.props.options[this.$data.activatedIndex] | 
        
        
           | 
                }, | 
        
        
           | 
                get activatedId() { | 
        
        
           | 
                  return !this.$data.hasActivatedItem ? undefined : this.$data.activatedOption.id | 
        
        
           | 
                }, | 
        
        
           | 
          
 | 
        
        
           | 
                // Functions | 
        
        
           | 
                pressKey(key) { | 
        
        
           | 
                  this.$data.keyPressed = key | 
        
        
           | 
                  setTimeout(() => { | 
        
        
           | 
                    this.$data.keyPressed = false | 
        
        
           | 
                  }, 0) | 
        
        
           | 
                }, | 
        
        
           | 
                scrollListbox({ direction = 'auto', index = this.$data.activatedIndex } = {}) { | 
        
        
           | 
                  let hasSelected = typeof index === 'number' | 
        
        
           | 
                  let listbox = this.$refs.listbox | 
        
        
           | 
                  if (!listbox) return | 
        
        
           | 
          
 | 
        
        
           | 
                  let listboxRect = listbox.getBoundingClientRect() | 
        
        
           | 
                  let listboxTriggerRect = this.$refs.listboxTrigger.getBoundingClientRect() | 
        
        
           | 
                  let listboxItem = listbox.children[index] | 
        
        
           | 
                  let previousItem = listbox.children[index - 1] ?? listboxItem | 
        
        
           | 
                  let nextItem = listbox.children[index + 1] ?? listboxItem | 
        
        
           | 
                  let previousItemRect = previousItem.getBoundingClientRect() | 
        
        
           | 
                  let nextItemRect = nextItem.getBoundingClientRect() | 
        
        
           | 
          
 | 
        
        
           | 
                  if (direction === 'auto' && this.$data.listboxOverlapsTrigger && hasSelected) { | 
        
        
           | 
                    let diff = listboxTriggerRect.top - listboxRect.top | 
        
        
           | 
                    let top = listboxItem.offsetTop - diff | 
        
        
           | 
                    listbox.scrollTo({ top }) | 
        
        
           | 
                  } else if ( | 
        
        
           | 
                    direction === 'down' && | 
        
        
           | 
                    nextItemRect.bottom + listboxTriggerRect.height > listboxRect.bottom | 
        
        
           | 
                  ) { | 
        
        
           | 
                    listbox.scrollTo({ | 
        
        
           | 
                      top: | 
        
        
           | 
                        index === this.$data.props.options.length - 1 | 
        
        
           | 
                          ? listbox.scrollHeight | 
        
        
           | 
                          : nextItem.offsetTop + nextItemRect.height - listboxRect.height, | 
        
        
           | 
                      behavior: 'smooth', | 
        
        
           | 
                    }) | 
        
        
           | 
                  } else if ( | 
        
        
           | 
                    direction === 'up' && | 
        
        
           | 
                    previousItemRect.top - listboxTriggerRect.height < listboxRect.top | 
        
        
           | 
                  ) { | 
        
        
           | 
                    listbox.scrollTo({ | 
        
        
           | 
                      top: index === 0 ? 0 : previousItem.offsetTop, | 
        
        
           | 
                      behavior: 'smooth', | 
        
        
           | 
                    }) | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                calculatePosition() { | 
        
        
           | 
                  let listbox = this.$refs.listbox | 
        
        
           | 
                  let listboxTrigger = this.$refs.listboxTrigger | 
        
        
           | 
                  if (!listbox || !listboxTrigger) return | 
        
        
           | 
                  let screenWidth = Math.min(window.innerWidth, window.outerWidth) | 
        
        
           | 
                  let screenHeight = window.innerHeight | 
        
        
           | 
                  let listboxRect = listbox.getBoundingClientRect() | 
        
        
           | 
                  let listboxTriggerRect = listboxTrigger.getBoundingClientRect() | 
        
        
           | 
                  let spaceBelowTrigger = screenHeight - listboxTriggerRect.bottom | 
        
        
           | 
                  let spaceAboveTrigger = listboxTriggerRect.top | 
        
        
           | 
                  let listboxTooTall = listboxRect.bottom > screenHeight | 
        
        
           | 
                  let listboxTooWide = listboxRect.right > screenWidth | 
        
        
           | 
                  let listboxTooWideForTrigger = listboxRect.width > listboxTriggerRect.width | 
        
        
           | 
                  let localPositioningStyles = {} | 
        
        
           | 
                  let localPositionClasses = [] | 
        
        
           | 
          
 | 
        
        
           | 
                  if (listboxTooTall) { | 
        
        
           | 
                    if (spaceAboveTrigger > spaceBelowTrigger && spaceAboveTrigger > listboxRect.height) { | 
        
        
           | 
                      localPositioningStyles[ | 
        
        
           | 
                        '--x-select--position-bottom' | 
        
        
           | 
                      ] = `${listboxTriggerRect.height}px` | 
        
        
           | 
                      localPositionClasses = ['from-bottom'] | 
        
        
           | 
                    } else if (spaceAboveTrigger > spaceBelowTrigger) { | 
        
        
           | 
                      localPositioningStyles['--x-select--position-bottom'] = `${Math.round( | 
        
        
           | 
                        listboxTriggerRect.bottom - screenHeight, | 
        
        
           | 
                      )}px` | 
        
        
           | 
                      localPositionClasses = ['from-bottom'] | 
        
        
           | 
                      this.$data.listboxOverlapsTrigger = true | 
        
        
           | 
                    } else { | 
        
        
           | 
                      localPositioningStyles['--x-select--position-top'] = `${Math.round( | 
        
        
           | 
                        -listboxTriggerRect.top, | 
        
        
           | 
                      )}px` | 
        
        
           | 
                      localPositionClasses = ['from-top'] | 
        
        
           | 
                      this.$data.listboxOverlapsTrigger = true | 
        
        
           | 
                    } | 
        
        
           | 
                  } else { | 
        
        
           | 
                    localPositionClasses = ['from-none'] | 
        
        
           | 
                  } | 
        
        
           | 
                  if (listboxTooWideForTrigger) { | 
        
        
           | 
                    localPositionClasses.push('is-too-wide-for-trigger') | 
        
        
           | 
                  } | 
        
        
           | 
                  if (listboxTooWide) { | 
        
        
           | 
                    localPositionClasses.push('is-too-wide-for-screen') | 
        
        
           | 
                  } | 
        
        
           | 
                  this.$data.positionClasses = localPositionClasses | 
        
        
           | 
                  this.$data.positioningStyles = localPositioningStyles | 
        
        
           | 
                }, | 
        
        
           | 
                activate(index) { | 
        
        
           | 
                  if (index < 0) return | 
        
        
           | 
                  if (index >= this.$data.props.options.length) return | 
        
        
           | 
                  this.$data.activatedIndex = index | 
        
        
           | 
                }, | 
        
        
           | 
                activateFirst() { | 
        
        
           | 
                  this.$data.activate(0) | 
        
        
           | 
                }, | 
        
        
           | 
                activateLast() { | 
        
        
           | 
                  this.$data.activate(this.$data.props.options.length - 1) | 
        
        
           | 
                }, | 
        
        
           | 
                activateFirstSelected() { | 
        
        
           | 
                  if (this.$data.hasSelected) { | 
        
        
           | 
                    this.$data.activate(this.$data.firstSelectedOptionIndex) | 
        
        
           | 
                  } else { | 
        
        
           | 
                    this.$data.activateFirst() | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                activatePrevious() { | 
        
        
           | 
                  if (!this.$data.hasActivatedItem) { | 
        
        
           | 
                    this.$data.activateLast() | 
        
        
           | 
                  } else { | 
        
        
           | 
                    this.$data.activate(this.$data.activatedIndex - 1) | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                activateNext() { | 
        
        
           | 
                  if (!this.$data.hasActivatedItem) { | 
        
        
           | 
                    this.$data.activateFirst() | 
        
        
           | 
                  } else { | 
        
        
           | 
                    this.$data.activate(this.$data.activatedIndex + 1) | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                open() { | 
        
        
           | 
                  this.$data.valueOnOpen = this.$data.props.modelValue | 
        
        
           | 
                  this.$data.expanded = true | 
        
        
           | 
                }, | 
        
        
           | 
                close() { | 
        
        
           | 
                  this.$data.touched = true | 
        
        
           | 
                  if (this.$refs.listbox?.matches(':focus')) { | 
        
        
           | 
                    this.$refs.listboxTrigger.focus({ preventScroll: true }) | 
        
        
           | 
                  } | 
        
        
           | 
                  this.$data.expanded = false | 
        
        
           | 
                  this.$data.$select.el.dispatchEvent(new CustomEvent('select:close', { bubbles: true })) | 
        
        
           | 
          
 | 
        
        
           | 
                  if ( | 
        
        
           | 
                    JSON.stringify(this.$data.valueOnOpen) !== JSON.stringify(this.$data.props.modelValue) | 
        
        
           | 
                  ) { | 
        
        
           | 
                    this.$data.$select.el.dispatchEvent( | 
        
        
           | 
                      new CustomEvent('select:change', { | 
        
        
           | 
                        bubbles: true, | 
        
        
           | 
                        detail: { | 
        
        
           | 
                          value: this.$data.props.modelValue, | 
        
        
           | 
                        }, | 
        
        
           | 
                      }), | 
        
        
           | 
                    ) | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                select(value) { | 
        
        
           | 
                  this.$data.$select.setValue(value) | 
        
        
           | 
                  this.$data.$select.el.dispatchEvent( | 
        
        
           | 
                    new CustomEvent('select:input', { | 
        
        
           | 
                      bubbles: true, | 
        
        
           | 
                      detail: { | 
        
        
           | 
                        value, | 
        
        
           | 
                      }, | 
        
        
           | 
                    }), | 
        
        
           | 
                  ) | 
        
        
           | 
                }, | 
        
        
           | 
                selectSingle(value) { | 
        
        
           | 
                  this.$data.select(this.$data.props.multiple ? [value] : value) | 
        
        
           | 
                }, | 
        
        
           | 
                selectSingleAndClose(value) { | 
        
        
           | 
                  this.$data.select(value) | 
        
        
           | 
                  this.$data.close() | 
        
        
           | 
                }, | 
        
        
           | 
                toggle(value) { | 
        
        
           | 
                  const currentValue = this.$data.props.modelValue | 
        
        
           | 
                  if (currentValue.includes(value)) { | 
        
        
           | 
                    this.$data.$select.setValue(currentValue.filter(selectedValue => selectedValue !== value)) | 
        
        
           | 
                  } else { | 
        
        
           | 
                    this.$data.$select.setValue([...currentValue, value]) | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                commitSingleValue(value) { | 
        
        
           | 
                  if (this.$data.props.multiple) { | 
        
        
           | 
                    this.$data.toggle(value) | 
        
        
           | 
                  } else { | 
        
        
           | 
                    this.$data.selectSingleAndClose(value) | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                onListboxKeydown(event) { | 
        
        
           | 
                  switch (event.key) { | 
        
        
           | 
                    case 'Escape': | 
        
        
           | 
                      event.preventDefault() | 
        
        
           | 
                      this.$data.pressKey(event.key) | 
        
        
           | 
                      this.$data.close() | 
        
        
           | 
                      break | 
        
        
           | 
          
 | 
        
        
           | 
                    case 'ArrowDown': | 
        
        
           | 
                      event.preventDefault() | 
        
        
           | 
                      this.$data.pressKey(event.key) | 
        
        
           | 
                      this.$data.activateNext() | 
        
        
           | 
                      break | 
        
        
           | 
          
 | 
        
        
           | 
                    case 'ArrowUp': | 
        
        
           | 
                      event.preventDefault() | 
        
        
           | 
                      this.$data.pressKey(event.key) | 
        
        
           | 
                      this.$data.activatePrevious() | 
        
        
           | 
                      break | 
        
        
           | 
          
 | 
        
        
           | 
                    case 'Home': | 
        
        
           | 
                      event.preventDefault() | 
        
        
           | 
                      this.$data.pressKey(event.key) | 
        
        
           | 
                      this.$data.activateFirst() | 
        
        
           | 
                      break | 
        
        
           | 
          
 | 
        
        
           | 
                    case 'End': | 
        
        
           | 
                      event.preventDefault() | 
        
        
           | 
                      this.$data.pressKey(event.key) | 
        
        
           | 
                      this.$data.activateLast() | 
        
        
           | 
                      break | 
        
        
           | 
          
 | 
        
        
           | 
                    case 'Enter': | 
        
        
           | 
                    case ' ': | 
        
        
           | 
                      event.preventDefault() | 
        
        
           | 
                      this.$data.pressKey(event.key) | 
        
        
           | 
                      if (!this.$data.hasActivatedItem) { | 
        
        
           | 
                        this.$data.close() | 
        
        
           | 
                        break | 
        
        
           | 
                      } | 
        
        
           | 
                      if (this.$data.props.multiple) { | 
        
        
           | 
                        this.$data.toggle(this.$data.activatedOption.value) | 
        
        
           | 
                      } else { | 
        
        
           | 
                        this.$data.selectSingleAndClose(this.$data.activatedOption.value) | 
        
        
           | 
                      } | 
        
        
           | 
                      break | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
          
 | 
        
        
           | 
                // Initialize | 
        
        
           | 
                init() { | 
        
        
           | 
                  this.$watch('$data?.$select?.props?.disabled', disabled => { | 
        
        
           | 
                    if (disabled) { | 
        
        
           | 
                      this.$data.close() | 
        
        
           | 
                    } | 
        
        
           | 
                  }) | 
        
        
           | 
          
 | 
        
        
           | 
                  this.$watch('listboxVisible', visible => { | 
        
        
           | 
                    if (!visible) { | 
        
        
           | 
                      this.$data.positioningStyles = {} | 
        
        
           | 
                      this.$data.positionClasses = [] | 
        
        
           | 
                      this.$data.listboxOverlapsTrigger = false | 
        
        
           | 
                    } | 
        
        
           | 
                  }) | 
        
        
           | 
          
 | 
        
        
           | 
                  this.$watch('expanded', expanded => { | 
        
        
           | 
                    if (!expanded) { | 
        
        
           | 
                      this.$data.activatedIndex = undefined | 
        
        
           | 
                    } else { | 
        
        
           | 
                      this.$data.activateFirstSelected() | 
        
        
           | 
                      let index = this.$data.hasSelected ? this.$data.firstSelectedOptionIndex : 0 | 
        
        
           | 
          
 | 
        
        
           | 
                      Alpine.nextTick(() => { | 
        
        
           | 
                        this.$data.calculatePosition() | 
        
        
           | 
          
 | 
        
        
           | 
                        setTimeout(() => { | 
        
        
           | 
                          this.$refs.listbox.focus({ preventScroll: true }) | 
        
        
           | 
                          this.$data.scrollListbox({ index }) | 
        
        
           | 
                        }, 0) | 
        
        
           | 
                      }) | 
        
        
           | 
                    } | 
        
        
           | 
                  }) | 
        
        
           | 
          
 | 
        
        
           | 
                  this.$watch('activatedIndex', (activatedIndex, oldActivatedIndex) => { | 
        
        
           | 
                    if (this.$data.hasActivatedItem && this.$data.keyPressed) { | 
        
        
           | 
                      this.$data.scrollListbox({ | 
        
        
           | 
                        direction: (activatedIndex ?? 0) > (oldActivatedIndex ?? 0) ? 'down' : 'up', | 
        
        
           | 
                      }) | 
        
        
           | 
                    } | 
        
        
           | 
                  }) | 
        
        
           | 
                }, | 
        
        
           | 
              } | 
        
        
           | 
            }) | 
        
        
           | 
          
 | 
        
        
           | 
            Alpine.directive('select', async (el, { expression }, { evaluate, cleanup, Alpine }) => { | 
        
        
           | 
              const html = /*html*/ `<div | 
        
        
           | 
                    x-data="_selectImplementation()" | 
        
        
           | 
                    class="x-select--select-wrapper" | 
        
        
           | 
                    :class="{ | 
        
        
           | 
                      'is-expanded': expanded, | 
        
        
           | 
                      'is-overlapping': listboxOverlapsTrigger, | 
        
        
           | 
                      ...Object.fromEntries(positionClasses.map(c => [c, true])), | 
        
        
           | 
                    }" | 
        
        
           | 
                  ></div>` | 
        
        
           | 
          
 | 
        
        
           | 
              el.insertAdjacentHTML('beforebegin', html) | 
        
        
           | 
              el.previousElementSibling.prepend(el) | 
        
        
           | 
          
 | 
        
        
           | 
              el.classList.add('x-select--select-field') | 
        
        
           | 
              el.setAttribute(':class', '{ touched: $data.touched }') | 
        
        
           | 
              el.tabIndex = -1 | 
        
        
           | 
              el.setAttribute('inert', '') | 
        
        
           | 
              el.setAttribute('aria-hidden', 'true') | 
        
        
           | 
              el.setAttribute('x-on:focus', '$refs.listboxTrigger.focus()') | 
        
        
           | 
          
 | 
        
        
           | 
              if (expression) { | 
        
        
           | 
                el.setAttribute('x-model', expression) | 
        
        
           | 
                Alpine.nextTick(() => updateSelectedOptions()) | 
        
        
           | 
                evaluate(`$watch('${expression}', () => $data.$select.updateSelectedOptions())`) | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              const optionsMap = new WeakMap() | 
        
        
           | 
              function readOptions() { | 
        
        
           | 
                const options = [...el.options].filter(option => !option.disabled) | 
        
        
           | 
                return options.map(option => { | 
        
        
           | 
                  let id | 
        
        
           | 
                  if (optionsMap.has(option)) { | 
        
        
           | 
                    id = optionsMap.get(option) | 
        
        
           | 
                  } else { | 
        
        
           | 
                    id = crypto.randomUUID() | 
        
        
           | 
                    optionsMap.set(option, id) | 
        
        
           | 
                  } | 
        
        
           | 
          
 | 
        
        
           | 
                  return { | 
        
        
           | 
                    id, | 
        
        
           | 
                    value: option.value, | 
        
        
           | 
                    label: option.textContent, | 
        
        
           | 
                  } | 
        
        
           | 
                }) | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              const state = Alpine.reactive({ | 
        
        
           | 
                id: el.id ?? crypto.randomUUID(), | 
        
        
           | 
                placeholder: el.getAttribute('placeholder') ?? '', | 
        
        
           | 
                required: el.required, | 
        
        
           | 
                multiple: el.multiple, | 
        
        
           | 
                disabled: el.disabled, | 
        
        
           | 
                options: readOptions(), | 
        
        
           | 
          
 | 
        
        
           | 
                selectedOptions: [], | 
        
        
           | 
          
 | 
        
        
           | 
                get selectedOption() { | 
        
        
           | 
                  if (this.multiple) { | 
        
        
           | 
                    return this.selectedOptions | 
        
        
           | 
                  } else { | 
        
        
           | 
                    return this.selectedOptions[0] | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
                get modelValue() { | 
        
        
           | 
                  if (this.multiple) { | 
        
        
           | 
                    return this.selectedOptions.map(option => option.value) | 
        
        
           | 
                  } else { | 
        
        
           | 
                    return this.selectedOptions[0]?.value | 
        
        
           | 
                  } | 
        
        
           | 
                }, | 
        
        
           | 
              }) | 
        
        
           | 
          
 | 
        
        
           | 
              function readSelectedOptions() { | 
        
        
           | 
                return [...el.options].flatMap((option, index) => | 
        
        
           | 
                  option.selected ? state.options[index] : [], | 
        
        
           | 
                ) | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              state.selectedOptions = readSelectedOptions() | 
        
        
           | 
          
 | 
        
        
           | 
              const updateMultiple = () => (state.multiple = el.multiple) | 
        
        
           | 
              const updateDisabled = () => (state.disabled = el.disabled) | 
        
        
           | 
              const updateId = () => (state.id = el.id ?? crypto.randomUUID()) | 
        
        
           | 
              const updatePlaceholder = () => (state.placeholder = el.getAttribute('placeholder') ?? '') | 
        
        
           | 
              const updateRequired = () => (state.required = el.required) | 
        
        
           | 
          
 | 
        
        
           | 
              const updateState = (option, getter) => { | 
        
        
           | 
                const newData = getter() | 
        
        
           | 
                if (JSON.stringify(newData) !== JSON.stringify(state[option])) { | 
        
        
           | 
                  state[option] = newData | 
        
        
           | 
                } | 
        
        
           | 
              } | 
        
        
           | 
          
 | 
        
        
           | 
              const updateOptions = () => updateState('options', readOptions) | 
        
        
           | 
              const updateSelectedOptions = () => updateState('selectedOptions', readSelectedOptions) | 
        
        
           | 
          
 | 
        
        
           | 
              el.addEventListener('change', updateSelectedOptions) | 
        
        
           | 
          
 | 
        
        
           | 
              const observer = new MutationObserver(entries => { | 
        
        
           | 
                for (const entry of entries) { | 
        
        
           | 
                  if (entry.type === 'attributes') { | 
        
        
           | 
                    switch (entry.attributeName) { | 
        
        
           | 
                      case 'multiple': | 
        
        
           | 
                        updateMultiple() | 
        
        
           | 
                        updateSelectedOptions() | 
        
        
           | 
          
 | 
        
        
           | 
                        if (expression) { | 
        
        
           | 
                          el.dispatchEvent(new Event('change', { bubbles: true })) | 
        
        
           | 
                        } | 
        
        
           | 
                        break | 
        
        
           | 
                      case 'disabled': | 
        
        
           | 
                        updateDisabled() | 
        
        
           | 
                        break | 
        
        
           | 
                      case 'id': | 
        
        
           | 
                        updateId() | 
        
        
           | 
                        break | 
        
        
           | 
                      case 'placeholder': | 
        
        
           | 
                        updatePlaceholder() | 
        
        
           | 
                        break | 
        
        
           | 
                      case 'required': | 
        
        
           | 
                        updateRequired() | 
        
        
           | 
                        break | 
        
        
           | 
                    } | 
        
        
           | 
                  } else if (entry.type === 'childList') { | 
        
        
           | 
                    updateOptions() | 
        
        
           | 
                    updateSelectedOptions() | 
        
        
           | 
                  } | 
        
        
           | 
                } | 
        
        
           | 
              }) | 
        
        
           | 
          
 | 
        
        
           | 
              observer.observe(el, { | 
        
        
           | 
                childList: true, | 
        
        
           | 
                attributes: true, | 
        
        
           | 
                subtree: true, | 
        
        
           | 
                attributeFilter: ['multiple', 'disabled', 'id', 'placeholder', 'required'], | 
        
        
           | 
              }) | 
        
        
           | 
          
 | 
        
        
           | 
              // Expose API to $select | 
        
        
           | 
              await Alpine.nextTick() | 
        
        
           | 
              const $select = { | 
        
        
           | 
                el, | 
        
        
           | 
                wrapperElement: el.parentElement, | 
        
        
           | 
                props: { | 
        
        
           | 
                  get selectedOption() { | 
        
        
           | 
                    return state.selectedOption | 
        
        
           | 
                  }, | 
        
        
           | 
                  get modelValue() { | 
        
        
           | 
                    return state.modelValue | 
        
        
           | 
                  }, | 
        
        
           | 
                  get options() { | 
        
        
           | 
                    return state.options | 
        
        
           | 
                  }, | 
        
        
           | 
                  get id() { | 
        
        
           | 
                    return state.id | 
        
        
           | 
                  }, | 
        
        
           | 
                  get disabled() { | 
        
        
           | 
                    return state.disabled | 
        
        
           | 
                  }, | 
        
        
           | 
                  get multiple() { | 
        
        
           | 
                    return state.multiple | 
        
        
           | 
                  }, | 
        
        
           | 
                  get placeholder() { | 
        
        
           | 
                    return state.placeholder | 
        
        
           | 
                  }, | 
        
        
           | 
                  get required() { | 
        
        
           | 
                    return state.required | 
        
        
           | 
                  }, | 
        
        
           | 
                }, | 
        
        
           | 
                setValue(value) { | 
        
        
           | 
                  value = Array.isArray(value) ? value : [value] | 
        
        
           | 
          
 | 
        
        
           | 
                  for (const option of el.options) { | 
        
        
           | 
                    option.selected = value.includes(option.value) | 
        
        
           | 
                  } | 
        
        
           | 
          
 | 
        
        
           | 
                  el.dispatchEvent(new Event('change', { bubbles: true })) | 
        
        
           | 
                }, | 
        
        
           | 
                updateSelectedOptions, | 
        
        
           | 
                refresh() { | 
        
        
           | 
                  updateMultiple() | 
        
        
           | 
                  updateDisabled() | 
        
        
           | 
          
 | 
        
        
           | 
                  updateOptions() | 
        
        
           | 
                  updateId() | 
        
        
           | 
                  updatePlaceholder() | 
        
        
           | 
          
 | 
        
        
           | 
                  updateSelectedOptions() | 
        
        
           | 
                }, | 
        
        
           | 
              } | 
        
        
           | 
              evaluate('$data').$select = $select | 
        
        
           | 
              Alpine.evaluate(el.parentElement, '$data').$select = $select | 
        
        
           | 
          
 | 
        
        
           | 
              // Can't inject this earlier because we need the $select API to be available | 
        
        
           | 
              el.insertAdjacentHTML( | 
        
        
           | 
                'afterend', | 
        
        
           | 
                /*html*/ ` | 
        
        
           | 
                  <button | 
        
        
           | 
                    x-ref="listboxTrigger" | 
        
        
           | 
                    type="button" | 
        
        
           | 
                    class="x-select--select-trigger" | 
        
        
           | 
                    :class="{ inert: expanded }" | 
        
        
           | 
                    :disabled="props.disabled" | 
        
        
           | 
                    :id="idTrigger" | 
        
        
           | 
                    aria-haspopup="true" | 
        
        
           | 
                    :aria-expanded="expanded" | 
        
        
           | 
                    :aria-controls="idListbox" | 
        
        
           | 
                    @click="open()" | 
        
        
           | 
                    @keydown.up.prevent="$el.click()" | 
        
        
           | 
                    @keydown.down.prevent="$el.click()" | 
        
        
           | 
                  > | 
        
        
           | 
                    <span class="x-select--select-trigger-label" x-text="getPlaceholder(props.selectedOption)"></span> | 
        
        
           | 
                  </button> | 
        
        
           | 
                  <template x-if="expanded"> | 
        
        
           | 
                    <ul | 
        
        
           | 
                      x-ref="listbox" | 
        
        
           | 
                      class="x-select--select-listbox" | 
        
        
           | 
                      :id="idListbox" | 
        
        
           | 
                      :style="positioningStyles" | 
        
        
           | 
                      tabindex="0" | 
        
        
           | 
                      role="listbox" | 
        
        
           | 
                      aria-orientation="vertical" | 
        
        
           | 
                      :aria-labelledby="idTrigger" | 
        
        
           | 
                      :aria-activedescendant="activatedId" | 
        
        
           | 
                      @keydown="onListboxKeydown" | 
        
        
           | 
                      @mouseout="activatedIndex = undefined" | 
        
        
           | 
                      @blur="close()" | 
        
        
           | 
                    > | 
        
        
           | 
                      <template x-for="({ id, value, label }, index) in props.options"> | 
        
        
           | 
                        <li | 
        
        
           | 
                          :key="id" | 
        
        
           | 
                          :id="id" | 
        
        
           | 
                          class="x-select--select-listbox-item" | 
        
        
           | 
                          :class="{ | 
        
        
           | 
                            'is-active': activatedIndex === index, | 
        
        
           | 
                            'is-selected': valueArray.includes(value) | 
        
        
           | 
                          }" | 
        
        
           | 
                          role="option" | 
        
        
           | 
                          :aria-selected="valueArray.includes(value)" | 
        
        
           | 
                          :value="value" | 
        
        
           | 
                          tabindex="-1" | 
        
        
           | 
                          @mouseenter="activatedIndex = index" | 
        
        
           | 
                          @mousedown.prevent="commitSingleValue(value)" | 
        
        
           | 
                          x-text="label" | 
        
        
           | 
                        ></li> | 
        
        
           | 
                      </template> | 
        
        
           | 
                    </ul> | 
        
        
           | 
                  </template> | 
        
        
           | 
                `, | 
        
        
           | 
              ) | 
        
        
           | 
          
 | 
        
        
           | 
              // Stop observing select on cleanup | 
        
        
           | 
              cleanup(() => { | 
        
        
           | 
                observer.disconnect() | 
        
        
           | 
                el.removeEventListener('change', updateSelectedOptions) | 
        
        
           | 
          
 | 
        
        
           | 
                el.classList.remove('x-select--select-field') | 
        
        
           | 
                el.removeAttribute('inert') | 
        
        
           | 
                el.removeAttribute('x-model') | 
        
        
           | 
                el.removeAttribute('x-on:focus') | 
        
        
           | 
                el.removeAttribute(':class') | 
        
        
           | 
                el.removeAttribute('tabindex') | 
        
        
           | 
                el.removeAttribute('aria-hidden') | 
        
        
           | 
          
 | 
        
        
           | 
                if (document.contains(el)) { | 
        
        
           | 
                  const container = el.parentElement | 
        
        
           | 
                  container.after(el) | 
        
        
           | 
                  container.remove() | 
        
        
           | 
                } | 
        
        
           | 
              }) | 
        
        
           | 
            }) | 
        
        
           | 
          } | 
        
  
nice one. what's the license here?