phonograph/svelte/src/expression-editor.webc.svelte
2025-10-09 08:00:53 +00:00

113 lines
3.3 KiB
Svelte

<svelte:options
customElement={{
props: {
identifier_hints: { attribute: "identifier-hints", type: "Array" },
value: { reflect: true, type: "Object" },
},
shadow: "none",
tag: "expression-editor",
}}
/>
<script lang="ts">
import EncodableEditor from "./encodable-editor.svelte";
import ExpressionSelector from "./expression-selector.svelte";
import { type PgExpressionAny } from "./expression.svelte";
import ExpressionEditor from "./expression-editor.webc.svelte";
import {
DEFAULT_EDITOR_STATE,
editor_state_from_encodable,
type EditorState,
encodable_from_editor_state,
} from "./editor-state.svelte";
import { type FieldInfo } from "./field.svelte";
import { type Presentation } from "./presentation.svelte";
const ASSIGNABLE_PRESENTATIONS: Presentation[] = [
{ t: "Text", c: { input_mode: { t: "MultiLine", c: {} } } },
{ t: "Timestamp", c: {} },
{ t: "Uuid", c: {} },
];
const ASSIGNABLE_FIELDS: FieldInfo[] = ASSIGNABLE_PRESENTATIONS.map(
(presentation) => ({
field: {
id: "",
table_label: "",
name: "",
presentation,
table_width_px: -1,
},
not_null: true,
has_default: false,
}),
);
type Props = {
identifier_hints?: string[];
value?: PgExpressionAny;
};
let { identifier_hints = [], value = $bindable() }: Props = $props();
let editor_state = $state<EditorState>(
value?.t === "Literal"
? editor_state_from_encodable(value.c)
: DEFAULT_EDITOR_STATE,
);
let editor_field_info = $state<FieldInfo>(ASSIGNABLE_FIELDS[0]);
$effect(() => {
if (value?.t === "Literal" && editor_field_info) {
const encodable_value = encodable_from_editor_state(
editor_state,
editor_field_info.field.presentation,
);
if (encodable_value) {
value.c = encodable_value;
}
}
});
function handle_identifier_selector_change(
ev: Event & { currentTarget: HTMLSelectElement },
) {
if (value?.t === "Identifier") {
value.c.parts_raw = [ev.currentTarget.value];
}
}
</script>
<div class="expression-editor__container">
<div class="expression-editor__sidebar">
<ExpressionSelector bind:value />
</div>
{#if value !== undefined}
<div class="expression-editor__main">
<div class="expression-editor__params">
{#if value.t === "Comparison"}
{#if value.c.t === "Infix"}
<ExpressionEditor bind:value={value.c.c.lhs} {identifier_hints} />
<ExpressionEditor bind:value={value.c.c.rhs} {identifier_hints} />
{:else if value.c.t === "IsNull" || value.c.t === "IsNotNull"}
<ExpressionEditor bind:value={value.c.c.lhs} {identifier_hints} />
{/if}
{:else if value.t === "Identifier"}
<select
onchange={handle_identifier_selector_change}
value={value.c.parts_raw[0]}
>
{#each identifier_hints as hint}
<option value={hint}>{hint}</option>
{/each}
</select>
{:else if value.t === "Literal"}
<EncodableEditor
bind:editor_state
bind:field_info={editor_field_info}
assignable_fields={ASSIGNABLE_FIELDS}
/>
{/if}
</div>
</div>
{/if}
</div>