|
2 | 2 |
|
3 | 3 | import { EllipsisHorizontalIcon } from '@heroicons/react/24/solid' |
4 | 4 | import classNames from 'classnames' |
5 | | -import React, { useRef, useState, useLayoutEffect } from 'react' |
| 5 | +import React, { useRef, useState, useLayoutEffect, ReactNode } from 'react' |
6 | 6 | import { AppliedFilterPillsList, PILL_X_GAP_PX } from './filter-pills-list' |
7 | 7 | import { useQueryContext } from '../query-context' |
8 | 8 | import { AppNavigationLink } from '../navigation/use-app-navigate' |
@@ -109,21 +109,21 @@ interface FiltersBarProps { |
109 | 109 | } |
110 | 110 | } |
111 | 111 |
|
112 | | -const canShowClearAllAction = ({ filters }: Pick<DashboardQuery, 'filters'>) => |
113 | | - filters.length >= 2 |
| 112 | +const canShowClearAllAction = ({ |
| 113 | + filters |
| 114 | +}: Pick<DashboardQuery, 'filters'>): boolean => filters.length >= 2 |
114 | 115 |
|
115 | 116 | const canShowSaveAsSegmentAction = ({ |
116 | 117 | filters, |
117 | 118 | isEditingSegment |
118 | | -}: Pick<DashboardQuery, 'filters'> & { isEditingSegment: boolean }) => |
| 119 | +}: Pick<DashboardQuery, 'filters'> & { isEditingSegment: boolean }): boolean => |
119 | 120 | filters.length >= 1 && !filters.some(isSegmentFilter) && !isEditingSegment |
120 | 121 |
|
121 | 122 | export const FiltersBar = ({ accessors }: FiltersBarProps) => { |
122 | 123 | const containerRef = useRef<HTMLDivElement>(null) |
123 | 124 | const pillsRef = useRef<HTMLDivElement>(null) |
124 | 125 | const [visibility, setVisibility] = useState<null | VisibilityState>(null) |
125 | 126 | const { query, expandedSegment } = useQueryContext() |
126 | | - const seeMoreRef = useRef<HTMLButtonElement>(null) |
127 | 127 |
|
128 | 128 | const showingClearAll = canShowClearAllAction({ filters: query.filters }) |
129 | 129 | const showingSaveAsSegment = canShowSaveAsSegmentAction({ |
@@ -203,58 +203,90 @@ export const FiltersBar = ({ accessors }: FiltersBarProps) => { |
203 | 203 | {visibility !== null && |
204 | 204 | (query.filters.length !== visibility.visibleCount || |
205 | 205 | mustShowSeeMoreMenu) && ( |
206 | | - <Popover className="md:relative"> |
207 | | - <BlurMenuButtonOnEscape targetRef={seeMoreRef} /> |
208 | | - <Popover.Button |
209 | | - title="See more" |
210 | | - ref={seeMoreRef} |
211 | | - className={classNames( |
212 | | - popover.toggleButton.classNames.rounded, |
213 | | - popover.toggleButton.classNames.shadow, |
214 | | - 'justify-center' |
215 | | - )} |
216 | | - style={{ |
217 | | - height: SEE_MORE_WIDTH_PX, |
218 | | - width: SEE_MORE_WIDTH_PX, |
219 | | - marginLeft: SEE_MORE_LEFT_MARGIN_PX, |
220 | | - marginRight: SEE_MORE_RIGHT_MARGIN_PX |
221 | | - }} |
222 | | - > |
223 | | - <EllipsisHorizontalIcon className="block h-5 w-5" /> |
224 | | - </Popover.Button> |
225 | | - <Transition |
226 | | - {...popover.transition.props} |
227 | | - className={classNames( |
228 | | - 'mt-2', |
229 | | - popover.transition.classNames.fullwidth, |
230 | | - 'md:right-auto' |
231 | | - )} |
232 | | - > |
233 | | - <Popover.Panel |
234 | | - className={classNames( |
235 | | - popover.panel.classNames.roundedSheet, |
236 | | - 'flex flex-col p-4 gap-y-2' |
237 | | - )} |
238 | | - > |
239 | | - {query.filters.length !== visibility.visibleCount && ( |
240 | | - <AppliedFilterPillsList |
241 | | - direction="vertical" |
242 | | - slice={{ |
243 | | - type: 'no-render-outside', |
244 | | - start: visibility.visibleCount |
245 | | - }} |
246 | | - /> |
247 | | - )} |
248 | | - {showingClearAll && <ClearAction />} |
249 | | - {showingSaveAsSegment && <SaveAsSegmentAction />} |
250 | | - </Popover.Panel> |
251 | | - </Transition> |
252 | | - </Popover> |
| 206 | + <SeeMoreMenu |
| 207 | + className="md:relative" |
| 208 | + filtersCount={query.filters.length} |
| 209 | + visibleFiltersCount={visibility.visibleCount} |
| 210 | + > |
| 211 | + {showingClearAll && <ClearAction />} |
| 212 | + {showingSaveAsSegment && <SaveAsSegmentAction />} |
| 213 | + </SeeMoreMenu> |
253 | 214 | )} |
254 | 215 | </div> |
255 | 216 | ) |
256 | 217 | } |
257 | 218 |
|
| 219 | +const SeeMoreMenu = ({ |
| 220 | + className, |
| 221 | + filtersCount, |
| 222 | + visibleFiltersCount, |
| 223 | + children |
| 224 | +}: { |
| 225 | + className?: string |
| 226 | + filtersCount: number |
| 227 | + visibleFiltersCount: number |
| 228 | + children: ReactNode |
| 229 | +}) => { |
| 230 | + const seeMoreRef = useRef<HTMLButtonElement>(null) |
| 231 | + const filtersInMenuCount = filtersCount - visibleFiltersCount |
| 232 | + |
| 233 | + const title = |
| 234 | + filtersInMenuCount === 1 |
| 235 | + ? 'See 1 more filter and actions' |
| 236 | + : filtersInMenuCount > 1 |
| 237 | + ? `See ${filtersInMenuCount} more filters and actions` |
| 238 | + : 'See actions' |
| 239 | + |
| 240 | + return ( |
| 241 | + <Popover className={className}> |
| 242 | + <BlurMenuButtonOnEscape targetRef={seeMoreRef} /> |
| 243 | + <Popover.Button |
| 244 | + title={title} |
| 245 | + ref={seeMoreRef} |
| 246 | + className={classNames( |
| 247 | + popover.toggleButton.classNames.rounded, |
| 248 | + popover.toggleButton.classNames.shadow, |
| 249 | + 'justify-center' |
| 250 | + )} |
| 251 | + style={{ |
| 252 | + height: SEE_MORE_WIDTH_PX, |
| 253 | + width: SEE_MORE_WIDTH_PX, |
| 254 | + marginLeft: SEE_MORE_LEFT_MARGIN_PX, |
| 255 | + marginRight: SEE_MORE_RIGHT_MARGIN_PX |
| 256 | + }} |
| 257 | + > |
| 258 | + <EllipsisHorizontalIcon className="block h-5 w-5" /> |
| 259 | + </Popover.Button> |
| 260 | + <Transition |
| 261 | + {...popover.transition.props} |
| 262 | + className={classNames( |
| 263 | + 'mt-2', |
| 264 | + popover.transition.classNames.fullwidth, |
| 265 | + 'md:right-auto' |
| 266 | + )} |
| 267 | + > |
| 268 | + <Popover.Panel |
| 269 | + className={classNames( |
| 270 | + popover.panel.classNames.roundedSheet, |
| 271 | + 'flex flex-col p-4 gap-y-2' |
| 272 | + )} |
| 273 | + > |
| 274 | + {filtersCount !== visibleFiltersCount && ( |
| 275 | + <AppliedFilterPillsList |
| 276 | + direction="vertical" |
| 277 | + slice={{ |
| 278 | + type: 'no-render-outside', |
| 279 | + start: visibleFiltersCount |
| 280 | + }} |
| 281 | + /> |
| 282 | + )} |
| 283 | + {children} |
| 284 | + </Popover.Panel> |
| 285 | + </Transition> |
| 286 | + </Popover> |
| 287 | + ) |
| 288 | +} |
| 289 | + |
258 | 290 | const ClearAction = () => ( |
259 | 291 | <AppNavigationLink |
260 | 292 | className={classNames( |
|
0 commit comments