Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Slider #15507

Open
wants to merge 19 commits into
base: 4.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const formComponents = [
'markdown-editor',
'rich-editor',
'select',
'slider',
'tags-input',
'textarea',
]
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"laravel-mix": "^6.0.37",
"luxon": "^3.4.3",
"mime": "^4.0.4",
"nouislider": "^15.8.1",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.4",
"postcss-nesting": "^13.0.0",
Expand All @@ -63,6 +64,7 @@
"tippy.js": "^6.3.7",
"trix": "^2.1",
"uuid-browser": "^3.1.0",
"vanilla-colorful": "^0.7.2"
"vanilla-colorful": "^0.7.2",
"wnumb": "^1.2.0"
}
}
1 change: 1 addition & 0 deletions packages/forms/dist/components/slider.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/forms/dist/index.css

Large diffs are not rendered by default.

186 changes: 186 additions & 0 deletions packages/forms/docs/02-fields/19-slider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
---
title: Slider
---
import AutoScreenshot from "@components/AutoScreenshot.astro"

## Overview

The slider component allows you to select a value from a range of values. The component uses the [noUiSlider library](https://refreshless.com/nouislider/).

<AutoScreenshot name="forms/fields/slider/simple" alt="Slider" version="4.x" />


## Range

By default, the slider has a range of 0 to 100. You can change this, using the `range()` method:

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->range(['min' => 0, 'max' => 300]),
```

## Step

You can add steps to the slider, where every time its dragged, it will "jump" to the next step. This can enabled using the `step()` method:

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->step(true),
```

## Pips

Pips allow the user to see the in between values of the sliders, which can be enabled by injecting Javascript code into the slider component:

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->pips(RawJs::make(<<<'JS'
{
mode: 'steps',
stepped: true,
density: 5,
}
JS))
->step(true)
]);
```

<AutoScreenshot name="forms/fields/slider/pips" alt="Slider" version="4.x" />

## Multiple Handles

You can add multiple handles to your slider by setting multiple values in the `start()` method, where each values represents the staring point of each handle:

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->connect(true)
->pips(RawJs::make(<<<'JS'
{
mode: 'steps',
stepped: true,
density: 5,
}
JS))
->start([10, 50])
->range(['min' => 0, 'max' => 200]),
```

<AutoScreenshot name="forms/fields/slider/increased" alt="Slider" version="4.x" />

## User Interaction

The slider component offers several ways to handle user interaction.

The slider handle can be `tapped`, `dragged`, `fixed` etc. The slider behaviour is defined by `SliderBehaviour::Drag`,`SliderBehaviour::DragAll`,`SliderBehaviour::Tap`,`SliderBehaviour::Fixed`,`SliderBehaviour::Snap`,`SliderBehaviour::Unconstrained`,`SliderBehaviour::InvertConnects` and `SliderBehaviour::None`.

```php
use Filament\Forms\Components\Slider;
use Filament\Forms\Components\Enums\SliderBehaviour;

Slider::make('slider')
->behaviour(SliderBehaviour::Drag),
```

The orientation of the slider can be set to `horizontal` or `vertical`:
```php
use Filament\Forms\Components\Slider;
use Filament\Forms\Components\Enums\SliderOrientation;

Slider::make('slider')
->orientation(SliderOrientation::Drag),
thethunderturner marked this conversation as resolved.
Show resolved Hide resolved
```

The direction of the slider can be set to `ltr` or `rtl`:
```php
use Filament\Forms\Components\Slider;
use Filament\Forms\Components\Enums\SliderDirection;

Slider::make('slider')
->direction(SliderDirection::LTR),
```

## Limit

The `limit()` method sets the maximum distance between the handles:

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->connect(true)
->step(true)
->start([10, 50])
->limit(90)
->range(['min' => 0, 'max' => 200]),
```
In order to use this method you need at least 2 handles.

## Margin

The `margin()` method sets the minimum distance between the handles:
```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->connect(true)
->step(true)
->start([10, 50])
->margin(90)
->range(['min' => 0, 'max' => 200]),
```

## Padding

The `padding()` method limits how close to the slider edges handles can be.

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->start([20, 80])
->padding([10,15])
->range(['min' => 0, 'max' => 100]),
```

