@styloviz/input-field 0.1.1

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.
@@ -0,0 +1,341 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { ElementRef, OnInit, OnDestroy } from '@angular/core';
3
+ import { ControlValueAccessor, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
4
+
5
+ type InputType = 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'datetime-local' | 'time' | 'month' | 'week' | 'color';
6
+ type InputSize = 'sm' | 'md' | 'lg';
7
+ type InputVariant = 'default' | 'filled' | 'flushed';
8
+ type InputState = 'default' | 'error' | 'success' | 'warning';
9
+ type InputMode = 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
10
+ /**
11
+ * A single option for select / datalist suggestion.
12
+ */
13
+ interface InputOption {
14
+ value: string;
15
+ label: string;
16
+ disabled?: boolean;
17
+ }
18
+ /**
19
+ * InputField — A premium form input for dashboards.
20
+ *
21
+ * Features:
22
+ * - text, email, password, number, tel, url, date, time, color, …
23
+ * - Textarea mode (multiline) via `multiline` input
24
+ * - Select mode via `options` input
25
+ * - 3 visual variants: default (bordered) · filled · flushed (underline)
26
+ * - 3 sizes: sm · md · lg
27
+ * - 4 validation states: default · error · success · warning
28
+ * - Leading / trailing icon slots (SVG path)
29
+ * - Inline leading / trailing text addons (e.g. "https://", ".com")
30
+ * - Password show/hide toggle built-in
31
+ * - Character counter with optional max-length
32
+ * - Helper text and error message slots
33
+ * - Full ControlValueAccessor — works with `formControl`, `formControlName`, `ngModel`
34
+ * - Accessible: `<label>`, `aria-describedby`, `aria-invalid`, focus-visible ring
35
+ */
36
+ declare class SvInputFieldComponent implements ControlValueAccessor, Validator {
37
+ /** Current value. Use `[(value)]` for signal two-way binding. */
38
+ value: _angular_core.ModelSignal<string>;
39
+ /** Input type. @default 'text' */
40
+ type: _angular_core.InputSignal<InputType>;
41
+ /** Renders a `<textarea>` instead of `<input>`. @default false */
42
+ multiline: _angular_core.InputSignal<boolean>;
43
+ /**
44
+ * When set, renders a `<select>` element.
45
+ * Use `type` is ignored when options are provided.
46
+ */
47
+ options: _angular_core.InputSignal<InputOption[]>;
48
+ /** Label text shown above the input. */
49
+ label: _angular_core.InputSignal<string>;
50
+ /** Marks the label with a red asterisk. @default false */
51
+ required: _angular_core.InputSignal<boolean>;
52
+ /** Optional label (replaces asterisk with a soft "(optional)" tag). @default false */
53
+ optionalTag: _angular_core.InputSignal<boolean>;
54
+ /** Placeholder text. */
55
+ placeholder: _angular_core.InputSignal<string>;
56
+ /** Helper text shown below the input (hidden when `errorMessage` is set). */
57
+ hint: _angular_core.InputSignal<string>;
58
+ /** Error message — switches state to `error` automatically when non-empty. */
59
+ errorMessage: _angular_core.InputSignal<string>;
60
+ /** Success message — shown below when state is `success`. */
61
+ successMessage: _angular_core.InputSignal<string>;
62
+ /** Visual style. @default 'default' */
63
+ variant: _angular_core.InputSignal<InputVariant>;
64
+ /** Size. @default 'md' */
65
+ size: _angular_core.InputSignal<InputSize>;
66
+ /**
67
+ * Explicit validation state override.
68
+ * Automatically set to `'error'` when `errorMessage` is non-empty.
69
+ * @default 'default'
70
+ */
71
+ state: _angular_core.InputSignal<InputState>;
72
+ /** SVG `<path d="...">` for the leading (left) icon. */
73
+ leadingIconPath: _angular_core.InputSignal<string>;
74
+ /** SVG `<path d="...">` for the trailing (right) icon. */
75
+ trailingIconPath: _angular_core.InputSignal<string>;
76
+ /**
77
+ * Short text prepended inside the input (e.g. `'https://'`, `'$'`).
78
+ * Ignored when `leadingIconPath` is set.
79
+ */
80
+ leadingAddon: _angular_core.InputSignal<string>;
81
+ /**
82
+ * Short text appended inside the input (e.g. `'.com'`, `'USD'`).
83
+ * Ignored when `trailingIconPath` is set.
84
+ */
85
+ trailingAddon: _angular_core.InputSignal<string>;
86
+ /**
87
+ * Maximum character count shown as a counter below the input.
88
+ * Set to 0 to disable. @default 0
89
+ */
90
+ maxLength: _angular_core.InputSignal<number>;
91
+ /** Disable the input. @default false */
92
+ disabled: _angular_core.InputSignal<boolean>;
93
+ /** Read-only mode. @default false */
94
+ readonly: _angular_core.InputSignal<boolean>;
95
+ /** Show a loading spinner in the trailing position. @default false */
96
+ loading: _angular_core.InputSignal<boolean>;
97
+ /** id forwarded to the native input — required for external `<label for>`. */
98
+ inputId: _angular_core.InputSignal<string>;
99
+ /** name attribute for the native input. */
100
+ inputName: _angular_core.InputSignal<string>;
101
+ /** Additional CSS classes on the root wrapper. */
102
+ customClass: _angular_core.InputSignal<string>;
103
+ /**
104
+ * `autocomplete` token (e.g. 'email', 'name', 'current-password', 'one-time-code').
105
+ * Defaults to 'current-password' for password type, otherwise the browser default.
106
+ */
107
+ autocomplete: _angular_core.InputSignal<string>;
108
+ /** Virtual-keyboard hint for mobile (e.g. 'numeric', 'email', 'tel'). */
109
+ inputMode: _angular_core.InputSignal<"" | InputMode>;
110
+ /** Native validation regex (without anchors — anchored automatically). */
111
+ pattern: _angular_core.InputSignal<string>;
112
+ /** Minimum length used by the built-in Validator and native `minlength`. @default 0 */
113
+ minLength: _angular_core.InputSignal<number>;
114
+ /** Native `min` for number/date/range types. */
115
+ min: _angular_core.InputSignal<string | number | null>;
116
+ /** Native `max` for number/date/range types. */
117
+ max: _angular_core.InputSignal<string | number | null>;
118
+ /** Native `step` for number/date/range types. */
119
+ step: _angular_core.InputSignal<string | number | null>;
120
+ /** Native spellcheck toggle. null = browser default. */
121
+ spellcheck: _angular_core.InputSignal<boolean | null>;
122
+ /** Autofocus the control on render. @default false */
123
+ autofocus: _angular_core.InputSignal<boolean>;
124
+ /** Emits when the input gains focus. */
125
+ focused: _angular_core.OutputEmitterRef<FocusEvent>;
126
+ /** Emits when the input loses focus. */
127
+ blurred: _angular_core.OutputEmitterRef<FocusEvent>;
128
+ /** Emits when Enter is pressed. */
129
+ submitted: _angular_core.OutputEmitterRef<string>;
130
+ readonly isFocused: _angular_core.WritableSignal<boolean>;
131
+ readonly showPassword: _angular_core.WritableSignal<boolean>;
132
+ readonly inputRef: _angular_core.Signal<ElementRef<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement> | undefined>;
133
+ private _onChange;
134
+ private _onTouched;
135
+ /** Tracks disabled state set programmatically via formControl.disable(). */
136
+ private readonly _formDisabled;
137
+ /**
138
+ * Merged disabled state — true when either the [disabled] input or the
139
+ * parent FormControl is disabled. Use this everywhere instead of disabled().
140
+ */
141
+ readonly resolvedDisabled: _angular_core.Signal<boolean>;
142
+ writeValue(val: string): void;
143
+ registerOnChange(fn: (v: string) => void): void;
144
+ registerOnTouched(fn: () => void): void;
145
+ setDisabledState(isDisabled: boolean): void;
146
+ validate(_: AbstractControl): ValidationErrors | null;
147
+ onNativeChange(event: Event): void;
148
+ onFocus(e: FocusEvent): void;
149
+ onBlur(e: FocusEvent): void;
150
+ onKeydown(event: KeyboardEvent): void;
151
+ togglePassword(): void;
152
+ /** Stable unique fallback id so label + aria associations always work. */
153
+ private readonly _autoId;
154
+ /** Effective id used by the native control and its <label for>. */
155
+ readonly resolvedId: _angular_core.Signal<string>;
156
+ /** Id of the hint/error/success description element. */
157
+ readonly describedById: _angular_core.Signal<string>;
158
+ isSelect: _angular_core.Signal<boolean>;
159
+ isPassword: _angular_core.Signal<boolean>;
160
+ isColor: _angular_core.Signal<boolean>;
161
+ isFloating: _angular_core.Signal<boolean>;
162
+ labelIsFloated: _angular_core.Signal<boolean>;
163
+ resolvedType: _angular_core.Signal<string>;
164
+ resolvedState: _angular_core.Signal<InputState>;
165
+ charCount: _angular_core.Signal<number>;
166
+ showCounter: _angular_core.Signal<boolean>;
167
+ counterOver: _angular_core.Signal<boolean>;
168
+ showHint: _angular_core.Signal<boolean>;
169
+ showError: _angular_core.Signal<boolean>;
170
+ showSuccess: _angular_core.Signal<boolean>;
171
+ /** True when any below-field description (hint/error/success) is rendered. */
172
+ hasDescription: _angular_core.Signal<boolean>;
173
+ /** Resolved autocomplete token. Smart default for passwords, else explicit value. */
174
+ resolvedAutocomplete: _angular_core.Signal<string | null>;
175
+ hasLeading: _angular_core.Signal<boolean>;
176
+ hasTrailing: _angular_core.Signal<boolean>;
177
+ rootClasses: _angular_core.Signal<string>;
178
+ floatingLabelClasses: _angular_core.Signal<string>;
179
+ labelSizeClass: _angular_core.Signal<string>;
180
+ /** Outer track that wraps the native input + addons + icons. */
181
+ trackClasses: _angular_core.Signal<string>;
182
+ /** The native `<input>`, `<textarea>` or `<select>` element. */
183
+ nativeInputClasses: _angular_core.Signal<string>;
184
+ private sidepadding;
185
+ private vertPadding;
186
+ /** Vertical padding for multiline (textarea) — adds extra top space when floating. */
187
+ private multilineVertPadding;
188
+ private heightClass;
189
+ addonClasses: _angular_core.Signal<string>;
190
+ leadingAddonClasses: _angular_core.Signal<string>;
191
+ trailingAddonClasses: _angular_core.Signal<string>;
192
+ iconClass: _angular_core.Signal<string>;
193
+ iconPadClass: _angular_core.Signal<string>;
194
+ stateIconPath: _angular_core.Signal<string>;
195
+ stateIconColorClass: _angular_core.Signal<string>;
196
+ hintColorClass: _angular_core.Signal<string>;
197
+ focus(): void;
198
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SvInputFieldComponent, never>;
199
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SvInputFieldComponent, "sv-input-field", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "multiline": { "alias": "multiline"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "optionalTag": { "alias": "optionalTag"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "hint": { "alias": "hint"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "successMessage": { "alias": "successMessage"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "leadingIconPath": { "alias": "leadingIconPath"; "required": false; "isSignal": true; }; "trailingIconPath": { "alias": "trailingIconPath"; "required": false; "isSignal": true; }; "leadingAddon": { "alias": "leadingAddon"; "required": false; "isSignal": true; }; "trailingAddon": { "alias": "trailingAddon"; "required": false; "isSignal": true; }; "maxLength": { "alias": "maxLength"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "inputId": { "alias": "inputId"; "required": false; "isSignal": true; }; "inputName": { "alias": "inputName"; "required": false; "isSignal": true; }; "customClass": { "alias": "customClass"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "inputMode": { "alias": "inputMode"; "required": false; "isSignal": true; }; "pattern": { "alias": "pattern"; "required": false; "isSignal": true; }; "minLength": { "alias": "minLength"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "step": { "alias": "step"; "required": false; "isSignal": true; }; "spellcheck": { "alias": "spellcheck"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "focused": "focused"; "blurred": "blurred"; "submitted": "submitted"; }, never, never, true, never>;
200
+ }
201
+
202
+ /** A single cell in the calendar day grid. */
203
+ interface CalendarDay {
204
+ readonly date: Date;
205
+ readonly label: number;
206
+ readonly isCurrentMonth: boolean;
207
+ readonly isToday: boolean;
208
+ readonly isSelected: boolean;
209
+ readonly isDisabled: boolean;
210
+ readonly key: string;
211
+ }
212
+ /**
213
+ * SvDatePickerComponent — premium custom calendar date picker.
214
+ *
215
+ * The popover panel is rendered directly into `document.body` via a lightweight
216
+ * Angular embedded-view portal so it is completely outside any parent
217
+ * `overflow:hidden`, `overflow:auto`, or CSS `transform` containment.
218
+ * A capture-phase, RAF-throttled scroll listener keeps the panel anchored to
219
+ * the trigger — including when a nested scrollable ancestor scrolls, not just
220
+ * the window — and the horizontal position is clamped so it never renders
221
+ * partially outside the viewport. Resize closes the panel instead of
222
+ * repositioning it with stale coordinates.
223
+ *
224
+ * @example
225
+ * ```html
226
+ * <sv-date-picker label="Start Date" [(value)]="dateStr" minDate="2024-01-01" />
227
+ * ```
228
+ */
229
+ declare class SvDatePickerComponent implements OnInit, OnDestroy, ControlValueAccessor {
230
+ /** Two-way bindable YYYY-MM-DD date string. */
231
+ readonly value: _angular_core.ModelSignal<string>;
232
+ /** Label rendered above the trigger. */
233
+ readonly label: _angular_core.InputSignal<string>;
234
+ /** Placeholder shown when no date is selected. */
235
+ readonly placeholder: _angular_core.InputSignal<string>;
236
+ /** Minimum selectable date (YYYY-MM-DD). Cells before it are disabled. */
237
+ readonly minDate: _angular_core.InputSignal<string>;
238
+ /** Maximum selectable date (YYYY-MM-DD). Cells after it are disabled. */
239
+ readonly maxDate: _angular_core.InputSignal<string>;
240
+ /** Disables the trigger and prevents the popover from opening. */
241
+ readonly disabled: _angular_core.InputSignal<boolean>;
242
+ /** Shows a red asterisk in the label. */
243
+ readonly required: _angular_core.InputSignal<boolean>;
244
+ /** Explicit accessible name for the trigger (falls back to `label`). */
245
+ readonly ariaLabel: _angular_core.InputSignal<string>;
246
+ /** Emitted when the calendar popover opens. */
247
+ readonly opened: _angular_core.OutputEmitterRef<void>;
248
+ /** Emitted when the calendar popover closes. */
249
+ readonly closed: _angular_core.OutputEmitterRef<void>;
250
+ private _onChange;
251
+ private _onTouched;
252
+ private readonly _formDisabled;
253
+ /** Merged disabled — the `[disabled]` input OR a disabled parent FormControl. */
254
+ readonly resolvedDisabled: _angular_core.Signal<boolean>;
255
+ writeValue(v: string): void;
256
+ registerOnChange(fn: (v: string) => void): void;
257
+ registerOnTouched(fn: () => void): void;
258
+ setDisabledState(isDisabled: boolean): void;
259
+ /** Sets the value from a user gesture and notifies the form (change + touched). */
260
+ private commitValue;
261
+ /** The ng-template that holds the calendar panel markup. */
262
+ private readonly panelTpl;
263
+ readonly isOpen: _angular_core.WritableSignal<boolean>;
264
+ readonly viewYear: _angular_core.WritableSignal<number>;
265
+ readonly viewMonth: _angular_core.WritableSignal<number>;
266
+ readonly viewMode: _angular_core.WritableSignal<"days" | "months" | "years">;
267
+ readonly openAbove: _angular_core.WritableSignal<boolean>;
268
+ readonly alignRight: _angular_core.WritableSignal<boolean>;
269
+ /** YYYY-MM-DD of the keyboard-focused day cell (roving tabindex). */
270
+ readonly activeKey: _angular_core.WritableSignal<string>;
271
+ /**
272
+ * Inline style object applied to the panel.
273
+ * Uses position:fixed with exact viewport coords so the panel
274
+ * escapes all parent overflow and transform containment.
275
+ */
276
+ readonly panelStyle: _angular_core.WritableSignal<Record<string, string>>;
277
+ /** Container div appended to document.body while the panel is open. */
278
+ private portalEl;
279
+ /** Embedded view holding the panel template nodes. */
280
+ private portalView;
281
+ /**
282
+ * Capture-phase scroll listener — fires for ANY scrollable ancestor
283
+ * (not just the window), RAF-throttled so it never runs more than once
284
+ * per frame. Repositions the panel to keep it anchored to the trigger
285
+ * instead of drifting or closing (see dropdown-instruction.md §6).
286
+ */
287
+ private _rafId;
288
+ private readonly _scrollHandler;
289
+ readonly weekDays: readonly ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
290
+ readonly monthNames: readonly ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
291
+ readonly yearRange: _angular_core.Signal<number[]>;
292
+ readonly displayValue: _angular_core.Signal<string>;
293
+ readonly monthName: _angular_core.Signal<"January" | "February" | "March" | "April" | "May" | "June" | "July" | "August" | "September" | "October" | "November" | "December">;
294
+ /** Accessible name for the trigger — combines the field name with the selection. */
295
+ readonly triggerAriaLabel: _angular_core.Signal<string | null>;
296
+ readonly calendarDays: _angular_core.Signal<CalendarDay[]>;
297
+ /** The 42 calendar days grouped into 6 weeks for `role="row"` grid semantics. */
298
+ readonly calendarWeeks: _angular_core.Signal<CalendarDay[][]>;
299
+ private readonly el;
300
+ private readonly appRef;
301
+ ngOnInit(): void;
302
+ ngOnDestroy(): void;
303
+ onDocumentClick(event: MouseEvent): void;
304
+ onEscape(): void;
305
+ onResize(): void;
306
+ toggle(): void;
307
+ close(returnFocus?: boolean): void;
308
+ selectDay(day: CalendarDay): void;
309
+ /** Roving tabindex — only the active day cell is in the tab order. */
310
+ dayTabIndex(day: CalendarDay): number;
311
+ /** Arrow / Home / End / PageUp / PageDown navigation + Enter/Space to select. */
312
+ onDayKeydown(event: KeyboardEvent): void;
313
+ private focusActiveDayDeferred;
314
+ selectMonth(monthIndex: number): void;
315
+ selectYear(year: number): void;
316
+ prevPeriod(): void;
317
+ nextPeriod(): void;
318
+ goToToday(): void;
319
+ clearDate(): void;
320
+ toDateStr(d: Date): string;
321
+ private isDateDisabled;
322
+ isMonthDisabled(idx: number): boolean;
323
+ isYearDisabled(year: number): boolean;
324
+ isViewMonthSelected(idx: number): boolean;
325
+ isViewYearSelected(year: number): boolean;
326
+ headerLabel(): string;
327
+ /**
328
+ * Computes fixed-position coordinates from the trigger's current viewport
329
+ * rect. position:fixed is viewport-relative — getBoundingClientRect() gives
330
+ * exactly that, regardless of scroll position. Called on open and again on
331
+ * every scroll (see _scrollHandler) so the panel tracks the trigger instead
332
+ * of drifting away from it as the page (or a nested container) scrolls.
333
+ */
334
+ private _calcPos;
335
+ private destroyPortal;
336
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SvDatePickerComponent, never>;
337
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SvDatePickerComponent, "sv-date-picker", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "minDate": { "alias": "minDate"; "required": false; "isSignal": true; }; "maxDate": { "alias": "maxDate"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
338
+ }
339
+
340
+ export { SvDatePickerComponent, SvInputFieldComponent };
341
+ export type { CalendarDay, InputMode, InputOption, InputSize, InputState, InputType, InputVariant };