diff --git a/apps/website/screens/components/avatar/code/AvatarCodePage.tsx b/apps/website/screens/components/avatar/code/AvatarCodePage.tsx
index 1d55b83a54..1c6722f879 100644
--- a/apps/website/screens/components/avatar/code/AvatarCodePage.tsx
+++ b/apps/website/screens/components/avatar/code/AvatarCodePage.tsx
@@ -7,6 +7,7 @@ import basicUsage from "./examples/basicUsage";
import clickable from "./examples/clickable";
import tooltip from "./examples/tooltip";
import status from "./examples/status";
+import StatusBadge from "@/common/StatusBadge";
const statusTypeString = `{
mode: 'default' | 'info' |
@@ -100,6 +101,19 @@ const sections = [
|
diff --git a/packages/lib/src/avatar/Avatar.tsx b/packages/lib/src/avatar/Avatar.tsx
index 01d3dffe66..c66929c2d4 100644
--- a/packages/lib/src/avatar/Avatar.tsx
+++ b/packages/lib/src/avatar/Avatar.tsx
@@ -1,5 +1,5 @@
-import { memo, useCallback, useMemo, useState } from "react";
-import AvatarPropsType from "./types";
+import { forwardRef, useCallback, useMemo, useState } from "react";
+import AvatarPropsType, { ContentType, LabelWrapperType } from "./types";
import { getBorderWidth, getFontSize, getInitials, getModeColor } from "./utils";
import DxcTypography from "../typography/Typography";
import DxcImage from "../image/Image";
@@ -63,107 +63,145 @@ const StatusContainer = styled.div<{
background-color: ${({ status }) => getModeColor(status!.mode)};
`;
-const DxcAvatar = memo(
- ({
- color = "neutral",
- disabled = false,
- icon = "person",
- imageSrc,
- label,
- linkHref,
- onClick,
- primaryText,
- secondaryText,
- shape = "circle",
- size = "medium",
- status,
- tabIndex = 0,
- title,
- }: AvatarPropsType) => {
+const content = ({
+ hasAction,
+ onClick,
+ linkHref,
+ disabled,
+ imageSrc,
+ error,
+ handleError,
+ label,
+ title,
+ size,
+ initials,
+ icon,
+ color,
+ status,
+}: ContentType) => (
+ <>
+
+ {(!!onClick || !!linkHref || disabled) && }
+
+ {imageSrc && !error ? (
+
+ ) : label ? (
+
+ {initials}
+
+ ) : (
+
+ {icon && (typeof icon === "string" ? : icon)}
+
+ )}
+
+ {status && }
+ >
+);
+
+const LabelWrapper = ({ condition, children, primaryText, secondaryText }: LabelWrapperType) =>
+ condition ? (
+
+ {children}
+
+ {primaryText && (
+
+ {primaryText}
+
+ )}
+ {secondaryText && (
+
+ {secondaryText}
+
+ )}
+
+
+ ) : (
+ <>{children}>
+ );
+
+const DxcAvatar = forwardRef(
+ (
+ {
+ color = "neutral",
+ disabled = false,
+ icon = "person",
+ imageSrc,
+ label,
+ linkHref,
+ onClick,
+ primaryText,
+ secondaryText,
+ shape = "circle",
+ size = "medium",
+ status,
+ tabIndex = 0,
+ title,
+ }: AvatarPropsType,
+ ref
+ ) => {
const [error, setError] = useState(false);
const initials = useMemo(() => getInitials(label), [label]);
const handleError = useCallback(() => setError(true), []);
const hasAction = !disabled && (!!onClick || !!linkHref);
- const content = (
- <>
-
- {(!!onClick || !!linkHref || disabled) && }
-
- {imageSrc && !error ? (
-
- ) : label ? (
-
- {initials}
-
- ) : (
-
- {icon && (typeof icon === "string" ? : icon)}
-
- )}
-
- {status && }
- >
- );
-
- const LabelWrapper = ({ condition, children }: { condition: boolean; children: React.ReactNode }) =>
- condition ? (
-
- {children}
-
- {primaryText && (
-
- {primaryText}
-
- )}
- {secondaryText && (
-
- {secondaryText}
-
- )}
-
-
- ) : (
- <>{children}>
- );
-
return (
-
+
void;
+ linkHref?: string;
+ disabled?: boolean;
+ imageSrc?: string;
+ error: boolean;
+ handleError: () => void;
+ label?: string;
+ title?: string;
+ size: Size;
+ initials: string;
+ icon?: string | SVG;
+ color: Color;
+ status?: Status;
+};
+
export default Props;
diff --git a/packages/lib/src/badge/Badge.tsx b/packages/lib/src/badge/Badge.tsx
index cdcb0e8926..85856a2c53 100644
--- a/packages/lib/src/badge/Badge.tsx
+++ b/packages/lib/src/badge/Badge.tsx
@@ -2,6 +2,7 @@ import styled from "@emotion/styled";
import BadgePropsType from "./types";
import DxcIcon from "../icon/Icon";
import { Tooltip } from "../tooltip/Tooltip";
+import { forwardRef } from "react";
const contextualColorMap = {
primary: {
@@ -136,33 +137,31 @@ const Label = styled.span<{ size: BadgePropsType["size"] }>`
line-height: normal;
`;
-const DxcBadge = ({
- label,
- title,
- mode = "contextual",
- color = "neutral",
- icon,
- notificationLimit = 99,
- size = "medium",
-}: BadgePropsType): JSX.Element => (
-
-
- {mode === "contextual" && icon && (
- {typeof icon === "string" ? : icon}
- )}
- {label && (
-
- )}
-
-
+const DxcBadge = forwardRef(
+ (
+ { label, title, mode = "contextual", color = "neutral", icon, notificationLimit = 99, size = "medium" },
+ ref
+ ): JSX.Element => (
+
+
+ {mode === "contextual" && icon && (
+ {typeof icon === "string" ? : icon}
+ )}
+ {label && (
+
+ )}
+
+
+ )
);
export default DxcBadge;
diff --git a/packages/lib/src/button/Button.tsx b/packages/lib/src/button/Button.tsx
index 9c3f86bd80..962dac87d7 100644
--- a/packages/lib/src/button/Button.tsx
+++ b/packages/lib/src/button/Button.tsx
@@ -1,4 +1,5 @@
import styled from "@emotion/styled";
+import { forwardRef } from "react";
import { spaces } from "../common/variables";
import ButtonPropsType, { Mode, Semantic, Size } from "./types";
import DxcIcon from "../icon/Icon";
@@ -66,38 +67,48 @@ const IconContainer = styled.div<{
}
`;
-const DxcButton = ({
- disabled,
- icon,
- iconPosition = "before",
- label,
- margin,
- mode = "primary",
- onClick,
- semantic = "default",
- size = { height: "large", width: "fitContent" },
- tabIndex = 0,
- title,
- type = "button",
-}: ButtonPropsType): JSX.Element => (
-
-
-
+const DxcButton = forwardRef(
+ (
+ {
+ disabled,
+ icon,
+ iconPosition = "before",
+ label,
+ margin,
+ mode = "primary",
+ onClick,
+ semantic = "default",
+ size = { height: "large", width: "fitContent" },
+ tabIndex = 0,
+ title,
+ type = "button",
+ },
+ ref
+ ): JSX.Element => {
+ return (
+
+
+
+ );
+ }
);
export default DxcButton;
diff --git a/packages/lib/src/card/Card.tsx b/packages/lib/src/card/Card.tsx
index 8591392ccc..2c7fb92bfe 100644
--- a/packages/lib/src/card/Card.tsx
+++ b/packages/lib/src/card/Card.tsx
@@ -106,7 +106,7 @@ const DxcCard = forwardRef(
size = { width: "fitContent", height: "fitContent" },
tabIndex = 0,
}: CardPropsType,
- ref: Ref
+ ref: Ref
) => {
const isInteractive = !!(onClick || onSelectionChange) || selectable;
const [internalSelected, setInternalSelected] = useState(
@@ -170,7 +170,7 @@ const DxcCard = forwardRef(
onClick={(event) => {
handleEvent(event, onClick);
}}
- ref={ref}
+ ref={ref as Ref}
onKeyDown={(event) => {
handleEvent(event, onClick);
}}
@@ -201,6 +201,7 @@ const DxcCard = forwardRef(
handleEvent(event, onClick, onSelectionChange, internalSelected, setInternalSelected, selected, selectable);
}}
aria-checked={selectable ? internalSelected : undefined}
+ ref={ref as Ref}
>
{image && (
diff --git a/packages/lib/src/chip/Chip.tsx b/packages/lib/src/chip/Chip.tsx
index dc758ab540..e5dd0adce3 100644
--- a/packages/lib/src/chip/Chip.tsx
+++ b/packages/lib/src/chip/Chip.tsx
@@ -3,7 +3,7 @@ import DxcIcon from "../icon/Icon";
import ChipPropsType, { ChipAvatarType } from "./types";
import DxcActionIcon from "../action-icon/ActionIcon";
import DxcAvatar from "../avatar/Avatar";
-import { isValidElement, ReactNode, useState } from "react";
+import { forwardRef, isValidElement, ReactNode, useState } from "react";
import { SVG } from "../common/utils";
import { getChipStyles } from "./utils";
@@ -87,60 +87,55 @@ const renderPrefix = (prefix: string | SVG | ChipAvatarType | undefined, disable
return isValidElement(prefix) ? {prefix} : undefined;
};
-const DxcChip = ({
- disabled = false,
- label,
- mode = "selectable",
- onClick,
- prefix,
- selected,
- tabIndex = 0,
-}: ChipPropsType) => {
- const [innerSelected, setInnerSelected] = useState(false);
-
- if (mode === "selectable" && isAvatarType(prefix) && !label) {
- return null;
- }
+const DxcChip = forwardRef(
+ ({ disabled = false, label, mode = "selectable", onClick, prefix, selected, tabIndex = 0 }, ref) => {
+ const [innerSelected, setInnerSelected] = useState(false);
- const handleSelectableClick = () => {
- if (selected == null) {
- setInnerSelected((prev) => !prev);
+ if (mode === "selectable" && isAvatarType(prefix) && !label) {
+ return null;
}
- onClick?.();
- };
-
- const isSelected = selected ?? innerSelected;
-
- return (
-
-
- {prefix && renderPrefix(prefix, disabled)}
- {label && {label}}
-
-
- {mode === "dismissible" && (
-
- )}
-
- );
-};
+
+ const handleSelectableClick = () => {
+ if (selected == null) {
+ setInnerSelected((prev) => !prev);
+ }
+ onClick?.();
+ };
+
+ const isSelected = selected ?? innerSelected;
+
+ return (
+
+
+ {prefix && renderPrefix(prefix, disabled)}
+ {label && {label}}
+
+
+ {mode === "dismissible" && (
+
+ )}
+
+ );
+ }
+);
export default DxcChip;
|