This commit is contained in:
2026-01-26 21:58:59 +08:00
parent 2b8f0892f4
commit 1ec60e3cbb

View File

@@ -14,16 +14,6 @@ export component Button {
// Callbacks
callback clicked();
// Calculate background color based on variant
private property <color> base-bg-color: {
if disabled { Theme.colors.muted }
else if variant == "destructive" { Theme.colors.destructive }
else if variant == "outline" { Colors.transparent }
else if variant == "secondary" { Theme.colors.secondary }
else if variant == "ghost" { Colors.transparent }
else { Theme.colors.primary }
};
// Calculate text color based on variant
private property <color> text-color: {
if disabled { Theme.colors.muted-foreground }
@@ -42,17 +32,74 @@ export component Button {
min-width: btn-height;
min-height: btn-height;
// Focus scope for keyboard navigation
focus-scope := FocusScope {
enabled: !disabled;
key-pressed(event) => {
if (event.text == " " || event.text == "\n") {
root.clicked();
return accept;
}
return reject;
}
}
// Main container
container := Rectangle {
background: base-bg-color;
border-radius: SpacingSystem.radius.md;
border-width: variant == "outline" ? 1px : 0px;
border-color: Theme.colors.border;
// Smooth transitions
animate background {
duration: Animations.durations.fast;
easing: Animations.ease-in-out;
// Touch interaction area (must be defined before using touch.pressed/has-hover)
touch := TouchArea {
enabled: !disabled;
clicked => {
// Don't set focus on mouse click (shadcn style)
root.clicked();
}
}
// Background with state-based colors (shadcn style)
background-rect := Rectangle {
width: 100%;
height: 100%;
border-radius: parent.border-radius;
// Calculate background color based on variant and state
background: {
if root.disabled {
Theme.colors.muted
} else if root.variant == "destructive" {
if touch.pressed { Theme.colors.destructive.darker(0.1) }
else if touch.has-hover { Theme.colors.destructive.darker(0.05) }
else { Theme.colors.destructive }
} else if root.variant == "outline" {
if touch.pressed { Theme.colors.accent.darker(0.05) }
else if touch.has-hover { Theme.colors.accent }
else { Colors.transparent }
} else if root.variant == "secondary" {
if touch.pressed { Theme.colors.secondary.darker(0.1) }
else if touch.has-hover { Theme.colors.secondary.darker(0.05) }
else { Theme.colors.secondary }
} else if root.variant == "ghost" {
if touch.pressed { Theme.colors.accent.darker(0.05) }
else if touch.has-hover { Theme.colors.accent }
else { Colors.transparent }
} else {
// default variant
if touch.pressed { Theme.colors.primary.darker(0.1) }
else if touch.has-hover { Theme.colors.primary.darker(0.05) }
else { Theme.colors.primary }
}
};
// Smooth transitions
animate background {
duration: Animations.durations.fast;
easing: Animations.ease-in-out;
}
}
// Content layout
@@ -72,38 +119,19 @@ export component Button {
horizontal-alignment: center;
}
}
// Touch interaction area
touch := TouchArea {
enabled: !disabled;
clicked => {
root.clicked();
}
}
// Combined overlay for both hover and press effects
overlay := Rectangle {
// Focus ring only for keyboard navigation (shadcn style)
// Will only show when using Tab key, not on mouse click
focus-ring := Rectangle {
width: 100%;
height: 100%;
border-radius: SpacingSystem.radius.md;
// 直接根据状态设置背景色,不使用 states 块
background: {
if disabled {
Colors.transparent
} else if touch.pressed {
#00000030 // 按压时深色
} else if touch.has-hover {
#ffffff10 // 悬停时浅色
} else {
Colors.transparent
}
};
animate background {
duration: 200ms;
easing: ease-in-out;
border-width: focus-scope.has-focus ? 2px : 0px;
border-color: Theme.colors.ring;
animate border-width {
duration: Animations.durations.fast;
easing: Animations.ease-in-out;
}
}
}