dev-react-microstore 4.0.0 → 5.0.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/README.md +101 -2
- package/dist/index.d.mts +85 -2
- package/dist/index.d.ts +85 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/example/README.md +54 -0
- package/example/eslint.config.js +28 -0
- package/example/index.html +13 -0
- package/example/package-lock.json +3382 -0
- package/example/package.json +29 -0
- package/example/public/index.html +98 -0
- package/example/public/vite.svg +1 -0
- package/example/src/App.css +613 -0
- package/example/src/App.tsx +34 -0
- package/example/src/assets/react.svg +1 -0
- package/example/src/components/Counter.tsx +112 -0
- package/example/src/components/CustomCompare.tsx +466 -0
- package/example/src/components/Logs.tsx +28 -0
- package/example/src/components/Search.tsx +38 -0
- package/example/src/components/ThemeToggle.tsx +25 -0
- package/example/src/components/TodoList.tsx +63 -0
- package/example/src/components/UserManager.tsx +68 -0
- package/example/src/index.css +68 -0
- package/example/src/main.tsx +10 -0
- package/example/src/store.ts +223 -0
- package/example/src/vite-env.d.ts +1 -0
- package/example/tsconfig.app.json +26 -0
- package/example/tsconfig.json +7 -0
- package/example/tsconfig.node.json +25 -0
- package/example/vite.config.ts +7 -0
- package/package.json +10 -3
- package/src/index.ts +247 -12
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { useStoreSelector } from '../../../src/index'
|
|
3
|
+
import store from '../store'
|
|
4
|
+
|
|
5
|
+
export default function TodoList() {
|
|
6
|
+
const { todos } = useStoreSelector(store, ['todos'])
|
|
7
|
+
const [todoText, setTodoText] = useState('')
|
|
8
|
+
|
|
9
|
+
const handleAddTodo = () => {
|
|
10
|
+
if (todoText.trim()) {
|
|
11
|
+
const newTodo = {
|
|
12
|
+
id: Date.now(),
|
|
13
|
+
text: todoText.trim(),
|
|
14
|
+
completed: false
|
|
15
|
+
}
|
|
16
|
+
store.set({ todos: [...todos, newTodo] })
|
|
17
|
+
setTodoText('')
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const handleToggleTodo = (id: number) => {
|
|
22
|
+
const updatedTodos = todos.map(todo =>
|
|
23
|
+
todo.id === id ? { ...todo, completed: !todo.completed } : todo
|
|
24
|
+
)
|
|
25
|
+
store.set({ todos: updatedTodos })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const handleDeleteTodo = (id: number) => {
|
|
29
|
+
const updatedTodos = todos.filter(todo => todo.id !== id)
|
|
30
|
+
store.set({ todos: updatedTodos })
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<section className="section">
|
|
35
|
+
<h3>📝 Todos</h3>
|
|
36
|
+
<div className="todo-form">
|
|
37
|
+
<input
|
|
38
|
+
type="text"
|
|
39
|
+
placeholder="Add a todo..."
|
|
40
|
+
value={todoText}
|
|
41
|
+
onChange={(e) => setTodoText(e.target.value)}
|
|
42
|
+
onKeyPress={(e) => e.key === 'Enter' && handleAddTodo()}
|
|
43
|
+
/>
|
|
44
|
+
<button onClick={handleAddTodo}>Add</button>
|
|
45
|
+
</div>
|
|
46
|
+
<div className="todo-list">
|
|
47
|
+
{todos.map(todo => (
|
|
48
|
+
<div key={todo.id} className={`todo-item ${todo.completed ? 'completed' : ''}`}>
|
|
49
|
+
<input
|
|
50
|
+
type="checkbox"
|
|
51
|
+
checked={todo.completed}
|
|
52
|
+
onChange={() => handleToggleTodo(todo.id)}
|
|
53
|
+
/>
|
|
54
|
+
<span className="todo-text">{todo.text}</span>
|
|
55
|
+
<button onClick={() => handleDeleteTodo(todo.id)} className="delete">
|
|
56
|
+
×
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
))}
|
|
60
|
+
</div>
|
|
61
|
+
</section>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import { useStoreSelector } from '../../../src/index'
|
|
3
|
+
import store from '../store'
|
|
4
|
+
|
|
5
|
+
export default function UserManager() {
|
|
6
|
+
const { userName: currentUserName, userEmail: currentUserEmail, isLoggedIn, userError } = useStoreSelector(store, ['userName', 'userEmail', 'isLoggedIn', 'userError'])
|
|
7
|
+
const [userName, setUserName] = useState('')
|
|
8
|
+
const [userEmail, setUserEmail] = useState('')
|
|
9
|
+
|
|
10
|
+
// Clear form on successful login
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (isLoggedIn && !userError) {
|
|
13
|
+
setUserName('')
|
|
14
|
+
setUserEmail('')
|
|
15
|
+
}
|
|
16
|
+
}, [isLoggedIn, userError])
|
|
17
|
+
|
|
18
|
+
const handleUserUpdate = () => {
|
|
19
|
+
store.set({
|
|
20
|
+
userName,
|
|
21
|
+
userEmail,
|
|
22
|
+
isLoggedIn: true
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const handleUserLogout = () => {
|
|
27
|
+
store.set({
|
|
28
|
+
userName: '',
|
|
29
|
+
userEmail: '',
|
|
30
|
+
isLoggedIn: false
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<section className="section">
|
|
36
|
+
<h3>👤 User Management (with persistence & transformation)</h3>
|
|
37
|
+
<div className="user-info">
|
|
38
|
+
{isLoggedIn ? (
|
|
39
|
+
<div>
|
|
40
|
+
<p><strong>Name:</strong> {currentUserName}</p>
|
|
41
|
+
<p><strong>Email:</strong> {currentUserEmail}</p>
|
|
42
|
+
<button onClick={handleUserLogout}>Logout</button>
|
|
43
|
+
</div>
|
|
44
|
+
) : (
|
|
45
|
+
<div className="user-form">
|
|
46
|
+
<input
|
|
47
|
+
type="text"
|
|
48
|
+
placeholder="Name"
|
|
49
|
+
value={userName}
|
|
50
|
+
onChange={(e) => setUserName(e.target.value)}
|
|
51
|
+
/>
|
|
52
|
+
<input
|
|
53
|
+
type="email"
|
|
54
|
+
placeholder="Email"
|
|
55
|
+
value={userEmail}
|
|
56
|
+
onChange={(e) => setUserEmail(e.target.value)}
|
|
57
|
+
/>
|
|
58
|
+
<button onClick={handleUserUpdate}>Login</button>
|
|
59
|
+
{userError && <div className="error-message">{userError}</div>}
|
|
60
|
+
<p className="help-text">
|
|
61
|
+
Names are normalized and emails are validated *
|
|
62
|
+
</p>
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
</div>
|
|
66
|
+
</section>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
color: rgba(255, 255, 255, 0.87);
|
|
8
|
+
background-color: #242424;
|
|
9
|
+
|
|
10
|
+
font-synthesis: none;
|
|
11
|
+
text-rendering: optimizeLegibility;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
a {
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
color: #646cff;
|
|
19
|
+
text-decoration: inherit;
|
|
20
|
+
}
|
|
21
|
+
a:hover {
|
|
22
|
+
color: #535bf2;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
margin: 0;
|
|
27
|
+
display: flex;
|
|
28
|
+
place-items: center;
|
|
29
|
+
min-width: 320px;
|
|
30
|
+
min-height: 100vh;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
h1 {
|
|
34
|
+
font-size: 3.2em;
|
|
35
|
+
line-height: 1.1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
button {
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
border: 1px solid transparent;
|
|
41
|
+
padding: 0.6em 1.2em;
|
|
42
|
+
font-size: 1em;
|
|
43
|
+
font-weight: 500;
|
|
44
|
+
font-family: inherit;
|
|
45
|
+
background-color: #1a1a1a;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
transition: border-color 0.25s;
|
|
48
|
+
}
|
|
49
|
+
button:hover {
|
|
50
|
+
border-color: #646cff;
|
|
51
|
+
}
|
|
52
|
+
button:focus,
|
|
53
|
+
button:focus-visible {
|
|
54
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@media (prefers-color-scheme: light) {
|
|
58
|
+
:root {
|
|
59
|
+
color: #213547;
|
|
60
|
+
background-color: #ffffff;
|
|
61
|
+
}
|
|
62
|
+
a:hover {
|
|
63
|
+
color: #747bff;
|
|
64
|
+
}
|
|
65
|
+
button {
|
|
66
|
+
background-color: #f9f9f9;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createStoreState, createPersistenceMiddleware, loadPersistedState } from '../../src/index';
|
|
2
|
+
|
|
3
|
+
// Define our app state interface
|
|
4
|
+
interface AppState {
|
|
5
|
+
count: number;
|
|
6
|
+
userName: string;
|
|
7
|
+
userEmail: string;
|
|
8
|
+
isLoggedIn: boolean;
|
|
9
|
+
userError: string;
|
|
10
|
+
theme: 'light' | 'dark';
|
|
11
|
+
todos: Array<{ id: number; text: string; completed: boolean }>;
|
|
12
|
+
searchResults: string[];
|
|
13
|
+
isSearching: boolean;
|
|
14
|
+
logs: Array<{ id: number; message: string; type: string; timestamp: string }>;
|
|
15
|
+
// Complex object for custom compare demo
|
|
16
|
+
gameState: {
|
|
17
|
+
player: {
|
|
18
|
+
name: string;
|
|
19
|
+
health: number;
|
|
20
|
+
mana: number;
|
|
21
|
+
level: number;
|
|
22
|
+
experience: number;
|
|
23
|
+
};
|
|
24
|
+
enemy: {
|
|
25
|
+
name: string;
|
|
26
|
+
health: number;
|
|
27
|
+
damage: number;
|
|
28
|
+
isAlive: boolean;
|
|
29
|
+
};
|
|
30
|
+
ui: {
|
|
31
|
+
showInventory: boolean;
|
|
32
|
+
showMap: boolean;
|
|
33
|
+
notifications: string[];
|
|
34
|
+
};
|
|
35
|
+
turn: 'player' | 'enemy';
|
|
36
|
+
isProcessingTurn: boolean;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Load persisted state
|
|
41
|
+
const persistedState = loadPersistedState<AppState>(
|
|
42
|
+
localStorage,
|
|
43
|
+
'microstore-example',
|
|
44
|
+
['userName', 'userEmail', 'isLoggedIn', 'theme']
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Create store with initial state merged with persisted state
|
|
48
|
+
const store = createStoreState<AppState>({
|
|
49
|
+
count: 0,
|
|
50
|
+
userName: '',
|
|
51
|
+
userEmail: '',
|
|
52
|
+
isLoggedIn: false,
|
|
53
|
+
userError: '',
|
|
54
|
+
theme: 'light',
|
|
55
|
+
...persistedState, // Apply persisted state
|
|
56
|
+
todos: [],
|
|
57
|
+
searchResults: [],
|
|
58
|
+
isSearching: false,
|
|
59
|
+
logs: [],
|
|
60
|
+
// Complex object for custom compare demo
|
|
61
|
+
gameState: {
|
|
62
|
+
player: {
|
|
63
|
+
name: 'Player 1',
|
|
64
|
+
health: 100,
|
|
65
|
+
mana: 50,
|
|
66
|
+
level: 1,
|
|
67
|
+
experience: 0
|
|
68
|
+
},
|
|
69
|
+
enemy: {
|
|
70
|
+
name: 'Goblin',
|
|
71
|
+
health: 30,
|
|
72
|
+
damage: 5,
|
|
73
|
+
isAlive: true
|
|
74
|
+
},
|
|
75
|
+
ui: {
|
|
76
|
+
showInventory: false,
|
|
77
|
+
showMap: false,
|
|
78
|
+
notifications: []
|
|
79
|
+
},
|
|
80
|
+
turn: 'player',
|
|
81
|
+
isProcessingTurn: false
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Persistence
|
|
86
|
+
store.addMiddleware(createPersistenceMiddleware(localStorage, 'microstore-example', ['userName', 'userEmail', 'isLoggedIn', 'theme']));
|
|
87
|
+
|
|
88
|
+
// Block negative counts
|
|
89
|
+
store.addMiddleware((state, update, next) => {
|
|
90
|
+
if (update.count !== undefined && update.count < 0) {
|
|
91
|
+
addLog(`Blocked: ${formatValue(state.count)} → ${formatValue(update.count)}`, 'error');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
next();
|
|
95
|
+
}, ['count']);
|
|
96
|
+
|
|
97
|
+
// Email validation
|
|
98
|
+
store.addMiddleware((state, update, next) => {
|
|
99
|
+
if (update.userEmail && !update.userEmail.includes('@')) {
|
|
100
|
+
addLog(`Blocked: ${formatValue(state.userEmail)} → ${formatValue(update.userEmail)}`, 'error');
|
|
101
|
+
next({ userError: 'Invalid email format' });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (update.userEmail !== undefined) {
|
|
105
|
+
next({ ...update, userError: '' });
|
|
106
|
+
} else {
|
|
107
|
+
next();
|
|
108
|
+
}
|
|
109
|
+
}, ['userEmail']);
|
|
110
|
+
|
|
111
|
+
// Auto-normalize user data
|
|
112
|
+
store.addMiddleware((_, update, next) => {
|
|
113
|
+
const mod = { ...update };
|
|
114
|
+
let changed = false;
|
|
115
|
+
|
|
116
|
+
if (update.userName) {
|
|
117
|
+
const norm = update.userName.trim().toUpperCase();
|
|
118
|
+
if (norm !== update.userName) { mod.userName = norm; changed = true; }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (update.userEmail) {
|
|
122
|
+
const norm = update.userEmail.trim().toLowerCase();
|
|
123
|
+
if (norm !== update.userEmail) { mod.userEmail = norm; changed = true; }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (changed) addLog('Transform: name/email normalized', 'info');
|
|
127
|
+
next(mod);
|
|
128
|
+
}, ['userName', 'userEmail']);
|
|
129
|
+
|
|
130
|
+
// Log all changes
|
|
131
|
+
store.addMiddleware((state, update, next) => {
|
|
132
|
+
Object.keys(update).filter(k => k !== 'logs').forEach(key => {
|
|
133
|
+
const before = state[key as keyof AppState];
|
|
134
|
+
const after = update[key as keyof AppState];
|
|
135
|
+
if (JSON.stringify(before) !== JSON.stringify(after)) {
|
|
136
|
+
addLog(`${key}: ${formatValue(before)} → ${formatValue(after)}`, 'info');
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
next();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Helper function to format values for display
|
|
143
|
+
function formatValue(value: unknown): string {
|
|
144
|
+
if (value === null) return 'null';
|
|
145
|
+
if (value === undefined) return 'undefined';
|
|
146
|
+
if (typeof value === 'string') return `"${value}"`;
|
|
147
|
+
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
148
|
+
if (Array.isArray(value)) return `[${value.length} items]`;
|
|
149
|
+
if (typeof value === 'object') {
|
|
150
|
+
try {
|
|
151
|
+
const str = JSON.stringify(value, null, 2);
|
|
152
|
+
const lines = str.split('\n');
|
|
153
|
+
if (lines.length > 5) {
|
|
154
|
+
return lines.slice(0, 4).join('\n') + '\n ...\n}';
|
|
155
|
+
}
|
|
156
|
+
return str;
|
|
157
|
+
} catch {
|
|
158
|
+
return '{object}';
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return String(value);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Mock search function
|
|
165
|
+
function performSearch(query: string): string[] {
|
|
166
|
+
const mockData = [
|
|
167
|
+
'JavaScript', 'TypeScript', 'React', 'Vue', 'Angular', 'Node.js',
|
|
168
|
+
'Express', 'MongoDB', 'PostgreSQL', 'Redis', 'Docker', 'Kubernetes'
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
if (!query.trim()) return [];
|
|
172
|
+
|
|
173
|
+
return mockData.filter(item =>
|
|
174
|
+
item.toLowerCase().includes(query.toLowerCase())
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Search functionality with debouncing
|
|
179
|
+
export function updateSearchQuery(query: string) {
|
|
180
|
+
// Check current state
|
|
181
|
+
const {isSearching} = store.select(['isSearching']);
|
|
182
|
+
const results = performSearch(query);
|
|
183
|
+
|
|
184
|
+
if(!query){
|
|
185
|
+
store.set({
|
|
186
|
+
searchResults: [],
|
|
187
|
+
isSearching: false
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if(!isSearching) {
|
|
193
|
+
store.set({
|
|
194
|
+
isSearching: query.length > 0
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Debounced search execution (300ms delay)
|
|
199
|
+
store.set({
|
|
200
|
+
searchResults: results,
|
|
201
|
+
isSearching: false
|
|
202
|
+
}, 300);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Helper function to add logs to store
|
|
206
|
+
let logCounter = 0;
|
|
207
|
+
function addLog(message: string, type: string = 'info') {
|
|
208
|
+
const currentState = store.get();
|
|
209
|
+
const newLog = {
|
|
210
|
+
id: Date.now() + (++logCounter), // Ensure unique IDs
|
|
211
|
+
message,
|
|
212
|
+
type,
|
|
213
|
+
timestamp: new Date().toLocaleTimeString()
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Keep only last 50 logs
|
|
217
|
+
const newLogs = [...currentState.logs, newLog].slice(-50);
|
|
218
|
+
|
|
219
|
+
// Update logs without triggering middleware (direct state update)
|
|
220
|
+
store.set({ logs: newLogs });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export default store;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
4
|
+
"target": "ES2020",
|
|
5
|
+
"useDefineForClassFields": true,
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
|
|
10
|
+
/* Bundler mode */
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"verbatimModuleSyntax": true,
|
|
14
|
+
"moduleDetection": "force",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"jsx": "react-jsx",
|
|
17
|
+
|
|
18
|
+
/* Linting */
|
|
19
|
+
"strict": true,
|
|
20
|
+
"noUnusedLocals": true,
|
|
21
|
+
"noUnusedParameters": true,
|
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
|
23
|
+
"noUncheckedSideEffectImports": true
|
|
24
|
+
},
|
|
25
|
+
"include": ["src"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"moduleDetection": "force",
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
|
|
16
|
+
/* Linting */
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"noUnusedParameters": true,
|
|
20
|
+
"erasableSyntaxOnly": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
"noUncheckedSideEffectImports": true
|
|
23
|
+
},
|
|
24
|
+
"include": ["vite.config.ts"]
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dev-react-microstore",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "A minimal global state manager for React with fine-grained subscriptions.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/OhadBaehr/react-microstore.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/OhadBaehr/react-microstore",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/OhadBaehr/react-microstore/issues"
|
|
14
|
+
},
|
|
7
15
|
"scripts": {
|
|
8
16
|
"build": "tsup src/index.ts --format esm,cjs --dts --minify",
|
|
9
17
|
"prepare": "npm run build"
|
|
@@ -21,8 +29,7 @@
|
|
|
21
29
|
"author": "Ohad Baehr",
|
|
22
30
|
"license": "MIT",
|
|
23
31
|
"peerDependencies": {
|
|
24
|
-
"react": ">=17.0.0"
|
|
25
|
-
"react-dom": ">=17.0.0"
|
|
32
|
+
"react": ">=17.0.0"
|
|
26
33
|
},
|
|
27
34
|
"devDependencies": {
|
|
28
35
|
"@types/react": "^19.1.2",
|