Skip to content

Commit

Permalink
Add range controller
Browse files Browse the repository at this point in the history
  • Loading branch information
justalever committed Oct 18, 2024
1 parent 3487cde commit 5ad725d
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ application.register('railsui-tooltip', RailsuiTooltip)
- [Date range picker](docs/date_range_picker.md)
- [Dropdown](docs/dropdown.md)
- [Modal](docs/modal.md)
- [Range](docs/range.md)
- [Select all](docs/select_all.md)
- [Tab](docs/tab.md)
- [Toast](docs/toast.md)
Expand Down
4 changes: 2 additions & 2 deletions dist/railsui-stimulus.cjs

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/railsui-stimulus.cjs.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/railsui-stimulus.module.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions dist/railsui-stimulus.module.js.map

Large diffs are not rendered by default.

146 changes: 146 additions & 0 deletions docs/range.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Range

Customize range inputs with CSS and Javascript. This is a simple example of how you can style a range input with CSS.

## Usage

```javascript
import { RailsuiRange } from 'railsui-stimulus'
application.register('railsui-range', RailsuiRange)
```

### Input trigger

```html
<div class="form-group" data-controller="railsui-range">
<label for="volume" class="text-sm font-medium mb-1 block">Volume</label>
<input
type="range"
id="volume"
class="form-input-range"
data-railsui-range-target="range"
data-action="input->railsui-range#onInput"
min="2"
max="100"
value="25"
/>
</div>
```

For this to work we'll need to add a custom CSS variable to our CSS that the controller can manipulate based on event listeners. This variable will be used to set the width of the range input's fill which ultimately is a gradient. This is a simple example of how you can style a range input with CSS.

Browsers handle range inputs differently so the amount of CSS we need to write is different for each browser. Sucks but necessary!

```css
.form-input-range {
position: relative;
background: transparent;
appearance: none;

--range-fill: 0;
}

.form-input-range::-webkit-slider-thumb {
appearance: none;
border: 2px solid white;
width: 16px;
height: 16px;
border-radius: 100%;
background: white;
cursor: pointer;
position: relative;
top: -4.5px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
outline: 1px solid rgba(0, 0, 0, 0.25);
}

.form-input-range::-moz-range-thumb {
appearance: none;
border: 2px solid white;
width: 16px;
height: 16px;
border-radius: 100%;
background: white;
cursor: pointer;
position: relative;
top: -4.5px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
outline: 1px solid rgba(0, 0, 0, 0.25);
}

.form-input-range::-ms-thumb {
appearance: none;
border: 2px solid white;
width: 16px;
height: 16px;
border-radius: 100%;
background: white;
cursor: pointer;
position: relative;
top: -4.5px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
outline: 1px solid rgba(0, 0, 0, 0.25);
}

.form-input-range::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
border-radius: 10px;
cursor: pointer;
background: linear-gradient(to right, #22c55e var(--range-fill), #d1d5db var(--range-fill));

@media (prefers-color-scheme: dark) {
background: linear-gradient(to right, #22c55e var(--range-fill), #374151 var(--range-fill));
}
}

.form-input-range::-moz-range-track {
width: 100%;
height: 4px;
border-radius: 10px;
cursor: pointer;
background: linear-gradient(to right, #22c55e var(--range-fill), #d1d5db var(--range-fill));

@media (prefers-color-scheme: dark) {
background: linear-gradient(to right, #22c55e var(--range-fill), #374151 var(--range-fill));
}
}

.form-input-range::-ms-track {
width: 100%;
height: 4px;
border-radius: 10px;
cursor: pointer;
background: linear-gradient(to right, #22c55e var(--range-fill), #d1d5db var(--range-fill));

@media (prefers-color-scheme: dark) {
background: linear-gradient(to right, #22c55e var(--range-fill), #374151 var(--range-fill));
}
}
```

Here's the meat and potatoes of the controller.

```javascript
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['range']

connect() {
this.updateTrack() // Set initial track based on value
}

updateTrack() {
const value =
((this.rangeTarget.value - this.rangeTarget.min) /
(this.rangeTarget.max - this.rangeTarget.min)) *
100
this.rangeTarget.style.setProperty('--range-fill', `${value}%`)
}

onInput() {
this.updateTrack() // Update track when input changes
}
}
```
120 changes: 119 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

<script type="module">
import { Application } from "@hotwired/stimulus"
import { RailsuiClipboard, RailsuiCountUp, RailsuiDateRangePicker, RailsuiDropdown, RailsuiModal, RailsuiSelectAll, RailsuiTabs, RailsuiToast, RailsuiToggle, RailsuiTooltip } from "railsui-stimulus";
import { RailsuiClipboard, RailsuiCountUp, RailsuiDateRangePicker, RailsuiDropdown, RailsuiModal, RailsuiRange, RailsuiSelectAll, RailsuiTabs, RailsuiToast, RailsuiToggle, RailsuiTooltip } from "railsui-stimulus";

