quang 20.1.9 → 20.2.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.
@@ -4,35 +4,103 @@ The `QuangInputComponent` must be configured using the `componentType` input pro
4
4
 
5
5
  ## Supported Types
6
6
 
7
- - text
8
- - textarea
9
- - password
10
- - email
11
- - number
12
- - url
13
- - search
14
- - tel
15
- - color
7
+ The component supports the following input types, each with specific behaviors and configurations:
8
+
9
+ ### Text Input Types
10
+
11
+ - **text** — Standard text input for general text entry
12
+ - **email** — Email input with built-in email validation
13
+ - **password** — Password input with optional show/hide toggle functionality
14
+ - **url** — URL input with URL format validation
15
+ - **search** — Search input with native search behavior
16
+ - **tel** — Telephone number input
17
+
18
+ ### Numeric Input Types
19
+
20
+ - **number** — Numeric input with step controls and min/max validation
21
+
22
+ ### Special Input Types
23
+
24
+ - **textarea** — Multi-line text input with resizable functionality
25
+ - **color** — Color picker input
26
+
27
+ ### Type-Specific Features
28
+
29
+ #### Textarea (`componentType="textarea"`)
30
+
31
+ - **Multi-line support**: Automatically expands for content
32
+ - **Resizable control**: Use `resizable` input to enable/disable manual resizing
33
+ - **No min/max number constraints**: Number-related inputs are ignored
34
+
35
+ #### Password (`componentType="password"`)
36
+
37
+ - **Toggle visibility**: Built-in show/hide password functionality
38
+ - **Icon support**: Custom icons through content projection
39
+ - **Security**: Masks input by default, reveals on toggle
40
+
41
+ #### Number (`componentType="number"`)
42
+
43
+ - **Step controls**: Use `componentStep` to define increment/decrement values
44
+ - **Range validation**: Set `minNumber` and `maxNumber` for value constraints
45
+ - **Decimal support**: Supports decimal values when step allows
46
+
47
+ #### Email (`componentType="email"`)
48
+
49
+ - **Format validation**: Automatic email format validation
50
+ - **Autocomplete**: Enhanced with email-specific autocomplete
51
+
52
+ #### Search (`componentType="search"`)
53
+
54
+ - **Clear button**: Native clear functionality on supported browsers
55
+ - **Search behavior**: Platform-specific search enhancements
16
56
 
17
57
  ## Inputs
18
58
 
59
+ ### Core Configuration
60
+
19
61
  - `componentType`: `'text' | 'textarea' | 'password' | 'email' | 'number' | 'url' | 'search' | 'tel' | 'color'` — Specifies the type of input. **(Required)**
20
- - `maxLengthText`: `number | null` — Maximum length for text input.
21
- - `minLengthText`: `number | null` — Minimum length for text input.
22
- - `minNumber`: `number | undefined` — Minimum value for number input.
23
- - `maxNumber`: `number | undefined` — Maximum value for number input.
24
- - `componentStep`: `number` — Step for number input. Default: `1`.
25
- - `resizable`: `boolean` — If false, disables textarea resizing. Default: `true` (only for textarea).
26
- - All standard form/label/validation-related inputs inherited from `QuangBaseComponent`:
27
- - `isReadonly`, `componentLabel`, `componentPlaceholder`, `componentTabIndex`, `componentClass`, `errorMap`, `successMessage`, `helpMessage`, `formControl`
62
+
63
+ ### Text-Specific Inputs
64
+
65
+ - `maxLengthText`: `number | null` — Maximum length for text input. Applies to: `text`, `textarea`, `email`, `password`, `url`, `search`, `tel`
66
+ - `minLengthText`: `number | null` — Minimum length for text input. Applies to: `text`, `textarea`, `email`, `password`, `url`, `search`, `tel`
67
+
68
+ ### Number-Specific Inputs
69
+
70
+ - `minNumber`: `number | undefined` — Minimum value for number input. **Only applies to**: `number`
71
+ - `maxNumber`: `number | undefined` — Maximum value for number input. **Only applies to**: `number`
72
+ - `componentStep`: `number` — Step increment for number input. Default: `1`. **Only applies to**: `number`
73
+
74
+ ### Textarea-Specific Inputs
75
+
76
+ - `resizable`: `boolean` — Controls textarea resizing behavior. Default: `true`
77
+
78
+ ### Password-Specific Inputs
79
+
80
+ - `showHidePasswordButton`: `boolean` — Shows/hides the password toggle button. Default: `true`. **Only applies to**: `password`
81
+ - `buttonClass`: `string` — Additional CSS classes for the password toggle button. **Only applies to**: `password`
82
+
83
+ ### Universal Inputs
84
+
85
+ - `isReadonly`: `boolean` — Makes the input read-only
86
+ - `componentLabel`: `string` — Label text (supports i18n keys)
87
+ - `componentPlaceholder`: `string` — Placeholder text (supports i18n keys)
88
+ - `componentTabIndex`: `number` — Tab index for accessibility
89
+ - `componentClass`: `string` — Additional CSS classes for the input element
90
+ - `errorMap`: `Record<string, any>` — Validation error messages
91
+ - `successMessage`: `string` — Success message text
92
+ - `helpMessage`: `string` — Help text displayed below the input
93
+ - `formControl`: `FormControl` — Angular reactive form control
28
94
 
