@mongez/atom 1.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.
Files changed (2) hide show
  1. package/README.md +862 -0
  2. package/package.json +35 -0
package/README.md ADDED
@@ -0,0 +1,862 @@
1
+ # Atoms
2
+
3
+ A powerful state management tool that could be used within any UI framework or Nodejs App.
4
+
5
+ ## Why?
6
+
7
+ The main purpose of the birth of this package is to work with a simple and performant state management tool to handle data among components and outside components.
8
+
9
+ ## Features
10
+
11
+ - Simple and easy to use
12
+ - Won't take more than few minutes to **master it**.
13
+ - Can be used outside components.
14
+ - Listen to atom's value change.
15
+ - Listen to atom's object property change.
16
+ - Lightweight in size.
17
+ - Easy Managing Objects, Arrays, and booleans.
18
+ - Open for Extension using Atom Actions.
19
+
20
+ ## React Atom
21
+
22
+ For React users, we have a [dedicated package](https://github.com/hassanzohdy/mongez-react-atom) that works perfectly with React, it has some extra features that would fit with React components.
23
+
24
+ ## Installation
25
+
26
+ `yarn add @mongez/atom`
27
+
28
+ Or
29
+
30
+ `npm i @mongez/atom`
31
+
32
+ Or
33
+
34
+ `pnpm add @mongez/atom`
35
+
36
+ ## Atoms are unique
37
+
38
+ Atoms are meant to be **unique** therefore the atom `key` can not be used in more than one atom, if other atom is being created with a previously defined atom, an error will be thrown that indicates to use another atom key.
39
+
40
+ ## Create A New Atom
41
+
42
+ The main idea here is every single data that might be manipulated will be stored independently in a shape of an `atom`.
43
+
44
+ This will raise the power of single responsibility.
45
+
46
+ ```ts
47
+ import { createAtom, Atom } from "@mongez/atom";
48
+
49
+ export const currencyAtom: createAtom<string> = createAtom({
50
+ key: "currency",
51
+ default: "EUR",
52
+ });
53
+ ```
54
+
55
+ > Please note that all atoms are immutables, the default data will be kept untouched if it is an object or an array.
56
+
57
+ When creating a new atom, it's recommended to pass the atom's value type as a generic type to the `atom` function, this will help you use the atom's value in a type-safe way.
58
+
59
+ ## Using Atoms
60
+
61
+ Now the `currencyAtom` atom has only single value, from this point we can use it in anywhere in our application components or event outside components.
62
+
63
+ > For demo purposes only, we'll use React in this documentation, but you can use the atom in any UI framework or even in Nodejs.
64
+
65
+ `some-component.ts`
66
+
67
+ ```tsx
68
+ import { useEffect, useState } from "react";
69
+ import { currencyAtom } from "~/src/atoms";
70
+
71
+ export default function Header() {
72
+ const [currency, setCurrency] = useState(currencyAtom.value);
73
+
74
+ useEffect(() => {
75
+ // Watch for currency changes
76
+ return currencyAtom.onChange(setCurrency);
77
+ }, []);
78
+
79
+ return (
80
+ <>
81
+ <h1>Header</h1>
82
+ Currency: {currency}
83
+ </>
84
+ );
85
+ }
86
+ ```
87
+
88
+ The `onChange` method will listen for any changes happen in the atom and return an [Event Subscription](https://github.com/hassanzohdy/mongez-events#event-subscription) that has `unsubscribe` method to remove the listener, this could be used in the cleanup process.
89
+
90
+ Another way to write the previous use effect for more readability.
91
+
92
+ ```tsx
93
+ useEffect(() => {
94
+ const eventSubscription = currencyAtom.onChange(setCurrency);
95
+ return () => eventSubscription.unsubscribe();
96
+ }, []);
97
+ ```
98
+
99
+ ## Types of atom values
100
+
101
+ Any atom must have a `default` value when initializing it, this value can be any type, it can be a string, number, boolean, object, array, however, when the default value is an `object`, the atom gets a **special treatment**.
102
+
103
+ We will see this later in the documentation.
104
+
105
+ ## Get atom value
106
+
107
+ Atom's value can be fetched in different ways, depends what are you trying to do.
108
+
109
+ For example, if you're using the atom outside a `React component` or you're using it inside a component but don't want to rerender the component when the atom's value changes, you can use the `atom.value` property.
110
+
111
+ ```ts
112
+ // anywhere in your app
113
+ import { currencyAtom } from "~/src/atoms";
114
+
115
+ console.log(currencyAtom.value); // get current value
116
+ ```
117
+
118
+ ## Update atom's value
119
+
120
+ The basic way to update atom's value is by using `atom.update`, this method receives the new value of the atom and updates it.
121
+
122
+ ```ts
123
+ // anywhere in your app
124
+ import { currencyAtom } from "~/src/atoms";
125
+
126
+ currencyAtom.update("USD"); // any component using the atom will be rerendered automatically.
127
+ ```
128
+
129
+ We can also pass a callback to the update function, the callback will receive the old value and the atom instance.
130
+
131
+ ```ts
132
+ // anywhere in your app
133
+ import { currencyAtom } from "~/src/atoms";
134
+
135
+ currencyAtom.update((oldValue, atom) => {
136
+ // do something with the old value
137
+ return "USD";
138
+ });
139
+ ```
140
+
141
+ > Please do remember that `atom.update` must receive a new reference of the value, otherwise it will not trigger the change event, for example `atom.update({ ...user })` will trigger the change event.
142
+
143
+ ```ts
144
+ // /src/atoms/user-atom.ts
145
+ import { createAtom } from "@mongez/atom";
146
+
147
+ export type UserData = {
148
+ name: string;
149
+ email: string;
150
+ age: number;
151
+ id: number;
152
+ };
153
+
154
+ export const userAtom = createAtom<UserData>({
155
+ key: "user",
156
+ default: {
157
+ name: "Hasan",
158
+ age: 30,
159
+ email: "hassanzohdy@gmail.com",
160
+ id: 1,
161
+ },
162
+ });
163
+ ```
164
+
165
+ Now if we want to make an update for the user atom using `atom.update`, it will be something like this:
166
+
167
+ ```ts
168
+ // anywhere in your app
169
+
170
+ import { userAtom } from "~/src/atoms/user-atom";
171
+
172
+ userAtom.update({
173
+ ...userAtom.value,
174
+ name: "Ahmed",
175
+ });
176
+ ```
177
+
178
+ Or using callback to get the old value:
179
+
180
+ ```ts
181
+ // anywhere in your app
182
+
183
+ import { userAtom } from "~/src/atoms/user-atom";
184
+
185
+ userAtom.update((oldValue) => {
186
+ return {
187
+ ...oldValue,
188
+ name: "Ahmed",
189
+ };
190
+ });
191
+ ```
192
+
193
+ ## Merge atom's value
194
+
195
+ If the atom is an object atom, you can use `atom.merge` to merge the new value with the old value.
196
+
197
+ ```ts
198
+ // src/atoms/user-atom.ts
199
+ import { createAtom } from "@mongez/atom";
200
+
201
+ export type UserData = {
202
+ name: string;
203
+ email: string;
204
+ age: number;
205
+ id: number;
206
+ };
207
+
208
+ export const userAtom = createAtom<UserData>({
209
+ key: "user",
210
+ default: {
211
+ name: "Hasan",
212
+ age: 30,
213
+ email: "hassanzohdy@gmail.com",
214
+ id: 1,
215
+ },
216
+ });
217
+ ```
218
+
219
+ Now if we want to make an update for the user atom using `atom.update`, it will be something like this:
220
+
221
+ ```ts
222
+ // anywhere in your app
223
+ import { userAtom } from "~/src/atoms";
224
+
225
+ userAtom.update({
226
+ ...userAtom.value,
227
+ name: "Ahmed",
228
+ age: 25,
229
+ });
230
+ ```
231
+
232
+ If you notice, we've to spread the old value and then add the new values, this is good, but we can use `atom.merge` instead.
233
+
234
+ ```ts
235
+ // anywhere in your app
236
+ import { userAtom } from "~/src/atoms";
237
+
238
+ userAtom.merge({
239
+ name: "Ahmed",
240
+ age: 25,
241
+ });
242
+ ```
243
+
244
+ This is just a shortcut for `atom.update`, it will merge the new value with the old value and then update the atom.
245
+
246
+ ## On Atom Reset
247
+
248
+ To listen to atom when it is reset, use `onReset` method.
249
+
250
+ ```ts
251
+ // anywhere in your app
252
+ import { currencyAtom } from "~/src/atoms";
253
+
254
+ currencyAtom.onReset((atom) => {
255
+ //
256
+ });
257
+ ```
258
+
259
+ > This will be triggered after the update event is triggered
260
+
261
+ ## Changing only single key in the atom's value
262
+
263
+ Instead of passing the whole object to the `setUser` function, we can pass only the key we want to change using `atom.change` function.
264
+
265
+ ```tsx
266
+ import React from "react";
267
+ import { userAtom } from "~/src/atoms";
268
+
269
+ export default function UserForm() {
270
+ const [user, setUser] = React.useState(userAtom.value);
271
+
272
+ React.useEffect(() => {
273
+ return userAtom.onChange(setUser);
274
+ }, []);
275
+
276
+ return (
277
+ <>
278
+ <h1>User Form</h1>
279
+ <input
280
+ type="text"
281
+ value={user.name}
282
+ onChange={(e) => userAtom.change("name", e.target.value)}
283
+ />
284
+ <input
285
+ type="text"
286
+ value={user.email}
287
+ onChange={(e) => userAtom.change("email", e.target.value)}
288
+ />
289
+ </>
290
+ );
291
+ }
292
+ ```
293
+
294
+ This will change only the given key in the atom's value, and trigger a component rerender if the atom's value is used in the component.
295
+
296
+ > Please note that `change` method calls `update` method under the hood, so it will generate a new object.
297
+
298
+ ## Get Atom single key value
299
+
300
+ If atom's value is an object, we can get a value from the atom directly using `atom.get` function.
301
+
302
+ ```ts
303
+ import { createAtom } from "@mongez/atom-react";
304
+
305
+ const userAtom = createAtom({
306
+ key: "user",
307
+ default: {
308
+ key: "Hasan",
309
+ address: {
310
+ city: "New York",
311
+ },
312
+ },
313
+ });
314
+
315
+ console.log(userAtom.get("key")); // Hasan
316
+ ```
317
+
318
+ Dot Notation is also supported.
319
+
320
+ ```ts
321
+ console.log(userAtom.get("address.city")); // New York
322
+ ```
323
+
324
+ If key doesn't exist, return default value instead.
325
+
326
+ ```ts
327
+ console.log(userAtom.get("email", "default@email.com")); // default@email.com
328
+ ```
329
+
330
+ ## Reset value
331
+
332
+ This feature might be useful in some scenarios when we need to reset the atom's value to its default value.
333
+
334
+ ```ts
335
+ // anywhere in your app
336
+ import { currencyAtom } from "~/src/atoms";
337
+
338
+ currencyAtom.reset(); // any component using the atom will be rerendered automatically.
339
+ ```
340
+
341
+ This will trigger an atom update and set the atom's value to its default value.
342
+
343
+ ## Silent Update (Update without triggering change event)
344
+
345
+ Works exactly like `update` method, but it will not trigger the change event.
346
+
347
+ ```ts
348
+ // anywhere in your app
349
+ import { currencyAtom } from "~/src/atoms";
350
+
351
+ currencyAtom.silentUpdate("USD"); // any component using the atom will be rerendered automatically.
352
+ ```
353
+
354
+ ## Silent Reset Value (Reset without triggering change event)
355
+
356
+ Sometimes its useful to reset the atom's value to its default value without triggering the change event, this can be achieved using `silentReset` method, a good sue case for this is when a component is unmounted and you want to reset the atom's value to its default value without triggering the change event.
357
+
358
+ ```tsx
359
+ // Header.tsx
360
+ import { currencyAtom } from "~/src/atoms";
361
+ import { useEffect } from "react";
362
+
363
+ export default function Header() {
364
+ const currency = currencyAtom.useValue();
365
+
366
+ useEffect(() => {
367
+ return () => currencyAtom.silentReset();
368
+ }, []);
369
+
370
+ return (
371
+ <>
372
+ <h1>Header</h1>
373
+ Currency: {currency}
374
+ </>
375
+ );
376
+ }
377
+ ```
378
+
379
+ This will not trigger the value change event, but it will reset the atom's value to its default value and **the reset event will be triggered though**
380
+
381
+ ## Silent Change (Change without triggering change event)
382
+
383
+ Works exactly like `change` method, but it will not trigger the change event.
384
+
385
+ ```ts
386
+ // anywhere in your app
387
+ import { userAtom } from "~/src/atoms";
388
+
389
+ userAtom.silentChange("name", "Ahmed");
390
+ ```
391
+
392
+ ## Destroy atom
393
+
394
+ We can also destroy the atom using `destroy()` method from the atom, it will automatically fire the `onDestroy` event.
395
+
396
+ ```ts
397
+ // anywhere in your app
398
+ import { currencyAtom } from "~/src/atoms";
399
+
400
+ currencyAtom.destroy();
401
+ ```
402
+
403
+ ## Getting atom key
404
+
405
+ To get the atom key, use `atom.key` will return the atom key.
406
+
407
+ ```ts
408
+ // anywhere in your app
409
+ import { currencyAtom } from "~/src/atoms";
410
+
411
+ console.log(currencyAtom.key); // currencyAtom
412
+ ```
413
+
414
+ ## Getting all atoms
415
+
416
+ To list all registered atoms, use `atomsList` utility for that purpose.
417
+
418
+ ```ts
419
+ // anywhere in your app
420
+ import { atomsList } from "~/src/atoms";
421
+
422
+ console.log(atomsList()); // [currencyAtom, ...]
423
+ ```
424
+
425
+ ## get handler function
426
+
427
+ Sometimes we may need to handle the `atom.get` function to get the data in a customized way, we can achieve this by defining in the atom function call how the atom will retrieve the object's value.
428
+
429
+ Without Defining the `atom getter`
430
+
431
+ ```ts
432
+ const settingsAtom = createAtom({
433
+ key: "user",
434
+ default: {
435
+ isLoaded: false,
436
+ settings: {},
437
+ },
438
+ });
439
+
440
+ // later
441
+ settingsAtom.update({
442
+ isLoaded: true,
443
+ settings: {
444
+ websiteName: "My Website Name",
445
+ },
446
+ });
447
+
448
+ console.log(userAtom.get("settings.websiteName")); // My Website Name
449
+ ```
450
+
451
+ After Defining it
452
+
453
+ ```ts
454
+ import { createAtom } from "@mongez/atom-react";
455
+
456
+ const settingsAtom = createAtom({
457
+ key: "settings",
458
+ default: {
459
+ isLoaded: false,
460
+ settings: {},
461
+ },
462
+ get(key: string, defaultValue: any = null, atomValue: any) {
463
+ return atomValue[key] !== undefined
464
+ ? atomValue[key]
465
+ : atomValue.settings[key] !== undefined
466
+ ? atomValue.settings[key]
467
+ : defaultValue;
468
+ },
469
+ });
470
+
471
+ // later
472
+ settingsAtom.update({
473
+ isLoaded: true,
474
+ settings: {
475
+ websiteName: "My Website Name",
476
+ },
477
+ });
478
+
479
+ console.log(settingsAtom.get("websiteName")); // My Website Name
480
+ ```
481
+
482
+ ## Listen to atom value changes
483
+
484
+ This is what happens with `useAtom` hook, it listens to the atom's value change using `onChange` method.
485
+
486
+ ```ts
487
+ // anywhere in your app
488
+ import { currencyAtom } from "~/src/atoms";
489
+
490
+ currencyAtom.onChange((newValue, oldValue, atom) => {
491
+ //
492
+ });
493
+ ```
494
+
495
+ > Please note the `onChange` is returning an [EventSubscription](https://github.com/hassanzohdy/mongez-events#unsubscribe-to-event) instance, we can remove the listener anytime, for example when unmounting the component.
496
+
497
+ ```ts
498
+ // anywhere in your app
499
+ import { currencyAtom } from "~/src/atoms";
500
+
501
+ // in your component...
502
+ const [currency, setCurrency] = useState(currencyAtom.value);
503
+ useEffect(() => {
504
+ const onCurrencyChange = currencyAtom.onChange(setCurrency);
505
+ return () => onCurrencyChange.unsubscribe();
506
+ }, []);
507
+ ```
508
+
509
+ ## Watch For Partial Change
510
+
511
+ Sometimes you may need to watch for only a key in the atom's value object, the `atom.watch` function is the perfect way to achieve this.
512
+
513
+ > Please note this only works if the atom's default is an object or an array.
514
+
515
+ ```ts
516
+ // anywhere in your app
517
+ import { createAtom } from "@mongez/atom";
518
+
519
+ const userAtom = createAtom({
520
+ key: "user",
521
+ default: {
522
+ key: "Hasan",
523
+ address: {
524
+ city: "New York",
525
+ },
526
+ },
527
+ });
528
+
529
+ userAtom.watch("key", (newName, oldName) => {
530
+ console.log(newName, oldName); // 'Hasan', 'Ali'
531
+ });
532
+
533
+ // later in the app
534
+ userAtom.update({
535
+ ...userAtom.value,
536
+ key: "Ali",
537
+ });
538
+ ```
539
+
540
+ > Dot notation is allowed too.
541
+
542
+ ```ts
543
+ // anywhere in your app
544
+ import { createAtom } from "@mongez/atom";
545
+
546
+ const userAtom = createAtom({
547
+ key: "user",
548
+ default: {
549
+ key: "Hasan",
550
+ address: {
551
+ city: "New York",
552
+ },
553
+ },
554
+ });
555
+
556
+ userAtom.watch("address.cty", (newCity, oldCity) => {
557
+ console.log(newName, oldName); // 'New York', 'Cairo'
558
+ });
559
+
560
+ // later in the app
561
+ userAtom.update({
562
+ ...userAtom.value,
563
+ address: {
564
+ ...userAtom.value.address,
565
+ city: "Cairo",
566
+ },
567
+ });
568
+ ```
569
+
570
+ ## Value Mutation Before Update
571
+
572
+ Sometimes it's useful to mutate the value before updating it in the atom, this can be achieved via defining `beforeUpdate` method in the atom declaration.
573
+
574
+ This is very useful especially when dealing with objects/arrays and you want to make some operations before using the final value.
575
+
576
+ `beforeUpdate(newValue: any, oldValue: any, atom: Atom)`
577
+
578
+ ```ts
579
+ import { createAtom, Atom } from "@mongez/atom";
580
+
581
+ export const multipleAtom: Atom = createAtom({
582
+ key: "multiple",
583
+ default: 0,
584
+ beforeUpdate(newNumber: number): number {
585
+ return newNumber * 2;
586
+ },
587
+ });
588
+
589
+ multipleAtom.update(4);
590
+
591
+ console.log(multipleAtom.value); // 8
592
+ ```
593
+
594
+ ## Listen to atom destruction
595
+
596
+ To detect atom destruction when `destroy()` method, use `onDestroy`.
597
+
598
+ ```ts
599
+ // anywhere in your app
600
+ import { currencyAtom } from "~/src/atoms";
601
+
602
+ const subscription = currencyAtom.onDestroy((atom) => {
603
+ //
604
+ });
605
+ ```
606
+
607
+ ## Atom Type
608
+
609
+ We can get the type of the atom's value using `atom.type` property.
610
+
611
+ ```tsx
612
+ const currencyAtom = createAtom({
613
+ key: "currency",
614
+ default: "USD",
615
+ });
616
+
617
+ console.log(currencyAtom.type); // string
618
+ ```
619
+
620
+ If the default value is an array it will be returned as array not object.
621
+
622
+ ```tsx
623
+ const todoListAtom = createAtom({
624
+ key: "todo",
625
+ default: [],
626
+ });
627
+
628
+ console.log(todoListAtom.type); // array
629
+ ```
630
+
631
+ ## Atom Actions
632
+
633
+ Sometimes, atoms need to have some actions that can be used to manipulate the atom's value, this can be achieved by defining `actions` object in the atom declaration.
634
+
635
+ ```ts
636
+ import { createAtom, Atom } from "@mongez/atom";
637
+
638
+ export const userAtom: Atom = createAtom({
639
+ key: "user",
640
+ default: {
641
+ name: "Hasan",
642
+ age: 30,
643
+ email: "",
644
+ },
645
+ actions: {
646
+ changeName(name: string) {
647
+ this.update({
648
+ ...this.value,
649
+ name,
650
+ });
651
+ },
652
+ changeEmail(email: string) {
653
+ this.update({
654
+ ...this.value,
655
+ email,
656
+ });
657
+ },
658
+ },
659
+ });
660
+
661
+ // later in the app
662
+
663
+ userAtom.changeName("Ahmed");
664
+ userAtom.changeEmail("");
665
+ ```
666
+
667
+ > All action methods are bound to the atom object itself, so feel free to use `this` to access the atom's object.
668
+
669
+ So basically the idea here is simple, we add the actions to the atom's declaration, then we can use these actions to manipulate the atom's value, this is super useful when we have a complex atom that needs to be manipulated in a specific way or if we want to enrich the atom with some actions.
670
+
671
+ > Please note that actions are meant to extend atom functionality, but keep in mind to keep it simple and clean.
672
+
673
+ ### Override existing atom methods
674
+
675
+ Actions can be used also to override existing atom functions like `atom.get()` for example.
676
+
677
+ ```ts
678
+ import { createAtom, Atom } from "@mongez/atom";
679
+
680
+ export const userAtom: Atom = createAtom({
681
+ key: "user",
682
+ default: {
683
+ name: "Hasan",
684
+ age: 30,
685
+ email: "",
686
+ },
687
+ actions: {
688
+ get(key: string, defaultValue: any = null) {
689
+ return this.value[key] || defaultValue;
690
+ },
691
+ },
692
+ });
693
+
694
+ // later in the app
695
+
696
+ console.log(userAtom.get("name")); // Hasan
697
+ ```
698
+
699
+ > Please note this is NOT Recommended to override existing atom methods, there could edge cases for this purpose.
700
+
701
+ ### Defining Actions Definition
702
+
703
+ The `createAtom` receives two generic types, the first one is the atom's value type, the second one is the actions definition type.
704
+
705
+ ```ts
706
+ import { createAtom, Atom } from "@mongez/atom";
707
+
708
+ type UserActions = {
709
+ changeName(name: string): void;
710
+ changeEmail(email: string): void;
711
+ };
712
+
713
+ export const userAtom: Atom = createAtom<UserData, UserActions>({
714
+ key: "user",
715
+ default: {
716
+ name: "Hasan",
717
+ age: 30,
718
+ email: "",
719
+ },
720
+ actions: {
721
+ changeName(name: string) {
722
+ this.update({
723
+ ...this.value,
724
+ name,
725
+ });
726
+ },
727
+ changeEmail(email: string) {
728
+ this.update({
729
+ ...this.value,
730
+ email,
731
+ });
732
+ },
733
+ },
734
+ });
735
+ ```
736
+
737
+ It's recommended to define the actions type to have a better type checking and auto-completion.
738
+
739
+ ## Working with atom as arrays
740
+
741
+ To treat the atom as an array, we will need to use the `atomCollection` function instead of `createAtom`, it provides more array functions that will help us to manipulate the atom's value.
742
+
743
+ ```ts
744
+ import { atomCollection } from "@mongez/atom";
745
+
746
+ const todoListAtom = atomCollection({
747
+ key: "todo",
748
+ default: [],
749
+ });
750
+ ```
751
+
752
+ Now we can use the following functions to manipulate the atom's value.
753
+
754
+ ### Add item to the end of the array
755
+
756
+ ```ts
757
+ todoListAtom.push("Buy Milk");
758
+ ```
759
+
760
+ > It can accept multiple items to add.
761
+
762
+ ```ts
763
+ todoListAtom.push("Buy Milk", "Buy Bread");
764
+ ```
765
+
766
+ ### Add item to the beginning of the array
767
+
768
+ ```ts
769
+ todoListAtom.unshift("Buy Milk");
770
+ ```
771
+
772
+ > It can accept multiple items to add.
773
+
774
+ ```ts
775
+ todoListAtom.unshift("Buy Milk", "Buy Bread");
776
+ ```
777
+
778
+ ### Remove item from the end of the array
779
+
780
+ ```ts
781
+ todoListAtom.pop();
782
+ ```
783
+
784
+ ### Remove item from the beginning of the array
785
+
786
+ ```ts
787
+ todoListAtom.shift();
788
+ ```
789
+
790
+ ### Update item in the array
791
+
792
+ ```ts
793
+ todoListAtom.replace(0, "Buy Bread");
794
+ ```
795
+
796
+ ### Get item from the array
797
+
798
+ There are two ways to get an item from the array, either by sending the item index, or passing a callback to find the item with:
799
+
800
+ ```ts
801
+ // by index
802
+ console.log(todoListAtom.get(0)); // Buy Milk
803
+
804
+ // by callback
805
+ console.log(todoListAtom.get((item) => item === "Buy Milk")); // Buy Milk
806
+ ```
807
+
808
+ If the item is not found, it will return `undefined`.
809
+
810
+ ### Remove item from the array
811
+
812
+ We can either pass the item index or a callback to remove the item from the array.
813
+
814
+ ```ts
815
+ // by index
816
+ todoListAtom.remove(0);
817
+
818
+ // by callback
819
+ todoListAtom.remove((item) => item === "Buy Milk");
820
+ ```
821
+
822
+ ### Remove item from the array by index
823
+
824
+ To remove the itm from the array using the item itself, just pass it to `removeItem` method:
825
+
826
+ ```ts
827
+ todoListAtom.removeItem("Buy Milk");
828
+ ```
829
+
830
+ This will remove the first found item in the array.
831
+
832
+ ### Remove all found items from the array
833
+
834
+ If element possibly exists more than once in the array, we can remove all of them using `removeAll` method.
835
+
836
+ ```ts
837
+ todoListAtom.removeAll("Buy Milk");
838
+ ```
839
+
840
+ ### Map over the array
841
+
842
+ The `map` method will update the atom's array with the new array.
843
+
844
+ ```ts
845
+ todoListAtom.map((item) => item.toUpperCase());
846
+ ```
847
+
848
+ ### Get the array length
849
+
850
+ ```ts
851
+ console.log(todoListAtom.length); // 2
852
+ ```
853
+
854
+ ### Reset the array
855
+
856
+ Just use the normal `reset` method.
857
+
858
+ ## Change Log
859
+
860
+ ## V1.0.0 (12 May 2024)
861
+
862
+ - Initial release
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@mongez/atom",
3
+ "version": "1.0.0",
4
+ "description": "An agnostic state management tool that work with any framework on browser or server",
5
+ "main": "./cjs/index.js",
6
+ "author": "hassanzohdy",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/hassanzohdy/atom"
10
+ },
11
+ "license": "MIT",
12
+ "dependencies": {
13
+ "@mongez/events": "^2.1.0",
14
+ "@mongez/reinforcements": "^2.3.10"
15
+ },
16
+ "keywords": [
17
+ "react",
18
+ "state",
19
+ "atom",
20
+ "state management",
21
+ "state management tool",
22
+ "state management library",
23
+ "recoil",
24
+ "Jotai",
25
+ "redux",
26
+ "angular",
27
+ "svelte",
28
+ "vue",
29
+ "astro",
30
+ "qwik",
31
+ "state management library for react"
32
+ ],
33
+ "module": "./esm/index.js",
34
+ "typings": "./cjs/index.d.ts"
35
+ }