@telperion/ng-pack 0.1.3
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.
- package/README.md +95 -0
- package/fesm2022/telperion-ng-pack-storage-signals.mjs +66 -0
- package/fesm2022/telperion-ng-pack-storage-signals.mjs.map +1 -0
- package/fesm2022/telperion-ng-pack-utils.mjs +69 -0
- package/fesm2022/telperion-ng-pack-utils.mjs.map +1 -0
- package/fesm2022/telperion-ng-pack.mjs +19 -0
- package/fesm2022/telperion-ng-pack.mjs.map +1 -0
- package/package.json +50 -0
- package/storage-signals/README.md +335 -0
- package/types/telperion-ng-pack-storage-signals.d.ts +13 -0
- package/types/telperion-ng-pack-utils.d.ts +53 -0
- package/types/telperion-ng-pack.d.ts +8 -0
- package/utils/README.md +3 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# @telperion/ng-pack
|
|
2
|
+
|
|
3
|
+
A collection of Angular utilities and libraries
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @telperion/ng-pack
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Available Modules
|
|
12
|
+
|
|
13
|
+
### Storage Signals
|
|
14
|
+
|
|
15
|
+
**Import:** `@telperion/ng-pack/storage-signals`
|
|
16
|
+
|
|
17
|
+
Angular signals-based wrapper for browser's localStorage and sessionStorage with reactive updates.
|
|
18
|
+
|
|
19
|
+
#### Key Features
|
|
20
|
+
|
|
21
|
+
- 🚀 Signal-based API integrated with Angular's signal system
|
|
22
|
+
- 🔄 Reactive updates automatically synced across components
|
|
23
|
+
- 🎯 Nested property access using dot notation
|
|
24
|
+
- 🏪 Support for both localStorage and sessionStorage
|
|
25
|
+
- 🔑 Namespaced storage organization
|
|
26
|
+
|
|
27
|
+
#### Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { ApplicationConfig } from '@angular/core';
|
|
31
|
+
import { provideLocalStorage } from '@telperion/ng-pack/storage-signals';
|
|
32
|
+
|
|
33
|
+
export const appConfig: ApplicationConfig = {
|
|
34
|
+
providers: [
|
|
35
|
+
provideLocalStorage('my-app'),
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { Component } from '@angular/core';
|
|
42
|
+
import { localStorageSignal } from '@telperion/ng-pack/storage-signals';
|
|
43
|
+
|
|
44
|
+
@Component({
|
|
45
|
+
selector: 'app-settings',
|
|
46
|
+
template: `
|
|
47
|
+
<div>
|
|
48
|
+
<p>Theme: {{ theme() }}</p>
|
|
49
|
+
<button (click)="theme.set('dark')">Dark Mode</button>
|
|
50
|
+
</div>
|
|
51
|
+
`
|
|
52
|
+
})
|
|
53
|
+
export class SettingsComponent {
|
|
54
|
+
// Access nested properties with dot notation
|
|
55
|
+
theme = localStorageSignal<string>('settings', 'ui.theme');
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
[Full documentation →](./storage-signals/README.md)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### Template Signal Forms
|
|
64
|
+
|
|
65
|
+
**Import:** `@telperion/ng-pack/template-signal-forms`
|
|
66
|
+
|
|
67
|
+
🚧 **Under Construction**
|
|
68
|
+
|
|
69
|
+
Signal-based forms utilities for Angular template-driven forms.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### Utils
|
|
74
|
+
|
|
75
|
+
**Import:** `@telperion/ng-pack/utils`
|
|
76
|
+
|
|
77
|
+
🚧 **Under Construction**
|
|
78
|
+
|
|
79
|
+
Common Angular utilities and helpers.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
### Running Unit Tests
|
|
86
|
+
|
|
87
|
+
Run `pnpm nx test ng-pack` to execute the unit tests.
|
|
88
|
+
|
|
89
|
+
### Building
|
|
90
|
+
|
|
91
|
+
Run `pnpm nx build ng-pack` to build the library.
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
This library is part of the Telperion monorepo.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { InjectionToken, inject } from '@angular/core';
|
|
2
|
+
import { ReactiveWebLocalStorage, ReactiveWebSessionStorage } from '@thalesrc/reactive-storage';
|
|
3
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
|
+
|
|
5
|
+
function storageSignal(storage, store, key) {
|
|
6
|
+
const source = toSignal(storage.get(store, key));
|
|
7
|
+
function setter(value) {
|
|
8
|
+
storage.set(store, key, value);
|
|
9
|
+
}
|
|
10
|
+
function updater(updaterFn) {
|
|
11
|
+
const currentValue = source();
|
|
12
|
+
const newValue = updaterFn(currentValue);
|
|
13
|
+
storage.set(store, key, newValue);
|
|
14
|
+
}
|
|
15
|
+
function deleter() {
|
|
16
|
+
storage.delete(store, key);
|
|
17
|
+
}
|
|
18
|
+
return new Proxy(source, {
|
|
19
|
+
apply() {
|
|
20
|
+
return source();
|
|
21
|
+
},
|
|
22
|
+
get(target, prop, receiver) {
|
|
23
|
+
switch (prop) {
|
|
24
|
+
case 'set':
|
|
25
|
+
return setter;
|
|
26
|
+
case 'update':
|
|
27
|
+
return updater;
|
|
28
|
+
case 'delete':
|
|
29
|
+
return deleter;
|
|
30
|
+
default:
|
|
31
|
+
return Reflect.get(target, prop, receiver);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const LOCAL_STORAGE = new InjectionToken('Telperion Local Storage');
|
|
38
|
+
function provideLocalStorage(appName) {
|
|
39
|
+
return {
|
|
40
|
+
provide: LOCAL_STORAGE,
|
|
41
|
+
useValue: new ReactiveWebLocalStorage(appName)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function localStorageSignal(store, key) {
|
|
45
|
+
const storage = inject(LOCAL_STORAGE);
|
|
46
|
+
return storageSignal(storage, store, key);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const SESSION_STORAGE = new InjectionToken('Telperion Session Storage');
|
|
50
|
+
function provideSessionStorage(appName) {
|
|
51
|
+
return {
|
|
52
|
+
provide: SESSION_STORAGE,
|
|
53
|
+
useValue: new ReactiveWebSessionStorage(appName)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function sessionStorageSignal(store, key) {
|
|
57
|
+
const storage = inject(SESSION_STORAGE);
|
|
58
|
+
return storageSignal(storage, store, key);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Generated bundle index. Do not edit.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
export { localStorageSignal, provideLocalStorage, provideSessionStorage, sessionStorageSignal };
|
|
66
|
+
//# sourceMappingURL=telperion-ng-pack-storage-signals.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telperion-ng-pack-storage-signals.mjs","sources":["../../storage-signals/src/storage.ts","../../storage-signals/src/local-storage.ts","../../storage-signals/src/session-storage.ts","../../storage-signals/src/telperion-ng-pack-storage-signals.ts"],"sourcesContent":["import { WritableSignal } from \"@angular/core\";\r\nimport { toSignal } from \"@angular/core/rxjs-interop\";\r\nimport { ReactiveStorage } from '@thalesrc/reactive-storage';\r\n\r\nexport interface StorageSignal<T> extends WritableSignal<T | null | undefined> {\r\n delete(): void;\r\n}\r\n\r\nexport function storageSignal<T>(storage: ReactiveStorage, store: string, key: string): StorageSignal<T> {\r\n const source = toSignal(storage.get<T>(store, key));\r\n\r\n function setter(value: T | null | undefined) {\r\n storage.set(store, key, value);\r\n }\r\n\r\n function updater(updaterFn: (value: T | null | undefined) => T | null | undefined) {\r\n const currentValue = source();\r\n const newValue = updaterFn(currentValue);\r\n\r\n storage.set(store, key, newValue);\r\n }\r\n\r\n function deleter() {\r\n storage.delete(store, key);\r\n }\r\n\r\n return new Proxy(source as StorageSignal<T>, {\r\n apply() {\r\n return source();\r\n },\r\n get(target, prop, receiver) {\r\n switch (prop) {\r\n case 'set':\r\n return setter;\r\n case 'update':\r\n return updater;\r\n case 'delete':\r\n return deleter;\r\n default:\r\n return Reflect.get(target, prop, receiver);\r\n }\r\n }\r\n })\r\n}\r\n","import { inject, InjectionToken, Provider } from \"@angular/core\";\r\nimport { ReactiveWebLocalStorage } from '@thalesrc/reactive-storage';\r\n\r\nimport { StorageSignal, storageSignal } from \"./storage\";\r\n\r\nconst LOCAL_STORAGE = new InjectionToken<ReactiveWebLocalStorage>('Telperion Local Storage');\r\n\r\nexport function provideLocalStorage(appName?: string): Provider {\r\n return {\r\n provide: LOCAL_STORAGE,\r\n useValue: new ReactiveWebLocalStorage(appName)\r\n };\r\n}\r\n\r\nexport function localStorageSignal<T>(store: string, key: string): StorageSignal<T> {\r\n const storage = inject(LOCAL_STORAGE);\r\n\r\n return storageSignal(storage, store, key);\r\n}\r\n","import { inject, InjectionToken, Provider } from \"@angular/core\";\r\nimport { ReactiveWebSessionStorage } from '@thalesrc/reactive-storage';\r\n\r\nimport { StorageSignal, storageSignal } from \"./storage\";\r\n\r\nconst SESSION_STORAGE = new InjectionToken<ReactiveWebSessionStorage>('Telperion Session Storage');\r\n\r\nexport function provideSessionStorage(appName?: string): Provider {\r\n return {\r\n provide: SESSION_STORAGE,\r\n useValue: new ReactiveWebSessionStorage(appName)\r\n };\r\n}\r\n\r\nexport function sessionStorageSignal<T>(store: string, key: string): StorageSignal<T> {\r\n const storage = inject(SESSION_STORAGE);\r\n\r\n return storageSignal(storage, store, key);\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;SAQgB,aAAa,CAAI,OAAwB,EAAE,KAAa,EAAE,GAAW,EAAA;AACnF,IAAA,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAI,KAAK,EAAE,GAAG,CAAC,CAAC;IAEnD,SAAS,MAAM,CAAC,KAA2B,EAAA;QACzC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC;IAChC;IAEA,SAAS,OAAO,CAAC,SAAgE,EAAA;AAC/E,QAAA,MAAM,YAAY,GAAG,MAAM,EAAE;AAC7B,QAAA,MAAM,QAAQ,GAAG,SAAS,CAAC,YAAY,CAAC;QAExC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC;IACnC;AAEA,IAAA,SAAS,OAAO,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC;IAC5B;AAEA,IAAA,OAAO,IAAI,KAAK,CAAC,MAA0B,EAAE;QAC3C,KAAK,GAAA;YACH,OAAO,MAAM,EAAE;QACjB,CAAC;AACD,QAAA,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAA;YACxB,QAAQ,IAAI;AACV,gBAAA,KAAK,KAAK;AACR,oBAAA,OAAO,MAAM;AACf,gBAAA,KAAK,QAAQ;AACX,oBAAA,OAAO,OAAO;AAChB,gBAAA,KAAK,QAAQ;AACX,oBAAA,OAAO,OAAO;AAChB,gBAAA;oBACE,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC;;QAEhD;AACD,KAAA,CAAC;AACJ;;ACtCA,MAAM,aAAa,GAAG,IAAI,cAAc,CAA0B,yBAAyB,CAAC;AAEtF,SAAU,mBAAmB,CAAC,OAAgB,EAAA;IAClD,OAAO;AACL,QAAA,OAAO,EAAE,aAAa;AACtB,QAAA,QAAQ,EAAE,IAAI,uBAAuB,CAAC,OAAO;KAC9C;AACH;AAEM,SAAU,kBAAkB,CAAI,KAAa,EAAE,GAAW,EAAA;AAC9D,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,aAAa,CAAC;IAErC,OAAO,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC;AAC3C;;ACbA,MAAM,eAAe,GAAG,IAAI,cAAc,CAA4B,2BAA2B,CAAC;AAE5F,SAAU,qBAAqB,CAAC,OAAgB,EAAA;IACpD,OAAO;AACL,QAAA,OAAO,EAAE,eAAe;AACxB,QAAA,QAAQ,EAAE,IAAI,yBAAyB,CAAC,OAAO;KAChD;AACH;AAEM,SAAU,oBAAoB,CAAI,KAAa,EAAE,GAAW,EAAA;AAChE,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,eAAe,CAAC;IAEvC,OAAO,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC;AAC3C;;AClBA;;AAEG;;;;"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { NgModule, forwardRef } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
class UtilsModule {
|
|
5
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UtilsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
6
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.5", ngImport: i0, type: UtilsModule });
|
|
7
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UtilsModule });
|
|
8
|
+
}
|
|
9
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: UtilsModule, decorators: [{
|
|
10
|
+
type: NgModule,
|
|
11
|
+
args: [{
|
|
12
|
+
imports: [],
|
|
13
|
+
}]
|
|
14
|
+
}] });
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Utility function to create a provider for a directive/component that can be injected as a service.
|
|
18
|
+
* This is useful for cases where you want to inject a directive/component instance into another directive/component.
|
|
19
|
+
*
|
|
20
|
+
* Example usage:
|
|
21
|
+
*
|
|
22
|
+
* files:
|
|
23
|
+
* - parent.directive.ts
|
|
24
|
+
* - child.directive.ts
|
|
25
|
+
* - parent.service.ts
|
|
26
|
+
*
|
|
27
|
+
* parent.service.ts:
|
|
28
|
+
* ```
|
|
29
|
+
* import { InjectionToken } from "@angular/core";
|
|
30
|
+
* import type { ParentDirective } from "./parent.directive";
|
|
31
|
+
*
|
|
32
|
+
* export const ParentService = new InjectionToken<ParentDirective>("ParentService");
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* parent.directive.ts:
|
|
36
|
+
* ```
|
|
37
|
+
* @Directive({
|
|
38
|
+
* selector: 'parent',
|
|
39
|
+
* providers: [provideServiceDirective(ParentService, ParentDirective)],
|
|
40
|
+
* })
|
|
41
|
+
* export class ParentDirective {...}
|
|
42
|
+
* ```
|
|
43
|
+
* child.directive.ts:
|
|
44
|
+
* ```
|
|
45
|
+
* @Directive({
|
|
46
|
+
* selector: 'child',
|
|
47
|
+
* })
|
|
48
|
+
* export class ChildDirective {
|
|
49
|
+
* #parent = inject(ParentService);
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @param token - The injection token to provide.
|
|
54
|
+
* @param directive - The directive/component class that will be provided.
|
|
55
|
+
* @returns A provider object that can be used in the providers array of an Angular module or component.
|
|
56
|
+
*/
|
|
57
|
+
function provideServiceDirective(token, directive) {
|
|
58
|
+
return {
|
|
59
|
+
provide: token,
|
|
60
|
+
useExisting: forwardRef(() => directive)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Generated bundle index. Do not edit.
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
export { UtilsModule, provideServiceDirective };
|
|
69
|
+
//# sourceMappingURL=telperion-ng-pack-utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telperion-ng-pack-utils.mjs","sources":["../../utils/src/lib/utils-module.ts","../../utils/src/lib/provide-service-directive.ts","../../utils/src/telperion-ng-pack-utils.ts"],"sourcesContent":["import { NgModule } from '@angular/core';\n\n@NgModule({\n imports: [],\n})\nexport class UtilsModule {}\n","import { forwardRef, InjectionToken, Provider, Type } from \"@angular/core\";\r\n\r\n/**\r\n * Utility function to create a provider for a directive/component that can be injected as a service.\r\n * This is useful for cases where you want to inject a directive/component instance into another directive/component.\r\n *\r\n * Example usage:\r\n *\r\n * files:\r\n * - parent.directive.ts\r\n * - child.directive.ts\r\n * - parent.service.ts\r\n *\r\n * parent.service.ts:\r\n * ```\r\n * import { InjectionToken } from \"@angular/core\";\r\n * import type { ParentDirective } from \"./parent.directive\";\r\n *\r\n * export const ParentService = new InjectionToken<ParentDirective>(\"ParentService\");\r\n * ```\r\n *\r\n * parent.directive.ts:\r\n * ```\r\n * @Directive({\r\n * selector: 'parent',\r\n * providers: [provideServiceDirective(ParentService, ParentDirective)],\r\n * })\r\n * export class ParentDirective {...}\r\n * ```\r\n * child.directive.ts:\r\n * ```\r\n * @Directive({\r\n * selector: 'child',\r\n * })\r\n * export class ChildDirective {\r\n * #parent = inject(ParentService);\r\n * }\r\n * ```\r\n *\r\n * @param token - The injection token to provide.\r\n * @param directive - The directive/component class that will be provided.\r\n * @returns A provider object that can be used in the providers array of an Angular module or component.\r\n */\r\nexport function provideServiceDirective<T extends Type<unknown>>(\r\n token: InjectionToken<T>,\r\n directive: T\r\n): Provider {\r\n return {\r\n provide: token,\r\n useExisting: forwardRef(() => directive)\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;MAKa,WAAW,CAAA;uGAAX,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA;wGAAX,WAAW,EAAA,CAAA;wGAAX,WAAW,EAAA,CAAA;;2FAAX,WAAW,EAAA,UAAA,EAAA,CAAA;kBAHvB,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;AACR,oBAAA,OAAO,EAAE,EAAE;AACZ,iBAAA;;;ACFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCG;AACG,SAAU,uBAAuB,CACrC,KAAwB,EACxB,SAAY,EAAA;IAEZ,OAAO;AACL,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,WAAW,EAAE,UAAU,CAAC,MAAM,SAAS;KACxC;AACH;;ACnDA;;AAEG;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Component } from '@angular/core';
|
|
3
|
+
import { CommonModule } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
class NgPack {
|
|
6
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: NgPack, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.5", type: NgPack, isStandalone: true, selector: "tng-ng-pack", ngImport: i0, template: `<p>NgPack works!</p>`, isInline: true, styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
8
|
+
}
|
|
9
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: NgPack, decorators: [{
|
|
10
|
+
type: Component,
|
|
11
|
+
args: [{ selector: 'tng-ng-pack', imports: [CommonModule], template: `<p>NgPack works!</p>` }]
|
|
12
|
+
}] });
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generated bundle index. Do not edit.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export { NgPack };
|
|
19
|
+
//# sourceMappingURL=telperion-ng-pack.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telperion-ng-pack.mjs","sources":["../../src/lib/ng-pack/ng-pack.ts","../../src/telperion-ng-pack.ts"],"sourcesContent":["import { Component } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n@Component({\n selector: 'tng-ng-pack',\n imports: [CommonModule],\n template: `<p>NgPack works!</p>`,\n styles: ``,\n})\nexport class NgPack {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;MASa,MAAM,CAAA;uGAAN,MAAM,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAN,MAAM,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,aAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAHP,CAAA,oBAAA,CAAsB,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EADtB,YAAY,EAAA,CAAA,EAAA,CAAA;;2FAIX,MAAM,EAAA,UAAA,EAAA,CAAA;kBANlB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,aAAa,EAAA,OAAA,EACd,CAAC,YAAY,CAAC,YACb,CAAA,oBAAA,CAAsB,EAAA;;;ACNlC;;AAEG;;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@telperion/ng-pack",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "^21.0.0",
|
|
6
|
+
"@angular/core": "^21.0.0",
|
|
7
|
+
"@angular/forms": "^21.0.0",
|
|
8
|
+
"rxjs": "^7.8.1"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@thalesrc/reactive-storage": "^1.0.5",
|
|
12
|
+
"tslib": "^2.3.0"
|
|
13
|
+
},
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"bugs": "https://github.com/telperiontech/telperion/issues",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"homepage": "https://open-source.telperion.tr",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/telperiontech/telperion.git"
|
|
21
|
+
},
|
|
22
|
+
"author": {
|
|
23
|
+
"name": "Ali Şahin Özçelik",
|
|
24
|
+
"email": "alisahinozcelik@gmail.com",
|
|
25
|
+
"url": "https://alisah.in"
|
|
26
|
+
},
|
|
27
|
+
"funding": {
|
|
28
|
+
"type": "patreon",
|
|
29
|
+
"url": "https://www.patreon.com/alisahin"
|
|
30
|
+
},
|
|
31
|
+
"module": "fesm2022/telperion-ng-pack.mjs",
|
|
32
|
+
"typings": "types/telperion-ng-pack.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
"./package.json": {
|
|
35
|
+
"default": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./types/telperion-ng-pack.d.ts",
|
|
39
|
+
"default": "./fesm2022/telperion-ng-pack.mjs"
|
|
40
|
+
},
|
|
41
|
+
"./storage-signals": {
|
|
42
|
+
"types": "./types/telperion-ng-pack-storage-signals.d.ts",
|
|
43
|
+
"default": "./fesm2022/telperion-ng-pack-storage-signals.mjs"
|
|
44
|
+
},
|
|
45
|
+
"./utils": {
|
|
46
|
+
"types": "./types/telperion-ng-pack-utils.d.ts",
|
|
47
|
+
"default": "./fesm2022/telperion-ng-pack-utils.mjs"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# @telperion/ng-pack/storage-signals
|
|
2
|
+
|
|
3
|
+
Angular signals-based wrapper for browser's localStorage and sessionStorage with reactive updates.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Signal-based API** - Seamlessly integrate with Angular's signal system
|
|
8
|
+
- 🔄 **Reactive updates** - Automatically sync changes across components
|
|
9
|
+
- 🎯 **Type-safe** - Full TypeScript support with generic typing
|
|
10
|
+
- 🏪 **Dual storage support** - Works with both localStorage and sessionStorage
|
|
11
|
+
- 🔑 **Namespaced storage** - Organize storage with app names and store names
|
|
12
|
+
- 🎯 **Nested property access** - Access deep object properties using dot notation
|
|
13
|
+
- 🧹 **Simple API** - Signal interface with `set()`, `update()`, and `delete()` methods
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
This is a secondary entry point of `@telperion/ng-pack`. Import from `@telperion/ng-pack/storage-signals`.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @telperion/ng-pack
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
### Local Storage
|
|
26
|
+
|
|
27
|
+
Configure localStorage in your application config:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { ApplicationConfig } from '@angular/core';
|
|
31
|
+
import { provideLocalStorage } from '@telperion/ng-pack/storage-signals';
|
|
32
|
+
|
|
33
|
+
export const appConfig: ApplicationConfig = {
|
|
34
|
+
providers: [
|
|
35
|
+
provideLocalStorage('my-app'), // Optional app name for namespacing
|
|
36
|
+
// ... other providers
|
|
37
|
+
]
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Session Storage
|
|
42
|
+
|
|
43
|
+
Configure sessionStorage in your application config:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { ApplicationConfig } from '@angular/core';
|
|
47
|
+
import { provideSessionStorage } from '@telperion/ng-pack/storage-signals';
|
|
48
|
+
|
|
49
|
+
export const appConfig: ApplicationConfig = {
|
|
50
|
+
providers: [
|
|
51
|
+
provideSessionStorage('my-app'), // Optional app name for namespacing
|
|
52
|
+
// ... other providers
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
### Basic Usage
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { Component } from '@angular/core';
|
|
63
|
+
import { localStorageSignal } from '@telperion/ng-pack/storage-signals';
|
|
64
|
+
|
|
65
|
+
@Component({
|
|
66
|
+
selector: 'app-user-settings',
|
|
67
|
+
template: `
|
|
68
|
+
<div>
|
|
69
|
+
<p>Theme: {{ theme() }}</p>
|
|
70
|
+
<button (click)="toggleTheme()">Toggle Theme</button>
|
|
71
|
+
<button (click)="resetTheme()">Reset</button>
|
|
72
|
+
</div>
|
|
73
|
+
`
|
|
74
|
+
})
|
|
75
|
+
export class UserSettingsComponent {
|
|
76
|
+
// Create a signal connected to localStorage
|
|
77
|
+
theme = localStorageSignal<string>('settings', 'theme');
|
|
78
|
+
|
|
79
|
+
toggleTheme() {
|
|
80
|
+
this.theme.update(current => current === 'dark' ? 'light' : 'dark');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
resetTheme() {
|
|
84
|
+
this.theme.delete();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Session Storage
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { Component } from '@angular/core';
|
|
93
|
+
import { sessionStorageSignal } from '@telperion/ng-pack/storage-signals';
|
|
94
|
+
|
|
95
|
+
@Component({
|
|
96
|
+
selector: 'app-wizard',
|
|
97
|
+
template: `
|
|
98
|
+
<div>
|
|
99
|
+
<p>Current Step: {{ currentStep() }}</p>
|
|
100
|
+
<button (click)="nextStep()">Next</button>
|
|
101
|
+
</div>
|
|
102
|
+
`
|
|
103
|
+
})
|
|
104
|
+
export class WizardComponent {
|
|
105
|
+
currentStep = sessionStorageSignal<number>('wizard', 'currentStep');
|
|
106
|
+
|
|
107
|
+
nextStep() {
|
|
108
|
+
this.currentStep.update(step => (step ?? 0) + 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Nested Property Access
|
|
114
|
+
|
|
115
|
+
One of the most powerful features is the ability to access nested object properties using dot notation:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
@Component({
|
|
119
|
+
selector: 'app-preferences',
|
|
120
|
+
template: `
|
|
121
|
+
<div>
|
|
122
|
+
<p>Theme: {{ theme() }}</p>
|
|
123
|
+
<p>Language: {{ language() }}</p>
|
|
124
|
+
<p>Notifications: {{ notifications() }}</p>
|
|
125
|
+
<button (click)="updateLanguage('es')">Spanish</button>
|
|
126
|
+
<button (click)="toggleNotifications()">Toggle Notifications</button>
|
|
127
|
+
</div>
|
|
128
|
+
`
|
|
129
|
+
})
|
|
130
|
+
export class PreferencesComponent {
|
|
131
|
+
// Access nested properties directly with dot notation
|
|
132
|
+
theme = localStorageSignal<string>('user', 'preferences.theme');
|
|
133
|
+
language = localStorageSignal<string>('user', 'preferences.language');
|
|
134
|
+
notifications = localStorageSignal<boolean>('user', 'preferences.notifications');
|
|
135
|
+
|
|
136
|
+
ngOnInit() {
|
|
137
|
+
// Initialize with default values if not set
|
|
138
|
+
if (!this.theme()) this.theme.set('light');
|
|
139
|
+
if (!this.language()) this.language.set('en');
|
|
140
|
+
if (this.notifications() === undefined) this.notifications.set(true);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
updateLanguage(language: string) {
|
|
144
|
+
this.language.set(language);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
toggleNotifications() {
|
|
148
|
+
this.notifications.update(enabled => !enabled);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
This approach provides several benefits:
|
|
154
|
+
- Each property has its own reactive signal
|
|
155
|
+
- No need for optional chaining or null checks in templates
|
|
156
|
+
- Updates to one property don't trigger re-renders for components using other properties
|
|
157
|
+
- More granular control and better performance
|
|
158
|
+
|
|
159
|
+
### Cross-Component Synchronization
|
|
160
|
+
|
|
161
|
+
Changes to storage signals are automatically synchronized across all components:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Component A
|
|
165
|
+
@Component({
|
|
166
|
+
selector: 'app-sidebar',
|
|
167
|
+
template: `<p>Count: {{ count() }}</p>`
|
|
168
|
+
})
|
|
169
|
+
export class SidebarComponent {
|
|
170
|
+
count = localStorageSignal<number>('app', 'count');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Component B
|
|
174
|
+
@Component({
|
|
175
|
+
selector: 'app-header',
|
|
176
|
+
template: `
|
|
177
|
+
<button (click)="increment()">
|
|
178
|
+
Count: {{ count() }}
|
|
179
|
+
</button>
|
|
180
|
+
`
|
|
181
|
+
})
|
|
182
|
+
export class HeaderComponent {
|
|
183
|
+
count = localStorageSignal<number>('app', 'count');
|
|
184
|
+
|
|
185
|
+
increment() {
|
|
186
|
+
this.count.update(n => (n ?? 0) + 1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Both components will show the same value and update together!
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## API Reference
|
|
193
|
+
|
|
194
|
+
### `provideLocalStorage(appName?: string): Provider`
|
|
195
|
+
|
|
196
|
+
Creates a provider for localStorage integration.
|
|
197
|
+
|
|
198
|
+
**Parameters:**
|
|
199
|
+
- `appName` (optional) - Namespace prefix for all storage keys
|
|
200
|
+
|
|
201
|
+
**Returns:** Angular Provider
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### `provideSessionStorage(appName?: string): Provider`
|
|
206
|
+
|
|
207
|
+
Creates a provider for sessionStorage integration.
|
|
208
|
+
|
|
209
|
+
**Parameters:**
|
|
210
|
+
- `appName` (optional) - Namespace prefix for all storage keys
|
|
211
|
+
|
|
212
|
+
**Returns:** Angular Provider
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### `localStorageSignal<T>(store: string, key: string): StorageSignal<T>`
|
|
217
|
+
|
|
218
|
+
Creates a signal connected to localStorage. Must be called within an injection context.
|
|
219
|
+
|
|
220
|
+
**Parameters:**
|
|
221
|
+
- `store` - Storage namespace/category (e.g., 'settings', 'user')
|
|
222
|
+
- `key` - Unique key within the store
|
|
223
|
+
|
|
224
|
+
**Returns:** `StorageSignal<T>`
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
### `sessionStorageSignal<T>(store: string, key: string): StorageSignal<T>`
|
|
229
|
+
|
|
230
|
+
Creates a signal connected to sessionStorage. Must be called within an injection context.
|
|
231
|
+
|
|
232
|
+
**Parameters:**
|
|
233
|
+
- `store` - Storage namespace/category (e.g., 'wizard', 'form-data')
|
|
234
|
+
- `key` - Unique key within the store
|
|
235
|
+
|
|
236
|
+
**Returns:** `StorageSignal<T>`
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### `StorageSignal<T>`
|
|
241
|
+
|
|
242
|
+
A signal interface extending Angular's `WritableSignal` with additional storage methods.
|
|
243
|
+
|
|
244
|
+
**Methods:**
|
|
245
|
+
- `()` - Read the current value
|
|
246
|
+
- `set(value: T | null | undefined)` - Set a new value
|
|
247
|
+
- `update(fn: (value: T | null | undefined) => T | null | undefined)` - Update using a function
|
|
248
|
+
- `delete()` - Remove the value from storage
|
|
249
|
+
|
|
250
|
+
## Storage Organization
|
|
251
|
+
|
|
252
|
+
The library uses a hierarchical storage structure:
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
[appName]:[store]:[key] = value
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Example:
|
|
259
|
+
```typescript
|
|
260
|
+
// With provideLocalStorage('my-app')
|
|
261
|
+
localStorageSignal<string>('settings', 'theme');
|
|
262
|
+
// Creates key: "my-app:settings:theme"
|
|
263
|
+
|
|
264
|
+
localStorageSignal<number>('user', 'id');
|
|
265
|
+
// Creates key: "my-app:user:id"
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
This organization helps prevent key collisions and makes storage management cleaner.
|
|
269
|
+
|
|
270
|
+
## TypeScript Support
|
|
271
|
+
|
|
272
|
+
The library is fully typed with TypeScript generics:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// Type-safe signals
|
|
276
|
+
const theme = localStorageSignal<'light' | 'dark'>('settings', 'theme');
|
|
277
|
+
theme.set('light'); // ✓ OK
|
|
278
|
+
theme.set('blue'); // ✗ Type error
|
|
279
|
+
|
|
280
|
+
const count = localStorageSignal<number>('app', 'count');
|
|
281
|
+
count.set(42); // ✓ OK
|
|
282
|
+
count.set('42'); // ✗ Type error
|
|
283
|
+
|
|
284
|
+
// Complex types
|
|
285
|
+
interface User {
|
|
286
|
+
id: number;
|
|
287
|
+
name: string;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const user = localStorageSignal<User>('auth', 'currentUser');
|
|
291
|
+
user.set({ id: 1, name: 'Alice' }); // ✓ OK
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Best Practices
|
|
295
|
+
|
|
296
|
+
1. **Use dot notation for nested properties** - Access deep object properties directly
|
|
297
|
+
```typescript
|
|
298
|
+
// Instead of managing the whole object
|
|
299
|
+
const user = localStorageSignal<User>('app', 'user');
|
|
300
|
+
const name = user()?.profile?.name;
|
|
301
|
+
|
|
302
|
+
// Access nested properties directly
|
|
303
|
+
const userName = localStorageSignal<string>('app', 'user.profile.name');
|
|
304
|
+
const userEmail = localStorageSignal<string>('app', 'user.profile.email');
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
2. **Use meaningful store names** - Group related keys together
|
|
308
|
+
```typescript
|
|
309
|
+
localStorageSignal('user-preferences', 'theme');
|
|
310
|
+
localStorageSignal('user-preferences', 'language');
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
3. **Initialize with defaults** - Check for null/undefined initial values
|
|
314
|
+
```typescript
|
|
315
|
+
const theme = localStorageSignal<string>('settings', 'theme');
|
|
316
|
+
if (!theme()) {
|
|
317
|
+
theme.set('light');
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
4. **Clean up sensitive data** - Use `delete()` when appropriate
|
|
322
|
+
```typescript
|
|
323
|
+
onLogout() {
|
|
324
|
+
this.authToken.delete();
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
5. **Use sessionStorage for temporary data** - Forms, wizards, temporary state
|
|
329
|
+
```typescript
|
|
330
|
+
const formDraft = sessionStorageSignal('form', 'draft');
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## License
|
|
334
|
+
|
|
335
|
+
This library is part of the Telperion monorepo.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { WritableSignal, Provider } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
interface StorageSignal<T> extends WritableSignal<T | null | undefined> {
|
|
4
|
+
delete(): void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
declare function provideLocalStorage(appName?: string): Provider;
|
|
8
|
+
declare function localStorageSignal<T>(store: string, key: string): StorageSignal<T>;
|
|
9
|
+
|
|
10
|
+
declare function provideSessionStorage(appName?: string): Provider;
|
|
11
|
+
declare function sessionStorageSignal<T>(store: string, key: string): StorageSignal<T>;
|
|
12
|
+
|
|
13
|
+
export { localStorageSignal, provideLocalStorage, provideSessionStorage, sessionStorageSignal };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Type, InjectionToken, Provider } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
declare class UtilsModule {
|
|
5
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<UtilsModule, never>;
|
|
6
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<UtilsModule, never, never, never>;
|
|
7
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<UtilsModule>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Utility function to create a provider for a directive/component that can be injected as a service.
|
|
12
|
+
* This is useful for cases where you want to inject a directive/component instance into another directive/component.
|
|
13
|
+
*
|
|
14
|
+
* Example usage:
|
|
15
|
+
*
|
|
16
|
+
* files:
|
|
17
|
+
* - parent.directive.ts
|
|
18
|
+
* - child.directive.ts
|
|
19
|
+
* - parent.service.ts
|
|
20
|
+
*
|
|
21
|
+
* parent.service.ts:
|
|
22
|
+
* ```
|
|
23
|
+
* import { InjectionToken } from "@angular/core";
|
|
24
|
+
* import type { ParentDirective } from "./parent.directive";
|
|
25
|
+
*
|
|
26
|
+
* export const ParentService = new InjectionToken<ParentDirective>("ParentService");
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* parent.directive.ts:
|
|
30
|
+
* ```
|
|
31
|
+
* @Directive({
|
|
32
|
+
* selector: 'parent',
|
|
33
|
+
* providers: [provideServiceDirective(ParentService, ParentDirective)],
|
|
34
|
+
* })
|
|
35
|
+
* export class ParentDirective {...}
|
|
36
|
+
* ```
|
|
37
|
+
* child.directive.ts:
|
|
38
|
+
* ```
|
|
39
|
+
* @Directive({
|
|
40
|
+
* selector: 'child',
|
|
41
|
+
* })
|
|
42
|
+
* export class ChildDirective {
|
|
43
|
+
* #parent = inject(ParentService);
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @param token - The injection token to provide.
|
|
48
|
+
* @param directive - The directive/component class that will be provided.
|
|
49
|
+
* @returns A provider object that can be used in the providers array of an Angular module or component.
|
|
50
|
+
*/
|
|
51
|
+
declare function provideServiceDirective<T extends Type<unknown>>(token: InjectionToken<T>, directive: T): Provider;
|
|
52
|
+
|
|
53
|
+
export { UtilsModule, provideServiceDirective };
|
package/utils/README.md
ADDED