From 61f60d00393c7f6bb23a27a463a90990e63990af Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 11 Sep 2026 00:23:29 +0200 Subject: [PATCH] swarm-ui: add Dialog/ConfirmDialog sections to the components page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mara (#4172): the components page was out of date against its own stated rule ("a new primitive gets a section here the same day it's added"). Dialog and ConfirmDialog are real standalone exported primitives (AgentsPage uses both directly) with no demo section. FormField deliberately stays excluded — its own comment already says it's not a reachable primitive, just TextField/SelectField's shared internal wrapper, so it was never meant to get one. Also gave the Table demo's "detail" column a multiselect filter, so the checkbox popover and reset-filters button — real, daily-used Table behavior — are actually shown rather than an unfiltered grid. --- .../swarm-ui/src/pages/ComponentsPage.tsx | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx b/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx index 916b125d..bb4f3fcf 100644 --- a/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx +++ b/frontend/packages/swarm-ui/src/pages/ComponentsPage.tsx @@ -20,6 +20,8 @@ import { type SelectOption, } from "../ui/select-field/SelectField.js"; import { Button, type ButtonVariant } from "../ui/button/Button.js"; +import { Dialog } from "../ui/dialog/Dialog.js"; +import { ConfirmDialog } from "../ui/confirm-dialog/ConfirmDialog.js"; import { Badge, type BadgeTone } from "@hive/shared/badge.js"; import { GearIcon } from "@hive/shared/icons.js"; import { Dropdown, type DropdownOption } from "@hive/shared/dropdown.js"; @@ -62,7 +64,17 @@ interface Row { const TABLE_COLUMNS: TableColumn[] = [ { key: "name", header: "name", render: (r) => r.name }, - { key: "detail", header: "detail", render: (r) => r.detail }, + { + key: "detail", + header: "detail", + render: (r) => r.detail, + // One filterable column, multiselect mode — the checkbox-list popover + // + reset-filters button are both real `Table` behavior an operator + // hits daily (`AgentsPage`/`HivesPage`), so the demo shows them rather + // than a plain unfilterable grid. + filterValues: (r) => [r.detail], + filterMode: "multiselect", + }, { key: "status", header: "status", @@ -181,6 +193,46 @@ function BadgeToggleSample() { ); } +// `Dialog` and `ConfirmDialog` both need `open` state to actually toggle — +// same "controlled sample needs its own wrapper" reasoning as +// `TextFieldSample` above. +function DialogSample() { + const [open, setOpen] = useState(false); + return ( + <> + + setOpen(false)} label="sample dialog"> +

+ Plain content — Dialog supplies the modal wiring (focus + trap, Escape, backdrop-click) and the close button; the caller owns + everything else, including its own heading if it wants one. +

+
+ + ); +} + +function ConfirmDialogSample() { + const [open, setOpen] = useState(false); + return ( + <> + + setOpen(false)} + onConfirm={() => setOpen(false)} + confirmLabel="confirm" + > +

+ The message is caller-owned children, same as{" "} + Dialog — only the button row and spacing are shared. +

+
+ + ); +} + export function ComponentsPage() { return ( @@ -278,6 +330,18 @@ export function ComponentsPage() { +
+ + + +
+ +
+ + + +
+
{BADGE_TONES.map((tone) => (