From 7a55c91a888b032974a15e8e53a42abf3650bc38 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Fri, 13 Nov 2026 16:00:20 +0100 Subject: [PATCH 1/2] feat(ui): finish the move to Geist: numbers, 13px chrome, sentence-case labels The Refine look swapped the face, but the type decisions around it were still the ones made for a monospace. - Numbers stay in Geist. The base rule that sent every `tabular-nums` element to Geist Mono is gone, so a sentence with a number in it no longer changes face halfway. Tabular figures still line columns up. Log lines, ids and code keep mono because they ask for it. - The stat figure defaults to the display face. - Chrome is 13px: kit controls step down from 14px, sidebar rows and breadcrumbs step up from 12px. - Group, column and stat labels are sentence case. The eyebrow drops its uppercase overline (the mono variant keeps it), and the sidebar group label, the key-value label and the command palette group label follow. - The top bar is 48px, down from 64px. --- .../src/page/investigations/detail/view-verdict.ts | 1 - apps/web/src/page/kit/section-heading.ts | 4 ++-- apps/web/src/page/kit/stat-rail.ts | 3 --- apps/web/src/page/overview/view-usage.ts | 2 -- apps/web/src/page/settings/billing/view-cycle.ts | 2 +- apps/web/src/shell/palette/view.ts | 4 ++-- apps/web/src/shell/view-topbar.ts | 2 +- docs/design-rules.md | 9 +++++++-- packages/ui/src/styles/tokens.css | 12 ++---------- packages/views/src/charts/paths-chart.ts | 2 +- packages/views/src/ui/INDEX.md | 2 +- packages/views/src/ui/autocomplete.styles.ts | 4 ++-- packages/views/src/ui/breadcrumb.styles.ts | 2 +- packages/views/src/ui/button.styles.ts | 2 +- packages/views/src/ui/combobox.styles.ts | 8 ++++---- packages/views/src/ui/eyebrow.styles.ts | 13 +++++++------ packages/views/src/ui/eyebrow.ts | 2 +- packages/views/src/ui/field.styles.ts | 2 +- packages/views/src/ui/field.ts | 4 ++-- packages/views/src/ui/input-group.styles.ts | 2 +- packages/views/src/ui/input.styles.ts | 2 +- packages/views/src/ui/key-value.styles.ts | 2 +- packages/views/src/ui/label.styles.ts | 2 +- packages/views/src/ui/select.styles.ts | 6 +++--- packages/views/src/ui/sidebar.styles.ts | 12 ++++++------ packages/views/src/ui/stat-figure.ts | 4 ++-- packages/views/src/ui/tabs.styles.ts | 2 +- packages/views/src/ui/textarea.styles.ts | 2 +- packages/views/src/ui/toggle.styles.ts | 2 +- 29 files changed, 54 insertions(+), 62 deletions(-) diff --git a/apps/web/src/page/investigations/detail/view-verdict.ts b/apps/web/src/page/investigations/detail/view-verdict.ts index 7e2a1b26c8..e39d26a7dc 100644 --- a/apps/web/src/page/investigations/detail/view-verdict.ts +++ b/apps/web/src/page/investigations/detail/view-verdict.ts @@ -87,7 +87,6 @@ const bigStat = (h: HtmlBuilder, elapsed: { value: string; unit: string } : statFigure(h, { value: elapsed.value, unit: elapsed.unit, - mono: false, valueClassName: "text-foreground", }) diff --git a/apps/web/src/page/kit/section-heading.ts b/apps/web/src/page/kit/section-heading.ts index 8118eac2d3..90b88be7ef 100644 --- a/apps/web/src/page/kit/section-heading.ts +++ b/apps/web/src/page/kit/section-heading.ts @@ -2,11 +2,11 @@ import { cn } from "@maple/ui/lib/utils" import type { Html, HtmlBuilder } from "foldkit/html" import { eyebrow } from "@maple/views/ui/eyebrow" -// A section's heading: a title row with hint, count and actions, or the uppercase eyebrow overline. +// A section's heading: a title row with hint, count and actions, or the eyebrow label. export type SectionHeadingOptions = Readonly<{ title: string - /** The uppercase overline above a form group or rail section, `mb-3` below. */ + /** The eyebrow label above a form group or rail section, `mb-3` below. */ variant?: "title" | "eyebrow" hint?: string count?: Html | string diff --git a/apps/web/src/page/kit/stat-rail.ts b/apps/web/src/page/kit/stat-rail.ts index 9080205086..cf076bf660 100644 --- a/apps/web/src/page/kit/stat-rail.ts +++ b/apps/web/src/page/kit/stat-rail.ts @@ -97,8 +97,6 @@ export type StatRailItemOptions = Readonly<{ ariaLabel?: string size?: "md" | "sm" hint?: Html | string - /** Title the tile like a chart card (the uppercase label eyebrow), for rails above chart grids. */ - isCardTitle?: boolean }> export const statRailItem = (h: HtmlBuilder, options: StatRailItemOptions): Html => { @@ -121,7 +119,6 @@ export const statRailItem = (h: HtmlBuilder, options: StatRailItemOptions< h.Class( cn( "truncate text-2xs font-medium", - options.isCardTitle === true && "uppercase tracking-caption", isSelected ? "text-primary" : "text-muted-foreground", ), ), diff --git a/apps/web/src/page/overview/view-usage.ts b/apps/web/src/page/overview/view-usage.ts index df1d8775e1..fc21bb4aab 100644 --- a/apps/web/src/page/overview/view-usage.ts +++ b/apps/web/src/page/overview/view-usage.ts @@ -40,7 +40,6 @@ export const usageCards = ( ? h.span([h.Class("sr-only")], ["Couldn't load"]) : h.span([h.Class("font-prose")], ["Couldn't load"]), compact: true, - isCardTitle: true, className: OVERVIEW_TILE_CLASS, }), ), @@ -54,7 +53,6 @@ export const usageCards = ( eyebrow: card.title, value: card.format(totals[card.key]), compact: true, - isCardTitle: true, className: OVERVIEW_TILE_CLASS, delta: previous === null diff --git a/apps/web/src/page/settings/billing/view-cycle.ts b/apps/web/src/page/settings/billing/view-cycle.ts index b41fd3408d..36e21162ff 100644 --- a/apps/web/src/page/settings/billing/view-cycle.ts +++ b/apps/web/src/page/settings/billing/view-cycle.ts @@ -65,7 +65,7 @@ const figure = ( }>, ): Html => vstack(h, { gap: "2", shrink: true, className: "p-4" }, [ - // The uppercase overline every KPI tile uses (Overview's usage cards, the Stat widget). + // The label every KPI tile uses (Overview's usage cards, the Stat widget). eyebrow(h, {}, [options.label]), statFigure(h, { size: "lg", value: options.value, valueClassName: options.valueClassName }), h.span([h.Class("font-prose text-2xs text-muted-foreground")], options.note), diff --git a/apps/web/src/shell/palette/view.ts b/apps/web/src/shell/palette/view.ts index df9b5316a9..b871058df6 100644 --- a/apps/web/src/shell/palette/view.ts +++ b/apps/web/src/shell/palette/view.ts @@ -25,11 +25,11 @@ import { hstack, hstackClass } from "@maple/views/ui/stack" import { Array as Arr } from "effect" /** - * Layout-free wrapper: group labels take the sidebar's uppercase tracked style, and a short scroll + * Layout-free wrapper: group labels take the sidebar's group label style, and a short scroll * fade keeps the last visible row from reading as disabled. */ const PALETTE_LIST_CLASS = - "contents [&_[data-slot=command-group-label]]:text-2xs [&_[data-slot=command-group-label]]:font-semibold [&_[data-slot=command-group-label]]:uppercase [&_[data-slot=command-group-label]]:tracking-overline [&_[data-slot=scroll-area-viewport]]:[--fade-size:0.5rem]" + "contents [&_[data-slot=command-group-label]]:text-xs [&_[data-slot=command-group-label]]:font-medium [&_[data-slot=scroll-area-viewport]]:[--fade-size:0.5rem]" // The command palette's popup: the input, the grouped entries (or "No results"), the footer hints. diff --git a/apps/web/src/shell/view-topbar.ts b/apps/web/src/shell/view-topbar.ts index 01066cc9bc..3eeff37758 100644 --- a/apps/web/src/shell/view-topbar.ts +++ b/apps/web/src/shell/view-topbar.ts @@ -80,7 +80,7 @@ export const topbar = ( gap: "2", align: "center", as: "header", - className: "h-16 shrink-0 border-b px-4", + className: "h-12 shrink-0 border-b px-4", attributes: [h.DataAttribute("slot", "app-topbar")], }, [ diff --git a/docs/design-rules.md b/docs/design-rules.md index db942b791e..5d9c3e02c3 100644 --- a/docs/design-rules.md +++ b/docs/design-rules.md @@ -42,8 +42,13 @@ only shrink (`bun run ui:patterns:check` in CI). The workflow is in `apps/web/CL ## Type and spacing - Weights are `font-normal`, `font-medium` and `font-semibold` (`maple/font-weight-scale`). -- Tracking is a token. An uppercase label is the `eyebrow` kit, or `tracking-caption` (0.08em) / - `tracking-overline` (0.12em); display type may take `tracking-tight`; nothing else is spaced. +- The interface reads in Geist. Chrome (nav rows, buttons, inputs, selects, tabs, breadcrumbs) is + 13px (`text-ui`). Numbers stay in Geist and line up with `tabular-nums` (`numeric` on + `typography`); `font-mono` (`mono`) is for machine text: log lines, ids, code, queries. +- A group, column or stat label is the `eyebrow` kit: sentence case, no tracking. Uppercase is for a + machine tag (a badge `tag`, a log level, the `mono` eyebrow) and takes `tracking-caption` (0.08em) + or `tracking-overline` (0.12em). +- Tracking is a token. Display type may take `tracking-tight`; nothing else is spaced. Tailwind's `tracking-wide`, `-wider`, `-widest` are banned (`maple/tracking-tokens`). - Spacing moves in half steps (2px). A quarter step (`gap-0.75`, `pl-3.75`) is an odd pixel; when a pixel offset is the point (centring a dot on a text line, meeting a rail), write it from a scale diff --git a/packages/ui/src/styles/tokens.css b/packages/ui/src/styles/tokens.css index 978cf3880d..77c8ccc9a4 100644 --- a/packages/ui/src/styles/tokens.css +++ b/packages/ui/src/styles/tokens.css @@ -532,8 +532,8 @@ --text-figure: 1.625rem; /* Inline code inside prose: a touch under the surrounding text, whatever its size. */ --text-code: 0.9em; - /* Tracking: `overline` for eyebrows and column labels, `caption` for the larger stat-tile - caption, `figure` pulls a large stat figure in a touch. */ + /* Tracking: `overline` and `caption` space the uppercase tags that remain (badges, log + levels, the mono eyebrow); `figure` pulls a large stat figure in a touch. */ --tracking-overline: 0.12em; --tracking-caption: 0.08em; --tracking-figure: -0.01em; @@ -818,14 +818,6 @@ html { @apply font-sans; } - /* Chrome reads in Geist; numbers that line up in a column stay in the mono face, except the - large stat figure. A `font-sans` utility on the element still wins. */ - .tabular-nums { - @apply font-mono; - } - .text-figure { - @apply font-sans; - } } /* xyflow Controls styling, shared by the flow views in @maple/views (service map, diff --git a/packages/views/src/charts/paths-chart.ts b/packages/views/src/charts/paths-chart.ts index 093da81f90..0566aa9216 100644 --- a/packages/views/src/charts/paths-chart.ts +++ b/packages/views/src/charts/paths-chart.ts @@ -76,7 +76,7 @@ const columnHeaders = (h: H, graph: PathsLayout, reverse: boolean): ReadonlyArra y: 10, "text-anchor": atRightEdge ? "end" : "start", }), - h.Class("fill-muted-foreground text-3xs font-medium uppercase tracking-caption"), + h.Class("fill-muted-foreground text-2xs font-medium"), ], [label], ) diff --git a/packages/views/src/ui/INDEX.md b/packages/views/src/ui/INDEX.md index 642cedb83e..0131be763f 100644 --- a/packages/views/src/ui/INDEX.md +++ b/packages/views/src/ui/INDEX.md @@ -286,7 +286,7 @@ existing copies onto it (see `apps/web/CLAUDE.md`). - `apps/web/src/page/kit/route-window.ts` `isWindowChange`, `snapModeOf`, `routeWindowStep`: A page's time window across `routeChanged`: re-resolved only when its own fields moved, and only Reload revalidates unchanged keys. - `apps/web/src/page/kit/save-bar.ts` `saveBar`: Pinned while a settings tab has unsaved edits. - `apps/web/src/page/kit/sdk-snippets.ts` `sdkSnippets`, `register`, `fillSnippet`: The snippet's text with the endpoint and key filled in. -- `apps/web/src/page/kit/section-heading.ts` `sectionHeading`: A section's heading: a title row with hint, count and actions, or the uppercase eyebrow overline. +- `apps/web/src/page/kit/section-heading.ts` `sectionHeading`: A section's heading: a title row with hint, count and actions, or the eyebrow label. - `apps/web/src/page/kit/sentence-card.ts` `sentenceCardHeadingId`, `sentenceCardSummaryId`, `sentenceCard`, `sentenceChain`, `sentenceRow`, `sentencePhrase`, `sentenceClause`, `sentenceSection`: Sentence cards: a form that reads top to bottom as one sentence ("When ... - `apps/web/src/page/kit/series-legend.ts` `seriesLegend` - `apps/web/src/page/kit/service-health-rollup.ts` `alertIncidentCauseLabel`, `anomalyDirection`, `deriveServiceHealthFromCauses`, `primaryServiceHealthCause`, `healthRank`, `baselineKey`, `buildBaselineMap`: Health rollup for a single service. diff --git a/packages/views/src/ui/autocomplete.styles.ts b/packages/views/src/ui/autocomplete.styles.ts index 1398fb0b7f..d8dfeade65 100644 --- a/packages/views/src/ui/autocomplete.styles.ts +++ b/packages/views/src/ui/autocomplete.styles.ts @@ -24,12 +24,12 @@ export const autocompletePopupStyles = "flex max-h-[min(var(--available-height),23rem)] flex-1 flex-col text-foreground" export const autocompleteItemStyles = - "flex min-h-8 cursor-default select-none items-center rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm" + "flex min-h-8 cursor-default select-none items-center rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui/5" export const autocompleteGroupStyles = "[[role=group]+&]:mt-1.5" export const autocompleteGroupLabelStyles = "px-2 py-1.5 font-medium text-muted-foreground text-xs" -export const autocompleteEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-sm" +export const autocompleteEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-ui/5" export const autocompleteListStyles = "not-empty:scroll-py-1 not-empty:p-1 in-data-has-overflow-y:pe-3" diff --git a/packages/views/src/ui/breadcrumb.styles.ts b/packages/views/src/ui/breadcrumb.styles.ts index c8959b5b1e..c0db34bfa3 100644 --- a/packages/views/src/ui/breadcrumb.styles.ts +++ b/packages/views/src/ui/breadcrumb.styles.ts @@ -1,5 +1,5 @@ export const breadcrumbListStyles = - "wrap-break-word flex flex-wrap items-center gap-1.5 text-muted-foreground text-sm sm:gap-2.5" + "wrap-break-word flex flex-wrap items-center gap-1.5 text-muted-foreground text-ui sm:gap-2.5" export const breadcrumbItemStyles = "inline-flex items-center gap-1.5" diff --git a/packages/views/src/ui/button.styles.ts b/packages/views/src/ui/button.styles.ts index 296ba2dbf2..f33655b3a1 100644 --- a/packages/views/src/ui/button.styles.ts +++ b/packages/views/src/ui/button.styles.ts @@ -1,7 +1,7 @@ import { cva } from "class-variance-authority" export const buttonVariants = cva( - "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-[scale] duration-150 ease-out active:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-loading:select-none data-loading:text-transparent sm:text-sm [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", + "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-[scale] duration-150 ease-out active:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-loading:select-none data-loading:text-transparent sm:text-ui/5 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", { defaultVariants: { size: "default", diff --git a/packages/views/src/ui/combobox.styles.ts b/packages/views/src/ui/combobox.styles.ts index 9809e76426..7c63149782 100644 --- a/packages/views/src/ui/combobox.styles.ts +++ b/packages/views/src/ui/combobox.styles.ts @@ -1,5 +1,5 @@ export const comboboxChipsInputStyles = - "min-w-12 flex-1 text-base outline-none sm:text-sm [[data-slot=combobox-chip]+&]:ps-0.5" + "min-w-12 flex-1 text-base outline-none sm:text-ui/5 [[data-slot=combobox-chip]+&]:ps-0.5" export const comboboxChipsInputSmStyles = "ps-1.5" @@ -38,19 +38,19 @@ export const comboboxPopupStyles = "flex max-h-[min(var(--available-height),23rem)] flex-1 flex-col text-foreground" export const comboboxItemStyles = - "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" + "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" export const comboboxItemIndicatorStyles = "col-start-1" export const comboboxItemTextStyles = "col-start-2" -export const comboboxEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-sm" +export const comboboxEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-ui/5" export const comboboxListStyles = "not-empty:scroll-py-1 not-empty:px-1 not-empty:py-1 in-data-has-overflow-y:pe-3" export const comboboxChipsStyles = - "relative inline-flex min-h-9 w-full flex-wrap gap-1 rounded-lg border border-input bg-background not-dark:bg-clip-padding p-[calc(--spacing(1)-1px)] text-base shadow-raised outline-none ring-ring/24 transition-shadow *:min-h-7 before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-control focus-within:border-ring focus-within:ring-[3px] has-disabled:pointer-events-none has-data-[size=lg]:min-h-10 has-data-[size=sm]:min-h-8 has-aria-invalid:border-destructive-a4 has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-within,[aria-invalid]]:shadow-none focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive-a2 has-data-[size=lg]:*:min-h-8 has-data-[size=sm]:*:min-h-6 sm:min-h-8 sm:text-sm sm:has-data-[size=lg]:min-h-9 sm:has-data-[size=sm]:min-h-7 sm:*:min-h-6 sm:has-data-[size=lg]:*:min-h-7 sm:has-data-[size=sm]:*:min-h-5 dark:not-has-disabled:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" + "relative inline-flex min-h-9 w-full flex-wrap gap-1 rounded-lg border border-input bg-background not-dark:bg-clip-padding p-[calc(--spacing(1)-1px)] text-base shadow-raised outline-none ring-ring/24 transition-shadow *:min-h-7 before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-control focus-within:border-ring focus-within:ring-[3px] has-disabled:pointer-events-none has-data-[size=lg]:min-h-10 has-data-[size=sm]:min-h-8 has-aria-invalid:border-destructive-a4 has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-within,[aria-invalid]]:shadow-none focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive-a2 has-data-[size=lg]:*:min-h-8 has-data-[size=sm]:*:min-h-6 sm:min-h-8 sm:text-ui/5 sm:has-data-[size=lg]:min-h-9 sm:has-data-[size=sm]:min-h-7 sm:*:min-h-6 sm:has-data-[size=lg]:*:min-h-7 sm:has-data-[size=sm]:*:min-h-5 dark:not-has-disabled:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" // A translucent foreground tint rather than `bg-accent`: in this theme // --accent, --muted and --secondary are all the same value as the diff --git a/packages/views/src/ui/eyebrow.styles.ts b/packages/views/src/ui/eyebrow.styles.ts index 1ff24346b3..bc1f8b9bcc 100644 --- a/packages/views/src/ui/eyebrow.styles.ts +++ b/packages/views/src/ui/eyebrow.styles.ts @@ -1,14 +1,15 @@ import { cva } from "class-variance-authority" -// The small uppercase overline that titles a group of fields, a stat, or a table column. -// `overline` is the canonical section label; `label` is the slightly larger stat-tile caption. -export const eyebrowVariants = cva("font-medium uppercase text-muted-foreground", { +// The small muted label that titles a group of fields, a stat, or a table column, in sentence case. +// `overline` is the canonical section label, `label` the slightly larger stat-tile caption and +// `mono` an uppercase machine tag. +export const eyebrowVariants = cva("font-medium text-muted-foreground", { defaultVariants: { variant: "overline" }, variants: { variant: { - overline: "text-3xs tracking-overline", - label: "text-2xs tracking-caption", - mono: "font-mono text-3xs tracking-overline text-foreground-subtle", + overline: "text-2xs", + label: "text-xs", + mono: "font-mono text-3xs uppercase tracking-overline text-foreground-subtle", }, }, }) diff --git a/packages/views/src/ui/eyebrow.ts b/packages/views/src/ui/eyebrow.ts index f608ef909d..b311353f3c 100644 --- a/packages/views/src/ui/eyebrow.ts +++ b/packages/views/src/ui/eyebrow.ts @@ -30,7 +30,7 @@ export const withHint = ( : [match[1] ?? "", h.span([h.Class("normal-case tracking-normal")], [match[2] ?? ""])] } -/** `Eyebrow`: the small uppercase overline that titles a group. */ +/** `Eyebrow`: the small muted label that titles a group. */ export const eyebrow = ( h: HtmlBuilder, options: EyebrowOptions, diff --git a/packages/views/src/ui/field.styles.ts b/packages/views/src/ui/field.styles.ts index 66e869f3b6..587adfdd7b 100644 --- a/packages/views/src/ui/field.styles.ts +++ b/packages/views/src/ui/field.styles.ts @@ -1,7 +1,7 @@ export const fieldStyles = "flex flex-col items-start gap-2" export const fieldLabelStyles = - "inline-flex items-center gap-2 font-medium text-base/4.5 text-foreground data-disabled:opacity-64 sm:text-sm/4" + "inline-flex items-center gap-2 font-medium text-base/4.5 text-foreground data-disabled:opacity-64 sm:text-ui/4" export const fieldDescriptionStyles = "text-muted-foreground text-xs" diff --git a/packages/views/src/ui/field.ts b/packages/views/src/ui/field.ts index b5d10cee91..a455267fcd 100644 --- a/packages/views/src/ui/field.ts +++ b/packages/views/src/ui/field.ts @@ -89,8 +89,8 @@ export const field = ( /** Base UI `useId`s of a field's parts; `description` only when a `FieldDescription` renders. */ export type FieldIds = Readonly<{ control: string; label: string; error: string; description?: string }> -// The small uppercase eyebrow look on a field label (a dense editor rail). -const EYEBROW_LABEL = cn(eyebrowVariants({ variant: "label" }), "sm:text-2xs sm:leading-normal") +// The eyebrow look on a field label (a dense editor rail). +const EYEBROW_LABEL = cn(eyebrowVariants({ variant: "label" }), "sm:leading-normal") /** Base UI `Field.Label`, wired to the control by id. */ export const fieldLabel = ( diff --git a/packages/views/src/ui/input-group.styles.ts b/packages/views/src/ui/input-group.styles.ts index e1f2be0b35..d356d6cd22 100644 --- a/packages/views/src/ui/input-group.styles.ts +++ b/packages/views/src/ui/input-group.styles.ts @@ -22,7 +22,7 @@ export const inputGroupAddonVariants = cva( ) export const inputGroupStyles = - "relative inline-flex w-full min-w-0 items-center rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-control has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a2 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive-a4 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-sm dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a3 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-md-inset" + "relative inline-flex w-full min-w-0 items-center rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-control has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a2 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive-a4 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-ui/5 dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a3 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-md-inset" export const inputGroupTextStyles = "line-clamp-1 flex items-center gap-2 whitespace-nowrap text-muted-foreground leading-none in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-mx-0.5" diff --git a/packages/views/src/ui/input.styles.ts b/packages/views/src/ui/input.styles.ts index 6b6d9a235c..aca34bffea 100644 --- a/packages/views/src/ui/input.styles.ts +++ b/packages/views/src/ui/input.styles.ts @@ -7,7 +7,7 @@ export const inputControlLayoutStyles = "relative inline-flex w-full" /** Border, background, shadow and focus ring — the part `unstyled` removes. */ export const inputControlChromeStyles = - "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-control has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] sm:text-sm dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" + "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-control has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] sm:text-ui/5 dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" export const inputStyles = "h-8.5 w-full min-w-0 rounded-[inherit] px-[calc(--spacing(3)-1px)] leading-8.5 outline-none [transition:background-color_5000000s_ease-in-out_0s] placeholder:text-foreground-subtle sm:h-7.5 sm:leading-7.5" diff --git a/packages/views/src/ui/key-value.styles.ts b/packages/views/src/ui/key-value.styles.ts index 99c02b70a2..e0f534f548 100644 --- a/packages/views/src/ui/key-value.styles.ts +++ b/packages/views/src/ui/key-value.styles.ts @@ -29,7 +29,7 @@ export const keyValueValueFirstStyles = "in-data-[value-first]:flex-row-reverse" export const keyValueLabelStyles = "shrink-0 text-muted-foreground" export const keyValueLabelOverlineStyles = - "in-data-[label=overline]:text-3xs in-data-[label=overline]:font-medium in-data-[label=overline]:uppercase in-data-[label=overline]:tracking-overline" + "in-data-[label=overline]:text-2xs in-data-[label=overline]:font-medium" export const keyValueValueStyles = "flex min-w-0 items-center gap-1 text-foreground in-data-[layout=split]:justify-end in-data-[layout=split]:text-right" diff --git a/packages/views/src/ui/label.styles.ts b/packages/views/src/ui/label.styles.ts index 71f50f5e87..9674f343ce 100644 --- a/packages/views/src/ui/label.styles.ts +++ b/packages/views/src/ui/label.styles.ts @@ -1,2 +1,2 @@ export const labelStyles = - "inline-flex items-center gap-2 font-medium text-base/4.5 text-foreground sm:text-sm/4" + "inline-flex items-center gap-2 font-medium text-base/4.5 text-foreground sm:text-ui/4" diff --git a/packages/views/src/ui/select.styles.ts b/packages/views/src/ui/select.styles.ts index 488aef27d1..166c6eb101 100644 --- a/packages/views/src/ui/select.styles.ts +++ b/packages/views/src/ui/select.styles.ts @@ -1,7 +1,7 @@ import { cva } from "class-variance-authority" export const selectTriggerVariants = cva( - "relative inline-flex min-h-9 min-w-36 select-none items-center justify-between gap-2 rounded-lg border border-input bg-background not-dark:bg-clip-padding px-[calc(--spacing(3)-1px)] text-left text-base text-foreground shadow-raised outline-none ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-control pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive-a4 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive-a2 data-disabled:pointer-events-none data-disabled:opacity-64 sm:min-h-8 sm:text-sm dark:bg-input/32 dark:aria-invalid:ring-destructive-a3 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none", + "relative inline-flex min-h-9 min-w-36 select-none items-center justify-between gap-2 rounded-lg border border-input bg-background not-dark:bg-clip-padding px-[calc(--spacing(3)-1px)] text-left text-base text-foreground shadow-raised outline-none ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-control pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive-a4 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive-a2 data-disabled:pointer-events-none data-disabled:opacity-64 sm:min-h-8 sm:text-ui/5 dark:bg-input/32 dark:aria-invalid:ring-destructive-a3 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none", { defaultVariants: { size: "default", @@ -40,7 +40,7 @@ export const selectScrollDownArrowStyles = "bottom-0 z-50 flex h-6 w-full cursor-default items-center justify-center before:pointer-events-none before:absolute before:inset-x-px before:bottom-px before:h-[200%] before:rounded-b-lg-inset before:bg-linear-to-t before:from-50% before:from-popover" export const selectItemStyles = - "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" + "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" export const selectItemIndicatorStyles = "col-start-1" @@ -51,6 +51,6 @@ export const selectItemTextStyles = "col-start-2 min-w-0" export const selectSeparatorStyles = "mx-2 my-1 h-px bg-border" export const selectLabelStyles = - "not-in-data-[slot=field]:mb-2 inline-flex cursor-default items-center gap-2 font-medium text-base/4.5 text-foreground sm:text-sm/4" + "not-in-data-[slot=field]:mb-2 inline-flex cursor-default items-center gap-2 font-medium text-base/4.5 text-foreground sm:text-ui/4" export const selectGroupLabelStyles = "px-2 py-1.5 font-medium text-muted-foreground text-xs" diff --git a/packages/views/src/ui/sidebar.styles.ts b/packages/views/src/ui/sidebar.styles.ts index 99c89fae46..58ff1b0a81 100644 --- a/packages/views/src/ui/sidebar.styles.ts +++ b/packages/views/src/ui/sidebar.styles.ts @@ -1,7 +1,7 @@ import { cva } from "class-variance-authority" export const sidebarMenuButtonVariants = cva( - "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-lg p-2 text-left text-xs outline-hidden ring-sidebar-ring transition-[width,height,padding] duration-200 ease-move group-data-instant:transition-none hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent/50 active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-64 group-has-data-[sidebar=menu-action]/menu-item:pe-8 aria-disabled:pointer-events-none aria-disabled:opacity-64 data-[active=child]:font-medium data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:active:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground data-[state=open]:active:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg:not([class*='size-'])]:size-4 [&>svg]:shrink-0", + "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-lg p-2 text-left text-ui outline-hidden ring-sidebar-ring transition-[width,height,padding] duration-200 ease-move group-data-instant:transition-none hover:bg-sidebar-accent/50 hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent/50 active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-64 group-has-data-[sidebar=menu-action]/menu-item:pe-8 aria-disabled:pointer-events-none aria-disabled:opacity-64 data-[active=child]:font-medium data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:active:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground data-[state=open]:active:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg:not([class*='size-'])]:size-4 [&>svg]:shrink-0", { defaultVariants: { size: "default", @@ -9,9 +9,9 @@ export const sidebarMenuButtonVariants = cva( }, variants: { size: { - default: "h-8 text-xs", + default: "h-8 text-ui", lg: "h-12 text-xs group-data-[collapsible=icon]:p-0!", - sm: "h-7 text-xs", + sm: "h-7 text-ui", }, variant: { // Hover is the selected tint at half strength, so the full tint stays the selected row's. @@ -89,7 +89,7 @@ export const sidebarContentStyles = export const sidebarGroupStyles = "relative flex w-full min-w-0 flex-col p-2" export const sidebarGroupLabelStyles = [ - "flex h-8 shrink-0 items-center rounded-lg px-2 font-semibold text-2xs text-sidebar-foreground uppercase tracking-overline outline-hidden ring-sidebar-ring transition-[margin,opacity] duration-200 ease-move group-data-instant:transition-none focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", + "flex h-8 shrink-0 items-center rounded-lg px-2 font-medium text-xs text-sidebar-foreground outline-hidden ring-sidebar-ring transition-[margin,opacity] duration-200 ease-move group-data-instant:transition-none focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:pointer-events-none group-data-[collapsible=icon]:opacity-0", ] as const @@ -100,7 +100,7 @@ export const sidebarGroupActionStyles = [ "group-data-[collapsible=icon]:hidden", ] as const -export const sidebarGroupContentStyles = "w-full text-xs" +export const sidebarGroupContentStyles = "w-full text-ui" export const sidebarMenuStyles = "flex w-full min-w-0 flex-col gap-1" @@ -128,6 +128,6 @@ export const sidebarMenuSubButtonStyles = [ "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground", ] as const -export const sidebarMenuSubButtonMdStyles = "text-xs" +export const sidebarMenuSubButtonMdStyles = "text-ui" export const sidebarMenuSubButtonIconCollapsibleStyles = "group-data-[collapsible=icon]:hidden" diff --git a/packages/views/src/ui/stat-figure.ts b/packages/views/src/ui/stat-figure.ts index f4c713a503..a3f73ab921 100644 --- a/packages/views/src/ui/stat-figure.ts +++ b/packages/views/src/ui/stat-figure.ts @@ -21,7 +21,7 @@ export interface StatFigureOptions { readonly value: Html | string readonly unit?: Html | string readonly size?: StatFigureSize - /** Mono figures for readouts; `false` sets the value in the display face. */ + /** Mono figures for a machine readout; the default is the display face. */ readonly mono?: boolean readonly className?: string readonly valueClassName?: string @@ -54,7 +54,7 @@ const figure = (h: HtmlBuilder, options: StatFigureOptions, className?: st h.Class( cn( statFigureValueStyles, - (options.mono ?? true) ? statFigureValueMonoStyles : statFigureValueDisplayStyles, + (options.mono ?? false) ? statFigureValueMonoStyles : statFigureValueDisplayStyles, statFigureValueSizeStyles[size], options.valueClassName, ), diff --git a/packages/views/src/ui/tabs.styles.ts b/packages/views/src/ui/tabs.styles.ts index a3189ba3c7..5e869c0e81 100644 --- a/packages/views/src/ui/tabs.styles.ts +++ b/packages/views/src/ui/tabs.styles.ts @@ -19,6 +19,6 @@ export const tabsIndicatorUnderlineStyles = export const tabsIndicatorDefaultStyles = "-z-1 rounded-md bg-background shadow-raised dark:bg-input" export const tabsTabStyles = - "relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] font-medium text-base outline-none hover:text-muted-foreground active:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-foreground data-disabled:opacity-64 sm:h-8 sm:text-sm [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0" + "relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] font-medium text-base outline-none hover:text-muted-foreground active:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-foreground data-disabled:opacity-64 sm:h-8 sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0" export const tabsPanelStyles = "flex-1 outline-none" diff --git a/packages/views/src/ui/textarea.styles.ts b/packages/views/src/ui/textarea.styles.ts index 9378f16fd8..9cc6c72c76 100644 --- a/packages/views/src/ui/textarea.styles.ts +++ b/packages/views/src/ui/textarea.styles.ts @@ -11,7 +11,7 @@ export const textareaControlLayoutStyles = "relative inline-flex w-full" /** Border, background, shadow and focus ring — the part `unstyled` removes. */ export const textareaControlChromeStyles = - "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-control sm:text-sm dark:bg-input/32 dark:has-aria-invalid:ring-destructive-a3" + "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-control sm:text-ui/5 dark:bg-input/32 dark:has-aria-invalid:ring-destructive-a3" export const textareaStyles = "field-sizing-content min-h-17.5 w-full rounded-[inherit] px-[calc(--spacing(3)-1px)] py-[calc(--spacing(1.5)-1px)] outline-none max-sm:min-h-20.5" diff --git a/packages/views/src/ui/toggle.styles.ts b/packages/views/src/ui/toggle.styles.ts index 68fc3f553d..a5c6dad7f9 100644 --- a/packages/views/src/ui/toggle.styles.ts +++ b/packages/views/src/ui/toggle.styles.ts @@ -2,7 +2,7 @@ import { cva } from "class-variance-authority" import { cn } from "@maple/ui/lib/utils" export const toggleVariants = cva( - "relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base text-foreground outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent active:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-pressed:bg-input/64 data-pressed:text-accent-foreground sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", + "relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base text-foreground outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent active:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-pressed:bg-input/64 data-pressed:text-accent-foreground sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", { // Segments carry text, not a lone icon, so they need more horizontal room // than the base sizes give: those are tuned for square icon toggles, where From 34823adb16f43bcf0643c1ee7f824a6293902df2 Mon Sep 17 00:00:00 2001 From: Makisuo Date: Fri, 13 Nov 2026 16:40:57 +0100 Subject: [PATCH 2/2] fix(ui): review follow-ups for the Geist type pass - Kit controls take 13px without a hard line height (`sm:text-ui`, not `sm:text-ui/5`), so a caller's `leading-*` on a textarea applies again. The where-clause highlight overlays follow their textarea's size; at 14px over a 13px textarea the coloured tokens drifted from the caret. - Kit pieces that set a quantity in mono no longer do: the numeric table cell, latency and error rate values, filter chip counts, chart legends and the nav count. A table row reads in one face. - Machine tags that relied on the uppercase transform take the mono eyebrow: service map node labels and runtime tags, the database panel badge, the code block language, the where-autocomplete kind. - Labels written in lowercase for the old transform are capitalised. - The sidebar's large row (org switcher) is 13px like the rows under it, and the eyebrow field label keeps 12px on desktop. - The service map fills the viewport under the 48px top bar. --- apps/web/src/page/alerts/hub/view-routing.ts | 9 +++------ apps/web/src/page/dashboards/widget/view-steps.ts | 2 +- apps/web/src/page/errors/issue/view-tables.ts | 2 +- .../infra-integrations/gcp/workload/view-sql-peek.ts | 2 +- apps/web/src/page/kit/code-block.ts | 2 +- apps/web/src/page/kit/data-table.ts | 3 +-- apps/web/src/page/kit/nav-shell.ts | 1 - apps/web/src/page/kit/query-builder/where-editor.ts | 2 +- apps/web/src/page/kit/where-autocomplete-view.ts | 2 +- apps/web/src/page/metrics/detail/view-controls.ts | 2 +- apps/web/src/page/overview/view-health.ts | 2 +- apps/web/src/page/replays/detail/view.ts | 2 +- apps/web/src/page/service-map/view-db-panel.ts | 2 +- apps/web/src/page/service-map/view-service-infra.ts | 2 +- apps/web/src/page/service-map/view.ts | 2 +- apps/web/src/page/services/detail/endpoint-peek/view.ts | 2 +- apps/web/src/page/services/list/view-table.ts | 2 +- apps/web/src/page/traces/list/view-advanced.ts | 4 ++-- packages/views/src/charts/plot-legend.ts | 2 +- packages/views/src/charts/timeseries-legend.ts | 4 ++-- .../views/src/service-map/graph/service-map-db-style.ts | 2 +- packages/views/src/service-map/map/node-card.ts | 2 +- packages/views/src/service-map/map/nodes.ts | 5 +++-- packages/views/src/ui/INDEX.md | 2 +- packages/views/src/ui/autocomplete.styles.ts | 4 ++-- packages/views/src/ui/button.styles.ts | 2 +- packages/views/src/ui/combobox.styles.ts | 8 ++++---- packages/views/src/ui/eyebrow.ts | 4 ++-- packages/views/src/ui/field.ts | 2 +- packages/views/src/ui/filter-chip.styles.ts | 2 +- packages/views/src/ui/input-group.styles.ts | 2 +- packages/views/src/ui/input.styles.ts | 2 +- packages/views/src/ui/select.styles.ts | 4 ++-- packages/views/src/ui/sidebar.styles.ts | 2 +- packages/views/src/ui/tabs.styles.ts | 2 +- packages/views/src/ui/textarea.styles.ts | 2 +- packages/views/src/ui/toggle.styles.ts | 2 +- packages/views/src/ui/values.ts | 4 ++-- 38 files changed, 50 insertions(+), 54 deletions(-) diff --git a/apps/web/src/page/alerts/hub/view-routing.ts b/apps/web/src/page/alerts/hub/view-routing.ts index 7bedbcb6e1..da8ed885e4 100644 --- a/apps/web/src/page/alerts/hub/view-routing.ts +++ b/apps/web/src/page/alerts/hub/view-routing.ts @@ -433,12 +433,9 @@ const logTable = ( [ eyebrow(h, { className: hstackClass({ gap: "2" }) }, [ group.label, - h.span( - [ - h.Class( - "tracking-normal normal-case text-foreground-subtle tabular-nums", - ), - ], + typography( + h, + { tone: "subtle", numeric: true }, [ String(group.events.length), " ", diff --git a/apps/web/src/page/dashboards/widget/view-steps.ts b/apps/web/src/page/dashboards/widget/view-steps.ts index ab0113cda8..5149faf151 100644 --- a/apps/web/src/page/dashboards/widget/view-steps.ts +++ b/apps/web/src/page/dashboards/widget/view-steps.ts @@ -270,7 +270,7 @@ const filterLine = ( const parsed = parseFunnelStepFilter(filterClause) return vstack(h, { gap: "0.5", className: "pl-6" }, [ hstack(h, { gap: "1.5" }, [ - eyebrow(h, { className: "shrink-0" }, ["where"]), + eyebrow(h, { className: "shrink-0" }, ["Where"]), whereEditor(h, { id: `widget-step-${scope}-${index}-filter`, value: filterClause, diff --git a/apps/web/src/page/errors/issue/view-tables.ts b/apps/web/src/page/errors/issue/view-tables.ts index 27fdae1a47..6510422959 100644 --- a/apps/web/src/page/errors/issue/view-tables.ts +++ b/apps/web/src/page/errors/issue/view-tables.ts @@ -74,7 +74,7 @@ const incidentRow = (h: HtmlBuilder, incident: ErrorIncidentDocument, cloc [ statusDot(h, { tone: isOpen ? "crit" : "neutral" }), eyebrow(h, { variant: "label", className: isOpen ? "text-severity-error" : undefined }, [ - incident.status, + Str.capitalize(incident.status), ]), ], ), diff --git a/apps/web/src/page/infra-integrations/gcp/workload/view-sql-peek.ts b/apps/web/src/page/infra-integrations/gcp/workload/view-sql-peek.ts index 6dd0f4db6f..f020fc18d4 100644 --- a/apps/web/src/page/infra-integrations/gcp/workload/view-sql-peek.ts +++ b/apps/web/src/page/infra-integrations/gcp/workload/view-sql-peek.ts @@ -72,7 +72,7 @@ const header = (h: H, model: Model, peek: QueryPeek, inputs: QueryPeekInputs): H [ eyebrow(h, { as: "div", className: hstackClass({ gap: "2" }) }, [ "Statement", - h.span([h.Class("normal-case tracking-normal")], [`· ${where}`]), + h.span([], [`· ${where}`]), ]), DialogView.dialogTitle(h, "sheet", id, `Statement on ${where}`, "sr-only"), DialogView.dialogDescription( diff --git a/apps/web/src/page/kit/code-block.ts b/apps/web/src/page/kit/code-block.ts index b3c8497929..c6a8837c80 100644 --- a/apps/web/src/page/kit/code-block.ts +++ b/apps/web/src/page/kit/code-block.ts @@ -33,7 +33,7 @@ export const codeBlock = (h: HtmlBuilder, options: CodeBlockOptions): H h, { align: "center", justify: "between", className: "px-3 py-1.5 text-muted-foreground" }, [ - ...(options.language === undefined ? [] : [eyebrow(h, {}, [options.language])]), + ...(options.language === undefined ? [] : [eyebrow(h, { variant: "mono" }, [options.language])]), CopyButton.view(h, { model: options.copy, toParentMessage: options.toCopyMessage, diff --git a/apps/web/src/page/kit/data-table.ts b/apps/web/src/page/kit/data-table.ts index 328ea1066d..7295cc88f8 100644 --- a/apps/web/src/page/kit/data-table.ts +++ b/apps/web/src/page/kit/data-table.ts @@ -10,10 +10,9 @@ import { infoHint } from "@maple/views/ui/info-hint" // A sortable data table: its column heads, numeric cells, row links, and empty and skeleton rows. -/** A numeric cell's figure: xs mono tabular, right-aligned; the call site adds width and tone. */ +/** A numeric cell's figure: xs tabular, right-aligned; the call site adds width and tone. */ export const NUMERIC_CELL = typographyClass({ size: "xs", - mono: true, numeric: true, className: "text-right", }) diff --git a/apps/web/src/page/kit/nav-shell.ts b/apps/web/src/page/kit/nav-shell.ts index 002f6cdbe5..7bcfb73f7b 100644 --- a/apps/web/src/page/kit/nav-shell.ts +++ b/apps/web/src/page/kit/nav-shell.ts @@ -34,7 +34,6 @@ const rowChildren = (h: HtmlBuilder, row: RowBase) => [ h, { size: "xs", - mono: true, numeric: true, tone: row.count.tone ?? "muted", className: "shrink-0", diff --git a/apps/web/src/page/kit/query-builder/where-editor.ts b/apps/web/src/page/kit/query-builder/where-editor.ts index a113bac712..96d6bb7c66 100644 --- a/apps/web/src/page/kit/query-builder/where-editor.ts +++ b/apps/web/src/page/kit/query-builder/where-editor.ts @@ -138,7 +138,7 @@ export const highlightOverlay = ( h.AriaHidden(true), h.Class( cn( - "pointer-events-none absolute inset-0 overflow-hidden rounded-lg border border-transparent text-base sm:text-sm", + "pointer-events-none absolute inset-0 overflow-hidden rounded-lg border border-transparent text-base sm:text-ui", textareaClassName, ), ), diff --git a/apps/web/src/page/kit/where-autocomplete-view.ts b/apps/web/src/page/kit/where-autocomplete-view.ts index 9e71b0f1b6..d1d0e5132b 100644 --- a/apps/web/src/page/kit/where-autocomplete-view.ts +++ b/apps/web/src/page/kit/where-autocomplete-view.ts @@ -56,7 +56,7 @@ export const suggestionListbox = ( [h.Class("min-w-0 truncate font-mono"), h.Title(suggestion.label)], [suggestion.label], ), - eyebrow(h, { className: "shrink-0" }, [suggestion.kind]), + eyebrow(h, { variant: "mono", className: "shrink-0" }, [suggestion.kind]), ], ), ), diff --git a/apps/web/src/page/metrics/detail/view-controls.ts b/apps/web/src/page/metrics/detail/view-controls.ts index 844e2954d9..53e16a71b5 100644 --- a/apps/web/src/page/metrics/detail/view-controls.ts +++ b/apps/web/src/page/metrics/detail/view-controls.ts @@ -116,7 +116,7 @@ const whereEditor = (h: H, model: Model): Html => { h.AriaHidden(true), h.Class( cn( - "pointer-events-none absolute inset-0 overflow-hidden rounded-lg border border-transparent text-base sm:text-sm", + "pointer-events-none absolute inset-0 overflow-hidden rounded-lg border border-transparent text-base sm:text-ui", textareaClassName, ), ), diff --git a/apps/web/src/page/overview/view-health.ts b/apps/web/src/page/overview/view-health.ts index 3e81b0dd30..993a9913a5 100644 --- a/apps/web/src/page/overview/view-health.ts +++ b/apps/web/src/page/overview/view-health.ts @@ -347,7 +347,7 @@ const serviceRow = ( h, { gap: "5", align: "center", className: "shrink-0 font-mono text-xs tabular-nums" }, [ - metric(h, "err", formatErrorRate(service.errorRate), metricTone(causeOf("error"))), + metric(h, "Errors", formatErrorRate(service.errorRate), metricTone(causeOf("error"))), metric( h, "p95", diff --git a/apps/web/src/page/replays/detail/view.ts b/apps/web/src/page/replays/detail/view.ts index 8761ec6c06..be0f6dc27b 100644 --- a/apps/web/src/page/replays/detail/view.ts +++ b/apps/web/src/page/replays/detail/view.ts @@ -153,7 +153,7 @@ const identityBar = (h: H, model: IdentityView, session: ReplayDetail, timeZone: typography(h, { size: "sm", weight: "semibold", mono: true, numeric: true }, [ formatSessionDuration(durationOf(session)), ]), - eyebrow(h, {}, ["duration"]), + eyebrow(h, {}, ["Duration"]), ]), ...(session.errorCount > 0 ? [errorCountPill(h, { count: session.errorCount })] : []), ]), diff --git a/apps/web/src/page/service-map/view-db-panel.ts b/apps/web/src/page/service-map/view-db-panel.ts index 2af19f17d1..79b5a28aca 100644 --- a/apps/web/src/page/service-map/view-db-panel.ts +++ b/apps/web/src/page/service-map/view-db-panel.ts @@ -182,7 +182,7 @@ const header = (h: H, inputs: DatabasePanelInputs): Html => { typography(h, { size: "sm", tone: "foreground", weight: "semibold", truncate: true }, [ style.title, ]), - eyebrow(h, { className: "shrink-0" }, [style.badge]), + eyebrow(h, { variant: "mono", className: "shrink-0" }, [style.badge]), ], [ iconButton( diff --git a/apps/web/src/page/service-map/view-service-infra.ts b/apps/web/src/page/service-map/view-service-infra.ts index 67c996dcd9..76734a7b9b 100644 --- a/apps/web/src/page/service-map/view-service-infra.ts +++ b/apps/web/src/page/service-map/view-service-infra.ts @@ -74,7 +74,7 @@ const workloadRow = (h: H, workload: ServiceWorkload, time: TimeSearch): Html => ], ), vstack(h, { align: "end", className: "gap-px shrink-0" }, [ - eyebrow(h, {}, ["pods"]), + eyebrow(h, {}, ["Pods"]), typography( h, { size: "sm", tone: "foreground", weight: "semibold", mono: true, numeric: true }, diff --git a/apps/web/src/page/service-map/view.ts b/apps/web/src/page/service-map/view.ts index 6324d62e07..d7f285a27a 100644 --- a/apps/web/src/page/service-map/view.ts +++ b/apps/web/src/page/service-map/view.ts @@ -248,7 +248,7 @@ export const view = Submodel.defineView((model, [ ...dbEdgesTimedOutNotice(h, model), h.div( - [h.Class("-mx-4 -mb-4 h-[calc(100vh-10rem)]")], + [h.Class("-mx-4 -mb-4 h-[calc(100vh-9rem)]")], [mapArea(h, model, inputs)], ), ], diff --git a/apps/web/src/page/services/detail/endpoint-peek/view.ts b/apps/web/src/page/services/detail/endpoint-peek/view.ts index a82cc2afee..961d2ed15d 100644 --- a/apps/web/src/page/services/detail/endpoint-peek/view.ts +++ b/apps/web/src/page/services/detail/endpoint-peek/view.ts @@ -342,7 +342,7 @@ const clientsCard = (h: H, detail: EndpointDetail, spanCount: number): Html => { ? typography(h, { size: "2xs", tone: "muted", as: "p" }, ["No requests carried a user agent"]) : vstack( h, - { gap: "1.5", className: typographyClass({ size: "2xs", numeric: true }) }, + { gap: "1.5", className: typographyClass({ size: "2xs", mono: true, numeric: true }) }, Arr.map(detail.userAgents.slice(0, 5), (agent) => hstack(h, { gap: "2", attributes: [h.Key(agent.value)] }, [ typography( diff --git a/apps/web/src/page/services/list/view-table.ts b/apps/web/src/page/services/list/view-table.ts index b273809a59..8295e61805 100644 --- a/apps/web/src/page/services/list/view-table.ts +++ b/apps/web/src/page/services/list/view-table.ts @@ -680,7 +680,7 @@ const mobileList = ( className: "block", }), }), - eyebrow(h, { as: "div" }, ["err"]), + eyebrow(h, { as: "div" }, ["Errors"]), ], ), ], diff --git a/apps/web/src/page/traces/list/view-advanced.ts b/apps/web/src/page/traces/list/view-advanced.ts index 777127aee5..591dff5107 100644 --- a/apps/web/src/page/traces/list/view-advanced.ts +++ b/apps/web/src/page/traces/list/view-advanced.ts @@ -66,7 +66,7 @@ export const suggestionList = (h: H, model: Model): ReadonlyArray => { }, [suggestion.label], ), - eyebrow(h, { className: "shrink-0" }, [suggestion.kind]), + eyebrow(h, { variant: "mono", className: "shrink-0" }, [suggestion.kind]), ], ) }), @@ -104,7 +104,7 @@ const editor = (h: H, model: Model): Html => { h.AriaHidden(true), h.Class( cn( - "pointer-events-none absolute inset-0 overflow-hidden rounded-lg border border-transparent text-base sm:text-sm", + "pointer-events-none absolute inset-0 overflow-hidden rounded-lg border border-transparent text-base sm:text-ui", TEXTAREA_CLASS, ), ), diff --git a/packages/views/src/charts/plot-legend.ts b/packages/views/src/charts/plot-legend.ts index c03e2a6942..8b8f12ce78 100644 --- a/packages/views/src/charts/plot-legend.ts +++ b/packages/views/src/charts/plot-legend.ts @@ -28,7 +28,7 @@ export interface PlotLegendState { const legendValue = (h: HtmlBuilder, value: string, secondary: string | undefined): Html => hstack( h, - { gap: "2", align: "baseline", as: "span", className: "ml-auto shrink-0 font-mono tabular-nums" }, + { gap: "2", align: "baseline", as: "span", className: "ml-auto shrink-0 tabular-nums" }, [ typography(h, { tone: "foreground" }, [value]), ...(secondary === undefined diff --git a/packages/views/src/charts/timeseries-legend.ts b/packages/views/src/charts/timeseries-legend.ts index c897d34327..e37b087d1f 100644 --- a/packages/views/src/charts/timeseries-legend.ts +++ b/packages/views/src/charts/timeseries-legend.ts @@ -175,7 +175,7 @@ const statsTable = ( ? [entryStats === null ? EMPTY_VALUE : "0"] : [], cn( - "px-2 py-0 text-right font-mono leading-4 tabular-nums text-foreground-subtle last:pr-0", + "px-2 py-0 text-right leading-4 tabular-nums text-foreground-subtle last:pr-0", column.className, ), ) @@ -183,7 +183,7 @@ const statsTable = ( h, [formatValueByUnit(entryStats[column.field], unit)], cn( - "px-2 py-0 text-right font-mono leading-4 tabular-nums last:pr-0", + "px-2 py-0 text-right leading-4 tabular-nums last:pr-0", column.className, ), ), diff --git a/packages/views/src/service-map/graph/service-map-db-style.ts b/packages/views/src/service-map/graph/service-map-db-style.ts index 2792597a1c..34ee4dad76 100644 --- a/packages/views/src/service-map/graph/service-map-db-style.ts +++ b/packages/views/src/service-map/graph/service-map-db-style.ts @@ -186,7 +186,7 @@ export function getDbStyle(system: string | undefined): DbStyle { export interface DbNodeStyle { /** Node title: the database identity, or "Hyperdrive" for the collapsed proxy node. */ title: string - /** Small uppercase badge: the underlying system, or the coarse category. */ + /** Small badge: the underlying system, or the coarse category. */ badge: string icon: DbIconKey color: string diff --git a/packages/views/src/service-map/map/node-card.ts b/packages/views/src/service-map/map/node-card.ts index 37de66ede7..6e5e8d79a0 100644 --- a/packages/views/src/service-map/map/node-card.ts +++ b/packages/views/src/service-map/map/node-card.ts @@ -99,7 +99,7 @@ export const metricCell = ( valueClassName?: string, ): Html => vstack(h, { className: "gap-px" }, [ - eyebrow(h, { className: "text-4xs text-foreground-subtle" }, [label]), + eyebrow(h, { variant: "mono", className: "text-4xs" }, [label]), h.span( [ h.Class( diff --git a/packages/views/src/service-map/map/nodes.ts b/packages/views/src/service-map/map/nodes.ts index dc6e0ecce2..639db45b31 100644 --- a/packages/views/src/service-map/map/nodes.ts +++ b/packages/views/src/service-map/map/nodes.ts @@ -48,7 +48,7 @@ const tintedCard = (color: string, tint: number, border: number, selected: boole const podsCell = (h: HtmlBuilder, data: ServiceNodeData): Html => vstack(h, { align: "end", className: "ml-auto gap-px" }, [ - eyebrow(h, { className: "text-4xs text-foreground-subtle" }, ["pods"]), + eyebrow(h, { variant: "mono", className: "text-4xs" }, ["pods"]), data.infra ? tooltipTrigger(h, [ hstack( @@ -123,7 +123,8 @@ const serviceNode = (h: HtmlBuilder, id: string, data: ServiceNodeData): R ? eyebrow( h, { - className: "shrink-0 text-4xs text-foreground-subtle", + variant: "mono", + className: "shrink-0 text-4xs", }, [runtimeInfo.short], ) diff --git a/packages/views/src/ui/INDEX.md b/packages/views/src/ui/INDEX.md index 0131be763f..5d7c6d634e 100644 --- a/packages/views/src/ui/INDEX.md +++ b/packages/views/src/ui/INDEX.md @@ -59,7 +59,7 @@ existing copies onto it (see `apps/web/CLAUDE.md`). - `packages/views/src/ui/error-count-pill.ts` `errorCountPill`: `ErrorCountPill`: a failure count as a toned pill, led by a dot or its kind's glyph. - `packages/views/src/ui/error-section.ts` `errorSectionView`: `ErrorSection`: the error banner, its highlighted body that copies itself, the "Copy as prompt" control and the Show more toggle. - `packages/views/src/ui/error-state.ts` `failureKind`, `failureSentence`, `autoRetryMessage`, `errorState`: The error state: a failure's glyph, sentence and retry. -- `packages/views/src/ui/eyebrow.ts` `withHint`, `eyebrow`: Keeps a trailing "(hint)" out of the uppercase transform; for any uppercased label. +- `packages/views/src/ui/eyebrow.ts` `withHint`, `eyebrow`: Keeps a trailing "(hint)" out of an uppercase transform; for any uppercased label. - `packages/views/src/ui/field.ts` `stateOf`, `controlAttributes`, `field`, `fieldLabel`, `fieldGroupLabel`, `input`, `fieldDescription`, `fieldError`, `fieldErrorText` (stateful: Model, init, update): The value and focus handlers a field's control reports through. - `packages/views/src/ui/file-input.ts` `fileInput`: `FileInput`: a hidden `` that a visible button opens by id; it reports the picked files. - `packages/views/src/ui/filter-chip.ts` `filterChip`, `filterChipItem`: An on/off filter toggle with an optional tone dot and trailing count. diff --git a/packages/views/src/ui/autocomplete.styles.ts b/packages/views/src/ui/autocomplete.styles.ts index d8dfeade65..c78b14fb8e 100644 --- a/packages/views/src/ui/autocomplete.styles.ts +++ b/packages/views/src/ui/autocomplete.styles.ts @@ -24,12 +24,12 @@ export const autocompletePopupStyles = "flex max-h-[min(var(--available-height),23rem)] flex-1 flex-col text-foreground" export const autocompleteItemStyles = - "flex min-h-8 cursor-default select-none items-center rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui/5" + "flex min-h-8 cursor-default select-none items-center rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui" export const autocompleteGroupStyles = "[[role=group]+&]:mt-1.5" export const autocompleteGroupLabelStyles = "px-2 py-1.5 font-medium text-muted-foreground text-xs" -export const autocompleteEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-ui/5" +export const autocompleteEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-ui" export const autocompleteListStyles = "not-empty:scroll-py-1 not-empty:p-1 in-data-has-overflow-y:pe-3" diff --git a/packages/views/src/ui/button.styles.ts b/packages/views/src/ui/button.styles.ts index f33655b3a1..9d11eddb66 100644 --- a/packages/views/src/ui/button.styles.ts +++ b/packages/views/src/ui/button.styles.ts @@ -1,7 +1,7 @@ import { cva } from "class-variance-authority" export const buttonVariants = cva( - "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-[scale] duration-150 ease-out active:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-loading:select-none data-loading:text-transparent sm:text-ui/5 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", + "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-[scale] duration-150 ease-out active:scale-[0.97] before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-loading:select-none data-loading:text-transparent sm:text-ui [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", { defaultVariants: { size: "default", diff --git a/packages/views/src/ui/combobox.styles.ts b/packages/views/src/ui/combobox.styles.ts index 7c63149782..f6c199cc78 100644 --- a/packages/views/src/ui/combobox.styles.ts +++ b/packages/views/src/ui/combobox.styles.ts @@ -1,5 +1,5 @@ export const comboboxChipsInputStyles = - "min-w-12 flex-1 text-base outline-none sm:text-ui/5 [[data-slot=combobox-chip]+&]:ps-0.5" + "min-w-12 flex-1 text-base outline-none sm:text-ui [[data-slot=combobox-chip]+&]:ps-0.5" export const comboboxChipsInputSmStyles = "ps-1.5" @@ -38,19 +38,19 @@ export const comboboxPopupStyles = "flex max-h-[min(var(--available-height),23rem)] flex-1 flex-col text-foreground" export const comboboxItemStyles = - "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" + "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" export const comboboxItemIndicatorStyles = "col-start-1" export const comboboxItemTextStyles = "col-start-2" -export const comboboxEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-ui/5" +export const comboboxEmptyStyles = "not-empty:p-2 text-center text-base text-muted-foreground sm:text-ui" export const comboboxListStyles = "not-empty:scroll-py-1 not-empty:px-1 not-empty:py-1 in-data-has-overflow-y:pe-3" export const comboboxChipsStyles = - "relative inline-flex min-h-9 w-full flex-wrap gap-1 rounded-lg border border-input bg-background not-dark:bg-clip-padding p-[calc(--spacing(1)-1px)] text-base shadow-raised outline-none ring-ring/24 transition-shadow *:min-h-7 before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-control focus-within:border-ring focus-within:ring-[3px] has-disabled:pointer-events-none has-data-[size=lg]:min-h-10 has-data-[size=sm]:min-h-8 has-aria-invalid:border-destructive-a4 has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-within,[aria-invalid]]:shadow-none focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive-a2 has-data-[size=lg]:*:min-h-8 has-data-[size=sm]:*:min-h-6 sm:min-h-8 sm:text-ui/5 sm:has-data-[size=lg]:min-h-9 sm:has-data-[size=sm]:min-h-7 sm:*:min-h-6 sm:has-data-[size=lg]:*:min-h-7 sm:has-data-[size=sm]:*:min-h-5 dark:not-has-disabled:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" + "relative inline-flex min-h-9 w-full flex-wrap gap-1 rounded-lg border border-input bg-background not-dark:bg-clip-padding p-[calc(--spacing(1)-1px)] text-base shadow-raised outline-none ring-ring/24 transition-shadow *:min-h-7 before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-control focus-within:border-ring focus-within:ring-[3px] has-disabled:pointer-events-none has-data-[size=lg]:min-h-10 has-data-[size=sm]:min-h-8 has-aria-invalid:border-destructive-a4 has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-within,[aria-invalid]]:shadow-none focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive-a2 has-data-[size=lg]:*:min-h-8 has-data-[size=sm]:*:min-h-6 sm:min-h-8 sm:text-ui sm:has-data-[size=lg]:min-h-9 sm:has-data-[size=sm]:min-h-7 sm:*:min-h-6 sm:has-data-[size=lg]:*:min-h-7 sm:has-data-[size=sm]:*:min-h-5 dark:not-has-disabled:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" // A translucent foreground tint rather than `bg-accent`: in this theme // --accent, --muted and --secondary are all the same value as the diff --git a/packages/views/src/ui/eyebrow.ts b/packages/views/src/ui/eyebrow.ts index b311353f3c..b3c1f77f9a 100644 --- a/packages/views/src/ui/eyebrow.ts +++ b/packages/views/src/ui/eyebrow.ts @@ -16,10 +16,10 @@ export interface EyebrowOptions { readonly icon?: IconName } -// A trailing "(hint)" often holds units or syntax (`5m`, `AND`); uppercasing would change its meaning. +// A trailing "(hint)" often holds units or syntax (`5m`, `AND`); the mono variant's uppercasing would change its meaning. const HINT = /^(.*\S)(\s+\(.*\))$/ -/** Keeps a trailing "(hint)" out of the uppercase transform; for any uppercased label. */ +/** Keeps a trailing "(hint)" out of an uppercase transform; for any uppercased label. */ export const withHint = ( h: HtmlBuilder, child: Html | string, diff --git a/packages/views/src/ui/field.ts b/packages/views/src/ui/field.ts index a455267fcd..5c7e2ae272 100644 --- a/packages/views/src/ui/field.ts +++ b/packages/views/src/ui/field.ts @@ -90,7 +90,7 @@ export const field = ( export type FieldIds = Readonly<{ control: string; label: string; error: string; description?: string }> // The eyebrow look on a field label (a dense editor rail). -const EYEBROW_LABEL = cn(eyebrowVariants({ variant: "label" }), "sm:leading-normal") +const EYEBROW_LABEL = cn(eyebrowVariants({ variant: "label" }), "sm:text-xs sm:leading-normal") /** Base UI `Field.Label`, wired to the control by id. */ export const fieldLabel = ( diff --git a/packages/views/src/ui/filter-chip.styles.ts b/packages/views/src/ui/filter-chip.styles.ts index c60d9f3d9f..0b1659710f 100644 --- a/packages/views/src/ui/filter-chip.styles.ts +++ b/packages/views/src/ui/filter-chip.styles.ts @@ -28,4 +28,4 @@ export const filterChipPressedBorderStyles = { export const filterChipDotOffStyles = "opacity-50" -export const filterChipCountStyles = "font-mono text-2xs text-muted-foreground tabular-nums" +export const filterChipCountStyles = "text-2xs text-muted-foreground tabular-nums" diff --git a/packages/views/src/ui/input-group.styles.ts b/packages/views/src/ui/input-group.styles.ts index d356d6cd22..11449cce4f 100644 --- a/packages/views/src/ui/input-group.styles.ts +++ b/packages/views/src/ui/input-group.styles.ts @@ -22,7 +22,7 @@ export const inputGroupAddonVariants = cva( ) export const inputGroupStyles = - "relative inline-flex w-full min-w-0 items-center rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-control has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a2 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive-a4 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-ui/5 dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a3 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-md-inset" + "relative inline-flex w-full min-w-0 items-center rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-control has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a2 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive-a4 has-autofill:bg-foreground/4 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-ui dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive-a3 has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-md-inset" export const inputGroupTextStyles = "line-clamp-1 flex items-center gap-2 whitespace-nowrap text-muted-foreground leading-none in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-mx-0.5" diff --git a/packages/views/src/ui/input.styles.ts b/packages/views/src/ui/input.styles.ts index aca34bffea..038b525c3b 100644 --- a/packages/views/src/ui/input.styles.ts +++ b/packages/views/src/ui/input.styles.ts @@ -7,7 +7,7 @@ export const inputControlLayoutStyles = "relative inline-flex w-full" /** Border, background, shadow and focus ring — the part `unstyled` removes. */ export const inputControlChromeStyles = - "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-control has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] sm:text-ui/5 dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" + "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-control has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-autofill:bg-foreground/4 has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] sm:text-ui dark:bg-input/32 dark:has-autofill:bg-foreground/8 dark:has-aria-invalid:ring-destructive-a3" export const inputStyles = "h-8.5 w-full min-w-0 rounded-[inherit] px-[calc(--spacing(3)-1px)] leading-8.5 outline-none [transition:background-color_5000000s_ease-in-out_0s] placeholder:text-foreground-subtle sm:h-7.5 sm:leading-7.5" diff --git a/packages/views/src/ui/select.styles.ts b/packages/views/src/ui/select.styles.ts index 166c6eb101..ee8b1b7845 100644 --- a/packages/views/src/ui/select.styles.ts +++ b/packages/views/src/ui/select.styles.ts @@ -1,7 +1,7 @@ import { cva } from "class-variance-authority" export const selectTriggerVariants = cva( - "relative inline-flex min-h-9 min-w-36 select-none items-center justify-between gap-2 rounded-lg border border-input bg-background not-dark:bg-clip-padding px-[calc(--spacing(3)-1px)] text-left text-base text-foreground shadow-raised outline-none ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-control pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive-a4 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive-a2 data-disabled:pointer-events-none data-disabled:opacity-64 sm:min-h-8 sm:text-ui/5 dark:bg-input/32 dark:aria-invalid:ring-destructive-a3 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none", + "relative inline-flex min-h-9 min-w-36 select-none items-center justify-between gap-2 rounded-lg border border-input bg-background not-dark:bg-clip-padding px-[calc(--spacing(3)-1px)] text-left text-base text-foreground shadow-raised outline-none ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-control pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive-a4 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive-a2 data-disabled:pointer-events-none data-disabled:opacity-64 sm:min-h-8 sm:text-ui dark:bg-input/32 dark:aria-invalid:ring-destructive-a3 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none", { defaultVariants: { size: "default", @@ -40,7 +40,7 @@ export const selectScrollDownArrowStyles = "bottom-0 z-50 flex h-6 w-full cursor-default items-center justify-center before:pointer-events-none before:absolute before:inset-x-px before:bottom-px before:h-[200%] before:rounded-b-lg-inset before:bg-linear-to-t before:from-50% before:from-popover" export const selectItemStyles = - "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" + "grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-ui [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:shrink-0" export const selectItemIndicatorStyles = "col-start-1" diff --git a/packages/views/src/ui/sidebar.styles.ts b/packages/views/src/ui/sidebar.styles.ts index 58ff1b0a81..aa0da1a205 100644 --- a/packages/views/src/ui/sidebar.styles.ts +++ b/packages/views/src/ui/sidebar.styles.ts @@ -10,7 +10,7 @@ export const sidebarMenuButtonVariants = cva( variants: { size: { default: "h-8 text-ui", - lg: "h-12 text-xs group-data-[collapsible=icon]:p-0!", + lg: "h-12 text-ui group-data-[collapsible=icon]:p-0!", sm: "h-7 text-ui", }, variant: { diff --git a/packages/views/src/ui/tabs.styles.ts b/packages/views/src/ui/tabs.styles.ts index 5e869c0e81..e4ad4f194c 100644 --- a/packages/views/src/ui/tabs.styles.ts +++ b/packages/views/src/ui/tabs.styles.ts @@ -19,6 +19,6 @@ export const tabsIndicatorUnderlineStyles = export const tabsIndicatorDefaultStyles = "-z-1 rounded-md bg-background shadow-raised dark:bg-input" export const tabsTabStyles = - "relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] font-medium text-base outline-none hover:text-muted-foreground active:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-foreground data-disabled:opacity-64 sm:h-8 sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0" + "relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] font-medium text-base outline-none hover:text-muted-foreground active:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-foreground data-disabled:opacity-64 sm:h-8 sm:text-ui [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0" export const tabsPanelStyles = "flex-1 outline-none" diff --git a/packages/views/src/ui/textarea.styles.ts b/packages/views/src/ui/textarea.styles.ts index 9cc6c72c76..470fd38ea8 100644 --- a/packages/views/src/ui/textarea.styles.ts +++ b/packages/views/src/ui/textarea.styles.ts @@ -11,7 +11,7 @@ export const textareaControlLayoutStyles = "relative inline-flex w-full" /** Border, background, shadow and focus ring — the part `unstyled` removes. */ export const textareaControlChromeStyles = - "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-control sm:text-ui/5 dark:bg-input/32 dark:has-aria-invalid:ring-destructive-a3" + "rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base text-foreground shadow-raised ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive-a2 has-aria-invalid:border-destructive-a4 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-control sm:text-ui dark:bg-input/32 dark:has-aria-invalid:ring-destructive-a3" export const textareaStyles = "field-sizing-content min-h-17.5 w-full rounded-[inherit] px-[calc(--spacing(3)-1px)] py-[calc(--spacing(1.5)-1px)] outline-none max-sm:min-h-20.5" diff --git a/packages/views/src/ui/toggle.styles.ts b/packages/views/src/ui/toggle.styles.ts index a5c6dad7f9..b1a5850539 100644 --- a/packages/views/src/ui/toggle.styles.ts +++ b/packages/views/src/ui/toggle.styles.ts @@ -2,7 +2,7 @@ import { cva } from "class-variance-authority" import { cn } from "@maple/ui/lib/utils" export const toggleVariants = cva( - "relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base text-foreground outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent active:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-pressed:bg-input/64 data-pressed:text-accent-foreground sm:text-ui/5 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", + "relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base text-foreground outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-lg-inset pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent active:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-pressed:bg-input/64 data-pressed:text-accent-foreground sm:text-ui [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", { // Segments carry text, not a lone icon, so they need more horizontal room // than the base sizes give: those are tuned for square icon toggles, where diff --git a/packages/views/src/ui/values.ts b/packages/views/src/ui/values.ts index 58755acbcc..ec28255705 100644 --- a/packages/views/src/ui/values.ts +++ b/packages/views/src/ui/values.ts @@ -56,7 +56,7 @@ export const latencyValue = ( return h.span( [ h.Title(latencyLevelLabel(level)), - h.Class(cn("font-mono tabular-nums", LATENCY_TEXT_TONE[level], options.className)), + h.Class(cn("tabular-nums", LATENCY_TEXT_TONE[level], options.className)), ], measure(h, formatLatency(options.ms), LATENCY_UNIT[level]), ) @@ -70,7 +70,7 @@ export const errorRateValue = ( [ h.Class( cn( - "font-mono tabular-nums", + "tabular-nums", ERROR_RATE_TEXT[errorRateLevel(options.rate)], options.className, ),