From 8de0aaa0122b503cd05894bc2270fe68c0a00355 Mon Sep 17 00:00:00 2001 From: robbanderson <45403355+robbanderson@users.noreply.github.com> Date: Wed, 25 Mar 2026 15:33:15 -0700 Subject: [PATCH 1/3] feat(apollo-wind): add FlowInput, FlowRadioGroup, and FlowCheckbox components New UiPath-themed variants of Input, RadioGroup, and Checkbox built on shadcn/Radix primitives using Apollo Wind semantic tokens. Includes FlowInputGroup/FlowInputAddon compound pattern for inline addons. - Add FlowInput, FlowInputGroup, FlowInputAddon with Storybook stories - Add FlowRadioGroup, FlowRadioGroupItem with Storybook stories - Add FlowCheckbox with Storybook stories - Update flow-properties-simple template to use new Flow components - Fix dark-theme scrollbar styling in tailwind.consumer.css Co-Authored-By: Claude Sonnet 4.6 --- .../UiPath/FlowCheckbox.stories.tsx | 98 +++++++++++++++++ .../src/components/UiPath/FlowCheckbox.tsx | 33 ++++++ .../components/UiPath/FlowInput.stories.tsx | 100 ++++++++++++++++++ .../src/components/UiPath/FlowInput.tsx | 65 ++++++++++++ .../UiPath/FlowRadioGroup.stories.tsx | 80 ++++++++++++++ .../src/components/UiPath/FlowRadioGroup.tsx | 38 +++++++ .../src/components/UiPath/index.ts | 7 ++ .../custom/flow-properties-simple.tsx | 27 ++--- .../src/styles/tailwind.consumer.css | 35 ++++++ 9 files changed, 464 insertions(+), 19 deletions(-) create mode 100644 packages/apollo-wind/src/components/UiPath/FlowCheckbox.stories.tsx create mode 100644 packages/apollo-wind/src/components/UiPath/FlowCheckbox.tsx create mode 100644 packages/apollo-wind/src/components/UiPath/FlowInput.stories.tsx create mode 100644 packages/apollo-wind/src/components/UiPath/FlowInput.tsx create mode 100644 packages/apollo-wind/src/components/UiPath/FlowRadioGroup.stories.tsx create mode 100644 packages/apollo-wind/src/components/UiPath/FlowRadioGroup.tsx create mode 100644 packages/apollo-wind/src/components/UiPath/index.ts diff --git a/packages/apollo-wind/src/components/UiPath/FlowCheckbox.stories.tsx b/packages/apollo-wind/src/components/UiPath/FlowCheckbox.stories.tsx new file mode 100644 index 000000000..da658268d --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/FlowCheckbox.stories.tsx @@ -0,0 +1,98 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { Label } from '@/components/ui/label'; +import { FlowCheckbox } from './FlowCheckbox'; + +// ============================================================================ +// Meta +// ============================================================================ + +const meta = { + title: 'Components/UiPath/Flow Checkbox', + component: FlowCheckbox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// ============================================================================ +// Stories +// ============================================================================ + +export const Default: Story = {}; + +export const Checked: Story = { + args: { + defaultChecked: true, + }, +}; + +export const WithLabel: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const Disabled: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const DisabledChecked: Story = { + render: () => ( +
+ + +
+ ), +}; + +export const WithDescription: Story = { + render: () => ( +
+
+ + +
+

+ Receive emails about new products, features, and more. +

+
+ ), +}; + +export const Group: Story = { + render: () => ( +
+ Notification preferences +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ ), +}; diff --git a/packages/apollo-wind/src/components/UiPath/FlowCheckbox.tsx b/packages/apollo-wind/src/components/UiPath/FlowCheckbox.tsx new file mode 100644 index 000000000..1e4863869 --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/FlowCheckbox.tsx @@ -0,0 +1,33 @@ +import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; +import { Check } from 'lucide-react'; +import * as React from 'react'; +import { cn } from '@/lib'; + +export interface FlowCheckboxProps + extends React.ComponentPropsWithoutRef {} + +const FlowCheckbox = React.forwardRef< + React.ElementRef, + FlowCheckboxProps +>(({ className, ...props }, ref) => ( + + + + + +)); +FlowCheckbox.displayName = CheckboxPrimitive.Root.displayName; + +export { FlowCheckbox }; diff --git a/packages/apollo-wind/src/components/UiPath/FlowInput.stories.tsx b/packages/apollo-wind/src/components/UiPath/FlowInput.stories.tsx new file mode 100644 index 000000000..67f2cc178 --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/FlowInput.stories.tsx @@ -0,0 +1,100 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { Check, CreditCard, Info, Loader2, Mail, Search } from 'lucide-react'; +import { FlowInput, FlowInputAddon, FlowInputGroup } from './FlowInput'; + +// Classes to reset FlowInput container styles when used inside a FlowInputGroup +const groupInputCn = 'flex-1 border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0'; + +const meta = { + title: 'Components/UiPath/Flow Input', + component: FlowInput, + parameters: { layout: 'centered' }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { placeholder: 'Enter text...' }, +}; + +export const Disabled: Story = { + args: { placeholder: 'Disabled input', disabled: true }, +}; + +export const WithValue: Story = { + args: { defaultValue: 'https://x.com/shadcn' }, +}; + +export const WithLeadingIcon: StoryObj = { + render: () => ( + + + + 12 results + + ), +}; + +export const WithLeadingText: StoryObj = { + render: () => ( + + https:// + + + + ), +}; + +export const WithTrailingStatus: StoryObj = { + render: () => ( + + https:// + + + + + + + + ), +}; + +export const WithLeadingIconOnly: StoryObj = { + render: () => ( + + + + + ), +}; + +export const WithCurrencyAddons: StoryObj = { + render: () => ( + + $ + + USD + + ), +}; + +export const WithCreditCard: StoryObj = { + render: () => ( + + + + + + ), +}; + +export const Loading: StoryObj = { + render: () => ( + + + + + ), +}; diff --git a/packages/apollo-wind/src/components/UiPath/FlowInput.tsx b/packages/apollo-wind/src/components/UiPath/FlowInput.tsx new file mode 100644 index 000000000..43afe2283 --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/FlowInput.tsx @@ -0,0 +1,65 @@ +import * as React from 'react'; +import { cn } from '@/lib'; + +const shadowSm = 'shadow-[0px_1px_2px_0px_rgba(0,0,0,0.05)]'; + +export interface FlowInputProps extends React.InputHTMLAttributes {} + +const FlowInput = React.forwardRef( + ({ className, type, ...props }, ref) => ( + + ) +); +FlowInput.displayName = 'FlowInput'; + +// Wraps FlowInput with inline addons (icons, text). Takes ownership of the +// container styles — use FlowInput with className overrides inside. +const FlowInputGroup = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +FlowInputGroup.displayName = 'FlowInputGroup'; + +// Inline slot for icons or text on either side of the input inside a group. +const FlowInputAddon = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +FlowInputAddon.displayName = 'FlowInputAddon'; + +export { FlowInput, FlowInputGroup, FlowInputAddon }; diff --git a/packages/apollo-wind/src/components/UiPath/FlowRadioGroup.stories.tsx b/packages/apollo-wind/src/components/UiPath/FlowRadioGroup.stories.tsx new file mode 100644 index 000000000..93f7e5e51 --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/FlowRadioGroup.stories.tsx @@ -0,0 +1,80 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { Label } from '@/components/ui/label'; +import { FlowRadioGroup, FlowRadioGroupItem } from './FlowRadioGroup'; + +// ============================================================================ +// Meta +// ============================================================================ + +const meta = { + title: 'Components/UiPath/Flow Radio Group', + component: FlowRadioGroup, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// ============================================================================ +// Stories +// ============================================================================ + +export const Default: Story = { + render: () => ( + +
+ + +
+
+ + +
+
+ + +
+
+ ), +}; + +export const Disabled: Story = { + render: () => ( + +
+ + +
+
+ + +
+
+ ), +}; + +export const WithDescription: Story = { + render: () => ( + +
+ +
+ + Pay with credit or debit card. +
+
+
+ +
+ + Pay with your Paypal account. +
+
+
+ ), +}; diff --git a/packages/apollo-wind/src/components/UiPath/FlowRadioGroup.tsx b/packages/apollo-wind/src/components/UiPath/FlowRadioGroup.tsx new file mode 100644 index 000000000..622a29ac7 --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/FlowRadioGroup.tsx @@ -0,0 +1,38 @@ +import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'; +import { Circle } from 'lucide-react'; +import * as React from 'react'; +import { cn } from '@/lib'; + +const FlowRadioGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +FlowRadioGroup.displayName = RadioGroupPrimitive.Root.displayName; + +const FlowRadioGroupItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)); +FlowRadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName; + +export { FlowRadioGroup, FlowRadioGroupItem }; diff --git a/packages/apollo-wind/src/components/UiPath/index.ts b/packages/apollo-wind/src/components/UiPath/index.ts new file mode 100644 index 000000000..239e4572e --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/index.ts @@ -0,0 +1,7 @@ +export { FlowInput, FlowInputGroup, FlowInputAddon } from './FlowInput'; +export type { FlowInputProps } from './FlowInput'; + +export { FlowRadioGroup, FlowRadioGroupItem } from './FlowRadioGroup'; + +export { FlowCheckbox } from './FlowCheckbox'; +export type { FlowCheckboxProps } from './FlowCheckbox'; diff --git a/packages/apollo-wind/src/components/custom/flow-properties-simple.tsx b/packages/apollo-wind/src/components/custom/flow-properties-simple.tsx index 053cde1af..fdd9cfc1e 100644 --- a/packages/apollo-wind/src/components/custom/flow-properties-simple.tsx +++ b/packages/apollo-wind/src/components/custom/flow-properties-simple.tsx @@ -17,7 +17,7 @@ import { AccordionItem, AccordionTrigger, } from '@/components/ui/accordion'; -import { Input } from '@/components/ui/input'; +import { FlowInput, FlowInputGroup } from '@/components/UiPath/FlowInput'; import { Select, SelectContent, @@ -120,12 +120,7 @@ function FieldItem({ {field.type === 'select' ? ( ) : field.type === 'url' ? ( -
- + setValue(e.target.value)} placeholder={field.placeholder} - className="h-full flex-1 rounded-none border-0 bg-transparent text-sm font-medium text-foreground-muted shadow-none placeholder:text-foreground-subtle focus-visible:ring-0" + className="flex-1 rounded-none border-0 bg-transparent px-3 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0" /> -
+ ) : ( - setValue(e.target.value)} placeholder={field.placeholder} - className={cn( - 'h-10 rounded-xl border-0 text-sm font-medium shadow-sm', - value - ? 'bg-surface-hover text-foreground' - : 'bg-surface-overlay text-foreground-muted placeholder:text-foreground-subtle' - )} /> )}
diff --git a/packages/apollo-wind/src/styles/tailwind.consumer.css b/packages/apollo-wind/src/styles/tailwind.consumer.css index 35d21154c..77aa2cb04 100644 --- a/packages/apollo-wind/src/styles/tailwind.consumer.css +++ b/packages/apollo-wind/src/styles/tailwind.consumer.css @@ -1072,4 +1072,39 @@ body.canvas, .canvas { @theme inline { --animate-collapsible-down: collapsible-down 200ms ease-out; --animate-collapsible-up: collapsible-up 200ms ease-out; +} + +/* ============================================================================ + * Theme-aware scrollbars + * + * Dark themes: future-dark + dark-hc are applied to ; + * dark + dark-hc are applied to . Both cases are covered by the + * class selectors below since * matches all descendants. + * ============================================================================ */ + +.future-dark, +.dark, +.dark-hc { + /* Firefox — inherits down the tree */ + scrollbar-width: thin; + scrollbar-color: var(--color-border) transparent; + + /* WebKit — pseudo-elements don't inherit, must target descendants */ + & *::-webkit-scrollbar { + width: 6px; + height: 6px; + } + + & *::-webkit-scrollbar-track { + background: transparent; + } + + & *::-webkit-scrollbar-thumb { + background-color: var(--color-border); + border-radius: 9999px; + } + + & *::-webkit-scrollbar-thumb:hover { + background-color: var(--color-border-hover); + } } \ No newline at end of file From 6921cac23be4e3a6f8671964c7dece59f95ed1ed Mon Sep 17 00:00:00 2001 From: robbanderson <45403355+robbanderson@users.noreply.github.com> Date: Wed, 25 Mar 2026 19:37:25 -0700 Subject: [PATCH 2/3] feat(apollo-wind): add Flow prefix to Canvas and View Toolbar story titles Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/custom/toolbar-canvas.stories.tsx | 2 +- .../apollo-wind/src/components/custom/toolbar-view.stories.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/apollo-wind/src/components/custom/toolbar-canvas.stories.tsx b/packages/apollo-wind/src/components/custom/toolbar-canvas.stories.tsx index 2c87bf6a6..2c3f0d528 100644 --- a/packages/apollo-wind/src/components/custom/toolbar-canvas.stories.tsx +++ b/packages/apollo-wind/src/components/custom/toolbar-canvas.stories.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import { FlowCanvasToolbar } from './toolbar-canvas'; const meta = { - title: 'Components/UiPath/Canvas Toolbar', + title: 'Components/UiPath/Flow Canvas Toolbar', component: FlowCanvasToolbar, parameters: { layout: 'centered', diff --git a/packages/apollo-wind/src/components/custom/toolbar-view.stories.tsx b/packages/apollo-wind/src/components/custom/toolbar-view.stories.tsx index 985175ed2..d0a6381e6 100644 --- a/packages/apollo-wind/src/components/custom/toolbar-view.stories.tsx +++ b/packages/apollo-wind/src/components/custom/toolbar-view.stories.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import { FlowViewToolbar } from './toolbar-view'; const meta = { - title: 'Components/UiPath/View Toolbar', + title: 'Components/UiPath/Flow View Toolbar', component: FlowViewToolbar, parameters: { layout: 'centered', From b2a83f6832a336207c29895b4dff2c1f11a81693 Mon Sep 17 00:00:00 2001 From: robbanderson <45403355+robbanderson@users.noreply.github.com> Date: Thu, 26 Mar 2026 07:25:21 -0700 Subject: [PATCH 3/3] feat(apollo-wind): remove drop shadow from FlowInput components Co-Authored-By: Claude Sonnet 4.6 --- packages/apollo-wind/src/components/UiPath/FlowInput.tsx | 4 ---- .../src/components/custom/flow-properties-simple.tsx | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/apollo-wind/src/components/UiPath/FlowInput.tsx b/packages/apollo-wind/src/components/UiPath/FlowInput.tsx index 43afe2283..f7d4f6135 100644 --- a/packages/apollo-wind/src/components/UiPath/FlowInput.tsx +++ b/packages/apollo-wind/src/components/UiPath/FlowInput.tsx @@ -1,8 +1,6 @@ import * as React from 'react'; import { cn } from '@/lib'; -const shadowSm = 'shadow-[0px_1px_2px_0px_rgba(0,0,0,0.05)]'; - export interface FlowInputProps extends React.InputHTMLAttributes {} const FlowInput = React.forwardRef( @@ -12,7 +10,6 @@ const FlowInput = React.forwardRef( className={cn( 'flex h-10 w-full rounded-xl bg-surface-overlay px-3 py-2', 'text-sm text-foreground placeholder:text-foreground-muted placeholder:font-normal', - shadowSm, 'transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', 'disabled:cursor-not-allowed disabled:opacity-50', @@ -34,7 +31,6 @@ const FlowInputGroup = React.forwardRef @@ -142,7 +142,7 @@ function FieldItem({ value={value} onChange={(e) => setValue(e.target.value)} placeholder={field.placeholder} - className="flex-1 rounded-none border-0 bg-transparent px-3 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0" + className="flex-1 rounded-none border-0 bg-transparent px-3 focus-visible:ring-0 focus-visible:ring-offset-0" />