@cdevhub/ngx-tw 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 +21 -0
- package/README.md +134 -0
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +108 -0
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-alert.mjs +240 -0
- package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +287 -0
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +332 -0
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +452 -0
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-button.mjs +227 -0
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +417 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +232 -0
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +4482 -0
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-card.mjs +157 -0
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +1454 -0
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +593 -0
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +228 -0
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +510 -0
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +1721 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +721 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-core.mjs +861 -0
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +1558 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +1833 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +693 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +331 -0
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +289 -0
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +572 -0
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +36 -0
- package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +278 -0
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-input.mjs +355 -0
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-item.mjs +241 -0
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +433 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +691 -0
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +678 -0
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +335 -0
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +708 -0
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +319 -0
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs +1722 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-separator.mjs +115 -0
- package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +768 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +149 -0
- package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +1147 -0
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +346 -0
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs +186 -0
- package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-split.mjs +1082 -0
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +579 -0
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +443 -0
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +391 -0
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +315 -0
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-table.mjs +994 -0
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +508 -0
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +147 -0
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +178 -0
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +1344 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +1136 -0
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +1311 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +533 -0
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw.mjs +61 -0
- package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -0
- package/package.json +265 -0
- package/theme/_base.css +394 -0
- package/theme/_dark.css +510 -0
- package/theme/_high-contrast.css +290 -0
- package/theme/_semantic.css +317 -0
- package/theme/_typography.css +9 -0
- package/theme/index.css +54 -0
- package/types/cdevhub-ngx-tw-accordion.d.ts +48 -0
- package/types/cdevhub-ngx-tw-alert.d.ts +67 -0
- package/types/cdevhub-ngx-tw-avatar.d.ts +79 -0
- package/types/cdevhub-ngx-tw-badge.d.ts +94 -0
- package/types/cdevhub-ngx-tw-breadcrumbs.d.ts +227 -0
- package/types/cdevhub-ngx-tw-button.d.ts +74 -0
- package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +200 -0
- package/types/cdevhub-ngx-tw-calendar-testing.d.ts +113 -0
- package/types/cdevhub-ngx-tw-calendar.d.ts +1704 -0
- package/types/cdevhub-ngx-tw-card.d.ts +48 -0
- package/types/cdevhub-ngx-tw-carousel.d.ts +406 -0
- package/types/cdevhub-ngx-tw-checkbox.d.ts +136 -0
- package/types/cdevhub-ngx-tw-code-block.d.ts +93 -0
- package/types/cdevhub-ngx-tw-collapsible.d.ts +151 -0
- package/types/cdevhub-ngx-tw-combobox.d.ts +389 -0
- package/types/cdevhub-ngx-tw-command-palette.d.ts +215 -0
- package/types/cdevhub-ngx-tw-core.d.ts +719 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +317 -0
- package/types/cdevhub-ngx-tw-date-range-picker.d.ts +313 -0
- package/types/cdevhub-ngx-tw-dialog.d.ts +303 -0
- package/types/cdevhub-ngx-tw-empty-state.d.ts +104 -0
- package/types/cdevhub-ngx-tw-flip-card.d.ts +95 -0
- package/types/cdevhub-ngx-tw-form-field.d.ts +210 -0
- package/types/cdevhub-ngx-tw-icon-lucide.d.ts +29 -0
- package/types/cdevhub-ngx-tw-icon.d.ts +134 -0
- package/types/cdevhub-ngx-tw-input.d.ts +110 -0
- package/types/cdevhub-ngx-tw-item.d.ts +70 -0
- package/types/cdevhub-ngx-tw-menu.d.ts +99 -0
- package/types/cdevhub-ngx-tw-paginator.d.ts +305 -0
- package/types/cdevhub-ngx-tw-popover.d.ts +157 -0
- package/types/cdevhub-ngx-tw-progress-bar.d.ts +100 -0
- package/types/cdevhub-ngx-tw-radio.d.ts +174 -0
- package/types/cdevhub-ngx-tw-segmented-control.d.ts +66 -0
- package/types/cdevhub-ngx-tw-select.d.ts +384 -0
- package/types/cdevhub-ngx-tw-separator.d.ts +28 -0
- package/types/cdevhub-ngx-tw-sheet.d.ts +335 -0
- package/types/cdevhub-ngx-tw-skeleton.d.ts +52 -0
- package/types/cdevhub-ngx-tw-slider.d.ts +258 -0
- package/types/cdevhub-ngx-tw-sort.d.ts +136 -0
- package/types/cdevhub-ngx-tw-spinner.d.ts +50 -0
- package/types/cdevhub-ngx-tw-split.d.ts +265 -0
- package/types/cdevhub-ngx-tw-stat.d.ts +140 -0
- package/types/cdevhub-ngx-tw-stepper.d.ts +127 -0
- package/types/cdevhub-ngx-tw-switch.d.ts +88 -0
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +107 -0
- package/types/cdevhub-ngx-tw-table.d.ts +479 -0
- package/types/cdevhub-ngx-tw-tabs.d.ts +121 -0
- package/types/cdevhub-ngx-tw-textarea.d.ts +62 -0
- package/types/cdevhub-ngx-tw-theme.d.ts +106 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +303 -0
- package/types/cdevhub-ngx-tw-timeline.d.ts +278 -0
- package/types/cdevhub-ngx-tw-toast.d.ts +388 -0
- package/types/cdevhub-ngx-tw-tooltip.d.ts +95 -0
- package/types/cdevhub-ngx-tw.d.ts +49 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, ElementRef, DestroyRef, input, booleanAttribute, signal, computed, isSignal, effect, untracked, isDevMode, Directive } from '@angular/core';
|
|
3
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { NgControl, NgForm, FormGroupDirective, Validators } from '@angular/forms';
|
|
5
|
+
import { FocusMonitor } from '@angular/cdk/a11y';
|
|
6
|
+
import { AutofillMonitor } from '@angular/cdk/text-field';
|
|
7
|
+
import { Platform } from '@angular/cdk/platform';
|
|
8
|
+
import { merge } from 'rxjs';
|
|
9
|
+
import { tv } from 'tailwind-variants';
|
|
10
|
+
import { TW_ERROR_STATE_MATCHER } from '@cdevhub/ngx-tw/core';
|
|
11
|
+
import { FormFieldControl, FormFieldComponent, TW_FORM_FIELD_CONTROL } from '@cdevhub/ngx-tw/form-field';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Extension point for directives that wrap an `<input twInput>` and need to
|
|
15
|
+
* own how its value is read and written. The directive's `value` property can
|
|
16
|
+
* be a plain object slot (`{ value: T }`) or a `WritableSignal<T>`. Mirrors
|
|
17
|
+
* Angular Material's `MAT_INPUT_VALUE_ACCESSOR`.
|
|
18
|
+
*/
|
|
19
|
+
const TW_INPUT_VALUE_ACCESSOR = new InjectionToken('TW_INPUT_VALUE_ACCESSOR');
|
|
20
|
+
const INVALID_INPUT_TYPES = new Set([
|
|
21
|
+
'button',
|
|
22
|
+
'checkbox',
|
|
23
|
+
'file',
|
|
24
|
+
'hidden',
|
|
25
|
+
'image',
|
|
26
|
+
'radio',
|
|
27
|
+
'range',
|
|
28
|
+
'reset',
|
|
29
|
+
'submit',
|
|
30
|
+
]);
|
|
31
|
+
const NEVER_EMPTY_TYPES = new Set([
|
|
32
|
+
'date',
|
|
33
|
+
'datetime-local',
|
|
34
|
+
'month',
|
|
35
|
+
'time',
|
|
36
|
+
'week',
|
|
37
|
+
'color',
|
|
38
|
+
]);
|
|
39
|
+
const inputVariants = tv({
|
|
40
|
+
base: 'block w-full bg-transparent text-fg placeholder:text-fg-subtle outline-none',
|
|
41
|
+
variants: {
|
|
42
|
+
inFormField: {
|
|
43
|
+
true: 'border-0 p-0 shadow-none focus:outline-none focus-visible:outline-none',
|
|
44
|
+
false: 'rounded-md border border-border transition-[color,border-color,box-shadow] duration-normal motion-reduce:transition-none hover:border-border-strong focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500',
|
|
45
|
+
},
|
|
46
|
+
size: {
|
|
47
|
+
xs: '',
|
|
48
|
+
sm: '',
|
|
49
|
+
md: '',
|
|
50
|
+
lg: '',
|
|
51
|
+
xl: '',
|
|
52
|
+
},
|
|
53
|
+
errorState: {
|
|
54
|
+
true: '',
|
|
55
|
+
false: '',
|
|
56
|
+
},
|
|
57
|
+
disabled: {
|
|
58
|
+
true: 'opacity-50 cursor-not-allowed',
|
|
59
|
+
false: '',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
compoundVariants: [
|
|
63
|
+
// Standalone density × size — inline padding + font scale.
|
|
64
|
+
{ inFormField: false, size: 'xs', class: 'px-2 py-1 text-xs' },
|
|
65
|
+
{ inFormField: false, size: 'sm', class: 'px-3 py-1.5 text-sm' },
|
|
66
|
+
{ inFormField: false, size: 'md', class: 'px-4 py-2 text-sm' },
|
|
67
|
+
{ inFormField: false, size: 'lg', class: 'px-5 py-2.5 text-base' },
|
|
68
|
+
{ inFormField: false, size: 'xl', class: 'px-6 py-3 text-base' },
|
|
69
|
+
// Standalone error state — colored border and focus ring.
|
|
70
|
+
{
|
|
71
|
+
inFormField: false,
|
|
72
|
+
errorState: true,
|
|
73
|
+
class: 'border-error-500 focus-visible:outline-error-500',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
defaultVariants: {
|
|
77
|
+
inFormField: false,
|
|
78
|
+
size: 'md',
|
|
79
|
+
errorState: false,
|
|
80
|
+
disabled: false,
|
|
81
|
+
},
|
|
82
|
+
}, { twMerge: true });
|
|
83
|
+
let nextInputId = 0;
|
|
84
|
+
/**
|
|
85
|
+
* Adapts a native `<input>` or `<textarea>` into an ngx-tw form-field-compatible
|
|
86
|
+
* control. Works standalone (applies its own border and focus styling) or
|
|
87
|
+
* inside a `<tw-form-field>` (strips its chrome and provides signals the
|
|
88
|
+
* form-field uses to float the label and wire `aria-describedby`).
|
|
89
|
+
*
|
|
90
|
+
* Extension points:
|
|
91
|
+
* - Implement a completely custom control → extend {@link FormFieldControl}
|
|
92
|
+
* and provide under `TW_FORM_FIELD_CONTROL`.
|
|
93
|
+
* - Swap value storage for an existing `<input twInput>` (masked input,
|
|
94
|
+
* date parser, etc.) → provide {@link TW_INPUT_VALUE_ACCESSOR}.
|
|
95
|
+
* - Change when errors show → override {@link TW_ERROR_STATE_MATCHER} at any
|
|
96
|
+
* injector level, or pass `errorStateMatcher` per instance.
|
|
97
|
+
*
|
|
98
|
+
* Forms integration is inherited: Angular's native value accessors attach to
|
|
99
|
+
* the underlying element, so the directive works with template-driven,
|
|
100
|
+
* reactive, and signal-based forms without additional glue.
|
|
101
|
+
*/
|
|
102
|
+
class InputDirective extends FormFieldControl {
|
|
103
|
+
elementRef = inject(ElementRef);
|
|
104
|
+
focusMonitor = inject(FocusMonitor);
|
|
105
|
+
autofillMonitor = inject(AutofillMonitor);
|
|
106
|
+
platform = inject(Platform);
|
|
107
|
+
destroyRef = inject(DestroyRef);
|
|
108
|
+
formField = inject(FormFieldComponent, { optional: true });
|
|
109
|
+
ngControl = inject(NgControl, {
|
|
110
|
+
optional: true,
|
|
111
|
+
self: true,
|
|
112
|
+
});
|
|
113
|
+
parentForm = inject(NgForm, { optional: true });
|
|
114
|
+
parentFormGroup = inject(FormGroupDirective, {
|
|
115
|
+
optional: true,
|
|
116
|
+
});
|
|
117
|
+
defaultMatcher = inject(TW_ERROR_STATE_MATCHER);
|
|
118
|
+
valueAccessor = inject(TW_INPUT_VALUE_ACCESSOR, {
|
|
119
|
+
optional: true,
|
|
120
|
+
self: true,
|
|
121
|
+
});
|
|
122
|
+
/** @internal */
|
|
123
|
+
_isTextarea = this.elementRef.nativeElement.tagName.toLowerCase() === 'textarea';
|
|
124
|
+
/** Contract value — `'input'` for `<input>` and `'textarea'` for `<textarea>`. Form-field appends it as `tw-form-field-type-*` for styling hooks. */
|
|
125
|
+
controlType = this._isTextarea ? 'textarea' : 'input';
|
|
126
|
+
uid = `tw-input-${nextInputId++}`;
|
|
127
|
+
/** Id on the underlying element. Auto-generated as `tw-input-N` when not provided. Used by the form-field's `<label for>` attribute. */
|
|
128
|
+
idInput = input(undefined, { ...(ngDevMode ? { debugName: "idInput" } : /* istanbul ignore next */ {}), alias: 'id' });
|
|
129
|
+
/** Native HTML input `type`. Defaults to `'text'`. Dev-mode throws on unsupported values (`checkbox`, `radio`, `submit`, etc.) — use the dedicated component instead. Ignored on `<textarea>`. */
|
|
130
|
+
type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
|
|
131
|
+
/** Density of a standalone field. Maps to the inline-padding scale (`px-2 py-1` xs … `px-6 py-3` xl) and font scale (`text-xs` xs, `text-sm` sm/md, `text-base` lg/xl). Ignored inside a `<tw-form-field>` — the wrapper's `size` carries density. Defaults to `'md'`. */
|
|
132
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
133
|
+
/** Disables the control. Also reflects `ngControl.disabled` when the element is bound to a reactive form. Defaults to `false`. */
|
|
134
|
+
disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled',
|
|
135
|
+
transform: booleanAttribute });
|
|
136
|
+
/** Marks the control as required. Also inferred from `Validators.required` on a bound `NgControl`. Defaults to `false`. */
|
|
137
|
+
requiredInput = input(false, { ...(ngDevMode ? { debugName: "requiredInput" } : /* istanbul ignore next */ {}), alias: 'required',
|
|
138
|
+
transform: booleanAttribute });
|
|
139
|
+
/** Makes the control read-only (native `readonly` attribute). Defaults to `false`. */
|
|
140
|
+
readonlyInput = input(false, { ...(ngDevMode ? { debugName: "readonlyInput" } : /* istanbul ignore next */ {}), alias: 'readonly',
|
|
141
|
+
transform: booleanAttribute });
|
|
142
|
+
/** Per-instance override of the {@link ErrorStateMatcher}. When omitted, the directive uses the `TW_ERROR_STATE_MATCHER` token's value. */
|
|
143
|
+
errorStateMatcher = input(undefined, ...(ngDevMode ? [{ debugName: "errorStateMatcher" }] : /* istanbul ignore next */ []));
|
|
144
|
+
/** Consumer-supplied `aria-describedby` ids. The form-field preserves these when merging hint and error ids. Alias: `aria-describedby`. */
|
|
145
|
+
userAriaDescribedBy = input(undefined, { ...(ngDevMode ? { debugName: "userAriaDescribedBy" } : /* istanbul ignore next */ {}), alias: 'aria-describedby' });
|
|
146
|
+
/** Consumer-supplied `aria-labelledby` ids. The form-field preserves these when merging in the projected label id. Alias: `aria-labelledby`. */
|
|
147
|
+
userAriaLabelledby = input(undefined, { ...(ngDevMode ? { debugName: "userAriaLabelledby" } : /* istanbul ignore next */ {}), alias: 'aria-labelledby' });
|
|
148
|
+
// ── Internal state signals ──
|
|
149
|
+
_value = signal(this._readInitialValue(), ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
|
|
150
|
+
_focused = signal(false, ...(ngDevMode ? [{ debugName: "_focused" }] : /* istanbul ignore next */ []));
|
|
151
|
+
_autofilled = signal(false, ...(ngDevMode ? [{ debugName: "_autofilled" }] : /* istanbul ignore next */ []));
|
|
152
|
+
_ngControlRev = signal(0, ...(ngDevMode ? [{ debugName: "_ngControlRev" }] : /* istanbul ignore next */ []));
|
|
153
|
+
_formSubmitRev = signal(0, ...(ngDevMode ? [{ debugName: "_formSubmitRev" }] : /* istanbul ignore next */ []));
|
|
154
|
+
// ── FormFieldControl signals ──
|
|
155
|
+
/** @internal */
|
|
156
|
+
id = computed(() => this.idInput() ?? this.uid, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
157
|
+
/** @internal */
|
|
158
|
+
value = computed(() => this._value() || null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
159
|
+
/** @internal */
|
|
160
|
+
focused = this._focused.asReadonly();
|
|
161
|
+
/** @internal */
|
|
162
|
+
empty = computed(() => {
|
|
163
|
+
if (!this._isTextarea && NEVER_EMPTY_TYPES.has(this.type())) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
return !this._value() && !this._autofilled();
|
|
167
|
+
}, ...(ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []));
|
|
168
|
+
/** @internal */
|
|
169
|
+
disabled = computed(() => {
|
|
170
|
+
this._ngControlRev();
|
|
171
|
+
return this.disabledInput() || !!this.ngControl?.disabled;
|
|
172
|
+
}, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
173
|
+
/** @internal */
|
|
174
|
+
required = computed(() => {
|
|
175
|
+
this._ngControlRev();
|
|
176
|
+
if (this.requiredInput())
|
|
177
|
+
return true;
|
|
178
|
+
return !!this.ngControl?.control?.hasValidator(Validators.required);
|
|
179
|
+
}, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
180
|
+
/** @internal */
|
|
181
|
+
errorState = computed(() => {
|
|
182
|
+
this._ngControlRev();
|
|
183
|
+
this._formSubmitRev();
|
|
184
|
+
this._focused();
|
|
185
|
+
const matcher = this.errorStateMatcher() ?? this.defaultMatcher;
|
|
186
|
+
const form = this.parentFormGroup ??
|
|
187
|
+
this.parentForm;
|
|
188
|
+
return matcher.isErrorState(this.ngControl?.control ?? null, form);
|
|
189
|
+
}, ...(ngDevMode ? [{ debugName: "errorState" }] : /* istanbul ignore next */ []));
|
|
190
|
+
/** @internal Active validation errors map from the bound `NgControl` (or `null` when the control reports none / is unbound). Recomputes on every `_ngControlRev` tick so `[twError match="…"]` reacts to validator transitions, including rules that fire/clear without flipping `VALID`/`INVALID`. */
|
|
191
|
+
errors = computed(() => {
|
|
192
|
+
this._ngControlRev();
|
|
193
|
+
return this.ngControl?.control?.errors ?? null;
|
|
194
|
+
}, ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
195
|
+
/** @internal */
|
|
196
|
+
classes = computed(() => inputVariants({
|
|
197
|
+
inFormField: !!this.formField,
|
|
198
|
+
size: this.size(),
|
|
199
|
+
errorState: this.errorState(),
|
|
200
|
+
disabled: this.disabled(),
|
|
201
|
+
}), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
202
|
+
constructor() {
|
|
203
|
+
super();
|
|
204
|
+
this.focusMonitor
|
|
205
|
+
.monitor(this.elementRef)
|
|
206
|
+
.pipe(takeUntilDestroyed())
|
|
207
|
+
.subscribe((origin) => {
|
|
208
|
+
const wasFocused = this._focused();
|
|
209
|
+
this._focused.set(!!origin);
|
|
210
|
+
if (wasFocused && !origin) {
|
|
211
|
+
// Blur often flips `touched` on the bound `NgControl`; bump the
|
|
212
|
+
// revision signal so `errorState` recomputes.
|
|
213
|
+
this._ngControlRev.update((n) => n + 1);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
this.destroyRef.onDestroy(() => this.focusMonitor.stopMonitoring(this.elementRef));
|
|
217
|
+
// Keep `_value` in sync when the accessor's value is itself a signal.
|
|
218
|
+
if (this.valueAccessor && isSignal(this.valueAccessor.value)) {
|
|
219
|
+
effect(() => {
|
|
220
|
+
const v = this.valueAccessor.value();
|
|
221
|
+
untracked(() => this._value.set(this._stringify(v)));
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
// Sync the `readonly` input to the native attribute.
|
|
225
|
+
effect(() => {
|
|
226
|
+
const el = this.elementRef.nativeElement;
|
|
227
|
+
if (this.readonlyInput()) {
|
|
228
|
+
el.setAttribute('readonly', 'true');
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
el.removeAttribute('readonly');
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
// Validate the input type in dev mode.
|
|
235
|
+
effect(() => {
|
|
236
|
+
const t = this.type();
|
|
237
|
+
if (isDevMode() &&
|
|
238
|
+
!this._isTextarea &&
|
|
239
|
+
INVALID_INPUT_TYPES.has(t)) {
|
|
240
|
+
throw new Error(`tw-input: unsupported input type "${t}". Use a dedicated ngx-tw component for that control.`);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
ngOnInit() {
|
|
245
|
+
if (this.platform.isBrowser) {
|
|
246
|
+
this.autofillMonitor
|
|
247
|
+
.monitor(this.elementRef.nativeElement)
|
|
248
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
249
|
+
.subscribe((event) => this._autofilled.set(event.isAutofilled));
|
|
250
|
+
this.destroyRef.onDestroy(() => this.autofillMonitor.stopMonitoring(this.elementRef.nativeElement));
|
|
251
|
+
}
|
|
252
|
+
// NgControl's `control` is set by the parent `FormControl*` directive's
|
|
253
|
+
// own `ngOnChanges`, which runs before children's `ngOnInit`. Subscribe
|
|
254
|
+
// here so `statusChanges`/`valueChanges` are actually available.
|
|
255
|
+
const ctrl = this.ngControl?.control;
|
|
256
|
+
if (ctrl) {
|
|
257
|
+
const streams = [ctrl.statusChanges, ctrl.valueChanges].filter((s) => !!s);
|
|
258
|
+
if (streams.length) {
|
|
259
|
+
merge(...streams)
|
|
260
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
261
|
+
.subscribe(() => this._ngControlRev.update((n) => n + 1));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const submit = this.parentFormGroup?.ngSubmit ?? this.parentForm?.ngSubmit;
|
|
265
|
+
if (submit) {
|
|
266
|
+
submit
|
|
267
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
268
|
+
.subscribe(() => this._formSubmitRev.update((n) => n + 1));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/** Moves focus to the underlying element. */
|
|
272
|
+
focus(options) {
|
|
273
|
+
this.elementRef.nativeElement.focus(options);
|
|
274
|
+
}
|
|
275
|
+
/** @internal Called when `<tw-form-field>` has computed the merged describedby ids. */
|
|
276
|
+
setDescribedByIds(ids) {
|
|
277
|
+
const el = this.elementRef.nativeElement;
|
|
278
|
+
if (ids.length) {
|
|
279
|
+
el.setAttribute('aria-describedby', ids.join(' '));
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
el.removeAttribute('aria-describedby');
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/** @internal Called when `<tw-form-field>` has computed the merged labelledby ids. The native `<label for>` association covers most cases; this attribute is mainly useful when a consumer also supplies `aria-labelledby` for an external label. */
|
|
286
|
+
setLabelledByIds(ids) {
|
|
287
|
+
const el = this.elementRef.nativeElement;
|
|
288
|
+
// Skip applying the projected label id by itself — native `<label for=>` already wires it
|
|
289
|
+
// and a redundant `aria-labelledby` can cause double-announcements in some screen readers.
|
|
290
|
+
// Only apply when the consumer supplied additional ids via `aria-labelledby`.
|
|
291
|
+
const userIds = this.userAriaLabelledby();
|
|
292
|
+
if (userIds || (ids.length > 1)) {
|
|
293
|
+
el.setAttribute('aria-labelledby', ids.join(' '));
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
el.removeAttribute('aria-labelledby');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/** @internal Called when the form-field container is clicked. */
|
|
300
|
+
onContainerClick(_event) {
|
|
301
|
+
if (!this._focused()) {
|
|
302
|
+
this.focus();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/** @internal */
|
|
306
|
+
_onInput() {
|
|
307
|
+
this._value.set(this._currentValue());
|
|
308
|
+
}
|
|
309
|
+
_currentValue() {
|
|
310
|
+
if (this.valueAccessor) {
|
|
311
|
+
const v = this.valueAccessor.value;
|
|
312
|
+
if (isSignal(v))
|
|
313
|
+
return this._stringify(v());
|
|
314
|
+
return this._stringify(v);
|
|
315
|
+
}
|
|
316
|
+
return this.elementRef.nativeElement.value;
|
|
317
|
+
}
|
|
318
|
+
_readInitialValue() {
|
|
319
|
+
const el = this.elementRef.nativeElement;
|
|
320
|
+
return el.value ?? '';
|
|
321
|
+
}
|
|
322
|
+
_stringify(v) {
|
|
323
|
+
return v === null || v === undefined ? '' : String(v);
|
|
324
|
+
}
|
|
325
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: InputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
326
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: InputDirective, isStandalone: true, selector: "input[twInput], textarea[twInput]", inputs: { idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, requiredInput: { classPropertyName: "requiredInput", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, readonlyInput: { classPropertyName: "readonlyInput", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: true, isRequired: false, transformFunction: null }, userAriaDescribedBy: { classPropertyName: "userAriaDescribedBy", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, userAriaLabelledby: { classPropertyName: "userAriaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "_onInput()" }, properties: { "class": "classes()", "attr.id": "id()", "attr.type": "_isTextarea ? null : type()", "disabled": "disabled()", "attr.aria-invalid": "errorState() || null", "attr.aria-required": "required() || null" } }, providers: [
|
|
327
|
+
{ provide: TW_FORM_FIELD_CONTROL, useExisting: InputDirective },
|
|
328
|
+
], exportAs: ["twInput"], usesInheritance: true, ngImport: i0 });
|
|
329
|
+
}
|
|
330
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: InputDirective, decorators: [{
|
|
331
|
+
type: Directive,
|
|
332
|
+
args: [{
|
|
333
|
+
selector: 'input[twInput], textarea[twInput]',
|
|
334
|
+
exportAs: 'twInput',
|
|
335
|
+
providers: [
|
|
336
|
+
{ provide: TW_FORM_FIELD_CONTROL, useExisting: InputDirective },
|
|
337
|
+
],
|
|
338
|
+
host: {
|
|
339
|
+
'[class]': 'classes()',
|
|
340
|
+
'[attr.id]': 'id()',
|
|
341
|
+
'[attr.type]': '_isTextarea ? null : type()',
|
|
342
|
+
'[disabled]': 'disabled()',
|
|
343
|
+
'[attr.aria-invalid]': 'errorState() || null',
|
|
344
|
+
'[attr.aria-required]': 'required() || null',
|
|
345
|
+
'(input)': '_onInput()',
|
|
346
|
+
},
|
|
347
|
+
}]
|
|
348
|
+
}], ctorParameters: () => [], propDecorators: { idInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], requiredInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], readonlyInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], errorStateMatcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorStateMatcher", required: false }] }], userAriaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-describedby", required: false }] }], userAriaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }] } });
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Generated bundle index. Do not edit.
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
export { InputDirective, TW_INPUT_VALUE_ACCESSOR };
|
|
355
|
+
//# sourceMappingURL=cdevhub-ngx-tw-input.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-input.mjs","sources":["../../../projects/ngx-tw/input/input.ts","../../../projects/ngx-tw/input/cdevhub-ngx-tw-input.ts"],"sourcesContent":["import {\n booleanAttribute,\n computed,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n inject,\n InjectionToken,\n input,\n isDevMode,\n isSignal,\n type OnInit,\n signal,\n type Signal,\n untracked,\n type WritableSignal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n FormGroupDirective,\n NgControl,\n NgForm,\n Validators,\n} from '@angular/forms';\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { AutofillMonitor } from '@angular/cdk/text-field';\nimport { Platform } from '@angular/cdk/platform';\nimport { merge } from 'rxjs';\nimport { tv } from 'tailwind-variants';\nimport {\n type ErrorStateMatcher,\n TW_ERROR_STATE_MATCHER,\n type TwFormSubmitted,\n type TwSize,\n} from '@cdevhub/ngx-tw/core';\nimport {\n FormFieldComponent,\n FormFieldControl,\n TW_FORM_FIELD_CONTROL,\n} from '@cdevhub/ngx-tw/form-field';\n\n/**\n * Extension point for directives that wrap an `<input twInput>` and need to\n * own how its value is read and written. The directive's `value` property can\n * be a plain object slot (`{ value: T }`) or a `WritableSignal<T>`. Mirrors\n * Angular Material's `MAT_INPUT_VALUE_ACCESSOR`.\n */\nexport const TW_INPUT_VALUE_ACCESSOR = new InjectionToken<{\n value: unknown | WritableSignal<unknown>;\n}>('TW_INPUT_VALUE_ACCESSOR');\n\nconst INVALID_INPUT_TYPES = new Set([\n 'button',\n 'checkbox',\n 'file',\n 'hidden',\n 'image',\n 'radio',\n 'range',\n 'reset',\n 'submit',\n]);\n\nconst NEVER_EMPTY_TYPES = new Set([\n 'date',\n 'datetime-local',\n 'month',\n 'time',\n 'week',\n 'color',\n]);\n\nconst inputVariants = tv(\n {\n base: 'block w-full bg-transparent text-fg placeholder:text-fg-subtle outline-none',\n variants: {\n inFormField: {\n true: 'border-0 p-0 shadow-none focus:outline-none focus-visible:outline-none',\n false:\n 'rounded-md border border-border transition-[color,border-color,box-shadow] duration-normal motion-reduce:transition-none hover:border-border-strong focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500',\n },\n size: {\n xs: '',\n sm: '',\n md: '',\n lg: '',\n xl: '',\n },\n errorState: {\n true: '',\n false: '',\n },\n disabled: {\n true: 'opacity-50 cursor-not-allowed',\n false: '',\n },\n },\n compoundVariants: [\n // Standalone density × size — inline padding + font scale.\n { inFormField: false, size: 'xs', class: 'px-2 py-1 text-xs' },\n { inFormField: false, size: 'sm', class: 'px-3 py-1.5 text-sm' },\n { inFormField: false, size: 'md', class: 'px-4 py-2 text-sm' },\n { inFormField: false, size: 'lg', class: 'px-5 py-2.5 text-base' },\n { inFormField: false, size: 'xl', class: 'px-6 py-3 text-base' },\n // Standalone error state — colored border and focus ring.\n {\n inFormField: false,\n errorState: true,\n class: 'border-error-500 focus-visible:outline-error-500',\n },\n ],\n defaultVariants: {\n inFormField: false,\n size: 'md',\n errorState: false,\n disabled: false,\n },\n },\n { twMerge: true },\n);\n\nlet nextInputId = 0;\n\n/**\n * Adapts a native `<input>` or `<textarea>` into an ngx-tw form-field-compatible\n * control. Works standalone (applies its own border and focus styling) or\n * inside a `<tw-form-field>` (strips its chrome and provides signals the\n * form-field uses to float the label and wire `aria-describedby`).\n *\n * Extension points:\n * - Implement a completely custom control → extend {@link FormFieldControl}\n * and provide under `TW_FORM_FIELD_CONTROL`.\n * - Swap value storage for an existing `<input twInput>` (masked input,\n * date parser, etc.) → provide {@link TW_INPUT_VALUE_ACCESSOR}.\n * - Change when errors show → override {@link TW_ERROR_STATE_MATCHER} at any\n * injector level, or pass `errorStateMatcher` per instance.\n *\n * Forms integration is inherited: Angular's native value accessors attach to\n * the underlying element, so the directive works with template-driven,\n * reactive, and signal-based forms without additional glue.\n */\n@Directive({\n selector: 'input[twInput], textarea[twInput]',\n exportAs: 'twInput',\n providers: [\n { provide: TW_FORM_FIELD_CONTROL, useExisting: InputDirective },\n ],\n host: {\n '[class]': 'classes()',\n '[attr.id]': 'id()',\n '[attr.type]': '_isTextarea ? null : type()',\n '[disabled]': 'disabled()',\n '[attr.aria-invalid]': 'errorState() || null',\n '[attr.aria-required]': 'required() || null',\n '(input)': '_onInput()',\n },\n})\nexport class InputDirective\n extends FormFieldControl<string>\n implements OnInit\n{\n private readonly elementRef = inject<\n ElementRef<HTMLInputElement | HTMLTextAreaElement>\n >(ElementRef);\n private readonly focusMonitor = inject(FocusMonitor);\n private readonly autofillMonitor = inject(AutofillMonitor);\n private readonly platform = inject(Platform);\n private readonly destroyRef = inject(DestroyRef);\n private readonly formField = inject(FormFieldComponent, { optional: true });\n private readonly ngControl = inject(NgControl, {\n optional: true,\n self: true,\n });\n private readonly parentForm = inject(NgForm, { optional: true });\n private readonly parentFormGroup = inject(FormGroupDirective, {\n optional: true,\n });\n private readonly defaultMatcher = inject(TW_ERROR_STATE_MATCHER);\n private readonly valueAccessor = inject(TW_INPUT_VALUE_ACCESSOR, {\n optional: true,\n self: true,\n });\n\n /** @internal */\n readonly _isTextarea =\n this.elementRef.nativeElement.tagName.toLowerCase() === 'textarea';\n\n /** Contract value — `'input'` for `<input>` and `'textarea'` for `<textarea>`. Form-field appends it as `tw-form-field-type-*` for styling hooks. */\n readonly controlType: string = this._isTextarea ? 'textarea' : 'input';\n\n private readonly uid = `tw-input-${nextInputId++}`;\n\n /** Id on the underlying element. Auto-generated as `tw-input-N` when not provided. Used by the form-field's `<label for>` attribute. */\n readonly idInput = input<string | undefined>(undefined, { alias: 'id' });\n\n /** Native HTML input `type`. Defaults to `'text'`. Dev-mode throws on unsupported values (`checkbox`, `radio`, `submit`, etc.) — use the dedicated component instead. Ignored on `<textarea>`. */\n readonly type = input<string>('text');\n\n /** Density of a standalone field. Maps to the inline-padding scale (`px-2 py-1` xs … `px-6 py-3` xl) and font scale (`text-xs` xs, `text-sm` sm/md, `text-base` lg/xl). Ignored inside a `<tw-form-field>` — the wrapper's `size` carries density. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Disables the control. Also reflects `ngControl.disabled` when the element is bound to a reactive form. Defaults to `false`. */\n readonly disabledInput = input<boolean, unknown>(false, {\n alias: 'disabled',\n transform: booleanAttribute,\n });\n\n /** Marks the control as required. Also inferred from `Validators.required` on a bound `NgControl`. Defaults to `false`. */\n readonly requiredInput = input<boolean, unknown>(false, {\n alias: 'required',\n transform: booleanAttribute,\n });\n\n /** Makes the control read-only (native `readonly` attribute). Defaults to `false`. */\n readonly readonlyInput = input<boolean, unknown>(false, {\n alias: 'readonly',\n transform: booleanAttribute,\n });\n\n /** Per-instance override of the {@link ErrorStateMatcher}. When omitted, the directive uses the `TW_ERROR_STATE_MATCHER` token's value. */\n readonly errorStateMatcher = input<ErrorStateMatcher | undefined>(undefined);\n\n /** Consumer-supplied `aria-describedby` ids. The form-field preserves these when merging hint and error ids. Alias: `aria-describedby`. */\n override readonly userAriaDescribedBy = input<string | undefined>(undefined, {\n alias: 'aria-describedby',\n });\n\n /** Consumer-supplied `aria-labelledby` ids. The form-field preserves these when merging in the projected label id. Alias: `aria-labelledby`. */\n override readonly userAriaLabelledby = input<string | undefined>(undefined, {\n alias: 'aria-labelledby',\n });\n\n // ── Internal state signals ──\n\n private readonly _value = signal<string>(this._readInitialValue());\n private readonly _focused = signal(false);\n private readonly _autofilled = signal(false);\n private readonly _ngControlRev = signal(0);\n private readonly _formSubmitRev = signal(0);\n\n // ── FormFieldControl signals ──\n\n /** @internal */\n readonly id = computed(() => this.idInput() ?? this.uid);\n\n /** @internal */\n readonly value = computed<string | null>(() => this._value() || null);\n\n /** @internal */\n readonly focused = this._focused.asReadonly();\n\n /** @internal */\n readonly empty = computed(() => {\n if (!this._isTextarea && NEVER_EMPTY_TYPES.has(this.type())) {\n return false;\n }\n return !this._value() && !this._autofilled();\n });\n\n /** @internal */\n readonly disabled = computed(() => {\n this._ngControlRev();\n return this.disabledInput() || !!this.ngControl?.disabled;\n });\n\n /** @internal */\n readonly required = computed(() => {\n this._ngControlRev();\n if (this.requiredInput()) return true;\n return !!this.ngControl?.control?.hasValidator(Validators.required);\n });\n\n /** @internal */\n readonly errorState = computed(() => {\n this._ngControlRev();\n this._formSubmitRev();\n this._focused();\n const matcher = this.errorStateMatcher() ?? this.defaultMatcher;\n const form: TwFormSubmitted | null =\n (this.parentFormGroup as TwFormSubmitted | null) ??\n (this.parentForm as TwFormSubmitted | null);\n return matcher.isErrorState(this.ngControl?.control ?? null, form);\n });\n\n /** @internal Active validation errors map from the bound `NgControl` (or `null` when the control reports none / is unbound). Recomputes on every `_ngControlRev` tick so `[twError match=\"…\"]` reacts to validator transitions, including rules that fire/clear without flipping `VALID`/`INVALID`. */\n override readonly errors = computed<Record<string, unknown> | null>(() => {\n this._ngControlRev();\n return (this.ngControl?.control?.errors as Record<string, unknown> | null) ?? null;\n });\n\n /** @internal */\n readonly classes = computed(() =>\n inputVariants({\n inFormField: !!this.formField,\n size: this.size(),\n errorState: this.errorState(),\n disabled: this.disabled(),\n }),\n );\n\n constructor() {\n super();\n\n this.focusMonitor\n .monitor(this.elementRef)\n .pipe(takeUntilDestroyed())\n .subscribe((origin) => {\n const wasFocused = this._focused();\n this._focused.set(!!origin);\n if (wasFocused && !origin) {\n // Blur often flips `touched` on the bound `NgControl`; bump the\n // revision signal so `errorState` recomputes.\n this._ngControlRev.update((n) => n + 1);\n }\n });\n this.destroyRef.onDestroy(() =>\n this.focusMonitor.stopMonitoring(this.elementRef),\n );\n\n // Keep `_value` in sync when the accessor's value is itself a signal.\n if (this.valueAccessor && isSignal(this.valueAccessor.value)) {\n effect(() => {\n const v = (this.valueAccessor!.value as Signal<unknown>)();\n untracked(() => this._value.set(this._stringify(v)));\n });\n }\n\n // Sync the `readonly` input to the native attribute.\n effect(() => {\n const el = this.elementRef.nativeElement;\n if (this.readonlyInput()) {\n el.setAttribute('readonly', 'true');\n } else {\n el.removeAttribute('readonly');\n }\n });\n\n // Validate the input type in dev mode.\n effect(() => {\n const t = this.type();\n if (\n isDevMode() &&\n !this._isTextarea &&\n INVALID_INPUT_TYPES.has(t)\n ) {\n throw new Error(\n `tw-input: unsupported input type \"${t}\". Use a dedicated ngx-tw component for that control.`,\n );\n }\n });\n }\n\n ngOnInit(): void {\n if (this.platform.isBrowser) {\n this.autofillMonitor\n .monitor(this.elementRef.nativeElement)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => this._autofilled.set(event.isAutofilled));\n this.destroyRef.onDestroy(() =>\n this.autofillMonitor.stopMonitoring(this.elementRef.nativeElement),\n );\n }\n\n // NgControl's `control` is set by the parent `FormControl*` directive's\n // own `ngOnChanges`, which runs before children's `ngOnInit`. Subscribe\n // here so `statusChanges`/`valueChanges` are actually available.\n const ctrl = this.ngControl?.control;\n if (ctrl) {\n const streams = [ctrl.statusChanges, ctrl.valueChanges].filter(\n (s): s is NonNullable<typeof s> => !!s,\n );\n if (streams.length) {\n merge(...streams)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this._ngControlRev.update((n) => n + 1));\n }\n }\n\n const submit = this.parentFormGroup?.ngSubmit ?? this.parentForm?.ngSubmit;\n if (submit) {\n submit\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this._formSubmitRev.update((n) => n + 1));\n }\n }\n\n /** Moves focus to the underlying element. */\n focus(options?: FocusOptions): void {\n this.elementRef.nativeElement.focus(options);\n }\n\n /** @internal Called when `<tw-form-field>` has computed the merged describedby ids. */\n setDescribedByIds(ids: string[]): void {\n const el = this.elementRef.nativeElement;\n if (ids.length) {\n el.setAttribute('aria-describedby', ids.join(' '));\n } else {\n el.removeAttribute('aria-describedby');\n }\n }\n\n /** @internal Called when `<tw-form-field>` has computed the merged labelledby ids. The native `<label for>` association covers most cases; this attribute is mainly useful when a consumer also supplies `aria-labelledby` for an external label. */\n override setLabelledByIds(ids: string[]): void {\n const el = this.elementRef.nativeElement;\n // Skip applying the projected label id by itself — native `<label for=>` already wires it\n // and a redundant `aria-labelledby` can cause double-announcements in some screen readers.\n // Only apply when the consumer supplied additional ids via `aria-labelledby`.\n const userIds = this.userAriaLabelledby();\n if (userIds || (ids.length > 1)) {\n el.setAttribute('aria-labelledby', ids.join(' '));\n } else {\n el.removeAttribute('aria-labelledby');\n }\n }\n\n /** @internal Called when the form-field container is clicked. */\n onContainerClick(_event: MouseEvent): void {\n if (!this._focused()) {\n this.focus();\n }\n }\n\n /** @internal */\n _onInput(): void {\n this._value.set(this._currentValue());\n }\n\n private _currentValue(): string {\n if (this.valueAccessor) {\n const v = this.valueAccessor.value;\n if (isSignal(v)) return this._stringify((v as Signal<unknown>)());\n return this._stringify(v);\n }\n return this.elementRef.nativeElement.value;\n }\n\n private _readInitialValue(): string {\n const el = this.elementRef.nativeElement;\n return el.value ?? '';\n }\n\n private _stringify(v: unknown): string {\n return v === null || v === undefined ? '' : String(v);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|