Skip to content

Commit

Permalink
Fix common styling and functionality fixes (#193)
Browse files Browse the repository at this point in the history
* Add onCopy to CodeBlock

* Fix button group cursor

* Add fillWidth option to button group

* Flyout should be interactable by default

* Add Ellipsis to be allowed to have different component

* Fix Link type

* Add ref to typography

* Add onCopyError

* Fix type error

* Add container element to select

* Add Flyout animation

* Update themes values

* Add Button Group color fix
  • Loading branch information
vineethasok authored Nov 1, 2023
1 parent bbfd4e4 commit 2132f92
Show file tree
Hide file tree
Showing 15 changed files with 169 additions and 56 deletions.
30 changes: 30 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
Flyout,
Select,
Text,
EllipsisContent,
} from "@/components";
import { Dialog } from "@/components/Dialog/Dialog";

Expand Down Expand Up @@ -386,6 +387,35 @@ const App = () => {
<p>I'm a dialog</p>
</Dialog.Content>
</Dialog>
<EllipsisContent
component={Text}
color="muted"
style={{ width: 100 }}
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod dolor
vehicula tortor condimentum blandit. Quisque eget efficitur nisi, sit amet
facilisis felis. Sed malesuada ut dui vel hendrerit. Nulla at neque libero. Ut id
fringilla nisl. Nulla semper a sem a molestie. Vestibulum consequat feugiat magna,
vitae pellentesque lacus gravida non. Vestibulum bibendum gravida felis ac
elementum. In suscipit risus a sollicitudin molestie. Ut id cursus felis, vel
auctor ex. Cras vel metus ipsum. Sed finibus, ligula ut convallis maximus, turpis
ex imperdiet enim, ac finibus nunc ante non est. Ut mattis ex magna, ac faucibus
mi egestas interdum.
</EllipsisContent>
<EllipsisContent
component="span"
style={{ width: 100 }}
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec euismod dolor
vehicula tortor condimentum blandit. Quisque eget efficitur nisi, sit amet
facilisis felis. Sed malesuada ut dui vel hendrerit. Nulla at neque libero. Ut id
fringilla nisl. Nulla semper a sem a molestie. Vestibulum consequat feugiat magna,
vitae pellentesque lacus gravida non. Vestibulum bibendum gravida felis ac
elementum. In suscipit risus a sollicitudin molestie. Ut id cursus felis, vel
auctor ex. Cras vel metus ipsum. Sed finibus, ligula ut convallis maximus, turpis
ex imperdiet enim, ac finibus nunc ante non est. Ut mattis ex magna, ac faucibus
mi egestas interdum.
</EllipsisContent>
</ClickUIProvider>
);
};
Expand Down
24 changes: 17 additions & 7 deletions src/components/ButtonGroup/ButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface ButtonGroupElementProps
extends Omit<HTMLAttributes<HTMLButtonElement>, "children"> {
value: string;
label?: ReactNode;
fillWidth?: boolean;
}

