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(component): post-tooltip refactor to improve structure, accessibility, and performance #4477

Open
wants to merge 56 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
a605132
feat(styles): added pop-in animation for post-popovercontainer
alionazherdetska Jan 20, 2025
f9542cd
fix(styles): fixed max-width and min-height for post-tooltip
alionazherdetska Jan 20, 2025
479d547
feat(component): added animation and refactored methods
alionazherdetska Jan 20, 2025
30a82c5
chore(stories): added the animation control to the tooltip-stories
alionazherdetska Jan 21, 2025
534467f
feat(component): refactored post-tooltip component, added the animation
alionazherdetska Jan 21, 2025
dc9239d
chore(component): refactored the commets for post-tooltip, added the …
alionazherdetska Jan 21, 2025
a8a98cf
deat(component): introduced the new `post-tooltip-trigger` component
alionazherdetska Jan 21, 2025
95f7b35
fix(docs): refactored the controls for the docs for 'post-tooltip'
alionazherdetska Jan 21, 2025
3f14297
chore(component): removed redundant stylesheet
alionazherdetska Jan 21, 2025
0c62bee
chore: autogenerated files
alionazherdetska Jan 21, 2025
0fc563e
fix(linting): removed redundant spacing
alionazherdetska Jan 21, 2025
576d6d0
fix(linting): removed redundant console.log
alionazherdetska Jan 22, 2025
128752a
chore(changeset): changesets were added
alionazherdetska Jan 22, 2025
83bdc91
chore(animation): added the comments for the progressive animation
alionazherdetska Jan 22, 2025
fbd30e4
fix(tests): fixed tests for `post-tooltip` component
alionazherdetska Jan 22, 2025
19d1da5
chore(component): replaced the old tooltip structure with a new one
alionazherdetska Jan 22, 2025
3d2a273
chore(styles): added display for `<post-tooltip-trigger>`
alionazherdetska Jan 23, 2025
980dfd8
chore(component): adjusted `popovercontainer` and its styles to be ab…
alionazherdetska Feb 11, 2025
fbea70f
Merge branch 'main' into tooltip
alionazherdetska Feb 11, 2025
0b8f76f
chore: autogenerated files
alionazherdetska Feb 11, 2025
1491814
Merge branch 'main' into tooltip
alionazherdetska Feb 28, 2025
b01f945
chore: reafactored validation
alionazherdetska Feb 28, 2025
8e41d98
fix: sonar-fix
alionazherdetska Feb 28, 2025
b2d2109
reverted changes
alionazherdetska Feb 28, 2025
602818a
Chore(component): exported postTooltipTrigger
alionazherdetska Feb 28, 2025
00ca31f
fix(test): refactored e2e tests
alionazherdetska Feb 28, 2025
5cfcefe
fix(test): refactored e2e tests
alionazherdetska Feb 28, 2025
24c3413
fix(test): refactored e2e tests
alionazherdetska Feb 28, 2025
64c31ed
fix(component): fixed delay
alionazherdetska Feb 28, 2025
f2d9643
fix: refactored tooltip-trigger
alionazherdetska Feb 28, 2025
039ad49
fix: refactored the component
alionazherdetska Feb 28, 2025
ccc1735
updated component
alionazherdetska Feb 28, 2025
0c3976c
updated tests
alionazherdetska Feb 28, 2025
8364cd5
updated tests
alionazherdetska Feb 28, 2025
018e97e
test fix
alionazherdetska Mar 1, 2025
a718bd9
test fix
alionazherdetska Mar 1, 2025
6c262f7
test fix
alionazherdetska Mar 1, 2025
82aa29f
test fix
alionazherdetska Mar 1, 2025
cf92bfd
reverted test change
alionazherdetska Mar 3, 2025
8c87fd5
test fix
alionazherdetska Mar 3, 2025
578c650
Merge branch 'main' into tooltip
alionazherdetska Mar 3, 2025
ecfbaae
chore(tests): addded new tests for `post-tooltip`
alionazherdetska Mar 3, 2025
31adcb7
chore: added a delay to `post-tooltip`
alionazherdetska Mar 4, 2025
157996c
set up for test
alionazherdetska Mar 4, 2025
24e24fd
reverted changes
alionazherdetska Mar 4, 2025
ea2ba29
adjusted the tests
alionazherdetska Mar 4, 2025
597cbe3
removed redundant comments
alionazherdetska Mar 5, 2025
786f1b3
fix: fixed the animation for the popovercontainer
alionazherdetska Mar 5, 2025
ef11c31
fix: remove redundant code
alionazherdetska Mar 5, 2025
4c80891
fix: improved the code style
alionazherdetska Mar 5, 2025
7ff8df0
fix: adjusted the animation
alionazherdetska Mar 5, 2025
84797be
refactored the component
alionazherdetska Mar 5, 2025
4dcef5b
fix: linting
alionazherdetska Mar 5, 2025
412565f
Merge branch 'main' into tooltip
alionazherdetska Mar 5, 2025
96c0e11
fixed the docs
alionazherdetska Mar 5, 2025
2b3e199
Merge branch 'tooltip' of https://github.com/swisspost/design-system …
alionazherdetska Mar 5, 2025
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
5 changes: 5 additions & 0 deletions .changeset/strong-actors-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-components': major
---

