angular-tailwind-components 1.8.3 → 1.9.0-RC1
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/README.md
CHANGED
|
@@ -6,7 +6,7 @@ A comprehensive Angular component library built entirely with **Tailwind CSS v4*
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- 🎨 **
|
|
9
|
+
- 🎨 **37 components** — Buttons, Inputs, Modals, Tables, DatePickers, and more
|
|
10
10
|
- 🎯 **Pure Tailwind CSS** — No Angular Material, Ng-Zorro, or other UI frameworks
|
|
11
11
|
- ⚡ **Angular 21** — Signals, standalone components, modern control flow
|
|
12
12
|
- 📝 **ControlValueAccessor** — Full reactive forms integration for all form components
|
|
@@ -69,7 +69,7 @@ export class ExampleComponent {
|
|
|
69
69
|
|
|
70
70
|
## Application configuration (`defineTheme`)
|
|
71
71
|
|
|
72
|
-
Use **`defineTheme`** from `angular-tailwind-components` as the single app-level entry: it registers **`EnvironmentProviders`** for optional **injection tokens** (`iconSize`, `datetimeLanguage`, `componentsSize`, `buttonKind`, `paginationSummary`) and, when you pass **`colors`**, an app initializer that applies semantic CSS variables on `document.documentElement` in the browser. Add **one** entry to `providers` without spreading.
|
|
72
|
+
Use **`defineTheme`** from `angular-tailwind-components` as the single app-level entry: it registers **`EnvironmentProviders`** for optional **injection tokens** (`iconSize`, `datetimeLanguage`, `componentsSize`, `buttonKind`, `paginationSummary`, `passwordLabels`) and, when you pass **`colors`**, an app initializer that applies semantic CSS variables on `document.documentElement` in the browser. Add **one** entry to `providers` without spreading.
|
|
73
73
|
|
|
74
74
|
`TailwindDefineThemeConfig` extends **`TailwindComponentsConfig`** with an optional **`colors`** field.
|
|
75
75
|
|
|
@@ -141,6 +141,7 @@ You can omit **`colors`** if you only need token defaults, or omit token keys if
|
|
|
141
141
|
| `componentsSize` | `TAILWIND_COMPONENTS_SIZE` |
|
|
142
142
|
| `buttonKind` | `TAILWIND_BUTTON_KIND` |
|
|
143
143
|
| `paginationSummary` | `TAILWIND_PAGINATION_SUMMARY` |
|
|
144
|
+
| `passwordLabels` | `TAILWIND_PASSWORD_LABELS` |
|
|
144
145
|
|
|
145
146
|
**`provideTailwindComponents`** is still exported for backward compatibility (token providers only, same implementation as the token slice of `defineTheme`). It is **deprecated**; prefer **`defineTheme`**.
|
|
146
147
|
|
|
@@ -204,6 +205,7 @@ Some components (for example `tailwind-card`, `tailwind-modal`, `tailwind-toolba
|
|
|
204
205
|
### Form Controls (with ControlValueAccessor)
|
|
205
206
|
|
|
206
207
|
- **Input** (`tailwind-input`): Text, email, password, number, search
|
|
208
|
+
- **Input Password** (`tailwind-input-password`): Password field with optional strength meter and show/hide toggle
|
|
207
209
|
- **Textarea** (`tailwind-textarea`): Multi-line text with resize modes and rows/cols
|
|
208
210
|
- **Upload** (`tailwind-upload`): File picker as button or drop zone; value as base64 data URL for forms, `filesSelected` for raw files
|
|
209
211
|
- **Input OTP** (`tailwind-input-otp`): Multi-digit OTP / PIN with paste and keyboard navigation
|
|
@@ -343,6 +343,13 @@ const TAILWIND_HEROICON_NAMES = [
|
|
|
343
343
|
'x-mark',
|
|
344
344
|
];
|
|
345
345
|
|
|
346
|
+
const DEFAULT_TAILWIND_PASSWORD_LABELS = {
|
|
347
|
+
prompt: 'Inserisci una password',
|
|
348
|
+
weak: 'Debole',
|
|
349
|
+
medium: 'Buona',
|
|
350
|
+
strong: 'Forte'
|
|
351
|
+
};
|
|
352
|
+
|
|
346
353
|
class TailwindComponent {
|
|
347
354
|
/** Optional ID for the component */
|
|
348
355
|
id = input(...(ngDevMode ? [undefined, { debugName: "id" }] : /* istanbul ignore next */ []));
|
|
@@ -622,6 +629,10 @@ const TAILWIND_BUTTON_KIND = new InjectionToken('TAILWIND_BUTTON_KIND');
|
|
|
622
629
|
* Use placeholders `{start}`, `{end}`, `{total}` (same rules as the `summary` input).
|
|
623
630
|
*/
|
|
624
631
|
const TAILWIND_PAGINATION_SUMMARY = new InjectionToken('TAILWIND_PAGINATION_SUMMARY');
|
|
632
|
+
/**
|
|
633
|
+
* Default labels for `tailwind-input-password` strength feedback when component inputs are omitted.
|
|
634
|
+
*/
|
|
635
|
+
const TAILWIND_PASSWORD_LABELS = new InjectionToken('TAILWIND_PASSWORD_LABELS');
|
|
625
636
|
|
|
626
637
|
const clampIconSize = (value) => {
|
|
627
638
|
if (!Number.isFinite(value))
|
|
@@ -991,6 +1002,216 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
991
1002
|
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tailwind-input-wrapper flex flex-col gap-1.5\">\n @if (label()) {\n <label\n [attr.for]=\"id() ? id() + '-inner' : null\"\n class=\"text-sm font-medium text-neutral-700\"\n [class.text-danger-600]=\"hasError()\">\n {{ label() }}\n </label>\n }\n\n <input\n [attr.id]=\"id() ? id() + '-inner' : null\"\n [type]=\"type()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"(helperText() || errorText()) && id() ? id() + '-helper' : null\"\n [value]=\"value()\"\n [class]=\"inputClasses()\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onBlur()\" />\n\n @if (helperText() && !hasError()) {\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"text-xs text-neutral-500\">\n {{ helperText() }}\n </p>\n }\n @if (errorText() && hasError()) {\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"text-xs text-danger-600\">\n {{ errorText() }}\n </p>\n }\n</div>\n", styles: [":host{display:block}\n"] }]
|
|
992
1003
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], helperText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helperText", required: false }] }], errorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorText", required: false }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
993
1004
|
|
|
1005
|
+
const LOWERCASE = /[a-z]/;
|
|
1006
|
+
const UPPERCASE = /[A-Z]/;
|
|
1007
|
+
const DIGIT = /\d/;
|
|
1008
|
+
const SYMBOL = /[^a-zA-Z0-9]/;
|
|
1009
|
+
const REPEATED_CHAR = /(.)\1{2,}/;
|
|
1010
|
+
const COMMON_SEQUENCES = ['123', '234', '345', '456', '567', '678', '789', 'abc', 'bcd', 'cde', 'qwerty', 'password'];
|
|
1011
|
+
function hasCommonSequence(value) {
|
|
1012
|
+
const lower = value.toLowerCase();
|
|
1013
|
+
return COMMON_SEQUENCES.some(seq => lower.includes(seq));
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Computes a password strength score (0–100) and maps it to weak / medium / strong.
|
|
1017
|
+
*/
|
|
1018
|
+
function computePasswordStrength(password) {
|
|
1019
|
+
if (!password) {
|
|
1020
|
+
return { score: 0, level: 'weak' };
|
|
1021
|
+
}
|
|
1022
|
+
let score = 0;
|
|
1023
|
+
const length = password.length;
|
|
1024
|
+
if (length >= 8)
|
|
1025
|
+
score += 25;
|
|
1026
|
+
else if (length >= 6)
|
|
1027
|
+
score += 15;
|
|
1028
|
+
else if (length >= 4)
|
|
1029
|
+
score += 8;
|
|
1030
|
+
else
|
|
1031
|
+
score += 4;
|
|
1032
|
+
if (length >= 12)
|
|
1033
|
+
score += 10;
|
|
1034
|
+
if (length >= 16)
|
|
1035
|
+
score += 5;
|
|
1036
|
+
const variety = [LOWERCASE, UPPERCASE, DIGIT, SYMBOL].filter(re => re.test(password)).length;
|
|
1037
|
+
score += variety * 12;
|
|
1038
|
+
if (REPEATED_CHAR.test(password)) {
|
|
1039
|
+
score -= 10;
|
|
1040
|
+
}
|
|
1041
|
+
if (hasCommonSequence(password)) {
|
|
1042
|
+
score -= 15;
|
|
1043
|
+
}
|
|
1044
|
+
score = Math.max(0, Math.min(100, score));
|
|
1045
|
+
let level;
|
|
1046
|
+
if (score < 40) {
|
|
1047
|
+
level = 'weak';
|
|
1048
|
+
}
|
|
1049
|
+
else if (score < 70) {
|
|
1050
|
+
level = 'medium';
|
|
1051
|
+
}
|
|
1052
|
+
else {
|
|
1053
|
+
level = 'strong';
|
|
1054
|
+
}
|
|
1055
|
+
return { score, level };
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Returns how many of the three meter segments should be filled (1–3) for the given level.
|
|
1059
|
+
*/
|
|
1060
|
+
function passwordStrengthMeterFill(level) {
|
|
1061
|
+
switch (level) {
|
|
1062
|
+
case 'weak':
|
|
1063
|
+
return 1;
|
|
1064
|
+
case 'medium':
|
|
1065
|
+
return 2;
|
|
1066
|
+
case 'strong':
|
|
1067
|
+
return 3;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
class TailwindInputPassword extends TailwindComponent {
|
|
1072
|
+
themeLabels = inject(TAILWIND_PASSWORD_LABELS, { optional: true });
|
|
1073
|
+
/** Label text */
|
|
1074
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
1075
|
+
/** Placeholder text */
|
|
1076
|
+
placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
1077
|
+
/** Size variant */
|
|
1078
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
1079
|
+
/** Helper text shown below input */
|
|
1080
|
+
helperText = input('', ...(ngDevMode ? [{ debugName: "helperText" }] : /* istanbul ignore next */ []));
|
|
1081
|
+
/** Error text shown when hasError is true */
|
|
1082
|
+
errorText = input('', ...(ngDevMode ? [{ debugName: "errorText" }] : /* istanbul ignore next */ []));
|
|
1083
|
+
/** Whether the input is in error state */
|
|
1084
|
+
hasError = input(false, ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
|
|
1085
|
+
/** Show strength feedback panel while typing */
|
|
1086
|
+
feedback = input(false, ...(ngDevMode ? [{ debugName: "feedback" }] : /* istanbul ignore next */ []));
|
|
1087
|
+
/** Show toggle to reveal/hide password */
|
|
1088
|
+
toggleMask = input(false, ...(ngDevMode ? [{ debugName: "toggleMask" }] : /* istanbul ignore next */ []));
|
|
1089
|
+
/** Override prompt label from theme token */
|
|
1090
|
+
promptLabel = input(undefined, ...(ngDevMode ? [{ debugName: "promptLabel" }] : /* istanbul ignore next */ []));
|
|
1091
|
+
/** Override weak strength label from theme token */
|
|
1092
|
+
weakLabel = input(undefined, ...(ngDevMode ? [{ debugName: "weakLabel" }] : /* istanbul ignore next */ []));
|
|
1093
|
+
/** Override medium strength label from theme token */
|
|
1094
|
+
mediumLabel = input(undefined, ...(ngDevMode ? [{ debugName: "mediumLabel" }] : /* istanbul ignore next */ []));
|
|
1095
|
+
/** Override strong strength label from theme token */
|
|
1096
|
+
strongLabel = input(undefined, ...(ngDevMode ? [{ debugName: "strongLabel" }] : /* istanbul ignore next */ []));
|
|
1097
|
+
/** Two-way bound value */
|
|
1098
|
+
value = model('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
1099
|
+
isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
1100
|
+
masked = signal(true, ...(ngDevMode ? [{ debugName: "masked" }] : /* istanbul ignore next */ []));
|
|
1101
|
+
isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : /* istanbul ignore next */ []));
|
|
1102
|
+
strength = computed(() => computePasswordStrength(this.value()), ...(ngDevMode ? [{ debugName: "strength" }] : /* istanbul ignore next */ []));
|
|
1103
|
+
strengthLevel = computed(() => this.strength().level, ...(ngDevMode ? [{ debugName: "strengthLevel" }] : /* istanbul ignore next */ []));
|
|
1104
|
+
meterFill = computed(() => passwordStrengthMeterFill(this.strengthLevel()), ...(ngDevMode ? [{ debugName: "meterFill" }] : /* istanbul ignore next */ []));
|
|
1105
|
+
showFeedbackPanel = computed(() => this.feedback() && this.isFocused() && this.value().length > 0, ...(ngDevMode ? [{ debugName: "showFeedbackPanel" }] : /* istanbul ignore next */ []));
|
|
1106
|
+
resolvedLabels = computed(() => {
|
|
1107
|
+
const defaults = this.themeLabels ?? DEFAULT_TAILWIND_PASSWORD_LABELS;
|
|
1108
|
+
return {
|
|
1109
|
+
prompt: this.promptLabel() ?? defaults.prompt,
|
|
1110
|
+
weak: this.weakLabel() ?? defaults.weak,
|
|
1111
|
+
medium: this.mediumLabel() ?? defaults.medium,
|
|
1112
|
+
strong: this.strongLabel() ?? defaults.strong
|
|
1113
|
+
};
|
|
1114
|
+
}, ...(ngDevMode ? [{ debugName: "resolvedLabels" }] : /* istanbul ignore next */ []));
|
|
1115
|
+
strengthLabel = computed(() => {
|
|
1116
|
+
const labels = this.resolvedLabels();
|
|
1117
|
+
const level = this.strengthLevel();
|
|
1118
|
+
if (level === 'medium')
|
|
1119
|
+
return labels.medium;
|
|
1120
|
+
if (level === 'strong')
|
|
1121
|
+
return labels.strong;
|
|
1122
|
+
return labels.weak;
|
|
1123
|
+
}, ...(ngDevMode ? [{ debugName: "strengthLabel" }] : /* istanbul ignore next */ []));
|
|
1124
|
+
inputType = computed(() => (this.masked() ? 'password' : 'text'), ...(ngDevMode ? [{ debugName: "inputType" }] : /* istanbul ignore next */ []));
|
|
1125
|
+
inputPaddingClass = computed(() => (this.toggleMask() ? 'pr-10' : ''), ...(ngDevMode ? [{ debugName: "inputPaddingClass" }] : /* istanbul ignore next */ []));
|
|
1126
|
+
toggleIcon = computed(() => (this.masked() ? 'eye' : 'eye-slash'), ...(ngDevMode ? [{ debugName: "toggleIcon" }] : /* istanbul ignore next */ []));
|
|
1127
|
+
toggleAriaLabel = computed(() => (this.masked() ? 'Mostra password' : 'Nascondi password'), ...(ngDevMode ? [{ debugName: "toggleAriaLabel" }] : /* istanbul ignore next */ []));
|
|
1128
|
+
inputClasses = computed(() => {
|
|
1129
|
+
const base = [
|
|
1130
|
+
'block w-full bg-white',
|
|
1131
|
+
'border transition-colors duration-150',
|
|
1132
|
+
'placeholder:text-neutral-400',
|
|
1133
|
+
'outline-none focus:outline focus:outline-2 focus:outline-offset-2',
|
|
1134
|
+
'disabled:bg-neutral-50 disabled:text-neutral-400 disabled:cursor-not-allowed'
|
|
1135
|
+
];
|
|
1136
|
+
const sizeMap = {
|
|
1137
|
+
xs: 'text-xs px-2 py-1 rounded-sm',
|
|
1138
|
+
sm: 'text-sm px-2.5 py-1.5 rounded-md',
|
|
1139
|
+
md: 'text-sm px-3 py-2 rounded-md',
|
|
1140
|
+
lg: 'text-base px-3.5 py-2.5 rounded-lg',
|
|
1141
|
+
xl: 'text-base px-4 py-3 rounded-lg'
|
|
1142
|
+
};
|
|
1143
|
+
const stateClass = this.hasError()
|
|
1144
|
+
? 'border-danger-400 focus:outline-danger-500 text-danger-900'
|
|
1145
|
+
: 'border-neutral-300 focus:outline-primary-500 text-neutral-900';
|
|
1146
|
+
return [...base, sizeMap[this.size()], stateClass, this.inputPaddingClass()].filter(Boolean).join(' ');
|
|
1147
|
+
}, ...(ngDevMode ? [{ debugName: "inputClasses" }] : /* istanbul ignore next */ []));
|
|
1148
|
+
meterSegmentClasses = computed(() => {
|
|
1149
|
+
const fill = this.meterFill();
|
|
1150
|
+
const level = this.strengthLevel();
|
|
1151
|
+
const activeClass = level === 'weak' ? 'bg-danger-500' : level === 'medium' ? 'bg-warning-500' : 'bg-success-600';
|
|
1152
|
+
return [0, 1, 2].map(index => {
|
|
1153
|
+
const isActive = index < fill;
|
|
1154
|
+
return isActive ? activeClass : 'bg-neutral-200';
|
|
1155
|
+
});
|
|
1156
|
+
}, ...(ngDevMode ? [{ debugName: "meterSegmentClasses" }] : /* istanbul ignore next */ []));
|
|
1157
|
+
// CVA
|
|
1158
|
+
onChange = () => { };
|
|
1159
|
+
onTouched = () => { };
|
|
1160
|
+
writeValue(value) {
|
|
1161
|
+
this.value.set(value ?? '');
|
|
1162
|
+
}
|
|
1163
|
+
registerOnChange(fn) {
|
|
1164
|
+
this.onChange = fn;
|
|
1165
|
+
}
|
|
1166
|
+
registerOnTouched(fn) {
|
|
1167
|
+
this.onTouched = fn;
|
|
1168
|
+
}
|
|
1169
|
+
setDisabledState(disabled) {
|
|
1170
|
+
this.isDisabled.set(disabled);
|
|
1171
|
+
}
|
|
1172
|
+
onInputChange(event) {
|
|
1173
|
+
const val = event.target.value;
|
|
1174
|
+
this.value.set(val);
|
|
1175
|
+
this.onChange(val);
|
|
1176
|
+
}
|
|
1177
|
+
onFocus() {
|
|
1178
|
+
this.isFocused.set(true);
|
|
1179
|
+
}
|
|
1180
|
+
onBlur() {
|
|
1181
|
+
this.isFocused.set(false);
|
|
1182
|
+
this.onTouched();
|
|
1183
|
+
}
|
|
1184
|
+
toggleMaskVisibility() {
|
|
1185
|
+
this.masked.update(v => !v);
|
|
1186
|
+
}
|
|
1187
|
+
onEscape() {
|
|
1188
|
+
if (this.showFeedbackPanel()) {
|
|
1189
|
+
this.isFocused.set(false);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TailwindInputPassword, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1193
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: TailwindInputPassword, isStandalone: true, selector: "tailwind-input-password", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, helperText: { classPropertyName: "helperText", publicName: "helperText", isSignal: true, isRequired: false, transformFunction: null }, errorText: { classPropertyName: "errorText", publicName: "errorText", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null }, feedback: { classPropertyName: "feedback", publicName: "feedback", isSignal: true, isRequired: false, transformFunction: null }, toggleMask: { classPropertyName: "toggleMask", publicName: "toggleMask", isSignal: true, isRequired: false, transformFunction: null }, promptLabel: { classPropertyName: "promptLabel", publicName: "promptLabel", isSignal: true, isRequired: false, transformFunction: null }, weakLabel: { classPropertyName: "weakLabel", publicName: "weakLabel", isSignal: true, isRequired: false, transformFunction: null }, mediumLabel: { classPropertyName: "mediumLabel", publicName: "mediumLabel", isSignal: true, isRequired: false, transformFunction: null }, strongLabel: { classPropertyName: "strongLabel", publicName: "strongLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, providers: [
|
|
1194
|
+
{
|
|
1195
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1196
|
+
useExisting: forwardRef(() => TailwindInputPassword),
|
|
1197
|
+
multi: true
|
|
1198
|
+
}
|
|
1199
|
+
], usesInheritance: true, ngImport: i0, template: "<div class=\"tailwind-input-password-wrapper flex flex-col gap-1.5\">\r\n @if (label()) {\r\n <label\r\n [attr.for]=\"id() ? id() + '-inner' : null\"\r\n class=\"text-sm font-medium text-neutral-700\"\r\n [class.text-danger-600]=\"hasError()\">\r\n {{ label() }}\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <input\r\n [attr.id]=\"id() ? id() + '-inner' : null\"\r\n [type]=\"inputType()\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"isDisabled()\"\r\n autocomplete=\"current-password\"\r\n [attr.aria-invalid]=\"hasError() || null\"\r\n [attr.aria-describedby]=\"(helperText() || errorText() || feedback()) && id() ? id() + '-helper' : null\"\r\n [value]=\"value()\"\r\n [class]=\"inputClasses()\"\r\n (input)=\"onInputChange($event)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\" />\r\n\r\n @if (toggleMask()) {\r\n <button\r\n type=\"button\"\r\n class=\"absolute right-2 top-1/2 -translate-y-1/2 inline-flex items-center justify-center rounded-md p-1 text-neutral-500 hover:text-neutral-700 focus:outline focus:outline-offset-2 focus:outline-primary-500 disabled:pointer-events-none disabled:opacity-50\"\r\n [attr.aria-label]=\"toggleAriaLabel()\"\r\n [disabled]=\"isDisabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"toggleMaskVisibility()\">\r\n <tailwind-icon [icon]=\"toggleIcon()\" [size]=\"16\" />\r\n </button>\r\n }\r\n\r\n @if (showFeedbackPanel()) {\r\n <div\r\n class=\"absolute left-0 top-full z-popover mt-1 w-max max-w-xl min-w-48 rounded-lg border border-neutral-200 bg-white p-3 shadow-lg\"\r\n role=\"region\"\r\n [attr.aria-label]=\"resolvedLabels().prompt\">\r\n <p class=\"mb-2 text-xs font-medium text-neutral-700\">{{ resolvedLabels().prompt }}</p>\r\n <div class=\"flex w-56 max-w-full gap-1\" role=\"img\" [attr.aria-label]=\"strengthLabel()\">\r\n @for (segmentClass of meterSegmentClasses(); track $index) {\r\n <span class=\"h-1.5 flex-1 rounded-full transition-colors duration-150\" [class]=\"segmentClass\"></span>\r\n }\r\n </div>\r\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"mt-2 text-xs text-neutral-600\" aria-live=\"polite\">\r\n {{ strengthLabel() }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (helperText() && !hasError()) {\r\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"text-xs text-neutral-500\">\r\n {{ helperText() }}\r\n </p>\r\n }\r\n @if (errorText() && hasError()) {\r\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"text-xs text-danger-600\">\r\n {{ errorText() }}\r\n </p>\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "component", type: TailwindIcon, selector: "tailwind-icon", inputs: ["icon", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1200
|
+
}
|
|
1201
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TailwindInputPassword, decorators: [{
|
|
1202
|
+
type: Component,
|
|
1203
|
+
args: [{ imports: [TailwindIcon], selector: 'tailwind-input-password', providers: [
|
|
1204
|
+
{
|
|
1205
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1206
|
+
useExisting: forwardRef(() => TailwindInputPassword),
|
|
1207
|
+
multi: true
|
|
1208
|
+
}
|
|
1209
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tailwind-input-password-wrapper flex flex-col gap-1.5\">\r\n @if (label()) {\r\n <label\r\n [attr.for]=\"id() ? id() + '-inner' : null\"\r\n class=\"text-sm font-medium text-neutral-700\"\r\n [class.text-danger-600]=\"hasError()\">\r\n {{ label() }}\r\n </label>\r\n }\r\n\r\n <div class=\"relative\">\r\n <input\r\n [attr.id]=\"id() ? id() + '-inner' : null\"\r\n [type]=\"inputType()\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"isDisabled()\"\r\n autocomplete=\"current-password\"\r\n [attr.aria-invalid]=\"hasError() || null\"\r\n [attr.aria-describedby]=\"(helperText() || errorText() || feedback()) && id() ? id() + '-helper' : null\"\r\n [value]=\"value()\"\r\n [class]=\"inputClasses()\"\r\n (input)=\"onInputChange($event)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\" />\r\n\r\n @if (toggleMask()) {\r\n <button\r\n type=\"button\"\r\n class=\"absolute right-2 top-1/2 -translate-y-1/2 inline-flex items-center justify-center rounded-md p-1 text-neutral-500 hover:text-neutral-700 focus:outline focus:outline-offset-2 focus:outline-primary-500 disabled:pointer-events-none disabled:opacity-50\"\r\n [attr.aria-label]=\"toggleAriaLabel()\"\r\n [disabled]=\"isDisabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"toggleMaskVisibility()\">\r\n <tailwind-icon [icon]=\"toggleIcon()\" [size]=\"16\" />\r\n </button>\r\n }\r\n\r\n @if (showFeedbackPanel()) {\r\n <div\r\n class=\"absolute left-0 top-full z-popover mt-1 w-max max-w-xl min-w-48 rounded-lg border border-neutral-200 bg-white p-3 shadow-lg\"\r\n role=\"region\"\r\n [attr.aria-label]=\"resolvedLabels().prompt\">\r\n <p class=\"mb-2 text-xs font-medium text-neutral-700\">{{ resolvedLabels().prompt }}</p>\r\n <div class=\"flex w-56 max-w-full gap-1\" role=\"img\" [attr.aria-label]=\"strengthLabel()\">\r\n @for (segmentClass of meterSegmentClasses(); track $index) {\r\n <span class=\"h-1.5 flex-1 rounded-full transition-colors duration-150\" [class]=\"segmentClass\"></span>\r\n }\r\n </div>\r\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"mt-2 text-xs text-neutral-600\" aria-live=\"polite\">\r\n {{ strengthLabel() }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (helperText() && !hasError()) {\r\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"text-xs text-neutral-500\">\r\n {{ helperText() }}\r\n </p>\r\n }\r\n @if (errorText() && hasError()) {\r\n <p [attr.id]=\"id() ? id() + '-helper' : null\" class=\"text-xs text-danger-600\">\r\n {{ errorText() }}\r\n </p>\r\n }\r\n</div>\r\n" }]
|
|
1210
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], helperText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helperText", required: false }] }], errorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorText", required: false }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], feedback: [{ type: i0.Input, args: [{ isSignal: true, alias: "feedback", required: false }] }], toggleMask: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleMask", required: false }] }], promptLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "promptLabel", required: false }] }], weakLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "weakLabel", required: false }] }], mediumLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediumLabel", required: false }] }], strongLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "strongLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onEscape: [{
|
|
1211
|
+
type: HostListener,
|
|
1212
|
+
args: ['document:keydown.escape']
|
|
1213
|
+
}] } });
|
|
1214
|
+
|
|
994
1215
|
class TailwindTextarea extends TailwindComponent {
|
|
995
1216
|
/** Label text */
|
|
996
1217
|
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
@@ -4661,6 +4882,9 @@ function providersFromTailwindComponentsConfig(config) {
|
|
|
4661
4882
|
if (config.paginationSummary !== undefined) {
|
|
4662
4883
|
providers.push({ provide: TAILWIND_PAGINATION_SUMMARY, useValue: config.paginationSummary });
|
|
4663
4884
|
}
|
|
4885
|
+
if (config.passwordLabels !== undefined) {
|
|
4886
|
+
providers.push({ provide: TAILWIND_PASSWORD_LABELS, useValue: config.passwordLabels });
|
|
4887
|
+
}
|
|
4664
4888
|
return providers;
|
|
4665
4889
|
}
|
|
4666
4890
|
/**
|
|
@@ -4808,5 +5032,5 @@ function defineTheme(config) {
|
|
|
4808
5032
|
* Generated bundle index. Do not edit.
|
|
4809
5033
|
*/
|
|
4810
5034
|
|
|
4811
|
-
export { DEFAULT_PAGINATION_LENGTH_OPTIONS, TAILWIND_BUTTON_KIND, TAILWIND_COMPONENTS_SIZE, TAILWIND_DATETIME_LANGUAGE, TAILWIND_HEROICON_NAMES, TAILWIND_ICON_SIZE, TAILWIND_MODAL_DATA, TAILWIND_PAGINATION_SUMMARY, TW_TABLE_SORT_DIR_ATTR, TW_TABLE_SORT_KEY_ATTR, TailwindAccordion, TailwindAccordionItem, TailwindAlert, TailwindAutocomplete, TailwindBadge, TailwindBreadcrumb, TailwindButton, TailwindCard, TailwindCheckbox, TailwindDatePicker, TailwindDateTimePicker, TailwindDivider, TailwindDrawer, TailwindIcon, TailwindInput, TailwindInputOtp, TailwindMenu, TailwindMessage, TailwindMeter, TailwindModal, TailwindModalRef, TailwindModalService, TailwindNotification, TailwindPagination, TailwindProgressBar, TailwindRadioGroup, TailwindSelect, TailwindSkeleton, TailwindSlider, TailwindSortHeaderDirective, TailwindSpinner, TailwindStep, TailwindStepper, TailwindTab, TailwindTabGroup, TailwindTable, TailwindTableRowDirective, TailwindTableRowDirective as TailwindTableRowTemplateDirective, TailwindTag, TailwindTextarea, TailwindTimePicker, TailwindTitle, TailwindToast, TailwindToastService, TailwindToggle, TailwindToolbar, TailwindTooltip, TailwindTooltipDirective, TailwindUpload, buildTailwindThemeVariableEntries, defineTheme, provideTailwindComponents };
|
|
5035
|
+
export { DEFAULT_PAGINATION_LENGTH_OPTIONS, DEFAULT_TAILWIND_PASSWORD_LABELS, TAILWIND_BUTTON_KIND, TAILWIND_COMPONENTS_SIZE, TAILWIND_DATETIME_LANGUAGE, TAILWIND_HEROICON_NAMES, TAILWIND_ICON_SIZE, TAILWIND_MODAL_DATA, TAILWIND_PAGINATION_SUMMARY, TAILWIND_PASSWORD_LABELS, TW_TABLE_SORT_DIR_ATTR, TW_TABLE_SORT_KEY_ATTR, TailwindAccordion, TailwindAccordionItem, TailwindAlert, TailwindAutocomplete, TailwindBadge, TailwindBreadcrumb, TailwindButton, TailwindCard, TailwindCheckbox, TailwindDatePicker, TailwindDateTimePicker, TailwindDivider, TailwindDrawer, TailwindIcon, TailwindInput, TailwindInputOtp, TailwindInputPassword, TailwindMenu, TailwindMessage, TailwindMeter, TailwindModal, TailwindModalRef, TailwindModalService, TailwindNotification, TailwindPagination, TailwindProgressBar, TailwindRadioGroup, TailwindSelect, TailwindSkeleton, TailwindSlider, TailwindSortHeaderDirective, TailwindSpinner, TailwindStep, TailwindStepper, TailwindTab, TailwindTabGroup, TailwindTable, TailwindTableRowDirective, TailwindTableRowDirective as TailwindTableRowTemplateDirective, TailwindTag, TailwindTextarea, TailwindTimePicker, TailwindTitle, TailwindToast, TailwindToastService, TailwindToggle, TailwindToolbar, TailwindTooltip, TailwindTooltipDirective, TailwindUpload, buildTailwindThemeVariableEntries, defineTheme, provideTailwindComponents };
|
|
4812
5036
|
//# sourceMappingURL=angular-tailwind-components.mjs.map
|