29
95
  ## Outputs
30
96
 
31
- - All standard outputs inherited from `QuangBaseComponent`:
32
- - `componentBlur`
97
+ - `showPassword`: `EventEmitter<boolean>` Emitted when the password visibility is toggled (password inputs only)
98
+ - `componentBlur`: `EventEmitter<void>` — Emitted when input loses focus
33
99
 
34
100
  ## Usage
35
101
 
102
+ ### Basic Text Input
103
+
36
104
  ```html
37
105
  <quang-input
38
106
  [errorMap]="errors()"
@@ -40,19 +108,75 @@ The `QuangInputComponent` must be configured using the `componentType` input pro
40
108
  componentType="text"
41
109
  formControlName="testInput"
42
110
  />
111
+ ```
112
+
113
+ ### Password Input with Toggle
114
+
115
+ ```html
116
+ <quang-input
117
+ [errorMap]="errors()"
118
+ [showHidePasswordButton]="true"
119
+ (showPassword)="onToggleShowPassword($event)"
120
+ componentLabel="form.label.password"
121
+ componentType="password"
122
+ formControlName="password"
123
+ >
124
+ @if (showPassword()) {
125
+ <svg-icon src="assets/icons/svg/visibility_off.svg" />
126
+ } @else {
127
+ <svg-icon src="assets/icons/svg/visibility.svg" />
128
+ }
129
+ </quang-input>
130
+ ```
131
+
132
+ #### TypeScript Example
133
+
134
+ ```typescript
135
+ export class MyComponent {
136
+ showPassword = signal<boolean>(false)
137
+
138
+ onToggleShowPassword(isVisible: boolean): void {
139
+ this.showPassword.set(isVisible)
140
+ }
141
+
142
+ errors(): Record<string, any> {
143
+ return this.form.get('password')?.errors ?? {}
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### Number Input with Constraints
43
149
 
150
+ ```html
44
151
  <quang-input
152
+ [componentStep]="5"
45
153
  [errorMap]="errors()"
46
- [isReadonly]="isReadonly()"
47
- [maxNumber]="10"
154
+ [maxNumber]="100"
48
155
  [minNumber]="0"
49
- componentLabel="form.label.input"
156
+ componentLabel="form.label.quantity"
50
157
  componentType="number"
51
- formControlName="testInput"
52
- successMessage="form.label.success"
158
+ formControlName="quantity"
53
159
  />
