← Commit history

settings-layout: the four mandatory modal mechanics (Escape, X, click-outside with the backdrop-hit-test, dim) + the Settings-never-Preferences naming rule

John Lauer ·46e4fd85ce ·2mo ago ·parent 46b17cf
3 files changed +39−2
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-ui-design",-  "version": "1.6.1",+  "version": "1.6.2",   "type": "skill",   "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths, dark-default, input-feedback, settings-layout). One install drops the whole set of skill files onto your container.",   "dependencies": {},
page.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-ui-design",-  "version": "1.6.1",+  "version": "1.6.2",   "type": "skill",   "description": "The Adom UI Design System plus a bundle of focused UI skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths, dark-default, input-feedback, settings-layout). One install drops the whole set of skill files onto your container.",   "dependencies": {},
skills/settings-layout/SKILL.md+37
@@ -121,6 +121,43 @@ fusion Dashboard). Give the dialog `tabindex="-1"`, focus the dialog itself on o `scrollTop = 0` (again inside a `requestAnimationFrame`, since the autofocus scroll lands after your first assignment). +## The name is SETTINGS (never Preferences)++Adom standardized on **Settings** (John, 2026-08-18). Never label a surface, button, tooltip,+menu item, or toast "Preferences", "Options", or "Config" - not even in prose. The only+acceptable appearance of another word is when you are naming a THIRD-PARTY app's own dialog+(e.g. "enabled in Fusion's preferences", because that is what Autodesk calls their screen).+Title the surface "<App> Settings".++## Modal mechanics: the four behaviors EVERY Adom settings box must have++Consistency here matters more than cleverness - a user who learns one Adom settings box has+learned them all. All four, every time, no exceptions:++1. **Escape closes.** A native `<dialog>` + `showModal()` gives you this free; a hand-rolled+   overlay must implement it.+2. **An X in the upper right closes.** Icon button, `aria-label="Close settings"`, in the+   header row opposite the title, with the standard hover/press feedback.+3. **Clicking OUTSIDE closes.** With a native `<dialog>` the backdrop is part of the dialog+   element, so a naive `click` handler on the dialog also fires for clicks on the dialog's own+   padding. Gate it on the pointer being outside the dialog's box:+   ```js+   dlg.addEventListener('click', e => {+     if (e.target !== dlg) return;                       // a child was clicked+     const r = dlg.getBoundingClientRect();+     const inside = e.clientX >= r.left && e.clientX <= r.right &&+                    e.clientY >= r.top  && e.clientY <= r.bottom;+     if (!inside) dlg.close();+   });+   ```+4. **The rest of the app dims.** `dialog::backdrop { background: rgba(0,0,0,.55) }` (or an+   equivalent overlay for a hand-rolled modal). The dim is what says "this is modal"; without+   it the dialog reads as a floating card and users click straight through it.++A "Close" button in the footer is fine as a fifth affordance, but it never replaces the X.+Ralph-test all four for real - drive Escape, click the X, click outside, and read the computed+backdrop color - because each one fails silently and independently.+ ## Copy rules  - Full sentences, present tense, second person where natural. No em-dashes ever (Adom rule).