@@ -17,65 +17,53 @@ import {
1717 type DropdownSeparatorProps ,
1818} from "../dropdown/index" ;
1919
20- // The Figma "Toolbar" component has a single `variant` axis describing where the
21- // toolbar is placed (Figma: Floater / Pages - Topbar / Comments bottom bar). The
22- // variants differ in two ways: their *surface* and their *density*. Only the
23- // floater is a self-contained surface — a white `surface-1` card with a subtle
24- // border, `radius/lg` corners and an `Overlay-100` shadow — so it can hover over
25- // content. Topbar and bottom-bar sit flush inside an existing bar, so they're flat
26- // (no surface, no shadow) and are therefore visually identical to each other.
20+ // A toolbar is described by two orthogonal axes — `elevation` and `density` — named
21+ // for what they actually express rather than where the toolbar is placed (placement
22+ // is the consumer's job, not a primitive's). The Figma "Toolbar" component models
23+ // these as placements (Floater / Pages - Topbar / Comments bottom bar), but those
24+ // collapse to combinations of the two axes here.
2725//
28- // Density differs too: the floater packs controls tighter (24px hit targets, a
29- // 14px chevron) while the topbar/bottom-bar are roomier (28px hit targets, a 16px
30- // chevron). Every placement shares the root `p-1.5` (6px) padding and `gap-2` (8px)
31- // item gap; clusters inside `ToolbarGroup`/`ToolbarToggleGroup` keep a tight
32- // `gap-0.5` (2px ).
26+ // `elevation`: whether the toolbar draws its own surface. `raised` is a
27+ // self-contained card — a white `surface-1` fill with a subtle border, `radius/lg`
28+ // corners and an `Overlay-100` shadow — so it can hover over content (the Figma
29+ // floater). `flat` draws no surface and sits flush inside an existing bar (the Figma
30+ // topbar / bottom-bar, which were visually identical ).
3331const toolbarVariants = cva ( "flex w-fit items-center gap-2 p-1.5 text-secondary" , {
3432 variants : {
35- variant : {
36- floater : surfaceVariants ( { elevation : "raised" , radius : "lg" } ) ,
37- topbar : "" ,
38- "bottom-bar" : "" ,
33+ elevation : {
34+ raised : surfaceVariants ( { elevation : "raised" , radius : "lg" } ) ,
35+ flat : "" ,
3936 } ,
4037 } ,
4138} ) ;
4239
43- export type ToolbarVariant = NonNullable < VariantProps < typeof toolbarVariants > [ "variant " ] > ;
40+ export type ToolbarElevation = NonNullable < VariantProps < typeof toolbarVariants > [ "elevation " ] > ;
4441
45- // The density of a toolbar defaults from its placement: the `floater ` is compact
46- // (24px hit targets ), while `topbar`/`bottom-bar` are comfortable (28px ). The
47- // resolved density is shared with the child controls (buttons, toggles, dropdown
48- // trigger) through context so they size themselves to match the root. Callers can
49- // pass `density` on the root to override the placement default — e.g. Figma's flat
50- // "fixed + compact" bar is a `topbar` forced to `compact` .
42+ // ` density`: how tightly the controls pack. `compact ` is 24px hit targets (a 14px
43+ // chevron ), `comfortable` is 28px (a 16px chevron ). It's shared with the child
44+ // controls (buttons, toggles, dropdown trigger) through context so they size
45+ // themselves to match the root. Both axes share the root `p-1.5` (6px) padding and
46+ // `gap-2` (8px) item gap; clusters inside `ToolbarGroup`/`ToolbarToggleGroup` keep a
47+ // tight `gap-0.5` (2px) .
5148type ToolbarDensity = "compact" | "comfortable" ;
5249
53- const DENSITY_BY_VARIANT : Record < ToolbarVariant , ToolbarDensity > = {
54- floater : "compact" ,
55- topbar : "comfortable" ,
56- "bottom-bar" : "comfortable" ,
57- } ;
58-
5950const ToolbarDensityContext = React . createContext < ToolbarDensity > ( "compact" ) ;
6051
6152export type ToolbarProps = Omit <
6253 React . ComponentProps < typeof BaseToolbar . Root > ,
6354 "className" | "render" | "style"
6455> & {
6556 /**
66- * Where the toolbar is placed, which controls its surface and the default density.
67- * `floater` is a self-contained card with a border + shadow that hovers over content
68- * and packs its controls tightly (24px). `topbar` and `bottom-bar` are flat, sit flush
69- * inside an existing bar, and default to the roomier 28px density.
57+ * Whether the toolbar draws its own surface. `raised` is a self-contained card
58+ * with a border + shadow that hovers over content; `flat` draws no surface and
59+ * sits flush inside an existing bar. Independent of `density`.
7060 */
71- variant : ToolbarVariant ;
61+ elevation : ToolbarElevation ;
7262 /**
73- * Hit-target density of the toolbar's controls. Defaults to the placement default
74- * (`floater` -> `compact`, `topbar`/`bottom-bar` -> `comfortable`); pass it to override
75- * the default and decouple density from `variant` — e.g. a flat `topbar` forced to
76- * `compact` for Figma's "fixed + compact" bar.
63+ * How tightly the controls pack. `compact` is 24px hit targets, `comfortable` is
64+ * 28px. Independent of `elevation`, so a flat bar can still be compact.
7765 */
78- density ? : ToolbarDensity ;
66+ density : ToolbarDensity ;
7967} ;
8068
8169/**
@@ -85,10 +73,10 @@ export type ToolbarProps = Omit<
8573 * carries `role="toolbar"`. Compose it from `ToolbarGroup`, `ToolbarButton`,
8674 * `ToolbarToggle`, `ToolbarSeparator` and `ToolbarDropdown`.
8775 */
88- export function Toolbar ( { variant , density, ...props } : ToolbarProps ) {
76+ export function Toolbar ( { elevation , density, ...props } : ToolbarProps ) {
8977 return (
90- < ToolbarDensityContext . Provider value = { density ?? DENSITY_BY_VARIANT [ variant ] } >
91- < BaseToolbar . Root className = { toolbarVariants ( { variant } ) } { ...props } />
78+ < ToolbarDensityContext . Provider value = { density } >
79+ < BaseToolbar . Root className = { toolbarVariants ( { elevation } ) } { ...props } />
9280 </ ToolbarDensityContext . Provider >
9381 ) ;
9482}
@@ -130,9 +118,6 @@ const itemVariants = cva(
130118 comfortable : "size-7 [&_svg]:size-4" ,
131119 } ,
132120 } ,
133- defaultVariants : {
134- density : "compact" ,
135- } ,
136121 } ,
137122) ;
138123
@@ -235,9 +220,6 @@ const dropdownTriggerVariants = cva(
235220 comfortable : "h-7" ,
236221 } ,
237222 } ,
238- defaultVariants : {
239- density : "compact" ,
240- } ,
241223 } ,
242224) ;
243225
@@ -248,9 +230,6 @@ const dropdownChevronVariants = cva("shrink-0 text-icon-secondary", {
248230 comfortable : "size-4" ,
249231 } ,
250232 } ,
251- defaultVariants : {
252- density : "compact" ,
253- } ,
254233} ) ;
255234
256235/**
0 commit comments