feat(field-editor): add display_modal mode with placement, blocking toggle, and unsaved-changes guard
- New `display_modal` prop opens the edit panel as a native <dialog> anchored
near the pencil trigger instead of shifting inline content
- `modal_placement` (center|above|below|left|right, default center) positions
the dialog relative to the trigger via getBoundingClientRect + CSS transform
- `modal_blocking` (default true) toggles showModal() vs show(); non-modal
mode adds a document pointerdown listener to close on outside click
- `cancel_edit()` now warns "Discard unsaved changes?" when draft differs from
saved value (matches data store form behaviour); skips warning after a
successful save
- Dialog background uses theme CSS vars directly (--color-surface-50/900) via
:global CSS — Skeleton tonal presets are intentionally semi-transparent and
rendered behind table content without explicit position:fixed + z-index
- Extracted edit panel to {#snippet edit_panel()} — shared by inline and
dialog paths with no duplication
- data-stores table: all three inline field editors switched to display_modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -238,10 +238,10 @@ function content_preview(ds: ae_DataStore): string {
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container mx-auto space-y-6 p-4">
|
||||
<div class="space-y-6">
|
||||
|
||||
<!-- ── Header ──────────────────────────────────────────────────────────── -->
|
||||
<header class="bg-surface-50-900-token border-surface-500/10 flex flex-wrap items-center justify-between gap-4 rounded-xl border p-4 shadow-lg">
|
||||
<header class="bg-surface-100-900 border-surface-500/10 flex flex-wrap items-center justify-between gap-4 rounded-xl border p-4 shadow-lg">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-primary-500/10 rounded-lg p-2">
|
||||
<Database size={24} class="text-primary-500" />
|
||||
@@ -535,14 +535,17 @@ function content_preview(ds: ae_DataStore): string {
|
||||
<tbody>
|
||||
{#each results as ds (ds.id ?? ds.data_store_id)}
|
||||
{@const ds_id = ds.id ?? ds.data_store_id}
|
||||
<tr class="border-surface-500/10 hover:bg-surface-500/5 border-b transition-colors">
|
||||
<tr class="border-surface-500/10 hover:bg-surface-500/5 border-b transition-colors duration-200">
|
||||
<td class="px-3 py-2">
|
||||
<AE_Field_Editor
|
||||
object_type="data_store"
|
||||
object_id={ds_id}
|
||||
field_name="code"
|
||||
edit_label="Code"
|
||||
current_value={ds.code ?? ''}
|
||||
placeholder="store_code"
|
||||
display_modal={true}
|
||||
modal_blocking={false}
|
||||
on_success={() => do_search(false)}>
|
||||
<span class="font-mono" class:opacity-40={!ds.enable}>{ds.code}</span>
|
||||
{#if !ds.enable}<span class="badge preset-tonal-error ml-1 text-[9px]">off</span>{/if}
|
||||
@@ -554,8 +557,10 @@ function content_preview(ds: ae_DataStore): string {
|
||||
object_type="data_store"
|
||||
object_id={ds_id}
|
||||
field_name="name"
|
||||
edit_label="Name"
|
||||
current_value={ds.name ?? ''}
|
||||
placeholder="Display name"
|
||||
display_modal={true}
|
||||
on_success={() => do_search(false)} />
|
||||
</td>
|
||||
<td class="px-3 py-2">
|
||||
@@ -563,9 +568,11 @@ function content_preview(ds: ae_DataStore): string {
|
||||
object_type="data_store"
|
||||
object_id={ds_id}
|
||||
field_name="type"
|
||||
edit_label="Type"
|
||||
current_value={ds.type ?? 'text'}
|
||||
field_type="select"
|
||||
select_options={ds_type_options}
|
||||
display_modal={true}
|
||||
on_success={() => do_search(false)}>
|
||||
<span class="badge {type_badge(ds.type)} font-mono text-[9px] uppercase">{ds.type ?? '?'}</span>
|
||||
</AE_Field_Editor>
|
||||
|
||||
Reference in New Issue
Block a user