Skip to content

Commit

Permalink
- Working on new Popover.
Browse files Browse the repository at this point in the history
  • Loading branch information
mattias800 committed Aug 21, 2024
1 parent 33ea39c commit cdadedd
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 1 deletion.
54 changes: 54 additions & 0 deletions packages/tooltip/src/components/popover/Popover2.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.floating {
display: flex;
flex-direction: row;
align-items: center;
background: white;
color: white;
border-radius: var(--swui-border-radius);
padding: var(--swui-metrics-spacing) calc(var(--swui-metrics-indent) * 2);
box-shadow: var(--swui-shadow-popover);

&.withIcon {
padding: calc(var(--swui-metrics-spacing) * 0.5);
padding-right: calc(var(--swui-metrics-indent) * 2);
}
}

.iconWrapper {
/* State vars */
--current-bg-color: transparent;
--current-border-color: var(--lhds-color-ui-50);
--current-icon-color: var(--lhds-color-ui-50);

/* Styling */
display: inline-flex;
flex-direction: row;
white-space: nowrap;
background-color: var(--current-bg-color);
border: 1px solid var(--current-border-color);
border-radius: var(--swui-border-radius);
padding: calc(var(--swui-metrics-spacing) * 0.5);
align-items: flex-start;

svg {
color: var(--current-icon-color);
}

&.info {
--current-border-color: var(--lhds-color-blue-300);
--current-bg-color: var(--lhds-color-blue-100);
--current-icon-color: var(--lhds-color-blue-700);
}

&.warning {
--current-border-color: var(--lhds-color-orange-300);
--current-bg-color: var(--lhds-color-orange-100);
--current-icon-color: var(--lhds-color-orange-700);
}

&.error {
--current-border-color: var(--lhds-color-red-300);
--current-bg-color: var(--lhds-color-red-100);
--current-icon-color: var(--lhds-color-red-700);
}
}
147 changes: 147 additions & 0 deletions packages/tooltip/src/components/popover/Popover2.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import {
Box,
Column,
Indent,
Row,
SeparatorLine,
Spacing,
Text,
} from "@stenajs-webui/core";
import { FlatButton, Icon, stenaTrash } from "@stenajs-webui/elements";
import * as React from "react";
import { ActionPrompt } from "./ActionPrompt";
import { Popover2 } from "./Popover2";
import { PopoverButton } from "./PopoverButton";

export default {
title: "tooltip/Popover2",
component: Popover2,
subcomponents: { PopoverButton, ActionPrompt },
};

export const Standard = () => (
<Box indent={10} spacing={10} display={"inline-block"}>
<PopoverButton
content={<ActionPrompt />}
renderButton={() => <FlatButton leftIcon={stenaTrash} />}
/>
</Box>
);

export const OnClick = () => (
<Box indent={10} spacing={10} display={"inline-block"}>
<PopoverButton
content={<ActionPrompt />}
renderButton={({ onClick }) => (
<FlatButton leftIcon={stenaTrash} onClick={onClick} />
)}
/>
</Box>
);

export const NoArrow = () => (
<Box indent={10} spacing={10} display={"inline-block"}>
<PopoverButton
content={<ActionPrompt />}
renderButton={({ onClick }) => (
<FlatButton leftIcon={stenaTrash} onClick={onClick} />
)}
arrow={false}
/>
</Box>
);

export const NoPadding = () => (
<Box indent={10} spacing={10} display={"inline-block"}>
<PopoverButton
disablePadding
content={
<Column>
<Indent spacing>
<Text>The line has</Text>
</Indent>
<SeparatorLine />
<Indent spacing>
<Text>no padding</Text>
</Indent>
</Column>
}
renderButton={({ onClick }) => (
<FlatButton leftIcon={stenaTrash} onClick={onClick} />
)}
/>
</Box>
);

export const Variants = () => (
<Box indent={10} spacing={10} display={"inline-block"}>
<PopoverButton
content={<ActionPrompt />}
renderButton={({ onClick }) => (
<FlatButton label={"standard"} onClick={onClick} />
)}
/>

<Spacing />

<PopoverButton
content={<ActionPrompt />}
renderButton={({ onClick }) => (
<FlatButton label={"info"} onClick={onClick} />
)}
variant={"info"}
/>

<Spacing />

<PopoverButton
content={<Text>Some warning.</Text>}
variant={"warning"}
renderButton={({ onClick }) => (
<FlatButton label={"warning"} onClick={onClick} />
)}
/>

<Spacing />

<PopoverButton
content={
<Row>
<Icon icon={stenaTrash} />
<Indent />
<Text>Something went wrong.</Text>
</Row>
}
variant={"error"}
renderButton={({ onClick }) => (
<FlatButton label={"error"} onClick={onClick} />
)}
/>
</Box>
);

export const ControlOpen = () => (
<Box indent={10} spacing={10} display={"inline-block"}>
<Popover2 content={<ActionPrompt />} visible>
<FlatButton leftIcon={stenaTrash} />
</Popover2>
</Box>
);

