Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bohnacker/svelte-number-spinner
Svelte UI component: a number input field that can be controlled with mouse and keyboard
https://github.com/bohnacker/svelte-number-spinner
input number-input svelte svelte-components ui
Last synced: 30 days ago
JSON representation
Svelte UI component: a number input field that can be controlled with mouse and keyboard
- Host: GitHub
- URL: https://github.com/bohnacker/svelte-number-spinner
- Owner: bohnacker
- License: mit
- Created: 2021-01-22T14:36:17.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2024-05-15T11:42:07.000Z (8 months ago)
- Last Synced: 2024-11-11T23:36:00.759Z (about 2 months ago)
- Topics: input, number-input, svelte, svelte-components, ui
- Language: Svelte
- Homepage:
- Size: 905 KB
- Stars: 29
- Watchers: 3
- Forks: 5
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# svelte-number-spinner
![Number Spinner](NumberSpinner.gif)
A highly configurable number spinner component for Svelte. It's a simple input field with a number that can be controlled using the mouse or keyboard. Pressing *Alt* or *Alt+Shift* makes steps smaller or bigger. Clicking on the input field without dragging the mouse or pressing *Enter* or any other non-control key like *-*, *1*, *2*, *3*, ... starts the normal input mode.
#### New since version 0.6.0
Mobile devices with touch are now also supported which needed some major rework. I had to remove the option to select between double click or simple click to start editing. Now, only simple click is possible.## Demo
[Simple example using number spinners for choosing a color](https://svelte.dev/repl/48e956986ed54c28888095d5c463f554?version=3.44.3)
[Number spinner demo showing all options](https://svelte.dev/repl/a73eaa408b804beb9f7a3457926f9829?version=3.31.2)
## Installation
```bash
npm install svelte-number-spinner
```## Usage
```svelte
import NumberSpinner from "svelte-number-spinner";
let value = 50;
```
## Props
| Prop | Type | Default | Description |
|---------------|----------|--------------|-----------------------------------------------------|
| value | Number | 0 | Input value |
| min | Number | -1e12 | Minimum value |
| max | Number | +1e12 | Maximum value |
| step | Number | 1 | Step |
| precision | Number | = step | Precision of value (should be a fraction of step) |
| speed | Number | 1 | Speed of value change on mouse drag |
| keyStep | Number | = step * 10 | Step for keyboard interaction |
| keyStepSlow | Number | = step | Slow step for keyboard interaction |
| keyStepFast | Number | = step * 100 | Fast step for keyboard interaction |
| decimals | Number | 0 | Number of decimals |
| format | Function | undefined | Function to format value |
| parse | Function | undefined | Function to parse formatted string back to value |
| horizontal | Boolean | true | Change value by dragging horizontally |
| vertical | Boolean | false | Change value by dragging vertically |
| circular | Boolean | false | Enable circular range (good for angles, hours, ...) |
| cursor | String | undefined | Individual cursor |
| class | String | undefined | Custom component class name |
| mainStyle | String | undefined | Custom inline style for general appearance |
| focusStyle | String | undefined | Custom inline style when focussed |
| draggingStyle | String | undefined | Custom inline style when dragging |
| editingStyle | String | undefined | Custom inline style when editing |
| fastStyle | String | undefined | Custom inline style for fast mode |
| slowStyle | String | undefined | Custom inline style for slow mode |
| options | Object | {} | Set any of the above props through this object |#### Prop `options`
If you have many number spinners that should have the same props you might want to use the `options` object. This sets all of the given props to the respective value.
The props in the options object are applied when mounting the component. So, changing the options later won't update the props of the number spinner. Plus, the props in the options object will not be modified by the number spinner component. So, `value` should typically not be part of the options.
Example:
```svelte
import NumberSpinner from "svelte-number-spinner";
let value1 = 50;
let value2 = 10;
let options = {horizontal:false, vertical:true}```
## Steps and speed
There are several props that give you control about how you can interact with the value of the number spinner.
By default, dragging the mouse 1 pixel will increase/decrease the value by step. This is usualy quite good. But if have small ranges compared to step (e.g. a range from 0 to 10 with step 1) it's a bit to sensitive to control. In this case set `speed` to a smaller number, e.g. `0.1`.
With keyboard interaction pressing an arrow key increases/decreases the value by 10\*step. In slow mode (holding down *Alt*) default is one step per key stroke and in fast mode (*Alt + Shift*) it's 100\*step. You can change these steps with the props `keyStep`, `keyStepSlow` and `keyStepFast`.
## Formatting numbers
Numbers are displayed as integer values by default. Internally they are handled with the given precision.
Use the prop `decimals` to display floating point numbers.
### Advanced formatting using `format` and `parse`
With the number spinner component you can only control numbers. But you can format this number in any possible way giving a callback function for the prop `format`. In most cases you should also give a reverse function that parses the string and converts it back to the correct number. This is necessary because in edit mode people will probably enter the number as they see it.
In this example the value e.g. 100 is formatted to "$ 100" using the function `addDollar(val)` for formatting and `removeDollar(str)` for parsing it back to a simple number. In fact it returns a string but parseFloat() is done in the number spinner component so you don't have to bother about that.
```svelte
let value = 100;
function addDollar(val) {
return "$ " + val;
}
function removeDollar(str) {
return str.replace("$", "").trim();
}```
### Using format and parse to implement non-linearI found that these two functions could also be used to implement non-linear ranges like exponential/logarithmic scales:
```svelte
Math.pow(10, val).toFixed(1)}
parse={val => Math.log10(val)}
/>
```## Styling
### Styling with custom class name
You can style the component by overriding the default styles by giving a custom class name. If you give your own class name all default styles are removed. So, best would be to take the default styles below, put it in your global css, rename the class and remove and change stuff.
It's recomended to keep the order for `:focus` and `.fast`/`.slow` selectors. Default styles are:
```css
.default {
display: inline-block;
box-sizing: border-box;
font-variant-numeric: tabular-nums;
background-color: white;
color: black;
width: 4em;
height: 1.6em;
margin: 0px;
padding: 0.25em;
border: 0.075em solid #0004;
border-radius: 0.15em;
text-align: right;
vertical-align: baseline;
cursor: ew-resize;
}.default:focus {
border: 0.075em solid #06f;
outline: none; /* removes the standard focus border */
}.default.fast {
border-top-width: 0.15em;
padding-top: 0.175em;
}.default.slow {
border-bottom-width: 0.15em;
padding-bottom: 0.175em;
}.default.dragging {
border-color: #04c;
}.default.editing {
cursor: initial;
}
```### Styling with props
If you want to replace just a few of the styles or add some more without removing the default style, it might be easier for you to use the props `mainStyle`, `focusStyle`, `fastStyle`, `slowStyle`, `draggingStyle` and `editingStyle`.
For each of them you can give a style string like `"width:80px; padding-right:10px"`. In the example below only the font color for fast and slow mode are changed:
```svelte
import NumberSpinner from "svelte-number-spinner";
```
## Events
| Event Name | Callback | Description |
|------------|---------------------|-------------------------------------------------------------------------------------|
| input | (ev) => {ev.detail} | Fires when value changes. ev.detail gives the actual value |
| change | (ev) => {ev.detail} | Fires when value changes, won't fire while typing. ev.detail gives the actual value |
| dragstart | (ev) => {} | Fires when dragging starts |
| dragend | (ev) => {} | Fires when dragging ends |
| editstart | (ev) => {} | Fires when edit mode is started |
| editend | (ev) => {} | Fires when edit mode is ended |
| focus | (ev) => {} | Fires when the number spinner gets the focus |
| blur | (ev) => {} | Fires when the number spinner loses the focus |
| keydown | (ev) => {} | Original keydown event |
| keypress | (ev) => {} | Original keypress event |
| keyup | (ev) => {} | Original keyup event |
```svelte
import NumberSpinner from "svelte-number-spinner";
function handleInput(ev) {
console.log("Value send by input event:", ev.detail);
}function handleChange(ev) {
console.log("Value send by change event:", ev.detail);
}```
In most cases you will probably use ```bind:value``` to react to changes of the value. This is more or less the same as listening to the change event. Use the input event if you need to get the changes while the user is typing.
## Develop
```bash
npm run dev
```This will build the component and start a livereload server for the example.