@plasius/react-state 1.0.4 → 1.0.6

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 CHANGED
@@ -1,5 +1,4 @@
1
1
 
2
-
3
2
  # Changelog
4
3
 
5
4
  All notable changes to this project will be documented in this file.
@@ -9,41 +8,44 @@ The format is based on **[Keep a Changelog](https://keepachangelog.com/en/1.1.0/
9
8
  ---
10
9
 
11
10
  ## [Unreleased]
12
- ### Added
13
- - (placeholder) Add new hooks, scoped store features, or context helpers here.
14
11
 
15
- ### Changed
16
- - (placeholder)
12
+ - **Added**
13
+ - (placeholder) Add new hooks, scoped store features, or context helpers here.
14
+
15
+ - **Changed**
16
+ - (placeholder)
17
17
 
18
- ### Fixed
19
- - (placeholder)
18
+ - **Fixed**
19
+ - (placeholder)
20
20
 
21
- ### Security
22
- - (placeholder)
21
+ - **Security**
22
+ - (placeholder)
23
23
 
24
24
  ---
25
25
 
26
- ## [0.1.0] - 2025-09-16
27
- ### Added
28
- - Initial public release of `@plasius/react-state`.
29
- - `createStore` for basic state container functionality with `dispatch`, `getState`, and subscription API.
30
- - `createScopedStoreContext` for React integration:
31
- - `<Provider>` component wrapping React trees,
32
- - `useStore()` to access state,
33
- - `useDispatch()` to dispatch actions.
34
- - Support for per-key subscriptions and selector-based subscriptions.
35
- - Unit tests with Vitest and component tests with React Testing Library.
36
- - Early Playwright integration tests for end-to-end validation of store-driven DOM.
26
+ ## [1.0.0] - 2025-09-16
27
+
28
+ - **Added**
37
29
 
38
- ### Changed
39
- - N/A (initial release)
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.
40
38
 
41
- ### Fixed
42
- - N/A (initial release)
39
+ - **Changed**
40
+ - N/A (initial release)
41
+
42
+ - **Fixed**
43
+ - N/A (initial release)
43
44
 
44
45
  ---
45
46
 
46
47
  ## Release process (maintainers)
48
+
47
49
  1. Update `CHANGELOG.md` under **Unreleased** with user‑visible changes.
48
50
  2. Bump version in `package.json` following SemVer (major/minor/patch).
49
51
  3. Move entries from **Unreleased** to a new version section with the current date.
@@ -54,5 +56,5 @@ The format is based on **[Keep a Changelog](https://keepachangelog.com/en/1.1.0/
54
56
 
55
57
  ---
56
58
 
57
- [Unreleased]: https://github.com/Plasius-LTD/react-state/compare/v0.1.0...HEAD
58
- [0.1.0]: https://github.com/Plasius-LTD/react-state/releases/tag/v0.1.0
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
@@ -25,7 +25,11 @@ npm install @plasius/react-state
25
25
 
26
26
  ## Usage Example
27
27
 
28
+ ### Accessing the store
29
+
28
30
  ```tsx
31
+ import { createStore } from '@plasius/react-state'
32
+
29
33
  type Action =
30
34
  | { type: "INCREMENT_VALUE"; payload: number }
31
35
  | { type: "SET_VALUE"; payload: number }
@@ -60,6 +64,71 @@ function doSomething() {
60
64
  }
61
65
  ```
62
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
+
63
132
  ---
64
133
 
65
134
  ## Contributing
@@ -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.4",
3
+ "version": "1.0.6",
4
4
  "description": "Tiny, testable, typesafe React Scoped Store helper.",
5
5
  "keywords": [
6
6
  "react",
@@ -46,13 +46,9 @@
46
46
  "test:watch": "vitest",
47
47
  "lint": "eslint .",
48
48
  "prepare": "npm run build",
49
- "clean": "rimraf dist",
50
- "test:e2e": "playwright test",
51
- "test:e2e:headed": "playwright test --headed",
52
- "e2e:report": "playwright show-report"
49
+ "clean": "rimraf dist"
53
50
  },
54
51
  "devDependencies": {
55
- "@playwright/test": "^1.55.0",
56
52
  "@testing-library/jest-dom": "^6.8.0",
57
53
  "@testing-library/react": "^16.3.0",
58
54
  "@types/node": "^24.3.1",