Sorry, the diff of this file is not supported yet
| import React, { Component } from "react"; | ||
| import PropTypes from "prop-types"; | ||
| class Transition extends Component { | ||
| componentWillMount() { | ||
| this.props.transition(this.props.to, this.props.data); | ||
| } | ||
| render() { | ||
| return this.props.children || null; | ||
| } | ||
| } | ||
| class State extends Component { | ||
| constructor(props, context) { | ||
| super(props, context); | ||
| context.machine._registerComponentForUpdates(this); | ||
| const transition = context.machine.transition; | ||
| this.transition = (...args) => | ||
| this.getActiveState() && transition(this.context.scope, ...args); | ||
| this.Transition = ({ transition, ...props }) => ( | ||
| <Transition transition={this.transition} {...props} /> | ||
| ); | ||
| } | ||
| resolvedDomainName = () => { | ||
| return this.props.for.split(".")[0]; | ||
| }; | ||
| componentWillUnmount() { | ||
| this.context.machine._unregisterComponentForUpdates(this); | ||
| } | ||
| getActiveState = () => { | ||
| const { machine: { getState } } = this.context; | ||
| const fullName = this.props.for; // maybe pass through helpers/resolveSubDomain here | ||
| const [resolvedDomainName, stateName] = fullName.split("."); | ||
| const stateInfo = getState(resolvedDomainName); | ||
| if (!stateInfo) return null; | ||
| if (stateName !== stateInfo.state) return null; | ||
| return stateInfo; | ||
| }; | ||
| render() { | ||
| const { machine: { transition, go, update }, scope } = this.context; | ||
| const stateInfo = this.getActiveState(); | ||
| if (!stateInfo) return null; | ||
| return ( | ||
| this.props.children({ | ||
| data: stateInfo.data, | ||
| transition: this.transition, // only transition if state is active | ||
| go: (...args) => this.getActiveState() && go(scope, ...args), | ||
| globalTransition: (...args) => transition(scope, ...args), // always transition | ||
| update: (...args) => this.getActiveState() && update(scope, ...args), | ||
| Transition: this.Transition | ||
| }) || null | ||
| ); | ||
| } | ||
| } | ||
| State.contextTypes = { | ||
| scope: PropTypes.array, | ||
| machine: PropTypes.object | ||
| }; | ||
| export default State; |
| import React from "react"; | ||
| import PropTypes from "prop-types"; | ||
| import hoistStatics from "hoist-non-react-statics"; | ||
| const withMachine = Component => { | ||
| const C = (props, context) => { | ||
| const { wrappedComponentRef, ...remainingProps } = props; | ||
| // const machineProps = (({ getData }) => ({ getData }))(context.machine); | ||
| const scopedProps = context.machine.scoped(context.scope); | ||
| return ( | ||
| <Component | ||
| {...remainingProps} | ||
| ref={wrappedComponentRef} | ||
| // {...machineProps} | ||
| {...scopedProps} | ||
| /> | ||
| ); | ||
| }; | ||
| C.displayName = `withMachine(${Component.displayName || Component.name})`; | ||
| C.WrappedComponent = Component; | ||
| C.propTypes = { | ||
| wrappedComponentRef: PropTypes.func | ||
| }; | ||
| C.contextTypes = { | ||
| scope: PropTypes.array, | ||
| machine: PropTypes.object | ||
| }; | ||
| return hoistStatics(C, Component); | ||
| }; | ||
| export default withMachine; |
| import React from "react"; | ||
| import PropTypes from "prop-types"; | ||
| import hoistStatics from "hoist-non-react-statics"; | ||
| import State from "./State"; | ||
| const withState = (stateName, Component) => { | ||
| const C = props => { | ||
| const { wrappedComponentRef, ...remainingProps } = props; | ||
| return ( | ||
| <State | ||
| for={stateName} | ||
| children={stateComponentProps => ( | ||
| <Component | ||
| {...remainingProps} | ||
| {...stateComponentProps} | ||
| ref={wrappedComponentRef} | ||
| /> | ||
| )} | ||
| /> | ||
| ); | ||
| }; | ||
| C.displayName = `withState(${Component.displayName || Component.name})`; | ||
| C.WrappedComponent = Component; | ||
| C.propTypes = { | ||
| wrappedComponentRef: PropTypes.func | ||
| }; | ||
| return hoistStatics(C, Component); | ||
| }; | ||
| export default withState; |
@@ -6,3 +6,3 @@ const APP_URL = "http://localhost:3001"; | ||
| cy.visit(APP_URL); | ||
| cy.get("[data-test='list-header']").should("have.text", "My List"); | ||
| cy.get("[data-test='list-header']").should("have.text", "My List - All"); | ||
| }); | ||
@@ -9,0 +9,0 @@ it("should toggle visibility", () => { |
+2
-1
| { | ||
| "name": "machinate", | ||
| "version": "1.0.13", | ||
| "version": "1.0.14", | ||
| "description": "practical state management", | ||
@@ -33,2 +33,3 @@ "main": "build/lib.js", | ||
| "dagjs": "^0.1.3", | ||
| "hoist-non-react-statics": "^2.5.0", | ||
| "prop-types": "^15.6.0", | ||
@@ -35,0 +36,0 @@ "react": "^16.2.0" |
@@ -1,25 +0,24 @@ | ||
| import { Component } from "react"; | ||
| import React, { Component } from "react"; | ||
| import PropTypes from "prop-types"; | ||
| import State from "./State"; | ||
| class DomainState extends Component { | ||
| constructor(props) { | ||
| super(props); | ||
| this.props._config.onAdd(this); | ||
| this.transition = this.props._config.machine.transition; | ||
| constructor(props, context) { | ||
| super(props, context); | ||
| context.machine._registerComponentForUpdates(this); | ||
| } | ||
| componentWillUnmount() { | ||
| // console.log( | ||
| // "Actual state unmounting", | ||
| // this.context.scope.join("/"), | ||
| // this.props._config.domainName | ||
| // ); | ||
| this.props._config.onRemove(this); | ||
| this.context.machine._unregisterComponentForUpdates(this); | ||
| } | ||
| resolvedDomainName = () => { | ||
| const { forDomain: domainName } = this.props; | ||
| const { scope } = this.context; | ||
| const resolvedDomainName = [...scope, domainName].join("/"); | ||
| return resolvedDomainName; | ||
| }; | ||
| render() { | ||
| const { | ||
| domainName, | ||
| machine: { getState, transition, go } | ||
| } = this.props._config; | ||
| const { scope } = this.context; | ||
| const stateInfo = getState([...scope, domainName].join("/")); | ||
| const { forDomain: domainName } = this.props; | ||
| const { scope, machine: { getState } } = this.context; | ||
| const resolvedDomainName = [...scope, domainName].join("/"); | ||
| const stateInfo = getState(resolvedDomainName); | ||
| if (!stateInfo) return null; | ||
@@ -31,6 +30,11 @@ | ||
| throw new Error(`State '${stateName}' not defined in '${domainName}'`); | ||
| return this.props[stateName](stateInfo.data, { | ||
| transition: transition, | ||
| go: go | ||
| }); | ||
| return ( | ||
| <State | ||
| key={resolvedDomainName + "." + stateName} | ||
| for={resolvedDomainName + "." + stateName} | ||
| children={stateComponentProps => | ||
| this.props[stateName](stateComponentProps) | ||
| } | ||
| /> | ||
| ); | ||
| } | ||
@@ -40,5 +44,6 @@ } | ||
| DomainState.contextTypes = { | ||
| scope: PropTypes.array | ||
| scope: PropTypes.array, | ||
| machine: PropTypes.object | ||
| }; | ||
| export default DomainState; |
@@ -26,3 +26,3 @@ import React from "react"; | ||
| return <DomainState key={forDomain} {...props} />; | ||
| return <DomainState key={forDomain} forDomain={forDomain} {...props} />; | ||
| } | ||
@@ -29,0 +29,0 @@ } |
+1
-0
@@ -91,2 +91,3 @@ export const expandSchemeSyntax = scheme => | ||
| const domainInfo = scheme[toDomainName]; | ||
| if (!domainInfo) throw new Error("Invalid state: " + toState); | ||
| if (!domainInfo.deps) return true; | ||
@@ -93,0 +94,0 @@ |
+13
-1
| import Machinate from "./components/Machinate"; | ||
| import States from "./components/States"; | ||
| import State from "./components/State"; | ||
| import withState from "./components/withState"; | ||
| import withMachine from "./components/withMachine"; | ||
| import Submachine from "./components/Submachine"; | ||
@@ -7,2 +10,11 @@ | ||
| export { Machinate, States, Submachine, isTransitionable, createMachine }; | ||
| export { | ||
| Machinate, | ||
| States, | ||
| State, | ||
| Submachine, | ||
| isTransitionable, | ||
| createMachine, | ||
| withState, | ||
| withMachine | ||
| }; |
+41
-23
@@ -53,3 +53,3 @@ import React from "react"; | ||
| const transition = ( | ||
| const _transition = ( | ||
| scope, | ||
@@ -166,3 +166,3 @@ domainName, | ||
| emitter.emit("triggered-add", { ...toAdd }); | ||
| transition(prefixArray, toAdd.domain, toAdd.state, undefined, true); | ||
| _transition(prefixArray, toAdd.domain, toAdd.state, undefined, true); | ||
| }); | ||
@@ -201,10 +201,34 @@ | ||
| const _componentFullName = comp => | ||
| [...comp.props._config.scope, comp.props._config.domainName].join("/"); | ||
| const _componentFullName = comp => comp.resolvedDomainName(); | ||
| // const _componentFullName = (scope, domainName) => | ||
| // [...scope, domainName].join("/"); | ||
| const go = (scope, notation, payload) => _ => { | ||
| transition(scope, notation, payload); | ||
| }; | ||
| const transition = (scope, notation, payload) => { | ||
| const [domainName, stateName] = notation.split("."); | ||
| transition(scope, domainName, stateName, payload); | ||
| _transition(scope, domainName, stateName, payload); | ||
| }; | ||
| const update = (scope, notation, updateFn) => { | ||
| const [domainName, stateName] = notation.split("."); | ||
| const stateInfo = getState( | ||
| resolveSubdomain(state, scope, domainName).fullName | ||
| ); | ||
| if (stateInfo.state === stateName) { | ||
| go(scope, notation, updateFn(stateInfo.data))(); | ||
| } | ||
| }; | ||
| const _registerComponentForUpdates = ref => { | ||
| components.push(ref); | ||
| }; | ||
| const _unregisterComponentForUpdates = ref => { | ||
| components = components.filter(comp => comp !== ref); | ||
| }; | ||
| const componentForDomain = (scope, domainName) => { | ||
@@ -218,20 +242,3 @@ const generatedPropTypes = Object.values( | ||
| const Wrapper = props => ( | ||
| <DomainState | ||
| _config={{ | ||
| onAdd: ref => components.push(ref), | ||
| onRemove: ref => | ||
| (components = components.filter(comp => comp !== ref)), | ||
| scope, | ||
| domainName, | ||
| machine: { | ||
| transition: (...args) => transition(scope, ...args), | ||
| go: (...args) => go(scope, ...args), | ||
| log: log, | ||
| getState | ||
| } | ||
| }} | ||
| {...props} | ||
| /> | ||
| ); | ||
| const Wrapper = props => <DomainState {...props} />; | ||
| Wrapper.displayName = domainName + "[Domain]"; | ||
@@ -280,7 +287,18 @@ Wrapper.propTypes = generatedPropTypes; | ||
| setState, | ||
| transition, | ||
| go, | ||
| update, | ||
| scoped: scope => ({ | ||
| transition: (...args) => transition(scope, ...args), | ||
| go: (...args) => go(scope, ...args), | ||
| update: (...args) => update(scope, ...args) | ||
| }), | ||
| getDomainInfo, | ||
| componentForDomain, | ||
| getComponents: () => components, | ||
| _registerComponentForUpdates, | ||
| _unregisterComponentForUpdates, | ||
| registerSubmachine, | ||
@@ -287,0 +305,0 @@ removeSubmachine, |
+13
-22
@@ -61,3 +61,3 @@ import React from "react"; | ||
| }); | ||
| test("should change within that domain when transitioning", () => { | ||
| xtest("should change within that domain when transitioning", () => { | ||
| const initialState = { Auth: "LoggedOut", Display: "Visible" }; | ||
@@ -86,3 +86,3 @@ machine = createMachine(scheme, initialState); | ||
| Visible={(_, { transition }) => { | ||
| transition("Display", "Hidden"); | ||
| transition("Display.Hidden"); | ||
| }} | ||
@@ -92,2 +92,4 @@ Hidden={() => null} | ||
| ); | ||
| // TODO: Replace with a better enzyme test where context is tested | ||
| wrapper2.getElement().props._config.machine.transition("Display", "Hidden"); | ||
@@ -124,3 +126,3 @@ | ||
| machine.transition(["App1"], "Auth", "LoggedIn", "bobsmith"); | ||
| machine.transition(["App1"], "Auth.LoggedIn", "bobsmith"); | ||
@@ -133,3 +135,3 @@ expect(machine.getState()).toEqual({ | ||
| machine.transition(["App1"], "Auth", "LoggedOut"); | ||
| machine.transition(["App1"], "Auth.LoggedOut"); | ||
| expect(machine.getState()).toEqual({ | ||
@@ -168,7 +170,3 @@ Auth: { state: "LoggedOut" }, | ||
| machine.transition( | ||
| ["Item-1", "Item-2", "Item-3", "Item-4"], | ||
| "Visible", | ||
| "No" | ||
| ); | ||
| machine.transition(["Item-1", "Item-2", "Item-3", "Item-4"], "Visible.No"); | ||
@@ -185,4 +183,3 @@ expect(machine.getState()).toEqual({ | ||
| ["Item-1", "Item-2", "Item-3", "Item-4"], | ||
| "Item-3/Visible", | ||
| "No" | ||
| "Item-3/Visible.No" | ||
| ); | ||
@@ -200,4 +197,3 @@ | ||
| ["Item-1", "Item-2", "Item-3", "Item-4"], | ||
| "Item-2/Visible", | ||
| "No" | ||
| "Item-2/Visible.No" | ||
| ); | ||
@@ -215,4 +211,3 @@ | ||
| ["Item-1", "Item-2", "Item-3", "Item-4"], | ||
| "Item-1/Visible", | ||
| "No" | ||
| "Item-1/Visible.No" | ||
| ); | ||
@@ -228,7 +223,3 @@ | ||
| machine.transition( | ||
| ["Item-1", "Item-2", "Item-3", "Item-4"], | ||
| "/Visible", | ||
| "No" | ||
| ); | ||
| machine.transition(["Item-1", "Item-2", "Item-3", "Item-4"], "/Visible.No"); | ||
@@ -243,3 +234,3 @@ expect(machine.getState()).toEqual({ | ||
| machine.transition(["Item-1", "Item-2", "Item-3"], "Visible", "Yes"); | ||
| machine.transition(["Item-1", "Item-2", "Item-3"], "Visible.Yes"); | ||
@@ -253,3 +244,3 @@ expect(machine.getState()).toEqual({ | ||
| }); | ||
| machine.transition([], "/Visible", "Yes"); | ||
| machine.transition([], "/Visible.Yes"); | ||
@@ -256,0 +247,0 @@ expect(machine.getState()).toEqual({ |
+10
-10
@@ -23,20 +23,20 @@ import { createMachine, isTransitionable } from "../src/machine"; | ||
| ).toBeFalsy(); | ||
| machine.transition([], "Auth", "LoggedIn"); | ||
| machine.transition([], "Display", "CreateItem"); | ||
| machine.transition([], "Auth.LoggedIn"); | ||
| machine.transition([], "Display.CreateItem"); | ||
| expect( | ||
| isTransitionable([], scheme, machine.getState(), "ItemWizard.Step1") | ||
| ).toBeTruthy(); | ||
| machine.transition([], "Display", "Dashboard"); | ||
| machine.transition([], "Display.Dashboard"); | ||
| expect( | ||
| isTransitionable([], scheme, machine.getState(), "ItemWizard.Step1") | ||
| ).toBeFalsy(); | ||
| machine.transition([], "Display", "CreateItem"); | ||
| machine.transition([], "Display.CreateItem"); | ||
| expect( | ||
| isTransitionable([], scheme, machine.getState(), "ItemWizard.Step1") | ||
| ).toBeTruthy(); | ||
| machine.transition([], "Auth", "LoggedOut"); | ||
| machine.transition([], "Auth.LoggedOut"); | ||
| expect( | ||
| isTransitionable([], scheme, machine.getState(), "ItemWizard.Step1") | ||
| ).toBeFalsy(); | ||
| machine.transition([], "Auth", "LoggedIn"); | ||
| machine.transition([], "Auth.LoggedIn"); | ||
| expect( | ||
@@ -50,3 +50,3 @@ isTransitionable([], scheme, machine.getState(), "ItemWizard.Step1") | ||
| const machine = createMachine(scheme, initialState); | ||
| expect(() => machine.transition([], "ItemWizard", "Step1")).toThrow(); | ||
| expect(() => machine.transition([], "ItemWizard,Step1")).toThrow(); | ||
@@ -61,3 +61,3 @@ expect(machine.getState()).not.toHaveProperty("ItemWizard"); | ||
| expect(machine.getState()).not.toHaveProperty("Display"); | ||
| machine.transition([], "Auth", "LoggedIn"); | ||
| machine.transition([], "Auth.LoggedIn"); | ||
| expect(machine.getState()).toHaveProperty("Display"); | ||
@@ -71,5 +71,5 @@ }); | ||
| expect(machine.getState()).not.toHaveProperty("Display"); | ||
| machine.transition([], "Auth", "LoggedIn"); | ||
| machine.transition([], "Auth.LoggedIn"); | ||
| expect(machine.getState()).toHaveProperty("Display"); | ||
| machine.transition([], "Auth", "LoggedOut"); | ||
| machine.transition([], "Auth.LoggedOut"); | ||
| expect(machine.getState()).not.toHaveProperty("Display"); | ||
@@ -76,0 +76,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
2308405
270.42%42
7.69%26793
205.44%4
33.33%183
346.34%2
Infinity%+ Added