{"id":26533431,"url":"https://github.com/DDtMM/angular-signal-generators","last_synced_at":"2025-03-21T19:05:27.566Z","repository":{"id":181092717,"uuid":"665973668","full_name":"DDtMM/angular-signal-generators","owner":"DDtMM","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-19T12:24:31.000Z","size":1294,"stargazers_count":1,"open_issues_count":6,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-19T13:28:06.423Z","etag":null,"topics":["angular","signals"],"latest_commit_sha":null,"homepage":"https://ddtmm.github.io/angular-signal-generators/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DDtMM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-07-13T12:18:00.000Z","updated_at":"2024-04-19T13:28:27.950Z","dependencies_parsed_at":"2023-12-03T21:25:16.194Z","dependency_job_id":"882758b2-014e-4836-b963-ed7ee8e442a7","html_url":"https://github.com/DDtMM/angular-signal-generators","commit_stats":null,"previous_names":["ddtmm/angular-signal-generators"],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DDtMM%2Fangular-signal-generators","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DDtMM%2Fangular-signal-generators/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DDtMM%2Fangular-signal-generators/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DDtMM%2Fangular-signal-generators/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DDtMM","download_url":"https://codeload.github.com/DDtMM/angular-signal-generators/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244852677,"owners_count":20521155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","signals"],"created_at":"2025-03-21T19:02:18.440Z","updated_at":"2025-03-21T19:05:27.556Z","avatar_url":"https://github.com/DDtMM.png","language":"TypeScript","readme":"# Angular Signal Generators \n\n Streamline your Angular development with Angular Signal Generators,\na library of signals and utilities designed to replace common patterns for faster, cleaner code.\n\nCheck out the **[demos](https://ddtmm.github.io/angular-signal-generators/)** to learn more.\n\n| Statements                  | Branches                | Functions                 | Lines             |\n| --------------------------- | ----------------------- | ------------------------- | ----------------- |\n| ![Statements](https://img.shields.io/badge/statements-100%25-brightgreen.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-100%25-brightgreen.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-100%25-brightgreen.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-100%25-brightgreen.svg?style=flat) |\n\n## Installation\n\n```\nnpm install @ddtmm/angular-signal-generators\n```\n\n## Usage\nYou can import the signals and utilities from `@ddtmm/angular-signal-generators`.  Like regular signals, the library's signals are used just like ordinary functions. \n\n```ts\nimport { debounceSignal, liftSignal, timerSignal } from '@ddtmm/angular-signal-generators';\n\n@Component({\n  selector: 'app-signal-demo',\n  standalone: true,\n  imports: [CommonModule, FormsModule],\n  template: `\n\u003cdiv\u003e{{$secondsSinceStart()}}\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cinput type=\"text\" [(ngModel)]=\"$debounced\" /\u003e\n  {{debounced()}}\n\u003c/div\u003e\n\u003cdiv\u003e\n  \u003cbutton type=\"button\" (click)=\"$liftedArray.push(secondsSinceStart())\"\u003e\n    Add Element\n  \u003c/button\u003e \n  {{$liftedArray() | json}}\n\u003c/div\u003e\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SignalDemoComponent {\n  readonly $debounced = debounceSignal('type in me', 1000);\n  readonly $liftedArray = liftSignal([0], null, ['push']);\n  readonly $secondsSinceStart = timerSignal(1000, 1000);\n}\n```\n\n## Signals\n\n### Animation Signals - springSignal / tweenSignal\n\nThese are directly inspired by Svelte's *spring* and *tweened* functions.  When the signal value changes, the observed value slowly morphs over time.  So if the original value was **1** and the next value was set to **5**, then the observed value will be something like *1*, *1.512*, *2.12*, *2.6553*, *3* over a set duration.\n\n### asyncSignal\n\nTakes an async source (Promise, Observable) or signal/function that returns an async source and returns that source's values as part of a signal.  Kind of like an rxjs flattening operator.\n\n### debounceSignal\n\nThis is very similar to rxjs's *debounce* operator.  This has two overloads - one where it accepts a signal and the value is debounced in a readonly signal, and one where it has a *set* and *update* method and the change of the value occurs after debounce time elapses.\n\n### DOM Observer Signals - intersectionSignal / mutationSignal / resizeSignal\n\nThese signals wrap the DOM observers IntersectionObserver, MutationObserver and ResizeObserver to output the last observation of changes to a target element passed to the signal.\n\n### eventSignal\n\nListens to HTML element events via Renderer2 and map them to new values.  \nSince a signal can be passed it is easy to use with viewChild function.\n\n### filterSignal\n\nFilters values set to a signal to prevent the value from changing:  \nIf the filter assigned at creation does not pass then the signal does not change. \nCan be used with guard functions.\n\n### liftSignal\n\n\"Lifts\" methods from a signal's value to the signal itself just by passing a tuple of method names.  The lifted methods should be those appropriate for mutating or updating the value.  For example, lifting `Array.push` will add a method called *push* to the signal.  Calling the *push* method will internally call `signal.mutate()` with a function that executes the push.\n\n### mapSignal\n\nCreates a signal whose input value is immediately mapped to a different value based on a selector.\nEither a value or multiple signals can be passed and used in the selector function.\n\n### mediaQuerySignal\n\nTakes a media query, and updates its value whenever the state of that query being matched changes.\n\n### nestSignal\n\nCreates a signal whose value changes after any nested signal's value updates no matter how deep the signal is nested.\nIt's value will be an object where every signal is replaced with its emitted value.\n\n### reduceSignal\n\nCreates a signal similar to `Array.reduce` or Rxjs's `scan` operator, using a reducer function to create a new value from the current and prior values.\n\n### sequenceSignal\n\nThe Sequence Signal is useful for situations where you want to easily cycle between options.  For example, if you want to toggle between true/false or a list of sizes.  These are still writable signals so you can manually override the current value.\n\nThere is also a special option to pass a cursor, which is similar to an iterator, but can be reset.  There will probably be more functionality added later.\n\n### Storage Signals - storageSignal / localStorageSignal / sessionStorageSignal\n\nSignals that uses a secondary storage system to store values, ideally beyond the lifetime of the application.  The next time the signal is initialized the initial value will come from this secondary storage.  Implementations using *localStorage* and *sessionStorage* exist for your convenience.\n\n### timerSignal\n\nThis is very similar to rxjs's *timer* operator.  It will be have like setTimeout or interval depending on the parameters passed.  The value of the timer is incremented after every \"tick\".\n\n## Utilities\n\n### gatedEffect\n\nAn effect with options to control when it start, stops or runs.\n\n### inspect\n\nInspired by Svelte's $inspect rune, logs the resolved values of signals deeply nested in an object, array or signal.\n\n### signalToIterator\n\nConverts a signal to an AsyncIterator.  Once created, changes are retained until elements are looped through at a later time.\n\n## Conventions\n\n### ReactiveSource and ValueSource\nAs much as possible signals the functions provided try to create signals from either values or other signals.\nTo accommodate this, many arguments are of type **ReactiveSource\u0026lt;T\u0026gt;** or **ValueSource\u0026lt;T\u0026gt;**.\n\n*ReactiveSource* can be either something that can be either converted to a signal with *toSignal*, a function that can be passed to *computed* or a regular old *signal*.  The purpose of this is to make things just a bit more convenient.\n\n### ValueSource\nA *ValueSource* is a *ReactiveSource* ***or a value***.  The limiting factor here is that if you wanted to use a *SignalSource* as a value, then you'd have to wrap that in a *signal*.\n\n```ts\nconst timerFromValue = timerSignal(1000);\n\nconst timeSourceAsSignal = signal(1000);\nconst timerFromSignal = timer(timeSourceAsSignal);\n\nconst timerFromComputedFn = timer(() =\u003e timeSourceAsSignal() * 2);\n\nconst timerSource$ = new BehaviorSubject(1000);\nconst timerFromObservable = timer(timerSource$);\n```\n### Overloads\nSeveral generators that accept a traditional value and a *ReactiveSource* will have different return types.  Those that accept a *ReactiveSource* will return a read only signal, whereas those with a traditional value will have methods to update the signal, though not necessarily the same as a *WritableSignal*.\n\n### Injector\nAll signal generators have an options parameter that accept injector.  This is either because *effect* is needed sometimes or it passed\nalong if an observable is converted to an signal.\n\n\n## Issues or Ideas?\nI'm just adding signals as I run into real life problems.  Please add an issue if you have an idea or run into a technical difficulty.\n","funding_links":[],"categories":["Recently Updated","Third Party Components"],"sub_categories":["[Mar 20, 2025](/content/2025/03/20/README.md)","Mixed Utilities"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDDtMM%2Fangular-signal-generators","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDDtMM%2Fangular-signal-generators","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDDtMM%2Fangular-signal-generators/lists"}