← Commit history

0.28.2: a click on a mounted select no longer opens the native popup under our list

Drew Owens ·73812a2fe4 · ·parent 281790f
4 files changed +65−3
docs/BUILD-NOTES.md+44
@@ -3,6 +3,50 @@ Decisions taken while building, and the places where the plan and the code disagreed. Newest first. +## Build notes, 2026-08-14 (0.28.2, one dropdown, not two)++A screenshot showed a phase cell with TWO differently-styled option lists stacked+on each other: ours, and the browser's own select popup underneath it.++**0.22.2 closed one door and left the other open.** That round replaced the native+popup with a custom list because the native one is browser UI: while it is open+the page gets no key events, so the first Tab was spent closing it. It removed the+`showPicker()` call. It did not stop the plain gesture: the select is still a real+`<select>`, and clicking an already-focused one opens the native popup on its own,+with no script involved. Mount the editor (our list opens), click the cell again,+and there are two.++**`preventDefault` on the select's mousedown is the whole fix.** That is what+suppresses a native select popup, and it is deliberately bound to mousedown ONLY:+the keyboard is untouched, so arrows, type-ahead and Enter are still the real+select's behaviour, which is the reason a real `<select>` is still the control+underneath rather than a div pretending to be one.++**The click is routed, not killed. The custom list IS the list, so a click toggles+it**, which is what clicking a dropdown has always meant: open when closed, closed+when open. A dead gesture would have been the cheaper fix and the worse one.+`preventDefault` also suppresses the focus mousedown would have granted, so focus+is restored by hand; the select is already focused from the mount, so that is a+no-op in the normal case and a repair in any case where it is not.++**One fix covers both selects.** Phase and status are built by the same branch and+go through the same `openCellList` path. The owner cell does NOT: it is a text+input with a `datalist`, which is a suggestion list rather than a fixed set, it has+no custom list of ours, and so it has nothing to stack with. Asserted rather than+assumed.++**On measuring a thing that is not in the DOM.** A native select popup is browser+chrome; headless Chrome cannot render it into `--dump-dom`, so counting `.cell-list`+nodes can never see it. The honest measurement is `defaultPrevented` on a real+dispatched mousedown, because that flag IS the suppression mechanism. It reads+**false on 0.28.1 and true on 0.28.2**, run against both builds on the same plan.+Alongside it: at most one custom list at any point, the toggle closing to 0 and+reopening to 1, the select still focused, the editor still open, Escape still+closing everything, a pick by CLICK committing (status to blocked) and a pick by+KEYBOARD committing (Workcells to Logistics), and Tab still walking exactly one+column per press (name, phase, owner, deadline). Keyboard, column, dependency, uid,+milestone-selection and New-panel-memory suites all unchanged.+ ## Build notes, 2026-08-14 (0.28.1, the New panel remembers everything but the name)  0.18.1 carried the owner and the two dates from the last successful create. The
gantt.html+18
@@ -4791,6 +4791,24 @@ function startCellEdit(td){     // leaving it costs one Tab like every other field.     openCellList(el,td);     el.addEventListener('change',syncCellList);+    // ...and the browser's popup must never open ON TOP of it. 0.22.2 removed the+    // showPicker path but left the plain one: clicking the already-focused select+    // still opened the native popup, so a second click on a phase cell produced+    // TWO differently-styled lists stacked on each other. preventDefault on+    // mousedown is what suppresses a native select popup, and it is deliberately+    // only on mousedown: the keyboard is untouched, so arrows, type-ahead and+    // Enter are still the real select's behaviour.+    //+    // The gesture is not dead, it is routed. The custom list IS the list, so a+    // click TOGGLES it, which is what clicking a dropdown has always meant.+    el.addEventListener('mousedown',e=>{+      e.preventDefault();+      if(cellList&&cellList.sel===el)closeCellList(); else openCellList(el,td);+      // preventDefault also suppresses the focus mousedown would have given. The+      // select is already focused from the mount, so this is a no-op in the normal+      // case and a repair in any case where it is not.+      try{ el.focus({preventScroll:true}); }catch(_){ try{ el.focus(); }catch(__){} }+    });   } else if(el.hasAttribute('list')){     // The owner datalist is a suggestion list, not a fixed set of choices, and its     // popup does not intercept Tab the way a select popup does, so it keeps the
package.json+1−1
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.28.1",+  "version": "0.28.2",   "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {
page.json+2−2
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.28.1",+  "version": "0.28.2",   "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {@@ -63,4 +63,4 @@     "name": "Drew Owens",     "email": "[email protected]"   }-}\ No newline at end of file+}