diff --git a/examples/angular17-reactive-forms/.editorconfig b/examples/angular17-reactive-forms/.editorconfig new file mode 100644 index 0000000000..59d9a3a3e7 --- /dev/null +++ b/examples/angular17-reactive-forms/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/examples/angular17-reactive-forms/.gitignore b/examples/angular17-reactive-forms/.gitignore new file mode 100644 index 0000000000..f915cb55be --- /dev/null +++ b/examples/angular17-reactive-forms/.gitignore @@ -0,0 +1,2 @@ +.angular +.vscode \ No newline at end of file diff --git a/examples/angular17-reactive-forms/README.md b/examples/angular17-reactive-forms/README.md new file mode 100644 index 0000000000..648b6b0c44 --- /dev/null +++ b/examples/angular17-reactive-forms/README.md @@ -0,0 +1,27 @@ +# Angular17ReactiveForms + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.8. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/examples/angular17-reactive-forms/angular.json b/examples/angular17-reactive-forms/angular.json new file mode 100644 index 0000000000..90fc1c7f1b --- /dev/null +++ b/examples/angular17-reactive-forms/angular.json @@ -0,0 +1,96 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "angular17-reactive-forms": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": "dist/angular17-reactive-forms", + "index": "src/index.html", + "browser": "src/main.ts", + "polyfills": [ + "zone.js" + ], + "tsConfig": "tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css", + "node_modules/@telekom/scale-components/dist/scale-components/scale-components.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular17-reactive-forms:build:production" + }, + "development": { + "buildTarget": "angular17-reactive-forms:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular17-reactive-forms:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": [ + "zone.js", + "zone.js/testing" + ], + "tsConfig": "tsconfig.spec.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + } + } + } + } + } +} diff --git a/examples/angular17-reactive-forms/package.json b/examples/angular17-reactive-forms/package.json new file mode 100644 index 0000000000..a495477161 --- /dev/null +++ b/examples/angular17-reactive-forms/package.json @@ -0,0 +1,39 @@ +{ + "name": "angular17-reactive-forms", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "private": true, + "dependencies": { + "@angular/animations": "^17.0.0", + "@angular/common": "^17.0.0", + "@angular/compiler": "^17.0.0", + "@angular/core": "^17.0.0", + "@angular/forms": "^17.0.0", + "@angular/platform-browser": "^17.0.0", + "@angular/platform-browser-dynamic": "^17.0.0", + "@angular/router": "^17.0.0", + "@telekom/scale-components": "^3.0.0-beta.147", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.14.2" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^17.0.8", + "@angular/cli": "^17.0.8", + "@angular/compiler-cli": "^17.0.0", + "@types/jasmine": "~5.1.0", + "jasmine-core": "~5.1.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.2.2" + } +} diff --git a/examples/angular17-reactive-forms/src/app/app.component.css b/examples/angular17-reactive-forms/src/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/angular17-reactive-forms/src/app/app.component.html b/examples/angular17-reactive-forms/src/app/app.component.html new file mode 100644 index 0000000000..2b698b5dba --- /dev/null +++ b/examples/angular17-reactive-forms/src/app/app.component.html @@ -0,0 +1,66 @@ + + + + + + + + + + + +
+
+

+ +

+ +

+ +

+

+ +

+

+ + Foo + Bar + +

+ +

+ +

+ + console.log + Reset +
+ +
{{ signupForm.value | json }}
+
+ +
+ + + + + + + + + + + diff --git a/examples/angular17-reactive-forms/src/app/app.component.spec.ts b/examples/angular17-reactive-forms/src/app/app.component.spec.ts new file mode 100644 index 0000000000..b582e54280 --- /dev/null +++ b/examples/angular17-reactive-forms/src/app/app.component.spec.ts @@ -0,0 +1,29 @@ +import { TestBed } from '@angular/core/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AppComponent], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have the 'angular17-reactive-forms' title`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app.title).toEqual('angular17-reactive-forms'); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('h1')?.textContent).toContain('Hello, angular17-reactive-forms'); + }); +}); diff --git a/examples/angular17-reactive-forms/src/app/app.component.ts b/examples/angular17-reactive-forms/src/app/app.component.ts new file mode 100644 index 0000000000..c3052ced9c --- /dev/null +++ b/examples/angular17-reactive-forms/src/app/app.component.ts @@ -0,0 +1,33 @@ +import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterOutlet } from '@angular/router'; +import { ReactiveFormsModule, FormGroup, FormControl, UntypedFormControl } from '@angular/forms'; +import { CheckedValueAccessorDirective } from '../directives/checked-value-accessor'; +import { DateValueAccessorDirective } from '../directives/date-value-accessor'; +import { SelectValueAccessorDirective } from '../directives/select-value-accessor'; +import { NumberValueAccessorDirective } from '../directives/number-value-accessor'; +import { RadioValueAccessorDirective } from '../directives/radio-value-accessor'; +import { TextValueAccessorDirective } from '../directives/text-value-accessor'; +@Component({ + selector: 'app-root', + standalone: true, + imports: [CommonModule, RouterOutlet, ReactiveFormsModule, CheckedValueAccessorDirective, DateValueAccessorDirective, SelectValueAccessorDirective,TextValueAccessorDirective, RadioValueAccessorDirective, NumberValueAccessorDirective ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], // Telekom Scale + templateUrl: './app.component.html', + styleUrl: './app.component.css' +}) +export class AppComponent { + title = 'angular17-reactive-forms'; + signupForm = new FormGroup({ + username: new UntypedFormControl('admin'), + password: new UntypedFormControl({ value: '', disabled: false }), + consent: new UntypedFormControl(), + select: new UntypedFormControl('foo'), + date: new UntypedFormControl(), + }); + + + onSubmit() { + console.log('submitting ->', this.signupForm.value, this.signupForm); + } +} diff --git a/examples/angular17-reactive-forms/src/app/app.config.ts b/examples/angular17-reactive-forms/src/app/app.config.ts new file mode 100644 index 0000000000..6c6ef6035f --- /dev/null +++ b/examples/angular17-reactive-forms/src/app/app.config.ts @@ -0,0 +1,8 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideRouter } from '@angular/router'; + +import { routes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [provideRouter(routes)] +}; diff --git a/examples/angular17-reactive-forms/src/app/app.routes.ts b/examples/angular17-reactive-forms/src/app/app.routes.ts new file mode 100644 index 0000000000..dc39edb5f2 --- /dev/null +++ b/examples/angular17-reactive-forms/src/app/app.routes.ts @@ -0,0 +1,3 @@ +import { Routes } from '@angular/router'; + +export const routes: Routes = []; diff --git a/examples/angular17-reactive-forms/src/assets/.gitkeep b/examples/angular17-reactive-forms/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/angular17-reactive-forms/src/directives/base-value-accessor.ts b/examples/angular17-reactive-forms/src/directives/base-value-accessor.ts new file mode 100644 index 0000000000..a2d0f844f7 --- /dev/null +++ b/examples/angular17-reactive-forms/src/directives/base-value-accessor.ts @@ -0,0 +1,48 @@ +/** + * @license + * Scale https://github.com/telekom/scale + * + * Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { Directive, ElementRef } from '@angular/core'; +import { ControlValueAccessor } from '@angular/forms'; + +@Directive({ +}) +export class BaseValueAccessorDirective implements ControlValueAccessor { + onChange = (_: any) => {}; + + onTouched = () => {}; + + constructor(protected el: ElementRef) {} + + writeValue(value: any) { + this.el.nativeElement.value = value; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + registerOnChange(fn: (_: any) => {}): void { + this.onChange = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.el.nativeElement.disabled = isDisabled; + } + + _handleInput(value: any): void { + this.onChange(value); + } + + _handleDatePickerSelect(target: any): void { + const value = target.querySelector('duet-date-picker').value; + this.onChange(value); + } +} diff --git a/examples/angular17-reactive-forms/src/directives/checked-value-accessor.ts b/examples/angular17-reactive-forms/src/directives/checked-value-accessor.ts new file mode 100644 index 0000000000..8bc5bd85cf --- /dev/null +++ b/examples/angular17-reactive-forms/src/directives/checked-value-accessor.ts @@ -0,0 +1,41 @@ +/** + * @license + * Scale https://github.com/telekom/scale + * + * Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { Directive, ElementRef } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { BaseValueAccessorDirective } from './base-value-accessor'; + +@Directive({ + standalone: true, + selector: 'scale-checkbox[formControlName],scale-switch[formControlName],[sclCheckedControl]', + host: { + '(scaleChange)': '_handleInput($event.target.checked)', + '(blur)': 'onTouched()' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: CheckedValueAccessorDirective, + multi: true + } + ] +}) +export class CheckedValueAccessorDirective extends BaseValueAccessorDirective { + + constructor(el: ElementRef) { + super(el); + } + + override writeValue(value: any) { + this.el.nativeElement.checked = value; + } + +} diff --git a/examples/angular17-reactive-forms/src/directives/date-value-accessor.ts b/examples/angular17-reactive-forms/src/directives/date-value-accessor.ts new file mode 100644 index 0000000000..193b43ef59 --- /dev/null +++ b/examples/angular17-reactive-forms/src/directives/date-value-accessor.ts @@ -0,0 +1,25 @@ +import { Directive, ElementRef } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; + +import { BaseValueAccessorDirective } from './base-value-accessor'; + +@Directive({ + standalone: true, + /* tslint:disable-next-line:directive-selector */ + selector: 'scale-date-picker[formControlName],[sclDateControl]', + host: { + '(scale-change)': '_handleDatePickerSelect($event.target)', + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: DateValueAccessorDirective, + multi: true + } + ] +}) +export class DateValueAccessorDirective extends BaseValueAccessorDirective { + constructor(el: ElementRef) { + super(el); + } +} diff --git a/examples/angular17-reactive-forms/src/directives/number-value-accessor.ts b/examples/angular17-reactive-forms/src/directives/number-value-accessor.ts new file mode 100644 index 0000000000..9108af22db --- /dev/null +++ b/examples/angular17-reactive-forms/src/directives/number-value-accessor.ts @@ -0,0 +1,43 @@ +/** + * @license + * Scale https://github.com/telekom/scale + * + * Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { Directive, ElementRef } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { BaseValueAccessorDirective } from './base-value-accessor'; + +@Directive({ + standalone: true, + selector: 'scale-text-field[type="number"][formControlName],[sclNumberControl]', + host: { + '(scaleInput)': '_handleInput($event.target.value)', + '(blur)': 'onTouched()' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: NumberValueAccessorDirective, + multi: true + } + ] +}) +export class NumberValueAccessorDirective extends BaseValueAccessorDirective { + + constructor(el: ElementRef) { + super(el); + } + + override registerOnChange(fn: (_: number|null) => void): void { + this.onChange = (value): void => { + fn(value === '' ? null : parseFloat(value)); + }; + } + +} diff --git a/examples/angular17-reactive-forms/src/directives/radio-value-accessor.ts b/examples/angular17-reactive-forms/src/directives/radio-value-accessor.ts new file mode 100644 index 0000000000..3465eb6a1e --- /dev/null +++ b/examples/angular17-reactive-forms/src/directives/radio-value-accessor.ts @@ -0,0 +1,39 @@ +/** + * @license + * Scale https://github.com/telekom/scale + * + * Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { Directive, ElementRef } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { BaseValueAccessorDirective } from './base-value-accessor'; + +@Directive({ + standalone: true, + selector: 'scale-radio-button[formControlName],[sclRadioControl]', + host: { + '(scaleChange)': '_handleInput($event.target.value)', + '(blur)': 'onTouched()' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: RadioValueAccessorDirective, + multi: true + } + ] +}) +export class RadioValueAccessorDirective extends BaseValueAccessorDirective { + + constructor(el: ElementRef) { + super(el); + } + + // TODO + +} diff --git a/examples/angular17-reactive-forms/src/directives/select-value-accessor.ts b/examples/angular17-reactive-forms/src/directives/select-value-accessor.ts new file mode 100644 index 0000000000..ee8ae42906 --- /dev/null +++ b/examples/angular17-reactive-forms/src/directives/select-value-accessor.ts @@ -0,0 +1,25 @@ +import { Directive, ElementRef } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; + +import { BaseValueAccessorDirective } from './base-value-accessor'; + +@Directive({ + standalone: true, + /* tslint:disable-next-line:directive-selector */ + selector: 'scale-dropdown-select[formControlName],[sclSelectControl]', + host: { + '(scale-change)': '_handleInput($event.target.value)' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: SelectValueAccessorDirective, + multi: true + } + ] +}) +export class SelectValueAccessorDirective extends BaseValueAccessorDirective { + constructor(el: ElementRef) { + super(el); + } +} diff --git a/examples/angular17-reactive-forms/src/directives/text-value-accessor.ts b/examples/angular17-reactive-forms/src/directives/text-value-accessor.ts new file mode 100644 index 0000000000..553b8c2607 --- /dev/null +++ b/examples/angular17-reactive-forms/src/directives/text-value-accessor.ts @@ -0,0 +1,38 @@ +/** + * @license + * Scale https://github.com/telekom/scale + * + * Copyright (c) 2021 Egor Kirpichev and contributors, Deutsche Telekom AG + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import { Directive, ElementRef } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { BaseValueAccessorDirective } from './base-value-accessor'; + +@Directive({ + standalone: true, + selector: 'scale-text-field:not([type="number"])[formControlName],scale-textarea[formControlName],scale-dropdown[formControlName],[sclTextControl]', + host: { + '(scaleInput)': '_handleInput($event.target.value)', + '(scaleChange)': '_handleInput($event.target.value)', + '(blur)': 'onTouched()' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: TextValueAccessorDirective, + multi: true + } + ] +}) +export class TextValueAccessorDirective extends BaseValueAccessorDirective { + + constructor(el: ElementRef) { + super(el); + } + +} diff --git a/examples/angular17-reactive-forms/src/favicon.ico b/examples/angular17-reactive-forms/src/favicon.ico new file mode 100644 index 0000000000..57614f9c96 Binary files /dev/null and b/examples/angular17-reactive-forms/src/favicon.ico differ diff --git a/examples/angular17-reactive-forms/src/index.html b/examples/angular17-reactive-forms/src/index.html new file mode 100644 index 0000000000..6f398bf1b6 --- /dev/null +++ b/examples/angular17-reactive-forms/src/index.html @@ -0,0 +1,13 @@ + + + + + Angular17ReactiveForms + + + + + + + + diff --git a/examples/angular17-reactive-forms/src/main.ts b/examples/angular17-reactive-forms/src/main.ts new file mode 100644 index 0000000000..5a23812fba --- /dev/null +++ b/examples/angular17-reactive-forms/src/main.ts @@ -0,0 +1,8 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; +import { defineCustomElements } from '@telekom/scale-components/loader'; + +bootstrapApplication(AppComponent, appConfig) + .catch((err) => console.error(err)); +defineCustomElements(); \ No newline at end of file diff --git a/examples/angular17-reactive-forms/src/styles.css b/examples/angular17-reactive-forms/src/styles.css new file mode 100644 index 0000000000..90d4ee0072 --- /dev/null +++ b/examples/angular17-reactive-forms/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/examples/angular17-reactive-forms/tsconfig.app.json b/examples/angular17-reactive-forms/tsconfig.app.json new file mode 100644 index 0000000000..374cc9d294 --- /dev/null +++ b/examples/angular17-reactive-forms/tsconfig.app.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/examples/angular17-reactive-forms/tsconfig.json b/examples/angular17-reactive-forms/tsconfig.json new file mode 100644 index 0000000000..f37b67ff02 --- /dev/null +++ b/examples/angular17-reactive-forms/tsconfig.json @@ -0,0 +1,33 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "esModuleInterop": true, + "sourceMap": true, + "declaration": false, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "ES2022", + "module": "ES2022", + "useDefineForClassFields": false, + "lib": [ + "ES2022", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/examples/angular17-reactive-forms/tsconfig.spec.json b/examples/angular17-reactive-forms/tsconfig.spec.json new file mode 100644 index 0000000000..be7e9da76f --- /dev/null +++ b/examples/angular17-reactive-forms/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +}