From e9dcffe540703d6e64548a82c71326342f03da05 Mon Sep 17 00:00:00 2001 From: VINEETH ASOK KUMAR Date: Mon, 16 Oct 2023 09:21:56 +0200 Subject: [PATCH] Add flyout component --- package-lock.json | 169 ++++++++++++++++++++++ package.json | 1 + src/App.tsx | 46 +++++- src/components/Flyout/Flyout.test.tsx | 0 src/components/Flyout/Flyout.tsx | 200 ++++++++++++++++++++++++++ src/components/index.ts | 1 + 6 files changed, 410 insertions(+), 7 deletions(-) create mode 100644 src/components/Flyout/Flyout.test.tsx create mode 100644 src/components/Flyout/Flyout.tsx diff --git a/package-lock.json b/package-lock.json index 5af5737e8..69a4e4f79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@radix-ui/react-avatar": "^1.0.3", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-context-menu": "^2.1.4", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.5", "@radix-ui/react-hover-card": "^1.0.6", "@radix-ui/react-popover": "^1.0.6", @@ -4289,6 +4290,117 @@ } } }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz", + "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz", + "integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-escape-keydown": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz", + "integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz", + "integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz", @@ -22902,6 +23014,63 @@ "@radix-ui/react-use-controllable-state": "1.0.1" } }, + "@radix-ui/react-dialog": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz", + "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "dependencies": { + "@radix-ui/react-dismissable-layer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz", + "integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-escape-keydown": "1.0.3" + } + }, + "@radix-ui/react-focus-scope": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz", + "integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1" + } + }, + "@radix-ui/react-portal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz", + "integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==", + "requires": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + } + } + } + }, "@radix-ui/react-direction": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz", diff --git a/package.json b/package.json index d716d30ae..b2fcd9bd3 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@radix-ui/react-avatar": "^1.0.3", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-context-menu": "^2.1.4", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.5", "@radix-ui/react-hover-card": "^1.0.6", "@radix-ui/react-popover": "^1.0.6", diff --git a/src/App.tsx b/src/App.tsx index 374eed700..55ec624d4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useRef, useState } from "react"; import "@/styles/globals.css"; import "./styles/variables.css"; @@ -28,6 +28,8 @@ import { Tabs, WarningAlert, CardPrimary, + Flyout, + Select, } from "@/components"; const App = () => { @@ -35,6 +37,7 @@ const App = () => { const [selectedButton, setSelectedButton] = useState(0); const [checked, setChecked] = useState(false); const [disabled] = useState(false); + const ref = useRef(null); return ( { onClick={() => console.log("click")} /> -
- console.log("click")} - /> +
console.log("click")} /> + + + console.log("click")} + /> + + + + + hadksjhadksjhaskdjhaksdjhkajsdhkajshdkjashdkjashd + + + + + + + { + return ; +}; + +const Trigger = ({ children, ...props }: Dialog.DialogTriggerProps) => { + return ( + +
{children}
+
+ ); +}; +Trigger.displayName = "Flyout.Trigger"; +Flyout.Trigger = Trigger; + +type FlyoutSizeType = "narrow" | "wide"; + +interface DialogContentProps extends Dialog.DialogContentProps { + container?: HTMLElement | null; + showOverlay?: boolean; + showClose?: boolean; + size?: FlyoutSizeType; +} + +const FlyoutContent = styled(Dialog.Content)<{ $size?: FlyoutSizeType }>` + display: flex; + flex-direction: column; + align-items: center; + height: 100%; + overflow: hidden; + ${({ theme, $size = "narrow" }) => ` + width: ${theme.click.flyout.size[$size].width}; + padding: ${theme.click.flyout.space.y} ${theme.click.flyout.space.x}; + gap: ${theme.click.flyout.space.gap}; + border-left: 1px solid ${theme.click.flyout.color.stroke.default}; + background: ${theme.click.flyout.color.background.default}; + box-shadow: -6px 0px 10px 0px ${theme.click.flyout.shadow.default}, -5px 0px 20px 0px ${theme.click.flyout.shadow.default}; + `} +`; + +const Content = ({ + showOverlay = false, + children, + container, + size, + ...props +}: DialogContentProps) => { + return ( + + {showOverlay && } + + {children} + + + ); +}; +Content.displayName = "Flyout.Content"; +Flyout.Content = Content; + +interface TitleHeaderProps extends Omit, "children"> { + title: string; + description: string; + children?: never; +} + +interface ChildrenHeaderProps extends HTMLAttributes { + title?: never; + description?: never; +} + +type HeaderProps = TitleHeaderProps | ChildrenHeaderProps; + +const FlyoutHeaderContainer = styled.div<{ $showBorder?: boolean }>` + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 1rem; + padding: 0rem 1.5rem 1rem; + ${({ theme, $showBorder = true }) => ` + border-bottom: ${ + $showBorder ? `1px solid ${theme.click.flyout.color.stroke.default}` : "none" + }; + `} +`; + +const FlexGrow = styled.div` + display: flex; + flex-direction: column; + flex: 1; +`; + +const FlyoutTitle = styled(Dialog.Title)` + ${({ theme }) => ` + color: ${theme.click.flyout.color.title.default}; + font: ${theme.typography.styles.product.titles.xl}; + `} +`; + +const FlyoutDescription = styled(Dialog.Description)` + ${({ theme }) => ` + color: ${theme.click.flyout.color.description.default}; + font: ${theme.typography.styles.product.text.normal.md}; + `} +`; + +const Header = ({ title, description, children, ...props }: HeaderProps) => { + if (children) { + return ( + + {children} + + + + + ); + } + + return ( + + + {title} + {description && ( + + Make changes to your profile here. Click save when you're done. + + )} + + + + + + ); +}; +Header.displayName = "Flyout.Header"; +Flyout.Header = Header; + +const FlyoutBody = styled.div` + display: flex; + flex-direction: column; + flex: 1; + ${({ theme }) => ` + gap: ${theme.click.flyout.space.gap}; + `} + padding: 0 1.5rem; +`; + +const Body = (props: HTMLAttributes) => ; + +Body.displayName = "Flyout.Body"; +Flyout.Body = Body; + +interface FooterProps extends HTMLAttributes { + cancelText?: string; + showClose?: boolean; +} + +const FlyoutFooter = styled.div` + margin-top: 1rem; + display: flex; + justify-content: flex-end; + align-items: center; + width: 100%; + padding: 1rem 1.5rem 0; + ${({ theme }) => ` + border-top: 1px solid ${theme.click.flyout.color.stroke.default}; + `} +`; + +const Footer = ({ cancelText, showClose, children, ...props }: FooterProps) => { + return ( + + {showClose && ( + + + + )} + {children} + + ); +}; +Footer.displayName = "Flyout.Footer"; +Flyout.Footer = Footer; diff --git a/src/components/index.ts b/src/components/index.ts index dfb7afbdd..924f0530a 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -16,6 +16,7 @@ export { CardPrimary } from "./CardPrimary/CardPrimary"; export { Checkbox } from "./Checkbox/Checkbox"; export { CodeBlock } from "./CodeBlock/CodeBlock"; export { EllipsisContent } from "./EllipsisContent/EllipsisContent"; +export { Flyout } from "./Flyout/Flyout"; export { InlineCodeBlock } from "./CodeBlock/InlineCodeBlock"; export { ContextMenu } from "./ContextMenu/ContextMenu"; export { default as Flags } from "./icons/Flags";