yuustate 0.0.1 → 3.10.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Muhammad Afifudin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -7,8 +7,97 @@ Inspired by [Zustand](https://zustand.docs.pmnd.rs) & [TanStack-Query](https://t
7
7
 
8
8
  _Fine-grained reactivity, minimal boilerplate, zero dependencies._
9
9
 
10
+ Demo: https://afiiif.github.io/yuustate/
11
+
12
+ **Installation:**
13
+
14
+ ```
15
+ npm install yuustate
16
+ ```
17
+
18
+ **Read the docs → https://yuustate.vercel.app**
19
+
20
+ <br>
21
+
22
+ ---
23
+
24
+ **Like Zustand, but has additional capabilities:**
25
+ - No selectors: automatically optimizes re-renders
26
+ - Store events: `onFirstSubscribe`, `onSubscribe`, `onUnsubscribe`, `onLastUnsubscribe`
27
+ - Easier to set initial state on SSR/SSG
28
+ - Smaller bundle
29
+
30
+ **Like TanStack Query, but:**
31
+ - DX is very similar to Zustand → One mental model for sync & async
32
+ - Much smaller bundle than TanStack Query → With nearly the same capabilities
33
+
34
+ ---
35
+
36
+ <br>
37
+
38
+ ## Store (Global State)
39
+
40
+ A store is a global state container that can be used both **inside and outside** React.\
41
+ With YuuState, creating a store is simple:
42
+
43
+ ```tsx
44
+ import { createStore } from "yuustate/react";
45
+
46
+ const useLawn = createStore({
47
+ plants: 3,
48
+ zombies: 1,
49
+ });
50
+ ```
51
+
52
+ Use it inside a component:
53
+
54
+ ```tsx
55
+ function MyPlants() {
56
+ const { plants } = useLawn(); // No selectors needed.
57
+
58
+ return <div>Plants: {plants}</div>; // Only re-render when plants state changes
59
+ }
60
+ ```
61
+
62
+ Update the state **anywhere**:
63
+
64
+ ```tsx
65
+ const addPlant = () => {
66
+ useLawn.setState(prev => ({ plants: prev.plants + 1 }));
67
+ };
68
+ ```
69
+
70
+ ## Query Store for Async State
71
+
72
+ Create a query store for async data with `createQuery`:
73
+
74
+ ```tsx
75
+ import { createQuery } from "yuustate/react";
76
+
77
+ const plantDetailQuery = createQuery(
78
+ async ({ id }) => {
79
+ const res = await fetch(`/api/plants/${id}`);
80
+ return res.json();
81
+ },
82
+ );
83
+ ```
84
+
85
+ Use it in your component:
86
+
87
+ ```tsx
88
+ function PlantDetail({ id }) {
89
+ const usePlantDetailQuery = plantDetailQuery({ id });
90
+ const { data, error } = usePlantDetailQuery();
91
+
92
+ if (!data && !error) return <div>Loading...</div>;
93
+ if (error) return <div>Error: {error.message}</div>;
94
+
95
+ return <div>Name: {data.name}, damage: {data.damage}</div>;
96
+ }
97
+ ```
98
+
99
+ <br>
100
+
10
101
  ---
11
102
 
12
- This package is the rebranded version of [floppy-disk](https://www.npmjs.com/package/floppy-disk).\
13
- While the name has changed, the API and functionality remain the same.
14
- Simply update your dependencies and imports to start using the new package.
103
+ Read the docs → https://yuustate.vercel.app
@@ -0,0 +1 @@
1
+ export * from "yuustate/vanilla";
package/esm/index.mjs ADDED
@@ -0,0 +1 @@
1
+ export * from 'yuustate/vanilla';
@@ -0,0 +1,143 @@
1
+ import { type InitStoreOptions, type SetStateInput } from "yuustate/vanilla";
2
+ /**
3
+ * Represents the state of a mutation.
4
+ *
5
+ * @remarks
6
+ * A mutation does not cache results and only tracks the latest execution.
7
+ *
8
+ * The state transitions are:
9
+ * - `INITIAL` → before any execution
10
+ * - `SUCCESS` → when mutation resolves successfully
11
+ * - `ERROR` → when mutation fails
12
+ *
13
+ * Unlike queries:
14
+ * - No retry mechanism
15
+ * - No caching across executions
16
+ */
17
+ export type MutationState<TData, TVariable, TError> = {
18
+ isPending: boolean;
19
+ } & ({
20
+ state: "INITIAL";
21
+ isSuccess: false;
22
+ isError: false;
23
+ variable: undefined;
24
+ data: undefined;
25
+ dataUpdatedAt: undefined;
26
+ error: undefined;
27
+ errorUpdatedAt: undefined;
28
+ } | {
29
+ state: "SUCCESS";
30
+ isSuccess: true;
31
+ isError: false;
32
+ variable: TVariable;
33
+ data: TData;
34
+ dataUpdatedAt: number;
35
+ error: undefined;
36
+ errorUpdatedAt: undefined;
37
+ } | {
38
+ state: "ERROR";
39
+ isSuccess: false;
40
+ isError: true;
41
+ variable: TVariable;
42
+ data: undefined;
43
+ dataUpdatedAt: undefined;
44
+ error: TError;
45
+ errorUpdatedAt: number;
46
+ });
47
+ export declare const INITIAL_STATE: MutationState<any, any, any>;
48
+ /**
49
+ * Configuration options for a mutation.
50
+ *
51
+ * @remarks
52
+ * Lifecycle callbacks are triggered for each execution.
53
+ */
54
+ export type MutationOptions<TData, TVariable, TError = Error> = InitStoreOptions<MutationState<TData, TVariable, TError>> & {
55
+ /**
56
+ * Called when the mutation succeeds.\
57
+ * If multiple concurrent executions happened, only the latest execution triggers this callback.
58
+ */
59
+ onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => void;
60
+ /**
61
+ * Called when the mutation fails.\
62
+ * If multiple concurrent executions happened, only the latest execution triggers this callback.
63
+ */
64
+ onError?: (error: TError, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => void;
65
+ /**
66
+ * Called after the mutation settles (either success or error).\
67
+ * If multiple concurrent executions happened, only the latest execution triggers this callback.
68
+ */
69
+ onSettled?: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => void;
70
+ };
71
+ /**
72
+ * Creates a mutation store for handling async operations that modify data.
73
+ *
74
+ * @param mutationFn - Async function that performs the mutation
75
+ * @param options - Optional configuration and lifecycle callbacks
76
+ *
77
+ * @returns A function that acts as both:
78
+ * - A React hook for subscribing to mutation state
79
+ * - A mutation controller (execute, reset, etc.)
80
+ *
81
+ * @remarks
82
+ * - Mutations are **not cached** and only track the latest execution.
83
+ * - Designed for operations that change data (e.g. create, update, delete).
84
+ * - No retry mechanism is provided by default.
85
+ * - The mutation always resolves (never throws): the result contains either `data` or `error`.
86
+ * - If multiple executions triggered at the same time:
87
+ * - Only the latest execution is allowed to update the state.
88
+ * - Results from previous executions are ignored if a newer one exists.
89
+ *
90
+ * @example
91
+ * const useCreateUser = createMutation(async (input) => {
92
+ * return api.createUser(input);
93
+ * });
94
+ *
95
+ * const { isPending } = useCreateUser();
96
+ * const result = await useCreateUser.execute({ name: 'John' });
97
+ *
98
+ * @see https://yuustate.vercel.app/docs/mutation
99
+ */
100
+ export declare const createMutation: <TData, TVariable = undefined, TError = Error>(mutationFn: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable, TError>) => Promise<TData>, options?: MutationOptions<TData, TVariable, TError>) => (() => MutationState<TData, TVariable, TError>) & {
101
+ subscribe: (subscriber: import("../vanilla.d.mts").Subscriber<MutationState<TData, TVariable, TError>>) => () => void;
102
+ getSubscriberCount: () => number;
103
+ getState: () => MutationState<TData, TVariable, TError>;
104
+ /**
105
+ * Manually updates the mutation state.
106
+ *
107
+ * @remarks
108
+ * - Intended for advanced use cases.
109
+ * - Prefer using provided mutation actions (`execute`, `reset`) instead.
110
+ */
111
+ setState: (value: SetStateInput<MutationState<TData, TVariable, TError>>) => void;
112
+ /**
113
+ * Executes the mutation.
114
+ *
115
+ * @param variable - Input passed to the mutation function
116
+ *
117
+ * @returns A promise that always resolves with:
118
+ * - `{ data, variable }` on success
119
+ * - `{ error, variable }` on failure
120
+ *
121
+ * @remarks
122
+ * - The promise never rejects to simplify async handling.
123
+ * - If a mutation is already in progress, a warning is logged.
124
+ * - When a new execution starts, all previous pending executions will resolve with the result of the latest execution.
125
+ */
126
+ execute: TVariable extends undefined ? () => Promise<{
127
+ variable: undefined;
128
+ data?: TData;
129
+ error?: TError;
130
+ }> : (variable: TVariable) => Promise<{
131
+ variable: TVariable;
132
+ data?: TData;
133
+ error?: TError;
134
+ }>;
135
+ /**
136
+ * Resets the mutation state back to its initial state.
137
+ *
138
+ * @remarks
139
+ * - Does not cancel any ongoing execution.
140
+ * - If an execution is still pending, its result may override the reset state.
141
+ */
142
+ reset: () => void;
143
+ };