UNPKG

@shopify/hydrogen-react

Version:

React components, hooks, and utilities for creating custom Shopify storefronts

1 lines 5.15 kB
{"version":3,"file":"useMachine.mjs","sources":["../../src/useMachine.ts"],"sourcesContent":["// Inlined React binding for xstate/fsm's state machine interpreter.\n//\n// This replaces the xstate/react/fsm entrypoint, which had no official version\n// supporting both React 19 and xstate/fsm. By owning this hook, we eliminate\n// the xstate/react dependency (and its React version peer dep constraint)\n// while keeping xstate/fsm and the cart state machine definition unchanged.\n//\n// Adapted from xstate/react v3.2.1/fsm (MIT license, Stately/xstate).\n// Copyright (c) 2015 David Khourshid\nimport {\n createMachine,\n interpret,\n InterpreterStatus,\n StateMachine,\n EventObject,\n} from '@xstate/fsm';\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\n// useLayoutEffect in the browser (sync after DOM mutations, before paint),\n// useEffect on the server (where useLayoutEffect warns). The check runs once\n// at module evaluation time (not per-render). This matches the original\n// xstate/react behavior via use-isomorphic-layout-effect.\nconst useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\nfunction useConstant<T>(fn: () => T): T {\n const ref = useRef<{v: T}>();\n if (!ref.current) {\n ref.current = {v: fn()};\n }\n return ref.current.v;\n}\n\nfunction getServiceState<\n TC extends object,\n TE extends EventObject,\n TS extends {value: any; context: TC},\n>(service: StateMachine.Service<TC, TE, TS>): StateMachine.State<TC, TE, TS> {\n let currentValue!: StateMachine.State<TC, TE, TS>;\n service.subscribe((state) => (currentValue = state)).unsubscribe();\n return currentValue;\n}\n\nexport function useMachine<\n TC extends object,\n TE extends EventObject,\n TS extends {value: any; context: TC},\n>(\n stateMachine: StateMachine.Machine<TC, TE, TS>,\n options?: {actions?: StateMachine.ActionMap<TC, TE>},\n): readonly [\n StateMachine.State<TC, TE, TS>,\n StateMachine.Service<TC, TE, TS>['send'],\n StateMachine.Service<TC, TE, TS>,\n] {\n const persistedStateRef = useRef<StateMachine.State<TC, TE, TS>>();\n\n const [service, queue] = useConstant(() => {\n const eventQueue: Array<TE | TE['type']> = [];\n const svc = interpret(\n createMachine(\n stateMachine.config,\n options ? options : (stateMachine as any)._options,\n ),\n );\n const originalSend = svc.send;\n svc.send = (event: TE | TE['type']) => {\n if (svc.status === InterpreterStatus.NotStarted) {\n eventQueue.push(event);\n return;\n }\n originalSend(event);\n persistedStateRef.current = svc.state;\n };\n return [svc, eventQueue] as const;\n });\n\n // Keep action implementations in sync without re-creating the service.\n // useIsomorphicLayoutEffect ensures this runs before child effects and paint,\n // preventing a window where stale action handlers could be invoked.\n useIsomorphicLayoutEffect(() => {\n if (options) {\n (service as any)._machine._options = options;\n }\n });\n\n const getSnapshot = useCallback(() => getServiceState(service), [service]);\n\n const subscribe = useCallback(\n (handleStoreChange: () => void) => {\n const {unsubscribe} = service.subscribe(handleStoreChange);\n return unsubscribe;\n },\n [service],\n );\n\n const storeSnapshot = useSyncExternalStore(\n subscribe,\n getSnapshot,\n getSnapshot,\n );\n\n useEffect(() => {\n service.start(persistedStateRef.current as any);\n queue.forEach(service.send);\n persistedStateRef.current = service.state;\n return () => {\n service.stop();\n };\n // service and queue are stable refs from useConstant\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return [storeSnapshot, service.send, service] as const;\n}\n"],"names":[],"mappings":";;AA4BA,MAAM,4BACJ,OAAO,WAAW,cAAc,kBAAkB;AAEpD,SAAS,YAAe,IAAgB;AACtC,QAAM,MAAM,OAAA;AACZ,MAAI,CAAC,IAAI,SAAS;AAChB,QAAI,UAAU,EAAC,GAAG,GAAA,EAAG;AAAA,EACvB;AACA,SAAO,IAAI,QAAQ;AACrB;AAEA,SAAS,gBAIP,SAA2E;AAC3E,MAAI;AACJ,UAAQ,UAAU,CAAC,UAAW,eAAe,KAAM,EAAE,YAAA;AACrD,SAAO;AACT;AAEO,SAAS,WAKd,cACA,SAKA;AACA,QAAM,oBAAoB,OAAA;AAE1B,QAAM,CAAC,SAAS,KAAK,IAAI,YAAY,MAAM;AACzC,UAAM,aAAqC,CAAA;AAC3C,UAAM,MAAM;AAAA,MACV;AAAA,QACE,aAAa;AAAA,QACb,UAAU,UAAW,aAAqB;AAAA,MAAA;AAAA,IAC5C;AAEF,UAAM,eAAe,IAAI;AACzB,QAAI,OAAO,CAAC,UAA2B;AACrC,UAAI,IAAI,WAAW,kBAAkB,YAAY;AAC/C,mBAAW,KAAK,KAAK;AACrB;AAAA,MACF;AACA,mBAAa,KAAK;AAClB,wBAAkB,UAAU,IAAI;AAAA,IAClC;AACA,WAAO,CAAC,KAAK,UAAU;AAAA,EACzB,CAAC;AAKD,4BAA0B,MAAM;AAC9B,QAAI,SAAS;AACV,cAAgB,SAAS,WAAW;AAAA,IACvC;AAAA,EACF,CAAC;AAED,QAAM,cAAc,YAAY,MAAM,gBAAgB,OAAO,GAAG,CAAC,OAAO,CAAC;AAEzE,QAAM,YAAY;AAAA,IAChB,CAAC,sBAAkC;AACjC,YAAM,EAAC,YAAA,IAAe,QAAQ,UAAU,iBAAiB;AACzD,aAAO;AAAA,IACT;AAAA,IACA,CAAC,OAAO;AAAA,EAAA;AAGV,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAGF,YAAU,MAAM;AACd,YAAQ,MAAM,kBAAkB,OAAc;AAC9C,UAAM,QAAQ,QAAQ,IAAI;AAC1B,sBAAkB,UAAU,QAAQ;AACpC,WAAO,MAAM;AACX,cAAQ,KAAA;AAAA,IACV;AAAA,EAGF,GAAG,CAAA,CAAE;AAEL,SAAO,CAAC,eAAe,QAAQ,MAAM,OAAO;AAC9C;"}