diff --git a/package.json b/package.json index dc797331..3977542b 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "@react-spring/web": "^10.0.3", "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.90.5", - "@umami/react-zen": "^0.200.0", + "@umami/react-zen": "^0.203.0", "@umami/redis-client": "^0.29.0", "bcryptjs": "^3.0.2", "chalk": "^5.6.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 493437aa..ad7d5d4e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,8 +45,8 @@ importers: specifier: ^5.90.5 version: 5.90.5(react@19.2.0) '@umami/react-zen': - specifier: ^0.200.0 - version: 0.200.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0)) + specifier: ^0.203.0 + version: 0.203.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0)) '@umami/redis-client': specifier: ^0.29.0 version: 0.29.0 @@ -2921,8 +2921,8 @@ packages: resolution: {integrity: sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@umami/react-zen@0.200.0': - resolution: {integrity: sha512-En5H5XpssItNPPSxb+xwGyMUalmqeoWCzMInGi/MJau/kkcJ2V0mSrgZ8RVRryl8cBg8fpktK7JaCTNULweUFA==} + '@umami/react-zen@0.203.0': + resolution: {integrity: sha512-lgGUapA0zDbLu63GINaEPndIsT8ry85vE316AWU/EEH3qYDBNscetcBfZFr+DTD/c5eLKy9OxmMwIpbs7k+/UA==} '@umami/redis-client@0.29.0': resolution: {integrity: sha512-Jaqh++jskqDB7ny75pfC02OvKp1JTS4asGDsFrRL3qy8sxL3PAl9+/mybCJe4/6vWrXDJKqpgkSfUDJq2bFjyw==} @@ -10670,7 +10670,7 @@ snapshots: '@typescript-eslint/types': 8.46.1 eslint-visitor-keys: 4.2.1 - '@umami/react-zen@0.200.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0))': + '@umami/react-zen@0.203.0(@babel/core@7.28.3)(@types/react@19.2.2)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.3)(use-sync-external-store@1.6.0(react@19.2.0))': dependencies: '@fontsource/jetbrains-mono': 5.2.8 '@internationalized/date': 3.10.0 diff --git a/src/app/(main)/MobileNav.tsx b/src/app/(main)/MobileNav.tsx index 2c9b50c0..d9ddad89 100644 --- a/src/app/(main)/MobileNav.tsx +++ b/src/app/(main)/MobileNav.tsx @@ -33,7 +33,7 @@ export function MobileNav() { ]; return ( - + {({ close }) => { return ( diff --git a/src/app/(main)/websites/[websiteId]/ExpandedViewModal.tsx b/src/app/(main)/websites/[websiteId]/ExpandedViewModal.tsx index 08503334..ec4c2aaf 100644 --- a/src/app/(main)/websites/[websiteId]/ExpandedViewModal.tsx +++ b/src/app/(main)/websites/[websiteId]/ExpandedViewModal.tsx @@ -1,6 +1,6 @@ -import { Dialog, Modal, useBreakpoint } from '@umami/react-zen'; +import { Dialog, Modal } from '@umami/react-zen'; import { WebsiteExpandedView } from '@/app/(main)/websites/[websiteId]/WebsiteExpandedView'; -import { useNavigation } from '@/components/hooks'; +import { useNavigation, useMobile } from '@/components/hooks'; export function ExpandedViewModal({ websiteId, @@ -14,8 +14,7 @@ export function ExpandedViewModal({ query: { view }, updateParams, } = useNavigation(); - const breakpoint = useBreakpoint(); - const isMobile = ['xs', 'sm', 'md'].includes(breakpoint); + const { isMobile } = useMobile(); const handleClose = (close: () => void) => { router.push(updateParams({ view: undefined })); diff --git a/src/components/common/DataGrid.tsx b/src/components/common/DataGrid.tsx index 5359eb28..4d09135f 100644 --- a/src/components/common/DataGrid.tsx +++ b/src/components/common/DataGrid.tsx @@ -6,9 +6,9 @@ import { cloneElement, isValidElement, } from 'react'; -import { SearchField, Row, Column, useBreakpoint } from '@umami/react-zen'; +import { SearchField, Row, Column } from '@umami/react-zen'; import { UseQueryResult } from '@tanstack/react-query'; -import { useMessages, useNavigation } from '@/components/hooks'; +import { useMessages, useMobile, useNavigation } from '@/components/hooks'; import { Pager } from '@/components/common/Pager'; import { LoadingPanel } from '@/components/common/LoadingPanel'; import { PageResult } from '@/lib/types'; @@ -42,8 +42,8 @@ export function DataGrid({ const { router, updateParams, query: queryParams } = useNavigation(); const [search, setSearch] = useState(queryParams?.search || data?.search || ''); const showPager = allowPaging && data && data.count > data.pageSize; - const breakpoint = useBreakpoint(); - const displayMode = ['xs', 'sm', 'md', 'lg'].includes(breakpoint) ? 'cards' : undefined; + const { isMobile } = useMobile(); + const displayMode = isMobile ? 'cards' : undefined; const handleSearch = (value: string) => { if (value !== search) { diff --git a/src/components/input/DateFilter.tsx b/src/components/input/DateFilter.tsx index 4b9c7f7d..f72ea281 100644 --- a/src/components/input/DateFilter.tsx +++ b/src/components/input/DateFilter.tsx @@ -1,16 +1,8 @@ import { useState, Key, Fragment } from 'react'; -import { - Modal, - Select, - ListItem, - ListSeparator, - Dialog, - SelectProps, - useBreakpoint, -} from '@umami/react-zen'; +import { Modal, Select, ListItem, ListSeparator, Dialog, SelectProps } from '@umami/react-zen'; import { endOfYear } from 'date-fns'; import { DatePickerForm } from '@/components/metrics/DatePickerForm'; -import { useMessages } from '@/components/hooks'; +import { useMessages, useMobile } from '@/components/hooks'; import { DateDisplay } from '@/components/common/DateDisplay'; import { parseDateRange } from '@/lib/date'; @@ -33,8 +25,7 @@ export function DateFilter({ const { formatMessage, labels } = useMessages(); const [showPicker, setShowPicker] = useState(false); const { startDate, endDate } = parseDateRange(value) || {}; - const breakpoint = useBreakpoint(); - const isMobile = ['xs', 'sm', 'md'].includes(breakpoint); + const { isMobile } = useMobile(); const options = [ { label: formatMessage(labels.today), value: '0day' }, @@ -119,7 +110,8 @@ export function DateFilter({ placeholder={formatMessage(labels.selectDate)} onChange={handleChange} renderValue={renderValue} - popoverProps={{ placement, isNonModal: isMobile }} + popoverProps={{ placement }} + isFullscreen={isMobile} > {options.map(({ label, value, divider }: any) => { return ( diff --git a/src/components/input/DialogButton.tsx b/src/components/input/DialogButton.tsx index bb831eef..f7184da6 100644 --- a/src/components/input/DialogButton.tsx +++ b/src/components/input/DialogButton.tsx @@ -25,7 +25,7 @@ export function DialogButton({ icon, label, title, - width = '800px', + width, height, minWidth, minHeight, diff --git a/src/components/input/FilterEditForm.tsx b/src/components/input/FilterEditForm.tsx index 7bc7915e..c69c69e5 100644 --- a/src/components/input/FilterEditForm.tsx +++ b/src/components/input/FilterEditForm.tsx @@ -1,7 +1,7 @@ -import { useFilters, useMessages, useNavigation } from '@/components/hooks'; +import { useFilters, useMessages, useMobile, useNavigation } from '@/components/hooks'; import { FieldFilters } from '@/components/input/FieldFilters'; import { SegmentFilters } from '@/components/input/SegmentFilters'; -import { Button, Column, Row, Tab, TabList, TabPanel, Tabs, useBreakpoint } from '@umami/react-zen'; +import { Button, Column, Row, Tab, TabList, TabPanel, Tabs } from '@umami/react-zen'; import { useState } from 'react'; export interface FilterEditFormProps { @@ -20,8 +20,7 @@ export function FilterEditForm({ websiteId, onChange, onClose }: FilterEditFormP const [currentFilters, setCurrentFilters] = useState(filters); const [currentSegment, setCurrentSegment] = useState(segment); const [currentCohort, setCurrentCohort] = useState(cohort); - const breakpoint = useBreakpoint(); - const isMobile = ['xs', 'sm', 'md'].includes(breakpoint); + const { isMobile } = useMobile(); const excludeFilters = pathname.includes('/pixels') || pathname.includes('/links'); const handleReset = () => { diff --git a/src/components/input/NavButton.tsx b/src/components/input/NavButton.tsx index e0f7508a..e1f7129d 100644 --- a/src/components/input/NavButton.tsx +++ b/src/components/input/NavButton.tsx @@ -12,9 +12,14 @@ import { Column, Pressable, IconLabel, - useBreakpoint, } from '@umami/react-zen'; -import { useConfig, useLoginQuery, useMessages, useNavigation } from '@/components/hooks'; +import { + useConfig, + useLoginQuery, + useMessages, + useMobile, + useNavigation, +} from '@/components/hooks'; import { BookText, ChevronRight, @@ -40,11 +45,10 @@ export function NavButton({ showText = true }: TeamsButtonProps) { const { cloudMode } = useConfig(); const { formatMessage, labels } = useMessages(); const { teamId } = useNavigation(); - const breakpoint = useBreakpoint(); + const { isMobile } = useMobile(); const team = user?.teams?.find(({ id }) => id === teamId); const selectedKeys = new Set([teamId || 'user']); const label = teamId ? team?.name : user.username; - const isMobile = ['xs', 'sm', 'md'].includes(breakpoint); const getUrl = (url: string) => { return cloudMode ? `${process.env.cloudUrl}${url}` : url; diff --git a/src/components/input/WebsiteFilterButton.tsx b/src/components/input/WebsiteFilterButton.tsx index 040ad954..25f81af4 100644 --- a/src/components/input/WebsiteFilterButton.tsx +++ b/src/components/input/WebsiteFilterButton.tsx @@ -1,22 +1,18 @@ -import { Button, Icon, DialogTrigger, Dialog, Text, Modal, useBreakpoint } from '@umami/react-zen'; import { ListFilter } from '@/components/icons'; import { FilterEditForm } from '@/components/input/FilterEditForm'; +import { DialogButton } from '@/components/input/DialogButton'; import { useMessages, useNavigation } from '@/components/hooks'; import { filtersArrayToObject } from '@/lib/params'; export function WebsiteFilterButton({ websiteId, - showText = true, }: { websiteId: string; position?: 'bottom' | 'top' | 'left' | 'right'; alignment?: 'end' | 'center' | 'start'; - showText?: boolean; }) { const { formatMessage, labels } = useMessages(); const { updateParams, router } = useNavigation(); - const breakpoint = useBreakpoint(); - const isMobile = ['xs', 'sm', 'md'].includes(breakpoint); const handleChange = ({ filters, segment, cohort }: any) => { const params = filtersArrayToObject(filters); @@ -27,20 +23,10 @@ export function WebsiteFilterButton({ }; return ( - - - - - {({ close }) => { - return ; - }} - - - + } label={formatMessage(labels.filter)} variant="outline"> + {({ close }) => { + return ; + }} + ); } diff --git a/src/components/metrics/DatePickerForm.tsx b/src/components/metrics/DatePickerForm.tsx index f1060316..8094e30a 100644 --- a/src/components/metrics/DatePickerForm.tsx +++ b/src/components/metrics/DatePickerForm.tsx @@ -47,7 +47,7 @@ export function DatePickerForm({ )} {selected.includes(FILTER_RANGE) && ( - +