@headlessui/vue
Advanced tools
Comparing version 0.1.3 to 0.1.4-alpha.1
@@ -101,2 +101,20 @@ 'use strict'; | ||
// TODO: This must already exist somewhere, right? 🤔 | ||
// Ref: https://www.w3.org/TR/uievents-key/#named-key-attribute-values | ||
var Keys; | ||
(function (Keys) { | ||
Keys["Space"] = " "; | ||
Keys["Enter"] = "Enter"; | ||
Keys["Escape"] = "Escape"; | ||
Keys["Backspace"] = "Backspace"; | ||
Keys["ArrowUp"] = "ArrowUp"; | ||
Keys["ArrowDown"] = "ArrowDown"; | ||
Keys["Home"] = "Home"; | ||
Keys["End"] = "End"; | ||
Keys["PageUp"] = "PageUp"; | ||
Keys["PageDown"] = "PageDown"; | ||
Keys["Tab"] = "Tab"; | ||
})(Keys || (Keys = {})); | ||
var MenuStates; | ||
@@ -107,22 +125,4 @@ | ||
MenuStates[MenuStates["Closed"] = 1] = "Closed"; | ||
})(MenuStates || (MenuStates = {})); // TODO: This must already exist somewhere, right? 🤔 | ||
// Ref: https://www.w3.org/TR/uievents-key/#named-key-attribute-values | ||
})(MenuStates || (MenuStates = {})); | ||
var Key; | ||
(function (Key) { | ||
Key["Space"] = " "; | ||
Key["Enter"] = "Enter"; | ||
Key["Escape"] = "Escape"; | ||
Key["Backspace"] = "Backspace"; | ||
Key["ArrowUp"] = "ArrowUp"; | ||
Key["ArrowDown"] = "ArrowDown"; | ||
Key["Home"] = "Home"; | ||
Key["End"] = "End"; | ||
Key["PageUp"] = "PageUp"; | ||
Key["PageDown"] = "PageDown"; | ||
Key["Tab"] = "Tab"; | ||
})(Key || (Key = {})); | ||
var Focus; | ||
@@ -282,5 +282,5 @@ | ||
window.addEventListener('pointerup', handler); | ||
window.addEventListener('click', handler); | ||
vue.onUnmounted(function () { | ||
return window.removeEventListener('pointerup', handler); | ||
return window.removeEventListener('click', handler); | ||
}); | ||
@@ -342,5 +342,5 @@ }); // @ts-expect-error Types of property 'dataRef' are incompatible. | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-13 | ||
case Key.Space: | ||
case Key.Enter: | ||
case Key.ArrowDown: | ||
case Keys.Space: | ||
case Keys.Enter: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
@@ -356,3 +356,3 @@ api.openMenu(); | ||
case Key.ArrowUp: | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
@@ -449,3 +449,12 @@ api.openMenu(); | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 | ||
case Key.Enter: | ||
// @ts-expect-error Fallthrough is expected here | ||
case Keys.Space: | ||
if (api.searchQuery.value !== '') { | ||
event.preventDefault(); | ||
return api.search(event.key); | ||
} | ||
// When in type ahead mode, fallthrough | ||
case Keys.Enter: | ||
event.preventDefault(); | ||
@@ -468,21 +477,21 @@ api.closeMenu(); | ||
case Key.ArrowDown: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.NextItem); | ||
case Key.ArrowUp: | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.PreviousItem); | ||
case Key.Home: | ||
case Key.PageUp: | ||
case Keys.Home: | ||
case Keys.PageUp: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.FirstItem); | ||
case Key.End: | ||
case Key.PageDown: | ||
case Keys.End: | ||
case Keys.PageDown: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.LastItem); | ||
case Key.Escape: | ||
case Keys.Escape: | ||
event.preventDefault(); | ||
@@ -497,3 +506,3 @@ api.closeMenu(); | ||
case Key.Tab: | ||
case Keys.Tab: | ||
return event.preventDefault(); | ||
@@ -568,5 +577,10 @@ | ||
function handlePointerEnter() { | ||
if (disabled) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
function handleClick(event) { | ||
if (disabled) return event.preventDefault(); | ||
api.closeMenu(); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value4; | ||
return (_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
}); | ||
} | ||
@@ -579,36 +593,627 @@ | ||
function handlePointerMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
} | ||
function handlePointerLeave() { | ||
if (disabled) return; | ||
if (!active.value) return; | ||
api.goToItem(Focus.Nothing); | ||
} | ||
function handleMouseMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
return function () { | ||
var slot = { | ||
active: active.value, | ||
disabled: disabled | ||
}; | ||
var propsWeControl = { | ||
id: id, | ||
role: 'menuitem', | ||
tabIndex: -1, | ||
"class": resolvePropValue(className, slot), | ||
'aria-disabled': disabled === true ? true : undefined, | ||
onClick: handleClick, | ||
onFocus: handleFocus, | ||
onPointerMove: handlePointerMove, | ||
onPointerLeave: handlePointerLeave | ||
}; | ||
return render({ | ||
props: _extends({}, props, propsWeControl), | ||
slot: slot, | ||
attrs: attrs, | ||
slots: slots | ||
}); | ||
}; | ||
} | ||
}); | ||
function resolvePropValue(property, bag) { | ||
if (property === undefined) return undefined; | ||
if (typeof property === 'function') return property(bag); | ||
return property; | ||
} | ||
var ListboxStates; | ||
(function (ListboxStates) { | ||
ListboxStates[ListboxStates["Open"] = 0] = "Open"; | ||
ListboxStates[ListboxStates["Closed"] = 1] = "Closed"; | ||
})(ListboxStates || (ListboxStates = {})); | ||
var Focus$1; | ||
(function (Focus) { | ||
Focus[Focus["First"] = 0] = "First"; | ||
Focus[Focus["Previous"] = 1] = "Previous"; | ||
Focus[Focus["Next"] = 2] = "Next"; | ||
Focus[Focus["Last"] = 3] = "Last"; | ||
Focus[Focus["Specific"] = 4] = "Specific"; | ||
Focus[Focus["Nothing"] = 5] = "Nothing"; | ||
})(Focus$1 || (Focus$1 = {})); | ||
var ListboxContext = /*#__PURE__*/Symbol('ListboxContext'); | ||
function useListboxContext(component) { | ||
var context = vue.inject(ListboxContext); | ||
if (context === undefined) { | ||
var err = new Error("<" + component + " /> is missing a parent <Listbox /> component."); | ||
if (Error.captureStackTrace) Error.captureStackTrace(err, useListboxContext); | ||
throw err; | ||
} | ||
return context; | ||
} // --- | ||
var Listbox = /*#__PURE__*/vue.defineComponent({ | ||
name: 'Listbox', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'template' | ||
}, | ||
modelValue: { | ||
type: [Object, String], | ||
"default": null | ||
} | ||
}, | ||
setup: function setup(props, _ref) { | ||
var slots = _ref.slots, | ||
attrs = _ref.attrs, | ||
emit = _ref.emit; | ||
function handlePointerUp(event) { | ||
if (disabled) return event.preventDefault(); // Turns out that we can't use nextTick here. Even if we do, the `handleClick` would *not* be | ||
// called because the closeMenu() update is *too fast* and the tree gets unmounted before it | ||
// bubbles up. So instead of nextTick, we use the good old double requestAnimationFrame to | ||
// wait for a "nextFrame". | ||
var passThroughProps = _objectWithoutPropertiesLoose(props, ["modelValue"]); | ||
requestAnimationFrame(function () { | ||
requestAnimationFrame(function () { | ||
var _api$buttonRef$value4; | ||
var listboxState = vue.ref(ListboxStates.Closed); | ||
var labelRef = vue.ref(null); | ||
var buttonRef = vue.ref(null); | ||
var optionsRef = vue.ref(null); | ||
var options = vue.ref([]); | ||
var searchQuery = vue.ref(''); | ||
var activeOptionIndex = vue.ref(null); | ||
var value = vue.computed(function () { | ||
return props.modelValue; | ||
}); | ||
api.closeMenu(); | ||
(_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
function calculateActiveOptionIndex(focus, id) { | ||
var _activeOptionIndex$va, _match; | ||
if (options.value.length <= 0) return null; | ||
var currentActiveOptionIndex = (_activeOptionIndex$va = activeOptionIndex.value) !== null && _activeOptionIndex$va !== void 0 ? _activeOptionIndex$va : -1; | ||
var nextActiveIndex = match(focus, (_match = {}, _match[Focus$1.First] = function () { | ||
return options.value.findIndex(function (option) { | ||
return !option.dataRef.disabled; | ||
}); | ||
}, _match[Focus$1.Previous] = function () { | ||
var idx = options.value.slice().reverse().findIndex(function (option, idx, all) { | ||
if (currentActiveOptionIndex !== -1 && all.length - idx - 1 >= currentActiveOptionIndex) return false; | ||
return !option.dataRef.disabled; | ||
}); | ||
if (idx === -1) return idx; | ||
return options.value.length - 1 - idx; | ||
}, _match[Focus$1.Next] = function () { | ||
return options.value.findIndex(function (option, idx) { | ||
if (idx <= currentActiveOptionIndex) return false; | ||
return !option.dataRef.disabled; | ||
}); | ||
}, _match[Focus$1.Last] = function () { | ||
var idx = options.value.slice().reverse().findIndex(function (option) { | ||
return !option.dataRef.disabled; | ||
}); | ||
if (idx === -1) return idx; | ||
return options.value.length - 1 - idx; | ||
}, _match[Focus$1.Specific] = function () { | ||
return options.value.findIndex(function (option) { | ||
return option.id === id; | ||
}); | ||
}, _match[Focus$1.Nothing] = function () { | ||
return null; | ||
}, _match)); | ||
if (nextActiveIndex === -1) return activeOptionIndex.value; | ||
return nextActiveIndex; | ||
} | ||
var api = { | ||
listboxState: listboxState, | ||
value: value, | ||
labelRef: labelRef, | ||
buttonRef: buttonRef, | ||
optionsRef: optionsRef, | ||
options: options, | ||
searchQuery: searchQuery, | ||
activeOptionIndex: activeOptionIndex, | ||
closeListbox: function closeListbox() { | ||
return listboxState.value = ListboxStates.Closed; | ||
}, | ||
openListbox: function openListbox() { | ||
return listboxState.value = ListboxStates.Open; | ||
}, | ||
goToOption: function goToOption(focus, id) { | ||
var nextActiveOptionIndex = calculateActiveOptionIndex(focus, id); | ||
if (searchQuery.value === '' && activeOptionIndex.value === nextActiveOptionIndex) return; | ||
searchQuery.value = ''; | ||
activeOptionIndex.value = nextActiveOptionIndex; | ||
}, | ||
search: function search(value) { | ||
searchQuery.value += value; | ||
var match = options.value.findIndex(function (option) { | ||
return !option.dataRef.disabled && option.dataRef.textValue.startsWith(searchQuery.value); | ||
}); | ||
if (match === -1 || match === activeOptionIndex.value) { | ||
return; | ||
} | ||
activeOptionIndex.value = match; | ||
}, | ||
clearSearch: function clearSearch() { | ||
searchQuery.value = ''; | ||
}, | ||
registerOption: function registerOption(id, dataRef) { | ||
// @ts-expect-error The expected type comes from property 'dataRef' which is declared here on type '{ id: string; dataRef: { textValue: string; disabled: boolean; }; }' | ||
options.value.push({ | ||
id: id, | ||
dataRef: dataRef | ||
}); | ||
}, | ||
unregisterOption: function unregisterOption(id) { | ||
var nextOptions = options.value.slice(); | ||
var currentActiveOption = activeOptionIndex.value !== null ? nextOptions[activeOptionIndex.value] : null; | ||
var idx = nextOptions.findIndex(function (a) { | ||
return a.id === id; | ||
}); | ||
if (idx !== -1) nextOptions.splice(idx, 1); | ||
options.value = nextOptions; | ||
activeOptionIndex.value = function () { | ||
if (idx === activeOptionIndex.value) return null; | ||
if (currentActiveOption === null) return null; // If we removed the option before the actual active index, then it would be out of sync. To | ||
// fix this, we will find the correct (new) index position. | ||
return nextOptions.indexOf(currentActiveOption); | ||
}(); | ||
}, | ||
select: function select(value) { | ||
emit('update:modelValue', value); | ||
} | ||
}; | ||
vue.onMounted(function () { | ||
function handler(event) { | ||
var _buttonRef$value, _optionsRef$value; | ||
if (listboxState.value !== ListboxStates.Open) return; | ||
if ((_buttonRef$value = buttonRef.value) === null || _buttonRef$value === void 0 ? void 0 : _buttonRef$value.contains(event.target)) return; | ||
if (!((_optionsRef$value = optionsRef.value) === null || _optionsRef$value === void 0 ? void 0 : _optionsRef$value.contains(event.target))) { | ||
var _buttonRef$value2; | ||
api.closeListbox(); | ||
if (!event.defaultPrevented) (_buttonRef$value2 = buttonRef.value) === null || _buttonRef$value2 === void 0 ? void 0 : _buttonRef$value2.focus(); | ||
} | ||
} | ||
window.addEventListener('click', handler); | ||
vue.onUnmounted(function () { | ||
return window.removeEventListener('click', handler); | ||
}); | ||
}); // @ts-expect-error Types of property 'dataRef' are incompatible. | ||
vue.provide(ListboxContext, api); | ||
return function () { | ||
var slot = { | ||
open: listboxState.value === ListboxStates.Open | ||
}; | ||
return render({ | ||
props: passThroughProps, | ||
slot: slot, | ||
slots: slots, | ||
attrs: attrs | ||
}); | ||
}; | ||
} | ||
}); // --- | ||
var ListboxLabel = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxLabel', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'label' | ||
} | ||
}, | ||
render: function render$1() { | ||
var api = useListboxContext('ListboxLabel'); | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open | ||
}; | ||
var propsWeControl = { | ||
id: this.id, | ||
ref: 'el', | ||
onPointerUp: this.handlePointerUp | ||
}; | ||
return render({ | ||
props: _extends({}, this.$props, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxLabel'); | ||
var id = "headlessui-listbox-label-" + useId(); | ||
return { | ||
id: id, | ||
el: api.labelRef, | ||
handlePointerUp: function handlePointerUp() { | ||
var _api$buttonRef$value; | ||
(_api$buttonRef$value = api.buttonRef.value) === null || _api$buttonRef$value === void 0 ? void 0 : _api$buttonRef$value.focus(); | ||
} | ||
}; | ||
} | ||
}); // --- | ||
var ListboxButton = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxButton', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'button' | ||
} | ||
}, | ||
render: function render$1() { | ||
var _api$optionsRef$value; | ||
var api = useListboxContext('ListboxButton'); | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open, | ||
focused: this.focused | ||
}; | ||
var propsWeControl = { | ||
ref: 'el', | ||
id: this.id, | ||
type: 'button', | ||
'aria-haspopup': true, | ||
'aria-controls': (_api$optionsRef$value = api.optionsRef.value) === null || _api$optionsRef$value === void 0 ? void 0 : _api$optionsRef$value.id, | ||
'aria-expanded': api.listboxState.value === ListboxStates.Open ? true : undefined, | ||
'aria-labelledby': api.labelRef.value ? [api.labelRef.value.id, this.id].join(' ') : undefined, | ||
onKeyDown: this.handleKeyDown, | ||
onFocus: this.handleFocus, | ||
onBlur: this.handleBlur, | ||
onPointerUp: this.handlePointerUp | ||
}; | ||
return render({ | ||
props: _extends({}, this.$props, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxButton'); | ||
var id = "headlessui-listbox-button-" + useId(); | ||
var focused = vue.ref(false); | ||
function handleKeyDown(event) { | ||
switch (event.key) { | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-13 | ||
case Keys.Space: | ||
case Keys.Enter: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
api.openListbox(); | ||
vue.nextTick(function () { | ||
var _api$optionsRef$value2; | ||
(_api$optionsRef$value2 = api.optionsRef.value) === null || _api$optionsRef$value2 === void 0 ? void 0 : _api$optionsRef$value2.focus(); | ||
if (!api.value.value) api.goToOption(Focus$1.First); | ||
}); | ||
break; | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
api.openListbox(); | ||
vue.nextTick(function () { | ||
var _api$optionsRef$value3; | ||
(_api$optionsRef$value3 = api.optionsRef.value) === null || _api$optionsRef$value3 === void 0 ? void 0 : _api$optionsRef$value3.focus(); | ||
if (!api.value.value) api.goToOption(Focus$1.Last); | ||
}); | ||
break; | ||
} | ||
} | ||
function handlePointerUp(event) { | ||
if (api.listboxState.value === ListboxStates.Open) { | ||
api.closeListbox(); | ||
} else { | ||
event.preventDefault(); | ||
api.openListbox(); | ||
vue.nextTick(function () { | ||
var _api$optionsRef$value4; | ||
return (_api$optionsRef$value4 = api.optionsRef.value) === null || _api$optionsRef$value4 === void 0 ? void 0 : _api$optionsRef$value4.focus(); | ||
}); | ||
} | ||
} | ||
function handleFocus() { | ||
var _api$optionsRef$value5; | ||
if (api.listboxState.value === ListboxStates.Open) return (_api$optionsRef$value5 = api.optionsRef.value) === null || _api$optionsRef$value5 === void 0 ? void 0 : _api$optionsRef$value5.focus(); | ||
focused.value = true; | ||
} | ||
function handleBlur() { | ||
focused.value = false; | ||
} | ||
return { | ||
id: id, | ||
el: api.buttonRef, | ||
focused: focused, | ||
handleKeyDown: handleKeyDown, | ||
handlePointerUp: handlePointerUp, | ||
handleFocus: handleFocus, | ||
handleBlur: handleBlur | ||
}; | ||
} | ||
}); // --- | ||
var ListboxOptions = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxOptions', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'ul' | ||
}, | ||
"static": { | ||
type: Boolean, | ||
"default": false | ||
} | ||
}, | ||
render: function render$1() { | ||
var _api$options$value$ap, _api$labelRef$value$i, _api$labelRef$value, _api$buttonRef$value2; | ||
var api = useListboxContext('ListboxOptions'); // `static` is a reserved keyword, therefore aliasing it... | ||
var _this$$props = this.$props, | ||
isStatic = _this$$props["static"], | ||
passThroughProps = _objectWithoutPropertiesLoose(_this$$props, ["static"]); | ||
if (!isStatic && api.listboxState.value === ListboxStates.Closed) return null; | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open | ||
}; | ||
var propsWeControl = { | ||
'aria-activedescendant': api.activeOptionIndex.value === null ? undefined : (_api$options$value$ap = api.options.value[api.activeOptionIndex.value]) === null || _api$options$value$ap === void 0 ? void 0 : _api$options$value$ap.id, | ||
'aria-labelledby': (_api$labelRef$value$i = (_api$labelRef$value = api.labelRef.value) === null || _api$labelRef$value === void 0 ? void 0 : _api$labelRef$value.id) !== null && _api$labelRef$value$i !== void 0 ? _api$labelRef$value$i : (_api$buttonRef$value2 = api.buttonRef.value) === null || _api$buttonRef$value2 === void 0 ? void 0 : _api$buttonRef$value2.id, | ||
id: this.id, | ||
onKeyDown: this.handleKeyDown, | ||
role: 'listbox', | ||
tabIndex: 0, | ||
ref: 'el' | ||
}; | ||
return render({ | ||
props: _extends({}, passThroughProps, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxOptions'); | ||
var id = "headlessui-listbox-options-" + useId(); | ||
var searchDebounce = vue.ref(null); | ||
function handleKeyDown(event) { | ||
if (searchDebounce.value) clearTimeout(searchDebounce.value); | ||
switch (event.key) { | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 | ||
// @ts-expect-error Fallthrough is expected here | ||
case Keys.Space: | ||
if (api.searchQuery.value !== '') { | ||
event.preventDefault(); | ||
return api.search(event.key); | ||
} | ||
// When in type ahead mode, fallthrough | ||
case Keys.Enter: | ||
event.preventDefault(); | ||
api.closeListbox(); | ||
if (api.activeOptionIndex.value !== null) { | ||
var dataRef = api.options.value[api.activeOptionIndex.value].dataRef; | ||
api.select(dataRef.value); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value3; | ||
return (_api$buttonRef$value3 = api.buttonRef.value) === null || _api$buttonRef$value3 === void 0 ? void 0 : _api$buttonRef$value3.focus(); | ||
}); | ||
} | ||
break; | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Next); | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Previous); | ||
case Keys.Home: | ||
case Keys.PageUp: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.First); | ||
case Keys.End: | ||
case Keys.PageDown: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Last); | ||
case Keys.Escape: | ||
event.preventDefault(); | ||
api.closeListbox(); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value4; | ||
return (_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
}); | ||
break; | ||
case Keys.Tab: | ||
return event.preventDefault(); | ||
default: | ||
if (event.key.length === 1) { | ||
api.search(event.key); | ||
searchDebounce.value = setTimeout(function () { | ||
return api.clearSearch(); | ||
}, 350); | ||
} | ||
break; | ||
} | ||
} | ||
return { | ||
id: id, | ||
el: api.optionsRef, | ||
handleKeyDown: handleKeyDown | ||
}; | ||
} | ||
}); | ||
var ListboxOption = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxOption', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'li' | ||
}, | ||
value: { | ||
type: [Object, String], | ||
"default": null | ||
}, | ||
disabled: { | ||
type: Boolean, | ||
"default": false | ||
}, | ||
"class": { | ||
type: [String, Function], | ||
required: false | ||
}, | ||
className: { | ||
type: [String, Function], | ||
required: false | ||
} | ||
}, | ||
setup: function setup(props, _ref2) { | ||
var slots = _ref2.slots, | ||
attrs = _ref2.attrs; | ||
var api = useListboxContext('ListboxOption'); | ||
var id = "headlessui-listbox-option-" + useId(); | ||
var disabled = props.disabled, | ||
defaultClass = props["class"], | ||
_props$className = props.className, | ||
className = _props$className === void 0 ? defaultClass : _props$className, | ||
value = props.value; | ||
var active = vue.computed(function () { | ||
return api.activeOptionIndex.value !== null ? api.options.value[api.activeOptionIndex.value].id === id : false; | ||
}); | ||
var selected = vue.computed(function () { | ||
return api.value.value === value; | ||
}); | ||
var dataRef = vue.ref({ | ||
disabled: disabled, | ||
value: value, | ||
textValue: '' | ||
}); | ||
vue.onMounted(function () { | ||
var _document$getElementB, _document$getElementB2; | ||
var textValue = (_document$getElementB = document.getElementById(id)) === null || _document$getElementB === void 0 ? void 0 : (_document$getElementB2 = _document$getElementB.textContent) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.toLowerCase().trim(); | ||
if (textValue !== undefined) dataRef.value.textValue = textValue; | ||
}); | ||
vue.onMounted(function () { | ||
return api.registerOption(id, dataRef); | ||
}); | ||
vue.onUnmounted(function () { | ||
return api.unregisterOption(id); | ||
}); | ||
vue.onMounted(function () { | ||
var _document$getElementB3, _document$getElementB4; | ||
if (!selected.value) return; | ||
api.goToOption(Focus$1.Specific, id); | ||
(_document$getElementB3 = document.getElementById(id)) === null || _document$getElementB3 === void 0 ? void 0 : (_document$getElementB4 = _document$getElementB3.focus) === null || _document$getElementB4 === void 0 ? void 0 : _document$getElementB4.call(_document$getElementB3); | ||
}); | ||
vue.watchEffect(function () { | ||
if (!active.value) return; | ||
vue.nextTick(function () { | ||
var _document$getElementB5, _document$getElementB6; | ||
return (_document$getElementB5 = document.getElementById(id)) === null || _document$getElementB5 === void 0 ? void 0 : (_document$getElementB6 = _document$getElementB5.scrollIntoView) === null || _document$getElementB6 === void 0 ? void 0 : _document$getElementB6.call(_document$getElementB5, { | ||
block: 'nearest' | ||
}); | ||
}); | ||
}); | ||
function handleClick(event) { | ||
if (disabled) return event.preventDefault(); | ||
api.select(value); | ||
api.closeListbox(); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value5; | ||
return (_api$buttonRef$value5 = api.buttonRef.value) === null || _api$buttonRef$value5 === void 0 ? void 0 : _api$buttonRef$value5.focus(); | ||
}); | ||
} | ||
function handleFocus() { | ||
if (disabled) return api.goToOption(Focus$1.Nothing); | ||
api.goToOption(Focus$1.Specific, id); | ||
} | ||
function handlePointerMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToOption(Focus$1.Specific, id); | ||
} | ||
function handlePointerLeave() { | ||
if (disabled) return; | ||
if (!active.value) return; | ||
api.goToOption(Focus$1.Nothing); | ||
} | ||
return function () { | ||
var slot = { | ||
active: active.value, | ||
selected: selected.value, | ||
disabled: disabled | ||
@@ -618,12 +1223,11 @@ }; | ||
id: id, | ||
role: 'menuitem', | ||
role: 'option', | ||
tabIndex: -1, | ||
"class": resolvePropValue(className, slot), | ||
"class": resolvePropValue$1(className, slot), | ||
'aria-disabled': disabled === true ? true : undefined, | ||
'aria-selected': selected.value === true ? selected.value : undefined, | ||
onClick: handleClick, | ||
onFocus: handleFocus, | ||
onMouseMove: handleMouseMove, | ||
onPointerEnter: handlePointerEnter, | ||
onPointerLeave: handlePointerLeave, | ||
onPointerUp: handlePointerUp | ||
onPointerMove: handlePointerMove, | ||
onPointerLeave: handlePointerLeave | ||
}; | ||
@@ -638,5 +1242,5 @@ return render({ | ||
} | ||
}); | ||
}); // --- | ||
function resolvePropValue(property, bag) { | ||
function resolvePropValue$1(property, bag) { | ||
if (property === undefined) return undefined; | ||
@@ -647,2 +1251,7 @@ if (typeof property === 'function') return property(bag); | ||
exports.Listbox = Listbox; | ||
exports.ListboxButton = ListboxButton; | ||
exports.ListboxLabel = ListboxLabel; | ||
exports.ListboxOption = ListboxOption; | ||
exports.ListboxOptions = ListboxOptions; | ||
exports.Menu = Menu; | ||
@@ -649,0 +1258,0 @@ exports.MenuButton = MenuButton; |
@@ -1,2 +0,2 @@ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue");function t(){return(t=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e}).apply(this,arguments)}function n(e,t){if(null==e)return{};var n,r,u={},o=Object.keys(e);for(r=0;r<o.length;r++)t.indexOf(n=o[r])>=0||(u[n]=e[n]);return u}function r(e,t){if(e in t){for(var n=t[e],u=arguments.length,o=new Array(u>2?u-2:0),a=2;a<u;a++)o[a-2]=arguments[a];return"function"==typeof n?n.apply(void 0,o):n}var i=new Error('Tried to handle "'+e+'" but there is no handler defined. Only defined handlers are: '+Object.keys(t).map((function(e){return'"'+e+'"'})).join(", ")+".");throw Error.captureStackTrace&&Error.captureStackTrace(i,r),i}function u(t){var r,u=t.props,o=t.attrs,a=t.slots,i=t.slot,l=u.as,s=n(u,["as"]),c=null===(r=a.default)||void 0===r?void 0:r.call(a,i);if("template"===l){if(Object.keys(s).length>0||"class"in o){var v=null!=c?c:[],d=v[0];if(v.slice(1).length>0)throw new Error('You should only render 1 child or use the `as="..."` prop');return e.cloneVNode(d,s)}return c}return e.h(l,s,c)}var o,a,i,l=0;function s(){return++l}!function(e){e[e.Open=0]="Open",e[e.Closed=1]="Closed"}(o||(o={})),function(e){e.Space=" ",e.Enter="Enter",e.Escape="Escape",e.Backspace="Backspace",e.ArrowUp="ArrowUp",e.ArrowDown="ArrowDown",e.Home="Home",e.End="End",e.PageUp="PageUp",e.PageDown="PageDown",e.Tab="Tab"}(a||(a={})),function(e){e[e.FirstItem=0]="FirstItem",e[e.PreviousItem=1]="PreviousItem",e[e.NextItem=2]="NextItem",e[e.LastItem=3]="LastItem",e[e.SpecificItem=4]="SpecificItem",e[e.Nothing=5]="Nothing"}(i||(i={}));var c=Symbol("MenuContext");function v(t){var n=e.inject(c);if(void 0===n){var r=new Error("<"+t+" /> is missing a parent <Menu /> component.");throw Error.captureStackTrace&&Error.captureStackTrace(r,v),r}return n}var d=e.defineComponent({props:{as:{type:[Object,String],default:"template"}},setup:function(t,n){var a=n.slots,l=n.attrs,s=e.ref(o.Closed),v=e.ref(null),d=e.ref(null),f=e.ref([]),p=e.ref(""),m=e.ref(null),I={menuState:s,buttonRef:v,itemsRef:d,items:f,searchQuery:p,activeItemIndex:m,closeMenu:function(){return s.value=o.Closed},openMenu:function(){return s.value=o.Open},goToItem:function(e,t){var n=function(e,t){var n,u;if(f.value.length<=0)return null;var o=null!==(n=m.value)&&void 0!==n?n:-1,a=r(e,((u={})[i.FirstItem]=function(){return f.value.findIndex((function(e){return!e.dataRef.disabled}))},u[i.PreviousItem]=function(){var e=f.value.slice().reverse().findIndex((function(e,t,n){return!(-1!==o&&n.length-t-1>=o||e.dataRef.disabled)}));return-1===e?e:f.value.length-1-e},u[i.NextItem]=function(){return f.value.findIndex((function(e,t){return!(t<=o||e.dataRef.disabled)}))},u[i.LastItem]=function(){var e=f.value.slice().reverse().findIndex((function(e){return!e.dataRef.disabled}));return-1===e?e:f.value.length-1-e},u[i.SpecificItem]=function(){return f.value.findIndex((function(e){return e.id===t}))},u[i.Nothing]=function(){return null},u));return-1===a?m.value:a}(e,t);""===p.value&&m.value===n||(p.value="",m.value=n)},search:function(e){p.value+=e;var t=f.value.findIndex((function(e){return e.dataRef.textValue.startsWith(p.value)&&!e.dataRef.disabled}));-1!==t&&t!==m.value&&(m.value=t)},clearSearch:function(){p.value=""},registerItem:function(e,t){f.value.push({id:e,dataRef:t})},unregisterItem:function(e){var t=f.value.slice(),n=null!==m.value?t[m.value]:null,r=t.findIndex((function(t){return t.id===e}));-1!==r&&t.splice(r,1),f.value=t,m.value=r===m.value||null===n?null:t.indexOf(n)}};return e.onMounted((function(){function t(e){var t,n,r;s.value===o.Open&&((null===(t=v.value)||void 0===t?void 0:t.contains(e.target))||(null===(n=d.value)||void 0===n?void 0:n.contains(e.target))||(I.closeMenu(),e.defaultPrevented||null===(r=v.value)||void 0===r||r.focus()))}window.addEventListener("pointerup",t),e.onUnmounted((function(){return window.removeEventListener("pointerup",t)}))})),e.provide(c,I),function(){return u({props:t,slot:{open:s.value===o.Open},slots:a,attrs:l})}}}),f=e.defineComponent({props:{as:{type:[Object,String],default:"button"}},render:function(){var e,n=v("MenuButton"),r={open:n.menuState.value===o.Open},a={ref:"el",id:this.id,type:"button","aria-haspopup":!0,"aria-controls":null===(e=n.itemsRef.value)||void 0===e?void 0:e.id,"aria-expanded":n.menuState.value===o.Open||void 0,onKeyDown:this.handleKeyDown,onFocus:this.handleFocus,onPointerUp:this.handlePointerUp};return u({props:t({},this.$props,a),slot:r,attrs:this.$attrs,slots:this.$slots})},setup:function(){var t=v("MenuButton");return{id:"headlessui-menu-button-"+s(),el:t.buttonRef,handleKeyDown:function(n){switch(n.key){case a.Space:case a.Enter:case a.ArrowDown:n.preventDefault(),t.openMenu(),e.nextTick((function(){var e;null===(e=t.itemsRef.value)||void 0===e||e.focus(),t.goToItem(i.FirstItem)}));break;case a.ArrowUp:n.preventDefault(),t.openMenu(),e.nextTick((function(){var e;null===(e=t.itemsRef.value)||void 0===e||e.focus(),t.goToItem(i.LastItem)}))}},handlePointerUp:function(n){t.menuState.value===o.Open?t.closeMenu():(n.preventDefault(),t.openMenu(),e.nextTick((function(){var e;return null===(e=t.itemsRef.value)||void 0===e?void 0:e.focus()})))},handleFocus:function(){var e;t.menuState.value===o.Open&&(null===(e=t.itemsRef.value)||void 0===e||e.focus())}}}}),p=e.defineComponent({props:{as:{type:[Object,String],default:"div"},static:{type:Boolean,default:!1}},render:function(){var e,r,a=v("MenuItems"),i=this.$props,l=i.static,s=n(i,["static"]);if(!l&&a.menuState.value===o.Closed)return null;var c={open:a.menuState.value===o.Open};return u({props:t({},s,{"aria-activedescendant":null===a.activeItemIndex.value||null===(e=a.items.value[a.activeItemIndex.value])||void 0===e?void 0:e.id,"aria-labelledby":null===(r=a.buttonRef.value)||void 0===r?void 0:r.id,id:this.id,onKeyDown:this.handleKeyDown,role:"menu",tabIndex:0,ref:"el"}),slot:c,attrs:this.$attrs,slots:this.$slots})},setup:function(){var t=v("MenuItems"),n="headlessui-menu-items-"+s(),r=e.ref(null);return{id:n,el:t.itemsRef,handleKeyDown:function(n){switch(r.value&&clearTimeout(r.value),n.key){case a.Enter:var u;n.preventDefault(),t.closeMenu(),null!==t.activeItemIndex.value&&(null===(u=document.getElementById(t.items.value[t.activeItemIndex.value].id))||void 0===u||u.click(),e.nextTick((function(){var e;return null===(e=t.buttonRef.value)||void 0===e?void 0:e.focus()})));break;case a.ArrowDown:return n.preventDefault(),t.goToItem(i.NextItem);case a.ArrowUp:return n.preventDefault(),t.goToItem(i.PreviousItem);case a.Home:case a.PageUp:return n.preventDefault(),t.goToItem(i.FirstItem);case a.End:case a.PageDown:return n.preventDefault(),t.goToItem(i.LastItem);case a.Escape:n.preventDefault(),t.closeMenu(),e.nextTick((function(){var e;return null===(e=t.buttonRef.value)||void 0===e?void 0:e.focus()}));break;case a.Tab:return n.preventDefault();default:1===n.key.length&&(t.search(n.key),r.value=setTimeout((function(){return t.clearSearch()}),350))}}}}}),m=e.defineComponent({props:{as:{type:[Object,String],default:"template"},disabled:{type:Boolean,default:!1},class:{type:[String,Function],required:!1},className:{type:[String,Function],required:!1}},setup:function(n,r){var o=r.slots,a=r.attrs,l=v("MenuItem"),c="headlessui-menu-item-"+s(),d=n.disabled,f=n.className,p=void 0===f?n.class:f,m=e.computed((function(){return null!==l.activeItemIndex.value&&l.items.value[l.activeItemIndex.value].id===c})),h=e.ref({disabled:d,textValue:""});function g(){d||l.goToItem(i.SpecificItem,c)}function b(){if(d)return l.goToItem(i.Nothing);l.goToItem(i.SpecificItem,c)}function x(){d||l.goToItem(i.Nothing)}function y(){d||m.value||l.goToItem(i.SpecificItem,c)}function w(e){if(d)return e.preventDefault();requestAnimationFrame((function(){requestAnimationFrame((function(){var e;l.closeMenu(),null===(e=l.buttonRef.value)||void 0===e||e.focus()}))}))}function S(e){if(d)return e.preventDefault()}return e.onMounted((function(){var e,t,n=null===(e=document.getElementById(c))||void 0===e||null===(t=e.textContent)||void 0===t?void 0:t.toLowerCase().trim();void 0!==n&&(h.value.textValue=n)})),e.onMounted((function(){return l.registerItem(c,h)})),e.onUnmounted((function(){return l.unregisterItem(c)})),function(){var e={active:m.value,disabled:d},r={id:c,role:"menuitem",tabIndex:-1,class:I(p,e),"aria-disabled":!0===d||void 0,onClick:S,onFocus:b,onMouseMove:y,onPointerEnter:g,onPointerLeave:x,onPointerUp:w};return u({props:t({},n,r),slot:e,attrs:a,slots:o})}}});function I(e,t){if(void 0!==e)return"function"==typeof e?e(t):e}exports.Menu=d,exports.MenuButton=f,exports.MenuItem=m,exports.MenuItems=p; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue");function t(){return(t=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e}).apply(this,arguments)}function n(e,t){if(null==e)return{};var n,o,u={},i=Object.keys(e);for(o=0;o<i.length;o++)t.indexOf(n=i[o])>=0||(u[n]=e[n]);return u}function o(e,t){if(e in t){for(var n=t[e],u=arguments.length,i=new Array(u>2?u-2:0),a=2;a<u;a++)i[a-2]=arguments[a];return"function"==typeof n?n.apply(void 0,i):n}var r=new Error('Tried to handle "'+e+'" but there is no handler defined. Only defined handlers are: '+Object.keys(t).map((function(e){return'"'+e+'"'})).join(", ")+".");throw Error.captureStackTrace&&Error.captureStackTrace(r,o),r}function u(t){var o,u=t.props,i=t.attrs,a=t.slots,r=t.slot,l=u.as,s=n(u,["as"]),c=null===(o=a.default)||void 0===o?void 0:o.call(a,r);if("template"===l){if(Object.keys(s).length>0||"class"in i){var v=null!=c?c:[],d=v[0];if(v.slice(1).length>0)throw new Error('You should only render 1 child or use the `as="..."` prop');return e.cloneVNode(d,s)}return c}return e.h(l,s,c)}var i,a,r,l=0;function s(){return++l}!function(e){e.Space=" ",e.Enter="Enter",e.Escape="Escape",e.Backspace="Backspace",e.ArrowUp="ArrowUp",e.ArrowDown="ArrowDown",e.Home="Home",e.End="End",e.PageUp="PageUp",e.PageDown="PageDown",e.Tab="Tab"}(i||(i={})),function(e){e[e.Open=0]="Open",e[e.Closed=1]="Closed"}(a||(a={})),function(e){e[e.FirstItem=0]="FirstItem",e[e.PreviousItem=1]="PreviousItem",e[e.NextItem=2]="NextItem",e[e.LastItem=3]="LastItem",e[e.SpecificItem=4]="SpecificItem",e[e.Nothing=5]="Nothing"}(r||(r={}));var c=Symbol("MenuContext");function v(t){var n=e.inject(c);if(void 0===n){var o=new Error("<"+t+" /> is missing a parent <Menu /> component.");throw Error.captureStackTrace&&Error.captureStackTrace(o,v),o}return n}var d,f,p=e.defineComponent({props:{as:{type:[Object,String],default:"template"}},setup:function(t,n){var i=n.slots,l=n.attrs,s=e.ref(a.Closed),v=e.ref(null),d=e.ref(null),f=e.ref([]),p=e.ref(""),m=e.ref(null),b={menuState:s,buttonRef:v,itemsRef:d,items:f,searchQuery:p,activeItemIndex:m,closeMenu:function(){return s.value=a.Closed},openMenu:function(){return s.value=a.Open},goToItem:function(e,t){var n=function(e,t){var n,u;if(f.value.length<=0)return null;var i=null!==(n=m.value)&&void 0!==n?n:-1,a=o(e,((u={})[r.FirstItem]=function(){return f.value.findIndex((function(e){return!e.dataRef.disabled}))},u[r.PreviousItem]=function(){var e=f.value.slice().reverse().findIndex((function(e,t,n){return!(-1!==i&&n.length-t-1>=i||e.dataRef.disabled)}));return-1===e?e:f.value.length-1-e},u[r.NextItem]=function(){return f.value.findIndex((function(e,t){return!(t<=i||e.dataRef.disabled)}))},u[r.LastItem]=function(){var e=f.value.slice().reverse().findIndex((function(e){return!e.dataRef.disabled}));return-1===e?e:f.value.length-1-e},u[r.SpecificItem]=function(){return f.value.findIndex((function(e){return e.id===t}))},u[r.Nothing]=function(){return null},u));return-1===a?m.value:a}(e,t);""===p.value&&m.value===n||(p.value="",m.value=n)},search:function(e){p.value+=e;var t=f.value.findIndex((function(e){return e.dataRef.textValue.startsWith(p.value)&&!e.dataRef.disabled}));-1!==t&&t!==m.value&&(m.value=t)},clearSearch:function(){p.value=""},registerItem:function(e,t){f.value.push({id:e,dataRef:t})},unregisterItem:function(e){var t=f.value.slice(),n=null!==m.value?t[m.value]:null,o=t.findIndex((function(t){return t.id===e}));-1!==o&&t.splice(o,1),f.value=t,m.value=o===m.value||null===n?null:t.indexOf(n)}};return e.onMounted((function(){function t(e){var t,n,o;s.value===a.Open&&((null===(t=v.value)||void 0===t?void 0:t.contains(e.target))||(null===(n=d.value)||void 0===n?void 0:n.contains(e.target))||(b.closeMenu(),e.defaultPrevented||null===(o=v.value)||void 0===o||o.focus()))}window.addEventListener("click",t),e.onUnmounted((function(){return window.removeEventListener("click",t)}))})),e.provide(c,b),function(){return u({props:t,slot:{open:s.value===a.Open},slots:i,attrs:l})}}}),m=e.defineComponent({props:{as:{type:[Object,String],default:"button"}},render:function(){var e,n=v("MenuButton"),o={open:n.menuState.value===a.Open},i={ref:"el",id:this.id,type:"button","aria-haspopup":!0,"aria-controls":null===(e=n.itemsRef.value)||void 0===e?void 0:e.id,"aria-expanded":n.menuState.value===a.Open||void 0,onKeyDown:this.handleKeyDown,onFocus:this.handleFocus,onPointerUp:this.handlePointerUp};return u({props:t({},this.$props,i),slot:o,attrs:this.$attrs,slots:this.$slots})},setup:function(){var t=v("MenuButton");return{id:"headlessui-menu-button-"+s(),el:t.buttonRef,handleKeyDown:function(n){switch(n.key){case i.Space:case i.Enter:case i.ArrowDown:n.preventDefault(),t.openMenu(),e.nextTick((function(){var e;null===(e=t.itemsRef.value)||void 0===e||e.focus(),t.goToItem(r.FirstItem)}));break;case i.ArrowUp:n.preventDefault(),t.openMenu(),e.nextTick((function(){var e;null===(e=t.itemsRef.value)||void 0===e||e.focus(),t.goToItem(r.LastItem)}))}},handlePointerUp:function(n){t.menuState.value===a.Open?t.closeMenu():(n.preventDefault(),t.openMenu(),e.nextTick((function(){var e;return null===(e=t.itemsRef.value)||void 0===e?void 0:e.focus()})))},handleFocus:function(){var e;t.menuState.value===a.Open&&(null===(e=t.itemsRef.value)||void 0===e||e.focus())}}}}),b=e.defineComponent({props:{as:{type:[Object,String],default:"div"},static:{type:Boolean,default:!1}},render:function(){var e,o,i=v("MenuItems"),r=this.$props,l=r.static,s=n(r,["static"]);if(!l&&i.menuState.value===a.Closed)return null;var c={open:i.menuState.value===a.Open};return u({props:t({},s,{"aria-activedescendant":null===i.activeItemIndex.value||null===(e=i.items.value[i.activeItemIndex.value])||void 0===e?void 0:e.id,"aria-labelledby":null===(o=i.buttonRef.value)||void 0===o?void 0:o.id,id:this.id,onKeyDown:this.handleKeyDown,role:"menu",tabIndex:0,ref:"el"}),slot:c,attrs:this.$attrs,slots:this.$slots})},setup:function(){var t=v("MenuItems"),n="headlessui-menu-items-"+s(),o=e.ref(null);return{id:n,el:t.itemsRef,handleKeyDown:function(n){switch(o.value&&clearTimeout(o.value),n.key){case i.Space:if(""!==t.searchQuery.value)return n.preventDefault(),t.search(n.key);case i.Enter:var u;n.preventDefault(),t.closeMenu(),null!==t.activeItemIndex.value&&(null===(u=document.getElementById(t.items.value[t.activeItemIndex.value].id))||void 0===u||u.click(),e.nextTick((function(){var e;return null===(e=t.buttonRef.value)||void 0===e?void 0:e.focus()})));break;case i.ArrowDown:return n.preventDefault(),t.goToItem(r.NextItem);case i.ArrowUp:return n.preventDefault(),t.goToItem(r.PreviousItem);case i.Home:case i.PageUp:return n.preventDefault(),t.goToItem(r.FirstItem);case i.End:case i.PageDown:return n.preventDefault(),t.goToItem(r.LastItem);case i.Escape:n.preventDefault(),t.closeMenu(),e.nextTick((function(){var e;return null===(e=t.buttonRef.value)||void 0===e?void 0:e.focus()}));break;case i.Tab:return n.preventDefault();default:1===n.key.length&&(t.search(n.key),o.value=setTimeout((function(){return t.clearSearch()}),350))}}}}}),h=e.defineComponent({props:{as:{type:[Object,String],default:"template"},disabled:{type:Boolean,default:!1},class:{type:[String,Function],required:!1},className:{type:[String,Function],required:!1}},setup:function(n,o){var i=o.slots,a=o.attrs,l=v("MenuItem"),c="headlessui-menu-item-"+s(),d=n.disabled,f=n.className,p=void 0===f?n.class:f,m=e.computed((function(){return null!==l.activeItemIndex.value&&l.items.value[l.activeItemIndex.value].id===c})),b=e.ref({disabled:d,textValue:""});function h(t){if(d)return t.preventDefault();l.closeMenu(),e.nextTick((function(){var e;return null===(e=l.buttonRef.value)||void 0===e?void 0:e.focus()}))}function g(){if(d)return l.goToItem(r.Nothing);l.goToItem(r.SpecificItem,c)}function I(){d||m.value||l.goToItem(r.SpecificItem,c)}function O(){d||m.value&&l.goToItem(r.Nothing)}return e.onMounted((function(){var e,t,n=null===(e=document.getElementById(c))||void 0===e||null===(t=e.textContent)||void 0===t?void 0:t.toLowerCase().trim();void 0!==n&&(b.value.textValue=n)})),e.onMounted((function(){return l.registerItem(c,b)})),e.onUnmounted((function(){return l.unregisterItem(c)})),function(){var e={active:m.value,disabled:d},o={id:c,role:"menuitem",tabIndex:-1,class:x(p,e),"aria-disabled":!0===d||void 0,onClick:h,onFocus:g,onPointerMove:I,onPointerLeave:O};return u({props:t({},n,o),slot:e,attrs:a,slots:i})}}});function x(e,t){if(void 0!==e)return"function"==typeof e?e(t):e}!function(e){e[e.Open=0]="Open",e[e.Closed=1]="Closed"}(d||(d={})),function(e){e[e.First=0]="First",e[e.Previous=1]="Previous",e[e.Next=2]="Next",e[e.Last=3]="Last",e[e.Specific=4]="Specific",e[e.Nothing=5]="Nothing"}(f||(f={}));var g=Symbol("ListboxContext");function I(t){var n=e.inject(g);if(void 0===n){var o=new Error("<"+t+" /> is missing a parent <Listbox /> component.");throw Error.captureStackTrace&&Error.captureStackTrace(o,I),o}return n}var O=e.defineComponent({name:"Listbox",props:{as:{type:[Object,String],default:"template"},modelValue:{type:[Object,String],default:null}},setup:function(t,i){var a=i.slots,r=i.attrs,l=i.emit,s=n(t,["modelValue"]),c=e.ref(d.Closed),v=e.ref(null),p=e.ref(null),m=e.ref(null),b=e.ref([]),h=e.ref(""),x=e.ref(null),I=e.computed((function(){return t.modelValue})),O={listboxState:c,value:I,labelRef:v,buttonRef:p,optionsRef:m,options:b,searchQuery:h,activeOptionIndex:x,closeListbox:function(){return c.value=d.Closed},openListbox:function(){return c.value=d.Open},goToOption:function(e,t){var n=function(e,t){var n,u;if(b.value.length<=0)return null;var i=null!==(n=x.value)&&void 0!==n?n:-1,a=o(e,((u={})[f.First]=function(){return b.value.findIndex((function(e){return!e.dataRef.disabled}))},u[f.Previous]=function(){var e=b.value.slice().reverse().findIndex((function(e,t,n){return!(-1!==i&&n.length-t-1>=i||e.dataRef.disabled)}));return-1===e?e:b.value.length-1-e},u[f.Next]=function(){return b.value.findIndex((function(e,t){return!(t<=i||e.dataRef.disabled)}))},u[f.Last]=function(){var e=b.value.slice().reverse().findIndex((function(e){return!e.dataRef.disabled}));return-1===e?e:b.value.length-1-e},u[f.Specific]=function(){return b.value.findIndex((function(e){return e.id===t}))},u[f.Nothing]=function(){return null},u));return-1===a?x.value:a}(e,t);""===h.value&&x.value===n||(h.value="",x.value=n)},search:function(e){h.value+=e;var t=b.value.findIndex((function(e){return!e.dataRef.disabled&&e.dataRef.textValue.startsWith(h.value)}));-1!==t&&t!==x.value&&(x.value=t)},clearSearch:function(){h.value=""},registerOption:function(e,t){b.value.push({id:e,dataRef:t})},unregisterOption:function(e){var t=b.value.slice(),n=null!==x.value?t[x.value]:null,o=t.findIndex((function(t){return t.id===e}));-1!==o&&t.splice(o,1),b.value=t,x.value=o===x.value||null===n?null:t.indexOf(n)},select:function(e){l("update:modelValue",e)}};return e.onMounted((function(){function t(e){var t,n,o;c.value===d.Open&&((null===(t=p.value)||void 0===t?void 0:t.contains(e.target))||(null===(n=m.value)||void 0===n?void 0:n.contains(e.target))||(O.closeListbox(),e.defaultPrevented||null===(o=p.value)||void 0===o||o.focus()))}window.addEventListener("click",t),e.onUnmounted((function(){return window.removeEventListener("click",t)}))})),e.provide(g,O),function(){return u({props:s,slot:{open:c.value===d.Open},slots:a,attrs:r})}}}),y=e.defineComponent({name:"ListboxLabel",props:{as:{type:[Object,String],default:"label"}},render:function(){var e={open:I("ListboxLabel").listboxState.value===d.Open};return u({props:t({},this.$props,{id:this.id,ref:"el",onPointerUp:this.handlePointerUp}),slot:e,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=I("ListboxLabel");return{id:"headlessui-listbox-label-"+s(),el:e.labelRef,handlePointerUp:function(){var t;null===(t=e.buttonRef.value)||void 0===t||t.focus()}}}}),w=e.defineComponent({name:"ListboxButton",props:{as:{type:[Object,String],default:"button"}},render:function(){var e,n=I("ListboxButton"),o={open:n.listboxState.value===d.Open,focused:this.focused},i={ref:"el",id:this.id,type:"button","aria-haspopup":!0,"aria-controls":null===(e=n.optionsRef.value)||void 0===e?void 0:e.id,"aria-expanded":n.listboxState.value===d.Open||void 0,"aria-labelledby":n.labelRef.value?[n.labelRef.value.id,this.id].join(" "):void 0,onKeyDown:this.handleKeyDown,onFocus:this.handleFocus,onBlur:this.handleBlur,onPointerUp:this.handlePointerUp};return u({props:t({},this.$props,i),slot:o,attrs:this.$attrs,slots:this.$slots})},setup:function(){var t=I("ListboxButton"),n="headlessui-listbox-button-"+s(),o=e.ref(!1);return{id:n,el:t.buttonRef,focused:o,handleKeyDown:function(n){switch(n.key){case i.Space:case i.Enter:case i.ArrowDown:n.preventDefault(),t.openListbox(),e.nextTick((function(){var e;null===(e=t.optionsRef.value)||void 0===e||e.focus(),t.value.value||t.goToOption(f.First)}));break;case i.ArrowUp:n.preventDefault(),t.openListbox(),e.nextTick((function(){var e;null===(e=t.optionsRef.value)||void 0===e||e.focus(),t.value.value||t.goToOption(f.Last)}))}},handlePointerUp:function(n){t.listboxState.value===d.Open?t.closeListbox():(n.preventDefault(),t.openListbox(),e.nextTick((function(){var e;return null===(e=t.optionsRef.value)||void 0===e?void 0:e.focus()})))},handleFocus:function(){var e;if(t.listboxState.value===d.Open)return null===(e=t.optionsRef.value)||void 0===e?void 0:e.focus();o.value=!0},handleBlur:function(){o.value=!1}}}}),S=e.defineComponent({name:"ListboxOptions",props:{as:{type:[Object,String],default:"ul"},static:{type:Boolean,default:!1}},render:function(){var e,o,i,a,r=I("ListboxOptions"),l=this.$props,s=l.static,c=n(l,["static"]);if(!s&&r.listboxState.value===d.Closed)return null;var v={open:r.listboxState.value===d.Open};return u({props:t({},c,{"aria-activedescendant":null===r.activeOptionIndex.value||null===(e=r.options.value[r.activeOptionIndex.value])||void 0===e?void 0:e.id,"aria-labelledby":null!==(o=null===(i=r.labelRef.value)||void 0===i?void 0:i.id)&&void 0!==o?o:null===(a=r.buttonRef.value)||void 0===a?void 0:a.id,id:this.id,onKeyDown:this.handleKeyDown,role:"listbox",tabIndex:0,ref:"el"}),slot:v,attrs:this.$attrs,slots:this.$slots})},setup:function(){var t=I("ListboxOptions"),n="headlessui-listbox-options-"+s(),o=e.ref(null);return{id:n,el:t.optionsRef,handleKeyDown:function(n){switch(o.value&&clearTimeout(o.value),n.key){case i.Space:if(""!==t.searchQuery.value)return n.preventDefault(),t.search(n.key);case i.Enter:n.preventDefault(),t.closeListbox(),null!==t.activeOptionIndex.value&&(t.select(t.options.value[t.activeOptionIndex.value].dataRef.value),e.nextTick((function(){var e;return null===(e=t.buttonRef.value)||void 0===e?void 0:e.focus()})));break;case i.ArrowDown:return n.preventDefault(),t.goToOption(f.Next);case i.ArrowUp:return n.preventDefault(),t.goToOption(f.Previous);case i.Home:case i.PageUp:return n.preventDefault(),t.goToOption(f.First);case i.End:case i.PageDown:return n.preventDefault(),t.goToOption(f.Last);case i.Escape:n.preventDefault(),t.closeListbox(),e.nextTick((function(){var e;return null===(e=t.buttonRef.value)||void 0===e?void 0:e.focus()}));break;case i.Tab:return n.preventDefault();default:1===n.key.length&&(t.search(n.key),o.value=setTimeout((function(){return t.clearSearch()}),350))}}}}}),L=e.defineComponent({name:"ListboxOption",props:{as:{type:[Object,String],default:"li"},value:{type:[Object,String],default:null},disabled:{type:Boolean,default:!1},class:{type:[String,Function],required:!1},className:{type:[String,Function],required:!1}},setup:function(n,o){var i=o.slots,a=o.attrs,r=I("ListboxOption"),l="headlessui-listbox-option-"+s(),c=n.disabled,v=n.className,d=void 0===v?n.class:v,p=n.value,m=e.computed((function(){return null!==r.activeOptionIndex.value&&r.options.value[r.activeOptionIndex.value].id===l})),b=e.computed((function(){return r.value.value===p})),h=e.ref({disabled:c,value:p,textValue:""});function x(t){if(c)return t.preventDefault();r.select(p),r.closeListbox(),e.nextTick((function(){var e;return null===(e=r.buttonRef.value)||void 0===e?void 0:e.focus()}))}function g(){if(c)return r.goToOption(f.Nothing);r.goToOption(f.Specific,l)}function O(){c||m.value||r.goToOption(f.Specific,l)}function y(){c||m.value&&r.goToOption(f.Nothing)}return e.onMounted((function(){var e,t,n=null===(e=document.getElementById(l))||void 0===e||null===(t=e.textContent)||void 0===t?void 0:t.toLowerCase().trim();void 0!==n&&(h.value.textValue=n)})),e.onMounted((function(){return r.registerOption(l,h)})),e.onUnmounted((function(){return r.unregisterOption(l)})),e.onMounted((function(){var e,t;b.value&&(r.goToOption(f.Specific,l),null===(e=document.getElementById(l))||void 0===e||null===(t=e.focus)||void 0===t||t.call(e))})),e.watchEffect((function(){m.value&&e.nextTick((function(){var e,t;return null===(e=document.getElementById(l))||void 0===e||null===(t=e.scrollIntoView)||void 0===t?void 0:t.call(e,{block:"nearest"})}))})),function(){var e={active:m.value,selected:b.value,disabled:c},o={id:l,role:"option",tabIndex:-1,class:T(d,e),"aria-disabled":!0===c||void 0,"aria-selected":!0===b.value?b.value:void 0,onClick:x,onFocus:g,onPointerMove:O,onPointerLeave:y};return u({props:t({},n,o),slot:e,attrs:a,slots:i})}}});function T(e,t){if(void 0!==e)return"function"==typeof e?e(t):e}exports.Listbox=O,exports.ListboxButton=w,exports.ListboxLabel=y,exports.ListboxOption=L,exports.ListboxOptions=S,exports.Menu=p,exports.MenuButton=m,exports.MenuItem=h,exports.MenuItems=b; | ||
//# sourceMappingURL=headlessui.cjs.production.min.js.map |
@@ -1,2 +0,2 @@ | ||
import { cloneVNode, h, defineComponent, ref, onMounted, onUnmounted, provide, computed, inject, nextTick } from 'vue'; | ||
import { cloneVNode, h, defineComponent, ref, onMounted, onUnmounted, provide, computed, inject, nextTick, watchEffect } from 'vue'; | ||
@@ -97,2 +97,20 @@ function _extends() { | ||
// TODO: This must already exist somewhere, right? 🤔 | ||
// Ref: https://www.w3.org/TR/uievents-key/#named-key-attribute-values | ||
var Keys; | ||
(function (Keys) { | ||
Keys["Space"] = " "; | ||
Keys["Enter"] = "Enter"; | ||
Keys["Escape"] = "Escape"; | ||
Keys["Backspace"] = "Backspace"; | ||
Keys["ArrowUp"] = "ArrowUp"; | ||
Keys["ArrowDown"] = "ArrowDown"; | ||
Keys["Home"] = "Home"; | ||
Keys["End"] = "End"; | ||
Keys["PageUp"] = "PageUp"; | ||
Keys["PageDown"] = "PageDown"; | ||
Keys["Tab"] = "Tab"; | ||
})(Keys || (Keys = {})); | ||
var MenuStates; | ||
@@ -103,22 +121,4 @@ | ||
MenuStates[MenuStates["Closed"] = 1] = "Closed"; | ||
})(MenuStates || (MenuStates = {})); // TODO: This must already exist somewhere, right? 🤔 | ||
// Ref: https://www.w3.org/TR/uievents-key/#named-key-attribute-values | ||
})(MenuStates || (MenuStates = {})); | ||
var Key; | ||
(function (Key) { | ||
Key["Space"] = " "; | ||
Key["Enter"] = "Enter"; | ||
Key["Escape"] = "Escape"; | ||
Key["Backspace"] = "Backspace"; | ||
Key["ArrowUp"] = "ArrowUp"; | ||
Key["ArrowDown"] = "ArrowDown"; | ||
Key["Home"] = "Home"; | ||
Key["End"] = "End"; | ||
Key["PageUp"] = "PageUp"; | ||
Key["PageDown"] = "PageDown"; | ||
Key["Tab"] = "Tab"; | ||
})(Key || (Key = {})); | ||
var Focus; | ||
@@ -278,5 +278,5 @@ | ||
window.addEventListener('pointerup', handler); | ||
window.addEventListener('click', handler); | ||
onUnmounted(function () { | ||
return window.removeEventListener('pointerup', handler); | ||
return window.removeEventListener('click', handler); | ||
}); | ||
@@ -338,5 +338,5 @@ }); // @ts-expect-error Types of property 'dataRef' are incompatible. | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-13 | ||
case Key.Space: | ||
case Key.Enter: | ||
case Key.ArrowDown: | ||
case Keys.Space: | ||
case Keys.Enter: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
@@ -352,3 +352,3 @@ api.openMenu(); | ||
case Key.ArrowUp: | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
@@ -445,3 +445,12 @@ api.openMenu(); | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 | ||
case Key.Enter: | ||
// @ts-expect-error Fallthrough is expected here | ||
case Keys.Space: | ||
if (api.searchQuery.value !== '') { | ||
event.preventDefault(); | ||
return api.search(event.key); | ||
} | ||
// When in type ahead mode, fallthrough | ||
case Keys.Enter: | ||
event.preventDefault(); | ||
@@ -464,21 +473,21 @@ api.closeMenu(); | ||
case Key.ArrowDown: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.NextItem); | ||
case Key.ArrowUp: | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.PreviousItem); | ||
case Key.Home: | ||
case Key.PageUp: | ||
case Keys.Home: | ||
case Keys.PageUp: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.FirstItem); | ||
case Key.End: | ||
case Key.PageDown: | ||
case Keys.End: | ||
case Keys.PageDown: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.LastItem); | ||
case Key.Escape: | ||
case Keys.Escape: | ||
event.preventDefault(); | ||
@@ -493,3 +502,3 @@ api.closeMenu(); | ||
case Key.Tab: | ||
case Keys.Tab: | ||
return event.preventDefault(); | ||
@@ -564,5 +573,10 @@ | ||
function handlePointerEnter() { | ||
if (disabled) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
function handleClick(event) { | ||
if (disabled) return event.preventDefault(); | ||
api.closeMenu(); | ||
nextTick(function () { | ||
var _api$buttonRef$value4; | ||
return (_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
}); | ||
} | ||
@@ -575,36 +589,627 @@ | ||
function handlePointerMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
} | ||
function handlePointerLeave() { | ||
if (disabled) return; | ||
if (!active.value) return; | ||
api.goToItem(Focus.Nothing); | ||
} | ||
function handleMouseMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
return function () { | ||
var slot = { | ||
active: active.value, | ||
disabled: disabled | ||
}; | ||
var propsWeControl = { | ||
id: id, | ||
role: 'menuitem', | ||
tabIndex: -1, | ||
"class": resolvePropValue(className, slot), | ||
'aria-disabled': disabled === true ? true : undefined, | ||
onClick: handleClick, | ||
onFocus: handleFocus, | ||
onPointerMove: handlePointerMove, | ||
onPointerLeave: handlePointerLeave | ||
}; | ||
return render({ | ||
props: _extends({}, props, propsWeControl), | ||
slot: slot, | ||
attrs: attrs, | ||
slots: slots | ||
}); | ||
}; | ||
} | ||
}); | ||
function resolvePropValue(property, bag) { | ||
if (property === undefined) return undefined; | ||
if (typeof property === 'function') return property(bag); | ||
return property; | ||
} | ||
var ListboxStates; | ||
(function (ListboxStates) { | ||
ListboxStates[ListboxStates["Open"] = 0] = "Open"; | ||
ListboxStates[ListboxStates["Closed"] = 1] = "Closed"; | ||
})(ListboxStates || (ListboxStates = {})); | ||
var Focus$1; | ||
(function (Focus) { | ||
Focus[Focus["First"] = 0] = "First"; | ||
Focus[Focus["Previous"] = 1] = "Previous"; | ||
Focus[Focus["Next"] = 2] = "Next"; | ||
Focus[Focus["Last"] = 3] = "Last"; | ||
Focus[Focus["Specific"] = 4] = "Specific"; | ||
Focus[Focus["Nothing"] = 5] = "Nothing"; | ||
})(Focus$1 || (Focus$1 = {})); | ||
var ListboxContext = /*#__PURE__*/Symbol('ListboxContext'); | ||
function useListboxContext(component) { | ||
var context = inject(ListboxContext); | ||
if (context === undefined) { | ||
var err = new Error("<" + component + " /> is missing a parent <Listbox /> component."); | ||
if (Error.captureStackTrace) Error.captureStackTrace(err, useListboxContext); | ||
throw err; | ||
} | ||
return context; | ||
} // --- | ||
var Listbox = /*#__PURE__*/defineComponent({ | ||
name: 'Listbox', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'template' | ||
}, | ||
modelValue: { | ||
type: [Object, String], | ||
"default": null | ||
} | ||
}, | ||
setup: function setup(props, _ref) { | ||
var slots = _ref.slots, | ||
attrs = _ref.attrs, | ||
emit = _ref.emit; | ||
function handlePointerUp(event) { | ||
if (disabled) return event.preventDefault(); // Turns out that we can't use nextTick here. Even if we do, the `handleClick` would *not* be | ||
// called because the closeMenu() update is *too fast* and the tree gets unmounted before it | ||
// bubbles up. So instead of nextTick, we use the good old double requestAnimationFrame to | ||
// wait for a "nextFrame". | ||
var passThroughProps = _objectWithoutPropertiesLoose(props, ["modelValue"]); | ||
requestAnimationFrame(function () { | ||
requestAnimationFrame(function () { | ||
var _api$buttonRef$value4; | ||
var listboxState = ref(ListboxStates.Closed); | ||
var labelRef = ref(null); | ||
var buttonRef = ref(null); | ||
var optionsRef = ref(null); | ||
var options = ref([]); | ||
var searchQuery = ref(''); | ||
var activeOptionIndex = ref(null); | ||
var value = computed(function () { | ||
return props.modelValue; | ||
}); | ||
api.closeMenu(); | ||
(_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
function calculateActiveOptionIndex(focus, id) { | ||
var _activeOptionIndex$va, _match; | ||
if (options.value.length <= 0) return null; | ||
var currentActiveOptionIndex = (_activeOptionIndex$va = activeOptionIndex.value) !== null && _activeOptionIndex$va !== void 0 ? _activeOptionIndex$va : -1; | ||
var nextActiveIndex = match(focus, (_match = {}, _match[Focus$1.First] = function () { | ||
return options.value.findIndex(function (option) { | ||
return !option.dataRef.disabled; | ||
}); | ||
}, _match[Focus$1.Previous] = function () { | ||
var idx = options.value.slice().reverse().findIndex(function (option, idx, all) { | ||
if (currentActiveOptionIndex !== -1 && all.length - idx - 1 >= currentActiveOptionIndex) return false; | ||
return !option.dataRef.disabled; | ||
}); | ||
if (idx === -1) return idx; | ||
return options.value.length - 1 - idx; | ||
}, _match[Focus$1.Next] = function () { | ||
return options.value.findIndex(function (option, idx) { | ||
if (idx <= currentActiveOptionIndex) return false; | ||
return !option.dataRef.disabled; | ||
}); | ||
}, _match[Focus$1.Last] = function () { | ||
var idx = options.value.slice().reverse().findIndex(function (option) { | ||
return !option.dataRef.disabled; | ||
}); | ||
if (idx === -1) return idx; | ||
return options.value.length - 1 - idx; | ||
}, _match[Focus$1.Specific] = function () { | ||
return options.value.findIndex(function (option) { | ||
return option.id === id; | ||
}); | ||
}, _match[Focus$1.Nothing] = function () { | ||
return null; | ||
}, _match)); | ||
if (nextActiveIndex === -1) return activeOptionIndex.value; | ||
return nextActiveIndex; | ||
} | ||
var api = { | ||
listboxState: listboxState, | ||
value: value, | ||
labelRef: labelRef, | ||
buttonRef: buttonRef, | ||
optionsRef: optionsRef, | ||
options: options, | ||
searchQuery: searchQuery, | ||
activeOptionIndex: activeOptionIndex, | ||
closeListbox: function closeListbox() { | ||
return listboxState.value = ListboxStates.Closed; | ||
}, | ||
openListbox: function openListbox() { | ||
return listboxState.value = ListboxStates.Open; | ||
}, | ||
goToOption: function goToOption(focus, id) { | ||
var nextActiveOptionIndex = calculateActiveOptionIndex(focus, id); | ||
if (searchQuery.value === '' && activeOptionIndex.value === nextActiveOptionIndex) return; | ||
searchQuery.value = ''; | ||
activeOptionIndex.value = nextActiveOptionIndex; | ||
}, | ||
search: function search(value) { | ||
searchQuery.value += value; | ||
var match = options.value.findIndex(function (option) { | ||
return !option.dataRef.disabled && option.dataRef.textValue.startsWith(searchQuery.value); | ||
}); | ||
if (match === -1 || match === activeOptionIndex.value) { | ||
return; | ||
} | ||
activeOptionIndex.value = match; | ||
}, | ||
clearSearch: function clearSearch() { | ||
searchQuery.value = ''; | ||
}, | ||
registerOption: function registerOption(id, dataRef) { | ||
// @ts-expect-error The expected type comes from property 'dataRef' which is declared here on type '{ id: string; dataRef: { textValue: string; disabled: boolean; }; }' | ||
options.value.push({ | ||
id: id, | ||
dataRef: dataRef | ||
}); | ||
}, | ||
unregisterOption: function unregisterOption(id) { | ||
var nextOptions = options.value.slice(); | ||
var currentActiveOption = activeOptionIndex.value !== null ? nextOptions[activeOptionIndex.value] : null; | ||
var idx = nextOptions.findIndex(function (a) { | ||
return a.id === id; | ||
}); | ||
if (idx !== -1) nextOptions.splice(idx, 1); | ||
options.value = nextOptions; | ||
activeOptionIndex.value = function () { | ||
if (idx === activeOptionIndex.value) return null; | ||
if (currentActiveOption === null) return null; // If we removed the option before the actual active index, then it would be out of sync. To | ||
// fix this, we will find the correct (new) index position. | ||
return nextOptions.indexOf(currentActiveOption); | ||
}(); | ||
}, | ||
select: function select(value) { | ||
emit('update:modelValue', value); | ||
} | ||
}; | ||
onMounted(function () { | ||
function handler(event) { | ||
var _buttonRef$value, _optionsRef$value; | ||
if (listboxState.value !== ListboxStates.Open) return; | ||
if ((_buttonRef$value = buttonRef.value) === null || _buttonRef$value === void 0 ? void 0 : _buttonRef$value.contains(event.target)) return; | ||
if (!((_optionsRef$value = optionsRef.value) === null || _optionsRef$value === void 0 ? void 0 : _optionsRef$value.contains(event.target))) { | ||
var _buttonRef$value2; | ||
api.closeListbox(); | ||
if (!event.defaultPrevented) (_buttonRef$value2 = buttonRef.value) === null || _buttonRef$value2 === void 0 ? void 0 : _buttonRef$value2.focus(); | ||
} | ||
} | ||
window.addEventListener('click', handler); | ||
onUnmounted(function () { | ||
return window.removeEventListener('click', handler); | ||
}); | ||
}); // @ts-expect-error Types of property 'dataRef' are incompatible. | ||
provide(ListboxContext, api); | ||
return function () { | ||
var slot = { | ||
open: listboxState.value === ListboxStates.Open | ||
}; | ||
return render({ | ||
props: passThroughProps, | ||
slot: slot, | ||
slots: slots, | ||
attrs: attrs | ||
}); | ||
}; | ||
} | ||
}); // --- | ||
var ListboxLabel = /*#__PURE__*/defineComponent({ | ||
name: 'ListboxLabel', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'label' | ||
} | ||
}, | ||
render: function render$1() { | ||
var api = useListboxContext('ListboxLabel'); | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open | ||
}; | ||
var propsWeControl = { | ||
id: this.id, | ||
ref: 'el', | ||
onPointerUp: this.handlePointerUp | ||
}; | ||
return render({ | ||
props: _extends({}, this.$props, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxLabel'); | ||
var id = "headlessui-listbox-label-" + useId(); | ||
return { | ||
id: id, | ||
el: api.labelRef, | ||
handlePointerUp: function handlePointerUp() { | ||
var _api$buttonRef$value; | ||
(_api$buttonRef$value = api.buttonRef.value) === null || _api$buttonRef$value === void 0 ? void 0 : _api$buttonRef$value.focus(); | ||
} | ||
}; | ||
} | ||
}); // --- | ||
var ListboxButton = /*#__PURE__*/defineComponent({ | ||
name: 'ListboxButton', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'button' | ||
} | ||
}, | ||
render: function render$1() { | ||
var _api$optionsRef$value; | ||
var api = useListboxContext('ListboxButton'); | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open, | ||
focused: this.focused | ||
}; | ||
var propsWeControl = { | ||
ref: 'el', | ||
id: this.id, | ||
type: 'button', | ||
'aria-haspopup': true, | ||
'aria-controls': (_api$optionsRef$value = api.optionsRef.value) === null || _api$optionsRef$value === void 0 ? void 0 : _api$optionsRef$value.id, | ||
'aria-expanded': api.listboxState.value === ListboxStates.Open ? true : undefined, | ||
'aria-labelledby': api.labelRef.value ? [api.labelRef.value.id, this.id].join(' ') : undefined, | ||
onKeyDown: this.handleKeyDown, | ||
onFocus: this.handleFocus, | ||
onBlur: this.handleBlur, | ||
onPointerUp: this.handlePointerUp | ||
}; | ||
return render({ | ||
props: _extends({}, this.$props, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxButton'); | ||
var id = "headlessui-listbox-button-" + useId(); | ||
var focused = ref(false); | ||
function handleKeyDown(event) { | ||
switch (event.key) { | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-13 | ||
case Keys.Space: | ||
case Keys.Enter: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
api.openListbox(); | ||
nextTick(function () { | ||
var _api$optionsRef$value2; | ||
(_api$optionsRef$value2 = api.optionsRef.value) === null || _api$optionsRef$value2 === void 0 ? void 0 : _api$optionsRef$value2.focus(); | ||
if (!api.value.value) api.goToOption(Focus$1.First); | ||
}); | ||
break; | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
api.openListbox(); | ||
nextTick(function () { | ||
var _api$optionsRef$value3; | ||
(_api$optionsRef$value3 = api.optionsRef.value) === null || _api$optionsRef$value3 === void 0 ? void 0 : _api$optionsRef$value3.focus(); | ||
if (!api.value.value) api.goToOption(Focus$1.Last); | ||
}); | ||
break; | ||
} | ||
} | ||
function handlePointerUp(event) { | ||
if (api.listboxState.value === ListboxStates.Open) { | ||
api.closeListbox(); | ||
} else { | ||
event.preventDefault(); | ||
api.openListbox(); | ||
nextTick(function () { | ||
var _api$optionsRef$value4; | ||
return (_api$optionsRef$value4 = api.optionsRef.value) === null || _api$optionsRef$value4 === void 0 ? void 0 : _api$optionsRef$value4.focus(); | ||
}); | ||
} | ||
} | ||
function handleFocus() { | ||
var _api$optionsRef$value5; | ||
if (api.listboxState.value === ListboxStates.Open) return (_api$optionsRef$value5 = api.optionsRef.value) === null || _api$optionsRef$value5 === void 0 ? void 0 : _api$optionsRef$value5.focus(); | ||
focused.value = true; | ||
} | ||
function handleBlur() { | ||
focused.value = false; | ||
} | ||
return { | ||
id: id, | ||
el: api.buttonRef, | ||
focused: focused, | ||
handleKeyDown: handleKeyDown, | ||
handlePointerUp: handlePointerUp, | ||
handleFocus: handleFocus, | ||
handleBlur: handleBlur | ||
}; | ||
} | ||
}); // --- | ||
var ListboxOptions = /*#__PURE__*/defineComponent({ | ||
name: 'ListboxOptions', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'ul' | ||
}, | ||
"static": { | ||
type: Boolean, | ||
"default": false | ||
} | ||
}, | ||
render: function render$1() { | ||
var _api$options$value$ap, _api$labelRef$value$i, _api$labelRef$value, _api$buttonRef$value2; | ||
var api = useListboxContext('ListboxOptions'); // `static` is a reserved keyword, therefore aliasing it... | ||
var _this$$props = this.$props, | ||
isStatic = _this$$props["static"], | ||
passThroughProps = _objectWithoutPropertiesLoose(_this$$props, ["static"]); | ||
if (!isStatic && api.listboxState.value === ListboxStates.Closed) return null; | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open | ||
}; | ||
var propsWeControl = { | ||
'aria-activedescendant': api.activeOptionIndex.value === null ? undefined : (_api$options$value$ap = api.options.value[api.activeOptionIndex.value]) === null || _api$options$value$ap === void 0 ? void 0 : _api$options$value$ap.id, | ||
'aria-labelledby': (_api$labelRef$value$i = (_api$labelRef$value = api.labelRef.value) === null || _api$labelRef$value === void 0 ? void 0 : _api$labelRef$value.id) !== null && _api$labelRef$value$i !== void 0 ? _api$labelRef$value$i : (_api$buttonRef$value2 = api.buttonRef.value) === null || _api$buttonRef$value2 === void 0 ? void 0 : _api$buttonRef$value2.id, | ||
id: this.id, | ||
onKeyDown: this.handleKeyDown, | ||
role: 'listbox', | ||
tabIndex: 0, | ||
ref: 'el' | ||
}; | ||
return render({ | ||
props: _extends({}, passThroughProps, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxOptions'); | ||
var id = "headlessui-listbox-options-" + useId(); | ||
var searchDebounce = ref(null); | ||
function handleKeyDown(event) { | ||
if (searchDebounce.value) clearTimeout(searchDebounce.value); | ||
switch (event.key) { | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 | ||
// @ts-expect-error Fallthrough is expected here | ||
case Keys.Space: | ||
if (api.searchQuery.value !== '') { | ||
event.preventDefault(); | ||
return api.search(event.key); | ||
} | ||
// When in type ahead mode, fallthrough | ||
case Keys.Enter: | ||
event.preventDefault(); | ||
api.closeListbox(); | ||
if (api.activeOptionIndex.value !== null) { | ||
var dataRef = api.options.value[api.activeOptionIndex.value].dataRef; | ||
api.select(dataRef.value); | ||
nextTick(function () { | ||
var _api$buttonRef$value3; | ||
return (_api$buttonRef$value3 = api.buttonRef.value) === null || _api$buttonRef$value3 === void 0 ? void 0 : _api$buttonRef$value3.focus(); | ||
}); | ||
} | ||
break; | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Next); | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Previous); | ||
case Keys.Home: | ||
case Keys.PageUp: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.First); | ||
case Keys.End: | ||
case Keys.PageDown: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Last); | ||
case Keys.Escape: | ||
event.preventDefault(); | ||
api.closeListbox(); | ||
nextTick(function () { | ||
var _api$buttonRef$value4; | ||
return (_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
}); | ||
break; | ||
case Keys.Tab: | ||
return event.preventDefault(); | ||
default: | ||
if (event.key.length === 1) { | ||
api.search(event.key); | ||
searchDebounce.value = setTimeout(function () { | ||
return api.clearSearch(); | ||
}, 350); | ||
} | ||
break; | ||
} | ||
} | ||
return { | ||
id: id, | ||
el: api.optionsRef, | ||
handleKeyDown: handleKeyDown | ||
}; | ||
} | ||
}); | ||
var ListboxOption = /*#__PURE__*/defineComponent({ | ||
name: 'ListboxOption', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'li' | ||
}, | ||
value: { | ||
type: [Object, String], | ||
"default": null | ||
}, | ||
disabled: { | ||
type: Boolean, | ||
"default": false | ||
}, | ||
"class": { | ||
type: [String, Function], | ||
required: false | ||
}, | ||
className: { | ||
type: [String, Function], | ||
required: false | ||
} | ||
}, | ||
setup: function setup(props, _ref2) { | ||
var slots = _ref2.slots, | ||
attrs = _ref2.attrs; | ||
var api = useListboxContext('ListboxOption'); | ||
var id = "headlessui-listbox-option-" + useId(); | ||
var disabled = props.disabled, | ||
defaultClass = props["class"], | ||
_props$className = props.className, | ||
className = _props$className === void 0 ? defaultClass : _props$className, | ||
value = props.value; | ||
var active = computed(function () { | ||
return api.activeOptionIndex.value !== null ? api.options.value[api.activeOptionIndex.value].id === id : false; | ||
}); | ||
var selected = computed(function () { | ||
return api.value.value === value; | ||
}); | ||
var dataRef = ref({ | ||
disabled: disabled, | ||
value: value, | ||
textValue: '' | ||
}); | ||
onMounted(function () { | ||
var _document$getElementB, _document$getElementB2; | ||
var textValue = (_document$getElementB = document.getElementById(id)) === null || _document$getElementB === void 0 ? void 0 : (_document$getElementB2 = _document$getElementB.textContent) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.toLowerCase().trim(); | ||
if (textValue !== undefined) dataRef.value.textValue = textValue; | ||
}); | ||
onMounted(function () { | ||
return api.registerOption(id, dataRef); | ||
}); | ||
onUnmounted(function () { | ||
return api.unregisterOption(id); | ||
}); | ||
onMounted(function () { | ||
var _document$getElementB3, _document$getElementB4; | ||
if (!selected.value) return; | ||
api.goToOption(Focus$1.Specific, id); | ||
(_document$getElementB3 = document.getElementById(id)) === null || _document$getElementB3 === void 0 ? void 0 : (_document$getElementB4 = _document$getElementB3.focus) === null || _document$getElementB4 === void 0 ? void 0 : _document$getElementB4.call(_document$getElementB3); | ||
}); | ||
watchEffect(function () { | ||
if (!active.value) return; | ||
nextTick(function () { | ||
var _document$getElementB5, _document$getElementB6; | ||
return (_document$getElementB5 = document.getElementById(id)) === null || _document$getElementB5 === void 0 ? void 0 : (_document$getElementB6 = _document$getElementB5.scrollIntoView) === null || _document$getElementB6 === void 0 ? void 0 : _document$getElementB6.call(_document$getElementB5, { | ||
block: 'nearest' | ||
}); | ||
}); | ||
}); | ||
function handleClick(event) { | ||
if (disabled) return event.preventDefault(); | ||
api.select(value); | ||
api.closeListbox(); | ||
nextTick(function () { | ||
var _api$buttonRef$value5; | ||
return (_api$buttonRef$value5 = api.buttonRef.value) === null || _api$buttonRef$value5 === void 0 ? void 0 : _api$buttonRef$value5.focus(); | ||
}); | ||
} | ||
function handleFocus() { | ||
if (disabled) return api.goToOption(Focus$1.Nothing); | ||
api.goToOption(Focus$1.Specific, id); | ||
} | ||
function handlePointerMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToOption(Focus$1.Specific, id); | ||
} | ||
function handlePointerLeave() { | ||
if (disabled) return; | ||
if (!active.value) return; | ||
api.goToOption(Focus$1.Nothing); | ||
} | ||
return function () { | ||
var slot = { | ||
active: active.value, | ||
selected: selected.value, | ||
disabled: disabled | ||
@@ -614,12 +1219,11 @@ }; | ||
id: id, | ||
role: 'menuitem', | ||
role: 'option', | ||
tabIndex: -1, | ||
"class": resolvePropValue(className, slot), | ||
"class": resolvePropValue$1(className, slot), | ||
'aria-disabled': disabled === true ? true : undefined, | ||
'aria-selected': selected.value === true ? selected.value : undefined, | ||
onClick: handleClick, | ||
onFocus: handleFocus, | ||
onMouseMove: handleMouseMove, | ||
onPointerEnter: handlePointerEnter, | ||
onPointerLeave: handlePointerLeave, | ||
onPointerUp: handlePointerUp | ||
onPointerMove: handlePointerMove, | ||
onPointerLeave: handlePointerLeave | ||
}; | ||
@@ -634,5 +1238,5 @@ return render({ | ||
} | ||
}); | ||
}); // --- | ||
function resolvePropValue(property, bag) { | ||
function resolvePropValue$1(property, bag) { | ||
if (property === undefined) return undefined; | ||
@@ -643,3 +1247,3 @@ if (typeof property === 'function') return property(bag); | ||
export { Menu, MenuButton, MenuItem, MenuItems }; | ||
export { Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions, Menu, MenuButton, MenuItem, MenuItems }; | ||
//# sourceMappingURL=headlessui.esm.js.map |
@@ -101,2 +101,20 @@ (function (global, factory) { | ||
// TODO: This must already exist somewhere, right? 🤔 | ||
// Ref: https://www.w3.org/TR/uievents-key/#named-key-attribute-values | ||
var Keys; | ||
(function (Keys) { | ||
Keys["Space"] = " "; | ||
Keys["Enter"] = "Enter"; | ||
Keys["Escape"] = "Escape"; | ||
Keys["Backspace"] = "Backspace"; | ||
Keys["ArrowUp"] = "ArrowUp"; | ||
Keys["ArrowDown"] = "ArrowDown"; | ||
Keys["Home"] = "Home"; | ||
Keys["End"] = "End"; | ||
Keys["PageUp"] = "PageUp"; | ||
Keys["PageDown"] = "PageDown"; | ||
Keys["Tab"] = "Tab"; | ||
})(Keys || (Keys = {})); | ||
var MenuStates; | ||
@@ -107,22 +125,4 @@ | ||
MenuStates[MenuStates["Closed"] = 1] = "Closed"; | ||
})(MenuStates || (MenuStates = {})); // TODO: This must already exist somewhere, right? 🤔 | ||
// Ref: https://www.w3.org/TR/uievents-key/#named-key-attribute-values | ||
})(MenuStates || (MenuStates = {})); | ||
var Key; | ||
(function (Key) { | ||
Key["Space"] = " "; | ||
Key["Enter"] = "Enter"; | ||
Key["Escape"] = "Escape"; | ||
Key["Backspace"] = "Backspace"; | ||
Key["ArrowUp"] = "ArrowUp"; | ||
Key["ArrowDown"] = "ArrowDown"; | ||
Key["Home"] = "Home"; | ||
Key["End"] = "End"; | ||
Key["PageUp"] = "PageUp"; | ||
Key["PageDown"] = "PageDown"; | ||
Key["Tab"] = "Tab"; | ||
})(Key || (Key = {})); | ||
var Focus; | ||
@@ -282,5 +282,5 @@ | ||
window.addEventListener('pointerup', handler); | ||
window.addEventListener('click', handler); | ||
vue.onUnmounted(function () { | ||
return window.removeEventListener('pointerup', handler); | ||
return window.removeEventListener('click', handler); | ||
}); | ||
@@ -342,5 +342,5 @@ }); // @ts-expect-error Types of property 'dataRef' are incompatible. | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-13 | ||
case Key.Space: | ||
case Key.Enter: | ||
case Key.ArrowDown: | ||
case Keys.Space: | ||
case Keys.Enter: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
@@ -356,3 +356,3 @@ api.openMenu(); | ||
case Key.ArrowUp: | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
@@ -449,3 +449,12 @@ api.openMenu(); | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 | ||
case Key.Enter: | ||
// @ts-expect-error Fallthrough is expected here | ||
case Keys.Space: | ||
if (api.searchQuery.value !== '') { | ||
event.preventDefault(); | ||
return api.search(event.key); | ||
} | ||
// When in type ahead mode, fallthrough | ||
case Keys.Enter: | ||
event.preventDefault(); | ||
@@ -468,21 +477,21 @@ api.closeMenu(); | ||
case Key.ArrowDown: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.NextItem); | ||
case Key.ArrowUp: | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.PreviousItem); | ||
case Key.Home: | ||
case Key.PageUp: | ||
case Keys.Home: | ||
case Keys.PageUp: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.FirstItem); | ||
case Key.End: | ||
case Key.PageDown: | ||
case Keys.End: | ||
case Keys.PageDown: | ||
event.preventDefault(); | ||
return api.goToItem(Focus.LastItem); | ||
case Key.Escape: | ||
case Keys.Escape: | ||
event.preventDefault(); | ||
@@ -497,3 +506,3 @@ api.closeMenu(); | ||
case Key.Tab: | ||
case Keys.Tab: | ||
return event.preventDefault(); | ||
@@ -568,5 +577,10 @@ | ||
function handlePointerEnter() { | ||
if (disabled) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
function handleClick(event) { | ||
if (disabled) return event.preventDefault(); | ||
api.closeMenu(); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value4; | ||
return (_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
}); | ||
} | ||
@@ -579,36 +593,627 @@ | ||
function handlePointerMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
} | ||
function handlePointerLeave() { | ||
if (disabled) return; | ||
if (!active.value) return; | ||
api.goToItem(Focus.Nothing); | ||
} | ||
function handleMouseMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToItem(Focus.SpecificItem, id); | ||
return function () { | ||
var slot = { | ||
active: active.value, | ||
disabled: disabled | ||
}; | ||
var propsWeControl = { | ||
id: id, | ||
role: 'menuitem', | ||
tabIndex: -1, | ||
"class": resolvePropValue(className, slot), | ||
'aria-disabled': disabled === true ? true : undefined, | ||
onClick: handleClick, | ||
onFocus: handleFocus, | ||
onPointerMove: handlePointerMove, | ||
onPointerLeave: handlePointerLeave | ||
}; | ||
return render({ | ||
props: _extends({}, props, propsWeControl), | ||
slot: slot, | ||
attrs: attrs, | ||
slots: slots | ||
}); | ||
}; | ||
} | ||
}); | ||
function resolvePropValue(property, bag) { | ||
if (property === undefined) return undefined; | ||
if (typeof property === 'function') return property(bag); | ||
return property; | ||
} | ||
var ListboxStates; | ||
(function (ListboxStates) { | ||
ListboxStates[ListboxStates["Open"] = 0] = "Open"; | ||
ListboxStates[ListboxStates["Closed"] = 1] = "Closed"; | ||
})(ListboxStates || (ListboxStates = {})); | ||
var Focus$1; | ||
(function (Focus) { | ||
Focus[Focus["First"] = 0] = "First"; | ||
Focus[Focus["Previous"] = 1] = "Previous"; | ||
Focus[Focus["Next"] = 2] = "Next"; | ||
Focus[Focus["Last"] = 3] = "Last"; | ||
Focus[Focus["Specific"] = 4] = "Specific"; | ||
Focus[Focus["Nothing"] = 5] = "Nothing"; | ||
})(Focus$1 || (Focus$1 = {})); | ||
var ListboxContext = /*#__PURE__*/Symbol('ListboxContext'); | ||
function useListboxContext(component) { | ||
var context = vue.inject(ListboxContext); | ||
if (context === undefined) { | ||
var err = new Error("<" + component + " /> is missing a parent <Listbox /> component."); | ||
if (Error.captureStackTrace) Error.captureStackTrace(err, useListboxContext); | ||
throw err; | ||
} | ||
return context; | ||
} // --- | ||
var Listbox = /*#__PURE__*/vue.defineComponent({ | ||
name: 'Listbox', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'template' | ||
}, | ||
modelValue: { | ||
type: [Object, String], | ||
"default": null | ||
} | ||
}, | ||
setup: function setup(props, _ref) { | ||
var slots = _ref.slots, | ||
attrs = _ref.attrs, | ||
emit = _ref.emit; | ||
function handlePointerUp(event) { | ||
if (disabled) return event.preventDefault(); // Turns out that we can't use nextTick here. Even if we do, the `handleClick` would *not* be | ||
// called because the closeMenu() update is *too fast* and the tree gets unmounted before it | ||
// bubbles up. So instead of nextTick, we use the good old double requestAnimationFrame to | ||
// wait for a "nextFrame". | ||
var passThroughProps = _objectWithoutPropertiesLoose(props, ["modelValue"]); | ||
requestAnimationFrame(function () { | ||
requestAnimationFrame(function () { | ||
var _api$buttonRef$value4; | ||
var listboxState = vue.ref(ListboxStates.Closed); | ||
var labelRef = vue.ref(null); | ||
var buttonRef = vue.ref(null); | ||
var optionsRef = vue.ref(null); | ||
var options = vue.ref([]); | ||
var searchQuery = vue.ref(''); | ||
var activeOptionIndex = vue.ref(null); | ||
var value = vue.computed(function () { | ||
return props.modelValue; | ||
}); | ||
api.closeMenu(); | ||
(_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
function calculateActiveOptionIndex(focus, id) { | ||
var _activeOptionIndex$va, _match; | ||
if (options.value.length <= 0) return null; | ||
var currentActiveOptionIndex = (_activeOptionIndex$va = activeOptionIndex.value) !== null && _activeOptionIndex$va !== void 0 ? _activeOptionIndex$va : -1; | ||
var nextActiveIndex = match(focus, (_match = {}, _match[Focus$1.First] = function () { | ||
return options.value.findIndex(function (option) { | ||
return !option.dataRef.disabled; | ||
}); | ||
}, _match[Focus$1.Previous] = function () { | ||
var idx = options.value.slice().reverse().findIndex(function (option, idx, all) { | ||
if (currentActiveOptionIndex !== -1 && all.length - idx - 1 >= currentActiveOptionIndex) return false; | ||
return !option.dataRef.disabled; | ||
}); | ||
if (idx === -1) return idx; | ||
return options.value.length - 1 - idx; | ||
}, _match[Focus$1.Next] = function () { | ||
return options.value.findIndex(function (option, idx) { | ||
if (idx <= currentActiveOptionIndex) return false; | ||
return !option.dataRef.disabled; | ||
}); | ||
}, _match[Focus$1.Last] = function () { | ||
var idx = options.value.slice().reverse().findIndex(function (option) { | ||
return !option.dataRef.disabled; | ||
}); | ||
if (idx === -1) return idx; | ||
return options.value.length - 1 - idx; | ||
}, _match[Focus$1.Specific] = function () { | ||
return options.value.findIndex(function (option) { | ||
return option.id === id; | ||
}); | ||
}, _match[Focus$1.Nothing] = function () { | ||
return null; | ||
}, _match)); | ||
if (nextActiveIndex === -1) return activeOptionIndex.value; | ||
return nextActiveIndex; | ||
} | ||
var api = { | ||
listboxState: listboxState, | ||
value: value, | ||
labelRef: labelRef, | ||
buttonRef: buttonRef, | ||
optionsRef: optionsRef, | ||
options: options, | ||
searchQuery: searchQuery, | ||
activeOptionIndex: activeOptionIndex, | ||
closeListbox: function closeListbox() { | ||
return listboxState.value = ListboxStates.Closed; | ||
}, | ||
openListbox: function openListbox() { | ||
return listboxState.value = ListboxStates.Open; | ||
}, | ||
goToOption: function goToOption(focus, id) { | ||
var nextActiveOptionIndex = calculateActiveOptionIndex(focus, id); | ||
if (searchQuery.value === '' && activeOptionIndex.value === nextActiveOptionIndex) return; | ||
searchQuery.value = ''; | ||
activeOptionIndex.value = nextActiveOptionIndex; | ||
}, | ||
search: function search(value) { | ||
searchQuery.value += value; | ||
var match = options.value.findIndex(function (option) { | ||
return !option.dataRef.disabled && option.dataRef.textValue.startsWith(searchQuery.value); | ||
}); | ||
if (match === -1 || match === activeOptionIndex.value) { | ||
return; | ||
} | ||
activeOptionIndex.value = match; | ||
}, | ||
clearSearch: function clearSearch() { | ||
searchQuery.value = ''; | ||
}, | ||
registerOption: function registerOption(id, dataRef) { | ||
// @ts-expect-error The expected type comes from property 'dataRef' which is declared here on type '{ id: string; dataRef: { textValue: string; disabled: boolean; }; }' | ||
options.value.push({ | ||
id: id, | ||
dataRef: dataRef | ||
}); | ||
}, | ||
unregisterOption: function unregisterOption(id) { | ||
var nextOptions = options.value.slice(); | ||
var currentActiveOption = activeOptionIndex.value !== null ? nextOptions[activeOptionIndex.value] : null; | ||
var idx = nextOptions.findIndex(function (a) { | ||
return a.id === id; | ||
}); | ||
if (idx !== -1) nextOptions.splice(idx, 1); | ||
options.value = nextOptions; | ||
activeOptionIndex.value = function () { | ||
if (idx === activeOptionIndex.value) return null; | ||
if (currentActiveOption === null) return null; // If we removed the option before the actual active index, then it would be out of sync. To | ||
// fix this, we will find the correct (new) index position. | ||
return nextOptions.indexOf(currentActiveOption); | ||
}(); | ||
}, | ||
select: function select(value) { | ||
emit('update:modelValue', value); | ||
} | ||
}; | ||
vue.onMounted(function () { | ||
function handler(event) { | ||
var _buttonRef$value, _optionsRef$value; | ||
if (listboxState.value !== ListboxStates.Open) return; | ||
if ((_buttonRef$value = buttonRef.value) === null || _buttonRef$value === void 0 ? void 0 : _buttonRef$value.contains(event.target)) return; | ||
if (!((_optionsRef$value = optionsRef.value) === null || _optionsRef$value === void 0 ? void 0 : _optionsRef$value.contains(event.target))) { | ||
var _buttonRef$value2; | ||
api.closeListbox(); | ||
if (!event.defaultPrevented) (_buttonRef$value2 = buttonRef.value) === null || _buttonRef$value2 === void 0 ? void 0 : _buttonRef$value2.focus(); | ||
} | ||
} | ||
window.addEventListener('click', handler); | ||
vue.onUnmounted(function () { | ||
return window.removeEventListener('click', handler); | ||
}); | ||
}); // @ts-expect-error Types of property 'dataRef' are incompatible. | ||
vue.provide(ListboxContext, api); | ||
return function () { | ||
var slot = { | ||
open: listboxState.value === ListboxStates.Open | ||
}; | ||
return render({ | ||
props: passThroughProps, | ||
slot: slot, | ||
slots: slots, | ||
attrs: attrs | ||
}); | ||
}; | ||
} | ||
}); // --- | ||
var ListboxLabel = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxLabel', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'label' | ||
} | ||
}, | ||
render: function render$1() { | ||
var api = useListboxContext('ListboxLabel'); | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open | ||
}; | ||
var propsWeControl = { | ||
id: this.id, | ||
ref: 'el', | ||
onPointerUp: this.handlePointerUp | ||
}; | ||
return render({ | ||
props: _extends({}, this.$props, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxLabel'); | ||
var id = "headlessui-listbox-label-" + useId(); | ||
return { | ||
id: id, | ||
el: api.labelRef, | ||
handlePointerUp: function handlePointerUp() { | ||
var _api$buttonRef$value; | ||
(_api$buttonRef$value = api.buttonRef.value) === null || _api$buttonRef$value === void 0 ? void 0 : _api$buttonRef$value.focus(); | ||
} | ||
}; | ||
} | ||
}); // --- | ||
var ListboxButton = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxButton', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'button' | ||
} | ||
}, | ||
render: function render$1() { | ||
var _api$optionsRef$value; | ||
var api = useListboxContext('ListboxButton'); | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open, | ||
focused: this.focused | ||
}; | ||
var propsWeControl = { | ||
ref: 'el', | ||
id: this.id, | ||
type: 'button', | ||
'aria-haspopup': true, | ||
'aria-controls': (_api$optionsRef$value = api.optionsRef.value) === null || _api$optionsRef$value === void 0 ? void 0 : _api$optionsRef$value.id, | ||
'aria-expanded': api.listboxState.value === ListboxStates.Open ? true : undefined, | ||
'aria-labelledby': api.labelRef.value ? [api.labelRef.value.id, this.id].join(' ') : undefined, | ||
onKeyDown: this.handleKeyDown, | ||
onFocus: this.handleFocus, | ||
onBlur: this.handleBlur, | ||
onPointerUp: this.handlePointerUp | ||
}; | ||
return render({ | ||
props: _extends({}, this.$props, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxButton'); | ||
var id = "headlessui-listbox-button-" + useId(); | ||
var focused = vue.ref(false); | ||
function handleKeyDown(event) { | ||
switch (event.key) { | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-13 | ||
case Keys.Space: | ||
case Keys.Enter: | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
api.openListbox(); | ||
vue.nextTick(function () { | ||
var _api$optionsRef$value2; | ||
(_api$optionsRef$value2 = api.optionsRef.value) === null || _api$optionsRef$value2 === void 0 ? void 0 : _api$optionsRef$value2.focus(); | ||
if (!api.value.value) api.goToOption(Focus$1.First); | ||
}); | ||
break; | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
api.openListbox(); | ||
vue.nextTick(function () { | ||
var _api$optionsRef$value3; | ||
(_api$optionsRef$value3 = api.optionsRef.value) === null || _api$optionsRef$value3 === void 0 ? void 0 : _api$optionsRef$value3.focus(); | ||
if (!api.value.value) api.goToOption(Focus$1.Last); | ||
}); | ||
break; | ||
} | ||
} | ||
function handlePointerUp(event) { | ||
if (api.listboxState.value === ListboxStates.Open) { | ||
api.closeListbox(); | ||
} else { | ||
event.preventDefault(); | ||
api.openListbox(); | ||
vue.nextTick(function () { | ||
var _api$optionsRef$value4; | ||
return (_api$optionsRef$value4 = api.optionsRef.value) === null || _api$optionsRef$value4 === void 0 ? void 0 : _api$optionsRef$value4.focus(); | ||
}); | ||
} | ||
} | ||
function handleFocus() { | ||
var _api$optionsRef$value5; | ||
if (api.listboxState.value === ListboxStates.Open) return (_api$optionsRef$value5 = api.optionsRef.value) === null || _api$optionsRef$value5 === void 0 ? void 0 : _api$optionsRef$value5.focus(); | ||
focused.value = true; | ||
} | ||
function handleBlur() { | ||
focused.value = false; | ||
} | ||
return { | ||
id: id, | ||
el: api.buttonRef, | ||
focused: focused, | ||
handleKeyDown: handleKeyDown, | ||
handlePointerUp: handlePointerUp, | ||
handleFocus: handleFocus, | ||
handleBlur: handleBlur | ||
}; | ||
} | ||
}); // --- | ||
var ListboxOptions = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxOptions', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'ul' | ||
}, | ||
"static": { | ||
type: Boolean, | ||
"default": false | ||
} | ||
}, | ||
render: function render$1() { | ||
var _api$options$value$ap, _api$labelRef$value$i, _api$labelRef$value, _api$buttonRef$value2; | ||
var api = useListboxContext('ListboxOptions'); // `static` is a reserved keyword, therefore aliasing it... | ||
var _this$$props = this.$props, | ||
isStatic = _this$$props["static"], | ||
passThroughProps = _objectWithoutPropertiesLoose(_this$$props, ["static"]); | ||
if (!isStatic && api.listboxState.value === ListboxStates.Closed) return null; | ||
var slot = { | ||
open: api.listboxState.value === ListboxStates.Open | ||
}; | ||
var propsWeControl = { | ||
'aria-activedescendant': api.activeOptionIndex.value === null ? undefined : (_api$options$value$ap = api.options.value[api.activeOptionIndex.value]) === null || _api$options$value$ap === void 0 ? void 0 : _api$options$value$ap.id, | ||
'aria-labelledby': (_api$labelRef$value$i = (_api$labelRef$value = api.labelRef.value) === null || _api$labelRef$value === void 0 ? void 0 : _api$labelRef$value.id) !== null && _api$labelRef$value$i !== void 0 ? _api$labelRef$value$i : (_api$buttonRef$value2 = api.buttonRef.value) === null || _api$buttonRef$value2 === void 0 ? void 0 : _api$buttonRef$value2.id, | ||
id: this.id, | ||
onKeyDown: this.handleKeyDown, | ||
role: 'listbox', | ||
tabIndex: 0, | ||
ref: 'el' | ||
}; | ||
return render({ | ||
props: _extends({}, passThroughProps, propsWeControl), | ||
slot: slot, | ||
attrs: this.$attrs, | ||
slots: this.$slots | ||
}); | ||
}, | ||
setup: function setup() { | ||
var api = useListboxContext('ListboxOptions'); | ||
var id = "headlessui-listbox-options-" + useId(); | ||
var searchDebounce = vue.ref(null); | ||
function handleKeyDown(event) { | ||
if (searchDebounce.value) clearTimeout(searchDebounce.value); | ||
switch (event.key) { | ||
// Ref: https://www.w3.org/TR/wai-aria-practices-1.2/#keyboard-interaction-12 | ||
// @ts-expect-error Fallthrough is expected here | ||
case Keys.Space: | ||
if (api.searchQuery.value !== '') { | ||
event.preventDefault(); | ||
return api.search(event.key); | ||
} | ||
// When in type ahead mode, fallthrough | ||
case Keys.Enter: | ||
event.preventDefault(); | ||
api.closeListbox(); | ||
if (api.activeOptionIndex.value !== null) { | ||
var dataRef = api.options.value[api.activeOptionIndex.value].dataRef; | ||
api.select(dataRef.value); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value3; | ||
return (_api$buttonRef$value3 = api.buttonRef.value) === null || _api$buttonRef$value3 === void 0 ? void 0 : _api$buttonRef$value3.focus(); | ||
}); | ||
} | ||
break; | ||
case Keys.ArrowDown: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Next); | ||
case Keys.ArrowUp: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Previous); | ||
case Keys.Home: | ||
case Keys.PageUp: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.First); | ||
case Keys.End: | ||
case Keys.PageDown: | ||
event.preventDefault(); | ||
return api.goToOption(Focus$1.Last); | ||
case Keys.Escape: | ||
event.preventDefault(); | ||
api.closeListbox(); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value4; | ||
return (_api$buttonRef$value4 = api.buttonRef.value) === null || _api$buttonRef$value4 === void 0 ? void 0 : _api$buttonRef$value4.focus(); | ||
}); | ||
break; | ||
case Keys.Tab: | ||
return event.preventDefault(); | ||
default: | ||
if (event.key.length === 1) { | ||
api.search(event.key); | ||
searchDebounce.value = setTimeout(function () { | ||
return api.clearSearch(); | ||
}, 350); | ||
} | ||
break; | ||
} | ||
} | ||
return { | ||
id: id, | ||
el: api.optionsRef, | ||
handleKeyDown: handleKeyDown | ||
}; | ||
} | ||
}); | ||
var ListboxOption = /*#__PURE__*/vue.defineComponent({ | ||
name: 'ListboxOption', | ||
props: { | ||
as: { | ||
type: [Object, String], | ||
"default": 'li' | ||
}, | ||
value: { | ||
type: [Object, String], | ||
"default": null | ||
}, | ||
disabled: { | ||
type: Boolean, | ||
"default": false | ||
}, | ||
"class": { | ||
type: [String, Function], | ||
required: false | ||
}, | ||
className: { | ||
type: [String, Function], | ||
required: false | ||
} | ||
}, | ||
setup: function setup(props, _ref2) { | ||
var slots = _ref2.slots, | ||
attrs = _ref2.attrs; | ||
var api = useListboxContext('ListboxOption'); | ||
var id = "headlessui-listbox-option-" + useId(); | ||
var disabled = props.disabled, | ||
defaultClass = props["class"], | ||
_props$className = props.className, | ||
className = _props$className === void 0 ? defaultClass : _props$className, | ||
value = props.value; | ||
var active = vue.computed(function () { | ||
return api.activeOptionIndex.value !== null ? api.options.value[api.activeOptionIndex.value].id === id : false; | ||
}); | ||
var selected = vue.computed(function () { | ||
return api.value.value === value; | ||
}); | ||
var dataRef = vue.ref({ | ||
disabled: disabled, | ||
value: value, | ||
textValue: '' | ||
}); | ||
vue.onMounted(function () { | ||
var _document$getElementB, _document$getElementB2; | ||
var textValue = (_document$getElementB = document.getElementById(id)) === null || _document$getElementB === void 0 ? void 0 : (_document$getElementB2 = _document$getElementB.textContent) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.toLowerCase().trim(); | ||
if (textValue !== undefined) dataRef.value.textValue = textValue; | ||
}); | ||
vue.onMounted(function () { | ||
return api.registerOption(id, dataRef); | ||
}); | ||
vue.onUnmounted(function () { | ||
return api.unregisterOption(id); | ||
}); | ||
vue.onMounted(function () { | ||
var _document$getElementB3, _document$getElementB4; | ||
if (!selected.value) return; | ||
api.goToOption(Focus$1.Specific, id); | ||
(_document$getElementB3 = document.getElementById(id)) === null || _document$getElementB3 === void 0 ? void 0 : (_document$getElementB4 = _document$getElementB3.focus) === null || _document$getElementB4 === void 0 ? void 0 : _document$getElementB4.call(_document$getElementB3); | ||
}); | ||
vue.watchEffect(function () { | ||
if (!active.value) return; | ||
vue.nextTick(function () { | ||
var _document$getElementB5, _document$getElementB6; | ||
return (_document$getElementB5 = document.getElementById(id)) === null || _document$getElementB5 === void 0 ? void 0 : (_document$getElementB6 = _document$getElementB5.scrollIntoView) === null || _document$getElementB6 === void 0 ? void 0 : _document$getElementB6.call(_document$getElementB5, { | ||
block: 'nearest' | ||
}); | ||
}); | ||
}); | ||
function handleClick(event) { | ||
if (disabled) return event.preventDefault(); | ||
api.select(value); | ||
api.closeListbox(); | ||
vue.nextTick(function () { | ||
var _api$buttonRef$value5; | ||
return (_api$buttonRef$value5 = api.buttonRef.value) === null || _api$buttonRef$value5 === void 0 ? void 0 : _api$buttonRef$value5.focus(); | ||
}); | ||
} | ||
function handleFocus() { | ||
if (disabled) return api.goToOption(Focus$1.Nothing); | ||
api.goToOption(Focus$1.Specific, id); | ||
} | ||
function handlePointerMove() { | ||
if (disabled) return; | ||
if (active.value) return; | ||
api.goToOption(Focus$1.Specific, id); | ||
} | ||
function handlePointerLeave() { | ||
if (disabled) return; | ||
if (!active.value) return; | ||
api.goToOption(Focus$1.Nothing); | ||
} | ||
return function () { | ||
var slot = { | ||
active: active.value, | ||
selected: selected.value, | ||
disabled: disabled | ||
@@ -618,12 +1223,11 @@ }; | ||
id: id, | ||
role: 'menuitem', | ||
role: 'option', | ||
tabIndex: -1, | ||
"class": resolvePropValue(className, slot), | ||
"class": resolvePropValue$1(className, slot), | ||
'aria-disabled': disabled === true ? true : undefined, | ||
'aria-selected': selected.value === true ? selected.value : undefined, | ||
onClick: handleClick, | ||
onFocus: handleFocus, | ||
onMouseMove: handleMouseMove, | ||
onPointerEnter: handlePointerEnter, | ||
onPointerLeave: handlePointerLeave, | ||
onPointerUp: handlePointerUp | ||
onPointerMove: handlePointerMove, | ||
onPointerLeave: handlePointerLeave | ||
}; | ||
@@ -638,5 +1242,5 @@ return render({ | ||
} | ||
}); | ||
}); // --- | ||
function resolvePropValue(property, bag) { | ||
function resolvePropValue$1(property, bag) { | ||
if (property === undefined) return undefined; | ||
@@ -647,2 +1251,7 @@ if (typeof property === 'function') return property(bag); | ||
exports.Listbox = Listbox; | ||
exports.ListboxButton = ListboxButton; | ||
exports.ListboxLabel = ListboxLabel; | ||
exports.ListboxOption = ListboxOption; | ||
exports.ListboxOptions = ListboxOptions; | ||
exports.Menu = Menu; | ||
@@ -649,0 +1258,0 @@ exports.MenuButton = MenuButton; |
@@ -1,2 +0,2 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e=e||self).headlessui={},e.Vue)}(this,(function(e,t){"use strict";function n(){return(n=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var u in n)Object.prototype.hasOwnProperty.call(n,u)&&(e[u]=n[u])}return e}).apply(this,arguments)}function u(e,t){if(null==e)return{};var n,u,r={},o=Object.keys(e);for(u=0;u<o.length;u++)t.indexOf(n=o[u])>=0||(r[n]=e[n]);return r}function r(e,t){if(e in t){for(var n=t[e],u=arguments.length,o=new Array(u>2?u-2:0),a=2;a<u;a++)o[a-2]=arguments[a];return"function"==typeof n?n.apply(void 0,o):n}var i=new Error('Tried to handle "'+e+'" but there is no handler defined. Only defined handlers are: '+Object.keys(t).map((function(e){return'"'+e+'"'})).join(", ")+".");throw Error.captureStackTrace&&Error.captureStackTrace(i,r),i}function o(e){var n,r=e.props,o=e.attrs,a=e.slots,i=e.slot,l=r.as,s=u(r,["as"]),c=null===(n=a.default)||void 0===n?void 0:n.call(a,i);if("template"===l){if(Object.keys(s).length>0||"class"in o){var d=null!=c?c:[],f=d[0];if(d.slice(1).length>0)throw new Error('You should only render 1 child or use the `as="..."` prop');return t.cloneVNode(f,s)}return c}return t.h(l,s,c)}var a,i,l,s=0;function c(){return++s}!function(e){e[e.Open=0]="Open",e[e.Closed=1]="Closed"}(a||(a={})),function(e){e.Space=" ",e.Enter="Enter",e.Escape="Escape",e.Backspace="Backspace",e.ArrowUp="ArrowUp",e.ArrowDown="ArrowDown",e.Home="Home",e.End="End",e.PageUp="PageUp",e.PageDown="PageDown",e.Tab="Tab"}(i||(i={})),function(e){e[e.FirstItem=0]="FirstItem",e[e.PreviousItem=1]="PreviousItem",e[e.NextItem=2]="NextItem",e[e.LastItem=3]="LastItem",e[e.SpecificItem=4]="SpecificItem",e[e.Nothing=5]="Nothing"}(l||(l={}));var d=Symbol("MenuContext");function f(e){var n=t.inject(d);if(void 0===n){var u=new Error("<"+e+" /> is missing a parent <Menu /> component.");throw Error.captureStackTrace&&Error.captureStackTrace(u,f),u}return n}var v=t.defineComponent({props:{as:{type:[Object,String],default:"template"}},setup:function(e,n){var u=n.slots,i=n.attrs,s=t.ref(a.Closed),c=t.ref(null),f=t.ref(null),v=t.ref([]),p=t.ref(""),m=t.ref(null),I={menuState:s,buttonRef:c,itemsRef:f,items:v,searchQuery:p,activeItemIndex:m,closeMenu:function(){return s.value=a.Closed},openMenu:function(){return s.value=a.Open},goToItem:function(e,t){var n=function(e,t){var n,u;if(v.value.length<=0)return null;var o=null!==(n=m.value)&&void 0!==n?n:-1,a=r(e,((u={})[l.FirstItem]=function(){return v.value.findIndex((function(e){return!e.dataRef.disabled}))},u[l.PreviousItem]=function(){var e=v.value.slice().reverse().findIndex((function(e,t,n){return!(-1!==o&&n.length-t-1>=o||e.dataRef.disabled)}));return-1===e?e:v.value.length-1-e},u[l.NextItem]=function(){return v.value.findIndex((function(e,t){return!(t<=o||e.dataRef.disabled)}))},u[l.LastItem]=function(){var e=v.value.slice().reverse().findIndex((function(e){return!e.dataRef.disabled}));return-1===e?e:v.value.length-1-e},u[l.SpecificItem]=function(){return v.value.findIndex((function(e){return e.id===t}))},u[l.Nothing]=function(){return null},u));return-1===a?m.value:a}(e,t);""===p.value&&m.value===n||(p.value="",m.value=n)},search:function(e){p.value+=e;var t=v.value.findIndex((function(e){return e.dataRef.textValue.startsWith(p.value)&&!e.dataRef.disabled}));-1!==t&&t!==m.value&&(m.value=t)},clearSearch:function(){p.value=""},registerItem:function(e,t){v.value.push({id:e,dataRef:t})},unregisterItem:function(e){var t=v.value.slice(),n=null!==m.value?t[m.value]:null,u=t.findIndex((function(t){return t.id===e}));-1!==u&&t.splice(u,1),v.value=t,m.value=u===m.value||null===n?null:t.indexOf(n)}};return t.onMounted((function(){function e(e){var t,n,u;s.value===a.Open&&((null===(t=c.value)||void 0===t?void 0:t.contains(e.target))||(null===(n=f.value)||void 0===n?void 0:n.contains(e.target))||(I.closeMenu(),e.defaultPrevented||null===(u=c.value)||void 0===u||u.focus()))}window.addEventListener("pointerup",e),t.onUnmounted((function(){return window.removeEventListener("pointerup",e)}))})),t.provide(d,I),function(){return o({props:e,slot:{open:s.value===a.Open},slots:u,attrs:i})}}}),p=t.defineComponent({props:{as:{type:[Object,String],default:"button"}},render:function(){var e,t=f("MenuButton"),u={open:t.menuState.value===a.Open},r={ref:"el",id:this.id,type:"button","aria-haspopup":!0,"aria-controls":null===(e=t.itemsRef.value)||void 0===e?void 0:e.id,"aria-expanded":t.menuState.value===a.Open||void 0,onKeyDown:this.handleKeyDown,onFocus:this.handleFocus,onPointerUp:this.handlePointerUp};return o({props:n({},this.$props,r),slot:u,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=f("MenuButton");return{id:"headlessui-menu-button-"+c(),el:e.buttonRef,handleKeyDown:function(n){switch(n.key){case i.Space:case i.Enter:case i.ArrowDown:n.preventDefault(),e.openMenu(),t.nextTick((function(){var t;null===(t=e.itemsRef.value)||void 0===t||t.focus(),e.goToItem(l.FirstItem)}));break;case i.ArrowUp:n.preventDefault(),e.openMenu(),t.nextTick((function(){var t;null===(t=e.itemsRef.value)||void 0===t||t.focus(),e.goToItem(l.LastItem)}))}},handlePointerUp:function(n){e.menuState.value===a.Open?e.closeMenu():(n.preventDefault(),e.openMenu(),t.nextTick((function(){var t;return null===(t=e.itemsRef.value)||void 0===t?void 0:t.focus()})))},handleFocus:function(){var t;e.menuState.value===a.Open&&(null===(t=e.itemsRef.value)||void 0===t||t.focus())}}}}),m=t.defineComponent({props:{as:{type:[Object,String],default:"div"},static:{type:Boolean,default:!1}},render:function(){var e,t,r=f("MenuItems"),i=this.$props,l=i.static,s=u(i,["static"]);if(!l&&r.menuState.value===a.Closed)return null;var c={open:r.menuState.value===a.Open};return o({props:n({},s,{"aria-activedescendant":null===r.activeItemIndex.value||null===(e=r.items.value[r.activeItemIndex.value])||void 0===e?void 0:e.id,"aria-labelledby":null===(t=r.buttonRef.value)||void 0===t?void 0:t.id,id:this.id,onKeyDown:this.handleKeyDown,role:"menu",tabIndex:0,ref:"el"}),slot:c,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=f("MenuItems"),n="headlessui-menu-items-"+c(),u=t.ref(null);return{id:n,el:e.itemsRef,handleKeyDown:function(n){switch(u.value&&clearTimeout(u.value),n.key){case i.Enter:var r;n.preventDefault(),e.closeMenu(),null!==e.activeItemIndex.value&&(null===(r=document.getElementById(e.items.value[e.activeItemIndex.value].id))||void 0===r||r.click(),t.nextTick((function(){var t;return null===(t=e.buttonRef.value)||void 0===t?void 0:t.focus()})));break;case i.ArrowDown:return n.preventDefault(),e.goToItem(l.NextItem);case i.ArrowUp:return n.preventDefault(),e.goToItem(l.PreviousItem);case i.Home:case i.PageUp:return n.preventDefault(),e.goToItem(l.FirstItem);case i.End:case i.PageDown:return n.preventDefault(),e.goToItem(l.LastItem);case i.Escape:n.preventDefault(),e.closeMenu(),t.nextTick((function(){var t;return null===(t=e.buttonRef.value)||void 0===t?void 0:t.focus()}));break;case i.Tab:return n.preventDefault();default:1===n.key.length&&(e.search(n.key),u.value=setTimeout((function(){return e.clearSearch()}),350))}}}}}),I=t.defineComponent({props:{as:{type:[Object,String],default:"template"},disabled:{type:Boolean,default:!1},class:{type:[String,Function],required:!1},className:{type:[String,Function],required:!1}},setup:function(e,u){var r=u.slots,a=u.attrs,i=f("MenuItem"),s="headlessui-menu-item-"+c(),d=e.disabled,v=e.className,p=void 0===v?e.class:v,m=t.computed((function(){return null!==i.activeItemIndex.value&&i.items.value[i.activeItemIndex.value].id===s})),I=t.ref({disabled:d,textValue:""});function g(){d||i.goToItem(l.SpecificItem,s)}function b(){if(d)return i.goToItem(l.Nothing);i.goToItem(l.SpecificItem,s)}function y(){d||i.goToItem(l.Nothing)}function w(){d||m.value||i.goToItem(l.SpecificItem,s)}function x(e){if(d)return e.preventDefault();requestAnimationFrame((function(){requestAnimationFrame((function(){var e;i.closeMenu(),null===(e=i.buttonRef.value)||void 0===e||e.focus()}))}))}function S(e){if(d)return e.preventDefault()}return t.onMounted((function(){var e,t,n=null===(e=document.getElementById(s))||void 0===e||null===(t=e.textContent)||void 0===t?void 0:t.toLowerCase().trim();void 0!==n&&(I.value.textValue=n)})),t.onMounted((function(){return i.registerItem(s,I)})),t.onUnmounted((function(){return i.unregisterItem(s)})),function(){var t={active:m.value,disabled:d},u={id:s,role:"menuitem",tabIndex:-1,class:h(p,t),"aria-disabled":!0===d||void 0,onClick:S,onFocus:b,onMouseMove:w,onPointerEnter:g,onPointerLeave:y,onPointerUp:x};return o({props:n({},e,u),slot:t,attrs:a,slots:r})}}});function h(e,t){if(void 0!==e)return"function"==typeof e?e(t):e}e.Menu=v,e.MenuButton=p,e.MenuItem=I,e.MenuItems=m,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e=e||self).headlessui={},e.Vue)}(this,(function(e,t){"use strict";function n(){return(n=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e}).apply(this,arguments)}function o(e,t){if(null==e)return{};var n,o,u={},i=Object.keys(e);for(o=0;o<i.length;o++)t.indexOf(n=i[o])>=0||(u[n]=e[n]);return u}function u(e,t){if(e in t){for(var n=t[e],o=arguments.length,i=new Array(o>2?o-2:0),a=2;a<o;a++)i[a-2]=arguments[a];return"function"==typeof n?n.apply(void 0,i):n}var r=new Error('Tried to handle "'+e+'" but there is no handler defined. Only defined handlers are: '+Object.keys(t).map((function(e){return'"'+e+'"'})).join(", ")+".");throw Error.captureStackTrace&&Error.captureStackTrace(r,u),r}function i(e){var n,u=e.props,i=e.attrs,a=e.slots,r=e.slot,l=u.as,s=o(u,["as"]),c=null===(n=a.default)||void 0===n?void 0:n.call(a,r);if("template"===l){if(Object.keys(s).length>0||"class"in i){var d=null!=c?c:[],v=d[0];if(d.slice(1).length>0)throw new Error('You should only render 1 child or use the `as="..."` prop');return t.cloneVNode(v,s)}return c}return t.h(l,s,c)}var a,r,l,s=0;function c(){return++s}!function(e){e.Space=" ",e.Enter="Enter",e.Escape="Escape",e.Backspace="Backspace",e.ArrowUp="ArrowUp",e.ArrowDown="ArrowDown",e.Home="Home",e.End="End",e.PageUp="PageUp",e.PageDown="PageDown",e.Tab="Tab"}(a||(a={})),function(e){e[e.Open=0]="Open",e[e.Closed=1]="Closed"}(r||(r={})),function(e){e[e.FirstItem=0]="FirstItem",e[e.PreviousItem=1]="PreviousItem",e[e.NextItem=2]="NextItem",e[e.LastItem=3]="LastItem",e[e.SpecificItem=4]="SpecificItem",e[e.Nothing=5]="Nothing"}(l||(l={}));var d=Symbol("MenuContext");function v(e){var n=t.inject(d);if(void 0===n){var o=new Error("<"+e+" /> is missing a parent <Menu /> component.");throw Error.captureStackTrace&&Error.captureStackTrace(o,v),o}return n}var f,p,m=t.defineComponent({props:{as:{type:[Object,String],default:"template"}},setup:function(e,n){var o=n.slots,a=n.attrs,s=t.ref(r.Closed),c=t.ref(null),v=t.ref(null),f=t.ref([]),p=t.ref(""),m=t.ref(null),b={menuState:s,buttonRef:c,itemsRef:v,items:f,searchQuery:p,activeItemIndex:m,closeMenu:function(){return s.value=r.Closed},openMenu:function(){return s.value=r.Open},goToItem:function(e,t){var n=function(e,t){var n,o;if(f.value.length<=0)return null;var i=null!==(n=m.value)&&void 0!==n?n:-1,a=u(e,((o={})[l.FirstItem]=function(){return f.value.findIndex((function(e){return!e.dataRef.disabled}))},o[l.PreviousItem]=function(){var e=f.value.slice().reverse().findIndex((function(e,t,n){return!(-1!==i&&n.length-t-1>=i||e.dataRef.disabled)}));return-1===e?e:f.value.length-1-e},o[l.NextItem]=function(){return f.value.findIndex((function(e,t){return!(t<=i||e.dataRef.disabled)}))},o[l.LastItem]=function(){var e=f.value.slice().reverse().findIndex((function(e){return!e.dataRef.disabled}));return-1===e?e:f.value.length-1-e},o[l.SpecificItem]=function(){return f.value.findIndex((function(e){return e.id===t}))},o[l.Nothing]=function(){return null},o));return-1===a?m.value:a}(e,t);""===p.value&&m.value===n||(p.value="",m.value=n)},search:function(e){p.value+=e;var t=f.value.findIndex((function(e){return e.dataRef.textValue.startsWith(p.value)&&!e.dataRef.disabled}));-1!==t&&t!==m.value&&(m.value=t)},clearSearch:function(){p.value=""},registerItem:function(e,t){f.value.push({id:e,dataRef:t})},unregisterItem:function(e){var t=f.value.slice(),n=null!==m.value?t[m.value]:null,o=t.findIndex((function(t){return t.id===e}));-1!==o&&t.splice(o,1),f.value=t,m.value=o===m.value||null===n?null:t.indexOf(n)}};return t.onMounted((function(){function e(e){var t,n,o;s.value===r.Open&&((null===(t=c.value)||void 0===t?void 0:t.contains(e.target))||(null===(n=v.value)||void 0===n?void 0:n.contains(e.target))||(b.closeMenu(),e.defaultPrevented||null===(o=c.value)||void 0===o||o.focus()))}window.addEventListener("click",e),t.onUnmounted((function(){return window.removeEventListener("click",e)}))})),t.provide(d,b),function(){return i({props:e,slot:{open:s.value===r.Open},slots:o,attrs:a})}}}),b=t.defineComponent({props:{as:{type:[Object,String],default:"button"}},render:function(){var e,t=v("MenuButton"),o={open:t.menuState.value===r.Open},u={ref:"el",id:this.id,type:"button","aria-haspopup":!0,"aria-controls":null===(e=t.itemsRef.value)||void 0===e?void 0:e.id,"aria-expanded":t.menuState.value===r.Open||void 0,onKeyDown:this.handleKeyDown,onFocus:this.handleFocus,onPointerUp:this.handlePointerUp};return i({props:n({},this.$props,u),slot:o,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=v("MenuButton");return{id:"headlessui-menu-button-"+c(),el:e.buttonRef,handleKeyDown:function(n){switch(n.key){case a.Space:case a.Enter:case a.ArrowDown:n.preventDefault(),e.openMenu(),t.nextTick((function(){var t;null===(t=e.itemsRef.value)||void 0===t||t.focus(),e.goToItem(l.FirstItem)}));break;case a.ArrowUp:n.preventDefault(),e.openMenu(),t.nextTick((function(){var t;null===(t=e.itemsRef.value)||void 0===t||t.focus(),e.goToItem(l.LastItem)}))}},handlePointerUp:function(n){e.menuState.value===r.Open?e.closeMenu():(n.preventDefault(),e.openMenu(),t.nextTick((function(){var t;return null===(t=e.itemsRef.value)||void 0===t?void 0:t.focus()})))},handleFocus:function(){var t;e.menuState.value===r.Open&&(null===(t=e.itemsRef.value)||void 0===t||t.focus())}}}}),h=t.defineComponent({props:{as:{type:[Object,String],default:"div"},static:{type:Boolean,default:!1}},render:function(){var e,t,u=v("MenuItems"),a=this.$props,l=a.static,s=o(a,["static"]);if(!l&&u.menuState.value===r.Closed)return null;var c={open:u.menuState.value===r.Open};return i({props:n({},s,{"aria-activedescendant":null===u.activeItemIndex.value||null===(e=u.items.value[u.activeItemIndex.value])||void 0===e?void 0:e.id,"aria-labelledby":null===(t=u.buttonRef.value)||void 0===t?void 0:t.id,id:this.id,onKeyDown:this.handleKeyDown,role:"menu",tabIndex:0,ref:"el"}),slot:c,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=v("MenuItems"),n="headlessui-menu-items-"+c(),o=t.ref(null);return{id:n,el:e.itemsRef,handleKeyDown:function(n){switch(o.value&&clearTimeout(o.value),n.key){case a.Space:if(""!==e.searchQuery.value)return n.preventDefault(),e.search(n.key);case a.Enter:var u;n.preventDefault(),e.closeMenu(),null!==e.activeItemIndex.value&&(null===(u=document.getElementById(e.items.value[e.activeItemIndex.value].id))||void 0===u||u.click(),t.nextTick((function(){var t;return null===(t=e.buttonRef.value)||void 0===t?void 0:t.focus()})));break;case a.ArrowDown:return n.preventDefault(),e.goToItem(l.NextItem);case a.ArrowUp:return n.preventDefault(),e.goToItem(l.PreviousItem);case a.Home:case a.PageUp:return n.preventDefault(),e.goToItem(l.FirstItem);case a.End:case a.PageDown:return n.preventDefault(),e.goToItem(l.LastItem);case a.Escape:n.preventDefault(),e.closeMenu(),t.nextTick((function(){var t;return null===(t=e.buttonRef.value)||void 0===t?void 0:t.focus()}));break;case a.Tab:return n.preventDefault();default:1===n.key.length&&(e.search(n.key),o.value=setTimeout((function(){return e.clearSearch()}),350))}}}}}),x=t.defineComponent({props:{as:{type:[Object,String],default:"template"},disabled:{type:Boolean,default:!1},class:{type:[String,Function],required:!1},className:{type:[String,Function],required:!1}},setup:function(e,o){var u=o.slots,a=o.attrs,r=v("MenuItem"),s="headlessui-menu-item-"+c(),d=e.disabled,f=e.className,p=void 0===f?e.class:f,m=t.computed((function(){return null!==r.activeItemIndex.value&&r.items.value[r.activeItemIndex.value].id===s})),b=t.ref({disabled:d,textValue:""});function h(e){if(d)return e.preventDefault();r.closeMenu(),t.nextTick((function(){var e;return null===(e=r.buttonRef.value)||void 0===e?void 0:e.focus()}))}function x(){if(d)return r.goToItem(l.Nothing);r.goToItem(l.SpecificItem,s)}function I(){d||m.value||r.goToItem(l.SpecificItem,s)}function y(){d||m.value&&r.goToItem(l.Nothing)}return t.onMounted((function(){var e,t,n=null===(e=document.getElementById(s))||void 0===e||null===(t=e.textContent)||void 0===t?void 0:t.toLowerCase().trim();void 0!==n&&(b.value.textValue=n)})),t.onMounted((function(){return r.registerItem(s,b)})),t.onUnmounted((function(){return r.unregisterItem(s)})),function(){var t={active:m.value,disabled:d},o={id:s,role:"menuitem",tabIndex:-1,class:g(p,t),"aria-disabled":!0===d||void 0,onClick:h,onFocus:x,onPointerMove:I,onPointerLeave:y};return i({props:n({},e,o),slot:t,attrs:a,slots:u})}}});function g(e,t){if(void 0!==e)return"function"==typeof e?e(t):e}!function(e){e[e.Open=0]="Open",e[e.Closed=1]="Closed"}(f||(f={})),function(e){e[e.First=0]="First",e[e.Previous=1]="Previous",e[e.Next=2]="Next",e[e.Last=3]="Last",e[e.Specific=4]="Specific",e[e.Nothing=5]="Nothing"}(p||(p={}));var I=Symbol("ListboxContext");function y(e){var n=t.inject(I);if(void 0===n){var o=new Error("<"+e+" /> is missing a parent <Listbox /> component.");throw Error.captureStackTrace&&Error.captureStackTrace(o,y),o}return n}var O=t.defineComponent({name:"Listbox",props:{as:{type:[Object,String],default:"template"},modelValue:{type:[Object,String],default:null}},setup:function(e,n){var a=n.slots,r=n.attrs,l=n.emit,s=o(e,["modelValue"]),c=t.ref(f.Closed),d=t.ref(null),v=t.ref(null),m=t.ref(null),b=t.ref([]),h=t.ref(""),x=t.ref(null),g=t.computed((function(){return e.modelValue})),y={listboxState:c,value:g,labelRef:d,buttonRef:v,optionsRef:m,options:b,searchQuery:h,activeOptionIndex:x,closeListbox:function(){return c.value=f.Closed},openListbox:function(){return c.value=f.Open},goToOption:function(e,t){var n=function(e,t){var n,o;if(b.value.length<=0)return null;var i=null!==(n=x.value)&&void 0!==n?n:-1,a=u(e,((o={})[p.First]=function(){return b.value.findIndex((function(e){return!e.dataRef.disabled}))},o[p.Previous]=function(){var e=b.value.slice().reverse().findIndex((function(e,t,n){return!(-1!==i&&n.length-t-1>=i||e.dataRef.disabled)}));return-1===e?e:b.value.length-1-e},o[p.Next]=function(){return b.value.findIndex((function(e,t){return!(t<=i||e.dataRef.disabled)}))},o[p.Last]=function(){var e=b.value.slice().reverse().findIndex((function(e){return!e.dataRef.disabled}));return-1===e?e:b.value.length-1-e},o[p.Specific]=function(){return b.value.findIndex((function(e){return e.id===t}))},o[p.Nothing]=function(){return null},o));return-1===a?x.value:a}(e,t);""===h.value&&x.value===n||(h.value="",x.value=n)},search:function(e){h.value+=e;var t=b.value.findIndex((function(e){return!e.dataRef.disabled&&e.dataRef.textValue.startsWith(h.value)}));-1!==t&&t!==x.value&&(x.value=t)},clearSearch:function(){h.value=""},registerOption:function(e,t){b.value.push({id:e,dataRef:t})},unregisterOption:function(e){var t=b.value.slice(),n=null!==x.value?t[x.value]:null,o=t.findIndex((function(t){return t.id===e}));-1!==o&&t.splice(o,1),b.value=t,x.value=o===x.value||null===n?null:t.indexOf(n)},select:function(e){l("update:modelValue",e)}};return t.onMounted((function(){function e(e){var t,n,o;c.value===f.Open&&((null===(t=v.value)||void 0===t?void 0:t.contains(e.target))||(null===(n=m.value)||void 0===n?void 0:n.contains(e.target))||(y.closeListbox(),e.defaultPrevented||null===(o=v.value)||void 0===o||o.focus()))}window.addEventListener("click",e),t.onUnmounted((function(){return window.removeEventListener("click",e)}))})),t.provide(I,y),function(){return i({props:s,slot:{open:c.value===f.Open},slots:a,attrs:r})}}}),w=t.defineComponent({name:"ListboxLabel",props:{as:{type:[Object,String],default:"label"}},render:function(){var e={open:y("ListboxLabel").listboxState.value===f.Open};return i({props:n({},this.$props,{id:this.id,ref:"el",onPointerUp:this.handlePointerUp}),slot:e,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=y("ListboxLabel");return{id:"headlessui-listbox-label-"+c(),el:e.labelRef,handlePointerUp:function(){var t;null===(t=e.buttonRef.value)||void 0===t||t.focus()}}}}),S=t.defineComponent({name:"ListboxButton",props:{as:{type:[Object,String],default:"button"}},render:function(){var e,t=y("ListboxButton"),o={open:t.listboxState.value===f.Open,focused:this.focused},u={ref:"el",id:this.id,type:"button","aria-haspopup":!0,"aria-controls":null===(e=t.optionsRef.value)||void 0===e?void 0:e.id,"aria-expanded":t.listboxState.value===f.Open||void 0,"aria-labelledby":t.labelRef.value?[t.labelRef.value.id,this.id].join(" "):void 0,onKeyDown:this.handleKeyDown,onFocus:this.handleFocus,onBlur:this.handleBlur,onPointerUp:this.handlePointerUp};return i({props:n({},this.$props,u),slot:o,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=y("ListboxButton"),n="headlessui-listbox-button-"+c(),o=t.ref(!1);return{id:n,el:e.buttonRef,focused:o,handleKeyDown:function(n){switch(n.key){case a.Space:case a.Enter:case a.ArrowDown:n.preventDefault(),e.openListbox(),t.nextTick((function(){var t;null===(t=e.optionsRef.value)||void 0===t||t.focus(),e.value.value||e.goToOption(p.First)}));break;case a.ArrowUp:n.preventDefault(),e.openListbox(),t.nextTick((function(){var t;null===(t=e.optionsRef.value)||void 0===t||t.focus(),e.value.value||e.goToOption(p.Last)}))}},handlePointerUp:function(n){e.listboxState.value===f.Open?e.closeListbox():(n.preventDefault(),e.openListbox(),t.nextTick((function(){var t;return null===(t=e.optionsRef.value)||void 0===t?void 0:t.focus()})))},handleFocus:function(){var t;if(e.listboxState.value===f.Open)return null===(t=e.optionsRef.value)||void 0===t?void 0:t.focus();o.value=!0},handleBlur:function(){o.value=!1}}}}),L=t.defineComponent({name:"ListboxOptions",props:{as:{type:[Object,String],default:"ul"},static:{type:Boolean,default:!1}},render:function(){var e,t,u,a,r=y("ListboxOptions"),l=this.$props,s=l.static,c=o(l,["static"]);if(!s&&r.listboxState.value===f.Closed)return null;var d={open:r.listboxState.value===f.Open};return i({props:n({},c,{"aria-activedescendant":null===r.activeOptionIndex.value||null===(e=r.options.value[r.activeOptionIndex.value])||void 0===e?void 0:e.id,"aria-labelledby":null!==(t=null===(u=r.labelRef.value)||void 0===u?void 0:u.id)&&void 0!==t?t:null===(a=r.buttonRef.value)||void 0===a?void 0:a.id,id:this.id,onKeyDown:this.handleKeyDown,role:"listbox",tabIndex:0,ref:"el"}),slot:d,attrs:this.$attrs,slots:this.$slots})},setup:function(){var e=y("ListboxOptions"),n="headlessui-listbox-options-"+c(),o=t.ref(null);return{id:n,el:e.optionsRef,handleKeyDown:function(n){switch(o.value&&clearTimeout(o.value),n.key){case a.Space:if(""!==e.searchQuery.value)return n.preventDefault(),e.search(n.key);case a.Enter:n.preventDefault(),e.closeListbox(),null!==e.activeOptionIndex.value&&(e.select(e.options.value[e.activeOptionIndex.value].dataRef.value),t.nextTick((function(){var t;return null===(t=e.buttonRef.value)||void 0===t?void 0:t.focus()})));break;case a.ArrowDown:return n.preventDefault(),e.goToOption(p.Next);case a.ArrowUp:return n.preventDefault(),e.goToOption(p.Previous);case a.Home:case a.PageUp:return n.preventDefault(),e.goToOption(p.First);case a.End:case a.PageDown:return n.preventDefault(),e.goToOption(p.Last);case a.Escape:n.preventDefault(),e.closeListbox(),t.nextTick((function(){var t;return null===(t=e.buttonRef.value)||void 0===t?void 0:t.focus()}));break;case a.Tab:return n.preventDefault();default:1===n.key.length&&(e.search(n.key),o.value=setTimeout((function(){return e.clearSearch()}),350))}}}}}),T=t.defineComponent({name:"ListboxOption",props:{as:{type:[Object,String],default:"li"},value:{type:[Object,String],default:null},disabled:{type:Boolean,default:!1},class:{type:[String,Function],required:!1},className:{type:[String,Function],required:!1}},setup:function(e,o){var u=o.slots,a=o.attrs,r=y("ListboxOption"),l="headlessui-listbox-option-"+c(),s=e.disabled,d=e.className,v=void 0===d?e.class:d,f=e.value,m=t.computed((function(){return null!==r.activeOptionIndex.value&&r.options.value[r.activeOptionIndex.value].id===l})),b=t.computed((function(){return r.value.value===f})),h=t.ref({disabled:s,value:f,textValue:""});function x(e){if(s)return e.preventDefault();r.select(f),r.closeListbox(),t.nextTick((function(){var e;return null===(e=r.buttonRef.value)||void 0===e?void 0:e.focus()}))}function g(){if(s)return r.goToOption(p.Nothing);r.goToOption(p.Specific,l)}function I(){s||m.value||r.goToOption(p.Specific,l)}function O(){s||m.value&&r.goToOption(p.Nothing)}return t.onMounted((function(){var e,t,n=null===(e=document.getElementById(l))||void 0===e||null===(t=e.textContent)||void 0===t?void 0:t.toLowerCase().trim();void 0!==n&&(h.value.textValue=n)})),t.onMounted((function(){return r.registerOption(l,h)})),t.onUnmounted((function(){return r.unregisterOption(l)})),t.onMounted((function(){var e,t;b.value&&(r.goToOption(p.Specific,l),null===(e=document.getElementById(l))||void 0===e||null===(t=e.focus)||void 0===t||t.call(e))})),t.watchEffect((function(){m.value&&t.nextTick((function(){var e,t;return null===(e=document.getElementById(l))||void 0===e||null===(t=e.scrollIntoView)||void 0===t?void 0:t.call(e,{block:"nearest"})}))})),function(){var t={active:m.value,selected:b.value,disabled:s},o={id:l,role:"option",tabIndex:-1,class:k(v,t),"aria-disabled":!0===s||void 0,"aria-selected":!0===b.value?b.value:void 0,onClick:x,onFocus:g,onPointerMove:I,onPointerLeave:O};return i({props:n({},e,o),slot:t,attrs:a,slots:u})}}});function k(e,t){if(void 0!==e)return"function"==typeof e?e(t):e}e.Listbox=O,e.ListboxButton=S,e.ListboxLabel=w,e.ListboxOption=T,e.ListboxOptions=L,e.Menu=m,e.MenuButton=b,e.MenuItem=x,e.MenuItems=h,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=headlessui.umd.production.min.js.map |
export * from './components/menu/menu'; | ||
export * from './components/listbox/listbox'; |
@@ -1,35 +0,75 @@ | ||
export declare enum MenuButtonState { | ||
export declare function getMenuButton(): HTMLElement | null; | ||
export declare function getMenuButtons(): HTMLElement[]; | ||
export declare function getMenu(): HTMLElement | null; | ||
export declare function getMenus(): HTMLElement[]; | ||
export declare function getMenuItems(): HTMLElement[]; | ||
export declare enum MenuState { | ||
Open = 0, | ||
Closed = 1 | ||
} | ||
export declare enum MenuState { | ||
export declare function assertMenuButton(options: { | ||
attributes?: Record<string, string | null>; | ||
textContent?: string; | ||
state: MenuState; | ||
}, button?: HTMLElement | null): void; | ||
export declare function assertMenuButtonLinkedWithMenu(button?: HTMLElement | null, menu?: HTMLElement | null): void; | ||
export declare function assertMenuLinkedWithMenuItem(item: HTMLElement | null, menu?: HTMLElement | null): void; | ||
export declare function assertNoActiveMenuItem(menu?: HTMLElement | null): void; | ||
export declare function assertMenu(options: { | ||
attributes?: Record<string, string | null>; | ||
textContent?: string; | ||
state: MenuState; | ||
}, menu?: HTMLElement | null): void; | ||
export declare function assertMenuItem(item: HTMLElement | null, options?: { | ||
tag?: string; | ||
attributes?: Record<string, string | null>; | ||
}): void; | ||
export declare function getListboxLabel(): HTMLElement | null; | ||
export declare function getListboxButton(): HTMLElement | null; | ||
export declare function getListboxButtons(): HTMLElement[]; | ||
export declare function getListbox(): HTMLElement | null; | ||
export declare function getListboxes(): HTMLElement[]; | ||
export declare function getListboxOptions(): HTMLElement[]; | ||
export declare enum ListboxState { | ||
Open = 0, | ||
Closed = 1 | ||
} | ||
declare type MenuButtonOptions = { | ||
export declare function assertListbox(options: { | ||
attributes?: Record<string, string | null>; | ||
textContent?: string; | ||
} & ({ | ||
state: MenuButtonState.Closed; | ||
} | { | ||
state: MenuButtonState.Open; | ||
}); | ||
export declare function assertMenuButton(button: HTMLElement | null, options: MenuButtonOptions): void; | ||
export declare function assertMenuButtonLinkedWithMenu(button: HTMLElement | null, menu: HTMLElement | null): void; | ||
export declare function assertMenuLinkedWithMenuItem(menu: HTMLElement | null, item: HTMLElement | null): void; | ||
export declare function assertNoActiveMenuItem(menu: HTMLElement | null): void; | ||
declare type MenuOptions = { | ||
state: ListboxState; | ||
}, listbox?: HTMLElement | null): void; | ||
export declare function assertListboxButton(options: { | ||
attributes?: Record<string, string | null>; | ||
} & ({ | ||
state: MenuState.Closed; | ||
} | { | ||
state: MenuState.Open; | ||
}); | ||
export declare function assertMenu(menu: HTMLElement | null, options: MenuOptions): void; | ||
declare type MenuItemOptions = { | ||
tag: string; | ||
textContent?: string; | ||
state: ListboxState; | ||
}, button?: HTMLElement | null): void; | ||
export declare function assertListboxLabel(options: { | ||
attributes?: Record<string, string | null>; | ||
}; | ||
export declare function assertMenuItem(item: HTMLElement | null, options?: MenuItemOptions): void; | ||
tag?: string; | ||
textContent?: string; | ||
}, label?: HTMLElement | null): void; | ||
export declare function assertListboxButtonLinkedWithListbox(button?: HTMLElement | null, listbox?: HTMLElement | null): void; | ||
export declare function assertListboxLabelLinkedWithListbox(label?: HTMLElement | null, listbox?: HTMLElement | null): void; | ||
export declare function assertListboxButtonLinkedWithListboxLabel(button?: HTMLElement | null, label?: HTMLElement | null): void; | ||
export declare function assertActiveListboxOption(item: HTMLElement | null, listbox?: HTMLElement | null): void; | ||
export declare function assertNoActiveListboxOption(listbox?: HTMLElement | null): void; | ||
export declare function assertNoSelectedListboxOption(items?: HTMLElement[]): void; | ||
export declare function assertListboxOption(item: HTMLElement | null, options?: { | ||
tag?: string; | ||
attributes?: Record<string, string | null>; | ||
selected?: boolean; | ||
}): void; | ||
export declare function getSwitch(): HTMLElement | null; | ||
export declare enum SwitchState { | ||
On = 0, | ||
Off = 1 | ||
} | ||
export declare function assertSwitch(options: { | ||
state: SwitchState; | ||
tag?: string; | ||
textContent?: string; | ||
label?: string; | ||
}, switchElement?: HTMLElement | null): void; | ||
export declare function assertLabelValue(element: HTMLElement | null, value: string): void; | ||
export declare function assertActiveElement(element: HTMLElement | null): void; | ||
export {}; |
@@ -51,4 +51,4 @@ export declare const Keys: Record<string, Partial<KeyboardEvent>>; | ||
export declare function focus(element: Document | Element | Window | null): Promise<void>; | ||
export declare function mouseEnter(element: Document | Element | Window | null): Promise<void>; | ||
export declare function mouseMove(element: Document | Element | Window | null): Promise<void>; | ||
export declare function hover(element: Document | Element | Window | null): Promise<void>; | ||
export declare function unHover(element: Document | Element | Window | null): Promise<void>; | ||
export declare function mouseLeave(element: Document | Element | Window | null): Promise<void>; |
{ | ||
"name": "@headlessui/vue", | ||
"version": "0.1.3", | ||
"version": "0.1.4-alpha.1", | ||
"main": "dist/index.js", | ||
@@ -34,16 +34,13 @@ "typings": "dist/index.d.ts", | ||
"devDependencies": { | ||
"@popperjs/core": "^2.4.4", | ||
"@tailwindcss/ui": "^0.6.2", | ||
"@testing-library/vue": "^5.0.4", | ||
"@popperjs/core": "^2.5.3", | ||
"@testing-library/vue": "^5.1.0", | ||
"@types/debounce": "^1.2.0", | ||
"@types/node": "^14.11.1", | ||
"@types/node": "^14.11.2", | ||
"@vue/compiler-sfc": "3.0.0-rc.13", | ||
"@vue/test-utils": "^2.0.0-beta.5", | ||
"@vue/test-utils": "^2.0.0-beta.6", | ||
"husky": "^4.3.0", | ||
"tailwindcss": "^1.8.10", | ||
"tsdx": "^0.13.3", | ||
"vite": "^1.0.0-rc.4", | ||
"vue": "^3.0.0-rc.13", | ||
"vue-router": "^4.0.0-beta.10" | ||
"vue-router": "^4.0.0-beta.12" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
499759
10
26
3830