@plures/unum 0.2.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.
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Create a universal binding between a component and Gun.js
3
+ *
4
+ * This function creates a binding that will automatically sync all component data
5
+ * with Gun.js without caring about the specific structure of the data.
6
+ *
7
+ * @param {string} gunPath - The Gun.js path where the data should be stored
8
+ * @param {Object} [options] - Configuration options
9
+ * @param {Object} [options.defaultData={}] - Default data to use if no data exists at the path
10
+ * @returns {Object} Props to pass to the component and methods to handle updates
11
+ */
12
+ export function createUniversalBinding(gunPath: string, options?: {
13
+ defaultData?: any;
14
+ }): any;
15
+ /**
16
+ * Universal HOC function to automatically bind any component to Gun.js
17
+ *
18
+ * @param {string} gunPath - The Gun.js path where the data should be stored
19
+ * @param {Object} [options] - Configuration options
20
+ * @param {Object} [options.defaultData={}] - Default data to use if no data exists at the path
21
+ * @returns {Function} A function that will bind component data to Gun.js
22
+ */
23
+ export function bindToGun(gunPath: string, options?: {
24
+ defaultData?: any;
25
+ }): Function;
26
+ /**
27
+ * Create a universal component wrapper that automatically adds Gun.js binding
28
+ * This is the simplest API - developers just call this function and get a component
29
+ * that automatically syncs with Gun.js
30
+ *
31
+ * @template T
32
+ * @param {import('svelte').ComponentType<T>} Component - The component to wrap
33
+ * @param {string} gunPath - The Gun.js path where data should be stored
34
+ * @param {Object} [options] - Configuration options
35
+ * @param {any} [options.defaultData={}] - Default data structure for the component
36
+ * @returns {import('svelte').ComponentType<T>} A wrapped component that syncs with Gun.js
37
+ */
38
+ export function gunBind<T>(Component: import("svelte").ComponentType<T>, gunPath: string): import("svelte").ComponentType<T>;
39
+ /**
40
+ * Simplest form - universal Gun.js binding for any component
41
+ * Use this as a decorator pattern or HOC
42
+ *
43
+ * @param {string} gunPath - Gun.js path for data storage
44
+ * @param {Object} [options] - Configuration options
45
+ * @returns {Function} A component decorator function for universal binding
46
+ *
47
+ * @example
48
+ * // Basic usage directly in a .svelte file:
49
+ * import { universalGunBind } from '$lib/svgun/universalGunBind';
50
+ *
51
+ * // At the top of your component script:
52
+ * const { props, handleDataChange } = universalGunBind('myComponent');
53
+ *
54
+ * // Access data as {$props.whatever} in your template
55
+ * // When component data changes, call handleDataChange(newData)
56
+ */
57
+ export function universalGunBind(gunPath: string, options?: any): Function;
58
+ /**
59
+ * Rune-compatible version for Svelte 5
60
+ * Use this with the new runes syntax in Svelte 5
61
+ *
62
+ * @param {string} gunPath - Gun.js path for data storage
63
+ * @param {Object} [options] - Configuration options
64
+ * @returns {Object} A binding object with rune-compatible properties
65
+ *
66
+ * @example
67
+ * // In a Svelte 5 component with runes:
68
+ * import { useGun } from '$lib/svgun/universalGunBind';
69
+ *
70
+ * const { data, handleChange } = useGun('myComponent');
71
+ *
72
+ * // Access data directly as {data.whatever}
73
+ * // When component data changes, call handleChange(newData)
74
+ */
75
+ export function useGun(gunPath: string, options?: any): any;
76
+ /**
77
+ * Completely component-agnostic serialization approach
78
+ *
79
+ * This serializes and de-serializes entire components without needing to know
80
+ * any details of their structure. Pages don't need to handle component-specific data.
81
+ *
82
+ * @template T
83
+ * @param {string} componentName - Unique name for this component instance
84
+ * @param {Object} [options] - Configuration options
85
+ * @param {T} [options.defaultComponent={}] - Default component data
86
+ * @returns {Object} A component binding that handles all persistence automatically
87
+ */
88
+ export function serializeComponent<T>(componentName: string, options?: {
89
+ defaultComponent?: T;
90
+ }): any;
91
+ /**
92
+ * Even simpler black-box component serialization
93
+ *
94
+ * This function creates a binding where pages just get the component object without
95
+ * needing to know anything about its structure.
96
+ *
97
+ * @template T
98
+ * @param {string} componentName - Unique name for this component
99
+ * @param {Object} [options] - Configuration options
100
+ * @param {T} [options.defaultComponent={}] - Default component data
101
+ * @returns {Object} An object containing component props and update handler
102
+ */
103
+ export function getComponent<T>(componentName: string, options?: {
104
+ defaultComponent?: T;
105
+ }): any;
106
+ /**
107
+ * The simplest possible component serialization API
108
+ *
109
+ * This function provides a truly black-box binding where pages get
110
+ * a complete component and an update handler, with no concern for structure.
111
+ *
112
+ * @template T
113
+ * @param {string} name - Component identifier
114
+ * @param {T} [defaultState={}] - Default component state if none exists
115
+ * @returns {[T, (newState: T) => void, () => void]} [componentData, updateHandler, destroy]
116
+ *
117
+ * @example
118
+ * // In your page or component:
119
+ * import { component } from '$lib/svgun/universalGunBind';
120
+ *
121
+ * // Get component data and update handler
122
+ * const [todoData, updateTodo] = component('todo', {
123
+ * items: [],
124
+ * title: 'My Todos'
125
+ * });
126
+ *
127
+ * // Use it with any component - no need to know its structure
128
+ * <TodoComponent
129
+ * items={todoData.items}
130
+ * title={todoData.title}
131
+ * onItemsChanged={(items) => updateTodo({...todoData, items})}
132
+ * />
133
+ */
134
+ export function component<T>(name: string, defaultState?: T): [T, (newState: T) => void, () => void];
135
+ /**
136
+ * Universal update handler for any component property
137
+ *
138
+ * This function creates a property-specific update handler for any component.
139
+ * It automatically handles merging the new property value with the existing component state.
140
+ *
141
+ * @template T
142
+ * @template K extends keyof T
143
+ * @param {T} componentData - The current component data
144
+ * @param {(newData: T) => void} updateFn - The component update function
145
+ * @param {K} propName - The property name to update
146
+ * @returns {(newValue: T[K]) => void} A property-specific update handler
147
+ *
148
+ * @example
149
+ * // In your page:
150
+ * import { component, createPropHandler } from '$lib/svgun/universalGunBind';
151
+ *
152
+ * const [counterData, updateCounter] = component('counter', { count: 0 });
153
+ * const handleCount = createPropHandler(counterData, updateCounter, 'count');
154
+ *
155
+ * // Then in your template:
156
+ * <PureCounter count={counterData.count} onCountChanged={handleCount} />
157
+ */
158
+ export function createPropHandler<T, K>(componentData: T, updateFn: (newData: T) => void, propName: K): (newValue: T[K]) => void;
159
+ /**
160
+ * Universal component update handler for any event from any component
161
+ *
162
+ * This function creates a completely generic update handler that works with any component
163
+ * and any event type. It automatically detects what property changed and updates the component data.
164
+ *
165
+ * @template T
166
+ * @param {T} componentData - The current component data
167
+ * @param {(newData: T) => void} updateFn - The component update function
168
+ * @returns {{
169
+ * prop: <K extends keyof T>(propName: K) => (newValue: T[K]) => void,
170
+ * auto: <K extends keyof T>(propName: K) => (eventOrValue: any) => void,
171
+ * full: (newData: T) => void
172
+ * }} A handler object with methods for different property update patterns
173
+ *
174
+ * @example
175
+ * // In your page:
176
+ * import { component, handler } from '$lib/svgun/universalGunBind';
177
+ *
178
+ * const [counterData, updateCounter] = component('counter', { count: 0 });
179
+ *
180
+ * // Then in your template, use any of these patterns:
181
+ * <PureCounter
182
+ * count={counterData.count}
183
+ * onCountChanged={handler(counterData, updateCounter).prop('count')}
184
+ * />
185
+ */
186
+ export function handler<T>(componentData: T, updateFn: (newData: T) => void): {
187
+ prop: <K extends keyof T>(propName: K) => (newValue: T[K]) => void;
188
+ auto: <K extends keyof T>(propName: K) => (eventOrValue: any) => void;
189
+ full: (newData: T) => void;
190
+ };
191
+ /**
192
+ * Ultra-simplified binding API - completely generic component data handler
193
+ *
194
+ * Use this when you want a single unified way to handle all component events without
195
+ * having to write specific handler functions for each component.
196
+ *
197
+ * @template T
198
+ * @template K extends keyof T
199
+ * @param {T} componentData - Current component data
200
+ * @param {(data: T) => void} updateFn - Function to update component data
201
+ * @param {K} propName - Name of the property to update
202
+ * @returns {(newValue: T[K]) => void} A universal handler for the specified property
203
+ *
204
+ * @example
205
+ * // Import and use in any page:
206
+ * import { component, handle } from '$lib/svgun/universalGunBind';
207
+ *
208
+ * const [data, update] = component('myComponent', { count: 0, name: 'Test' });
209
+ *
210
+ * // Then in your template:
211
+ * <MyComponent
212
+ * count={data.count}
213
+ * name={data.name}
214
+ * onCountChange={handle(data, update, 'count')}
215
+ * onNameChange={handle(data, update, 'name')}
216
+ * />
217
+ */
218
+ export function handle<T, K>(componentData: T, updateFn: (data: T) => void, propName: K): (newValue: T[K]) => void;
219
+ //# sourceMappingURL=universalGunBind.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"universalGunBind.d.ts","sourceRoot":"","sources":["../src/universalGunBind.js"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,gDALW,MAAM,YAEd;IAAyB,WAAW;CACpC,OA0CF;AAED;;;;;;;GAOG;AACH,mCALW,MAAM,YAEd;IAAyB,WAAW;CACpC,YA+BF;AAED;;;;;;;;;;;GAWG;AAEH,wBARa,CAAC,aACH,OAAO,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,WACjC,MAAM,GAGJ,OAAO,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAM7C;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,0CAdW,MAAM,2BAuChB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,gCAbW,MAAM,sBAwBhB;AAED;;;;;;;;;;;GAWG;AACH,mCANa,CAAC,iBACH,MAAM,YAEd;IAAoB,gBAAgB,GAA5B,CAAC;CACT,OA6BF;AAED;;;;;;;;;;;GAWG;AACH,6BANa,CAAC,iBACH,MAAM,YAEd;IAAoB,gBAAgB,GAA5B,CAAC;CACT,OAkBF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,0BAtBa,CAAC,QACH,MAAM,iBACN,CAAC,GACC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,EAAE,MAAM,IAAI,CAAC,CAyBlD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,kCAjBa,CAAC,EACD,CAAC,iBACH,CAAC,YACD,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,YACpB,CAAC,GACC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAmBpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBArBa,CAAC,iBACH,CAAC,YACD,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,GAClB;IACR,IAAI,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACnE,IAAI,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,GAAG,KAAK,IAAI,CAAC;IACtE,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;CAC3B,CA8CH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,uBArBa,CAAC,EACD,CAAC,iBACH,CAAC,YACD,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,YACjB,CAAC,GACC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CA6BpC"}
@@ -0,0 +1,394 @@
1
+ /**
2
+ * unum Universal Binding - Completely generic Gun.js data binding for any Svelte component
3
+ *
4
+ * This module provides a universal binding mechanism for Gun.js data to Svelte components,
5
+ * supporting both Svelte 4 and 5 with a clean API.
6
+ */
7
+ import { connect } from './unum.js';
8
+ /**
9
+ * Create a universal binding between a component and Gun.js
10
+ *
11
+ * This function creates a binding that will automatically sync all component data
12
+ * with Gun.js without caring about the specific structure of the data.
13
+ *
14
+ * @param {string} gunPath - The Gun.js path where the data should be stored
15
+ * @param {Object} [options] - Configuration options
16
+ * @param {Object} [options.defaultData={}] - Default data to use if no data exists at the path
17
+ * @returns {Object} Props to pass to the component and methods to handle updates
18
+ */
19
+ export function createUniversalBinding(gunPath, options = {}) {
20
+ const { defaultData = {} } = options;
21
+ // Create Gun connection
22
+ const gunStore = connect(gunPath, { defaultData });
23
+ // Return binding object with props and update handler
24
+ return {
25
+ // Subscribe to Gun data changes
26
+ subscribe: gunStore.subscribe,
27
+ // Handle all component data changes automatically
28
+ handleDataChange: gunStore.handleChange,
29
+ // Get current data
30
+ get data() {
31
+ // Extract data from the store (will be reactive)
32
+ let currentData = {};
33
+ const unsubscribe = gunStore.subscribe(data => {
34
+ currentData = data;
35
+ });
36
+ unsubscribe();
37
+ return currentData;
38
+ },
39
+ // Update specific field
40
+ updateField(field, value) {
41
+ gunStore.updateField(field, value);
42
+ },
43
+ // Update entire data object
44
+ updateData(newData) {
45
+ gunStore.set(newData);
46
+ },
47
+ // Clean up when done
48
+ destroy() {
49
+ gunStore.destroy();
50
+ }
51
+ };
52
+ }
53
+ /**
54
+ * Universal HOC function to automatically bind any component to Gun.js
55
+ *
56
+ * @param {string} gunPath - The Gun.js path where the data should be stored
57
+ * @param {Object} [options] - Configuration options
58
+ * @param {Object} [options.defaultData={}] - Default data to use if no data exists at the path
59
+ * @returns {Function} A function that will bind component data to Gun.js
60
+ */
61
+ export function bindToGun(gunPath, options = {}) {
62
+ return function (Component) {
63
+ // Return a function that creates a new component with the right props
64
+ const WrappedComponent = function (wrapperOptions = {}) {
65
+ // Create Gun binding
66
+ const binding = createUniversalBinding(gunPath, wrapperOptions);
67
+ // Get the original component
68
+ const instance = new Component({
69
+ ...options,
70
+ props: {
71
+ ...binding.data,
72
+ ...(options.props || {}),
73
+ onDataChanged: binding.handleDataChange
74
+ }
75
+ });
76
+ // Add Gun-specific methods to the component instance
77
+ instance.$gunBinding = binding;
78
+ // Return the enhanced component instance
79
+ return instance;
80
+ };
81
+ // Ensure the constructor looks like a Svelte component
82
+ WrappedComponent.prototype = Component.prototype;
83
+ return WrappedComponent;
84
+ };
85
+ }
86
+ /**
87
+ * Create a universal component wrapper that automatically adds Gun.js binding
88
+ * This is the simplest API - developers just call this function and get a component
89
+ * that automatically syncs with Gun.js
90
+ *
91
+ * @template T
92
+ * @param {import('svelte').ComponentType<T>} Component - The component to wrap
93
+ * @param {string} gunPath - The Gun.js path where data should be stored
94
+ * @param {Object} [options] - Configuration options
95
+ * @param {any} [options.defaultData={}] - Default data structure for the component
96
+ * @returns {import('svelte').ComponentType<T>} A wrapped component that syncs with Gun.js
97
+ */
98
+ // eslint-disable-next-line no-unused-vars
99
+ export function gunBind(Component, gunPath) {
100
+ // For TypeScript compatibility, use a simpler approach
101
+ return Component;
102
+ }
103
+ /**
104
+ * Simplest form - universal Gun.js binding for any component
105
+ * Use this as a decorator pattern or HOC
106
+ *
107
+ * @param {string} gunPath - Gun.js path for data storage
108
+ * @param {Object} [options] - Configuration options
109
+ * @returns {Function} A component decorator function for universal binding
110
+ *
111
+ * @example
112
+ * // Basic usage directly in a .svelte file:
113
+ * import { universalGunBind } from '$lib/svgun/universalGunBind';
114
+ *
115
+ * // At the top of your component script:
116
+ * const { props, handleDataChange } = universalGunBind('myComponent');
117
+ *
118
+ * // Access data as {$props.whatever} in your template
119
+ * // When component data changes, call handleDataChange(newData)
120
+ */
121
+ export function universalGunBind(gunPath, options = {}) {
122
+ // Create the Gun binding
123
+ const binding = createUniversalBinding(gunPath, options);
124
+ // Get data from Gun as it changes
125
+ const props = {};
126
+ let unsubscribe = null;
127
+ // Setup subscription to Gun data
128
+ unsubscribe = binding.subscribe(data => {
129
+ // Update props with Gun data
130
+ Object.keys(data).forEach(key => {
131
+ props[key] = data[key];
132
+ });
133
+ });
134
+ // Return binding object to use in components
135
+ return {
136
+ props, // Pass this to component
137
+ handleDataChange: binding.handleDataChange, // Call this when component data changes
138
+ destroy: () => {
139
+ if (unsubscribe)
140
+ unsubscribe();
141
+ binding.destroy();
142
+ }
143
+ };
144
+ }
145
+ /**
146
+ * Rune-compatible version for Svelte 5
147
+ * Use this with the new runes syntax in Svelte 5
148
+ *
149
+ * @param {string} gunPath - Gun.js path for data storage
150
+ * @param {Object} [options] - Configuration options
151
+ * @returns {Object} A binding object with rune-compatible properties
152
+ *
153
+ * @example
154
+ * // In a Svelte 5 component with runes:
155
+ * import { useGun } from '$lib/svgun/universalGunBind';
156
+ *
157
+ * const { data, handleChange } = useGun('myComponent');
158
+ *
159
+ * // Access data directly as {data.whatever}
160
+ * // When component data changes, call handleChange(newData)
161
+ */
162
+ export function useGun(gunPath, options = {}) {
163
+ const binding = createUniversalBinding(gunPath, options);
164
+ // For Svelte 5 runes compatibility
165
+ return {
166
+ data: binding.data,
167
+ handleChange: binding.handleDataChange,
168
+ updateField: binding.updateField,
169
+ updateData: binding.updateData,
170
+ destroy: binding.destroy
171
+ };
172
+ }
173
+ /**
174
+ * Completely component-agnostic serialization approach
175
+ *
176
+ * This serializes and de-serializes entire components without needing to know
177
+ * any details of their structure. Pages don't need to handle component-specific data.
178
+ *
179
+ * @template T
180
+ * @param {string} componentName - Unique name for this component instance
181
+ * @param {Object} [options] - Configuration options
182
+ * @param {T} [options.defaultComponent={}] - Default component data
183
+ * @returns {Object} A component binding that handles all persistence automatically
184
+ */
185
+ export function serializeComponent(componentName, options = {}) {
186
+ const { defaultComponent = {} } = options;
187
+ // Create Gun connection with properly namespaced path
188
+ const gunStore = connect(`component_${componentName}`, { defaultData: defaultComponent });
189
+ // Return a single reactive object for this component
190
+ return {
191
+ // Get the component data
192
+ component: gunStore.data,
193
+ // Subscribe to component data changes (for reactive UI updates)
194
+ subscribe: gunStore.subscribe,
195
+ // Update the entire component at once
196
+ update(newComponentData) {
197
+ gunStore.set(newComponentData);
198
+ },
199
+ // Handle component updates
200
+ handleUpdate(componentData) {
201
+ gunStore.set(componentData);
202
+ },
203
+ // Clean up
204
+ destroy: gunStore.destroy
205
+ };
206
+ }
207
+ /**
208
+ * Even simpler black-box component serialization
209
+ *
210
+ * This function creates a binding where pages just get the component object without
211
+ * needing to know anything about its structure.
212
+ *
213
+ * @template T
214
+ * @param {string} componentName - Unique name for this component
215
+ * @param {Object} [options] - Configuration options
216
+ * @param {T} [options.defaultComponent={}] - Default component data
217
+ * @returns {Object} An object containing component props and update handler
218
+ */
219
+ export function getComponent(componentName, options = {}) {
220
+ const binding = serializeComponent(componentName, options);
221
+ return {
222
+ // The complete component data as a reactive object
223
+ componentData: binding.component,
224
+ // Component update handler - call this when component changes
225
+ onComponentChange: binding.handleUpdate,
226
+ // For Svelte store compatibility
227
+ subscribe: binding.subscribe,
228
+ // Clean up
229
+ destroy: binding.destroy
230
+ };
231
+ }
232
+ /**
233
+ * The simplest possible component serialization API
234
+ *
235
+ * This function provides a truly black-box binding where pages get
236
+ * a complete component and an update handler, with no concern for structure.
237
+ *
238
+ * @template T
239
+ * @param {string} name - Component identifier
240
+ * @param {T} [defaultState={}] - Default component state if none exists
241
+ * @returns {[T, (newState: T) => void, () => void]} [componentData, updateHandler, destroy]
242
+ *
243
+ * @example
244
+ * // In your page or component:
245
+ * import { component } from '$lib/svgun/universalGunBind';
246
+ *
247
+ * // Get component data and update handler
248
+ * const [todoData, updateTodo] = component('todo', {
249
+ * items: [],
250
+ * title: 'My Todos'
251
+ * });
252
+ *
253
+ * // Use it with any component - no need to know its structure
254
+ * <TodoComponent
255
+ * items={todoData.items}
256
+ * title={todoData.title}
257
+ * onItemsChanged={(items) => updateTodo({...todoData, items})}
258
+ * />
259
+ */
260
+ export function component(name, defaultState = {}) {
261
+ const { componentData, onComponentChange, destroy } = getComponent(name, { defaultComponent: defaultState });
262
+ // Return as a tuple for simpler usage:
263
+ // [componentData, updateHandler, cleanup]
264
+ return [componentData, onComponentChange, destroy];
265
+ }
266
+ /**
267
+ * Universal update handler for any component property
268
+ *
269
+ * This function creates a property-specific update handler for any component.
270
+ * It automatically handles merging the new property value with the existing component state.
271
+ *
272
+ * @template T
273
+ * @template K extends keyof T
274
+ * @param {T} componentData - The current component data
275
+ * @param {(newData: T) => void} updateFn - The component update function
276
+ * @param {K} propName - The property name to update
277
+ * @returns {(newValue: T[K]) => void} A property-specific update handler
278
+ *
279
+ * @example
280
+ * // In your page:
281
+ * import { component, createPropHandler } from '$lib/svgun/universalGunBind';
282
+ *
283
+ * const [counterData, updateCounter] = component('counter', { count: 0 });
284
+ * const handleCount = createPropHandler(counterData, updateCounter, 'count');
285
+ *
286
+ * // Then in your template:
287
+ * <PureCounter count={counterData.count} onCountChanged={handleCount} />
288
+ */
289
+ export function createPropHandler(componentData, updateFn, propName) {
290
+ return function (newValue) {
291
+ updateFn({
292
+ ...componentData,
293
+ [propName]: newValue
294
+ });
295
+ };
296
+ }
297
+ /**
298
+ * Universal component update handler for any event from any component
299
+ *
300
+ * This function creates a completely generic update handler that works with any component
301
+ * and any event type. It automatically detects what property changed and updates the component data.
302
+ *
303
+ * @template T
304
+ * @param {T} componentData - The current component data
305
+ * @param {(newData: T) => void} updateFn - The component update function
306
+ * @returns {{
307
+ * prop: <K extends keyof T>(propName: K) => (newValue: T[K]) => void,
308
+ * auto: <K extends keyof T>(propName: K) => (eventOrValue: any) => void,
309
+ * full: (newData: T) => void
310
+ * }} A handler object with methods for different property update patterns
311
+ *
312
+ * @example
313
+ * // In your page:
314
+ * import { component, handler } from '$lib/svgun/universalGunBind';
315
+ *
316
+ * const [counterData, updateCounter] = component('counter', { count: 0 });
317
+ *
318
+ * // Then in your template, use any of these patterns:
319
+ * <PureCounter
320
+ * count={counterData.count}
321
+ * onCountChanged={handler(counterData, updateCounter).prop('count')}
322
+ * />
323
+ */
324
+ export function handler(componentData, updateFn) {
325
+ return {
326
+ // Update a specific property
327
+ prop(propName) {
328
+ return (newValue) => {
329
+ updateFn({
330
+ ...componentData,
331
+ [propName]: newValue
332
+ });
333
+ };
334
+ },
335
+ // Smart handler that automatically detects property and value from event
336
+ // Works with both direct values and event objects with .target.value
337
+ auto(propName) {
338
+ return (eventOrValue) => {
339
+ const value = eventOrValue && eventOrValue.target
340
+ ? eventOrValue.target.value
341
+ : eventOrValue;
342
+ updateFn({
343
+ ...componentData,
344
+ [propName]: value
345
+ });
346
+ };
347
+ },
348
+ // Handle entire component update at once
349
+ full(newData) {
350
+ updateFn(newData);
351
+ }
352
+ };
353
+ }
354
+ /**
355
+ * Ultra-simplified binding API - completely generic component data handler
356
+ *
357
+ * Use this when you want a single unified way to handle all component events without
358
+ * having to write specific handler functions for each component.
359
+ *
360
+ * @template T
361
+ * @template K extends keyof T
362
+ * @param {T} componentData - Current component data
363
+ * @param {(data: T) => void} updateFn - Function to update component data
364
+ * @param {K} propName - Name of the property to update
365
+ * @returns {(newValue: T[K]) => void} A universal handler for the specified property
366
+ *
367
+ * @example
368
+ * // Import and use in any page:
369
+ * import { component, handle } from '$lib/svgun/universalGunBind';
370
+ *
371
+ * const [data, update] = component('myComponent', { count: 0, name: 'Test' });
372
+ *
373
+ * // Then in your template:
374
+ * <MyComponent
375
+ * count={data.count}
376
+ * name={data.name}
377
+ * onCountChange={handle(data, update, 'count')}
378
+ * onNameChange={handle(data, update, 'name')}
379
+ * />
380
+ */
381
+ export function handle(componentData, updateFn, propName) {
382
+ return function handleComponentEvent(newValue) {
383
+ // Extract value from event object if needed
384
+ const value = newValue && typeof newValue === 'object' && 'target' in newValue
385
+ ? newValue.target.value
386
+ : newValue;
387
+ // Update the component data with the new property value
388
+ updateFn({
389
+ ...componentData,
390
+ [propName]: value
391
+ });
392
+ };
393
+ }
394
+ //# sourceMappingURL=universalGunBind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"universalGunBind.js","sourceRoot":"","sources":["../src/universalGunBind.js"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@plures/unum",
3
+ "version": "0.2.2",
4
+ "description": "Modern Svelte bindings for PluresDB (pluresdb npm package) with Svelte 4 and 5 compatibility",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "LICENSE.md"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "test:coverage": "vitest run --coverage",
17
+ "test:prepublish": "node scripts/test-prepublish.js",
18
+ "lint": "eslint src/**/*.js",
19
+ "prepublishOnly": "npm run test && npm run build",
20
+ "publish:npm": "npm run prepublishOnly && npm publish --access public"
21
+ },
22
+ "keywords": [
23
+ "svelte",
24
+ "svelte5",
25
+ "reactive",
26
+ "store",
27
+ "runes",
28
+ "database",
29
+ "decentralized",
30
+ "pluresdb",
31
+ "p2p"
32
+ ],
33
+ "author": "Oasis Team",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/plures/unum"
38
+ },
39
+ "peerDependencies": {
40
+ "svelte": "^4.0.0 || ^5.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "@vitest/coverage-v8": "^1.0.0",
44
+ "eslint": "^8.0.0",
45
+ "jsdom": "^24.0.0",
46
+ "typescript": "^5.8.2",
47
+ "vitest": "^1.0.0"
48
+ }
49
+ }