Badges: auto-focus input when field accordion opens; add Revert button to field forms
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_func } from '$lib/ae_events_functions';
|
||||
import { browser } from '$app/environment';
|
||||
import { Pencil, Check, X, LoaderCircle, ChevronDown, Printer } from 'lucide-svelte';
|
||||
import { Pencil, Check, X, LoaderCircle, ChevronDown, Printer, RotateCcw } from 'lucide-svelte';
|
||||
|
||||
interface Props {
|
||||
event_id: string;
|
||||
@@ -283,6 +283,33 @@
|
||||
?? $lq__event_badge_obj?.badge_type_code
|
||||
?? ''
|
||||
);
|
||||
|
||||
// --- Focus management: focus the input when its accordion opens ---
|
||||
// rAF gives the CSS accordion one repaint tick before focus() is called,
|
||||
// avoiding jumping to an invisible (height: 0) element.
|
||||
let input_ref_name: HTMLInputElement | undefined;
|
||||
let input_ref_title: HTMLInputElement | undefined;
|
||||
let input_ref_affiliations: HTMLTextAreaElement | undefined;
|
||||
let input_ref_location: HTMLInputElement | undefined;
|
||||
let input_ref_pronouns: HTMLInputElement | undefined;
|
||||
let input_ref_allow_tracking: HTMLInputElement | undefined;
|
||||
let select_ref_badge_type: HTMLSelectElement | undefined;
|
||||
|
||||
$effect(() => {
|
||||
const field = active_field;
|
||||
if (!field) return;
|
||||
requestAnimationFrame(() => {
|
||||
switch (field) {
|
||||
case 'name': input_ref_name?.focus(); break;
|
||||
case 'title': input_ref_title?.focus(); break;
|
||||
case 'affiliations': input_ref_affiliations?.focus(); break;
|
||||
case 'location': input_ref_location?.focus(); break;
|
||||
case 'pronouns': input_ref_pronouns?.focus(); break;
|
||||
case 'allow_tracking': input_ref_allow_tracking?.focus(); break;
|
||||
case 'badge_type': select_ref_badge_type?.focus(); break;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- ============================================================
|
||||
@@ -332,9 +359,21 @@
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<!-- Save/cancel row (inside accordion edit forms) -->
|
||||
{#snippet field_actions(field_key: string, on_save: () => void, on_cancel: () => void)}
|
||||
<!-- Save/cancel row (inside accordion edit forms).
|
||||
on_revert is optional — only passed when an override is currently saved;
|
||||
clears the override back to the base imported value. Layout: [Revert] [Save] [X] -->
|
||||
{#snippet field_actions(field_key: string, on_save: () => void, on_cancel: () => void, on_revert?: () => void)}
|
||||
<div class="flex gap-2 mt-2">
|
||||
{#if on_revert}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-warning shrink-0"
|
||||
onclick={on_revert}
|
||||
disabled={field_save_status[field_key] === 'saving'}
|
||||
title="Remove override — restore original imported value"
|
||||
aria-label="Revert to original value"
|
||||
><RotateCcw size="13" /></button>
|
||||
{/if}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm flex-1"
|
||||
@@ -453,13 +492,17 @@
|
||||
name="ctrl-full-name"
|
||||
type="text"
|
||||
class="input w-full"
|
||||
bind:this={input_ref_name}
|
||||
bind:value={edit_full_name_override}
|
||||
placeholder={$lq__event_badge_obj?.full_name ?? 'Full name'}
|
||||
/>
|
||||
{@render field_actions(
|
||||
'name',
|
||||
() => save_field('name', { full_name_override: edit_full_name_override || null }),
|
||||
() => cancel_field('name')
|
||||
() => cancel_field('name'),
|
||||
$lq__event_badge_obj?.full_name_override
|
||||
? () => save_field('name', { full_name_override: null })
|
||||
: undefined
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -501,13 +544,17 @@
|
||||
name="ctrl-pro-title"
|
||||
type="text"
|
||||
class="input w-full"
|
||||
bind:this={input_ref_title}
|
||||
bind:value={edit_professional_title_override}
|
||||
placeholder={$lq__event_badge_obj?.professional_title ?? 'Professional title'}
|
||||
/>
|
||||
{@render field_actions(
|
||||
'title',
|
||||
() => save_field('title', { professional_title_override: edit_professional_title_override || null }),
|
||||
() => cancel_field('title')
|
||||
() => cancel_field('title'),
|
||||
$lq__event_badge_obj?.professional_title_override
|
||||
? () => save_field('title', { professional_title_override: null })
|
||||
: undefined
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -549,13 +596,17 @@
|
||||
name="ctrl-affiliations"
|
||||
class="textarea w-full"
|
||||
rows="2"
|
||||
bind:this={input_ref_affiliations}
|
||||
bind:value={edit_affiliations_override}
|
||||
placeholder={$lq__event_badge_obj?.affiliations ?? 'Organization / affiliations'}
|
||||
></textarea>
|
||||
{@render field_actions(
|
||||
'affiliations',
|
||||
() => save_field('affiliations', { affiliations_override: edit_affiliations_override || null }),
|
||||
() => cancel_field('affiliations')
|
||||
() => cancel_field('affiliations'),
|
||||
$lq__event_badge_obj?.affiliations_override
|
||||
? () => save_field('affiliations', { affiliations_override: null })
|
||||
: undefined
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -597,13 +648,17 @@
|
||||
name="ctrl-location"
|
||||
type="text"
|
||||
class="input w-full"
|
||||
bind:this={input_ref_location}
|
||||
bind:value={edit_location_override}
|
||||
placeholder={$lq__event_badge_obj?.location ?? 'City, State / Country'}
|
||||
/>
|
||||
{@render field_actions(
|
||||
'location',
|
||||
() => save_field('location', { location_override: edit_location_override || null }),
|
||||
() => cancel_field('location')
|
||||
() => cancel_field('location'),
|
||||
$lq__event_badge_obj?.location_override
|
||||
? () => save_field('location', { location_override: null })
|
||||
: undefined
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -640,6 +695,7 @@
|
||||
name="ctrl-allow-tracking"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
bind:this={input_ref_allow_tracking}
|
||||
bind:checked={edit_allow_tracking}
|
||||
/>
|
||||
<span class="text-xs">Allow exhibitor lead scanning</span>
|
||||
@@ -685,13 +741,17 @@
|
||||
name="ctrl-pronouns"
|
||||
type="text"
|
||||
class="input w-full"
|
||||
bind:this={input_ref_pronouns}
|
||||
bind:value={edit_pronouns_override}
|
||||
placeholder={$lq__event_badge_obj?.pronouns ?? 'e.g. they/them'}
|
||||
/>
|
||||
{@render field_actions(
|
||||
'pronouns',
|
||||
() => save_field('pronouns', { pronouns_override: edit_pronouns_override || null }),
|
||||
() => cancel_field('pronouns')
|
||||
() => cancel_field('pronouns'),
|
||||
$lq__event_badge_obj?.pronouns_override
|
||||
? () => save_field('pronouns', { pronouns_override: null })
|
||||
: undefined
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -739,6 +799,7 @@
|
||||
id="ctrl-badge-type"
|
||||
name="ctrl-badge-type"
|
||||
class="select w-full"
|
||||
bind:this={select_ref_badge_type}
|
||||
bind:value={edit_badge_type_code}
|
||||
>
|
||||
<option value={null}>— Select badge type —</option>
|
||||
@@ -756,7 +817,10 @@
|
||||
? (badge_type_code_li.find(item => item.code === edit_badge_type_code)?.name ?? edit_badge_type_code)
|
||||
: null
|
||||
}),
|
||||
() => cancel_field('badge_type')
|
||||
() => cancel_field('badge_type'),
|
||||
$lq__event_badge_obj?.badge_type_code_override
|
||||
? () => save_field('badge_type', { badge_type_code_override: null, badge_type_override: null })
|
||||
: undefined
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user