diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b9af1d47c..c9d3d79f35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,32 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/amir-ba/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + + +### Bug Fixes + +* **button:** Include name and value properties on temporary submit button ([#2351](https://github.com/amir-ba/scale/issues/2351)) ([e0ff157](https://github.com/amir-ba/scale/commit/e0ff15764128fecc0a643d14e1ee01f64ab67d0f)) +* **data-grid:** imporves pagination with 0 elements ([#2316](https://github.com/amir-ba/scale/issues/2316)) ([42a3b36](https://github.com/amir-ba/scale/commit/42a3b3699df5b361b63fc9c466461e2af61d67ed)) +* **nav-item:** hover underline on function slots ([#2260](https://github.com/amir-ba/scale/issues/2260)) ([6e8c380](https://github.com/amir-ba/scale/commit/6e8c38027a861babd28e8925dcc5db1c87a4b05d)) +* **segment:** improves loading of the component and solves nested elemnts sizing issue ([#2358](https://github.com/amir-ba/scale/issues/2358)) ([299be7d](https://github.com/amir-ba/scale/commit/299be7d00122ed34fcde07cff9e288e291e33318)) +* **tab-nav:** fixes preselect logic in tabs with disabled attribute ([#2320](https://github.com/amir-ba/scale/issues/2320)) ([bd30a6f](https://github.com/amir-ba/scale/commit/bd30a6f2a187976ae85234b5f526537f68b3ea80)) +* dropdown scroll fixed ([#2333](https://github.com/amir-ba/scale/issues/2333)) ([592c69d](https://github.com/amir-ba/scale/commit/592c69d00e4a50f7113973bc583dff19f1cc8979)) + + +### Features + +* **accordion:** allow collapsible to be individually expanded ([#2263](https://github.com/amir-ba/scale/issues/2263)) ([9b02151](https://github.com/amir-ba/scale/commit/9b021511c94e29e9644680afcb15236b96ab35b5)) +* **data-grid:** add scale-selection event and enhance editable text field ([#2362](https://github.com/amir-ba/scale/issues/2362)) ([eeaecaf](https://github.com/amir-ba/scale/commit/eeaecaf461f014fb57c4ad14e3f279640b777c5f)) +* aria-details added to all input types ([#2359](https://github.com/amir-ba/scale/issues/2359)) ([4c45650](https://github.com/amir-ba/scale/commit/4c45650e14eff01ef42525f08ba27c1c7b0f2109)) +* **data-grid:** added tooltip and scale-icon in data-grid action cell ([#2308](https://github.com/amir-ba/scale/issues/2308)) ([30a0ce5](https://github.com/amir-ba/scale/commit/30a0ce5bdb8ca13d0c6a067894a0ee4aef6dd98b)) +* **data-grid:** adds presort to grid ([#2335](https://github.com/amir-ba/scale/issues/2335)) ([f657202](https://github.com/amir-ba/scale/commit/f6572021489ae07914dbbb6d31cb0aa2d20ea74c)) + + + + + + # [3.0.0-beta.153](https://github.com/amir-ba/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) 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" + ] +} diff --git a/lerna.json b/lerna.json index 38d3ad7c17..4715d803df 100644 --- a/lerna.json +++ b/lerna.json @@ -7,7 +7,7 @@ "--pure-lockfile" ], "useWorkspaces": true, - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "command": { "version": { "allowBranch": "main" diff --git a/packages/components-angular/CHANGELOG.md b/packages/components-angular/CHANGELOG.md index 45a1eb8e10..09d006c99a 100644 --- a/packages/components-angular/CHANGELOG.md +++ b/packages/components-angular/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + +**Note:** Version bump only for package @telekom/scale-components-angular + + + + + + # [3.0.0-beta.153](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) **Note:** Version bump only for package @telekom/scale-components-angular diff --git a/packages/components-angular/package.json b/packages/components-angular/package.json index 269663bb4f..579ce4ea1f 100644 --- a/packages/components-angular/package.json +++ b/packages/components-angular/package.json @@ -1,6 +1,6 @@ { "name": "@telekom/scale-components-angular", - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "description": "Angular specific wrapper for @telekom/scale-components", "license": "MPL-2.0", "homepage": "https://github.com/telekom/scale", diff --git a/packages/components-react/CHANGELOG.md b/packages/components-react/CHANGELOG.md index 0bfd4a4b1c..ea74e3edcf 100644 --- a/packages/components-react/CHANGELOG.md +++ b/packages/components-react/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + +**Note:** Version bump only for package @telekom/scale-components-react + + + + + + # [3.0.0-beta.153](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) **Note:** Version bump only for package @telekom/scale-components-react diff --git a/packages/components-react/package.json b/packages/components-react/package.json index 9f39f66adc..e33d80ebe6 100755 --- a/packages/components-react/package.json +++ b/packages/components-react/package.json @@ -1,7 +1,7 @@ { "name": "@telekom/scale-components-react", "sideEffects": false, - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "description": "React proxy for @telekom/scale-components", "license": "MPL-2.0", "homepage": "https://github.com/telekom/scale", diff --git a/packages/components-vue/CHANGELOG.md b/packages/components-vue/CHANGELOG.md index 65bb314256..99547288dd 100644 --- a/packages/components-vue/CHANGELOG.md +++ b/packages/components-vue/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + +**Note:** Version bump only for package @telekom/scale-components-vue + + + + + + # [3.0.0-beta.153](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) **Note:** Version bump only for package @telekom/scale-components-vue diff --git a/packages/components-vue/package.json b/packages/components-vue/package.json index 55cbc57931..e7fc109275 100644 --- a/packages/components-vue/package.json +++ b/packages/components-vue/package.json @@ -1,7 +1,7 @@ { "name": "@telekom/scale-components-vue", "sideEffects": false, - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "description": "Vue specific wrapper for @telekom/scale-components", "license": "MPL-2.0", "homepage": "https://github.com/telekom/scale", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 3d48d3c1ca..e3fe456044 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -3,6 +3,32 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + + +### Bug Fixes + +* **button:** Include name and value properties on temporary submit button ([#2351](https://github.com/telekom/scale/issues/2351)) ([e0ff157](https://github.com/telekom/scale/commit/e0ff15764128fecc0a643d14e1ee01f64ab67d0f)) +* **data-grid:** imporves pagination with 0 elements ([#2316](https://github.com/telekom/scale/issues/2316)) ([42a3b36](https://github.com/telekom/scale/commit/42a3b3699df5b361b63fc9c466461e2af61d67ed)) +* **nav-item:** hover underline on function slots ([#2260](https://github.com/telekom/scale/issues/2260)) ([6e8c380](https://github.com/telekom/scale/commit/6e8c38027a861babd28e8925dcc5db1c87a4b05d)) +* **segment:** improves loading of the component and solves nested elemnts sizing issue ([#2358](https://github.com/telekom/scale/issues/2358)) ([299be7d](https://github.com/telekom/scale/commit/299be7d00122ed34fcde07cff9e288e291e33318)) +* **tab-nav:** fixes preselect logic in tabs with disabled attribute ([#2320](https://github.com/telekom/scale/issues/2320)) ([bd30a6f](https://github.com/telekom/scale/commit/bd30a6f2a187976ae85234b5f526537f68b3ea80)) +* dropdown scroll fixed ([#2333](https://github.com/telekom/scale/issues/2333)) ([592c69d](https://github.com/telekom/scale/commit/592c69d00e4a50f7113973bc583dff19f1cc8979)) + + +### Features + +* **accordion:** allow collapsible to be individually expanded ([#2263](https://github.com/telekom/scale/issues/2263)) ([9b02151](https://github.com/telekom/scale/commit/9b021511c94e29e9644680afcb15236b96ab35b5)) +* **data-grid:** add scale-selection event and enhance editable text field ([#2362](https://github.com/telekom/scale/issues/2362)) ([eeaecaf](https://github.com/telekom/scale/commit/eeaecaf461f014fb57c4ad14e3f279640b777c5f)) +* aria-details added to all input types ([#2359](https://github.com/telekom/scale/issues/2359)) ([4c45650](https://github.com/telekom/scale/commit/4c45650e14eff01ef42525f08ba27c1c7b0f2109)) +* **data-grid:** added tooltip and scale-icon in data-grid action cell ([#2308](https://github.com/telekom/scale/issues/2308)) ([30a0ce5](https://github.com/telekom/scale/commit/30a0ce5bdb8ca13d0c6a067894a0ee4aef6dd98b)) +* **data-grid:** adds presort to grid ([#2335](https://github.com/telekom/scale/issues/2335)) ([f657202](https://github.com/telekom/scale/commit/f6572021489ae07914dbbb6d31cb0aa2d20ea74c)) + + + + + + # [3.0.0-beta.153](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) diff --git a/packages/components/package.json b/packages/components/package.json index c014e2b82f..5ab2660dd9 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@telekom/scale-components", - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "description": "Scale is the digital design system for Telekom products and experiences.", "homepage": "https://github.com/telekom/scale", "repository": { diff --git a/packages/components/src/components/accordion/accordion.tsx b/packages/components/src/components/accordion/accordion.tsx index 2c8d0d87a7..ea228f9fd0 100644 --- a/packages/components/src/components/accordion/accordion.tsx +++ b/packages/components/src/components/accordion/accordion.tsx @@ -66,7 +66,7 @@ export class Accordion { /** * Handle `expanded` */ - if (!this.dependent) { + if (this.expanded && !this.dependent) { this.getCollapsibleChildren().forEach((child) => { child.expanded = this.expanded; }); diff --git a/packages/components/src/components/button/button.tsx b/packages/components/src/components/button/button.tsx index 385941a44e..a0e3f6e4eb 100644 --- a/packages/components/src/components/button/button.tsx +++ b/packages/components/src/components/button/button.tsx @@ -102,6 +102,12 @@ export class Button { if (this.type) { fakeButton.type = this.type; } + if (this.value) { + fakeButton.value = this.value; + } + if (this.name) { + fakeButton.name = this.name; + } fakeButton.style.display = 'none'; parentForm.appendChild(fakeButton); fakeButton.click(); diff --git a/packages/components/src/components/checkbox/checkbox.tsx b/packages/components/src/components/checkbox/checkbox.tsx index 65b9a44936..a341a77324 100644 --- a/packages/components/src/components/checkbox/checkbox.tsx +++ b/packages/components/src/components/checkbox/checkbox.tsx @@ -65,6 +65,8 @@ export class Checkbox { @Prop() styles?: string; /** (optional) Input required */ @Prop() required?: boolean; + /** (optional) id or space separated list of ids of elements that provide or link to additional related information. */ + @Prop() ariaDetailsId?: string; /** Emitted when the value has changed. */ @Event({ eventName: 'scale-change' }) scaleChange: EventEmitter; @@ -189,7 +191,8 @@ export class Checkbox { aria-label={this.ariaLabelCheckbox} aria-checked={this.indeterminate ? 'mixed' : false} aria-invalid={this.status === 'error' || this.invalid ? 'true' : null} - aria-describedBy={helperText.id} + aria-describedBy={helperText ? helperText.id : this.ariaDetailsId} + aria-details={this.ariaDetailsId} disabled={this.disabled} required={this.required} onChange={this.handleChange} diff --git a/packages/components/src/components/checkbox/readme.md b/packages/components/src/components/checkbox/readme.md index 1922303c48..4e083e2f83 100644 --- a/packages/components/src/components/checkbox/readme.md +++ b/packages/components/src/components/checkbox/readme.md @@ -7,22 +7,23 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------- | --------------------- | ----------------------------------------------------------------------------------------- | --------- | ----------- | -| `ariaLabelCheckbox` | `aria-label-checkbox` | (optional) Input label output | `string` | `undefined` | -| `checked` | `checked` | (optional) Active switch | `boolean` | `false` | -| `disabled` | `disabled` | (optional) Input disabled | `boolean` | `false` | -| `helperText` | `helper-text` | (optional) Input helper text | `string` | `undefined` | -| `hideLabel` | `hide-label` | (optional) Hides the specified label visually | `boolean` | `false` | -| `indeterminate` | `indeterminate` | (optional) indeterminate | `boolean` | `false` | -| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | -| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | -| `label` | `label` | (optional) Input label | `string` | `''` | -| `name` | `name` | (optional) Input name | `string` | `undefined` | -| `required` | `required` | (optional) Input required | `boolean` | `undefined` | -| `status` | `status` | **[DEPRECATED]** - invalid should replace status

| `string` | `''` | -| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | -| `value` | `value` | (optional) Input value | `string` | `''` | +| Property | Attribute | Description | Type | Default | +| ------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------- | --------- | ----------- | +| `ariaDetailsId` | `aria-details-id` | (optional) id or space separated list of ids of elements that provide or link to additional related information. | `string` | `undefined` | +| `ariaLabelCheckbox` | `aria-label-checkbox` | (optional) Input label output | `string` | `undefined` | +| `checked` | `checked` | (optional) Active switch | `boolean` | `false` | +| `disabled` | `disabled` | (optional) Input disabled | `boolean` | `false` | +| `helperText` | `helper-text` | (optional) Input helper text | `string` | `undefined` | +| `hideLabel` | `hide-label` | (optional) Hides the specified label visually | `boolean` | `false` | +| `indeterminate` | `indeterminate` | (optional) indeterminate | `boolean` | `false` | +| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | +| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | +| `label` | `label` | (optional) Input label | `string` | `''` | +| `name` | `name` | (optional) Input name | `string` | `undefined` | +| `required` | `required` | (optional) Input required | `boolean` | `undefined` | +| `status` | `status` | **[DEPRECATED]** - invalid should replace status

