Skip to content

Commit

Permalink
feat(store): add strong types to provider for stores with input and a…
Browse files Browse the repository at this point in the history
…dd improved create options
  • Loading branch information
DawidWraga committed Apr 19, 2024
1 parent 850a194 commit 17a5772
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 25 deletions.
38 changes: 23 additions & 15 deletions packages/store/src/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,16 @@ export const store = <TState extends State>(
return storeApi;
},

name: (newName: string) => {
identify: (newName: string) => {
Object.assign(_def.options, { name: newName });
return storeApi;
},

devtools: (enabled = true) => {
Object.assign(_def.options, { devtools: { enabled } });
return storeApi;
},

/**
* extend based methods:
*/
Expand Down Expand Up @@ -138,23 +143,26 @@ export const store = <TState extends State>(
return storeApi as unknown as StoreApi<TState>;
};

type StoreProviderProps<TState, TInput> = {
initialValue?: Partial<TState> & TInput;
children: React.ReactNode;
};

export function createStoreContext<
TState extends State,
TExtensions extends object,
>(store: StoreApi<TState, TExtensions>) {
const Context = React.createContext<StoreApi<TState, TExtensions> | null>(
null
);

const Provider = ({
children,
initialValue: localInitialValue = {},
}: {
initialValue?: Partial<TState>;
children: React.ReactNode;
}) => {
const storeInstance = React.useRef<StoreApi<TState, TExtensions>>(
store.create(localInitialValue as TState)
TInput extends Record<string, any> = {},
>(store: StoreApi<TState, TExtensions, TInput>) {
const Context = React.createContext<StoreApi<
TState,
TExtensions,
TInput
> | null>(null);

const Provider = (props: StoreProviderProps<TState, TInput>) => {
const { children, initialValue: localInitialValue } = props;
const storeInstance = React.useRef<StoreApi<TState, TExtensions, TInput>>(
store.create(localInitialValue)
);

React.useEffect(() => {
Expand Down
10 changes: 10 additions & 0 deletions packages/store/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ export type StoreBuilderMethods<
> = {
_def: StoreDef<TState, TExtendedProps>;

identify: (newName: string) => StoreApi<TState, TExtendedProps, TInput>;

/**
*
* @param enabled enable or disable devtools
* @default true
*
*/
devtools: (enabled?: boolean) => StoreApi<TState, TExtendedProps, TInput>;

input: <TNewInput extends Record<string, any>>(
initialInput: TNewInput
) => StoreApi<TState, TExtendedProps, TNewInput>;
Expand Down
9 changes: 0 additions & 9 deletions packages/store/src/utils/create-inner-store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,18 @@ import { createStore as createVanillaStore } from 'zustand/vanilla';

import { immerMiddleware } from '../middlewares/immer.middleware';
import {
EffectBuilder,
ImmerStoreApi,
SetImmerState,
State,
StoreApi,
StoreDef,
} from '../types';
import { StoreOptions } from '../types/CreateStoreOptions';
import { pipe } from '../utils/pipe';

import React from 'react';
import type { StateCreator } from 'zustand';
import {
createComputedMethods,
ComputedBuilder,
ComputedProps,
} from '../utils/create-computed-methods';

import { subscribeWithSelector } from 'zustand/middleware';
import { createMethodsProxy } from '../utils/create-methods-proxy';
import { createSplitProps } from './split-props';
/** creates the internal store with middlwares */
export const createInnerStore = <TState extends State>(
storeDef: StoreDef<TState>
Expand Down
4 changes: 3 additions & 1 deletion packages/store/test/store-builder.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, test, vi } from 'vitest';
import { store } from '../src';
import { createStoreContext, store } from '../src';

describe('should access and update the entire state', () => {
const countStoreBuilder = store().state({
Expand Down Expand Up @@ -103,6 +103,8 @@ describe('should access and update the entire state + INPUT METHODS', () => {

const countStore = countStoreBuilder.create();

const countStoreCtx = createStoreContext(countStoreBuilder);

test('get', () => {
const counterValues = countStore.count.get();

Expand Down
63 changes: 63 additions & 0 deletions packages/store/test/store-options.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { describe, expect, test, vi } from 'vitest';
import { createStoreContext, store } from '../src';

describe('should access and update the entire state', () => {
const countStoreBuilder = store()
.identify('countStore')
.devtools()
.input({ setting: false })
.state({
count: 2,
})
.computed((store) => ({
doubled: () => store.count.get() * 2,
}))
.actions((store) => ({
increment() {
store.count.set(store.count.get() + 1);
},
decrement() {
store.count.set(store.count.get() - 1);
},
}))
.effects((store) => ({
log: () => store.onChange(console.log),
}));

const countStore = countStoreBuilder.create();

const countStoreCtx = createStoreContext(countStoreBuilder);

test('get', () => {
const counterValues = countStore.count.get();

expect(counterValues).toBe(2);
});

test('set', () => {
countStore.count.set(10);

expect(countStore.count.get()).toBe(10);
});

test('assign', () => {
// console.log('INSIDE ASSIGN NESTED OBJ: ', countStore);
countStore.assign({
count: 30,
});

expect(countStore.get()).toStrictEqual({
count: 30,
});
});

test('input', () => {
expect(countStore.setting).toBe(false);
});
test('input with different instnes', () => {
const countStore2 = countStoreBuilder.create({ setting: true });

expect(countStore.setting).toBe(false);
expect(countStore2.setting).toBe(true);
});
});

0 comments on commit 17a5772

Please sign in to comment.