const Alerter = () => {
alert("I was rendered.");

return <Text>I alert when I am rendered.</Text>;
};

export const Lazy = () => (
<Box indent={10} spacing={10} display={"inline-block"}>
<PopoverButton
content={<Alerter />}
lazy
renderButton={({ onClick }) => (
<FlatButton leftIcon={stenaTrash} onClick={onClick} />
)}
/>
</Box>
);
109 changes: 109 additions & 0 deletions packages/tooltip/src/components/popover/Popover2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import * as React from "react";
import { PropsWithChildren, ReactNode, useRef } from "react";
import { Placement } from "../tooltip/Tooltip";
import {
arrow,
autoUpdate,
flip,
FloatingArrow,
FloatingFocusManager,
offset,
shift,
useDismiss,
useFloating,
useInteractions,
useRole,
useTransitionStyles,
} from "@floating-ui/react";
import cx from "classnames";
import moduleStyles from "./Popover2.module.css";

export type PopoverVariant =
| "standard"
| "info"
| "warning"
| "error"
| "outlined";

export type PopoverTheme = "light" | "dark";

export interface Popover2Props extends PropsWithChildren {
visible?: boolean;
onRequestClose?: () => void;
placement?: Placement;
arrow?: boolean;
disablePadding?: boolean;
lazy?: boolean;
variant?: PopoverVariant;
theme?: PopoverTheme;
content: ReactNode;
}

const ARROW_WIDTH = 12;
const ARROW_HEIGHT = 8;
const GAP = 2;

export const Popover2: React.FC<Popover2Props> = ({
children,
variant,
content,
visible,
arrow: arrowVisible = true,
}) => {
const arrowRef = useRef(null);

const { refs, floatingStyles, context } = useFloating({
open: visible,
middleware: [
offset(ARROW_HEIGHT + GAP),
flip({ padding: 5 }),
shift({ padding: 5 }),
arrow({ element: arrowRef }),
],
whileElementsMounted: autoUpdate,
});

const { isMounted, styles } = useTransitionStyles(context, {
initial: {
opacity: 0,
},
});

const dismiss = useDismiss(context);
const role = useRole(context);

const { getReferenceProps } = useInteractions([dismiss, role]);

return (
<>
<div ref={refs.setReference} {...getReferenceProps()}>
{children}
</div>

{isMounted && (
<FloatingFocusManager context={context} modal={false}>
<div ref={refs.setFloating} style={floatingStyles}>
<div
style={styles}
className={cx(
moduleStyles.floating,
variant && moduleStyles.withIcon
)}
>
{content}
{arrowVisible && (
<FloatingArrow
ref={arrowRef}
context={context}
width={ARROW_WIDTH}
height={ARROW_HEIGHT}
fill={"white"}
/>
)}
</div>
</div>
</FloatingFocusManager>
)}
</>
);
};
28 changes: 28 additions & 0 deletions packages/tooltip/src/components/popover/PopoverButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react";
import { ReactNode } from "react";
import { Popover2, Popover2Props } from "./Popover2";
import { useBoolean } from "@stenajs-webui/core";

export type PopoverButtonRenderer = (
args: PopoverButtonRendererArgs
) => ReactNode;

export interface PopoverButtonRendererArgs {
onClick: () => void;
}

export interface PopoverButtonProps extends Omit<Popover2Props, "children"> {
renderButton: PopoverButtonRenderer;
}

export const PopoverButton: React.FC<PopoverButtonProps> = ({
renderButton,
...popoverProps
}) => {
const [isOpen, open, close] = useBoolean(false);
return (
<Popover2 {...popoverProps} visible={isOpen} onRequestClose={close}>
{renderButton({ onClick: open })}
</Popover2>
);
};
8 changes: 7 additions & 1 deletion packages/tooltip/src/components/tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ import {

export interface TooltipProps extends PropsWithChildren {
placement?: Placement;
visible?: boolean;
label: string;
variant?: TooltipVariant;
maxWidth?: CSSProperties["maxWidth"];
// Remove
appendTo?: HTMLElement;
zIndex?: number | string;
}

type TooltipVariant = "info" | "warning" | "error";
Expand All @@ -46,6 +50,7 @@ export type Placement = "top" | "right" | "bottom" | "left";

export const Tooltip: React.FC<TooltipProps> = ({
children,
visible,
placement,
label,
variant,
Expand All @@ -57,7 +62,7 @@ export const Tooltip: React.FC<TooltipProps> = ({

const { refs, floatingStyles, context } = useFloating({
placement,
open: isOpen,
open: visible ?? isOpen,
onOpenChange: setIsOpen,
middleware: [
offset(ARROW_HEIGHT + GAP),
Expand Down Expand Up @@ -115,6 +120,7 @@ export const Tooltip: React.FC<TooltipProps> = ({
context={context}
width={ARROW_WIDTH}
height={ARROW_HEIGHT}
fill={"#333"}
/>
</div>
</div>
Expand Down

0 comments on commit cdadedd

Please sign in to comment.