Add checkbox component and add error handling to fancy form fields
This commit is contained in:
parent
b312ac68c8
commit
f7967d6319
6 changed files with 99 additions and 12 deletions
|
@ -22,6 +22,7 @@
|
|||
<style>
|
||||
img {
|
||||
width: 22px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
div {
|
||||
font-size: var(--font-size-l);
|
||||
|
|
62
packages/bbui/src/FancyForm/FancyCheckbox.svelte
Normal file
62
packages/bbui/src/FancyForm/FancyCheckbox.svelte
Normal file
|
@ -0,0 +1,62 @@
|
|||
<script>
|
||||
import { createEventDispatcher, getContext, onMount } from "svelte"
|
||||
import FancyField from "./FancyField.svelte"
|
||||
import Checkbox from "../Form/Core/Checkbox.svelte"
|
||||
|
||||
export let value
|
||||
export let text
|
||||
export let disabled = false
|
||||
export let error = null
|
||||
export let validate = null
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const formContext = getContext("fancy-form")
|
||||
const id = Math.random()
|
||||
|
||||
const onChange = () => {
|
||||
const newValue = !value
|
||||
dispatch("change", newValue)
|
||||
value = newValue
|
||||
if (validate) {
|
||||
error = validate(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
const API = {
|
||||
validate: () => {
|
||||
if (validate) {
|
||||
error = validate(value)
|
||||
}
|
||||
return !error
|
||||
},
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (formContext) {
|
||||
formContext.registerField(id, API)
|
||||
}
|
||||
return () => {
|
||||
if (formContext) {
|
||||
formContext.unregisterField(id)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<FancyField {error} {disabled} clickable on:click={onChange}>
|
||||
<span>
|
||||
<Checkbox {disabled} {value} />
|
||||
</span>
|
||||
{#if text}
|
||||
{text}
|
||||
{/if}
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
</FancyField>
|
||||
|
||||
<style>
|
||||
span {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
|
@ -1,4 +1,6 @@
|
|||
<script>
|
||||
import Icon from "../Icon/Icon.svelte"
|
||||
|
||||
export let disabled = false
|
||||
export let error = null
|
||||
export let focused = false
|
||||
|
@ -13,7 +15,14 @@
|
|||
class:clickable
|
||||
>
|
||||
<div class="content" on:click>
|
||||
<slot />
|
||||
<div class="field">
|
||||
<slot />
|
||||
</div>
|
||||
{#if error}
|
||||
<div class="error-icon">
|
||||
<Icon name="Alert" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if error}
|
||||
<div class="error-message">
|
||||
|
@ -53,14 +62,20 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
.content {
|
||||
position: relative;
|
||||
height: 64px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.content,
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
position: relative;
|
||||
gap: 10px;
|
||||
}
|
||||
.field {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.error-message {
|
||||
background: var(--spectrum-global-color-red-400);
|
||||
|
@ -69,4 +84,10 @@
|
|||
padding: 6px 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.error-icon {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.error-icon :global(.spectrum-Icon) {
|
||||
fill: var(--spectrum-global-color-red-400);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { createEventDispatcher, getContext, onMount } from "svelte"
|
||||
import FancyField from "./FancyField.svelte"
|
||||
import Icon from "../Icon/Icon.svelte"
|
||||
|
||||
export let label
|
||||
export let value
|
||||
|
@ -29,8 +30,6 @@
|
|||
validate: () => {
|
||||
if (validate) {
|
||||
error = validate(value)
|
||||
} else {
|
||||
error = null
|
||||
}
|
||||
return !error
|
||||
},
|
||||
|
@ -69,25 +68,25 @@
|
|||
.label {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transform: translateY(-12px);
|
||||
transform: translateY(calc(-50% - 12px));
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
transition: font-size 130ms ease-out, transform 130ms ease-out;
|
||||
}
|
||||
.label.placeholder {
|
||||
font-size: 15px;
|
||||
transform: translateY(0);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
input {
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
transition: transform 130ms ease-out;
|
||||
transform: translateY(9px);
|
||||
background: transparent;
|
||||
font-size: 15px;
|
||||
color: var(--spectrum-global-color-gray-900);
|
||||
outline: none;
|
||||
border: none;
|
||||
transition: transform 130ms ease-out;
|
||||
width: 100%;
|
||||
transform: translateY(9px);
|
||||
}
|
||||
input.placeholder {
|
||||
transform: translateY(0);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export { default as FancyInput } from "./FancyInput.svelte"
|
||||
export { default as FancyCheckbox } from "./FancyCheckbox.svelte"
|
||||
export { default as FancyButton } from "./FancyButton.svelte"
|
||||
export { default as FancyForm } from "./FancyForm.svelte"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import "@spectrum-css/link/dist/index-vars.css"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let href = "#"
|
||||
export let size = "M"
|
||||
|
@ -9,10 +10,12 @@
|
|||
export let overBackground = false
|
||||
export let target
|
||||
export let download
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<a
|
||||
on:click
|
||||
on:click={e => e.stopPropagation() && dispatch(e)}
|
||||
{href}
|
||||
{target}
|
||||
{download}
|
||||
|
|
Loading…
Reference in a new issue