fix: enable no-deprecated-classes tailwind lint rule (#9417)

## Summary

Enable `better-tailwindcss/no-deprecated-classes` lint rule and auto-fix
all 103 violations across 65 files. First PR in a stacked series for
#9300.

## Changes

- **What**: Replace deprecated Tailwind v3 classes with v4 equivalents:
  - `rounded` → `rounded-sm` (85)
  - `flex-shrink-0` → `shrink-0` (16)
  - `flex-grow` → `grow` (2)
- Enable `no-deprecated-classes` as `'error'` in eslint config
- Update one test asserting on `'rounded'` class string

## Review Focus

Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes (Tailwind v4 aliases these classes
identically).

Fixes #9300 (partial — 1 of 3 rules)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9417-fix-enable-no-deprecated-classes-tailwind-lint-rule-31a6d73d3650819eaef4cf8ad84fb186)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
This commit is contained in:
Christian Byrne
2026-03-04 23:41:23 -08:00
committed by GitHub
parent 7cd11f0da5
commit 493b1e42aa
66 changed files with 107 additions and 103 deletions

View File

@@ -19,7 +19,7 @@
<div
v-for="command in subcategoryCommands"
:key="command.id"
class="shortcut-item flex items-center justify-between rounded py-2 transition-colors duration-200"
class="shortcut-item flex items-center justify-between rounded-sm py-2 transition-colors duration-200"
>
<div class="shortcut-info grow pr-4">
<div class="shortcut-name text-sm font-medium">
@@ -35,7 +35,7 @@
<span
v-for="key in command.keybinding!.combo.getKeySequences()"
:key="key"
class="key-badge min-w-6 rounded bg-muted-background px-2 py-1 text-center font-mono text-xs"
class="key-badge min-w-6 rounded-sm bg-muted-background px-2 py-1 text-center font-mono text-xs"
>
{{ formatKey(key) }}
</span>

View File

@@ -2,7 +2,7 @@
<span
:class="
cn(
'flex items-center gap-1 rounded border px-1.5 py-0.5 text-xxs',
'flex items-center gap-1 rounded-sm border px-1.5 py-0.5 text-xxs',
textColorClass
)
"

View File

@@ -2,7 +2,7 @@
<div class="image-upload-wrapper">
<div class="flex items-center gap-2">
<div
class="preview-box flex h-16 w-16 items-center justify-center rounded border p-2"
class="preview-box flex h-16 w-16 items-center justify-center rounded-sm border p-2"
:class="{ 'bg-base-background': !modelValue }"
>
<img

View File

@@ -117,7 +117,7 @@ watchDebounced(
const wrapperStyle = computed(() => {
if (showBorder) {
return cn(
'rounded p-2 border border-solid border-border-default box-border',
'rounded-sm p-2 border border-solid border-border-default box-border',
isLarge.value ? 'h-10' : 'h-8'
)
}

View File

@@ -27,7 +27,7 @@
<button
:class="
cn(
'flex size-6 shrink-0 cursor-pointer items-center justify-center rounded border-none bg-transparent text-muted-foreground hover:text-foreground',
'flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-sm border-none bg-transparent text-muted-foreground hover:text-foreground',
'opacity-0 group-hover/tree-node:opacity-100'
)
"

View File

@@ -133,7 +133,7 @@
<!-- Title -->
<span
v-if="isLoading"
class="inline-block h-8 w-48 animate-pulse rounded bg-dialog-surface"
class="inline-block h-8 w-48 animate-pulse rounded-sm bg-dialog-surface"
></span>
<!-- Template Cards Grid -->
@@ -164,10 +164,10 @@
<CardBottom>
<div class="px-4 py-3">
<div
class="mb-2 h-6 animate-pulse rounded bg-dialog-surface"
class="mb-2 h-6 animate-pulse rounded-sm bg-dialog-surface"
></div>
<div
class="h-4 animate-pulse rounded bg-dialog-surface"
class="h-4 animate-pulse rounded-sm bg-dialog-surface"
></div>
</div>
</CardBottom>
@@ -349,10 +349,10 @@
<CardBottom>
<div class="px-4 py-3">
<div
class="mb-2 h-6 animate-pulse rounded bg-dialog-surface"
class="mb-2 h-6 animate-pulse rounded-sm bg-dialog-surface"
></div>
<div
class="h-4 animate-pulse rounded bg-dialog-surface"
class="h-4 animate-pulse rounded-sm bg-dialog-surface"
></div>
</div>
</CardBottom>

View File

@@ -68,7 +68,7 @@
@keydown.space.prevent="toggleSelectAll"
>
<div
class="flex size-4 shrink-0 items-center justify-center rounded p-0.5 transition-all duration-200"
class="flex size-4 shrink-0 items-center justify-center rounded-sm p-0.5 transition-all duration-200"
:class="
isAllSelected || isSomeSelected
? 'bg-primary-background'
@@ -113,7 +113,7 @@
@keydown.space.prevent="toggleNode(node.label)"
>
<div
class="flex size-4 shrink-0 items-center justify-center rounded p-0.5 transition-all duration-200"
class="flex size-4 shrink-0 items-center justify-center rounded-sm p-0.5 transition-all duration-200"
:class="
replacedTypes.has(node.label) || selectedTypes.has(node.label)
? 'bg-primary-background'

View File

@@ -12,7 +12,7 @@
}}
</h2>
<button
class="cursor-pointer rounded border-none bg-transparent p-0 text-muted-foreground transition-colors hover:text-base-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-secondary-foreground"
class="cursor-pointer rounded-sm border-none bg-transparent p-0 text-muted-foreground transition-colors hover:text-base-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-secondary-foreground"
@click="() => handleClose()"
>
<i class="icon-[lucide--x] size-6" />

View File

@@ -10,7 +10,7 @@
{{ $t('subscription.cancelDialog.title') }}
</h2>
<button
class="cursor-pointer rounded border-none bg-transparent p-0 text-muted-foreground transition-colors hover:text-base-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-secondary-foreground"
class="cursor-pointer rounded-sm border-none bg-transparent p-0 text-muted-foreground transition-colors hover:text-base-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-secondary-foreground"
:aria-label="$t('g.close')"
:disabled="isLoading"
@click="onClose"

View File

@@ -40,7 +40,7 @@
</div>
<div
class="flex cursor-pointer items-center justify-between rounded px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
class="flex cursor-pointer items-center justify-between rounded-sm px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
@click="setMode('hand')"
>
<div class="flex items-center gap-2">

View File

@@ -16,7 +16,7 @@
<span class="flex-1">{{ item.label }}</span>
<span
v-if="item.shortcut"
class="flex h-3.5 min-w-3.5 items-center justify-center rounded bg-interface-menu-keybind-surface-default px-1 py-0 text-xs"
class="flex h-3.5 min-w-3.5 items-center justify-center rounded-sm bg-interface-menu-keybind-surface-default px-1 py-0 text-xs"
>
{{ item.shortcut }}
</span>

View File

@@ -10,7 +10,7 @@
>
<div class="flex flex-col gap-1">
<div
class="flex cursor-pointer items-center justify-between rounded px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
class="flex cursor-pointer items-center justify-between rounded-sm px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
@mousedown="startRepeat('Comfy.Canvas.ZoomIn')"
@mouseup="stopRepeat"
@mouseleave="stopRepeat"
@@ -22,7 +22,7 @@
</div>
<div
class="flex cursor-pointer items-center justify-between rounded px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
class="flex cursor-pointer items-center justify-between rounded-sm px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
@mousedown="startRepeat('Comfy.Canvas.ZoomOut')"
@mouseup="stopRepeat"
@mouseleave="stopRepeat"
@@ -34,7 +34,7 @@
</div>
<div
class="flex cursor-pointer items-center justify-between rounded px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
class="flex cursor-pointer items-center justify-between rounded-sm px-3 py-2 text-sm hover:bg-node-component-surface-hovered"
@click="executeCommand('Comfy.Canvas.FitView')"
>
<span class="font-medium">{{ $t('zoomControls.zoomToFit') }}</span>
@@ -45,7 +45,7 @@
<div
ref="zoomInputContainer"
class="zoomInputContainer flex items-center gap-1 rounded bg-input-surface p-2"
class="zoomInputContainer flex items-center gap-1 rounded-sm bg-input-surface p-2"
>
<InputNumber
:default-value="canvasStore.appScalePercentage"
@@ -59,7 +59,7 @@
@input="applyZoom"
@keyup.enter="applyZoom"
/>
<span class="flex-shrink-0 text-sm text-text-primary">%</span>
<span class="shrink-0 text-sm text-text-primary">%</span>
</div>
</div>
</div>

View File

@@ -31,7 +31,7 @@
:key="subOption.label"
:class="
cn(
'hover:bg-secondary-background-hover rounded cursor-pointer',
'hover:bg-secondary-background-hover rounded-sm cursor-pointer',
isColorSubmenu
? 'w-7 h-7 flex items-center justify-center'
: 'flex items-center gap-2 px-3 py-1.5 text-sm',
@@ -51,9 +51,9 @@
<template v-else-if="!subOption.color">
<i
v-if="isShapeSelected(subOption)"
class="icon-[lucide--check] size-4 flex-shrink-0"
class="icon-[lucide--check] size-4 shrink-0"
/>
<div v-else class="w-4 flex-shrink-0" />
<div v-else class="w-4 shrink-0" />
<span>{{ subOption.label }}</span>
</template>
</div>

View File

@@ -102,7 +102,7 @@
<article
v-for="release in releaseStore.recentReleases"
:key="release.id || release.version"
class="release-menu-item flex h-12 min-h-6 cursor-pointer items-center gap-2 self-stretch rounded p-2 transition-colors hover:bg-interface-menu-component-surface-hovered"
class="release-menu-item flex h-12 min-h-6 cursor-pointer items-center gap-2 self-stretch rounded-sm p-2 transition-colors hover:bg-interface-menu-component-surface-hovered"
role="button"
tabindex="0"
@click="onReleaseClick(release)"

View File

@@ -154,7 +154,7 @@
:style="popoverStyle"
>
<div
class="flex size-4 shrink-0 items-center justify-center rounded p-0.5 transition-all duration-200"
class="flex size-4 shrink-0 items-center justify-center rounded-sm p-0.5 transition-all duration-200"
:class="
slotProps.selected
? 'bg-primary-background'

View File

@@ -57,7 +57,7 @@
option: ({ context }: SelectPassThroughMethodOptions<SelectOption>) => ({
class: cn(
// Row layout
'flex items-center justify-between gap-3 px-2 py-3 rounded',
'flex items-center justify-between gap-3 px-2 py-3 rounded-sm',
'hover:bg-secondary-background-hover',
// Add focus state for keyboard navigation
context.focused && 'bg-secondary-background-hover',

View File

@@ -82,7 +82,7 @@
</Button>
</div>
<div
class="col-span-2 mt-2 rounded bg-interface-panel-hover-surface px-4 py-2 text-[0.75rem] leading-normal text-text-secondary"
class="col-span-2 mt-2 rounded-sm bg-interface-panel-hover-surface px-4 py-2 text-[0.75rem] leading-normal text-text-secondary"
>
{{ errorMessageValue }}
</div>

View File

@@ -12,7 +12,7 @@
/>
<div
v-if="timeLabel"
class="absolute bottom-2 left-2 rounded px-2 py-0.5 text-xs text-text-primary"
class="absolute bottom-2 left-2 rounded-sm px-2 py-0.5 text-xs text-text-primary"
:style="{
background: 'rgba(217, 217, 217, 0.40)',
backdropFilter: 'blur(2px)'

View File

@@ -123,7 +123,7 @@ function handleResetToDefault() {
<Button
variant="textonly"
size="unset"
class="w-full flex items-center gap-2 rounded px-3 py-2 text-sm transition-all active:scale-95"
class="w-full flex items-center gap-2 rounded-sm px-3 py-2 text-sm transition-all active:scale-95"
@click="
() => {
handleRename()
@@ -139,7 +139,7 @@ function handleResetToDefault() {
v-if="hasParents"
variant="textonly"
size="unset"
class="w-full flex items-center gap-2 rounded px-3 py-2 text-sm transition-all active:scale-95"
class="w-full flex items-center gap-2 rounded-sm px-3 py-2 text-sm transition-all active:scale-95"
@click="
() => {
if (isShownOnParents) handleHideInput()
@@ -161,7 +161,7 @@ function handleResetToDefault() {
<Button
variant="textonly"
size="unset"
class="w-full flex items-center gap-2 rounded px-3 py-2 text-sm transition-all active:scale-95"
class="w-full flex items-center gap-2 rounded-sm px-3 py-2 text-sm transition-all active:scale-95"
@click="
() => {
handleToggleFavorite()
@@ -183,7 +183,7 @@ function handleResetToDefault() {
v-if="hasDefault"
variant="textonly"
size="unset"
class="w-full flex items-center gap-2 rounded px-3 py-2 text-sm transition-all active:scale-95"
class="w-full flex items-center gap-2 rounded-sm px-3 py-2 text-sm transition-all active:scale-95"
:disabled="isCurrentValueDefault"
@click="
() => {

View File

@@ -136,7 +136,7 @@ function openFullSettings() {
>
<Slider
:model-value="[gridSpacing]"
class="flex-grow text-xs"
class="grow text-xs"
:min="GRID_SIZE_MIN"
:max="GRID_SIZE_MAX"
:step="GRID_SIZE_STEP"

View File

@@ -282,7 +282,7 @@ onMounted(() => {
>
<Button
size="sm"
class="rounded border-none px-3 py-0.5"
class="rounded-sm border-none px-3 py-0.5"
@click.stop="showRecommended"
>
{{ $t('subgraphStore.showRecommended') }}

View File

@@ -27,7 +27,7 @@ function getIcon() {
<div
:class="
cn(
'flex py-1 px-2 break-all rounded items-center gap-1',
'flex py-1 px-2 break-all rounded-sm items-center gap-1',
'bg-node-component-surface',
props.isDraggable && 'hover:ring-1 ring-accent-background',
props.class

View File

@@ -121,7 +121,7 @@ const categoryTree = computed<CategoryNode[]>(() => {
function categoryBtnClass(id: string) {
return cn(
'cursor-pointer border-none bg-transparent rounded px-3 py-2.5 text-left text-sm transition-colors',
'cursor-pointer border-none bg-transparent rounded-sm px-3 py-2.5 text-left text-sm transition-colors',
selectedCategory.value === id
? CATEGORY_SELECTED_CLASS
: CATEGORY_UNSELECTED_CLASS

View File

@@ -6,7 +6,7 @@
:style="{ paddingLeft: `${0.75 + depth * 1.25}rem` }"
:class="
cn(
'w-full cursor-pointer rounded border-none bg-transparent py-2.5 pr-3 text-left text-sm transition-colors',
'w-full cursor-pointer rounded-sm border-none bg-transparent py-2.5 pr-3 text-left text-sm transition-colors',
selectedCategory === node.key
? CATEGORY_SELECTED_CLASS
: CATEGORY_UNSELECTED_CLASS

View File

@@ -11,7 +11,7 @@
<span v-if="showIdName">&nbsp;</span>
<span
v-if="showIdName"
class="rounded bg-secondary-background px-1.5 py-0.5 text-xs text-muted-foreground"
class="rounded-sm bg-secondary-background px-1.5 py-0.5 text-xs text-muted-foreground"
v-html="highlightQuery(nodeDef.name, currentQuery)"
/>
@@ -28,7 +28,7 @@
nodeDef.nodeSource.type !== NodeSourceType.Core &&
nodeDef.nodeSource.type !== NodeSourceType.Unknown
"
class="inline-flex shrink-0 rounded border border-border px-1.5 py-0.5 text-xs bg-base-foreground/5 text-base-foreground/70 mr-0.5"
class="inline-flex shrink-0 rounded-sm border border-border px-1.5 py-0.5 text-xs bg-base-foreground/5 text-base-foreground/70 mr-0.5"
>
{{ nodeDef.nodeSource.displayText }}
</span>
@@ -46,31 +46,31 @@
<div v-if="!showDescription" class="flex items-center gap-1">
<span
v-if="nodeDef.deprecated"
class="rounded bg-red-500/20 px-1.5 py-0.5 text-xs text-red-400"
class="rounded-sm bg-red-500/20 px-1.5 py-0.5 text-xs text-red-400"
>
{{ $t('g.deprecated') }}
</span>
<span
v-if="nodeDef.experimental"
class="rounded bg-blue-500/20 px-1.5 py-0.5 text-xs text-blue-400"
class="rounded-sm bg-blue-500/20 px-1.5 py-0.5 text-xs text-blue-400"
>
{{ $t('g.experimental') }}
</span>
<span
v-if="nodeDef.dev_only"
class="rounded bg-cyan-500/20 px-1.5 py-0.5 text-xs text-cyan-400"
class="rounded-sm bg-cyan-500/20 px-1.5 py-0.5 text-xs text-cyan-400"
>
{{ $t('g.devOnly') }}
</span>
<span
v-if="showNodeFrequency && nodeFrequency > 0"
class="rounded bg-secondary-background px-1.5 py-0.5 text-xs text-muted-foreground"
class="rounded-sm bg-secondary-background px-1.5 py-0.5 text-xs text-muted-foreground"
>
{{ formatNumberWithSuffix(nodeFrequency, { roundToInt: true }) }}
</span>
<span
v-if="nodeDef.nodeSource.type !== NodeSourceType.Unknown"
class="rounded bg-secondary-background px-2 py-0.5 text-sm text-muted-foreground"
class="rounded-sm bg-secondary-background px-2 py-0.5 text-sm text-muted-foreground"
>
{{ nodeDef.nodeSource.displayText }}
</span>

View File

@@ -60,7 +60,7 @@
/>
<span
v-if="item?.comfyCommand?.keybinding"
class="keybinding-tag ml-auto rounded border border-surface p-1 text-xs text-nowrap text-muted"
class="keybinding-tag ml-auto rounded-sm border border-surface p-1 text-xs text-nowrap text-muted"
>
{{ item.comfyCommand.keybinding.combo.toString() }}
</span>

View File

@@ -154,7 +154,7 @@ const getTabTooltipSuffix = (tab: SidebarTabExtension) => {
const isOverflowing = ref(false)
const groupClasses = computed(() =>
cn(
'sidebar-item-group flex flex-col items-center overflow-hidden flex-shrink-0',
'sidebar-item-group flex flex-col items-center overflow-hidden shrink-0',
!isConnected.value && 'rounded-lg shadow-interface pointer-events-auto'
)
)

View File

@@ -35,7 +35,7 @@ const isPending = computed(() => job.status === 'created')
}}</span>
</div>
<div class="flex flex-shrink-0 items-center gap-2">
<div class="flex shrink-0 items-center gap-2">
<template v-if="isFailed">
<i
class="icon-[lucide--circle-alert] size-4 text-destructive-background"

View File

@@ -16,7 +16,7 @@ const { class: className, ...restProps } = defineProps<
:class="
cn(
'relative flex w-full cursor-pointer select-none items-center justify-between',
'gap-3 rounded px-2 py-3 text-sm outline-none',
'gap-3 rounded-sm px-2 py-3 text-sm outline-none',
'hover:bg-secondary-background-hover',
'focus:bg-secondary-background-hover',
'data-[state=checked]:bg-secondary-background-selected',

View File

@@ -28,7 +28,7 @@
type="text"
inputmode="numeric"
:style="{ width: `${inputWidth}ch` }"
class="min-w-0 rounded border-none bg-transparent text-center text-base-foreground font-medium text-lg focus-visible:outline-none"
class="min-w-0 rounded-sm border-none bg-transparent text-center text-base-foreground font-medium text-lg focus-visible:outline-none"
:disabled="disabled"
@input="handleInputChange"
@blur="handleInputBlur"