Skip to content

Instantly share code, notes, and snippets.

@DaveWelling
Last active August 3, 2020 21:44
Show Gist options
  • Save DaveWelling/74b101f70c55c642a6c57ff0be1218b0 to your computer and use it in GitHub Desktop.
Save DaveWelling/74b101f70c55c642a6c57ff0be1218b0 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
/* eslint camelcase: 0 */ // Ignore camelcase in this file.
// To get a visualization of this finite state machine,
// to to https://xstate.js.org/viz/?gist=74b101f70c55c642a6c57ff0be1218b0.
// You may have to copy the code below and replace the
// 'CODE' section in the link above.
// (HINT: It is easier to copy if you collapse all the top level stuff)
// ********************************************************
// TO COPY TO VISUALIZATION TOOL LINKED ABOVE, START COPY HERE
// ********************************************************
const isTrue = 'isTrue';
const isFalse = 'isFalse';
// A default context for visualization tool - overridden by app.
// eslint-disable-next-line no-unused-vars
const context = {
listOptions: [],
currentInputText: '',
initialSelectedOptions: [],
currentSelectedOptions: [],
initialFilters: {},
currentFilters: {},
settings: {
autoSelect: false,
autoHide: false,
multiSelect: false,
hNode: {},
formContext: {}
},
subscriptions: {},
callbackForTextInputChange: () => {},
onSelectionChanged: () => {}
// for reference (it is set later):
// focusedListOption: undefined
};
const fsmGuards = {
c_and: (context, event, { cond }) =>
cond.conditions.every(childCond =>
fsmGuards[typeof childCond === 'string' ? childCond : childCond.type](context, event, {
cond: childCond
})
),
c_multiSelect: (context, event, { cond }) =>
(cond.isFalse && !context.settings.multiSelect) || (!cond.isFalse && context.settings.multiSelect),
c_keyEqual: (context, event, { cond }) => {
return event.keyValue === cond.keyValue;
},
c_listOptionFocused: (context, event, { cond }) =>
(context.focusedListOption && !cond.isFalse) || (!context.focusedListOption && cond.isFalse),
c_onlyOneSelectionOption: (context, event, { cond }) => {
return context.listOptions && context.listOptions.length === 1 && !cond.isFalse;
},
c_autoHide: (context, event, { cond }) => context.settings.autoHide && !cond.isFalse,
c_autoSelect: (context, event, { cond }) => {
return context.settings.autoSelect && !cond.isFalse;
},
c_atLeastOneListOption: (context, event, { cond }) => context.listOptions.length > 0 && !cond.isFalse,
c_currentInputTextEqualOriginal: (context, event, { cond }) => {
if (!context.settings) return true;
let result;
if (context.settings.multiSelect) {
result = context.currentInputText === '';
} else {
const { propertyName } = context.settings.hNode;
result =
(!context.initialSelectedOptions &&
(typeof context.currentInputText === 'undefined' || context.currentInputText === '')) ||
context.currentInputText ===
(context.initialSelectedOptions ? context.initialSelectedOptions[propertyName] : '');
}
return !cond.isFalse ? result : !result;
},
c_incomingInputTextEqualOriginal: (context, event, { cond }) => {
if (!context.settings) return true;
if (context.settings.multiSelect) {
return event.searchTerm === '' && !cond.isFalse;
} else {
const { propertyName } = context.settings.hNode;
const result =
(!context.initialSelectedOptions &&
(typeof event.searchTerm === 'undefined' || event.searchTerm === '')) ||
event.searchTerm ===
(context.initialSelectedOptions ? context.initialSelectedOptions[propertyName] : '');
// Invert result if isFalse is passed.
return !cond.isFalse ? result : !result;
}
},
c_enterIsQueued: context => context.enterQueued,
c_isLoading: context => context.loadActorRef.state.matches('is_loading'),
c_cursorInInput: (context, event, { cond }) => {
const result = event.tagName.toLowerCase() === 'input';
return !cond.isFalse ? result : !result;
}
};
const fsmConfig = {
id: 'dropDownFsm',
initial: 'is_mounted',
context: {
// Default this or you will get this error: "A component is changing an uncontrolled input of type text to be controlled"
currentInputText: ''
},
states: {
is_mounted: {
on: {
FORM_BECOMES_VISIBLE: 'is_preparingToDisplay'
}
},
is_preparingToDisplay: {
entry: ['do_addSubscriptions', 'do_spawnLoadMachine'],
on: {
LOAD_SUCCESS: {
target: 'is_loaded',
actions: 'do_updateListOptions'
},
VALUE_SELECTED: {
actions: ['do_displayValue']
}
}
},
is_loaded: {
on: {
FORM_BECOMES_HIDDEN: {
target: 'is_mounted',
actions: ['do_shutdownLoadMachine']
}
},
always: [
{
target: 'is_hidden',
cond: {
type: 'c_and',
conditions: [
{
type: 'c_onlyOneSelectionOption'
},
{
type: 'c_autoHide'
},
{
type: 'c_autoSelect'
}
]
},
actions: 'do_selectFirstListOption'
},
{
target: 'is_hidden',
cond: {
type: 'c_and',
conditions: [
{
type: 'c_onlyOneSelectionOption'
},
{
type: 'c_autoHide'
}
]
}
},
{
target: 'is_visible',
cond: {
type: 'c_and',
conditions: [
{
type: 'c_onlyOneSelectionOption'
},
{
type: 'c_autoSelect'
}
]
},
actions: 'do_selectFirstListOption'
},
{
target: 'is_visible',
actions: 'do_raiseSelectEvent'
}
]
},
is_visible: {
invoke: {
id: 'testSelectionInForeignRelation',
src: 'svc_testSelectionInForeignRelation'
},
initial: 'is_waitingForFocus',
on: {
FORM_BECOMES_HIDDEN: {
target: 'is_mounted',
actions: ['do_shutdownLoadMachine', 'do_unsubscribe']
},
SIBLING_DEPENDENCY_CHANGED: {
actions: [
'do_composeForeignRelationSelectionFilter',
'do_sendFilterToLoad',
'do_verifySelectionInForeignRelationDependency'
]
},
SELECTED_OPTION_NOT_IN_DEPENDENCY: {
actions: 'do_clearCurrentSelection'
}
},
states: {
is_waitingForFocus: {
entry: 'do_displayValue',
on: {
GETS_FOCUS: 'is_focused',
VALUE_SELECTED: {
actions: ['do_raiseSelectEvent', 'do_displayValue']
}
}
},
is_focused: {
entry: ['do_storeOriginalValue'],
initial: 'is_ready',
on: {
LOST_FOCUS: {
target: 'is_waitingForFocus',
actions: ['do_revertInputText']
},
KEY_DOWN: [
{
// ARROW DOWN from input box
cond: {
type: 'c_and',
conditions: [
{
type: 'c_keyEqual',
keyValue: 'ArrowDown'
},
{
type: 'c_cursorInInput'
}
]
},
actions: 'do_focusFirstListOption'
},
{
// ARROW DOWN from inside list
cond: {
type: 'c_and',
conditions: [
{
type: 'c_keyEqual',
keyValue: 'ArrowDown'
},
{
type: 'c_cursorInInput',
isFalse
}
]
},
actions: 'do_focusNextListOption'
},
{
// ARROW UP from inside list
cond: {
type: 'c_and',
conditions: [
{
type: 'c_keyEqual',
keyValue: 'ArrowUp'
},
{
type: 'c_cursorInInput',
isFalse
}
]
},
actions: 'do_focusPreviousListOption'
},
{
// ESCAPE
target: 'is_focused.is_ready',
cond: {
type: 'c_keyEqual',
keyValue: 'Escape'
},
actions: ['do_revertInputText']
},
{
// ENTER ON FOCUSED LIST OPTION
target: 'is_waitingForFocus',
cond: {
type: 'c_and',
conditions: [
{
type: 'c_keyEqual',
keyValue: 'Enter'
},
{
type: 'c_listOptionFocused'
}
]
},
actions: ['do_selectFocusedListOption', 'do_gotoNextControl']
},
{
// ENTER FROM INPUT BOX
target: 'is_waitingForFocus',
cond: {
type: 'c_and',
conditions: [
{
type: 'c_keyEqual',
keyValue: 'Enter'
},
{
type: 'c_isLoading',
isFalse
},
{
type: 'c_atLeastOneListOption'
}
]
},
actions: 'do_selectFirstListOption'
},
{
cond: {
type: 'c_and',
conditions: [
{
type: 'c_keyEqual',
keyValue: 'Enter'
},
{
type: 'c_isLoading'
}
]
},
actions: 'do_queueEnterForLoadSuccess'
}
],
VALUE_SELECTED: [
{
target: 'is_waitingForFocus',
cond: {
type: 'c_multiSelect',
isFalse
},
actions: ['do_raiseSelectEvent', 'do_displayValue']
},
{
target: 'is_focused.is_ready',
cond: {
type: 'c_multiSelect',
isTrue
},
actions: ['do_raiseSelectEvent', 'do_displayValue']
}
],
LOAD_SUCCESS: [
{
target: 'is_waitingForFocus',
cond: {
type: 'c_and',
conditions: ['c_enterIsQueued', 'c_atLeastOneListOption']
},
actions: ['do_clearEnterQueue', 'do_selectFirstListOption', 'do_gotoNextControl']
},
{
target: 'is_focused.is_ready',
cond: 'c_currentInputTextEqualOriginal',
actions: 'do_updateListOptions'
},
{
target: 'is_focused.is_inputDirty',
cond: {
type: 'c_currentInputTextEqualOriginal',
isFalse
},
actions: 'do_updateListOptions'
}
],
LOAD_FAILURE: {
actions: 'do_clearEnterQueue'
},
SEARCH_TEXT_CHANGED: [
{
target: 'is_focused.is_ready',
cond: 'c_incomingInputTextEqualOriginal',
actions: ['do_setCurrentInputText', 'do_composeSearchFilter', 'do_sendFilterToLoad']
},
{
target: 'is_focused.is_inputDirty',
cond: {
type: 'c_incomingInputTextEqualOriginal',
isFalse
},
actions: ['do_setCurrentInputText', 'do_composeSearchFilter', 'do_sendFilterToLoad']
}
],
LIST_OPTION_FOCUSED: {
actions: 'do_setFocusedListOption'
}
},
states: {
is_ready: {},
is_inputDirty: {}
}
}
}
},
is_hidden: {
on: {
SIBLING_DEPENDENCY_CHANGED: {
target: 'is_preparingToDisplay',
actions: [
'do_composeForeignRelationSelectionFilter',
'do_sendFilterToLoad',
'do_verifySelectionInForeignRelationDependency'
]
}
}
}
}
};
// TO COPY TO VISUALIZATION UNCOMMENT THIS
const ddMachine = Machine({ ...fsmConfig, context }, { guards: fsmGuards });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment