Catalog chips now announce Select or Deselect so they are named for assistive tech. Method and value modals open blank; Generate draft inserts the catalog copy that used to be prefilled, and Customize still keeps the section headings. Co-authored-by: Cursor <cursoragent@cursor.com>
129 lines
4.0 KiB
TypeScript
129 lines
4.0 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* Shared labelled text area for create-flow modal sections.
|
|
* Figma: "Step Modal" Text Area Section (23746:49780) when `generateDraftText`
|
|
* is set — tall compose field + Generate draft control. Otherwise the
|
|
* embedded Control / Text Area pattern.
|
|
*/
|
|
|
|
import { memo, useId } from "react";
|
|
import TextArea from "../../../components/controls/TextArea";
|
|
import InputLabel from "../../../components/type/InputLabel";
|
|
|
|
export interface ModalTextAreaFieldProps {
|
|
/** Label rendered above the text area. */
|
|
label: string;
|
|
/** Show the help "?" icon next to the label. Off until tooltip behavior ships. */
|
|
helpIcon?: boolean;
|
|
/** Current text value. */
|
|
value: string;
|
|
/** Fired on every change with the new value (no event). */
|
|
onChange: (_value: string) => void;
|
|
/** Optional rows for the underlying `<textarea>` (default 4). */
|
|
rows?: number;
|
|
/** Optional placeholder. */
|
|
placeholder?: string;
|
|
/** Disable the field. */
|
|
disabled?: boolean;
|
|
/**
|
|
* Catalog/preset copy inserted by Generate draft. When a non-empty string
|
|
* is passed, the Figma compose field + ghost control are shown.
|
|
*/
|
|
generateDraftText?: string;
|
|
/** Visible label for the Generate draft control. */
|
|
generateDraftLabel?: string;
|
|
/** Hint beside Generate draft. */
|
|
generateDraftHint?: string;
|
|
className?: string;
|
|
}
|
|
|
|
function PlusGlyph() {
|
|
return (
|
|
<svg
|
|
aria-hidden
|
|
width="14"
|
|
height="14"
|
|
viewBox="0 0 14 14"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="shrink-0 text-[var(--color-content-default-brand-primary,#fefcc9)]"
|
|
>
|
|
<path
|
|
d="M7 3V11M3 7H11"
|
|
stroke="currentColor"
|
|
strokeWidth="1.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function ModalTextAreaFieldComponent({
|
|
label,
|
|
helpIcon = false,
|
|
value,
|
|
onChange,
|
|
rows = 4,
|
|
placeholder,
|
|
disabled = false,
|
|
generateDraftText,
|
|
generateDraftLabel,
|
|
generateDraftHint,
|
|
className = "",
|
|
}: ModalTextAreaFieldProps) {
|
|
const labelId = useId();
|
|
const draftSource = generateDraftText?.trim() ?? "";
|
|
const showGenerateDraft =
|
|
draftSource.length > 0 && Boolean(generateDraftLabel);
|
|
const compose = showGenerateDraft;
|
|
|
|
return (
|
|
<div
|
|
className={`flex flex-col ${compose ? "gap-[12px]" : "gap-2"} ${className}`.trim()}
|
|
>
|
|
<div id={labelId}>
|
|
<InputLabel
|
|
label={label}
|
|
helpIcon={helpIcon}
|
|
size="s"
|
|
palette="default"
|
|
/>
|
|
</div>
|
|
<TextArea
|
|
formHeader={false}
|
|
value={value}
|
|
onChange={(e) => onChange(e.target.value)}
|
|
size="large"
|
|
rows={compose ? 12 : rows}
|
|
appearance={compose ? "compose" : "embedded"}
|
|
placeholder={placeholder}
|
|
disabled={disabled}
|
|
aria-labelledby={labelId}
|
|
/>
|
|
{showGenerateDraft && !disabled ? (
|
|
<div className="flex items-center">
|
|
<button
|
|
type="button"
|
|
onClick={() => onChange(draftSource)}
|
|
className="flex shrink-0 items-center justify-center gap-[var(--measures-spacing-050,2px)] overflow-clip rounded-[var(--measures-radius-full,9999px)] px-[var(--space-250,10px)] py-[var(--measures-spacing-200,8px)] text-x-small-label text-[color:var(--color-content-default-primary,white)] hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-default-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-transparent"
|
|
>
|
|
<PlusGlyph />
|
|
{generateDraftLabel}
|
|
</button>
|
|
{generateDraftHint ? (
|
|
<p className="text-[length:var(--sizing-300,12px)] leading-normal text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
|
|
{generateDraftHint}
|
|
</p>
|
|
) : null}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
ModalTextAreaFieldComponent.displayName = "ModalTextAreaField";
|
|
|
|
export default memo(ModalTextAreaFieldComponent);
|