chore: Updating List item and List components in ADS to start using it in Entity explorer (#38344)
This commit is contained in:
parent
aaabb154f8
commit
2246bde9bb
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { List, ListItem, Icon } from "@appsmith/ads";
|
import { List, ListItem, Icon, Button } from "@appsmith/ads";
|
||||||
import type { StoryObj } from "@storybook/react";
|
import type { StoryObj } from "@storybook/react";
|
||||||
import type { ListItemProps, ListProps } from "@appsmith/ads";
|
import type { ListItemProps, ListProps } from "@appsmith/ads";
|
||||||
|
|
||||||
|
|
@ -79,15 +79,21 @@ const ListItemArgTypes = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
endIcon: {
|
rightControl: {
|
||||||
control: "text",
|
description: "The control to display at the end of the list item",
|
||||||
description: "The icon to display at the end of the list item",
|
|
||||||
table: {
|
table: {
|
||||||
type: {
|
type: {
|
||||||
summary: "string",
|
summary: "ReactNode",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
rightControlVisibility: {
|
||||||
|
description:
|
||||||
|
"`always` type will show the right control always. `hover` type will show the right control only when the list item is hovered.",
|
||||||
|
control: "radio",
|
||||||
|
options: ["always", "hover"],
|
||||||
|
defaultValue: "always",
|
||||||
|
},
|
||||||
description: {
|
description: {
|
||||||
control: "text",
|
control: "text",
|
||||||
description: "Description text to be shown alongside the title",
|
description: "Description text to be shown alongside the title",
|
||||||
|
|
@ -140,11 +146,12 @@ const ListItemArgTypes = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onEndIconClick: {
|
customTitleComponent: {
|
||||||
description: "callback for when the end icon is clicked",
|
description:
|
||||||
|
"A custom title component for the list item to use input component for name editing",
|
||||||
table: {
|
table: {
|
||||||
type: {
|
type: {
|
||||||
summary: "() => void",
|
summary: "ReactNode",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -163,7 +170,7 @@ ListItemLargeStory.args = {
|
||||||
description: "inline",
|
description: "inline",
|
||||||
descriptionType: "inline",
|
descriptionType: "inline",
|
||||||
size: "lg",
|
size: "lg",
|
||||||
endIcon: "add-more",
|
rightControl: <Icon name="add-more" size={"md"} />,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ListItemErrorStory = ListItemTemplate.bind({}) as StoryObj;
|
export const ListItemErrorStory = ListItemTemplate.bind({}) as StoryObj;
|
||||||
|
|
@ -215,10 +222,12 @@ ListItemOverflowStory.args = {
|
||||||
title: "Action item 1 Action item 1 Action item 1 Action item 1",
|
title: "Action item 1 Action item 1 Action item 1 Action item 1",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ListItemEndIconStory = ListItemTemplate.bind({}) as StoryObj;
|
export const ListItemRightControlStory = ListItemTemplate.bind({}) as StoryObj;
|
||||||
ListItemEndIconStory.storyName = "List item end icon";
|
ListItemRightControlStory.storyName = "List item right control";
|
||||||
ListItemEndIconStory.argTypes = ListItemArgTypes;
|
ListItemRightControlStory.argTypes = ListItemArgTypes;
|
||||||
ListItemEndIconStory.args = {
|
ListItemRightControlStory.args = {
|
||||||
title: "Action item 1",
|
title: "Action item 1",
|
||||||
endIcon: "add-more",
|
rightControl: (
|
||||||
|
<Button isIconButton kind="tertiary" size={"sm"} startIcon="add-more" />
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -26,47 +26,15 @@ const Sizes = {
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const StyledList = styled.div`
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
padding: var(--ads-v2-spaces-1);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--ads-v2-spaces-2);
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Wrapper = styled.div`
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--ads-v2-spaces-3);
|
|
||||||
cursor: pointer;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const TooltipTextWrapper = styled.div`
|
export const TooltipTextWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ContentWrapper = styled.div`
|
|
||||||
display: flex;
|
|
||||||
gap: var(--ads-v2-spaces-3);
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const ContentTextWrapper = styled.div`
|
|
||||||
display: flex;
|
|
||||||
gap: var(--ads-v2-spaces-3);
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const DescriptionWrapper = styled.div`
|
export const DescriptionWrapper = styled.div`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
gap: var(--ads-v2-spaces-3);
|
gap: var(--ads-v2-spaces-2);
|
||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -74,34 +42,24 @@ export const InlineDescriptionWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 0;
|
|
||||||
gap: var(--ads-v2-spaces-3);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const EndIconWrapper = styled.div`
|
export const RightControlWrapper = styled.div`
|
||||||
position: absolute;
|
height: 100%;
|
||||||
right: var(--ads-v2-spaces-3);
|
line-height: normal;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledListItem = styled.div<{
|
export const ContentTextWrapper = styled.div`
|
||||||
size: ListSizes;
|
|
||||||
endIcon?: string;
|
|
||||||
isBlockDescription: boolean;
|
|
||||||
}>`
|
|
||||||
${Variables};
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: var(--ads-v2-border-radius);
|
|
||||||
padding: var(--ads-v2-spaces-3);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
// 40px is the offset to make it look like the end icon is part of this div
|
gap: var(--ads-v2-spaces-3);
|
||||||
${(props) => !!props.endIcon && `padding: 8px 40px 8px 8px;`}}
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
${({ size }) => Sizes[size]}
|
min-width: 0;
|
||||||
|
|
||||||
|
|
||||||
& .${ListItemTextOverflowClassName} {
|
& .${ListItemTextOverflowClassName} {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -115,7 +73,7 @@ export const StyledListItem = styled.div<{
|
||||||
}
|
}
|
||||||
|
|
||||||
& .${ListItemBDescClassName} {
|
& .${ListItemBDescClassName} {
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 1;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
text-overflow: initial;
|
text-overflow: initial;
|
||||||
|
|
@ -126,14 +84,53 @@ export const StyledListItem = styled.div<{
|
||||||
|
|
||||||
& .${ListItemIDescClassName} {
|
& .${ListItemIDescClassName} {
|
||||||
font-size: var(--listitem-idescription-font-size);
|
font-size: var(--listitem-idescription-font-size);
|
||||||
|
line-height: 16px;
|
||||||
|
padding-right: var(--ads-v2-spaces-2);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledList = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
padding: var(--ads-v2-spaces-1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--ads-v2-spaces-2);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledListItem = styled.div<{
|
||||||
|
size: ListSizes;
|
||||||
|
}>`
|
||||||
|
${Variables};
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
border-radius: var(--ads-v2-border-radius);
|
||||||
|
padding: var(--ads-v2-spaces-2);
|
||||||
|
padding-left: var(--ads-v2-spaces-3);
|
||||||
|
|
||||||
|
${({ size }) => Sizes[size]}
|
||||||
|
|
||||||
|
&[data-isblockdescription="true"] {
|
||||||
|
height: 54px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&[data-isblockdescription="false"] {
|
||||||
background-color: var(--ads-v2-colors-content-surface-hover-bg);
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&[data-rightcontrolvisibility="hover"] {
|
||||||
background-color: var(--ads-v2-colors-content-surface-active-bg);
|
${RightControlWrapper} {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&:hover ${RightControlWrapper} {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-selected="true"] {
|
&[data-selected="true"] {
|
||||||
|
|
@ -144,6 +141,15 @@ export const StyledListItem = styled.div<{
|
||||||
&[data-disabled="true"] {
|
&[data-disabled="true"] {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: var(--ads-v2-opacity-disabled);
|
opacity: var(--ads-v2-opacity-disabled);
|
||||||
|
background-color: var(--ads-v2-colors-content-surface-default-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--ads-v2-colors-content-surface-hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--ads-v2-colors-content-surface-active-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Focus styles */
|
/* Focus styles */
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,14 @@ import type { ListItemProps, ListProps } from "./List.types";
|
||||||
import {
|
import {
|
||||||
ContentTextWrapper,
|
ContentTextWrapper,
|
||||||
DescriptionWrapper,
|
DescriptionWrapper,
|
||||||
EndIconWrapper,
|
|
||||||
InlineDescriptionWrapper,
|
InlineDescriptionWrapper,
|
||||||
|
RightControlWrapper,
|
||||||
StyledList,
|
StyledList,
|
||||||
StyledListItem,
|
StyledListItem,
|
||||||
TooltipTextWrapper,
|
TooltipTextWrapper,
|
||||||
Wrapper,
|
|
||||||
} from "./List.styles";
|
} from "./List.styles";
|
||||||
import type { TextProps } from "../Text";
|
import type { TextProps } from "../Text";
|
||||||
import { Text } from "../Text";
|
import { Text } from "../Text";
|
||||||
import { Button } from "../Button";
|
|
||||||
import { Tooltip } from "../Tooltip";
|
import { Tooltip } from "../Tooltip";
|
||||||
import {
|
import {
|
||||||
ListClassName,
|
ListClassName,
|
||||||
|
|
@ -23,7 +21,6 @@ import {
|
||||||
ListItemIDescClassName,
|
ListItemIDescClassName,
|
||||||
ListItemTextOverflowClassName,
|
ListItemTextOverflowClassName,
|
||||||
ListItemTitleClassName,
|
ListItemTitleClassName,
|
||||||
ListItemWrapperClassName,
|
|
||||||
} from "./List.constants";
|
} from "./List.constants";
|
||||||
|
|
||||||
function List({ className, items, ...rest }: ListProps) {
|
function List({ className, items, ...rest }: ListProps) {
|
||||||
|
|
@ -85,8 +82,9 @@ function ListItem(props: ListItemProps) {
|
||||||
const {
|
const {
|
||||||
description,
|
description,
|
||||||
descriptionType = "inline",
|
descriptionType = "inline",
|
||||||
endIcon,
|
|
||||||
hasError,
|
hasError,
|
||||||
|
rightControl,
|
||||||
|
rightControlVisibility = "always",
|
||||||
size = "md",
|
size = "md",
|
||||||
startIcon,
|
startIcon,
|
||||||
title,
|
title,
|
||||||
|
|
@ -104,27 +102,6 @@ function ListItem(props: ListItemProps) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const endIconhandleKeyDown = (e: React.KeyboardEvent) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
if (!props.isDisabled && props.onEndIconClick) {
|
|
||||||
switch (e.key) {
|
|
||||||
case "Enter":
|
|
||||||
case " ":
|
|
||||||
props.onEndIconClick();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const endIconOnClick = (e: React.MouseEvent) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
if (!props.isDisabled && props.onEndIconClick) {
|
|
||||||
props.onEndIconClick();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOnClick = () => {
|
const handleOnClick = () => {
|
||||||
if (!props.isDisabled && props.onClick) {
|
if (!props.isDisabled && props.onClick) {
|
||||||
props.onClick();
|
props.onClick();
|
||||||
|
|
@ -132,20 +109,23 @@ function ListItem(props: ListItemProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper className={clsx(ListItemWrapperClassName, props.wrapperClassName)}>
|
|
||||||
<StyledListItem
|
<StyledListItem
|
||||||
className={clsx(ListItemClassName, props.className)}
|
className={clsx(ListItemClassName, props.className)}
|
||||||
data-disabled={props.isDisabled || false}
|
data-disabled={props.isDisabled || false}
|
||||||
|
data-isblockdescription={isBlockDescription}
|
||||||
|
data-rightcontrolvisibility={rightControlVisibility}
|
||||||
data-selected={props.isSelected}
|
data-selected={props.isSelected}
|
||||||
endIcon={props.endIcon}
|
|
||||||
isBlockDescription={isBlockDescription}
|
|
||||||
onClick={handleOnClick}
|
|
||||||
onKeyDown={listItemhandleKeyDown}
|
|
||||||
size={size}
|
size={size}
|
||||||
tabIndex={props.isDisabled ? -1 : 0}
|
tabIndex={props.isDisabled ? -1 : 0}
|
||||||
>
|
>
|
||||||
<ContentTextWrapper>
|
<ContentTextWrapper
|
||||||
|
onClick={handleOnClick}
|
||||||
|
onKeyDown={listItemhandleKeyDown}
|
||||||
|
>
|
||||||
{startIcon}
|
{startIcon}
|
||||||
|
{props.customTitleComponent ? (
|
||||||
|
props.customTitleComponent
|
||||||
|
) : (
|
||||||
<InlineDescriptionWrapper>
|
<InlineDescriptionWrapper>
|
||||||
<DescriptionWrapper>
|
<DescriptionWrapper>
|
||||||
<TextWithTooltip
|
<TextWithTooltip
|
||||||
|
|
@ -175,22 +155,12 @@ function ListItem(props: ListItemProps) {
|
||||||
</TextWithTooltip>
|
</TextWithTooltip>
|
||||||
)}
|
)}
|
||||||
</InlineDescriptionWrapper>
|
</InlineDescriptionWrapper>
|
||||||
</ContentTextWrapper>
|
|
||||||
</StyledListItem>
|
|
||||||
{endIcon && (
|
|
||||||
<EndIconWrapper>
|
|
||||||
<Button
|
|
||||||
isDisabled={props.isDisabled}
|
|
||||||
isIconButton
|
|
||||||
kind="tertiary"
|
|
||||||
onClick={endIconOnClick}
|
|
||||||
onKeyDown={endIconhandleKeyDown}
|
|
||||||
size={"sm"}
|
|
||||||
startIcon={endIcon}
|
|
||||||
/>
|
|
||||||
</EndIconWrapper>
|
|
||||||
)}
|
)}
|
||||||
</Wrapper>
|
</ContentTextWrapper>
|
||||||
|
{rightControl && (
|
||||||
|
<RightControlWrapper>{rightControl}</RightControlWrapper>
|
||||||
|
)}
|
||||||
|
</StyledListItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ export type ListSizes = Extract<Sizes, "md" | "lg">;
|
||||||
export interface ListItemProps {
|
export interface ListItemProps {
|
||||||
/** The icon to display before the list item title. */
|
/** The icon to display before the list item title. */
|
||||||
startIcon?: ReactNode;
|
startIcon?: ReactNode;
|
||||||
/** The icon to display at the end. Pass name of the icon from remix-icon library(eg: home-2-line) or an svg icon. */
|
/** The control to display at the end. */
|
||||||
endIcon?: string;
|
rightControl?: ReactNode;
|
||||||
/** callback for when the endIcon is clicked */
|
/** */
|
||||||
onEndIconClick?: () => void;
|
rightControlVisibility?: "hover" | "always";
|
||||||
/** callback for when the list item is clicked */
|
/** callback for when the list item is clicked */
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
/** Whether the list item is disabled. */
|
/** Whether the list item is disabled. */
|
||||||
|
|
@ -23,17 +23,17 @@ export interface ListItemProps {
|
||||||
/** The title/label of the list item */
|
/** The title/label of the list item */
|
||||||
title: string;
|
title: string;
|
||||||
/** Description text to be shown alongside the title */
|
/** Description text to be shown alongside the title */
|
||||||
description: string;
|
description?: string;
|
||||||
/** `inline` type will show the description beside the title. `block` type will show the description
|
/** `inline` type will show the description beside the title. `block` type will show the description
|
||||||
* below the title.
|
* below the title.
|
||||||
*/
|
*/
|
||||||
descriptionType: "inline" | "block";
|
descriptionType?: "inline" | "block";
|
||||||
/** class names for the list item */
|
/** class names for the list item */
|
||||||
className?: string;
|
className?: string;
|
||||||
/** class names for the wrapper */
|
|
||||||
wrapperClassName?: string;
|
|
||||||
/** id for the list item */
|
/** id for the list item */
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/** customTitleComponent for the list item to use input component for name editing */
|
||||||
|
customTitleComponent?: ReactNode | ReactNode[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListProps {
|
export interface ListProps {
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ export const useAddQueryListItems = () => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
startIcon: icon,
|
startIcon: icon,
|
||||||
wrapperClassName: className,
|
className: className,
|
||||||
title,
|
title,
|
||||||
description:
|
description:
|
||||||
fileOperation.focusEntityType === FocusEntity.QUERY_MODULE_INSTANCE
|
fileOperation.focusEntityType === FocusEntity.QUERY_MODULE_INSTANCE
|
||||||
|
|
|
||||||
|
|
@ -266,8 +266,8 @@ export { EntityIcon };
|
||||||
// fontSize is set to 56% by default.
|
// fontSize is set to 56% by default.
|
||||||
export function ApiMethodIcon(
|
export function ApiMethodIcon(
|
||||||
type: keyof typeof HTTP_METHOD,
|
type: keyof typeof HTTP_METHOD,
|
||||||
height = "18px",
|
height = "16px",
|
||||||
width = "36px",
|
width = "34px",
|
||||||
fontSize = 52,
|
fontSize = 52,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const AddJS = () => {
|
||||||
: "",
|
: "",
|
||||||
descriptionType: "inline",
|
descriptionType: "inline",
|
||||||
onClick: onCreateItemClick.bind(null, data),
|
onClick: onCreateItemClick.bind(null, data),
|
||||||
wrapperClassName: createAddClassName(title),
|
className: createAddClassName(title),
|
||||||
} as ListItemProps;
|
} as ListItemProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ const StyledList = styled(List)`
|
||||||
& .ds-load-more .ads-v2-listitem__title {
|
& .ds-load-more .ads-v2-listitem__title {
|
||||||
--color: var(--ads-v2-color-fg-subtle);
|
--color: var(--ads-v2-color-fg-subtle);
|
||||||
}
|
}
|
||||||
& .ads-v2-listitem__wrapper .ads-v2-listitem__idesc {
|
& .ads-v2-listitem .ads-v2-listitem__idesc {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .ads-v2-listitem__wrapper:hover .ads-v2-listitem__idesc {
|
& .ads-v2-listitem:hover .ads-v2-listitem__idesc {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user