Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(components): post-language-switch web component #4044

Merged
merged 31 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9100dd4
create web component
leagrdv Nov 1, 2024
d6c4f7f
Merge branch 'main' into 3633-component-language-switch
leagrdv Nov 13, 2024
4fa3087
add story and connect to language-option
leagrdv Nov 13, 2024
6ba7241
wip add post-menu
leagrdv Nov 13, 2024
848a2c7
wip language switch
leagrdv Nov 14, 2024
f5fc61a
wip language switch, set web components in post-language-option-switch
leagrdv Nov 15, 2024
d679f5d
Merge branch 'main' into 3633-component-language-switch
leagrdv Nov 18, 2024
b16b764
fix switch between types + start styling
leagrdv Nov 19, 2024
2b9c7fb
Merge branch 'main' into 3633-component-language-switch
leagrdv Nov 20, 2024
79cb196
finish design of post-language-option-switch + links
leagrdv Nov 21, 2024
62c034b
Add changeset and fix tests
leagrdv Nov 21, 2024
0f3601d
add tests
leagrdv Nov 21, 2024
7b57d13
Merge branch 'main' into 3633-component-language-switch
leagrdv Nov 21, 2024
fa71f9e
Merge branch 'main' into 3633-component-language-switch
leagrdv Nov 29, 2024
d0529b3
update snapshot with schemes
leagrdv Nov 29, 2024
2828efd
rename ID
leagrdv Nov 29, 2024
f564157
Merge branch 'main' into 3633-component-language-switch
leagrdv Dec 4, 2024
57d4026
proposal for a new internal structure
gfellerph Dec 4, 2024
6120984
Merge branch 'main' into 3633-component-language-switch
leagrdv Dec 5, 2024
66dc8cb
rename post-language-switch to post-language-switch-2 and post-langua…
leagrdv Dec 5, 2024
03c02dc
add styling
leagrdv Dec 5, 2024
b340b17
fix markup issue + add pointer
leagrdv Dec 5, 2024
3e70518
Merge branch 'main' into 3633-component-language-switch
leagrdv Dec 6, 2024
dd011a7
fix code smells
leagrdv Dec 6, 2024
cefc0bf
update language switch, delete unused code, dynamically set variant a…
leagrdv Dec 6, 2024
e897f77
Merge branch 'main' into 3633-component-language-switch
gfellerph Dec 9, 2024
3826d13
chore: update header sample markup (#4185)
gfellerph Dec 10, 2024
22ff9a9
Merge branch 'main' into 3633-component-language-switch
leagrdv Dec 10, 2024
84c761b
Merge branch 'main' into 3633-component-language-switch
leagrdv Dec 10, 2024
fe0265d
remove generated prop
gfellerph Dec 11, 2024
c15960d
remove name prop and use nanoid
gfellerph Dec 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading