diff --git a/CHANGELOG.md b/CHANGELOG.md
index fe72cc56d9..269d3107ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,33 @@
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.144](https://github.com/telekom/scale/compare/v3.0.0-beta.143...v3.0.0-beta.144) (2023-11-30)
+
+
+### Bug Fixes
+
+* add hidden input with name attribute ([#2212](https://github.com/telekom/scale/issues/2212)) ([ebd325f](https://github.com/telekom/scale/commit/ebd325f26c208f8fb8f0803835d5571461730631))
+* add prop for removing tabindex ([#2215](https://github.com/telekom/scale/issues/2215)) ([3fdafab](https://github.com/telekom/scale/commit/3fdafab34f567056044918228b84fcb6c30869d1))
+* allow sorting by german date format ([#2159](https://github.com/telekom/scale/issues/2159)) ([4229de7](https://github.com/telekom/scale/commit/4229de7588dbaacf6b6be07d7694c2b88b14bd3a))
+* aria role behavior ([#2171](https://github.com/telekom/scale/issues/2171)) ([59c57bc](https://github.com/telekom/scale/commit/59c57bc08d98957675bd210927cf028ceb275f89))
+* exclude hidden input from dropdown select options ([#2224](https://github.com/telekom/scale/issues/2224)) ([d5e2e5b](https://github.com/telekom/scale/commit/d5e2e5bdfc82baa7cdf8bcfcc7ba74fe67731f9b))
+* logo only focusable if href provided ([#2207](https://github.com/telekom/scale/issues/2207)) ([63c8657](https://github.com/telekom/scale/commit/63c8657348f99a2494c68d95e36b0fc087ebcc86))
+* modal tooltip placement ([07061ef](https://github.com/telekom/scale/commit/07061ef596f1f3e821af3db8ee6ef2c2c9b13353))
+* remove language from app-footer logo ([#2183](https://github.com/telekom/scale/issues/2183)) ([f8200de](https://github.com/telekom/scale/commit/f8200def12e576c343d71cab9d4f4fe3cc302714))
+* revert unwanted changes on main ([78f3009](https://github.com/telekom/scale/commit/78f30093182ee2d4c64f65d8e01a34815e2b23c7))
+* tooltip within modal ([#2206](https://github.com/telekom/scale/issues/2206)) ([ed10e49](https://github.com/telekom/scale/commit/ed10e49e109748d439d98ae81f7cb33246906e22))
+* use spans inside labels for correct html ([#2217](https://github.com/telekom/scale/issues/2217)) ([6d1d3f7](https://github.com/telekom/scale/commit/6d1d3f795dcd7e37c431bdf830f2a3867b7ebd3a))
+
+
+### Features
+
+* **dropdown-select:** add disabled state for individual options ([#2174](https://github.com/telekom/scale/issues/2174)) ([b53b711](https://github.com/telekom/scale/commit/b53b7113ddf73725ae30cb28f39868caf2d05683))
+* update ghost button color ([#2181](https://github.com/telekom/scale/issues/2181)) ([60d33c4](https://github.com/telekom/scale/commit/60d33c4fb15c5f79b43b386d077c11ea7e0c9dde))
+
+
+
+
+
# [3.0.0-beta.143](https://github.com/telekom/scale/compare/v3.0.0-beta.142...v3.0.0-beta.143) (2023-11-03)
diff --git a/examples/vite-react/.eslintrc.cjs b/examples/vite-react/.eslintrc.cjs
new file mode 100644
index 0000000000..d6c9537953
--- /dev/null
+++ b/examples/vite-react/.eslintrc.cjs
@@ -0,0 +1,18 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parser: '@typescript-eslint/parser',
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+}
diff --git a/examples/vite-react/.gitignore b/examples/vite-react/.gitignore
new file mode 100644
index 0000000000..a547bf36d8
--- /dev/null
+++ b/examples/vite-react/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/vite-react/README.md b/examples/vite-react/README.md
new file mode 100644
index 0000000000..1ebe379f5f
--- /dev/null
+++ b/examples/vite-react/README.md
@@ -0,0 +1,27 @@
+# React + TypeScript + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
+
+- Configure the top-level `parserOptions` property like this:
+
+```js
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ project: ['./tsconfig.json', './tsconfig.node.json'],
+ tsconfigRootDir: __dirname,
+ },
+```
+
+- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
+- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
+- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
diff --git a/examples/vite-react/index.html b/examples/vite-react/index.html
new file mode 100644
index 0000000000..e4b78eae12
--- /dev/null
+++ b/examples/vite-react/index.html
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/packages/components/src/components/checkbox/checkbox.tsx b/packages/components/src/components/checkbox/checkbox.tsx
index 7b5abf0a2e..65b9a44936 100644
--- a/packages/components/src/components/checkbox/checkbox.tsx
+++ b/packages/components/src/components/checkbox/checkbox.tsx
@@ -195,9 +195,9 @@ export class Checkbox {
onChange={this.handleChange}
/>
- {this.renderIcon()}
+ {this.renderIcon()}
{/* TODO: discuss deprecation of the slot (move closer so W3C spec) */}
- {this.label || }
+ {this.label || }
{this.renderHelperText(helperText)}
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 810b21f98f..59ed61527c 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
@@ -16,7 +16,7 @@ export interface Cell {
mobileTitle?: boolean;
resizable?: boolean;
sortable?: boolean;
- sortBy?: 'number' | 'text';
+ sortBy?: 'number' | 'text' | 'date';
stretchWeight?: number;
textAlign?: 'left' | 'center' | 'right';
visible?: boolean;
diff --git a/packages/components/src/components/data-grid/cell-handlers/date-cell.tsx b/packages/components/src/components/data-grid/cell-handlers/date-cell.tsx
index a39ae76dab..7d0a27d812 100644
--- a/packages/components/src/components/data-grid/cell-handlers/date-cell.tsx
+++ b/packages/components/src/components/data-grid/cell-handlers/date-cell.tsx
@@ -21,7 +21,7 @@ import { Cell } from './cell-interface';
export const DateCell: Cell = {
defaults: {
- sortBy: 'text',
+ sortBy: 'date',
},
render: ({ content, isAutoWidthCheck }) => {
let value = content;
diff --git a/packages/components/src/components/data-grid/data-grid.tsx b/packages/components/src/components/data-grid/data-grid.tsx
index cc639079a2..dfb7e0f3c5 100644
--- a/packages/components/src/components/data-grid/data-grid.tsx
+++ b/packages/components/src/components/data-grid/data-grid.tsx
@@ -28,6 +28,8 @@ import {
import classNames from 'classnames';
import { emitEvent } from '../../utils/utils';
+import { parse } from 'date-fns';
+
// [ ] add options to show nested content without the html column
// [ ] add options to pre-expand all html content
// [ ] Uber cell type where all options are available for user
@@ -413,10 +415,25 @@ export class DataGrid {
}
sortTable(sortDirection, type, columnIndex) {
+ const format = this.fields[columnIndex].format;
if (sortDirection === 'none') {
this.rows.sort((a, b) => {
return a.initialIndex - b.initialIndex;
});
+ } else if (type === 'date' && format) {
+ this.rows.sort((a, b) => {
+ const getDateObject = (dateString) => {
+ const parsed = parse(dateString, format, new Date());
+ return parsed;
+ };
+
+ const dateObjectA = getDateObject(a[columnIndex]);
+ const dateObjectB = getDateObject(b[columnIndex]);
+ // valueOf here for typescript to not complain about dateObjectA and dateObjectB not being numbers
+ return sortDirection === 'ascending'
+ ? dateObjectA.valueOf() - dateObjectB.valueOf()
+ : dateObjectB.valueOf() - dateObjectA.valueOf();
+ });
} else {
switch (
(CELL_TYPES[type] &&
@@ -425,6 +442,7 @@ export class DataGrid {
CELL_DEFAULTS.sortBy
) {
case 'text':
+ case 'date':
if (sortDirection === 'ascending') {
this.rows.sort((a, b) => {
const textA = a[columnIndex].toLowerCase();
diff --git a/packages/components/src/components/dropdown-select-item/dropdown-select-item.tsx b/packages/components/src/components/dropdown-select-item/dropdown-select-item.tsx
index 8b6a8b3ef0..0904e2468e 100644
--- a/packages/components/src/components/dropdown-select-item/dropdown-select-item.tsx
+++ b/packages/components/src/components/dropdown-select-item/dropdown-select-item.tsx
@@ -10,6 +10,7 @@ export class DropdownSelectItem {
@Prop() selected?: boolean;
@Prop() focused?: boolean;
@Prop({ reflect: true }) value?: any;
+ @Prop({ reflect: true }) disabled?: boolean;
render() {
return (
diff --git a/packages/components/src/components/dropdown-select-item/readme.md b/packages/components/src/components/dropdown-select-item/readme.md
index c67a191923..ae5b8847ff 100644
--- a/packages/components/src/components/dropdown-select-item/readme.md
+++ b/packages/components/src/components/dropdown-select-item/readme.md
@@ -9,6 +9,7 @@
| Property | Attribute | Description | Type | Default |
| ---------- | ---------- | ----------- | --------- | ----------- |
+| `disabled` | `disabled` | | `boolean` | `undefined` |
| `focused` | `focused` | | `boolean` | `undefined` |
| `selected` | `selected` | | `boolean` | `undefined` |
| `value` | `value` | | `any` | `undefined` |
diff --git a/packages/components/src/components/dropdown-select/dropdown-select.css b/packages/components/src/components/dropdown-select/dropdown-select.css
index 9c3f1bcbdd..e289e61e43 100644
--- a/packages/components/src/components/dropdown-select/dropdown-select.css
+++ b/packages/components/src/components/dropdown-select/dropdown-select.css
@@ -257,7 +257,12 @@
color: var(--color);
}
-[part~='option']:hover {
+[part~='option'][part~='disabled'] {
+ color: var(--color-disabled);
+ cursor: not-allowed;
+}
+
+[part~='option']:not([part~='disabled']):hover {
background-color: var(--background-hover);
}
diff --git a/packages/components/src/components/dropdown-select/dropdown-select.e2e.ts b/packages/components/src/components/dropdown-select/dropdown-select.e2e.ts
index bcddce9f16..c9df9594d8 100644
--- a/packages/components/src/components/dropdown-select/dropdown-select.e2e.ts
+++ b/packages/components/src/components/dropdown-select/dropdown-select.e2e.ts
@@ -1,4 +1,4 @@
-import { newE2EPage } from '@stencil/core/testing';
+import { E2EElement, E2EPage, newE2EPage } from '@stencil/core/testing';
import { DropdownSelect } from './dropdown-select';
describe('DropdownSelect', function () {
@@ -59,4 +59,112 @@ describe('DropdownSelect', function () {
expect(comboboxEl).toEqualText('Cedric');
expect(selectEl).toEqualAttribute('value', 'cedric');
});
+
+ describe('when contains some disabled options', () => {
+ let page: E2EPage;
+ let selectEl: E2EElement;
+ let comboboxEl: E2EElement;
+
+ beforeEach(async () => {
+ page = await newE2EPage({
+ components: [DropdownSelect],
+ html: `
+
+ Adam
+ Cedrik
+ Cedric
+ Cem
+ Chris
+ Christian
+ Christiano
+ `,
+ });
+
+ selectEl = await page.find('scale-dropdown-select');
+ comboboxEl = await page.find(
+ 'scale-dropdown-select >>> [part="combobox"]'
+ );
+ });
+
+ it('should skip disabled options when navigating with keyboard', async () => {
+ await page.keyboard.down('Tab');
+ await page.keyboard.down('Enter');
+ await page.keyboard.down('ArrowDown');
+ await page.keyboard.down('ArrowDown');
+ await page.keyboard.down('Enter');
+ await page.waitForChanges();
+
+ // should skip Cedrik and Cedric
+ expect(comboboxEl).toEqualText('Cem');
+ expect(selectEl).toEqualAttribute('value', 'cem');
+ });
+
+ it('should skip disabled options when typing', async () => {
+ await page.keyboard.down('Tab');
+ await page.keyboard.down('Enter');
+ await page.keyboard.down('c');
+ await page.keyboard.down('e');
+ await page.keyboard.down('Enter');
+ await page.waitForChanges();
+
+ expect(comboboxEl).toEqualText('Cem');
+ expect(selectEl).toEqualAttribute('value', 'cem');
+ });
+ });
+
+ describe('when ALL options are disabled', () => {
+ let page: E2EPage;
+ let selectEl: E2EElement;
+ let comboboxEl: E2EElement;
+
+ beforeEach(async () => {
+ page = await newE2EPage({
+ components: [DropdownSelect],
+ html: `
+
+ Adam
+ Cedrik
+ Cedric
+ Cem
+ Chris
+ Christian
+ Christiano
+ `,
+ });
+
+ selectEl = await page.find('scale-dropdown-select');
+ comboboxEl = await page.find(
+ 'scale-dropdown-select >>> [part="combobox"]'
+ );
+ });
+
+ it('should not be able to select any option', async () => {
+ await page.keyboard.down('Tab');
+ await page.keyboard.down('Enter');
+ await page.keyboard.down('ArrowDown');
+ await page.keyboard.down('ArrowDown');
+ await page.keyboard.down('ArrowDown');
+ await page.keyboard.down('ArrowUp');
+ await page.keyboard.down('ArrowUp');
+ await page.keyboard.down('ArrowDown');
+ await page.keyboard.down('Enter');
+ await page.waitForChanges();
+
+ expect(comboboxEl).toEqualText('');
+ expect(selectEl).toEqualAttribute('value', 'default');
+ });
+
+ it('should not be able to select any option by typing', async () => {
+ await page.keyboard.down('Tab');
+ await page.keyboard.down('Enter');
+ await page.keyboard.down('c');
+ await page.keyboard.down('e');
+ await page.keyboard.down('d');
+ await page.keyboard.down('Enter');
+ await page.waitForChanges();
+
+ expect(comboboxEl).toEqualText('');
+ expect(selectEl).toEqualAttribute('value', 'default');
+ });
+ });
});
diff --git a/packages/components/src/components/dropdown-select/dropdown-select.spec.ts b/packages/components/src/components/dropdown-select/dropdown-select.spec.ts
index 3224b4b0c5..f6b25d283d 100644
--- a/packages/components/src/components/dropdown-select/dropdown-select.spec.ts
+++ b/packages/components/src/components/dropdown-select/dropdown-select.spec.ts
@@ -82,4 +82,41 @@ describe('DropdownSelect', function () {
})
);
});
+
+ describe('when clicking on disabled option', () => {
+ it('should neither change it`s value, nor emit an event', async () => {
+ const page = await newSpecPage({
+ components: [DropdownSelect],
+ html: `
+
+ Caspar
+ Cedric
+ Cem
+ `,
+ });
+
+ const clickSpy = jest.fn();
+ const changeSpy = jest.fn();
+
+ const selectEl = page.doc.querySelector('scale-dropdown-select');
+ selectEl.addEventListener('scale-change', changeSpy);
+ const comboboxEl: HTMLElement =
+ selectEl.shadowRoot.querySelector('[part="combobox"]');
+ comboboxEl.scrollIntoView = function () {};
+ comboboxEl.focus = function () {};
+ const optionsEls: NodeListOf
=
+ selectEl.shadowRoot.querySelectorAll('[role="option"]');
+ optionsEls[1].addEventListener('click', clickSpy);
+
+ comboboxEl.click();
+ optionsEls[1].click();
+
+ await page.waitForChanges();
+
+ expect(comboboxEl.textContent).not.toBe('Cem');
+ expect(selectEl.value).not.toBe('cem');
+ expect(clickSpy).toBeCalledTimes(1);
+ expect(changeSpy).not.toBeCalled();
+ });
+ });
});
diff --git a/packages/components/src/components/dropdown-select/dropdown-select.tsx b/packages/components/src/components/dropdown-select/dropdown-select.tsx
index c16579c5e8..c13886e3db 100644
--- a/packages/components/src/components/dropdown-select/dropdown-select.tsx
+++ b/packages/components/src/components/dropdown-select/dropdown-select.tsx
@@ -31,17 +31,38 @@ enum Actions {
const DEFAULT_ICON_SIZE = 20;
+interface SelectOption {
+ label: string;
+ value: any;
+ disabled: boolean;
+ ItemElement: VNode;
+}
+
const isElementValue = (x: unknown): x is Element & { value: string } =>
typeof (x as { value: unknown }).value === 'string';
const readValue = (element: Element) =>
isElementValue(element) ? element.value : null;
-const readOptions = (
- hostElement: HTMLElement
-): Array<{ label: string; value: any; ItemElement: VNode }> => {
- return Array.from(hostElement.children).map((x) => ({
+const isElementDisabled = (x: unknown): x is Element & { disable: boolean } => {
+ return typeof (x as { disable: unknown }).disable === 'boolean';
+};
+const readDisabled = (element: Element) => {
+ const attr = element.getAttribute('disabled');
+ return (
+ (attr !== null && `${attr}` !== 'false') ||
+ (isElementDisabled(element) ? element.disable : false)
+ );
+};
+
+const readOptions = (hostElement: HTMLElement): SelectOption[] => {
+ const children = Array.from(hostElement.children);
+ const options = children.filter(
+ (x: HTMLElement) => x.tagName !== 'INPUT' && x.hidden === false
+ );
+ return options.map((x) => ({
label: x.textContent.trim(),
value: x.getAttribute('value') ?? readValue(x),
+ disabled: readDisabled(x),
ItemElement: ,
}));
};
@@ -95,39 +116,65 @@ function getActionFromKey(event: KeyboardEvent, open: boolean) {
}
}
-function jumpToIndex(currentIndex: number, maxIndex: number, action: Actions) {
+function jumpToIndex(from: number, action: Actions, options: SelectOption[]) {
const JUMP_SIZE = 10;
+ const findNearestEnabled = (current: number, step: number) => {
+ let nextIndex: number = current;
+ let nextOption: SelectOption;
+
+ do {
+ nextIndex += step;
+ nextOption = options[nextIndex];
+ if (nextOption === undefined) {
+ break;
+ }
+ } while (nextOption?.disabled);
+
+ return nextOption ? nextIndex : current;
+ };
+ let nearest: number;
switch (action) {
case Actions['First']:
- return 0;
+ return options[0]?.disabled ? findNearestEnabled(-1, 1) : 0;
case Actions['Last']:
- return maxIndex;
+ nearest = findNearestEnabled(options.length, -1);
+ return nearest === options.length ? -1 : nearest; // rare case when all options are disabled
case Actions['Previous']:
- return Math.max(0, currentIndex - 1);
+ nearest = findNearestEnabled(from, from === -1 ? 1 : -1);
+ return nearest === options.length ? -1 : nearest; // rare case when all options are disabled
case Actions['Next']:
- return Math.min(maxIndex, currentIndex + 1);
+ return findNearestEnabled(from, 1);
case Actions['PageUp']:
- return Math.max(0, currentIndex - JUMP_SIZE);
+ const lowerBound = Math.max(from - JUMP_SIZE, -1);
+ return findNearestEnabled(lowerBound, 1);
case Actions['PageDown']:
- return Math.min(maxIndex, currentIndex + JUMP_SIZE);
+ const upperBound = Math.min(from + JUMP_SIZE, options.length);
+ nearest = findNearestEnabled(upperBound, -1);
+ return nearest === options.length ? -1 : nearest; // rare case when all options are disabled
default:
- return currentIndex;
+ return from;
}
}
-function matchOptions(options: string[] = [], filter: string) {
+function matchEnabledOptions(options: SelectOption[] = [], filter: string) {
return options.filter(
- (option) => option.toLowerCase().indexOf(filter.toLowerCase()) === 0
+ (option) =>
+ !option.disabled &&
+ option.label.toLowerCase().indexOf(filter.toLowerCase()) === 0
);
}
-function getIndexByChar(values: string[], filter: string, startIndex = 0) {
- const sortedValues = [
+function getIndexByChar(
+ values: SelectOption[],
+ filter: string,
+ startIndex = 0
+) {
+ const sortedOptions = [
...values.slice(startIndex),
...values.slice(0, startIndex),
];
- const firstHit = matchOptions(sortedValues, filter)[0];
+ const firstHit = matchEnabledOptions(sortedOptions, filter)[0];
const allMatchingChars = (array) => array.every((char) => char === array[0]);
if (firstHit) {
@@ -135,7 +182,7 @@ function getIndexByChar(values: string[], filter: string, startIndex = 0) {
}
if (allMatchingChars(filter.split(''))) {
- const hits = matchOptions(sortedValues, filter[0]);
+ const hits = matchEnabledOptions(sortedOptions, filter[0]);
return values.indexOf(hits[0]);
}
@@ -229,6 +276,7 @@ export class DropdownSelect {
this.currentIndex = readOptions(this.hostElement).findIndex(
({ value }) => value === newValue
);
+ this.updateInputHidden(newValue);
}
connectedCallback() {
@@ -259,6 +307,27 @@ export class DropdownSelect {
});
}
+ // this workaround is needed to make the component work with form
+ // https://github.com/ionic-team/stencil/issues/2284
+ componentDidLoad() {
+ this.appendInputHidden();
+ }
+
+ appendInputHidden(): void {
+ const input = document.createElement('input');
+ input.name = this.name;
+ input.id = this.name;
+ input.value = this.value;
+ input.type = 'hidden';
+ this.hostElement.appendChild(input);
+ }
+
+ updateInputHidden(value: string = this.value): void {
+ this.hostElement.querySelector(
+ `input[name=${this.name}]`
+ ).value = value;
+ }
+
selectOption = (index) => {
this.currentIndex = index;
this.value = readOptions(this.hostElement)[index].value;
@@ -267,7 +336,10 @@ export class DropdownSelect {
handleOptionChange(index) {
this.currentIndex = index;
- this.bringIntoView(index);
+
+ if (index > -1) {
+ this.bringIntoView(index);
+ }
}
bringIntoView(index) {
@@ -302,6 +374,10 @@ export class DropdownSelect {
handleOptionClick(event, index) {
event.stopPropagation();
+ if (readOptions(this.hostElement)[index].disabled) {
+ return;
+ }
+
this.handleOptionChange(index);
this.selectOption(index);
this.setOpen(false);
@@ -325,7 +401,7 @@ export class DropdownSelect {
const queryString = this.getSearchString(char);
const queryIndex = getIndexByChar(
- readOptions(this.hostElement).map(({ label }) => label),
+ readOptions(this.hostElement),
queryString,
this.currentIndex + 1
);
@@ -340,7 +416,7 @@ export class DropdownSelect {
handleKeyDown = (event) => {
const { key } = event;
- const max = readOptions(this.hostElement).length - 1;
+ const options = readOptions(this.hostElement);
const action = getActionFromKey(event, this.open);
emitEvent(this, 'scaleKeydown', event);
@@ -354,11 +430,16 @@ export class DropdownSelect {
case Actions['PageDown']:
event.preventDefault();
return this.handleOptionChange(
- jumpToIndex(this.currentIndex, max, action)
+ jumpToIndex(this.currentIndex, action, options)
);
case Actions['CloseSelect']:
event.preventDefault();
- this.selectOption(this.currentIndex);
+ if (options[this.currentIndex]?.disabled) {
+ return;
+ }
+ if (this.currentIndex !== -1) {
+ this.selectOption(this.currentIndex);
+ }
case Actions['Close']:
event.preventDefault();
return this.setOpen(false);
@@ -381,11 +462,9 @@ export class DropdownSelect {
handleClick = () => {
this.setOpen(!this.open);
-
const indexOfValue = readOptions(this.hostElement).findIndex(
({ value }) => value === this.value
);
-
if (indexOfValue > -1) {
setTimeout(() => {
this.bringIntoView(indexOfValue);
@@ -394,18 +473,12 @@ export class DropdownSelect {
};
render() {
- const ValueElement = (
- readOptions(this.hostElement).find(({ value }) => value === this.value) ||
- ({} as any)
- ).ItemElement;
- const hasEmptyValueElement =
- (
- readOptions(this.hostElement).find(
- ({ value }) => value === this.value
- ) || ({} as any)
- ).value === ''
- ? true
- : false;
+ const element =
+ readOptions(this.hostElement).find(({ value }) => value === this.value) ??
+ ({} as any);
+
+ const ValueElement = element.ItemElement;
+ const hasEmptyValueElement = element.value === '';
const helperTextId = `helper-message-${generateUniqueId()}`;
const ariaDescribedByAttr = { 'aria-describedBy': helperTextId };
@@ -461,12 +534,10 @@ export class DropdownSelect {
tabindex="-1"
>
{readOptions(this.hostElement).map(
- ({ value, ItemElement }, index) => (
+ ({ value, disabled, ItemElement }, index) => (
{
this.handleOptionClick(event, index);
@@ -474,6 +545,7 @@ export class DropdownSelect {
{...(value === this.value
? { 'aria-selected': 'true' }
: {})}
+ {...(disabled ? { 'aria-disabled': 'true' } : {})}
>
{ItemElement}
{value === this.value ? (
@@ -541,4 +613,12 @@ export class DropdownSelect {
this.hideLabelVisually && 'hide-label'
);
}
+
+ getOptionPartMap(index: number, disabled: boolean) {
+ return classNames(
+ 'option',
+ index === this.currentIndex && `current`,
+ disabled && `disabled`
+ );
+ }
}
diff --git a/packages/components/src/components/notification/notification.css b/packages/components/src/components/notification/notification.css
index 3dd3eba13c..3a33e2e36f 100644
--- a/packages/components/src/components/notification/notification.css
+++ b/packages/components/src/components/notification/notification.css
@@ -127,9 +127,11 @@
padding-left: var(--spacing-y);
}
-[part='heading'] {
+[part='heading'],
+[part='heading'] ::slotted(*) {
font: var(--telekom-text-style-heading-6);
line-height: var(--telekom-typography-line-spacing-tight);
+ margin: 0;
}
[part='text'] {
diff --git a/packages/components/src/components/notification/notification.tsx b/packages/components/src/components/notification/notification.tsx
index 15ed7af6b4..3cc19abe30 100644
--- a/packages/components/src/components/notification/notification.tsx
+++ b/packages/components/src/components/notification/notification.tsx
@@ -59,8 +59,10 @@ export class Notification {
@Prop() dismissible?: boolean = false;
/** (optional) Time in milliseconds until it closes by itself */
@Prop() delay?: number;
- /** (optional) `aria-live` of element */
+ /** @deprecated - ariaRole should replace innerAriaLive */
@Prop() innerAriaLive?: string = 'assertive';
+ /** (optional) string prepended to the heading */
+ @Prop() innerRole?: 'alert' | 'status' = 'alert';
/** (optional) Label for close button */
@Prop() closeButtonLabel?: string = 'Close';
/** (optional) `title` for close button */
@@ -69,13 +71,13 @@ export class Notification {
@Prop() headingLevel: number = 2;
/** (optional) string prepended to the heading */
@Prop() ariaHeading?: string = 'Information';
+
/** (optional) Injected styles */
@Prop() styles?: string;
/** What actually triggers opening/closing the notification */
@State() isOpen: boolean = this.opened || false;
@State() animationState: 'in' | 'out' | undefined;
- @State() role: string = 'alert';
@State() hasTextSlot: boolean = false;
// @State() hasActionSlot: boolean = false; // unused for now
@@ -91,8 +93,9 @@ export class Notification {
connectedCallback() {
if (this.hostElement.hasAttribute('opened')) {
- // Do not use `role="alert"` if opened/visible on page load
- this.role = undefined;
+ if (this.innerAriaLive === 'polite' || this.innerRole === 'status') {
+ this.innerRole = 'status';
+ }
this.isOpen = true;
}
if (this.delay !== undefined) {
@@ -115,7 +118,6 @@ export class Notification {
open = () => {
this.isOpen = true;
- this.role = 'alert';
this.animationState = 'in';
requestAnimationFrame(async () => {
await animationsFinished(this.hostElement.shadowRoot);
@@ -164,24 +166,22 @@ export class Notification {
`variant-${this.variant}`,
this.isOpen && 'open'
)}
- role={this.role}
+ role={this.innerRole}
>
-
+
- {this.heading}
+ {this.heading ? {this.heading} : null}
+
{this.hasTextSlot && (
diff --git a/packages/components/src/components/notification/readme.md b/packages/components/src/components/notification/readme.md
index c887f7a336..c3fe2f6412 100644
--- a/packages/components/src/components/notification/readme.md
+++ b/packages/components/src/components/notification/readme.md
@@ -7,20 +7,21 @@
## Properties
-| Property | Attribute | Description | Type | Default |
-| ------------------ | -------------------- | --------------------------------------------------------- | ------------------------------------------------------- | ----------------- |
-| `ariaHeading` | `aria-heading` | (optional) string prepended to the heading | `string` | `'Information'` |
-| `closeButtonLabel` | `close-button-label` | (optional) Label for close button | `string` | `'Close'` |
-| `closeButtonTitle` | `close-button-title` | (optional) `title` for close button | `string` | `'Close'` |
-| `delay` | `delay` | (optional) Time in milliseconds until it closes by itself | `number` | `undefined` |
-| `dismissible` | `dismissible` | (optional) Show the close button | `boolean` | `false` |
-| `heading` | `heading` | Heading | `string` | `undefined` |
-| `headingLevel` | `heading-level` | Default aria-level for heading | `number` | `2` |
-| `innerAriaLive` | `inner-aria-live` | (optional) `aria-live` of element | `string` | `'assertive'` |
-| `opened` | `opened` | (optional) Visible | `boolean` | `undefined` |
-| `styles` | `styles` | (optional) Injected styles | `string` | `undefined` |
-| `type` | `type` | (optional) Type | `"banner" \| "inline" \| "toast"` | `'inline'` |
-| `variant` | `variant` | (optional) Variant | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` |
+| Property | Attribute | Description | Type | Default |
+| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------- |
+| `ariaHeading` | `aria-heading` | (optional) string prepended to the heading | `string` | `'Information'` |
+| `closeButtonLabel` | `close-button-label` | (optional) Label for close button | `string` | `'Close'` |
+| `closeButtonTitle` | `close-button-title` | (optional) `title` for close button | `string` | `'Close'` |
+| `delay` | `delay` | (optional) Time in milliseconds until it closes by itself | `number` | `undefined` |
+| `dismissible` | `dismissible` | (optional) Show the close button | `boolean` | `false` |
+| `heading` | `heading` | Heading | `string` | `undefined` |
+| `headingLevel` | `heading-level` | Default aria-level for heading | `number` | `2` |
+| `innerAriaLive` | `inner-aria-live` |
**[DEPRECATED]** - ariaRole should replace innerAriaLive
| `string` | `'assertive'` |
+| `innerRole` | `inner-role` | (optional) string prepended to the heading | `"alert" \| "status"` | `'alert'` |
+| `opened` | `opened` | (optional) Visible | `boolean` | `undefined` |
+| `styles` | `styles` | (optional) Injected styles | `string` | `undefined` |
+| `type` | `type` | (optional) Type | `"banner" \| "inline" \| "toast"` | `'inline'` |
+| `variant` | `variant` | (optional) Variant | `"danger" \| "informational" \| "success" \| "warning"` | `'informational'` |
## Events
diff --git a/packages/components/src/components/switch/__snapshots__/switch.spec.ts.snap b/packages/components/src/components/switch/__snapshots__/switch.spec.ts.snap
index 7d76add8c1..9a0d30db16 100644
--- a/packages/components/src/components/switch/__snapshots__/switch.spec.ts.snap
+++ b/packages/components/src/components/switch/__snapshots__/switch.spec.ts.snap
@@ -5,17 +5,17 @@ exports[`Switch should match snapshot 1`] = `
diff --git a/packages/components/src/components/switch/switch.css b/packages/components/src/components/switch/switch.css
index 98b59981b5..ba3562eae8 100644
--- a/packages/components/src/components/switch/switch.css
+++ b/packages/components/src/components/switch/switch.css
@@ -202,6 +202,7 @@ scale-switch {
transition-timing-function: var(--transition-easing);
color: transparent;
border: 1px solid rgba(0, 0, 0, 0.04);
+ display: inline-block;
}
.switch--checked .switch__thumb {
diff --git a/packages/components/src/components/switch/switch.tsx b/packages/components/src/components/switch/switch.tsx
index 78fa077679..fbd6dd7968 100644
--- a/packages/components/src/components/switch/switch.tsx
+++ b/packages/components/src/components/switch/switch.tsx
@@ -70,15 +70,15 @@ export class Switch {
emitEvent(this, 'scaleChange', { value: this.checked });
}}
/>
-
-
+
+
-
-
+
+
{this.checked ? 'I' : '0'}
-
-
-
+
+
+
{this.label &&
{this.label} }
diff --git a/packages/components/src/components/tab-panel/readme.md b/packages/components/src/components/tab-panel/readme.md
index 385cbb2449..7d79819260 100644
--- a/packages/components/src/components/tab-panel/readme.md
+++ b/packages/components/src/components/tab-panel/readme.md
@@ -7,11 +7,12 @@
## Properties
-| Property | Attribute | Description | Type | Default |
-| -------- | --------- | ----------------------------------------------------------------------------------- | -------------------- | ----------- |
-| `size` | `size` |
**[DEPRECATED]** - no more size difference
| `"large" \| "small"` | `'small'` |
-| `small` | `small` |
**[DEPRECATED]** - no more size difference
| `boolean` | `false` |
-| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` |
+| Property | Attribute | Description | Type | Default |
+| --------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ----------- |
+| `size` | `size` |
**[DEPRECATED]** - no more size difference
| `"large" \| "small"` | `'small'` |
+| `small` | `small` |
**[DEPRECATED]** - no more size difference
| `boolean` | `false` |
+| `styles` | `styles` | (optional) Injected CSS styles | `string` | `undefined` |
+| `tabbablePanel` | `tabbable-panel` | (optional) adds tab-index="0" to the panel, set to false to exclude the tab-panel from the tab sequence, e.g. if the first element in the panel is a focusable button | `boolean` | `true` |
## Shadow Parts
diff --git a/packages/components/src/components/tab-panel/tab-panel.tsx b/packages/components/src/components/tab-panel/tab-panel.tsx
index 6341b5a3b5..64386ad1bb 100644
--- a/packages/components/src/components/tab-panel/tab-panel.tsx
+++ b/packages/components/src/components/tab-panel/tab-panel.tsx
@@ -29,6 +29,8 @@ export class TabPanel {
/** (optional) size */
/** @deprecated - no more size difference */
@Prop() size: 'small' | 'large' = 'small';
+ /** (optional) adds tab-index="0" to the panel, set to false to exclude the tab-panel from the tab sequence, e.g. if the first element in the panel is a focusable button */
+ @Prop() tabbablePanel?: boolean = true;
/** (optional) Injected CSS styles */
@Prop() styles?: string;
@@ -43,12 +45,18 @@ export class TabPanel {
}
}
+ setTabIndex() {
+ if (this.tabbablePanel === true) {
+ return { tabindex: '0' };
+ }
+ }
+
render() {
return (
{this.styles && }
diff --git a/packages/components/src/components/telekom/app-footer/app-footer.tsx b/packages/components/src/components/telekom/app-footer/app-footer.tsx
index 641808bb49..763528319c 100644
--- a/packages/components/src/components/telekom/app-footer/app-footer.tsx
+++ b/packages/components/src/components/telekom/app-footer/app-footer.tsx
@@ -38,7 +38,6 @@ export class AppFooter {
@Prop() logoTitle?: string;
@Prop() logoClick?: any;
@Prop() logoAriaDescribedBy?: string;
- @Prop() claimLang: string;
/** (optional) Injected CSS styles */
@Prop() styles?: string;
hasSlotLogo: boolean;
@@ -67,7 +66,6 @@ export class AppFooter {
{
if (this.scrollIntoViewOnFocus === true) {
window.scrollTo({ top: 0 });
@@ -96,7 +96,6 @@ export class Logo {
title={this.logoHideTitle ? undefined : this.logoTitle}
aria-describedby={this.logoAriaDescribedBy}
aria-hidden={this.logoAriaHidden}
- tabindex={this.logoAriaHidden ? -1 : 0}
>
diff --git a/packages/components/src/components/telekom/telekom-header/telekom-header.tsx b/packages/components/src/components/telekom/telekom-header/telekom-header.tsx
index f1f6661a87..3d8b192028 100644
--- a/packages/components/src/components/telekom/telekom-header/telekom-header.tsx
+++ b/packages/components/src/components/telekom/telekom-header/telekom-header.tsx
@@ -76,6 +76,7 @@ export class TelekomHeader {
href={this.logoHref}
logoTitle={this.logoTitle}
logoHideTitle={this.logoHideTitle}
+ focusable={this.logoHref ? true : false}
>
diff --git a/packages/components/src/components/tooltip/tooltip.css b/packages/components/src/components/tooltip/tooltip.css
index 5dfbc0b689..d20175277b 100644
--- a/packages/components/src/components/tooltip/tooltip.css
+++ b/packages/components/src/components/tooltip/tooltip.css
@@ -19,6 +19,7 @@
--line-height: var(--telekom-typography-line-spacing-standard);
--spacing: var(--telekom-spacing-composition-space-02)
var(--telekom-spacing-composition-space-04);
+ --width: auto;
/* arrow */
--arrow-size: 12px;
@@ -34,12 +35,12 @@
--z-index: var(--scl-z-index-70);
display: contents;
- position: relative;
box-sizing: border-box;
}
[part='tooltip'] {
position: absolute;
+ width: var(--width);
z-index: var(--z-index);
top: 0;
left: 0;
diff --git a/packages/components/src/components/tooltip/tooltip.tsx b/packages/components/src/components/tooltip/tooltip.tsx
index c4e5491899..b10f0cf310 100644
--- a/packages/components/src/components/tooltip/tooltip.tsx
+++ b/packages/components/src/components/tooltip/tooltip.tsx
@@ -22,7 +22,15 @@ import {
State,
Listen,
} from '@stencil/core';
-import { computePosition, offset, flip, shift, arrow } from '@floating-ui/dom';
+import {
+ computePosition,
+ offset,
+ flip,
+ shift,
+ arrow,
+ platform,
+} from '@floating-ui/dom';
+import { offsetParent } from 'composed-offset-position';
import { isClickOutside } from '../../utils/utils';
import statusNote from '../../utils/status-note';
@@ -161,6 +169,11 @@ export class Tooltip {
arrow({ element: this.arrowEl, padding: this.arrowPadding }),
shift({ crossAxis: true }),
],
+ platform: {
+ ...platform,
+ getOffsetParent: (element) =>
+ platform.getOffsetParent(element, offsetParent),
+ },
}
);
Object.assign(this.tooltipEl.style, {
diff --git a/packages/components/src/html/dropdown-select.html b/packages/components/src/html/dropdown-select.html
index 7ca957dcfc..bbb0ebf20b 100644
--- a/packages/components/src/html/dropdown-select.html
+++ b/packages/components/src/html/dropdown-select.html
@@ -37,10 +37,10 @@
Caspar
-
+
Cedric
- Cedrik
Cem
diff --git a/packages/design-tokens/CHANGELOG.md b/packages/design-tokens/CHANGELOG.md
index 1c6e991736..3b1b221a39 100644
--- a/packages/design-tokens/CHANGELOG.md
+++ b/packages/design-tokens/CHANGELOG.md
@@ -3,6 +3,14 @@
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.144](https://github.com/telekom/scale/compare/v3.0.0-beta.143...v3.0.0-beta.144) (2023-11-30)
+
+**Note:** Version bump only for package @telekom/scale-design-tokens
+
+
+
+
+
# [3.0.0-beta.143](https://github.com/telekom/scale/compare/v3.0.0-beta.142...v3.0.0-beta.143) (2023-11-03)
**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 0c4063c63c..876f33ee21 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.143",
+ "version": "3.0.0-beta.144",
"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 0daa77fba6..4f793b4b8c 100644
--- a/packages/storybook-vue/CHANGELOG.md
+++ b/packages/storybook-vue/CHANGELOG.md
@@ -3,6 +3,27 @@
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.144](https://github.com/telekom/scale/compare/v3.0.0-beta.143...v3.0.0-beta.144) (2023-11-30)
+
+
+### Bug Fixes
+
+* add prop for removing tabindex ([#2215](https://github.com/telekom/scale/issues/2215)) ([3fdafab](https://github.com/telekom/scale/commit/3fdafab34f567056044918228b84fcb6c30869d1))
+* allow sorting by german date format ([#2159](https://github.com/telekom/scale/issues/2159)) ([4229de7](https://github.com/telekom/scale/commit/4229de7588dbaacf6b6be07d7694c2b88b14bd3a))
+* aria role behavior ([#2171](https://github.com/telekom/scale/issues/2171)) ([59c57bc](https://github.com/telekom/scale/commit/59c57bc08d98957675bd210927cf028ceb275f89))
+* logo only focusable if href provided ([#2207](https://github.com/telekom/scale/issues/2207)) ([63c8657](https://github.com/telekom/scale/commit/63c8657348f99a2494c68d95e36b0fc087ebcc86))
+* tooltip within modal ([#2206](https://github.com/telekom/scale/issues/2206)) ([ed10e49](https://github.com/telekom/scale/commit/ed10e49e109748d439d98ae81f7cb33246906e22))
+
+
+### Features
+
+* **dropdown-select:** add disabled state for individual options ([#2174](https://github.com/telekom/scale/issues/2174)) ([b53b711](https://github.com/telekom/scale/commit/b53b7113ddf73725ae30cb28f39868caf2d05683))
+* update ghost button color ([#2181](https://github.com/telekom/scale/issues/2181)) ([60d33c4](https://github.com/telekom/scale/commit/60d33c4fb15c5f79b43b386d077c11ea7e0c9dde))
+
+
+
+
+
# [3.0.0-beta.143](https://github.com/telekom/scale/compare/v3.0.0-beta.142...v3.0.0-beta.143) (2023-11-03)
**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 091b76ac9d..15f022c12d 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.143",
+ "version": "3.0.0-beta.144",
"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.143",
- "@telekom/scale-components-vue": "^3.0.0-beta.143"
+ "@telekom/scale-components": "^3.0.0-beta.144",
+ "@telekom/scale-components-vue": "^3.0.0-beta.144"
},
"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/public/assets/3_components/dropdown-select/dropdown-select-items-disabled.png b/packages/storybook-vue/public/assets/3_components/dropdown-select/dropdown-select-items-disabled.png
new file mode 100644
index 0000000000..69428ee521
Binary files /dev/null and b/packages/storybook-vue/public/assets/3_components/dropdown-select/dropdown-select-items-disabled.png differ
diff --git a/packages/storybook-vue/stories/components/button/Button.stories.mdx b/packages/storybook-vue/stories/components/button/Button.stories.mdx
index 540c46e216..5c4db20b29 100644
--- a/packages/storybook-vue/stories/components/button/Button.stories.mdx
+++ b/packages/storybook-vue/stories/components/button/Button.stories.mdx
@@ -221,6 +221,23 @@ For Shadow Parts, please inspect the element's #shadow.
Label
```
+## Ghost Standard
+
+
+
+ {Template.bind({})}
+
+
+
+```html
+Label
+```
+
## Disabled
@@ -256,6 +273,25 @@ For Shadow Parts, please inspect the element's #shadow.
Label
```
+## Ghost Disabled
+
+
+
+ {Template.bind({})}
+
+
+
+```html
+Label
+```
+
+
## With Icon Before
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 9438456caa..d1bd284283 100644
--- a/packages/storybook-vue/stories/components/data-grid/DataGrid.stories.mdx
+++ b/packages/storybook-vue/stories/components/data-grid/DataGrid.stories.mdx
@@ -439,6 +439,12 @@ Email label is partially beautified by automatically removing the protocol (`mai
Expected format: date/time `string`, eg `'10:23:00'`
+##### Unique options, and their defaults
+
+- `format?: string = 'MM.dd.yyyy'`
+
+to properly sort by date, the date string value is parsed according to this format. For more info and additional formatting options, e.g. `'dd/MM/yyyy'` check the [date-fn docs](https://date-fns.org/v2.30.0/docs/parse).
+
{`
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 03b19a041d..b295b8e77e 100644
--- a/packages/storybook-vue/stories/components/dropdown-select/DropdownSelect.stories.mdx
+++ b/packages/storybook-vue/stories/components/dropdown-select/DropdownSelect.stories.mdx
@@ -1,16 +1,30 @@
import { Meta, Story, ArgsTable, Canvas } from '@storybook/addon-docs';
import ScaleDropdownSelect from './ScaleDropdownSelect.vue';
+import ScaleDropdownSelectItem from './ScaleDropdownSelectItem.vue';
import { action } from '@storybook/addon-actions';
export const Template = (args, { argTypes }) => ({
components: { ScaleDropdownSelect },
- props: ScaleDropdownSelect.props,
+ props: {
+ itemProps: { default: {} },
+ ...ScaleDropdownSelect.props,
+ },
+ data() {
+ return {
+ items: [
+ { value: 'caspar', label: 'Caspar' },
+ { value: 'cedric', label: 'Cedric' },
+ { value: 'cem', label: 'Cem' },
+ ],
+ };
+ },
template: `
({
@scaleBlur="['scale-blur']"
@scaleKeyDown="['scale-keydown']"
>
- Caspar
- Cedric
- Cem
+ {{ item.label }}
`,
@@ -148,6 +165,7 @@ export const Template = (args, { argTypes }) => ({
## Disabled
+### Whole Dropdown Select disabled
({
```
+### Individual items disabled
+
+
+ {Template.bind({})}
+
+
+
+```html
+
+ Caspar
+ Cedric
+ Cem
+
+```
+
## Error
diff --git a/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue b/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue
index 2fcdba068d..7b4ad43c48 100644
--- a/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue
+++ b/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelect.vue
@@ -23,6 +23,7 @@
import { action } from '@storybook/addon-actions';
export default {
+ name: 'Dropdown Select',
props: {
label: { type: String },
helperText: { type: String },
@@ -32,8 +33,8 @@ export default {
value: { type: String },
variant: { type: String },
comboboxId: { type: String },
- hideLabelVisually: {type: Boolean, default: false},
- floatingStrategy: { type: String }
+ hideLabelVisually: { type: Boolean, default: false },
+ floatingStrategy: { type: String },
},
methods: {
'scale-change'($event) {
diff --git a/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelectItem.vue b/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelectItem.vue
new file mode 100644
index 0000000000..c6f1eeed77
--- /dev/null
+++ b/packages/storybook-vue/stories/components/dropdown-select/ScaleDropdownSelectItem.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/storybook-vue/stories/components/dropdown-select/dropdown-select.md b/packages/storybook-vue/stories/components/dropdown-select/dropdown-select.md
index fb39f78814..08a273c3c4 100644
--- a/packages/storybook-vue/stories/components/dropdown-select/dropdown-select.md
+++ b/packages/storybook-vue/stories/components/dropdown-select/dropdown-select.md
@@ -56,6 +56,18 @@ When a Value from the dropdown is selected, it takes the place of the Label and
The dropdown menu contains the available options or groups of options.
+## Deactivated state
+
+Deactivate a dropdown select item when:
+
+- users have to complete another action before selecting the
+ dropdown select item or
+- the option must be listed but users can\'t currently select it.
+
+![Disabled Dropdown Select](assets/3_components/dropdown-select/dropdown-select-items-disabled.png)
+
+> The disabled state is exempt from the WCAG contrast minimum for text colors. You can find more information in the [WCAG guidelines](https://www.w3.org/TR/WCAG21/#contrast-minimum).
+
## Related components
[Checkbox, ](?path=/usage/components-checkbox--standard)
diff --git a/packages/storybook-vue/stories/components/dropdown-select/dropdown-select_de.md b/packages/storybook-vue/stories/components/dropdown-select/dropdown-select_de.md
index a5f78002f1..4389b87761 100644
--- a/packages/storybook-vue/stories/components/dropdown-select/dropdown-select_de.md
+++ b/packages/storybook-vue/stories/components/dropdown-select/dropdown-select_de.md
@@ -52,6 +52,17 @@ Wenn ein Wert aus der Dropdown-Liste ausgewählt wird, nimmt er den Platz des La
Das Dropdown Menü beinhaltet die verfügbaren Optionen oder Optionsgruppen.
+## Deaktivierter Zustand
+
+Deaktiviere einen Dropdown-Select Item, wenn
+
+- eine andere Aktion erfolgen muss, bevor der Dropdown-Select Item nutzbar ist oder
+- die Option aufgeführt werden muss, aber aktuell nicht auswählbar ist.
+
+![Deaktivierte Dropdown Select](assets/3_components/dropdown-select/dropdown-select-items-disabled.png)
+
+> Der deaktivierte Zustand (Disabled State) ist vom Kontrastminimum der WCAG für Textfarben ausgenommen. Weitere Informationen hierzu findest du in den [Richtlinien der WCAG](https://www.w3.org/TR/WCAG21/#contrast-minimum).
+
## Verwandte Komponenten
[Checkbox, ](?path=/usage/components-checkbox--standard)
diff --git a/packages/storybook-vue/stories/components/notification/Notification.stories.mdx b/packages/storybook-vue/stories/components/notification/Notification.stories.mdx
index fe61a250fc..dc242dde7c 100644
--- a/packages/storybook-vue/stories/components/notification/Notification.stories.mdx
+++ b/packages/storybook-vue/stories/components/notification/Notification.stories.mdx
@@ -49,7 +49,8 @@ import ScaleNotification from './ScaleNotification.vue';
innerAriaLive: {
control: {
type: 'text'
- }
+ },
+ description: 'Deprecated! innerAriaLive has been replaced by innerRole'
},
headingLevel: {
control: {
diff --git a/packages/storybook-vue/stories/components/notification/ScaleNotification.vue b/packages/storybook-vue/stories/components/notification/ScaleNotification.vue
index 40b36ba336..1adb3b6d4b 100644
--- a/packages/storybook-vue/stories/components/notification/ScaleNotification.vue
+++ b/packages/storybook-vue/stories/components/notification/ScaleNotification.vue
@@ -14,6 +14,7 @@ export default {
dismissible: { type: Boolean },
delay: { type: Number },
innerAriaLive: { type: String },
+ innerRole: { type: String, default: 'alert' },
closeButtonLabel: { type: String },
closeButtonTitle: { type: String },
styles: { type: String },
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 af0fca6517..3a09963717 100644
--- a/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx
+++ b/packages/storybook-vue/stories/components/tab-navigation/TabNav.stories.mdx
@@ -6,10 +6,12 @@ import {
Description,
} from '@storybook/addon-docs';
import ScaleTabNav from './ScaleTabNav.vue';
+import TabPanel from './TabPanel.vue';
+ export default {
+ name: 'Tab Panel',
+ props: {
+ styles: { type: String },
+ tabbable: { type: Boolean, default: 'true',
+ argTypes:{
+ table: {
+ type: { summary: 'string' },
+ },
+ description: `(optional) Injected styles`,
+ control: { type: null },
+ },
+ },
+ }
+ };
+
diff --git a/packages/storybook-vue/stories/components/telekom-footer/FooterContent.vue b/packages/storybook-vue/stories/components/telekom-footer/FooterContent.vue
index 1233b0c04e..5df9c0a7e2 100644
--- a/packages/storybook-vue/stories/components/telekom-footer/FooterContent.vue
+++ b/packages/storybook-vue/stories/components/telekom-footer/FooterContent.vue
@@ -2,7 +2,7 @@
export default {
name: 'FooterContent',
props: {
- logoHref: { type: String, default: 'javascript:void(0);' },
+ logoHref: { type: String, default: '' },
logoTitle: { type: String, default: 'Telekom Logo' },
logoHideTitle: { type: Boolean, default: false }
}
diff --git a/packages/storybook-vue/stories/components/tooltip/Tooltip.stories.mdx b/packages/storybook-vue/stories/components/tooltip/Tooltip.stories.mdx
index e234397220..fdfd21b901 100644
--- a/packages/storybook-vue/stories/components/tooltip/Tooltip.stories.mdx
+++ b/packages/storybook-vue/stories/components/tooltip/Tooltip.stories.mdx
@@ -149,6 +149,7 @@ export const FocusTemplate = (args, { argTypes }) => ({
--line-height: var(--telekom-typography-line-spacing-standard);
--spacing: var(--telekom-spacing-composition-space-02)
var(--telekom-spacing-composition-space-04);
+ --width: auto;
/* arrow */
--arrow-size: 12px;
diff --git a/packages/storybook-vue/stories/update_history/Design_de.md b/packages/storybook-vue/stories/update_history/Design_de.md
index 5d78e92878..18da3dd34a 100644
--- a/packages/storybook-vue/stories/update_history/Design_de.md
+++ b/packages/storybook-vue/stories/update_history/Design_de.md
@@ -2,6 +2,12 @@
Diese Seite dokumentiert Updates der visuellen Erscheinung von Scale
+## Aktualisierung des Ghost Buttons
+
+30.11.2023
+
+Wir haben die Farbe des Ghost Buttons geändert, um die Barrierefreiheit im Dark Mode zu optimieren.
+
## Typografie-Update
06.04.2023
diff --git a/packages/storybook-vue/stories/update_history/Design_en.md b/packages/storybook-vue/stories/update_history/Design_en.md
index 33c0d38889..0975357eba 100644
--- a/packages/storybook-vue/stories/update_history/Design_en.md
+++ b/packages/storybook-vue/stories/update_history/Design_en.md
@@ -2,6 +2,12 @@
This page documents updates to the visual appearance of Scale.
+## Ghost Button Update
+
+30.11.2023
+
+We have changed the color of the Ghost Button to optimize accessibility in dark mode.
+
## Type Update
06.04.2023
diff --git a/packages/visual-tests/CHANGELOG.md b/packages/visual-tests/CHANGELOG.md
index f2fc5575ce..d9562ddcd4 100644
--- a/packages/visual-tests/CHANGELOG.md
+++ b/packages/visual-tests/CHANGELOG.md
@@ -3,6 +3,14 @@
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.144](https://github.com/telekom/scale/compare/v3.0.0-beta.143...v3.0.0-beta.144) (2023-11-30)
+
+**Note:** Version bump only for package @telekom/scale-visual-tests
+
+
+
+
+
# [3.0.0-beta.143](https://github.com/telekom/scale/compare/v3.0.0-beta.142...v3.0.0-beta.143) (2023-11-03)
**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 ab10f50ab2..fcaeb8ccd7 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.143",
+ "version": "3.0.0-beta.144",
"main": "index.js",
"license": "MPL-2.0",
"scripts": {
diff --git a/packages/visual-tests/src/switch.visual.spec.js b/packages/visual-tests/src/switch.visual.spec.js
index 54d6cc566f..1ea18fbe3f 100644
--- a/packages/visual-tests/src/switch.visual.spec.js
+++ b/packages/visual-tests/src/switch.visual.spec.js
@@ -31,6 +31,7 @@ describe('Switch', () => {
test.each([['standard']])('focus %p', async (variant) => {
await global.runSetup(`components-switch--${variant}`);
+ await global.page.waitFor(300);
await global.page.keyboard.press('Tab');
await global.page.waitFor(300);
await global.visualCheck();
diff --git a/yarn.lock b/yarn.lock
index f5ee0d817c..b904652a56 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2991,6 +2991,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.21.0":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885"
+ integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
"@babel/runtime@^7.7.6":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
@@ -3526,17 +3533,25 @@
unique-filename "^1.1.1"
which "^1.3.1"
-"@floating-ui/core@^0.7.3":
- version "0.7.3"
- resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86"
- integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==
+"@floating-ui/core@^1.4.2":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.5.0.tgz#5c05c60d5ae2d05101c3021c1a2a350ddc027f8c"
+ integrity sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==
+ dependencies:
+ "@floating-ui/utils" "^0.1.3"
-"@floating-ui/dom@^0.5.4":
- version "0.5.4"
- resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-0.5.4.tgz#4eae73f78bcd4bd553ae2ade30e6f1f9c73fe3f1"
- integrity sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==
+"@floating-ui/dom@^1.2.8":
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa"
+ integrity sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==
dependencies:
- "@floating-ui/core" "^0.7.3"
+ "@floating-ui/core" "^1.4.2"
+ "@floating-ui/utils" "^0.1.3"
+
+"@floating-ui/utils@^0.1.3":
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9"
+ integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
"@hapi/address@2.x.x":
version "2.1.4"
@@ -8472,6 +8487,11 @@ component-emitter@^1.2.1:
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+composed-offset-position@^0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/composed-offset-position/-/composed-offset-position-0.0.4.tgz#ca8854abf15e3c235ecf4df125a27fe88af76ea4"
+ integrity sha512-vMlvu1RuNegVE0YsCDSV/X4X10j56mq7PCIyOKK74FxkXzGLwhOUmdkJLSdOBOMwWycobGUMgft2lp+YgTe8hw==
+
compressible@~2.0.16:
version "2.0.18"
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
@@ -9124,10 +9144,12 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
-date-fns@^2.6.0:
- version "2.15.0"
- resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.15.0.tgz"
- integrity sha512-ZCPzAMJZn3rNUvvQIMlXhDr4A+Ar07eLeGsGREoWU19a3Pqf5oYa+ccd+B3F6XVtQY6HANMFdOQ8A+ipFnvJdQ==
+date-fns@^2.30.0:
+ version "2.30.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
+ integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
+ dependencies:
+ "@babel/runtime" "^7.21.0"
dateformat@3.0.2:
version "3.0.2"
@@ -16622,6 +16644,11 @@ regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
+regenerator-runtime@^0.14.0:
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
+ integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
+
regenerator-transform@^0.14.2:
version "0.14.5"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz"