Releases: riccardoperra/statebuilder
statebuilder@0.6.1
Patch Changes
- 46892dd: add before event to command plugin
statebuilder@0.6.0
Minor Changes
- 3ce5a15: - States will now get resolved using their Container reactive context instead of the context where they are defined.
- Errors thrown through the state lifecycle will return a
StateBuilderError
class. - Add the
remove
method to the Container API to destroy a state - Add container hierarchy
- Export
ɵdefineResource
andɵWithResourceStorage
state resource API
- Errors thrown through the state lifecycle will return a
statebuilder@0.5.0
Minor Changes
-
8d627ba: feat: allow to inject states inside builders
Since this version, you can inject other states into plugins (
.extend
).const AppState = defineSignal(() => ({})); const CounterState = defineSignal(() => 1).extend((_, context) => { const appState = context.inject(AppState); });
statebuilder@0.4.3
statebuilder@0.4.2
What's Changed
- missing esm exports in statebuilder package
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/statebuilder@0.4.0...statebuilder@0.4.2
statebuilder@0.4.1
What's Changed
- fix: refactor command listener with @solid-primitives/event-bus by @riccardoperra in #23
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/statebuilder@0.4.0...statebuilder@0.4.1
statebuilder@0.4.0
What's new
State plugin hooks - #20
With statebuilder@0.4.0, the core system will now support some initialization hooks
under the hood:
- onInit: it runs when your store state initialises, after all given plugins have been applied.
- onDestroy: it runs when the reactive owner is disposed.
You can access these hooks while creating a plugin or while defining a store extension through the .extend()
method. Hooks are basically registered callbacks in a queue system and they will be applied in order.
const myPlugin = makePlugin((state, context) => {
context.hooks.onInit(() => console.log('run on state init'));
context.hooks.onDestroy(() => console.log('run on state destroy'));
}, { name: 'myPlugin' });
createRoot(dispose => {
const container = Container.create();
const CountState = defineSignal(() => 0)
.extend(myPlugin);
const count = container.get(CountState);
// ✅ onInit hook will run
container.get(CountState);
// ❌ onInit hook will not run anymore: state is already initialised
dispose();
// ✅ onDestroy hook will run
})
State support for solid-js createResource
- #22
This new version add support for creating StateBuilders state definitions using solid-js createResource
under the hood. It's now marked as experimental feature.
The state built with this new api will return basically a Resource which uses the mutate
function under the hood as store setter
. It acts like a wrapper but with the support of StateBuilder plugin extension and hook system.
import { experimental__defineResource } from 'statebuilder';
const TodoAsyncState = experimental__defineResource(
() => fetch('https://jsonplaceholder.typicode.com/todos/1').then(response => response.json())
).extend(() => {
// ...
});
const todoState = container.get(TodoAsyncState);
// ˆ? todoState: Resource<Todo> & { set: Setter<Todo>, refetch(init?: unknown): void }
statebuilder/commands drop support for RxJS - #17
Since this version, the command
plugin will not use anymore RxJS to handle the command event state. Instead, it will use directly the solid-js signal based system.
Since Solid handle signals like RxJS BehaviorSubject
, and the previous implementation had an attached Subject
under the hood, the code for watching the commands events should change.
Since the watchCommand
method will now return an Accessor<Command>
instead of a BehaviorSubject
, In order to avoid to run the callback before receiving your watched commands, you can mix the createEffect
with the on
utility.
Before:
interface Commands {
add: number;
}
const CountStore = defineSignal(() => 0)
.extend(withProxyCommands<Commands>())
.extend(state => {
const watch$ = state.watchCommand([state.commands.add]);
// ˆ? watch$: Observable<StateCommand<'add', number>>
watch$.subscribe((x) => console.log(x))
})
After:
import {createEffect, on} from 'solid-js';
interface Commands {
add: number;
}
const CountStore = defineSignal(() => 0)
.extend(withProxyCommands<Commands>())
.extend(state => {
const watched = state.watchCommand([state.commands.add]);
// ˆ? watched: Accessor<StateCommand<'add', number>>
createEffect(on(watched, command => {
console.log(command);
}))
})
What's Changed
- perf: refactor commands plugin removing RxJS by @riccardoperra in #17
- feat: add store definition init/destroy hooks. support local owner by @riccardoperra in #20
- test: hooks by @riccardoperra in #21
- feat: command devtools by @riccardoperra in #19
- feat: store resource by @riccardoperra in #22
- chore: update versions by @github-actions in #18
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/statebuilder@0.3.1...statebuilder@0.4.0
statebuilder@0.3.1
Patch Changes
- 16fffae: perf: improve type resolution performance
statebuilder@0.3.0
Breaking changes
This new version removes withPlugin
introduced in 0.2.4. Instead, now plugins will infer automatically the type, and uses a generic signatureby default.
const store = defineSignal(() => 1).extend(
withProxyCommands<{increment: boolean}>())
);
store.hold(
store.commands.increment,
(command, { set }) => {
// ✅ Now `set` is Setter<number> instead of (...args: any) => void
set(v => v + 1);
});
Create plugins with store constraints
In order to create plugins that must follow a specific store signature, you can now use the .typed
helper of makePlugin function.
const pluginOnlyForStoreLike = () => makePlugin.typed<Store<{ count: number }>>()(store => {
// ...
});
// ❌ pluginOnlyForStoreLike cannot be used anymore since store does not follow the { count : number } state signature
const store1 = defineStore(0).extend(pluginOnlyForStoreLike())
What's Changed
- feat: refactor types for implicit inference by @riccardoperra in #13
- chore: update versions by @github-actions in #14
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/statebuilder@0.2.4...statebuilder@0.3.0
statebuilder@0.2.4
What's Changed
- perf: improve types and documentation by @riccardoperra in #9
- perf: remove symbol overhead by @riccardoperra in #11
- chore: update versions by @github-actions in #10
Better store typings with store context
This new version introduces withPlugin
, a new utility that can be used to be able to type plugins with the current store, instead of the GenericStoreApi
alias. This can be useful when some generic plugins uses the get/setter store api and take advanted of its types to create derived properties
import {defineSignal, withPlugin} from 'statebuilder';
import {withProxyCommands} from 'statebuilder/commands';
const store = defineSignal(() => 1).extend(
withPlugin((ctx) =>
withProxyCommands.of(ctx).with<{ increment: boolean }>(),
),
);
store.hold(
store.commands.increment,
(command, { set }) => {
// ✅ Now `set` is Setter<number> instead of (...args: any) => void
set(v => v + 1);
});
Full Changelog: https://github.com/riccardoperra/statebuilder/compare/statebuilder@0.2.3...statebuilder@0.2.4