Edit on StackBlitz
"use client";
import { useEffect, useRef } from "react";
import { LayoutWatcher, LayoutData, LayoutTrigger, Show } from "lisn.js";
import "lisn.js/base.css";
import styles from "./demo.module.css";
export default function Page() {
const boxRef = useRef<HTMLDivElement>(null);
const msgRef = useRef<HTMLHeadingElement>(null);
const windowLayoutMsgRef = useRef<HTMLParagraphElement>(null);
const boxLayoutMsgRef = useRef<HTMLParagraphElement>(null);
useEffect(() => {
// box layout
const box = boxRef.current;
const msg = boxLayoutMsgRef.current;
const handler = (layout: LayoutData) => {
const { device, aspectRatio } = layout;
if (msg && device && aspectRatio) {
msg.innerText =
`The resizable box below has a ${formatLayout(device)} width ` +
`and a ${formatLayout(aspectRatio)} aspect ratio.`;
}
};
let watcher: LayoutWatcher;
if (box) {
watcher = LayoutWatcher.create({ root: box });
watcher.onLayout(handler);
}
return () => {
// cleanup
watcher?.offLayout(handler);
};
}, []);
useEffect(() => {
// window layout
const msg = windowLayoutMsgRef.current;
const handler = (layout: LayoutData) => {
const { device, aspectRatio } = layout;
if (msg && device && aspectRatio) {
msg.innerText =
`This is a ${formatLayout(device)} device ` +
`with a ${formatLayout(aspectRatio)} aspect ratio.`;
}
};
const watcher = LayoutWatcher.reuse();
watcher.onLayout(handler);
return () => {
// cleanup
watcher.offLayout(handler);
};
}, []);
useEffect(() => {
// You could also use LayoutWatcher directly and show/hide the element in
// your callback
const msg = msgRef.current;
let trigger: LayoutTrigger;
if (msg) {
trigger = new LayoutTrigger(msg, [new Show(msg)], {
layout: "max tablet",
});
}
return () => {
// cleanup
trigger?.destroy();
};
}, []);
return (
<>
<div className={styles.wrapper}>
<h4 ref={msgRef} className={[styles.msg, "lisn-hide"].join(" ")}>
This demo is best viewed on a computer.
</h4>
<div className={styles.demo}>
<p ref={windowLayoutMsgRef}></p>
<p ref={boxLayoutMsgRef}></p>
<div ref={boxRef} className={styles.box}></div>
</div>
</div>
</>
);
}
const layoutMapping: { [K in string]: string } = {
"mobile-wide": "mobile (landscape)",
square: "roughly square",
};
const formatLayout = (l: string) =>
(l in layoutMapping ? layoutMapping[l] : l).replace(/-/g, " ");
/* Container */
.wrapper {
position: fixed;
top: 0;
left: 0;
width: 100vw;
width: 100dvw;
height: 100vh;
height: 100dvh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
}
.demo {
text-align: center;
width: 100%;
padding: 1em;
}
.box {
margin: 0 auto;
width: 400px;
height: 400px;
resize: both;
background: var(--bg-color-lighter);
box-shadow: var(--lisn-shadow);
overflow: hidden;
}
Edit on CodePen
document.addEventListener("DOMContentLoaded", () => {
const layoutMapping = {
"mobile-wide": "mobile (landscape)",
square: "roughly square",
};
const formatLayout = (l) => (layoutMapping[l] ?? l).replace(/-/g, " ");
const main = document.getElementById("demo");
const box = main.querySelector(".box");
const windowLayout = main.querySelector(".window-layout");
const boxLayout = main.querySelector(".box-layout");
LISN.watchers.LayoutWatcher.reuse().onLayout((layout) => {
windowLayout.innerText =
`This is a ${formatLayout(layout.device)} device ` +
`with a ${formatLayout(layout.aspectRatio)} aspect ratio.`;
});
LISN.watchers.LayoutWatcher.create({ root: box }).onLayout((layout) => {
boxLayout.innerText =
`The resizable box below has a ${formatLayout(layout.device)} width ` +
`and a ${formatLayout(layout.aspectRatio)} aspect ratio.`;
});
const msg = document.getElementById("msg");
// or you could use LayoutWatcher directly and show/hide the element in your callback
new LISN.triggers.LayoutTrigger(msg, [new LISN.actions.Show(msg)], {
layout: "max tablet",
});
});
<h4 id="msg">This demo is best viewed on a computer.</h4>
<div id="demo">
<p class="window-layout"></p>
<p class="box-layout"></p>
<div class="box"></div>
</div>
#demo {
text-align: center;
width: 100%;
padding: 1em;
}
#demo .box {
margin: 0 auto;
width: 400px;
height: 400px;
resize: both;
background: #28283f;
box-shadow: var(--lisn-shadow);
overflow: hidden;
}
Edit on CodePen
<h4 data-lisn-on-layout="max tablet @show">
This demo is best viewed on a computer.
</h4>
<div id="demo">
<p>
This is a
<span data-lisn-on-layout="mobile @display">mobile</span>
<span data-lisn-on-layout="mobile-wide @display"
>mobile (landscape)</span
>
<span data-lisn-on-layout="tablet @display">tablet</span>
<span data-lisn-on-layout="desktop @display">desktop</span>
device with a
<span data-lisn-on-layout="very-wide @display">very-wide</span>
<span data-lisn-on-layout="wide @display">wide</span>
<span data-lisn-on-layout="square @display">roughly square</span>
<span data-lisn-on-layout="tall @display">tall</span>
<span data-lisn-on-layout="very-tall @display">very tall</span>
aspect ratio.
</p>
<p>
The resizable box below has a
<span data-lisn-on-layout="mobile @display +root=next.box"
>mobile</span
>
<span data-lisn-on-layout="mobile-wide @display +root=next.box"
>mobile (landscape)</span
>
<span data-lisn-on-layout="tablet @display +root=next.box"
>tablet</span
>
<span data-lisn-on-layout="desktop @display +root=next.box"
>desktop</span
>
width and a
<span data-lisn-on-layout="very-wide @display +root=next.box"
>very-wide</span
>
<span data-lisn-on-layout="wide @display +root=next.box">wide</span>
<span data-lisn-on-layout="square @display +root=next.box"
>roughly square</span
>
<span data-lisn-on-layout="tall @display +root=next.box">tall</span>
<span data-lisn-on-layout="very-tall @display +root=next.box"
>very tall</span
>
aspect ratio.
</p>
<div class="box"></div>
</div>
#demo {
text-align: center;
width: 100%;
padding: 1em;
}
#demo .box {
margin: 0 auto;
width: 400px;
height: 400px;
resize: both;
background: #28283f;
box-shadow: var(--lisn-shadow);
overflow: hidden;
}