Components

Shared primitives from @polystaq/ui plus product-specific UI patterns from apps/app.

Button

Variants

6 intent variants. Default maps to the neutral primary token.

Sizes

8 sizes including icon-only variants.

States

Card

Anatomy

Default card
Supporting description in muted foreground.

Body content, data, or nested components.

Small variant
Reduced padding for dense layouts.
StatusActive
PlanPro
Regionus-east-1

Input & Label

States

Inline title input

Used in the properties panel to edit block and connector names. Strips all borders and rings.

Alert

Variants

Product Patterns — Canvas Toolbar

Floating toolbar

The only dark surface in the product. Position: absolute inset-x-0 bottom-5, centered. Active tool uses #0c8ce9 electric blue.

Product Patterns — Canvas Block

Block element

rounded-[5px] tight radius. Inset shadow gives depth against the white canvas. Bold 18px white text.

Start event
Review
Handoff
Done

Note element

Yellow sticky. All styling hardcoded — not theme tokens. Resizable via ReactFlow NodeResizer.

Add note

Product Patterns — Connector

FlowConnector

Custom @xyflow/react edge type. A bezier path with 28 px straight lead segments from each handle, strokeWidth 1.5, strokeLinecap round. Default: gradient color, arrow end, solid pattern.

• Lead segment: 28 px straight from handle before curve begins

• Bezier curve via getBezierPath() from @xyflow/react

• Hit area: 28 px wide (wider than the 3 px visible stroke)

• Default data: color "#5552E1", colorMode "gradient", end "arrow", start "none", pattern "solid"

Color modes

Gradient derives its start and end color from the connected block nodes — source color → target color. Solid uses a fixed hex from the same 4-color palette as canvas blocks.

Gradient

colorMode: "gradient" — source block color → target block color

Solid

colorMode: "solid" — fixed hex, same palette as canvas blocks

Stroke patterns

Three stroke patterns. Dashed uses strokeDasharray 10 8; dotted uses 2 8. All share strokeWidth 1.5 and strokeLinecap round.

Solid

Dashed

Dotted

Endpoint markers

Start and end are independently configurable. Arrow is the default end; none is the default start. Markers are SVG shapes drawn at the handle attachment point.

Arrow

Circle

Square

None

Arrow endpoint offsets the path by 13 px so the line meets the tip of the triangle rather than its center.

Label & icon

Label text sits at the bezier midpoint offset translate-y-3 below the path. Icon floats above: translate-y-[calc(100%+8px)]. Both use text-xs font-semibold italic with a bg-white/80 pill. Color matches the connector's labelColor (source color for gradient, solid color otherwise).

Approved

When the connector is steep (more vertical than horizontal) the label shifts to translate-y-3 only, and the icon and label stack together rather than splitting above/below.

Connection handles

Each block and note node renders four handles (top, right, bottom, left). Handles are opacity-0 by default and fade in on group hover. They act as both source and target.

Review

!size-3 !border-2 !border-white !bg-[#5552E1]

opacity-0 group-hover:opacity-100

• Each handle is both isConnectableStart and isConnectableEnd

Node

A mid-connector node inserted by left-clicking on an existing connector. Lets users insert a step or extract a branch midway through a flow. Rendered as a small colored dot that inherits color from the incoming edge — solid color in solid mode, source block color in gradient mode. A minimal radial glow sits behind the dot.

size-2.5 rounded-full — dot, colored from incoming edge

• Backdrop: size-5 radial-gradient(circle, color·30% 0%, transparent 70%)

• Gradient mode: uses source block color · Solid mode: uses edge color

• Selected ring: ring-2 ring-offset-1 in the edge color

• Inserted by left-clicking midway on an existing connector — splits it into two segments

Animations

Animated states communicate direction, activity level, and item throughput. Animate only connectors with live or in-progress data flow — static canvases stay still.

Flow

Dashes animate in the edge direction. Speed encodes activity level — fast (0.3s), normal (0.5s), slow (1s).

Pulse

Opacity fades 15 % → 100 % → 15 % over 2 s. Signals an idle but live connection — exists, nothing moving yet.

Particle

Dots travel along the bezier path via SVG animateMotion + mpath. Particle count and interval encode throughput — shown here: 2 on the top branch, 1 on bottom.

Counter

42 items

Badge at the bezier midpoint shows cumulative count or throughput rate. Updates live. Shares the same italic pill style as the connector label.

FlowstrokeDasharray: "6 4" + strokeDashoffset 20→0 animating indefinitely. Duration encodes speed.

Pulse — opacity 0.15 → 1 → 0.15 over 2 s ease-in-out. Path and arrowhead both animate together.

Particle<animateMotion> on a <circle> referencing the connector path via <mpath>. Stagger with begin offset.

Counter — pill badge; same italic font + bg-white/80 backdrop as the connector label. Update from canvas page item counts.

Product Patterns — Emoji Picker

EmojiPicker

Inline picker for assigning an emoji, icon, or uploaded image to a canvas block. Tabbed interface with search, categorized emoji grid, and a category quick-jump bar.

Recent

• Tabs: Emoji (default) · Icons · Upload

• Active tab underline uses --brand-violet

• Category bar at the bottom quick-jumps between 8 categories + Recent

• Props: onSelect(emoji) · onRemove() · className

Product Patterns — Canvas Grid

Column & Row Grid

An invisible alignment layer over the canvas. Columns define X-axis snap positions; rows define Y-axis snap positions — similar to tab stops in a word processor. Blocks snap to the nearest column/row intersection when dragged.

ColumnRowActionThing 1ActionThing 2Thing 3Thing 4

Columns — vertical snap rails set per-canvas, like tab stops. Blocks in the same column share an X-center.

Rows — horizontal snap rails. Blocks in the same row share a Y-center (shown as dashed lines through block midpoints).

• Branching blocks stay in their column; diverging children each occupy their own row in the next column (Thing 3 & 4 above).

• Column and row positions are canvas-level settings — they persist across the full canvas, not per-block.

Spacing model

Column width and row height are the two configurable values, measured in canvas pixels. The UI for adjusting them mirrors a word processor ruler — drag to add or remove stops.

Column spacing

0
100
200
300
Col 1
Col 2
Col 3

Row height

Rows snap to the nearest configured Y position. When a block is dragged vertically, it locks to the closest row rail.

Row height controls the minimum vertical spacing between block centers — preventing overlaps when blocks share a column.

Default column width: TBD px
Default row height: TBD px
Snap threshold: TBD px

Product Patterns — Properties Panel

Panel layout

max-w-[460px], absolute right-0 inset-y-0, border-l border-border, bg-background. Backdrop is bg-black/10.

Start event

Icon
Check
Property
Event
Color