public/controls/inputs/New-UiSlider.ps1

function New-UiSlider {
    <#
    .SYNOPSIS
        Creates a slider control for numeric value selection.
    .DESCRIPTION
        Renders a horizontal or vertical slider with optional tick marks and a live value
        label. -IsSnapToTick makes the thumb land on ticks. The label takes a format string
        (percentage, decimal) and -EnabledWhen gates the control like any other input.
    .PARAMETER Variable
        Variable name to store the slider value.
    .PARAMETER Label
        Label text displayed above the slider.
    .PARAMETER Minimum
        Minimum value (default: 0).
    .PARAMETER Maximum
        Maximum value (default: 100).
    .PARAMETER Default
        Initial value (default: 50).
    .PARAMETER TickFrequency
        Interval between tick marks. Set to 0 to hide ticks.
    .PARAMETER IsSnapToTick
        Snaps the thumb to tick values. Does nothing unless -TickFrequency is above 0.
    .PARAMETER ShowValueLabel
        If true, displays the current value next to the slider.
    .PARAMETER ValueLabelFormat
        Format string for the value label (e.g., "{0:N0}" for integers, "{0:P0}" for percentage).
    .PARAMETER Vertical
        If true, creates a vertical slider instead of horizontal.
    .PARAMETER Height
        Height of vertical slider (default: 100). Only valid with -Vertical.
    .PARAMETER MaxHeight
        Maximum height for vertical slider. Only valid with -Vertical.
    .PARAMETER MaxWidth
        Maximum width for horizontal slider. Only valid without -Vertical.
    .PARAMETER FullWidth
        If true, expands to fill available width.
    .PARAMETER EnabledWhen
        Conditional enabling based on another control's state. Accepts either:
        - A control proxy (e.g., $toggleControl) - enables when that control is truthy
        - A scriptblock (e.g., { $toggle -and $userName }) - enables when expression is true
 
        Truthy values: CheckBox=checked, TextBox=non-empty, ComboBox=has selection.
    .PARAMETER ClearIfDisabled
        When used with -EnabledWhen, resets the slider to its Minimum when the control
        becomes disabled.
    .PARAMETER WPFProperties
        Hashtable of additional WPF properties to set on the control.
    .EXAMPLE
        New-UiSlider -Variable "volume" -Label "Volume" -Minimum 0 -Maximum 100 -Default 50
    .EXAMPLE
        New-UiSlider -Variable "opacity" -Label "Opacity" -Minimum 0 -Maximum 1 -Default 1 -TickFrequency 0.1 -ShowValueLabel -ValueLabelFormat "{0:P0}"
    .EXAMPLE
        New-UiSlider -Variable "level" -Vertical -Height 150 -Minimum 0 -Maximum 10 -Default 5
    #>

    [CmdletBinding(DefaultParameterSetName = 'Horizontal')]
    param(
        [Parameter(Mandatory)]
        [string]$Variable,
        
        [string]$Label,
        
        [double]$Minimum = 0,
        
        [double]$Maximum = 100,
        
        [double]$Default = 50,
        
        [double]$TickFrequency = 0,
        
        [switch]$IsSnapToTick,
        
        [switch]$ShowValueLabel,
        
        [string]$ValueLabelFormat = "{0:N0}",
        
        [Parameter(ParameterSetName = 'Vertical', Mandatory)]
        [switch]$Vertical,
        
        [Parameter(ParameterSetName = 'Vertical')]
        [int]$Height = 100,
        
        [Parameter(ParameterSetName = 'Vertical')]
        [int]$MaxHeight,
        
        [Parameter(ParameterSetName = 'Horizontal')]
        [int]$MaxWidth,
        
        [switch]$FullWidth,

        [Parameter()]
        [object]$EnabledWhen,

        [switch]$ClearIfDisabled,
        
        [Parameter()]
        [hashtable]$WPFProperties
    )

    $session = Assert-UiSession -CallerName 'New-UiSlider'
    Write-Debug "Variable='$Variable', Min=$Minimum, Max=$Maximum, Default=$Default"

    $colors  = Get-ThemeColors
    $parent  = $session.CurrentParent
    Write-Debug "Parent: $($parent.GetType().Name)"

    $stack = [System.Windows.Controls.StackPanel]::new()
    $stack.Margin = [System.Windows.Thickness]::new(4, 4, 4, 8)
    
    # Apply MaxWidth/MaxHeight constraints based on orientation
    if ($Vertical -and $MaxHeight -gt 0) {
        $stack.MaxHeight = $MaxHeight
    }
    elseif (!$Vertical) {
        # Horizontal sliders should stretch to fill available width
        $stack.HorizontalAlignment = 'Stretch'
        if ($MaxWidth -gt 0) {
            $stack.MaxWidth = $MaxWidth
        }
    }

    if ($Label) {
        $labelBlock = [System.Windows.Controls.TextBlock]@{
            Text       = $Label
            FontSize   = 12
            Foreground = ConvertTo-UiBrush $colors.ControlFg
            Margin     = [System.Windows.Thickness]::new(0, 0, 0, 4)
            Tag        = 'ControlFgBrush'
        }
        [PsUi.ThemeEngine]::RegisterElement($labelBlock)
        [void]$stack.Children.Add($labelBlock)
    }

    # Slider with optional value display
    if ($ShowValueLabel) {
        if ($Vertical) {
            # For vertical sliders, put value label below the slider
            $sliderPanel = [System.Windows.Controls.StackPanel]::new()
            $sliderPanel.Orientation = 'Vertical'
            $sliderPanel.HorizontalAlignment = 'Center'
            
            $slider = [System.Windows.Controls.Slider]::new()
            $slider.Minimum = $Minimum
            $slider.Maximum = $Maximum
            $slider.Value = $Default
            $slider.Orientation = 'Vertical'
            $slider.HorizontalAlignment = 'Center'
            
            if ($TickFrequency -gt 0) {
                $slider.TickFrequency = $TickFrequency
                $slider.TickPlacement = 'TopLeft'
                $slider.IsSnapToTickEnabled = $IsSnapToTick
            }
            
            Set-SliderStyle -Slider $slider
            
            # Override: Explicit height for vertical slider sizing
            $slider.Height = $Height
            [void]$sliderPanel.Children.Add($slider)
            
            $valueLabel = [System.Windows.Controls.TextBlock]::new()
            $valueLabel.Text = $ValueLabelFormat -f $Default
            $valueLabel.FontSize = 11
            $valueLabel.Foreground = ConvertTo-UiBrush $colors.ControlFg
            $valueLabel.HorizontalAlignment = 'Center'
            $valueLabel.Margin = [System.Windows.Thickness]::new(0, 4, 0, 0)
            $valueLabel.Tag = 'ControlFgBrush'
            [PsUi.ThemeEngine]::RegisterElement($valueLabel)
            [void]$sliderPanel.Children.Add($valueLabel)
            
            # Update value label when slider changes
            $slider.Add_ValueChanged({
                param($sender, $eventArgs)
                $valueLabel.Text = $ValueLabelFormat -f $eventArgs.NewValue
            }.GetNewClosure())
            
            [void]$stack.Children.Add($sliderPanel)
        }
        else {
            # For horizontal sliders, put value label to the right
            $sliderPanel = [System.Windows.Controls.Grid]::new()
            $sliderPanel.ColumnDefinitions.Add([System.Windows.Controls.ColumnDefinition]::new())
            $sliderPanel.ColumnDefinitions[0].Width = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star)
            $sliderPanel.ColumnDefinitions.Add([System.Windows.Controls.ColumnDefinition]::new())
            $sliderPanel.ColumnDefinitions[1].Width = [System.Windows.GridLength]::Auto

            $slider = [System.Windows.Controls.Slider]::new()
            $slider.Minimum = $Minimum
            $slider.Maximum = $Maximum
            $slider.Value = $Default
            $slider.VerticalAlignment = 'Center'
            
            if ($TickFrequency -gt 0) {
                $slider.TickFrequency = $TickFrequency
                $slider.TickPlacement = 'BottomRight'
                $slider.IsSnapToTickEnabled = $IsSnapToTick
            }
            
            Set-SliderStyle -Slider $slider
            [System.Windows.Controls.Grid]::SetColumn($slider, 0)
            [void]$sliderPanel.Children.Add($slider)

            $valueLabel = [System.Windows.Controls.TextBlock]::new()
            $valueLabel.Text = $ValueLabelFormat -f $Default
            $valueLabel.FontSize = 12
            $valueLabel.Foreground = ConvertTo-UiBrush $colors.ControlFg
            $valueLabel.VerticalAlignment = 'Center'
            $valueLabel.Margin = [System.Windows.Thickness]::new(8, 0, 0, 0)
            $valueLabel.MinWidth = 40
            $valueLabel.TextAlignment = 'Right'
            $valueLabel.Tag = 'ControlFgBrush'
            [PsUi.ThemeEngine]::RegisterElement($valueLabel)
            [System.Windows.Controls.Grid]::SetColumn($valueLabel, 1)
            [void]$sliderPanel.Children.Add($valueLabel)

            # Update value label when slider changes
            $slider.Add_ValueChanged({
                param($sender, $eventArgs)
                $valueLabel.Text = $ValueLabelFormat -f $eventArgs.NewValue
            }.GetNewClosure())

            [void]$stack.Children.Add($sliderPanel)
        }
    }
    else {
        $slider = [System.Windows.Controls.Slider]::new()
        $slider.Minimum = $Minimum
        $slider.Maximum = $Maximum
        $slider.Value = $Default
        
        if ($Vertical) {
            $slider.Orientation = 'Vertical'
            $slider.HorizontalAlignment = 'Center'
        }
        
        if ($TickFrequency -gt 0) {
            $slider.TickFrequency = $TickFrequency
            $slider.TickPlacement = if ($Vertical) { 'TopLeft' } else { 'BottomRight' }
            $slider.IsSnapToTickEnabled = $IsSnapToTick
        }
        
        Set-SliderStyle -Slider $slider
        
        # Override: Explicit height for vertical slider sizing
        if ($Vertical) {
            $slider.Height = $Height
        }
        
        [void]$stack.Children.Add($slider)
    }

    # Tag wrapper for FormLayout unwrapping (when label exists)
    if ($Label) {
        $controlElement = if ($ShowValueLabel) { $sliderPanel } else { $slider }
        Set-UiFormControlTag -Wrapper $stack -Label $labelBlock -Control $controlElement
    }

    # FullWidth in WrapPanel contexts
    Set-FullWidthConstraint -Control $stack -Parent $parent -FullWidth:$FullWidth
    
    # Apply custom WPF properties if specified
    if ($WPFProperties) {
        Set-UiProperties -Control $stack -Properties $WPFProperties
    }
    
    Write-Debug "Adding to $($parent.GetType().Name)"
    [void]$parent.Children.Add($stack)

    # Register control in all session registries
    Register-UiControlComplete -Name $Variable -Control $slider -InitialValue $slider.Value

    if ($EnabledWhen) {
        Register-UiCondition -TargetControl $slider -Condition $EnabledWhen -ClearIfDisabled:$ClearIfDisabled
    }
}