54
160
  ```
55
161
 
56
- ## Notes
162
+ ### Textarea
163
+
164
+ ```html
165
+ <quang-input
166
+ [errorMap]="errors()"
167
+ [maxLengthText]="500"
168
+ componentLabel="form.label.description"
169
+ componentType="textarea"
170
+ formControlName="description"
171
+ />
172
+ ```
173
+
174
+ ### Type-Specific Features
175
+
176
+ The component supports various input types with specific behaviors:
57
177
 
58
- This component extends the `QuangBaseComponent` and inherits its features, such as label and validation messages.
178
+ - **text, email, url, search, tel**: Support text length constraints
179
+ - **password**: Built-in show/hide toggle functionality with icon support
180
+ - **number**: Step controls and min/max validation
181
+ - **textarea**: Multi-line support with resizable control
182
+ - **color**: Color picker input
@@ -10,9 +10,15 @@ declare class QuangInputComponent extends QuangBaseComponent<string | number> {
10
10
  maxNumber: _angular_core.InputSignal<number | undefined>;
11
11
  componentStep: _angular_core.InputSignal<number>;
12
12
  resizable: _angular_core.InputSignal<boolean>;
13
+ buttonClass: _angular_core.InputSignal<string>;
14
+ showHidePasswordButton: _angular_core.InputSignal<boolean>;
15
+ showPassword: _angular_core.OutputEmitterRef<boolean>;
16
+ private onShowPassword;
17
+ componentInputType: _angular_core.Signal<InputType>;
13
18
  constructor();
19
+ onTogglePasswordVisibility(): void;
14
20
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<QuangInputComponent, never>;
15
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuangInputComponent, "quang-input", never, { "componentType": { "alias": "componentType"; "required": true; "isSignal": true; }; "maxLengthText": { "alias": "maxLengthText"; "required": false; "isSignal": true; }; "minLengthText": { "alias": "minLengthText"; "required": false; "isSignal": true; }; "minNumber": { "alias": "minNumber"; "required": false; "isSignal": true; }; "maxNumber": { "alias": "maxNumber"; "required": false; "isSignal": true; }; "componentStep": { "alias": "componentStep"; "required": false; "isSignal": true; }; "resizable": { "alias": "resizable"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
21
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<QuangInputComponent, "quang-input", never, { "componentType": { "alias": "componentType"; "required": true; "isSignal": true; }; "maxLengthText": { "alias": "maxLengthText"; "required": false; "isSignal": true; }; "minLengthText": { "alias": "minLengthText"; "required": false; "isSignal": true; }; "minNumber": { "alias": "minNumber"; "required": false; "isSignal": true; }; "maxNumber": { "alias": "maxNumber"; "required": false; "isSignal": true; }; "componentStep": { "alias": "componentStep"; "required": false; "isSignal": true; }; "resizable": { "alias": "resizable"; "required": false; "isSignal": true; }; "buttonClass": { "alias": "buttonClass"; "required": false; "isSignal": true; }; "showHidePasswordButton": { "alias": "showHidePasswordButton"; "required": false; "isSignal": true; }; }, { "showPassword": "showPassword"; }, never, ["*"], true, never>;
16
22
  }
17
23
 
18
24
  export { QuangInputComponent };
@@ -1,43 +1,67 @@
1
1
  # QuangPaginatorComponent
2
2
 
3
- The `QuangPaginatorComponent` provides controls for navigating through pages of data, supporting configurations for total items, items per page, and current page.
4
-
5
- ## Features
6
-
7
- - Pagination controls
8
- - Configurable total items, items per page, and current page
9
- - Emits events for page changes
3
+ The `QuangPaginatorComponent` is a pagination control that provides navigation through large datasets with configurable page sizes and internationalization support.
10
4
 
11
5
  ## Inputs
12
6
 
13
- - `page`: `number` — Current page number. **(Required)**
14
- - `pageSize`: `number` — Number of items per page. **(Required)**
15
- - `sizeList`: `number[]` — List of selectable page sizes. Default: `[]`.
16
- - `totalItems`: `number` — Total number of items to paginate. **(Required)**
17
- - `showTotalElementsCount`: `boolean` — Show/hide total items count. Default: `true`.
18
- - `totalItemsText`: `string` — Translation key for total items label. Default: `'quangPaginator.totalItems'`.
19
- - `sizeText`: `string` — Translation key for size label. Default: `'quangPaginator.size'`.
20
- - `pageRangeText`: `string` — Translation key for page range label. Default: `'quangPaginator.pageRange'`. If the translation is overwritten, it should contain `{{page}}` and `{{amountPages}}` placeholders to display the correct numeric values.
21
- - `componentId`, `componentTabIndex`, `componentClass`: Standard component inputs.
7
+ - `page`: `number` — Current active page number (1-based indexing). **(Required)**
8
+ - `pageSize`: `number` — Number of items displayed per page. **(Required)**
9
+ - `totalItems`: `number` — Total number of items in the dataset. **(Required)**
10
+ - `sizeList`: `number[]` — Array of available page size options for user selection. Default: `[]`
11
+ - `showTotalElementsCount`: `boolean` — Controls visibility of total items count display. Default: `true`
12
+ - `totalItemsText`: `string` — Translation key for total items label text. Default: `'quangPaginator.totalItems'`
13
+ - `sizeText`: `string` — Translation key for page size selector label. Default: `'quangPaginator.size'`
14
+ - `pageRangeText`: `string` — Translation key for page range display. Must include `{{page}}` and `{{amountPages}}` placeholders. Default: `'quangPaginator.pageRange'`
15
+ - `componentId`: `string` Unique identifier for the paginator instance
16
+ - `componentTabIndex`: `number` — Base tab index for paginator controls. Default: `0`
17
+ - `componentClass`: `string | string[]` — Additional CSS classes for styling customization
22
18
 
23
19
  ## Outputs
24
20
 
25
- - `changePage`: Emits the new page number when the user navigates to a different page.
26
- - `changeSize`: Emits the new page size when the user changes it.
21
+ - `changePage`: `EventEmitter<number>` Emitted when user navigates to a different page
22
+ - `changeSize`: `EventEmitter<number>` Emitted when user changes the page size
27
23
 
28
24
  ## Usage
29
25
 
26
+ ### Basic Paginator
27
+
30
28
  ```html
31
29
  <quang-paginator
32
- [page]="1"
33
- [pageSize]="10"
34
- [sizeList]="[5, 10, 20]"
35
- [totalItems]="30"
36
- (changePage)="onChangePage($event)"
37
- (changeSize)="onChangePageSize($event)"
38
- />
30
+ [page]="currentPage"
31
+ [pageSize]="itemsPerPage"
32
+ [totalItems]="totalItemCount"
33
+ (changePage)="onPageChange($event)"
34
+ (changeSize)="onPageSizeChange($event)"
35
+ >
36
+ </quang-paginator>
39
37
  ```
40
38
 
41
- ## Notes
39
+ #### TypeScript Example
40
+
41
+ ```typescript
42
+ export class MyComponent {
43
+ currentPage = 1
44
+ itemsPerPage = 20
45
+ totalItemCount = 150
46
+
47
+ onPageChange(page: number): void {
48
+ this.currentPage = page
49
+ // Load data for new page
50
+ }
51
+
52
+ onPageSizeChange(pageSize: number): void {
53
+ this.itemsPerPage = pageSize
54
+ this.currentPage = 1 // Reset to first page
55
+ // Load data with new page size
56
+ }
57
+ }
58
+ ```
59
+
60
+ ### Translation Integration
61
+
62
+ The component uses QuangTranslationService for all text content:
42
63
 
43
- This component provides a user-friendly interface for pagination in lists and tables.
64
+ - **Default Keys**: Uses `quangPaginator.*` translation keys
65
+ - **Custom Override**: All text keys can be overridden via inputs
66
+ - **Placeholder Support**: Page range text supports `{{page}}` and `{{amountPages}}` placeholders
67
+ - **Dynamic Translation**: Responds to language changes automatically
@@ -2,53 +2,43 @@
2
2
 
3
3
  The `QuangSelectComponent` supports single or multiple selections from a dropdown list.
4
4
 
5
- ## Features
5
+ ## Input
6
6
 
7
- - Single selection
8
- - Multiple selection
9
- - Customizable options
7
+ - `selectOptions`: `SelectOption[]` - Array of options to display in the dropdown (required)
8
+ - `selectionMode`: `'single' | 'multiple'` - Selection mode (default: 'single')
10
9
 
11
- ## Inputs
10
+ All standard inputs inherited from `QuangBaseComponent`: `isReadonly`, `componentLabel`, `componentPlaceholder`, `componentTabIndex`, `componentClass`, `errorMap`, `successMessage`, `helpMessage`, `formControl`
12
11
 
13
- - `selectOptions`: `SelectOption[]` — Array of options to display in the dropdown. **(Required)**
14
- - `selectionMode`: `'single' | 'multiple'` — Enables single or multiple selection mode. Default: `'single'`.
15
- - All standard form/label/validation-related inputs inherited from `QuangBaseComponent`:
16
- - `isReadonly`, `componentLabel`, `componentPlaceholder`, `componentTabIndex`, `componentClass`, `errorMap`, `successMessage`, `helpMessage`, `formControl`
12
+ ## Output
17
13
 
18
- ## Outputs
19
-
20
- - All standard outputs inherited from `QuangBaseComponent`:
21
- - `componentBlur`
14
+ All standard outputs inherited from `QuangBaseComponent`: `componentBlur`
22
15
 
23
16
  ## Usage
24
17
 
18
+ ### Single Selection
25
19
  ```html
