site-libsoc/Server/app/sveltekit/src/components/select-component.svelte

257 lines
7.8 KiB
Svelte

<svelte:options tag="select-component" />
<script>
// Import libraries
import { onMount } from 'svelte'
import { px2rem,getTextWidth,getCanvasFont } from "/js/libraries/miscTools.js"
//Export
export let callback = null
export let options = [""]
export let value = null
export let valueindex = null
// Main code
let root = arguments[0]
let select
let optionsHolder
let optionButtons = []
let currentOption
let currentOptionButton
let init = false
let key = 0
let obs = null
$: setKeyValue(value,options)
$: setKeyIndex(valueindex,options)
$: changeOptionsWidth(select,optionsHolder)
function setKeyValue(value,options) {
if (value!==null) {
if (options.includes(value)) {
let index = options.findIndex((element) => element==value)
currentOption.innerHTML = value
optionButtons[index].style.display = "none"
valueindex = index
}
key += 1
}
}
function setKeyIndex(valueindex,options) {
if (valueindex!=null && options!=undefined && options[valueindex]!=value) {
value = options[valueindex]
key += 1
}
}
function indexToValue(index) {
value = options[index]
}
function changeVisibility() {
if (optionsHolder.style.display=="none") {
optionsHolder.style.display = "initial"
}
else {
optionsHolder.style.display = "none"
}
}
function changeOption(index,callback) {
valueindex = index
value = options[index]
if (callback!=undefined && callback!=null) {
callback(index)
}
}
function hideSelect() {
optionsHolder.style.display = "none"
}
function changeOptionsWidth(select,optionsHolder) {
let selectWidth
if (select!=undefined && optionsHolder!=undefined) {
let selectWidthText = getComputedStyle(select).getPropertyValue('--width')
if (isNaN(selectWidthText) || selectWidthText=="") {
if (obs==null) {
obs = new ResizeObserver(() => changeOptionsWidth(select,optionsHolder))
obs.observe(currentOptionButton)
return
}
else {
selectWidthText = getComputedStyle(currentOptionButton).getPropertyValue('width')
selectWidth = px2rem(parseFloat(selectWidthText.slice(0,selectWidthText.length-2)))
}
}
else {
selectWidth = parseFloat(selectWidthText.slice(0,selectWidthText.length-2))
}
let spanWidths = []
for (let i=0;i<optionsHolder.children.length;i++) {
let span = optionsHolder.children[i].children[0]
let spanWidth = getTextWidth(span.innerHTML, getCanvasFont(span))
spanWidths.push(spanWidth)
}
let maxOptionsWidth = px2rem(Math.max(...spanWidths))
if (maxOptionsWidth>selectWidth) {
let width = 1.1*maxOptionsWidth+"rem"
optionsHolder.style.width = width
for (let i=0;i<optionsHolder.children.length;i++) {
let button = optionsHolder.children[i]
button.style.width = width
}
optionsHolder.style.marginLeft = - (1.1*maxOptionsWidth - selectWidth) /2 - 0.05 + "rem"
}
else {
let width = selectWidth + 0.1 + "rem"
for (let i=0;i<optionsHolder.children.length;i++) {
let button = optionsHolder.children[i]
button.style.width = width
}
}
}
}
onMount(() => {
init = true
root.addEventListener('focusout', hideSelect)
})
</script>
<div bind:this={select} class="select">
{#key key}
<button bind:this={currentOptionButton} id="current-option-button" on:click={changeVisibility}>
<div id="current-options-div">
<span bind:this={currentOption} id="current-options-span">{value!=null ? value : ""}</span>
</div>
<img id="arrow-down" src="../assets/arrow_down.svg" alt="arrow down">
</button>
<div bind:this={optionsHolder} id="options-holder" style="display: none">
{#each options as option, i}
<button bind:this={optionButtons[i]} value={i} on:click={() => changeOption(i,callback)}>
<span>{option}</span>
</button>
{/each}
</div>
{/key}
</div>
<style>
@import '/css/common.css';
#current-options-div {
position: relative;
overflow: hidden;
width: calc(100% - 2.5rem);
text-align: var(--text-align,left);
padding-top: 0.5rem;
}
#arrow-down {
right: 0.5rem;
width: 1.365rem;
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.select {
position: relative;
margin-top: var(--margin-top,0);
width: var(--width);
max-width: var(--max-width);
height: var(--height,2.75rem);
border: var(--border,rgba(0,0,0,var(--opacity,1)) solid);
border-width: var(--border-width, 0.063rem);
border-radius: var(--border-radius,0.126rem);
}
.select button {
width: var(--width);
max-width: var(--max-width);
}
#current-option-button, #current-option-button * {
opacity: var(--opacity,1);
font-family: var(--font-family,var(--serif), serif);
font-size: var(--font-size, 1.3rem);
}
.select >:first-child {
margin-right: -2.75rem;
padding-right: 0.0rem;
}
.select span {
position: relative;
padding-top: 0.5rem;
padding-left: 0.3rem;
white-space: nowrap;
}
#current-option-button {
display: flex;
width: 100%;
height: 100%;
padding-left: 0.341rem;
font-weight: var(--font-weight,400);
}
#options-holder {
position: absolute;
margin-top: calc(-1 * var(--border-width, 0.063rem));
background: white;
z-index: 1;
margin-left: -0.05rem;
border-radius: var(--border-radius-options,0.126rem);
}
#options-holder * {
font-size: var(--options-font-size, 1.2rem);
font-family: var(--font-family,var(--serif), serif);
}
#options-holder button {
display: flex;
position: relative;
width: var(--width);
background: white;
font-weight: 400;
text-align: var(--text-align,left);
padding-top: 0.341rem;
padding-bottom: 0.341rem;
padding-right: 3.515rem;
padding-left: 0.341rem;
}
#options-holder button:hover {
background: #cdcdcd;
}
#options-holder button {
border: black solid;
border-width: 0 var(--border-width-options,var(--border-width, 0.063rem)) 0 var(--border-width-options,var(--border-width, 0.063rem));
}
#options-holder >:first-child {
border-top: black solid var(--border-width-options,var(--border-width, 0.063rem));
border-top-left-radius: var(--border-radius-options,0.126rem);
border-top-right-radius: var(--border-radius-options,0.126rem);
}
#options-holder >:last-child {
border-bottom: black solid var(--border-width-options,var(--border-width, 0.063rem));
border-bottom-left-radius: var(--border-radius-options,0.126rem);
border-bottom-right-radius: var(--border-radius-options,0.126rem);
}
</style>