@legendapp/state 2.2.0-next.7 → 2.2.0-next.71

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.
Files changed (298) hide show
  1. package/README.md +4 -2
  2. package/babel.js.map +1 -1
  3. package/config/enable$get.d.ts +8 -0
  4. package/config/enable$get.js +24 -0
  5. package/config/enable$get.js.map +1 -0
  6. package/config/enable$get.mjs +21 -0
  7. package/config/enable$get.mjs.map +1 -0
  8. package/config/enableReactComponents.js.map +1 -1
  9. package/config/enableReactComponents.mjs.map +1 -1
  10. package/config/enableReactNativeComponents.js.map +1 -1
  11. package/config/enableReactNativeComponents.mjs.map +1 -1
  12. package/config/enableReactTracking.d.ts +0 -9
  13. package/config/enableReactTracking.js.map +1 -1
  14. package/config/enableReactTracking.mjs.map +1 -1
  15. package/config/enableReactUse.d.ts +1 -1
  16. package/config/enableReactUse.js +1 -0
  17. package/config/enableReactUse.js.map +1 -1
  18. package/config/enableReactUse.mjs +1 -0
  19. package/config/enableReactUse.mjs.map +1 -1
  20. package/config/enable_peek.d.ts +8 -0
  21. package/config/{enableDirectPeek.js → enable_peek.js} +6 -3
  22. package/config/enable_peek.js.map +1 -0
  23. package/config/{enableDirectPeek.mjs → enable_peek.mjs} +5 -3
  24. package/config/enable_peek.mjs.map +1 -0
  25. package/helpers/fetch.d.ts +4 -3
  26. package/helpers/fetch.js.map +1 -1
  27. package/helpers/fetch.mjs.map +1 -1
  28. package/helpers/pageHash.js.map +1 -1
  29. package/helpers/pageHash.mjs.map +1 -1
  30. package/helpers/pageHashParams.js.map +1 -1
  31. package/helpers/pageHashParams.mjs.map +1 -1
  32. package/helpers/time.d.ts +2 -2
  33. package/helpers/time.js.map +1 -1
  34. package/helpers/time.mjs.map +1 -1
  35. package/history.js +2 -2
  36. package/history.js.map +1 -1
  37. package/history.mjs +3 -3
  38. package/history.mjs.map +1 -1
  39. package/index.d.ts +30 -9
  40. package/index.js +877 -661
  41. package/index.js.map +1 -1
  42. package/index.mjs +874 -658
  43. package/index.mjs.map +1 -1
  44. package/package.json +22 -25
  45. package/persist-plugins/async-storage.d.ts +3 -3
  46. package/persist-plugins/async-storage.js +8 -7
  47. package/persist-plugins/async-storage.js.map +1 -1
  48. package/persist-plugins/async-storage.mjs +9 -8
  49. package/persist-plugins/async-storage.mjs.map +1 -1
  50. package/persist-plugins/fetch.js.map +1 -1
  51. package/persist-plugins/fetch.mjs.map +1 -1
  52. package/persist-plugins/firebase.d.ts +1 -1
  53. package/persist-plugins/firebase.js +12 -11
  54. package/persist-plugins/firebase.js.map +1 -1
  55. package/persist-plugins/firebase.mjs +13 -12
  56. package/persist-plugins/firebase.mjs.map +1 -1
  57. package/persist-plugins/indexeddb.d.ts +10 -10
  58. package/persist-plugins/indexeddb.js +2 -2
  59. package/persist-plugins/indexeddb.js.map +1 -1
  60. package/persist-plugins/indexeddb.mjs +2 -2
  61. package/persist-plugins/indexeddb.mjs.map +1 -1
  62. package/persist-plugins/local-storage.d.ts +3 -4
  63. package/persist-plugins/local-storage.js +19 -7
  64. package/persist-plugins/local-storage.js.map +1 -1
  65. package/persist-plugins/local-storage.mjs +20 -9
  66. package/persist-plugins/local-storage.mjs.map +1 -1
  67. package/persist-plugins/mmkv.d.ts +8 -8
  68. package/persist-plugins/mmkv.js +5 -4
  69. package/persist-plugins/mmkv.js.map +1 -1
  70. package/persist-plugins/mmkv.mjs +6 -5
  71. package/persist-plugins/mmkv.mjs.map +1 -1
  72. package/persist-plugins/query.js.map +1 -1
  73. package/persist-plugins/query.mjs.map +1 -1
  74. package/persist.d.ts +2 -14
  75. package/persist.js +1250 -268
  76. package/persist.js.map +1 -1
  77. package/persist.mjs +1250 -269
  78. package/persist.mjs.map +1 -1
  79. package/react-hooks/createObservableHook.js +1 -1
  80. package/react-hooks/createObservableHook.js.map +1 -1
  81. package/react-hooks/createObservableHook.mjs +1 -1
  82. package/react-hooks/createObservableHook.mjs.map +1 -1
  83. package/react-hooks/useFetch.d.ts +4 -3
  84. package/react-hooks/useFetch.js.map +1 -1
  85. package/react-hooks/useFetch.mjs.map +1 -1
  86. package/react-hooks/useHover.js.map +1 -1
  87. package/react-hooks/useHover.mjs.map +1 -1
  88. package/react-hooks/useMeasure.js.map +1 -1
  89. package/react-hooks/useMeasure.mjs.map +1 -1
  90. package/react-hooks/useObservableNextRouter.js.map +1 -1
  91. package/react-hooks/useObservableNextRouter.mjs.map +1 -1
  92. package/react-hooks/useObservableQuery.js.map +1 -1
  93. package/react-hooks/useObservableQuery.mjs.map +1 -1
  94. package/react-hooks/usePersistedObservable.d.ts +5 -3
  95. package/react-hooks/usePersistedObservable.js +5 -2
  96. package/react-hooks/usePersistedObservable.js.map +1 -1
  97. package/react-hooks/usePersistedObservable.mjs +5 -2
  98. package/react-hooks/usePersistedObservable.mjs.map +1 -1
  99. package/react.js +61 -75
  100. package/react.js.map +1 -1
  101. package/react.mjs +61 -75
  102. package/react.mjs.map +1 -1
  103. package/src/ObservableObject.ts +1184 -0
  104. package/src/ObservablePrimitive.ts +62 -0
  105. package/src/babel/index.ts +70 -0
  106. package/src/batching.ts +372 -0
  107. package/src/computed.ts +16 -0
  108. package/src/config/enable$get.ts +30 -0
  109. package/src/config/enableReactComponents.ts +26 -0
  110. package/src/config/enableReactNativeComponents.ts +102 -0
  111. package/src/config/enableReactTracking.ts +60 -0
  112. package/src/config/enableReactUse.ts +23 -0
  113. package/src/config/enable_peek.ts +31 -0
  114. package/src/config.ts +47 -0
  115. package/src/createObservable.ts +46 -0
  116. package/src/event.ts +26 -0
  117. package/src/globals.ts +224 -0
  118. package/src/helpers/fetch.ts +26 -0
  119. package/src/helpers/pageHash.ts +41 -0
  120. package/src/helpers/pageHashParams.ts +55 -0
  121. package/src/helpers/time.ts +30 -0
  122. package/src/helpers.ts +221 -0
  123. package/src/history/trackHistory.ts +29 -0
  124. package/src/is.ts +56 -0
  125. package/src/linked.ts +6 -0
  126. package/src/observable.ts +32 -0
  127. package/src/observableInterfaces.ts +165 -0
  128. package/src/observableTypes.ts +221 -0
  129. package/src/observe.ts +89 -0
  130. package/src/onChange.ts +136 -0
  131. package/src/persist/configureObservablePersistence.ts +7 -0
  132. package/src/persist/fieldTransformer.ts +149 -0
  133. package/src/persist/observablePersistRemoteFunctionsAdapter.ts +39 -0
  134. package/src/persist/persistObservable.ts +1029 -0
  135. package/src/persist-plugins/async-storage.ts +102 -0
  136. package/src/persist-plugins/fetch.ts +33 -0
  137. package/src/persist-plugins/firebase.ts +1050 -0
  138. package/src/persist-plugins/indexeddb.ts +433 -0
  139. package/src/persist-plugins/local-storage.ts +90 -0
  140. package/src/persist-plugins/mmkv.ts +90 -0
  141. package/src/persist-plugins/query.ts +133 -0
  142. package/src/persistTypes.ts +226 -0
  143. package/src/proxy.ts +28 -0
  144. package/src/react/Computed.tsx +7 -0
  145. package/src/react/For.tsx +116 -0
  146. package/src/react/Memo.tsx +4 -0
  147. package/src/react/Reactive.tsx +53 -0
  148. package/src/react/Show.tsx +33 -0
  149. package/src/react/Switch.tsx +43 -0
  150. package/src/react/react-globals.ts +3 -0
  151. package/src/react/{reactInterfaces.d.ts → reactInterfaces.ts} +15 -7
  152. package/src/react/reactive-observer.tsx +210 -0
  153. package/src/react/useComputed.ts +36 -0
  154. package/src/react/useEffectOnce.ts +41 -0
  155. package/src/react/useIsMounted.ts +16 -0
  156. package/src/react/useMount.ts +15 -0
  157. package/src/react/useObservable.ts +24 -0
  158. package/src/react/useObservableReducer.ts +52 -0
  159. package/src/react/useObservableState.ts +30 -0
  160. package/src/react/useObserve.ts +54 -0
  161. package/src/react/useObserveEffect.ts +40 -0
  162. package/src/react/usePauseProvider.tsx +13 -0
  163. package/src/react/useSelector.ts +167 -0
  164. package/src/react/useUnmount.ts +8 -0
  165. package/src/react/useWhen.ts +9 -0
  166. package/src/react-hooks/createObservableHook.ts +53 -0
  167. package/src/react-hooks/useFetch.ts +16 -0
  168. package/src/react-hooks/useHover.ts +40 -0
  169. package/src/react-hooks/useMeasure.ts +48 -0
  170. package/src/react-hooks/useObservableNextRouter.ts +137 -0
  171. package/src/react-hooks/useObservableQuery.ts +205 -0
  172. package/src/react-hooks/usePersistedObservable.ts +24 -0
  173. package/src/retry.ts +69 -0
  174. package/src/setupTracking.ts +26 -0
  175. package/src/sync/activateSyncedNode.ts +146 -0
  176. package/src/sync/configureObservableSync.ts +7 -0
  177. package/src/sync/syncHelpers.ts +15 -0
  178. package/src/sync/syncObservable.ts +989 -0
  179. package/src/sync/syncObservableAdapter.ts +30 -0
  180. package/src/sync/synced.ts +20 -0
  181. package/src/sync-plugins/fetch.ts +42 -0
  182. package/src/syncTypes.ts +163 -0
  183. package/src/trace/traceHelpers.ts +11 -0
  184. package/src/trace/useTraceListeners.ts +34 -0
  185. package/src/trace/useTraceUpdates.ts +24 -0
  186. package/src/trace/useVerifyNotTracking.ts +33 -0
  187. package/src/trace/useVerifyOneRender.ts +10 -0
  188. package/src/trackSelector.ts +52 -0
  189. package/src/tracking.ts +43 -0
  190. package/src/types/babel.d.ts +12 -0
  191. package/src/when.ts +70 -0
  192. package/sync-plugins/fetch.d.ts +11 -0
  193. package/sync-plugins/fetch.js +24 -0
  194. package/sync-plugins/fetch.js.map +1 -0
  195. package/sync-plugins/fetch.mjs +22 -0
  196. package/sync-plugins/fetch.mjs.map +1 -0
  197. package/sync.d.ts +8 -0
  198. package/sync.js +919 -0
  199. package/sync.js.map +1 -0
  200. package/sync.mjs +912 -0
  201. package/sync.mjs.map +1 -0
  202. package/trace.js +13 -10
  203. package/trace.js.map +1 -1
  204. package/trace.mjs +11 -8
  205. package/trace.mjs.map +1 -1
  206. package/types/babel.d.ts +3 -3
  207. package/config/enableDirectAccess.d.ts +0 -7
  208. package/config/enableDirectAccess.js +0 -25
  209. package/config/enableDirectAccess.js.map +0 -1
  210. package/config/enableDirectAccess.mjs +0 -23
  211. package/config/enableDirectAccess.mjs.map +0 -1
  212. package/config/enableDirectPeek.d.ts +0 -7
  213. package/config/enableDirectPeek.js.map +0 -1
  214. package/config/enableDirectPeek.mjs.map +0 -1
  215. package/config/enableReactDirectRender.d.ts +0 -2
  216. package/config/enableReactDirectRender.js +0 -78
  217. package/config/enableReactDirectRender.js.map +0 -1
  218. package/config/enableReactDirectRender.mjs +0 -75
  219. package/config/enableReactDirectRender.mjs.map +0 -1
  220. package/src/ObservableObject.d.ts +0 -14
  221. package/src/ObservablePrimitive.d.ts +0 -7
  222. package/src/babel/index.d.ts +0 -17
  223. package/src/batching.d.ts +0 -6
  224. package/src/computed.d.ts +0 -4
  225. package/src/config/enableDirectAccess.d.ts +0 -7
  226. package/src/config/enableDirectPeek.d.ts +0 -7
  227. package/src/config/enableReactComponents.d.ts +0 -7
  228. package/src/config/enableReactDirectRender.d.ts +0 -2
  229. package/src/config/enableReactNativeComponents.d.ts +0 -20
  230. package/src/config/enableReactTracking.d.ts +0 -15
  231. package/src/config/enableReactUse.d.ts +0 -7
  232. package/src/config.d.ts +0 -8
  233. package/src/createObservable.d.ts +0 -2
  234. package/src/event.d.ts +0 -2
  235. package/src/globals.d.ts +0 -32
  236. package/src/helpers/fetch.d.ts +0 -6
  237. package/src/helpers/pageHash.d.ts +0 -7
  238. package/src/helpers/pageHashParams.d.ts +0 -7
  239. package/src/helpers/time.d.ts +0 -3
  240. package/src/helpers.d.ts +0 -13
  241. package/src/history/trackHistory.d.ts +0 -4
  242. package/src/is.d.ts +0 -10
  243. package/src/observable.d.ts +0 -16
  244. package/src/observableInterfaces.d.ts +0 -456
  245. package/src/observe.d.ts +0 -6
  246. package/src/onChange.d.ts +0 -7
  247. package/src/persist/configureObservablePersistence.d.ts +0 -3
  248. package/src/persist/fieldTransformer.d.ts +0 -8
  249. package/src/persist/observablePersistRemoteFunctionsAdapter.d.ts +0 -2
  250. package/src/persist/persistActivateNode.d.ts +0 -1
  251. package/src/persist/persistHelpers.d.ts +0 -1
  252. package/src/persist/persistObservable.d.ts +0 -25
  253. package/src/persist-plugins/async-storage.d.ts +0 -14
  254. package/src/persist-plugins/fetch.d.ts +0 -10
  255. package/src/persist-plugins/firebase.d.ts +0 -51
  256. package/src/persist-plugins/indexeddb.d.ts +0 -25
  257. package/src/persist-plugins/local-storage.d.ts +0 -21
  258. package/src/persist-plugins/mmkv.d.ts +0 -14
  259. package/src/persist-plugins/query.d.ts +0 -18
  260. package/src/proxy.d.ts +0 -5
  261. package/src/react/Computed.d.ts +0 -5
  262. package/src/react/For.d.ts +0 -15
  263. package/src/react/Memo.d.ts +0 -3
  264. package/src/react/Reactive.d.ts +0 -9
  265. package/src/react/Show.d.ts +0 -18
  266. package/src/react/Switch.d.ts +0 -14
  267. package/src/react/react-globals.d.ts +0 -3
  268. package/src/react/reactive-observer.d.ts +0 -14
  269. package/src/react/useComputed.d.ts +0 -5
  270. package/src/react/useEffectOnce.d.ts +0 -1
  271. package/src/react/useIsMounted.d.ts +0 -2
  272. package/src/react/useMount.d.ts +0 -2
  273. package/src/react/useObservable.d.ts +0 -9
  274. package/src/react/useObservableReducer.d.ts +0 -7
  275. package/src/react/useObservableState.d.ts +0 -2
  276. package/src/react/useObserve.d.ts +0 -4
  277. package/src/react/useObserveEffect.d.ts +0 -4
  278. package/src/react/usePauseProvider.d.ts +0 -8
  279. package/src/react/useSelector.d.ts +0 -3
  280. package/src/react/useUnmount.d.ts +0 -2
  281. package/src/react/useWhen.d.ts +0 -3
  282. package/src/react-hooks/createObservableHook.d.ts +0 -2
  283. package/src/react-hooks/useFetch.d.ts +0 -6
  284. package/src/react-hooks/useHover.d.ts +0 -3
  285. package/src/react-hooks/useMeasure.d.ts +0 -6
  286. package/src/react-hooks/useObservableNextRouter.d.ts +0 -33
  287. package/src/react-hooks/useObservableQuery.d.ts +0 -6
  288. package/src/react-hooks/usePersistedObservable.d.ts +0 -11
  289. package/src/retry.d.ts +0 -9
  290. package/src/setupTracking.d.ts +0 -2
  291. package/src/trace/traceHelpers.d.ts +0 -2
  292. package/src/trace/useTraceListeners.d.ts +0 -1
  293. package/src/trace/useTraceUpdates.d.ts +0 -1
  294. package/src/trace/useVerifyNotTracking.d.ts +0 -1
  295. package/src/trace/useVerifyOneRender.d.ts +0 -1
  296. package/src/trackSelector.d.ts +0 -7
  297. package/src/tracking.d.ts +0 -13
  298. package/src/when.d.ts +0 -3
@@ -0,0 +1,60 @@
1
+ import {
2
+ type GetOptions,
3
+ configureLegendState,
4
+ internal,
5
+ isObject,
6
+ tracking,
7
+ type NodeValue,
8
+ type TrackingType,
9
+ } from '@legendapp/state';
10
+ import { UseSelectorOptions, useSelector } from '@legendapp/state/react';
11
+ import { createContext, useContext } from 'react';
12
+ // @ts-expect-error Internals
13
+ import { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED as ReactInternals } from 'react';
14
+
15
+ const ReactRenderContext = createContext(0);
16
+
17
+ function needsSelector() {
18
+ // If we're already tracking then we definitely don't need useSelector
19
+ if (!tracking.current) {
20
+ try {
21
+ // If there's no dispatcher we're definitely not in React
22
+ // This is an optimization to not need to run useContext. If in a future React version
23
+ // this works differently we can change it or just remove it.
24
+ const dispatcher = ReactInternals.ReactCurrentDispatcher.current;
25
+ if (dispatcher) {
26
+ // If there's a dispatcher then we may be inside of a hook.
27
+ // Attempt a useContext hook, which will throw an error if outside of render.
28
+ useContext(ReactRenderContext);
29
+ return true;
30
+ }
31
+ } catch {} // eslint-disable-line no-empty
32
+ }
33
+ return false;
34
+ }
35
+
36
+ interface ReactTrackingOptions {
37
+ auto?: boolean; // Make all get() calls act as useSelector() hooks
38
+ warnUnobserved?: boolean; // Warn if get() is used outside of an observer
39
+ }
40
+
41
+ export function enableReactTracking({ auto, warnUnobserved }: ReactTrackingOptions) {
42
+ const { get } = internal;
43
+
44
+ configureLegendState({
45
+ observableFunctions: {
46
+ get: (node: NodeValue, options?: TrackingType | (GetOptions & UseSelectorOptions)) => {
47
+ if (needsSelector()) {
48
+ if (auto) {
49
+ return useSelector(() => get(node, options), isObject(options) ? options : undefined);
50
+ } else if (process.env.NODE_ENV === 'development' && warnUnobserved) {
51
+ console.warn(
52
+ '[legend-state] Detected a `get()` call in an unobserved component. You may want to wrap it in observer: https://legendapp.com/open-source/state/react-api/#observer-hoc',
53
+ );
54
+ }
55
+ }
56
+ return get(node, options);
57
+ },
58
+ },
59
+ });
60
+ }
@@ -0,0 +1,23 @@
1
+ import { configureLegendState, internal, NodeValue } from '@legendapp/state';
2
+ import { useSelector, UseSelectorOptions } from '@legendapp/state/react';
3
+
4
+ // TODO: Deprecate
5
+
6
+ export function enableReactUse() {
7
+ configureLegendState({
8
+ observableFunctions: {
9
+ use: (node: NodeValue, options?: UseSelectorOptions) => useSelector(internal.getProxy(node), options),
10
+ },
11
+ });
12
+ }
13
+
14
+ // Types:
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
17
+ import type { ImmutableObservableBase } from '@legendapp/state';
18
+
19
+ declare module '@legendapp/state' {
20
+ interface ImmutableObservableBase<T> {
21
+ use(options?: UseSelectorOptions): T;
22
+ }
23
+ }
@@ -0,0 +1,31 @@
1
+ import { configureLegendState, internal } from '@legendapp/state';
2
+
3
+ export function enable_peek() {
4
+ configureLegendState({
5
+ observableProperties: {
6
+ _: {
7
+ get(node) {
8
+ return internal.peek(node);
9
+ },
10
+ set(node, value) {
11
+ internal.setNodeValue(node, value);
12
+ },
13
+ },
14
+ },
15
+ });
16
+ }
17
+
18
+ // TODOv4 deprecate
19
+ export const enableDirectAccess = enable_peek;
20
+
21
+ // Types:
22
+
23
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
+ import type { ImmutableObservableBase } from '@legendapp/state';
25
+
26
+ declare module '@legendapp/state' {
27
+ interface ImmutableObservableBase<T> {
28
+ get _(): T;
29
+ set _(value: T | null | undefined);
30
+ }
31
+ }
package/src/config.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { globalState } from './globals';
2
+ import { observableProperties as _observableProperties, observableFns } from './ObservableObject';
3
+ import { ObservablePrimitiveClass } from './ObservablePrimitive';
4
+ import type { NodeValue } from './observableInterfaces';
5
+
6
+ export function configureLegendState({
7
+ observableFunctions,
8
+ observableProperties,
9
+ jsonReplacer,
10
+ jsonReviver,
11
+ }: {
12
+ observableFunctions?: Record<string, (node: NodeValue, ...args: any[]) => any>;
13
+ observableProperties?: Record<string, { get: (node: NodeValue) => any; set: (node: NodeValue, value: any) => any }>;
14
+ jsonReplacer?: (this: any, key: string, value: any) => any;
15
+ jsonReviver?: (this: any, key: string, value: any) => any;
16
+ }) {
17
+ if (observableFunctions) {
18
+ for (const key in observableFunctions) {
19
+ const fn = observableFunctions[key];
20
+ observableFns.set(key, fn);
21
+ ObservablePrimitiveClass.prototype[key] = function (...args: any[]) {
22
+ return fn.call(this, this._node, ...args);
23
+ };
24
+ }
25
+ }
26
+ if (observableProperties) {
27
+ for (const key in observableProperties) {
28
+ const fns = observableProperties[key];
29
+ _observableProperties.set(key, fns);
30
+ Object.defineProperty(ObservablePrimitiveClass.prototype, key, {
31
+ configurable: true,
32
+ get() {
33
+ return fns.get.call(this, this._node);
34
+ },
35
+ set(value: any) {
36
+ return fns.set.call(this, this._node, value);
37
+ },
38
+ });
39
+ }
40
+ }
41
+ if (jsonReplacer) {
42
+ globalState.replacer = jsonReplacer;
43
+ }
44
+ if (jsonReviver) {
45
+ globalState.reviver = jsonReviver;
46
+ }
47
+ }
@@ -0,0 +1,46 @@
1
+ import { isObservable, setNodeValue } from './globals';
2
+ import { isActualPrimitive, isFunction, isPromise } from './is';
3
+ import type { ClassConstructor, ObservableRoot } from './observableInterfaces';
4
+ import { NodeValue } from './observableInterfaces';
5
+ import { Observable, ObservablePrimitive } from './observableTypes';
6
+
7
+ export function createObservable<T>(
8
+ value: T | undefined,
9
+ makePrimitive: boolean,
10
+ extractPromise: Function,
11
+ createObject: Function,
12
+ createPrimitive?: Function,
13
+ ): Observable<T> {
14
+ if (isObservable(value)) {
15
+ return value as Observable<T>;
16
+ }
17
+ const valueIsPromise = isPromise<T>(value);
18
+ const valueIsFunction = isFunction(value);
19
+
20
+ const root: ObservableRoot = {
21
+ _: value,
22
+ };
23
+
24
+ let node: NodeValue = {
25
+ root,
26
+ lazy: true,
27
+ };
28
+
29
+ if (valueIsFunction) {
30
+ node = Object.assign(() => {}, node);
31
+ node.lazyFn = value;
32
+ }
33
+
34
+ const prim = makePrimitive || isActualPrimitive(value);
35
+
36
+ const obs = prim
37
+ ? (new (createPrimitive as ClassConstructor<T>)(node) as ObservablePrimitive<T>)
38
+ : (createObject(node) as Observable<T>);
39
+
40
+ if (valueIsPromise) {
41
+ setNodeValue(node, undefined);
42
+ extractPromise(node, value);
43
+ }
44
+
45
+ return obs as any;
46
+ }
package/src/event.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { getNode, symbolGetNode } from './globals';
2
+ import { observable } from './observable';
3
+ import type { ObservableEvent } from './observableInterfaces';
4
+
5
+ export function event(): ObservableEvent {
6
+ // event simply wraps around a number observable
7
+ // which increments its value to dispatch change events
8
+ const obs = observable(0);
9
+ const node = getNode(obs);
10
+ node.isEvent = true;
11
+ return {
12
+ fire: function () {
13
+ // Notify increments the value so that the observable changes
14
+ obs.set((v) => v + 1);
15
+ },
16
+ on: function (cb: () => void) {
17
+ return obs.onChange(cb);
18
+ },
19
+ get: function () {
20
+ // Return the value so that when will be truthy
21
+ return obs.get();
22
+ },
23
+ // @ts-expect-error eslint doesn't like adding symbols to the object but this does work
24
+ [symbolGetNode]: node,
25
+ };
26
+ }
package/src/globals.ts ADDED
@@ -0,0 +1,224 @@
1
+ import { isArray, isChildNodeValue, isDate, isFunction, isObject } from './is';
2
+ import type { NodeValue, ObservableEvent, TypeAtPath, UpdateFn } from './observableInterfaces';
3
+ import type { Observable, ObservableParam } from './observableTypes';
4
+
5
+ export const symbolToPrimitive = Symbol.toPrimitive;
6
+ export const symbolGetNode = Symbol('getNode');
7
+ export const symbolDelete = /* @__PURE__ */ Symbol('delete');
8
+ export const symbolOpaque = Symbol('opaque');
9
+ export const optimized = Symbol('optimized');
10
+ export const symbolLinked = Symbol('linked');
11
+
12
+ export const globalState = {
13
+ isLoadingLocal: false,
14
+ isMerging: false,
15
+ isLoadingRemote: false,
16
+ activateSyncedNode: undefined as unknown as (node: NodeValue, newValue: any) => { update: UpdateFn; value: any },
17
+ pendingNodes: new Map<NodeValue, () => void>(),
18
+ dirtyNodes: new Set<NodeValue>(),
19
+ replacer: undefined as undefined | ((this: any, key: string, value: any) => any),
20
+ reviver: undefined as undefined | ((this: any, key: string, value: any) => any),
21
+ };
22
+
23
+ export function getPathType(value: any): TypeAtPath {
24
+ return isArray(value) ? 'array' : value instanceof Map ? 'map' : value instanceof Set ? 'set' : 'object';
25
+ }
26
+
27
+ function replacer(key: string, value: any) {
28
+ if (value instanceof Map) {
29
+ return {
30
+ __LSType: 'Map',
31
+ value: Array.from(value.entries()), // or with spread: value: [...value]
32
+ };
33
+ } else if (value instanceof Set) {
34
+ return {
35
+ __LSType: 'Set',
36
+ value: Array.from(value), // or with spread: value: [...value]
37
+ };
38
+ } else if (globalState.replacer) {
39
+ value = globalState.replacer(key, value);
40
+ }
41
+ return value;
42
+ }
43
+
44
+ const ISO8601 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
45
+ function reviver(key: string, value: any) {
46
+ if (value) {
47
+ if (typeof value === 'string' && ISO8601.test(value)) {
48
+ return new Date(value);
49
+ }
50
+ if (typeof value === 'object') {
51
+ if (value.__LSType === 'Map') {
52
+ return new Map(value.value);
53
+ } else if (value.__LSType === 'Set') {
54
+ return new Set(value.value);
55
+ }
56
+ }
57
+ if (globalState.reviver) {
58
+ value = globalState.reviver(key, value);
59
+ }
60
+ }
61
+ return value;
62
+ }
63
+
64
+ export function safeStringify(value: any) {
65
+ return JSON.stringify(value, replacer);
66
+ }
67
+ export function safeParse(value: any) {
68
+ return JSON.parse(value, reviver);
69
+ }
70
+ export function clone(value: any) {
71
+ return safeParse(safeStringify(value));
72
+ }
73
+
74
+ export function isObservable(obs: any): obs is Observable {
75
+ return !!obs && !!obs[symbolGetNode as any];
76
+ }
77
+
78
+ export function getNode(obs: ObservableParam): NodeValue {
79
+ return obs && (obs as any)[symbolGetNode];
80
+ }
81
+
82
+ export function isEvent(obs: any): obs is ObservableEvent {
83
+ return obs && (obs[symbolGetNode as any] as NodeValue)?.isEvent;
84
+ }
85
+
86
+ export function setNodeValue(node: NodeValue, newValue: any) {
87
+ const parentNode = node.parent ?? node;
88
+ const key = node.parent ? node.key : '_';
89
+
90
+ const isDelete = newValue === symbolDelete;
91
+ if (isDelete) newValue = undefined;
92
+
93
+ // Get the value of the parent
94
+ const parentValue = node.parent ? ensureNodeValue(parentNode) : parentNode.root;
95
+
96
+ // Save the previous value first
97
+ const prevValue = parentValue[key];
98
+
99
+ const isFunc = isFunction(newValue);
100
+
101
+ // Compute newValue if newValue is a function or an observable
102
+ newValue = !parentNode.isAssigning && isFunc && !isFunction(prevValue) ? newValue(prevValue) : newValue;
103
+
104
+ if (
105
+ !globalState.isMerging ||
106
+ prevValue === undefined ||
107
+ isFunction(prevValue) ||
108
+ !node.parent?.functions?.get(key)
109
+ ) {
110
+ try {
111
+ parentNode.isSetting = (parentNode.isSetting || 0) + 1;
112
+
113
+ // Save the new value
114
+ if (isDelete) {
115
+ delete parentValue[key];
116
+ } else {
117
+ parentValue[key] = newValue;
118
+ }
119
+ } finally {
120
+ parentNode.isSetting!--;
121
+ }
122
+ }
123
+
124
+ return { prevValue, newValue };
125
+ }
126
+
127
+ const arrNodeKeys: string[] = [];
128
+ export function getNodeValue(node: NodeValue): any {
129
+ let count = 0;
130
+ let n: NodeValue = node;
131
+ while (isChildNodeValue(n)) {
132
+ arrNodeKeys[count++] = n.key;
133
+ n = n.parent;
134
+ }
135
+ let child = node.root._;
136
+ for (let i = count - 1; child && i >= 0; i--) {
137
+ const key = arrNodeKeys[i] as any;
138
+ child = key !== 'size' && (child instanceof Map || child instanceof WeakMap) ? child.get(key) : child[key];
139
+ }
140
+ return child;
141
+ }
142
+
143
+ export function getChildNode(node: NodeValue, key: string, asFunction?: Function): NodeValue {
144
+ // Get the child by key
145
+ let child = node.children?.get(key);
146
+
147
+ // Create the child node if it doesn't already exist
148
+ if (!child) {
149
+ child = {
150
+ root: node.root,
151
+ parent: node,
152
+ key,
153
+ lazy: true,
154
+ };
155
+ // Lookup functions are bound with the child key
156
+ if (node.lazyFn?.length === 1) {
157
+ asFunction = node.lazyFn.bind(node, key);
158
+ }
159
+ if (isFunction(asFunction)) {
160
+ child = Object.assign(() => {}, child);
161
+ child.lazyFn = asFunction;
162
+ }
163
+ if (!node.children) {
164
+ node.children = new Map();
165
+ }
166
+ node.children.set(key, child);
167
+ }
168
+
169
+ return child;
170
+ }
171
+
172
+ export function ensureNodeValue(node: NodeValue) {
173
+ let value = getNodeValue(node);
174
+ if (!value || isFunction(value)) {
175
+ if (isChildNodeValue(node)) {
176
+ const parent = ensureNodeValue(node.parent);
177
+ value = parent[node.key] = {};
178
+ } else {
179
+ value = node.root._ = {};
180
+ }
181
+ }
182
+ return value;
183
+ }
184
+
185
+ export function findIDKey(obj: unknown | undefined, node: NodeValue): string | ((value: any) => string) | undefined {
186
+ let idKey: string | ((value: any) => string) | undefined = isObservable(obj)
187
+ ? undefined
188
+ : isObject(obj)
189
+ ? 'id' in obj
190
+ ? 'id'
191
+ : 'key' in obj
192
+ ? 'key'
193
+ : '_id' in obj
194
+ ? '_id'
195
+ : '__id' in obj
196
+ ? '__id'
197
+ : undefined
198
+ : undefined;
199
+
200
+ if (!idKey && node.parent) {
201
+ const k = node.key + '_keyExtractor';
202
+ const keyExtractor =
203
+ (node.functions?.get(k) as (value: any) => string) ??
204
+ (getNodeValue(node.parent)[node.key + '_keyExtractor'] as (value: any) => string);
205
+ if (keyExtractor && isFunction(keyExtractor)) {
206
+ idKey = keyExtractor;
207
+ }
208
+ }
209
+
210
+ return idKey;
211
+ }
212
+
213
+ export function extractFunction(node: NodeValue, key: string, fnOrComputed: Function): void;
214
+ export function extractFunction(node: NodeValue, key: string, fnOrComputed: Observable): void;
215
+ export function extractFunction(node: NodeValue, key: string, fnOrComputed: Function | Observable): void {
216
+ if (!node.functions) {
217
+ node.functions = new Map();
218
+ }
219
+
220
+ node.functions.set(key, fnOrComputed);
221
+ }
222
+ export function equals(a: unknown, b: unknown) {
223
+ return a === b || (isDate(a) && isDate(b) && +a === +b);
224
+ }
@@ -0,0 +1,26 @@
1
+ import { Observable, observable } from '@legendapp/state';
2
+
3
+ export function observableFetch<T>(
4
+ input: RequestInfo | URL,
5
+ init?: RequestInit,
6
+ valueType?: 'arrayBuffer' | 'blob' | 'formData' | 'json' | 'text',
7
+ ): Observable<{
8
+ data?: T;
9
+ error?: any;
10
+ errorStr?: string;
11
+ loading: boolean;
12
+ }> {
13
+ const obs: Observable<any> = observable({
14
+ data: undefined,
15
+ error: undefined,
16
+ errorStr: undefined,
17
+ loading: true,
18
+ });
19
+
20
+ fetch(input, init)
21
+ .then((response) => response[valueType || 'json']())
22
+ .then((value) => obs.set({ data: value, loading: false }))
23
+ .catch((error) => obs.set({ loading: false, error, errorStr: error?.toString?.() }));
24
+
25
+ return obs as any;
26
+ }
@@ -0,0 +1,41 @@
1
+ import { observable, Observable } from '@legendapp/state';
2
+
3
+ interface Options {
4
+ setter: 'pushState' | 'replaceState' | 'hash';
5
+ }
6
+ let _options: Options = { setter: 'hash' };
7
+
8
+ function configurePageHash(options: Options) {
9
+ _options = options;
10
+ }
11
+
12
+ const hasWindow = typeof window !== 'undefined';
13
+ const pageHash: Observable<string> = observable(hasWindow ? window.location.hash.slice(1) : '');
14
+
15
+ if (hasWindow) {
16
+ let isSetting = false;
17
+ // Set the page hash when the observable changes
18
+ pageHash.onChange(({ value }) => {
19
+ if (!isSetting) {
20
+ const hash = '#' + value;
21
+ const setter = _options?.setter || 'hash';
22
+ if (setter === 'pushState') {
23
+ history.pushState(null, null as any, hash);
24
+ } else if (setter === 'replaceState') {
25
+ history.replaceState(null, null as any, hash);
26
+ } else {
27
+ location.hash = hash;
28
+ }
29
+ }
30
+ });
31
+ // Update the observable whenever the hash changes
32
+ const cb = () => {
33
+ isSetting = true;
34
+ pageHash.set(window.location.hash.slice(1));
35
+ isSetting = false;
36
+ };
37
+ // Subscribe to window hashChange event
38
+ window.addEventListener('hashchange', cb);
39
+ }
40
+
41
+ export { configurePageHash, pageHash };
@@ -0,0 +1,55 @@
1
+ import { observable, Observable } from '@legendapp/state';
2
+
3
+ interface Options {
4
+ setter: 'pushState' | 'replaceState' | 'hash';
5
+ }
6
+ let _options: Options = { setter: 'hash' };
7
+
8
+ function configurePageHashParams(options: Options) {
9
+ _options = options;
10
+ }
11
+
12
+ function toParams(str: string) {
13
+ const ret: Record<string, string> = {};
14
+ const searchParams = new URLSearchParams(str);
15
+ for (const [key, value] of searchParams) {
16
+ ret[key] = value;
17
+ }
18
+ return ret;
19
+ }
20
+ function toString(params: Record<string, string>) {
21
+ return new URLSearchParams(params).toString().replace(/=$/, '');
22
+ }
23
+
24
+ const hasWindow = typeof window !== 'undefined';
25
+ const pageHashParams: Observable<Record<string, string>> = observable(
26
+ hasWindow ? toParams(window.location.hash.slice(1)) : {},
27
+ );
28
+
29
+ if (hasWindow) {
30
+ let isSetting = false;
31
+ // Set the page hash when the observable changes
32
+ pageHashParams.onChange(({ value }) => {
33
+ if (!isSetting) {
34
+ const hash = '#' + toString(value);
35
+ const setter = _options?.setter || 'hash';
36
+ if (setter === 'pushState') {
37
+ history.pushState(null, null as any, hash);
38
+ } else if (setter === 'replaceState') {
39
+ history.replaceState(null, null as any, hash);
40
+ } else {
41
+ location.hash = hash;
42
+ }
43
+ }
44
+ });
45
+ // Update the observable whenever the hash changes
46
+ const cb = () => {
47
+ isSetting = true;
48
+ pageHashParams.set(toParams(window.location.hash.slice(1)));
49
+ isSetting = false;
50
+ };
51
+ // Subscribe to window hashChange event
52
+ window.addEventListener('hashchange', cb);
53
+ }
54
+
55
+ export { configurePageHashParams, pageHashParams };
@@ -0,0 +1,30 @@
1
+ import { observable } from '@legendapp/state';
2
+
3
+ const MSPerMinute = 60000;
4
+
5
+ function clearTime(date: Date | number) {
6
+ date = new Date(date);
7
+ date.setHours(0, 0, 0, 0);
8
+ return date;
9
+ }
10
+
11
+ let time = new Date();
12
+ const currentTime = observable(time);
13
+ const currentDay = observable(clearTime(time));
14
+ const timeToSecond = (60 - time.getSeconds() + 1) * 1000;
15
+ function update() {
16
+ const now = new Date();
17
+ currentTime.set(now);
18
+
19
+ if (now.getDate() !== time.getDate()) {
20
+ currentDay.set(clearTime(now));
21
+ }
22
+
23
+ time = now;
24
+ }
25
+ setTimeout(() => {
26
+ update();
27
+ setInterval(update, MSPerMinute);
28
+ }, timeToSecond);
29
+
30
+ export { currentTime, currentDay };