diff --git a/package-lock.json b/package-lock.json
index acffd35..7d01146 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -38,7 +38,7 @@
"@jcesarmobile/capacitor-ocr": "^0.3.0",
"@meauxt/react-swipeable-list": "^1.0.0",
"@mui/icons-material": "^5.16.13",
- "@mui/joy": "^5.0.0-beta.20",
+ "@mui/joy": "5.0.0-beta.52",
"@mui/material": "^5.15.2",
"@openreplay/tracker": "^14.0.4",
"@revenuecat/purchases-capacitor": "^12.0.0",
diff --git a/package.json b/package.json
index 714c5e9..1f6146c 100644
--- a/package.json
+++ b/package.json
@@ -70,7 +70,7 @@
"@jcesarmobile/capacitor-ocr": "^0.3.0",
"@meauxt/react-swipeable-list": "^1.0.0",
"@mui/icons-material": "^5.16.13",
- "@mui/joy": "^5.0.0-beta.20",
+ "@mui/joy": "5.0.0-beta.52",
"@mui/material": "^5.15.2",
"@openreplay/tracker": "^14.0.4",
"@revenuecat/purchases-capacitor": "^12.0.0",
diff --git a/src/components/common/AppModal.jsx b/src/components/common/AppModal.jsx
index 55fefc6..72c84a7 100644
--- a/src/components/common/AppModal.jsx
+++ b/src/components/common/AppModal.jsx
@@ -2,7 +2,6 @@ import { Close } from '@mui/icons-material'
import { Box, Divider, IconButton, Modal, Sheet, Typography } from '@mui/joy'
import useMediaQuery from '@mui/material/useMediaQuery'
import { forwardRef, useId } from 'react'
-import { Z_INDEX } from '../../constants/zIndex'
const WIDTH_BY_SIZE = {
sm: 400,
@@ -27,6 +26,7 @@ const AppModal = forwardRef(
size = 'md',
fullWidth = true,
isMobile: isMobileProp,
+ keepMounted = false,
mobilePresentation = 'sheet',
role = 'dialog',
showCloseButton = true,
@@ -63,9 +63,16 @@ const AppModal = forwardRef(
onClose={handleClose}
aria-labelledby={titleId}
aria-describedby={descriptionId}
- keepMounted
+ keepMounted={keepMounted}
sx={{
- zIndex: Z_INDEX.MODAL_BACKDROP,
+ // Joy raises portaled listboxes above modals, but its selector misses
+ // Menu because Menu renders with role="menu". Keep the workaround in
+ // the modal primitive so individual menus never need a z-index.
+ ...(open && {
+ '& ~ [role="menu"]': {
+ '--unstable_popup-zIndex': 'calc(var(--joy-zIndex-modal) + 1)',
+ },
+ }),
display: 'flex',
alignItems: isSheet ? 'flex-end' : 'center',
justifyContent: 'center',
@@ -85,7 +92,6 @@ const AppModal = forwardRef(
aria-describedby={descriptionId}
variant='outlined'
sx={{
- zIndex: Z_INDEX.MODAL_CONTENT,
display: 'flex',
flexDirection: 'column',
width: isFullscreen
diff --git a/src/constants/zIndex.js b/src/constants/zIndex.js
deleted file mode 100644
index 59ab5e1..0000000
--- a/src/constants/zIndex.js
+++ /dev/null
@@ -1,38 +0,0 @@
-// Z-index constants for consistent layering
-// Lower values appear behind higher values
-
-export const Z_INDEX = {
- // Base layer (0-99)
- BASE: 0,
- CARD_OVERLAY: 1,
- DROPDOWN_ITEM: 2,
- TOOLTIP: 3,
-
- // UI Components (100-999)
- SAFE_AREA: 100,
- CALENDAR: 110,
- SMART_INPUT: 110,
- AUTOCOMPLETE: 200,
-
- // Navigation (1000-1999)
- NAVBAR: 1000,
- DRAWER: 999,
-
- // Modals and Overlays (2000-8999)
- MODAL_BACKDROP: 2000,
- MODAL_CONTENT: 2001,
- MODAL_CLOSE_BUTTON: 2002,
- // Popups that must float above open modals (portaled to document.body)
- MODAL_POPOVER: 2100,
- TOAST: 3000,
-
- // Critical System UI (9000-9999)
- LOADING_SCREEN: 9000,
- ALERTS: 9500,
- NETWORK_BANNER: 9600,
-
- // Maximum (10000+) - Reserved for absolute emergencies
- EMERGENCY: 10000,
-}
-
-export default Z_INDEX
diff --git a/src/service/AlertsProvider.jsx b/src/service/AlertsProvider.jsx
index 470c36a..62c2afd 100644
--- a/src/service/AlertsProvider.jsx
+++ b/src/service/AlertsProvider.jsx
@@ -1,7 +1,6 @@
import { Alert, Box } from '@mui/joy'
import PropTypes from 'prop-types'
import { createContext, useCallback, useContext, useState } from 'react'
-import Z_INDEX from '../constants/zIndex'
const FADE_DURATION = 400 // ms
const ALERT_DURATION = 5000 // ms
@@ -48,7 +47,7 @@ export const AlertsProvider = ({ children }) => {
top: 0,
left: 0,
width: '100%',
- zIndex: Z_INDEX.ALERTS,
+ zIndex: 'var(--joy-zIndex-snackbar)',
overflow: 'hidden',
}}
>
diff --git a/src/views/Chores/components/ChoreToolbarPrototype.jsx b/src/views/Chores/components/ChoreToolbarPrototype.jsx
index 29960b4..cd4e28d 100644
--- a/src/views/Chores/components/ChoreToolbarPrototype.jsx
+++ b/src/views/Chores/components/ChoreToolbarPrototype.jsx
@@ -38,16 +38,17 @@ import {
ButtonGroup,
Chip,
Divider,
+ Dropdown,
IconButton,
Input,
Menu,
+ MenuButton,
MenuItem,
Typography,
} from '@mui/joy'
-import { useEffect, useRef, useState } from 'react'
+import { useEffect, useState } from 'react'
import AppModal from '../../../components/common/AppModal'
import ActiveFilterChips from '../../../components/common/filter/ActiveFilterChips'
-import { Z_INDEX } from '../../../constants/zIndex'
import KeyboardShortcutHint from '../../../components/common/KeyboardShortcutHint'
import { FILTER_COLORS } from '../../../utils/Colors'
import Priorities from '../../../utils/Priorities'
@@ -229,9 +230,8 @@ const ChoreToolbar = ({
const [localSelections, setLocalSelections] = useState(defaultSelections())
const [savingFilter, setSavingFilter] = useState(false)
const [saveFilterName, setSaveFilterName] = useState('')
- const [saveMenuAnchorEl, setSaveMenuAnchorEl] = useState(null)
+ const [saveMenuOpen, setSaveMenuOpen] = useState(false)
const [editingSavedFilter, setEditingSavedFilter] = useState(null)
- const saveMenuRef = useRef(null)
const activeConditions = selectionsToConditions(localSelections)
// ── badge counts ─────────────────────────────────────────────────────────────
@@ -419,13 +419,13 @@ const ChoreToolbar = ({
}
setSavingFilter(false)
setSaveFilterName('')
- setSaveMenuAnchorEl(null)
+ setSaveMenuOpen(false)
setFilterSheetOpen(true)
}
useEffect(() => {
if (!filterSheetOpen || savingFilter || activeConditions.length === 0) {
- setSaveMenuAnchorEl(null)
+ setSaveMenuOpen(false)
}
}, [filterSheetOpen, savingFilter, activeConditions.length])
@@ -504,7 +504,7 @@ const ChoreToolbar = ({
onFilterSaved?.(editingSavedFilter.name)
})
- setSaveMenuAnchorEl(null)
+ setSaveMenuOpen(false)
setFilterSheetOpen(false)
}
@@ -681,7 +681,7 @@ const ChoreToolbar = ({
open={filterSheetOpen}
isMobile
onClose={() => {
- setSaveMenuAnchorEl(null)
+ setSaveMenuOpen(false)
setFilterSheetOpen(false)
}}
maxHeight='92vh'
@@ -747,7 +747,7 @@ const ChoreToolbar = ({
disabled={!hasAnyActive && activeConditions.length === 0}
onClick={() => {
setLocalSelections(defaultSelections())
- setSaveMenuAnchorEl(null)
+ setSaveMenuOpen(false)
onClearAllFilters?.()
setFilterSheetOpen(false)
}}
@@ -756,33 +756,29 @@ const ChoreToolbar = ({
{activeConditions.length > 0 ? (
- <>
+ setSaveMenuOpen(isOpen)}
+ >
- setSaveMenuAnchorEl(e.currentTarget)}
>
-
+
-
) : (