26
20
  <quang-select
27
21
  [errorMap]="errors()"
28
- [isReadonly]="isReadonly()"
29
22
  [selectOptions]="stringList"
30
- class="col-4"
31
23
  componentLabel="form.label.select"
32
- componentPlaceholder="Placeholder select singola scelta"
24
+ componentPlaceholder="Select an option"
33
25
  formControlName="testInput"
34
- playgroundSourceCode
35
- selectionMode="single"
36
- successMessage="form.label.success"
37
- />
26
+ selectionMode="single">
27
+ </quang-select>
28
+ ```
38
29
 
30
+ ### Multiple Selection
31
+ ```html
39
32
  <quang-select
40
33
  [errorMap]="errors()"
41
- [isReadonly]="isReadonly()"
42
34
  [selectOptions]="numberList"
43
- class="col-4"
44
35
  componentLabel="form.label.multipleSelect"
45
- componentPlaceholder="Placeholder select scelta multipla"
36
+ componentPlaceholder="Select multiple options"
46
37
  formControlName="testInputMultiple"
47
- selectionMode="multiple"
48
- successMessage="form.label.success"
49
- />
38
+ selectionMode="multiple">
39
+ </quang-select>
50
40
  ```
51
41
 
52
- ## Notes
42
+ ## QuangTranslationService Integration
53
43
 
54
- This component extends the `QuangBaseComponent` and inherits its features, such as label and validation messages.
44
+ The component supports automatic translation of all labels, help messages, and error messages through `QuangTranslationService`.
@@ -2,29 +2,21 @@
2
2
 
3
3
  The `QuangWysiwygComponent` is a rich text editor based on [SunEditor](https://github.com/JiHong88/SunEditor), offering a wide range of formatting options for creating and editing HTML content.
4
4
 
5
- ## Features
5
+ ## Input
6
6
 
7
- - Rich text editing
8
- - Wide range of formatting options
9
- - Supports custom toolbars and plugins
7
+ - `wysiwygOptions`: `object` - Configuration options for the editor (required)
8
+ - `minHeight`: `string | undefined` - Minimum height for the editor area (default: '200px')
9
+ - `highlightColor`: `boolean` - Show/hide the highlight color button in toolbar (default: true)
10
+ - `isReadonly`: `boolean` - If true, the editor is readonly
11
+ - `onImageUploadError`: `(errorMessage: any, result: any, core: any) => boolean` - Callback for image upload errors
12
+ - `onFileDrop`: `(e: any, cleanData: any, maxCharCount: any, core: any) => boolean` - Callback for file drop events
13
+ - Toolbar button toggles (all `boolean`, default: `true`): `font`, `fontSize`, `formatBlock`, `paragraphStyle`, `blockquote`, `bold`, `underline`, `italic`, `strike`, `fontColor`, `textStyle`, `removeFormat`, `align`, `list`, `table`, `link`, `image`, `fullScreen`, `showBlocks`
10
14
 
11
- ## Inputs
15
+ All standard inputs inherited from `QuangBaseComponent`: `componentLabel`, `componentPlaceholder`, `componentTabIndex`, `componentClass`, `errorMap`, `successMessage`, `helpMessage`, `formControl`
12
16
 
13
- - `wysiwygOptions`: `object` — Configuration options for the editor. **(Required)**
14
- - `minHeight`: `string | undefined` — Minimum height for the editor area. Default: `'200px'`.
15
- - `highlightColor`: `boolean` — Show/hide the highlight color button in the toolbar. Default: `true`.
16
- - `isReadonly`: `boolean` — If true, the editor is readonly.
17
- - `onImageUploadError`: `(errorMessage: any, result: any, core: any) => boolean` — Callback for image upload errors.
18
- - `onFileDrop`: `(e: any, cleanData: any, maxCharCount: any, core: any) => boolean` — Callback for file drop events.
19
- - Toolbar button toggles (all `boolean`, default: `true`):
20
- - `font`, `fontSize`, `formatBlock`, `paragraphStyle`, `blockquote`, `bold`, `underline`, `italic`, `strike`, `fontColor`, `textStyle`, `removeFormat`, `align`, `list`, `table`, `link`, `image`, `fullScreen`, `showBlocks`
21
- - All standard form/label/validation-related inputs inherited from `QuangBaseComponent`:
22
- - `componentLabel`, `componentPlaceholder`, `componentTabIndex`, `componentClass`, `errorMap`, `successMessage`, `helpMessage`, `formControl`
17
+ ## Output
23
18
 
24
- ## Outputs
25
-
26
- - All standard outputs inherited from `QuangBaseComponent`:
27
- - `componentBlur`
19
+ All standard outputs inherited from `QuangBaseComponent`: `componentBlur`
28
20
 
29
21
  ## Usage
30
22
 
@@ -45,11 +37,7 @@ The `QuangWysiwygComponent` is a rich text editor based on [SunEditor](https://g
45
37
  ### Note
46
38
 
47
39
  Remember to import:
48
-
49
40
  `node_modules/quang/components/wysiwyg/global-wysiswyg.component.scss`
50
-
51
41
  or
52
-
53
42
  `quang/components/wysiwyg/global-wysiswyg.component.scss`
54
-
55
43
  in your global style (suggested "vendors" folder).
@@ -1,6 +1,6 @@
1
1
  import { NgClass } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { input, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { input, output, signal, computed, forwardRef, ChangeDetectionStrategy, Component } from '@angular/core';
4
4
  import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import { TranslocoPipe } from '@jsverse/transloco';
@@ -20,20 +20,29 @@ class QuangInputComponent extends QuangBaseComponent {
20
20
  this.maxNumber = input(undefined);
21
21
  this.componentStep = input(1);
22
22
  this.resizable = input(true);
23
+ this.buttonClass = input('');
24
+ this.showHidePasswordButton = input(true);
25
+ this.showPassword = output();
26
+ this.onShowPassword = signal(false);
27
+ this.componentInputType = computed(() => this.componentType() === 'password' && this.onShowPassword() ? 'text' : this.componentType());
23
28
  toObservable(this.componentType)
24
29
  .pipe(takeUntilDestroyed(this.destroyRef))
25
30
  .subscribe(() => {
26
31
  this.setupFormControl();
27
32
  });
28
33
  }
34
+ onTogglePasswordVisibility() {
35
+ this.onShowPassword.update((current) => !current);
36
+ this.showPassword.emit(this.onShowPassword());
37
+ }
29
38
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: QuangInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
30
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: QuangInputComponent, isStandalone: true, selector: "quang-input", inputs: { componentType: { classPropertyName: "componentType", publicName: "componentType", isSignal: true, isRequired: true, transformFunction: null }, maxLengthText: { classPropertyName: "maxLengthText", publicName: "maxLengthText", isSignal: true, isRequired: false, transformFunction: null }, minLengthText: { classPropertyName: "minLengthText", publicName: "minLengthText", isSignal: true, isRequired: false, transformFunction: null }, minNumber: { classPropertyName: "minNumber", publicName: "minNumber", isSignal: true, isRequired: false, transformFunction: null }, maxNumber: { classPropertyName: "maxNumber", publicName: "maxNumber", isSignal: true, isRequired: false, transformFunction: null }, componentStep: { classPropertyName: "componentStep", publicName: "componentStep", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
39
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: QuangInputComponent, isStandalone: true, selector: "quang-input", inputs: { componentType: { classPropertyName: "componentType", publicName: "componentType", isSignal: true, isRequired: true, transformFunction: null }, maxLengthText: { classPropertyName: "maxLengthText", publicName: "maxLengthText", isSignal: true, isRequired: false, transformFunction: null }, minLengthText: { classPropertyName: "minLengthText", publicName: "minLengthText", isSignal: true, isRequired: false, transformFunction: null }, minNumber: { classPropertyName: "minNumber", publicName: "minNumber", isSignal: true, isRequired: false, transformFunction: null }, maxNumber: { classPropertyName: "maxNumber", publicName: "maxNumber", isSignal: true, isRequired: false, transformFunction: null }, componentStep: { classPropertyName: "componentStep", publicName: "componentStep", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, buttonClass: { classPropertyName: "buttonClass", publicName: "buttonClass", isSignal: true, isRequired: false, transformFunction: null }, showHidePasswordButton: { classPropertyName: "showHidePasswordButton", publicName: "showHidePasswordButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { showPassword: "showPassword" }, providers: [
31
40
  {
32
41
  provide: NG_VALUE_ACCESSOR,
33
42
  useExisting: forwardRef(() => QuangInputComponent),
34
43
  multi: true,
35
44
  },
36
- ], usesInheritance: true, ngImport: i0, template: "@if (componentType()) {\n <div class=\"mb-3\">\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label\"\n >\n {{ componentLabel() | transloco }}\n <span [hidden]=\"!_isRequired()\">*</span>\n </label>\n }\n @if (componentType() !== 'textarea') {\n <input\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [max]=\"maxNumber()\"\n [min]=\"minNumber()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [step]=\"componentStep()\"\n [tabIndex]=\"componentTabIndex()\"\n [type]=\"componentType()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n autocomplete=\"off\"\n class=\"form-control\"\n />\n }\n @if (componentType() === 'textarea') {\n <textarea\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.no-resize]=\"!resizable()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n class=\"form-control\"\n ></textarea>\n }\n <div class=\"valid-feedback\">\n {{ successMessage() | transloco }}\n </div>\n <div class=\"invalid-feedback\">\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n </div>\n}\n", styles: ["input::-webkit-search-cancel-button{-webkit-appearance:none;height:.75rem;width:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 3 1024 1024' width='12' height='12' fill='currentColor'%3E%3Cpath d='M9 1018q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5l459-459 459 459q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5 9-9 9-22 0-13-9-22l-459-459 459-459q9-9 9-22 0-13-9-22-9-9-22-9-13 0-22 9l-459 459-459-459q-9-9-22-9-13 0-22 9-9 9-9 22 0 13 9 22l459 459-459 459q-9 9-9 22 0 13 9 22l0 0z'/%3E%3C/svg%3E%0A\");cursor:pointer}:host{display:block}.no-resize{resize:none}\n"], dependencies: [{ kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
45
+ ], usesInheritance: true, ngImport: i0, template: "@if (componentType()) {\n <div class=\"mb-3\">\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label\"\n >\n {{ componentLabel() | transloco }}\n <span [hidden]=\"!_isRequired()\">*</span>\n </label>\n }\n @if (componentType() !== 'textarea') {\n <div class=\"input-container\">\n <input\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.with-button-password]=\"showHidePasswordButton()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [max]=\"maxNumber()\"\n [min]=\"minNumber()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [step]=\"componentStep()\"\n [tabIndex]=\"componentTabIndex()\"\n [type]=\"componentInputType()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n autocomplete=\"off\"\n class=\"form-control\"\n />\n @if (componentType() === 'password' && showHidePasswordButton()) {\n <button\n [class.border-danger]=\"_showErrors()\"\n [class.border-success]=\"_showSuccess()\"\n [ngClass]=\"buttonClass()\"\n (click)=\"_ngControl()?.disabled ? null : onTogglePasswordVisibility()\"\n #calendarButton\n aria-label=\"calendar-button\"\n class=\"btn btn-outline-secondary btn-outline-password\"\n type=\"button\"\n >\n <ng-content></ng-content>\n </button>\n }\n </div>\n }\n @if (componentType() === 'textarea') {\n <textarea\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.no-resize]=\"!resizable()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n class=\"form-control\"\n ></textarea>\n }\n <div class=\"valid-feedback\">\n {{ successMessage() | transloco }}\n </div>\n <div class=\"invalid-feedback\">\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n </div>\n}\n", styles: ["input::-webkit-search-cancel-button{-webkit-appearance:none;height:.75rem;width:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 3 1024 1024' width='12' height='12' fill='currentColor'%3E%3Cpath d='M9 1018q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5l459-459 459 459q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5 9-9 9-22 0-13-9-22l-459-459 459-459q9-9 9-22 0-13-9-22-9-9-22-9-13 0-22 9l-459 459-459-459q-9-9-22-9-13 0-22 9-9 9-9 22 0 13 9 22l459 459-459 459q-9 9-9 22 0 13 9 22l0 0z'/%3E%3C/svg%3E%0A\");cursor:pointer}:host{display:block}.no-resize{resize:none}.btn-outline-password{border-left:0;border-top-left-radius:0;border-bottom-left-radius:0;min-width:unset;display:flex;border-color:var(--bs-border-color)}.input-container{display:flex}input{flex:1}input.with-button-password{border-top-right-radius:0;border-bottom-right-radius:0}input:disabled{border-radius:var(--bs-border-radius)}.border-danger{border-color:var(--bs-form-invalid-border-color)}.border-success{border-color:var(--bs-form-valid-border-color)}\n"], dependencies: [{ kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
37
46
  }
38
47
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: QuangInputComponent, decorators: [{
39
48
  type: Component,
@@ -43,7 +52,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
43
52
  useExisting: forwardRef(() => QuangInputComponent),
44
53
  multi: true,
45
54
  },
46
- ], imports: [TranslocoPipe, NgClass], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (componentType()) {\n <div class=\"mb-3\">\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label\"\n >\n {{ componentLabel() | transloco }}\n <span [hidden]=\"!_isRequired()\">*</span>\n </label>\n }\n @if (componentType() !== 'textarea') {\n <input\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [max]=\"maxNumber()\"\n [min]=\"minNumber()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [step]=\"componentStep()\"\n [tabIndex]=\"componentTabIndex()\"\n [type]=\"componentType()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n autocomplete=\"off\"\n class=\"form-control\"\n />\n }\n @if (componentType() === 'textarea') {\n <textarea\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.no-resize]=\"!resizable()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n class=\"form-control\"\n ></textarea>\n }\n <div class=\"valid-feedback\">\n {{ successMessage() | transloco }}\n </div>\n <div class=\"invalid-feedback\">\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n </div>\n}\n", styles: ["input::-webkit-search-cancel-button{-webkit-appearance:none;height:.75rem;width:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 3 1024 1024' width='12' height='12' fill='currentColor'%3E%3Cpath d='M9 1018q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5l459-459 459 459q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5 9-9 9-22 0-13-9-22l-459-459 459-459q9-9 9-22 0-13-9-22-9-9-22-9-13 0-22 9l-459 459-459-459q-9-9-22-9-13 0-22 9-9 9-9 22 0 13 9 22l459 459-459 459q-9 9-9 22 0 13 9 22l0 0z'/%3E%3C/svg%3E%0A\");cursor:pointer}:host{display:block}.no-resize{resize:none}\n"] }]
55
+ ], imports: [TranslocoPipe, NgClass], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (componentType()) {\n <div class=\"mb-3\">\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label\"\n >\n {{ componentLabel() | transloco }}\n <span [hidden]=\"!_isRequired()\">*</span>\n </label>\n }\n @if (componentType() !== 'textarea') {\n <div class=\"input-container\">\n <input\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.with-button-password]=\"showHidePasswordButton()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [max]=\"maxNumber()\"\n [min]=\"minNumber()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [step]=\"componentStep()\"\n [tabIndex]=\"componentTabIndex()\"\n [type]=\"componentInputType()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n autocomplete=\"off\"\n class=\"form-control\"\n />\n @if (componentType() === 'password' && showHidePasswordButton()) {\n <button\n [class.border-danger]=\"_showErrors()\"\n [class.border-success]=\"_showSuccess()\"\n [ngClass]=\"buttonClass()\"\n (click)=\"_ngControl()?.disabled ? null : onTogglePasswordVisibility()\"\n #calendarButton\n aria-label=\"calendar-button\"\n class=\"btn btn-outline-secondary btn-outline-password\"\n type=\"button\"\n >\n <ng-content></ng-content>\n </button>\n }\n </div>\n }\n @if (componentType() === 'textarea') {\n <textarea\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.no-resize]=\"!resizable()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n class=\"form-control\"\n ></textarea>\n }\n <div class=\"valid-feedback\">\n {{ successMessage() | transloco }}\n </div>\n <div class=\"invalid-feedback\">\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n </div>\n}\n", styles: ["input::-webkit-search-cancel-button{-webkit-appearance:none;height:.75rem;width:.75rem;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 3 1024 1024' width='12' height='12' fill='currentColor'%3E%3Cpath d='M9 1018q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5l459-459 459 459q5 4 10.5 6.5 5.5 2.5 11.5 2.5 6 0 11.5-2.5 5.5-2.5 10.5-6.5 9-9 9-22 0-13-9-22l-459-459 459-459q9-9 9-22 0-13-9-22-9-9-22-9-13 0-22 9l-459 459-459-459q-9-9-22-9-13 0-22 9-9 9-9 22 0 13 9 22l459 459-459 459q-9 9-9 22 0 13 9 22l0 0z'/%3E%3C/svg%3E%0A\");cursor:pointer}:host{display:block}.no-resize{resize:none}.btn-outline-password{border-left:0;border-top-left-radius:0;border-bottom-left-radius:0;min-width:unset;display:flex;border-color:var(--bs-border-color)}.input-container{display:flex}input{flex:1}input.with-button-password{border-top-right-radius:0;border-bottom-right-radius:0}input:disabled{border-radius:var(--bs-border-radius)}.border-danger{border-color:var(--bs-form-invalid-border-color)}.border-success{border-color:var(--bs-form-valid-border-color)}\n"] }]
47
56
  }], ctorParameters: () => [] });
48
57
 
49
58
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"quang-components-input.mjs","sources":["../../../projects/quang/components/input/input.component.ts","../../../projects/quang/components/input/input.component.html","../../../projects/quang/components/input/quang-components-input.ts"],"sourcesContent":["import { NgClass } from '@angular/common'\nimport { ChangeDetectionStrategy, Component, forwardRef, input } from '@angular/core'\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'\nimport { NG_VALUE_ACCESSOR } from '@angular/forms'\n\nimport { TranslocoPipe } from '@jsverse/transloco'\n\nimport { QuangBaseComponent } from 'quang/components/shared'\n\nexport type InputType = 'text' | 'textarea' | 'password' | 'email' | 'number' | 'url' | 'search' | 'tel' | 'color'\n\n@Component({\n selector: 'quang-input',\n templateUrl: './input.component.html',\n styleUrl: './input.component.scss',\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => QuangInputComponent),\n multi: true,\n },\n ],\n imports: [TranslocoPipe, NgClass],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Input component that handles all the types declared in {@link InputType}\n * @property {boolean} resizable just for textarea {@link InputType}\n */\nexport class QuangInputComponent extends QuangBaseComponent<string | number> {\n componentType = input.required<InputType>()\n\n maxLengthText = input<number | null>(null)\n\n minLengthText = input<number | null>(null)\n\n minNumber = input<number | undefined>(undefined)\n\n maxNumber = input<number | undefined>(undefined)\n\n componentStep = input<number>(1)\n\n resizable = input(true)\n\n constructor() {\n super()\n toObservable(this.componentType)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n this.setupFormControl()\n })\n }\n}\n","@if (componentType()) {\n <div class=\"mb-3\">\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label\"\n >\n {{ componentLabel() | transloco }}\n <span [hidden]=\"!_isRequired()\">*</span>\n </label>\n }\n @if (componentType() !== 'textarea') {\n <input\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [max]=\"maxNumber()\"\n [min]=\"minNumber()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [step]=\"componentStep()\"\n [tabIndex]=\"componentTabIndex()\"\n [type]=\"componentType()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n autocomplete=\"off\"\n class=\"form-control\"\n />\n }\n @if (componentType() === 'textarea') {\n <textarea\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.no-resize]=\"!resizable()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n class=\"form-control\"\n ></textarea>\n }\n <div class=\"valid-feedback\">\n {{ successMessage() | transloco }}\n </div>\n <div class=\"invalid-feedback\">\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quang-components-input.mjs","sources":["../../../projects/quang/components/input/input.component.ts","../../../projects/quang/components/input/input.component.html","../../../projects/quang/components/input/quang-components-input.ts"],"sourcesContent":["import { NgClass } from '@angular/common'\nimport { ChangeDetectionStrategy, Component, computed, forwardRef, input, output, signal } from '@angular/core'\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'\nimport { NG_VALUE_ACCESSOR } from '@angular/forms'\n\nimport { TranslocoPipe } from '@jsverse/transloco'\n\nimport { QuangBaseComponent } from 'quang/components/shared'\n\nexport type InputType = 'text' | 'textarea' | 'password' | 'email' | 'number' | 'url' | 'search' | 'tel' | 'color'\n\n@Component({\n selector: 'quang-input',\n templateUrl: './input.component.html',\n styleUrl: './input.component.scss',\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => QuangInputComponent),\n multi: true,\n },\n ],\n imports: [TranslocoPipe, NgClass],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Input component that handles all the types declared in {@link InputType}\n * @property {boolean} resizable just for textarea {@link InputType}\n */\nexport class QuangInputComponent extends QuangBaseComponent<string | number> {\n componentType = input.required<InputType>()\n\n maxLengthText = input<number | null>(null)\n\n minLengthText = input<number | null>(null)\n\n minNumber = input<number | undefined>(undefined)\n\n maxNumber = input<number | undefined>(undefined)\n\n componentStep = input<number>(1)\n\n resizable = input(true)\n\n buttonClass = input<string>('')\n\n showHidePasswordButton = input(true)\n\n showPassword = output<boolean>()\n\n private onShowPassword = signal<boolean>(false)\n\n componentInputType = computed<InputType>(() =>\n this.componentType() === 'password' && this.onShowPassword() ? 'text' : this.componentType()\n )\n\n constructor() {\n super()\n toObservable(this.componentType)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n this.setupFormControl()\n })\n }\n\n onTogglePasswordVisibility(): void {\n this.onShowPassword.update((current) => !current)\n this.showPassword.emit(this.onShowPassword())\n }\n}\n","@if (componentType()) {\n <div class=\"mb-3\">\n @if (componentLabel()) {\n <label\n [htmlFor]=\"componentId()\"\n class=\"form-label\"\n >\n {{ componentLabel() | transloco }}\n <span [hidden]=\"!_isRequired()\">*</span>\n </label>\n }\n @if (componentType() !== 'textarea') {\n <div class=\"input-container\">\n <input\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [attr.required]=\"getIsRequiredControl()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.with-button-password]=\"showHidePasswordButton()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [max]=\"maxNumber()\"\n [min]=\"minNumber()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [step]=\"componentStep()\"\n [tabIndex]=\"componentTabIndex()\"\n [type]=\"componentInputType()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n autocomplete=\"off\"\n class=\"form-control\"\n />\n @if (componentType() === 'password' && showHidePasswordButton()) {\n <button\n [class.border-danger]=\"_showErrors()\"\n [class.border-success]=\"_showSuccess()\"\n [ngClass]=\"buttonClass()\"\n (click)=\"_ngControl()?.disabled ? null : onTogglePasswordVisibility()\"\n #calendarButton\n aria-label=\"calendar-button\"\n class=\"btn btn-outline-secondary btn-outline-password\"\n type=\"button\"\n >\n <ng-content></ng-content>\n </button>\n }\n </div>\n }\n @if (componentType() === 'textarea') {\n <textarea\n [attr.maxLength]=\"maxLengthText()\"\n [attr.minLength]=\"minLengthText()\"\n [class.is-invalid]=\"_showErrors()\"\n [class.is-valid]=\"_showSuccess()\"\n [class.no-resize]=\"!resizable()\"\n [disabled]=\"_isDisabled()\"\n [id]=\"componentId()\"\n [ngClass]=\"componentClass()\"\n [placeholder]=\"componentPlaceholder() | transloco\"\n [readOnly]=\"isReadonly()\"\n [tabIndex]=\"componentTabIndex()\"\n [value]=\"_value()\"\n (blur)=\"onBlurHandler()\"\n (input)=\"onChangedEventHandler($event)\"\n class=\"form-control\"\n ></textarea>\n }\n <div class=\"valid-feedback\">\n {{ successMessage() | transloco }}\n </div>\n <div class=\"invalid-feedback\">\n {{ _currentErrorMessage() | transloco: _currentErrorMessageExtraData() }}\n </div>\n @if (helpMessage()) {\n <small\n [hidden]=\"_showSuccess() || _showErrors()\"\n aria-live=\"assertive\"\n class=\"form-text text-muted\"\n >\n {{ helpMessage() | transloco }}\n </small>\n }\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}