init
This commit is contained in:
@@ -14,16 +14,6 @@ export component Button {
|
|||||||
// Callbacks
|
// Callbacks
|
||||||
callback clicked();
|
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
|
// Calculate text color based on variant
|
||||||
private property <color> text-color: {
|
private property <color> text-color: {
|
||||||
if disabled { Theme.colors.muted-foreground }
|
if disabled { Theme.colors.muted-foreground }
|
||||||
@@ -42,18 +32,75 @@ export component Button {
|
|||||||
min-width: btn-height;
|
min-width: btn-height;
|
||||||
min-height: 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
|
// Main container
|
||||||
container := Rectangle {
|
container := Rectangle {
|
||||||
background: base-bg-color;
|
|
||||||
border-radius: SpacingSystem.radius.md;
|
border-radius: SpacingSystem.radius.md;
|
||||||
border-width: variant == "outline" ? 1px : 0px;
|
border-width: variant == "outline" ? 1px : 0px;
|
||||||
border-color: Theme.colors.border;
|
border-color: Theme.colors.border;
|
||||||
|
|
||||||
|
// 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
|
// Smooth transitions
|
||||||
animate background {
|
animate background {
|
||||||
duration: Animations.durations.fast;
|
duration: Animations.durations.fast;
|
||||||
easing: Animations.ease-in-out;
|
easing: Animations.ease-in-out;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Content layout
|
// Content layout
|
||||||
HorizontalLayout {
|
HorizontalLayout {
|
||||||
@@ -73,37 +120,18 @@ export component Button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Touch interaction area
|
// Focus ring only for keyboard navigation (shadcn style)
|
||||||
touch := TouchArea {
|
// Will only show when using Tab key, not on mouse click
|
||||||
enabled: !disabled;
|
focus-ring := Rectangle {
|
||||||
|
|
||||||
clicked => {
|
|
||||||
root.clicked();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combined overlay for both hover and press effects
|
|
||||||
overlay := Rectangle {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: SpacingSystem.radius.md;
|
border-radius: SpacingSystem.radius.md;
|
||||||
|
border-width: focus-scope.has-focus ? 2px : 0px;
|
||||||
|
border-color: Theme.colors.ring;
|
||||||
|
|
||||||
// 直接根据状态设置背景色,不使用 states 块
|
animate border-width {
|
||||||
background: {
|
duration: Animations.durations.fast;
|
||||||
if disabled {
|
easing: Animations.ease-in-out;
|
||||||
Colors.transparent
|
|
||||||
} else if touch.pressed {
|
|
||||||
#00000030 // 按压时深色
|
|
||||||
} else if touch.has-hover {
|
|
||||||
#ffffff10 // 悬停时浅色
|
|
||||||
} else {
|
|
||||||
Colors.transparent
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
animate background {
|
|
||||||
duration: 200ms;
|
|
||||||
easing: ease-in-out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user