The trigger for <post-tooltip> has been updated. Rather than using an attribute to associate a trigger element with the tooltip, a new <post-tooltip-trigger> element now wraps the target element to display the tooltip.
7 changes: 7 additions & 0 deletions .changeset/tiny-frogs-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@swisspost/design-system-documentation': patch
'@swisspost/design-system-components': patch
'@swisspost/design-system-styles': patch
---

The default value of the arrow property for the <post-tooltip> element has been changed to false.
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ <h2>Post Tag</h2>

<div class="my-24">
<h2>Post Tooltip</h2>
<button class="btn btn-secondary btn-large" data-tooltip-target="tooltip-one">Button</button>
<post-tooltip id="tooltip-one" placement="top">Hi there 👋</post-tooltip>
<post-tooltip-trigger for="tooltip-one">
<button class="btn btn-secondary btn-large">Button</button>
</post-tooltip-trigger>
</div>
75 changes: 60 additions & 15 deletions packages/components/cypress/e2e/tooltip.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe('tooltips', { baseUrl: null, includeShadowDom: true }, () => {
cy.get('#target1').as('target1');
cy.get('#target2').as('target2');
cy.get('#tooltip-one').find('post-popovercontainer[popover]').as('tooltip');
cy.get('post-tooltip-trigger[for="tooltip-one"]').as('trigger');
});

it('should display a tooltip', () => {
Expand All @@ -30,22 +31,63 @@ describe('tooltips', { baseUrl: null, includeShadowDom: true }, () => {
});
});

it('should append aria-describedby without deleting existing values', () => {
cy.get('@target1')
.should('have.attr', 'aria-describedby')
.should('eq', 'existing-value tooltip-one');
});

