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 { matchSorter } from 'match-sorter';
|
||||||
import Spinner from './Spinner.svelte';
|
import Spinner from './Spinner.svelte';
|
||||||
import type { KeyOption } from 'match-sorter';
|
import type { KeyOption } from 'match-sorter';
|
||||||
|
import { Tween } from 'svelte/motion';
|
||||||
|
import { cubicOut } from 'svelte/easing';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
@@ -147,7 +149,6 @@
|
|||||||
*/
|
*/
|
||||||
searchKeys?: ('value' | 'label' | 'preview' | 'infotext')[];
|
searchKeys?: ('value' | 'label' | 'preview' | 'infotext')[];
|
||||||
|
|
||||||
// TODO: implement searchKeys above.
|
|
||||||
/** Additional classes applied to the persistent div container */
|
/** Additional classes applied to the persistent div container */
|
||||||
class?: ClassValue | null | undefined;
|
class?: ClassValue | null | undefined;
|
||||||
/** Optional action applied to the main input */
|
/** Optional action applied to the main input */
|
||||||
@@ -216,7 +217,6 @@
|
|||||||
let searchValue = $state('');
|
let searchValue = $state('');
|
||||||
let pickerPosition = $state<'top' | 'bottom'>('bottom');
|
let pickerPosition = $state<'top' | 'bottom'>('bottom');
|
||||||
let searching = $state(false);
|
let searching = $state(false);
|
||||||
let iconWidth = $state<number | undefined>(undefined);
|
|
||||||
|
|
||||||
let searchInput = $state<HTMLInputElement | null>(null);
|
let searchInput = $state<HTMLInputElement | null>(null);
|
||||||
let searchContainer = $state<HTMLDivElement | null>(null);
|
let searchContainer = $state<HTMLDivElement | null>(null);
|
||||||
@@ -264,6 +264,29 @@
|
|||||||
/** validation options build from props */
|
/** validation options build from props */
|
||||||
const validateOpts: ValidatorOptions = $derived({ required });
|
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 ***/
|
/*** HELPER FUNCTIONS ***/
|
||||||
|
|
||||||
/** returns the index of the highlighted item in filteredItems */
|
/** returns the index of the highlighted item in filteredItems */
|
||||||
@@ -637,8 +660,8 @@
|
|||||||
{#if iconVisible}
|
{#if iconVisible}
|
||||||
<div
|
<div
|
||||||
class={[
|
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
|
transition:scale
|
||||||
bind:clientWidth={iconWidth}
|
bind:clientWidth={iconWidth}
|
||||||
@@ -663,7 +686,7 @@
|
|||||||
|
|
||||||
<!-- Combobox input box -->
|
<!-- Combobox input box -->
|
||||||
<StyledRawInput
|
<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!']}
|
class={[caret && 'pr-9', !valid && 'border-red-500!']}
|
||||||
{compact}
|
{compact}
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
Reference in New Issue
Block a user