Skip to content

Commit 9c21fd3

Browse files
feat: adding baseui components to propel package (#7585)
* feat: adding baseui components * fix: export from the package.json
1 parent f142266 commit 9c21fd3

File tree

14 files changed

+815
-26
lines changed

14 files changed

+815
-26
lines changed

packages/propel/.eslintrc.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,29 @@ module.exports = {
33
root: true,
44
extends: ["@plane/eslint-config/library.js"],
55
parser: "@typescript-eslint/parser",
6+
rules: {
7+
"import/order": [
8+
"warn",
9+
{
10+
groups: ["builtin", "external", "internal", "parent", "sibling"],
11+
pathGroups: [
12+
{
13+
pattern: "react",
14+
group: "external",
15+
position: "before",
16+
},
17+
{
18+
pattern: "@plane/**",
19+
group: "external",
20+
position: "after",
21+
},
22+
],
23+
pathGroupsExcludedImportTypes: ["builtin", "internal", "react"],
24+
alphabetize: {
25+
order: "asc",
26+
caseInsensitive: true,
27+
},
28+
},
29+
],
30+
},
631
};

packages/propel/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@
1212
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist"
1313
},
1414
"exports": {
15-
"./ui/*": "./src/ui/*.tsx",
15+
"./avatar": "./src/avatar/index.ts",
1616
"./charts/*": "./src/charts/*/index.ts",
17+
"./dialog": "./src/dialog/index.ts",
18+
"./menu": "./src/menu/index.ts",
1719
"./table": "./src/table/index.ts",
20+
"./tabs": "./src/tabs/index.ts",
1821
"./styles/fonts": "./src/styles/fonts/index.css"
1922
},
2023
"dependencies": {
21-
"@radix-ui/react-slot": "^1.1.1",
24+
"@base-ui-components/react": "^1.0.0-beta.2",
25+
"@plane/utils": "*",
2226
"@tanstack/react-table": "^8.21.3",
2327
"class-variance-authority": "^0.7.1",
2428
"lucide-react": "^0.469.0",
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import React from "react";
2+
import { Avatar as AvatarPrimitive } from "@base-ui-components/react/avatar";
3+
// utils
4+
import { cn } from "@plane/utils";
5+
6+
export type TAvatarSize = "sm" | "md" | "base" | "lg" | number;
7+
8+
type Props = {
9+
name?: string; //The name of the avatar which will be displayed on the tooltip
10+
fallbackBackgroundColor?: string; //The background color if the avatar image fails to load
11+
fallbackText?: string;
12+
fallbackTextColor?: string; //The text color if the avatar image fails to load
13+
showTooltip?: boolean;
14+
size?: TAvatarSize; //The size of the avatars
15+
shape?: "circle" | "square";
16+
src?: string; //The source of the avatar image
17+
className?: string;
18+
};
19+
20+
/**
21+
* Get the size details based on the size prop
22+
* @param size The size of the avatar
23+
* @returns The size details
24+
*/
25+
export const getSizeInfo = (size: TAvatarSize) => {
26+
switch (size) {
27+
case "sm":
28+
return {
29+
avatarSize: "h-4 w-4",
30+
fontSize: "text-xs",
31+
spacing: "-space-x-1",
32+
};
33+
case "md":
34+
return {
35+
avatarSize: "h-5 w-5",
36+
fontSize: "text-xs",
37+
spacing: "-space-x-1",
38+
};
39+
case "base":
40+
return {
41+
avatarSize: "h-6 w-6",
42+
fontSize: "text-sm",
43+
spacing: "-space-x-1.5",
44+
};
45+
case "lg":
46+
return {
47+
avatarSize: "h-7 w-7",
48+
fontSize: "text-sm",
49+
spacing: "-space-x-1.5",
50+
};
51+
default:
52+
return {
53+
avatarSize: "h-5 w-5",
54+
fontSize: "text-xs",
55+
spacing: "-space-x-1",
56+
};
57+
}
58+
};
59+
60+
/**
61+
* Get the border radius based on the shape prop
62+
* @param shape The shape of the avatar
63+
* @returns The border radius
64+
*/
65+
export const getBorderRadius = (shape: "circle" | "square") => {
66+
switch (shape) {
67+
case "circle":
68+
return "rounded-full";
69+
case "square":
70+
return "rounded";
71+
default:
72+
return "rounded-full";
73+
}
74+
};
75+
76+
/**
77+
* Check if the value is a valid number
78+
* @param value The value to check
79+
* @returns Whether the value is a valid number or not
80+
*/
81+
export const isAValidNumber = (value: any) => typeof value === "number" && !isNaN(value);
82+
83+
export const Avatar: React.FC<Props> = (props) => {
84+
const {
85+
name,
86+
fallbackBackgroundColor,
87+
fallbackText,
88+
fallbackTextColor,
89+
showTooltip = true,
90+
size = "md",
91+
shape = "circle",
92+
src,
93+
className = "",
94+
} = props;
95+
96+
// get size details based on the size prop
97+
const sizeInfo = getSizeInfo(size);
98+
99+
const fallbackLetter = name?.[0]?.toUpperCase() ?? fallbackText ?? "?";
100+
return (
101+
<div
102+
className={cn("grid place-items-center overflow-hidden", getBorderRadius(shape), {
103+
[sizeInfo.avatarSize]: !isAValidNumber(size),
104+
})}
105+
tabIndex={-1}
106+
>
107+
<AvatarPrimitive.Root className={cn("h-full w-full", getBorderRadius(shape), className)}>
108+
<AvatarPrimitive.Image src={src} width="48" height="48" />
109+
<AvatarPrimitive.Fallback
110+
className={cn(sizeInfo.fontSize, "grid h-full w-full place-items-center", getBorderRadius(shape), className)}
111+
style={{
112+
backgroundColor: fallbackBackgroundColor ?? "rgba(var(--color-primary-500))",
113+
color: fallbackTextColor ?? "#ffffff",
114+
}}
115+
>
116+
{fallbackLetter}
117+
</AvatarPrimitive.Fallback>
118+
</AvatarPrimitive.Root>
119+
</div>
120+
);
121+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./avatar";
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export enum EDialogPosition {
2+
TOP = "flex items-center justify-center text-center mx-4 my-10 md:my-20",
3+
CENTER = "flex items-end sm:items-center justify-center p-4 min-h-full",
4+
}
5+
6+
export enum EDialogWidth {
7+
SM = "sm:max-w-sm",
8+
MD = "sm:max-w-md",
9+
LG = "sm:max-w-lg",
10+
XL = "sm:max-w-xl",
11+
XXL = "sm:max-w-2xl",
12+
XXXL = "sm:max-w-3xl",
13+
XXXXL = "sm:max-w-4xl",
14+
VXL = "sm:max-w-5xl",
15+
VIXL = "sm:max-w-6xl",
16+
VIIXL = "sm:max-w-7xl",
17+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./root";
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"use client";
2+
3+
import * as React from "react";
4+
import { Dialog as BaseDialog } from "@base-ui-components/react";
5+
import { cn } from "@plane/utils";
6+
import { EDialogWidth } from "./constants";
7+
8+
function DialogPortal({ ...props }: React.ComponentProps<typeof BaseDialog.Portal>) {
9+
return <BaseDialog.Portal data-slot="dialog-portal" {...props} />;
10+
}
11+
12+
function DialogOverlay({ className, ...props }: React.ComponentProps<typeof BaseDialog.Backdrop>) {
13+
return (
14+
<BaseDialog.Backdrop
15+
data-slot="dialog-overlay"
16+
className={cn(
17+
"fixed inset-0 z-30 bg-custom-backdrop transition-all duration-200 [&[data-ending-style]]:opacity-0 [&[data-starting-style]]:opacity-0",
18+
className
19+
)}
20+
{...props}
21+
/>
22+
);
23+
}
24+
25+
function Dialog({ ...props }: React.ComponentProps<typeof BaseDialog.Root>) {
26+
return <BaseDialog.Root data-slot="dialog" {...props} />;
27+
}
28+
29+
function DialogTrigger({ ...props }: React.ComponentProps<typeof BaseDialog.Trigger>) {
30+
return <BaseDialog.Trigger data-slot="dialog-trigger" {...props} />;
31+
}
32+
33+
function DialogPanel({
34+
className,
35+
width = EDialogWidth.XXL,
36+
children,
37+
...props
38+
}: React.ComponentProps<typeof BaseDialog.Popup> & { width?: EDialogWidth }) {
39+
return (
40+
<DialogPortal data-slot="dialog-portal">
41+
<DialogOverlay />
42+
<BaseDialog.Popup
43+
data-slot="dialog-content"
44+
className={cn(
45+
"fixed flex justify-center top-0 left-0 w-full z-30 px-4 sm:py-20 overflow-y-auto overflow-hidden outline-none"
46+
)}
47+
{...props}
48+
>
49+
<div
50+
className={cn(
51+
"rounded-lg bg-custom-background-100 text-left shadow-custom-shadow-md transition-all w-full",
52+
width,
53+
className
54+
)}
55+
>
56+
{children}
57+
</div>
58+
</BaseDialog.Popup>
59+
</DialogPortal>
60+
);
61+
}
62+
63+
function DialogTitle({ className, ...props }: React.ComponentProps<typeof BaseDialog.Title>) {
64+
return (
65+
<BaseDialog.Title
66+
data-slot="dialog-title"
67+
className={cn("text-lg leading-none font-semibold", className)}
68+
{...props}
69+
/>
70+
);
71+
}
72+
// compound components
73+
Dialog.Trigger = DialogTrigger;
74+
Dialog.Panel = DialogPanel;
75+
Dialog.Title = DialogTitle;
76+
77+
export { Dialog, DialogTitle, DialogTrigger, DialogPanel };

packages/propel/src/menu/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./menu";
2+
export * from "./types";

0 commit comments

Comments
 (0)