Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Modular Layouts to React #4764

Merged
merged 28 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0ec6ac7
Port over previous branch
gettinToasty Oct 3, 2023
651ecaf
Attach mins to Elements
gettinToasty Oct 4, 2023
6618e58
Fix event typing in ResizeBar
gettinToasty Oct 4, 2023
b994afc
Fix compilation errors
gettinToasty Oct 4, 2023
346bc70
Fix console errors
gettinToasty Oct 4, 2023
39c794b
Add Classic Layout
gettinToasty Oct 4, 2023
5f132ce
Fix infinite rerender
gettinToasty Oct 5, 2023
fa2d615
Add logs
gettinToasty Oct 5, 2023
40b111d
Get resize working
gettinToasty Oct 23, 2023
c5c656e
Fix drag smoothness
gettinToasty Oct 24, 2023
3d60273
Add FourByFour layout'
gettinToasty Oct 26, 2023
251a9bd
Add Pyramid Layout
gettinToasty Oct 26, 2023
c3056e5
Add OnePane Layout
gettinToasty Oct 26, 2023
891cb08
Refactor styleBlocking to be handled in ResizeBar
gettinToasty Oct 26, 2023
1e4c65e
Add column layouts
gettinToasty Oct 26, 2023
684baa7
Remove old layouts
gettinToasty Oct 26, 2023
36958a4
Fix columns in OnePaneR
gettinToasty Oct 26, 2023
c11e86b
Fix stale issue in componentRef checks
gettinToasty Oct 26, 2023
aa19d0a
Add missing key
gettinToasty Nov 6, 2023
07e91b7
Merge branch 'master' into sb_port_layouts_library
gettinToasty Nov 6, 2023
836893c
Fix double bar layout tests
gettinToasty Nov 6, 2023
25f85f7
Fix column layouts
gettinToasty Nov 7, 2023
6280c4f
Fix Triplets layout
gettinToasty Nov 7, 2023
9e7aad8
Fix 2nd bar popping
gettinToasty Nov 7, 2023
912eb58
Add documentation and useCallback to prevent function rebuilding
gettinToasty Dec 7, 2023
6830677
Fix strict null check
gettinToasty Dec 7, 2023
b110af0
Prevent function initialization error
gettinToasty Dec 7, 2023
af3b542
Unhook functions used at initialization
gettinToasty Dec 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions app/components-react/editor/elements/Browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { ELayoutElement } from 'services/layout';
import { Services } from 'components-react/service-provider';
import useBaseElement from './hooks';

