floppy-disk 2.16.0 → 3.0.0-alpha.2
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/README.md +0 -835
- package/esm/index.d.mts +1 -0
- package/esm/index.mjs +1 -0
- package/esm/react/create-mutation.d.mts +135 -0
- package/esm/react/create-query.d.mts +319 -0
- package/esm/react/create-store.d.mts +25 -0
- package/esm/react/create-stores.d.mts +32 -0
- package/esm/react/use-isomorphic-layout-effect.d.mts +6 -0
- package/esm/react/use-store.d.mts +18 -0
- package/esm/react.d.mts +6 -0
- package/esm/react.mjs +503 -0
- package/esm/vanilla/basic.d.mts +21 -0
- package/esm/vanilla/hash.d.mts +7 -0
- package/esm/vanilla/shallow.d.mts +6 -0
- package/esm/vanilla/store.d.mts +75 -0
- package/esm/vanilla.d.mts +4 -0
- package/esm/vanilla.mjs +109 -0
- package/index.d.ts +1 -0
- package/index.js +12 -0
- package/package.json +50 -45
- package/react/create-mutation.d.ts +135 -0
- package/react/create-query.d.ts +319 -0
- package/react/create-store.d.ts +25 -0
- package/react/create-stores.d.ts +32 -0
- package/react/use-isomorphic-layout-effect.d.ts +6 -0
- package/react/use-store.d.ts +18 -0
- package/{lib/index.d.ts → react.d.ts} +2 -4
- package/react.js +511 -0
- package/ts_version_4.5_and_above_is_required.d.ts +0 -0
- package/vanilla/basic.d.ts +21 -0
- package/vanilla/hash.d.ts +7 -0
- package/vanilla/shallow.d.ts +6 -0
- package/vanilla/store.d.ts +75 -0
- package/vanilla.d.ts +4 -0
- package/vanilla.js +118 -0
- package/esm/fetcher.d.ts +0 -27
- package/esm/fetcher.js +0 -95
- package/esm/index.d.ts +0 -8
- package/esm/index.js +0 -8
- package/esm/react/create-bi-direction-query.d.ts +0 -166
- package/esm/react/create-bi-direction-query.js +0 -74
- package/esm/react/create-mutation.d.ts +0 -39
- package/esm/react/create-mutation.js +0 -56
- package/esm/react/create-query.d.ts +0 -319
- package/esm/react/create-query.js +0 -434
- package/esm/react/create-store.d.ts +0 -51
- package/esm/react/create-store.js +0 -38
- package/esm/react/create-stores.d.ts +0 -77
- package/esm/react/create-stores.js +0 -125
- package/esm/react/with-context.d.ts +0 -5
- package/esm/react/with-context.js +0 -14
- package/esm/store.d.ts +0 -24
- package/esm/store.js +0 -51
- package/esm/utils.d.ts +0 -24
- package/esm/utils.js +0 -31
- package/lib/fetcher.d.ts +0 -27
- package/lib/fetcher.js +0 -99
- package/lib/index.js +0 -11
- package/lib/react/create-bi-direction-query.d.ts +0 -166
- package/lib/react/create-bi-direction-query.js +0 -78
- package/lib/react/create-mutation.d.ts +0 -39
- package/lib/react/create-mutation.js +0 -60
- package/lib/react/create-query.d.ts +0 -319
- package/lib/react/create-query.js +0 -438
- package/lib/react/create-store.d.ts +0 -51
- package/lib/react/create-store.js +0 -42
- package/lib/react/create-stores.d.ts +0 -77
- package/lib/react/create-stores.js +0 -130
- package/lib/react/with-context.d.ts +0 -5
- package/lib/react/with-context.js +0 -18
- package/lib/store.d.ts +0 -24
- package/lib/store.js +0 -55
- package/lib/utils.d.ts +0 -24
- package/lib/utils.js +0 -39
- package/utils/package.json +0 -6
package/esm/vanilla.mjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const isClient = typeof window !== "undefined" && !("Deno" in window);
|
|
2
|
+
const noop = () => {
|
|
3
|
+
};
|
|
4
|
+
const identity = (value) => value;
|
|
5
|
+
const getValue = (valueOrComputeValueFn, ...params) => {
|
|
6
|
+
if (typeof valueOrComputeValueFn === "function") {
|
|
7
|
+
return valueOrComputeValueFn(...params);
|
|
8
|
+
}
|
|
9
|
+
return valueOrComputeValueFn;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const shallow = (a, b) => {
|
|
13
|
+
if (Object.is(a, b)) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (a instanceof Map && b instanceof Map) {
|
|
20
|
+
if (a.size !== b.size) return false;
|
|
21
|
+
for (const [key, value] of a) {
|
|
22
|
+
if (!Object.is(value, b.get(key))) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
if (a instanceof Set && b instanceof Set) {
|
|
29
|
+
if (a.size !== b.size) return false;
|
|
30
|
+
for (const value of a) {
|
|
31
|
+
if (!b.has(value)) return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
const keysA = Object.keys(a);
|
|
36
|
+
if (keysA.length !== Object.keys(b).length) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
40
|
+
if (!Object.prototype.hasOwnProperty.call(b, keysA[i]) || !Object.is(a[keysA[i]], b[keysA[i]])) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const hasObjectPrototype = (value) => {
|
|
48
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
49
|
+
};
|
|
50
|
+
const isPlainObject = (value) => {
|
|
51
|
+
if (!hasObjectPrototype(value)) return false;
|
|
52
|
+
const ctor = value.constructor;
|
|
53
|
+
if (typeof ctor === "undefined") return true;
|
|
54
|
+
const prot = ctor.prototype;
|
|
55
|
+
if (!hasObjectPrototype(prot)) return false;
|
|
56
|
+
if (!prot.hasOwnProperty("isPrototypeOf")) return false;
|
|
57
|
+
if (Object.getPrototypeOf(value) !== Object.prototype) return false;
|
|
58
|
+
return true;
|
|
59
|
+
};
|
|
60
|
+
const getHash = (value) => JSON.stringify(
|
|
61
|
+
value,
|
|
62
|
+
(_, val) => isPlainObject(val) ? Object.keys(val).sort().reduce((result, key) => {
|
|
63
|
+
result[key] = val[key];
|
|
64
|
+
return result;
|
|
65
|
+
}, {}) : val
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const initStore = (initialState, options = {}) => {
|
|
69
|
+
const {
|
|
70
|
+
onFirstSubscribe = noop,
|
|
71
|
+
onSubscribe = noop,
|
|
72
|
+
onUnsubscribe = noop,
|
|
73
|
+
onLastUnsubscribe = noop
|
|
74
|
+
} = options;
|
|
75
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
76
|
+
const getSubscribers = () => subscribers;
|
|
77
|
+
const subscribe = (subscriber) => {
|
|
78
|
+
subscribers.add(subscriber);
|
|
79
|
+
if (subscribers.size === 1) onFirstSubscribe(state, storeApi);
|
|
80
|
+
onSubscribe(state, storeApi);
|
|
81
|
+
return () => {
|
|
82
|
+
subscribers.delete(subscriber);
|
|
83
|
+
onUnsubscribe(state, storeApi);
|
|
84
|
+
if (subscribers.size === 0) onLastUnsubscribe(state, storeApi);
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
let state = initialState;
|
|
88
|
+
const getState = () => state;
|
|
89
|
+
const setState = (value) => {
|
|
90
|
+
const prevState = state;
|
|
91
|
+
const newValue = getValue(value, state);
|
|
92
|
+
for (const key in newValue) {
|
|
93
|
+
if (!Object.is(prevState[key], newValue[key])) {
|
|
94
|
+
state = { ...prevState, ...newValue };
|
|
95
|
+
[...subscribers].forEach((subscriber) => subscriber(state, prevState));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const storeApi = {
|
|
101
|
+
getState,
|
|
102
|
+
setState,
|
|
103
|
+
subscribe,
|
|
104
|
+
getSubscribers
|
|
105
|
+
};
|
|
106
|
+
return storeApi;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export { getHash, getValue, identity, initStore, isClient, isPlainObject, noop, shallow };
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'floppy-disk/vanilla';
|
package/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vanilla = require('floppy-disk/vanilla');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.keys(vanilla).forEach(function (k) {
|
|
8
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return vanilla[k]; }
|
|
11
|
+
});
|
|
12
|
+
});
|
package/package.json
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "floppy-disk",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
3
|
+
"description": "Lightweight, simple, and powerful state management library",
|
|
4
|
+
"private": false,
|
|
5
|
+
"version": "3.0.0-alpha.2",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"tag": "alpha"
|
|
8
|
+
},
|
|
5
9
|
"keywords": [
|
|
10
|
+
"utilities",
|
|
11
|
+
"store",
|
|
6
12
|
"state",
|
|
7
|
-
"manager",
|
|
8
|
-
"management",
|
|
9
13
|
"react",
|
|
10
14
|
"hooks",
|
|
11
|
-
"store",
|
|
12
|
-
"utilities",
|
|
13
15
|
"query"
|
|
14
16
|
],
|
|
15
17
|
"author": "Muhammad Afifudin",
|
|
@@ -24,59 +26,62 @@
|
|
|
24
26
|
"homepage": "https://github.com/afiiif/floppy-disk#readme",
|
|
25
27
|
"sideEffects": false,
|
|
26
28
|
"files": [
|
|
27
|
-
"
|
|
28
|
-
"esm/",
|
|
29
|
-
"utils/"
|
|
29
|
+
"**"
|
|
30
30
|
],
|
|
31
|
-
"main": "./
|
|
32
|
-
"
|
|
33
|
-
"
|
|
31
|
+
"main": "./index.js",
|
|
32
|
+
"types": "./index.d.ts",
|
|
33
|
+
"typesVersions": {
|
|
34
|
+
">=4.5": {
|
|
35
|
+
"esm/*": [
|
|
36
|
+
"esm/*"
|
|
37
|
+
],
|
|
38
|
+
"*": [
|
|
39
|
+
"*"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"*": {
|
|
43
|
+
"esm/*": [
|
|
44
|
+
"ts_version_4.5_and_above_is_required.d.ts"
|
|
45
|
+
],
|
|
46
|
+
"*": [
|
|
47
|
+
"ts_version_4.5_and_above_is_required.d.ts"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
34
51
|
"exports": {
|
|
35
52
|
"./package.json": "./package.json",
|
|
36
53
|
".": {
|
|
37
54
|
"import": {
|
|
38
|
-
"types": "./esm/index.d.
|
|
39
|
-
"default": "./esm/index.
|
|
40
|
-
},
|
|
41
|
-
"module": {
|
|
42
|
-
"types": "./esm/index.d.ts",
|
|
43
|
-
"default": "./esm/index.js"
|
|
55
|
+
"types": "./esm/index.d.mts",
|
|
56
|
+
"default": "./esm/index.mjs"
|
|
44
57
|
},
|
|
45
58
|
"default": {
|
|
46
|
-
"types": "./
|
|
47
|
-
"default": "./
|
|
59
|
+
"types": "./index.d.ts",
|
|
60
|
+
"default": "./index.js"
|
|
48
61
|
}
|
|
49
62
|
},
|
|
50
|
-
"
|
|
63
|
+
"./*": {
|
|
51
64
|
"import": {
|
|
52
|
-
"types": "./esm
|
|
53
|
-
"default": "./esm
|
|
54
|
-
},
|
|
55
|
-
"module": {
|
|
56
|
-
"types": "./esm/utils.d.ts",
|
|
57
|
-
"default": "./esm/utils.js"
|
|
65
|
+
"types": "./esm/*.d.mts",
|
|
66
|
+
"default": "./esm/*.mjs"
|
|
58
67
|
},
|
|
59
68
|
"default": {
|
|
60
|
-
"types": "
|
|
61
|
-
"default": "
|
|
69
|
+
"types": "./*.d.ts",
|
|
70
|
+
"default": "./*.js"
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
},
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"name": "experimental",
|
|
78
|
-
"prerelease": true
|
|
79
|
-
}
|
|
80
|
-
]
|
|
74
|
+
"packageManager": "pnpm@10.32.1",
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"@types/react": ">=17.0",
|
|
77
|
+
"react": ">=17.0"
|
|
78
|
+
},
|
|
79
|
+
"peerDependenciesMeta": {
|
|
80
|
+
"@types/react": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"react": {
|
|
84
|
+
"optional": true
|
|
85
|
+
}
|
|
81
86
|
}
|
|
82
87
|
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { type InitStoreOptions, type SetState } from 'floppy-disk/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> = {
|
|
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: any;
|
|
45
|
+
errorUpdatedAt: number;
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Configuration options for a mutation.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* Lifecycle callbacks are triggered for each execution.
|
|
52
|
+
*/
|
|
53
|
+
export type MutationOptions<TData, TVariable> = InitStoreOptions<MutationState<TData, TVariable>> & {
|
|
54
|
+
/**
|
|
55
|
+
* Called when the mutation succeeds.
|
|
56
|
+
*/
|
|
57
|
+
onSuccess?: (data: TData, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Called when the mutation fails.
|
|
60
|
+
*/
|
|
61
|
+
onError?: (error: any, variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Called after the mutation settles (either success or error).
|
|
64
|
+
*/
|
|
65
|
+
onSettled?: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => void;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Creates a mutation store for handling async operations that modify data.
|
|
69
|
+
*
|
|
70
|
+
* @param mutationFn - Async function that performs the mutation
|
|
71
|
+
* @param options - Optional configuration and lifecycle callbacks
|
|
72
|
+
*
|
|
73
|
+
* @returns A function that acts as both:
|
|
74
|
+
* - A React hook for subscribing to mutation state
|
|
75
|
+
* - A mutation controller (execute, reset, etc.)
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* - Mutations are **not cached** and only track the latest execution.
|
|
79
|
+
* - Designed for operations that change data (e.g. create, update, delete).
|
|
80
|
+
* - No retry mechanism is provided by default.
|
|
81
|
+
* - Each execution overwrites the previous state.
|
|
82
|
+
* - The mutation always resolves (never throws): the result contains either `data` or `error`.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const useCreateUser = createMutation(async (input) => {
|
|
86
|
+
* return api.createUser(input);
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* const { isPending } = useCreateUser();
|
|
90
|
+
* const result = await useCreateUser.execute({ name: 'John' });
|
|
91
|
+
*/
|
|
92
|
+
export declare const createMutation: <TData, TVariable = undefined>(mutationFn: (variable: TVariable, stateBeforeExecute: MutationState<TData, TVariable>) => Promise<TData>, options?: MutationOptions<TData, TVariable>) => (<TStateSlice = MutationState<TData, TVariable>>(selector?: (state: MutationState<TData, TVariable>) => TStateSlice) => TStateSlice) & {
|
|
93
|
+
subscribe: (subscriber: import("../vanilla.ts").Subscriber<MutationState<TData, TVariable>>) => () => void;
|
|
94
|
+
getSubscribers: () => Set<import("../vanilla.ts").Subscriber<MutationState<TData, TVariable>>>;
|
|
95
|
+
getState: () => MutationState<TData, TVariable>;
|
|
96
|
+
/**
|
|
97
|
+
* Manually updates the mutation state.
|
|
98
|
+
*
|
|
99
|
+
* @remarks
|
|
100
|
+
* - Intended for advanced use cases.
|
|
101
|
+
* - Prefer using provided mutation actions (`execute`, `reset`) instead.
|
|
102
|
+
*/
|
|
103
|
+
setState: (value: SetState<MutationState<TData, TVariable>>) => void;
|
|
104
|
+
/**
|
|
105
|
+
* Executes the mutation.
|
|
106
|
+
*
|
|
107
|
+
* @param variable - Input passed to the mutation function
|
|
108
|
+
*
|
|
109
|
+
* @returns A promise that always resolves with:
|
|
110
|
+
* - `{ data, variable }` on success
|
|
111
|
+
* - `{ error, variable }` on failure
|
|
112
|
+
*
|
|
113
|
+
* @remarks
|
|
114
|
+
* - If a mutation is already in progress, a warning is logged.
|
|
115
|
+
* - Concurrent executions are allowed but may lead to race conditions.
|
|
116
|
+
* - The promise never rejects to simplify async handling.
|
|
117
|
+
*/
|
|
118
|
+
execute: TVariable extends undefined ? () => Promise<{
|
|
119
|
+
variable: undefined;
|
|
120
|
+
data?: TData;
|
|
121
|
+
error?: any;
|
|
122
|
+
}> : (variable: TVariable) => Promise<{
|
|
123
|
+
variable: TVariable;
|
|
124
|
+
data?: TData;
|
|
125
|
+
error?: any;
|
|
126
|
+
}>;
|
|
127
|
+
/**
|
|
128
|
+
* Resets the mutation state back to its initial state.
|
|
129
|
+
*
|
|
130
|
+
* @remarks
|
|
131
|
+
* - Does not cancel any ongoing request.
|
|
132
|
+
* - If a request is still pending, its result may override the reset state.
|
|
133
|
+
*/
|
|
134
|
+
reset: () => void;
|
|
135
|
+
};
|