# @judo/core

> Core React contexts and hooks for JUDO UI Runtime

## Purpose

Central state management layer providing application context, navigation, data binding, validation, dispatch, runtime configuration, customizations, and refresh signaling. This is the **heart of the React runtime** — it bridges model definitions to live React component trees.

## Architecture Layer

**Layer 3 (Infrastructure)** — consumed by components, app-shell, and actions packages.

## Dependencies

- `@judo/model-api` — model type definitions
- `@judo/model-loader` — model registry
- `@judo/actions` — action types (used by `DispatchContext`)
- `react ^19` — React (peer)

## File Structure

```
src/
├── index.ts                          # Barrel re-export
├── contexts/
│   ├── application-context.tsx       # Application/actor context
│   ├── navigation-context.tsx        # Page stack + dialog navigation
│   ├── data-context.tsx              # DataStore provider
│   ├── dispatch-context.tsx          # Action dispatch provider
│   ├── page-context.tsx              # Current page metadata
│   ├── refresh-signal-context.tsx    # Post-operation refresh signal
│   ├── runtime-config-context.tsx    # Feature flags / runtime config
│   ├── validation-context.tsx        # Form-level validation state
│   ├── customizations-context.tsx    # Component overrides, interceptors, page customizations
│   ├── mui-pro-context.tsx           # MUI X Pro component access
│   ├── selector-selection-context.tsx # Selector dialog selection sharing
│   └── index.ts                      # Barrel re-export for contexts
├── hooks/
│   ├── use-visual-binding.ts         # Visual element ↔ data store binding (incl. hiddenBy/enabledBy/requiredBy)
│   ├── use-element-visibility.ts     # hiddenBy runtime evaluation for any VisualElement
│   ├── use-element-disabled.ts       # enabledBy runtime evaluation for any VisualElement
│   ├── use-validation.ts             # Per-element validation + useFormValidation
│   ├── use-data-selector.ts          # Selector-based data subscriptions
│   ├── use-edit-mode.ts              # Edit/dirty mode detection
│   ├── use-visual-element.ts         # Visual element lookup utility
│   ├── use-debounced-callback.ts     # Debounced callback for typeahead/autocomplete
│   └── index.ts                      # Barrel re-export for hooks
├── store/
│   ├── data-store.ts                 # DataStore class (external store)
│   ├── selectors.ts                  # Selector factory functions
│   └── index.ts                      # Barrel re-export for store
└── utils/
    ├── deep-equal.ts                 # Deep equality comparison
    └── index.ts                      # Barrel re-export for utils
```

## Exports Summary

### Context Providers (11)

