Extract shared datasette-modal web component for all modal dialogs#2820
Open
simonw wants to merge 7 commits into
Open
Extract shared datasette-modal web component for all modal dialogs#2820simonw wants to merge 7 commits into
simonw wants to merge 7 commits into
Conversation
All eight modal dialogs (create table, alter table, insert/edit row, delete row, set column type, column chooser, mobile column actions and the navigation jump menu) previously each implemented their own <dialog> creation, header/footer markup, backdrop-click and Escape handling, busy-state guards, focus restoration and near-identical frame CSS. This extracts all of that into a new <datasette-modal> web component (datasette/static/datasette-modal.js) that wraps a native <dialog> and provides: - The standard modal frame, header (title + meta chip), footer and button styles, distributed via a stylesheet adopted into whichever document or shadow root the element is connected to - so it also works inside the shadow DOM of column-chooser and navigation-search - Close on backdrop click and Escape, a busy property that blocks dismissal during saves, and a closeGuard hook for discard-changes confirmation prompts - Focus restoration to the triggering element on close - datasette-modal-open and datasette-modal-close events - Per-dialog sizing via --datasette-modal-width / --datasette-modal-max-height custom properties The component is exposed as window.DatasetteModal and via a new datasetteManager.createModal() method, and is documented in docs/javascript_plugins.rst as a stable public API for plugins. This removes roughly 1,200 lines of duplicated frame markup, event wiring and CSS across table.js, edit-tools.js, mobile-column-actions.js, column-chooser.js, navigation-search.js and app.css, while keeping the existing dialog ids, class names and inner structure intact. Also adds Playwright coverage for the column chooser, mobile column actions and set-column-type dialogs, which previously had none. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2820 +/- ##
=====================================
Coverage 0.00% 0.00%
=====================================
Files 73 73
Lines 12037 12043 +6
=====================================
- Misses 12037 12043 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Owner
Author
|
Taken with shot-scraper against a local Datasette instance running the createModal() example plugin code from the Modal dialogs docs section, then palette-quantized to keep the file size down (87KB at 1520x920). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
Owner
Author
docs/generate-datasette-modal-example.sh builds a temporary demo database and plugins directory containing the createModal() example from the Modal dialogs documentation, starts a Datasette server, takes the screenshot with shot-scraper, quantizes it to an 8-bit palette PNG and stops the server again. Output is byte-identical to the committed docs/datasette-modal-example.png. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
The dialog's aria-expanded sync on the trigger button runs from the native dialog close event, which fires in a queued task after the dialog is already hidden. Use a retrying expect() assertion instead of reading the attribute immediately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
Each test boots its own Datasette subprocess and the 10 second wait_for_server timeout was too tight on loaded CI runners, causing intermittent connection-refused errors at fixture setup (seen on the webkit run). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
Clicking any element inside a <datasette-modal> that carries a
data-modal-cancel attribute now calls requestClose("cancel"), so
Cancel buttons no longer need JavaScript wiring. Like other
dismissals this respects the busy property and the closeGuard hook.
The set-column-type, row-delete and create-table dialogs now use the
attribute instead of their own click listeners, and the plugin
documentation example is simplified to match (the regenerated docs
screenshot is unchanged).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fable 5 PR
All eight modal dialogs (create table, alter table, insert/edit row,
delete row, set column type, column chooser, mobile column actions and
the navigation jump menu) previously each implemented their own
creation, header/footer markup, backdrop-click and Escape handling,
busy-state guards, focus restoration and near-identical frame CSS.
This extracts all of that into a new web component
(datasette/static/datasette-modal.js) that wraps a native and
provides:
button styles, distributed via a stylesheet adopted into whichever
document or shadow root the element is connected to - so it also
works inside the shadow DOM of column-chooser and navigation-search
dismissal during saves, and a closeGuard hook for discard-changes
confirmation prompts
--datasette-modal-max-height custom properties
The component is exposed as window.DatasetteModal and via a new
datasetteManager.createModal() method, and is documented in
docs/javascript_plugins.rst as a stable public API for plugins.
This removes roughly 1,200 lines of duplicated frame markup, event
wiring and CSS across table.js, edit-tools.js, mobile-column-actions.js,
column-chooser.js, navigation-search.js and app.css, while keeping the
existing dialog ids, class names and inner structure intact.
Also adds Playwright coverage for the column chooser, mobile column
actions and set-column-type dialogs, which previously had none.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01TShiUYVMmmF4zyJR6GMw34
Documentation: https://datasette--2820.org.readthedocs.build/en/2820/javascript_plugins.html#modal-dialogs-the-datasette-modal-element