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..f7d4f6135 --- /dev/null +++ b/packages/apollo-wind/src/components/UiPath/FlowInput.tsx @@ -0,0 +1,61 @@ +import * as React from 'react'; +import { cn } from '@/lib'; + +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..7d2f0583e 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 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/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', 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