diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx index 06d0d287411..9b35012f1c4 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx +++ b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-logs/landing-preview-logs.tsx @@ -236,10 +236,7 @@ export function LandingPreviewLogs() { {COL_HEADERS.map(({ key, label }) => ( - + ) diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/column-header-menu.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/column-header-menu.tsx index 8d775e8b8ac..e2834ab3c7d 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/column-header-menu.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/column-header-menu.tsx @@ -162,8 +162,9 @@ export const ColumnHeaderMenu = React.memo(function ColumnHeaderMenu({ const ghost = document.createElement('div') ghost.textContent = ghostLabel + ghost.className = 'text-small' ghost.style.cssText = - 'position:absolute;top:-9999px;padding:4px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;font-size:13px;font-weight:500;white-space:nowrap;color:var(--text-primary)' + 'position:absolute;top:-9999px;padding:4px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;white-space:nowrap;color:var(--text-primary)' document.body.appendChild(ghost) e.dataTransfer.setDragImage(ghost, ghost.offsetWidth / 2, ghost.offsetHeight / 2) requestAnimationFrame(() => ghost.parentNode?.removeChild(ghost)) @@ -284,7 +285,7 @@ export const ColumnHeaderMenu = React.memo(function ColumnHeaderMenu({ if (e.key === 'Escape') onRenameCancel() }} onBlur={onRenameSubmit} - className='ml-1.5 min-w-0 flex-1 border-0 bg-transparent p-0 font-medium text-[var(--text-primary)] text-small outline-none focus:outline-none focus:ring-0' + className='ml-1.5 min-w-0 flex-1 border-0 bg-transparent p-0 text-[var(--text-primary)] text-small outline-none focus:outline-none focus:ring-0' /> ) : readOnly ? ( @@ -295,7 +296,7 @@ export const ColumnHeaderMenu = React.memo(function ColumnHeaderMenu({ blockIconInfo={sourceInfo?.blockIconInfo} blockMissing={blockMissing} /> - + {column.workflowGroupId ? column.headerLabel : column.name} @@ -313,7 +314,7 @@ export const ColumnHeaderMenu = React.memo(function ColumnHeaderMenu({ blockIconInfo={sourceInfo?.blockIconInfo} blockMissing={blockMissing} /> - + {column.workflowGroupId ? column.headerLabel : column.name} diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/workflow-group-meta-cell.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/workflow-group-meta-cell.tsx index 031a9c8a6f2..bf09f73c3eb 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/workflow-group-meta-cell.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/workflow-group-meta-cell.tsx @@ -368,8 +368,9 @@ export function WorkflowGroupMetaCell({ const ghost = document.createElement('div') ghost.textContent = name + ghost.className = 'text-xs' ghost.style.cssText = - 'position:absolute;top:-9999px;padding:4px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;font-size:13px;font-weight:500;white-space:nowrap;color:var(--text-primary)' + 'position:absolute;top:-9999px;padding:4px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;white-space:nowrap;color:var(--text-primary)' document.body.appendChild(ghost) e.dataTransfer.setDragImage(ghost, ghost.offsetWidth / 2, ghost.offsetHeight / 2) requestAnimationFrame(() => ghost.parentNode?.removeChild(ghost)) @@ -438,9 +439,7 @@ export function WorkflowGroupMetaCell({ ) : ( )} - - {name} - + {name} {onRunColumn && ( diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx index bcca45899c4..c37bf812c6e 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/table-grid.tsx @@ -1687,11 +1687,10 @@ export function TableGrid({ host.appendChild(measure) try { - measure.className = 'font-medium text-small' + measure.className = 'text-small' measure.textContent = column.headerLabel maxWidth = Math.max(maxWidth, measure.getBoundingClientRect().width + 57) - measure.className = 'text-small' for (const row of currentRows) { const val = row.data[column.key] if (val == null) continue diff --git a/packages/emcn/src/AGENTS.md b/packages/emcn/src/AGENTS.md index 8f8497c5913..c7bfda44b81 100644 --- a/packages/emcn/src/AGENTS.md +++ b/packages/emcn/src/AGENTS.md @@ -6,6 +6,6 @@ These rules apply to `packages/emcn/**`. - Use Radix UI primitives for accessibility where applicable. - Use CVA when a component has 2+ variants; use direct `className` composition for single-style components. - Export both the component and its variants helper when using CVA. -- Keep tokens consistent with the chip-pill canonical look: normal font-weight, `--text-body` value text, `--text-icon` icons at `size-[14px]`, `rounded-lg`. Components own their exact tokens (e.g. `Button` uses `rounded-[5px]`+`font-medium`). See `.claude/rules/emcn-components.md` for the full chip-chrome reference. +- Keep tokens consistent with the chip-pill canonical look: normal font-weight, `--text-body` value text, `--text-icon` icons at `size-[14px]`, `rounded-lg`. Components own their exact geometry tokens (e.g. `Button` uses `rounded-[5px]`), but never their own font-weight — every primitive inherits the document 400, and a weight class is reached for only to step deliberately up. See `.claude/rules/emcn-components.md` for the full chip-chrome reference. - Prefer `transition-colors` for interactive hover and active states. - Use TSDoc when documenting public components or APIs. diff --git a/packages/emcn/src/components/avatar/avatar.tsx b/packages/emcn/src/components/avatar/avatar.tsx index a511b7cb089..85ebaa522c8 100644 --- a/packages/emcn/src/components/avatar/avatar.tsx +++ b/packages/emcn/src/components/avatar/avatar.tsx @@ -133,6 +133,11 @@ AvatarImage.displayName = 'AvatarImage' /** * Fallback component for Avatar. Displays initials or icon when image is unavailable. + * + * Carries the package's only hardcoded `font-medium`, and deliberately: one or + * two capitals at `text-xs` on a filled disc are a glyph, not running text, and + * need the extra mass to read at avatar sizes. This is the sanctioned "step up + * from body" — every other primitive inherits the document 400. */ const AvatarFallback = React.forwardRef< React.ElementRef, diff --git a/packages/emcn/src/components/badge/badge.tsx b/packages/emcn/src/components/badge/badge.tsx index 7f7cea2c7d4..a7dffc6821b 100644 --- a/packages/emcn/src/components/badge/badge.tsx +++ b/packages/emcn/src/components/badge/badge.tsx @@ -5,41 +5,38 @@ import { cn } from '../../lib/cn' /** Shared base styles for status color badge variants */ const STATUS_BASE = 'gap-1.5 rounded-md' -const badgeVariants = cva( - 'inline-flex items-center font-medium focus:outline-none transition-colors', - { - variants: { - variant: { - default: - 'gap-1 rounded-[40px] border border-[var(--border)] text-[var(--text-secondary)] bg-[var(--surface-4)] hover-hover:text-[var(--text-primary)] hover-hover:border-[var(--border-1)] hover-hover:bg-[var(--surface-6)] dark:hover-hover:bg-[var(--surface-5)]', - outline: - 'gap-1 rounded-[40px] border border-[var(--border-1)] bg-transparent text-[var(--text-secondary)] hover-hover:text-[var(--text-primary)] hover-hover:bg-[var(--surface-5)] dark:hover-hover:bg-transparent dark:hover-hover:border-[var(--surface-6)]', - type: 'gap-1 rounded-[40px] border border-[var(--border)] text-[var(--text-secondary)] bg-[var(--surface-4)] dark:bg-[var(--surface-6)]', - green: `${STATUS_BASE} bg-[var(--badge-success-bg)] text-[var(--badge-success-text)]`, - red: `${STATUS_BASE} bg-[var(--badge-error-bg)] text-[var(--badge-error-text)]`, - gray: `${STATUS_BASE} bg-[var(--badge-gray-bg)] text-[var(--badge-gray-text)]`, - blue: `${STATUS_BASE} bg-[var(--badge-blue-bg)] text-[var(--badge-blue-text)]`, - 'blue-secondary': `${STATUS_BASE} bg-[var(--badge-blue-secondary-bg)] text-[var(--badge-blue-secondary-text)]`, - purple: `${STATUS_BASE} bg-[var(--badge-purple-bg)] text-[var(--badge-purple-text)]`, - orange: `${STATUS_BASE} bg-[var(--badge-orange-bg)] text-[var(--badge-orange-text)]`, - amber: `${STATUS_BASE} bg-[var(--badge-amber-bg)] text-[var(--badge-amber-text)]`, - teal: `${STATUS_BASE} bg-[var(--badge-teal-bg)] text-[var(--badge-teal-text)]`, - cyan: `${STATUS_BASE} bg-[var(--badge-cyan-bg)] text-[var(--badge-cyan-text)]`, - pink: `${STATUS_BASE} bg-[var(--badge-pink-bg)] text-[var(--badge-pink-text)]`, - 'gray-secondary': `${STATUS_BASE} bg-[var(--surface-4)] text-[var(--text-secondary)]`, - }, - size: { - sm: 'px-[7px] py-[1px] text-xs', - md: 'px-[9px] py-0.5 text-caption', - lg: 'px-[9px] py-[2.25px] text-caption', - }, +const badgeVariants = cva('inline-flex items-center focus:outline-none transition-colors', { + variants: { + variant: { + default: + 'gap-1 rounded-[40px] border border-[var(--border)] text-[var(--text-secondary)] bg-[var(--surface-4)] hover-hover:text-[var(--text-primary)] hover-hover:border-[var(--border-1)] hover-hover:bg-[var(--surface-6)] dark:hover-hover:bg-[var(--surface-5)]', + outline: + 'gap-1 rounded-[40px] border border-[var(--border-1)] bg-transparent text-[var(--text-secondary)] hover-hover:text-[var(--text-primary)] hover-hover:bg-[var(--surface-5)] dark:hover-hover:bg-transparent dark:hover-hover:border-[var(--surface-6)]', + type: 'gap-1 rounded-[40px] border border-[var(--border)] text-[var(--text-secondary)] bg-[var(--surface-4)] dark:bg-[var(--surface-6)]', + green: `${STATUS_BASE} bg-[var(--badge-success-bg)] text-[var(--badge-success-text)]`, + red: `${STATUS_BASE} bg-[var(--badge-error-bg)] text-[var(--badge-error-text)]`, + gray: `${STATUS_BASE} bg-[var(--badge-gray-bg)] text-[var(--badge-gray-text)]`, + blue: `${STATUS_BASE} bg-[var(--badge-blue-bg)] text-[var(--badge-blue-text)]`, + 'blue-secondary': `${STATUS_BASE} bg-[var(--badge-blue-secondary-bg)] text-[var(--badge-blue-secondary-text)]`, + purple: `${STATUS_BASE} bg-[var(--badge-purple-bg)] text-[var(--badge-purple-text)]`, + orange: `${STATUS_BASE} bg-[var(--badge-orange-bg)] text-[var(--badge-orange-text)]`, + amber: `${STATUS_BASE} bg-[var(--badge-amber-bg)] text-[var(--badge-amber-text)]`, + teal: `${STATUS_BASE} bg-[var(--badge-teal-bg)] text-[var(--badge-teal-text)]`, + cyan: `${STATUS_BASE} bg-[var(--badge-cyan-bg)] text-[var(--badge-cyan-text)]`, + pink: `${STATUS_BASE} bg-[var(--badge-pink-bg)] text-[var(--badge-pink-text)]`, + 'gray-secondary': `${STATUS_BASE} bg-[var(--surface-4)] text-[var(--text-secondary)]`, }, - defaultVariants: { - variant: 'default', - size: 'md', + size: { + sm: 'px-[7px] py-[1px] text-xs', + md: 'px-[9px] py-0.5 text-caption', + lg: 'px-[9px] py-[2.25px] text-caption', }, - } -) + }, + defaultVariants: { + variant: 'default', + size: 'md', + }, +}) /** Color variants that support dot indicators */ const STATUS_VARIANTS = [ diff --git a/packages/emcn/src/components/button-group/button-group.tsx b/packages/emcn/src/components/button-group/button-group.tsx index ca7056669d6..d1ead7aaef9 100644 --- a/packages/emcn/src/components/button-group/button-group.tsx +++ b/packages/emcn/src/components/button-group/button-group.tsx @@ -100,7 +100,7 @@ function ButtonGroup({ } const buttonGroupItemVariants = cva( - 'inline-flex items-center justify-center font-medium transition-colors outline-none focus:outline-none focus-visible:outline-none disabled:pointer-events-none disabled:opacity-70 px-2 py-1 text-caption border', + 'inline-flex items-center justify-center transition-colors outline-none focus:outline-none focus-visible:outline-none disabled:pointer-events-none disabled:opacity-70 px-2 py-1 text-caption border', { variants: { active: { diff --git a/packages/emcn/src/components/button/button.tsx b/packages/emcn/src/components/button/button.tsx index e1916bda1e4..1893a682403 100644 --- a/packages/emcn/src/components/button/button.tsx +++ b/packages/emcn/src/components/button/button.tsx @@ -21,7 +21,7 @@ import { cn } from '../../lib/cn' * @example */ const buttonVariants = cva( - 'inline-flex items-center justify-center font-medium transition-colors disabled:pointer-events-none disabled:opacity-70 outline-none focus:outline-none focus-visible:outline-none rounded-[5px]', + 'inline-flex items-center justify-center transition-colors disabled:pointer-events-none disabled:opacity-70 outline-none focus:outline-none focus-visible:outline-none rounded-[5px]', { variants: { variant: { diff --git a/packages/emcn/src/components/chip-combobox/chip-combobox.tsx b/packages/emcn/src/components/chip-combobox/chip-combobox.tsx index b766225e8ed..9650a9892f7 100644 --- a/packages/emcn/src/components/chip-combobox/chip-combobox.tsx +++ b/packages/emcn/src/components/chip-combobox/chip-combobox.tsx @@ -11,8 +11,9 @@ import { Combobox, type ComboboxProps } from '../combobox/combobox' * Reuses 100% of `Combobox` — search, editable entry, multi-select, groups, * async loading, per-option icons, and `overlayContent` all work unchanged. * Only the trigger chrome is overridden (the `className` merges last in - * `Combobox`, so `rounded-lg` / height / dark surface and the chip typography - * — normal weight, `--text-body` — win over the heavier combobox defaults). + * `Combobox`, so `rounded-lg` / height / dark surface and the chip `--text-body` + * color win over the combobox defaults). Weight is no longer overridden here — + * `Combobox` inherits the document's 400, which is already the chip weight. * The muted placeholder still applies because the combobox tints the inner * label span with `--text-muted` independently of the trigger className. * @@ -27,7 +28,7 @@ export function ChipCombobox({ className, ...props }: ComboboxProps) { diff --git a/packages/emcn/src/components/chip-modal/chip-modal.tsx b/packages/emcn/src/components/chip-modal/chip-modal.tsx index 85418066f65..4dbb0ab3e10 100644 --- a/packages/emcn/src/components/chip-modal/chip-modal.tsx +++ b/packages/emcn/src/components/chip-modal/chip-modal.tsx @@ -623,10 +623,7 @@ function ChipModalField(props: ChipModalFieldProps) { return (
-
diff --git a/packages/emcn/src/components/combobox/combobox.tsx b/packages/emcn/src/components/combobox/combobox.tsx index 16c361c5bf3..7cf58e0187c 100644 --- a/packages/emcn/src/components/combobox/combobox.tsx +++ b/packages/emcn/src/components/combobox/combobox.tsx @@ -21,7 +21,7 @@ import { Input } from '../input/input' import { Popover, PopoverAnchor, PopoverContent, PopoverScrollArea } from '../popover/popover' const comboboxVariants = cva( - 'flex w-full rounded-sm border border-[var(--border-1)] bg-[var(--surface-5)] px-2 font-sans font-medium text-[var(--text-primary)] placeholder:text-[var(--text-muted)] outline-none disabled:cursor-not-allowed disabled:opacity-50', + 'flex w-full rounded-sm border border-[var(--border-1)] bg-[var(--surface-5)] px-2 font-sans text-[var(--text-primary)] placeholder:text-[var(--text-muted)] outline-none disabled:cursor-not-allowed disabled:opacity-50', { variants: { variant: { @@ -572,7 +572,7 @@ const Combobox = memo( @@ -797,7 +797,7 @@ const Combobox = memo( !option.disabled && setHighlightedIndex(globalIndex) } className={cn( - 'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-1.5 font-medium font-sans', + 'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-1.5 font-sans', size === 'sm' ? 'py-[5px] text-caption' : 'py-1.5 text-sm', 'hover-hover:bg-[var(--surface-active)]', (isHighlighted || isSelected) && 'bg-[var(--surface-active)]', @@ -837,7 +837,7 @@ const Combobox = memo( }} onMouseEnter={() => setHighlightedIndex(-1)} className={cn( - 'relative flex cursor-pointer select-none items-center rounded-sm px-1.5 font-medium font-sans', + 'relative flex cursor-pointer select-none items-center rounded-sm px-1.5 font-sans', size === 'sm' ? 'py-[5px] text-caption' : 'py-1.5 text-sm', 'hover-hover:bg-[var(--surface-active)]', !multiSelectValues?.length && 'bg-[var(--surface-active)]' @@ -871,7 +871,7 @@ const Combobox = memo( }} onMouseEnter={() => !option.disabled && setHighlightedIndex(index)} className={cn( - 'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-1.5 font-medium font-sans', + 'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-1.5 font-sans', size === 'sm' ? 'py-[5px] text-caption' : 'py-1.5 text-sm', 'hover-hover:bg-[var(--surface-active)]', (isHighlighted || isSelected) && 'bg-[var(--surface-active)]', diff --git a/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx b/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx index 220c61fb684..c7af01b215b 100644 --- a/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx +++ b/packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx @@ -298,11 +298,7 @@ const DropdownMenuLabel = React.forwardRef< >(({ className, inset, ...props }, ref) => ( )) diff --git a/packages/emcn/src/components/input-otp/input-otp.tsx b/packages/emcn/src/components/input-otp/input-otp.tsx index af5642e0747..a6c5ea82fff 100644 --- a/packages/emcn/src/components/input-otp/input-otp.tsx +++ b/packages/emcn/src/components/input-otp/input-otp.tsx @@ -77,7 +77,7 @@ const InputOTPSlot = React.forwardRef<
diff --git a/packages/emcn/src/components/label/label.tsx b/packages/emcn/src/components/label/label.tsx index a4623bca65a..412f12e8dc7 100644 --- a/packages/emcn/src/components/label/label.tsx +++ b/packages/emcn/src/components/label/label.tsx @@ -25,7 +25,7 @@ function Label({ className, ...props }: LabelProps) { return ( - + {children} @@ -825,7 +825,7 @@ const ModalTabsTrigger = React.forwardRef< ( return (
)} {folderTitle && !onFolderSelect && ( -
+
{folderTitle}
)} @@ -1173,7 +1167,7 @@ const PopoverSearch = React.forwardRef( (function Prog
- - {title} - + {title} {meta != null && ( {meta} )} diff --git a/packages/emcn/src/components/tab-strip/tab-strip.tsx b/packages/emcn/src/components/tab-strip/tab-strip.tsx index d1fb18c7d6e..f6f6e4e90e5 100644 --- a/packages/emcn/src/components/tab-strip/tab-strip.tsx +++ b/packages/emcn/src/components/tab-strip/tab-strip.tsx @@ -180,7 +180,7 @@ function Tab({ aria-current={tab.active ? 'page' : undefined} aria-label={tab.pinned ? tab.title : undefined} className={cn( - 'h-[30px] w-full select-none rounded-b-none border border-transparent border-b-0 bg-transparent py-0 font-normal text-caption', + 'h-[30px] w-full select-none rounded-b-none border border-transparent border-b-0 bg-transparent py-0 text-caption', tab.pinned ? 'justify-center px-0' : 'justify-start gap-1.5 px-2', closeable && !tab.pinned && 'pr-7', tab.active && diff --git a/packages/emcn/src/components/table/table.tsx b/packages/emcn/src/components/table/table.tsx index 498c0067c4f..0ba67ba490f 100644 --- a/packages/emcn/src/components/table/table.tsx +++ b/packages/emcn/src/components/table/table.tsx @@ -54,7 +54,7 @@ const TableFooter = React.forwardRef< tr]:last:border-b-0', + 'border-t bg-[color-mix(in_srgb,var(--surface-3)_50%,transparent)] [&>tr]:last:border-b-0', className )} {...props} @@ -80,7 +80,7 @@ const TableHead = React.forwardRef< [role=checkbox]]:translate-y-[2px]', + 'h-10 px-3 py-2 text-left align-middle text-[var(--text-secondary)] [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]', className )} {...props} diff --git a/packages/emcn/src/components/tag-input/tag-input.tsx b/packages/emcn/src/components/tag-input/tag-input.tsx index 6cee52f3be3..3e5a99eddc9 100644 --- a/packages/emcn/src/components/tag-input/tag-input.tsx +++ b/packages/emcn/src/components/tag-input/tag-input.tsx @@ -180,7 +180,7 @@ const TagInputTag = React.memo(function TagInputTag({ onRightIconClick={disabled ? undefined : handleRemove} rightIconLabel={`Remove ${item.value}`} > - + {item.value} {showError && {item.error}} @@ -423,7 +423,7 @@ const TagInput = React.forwardRef(
{inputValue.trim() && (