@getmicdrop/svelte-components 5.7.2 → 5.8.1

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 (44) hide show
  1. package/dist/primitives/Checkbox/Checkbox.svelte +3 -3
  2. package/dist/stores/auth.svelte.d.ts +39 -0
  3. package/dist/stores/auth.svelte.d.ts.map +1 -0
  4. package/dist/stores/auth.svelte.js +60 -0
  5. package/dist/stores/formDataStore.svelte.d.ts +47 -0
  6. package/dist/stores/formDataStore.svelte.d.ts.map +1 -0
  7. package/dist/stores/formDataStore.svelte.js +84 -0
  8. package/dist/stores/formSave.svelte.d.ts +33 -0
  9. package/dist/stores/formSave.svelte.d.ts.map +1 -0
  10. package/dist/stores/formSave.svelte.js +113 -0
  11. package/dist/stores/index.d.ts +4 -4
  12. package/dist/stores/index.js +6 -7
  13. package/dist/stores/navigation.svelte.d.ts +35 -0
  14. package/dist/stores/navigation.svelte.d.ts.map +1 -0
  15. package/dist/stores/navigation.svelte.js +69 -0
  16. package/package.json +8 -9
  17. package/dist/stores/auth.js +0 -36
  18. package/dist/stores/auth.spec.d.ts +0 -2
  19. package/dist/stores/auth.spec.d.ts.map +0 -1
  20. package/dist/stores/auth.spec.js +0 -139
  21. package/dist/stores/createFormStore.d.ts +0 -77
  22. package/dist/stores/createFormStore.d.ts.map +0 -1
  23. package/dist/stores/createFormStore.js +0 -410
  24. package/dist/stores/createFormStore.spec.d.ts +0 -2
  25. package/dist/stores/createFormStore.spec.d.ts.map +0 -1
  26. package/dist/stores/createFormStore.spec.js +0 -540
  27. package/dist/stores/formDataStore.d.ts +0 -17
  28. package/dist/stores/formDataStore.d.ts.map +0 -1
  29. package/dist/stores/formDataStore.js +0 -25
  30. package/dist/stores/formDataStore.spec.d.ts +0 -2
  31. package/dist/stores/formDataStore.spec.d.ts.map +0 -1
  32. package/dist/stores/formDataStore.spec.js +0 -257
  33. package/dist/stores/formSave.d.ts +0 -24
  34. package/dist/stores/formSave.d.ts.map +0 -1
  35. package/dist/stores/formSave.js +0 -132
  36. package/dist/stores/formSave.spec.d.ts +0 -2
  37. package/dist/stores/formSave.spec.d.ts.map +0 -1
  38. package/dist/stores/formSave.spec.js +0 -296
  39. package/dist/stores/navigation.d.ts +0 -5
  40. package/dist/stores/navigation.d.ts.map +0 -1
  41. package/dist/stores/navigation.js +0 -12
  42. package/dist/stores/navigation.spec.d.ts +0 -2
  43. package/dist/stores/navigation.spec.d.ts.map +0 -1
  44. package/dist/stores/navigation.spec.js +0 -136
