Skip to content

Commit

Permalink
Use shadow root to isolate devui styling
Browse files Browse the repository at this point in the history
Summary:
- use shadow root to isolate devui styling from the rest of the page
- disable CSSOM injection to ensure compatibility when running as injected script by extension
- bump version to 1.0.1

Reviewed By: zjm-meta

Differential Revision:
D68784182

Privacy Context Container: L1233623

fbshipit-source-id: f3b6668fbd5553cb1d66a957cf1631d3b3935818
  • Loading branch information
felixtrz authored and facebook-github-bot committed Jan 28, 2025
1 parent dc788d2 commit 35fb98e
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 64 deletions.
4 changes: 2 additions & 2 deletions devui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion devui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@iwer/devui",
"version": "1.0.0",
"version": "1.0.1",
"description": "Dev UI for IWER",
"type": "module",
"main": "lib/index.js",
Expand Down
9 changes: 1 addition & 8 deletions devui/src/components/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,6 @@ export const KeyRow = styled.div<{ $reverse: boolean }>`
justify-content: center;
`;

export const ButtonGroupColumn = styled.div`
display: flex;
flex-direction: column;
height: 50px;
justify-content: space-between;
`;

export const FAIcon = styled(FontAwesomeIcon)<{ $size?: number }>`
height: ${({ $size }) => `${$size}px`};
min-height: ${({ $size }) => `${$size}px`};
Expand Down Expand Up @@ -362,6 +355,6 @@ export const InputSuffix = styled.span`
top: 50%;
transform: translateY(-50%);
pointer-events: none;
color: var(--panel-light-grey);
color: ${Colors.textGrey};
font-size: 10px;
`;
137 changes: 84 additions & 53 deletions devui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { HeaderUI } from './components/header.js';
import { HeadsetUI } from './components/headset.js';
import { IWERIcon } from './components/icons.js';
import { InputLayer } from './scene.js';
import { StyleSheetManager } from 'styled-components';
import { VERSION } from './version.js';
import { XRDevice } from 'iwer';
import { createRoot } from 'react-dom/client';
Expand All @@ -32,15 +33,32 @@ export class DevUI {
this.devUIContainer.style.left = '50vw';
this.devUIContainer.style.transform = 'translate(-50%, -50%)';
this.devUIContainer.style.pointerEvents = 'none';
const devUIShadowRoot = this.devUIContainer.attachShadow({
mode: 'open',
});
this.inputLayer = new InputLayer(xrDevice);
const root = createRoot(this.devUIContainer);
root.render(<Overlay xrDevice={xrDevice} inputLayer={this.inputLayer} />);
const root = createRoot(devUIShadowRoot);
root.render(
<Overlay
xrDevice={xrDevice}
inputLayer={this.inputLayer}
shadowRoot={devUIShadowRoot}
/>,
);

const installOfferSessionUI = () => {
const offerSessionUIContainer = document.createElement('div');
document.body.appendChild(offerSessionUIContainer);
const offerSessionRoot = createRoot(offerSessionUIContainer);
offerSessionRoot.render(<OfferSessionUI xrDevice={xrDevice} />);
const offerSessionShadowRoot = offerSessionUIContainer.attachShadow({
mode: 'open',
});
const offerSessionRoot = createRoot(offerSessionShadowRoot);
offerSessionRoot.render(
<OfferSessionUI
xrDevice={xrDevice}
shadowRoot={offerSessionShadowRoot}
/>,
);
};

if (document.body) {
Expand All @@ -62,9 +80,14 @@ export class DevUI {
interface OverlayProps {
xrDevice: XRDevice;
inputLayer: InputLayer;
shadowRoot: ShadowRoot;
}

const Overlay: React.FC<OverlayProps> = ({ xrDevice, inputLayer }) => {
const Overlay: React.FC<OverlayProps> = ({
xrDevice,
inputLayer,
shadowRoot,
}) => {
const [pointerLocked, setPointerLocked] = useState(false);

useEffect(() => {
Expand Down Expand Up @@ -113,36 +136,42 @@ const Overlay: React.FC<OverlayProps> = ({ xrDevice, inputLayer }) => {
}, []);

return (
<div
style={{
width: '100vw',
height: '100vh',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
pointerEvents: 'none',
}}
>
<HeaderUI xrDevice={xrDevice} inputLayer={inputLayer} />
<HeadsetUI
xrDevice={xrDevice}
inputLayer={inputLayer}
pointerLocked={pointerLocked}
/>
<ControlsUI
xrDevice={xrDevice}
inputLayer={inputLayer}
pointerLocked={pointerLocked}
/>
</div>
<StyleSheetManager target={shadowRoot} disableCSSOMInjection={true}>
<div
style={{
width: '100vw',
height: '100vh',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
pointerEvents: 'none',
}}
>
<HeaderUI xrDevice={xrDevice} inputLayer={inputLayer} />
<HeadsetUI
xrDevice={xrDevice}
inputLayer={inputLayer}
pointerLocked={pointerLocked}
/>
<ControlsUI
xrDevice={xrDevice}
inputLayer={inputLayer}
pointerLocked={pointerLocked}
/>
</div>
</StyleSheetManager>
);
};

interface OfferSessionProps {
xrDevice: XRDevice;
shadowRoot: ShadowRoot;
}

const OfferSessionUI: React.FC<OfferSessionProps> = ({ xrDevice }) => {
const OfferSessionUI: React.FC<OfferSessionProps> = ({
xrDevice,
shadowRoot,
}) => {
const [showOffer, setShowOffer] = React.useState(
xrDevice.sessionOffered && !xrDevice.activeSession,
);
Expand All @@ -154,34 +183,36 @@ const OfferSessionUI: React.FC<OfferSessionProps> = ({ xrDevice }) => {
}, []);

return (
<HeaderButtonsContainer
style={{
zIndex: 899,
position: 'fixed',
top: showOffer ? '8px' : '-30px',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyItems: 'space-between',
left: '50vw',
transform: 'translateX(-50%)',
transition: 'all 0.2s ease-in-out',
paddingLeft: '5px',
gap: '3px',
}}
>
<IWERIcon size={24} />
<HeaderButton
onClick={() => {
xrDevice.grantOfferedSession();
}}
<StyleSheetManager target={shadowRoot} disableCSSOMInjection={true}>
<HeaderButtonsContainer
style={{
fontSize: '16px',
zIndex: 899,
position: 'fixed',
top: showOffer ? '8px' : '-30px',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyItems: 'space-between',
left: '50vw',
transform: 'translateX(-50%)',
transition: 'all 0.2s ease-in-out',
paddingLeft: '5px',
gap: '3px',
}}
>
Enter XR
</HeaderButton>
</HeaderButtonsContainer>
<IWERIcon size={24} />
<HeaderButton
onClick={() => {
xrDevice.grantOfferedSession();
}}
style={{
fontSize: '16px',
}}
>
Enter XR
</HeaderButton>
</HeaderButtonsContainer>
</StyleSheetManager>
);
};

Expand Down

0 comments on commit 35fb98e

Please sign in to comment.