Skip to content

Commit

Permalink
fix(form-pill): fix issues where pill text not being truncated (#4047)
Browse files Browse the repository at this point in the history
* fix(form-pill): fix issues where pill textt not being truncated

* chore(pr): update lockfile

* chore(pr): refactor recursion types

* fix(storybook): a11y unique ids

* fix(storybook): fix a11y violations

* chore(combobox): add ellipse stlying when selected value exceeds length

* fix(form-pill): apply ellipse min width box only to elements that have text as the child

* Update packages/paste-core/components/combobox/stories/MultiselectCombobox.stories.tsx

Co-authored-by: Sarah <[email protected]>

* Update packages/paste-core/components/form-pill-group/stories/index.stories.tsx

Co-authored-by: Nora Krantz <[email protected]>

* chore(pr): addressing comments

* chore(pr): addressing comments

---------

Co-authored-by: Sarah <[email protected]>
Co-authored-by: Nora Krantz <[email protected]>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Sep 3, 2024
1 parent e4d5814 commit f612d1b
Show file tree
Hide file tree
Showing 13 changed files with 236 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changeset/violet-cows-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/form-pill-group": patch
"@twilio-paste/core": patch
---

[FormPillGroup] fixed a bug where long text in a form pill would wrap and break styling. Text within FormPill is now truncated so FormPill(s) will not stretch beyond FormPillGroup width.
6 changes: 6 additions & 0 deletions .changeset/warm-zoos-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@twilio-paste/combobox": patch
"@twilio-paste/core": patch
---

[Combobox] added ellipse styling to text that exceeds length of a single select combobox when not active
2 changes: 2 additions & 0 deletions packages/paste-core/components/combobox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/text": "^10.0.0",
"@twilio-paste/theme": "^11.0.0",
"@twilio-paste/truncate": "^14.0.0",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@twilio-paste/utils": "^5.0.0",
Expand Down Expand Up @@ -89,6 +90,7 @@
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/text": "^10.1.0",
"@twilio-paste/theme": "^11.0.1",
"@twilio-paste/truncate": "^14.1.0",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@twilio-paste/utils": "^5.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ const Combobox = React.forwardRef<HTMLInputElement, ComboboxProps>(
autocomplete={autocomplete}
aria-describedby={helpText != null ? helpTextId : null}
element={`${element}_ELEMENT`}
textOverflow="ellipsis"
/>
{!autocomplete && (
<InputChevronWrapper element={`${element}_CHEVRON_WRAPPER`}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,16 @@ ComboboxInModal.parameters = {
},
};

export const ComboboxErrorNarrowContainer: StoryFn = () => {
return (
<Box maxWidth="150px">
<Combobox items={items} labelText="Choose a component:" helpText="This is the help text" hasError />
</Box>
);
};

ComboboxErrorNarrowContainer.storyName = "Combobox - Error narrow container";

export const ComboboxInPopover: StoryFn = () => {
return (
<PopoverContainer baseId="popover-example">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -713,3 +713,27 @@ export default {
),
],
} as Meta;

export const MultiselectComboboxInNarrowContainer = (): StoryFn => {
const [inputValue, setInputValue] = React.useState("");
const filteredItems = React.useMemo(() => getFilteredItems(inputValue), [inputValue]);

return (
<Box maxWidth="300px">
<MultiselectCombobox
labelText="Choose a Paste Component"
selectedItemsLabelText="Selected Paste components"
helpText="Paste components are the building blocks of your product UI."
items={filteredItems}
onInputValueChange={({ inputValue: newInputValue = "" }) => {
setInputValue(newInputValue);
}}
onSelectedItemsChange={(selectedItems) => {
// eslint-disable-next-line no-console
console.log(selectedItems);
}}
/>
</Box>
);
};
MultiselectComboboxInNarrowContainer.storyName = "Narrow Container";
2 changes: 2 additions & 0 deletions packages/paste-core/components/form-pill-group/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@twilio-paste/style-props": "^9.0.0",
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/theme": "^11.0.0",
"@twilio-paste/truncate": "^14.0.0",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@types/react": "^16.8.6 || ^17.0.2 || ^18.0.27",
Expand All @@ -58,6 +59,7 @@
"@twilio-paste/style-props": "^9.1.0",
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/theme": "^11.0.0",
"@twilio-paste/truncate": "^14.1.0",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@types/react": "^18.0.27",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export const FormPill = React.forwardRef<HTMLElement, FormPillProps>(
position="relative"
display="inline-block"
borderRadius="borderRadiusPill"
maxWidth="100%"
{...computedStyles}
>
<CompositeItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Box, safelySpreadBoxProps } from "@twilio-paste/box";
import type { BoxElementProps, BoxProps } from "@twilio-paste/box";
import { ErrorIcon } from "@twilio-paste/icons/esm/ErrorIcon";
import { ScreenReaderOnly } from "@twilio-paste/screen-reader-only";
import { Truncate } from "@twilio-paste/truncate";
import * as React from "react";

import { hoverPillStyles, pillStyles } from "./FormPill.styles";
Expand Down Expand Up @@ -54,6 +55,29 @@ export const FormPillButton = React.forwardRef<HTMLElement, FormPillStylesProps>
const { size, variant: groupVariant } = React.useContext(FormPillGroupContext);
const { height, fontSize } = sizeStyles[size];

const renderChildren = (children: React.ReactNode): React.ReactNode => {
if (typeof children === "string") {
return <Truncate title={children}>{children}</Truncate>;
}

if (React.isValidElement(children)) {
if (children.props.children && typeof children.props.children === "string") {
return (
<Box minWidth="0" element={`${element}_TEXT_TRUNCATE_WRAPPER`}>
<children.type {...children.props}>{renderChildren(children.props.children)}</children.type>
</Box>
);
}
return <children.type {...children.props}>{renderChildren(children.props.children)}</children.type>;
}

if (Array.isArray(children)) {
return children.map((child) => renderChildren(child));
}

return children;
};

return (
<Box
{...safelySpreadBoxProps(props)}
Expand All @@ -77,6 +101,7 @@ export const FormPillButton = React.forwardRef<HTMLElement, FormPillStylesProps>
paddingLeft="space30"
paddingRight={isDismissable ? (size === "large" ? "space90" : "space80") : "space30"}
transition="background-color 150ms ease-in, border-color 150ms ease-in, box-shadow 150ms ease-in, color 150ms ease-in"
maxWidth="100%"
{...computedStyles}
>
<Box display="flex" height="100%" alignItems="center" columnGap="space20" opacity={isDisabled ? 0.3 : 1}>
Expand All @@ -86,7 +111,7 @@ export const FormPillButton = React.forwardRef<HTMLElement, FormPillStylesProps>
<ScreenReaderOnly>{i18nErrorLabel}</ScreenReaderOnly>
</>
) : null}
{props.children}
{renderChildren(props.children)}
</Box>
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const FormPillGroupStyles = React.forwardRef<HTMLUListElement, FormPillGroupProp
padding="space0"
display={display}
flexWrap="wrap"
maxWidth="100%"
{...SizeStyles[size]}
>
{props.children}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { StoryFn } from "@storybook/react";
// eslint-disable-next-line import/no-extraneous-dependencies
import { Avatar } from "@twilio-paste/avatar";
import { Box } from "@twilio-paste/box";
import { CalendarIcon } from "@twilio-paste/icons/esm/CalendarIcon";
import { Stack } from "@twilio-paste/stack";
import { Text } from "@twilio-paste/text";
import * as React from "react";

import { FormPill, FormPillGroup, useFormPillState } from "../src";
Expand Down Expand Up @@ -177,6 +180,152 @@ export const FormPillTreeVariant = (): JSX.Element => {

FormPillTreeVariant.storyName = "FormPillGroup Tree Variant";

export const PillStringOverflowVSComposed: StoryFn<
React.PropsWithChildren<{
selected?: boolean;
dismissable?: boolean;
disabled?: boolean;
ariaLabel?: string;
size?: FormPillGroupSizeVariant;
}>
> = ({ selected = false, dismissable = true, disabled = false, ariaLabel = "Basic pills:", size }) => {
const pillState = useFormPillState();
const pillState2 = useFormPillState();

return (
<Box maxWidth="150px">
<Stack orientation="vertical" spacing="space80">
<FormPillGroup {...pillState} data-testid="form-pill-group-1" aria-label={ariaLabel} size={size}>
{PILL_NAMES.map((pill, index) => (
<FormPill
key={`${pill}-1`}
data-testid={`form-pill-${index}-01`}
{...pillState}
selected={selected}
variant={index > 2 ? "error" : "default"}
onDismiss={dismissable ? () => {} : undefined}
disabled={disabled}
>
{index % 3 === 2 ? (
<Avatar
size={size === "large" ? "sizeIcon20" : "sizeIcon10"}
name="avatar example"
src="./avatars/avatar4.png"
/>
) : null}
{index % 3 === 1 ? (
<CalendarIcon decorative size={size === "large" ? "sizeIcon20" : "sizeIcon10"} />
) : null}
{pill}
</FormPill>
))}
</FormPillGroup>

<FormPillGroup {...pillState2} data-testid="form-pill-group-2" aria-label={ariaLabel} size={size}>
{PILL_NAMES.map((pill, index) => (
<FormPill
key={`${pill}-2`}
data-testid={`form-pill-${index}-02`}
{...pillState2}
selected={selected}
variant={index > 2 ? "error" : "default"}
onDismiss={dismissable ? () => {} : undefined}
disabled={disabled}
>
{pill}
</FormPill>
))}
</FormPillGroup>
</Stack>
</Box>
);
};

PillStringOverflowVSComposed.storyName = "Pill String Overflow vs Composed";

export const PillNarrowContainerDecorationsEnd: StoryFn<
React.PropsWithChildren<{
selected?: boolean;
dismissable?: boolean;
disabled?: boolean;
ariaLabel?: string;
size?: FormPillGroupSizeVariant;
}>
> = ({ selected = false, dismissable = true, disabled = false, ariaLabel = "Basic pills:", size }) => {
const pillState = useFormPillState();
const pillState2 = useFormPillState();

return (
<Box maxWidth="150px">
<FormPillGroup {...pillState} data-testid="form-pill-group" aria-label={ariaLabel} size={size}>
{PILL_NAMES.map((pill, index) => (
<FormPill
key={`${pill}-1`}
data-testid={`form-pill-${index}`}
{...pillState}
selected={selected}
variant={index > 2 ? "error" : "default"}
onDismiss={dismissable ? () => {} : undefined}
disabled={disabled}
>
{pill}
{index % 3 === 2 ? (
<Avatar
size={size === "large" ? "sizeIcon20" : "sizeIcon10"}
name="avatar example"
src="./avatars/avatar4.png"
/>
) : null}
{index % 3 === 1 ? <CalendarIcon decorative size={size === "large" ? "sizeIcon20" : "sizeIcon10"} /> : null}
</FormPill>
))}
</FormPillGroup>
</Box>
);
};

export const PillNarrowContainerFormattedTextContent: StoryFn<
React.PropsWithChildren<{
selected?: boolean;
dismissable?: boolean;
disabled?: boolean;
ariaLabel?: string;
size?: FormPillGroupSizeVariant;
}>
> = ({ selected = false, dismissable = true, disabled = false, ariaLabel = "Basic pills:", size }) => {
const pillState = useFormPillState();

return (
<Box maxWidth="90px">
<FormPillGroup {...pillState} data-testid="form-pill-group" aria-label={ariaLabel} size={size}>
{PILL_NAMES.map((pill, index) => (
<FormPill
key={`${pill}-1`}
data-testid={`form-pill-${index}`}
{...pillState}
selected={selected}
variant={index > 2 ? "error" : "default"}
onDismiss={dismissable ? () => {} : undefined}
disabled={disabled}
>
{index % 3 === 2 ? (
<Avatar
size={size === "large" ? "sizeIcon20" : "sizeIcon10"}
name="avatar example"
src="./avatars/avatar4.png"
/>
) : null}
{index % 3 === 1 ? <CalendarIcon decorative size={size === "large" ? "sizeIcon20" : "sizeIcon10"} /> : null}
<Text as="p" fontWeight="fontWeightBold" fontStyle="italic">
{pill}
</Text>
</FormPill>
))}
</FormPillGroup>
</Box>
);
};

// eslint-disable-next-line import/no-default-export
export default {
title: "Components/Form Pill Group",
Expand Down
2 changes: 2 additions & 0 deletions packages/paste-core/components/popover/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/text": "^10.0.0",
"@twilio-paste/theme": "^11.0.0",
"@twilio-paste/truncate": "^14.0.0",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@types/react": "^16.8.6 || ^17.0.2 || ^18.0.27",
Expand Down Expand Up @@ -71,6 +72,7 @@
"@twilio-paste/styling-library": "^3.0.0",
"@twilio-paste/text": "^10.1.0",
"@twilio-paste/theme": "^11.0.0",
"@twilio-paste/truncate": "^14.1.0",
"@twilio-paste/types": "^6.0.0",
"@twilio-paste/uid-library": "^2.0.0",
"@types/react": "^18.0.27",
Expand Down
6 changes: 6 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12207,6 +12207,7 @@ __metadata:
"@twilio-paste/styling-library": ^3.0.0
"@twilio-paste/text": ^10.1.0
"@twilio-paste/theme": ^11.0.1
"@twilio-paste/truncate": ^14.1.0
"@twilio-paste/types": ^6.0.0
"@twilio-paste/uid-library": ^2.0.0
"@twilio-paste/utils": ^5.0.0
Expand Down Expand Up @@ -12244,6 +12245,7 @@ __metadata:
"@twilio-paste/styling-library": ^3.0.0
"@twilio-paste/text": ^10.0.0
"@twilio-paste/theme": ^11.0.0
"@twilio-paste/truncate": ^14.0.0
"@twilio-paste/types": ^6.0.0
"@twilio-paste/uid-library": ^2.0.0
"@twilio-paste/utils": ^5.0.0
Expand Down Expand Up @@ -13073,6 +13075,7 @@ __metadata:
"@twilio-paste/style-props": ^9.1.0
"@twilio-paste/styling-library": ^3.0.0
"@twilio-paste/theme": ^11.0.0
"@twilio-paste/truncate": ^14.1.0
"@twilio-paste/types": ^6.0.0
"@twilio-paste/uid-library": ^2.0.0
"@types/react": ^18.0.27
Expand All @@ -13094,6 +13097,7 @@ __metadata:
"@twilio-paste/style-props": ^9.0.0
"@twilio-paste/styling-library": ^3.0.0
"@twilio-paste/theme": ^11.0.0
"@twilio-paste/truncate": ^14.0.0
"@twilio-paste/types": ^6.0.0
"@twilio-paste/uid-library": ^2.0.0
"@types/react": ^16.8.6 || ^17.0.2 || ^18.0.27
Expand Down Expand Up @@ -14109,6 +14113,7 @@ __metadata:
"@twilio-paste/styling-library": ^3.0.0
"@twilio-paste/text": ^10.1.0
"@twilio-paste/theme": ^11.0.0
"@twilio-paste/truncate": ^14.1.0
"@twilio-paste/types": ^6.0.0
"@twilio-paste/uid-library": ^2.0.0
"@types/react": ^18.0.27
Expand Down Expand Up @@ -14137,6 +14142,7 @@ __metadata:
"@twilio-paste/styling-library": ^3.0.0
"@twilio-paste/text": ^10.0.0
"@twilio-paste/theme": ^11.0.0
"@twilio-paste/truncate": ^14.0.0
"@twilio-paste/types": ^6.0.0
"@twilio-paste/uid-library": ^2.0.0
"@types/react": ^16.8.6 || ^17.0.2 || ^18.0.27
Expand Down

0 comments on commit f612d1b

Please sign in to comment.