Skip to content

Commit

Permalink
feat(components): post-language-switch web component (#4044)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Gfeller <[email protected]>
  • Loading branch information
leagrdv and gfellerph authored Dec 11, 2024
1 parent 456317c commit 6c79d1c
Show file tree
Hide file tree
Showing 34 changed files with 662 additions and 106 deletions.
6 changes: 6 additions & 0 deletions .changeset/yellow-gifts-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@swisspost/design-system-documentation': minor
'@swisspost/design-system-components': minor
---

Added the `post-language-switch` component that enables users to change the language of a page.
5 changes: 3 additions & 2 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@
"dependencies": {
"@floating-ui/dom": "1.6.8",
"@oddbird/popover-polyfill": "0.3.7",
"@swisspost/design-system-styles": "workspace:9.0.0-next.8",
"@swisspost/design-system-icons": "workspace:9.0.0-next.8",
"@swisspost/design-system-styles": "workspace:9.0.0-next.8",
"ally.js": "1.4.1",
"long-press-event": "2.5.0"
"long-press-event": "2.5.0",
"nanoid": "5.0.9"
},
"devDependencies": {
"@percy/cli": "1.29.1",
Expand Down
63 changes: 63 additions & 0 deletions packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { HeadingLevel } from "./types/index";
import { BannerType } from "./components/post-banner/banner-types";
import { SwitchVariant } from "./components/post-language-switch/switch-variants";
import { Placement } from "@floating-ui/dom";
export { HeadingLevel } from "./types/index";
export { BannerType } from "./components/post-banner/banner-types";
export { SwitchVariant } from "./components/post-language-switch/switch-variants";
export { Placement } from "@floating-ui/dom";
export namespace Components {
interface PostAccordion {
Expand Down Expand Up @@ -216,6 +218,10 @@ export namespace Components {
* The ISO 639 language code, formatted according to [RFC 5646 (also known as BCP 47)](https://datatracker.ietf.org/doc/html/rfc5646). For example, "de".
*/
"code": string;
/**
* Used on parent component (post-language-switch) to detect elements that are manually added
*/
"generated": boolean;
/**
* The full name of the language. For example, "Deutsch".
*/
Expand All @@ -228,6 +234,28 @@ export namespace Components {
* The URL used for the href attribute of the internal anchor. This field is optional; if not provided, a button will be used internally instead of an anchor.
*/
"url": string;
/**
* The variant of the post-language-switch parent (dynamically set by the parent)
*/
"variant"?: SwitchVariant | null;
}
interface PostLanguageSwitch {
/**
* A title for the list of language options
*/
"caption": string;
/**
* A descriptive text for the list of language options
*/
"description": string;
/**
* The name of the language switch, which will be used on the dropdown as an ID
*/
"name": string;
/**
* Variant that determines the rendering of the language switch either as a list (used on mobile in the header) or a dropdown (used on desktop in the header)
*/
"variant": SwitchVariant;
}
interface PostList {
/**
Expand Down Expand Up @@ -617,6 +645,12 @@ declare global {
prototype: HTMLPostLanguageOptionElement;
new (): HTMLPostLanguageOptionElement;
};
interface HTMLPostLanguageSwitchElement extends Components.PostLanguageSwitch, HTMLStencilElement {
}
var HTMLPostLanguageSwitchElement: {
prototype: HTMLPostLanguageSwitchElement;
new (): HTMLPostLanguageSwitchElement;
};
interface HTMLPostListElement extends Components.PostList, HTMLStencilElement {
}
var HTMLPostListElement: {
Expand Down Expand Up @@ -806,6 +840,7 @@ declare global {
"post-header": HTMLPostHeaderElement;
"post-icon": HTMLPostIconElement;
"post-language-option": HTMLPostLanguageOptionElement;
"post-language-switch": HTMLPostLanguageSwitchElement;
"post-list": HTMLPostListElement;
"post-list-item": HTMLPostListItemElement;
"post-logo": HTMLPostLogoElement;
Expand Down Expand Up @@ -1011,6 +1046,10 @@ declare namespace LocalJSX {
* The ISO 639 language code, formatted according to [RFC 5646 (also known as BCP 47)](https://datatracker.ietf.org/doc/html/rfc5646). For example, "de".
*/
"code": string;
/**
* Used on parent component (post-language-switch) to detect elements that are manually added
*/
"generated"?: boolean;
/**
* The full name of the language. For example, "Deutsch".
*/
Expand All @@ -1023,6 +1062,28 @@ declare namespace LocalJSX {
* The URL used for the href attribute of the internal anchor. This field is optional; if not provided, a button will be used internally instead of an anchor.
*/
"url"?: string;
/**
* The variant of the post-language-switch parent (dynamically set by the parent)
*/
"variant"?: SwitchVariant | null;
}
interface PostLanguageSwitch {
/**
* A title for the list of language options
*/
"caption"?: string;
/**
* A descriptive text for the list of language options
*/
"description"?: string;
/**
* The name of the language switch, which will be used on the dropdown as an ID
*/
"name"?: string;
/**
* Variant that determines the rendering of the language switch either as a list (used on mobile in the header) or a dropdown (used on desktop in the header)
*/
"variant"?: SwitchVariant;
}
interface PostList {
/**
Expand Down Expand Up @@ -1202,6 +1263,7 @@ declare namespace LocalJSX {
"post-header": PostHeader;
"post-icon": PostIcon;
"post-language-option": PostLanguageOption;
"post-language-switch": PostLanguageSwitch;
"post-list": PostList;
"post-list-item": PostListItem;
"post-logo": PostLogo;
Expand Down Expand Up @@ -1245,6 +1307,7 @@ declare module "@stencil/core" {
*/
"post-icon": LocalJSX.PostIcon & JSXBase.HTMLAttributes<HTMLPostIconElement>;
"post-language-option": LocalJSX.PostLanguageOption & JSXBase.HTMLAttributes<HTMLPostLanguageOptionElement>;
"post-language-switch": LocalJSX.PostLanguageSwitch & JSXBase.HTMLAttributes<HTMLPostLanguageSwitchElement>;
"post-list": LocalJSX.PostList & JSXBase.HTMLAttributes<HTMLPostListElement>;
"post-list-item": LocalJSX.PostListItem & JSXBase.HTMLAttributes<HTMLPostListItemElement>;
"post-logo": LocalJSX.PostLogo & JSXBase.HTMLAttributes<HTMLPostLogoElement>;
Expand Down
27 changes: 23 additions & 4 deletions packages/components/src/components/post-header/post-header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Component, h, Host, State, Element, Listen } from '@stencil/core';
import { throttle } from 'throttle-debounce';
import { version } from '@root/package.json';
import { SwitchVariant } from '@/components';

type DEVICE_SIZE = 'mobile' | 'tablet' | 'desktop' | null;

@Component({
tag: 'post-header',
Expand All @@ -9,7 +12,7 @@ import { version } from '@root/package.json';
})
export class PostHeader {
@Element() host: HTMLPostHeaderElement;
@State() device: 'mobile' | 'tablet' | 'desktop' = null;
@State() device: DEVICE_SIZE = null;
@State() mobileMenuExtended: boolean = false;

private scrollParent = null;
Expand Down Expand Up @@ -67,17 +70,33 @@ export class PostHeader {
}

private handleResize() {
const previousDevice = this.device;
let newDevice: DEVICE_SIZE;
const width = window?.innerWidth;

if (width >= 1024) {
this.device = 'desktop';
newDevice = 'desktop';
this.mobileMenuExtended = false; // Close any open mobile menu
} else if (width >= 600) {
this.device = 'tablet';
newDevice = 'tablet';
} else {
this.device = 'mobile';
newDevice = 'mobile';
}

// Apply only on change for doing work only when necessary
if (newDevice !== previousDevice) {
this.device = newDevice;
window.requestAnimationFrame(() => {
this.switchLanguageSwitchMode();
});
}
}

private switchLanguageSwitchMode() {
const variant: SwitchVariant = this.device === 'desktop' ? 'dropdown' : 'list';
this.host.querySelector('post-language-switch')?.setAttribute('variant', variant);
}

private handleMobileMenuToggle() {
this.mobileMenuExtended = !this.mobileMenuExtended;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/components/src/components/post-icon/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ some content
- [post-breadcrumb-item](../post-breadcrumb-item)
- [post-card-control](../post-card-control)
- [post-closebutton](../post-closebutton)
- [post-language-switch](../post-language-switch)
- [post-rating](../post-rating)
- [post-tag](../post-tag)

Expand All @@ -40,6 +41,7 @@ graph TD;
post-breadcrumb-item --> post-icon
post-card-control --> post-icon
post-closebutton --> post-icon
post-language-switch --> post-icon
post-rating --> post-icon
post-tag --> post-icon
style post-icon fill:#f9f,stroke:#333,stroke-width:4px
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,42 @@ a {
width: 100%;
padding: var(--post-language-option-padding);
}

.post-language-option-list {
@include post.focus-style;
border-radius: 2px;
width: 40px;
height: 40px;

&[aria-current='true'],
&[aria-current='page'] {
background-color: #050400;
color: #fff;
}
}

.post-language-option-dropdown {
padding-block: 13px;
padding-inline: 24px;
box-sizing: border-box;
position: relative;

&[aria-current='true'],
&[aria-current='page'] {
&::after {
content: '';
left: -2px;
height: 3px;
background-color: #504f4b;
width: calc(100% + 4px);
display: block;
position: absolute;
bottom: 3px;
}

&:focus::after {
width: calc(100% - 5px);
left: 2px;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '@stencil/core';
import { checkEmptyOrType, checkType } from '@/utils';
import { version } from '@root/package.json';
import { SwitchVariant } from '../post-language-switch/switch-variants';

/**
* @slot default - Slot for placing the content inside the anchor or button.
Expand Down Expand Up @@ -51,6 +52,11 @@ export class PostLanguageOption {
);
}

/**
* The variant of the post-language-switch parent (dynamically set by the parent)
*/
@Prop() variant?: SwitchVariant | null;

/**
* The full name of the language. For example, "Deutsch".
*/
Expand Down Expand Up @@ -122,6 +128,7 @@ export class PostLanguageOption {
<Host data-version={version} role="listitem">
{this.url ? (
<a
class={this.variant ? `post-language-option-${this.variant}` : ''}
aria-current={this.active ? 'page' : undefined}
aria-label={this.name}
href={this.url}
Expand All @@ -133,6 +140,7 @@ export class PostLanguageOption {
</a>
) : (
<button
class={this.variant ? `post-language-option-${this.variant}` : ''}
aria-current={this.active ? 'true' : undefined}
aria-label={this.name}
lang={lang}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@

## Properties

| Property | Attribute | Description | Type | Default |
| ------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- |
| `active` | `active` | If set to `true`, the language option is considered the current language for the page. | `boolean` | `undefined` |
| `code` _(required)_ | `code` | The ISO 639 language code, formatted according to [RFC 5646 (also known as BCP 47)](https://datatracker.ietf.org/doc/html/rfc5646). For example, "de". | `string` | `undefined` |
| `name` | `name` | The full name of the language. For example, "Deutsch". | `string` | `undefined` |
| `url` | `url` | The URL used for the href attribute of the internal anchor. This field is optional; if not provided, a button will be used internally instead of an anchor. | `string` | `undefined` |
| Property | Attribute | Description | Type | Default |
| ------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ----------- |
| `active` | `active` | If set to `true`, the language option is considered the current language for the page. | `boolean` | `undefined` |
| `code` _(required)_ | `code` | The ISO 639 language code, formatted according to [RFC 5646 (also known as BCP 47)](https://datatracker.ietf.org/doc/html/rfc5646). For example, "de". | `string` | `undefined` |
| `generated` | `generated` | Used on parent component (post-language-switch) to detect elements that are manually added | `boolean` | `undefined` |
| `name` | `name` | The full name of the language. For example, "Deutsch". | `string` | `undefined` |
| `url` | `url` | The URL used for the href attribute of the internal anchor. This field is optional; if not provided, a button will be used internally instead of an anchor. | `string` | `undefined` |
| `variant` | `variant` | The variant of the post-language-switch parent (dynamically set by the parent) | `"dropdown" \| "list"` | `undefined` |


## Events
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@use '@swisspost/design-system-styles/tokens/components';
@use '@swisspost/design-system-styles/functions/tokens';
@use '@swisspost/design-system-styles/mixins/button' as button-mx;
@use '@swisspost/design-system-styles/mixins/utilities' as utilities-mx;

tokens.$default-map: components.$post-button;

:host {
display: block;
}

.post-language-switch-dropdown-container {
display: flex;
flex-direction: column;
}

.post-language-switch-trigger {
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
border-width: tokens.get('button-border-width');
border-radius: tokens.get('button-border-radius-round');
background-color: transparent;
font-family: inherit;
font-weight: tokens.get('button-label-font-weight');
@include button-mx.button-size(sm);

&:disabled {
border-style: tokens.get('button-border-style-disabled');
@include button-mx.button-variant-def('disabled', 'tertiary');
}

@include utilities-mx.focus-style;
@include button-mx.button-variant-def('enabled', 'tertiary');

@include utilities-mx.not-disabled-hover() {
@include button-mx.button-variant-def('hover', 'tertiary');
}
}
Loading

0 comments on commit 6c79d1c

Please sign in to comment.