From 0b6442528477383849ae42c706be87fb07c9a83c Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Thu, 6 Feb 2025 19:48:22 +0100 Subject: [PATCH] Lib: Replace the popup with a native select element + bind the value --- src/lib/components/cards/DriverCard.svelte | 2 +- src/lib/components/cards/RaceCard.svelte | 7 +- src/lib/components/cards/RacePickCard.svelte | 36 +++--- .../components/cards/RaceResultCard.svelte | 19 ++- .../components/cards/SubstitutionCard.svelte | 33 +++-- src/lib/components/form/Dropdown.svelte | 113 ++---------------- 6 files changed, 60 insertions(+), 150 deletions(-) diff --git a/src/lib/components/cards/DriverCard.svelte b/src/lib/components/cards/DriverCard.svelte index 428bc57..aec3254 100644 --- a/src/lib/components/cards/DriverCard.svelte +++ b/src/lib/components/cards/DriverCard.svelte @@ -92,7 +92,7 @@ {#await data.teams then teams} {#await data.graphics then graphics} @@ -86,7 +89,7 @@ { - node.addEventListener("DropdownChange", update_pxx_preview); - }; - - // This event handler is registered to the Dropdown's element through the action above. - const update_pxx_preview = async (event: Event) => { - const target: HTMLInputElement = event.target as HTMLInputElement; - - const src: string = - get_by_value(await data.drivers, "code", target.value)?.headshot_url || ""; - const img = document.getElementById("headshot_preview") as HTMLImageElement; - - // Can be null if lazyimg not loaded - if (img) img.src = src; - }; + // Await promises + let drivers: Driver[] | undefined = $state(undefined); + data.drivers.then((d: Driver[]) => (drivers = d)); const required: boolean = $derived(!racepick); const disabled: boolean = $derived(!data.admin); @@ -86,6 +73,14 @@ let pxx_select_value: string = $state(racepick?.pxx ?? ""); let dnf_select_value: string = $state(racepick?.dnf ?? ""); + + // Update preview + $effect(() => { + if (!drivers) return; + const src: string = get_by_value(drivers, "id", pxx_select_value)?.headshot_url ?? ""; + const img: HTMLImageElement = document.getElementById("headshot_preview") as HTMLImageElement; + if (img) img.src = src; + }); {#await Promise.all([data.graphics, data.drivers]) then [graphics, drivers]} @@ -118,8 +113,7 @@ {#await active_drivers_and_substitutes then pxx_drivers} P{data.currentrace?.pxx ?? "XX"} - {/await} - - {#await active_drivers_and_substitutes then pxx_drivers} + { + races = r; + }); + const required: boolean = $derived(!result); const disabled: boolean = $derived(!data.admin); const labelwidth: string = "70px"; @@ -38,10 +43,18 @@ // TODO: Currentrace needs to be updated once a race is selected // This way it doesn't update the placeholder (or the chips)... - const currentrace: Promise = $derived.by(async () => - get_by_value(await data.races, "id", race_select_value), + // const currentrace: Promise = $derived.by(async () => + // get_by_value(await data.races, "id", race_select_value), + // ); + + let currentrace: Race | undefined = $derived( + races ? (get_by_value(races, "id", race_select_value) ?? undefined) : undefined, ); + $effect(() => { + console.log("Updated currentrace", currentrace); + }); + let pxxs_input: string = $state(""); let pxxs_chips: string[] = $state([]); @@ -179,7 +192,7 @@ {#await data.races then races} - node.addEventListener("DropdownChange", update_substitute_preview); - - // This event handler is registered to the Dropdown's element through the action above. - const update_substitute_preview = async (event: Event) => { - const target: HTMLInputElement = event.target as HTMLInputElement; - - const src: string = - get_by_value(await data.drivers, "code", target.value)?.headshot_url ?? ""; - const img = document.getElementById("headshot_preview") as HTMLImageElement; - - // Can be null if lazyimage hasn't loaded - if (img) img.src = src; - }; + // Await promises + let drivers: Driver[] | undefined = $state(undefined); + data.drivers.then((d: Driver[]) => (drivers = d)); const active_drivers = (drivers: Driver[]): Driver[] => drivers.filter((driver: Driver) => driver.active); @@ -54,6 +42,14 @@ let substitute_select_value: string = $state(substitution?.substitute ?? ""); let driver_select_value: string = $state(substitution?.for ?? ""); let race_select_value: string = $state(substitution?.race ?? ""); + + // Update preview + $effect(() => { + if (!drivers) return; + const src: string = get_by_value(drivers, "id", substitute_select_value)?.headshot_url ?? ""; + const img: HTMLImageElement = document.getElementById("headshot_preview") as HTMLImageElement; + if (img) img.src = src; + }); {#await Promise.all([data.graphics, data.drivers]) then [graphics, drivers]} @@ -82,8 +78,7 @@ - import { ListBox, ListBoxItem, popup, type PopupSettings } from "@skeletonlabs/skeleton"; import type { Snippet } from "svelte"; - import type { Action } from "svelte/action"; - import type { HTMLInputAttributes } from "svelte/elements"; - import { v4 as uuid } from "uuid"; - import { type DropdownOption, LazyImage } from "$lib/components"; + import type { HTMLSelectAttributes } from "svelte/elements"; + import { type DropdownOption } from "$lib/components"; - interface DropdownProps extends HTMLInputAttributes { + interface DropdownProps extends HTMLSelectAttributes { children: Snippet; - /** Placeholder for the empty input element */ - placeholder?: string; - - /** Form name of the input element, to reference input data after form submission */ - name?: string; - /** Manually set the label width, to align multiple inputs vertically. Supply value in CSS units. */ labelwidth?: string; /** The variable to bind to the input element. Has to be a [$state] so its value can be updated with the input element's contents. */ - input_variable: string; - - /** Any action to bind to the input element */ - action?: Action; - - /** The ID of the popup to trigger. UUID by default. */ - popup_id?: string; - - /** The [PopupSettings] object for the popup to trigger. */ - popup_settings?: PopupSettings; + value?: string; /** The options this autocomplete component allows to choose from. * Example: [[{ label: "Aston", value: "0" }, { label: "VCARB", value: "1" }]]. @@ -38,42 +20,11 @@ let { children, - placeholder = "", - name = "", labelwidth = "auto", - input_variable, - action = undefined, - popup_id = uuid(), - popup_settings = { - event: "click", - target: popup_id, - placement: "bottom", - closeQuery: ".listbox-item", - }, + value = $bindable(), options, ...restProps }: DropdownProps = $props(); - - /** Find the "label" of an option by its "value" */ - const get_label = (value: string): string | undefined => { - return options.find((o) => o.value === value)?.label; - }; - - // Use an action to fill the "input" variable - // required to dispatch the custom event using $effect - let input: HTMLInputElement | undefined = undefined; - const obtain_input: Action = (node: HTMLElement) => { - input = node as HTMLInputElement; - }; - - // This will run everyting "input_variable" changes. - // The event is fired when the input's value is updated via JavaScript. - $effect(() => { - // Just list this so SvelteKit picks it up as dependency - input_variable; - - if (input) input.dispatchEvent(new CustomEvent("DropdownChange")); - });
@@ -83,55 +34,11 @@ > {@render children()}
- - {#if action} - event.preventDefault()} - value={get_label(input_variable) ?? placeholder} - {...restProps} - /> - {:else} - event.preventDefault()} - value={get_label(input_variable) ?? placeholder} - {...restProps} - /> - {/if} - - -
- +