ReviewOS

also looking at this

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

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.

resources/components/DateRangePicker.stxmodified+11-0
Changes to resources/components/DateRangePicker.stx
@@ -181,6 +181,16 @@ function pickLeftMonth(e) { pickSetYm(pickYearOf(calYm()), Number(e.target.value
181181function pickLeftYear(e) { pickSetYm(Number(e.target.value), pickMonthIdx(calYm()), false) }
182182function pickRightMonth(e) { pickSetYm(pickYearOf(pickRightYm()), Number(e.target.value), true) }
183183function 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.
188function pickClose(e) {
189 const d = e.currentTarget.closest('details')
190 if (d) d.removeAttribute('open')
191 selStart.set('')
192 selHover.set('')
193}
184194function pickEscape(e) {
185195 if (e.key !== 'Escape') return
186196 selStart.set('')
@@ -194,6 +204,7 @@ function pickEscape(e) {
194204 <i class="i-hugeicons-calendar-03" aria-hidden="true"></i>
195205 <span>{{ summary }}</span>
196206 </summary>
207 <div class="drp-backdrop" @click="pickClose" aria-hidden="true"></div>
197208 <div class="date-popover drp" role="dialog" aria-label="Reporting period">
198209 <div class="drp-presets" role="list">
199210 <button type="button" role="listitem" :class="pickPresetClass('today')" @click="pickApply('today')">Today</button>
resources/views/dashboard.stxmodified+1-0
Changes to resources/views/dashboard.stx
@@ -2188,6 +2188,7 @@ summary:focus-visible {
21882188/* Period picker: presets down the left, two months on the right. The range is
21892189 drawn flat with rounded ends, the way Fathom's is, on the --bar wash the KPI
21902190 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; }
21912192.drp { display: grid; grid-template-columns: 10.5rem minmax(0, 1fr); gap: 0.75rem; }
21922193.drp-presets { display: flex; flex-direction: column; gap: 0.15rem; padding-right: 0.75rem; border-right: 1px solid var(--border); }
21932194.drp-preset {
tests/unit/date-range-picker.test.tsmodified+13-0
Changes to tests/unit/date-range-picker.test.ts
@@ -113,6 +113,19 @@ describe('date range picker: wiring', () => {
113113 expect(dashboard).not.toContain('type="date"')
114114 })
115115
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
116129 test('at phone width the panel shows one calendar inside the visible viewport', () => {
117130 // Anchored on the rule that already switches the menu to phone layout, so the
118131 // test does not depend on the block's breakpoint value.