@@ -1,139 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { get } from 'svelte/store';
3
- import { auth, setAuthState, clearAuthState, initializeAuthState } from './auth';
4
-
5
- describe('auth store', () => {
6
- beforeEach(() => {
7
- // Reset auth state before each test
8
- clearAuthState();
9
- // Clear cookies
10
- Object.defineProperty(document, 'cookie', {
11
- writable: true,
12
- value: '',
13
- });
14
- });
15
-
16
- describe('initial state', () => {
17
- it('starts with isAuthenticated as false', () => {
18
- expect(get(auth).isAuthenticated).toBe(false);
19
- });
20
-
21
- it('starts with token as null', () => {
22
- expect(get(auth).token).toBe(null);
23
- });
24
-
25
- it('starts with userDetails as null', () => {
26
- expect(get(auth).userDetails).toBe(null);
27
- });
28
- });
29
-
30
- describe('setAuthState', () => {
31
- it('sets authentication state', () => {
32
- setAuthState({
33
- isAuthenticated: true,
34
- token: 'test-token',
35
- userDetails: { email: 'test@test.com' },
36
- });
37
-
38
- const state = get(auth);
39
- expect(state.isAuthenticated).toBe(true);
40
- expect(state.token).toBe('test-token');
41
- expect(state.userDetails).toEqual({ email: 'test@test.com' });
42
- });
43
-
44
- it('can update partial state', () => {
45
- setAuthState({ isAuthenticated: true, token: 'token1', userDetails: null });
46
- setAuthState({ isAuthenticated: true, token: 'token2', userDetails: { name: 'User' } });
47
-
48
- const state = get(auth);
49
- expect(state.token).toBe('token2');
50
- expect(state.userDetails).toEqual({ name: 'User' });
51
- });
52
- });
53
-
54
- describe('clearAuthState', () => {
55
- it('clears authentication state', () => {
56
- setAuthState({
57
- isAuthenticated: true,
58
- token: 'test-token',
59
- userDetails: { email: 'test@test.com' },
60
- });
61
-
62
- clearAuthState();
63
-
64
- const state = get(auth);
65
- expect(state.isAuthenticated).toBe(false);
66
- expect(state.token).toBe(null);
67
- expect(state.userDetails).toBe(null);
68
- });
69
- });
70
-
71
- describe('initializeAuthState', () => {
72
- it('does nothing when no performer_token cookie exists', () => {
73
- Object.defineProperty(document, 'cookie', {
74
- writable: true,
75
- value: '',
76
- });
77
-
78
- initializeAuthState();
79
-
80
- const state = get(auth);
81
- expect(state.isAuthenticated).toBe(false);
82
- });
83
-
84
- it('sets auth state from performer_token cookie', () => {
85
- Object.defineProperty(document, 'cookie', {
86
- writable: true,
87
- value: 'performer_token=my-token',
88
- });
89
-
90
- initializeAuthState();
91
-
92
- const state = get(auth);
93
- expect(state.isAuthenticated).toBe(true);
94
- expect(state.token).toBe('my-token');
95
- });
96
-
97
- it('parses userDetails cookie when present', () => {
98
- const userDetails = JSON.stringify({ email: 'test@test.com', firstName: 'Test' });
99
- Object.defineProperty(document, 'cookie', {
100
- writable: true,
101
- value: `performer_token=my-token; userDetails=${encodeURIComponent(userDetails)}`,
102
- });
103
-
104
- initializeAuthState();
105
-
106
- const state = get(auth);
107
- expect(state.userDetails).toEqual({ email: 'test@test.com', firstName: 'Test' });
108
- });
109
-
110
- it('handles missing userDetails cookie', () => {
111
- Object.defineProperty(document, 'cookie', {
112
- writable: true,
113
- value: 'performer_token=my-token',
114
- });
115
-
116
- initializeAuthState();
117
-
118
- const state = get(auth);
119
- expect(state.isAuthenticated).toBe(true);
120
- expect(state.userDetails).toBe(null);
121
- });
122
- });
123
-
124
- describe('store subscription', () => {
125
- it('can subscribe to auth changes', () => {
126
- const values = [];
127
- const unsubscribe = auth.subscribe((value) => {
128
- values.push(value.isAuthenticated);
129
- });
130
-
131
- setAuthState({ isAuthenticated: true, token: 'token', userDetails: null });
132
- clearAuthState();
133
-
134
- unsubscribe();
135
-
136
- expect(values).toEqual([false, true, false]);
137
- });
138
- });
139
- });
@@ -1,77 +0,0 @@
1
- /**
2
- * @deprecated Use createFormStore from '@getmicdrop/svelte-components/forms' instead.
3
- * @typedef {Object} FormStoreOptions
4
- * @property {Object} initialData - Initial form data
5
- * @property {string} [endpoint] - API endpoint for saving
6
- * @property {string} [successMessage] - Message to show on success
7
- * @property {string} [errorMessage] - Message to show on error
8
- * @property {Function} [validate] - Validation function returning { isValid, errors }
9
- * @property {Function} [transformData] - Transform data before saving
10
- * @property {Function} [onSuccess] - Callback after successful save
11
- * @property {Function} [onError] - Callback after error
12
- * @property {boolean} [showToasts=true] - Show toast notifications
13
- */
14
- /**
15
- * @deprecated Use createFormStore from '@getmicdrop/svelte-components/forms' instead.
16
- *
17
- * Creates a comprehensive form store with state management, dirty tracking,
18
- * validation, and save handling.
19
- *
20
- * @param {FormStoreOptions} options - Configuration options
21
- * @returns {Object} Form store with all state and handlers
22
- *
23
- * @example
24
- * const form = createFormStore({
25
- * initialData: { name: '', email: '' },
26
- * endpoint: '/api/profile',
27
- * validate: (data) => {
28
- * const errors = {};
29
- * if (!data.name) errors.name = 'Name is required';
30
- * return { isValid: Object.keys(errors).length === 0, errors };
31
- * }
32
- * });
33
- *
34
- * // In Svelte component:
35
- * <input bind:value={$form.data.name} on:input={form.checkDirty} />
36
- * <button on:click={form.submit} disabled={$form.isLoading}>Save</button>
37
- */
38
- export function createFormStore(options?: FormStoreOptions): Object;
39
- export type FormStoreOptions = {
40
- /**
41
- * - Initial form data
42
- */
43
- initialData: Object;
44
- /**
45
- * - API endpoint for saving
46
- */
47
- endpoint?: string | undefined;
48
- /**
49
- * - Message to show on success
50
- */
51
- successMessage?: string | undefined;
52
- /**
53
- * - Message to show on error
54
- */
55
- errorMessage?: string | undefined;
56
- /**
57
- * - Validation function returning { isValid, errors }
58
- */
59
- validate?: Function | undefined;
60
- /**
61
- * - Transform data before saving
62
- */
63
- transformData?: Function | undefined;
64
- /**
65
- * - Callback after successful save
66
- */
67
- onSuccess?: Function | undefined;
68
- /**
69
- * - Callback after error
70
- */
71
- onError?: Function | undefined;
72
- /**
73
- * - Show toast notifications
74
- */
75
- showToasts?: boolean | undefined;
76
- };
77
- //# sourceMappingURL=createFormStore.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createFormStore.d.ts","sourceRoot":"","sources":["../../src/lib/stores/createFormStore.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,0CAlBW,gBAAgB,GACd,MAAM,CAgXlB;;;;;iBAlYa,MAAM"}
@@ -1,410 +0,0 @@
1
- /**
2
- * @deprecated Use `@getmicdrop/svelte-components/forms` instead.
3
- * This Svelte 4 store-based implementation will be removed in the next major version.
4
- *
5
- * Migration:
6
- * ```typescript
7
- * // Old (Svelte 4 stores):
8
- * import { createFormStore } from '@getmicdrop/svelte-components/stores/createFormStore';
9
- * const form = createFormStore({ initialData: {...}, endpoint: '...' });
10
- *
11
- * // New (Svelte 5 runes):
12
- * import { createFormStore } from '@getmicdrop/svelte-components/forms';
13
- * import { z } from 'zod';
14
- * const schema = z.object({ name: z.string(), email: z.string().email() });
15
- * const form = createFormStore(schema, { name: '', email: '' });
16
- * ```
17
- */
18
- import { writable, derived, get } from "svelte/store";
19
- import { showToast } from "./toaster";
20
-
21
- /**
22
- * @deprecated Use createFormStore from '@getmicdrop/svelte-components/forms' instead.
23
- * @typedef {Object} FormStoreOptions
24
- * @property {Object} initialData - Initial form data
25
- * @property {string} [endpoint] - API endpoint for saving
26
- * @property {string} [successMessage] - Message to show on success
27
- * @property {string} [errorMessage] - Message to show on error
28
- * @property {Function} [validate] - Validation function returning { isValid, errors }
29
- * @property {Function} [transformData] - Transform data before saving
30
- * @property {Function} [onSuccess] - Callback after successful save
31
- * @property {Function} [onError] - Callback after error
32
- * @property {boolean} [showToasts=true] - Show toast notifications
33
- */
34
-
35
- /**
36
- * @deprecated Use createFormStore from '@getmicdrop/svelte-components/forms' instead.
37
- *
38
- * Creates a comprehensive form store with state management, dirty tracking,
39
- * validation, and save handling.
40
- *
41
- * @param {FormStoreOptions} options - Configuration options
42
- * @returns {Object} Form store with all state and handlers
43
- *
44
- * @example
45
- * const form = createFormStore({
46
- * initialData: { name: '', email: '' },
47
- * endpoint: '/api/profile',
48
- * validate: (data) => {
49
- * const errors = {};
50
- * if (!data.name) errors.name = 'Name is required';
51
- * return { isValid: Object.keys(errors).length === 0, errors };
52
- * }
53
- * });
54
- *
55
- * // In Svelte component:
56
- * <input bind:value={$form.data.name} on:input={form.checkDirty} />
57
- * <button on:click={form.submit} disabled={$form.isLoading}>Save</button>
58
- */
59
- export function createFormStore(options = {}) {
60
- console.warn(
61
- '[DEPRECATED] createFormStore from stores/createFormStore is deprecated. ' +
62
- 'Use createFormStore from @getmicdrop/svelte-components/forms instead.'
63
- );
64
- const {
65
- initialData = {},
66
- endpoint = "",
67
- successMessage = "Changes saved successfully",
68
- errorMessage = "Failed to save changes",
69
- validate,
70
- transformData,
71
- onSuccess,
72
- onError,
73
- showToasts = true,
74
- } = options;
75
-
76
- // Deep clone initial data to prevent mutations
77
- const cloneData = (data) => JSON.parse(JSON.stringify(data));
78
-
79
- // Core state stores
80
- const data = writable(cloneData(initialData));
81
- const initial = writable(cloneData(initialData));
82
- const errors = writable({});
83
- const isLoading = writable(false);
84
- const isSuccess = writable(false);
85
- const saveError = writable(null);
86
- const showErrors = writable(false);
87
-
88
- // Derived states
89
- const isDirty = derived(
90
- [data, initial],
91
- ([$data, $initial]) => JSON.stringify($data) !== JSON.stringify($initial)
92
- );
93
-
94
- const isValid = derived(
95
- errors,
96
- ($errors) => countErrors($errors) === 0
97
- );
98
-
99
- const errorCount = derived(
100
- errors,
101
- ($errors) => countErrors($errors)
102
- );
103
-
104
- const errorList = derived(
105
- errors,
106
- ($errors) => flattenErrors($errors)
107
- );
108
-
109
- /**
110
- * Count total errors in a nested error object
111
- */
112
- function countErrors(errorObj) {
113
- let count = 0;
114
- const traverse = (obj) => {
115
- if (!obj || typeof obj !== 'object') return;
116
- Object.values(obj).forEach(value => {
117
- if (typeof value === 'string' && value) {
118
- count++;
119
- } else if (typeof value === 'object') {
120
- traverse(value);
121
- }
122
- });
123
- };
124
- traverse(errorObj);
125
- return count;
126
- }
127
-
128
- /**
129
- * Flatten nested errors into array of { field, message, section }
130
- */
131
- function flattenErrors(errorObj) {
132
- const list = [];
133
- const traverse = (obj, section = '') => {
134
- if (!obj || typeof obj !== 'object') return;
135
- Object.entries(obj).forEach(([key, value]) => {
136
- if (typeof value === 'string' && value) {
137
- list.push({ field: key, message: value, section });
138
- } else if (typeof value === 'object') {
139
- traverse(value, key);
140
- }
141
- });
142
- };
143
- traverse(errorObj);
144
- return list;
145
- }
146
-
147
- /**
148
- * Update form data (partial update)
149
- */
150
- function updateData(updates) {
151
- data.update(current => ({ ...current, ...updates }));
152
- }
153
-
154
- /**
155
- * Update a specific section of form data
156
- */
157
- function updateSection(section, updates) {
158
- data.update(current => ({
159
- ...current,
160
- [section]: { ...current[section], ...updates }
161
- }));
162
- }
163
-
164
- /**
165
- * Update a specific field
166
- */
167
- function updateField(section, field, value) {
168
- data.update(current => ({
169
- ...current,
170
- [section]: { ...current[section], [field]: value }
171
- }));
172
- }
173
-
174
- /**
175
- * Check if form is dirty (call after data changes)
176
- */
177
- function checkDirty() {
178
- // Dirty state is computed automatically via derived store
179
- // Reset success state when dirty
180
- const dirty = get(isDirty);
181
- if (dirty) {
182
- isSuccess.set(false);
183
- }
184
- return dirty;
185
- }
186
-
187
- /**
188
- * Run validation and update errors
189
- * @returns {boolean} Whether form is valid
190
- */
191
- function runValidation() {
192
- if (!validate) {
193
- errors.set({});
194
- return true;
195
- }
196
-
197
- const currentData = get(data);
198
- const result = validate(currentData);
199
-
200
- if (typeof result === 'boolean') {
201
- // Simple boolean validation
202
- return result;
203
- }
204
-
205
- // Object-based validation { isValid, errors }
206
- errors.set(result.errors || {});
207
- return result.isValid;
208
- }
209
-
210
- /**
211
- * Clear all errors
212
- */
213
- function clearErrors() {
214
- errors.set({});
215
- showErrors.set(false);
216
- }
217
-
218
- /**
219
- * Clear error for specific field
220
- */
221
- function clearFieldError(section, field) {
222
- errors.update(current => {
223
- if (current[section]) {
224
- const updated = { ...current };
225
- updated[section] = { ...current[section] };
226
- delete updated[section][field];
227
- return updated;
228
- }
229
- return current;
230
- });
231
- }
232
-
233
- /**
234
- * Set error for specific field
235
- */
236
- function setFieldError(section, field, message) {
237
- errors.update(current => ({
238
- ...current,
239
- [section]: { ...current[section], [field]: message }
240
- }));
241
- }
242
-
243
- /**
244
- * Submit the form
245
- * @param {string} [customEndpoint] - Override default endpoint
246
- * @returns {Promise<boolean>} Success status
247
- */
248
- async function submit(customEndpoint = null) {
249
- showErrors.set(true);
250
-
251
- // Run validation
252
- const valid = runValidation();
253
- if (!valid) {
254
- return false;
255
- }
256
-
257
- const targetEndpoint = customEndpoint || endpoint;
258
- if (!targetEndpoint) {
259
- console.error("No endpoint specified for form save");
260
- return false;
261
- }
262
-
263
- isLoading.set(true);
264
- isSuccess.set(false);
265
- saveError.set(null);
266
-
267
- try {
268
- let submitData = get(data);
269
-
270
- // Transform data if transformer provided
271
- if (transformData) {
272
- submitData = transformData(submitData);
273
- }
274
-
275
- const res = await fetch(targetEndpoint, {
276
- method: "POST",
277
- headers: { "Content-Type": "application/json" },
278
- body: JSON.stringify(submitData),
279
- });
280
-
281
- if (res.ok) {
282
- isSuccess.set(true);
283
- // Update initial data to current (form is now clean)
284
- initial.set(cloneData(get(data)));
285
-
286
- if (showToasts && successMessage) {
287
- showToast(successMessage, "success");
288
- }
289
- onSuccess?.();
290
- return true;
291
- } else {
292
- const errorData = await res.json().catch(() => ({}));
293
- const errorMsg = errorData.message || errorMessage;
294
- saveError.set(errorMsg);
295
-
296
- if (showToasts) {
297
- showToast(errorMsg, "error");
298
- }
299
- onError?.(errorMsg);
300
- return false;
301
- }
302
- } catch (err) {
303
- const errorMsg = err.message || "Something went wrong";
304
- saveError.set(errorMsg);
305
-
306
- if (showToasts) {
307
- showToast(errorMsg, "error");
308
- }
309
- onError?.(errorMsg);
310
- return false;
311
- } finally {
312
- isLoading.set(false);
313
- }
314
- }
315
-
316
- /**
317
- * Reset form to initial data
318
- */
319
- function reset() {
320
- data.set(cloneData(get(initial)));
321
- errors.set({});
322
- showErrors.set(false);
323
- isSuccess.set(false);
324
- saveError.set(null);
325
- }
326
-
327
- /**
328
- * Reset form to new initial data
329
- */
330
- function resetTo(newInitialData) {
331
- const cloned = cloneData(newInitialData);
332
- initial.set(cloned);
333
- data.set(cloned);
334
- errors.set({});
335
- showErrors.set(false);
336
- isSuccess.set(false);
337
- saveError.set(null);
338
- }
339
-
340
- /**
341
- * Reset only the success state
342
- */
343
- function resetSuccess() {
344
- isSuccess.set(false);
345
- }
346
-
347
- /**
348
- * Mark form as saved (update initial to match current)
349
- */
350
- function markSaved() {
351
- initial.set(cloneData(get(data)));
352
- isSuccess.set(true);
353
- }
354
-
355
- // Create a subscribable store that combines all state
356
- const combinedStore = derived(
357
- [data, errors, isLoading, isSuccess, saveError, isDirty, isValid, errorCount, showErrors],
358
- ([$data, $errors, $isLoading, $isSuccess, $saveError, $isDirty, $isValid, $errorCount, $showErrors]) => ({
359
- data: $data,
360
- errors: $errors,
361
- isLoading: $isLoading,
362
- isSuccess: $isSuccess,
363
- saveError: $saveError,
364
- isDirty: $isDirty,
365
- isValid: $isValid,
366
- errorCount: $errorCount,
367
- showErrors: $showErrors,
368
- })
369
- );
370
-
371
- return {
372
- // Subscribable combined store
373
- subscribe: combinedStore.subscribe,
374
-
375
- // Individual stores (for direct subscription)
376
- data,
377
- errors,
378
- isLoading,
379
- isSuccess,
380
- saveError,
381
- isDirty,
382
- isValid,
383
- errorCount,
384
- errorList,
385
- showErrors,
386
-
387
- // Actions
388
- updateData,
389
- updateSection,
390
- updateField,
391
- checkDirty,
392
- runValidation,
393
- clearErrors,
394
- clearFieldError,
395
- setFieldError,
396
- submit,
397
- reset,
398
- resetTo,
399
- resetSuccess,
400
- markSaved,
401
-
402
- // Convenience getters
403
- get currentData() { return get(data); },
404
- get currentErrors() { return get(errors); },
405
- get loading() { return get(isLoading); },
406
- get success() { return get(isSuccess); },
407
- get dirty() { return get(isDirty); },
408
- get valid() { return get(isValid); },
409
- };
410
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=createFormStore.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createFormStore.spec.d.ts","sourceRoot":"","sources":["../../src/lib/stores/createFormStore.spec.js"],"names":[],"mappings":""}