|
import { useEscapeKeydown } from '../../internal/actions/index.js'; |
|
import { addEventListener, addMeltEventListener, makeElement, createElHelpers, effect, executeCallbacks, isContentEditable, isHTMLInputElement, kbd, noop, omit, } from '../../internal/helpers/index.js'; |
|
import { writable } from 'svelte/store'; |
|
import { createListbox } from '../listbox/create.js'; |
|
|
|
export const INTERACTION_KEYS = [kbd.ARROW_LEFT, kbd.ESCAPE, kbd.ARROW_RIGHT, kbd.SHIFT, kbd.CAPS_LOCK, kbd.CONTROL, kbd.ALT, kbd.META, kbd.ENTER, kbd.F1, kbd.F2, kbd.F3, kbd.F4, kbd.F5, kbd.F6, kbd.F7, kbd.F8, kbd.F9, kbd.F10, kbd.F11, kbd.F12]; |
|
const { name } = createElHelpers('combobox'); |
|
|
|
|
|
|
|
|
|
|
|
export function createCombobox(props) { |
|
const listbox = createListbox({ ...props, builder: 'combobox', typeahead: false }); |
|
const inputValue = writable(''); |
|
const touchedInput = writable(false); |
|
|
|
|
|
|
|
|
|
const input = makeElement(name('input'), { |
|
stores: [listbox.elements.trigger, inputValue], |
|
returned: ([$trigger, $inputValue]) => { |
|
return { |
|
...omit($trigger, 'action'), |
|
role: 'combobox', |
|
value: $inputValue, |
|
autocomplete: 'off', |
|
}; |
|
}, |
|
action: (node) => { |
|
const unsubscribe = executeCallbacks(addMeltEventListener(node, 'input', (e) => { |
|
if (!isHTMLInputElement(e.target) && !isContentEditable(e.target)) |
|
return; |
|
touchedInput.set(true); |
|
}), |
|
|
|
addEventListener(node, 'input', (e) => { |
|
if (isHTMLInputElement(e.target)) { |
|
inputValue.set(e.target.value); |
|
} |
|
if (isContentEditable(e.target)) { |
|
inputValue.set(e.target.innerText); |
|
} |
|
})); |
|
let unsubEscapeKeydown = noop; |
|
const escape = useEscapeKeydown(node, { |
|
handler: () => { |
|
listbox.helpers.closeMenu(); |
|
}, |
|
}); |
|
if (escape && escape.destroy) { |
|
unsubEscapeKeydown = escape.destroy; |
|
} |
|
const { destroy } = listbox.elements.trigger(node); |
|
return { |
|
destroy() { |
|
destroy?.(); |
|
unsubscribe(); |
|
unsubEscapeKeydown(); |
|
}, |
|
}; |
|
}, |
|
}); |
|
effect(listbox.states.open, ($open) => { |
|
if (!$open) { |
|
touchedInput.set(false); |
|
} |
|
}); |
|
return { |
|
...listbox, |
|
elements: { |
|
...omit(listbox.elements, 'trigger'), |
|
input, |
|
}, |
|
states: { |
|
...listbox.states, |
|
touchedInput, |
|
inputValue, |
|
}, |
|
}; |
|
} |
|
|