feat(store): add shared Zustand store package with counter example
- Create packages/store with @multica/store package - Add zustand to pnpm catalog for version consistency - Add counter store as cross-platform state example - Integrate counter into ComponentExample for verification - Add tsconfig path mappings for web and desktop - Add @multica/store to Next.js transpilePackages - Add @multica/store dependency to packages/ui Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
eb5c388a80
commit
d7d2861a79
11 changed files with 133 additions and 3 deletions
|
|
@ -16,7 +16,8 @@
|
|||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@multica/ui/*": ["../../packages/ui/src/*"]
|
||||
"@multica/ui/*": ["../../packages/ui/src/*"],
|
||||
"@multica/store/*": ["../../packages/store/src/*"]
|
||||
},
|
||||
|
||||
/* Linting */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
transpilePackages: ["@multica/ui"],
|
||||
transpilePackages: ["@multica/ui", "@multica/store"],
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@
|
|||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"@multica/ui/*": ["../../packages/ui/src/*"]
|
||||
"@multica/ui/*": ["../../packages/ui/src/*"],
|
||||
"@multica/store/*": ["../../packages/store/src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
|
|
|
|||
15
packages/store/package.json
Normal file
15
packages/store/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@multica/store",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./*": "./src/*.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"zustand": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "catalog:"
|
||||
}
|
||||
}
|
||||
15
packages/store/src/counter.ts
Normal file
15
packages/store/src/counter.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { create } from 'zustand'
|
||||
|
||||
interface CounterState {
|
||||
count: number
|
||||
increment: () => void
|
||||
decrement: () => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
export const useCounterStore = create<CounterState>((set) => ({
|
||||
count: 0,
|
||||
increment: () => set((state) => ({ count: state.count + 1 })),
|
||||
decrement: () => set((state) => ({ count: state.count - 1 })),
|
||||
reset: () => set({ count: 0 }),
|
||||
}))
|
||||
1
packages/store/src/index.ts
Normal file
1
packages/store/src/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { useCounterStore } from './counter'
|
||||
19
packages/store/tsconfig.json
Normal file
19
packages/store/tsconfig.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@multica/store/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
"./hooks/*": "./src/hooks/*.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@multica/store": "workspace:*",
|
||||
"@base-ui/react": "^1.1.0",
|
||||
"@hugeicons/core-free-icons": "^3.1.1",
|
||||
"@hugeicons/react": "^1.1.4",
|
||||
|
|
|
|||
|
|
@ -65,16 +65,52 @@ import {
|
|||
import { Textarea } from "@multica/ui/components/ui/textarea"
|
||||
import { HugeiconsIcon } from "@hugeicons/react"
|
||||
import { PlusSignIcon, BluetoothIcon, MoreVerticalCircle01Icon, FileIcon, FolderIcon, FolderOpenIcon, CodeIcon, MoreHorizontalCircle01Icon, SearchIcon, FloppyDiskIcon, DownloadIcon, EyeIcon, LayoutIcon, PaintBoardIcon, SunIcon, MoonIcon, ComputerIcon, UserIcon, CreditCardIcon, SettingsIcon, KeyboardIcon, LanguageCircleIcon, NotificationIcon, MailIcon, ShieldIcon, HelpCircleIcon, File01Icon, LogoutIcon } from "@hugeicons/core-free-icons"
|
||||
import { useCounterStore } from "@multica/store/counter"
|
||||
|
||||
export function ComponentExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CounterExample />
|
||||
<CardExample />
|
||||
<FormExample />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CounterExample() {
|
||||
const { count, increment, decrement, reset } = useCounterStore()
|
||||
|
||||
return (
|
||||
<Example title="Counter (Zustand Store)">
|
||||
<Card className="w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Shared Counter</CardTitle>
|
||||
<CardDescription>
|
||||
This counter uses Zustand from @multica/store, shared across web and desktop.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center justify-center gap-4">
|
||||
<Button variant="outline" size="icon" onClick={decrement}>
|
||||
-
|
||||
</Button>
|
||||
<span className="text-4xl font-bold tabular-nums">{count}</span>
|
||||
<Button variant="outline" size="icon" onClick={increment}>
|
||||
+
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="justify-between">
|
||||
<Button variant="ghost" onClick={reset}>
|
||||
Reset
|
||||
</Button>
|
||||
<Badge variant="secondary">Count: {count}</Badge>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardExample() {
|
||||
return (
|
||||
<Example title="Card" className="items-center justify-center">
|
||||
|
|
|
|||
40
pnpm-lock.yaml
generated
40
pnpm-lock.yaml
generated
|
|
@ -24,6 +24,9 @@ catalogs:
|
|||
typescript:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
zustand:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.10
|
||||
|
||||
importers:
|
||||
|
||||
|
|
@ -241,6 +244,16 @@ importers:
|
|||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
|
||||
packages/store:
|
||||
dependencies:
|
||||
zustand:
|
||||
specifier: 'catalog:'
|
||||
version: 5.0.10(@types/react@19.2.10)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3))
|
||||
devDependencies:
|
||||
typescript:
|
||||
specifier: 'catalog:'
|
||||
version: 5.9.3
|
||||
|
||||
packages/ui:
|
||||
dependencies:
|
||||
'@base-ui/react':
|
||||
|
|
@ -252,6 +265,9 @@ importers:
|
|||
'@hugeicons/react':
|
||||
specifier: ^1.1.4
|
||||
version: 1.1.4(react@19.2.3)
|
||||
'@multica/store':
|
||||
specifier: workspace:*
|
||||
version: link:../store
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1
|
||||
|
|
@ -5712,6 +5728,24 @@ packages:
|
|||
zod@4.3.6:
|
||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||
|
||||
zustand@5.0.10:
|
||||
resolution: {integrity: sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
peerDependencies:
|
||||
'@types/react': '>=18.0.0'
|
||||
immer: '>=9.0.6'
|
||||
react: '>=18.0.0'
|
||||
use-sync-external-store: '>=1.2.0'
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
immer:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
use-sync-external-store:
|
||||
optional: true
|
||||
|
||||
snapshots:
|
||||
|
||||
7zip-bin@5.2.0: {}
|
||||
|
|
@ -12059,3 +12093,9 @@ snapshots:
|
|||
zod@3.25.76: {}
|
||||
|
||||
zod@4.3.6: {}
|
||||
|
||||
zustand@5.0.10(@types/react@19.2.10)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)):
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.10
|
||||
react: 19.2.3
|
||||
use-sync-external-store: 1.6.0(react@19.2.3)
|
||||
|
|
|
|||
|
|
@ -9,3 +9,4 @@ catalog:
|
|||
"@types/react-dom": "^19"
|
||||
"@types/node": "^25.0.10"
|
||||
typescript: "^5.9.3"
|
||||
zustand: "^5.0.0"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue