diff --git a/example/src/Example.tsx b/example/src/Example.tsx
index ee90325..f8800c5 100644
--- a/example/src/Example.tsx
+++ b/example/src/Example.tsx
@@ -48,6 +48,51 @@ export default function Example() {
Heading
+
+ Media
+
+
+ Underlined appears on phone
+
+
+ Square border appears on md Phone
+
)}
{!example && (
diff --git a/example/src/components/Heading.tsx b/example/src/components/Heading.tsx
index 92fbcf8..43c4756 100644
--- a/example/src/components/Heading.tsx
+++ b/example/src/components/Heading.tsx
@@ -19,7 +19,6 @@ const underLinedStyle = css({
underlined: true,
css: {
borderBottomColor: 'black',
- borderBottomWidth: 1,
},
},
{
@@ -27,7 +26,6 @@ const underLinedStyle = css({
underlined: true,
css: {
borderBottomColor: 'red',
- borderBottomWidth: 1,
},
},
{
@@ -35,7 +33,6 @@ const underLinedStyle = css({
underlined: true,
css: {
borderBottomColor: 'blue',
- borderBottomWidth: 1,
},
},
{
@@ -43,7 +40,6 @@ const underLinedStyle = css({
underlined: true,
css: {
borderBottomColor: 'green',
- borderBottomWidth: 1,
},
},
{
@@ -51,7 +47,6 @@ const underLinedStyle = css({
underlined: true,
css: {
borderBottomColor: 'purple',
- borderBottomWidth: 1,
},
},
{
@@ -82,6 +77,7 @@ export const Heading = styled(
true: {
paddingRight: 4,
paddingLeft: 4,
+ borderBottomWidth: 1,
},
},
},
diff --git a/src/internals/index.js b/src/internals/index.js
index 4125c6f..a7217b2 100644
--- a/src/internals/index.js
+++ b/src/internals/index.js
@@ -118,8 +118,9 @@ export function createStitches(config = {}) {
let variantStyles = [];
let compoundVariantStyles = [];
+ const appliedVariants = {};
- const { mediaKey, breakpoint } = useMemo(() => {
+ const matchedMedias = useMemo(() => {
if (typeof config.media === 'object') {
const correctedWindowWidth =
PixelRatio.getPixelSizeForLayoutSize(windowWidth);
@@ -128,63 +129,58 @@ export function createStitches(config = {}) {
// The order of the media key value pairs should be constant
// but is that guaranteed? So if the keys are ordered from
// smallest screen size to largest everything should work ok...
- const _mediaKey = utils.resolveMediaRangeQuery(
+ const matchedMedias = utils.resolveMediaRangeQuery(
config.media,
correctedWindowWidth
);
- return {
- mediaKey: _mediaKey,
- breakpoint: _mediaKey && `@${_mediaKey}`,
- };
+ return matchedMedias;
}
- return {};
+ return [];
}, [windowWidth]);
if (variants) {
variantStyles = Object.keys(variants)
.map((prop) => {
- let propValue = props[prop];
+ const propValue = props[prop] ?? defaultVariants[prop];
- if (propValue === undefined) {
- propValue = defaultVariants[prop];
- }
-
- let styleSheetKey = `${prop}_${propValue}`;
+ const styleSheetKey = `${prop}_${propValue}`;
- // Handle responsive prop value
- // NOTE: only one media query will be applied since the `styleSheetKey`
- // is being rewritten by the last matching media query and defaults to `@initial`
- if (
- typeof propValue === 'object' &&
- typeof config.media === 'object'
- ) {
- // `@initial` acts as the default value if none of the media query values match
- // It's basically the as setting `prop="value"`, eg. `color="primary"`
- if (typeof propValue['@initial'] === 'string') {
- styleSheetKey = `${prop}_${propValue['@initial']}`;
- }
-
- if (breakpoint && propValue[breakpoint] !== undefined) {
- const val = config.media[mediaKey];
-
- if (val === true || typeof val === 'string') {
- styleSheetKey = `${prop}_${propValue[breakpoint]}`;
- }
+ if (typeof propValue !== 'object') {
+ if (propValue) {
+ appliedVariants[prop] = propValue;
}
+ return styleSheet[styleSheetKey];
}
- const extractedStyle = styleSheetKey
- ? styleSheet[styleSheetKey]
- : undefined;
-
- if (extractedStyle && breakpoint in extractedStyle) {
- // WARNING: lodash merge modifies the first argument reference or skips if object is frozen.
- return merge({}, extractedStyle, extractedStyle[breakpoint]);
- }
+ const matchedMediasDetected = [
+ {
+ mediaKey: 'initial',
+ breakpoint: '@initial',
+ },
+ ...matchedMedias,
+ ];
+
+ // NOTE: Even if multiple values are matched, restict variant value is last matched and
+ // compensated to be determined uniquely.
+ const finalVariantStyle = matchedMediasDetected.reduce(
+ (currentStyle, matchedMedia) => {
+ const breakpoint = matchedMedia.breakpoint;
+ if (breakpoint && propValue[breakpoint] !== undefined) {
+ const styleSheetKey = `${prop}_${propValue[breakpoint]}`;
+ const extractedStyle = styleSheet[styleSheetKey];
+ if (extractedStyle) {
+ appliedVariants[prop] = propValue[breakpoint];
+ return extractedStyle;
+ }
+ }
+ return currentStyle;
+ },
+ {}
+ );
- return extractedStyle;
+ return finalVariantStyle;
})
.filter(Boolean);
}
@@ -198,25 +194,19 @@ export function createStitches(config = {}) {
if (
compoundEntries.every(([prop, value]) => {
- const propValue = props[prop] ?? defaultVariants[prop];
+ const propValue =
+ appliedVariants[prop] ?? defaultVariants[prop];
return propValue === value;
})
) {
const key = utils.getCompoundKey(compoundEntries);
- const extractedStyle = styleSheet[key];
-
- if (extractedStyle && breakpoint in extractedStyle) {
- // WARNING: lodash merge modifies the first argument reference or skips if object is frozen.
- return merge({}, extractedStyle, extractedStyle[breakpoint]);
- }
-
- return extractedStyle;
+ return styleSheet[key];
}
})
.filter(Boolean);
}
- let cssStyles = props.css
+ const cssStyles = props.css
? utils.processStyles({
styles: props.css || {},
theme: theme.values,
@@ -224,20 +214,12 @@ export function createStitches(config = {}) {
})
: {};
- if (cssStyles && breakpoint in cssStyles) {
- // WARNING: lodash merge modifies the first argument reference or skips if object is frozen.
- cssStyles = merge({}, cssStyles, cssStyles[breakpoint]);
- }
-
- const mediaStyle = styleSheet.base[breakpoint] || {};
-
const stitchesStyles = [
styleSheet.base,
- mediaStyle,
...variantStyles,
...compoundVariantStyles,
cssStyles,
- ];
+ ].map((style) => utils.applyMediaStyles(style, matchedMedias));
const allStyles =
typeof props.style === 'function'
diff --git a/src/internals/utils.js b/src/internals/utils.js
index 81e10d6..bc356ba 100644
--- a/src/internals/utils.js
+++ b/src/internals/utils.js
@@ -59,24 +59,41 @@ function matchMediaRangeQuery(query, windowWidth) {
return result;
}
-export function resolveMediaRangeQuery(media, windowWidth) {
- const entries = Object.entries(media);
- let result;
-
- for (let i = 0; i < entries.length; i++) {
- const [breakpoint, queryOrFlag] = entries[i];
-
- // TODO: handle boolean flag
- if (typeof queryOrFlag !== 'string') continue;
-
- const match = matchMediaRangeQuery(queryOrFlag, windowWidth);
+function createMatchedMedia(mediaKey) {
+ return {
+ mediaKey: mediaKey,
+ breakpoint: mediaKey && `@${mediaKey}`,
+ };
+}
+export function resolveMediaRangeQuery(queryObjects, windowWidth) {
+ const iterator = Object.entries(queryObjects);
+ const mediaAppliedKeys = [];
+ for (let i = 0; i < iterator.length; i++) {
+ const [key, query] = iterator[i];
+ if (query === true) {
+ mediaAppliedKeys.push(createMatchedMedia(key));
+ }
+ if (typeof query !== 'string') continue;
+ const match = matchMediaRangeQuery(query, windowWidth);
if (match) {
- result = breakpoint;
+ mediaAppliedKeys.push(createMatchedMedia(key));
}
}
+ return mediaAppliedKeys;
+}
- return result;
+export function applyMediaStyles(originalStyle, matchedMedias) {
+ return matchedMedias.reduce(
+ (currentStyle, matcheMedia) => {
+ const breakpoint = matcheMedia.breakpoint;
+ if (breakpoint && breakpoint in originalStyle) {
+ return merge(currentStyle, originalStyle[breakpoint]);
+ }
+ return currentStyle;
+ },
+ { ...originalStyle }
+ );
}
export function processThemeMap(themeMap) {