Skip to content

Instantly share code, notes, and snippets.

@saneef
Last active October 21, 2020 07:24
Show Gist options
  • Save saneef/50c56ac348d7e723ce1e62d9f1242442 to your computer and use it in GitHub Desktop.
Save saneef/50c56ac348d7e723ce1e62d9f1242442 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const MIN_LENGTH = 3;
const autocompleteInputMachine = Machine(
{
id: "autocomplete-input",
initial: "idle",
context: {
query: "",
message: "",
suggestions: [],
activeSuggestionIndex: -1,
},
on: {
CHANGE: { target: "checkValue", actions: "saveQuery" },
submit: {
target: "search",
cond: "hasValue",
},
},
states: {
idle: {
id: "idle",
},
checkValue: {
id: "checkValue",
on: {
'': [{ target: "fetch", cond: "hasMinLength" }, { target: "idle" }]
},
},
fetch: {
id: "fetch",
invoke: {
id: "fetch",
src: "fetchSuggestions",
onDone: {
target: "validateSuggestions",
actions: assign({
suggestions: (context, event) => event.data,
}),
},
onError: {
target: "error",
actions: assign({
message: (context, event) => event.data,
}),
},
},
},
error: {},
validateSuggestions: {
on: {
"": [
{ target: "suggestions", cond: "hasSuggestions" },
{ target: "idle" },
],
}
},
suggestions: {
initial: "inactive",
entry: "saveLastQuery",
exit: "deleteLastQuery",
on: {
click: {
target: "search",
cond: "hasQuery",
},
},
states: {
inactive: {
exit: "resetActiveSuggestionIndex",
on: {
keyup: [
{
target: "active",
cond: "isArrowUpKey",
actions: ["activatePrev"],
},
{
target: "active",
cond: "isArrowDownKey",
actions: ["activateNext"],
},
],
},
},
active: {
on: {
keyup: [
{
target: "inactive",
cond: "isArrowUpKeyAndFirstItemActive",
},
{
target: "inactive",
cond: "isArrowDownKeyAndLastItemActive",
},
{
target: "active",
cond: "isArrowUpKey",
actions: "activatePrev",
},
{
target: "active",
cond: "isArrowDownKey",
actions: "activateNext",
},
],
},
},
},
},
search: {
id: "search",
type: "final",
entry: "setQuery",
},
},
},
{
actions: {
resetActiveSuggestionIndex: assign({
activeSuggestionIndex: -1,
}),
saveQuery: assign({
query: (context, event) => event.value,
}),
saveLastQuery: assign({
prevQuery: (context, event) => context.query,
}),
deleteLastQuery: assign({
prevQuery: undefined,
}),
activateNext: assign({
activeSuggestionIndex: (context, event) => {
let index = context.activeSuggestionIndex || 0;
index = index + 1;
if (index > context.suggestions.length - 1) {
index = 0;
}
return index;
},
}),
activatePrev: assign({
activeSuggestionIndex: (context, event) => {
let index = context.activeSuggestionIndex || 0;
index = index - 1;
if (index < 0) {
index = context.suggestions.length - 1;
}
return index;
},
}),
setQuery: assign({
query: (context, event) => event.query,
}),
},
guards: {
hasMinLength: (context, event) =>
context.query && context.query.length >= MIN_LENGTH,
hasValue: (context, event) => context.query && context.query !== "",
hasSuggestions: (context) => context.suggestions.length,
isArrowDownKey: (context, event) => event.key === "ArrowDown",
isArrowUpKey: (context, event) => event.key === "ArrowUp",
isArrowDownKeyAndLastItemActive: (context, event) =>
event.key === "ArrowDown" &&
context.activeSuggestionIndex === context.suggestions.length - 1,
isArrowUpKeyAndFirstItemActive: (context, event) =>
event.key === "ArrowUp" && context.activeSuggestionIndex === 0,
hasQuery: (context, event) => event.query,
},
services: {
fetchSuggestions: (context) =>
fetchSuggestions({ query: context.query, errorRate: 0.25 }),
},
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment