Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3ca10f3
feat(ui): add F0CardRow component
warcos-fact Jun 5, 2026
696ac35
chore(ui): show F0CardRow as a top-level Storybook entry
warcos-fact Jun 5, 2026
e9e8a48
fix(ui): wrap F0CardRow title and description instead of truncating
warcos-fact Jun 5, 2026
2538139
docs(ui): update F0CardRow description docs to reflect wrapping
warcos-fact Jun 5, 2026
43cfc49
refactor(ui): adapt F0CardRow actions to ButtonGroup
warcos-fact Jun 8, 2026
ef9d75c
feat(ui): make F0CardRow confirm a primary, label confirm/reject on s…
warcos-fact Jun 8, 2026
fabd05e
feat(ui): default F0CardRow reject label to "Reject"
warcos-fact Jun 8, 2026
fbd0348
fix(ui): make F0CardRow stacked footer bleed symmetrically
warcos-fact Jun 8, 2026
916c5e8
feat(ui): add F0CardRow resolved-state status slot
warcos-fact Jun 8, 2026
a401e1e
feat(ui): add F0CardRow inactive (struck-through) state
warcos-fact Jun 8, 2026
aaf1892
feat(ui): add F0CardRow icon resolved-state option
warcos-fact Jun 8, 2026
cbc6451
refactor(ui): make F0CardRow resolved status icon-only
warcos-fact Jun 8, 2026
27cb23b
refactor(ui): drop redundant title guard in F0CardRow
warcos-fact Jun 8, 2026
346c087
Merge branch 'main' into feat/f0-card-row
warcos-fact Jun 8, 2026
ff428fc
feat(sds): render F0HILActionConfirmation with F0CardRow
warcos-fact Jun 5, 2026
e7298ad
feat(sds): build F0HILActionConfirmation on F0CardRow confirm/reject …
warcos-fact Jun 5, 2026
bf6f8cb
fix(sds): require text in F0HILActionConfirmation, drop empty-title c…
warcos-fact Jun 8, 2026
043da63
Merge branch 'main' into feat/f0-hil-card-row
warcos-fact Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
import { F0Button } from "@/components/F0Button"
import Check from "@/icons/app/Check"
import { F0CardRow } from "@/components/F0Card"

import { F0HILActionConfirmationProps } from "./types"

export const F0HILActionConfirmation = ({
text,
description,
avatar,
confirmationText,
onConfirm,
cancelText,
onCancel,
stackAt = "sm",
}: F0HILActionConfirmationProps) => {
return (
<div className="flex flex-col gap-2">
{text && <p>{text}</p>}
<div className="flex gap-2">
<F0Button
type="button"
variant="default"
size="md"
icon={Check}
onClick={onConfirm}
label={confirmationText}
/>
<F0Button
type="button"
variant="outline"
size="md"
onClick={onCancel}
label={cancelText}
/>
</div>
</div>
<F0CardRow
title={text}
description={description}
avatar={avatar}
stackAt={stackAt}
confirmAction={{
label: confirmationText,
onClick: onConfirm,
}}
rejectAction={{
label: cancelText,
onClick: onCancel,
}}
/>
)
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import type { Meta, StoryObj } from "@storybook/react-vite"

import image from "@storybook-static/avatars/person04.jpg"

import { F0HILActionConfirmation } from ".."

const meta = {
title: "AI/F0HILActionConfirmation",
component: F0HILActionConfirmation,
parameters: {
layout: "centered",
layout: "padded",
docs: {
description: {
component:
"An inline human-in-the-loop approve/reject row built on `F0CardRow`'s confirm/reject variant: the prompt sits on the left as the row title (with an optional avatar and description) and icon-only ✓ (confirm) / ✗ (reject) buttons pin to the trailing edge.",
},
},
},
tags: ["autodocs"],
decorators: [
(Story) => (
<div className="w-full max-w-[480px]">
<Story />
</div>
),
],
args: {
text: "Send the follow-up email to the candidate?",
confirmationText: "Confirm",
onConfirm: () => {},
cancelText: "Cancel",
Expand All @@ -18,23 +34,38 @@ const meta = {
argTypes: {
text: {
control: "text",
description: "Optional descriptive text shown above the action buttons",
description: "The prompt shown as the row title.",
},
description: {
control: "text",
description: "Optional secondary line shown beneath the title.",
},
avatar: {
control: "object",
description: "Optional avatar rendered on the left of the row.",
},
stackAt: {
control: "select",
options: ["sm", "md", "lg", "never"],
description:
"Container width at which the ✓/✗ actions drop onto their own line.",
table: { defaultValue: { summary: "sm" } },
},
confirmationText: {
control: "text",
description: "Text displayed on the confirmation button",
description: "Accessible label and tooltip for the confirm (✓) button.",
},
onConfirm: {
action: "confirmed",
description: "Callback fired when the confirmation button is clicked",
description: "Callback fired when the confirm button is clicked",
},
cancelText: {
control: "text",
description: "Text displayed on the cancel button",
description: "Accessible label and tooltip for the reject (✗) button.",
},
onCancel: {
action: "cancelled",
description: "Callback fired when the cancel button is clicked",
description: "Callback fired when the reject button is clicked",
},
},
} satisfies Meta<typeof F0HILActionConfirmation>
Expand All @@ -44,15 +75,32 @@ type Story = StoryObj<typeof meta>

export const Default: Story = {
args: {
text: "Send the follow-up email to the candidate?",
confirmationText: "Confirm",
cancelText: "Cancel",
},
}

export const WithDescriptiveText: Story = {
export const WithDescription: Story = {
args: {
text: "Are you sure you want to proceed with this action?",
confirmationText: "Yes, proceed",
cancelText: "No, cancel",
text: "Approve 3 days off",
description: "Requested by Jane Cooper · Jun 10–12",
confirmationText: "Approve",
cancelText: "Reject",
},
}

export const WithAvatar: Story = {
args: {
avatar: {
type: "person",
firstName: "Jane",
lastName: "Cooper",
src: image,
},
text: "Jane Cooper",
description: "Requested 3 days off",
confirmationText: "Approve",
cancelText: "Reject",
},
}
37 changes: 30 additions & 7 deletions packages/react/src/sds/ai/F0HILActionConfirmation/types.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,48 @@
import type { F0CardRowProps } from "@/components/F0Card"

/**
* Props for the F0HILActionConfirmation component
* Props for the F0HILActionConfirmation component.
*
* Renders an inline approve/reject row built on `F0CardRow`'s confirm/reject
* variant: the prompt as the row title, with icon-only ✓ (confirm) and ✗
* (reject) buttons at the trailing edge.
*/
export type F0HILActionConfirmationProps = {
/**
* Optional descriptive text shown above the action buttons
* The prompt shown as the row title (e.g. the action awaiting confirmation).
* Required — a confirmation without a prompt has no meaning.
*/
text?: string
text: string
/**
* Text displayed on the confirmation button
* Optional secondary line shown beneath the title (single line, truncated).
*/
description?: F0CardRowProps["description"]
/**
* Optional avatar rendered on the left of the row. Accepts any avatar type in
* the system (person, company, team, file, icon, emoji, …).
*/
avatar?: F0CardRowProps["avatar"]
/**
* Container width at which the ✓/✗ actions drop onto their own line instead of
* staying inline. Prevents the buttons from overlapping the prompt in narrow
* containers. Set to `"never"` to keep them inline at every width.
* @default "sm"
*/
stackAt?: F0CardRowProps["stackAt"]
/**
* Accessible label and tooltip for the confirm (✓) button.
*/
confirmationText: string
/**
* Callback fired when the confirmation button is clicked
* Callback fired when the confirm button is clicked.
*/
onConfirm: () => void
/**
* Text displayed on the cancel button
* Accessible label and tooltip for the reject (✗) button.
*/
cancelText: string
/**
* Callback fired when the cancel button is clicked
* Callback fired when the reject button is clicked.
*/
onCancel: () => void
}
Loading