(() => {
const application = Application.start()
Expand All @@ -39,6 +39,7 @@
application.register('railsui-date-range-picker', RailsuiDateRangePicker)
application.register('railsui-dropdown', RailsuiDropdown)
application.register('railsui-modal', RailsuiModal)
application.register('railsui-range', RailsuiRange)
application.register('railsui-select-all', RailsuiSelectAll)
application.register('railsui-tabs', RailsuiTabs)
application.register('railsui-toast', RailsuiToast)
Expand Down Expand Up @@ -137,6 +138,10 @@
<a href="#modal"
class="p-2 rounded hover:bg-neutral-100 transition ease-in-out duration-200 block w-full">Modal</a>
</li>
<li>
<a href="#range"
class="p-2 rounded hover:bg-neutral-100 transition ease-in-out duration-200 block w-full">Range slider</a>
</li>
<li>
<a href="#select_all"
class="p-2 rounded hover:bg-neutral-100 transition ease-in-out duration-200 block w-full">Select all</a>
Expand Down Expand Up @@ -359,6 +364,119 @@ <h3 id="modal-title" class="text-2xl font-bold text-neutral-900 tracking-tight">
</div>
</div>

<div id="range" class="md:p-10 p-6 rounded-xl border border-neutral-300/80 bg-white">
<div class="prose mb-6 prose-neutral max-w-full">
<h2 class="text-2xl text-neutral-800 font-semibold mb-4">Range slider</h2>
<p>Range sliders aren't too easy to customize. With custom CSS variables and a dash of JavaScript from the
range controller we can make this more branded.</p>
</div>
<style>
/* Requires range_controller.js */
.form-input-range {
position: relative;
background: transparent;
appearance: none;

--range-fill: 0;
}

.form-input-range::-webkit-slider-thumb {
appearance: none;
border: 2px solid white;
width: 16px;
height: 16px;
border-radius: 100%;
background: white;
cursor: pointer;
position: relative;
top: -4.5px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
outline: 1px solid rgba(0, 0, 0, 0.25);
}

.form-input-range::-moz-range-thumb {
appearance: none;
border: 2px solid white;
width: 16px;
height: 16px;
border-radius: 100%;
background: white;
cursor: pointer;
position: relative;
top: -4.5px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
outline: 1px solid rgba(0, 0, 0, 0.25);
}

.form-input-range::-ms-thumb {
appearance: none;
border: 2px solid white;
width: 16px;
height: 16px;
border-radius: 100%;
background: white;
cursor: pointer;
position: relative;
top: -4.5px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
outline: 1px solid rgba(0, 0, 0, 0.25);
}

.form-input-range::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
border-radius: 10px;
cursor: pointer;
background: linear-gradient(to right,
#22c55e var(--range-fill),
#d1d5db var(--range-fill));

@media (prefers-color-scheme: dark) {
background: linear-gradient(to right,
#22c55e var(--range-fill),
#374151 var(--range-fill));
}
}

.form-input-range::-moz-range-track {
width: 100%;
height: 4px;
border-radius: 10px;
cursor: pointer;
background: linear-gradient(to right,
#22c55e var(--range-fill),
#d1d5db var(--range-fill));

@media (prefers-color-scheme: dark) {
background: linear-gradient(to right,
#22c55e var(--range-fill),
#374151 var(--range-fill));
}
}

.form-input-range::-ms-track {
width: 100%;
height: 4px;
border-radius: 10px;
cursor: pointer;
background: linear-gradient(to right,
#22c55e var(--range-fill),
#d1d5db var(--range-fill));

@media (prefers-color-scheme: dark) {
background: linear-gradient(to right,
#22c55e var(--range-fill),
#374151 var(--range-fill));
}
}
</style>
<div class="form-group" data-controller="railsui-range">
<label for="volume" class="text-sm font-medium mb-1 block">Volume</label>
<input type="range" id="volume" class="form-input-range" data-railsui-range-target="range"
data-action="input->railsui-range#onInput" min="2" max="100" value="25" />
</div>
</div>

<!-- Select all -->
<div id="select_all" class="md:p-10 p-6 rounded-xl border border-neutral-300/80 bg-white">
<div class="prose mb-6 prose-neutral max-w-full">
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { default as RailsuiCountUp } from './railsui_count_up'
export { default as RailsuiDateRangePicker } from './railsui_date_range_picker'
export { default as RailsuiDropdown } from './railsui_dropdown'
export { default as RailsuiModal } from './railsui_modal'
export { default as RailsuiRange } from './railsui_range'
export { default as RailsuiSelectAll } from './railsui_select_all'
export { default as RailsuiTabs } from './railsui_tabs'
export { default as RailsuiToast } from './railsui_toast'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "railsui-stimulus",
"version": "1.0.3",
"version": "1.0.4",
"description": "Rails UI Stimulus.js Components",
"main": "./dist/railsui-stimulus.cjs",
"module": "./dist/railsui-stimulus.module.js",
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { default as RailsuiCountUp } from './railsui_count_up'
export { default as RailsuiDateRangePicker } from './railsui_date_range_picker'
export { default as RailsuiDropdown } from './railsui_dropdown'
export { default as RailsuiModal } from './railsui_modal'
export { default as RailsuiRange } from './railsui_range'
export { default as RailsuiSelectAll } from './railsui_select_all'
export { default as RailsuiTabs } from './railsui_tabs'
export { default as RailsuiToast } from './railsui_toast'
Expand Down
21 changes: 21 additions & 0 deletions src/railsui_range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['range']

connect() {
this.updateTrack() // Set initial track based on value
}

updateTrack() {
const value =
((this.rangeTarget.value - this.rangeTarget.min) /
(this.rangeTarget.max - this.rangeTarget.min)) *
100
this.rangeTarget.style.setProperty('--range-fill', `${value}%`)
}

onInput() {
this.updateTrack() // Update track when input changes
}
}

0 comments on commit 5ad725d

Please sign in to comment.