@@ -32,3 +32,4 @@ export type { TopBannerProps } from "./top-banner";
|
||||
export { AnimatedPopover } from "./popover/index";
|
||||
export { TableActions, DropdownActions } from "./table/TableActions";
|
||||
export type { ActionType } from "./table/TableActions";
|
||||
export { Skeleton, SkeletonAvatar, SkeletonButton, SkeletonContainer, SkeletonText } from "./skeleton";
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import React from "react";
|
||||
|
||||
import classNames from "@calcom/lib/classNames";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
||||
type SkeletonBaseProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
interface SkeletonContainer {
|
||||
as?: keyof JSX.IntrinsicElements;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const SkeletonAvatar: React.FC<SkeletonBaseProps> = ({ className }) => {
|
||||
return <div className={classNames(`mt-1 rounded-full bg-gray-200 ltr:mr-2 rtl:ml-2`, className)} />;
|
||||
};
|
||||
|
||||
type SkeletonProps<T> = {
|
||||
as: keyof JSX.IntrinsicElements | React.FC;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
loading?: boolean;
|
||||
waitForTranslation?: boolean;
|
||||
loadingClassName?: string;
|
||||
} & (T extends React.FC<infer P>
|
||||
? P
|
||||
: T extends keyof JSX.IntrinsicElements
|
||||
? JSX.IntrinsicElements[T]
|
||||
: never);
|
||||
|
||||
const Skeleton = <T extends keyof JSX.IntrinsicElements | React.FC>({
|
||||
as,
|
||||
className = "",
|
||||
children,
|
||||
loading = false,
|
||||
/**
|
||||
* Assumes that the text needs translation by default and wait for it.
|
||||
*/
|
||||
waitForTranslation = true,
|
||||
/**
|
||||
* Classes that you need only in loading state
|
||||
*/
|
||||
loadingClassName = "",
|
||||
...rest
|
||||
}: SkeletonProps<T>) => {
|
||||
const { isLocaleReady } = useLocale();
|
||||
loading = (waitForTranslation ? !isLocaleReady : false) || loading;
|
||||
const Component = as;
|
||||
return (
|
||||
<Component
|
||||
className={classNames(
|
||||
loading
|
||||
? classNames(
|
||||
"font-size-0 dark:white-300 animate-pulse rounded-md bg-gray-300 text-transparent",
|
||||
loadingClassName
|
||||
)
|
||||
: "",
|
||||
className
|
||||
)}
|
||||
{...rest}>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
|
||||
const SkeletonText: React.FC<SkeletonBaseProps & { invisible?: boolean }> = ({
|
||||
className = "",
|
||||
invisible = false,
|
||||
}) => {
|
||||
return (
|
||||
<span
|
||||
className={classNames(
|
||||
`font-size-0 dark:white-300 inline-block animate-pulse rounded-md bg-gray-300 empty:before:inline-block empty:before:content-['']`,
|
||||
className,
|
||||
invisible ? "invisible" : ""
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const SkeletonButton: React.FC<SkeletonBaseProps> = ({ className }) => {
|
||||
return (
|
||||
<SkeletonContainer>
|
||||
<div className={classNames(`rounded-md bg-gray-200`, className)} />
|
||||
</SkeletonContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const SkeletonContainer: React.FC<SkeletonContainer> = ({ children, as, className }) => {
|
||||
const Component = as || "div";
|
||||
return <Component className={classNames("animate-pulse", className)}>{children}</Component>;
|
||||
};
|
||||
|
||||
export { Skeleton, SkeletonAvatar, SkeletonText, SkeletonButton, SkeletonContainer };
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';
|
||||
import { Examples, Example, Note, Title, VariantsTable, VariantColumn, RowTitles, CustomArgsTable} from '@calcom/storybook/components'
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
import { Skeleton, SkeletonAvatar, SkeletonText, SkeletonButton, SkeletonContainer } from './';
|
||||
|
||||
<Meta title="UI/Skeleton" component={Skeleton} />
|
||||
|
||||
<Title title="Skeleton" suffix="Brief" subtitle="Version 2.0 — Last Update: 22 Aug 2022"/>
|
||||
|
||||
|
||||
## Definition
|
||||
Skeletons are used as a placeholder to the content while the content is being loaded. It is used to improve the user experience by providing a visual cue that the content is loading.
|
||||
|
||||
## Structure
|
||||
|
||||
<CustomArgsTable of={Skeleton} />
|
||||
|
||||
|
||||
<Examples title="Skeleton Avatar" >
|
||||
<Example title="Primary">
|
||||
<SkeletonAvatar className="h-8 w-8" />
|
||||
</Example>
|
||||
</Examples>
|
||||
|
||||
<Examples title="Skeleton Text" >
|
||||
<Example title="Primary">
|
||||
<SkeletonText className="h-4 w-32"/>
|
||||
</Example>
|
||||
</Examples>
|
||||
|
||||
<Examples title="Skeleton Button" >
|
||||
<Example title="Primary">
|
||||
<SkeletonButton className="h-8 w-32"/>
|
||||
</Example>
|
||||
</Examples>
|
||||
Reference in New Issue
Block a user