## Tooltips

You can add and even format tooltips to the slider handles:

<AutoScreenshot name="forms/fields/slider/tooltips" alt="Slider" version="4.x" />

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->connect(true)
->tooltips(true)
->format(RawJs::make(<<<'JS'
wNumb({decimals: 1})
JS))
->start([50, 150])
->range(['min' => 0, 'max' => 200]),
```

If you would like to use Aria format for the tooltips, you should use the `ariaFormat()` method:

```php
use Filament\Forms\Components\Slider;

Slider::make('slider')
->connect(true)
->tooltips(true)
->ariaFormat(RawJs::make(<<<'JS'
wNumb({decimals: 3})
JS))
->start([50, 150])
->range(['min' => 0, 'max' => 200]),
```

5 changes: 5 additions & 0 deletions packages/forms/resources/css/components/slider.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import 'nouislider/dist/nouislider.css';

.noUi-connect {
@apply bg-primary-600 opacity-100;
}
60 changes: 60 additions & 0 deletions packages/forms/resources/js/components/slider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import noUiSlider from 'nouislider'
import wNumb from 'wnumb'

// Expose wNumb library to the window object
window.wNumb = wNumb

export default function sliderFormComponent({
state,
range,
step,
start,
margin,
limit,
padding,
connect,
direction,
orientation,
behaviour,
tooltips,
format,
pips,
ariaFormat,
}) {
return {
state,

slider: null,

init: function () {
this.slider = noUiSlider.create(this.$el, {
start: start,
range: range,
step: step,
margin: margin,
limit: limit,
padding: padding,
connect: connect,
direction: direction,
orientation: orientation,
behaviour: behaviour,
tooltips: tooltips,
format: format,
pips: pips,
ariaFormat: ariaFormat,
})

// Set the initial value of the slider
if (![null, undefined, ''].includes(this.state)) {
this.slider.set(this.state)
}

this.slider.on(
'update',
(values, handle, unencoded, tap, positions, noUiSlider) => {
this.state = values ?? null
},
)
},
}
}
1 change: 1 addition & 0 deletions packages/forms/resources/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import '../css/components/file-upload.css'
import '../css/components/markdown-editor.css'
import '../css/components/rich-editor.css'
import '../css/components/select.css'
import '../css/components/slider.css'
import '../css/components/tags-input.css'
59 changes: 59 additions & 0 deletions packages/forms/resources/views/components/slider.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@php
use Filament\Support\Facades\FilamentView;

$id = $getId();
$statePath = $getStatePath();
$range = $getRange();
$step = $getStep();
$start = $getStart();
$margin = $getMargin();
$limit = $getLimit();
$padding = $getPadding();
$connect = $getConnect();
$direction = $getDirection();
$orientation = $getOrientation();
$behaviour = $getBehaviour();
$tooltips = $getTooltips();
$format = $getFormat();
$pips = $getPips();
$ariaFormat = $getAriaFormat();
@endphp

<x-dynamic-component :component="$getFieldWrapperView()" :field="$field">
<div
{{-- Set dimensions! Vertical sliders don't assume a default height, so a height needs to be set. --}}
{{-- Set margin bottom when orientation is horizontal due to nouislider bug --}}
@class([
'h-40' => $orientation === Filament\Forms\Components\Enums\SliderOrientation::Vertical->value,
'mb-8' => $orientation === Filament\Forms\Components\Enums\SliderOrientation::Horizontal->value,
])
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('slider', 'filament/forms') }}"
x-data="sliderFormComponent({
state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$statePath}')") }},
range: @js($range),
step: @js($step),
start: @js($start),
margin: @js($margin),
limit: @js($limit),
padding: @js($padding),
connect: @js($connect),
direction: @js($direction),
orientation: @js($orientation),
behaviour: @js($behaviour),
tooltips: @js($tooltips),
format: @js($format),
pips: @js($pips),
ariaFormat: @js($ariaFormat),
})"
{{
$attributes
->merge([
'disabled' => $isDisabled(),
'wire:target' => $statePath,
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
}}
></div>
</x-dynamic-component>
Loading