Skip to content

Commit

Permalink
Merge pull request #232 from Telegram-Mini-Apps/feature/css-utils
Browse files Browse the repository at this point in the history
Export CSS utilities
  • Loading branch information
heyqbnk authored Feb 23, 2024
2 parents d37ad09 + 9792afa commit 832ceb7
Show file tree
Hide file tree
Showing 12 changed files with 326 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/nice-bags-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tma.js/sdk": patch
---

Move css utils to the separate folder. Write tests. Fix a bug in viewport stable height CSS var
175 changes: 175 additions & 0 deletions packages/sdk/src/css/__tests__/bindMiniAppCSSVars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { expect, vi, it, SpyInstance, afterEach, beforeAll, describe } from 'vitest';
import { ThemeParams } from '../../theme-params';
import { dispatchWindowMessageEvent } from '../../../test-utils/dispatchWindowMessageEvent';
import { bindMiniAppCSSVars } from '../bindMiniAppCSSVars';
import { MiniApp } from '../../mini-app';

let setCSSPropertySpy: SpyInstance<[string, string, string?], void>;

beforeAll(() => {
setCSSPropertySpy = vi
.spyOn(document.documentElement.style, 'setProperty')
.mockImplementation(() => {
});
});

afterEach(() => {
vi.clearAllMocks();
});

describe('background', () => {
it('should set --tg-background-color equal to miniApp.backgroundColor', () => {
bindMiniAppCSSVars(
new MiniApp({
backgroundColor: '#111111',
headerColor: '#222222',
botInline: false,
version: '7.0',
createRequestId() {
return 'abc';
},
}),
new ThemeParams({}),
);

expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-background-color', '#111111');
});

it('should update --tg-background-color according to the changes applied to mini app background color', () => {
const ma = new MiniApp({
backgroundColor: '#111111',
headerColor: '#222222',
botInline: false,
version: '7.0',
postEvent() {
},
createRequestId() {
return 'abc';
},
});

bindMiniAppCSSVars(ma, new ThemeParams({}));
setCSSPropertySpy.mockClear();

ma.setBackgroundColor('#999999');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-background-color', '#999999');
});
});

describe('header', () => {
it('should set --tg-header-color equal to miniApp.headerColor if this value is RGB', () => {
bindMiniAppCSSVars(
new MiniApp({
backgroundColor: '#111111',
headerColor: '#222222',
botInline: false,
version: '7.0',
createRequestId() {
return 'abc';
},
}),
new ThemeParams({}),
);

expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-header-color', '#222222');
});

it('should set --tg-header-color equal to themeParams.backgroundColor if miniApp.headerColor = "bg_color" and backgroundColor property is presented in theme params', () => {
const tp = new ThemeParams({});
tp.listen();

bindMiniAppCSSVars(
new MiniApp({
backgroundColor: '#111111',
headerColor: 'bg_color',
botInline: false,
version: '7.0',
createRequestId() {
return 'abc';
},
}),
tp,
);

// Background only.
expect(setCSSPropertySpy).toHaveBeenCalledTimes(1);
setCSSPropertySpy.mockClear();

dispatchWindowMessageEvent('theme_changed', {
theme_params: {
bg_color: '#ffffff',
},
});

expect(setCSSPropertySpy).toHaveBeenCalledTimes(1);
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-header-color', '#ffffff');
});

it('should set --tg-header-color equal to themeParams.secondaryBackgroundColor if miniApp.headerColor = "secondary_bg_color" and secondaryBackgroundColor property is presented in theme params', () => {
const tp = new ThemeParams({});
tp.listen();

bindMiniAppCSSVars(
new MiniApp({
backgroundColor: '#111111',
headerColor: 'secondary_bg_color',
botInline: false,
version: '7.0',
createRequestId() {
return 'abc';
},
}),
tp,
);

// Background only.
expect(setCSSPropertySpy).toHaveBeenCalledTimes(1);
setCSSPropertySpy.mockClear();

dispatchWindowMessageEvent('theme_changed', {
theme_params: {
secondary_bg_color: '#000000',
},
});
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-header-color', '#000000');
});

it('should actualize --tg-header-color if either mini app or theme params changed', () => {
const ma = new MiniApp({
backgroundColor: '#111111',
headerColor: '#aabbcc',
botInline: false,
version: '7.0',
postEvent() {},
createRequestId() {
return 'abc';
},
});
const tp = new ThemeParams({
backgroundColor: '#ffffff',
secondaryBackgroundColor: '#000000',
});
tp.listen();

bindMiniAppCSSVars(ma, tp);
setCSSPropertySpy.mockClear();

ma.setHeaderColor('bg_color');
expect(setCSSPropertySpy).toHaveBeenCalledTimes(1);
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-header-color', '#ffffff');
setCSSPropertySpy.mockClear();

ma.setHeaderColor('secondary_bg_color');
expect(setCSSPropertySpy).toHaveBeenCalledTimes(1);
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-header-color', '#000000');
setCSSPropertySpy.mockClear();

dispatchWindowMessageEvent('theme_changed', {
theme_params: {
secondary_bg_color: '#abcdef',
},
});
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-header-color', '#abcdef');
setCSSPropertySpy.mockClear();
});
});
52 changes: 52 additions & 0 deletions packages/sdk/src/css/__tests__/bindThemeCSSVars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { expect, vi, it, SpyInstance, afterEach, beforeAll } from 'vitest';
import { bindThemeCSSVars } from '../bindThemeCSSVars';
import { ThemeParams } from '../../theme-params';
import { dispatchWindowMessageEvent } from '../../../test-utils/dispatchWindowMessageEvent';

let setCSSPropertySpy: SpyInstance<[string, string, string?], void>;

beforeAll(() => {
setCSSPropertySpy = vi
.spyOn(document.documentElement.style, 'setProperty')
.mockImplementation(() => {
});
});

afterEach(() => {
vi.clearAllMocks();
});

it('should set --tg-theme-{key} CSS vars, where key is a kebab-cased theme keys', () => {
bindThemeCSSVars(new ThemeParams({
backgroundColor: '#abcdef',
accentTextColor: '#000011',
}));

expect(setCSSPropertySpy).toHaveBeenCalledTimes(2);
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-theme-background-color', '#abcdef');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-theme-accent-text-color', '#000011');
});

it('should update --tg-theme-{key}variables to the values, received in the Theme change events', async () => {
const tp = new ThemeParams({
backgroundColor: '#abcdef',
accentTextColor: '#000011',
});
bindThemeCSSVars(tp);
setCSSPropertySpy.mockClear();

await tp.listen();

dispatchWindowMessageEvent('theme_changed', {
theme_params: {
bg_color: '#111111',
accent_text_color: '#222222',
text_color: '#333333',
},
});

expect(setCSSPropertySpy).toHaveBeenCalledTimes(3);
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-theme-background-color', '#111111');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-theme-accent-text-color', '#222222');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-theme-text-color', '#333333');
});
55 changes: 55 additions & 0 deletions packages/sdk/src/css/__tests__/bindViewportCSSVars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { expect, vi, it, SpyInstance, afterEach, beforeAll } from 'vitest';
import { bindViewportCSSVars } from '../bindViewportCSSVars';
import { Viewport } from '../../viewport';
import { dispatchWindowMessageEvent } from '../../../test-utils/dispatchWindowMessageEvent';

let setCSSPropertySpy: SpyInstance<[string, string, string?], void>;

beforeAll(() => {
setCSSPropertySpy = vi
.spyOn(document.documentElement.style, 'setProperty')
.mockImplementation(() => {
});
});

afterEach(() => {
vi.clearAllMocks();
});

it('should set --tg-viewport-height = viewport.height, --tg-viewport-width = viewport.width, --tg-viewport-stable-height = viewport.stableHeight', () => {
bindViewportCSSVars(new Viewport({
height: 192,
width: 1000,
isExpanded: false,
stableHeight: 200,
}));

expect(setCSSPropertySpy).toHaveBeenCalledTimes(3);
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-viewport-height', '192px');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-viewport-width', '1000px');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-viewport-stable-height', '200px');
});