export default function Display() {
const mins = { x: 0, y: 0 };

export function Browser() {
const { LayoutService, UserService } = Services;
const containerRef = useRef<HTMLDivElement>(null);

const { renderElement } = useBaseElement(<BrowserEl />, { x: 0, y: 0 }, containerRef.current);
const { renderElement } = useBaseElement(<BrowserEl />, mins, containerRef.current);

function url() {
const src = LayoutService.views.currentTab.slottedElements[ELayoutElement.Browser]?.src;
Expand Down Expand Up @@ -36,3 +38,5 @@ export default function Display() {
</div>
);
}

Browser.mins = mins;
8 changes: 6 additions & 2 deletions app/components-react/editor/elements/Display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ import React, { useRef } from 'react';
import StudioEditor from 'components-react/root/StudioEditor';
import useBaseElement from './hooks';

export default function Display() {
const mins = { x: 0, y: 0 };

export function Display() {
const containerRef = useRef<HTMLDivElement>(null);

const { renderElement } = useBaseElement(<StudioEditor />, { x: 0, y: 0 }, containerRef.current);
const { renderElement } = useBaseElement(<StudioEditor />, mins, containerRef.current);

return (
<div ref={containerRef} style={{ height: '100%' }}>
{renderElement()}
</div>
);
}

Display.mins = mins;
8 changes: 6 additions & 2 deletions app/components-react/editor/elements/LegacyEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { Services } from 'components-react/service-provider';
import BrowserView from 'components-react/shared/BrowserView';
import styles from './RecentEvents.m.less';

export default function LegacyEvents(p: { onPopout: () => void }) {
const mins = { x: 360, y: 150 };

export function LegacyEvents(p: { onPopout: () => void }) {
const { UserService, RecentEventsService, MagicLinkService } = Services;

const containerRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -47,7 +49,7 @@ export default function LegacyEvents(p: { onPopout: () => void }) {
});
}

const { renderElement } = useBaseElement(<Element />, { x: 360, y: 150 }, containerRef.current);
const { renderElement } = useBaseElement(<Element />, mins, containerRef.current);

function Element() {
if (!UserService.isLoggedIn) {
Expand Down Expand Up @@ -76,3 +78,5 @@ export default function LegacyEvents(p: { onPopout: () => void }) {
</div>
);
}

LegacyEvents.mins = mins;
8 changes: 6 additions & 2 deletions app/components-react/editor/elements/Minifeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import React, { useRef } from 'react';
import RecentEvents from './RecentEvents';
import useBaseElement from './hooks';

export default function MiniFeed() {
const mins = { x: 330, y: 90 };

export function MiniFeed() {
const containerRef = useRef<HTMLDivElement>(null);
const { renderElement } = useBaseElement(
<RecentEvents isOverlay={false} />,
{ x: 330, y: 90 },
mins,
containerRef.current,
);

Expand All @@ -16,3 +18,5 @@ export default function MiniFeed() {
</div>
);
}

MiniFeed.mins = mins;
8 changes: 6 additions & 2 deletions app/components-react/editor/elements/Mixer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import { Services } from 'components-react/service-provider';
import { Menu } from 'util/menus/Menu';
import { $t } from 'services/i18n';

export default function Mixer() {
const mins = { x: 150, y: 120 };

export function Mixer() {
const { EditorCommandsService, AudioService, CustomizationService } = Services;

const containerRef = useRef<HTMLDivElement>(null);

const { renderElement } = useBaseElement(<Element />, { x: 150, y: 120 }, containerRef.current);
const { renderElement } = useBaseElement(<Element />, mins, containerRef.current);

const needToRenderVolmeters: boolean = useMemo(() => {
// render volmeters without hardware acceleration only if we don't have the webgl context
Expand Down Expand Up @@ -85,3 +87,5 @@ export default function Mixer() {
</div>
);
}

Mixer.mins = mins;
8 changes: 6 additions & 2 deletions app/components-react/editor/elements/RecordingPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import { Services } from 'components-react/service-provider';
import useBaseElement from './hooks';
import { useVuex } from 'components-react/hooks';

export default function RecordingPreview() {
const mins = { x: 0, y: 0 };

export function RecordingPreview() {
const { WindowsService, StreamingService } = Services;

const containerRef = useRef<HTMLDivElement>(null);

const { renderElement } = useBaseElement(<RecPreview />, { x: 0, y: 0 }, containerRef.current);
const { renderElement } = useBaseElement(<RecPreview />, mins, containerRef.current);

const { hideStyleBlockers, selectiveRecording } = useVuex(() => ({
hideStyleBlockers: WindowsService.state[Util.getCurrentUrlParams().windowId].hideStyleBlockers,
Expand Down Expand Up @@ -42,3 +44,5 @@ export default function RecordingPreview() {
</div>
);
}

RecordingPreview.mins = mins;
12 changes: 6 additions & 6 deletions app/components-react/editor/elements/SceneSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,11 @@ function TreeNode(p: { scene: IScene; removeScene: (scene: IScene) => void }) {
);
}

export default function SceneSelectorElement() {
const mins = { x: 200, y: 120 };

export function SceneSelectorElement() {
const containerRef = useRef<HTMLDivElement>(null);
const { renderElement } = useBaseElement(
<SceneSelector />,
{ x: 200, y: 120 },
containerRef.current,
);
const { renderElement } = useBaseElement(<SceneSelector />, mins, containerRef.current);

return (
<div
Expand All @@ -331,3 +329,5 @@ export default function SceneSelectorElement() {
</div>
);
}

SceneSelectorElement.mins = mins;
12 changes: 6 additions & 6 deletions app/components-react/editor/elements/SourceSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -862,13 +862,11 @@ const TreeNode = React.forwardRef(
},
);

export default function SourceSelectorElement() {
const mins = { x: 200, y: 120 };

export function SourceSelectorElement() {
const containerRef = useRef<HTMLDivElement>(null);
const { renderElement } = useBaseElement(
<SourceSelector />,
{ x: 200, y: 120 },
containerRef.current,
);
const { renderElement } = useBaseElement(<SourceSelector />, mins, containerRef.current);

return (
<div
Expand All @@ -880,3 +878,5 @@ export default function SourceSelectorElement() {
</div>
);
}

SourceSelectorElement.mins = mins;
12 changes: 6 additions & 6 deletions app/components-react/editor/elements/StreamPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@ import { Services } from 'components-react/service-provider';
import useBaseElement from './hooks';
import { useVuex } from 'components-react/hooks';

export default function StreamPreview() {
const mins = { x: 0, y: 0 };

export function StreamPreview() {
const { WindowsService, StreamingService } = Services;

const containerRef = useRef<HTMLDivElement>(null);

const { renderElement } = useBaseElement(
<StreamPreviewElement />,
{ x: 0, y: 0 },
containerRef.current,
);
const { renderElement } = useBaseElement(<StreamPreviewElement />, mins, containerRef.current);

const { hideStyleBlockers, selectiveRecording } = useVuex(() => ({
hideStyleBlockers: WindowsService.state[Util.getCurrentUrlParams().windowId].hideStyleBlockers,
Expand Down Expand Up @@ -46,3 +44,5 @@ export default function StreamPreview() {
</div>
);
}

StreamPreview.mins = mins;
9 changes: 9 additions & 0 deletions app/components-react/editor/elements/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export { MiniFeed } from './Minifeed';
export { LegacyEvents } from './LegacyEvents';
export { SceneSelectorElement } from './SceneSelector';
export { SourceSelectorElement } from './SourceSelector';
export { Mixer } from './Mixer';
export { RecordingPreview } from './RecordingPreview';
export { StreamPreview } from './StreamPreview';
export { Browser } from './Browser';
export { Display } from './Display';
40 changes: 40 additions & 0 deletions app/components-react/editor/layouts/Classic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import cx from 'classnames';
import useLayout, { LayoutProps } from './hooks';
import ResizeBar from 'components-react/root/ResizeBar';
import styles from './Layouts.m.less';

export function Classic(p: React.PropsWithChildren<LayoutProps>) {
const { mins, bars, resizes, calculateMax, setBar, componentRef } = useLayout(
[['1'], ['2', '3', '4']],
false,
p.childrenMins,
p.onTotalWidth,
);

return (
<div className={styles.rows} ref={componentRef}>
<div className={styles.cell} style={{ height: `${100 - resizes.bar1 * 100}%` }}>
{p.children?.['1'] || <></>}
</div>
<ResizeBar
position="top"
value={bars.bar1}
onInput={(value: number) => setBar('bar1', value)}
max={calculateMax(mins.rest)}
min={mins.bar1}
>
<div
className={styles.segmented}
style={{ height: `${resizes.bar1 * 100}%`, padding: '8px' }}
>
{['2', '3', '4'].map(slot => (
<div key={slot} className={cx(styles.cell, 'no-top-padding')}>
{p.children?.[slot] || <></>}
</div>
))}
</div>
</ResizeBar>
</div>
);
}
57 changes: 57 additions & 0 deletions app/components-react/editor/layouts/Default.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import cx from 'classnames';
import useLayout, { LayoutProps } from './hooks';
import ResizeBar from 'components-react/root/ResizeBar';
import styles from './Layouts.m.less';

export function Default(p: React.PropsWithChildren<LayoutProps>) {
const { mins, bars, resizes, calculateMax, setBar, componentRef } = useLayout(
[['1'], ['2'], ['3', '4', '5']],
false,
p.childrenMins,
p.onTotalWidth,
);

return (
<div className={styles.rows} ref={componentRef}>
<div
className={styles.cell}
style={{ height: `${100 - (resizes.bar1 + resizes.bar2!) * 100}%` }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what instances would resizes.bar2 be null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About half of the layouts only have one resizable bar so it has to be an optional/nullable parameter, but we know which layouts in which 2 resize bars exist so we are able to safely assert them

>
{p.children?.['1'] || <></>}
</div>
<ResizeBar
position="top"
value={bars.bar1}
onInput={(value: number) => setBar('bar1', value)}
max={calculateMax(mins.rest + bars.bar2)}
min={mins.bar1}
>
<div
style={{ height: `${resizes.bar1 * 100}%` }}
className={cx(styles.cell, 'no-top-padding')}
>
{p.children?.['2'] || <></>}
</div>
</ResizeBar>
<ResizeBar
position="top"
value={bars.bar2}
onInput={(value: number) => setBar('bar2', value)}
max={calculateMax(mins.rest + mins.bar1)}
min={mins.bar2}
>
<div
className={styles.segmented}
style={{ height: `${resizes.bar2! * 100}%`, padding: '0 8px' }}
>
{['3', '4', '5'].map(slot => (
<div key={slot} className={cx(styles.cell, 'no-top-padding')}>
{p.children?.[slot] || <></>}
</div>
))}
</div>
</ResizeBar>
</div>
);
}
52 changes: 52 additions & 0 deletions app/components-react/editor/layouts/FourByFour.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import cx from 'classnames';
import useLayout, { LayoutProps } from './hooks';
import ResizeBar from 'components-react/root/ResizeBar';
import styles from './Layouts.m.less';

export function FourByFour(p: React.PropsWithChildren<LayoutProps>) {
const { mins, bars, resizes, calculateMax, setBar, componentRef } = useLayout(
[['1'], ['2', '3'], ['4', '5']],
false,
p.childrenMins,
p.onTotalWidth,
);

return (
<div className={styles.rows} ref={componentRef}>
<div
className={styles.cell}
style={{ height: `${100 - (resizes.bar1 + resizes.bar2) * 100}%` }}
>
{p.children?.['1'] || <></>}
</div>
<ResizeBar
position="top"
value={bars.bar1}
onInput={(value: number) => setBar('bar1', value)}
max={calculateMax(mins.rest + bars.bar2)}
min={mins.bar1}
>
<div className={styles.segmented} style={{ height: `${resizes.bar1 * 100}%` }}>
<div className={cx(styles.cell, 'no-top-padding')}>{p.children?.['2'] || <></>}</div>
<div className={cx(styles.cell, 'no-top-padding')}>{p.children?.['3'] || <></>}</div>
</div>
</ResizeBar>
<ResizeBar
position="top"
value={bars.bar2}
onInput={(value: number) => setBar('bar2', value)}
max={calculateMax(mins.rest + mins.bar1)}
min={mins.bar2}
>
<div
className={styles.segmented}
style={{ height: `${resizes.bar2 * 100}%`, padding: '0 8px' }}
>
<div className={cx(styles.cell, 'no-top-padding')}>{p.children?.['4'] || <></>}</div>
<div className={cx(styles.cell, 'no-top-padding')}>{p.children?.['5'] || <></>}</div>
</div>
</ResizeBar>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
flex-direction: column;
position: relative;
height: 100%;
width: 100%;
}

.columns {
position: relative;
display: flex;
height: 100%;
width: 100%;
}

.segmented {
Expand All @@ -23,6 +25,7 @@
display: flex;
height: 100%;
flex-direction: column;
position: relative;
}

.cell {
Expand Down
Loading
Loading