From 2cd2872274dd7759d6eb63a7a71fe1bd6c92b125 Mon Sep 17 00:00:00 2001 From: Harald Brunner Date: Sat, 12 Feb 2022 16:31:08 +0100 Subject: [PATCH] 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. --- COMPONENT_INDEX.md | 19 ++---- docs/src/COMPONENT_API.json | 26 +------- src/Breakpoint/Breakpoint.svelte | 86 +++++-------------------- src/Breakpoint/breakpointObserver.js | 71 ++++++++++++++++++++ src/Breakpoint/constants.js | 13 ++++ src/Breakpoint/index.js | 2 + src/Breakpoint/types.d.ts | 2 + src/index.js | 2 +- types/Breakpoint/Breakpoint.svelte.d.ts | 13 +--- types/index.d.ts | 2 + 10 files changed, 115 insertions(+), 121 deletions(-) create mode 100644 src/Breakpoint/breakpointObserver.js create mode 100644 src/Breakpoint/constants.js create mode 100644 src/Breakpoint/types.d.ts diff --git a/COMPONENT_INDEX.md b/COMPONENT_INDEX.md index 52610ed0..4c5249f1 100644 --- a/COMPONENT_INDEX.md +++ b/COMPONENT_INDEX.md @@ -348,21 +348,12 @@ None. ## `Breakpoint` -### Types - -```ts -export type BreakpointSize = "sm" | "md" | "lg" | "xlg" | "max"; - -export type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584; -``` - ### Props -| Prop name | Kind | Reactive | Type | Default value | Description | -| :---------- | :----------------- | :------- | :--------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------- | -| sizes | let | Yes | Record | { sm: false, md: false, lg: false, xlg: false, max: false, } | Carbon grid sizes as an object | -| size | let | Yes | BreakpointSize | undefined | Determine the current Carbon grid breakpoint size | -| breakpoints | const | No | Record | { sm: 320, md: 672, lg: 1056, xlg: 1312, max: 1584, } | Reference the Carbon grid breakpoints | +| Prop name | Kind | Reactive | Type | Default value | Description | +| :-------- | :--------------- | :------- | :------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------- | +| sizes | let | Yes | Record | { sm: false, md: false, lg: false, xlg: false, max: false, } | Carbon grid sizes as an object | +| size | let | Yes | BreakpointSize | undefined | Determine the current Carbon grid breakpoint size | ### Slots @@ -374,7 +365,7 @@ export type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584; | Event name | Type | Detail | | :--------- | :--------- | :----------------------------------------------------------------------- | -| match | dispatched | { size: BreakpointSize; breakpointValue: BreakpointValue; } | +| change | dispatched | { size: BreakpointSize; breakpointValue: BreakpointValue; } | ## `Button` diff --git a/docs/src/COMPONENT_API.json b/docs/src/COMPONENT_API.json index 26b3b972..7b5c2ea3 100644 --- a/docs/src/COMPONENT_API.json +++ b/docs/src/COMPONENT_API.json @@ -387,17 +387,6 @@ "isFunctionDeclaration": false, "constant": false, "reactive": true - }, - { - "name": "breakpoints", - "kind": "const", - "description": "Reference the Carbon grid breakpoints", - "type": "Record", - "value": "{ sm: 320, md: 672, lg: 1056, xlg: 1312, max: 1584, }", - "isFunction": false, - "isFunctionDeclaration": false, - "constant": true, - "reactive": false } ], "slots": [ @@ -410,22 +399,11 @@ "events": [ { "type": "dispatched", - "name": "match", + "name": "change", "detail": "{ size: BreakpointSize; breakpointValue: BreakpointValue; }" } ], - "typedefs": [ - { - "type": "\"sm\" | \"md\" | \"lg\" | \"xlg\" | \"max\"", - "name": "BreakpointSize", - "ts": "type BreakpointSize = \"sm\" | \"md\" | \"lg\" | \"xlg\" | \"max\"" - }, - { - "type": "320 | 672 | 1056 | 1312 | 1584", - "name": "BreakpointValue", - "ts": "type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584" - } - ] + "typedefs": [] }, { "moduleName": "Button", diff --git a/src/Breakpoint/Breakpoint.svelte b/src/Breakpoint/Breakpoint.svelte index 19ef305f..740d6ea2 100644 --- a/src/Breakpoint/Breakpoint.svelte +++ b/src/Breakpoint/Breakpoint.svelte @@ -1,8 +1,6 @@ diff --git a/src/Breakpoint/breakpointObserver.js b/src/Breakpoint/breakpointObserver.js new file mode 100644 index 00000000..7d54d7d3 --- /dev/null +++ b/src/Breakpoint/breakpointObserver.js @@ -0,0 +1,71 @@ +/// + +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} */ + 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]), + }; +} diff --git a/src/Breakpoint/constants.js b/src/Breakpoint/constants.js new file mode 100644 index 00000000..31d83113 --- /dev/null +++ b/src/Breakpoint/constants.js @@ -0,0 +1,13 @@ +/// + +/** + * Pixel sizes of Carbon grid breakpoints. + * @type {Record} + */ +export const breakpoints = Object.freeze({ + sm: 320, + md: 672, + lg: 1056, + xlg: 1312, + max: 1584, +}); diff --git a/src/Breakpoint/index.js b/src/Breakpoint/index.js index a84d174b..5a25c354 100644 --- a/src/Breakpoint/index.js +++ b/src/Breakpoint/index.js @@ -1 +1,3 @@ export { default as Breakpoint } from "./Breakpoint.svelte"; +export { breakpointObserver } from "./breakpointObserver"; +export { breakpoints } from "./constants"; diff --git a/src/Breakpoint/types.d.ts b/src/Breakpoint/types.d.ts new file mode 100644 index 00000000..dc6f50b0 --- /dev/null +++ b/src/Breakpoint/types.d.ts @@ -0,0 +1,2 @@ +declare type BreakpointSize = "sm" | "md" | "lg" | "xlg" | "max"; +declare type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584; diff --git a/src/index.js b/src/index.js index 0b8733d3..a57b29e7 100644 --- a/src/index.js +++ b/src/index.js @@ -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"; diff --git a/types/Breakpoint/Breakpoint.svelte.d.ts b/types/Breakpoint/Breakpoint.svelte.d.ts index b46f0c3e..f247939e 100644 --- a/types/Breakpoint/Breakpoint.svelte.d.ts +++ b/types/Breakpoint/Breakpoint.svelte.d.ts @@ -1,10 +1,6 @@ /// import { SvelteComponentTyped } from "svelte"; -export type BreakpointSize = "sm" | "md" | "lg" | "xlg" | "max"; - -export type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584; - export interface BreakpointProps { /** * Determine the current Carbon grid breakpoint size @@ -22,15 +18,10 @@ export interface BreakpointProps { export default class Breakpoint extends SvelteComponentTyped< BreakpointProps, { - match: CustomEvent<{ + change: CustomEvent<{ size: BreakpointSize; breakpointValue: BreakpointValue; }>; }, { default: { size: BreakpointSize; sizes: Record } } -> { - /** - * Reference the Carbon grid breakpoints - */ - breakpoints: Record; -} +> {} diff --git a/types/index.d.ts b/types/index.d.ts index 2aed619a..2df62c5b 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -6,6 +6,8 @@ export { default as Breadcrumb } from "./Breadcrumb/Breadcrumb.svelte"; export { default as BreadcrumbItem } from "./Breadcrumb/BreadcrumbItem.svelte"; export { default as BreadcrumbSkeleton } from "./Breadcrumb/BreadcrumbSkeleton.svelte"; export { default as Breakpoint } from "./Breakpoint/Breakpoint.svelte"; +export { default as breakpoints } from "./Breakpoint"; +export { default as breakpointObserver } from "./Breakpoint"; export { default as Button } from "./Button/Button.svelte"; export { default as ButtonSkeleton } from "./Button/ButtonSkeleton.svelte"; export { default as ButtonSet } from "./Button/ButtonSet.svelte";