it('should update --tg-viewport-height, --tg-viewport-width, --tg-viewport-stable-height according to the values, received in the Viewport change events', () => {
const viewport = new Viewport({
height: 192,
width: 1000,
isExpanded: false,
stableHeight: 200,
});
bindViewportCSSVars(viewport);
setCSSPropertySpy.mockClear();

viewport.listen();
dispatchWindowMessageEvent('viewport_changed', {
height: 900,
is_state_stable: true,
is_expanded: false,
width: 1800,
})

expect(setCSSPropertySpy).toHaveBeenCalledTimes(3);
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-viewport-height', '900px');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-viewport-width', '1800px');
expect(setCSSPropertySpy).toHaveBeenCalledWith('--tg-viewport-stable-height', '900px');
});
14 changes: 14 additions & 0 deletions packages/sdk/src/css/__tests__/setCSSVar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { afterEach, expect, it, vi } from 'vitest';
import { setCSSVar } from '../setCSSVar';

afterEach(() => {
vi.restoreAllMocks();
})

it('should call document.documentElement.style.setProperty with passed "name" and "value" arguments', () => {
const spy = vi.spyOn(document.documentElement.style, 'setProperty').mockImplementation(() => {});

setCSSVar('tma', 'is cool')
expect(spy).toHaveBeenCalledOnce();
expect(spy).toHaveBeenCalledWith('tma', 'is cool');
})
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { setCSSVar } from '~/init/css/setCSSVar.js';
import { isRGB } from '~/colors/index.js';
import { setCSSVar } from '~/css/setCSSVar.js';
import type { MiniApp } from '~/mini-app/index.js';
import type { ThemeParams } from '~/theme-params/index.js';

Expand Down Expand Up @@ -26,16 +27,18 @@ export function bindMiniAppCSSVars(miniApp: MiniApp, themeParams: ThemeParams):
secondaryBackgroundColor,
} = themeParams;

if (miniApp.headerColor === 'bg_color') {
if (backgroundColor) {
setCSSVar('--tg-header-color', backgroundColor);
}
} else if (miniApp.headerColor === 'secondary_bg_color') {
if (secondaryBackgroundColor) {
setCSSVar('--tg-header-color', secondaryBackgroundColor);
}
} else {
if (isRGB(miniApp.headerColor)) {
setCSSVar('--tg-header-color', miniApp.headerColor);
return;
}

if (miniApp.headerColor === 'bg_color' && backgroundColor) {
setCSSVar('--tg-header-color', backgroundColor);
return;
}

if (miniApp.headerColor === 'secondary_bg_color' && secondaryBackgroundColor) {
setCSSVar('--tg-header-color', secondaryBackgroundColor);
}
};

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { setCSSVar } from './setCSSVar.js';
export function bindViewportCSSVars(viewport: Viewport): void {
const setHeight = () => setCSSVar('--tg-viewport-height', `${viewport.height}px`);
const setWidth = () => setCSSVar('--tg-viewport-width', `${viewport.width}px`);
const setStableHeight = () => setCSSVar('--tg-viewport-height', `${viewport.stableHeight}px`);
const setStableHeight = () => setCSSVar('--tg-viewport-stable-height', `${viewport.stableHeight}px`);

// TODO: Should probably add debounce or throttle.
viewport.on('change:height', setHeight);
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk/src/css/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './bindMiniAppCSSVars.js';
export * from './bindThemeCSSVars.js';
export * from './bindViewportCSSVars.js';
export * from './setCSSVar.js';
File renamed without changes.
6 changes: 6 additions & 0 deletions packages/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ export {
type RGB,
type RGBShort,
} from './colors/index.js';
export {
setCSSVar,
bindMiniAppCSSVars,
bindThemeCSSVars,
bindViewportCSSVars,
} from './css/index.js';
export { HapticFeedback } from './haptic-feedback/index.js';
export {
init,
Expand Down
4 changes: 1 addition & 3 deletions packages/sdk/src/init/css/processCSSVarsOption.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { bindMiniAppCSSVars, bindThemeCSSVars, bindViewportCSSVars } from '~/css/index.js';
import type { MiniApp } from '~/mini-app/index.js';
import type { ThemeParams } from '~/theme-params/index.js';
import type { Viewport } from '~/viewport/index.js';

import { bindMiniAppCSSVars } from './bindMiniAppCSSVars.js';
import { bindThemeCSSVars } from './bindThemeCSSVars.js';
import { bindViewportCSSVars } from './bindViewportCSSVars.js';
import type { InitCSSVarsOption, InitCSSVarsSpecificOption } from '../types.js';

/**
Expand Down

0 comments on commit 832ceb7

Please sign in to comment.