Skip to content

Commit 522aaa4

Browse files
lukasIOOcupe
andauthored
Responsive auto grid (#242)
* wip * responsive auto grid * add gitignore to nextjs * handle alone in the room * fix import Co-authored-by: Jonas Schell <[email protected]>
1 parent 50afbb8 commit 522aaa4

File tree

6 files changed

+73
-35
lines changed

6 files changed

+73
-35
lines changed

packages/react/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"dependencies": {
3939
"@floating-ui/react": "^0.15.1",
4040
"@livekit/components-core": "0.1.12",
41+
"@react-hook/resize-observer": "^1.2.6",
4142
"clsx": "^1.2.1"
4243
},
4344
"peerDependencies": {
@@ -61,4 +62,4 @@
6162
"publishConfig": {
6263
"access": "public"
6364
}
64-
}
65+
}

packages/react/src/components/layout/GridLayout.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { TileLoop } from '../TileLoop';
33
import { ParticipantFilter, useParticipants } from '../../hooks';
4-
import { mergeProps } from '../../utils';
4+
import { mergeProps, useSize } from '../../utils';
55

66
export interface GridLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
77
/**
@@ -25,22 +25,33 @@ export interface GridLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
2525
*/
2626
export function GridLayout({ filter, filterDependencies, ...props }: GridLayoutProps) {
2727
const participants = useParticipants({ filter, filterDependencies });
28+
const containerEl = React.createRef<HTMLDivElement>();
2829
const gridEl = React.createRef<HTMLDivElement>();
2930

31+
const { width, height } = useSize(containerEl);
32+
3033
React.useEffect(() => {
31-
gridEl.current?.style.setProperty('--lk-p-count', participants.length.toFixed(0));
32-
gridEl.current?.style.setProperty(
33-
'--lk-col-count',
34-
Math.ceil(Math.sqrt(participants.length)).toString(),
35-
);
36-
}, [participants, gridEl]);
34+
const containerRatio = width / height;
35+
const tileRatio = 16 / 10;
36+
const colAdjust = Math.sqrt(containerRatio / tileRatio);
37+
const colFraction = Math.sqrt(participants.length) * colAdjust;
38+
const cols = Math.max(participants.length === 1 ? 1 : 2, Math.round(colFraction));
39+
const widthAdjust = Math.min(100, 100 + (cols > colFraction ? 1 : -1) * (colFraction % 1) * 50);
40+
if (gridEl.current) {
41+
gridEl.current.style.setProperty('--lk-col-count', cols.toString());
42+
gridEl.current.style.width = `${widthAdjust}%`;
43+
}
44+
}, [width, height, participants, gridEl.current]);
45+
3746
const elementProps = React.useMemo(
3847
() => mergeProps(props, { className: 'lk-grid-layout' }),
3948
[props],
4049
);
4150
return (
42-
<div ref={gridEl} {...elementProps}>
43-
{props.children ?? <TileLoop filter={filter} filterDependencies={filterDependencies} />}
51+
<div ref={containerEl} className="lk-grid-layout-wrapper">
52+
<div ref={gridEl} {...elementProps}>
53+
{props.children ?? <TileLoop filter={filter} filterDependencies={filterDependencies} />}
54+
</div>
4455
</div>
4556
);
4657
}

packages/react/src/prefabs/VideoConference.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,9 @@ export function VideoConference({ ...props }: VideoConferenceProps) {
4343
<LayoutContextProvider onPinChange={handleFocusStateChange} onWidgetChange={setWidgetState}>
4444
<div className="lk-video-conference-inner">
4545
{layout === 'grid' ? (
46-
<div className="lk-grid-layout-wrapper">
47-
<GridLayout>
48-
<TileLoop />
49-
</GridLayout>
50-
</div>
46+
<GridLayout>
47+
<TileLoop />
48+
</GridLayout>
5149
) : (
5250
<div className="lk-focus-layout-wrapper">
5351
<FocusLayoutContainer />

packages/react/src/utils.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import { mergeProps as mergePropsReactAria } from './mergeProps';
33
import { Observable } from 'rxjs';
4+
import useResizeObserver from '@react-hook/resize-observer';
45

56
type LKComponentAttributes<T extends HTMLElement> = React.HTMLAttributes<T>;
67

@@ -58,4 +59,18 @@ function cloneSingleChild(
5859
});
5960
}
6061

61-
export { mergeProps, LKComponentAttributes, useObservableState, cloneSingleChild };
62+
const useSize = (target: React.RefObject<HTMLDivElement>) => {
63+
const [size, setSize] = React.useState({ width: 0, height: 0 });
64+
React.useLayoutEffect(() => {
65+
if (target?.current) {
66+
const { width, height } = target.current.getBoundingClientRect();
67+
setSize({ width, height });
68+
}
69+
}, [target.current]);
70+
71+
// Where the magic happens
72+
useResizeObserver(target, (entry) => setSize(entry.contentRect));
73+
return size;
74+
};
75+
76+
export { mergeProps, LKComponentAttributes, useObservableState, cloneSingleChild, useSize };

packages/styles/scss/components/_grid-layout.scss

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,23 @@
99
}
1010

