Skip to content

Instantly share code, notes, and snippets.

@christianhg
Last active June 28, 2021 19:29
Show Gist options
  • Save christianhg/66480bef0e036e600a453f970267b5d9 to your computer and use it in GitHub Desktop.
Save christianhg/66480bef0e036e600a453f970267b5d9 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const findIndex = (items, item) => {
const index = items.findIndex(item)
console.log(index)
return index >= 0 ? index : undefined
}
const comboboxMachine = Machine({
id: 'combobox',
context: {
results: [],
query: '',
pointer: 0,
selection: undefined,
items: ["apple", "banana", "coconut"]
},
initial: 'enabled',
states: {
disabled: {
on: {
TOGGLE_DISABLED: 'enabled'
}
},
enabled: {
on: {
TOGGLE_DISABLED: 'disabled'
},
type: 'parallel',
states: {
input: {
initial: 'idle',
states: {
idle: {
on: {
FOCUS: {
target: 'focused'
}
}
},
focused: {
on: {
BLUR: {
target: 'idle'
}
}
}
}
},
list: {
initial: 'closed',
states: {
closed: {
on: {
FOCUS: 'opened'
}
},
opened: {
always: [
{
cond: 'hasSelection',
actions: ['pointAtSelection'],
target: 'browsingList'
}
],
on: {
BLUR: 'closed',
QUERY_CHANGED: [
{
target: '.',
actions: ['updateQuery', 'updateResults']
}
]
},
initial: 'idle',
states: {
idle: {
on: {
DOWN: [
{
cond: 'hasResults',
target: 'browsingList'
},
{
target: 'focusingFooter'
}
]
}
},
browsingList: {
on: {
UP: [
{
cond: 'firstResult',
target: 'browsingList'
},
{
actions: ['movePointerUp']
}
],
DOWN: [
{
cond: 'lastResult',
target: 'focusingFooter'
},
{
actions: ['movePointerDown']
}
],
ENTER: {
actions: ['setSelection', 'reset', send('BLUR')]
}
},
},
focusingFooter: {
on: {
UP: {
cond: 'hasResults',
target: 'browsingList'
},
ENTER: {
actions: ['reset', send('BLUR')]
}
}
}
}
}
}
}
}
},
}
}, {
guards: {
firstResult: (context) => context.pointer === 0,
lastResult: (context) => context.pointer === context.results.length - 1,
hasResults: (context) => context.results.length > 0 && context.query.length > 0,
noResults: (context) => context.results.length === 0 && context.query.length > 0,
hasSelection: (context) => {
console.log('has selection', context)
return context.selectection !== undefined}
},
actions: {
movePointerUp: assign({
pointer: (context) => context.pointer - 1
}),
movePointerDown: assign({
pointer: (context) => context.pointer + 1
}),
reset: assign({
pointer: 0,
query: '',
results: [],
}),
resetQuery: assign({
query: '',
results: [],
}),
updateQuery: assign({
query: (context, event) =>
event.type === 'QUERY_CHANGED' ? event.query : context.query,
}),
updateResults: assign({
results: (context, event) =>
event.type === 'QUERY_CHANGED' ? event.results : context.results,
}),
setSelection: assign({
selection: (context) => context.results[context.pointer]
}),
pointAtSelection: assign({
pointer: (context) => findIndex(context.items, context.selection) ?? 0
})
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment