The AppSizeListener
component is used to determine the current application
size based on media queries. You normally want to add this component near the
root of your app and then use the useAppSize
hook to determine the current app
size within child components.
If you are using the @react-md/layout package, this will be handled for you automatically.
The current app size will contain the following keys:
interface AppSize {
isPhone: boolean;
isTablet: boolean;
isDesktop: boolean;
isLargeDesktop: boolean;
isLandscape: boolean;
}
which will be determined by different min and max widths passed into the
AppSizeListener
component.
The default breakpoints and media queries will be:
const isPhone = "screen and (max-width: 767px)";
const isTablet = "screen and (min-width: 768px) and (max-width: 1024px)";
const isDesktop = "screen and (min-width: 1025px)";
const isLargeDesktop = "screen and (min-width: 1280px)";
const isLandscape = window.innerWidth > window.innerHeight;
The media queries will actually be using
em
instead of pixels, but I converted this example to pixels for human readability.
{
"isPhone": false,
"isTablet": false,
"isDesktop": true,
"isLargeDesktop": false,
"isLandscape": true
}
This package also exports some helper components that allow you to render
specific parts only when the AppSize
matches specific devices. Since I want to
try to keep the app size minimal, the default helper components are:
PhoneOnly
TabletOnly
DesktopOnly
MobileOnly
You can always hook into the AppSizeContext
and implement more specific
implementations if the need arises in your app.
This package also exposes some mixins that allow you to apply styles at specific breakpoints as well:
rmd-utils-phone-media
rmd-utils-tablet-only-media
rmd-utils-tablet-media
rmd-utils-desktop-media
rmd-utils-large-desktop-media
The rmd-utils-phone-media
and rmd-utils-tablet-only-media
will be the only
mixins that allow for the breakpoints to prevent styles in large screen sizes
while the rmd-utils-tablet-media
, rmd-utils-desktop-media
and
rmd-utils-large-desktop-media
will work by using the min-width
of the
specific media matcher.
The example below will showcase the *Only
components and render text when the
app size matches as well as a few examples of using the mixins to add dynamic
styles based on the screen size.
This will only appear on desktop screen sizes.
This section will gain different styles as the viewport increases. I highly recommend opening the dev tools and seeing how the different styles get applied and when some are completely removed to get a better understanding of the media queries.
This package also exports a ResizeListener
component that will listen to
entire window resize events while mounted. The resize event callback will be
throttled for extra performance as well as delegating the event using the
@react-md/utils delegateEvent
helper. This is extremely useful when you need to track
specific pixel updates instead of breakpoint changes.
The example below will update the current app size in pixels while the listener
is enabled. You can toggle the two checkboxes to see the different behavior for
the immediate
prop and how the ResizeListener
stops triggering callbacks
while unmounted.
The current app size is:
0px
The useResizeObserver
hook is useful when you want to watch a specific element
resize when it can't be handled just by an entire page resize listener. The
ResizeObserver
is useful when you want to watch a specific element resizing
when it can't be handled just by an entire page resize listener. This hook
returns an ordered list containing a ref
object containing the current element
if you need access to that element and a refHandler
that should be passed to
the target element.
The example below will animating between different max heights and max widths
once the "Start" button is pressed and show the current height
and width
values within the table.
Height: | 110 |
---|---|
Width: | 150 |
The grid system in material design is a bit confusing if you are coming from another CSS grid system like the bootstrap grid system since the number of columns changes depending on the viewport size. The grid system will have:
The dynamic columns are actually pretty nice since having a cell that spans 1 column on desktop and 1 column on mobile would normally have an extremely small column on mobile. However, the second you start using cells that span more than one column, it becomes a bit harder to layout your grid. The grid has some "safeguarding" built in so that if you attempt to make a cell span more columns than available at the current viewport, it will update itself to just be full width instead.
The example below will show some examples of rendering cells and spanning a few
columns by using the Grid
and GridCell
components.
Note: You can opt out of this behavior and have static columns by either setting the
$rmd-grid-columns
variable or by providing acolumns
prop to theGrid
component. This component also relies on theAppSizeListener
as a parent component for media query updates and will throw an error if it does not exist.
Most grid systems define a static number of columns that should appear on each row and have each cell have a percentage width based on how many columns they should span. One of the most well-known ones is the bootstrap grid system that defines a 12 column grid system. This is nice for a lot of cases, but it is a bit restrictive since you'll need to test every single viewport width to ensure that each cell shows up nicely and add additional breakpoints to increase cell width as needed. What if you just want to say:
"I don't care how many columns there are at a time, but each cell should grow
up to X
px and columns should be added as needed"?"
This is where the GridList
component comes in handy since that's exactly what
it does. This component will try to show as many columns as possible by trying
to render as many "full width" cells as possible until it reaches the
container's width. If there is still some leftover room, each cell will shrink
and a new column will be added.
The example below will allow you to configure:
top
, right
,
bottom
, and left
of each cellThe
containerPadding
prop is a bit weird as it is really the total number of pixels to subtract from thecontainer.offsetWidth
sincepadding
andborder
widths are included. TheGridList
will automatically subtract the current visible scrollbar width (if the OS renders them inline with content), but there isn't anything built in at this time to subtract padding and border for performance concerns. It's much easier to just update this value if you change the padding or add a border to this component.
The current number of columns and the size of each column can be retrieved
either with the useGridListSize
hook or using the "children render function"
pattern. If you want to use the children render function pattern, a quick
example is:
<GridList>
{({ columns, cellWidth }) => (
<GridListCell>
Columns: {columns}
<br />
Cell Width: {cellWidth}
</GridListCell>
)}
</GridList>
However, the hook API is easier to understand so the following example will use
the useGridListSize
hook instead.
Note: The grid list size will be
0
if server side rendering since theGridList
requires access to the DOM to calculate sizing.
Columns: | -1 |
---|---|
Cell Width: | 150 |
react-md@2.8.0
introduces a new public hover mode API that allows different
temporary elements like tooltips and popover dialogs to appear immediately after
an element has been hovered instead of waiting the default hover duration
(1s
). To use this functionality you'll need to:
HoverModeProvider
or Configuration
(from @react-md/layout) component as
a parent componentuseHoverMode
hook to provide the mouse event handlers, visibility,
and other functionalityI recommend checking out the useHoverMode type definitions for more information around what's returned.
The example below will show how you can use the hover mode API to create a Wikipedia-like preview window while hovering over links.
Material Design (codenamed Quantum Paper) Design Language "card" motifs that debuted in Google Now , Material Design uses more grid-based layouts, responsive animations and transitions, padding, and depth effects such as lighting and shadows. Google announced Material Design on June 25, 2014, at the 2014 Google I/O conference.
The useHoverMode
hook can also be updated to implement a "sticky" spec that
allows the user to click the element to toggle the visibility state. Once the
element has been clicked, the onMouseEnter
and onMouseLeave
behavior will be
disabled until the visibility is set to false
once more.