forked from tsai/budibase
committed by
GitHub
17 changed files with 701 additions and 228 deletions
@ -0,0 +1,53 @@ |
|||
<script> |
|||
export let disabled = false; |
|||
export let hidden = false; |
|||
export let primary = true; |
|||
export let alert = false; |
|||
export let warning = false; |
|||
</script> |
|||
|
|||
<style> |
|||
.primary { |
|||
color: #0055ff; |
|||
background: rgb(54, 133, 249, 0.1); |
|||
} |
|||
|
|||
.alert { |
|||
color: rgba(255, 0, 31, 1); |
|||
background: rgba(255, 0, 31, 0.1);; |
|||
} |
|||
|
|||
.button { |
|||
font-size: 18px; |
|||
font-weight: bold; |
|||
border-radius: 5px; |
|||
border: none; |
|||
width: 167px; |
|||
height: 64px; |
|||
} |
|||
|
|||
.button:hover { |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.button:disabled { |
|||
color: rgba(22, 48, 87, 0.2); |
|||
cursor: default; |
|||
background: transparent; |
|||
} |
|||
|
|||
.hidden { |
|||
visibility: hidden; |
|||
} |
|||
</style> |
|||
|
|||
<button |
|||
on:click |
|||
class="button" |
|||
class:hidden |
|||
class:primary |
|||
class:alert |
|||
class:warning |
|||
{disabled}> |
|||
<slot /> |
|||
</button> |
|||
|
After Width: | Height: | Size: 228 B |
|
After Width: | Height: | Size: 446 B |
@ -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,41 +1,44 @@ |
|||
<script> |
|||
import UIkit from "uikit"; |
|||
import UIkit from "uikit"; |
|||
|
|||
export let isOpen = false; |
|||
export let onClosed = () => {}; |
|||
export let id = ""; |
|||
export let isOpen = false; |
|||
export let onClosed = () => {}; |
|||
export let id = ""; |
|||
|
|||
let ukModal; |
|||
let listenerAdded = false; |
|||
let ukModal; |
|||
let listenerAdded = false; |
|||
|
|||
$: { |
|||
if(ukModal && !listenerAdded) { |
|||
listenerAdded = true; |
|||
ukModal.addEventListener("hidden", onClosed); |
|||
$: { |
|||
if (ukModal && !listenerAdded) { |
|||
listenerAdded = true; |
|||
ukModal.addEventListener("hidden", onClosed); |
|||
} |
|||
|
|||
if(ukModal) { |
|||
if(isOpen) { |
|||
UIkit.modal(ukModal).show(); |
|||
} else { |
|||
UIkit.modal(ukModal).hide(); |
|||
} |
|||
if (ukModal) { |
|||
if (isOpen) { |
|||
UIkit.modal(ukModal).show(); |
|||
} else { |
|||
UIkit.modal(ukModal).hide(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
</script> |
|||
|
|||
<div bind:this={ukModal} uk-modal {id}> |
|||
<div class="uk-modal-dialog uk-modal-body" uk-overflow-auto> |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
<style> |
|||
.uk-modal-dialog { |
|||
border-radius: 0.3rem; |
|||
width: 60%; |
|||
height: 80vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
</style> |
|||
|
|||
.uk-modal-dialog { |
|||
border-radius: .3rem; |
|||
} |
|||
|
|||
</style> |
|||
<div bind:this={ukModal} uk-modal {id}> |
|||
<div class="uk-modal-dialog uk-modal-body" uk-overflow-auto> |
|||
{#if onClosed} |
|||
<button class="uk-modal-close-default" type="button" uk-close /> |
|||
{/if} |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
|
|||
@ -0,0 +1,23 @@ |
|||
<style> |
|||
button { |
|||
cursor: pointer; |
|||
outline: none; |
|||
border: none; |
|||
border-radius: 5px; |
|||
background: rgba(249, 249, 249, 1); |
|||
|
|||
width: 1.8rem; |
|||
height: 1.8rem; |
|||
padding-bottom: 10px; |
|||
|
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
font-size: 1.2rem; |
|||
font-weight: 700; |
|||
color: rgba(22, 48, 87, 1); |
|||
} |
|||
</style> |
|||
|
|||
<button on:click>+</button> |
|||
@ -0,0 +1,55 @@ |
|||
<script> |
|||
import getIcon from "./icon"; |
|||
export let value; |
|||
</script> |
|||
|
|||
<style> |
|||
.select-container { |
|||
padding-bottom: 10px; |
|||
font-size: 0.9rem; |
|||
color: var(--secondary50); |
|||
font-weight: bold; |
|||
position: relative; |
|||
} |
|||
|
|||
select { |
|||
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; |
|||
} |
|||
|
|||
.arrow { |
|||
position: absolute; |
|||
right: 10px; |
|||
top: 0; |
|||
bottom: 0; |
|||
margin: auto; |
|||
width: 30px; |
|||
height: 30px; |
|||
pointer-events: none; |
|||
color: var(--primary100); |
|||
} |
|||
</style> |
|||
|
|||
<div class="select-container"> |
|||
<select on:change {value}> |
|||
<slot /> |
|||
</select> |
|||
<span class="arrow"> |
|||
{@html getIcon('chevron-down', '24')} |
|||
</span> |
|||
</div> |
|||
@ -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> |
|||
@ -0,0 +1,164 @@ |
|||
<script> |
|||
import Modal from "../../common/Modal.svelte"; |
|||
import HandlerSelector from "./HandlerSelector.svelte"; |
|||
import IconButton from "../../common/IconButton.svelte"; |
|||
import ActionButton from "../../common/ActionButton.svelte"; |
|||
import PlusButton from "../../common/PlusButton.svelte"; |
|||
import Select from "../../common/Select.svelte"; |
|||
import Input from "../../common/Input.svelte"; |
|||
import getIcon from "../../common/icon"; |
|||
|
|||
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers"; |
|||
|
|||
export let event; |
|||
export let eventOptions; |
|||
export let open; |
|||
export let onClose; |
|||
export let onPropChanged; |
|||
|
|||
let eventType = "onClick"; |
|||
let draftEventHandler = { parameters: [] }; |
|||
|
|||
$: eventData = event || { handlers: [] }; |
|||
|
|||
const closeModal = () => { |
|||
onClose(); |
|||
draftEventHandler = { parameters: [] }; |
|||
eventData = { handlers: [] }; |
|||
}; |
|||
|
|||
const updateEventHandler = (updatedHandler, index) => { |
|||
eventData.handlers[index] = updatedHandler; |
|||
}; |
|||
|
|||
const updateDraftEventHandler = updatedHandler => { |
|||
draftEventHandler = updatedHandler; |
|||
}; |
|||
|
|||
const deleteEventHandler = index => { |
|||
eventData.handlers.splice(index, 1); |
|||
eventData = eventData; |
|||
}; |
|||
|
|||
const createNewEventHandler = handler => { |
|||
const newHandler = handler || { |
|||
parameters: {}, |
|||
[EVENT_TYPE_MEMBER_NAME]: "" |
|||
}; |
|||
eventData.handlers.push(newHandler); |
|||
eventData = eventData; |
|||
}; |
|||
|
|||
const deleteEvent = () => { |
|||
onPropChanged(eventType, []); |
|||
closeModal(); |
|||
}; |
|||
|
|||
const saveEventData = () => { |
|||
onPropChanged(eventType, eventData.handlers); |
|||
closeModal(); |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
h2 { |
|||
color: var(--primary100); |
|||
font-size: 20px; |
|||
font-weight: bold; |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
h5 { |
|||
color: rgba(22, 48, 87, 0.6); |
|||
font-size: 15px; |
|||
margin: 0; |
|||
} |
|||
|
|||
.event-options { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
grid-gap: 10px; |
|||
} |
|||
|
|||
.actions, |
|||
header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.actions { |
|||
margin-top: auto; |
|||
} |
|||
|
|||
header { |
|||
margin-top: 30px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
a { |
|||
color: rgba(22, 48, 87, 0.6); |
|||
font-size: 12px; |
|||
margin-top: 0; |
|||
} |
|||
</style> |
|||
|
|||
<Modal bind:isOpen={open} onClosed={closeModal}> |
|||
<h2> |
|||
{eventData.name ? `${eventData.name} Event` : 'Create a New Component Event'} |
|||
</h2> |
|||
<a href="https://docs.budibase.com/" target="_blank"> |
|||
Click here to learn more about component events |
|||
</a> |
|||
|
|||
<div class="event-options"> |
|||
<div> |
|||
<header> |
|||
<h5>Event Type</h5> |
|||
{@html getIcon('info', 20)} |
|||
</header> |
|||
<Select :value={eventType}> |
|||
{#each eventOptions as option} |
|||
<option value={option.name}>{option.name}</option> |
|||
{/each} |
|||
</Select> |
|||
</div> |
|||
</div> |
|||
|
|||
<header> |
|||
<h5>Event Action(s)</h5> |
|||
{@html getIcon('info', 20)} |
|||
</header> |
|||
<HandlerSelector |
|||
newHandler |
|||
onChanged={updateDraftEventHandler} |
|||
onCreate={() => { |
|||
createNewEventHandler(draftEventHandler); |
|||
draftEventHandler = { parameters: [] }; |
|||
}} |
|||
handler={draftEventHandler} /> |
|||
{#if eventData} |
|||
{#each eventData.handlers as handler, index} |
|||
<HandlerSelector |
|||
{index} |
|||
onChanged={updateEventHandler} |
|||
onRemoved={() => deleteEventHandler(index)} |
|||
{handler} /> |
|||
{/each} |
|||
{/if} |
|||
|
|||
<div class="actions"> |
|||
<ActionButton |
|||
alert |
|||
disabled={eventData.handlers.length === 0} |
|||
hidden={!eventData.name} |
|||
on:click={deleteEvent}> |
|||
Delete |
|||
</ActionButton> |
|||
<ActionButton |
|||
disabled={eventData.handlers.length === 0} |
|||
on:click={saveEventData}> |
|||
Save |
|||
</ActionButton> |
|||
</div> |
|||
</Modal> |
|||
@ -0,0 +1,152 @@ |
|||
<script> |
|||
import { |
|||
keys, |
|||
map, |
|||
some, |
|||
includes, |
|||
cloneDeep, |
|||
isEqual, |
|||
sortBy, |
|||
filter, |
|||
difference |
|||
} from "lodash/fp"; |
|||
import { pipe } from "../../common/core"; |
|||
import Checkbox from "../../common/Checkbox.svelte"; |
|||
import Textbox from "../../common/Textbox.svelte"; |
|||
import Dropdown from "../../common/Dropdown.svelte"; |
|||
import PlusButton from "../../common/PlusButton.svelte"; |
|||
import IconButton from "../../common/IconButton.svelte"; |
|||
import Modal from "../../common/Modal.svelte"; |
|||
import EventEditorModal from "./EventEditorModal.svelte"; |
|||
import HandlerSelector from "./HandlerSelector.svelte"; |
|||
|
|||
import { PencilIcon } from "../../common/Icons"; |
|||
import { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers"; |
|||
|
|||
export const EVENT_TYPE = "event"; |
|||
|
|||
export let componentInfo; |
|||
export let onPropChanged = () => {}; |
|||
export let components; |
|||
|
|||
let modalOpen = false; |
|||
let events = []; |
|||
let selectedEvent = null; |
|||
|
|||
$: { |
|||
events = Object.keys(componentInfo) |
|||
.filter(key => findType(key) === EVENT_TYPE) |
|||
.map(key => ({ name: key, handlers: componentInfo[key] })); |
|||
} |
|||
|
|||
function findType(propName) { |
|||
if (!componentInfo._component) return; |
|||
return components.find(({ name }) => name === componentInfo._component) |
|||
.props[propName]; |
|||
} |
|||
|
|||
const openModal = event => { |
|||
selectedEvent = event; |
|||
modalOpen = true; |
|||
}; |
|||
|
|||
const closeModal = () => { |
|||
selectedEvent = null; |
|||
modalOpen = false; |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
h3 { |
|||
text-transform: uppercase; |
|||
font-size: 12px; |
|||
font-weight: 700; |
|||
color: #8997ab; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.root { |
|||
font-size: 10pt; |
|||
width: 100%; |
|||
} |
|||
|
|||
.form-root { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
header { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.handler-container { |
|||
display: grid; |
|||
grid-template-columns: repeat(2, 1fr); |
|||
border: 2px solid #f9f9f9; |
|||
height: 80px; |
|||
} |
|||
|
|||
.hierarchy-item { |
|||
cursor: pointer; |
|||
padding: 11px 7px; |
|||
margin: 5px 0; |
|||
border-radius: 5px; |
|||
font-size: 1.5em; |
|||
width: 100%; |
|||
} |
|||
|
|||
.hierarchy-item:hover { |
|||
background: #f9f9f9; |
|||
} |
|||
|
|||
.event-name { |
|||
margin-top: 5px; |
|||
font-weight: bold; |
|||
font-size: 16px; |
|||
color: rgba(22, 48, 87, 0.6); |
|||
align-self: end; |
|||
} |
|||
|
|||
.edit-text { |
|||
font-family: Arial, Helvetica, sans-serif; |
|||
font-weight: bold; |
|||
align-self: end; |
|||
justify-self: end; |
|||
font-size: 10px; |
|||
color: rgba(35, 65, 105, 0.4); |
|||
} |
|||
|
|||
.selected { |
|||
color: var(--button-text); |
|||
background: var(--background-button) !important; |
|||
} |
|||
</style> |
|||
|
|||
<header> |
|||
<h3>Events</h3> |
|||
<PlusButton on:click={() => openModal()} /> |
|||
</header> |
|||
|
|||
<div class="root"> |
|||
<form class="uk-form-stacked form-root"> |
|||
{#each events as event, index} |
|||
{#if event.handlers.length > 0} |
|||
<div |
|||
class="handler-container hierarchy-item {selectedEvent && selectedEvent.index === index ? 'selected' : ''}" |
|||
on:click={() => openModal({ ...event, index })}> |
|||
<span class="event-name">{event.name}</span> |
|||
<span class="edit-text">EDIT</span> |
|||
</div> |
|||
{/if} |
|||
{/each} |
|||
</form> |
|||
</div> |
|||
<EventEditorModal |
|||
{onPropChanged} |
|||
open={modalOpen} |
|||
onClose={closeModal} |
|||
eventOptions={events} |
|||
event={selectedEvent} |
|||
/> |
|||
@ -0,0 +1,148 @@ |
|||
<script> |
|||
import IconButton from "../../common/IconButton.svelte"; |
|||
import PlusButton from "../../common/PlusButton.svelte"; |
|||
import Select from "../../common/Select.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 handler; |
|||
export let onCreate; |
|||
export let onChanged; |
|||
export let onRemoved; |
|||
|
|||
export let index; |
|||
export let newHandler; |
|||
|
|||
let eventOptions; |
|||
let handlerType; |
|||
let parameters = []; |
|||
|
|||
$: eventOptions = allHandlers( |
|||
{ hierarchy: $store.hierarchy }, |
|||
userWithFullAccess({ |
|||
hierarchy: $store.hierarchy, |
|||
actions: keyBy("name")($store.actions) |
|||
}) |
|||
); |
|||
|
|||
$: { |
|||
if (handler) { |
|||
handlerType = handler[EVENT_TYPE_MEMBER_NAME]; |
|||
parameters = Object.entries(handler.parameters).map(([name, value]) => ({ |
|||
name, |
|||
value |
|||
})); |
|||
} else { |
|||
// Empty Handler |
|||
handlerType = ""; |
|||
parameters = []; |
|||
} |
|||
} |
|||
|
|||
const handlerChanged = (type, params) => { |
|||
const handlerParams = {}; |
|||
for (let param of params) { |
|||
handlerParams[param.name] = param.value; |
|||
} |
|||
|
|||
const updatedHandler = { |
|||
[EVENT_TYPE_MEMBER_NAME]: type, |
|||
parameters: handlerParams |
|||
}; |
|||
|
|||
onChanged(updatedHandler, index); |
|||
}; |
|||
|
|||
const handlerTypeChanged = e => { |
|||
const handlerType = eventOptions.find( |
|||
handler => handler.name === e.target.value |
|||
); |
|||
const defaultParams = handlerType.parameters.map(param => ({ |
|||
name: param, |
|||
value: "" |
|||
})); |
|||
|
|||
handlerChanged(handlerType.name, defaultParams); |
|||
}; |
|||
|
|||
const onParameterChanged = index => value => { |
|||
const newParams = [...parameters]; |
|||
newParams[index].value = value; |
|||
handlerChanged(handlerType, newParams); |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.type-selector-container { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
background: rgba(223, 223, 223, 0.5); |
|||
border: 1px solid #dfdfdf; |
|||
margin-bottom: 18px; |
|||
} |
|||
|
|||
.handler-option { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.new-handler { |
|||
background: #fff; |
|||
} |
|||
|
|||
.handler-controls { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
grid-gap: 10px; |
|||
padding: 22px; |
|||
} |
|||
|
|||
.event-action-button { |
|||
margin-right: 20px; |
|||
} |
|||
|
|||
span { |
|||
font-size: 12px; |
|||
margin-bottom: 5px; |
|||
} |
|||
</style> |
|||
|
|||
<div class="type-selector-container {newHandler && 'new-handler'}"> |
|||
<div class="handler-controls"> |
|||
<div class="handler-option"> |
|||
<span>Action</span> |
|||
<Select value={handlerType} on:change={handlerTypeChanged}> |
|||
<option /> |
|||
{#each eventOptions as option} |
|||
<option value={option.name}>{option.name}</option> |
|||
{/each} |
|||
</Select> |
|||
</div> |
|||
{#if parameters} |
|||
{#each parameters as param, idx} |
|||
<div class="handler-option"> |
|||
<span>{param.name}</span> |
|||
<StateBindingControl |
|||
onChanged={onParameterChanged(idx)} |
|||
value={param.value} /> |
|||
</div> |
|||
{/each} |
|||
{/if} |
|||
</div> |
|||
<div class="event-action-button"> |
|||
{#if parameters.length > 0} |
|||
{#if newHandler} |
|||
<PlusButton on:click={onCreate} /> |
|||
{:else} |
|||
<IconButton icon="x" on:click={onRemoved} /> |
|||
{/if} |
|||
{/if} |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1 @@ |
|||
export { default } from "./EventsEditor.svelte"; |
|||
Loading…
Reference in new issue