forked from tsai/budibase
31 changed files with 109 additions and 1026 deletions
@ -1,67 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Checkbox from "./Checkbox.svelte"; |
|
||||
|
|
||||
let checked = false |
|
||||
|
|
||||
let menu = [ |
|
||||
{text: 'Cookies and cream', checked: false}, |
|
||||
{text: 'Mint choc chip', checked: false}, |
|
||||
{text: 'Raspberry ripple', checked: true} |
|
||||
]; |
|
||||
</script> |
|
||||
|
|
||||
<View name="Single checkbox"> |
|
||||
<Checkbox bind:checked value="value"> |
|
||||
<label for="value">One single checkbox with text</label> |
|
||||
</Checkbox> |
|
||||
</View> |
|
||||
|
|
||||
<View name="Single disabled checkbox"> |
|
||||
<Checkbox disabled checked value="value"> |
|
||||
<label for="someOtherValue">A disabled checkbox</label> |
|
||||
</Checkbox> |
|
||||
</View> |
|
||||
|
|
||||
<View name="No text"> |
|
||||
<Checkbox bind:checked value="somevalue" /> |
|
||||
</View> |
|
||||
|
|
||||
## Multiple checkboxes |
|
||||
Use an array and an each block to use multiple checkboxes |
|
||||
```svelte |
|
||||
<script> |
|
||||
let menu = [ |
|
||||
{text: 'Cookies and cream', checked: false}, |
|
||||
{text: 'Mint choc chip', checked: false}, |
|
||||
{text: 'Raspberry ripple', checked: true} |
|
||||
]; |
|
||||
</script> |
|
||||
|
|
||||
{#each menu as {text, checked}} |
|
||||
<Checkbox value={text} bind:checked> |
|
||||
<label for={text}>{text}</label> |
|
||||
</Checkbox> |
|
||||
{/each} |
|
||||
``` |
|
||||
|
|
||||
<View name="Multiple checkboxes"> |
|
||||
<div class="container"> |
|
||||
{#each menu as {text, checked}} |
|
||||
<Checkbox value={text} bind:checked> |
|
||||
<label for={text}>{text}</label> |
|
||||
</Checkbox> |
|
||||
{/each} |
|
||||
</div> |
|
||||
</View> |
|
||||
|
|
||||
<style> |
|
||||
label { |
|
||||
display: grid; |
|
||||
place-items: center; |
|
||||
} |
|
||||
.container { |
|
||||
display: grid; |
|
||||
grid-gap: 10px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -0,0 +1,36 @@ |
|||||
|
<script> |
||||
|
import "@spectrum-css/fieldgroup/dist/index-vars.css" |
||||
|
import "@spectrum-css/radio/dist/index-vars.css" |
||||
|
import { createEventDispatcher } from "svelte" |
||||
|
|
||||
|
export let direction = "vertical" |
||||
|
export let value = null |
||||
|
export let options = [] |
||||
|
export let error = null |
||||
|
export let disabled = false |
||||
|
export let getOptionLabel = option => option |
||||
|
export let getOptionValue = option => option |
||||
|
|
||||
|
const dispatch = createEventDispatcher() |
||||
|
const onChange = e => dispatch("change", e.target.value) |
||||
|
</script> |
||||
|
|
||||
|
<div class={`spectrum-FieldGroup spectrum-FieldGroup--${direction}`}> |
||||
|
{#if options && Array.isArray(options)} |
||||
|
{#each options as option} |
||||
|
<div |
||||
|
class="spectrum-Radio spectrum-FieldGroup-item spectrum-Radio--emphasized" |
||||
|
class:is-invalid={!!error}> |
||||
|
<input |
||||
|
on:change={onChange} |
||||
|
bind:group={value} |
||||
|
value={getOptionValue(option)} |
||||
|
type="radio" |
||||
|
class="spectrum-Radio-input" |
||||
|
{disabled} /> |
||||
|
<span class="spectrum-Radio-button" /> |
||||
|
<label class="spectrum-Radio-label">{getOptionLabel(option)}</label> |
||||
|
</div> |
||||
|
{/each} |
||||
|
{/if} |
||||
|
</div> |
||||
@ -1,57 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Select from "./Select.svelte"; |
|
||||
import DataList from "./DataList.svelte"; |
|
||||
import Spacer from "../Spacer/Spacer.svelte" |
|
||||
|
|
||||
const options = ["Chocolate", "Vanilla", "Strawberry Cheesecake"]; |
|
||||
</script> |
|
||||
|
|
||||
<View name="default"> |
|
||||
<DataList name="Test" label="Flavour"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</DataList> |
|
||||
</View> |
|
||||
|
|
||||
<View name="secondary"> |
|
||||
<DataList secondary name="Test" label="Flavour"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</DataList> |
|
||||
</View> |
|
||||
|
|
||||
<View name="outline"> |
|
||||
<DataList outline name="Test" label="Flavour"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</DataList> |
|
||||
</View> |
|
||||
|
|
||||
<View name="disabled"> |
|
||||
<DataList disabled name="Test" label="Flavour"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</DataList> |
|
||||
</View> |
|
||||
|
|
||||
<View name="thin"> |
|
||||
<DataList thin name="Test" label="Flavour"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</DataList> |
|
||||
</View> |
|
||||
|
|
||||
<View name="extraThin"> |
|
||||
<DataList extraThin name="Test" label="Flavour"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</DataList> |
|
||||
</View> |
|
||||
|
|
||||
@ -1,62 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Input from "./Input.svelte"; |
|
||||
import Button from "../Button/Button.svelte"; |
|
||||
</script> |
|
||||
|
|
||||
<View name="default"> |
|
||||
<Input placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="presentation"> |
|
||||
<Input presentation placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="outline"> |
|
||||
<Input outline placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="disabled"> |
|
||||
<Input disabled placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="disabled with value"> |
|
||||
<Input value="Some text" disabled placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="thin"> |
|
||||
<Input thin placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="extraThin"> |
|
||||
<Input extraThin placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="large"> |
|
||||
<Input large placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="border"> |
|
||||
<Input border presentation placeholder="Enter your name" label="Name" /> |
|
||||
</View> |
|
||||
|
|
||||
|
|
||||
<View name="number"> |
|
||||
<Input type="number" placeholder="Enter your age" label="Age" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="with edit buttons"> |
|
||||
<Input |
|
||||
thin |
|
||||
edit |
|
||||
placeholder="Enter your name" |
|
||||
label="Name" |
|
||||
on:save={console.log} /> |
|
||||
</View> |
|
||||
<View name="with error message"> |
|
||||
<Input |
|
||||
placeholder="Enter your name" |
|
||||
label="Name" |
|
||||
error="This is an error message!" |
|
||||
on:save={console.log} /> |
|
||||
</View> |
|
||||
@ -1,63 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Multiselect from "./Multiselect.svelte"; |
|
||||
|
|
||||
const options = ["Red", "Blue", "Yellow", "Green", "Pink", "Very long color name to show text wrapping"]; |
|
||||
</script> |
|
||||
|
|
||||
<View name="default"> |
|
||||
<Multiselect name="Test" label="Colours" placeholder="Choose some colours"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Multiselect> |
|
||||
</View> |
|
||||
|
|
||||
<View name="right aligned"> |
|
||||
<div class="max-width"> |
|
||||
<Multiselect align="right" name="Test" label="Colours" placeholder="Choose some colours"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Multiselect> |
|
||||
</div> |
|
||||
</View> |
|
||||
|
|
||||
<View name="secondary"> |
|
||||
<Multiselect name="Test" label="Colours" secondary placeholder="Choose some colours"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Multiselect> |
|
||||
</View> |
|
||||
|
|
||||
<View name="outline"> |
|
||||
<Multiselect name="Test" label="Colours" outline placeholder="Choose some colours"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Multiselect> |
|
||||
</View> |
|
||||
|
|
||||
<View name="disabled"> |
|
||||
<Multiselect name="Test" label="Colours" disabled placeholder="Choose some colours"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Multiselect> |
|
||||
</View> |
|
||||
|
|
||||
<View name="extraThin"> |
|
||||
<Multiselect name="Test" label="Colours" extraThin placeholder="Choose some colours"> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Multiselect> |
|
||||
</View> |
|
||||
|
|
||||
<style> |
|
||||
.max-width { |
|
||||
align-self: flex-end; |
|
||||
max-width: 150px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,140 +0,0 @@ |
|||||
<script> |
|
||||
import { createEventDispatcher } from "svelte" |
|
||||
|
|
||||
const dispatch = createEventDispatcher() |
|
||||
|
|
||||
export let value |
|
||||
export let group |
|
||||
export let name |
|
||||
export let disabled = false |
|
||||
|
|
||||
function handleChange() { |
|
||||
if (disabled) return |
|
||||
group = value |
|
||||
dispatch("change", group) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<div class="container"> |
|
||||
<input |
|
||||
{disabled} |
|
||||
on:change={handleChange} |
|
||||
{value} |
|
||||
bind:group |
|
||||
type="radio" |
|
||||
{name} |
|
||||
class="checkbox" |
|
||||
id={value} /> |
|
||||
<div class="checkbox-container" on:click={handleChange}> |
|
||||
<div class:disabled class="check-div" class:checked={group === value}> |
|
||||
<div class="tick_mark" /> |
|
||||
</div> |
|
||||
</div> |
|
||||
<slot /> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.container { |
|
||||
display: flex; |
|
||||
gap: var(--spacing-s); |
|
||||
} |
|
||||
.checkbox-container { |
|
||||
position: relative; |
|
||||
z-index: 0; |
|
||||
} |
|
||||
|
|
||||
.checkbox { |
|
||||
display: none; |
|
||||
} |
|
||||
|
|
||||
.check-div { |
|
||||
position: relative; |
|
||||
width: 20px; |
|
||||
height: 20px; |
|
||||
background-color: var(--grey-2); |
|
||||
cursor: pointer; |
|
||||
transition: 0.2s ease transform, 0.2s ease background-color, |
|
||||
0.2s ease box-shadow; |
|
||||
overflow: hidden; |
|
||||
border-radius: 4px; |
|
||||
} |
|
||||
|
|
||||
.check-div:before { |
|
||||
content: ""; |
|
||||
position: absolute; |
|
||||
top: 50%; |
|
||||
right: 0; |
|
||||
left: 0; |
|
||||
width: 12px; |
|
||||
height: 12px; |
|
||||
margin: 0 auto; |
|
||||
background-color: var(--background); |
|
||||
transform: translateY(-50%); |
|
||||
transition: 0.2s ease width, 0.2s ease height; |
|
||||
border-radius: 2px; |
|
||||
} |
|
||||
|
|
||||
.check-div:active { |
|
||||
transform: translateY(-50%) scale(0.9); |
|
||||
} |
|
||||
|
|
||||
.tick_mark { |
|
||||
position: absolute; |
|
||||
top: 50%; |
|
||||
left: 6px; |
|
||||
width: 5px; |
|
||||
height: 4px; |
|
||||
margin: 0 auto; |
|
||||
transform: rotateZ(-40deg); |
|
||||
} |
|
||||
|
|
||||
.tick_mark:before, |
|
||||
.tick_mark:after { |
|
||||
content: ""; |
|
||||
position: absolute; |
|
||||
background-color: var(--ink); |
|
||||
border-radius: 2px; |
|
||||
opacity: 0; |
|
||||
transition: 0.2s ease transform, 0.2s ease opacity; |
|
||||
} |
|
||||
|
|
||||
.tick_mark:before { |
|
||||
left: 0; |
|
||||
bottom: 0; |
|
||||
width: 2px; |
|
||||
height: 6px; |
|
||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.23); |
|
||||
transform: translateY(-68px); |
|
||||
} |
|
||||
|
|
||||
.tick_mark:after { |
|
||||
left: 0; |
|
||||
bottom: 0; |
|
||||
width: 12px; |
|
||||
height: 2px; |
|
||||
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.23); |
|
||||
transform: translateX(78px); |
|
||||
} |
|
||||
|
|
||||
.check-div.disabled:active { |
|
||||
transform: none; |
|
||||
} |
|
||||
|
|
||||
.checked { |
|
||||
background-color: var(--grey-2); |
|
||||
} |
|
||||
.checked.disabled { |
|
||||
background-color: var(--grey-5); |
|
||||
} |
|
||||
|
|
||||
.checked:before { |
|
||||
width: 0; |
|
||||
height: 0; |
|
||||
} |
|
||||
|
|
||||
.checked .tick_mark:before, |
|
||||
.checked .tick_mark:after { |
|
||||
transform: translate(0); |
|
||||
opacity: 1; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,64 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Radio from "./Radio.svelte"; |
|
||||
|
|
||||
let selected = 'Cookies and cream' |
|
||||
let selected2 = 'Mint choc chip' |
|
||||
|
|
||||
let menu = [ |
|
||||
'Cookies and cream', |
|
||||
'Mint choc chip', |
|
||||
'Raspberry ripple' |
|
||||
]; |
|
||||
</script> |
|
||||
|
|
||||
## Multiple checkboxes |
|
||||
Use an array and an each block to use the radio button. |
|
||||
```svelte |
|
||||
<script> |
|
||||
let selected = 'Cookies and cream' |
|
||||
let selected2 = 'Cookies and cream' |
|
||||
|
|
||||
let menu = [ |
|
||||
'Cookies and cream', |
|
||||
'Mint choc chip', |
|
||||
'Raspberry ripple' |
|
||||
]; |
|
||||
</script> |
|
||||
|
|
||||
{#each menu as flavour} |
|
||||
<Radio name="Ice Cream Flavour" value={flavour} bind:group={selected} label={flavour} showLabel/> |
|
||||
{/each} |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
<View name="Multiple radio buttons"> |
|
||||
<div class="container"> |
|
||||
{#each menu as flavour} |
|
||||
<Radio name="Ice Cream Flavour" value={flavour} bind:group={selected}> |
|
||||
<label for={flavour}>{flavour}</label> |
|
||||
</Radio> |
|
||||
{/each} |
|
||||
</div> |
|
||||
</View> |
|
||||
|
|
||||
<View name="Disabled Radio inputs"> |
|
||||
<div class="container"> |
|
||||
{#each menu as flavour} |
|
||||
<Radio disabled name="Ice Cream Flavour" value={flavour} bind:group={selected2}> |
|
||||
<label for={flavour}>{flavour}</label> |
|
||||
</Radio> |
|
||||
{/each} |
|
||||
</div> |
|
||||
</View> |
|
||||
|
|
||||
<style> |
|
||||
label { |
|
||||
display: grid; |
|
||||
place-items: center; |
|
||||
} |
|
||||
.container { |
|
||||
display: grid; |
|
||||
grid-gap: 10px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -0,0 +1,37 @@ |
|||||
|
<script> |
||||
|
import Field from "./Field.svelte" |
||||
|
import RadioGroup from "./Core/RadioGroup.svelte" |
||||
|
import { createEventDispatcher } from "svelte" |
||||
|
|
||||
|
export let value = null |
||||
|
export let label = undefined |
||||
|
export let disabled = false |
||||
|
export let labelPosition = "above" |
||||
|
export let error = null |
||||
|
export let options = [] |
||||
|
export let getOptionLabel = option => extractProperty(option, "label") |
||||
|
export let getOptionValue = option => extractProperty(option, "value") |
||||
|
|
||||
|
const dispatch = createEventDispatcher() |
||||
|
const onChange = e => { |
||||
|
dispatch("change", e.detail) |
||||
|
value = e.detail |
||||
|
} |
||||
|
const extractProperty = (value, property) => { |
||||
|
if (value && typeof value === "object") { |
||||
|
return value[property] |
||||
|
} |
||||
|
return value |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<Field {label} {labelPosition} {disabled} {error}> |
||||
|
<RadioGroup |
||||
|
{error} |
||||
|
{disabled} |
||||
|
{value} |
||||
|
{options} |
||||
|
{getOptionLabel} |
||||
|
{getOptionValue} |
||||
|
on:change={onChange} /> |
||||
|
</Field> |
||||
@ -1,40 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import RichText from "./RichText.svelte"; |
|
||||
|
|
||||
const options = { placeholder: "this is not the default value!" }; |
|
||||
let value; |
|
||||
</script> |
|
||||
|
|
||||
### Rich Text Component |
|
||||
|
|
||||
This component uses the QuillJS library to add Rich Text editing functionality. |
|
||||
|
|
||||
It exposes a <code>content</code> variable that you can bind to in order to get Markdown out of the component. |
|
||||
|
|
||||
As well as the content you can also pass in an option object that looks like so: |
|
||||
|
|
||||
```js |
|
||||
let options = { |
|
||||
modules: { |
|
||||
toolbar: [ |
|
||||
[{ header: [1, 2, 3, false] }], |
|
||||
['bold', 'italic', 'underline', 'strike'] |
|
||||
] |
|
||||
}, |
|
||||
placeholder: 'Type something...', |
|
||||
theme: 'snow' |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
<View name="default"> |
|
||||
<RichText bind:value /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="passing in Markdown"> |
|
||||
<RichText value="# This is an h1 heading!" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="passing in custom options"> |
|
||||
<RichText {options} /> |
|
||||
</View> |
|
||||
@ -1,62 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Select from "./Select.svelte"; |
|
||||
import Spacer from "../Spacer/Spacer.svelte" |
|
||||
|
|
||||
const options = ["Chocolate", "Vanilla", "Strawberry Cheesecake"]; |
|
||||
</script> |
|
||||
|
|
||||
<View name="default"> |
|
||||
<Select name="Test" label="Flavour"> |
|
||||
<option value="">Choose an option</option> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
</View> |
|
||||
|
|
||||
<View name="secondary"> |
|
||||
<Select secondary name="Test" label="Flavour"> |
|
||||
<option value="">Choose an option</option> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
</View> |
|
||||
|
|
||||
<View name="outline"> |
|
||||
<Select outline name="Test" label="Flavour"> |
|
||||
<option value="">Choose an option</option> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
</View> |
|
||||
|
|
||||
<View name="disabled"> |
|
||||
<Select disabled name="Test" label="Flavour"> |
|
||||
<option value="">Choose an option</option> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
</View> |
|
||||
|
|
||||
<View name="thin"> |
|
||||
<Select thin name="Test" label="Flavour"> |
|
||||
<option value="">Choose an option</option> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
</View> |
|
||||
|
|
||||
<View name="extraThin"> |
|
||||
<Select extraThin name="Test" label="Flavour"> |
|
||||
<option value="">Choose an option</option> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
</View> |
|
||||
|
|
||||
@ -1,26 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Slider from "./Slider.svelte"; |
|
||||
</script> |
|
||||
|
|
||||
<View name="default"> |
|
||||
<Slider label=Quantity value="50" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="show value"> |
|
||||
<Slider label="Quantity" value="50" showValue /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="show range"> |
|
||||
<Slider label="Quantity" value="25" showValue showRange min="0" max="100" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="custom min and max"> |
|
||||
<Slider label="Quantity" value="350" showValue showRange min="50" max="500" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="custom step"> |
|
||||
<Slider label="Quantity" value="25" step="25" showValue showRange min="0" max="100" /> |
|
||||
</View> |
|
||||
|
|
||||
|
|
||||
@ -1,30 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import TextArea from "./TextArea.svelte"; |
|
||||
|
|
||||
import Button from "../Button/Button.svelte"; |
|
||||
</script> |
|
||||
|
|
||||
<View name="default"> |
|
||||
<TextArea placeholder="Enter your email text" label="Email Body" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="disabled"> |
|
||||
<TextArea disabled placeholder="Enter your email text" label="Email Body" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="no label"> |
|
||||
<TextArea placeholder="Enter your email text" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="thin"> |
|
||||
<TextArea thin placeholder="Enter your email text" label="Email Body" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="extraThin"> |
|
||||
<TextArea extraThin placeholder="Enter your email text" label="Email Body" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="with buttons"> |
|
||||
<TextArea edit placeholder="Enter your email text" label="Email Body" /> |
|
||||
</View> |
|
||||
@ -1,21 +0,0 @@ |
|||||
<script> |
|
||||
import { View } from "svench"; |
|
||||
import Toggle from "./Toggle.svelte"; |
|
||||
</script> |
|
||||
|
|
||||
<View name="default"> |
|
||||
<Toggle /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="checked with text"> |
|
||||
<Toggle text="Display on mobile?" /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="thin"> |
|
||||
<Toggle text="Display on mobile?" thin /> |
|
||||
</View> |
|
||||
|
|
||||
<View name="disabled"> |
|
||||
<Toggle disabled={true} /> |
|
||||
</View> |
|
||||
|
|
||||
@ -1,171 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount, onDestroy } from "svelte" |
|
||||
import { Modal, ModalContent } from "@budibase/bbui" |
|
||||
import CreateEditColumn from "../modals/CreateEditColumn.svelte" |
|
||||
import { FIELDS } from "constants/backend" |
|
||||
|
|
||||
const SORT_ICON_MAP = { |
|
||||
asc: "ri-arrow-down-fill", |
|
||||
desc: "ri-arrow-up-fill", |
|
||||
} |
|
||||
|
|
||||
export let field |
|
||||
export let displayName |
|
||||
export let column |
|
||||
export let enableSorting = true |
|
||||
export let showColumnMenu |
|
||||
export let progressSort |
|
||||
export let editable |
|
||||
|
|
||||
let menuButton |
|
||||
let sortDirection = "" |
|
||||
let modal |
|
||||
let hovered |
|
||||
let filterActive |
|
||||
|
|
||||
function toggleMenu() { |
|
||||
showColumnMenu(menuButton) |
|
||||
} |
|
||||
|
|
||||
function onSort(event) { |
|
||||
progressSort(event.shiftKey) |
|
||||
} |
|
||||
|
|
||||
function showModal() { |
|
||||
modal.show() |
|
||||
} |
|
||||
|
|
||||
function setSort() { |
|
||||
sortDirection = column.getSort() |
|
||||
} |
|
||||
|
|
||||
function setFilterActive(e) { |
|
||||
filterActive = e.column.filterActive |
|
||||
} |
|
||||
|
|
||||
onMount(() => { |
|
||||
column.addEventListener("sortChanged", setSort) |
|
||||
column.addEventListener("filterActiveChanged", setFilterActive) |
|
||||
}) |
|
||||
|
|
||||
onDestroy(() => { |
|
||||
column.removeEventListener("sortChanged", setSort) |
|
||||
column.removeEventListener("filterActiveChanged", setFilterActive) |
|
||||
}) |
|
||||
|
|
||||
$: type = FIELDS[field?.type?.toUpperCase()]?.name |
|
||||
</script> |
|
||||
|
|
||||
<header |
|
||||
on:click={onSort} |
|
||||
data-cy="table-header" |
|
||||
on:mouseover={() => (hovered = true)} |
|
||||
on:mouseleave={() => (hovered = false)}> |
|
||||
<div class="column-header"> |
|
||||
<div class="column-header-text"> |
|
||||
<div class="column-header-name"> |
|
||||
{displayName} |
|
||||
{#if field.autocolumn}<i class="auto ri-magic-fill" />{/if} |
|
||||
</div> |
|
||||
{#if type} |
|
||||
<div class="column-header-type">{type}</div> |
|
||||
{/if} |
|
||||
</div> |
|
||||
<i class={`${SORT_ICON_MAP[sortDirection]} icon`} /> |
|
||||
</div> |
|
||||
<Modal bind:this={modal}> |
|
||||
<ModalContent |
|
||||
size="large" |
|
||||
showCancelButton={false} |
|
||||
showConfirmButton={false} |
|
||||
title={`Edit Column: ${field.name}`}> |
|
||||
<CreateEditColumn onClosed={modal.hide} {field} /> |
|
||||
</ModalContent> |
|
||||
</Modal> |
|
||||
<section class:show={hovered || filterActive}> |
|
||||
{#if editable && hovered} |
|
||||
<span on:click|stopPropagation={showModal}> |
|
||||
<i class="ri-pencil-line icon" /> |
|
||||
</span> |
|
||||
{/if} |
|
||||
<span on:click|stopPropagation={toggleMenu} bind:this={menuButton}> |
|
||||
<i class="ri-filter-line icon" class:active={filterActive} /> |
|
||||
</span> |
|
||||
</section> |
|
||||
</header> |
|
||||
|
|
||||
<style> |
|
||||
header { |
|
||||
font-family: Inter; |
|
||||
font-weight: 600; |
|
||||
display: flex; |
|
||||
justify-content: space-between; |
|
||||
height: 100%; |
|
||||
width: 100%; |
|
||||
align-items: center; |
|
||||
color: var(--ink); |
|
||||
} |
|
||||
|
|
||||
section { |
|
||||
opacity: 0; |
|
||||
transition: 0.3s all; |
|
||||
} |
|
||||
|
|
||||
section.show { |
|
||||
opacity: 1; |
|
||||
} |
|
||||
|
|
||||
.column-header { |
|
||||
display: flex; |
|
||||
flex-direction: row; |
|
||||
justify-content: flex-start; |
|
||||
align-items: center; |
|
||||
gap: var(--spacing-s); |
|
||||
} |
|
||||
|
|
||||
.column-header-text { |
|
||||
flex: 1 1 auto; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: flex-start; |
|
||||
align-items: stretch; |
|
||||
gap: var(--spacing-xs); |
|
||||
} |
|
||||
|
|
||||
.column-header-name { |
|
||||
white-space: normal !important; |
|
||||
text-overflow: ellipsis; |
|
||||
display: -webkit-box; |
|
||||
-webkit-box-orient: vertical; |
|
||||
-webkit-line-clamp: 1; |
|
||||
overflow: hidden; |
|
||||
} |
|
||||
|
|
||||
.column-header-type { |
|
||||
font-size: var(--font-size-xs); |
|
||||
color: var(--grey-6); |
|
||||
} |
|
||||
|
|
||||
.icon { |
|
||||
transition: 0.2s all; |
|
||||
font-size: var(--font-size-m); |
|
||||
font-weight: 500; |
|
||||
} |
|
||||
.auto { |
|
||||
font-size: 9px; |
|
||||
transition: none; |
|
||||
position: relative; |
|
||||
margin-left: 2px; |
|
||||
top: -3px; |
|
||||
color: var(--grey-6); |
|
||||
} |
|
||||
|
|
||||
.icon:hover { |
|
||||
color: var(--blue); |
|
||||
} |
|
||||
|
|
||||
.icon.active, |
|
||||
.icon:hover { |
|
||||
color: var(--blue); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,35 +0,0 @@ |
|||||
import TableHeader from "./TableHeader.svelte" |
|
||||
|
|
||||
export default class TableHeaderWrapper { |
|
||||
constructor() {} |
|
||||
|
|
||||
init(params) { |
|
||||
this.agParams = params |
|
||||
this.container = document.createElement("div") |
|
||||
this.container.style.height = "100%" |
|
||||
this.container.style.width = "100%" |
|
||||
|
|
||||
this.headerComponent = new TableHeader({ |
|
||||
target: this.container, |
|
||||
props: params, |
|
||||
}) |
|
||||
this.gui = this.container |
|
||||
} |
|
||||
|
|
||||
// can get called more than once, you should return the HTML element
|
|
||||
getGui() { |
|
||||
return this.gui |
|
||||
} |
|
||||
|
|
||||
// gets called when a new Column Definition has been set for this header
|
|
||||
refresh(params) { |
|
||||
this.agParams = params |
|
||||
this.headerComponent = new TableHeader({ |
|
||||
target: this.container, |
|
||||
props: params, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
// optional method, gets called once, when component is destroyed
|
|
||||
destroy() {} |
|
||||
} |
|
||||
@ -1,27 +0,0 @@ |
|||||
<script> |
|
||||
import Spinner from "components/common/Spinner.svelte" |
|
||||
import { fade } from "svelte/transition" |
|
||||
import Logo from "/assets/bb-logo.svg" |
|
||||
</script> |
|
||||
|
|
||||
<div class="ag-overlay-loading-center loading-container"> |
|
||||
<div transition:fade class="loading-overlay"> |
|
||||
<img height="30" width="30" src={Logo} alt="Budibase icon" /> |
|
||||
<span> Loading Your Data </span> |
|
||||
<Spinner size="12" /> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.loading-overlay { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
font-family: var(--font-sans); |
|
||||
font-weight: 500; |
|
||||
color: var(--ink); |
|
||||
} |
|
||||
|
|
||||
.loading-overlay > * { |
|
||||
margin-right: var(--spacing-m); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,17 +0,0 @@ |
|||||
import LoadingOverlay from "./LoadingOverlay.svelte" |
|
||||
|
|
||||
export default class LoadingOverlayWrapper { |
|
||||
init(params) { |
|
||||
this.gui = document.createElement("div") |
|
||||
new LoadingOverlay({ |
|
||||
target: this.gui, |
|
||||
props: { |
|
||||
params, |
|
||||
}, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
getGui() { |
|
||||
return this.gui |
|
||||
} |
|
||||
} |
|
||||
@ -1,110 +0,0 @@ |
|||||
<script> |
|
||||
import "@spectrum-css/picker/dist/index-vars.css" |
|
||||
import "@spectrum-css/popover/dist/index-vars.css" |
|
||||
import "@spectrum-css/menu/dist/index-vars.css" |
|
||||
import { fly } from "svelte/transition" |
|
||||
|
|
||||
export let fieldState |
|
||||
export let fieldText = "" |
|
||||
export let isPlaceholder = false |
|
||||
export let placeholderOption = null |
|
||||
export let options = [] |
|
||||
export let isOptionSelected = () => false |
|
||||
export let onSelectOption = () => {} |
|
||||
export let getOptionLabel = option => option |
|
||||
export let getOptionValue = option => option |
|
||||
export let open = false |
|
||||
</script> |
|
||||
|
|
||||
{#if fieldState} |
|
||||
<button |
|
||||
id={$fieldState.fieldId} |
|
||||
class="spectrum-Picker spectrum-Picker--sizeM" |
|
||||
disabled={$fieldState.disabled} |
|
||||
class:is-invalid={!$fieldState.valid} |
|
||||
class:is-open={open} |
|
||||
aria-haspopup="listbox" |
|
||||
on:click={() => (open = true)}> |
|
||||
<span class="spectrum-Picker-label" class:is-placeholder={isPlaceholder}> |
|
||||
{fieldText} |
|
||||
</span> |
|
||||
{#if !$fieldState.valid} |
|
||||
<svg |
|
||||
class="spectrum-Icon spectrum-Icon--sizeM spectrum-Picker-validationIcon" |
|
||||
focusable="false" |
|
||||
aria-hidden="true" |
|
||||
aria-label="Folder"> |
|
||||
<use xlink:href="#spectrum-icon-18-Alert" /> |
|
||||
</svg> |
|
||||
{/if} |
|
||||
<svg |
|
||||
class="spectrum-Icon spectrum-UIIcon-ChevronDown100 spectrum-Picker-menuIcon" |
|
||||
focusable="false" |
|
||||
aria-hidden="true"> |
|
||||
<use xlink:href="#spectrum-css-icon-Chevron100" /> |
|
||||
</svg> |
|
||||
</button> |
|
||||
{#if open} |
|
||||
<div class="overlay" on:mousedown|self={() => (open = false)} /> |
|
||||
<div |
|
||||
transition:fly={{ y: -20, duration: 200 }} |
|
||||
class="spectrum-Popover spectrum-Popover--bottom spectrum-Picker-popover is-open"> |
|
||||
<ul class="spectrum-Menu" role="listbox"> |
|
||||
{#if placeholderOption} |
|
||||
<li |
|
||||
class="spectrum-Menu-item" |
|
||||
class:is-selected={isPlaceholder} |
|
||||
role="option" |
|
||||
aria-selected="true" |
|
||||
tabindex="0" |
|
||||
on:click={() => onSelectOption(null)}> |
|
||||
<span class="spectrum-Menu-itemLabel">{placeholderOption}</span> |
|
||||
<svg |
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon" |
|
||||
focusable="false" |
|
||||
aria-hidden="true"> |
|
||||
<use xlink:href="#spectrum-css-icon-Checkmark100" /> |
|
||||
</svg> |
|
||||
</li> |
|
||||
{/if} |
|
||||
{#each options as option} |
|
||||
<li |
|
||||
class="spectrum-Menu-item" |
|
||||
class:is-selected={isOptionSelected(getOptionValue(option))} |
|
||||
role="option" |
|
||||
aria-selected="true" |
|
||||
tabindex="0" |
|
||||
on:click={() => onSelectOption(getOptionValue(option))}> |
|
||||
<span |
|
||||
class="spectrum-Menu-itemLabel">{getOptionLabel(option)}</span> |
|
||||
<svg |
|
||||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Menu-checkmark spectrum-Menu-itemIcon" |
|
||||
focusable="false" |
|
||||
aria-hidden="true"> |
|
||||
<use xlink:href="#spectrum-css-icon-Checkmark100" /> |
|
||||
</svg> |
|
||||
</li> |
|
||||
{/each} |
|
||||
</ul> |
|
||||
</div> |
|
||||
{/if} |
|
||||
{/if} |
|
||||
|
|
||||
<style> |
|
||||
.overlay { |
|
||||
position: fixed; |
|
||||
top: 0; |
|
||||
left: 0; |
|
||||
width: 100vw; |
|
||||
height: 100vh; |
|
||||
z-index: 999; |
|
||||
} |
|
||||
.spectrum-Popover { |
|
||||
max-height: 240px; |
|
||||
width: 100%; |
|
||||
z-index: 999; |
|
||||
} |
|
||||
.spectrum-Picker { |
|
||||
width: 100%; |
|
||||
} |
|
||||
</style> |
|
||||
Loading…
Reference in new issue