swaf/src/assets/views/utils/Field.svelte

102 lines
3.8 KiB
Svelte
Raw Normal View History

2021-06-01 16:14:24 +02:00
<script lang="ts">
import {locals} from '../../ts/stores.js';
import Message from "../components/Message.svelte";
import Icon from "./Icon.svelte";
import {getContext} from "svelte";
export let type: string;
export let name: string;
type FieldValue = string | number | Record<string, FieldValue>;
export let value: FieldValue | undefined = undefined;
export let placeholder: string | undefined = undefined;
export let hint: string | undefined = undefined;
export let extraData: string[] | undefined = undefined;
export let icon: string | undefined = undefined;
const formId = getContext('formId');
const fieldId = `${formId}-${name}-field`;
const validation = $locals.validation()?.[name];
const previousFormData = $locals.previousFormData() || [];
value = type !== 'hidden' && previousFormData[name] || value || validation?.value || '';
function durationValue(f: string): number {
if (previousFormData[name]) {
return value[f];
}
switch (f) {
case 's':
return value % 60;
case 'm':
return (value - value % 60) / 60 % 60;
case 'h':
return (value - value % 3600) / 3600;
default:
return 0;
}
}
function handleInput(e) {
// in here, you can switch on type and implement
// whatever behaviour you need
value = type.match(/^(number|range)$/)
? +e.target.value
: e.target.value;
}
</script>
{#if type === 'hidden'}
{#if validation}
<Message type="error" content={validation.message}/>
{/if}
<input type="hidden" name={name} value={value}>
{:else}
<div class="form-field" class:inline={type === 'checkbox'}>
<div class="control">
{#if icon}
<Icon name={icon}/>
{/if}
{#if type === 'duration'}
<div class="input-group">
{#each extraData as f}
<div class="time-input">
<input type="number" name="{name}[{f}]" id="{fieldId}-{f}"
value={durationValue(f)}
min="0" max={(f === 's' || f === 'm') && '60' || undefined}
{...$$restProps}>
<label for="{fieldId}-{f}">{{ f }}</label>
</div>
{/each}
</div>
{:else if type === 'select'}
<select name={name} id={fieldId} {...$$restProps} on:input={handleInput}>
{#each extraData as option}
<option value={(option.display === undefined || option.value !== undefined) && (option.value || option)}
selected={value === (option.value || option)}>{option.display || option}</option>
{/each}
</select>
<i data-feather="chevron-down"></i>
{:else if type === 'textarea'}
<textarea {name} id={fieldId} bind:value={value} {...$$restProps}></textarea>
{:else if type === 'checkbox'}
<input {type} {name} id={fieldId} checked={value === 'on'} {...$$restProps}>
{:else}
<input {type} {name} id={fieldId} {value} {...$$restProps} on:input={handleInput}>
{/if}
<label for="{fieldId}{type === 'duration' && '-' + extraData[0] || ''}">{@html placeholder || ''}<slot/></label>
</div>
{#if validation}
<div class="error"><i data-feather="x-circle"></i> {validation.message}</div>
{/if}
{#if hint}
<div class="hint"><i data-feather="info"></i> {hint}</div>
{/if}
</div>
{/if}