Skip to content

Commit

Permalink
fix(components): replace the componentOnReady method by an helper
Browse files Browse the repository at this point in the history
  • Loading branch information
alizedebray committed Aug 14, 2024
1 parent e8460d8 commit 65eade9
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/serious-games-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-components': patch
---

Fixed the post-tabs component throwing an error when imported individually.
7 changes: 4 additions & 3 deletions packages/components/src/components/post-tabs/post-tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component, Element, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';
import { version } from '@root/package.json';
import { fadeIn, fadeOut } from '@/animations';
import { componentOnReady } from '@/utils';

/**
* @slot tabs - Slot for placing tab headers. Each tab header should be a <post-tab-header> element.
Expand Down Expand Up @@ -100,7 +101,7 @@ export class PostTabs {
if (!this.tabs) return;

this.tabs.forEach(async tab => {
await tab.componentOnReady();
await componentOnReady(tab);

// if the tab has an "aria-controls" attribute it was already linked to its panel: do nothing
if (tab.getAttribute('aria-controls')) return;
Expand All @@ -120,8 +121,8 @@ export class PostTabs {
}
});

tab.addEventListener('keydown', ({ key }) => {
if (key === 'ArrowRight' || key === 'ArrowLeft') this.navigateTabs(tab, key);
tab.addEventListener('keydown', (e: KeyboardEvent) => {
if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') this.navigateTabs(tab, e.key);
});
});

Expand Down
25 changes: 25 additions & 0 deletions packages/components/src/utils/component-on-ready.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { HostElement } from '@stencil/core/internal';

/**
* Invoke the `componentOnReady` method if it is available, simulate it otherwise
* @see https://stenciljs.com/docs/api#componentonready
*/
export const componentOnReady = <T extends HostElement>(el: T): Promise<T> => {
if (typeof el.componentOnReady === 'function') {
return el.componentOnReady();
} else {
return new Promise(resolve =>
customOnReady(() => {
resolve(el);
}),
);
}
};

const customOnReady = (callback: FrameRequestCallback) => {
if (typeof requestAnimationFrame === 'function') {
return requestAnimationFrame(callback);
}

return setTimeout(callback);
};
1 change: 1 addition & 0 deletions packages/components/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './component-on-ready';
export * from './property-checkers';
export * from './debounce';
export * from './get-root';
Expand Down
51 changes: 51 additions & 0 deletions packages/components/src/utils/tests/component-on-ready.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { componentOnReady } from '../component-on-ready';
import { HostElement } from '@stencil/core/internal';

describe('componentOnReady', () => {
const mockRequestAnimationFrame = jest.fn();
const mockSetTimeout = jest.fn();

beforeAll(() => {
global.requestAnimationFrame = mockRequestAnimationFrame;
global.setTimeout = mockSetTimeout;
});

afterEach(() => {
mockRequestAnimationFrame.mockClear();
mockSetTimeout.mockClear();
});

it('should return the result of componentOnReady if it exists', async () => {
const el = {
componentOnReady: jest.fn().mockResolvedValue('resolvedValue'),
} as HostElement;

const result = await componentOnReady(el);
expect(el.componentOnReady).toHaveBeenCalledTimes(1);
expect(result).toBe('resolvedValue');
});

it('should use customOnReady if componentOnReady does not exist and requestAnimationFrame is available', async () => {
mockRequestAnimationFrame.mockImplementation(callback => callback());

const el = {} as HostElement;
const promise = componentOnReady(el);

const result = await promise;
expect(mockRequestAnimationFrame).toHaveBeenCalledTimes(1);
expect(result).toBe(el);
});

it('should use customOnReady if componentOnReady does not exist and requestAnimationFrame is not available', async () => {
delete global.requestAnimationFrame;

mockSetTimeout.mockImplementation(callback => callback());

const el = {} as HostElement;
const promise = componentOnReady(el);

const result = await promise;
expect(mockSetTimeout).toHaveBeenCalledTimes(1);
expect(result).toBe(el);
});
});

0 comments on commit 65eade9

Please sign in to comment.