combobox: improve icon padding behaviour
Tween the value and make it more consistent with the underlying StyledRawInput type.
This commit is contained in:
@@ -50,6 +50,8 @@
|
||||
import { matchSorter } from 'match-sorter';
|
||||
import Spinner from './Spinner.svelte';
|
||||
import type { KeyOption } from 'match-sorter';
|
||||
import { Tween } from 'svelte/motion';
|
||||
import { cubicOut } from 'svelte/easing';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
@@ -147,7 +149,6 @@
|
||||
*/
|
||||
searchKeys?: ('value' | 'label' | 'preview' | 'infotext')[];
|
||||
|
||||
// TODO: implement searchKeys above.
|
||||
/** Additional classes applied to the persistent div container */
|
||||
class?: ClassValue | null | undefined;
|
||||
/** Optional action applied to the main input */
|
||||
@@ -216,7 +217,6 @@
|
||||
let searchValue = $state('');
|
||||
let pickerPosition = $state<'top' | 'bottom'>('bottom');
|
||||
let searching = $state(false);
|
||||
let iconWidth = $state<number | undefined>(undefined);
|
||||
|
||||
let searchInput = $state<HTMLInputElement | null>(null);
|
||||
let searchContainer = $state<HTMLDivElement | null>(null);
|
||||
@@ -264,6 +264,29 @@
|
||||
/** validation options build from props */
|
||||
const validateOpts: ValidatorOptions = $derived({ required });
|
||||
|
||||
/** calculates padding for the input based on icon visibility and size */
|
||||
const calculatePadding = () => {
|
||||
const gap = 5; // gap between icon and text
|
||||
// base padding when no icon is visible, see StyledRawInput padding
|
||||
const basePadding = compact ? 12 : 18;
|
||||
// if icon is visible, padding is icon width + gap + base padding,
|
||||
// otherwise it's just base padding
|
||||
return iconVisible ? iconWidth + gap + basePadding : basePadding;
|
||||
};
|
||||
let iconWidth = $state<number>(0);
|
||||
/** tweens main input padding */
|
||||
const inputPadding = new Tween(calculatePadding(), {
|
||||
duration: 150,
|
||||
easing: cubicOut
|
||||
});
|
||||
$effect(() => {
|
||||
if (iconWidth >= 0) {
|
||||
untrack(() => {
|
||||
inputPadding.target = calculatePadding();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/*** HELPER FUNCTIONS ***/
|
||||
|
||||
/** returns the index of the highlighted item in filteredItems */
|
||||
@@ -637,8 +660,8 @@
|
||||
{#if iconVisible}
|
||||
<div
|
||||
class={[
|
||||
(iconWidth === undefined || iconWidth === 0) && 'opacity-0',
|
||||
'pointer-events-none absolute top-1/2 left-3.5 -translate-y-1/2 transform select-none'
|
||||
'pointer-events-none absolute top-1/2 left-3.5 -translate-y-1/2 transform select-none',
|
||||
iconWidth === 0 && 'opacity-0'
|
||||
]}
|
||||
transition:scale
|
||||
bind:clientWidth={iconWidth}
|
||||
@@ -663,7 +686,7 @@
|
||||
|
||||
<!-- Combobox input box -->
|
||||
<StyledRawInput
|
||||
style={iconWidth && iconVisible ? `padding-left: ${iconWidth + 14 + 10}px` : undefined}
|
||||
style={`padding-left: ${inputPadding.current}px`}
|
||||
class={[caret && 'pr-9', !valid && 'border-red-500!']}
|
||||
{compact}
|
||||
type="text"
|
||||
|
||||
Reference in New Issue
Block a user