@ng-zen/cli 20.0.0 → 20.1.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/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/schematics/components/components-generator.js.map +1 -1
- package/schematics/components/components-generator.ts +1 -0
- package/schematics/components/files/checkbox/checkbox.stories.ts +4 -4
- package/schematics/components/files/checkbox/checkbox.ts +22 -53
- package/schematics/components/files/form-control/form-control.spec.ts +31 -0
- package/schematics/components/files/form-control/form-control.stories.ts +37 -0
- package/schematics/components/files/form-control/form-control.ts +116 -0
- package/schematics/components/files/form-control/index.ts +1 -0
- package/schematics/components/files/input/input.stories.ts +0 -3
- package/schematics/components/files/input/input.ts +8 -55
- package/schematics/components/files/switch/switch.ts +10 -65
- package/schematics/components/schema.json +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [20.1.0](https://github.com/kstepien3/ng-zen/compare/v20.0.0...v20.1.0) (2025-08-04)
|
|
2
|
+
|
|
3
|
+
### 🚀 New Features
|
|
4
|
+
|
|
5
|
+
* **checkbox:** add indeterminate state if value is null ([#260](https://github.com/kstepien3/ng-zen/issues/260)) ([d13c241](https://github.com/kstepien3/ng-zen/commit/d13c2416984df1de188082760aadfe280c7ed315))
|
|
6
|
+
* **form-control:** add abstract logic for form control components ([#252](https://github.com/kstepien3/ng-zen/issues/252)) ([10e66b4](https://github.com/kstepien3/ng-zen/commit/10e66b4b0606a05d02ba527de42407129e085cbe))
|
|
7
|
+
|
|
8
|
+
## [20.1.0-next.1](https://github.com/kstepien3/ng-zen/compare/v20.0.0...v20.1.0-next.1) (2025-07-30)
|
|
9
|
+
|
|
10
|
+
### 🚀 New Features
|
|
11
|
+
|
|
12
|
+
* **checkbox:** add indeterminate state if value is null ([#260](https://github.com/kstepien3/ng-zen/issues/260)) ([d13c241](https://github.com/kstepien3/ng-zen/commit/d13c2416984df1de188082760aadfe280c7ed315))
|
|
13
|
+
* **form-control:** add abstract logic for form control components ([#252](https://github.com/kstepien3/ng-zen/issues/252)) ([10e66b4](https://github.com/kstepien3/ng-zen/commit/10e66b4b0606a05d02ba527de42407129e085cbe))
|
|
14
|
+
|
|
1
15
|
## [20.0.0](https://github.com/kstepien3/ng-zen/compare/v19.4.0...v20.0.0) (2025-07-22)
|
|
2
16
|
|
|
3
17
|
### ⚠ BREAKING CHANGES
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components-generator.js","sourceRoot":"","sources":["../../../../../src/schematics/components/components-generator.ts"],"names":[],"mappings":"","sourcesContent":["import { GeneratorSchemaBase } from '../../types';\n\nexport type ComponentType =\n | 'avatar'\n | 'button'\n | 'checkbox'\n | 'divider'\n | 'icon'\n | 'input'\n | 'skeleton'\n | 'switch'\n | 'textarea';\n\nexport interface ComponentGeneratorSchema extends GeneratorSchemaBase {\n components: ComponentType[];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"components-generator.js","sourceRoot":"","sources":["../../../../../src/schematics/components/components-generator.ts"],"names":[],"mappings":"","sourcesContent":["import { GeneratorSchemaBase } from '../../types';\n\nexport type ComponentType =\n | 'avatar'\n | 'button'\n | 'checkbox'\n | 'divider'\n | 'form-control'\n | 'icon'\n | 'input'\n | 'skeleton'\n | 'switch'\n | 'textarea';\n\nexport interface ComponentGeneratorSchema extends GeneratorSchemaBase {\n components: ComponentType[];\n}\n"]}
|
|
@@ -7,16 +7,17 @@ export default {
|
|
|
7
7
|
component: ZenCheckbox,
|
|
8
8
|
tags: ['autodocs'],
|
|
9
9
|
argTypes: {
|
|
10
|
-
value: {
|
|
10
|
+
value: {
|
|
11
|
+
control: 'radio',
|
|
12
|
+
options: [true, false, null],
|
|
13
|
+
},
|
|
11
14
|
disabled: { control: 'boolean' },
|
|
12
15
|
required: { control: 'boolean' },
|
|
13
|
-
id: { control: 'text' },
|
|
14
16
|
},
|
|
15
17
|
args: {
|
|
16
18
|
value: false,
|
|
17
19
|
disabled: false,
|
|
18
20
|
required: false,
|
|
19
|
-
id: '',
|
|
20
21
|
},
|
|
21
22
|
} satisfies Meta<ZenCheckbox>;
|
|
22
23
|
|
|
@@ -29,7 +30,6 @@ export const Default: Story = {
|
|
|
29
30
|
<zen-checkbox
|
|
30
31
|
[disabled]="${args.disabled}"
|
|
31
32
|
[value]="${args.value}"
|
|
32
|
-
${args.id ? 'id="' + args.id + '"' : ''}
|
|
33
33
|
${args.required ? 'required' : ''}
|
|
34
34
|
/>`,
|
|
35
35
|
}),
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ChangeDetectionStrategy, Component, effect, ElementRef, model, viewChild } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
|
|
4
|
+
import { ZenFormControl, ZenFormControlProvider } from '../form-control';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* ZenCheckbox is a reusable checkbox component designed to provide
|
|
@@ -8,7 +10,9 @@ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/f
|
|
|
8
10
|
* for boolean values.
|
|
9
11
|
*
|
|
10
12
|
* @example
|
|
11
|
-
* <zen-checkbox value="
|
|
13
|
+
* <zen-checkbox [value]="true" /> Checked
|
|
14
|
+
* <zen-checkbox [value]="false" /> Unchecked
|
|
15
|
+
* <zen-checkbox [value]="null" /> Indeterminate
|
|
12
16
|
*
|
|
13
17
|
* ### CSS Custom Properties
|
|
14
18
|
*
|
|
@@ -25,7 +29,7 @@ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/f
|
|
|
25
29
|
* }
|
|
26
30
|
* ```
|
|
27
31
|
*
|
|
28
|
-
* @implements {
|
|
32
|
+
* @implements {ZenFormControl<boolean>}
|
|
29
33
|
*
|
|
30
34
|
* @author Konrad Stępień
|
|
31
35
|
* @license {@link https://github.com/kstepien3/ng-zen/blob/master/LICENSE|BSD-2-Clause}
|
|
@@ -37,10 +41,9 @@ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/f
|
|
|
37
41
|
template: `
|
|
38
42
|
<input
|
|
39
43
|
[attr.aria-disabled]="disabled()"
|
|
40
|
-
[attr.id]="id()"
|
|
41
44
|
[disabled]="disabled()"
|
|
42
45
|
[ngModel]="value()"
|
|
43
|
-
(ngModelChange)="
|
|
46
|
+
(ngModelChange)="onInput($event)"
|
|
44
47
|
#inputElement
|
|
45
48
|
type="checkbox"
|
|
46
49
|
/>
|
|
@@ -54,59 +57,25 @@ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/f
|
|
|
54
57
|
styleUrls: ['./checkbox.scss'],
|
|
55
58
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
56
59
|
imports: [FormsModule],
|
|
57
|
-
providers: [
|
|
58
|
-
{
|
|
59
|
-
provide: NG_VALUE_ACCESSOR,
|
|
60
|
-
useExisting: forwardRef(() => ZenCheckbox),
|
|
61
|
-
multi: true,
|
|
62
|
-
},
|
|
63
|
-
],
|
|
60
|
+
providers: [ZenFormControlProvider(ZenCheckbox)],
|
|
64
61
|
host: {
|
|
65
62
|
'(blur)': 'onTouched()',
|
|
66
63
|
},
|
|
67
64
|
})
|
|
68
|
-
export class ZenCheckbox
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
readonly required = input(false, { transform: booleanAttribute });
|
|
75
|
-
/** Sets the HTML id attribute for the checkbox element. */
|
|
76
|
-
readonly id = input<string>();
|
|
77
|
-
|
|
78
|
-
/** @ignore */
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
80
|
-
onChange: (value: boolean) => void = () => {};
|
|
81
|
-
/** @ignore */
|
|
82
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
83
|
-
onTouched: () => void = () => {};
|
|
84
|
-
|
|
85
|
-
/** @ignore */
|
|
86
|
-
writeValue(value: boolean): void {
|
|
87
|
-
this.value.set(value);
|
|
88
|
-
}
|
|
89
|
-
|
|
65
|
+
export class ZenCheckbox extends ZenFormControl<boolean | null> {
|
|
66
|
+
/**
|
|
67
|
+
* Holds the current checkbox value.
|
|
68
|
+
* Set value to `null` to mark the checkbox as indeterminate
|
|
69
|
+
*/
|
|
70
|
+
readonly value = model<boolean | null>(false);
|
|
90
71
|
/** @ignore */
|
|
91
|
-
|
|
92
|
-
this.onChange = fn;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** @ignore */
|
|
96
|
-
registerOnTouched(fn: () => void): void {
|
|
97
|
-
this.onTouched = fn;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** @ignore */
|
|
101
|
-
setDisabledState(isDisabled: boolean): void {
|
|
102
|
-
this.disabled.set(isDisabled);
|
|
103
|
-
}
|
|
72
|
+
private readonly inputElement = viewChild.required<ElementRef<HTMLInputElement>>('inputElement');
|
|
104
73
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (this.disabled()) return;
|
|
74
|
+
constructor() {
|
|
75
|
+
super();
|
|
108
76
|
|
|
109
|
-
|
|
110
|
-
|
|
77
|
+
effect(() => {
|
|
78
|
+
if (this.value() === null) this.inputElement().nativeElement.indeterminate = true;
|
|
79
|
+
});
|
|
111
80
|
}
|
|
112
81
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Component, model } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
|
|
4
|
+
import { ZenFormControl, ZenFormControlProvider } from './form-control';
|
|
5
|
+
|
|
6
|
+
@Component({
|
|
7
|
+
template: '...',
|
|
8
|
+
providers: [ZenFormControlProvider(FormControl)],
|
|
9
|
+
})
|
|
10
|
+
class FormControl extends ZenFormControl<string> {
|
|
11
|
+
readonly value = model<string>('');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('FormControl', () => {
|
|
15
|
+
let component: FormControl;
|
|
16
|
+
let fixture: ComponentFixture<FormControl>;
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
await TestBed.configureTestingModule({
|
|
20
|
+
imports: [FormControl],
|
|
21
|
+
}).compileComponents();
|
|
22
|
+
|
|
23
|
+
fixture = TestBed.createComponent(FormControl);
|
|
24
|
+
component = fixture.componentInstance;
|
|
25
|
+
fixture.detectChanges();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should create', () => {
|
|
29
|
+
expect(component).toBeTruthy();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Meta, moduleMetadata } from '@storybook/angular';
|
|
2
|
+
|
|
3
|
+
import { ZenCheckbox } from '../checkbox';
|
|
4
|
+
import { ZenInput } from '../input';
|
|
5
|
+
import { ZenSwitch } from '../switch';
|
|
6
|
+
import { ZenFormControl } from './form-control';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: 'Components/FormControl',
|
|
10
|
+
component: ZenFormControl,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
decorators: [moduleMetadata({ imports: [ZenCheckbox, ZenInput, ZenSwitch] })],
|
|
13
|
+
args: {
|
|
14
|
+
value: '',
|
|
15
|
+
disabled: false,
|
|
16
|
+
required: false,
|
|
17
|
+
},
|
|
18
|
+
argTypes: {
|
|
19
|
+
value: { control: false },
|
|
20
|
+
placeholder: { control: false },
|
|
21
|
+
disabled: { control: 'boolean' },
|
|
22
|
+
required: { control: 'boolean' },
|
|
23
|
+
},
|
|
24
|
+
parameters: {
|
|
25
|
+
docs: {
|
|
26
|
+
canvas: {
|
|
27
|
+
// This will remove the "show code" button
|
|
28
|
+
// https://storybook.js.org/docs/api/doc-blocks/doc-block-canvas#sourcestate
|
|
29
|
+
sourceState: 'none',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
} satisfies Meta<ZenFormControl<unknown>>;
|
|
34
|
+
|
|
35
|
+
export { Default as Checkbox } from '../checkbox/checkbox.stories';
|
|
36
|
+
export { Default as Input } from '../input/input.stories';
|
|
37
|
+
export { Default as Switch } from '../switch/switch.stories';
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { booleanAttribute, Directive, forwardRef, input, model, ModelSignal, Type } from '@angular/core';
|
|
2
|
+
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
export const ZenFormControlProvider = <T extends ZenFormControl<any>>(component: Type<T>) => ({
|
|
6
|
+
provide: NG_VALUE_ACCESSOR,
|
|
7
|
+
useExisting: forwardRef(() => component),
|
|
8
|
+
multi: true,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A base class for creating custom Angular form controls that integrate with both
|
|
13
|
+
* template-driven and reactive forms. It simplifies the implementation of the
|
|
14
|
+
* ControlValueAccessor interface by using signals for the control's value and state.
|
|
15
|
+
*
|
|
16
|
+
* Subclasses must provide an implementation for the abstract `value` property.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* @Component({
|
|
22
|
+
* template: '...',
|
|
23
|
+
* providers: [ZenFormControlProvider(ZenInput)]
|
|
24
|
+
* })
|
|
25
|
+
* export class Input extends ZenFormControl<string> {
|
|
26
|
+
* readonly value = model<string>('')
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @implements {ControlValueAccessor}
|
|
31
|
+
*
|
|
32
|
+
* @author Konrad Stępień
|
|
33
|
+
* @license {@link https://github.com/kstepien3/ng-zen/blob/master/LICENSE|BSD-2-Clause}
|
|
34
|
+
* @see [GitHub](https://github.com/kstepien3/ng-zen)
|
|
35
|
+
*/
|
|
36
|
+
@Directive({})
|
|
37
|
+
export abstract class ZenFormControl<Value> implements ControlValueAccessor {
|
|
38
|
+
/**
|
|
39
|
+
* The underlying value of the control.
|
|
40
|
+
* Subclasses must provide their own implementation, typically using `model()`.
|
|
41
|
+
*/
|
|
42
|
+
abstract readonly value: ModelSignal<Value>;
|
|
43
|
+
|
|
44
|
+
/** The placeholder text for the form control. */
|
|
45
|
+
readonly placeholder = input<string>();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Whether the form control is disabled.
|
|
49
|
+
*/
|
|
50
|
+
readonly disabled = model(false);
|
|
51
|
+
|
|
52
|
+
/** Whether the form control is required. */
|
|
53
|
+
readonly required = input(false, { transform: booleanAttribute });
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @internal For internal use by Angular forms.
|
|
57
|
+
* @ignore
|
|
58
|
+
*/
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
60
|
+
onChange: (value: Value) => void = () => {};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @internal For internal use by Angular forms.
|
|
64
|
+
* @ignore
|
|
65
|
+
*/
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
67
|
+
onTouched: () => void = () => {};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Should be called by the subclass when the control's value changes
|
|
71
|
+
* as a result of user interaction. This method updates the control's value
|
|
72
|
+
* and notifies Angular of the change.
|
|
73
|
+
*/
|
|
74
|
+
onInput(value: Value): void {
|
|
75
|
+
if (this.disabled()) return;
|
|
76
|
+
|
|
77
|
+
this.value.set(value);
|
|
78
|
+
this.onChange(this.value());
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Writes a new value to the element.
|
|
83
|
+
* @internal For internal use by Angular forms.
|
|
84
|
+
* @ignore
|
|
85
|
+
*/
|
|
86
|
+
writeValue(value: Value): void {
|
|
87
|
+
this.value.set(value);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Registers a callback function that is called when the control's value changes in the UI.
|
|
92
|
+
* @internal For internal use by Angular forms.
|
|
93
|
+
* @ignore
|
|
94
|
+
*/
|
|
95
|
+
registerOnChange(fn: (value: Value) => void): void {
|
|
96
|
+
this.onChange = fn;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Registers a callback function that is called by the forms API on component touch.
|
|
101
|
+
* @internal For internal use by Angular forms.
|
|
102
|
+
* @ignore
|
|
103
|
+
*/
|
|
104
|
+
registerOnTouched(fn: () => void): void {
|
|
105
|
+
this.onTouched = fn;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* This function is called by the forms API when the control status changes to or from "DISABLED".
|
|
110
|
+
* @internal For internal use by Angular forms.
|
|
111
|
+
* @ignore
|
|
112
|
+
*/
|
|
113
|
+
setDisabledState(isDisabled: boolean): void {
|
|
114
|
+
this.disabled.set(isDisabled);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './form-control';
|
|
@@ -11,14 +11,12 @@ export default {
|
|
|
11
11
|
placeholder: { control: 'text' },
|
|
12
12
|
disabled: { control: 'boolean' },
|
|
13
13
|
required: { control: 'boolean' },
|
|
14
|
-
id: { control: 'text' },
|
|
15
14
|
},
|
|
16
15
|
args: {
|
|
17
16
|
value: '',
|
|
18
17
|
placeholder: '',
|
|
19
18
|
disabled: false,
|
|
20
19
|
required: false,
|
|
21
|
-
id: '',
|
|
22
20
|
},
|
|
23
21
|
} satisfies Meta<ZenInput>;
|
|
24
22
|
|
|
@@ -31,7 +29,6 @@ export const Default: Story = {
|
|
|
31
29
|
<zen-input
|
|
32
30
|
[disabled]="${args.disabled}"
|
|
33
31
|
[value]="'${args.value}'"
|
|
34
|
-
${args.id ? 'id="' + args.id + '"' : ''}
|
|
35
32
|
${args.placeholder ? 'placeholder="' + args.placeholder + '"' : ''}
|
|
36
33
|
${args.required ? 'required' : ''}
|
|
37
34
|
/>`,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
|
|
4
|
+
import { ZenFormControl, ZenFormControlProvider } from '../form-control/form-control';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* ZenInput is a reusable text input component designed to provide
|
|
@@ -22,7 +24,7 @@ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/f
|
|
|
22
24
|
* }
|
|
23
25
|
* ```
|
|
24
26
|
*
|
|
25
|
-
* @implements {
|
|
27
|
+
* @implements {ZenFormControl<string>}
|
|
26
28
|
*
|
|
27
29
|
* @author Konrad Stępień
|
|
28
30
|
* @license {@link https://github.com/kstepien3/ng-zen/blob/master/LICENSE|BSD-2-Clause}
|
|
@@ -33,69 +35,20 @@ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/f
|
|
|
33
35
|
standalone: true,
|
|
34
36
|
template: `
|
|
35
37
|
<input
|
|
36
|
-
[attr.id]="id()"
|
|
37
38
|
[attr.placeholder]="placeholder()"
|
|
38
39
|
[attr.required]="required()"
|
|
39
40
|
[disabled]="disabled()"
|
|
40
41
|
[ngModel]="value()"
|
|
41
42
|
[value]="value()"
|
|
42
43
|
(blur)="onTouched()"
|
|
43
|
-
(ngModelChange)="
|
|
44
|
+
(ngModelChange)="onInput($event)"
|
|
44
45
|
/>
|
|
45
46
|
`,
|
|
46
47
|
styleUrls: ['./input.scss'],
|
|
47
48
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
48
|
-
providers: [
|
|
49
|
-
{
|
|
50
|
-
provide: NG_VALUE_ACCESSOR,
|
|
51
|
-
useExisting: forwardRef(() => ZenInput),
|
|
52
|
-
multi: true,
|
|
53
|
-
},
|
|
54
|
-
],
|
|
49
|
+
providers: [ZenFormControlProvider(ZenInput)],
|
|
55
50
|
imports: [FormsModule],
|
|
56
51
|
})
|
|
57
|
-
export class ZenInput
|
|
58
|
-
/** Holds the current input value. */
|
|
52
|
+
export class ZenInput extends ZenFormControl<string> {
|
|
59
53
|
readonly value = model('');
|
|
60
|
-
/** Determines if the input is disabled. */
|
|
61
|
-
readonly disabled = model(false);
|
|
62
|
-
/** Determines if the input is required.*/
|
|
63
|
-
readonly required = input(false, { transform: booleanAttribute });
|
|
64
|
-
/** Sets the HTML id attribute for the input element.*/
|
|
65
|
-
readonly id = input<string>();
|
|
66
|
-
/** Provides a hint or example text that will be displayed */
|
|
67
|
-
readonly placeholder = input<string>();
|
|
68
|
-
|
|
69
|
-
/** @ignore */
|
|
70
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
71
|
-
onChange: (value: string) => void = () => {};
|
|
72
|
-
/** @ignore */
|
|
73
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
74
|
-
onTouched: () => void = () => {};
|
|
75
|
-
|
|
76
|
-
/** @ignore */
|
|
77
|
-
writeValue(value: string): void {
|
|
78
|
-
this.value.set(value);
|
|
79
|
-
}
|
|
80
|
-
/** @ignore */
|
|
81
|
-
registerOnChange(fn: (value: string) => void): void {
|
|
82
|
-
this.onChange = fn;
|
|
83
|
-
}
|
|
84
|
-
/** @ignore */
|
|
85
|
-
registerOnTouched(fn: () => void): void {
|
|
86
|
-
this.onTouched = fn;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** @ignore */
|
|
90
|
-
setDisabledState(isDisabled: boolean): void {
|
|
91
|
-
this.disabled.set(isDisabled);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** Handles input change event */
|
|
95
|
-
onInputChange(value: string): void {
|
|
96
|
-
if (this.disabled()) return;
|
|
97
|
-
|
|
98
|
-
this.value.set(value);
|
|
99
|
-
this.onChange(value);
|
|
100
|
-
}
|
|
101
54
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component,
|
|
2
|
-
|
|
1
|
+
import { ChangeDetectionStrategy, Component, model } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
import { ZenFormControl, ZenFormControlProvider } from '../form-control';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* ZenInput is a reusable text input component designed to provide
|
|
@@ -25,7 +26,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
|
25
26
|
* }
|
|
26
27
|
* ```
|
|
27
28
|
*
|
|
28
|
-
* @implements {
|
|
29
|
+
* @implements {ZenFormControl<boolean>}
|
|
29
30
|
*
|
|
30
31
|
* @author Konrad Stępień
|
|
31
32
|
* @license {@link https://github.com/kstepien3/ng-zen/blob/master/LICENSE|BSD-2-Clause}
|
|
@@ -41,75 +42,19 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
|
41
42
|
`,
|
|
42
43
|
styleUrl: './switch.scss',
|
|
43
44
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
44
|
-
providers: [
|
|
45
|
-
{
|
|
46
|
-
provide: NG_VALUE_ACCESSOR,
|
|
47
|
-
useExisting: forwardRef(() => ZenSwitch),
|
|
48
|
-
multi: true,
|
|
49
|
-
},
|
|
50
|
-
],
|
|
45
|
+
providers: [ZenFormControlProvider(ZenSwitch)],
|
|
51
46
|
host: {
|
|
52
47
|
tabindex: '0',
|
|
53
48
|
'[attr.data-disabled]': 'disabled()',
|
|
54
49
|
'[attr.data-checked]': 'value()',
|
|
55
50
|
'(blur)': 'onTouched()',
|
|
56
|
-
'(click)': '
|
|
51
|
+
'(click)': 'onInput(!this.value())',
|
|
57
52
|
'(keydown)': 'onKeyDown($event)',
|
|
58
53
|
},
|
|
59
54
|
})
|
|
60
|
-
export class ZenSwitch
|
|
55
|
+
export class ZenSwitch extends ZenFormControl<boolean> {
|
|
61
56
|
/** Holds the current checkbox value. */
|
|
62
57
|
readonly value = model(false);
|
|
63
|
-
/** Determines if the checkbox is disabled. */
|
|
64
|
-
readonly disabled = model(false);
|
|
65
|
-
|
|
66
|
-
/** @ignore */
|
|
67
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
68
|
-
onChange: (value: boolean) => void = () => {};
|
|
69
|
-
/** @ignore */
|
|
70
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
71
|
-
onTouched: () => void = () => {};
|
|
72
|
-
/**
|
|
73
|
-
* Writes a new value to the component.
|
|
74
|
-
* @ignore
|
|
75
|
-
*/
|
|
76
|
-
writeValue(value: boolean): void {
|
|
77
|
-
this.value.set(value);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Registers a function to be called when the value changes.
|
|
82
|
-
* @ignore
|
|
83
|
-
*/
|
|
84
|
-
registerOnChange(fn: (value: boolean) => void): void {
|
|
85
|
-
this.onChange = fn;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Registers a function to be called when the component is touched.
|
|
90
|
-
* @ignore
|
|
91
|
-
*/
|
|
92
|
-
registerOnTouched(fn: () => void): void {
|
|
93
|
-
this.onTouched = fn;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Sets the disabled state of the component.
|
|
98
|
-
* @ignore
|
|
99
|
-
*/
|
|
100
|
-
setDisabledState(isDisabled: boolean): void {
|
|
101
|
-
this.disabled.set(isDisabled);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Toggles the switch value and notifies the change.
|
|
106
|
-
*/
|
|
107
|
-
onInputChange(value: boolean): void {
|
|
108
|
-
if (this.disabled()) return;
|
|
109
|
-
|
|
110
|
-
this.writeValue(value);
|
|
111
|
-
this.onChange(value);
|
|
112
|
-
}
|
|
113
58
|
|
|
114
59
|
/**
|
|
115
60
|
* Handles keyboard events for accessibility.
|
|
@@ -119,15 +64,15 @@ export class ZenSwitch implements ControlValueAccessor {
|
|
|
119
64
|
case 'Enter':
|
|
120
65
|
case 'Space': {
|
|
121
66
|
event.preventDefault();
|
|
122
|
-
this.
|
|
67
|
+
this.onInput(!this.value());
|
|
123
68
|
break;
|
|
124
69
|
}
|
|
125
70
|
case 'ArrowRight': {
|
|
126
|
-
this.
|
|
71
|
+
this.onInput(true);
|
|
127
72
|
break;
|
|
128
73
|
}
|
|
129
74
|
case 'ArrowLeft': {
|
|
130
|
-
this.
|
|
75
|
+
this.onInput(false);
|
|
131
76
|
break;
|
|
132
77
|
}
|
|
133
78
|
}
|
|
@@ -10,7 +10,18 @@
|
|
|
10
10
|
"type": "array",
|
|
11
11
|
"items": {
|
|
12
12
|
"type": "string",
|
|
13
|
-
"enum": [
|
|
13
|
+
"enum": [
|
|
14
|
+
"avatar",
|
|
15
|
+
"button",
|
|
16
|
+
"checkbox",
|
|
17
|
+
"divider",
|
|
18
|
+
"form-control",
|
|
19
|
+
"icon",
|
|
20
|
+
"input",
|
|
21
|
+
"skeleton",
|
|
22
|
+
"switch",
|
|
23
|
+
"textarea"
|
|
24
|
+
]
|
|
14
25
|
},
|
|
15
26
|
"multiselect": true,
|
|
16
27
|
"x-prompt": "Which component should be generated?"
|