| Provider                    | Key Props                                               | Purpose                                                                                                                                           |
| --------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ApplicationProvider`       | `registry`                                              | Subscribes to `ModelRegistry` via `useSyncExternalStore`. Exposes active application + actor switching.                                           |
| `NavigationProvider`        | `initialPage?`, `navigate?`, `getRouteForPage?`         | Page stack navigation, dialog open/close with callbacks, React Router integration.                                                                |
| `DataProvider`              | `store?`                                                | Creates/wraps a `DataStore` instance in React context.                                                                                            |
| `ValidationProvider`        | —                                                       | Manages field errors (`Map`) and touched state (`Set`).                                                                                           |
| `PageProvider`              | `pageDefinition`, `transferId?`, `params?`, `isDialog?` | Current page metadata.                                                                                                                            |
| `RuntimeConfigProvider`     | `config?`                                               | Feature flags (guards, forceShowTotalCount, headerFilters) and MUI Pro license key.                                                               |
| `DispatchProvider`          | `dispatch`                                              | Action dispatch function for the component tree.                                                                                                  |
| `RefreshSignalProvider`     | `signal`                                                | Page-level refresh signal. ViewContainerRenderer increments after successful operations; embedded components watch and re-dispatch refresh logic. |
| `CustomizationsProvider`    | `customizations?`                                       | Component overrides, interceptors, page-scoped customization bundles. HMR support via ref + version counter.                                      |
| `MuiProProvider`            | `isProEnabled`, `components?`                           | Provides Pro variants of MUI X components (e.g., `DataGridPro`). Activated when MUI Pro license is set.                                           |
| `SelectorSelectionProvider` | `ownerTransfer?`                                        | Shares selection state (via mutable ref) between table and dialog footer in selector dialogs.                                                     |

Each provider exports a **mandatory hook** (`useX()` — throws if outside provider) and an **optional hook** (`useXOptional()` — returns null), except `RefreshSignalProvider` which provides only `useRefreshSignal()` (returns 0 when outside provider).

### DataStore

| Export                       | Kind      | Description                                                                                                |
| ---------------------------- | --------- | ---------------------------------------------------------------------------------------------------------- |
| `TransferData`               | interface | Shape of transfer data objects with JUDO internal properties (`__signedIdentifier`, `__identifier`, etc.). |
| `TransferState`              | interface | Per-transfer tracked state: `data`, `originalData`, `isDirty`, `isLoading`, `error`.                       |
| `DataStoreState`             | interface | Full store state: `transfers` map + `version` counter.                                                     |
| `DataSelector<T>`            | type      | Selector function: `(state: DataStoreState) => T`.                                                         |
| `createEmptyTransferState()` | function  | Factory returning a new empty `TransferState`.                                                             |
| `DataStore` (class)          | class     | External store (not React state) with selector-based subscriptions.                                        |

**DataStore methods:**

| Method                                          | Description                                                                             |
| ----------------------------------------------- | --------------------------------------------------------------------------------------- |
| `subscribe(selector, callback)`                 | Subscribe to a data slice. Only fires when selected value changes. Returns unsubscribe. |
| `getSnapshot(selector)`                         | Returns current value for a selector.                                                   |
| `getState()`                                    | Returns full state (debug/test).                                                        |
| `getTransfer(transferId)`                       | Get transfer state by ID.                                                               |
| `setTransferData(transferId, data)`             | Sets transfer data & originalData, resets dirty/loading/error.                          |
| `updateTransferField(transferId, field, value)` | Updates one field, recalculates `isDirty`. Creates transfer if absent.                  |
| `updateTransferFields(transferId, updates)`     | Batch field updates, recalculates `isDirty`.                                            |
| `setTransferLoading(transferId, loading)`       | Toggle loading state.                                                                   |
| `setTransferError(transferId, error)`           | Set error, clears loading.                                                              |
| `resetTransfer(transferId)`                     | Reverts data to originalData, clears dirty.                                             |
| `clearTransfer(transferId)`                     | Removes transfer from store.                                                            |
| `clearAll()`                                    | Clears all transfers.                                                                   |

### Selector Factories

| Function                                 | Description                                     |
| ---------------------------------------- | ----------------------------------------------- |
| `selectTransfer(transferId)`             | Selector for entire transfer state.             |
| `selectTransferField(transferId, field)` | Selector for a single field value.              |
| `selectTransferLoading(transferId)`      | Selector for loading state.                     |
| `selectTransferError(transferId)`        | Selector for error state.                       |
| `selectTransferDirty(transferId)`        | Selector for dirty state.                       |
| `selectTransferIds`                      | Direct selector returning all transfer IDs.     |
| `selectVersion`                          | Direct selector returning store version number. |

### React Hooks

| Hook                                                        | Description                                                                                                                                                                                                             |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `useApplication()` / `useApplicationOptional()`             | Access application context (`ApplicationContextType`).                                                                                                                                                                  |
| `useNavigation()` / `useNavigationOptional()`               | Access navigation context (page stack, dialogs).                                                                                                                                                                        |
| `useDataStore()` / `useDataStoreOptional()`                 | Access `DataStore` instance.                                                                                                                                                                                            |
| `useValidationContext()` / `useValidationContextOptional()` | Access validation context (field errors, touched state).                                                                                                                                                                |
| `usePageContext()` / `usePageContextOptional()`             | Access current page metadata.                                                                                                                                                                                           |
| `useRuntimeConfig()` / `useRuntimeConfigOptional()`         | Access runtime configuration (returns `RuntimeConfigContextType`).                                                                                                                                                      |
| `useDispatch()` / `useDispatchOptional()`                   | Access action dispatch function.                                                                                                                                                                                        |
| `useCustomizations()` / `useCustomizationsOptional()`       | Access customizations context (component overrides, interceptors, page customizations).                                                                                                                                 |
| `useMuiPro()` / `useMuiProOptional()`                       | Access MUI Pro component context.                                                                                                                                                                                       |
| `useSelectorSelection()` / `useSelectorSelectionOptional()` | Access selector dialog selection state.                                                                                                                                                                                 |
| `useVisualBinding(element, attributeType?)`                 | **Core binding hook.** Subscribes to `DataStore` for attribute data. Resolves label, hidden, disabled, required, readOnly. Integrates `hiddenBy`, `enabledBy`, `requiredBy` dynamic behavior and validation for errors. |
| `useElementVisibility(element)`                             | Evaluates runtime hidden state of any `VisualElement` via `hiddenBy` dynamic data, static `hidden`, and customization overrides. Safe outside `DataProvider`.                                                           |
| `useElementDisabled(element)`                               | Evaluates runtime disabled state of any `VisualElement` via `enabledBy` dynamic data, static `disabled`, and customization overrides. `enabledBy` fully controls disabled when present. Safe outside `DataProvider`.    |
| `useValidation(element)`                                    | Per-element validation. Returns `ValidationResult` with error (only for touched fields), touch/setError/clearError methods.                                                                                             |
| `useFormValidation()`                                       | Alias for `useValidationContext()` — throws if outside `ValidationProvider`.                                                                                                                                            |
| `useDataSelector(selector)`                                 | Generic selector subscription via `useSyncExternalStore`.                                                                                                                                                               |
| `useTransferState(transferId)`                              | Convenience hook for full transfer state.                                                                                                                                                                               |
| `useTransferField(transferId, field)`                       | Convenience hook for single field value.                                                                                                                                                                                |
| `useTransferLoading(transferId)`                            | Convenience hook for transfer loading state.                                                                                                                                                                            |
| `useTransferDirty(transferId)`                              | Convenience hook for transfer dirty state.                                                                                                                                                                              |
| `useEditMode()`                                             | Derives edit mode from `PageContext` transfer ID + `DataStore` dirty state. No parameters — reads context directly.                                                                                                     |
| `useRefreshSignal()`                                        | Returns current page-level refresh signal (0 when outside provider).                                                                                                                                                    |
| `useComponentOverride(element)`                             | Returns custom component for element by sourceId, or null.                                                                                                                                                              |
| `useComponentInterceptor(element)`                          | Returns intercepted component for element by `@type`, or null.                                                                                                                                                          |
| `useSubThemeProvider(element)`                              | Returns the `SubThemeHook` for an element's `subTheme` property, or null.                                                                                                                                               |
| `usePageActionOverrides(page, action)`                      | Returns action lifecycle overrides for an action on a page.                                                                                                                                                             |
| `useVisualPropertyOverrides(element)`                       | Returns visual property overrides for an element.                                                                                                                                                                       |
| `useResolvedPageActionOverrides()`                          | Returns all resolved action overrides for current page.                                                                                                                                                                 |
| `useActionLifecycleOverrides(actionSourceId)`               | Returns lifecycle overrides for a specific action by sourceId.                                                                                                                                                          |
| `useTypeaheadProvider(elementSourceId)`                     | Returns the typeahead provider for a text input, resolved from page-scoped `PageCustomization`.                                                                                                                         |
| `useTableRowHighlighting(elementSourceId)`                  | Returns the `TableRowHighlightConfig[]` for a table element, resolved from page-scoped `PageCustomization`.                                                                                                             |
| `useEnumOptionFilter(elementSourceId)`                      | Returns a wrapped filter function for enum input options. Subscribes to transfer data changes for reactive re-evaluation.                                                                                               |
| `useDateValidationProps(elementSourceId)`                   | Returns `DateValidationProps` for a date/datetime input. Subscribes to transfer data changes for reactive re-evaluation.                                                                                                |
| `useColumnCustomizers()`                                    | Returns all column customizer functions for the current page from `PageCustomization.columnCustomizers`.                                                                                                                |
| `useItemContainerConfig(elementSourceId)`                   | Returns `ItemContainerConfig` for a table element from `PageCustomization.itemContainerConfigs`.                                                                                                                        |
| `useDebouncedCallback(callback, delay?)`                    | Returns a debounced version of the callback (default 300ms). Used by autocomplete/typeahead.                                                                                                                            |
| `getVisualElement(registry, sourceId)`                      | Utility function (not a hook) — looks up a `VisualElement` by sourceId from model registry.                                                                                                                             |

### Additional Exported Components

| Export                        | Kind      | Description                                                                                              |
| ----------------------------- | --------- | -------------------------------------------------------------------------------------------------------- |
| `PageActionOverridesProvider` | component | Calls registered page action hook and provides resolved overrides to descendants. Inside `PageProvider`. |
| `VisualPropertiesProvider`    | component | Calls registered visual properties hook and provides overrides to descendants. Inside `PageProvider`.    |

### Context Types

| Type                           | Description                                                                                                                                                                                                                                    |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ApplicationContextType`       | `application`, `applications`, `actorName`, `switchActor`, `switchActorWithNavigation`                                                                                                                                                         |
| `NavigationContextType`        | Extends `NavigationState`. Methods: `navigateTo`, `goBack`, `openDialog`, `closeDialog`, `replacePage`, `clearStack`, `dialog`, `canGoBack`                                                                                                    |
| `PageStackEntry`               | `pageDefinition`, `params?`, `scrollPosition?`                                                                                                                                                                                                 |
| `NavigationState`              | `pageStack`, `currentPage`, `dialogStack`                                                                                                                                                                                                      |
| `DialogState`                  | `pageDefinition`, `size`, `params?`                                                                                                                                                                                                            |
| `DialogCloseResultType`        | `"cancelled" \| "created" \| "updated" \| "deleted" \| "selected" \| "submitted"`                                                                                                                                                              |
| `DialogCloseResult`            | Discriminated union for each result type (e.g., `{ type: "created"; isEager: boolean; data?: unknown }`)                                                                                                                                       |
| `DialogCloseCallback`          | `(result?: DialogCloseResult) => void`                                                                                                                                                                                                         |
| `PageContextType`              | `pageDefinition`, `transferId`, `params`, `isDialog`                                                                                                                                                                                           |
| `ValidationContextType`        | Methods: `getError`, `setError`, `setErrors`, `touch`, `isTouched`, `clearErrors`, `clearError`, `validateAll`, `getAllErrors`, `isValid`                                                                                                      |
| `ValidationState`              | `errors: Map<string, string>`, `touched: Set<string>`                                                                                                                                                                                          |
| `RuntimeConfig`                | `features?: FeaturesConfig`, `muiProLicenseKey?`                                                                                                                                                                                               |
| `FeaturesConfig`               | `guards?`, `forceShowTotalCountForLazyTables?`, `headerFilters?`                                                                                                                                                                               |
| `RuntimeConfigContextType`     | `{ config: RuntimeConfig }`                                                                                                                                                                                                                    |
| `DispatchFn`                   | `(action: Action) => Promise<unknown>` (uses `Action` from `@judo/actions`)                                                                                                                                                                    |
| `DispatchContextType`          | `{ dispatch: DispatchFn }`                                                                                                                                                                                                                     |
| `CustomizationsContextType`    | `version`, `getPageCustomization`, `getComponent`, `getComponentInterceptor`, `getSubThemeProvider`, `getRedirectHandler`, `getCustomRoutes`, `getMenuCustomizer`, `getFooterText`, `getHeroComponent`, `getSettingsPage`, `getGuestComponent` |
| `MuiProContextType`            | `isProEnabled`, `getComponent(name)`                                                                                                                                                                                                           |
| `SelectorSelectionContextType` | `selectedTransfersRef` (mutable ref), `ownerTransfer?`                                                                                                                                                                                         |
| `VisualBindingResult`          | `value`, `onChange`, `error`, `hidden`, `disabled`, `required`, `label`, `readOnly`, `isLoading`, `isDirty`                                                                                                                                    |
| `ValidationResult`             | `error`, `isTouched`, `touch()`, `setError()`, `clearError()`                                                                                                                                                                                  |
| `EditModeResult`               | `isEditMode`, `transferId`                                                                                                                                                                                                                     |

