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: add TS to helpers package #798

Merged
merged 7 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 0 additions & 13 deletions packages/helpers/babel.config.js

This file was deleted.

19 changes: 15 additions & 4 deletions packages/helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"author": "ggdaltoso <[email protected]>",
"homepage": "https://gympass.github.io/yoga/",
"license": "MIT",
"main": "src/index.js",
"main": "src/index.ts",
"types": "src/index.ts",
"publishConfig": {
"access": "public",
"directory": "dist"
Expand All @@ -21,14 +22,24 @@
"url": "git+https://github.com/Gympass/yoga.git"
},
"scripts": {
"build": "yarn build:cjs && yarn build:esm",
"build:cjs": "NODE_ENV=cjs babel ./src --out-dir dist/cjs",
"build:esm": "NODE_ENV=esm babel ./src --out-dir dist/esm",
"build": "yarn build:types && yarn build:cjs && yarn build:esm",
"build:cjs": "tsup src !src/types.ts --outDir dist/cjs --format=cjs",
"build:esm": "tsup src !src/types.ts --format=esm --legacy-output",
"build:types": "tsup --outDir dist/typings --dts-only",
"prebuild": "rm -rf ./dist",
"prepublishOnly": "node ../../scripts/prepublish.js",
"test": "NODE_ENV=test jest --config=../../jest/config/helpers.js"
},
"bugs": {
"url": "https://github.com/Gympass/yoga/issues"
},
"tsup": {
"entry": [
"src/index.ts",
"src/**/*.(t|j)s",
"!src/**/*.test.(t|j)s"
],
"splitting": false,
"bundle": false
}
}
21 changes: 12 additions & 9 deletions packages/helpers/src/hide.js → packages/helpers/src/hide.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import tokens from '@gympass/yoga-tokens';
import tokens, { BreakpointsType } from '@gympass/yoga-tokens';

const { breakpoints } = tokens;

import { css } from 'styled-components';

import { not } from './media';
import { Entries, Hide } from './types';

const { breakpoints } = tokens;
const availableBreakpoints = Object.entries(breakpoints);
const availableBreakpoints = Object.entries(
breakpoints
) as unknown as Entries<BreakpointsType>;