it('should patch aria after button has been inserted', () => {
it('should patch aria after trigger is inserted', () => {
cy.document().then(doc => {
const btn = doc.createElement('span');
btn.setAttribute('data-tooltip-target', 'tooltip-one');
btn.innerHTML = 'added after the fact';
const trigger = doc.createElement('post-tooltip-trigger');
trigger.setAttribute('for', 'tooltip-one');

const btn = doc.createElement('button');
btn.id = 'added-later';
doc.body.appendChild(btn);
btn.textContent = 'added after the fact';

trigger.appendChild(btn);
doc.body.appendChild(trigger);
});

cy.get('#added-later')
.should('exist')
.and('have.attr', 'aria-describedby', 'tooltip-one');
});

describe('trigger behavior', () => {
it('should initialize trigger with correct attributes', () => {
cy.get('@trigger').first().within(() => {
cy.get('button')
.should('have.attr', 'aria-describedby')
.then((ariaDescribedBy) => {
expect(ariaDescribedBy).to.include('tooltip-one');
});
});
});

it('should show tooltip on trigger hover', () => {
cy.get('@tooltip').should('not.be.visible');
cy.get('@trigger').first().trigger('pointerenter');
cy.wait(100);
cy.get('.\\:popover-open, :popover-open').should('exist');
});

it('should hide tooltip on trigger pointerout', () => {
cy.get('@trigger').first().trigger('pointerenter');
cy.wait(100);
cy.get('.\\:popover-open, :popover-open').should('exist');
cy.get('@trigger').first().trigger('pointerleave');
cy.wait(100);
cy.get('@tooltip').should('not.be.visible');
});

it('should show tooltip on trigger focus', () => {
cy.get('@tooltip').should('not.be.visible');
cy.get('@trigger').first().find('button').focus();
cy.get('.\\:popover-open, :popover-open').should('exist');
});

it('should hide tooltip on trigger blur', () => {
cy.get('@trigger').first().find('button').focus();
cy.get('.\\:popover-open, :popover-open').should('exist');
cy.get('@trigger').first().find('button').blur();
cy.get('@tooltip').should('not.be.visible');
});
cy.get('#added-later').should('have.attr', 'aria-describedby').should('eq', 'tooltip-one');
cy.get('#added-later').should('have.attr', 'tabindex').should('eq', '0');
});
});

Expand All @@ -59,7 +101,8 @@ describe('tooltips', { baseUrl: null, includeShadowDom: true }, () => {

it('should show tooltip on hovered child element', () => {
cy.get('@tooltip').should('not.be.visible');
cy.get('@target-child').trigger('pointerover');
cy.get('@target-child').trigger('pointerenter');
cy.wait(100);
cy.get('.\\:popover-open, :popover-open').should('exist');
});
});
Expand All @@ -71,7 +114,9 @@ describe('tooltips', { baseUrl: null, includeShadowDom: true }, () => {
});

it('should add tabindex', () => {
cy.get('@target').should('have.attr', 'tabindex').should('eq', '0');
cy.get('@target')
.should('have.attr', 'tabindex')
.and('eq', '0');
});
});

