Upgrade Tailwind to v4 (#491)

This commit is contained in:
Gregory Schier
2026-07-02 09:53:22 -07:00
committed by GitHub
parent bdf78254b5
commit 9b524e3dc7
112 changed files with 744 additions and 1027 deletions
-134
View File
@@ -1,134 +0,0 @@
const plugin = require("tailwindcss/plugin");
const sizes = {
"2xs": "1.4rem",
xs: "1.8rem",
sm: "2.0rem",
md: "2.3rem",
lg: "2.6rem",
};
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class", '[data-resolved-appearance="dark"]'],
theme: {
extend: {
keyframes: {
blinkRing: {
"0%, 49%": { "--tw-ring-color": "var(--primary)" },
"50%, 99%": { "--tw-ring-color": "transparent" },
"100%": { "--tw-ring-color": "var(--primary)" },
},
},
animation: {
blinkRing: "blinkRing 150ms step-start 400ms infinite",
},
opacity: {
disabled: "0.3",
},
fontSize: {
xs: "0.8rem",
},
height: sizes,
width: sizes,
minHeight: sizes,
minWidth: sizes,
lineHeight: {
// HACK: Minus 2 to account for borders inside inputs
xs: "calc(1.75rem - 2px)",
sm: "calc(2.0rem - 2px)",
md: "calc(2.5rem - 2px)",
},
transitionProperty: {
grid: "grid",
},
},
fontFamily: {
mono: [
"var(--font-family-editor)",
"JetBrains Mono",
"ui-monospace",
"SFMono-Regular",
"Menlo",
"Monaco",
"Fira Code",
"Ubuntu Mono",
"Consolas",
"Liberation Mono",
"Courier New",
"DejaVu Sans Mono",
"Hack",
"monospace",
],
sans: [
"var(--font-family-interface)",
"Inter UI",
"-apple-system",
"BlinkMacSystemFont",
"Segoe UI",
"Roboto",
"Oxygen-Sans",
"Ubuntu",
"Cantarell",
"Helvetica Neue",
"sans-serif",
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
],
},
fontSize: {
"4xs": "0.6rem",
"3xs": "0.675rem",
"2xs": "0.75rem",
xs: "0.8rem",
sm: "0.9rem",
base: "1rem",
lg: "1.12rem",
xl: "1.25rem",
"2xl": "1.5rem",
"3xl": "2rem",
"4xl": "2.5rem",
"5xl": "3rem",
editor: "var(--editor-font-size)",
shrink: "0.8em",
},
boxShadow: {
DEFAULT: "0 1px 3px 0 var(--shadow)",
lg: "0 10px 15px -3px var(--shadow)",
},
colors: {
transparent: "transparent",
placeholder: "var(--textSubtlest)",
shadow: "var(--shadow)",
backdrop: "var(--backdrop)",
selection: "var(--selection)",
// New theme values
surface: "var(--surface)",
"surface-highlight": "var(--surfaceHighlight)",
"surface-active": "var(--surfaceActive)",
text: "var(--text)",
"text-subtle": "var(--textSubtle)",
"text-subtlest": "var(--textSubtlest)",
border: "var(--border)",
"border-subtle": "var(--borderSubtle)",
"border-focus": "var(--borderFocus)",
primary: "var(--primary)",
danger: "var(--danger)",
secondary: "var(--secondary)",
success: "var(--success)",
info: "var(--info)",
notice: "var(--notice)",
warning: "var(--warning)",
},
},
plugins: [
require("@tailwindcss/container-queries"),
// oxlint-disable-next-line unbound-method -- destructured from plugin API
plugin(({ addVariant }) => {
addVariant("hocus", ["&:hover", "&:focus-visible", "&.focus:focus"]);
addVariant("focus-visible-or-class", ["&:focus-visible", "&.focus:focus"]);
}),
],
};
+124
View File
@@ -0,0 +1,124 @@
@custom-variant dark (&:is([data-resolved-appearance="dark"] *));
@custom-variant hocus (&:hover, &:focus-visible, &.focus:focus);
@custom-variant focus-visible-or-class (&:focus-visible, &.focus:focus);
@theme inline {
--font-mono:
var(--font-family-editor), JetBrains Mono, ui-monospace, SFMono-Regular,
Menlo, Monaco, Fira Code, Ubuntu Mono, Consolas, Liberation Mono,
Courier New, DejaVu Sans Mono, Hack, monospace;
--font-sans:
var(--font-family-interface), Inter UI, -apple-system, BlinkMacSystemFont,
Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue,
sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
--font-serif: initial;
--text-*: initial;
--text-4xs: 0.6rem;
--text-3xs: 0.675rem;
--text-2xs: 0.75rem;
--text-xs: 0.8rem;
--text-sm: 0.9rem;
--text-base: 1rem;
--text-lg: 1.12rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 2rem;
--text-4xl: 2.5rem;
--text-5xl: 3rem;
--text-editor: var(--editor-font-size);
--text-shrink: 0.8em;
--shadow-*: initial;
--shadow: 0 1px 3px 0 var(--shadow);
--shadow-lg: 0 10px 15px -3px var(--shadow);
--color-*: initial;
--color-transparent: transparent;
--color-placeholder: var(--textSubtlest);
--color-shadow: var(--shadow);
--color-backdrop: var(--backdrop);
--color-selection: var(--selection);
--color-surface: var(--surface);
--color-surface-highlight: var(--surfaceHighlight);
--color-surface-active: var(--surfaceActive);
--color-text: var(--text);
--color-text-subtle: var(--textSubtle);
--color-text-subtlest: var(--textSubtlest);
--color-border: var(--border);
--color-border-subtle: var(--borderSubtle);
--color-border-focus: var(--borderFocus);
--color-primary: var(--primary);
--color-danger: var(--danger);
--color-secondary: var(--secondary);
--color-success: var(--success);
--color-info: var(--info);
--color-notice: var(--notice);
--color-warning: var(--warning);
--animate-blinkRing: blinkRing 150ms step-start 400ms infinite;
--opacity-disabled: 30%;
--height-2xs: 1.4rem;
--height-xs: 1.8rem;
--height-sm: 2rem;
--height-md: 2.3rem;
--height-lg: 2.6rem;
--width-2xs: 1.4rem;
--width-xs: 1.8rem;
--width-sm: 2rem;
--width-md: 2.3rem;
--width-lg: 2.6rem;
--min-height-2xs: 1.4rem;
--min-height-xs: 1.8rem;
--min-height-sm: 2rem;
--min-height-md: 2.3rem;
--min-height-lg: 2.6rem;
--min-width-2xs: 1.4rem;
--min-width-xs: 1.8rem;
--min-width-sm: 2rem;
--min-width-md: 2.3rem;
--min-width-lg: 2.6rem;
--leading-xs: calc(1.75rem - 2px);
--leading-sm: calc(2rem - 2px);
--leading-md: calc(2.5rem - 2px);
--transition-property-grid: grid;
@keyframes blinkRing {
0%,
49% {
--tw-ring-color: var(--primary);
}
50%,
99% {
--tw-ring-color: transparent;
}
100% {
--tw-ring-color: var(--primary);
}
}
}
/*
The default border color has changed to `currentcolor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentcolor);
}
}
-5
View File
@@ -1,5 +0,0 @@
import type { Config } from "tailwindcss";
declare const config: Config;
export = config;
+1 -6
View File
@@ -2,10 +2,5 @@
"name": "@yaakapp-internal/tailwind-config",
"version": "1.0.0",
"private": true,
"main": "index.cjs",
"types": "index.d.ts",
"dependencies": {
"@tailwindcss/container-queries": "^0.1.1",
"tailwindcss": "^3.4.17"
}
"style": "index.css"
}
+3 -3
View File
@@ -61,8 +61,8 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
"border",
"max-w-full min-w-0",
"hocus:opacity-100",
"whitespace-nowrap outline-none",
"flex-shrink-0 flex items-center",
"whitespace-nowrap outline-hidden",
"shrink-0 flex items-center",
"outline-0",
isDisabled ? "pointer-events-none opacity-disabled" : "pointer-events-auto",
justify === "start" && "justify-start",
@@ -70,7 +70,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
size === "md" && "h-md px-3 rounded-md",
size === "sm" && "h-sm px-2.5 rounded-md",
size === "xs" && "h-xs px-2 text-sm rounded-md",
size === "2xs" && "h-2xs px-2 text-xs rounded",
size === "2xs" && "h-2xs px-2 text-xs rounded-sm",
size === "auto" && "px-3 py-2 rounded-md",
variant === "solid" && "border-transparent",
variant === "solid" &&
+2 -2
View File
@@ -23,8 +23,8 @@ export const DropMarker = memo(
<div
className={classNames(
"absolute bg-primary rounded-full",
orientation === "horizontal" && "left-2 right-2 -bottom-[0.1rem] h-[0.2rem]",
orientation === "vertical" && "-left-[0.1rem] top-0 bottom-0 w-[0.2rem]",
orientation === "horizontal" && "left-2 right-2 bottom-[-0.1rem] h-[0.2rem]",
orientation === "vertical" && "left-[-0.1rem] top-0 bottom-0 w-[0.2rem]",
)}
/>
</div>
@@ -12,8 +12,8 @@ export function FormattedError({ children, className }: Props) {
className={classNames(
className,
"cursor-text select-auto",
"[&_*]:cursor-text [&_*]:select-auto",
"font-mono text-sm w-full bg-surface-highlight p-3 rounded",
"**:cursor-text **:select-auto",
"font-mono text-sm w-full bg-surface-highlight p-3 rounded-sm",
"whitespace-pre-wrap border border-danger border-dashed overflow-x-auto",
)}
>
+1 -1
View File
@@ -67,7 +67,7 @@ export function HeaderSize({
style={finalStyle}
className={classNames(
className,
"pt-[1px]", // Make up for bottom border
"pt-px", // Make up for bottom border
"select-none relative flex items-center",
"w-full border-b border-border-subtle min-w-0",
)}
+1 -1
View File
@@ -319,7 +319,7 @@ export const Icon = memo(function Icon({
className,
!spin && "transform-gpu",
spin && "animate-spin",
"flex-shrink-0",
"shrink-0",
size === "xl" && "h-6 w-6",
size === "lg" && "h-5 w-5",
size === "md" && "h-4 w-4",
+3 -3
View File
@@ -60,8 +60,8 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(functio
type={type}
className={classNames(
className,
"group/button relative flex-shrink-0",
"!px-0",
"group/button relative shrink-0",
"px-0!",
size === "md" && "w-md",
size === "sm" && "w-sm",
size === "xs" && "w-xs",
@@ -85,7 +85,7 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(functio
className={classNames(
iconClassName,
"group-hover/button:text-text",
confirmed && "!text-success",
confirmed && "text-success!",
props.disabled && "opacity-70",
)}
/>
+2 -2
View File
@@ -6,8 +6,8 @@ export function InlineCode({ className, ...props }: HTMLAttributes<HTMLSpanEleme
<code
className={classNames(
className,
"font-mono text-shrink bg-surface-highlight border border-border-subtle flex-grow-0",
"px-1.5 py-0.5 rounded text shadow-inner break-words",
"font-mono text-shrink bg-surface-highlight border border-border-subtle grow-0",
"px-1.5 py-0.5 rounded-sm text shadow-inner wrap-break-word",
)}
{...props}
/>
+1 -1
View File
@@ -8,7 +8,7 @@ interface Props {
export function LoadingIcon({ size = "md", className }: Props) {
const classes = classNames(
className,
"text-inherit flex-shrink-0",
"text-inherit shrink-0",
size === "xl" && "h-6 w-6",
size === "lg" && "h-5 w-5",
size === "md" && "h-4 w-4",
+1 -1
View File
@@ -72,7 +72,7 @@ export function Overlay({
onClick={onClose}
className={classNames(
"absolute inset-0",
variant === "default" && "bg-backdrop backdrop-blur-sm",
variant === "default" && "bg-backdrop backdrop-blur-xs",
)}
/>
+1 -1
View File
@@ -101,7 +101,7 @@ export function ResizeHandle({
{isResizing && (
<div
className={classNames(
"fixed -left-[100vw] -right-[100vw] -top-[100vh] -bottom-[100vh]",
"fixed left-[-100vw] right-[-100vw] top-[-100vh] bottom-[-100vh]",
vertical && "cursor-row-resize",
!vertical && "cursor-col-resize",
)}
+1 -1
View File
@@ -130,7 +130,7 @@ export function SidebarLayout({
</div>
<ResizeHandle
style={drag}
className="-translate-x-[1px]"
className="-translate-x-px"
justify="end"
side="right"
onResizeStart={handleResizeStart}
+2 -2
View File
@@ -87,7 +87,7 @@ export function TableCell({
<td
className={classNames(
className,
"py-2 [&:not(:first-child)]:pl-4 whitespace-nowrap",
"py-2 not-first:pl-4 whitespace-nowrap",
align === "left" ? "text-left" : align === "center" ? "text-center" : "text-right",
)}
>
@@ -119,7 +119,7 @@ export function TableHeaderCell({
<th
className={classNames(
className,
"whitespace-nowrap py-2 [&:not(:first-child)]:pl-4 text-left text-text-subtle",
"whitespace-nowrap py-2 not-first:pl-4 text-left text-text-subtle",
)}
>
{children}
@@ -38,7 +38,7 @@ export function WindowControls({
{!onlyX && (
<>
<Button
className="!h-full px-4 text-text-subtle hocus:text hocus:bg-surface-highlight rounded-none"
className="h-full! px-4 text-text-subtle hocus:text hocus:bg-surface-highlight rounded-none"
color="custom"
onClick={() => getCurrentWebviewWindow().minimize()}
>
@@ -48,7 +48,7 @@ export function WindowControls({
</svg>
</Button>
<Button
className="!h-full px-4 text-text-subtle hocus:text hocus:bg-surface-highlight rounded-none"
className="h-full! px-4 text-text-subtle hocus:text hocus:bg-surface-highlight rounded-none"
color="custom"
onClick={async () => {
const w = getCurrentWebviewWindow();
@@ -81,7 +81,7 @@ export function WindowControls({
)}
<Button
color="custom"
className="!h-full px-4 text-text-subtle rounded-none hocus:bg-danger hocus:text-text"
className="h-full! px-4 text-text-subtle rounded-none hocus:bg-danger hocus:text-text"
onClick={() => getCurrentWebviewWindow().close()}
>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+3 -3
View File
@@ -662,7 +662,7 @@ function TreeInner<T extends { id: string }>(
ref={treeRef}
className={classNames(
className,
"outline-none h-full",
"outline-hidden h-full",
"overflow-y-auto overflow-x-hidden",
"grid grid-rows-[auto_1fr]",
)}
@@ -670,8 +670,8 @@ function TreeInner<T extends { id: string }>(
<div
className={classNames(
"[&_.tree-item.selected_.tree-item-inner]:text-text",
"[&:focus-within]:[&_.tree-item.selected]:bg-surface-active",
"[&:not(:focus-within)]:[&_.tree-item.selected:not([data-context-menu-open])]:bg-surface-highlight",
"focus-within:[&_.tree-item.selected]:bg-surface-active",
"not-focus-within:[&_.tree-item.selected:not([data-context-menu-open])]:bg-surface-highlight",
"[&_.tree-item.selected[data-context-menu-open]]:bg-surface-active",
// Round the items, but only if the ends of the selection.
// Also account for the drop marker being in between items
+4 -4
View File
@@ -326,7 +326,7 @@ function TreeItem_<T extends { id: string }>({
<button
type="button"
tabIndex={-1}
className="h-full pl-[0.5rem] outline-none"
className="h-full pl-2 outline-hidden"
onClick={toggleCollapsed}
>
<Icon
@@ -334,7 +334,7 @@ function TreeItem_<T extends { id: string }>({
className={classNames(
"transition-transform text-text-subtlest",
"ml-auto",
"w-[1rem] h-[1rem]",
"w-4 h-4",
!isCollapsed && node.children.length > 0 && "rotate-90",
)}
/>
@@ -349,7 +349,7 @@ function TreeItem_<T extends { id: string }>({
onClick={handleClick}
onDoubleClick={handleDoubleClick}
disabled={editing}
className="cursor-default tree-item-inner pr-1 focus:outline-none flex items-center gap-2 h-full whitespace-nowrap"
className="cursor-default tree-item-inner pr-1 focus:outline-hidden flex items-center gap-2 h-full whitespace-nowrap"
{...attributes}
{...listeners}
tabIndex={isLastSelected ? 0 : -1}
@@ -366,7 +366,7 @@ function TreeItem_<T extends { id: string }>({
placeholder={placeholder}
autoCapitalize="off"
autoCorrect="off"
className="bg-transparent outline-none w-full cursor-text"
className="bg-transparent outline-hidden w-full cursor-text"
onBlur={handleEditBlur}
onKeyDown={handleEditKeyDown}
/>