Skip to content

Commit

Permalink
fix(up): remove incorrect validation when breakpoint is equal zero
Browse files Browse the repository at this point in the history
  • Loading branch information
mg901 committed Apr 25, 2023
1 parent 90a3b22 commit ae47e05
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 253 deletions.
198 changes: 98 additions & 100 deletions core/breakpoints.js
Original file line number Diff line number Diff line change
@@ -1,114 +1,112 @@
const { createInvariantWithPrefix } = require('../library');
const { createInvariantWithPrefix, memoize } = require('../library');

const DEFAULT_BREAKPOINTS = {
xs: '0px',
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px',
xxl: '1400px',
};

exports.createBreakpoints = ({ breakpoints, errorPrefix }) => {
const keys = Object.keys(Object(breakpoints));
const values = Object.values(Object(breakpoints));
const entries = Object.entries(Object(breakpoints));
const invariant = createInvariantWithPrefix(errorPrefix);
const ERROR_PREFIX = '[breakpoints]: ';

const defaultOptions = {
breakpoints: DEFAULT_BREAKPOINTS,
errorPrefix: ERROR_PREFIX,
};

const validation = withValidation({
invariant,
exports.DEFAULT_BREAKPOINTS = DEFAULT_BREAKPOINTS;
exports.ERROR_PREFIX = ERROR_PREFIX;

exports.createBreakpoints = ({ breakpoints, errorPrefix } = defaultOptions) => {
const names = Object.keys(breakpoints);
const validation = createValidation({
names,
breakpoints,
keys,
errorPrefix,
});

return {
keys,
entries,
invariant,
...withBreakpoints({
validation,
breakpoints,
keys,
values,
}),
};
};
const getValueByName = memoize((name) => {
validation.checkIsValidName(name);
validation.checkIsFirstName(name);

function withValidation({ keys, invariant, breakpoints }) {
return {
throwIsInvalidName,
throwIsValueIsZero,
throwIsLastBreakpoint,
return breakpoints[name];
});

const getNextName = (name) => {
const nextIndex = names.indexOf(name) + 1;

return names[nextIndex];
};

function throwIsInvalidName(name) {
invariant(
breakpoints[name],
`breakpoint \`${name}\` not found in ${keys.join(', ')}.`
);
}

function throwIsValueIsZero(name) {
const value = breakpoints[name];
const isNotZero = parseFloat(value) !== 0;

invariant(
isNotZero,
`\`${name}: ${value}\` cannot be assigned as minimum breakpoint.`
);
}

function throwIsLastBreakpoint(name) {
const isNotLast = name !== keys.at(-1);
const validName = keys.at(-2);

invariant(
isNotLast,
`\`${name}\` doesn't have a maximum width. Use \`${validName}\`. See https://github.com/mg901/styled-breakpoints/issues/4 .`
);
}
}
const getNextValueByName = memoize((name) => {
validation.checkIsValidName(name);
validation.checkIsLastName(name);

return breakpoints[getNextName(name)];
});

// 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
const calcMaxWidth = (value) => {
return `${parseFloat(value) - 0.02}px`;
};

function withBreakpoints(state) {
return {
up,
down,
between,
only,
up: memoize((name) => {
validation.checkIsValidName(name);

return breakpoints[name];
}),

down: (max) => calcMaxWidth(getValueByName(max)),

between: (min, max) => ({
min: getValueByName(min),
max: calcMaxWidth(getValueByName(max)),
}),

only: (name) => ({
min: getValueByName(name),
max: calcMaxWidth(getNextValueByName(name)),
}),
};
};

function up(min) {
state.validation.throwIsInvalidName(min);

return state.breakpoints[min];
}

function down(max) {
state.validation.throwIsInvalidName(max);
state.validation.throwIsValueIsZero(max);
state.validation.throwIsLastBreakpoint(max);

return calcMaxWidth(state.breakpoints[max]);
}

function between(min, max) {
return {
min: up(min),
max: down(max),
};
}

function only(name) {
state.validation.throwIsInvalidName(name);
state.validation.throwIsLastBreakpoint(name);
const nextIndex = state.keys.indexOf(name) + 1;

return {
min: up(name),
max: calcMaxWidth(state.values[nextIndex]),
};
}
}
function createValidation({ names, breakpoints, errorPrefix }) {
const invariant = createInvariantWithPrefix(errorPrefix);

// 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
function calcMaxWidth(value) {
return `${parseFloat(value) - 0.02}px`;
return {
checkIsValidName: (name) => {
invariant(
breakpoints[name],
`breakpoint \`${name}\` not found in ${names.join(', ')}.`
);
},
checkIsFirstName: (name) => {
const value = breakpoints[name];
const isNotZero = parseFloat(value) !== 0;

invariant(
isNotZero,
`\`${name}: ${value}\` cannot be assigned as minimum breakpoint.`
);
},
checkIsLastName: (name) => {
const currentIndex = names.indexOf(name);
const nextIndex = currentIndex + 1;
const isNotLast = names.length !== nextIndex;
const validName = names[names.length - 2];

invariant(
isNotLast,
`\`${name}\` doesn't have a maximum width. Use \`${validName}\`. See https://github.com/mg901/styled-breakpoints/issues/4 .`
);
},
};
}

exports.calcMaxWidth = calcMaxWidth;
Loading

0 comments on commit ae47e05

Please sign in to comment.