// Button Component // Shadcn-style button with multiple variants and sizes import { Theme, Typography, SpacingSystem } from "../theme/theme.slint"; import { Animations } from "../utils/animations.slint"; export component Button { // Public properties in property text: "Button"; in property variant: "default"; // default | destructive | outline | secondary | ghost in property size: "md"; // sm | md | lg in property disabled: false; // Callbacks callback clicked(); // Calculate text color based on variant private property text-color: { if disabled { Theme.colors.muted-foreground } else if variant == "destructive" { Theme.colors.destructive-foreground } else if variant == "outline" { Theme.colors.foreground } else if variant == "secondary" { Theme.colors.secondary-foreground } else if variant == "ghost" { Theme.colors.foreground } else { Theme.colors.primary-foreground } }; // Calculate size-based dimensions private property btn-height: size == "sm" ? 36px : size == "lg" ? 44px : 40px; private property btn-padding-x: size == "sm" ? 12px : size == "lg" ? 24px : 16px; private property font-size: size == "sm" ? Typography.sizes.sm : size == "lg" ? Typography.sizes.lg : Typography.sizes.base; 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 { border-radius: SpacingSystem.radius.md; border-width: variant == "outline" ? 1px : 0px; 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 animate background { duration: Animations.durations.fast; easing: Animations.ease-in-out; } } // Content layout HorizontalLayout { padding-left: btn-padding-x; padding-right: btn-padding-x; spacing: SpacingSystem.spacing.s2; alignment: center; // Button text Text { text: root.text; color: text-color; font-size: font-size; font-weight: Typography.weights.medium; vertical-alignment: center; horizontal-alignment: center; } } // 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; 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; } } } }