1111
.grid-layout {
12-
--lk-p-count: 2;
13-
--lk-max-col-count: 5;
14-
--lk-col-count: min(
15-
calc(var(--lk-p-count) / var(--lk-max-col-count) + 1),
16-
var(--lk-max-col-count)
17-
);
12+
--lk-col-count: 2;
1813
display: grid;
1914
grid-template-columns: repeat(var(--lk-col-count), minmax(0, 1fr));
20-
grid-template-rows: repeat(auto-fit, minmax(0px, 1fr));
15+
grid-template-rows: repeat(auto-fit, minmax(0, 1fr));
2116
grid-gap: var(--grid-gap);
22-
// width: 100%;
23-
width: max-content;
17+
width: 100%;
2418
height: 100%;
2519
max-width: 100%;
2620
max-height: 100%;
2721
padding: var(--grid-gap);
2822

2923
> * {
3024
height: 100%;
31-
width: auto;
32-
max-width: 100%;
33-
max-height: 100%;
34-
aspect-ratio: 4 / 3;
35-
margin: auto;
36-
justify-content: start;
37-
}
38-
39-
@media (max-width: 660px) {
40-
grid-template-columns: repeat(calc(var(--lk-col-count) / 1.5), 1fr);
25+
width: 100%;
26+
// max-width: 100%;
27+
// max-height: 100%;
28+
// aspect-ratio: 16 / 10;
29+
// object-fit: cover;
4130
}
4231
}

yarn.lock

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,11 @@
15961596
"@jridgewell/resolve-uri" "3.1.0"
15971597
"@jridgewell/sourcemap-codec" "1.4.14"
15981598

1599+
"@juggle/resize-observer@^3.3.1":
1600+
version "3.4.0"
1601+
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
1602+
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
1603+
15991604
"@livekit/changesets-changelog-github@^0.0.3":
16001605
version "0.0.3"
16011606
resolved "https://registry.npmjs.org/@livekit/changesets-changelog-github/-/changesets-changelog-github-0.0.3.tgz"
@@ -1820,6 +1825,25 @@
18201825
resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
18211826
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
18221827

1828+
"@react-hook/latest@^1.0.2":
1829+
version "1.0.3"
1830+
resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80"
1831+
integrity sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==
1832+
1833+
"@react-hook/passive-layout-effect@^1.2.0":
1834+
version "1.2.1"
1835+
resolved "https://registry.yarnpkg.com/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz#c06dac2d011f36d61259aa1c6df4f0d5e28bc55e"
1836+
integrity sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==
1837+
1838+
"@react-hook/resize-observer@^1.2.6":
1839+
version "1.2.6"
1840+
resolved "https://registry.yarnpkg.com/@react-hook/resize-observer/-/resize-observer-1.2.6.tgz#9a8cf4c5abb09becd60d1d65f6bf10eec211e291"
1841+
integrity sha512-DlBXtLSW0DqYYTW3Ft1/GQFZlTdKY5VAFIC4+km6IK5NiPPDFchGbEJm1j6pSgMqPRHbUQgHJX7RaR76ic1LWA==
1842+
dependencies:
1843+
"@juggle/resize-observer" "^3.3.1"
1844+
"@react-hook/latest" "^1.0.2"
1845+
"@react-hook/passive-layout-effect" "^1.2.0"
1846+
18231847
"@rollup/pluginutils@^4.2.0":
18241848
version "4.2.1"
18251849
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"

0 commit comments

Comments
 (0)