mates 0.0.2 โ†’ 0.0.3

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.
Files changed (2) hide show
  1. package/README.md +356 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -0,0 +1,356 @@
1
+ # ๐Ÿงช Mates
2
+
3
+ **Mates** is a lightweight, reactive state management framework for web applications that makes managing state a breeze! Think React hooks, but for any framework (or no framework at all)!
4
+
5
+ ## ๐Ÿš€ Features
6
+
7
+ - ๐Ÿ”„ **Reactive State**: Automatic UI updates when state changes
8
+ - ๐Ÿงฉ **Composable**: Mix and match different state types
9
+ - ๐Ÿ” **Transparent**: See exactly how data flows through your app
10
+ - ๐ŸŽ๏ธ **Fast**: Minimal re-renders, optimized updates
11
+ - ๐Ÿชถ **Lightweight**: Tiny footprint, big capabilities
12
+ - ๐Ÿ”Œ **Framework-Agnostic**: Works with any framework or vanilla JS/TS
13
+
14
+ ## ๐Ÿ“ฆ Installation
15
+
16
+ ```bash
17
+ npm install mates
18
+ # or
19
+ yarn add mates
20
+ ```
21
+
22
+ ## ๐Ÿง  Core Concepts
23
+
24
+ Mates offers several types of state management tools that work together seamlessly as part of the framework:
25
+
26
+ ### ๐Ÿ” Views: Building Reactive UIs
27
+
28
+ Views are the building blocks of your UI. They're functions that return HTML templates and automatically subscribe to state changes.
29
+
30
+ ```typescript
31
+ import { view, atom } from "mates";
32
+ import { html } from "lit-html";
33
+
34
+ // Create a view that uses this state
35
+ const CounterView = (props) => {
36
+ let count = 0;
37
+ const incr = setter(() => count++);
38
+ return () => {
39
+ // This function renders the template
40
+ return html`
41
+ <div>
42
+ <h1>Count: ${count}</h1>
43
+ <button @click=${incr}>Increment</button>
44
+ </div>
45
+ `;
46
+ };
47
+ };
48
+
49
+ // Render the view in your app in an element
50
+ // second param should be id of the element
51
+ renderView(CounterView, "app");
52
+ ```
53
+
54
+ ### โš›๏ธ Atoms: Simple Reactive State
55
+
56
+ Atoms are the simplest form of state. They store a single value that can be read and updated.
57
+
58
+ ```typescript
59
+ import { atom } from "mates";
60
+
61
+ // Create an atom with initial value
62
+ const username = atom("guest");
63
+
64
+ // Read the value
65
+ console.log(username()); // "guest"
66
+
67
+ // Update the value
68
+ username.set("alice");
69
+
70
+ // Use setter function
71
+ username.set((prev) => prev.toUpperCase());
72
+
73
+ // you can also update the values in an object or array using .update()
74
+
75
+ const address = atom({ street: "" });
76
+ address.update((s) => (s.street = "newstreet"));
77
+ ```
78
+
79
+ ### Counter app using atoms
80
+
81
+ ```typescript
82
+
83
+ ```
84
+
85
+ ### ๐Ÿงช Units: Object-Based State
86
+
87
+ Units are perfect for managing object-based state with methods.
88
+
89
+ ```typescript
90
+ import { unit } from "mates";
91
+
92
+ // Create a unit
93
+ const todoList = unit({
94
+ items: [],
95
+
96
+ // Methods with _ prefix automatically trigger updates
97
+ _addItem(text) {
98
+ this.items.push({ text, completed: false });
99
+ },
100
+
101
+ _toggleItem(index) {
102
+ this.items[index].completed = !this.items[index].completed;
103
+ },
104
+
105
+ // Computed property (cached and recalculated when dependencies change)
106
+ get completedCount() {
107
+ return this.items.filter((item) => item.completed).length;
108
+ },
109
+
110
+ async loadData() {
111
+ const data = await fetchData();
112
+ this._addItem(data); // updates items
113
+ },
114
+ });
115
+
116
+ // Use the unit
117
+ todoList().items; // []
118
+ todoList()._addItem("Learn Mates");
119
+ ```
120
+
121
+ ### ๐Ÿซง Bubbles: Encapsulated Logic
122
+
123
+ Bubbles help you encapsulate complex state logic into a reusable entity.
124
+
125
+ ```typescript
126
+ import { bubble } from "mates";
127
+
128
+ const counterBubble = bubble((setter) => {
129
+ let count = 0;
130
+
131
+ // Create functions that update state with setter
132
+ const increment = setter(() => count++);
133
+ const decrement = setter(() => count--);
134
+ const reset = setter(() => (count = 0));
135
+
136
+ // Return a function that returns the state object
137
+ return () => ({
138
+ count,
139
+ increment,
140
+ decrement,
141
+ reset,
142
+ });
143
+ });
144
+
145
+ // Use the bubble
146
+ const { count, increment } = counterBubble();
147
+ console.log(count); // 0
148
+ increment();
149
+ console.log(counterBubble().count); // 1
150
+ ```
151
+
152
+ ### ๐Ÿ“Š Getters: Computed Values
153
+
154
+ Getters create computed values that only recalculate when their dependencies change.
155
+
156
+ ```typescript
157
+ import { atom, getter } from "mates";
158
+
159
+ const firstName = atom("John");
160
+ const lastName = atom("Doe");
161
+
162
+ const fullName = getter(() => {
163
+ return `${firstName()} ${lastName()}`;
164
+ });
165
+
166
+ console.log(fullName()); // "John Doe"
167
+
168
+ // Only recalculates when dependencies change
169
+ firstName.set("Jane");
170
+ console.log(fullName()); // "Jane Doe"
171
+ ```
172
+
173
+ ### ๐Ÿงฌ Molecules: Organizing State
174
+
175
+ Molecules help you organize your state into classes for better structure.
176
+
177
+ ```typescript
178
+ import { molecule, atom } from "mates";
179
+
180
+ class UserStore {
181
+ name = atom("Guest");
182
+ isLoggedIn = atom(false);
183
+
184
+ login(username) {
185
+ this.name.set(username);
186
+ this.isLoggedIn.set(true);
187
+ }
188
+
189
+ logout() {
190
+ this.name.set("Guest");
191
+ this.isLoggedIn.set(false);
192
+ }
193
+ }
194
+
195
+ // Create a molecule from the class
196
+ const userStore = molecule(UserStore);
197
+
198
+ // Use the molecule
199
+ console.log(userStore().name()); // "Guest"
200
+ userStore().login("Alice");
201
+ console.log(userStore().isLoggedIn()); // true
202
+ ```
203
+
204
+ ### ๐Ÿ”„ XProvider: Context Management
205
+
206
+ XProvider allows you to provide and consume context across your application.
207
+
208
+ ```typescript
209
+ import { html } from "lit-html";
210
+ import { view, useContext } from "mates";
211
+
212
+ // Create a context class
213
+ class ThemeContext {
214
+ theme = "light";
215
+
216
+ toggleTheme() {
217
+ this.theme = this.theme === "light" ? "dark" : "light";
218
+ }
219
+ }
220
+
221
+ // Provider component
222
+ const ThemeProvider = view(
223
+ (props) => {
224
+ const themeContext = new ThemeContext();
225
+
226
+ return () => html`
227
+ <x-provider .value=${themeContext}> ${props().children} </x-provider>
228
+ `;
229
+ },
230
+ { children: [] }
231
+ );
232
+
233
+ // Consumer component
234
+ const ThemedButton = view(() => {
235
+ // Get context instance
236
+ const theme = useContext(ThemeContext);
237
+
238
+ return () => html`
239
+ <button class="${theme.theme}-theme" @click=${() => theme.toggleTheme()}>
240
+ Toggle Theme (Current: ${theme.theme})
241
+ </button>
242
+ `;
243
+ }, {});
244
+ ```
245
+
246
+ ## ๐ŸŽฎ Complete Example
247
+
248
+ Here's a complete todo list example that showcases Mates' features:
249
+
250
+ ```typescript
251
+ import { html } from "lit-html";
252
+ import { view, bubble, atom } from "mates";
253
+
254
+ // Create state with a bubble
255
+ const todos = bubble((setter) => {
256
+ let items = [];
257
+ let newTodoText = "";
258
+
259
+ const setNewTodoText = setter((text) => {
260
+ newTodoText = text;
261
+ });
262
+
263
+ const addTodo = setter(() => {
264
+ if (newTodoText.trim()) {
265
+ items.push({ text: newTodoText, completed: false });
266
+ newTodoText = "";
267
+ }
268
+ });
269
+
270
+ const toggleTodo = setter((index) => {
271
+ items[index].completed = !items[index].completed;
272
+ });
273
+
274
+ const deleteTodo = setter((index) => {
275
+ items.splice(index, 1);
276
+ });
277
+
278
+ return () => ({
279
+ items,
280
+ newTodoText,
281
+ setNewTodoText,
282
+ addTodo,
283
+ toggleTodo,
284
+ deleteTodo,
285
+ });
286
+ });
287
+
288
+ // Create a view for the todo app
289
+ const TodoApp = view(() => {
290
+ return () => {
291
+ const {
292
+ items,
293
+ newTodoText,
294
+ setNewTodoText,
295
+ addTodo,
296
+ toggleTodo,
297
+ deleteTodo,
298
+ } = todos();
299
+
300
+ return html`
301
+ <div class="todo-app">
302
+ <h1>Todo List</h1>
303
+ <div class="add-todo">
304
+ <input
305
+ value=${newTodoText}
306
+ @input=${(e) => setNewTodoText(e.target.value)}
307
+ @keypress=${(e) => e.key === "Enter" && addTodo()}
308
+ placeholder="Add new todo"
309
+ />
310
+ <button @click=${addTodo}>Add</button>
311
+ </div>
312
+
313
+ <ul class="todo-list">
314
+ ${items.map(
315
+ (item, index) => html`
316
+ <li class=${item.completed ? "completed" : ""}>
317
+ <input
318
+ type="checkbox"
319
+ .checked=${item.completed}
320
+ @change=${() => toggleTodo(index)}
321
+ />
322
+ <span>${item.text}</span>
323
+ <button @click=${() => deleteTodo(index)}>Delete</button>
324
+ </li>
325
+ `
326
+ )}
327
+ </ul>
328
+
329
+ <div class="todo-stats">
330
+ <p>${items.filter((item) => !item.completed).length} items left</p>
331
+ </div>
332
+ </div>
333
+ `;
334
+ };
335
+ }, {});
336
+
337
+ // Mount the app
338
+ document.body.appendChild(TodoApp);
339
+ ```
340
+
341
+ ## ๐Ÿ”„ Why Mates?
342
+
343
+ Mates gives you the power and simplicity of React hooks without the React! As a complete framework, it's perfect for:
344
+
345
+ - Building lightweight web apps without other heavy frameworks
346
+ - Adding reactivity to existing applications
347
+ - Creating reusable, reactive components
348
+ - Prototyping ideas quickly
349
+
350
+ ## ๐Ÿ“š Learn More
351
+
352
+ Check out our [examples](https://github.com/yourusername/mates/tree/main/examples) to see more usage patterns and advanced framework features.
353
+
354
+ ## ๐Ÿ“„ License
355
+
356
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mates",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "description": "Mates is a front end framework for building web applications",
6
6
  "main": "dist/index.js",