springest 0.0.0-stage → 0.2.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 springest
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,152 @@
1
- # Temporary Holding Version
1
+ # springest
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Standalone UI components for Angular 21.2, PrimeNG 21 and Signal Forms.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install springest@0.2.0 primeng@^21.1.0 @ngx-translate/core@^15.0.0 chart.js@^4.5.0
9
+ ```
10
+
11
+ Angular common/core/forms (^21.2.0) and RxJS (^7.8.0) are peer dependencies and must be provided by the application. Angular Signal Forms are experimental in Angular 21; this package targets that version. Configure a PrimeNG theme in your application.
12
+
13
+ ```ts
14
+ import { ButtonComponent, BasicSelectComponent } from 'springest';
15
+ ```
16
+
17
+ BasicSelect supports a scalar or null value. Use object options with `optionLabel` (default: `name`) and `optionValue` to select a property. Bind with Angular Signal Forms `[formField]` or two-way `[(value)]`. `changed` emits the selected value, blur marks the field touched, and `closed` emits when the popup closes.
18
+
19
+ ## Fields and validation
20
+
21
+ `BasicInputComponent`, `TextareaComponent`, `FilePickerComponent`, `ToggleComponent`, and `SegmentedControlComponent` support `[formField]` or `[(value)]`, `changed`, `touched`, `disabled`, and `readonly`. Validation belongs in your form schema. `FormFieldComponent` also accepts an existing Reactive Forms `AbstractControl`.
22
+
23
+ ```ts
24
+ import {Component, signal} from '@angular/core';
25
+ import {email, form, FormField, max, maxLength, min, minLength, required, submit} from '@angular/forms/signals';
26
+ import {BasicInputComponent, FormFieldComponent, TextareaComponent} from 'springest';
27
+
28
+ @Component({
29
+ imports: [FormField, FormFieldComponent, BasicInputComponent, TextareaComponent],
30
+ template: `
31
+ <form novalidate (submit)="$event.preventDefault(); save()">
32
+ <app-form-field [field]="fields.email" label="Email" [showLabel]="true" [submitted]="submitted()">
33
+ <app-basic-input type="email" [formField]="fields.email" autocomplete="email" />
34
+ </app-form-field>
35
+ <app-form-field [field]="fields.amount" label="Amount" [showLabel]="true" [submitted]="submitted()">
36
+ <app-basic-input type="number" [formField]="fields.amount" [step]="1" />
37
+ </app-form-field>
38
+ <app-form-field [field]="fields.note" [submitted]="submitted()">
39
+ <app-textarea label="Note" [formField]="fields.note" [rows]="4" />
40
+ </app-form-field>
41
+ <button type="submit">Save</button>
42
+ </form>
43
+ `,
44
+ })
45
+ export class Editor {
46
+ readonly submitted = signal(false);
47
+ readonly data = signal({email: '', amount: null as number | null, note: ''});
48
+ readonly fields = form(this.data, path => {
49
+ required(path.email, {message: 'Email is required'});
50
+ email(path.email, {message: 'Enter a valid email'});
51
+ min(path.amount, 1, {message: 'Number must be between 1 and 100'});
52
+ max(path.amount, 100, {message: 'Number must be between 1 and 100'});
53
+ minLength(path.note, 8, {message: 'Minimum 8 characters'});
54
+ maxLength(path.note, 500);
55
+ });
56
+ async save() {
57
+ this.submitted.set(true);
58
+ await submit(this.fields, async () => { console.log(this.data()); });
59
+ }
60
+ }
61
+ ```
62
+
63
+ Input `type` accepts `text` (default), `email`, `search`, or `number`. Text types emit strings; number emits `number | null`, with an empty field represented by `null`. Initialize numeric form/two-way values with `null` or a number. For two-way `[(value)]`, `min`, `max`, and `step` are native input attributes. With `[formField]`, configure `min`, `max`, and `maxLength` in the schema: Angular supplies them to the control and rejects simultaneous property bindings. `step` can still be supplied directly. Input also forwards `autocomplete`, `lang`, `spellcheck`, `readonly`, and both `disabled` and the existing `isDisabled`. The existing `placeholder` remains the fallback floating label when `label` is omitted.
64
+
65
+ FormField displays the first error after touch or when `submitted` is true. Angular `submit()` also marks invalid fields touched. Reset your `submitted` signal when starting a fresh form. Messages prefer `errorMessages` overrides, then the validator's `message`, then English defaults. The existing `ERRORS.FIELD_REQUIRED` translation is used when available. Override entries can be text or a function receiving the error parameters:
66
+
67
+ ```html
68
+ <app-form-field [field]="fields.note"
69
+ [errorMessages]="{required: 'Обязательное поле', minLength: 'Минимум 8 символов'}">
70
+ <app-textarea [formField]="fields.note" label="Описание" />
71
+ </app-form-field>
72
+ ```
73
+
74
+ Use one control per FormField. The wrapper owns its `controlId`, label and error IDs; outside it, controls use a unique `inputId` which you can override. Controls expose `ariaLabel`, `ariaLabelledBy`, `ariaDescribedBy`, and `ariaInvalid`. Descriptions preserve your supplied IDs and append the visible error ID. Labels and errors reach the internal native/focusable element, including Select, MultiSelect, Password, Checkbox and Calendar (`global-calendar`). Readonly disables selection in Select/MultiSelect and blocks date selection as well as typing in Calendar.
75
+
76
+ ## Files, switches and segmented choices
77
+
78
+ ```html
79
+ <app-file-picker label="Attachments" [(value)]="files" accept=".pdf,image/*" [multiple]="true" />
80
+ <app-toggle label="Notifications" [(value)]="notifications" />
81
+ <app-segmented-control label="Plan" [items]="plans" [(value)]="plan" variant="cards">
82
+ <ng-template #item let-item let-selected="selected">
83
+ <strong>{{ item.label }}</strong>
84
+ <span>{{ selected ? 'Selected' : 'Choose this plan' }}</span>
85
+ </ng-template>
86
+ </app-segmented-control>
87
+ ```
88
+
89
+ Import `FilePickerComponent`, `ToggleComponent`, and `SegmentedControlComponent` in the consuming standalone component. Initialize `files` as `File[] = []`, notifications as a boolean, and plan as `Value | null`. `plans` uses the existing `ControlItemInterface[]`, for example `[{label: 'Basic', value: 'basic'}, {label: 'Pro', value: 'pro'}]`.
90
+
91
+ FilePicker selects local files and displays their names. Default selection is a single file; clearing or resetting to `[]` also clears the native picker, allowing the same file to be selected again. Cancelling the picker preserves the current selection. `accept` is a browser hint; validate files before upload in your application.
92
+
93
+ SegmentedControl selects one scalar value and defaults to `variant="segments"`. `allowEmpty` defaults to false, so clicking the selected item keeps it selected. Cards use the same keyboard behavior and can project `#item` with `$implicit: ControlItemInterface` and `selected: boolean` (`SegmentedControlItemContext`). Readonly disables interaction in Toggle and SegmentedControl.
94
+
95
+ ## Buttons, dialog and pagination
96
+
97
+ ```html
98
+ <app-button type="submit" [loading]="saving" [aria]="{'aria-label': 'Save changes'}">
99
+ <span>Save <strong>changes</strong></span>
100
+ </app-button>
101
+
102
+ <app-dialog [(visible)]="confirmVisible" header="Confirm changes">
103
+ <p>Apply these changes?</p>
104
+ <div dialogActions>
105
+ <app-button label="Cancel" (click)="confirmVisible = false" />
106
+ <app-button label="Apply" [loading]="saving" (click)="apply()" />
107
+ </div>
108
+ </app-dialog>
109
+
110
+ <app-pagination [(first)]="offset" [(rows)]="pageSize" [totalRecords]="total"
111
+ [rowsPerPageOptions]="[10, 25, 100]" (pageChange)="loadPage($event)" />
112
+ ```
113
+
114
+ Import `ButtonComponent`, `DialogComponent`, and `PaginationComponent`. Button projects nested content into its actual button and forwards its `aria` dictionary there. Loading shows the PrimeNG spinner, sets `aria-busy`, and disables activation; use an accessible name for icon-only buttons.
115
+
116
+ Dialog is modal, closes with Escape or its close button, traps focus and restores the opener's focus. Background clicks do not dismiss it; dragging and resizing are disabled. The application supplies all action buttons through `[dialogActions]` and controls `visible`.
117
+
118
+ Pagination defaults to `first = 0`, `rows = 10`, and `totalRecords = 0`. `first` is the record offset, and `page` in the exported `PaginatorState` event is zero-based. The component changes page state; the application loads or slices records.
119
+
120
+ ## Development checks
121
+
122
+ Run `npm run build` and `npm run check:ui`. The latter checks strict Angular consumer templates and the affected component/integration tests, including Toast. `npm run check:toast` remains available. The existing runner reuses Jest from the sibling `../angular-core` checkout; it must be present. Select individual specs with `node scripts/check-toast.cjs "projects/ui/src/lib/button/*.spec.ts"`.
123
+
124
+ ## Toast
125
+
126
+ Import the standalone host and place it once in your application's root template:
127
+
128
+ ```ts
129
+ import { Component, inject } from '@angular/core';
130
+ import { ToastComponent, ToastService } from 'springest';
131
+
132
+ @Component({
133
+ selector: 'app-root',
134
+ imports: [ToastComponent],
135
+ template: '<app-toast /><button (click)="save()">Save</button>',
136
+ })
137
+ export class AppComponent {
138
+ private readonly toast = inject(ToastService);
139
+
140
+ save(): void {
141
+ this.toast.mostrarToast('Saved', 'Your changes were saved', 'correct');
142
+ }
143
+ }
144
+ ```
145
+
146
+ `mostrarToast(message, description = null, variant = 'correct')` supports `correct`, `warn`, `error`, and `info`. A new notification replaces the current one and restarts its five-second lifetime. The host appears at the top right using your configured PrimeNG theme. Close it with its accessible close button or call `clear()`. `toast$` emits the current `ToastPayload` or `null`.
147
+
148
+ `ToastService` is provided in root. The host provides its own PrimeNG `MessageService`; no application provider is needed. `ToastPayload` and `ToastVariant` are also exported from `springest`.
149
+
150
+ ## License
151
+
152
+ MIT. See LICENSE.