Skip to content

Commit

Permalink
Merge pull request #1 from jantinnerezo/feature/wire-attribute
Browse files Browse the repository at this point in the history
Wire attributes
  • Loading branch information
jantinnerezo authored Oct 11, 2021
2 parents 4584caf + e60ad5e commit 4c7b4b0
Show file tree
Hide file tree
Showing 13 changed files with 343 additions and 87 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
.idea
.DS_Store
composer.lock
.phpunit.result.cache
.phpunit.result.cache
/build
173 changes: 121 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,71 +1,140 @@
## Livewire Range Slider

## Installation
A simple [noUiSlider](https://github.com/leongersen/noUiSlider) blade component for your Livewire Components.

To get started, you need to add this into the repositories array of your project's composer.json.
![preview](https://banners.beyondco.de/Livewire%20Range%20Slider.jpeg?theme=light&packageManager=composer+require&packageName=jantinnerezo%2Flivewire-range-slider&pattern=tinyCheckers&style=style_1&description=A+simple+noUiSlider+blade+component+for+your+Livewire+Components.&md=1&showWatermark=0&fontSize=100px&images=adjustments)

```json
"repositories": [
{
"type": "vcs",
"url": "https://github.com/jantinnerezo/livewire-range-slider.git"
}
],
### Installation

To get started, you need to require the package to your project's composer.json

```bash
composer require jantinnerezo/livewire-range-slider
```
And then require the package.

Next, simply add the component to your template after the ``@livewireScripts``.

```html
<html>
<body>
<!-- @livewireScripts -->

<x-livewire-range-slider::scripts />
</body>
</html>
```
composer require jantinnerezo/livewire-range-slider

### Requirements

This package is meant to use with [Livewire](https://laravel-livewire.com/) components. Make sure you are using it with Livewire projects only.

- PHP 7.4 or higher

- [Laravel 8](https://laravel.com/docs/8.x/installation)

- [Livewire](https://laravel-livewire.com/)

- [Alpine](https://alpinejs.dev)

- [noUiSlider](https://github.com/leongersen/noUiSlider) - already included into the package's bundled scripts.



### Usage

Assuming you have this properties inside your livewire component.

```php

public $options = [
'start' => [
10,
20
],
'range' => [
'min' => [1],
'max' => [100]
],
'connect' => true,
'behaviour' => 'tap-drag',
'tooltips' => true,
'pips' => [
'mode' => 'steps',
'stepped' => true,
'density' => 4
]
];

public $values = [];
```
Next, add `<x-livewire-range-slider::scripts />` component after the other app scripts.

```blade
@livewireScripts
<x-livewire-range-slider::scripts />
```
The `$options` property is simply the noUiSlider options you pass to the component, for more details and configurations please check [noUiSlider - JavaScript Range Slider | Refreshless.com](https://refreshless.com/nouislider/).

## Alpine
Livewire Range Slider requires [Alpine](https://github.com/alpinejs/alpine). You can use the official CDN to quickly include Alpine:
The `$values` property is the model for the range slider values.

```html
<!-- Alpine v2 -->
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js" defer></script>

<!-- Alpine v3 -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>

###### Livewire's default ``wire:model`` attribute

```html
<x-range-slider :options="$options" wire:model="values" />
```

## Usage
######

###### Debouncing

If you want to avoid too many network requests, ``.debounce`` modifier works out-of-the-box.

```blade
<x-livewire-range-slider::range-slider
:options="$options"
wire:model="values"
```html
<x-range-slider
    :options="$options"
    wire:model.debounce.500ms="values"
/>
```

## Customization
Styling makes it easy using Tailwind CSS. `resources/js/range-slider/theming.js`
```javascript
const plugin = require('tailwindcss/plugin');

module.exports = plugin(function({ addComponents, theme }) {
const components = {
'.noUi-target': { },
'.noUi-base': { }.
'.noUi-origin': { },
'.noUi-handle': { },
'.noUi-touch-area': { },
'.noUi-connect': { },
'.noUi-state-tap': { }
}
addComponents(components);
});
```

And require plugin into the `tailwind.config.js`:

``` javascript
plugins: [
require('./resources/js/range-slider/theming.js')
],

###### Deferred

In cases where you don't need range slider to live, you can use`.defer` modifier.

```html
<x-range-slider :options="$options" wire:model.defer="values" />
```

###### Multiple properties

Assigning a property for each handle also works out-of-the-box, simply add the properties to `wire:models` comma separated.

```php

public $options = [
'start' => [
10,
20
],
'range' => [
'min' => [1],
'max' => [100]
],
'connect' => true,
'behaviour' => 'tap-drag',
'tooltips' => true,
'pips' => [
'mode' => 'steps',
'stepped' => true,
'density' => 4
]
];

public $handle1;

public $handle2;
```

``` html
<x-range-slider :options="$options" wire:models="handle1,handle2" />
```

Make sure the start array length and number of properties are matched.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
},
"require-dev": {
"orchestra/testbench": "^6.0",
"phpunit/phpunit": "^9.0"
"phpunit/phpunit": "^9.0",
"livewire/livewire": "^2.4"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion dist/range-slider.js

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
</phpunit>
60 changes: 39 additions & 21 deletions resources/js/range-slider.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,54 @@
import noUiSlider from 'nouislider';
import 'nouislider/dist/nouislider.css'

const LAZY = 'lazy';
const IMMEDIATE = 'immediate';
const UNDEFINED_MODEL = 'undefined_model';

window.LivewireRangeSlider = function (data) {
window.LivewireRangeSliderDevelop = function (data) {
return {
rangeSlider: null,
model: null,
handling: null,
init() {
models: [],
model: UNDEFINED_MODEL,
dispatch: null,
init($dispatch) {
this.dispatch = $dispatch;

this.setup();

if (this.isLazy() || this.hasModels()) {
this.rangeSlider.on('change',
(values, handle) => this.handleChange(values, handle)
);

return;
}

this.rangeSlider.on('update',
(values) => this.handleUpdate(values)
);
},
setup() {
noUiSlider.create(this.$refs.range, {
...data.options
})

this.rangeSlider = this.$refs.range.noUiSlider;

if (this.handling == LAZY) {
this.rangeSlider.on('change', (values, handle) => {
this.$wire.set(this.model, values);
});
}

if (this.handling == IMMEDIATE) {
this.rangeSlider.on('update', (values, handle) => {
this.$wire.set(this.model, values);
});
}
},
getValues() {
this.$wire.set(this.model, this.$refs.range.noUiSlider.get());
handleUpdate(values) {
this.dispatch('input', values);
},
isLazy() {
return this.model !== UNDEFINED_MODEL;
},
hasModels() {
return this.models.length === this.options.start.length;
},
handleChange(values, handle) {
if (this.isLazy()) {
this.$wire.set(this.model, values);
} else {
this.$wire.set(this.models[handle], values[handle]);
}
},
...data
}
}
}
25 changes: 19 additions & 6 deletions resources/views/components/range-slider.blade.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
@props(['options' => [], 'handling' => null])
@php
$count = count($options['start']);
$modelsCount = count($getWireModels($attributes));
if ($missingWireModelAttributes($attributes)) {
throw new \Jantinnerezo\LivewireRangeSlider\Exceptions\RangeSliderException('Missing wire:model or wire:models attribute.');
}
<div
x-data='LivewireRangeSlider({
if ($notEnoughModels($attributes)) {
throw new \Jantinnerezo\LivewireRangeSlider\Exceptions\RangeSliderException(
"Properties you provided on wire:models did not match with the number of handles. Expected models count: {$count} received {$modelsCount} "
);
}
@endphp
<div
x-data='LivewireRangeSliderDevelop({
options: {!! json_encode($options) !!},
model: "{{ $attributes->get('wire:model') }}",
handling: "{{ $handling }}",
models: {!! json_encode($getWireModels($attributes)) !!},
model: "{{ $getWireModel($attributes) }}"
})'
x-init="init()"
x-init="init($dispatch)"
{{ $attributes }}
wire:ignore
>
<div x-ref="range"></div>
Expand Down
7 changes: 6 additions & 1 deletion resources/views/components/scripts.blade.php
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
@include('livewire-range-slider::script-renderer')
@isset($jsPath)
<script>
/**** Livewire Range Slider Scripts ****/
{!! file_get_contents($jsPath) !!}
</script>
@endisset
3 changes: 0 additions & 3 deletions resources/views/script-renderer.blade.php

This file was deleted.

21 changes: 21 additions & 0 deletions src/Exceptions/RangeSliderException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Jantinnerezo\LivewireRangeSlider\Exceptions;

use Exception;

class RangeSliderException extends Exception
{
protected $message;

public function __construct($message)
{
$this->message = $message;

parent::__construct();
}

public function __toString() {
return "Livewire Range Slider Component Exception: {$this->message}";
}
}
Loading

0 comments on commit 4c7b4b0

Please sign in to comment.