diff --git a/datasette/static/app.css b/datasette/static/app.css index 9a57ad90..6971635b 100644 --- a/datasette/static/app.css +++ b/datasette/static/app.css @@ -1272,46 +1272,8 @@ dialog.row-delete-dialog { } dialog.row-edit-dialog { - --ink: #0f0f0f; - --paper: #eef6ff; - --muted: #6b6b6b; - --rule: #d8e6f5; - --accent: #1a56db; - --card: #ffffff; - border: none; - border-radius: var(--modal-border-radius, 0.75rem); - padding: 0; - margin: auto; width: min(720px, calc(100vw - 32px)); - max-width: 95vw; max-height: min(780px, calc(100vh - 32px)); - box-shadow: var(--modal-shadow, 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)); - animation: datasette-modal-slide-in var(--modal-animation-duration, 0.2s) ease-out; - overflow: hidden; - font-family: system-ui, -apple-system, sans-serif; - background: var(--card); -} - -dialog.row-edit-dialog[open] { - display: flex; - flex-direction: column; -} - -dialog.row-edit-dialog::backdrop { - background: var(--modal-backdrop-bg, rgba(0, 0, 0, 0.5)); - backdrop-filter: var(--modal-backdrop-blur, blur(4px)); - -webkit-backdrop-filter: var(--modal-backdrop-blur, blur(4px)); - animation: datasette-modal-fade-in var(--modal-animation-duration, 0.2s) ease-out; -} - -.row-edit-dialog .modal-header { - padding: 20px 24px 12px; - border-bottom: 1px solid var(--rule); - display: flex; - align-items: center; - gap: 12px; - flex-shrink: 0; - min-width: 0; } .row-edit-dialog .modal-title { @@ -1320,9 +1282,6 @@ dialog.row-edit-dialog::backdrop { gap: 0.35rem; min-width: 0; max-width: 100%; - font-size: 1rem; - font-weight: 600; - color: var(--ink); } .row-edit-dialog .modal-title .row-dialog-action, @@ -1692,7 +1651,7 @@ textarea.row-edit-input { justify-content: flex-start; } -.row-edit-bulk-actions .btn { +.row-edit-bulk-actions .modal-btn { padding-left: 12px; padding-right: 12px; } @@ -1936,17 +1895,6 @@ datasette-autocomplete input[type="text"], max-width: 46rem; } -.row-edit-dialog .modal-footer { - padding: 14px 20px; - border-top: 1px solid var(--rule); - display: flex; - align-items: center; - justify-content: flex-end; - gap: 10px; - flex-shrink: 0; - background: var(--paper); -} - .row-edit-mode-link { color: var(--accent); font-size: 0.9rem; @@ -1957,39 +1905,7 @@ datasette-autocomplete input[type="text"], display: none; } -.row-edit-dialog .btn { - border: none; - border-radius: 5px; - padding: 9px 20px; - font-size: 0.85rem; - font-weight: 500; - cursor: pointer; - touch-action: manipulation; - font-family: inherit; - transition: background 0.12s; -} - -.row-edit-dialog .btn-ghost { - background: transparent; - color: var(--muted); - border: 1px solid var(--rule); -} - -.row-edit-dialog .btn-ghost:hover { - background: var(--rule); - color: var(--ink); -} - -.row-edit-dialog .btn-primary { - background: var(--accent); - color: #fff; -} - -.row-edit-dialog .btn-primary:hover { - background: #1949b8; -} - -.row-edit-dialog .btn:disabled { +.row-edit-dialog .modal-btn:disabled { opacity: 0.55; cursor: not-allowed; } diff --git a/datasette/static/edit-tools.js b/datasette/static/edit-tools.js index 402af956..edb00c7f 100644 --- a/datasette/static/edit-tools.js +++ b/datasette/static/edit-tools.js @@ -5572,6 +5572,7 @@ function setRowEditDialogLoading(state, isLoading) { function setRowEditDialogSaving(state, isSaving) { state.isSaving = isSaving; + state.modal.busy = isSaving; updateRowEditDialogButtons(state); } @@ -5789,18 +5790,6 @@ function confirmDiscardRowEditChanges(state) { return window.confirm(message); } -function closeRowEditDialogIfConfirmed(state) { - if (!state || state.isSaving) { - return false; - } - if (!confirmDiscardRowEditChanges(state)) { - return false; - } - state.shouldRestoreFocus = true; - state.dialog.close(); - return true; -} - function setRowInsertDialogTitle(state) { var insertData = tableInsertData() || {}; var title = rowEditIsMultipleInsert(state) @@ -6626,38 +6615,6 @@ async function insertBulkPreviewRows(state) { } } -function scheduleCloseRowEditDialogIfConfirmed(state) { - // Fix for an issue in Safari where hitting Esc would show - // the confirm() prompt asking if state should be discarded - // but the Esc key press would then cancel that dialog too. - // Wait for keyup, then move the confirm() to a fresh timer tick. - if (!state || state.isSaving || state.isClosePending) { - return false; - } - if (!rowEditDialogHasChanges(state)) { - state.shouldRestoreFocus = true; - state.dialog.close(); - return true; - } - state.isClosePending = true; - var closeAfterKeyup = function () { - if (!state.isClosePending) { - return; - } - state.isClosePending = false; - closeRowEditDialogIfConfirmed(state); - }; - var onKeyup = function (ev) { - if (ev.key !== "Escape") { - return; - } - document.removeEventListener("keyup", onKeyup, true); - setTimeout(closeAfterKeyup, 0); - }; - document.addEventListener("keyup", onKeyup, true); - return true; -} - function findDataRowElement(root, rowId) { var elements = root.querySelectorAll("[data-row]"); for (var i = 0; i < elements.length; i += 1) { @@ -6747,9 +6704,8 @@ async function saveRowEditDialog(state) { } var formValues = collectRowFormValues(state); if (state.mode === "edit" && !Object.keys(formValues).length) { - state.shouldRestoreFocus = true; hideRowMutationStatus(); - state.dialog.close(); + state.modal.close(); return; } var payload = @@ -6782,9 +6738,8 @@ async function saveRowEditDialog(state) { insertedRowData, insertData.primaryKeys || [], ); - state.shouldRestoreFocus = false; if (!insertedRowId) { - state.dialog.close(); + state.modal.close({ restoreFocus: false }); var missingIdStatus = showRowMutationStatus( state.manager, "Inserted row. Refresh the page to see it.", @@ -6800,7 +6755,7 @@ async function saveRowEditDialog(state) { try { insertedRow = await fetchUpdatedRowElement(state); } catch (_error) { - state.dialog.close(); + state.modal.close({ restoreFocus: false }); var refreshFailedStatus = showRowMutationStatus( state.manager, "Inserted row, but could not refresh the table row. Refresh the page to see it.", @@ -6815,7 +6770,7 @@ async function saveRowEditDialog(state) { rowTitleLabel(insertedRow), ); var addedRow = addInsertedRowToPage(insertedRow); - state.dialog.close(); + state.modal.close({ restoreFocus: false }); showRowMutationStatus(state.manager, insertedStatusMessage, false); if (addedRow) { var insertedFocusTarget = @@ -6824,7 +6779,7 @@ async function saveRowEditDialog(state) { insertedFocusTarget.focus(); } } else { - state.dialog.close(); + state.modal.close({ restoreFocus: false }); var filteredStatus = showRowMutationStatus( state.manager, "Inserted row. It does not match the current filters.", @@ -6836,8 +6791,7 @@ async function saveRowEditDialog(state) { } if (isRowPage()) { - state.shouldRestoreFocus = false; - state.dialog.close(); + state.modal.close({ restoreFocus: false }); location.reload(); return; } @@ -6873,8 +6827,7 @@ async function saveRowEditDialog(state) { ); } - state.shouldRestoreFocus = false; - state.dialog.close(); + state.modal.close({ restoreFocus: false }); if (focusTarget && document.contains(focusTarget)) { focusTarget.focus(); } @@ -7018,7 +6971,8 @@ function ensureRowEditDialog(manager) { return null; } - var dialog = document.createElement("dialog"); + var modal = DatasetteModal.create(); + var dialog = modal.dialog; dialog.id = ROW_EDIT_DIALOG_ID; dialog.className = "row-edit-dialog"; dialog.setAttribute("aria-labelledby", "row-edit-title"); @@ -7048,7 +7002,7 @@ function ensureRowEditDialog(manager) {