Expand Down
26 changes: 13 additions & 13 deletions packages/components/cypress/fixtures/post-tooltip.test.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
<script src="../../dist/post-components/post-components.esm.js" type="module"></script>
</head>
<body>
<button aria-describedby="existing-value" data-tooltip-target="tooltip-one" id="target1">
toggle
</button>
<button data-tooltip-target="tooltip-one" id="target2">
toggle 2 <span>child element</span>
</button>
<button data-tooltip-target="tooltip-one" id="target-child-element">
toggle with <span>child element</span>
</button>
<post-tooltip id="tooltip-one">
<p>This is a test</p>
</post-tooltip>
<span id="non-focusable-span" data-tooltip-target="tooltip-one">non-focusable</span>
<post-tooltip-trigger for="tooltip-one">
<button aria-describedby="existing-value" id="target1">toggle</button>
</post-tooltip-trigger>
<post-tooltip-trigger for="tooltip-one">
<button id="target2">toggle 2 <span>child element</span></button>
</post-tooltip-trigger>
<post-tooltip-trigger for="tooltip-one">
<button id="target-child-element">toggle with <span>child element</span></button>
</post-tooltip-trigger>
<post-tooltip id="tooltip-one">This is a test</post-tooltip>
<post-tooltip-trigger for="tooltip-one"
><span id="non-focusable-span">non-focusable</span></post-tooltip-trigger
>
</body>
</html>
92 changes: 68 additions & 24 deletions packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,38 +374,42 @@ export namespace Components {
"toggle": (target: HTMLElement, force?: boolean) => Promise<void>;
}
interface PostPopovercontainer {
/**
* Animation style
*/
"animation"?: 'pop-in';
/**
* Whether or not to display a little pointer arrow
*/
"arrow"?: boolean;
/**
* Gap between the edge of the page and the popover
* Gap between the edge of the page and the popovercontainer
*/
"edgeGap"?: number;
/**
* Programmatically hide this tooltip
* Programmatically hide the popovercontainer
*/
"hide": () => Promise<void>;
/**
* Whether or not the popover should close when user clicks outside of it
*/
"manualClose": boolean;
/**
* Defines the placement of the tooltip according to the floating-ui options available at https://floating-ui.com/docs/computePosition#placement. Tooltips are automatically flipped to the opposite side if there is not enough available space and are shifted towards the viewport if they would overlap edge boundaries.
* Defines the placement of the popovercontainer according to the floating-ui options available at https://floating-ui.com/docs/computePosition#placement. Popovercontainers are automatically flipped to the opposite side if there is not enough available space and are shifted towards the viewport if they would overlap edge boundaries.
*/
"placement"?: Placement;
/**
* Enables a safespace through which the cursor can be moved without the popover being disabled
*/
"safeSpace"?: 'triangle' | 'trapezoid';
/**
* Programmatically display the tooltip
* @param target An element with [data-tooltip-target="id"] where the tooltip should be shown
* Programmatically display the popovercontainer
* @param target An element with [data-popover-target="id"] where the popovercontainer should be shown
*/
"show": (target: HTMLElement) => Promise<void>;
/**
* Toggle tooltip display
* @param target An element with [data-tooltip-target="id"] where the tooltip should be shown
* Toggle popovercontainer display
* @param target An element with [data-popover-target="id"] where the popovercontainer should be shown
* @param force Pass true to always show or false to always hide
*/
"toggle": (target: HTMLElement, force?: boolean) => Promise<boolean>;
Expand Down Expand Up @@ -472,34 +476,47 @@ export namespace Components {
}
interface PostTooltip {
/**
* Wheter or not to display a little pointer arrow
* Choose a tooltip animation
*/
"arrow"?: boolean;
"animation"?: 'pop-in' | null;
/**
* If `true`, the tooltip is displayed a few milliseconds after it is triggered
* Whether or not to display a little pointer arrow
*/
"delayed": boolean;
"arrow"?: boolean;
/**
* Programmatically hide this tooltip
* Programmatically hide this tooltip.
*/
"hide": () => Promise<void>;
/**
* Indicates the open state of the tooltip
*/
"open": boolean;
/**
* Defines the placement of the tooltip according to the floating-ui options available at https://floating-ui.com/docs/computePosition#placement. Tooltips are automatically flipped to the opposite side if there is not enough available space and are shifted towards the viewport if they would overlap edge boundaries.
*/
"placement"?: Placement;
/**
* Programmatically display the tooltip
* @param target An element with [data-tooltip-target="id"] where the tooltip should be shown
* @param triggeredByFocus A boolean indicating if the tooltip was triggered by a focus event.
* Programmatically display the tooltip.
* @param target An element where the tooltip should be shown
*/
"show": (target: HTMLElement, triggeredByFocus?: boolean) => Promise<void>;
"show": (target: HTMLElement) => Promise<void>;
/**
* Toggle tooltip display
* @param target An element with [data-tooltip-target="id"] where the tooltip should be shown
* Toggle tooltip display.
* @param target An element where the tooltip should be shown
* @param force Pass true to always show or false to always hide
*/
"toggle": (target: HTMLElement, force?: boolean) => Promise<void>;
}
interface PostTooltipTrigger {
/**
* Delay (in milliseconds) before the tooltip is shown.
*/
"delay": number;
/**
* ID of the tooltip element that this trigger is linked to.
*/
"for": string;
}
}
export interface PostBannerCustomEvent<T> extends CustomEvent<T> {
detail: T;
Expand Down Expand Up @@ -871,6 +888,12 @@ declare global {
prototype: HTMLPostTooltipElement;
new (): HTMLPostTooltipElement;
};
interface HTMLPostTooltipTriggerElement extends Components.PostTooltipTrigger, HTMLStencilElement {
}
var HTMLPostTooltipTriggerElement: {
prototype: HTMLPostTooltipTriggerElement;
new (): HTMLPostTooltipTriggerElement;
};
interface HTMLElementTagNameMap {
"post-accordion": HTMLPostAccordionElement;
"post-accordion-item": HTMLPostAccordionItemElement;
Expand Down Expand Up @@ -907,6 +930,7 @@ declare global {
"post-tag": HTMLPostTagElement;
"post-togglebutton": HTMLPostTogglebuttonElement;
"post-tooltip": HTMLPostTooltipElement;
"post-tooltip-trigger": HTMLPostTooltipTriggerElement;
}
}
declare namespace LocalJSX {
Expand Down Expand Up @@ -1216,24 +1240,28 @@ declare namespace LocalJSX {
"placement"?: Placement;
}
interface PostPopovercontainer {
/**
* Animation style
*/
"animation"?: 'pop-in';
/**
* Whether or not to display a little pointer arrow
*/
"arrow"?: boolean;
/**
* Gap between the edge of the page and the popover
* Gap between the edge of the page and the popovercontainer
*/
"edgeGap"?: number;
/**
* Whether or not the popover should close when user clicks outside of it
*/
"manualClose"?: boolean;
/**
* Fires whenever the popover gets shown or hidden, passing the new state in event.details as a boolean
* Fires whenever the popovercontainer gets shown or hidden, passing the new state in event.details as a boolean
*/
"onPostToggle"?: (event: PostPopovercontainerCustomEvent<boolean>) => void;
/**
* Defines the placement of the tooltip according to the floating-ui options available at https://floating-ui.com/docs/computePosition#placement. Tooltips are automatically flipped to the opposite side if there is not enough available space and are shifted towards the viewport if they would overlap edge boundaries.
* Defines the placement of the popovercontainer according to the floating-ui options available at https://floating-ui.com/docs/computePosition#placement. Popovercontainers are automatically flipped to the opposite side if there is not enough available space and are shifted towards the viewport if they would overlap edge boundaries.
*/
"placement"?: Placement;
/**
Expand Down Expand Up @@ -1311,18 +1339,32 @@ declare namespace LocalJSX {
}
interface PostTooltip {
/**
* Wheter or not to display a little pointer arrow
* Choose a tooltip animation
*/
"animation"?: 'pop-in' | null;
/**
* Whether or not to display a little pointer arrow
*/
"arrow"?: boolean;
/**
* If `true`, the tooltip is displayed a few milliseconds after it is triggered
* Indicates the open state of the tooltip
*/
"delayed"?: boolean;
"open"?: boolean;
/**
* Defines the placement of the tooltip according to the floating-ui options available at https://floating-ui.com/docs/computePosition#placement. Tooltips are automatically flipped to the opposite side if there is not enough available space and are shifted towards the viewport if they would overlap edge boundaries.
*/
"placement"?: Placement;
}
interface PostTooltipTrigger {
/**
* Delay (in milliseconds) before the tooltip is shown.
*/
"delay"?: number;
/**
* ID of the tooltip element that this trigger is linked to.
*/
"for": string;
}
interface IntrinsicElements {
"post-accordion": PostAccordion;
"post-accordion-item": PostAccordionItem;
Expand Down Expand Up @@ -1359,6 +1401,7 @@ declare namespace LocalJSX {
"post-tag": PostTag;
"post-togglebutton": PostTogglebutton;
"post-tooltip": PostTooltip;
"post-tooltip-trigger": PostTooltipTrigger;
}
}
export { LocalJSX as JSX };
Expand Down Expand Up @@ -1406,6 +1449,7 @@ declare module "@stencil/core" {
"post-tag": LocalJSX.PostTag & JSXBase.HTMLAttributes<HTMLPostTagElement>;
"post-togglebutton": LocalJSX.PostTogglebutton & JSXBase.HTMLAttributes<HTMLPostTogglebuttonElement>;
"post-tooltip": LocalJSX.PostTooltip & JSXBase.HTMLAttributes<HTMLPostTooltipElement>;
"post-tooltip-trigger": LocalJSX.PostTooltipTrigger & JSXBase.HTMLAttributes<HTMLPostTooltipTriggerElement>;
}
}
}
Loading