Skip to content

Commit 37fa378

Browse files
added store options functions with scope
1 parent 273bc4c commit 37fa378

File tree

11 files changed

+209
-8
lines changed

11 files changed

+209
-8
lines changed

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ const vehicleStoreWithComponentScope = useVehicleStore()
107107

108108
```ts
109109
// vehicle-store.ts
110-
import { type StoreCreatorContext } from 'pinia-scope'
110+
import { type StoreCreatorContext, defineScopeableStore } from 'pinia-scope'
111111
import { useTireStore } from 'tire-store.ts'
112112

113113
export const useVehicleStore = defineScopeableStore('vehicles', ({ scope }: StoreCreatorContext) => {
@@ -278,6 +278,23 @@ const vehicleStoreUnscoped = useVehicleStore.componentScoped()
278278
const vehicleStoreScoped = useVehicleStore('my-scope')
279279
```
280280

281+
282+
### Pinia Plugins
283+
The scope can be used to determine plugin options by passing a function as the store options argument.
284+
```ts
285+
// main.js
286+
import { defineScopeableStore } from 'pinia-scope'
287+
288+
export const useVehicleStore = defineScopeableStore('vehicles', ({ scope }: StoreCreatorContext) => {
289+
290+
// ...
291+
}, (scope: string) => {
292+
return {
293+
somePluginOption: scope === 'foo'
294+
}
295+
})
296+
```
297+
281298
## API
282299

283300
All API methods (excluding `attachPiniaScope()`) will work inside a vue component or a context where [getActivePinia()](https://pinia.vuejs.org/api/pinia/functions/getActivePinia.html#getActivePinia-) will return a result.

examples/vehicle-editor/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@vitejs/plugin-vue": "^6.0.0",
1919
"@vue/tsconfig": "^0.7.0",
2020
"file-saver": "^2.0.5",
21+
"pinia-plugin-persistedstate": "^4.5.0",
2122
"sass": "^1.77.6",
2223
"typescript": "~5.8.3",
2324
"vite": "^7.0.3",

examples/vehicle-editor/src/main.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import { createPinia } from 'pinia'
44

55
import './scss/styles.scss'
66
import { attachPiniaScope } from 'pinia-scope'
7+
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
78

89
const app = createApp(App)
910
const pinia = createPinia()
11+
pinia.use(piniaPluginPersistedstate);
1012

1113
attachPiniaScope(pinia)
1214
app.use(pinia)

examples/vehicle-editor/src/store/engine-store.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,9 @@ export const useEngineStore = defineScopeableStore('engines', ({ scope }) => {
126126
get,
127127
$reset,
128128
}
129+
}, (scope: string) => {
130+
return {
131+
persist: scope === '',
132+
}
129133
})
130134

