@plasius/react-state 1.0.3 → 1.0.5

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.
@@ -2,8 +2,6 @@ name: CD (Publish to npm)
2
2
 
3
3
  on:
4
4
  workflow_dispatch:
5
- release:
6
- types: [published]
7
5
 
8
6
  permissions:
9
7
  contents: write
@@ -40,6 +38,9 @@ jobs:
40
38
  NEW_VER=$(npm version patch -m "chore: release v%s [skip ci]")
41
39
  echo "New version: $NEW_VER"
42
40
  git push --follow-tags
41
+ VER_NO_V=${NEW_VER#v}
42
+ echo "tag=$NEW_VER" >> "$GITHUB_OUTPUT"
43
+ echo "version=$VER_NO_V" >> "$GITHUB_OUTPUT"
43
44
 
44
45
  NAME=$(node -p "require('./package.json').name")
45
46
  echo "name=$NAME" >> "$GITHUB_OUTPUT"
@@ -49,6 +50,21 @@ jobs:
49
50
  echo "flags=--access public" >> "$GITHUB_OUTPUT"
50
51
  fi
51
52
 
53
+ - name: Create GitHub Release from tag (first-party)
54
+ env:
55
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56
+ run: |
57
+ set -euo pipefail
58
+ TAG="${{ steps.pkg.outputs.tag }}"
59
+ if gh release view "$TAG" >/dev/null 2>&1; then
60
+ echo "Release $TAG already exists; skipping creation."
61
+ else
62
+ gh release create "$TAG" \
63
+ --title "Release $TAG" \
64
+ --generate-notes \
65
+ --latest
66
+ fi
67
+
52
68
  - name: Publish
53
69
  env:
54
70
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/CHANGELOG.md ADDED
@@ -0,0 +1,60 @@
1
+
2
+ # Changelog
3
+
4
+ All notable changes to this project will be documented in this file.
5
+
6
+ The format is based on **[Keep a Changelog](https://keepachangelog.com/en/1.1.0/)**, and this project adheres to **[Semantic Versioning](https://semver.org/spec/v2.0.0.html)**.
7
+
8
+ ---
9
+
10
+ ## [Unreleased]
11
+
12
+ - **Added**
13
+ - (placeholder) Add new hooks, scoped store features, or context helpers here.
14
+
15
+ - **Changed**
16
+ - (placeholder)
17
+
18
+ - **Fixed**
19
+ - (placeholder)
20
+
21
+ - **Security**
22
+ - (placeholder)
23
+
24
+ ---
25
+
26
+ ## [1.0.0] - 2025-09-16
27
+
28
+ - **Added**
29
+
30
+ - Initial public release of `@plasius/react-state`.
31
+ - `createStore` for basic state container functionality with `dispatch`, `getState`, and subscription API.
32
+ - `createScopedStoreContext` for React integration:
33
+ - `<Provider>` component wrapping React trees,
34
+ - `useStore()` to access state,
35
+ - `useDispatch()` to dispatch actions.
36
+ - Support for per-key subscriptions and selector-based subscriptions.
37
+ - Unit tests with Vitest and component tests with React Testing Library.
38
+
39
+ - **Changed**
40
+ - N/A (initial release)
41
+
42
+ - **Fixed**
43
+ - N/A (initial release)
44
+
45
+ ---
46
+
47
+ ## Release process (maintainers)
48
+
49
+ 1. Update `CHANGELOG.md` under **Unreleased** with user‑visible changes.
50
+ 2. Bump version in `package.json` following SemVer (major/minor/patch).
51
+ 3. Move entries from **Unreleased** to a new version section with the current date.
52
+ 4. Tag the release in Git (`vX.Y.Z`) and push tags.
53
+ 5. Publish to npm (via CI/CD or `npm publish`).
54
+
55
+ > Tip: Use Conventional Commits in PR titles/bodies to make changelog updates easier.
56
+
57
+ ---
58
+
59
+ [Unreleased]: https://github.com/Plasius-LTD/react-state/compare/v1.0.0...HEAD
60
+ [1.0.0]: https://github.com/Plasius-LTD/react-state/releases/tag/v1.0.0
package/README.md CHANGED
@@ -7,19 +7,29 @@
7
7
  [![Security Policy](https://img.shields.io/badge/security%20policy-yes-orange.svg)](./SECURITY.md)
8
8
  [![Changelog](https://img.shields.io/badge/changelog-md-blue.svg)](./CHANGELOG.md)
9
9
 
10
+ ---
11
+
10
12
  ## Overview
11
13
 
12
14
  `@plasius/react-state` provides a scoped state management solution for React applications. It allows developers to create isolated, testable, and composable stores without introducing heavy dependencies.
13
15
 
16
+ ---
17
+
14
18
  ## Installation
15
19
 
16
20
  ```bash
17
21
  npm install @plasius/react-state
18
22
  ```
19
23
 
24
+ ---
25
+
20
26
  ## Usage Example
21
27
 
28
+ ### Accessing the store
29
+
22
30
  ```tsx
31
+ import { createStore } from '@plasius/react-state'
32
+
23
33
  type Action =
24
34
  | { type: "INCREMENT_VALUE"; payload: number }
25
35
  | { type: "SET_VALUE"; payload: number }
@@ -54,9 +64,81 @@ function doSomething() {
54
64
  }
55
65
  ```
56
66
 
67
+ ### Scoped react hooks
68
+
69
+ ```tsx
70
+ import { createScopedStore } from '@plasius/react-state'
71
+
72
+ type Action =
73
+ | { type: "INCREMENT_VALUE"; payload: number }
74
+ | { type: "SET_VALUE"; payload: number }
75
+ | { type: "DECREMENT_VALUE"; payload: number };
76
+
77
+ interface State {
78
+ value: number;
79
+ }
80
+
81
+ const initialState: State = { value: 0 };
82
+
83
+ function reducer(state: State, action: Action): State {
84
+ switch (action.type) {
85
+ case "INCREMENT_VALUE":
86
+ return { ...state, value: state.value + action.payload };
87
+ case "DECREMENT_VALUE":
88
+ return { ...state, value: state.value - action.payload };
89
+ case "SET_VALUE":
90
+ // Distinct-until-changed: return the SAME reference if no change,
91
+ // so listeners relying on referential equality will not fire.
92
+ if (action.payload === state.value) return state;
93
+ return { ...state, value: action.payload };
94
+ default:
95
+ return state;
96
+ }
97
+ }
98
+
99
+ const store = createStore<State, Action>(reducer, initialState);
100
+
101
+ const Counter = () => {
102
+ const state = store.useStore();
103
+ const dispatch = store.useDispatch();
104
+
105
+ return (
106
+ <div>
107
+ <button id="counter-inc" onClick={() => dispatch({ type: "inc" })}>
108
+ +
109
+ </button>
110
+ <button id="counter-dec" onClick={() => dispatch({ type: "dec" })}>
111
+ -
112
+ </button>
113
+ <input
114
+ aria-label="Counter value"
115
+ title=""
116
+ id="counter-set"
117
+ type="number"
118
+ value={state.count}
119
+ onChange={(e) =>
120
+ dispatch({ type: "set", payload: Number(e.target.value) })
121
+ }
122
+ />
123
+ </div>
124
+ );
125
+ };
126
+
127
+ function App() {
128
+ return (<><store.Provider><Counter /></store.Provider></>);
129
+ }
130
+ ```
131
+
132
+ ---
133
+
57
134
  ## Contributing
58
135
 
59
- Contributions are welcome! Please read our [Code of Conduct](./CODE_OF_CONDUCT.md) and [Contributing Guide](./CONTRIBUTING.md) before submitting PRs.
136
+ We welcome contributions! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
137
+
138
+ - [Code of Conduct](./CODE_OF_CONDUCT.md)
139
+ - [Contributor License Agreement](./legal/CLA.md)
140
+
141
+ ---
60
142
 
61
143
  ## License
62
144
 
@@ -0,0 +1,42 @@
1
+ # ADR-0001: React State Store Purpose and Scope
2
+
3
+ ## Status
4
+
5
+ - Proposed → Accepted
6
+ - Date: 2025-09-12
7
+ - Version: 1.0
8
+ - Supersedes: N/A
9
+ - Superseded by: N/A
10
+
11
+ ## Context
12
+
13
+ Managing React application state across multiple components is a common challenge. Existing solutions (Redux, Zustand, Jotai, etc.) offer different trade-offs in complexity, ergonomics, and bundle size. For the Plasius ecosystem, we want:
14
+
15
+ - A minimal, type-safe state container,
16
+ - Strong integration with React via Context and Hooks,
17
+ - Support for both global and scoped stores,
18
+ - Predictable subscription and unsubscribe behaviour,
19
+ - Alignment with SOLID principles and enterprise-grade maintainability.
20
+
21
+ ## Decision
22
+
23
+ We will build a dedicated library, `@plasius/react-state`, that:
24
+
25
+ - Provides a `createStore` primitive for basic state containers,
26
+ - Provides `createScopedStoreContext` to integrate with React Context/Provider patterns,
27
+ - Exposes hooks (`useStore`, `useDispatch`) to read state and dispatch actions,
28
+ - Supports subscriptions: global, per-key, and selector-based,
29
+ - Ensures distinct-until-changed semantics to avoid unnecessary re-renders,
30
+ - Is published as an open source package under the Plasius-LTD organisation.
31
+
32
+ ## Consequences
33
+
34
+ - **Positive:** Consistent and predictable state handling across Plasius projects, type-safe APIs, lighter alternative to Redux, improved testability, open source adoption possible.
35
+ - **Negative:** Adds maintenance burden to keep feature parity with evolving React ecosystem; community may default to established libraries.
36
+ - **Neutral:** Internal consumers may still choose other state management libs if required, but Plasius packages will standardise on this one.
37
+
38
+ ## Alternatives Considered
39
+
40
+ - **Use Redux or Redux Toolkit:** Very mature, but verbose and heavier than desired.
41
+ - **Use Zustand or Jotai:** Good ergonomics, but external dependency risk and less control over PII handling and subscription semantics.
42
+ - **React Context alone:** Too minimal, lacking structured dispatch and subscribe/unsubscribe APIs.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasius/react-state",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Tiny, testable, typesafe React Scoped Store helper.",
5
5
  "keywords": [
6
6
  "react",