also looking at this
fix(dashboard): close the date picker on a click outside it
#56
3 files
+25
-0
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -181,6 +181,16 @@ function pickLeftMonth(e) { pickSetYm(pickYearOf(calYm()), Number(e.target.value | ||
| 181 | 181 | function pickLeftYear(e) { pickSetYm(Number(e.target.value), pickMonthIdx(calYm()), false) } |
| 182 | 182 | function pickRightMonth(e) { pickSetYm(pickYearOf(pickRightYm()), Number(e.target.value), true) } |
| 183 | 183 | function pickRightYear(e) { pickSetYm(Number(e.target.value), pickMonthIdx(pickRightYm()), true) } |
| 184 | // A native <details> only closes from its own summary, so an open panel would | |
| 185 | // otherwise sit there after the pointer moves on. The transparent .drp-backdrop | |
| 186 | // below covers the rest of the page while the panel is open; a click on it lands | |
| 187 | // here and closes the panel, the same way clicking away from a menu should. | |
| 188 | function pickClose(e) { | |
| 189 | const d = e.currentTarget.closest('details') | |
| 190 | if (d) d.removeAttribute('open') | |
| 191 | selStart.set('') | |
| 192 | selHover.set('') | |
| 193 | } | |
| 184 | 194 | function pickEscape(e) { |
| 185 | 195 | if (e.key !== 'Escape') return |
| 186 | 196 | selStart.set('') |
| @@ -194,6 +204,7 @@ function pickEscape(e) { | ||
| 194 | 204 | <i class="i-hugeicons-calendar-03" aria-hidden="true"></i> |
| 195 | 205 | <span>{{ summary }}</span> |
| 196 | 206 | </summary> |
| 207 | <div class="drp-backdrop" @click="pickClose" aria-hidden="true"></div> | |
| 197 | 208 | <div class="date-popover drp" role="dialog" aria-label="Reporting period"> |
| 198 | 209 | <div class="drp-presets" role="list"> |
| 199 | 210 | <button type="button" role="listitem" :class="pickPresetClass('today')" @click="pickApply('today')">Today</button> |
| @@ -2188,6 +2188,7 @@ summary:focus-visible { | ||
| 2188 | 2188 | /* Period picker: presets down the left, two months on the right. The range is |
| 2189 | 2189 | drawn flat with rounded ends, the way Fathom's is, on the --bar wash the KPI |
| 2190 | 2190 | bars already use so it reads as the same accent at the same strength. */ |
| 2191 | .drp-backdrop { position: fixed; inset: 0; z-index: 39; background: transparent; cursor: default; } | |
| 2191 | 2192 | .drp { display: grid; grid-template-columns: 10.5rem minmax(0, 1fr); gap: 0.75rem; } |
| 2192 | 2193 | .drp-presets { display: flex; flex-direction: column; gap: 0.15rem; padding-right: 0.75rem; border-right: 1px solid var(--border); } |
| 2193 | 2194 | .drp-preset { |
| @@ -113,6 +113,19 @@ describe('date range picker: wiring', () => { | ||
| 113 | 113 | expect(dashboard).not.toContain('type="date"') |
| 114 | 114 | }) |
| 115 | 115 | |
| 116 | test('an open panel is dismissed by a click outside it', () => { | |
| 117 | // A native <details> has no outside-click close, so the component adds a | |
| 118 | // transparent full-viewport backdrop behind the panel that closes it. | |
| 119 | expect(component).toContain('<div class="drp-backdrop" @click="pickClose"') | |
| 120 | expect(component).toMatch(/function pickClose\(e\) \{[\s\S]*?closest\('details'\)[\s\S]*?removeAttribute\('open'\)/) | |
| 121 | // It sits below the panel and above the sticky nav so a click on the panel | |
| 122 | // itself never reaches it, but a click on the page behind does. | |
| 123 | const backdrop = dashboard.match(/\.drp-backdrop\s*\{[^}]*\}/)?.[0] ?? '' | |
| 124 | expect(backdrop).toContain('position: fixed') | |
| 125 | expect(backdrop).toContain('inset: 0') | |
| 126 | expect(backdrop).toMatch(/z-index:\s*39\b/) | |
| 127 | }) | |
| 128 | ||
| 116 | 129 | test('at phone width the panel shows one calendar inside the visible viewport', () => { |
| 117 | 130 | // Anchored on the rule that already switches the menu to phone layout, so the |
| 118 | 131 | // test does not depend on the block's breakpoint value. |