@friendofsvelte/state 0.0.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.
- package/README.md +139 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/state.svelte.d.ts +16 -0
- package/dist/state.svelte.js +31 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Persistent Svelte 5 State
|
|
2
|
+
|
|
3
|
+
A lightweight, type-safe state management solution for Svelte applications with built-in storage persistence.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎯 **Type-safe**: Full TypeScript support with automatic type inference
|
|
8
|
+
- 💾 **Persistent Storage**: Automatic state persistence in localStorage or sessionStorage
|
|
9
|
+
- 🪶 **Lightweight**: Zero dependencies beyond Svelte
|
|
10
|
+
- âš¡ **Reactive**: Seamless integration with Svelte's reactivity system
|
|
11
|
+
- 🔄 **Auto-sync**: Automatically syncs state across components
|
|
12
|
+
- 📦 **Simple API**: Just one function to manage all your state needs
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @friendofsvelte/state
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
1. Define your types in your `app.d.ts`:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
declare global {
|
|
26
|
+
interface PodTypeRegistry {
|
|
27
|
+
layout: {
|
|
28
|
+
bg: string;
|
|
29
|
+
};
|
|
30
|
+
userSettings: {
|
|
31
|
+
theme: 'light' | 'dark';
|
|
32
|
+
fontSize: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export {};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. Use in your components:
|
|
41
|
+
|
|
42
|
+
```svelte
|
|
43
|
+
<script lang="ts">
|
|
44
|
+
import { pod } from '@friendofsvelte/state';
|
|
45
|
+
|
|
46
|
+
// Initialize with value
|
|
47
|
+
let app = pod('layout', 'localStorage', {
|
|
48
|
+
bg: 'lightblue'
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Or use existing value
|
|
52
|
+
let settings = pod('userSettings');
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<div style="background-color: {app.bg}">
|
|
56
|
+
<!-- Your content -->
|
|
57
|
+
</div>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API Reference
|
|
61
|
+
|
|
62
|
+
### `pod<K>(key: K, storage?: StorageType, context?: GetTypeFromRegistry<K>)`
|
|
63
|
+
|
|
64
|
+
Creates or retrieves a persistent state container.
|
|
65
|
+
|
|
66
|
+
Parameters:
|
|
67
|
+
- `key`: Unique identifier for the state container
|
|
68
|
+
- `storage`: (Optional) Storage type - 'localStorage' or 'sessionStorage' (default: 'localStorage')
|
|
69
|
+
- `context`: (Optional) Initial state value
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
- A reactive state object of type `GetTypeFromRegistry<K>`
|
|
73
|
+
|
|
74
|
+
## Type Safety
|
|
75
|
+
|
|
76
|
+
Pod State provides complete type safety through TypeScript. The global `PodTypeRegistry` interface allows you to define types for all your state containers in one place:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
interface PodTypeRegistry {
|
|
80
|
+
layout: {
|
|
81
|
+
bg: string;
|
|
82
|
+
};
|
|
83
|
+
userSettings: {
|
|
84
|
+
theme: 'light' | 'dark';
|
|
85
|
+
fontSize: number;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Examples
|
|
91
|
+
|
|
92
|
+
### Basic Usage
|
|
93
|
+
|
|
94
|
+
```svelte
|
|
95
|
+
<script lang="ts">
|
|
96
|
+
import { pod } from '@friendofsvelte/state';
|
|
97
|
+
|
|
98
|
+
let app = pod('layout', 'localStorage', {
|
|
99
|
+
bg: 'lightblue'
|
|
100
|
+
});
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<button onclick={() => app.bg = 'lightgreen'}>
|
|
104
|
+
Change Background
|
|
105
|
+
</button>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Shared State
|
|
109
|
+
|
|
110
|
+
```svelte
|
|
111
|
+
<!-- ComponentA.svelte -->
|
|
112
|
+
<script>
|
|
113
|
+
import { pod } from '@friendofsvelte/state';
|
|
114
|
+
let settings = pod('userSettings');
|
|
115
|
+
</script>
|
|
116
|
+
|
|
117
|
+
<!-- ComponentB.svelte -->
|
|
118
|
+
<script>
|
|
119
|
+
import { pod } from '@friendofsvelte/state';
|
|
120
|
+
let settings = pod('userSettings');
|
|
121
|
+
// Will automatically sync with ComponentA
|
|
122
|
+
</script>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Testing
|
|
126
|
+
|
|
127
|
+
Pod State includes a test suite to ensure reliability. Run tests with:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npm test
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Contributing
|
|
134
|
+
|
|
135
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT License - see LICENSE file for details
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type StorageType = 'localStorage' | 'sessionStorage';
|
|
2
|
+
type TypeRegistry = {
|
|
3
|
+
[K in PropertyKey]: unknown;
|
|
4
|
+
};
|
|
5
|
+
declare global {
|
|
6
|
+
type PodTypeRegistry = TypeRegistry;
|
|
7
|
+
}
|
|
8
|
+
type GetTypeFromRegistry<K extends keyof PodTypeRegistry> = PodTypeRegistry[K] extends never ? unknown : PodTypeRegistry[K];
|
|
9
|
+
/**
|
|
10
|
+
* Get a persistent state from storage, or initialize with an optional context.
|
|
11
|
+
* @param key - The key to store the state.
|
|
12
|
+
* @param storage - The storage type to use.
|
|
13
|
+
* @param context - The initial state or override.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pod<K extends keyof PodTypeRegistry>(key: K, storage?: StorageType, context?: GetTypeFromRegistry<K>): GetTypeFromRegistry<K>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
|
+
function track(key, storage, context) {
|
|
3
|
+
let state = $state(context ?? {});
|
|
4
|
+
if (typeof window !== 'undefined') {
|
|
5
|
+
if (context === undefined) {
|
|
6
|
+
const storedValue = untrack(() => window[storage].getItem(String(key)));
|
|
7
|
+
if (storedValue) {
|
|
8
|
+
try {
|
|
9
|
+
state = JSON.parse(storedValue);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
state = {};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
$effect.pre(() => {
|
|
17
|
+
const json = JSON.stringify($state.snapshot(state));
|
|
18
|
+
window[storage].setItem(String(key), json);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return state;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get a persistent state from storage, or initialize with an optional context.
|
|
25
|
+
* @param key - The key to store the state.
|
|
26
|
+
* @param storage - The storage type to use.
|
|
27
|
+
* @param context - The initial state or override.
|
|
28
|
+
*/
|
|
29
|
+
export function pod(key, storage = 'localStorage', context) {
|
|
30
|
+
return track(key, storage, context);
|
|
31
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@friendofsvelte/state",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"dev": "vite dev",
|
|
6
|
+
"build": "vite build && npm run prepack",
|
|
7
|
+
"preview": "vite preview",
|
|
8
|
+
"prepare": "svelte-kit sync || echo ''",
|
|
9
|
+
"prepack": "svelte-kit sync && svelte-package && publint",
|
|
10
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
11
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
12
|
+
"format": "prettier --write .",
|
|
13
|
+
"lint": "prettier --check . && eslint .",
|
|
14
|
+
"test:unit": "vitest",
|
|
15
|
+
"test": "npm run test:unit -- --run"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"!dist/**/*.test.*",
|
|
20
|
+
"!dist/**/*.spec.*"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": [
|
|
23
|
+
"**/*.css"
|
|
24
|
+
],
|
|
25
|
+
"svelte": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"svelte": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"svelte": "^5.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/compat": "^1.2.5",
|
|
39
|
+
"@eslint/js": "^9.18.0",
|
|
40
|
+
"@sveltejs/adapter-auto": "^4.0.0",
|
|
41
|
+
"@sveltejs/kit": "^2.16.0",
|
|
42
|
+
"@sveltejs/package": "^2.0.0",
|
|
43
|
+
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
|
44
|
+
"@tailwindcss/vite": "^4.0.0",
|
|
45
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
46
|
+
"@testing-library/svelte": "^5.2.4",
|
|
47
|
+
"eslint": "^9.18.0",
|
|
48
|
+
"eslint-config-prettier": "^10.0.1",
|
|
49
|
+
"eslint-plugin-svelte": "^2.46.1",
|
|
50
|
+
"globals": "^15.14.0",
|
|
51
|
+
"jsdom": "^25.0.1",
|
|
52
|
+
"prettier": "^3.4.2",
|
|
53
|
+
"prettier-plugin-svelte": "^3.3.3",
|
|
54
|
+
"prettier-plugin-tailwindcss": "^0.6.11",
|
|
55
|
+
"publint": "^0.3.2",
|
|
56
|
+
"svelte": "^5.0.0",
|
|
57
|
+
"svelte-check": "^4.0.0",
|
|
58
|
+
"tailwindcss": "^4.0.0",
|
|
59
|
+
"typescript": "^5.0.0",
|
|
60
|
+
"typescript-eslint": "^8.20.0",
|
|
61
|
+
"vite": "^6.0.0",
|
|
62
|
+
"vitest": "^3.0.0"
|
|
63
|
+
}
|
|
64
|
+
}
|