examples/vehicle-editor/src/store/vehicle-store.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,9 @@ export const useVehicleStore = defineScopeableStore('vehicles', ({ scope }) => {
9292
get,
9393
getInfo,
9494
}
95+
}, (scope: string) => {
96+
return {
97+
persist: scope === '',
98+
}
9599
})
96100

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "pinia-scope",
33
"type": "module",
4-
"version": "1.5.1",
5-
"packageManager": "pnpm@10.13.1",
4+
"version": "1.6.0",
5+
"packageManager": "pnpm@10.14.0",
66
"description": "Scoped Pinia Stores for Vue",
77
"author": {
88
"name": "Carl Olsen",

pnpm-lock.yaml

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/functions/defineNonScopeableStore.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { defineStore } from 'pinia'
2-
import { type ScopeOptionsInput } from '../scope-options'
32
import {
43
makeStoreFactory,
54
type ScopeableStoreOptions,
@@ -16,9 +15,12 @@ export function defineNonScopeableStore<Id extends string, SS, SD extends StoreD
1615
storeCreator: (context: NonScopeContext) => SS,
1716
setupOptions?: ScopeableStoreOptions<Id, SS>,
1817
): ScopeableStoreResult<S> {
19-
function makeStore(scope: string, options?: ScopeOptionsInput) {
18+
function makeStore(scope: string) {
2019
if (scope === '') {
2120
let setup = (): SS => storeCreator({ unScoped: '' })
21+
if (typeof setupOptions === 'function') {
22+
setupOptions = setupOptions(scope)
23+
}
2224
const useStore = defineStore(id, setup, setupOptions) as SD
2325
return useStore() as S
2426
}

src/functions/defineScopeableStore.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@ export type ScopedContext = {
1717
scope: string;
1818
}
1919

20-
export type ScopeableStoreOptions<Id extends string, SS> = DefineSetupStoreOptions<
20+
export type ScopeableStoreOptions<Id extends string, SS> =
21+
ScopeableStoreOptionsObject<Id, SS>
22+
| ScopeableStoreOptionsCreator<Id, SS>
23+
24+
export type ScopeableStoreOptionsObject<Id extends string, SS> = DefineSetupStoreOptions<
2125
Id,
2226
_ExtractStateFromSetupStore<SS>,
2327
_ExtractGettersFromSetupStore<SS>,
2428
_ExtractActionsFromSetupStore<SS>
2529
>
2630

31+
export interface ScopeableStoreOptionsCreator<Id extends string, SS> {
32+
(scope: string): ScopeableStoreOptionsObject<Id, SS>
33+
}
34+
2735
export type ScopeableStoreResult<S> = {
2836
(scope?: string, options?: ScopeOptionsInput): S;
2937
componentScoped(): S;
@@ -66,6 +74,10 @@ export function defineScopeableStore<Id extends string, SS, SD extends StoreDef<
6674
}
6775
}
6876
}
77+
if (typeof setupOptions === 'function') {
78+
setupOptions = setupOptions(scope)
79+
}
80+
6981
const useStore = defineStore(scopedId, setup, setupOptions) as SD
7082
const store = useStore() as S
7183

tests/unit/defineNonScopeableStore.test.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, expect, it } from 'vitest'
22
import { defineNonScopeableStore } from '../../src/functions/defineNonScopeableStore'
3-
import { createPinia, setActivePinia } from 'pinia'
3+
import { createPinia, type PiniaPluginContext, setActivePinia } from 'pinia'
44
import { attachPiniaScope } from '../../src/pinia-scope'
55
import { mount } from '@vue/test-utils'
66
import { setComponentScope } from '../../src'
@@ -103,4 +103,45 @@ describe('defineNonScopeableStore()', () => {
103103
}).toThrowError(`Attempting to use un-scopeable store (store id: "${TEST_STORE_ID}") with scope "${SCOPE_A}".`)
104104
})
105105

106+
it('handles plugin options function', async () => {
107+
let count = 0
108+
const options = {
109+
foo: {
110+
some: 'thing',
111+
},
112+
}
113+
114+
function testPiniaPlugin(context: PiniaPluginContext) {
115+
count++
116+
expect(context.options).toEqual({
117+
actions: {},
118+
scope: '',
119+
...options,
120+
})
121+
}
122+
123+
const pinia = createPinia()
124+
attachPiniaScope(pinia, {
125+
autoInjectScope: true,
126+
})
127+
pinia.use(testPiniaPlugin)
128+
setActivePinia(pinia)
129+
mount({ template: 'none' }, { global: { plugins: [pinia] } })
130+
131+
const useTestStore = defineNonScopeableStore('test', (context) => {
132+
return {
133+
a: 'b',
134+
}
135+
// @ts-expect-error
136+
}, (scope: string) => {
137+
return {
138+
scope,
139+
...options,
140+
}
141+
})
142+
143+
const store = useTestStore()
144+
expect(count).toBe(1)
145+
})
146+
106147
})

0 commit comments

Comments
 (0)