Block a user
@phoenix-tekhne/angular-dynamis (2.5.1)
Published 2026-05-28 07:22:39 -07:00 by dmonphx
Installation
@phoenix-tekhne:registry=https://gitrepo.cstudiosinc.com/api/packages/dmonphx/npm/npm install @phoenix-tekhne/angular-dynamis@2.5.1"@phoenix-tekhne/angular-dynamis": "2.5.1"About this package
@phoenix-tekhne/angular-dynamis
Angular services for headless UI interactions using RxJS. Part of the Phoenix Tekhne Design System.
Installation
npm install @phoenix-tekhne/angular-dynamis @phoenix-tekhne/dynamis-core
Peer Dependencies:
@angular/core@^17.0.0rxjs@^7.8.0
Quick Start
import { Component } from '@angular/core';
import { PressService } from '@phoenix-tekhne/angular-dynamis';
@Component({
selector: 'app-button',
template: `
<button
[attr.data-pressed]="(pressService.state$ | async)?.isPressed"
(pointerdown)="pressService.handlePointerDown($event)"
(pointerup)="pressService.handlePointerUp($event)"
(keydown)="pressService.handleKeyDown($event)"
(keyup)="pressService.handleKeyUp($event)"
>
<ng-content></ng-content>
</button>
`,
})
export class ButtonComponent {
constructor(public pressService: PressService) {
pressService.initialize({ isDisabled: false });
}
}
Services
| Service | Greek | Purpose |
|---|---|---|
PressService |
προσκρούσις (pressing against) | Button press interactions |
ToggleService |
κράσις (mixing) | Toggle/checkbox state (binary & tri-state) |
TextFieldService |
λέξις (word) | Text field validation and state |
SelectService |
ἔλλειψις (choice) | Select/dropdown interactions |
ToastService |
κήρυγμα (proclamation) | Toast notifications |
API Reference
PressService (Press)
Handles button press interactions with pointer and keyboard support.
import { Component, OnInit } from '@angular/core';
import { PressService } from '@phoenix-tekhne/angular-dynamis';
@Component({
selector: 'app-button',
template: `
<button
[attr.aria-pressed]="(pressService.state$ | async)?.isPressed"
[attr.data-pressed]="(pressService.state$ | async)?.isPressed"
(pointerdown)="pressService.handlePointerDown($event)"
(pointerup)="pressService.handlePointerUp($event)"
(pointercancel)="pressService.handlePointerCancel($event)"
(keydown)="pressService.handleKeyDown($event)"
(keyup)="pressService.handleKeyUp($event)"
[disabled]="isDisabled"
>
<ng-content></ng-content>
</button>
`,
providers: [PressService],
})
export class ButtonComponent implements OnInit {
@Input() isDisabled = false;
constructor(public pressService: PressService) {}
ngOnInit(): void {
this.pressService.initialize({
isDisabled: this.isDisabled,
onPress: () => this.onPress.emit(),
onRelease: () => this.onRelease.emit(),
});
}
@Output() onPress = new EventEmitter<void>();
@Output() onRelease = new EventEmitter<void>();
}
Options:
| Option | Type | Default | Description |
|---|---|---|---|
isDisabled |
boolean |
false |
Disables press handling |
onPress |
() => void |
- | Callback when press activates |
onRelease |
() => void |
- | Callback when press releases |
Observable Properties:
| Property | Type | Description |
|---|---|---|
state$ |
Observable<PressState> |
Current press state |
ToggleService (Toggle/Checkbox)
Handles toggle and checkbox state, supporting both binary and tri-state (indeterminate).
import { Component, OnInit } from '@angular/core';
import { ToggleService, KrasisStateValue } from '@phoenix-tekhne/angular-dynamis';
@Component({
selector: 'app-checkbox',
template: `
<div
role="checkbox"
[attr.aria-checked]="getAriaChecked()"
[attr.data-checked]="(toggleService.state$ | async)?.value === true"
tabindex="0"
(click)="toggleService.toggle()"
(keydown)="handleKeyDown($event)"
>
<span class="checkmark">
{{ (toggleService.state$ | async)?.value === true ? '✓' :
(toggleService.state$ | async)?.value === 'indeterminate' ? '−' : '' }}
</span>
<ng-content></ng-content>
</div>
`,
providers: [ToggleService],
})
export class CheckboxComponent implements OnInit {
@Input() isDisabled = false;
@Input() initialValue: KrasisStateValue = false;
@Input() allowIndeterminate = false;
constructor(public toggleService: ToggleService) {}
ngOnInit(): void {
this.toggleService.initialize({
isDisabled: this.isDisabled,
initialValue: this.initialValue,
allowIndeterminate: this.allowIndeterminate,
onChange: (value) => this.onChange.emit(value),
});
}
@Output() onChange = new EventEmitter<KrasisStateValue>();
getAriaChecked(): string {
const value = this.toggleService.value;
if (value === 'indeterminate') return 'mixed';
return String(value);
}
handleKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.toggleService.toggle();
}
}
}
Options:
| Option | Type | Default | Description |
|---|---|---|---|
isDisabled |
boolean |
false |
Disables toggle |
initialValue |
boolean | 'indeterminate' |
false |
Initial checked state |
allowIndeterminate |
boolean |
false |
Enable tri-state mode |
onChange |
(value) => void |
- | Callback on value change |
TextFieldService (Text Field)
Handles text field state, validation, and formatting.
import { Component, OnInit } from '@angular/core';
import { TextFieldService } from '@phoenix-tekhne/angular-dynamis';
@Component({
selector: 'app-text-field',
template: `
<div>
<input
[value]="textFieldService.value"
(input)="textFieldService.handleChange($event.target.value)"
(focus)="textFieldService.handleFocus()"
(blur)="textFieldService.handleBlur()"
[disabled]="isDisabled"
[required]="isRequired"
[attr.aria-invalid]="!(textFieldService.state$ | async)?.isValid"
[attr.data-dirty]="(textFieldService.state$ | async)?.isDirty"
[attr.data-visited]="(textFieldService.state$ | async)?.isVisited"
/>
<span *ngIf="!(textFieldService.state$ | async)?.isValid && (textFieldService.state$ | async)?.isVisited">
{{ textFieldService.getValidationMessage() }}
</span>
</div>
`,
providers: [TextFieldService],
})
export class TextFieldComponent implements OnInit {
@Input() isDisabled = false;
@Input() isRequired = false;
@Input() minLength?: number;
@Input() maxLength?: number;
@Input() pattern?: string;
@Input() validate?: (value: string) => boolean;
constructor(public textFieldService: TextFieldService) {}
ngOnInit(): void {
this.textFieldService.initialize({
isDisabled: this.isDisabled,
isRequired: this.isRequired,
minLength: this.minLength,
maxLength: this.maxLength,
pattern: this.pattern,
validate: this.validate,
onChange: (value) => this.onChange.emit(value),
onBlur: (value) => this.onBlur.emit(value),
});
}
@Output() onChange = new EventEmitter<string>();
@Output() onBlur = new EventEmitter<string>();
}
SelectService (Select/Dropdown)
Handles select and dropdown interactions with single and multi-select support.
import { Component, OnInit } from '@angular/core';
import { SelectService, SelectItem } from '@phoenix-tekhne/angular-dynamis';
@Component({
selector: 'app-select',
template: `
<div>
<button
[attr.aria-expanded]="(selectService.state$ | async)?.isOpen"
(click)="selectService.handleTriggerClick()"
(keydown)="selectService.handleTriggerKeyDown($event)"
>
{{ selectService.displayLabel || 'Select...' }}
</button>
<ul
*ngIf="(selectService.state$ | async)?.isOpen"
role="listbox"
[attr.data-open]="(selectService.state$ | async)?.isOpen"
>
<li
*ngFor="let item of items; let i = index"
role="option"
[attr.data-selected]="selectService.selectedValues.includes(item.id)"
(click)="selectService.selectItem(item.id)"
>
{{ item.label }}
</li>
</ul>
</div>
`,
providers: [SelectService],
})
export class SelectComponent implements OnInit {
@Input() items: SelectItem[] = [];
@Input() isMulti = false;
constructor(public selectService: SelectService) {}
ngOnInit(): void {
this.selectService.initialize({
isMulti: this.isMulti,
onChange: (values) => this.onChange.emit(values),
});
this.selectService.setItems(this.items);
}
@Output() onChange = new EventEmitter<string[]>();
}
ToastService (Toast Notifications)
Manages toast notification lifecycle including queuing and dismissal.
import { Component, OnInit } from '@angular/core';
import { ToastService } from '@phoenix-tekhne/angular-dynamis';
@Component({
selector: 'app-toast-container',
template: `
<div [attr.data-position]="(toastService.state$ | async)?.position" class="toast-container">
<div
*ngFor="let toast of toastService.getVisibleToasts()"
class="toast"
[attr.data-variant]="toast.variant"
(mouseenter)="toastService.pause(toast.id)"
(mouseleave)="toastService.resume(toast.id)"
>
<span *ngIf="toast.title" class="toast-title">{{ toast.title }}</span>
<span class="toast-message">{{ toast.message }}</span>
<button *ngIf="toast.dismissible" (click)="toastService.dismiss(toast.id)">×</button>
</div>
</div>
`,
providers: [ToastService],
})
export class ToastContainerComponent implements OnInit {
constructor(public toastService: ToastService) {}
ngOnInit(): void {
this.toastService.initialize({
position: 'bottom-right',
maxVisible: 5,
duration: 5000,
});
}
}
// Usage in a service:
@Injectable({ providedIn: 'root' })
export class NotificationService {
constructor(private toastService: ToastService) {
this.toastService.initialize({ position: 'bottom-right' });
}
showSuccess(message: string, title?: string): string {
return this.toastService.success(message, title);
}
showError(message: string, title?: string): string {
return this.toastService.error(message, title);
}
}
Options:
| Option | Type | Default | Description |
|---|---|---|---|
maxVisible |
number |
5 |
Maximum visible toasts |
position |
ToastPosition |
'bottom-right' |
Toast position |
duration |
number |
5000 |
Default duration in ms |
pauseOnHover |
boolean |
true |
Pause on hover |
dismissible |
boolean |
true |
Allow dismissal |
showProgress |
boolean |
false |
Show progress bar |
RxJS Patterns
All services follow consistent RxJS patterns:
BehaviorSubject for State
@Injectable({ providedIn: 'root' })
export class MyService {
private stateSubject = new BehaviorSubject<State>(initialState);
state$ = this.stateSubject.asObservable();
}
Observable Pattern
// Subscribe to state changes
this.pressService.state$.subscribe(state => {
console.log('Is pressed:', state.isPressed);
});
// Use with async pipe in templates
<div>{{ (pressService.state$ | async)?.isPressed }}</div>
Greek Terminology
| Greek | Transliteration | English | Used For |
|---|---|---|---|
| δύναμις | dynamis | Power, Ability | Core state machine package |
| προσκρούσις | proskrousis | Pressing against, striking | Button press interactions |
| κράσις | krasis | Mixing | Toggle/checkbox state |
| λέξις | lexis | Word | Text field validation |
| ἔλλειψις | epilipsis | Choice, selection | Select/dropdown |
| κήρυγμα | kerygma | Proclamation | Toast notifications |
Related Packages
@phoenix-tekhne/dynamis-core- Pure TypeScript state machines@phoenix-tekhne/react-dynamis- React hooks@phoenix-tekhne/vue-dynamis- Vue 3 composables@phoenix-tekhne/svelte-dynamis- Svelte stores@phoenix-tekhne/web-dynamis- Web Components
License
MIT
Dependencies
Dependencies
| ID | Version |
|---|---|
| @phoenix-tekhne/dynamis-core | 2.5.1 |
Development Dependencies
| ID | Version |
|---|---|
| @angular/core | ^19.0.0 |
| rxjs | ^7.8.0 |
| typescript | ^5.7.0 |
| vite | ^6.0.0 |
| vitest | ^2.0.0 |
Peer Dependencies
| ID | Version |
|---|---|
| @angular/core | ^19.0.0 |
| rxjs | ^7.5.0 |
Keywords
angular
angular2
headless
ui
components
services
rxjs
design-system
phoenix-tekhne
Details
2026-05-28 07:22:39 -07:00
Assets (1)
Versions (1)
View all
npm
5
Phoenix Tekhne Team
MIT
latest
16 KiB
angular-dynamis-2.5.1.tgz
16 KiB
2.5.1
2026-05-28