Skip to content

UI Providers

Singleton context providers that power shared UI systems — context menus, galleries, popovers, and navigation state. Most are already mounted in ClientProviders; only PopoverProvider, MenuProvider, PredictionContextMenuProvider, and PredictionDropdownProvider require local placement.


Provider Map

Provider Global? Hook Purpose
ActionMenuProvider yes useActionMenu() Programmatic context menu rendered as a portal
MediaResourceGalleryProvider yes useMediaResourceGallery() Lightbox gallery for MediaResourceRenderer
FloatingWindowProvider yes useFloatingWindow() Draggable/resizable floating panels
ModalProvider yes useModal(), useInlineModal() Modal stack
PopoverProvider no usePopoverProvider() Single-active-popover within a subtree
MenuProvider no useMenu() Sidebar collapsed/expanded state
PredictionContextMenuProvider no usePredictionContextMenu() Context menu for generation prediction cards
PredictionDropdownProvider no usePredictionDropdown() Dropdown for generation prediction cards

"Global" means mounted once in ClientProviders — no per-page setup needed.


ActionMenuProvider + useActionMenu()

Global singleton. Renders the menu as a createPortal to document.body.

import { useActionMenu } from "@/providers/ActionMenuProvider";

const menu = useActionMenu();
menu.open(event, { actions, context: myEntity });
menu.close();
menu.isOpen; // boolean
  • open(position, options) — position can be a MouseEvent, KeyboardEvent, or { x, y } coordinates
  • Menu auto-repositions to stay within the viewport (estimates 200×300 px)
  • context in OpenMenuOptions maps to ctx.data inside action handlers
  • Auto-closes on outside left-click, scroll (outside the menu), resize, and Escape
  • Async onSelect shows a per-item loading spinner; errors surface as a toast
  • confirm on a StandardAction shows an AlertDialog before executing

See Action Menu for the full Action<T> type reference.

Source: src/providers/ActionMenuProvider.tsx


MediaResourceGalleryProvider + useMediaResourceGallery()

Global singleton. Powers the lightbox opened when clicking a MediaResourceRenderer.

import { useMediaResourceGallery } from "@/providers/MediaResourceGalleryProvider";

const gallery = useMediaResourceGallery(); // returns null outside provider
Method Description
register(galleryKey, resource) Add a resource to a named gallery group
unregister(galleryKey, resourceId) Remove a resource from a group
open(galleryKey, resource, options?) Open the lightbox at the given resource
close() Close the topmost gallery layer
isOpen boolean
layerCount Number of stacked gallery layers currently open

Stacking: galleries push onto a layer stack. Opening the same galleryKey again updates the selected resource in place instead of adding a new layer.

OpenGalleryOptions:

Prop Type Description
leftSidebar ReactNode Custom left sidebar content inside the lightbox
additionalActions ReactNode Extra footer actions

MediaResourceRenderer calls gallery.register on mount and gallery.unregister on unmount automatically. You do not call these methods directly unless building a custom gallery consumer.

useMediaResourceGallery() returns null gracefully outside the provider. Use useMediaResourceGalleryRequired() if you need to throw on missing context.

Source: src/providers/MediaResourceGalleryProvider.tsx


PopoverProvider + usePopoverProvider()

Local provider — mount it around any subtree that needs only one popover open at a time. Not a global singleton.

import {
  PopoverProvider,
  usePopoverProvider,
  ManagedPopover,
} from "@/providers/PopoverProvider";

// Wrap the subtree
<PopoverProvider>
  <CommentPinList />
</PopoverProvider>

// Inside a child — open/close by ID
const { open, close, isOpen, activeId } = usePopoverProvider();
open("pin-42");   // closes any other open popover in this subtree
isOpen("pin-42"); // true
close();          // closes the active popover

ManagedPopover component

Convenience wrapper that wires a Radix Popover to the provider:

<ManagedPopover
  id="pin-42"
  content={<CommentPinPopover pin={pin} />}
  contentProps={{ side: "top", sideOffset: 8 }}
>
  <PinButton onClick={() => open("pin-42")} />
</ManagedPopover>
Prop Type Description
id string Unique ID in this provider subtree
content ReactNode Popover panel content
children ReactNode Anchor element
onClose () => void Called when the popover closes
contentProps PopoverContentProps Passed to Radix PopoverContent

