Skip to content

Commit

Permalink
fix(error-messages): fix error messages and remove
Browse files Browse the repository at this point in the history
monads
  • Loading branch information
mg901 committed Mar 30, 2019
1 parent 7369f23 commit 74dc45f
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 56 deletions.
57 changes: 3 additions & 54 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,4 @@
// @flow
// @flow strict

import { calcMinWidthInPx, calcMaxWidthInPx } from './calculators';
import { withMinMedia, withMaxMedia, withMinAndMaxMedia } from './HOFs';
import type { BpProps } from './models';

type Up = (string) => (BpProps) => string;
export const up: Up = (breakName) => ({ theme }) =>
withMinMedia(
calcMinWidthInPx(
breakName,
theme,
theme.ERROR_PREFIX_FOR_STYLED_BREAKPOINTS,
),
);

type Down = (string) => (BpProps) => string;
export const down: Down = (breakName) => ({ theme }) =>
withMaxMedia(
calcMaxWidthInPx(
breakName,
theme,
theme.ERROR_PREFIX_FOR_STYLED_BREAKPOINTS,
),
);

type Between = (string, string) => (BpProps) => string;
export const between: Between = (minBreak, maxBreak) => ({ theme }) =>
withMinAndMaxMedia(
calcMinWidthInPx(
minBreak,
theme,
theme.ERROR_PREFIX_FOR_STYLED_BREAKPOINTS,
),
calcMaxWidthInPx(
maxBreak,
theme,
theme.ERROR_PREFIX_FOR_STYLED_BREAKPOINTS,
),
);

type Only = (string) => (BpProps) => string;
export const only: Only = (breakName) => ({ theme }) =>
withMinAndMaxMedia(
calcMinWidthInPx(
breakName,
theme,
theme.ERROR_PREFIX_FOR_STYLED_BREAKPOINTS,
),
calcMaxWidthInPx(
breakName,
theme,
theme.ERROR_PREFIX_FOR_STYLED_BREAKPOINTS,
),
);
export { BpProps } from './models';
export { up, down, only, between } from './utils';
3 changes: 1 addition & 2 deletions src/models.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @flow
// @flow strict

export type Breakpoints = { [name: string]: string };

Expand All @@ -7,7 +7,6 @@ export type ThemeWithBreaks = {
};

export type CustomTheme = {
ERROR_PREFIX_FOR_STYLED_BREAKPOINTS?: string,
breakpoints?: Breakpoints,
};

Expand Down
147 changes: 147 additions & 0 deletions src/utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// @flow strict

import type {
Breakpoints,
CustomTheme,
ThemeWithBreaks,
BpProps,
} from '../models';

export const DEFAULT_BREAKS_MAP: Breakpoints = {
tablet: '768px',
desktop: '992px',
lgDesktop: '1200px',
};

export const DEFAULT_BREAKS: ThemeWithBreaks = {
breakpoints: DEFAULT_BREAKS_MAP,
};

export const withMinMedia = (minWidth: string): string =>
`@media (min-width: ${minWidth})`;

export const withMaxMedia = (maxWidth: string): string =>
`@media (max-width: ${maxWidth})`;

export const withMinAndMaxMedia = (
minWidth: string,
maxWidth: string,
): string => `@media (min-width: ${minWidth}) and (max-width: ${maxWidth})`;

export const isObject = (value: mixed): boolean =>
Object.prototype.toString.call(value).slice(8, -1) === 'Object';

export const toEm = (inPx: string): string => `${parseFloat(inPx) / 16}em`;

export const makeErrorMessage = (
breakName: string,
breaks: Breakpoints,
): string =>
`'${String(breakName)}' is invalid breakpoint name. Use '${Object.keys(
breaks,
).join(', ')}'.`;

export const setCustomOrDefaultTheme = (theme: CustomTheme): ThemeWithBreaks =>
theme &&
theme.breakpoints &&
isObject(theme.breakpoints) &&
Object.keys(theme.breakpoints).length > 0
? { ...theme }
: { ...theme, ...DEFAULT_BREAKS };

export const invariant = (condition: mixed, message: string): void => {
if (!condition) {
throw new Error(`[styled-breakpoints]: ${String(message)}`);
}
};

export const getBreakpointValue = (
breakName: string,
breaks: Breakpoints,
): string => {
invariant(breaks[String(breakName)], makeErrorMessage(breakName, breaks));

return breaks[breakName];
};

export const getNextBreakpointName: (string) => (Breakpoints) => string = (
breakName,
) => (breaks) => {
const breakNames = Object.keys(breaks);
const penultimateBreakName = breakNames[breakNames.length - 2];
const currentPosition = breakNames.indexOf(String(breakName));
const isInvalidBreakName = currentPosition === -1;
const isLastBreakName =
currentPosition > -1 && currentPosition >= breakNames.length - 1;

if (isInvalidBreakName) {
invariant(!isInvalidBreakName, makeErrorMessage(breakName, breaks));
}

if (isLastBreakName) {
invariant(
!isLastBreakName,
`Don't use '${breakName}' because it doesn't have a maximum width. Use '${penultimateBreakName}'.`,
);
}

return breakNames[currentPosition + 1];
};

// Maximum breakpoint width. Null for the largest (last) breakpoint.
// The maximum value is calculated as the minimum of the next one less 0.02px
// to work around the limitations of `min-` and `max-` prefixes and viewports with fractional widths.
// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max
// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.
// See https://bugs.webkit.org/show_bug.cgi?id=178261

export const getNextBreakpointValue = (
breakName: string,
breaks: Breakpoints,
): string => {
invariant(
breaks[breakName],
`'${String(breakName)}' is invalid breakpoint name. Use '${Object.keys(
breaks,
)
.slice(0, -1)
.join(', ')}'.`,
);
const getNextProp = getNextBreakpointName(breakName);

return `${parseFloat(breaks[getNextProp(breaks)]) - 0.02}px`;
};

export const calcMinWidth = (breakName: string, theme: CustomTheme): string => {
const newTheme = setCustomOrDefaultTheme(theme);

return toEm(getBreakpointValue(breakName, newTheme.breakpoints));
};

export const calcMaxWidth = (breakName: string, theme: CustomTheme): string => {
const newTheme = setCustomOrDefaultTheme(theme);

return toEm(getNextBreakpointValue(breakName, newTheme.breakpoints));
};

type Up = (string) => (BpProps) => string;
export const up: Up = (breakName) => ({ theme }) =>
withMinMedia(calcMinWidth(breakName, theme));

type Down = (string) => (BpProps) => string;
export const down: Down = (breakName) => ({ theme }) =>
withMaxMedia(calcMaxWidth(breakName, theme));

type Between = (string, string) => (BpProps) => string;
export const between: Between = (minBreak, maxBreak) => ({ theme }) =>
withMinAndMaxMedia(
calcMinWidth(minBreak, theme),
calcMaxWidth(maxBreak, theme),
);

type Only = (string) => (BpProps) => string;
export const only: Only = (breakName) => ({ theme }) =>
withMinAndMaxMedia(
calcMinWidth(breakName, theme),
calcMaxWidth(breakName, theme),
);

0 comments on commit 74dc45f

Please sign in to comment.