Skip to content

Commit

Permalink
docs: add a new customization page for "Shadow DOM"
Browse files Browse the repository at this point in the history
  • Loading branch information
cheton committed Dec 1, 2024
1 parent fbb0229 commit 8a60e4c
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 0 deletions.
10 changes: 10 additions & 0 deletions packages/react-docs/config/sidebar-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
MigrateSuccessIcon,
RocketIcon,
SVGIcon,
ToolsConfigurationIcon,
UserTeamIcon,
WidgetsIcon,
WorkspaceIcon,
Expand Down Expand Up @@ -61,6 +62,15 @@ export const routes = [
{ title: 'React Icons', path: 'contributing/react-icons' },
],
},
{
title: 'Customization',
icon: (props) => (
<ToolsConfigurationIcon size="4x" {...props} />
),
routes: [
{ title: 'Shadow DOM', path: 'customization/shadow-dom' },
],
},
{
title: 'Migrations',
icon: (props) => (
Expand Down
14 changes: 14 additions & 0 deletions packages/react-docs/pages/customization/index.page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useRouter } from 'next/router';
import { useOnce } from '@tonic-ui/react-hooks';

const Root = () => {
const router = useRouter();

useOnce(() => {
router.push('/customization/shadow-dom');
});

return null;
};

export default Root;
176 changes: 176 additions & 0 deletions packages/react-docs/pages/customization/shadow-dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import createCache from '@emotion/cache';
import { CacheProvider } from '@emotion/react';
import {
Button,
Flex,
Grid,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
PortalManager,
Stack,
Text,
TonicProvider,
createTheme,
useColorMode,
usePortalManager,
} from '@tonic-ui/react';
import BorderedBox from '@/components/BorderedBox';
import React, { useEffect } from 'react';
import { createRoot } from 'react-dom/client';

const TestModal = ({ onClose }) => {
return (
<Modal
closeOnEsc
closeOnOutsideClick
isClosable
isOpen
onClose={onClose}
size="sm"
>
<ModalOverlay />
<ModalContent>
<ModalHeader>
Modal Header
</ModalHeader>
<ModalBody>
Modal Body
</ModalBody>
<ModalFooter>
<Grid templateColumns="repeat(2, 1fr)" columnGap="2x">
<Button variant="primary" onClick={onClose}>
OK
</Button>
<Button variant="default" onClick={onClose}>
Cancel
</Button>
</Grid>
</ModalFooter>
</ModalContent>
</Modal>
);
};

const ShadowDOMContainer = () => {
const portal = usePortalManager();

return (
<BorderedBox py="4x" px="6x">
<Stack
spacing="2x"
sx={{ textAlign: 'center' }}
>
<Text>Shadow DOM</Text>
<Button
variant="primary"
onClick={() => {
portal((close) => <TestModal onClose={close} />);
}}
>
Open Modal
</Button>
</Stack>
</BorderedBox>
);
};

const NativeDOMContainer = () => {
const portal = usePortalManager();

return (
<BorderedBox py="4x" px="6x">
<Stack
spacing="2x"
sx={{ textAlign: 'center' }}
>
<Text>Native DOM</Text>
<Button
variant="primary"
onClick={() => {
portal((close) => <TestModal onClose={close} />);
}}
>
Open Modal
</Button>
</Stack>
</BorderedBox>
);
};

const App = () => {
const [colorMode] = useColorMode();

useEffect(() => {
const container = document.querySelector('#shadow-root');
if (!container) {
return;
}

let shadowContainer = container.shadowRoot;
if (!shadowContainer) {
shadowContainer = container.attachShadow({ mode: 'open' });
}

let shadowRootElement = shadowContainer.querySelector('#shadow-content');
if (!shadowRootElement) {
shadowRootElement = document.createElement('div');
shadowRootElement.id = 'shadow-content';
}

if (!shadowContainer.contains(shadowRootElement)) {
shadowContainer.appendChild(shadowRootElement);
}

const cache = createCache({
key: 'tonic-ui-shadow',
prepend: true,
container: shadowContainer,
});

const shadowTheme = createTheme({
cssVariables: {
prefix: 'tonic-shadow',
rootSelector: ':host',
},
});

const root = createRoot(shadowRootElement);
root.render(
<CacheProvider value={cache}>
<TonicProvider
colorMode={{
value: colorMode,
}}
theme={shadowTheme}
>
<PortalManager>
<ShadowDOMContainer />
</PortalManager>
</TonicProvider>
</CacheProvider>
);

return () => {
// Unmount the React component
root.unmount();

// Remove all children of the shadow container
while (shadowContainer.firstChild) {
shadowContainer.removeChild(shadowContainer.firstChild);
}
};
}, [colorMode]);

return (
<Flex columnGap="8x">
<div id="shadow-root" />
<NativeDOMContainer />
</Flex>
);
};

export default App;
3 changes: 3 additions & 0 deletions packages/react-docs/pages/customization/shadow-dom.page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Shadow DOM

{render('./shadow-dom')}

0 comments on commit 8a60e4c

Please sign in to comment.