const hide = isNot =>
const hide = (isNot = false) =>
availableBreakpoints.reduce((acc, [key, breakpoint], index) => {
if (index === 0) {
const [, secondBreakpoint] = availableBreakpoints[index + 1];
Expand Down Expand Up @@ -37,10 +43,7 @@ const hide = isNot =>
const [, nextBreakpoint] = availableBreakpoints[index + 1];

acc[key] = css`
@media ${not(
isNot,
)} (min-width: ${breakpoint.width}px) and (max-width: ${nextBreakpoint.width -
1}px) {
@media ${not(isNot)} (min-width: ${breakpoint.width}px) and (max-width: ${nextBreakpoint.width - 1}px) {
display: none !important;
}
`;
Expand All @@ -52,6 +55,6 @@ const hide = isNot =>
`;

return acc;
}, {});
}, {} as Hide);

export default hide;
File renamed without changes.
62 changes: 0 additions & 62 deletions packages/helpers/src/media.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,58 +1,59 @@
/* eslint-disable import/no-named-as-default-member */
import tokens from '@gympass/yoga-tokens';
import tokens, { BreakpointsKey } from '@gympass/yoga-tokens';

import media, { matcher, not } from './media';
import { Matcher } from './types';

const { breakpoints } = tokens;
const { breakpoints, BREAKPOINTS_KEYS } = tokens;

const formatCss = style =>
Array.isArray(style)
? style.join().replace(/,|\s*/g, '')
: style.replace(/,|\s*/g, '');

const expectedStyle = (...args) => {
const expectedStyle: Matcher = (...args) => {
return formatCss(matcher(...args)`
padding: 10px;
`);
};

const expectedHideStyle = breakpoint =>
const expectedHideStyle: (breakpoint: string) => void = breakpoint =>
matheushdsbr marked this conversation as resolved.
Show resolved Hide resolved
formatCss(`@media (min-width: ${breakpoints[breakpoint].width}px) {
display: none !important;
}`);

describe('media', () => {
it.each(Object.keys(breakpoints))('.%s', breakpoint => {
it.each(BREAKPOINTS_KEYS)('.%s', breakpoint => {
const style = media[breakpoint]`
padding: 10px;
`;

expect(formatCss(style)).toBe(expectedStyle(breakpoint));
expect(formatCss(style)).toBe(expectedStyle(breakpoint as BreakpointsKey));
});

it.each(Object.keys(breakpoints))('.not.%s', breakpoint => {
it.each(BREAKPOINTS_KEYS)('.not.%s', breakpoint => {
const notStyle = media.not[breakpoint]`
padding: 10px;
`;

expect(formatCss(notStyle)).toBe(expectedStyle(breakpoint, true));
expect(formatCss(notStyle)).toBe(expectedStyle(breakpoint as BreakpointsKey, true));
});

describe('max', () => {
it.each(Object.keys(breakpoints))(".max('%s')", breakpoint => {
const style = media.max(breakpoint)`
it.each(BREAKPOINTS_KEYS)(".max('%s')", breakpoint => {
const style = media.max(breakpoint as BreakpointsKey)`
padding: 10px;
`;

expect(formatCss(style)).toBe(expectedStyle(breakpoint, false, 'max'));
expect(formatCss(style)).toBe(expectedStyle(breakpoint as BreakpointsKey, false, 'max'));
});

it.each(Object.keys(breakpoints))(".not.max('%s')", breakpoint => {
const style = media.not.max(breakpoint)`
const style = media.not.max(breakpoint as BreakpointsKey)`
padding: 10px;
`;

expect(formatCss(style)).toBe(expectedStyle(breakpoint, true, 'max'));
expect(formatCss(style)).toBe(expectedStyle(breakpoint as BreakpointsKey, true, 'max'));
});
});

Expand All @@ -71,19 +72,19 @@ describe('media', () => {
];

it.each(comparisons)(".between('%s', '%s')", (min, max) => {
const style = media.between(min, max)`
const style = media.between(min as BreakpointsKey, max as BreakpointsKey)`
padding: 10px;
`;

expect(formatCss(style)).toBe(expectedStyle([min, max], false));
expect(formatCss(style)).toBe(expectedStyle([min as BreakpointsKey, max as BreakpointsKey], false));
});

it.each(comparisons)(".not.between('%s', '%s')", (min, max) => {
const style = media.not.between(min, max)`
const style = media.not.between(min as BreakpointsKey, max as BreakpointsKey)`
padding: 10px;
`;

expect(formatCss(style)).toBe(expectedStyle([min, max], true));
expect(formatCss(style)).toBe(expectedStyle([min as BreakpointsKey, max as BreakpointsKey], true));
});
});
});
Expand Down
65 changes: 65 additions & 0 deletions packages/helpers/src/media.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import tokens, { BreakpointsKey } from '@gympass/yoga-tokens';

import { css } from 'styled-components';

import hide from './hide';
import { Matcher, Media, Width } from './types';

const { breakpoints, BREAKPOINTS_KEYS } = tokens;

const availableBreakpoints = BREAKPOINTS_KEYS as BreakpointsKey[];

const media: Media = { not: {} } as Media;

export const not = (isNot?: boolean) => (isNot ? 'not all and ' : '');

const getRange = (width: Width, range: 'min' | 'max') => {
try {
if (Array.isArray(width)) {
const [min, max] = width;

const {
[min]: { width: minBreakpoint },
[max]: { width: maxBreakpoint }
} = breakpoints;

return `(min-width: ${minBreakpoint}px) and (max-width: ${maxBreakpoint}px)`;
}

return `(${range}-width: ${breakpoints[width].width}px)`;
} catch {
const msg = `Make sure you've entered the right breakpoints.
Your input: ${Array.isArray(width) ? width.join(', ') : width}
Available breakpoints: ${availableBreakpoints.join(', ')}`;

throw new Error(msg);
}
};

export const matcher: Matcher =
(width: Width, isNot = false, range: 'min' | 'max' = 'min') =>
(...style) => {
return css`
@media ${not(isNot)}${getRange(width, range)} {
${css(...style)}
}
`;
};

availableBreakpoints.forEach((breakpoint) => {
media[breakpoint] = matcher(breakpoint);
media.not[breakpoint] = matcher(breakpoint, true);
});

media.max = (width: Width) => matcher(width, false, 'max');
media.not.max = (width: Width) => matcher(width, true, 'max');

media.between = (min: BreakpointsKey, max: BreakpointsKey) =>
matcher([min, max], false, 'max');
media.not.between = (min: BreakpointsKey, max: BreakpointsKey) =>
matcher([min, max], true, 'max');

media.hide = hide();
media.not.hide = hide(true);

export default media;
51 changes: 51 additions & 0 deletions packages/helpers/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { BreakpointsKey} from '@gympass/yoga-tokens';

import { CSSObject, FlattenSimpleInterpolation } from 'styled-components';
export type Width = BreakpointsKey | BreakpointsKey[];

export type Media = {
not: MediaProps;
} & MediaProps;

export type Matcher = (
width: Width,
isNot?: boolean,
range?: 'min' | 'max'
) => Match;

export type Hide = {
[key in BreakpointsKey | StartBreakPoints]?: FlattenSimpleInterpolation;
};

export type Entries<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T][];

type StartBreakPoints =
| 'xxs-start'
| 'xs-start'
| 'sm-start'
| 'md-start'
| 'lg-start'
| 'xl-start'
| 'xxl-start'
| 'xxxl-start';

type MediaProps = {
hide: Hide;
max: Max;
between: Between;
} & MappedType;

type MappedType = {
[key in BreakpointsKey]: Match;
};

type Max = (width: Width) => Match;

export type Between = (min: BreakpointsKey, max: BreakpointsKey) => Match;

type Match = (
first: TemplateStringsArray | CSSObject,
...interpolations: any[]
) => FlattenSimpleInterpolation;
Loading
Loading