@actuallab/fusion-react 12.2.23 → 12.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/use-computed-state.ts","../src/use-mutable-state.ts"],"sourcesContent":["export { useComputedState } from './use-computed-state.js';\r\nexport type { UseComputedStateResult } from './use-computed-state.js';\r\nexport { useMutableState } from './use-mutable-state.js';\r\n// Re-export from @actuallab/fusion for convenience\r\nexport { UIActionTracker, uiActions, UIUpdateDelayer } from '@actuallab/fusion';\r\n","import { useEffect, useReducer, useRef } from 'react';\r\nimport {\r\n ComputedState,\r\n type ComputedStateOptions,\r\n type StateComputer,\r\n} from '@actuallab/fusion';\r\n\r\nexport interface UseComputedStateResult<T> {\r\n value: T | undefined;\r\n error: unknown;\r\n isInitial: boolean;\r\n state: ComputedState<T>;\r\n}\r\n\r\n/**\r\n * React hook wrapping Fusion's ComputedState.\r\n * Creates a ComputedState keyed on deps, subscribes to updates, and triggers re-renders.\r\n */\r\nexport function useComputedState<T>(\r\n computer: StateComputer<T>,\r\n deps: readonly unknown[],\r\n options?: ComputedStateOptions<T>\r\n): UseComputedStateResult<T> {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<ComputedState<T> | null>(null);\r\n const depsRef = useRef<readonly unknown[]>(deps);\r\n\r\n // Check if deps changed\r\n const depsChanged =\r\n deps.length !== depsRef.current.length ||\r\n deps.some((d, i) => d !== depsRef.current[i]);\r\n\r\n if (depsChanged || stateRef.current === null) {\r\n // Dispose old state\r\n stateRef.current?.dispose();\r\n depsRef.current = deps;\r\n stateRef.current = new ComputedState<T>(computer, options);\r\n }\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n // Wait for first update\r\n try {\r\n await state.whenFirstTimeUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (cancelled || state.isDisposed) return;\r\n forceRender();\r\n\r\n // Subscribe to subsequent updates\r\n while (!cancelled && !state.isDisposed) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (!cancelled && !state.isDisposed) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n state.dispose();\r\n };\r\n }, [state]);\r\n\r\n const isInitial = state.updateIndex === 0;\r\n return {\r\n value: isInitial ? undefined : state.valueOrUndefined,\r\n error: isInitial ? undefined : state.error,\r\n isInitial,\r\n state,\r\n };\r\n}\r\n","import { useEffect, useReducer, useRef } from 'react';\r\nimport { MutableState } from '@actuallab/fusion';\r\nimport type { Result } from '@actuallab/core';\r\n\r\n/**\r\n * React hook wrapping Fusion's MutableState.\r\n * Returns [value, setter, state] — re-renders on updates.\r\n */\r\nexport function useMutableState<T>(\r\n initial: T\r\n): [T, (value: Result<T> | T) => void, MutableState<T>] {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<MutableState<T> | null>(null);\r\n\r\n stateRef.current ??= new MutableState<T>(initial);\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n while (!cancelled) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (!cancelled) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }, [state]);\r\n\r\n return [state.value, v => state.set(v), state];\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA8C;AAC9C,oBAIO;AAaA,SAAS,iBACZ,UACA,MACA,SACyB;AACzB,QAAM,CAAC,EAAE,WAAW,QAAI,yBAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,eAAW,qBAAgC,IAAI;AACrD,QAAM,cAAU,qBAA2B,IAAI;AAG/C,QAAM,cACF,KAAK,WAAW,QAAQ,QAAQ,UAChC,KAAK,KAAK,CAAC,GAAG,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAEhD,MAAI,eAAe,SAAS,YAAY,MAAM;AAE1C,aAAS,SAAS,QAAQ;AAC1B,YAAQ,UAAU;AAClB,aAAS,UAAU,IAAI,4BAAiB,UAAU,OAAO;AAAA,EAC7D;AAEA,QAAM,QAAQ,SAAS;AAEvB,8BAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAE1B,UAAI;AACA,cAAM,MAAM,qBAAqB;AAAA,MACrC,QAAQ;AACJ;AAAA,MACJ;AACA,UAAI,aAAa,MAAM,WAAY;AACnC,kBAAY;AAGZ,aAAO,CAAC,aAAa,CAAC,MAAM,YAAY;AACpC,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AACA,YAAI,CAAC,aAAa,CAAC,MAAM,WAAY,aAAY;AAAA,MACrD;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AACZ,YAAM,QAAQ;AAAA,IAClB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,YAAY,MAAM,gBAAgB;AACxC,SAAO;AAAA,IACH,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC;AAAA,IACA;AAAA,EACJ;AACJ;;;AChFA,IAAAA,gBAA8C;AAC9C,IAAAC,iBAA6B;AAOtB,SAAS,gBACZ,SACoD;AACpD,QAAM,CAAC,EAAE,WAAW,QAAI,0BAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,eAAW,sBAA+B,IAAI;AAEpD,WAAS,YAAY,IAAI,4BAAgB,OAAO;AAEhD,QAAM,QAAQ,SAAS;AAEvB,+BAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAC1B,aAAO,CAAC,WAAW;AACf,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AACA,YAAI,CAAC,UAAW,aAAY;AAAA,MAChC;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AAAA,IAChB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO,CAAC,MAAM,OAAO,OAAK,MAAM,IAAI,CAAC,GAAG,KAAK;AACjD;;;AFpCA,IAAAC,iBAA4D;","names":["import_react","import_fusion","import_fusion"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/use-computed-state.ts","../src/use-mutable-state.ts"],"sourcesContent":["export { useComputedState } from './use-computed-state.js';\r\nexport type { UseComputedStateResult } from './use-computed-state.js';\r\nexport { useMutableState } from './use-mutable-state.js';\r\n// Re-export from @actuallab/fusion for convenience\r\nexport { UIActionTracker, uiActions, UIUpdateDelayer } from '@actuallab/fusion';\r\n","import { useEffect, useReducer, useRef } from 'react';\r\nimport {\r\n ComputedState,\r\n type ComputedStateOptions,\r\n type StateComputer,\r\n} from '@actuallab/fusion';\r\n\r\nexport interface UseComputedStateResult<T> {\r\n value: T | undefined;\r\n error: unknown;\r\n isInitial: boolean;\r\n state: ComputedState<T>;\r\n}\r\n\r\n/**\r\n * React hook wrapping Fusion's ComputedState.\r\n * Creates a ComputedState keyed on deps, subscribes to updates, and triggers re-renders.\r\n */\r\nexport function useComputedState<T>(\r\n computer: StateComputer<T>,\r\n deps: readonly unknown[],\r\n options?: ComputedStateOptions<T>\r\n): UseComputedStateResult<T> {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<ComputedState<T> | null>(null);\r\n const depsRef = useRef<readonly unknown[]>(deps);\r\n\r\n // Check if deps changed\r\n const depsChanged =\r\n deps.length !== depsRef.current.length ||\r\n deps.some((d, i) => d !== depsRef.current[i]);\r\n\r\n if (depsChanged || stateRef.current === null) {\r\n // Dispose old state\r\n stateRef.current?.dispose();\r\n depsRef.current = deps;\r\n stateRef.current = new ComputedState<T>(computer, options);\r\n }\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n // Wait for first update\r\n try {\r\n await state.whenFirstTimeUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (cancelled || state.isDisposed) return;\r\n forceRender();\r\n\r\n // Subscribe to subsequent updates\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\r\n while (!cancelled && !state.isDisposed) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\r\n if (!cancelled && !state.isDisposed) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n state.dispose();\r\n };\r\n }, [state]);\r\n\r\n const isInitial = state.updateIndex === 0;\r\n return {\r\n value: isInitial ? undefined : state.valueOrUndefined,\r\n error: isInitial ? undefined : state.error,\r\n isInitial,\r\n state,\r\n };\r\n}\r\n","import { useEffect, useReducer, useRef } from 'react';\r\nimport { MutableState } from '@actuallab/fusion';\r\nimport type { Result } from '@actuallab/core';\r\n\r\n/**\r\n * React hook wrapping Fusion's MutableState.\r\n * Returns [value, setter, state] — re-renders on updates.\r\n */\r\nexport function useMutableState<T>(\r\n initial: T\r\n): [T, (value: Result<T> | T) => void, MutableState<T>] {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<MutableState<T> | null>(null);\r\n\r\n stateRef.current ??= new MutableState<T>(initial);\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n while (!cancelled) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\r\n if (!cancelled) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }, [state]);\r\n\r\n return [state.value, v => state.set(v), state];\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA8C;AAC9C,oBAIO;AAaA,SAAS,iBACZ,UACA,MACA,SACyB;AACzB,QAAM,CAAC,EAAE,WAAW,QAAI,yBAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,eAAW,qBAAgC,IAAI;AACrD,QAAM,cAAU,qBAA2B,IAAI;AAG/C,QAAM,cACF,KAAK,WAAW,QAAQ,QAAQ,UAChC,KAAK,KAAK,CAAC,GAAG,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAEhD,MAAI,eAAe,SAAS,YAAY,MAAM;AAE1C,aAAS,SAAS,QAAQ;AAC1B,YAAQ,UAAU;AAClB,aAAS,UAAU,IAAI,4BAAiB,UAAU,OAAO;AAAA,EAC7D;AAEA,QAAM,QAAQ,SAAS;AAEvB,8BAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAE1B,UAAI;AACA,cAAM,MAAM,qBAAqB;AAAA,MACrC,QAAQ;AACJ;AAAA,MACJ;AACA,UAAI,aAAa,MAAM,WAAY;AACnC,kBAAY;AAIZ,aAAO,CAAC,aAAa,CAAC,MAAM,YAAY;AACpC,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AAEA,YAAI,CAAC,aAAa,CAAC,MAAM,WAAY,aAAY;AAAA,MACrD;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AACZ,YAAM,QAAQ;AAAA,IAClB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,YAAY,MAAM,gBAAgB;AACxC,SAAO;AAAA,IACH,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC;AAAA,IACA;AAAA,EACJ;AACJ;;;AClFA,IAAAA,gBAA8C;AAC9C,IAAAC,iBAA6B;AAOtB,SAAS,gBACZ,SACoD;AACpD,QAAM,CAAC,EAAE,WAAW,QAAI,0BAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,eAAW,sBAA+B,IAAI;AAEpD,WAAS,YAAY,IAAI,4BAAgB,OAAO;AAEhD,QAAM,QAAQ,SAAS;AAEvB,+BAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAC1B,aAAO,CAAC,WAAW;AACf,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AAEA,YAAI,CAAC,UAAW,aAAY;AAAA,MAChC;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AAAA,IAChB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO,CAAC,MAAM,OAAO,OAAK,MAAM,IAAI,CAAC,GAAG,KAAK;AACjD;;;AFrCA,IAAAC,iBAA4D;","names":["import_react","import_fusion","import_fusion"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/use-computed-state.ts","../src/use-mutable-state.ts","../src/index.ts"],"sourcesContent":["import { useEffect, useReducer, useRef } from 'react';\r\nimport {\r\n ComputedState,\r\n type ComputedStateOptions,\r\n type StateComputer,\r\n} from '@actuallab/fusion';\r\n\r\nexport interface UseComputedStateResult<T> {\r\n value: T | undefined;\r\n error: unknown;\r\n isInitial: boolean;\r\n state: ComputedState<T>;\r\n}\r\n\r\n/**\r\n * React hook wrapping Fusion's ComputedState.\r\n * Creates a ComputedState keyed on deps, subscribes to updates, and triggers re-renders.\r\n */\r\nexport function useComputedState<T>(\r\n computer: StateComputer<T>,\r\n deps: readonly unknown[],\r\n options?: ComputedStateOptions<T>\r\n): UseComputedStateResult<T> {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<ComputedState<T> | null>(null);\r\n const depsRef = useRef<readonly unknown[]>(deps);\r\n\r\n // Check if deps changed\r\n const depsChanged =\r\n deps.length !== depsRef.current.length ||\r\n deps.some((d, i) => d !== depsRef.current[i]);\r\n\r\n if (depsChanged || stateRef.current === null) {\r\n // Dispose old state\r\n stateRef.current?.dispose();\r\n depsRef.current = deps;\r\n stateRef.current = new ComputedState<T>(computer, options);\r\n }\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n // Wait for first update\r\n try {\r\n await state.whenFirstTimeUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (cancelled || state.isDisposed) return;\r\n forceRender();\r\n\r\n // Subscribe to subsequent updates\r\n while (!cancelled && !state.isDisposed) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (!cancelled && !state.isDisposed) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n state.dispose();\r\n };\r\n }, [state]);\r\n\r\n const isInitial = state.updateIndex === 0;\r\n return {\r\n value: isInitial ? undefined : state.valueOrUndefined,\r\n error: isInitial ? undefined : state.error,\r\n isInitial,\r\n state,\r\n };\r\n}\r\n","import { useEffect, useReducer, useRef } from 'react';\r\nimport { MutableState } from '@actuallab/fusion';\r\nimport type { Result } from '@actuallab/core';\r\n\r\n/**\r\n * React hook wrapping Fusion's MutableState.\r\n * Returns [value, setter, state] — re-renders on updates.\r\n */\r\nexport function useMutableState<T>(\r\n initial: T\r\n): [T, (value: Result<T> | T) => void, MutableState<T>] {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<MutableState<T> | null>(null);\r\n\r\n stateRef.current ??= new MutableState<T>(initial);\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n while (!cancelled) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (!cancelled) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }, [state]);\r\n\r\n return [state.value, v => state.set(v), state];\r\n}\r\n","export { useComputedState } from './use-computed-state.js';\r\nexport type { UseComputedStateResult } from './use-computed-state.js';\r\nexport { useMutableState } from './use-mutable-state.js';\r\n// Re-export from @actuallab/fusion for convenience\r\nexport { UIActionTracker, uiActions, UIUpdateDelayer } from '@actuallab/fusion';\r\n"],"mappings":";AAAA,SAAS,WAAW,YAAY,cAAc;AAC9C;AAAA,EACI;AAAA,OAGG;AAaA,SAAS,iBACZ,UACA,MACA,SACyB;AACzB,QAAM,CAAC,EAAE,WAAW,IAAI,WAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,WAAW,OAAgC,IAAI;AACrD,QAAM,UAAU,OAA2B,IAAI;AAG/C,QAAM,cACF,KAAK,WAAW,QAAQ,QAAQ,UAChC,KAAK,KAAK,CAAC,GAAG,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAEhD,MAAI,eAAe,SAAS,YAAY,MAAM;AAE1C,aAAS,SAAS,QAAQ;AAC1B,YAAQ,UAAU;AAClB,aAAS,UAAU,IAAI,cAAiB,UAAU,OAAO;AAAA,EAC7D;AAEA,QAAM,QAAQ,SAAS;AAEvB,YAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAE1B,UAAI;AACA,cAAM,MAAM,qBAAqB;AAAA,MACrC,QAAQ;AACJ;AAAA,MACJ;AACA,UAAI,aAAa,MAAM,WAAY;AACnC,kBAAY;AAGZ,aAAO,CAAC,aAAa,CAAC,MAAM,YAAY;AACpC,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AACA,YAAI,CAAC,aAAa,CAAC,MAAM,WAAY,aAAY;AAAA,MACrD;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AACZ,YAAM,QAAQ;AAAA,IAClB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,YAAY,MAAM,gBAAgB;AACxC,SAAO;AAAA,IACH,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC;AAAA,IACA;AAAA,EACJ;AACJ;;;AChFA,SAAS,aAAAA,YAAW,cAAAC,aAAY,UAAAC,eAAc;AAC9C,SAAS,oBAAoB;AAOtB,SAAS,gBACZ,SACoD;AACpD,QAAM,CAAC,EAAE,WAAW,IAAID,YAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,WAAWC,QAA+B,IAAI;AAEpD,WAAS,YAAY,IAAI,aAAgB,OAAO;AAEhD,QAAM,QAAQ,SAAS;AAEvB,EAAAF,WAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAC1B,aAAO,CAAC,WAAW;AACf,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AACA,YAAI,CAAC,UAAW,aAAY;AAAA,MAChC;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AAAA,IAChB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO,CAAC,MAAM,OAAO,OAAK,MAAM,IAAI,CAAC,GAAG,KAAK;AACjD;;;ACpCA,SAAS,iBAAiB,WAAW,uBAAuB;","names":["useEffect","useReducer","useRef"]}
1
+ {"version":3,"sources":["../src/use-computed-state.ts","../src/use-mutable-state.ts","../src/index.ts"],"sourcesContent":["import { useEffect, useReducer, useRef } from 'react';\r\nimport {\r\n ComputedState,\r\n type ComputedStateOptions,\r\n type StateComputer,\r\n} from '@actuallab/fusion';\r\n\r\nexport interface UseComputedStateResult<T> {\r\n value: T | undefined;\r\n error: unknown;\r\n isInitial: boolean;\r\n state: ComputedState<T>;\r\n}\r\n\r\n/**\r\n * React hook wrapping Fusion's ComputedState.\r\n * Creates a ComputedState keyed on deps, subscribes to updates, and triggers re-renders.\r\n */\r\nexport function useComputedState<T>(\r\n computer: StateComputer<T>,\r\n deps: readonly unknown[],\r\n options?: ComputedStateOptions<T>\r\n): UseComputedStateResult<T> {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<ComputedState<T> | null>(null);\r\n const depsRef = useRef<readonly unknown[]>(deps);\r\n\r\n // Check if deps changed\r\n const depsChanged =\r\n deps.length !== depsRef.current.length ||\r\n deps.some((d, i) => d !== depsRef.current[i]);\r\n\r\n if (depsChanged || stateRef.current === null) {\r\n // Dispose old state\r\n stateRef.current?.dispose();\r\n depsRef.current = deps;\r\n stateRef.current = new ComputedState<T>(computer, options);\r\n }\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n // Wait for first update\r\n try {\r\n await state.whenFirstTimeUpdated();\r\n } catch {\r\n return;\r\n }\r\n if (cancelled || state.isDisposed) return;\r\n forceRender();\r\n\r\n // Subscribe to subsequent updates\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\r\n while (!cancelled && !state.isDisposed) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\r\n if (!cancelled && !state.isDisposed) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n state.dispose();\r\n };\r\n }, [state]);\r\n\r\n const isInitial = state.updateIndex === 0;\r\n return {\r\n value: isInitial ? undefined : state.valueOrUndefined,\r\n error: isInitial ? undefined : state.error,\r\n isInitial,\r\n state,\r\n };\r\n}\r\n","import { useEffect, useReducer, useRef } from 'react';\r\nimport { MutableState } from '@actuallab/fusion';\r\nimport type { Result } from '@actuallab/core';\r\n\r\n/**\r\n * React hook wrapping Fusion's MutableState.\r\n * Returns [value, setter, state] — re-renders on updates.\r\n */\r\nexport function useMutableState<T>(\r\n initial: T\r\n): [T, (value: Result<T> | T) => void, MutableState<T>] {\r\n const [, forceRender] = useReducer(c => c + 1, 0);\r\n const stateRef = useRef<MutableState<T> | null>(null);\r\n\r\n stateRef.current ??= new MutableState<T>(initial);\r\n\r\n const state = stateRef.current;\r\n\r\n useEffect(() => {\r\n let cancelled = false;\r\n\r\n const subscribe = async () => {\r\n while (!cancelled) {\r\n try {\r\n await state.whenUpdated();\r\n } catch {\r\n return;\r\n }\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\r\n if (!cancelled) forceRender();\r\n }\r\n };\r\n\r\n void subscribe();\r\n\r\n return () => {\r\n cancelled = true;\r\n };\r\n }, [state]);\r\n\r\n return [state.value, v => state.set(v), state];\r\n}\r\n","export { useComputedState } from './use-computed-state.js';\r\nexport type { UseComputedStateResult } from './use-computed-state.js';\r\nexport { useMutableState } from './use-mutable-state.js';\r\n// Re-export from @actuallab/fusion for convenience\r\nexport { UIActionTracker, uiActions, UIUpdateDelayer } from '@actuallab/fusion';\r\n"],"mappings":";AAAA,SAAS,WAAW,YAAY,cAAc;AAC9C;AAAA,EACI;AAAA,OAGG;AAaA,SAAS,iBACZ,UACA,MACA,SACyB;AACzB,QAAM,CAAC,EAAE,WAAW,IAAI,WAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,WAAW,OAAgC,IAAI;AACrD,QAAM,UAAU,OAA2B,IAAI;AAG/C,QAAM,cACF,KAAK,WAAW,QAAQ,QAAQ,UAChC,KAAK,KAAK,CAAC,GAAG,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAEhD,MAAI,eAAe,SAAS,YAAY,MAAM;AAE1C,aAAS,SAAS,QAAQ;AAC1B,YAAQ,UAAU;AAClB,aAAS,UAAU,IAAI,cAAiB,UAAU,OAAO;AAAA,EAC7D;AAEA,QAAM,QAAQ,SAAS;AAEvB,YAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAE1B,UAAI;AACA,cAAM,MAAM,qBAAqB;AAAA,MACrC,QAAQ;AACJ;AAAA,MACJ;AACA,UAAI,aAAa,MAAM,WAAY;AACnC,kBAAY;AAIZ,aAAO,CAAC,aAAa,CAAC,MAAM,YAAY;AACpC,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AAEA,YAAI,CAAC,aAAa,CAAC,MAAM,WAAY,aAAY;AAAA,MACrD;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AACZ,YAAM,QAAQ;AAAA,IAClB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,YAAY,MAAM,gBAAgB;AACxC,SAAO;AAAA,IACH,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC,OAAO,YAAY,SAAY,MAAM;AAAA,IACrC;AAAA,IACA;AAAA,EACJ;AACJ;;;AClFA,SAAS,aAAAA,YAAW,cAAAC,aAAY,UAAAC,eAAc;AAC9C,SAAS,oBAAoB;AAOtB,SAAS,gBACZ,SACoD;AACpD,QAAM,CAAC,EAAE,WAAW,IAAID,YAAW,OAAK,IAAI,GAAG,CAAC;AAChD,QAAM,WAAWC,QAA+B,IAAI;AAEpD,WAAS,YAAY,IAAI,aAAgB,OAAO;AAEhD,QAAM,QAAQ,SAAS;AAEvB,EAAAF,WAAU,MAAM;AACZ,QAAI,YAAY;AAEhB,UAAM,YAAY,YAAY;AAC1B,aAAO,CAAC,WAAW;AACf,YAAI;AACA,gBAAM,MAAM,YAAY;AAAA,QAC5B,QAAQ;AACJ;AAAA,QACJ;AAEA,YAAI,CAAC,UAAW,aAAY;AAAA,MAChC;AAAA,IACJ;AAEA,SAAK,UAAU;AAEf,WAAO,MAAM;AACT,kBAAY;AAAA,IAChB;AAAA,EACJ,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO,CAAC,MAAM,OAAO,OAAK,MAAM,IAAI,CAAC,GAAG,KAAK;AACjD;;;ACrCA,SAAS,iBAAiB,WAAW,uBAAuB;","names":["useEffect","useReducer","useRef"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuallab/fusion-react",
3
- "version": "12.2.23",
3
+ "version": "12.3.4",
4
4
  "description": "React integration for Fusion - hooks and UI action tracking",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -26,8 +26,8 @@
26
26
  "clean": "rm -rf dist"
27
27
  },
28
28
  "dependencies": {
29
- "@actuallab/core": "12.2.23",
30
- "@actuallab/fusion": "12.2.23"
29
+ "@actuallab/core": "12.3.4",
30
+ "@actuallab/fusion": "12.3.4"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "react": "^19.0.0"