forked from tsai/budibase
8 changed files with 233 additions and 2 deletions
@ -0,0 +1,172 @@ |
|||||
|
<script> |
||||
|
import "@spectrum-css/textfield/dist/index-vars.css" |
||||
|
import "@spectrum-css/actionbutton/dist/index-vars.css" |
||||
|
import "@spectrum-css/stepper/dist/index-vars.css" |
||||
|
import { createEventDispatcher } from "svelte" |
||||
|
|
||||
|
export let value = null |
||||
|
export let placeholder = null |
||||
|
export let disabled = false |
||||
|
export let error = null |
||||
|
export let id = null |
||||
|
export let readonly = false |
||||
|
export let updateOnChange = true |
||||
|
export let quiet = false |
||||
|
export let min |
||||
|
export let max |
||||
|
export let step |
||||
|
|
||||
|
const dispatch = createEventDispatcher() |
||||
|
let focus = false |
||||
|
|
||||
|
// We need to keep the field value bound to a different variable in order |
||||
|
// to properly handle erroneous values. If we don't do this then it is |
||||
|
// possible for the field to show stale text which does not represent the |
||||
|
// real value. The reactive statement is to ensure that external changes to |
||||
|
// the value prop are reflected. |
||||
|
let fieldValue = value |
||||
|
$: fieldValue = value |
||||
|
|
||||
|
// Ensure step is always a numeric value defaulting to 1 |
||||
|
$: step = step == null || isNaN(step) ? 1 : step |
||||
|
|
||||
|
const updateValue = value => { |
||||
|
if (readonly) { |
||||
|
return |
||||
|
} |
||||
|
const float = parseFloat(value) |
||||
|
value = isNaN(float) ? null : float |
||||
|
if (value != null) { |
||||
|
if (min != null && value < min) { |
||||
|
value = min |
||||
|
} else if (max != null && value > max) { |
||||
|
value = max |
||||
|
} |
||||
|
} |
||||
|
dispatch("change", value) |
||||
|
fieldValue = value |
||||
|
} |
||||
|
|
||||
|
const onFocus = () => { |
||||
|
if (readonly) { |
||||
|
return |
||||
|
} |
||||
|
focus = true |
||||
|
} |
||||
|
|
||||
|
const onBlur = event => { |
||||
|
if (readonly) { |
||||
|
return |
||||
|
} |
||||
|
focus = false |
||||
|
updateValue(event.target.value) |
||||
|
} |
||||
|
|
||||
|
const onInput = event => { |
||||
|
if (readonly || !updateOnChange) { |
||||
|
return |
||||
|
} |
||||
|
updateValue(event.target.value) |
||||
|
} |
||||
|
|
||||
|
const updateValueOnEnter = event => { |
||||
|
if (readonly) { |
||||
|
return |
||||
|
} |
||||
|
if (event.key === "Enter") { |
||||
|
updateValue(event.target.value) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const stepUp = () => { |
||||
|
if (value == null || isNaN(value)) { |
||||
|
updateValue(step) |
||||
|
} else { |
||||
|
updateValue(value + step) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const stepDown = () => { |
||||
|
if (value == null || isNaN(value)) { |
||||
|
updateValue(step) |
||||
|
} else { |
||||
|
updateValue(value - step) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<div |
||||
|
class="spectrum-Stepper" |
||||
|
class:spectrum-Stepper--quiet={quiet} |
||||
|
class:is-invalid={!!error} |
||||
|
class:is-disabled={disabled} |
||||
|
class:is-focused={focus} |
||||
|
> |
||||
|
{#if error} |
||||
|
<svg |
||||
|
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Textfield-validationIcon" |
||||
|
focusable="false" |
||||
|
aria-hidden="true" |
||||
|
> |
||||
|
<use xlink:href="#spectrum-icon-18-Alert" /> |
||||
|
</svg> |
||||
|
{/if} |
||||
|
|
||||
|
<div class="spectrum-Textfield spectrum-Stepper-textfield"> |
||||
|
<input |
||||
|
{disabled} |
||||
|
{readonly} |
||||
|
{id} |
||||
|
bind:value={fieldValue} |
||||
|
placeholder={placeholder || ""} |
||||
|
type="number" |
||||
|
class="spectrum-Textfield-input spectrum-Stepper-input" |
||||
|
on:click |
||||
|
on:blur |
||||
|
on:focus |
||||
|
on:input |
||||
|
on:keyup |
||||
|
on:blur={onBlur} |
||||
|
on:focus={onFocus} |
||||
|
on:input={onInput} |
||||
|
on:keyup={updateValueOnEnter} |
||||
|
/> |
||||
|
</div> |
||||
|
<span class="spectrum-Stepper-buttons"> |
||||
|
<button |
||||
|
class="spectrum-ActionButton spectrum-ActionButton--sizeM spectrum-Stepper-stepUp" |
||||
|
tabindex="-1" |
||||
|
on:click={stepUp} |
||||
|
> |
||||
|
<svg |
||||
|
class="spectrum-Icon spectrum-UIIcon-ChevronUp75" |
||||
|
focusable="false" |
||||
|
aria-hidden="true" |
||||
|
> |
||||
|
<use xlink:href="#spectrum-css-icon-Chevron75" /> |
||||
|
</svg> |
||||
|
</button> |
||||
|
<button |
||||
|
class="spectrum-ActionButton spectrum-ActionButton--sizeM spectrum-Stepper-stepDown" |
||||
|
tabindex="-1" |
||||
|
on:click={stepDown} |
||||
|
> |
||||
|
<svg |
||||
|
class="spectrum-Icon spectrum-UIIcon-ChevronDown75" |
||||
|
focusable="false" |
||||
|
aria-hidden="true" |
||||
|
> |
||||
|
<use xlink:href="#spectrum-css-icon-Chevron75" /> |
||||
|
</svg> |
||||
|
</button> |
||||
|
</span> |
||||
|
</div> |
||||
|
|
||||
|
<style> |
||||
|
.spectrum-Stepper { |
||||
|
width: 100%; |
||||
|
} |
||||
|
.spectrum-Stepper::before { |
||||
|
display: none; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,45 @@ |
|||||
|
<script> |
||||
|
import Field from "./Field.svelte" |
||||
|
import Stepper from "./Core/Stepper.svelte" |
||||
|
import { createEventDispatcher } from "svelte" |
||||
|
|
||||
|
export let value = null |
||||
|
export let label = null |
||||
|
export let labelPosition = "above" |
||||
|
export let placeholder = null |
||||
|
export let disabled = false |
||||
|
export let readonly = false |
||||
|
export let error = null |
||||
|
export let updateOnChange = true |
||||
|
export let quiet = false |
||||
|
export let min = null |
||||
|
export let max = null |
||||
|
export let step = 1 |
||||
|
|
||||
|
const dispatch = createEventDispatcher() |
||||
|
const onChange = e => { |
||||
|
value = e.detail |
||||
|
dispatch("change", e.detail) |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<Field {label} {labelPosition} {error}> |
||||
|
<Stepper |
||||
|
{updateOnChange} |
||||
|
{error} |
||||
|
{disabled} |
||||
|
{readonly} |
||||
|
{value} |
||||
|
{placeholder} |
||||
|
{quiet} |
||||
|
{min} |
||||
|
{max} |
||||
|
{step} |
||||
|
on:change={onChange} |
||||
|
on:click |
||||
|
on:input |
||||
|
on:blur |
||||
|
on:focus |
||||
|
on:keyup |
||||
|
/> |
||||
|
</Field> |
||||
Loading…
Reference in new issue