UNPKG

@ideal-postcodes/address-finder

Version:

Address Finder JS library backed by the Ideal Postcodes UK address search API

242 lines (241 loc) 8.06 kB
import { createMachine, interpret } from "@xstate/fsm"; // @hidden export const create = ({ c }) => { const machine = createMachine({ initial: "closed", states: { closed: { entry: ["close"], exit: ["open"], on: { COUNTRY_CHANGE_EVENT: { actions: ["updateContextWithCountry"], }, AWAKE: [ { target: "suggesting", cond: () => c.suggestions.length > 0, }, { target: "notifying", }, ], }, }, notifying: { entry: ["renderNotice"], exit: ["clearAnnouncement"], on: { CLOSE: "closed", SUGGEST: { target: "suggesting", actions: ["updateSuggestions"] }, NOTIFY: { target: "notifying", actions: ["updateMessage"] }, INPUT: { actions: "input" }, CHANGE_COUNTRY: { target: "suggesting_country" }, }, }, suggesting_country: { entry: [ "clearInput", "renderContexts", "gotoCurrent", "expand", "addCountryHint", ], exit: [ "resetCurrent", "gotoCurrent", "contract", "clearHint", "clearInput", ], on: { CLOSE: "closed", NOTIFY: { target: "notifying", actions: ["updateMessage"] }, NEXT: { actions: ["next", "gotoCurrent"] }, PREVIOUS: { actions: ["previous", "gotoCurrent"] }, RESET: { actions: ["resetCurrent", "gotoCurrent"] }, INPUT: { actions: ["countryInput"], }, SELECT_COUNTRY: { target: "notifying", actions: ["selectCountry"], }, }, }, suggesting: { entry: ["renderSuggestions", "gotoCurrent", "expand", "addHint"], exit: ["resetCurrent", "gotoCurrent", "contract", "clearHint"], on: { CLOSE: "closed", SUGGEST: { target: "suggesting", actions: ["updateSuggestions"] }, NOTIFY: { target: "notifying", actions: ["updateMessage"] }, INPUT: { actions: "input" }, CHANGE_COUNTRY: { target: "suggesting_country" }, NEXT: { actions: ["next", "gotoCurrent"] }, PREVIOUS: { actions: ["previous", "gotoCurrent"] }, RESET: { actions: ["resetCurrent", "gotoCurrent"] }, SELECT_ADDRESS: { target: "closed", actions: ["selectAddress"] }, }, }, }, }, { actions: { // Updates the Address Finder context updateContextWithCountry: (_, e) => { if (e.type !== "COUNTRY_CHANGE_EVENT") return; if (!e.contextDetails) return; c.applyContext(e.contextDetails); c.suggestions = []; c.cache.clear(); }, addHint: () => { c.setPlaceholder(c.options.msgPlaceholder); }, addCountryHint: () => { c.setPlaceholder(c.options.msgPlaceholderCountry); }, clearHint: () => { c.unsetPlaceholder(); }, // Empties current input clearInput: () => { c.clearInput(); }, /** * Updates current li in list to active descendant */ gotoCurrent: () => { c.goToCurrent(); }, /** * Unhighlights a suggestion */ resetCurrent: () => { c.current = -1; }, /** * Triggers onInput callback */ input: (_, e) => { if (e.type !== "INPUT") return; c.retrieveSuggestions(e.event); }, /** * Narrows country search box */ countryInput: () => { c.renderContexts(); }, /** * Clears ARIA announcement fields */ clearAnnouncement: () => { c.announce(""); }, /** * Renders suggestion within list */ renderContexts: (_, e) => { if (e.type !== "CHANGE_COUNTRY") return; c.renderContexts(); }, /** * Renders suggestion within list */ renderSuggestions: (_, e) => { if (e.type !== "SUGGEST") return; c.renderSuggestions(); }, /** * Update suggestions */ updateSuggestions: (_, e) => { if (e.type !== "SUGGEST") return; c.updateSuggestions(e.suggestions); }, /** * Hides list and runs callback */ close: (_, e) => { if (e.type === "CLOSE") return c.close(e.reason); c.close(); }, /** * Makes list visible and run callback */ open: () => { c.open(); }, /** * Marks aria component as expanded */ expand: () => { c.ariaExpand(); }, /** * Marks aria component as closed */ contract: () => { c.ariaContract(); }, /** * Assigns notification message */ updateMessage: (_, e) => { if (e.type !== "NOTIFY") return; c.notification = e.notification; }, /** * Renders message container and current message */ renderNotice: () => { c.renderNotice(); }, /** * Selects next element in list. Wraps to top if at bottom */ next: () => { c.next(); }, /** * Selects previous element in list. Wraps to bottom if at top */ previous: () => { c.previous(); }, /** * Triggers select on current context or clicked element */ selectCountry: (_, e) => { if (e.type !== "SELECT_COUNTRY") return; const co = e.contextDetails; if (!co) return; c.applyContext(co); c.notification = `Country switched to ${co.description} ${co.emoji}`; }, /** * Triggers select on current suggestion or clicked element */ selectAddress: (_, e) => { if (e.type !== "SELECT_ADDRESS") return; const s = e.suggestion; if (!s) return; c.applySuggestion(s); }, }, }); return interpret(machine); };