| `string` | `''` | +| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | +| `value` | `value` | (optional) Input value | `string` | `''` | ## Events diff --git a/packages/components/src/components/data-grid/cell-handlers/actions-cell.tsx b/packages/components/src/components/data-grid/cell-handlers/actions-cell.tsx index be350c4068..a134239ec5 100644 --- a/packages/components/src/components/data-grid/cell-handlers/actions-cell.tsx +++ b/packages/components/src/components/data-grid/cell-handlers/actions-cell.tsx @@ -18,18 +18,22 @@ export const ActionsCell: Cell = { return (
{content.map((action) => { - const { label, ...props } = action; + const { label, iconName, tooltip, ...props } = action; + const tooltipProps = tooltip ? { title: tooltip } : {}; + const IconComponent = resolveIconComponent(iconName); if (typeof label === 'object' && '__html' in label) { return ( ); } return ( - + + {IconComponent} {label} ); @@ -38,3 +42,15 @@ export const ActionsCell: Cell = { ); }, }; + +function resolveIconComponent(iconName) { + switch (iconName) { + case 'edit': + return ; + case 'delete': + return ; + + default: + return null; + } +} diff --git a/packages/components/src/components/data-grid/cell-handlers/cell-interface.ts b/packages/components/src/components/data-grid/cell-handlers/cell-interface.ts index 59ed61527c..b8aef21953 100644 --- a/packages/components/src/components/data-grid/cell-handlers/cell-interface.ts +++ b/packages/components/src/components/data-grid/cell-handlers/cell-interface.ts @@ -17,6 +17,8 @@ export interface Cell { resizable?: boolean; sortable?: boolean; sortBy?: 'number' | 'text' | 'date'; + presort?: boolean; + presortDirection?: 'ascending' | 'descending'; stretchWeight?: number; textAlign?: 'left' | 'center' | 'right'; visible?: boolean; @@ -30,5 +32,6 @@ export interface Cell { rowIndex, columnIndex, isAutoWidthCheck, + localization, }): HTMLElement; } diff --git a/packages/components/src/components/data-grid/cell-handlers/html-cell.tsx b/packages/components/src/components/data-grid/cell-handlers/html-cell.tsx index 00a2acd381..f77e71ce8e 100644 --- a/packages/components/src/components/data-grid/cell-handlers/html-cell.tsx +++ b/packages/components/src/components/data-grid/cell-handlers/html-cell.tsx @@ -20,16 +20,24 @@ export const HTMLCell: Cell = { // Skip check as content width is always the same return rows[0][columnIndex]; }, - render: ({ content, component }) => { + render: ({ content, component, localization }) => { + const getAriaLabel = () => { + if (localization?.expand && localization?.collapse) { + return content.isExpanded + ? localization?.collapse + : localization?.expand; + } + return `Activate to ${ + content.isExpanded ? 'collapse' : 'expand' + } content`; + }; return ( content && ( { content.isExpanded = !content.isExpanded; component.forceRender++; diff --git a/packages/components/src/components/data-grid/cell-handlers/tags-cell.tsx b/packages/components/src/components/data-grid/cell-handlers/tags-cell.tsx index c1e4ef3cd8..50c46cf97a 100644 --- a/packages/components/src/components/data-grid/cell-handlers/tags-cell.tsx +++ b/packages/components/src/components/data-grid/cell-handlers/tags-cell.tsx @@ -33,7 +33,11 @@ export const TagsCell: Cell = {
    {tags.map((tag) => (
  • - + {tag.content}
  • diff --git a/packages/components/src/components/data-grid/cell-handlers/text-cell.tsx b/packages/components/src/components/data-grid/cell-handlers/text-cell.tsx index fde8fd876b..c2720094f4 100644 --- a/packages/components/src/components/data-grid/cell-handlers/text-cell.tsx +++ b/packages/components/src/components/data-grid/cell-handlers/text-cell.tsx @@ -38,6 +38,7 @@ export const TextCell: Cell = { iconPrefix, iconSuffix, label, + textFieldProps = {}, } = field; // Input component doesn't expand with content, so need to return a fake element that simulates width @@ -52,6 +53,7 @@ export const TextCell: Cell = { if (editable) { const props = { type: 'text', + ...textFieldProps, value: content, label, } as any; diff --git a/packages/components/src/components/data-grid/data-grid.tsx b/packages/components/src/components/data-grid/data-grid.tsx index 24d643781a..d4637a8ec1 100644 --- a/packages/components/src/components/data-grid/data-grid.tsx +++ b/packages/components/src/components/data-grid/data-grid.tsx @@ -102,7 +102,7 @@ export class DataGrid { /** (optional) Set to true to add selection column */ @Prop() selectable?: boolean = false; /** Read-only selection array - populated with raw data from selected rows */ - @Prop() selection: string[] = []; + @Prop({ mutable: true }) selection: any[] = []; /** (optional) Shade every second row darker */ @Prop() shadeAlternate?: boolean = true; /** (optional) Injected css styles */ @@ -112,13 +112,16 @@ export class DataGrid { /** (optional) Title for sortable columns */ @Prop() sortableColumnTitle?: string = 'Activate to sort column'; /** - * (optional) set localization for sort, toggle and select/deselect table + * (optional) set localization for sort, toggle, select/deselect, table options, expand/collapse (html cell) * Default is English. */ @Prop() localization?: { sortBy: string; toggle: string; select: string; + tableOptions: string; + expand?: string; + collapse?: string; }; /* 4. Events (alphabetical) */ /** Event triggered every time the editable cells are changed, updating the original rows data */ @@ -133,6 +136,9 @@ export class DataGrid { /** @deprecated in v3 in favor of kebab-case event names */ @Event({ eventName: 'scaleSort' }) scaleSortLegacy: EventEmitter; + /** Event triggered every time the selection list updates */ + @Event({ eventName: 'scale-selection' }) + scaleSelection: EventEmitter; /* 5. Private Properties (alphabetical) */ /** Used to update column divider during interaction */ private activeDivider: any; @@ -179,11 +185,12 @@ export class DataGrid { this.applyResponsiveClasses = this.applyResponsiveClasses.bind(this); this.updateColumnStretching = this.updateColumnStretching.bind(this); } + componentWillLoad() { this.fieldsHandler(); this.rowsHandler(); } - componentWillUpdate() {} + componentDidRender() { if (this.needsAutoWidthParse) { this.calculateAutoWidths(); @@ -195,10 +202,11 @@ export class DataGrid { } }); } + componentDidLoad() { this.addResizeObserver(); } - componentDidUpdate() {} + disconnectedCallback() { this.removeResizeObserver(); } @@ -213,8 +221,12 @@ export class DataGrid { this.resetSortingToggle(); this.dataNeedsCheck = true; } + @Watch('rows') rowsHandler() { + if (!this.rows) { + return; + } // Reset pagination to the last page of the new records if new records are less than previous. if (this.paginationStart > this.rows.length) { this.paginationStart = @@ -222,6 +234,7 @@ export class DataGrid { } this.parseRows(); this.setInitialRowProps(); + this.presortTable(); this.dataNeedsCheck = true; // Set flag to dirty to redo column width with new data this.needsAutoWidthParse = true; @@ -242,7 +255,8 @@ export class DataGrid { this.sortTable( this.fields[this.activeSortingIndex].sortDirection, this.fields[this.activeSortingIndex].type, - this.activeSortingIndex + this.activeSortingIndex, + true ); } } @@ -392,19 +406,19 @@ export class DataGrid { } updateReadableSelection() { - this.selection.length = 0; + this.selection = []; this.rows.forEach((row) => row.selected && this.selection.push(row)); - // Check header checkbox if any or none are selected const selectAll = this.hostElement.shadowRoot.querySelector( '.thead__cell--selection scale-checkbox' ) as HTMLInputElement; selectAll.checked = !!this.selection.length; + emitEvent(this, 'scaleSelection', this.selection); // selectAll.indeterminate = !!this.selection.length; } // Sorting handlers - toggleTableSorting(sortDirection, columnIndex, type) { + toggleTableSorting(currentSortDirection, columnIndex, type) { // Remove sorting from previous column index if ( this.activeSortingIndex > -1 && @@ -416,16 +430,16 @@ export class DataGrid { this.activeSortingIndex = columnIndex; const newSortDirection = - sortDirection === 'none' + currentSortDirection === 'none' ? 'ascending' - : sortDirection === 'ascending' + : currentSortDirection === 'ascending' ? 'descending' : 'none'; this.fields[columnIndex].sortDirection = newSortDirection; this.sortTable(newSortDirection, type, columnIndex); } - sortTable(sortDirection, type, columnIndex) { + sortTable(sortDirection, type, columnIndex, shouldTriggerEvent = true) { const format = this.fields[columnIndex].format; if (sortDirection === 'none') { this.rows.sort((a, b) => { @@ -482,8 +496,10 @@ export class DataGrid { } } this.forceRender++; - // Trigger event - this.triggerSortEvent(sortDirection, type, columnIndex); + if (shouldTriggerEvent) { + // Trigger event + this.triggerSortEvent(sortDirection, type, columnIndex); + } } resetSortingToggle() { @@ -493,6 +509,23 @@ export class DataGrid { this.activeSortingIndex = -1; } + presortTable(): void { + const columnToPresort = this.fields.find( + (col) => col.sortable && col.presort + ); + if (!columnToPresort) { + return; + } + const columnIndex = this.fields.indexOf(columnToPresort); + const direction = + columnToPresort.presortDirection === 'descending' + ? 'descending' + : 'ascending'; + this.activeSortingIndex = columnIndex; + this.fields[columnIndex].sortDirection = direction; + this.sortTable(direction, columnToPresort.type, columnIndex, false); + } + // Column resize handlers onDividerDown(e) { this.polyfillMousePosition(e); @@ -797,7 +830,11 @@ export class DataGrid { icon-only data-sortable={this.isSortable} > - + {this.isSortable && ( @@ -919,6 +956,7 @@ export class DataGrid {
    (this.elScrollContainer = el)} class={`${name}__scroll-container`} + part="scrollable" style={{ height: this.height || 'auto' }} onScroll={() => this.onTableScroll()} > @@ -996,7 +1034,7 @@ export class DataGrid { {this.numbered && this.renderTableHeadNumberedCell()} {this.selectable && this.renderTableHeadSelectableCell()} - {this.fields.map( + {this.fields?.map( ( { type, @@ -1137,7 +1175,7 @@ export class DataGrid { ref={(el) => (this.elToggleSelectAll = el)} onScaleChange={() => this.toggleSelectAll()} hideLabel={true} - aria-label="Select" + ariaLabelCheckbox="Select" > ); @@ -1311,6 +1349,7 @@ export class DataGrid { component: this, rowIndex, columnIndex, + localization: this.localization, })} ); @@ -1355,7 +1394,7 @@ export class DataGrid { > {this.styles && }
    -
    +
    {/* h4 tag + h5 styles feels weird, ideally one should be able to set the tag with an attribute */} {this.heading && (

    {this.heading}

    diff --git a/packages/components/src/components/data-grid/readme.md b/packages/components/src/components/data-grid/readme.md index c607a5f84e..61a0ffd2d1 100644 --- a/packages/components/src/components/data-grid/readme.md +++ b/packages/components/src/components/data-grid/readme.md @@ -5,36 +5,45 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| --------------------- | ----------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------- | --------------------------- | -| `fields` | `fields` | Input fields config array | `any` | `undefined` | -| `freezeHeader` | `freeze-header` | (optional) Freeze header row from scrolling | `boolean` | `false` | -| `heading` | `heading` | (optional) Heading string | `string` | `''` | -| `height` | `height` | (optional) Set static table height, by default will auto-resize | `string` | `undefined` | -| `hideBorder` | `hide-border` | (optional) Set to true to remove border | `boolean` | `false` | -| `hideHeader` | `hide-header` | (optional) Set to true to hide header row | `boolean` | `false` | -| `hideInfo` | `hide-info` | (optional) Set to true to remove info footer block including pagination and selection status | `boolean` | `false` | -| `hideMenu` | `hide-menu` | (optional) Set to true to hide settings menu | `boolean` | `false` | -| `localization` | -- | (optional) set localization for sort, toggle and select/deselect table Default is English. | `{ sortBy: string; toggle: string; select: string; }` | `undefined` | -| `numbered` | `numbered` | (optional) Set to true to add numbers column | `boolean` | `false` | -| `pageSize` | `page-size` | (optional) Set number of rows to display per pagination page | `number` | `Infinity` | -| `rows` | `rows` | Input data array | `any` | `undefined` | -| `selectable` | `selectable` | (optional) Set to true to add selection column | `boolean` | `false` | -| `selection` | -- | Read-only selection array - populated with raw data from selected rows | `string[]` | `[]` | -| `shadeAlternate` | `shade-alternate` | (optional) Shade every second row darker | `boolean` | `true` | -| `sortableColumnTitle` | `sortable-column-title` | (optional) Title for sortable columns | `string` | `'Activate to sort column'` | -| `styles` | `styles` | (optional) Injected css styles | `any` | `undefined` | -| `visible` | `visible` | (optional) Set to false to hide table, used for nested tables to re-render upon toggle | `boolean` | `true` | +| Property | Attribute | Description | Type | Default | +| --------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------- | +| `fields` | `fields` | Input fields config array | `any` | `undefined` | +| `freezeHeader` | `freeze-header` | (optional) Freeze header row from scrolling | `boolean` | `false` | +| `heading` | `heading` | (optional) Heading string | `string` | `''` | +| `height` | `height` | (optional) Set static table height, by default will auto-resize | `string` | `undefined` | +| `hideBorder` | `hide-border` | (optional) Set to true to remove border | `boolean` | `false` | +| `hideHeader` | `hide-header` | (optional) Set to true to hide header row | `boolean` | `false` | +| `hideInfo` | `hide-info` | (optional) Set to true to remove info footer block including pagination and selection status | `boolean` | `false` | +| `hideMenu` | `hide-menu` | (optional) Set to true to hide settings menu | `boolean` | `false` | +| `localization` | -- | (optional) set localization for sort, toggle, select/deselect, table options, expand/collapse (html cell) Default is English. | `{ sortBy: string; toggle: string; select: string; tableOptions: string; expand?: string; collapse?: string; }` | `undefined` | +| `numbered` | `numbered` | (optional) Set to true to add numbers column | `boolean` | `false` | +| `pageSize` | `page-size` | (optional) Set number of rows to display per pagination page | `number` | `Infinity` | +| `rows` | `rows` | Input data array | `any` | `undefined` | +| `selectable` | `selectable` | (optional) Set to true to add selection column | `boolean` | `false` | +| `selection` | -- | Read-only selection array - populated with raw data from selected rows | `any[]` | `[]` | +| `shadeAlternate` | `shade-alternate` | (optional) Shade every second row darker | `boolean` | `true` | +| `sortableColumnTitle` | `sortable-column-title` | (optional) Title for sortable columns | `string` | `'Activate to sort column'` | +| `styles` | `styles` | (optional) Injected css styles | `any` | `undefined` | +| `visible` | `visible` | (optional) Set to false to hide table, used for nested tables to re-render upon toggle | `boolean` | `true` | ## Events -| Event | Description | Type | -| ------------ | -------------------------------------------------------------------------------------------------- | ---------------------------------------- | -| `scale-edit` | Event triggered every time the editable cells are changed, updating the original rows data | `CustomEvent` | -| `scale-sort` | Event triggered every time the data is sorted, changing original rows data | `CustomEvent` | -| `scaleEdit` | **[DEPRECATED]** in v3 in favor of kebab-case event names

    | `CustomEvent` | -| `scaleSort` | **[DEPRECATED]** in v3 in favor of kebab-case event names

    | `CustomEvent` | +| Event | Description | Type | +| ----------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------------- | +| `scale-edit` | Event triggered every time the editable cells are changed, updating the original rows data | `CustomEvent` | +| `scale-selection` | Event triggered every time the selection list updates | `CustomEvent` | +| `scale-sort` | Event triggered every time the data is sorted, changing original rows data | `CustomEvent` | +| `scaleEdit` | **[DEPRECATED]** in v3 in favor of kebab-case event names

    | `CustomEvent` | +| `scaleSort` | **[DEPRECATED]** in v3 in favor of kebab-case event names

    | `CustomEvent` | + + +## Shadow Parts + +| Part | Description | +| -------------- | ----------- | +| `"scrollable"` | | +| `"title"` | | ## Dependencies @@ -62,6 +71,8 @@ - [scale-dropdown-select-item](../dropdown-select-item) - [scale-tag](../tag) - [scale-text-field](../text-field) +- [scale-icon-action-edit](../icons/action-edit) +- [scale-icon-action-remove](../icons/action-remove) ### Graph ```mermaid @@ -87,6 +98,8 @@ graph TD; scale-data-grid --> scale-dropdown-select-item scale-data-grid --> scale-tag scale-data-grid --> scale-text-field + scale-data-grid --> scale-icon-action-edit + scale-data-grid --> scale-icon-action-remove scale-menu-flyout-item --> scale-icon-action-checkmark scale-menu-flyout-item --> scale-icon-navigation-right scale-checkbox --> scale-icon-action-minus diff --git a/packages/components/src/components/date-picker/date-picker.tsx b/packages/components/src/components/date-picker/date-picker.tsx index 5a15423b68..a202a02a30 100644 --- a/packages/components/src/components/date-picker/date-picker.tsx +++ b/packages/components/src/components/date-picker/date-picker.tsx @@ -151,6 +151,10 @@ export class DatePicker { @Prop() variant?: 'informational' | 'warning' | 'danger' | 'success' = 'informational'; + + /** (optional) id or space separated list of ids of elements that provide or link to additional related information. */ + @Prop() ariaDetailsId?: string; + /** Whether the input element has focus */ @State() hasFocus: boolean = false; @@ -308,11 +312,15 @@ export class DatePicker { input.addEventListener('keyup', this.handleKeyPress); } - if (input && this.helperText) { - input.setAttribute( - 'aria-describedby', - `helper-message-${this.internalId}` - ); + if (input && (this.helperText || this.ariaDetailsId)) { + const describedBy = this.helperText + ? `helper-message-${this.internalId}` + : this.ariaDetailsId; + input.setAttribute('aria-describedby', describedBy); + } + + if (input && this.ariaDetailsId) { + input.setAttribute('aria-details', this.ariaDetailsId); } if (input && this.placeholder) { @@ -483,7 +491,7 @@ export class DatePicker { dateAdapter={this.dateAdapter} disabled={this.disabled} value={this.value} - ref={(element: HTMLElement & DuetDatePicker) => + ref={(element: HTMLDuetDatePickerElement & DuetDatePicker) => (this.duetInput = element) } > diff --git a/packages/components/src/components/date-picker/readme.md b/packages/components/src/components/date-picker/readme.md index 8b3077a06f..06836403f4 100644 --- a/packages/components/src/components/date-picker/readme.md +++ b/packages/components/src/components/date-picker/readme.md @@ -9,6 +9,7 @@ | Property | Attribute | Description | Type | Default | | ---------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------- | +| `ariaDetailsId` | `aria-details-id` | (optional) id or space separated list of ids of elements that provide or link to additional related information. | `string` | `undefined` | | `dateAdapter` | `date-adapter` | Date adapter, for custom parsing/formatting. Must be object with a `parse` function which accepts a `string` and returns a `Date`, and a `format` function which accepts a `Date` and returns a `string`. Default is IS0-8601 parsing and formatting. | `any` | `undefined` | | `direction` | `direction` | Forces the opening direction of the calendar modal to be always left or right. This setting can be useful when the input is smaller than the opening date picker would be as by default the picker always opens towards right. | `"left" \| "right"` | `'right'` | | `disabled` | `disabled` | Makes the date picker input component disabled. This prevents users from being able to interact with the input, and conveys its inactive state to assistive technologies. | `boolean` | `false` | diff --git a/packages/components/src/components/dropdown-select/dropdown-select.tsx b/packages/components/src/components/dropdown-select/dropdown-select.tsx index afe80c06ce..2c8e429f00 100644 --- a/packages/components/src/components/dropdown-select/dropdown-select.tsx +++ b/packages/components/src/components/dropdown-select/dropdown-select.tsx @@ -257,6 +257,8 @@ export class DropdownSelect { @Prop() ariaLabelSelected?: string = 'selected'; /** (optional) Text displayed in high contrast mode only to indicate disabled state */ @Prop() hcmLabelDisabled?: string = 'this field is disabled'; + /** (optional) id or space separated list of ids of elements that provide or link to additional related information. */ + @Prop() ariaDetailsId?: string; @Event({ eventName: 'scale-change' }) scaleChange!: EventEmitter; @Event({ eventName: 'scale-focus' }) scaleFocus!: EventEmitter; @@ -490,7 +492,8 @@ export class DropdownSelect { const ValueElement = element.ItemElement; const hasEmptyValueElement = element.value === ''; const helperTextId = `helper-message-${generateUniqueId()}`; - const ariaDescribedByAttr = { 'aria-describedBy': helperTextId }; + const describedBy = this.helperText ? helperTextId : this.ariaDetailsId; + const ariaDescribedByAttr = { 'aria-describedBy': describedBy }; return ( @@ -505,6 +508,7 @@ export class DropdownSelect { aria-expanded={this.open ? 'true' : 'false'} aria-haspopup="listbox" aria-labelledby={`${this.comboboxId}-label`} + aria-details={this.ariaDetailsId} id={this.comboboxId} part="combobox" role="combobox" @@ -521,7 +525,7 @@ export class DropdownSelect { ).value, } : {})} - {...(this.helperText ? ariaDescribedByAttr : {})} + {...ariaDescribedByAttr} {...(this.invalid ? { 'aria-invalid': 'true' } : {})} > diff --git a/packages/components/src/components/dropdown-select/readme.md b/packages/components/src/components/dropdown-select/readme.md index 68ea780eba..31a69bfab3 100644 --- a/packages/components/src/components/dropdown-select/readme.md +++ b/packages/components/src/components/dropdown-select/readme.md @@ -7,22 +7,23 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------- | --------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------- | -------------------------- | -| `ariaLabelSelected` | `aria-label-selected` | (optional) Screen reader text appended to the selected element | `string` | `'selected'` | -| `comboboxId` | `combobox-id` | | `string` | `'combobox'` | -| `disabled` | `disabled` | | `boolean` | `undefined` | -| `floatingStrategy` | `floating-strategy` | | `"absolute" \| "fixed"` | `'absolute'` | -| `hcmLabelDisabled` | `hcm-label-disabled` | (optional) Text displayed in high contrast mode only to indicate disabled state | `string` | `'this field is disabled'` | -| `helperText` | `helper-text` | | `string` | `''` | -| `hideLabelVisually` | `hide-label-visually` | (optional) to hide the label | `boolean` | `false` | -| `invalid` | `invalid` | | `boolean` | `false` | -| `label` | `label` | | `string` | `undefined` | -| `name` | `name` | | `string` | `undefined` | -| `readonly` | `readonly` | | `boolean` | `undefined` | -| `transparent` | `transparent` | | `boolean` | `undefined` | -| `value` | `value` | | `any` | `undefined` | -| `variant` | `variant` | | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` | +| Property | Attribute | Description | Type | Default | +| ------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | -------------------------- | +| `ariaDetailsId` | `aria-details-id` | (optional) id or space separated list of ids of elements that provide or link to additional related information. | `string` | `undefined` | +| `ariaLabelSelected` | `aria-label-selected` | (optional) Screen reader text appended to the selected element | `string` | `'selected'` | +| `comboboxId` | `combobox-id` | | `string` | `'combobox'` | +| `disabled` | `disabled` | | `boolean` | `undefined` | +| `floatingStrategy` | `floating-strategy` | | `"absolute" \| "fixed"` | `'absolute'` | +| `hcmLabelDisabled` | `hcm-label-disabled` | (optional) Text displayed in high contrast mode only to indicate disabled state | `string` | `'this field is disabled'` | +| `helperText` | `helper-text` | | `string` | `''` | +| `hideLabelVisually` | `hide-label-visually` | (optional) to hide the label | `boolean` | `false` | +| `invalid` | `invalid` | | `boolean` | `false` | +| `label` | `label` | | `string` | `undefined` | +| `name` | `name` | | `string` | `undefined` | +| `readonly` | `readonly` | | `boolean` | `undefined` | +| `transparent` | `transparent` | | `boolean` | `undefined` | +| `value` | `value` | | `any` | `undefined` | +| `variant` | `variant` | | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` | ## Events diff --git a/packages/components/src/components/dropdown/dropdown.tsx b/packages/components/src/components/dropdown/dropdown.tsx index ffd36e0bba..2adfa3745c 100644 --- a/packages/components/src/components/dropdown/dropdown.tsx +++ b/packages/components/src/components/dropdown/dropdown.tsx @@ -70,6 +70,8 @@ export class Dropdown { @Prop() controlled?: boolean = false; /** (optional) to avoid displaying the label */ @Prop() hideLabelVisually?: boolean = false; + /** (optional) id or space separated list of ids of elements that provide or link to additional related information. */ + @Prop() ariaDetailsId?: string; /** (optional) Injected CSS styles */ @Prop() styles?: string; @@ -242,7 +244,8 @@ export class Dropdown { const ariaInvalidAttr = this.status === 'error' || this.invalid ? { 'aria-invalid': 'true' } : {}; const helperTextId = `helper-message-${this.internalId}`; - const ariaDescribedByAttr = { 'aria-describedBy': helperTextId }; + const describedBy = this.helperText ? helperTextId : this.ariaDetailsId; + const ariaDescribedByAttr = { 'aria-describedBy': describedBy }; return ( @@ -268,7 +271,10 @@ export class Dropdown { name={this.name} size={this.visibleSize} {...ariaInvalidAttr} - {...(this.helperText ? ariaDescribedByAttr : {})} + {...(this.helperText || this.ariaDetailsId + ? ariaDescribedByAttr + : {})} + aria-details={this.ariaDetailsId} > diff --git a/packages/components/src/components/dropdown/readme.md b/packages/components/src/components/dropdown/readme.md index 2daa67e513..f673b4eb41 100644 --- a/packages/components/src/components/dropdown/readme.md +++ b/packages/components/src/components/dropdown/readme.md @@ -7,25 +7,26 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------- | --------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------- | -| `controlled` | `controlled` | (optional) Makes type `select` behave as a controlled component in React | `boolean` | `false` | -| `disabled` | `disabled` | | `boolean` | `undefined` | -| `helperText` | `helper-text` | (optional) Input helper text | `string` | `''` | -| `hideLabelVisually` | `hide-label-visually` | (optional) to avoid displaying the label | `boolean` | `false` | -| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | -| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | -| `label` | `label` | (optional) Input label | `string` | `''` | -| `multiple` | `multiple` | (optional) select multiple options | `boolean` | `undefined` | -| `name` | `name` | (optional) Input name | `string` | `''` | -| `required` | `required` | (optional) Input required | `boolean` | `undefined` | -| `size` | `size` | **[DEPRECATED]**

    | `string` | `undefined` | -| `status` | `status` | **[DEPRECATED]** - invalid should replace status

    | `string` | `''` | -| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | -| `transparent` | `transparent` | (optional) input background transparent | `boolean` | `undefined` | -| `value` | `value` | (optional) Input value | `number \| string` | `''` | -| `variant` | `variant` | (optional) Variant | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` | -| `visibleSize` | `visible-size` | (optional) the number of visible options in a select drop-down list | `number` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------- | +| `ariaDetailsId` | `aria-details-id` | (optional) id or space separated list of ids of elements that provide or link to additional related information. | `string` | `undefined` | +| `controlled` | `controlled` | (optional) Makes type `select` behave as a controlled component in React | `boolean` | `false` | +| `disabled` | `disabled` | | `boolean` | `undefined` | +| `helperText` | `helper-text` | (optional) Input helper text | `string` | `''` | +| `hideLabelVisually` | `hide-label-visually` | (optional) to avoid displaying the label | `boolean` | `false` | +| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | +| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | +| `label` | `label` | (optional) Input label | `string` | `''` | +| `multiple` | `multiple` | (optional) select multiple options | `boolean` | `undefined` | +| `name` | `name` | (optional) Input name | `string` | `''` | +| `required` | `required` | (optional) Input required | `boolean` | `undefined` | +| `size` | `size` | **[DEPRECATED]**

    | `string` | `undefined` | +| `status` | `status` | **[DEPRECATED]** - invalid should replace status

    | `string` | `''` | +| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | +| `transparent` | `transparent` | (optional) input background transparent | `boolean` | `undefined` | +| `value` | `value` | (optional) Input value | `number \| string` | `''` | +| `variant` | `variant` | (optional) Variant | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` | +| `visibleSize` | `visible-size` | (optional) the number of visible options in a select drop-down list | `number` | `undefined` | ## Events diff --git a/packages/components/src/components/pagination/pagination.spec.ts b/packages/components/src/components/pagination/pagination.spec.ts index 33272df330..3f58647aca 100644 --- a/packages/components/src/components/pagination/pagination.spec.ts +++ b/packages/components/src/components/pagination/pagination.spec.ts @@ -125,4 +125,24 @@ describe('pagination', () => { }) ); }); + it('should show no start element when total elements is zero', async () => { + const specPage = await newSpecPage({ + components: [Pagination], + html: ` + `, + }); + const paginationInfoElement = + specPage.root.shadowRoot.querySelector('.pagination__info'); + const buttonPrev = specPage.root.shadowRoot.querySelector( + '.pagination__prev-prompt' + ); + expect(paginationInfoElement.textContent).toEqual('0-0 / 0'); + expect(buttonPrev.hasAttribute('disabled')).toBe(true); + }); }); diff --git a/packages/components/src/components/pagination/pagination.tsx b/packages/components/src/components/pagination/pagination.tsx index 28ef043342..4954da48c3 100644 --- a/packages/components/src/components/pagination/pagination.tsx +++ b/packages/components/src/components/pagination/pagination.tsx @@ -177,9 +177,9 @@ export class Pagination { /* 10. Render */ render() { const total = this.totalElements; - const start = this.startElement + 1; + const start = total === 0 ? 0 : this.startElement + 1; const end = Math.min(this.startElement + this.pageSize, total); - const isAtStart = start === 1; + const isAtStart = start === 1 || total === 0; const isAtEnd = end === total; return ( diff --git a/packages/components/src/components/radio-button/radio-button.tsx b/packages/components/src/components/radio-button/radio-button.tsx index 42e84849b1..5ba1d3e7c9 100644 --- a/packages/components/src/components/radio-button/radio-button.tsx +++ b/packages/components/src/components/radio-button/radio-button.tsx @@ -53,6 +53,8 @@ export class RadioButton { @Prop() inputId?: string; /** (optional) Injected CSS styles */ @Prop() styles?: string; + /** (optional) id or space separated list of ids of elements that provide or link to additional related information. */ + @Prop() ariaDetailsId?: string; @Event({ eventName: 'scale-change' }) scaleChange!: EventEmitter; @@ -124,7 +126,8 @@ export class RadioButton { const ariaInvalidAttr = this.status === 'error' || this.invalid ? { 'aria-invalid': 'true' } : {}; const helperTextId = `helper-message-${this.internalId}`; - const ariaDescribedByAttr = { 'aria-describedBy': helperTextId }; + const describedBy = this.helperText ? helperTextId : this.ariaDetailsId; + const ariaDescribedByAttr = { 'aria-describedBy': describedBy }; return ( @@ -138,7 +141,10 @@ export class RadioButton { checked={this.checked} disabled={this.disabled} {...ariaInvalidAttr} - {...(this.helperText ? ariaDescribedByAttr : {})} + {...(this.helperText || this.ariaDetailsId + ? ariaDescribedByAttr + : {})} + aria-details={this.ariaDetailsId} /> {!!this.helperText && ( diff --git a/packages/components/src/components/radio-button/readme.md b/packages/components/src/components/radio-button/readme.md index c0034e5871..5d4c086c81 100644 --- a/packages/components/src/components/radio-button/readme.md +++ b/packages/components/src/components/radio-button/readme.md @@ -7,18 +7,19 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ------------ | ------------- | ----------------------------------------------------------------------------------------- | ------------------ | ----------- | -| `checked` | `checked` | (optional) Input checked | `boolean` | `false` | -| `disabled` | `disabled` | (optional) Input disabled | `boolean` | `undefined` | -| `helperText` | `helper-text` | (optional) Input helper text | `string` | `''` | -| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | -| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | -| `label` | `label` | (optional) Input label | `string` | `''` | -| `name` | `name` | (optional) Input name | `string` | `''` | -| `status` | `status` | **[DEPRECATED]** - invalid should replace status

    | `string` | `''` | -| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | -| `value` | `value` | (optional) Input value | `number \| string` | `''` | +| Property | Attribute | Description | Type | Default | +| --------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------ | ----------- | +| `ariaDetailsId` | `aria-details-id` | (optional) id or space separated list of ids of elements that provide or link to additional related information. | `string` | `undefined` | +| `checked` | `checked` | (optional) Input checked | `boolean` | `false` | +| `disabled` | `disabled` | (optional) Input disabled | `boolean` | `undefined` | +| `helperText` | `helper-text` | (optional) Input helper text | `string` | `''` | +| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | +| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | +| `label` | `label` | (optional) Input label | `string` | `''` | +| `name` | `name` | (optional) Input name | `string` | `''` | +| `status` | `status` | **[DEPRECATED]** - invalid should replace status

    | `string` | `''` | +| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | +| `value` | `value` | (optional) Input value | `number \| string` | `''` | ## Events diff --git a/packages/components/src/components/segment/__snapshots__/segment.spec.ts.snap b/packages/components/src/components/segment/__snapshots__/segment.spec.ts.snap index bf96880a50..1c95275796 100644 --- a/packages/components/src/components/segment/__snapshots__/segment.spec.ts.snap +++ b/packages/components/src/components/segment/__snapshots__/segment.spec.ts.snap @@ -15,6 +15,8 @@ exports[`Segment should match standard snapshot 1`] = `
    - Label + + Label + `; diff --git a/packages/components/src/components/segment/readme.md b/packages/components/src/components/segment/readme.md index bc5a198334..249d97f3ad 100644 --- a/packages/components/src/components/segment/readme.md +++ b/packages/components/src/components/segment/readme.md @@ -7,24 +7,24 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ---------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------- | -------------- | -| `adjacentSiblings` | `adjacent-siblings` | | `"left" \| "leftright" \| "right"` | `undefined` | -| `ariaDescriptionTranslation` | `aria-description-translation` | a11y text for getting meaningful value. `$buttonNumber` and `$selected` are template variables and will be replaces by their corresponding properties. | `string` | `'$selected'` | -| `ariaLabelSegment` | `aria-label-segment` | (optional) aria-label attribute needed for icon-only segments | `string` | `undefined` | -| `ariaLangDeselected` | `aria-lang-deselected` | (optional) translation of 'deselected | `string` | `'deselected'` | -| `ariaLangSelected` | `aria-lang-selected` | (optional) translation of 'selected | `string` | `'selected'` | -| `disabled` | `disabled` | (optional) If `true`, the segment is disabled | `boolean` | `false` | -| `hasIcon` | `has-icon` | (optional) position within group | `boolean` | `undefined` | -| `iconOnly` | `icon-only` | (optional) position within group | `boolean` | `undefined` | -| `position` | `position` | (optional) position within group | `number` | `undefined` | -| `segmentId` | `segment-id` | (optional) segment's id | `string` | `undefined` | -| `selected` | `selected` | (optional) If `true`, the segment is selected | `boolean` | `false` | -| `selectedIndex` | `selected-index` | (optional) the index of the currently selected segment in the segmented-button | `string` | `undefined` | -| `size` | `size` | (optional) The size of the segment | `"large" \| "medium" \| "small"` | `'small'` | -| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | -| `textOnly` | `text-only` | (optional) position within group | `boolean` | `undefined` | -| `width` | `width` | (optional) Segment width set to ensure that all segments have the same width | `string` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ---------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------- | ------------------ | +| `adjacentSiblings` | `adjacent-siblings` | | `"left" \| "leftright" \| "right"` | `undefined` | +| `ariaDescriptionTranslation` | `aria-description-translation` | a11y text for getting meaningful value. `$buttonNumber` and `$selected` are template variables and will be replaces by their corresponding properties. | `string` | `'$selected'` | +| `ariaLabelSegment` | `aria-label-segment` | (optional) aria-label attribute needed for icon-only segments | `string` | `undefined` | +| `ariaLangDeselected` | `aria-lang-deselected` | (optional) translation of 'deselected | `string` | `'deselected'` | +| `ariaLangSelected` | `aria-lang-selected` | (optional) translation of 'selected | `string` | `'selected'` | +| `disabled` | `disabled` | (optional) If `true`, the segment is disabled | `boolean` | `false` | +| `hasIcon` | `has-icon` | (optional) position within group | `boolean` | `undefined` | +| `iconOnly` | `icon-only` | (optional) position within group | `boolean` | `undefined` | +| `position` | `position` | (optional) position within group | `number` | `undefined` | +| `segmentId` | `segment-id` | (optional) segment's id | `string` | `'segment-' + i++` | +| `selected` | `selected` | (optional) If `true`, the segment is selected | `boolean` | `false` | +| `selectedIndex` | `selected-index` | (optional) the index of the currently selected segment in the segmented-button | `string` | `undefined` | +| `size` | `size` | (optional) The size of the segment | `"large" \| "medium" \| "small"` | `'small'` | +| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | +| `textOnly` | `text-only` | (optional) position within group | `boolean` | `undefined` | +| `width` | `width` | (optional) Segment width set to ensure that all segments have the same width | `string` | `undefined` | ## Events diff --git a/packages/components/src/components/segment/segment.tsx b/packages/components/src/components/segment/segment.tsx index c2daf67c0c..67b45ffa82 100644 --- a/packages/components/src/components/segment/segment.tsx +++ b/packages/components/src/components/segment/segment.tsx @@ -38,7 +38,7 @@ export class Segment { /** (optional) If `true`, the segment is disabled */ @Prop() disabled?: boolean = false; /** (optional) segment's id */ - @Prop({ reflect: true, mutable: true }) segmentId?: string; + @Prop({ reflect: true }) segmentId?: string = 'segment-' + i++; /** (optional) aria-label attribute needed for icon-only segments */ @Prop() ariaLabelSegment: string; /** (optional) Segment width set to ensure that all segments have the same width */ @@ -84,13 +84,10 @@ export class Segment { async setFocus() { this.focusableElement.focus(); } - componentWillLoad() { - if (this.segmentId == null) { - this.segmentId = 'segment-' + i++; - } + this.handleIcon(); } - componentDidUpdate() { + componentWillUpdate() { this.handleIcon(); } diff --git a/packages/components/src/components/segmented-button/__snapshots__/segmented-button.spec.ts.snap b/packages/components/src/components/segmented-button/__snapshots__/segmented-button.spec.ts.snap index 41c565086d..82e5bc5170 100644 --- a/packages/components/src/components/segmented-button/__snapshots__/segmented-button.spec.ts.snap +++ b/packages/components/src/components/segmented-button/__snapshots__/segmented-button.spec.ts.snap @@ -3,7 +3,7 @@ exports[`SegmentedButton should match selected button snapshot 1`] = ` -
    +
    @@ -19,7 +19,7 @@ exports[`SegmentedButton should match selected button snapshot 1`] = ` exports[`SegmentedButton should match standard snapshot 1`] = ` -
    +
    @@ -36,4 +36,4 @@ exports[`SegmentedButton should match standard snapshot 1`] = ` Label -`; +`; \ No newline at end of file diff --git a/packages/components/src/components/segmented-button/segmented-button.tsx b/packages/components/src/components/segmented-button/segmented-button.tsx index b93fea17c1..e32fbc09ef 100644 --- a/packages/components/src/components/segmented-button/segmented-button.tsx +++ b/packages/components/src/components/segmented-button/segmented-button.tsx @@ -52,7 +52,7 @@ export class SegmentedButton { /** (optional) Allow more than one button to be selected */ @Prop() multiSelect: boolean = false; /** (optional) the index of the selected segment */ - @Prop() selectedIndex?: number; + @Prop({ mutable: true }) selectedIndex?: number; /** (optional) If `true`, the button is disabled */ @Prop({ reflect: true }) disabled?: boolean = false; /** (optional) If `true`, expand to container width */ @@ -119,47 +119,52 @@ export class SegmentedButton { }); } - componentDidLoad() { + componentWillLoad() { const tempState: SegmentStatus[] = []; const segments = this.getAllSegments(); this.slottedSegments = segments.length; - const longestButtonWidth = this.getLongestButtonWidth(); - segments.forEach((segment) => { - this.position++; + segments.forEach((segment, i) => { tempState.push({ id: segment.getAttribute('segment-id') || segment.segmentId, selected: segment.hasAttribute('selected') || segment.selected, }); - segment.setAttribute('position', this.position.toString()); + segment.setAttribute('position', `${i + 1}`); segment.setAttribute( 'aria-description-translation', '$position $selected' ); }); + this.setState(tempState); + this.selectedIndex = this.getSelectedIndex(); + this.showHelperText = this.shouldShowHelperText(); + } + componentDidLoad() { + const longestButtonWidth = this.getLongestButtonWidth(); if (!this.fullWidth) { - this.container.style.gridTemplateColumns = `repeat(${ - this.hostElement.children.length - }, ${Math.ceil(longestButtonWidth)}px)`; + this.container.style.gridTemplateColumns = longestButtonWidth + ? `repeat(${this.hostElement.children.length}, ${Math.ceil( + longestButtonWidth + )}px)` + : `repeat(${this.hostElement.children.length}, auto)`; } else { this.container.style.display = 'flex'; } - - this.selectedIndex = this.getSelectedIndex(); this.propagatePropsToChildren(); - this.position = 0; - this.status = tempState; - this.setState(tempState); } componentWillUpdate() { this.selectedIndex = this.getSelectedIndex(); - this.showHelperText = false; + this.showHelperText = this.shouldShowHelperText(); + } + shouldShowHelperText() { + let showHelperText = false; if ( this.invalid && this.status.filter((e) => e.selected === true).length <= 0 ) { - this.showHelperText = true; + showHelperText = true; } + return showHelperText; } getSelectedIndex() { @@ -195,27 +200,29 @@ export class SegmentedButton { // all segmented buttons should have the same width, based on the largest one getLongestButtonWidth() { let tempWidth = 0; - Array.from(this.hostElement.children).forEach((child) => { - const selected = child.hasAttribute('selected'); - const iconOnly = child.hasAttribute('icon-only'); - const checkmark = - this.size === 'small' - ? CHECKMARK_WIDTH_SMALL - : this.size === 'medium' - ? CHECKMARK_WIDTH_MEDIUM - : CHECKMARK_WIDTH_LARGE; - if (selected || iconOnly) { - tempWidth = - child.getBoundingClientRect().width > tempWidth - ? child.getBoundingClientRect().width - : tempWidth; - } else { - tempWidth = - child.getBoundingClientRect().width + checkmark > tempWidth - ? child.getBoundingClientRect().width + checkmark - : tempWidth; - } - }); + Array.from(this.hostElement.children) + .filter((child) => child.getBoundingClientRect().width) + .forEach((child) => { + const selected = child.hasAttribute('selected'); + const iconOnly = child.hasAttribute('icon-only'); + const checkmark = + this.size === 'small' + ? CHECKMARK_WIDTH_SMALL + : this.size === 'medium' + ? CHECKMARK_WIDTH_MEDIUM + : CHECKMARK_WIDTH_LARGE; + if (selected || iconOnly) { + tempWidth = + child.getBoundingClientRect().width > tempWidth + ? child.getBoundingClientRect().width + : tempWidth; + } else { + tempWidth = + child.getBoundingClientRect().width + checkmark > tempWidth + ? child.getBoundingClientRect().width + checkmark + : tempWidth; + } + }); return tempWidth; } diff --git a/packages/components/src/components/tab-header/readme.md b/packages/components/src/components/tab-header/readme.md index 34d7389ef8..d2a70cb660 100644 --- a/packages/components/src/components/tab-header/readme.md +++ b/packages/components/src/components/tab-header/readme.md @@ -18,9 +18,10 @@ ## Events -| Event | Description | Type | -| -------------- | ----------- | ------------------ | -| `scale-select` | | `CustomEvent` | +| Event | Description | Type | +| ---------------- | ------------------------------------------------ | ------------------ | +| `scale-disabled` | Emitted when currently selected tab got disabled | `CustomEvent` | +| `scale-select` | Emitted on header select | `CustomEvent` | ---------------------------------------------- diff --git a/packages/components/src/components/tab-header/tab-header.tsx b/packages/components/src/components/tab-header/tab-header.tsx index 6102ce7f24..05eb9c772d 100644 --- a/packages/components/src/components/tab-header/tab-header.tsx +++ b/packages/components/src/components/tab-header/tab-header.tsx @@ -47,13 +47,16 @@ export class TabHeader { /** (optional) size */ @Prop() size?: 'small' | 'large' = 'small'; /** (optional) Whether the tab is selected */ - @Prop() selected?: boolean; + @Prop({ mutable: true }) selected?: boolean; /** (optional) Injected CSS styles */ @Prop() styles?: string; @State() hasFocus: boolean = false; + /** Emitted on header select */ @Event({ eventName: 'scale-select' }) scaleSelect: EventEmitter; + /** Emitted when currently selected tab got disabled */ + @Event({ eventName: 'scale-disabled' }) scaleDisabled: EventEmitter; @Listen('click') handleClick(event: MouseEvent) { @@ -61,28 +64,30 @@ export class TabHeader { if (this.disabled) { return; } + this.selected = true; this.scaleSelect.emit(); } @Watch('selected') selectedChanged(newValue: boolean) { - if (!this.hostElement.isConnected) { + if (!this.hostElement.isConnected || this.disabled) { return; } - if (!this.disabled) { - if (newValue === true && this.tabsHaveFocus()) { - // Having focus on the host element, and not on inner elements, - // is required because screen readers. - this.hostElement.focus(); - } - this.updateSlottedIcon(); + if (newValue) { + this.scaleSelect.emit(); + } + if (newValue && this.tabsHaveFocus()) { + // Having focus on the host element and not on inner elements is required because of screen readers + this.hostElement.focus(); } + this.updateSlottedIcon(); } @Watch('disabled') disabledChanged() { if (this.disabled) { this.selected = false; + this.scaleDisabled.emit(); } } diff --git a/packages/components/src/components/tab-nav/tab-nav.tsx b/packages/components/src/components/tab-nav/tab-nav.tsx index 9c199f36db..6d4416e32a 100644 --- a/packages/components/src/components/tab-nav/tab-nav.tsx +++ b/packages/components/src/components/tab-nav/tab-nav.tsx @@ -42,9 +42,12 @@ export class TabNav { handleSelect(event) { const nextTab = event.target as HTMLScaleTabHeaderElement; // Act only if it's a direct child - if (this.getAllEnabledTabs().includes(nextTab) && !nextTab.disabled) { - this.selectTab(nextTab); - } + this.selectNextTab(nextTab); + } + + @Listen('scale-disabled') + handleDisabledTabHeader() { + this.selectNextTab(); } @Listen('keydown') @@ -92,7 +95,7 @@ export class TabNav { customElements.whenDefined('scale-tab-header'), customElements.whenDefined('scale-tab-panel'), ]).then(() => { - this.linkPanels(); + this.linkPanelsAndSelectTab(); this.propagateSizeToTabs(); }); @@ -144,24 +147,33 @@ export class TabNav { return tabs[tabs.length - 1]; } - linkPanels() { + linkPanelsAndSelectTab() { const tabs = this.getAllTabs(); - const selectedTab = - tabs.find((x) => x.selected) || tabs.filter((x) => !x.disabled)[0]; - tabs.forEach((tab) => { const panel = tab.nextElementSibling; tab.setAttribute('aria-controls', panel.id); panel.setAttribute('aria-labelledby', tab.id); }); - this.selectTab(selectedTab); + this.selectNextTab(); } - reset() { + selectNextTab(nextTab?: HTMLScaleTabHeaderElement): void { + const tabs = this.getAllTabs(); + const tabToSelect = + (!nextTab?.disabled && nextTab) || + tabs.find((tab) => tab.selected) || + tabs.filter((tab) => !tab.disabled)[0]; + this.selectTab(tabToSelect); + } + + reset(nextTab?: HTMLScaleTabHeaderElement) { const tabs = this.getAllEnabledTabs(); + tabs.forEach((tab) => { + if (tab !== nextTab) { + tab.selected = false; + } + }); const panels = this.getAllPanels(); - - tabs.forEach((tab) => (tab.selected = false)); panels.forEach((panel) => (panel.hidden = true)); } @@ -171,10 +183,12 @@ export class TabNav { } selectTab(nextTab: HTMLScaleTabHeaderElement) { + this.reset(nextTab); + if (!nextTab.selected) { + nextTab.selected = true; + } const nextPanel = this.findPanelForTab(nextTab); - this.reset(); nextPanel.hidden = false; - nextTab.selected = true; } /** diff --git a/packages/components/src/components/telekom/telekom-nav-item/telekom-nav-item.css b/packages/components/src/components/telekom/telekom-nav-item/telekom-nav-item.css index ab7246040f..86a00b32ea 100644 --- a/packages/components/src/components/telekom/telekom-nav-item/telekom-nav-item.css +++ b/packages/components/src/components/telekom/telekom-nav-item/telekom-nav-item.css @@ -205,6 +205,15 @@ left: 0; } +.scale-telekom-nav-list[variant='functions'] + > .scale-telekom-nav-item + > :where(a, button):hover:after, +.scale-telekom-nav-list[variant='functions'] + > .scale-telekom-nav-item + > :where(button[aria-expanded='true']):after { + width: 100%; +} + .scale-telekom-nav-list[variant='main-nav'] > .scale-telekom-nav-item > :where(a, button):has(scale-badge[label]):hover:after, diff --git a/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.css b/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.css index 880e05a2a8..c5f71e4817 100644 --- a/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.css +++ b/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.css @@ -68,7 +68,7 @@ scale-telekom-profile-menu scale-menu-flyout { height: 12px; } -.scale-telekom-nav-item > button { +scale-telekom-profile-menu .scale-telekom-nav-item > button { padding-bottom: var(--_spacing-bottom-slotted-bottom); } diff --git a/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.tsx b/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.tsx index 598db4e56e..ca72410d3c 100644 --- a/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.tsx +++ b/packages/components/src/components/telekom/telekom-profile-menu/telekom-profile-menu.tsx @@ -165,7 +165,7 @@ export class TelekomProfileMenu { buildLogoutButton() { return { type: 'button', - name: this.logoutLabel, + name: this.logoutLabel || 'Logout', href: this.logoutUrl || LOGOUT_DEFAULT, variant: 'secondary', onClick: this.logoutHandler, @@ -176,17 +176,11 @@ export class TelekomProfileMenu { const divider = [{ type: 'divider' }]; const userInfo = readData(this.userInfo); - if (!userInfo) { - // console.error("userInfo missing"); - } - userInfo.type = 'userInfo'; - - let serviceLinks = readData(this.serviceLinks); - if (!serviceLinks) { - // console.error("serviceLinks missing"); - serviceLinks = []; + if (userInfo) { + userInfo.type = 'userInfo'; } + const serviceLinks = readData(this.serviceLinks) || []; for (const el of serviceLinks) { el.type = 'item'; } @@ -200,9 +194,11 @@ export class TelekomProfileMenu { let menu = []; - menu = menu.concat(userInfo); + if (userInfo) { + menu = menu.concat(userInfo); + } - if (!this.serviceLinksEmpty()) { + if (userInfo && !this.serviceLinksEmpty()) { menu = menu.concat(divider); } @@ -221,7 +217,10 @@ export class TelekomProfileMenu { } serviceLinksEmpty() { - return (this.hideLoginSettings && this.serviceLinks.length < 1) === true; + return ( + this.hideLoginSettings && + (!this.serviceLinks || this.serviceLinks.length < 1) + ); } buildDesktopMenuStyles() { diff --git a/packages/components/src/components/textarea/readme.md b/packages/components/src/components/textarea/readme.md index 0111cfd0ba..c5e9044087 100644 --- a/packages/components/src/components/textarea/readme.md +++ b/packages/components/src/components/textarea/readme.md @@ -7,29 +7,30 @@ ## Properties -| Property | Attribute | Description | Type | Default | -| ---------------- | ----------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------- | -| `cols` | `cols` | (optional) textarea column | `number` | `undefined` | -| `counter` | `counter` | (optional) Input counter | `boolean` | `undefined` | -| `disabled` | `disabled` | (optional) Input disabled | `boolean` | `undefined` | -| `helperText` | `helper-text` | (optional) Input helper text | `string` | `''` | -| `inputAutofocus` | `input-autofocus` | (optional) the input should automatically get focus when the page loads. | `boolean` | `undefined` | -| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | -| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | -| `label` | `label` | (optional) Input label | `string` | `''` | -| `maxLength` | `max-length` | (optional) Input max length | `number` | `undefined` | -| `minLength` | `min-length` | (optional) Input min length | `number` | `undefined` | -| `name` | `name` | (optional) Input name | `string` | `''` | -| `placeholder` | `placeholder` | (optional) Input placeHolder | `string` | `''` | -| `readonly` | `readonly` | (optional) Input readonly | `boolean` | `undefined` | -| `required` | `required` | (optional) Input required | `boolean` | `undefined` | -| `resize` | `resize` | (optional) textarea resize | `"horizontal" \| "none" \| "unset" \| "vertical"` | `undefined` | -| `rows` | `rows` | (optional) textarea row | `number` | `undefined` | -| `status` | `status` | **[DEPRECATED]** - invalid should replace status

    | `string` | `''` | -| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | -| `transparent` | `transparent` | (optional) input background transparent | `boolean` | `undefined` | -| `value` | `value` | (optional) Input value | `number \| string` | `''` | -| `variant` | `variant` | (optional) Variant | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` | +| Property | Attribute | Description | Type | Default | +| ---------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------- | +| `ariaDetailsId` | `aria-details-id` | (optional) id or space separated list of ids of elements that provide or link to additional related information. | `string` | `undefined` | +| `cols` | `cols` | (optional) textarea column | `number` | `undefined` | +| `counter` | `counter` | (optional) Input counter | `boolean` | `undefined` | +| `disabled` | `disabled` | (optional) Input disabled | `boolean` | `undefined` | +| `helperText` | `helper-text` | (optional) Input helper text | `string` | `''` | +| `inputAutofocus` | `input-autofocus` | (optional) the input should automatically get focus when the page loads. | `boolean` | `undefined` | +| `inputId` | `input-id` | (optional) Input checkbox id | `string` | `undefined` | +| `invalid` | `invalid` | (optional) Input status | `boolean` | `false` | +| `label` | `label` | (optional) Input label | `string` | `''` | +| `maxLength` | `max-length` | (optional) Input max length | `number` | `undefined` | +| `minLength` | `min-length` | (optional) Input min length | `number` | `undefined` | +| `name` | `name` | (optional) Input name | `string` | `''` | +| `placeholder` | `placeholder` | (optional) Input placeHolder | `string` | `''` | +| `readonly` | `readonly` | (optional) Input readonly | `boolean` | `undefined` | +| `required` | `required` | (optional) Input required | `boolean` | `undefined` | +| `resize` | `resize` | (optional) textarea resize | `"horizontal" \| "none" \| "unset" \| "vertical"` | `undefined` | +| `rows` | `rows` | (optional) textarea row | `number` | `undefined` | +| `status` | `status` | **[DEPRECATED]** - invalid should replace status

    | `string` | `''` | +| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` | +| `transparent` | `transparent` | (optional) input background transparent | `boolean` | `undefined` | +| `value` | `value` | (optional) Input value | `number \| string` | `''` | +| `variant` | `variant` | (optional) Variant | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` | ## Events diff --git a/packages/components/src/components/textarea/textarea.tsx b/packages/components/src/components/textarea/textarea.tsx index 3405e05c51..b8d39bc831 100644 --- a/packages/components/src/components/textarea/textarea.tsx +++ b/packages/components/src/components/textarea/textarea.tsx @@ -77,6 +77,8 @@ export class Textarea { @Prop() inputAutofocus?: boolean; /** (optional) Injected CSS styles */ @Prop() styles?: string; + /** (optional) id or space separated list of ids of elements that provide or link to additional related information. */ + @Prop() ariaDetailsId?: string; /** Emitted when a keyboard input occurred. */ @Event({ eventName: 'scale-input' }) scaleInput!: EventEmitter; @@ -173,7 +175,8 @@ export class Textarea { const ariaInvalidAttr = this.status === 'error' || this.invalid ? { 'aria-invalid': 'true' } : {}; const helperTextId = `helper-message-${this.internalId}`; - const ariaDescribedByAttr = { 'aria-describedBy': helperTextId }; + const describedBy = this.helperText ? helperTextId : this.ariaDetailsId; + const ariaDescribedByAttr = { 'aria-describedBy': describedBy }; const readonlyAttr = this.readonly ? { readonly: 'readonly' } : {}; return ( @@ -212,7 +215,10 @@ export class Textarea { {...(!!this.rows ? { rows: this.rows } : {})} {...(!!this.cols ? { cols: this.cols } : {})} {...ariaInvalidAttr} - {...(this.helperText ? ariaDescribedByAttr : {})} + {...(this.helperText || this.ariaDetailsId + ? ariaDescribedByAttr + : {})} + aria-details={this.ariaDetailsId} ref={(el) => (this.focusableElement = el)} />
    diff --git a/packages/components/src/html/data-grid.html b/packages/components/src/html/data-grid.html index ca25564166..36b48f64db 100644 --- a/packages/components/src/html/data-grid.html +++ b/packages/components/src/html/data-grid.html @@ -172,6 +172,8 @@ type: 'number', label: 'Numbers', sortable: true, + presort: true, + presortDirection: 'descending', precision: 2, decimalSymbol: '.', groupSymbol: ',', @@ -187,6 +189,16 @@ style: 'switch', editable: true, }, + { + type: 'text', + label: 'Nr-edit', + editable: true, + width: 60, + textFieldProps: { + type: 'number', + max: 2, + }, + }, { type: 'graph', label: 'Progress', @@ -212,10 +224,15 @@ 'One', 'Lorem ipsum dolor sit amet sime', 'http://example.com', - 'Simple, Short', + [ + { content: 'Apple', color: 'red', size: 'standard' }, + { content: 'Pear', color: 'green', type: 'strong' }, + { content: 'Bug' }, + ], '00:00:20', - 102045.0, + 101045.0, false, + 1, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -249,6 +266,7 @@ '00:01:15', 43.2, true, + 2, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -282,6 +300,7 @@ '00:00:20', 102045.0, false, + 3, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -318,8 +337,9 @@ 'http://example.com', 'Simple, Short', '00:01:15', - 43.2, + 45.2, true, + 4, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -351,8 +371,9 @@ 'http://example.com', 'Simple, Short', '00:00:20', - 102045.0, + 103045.0, false, + 5, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -384,8 +405,9 @@ 'http://example.com', 'Simple, Short', '00:01:15', - 43.2, + 47.2, true, + 6, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -417,8 +439,9 @@ 'http://example.com', 'Simple, Short', '00:00:20', - 102045.0, + 105045.0, false, + 7, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -450,8 +473,9 @@ 'http://example.com', 'Simple, Short', '00:01:15', - 43.2, + 48.2, true, + 8, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -483,8 +507,9 @@ 'http://example.com', 'Simple, Short', '00:00:20', - 102045.0, + 109045.0, false, + 9, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -516,8 +541,9 @@ 'http://example.com', 'Simple, Short', '00:01:15', - 43.2, + 40.2, true, + 10, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -549,8 +575,9 @@ 'http://example.com', 'Simple, Short', '00:00:20', - 102045.0, + 108045.0, false, + 11, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -584,6 +611,7 @@ '00:01:15', 43.2, true, + 12, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -616,6 +644,7 @@ '00:00:20', 102045.0, false, + 13, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -649,6 +678,7 @@ '00:01:15', 43.2, true, + 14, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -683,6 +713,7 @@ 102045.0, false, 15, + 15, (() => { const demoNestedContent = document.createElement('div'); demoNestedContent.innerHTML = ` @@ -715,6 +746,7 @@ '00:01:15', 43.2, true, + 16, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -748,6 +780,7 @@ '00:00:20', 102045.0, false, + 17, 15, (() => { const demoNestedContent = document.createElement('div'); @@ -781,6 +814,7 @@ '00:01:15', 43.2, true, + 18, 73.2, (() => { const demoNestedContent = document.createElement('div'); @@ -805,11 +839,29 @@ ], ]; + const localization = { + sortBy: 'SortLoc', + toggle: 'ToggleLoc', + select: 'SelectLoc', + tableOptions: 'OptionsLoc', + expand: 'Klicken Sie zu expanden', + }; + // Pass in data const table = document.querySelector('#table1'); - + document + .querySelector('scale-data-grid') + .addEventListener('scale-sort', ({ detail }) => { + console.log('sort', detail); + }); + document + .querySelector('scale-data-grid') + .addEventListener('scale-selection', ({ detail }) => { + console.log('select', detail); + }); table.fields = fields; table.rows = rows; + table.localization = localization; // table.addEventListener('scaleEdit', ({ detail }) => { // const { rows, rowIndex, columnIndex, value } = detail; diff --git a/packages/components/src/html/segment-button.html b/packages/components/src/html/segment-button.html new file mode 100644 index 0000000000..771e502b3e --- /dev/null +++ b/packages/components/src/html/segment-button.html @@ -0,0 +1,80 @@ + + + + + + Segment Buttons + + + + + + + + + +
    Open Me for Disaster
    + + Apple + One+ + Samsung + Huawei + +
    +
    + + Apple + One+ + Samsung + Huawei + +
    + + Label + Label + +
    + + + + + Apple + + + + + One+ + + + + + Samsung + + + + + Huawei + + +
    + + + Apple + One+ + Samsung + Huawei + + + diff --git a/packages/components/src/html/tab-nav.html b/packages/components/src/html/tab-nav.html new file mode 100644 index 0000000000..781aa03b9f --- /dev/null +++ b/packages/components/src/html/tab-nav.html @@ -0,0 +1,58 @@ + + + + + + Stencil Component Starter + + + + + + + +

    + + General + + 1 Freegan kinfolk farm-to-table humblebrag cred… + + Usage + + 2 Bespoke austin pork belly yuccie pop-up. Before they sold out… + + Style + + 3 Biodiesel chia af hoodie tumeric bespoke letterpress… + + Code + + 4 Asymmetrical tattooed chia, banh mi blog microdosing… + + +

    + + + diff --git a/packages/components/src/html/telekom-header-profile-menu.html b/packages/components/src/html/telekom-header-profile-menu.html new file mode 100644 index 0000000000..22c169c62f --- /dev/null +++ b/packages/components/src/html/telekom-header-profile-menu.html @@ -0,0 +1,601 @@ + + + + + + Telekom Header + + + + + + + + + + + + + + + + + My heading + + + + + My heading + + + + + My heading + + + + + My heading + + + + + My heading + + + + + + + + + + + Tarife + + + + Geräte + + + + Vernetztes Zuhause + + + + Netz + + + + + + + Topic Three + + + Topic Four + + + Topic Five + + + + + + Metalink ext 1 + + + + + + Metalink ext 2 + + + + + + + Metalink 1 + + + Metalink 2 + + + + + MK + + + SO + + + DE + + + + + + + + + + + + + + + + + + + + + + + + + + Metalink ext 1 + + + + + + Metalink ext 2 + + + + + + + MK + + + SO + + + DE + + + + Topic One + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + + Topic Two + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + Second Level + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + Third Level + + + + + Topic Three + + + Topic Four + + + Topic Five + + + + Metalink ext 1 + + + Metalink ext 2 + + + + + +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    +

     

    + + + + 1 + 2 + 3 + 4 + 5 + + + diff --git a/packages/components/stencil.config.ts b/packages/components/stencil.config.ts index 7ba424577c..b47b33ab89 100644 --- a/packages/components/stencil.config.ts +++ b/packages/components/stencil.config.ts @@ -78,7 +78,7 @@ export const config: Config = { }, { type: 'docs-vscode', - file: 'custom-elements.json', + file: './dist/vscode-data.json', }, { type: 'docs-json', diff --git a/packages/design-tokens/CHANGELOG.md b/packages/design-tokens/CHANGELOG.md index b1f3cb2653..25682a59b5 100644 --- a/packages/design-tokens/CHANGELOG.md +++ b/packages/design-tokens/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + +**Note:** Version bump only for package @telekom/scale-design-tokens + + + + + + # [3.0.0-beta.153](https://github.com/telekom/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) **Note:** Version bump only for package @telekom/scale-design-tokens diff --git a/packages/design-tokens/package.json b/packages/design-tokens/package.json index e8f5098ba9..78abee5353 100644 --- a/packages/design-tokens/package.json +++ b/packages/design-tokens/package.json @@ -1,6 +1,6 @@ { "name": "@telekom/scale-design-tokens", - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "type": "module", "description": "Design Tokens for the Scale Design System", "homepage": "https://github.com/telekom/scale", diff --git a/packages/storybook-vue/CHANGELOG.md b/packages/storybook-vue/CHANGELOG.md index 902dc2e621..dc9a575594 100644 --- a/packages/storybook-vue/CHANGELOG.md +++ b/packages/storybook-vue/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/amir-ba/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + + +### Bug Fixes + +* **tab-nav:** fixes preselect logic in tabs with disabled attribute ([#2320](https://github.com/amir-ba/scale/issues/2320)) ([bd30a6f](https://github.com/amir-ba/scale/commit/bd30a6f2a187976ae85234b5f526537f68b3ea80)) + + +### Features + +* **data-grid:** add scale-selection event and enhance editable text field ([#2362](https://github.com/amir-ba/scale/issues/2362)) ([eeaecaf](https://github.com/amir-ba/scale/commit/eeaecaf461f014fb57c4ad14e3f279640b777c5f)) +* aria-details added to all input types ([#2359](https://github.com/amir-ba/scale/issues/2359)) ([4c45650](https://github.com/amir-ba/scale/commit/4c45650e14eff01ef42525f08ba27c1c7b0f2109)) +* **data-grid:** adds presort to grid ([#2335](https://github.com/amir-ba/scale/issues/2335)) ([f657202](https://github.com/amir-ba/scale/commit/f6572021489ae07914dbbb6d31cb0aa2d20ea74c)) + + + + + + # [3.0.0-beta.153](https://github.com/amir-ba/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) **Note:** Version bump only for package @telekom/scale-storybook-vue diff --git a/packages/storybook-vue/package.json b/packages/storybook-vue/package.json index cd29504581..a87631faaf 100644 --- a/packages/storybook-vue/package.json +++ b/packages/storybook-vue/package.json @@ -2,7 +2,7 @@ "homepage": "https://telekom.github.io/scale", "name": "@telekom/scale-storybook-vue", "private": true, - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "main": "index.js", "license": "MPL-2.0", "devDependencies": { @@ -32,8 +32,8 @@ "dependencies": { "@storybook/addon-viewport": "^6.4.22", "@telekom/design-tokens": "^1.0.0-beta.2", - "@telekom/scale-components": "^3.0.0-beta.153", - "@telekom/scale-components-vue": "^3.0.0-beta.153" + "@telekom/scale-components": "^3.0.0-beta.154", + "@telekom/scale-components-vue": "^3.0.0-beta.154" }, "scripts": { "prestart": "rm -rf node_modules/.cache/ && yes | cp -a ../components/dist/scale-components/fonts/* public/fonts/ && yes | cp -a ../components/dist/scale-components/scale-components.css public/", diff --git a/packages/storybook-vue/stories/components/checkbox/Checkbox.stories.mdx b/packages/storybook-vue/stories/components/checkbox/Checkbox.stories.mdx index 915a66902d..61b9b7c4fc 100644 --- a/packages/storybook-vue/stories/components/checkbox/Checkbox.stories.mdx +++ b/packages/storybook-vue/stories/components/checkbox/Checkbox.stories.mdx @@ -68,8 +68,9 @@ export const Template = (args, { argTypes }) => ({ ```css scale-checkbox { --spacing-x: var(--telekom-spacing-composition-space-04); - --transition: all var(--telekom-motion-duration-transition) - var(--telekom-motion-easing-standard); + --transition: all var(--telekom-motion-duration-transition) var( + --telekom-motion-easing-standard + ); --color-text: var(--telekom-color-text-and-icon-standard); --color-error: var(--telekom-color-functional-danger-standard); --color-disabled: var(--telekom-color-text-and-icon-disabled); @@ -254,4 +255,4 @@ scale-checkbox { > -``` \ No newline at end of file +``` diff --git a/packages/storybook-vue/stories/components/checkbox/ScaleCheckbox.vue b/packages/storybook-vue/stories/components/checkbox/ScaleCheckbox.vue index 6aa6a2d29a..99353851b7 100644 --- a/packages/storybook-vue/stories/components/checkbox/ScaleCheckbox.vue +++ b/packages/storybook-vue/stories/components/checkbox/ScaleCheckbox.vue @@ -31,7 +31,8 @@ export default { value: { type: String }, inputId: { type: String }, required: { type: Boolean }, - ariaLabelCheckbox: { type: String} + ariaLabelCheckbox: { type: String }, + ariaDetailsId: { type: String }, }, methods: { scaleChange($event) { diff --git a/packages/storybook-vue/stories/components/data-grid/DataGrid.stories.mdx b/packages/storybook-vue/stories/components/data-grid/DataGrid.stories.mdx index 4c38c09346..db35d26a9d 100644 --- a/packages/storybook-vue/stories/components/data-grid/DataGrid.stories.mdx +++ b/packages/storybook-vue/stories/components/data-grid/DataGrid.stories.mdx @@ -42,7 +42,7 @@ import ScaleDataGrid from './ScaleDataGrid.vue'; }, description: `(optional) Title for sortable columns`, control: { type: null }, - }, + }, height: { table: { type: { summary: 'string' }, @@ -111,7 +111,7 @@ import ScaleDataGrid from './ScaleDataGrid.vue'; table: { type: { summary: 'object' }, }, - description: `(optional) localization object for sort by, toogle visibility and select/deselect all. The default value is English`, + description: `(optional) localization object for sort by, toogle visibility, select/deselect all, table settings, expand/collapse buttons. The default value is English. To provide localization, use object with next keys: 'sortBy', 'toggle', 'select', 'tableOptions', 'expand', 'collapse'`, control: { type: null }, }, shadeAlternate: { @@ -169,6 +169,14 @@ import ScaleDataGrid from './ScaleDataGrid.vue'; description: `Event triggered every time the data is sorted, changing original rows data`, control: { type: null }, }, + eventScaleSelection: { + name: '[event] scale-selection', + table: { + type: { summary: 'event' }, + }, + description: `Event triggered every time the selection list updates`, + control: { type: null }, + }, slotMenu: { name: '[slot] menu', table: { @@ -309,6 +317,8 @@ const rows = [ [1, 'John', '12:30'], [2, 'Mary', '2:12'], [3, 'Patek', '16:01'], - `resizable?: boolean = true` - `sortable?: boolean = false` - `sortBy?: 'number' | 'text' = 'text'` +- `presort?: boolean = false` +- `presortDirection?: 'ascending' | 'descending' = 'ascending'` - `textAlign?: 'left' | 'center' | 'right' = 'left'` - `stretchWeight?: 'number'` - `visible?: boolean = true` @@ -669,7 +679,7 @@ Expected format: string ## Tags Cell -Expected format: comma delimited `string`, eg `'one, two, three'` or array of objects with content and color keys, e.g. `{content: 'Apple', color: 'red'}` +Expected format: comma delimited `string`, eg `'one, two, three'` or array of objects with required content key and optional color, type, size keys, e.g. `{content: 'Apple', color: 'red'}`. Acceptable values for color, type, size are same as for [Tag component](?path=/docs/components-tag--standard). @@ -738,8 +748,12 @@ Expected format: unformatted `string`, eg `'this is a string'` - `iconPrefix?: scale-icon-string (eg 'action-download')` - `iconSuffix?: scale-icon-string (eg 'action-download')` - `editable?: boolean = false` +- `textFieldProps?: Object (eg { type: 'number', helperText: 'Enter a number' })` - + + If `editable` is set to `true`, a `scale-text-field` is used for the element. The properties of the `scale-text-field` can be passed directly to the editable component using the `textFieldProps` attribute. + and if the `editable` is set to `false`, the `textFieldProps` has no effect, as the cell will be read-only. + {` @@ -1381,6 +1395,43 @@ Expected format: unformatted `string`, eg `'this is a string'` +## Presort + +To make grid presorted by certain field on init, add next props to this field: `sortable: true`, `presort: true`, `presortDirection: 'ascending' | 'descending'`. + + + + {` + + + `} + + + diff --git a/packages/storybook-vue/stories/components/date-picker/DatePicker.stories.mdx b/packages/storybook-vue/stories/components/date-picker/DatePicker.stories.mdx index d43cb7f1b9..4ae56bf53e 100644 --- a/packages/storybook-vue/stories/components/date-picker/DatePicker.stories.mdx +++ b/packages/storybook-vue/stories/components/date-picker/DatePicker.stories.mdx @@ -204,7 +204,7 @@ export const RangeTemplate = (args, { argTypes }) => ({ args={{ value: '2020-12-31', label: 'Standard', - placeholder: 'Select date' + placeholder: 'Select date', }} > {Template.bind({})} @@ -251,8 +251,9 @@ duet-date-picker { --font-size-day: var(--telekom-typography-font-size-body); --font-size-table-header: var(--telekom-typography-font-size-caption); --font-weight-table-header: var(--telekom-typography-font-weight-extra-bold); - --focus-outline: var(--telekom-line-weight-highlight) solid - var(--telekom-color-functional-focus-standard); + --focus-outline: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-focus-standard + ); --z-index-label: 10; } @@ -290,7 +291,7 @@ duet-date-picker { label: 'With Error', invalid: true, helperText: 'something is wrong', - placeholder: 'select date' + placeholder: 'select date', }} > {Template.bind({})} diff --git a/packages/storybook-vue/stories/components/date-picker/ScaleDatePicker.vue b/packages/storybook-vue/stories/components/date-picker/ScaleDatePicker.vue index 7dc8496b8b..087eaeda1c 100644 --- a/packages/storybook-vue/stories/components/date-picker/ScaleDatePicker.vue +++ b/packages/storybook-vue/stories/components/date-picker/ScaleDatePicker.vue @@ -50,6 +50,7 @@ export default { styles: { type: String }, placeholder: { type: String }, size: { type: String }, + ariaDetailsId: { type: String }, }, methods: { scaleChange($event) { diff --git a/packages/storybook-vue/stories/components/dropdown-select/DropdownSelect.stories.mdx b/packages/storybook-vue/stories/components/dropdown-select/DropdownSelect.stories.mdx index b295b8e77e..ee7c61bec7 100644 --- a/packages/storybook-vue/stories/components/dropdown-select/DropdownSelect.stories.mdx +++ b/packages/storybook-vue/stories/components/dropdown-select/DropdownSelect.stories.mdx @@ -13,8 +13,8 @@ import { action } from '@storybook/addon-actions'; export const Template = (args, { argTypes }) => ({ components: { ScaleDropdownSelect }, props: { - itemProps: { default: {} }, - ...ScaleDropdownSelect.props, + itemProps: { default: {} }, + ...ScaleDropdownSelect.props, }, data() { return { @@ -106,18 +106,22 @@ export const Template = (args, { argTypes }) => ({ --color-disabled: var(--telekom-color-text-and-icon-disabled); --background-disabled: none; --background-hover: var(--telekom-color-ui-state-fill-hovered); - --border: var(--telekom-spacing-composition-space-01) solid - var(--telekom-color-ui-border-standard); + --border: var(--telekom-spacing-composition-space-01) solid var( + --telekom-color-ui-border-standard + ); --border-color-hover: var(--telekom-color-ui-border-hovered); --border-color-focus: var(--telekom-color-ui-border-hovered); --border-color-disabled: var(--telekom-color-ui-border-disabled); - --border-invalid: var(--telekom-spacing-composition-space-02) solid - var(--telekom-color-functional-danger-hovered); - --focus-outline: var(--telekom-line-weight-highlight) solid - var(--telekom-color-functional-focus-standard); + --border-invalid: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-danger-hovered + ); + --focus-outline: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-focus-standard + ); --spacing-x: var(--telekom-spacing-composition-space-05); - --transition: all var(--telekom-motion-duration-transition) - var(--telekom-motion-easing-standard); + --transition: all var(--telekom-motion-duration-transition) var( + --telekom-motion-easing-standard + ); --radius: var(--telekom-radius-standard); --spacing-x-for-helper-text: var(--telekom-spacing-composition-space-03); @@ -128,9 +132,9 @@ export const Template = (args, { argTypes }) => ({ 18px 32px 4px 12px (subtracting 1px from border) */ - --spacing-combobox: 1.125rem - calc(2rem - var(--telekom-spacing-composition-space-01)) 0.25rem - calc(0.75rem - var(--telekom-spacing-composition-space-01)); + --spacing-combobox: 1.125rem calc( + 2rem - var(--telekom-spacing-composition-space-01) + ) 0.25rem calc(0.75rem - var(--telekom-spacing-composition-space-01)); /*meta*/ --spacing-y-meta: var(--telekom-spacing-composition-space-03); @@ -155,17 +159,16 @@ export const Template = (args, { argTypes }) => ({ /*listbox*/ --background-listbox: var(--telekom-color-background-surface); - --box-shadow-listbox: 0 2px 4px 0 rgba(0, 0, 0, 0.1), - 0 4px 16px 0 rgba(0, 0, 0, 0.1); + --box-shadow-listbox: 0 2px 4px 0 rgba(0, 0, 0, 0.1), 0 4px 16px 0 rgba(0, 0, 0, 0.1); --max-height-listbox: 300px; --z-index-listbox: 99; } - ``` ## Disabled ### Whole Dropdown Select disabled + ({ ``` ### Individual items disabled + ({ ```html - Caspar - Cedric + Caspar + Cedric Cem ``` diff --git a/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue b/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue index 7b4ad43c48..9b63c21bb4 100644 --- a/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue +++ b/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue @@ -35,6 +35,7 @@ export default { comboboxId: { type: String }, hideLabelVisually: { type: Boolean, default: false }, floatingStrategy: { type: String }, + ariaDetailsId: { type: String }, }, methods: { 'scale-change'($event) { diff --git a/packages/storybook-vue/stories/components/dropdown/DropDown.stories.mdx b/packages/storybook-vue/stories/components/dropdown/DropDown.stories.mdx index 4f6dea162e..39fee2f627 100644 --- a/packages/storybook-vue/stories/components/dropdown/DropDown.stories.mdx +++ b/packages/storybook-vue/stories/components/dropdown/DropDown.stories.mdx @@ -97,24 +97,31 @@ export const Template = (args, { argTypes }) => ({ --font-weight: var(--telekom-typography-font-weight-bold); --height: var(--telekom-spacing-composition-space-13); --spacing-x: var(--telekom-spacing-composition-space-05); - --spacing-dropdown: 18px var(--telekom-spacing-composition-space-12) 5px - calc(var(--spacing-x) - 1px); - --transition: all var(--telekom-motion-duration-transition) - var(--telekom-motion-easing-standard); + --spacing-dropdown: 18px var(--telekom-spacing-composition-space-12) 5px calc( + var(--spacing-x) - 1px + ); + --transition: all var(--telekom-motion-duration-transition) var( + --telekom-motion-easing-standard + ); --radius: var(--telekom-radius-standard); - --border: var(--telekom-spacing-composition-space-01) solid - var(--telekom-color-ui-border-standard); - --border-danger: var(--telekom-spacing-composition-space-02) solid - var(--telekom-color-functional-danger-standard); - --border-success: var(--telekom-spacing-composition-space-02) solid - var(--telekom-color-functional-success-standard); - --border-warning: var(--telekom-spacing-composition-space-02) solid - var(--telekom-color-functional-warning-standard); + --border: var(--telekom-spacing-composition-space-01) solid var( + --telekom-color-ui-border-standard + ); + --border-danger: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-danger-standard + ); + --border-success: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-success-standard + ); + --border-warning: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-warning-standard + ); --border-color-hover: var(--telekom-color-ui-border-hovered); --border-color-focus: var(--telekom-color-ui-border-hovered); --border-color-disabled: var(--telekom-color-ui-border-disabled); - --focus-outline: var(--telekom-line-weight-highlight) solid - var(--telekom-color-functional-focus-standard); + --focus-outline: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-focus-standard + ); --color-disabled: var(--telekom-color-text-and-icon-disabled); --background-disabled: none; --color: var(--telekom-color-text-and-icon-standard); @@ -267,6 +274,9 @@ The display error is on the browser side. - + ``` diff --git a/packages/storybook-vue/stories/components/dropdown/ScaleDropDown.vue b/packages/storybook-vue/stories/components/dropdown/ScaleDropDown.vue index d4de8dad51..34cded1916 100644 --- a/packages/storybook-vue/stories/components/dropdown/ScaleDropDown.vue +++ b/packages/storybook-vue/stories/components/dropdown/ScaleDropDown.vue @@ -40,6 +40,7 @@ export default { controlled: { type: Boolean }, styles: { type: String }, size: { type: String }, + ariaDetailsId: { type: String }, }, methods: { scaleInput($event) { diff --git a/packages/storybook-vue/stories/components/radio-button-group/RadioButtonGroup.stories.mdx b/packages/storybook-vue/stories/components/radio-button-group/RadioButtonGroup.stories.mdx index e7d12e2a55..3cc4a0ac29 100644 --- a/packages/storybook-vue/stories/components/radio-button-group/RadioButtonGroup.stories.mdx +++ b/packages/storybook-vue/stories/components/radio-button-group/RadioButtonGroup.stories.mdx @@ -54,8 +54,8 @@ export const Template = (args, context) => ({ :disabled="itemProps[index]?.disabled" > - ` -}) + `, +});
    ({ {Template.bind({})} @@ -137,8 +137,9 @@ scale-radio-button { --color-disabled: var(--telekom-color-text-and-icon-disabled); --background-disabled: var(--telekom-color-ui-disabled); --color-error: var(--telekom-color-text-and-icon-functional-danger); - --transition: all var(--telekom-motion-duration-transition) - var(--telekom-motion-easing-standard); + --transition: all var(--telekom-motion-duration-transition) var( + --telekom-motion-easing-standard + ); --color-primary: var(--telekom-color-text-and-icon-primary-standard); --color-primary-hover: var(--telekom-color-text-and-icon-standard); --color-primary-active: var(--telekom-color-text-and-icon-standard); @@ -171,26 +172,29 @@ scale-radio-button { --height-control: var(--telekom-spacing-composition-space-07); --transition-control: var(--transition); --background-color-control: var(--telekom-color-ui-base); - --border-control: var(--telekom-spacing-composition-space-01) solid - var(--telekom-color-ui-border-standard); + --border-control: var(--telekom-spacing-composition-space-01) solid var( + --telekom-color-ui-border-standard + ); --line-height-helper-text: var(--telekom-typography-line-spacing-standard); --border-control-checked: calc( 0.25 * var(--telekom-spacing-composition-space-05) - ) - solid var(--telekom-color-background-canvas); + ) solid var(--telekom-color-background-canvas); --border-control-checked-disabled: calc( 0.5 * var(--telekom-spacing-composition-space-05) - ) - solid var(--telekom-color-ui-border-disabled); + ) solid var(--telekom-color-ui-border-disabled); --background-control-checked-disabled: none; - --border-control-active: var(--telekom-spacing-composition-space-04) solid - var(--telekom-color-primary-pressed); - --border-control-disabled: 0 0 0 var(--telekom-spacing-composition-space-01) - var(--telekom-color-ui-border-disabled); - --border-control-error: var(--telekom-spacing-composition-space-02) solid - var(--telekom-color-functional-danger-standard); - --box-shadow-control-focus: 0 0 0 var(--telekom-spacing-composition-space-03) - var(--color-focus); + --border-control-active: var(--telekom-spacing-composition-space-04) solid var( + --telekom-color-primary-pressed + ); + --border-control-disabled: 0 0 0 var(--telekom-spacing-composition-space-01) var( + --telekom-color-ui-border-disabled + ); + --border-control-error: var(--telekom-spacing-composition-space-02) solid var( + --telekom-color-functional-danger-standard + ); + --box-shadow-control-focus: 0 0 0 var(--telekom-spacing-composition-space-03) var( + --color-focus + ); } ``` @@ -233,7 +237,10 @@ scale-radio-button { ```html - + {Template.bind({})} @@ -279,7 +286,11 @@ scale-radio-button { ```html - + {Template.bind({})} diff --git a/packages/storybook-vue/stories/components/radio-button-group/ScaleRadioButton.vue b/packages/storybook-vue/stories/components/radio-button-group/ScaleRadioButton.vue index 6254aaad3a..9404f7ed18 100644 --- a/packages/storybook-vue/stories/components/radio-button-group/ScaleRadioButton.vue +++ b/packages/storybook-vue/stories/components/radio-button-group/ScaleRadioButton.vue @@ -10,15 +10,16 @@ export default { checked: { type: Boolean }, value: { type: String }, inputId: { type: String }, - styles: { type: String } + styles: { type: String }, + ariaDetailsId: { type: String }, }, methods: { fireEvents() { this.$emit('scale-change'); - } + }, }, render() { return this.$slots.default; - } + }, }; diff --git a/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue b/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue index 5459aa6c41..5313d2d49c 100644 --- a/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue +++ b/packages/storybook-vue/stories/components/tab-navigation/ScaleTabNav.vue @@ -24,7 +24,7 @@ bitters.

    - + Style @@ -55,8 +55,10 @@ export default { props: { styles: { type: String }, disabled: { type: Boolean, default: false }, + preselected: { type: Boolean, default: false }, withIcon: { type: Boolean, default: true }, size: { type: String, default: 'small' }, + small: { type: Boolean, default: false }, }, }; diff --git a/packages/storybook-vue/stories/components/tab-navigation/TabHeader.vue b/packages/storybook-vue/stories/components/tab-navigation/TabHeader.vue new file mode 100644 index 0000000000..cf8d656419 --- /dev/null +++ b/packages/storybook-vue/stories/components/tab-navigation/TabHeader.vue @@ -0,0 +1,11 @@ + diff --git a/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx b/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx index 3a09963717..bc5660a73f 100644 --- a/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx +++ b/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx @@ -6,12 +6,13 @@ import { Description, } from '@storybook/addon-docs'; import ScaleTabNav from './ScaleTabNav.vue'; +import TabHeader from './TabHeader.vue'; import TabPanel from './TabPanel.vue'; @@ -41,7 +49,7 @@ export const Template = (args, { argTypes }) => ({ components: { ScaleTabNav }, props: ScaleTabNav.props, template: ` - + `, }); @@ -123,8 +131,9 @@ export const Template = (args, { argTypes }) => ({ --color-hover: var(--telekom-color-text-and-icon-primary-hovered); --color-active: var(--telekom-color-text-and-icon-primary-pressed); --color-selected: var(--telekom-color-text-and-icon-primary-standard); - --focus-outline: var(--telekom-line-weight-highlight) solid - var(--telekom-color-functional-focus-standard); + --focus-outline: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-focus-standard + ); --spacing-right-slotted: var(--telekom-spacing-composition-space-04); --color-disabled: var(--telekom-color-text-and-icon-disabled); --radius: var(--telekom-radius-standard); @@ -200,6 +209,38 @@ For Shadow Parts, please inspect the element's #shadow. ``` +## Preselected Tab + + + + {Template.bind({})} + + + +```html + + General + + Freegan kinfolk farm-to-table humblebrag cred… + + Usage + + Bespoke austin pork belly yuccie pop-up. Before they sold out… + + Style + + Biodiesel chia af hoodie tumeric bespoke letterpress… + + Code + + Asymmetrical tattooed chia, banh mi blog microdosing… + + +``` + ## Large, Text & Icon diff --git a/packages/storybook-vue/stories/components/text-area/ScaleTextArea.vue b/packages/storybook-vue/stories/components/text-area/ScaleTextArea.vue index 28e4115f48..ac9931bec1 100644 --- a/packages/storybook-vue/stories/components/text-area/ScaleTextArea.vue +++ b/packages/storybook-vue/stories/components/text-area/ScaleTextArea.vue @@ -52,6 +52,7 @@ export default { transparent: { type: Boolean }, inputAutofocus: { type: Boolean }, styles: { type: String }, + ariaDetailsId: { type: String }, }, methods: { scaleInput($event) { diff --git a/packages/storybook-vue/stories/components/text-area/TextArea.stories.mdx b/packages/storybook-vue/stories/components/text-area/TextArea.stories.mdx index 64637c058e..a815809d15 100644 --- a/packages/storybook-vue/stories/components/text-area/TextArea.stories.mdx +++ b/packages/storybook-vue/stories/components/text-area/TextArea.stories.mdx @@ -89,20 +89,24 @@ export const Template = (args, { argTypes }) => ({ ```css scale-textarea { - --transition: all var(--telekom-motion-duration-transition) - var(--telekom-motion-easing-standard); + --transition: all var(--telekom-motion-duration-transition) var( + --telekom-motion-easing-standard + ); --radius: var(--telekom-radius-standard); - --border: var(--telekom-line-weight-standard) solid - var(--telekom-color-ui-border-standard); - --border-error: var(--telekom-line-weight-highlight) solid - var(--telekom-color-functional-danger-standard); + --border: var(--telekom-line-weight-standard) solid var( + --telekom-color-ui-border-standard + ); + --border-error: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-danger-standard + ); --border-color-hover: var(--telekom-color-ui-border-hovered); --border-color-focus: var(--telekom-color-ui-border-hovered); --border-color-disabled: var(--telekom-color-ui-border-disabled); --background-color-hover: var(--telekom-color-ui-state-fill-hovered); --background-color-disabled: none; - --focus-outline: var(--telekom-line-weight-highlight) solid - var(--telekom-color-functional-focus-standard); + --focus-outline: var(--telekom-line-weight-highlight) solid var( + --telekom-color-functional-focus-standard + ); --spacing-x-control: var(--telekom-spacing-composition-space-05); --spacing-bottom-control: var(--telekom-spacing-composition-space-05); --spacing-top-control: calc( @@ -126,8 +130,8 @@ scale-textarea { 18px 32px 4px 12px (subtracting 1px from border) */ - --spacing-control: 0 calc(2rem - var(--telekom-spacing-composition-space-01)) - 0.25rem calc(0.75rem - var(--telekom-spacing-composition-space-01)); + --spacing-control: 0 calc(2rem - var(--telekom-spacing-composition-space-01)) 0.25rem + calc(0.75rem - var(--telekom-spacing-composition-space-01)); --transition-control: var(--transition); --background-control: var(--telekom-color-ui-state-fill-standard); @@ -236,9 +240,9 @@ scale-textarea { {Template.bind({})} @@ -246,7 +250,11 @@ scale-textarea { ```html - + ``` ## Max Length With Counter diff --git a/packages/visual-tests/CHANGELOG.md b/packages/visual-tests/CHANGELOG.md index c9f0645a23..a9e48e8479 100644 --- a/packages/visual-tests/CHANGELOG.md +++ b/packages/visual-tests/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.0.0-beta.154](https://github.com/amir-ba/scale/compare/v3.0.0-beta.152...v3.0.0-beta.154) (2024-11-06) + +**Note:** Version bump only for package @telekom/scale-visual-tests + + + + + + # [3.0.0-beta.153](https://github.com/amir-ba/scale/compare/v3.0.0-beta.152...v3.0.0-beta.153) (2024-09-19) **Note:** Version bump only for package @telekom/scale-visual-tests diff --git a/packages/visual-tests/package.json b/packages/visual-tests/package.json index 295e79fba9..7b35faa26a 100644 --- a/packages/visual-tests/package.json +++ b/packages/visual-tests/package.json @@ -1,7 +1,7 @@ { "name": "@telekom/scale-visual-tests", "private": true, - "version": "3.0.0-beta.153", + "version": "3.0.0-beta.154", "main": "index.js", "license": "MPL-2.0", "scripts": {