export interface ButtonGroupProps
Expand All @@ -21,14 +22,15 @@ export const ButtonGroup = ({
...props
}: ButtonGroupProps) => {
const lastIndex = options.length - 1;
const btns = options.map(({ value, label, ...props }, index) => {
const btns = options.map(({ value, label, fillWidth, ...props }, index) => {
const position: ButtonPosition =
index === 0 ? "left" : index === lastIndex ? "right" : "center";
return (
<Button
key={value}
$active={value === selected}
$position={position}
$fillWidth={fillWidth}
onClick={() => onClick?.(value)}
role="button"
{...props}
Expand All @@ -46,6 +48,7 @@ interface ButtonProps {
$active: boolean;
$position: ButtonPosition;
theme: DefaultTheme;
$fillWidth?: boolean;
}

const ButtonGroupWrapper = styled.div`
Expand Down Expand Up @@ -82,21 +85,28 @@ const Button = styled.button<ButtonProps>`
padding: ${({ theme }) => theme.click.button.basic.space.y}
${({ theme }) => theme.click.button.basic.space.x};
gap: ${({ theme }) => theme.click.button.basic.space.group};
${({ $fillWidth = false }) => ($fillWidth ? "flex: 1;" : "")}
cursor: pointer;
&:hover {
background: ${({ theme }) => theme.click.button.group.color.background.hover};
}
&:disabled {
cursor: not-allowed;
background: ${({ theme, $active }) =>
theme.click.button.group.color.background[
$active ? "disabled-active" : "disabled"
]};
}
&:active,
&:focus {
background: ${({ theme }) => theme.click.button.group.color.background.active};
}
&:disabled {
cursor: disabled;
background: ${({ theme }) =>
theme.click.button.basic.color.primary.background.disabled};
&:disabled {
background: ${({ theme }) =>
theme.click.button.group.color.background["disabled-active"]};
}
}
border-radius: ${({ $position }: ButtonProps) =>
Expand Down
42 changes: 34 additions & 8 deletions src/components/CodeBlock/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ SyntaxHighlighter.registerLanguage("bash", bash);
SyntaxHighlighter.registerLanguage("json", json);

export type CodeThemeType = "light" | "dark";
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "onCopy"> {
language?: string;
children: string;
theme?: CodeThemeType;
showLineNumbers?: boolean;
showWrapButton?: boolean;
wrapLines?: boolean;
onCopy?: (value: string) => void | Promise<void>;
onCopyError?: (error: string) => void | Promise<void>;
}

interface RendererNodeType {
Expand Down Expand Up @@ -52,9 +54,15 @@ const CodeBlockContainer = styled.div<{ $theme?: CodeThemeType }>`
}}
`;

const CodeButton = styled(EmptyButton)<{ $copied: boolean }>`
${({ $copied }) => `
color: ${$copied ? "green" : "inherit"};
const CodeButton = styled(EmptyButton)<{ $copied: boolean; $error: boolean }>`
${({ $copied, $error, theme }) => `
color: ${
$copied
? theme.click.alert.color.text.success
: $error
? theme.click.alert.color.text.danger
: "inherit"
};
padding: 0;
border: 0;
`}
Expand Down Expand Up @@ -88,18 +96,34 @@ export const CodeBlock = ({
showLineNumbers,
showWrapButton = false,
wrapLines = false,
onCopy,
onCopyError,
...props
}: Props) => {
const [copied, setCopied] = useState(false);
const [errorCopy, setErrorCopy] = useState(false);
const [wrap, setWrap] = useState(wrapLines);
const customStyle = useColorStyle(theme);
const ref = useRef<HTMLElement>(null);

const copyCodeToClipboard = async () => {
if (ref.current?.textContent) {
await navigator.clipboard.writeText(ref.current.textContent);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
try {
await navigator.clipboard.writeText(ref.current.textContent);
if (typeof onCopy == "function") {
onCopy(ref.current.textContent);
}
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (error) {
let message = "Unable to copy code";
if (error instanceof Error) message = error.message;
setErrorCopy(true);
if (typeof onCopyError === "function") {
onCopyError(message);
}
setTimeout(() => setErrorCopy(false), 2000);
}
}
};
const wrapElement = () => {
Expand All @@ -122,14 +146,16 @@ export const CodeBlock = ({
<CodeButton
as={IconButton}
$copied={false}
$error={false}
icon="document"
onClick={wrapElement}
/>
)}
<CodeButton
as={IconButton}
$copied={copied}
icon={copied ? "check" : "copy"}
$error={errorCopy}
icon={copied ? "check" : errorCopy ? "warning" : "copy"}
onClick={copyCodeToClipboard}
/>
</ButtonContainer>
Expand Down
18 changes: 15 additions & 3 deletions src/components/EllipsisContent/EllipsisContent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { HTMLAttributes, forwardRef } from "react";
import {
ComponentPropsWithRef,
ComponentPropsWithoutRef,
ElementType,
forwardRef,
} from "react";
import { mergeRefs } from "@/utils/mergeRefs";
import styled from "styled-components";

Expand All @@ -17,11 +22,18 @@ const EllipsisContainer = styled.div`
text-overflow: ellipsis;
}
`;
export interface EllipsisContentProps<T extends ElementType> {
component?: T;
}

export const EllipsisContent = forwardRef<HTMLElement, HTMLAttributes<HTMLSpanElement>>(
(props, ref) => {
export const EllipsisContent = forwardRef(
<T extends ElementType = "div">(
{ component, ...props }: EllipsisContentProps<T> & ComponentPropsWithoutRef<T>,
ref: ComponentPropsWithRef<T>["ref"]
) => {
return (
<EllipsisContainer
as={component ?? "div"}
ref={mergeRefs([
ref,
node => {
Expand Down
13 changes: 10 additions & 3 deletions src/components/Flyout/Flyout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { Button, ButtonProps, Icon, Separator } from "..";
import styled from "styled-components";
import { CrossButton } from "../commonElement";
import { keyframes } from "styled-components";

export type FlyoutProps = DialogProps;

Expand Down Expand Up @@ -51,23 +52,29 @@ export interface DialogContentProps extends RadixDialogContentProps {
closeOnInteractOutside?: boolean;
}

const animationWidth = keyframes({
"0%": { width: 0 },
"100%": { width: "var(--flyout-width, 100%)" },
});

const FlyoutContent = styled(DialogContent)<{
$size?: FlyoutSizeType;
$strategy: Strategy;
}>`
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
overflow: hidden;
flex: 1;
top: 0;
right: 0;
bottom: 0;
${({ theme, $size = "default", $strategy }) => `
--flyout-width: ${({ theme, $size = "default" }) =>
theme.click.flyout.size[$size].width};
animation: ${animationWidth} 500ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
${({ theme, $strategy }) => `
position: ${$strategy};
height: ${$strategy === "relative" ? "100%" : "auto"};
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};
Expand Down
2 changes: 1 addition & 1 deletion src/components/Link/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const IconWrapper = styled.span<{ $size: TextSize }>`
`;

/** Component for linking to other pages or sections from with body text */
export const Link = <T extends React.ElementType = "a">({
export const Link = <T extends ElementType = "a">({
size = "md",
weight = "normal",
className,
Expand Down
3 changes: 2 additions & 1 deletion src/components/Select/common/InternalSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export const InternalSelect = ({
placeholder = "Select an option",
multiple,
showSearch = false,
container,
...props
}: SelectContainerProps) => {
const defaultId = useId();
Expand Down Expand Up @@ -383,7 +384,7 @@ export const InternalSelect = ({
))}
</HiddenSelectElement>
)}
<Portal>
<Portal container={container}>
<SelectPopoverContent
sideOffset={5}
onFocus={onFocus}
Expand Down
1 change: 1 addition & 0 deletions src/components/Select/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ interface InternalSelectProps
multiple?: boolean;
showSearch?: boolean;
customText?: string;
container?: HTMLElement;
}

export type SelectOptionProp = SelectOptionType | SelectChildrenType;
Expand Down
25 changes: 14 additions & 11 deletions src/components/Typography/Text/Text.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTMLAttributes } from "react";
import { HTMLAttributes, forwardRef } from "react";
import styled from "styled-components";

export type TextColor = "default" | "muted";
Expand All @@ -13,16 +13,19 @@ export interface TextProps extends HTMLAttributes<HTMLParagraphElement> {
}

/** Component for writing blocks of body copy */
const _Text = ({ color, size, weight, className, children, ...props }: TextProps) => (
<CuiText
$color={color}
$size={size}
$weight={weight}
className={className}
{...props}
>
{children}
</CuiText>
const _Text = forwardRef<HTMLParagraphElement, TextProps>(
({ color, size, weight, className, children, ...props }, ref) => (
<CuiText
ref={ref}
$color={color}
$size={size}
$weight={weight}
className={className}
{...props}
>
{children}
</CuiText>
)
);

const CuiText = styled.p<{ $color?: TextColor; $size?: TextSize; $weight?: TextWeight }>`
Expand Down
25 changes: 14 additions & 11 deletions src/components/Typography/Title/Title.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTMLAttributes } from "react";
import { HTMLAttributes, forwardRef } from "react";
import styled from "styled-components";
export type TitleColor = "default" | "muted";
export type TitleSize = "xs" | "sm" | "md" | "lg" | "xl";
Expand All @@ -13,16 +13,19 @@ export interface TitleProps extends HTMLAttributes<HTMLHeadingElement> {
}

/** The `title` component allows you to easily add headings to your pages. They do not include built in margins. */
export const Title = ({ size, family, type, color, children, ...props }: TitleProps) => (
<CuiTitle
$color={color}
$size={size}
$family={family}
as={type}
{...props}
>
{children}
</CuiTitle>
export const Title = forwardRef<HTMLHeadingElement, TitleProps>(
({ size, family, type, color, children, ...props }, ref) => (
<CuiTitle
ref={ref}
$color={color}
$size={size}
$family={family}
as={type}
{...props}
>
{children}
</CuiTitle>
)
);

const CuiTitle = styled.div<{
Expand Down
Loading

1 comment on commit 2132f92

@vercel
Copy link

@vercel vercel bot commented on 2132f92 Nov 1, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

click-ui – ./

click-ui-clickhouse.vercel.app
click-ui-git-main-clickhouse.vercel.app
click-ui.vercel.app

Please sign in to comment.