Used internally by CommentPinOverlay to manage annotation pins on MediaResourceRenderer.

Source: src/providers/PopoverProvider.tsx


Local provider — controls whether the sidebar navigation is collapsed. Mount it around the layout that contains the sidebar.

import { MenuProvider, useMenu } from "@/providers/MenuContext";

// In the layout
<MenuProvider defaultCollapsed={true}>
  <Sidebar />
  {children}
</MenuProvider>

// In any child
const { isCollapsed, toggleCollapsed } = useMenu();
Value Type Description
isCollapsed boolean Current collapsed state
toggleCollapsed () => void Toggle between collapsed and expanded

Source: src/providers/MenuContext.tsx


PredictionContextMenuProvider + usePredictionContextMenu()

Local provider — singleton context menu for generation prediction cards. Renders one portal at a time; opening a new menu immediately replaces the previous one.

import {
  PredictionContextMenuProvider,
  usePredictionContextMenu,
} from "@/providers/PredictionContextMenuProvider";

// Mount around the generation grid
<PredictionContextMenuProvider toolbarHidden={false}>
  <GenerationGrid />
</PredictionContextMenuProvider>

// Inside a card — open on right-click
const { openContextMenu, closeContextMenu, isOpen } =
  usePredictionContextMenu();

openContextMenu(data, { x: e.clientX, y: e.clientY });

ContextMenuData:

Field Type Description
prediction PredictionPublic The prediction entity
generation Generation Parent generation
shootingLook ShootingLookPublic? Optional, for subject-swap actions
imageUrl string \| null Preview image URL
predictionShotType string? Shot type label
refineOptions RefineOption[] Available refine actions
toolsWithInputImage any[] AI tools that accept this image as input
hideDelete boolean? Suppress the delete action
onDelete () => Promise<void> Delete callback
onAIToolClick (tool) => void AI tool selection callback
onQuickAction (tool) => void Quick action callback
onDownload (format) => Promise<void>? Download with format selection

Auto-closes on outside left-click, scroll (outside the menu and Radix portals), resize, and Escape.

Source: src/providers/PredictionContextMenuProvider.tsx


PredictionDropdownProvider + usePredictionDropdown()

Local provider — singleton Radix DropdownMenu for generation prediction cards, triggered by a button rather than right-click. Uses a virtual fixed-position trigger anchored to the stored trigger element bounds.

import {
  PredictionDropdownProvider,
  usePredictionDropdown,
} from "@/providers/PredictionDropdownProvider";

<PredictionDropdownProvider toolbarHidden={false}>
  <GenerationGrid />
</PredictionDropdownProvider>

// Inside a card
const { openDropdown, closeDropdown, isOpen } = usePredictionDropdown();

openDropdown(data, buttonElement); // opens anchored to the button

DropdownData is the same shape as ContextMenuData minus shootingLook, onQuickAction, and position — the trigger element provides the anchor.

Auto-closes on outside click, scroll, and resize.

Source: src/providers/PredictionDropdownProvider.tsx


ClientProviders — Global Provider Tree

The full nesting order (outermost → innermost):

OrganizationContextProvider
  WebSocketProvider
    OrganizationProvider
      BreadcrumbRegistryProvider
        DragProvider
          ProductProvider
            GalleryFilterProvider (mode="global-persisted", key="main-gallery")
              ExportTasksProvider
                ModalProvider
                  FloatingWindowProvider
                    TooltipProvider
                      ActionMenuProvider
                        MediaResourceGalleryProvider
                          {children}
                          <UploadProgressDialog />
                          <ModalOutlet />
                          <FloatingWindowOutlet />

Source: src/providers/ClientProviders.tsx


Source Files

File Contents
src/providers/ClientProviders.tsx Global provider tree, queryClient config
src/providers/ActionMenuProvider.tsx Action menu context + portal renderer
src/providers/MediaResourceGalleryProvider.tsx Lightbox gallery context + layer stack
src/providers/FloatingWindowProvider.tsx Floating window context (see Floating Windows)
src/providers/ModalProvider.tsx Modal stack context (see Modals)
src/providers/PopoverProvider.tsx Single-active-popover context + ManagedPopover
src/providers/MenuContext.tsx Sidebar collapsed state
src/providers/PredictionContextMenuProvider.tsx Prediction card right-click menu
src/providers/PredictionDropdownProvider.tsx Prediction card dropdown menu