Complete OptionSelect Component

This commit is contained in:
Conor_Mack 2020-05-28 16:24:53 +01:00
parent 1f8fa462a0
commit 73223debe9
10 changed files with 268 additions and 48 deletions

View File

@ -78,4 +78,8 @@
.switcher > .selected { .switcher > .selected {
color: var(--ink); color: var(--ink);
} }
.panel {
height: 100%;
}
</style> </style>

View File

@ -55,6 +55,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%;
} }
.design-view-state-categories { .design-view-state-categories {

View File

@ -1,36 +1,218 @@
<script> <script>
import { onMount } from "svelte" import { onMount, beforeUpdate } from "svelte"
export let value = "" //Create utilities and move this in
export let onChange = value => {} import { buildStyle } from "../../../../standard-components/src/buildStyle.js"
export let options = [] export let options = []
export let initialValue = "" export let value = ""
export let styleBindingProperty = "" export let styleBindingProperty
export let onChange = value => {}
let open = null
let rotate = ""
let select
let selectMenu
let icon
let selectYPosition = null
let availableSpace = 0
let positionSide = "top"
let maxHeight = null
let menuHeight
const handleStyleBind = value => const handleStyleBind = value =>
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {} !!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {}
$: isOptionsObject = options.every(o => typeof o === "object")
onMount(() => { onMount(() => {
if (!value && !!initialValue) { if (select) {
value = initialValue select.addEventListener("keydown", addSelectKeyEvents)
}
return () => {
select.removeEventListener("keydown", addSelectKeyEvents)
} }
}) })
function checkPosition() {
const { bottom, top: spaceAbove } = select.getBoundingClientRect()
const spaceBelow = window.innerHeight - bottom
if (spaceAbove > spaceBelow) {
positionSide = "bottom"
maxHeight = `${spaceAbove.toFixed(0) - 20}px`
} else {
positionSide = "top"
maxHeight = `${spaceBelow.toFixed(0) - 20}px`
}
}
function addSelectKeyEvents(e) {
if (e.key === "Enter") {
if (!open) {
toggleSelect(true)
}
} else if (e.key === "Escape") {
if (open) {
toggleSelect(false)
}
}
}
function toggleSelect(isOpen) {
checkPosition()
if (isOpen) {
icon.style.transform = "rotate(180deg)"
} else {
icon.style.transform = "rotate(0deg)"
}
open = isOpen
}
function handleClick(val) {
value = val
onChange(value)
}
$: menuStyle = buildStyle({
maxHeight,
transformOrigin: `center ${positionSide}`,
[positionSide]: "32px",
})
$: isOptionsObject = options.every(o => typeof o === "object")
$: selectedOption = isOptionsObject
? options.find(o => o.value === value)
: {}
$: displayLabel =
selectedOption && selectedOption.label ? selectedOption.label : value || ""
</script> </script>
<select <div
class="uk-select uk-form-small" tabindex="0"
{value} bind:this={select}
on:change={ev => onChange(ev.target.value)}> class="bb-select-container"
on:click={() => toggleSelect(!open)}>
<div class="bb-select-anchor selected">
<span>{displayLabel}</span>
<i bind:this={icon} class="ri-arrow-down-s-fill" />
</div>
<div
bind:this={selectMenu}
style={menuStyle}
class="bb-select-menu"
class:open>
<ul>
{#if isOptionsObject} {#if isOptionsObject}
{#each options as { value, label }} {#each options as { value: v, label }}
<option {...handleStyleBind(value || label)} value={value || label}> <li
{...handleStyleBind(v)}
on:click|self={handleClick(v)}
class:selected={value === v}>
{label} {label}
</option> </li>
{/each} {/each}
{:else} {:else}
{#each options as value} {#each options as v}
<option {...handleStyleBind(value)} {value}>{value}</option> <li
{...handleStyleBind(v)}
on:click|self={handleClick(v)}
class:selected={value === v}>
{v}
</li>
{/each} {/each}
{/if} {/if}
</select> </ul>
</div>
</div>
{#if open}
<div on:click|self={() => toggleSelect(false)} class="overlay" />
{/if}
<style>
.overlay {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 1;
}
.bb-select-container {
position: relative;
outline: none;
margin: 5px;
width: 164px;
height: 32px;
cursor: pointer;
}
.bb-select-anchor {
cursor: pointer;
display: flex;
padding: 5px 10px;
background-color: #f2f2f2;
border-radius: 2px;
border: 1px solid var(--grey-dark);
}
.bb-select-anchor > span {
color: #565a66;
font-weight: 500;
flex: 1;
}
.bb-select-anchor > i {
flex: 0 0 20px;
}
.selected {
color: #565a66;
font-weight: 500;
}
.bb-select-menu {
position: absolute;
display: flex;
box-sizing: border-box;
flex-direction: column;
opacity: 0;
width: 164px;
z-index: 2;
color: #808192;
font-weight: 500;
height: fit-content !important;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
border-right: 1px solid var(--grey-dark);
border-left: 1px solid var(--grey-dark);
border-bottom: 1px solid var(--grey-dark);
background-color: #f2f2f2;
transform: scale(0);
transition: opacity 0.13s linear, transform 0.12s cubic-bezier(0, 0, 0.2, 1);
overflow-y: auto;
}
.open {
transform: scale(1);
opacity: 1;
}
ul {
list-style-type: none;
margin: 0;
padding: 5px 10px;
}
li {
height: auto;
padding: 5px 0px;
cursor: pointer;
}
i {
transition: transform 0.13s ease;
transform-origin: center;
}
</style>

View File

@ -0,0 +1,33 @@
<script>
import { onMount } from "svelte"
export let value = ""
export let onChange = value => {}
export let options = []
export let initialValue = ""
export let styleBindingProperty = ""
const handleStyleBind = value =>
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {}
$: isOptionsObject = options.every(o => typeof o === "object")
onMount(() => {
if (!value && !!initialValue) {
value = initialValue
}
})
</script>
<select {value} on:change={ev => onChange(ev.target.value)}>
{#if isOptionsObject}
{#each options as { value, label }}
<option {...handleStyleBind(value || label)} value={value || label}>
{label}
</option>
{/each}
{:else}
{#each options as value}
<option {...handleStyleBind(value)} {value}>{value}</option>
{/each}
{/if}
</select>

View File

@ -49,6 +49,8 @@
.label { .label {
flex: 0 0 50px; flex: 0 0 50px;
display: flex;
align-items: center;
padding: 0px 5px; padding: 0px 5px;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;

View File

@ -70,12 +70,16 @@
} }
.property-panel { .property-panel {
height: 0px; /* height: 0px;
overflow: hidden; overflow: hidden; */
display: none;
} }
.show { .show {
overflow: auto; /* overflow: auto;
height: auto; height: auto; */
display: flex;
flex-direction: column;
flex: 1;
} }
</style> </style>

View File

@ -3,6 +3,7 @@
import InputGroup from "../common/Inputs/InputGroup.svelte" import InputGroup from "../common/Inputs/InputGroup.svelte"
import Colorpicker from "../common/Colorpicker.svelte" import Colorpicker from "../common/Colorpicker.svelte"
import { excludeProps } from "./propertyCategories.js" import { excludeProps } from "./propertyCategories.js"
import OptionSelectNew from "./OptionSelectNew.svelte"
export let panelDefinition = [] export let panelDefinition = []
export let componentDefinition = {} export let componentDefinition = {}
@ -16,6 +17,9 @@
} }
</script> </script>
<OptionSelectNew
options={['arial enjfhewhfhw iejfiewj ewfnew', 'comicsans', 'tachoma', 'bla']} />
{#if panelDefinition.length > 0} {#if panelDefinition.length > 0}
{#each panelDefinition as definition} {#each panelDefinition as definition}
{#if propExistsOnComponentDef(definition.key)} {#if propExistsOnComponentDef(definition.key)}

View File

@ -151,8 +151,7 @@
.components-pane { .components-pane {
grid-column: 3; grid-column: 3;
background-color: var(--white); background-color: var(--white);
height: 100vh; height: calc(100vh - 49px);
overflow-y: scroll;
} }
.components-nav-page { .components-nav-page {

View File

@ -13,9 +13,9 @@ export const layout = [
control: OptionSelect, control: OptionSelect,
initialValue: "columnReverse", initialValue: "columnReverse",
options: [ options: [
{ label: "row" }, { label: "row", value: "row" },
{ label: "row-reverse", value: "rowReverse" }, { label: "row-reverse", value: "rowReverse" },
{ label: "column" }, { label: "column", value: "column" },
{ label: "column-reverse", value: "columnReverse" }, { label: "column-reverse", value: "columnReverse" },
], ],
}, },
@ -25,7 +25,10 @@ export const layout = [
label: "Wrap", label: "Wrap",
key: "flex-wrap", key: "flex-wrap",
control: OptionSelect, control: OptionSelect,
options: [{ label: "wrap" }, { label: "no wrap", value: "noWrap" }], options: [
{ label: "wrap", value: "wrap" },
{ label: "no wrap", value: "noWrap" },
],
}, },
] ]
@ -59,13 +62,7 @@ export const position = [
label: "Position", label: "Position",
key: "position", key: "position",
control: OptionSelect, control: OptionSelect,
options: [ options: ["static", "relative", "fixed", "absolute", "sticky"],
{ label: "static" },
{ label: "relative" },
{ label: "fixed" },
{ label: "absolute" },
{ label: "sticky" },
],
}, },
] ]
@ -91,12 +88,7 @@ export const typography = [
label: "Weight", label: "Weight",
key: "font-weight", key: "font-weight",
control: OptionSelect, control: OptionSelect,
options: [ options: ["normal", "bold", "bolder", "lighter"],
{ label: "normal" },
{ label: "bold" },
{ label: "bolder" },
{ label: "lighter" },
],
}, },
{ label: "size", key: "font-size", defaultValue: "", control: Input }, { label: "size", key: "font-size", defaultValue: "", control: Input },
{ label: "Line H", key: "line-height", control: Input }, { label: "Line H", key: "line-height", control: Input },

View File

@ -163,7 +163,6 @@
grid-column: 3; grid-column: 3;
background-color: var(--white); background-color: var(--white);
min-height: 0px; min-height: 0px;
overflow-y: scroll;
} }
.components-nav-page { .components-nav-page {