New edit-rule page created
This commit is contained in:
@@ -19,6 +19,9 @@ export interface InlineTextButtonProps {
|
||||
disabled?: boolean;
|
||||
ariaLabel?: string;
|
||||
type?: "button" | "submit" | "reset";
|
||||
/** When set, removes the default underline (e.g. inverse surfaces). */
|
||||
underline?: boolean;
|
||||
"data-testid"?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,9 +40,16 @@ function InlineTextButtonComponent({
|
||||
disabled = false,
|
||||
ariaLabel,
|
||||
type = "button",
|
||||
underline = true,
|
||||
"data-testid": dataTestId,
|
||||
}: InlineTextButtonProps) {
|
||||
const baseClasses =
|
||||
"cursor-pointer border-none bg-transparent p-0 font-inter font-normal text-[length:inherit] leading-[inherit] text-[color:var(--color-content-default-tertiary,#b4b4b4)] underline decoration-solid underline-offset-[3px] hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--color-border-invert-primary)] disabled:cursor-not-allowed disabled:opacity-60";
|
||||
const baseClasses = [
|
||||
"cursor-pointer border-none bg-transparent p-0",
|
||||
underline
|
||||
? "font-inter font-normal text-[length:inherit] leading-[inherit] text-[color:var(--color-content-default-tertiary,#b4b4b4)] underline decoration-solid underline-offset-[3px]"
|
||||
: "text-[length:inherit] leading-[inherit] text-[color:inherit] no-underline",
|
||||
"hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--color-border-invert-primary)] disabled:cursor-not-allowed disabled:opacity-60",
|
||||
].join(" ");
|
||||
|
||||
return (
|
||||
<button
|
||||
@@ -47,6 +57,7 @@ function InlineTextButtonComponent({
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
data-testid={dataTestId}
|
||||
className={`${baseClasses} ${className}`.trim()}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -25,6 +25,9 @@ const RuleContainer = memo<RuleProps>(
|
||||
({
|
||||
title,
|
||||
description,
|
||||
onDescriptionClick,
|
||||
descriptionEmptyHint,
|
||||
descriptionEditAriaLabel,
|
||||
icon,
|
||||
backgroundColor = "bg-[var(--color-community-teal-100)]",
|
||||
className = "",
|
||||
@@ -75,6 +78,9 @@ const RuleContainer = memo<RuleProps>(
|
||||
<RuleView
|
||||
title={title}
|
||||
description={description}
|
||||
onDescriptionClick={onDescriptionClick}
|
||||
descriptionEmptyHint={descriptionEmptyHint}
|
||||
descriptionEditAriaLabel={descriptionEditAriaLabel}
|
||||
icon={icon}
|
||||
backgroundColor={backgroundColor}
|
||||
className={className}
|
||||
|
||||
@@ -25,6 +25,18 @@ export interface RuleBottomLink {
|
||||
export interface RuleProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
/**
|
||||
* When set, the description row (or {@link descriptionEmptyHint} when there
|
||||
* is no body text) is clickable — caller handles modal / navigation.
|
||||
*/
|
||||
onDescriptionClick?: () => void;
|
||||
/**
|
||||
* When {@link onDescriptionClick} is set, forwarded to the control’s
|
||||
* `aria-label` (keyboard / SR).
|
||||
*/
|
||||
descriptionEditAriaLabel?: string;
|
||||
/** Shown when {@link onDescriptionClick} is set and `description` is empty. */
|
||||
descriptionEmptyHint?: string;
|
||||
icon?: React.ReactNode;
|
||||
backgroundColor?: string;
|
||||
className?: string;
|
||||
@@ -51,6 +63,9 @@ export interface RuleProps {
|
||||
export interface RuleViewProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
onDescriptionClick?: () => void;
|
||||
descriptionEmptyHint?: string;
|
||||
descriptionEditAriaLabel?: string;
|
||||
icon?: React.ReactNode;
|
||||
backgroundColor: string;
|
||||
className: string;
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
import Image from "next/image";
|
||||
import { useTranslation } from "../../../contexts/MessagesContext";
|
||||
import MultiSelect from "../../controls/MultiSelect";
|
||||
import InlineTextButton from "../../buttons/InlineTextButton";
|
||||
import NavigationLink from "../../navigation/Link";
|
||||
import type { RuleBottomLink, RuleViewProps } from "./Rule.types";
|
||||
|
||||
export function RuleView({
|
||||
title,
|
||||
description,
|
||||
onDescriptionClick,
|
||||
descriptionEmptyHint,
|
||||
descriptionEditAriaLabel,
|
||||
icon,
|
||||
backgroundColor,
|
||||
className,
|
||||
@@ -314,6 +318,41 @@ export function RuleView({
|
||||
</div>
|
||||
) : expanded ? (
|
||||
<>
|
||||
{(description ||
|
||||
(onDescriptionClick &&
|
||||
typeof descriptionEmptyHint === "string")) && (
|
||||
<div
|
||||
className={`relative w-full shrink-0 border-b border-solid border-[var(--color-content-invert-primary)] pb-[16px] ${
|
||||
expanded && (isLarge || isMedium) ? "px-0" : "px-[12px]"
|
||||
}`}
|
||||
>
|
||||
{onDescriptionClick ? (
|
||||
<InlineTextButton
|
||||
type="button"
|
||||
underline={false}
|
||||
data-testid="rule-description-edit"
|
||||
ariaLabel={descriptionEditAriaLabel}
|
||||
className={`${descriptionClass} w-full min-w-0 cursor-pointer whitespace-pre-wrap text-left text-[var(--color-content-invert-primary)] hover:!opacity-100 ${
|
||||
!description && descriptionEmptyHint ? "opacity-70" : ""
|
||||
}`.trim()}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDescriptionClick();
|
||||
}}
|
||||
>
|
||||
{description ?? descriptionEmptyHint ?? ""}
|
||||
</InlineTextButton>
|
||||
) : (
|
||||
description && (
|
||||
<p
|
||||
className={`${descriptionClass} cursor-inherit text-[var(--color-content-invert-primary)]`}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* Categories Section - Using MultiSelect */}
|
||||
{categories && categories.length > 0 && (
|
||||
<div
|
||||
@@ -352,16 +391,6 @@ export function RuleView({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{/* Footer: Description */}
|
||||
{description && (
|
||||
<div className="border-t border-solid border-[var(--color-content-invert-primary)] pt-[16px] relative shrink-0 w-full">
|
||||
<p
|
||||
className={`${descriptionClass} cursor-inherit text-[var(--color-content-invert-primary)]`}
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
/* Collapsed State: Description */
|
||||
|
||||
Reference in New Issue
Block a user