diff --git a/.changeset/add-field-container-info-tooltip.md b/.changeset/add-field-container-info-tooltip.md new file mode 100644 index 00000000000..6f4932c0115 --- /dev/null +++ b/.changeset/add-field-container-info-tooltip.md @@ -0,0 +1,13 @@ +--- +"@dextinity/admin": minor +--- + +Add `infoTooltip` prop to `FieldContainer` and `Field` + +Form fields sometimes need additional explanation beyond the label. `FieldContainer` (and therefore every `Field`-based component like `TextField`) now accepts an `infoTooltip` prop that renders an info icon with a tooltip next to the label, mirroring the existing `infoTooltip` prop on `FormSection`. + +**Example** + +```tsx + +``` diff --git a/.github/pr-assets/com-1646/field-container-info-tooltip-open.png b/.github/pr-assets/com-1646/field-container-info-tooltip-open.png new file mode 100644 index 00000000000..41731444ff3 Binary files /dev/null and b/.github/pr-assets/com-1646/field-container-info-tooltip-open.png differ diff --git a/.github/pr-assets/com-1646/field-container-info-tooltip.png b/.github/pr-assets/com-1646/field-container-info-tooltip.png new file mode 100644 index 00000000000..777678e1036 Binary files /dev/null and b/.github/pr-assets/com-1646/field-container-info-tooltip.png differ diff --git a/.github/pr-assets/com-1646/figma-label-reference.png b/.github/pr-assets/com-1646/figma-label-reference.png new file mode 100644 index 00000000000..0d49299497e Binary files /dev/null and b/.github/pr-assets/com-1646/figma-label-reference.png differ diff --git a/packages/admin/admin/src/form/Field.tsx b/packages/admin/admin/src/form/Field.tsx index 041283f0c44..fda399a3300 100644 --- a/packages/admin/admin/src/form/Field.tsx +++ b/packages/admin/admin/src/form/Field.tsx @@ -1,5 +1,5 @@ import type { FieldValidator } from "final-form"; -import { type ComponentType, createElement, type ReactNode, useRef } from "react"; +import { type ComponentProps, type ComponentType, createElement, type ReactNode, useRef } from "react"; import { Field as FinalFormField, type FieldMetaState, type FieldRenderProps, FormSpy, useForm } from "react-final-form"; import { FormattedMessage } from "react-intl"; @@ -26,6 +26,7 @@ export interface FieldProps["infoTooltip"]; component?: ComponentType | string; children?: (props: FieldRenderProps) => ReactNode; required?: boolean; @@ -45,6 +46,7 @@ export function Field, "children">; + iconMapping?: { + infoTooltip?: ReactElement; + }; }; export type FieldContainerClassKey = @@ -44,6 +51,7 @@ export type FieldContainerClassKey = | "fieldMarginNever" | "fieldMarginOnlyIfNotLast" | "label" + | "infoTooltip" | "inputContainer" | "hasError" | "error" @@ -205,6 +213,17 @@ const Label = createComponentSlot(FormLabel) `, ); +const InfoTooltip = createComponentSlot(Tooltip)({ + componentName: "FormFieldContainer", + slotName: "infoTooltip", +})( + ({ theme }) => css` + color: ${theme.palette.text.secondary}; + margin-left: 4px; + font-size: 16px; + `, +); + const InputContainer = createComponentSlot("div")({ componentName: "FormFieldContainer", slotName: "inputContainer", @@ -306,6 +325,22 @@ const HelperTextContent = createComponentSlot("span")({ slotName: "helperTextContent", })(); +const getInfoTooltipProps = (infoTooltip: FieldContainerProps["infoTooltip"]) => { + if (!infoTooltip) { + return null; + } + + if (isValidElement(infoTooltip) || typeof infoTooltip === "string") { + return { title: infoTooltip }; + } + + if (typeof infoTooltip === "object") { + return infoTooltip; + } + + return null; +}; + export const FieldContainer = (inProps: PropsWithChildren) => { const { variant = "vertical", @@ -320,6 +355,8 @@ export const FieldContainer = (inProps: PropsWithChildren) helperText, secondaryHelperText, helperTextIcon, + infoTooltip, + iconMapping = {}, scrollTo = false, fieldMargin = "onlyIfNotLast", slotProps, @@ -330,6 +367,9 @@ export const FieldContainer = (inProps: PropsWithChildren) const hasError = !!error; const hasWarning = !hasError && !!warning; + const { infoTooltip: infoTooltipIcon = } = iconMapping; + const infoTooltipProps = getInfoTooltipProps(infoTooltip); + const ref = useRef(null); useEffect(() => { @@ -355,6 +395,11 @@ export const FieldContainer = (inProps: PropsWithChildren) {children} diff --git a/packages/admin/admin/src/form/__stories__/FieldContainer.stories.tsx b/packages/admin/admin/src/form/__stories__/FieldContainer.stories.tsx index 4883e66df33..efd9222e033 100644 --- a/packages/admin/admin/src/form/__stories__/FieldContainer.stories.tsx +++ b/packages/admin/admin/src/form/__stories__/FieldContainer.stories.tsx @@ -35,6 +35,14 @@ export const FieldContainer = () => { +
+ + +
)} />