1- import { atom } from 'nanostores'
2- import type { AnyStore , WritableAtom } from 'nanostores' ;
3- import type { AllPaths , BaseDeepMap , FromPath , FromPathWithIndexSignatureUndefined } from './path.types.js' ;
4- import { getPath , isObject , setPath } from './path.js' ;
1+ import { atom } from "nanostores" ;
2+ import type { WritableAtom } from "nanostores" ;
3+ import type {
4+ AllPaths ,
5+ BaseDeepMap ,
6+ FromPath ,
7+ FromPathWithIndexSignatureUndefined ,
8+ } from "./path.types.js" ;
9+ import { getPath , isObject , setPath } from "./path.js" ;
510
611export type DeepMapStore < T extends BaseDeepMap > = {
7- value : T
12+ value : T ;
813
914 /**
10- * Subscribe to store changes.
11- *
12- * In contrast with {@link Store#subscribe} it do not call listener
13- * immediately.
14- *
15- * @param listener Callback with store value and old value.
16- * @param changedKey Key that was changed. Will present only if `setKey`
17- * has been used to change a store.
18- * @returns Function to remove listener.
19- */
15+ * Subscribe to store changes.
16+ *
17+ * In contrast with {@link Store#subscribe} it do not call listener
18+ * immediately.
19+ *
20+ * @param listener Callback with store value and old value.
21+ * @param changedKey Key that was changed. Will present only if `setKey`
22+ * has been used to change a store.
23+ * @returns Function to remove listener.
24+ */
2025 listen (
2126 listener : (
2227 value : T ,
2328 oldValue : T ,
24- changedKey : AllPaths < T > | undefined
25- ) => void
26- ) : ( ) => void
29+ changedKey : AllPaths < T > | undefined ,
30+ ) => void ,
31+ ) : ( ) => void ;
2732
2833 /**
29- * Low-level method to notify listeners about changes in the store.
30- *
31- * Can cause unexpected behaviour when combined with frontend frameworks
32- * doing equality checks for values, e.g. React.
33- */
34- notify ( oldValue ?: T , changedKey ?: AllPaths < T > ) : void
34+ * Low-level method to notify listeners about changes in the store.
35+ *
36+ * Can cause unexpected behaviour when combined with frontend frameworks
37+ * doing equality checks for values, e.g. React.
38+ */
39+ notify ( oldValue ?: T , changedKey ?: AllPaths < T > ) : void ;
40+
41+ getKey : < K extends AllPaths < T > | "" > ( key : K ) => FromPath < T , K > ;
3542
3643 /**
37- * Change key in store value. Copies are made at each level of `key` so that
38- * no part of the original object is mutated.
39- *
40- * ```js
41- * $settings.setKey('visuals.theme', 'dark')
42- * ```
43- *
44- * @param key The key name. Attributes can be split with a dot `.` and `[]`.
45- * @param value New value.
46- */
47- setKey : < K extends AllPaths < T > | '' > (
44+ * Change key in store value. Copies are made at each level of `key` so that
45+ * no part of the original object is mutated.
46+ *
47+ * ```js
48+ * $settings.setKey('visuals.theme', 'dark')
49+ * ```
50+ *
51+ * @param key The key name. Attributes can be split with a dot `.` and `[]`.
52+ * @param value New value.
53+ */
54+ setKey : < K extends AllPaths < T > | "" > (
4855 key : K ,
49- value : FromPathWithIndexSignatureUndefined < T , K > | undefined
50- ) => void
56+ value : FromPathWithIndexSignatureUndefined < T , K > | undefined ,
57+ ) => void ;
5158
5259 /**
53- * Change key in store value. Copies are made at each level of `key` so that
54- * no part of the original object is mutated.
55- *
56- * ```js
57- * $settings.updateKey('settings', { theme: 'dark' })
58- * ```
59- *
60- * @param key The key name. Attributes can be split with a dot `.` and `[]`.
61- * @param value New value.
62- */
63- updateKey : < K extends AllPaths < T > | '' > (
60+ * Change store value.
61+ * @param newValue — Update store value.
62+ */
63+ update : ( value : Partial < T > | undefined ) => void ;
64+
65+ /**
66+ * Change key in store value. Copies are made at each level of `key` so that
67+ * no part of the original object is mutated.
68+ *
69+ * ```js
70+ * $settings.updateKey('settings', { theme: 'dark' })
71+ * ```
72+ *
73+ * @param key The key name. Attributes can be split with a dot `.` and `[]`.
74+ * @param value New value.
75+ */
76+ updateKey : < K extends AllPaths < T > | "" > (
6477 key : K ,
65- value : Partial < FromPathWithIndexSignatureUndefined < T , K > > | undefined
66- ) => void
78+ value : Partial < FromPathWithIndexSignatureUndefined < T , K > > | undefined ,
79+ ) => void ;
6780
6881 /**
69- * Subscribe to store changes and call listener immediately.
70- *
71- * ```
72- * import { $settings } from '../store'
73- *
74- * $settings.subscribe(settings => {
75- * console.log(settings)
76- * })
77- * ```
78- *
79- * @param listener Callback with store value and old value.
80- * @param changedKey Key that was changed. Will present only
81- * if `setKey` has been used to change a store.
82- * @returns Function to remove listener.
83- */
82+ * Subscribe to store changes and call listener immediately.
83+ *
84+ * ```
85+ * import { $settings } from '../store'
86+ *
87+ * $settings.subscribe(settings => {
88+ * console.log(settings)
89+ * })
90+ * ```
91+ *
92+ * @param listener Callback with store value and old value.
93+ * @param changedKey Key that was changed. Will present only
94+ * if `setKey` has been used to change a store.
95+ * @returns Function to remove listener.
96+ */
8497 subscribe (
8598 listener : (
8699 value : T ,
87100 oldValue : T | undefined ,
88- changedKey : AllPaths < T > | undefined
89- ) => void
90- ) : ( ) => void
91- } & Omit < WritableAtom < T > , ' listen' | ' notify' | ' setKey' | ' subscribe' >
101+ changedKey : AllPaths < T > | undefined ,
102+ ) => void ,
103+ ) : ( ) => void ;
104+ } & Omit < WritableAtom < T > , " listen" | " notify" | " setKey" | " subscribe" > ;
92105
93106/**
94107 * Create deep map store. Deep map store is a store with an object as store
@@ -98,66 +111,42 @@ export type DeepMapStore<T extends BaseDeepMap> = {
98111 * @returns The store object with methods to subscribe.
99112 */
100113export function deepMap < T extends BaseDeepMap > ( init ?: T ) : DeepMapStore < T > {
101- const $deepmap = atom ( init ) as DeepMapStore < T >
114+ const $deepmap = atom ( init ) as DeepMapStore < T > ;
102115
103- $deepmap . setKey = < K extends AllPaths < T > | '' > (
116+ $deepmap . getKey = < K extends AllPaths < T > | "" > ( key : K ) : any => {
117+ return getPath ( key , $deepmap . value as BaseDeepMap ) ;
118+ } ;
119+
120+ $deepmap . setKey = < K extends AllPaths < T > | "" > (
104121 key : K ,
105- value : FromPathWithIndexSignatureUndefined < T , K > | undefined
122+ value : FromPathWithIndexSignatureUndefined < T , K > | undefined ,
106123 ) : void => {
107124 if ( getPath ( key , $deepmap . value as BaseDeepMap ) !== value ) {
108- const oldValue = $deepmap . value
109- $deepmap . value = setPath ( key , value , $deepmap . value as BaseDeepMap ) as T
110- $deepmap . notify ( oldValue , key as AllPaths < T > )
125+ const oldValue = $deepmap . value ;
126+ $deepmap . value = setPath ( key , value , $deepmap . value as BaseDeepMap ) as T ;
127+ $deepmap . notify ( oldValue , key as AllPaths < T > ) ;
111128 }
112- }
129+ } ;
113130
114- $deepmap . updateKey = < K extends AllPaths < T > | '' > (
131+ $deepmap . updateKey = < K extends AllPaths < T > | "" > (
115132 key : K ,
116- value : Partial < FromPathWithIndexSignatureUndefined < T , K > > | undefined
133+ value : Partial < FromPathWithIndexSignatureUndefined < T , K > > | undefined ,
117134 ) : void => {
118- const oldValue = getPath ( key , $deepmap . value as BaseDeepMap )
135+ const oldValue = getPath ( key , $deepmap . value as BaseDeepMap ) ;
119136 let newValue : any = value ;
120137
121138 if ( isObject ( oldValue ) && isObject ( value ) ) {
122- newValue = { ...oldValue as object , ...value } ;
139+ newValue = { ...( oldValue as object ) , ...value } ;
123140 } else if ( Array . isArray ( oldValue ) && Array . isArray ( value ) ) {
124141 newValue = [ ...oldValue , ...value ] ;
125142 }
126143
127144 $deepmap . setKey ( key , newValue as any ) ;
128- }
145+ } ;
129146
130- return $deepmap
131- }
147+ $deepmap . update = ( value : Partial < T > | undefined ) : void => {
148+ $deepmap . updateKey ( "" , value ) ;
149+ } ;
132150
133- /**
134- * Get a value by key from a store with an object value.
135- * Works with `map`, `deepMap`, and `atom`.
136- *
137- * ```js
138- * import { getKey, map } from 'nanostores'
139- *
140- * const $user = map({ name: 'John', profile: { age: 30 } })
141- *
142- * // Simple key access
143- * getKey($user, 'name') // Returns 'John'
144- *
145- * // Nested access with dot notation
146- * getKey($user, 'profile.age') // Returns 30
147- *
148- * // Array access
149- * const $items = map({ products: ['apple', 'banana'] })
150- * getKey($items, 'products[1]') // Returns 'banana'
151- * ```
152- *
153- * @param store The store to get the value from.
154- * @param key The key to access. Can be a simple key or a path with dot notation.
155- * @returns The value for this key
156- */
157- export function getKey <
158- T extends Record < string , unknown > ,
159- K extends AllPaths < T > | ''
160- > ( store : AnyStore < T > , key : K ) : FromPath < T , K > {
161- const value = store . get ( )
162- return getPath ( key , value )
151+ return $deepmap ;
163152}
0 commit comments