Skip to content

Instantly share code, notes, and snippets.

@itaditya
Created March 17, 2022 10:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save itaditya/a168e78596f63adcee7f92a3a6fdef81 to your computer and use it in GitHub Desktop.
Save itaditya/a168e78596f63adcee7f92a3a6fdef81 to your computer and use it in GitHub Desktop.
Mobile-first match breakpoints
import { render } from "solid-js/web";
import { createSignal, createEffect, createMemo, onCleanup, Show, Switch, Match } from "solid-js";
interface ArrayLike<T> {
readonly length: number;
readonly [n: number]: T;
}
function objectEntries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][] {
return Object.entries(o);
}
type MqlInstances = Record<string, MediaQueryList>;
function createMatchBreakpoints(breakpoints: Record<string, string>) {
const mqlInstances = createMemo(() => {
const mqlInstances: MqlInstances = {};
objectEntries(breakpoints).forEach(([token, width]) => {
const mediaquery = `(min-width: ${width})`;
const instance = window.matchMedia(mediaquery);
mqlInstances[token] = instance;
});
return mqlInstances;
});
function getInitialMatches() {
const matches = {};
objectEntries(mqlInstances()).forEach(([token, mql]) => {
matches[token] = mql.matches;
});
return matches;
}
const [matches, setMatches] = createSignal(getInitialMatches());
function minMatch(token: string) {
const isMatching = matches()[token];
return Boolean(isMatching);
}
createEffect(() => {
objectEntries(mqlInstances()).forEach(([token, mql]) => {
const listener = (event: MediaQueryListEvent) => {
setMatches((prev) => {
return {
...prev,
[token]: event.matches,
};
});
};
mql.addEventListener("change", listener);
onCleanup(() => {
mql.removeEventListener("change", listener);
});
});
});
return {
minMatch,
matches,
};
}
const breakpoints = {
sm: "640px",
md: "768px",
lg: "1024px",
xl: "1280px",
} as const;
function Widget() {
const { minMatch } = createMatchBreakpoints(breakpoints);
return (
<div>
<h3>Try resizing window</h3>
<Switch fallback={<div>Smallest</div>}>
<Match when={minMatch('xl')}>Extra Large</Match>
<Match when={minMatch('lg')}>Large</Match>
<Match when={minMatch('md')}>Medium</Match>
<Match when={minMatch('sm')}>Small</Match>
</Switch>
</div>
);
}
function App() {
const [toggle, setToggle] = createSignal(true);
return (
<div>
<button type="button" onClick={() => setToggle((old) => !old)}>
Toggle
</button>
<Show when={toggle()}>
<Widget />
</Show>
</div>
);
}
render(() => <App />, document.getElementById("app"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment