mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-21 04:39:19 +00:00
Implement breakpointObserver.
Drop breakpoints constant export from Breakpoint component. Expose breakpoints constant separately and freeze it. Change `match` event to 'change`, because it is now based on store and captures initial value change. Issues: - Wrong exports in types/index.d.ts - Typedefs lost from docs.
This commit is contained in:
parent
acf8a26290
commit
2cd2872274
10 changed files with 115 additions and 121 deletions
|
@ -1,8 +1,6 @@
|
|||
<script>
|
||||
/**
|
||||
* @typedef {"sm" | "md" | "lg" | "xlg" | "max"} BreakpointSize
|
||||
* @typedef {320 | 672 | 1056 | 1312 | 1584} BreakpointValue
|
||||
* @event {{ size: BreakpointSize; breakpointValue: BreakpointValue; }} match
|
||||
* @event {{ size: BreakpointSize; breakpointValue: BreakpointValue; }} change
|
||||
* @slot {{ size: BreakpointSize; sizes: Record<BreakpointSize, boolean>; }}
|
||||
*/
|
||||
|
||||
|
@ -24,77 +22,23 @@
|
|||
max: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Reference the Carbon grid breakpoints
|
||||
* @type {Record<BreakpointSize, BreakpointValue>}
|
||||
*/
|
||||
export const breakpoints = {
|
||||
sm: 320,
|
||||
md: 672,
|
||||
lg: 1056,
|
||||
xlg: 1312,
|
||||
max: 1584,
|
||||
};
|
||||
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { breakpointObserver } from "./breakpointObserver";
|
||||
import { breakpoints } from "./constants";
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const observer = breakpointObserver();
|
||||
|
||||
onMount(() => {
|
||||
const width = window.innerWidth;
|
||||
|
||||
if (width > breakpoints.max) size = "max";
|
||||
else if (width < breakpoints.md) size = "sm";
|
||||
else if (width >= breakpoints.md && width <= breakpoints.lg) size = "md";
|
||||
else if (width >= breakpoints.lg && width <= breakpoints.xlg) size = "lg";
|
||||
else if (width >= breakpoints.xlg && width <= breakpoints.max) size = "xlg";
|
||||
|
||||
const match = {
|
||||
sm: window.matchMedia(`(max-width: ${breakpoints.md}px)`),
|
||||
md: window.matchMedia(
|
||||
`(min-width: ${breakpoints.md}px) and (max-width: ${breakpoints.lg}px)`
|
||||
),
|
||||
lg: window.matchMedia(
|
||||
`(min-width: ${breakpoints.lg}px) and (max-width: ${breakpoints.xlg}px)`
|
||||
),
|
||||
xlg: window.matchMedia(
|
||||
`(min-width: ${breakpoints.xlg}px) and (max-width: ${breakpoints.max}px)`
|
||||
),
|
||||
max: window.matchMedia(`(min-width: ${breakpoints.max}px)`),
|
||||
};
|
||||
const matchers = Object.entries(match);
|
||||
const matchersBySize = Object.fromEntries(
|
||||
matchers.map(([size, queryList]) => [queryList.media, size])
|
||||
);
|
||||
|
||||
function handleChange({ matches, media }) {
|
||||
const size = matchersBySize[media];
|
||||
|
||||
sizes = { ...sizes };
|
||||
sizes[size] = matches;
|
||||
|
||||
if (matches)
|
||||
dispatch("match", { size, breakpointValue: breakpoints[size] });
|
||||
}
|
||||
|
||||
matchers.forEach(([size, queryList]) =>
|
||||
queryList.addEventListener("change", handleChange)
|
||||
);
|
||||
|
||||
return () => {
|
||||
matchers.forEach(([size, queryList]) =>
|
||||
queryList.removeEventListener("change", handleChange)
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
$: {
|
||||
if (sizes.sm) size = "sm";
|
||||
if (sizes.md) size = "md";
|
||||
if (sizes.lg) size = "lg";
|
||||
if (sizes.xlg) size = "xlg";
|
||||
if (sizes.max) size = "max";
|
||||
}
|
||||
$: size = $observer;
|
||||
$: sizes = {
|
||||
sm: size == "sm",
|
||||
md: size == "md",
|
||||
lg: size == "lg",
|
||||
xlg: size == "xlg",
|
||||
max: size == "max",
|
||||
};
|
||||
$: if (size != undefined)
|
||||
dispatch("change", { size, breakpointValue: breakpoints[size] });
|
||||
</script>
|
||||
|
||||
<slot size="{size}" sizes="{sizes}" />
|
||||
|
|
71
src/Breakpoint/breakpointObserver.js
Normal file
71
src/Breakpoint/breakpointObserver.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
/// <reference path="./types.d.ts"/>
|
||||
|
||||
import { onMount } from "svelte";
|
||||
import { derived, writable } from "svelte/store";
|
||||
import { breakpoints } from "./constants";
|
||||
|
||||
/**
|
||||
* Creates a readable store that returns the current {@link BreakpointSize}.
|
||||
* It also provides functions for creating derived stores used to do comparisons.
|
||||
*/
|
||||
export function breakpointObserver() {
|
||||
const store = writable(undefined);
|
||||
|
||||
onMount(() => {
|
||||
/** @type {Record<BreakpointSize, MediaQueryList>} */
|
||||
const match = {
|
||||
sm: window.matchMedia(`(max-width: ${breakpoints.md}px)`),
|
||||
md: window.matchMedia(
|
||||
`(min-width: ${breakpoints.md}px) and (max-width: ${breakpoints.lg}px)`
|
||||
),
|
||||
lg: window.matchMedia(
|
||||
`(min-width: ${breakpoints.lg}px) and (max-width: ${breakpoints.xlg}px)`
|
||||
),
|
||||
xlg: window.matchMedia(
|
||||
`(min-width: ${breakpoints.xlg}px) and (max-width: ${breakpoints.max}px)`
|
||||
),
|
||||
max: window.matchMedia(`(min-width: ${breakpoints.max}px)`),
|
||||
};
|
||||
const matchers = Object.entries(match);
|
||||
const sizeByMedia = Object.fromEntries(
|
||||
matchers.map(([size, queryList]) => [queryList.media, size])
|
||||
);
|
||||
|
||||
const size = matchers.find(([size, queryList]) => queryList.matches)[0];
|
||||
store.set(size);
|
||||
|
||||
/** @type {(e: MediaQueryListEvent) => void} */
|
||||
function handleChange({ matches, media }) {
|
||||
const size = sizeByMedia[media];
|
||||
if (matches) store.set(size);
|
||||
}
|
||||
|
||||
matchers.forEach(([size, queryList]) =>
|
||||
queryList.addEventListener("change", handleChange)
|
||||
);
|
||||
|
||||
return () => {
|
||||
matchers.forEach(([size, queryList]) =>
|
||||
queryList.removeEventListener("change", handleChange)
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
subscribe: store.subscribe,
|
||||
/**
|
||||
* Returns a store readable store that returns whether the current
|
||||
* breakpoint smaller than {@link size}.
|
||||
* @param {BreakpointSize} size Size to compare against.
|
||||
*/
|
||||
smallerThan: (size) =>
|
||||
derived(store, ($size) => breakpoints[$size] < breakpoints[size]),
|
||||
/**
|
||||
* Returns a store readable store that returns whether the current
|
||||
* breakpoint larger than {@link size}.
|
||||
* @param {BreakpointSize} size Size to compare against.
|
||||
*/
|
||||
largerThan: (size) =>
|
||||
derived(store, ($size) => breakpoints[$size] > breakpoints[size]),
|
||||
};
|
||||
}
|
13
src/Breakpoint/constants.js
Normal file
13
src/Breakpoint/constants.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/// <reference path="./types.d.ts"/>
|
||||
|
||||
/**
|
||||
* Pixel sizes of Carbon grid breakpoints.
|
||||
* @type {Record<BreakpointSize, BreakpointValue>}
|
||||
*/
|
||||
export const breakpoints = Object.freeze({
|
||||
sm: 320,
|
||||
md: 672,
|
||||
lg: 1056,
|
||||
xlg: 1312,
|
||||
max: 1584,
|
||||
});
|
|
@ -1 +1,3 @@
|
|||
export { default as Breakpoint } from "./Breakpoint.svelte";
|
||||
export { breakpointObserver } from "./breakpointObserver";
|
||||
export { breakpoints } from "./constants";
|
||||
|
|
2
src/Breakpoint/types.d.ts
vendored
Normal file
2
src/Breakpoint/types.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
declare type BreakpointSize = "sm" | "md" | "lg" | "xlg" | "max";
|
||||
declare type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584;
|
|
@ -1,7 +1,7 @@
|
|||
export { Accordion, AccordionItem, AccordionSkeleton } from "./Accordion";
|
||||
export { AspectRatio } from "./AspectRatio";
|
||||
export { Breadcrumb, BreadcrumbItem, BreadcrumbSkeleton } from "./Breadcrumb";
|
||||
export { Breakpoint } from "./Breakpoint";
|
||||
export { Breakpoint, breakpoints, breakpointObserver } from "./Breakpoint";
|
||||
export { Button, ButtonSkeleton, ButtonSet } from "./Button";
|
||||
export { Checkbox, CheckboxSkeleton } from "./Checkbox";
|
||||
export { ContentSwitcher, Switch } from "./ContentSwitcher";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue