) => {
+ if (props.onFocus) {
+ props.onFocus(event);
+ }
+
+ if (props.focus) {
+ props.focus(event);
+ }
+ }
+ });
+
+ onMount(() => {
+ state._id = props.id || 'switch-' + uuid();
+ });
+ // jscpd:ignore-end
+
+ return (
+
+ );
+}
diff --git a/packages/components/src/components/switch/switch.scss b/packages/components/src/components/switch/switch.scss
new file mode 100644
index 00000000000..cde06ff0276
--- /dev/null
+++ b/packages/components/src/components/switch/switch.scss
@@ -0,0 +1,218 @@
+@use "@db-ui/foundations/build/scss/variables";
+@use "@db-ui/foundations/build/scss/colors";
+@use "@db-ui/foundations/build/scss/fonts";
+@use "@db-ui/foundations/build/scss/helpers";
+@use "@db-ui/foundations/build/scss/icons";
+@use "../../styles/form-components";
+
+$switch-fixed-padding: helpers.px-to-rem(2);
+
+$switch-inactive-thumb-size: calc(
+ #{form-components.$font-size-height} - #{$switch-fixed-padding} * 2
+);
+
+$switch-active-thumb-size: calc(#{form-components.$font-size-height});
+
+$checked-active-transition-size: calc(
+ #{form-components.$font-size-height} - #{$switch-fixed-padding} * 2
+);
+
+%active-transition {
+ &::before {
+ inline-size: calc(
+ #{$switch-active-thumb-size} - #{$switch-fixed-padding} * 2 + #{variables.$db-spacing-fixed-2xs}
+ );
+ margin: 0;
+ }
+
+ &:checked {
+ &::before {
+ block-size: $checked-active-transition-size;
+ }
+ }
+}
+
+.db-switch {
+ @include form-components.set-default-check-element(check);
+ justify-content: space-between;
+ user-select: none;
+
+ // This is needed when clicking on the label instead of the input
+ @include helpers.active {
+ & > input {
+ @extend %active-transition;
+ }
+ }
+
+ & > input {
+ --db-icon-margin-start: 0;
+ --thumb-offset-x: #{$switch-fixed-padding};
+ @extend %db-overwrite-font-size-sm;
+
+ @include icons.set-icon("cross", "after");
+ appearance: none;
+
+ inline-size: calc(
+ #{form-components.$font-size-height} * 2 + #{$switch-fixed-padding}
+ );
+ block-size: form-components.$font-size-height;
+ box-sizing: content-box;
+
+ display: flex;
+ align-items: center;
+ gap: $switch-fixed-padding;
+
+ background-color: colors.$db-current-color-bg-enabled;
+ border-radius: variables.$db-border-radius-full;
+
+ &::after {
+ visibility: hidden;
+ align-self: center;
+ aspect-ratio: 1;
+ }
+
+ // thumb
+ &::before {
+ content: "";
+ aspect-ratio: 1;
+ block-size: $switch-inactive-thumb-size;
+ background: colors.$db-current-color-enabled;
+ border-radius: variables.$db-border-radius-full;
+ transform: translateX(var(--thumb-offset-x));
+
+ margin-inline-end: calc(
+ #{$switch-active-thumb-size} - #{$switch-inactive-thumb-size}
+ );
+
+ transition:
+ margin variables.$db-transition-duration-fast
+ variables.$db-transition-timing-emotional,
+ inline-size variables.$db-transition-duration-fast
+ variables.$db-transition-timing-emotional,
+ block-size variables.$db-transition-duration-fast
+ variables.$db-transition-timing-emotional,
+ transform variables.$db-transition-duration-fast
+ variables.$db-transition-timing-emotional;
+
+ // Adopted by https://www.heise.de/developer/artikel/a11y-Reduced-Motion-4356171.html
+ @media (prefers-reduced-motion: reduce) {
+ transition-duration: 0.01s !important;
+ }
+ }
+
+ /* positioned at the end of the track: track length - 100% (thumb width) */
+ &:checked {
+ --db-current-icon-color: #{colors.$db-current-color-bg-enabled};
+ --thumb-offset-x: calc(100% + #{$switch-fixed-padding});
+
+ background-color: colors.$db-current-color-enabled;
+
+ @include helpers.hover {
+ background-color: colors.$db-current-color-hover;
+ border-color: colors.$db-current-color-hover;
+ }
+
+ @include helpers.active {
+ background-color: colors.$db-current-color-pressed;
+ border-color: colors.$db-current-color-pressed;
+ }
+
+ &::before {
+ block-size: $switch-active-thumb-size;
+ background-color: colors.$db-current-color-bg-enabled;
+ margin: 0;
+ }
+ }
+
+ &:focus-visible {
+ // Overwrite default border-radius
+ border-radius: variables.$db-border-radius-full;
+ }
+ }
+
+ &[data-variant="hidden"] {
+ gap: 0;
+ }
+
+ &[data-size="small"] {
+ gap: variables.$db-spacing-fixed-2xs;
+
+ & > input {
+ @extend %db-overwrite-font-size-xs;
+ }
+ }
+
+ &[data-emphasis="strong"] {
+ // This is needed when clicking on an active strong switch
+ @include helpers.hover {
+ & > input {
+ background-color: colors.$db-current-color-bg-hover;
+ border-color: colors.$db-current-color-bg-hover;
+ }
+ }
+
+ @include helpers.active {
+ & > input {
+ background-color: colors.$db-current-color-bg-pressed;
+ border-color: colors.$db-current-color-bg-pressed;
+
+ &::before {
+ block-size: $checked-active-transition-size;
+ }
+ }
+ }
+
+ & > input {
+ --db-check-element-border-color: #{colors.$db-current-color-bg-enabled};
+ @extend %db-critical-contrast-low;
+
+ &:not(:checked) {
+ --thumb-offset-x: 0;
+ }
+
+ &:checked {
+ @extend %db-successful-contrast-low;
+
+ &::before {
+ background-color: colors.$db-current-color-enabled;
+ }
+ }
+
+ &::before {
+ block-size: $switch-active-thumb-size;
+ margin: 0;
+ }
+ }
+ }
+
+ &[data-emphasis="strong"],
+ &[data-visual-aid="true"] {
+ & > input {
+ &::after {
+ visibility: visible;
+ block-size: $switch-active-thumb-size;
+ }
+
+ &:checked {
+ @include icons.set-icon("check", "after");
+
+ &::after {
+ transform: translateX(
+ calc(-100% - #{$switch-fixed-padding})
+ );
+ block-size: $switch-active-thumb-size;
+ }
+ }
+ }
+ }
+
+ & > input {
+ &[data-aid-icon]:not(:checked)::after {
+ content: attr(data-aid-icon);
+ }
+
+ &[data-aid-icon-after]:checked::after {
+ content: attr(data-aid-icon-after);
+ }
+ }
+}
diff --git a/packages/components/src/components/switch/switch.spec.tsx b/packages/components/src/components/switch/switch.spec.tsx
new file mode 100644
index 00000000000..92f5b0e48fb
--- /dev/null
+++ b/packages/components/src/components/switch/switch.spec.tsx
@@ -0,0 +1,36 @@
+import { test, expect } from '@playwright/experimental-ct-react';
+import AxeBuilder from '@axe-core/playwright';
+
+import { DBSwitch } from './index';
+// @ts-ignore - vue can only find it with .ts as file ending
+import { DEFAULT_VIEWPORT } from '../../shared/constants.ts';
+
+const comp = Test;
+
+const testComponent = () => {
+ test('should contain text', async ({ mount }) => {
+ const component = await mount(comp);
+ await expect(component).toContainText('Test');
+ });
+
+ test('should match screenshot', async ({ mount }) => {
+ const component = await mount(comp);
+ await expect(component).toHaveScreenshot();
+ });
+};
+
+test.describe('DBSwitch', () => {
+ test.use({ viewport: DEFAULT_VIEWPORT });
+ testComponent();
+});
+
+test.describe('DBSwitch', () => {
+ test('should not have any A11y issues', async ({ page, mount }) => {
+ await mount(comp);
+ const accessibilityScanResults = await new AxeBuilder({ page })
+ .include('.db-switch')
+ .analyze();
+
+ expect(accessibilityScanResults.violations).toEqual([]);
+ });
+});
diff --git a/packages/components/src/components/textarea/textarea.lite.tsx b/packages/components/src/components/textarea/textarea.lite.tsx
index dc195e0a9cb..6a15c585255 100644
--- a/packages/components/src/components/textarea/textarea.lite.tsx
+++ b/packages/components/src/components/textarea/textarea.lite.tsx
@@ -99,15 +99,22 @@ export default function DBTextarea(props: DBTextareaProps) {
state._validMessageId = state._id + DEFAULT_VALID_MESSAGE_ID_SUFFIX;
state._invalidMessageId =
state._id + DEFAULT_INVALID_MESSAGE_ID_SUFFIX;
-
- state._descByIds = [
- state._messageId,
- state._validMessageId,
- state._invalidMessageId
- ].join(' ');
}
}, [state._id]);
+ onUpdate(() => {
+ const descByIds = [state._validMessageId, state._invalidMessageId];
+ if (props.message) {
+ descByIds.push(state._messageId);
+ }
+ state._descByIds = descByIds.join(' ');
+ }, [
+ props.message,
+ state._messageId,
+ state._validMessageId,
+ state._invalidMessageId
+ ]);
+
return (
void;
+ onClose?: (event?: any) => void;
};
export type CloseEventState = {
diff --git a/packages/components/src/styles/_component.scss b/packages/components/src/styles/_component.scss
index 88f365e7c52..0120b869fa3 100644
--- a/packages/components/src/styles/_component.scss
+++ b/packages/components/src/styles/_component.scss
@@ -5,7 +5,7 @@
$default-mobile-header-height: var(
--db-sizing-fixed-mobile-header,
- #{helpers.to-rem(56)}
+ #{helpers.px-to-rem(56)}
);
$default-disabled: 0.4;
diff --git a/packages/components/src/styles/_link-components.scss b/packages/components/src/styles/_link-components.scss
index d4b15361edb..d8de3633cda 100644
--- a/packages/components/src/styles/_link-components.scss
+++ b/packages/components/src/styles/_link-components.scss
@@ -38,7 +38,7 @@
// Link underline
// TODO: We should evaluate whether we could move this declaration to the @font-face declarations even already
text-underline-position: from-font;
- text-decoration-thickness: helpers.to-rem($pxValue: 1);
+ text-decoration-thickness: helpers.px-to-rem($pxValue: 1);
white-space: nowrap;
&:focus-visible {
diff --git a/packages/components/src/styles/_scrollbar.scss b/packages/components/src/styles/_scrollbar.scss
index c0aac5121ee..decc8c94855 100644
--- a/packages/components/src/styles/_scrollbar.scss
+++ b/packages/components/src/styles/_scrollbar.scss
@@ -4,7 +4,7 @@
@use "@db-ui/foundations/build/scss/animation";
@use "./form-components";
-$scrollbar-width: helpers.to-rem(8);
+$scrollbar-width: helpers.px-to-rem(8);
%scrollbar {
&::-webkit-scrollbar {
diff --git a/packages/components/src/styles/_tag-components.scss b/packages/components/src/styles/_tag-components.scss
index 2a168bdd513..8629e69e370 100644
--- a/packages/components/src/styles/_tag-components.scss
+++ b/packages/components/src/styles/_tag-components.scss
@@ -27,7 +27,7 @@ $interactive-selectors: "label, button:not(.db-tab-remove-button), a";
@extend %db-#{$name}-bg-lvl-1;
&[data-emphasis="strong"] {
- @extend %db-#{$name}-component;
+ @extend %db-#{$name}-contrast-high;
}
}
}
diff --git a/packages/components/src/styles/db-ui-components.scss b/packages/components/src/styles/db-ui-components.scss
index e1aae81e130..e6884c9eb5b 100644
--- a/packages/components/src/styles/db-ui-components.scss
+++ b/packages/components/src/styles/db-ui-components.scss
@@ -20,25 +20,21 @@
@forward "../components/navigation-item/navigation-item";
@forward "../components/textarea/textarea";
@forward "../components/badge/badge";
-
@forward "../components/accordion/accordion";
-
@forward "../components/accordion-item/accordion-item";
@forward "../components/navigation/navigation";
-
@forward "../components/popover/popover";
@forward "../components/tooltip/tooltip";
@forward "dialog-init";
-
@forward "../components/tab-item/tab-item";
-
@forward "../components/tab-list/tab-list";
-
@forward "../components/tabs/tabs";
-
@forward "../components/tab-panel/tab-panel";
+@forward "../components/switch/switch";
// angular-workaround
+dbswitch,
+db-switch,
dbtab-panel,
db-tab-panel,
dbtabs,
diff --git a/packages/components/src/utils/index.ts b/packages/components/src/utils/index.ts
index c397c1f35bd..f79ce3c92ad 100644
--- a/packages/components/src/utils/index.ts
+++ b/packages/components/src/utils/index.ts
@@ -164,18 +164,31 @@ export const isInView = (el: Element) => {
};
};
-export const handleDataOutside = (el: Element) => {
+export interface DBDataOutsidePair {
+ vx?: 'left' | 'right';
+ vy?: 'top' | 'bottom';
+}
+export const handleDataOutside = (el: Element): DBDataOutsidePair => {
const { outTop, outBottom, outLeft, outRight } = isInView(el);
+ let dataOutsidePair: DBDataOutsidePair = {};
+
if (outTop || outBottom) {
- el.setAttribute('data-outside-vy', outTop ? 'top' : 'bottom');
+ dataOutsidePair = { vy: outTop ? 'top' : 'bottom' };
+ el.setAttribute('data-outside-vy', dataOutsidePair.vy!);
} else {
el.removeAttribute('data-outside-vy');
}
if (outLeft || outRight) {
- el.setAttribute('data-outside-vx', outRight ? 'right' : 'left');
+ dataOutsidePair = {
+ ...dataOutsidePair,
+ vx: outRight ? 'right' : 'left'
+ };
+ el.setAttribute('data-outside-vx', dataOutsidePair.vx!);
} else {
el.removeAttribute('data-outside-vx');
}
+
+ return dataOutsidePair;
};
export default {
diff --git a/packages/components/src/utils/navigation.ts b/packages/components/src/utils/navigation.ts
index d10bdb6679c..b618f475a23 100644
--- a/packages/components/src/utils/navigation.ts
+++ b/packages/components/src/utils/navigation.ts
@@ -1,3 +1,6 @@
+import { DBNavigationItemTriangleData } from '../components/navigation-item/model';
+import { handleDataOutside } from './index';
+
export const isEventTargetNavigationItem = (event: unknown): boolean => {
const { target } = event as { target: HTMLElement };
return Boolean(
@@ -6,6 +9,198 @@ export const isEventTargetNavigationItem = (event: unknown): boolean => {
);
};
+export class NavigationItemSafeTriangle {
+ private readonly element: HTMLElement;
+ private readonly subNavigation: Element;
+ private readonly parentSubNavigation: Element | null;
+ private triangleData?: DBNavigationItemTriangleData;
+ private initialized: boolean = false;
+ private mouseX: number = 0;
+ private mouseY: number = 0;
+ constructor(element: HTMLElement, subNavigation: Element) {
+ this.element = element;
+ this.subNavigation = subNavigation;
+ this.parentSubNavigation = this.element.closest('.db-sub-navigation');
+
+ /*
+ * only initiate if:
+ * 1. item is not at root navigation level
+ * 2. item is not in the mobile navigation / within db-drawer
+ */
+ if (this.parentSubNavigation && !this.element.closest('.db-drawer')) {
+ this.init();
+ }
+ }
+
+ private init() {
+ const parentElementWidth =
+ this.parentSubNavigation?.getBoundingClientRect().width ?? 0;
+
+ // the triangle has the width of the sub-navigation, current nav-item can be wider.
+ // so the width of the triangle must be adapted to a possibly wider nav-item.
+ this.element.style.setProperty(
+ '--db-navigation-item-inline-size',
+ `${parentElementWidth}px`
+ );
+
+ this.initialized = true;
+ }
+
+ public enableFollow() {
+ if (!this.initialized || this.triangleData) {
+ return;
+ }
+
+ const dataOutsidePair = handleDataOutside(this.subNavigation);
+
+ const itemRect = this.element.getBoundingClientRect();
+ const parentElementWidth =
+ this.parentSubNavigation?.getBoundingClientRect().width ?? 0;
+
+ this.triangleData = {
+ itemRect,
+ parentElementWidth,
+ subNavigationHeight:
+ this.subNavigation.getBoundingClientRect().height,
+ padding: (parentElementWidth - itemRect.width) / 2,
+ outsideVX: dataOutsidePair.vx,
+ outsideVY: dataOutsidePair.vy
+ };
+ }
+
+ public disableFollow() {
+ this.triangleData = undefined;
+ }
+
+ private getTriangleTipX(): number {
+ if (!this.triangleData) return 0;
+
+ if (this.triangleData.outsideVX === 'right') {
+ // vertical flipped triangle needs an inverted x pos
+ return this.triangleData.itemRect.width - this.mouseX;
+ }
+
+ // triangle stops shrinking from 75% x pos
+ return Math.min(this.mouseX, this.triangleData.itemRect.width * 0.75);
+ }
+
+ private getTriangleTipY(): number {
+ if (!this.triangleData) return 0;
+
+ // padding must be added to the y pos of the tip so that the y pos matches the cursor
+ const mouseYLimited =
+ Math.max(
+ Math.min(this.mouseY, this.triangleData.itemRect.height),
+ 0
+ ) + this.triangleData.padding;
+
+ if (this.triangleData.outsideVY === 'bottom') {
+ // add offset to tip y pos to match corrected sub-navigation y pos
+ return (
+ mouseYLimited +
+ (this.triangleData.subNavigationHeight -
+ this.triangleData.padding * 2 -
+ this.triangleData.itemRect.height)
+ );
+ }
+
+ return mouseYLimited;
+ }
+
+ private hasMouseEnteredSubNavigation(): boolean {
+ if (!this.triangleData) {
+ return false;
+ }
+
+ const isSubNavigationOnLeftSide =
+ this.triangleData.outsideVX === 'right';
+
+ if (
+ isSubNavigationOnLeftSide &&
+ this.mouseX < -1 * this.triangleData.padding
+ ) {
+ return true;
+ }
+
+ if (
+ !isSubNavigationOnLeftSide &&
+ this.mouseX >
+ this.triangleData.parentElementWidth - this.triangleData.padding
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private getTriangleCoordinates(variant: 'safe-triangle' | 'fill-gap'):
+ | undefined
+ | {
+ lb: string;
+ lt: string;
+ rt: string;
+ rb: string;
+ } {
+ if (!this.triangleData) {
+ return;
+ }
+
+ if (variant === 'fill-gap') {
+ const itemHeight = `${this.triangleData.itemRect.height + 2 * this.triangleData.padding}px`;
+ const xStart = `${this.triangleData.parentElementWidth - this.triangleData.padding}px`;
+
+ return {
+ lb: `${xStart} ${itemHeight}`,
+ lt: `${xStart} 0`,
+ rt: '100% 0',
+ rb: `100% ${itemHeight}`
+ };
+ }
+
+ const tipX = this.getTriangleTipX();
+ const tipY = this.getTriangleTipY();
+
+ const lb = `${tipX}px ${tipY + this.triangleData.padding}px`;
+ const lt = `${tipX}px ${tipY - this.triangleData.padding}px`;
+
+ return {
+ lb,
+ lt,
+ rt: '100% 0',
+ rb: '100% 100%'
+ };
+ }
+
+ public followByMouseEvent(event: MouseEvent) {
+ if (!this.initialized || !this.triangleData) {
+ return;
+ }
+
+ this.mouseX = event.clientX - this.triangleData.itemRect.left;
+ this.mouseY = event.clientY - this.triangleData.itemRect.top;
+
+ const isOverSubNavigation = this.hasMouseEnteredSubNavigation();
+
+ const coordinates = this.getTriangleCoordinates(
+ isOverSubNavigation ? 'fill-gap' : 'safe-triangle'
+ );
+
+ if (!coordinates) {
+ return;
+ }
+
+ this.element.style.setProperty(
+ '--db-navigation-item-clip-path',
+ `polygon(${coordinates.lb}, ${coordinates.lt}, ${coordinates.rt}, ${coordinates.rb})`
+ );
+
+ if (isOverSubNavigation) {
+ this.triangleData = undefined;
+ }
+ }
+}
+
export default {
- isEventTargetNavigationItem
+ isEventTargetNavigationItem,
+ NavigationItemSafeTriangle
};
diff --git a/packages/components/test/playwright/config.ts b/packages/components/test/playwright/config.ts
index 7680c5f583a..c7ec91b1922 100644
--- a/packages/components/test/playwright/config.ts
+++ b/packages/components/test/playwright/config.ts
@@ -22,10 +22,14 @@ const config = defineConfig({
reporter: process.env.CI ? 'blob' : [['list'], ['html', { open: 'never' }]],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
- trace: 'on-first-retry',
/* Port to use for Playwright component endpoint. */
- ctPort: 3100
+ ctPort: 3100,
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: process.env.CI ? 'on-first-retry' : 'on',
+
+ /* Collect video when retrying the failed test. */
+ video: process.env.CI ? 'on-first-retry' : 'on'
},
/* Configure projects for major browsers */
projects: [
diff --git a/packages/foundations/package.json b/packages/foundations/package.json
index 9119d3c9b97..c19b56483fc 100644
--- a/packages/foundations/package.json
+++ b/packages/foundations/package.json
@@ -40,10 +40,10 @@
"devDependencies": {
"@csstools/normalize.css": "12.1.1",
"cpr": "3.0.1",
- "cssnano": "^6.1.2",
+ "cssnano": "^7.0.1",
"dotenv": "^16.4.5",
"nodemon": "3.1.0",
- "sass": "^1.75.0"
+ "sass": "^1.76.0"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
diff --git a/packages/foundations/scss/_focus.scss b/packages/foundations/scss/_focus.scss
index 395fe80dc83..8fd8a0e1ec0 100644
--- a/packages/foundations/scss/_focus.scss
+++ b/packages/foundations/scss/_focus.scss
@@ -18,7 +18,12 @@
#{variables.$db-transition-duration-ultra-fast}
);
- &:not([type="radio"]) {
+ &:not([type="radio"], [role="switch"]) {
border-radius: variables.$db-border-radius-xs;
}
+
+ // Adopted by https://www.heise.de/developer/artikel/a11y-Reduced-Motion-4356171.html
+ @media (prefers-reduced-motion: reduce) {
+ transition-duration: 0.01s !important;
+ }
}
diff --git a/packages/foundations/scss/_init.scss b/packages/foundations/scss/_init.scss
index 7db1ea48227..8ba58bfbf03 100644
--- a/packages/foundations/scss/_init.scss
+++ b/packages/foundations/scss/_init.scss
@@ -24,6 +24,12 @@ body {
padding: 0;
}
+body,
+#root,
+#app {
+ block-size: inherit;
+}
+
body,
// Power Apps related
.app-canvas,
@@ -149,12 +155,12 @@ fieldset {
// Code
pre:has(code) {
- @extend %db-neutral-component;
+ @extend %db-neutral-contrast-high;
padding: variables.$db-spacing-fixed-xs;
}
code {
- @extend %db-neutral-component;
+ @extend %db-neutral-contrast-high;
padding-block: variables.$db-spacing-fixed-3xs;
padding-inline: variables.$db-spacing-fixed-2xs;
}
diff --git a/packages/foundations/scss/_screen-sizes.scss b/packages/foundations/scss/_screen-sizes.scss
index 2a81b9f0e0d..3abfa92cbdf 100644
--- a/packages/foundations/scss/_screen-sizes.scss
+++ b/packages/foundations/scss/_screen-sizes.scss
@@ -6,11 +6,11 @@ $db-screen-size-md: 1024;
$db-screen-size-lg: 1440;
$db-screen-size-xl: 1920;
-$db-breakpoint-xs: helpers.to-em($db-screen-size-xs);
-$db-breakpoint-sm: helpers.to-em($db-screen-size-sm);
-$db-breakpoint-md: helpers.to-em($db-screen-size-md);
-$db-breakpoint-lg: helpers.to-em($db-screen-size-lg);
-$db-breakpoint-xl: helpers.to-em($db-screen-size-xl);
+$db-breakpoint-xs: helpers.px-to-em($db-screen-size-xs);
+$db-breakpoint-sm: helpers.px-to-em($db-screen-size-sm);
+$db-breakpoint-md: helpers.px-to-em($db-screen-size-md);
+$db-breakpoint-lg: helpers.px-to-em($db-screen-size-lg);
+$db-breakpoint-xl: helpers.px-to-em($db-screen-size-xl);
:root {
--db-breakpoint-xs: #{$db-breakpoint-xs};
@@ -33,7 +33,7 @@ $db-breakpoint-xl: helpers.to-em($db-screen-size-xl);
}
@if ($width == "min") {
- @media screen and (min-width: helpers.to-em($screen)) {
+ @media screen and (min-width: helpers.px-to-em($screen)) {
&:not([data-force-mobile]),
&[data-force-mobile="false"] {
@content;
@@ -44,7 +44,7 @@ $db-breakpoint-xl: helpers.to-em($db-screen-size-xl);
@content;
}
- @media screen and (max-width: helpers.to-em($screen - 1)) {
+ @media screen and (max-width: helpers.px-to-em($screen - 1)) {
@content;
}
}
diff --git a/packages/foundations/scss/colors/_placeholder.scss b/packages/foundations/scss/colors/_placeholder.scss
index fd81142e3e8..fd7dd0fa36d 100644
--- a/packages/foundations/scss/colors/_placeholder.scss
+++ b/packages/foundations/scss/colors/_placeholder.scss
@@ -22,28 +22,40 @@
}
@each $variant in variables.$variants {
- %db-#{$variant}-component {
- --db-current-icon-color: var(--db-#{$variant}-on-contrast-enabled);
- --db-current-color-enabled: var(--db-#{$variant}-on-contrast-enabled);
- --db-current-color-bg-enabled: var(
- --db-#{$variant}-contrast-high-enabled
- );
- --db-current-color-bg-hover: var(--db-#{$variant}-contrast-high-hover);
- --db-current-color-bg-pressed: var(
- --db-#{$variant}-contrast-high-pressed
- );
- --db-current-color-border: var(--db-#{$variant}-contrast-high-enabled);
- @extend %set-current-colors;
+ @each $contrast in [ "high", "low"] {
+ %db-#{$variant}-contrast-#{$contrast} {
+ --db-current-icon-color: var(--db-#{$variant}-on-contrast-enabled);
+ --db-current-color-enabled: var(
+ --db-#{$variant}-on-contrast-enabled
+ );
+ --db-current-color-bg-enabled: var(
+ --db-#{$variant}-contrast-#{$contrast}-enabled
+ );
+ --db-current-color-bg-hover: var(
+ --db-#{$variant}-contrast-#{$contrast}-hover
+ );
+ --db-current-color-bg-pressed: var(
+ --db-#{$variant}-contrast-#{$contrast}-pressed
+ );
+ --db-current-color-border: var(
+ --db-#{$variant}-contrast-#{$contrast}-enabled
+ );
+ @extend %set-current-colors;
- &-interactive {
- @extend %db-#{$variant}-component;
+ &-interactive {
+ @extend %db-#{$variant}-contrast-#{$contrast};
- &:hover {
- background: var(--db-#{$variant}-contrast-high-hover);
- }
+ &:hover {
+ background: var(
+ --db-#{$variant}-contrast-#{$contrast}-hover
+ );
+ }
- &:active {
- background: var(--db-#{$variant}-contrast-high-pressed);
+ &:active {
+ background: var(
+ --db-#{$variant}-contrast-#{$contrast}-pressed
+ );
+ }
}
}
}
diff --git a/packages/foundations/scss/colors/classes/_get-class.scss b/packages/foundations/scss/colors/classes/_get-class.scss
index 2411067195d..d34b3b6ea23 100644
--- a/packages/foundations/scss/colors/classes/_get-class.scss
+++ b/packages/foundations/scss/colors/classes/_get-class.scss
@@ -26,11 +26,13 @@
}
}
- .db-#{$variant}-component {
- @extend %db-#{$variant}-component;
+ @each $contrast in [ "high", "low"] {
+ .db-#{$variant}-contrast-#{$contrast} {
+ @extend %db-#{$variant}-contrast-#{$contrast};
- &-interactive {
- @extend %db-#{$variant}-component-interactive;
+ &-interactive {
+ @extend %db-#{$variant}-contrast-#{$contrast}-interactive;
+ }
}
}
}
diff --git a/packages/foundations/scss/helpers/_functions.scss b/packages/foundations/scss/helpers/_functions.scss
index f53cdba5a1c..33ed21c7d77 100644
--- a/packages/foundations/scss/helpers/_functions.scss
+++ b/packages/foundations/scss/helpers/_functions.scss
@@ -4,11 +4,11 @@
@use "../colors";
@use "../variables";
-@function to-rem($pxValue) {
+@function px-to-rem($pxValue) {
@return #{$pxValue * 0.0625}rem;
}
-@function to-em($pxValue) {
+@function px-to-em($pxValue) {
@return #{$pxValue * 0.0625}em;
}
diff --git a/packages/foundations/scss/icons/_icon-helpers.scss b/packages/foundations/scss/icons/_icon-helpers.scss
index a6b088e640d..00902143ff6 100644
--- a/packages/foundations/scss/icons/_icon-helpers.scss
+++ b/packages/foundations/scss/icons/_icon-helpers.scss
@@ -5,7 +5,7 @@
@use "../variables";
$default-icon-size: 24;
-$default-icon-size-rem: #{helpers.to-rem($default-icon-size)};
+$default-icon-size-rem: #{helpers.px-to-rem($default-icon-size)};
$default-icon-variants: "default", "inverted", "filled";
$default-icon-content: var(--db-icon, attr(data-icon));
diff --git a/showcases/angular-showcase/package.json b/showcases/angular-showcase/package.json
index 89af09608ac..da1ed495767 100644
--- a/showcases/angular-showcase/package.json
+++ b/showcases/angular-showcase/package.json
@@ -12,22 +12,22 @@
"watch": "ng build --watch --configuration development"
},
"dependencies": {
- "@angular/animations": "17.3.5",
- "@angular/common": "17.3.5",
- "@angular/compiler": "17.3.5",
- "@angular/core": "17.3.5",
- "@angular/forms": "17.3.5",
- "@angular/platform-browser": "17.3.5",
- "@angular/platform-browser-dynamic": "17.3.5",
- "@angular/router": "17.3.5",
+ "@angular/animations": "17.3.7",
+ "@angular/common": "17.3.7",
+ "@angular/compiler": "17.3.7",
+ "@angular/core": "17.3.7",
+ "@angular/forms": "17.3.7",
+ "@angular/platform-browser": "17.3.7",
+ "@angular/platform-browser-dynamic": "17.3.7",
+ "@angular/router": "17.3.7",
"rxjs": "~7.8.1",
"tslib": "^2.6.2",
- "zone.js": "~0.14.4"
+ "zone.js": "~0.14.5"
},
"devDependencies": {
- "@angular-devkit/build-angular": "17.3.5",
- "@angular/cli": "17.3.5",
- "@angular/compiler-cli": "17.3.5",
+ "@angular-devkit/build-angular": "17.3.6",
+ "@angular/cli": "17.3.6",
+ "@angular/compiler-cli": "17.3.7",
"ng-packagr": "17.3.0",
"typescript": "^5.4.5"
}
diff --git a/showcases/angular-showcase/src/app/app.component.html b/showcases/angular-showcase/src/app/app.component.html
index 5f78c855b0b..fef900e968f 100644
--- a/showcases/angular-showcase/src/app/app.component.html
+++ b/showcases/angular-showcase/src/app/app.component.html
@@ -4,7 +4,7 @@
}
@if (!page) {
-
+
@@ -29,17 +28,17 @@
@if (exampleProps.areaPopup) {
-
+
Test1
-
+
Test2
-
+
Test3
diff --git a/showcases/angular-showcase/src/app/components/navigation/navigation.component.html b/showcases/angular-showcase/src/app/components/navigation/navigation.component.html
index 39dbd89bfe5..c784d470f06 100644
--- a/showcases/angular-showcase/src/app/components/navigation/navigation.component.html
+++ b/showcases/angular-showcase/src/app/components/navigation/navigation.component.html
@@ -23,34 +23,31 @@ {{ exampleName }}
Sub-Navi-Item 1
-
+
Sub-Sub-Navi-Item 1
-
+
Sub-Sub-Navi-Item 2
-
+
Sub-Navi-Item 2
-
+
Navi-Item 2
-
+
Navi-Item 3
diff --git a/showcases/angular-showcase/src/app/components/switch/switch.component.html b/showcases/angular-showcase/src/app/components/switch/switch.component.html
new file mode 100644
index 00000000000..d1cf6d151b4
--- /dev/null
+++ b/showcases/angular-showcase/src/app/components/switch/switch.component.html
@@ -0,0 +1,31 @@
+
+
+
+ {{ exampleName }}
+
+ @if (exampleProps.variant === "hidden") {
+
+ {{ exampleName }}
+
+ }
+
+
diff --git a/showcases/angular-showcase/src/app/components/switch/switch.component.ts b/showcases/angular-showcase/src/app/components/switch/switch.component.ts
new file mode 100644
index 00000000000..f2f032026e1
--- /dev/null
+++ b/showcases/angular-showcase/src/app/components/switch/switch.component.ts
@@ -0,0 +1,15 @@
+import { Component } from '@angular/core';
+import { DefaultComponent } from '../default.component';
+import defaultComponentVariants from '../../../../../shared/switch.json';
+import { DBSwitch } from '../../../../../../output/angular/src/components/switch';
+import { DBInfotext } from '../../../../../../output/angular/src/components/infotext';
+
+@Component({
+ selector: 'app-switch',
+ templateUrl: './switch.component.html',
+ imports: [DefaultComponent, DBSwitch, DBInfotext],
+ standalone: true
+})
+export class SwitchComponent {
+ variants = defaultComponentVariants;
+}
diff --git a/showcases/angular-showcase/src/app/utils/navigation-item.ts b/showcases/angular-showcase/src/app/utils/navigation-item.ts
index 58b2235f471..74a3ebff257 100644
--- a/showcases/angular-showcase/src/app/utils/navigation-item.ts
+++ b/showcases/angular-showcase/src/app/utils/navigation-item.ts
@@ -1,4 +1,5 @@
import { Routes } from '@angular/router';
+import { SwitchComponent } from '../components/switch/switch.component';
import { TabsComponent } from '../components/tabs/tabs.component';
import { TabItemComponent } from '../components/tab-item/tab-item.component';
import { TooltipComponent } from '../components/tooltip/tooltip.component';
@@ -125,6 +126,7 @@ export const NAVIGATION_ITEMS: NavItem[] = [
label: 'Checkbox',
component: CheckboxComponent
},
+ { path: '03/switch', label: 'Switch', component: SwitchComponent },
{ path: '03/select', label: 'Select', component: SelectComponent }
])
},
diff --git a/showcases/e2e/default.ts b/showcases/e2e/default.ts
index 04f93d7f287..24d21810f39 100644
--- a/showcases/e2e/default.ts
+++ b/showcases/e2e/default.ts
@@ -15,16 +15,21 @@ export const getDefaultScreenshotTest = (
testInfo.project.name === 'webkit' ||
testInfo.project.name === 'mobile_safari';
const showcase = process.env.showcase;
+ const diffPixel = process.env.diff;
+ const maxDiffPixelRatio = process.env.ratio;
const isAngular = showcase.startsWith('angular');
- const header = await page.locator('header');
+ const config: any = {};
- const config: any = {
- fullPage: true,
- mask: [header]
- };
+ if (maxDiffPixelRatio ?? diffPixel) {
+ if (maxDiffPixelRatio) {
+ config.maxDiffPixelRatio = Number(maxDiffPixelRatio);
+ }
- if (isAngular) {
+ if (diffPixel) {
+ config.maxDiffPixels = Number(diffPixel);
+ }
+ } else if (isAngular) {
config.maxDiffPixels = 1000;
} else if (isWebkit) {
config.maxDiffPixels = 120;
@@ -34,9 +39,24 @@ export const getDefaultScreenshotTest = (
await page.goto(
`./#/${path}?density=${density}&color=${color}`,
- { waitUntil: 'networkidle' }
+ { waitUntil: 'domcontentloaded' }
+ );
+
+ const dbPage = page.locator('.db-page');
+ await expect(dbPage).toHaveAttribute(
+ 'data-fonts-loaded',
+ 'true'
+ );
+ await expect(page.locator('html')).toHaveCSS(
+ 'overflow',
+ 'hidden'
);
await setScrollViewport(page, fixedHeight)();
+
+ const header = await page.locator('header');
+
+ config.mask = [header];
+
await expect(page).toHaveScreenshot(
[density, `${color}.png`],
config
diff --git a/showcases/e2e/fixtures/viewport.ts b/showcases/e2e/fixtures/viewport.ts
index d71cae693c4..e7a42dafcf2 100644
--- a/showcases/e2e/fixtures/viewport.ts
+++ b/showcases/e2e/fixtures/viewport.ts
@@ -1,19 +1,24 @@
-import type { Page } from '@playwright/test';
+import { expect, type Page } from '@playwright/test';
export const setScrollViewport = (page: Page, fixedHeight?: number) => {
return async () => {
const header = await page.waitForSelector('.db-header');
const headerHeight: number = await header.evaluate((node) =>
- Number(node?.scrollHeight ?? node?.clientHeight ?? 72)
+ Number(node?.scrollHeight ?? 72)
);
const main = await page.waitForSelector('.db-main');
const mainHeight: number = await main.evaluate((node) =>
- Number(node?.scrollHeight ?? node?.clientHeight ?? 2500)
+ Number(node?.scrollHeight ?? 2500)
);
+ const width = page.viewportSize().width;
+ const height = fixedHeight ?? headerHeight + mainHeight;
+
await page.setViewportSize({
- width: page.viewportSize().width,
- height: fixedHeight ?? headerHeight + mainHeight
+ width,
+ height
});
+
+ await expect(page.viewportSize().height).toEqual(height);
};
};
diff --git a/showcases/e2e/switch/showcase-switch.spec.ts b/showcases/e2e/switch/showcase-switch.spec.ts
new file mode 100644
index 00000000000..1a1dcd7fd91
--- /dev/null
+++ b/showcases/e2e/switch/showcase-switch.spec.ts
@@ -0,0 +1,7 @@
+import { test } from '@playwright/test';
+// @ts-expect-error - required for playwright
+import { getDefaultScreenshotTest } from '../default.ts';
+
+test.describe('DBSwitch', () => {
+ getDefaultScreenshotTest('03/switch');
+});
diff --git a/showcases/patternhub/components/component-parser/data.ts b/showcases/patternhub/components/component-parser/data.ts
index 4cde4fe53c2..94fbd1fda24 100644
--- a/showcases/patternhub/components/component-parser/data.ts
+++ b/showcases/patternhub/components/component-parser/data.ts
@@ -5,7 +5,8 @@ export type ComponentParserType = {
export type ComponentType = {
index?: string | number;
type?: /* Template hygen type */
- | 'tab-panel'
+ | 'switch'
+ | 'tab-panel'
| 'tabs'
| 'tab-list'
| 'tab'
diff --git a/showcases/patternhub/components/component-parser/index.tsx b/showcases/patternhub/components/component-parser/index.tsx
index 01cc50c9311..0753ed4f3c5 100644
--- a/showcases/patternhub/components/component-parser/index.tsx
+++ b/showcases/patternhub/components/component-parser/index.tsx
@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react';
+import DBSwitch from '../src/components/switch/switch';
import DBTabPanel from '../src/components/tab-panel/tab-panel';
import DBTabs from '../src/components/tabs/tabs';
import DBTabList from '../src/components/tab-list/tab-list';
@@ -321,6 +322,14 @@ const ComponentSwitch = ({
);
}
+ if (type === 'switch') {
+ return (
+
+ {resolvedContent}
+
+ );
+ }
+
// Template hygen before
return {resolvedContent};
diff --git a/showcases/patternhub/components/default-page.tsx b/showcases/patternhub/components/default-page.tsx
index c1624092bfc..92b0049b124 100644
--- a/showcases/patternhub/components/default-page.tsx
+++ b/showcases/patternhub/components/default-page.tsx
@@ -77,7 +77,7 @@ const DefaultPage = ({ children }: any) => {
{router.isReady && !fullscreen && (
{
{colorScheme2}
{
setColorScheme2(
colorScheme2 === 'light' ? 'dark' : 'light'
diff --git a/showcases/patternhub/styles/globals.scss b/showcases/patternhub/styles/globals.scss
index 5af9a5ef54a..cac27b36469 100644
--- a/showcases/patternhub/styles/globals.scss
+++ b/showcases/patternhub/styles/globals.scss
@@ -224,7 +224,7 @@ div[class^="ch-"] {
}
%spacing {
- @extend %db-successful-component;
+ @extend %db-successful-contrast-high;
height: 100%;
display: flex;
justify-content: center;
@@ -301,7 +301,7 @@ div[class^="ch-"] {
.sizing {
@extend %spacing;
- @extend %db-warning-component;
+ @extend %db-warning-contrast-high;
position: unset;
block-size: variables.$db-sizing-md;
inline-size: variables.$db-sizing-md;
diff --git a/showcases/playwright.config.ts b/showcases/playwright.config.ts
index 81b14786599..15fdd76be16 100644
--- a/showcases/playwright.config.ts
+++ b/showcases/playwright.config.ts
@@ -37,7 +37,10 @@ const config: PlaywrightTestConfig = {
baseURL: `http://localhost:8080/${process.env.showcase}/`,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
- trace: process.env.CI ? 'on-first-retry' : 'on'
+ trace: process.env.CI ? 'on-first-retry' : 'on',
+
+ /* Collect video when retrying the failed test. */
+ video: process.env.CI ? 'on-first-retry' : 'on'
},
webServer: {
command: `cd ${process.env.showcase} && npm run preview`,
@@ -72,13 +75,16 @@ const config: PlaywrightTestConfig = {
{
name: 'mobile_chrome',
use: {
- ...devices['Pixel 5']
+ ...devices['Pixel 5'],
+ isMobile: true
}
},
{
name: 'mobile_safari',
use: {
- ...devices['iPhone 12']
+ ...devices['iPhone 12'],
+ isMobile: true,
+ deviceScaleFactor: 2
}
}
],
diff --git a/showcases/react-showcase/package.json b/showcases/react-showcase/package.json
index 17ad060ffc4..d4230d00cda 100644
--- a/showcases/react-showcase/package.json
+++ b/showcases/react-showcase/package.json
@@ -14,16 +14,16 @@
"test:e2e": "cross-env showcase=react-showcase npx playwright test --config=../playwright.config.ts"
},
"dependencies": {
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-router-dom": "6.22.3"
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "react-router-dom": "6.23.0"
},
"devDependencies": {
- "@types/react": "^18.2.79",
- "@types/react-dom": "^18.2.25",
+ "@types/react": "^18.3.1",
+ "@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.2.1",
"cross-env": "^7.0.3",
"typescript": "^5.4.5",
- "vite": "^5.2.10"
+ "vite": "^5.2.11"
}
}
diff --git a/showcases/react-showcase/src/app.tsx b/showcases/react-showcase/src/app.tsx
index cb22952fb37..fdad920a072 100644
--- a/showcases/react-showcase/src/app.tsx
+++ b/showcases/react-showcase/src/app.tsx
@@ -21,7 +21,8 @@ const App = () => {
return (
(
+}: DBNavigationItemProps & { areaPopup: boolean }) => (
{
// eslint-disable-next-line no-alert
alert(children.toString());
diff --git a/showcases/react-showcase/src/components/page/index.tsx b/showcases/react-showcase/src/components/page/index.tsx
index da5a70b76a9..2b6d6e49e2e 100644
--- a/showcases/react-showcase/src/components/page/index.tsx
+++ b/showcases/react-showcase/src/components/page/index.tsx
@@ -13,7 +13,7 @@ import { getVariants } from '../data';
import DefaultComponent from '../index';
const getPage = ({
- type,
+ variant,
fadeIn,
children,
className,
@@ -22,7 +22,7 @@ const getPage = ({
key
}: DBPageProps) => (
(
+ <>
+
+ {children}
+
+ {variant === 'hidden' && (
+
+ {children}
+
+ )}
+ >
+);
+
+const SwitchComponent = () => {
+ return (
+
+ );
+};
+
+export default SwitchComponent;
diff --git a/showcases/react-showcase/src/utils/navigation-item.tsx b/showcases/react-showcase/src/utils/navigation-item.tsx
index 7b356f8125a..af47c8ac1b6 100644
--- a/showcases/react-showcase/src/utils/navigation-item.tsx
+++ b/showcases/react-showcase/src/utils/navigation-item.tsx
@@ -1,3 +1,4 @@
+import SwitchComponent from '../components/switch';
import TabsComponent from '../components/tabs';
import TabItemComponent from '../components/tab-item';
import TooltipComponent from '../components/tooltip';
@@ -128,6 +129,7 @@ export const NAVIGATION_ITEMS: NavigationItem[] = [
label: 'Checkbox',
component:
},
+ { path: 'switch', label: 'Switch', component: },
{ path: 'select', label: 'Select', component: }
])
},
diff --git a/showcases/shared/switch.json b/showcases/shared/switch.json
new file mode 100644
index 00000000000..bbadcea62a5
--- /dev/null
+++ b/showcases/shared/switch.json
@@ -0,0 +1,157 @@
+[
+ {
+ "name": "Density",
+ "examples": [
+ {
+ "name": "functional",
+ "className": "db-density-functional",
+ "props": {}
+ },
+ {
+ "name": "regular (Default)",
+ "className": "db-density-regular",
+ "props": {}
+ },
+ {
+ "name": "expressive",
+ "className": "db-density-expressive",
+ "props": {}
+ }
+ ]
+ },
+ {
+ "name": "States",
+ "examples": [
+ {
+ "name": "(Def) Enabled",
+ "props": {}
+ },
+ {
+ "name": "Checked",
+ "props": {
+ "checked": true
+ }
+ },
+ {
+ "name": "Disabled",
+ "props": {
+ "disabled": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "Emphasis",
+ "examples": [
+ {
+ "name": "(Def) Weak + unchecked",
+ "props": {
+ "emphasis": "weak"
+ }
+ },
+ {
+ "name": "Strong + unchecked",
+ "props": {
+ "emphasis": "strong"
+ }
+ },
+ {
+ "name": "(Def) Weak + checked",
+ "props": {
+ "emphasis": "weak",
+ "checked": true
+ }
+ },
+ {
+ "name": "Strong + checked",
+ "props": {
+ "emphasis": "strong",
+ "checked": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "Visual Aid",
+ "examples": [
+ {
+ "name": "(Def) No Visual Aid + unchecked",
+ "props": {
+ "visualAid": false
+ }
+ },
+ {
+ "name": "Visual Aid + unchecked",
+ "props": {
+ "visualAid": true
+ }
+ },
+ {
+ "name": "(Def) No Visual Aid + checked",
+ "props": {
+ "visualAid": false,
+ "checked": true
+ }
+ },
+ {
+ "name": "Visual Aid + checked",
+ "props": {
+ "visualAid": true,
+ "checked": true
+ }
+ }
+ ]
+ },
+ {
+ "name": "Size",
+ "examples": [
+ {
+ "name": "(Def) Medium",
+ "props": {}
+ },
+ {
+ "name": "Small",
+ "props": {
+ "size": "small"
+ }
+ }
+ ]
+ },
+ {
+ "name": "Content",
+ "examples": [
+ {
+ "name": "(Def) Label",
+ "props": {}
+ },
+ {
+ "name": "No Label",
+ "props": {
+ "variant": "hidden"
+ }
+ }
+ ]
+ },
+ {
+ "name": "Examples",
+ "examples": [
+ {
+ "name": "Custom Icons",
+ "props": {
+ "visualAid": true,
+ "icon": "night",
+ "iconAfter": "day"
+ }
+ },
+ {
+ "name": "Custom Icons+ Emphasis",
+ "props": {
+ "visualAid": true,
+ "icon": "lock_closed",
+ "iconAfter": "lock_open",
+ "emphasis": "strong"
+ }
+ }
+ ]
+ }
+]
diff --git a/showcases/showcase-styles.css b/showcases/showcase-styles.css
index 7117c8c3437..ceabcb96bde 100644
--- a/showcases/showcase-styles.css
+++ b/showcases/showcase-styles.css
@@ -136,3 +136,8 @@ db-card:is(.variants-card) > .db-card {
.db-page.fixed-header-footer main {
overflow-x: hidden;
}
+
+:root {
+ block-size: 100%;
+ overflow: hidden;
+}
diff --git a/showcases/vanilla-showcase/package.json b/showcases/vanilla-showcase/package.json
index 66102a2d30e..358a26bd316 100644
--- a/showcases/vanilla-showcase/package.json
+++ b/showcases/vanilla-showcase/package.json
@@ -20,6 +20,6 @@
"devDependencies": {
"cpr": "3.0.1",
"npm-run-all": "4.1.5",
- "vite": "^5.2.10"
+ "vite": "^5.2.11"
}
}
diff --git a/showcases/vanilla-showcase/src/app-shell.js b/showcases/vanilla-showcase/src/app-shell.js
index 213c8cf2751..c88c06222f6 100644
--- a/showcases/vanilla-showcase/src/app-shell.js
+++ b/showcases/vanilla-showcase/src/app-shell.js
@@ -97,7 +97,7 @@ const getMetaNavigation = (mobile) => {
const getAppShell = (content) =>
`
-
+
-
+
-
+
diff --git a/showcases/vue-showcase/src/components/navigation-item/NavigationItem.vue b/showcases/vue-showcase/src/components/navigation-item/NavigationItem.vue
index 77bf403cfe2..2ca80399c0e 100644
--- a/showcases/vue-showcase/src/components/navigation-item/NavigationItem.vue
+++ b/showcases/vue-showcase/src/components/navigation-item/NavigationItem.vue
@@ -3,7 +3,7 @@ import DefaultComponent from "../DefaultComponent.vue";
import defaultComponentVariants from "../../../../shared/navigation-item.json";
import { DBNavigationItem } from "../../../../../output/vue/src";
-const log = (exampleName: string) => {
+const log = (exampleName?: string) => {
// eslint-disable-next-line no-alert
alert(exampleName);
};
diff --git a/showcases/vue-showcase/src/components/navigation/Navigation.vue b/showcases/vue-showcase/src/components/navigation/Navigation.vue
index 140a5f4f14d..1b2f51e3949 100644
--- a/showcases/vue-showcase/src/components/navigation/Navigation.vue
+++ b/showcases/vue-showcase/src/components/navigation/Navigation.vue
@@ -14,11 +14,11 @@ import { DBNavigation, DBNavigationItem } from "../../../../../output/vue/src";
Navi-Item 1
-
+
Sub-Navi-Item 1
-
+
Sub-Sub-Navi-Item 1
diff --git a/showcases/vue-showcase/src/components/switch/Switch.vue b/showcases/vue-showcase/src/components/switch/Switch.vue
new file mode 100644
index 00000000000..d1826f93d14
--- /dev/null
+++ b/showcases/vue-showcase/src/components/switch/Switch.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ {{ exampleName }}
+
+
+ {{ exampleName }}
+
+
+
+
diff --git a/showcases/vue-showcase/src/utils/navigation-items.ts b/showcases/vue-showcase/src/utils/navigation-items.ts
index 4a0c66090ab..b3bc5e90f8b 100644
--- a/showcases/vue-showcase/src/utils/navigation-items.ts
+++ b/showcases/vue-showcase/src/utils/navigation-items.ts
@@ -1,4 +1,5 @@
import type { RouteRecordRaw } from 'vue-router';
+import Switch from '../components/switch/Switch.vue';
import Tabs from '../components/tabs/Tabs.vue';
import TabItem from '../components/tab-item/TabItem.vue';
import Tooltip from '../components/tooltip/Tooltip.vue';
@@ -113,6 +114,7 @@ export const navigationItems: NavItem[] = [
label: 'Checkbox',
component: Checkbox
},
+ { path: '/03/switch', label: 'Switch', component: Switch },
{ path: '/03/select', label: 'Select', component: Select }
])
},