From 607806bdb8caa19bc147ad6337dcd097ca491bbb Mon Sep 17 00:00:00 2001 From: larscom Date: Sun, 24 Dec 2023 17:38:30 +0100 Subject: [PATCH] add license, workflow, basics --- .github/workflows/workflow.yml | 55 +++++++++++++++++++ .npmrc | 1 + LICENSE | 21 +++++++ README.md | 23 ++++++-- package-lock.json | 4 +- package.json | 6 +- projects/ngrx-signals-storage/package.json | 30 +++++++++- .../src/lib/with-storage.ts | 45 +++++++++++---- src/app/app.component.html | 5 +- src/app/app.component.ts | 15 ++--- src/index.html | 2 +- 11 files changed, 172 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/workflow.yml create mode 100644 .npmrc create mode 100644 LICENSE diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..fb3e56b --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,55 @@ +name: workflow + +on: + push: + tags: + - '*.*.*' + branches: + - '**' + pull_request: + branches: + - master + +jobs: + test: + runs-on: ubuntu-latest + env: + TZ: Europe/Amsterdam + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + registry-url: https://registry.npmjs.org/ + - run: | + npm ci --ignore-scripts --legacy-peer-deps + npm run test + + publish: + if: startsWith(github.ref, 'refs/tags/') + needs: [test] + runs-on: ubuntu-latest + env: + TZ: Europe/Amsterdam + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 20 + registry-url: https://registry.npmjs.org/ + env: + NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} + - run: | + npm ci --ignore-scripts --legacy-peer-deps + npm run build:lib + - run: | + cd dist/ngrx-signals-storage + + version=${{ github.ref_name }} + pkgJson="./package.json" + sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$version\"/" $pkgJson + + ls -ltra . + cat pkgJson + + npm publish diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..9555e17 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +tag-version-prefix="" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ba6b418 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Lars Kniep + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 4dcd1a8..75fa75d 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,20 @@ ![npm](https://img.shields.io/npm/dw/@larscom/ngrx-signals-storage) [![license](https://img.shields.io/npm/l/@larscom/ngrx-signals-storage.svg)](https://github.com/larscom/ngrx-signals-storage/blob/master/LICENSE) -> Simply save the signal state to localstorage/sessionstorage and restore state on page reload. +> Save signal state (@ngrx/signals) to localStorage/sessionStorage and restore the state on page load. + +## Installation + +```bash +npm install @larscom/ngrx-signals-storage +``` ## Dependencies `@larscom/ngrx-signals-storage` depends on [@ngrx/signals](https://ngrx.io/guide/signals/install) and [Angular](https://github.com/angular/angular) -## Installation - ```bash -npm install @larscom/ngrx-signals-storage + npm install @ngrx/signals ``` ## Usage @@ -21,5 +25,14 @@ npm install @larscom/ngrx-signals-storage Import `withStorage` function ```ts - +import { withStorage } from '@larscom/ngrx-signals-storage' +import { withState, signalStore } from '@ngrx/signals' + +export const CounterStore = signalStore( + withState({ + count: 0 + }), + // state will be saved to sessionStorage under the key: 'myKey' + withStorage('myKey', sessionStorage) +) ``` diff --git a/package-lock.json b/package-lock.json index 1e891a0..7319323 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ngrx-signals-storage", - "version": "0.0.0", + "version": "0.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ngrx-signals-storage", - "version": "0.0.0", + "version": "0.0.2", "dependencies": { "@angular/animations": "^17.0.0", "@angular/common": "^17.0.0", diff --git a/package.json b/package.json index e590377..4501452 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "ngrx-signals-storage", - "version": "0.0.0", + "version": "0.0.1", "scripts": { "ng": "ng", "start": "ng serve", + "test": "exit 0", "build": "ng build", - "watch": "ng build --watch --configuration development", - "test": "ng test" + "build:lib": "ng build ngrx-signals-storage && cpx README.md dist/ngrx-signals-storage" }, "private": true, "dependencies": { diff --git a/projects/ngrx-signals-storage/package.json b/projects/ngrx-signals-storage/package.json index b6c3096..9ed5ac8 100644 --- a/projects/ngrx-signals-storage/package.json +++ b/projects/ngrx-signals-storage/package.json @@ -1,10 +1,36 @@ { - "name": "ngrx-signals-storage", + "name": "@larscom/ngrx-signals-storage", "version": "0.0.0", + "description": "Save signal state (@ngrx/signals) to localstorage/sessionstorage and restore the state on page load.", + "repository": { + "type": "git", + "url": "git+https://github.com/larscom/ngrx-signals-storage.git" + }, + "publishConfig": { + "access": "public" + }, + "keywords": [ + "angular", + "ngrx", + "redux", + "store", + "state", + "signals", + "storage", + "localstorage", + "sessionstorage", + "reactive" + ], + "author": "Lars Kniep", + "license": "MIT", + "bugs": { + "url": "https://github.com/larscom/ngrx-signals-storage/issues" + }, + "homepage": "https://github.com/larscom/ngrx-signals-storage#readme", "peerDependencies": { "@angular/common": "^17.0.0", "@angular/core": "^17.0.0", - "@ngrx/signals" : "^17.0.0" + "@ngrx/signals": "^17.0.0" }, "dependencies": { "tslib": "^2.3.0" diff --git a/projects/ngrx-signals-storage/src/lib/with-storage.ts b/projects/ngrx-signals-storage/src/lib/with-storage.ts index 29dd8cf..d0b101e 100644 --- a/projects/ngrx-signals-storage/src/lib/with-storage.ts +++ b/projects/ngrx-signals-storage/src/lib/with-storage.ts @@ -3,28 +3,51 @@ import { effect } from '@angular/core' import { getState, patchState } from '@ngrx/signals' import { EmptyFeatureResult, SignalStoreFeature, SignalStoreFeatureResult } from '@ngrx/signals/src/signal-store-models' +/** + * The `withStorage` function that lets you save the state to localstorage/sessionstorage + * and rehydrate the state upon page load. + * + * @param key the key under which the state should be saved into `Storage` + * @param storage the implementation + * + * @example + * export const CounterStore = signalStore( + * withState({ + * count: 0 + * }), + * withStorage('myKey', sessionStorage) + * ) + * + * Check out github for more information. + * @see https://github.com/larscom/ngrx-signals-storage + */ export function withStorage( key: string, storage: Storage ): SignalStoreFeature { - const state = storage.getItem(key) - const fromStorage = state ? JSON.parse(state) : null + const item = storage.getItem(key) + const storageState: State['state'] | null = item ? JSON.parse(item) : null + + let hydrated = false - let patched = false return (store) => { if (Object.keys(store.slices).length === 0) { throw Error("'withStorage' must be after 'withState'") } - if (fromStorage != null && !patched) { - const state = Object.keys(store.slices).reduce((state, key) => { - return { - ...state, - [key]: fromStorage[key] - } - }, Object()) + if (storageState != null && !hydrated) { + const state = Object.keys(store.slices).reduce((state, key) => { + const value = storageState[key as keyof State['state']] + return value + ? { + ...state, + [key]: value + } + : state + }, getState(store)) + patchState(store, state) - patched = true + hydrated = true } effect(() => { diff --git a/src/app/app.component.html b/src/app/app.component.html index 4c61d36..e1548f8 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,2 +1,5 @@ -

Hello World!

+

Counter

{{ store.count() }}
+ +

Date

+
{{ store.date() }}
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index fde7ae7..23bd1ba 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -7,19 +7,16 @@ import { patchState, signalStore, withMethods, withState } from '@ngrx/signals' export const CounterStore = signalStore( withState({ - count: 10, - count2: 100, - nested: { - myval: 500 - } + count: 100, + date: new Date() }), withStorage('state', sessionStorage), withMethods(({ count, ...store }) => ({ + setDate(date: Date) { + patchState(store, { date }) + }, increment(by: number) { patchState(store, { count: count() + by }) - }, - decrement(by: number) { - patchState(store, { count: count() - by }) } })) ) @@ -37,7 +34,5 @@ export class AppComponent { constructor() { setTimeout(() => this.store.increment(100), 3000) - // setTimeout(() => this.store.increment(100), 4000) - // setTimeout(() => this.store.increment(100), 6000) } } diff --git a/src/index.html b/src/index.html index 0f6142d..8e8c314 100644 --- a/src/index.html +++ b/src/index.html @@ -2,7 +2,7 @@ - NgrxSignalsStorageApp + @larscom/ngrx-signals-storage