Skip to content

ljlm0402/zenon

Repository files navigation


Project Logo

zenon

πŸ¦‰ A minimalist, Zustand-inspired state manager for Vue 3

npm Info

npm Version npm Release Version npm Downloads npm Package License

github Stars github Forks github Contributors github Issues


✨ Features

  • πŸƒ Vue 3 Composition API only
  • ⚑️ Almost identical DX to Zustand: supports set/get/selector, middleware composition
  • πŸ§‘β€πŸ’» TypeScript friendly: easy type inference, separation, and actions
  • πŸš€ Lightweight & simple: true 1-file store, ZERO learning curve
  • 🧩 Selector-based partial subscription supported for optimal component performance
  • 🧩 Pluggable middleware support (Logger, Persist, ... with compose or chain)
  • πŸ—‚ Full npm-style import/usage (import ... from "zenon", "zenon/plugins", etc.)

πŸ’Ύ Installation

pnpm add zenon
# or
npm install zenon
# or
yarn add zenon

πŸ“ Usage Example

// stores/counter.ts
import { createStore, compose } from "zenon";
import { withLogger, withPersist } from "zenon/plugins";

type CounterState = { count: number };
type CounterActions = {
  increase: () => void;
  reset: () => void;
};

const STORE_KEY = "zenon-counter";

// Compose DX
export const useCounter = () =>
  createStore(
    compose(
      withLogger({ store: "counter", timestamp: true, expanded: true }),
      withPersist<CounterState & CounterActions>(STORE_KEY, {
        storage: window.sessionStorage,
      })
    )((set, get) => ({
      count: 0,
      increase: () => set({ count: get().count + 1 }, "increase"),
      reset: () => set({ count: 0 }, "reset"),
    }))
  );

🎯 Comoponents Usage

<template>
  <div>
    <h2>Zenon Counter</h2>
    <p>Count: {{ count }}</p>
    <button @click="increase">+1</button>
    <button @click="reset">Reset</button>
  </div>
</template>

<script setup lang="ts">
import { useCounter } from "@/stores/counter";
const store = useCounter();
const count = store.useSelector((s) => s.count);
const { increase, reset } = store;
</script>

🧩 Middleware (Logger, Persist)

  • Compose or chain multiple plugins

  • Plugin entry: zenon/plugins

import { createStore, compose } from "zenon";
import { withLogger, withPersist } from "zenon/plugins";

// Compose style
export const useCounter = () =>
  createStore(
    compose(
      withLogger({ store: "counter" }),
      withPersist("counter")
    )((set, get) => ({
      count: 0,
      increase: () => set({ count: get().count + 1 }, "increase"),
      reset: () => set({ count: 0 }, "reset"),
    }))
  );

// Or chain style
export const useCounter = () =>
  createStore(
    withLogger({ store: "counter" })(
      withPersist("counter")((set, get) => ({
        count: 0,
        increase: () => set({ count: get().count + 1 }, "increase"),
        reset: () => set({ count: 0 }, "reset"),
      }))
    )
  );

🚦 Partial Subscription with Selector

const store = useCounter();
const count = store.useSelector((s) => s.count); // Subscribe only to count
const double = store.useSelector((s) => s.count * 2); // Derived value is also OK

πŸ“š License

MIT

⭐️ Star & Contribute

Ideas, PRs, and feedback are all welcome!

About

πŸ¦‰ A minimal, reactive state manager for Vue 3, inspired by Zustand

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published