diff --git a/Partas.Solid.FablePlugin/Partas.Solid.FablePlugin.fsproj b/Partas.Solid.FablePlugin/Partas.Solid.FablePlugin.fsproj index 9dd6e2c..990cdc1 100644 --- a/Partas.Solid.FablePlugin/Partas.Solid.FablePlugin.fsproj +++ b/Partas.Solid.FablePlugin/Partas.Solid.FablePlugin.fsproj @@ -2,6 +2,7 @@ net6.0 + false 3239;0025 Partas.Solid.FablePlugin Partas.Solid.FablePlugin @@ -27,6 +28,7 @@ + diff --git a/Partas.Solid.TanStack.Store/Partas.Solid.TanStack.Store.fsproj b/Partas.Solid.TanStack.Store/Partas.Solid.TanStack.Store.fsproj new file mode 100644 index 0000000..df22699 --- /dev/null +++ b/Partas.Solid.TanStack.Store/Partas.Solid.TanStack.Store.fsproj @@ -0,0 +1,27 @@ + + + + library + net6.0 + Partas.Solid.TanStack.Store + Partas.Solid.TanStack.Store + Partas.Solid.TanStack.Store + Shayan Habibi, Vladimir Schur and Contributors + MIT + Partas;Solid;TanStack;Store;Fable + + + + + + + + + + + + + + + + diff --git a/Partas.Solid.TanStack.Store/Spec.fs b/Partas.Solid.TanStack.Store/Spec.fs new file mode 100644 index 0000000..de725b2 --- /dev/null +++ b/Partas.Solid.TanStack.Store/Spec.fs @@ -0,0 +1,5 @@ +namespace Partas.Solid.TanStack.Store + +module Spec = + [] + let PackageName = "@tanstack/solid-store" diff --git a/Partas.Solid.TanStack.Store/Store.fs b/Partas.Solid.TanStack.Store/Store.fs new file mode 100644 index 0000000..0f7d4a1 --- /dev/null +++ b/Partas.Solid.TanStack.Store/Store.fs @@ -0,0 +1,59 @@ +namespace Partas.Solid.TanStack.Store + +open Fable.Core +open Fable.Core.JS +open Partas.Solid +open System + +[] +module Bindings = + + /// Store options - use anonymous record with !! operator: + /// new Store(0, !!{| updateFn = fun prev updater -> ... |}) + [] + type StoreOptions<'T> = + abstract member updateFn: ('T -> ('T -> 'T) -> 'T) option with get + abstract member onUpdate: (unit -> unit) option with get + + [] + type Store<'T>(initialValue: 'T, ?options: StoreOptions<'T>) = + member _.state: 'T = jsNative + member _.setState(updater: 'T -> 'T) : unit = jsNative + member _.setState(newState: 'T) : unit = jsNative + member _.subscribe(callback: unit -> unit) : (unit -> unit) = jsNative + + [] + let batch (fn: unit -> unit) : unit = jsNative + + [] + type DerivedFnProps<'T> = + abstract member prevVal: 'T option with get + abstract member prevDepVals: obj[] option with get + abstract member currDepVals: obj[] with get + + [] + type DerivedOptions<'T>(fn: DerivedFnProps<'T> -> 'T, deps: obj[]) = + member val fn = fn with get, set + member val deps = deps with get, set + member val onSubscribe: (Action<'T> * Derived<'T> -> (unit -> unit)) option = None with get, set + member val onUpdate: (unit -> unit) option = None with get, set + + and [] Derived<'T>(options: DerivedOptions<'T>) = + member _.state: 'T = jsNative + member _.mount() : (unit -> unit) = jsNative + + [] + type EffectOptions(fn: unit -> unit, deps: obj[]) = + member val fn = fn with get, set + member val deps = deps with get, set + member val eager = false with get, set + + [] + type Effect(options: EffectOptions) = + member _.mount() : (unit -> unit) = jsNative + + [] + let useStore (store: Store<'T>) (selector: 'T -> 'U) : Accessor<'U> = jsNative + + [] + let useStoreFull (store: Store<'T>) : Accessor<'T> = jsNative diff --git a/Partas.Solid.Tests.Plugin/Compiled/Partas.Solid.Tests.Plugin.Compiled.fsproj b/Partas.Solid.Tests.Plugin/Compiled/Partas.Solid.Tests.Plugin.Compiled.fsproj index 6e9024a..1c3f5e4 100644 --- a/Partas.Solid.Tests.Plugin/Compiled/Partas.Solid.Tests.Plugin.Compiled.fsproj +++ b/Partas.Solid.Tests.Plugin/Compiled/Partas.Solid.Tests.Plugin.Compiled.fsproj @@ -95,12 +95,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BasicStore/BasicStore.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BasicStore/BasicStore.expected new file mode 100644 index 0000000..664e93a --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BasicStore/BasicStore.expected @@ -0,0 +1,15 @@ + +import { useStore, Store } from "@tanstack/solid-store"; +import { int32ToString } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Util.js"; + +export const store = new Store(0); + +export function Component() { + const count = useStore(store, (state) => (state | 0)); + return
{ + store.setState((s) => ((s + 1) | 0)); + }}> + {int32ToString(count())} +
; +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BasicStore/BasicStore.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BasicStore/BasicStore.fs new file mode 100644 index 0000000..136211d --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BasicStore/BasicStore.fs @@ -0,0 +1,12 @@ +module BasicStore + +open Partas.Solid +open Partas.Solid.TanStack.Store + +let store = new Store (0) + +[] +let Component () = + let count = useStore store (fun state -> state) + + div().on ("click", fun _ -> store.setState (fun s -> s + 1)) { string (count ()) } diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BatchUpdates/BatchUpdates.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BatchUpdates/BatchUpdates.expected new file mode 100644 index 0000000..3f03886 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BatchUpdates/BatchUpdates.expected @@ -0,0 +1,13 @@ + +import { batch, Store } from "@tanstack/solid-store"; + +export const store = new Store(0); + +export function performBatchUpdate() { + batch(() => { + store.setState((_arg) => 1); + store.setState((_arg_1) => 2); + store.setState((s) => ((s + 1) | 0)); + }); +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BatchUpdates/BatchUpdates.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BatchUpdates/BatchUpdates.fs new file mode 100644 index 0000000..32689fd --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/BatchUpdates/BatchUpdates.fs @@ -0,0 +1,11 @@ +module BatchUpdates + +open Partas.Solid.TanStack.Store + +let store = new Store (0) + +let performBatchUpdate () = + batch (fun () -> + store.setState (fun _ -> 1) + store.setState (fun _ -> 2) + store.setState (fun s -> s + 1)) diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedDepVals/DerivedDepVals.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedDepVals/DerivedDepVals.expected new file mode 100644 index 0000000..6d933d7 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedDepVals/DerivedDepVals.expected @@ -0,0 +1,14 @@ + +import { Derived, Store } from "@tanstack/solid-store"; +import { map, defaultArg } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Option.js"; +import { item } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Array.js"; + +export const count = new Store(1); + +export const sumWithPrev = new Derived({ + fn: (props) => ((defaultArg(map((arr) => (item(0, arr) | 0), props.prevDepVals), 0) + item(0, props.currDepVals)) | 0), + deps: [count], +}); + +export const unmount = sumWithPrev.mount(); + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedDepVals/DerivedDepVals.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedDepVals/DerivedDepVals.fs new file mode 100644 index 0000000..0259dea --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedDepVals/DerivedDepVals.fs @@ -0,0 +1,24 @@ +module DerivedDepVals + +open Partas.Solid.TanStack.Store + +let count = new Store (1) + +let sumWithPrev = + new Derived ( + DerivedOptions ( + (fun props -> + let prevDep = + props.prevDepVals + |> Option.map (fun arr -> unbox arr[0]) + |> Option.defaultValue 0 + + let currDep = unbox props.currDepVals[0] + + prevDep + + currDep), + [| count |] + ) + ) + +let unmount = sumWithPrev.mount () diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedPrevVal/DerivedPrevVal.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedPrevVal/DerivedPrevVal.expected new file mode 100644 index 0000000..b0d88a7 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedPrevVal/DerivedPrevVal.expected @@ -0,0 +1,16 @@ + +import { Derived, Store } from "@tanstack/solid-store"; +import { defaultArg } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Option.js"; + +export const count = new Store(1); + +export const runningTotal = new Derived({ + fn: (props) => { + const prev = defaultArg(props.prevVal, 0) | 0; + return (count.state + prev) | 0; + }, + deps: [count], +}); + +export const unmount = runningTotal.mount(); + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedPrevVal/DerivedPrevVal.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedPrevVal/DerivedPrevVal.fs new file mode 100644 index 0000000..e4f3830 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedPrevVal/DerivedPrevVal.fs @@ -0,0 +1,21 @@ +module DerivedPrevVal + +open Partas.Solid.TanStack.Store + +let count = new Store (1) + +let runningTotal = + new Derived ( + DerivedOptions ( + (fun props -> + let prev = + props.prevVal + |> Option.defaultValue 0 + + count.state + + prev), + [| count |] + ) + ) + +let unmount = runningTotal.mount () diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedStore/DerivedStore.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedStore/DerivedStore.expected new file mode 100644 index 0000000..dc4a7c9 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedStore/DerivedStore.expected @@ -0,0 +1,29 @@ + +import { useStore, Derived, Store } from "@tanstack/solid-store"; + +export const countStore = new Store(5); + +export const doubledOptions = { + fn: (props) => ((countStore.state * 2) | 0), + deps: [countStore], +}; + +export const doubled = new Derived(doubledOptions); + +export function Component() { + const count = useStore(countStore, (s) => (s | 0)); + return
+ + {`Count: ${count()}`} + + + {`Doubled: ${doubled.state}`} + + +
; +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedStore/DerivedStore.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedStore/DerivedStore.fs new file mode 100644 index 0000000..b52669d --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/DerivedStore/DerivedStore.fs @@ -0,0 +1,28 @@ +module DerivedStore + +open Partas.Solid +open Partas.Solid.TanStack.Store + +let countStore = new Store (5) + +let doubledOptions = + DerivedOptions ( + (fun props -> + let current = countStore.state + + current + * 2), + [| countStore |] + ) + +let doubled = new Derived (doubledOptions) + +[] +let Component () = + let count = useStore countStore (fun s -> s) + + div () { + span () { $"Count: {count ()}" } + span () { $"Doubled: {doubled.state}" } + button().on ("click", fun _ -> countStore.setState (fun s -> s + 1)) { "Increment" } + } diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectEager/EffectEager.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectEager/EffectEager.expected new file mode 100644 index 0000000..4925a1c --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectEager/EffectEager.expected @@ -0,0 +1,19 @@ + +import { Effect, Store } from "@tanstack/solid-store"; +import { some } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Option.js"; + +export const store = new Store(0); + +export const eagerEffect = (() => { + const opts = { + fn: () => { + console.log(some("Immediate effect:"), store.state); + }, + deps: [store], + }; + opts.eager = true; + return new Effect(opts); +})(); + +export const unmount = eagerEffect.mount(); + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectEager/EffectEager.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectEager/EffectEager.fs new file mode 100644 index 0000000..6765f50 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectEager/EffectEager.fs @@ -0,0 +1,15 @@ +module EffectEager + +open Partas.Solid.TanStack.Store +open Fable.Core.JS + +let store = new Store (0) + +let eagerEffect = + let opts = + EffectOptions ((fun () -> console.log ("Immediate effect:", store.state)), [| store |]) + + opts.eager <- true + new Effect (opts) + +let unmount = eagerEffect.mount () diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectStore/EffectStore.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectStore/EffectStore.expected new file mode 100644 index 0000000..a08ccbe --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectStore/EffectStore.expected @@ -0,0 +1,30 @@ + +import { useStore, Effect, Store } from "@tanstack/solid-store"; +import { some } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Option.js"; +import { int32ToString } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Util.js"; + +export const store = new Store(0); + +export const effectOptions = { + fn: () => { + console.log(some("Store changed:"), store.state); + }, + deps: [store], +}; + +export const storeEffect = new Effect(effectOptions); + +export function Component() { + const count = useStore(store, (s) => (s | 0)); + return
+ + {int32ToString(count())} + + +
; +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectStore/EffectStore.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectStore/EffectStore.fs new file mode 100644 index 0000000..883e53f --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/EffectStore/EffectStore.fs @@ -0,0 +1,21 @@ +module EffectStore + +open Partas.Solid +open Partas.Solid.TanStack.Store +open Fable.Core + +let store = new Store (0) + +let effectOptions = + EffectOptions ((fun () -> JS.console.log ("Store changed:", store.state)), [| store |]) + +let storeEffect = new Effect (effectOptions) + +[] +let Component () = + let count = useStore store (fun s -> s) + + div () { + span () { string (count ()) } + button().on ("click", fun _ -> store.setState (fun s -> s + 1)) { "Increment" } + } diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/MountUnmount/MountUnmount.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/MountUnmount/MountUnmount.expected new file mode 100644 index 0000000..d0958d2 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/MountUnmount/MountUnmount.expected @@ -0,0 +1,32 @@ + +import { Effect, Derived, Store } from "@tanstack/solid-store"; +import { some } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Option.js"; +import { onCleanup } from "solid-js"; +import { int32ToString } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Util.js"; + +export const store = new Store(0); + +export const derived = new Derived({ + fn: (_arg) => ((store.state * 2) | 0), + deps: [store], +}); + +export const effect = new Effect({ + fn: () => { + console.log(some(store.state)); + }, + deps: [store], +}); + +export function Component() { + const derivedUnmount = derived.mount(); + const effectUnmount = effect.mount(); + onCleanup(() => { + derivedUnmount(); + effectUnmount(); + }); + return
+ {int32ToString(derived.state)} +
; +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/MountUnmount/MountUnmount.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/MountUnmount/MountUnmount.fs new file mode 100644 index 0000000..8d61d67 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/MountUnmount/MountUnmount.fs @@ -0,0 +1,31 @@ +module MountUnmount + +open Partas.Solid +open Partas.Solid.TanStack.Store +open Fable.Core.JS + +let store = new Store (0) + +let derived = + new Derived ( + DerivedOptions ( + (fun _ -> + store.state + * 2), + [| store |] + ) + ) + +let effect = + new Effect (EffectOptions ((fun () -> console.log (store.state)), [| store |])) + +[] +let Component () = + let derivedUnmount = derived.mount () + let effectUnmount = effect.mount () + + onCleanup (fun () -> + derivedUnmount () + effectUnmount ()) + + div () { string derived.state } diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/RecordState/RecordState.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/RecordState/RecordState.expected new file mode 100644 index 0000000..cf66933 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/RecordState/RecordState.expected @@ -0,0 +1,38 @@ + +import { Record } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Types.js"; +import { record_type, string_type, int32_type } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Reflection.js"; +import { useStore, Store } from "@tanstack/solid-store"; +import { int32ToString } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Util.js"; + +export class AppState extends Record { + constructor(count, name) { + super(); + this.count = (count | 0); + this.name = name; + } +} + +export function AppState_$reflection() { + return record_type("RecordState.AppState", [], AppState, () => [["count", int32_type], ["name", string_type]]); +} + +export const store = new Store(new AppState(0, "Test")); + +export function Component() { + const count = useStore(store, (s) => (s.count | 0)); + const name = useStore(store, (s_1) => s_1.name); + return
+ + {name()} + + + {int32ToString(count())} + + +
; +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/RecordState/RecordState.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/RecordState/RecordState.fs new file mode 100644 index 0000000..1473937 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/RecordState/RecordState.fs @@ -0,0 +1,31 @@ +module RecordState + +open Partas.Solid +open Partas.Solid.TanStack.Store + +type AppState = { count: int; name: string } + +let store = new Store ({ count = 0; name = "Test" }) + +[] +let Component () = + let count = useStore store (fun s -> s.count) + let name = useStore store (fun s -> s.name) + + div () { + span () { name () } + span () { string (count ()) } + + button() + .on ( + "click", + fun _ -> + store.setState (fun s -> + { s with + count = + s.count + + 1 }) + ) { + "Increment" + } + } diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/StoreOptions/StoreOptions.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/StoreOptions/StoreOptions.expected new file mode 100644 index 0000000..d388956 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/StoreOptions/StoreOptions.expected @@ -0,0 +1,14 @@ + +import { Store } from "@tanstack/solid-store"; +import { some } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Option.js"; + +export const store = new Store(12, { + updateFn: (prev, updater) => ((updater(prev) + prev) | 0), +}); + +export const storeWithOnUpdate = new Store(0, { + onUpdate: () => { + console.log(some("Updated!")); + }, +}); + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/StoreOptions/StoreOptions.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/StoreOptions/StoreOptions.fs new file mode 100644 index 0000000..d037ae0 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/StoreOptions/StoreOptions.fs @@ -0,0 +1,17 @@ +module StoreOptions + +open Partas.Solid.TanStack.Store +open Fable.Core.JS +open Fable.Core.JsInterop + +let store = + new Store ( + 12, + !!{| updateFn = + fun prev updater -> + updater prev + + prev |} + ) + +let storeWithOnUpdate = + new Store (0, !!{| onUpdate = fun () -> console.log ("Updated!") |}) diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/Subscribe/Subscribe.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/Subscribe/Subscribe.expected new file mode 100644 index 0000000..7814d15 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/Subscribe/Subscribe.expected @@ -0,0 +1,14 @@ + +import { Store } from "@tanstack/solid-store"; +import { some } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Option.js"; + +export const store = new Store(0); + +export const unsub = store.subscribe(() => { + console.log(some("State changed:"), store.state); +}); + +export function cleanup() { + unsub(); +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/Subscribe/Subscribe.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/Subscribe/Subscribe.fs new file mode 100644 index 0000000..f1ffd91 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/Subscribe/Subscribe.fs @@ -0,0 +1,10 @@ +module Subscribe + +open Partas.Solid.TanStack.Store +open Fable.Core.JS + +let store = new Store (0) + +let unsub = store.subscribe (fun () -> console.log ("State changed:", store.state)) + +let cleanup () = unsub () diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/UseStoreFull/UseStoreFull.expected b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/UseStoreFull/UseStoreFull.expected new file mode 100644 index 0000000..fcd99c9 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/UseStoreFull/UseStoreFull.expected @@ -0,0 +1,13 @@ + +import { useStoreFull, Store } from "@tanstack/solid-store"; +import { int32ToString } from "../../fable_modules/fable-library-js.5.0.0-alpha.14/Util.js"; + +export const store = new Store(42); + +export function Component() { + const state = useStoreFull(store); + return
+ {int32ToString(state())} +
; +} + diff --git a/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/UseStoreFull/UseStoreFull.fs b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/UseStoreFull/UseStoreFull.fs new file mode 100644 index 0000000..47396e0 --- /dev/null +++ b/Partas.Solid.Tests.Plugin/Compiled/TanStackStoreCases/UseStoreFull/UseStoreFull.fs @@ -0,0 +1,12 @@ +module UseStoreFull + +open Partas.Solid +open Partas.Solid.TanStack.Store + +let store = new Store (42) + +[] +let Component () = + let state = useStoreFull store + + div () { string (state ()) } diff --git a/Partas.Solid.Tests.Plugin/Tests.fs b/Partas.Solid.Tests.Plugin/Tests.fs index 0e28b82..27c20db 100644 --- a/Partas.Solid.Tests.Plugin/Tests.fs +++ b/Partas.Solid.Tests.Plugin/Tests.fs @@ -1,108 +1,147 @@ -module Partas.Solid.Tests.Plugin.IssueTests - -open Expecto -open Partas.Solid.Tests.Plugin.Common - -let built = lazy buildCases () - -let runIssueCase caseName = - fun _ -> - built.Value - let folderName = "IssueCases" - runCase folderName caseName - -let runSolidCase name caseName = - let runSolidCase' caseName = - fun _ -> - built.Value - let folderName = "SolidCases" - runCase folderName caseName - - testCase name - <| runSolidCase' caseName - -let runAttributeCase name caseName = - let runAttributeCase' caseName = - fun _ -> - built.Value - let folderName = "AttributeCases" - runCase folderName caseName - - testCase name - <| runAttributeCase' caseName - - -[] -let IssueCases = - testList - "IssueCases" - [ testCase "#2 createSignal getting converted into Tag" - <| runIssueCase "CreateSignalTagConstructor" - testCase "#9 Index access is rendered" - <| runIssueCase "IndexAccess" - testCase "#11 String interpolation is transformed" - <| runIssueCase "TransformInsideStringInterpolation" - testCase "#13 Getter extensions are transformed" - <| runIssueCase "TransformGetterExtensions" - testCase "#14 Object Expressions are transformed" - <| runIssueCase "ObjectExpressions" - testCase "#15 props.words.ToCharArray() |> Array.map string" - <| runIssueCase "CharArrayMapping" - testCase "#16 val mutable overloads render" - <| runIssueCase "ValMutableOverloads" - testCase "#18 indexed identifiers spread" - <| runIssueCase "IndexedPropSpreading" - testCase "#28 ThisArg is transformed" - <| runIssueCase "ThisArgTransforms" - testCase "#29 val mutable overloads render 2" - <| runIssueCase "InheritedProperty" - testCase "#37 passing objects as event handlers" - <| runIssueCase "ObjectEventHandler" ] - -[] -let SolidCases = - testList - "SolidCases" - [ runSolidCase "TagsNoChildren" "TagsNoChildren" - runSolidCase "Library Imports and User Imports" "LibraryImport" - "TagExtensions" - |> runSolidCase "Tag Extensions" - "ImportedTagsWithExtensions" - |> runSolidCase "Imported Tags with Extensions" - "ChildrenSimple" - |> runSolidCase "Tags with child elements" - "MergeProps" - |> runSolidCase "Default property setting" - "SplitProps" - |> runSolidCase "Property accessing with split props" - "CombinedSpread" - |> runSolidCase "mergeProps splitProps and property spreading" - "OperatorsInProps" - |> runSolidCase "Property getters mixed with Operands are transformed" - "FieldGettersInComputations" - |> runSolidCase "Field getters and records are transformed" - "TagsAsValuesSimple" - |> runSolidCase "Tags can be used as values" - "FieldGetExpressionsTransformed" - |> runSolidCase "FieldGets like props.words.Length are transformed" - "SignalSetterInvoke" - |> runSolidCase "Signal Setters can be invoked with a handler" - "ExperimentalBuilders" - |> runSolidCase "Experimental Builders compile correct output" - "CssStyles" - |> runSolidCase "CssStyle definitions compiles correct output" - "ChildLambdaProvider" - |> runSolidCase "ChildLambdaProvider interfaces" - "SolidComponentAsTagValues" - |> runSolidCase "SolidComponent let bindings as TagValues" - "ValueUnrollerDecisionTree" - |> runSolidCase "Decision Trees in arrays do not spawn singleton instructions" ] - -[] -let AttributeCases = - testList - "AttributeCases" - [ "PartasImportAttr" - |> runAttributeCase "PartasImport Attribute" - "Pojo" - |> runAttributeCase "Pojo Optimisation" ] +module Partas.Solid.Tests.Plugin.IssueTests + +open Expecto +open Partas.Solid.Tests.Plugin.Common + +let built = lazy buildCases () + +let runIssueCase caseName = + fun _ -> + built.Value + let folderName = "IssueCases" + runCase folderName caseName + +let runSolidCase name caseName = + let runSolidCase' caseName = + fun _ -> + built.Value + let folderName = "SolidCases" + runCase folderName caseName + + testCase name + <| runSolidCase' caseName + +let runAttributeCase name caseName = + let runAttributeCase' caseName = + fun _ -> + built.Value + let folderName = "AttributeCases" + runCase folderName caseName + + testCase name + <| runAttributeCase' caseName + + +[] +let IssueCases = + testList + "IssueCases" + [ testCase "#2 createSignal getting converted into Tag" + <| runIssueCase "CreateSignalTagConstructor" + testCase "#9 Index access is rendered" + <| runIssueCase "IndexAccess" + testCase "#11 String interpolation is transformed" + <| runIssueCase "TransformInsideStringInterpolation" + testCase "#13 Getter extensions are transformed" + <| runIssueCase "TransformGetterExtensions" + testCase "#14 Object Expressions are transformed" + <| runIssueCase "ObjectExpressions" + testCase "#15 props.words.ToCharArray() |> Array.map string" + <| runIssueCase "CharArrayMapping" + testCase "#16 val mutable overloads render" + <| runIssueCase "ValMutableOverloads" + testCase "#18 indexed identifiers spread" + <| runIssueCase "IndexedPropSpreading" + testCase "#28 ThisArg is transformed" + <| runIssueCase "ThisArgTransforms" + testCase "#29 val mutable overloads render 2" + <| runIssueCase "InheritedProperty" + testCase "#37 passing objects as event handlers" + <| runIssueCase "ObjectEventHandler" ] + +[] +let SolidCases = + testList + "SolidCases" + [ runSolidCase "TagsNoChildren" "TagsNoChildren" + runSolidCase "Library Imports and User Imports" "LibraryImport" + "TagExtensions" + |> runSolidCase "Tag Extensions" + "ImportedTagsWithExtensions" + |> runSolidCase "Imported Tags with Extensions" + "ChildrenSimple" + |> runSolidCase "Tags with child elements" + "MergeProps" + |> runSolidCase "Default property setting" + "SplitProps" + |> runSolidCase "Property accessing with split props" + "CombinedSpread" + |> runSolidCase "mergeProps splitProps and property spreading" + "OperatorsInProps" + |> runSolidCase "Property getters mixed with Operands are transformed" + "FieldGettersInComputations" + |> runSolidCase "Field getters and records are transformed" + "TagsAsValuesSimple" + |> runSolidCase "Tags can be used as values" + "FieldGetExpressionsTransformed" + |> runSolidCase "FieldGets like props.words.Length are transformed" + "SignalSetterInvoke" + |> runSolidCase "Signal Setters can be invoked with a handler" + "ExperimentalBuilders" + |> runSolidCase "Experimental Builders compile correct output" + "CssStyles" + |> runSolidCase "CssStyle definitions compiles correct output" + "ChildLambdaProvider" + |> runSolidCase "ChildLambdaProvider interfaces" + "SolidComponentAsTagValues" + |> runSolidCase "SolidComponent let bindings as TagValues" + "ValueUnrollerDecisionTree" + |> runSolidCase "Decision Trees in arrays do not spawn singleton instructions" ] + +[] +let AttributeCases = + testList + "AttributeCases" + [ "PartasImportAttr" + |> runAttributeCase "PartasImport Attribute" + "Pojo" + |> runAttributeCase "Pojo Optimisation" ] + +let runTanStackStoreCase name caseName = + let runTanStackStoreCase' caseName = + fun _ -> + built.Value + let folderName = "TanStackStoreCases" + runCase folderName caseName + + testCase name + <| runTanStackStoreCase' caseName + +[] +let TanStackStoreCases = + testList + "TanStackStoreCases" + [ "BasicStore" + |> runTanStackStoreCase "Basic Store Usage" + "UseStoreFull" + |> runTanStackStoreCase "useStoreFull hook" + "RecordState" + |> runTanStackStoreCase "Record type state" + "DerivedStore" + |> runTanStackStoreCase "Derived store" + "EffectStore" + |> runTanStackStoreCase "Effect store" + "Subscribe" + |> runTanStackStoreCase "Store subscribe/unsubscribe" + "StoreOptions" + |> runTanStackStoreCase "Store with updateFn and onUpdate options" + "BatchUpdates" + |> runTanStackStoreCase "Batch updates" + "DerivedPrevVal" + |> runTanStackStoreCase "Derived with prevVal" + "DerivedDepVals" + |> runTanStackStoreCase "Derived with prevDepVals/currDepVals" + "EffectEager" + |> runTanStackStoreCase "Effect with eager option" + "MountUnmount" + |> runTanStackStoreCase "Mount/unmount with cleanup" ] diff --git a/Partas.Solid.sln b/Partas.Solid.sln index 04b6e58..b551dd4 100644 --- a/Partas.Solid.sln +++ b/Partas.Solid.sln @@ -7,9 +7,9 @@ EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ScratchTests", "ScratchTests\ScratchTests.fsproj", "{D37CEC92-48BD-4872-8D8B-66721E37E85F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{18D88D48-EDE5-4FB6-8BC4-BE6602CA3871}" - ProjectSection(SolutionItems) = preProject - build.fsx = build.fsx - EndProjectSection + ProjectSection(SolutionItems) = preProject + build.fsx = build.fsx + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Src", "Src", "{44C0FC57-5623-45D9-8E50-84717E7246CA}" EndProject @@ -24,51 +24,108 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{6B45 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".environment", ".environment", "{6C4442D5-CCA1-4419-853E-04F17CF40674}" - ProjectSection(SolutionItems) = preProject - .gitignore = .gitignore - LICENSE.txt = LICENSE.txt - README.md = README.md - .editorconfig = .editorconfig - .config/dotnet-tools.json = .config/dotnet-tools.json - docs/RELEASE_NOTES.md = docs/RELEASE_NOTES.md - cliff.toml = cliff.toml - .cliffignore = .cliffignore - EndProjectSection + ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore + LICENSE.txt = LICENSE.txt + README.md = README.md + .editorconfig = .editorconfig + .config\dotnet-tools.json = .config\dotnet-tools.json + docs\RELEASE_NOTES.md = docs\RELEASE_NOTES.md + cliff.toml = cliff.toml + .cliffignore = .cliffignore + EndProjectSection EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Partas.Solid.Tests.Core", "Partas.Solid.Tests.Core\Partas.Solid.Tests.Core.fsproj", "{B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Partas.Solid.Tests.Plugin", "Partas.Solid.Tests.Plugin\Partas.Solid.Tests.Plugin.fsproj", "{3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Partas.Solid.TanStack.Store", "Partas.Solid.TanStack.Store\Partas.Solid.TanStack.Store.fsproj", "{B2A650F2-8401-43D1-B107-41B8361859DF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Debug|x64.ActiveCfg = Debug|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Debug|x64.Build.0 = Debug|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Debug|x86.ActiveCfg = Debug|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Debug|x86.Build.0 = Debug|Any CPU {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Release|Any CPU.ActiveCfg = Release|Any CPU {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Release|Any CPU.Build.0 = Release|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Release|x64.ActiveCfg = Release|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Release|x64.Build.0 = Release|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Release|x86.ActiveCfg = Release|Any CPU + {2360B137-35B4-4CC8-A004-E19DEC1D5759}.Release|x86.Build.0 = Release|Any CPU {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Debug|x64.ActiveCfg = Debug|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Debug|x64.Build.0 = Debug|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Debug|x86.ActiveCfg = Debug|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Debug|x86.Build.0 = Debug|Any CPU {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Release|Any CPU.ActiveCfg = Release|Any CPU {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Release|Any CPU.Build.0 = Release|Any CPU - {107B9E6E-5EF2-4ECA-91F1-11D3A7940D4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {107B9E6E-5EF2-4ECA-91F1-11D3A7940D4F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {107B9E6E-5EF2-4ECA-91F1-11D3A7940D4F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {107B9E6E-5EF2-4ECA-91F1-11D3A7940D4F}.Release|Any CPU.Build.0 = Release|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Release|x64.ActiveCfg = Release|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Release|x64.Build.0 = Release|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Release|x86.ActiveCfg = Release|Any CPU + {1AE69025-B907-4C3A-AB48-0093DB5070A4}.Release|x86.Build.0 = Release|Any CPU {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Debug|x64.ActiveCfg = Debug|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Debug|x64.Build.0 = Debug|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Debug|x86.ActiveCfg = Debug|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Debug|x86.Build.0 = Debug|Any CPU {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Release|Any CPU.Build.0 = Release|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Release|x64.ActiveCfg = Release|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Release|x64.Build.0 = Release|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Release|x86.ActiveCfg = Release|Any CPU + {D37CEC92-48BD-4872-8D8B-66721E37E85F}.Release|x86.Build.0 = Release|Any CPU {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Debug|x64.ActiveCfg = Debug|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Debug|x64.Build.0 = Debug|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Debug|x86.ActiveCfg = Debug|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Debug|x86.Build.0 = Debug|Any CPU {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Release|Any CPU.ActiveCfg = Release|Any CPU {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Release|Any CPU.Build.0 = Release|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Release|x64.ActiveCfg = Release|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Release|x64.Build.0 = Release|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Release|x86.ActiveCfg = Release|Any CPU + {B3D8EF27-8A7F-46A9-9E71-3AD47B666C60}.Release|x86.Build.0 = Release|Any CPU {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Debug|x64.ActiveCfg = Debug|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Debug|x64.Build.0 = Debug|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Debug|x86.ActiveCfg = Debug|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Debug|x86.Build.0 = Debug|Any CPU {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Release|Any CPU.Build.0 = Release|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Release|x64.ActiveCfg = Release|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Release|x64.Build.0 = Release|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Release|x86.ActiveCfg = Release|Any CPU + {3C3EE6AA-E4DB-4852-BBC9-620A3FD48CB4}.Release|x86.Build.0 = Release|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Debug|x64.ActiveCfg = Debug|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Debug|x64.Build.0 = Debug|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Debug|x86.ActiveCfg = Debug|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Debug|x86.Build.0 = Debug|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Release|Any CPU.Build.0 = Release|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Release|x64.ActiveCfg = Release|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Release|x64.Build.0 = Release|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Release|x86.ActiveCfg = Release|Any CPU + {B2A650F2-8401-43D1-B107-41B8361859DF}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {2360B137-35B4-4CC8-A004-E19DEC1D5759} = {44C0FC57-5623-45D9-8E50-84717E7246CA} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a68515f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "Partas.Solid", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}