Skip to content

Commit ec0ce29

Browse files
committed
feat(checkpoints): add useCheckpoint composable
1 parent 3b2de42 commit ec0ce29

File tree

38 files changed

+561
-36
lines changed

38 files changed

+561
-36
lines changed

.vscode/settings.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,15 @@
55
"vue.complete.casing.tags": "pascal",
66
"typescript.preferences.importModuleSpecifier": "non-relative",
77
"typescript.tsdk": "node_modules/typescript/lib",
8-
"cSpell.words": ["composables", "Pinia", "Tinybase", "todos", "wildcarded"]
8+
"cSpell.words": [
9+
"composables",
10+
"Moraru",
11+
"Pinia",
12+
"pkgroll",
13+
"Tinybase",
14+
"todos",
15+
"vitepress",
16+
"vueuse",
17+
"wildcarded"
18+
]
919
}

packages/private/docs/.vitepress/config.mts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ export default defineConfig({
3737
{ text: 'Writable References', link: '/api/store/references' },
3838
],
3939
},
40+
{
41+
text: 'Checkpoints',
42+
items: [
43+
{ text: 'Composables', link: '/api/checkpoints/composables' },
44+
{ text: 'Context', link: '/api/checkpoints/context' },
45+
],
46+
},
4047
{
4148
text: 'Common',
4249
items: [

packages/private/docs/.vitepress/theme/components/MyLayout.vue

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,27 @@ import { useRoute } from 'vitepress'
33
import DefaultTheme from 'vitepress/theme'
44
import VPSwitchStoreStyle from './VPSwitchStoreStyle.vue'
55
import { computed } from 'vue'
6+
import { useBodyClass } from '../composables/useBodyClass.mjs'
7+
import { useLocalStorage } from '@vueuse/core'
68
79
const { Layout } = DefaultTheme
810
911
const route = useRoute()
1012
1113
const isApiPage = computed(() => route.path.startsWith('/api'))
14+
15+
const isDefaultStore = useLocalStorage('isDefaultStoreSelected', true)
16+
useBodyClass(isDefaultStore, {
17+
trueClass: 'default-store',
18+
falseClass: 'custom-store',
19+
})
1220
</script>
1321

1422
<template>
1523
<Layout>
1624
<template #sidebar-nav-before>
1725
<ClientOnly v-if="isApiPage">
18-
<VPSwitchStoreStyle />
26+
<VPSwitchStoreStyle v-model="isDefaultStore" />
1927
</ClientOnly>
2028
</template>
2129
</Layout>

packages/private/docs/.vitepress/theme/components/VPSwitchStoreStyle.vue

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
11
<script lang="ts" setup>
22
// copy/pasted from https://github.com/vuejs/vitepress/blob/8fef47848bd3418014b06eea1337b1e66e0473c6/src/client/theme-default/components/VPSwitchAppearance.vue
33
// minor modifications
4-
import { watch, ref } from 'vue'
54
import VPSwitch from './VPSwitch.vue'
65
7-
const isDefaultStoreSelected = ref(localStorage.getItem('isDefaultStoreSelected') !== 'false')
8-
9-
watch(
10-
isDefaultStoreSelected,
11-
() => {
12-
localStorage.setItem('isDefaultStoreSelected', isDefaultStoreSelected.value.toString())
13-
if (isDefaultStoreSelected.value) {
14-
document.body.classList.add('default-store')
15-
document.body.classList.remove('custom-store')
16-
} else {
17-
document.body.classList.remove('default-store')
18-
document.body.classList.add('custom-store')
19-
}
20-
},
21-
{ immediate: true },
22-
)
6+
const isDefaultStoreSelected = defineModel({
7+
type: Boolean,
8+
required: true,
9+
})
2310
</script>
2411

2512
<template>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { MaybeRefOrGetter, toRef, watch } from 'vue'
2+
3+
interface UseBodyClassOptions {
4+
trueClass: string
5+
falseClass: string
6+
}
7+
8+
export function useBodyClass(value: MaybeRefOrGetter<boolean>, options: UseBodyClassOptions): void {
9+
const { trueClass } = options
10+
const { falseClass } = options
11+
12+
const updateBodyClass = (newValue: boolean) => {
13+
document.body.classList.remove(newValue ? falseClass : trueClass)
14+
document.body.classList.add(newValue ? trueClass : falseClass)
15+
}
16+
17+
watch(toRef(value), updateBodyClass, { immediate: true })
18+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Composables {#composables}
2+
3+
Checkpoinnts composables.
4+
5+
## useCheckpoint {#use-checkpoint}
6+
7+
The `useCheckpoint` composable returns the label for a checkpoint, and registers a listener so that any changes to that result will cause a re-render.
8+
9+
When first accessed, this composable will create a listener so that changes to the label will cause a re-render. When the component containing this composable is unmounted, the listener will be automatically removed.
10+
11+
### Parameters
12+
13+
<div class="hide-default-store">
14+
15+
- `checkpoints` ([`Checkpoints`](https://tinybase.org/api/checkpoints/interfaces/checkpoints/checkpoints/)): The [`Checkpoints`](https://tinybase.org/api/checkpoints/interfaces/checkpoints/checkpoints/) object to be accessed.
16+
17+
</div>
18+
19+
- `checkpointId` ([`MaybeRefOrGetter`](https://vuejs.org/api/utility-types.html#maybereforgetter)`<string>`): The [Id](https://tinybase.org/api/common/type-aliases/identity/id/) of the checkpoint.
20+
21+
### Returns
22+
23+
- `ComputedRef<string | undefined>`: A **readonly** reference to the string label for the requested checkpoint, an empty string if it was never set, or `undefined` if the checkpoint does not exist..
24+
25+
### Example
26+
27+
<div class="hide-default-store">
28+
29+
```vue
30+
<script setup lang="ts">
31+
import { useCell, injectStore, useCheckpoint } from 'vue-tinybase/custom-store'
32+
33+
import { Store1Key, Checkpoints1Key } from './store'
34+
35+
const store = injectStore(Store1Key)
36+
const checkpoints = injectCheckpoints(Checkpoints1Key)
37+
38+
const checkpointLabel = useCheckpoint(checkpoints, '1')
39+
// UI will be empty
40+
41+
store.setCell('pets', 'fido', 'sold', true)
42+
checkpoints.addCheckpoint('sale')
43+
// UI will show: 'sale'
44+
</script>
45+
46+
<template>
47+
<div>{{ checkpointLabel }}</div>
48+
</template>
49+
```
50+
51+
</div>
52+
53+
<div class="hide-custom-store">
54+
55+
```vue
56+
<script setup lang="ts">
57+
import { useCell, injectStore, useCheckpoint, injectCheckpoints } from 'vue-tinybase'
58+
59+
const store = injectStore()
60+
61+
const checkpoints = injectCheckpoints()
62+
63+
const checkpointLabel = useCheckpoint('1')
64+
// UI will be empty
65+
66+
store.setCell('pets', 'fido', 'sold', true)
67+
checkpoints.addCheckpoint('sale')
68+
// UI will show: 'sale'
69+
</script>
70+
71+
<template>
72+
<div>{{ checkpointLabel }}</div>
73+
</template>
74+
```
75+
76+
</div>
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Context {#context}
2+
3+
Context-related functions for providing and injecting checkpoints object into the app or part of the app.
4+
5+
For all the examples assume the following `store.ts` file:
6+
7+
<div class="hide-custom-store">
8+
9+
```ts
10+
import { createStore, createCheckpoints } from 'tinybase'
11+
12+
export const store = createStore()
13+
export const checkpoints = createCheckpoints(store)
14+
```
15+
16+
</div>
17+
18+
<div class="hide-default-store">
19+
20+
```ts
21+
import { createStore, createCheckpoints } from 'tinybase'
22+
import type { InjectionKey } from 'vue'
23+
24+
export const store1 = createStore()
25+
export const store2 = createStore()
26+
27+
export const checkpoints1 = createCheckpoints(store1)
28+
export const checkpoints2 = createCheckpoints(store2)
29+
30+
export const Store1Key = Symbol('Store1') as InjectionKey<typeof store1>
31+
export const Store2Key = Symbol('Store2') as InjectionKey<typeof store2>
32+
33+
export const Checkpoints1Key = Symbol('Checkpoints1') as InjectionKey<typeof checkpoints1>
34+
export const Checkpoints2Key = Symbol('Checkpoints2') as InjectionKey<typeof checkpoints2>
35+
```
36+
37+
</div>
38+
39+
## provideCheckpoints {#provide-checkpoints}
40+
41+
Provide a checkpoints object to all child components, enabling them to access the checkpoints object without having to pass it down as a prop.
42+
43+
- **Parameters**
44+
45+
<div class="hide-default-store">
46+
47+
- `checkpointsKey` (`string | symbol`): Unique injection key.
48+
49+
</div>
50+
51+
- `checkpoints` ([`Checkpoints`](https://tinybase.org/api/checkpoints/interfaces/checkpoints/checkpoints/)): The checkpoints object to provide.
52+
53+
- **Example**
54+
55+
<div class="hide-custom-store">
56+
57+
```vue
58+
<script setup lang="ts">
59+
import { provideCheckpoints } from 'vue-tinybase'
60+
61+
import { checkpoints } from './store'
62+
63+
provideCheckpoints(checkpoints)
64+
</script>
65+
```
66+
67+
</div>
68+
69+
<div class="hide-default-store">
70+
71+
```vue
72+
<script setup lang="ts">
73+
import { provideCheckpoints } from 'vue-tinybase/custom-store'
74+
75+
import { checkpoints1, checkpoints2, Checkpoints1Key, Checkpoints2Key } from './store'
76+
77+
provideCheckpoints(Checkpoints1Key, checkpoints1)
78+
provideCheckpoints(Checkpoints2Key, checkpoints2)
79+
</script>
80+
```
81+
82+
</div>
83+
84+
## injectCheckpoints {#inject-checkpoints}
85+
86+
Inject a checkpoints object provided by [`provideCheckpoints`](/api/checkpoints/context#provide-checkpoints).
87+
88+
<div class="hide-default-store">
89+
90+
- **Parameters**
91+
92+
- `checkpointsKey` (`string | symbol`): Checkpoints object injection key.
93+
94+
</div>
95+
96+
- **Example**
97+
98+
<div class="hide-custom-store">
99+
100+
```vue
101+
<script setup lang="ts">
102+
import { injectCheckpoints } from 'vue-tinybase'
103+
104+
const store = injectCheckpoints()
105+
</script>
106+
```
107+
108+
</div>
109+
110+
<div class="hide-default-store">
111+
112+
```vue
113+
<script setup lang="ts">
114+
import { injectCheckpoints } from 'vue-tinybase/custom-store'
115+
116+
import { Checkpoints1Key } from './store'
117+
118+
const checkpoints1 = injectCheckpoints(Checkpoints1Key)
119+
</script>
120+
```
121+
122+
</div>

packages/private/docs/guide/getting-started/connect-to-vuejs-app.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,5 @@ app.mount('#app')
4040
In this example, we create a Vue app and use the provideStore function in the setup function to provide the TinyBase store. The render function is used to render the main App component.
4141

4242
After providing the store, you can use `vue-tinybase` [event hooks](/api/store/events), [composables](/api/store/composables), and [writable references](/api/store/references) inside all components of your app. This integration enables you to interact with the store’s state and respond to changes efficiently.
43+
44+
There are similar provide-related functions for [checkpoints](/api/checkpoints/context) that you can use to provide these objects to your app or part of the app.

packages/private/docs/guide/usage-with-typescript.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ For more information on Schema-based typing, please refer to the [official TinyB
99
The following code snippet demonstrates how to define a schema for your store and connect it to all composables imported from `vue-tinybase`:
1010

1111
```typescript
12-
import { createStore } from 'tinybase/with-schemas'
12+
import { createStore, createCheckpoints } from 'tinybase/with-schemas'
1313

1414
// Create a store with schema-based typing
1515
export const store = createStore()
@@ -27,13 +27,18 @@ export const store = createStore()
2727
val3: { type: 'boolean', default: false },
2828
})
2929

30+
// If you want - also create checkpoints
31+
const checkpoints = createCheckpoints(store)
32+
3033
// Export the store type
3134
export type Store = typeof store
35+
export type Checkpoints = typeof checkpoints
3236

3337
// Extend the Vue-Tinybase context with the store type
3438
declare module 'vue-tinybase' {
3539
export interface VueTinybaseContext {
3640
store: Store
41+
checkpoints: Checkpoints
3742
}
3843
}
3944
```

packages/private/docs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"vitepress": "^1.2.3"
1717
},
1818
"dependencies": {
19+
"@vueuse/core": "^10.11.0",
1920
"vue": "^3.4.31"
2021
}
2122
}

0 commit comments

Comments
 (0)