@judo/feedback
v0.1.1
Published
User feedback system for JUDO UI Runtime (dialogs, notifications, loading)
Readme
@judo/feedback
User feedback system for JUDO UI Runtime (dialogs, notifications, loading)
Purpose
Provides three feedback subsystems — Dialogs, Notifications, and Loading — each following a consistent Service → Provider → Hook → Component architecture. A unified FeedbackProvider composes all three.
Architecture Layer
Layer 4 (Features) — consumed by actions, components, app-shell, and guards.
Dependencies
@judo/model-api— model type definitions@mui/material ^7— UI components (peer)notistack ^3— toast notifications (peer)react ^19— React (peer)
File Structure
src/
├── index.ts # Public barrel re-export
├── provider/
│ └── index.tsx # FeedbackProvider, useFeedback
├── dialogs/
│ ├── service/
│ │ ├── dialog-service.ts # Interfaces + generateDialogId
│ │ └── dialog-service-impl.ts # DialogServiceImpl class
│ ├── provider/
│ │ └── dialog-provider.tsx # DialogProvider, useDialog, useDialogOptional
│ ├── components/
│ │ ├── confirm-dialog.tsx # ConfirmDialog
│ │ ├── alert-dialog.tsx # AlertDialog
│ │ └── dialog-host.tsx # DialogHost (renders active dialogs)
│ └── hooks/
│ └── use-confirmation.ts # useConfirmation
├── notifications/
│ ├── service/
│ │ ├── notification-service.ts # Interfaces + mapPositionToAnchorOrigin
│ │ └── notification-service-impl.ts # NotificationServiceImpl class
│ ├── provider/
│ │ └── notification-provider.tsx # NotificationProvider
│ └── hooks/
│ └── use-notifications.ts # useNotifications
└── loading/
├── service/
│ ├── loading-service.ts # Interfaces
│ └── loading-service-impl.ts # LoadingServiceImpl class
├── provider/
│ └── loading-provider.tsx # LoadingProvider, useLoading, useLoadingOptional
├── components/
│ ├── container-loading.tsx # ContainerLoading
│ ├── global-loading-overlay.tsx # GlobalLoadingOverlay
│ └── skeletons/
│ ├── text-input-skeleton.tsx
│ ├── table-skeleton.tsx
│ ├── form-skeleton.tsx
│ ├── card-skeleton.tsx
│ └── link-skeleton.tsx
└── hooks/
├── use-loading-state.ts # useLoadingState
└── use-component-loading.ts # useComponentLoadingExports Summary
Dialogs
Service Layer
| Export | Kind | Description |
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------- |
| ConfirmDialogOptions | interface | Options for confirmation dialogs: title, message, confirmText, cancelText, confirmColor, destructive. |
| AlertDialogOptions | interface | Options for alert dialogs: title, message, variant, okText. |
| CustomDialogProps | interface | Props injected into custom dialog components: onClose. |
| CustomDialog | interface | Configuration for opening a custom dialog: component, props, size, fullWidth, disableBackdropClick. |
| DialogState | interface | Internal state for tracking an open dialog: id, type, options, dialog. |
| DialogService | interface | Service interface: confirm, alert, open, close, closeAll, subscribe, getSnapshot. |
| generateDialogId() | function | Generates a unique dialog ID using timestamp + random. |
| DialogServiceImpl | class | Concrete implementation using immutable array updates and a Map of resolvers. |
Components
| Export | Kind | Description |
| --------------- | --------- | --------------------------------------------------------------------- |
| ConfirmDialog | component | MUI Dialog with confirm/cancel buttons. Supports destructive styling. |
| AlertDialog | component | MUI Dialog for alerts with severity badge. |
| DialogHost | component | Renders all active dialogs by subscribing to the service. |
Provider & Hooks
| Export | Kind | Description |
| --------------------- | --------- | ------------------------------------------------------------------------------ |
| DialogProvider | component | Creates/accepts a DialogService, provides via context, renders DialogHost. |
| useDialog() | hook | Gets DialogService from context. Throws if outside provider. |
| useDialogOptional() | hook | Gets DialogService or null. |
| useConfirmation() | hook | Convenience wrapper for model-driven confirmation flows. |
Notifications
Service Layer
| Export | Kind | Description |
| ------------------------------------- | --------- | ------------------------------------------------------------------------------------------------- |
| NotificationOptions | interface | Customize a notification: duration, position, action, key. |
| Notification | interface | Full notification (extends NotificationOptions): adds message, variant. |
| NotificationAction | interface | Action button for a notification: label, onClick. |
| NotificationVariant | type | "success" \| "error" \| "warning" \| "info" |
| NotificationPosition | type | "top-right" \| "top-center" \| "top-left" \| "bottom-right" \| "bottom-center" \| "bottom-left" |
| NotificationService | interface | Methods: show, success, error, warning, info, dismiss, dismissAll. |
| mapPositionToAnchorOrigin(position) | function | Maps position strings to notistack anchor origin objects. |
| NotificationServiceImpl | class | Implementation using notistack. Error notifications persist by default. |
Provider & Hooks
| Export | Kind | Description |
| ---------------------- | --------- | ------------------------------------------------------------------------------ |
| NotificationProvider | component | Wraps children with notistack SnackbarProvider. Default max 5, bottom-right. |
| useNotifications() | hook | Returns a NotificationService backed by notistack's useSnackbar. |
Loading
Service Layer
| Export | Kind | Description |
| -------------------- | --------- | ----------------------------------------------------------------------------------------------------- |
| LoadingOptions | interface | Options when starting a loading operation: global, message, showProgress, progress. |
| LoadingSnapshot | interface | Snapshot of current loading state: isLoading, activeKeys, globalLoading, message, progress. |
| LoadingService | interface | Methods: start, end, isLoading, isLoadingKey, getActiveKeys, subscribe, getSnapshot. |
| LoadingServiceImpl | class | Implementation using a Map. Caches snapshots for referential stability. |
Components
| Export | Kind | Description |
| ---------------------- | --------- | ------------------------------------------------------------------------------------------------------------ |
| TextInputSkeleton | component | Skeleton placeholder for text inputs. |
| TableSkeleton | component | Skeleton for tables (header + N×M grid). Default 5×4. |
| FormSkeleton | component | Skeleton for forms (N input fields). Default 4. |
| CardSkeleton | component | Skeleton for cards (MUI Card with 3 text lines). |
| LinkSkeleton | component | Skeleton for link/autocomplete inputs. |
| ContainerLoading | component | Wraps children with loading state. Shows skeleton or spinner. Anti-flicker delay (default 200ms). |
| GlobalLoadingOverlay | component | Full-screen Backdrop overlay shown when any loading key has global: true. Supports determinate progress. |
Provider & Hooks
| Export | Kind | Description |
| -------------------------- | --------- | ------------------------------------------------------------------------------------ |
| LoadingProvider | component | Provides LoadingService via context. Optionally renders GlobalLoadingOverlay. |
| useLoading() | hook | Gets LoadingService. Throws if outside provider. |
| useLoadingOptional() | hook | Gets LoadingService or null. |
| useLoadingState() | hook | Subscribes to loading service, returns current LoadingSnapshot. |
| useComponentLoading(key) | hook | Per-component loading management. Returns { isLoading, startLoading, endLoading }. |
Unified Provider
| Export | Kind | Description |
| ------------------ | --------- | -------------------------------------------------------------------------------------- |
| FeedbackProvider | component | Composes DialogProvider → NotificationProvider → LoadingProvider in one wrapper. |
| useFeedback() | hook | Returns all three services: { dialogs, notifications, loading }. |
Key Patterns
- Service / Provider / Hook / Component separation: Each subsystem has a pure-logic service class, a React context provider, consumer hooks, and presentational components
subscribe/getSnapshot: Dialog and Loading services are consumed viauseSyncExternalStorefor tear-free rendering- Promise-based dialog resolution:
confirm/alertreturn Promises. AMapmaps dialog IDs to their resolve functions - Snapshot caching:
LoadingServiceImplcaches the snapshot object and invalidates on mutation for referential stability - Anti-flicker in
ContainerLoading: UsesminLoadingTime(default 200ms) to prevent brief loading flashes - Error notifications persist: Error variant sets
duration: 0(no auto-hide) by default - Optional service injection:
DialogProviderandLoadingProvideraccept optionalserviceprop for testing - Immutable state updates:
DialogServiceImpluses spread-into-new-array and filter for immutable snapshots
