phonograph/svelte/src/field-details.svelte

143 lines
3.9 KiB
Svelte
Raw Normal View History

2025-09-08 15:56:57 -07:00
<!--
@component
UI for inspecting and altering field configuration when creating or editing a
field. This is typically rendered within a popover component, and within an HTML
<form> element defining the appropriate action for form submission.
-->
<script lang="ts">
import {
type Presentation,
all_presentation_tags,
all_text_input_modes,
} from "./presentation.svelte";
type Assert<_T extends true> = void;
type Props = {
label_value: string;
name_input_disabled?: boolean;
name_value: string;
on_name_input?(
ev: Event & { currentTarget: EventTarget & HTMLInputElement },
): void;
on_presentation_input?(presentation: Presentation): void;
2025-09-08 15:56:57 -07:00
presentation?: Presentation;
};
let {
presentation = $bindable(get_empty_presentation("Text")),
name_input_disabled = false,
name_value = $bindable(),
label_value = $bindable(),
on_name_input,
on_presentation_input,
2025-09-08 15:56:57 -07:00
}: Props = $props();
function handle_presentation_tag_change(
ev: Event & { currentTarget: EventTarget & HTMLSelectElement },
) {
const tag = ev.currentTarget
.value as (typeof all_presentation_tags)[number];
presentation = get_empty_presentation(tag);
on_presentation_input?.(presentation);
2025-09-08 15:56:57 -07:00
}
function get_empty_presentation(
tag: (typeof all_presentation_tags)[number],
): Presentation {
if (tag === "Dropdown") {
return { t: "Dropdown", c: { allow_custom: true } };
}
2025-09-08 15:56:57 -07:00
if (tag === "Text") {
return { t: "Text", c: { input_mode: { t: "SingleLine", c: {} } } };
}
if (tag === "Timestamp") {
return { t: "Timestamp", c: {} };
}
if (tag === "Uuid") {
return { t: "Uuid", c: {} };
}
type _ = Assert<typeof tag extends never ? true : false>;
throw new Error("this should be unreachable");
}
function handle_text_input_mode_change(
ev: Event & { currentTarget: EventTarget & HTMLSelectElement },
) {
if (presentation.t === "Text") {
const tag = ev.currentTarget
.value as (typeof all_text_input_modes)[number];
if (tag === "SingleLine") {
presentation.c.input_mode = {
t: "SingleLine",
c: {},
};
} else if (tag === "MultiLine") {
presentation.c.input_mode = {
t: "MultiLine",
c: {},
};
} else {
type _ = Assert<typeof tag extends never ? true : false>;
throw new Error("this should be unreachable");
}
on_presentation_input?.(presentation);
2025-09-08 15:56:57 -07:00
}
}
</script>
<h2 class="form-section__heading">Field Details</h2>
<label class="form-section">
<div class="form-section__label">SQL-friendly Name</div>
<input
bind:value={name_value}
class="form-section__input form-section__input--text"
disabled={name_input_disabled}
name="name"
type="text"
/>
</label>
<label class="form-section">
<div class="form-section__label">Human-friendly Label</div>
<input
bind:value={label_value}
class="form-section__input form-section__input--text"
name="label"
oninput={on_name_input}
type="text"
/>
</label>
<label class="form-section">
<div class="form-section__label">Present As</div>
2025-09-08 15:56:57 -07:00
<select
class="form-section__input"
name="presentation_tag"
2025-09-08 15:56:57 -07:00
onchange={handle_presentation_tag_change}
value={presentation?.t}
>
{#each all_presentation_tags as presentation_tag}
<option value={presentation_tag}>
{presentation_tag}
</option>
{/each}
</select>
</label>
{#if presentation?.t === "Text"}
<label class="form-section">
<div class="form-section__label">Input Mode</div>
<select
class="form-section__input"
name="text_input_mode"
2025-09-08 15:56:57 -07:00
onchange={handle_text_input_mode_change}
value={presentation.c.input_mode.t}
>
{#each all_text_input_modes as input_mode}
<option value={input_mode}>
{input_mode}
</option>
{/each}
</select>
</label>
{/if}