state management like designs
This commit is contained in:
parent
c064f08d55
commit
61cc39fc96
|
@ -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 />
|
|
@ -36,6 +36,7 @@ $: {
|
|||
|
||||
.uk-modal-dialog {
|
||||
border-radius: .3rem;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -14,21 +14,22 @@
|
|||
|
||||
select {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-family: sans-serif;
|
||||
font-weight: 700;
|
||||
color: #444;
|
||||
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;
|
||||
border-radius: 0.5em;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background-color: #fafafa;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
const onPropChanged = store.setComponentProp;
|
||||
const onStyleChanged = store.setComponentStyle;
|
||||
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
|
|
@ -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,19 +1,58 @@
|
|||
<script>
|
||||
import Modal from "../../common/Modal.svelte";
|
||||
import EventSelector from "../EventSelector.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 { EVENT_TYPE_MEMBER_NAME } from "../../common/eventHandlers";
|
||||
|
||||
export let event;
|
||||
|
||||
export let events;
|
||||
export let open;
|
||||
export let closeModal;
|
||||
export let changeEventHandler;
|
||||
export let removeEventHandler;
|
||||
export let addEventHandler;
|
||||
export let onClose;
|
||||
export let onPropChanged;
|
||||
|
||||
let newEventType = "onClick";
|
||||
let eventType = "onClick";
|
||||
let newEventHandler = { parameters: [] };
|
||||
let eventData = event || { handlers: [] };
|
||||
|
||||
const changeEventHandler = (updatedHandler, index) => {
|
||||
eventData.handlers[index] = updatedHandler;
|
||||
};
|
||||
|
||||
const changeNewEventHandler = updatedHandler => {
|
||||
newEventHandler = 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, []);
|
||||
eventData = { handlers: [] };
|
||||
onClose();
|
||||
};
|
||||
|
||||
const saveEventData = () => {
|
||||
onPropChanged(eventType, eventData.handlers);
|
||||
eventData = { handlers: [] };
|
||||
onClose();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -21,75 +60,63 @@
|
|||
color: var(--primary100);
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
/* TODO: Should be it's own component */
|
||||
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;
|
||||
}
|
||||
|
||||
.event-action {
|
||||
background: #fafafa;
|
||||
h5 {
|
||||
color: rgba(22, 48, 87, 0.6);
|
||||
font-size: 16px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.event-options {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 10px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
<Modal bind:isOpen={open} onClosed={closeModal}>
|
||||
{#if event}
|
||||
<h2>{event.name}</h2>
|
||||
{:else}
|
||||
<h2>Create a New Component Event</h2>
|
||||
{/if}
|
||||
<span>Click here to learn more about component events</span>
|
||||
<Modal bind:isOpen={open} onClosed={onClose}>
|
||||
<h2>{eventData.name || "Create a New Component Event"}</h2>
|
||||
<p>Click here to learn more about component events</p>
|
||||
|
||||
<div class="event-options">
|
||||
<div>
|
||||
<h5>Event Name</h5>
|
||||
<input type="text" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h5>Event Type</h5>
|
||||
<Select bind:value={newEventType}>
|
||||
{#each events as [name]}
|
||||
<option value={name}>{name}</option>
|
||||
<Select bind:value={eventType}>
|
||||
{#each events as event}
|
||||
<option value={event.name}>{event.name}</option>
|
||||
{/each}
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>Event Action(s)</h5>
|
||||
{#if event.handlers}
|
||||
{#each event.handlers as handler, index}
|
||||
<HandlerSelector
|
||||
newHandler
|
||||
onChanged={changeNewEventHandler}
|
||||
onCreate={() => {
|
||||
createNewEventHandler(newEventHandler)
|
||||
newEventHandler = { parameters: [] };
|
||||
}}
|
||||
handler={newEventHandler} />
|
||||
{#if eventData}
|
||||
{#each eventData.handlers as handler, index}
|
||||
<HandlerSelector
|
||||
{index}
|
||||
onChanged={changeEventHandler}
|
||||
onRemoved={() => removeEventHandler(index)}
|
||||
onRemoved={() => deleteEventHandler(index)}
|
||||
{handler} />
|
||||
<hr />
|
||||
{/each}
|
||||
{/if}
|
||||
<div
|
||||
class="addelement-container"
|
||||
on:click={() => addEventHandler(newEventType)}>
|
||||
<IconButton icon="plus" size="12" />
|
||||
Add Handler
|
||||
|
||||
<div class="actions">
|
||||
<ActionButton on:click={deleteEvent}>Delete</ActionButton>
|
||||
<ActionButton disabled={eventData.handlers.length === 0} on:click={saveEventData}>Save</ActionButton>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
@ -31,18 +31,13 @@
|
|||
|
||||
let modalOpen = false;
|
||||
let events = [];
|
||||
let selectedEvent = {};
|
||||
let newEventType = "onClick";
|
||||
let selectedEvent = null;
|
||||
|
||||
// TODO: only show events that have handlers
|
||||
|
||||
$: events =
|
||||
componentInfo &&
|
||||
Object.entries(componentInfo).filter(
|
||||
([name]) => findType(name) == EVENT_TYPE
|
||||
);
|
||||
|
||||
$: action = selectedEvent ? "Edit" : "Create";
|
||||
$: {
|
||||
events = Object.keys(componentInfo)
|
||||
.filter(key => componentInfo[key].length && findType(key) === EVENT_TYPE)
|
||||
.map(key => ({ name: key, handlers: componentInfo[key] }));
|
||||
}
|
||||
|
||||
function findType(propName) {
|
||||
if (!componentInfo._component) return;
|
||||
|
@ -56,45 +51,9 @@
|
|||
};
|
||||
|
||||
const closeModal = () => {
|
||||
selectedEvent = {};
|
||||
selectedEvent = null;
|
||||
modalOpen = false;
|
||||
};
|
||||
|
||||
const addEventHandler = eventType => {
|
||||
const newEventHandler = {
|
||||
parameters: {},
|
||||
[EVENT_TYPE_MEMBER_NAME]: ""
|
||||
};
|
||||
// TODO: improve - just pass the event from props
|
||||
selectedEvent = {
|
||||
...selectedEvent,
|
||||
handlers: [...(selectedEvent.handlers || []), newEventHandler]
|
||||
};
|
||||
// events = [...events, newEventHandler];
|
||||
onPropChanged(newEventType, [...selectedEvent.handlers, newEventHandler]);
|
||||
};
|
||||
|
||||
const changeEventHandler = (updatedHandler, index) => {
|
||||
// TODO: Improve
|
||||
const handlers = [...selectedEvent.handlers];
|
||||
handlers[index] = updatedHandler;
|
||||
|
||||
console.log("CHANGED HANDLERS", handlers);
|
||||
|
||||
selectedEvent = {
|
||||
...selectedEvent,
|
||||
handlers
|
||||
};
|
||||
|
||||
onPropChanged(newEventType, handlers);
|
||||
};
|
||||
|
||||
// TODO: verify
|
||||
const removeEventHandler = index => {
|
||||
const handlers = [...selectedEvent.handlers];
|
||||
handlers.splice(index, 1);
|
||||
onPropChanged(newEventType, handlers);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
@ -125,8 +84,7 @@
|
|||
.handler-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-gap: 10px;
|
||||
border: 2px solid #fafafa;
|
||||
border: 2px solid #f9f9f9;
|
||||
}
|
||||
|
||||
.hierarchy-item {
|
||||
|
@ -134,52 +92,66 @@
|
|||
padding: 11px 7px;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
font-size: 1.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hierarchy-item:hover {
|
||||
background: #fafafa;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.event-name {
|
||||
font-size: 12px;
|
||||
color: rgba(35, 65, 105, 0.4);
|
||||
grid-column: 1 / span 2;
|
||||
}
|
||||
|
||||
.event-identifier {
|
||||
margin-top: 5px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: rgba(22, 48, 87, 0.6)
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.event-name {
|
||||
}
|
||||
|
||||
.handler-identifier {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="heading">
|
||||
<h3>Events</h3>
|
||||
<PlusButton on:click={() => openModal({})} />
|
||||
<PlusButton on:click={() => openModal()} />
|
||||
</div>
|
||||
|
||||
<div class="root">
|
||||
|
||||
<form class="uk-form-stacked form-root">
|
||||
{#each events as [name, handlers], index}
|
||||
{#if handlers.length > 0}
|
||||
{#each events as event, index}
|
||||
{#if event.handlers.length > 0}
|
||||
<div
|
||||
class="handler-container hierarchy-item {selectedEvent.index === index ? 'selected' : ''}"
|
||||
on:click={() => openModal({ name, handlers, index })}>
|
||||
<span class="event-name">{name}</span>
|
||||
class="handler-container hierarchy-item {selectedEvent && selectedEvent.index === index ? 'selected' : ''}"
|
||||
on:click={() => openModal({ ...event, index })}>
|
||||
<span class="event-name">{event.name}</span>
|
||||
<span class="event-identifier">{event.name}</span>
|
||||
<span class="edit-text">EDIT</span>
|
||||
<span class="handler-identifier">updateState</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</form>
|
||||
</div>
|
||||
<EventEditorModal
|
||||
{onPropChanged}
|
||||
events={events}
|
||||
open={modalOpen}
|
||||
onClose={closeModal}
|
||||
event={selectedEvent}
|
||||
{events}
|
||||
{addEventHandler}
|
||||
{changeEventHandler}
|
||||
{removeEventHandler} />
|
||||
/>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<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 StateBindingControl from "../StateBindingControl.svelte";
|
||||
import { find, map, keys, reduce, keyBy } from "lodash/fp";
|
||||
import { pipe, userWithFullAccess } from "../../common/core";
|
||||
import {
|
||||
|
@ -11,9 +12,12 @@
|
|||
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;
|
||||
|
@ -76,44 +80,60 @@
|
|||
|
||||
<style>
|
||||
.type-selector-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 10px;
|
||||
background: #fafafa;
|
||||
padding: 22px;
|
||||
border: 1px solid var(--primary75);
|
||||
}
|
||||
|
||||
.type-selector {
|
||||
border-color: var(--primary50);
|
||||
border-radius: 2px;
|
||||
flex: 1 0 auto;
|
||||
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;
|
||||
}
|
||||
|
||||
.handler-option > div {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.new-handler {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.handler-controls {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 10px;
|
||||
padding: 22px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="type-selector-container">
|
||||
<div class="handler-option">
|
||||
Action
|
||||
<Select value={handlerType} on:change={handlerTypeChanged}>
|
||||
<option />
|
||||
{#each eventOptions as option}
|
||||
<option value={option.name}>{option.name}</option>
|
||||
<div class="type-selector-container {newHandler && 'new-handler'}">
|
||||
<div class="handler-controls">
|
||||
<div class="handler-option">
|
||||
Action
|
||||
<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">
|
||||
<div>{param.name}</div>
|
||||
<StateBindingControl
|
||||
onChanged={onParameterChanged(idx)}
|
||||
value={param.value} />
|
||||
</div>
|
||||
{/each}
|
||||
</Select>
|
||||
{/if}
|
||||
</div>
|
||||
{#if parameters}
|
||||
{#each parameters as param, idx}
|
||||
<div class="handler-option">
|
||||
<div>{param.name}</div>
|
||||
<StateBindingControl
|
||||
onChanged={onParameterChanged(idx)}
|
||||
value={param.value} />
|
||||
</div>
|
||||
{/each}
|
||||
{#if newHandler}
|
||||
<PlusButton on:click={onCreate} />
|
||||
{:else}
|
||||
<IconButton icon="x" on:click={onRemoved} />
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
@ -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>
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import IconButton from "../common/IconButton.svelte";
|
||||
import Input from "../common/Input.svelte";
|
||||
import {
|
||||
isBinding, getBinding, setBinding
|
||||
} from "../common/binding";
|
||||
|
@ -81,13 +82,13 @@
|
|||
{#if isExpanded}
|
||||
<div>
|
||||
<div class="binding-prop-label">Binding Path</div>
|
||||
<input class="uk-input uk-form-small"
|
||||
<Input
|
||||
value={bindingPath}
|
||||
on:change={setBindingPath} >
|
||||
on:change={setBindingPath} />
|
||||
<div class="binding-prop-label">Fallback Value</div>
|
||||
<input class="uk-input uk-form-small"
|
||||
<Input
|
||||
value={bindingFallbackValue}
|
||||
on:change={setBindingFallback} >
|
||||
on:change={setBindingFallback} />
|
||||
<div class="binding-prop-label">Binding Source</div>
|
||||
<select class="uk-select uk-form-small"
|
||||
value={bindingSource}
|
||||
|
@ -119,7 +120,7 @@
|
|||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<input on:change={ev => onChanged(ev.target.value)}
|
||||
<Input on:change={ev => onChanged(ev.target.value)}
|
||||
bind:value={value}
|
||||
style="flex: 1 0 auto;" />
|
||||
{/if}
|
||||
|
|
Loading…
Reference in New Issue