### Utilities

| Export                | Kind     | Description                                                                                                                                                                                |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `deepEqual(a, b)`     | function | Recursive deep equality comparison. Handles references, null/undefined, primitives, Arrays, Dates, and plain Objects. Used by `DataStore` for dirty tracking and selector cache stability. |
| `DEFAULT_DEBOUNCE_MS` | constant | Default debounce delay (300ms) used by `useDebouncedCallback`.                                                                                                                             |

## Key Patterns

- **Mandatory + Optional hook pairs**: Every context exports both `useX()` (throws) and `useXOptional()` (returns null)
- **External store with selector-based subscriptions**: `DataStore` is a plain class; hooks subscribe via `useSyncExternalStore` + selector functions for fine-grained re-renders
- **Referential stability via deep-equal cache**: `useVisualBinding` and dynamic behavior hooks use ref-based caches with `deepEqual` to ensure referential stability for `useSyncExternalStore`
- **Model-driven binding**: `useVisualBinding` bridges `VisualElement` to `DataStore` by resolving `attributeType.name` as the data field key
- **Dynamic behavior via `*By` references**: `hiddenBy`/`enabledBy`/`requiredBy` properties on `VisualElement` reference `AttributeType` instances — hooks subscribe to the DataStore for those boolean fields and evaluate runtime visibility/disabled/required state
- **`enabledBy` vs `hiddenBy` asymmetry**: `enabledBy` fully replaces the static `disabled` value when present; `hiddenBy` only overrides _to hidden_ (never clears static `hidden=true`)
- **Dialog lifecycle with callbacks**: `openDialog` accepts an `onClose?: DialogCloseCallback` callback; dialog close callbacks stored in a ref-based stack (`dialogCloseCallbackStackRef`)
- **React Router integration**: `NavigationProvider` optionally accepts `navigate` and `getRouteForPage` props
- **`useSyncExternalStore` throughout**: `ApplicationProvider`, all data hooks, dynamic behavior hooks, and customization data-reactive hooks use React 18+ tear-free external store pattern
- **RefreshSignalProvider**: Post-operation refresh signaling — ViewContainerRenderer increments a counter after operations; embedded components watch and re-dispatch their refresh logic
- **Customizations with HMR support**: `CustomizationsProvider` stores config in a ref and uses a version counter; when customizations identity changes, version bumps and consumers re-render
- **Selector selection via mutable ref**: `SelectorSelectionProvider` uses a `useRef` for selection state to avoid re-renders; value only read at dispatch time
