stacks/analyticshq
fix(dashboard): close the date picker on a click outside it
#56
Merged
glennmichael123
wants to merge
fix/date-picker-dismiss
into
main
3 files
+25
-0
resources/components/DateRangePicker.stxmodified+11-0Changes to resources/components/DateRangePicker.stx | @@ -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> |
resources/views/dashboard.stxmodified+1-0Changes to resources/views/dashboard.stx | @@ -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 { |
tests/unit/date-range-picker.test.tsmodified+13-0Changes to tests/unit/date-range-picker.test.ts | @@ -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 | + |
| 118 | + |
| 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 | + |
| 122 | + |
| 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 | |
| 118 | 131 | |