forked from tsai/budibase
12 changed files with 238 additions and 528 deletions
@ -0,0 +1,30 @@ |
|||||
|
<script> |
||||
|
export let disabled = false; |
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
.action-button { |
||||
|
color: #0055ff; |
||||
|
background: rgb(54, 133, 249, 0.1); |
||||
|
font-size: 18px; |
||||
|
font-weight: bold; |
||||
|
border-radius: 5px; |
||||
|
border: none; |
||||
|
width: 167px; |
||||
|
height: 64px; |
||||
|
} |
||||
|
|
||||
|
.action-button:hover { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.action-button:disabled { |
||||
|
color:#163057; |
||||
|
cursor: default; |
||||
|
background: transparent; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<button on:click class="action-button" {disabled}> |
||||
|
<slot /> |
||||
|
</button> |
||||
@ -0,0 +1,27 @@ |
|||||
|
<script> |
||||
|
export let value = ""; |
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
input { |
||||
|
display: block; |
||||
|
font-size: 14px; |
||||
|
font-family: sans-serif; |
||||
|
font-weight: 500; |
||||
|
color: #163057; |
||||
|
line-height: 1.3; |
||||
|
padding: 1em 2.6em 0.9em 1.4em; |
||||
|
width: 100%; |
||||
|
max-width: 100%; |
||||
|
box-sizing: border-box; |
||||
|
margin: 0; |
||||
|
-moz-appearance: none; |
||||
|
-webkit-appearance: none; |
||||
|
appearance: none; |
||||
|
background: #fff; |
||||
|
border: 1px solid #ccc; |
||||
|
height: 50px; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<input type="text" on:change bind:value /> |
||||
@ -1,88 +0,0 @@ |
|||||
<script> |
|
||||
import IconButton from "../common/IconButton.svelte"; |
|
||||
import EventSelector from "./EventSelector.svelte"; |
|
||||
import { |
|
||||
filter |
|
||||
} from "lodash/fp"; |
|
||||
import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers"; |
|
||||
|
|
||||
export let parentProps; |
|
||||
export let propDef; |
|
||||
export let onValueChanged; |
|
||||
|
|
||||
$: events = parentProps[propDef.____name]; |
|
||||
|
|
||||
const addHandler = () => { |
|
||||
const newHandler = {parameters:{}}; |
|
||||
newHandler[EVENT_TYPE_MEMBER_NAME] = ""; |
|
||||
events = [...events, newHandler]; |
|
||||
onValueChanged(events); |
|
||||
} |
|
||||
|
|
||||
const onEventHandlerChanged = (oldEvent) => (newEvent) => { |
|
||||
const indexOfOldEvent = events.indexOf(oldEvent); |
|
||||
const newEvents = [...events]; |
|
||||
newEvents.splice( |
|
||||
events.indexOf(oldEvent), |
|
||||
1, |
|
||||
newEvent); |
|
||||
events = newEvents; |
|
||||
onValueChanged(events); |
|
||||
} |
|
||||
|
|
||||
const removeHandler = (index) => () => { |
|
||||
events = filter(e => e !== events[index])(events); |
|
||||
onValueChanged(events); |
|
||||
} |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
<div class="control-container"> |
|
||||
{#each events as ev, index} |
|
||||
|
|
||||
<div class="handler-container"> |
|
||||
<EventSelector onChanged={onEventHandlerChanged(ev)} |
|
||||
onRemoved={removeHandler(index)} |
|
||||
event={ev} /> |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
<div class="separator"></div> |
|
||||
{/each} |
|
||||
|
|
||||
<div class="addelement-container" |
|
||||
on:click={addHandler}> |
|
||||
<IconButton icon="plus" |
|
||||
size="12"/> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
|
|
||||
<style> |
|
||||
.addelement-container { |
|
||||
cursor: pointer; |
|
||||
padding: 3px 0px; |
|
||||
text-align: center; |
|
||||
} |
|
||||
|
|
||||
.addelement-container:hover { |
|
||||
background-color: var(--primary25); |
|
||||
margin-top: 5px; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
.control-container { |
|
||||
padding-left: 3px; |
|
||||
background: var(--secondary10); |
|
||||
} |
|
||||
|
|
||||
.separator { |
|
||||
width: 60%; |
|
||||
margin: 10px auto; |
|
||||
border-style:solid; |
|
||||
border-width: 1px 0 0 0; |
|
||||
border-color: var(--primary25); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,105 +0,0 @@ |
|||||
<script> |
|
||||
import IconButton from "../common/IconButton.svelte"; |
|
||||
import StateBindingControl from "./StateBindingControl.svelte"; |
|
||||
import { |
|
||||
find, map, keys, reduce, keyBy |
|
||||
} from "lodash/fp"; |
|
||||
import { pipe, userWithFullAccess } from "../common/core"; |
|
||||
import { EVENT_TYPE_MEMBER_NAME, allHandlers } from "../common/eventHandlers"; |
|
||||
import { store } from "../builderStore"; |
|
||||
|
|
||||
export let event; |
|
||||
export let onChanged; |
|
||||
export let onRemoved; |
|
||||
|
|
||||
let eventType; |
|
||||
let parameters = []; |
|
||||
|
|
||||
|
|
||||
$: events = allHandlers( |
|
||||
{hierarchy: $store.hierarchy}, |
|
||||
userWithFullAccess({ |
|
||||
hierarchy: s.hierarchy, |
|
||||
actions: keyBy("name")($store.actions) |
|
||||
}) |
|
||||
); |
|
||||
|
|
||||
$: if(event) { |
|
||||
eventType = event[EVENT_TYPE_MEMBER_NAME]; |
|
||||
parameters = pipe(event.parameters, [ |
|
||||
keys, |
|
||||
map(k => ({name:k, value:event.parameters[k]})) |
|
||||
]); |
|
||||
} else { |
|
||||
eventType = ""; |
|
||||
parameters = []; |
|
||||
} |
|
||||
|
|
||||
const eventChanged = (type, parameters) => { |
|
||||
const paramsAsObject = reduce( |
|
||||
(obj, p) => { |
|
||||
obj[p.name] = p.value; |
|
||||
return obj; |
|
||||
} |
|
||||
, {} |
|
||||
)(parameters) |
|
||||
|
|
||||
const ev = {}; |
|
||||
ev[EVENT_TYPE_MEMBER_NAME]=type; |
|
||||
ev.parameters = paramsAsObject; |
|
||||
|
|
||||
onChanged(ev); |
|
||||
} |
|
||||
|
|
||||
const eventTypeChanged = (ev) => { |
|
||||
const eType = find(e => e.name === ev.target.value)(events); |
|
||||
const emptyParameters = map(p => ({name:p, value:""}))(eType.parameters); |
|
||||
eventChanged(eType.name, emptyParameters); |
|
||||
} |
|
||||
|
|
||||
const onParameterChanged = index => val => { |
|
||||
const newparameters = [...parameters]; |
|
||||
newparameters[index].value = val; |
|
||||
eventChanged(eventType, newparameters); |
|
||||
} |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
<div class="type-selector-container"> |
|
||||
<select class="type-selector uk-select uk-form-small " value={eventType} on:change={eventTypeChanged}> |
|
||||
<option></option> |
|
||||
{#each events as ev} |
|
||||
<option value={ev.name}>{ev.name}</option> |
|
||||
{/each} |
|
||||
</select> |
|
||||
|
|
||||
<IconButton icon="trash" |
|
||||
size="12" |
|
||||
on:click={onRemoved}/> |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
{#if parameters} |
|
||||
{#each parameters as p, index} |
|
||||
|
|
||||
<div> |
|
||||
{p.name} |
|
||||
</div> |
|
||||
<StateBindingControl onChanged={onParameterChanged(index)} |
|
||||
value={p.value} /> |
|
||||
|
|
||||
{/each} |
|
||||
{/if} |
|
||||
|
|
||||
<style> |
|
||||
.type-selector-container { |
|
||||
display: flex; |
|
||||
} |
|
||||
|
|
||||
.type-selector { |
|
||||
border-color: var(--primary50); |
|
||||
border-radius: 2px; |
|
||||
width: 50px; |
|
||||
flex: 1 0 auto; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,177 +0,0 @@ |
|||||
<script> |
|
||||
import { |
|
||||
isString |
|
||||
} from "lodash/fp"; |
|
||||
import IconButton from "../../common/IconButton.svelte"; |
|
||||
import { |
|
||||
isBinding, getBinding, setBinding |
|
||||
} from "../../common/binding"; |
|
||||
|
|
||||
export let value=""; |
|
||||
export let onChanged= () => {}; |
|
||||
export let type=""; |
|
||||
export let options=[]; |
|
||||
|
|
||||
let isBound=false; |
|
||||
let bindingPath=""; |
|
||||
let bindingFallbackValue=""; |
|
||||
let bindingSource="store"; |
|
||||
let isExpanded = false; |
|
||||
let forceIsBound = false; |
|
||||
let canOnlyBind = false; |
|
||||
|
|
||||
$: { |
|
||||
canOnlyBind = type === "state"; |
|
||||
if(!forceIsBound && canOnlyBind) |
|
||||
forceIsBound = true; |
|
||||
|
|
||||
isBound= forceIsBound || isBinding(value); |
|
||||
|
|
||||
if(isBound) { |
|
||||
const binding = getBinding(value); |
|
||||
bindingPath= binding.path; |
|
||||
bindingFallbackValue= binding.fallback; |
|
||||
bindingSource = binding.source || "store"; |
|
||||
} else { |
|
||||
bindingPath=""; |
|
||||
bindingFallbackValue=""; |
|
||||
bindingSource="store"; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const clearBinding = () => { |
|
||||
forceIsBound = false; |
|
||||
onChanged(""); |
|
||||
} |
|
||||
|
|
||||
const bind = (path, fallback, source) => { |
|
||||
if(!path) { |
|
||||
clearBinding(""); |
|
||||
return; |
|
||||
} |
|
||||
const binding = setBinding({path, fallback, source}); |
|
||||
onChanged(binding); |
|
||||
} |
|
||||
|
|
||||
const setBindingPath = ev => { |
|
||||
forceIsBound = canOnlyBind; |
|
||||
bind(ev.target.value, bindingFallbackValue, bindingSource) |
|
||||
} |
|
||||
|
|
||||
const setBindingFallback = ev => { |
|
||||
bind(bindingPath, ev.target.value, bindingSource); |
|
||||
} |
|
||||
|
|
||||
const setBindingSource = ev => { |
|
||||
bind(bindingPath, bindingFallbackValue, ev.target.value); |
|
||||
} |
|
||||
|
|
||||
// const makeBinding = () => { |
|
||||
// forceIsBound=true; |
|
||||
// isExpanded=true; |
|
||||
// } |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
{#if isBound} |
|
||||
<div> |
|
||||
<div class="bound-header"> |
|
||||
<div>{isExpanded ? "" : bindingPath}</div> |
|
||||
<IconButton icon={isExpanded ? "chevron-up" : "chevron-down"} |
|
||||
size="12" |
|
||||
on:click={() => isExpanded=!isExpanded}/> |
|
||||
{#if !canOnlyBind} |
|
||||
<IconButton icon="trash" |
|
||||
size="12" |
|
||||
on:click={clearBinding}/> |
|
||||
{/if} |
|
||||
</div> |
|
||||
{#if isExpanded} |
|
||||
<div> |
|
||||
<div class="binding-prop-label">Binding Path</div> |
|
||||
<input class="uk-input uk-form-small" |
|
||||
value={bindingPath} |
|
||||
on:change={setBindingPath} > |
|
||||
<div class="binding-prop-label">Fallback Value</div> |
|
||||
<input class="uk-input uk-form-small" |
|
||||
value={bindingFallbackValue} |
|
||||
on:change={setBindingFallback} > |
|
||||
<div class="binding-prop-label">Binding Source</div> |
|
||||
<select class="uk-select uk-form-small" |
|
||||
value={bindingSource} |
|
||||
on:change={setBindingSource}> |
|
||||
|
|
||||
<option>store</option> |
|
||||
<option>context</option> |
|
||||
|
|
||||
</select> |
|
||||
</div> |
|
||||
{/if} |
|
||||
|
|
||||
</div> |
|
||||
{:else} |
|
||||
<div class="unbound-container"> |
|
||||
|
|
||||
{#if type === "bool"} |
|
||||
|
|
||||
<div> |
|
||||
<IconButton icon={value == true ? "check-square" : "square"} |
|
||||
size="19" |
|
||||
on:click={() => onChanged(!value)} /> |
|
||||
</div> |
|
||||
|
|
||||
{:else if type === "options"} |
|
||||
|
|
||||
<select class="uk-select uk-form-small" |
|
||||
value={value} |
|
||||
on:change={ev => onChanged(ev.target.value)}> |
|
||||
{#each options as option} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/each} |
|
||||
</select> |
|
||||
|
|
||||
{:else} |
|
||||
|
|
||||
<input on:change={ev => onChanged(ev.target.value)} |
|
||||
bind:value={value} |
|
||||
style="flex: 1 0 auto;" /> |
|
||||
|
|
||||
|
|
||||
{/if} |
|
||||
|
|
||||
</div> |
|
||||
{/if} |
|
||||
|
|
||||
|
|
||||
<style> |
|
||||
.unbound-container { |
|
||||
display:flex; |
|
||||
} |
|
||||
|
|
||||
.bound-header { |
|
||||
display: flex; |
|
||||
} |
|
||||
|
|
||||
.bound-header > div:nth-child(1) { |
|
||||
flex: 1 0 auto; |
|
||||
width: 30px; |
|
||||
color: var(--secondary50); |
|
||||
padding-left: 5px; |
|
||||
} |
|
||||
|
|
||||
.binding-prop-label { |
|
||||
color: var(--secondary50); |
|
||||
} |
|
||||
|
|
||||
input { |
|
||||
font-size: 12px; |
|
||||
font-weight: 700; |
|
||||
color: #163057; |
|
||||
opacity: 0.7; |
|
||||
padding: 5px 10px; |
|
||||
box-sizing: border-box; |
|
||||
border: 1px solid #DBDBDB; |
|
||||
border-radius: 2px; |
|
||||
outline: none; |
|
||||
} |
|
||||
</style> |
|
||||
Loading…
Reference in new issue