From 9d10dae43d3ed12e4c0ffea7ebe78b8f52eb61fa Mon Sep 17 00:00:00 2001 From: kumaradityaraj Date: Wed, 5 Aug 2026 13:48:31 +0530 Subject: [PATCH 1/9] adding componnets Signed-off-by: kumaradityaraj --- .../open-workflow-diagram-editor/package.json | 1 + .../src/components/ui/combobox.tsx | 285 ++++++++++++++++++ .../src/components/ui/input-group.tsx | 161 ++++++++++ .../src/components/ui/switch.tsx | 33 ++ .../src/components/ui/textarea.tsx | 18 ++ pnpm-lock.yaml | 93 ++++++ pnpm-workspace.yaml | 1 + 7 files changed, 592 insertions(+) create mode 100644 packages/open-workflow-diagram-editor/src/components/ui/combobox.tsx create mode 100644 packages/open-workflow-diagram-editor/src/components/ui/input-group.tsx create mode 100644 packages/open-workflow-diagram-editor/src/components/ui/switch.tsx create mode 100644 packages/open-workflow-diagram-editor/src/components/ui/textarea.tsx diff --git a/packages/open-workflow-diagram-editor/package.json b/packages/open-workflow-diagram-editor/package.json index 3540322e..d517b3d2 100644 --- a/packages/open-workflow-diagram-editor/package.json +++ b/packages/open-workflow-diagram-editor/package.json @@ -41,6 +41,7 @@ "test-e2e:ui": "playwright test --ui" }, "dependencies": { + "@base-ui/react": "catalog:", "@openworkflowspec/i18n": "workspace:*", "@openworkflowspec/sdk": "catalog:", "@xyflow/react": "catalog:", diff --git a/packages/open-workflow-diagram-editor/src/components/ui/combobox.tsx b/packages/open-workflow-diagram-editor/src/components/ui/combobox.tsx new file mode 100644 index 00000000..b0b25fa4 --- /dev/null +++ b/packages/open-workflow-diagram-editor/src/components/ui/combobox.tsx @@ -0,0 +1,285 @@ +"use client"; + +import * as React from "react"; +import { Combobox as ComboboxPrimitive } from "@base-ui/react"; +import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { + InputGroup, + InputGroupAddon, + InputGroupButton, + InputGroupInput, +} from "@/components/ui/input-group"; + +const Combobox = ComboboxPrimitive.Root; + +function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) { + return ; +} + +function ComboboxTrigger({ className, children, ...props }: ComboboxPrimitive.Trigger.Props) { + return ( + + {children} + + + ); +} + +function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) { + return ( + } + className={cn(className)} + {...props} + > + + + ); +} + +function ComboboxInput({ + className, + children, + disabled = false, + showTrigger = true, + showClear = false, + ...props +}: ComboboxPrimitive.Input.Props & { + showTrigger?: boolean; + showClear?: boolean; +}) { + return ( + + } {...props} /> + + {showTrigger && ( + + + + )} + {showClear && } + + {children} + + ); +} + +function ComboboxContent({ + className, + side = "bottom", + sideOffset = 6, + align = "start", + alignOffset = 0, + anchor, + ...props +}: ComboboxPrimitive.Popup.Props & + Pick< + ComboboxPrimitive.Positioner.Props, + "side" | "align" | "sideOffset" | "alignOffset" | "anchor" + >) { + return ( + + + + + + ); +} + +function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) { + return ( + + ); +} + +function ComboboxItem({ className, children, ...props }: ComboboxPrimitive.Item.Props) { + return ( + + {children} + + } + > + + + + ); +} + +function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) { + return ( + + ); +} + +function ComboboxLabel({ className, ...props }: ComboboxPrimitive.GroupLabel.Props) { + return ( + + ); +} + +function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) { + return ; +} + +function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { + return ( + + ); +} + +function ComboboxSeparator({ className, ...props }: ComboboxPrimitive.Separator.Props) { + return ( + + ); +} + +function ComboboxChips({ + className, + ...props +}: React.ComponentPropsWithRef & ComboboxPrimitive.Chips.Props) { + return ( + + ); +} + +function ComboboxChip({ + className, + children, + showRemove = true, + ...props +}: ComboboxPrimitive.Chip.Props & { + showRemove?: boolean; +}) { + return ( + + {children} + {showRemove && ( + } + className="dec:-ml-1 dec:opacity-50 dec:hover:opacity-100" + data-slot="combobox-chip-remove" + > + + + )} + + ); +} + +function ComboboxChipsInput({ className, children, ...props }: ComboboxPrimitive.Input.Props) { + return ( + + ); +} + +function useComboboxAnchor() { + return React.useRef(null); +} + +export { + Combobox, + ComboboxInput, + ComboboxContent, + ComboboxList, + ComboboxItem, + ComboboxGroup, + ComboboxLabel, + ComboboxCollection, + ComboboxEmpty, + ComboboxSeparator, + ComboboxChips, + ComboboxChip, + ComboboxChipsInput, + ComboboxTrigger, + ComboboxValue, + useComboboxAnchor, +}; diff --git a/packages/open-workflow-diagram-editor/src/components/ui/input-group.tsx b/packages/open-workflow-diagram-editor/src/components/ui/input-group.tsx new file mode 100644 index 00000000..b7922f52 --- /dev/null +++ b/packages/open-workflow-diagram-editor/src/components/ui/input-group.tsx @@ -0,0 +1,161 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; + +function InputGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( +
textarea]:h-auto", + + // Variants based on alignment. + "dec:has-[>[data-align=inline-start]]:[&>input]:pl-2", + "dec:has-[>[data-align=inline-end]]:[&>input]:pr-2", + "dec:has-[>[data-align=block-start]]:h-auto dec:has-[>[data-align=block-start]]:flex-col dec:has-[>[data-align=block-start]]:[&>input]:pb-3", + "dec:has-[>[data-align=block-end]]:h-auto dec:has-[>[data-align=block-end]]:flex-col dec:has-[>[data-align=block-end]]:[&>input]:pt-3", + + // Focus state. + "dec:has-[[data-slot=input-group-control]:focus-visible]:border-ring dec:has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] dec:has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50", + + // Error state. + "dec:has-[[data-slot][aria-invalid=true]]:border-destructive dec:has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dec:dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40", + + className, + )} + {...props} + /> + ); +} + +const inputGroupAddonVariants = cva( + "dec:flex dec:h-auto dec:cursor-text dec:items-center dec:justify-center dec:gap-2 dec:py-1.5 dec:text-sm dec:font-medium dec:text-muted-foreground dec:select-none dec:group-data-[disabled=true]/input-group:opacity-50 dec:[&>kbd]:rounded-[calc(var(--radius)-5px)] dec:[&>svg:not([class*=size-])]:size-4", + { + variants: { + align: { + "inline-start": + "dec:order-first dec:pl-3 dec:has-[>button]:ml-[-0.45rem] dec:has-[>kbd]:ml-[-0.35rem]", + "inline-end": + "dec:order-last dec:pr-3 dec:has-[>button]:mr-[-0.45rem] dec:has-[>kbd]:mr-[-0.35rem]", + "block-start": + "dec:order-first dec:w-full dec:justify-start dec:px-3 dec:pt-3 dec:group-has-[>input]/input-group:pt-2.5 dec:[.border-b]:pb-3", + "block-end": + "dec:order-last dec:w-full dec:justify-start dec:px-3 dec:pb-3 dec:group-has-[>input]/input-group:pb-2.5 dec:[.border-t]:pt-3", + }, + }, + defaultVariants: { + align: "inline-start", + }, + }, +); + +function InputGroupAddon({ + className, + align = "inline-start", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
{ + if ((e.target as HTMLElement).closest("button")) { + return; + } + e.currentTarget.parentElement?.querySelector("input")?.focus(); + }} + {...props} + /> + ); +} + +const inputGroupButtonVariants = cva( + "dec:flex dec:items-center dec:gap-2 dec:text-sm dec:shadow-none", + { + variants: { + size: { + xs: "dec:h-6 dec:gap-1 dec:rounded-[calc(var(--radius)-5px)] dec:px-2 dec:has-[>svg]:px-2 dec:[&>svg:not([class*=size-])]:size-3.5", + sm: "dec:h-8 dec:gap-1.5 dec:rounded-md dec:px-2.5 dec:has-[>svg]:px-2.5", + "icon-xs": "dec:size-6 dec:rounded-[calc(var(--radius)-5px)] dec:p-0 dec:has-[>svg]:p-0", + "icon-sm": "dec:size-8 dec:p-0 dec:has-[>svg]:p-0", + }, + }, + defaultVariants: { + size: "xs", + }, + }, +); + +function InputGroupButton({ + className, + type = "button", + variant = "ghost", + size = "xs", + ...props +}: Omit, "size"> & + VariantProps) { + return ( +