diff --git a/.changeset/25921-fields-zero-consumer-exports.md b/.changeset/25921-fields-zero-consumer-exports.md new file mode 100644 index 00000000000..65a2be9d399 --- /dev/null +++ b/.changeset/25921-fields-zero-consumer-exports.md @@ -0,0 +1,20 @@ +--- +'@object-ui/fields': patch +--- + +refactor(fields)!: retire six zero-consumer exports (four file-value helpers, the filter-condition extra operators, the grid column sum) + +Clause-②: no (narrowing) +Metadata-protocol: none + + + +**BREAKING** for a host that imports any of these six names from `@object-ui/fields`. None had an importer anywhere in the workspace or in hotcrm, so the Console and every `@object-ui/*` package are unaffected. Every module stays in the package: `FileField`, `ImageField` and `AvatarField` keep reading the file-value helpers, `FilterConditionField` keeps offering its extra operators, `fileUrlFromId` keeps building on the storage base path and `GridField` keeps summing its total column. Only the entry stops publishing them. `fileIdOf`, `fileUrlFromId`, `readFileValue`, `readFileValues`, `fileValueForSubmit`, `isFileIdToken`, `UploadIncompleteError`, the `FileValueView` and `UploadResultLike` types, `condToMongo`, `kvToCondition`, `isMatchAllCriteria`, `FilterConditionField`, `evalArith`, `lookupAutofillPatch`, `computeRow`, `GridField`, `LineItemsField` and the `GridColumn` type stay exported unchanged. + +What leaves, and what to write instead: + +- FROM `isImageValue` TO `readFileValue(value)` and a check on its `mimeType`. +- FROM `uploadResultView`, `withRecentUploads` TO `FileField` / `ImageField` / `AvatarField`, which show a just-uploaded file themselves. +- FROM `FILE_STORAGE_BASE_PATH` TO `fileUrlFromId`, which builds the download URL for a file id on that path. +- FROM `FILTER_CONDITION_EXTRA_OPERATORS` TO `FilterConditionField`, which offers those operators itself. +- FROM `sumColumn` TO `GridField`, which draws the total of its declared total column, or a local reduce over the rows. diff --git a/.changeset/25921-react-zero-consumer-exports.md b/.changeset/25921-react-zero-consumer-exports.md new file mode 100644 index 00000000000..c0e17c889c8 --- /dev/null +++ b/.changeset/25921-react-zero-consumer-exports.md @@ -0,0 +1,32 @@ +--- +'@object-ui/react': patch +--- + +refactor(react)!: retire twenty zero-consumer exports, and delete the two motion hooks, two helpers and one type nothing reads + +Clause-②: no (narrowing) +Metadata-protocol: none + + + +**BREAKING** for a host that imports any of these twenty names from `@object-ui/react`. None had an importer anywhere in the workspace or in hotcrm, so the Console and every `@object-ui/*` package are unaffected. + +Seven of them are **gone from the package, not only from the entry**, because nothing inside the package read them either: the `hooks/useReducedMotion.ts` module (`useReducedMotion`) and the `hooks/useViewTransition.ts` module (`useViewTransition`, `ViewTransitionConfig`, `ViewTransitionResult`) are deleted, and the functions `useHasPageVariables` and `getShortcutDescriptions` and the type `AnimationTriggerType` are deleted from their modules. + +The other thirteen stay in their modules for the code that reads them and only leave the entry: `formatUnresolvableVisibilityMessage` (the visibility reporter still formats with it), `evaluateConfigBagInScope` (`useConfigBagEvaluator` still calls it), `SUPPORTED_TRANSITION_PRESETS` / `SUPPORTED_EASING_FUNCTIONS` and the three `SUPPORTED_NOTIFICATION_*` sets (the spec-parity tests still hold them against the spec vocabularies, and `resolveNotificationPosition` still checks positions against its set), `useOptionalTheme`, `resolveNotificationPresentation` (`NotificationProvider` still calls it), the raw `HostMapStyleContext` / `RecordPagePreferencesContext` / `PrintPageContext` objects, and `NoDataSourcePanel` (`ElementDataSourceGate` still renders it). Every other name the entry exported stays exported unchanged, among them `reportUnresolvableVisibilityPredicate`, `UNRESOLVABLE_VISIBILITY_PREFIX`, `UNRESOLVABLE_ENABLEMENT_PREFIX`, `useAnimation`, `useTheme`, `useNotifications`, `NotificationProvider`, the `HostMapStyleProvider` / `RecordPagePreferencesProvider` / `PrintPageProvider` providers with their `useHostMapStyle` / `useRecordPagePreferences` / `usePrintPage` hooks, `usePageVariables`, `useKeyboardShortcuts` and `ElementDataSourceGate`. + +What leaves, and what to write instead: + +- FROM `useReducedMotion` TO `window.matchMedia('(prefers-reduced-motion: reduce)')` in your own hook; the package no longer carries one. +- FROM `useViewTransition`, `ViewTransitionConfig`, `ViewTransitionResult` TO `document.startViewTransition` called directly; the package no longer carries a wrapper. +- FROM `useHasPageVariables` TO `usePageVariables()`, which answers a frozen empty value outside a `PageVariablesProvider`. +- FROM `getShortcutDescriptions` TO a local map over your `KeyboardShortcutDefinition[]` (filter on `description` and `enabled !== false`). +- FROM `AnimationTriggerType` TO a local string union: no function in the package takes it. +- FROM `formatUnresolvableVisibilityMessage` TO `reportUnresolvableVisibilityPredicate`, which formats and reports in one call; filter its lines by `UNRESOLVABLE_VISIBILITY_PREFIX` / `UNRESOLVABLE_ENABLEMENT_PREFIX`. +- FROM `evaluateConfigBagInScope` TO `SchemaRenderer`, which evaluates a node's config bag itself. +- FROM `SUPPORTED_TRANSITION_PRESETS`, `SUPPORTED_EASING_FUNCTIONS` TO the `TransitionPresetType` / `EasingPreset` types, or the spec's `TransitionPresetSchema` / `EasingFunctionSchema` for a runtime list. +- FROM `useOptionalTheme` TO `useTheme` inside a `ThemeProvider`. +- FROM `resolveNotificationPresentation` TO `useNotificationsByPresentation(presentation)`, which returns the notifications a surface of that presentation renders. +- FROM `SUPPORTED_NOTIFICATION_DISPLAY_TYPES`, `SUPPORTED_NOTIFICATION_POSITIONS`, `SUPPORTED_NOTIFICATION_ACTION_VARIANTS` TO the `NotificationDisplayType` / `NotificationPositionValue` / `NotificationActionVariant` types, or `resolveNotificationPosition` to normalize a position. +- FROM `HostMapStyleContext`, `RecordPagePreferencesContext`, `PrintPageContext` TO their providers (`HostMapStyleProvider`, `RecordPagePreferencesProvider`, `PrintPageProvider`) and hooks (`useHostMapStyle`, `useRecordPagePreferences`, `usePrintPage`). +- FROM `NoDataSourcePanel` TO `ElementDataSourceGate`, which renders it when no data source resolves, or `noDataSourceMessage` for the text. diff --git a/ui/packages/fields/src/index.tsx b/ui/packages/fields/src/index.tsx index b9cba58b48a..d3fac6ee8bc 100644 --- a/ui/packages/fields/src/index.tsx +++ b/ui/packages/fields/src/index.tsx @@ -5420,7 +5420,18 @@ export * from './widgets/types.js'; // File field value shapes (ObjectStack ADR-0104 D3 wave 2) — the single // arbiter of reference vs expanded vs legacy-blob form, shared by the upload // widgets and by action-param serialization. -export * from './widgets/file-value.js'; +// isImageValue, uploadResultView, withRecentUploads and FILE_STORAGE_BASE_PATH +// stay module-level: the upload widgets read them; no host does. +export { + fileIdOf, + fileUrlFromId, + readFileValue, + readFileValues, + fileValueForSubmit, + isFileIdToken, + UploadIncompleteError, +} from './widgets/file-value.js'; +export type { FileValueView, UploadResultLike } from './widgets/file-value.js'; export * from './FieldEditWidget.js'; export * from './widgets/TextField.js'; export * from './widgets/NumberField.js'; @@ -5445,7 +5456,7 @@ export * from './widgets/RichTextField.js'; export * from './widgets/LookupField.js'; export * from './widgets/CapabilityMultiSelectField.js'; export * from './widgets/ObjectRefField.js'; -export * from './widgets/FilterConditionField.js'; +export { condToMongo, kvToCondition, isMatchAllCriteria, FilterConditionField } from './widgets/FilterConditionField.js'; export * from './widgets/RecipientPickerField.js'; // The kind table and the two spellings the reference widgets share with a host // face (objectui#12613), published so the face names a stored value as the @@ -5484,7 +5495,8 @@ export * from './widgets/AutoNumberField.js'; export * from './widgets/UserField.js'; export * from './widgets/ObjectField.js'; export * from './widgets/VectorField.js'; -export * from './widgets/GridField.js'; +export { evalArith, lookupAutofillPatch, computeRow, GridField, LineItemsField } from './widgets/GridField.js'; +export type { GridColumn } from './widgets/GridField.js'; export * from './widgets/lookupAutofill.js'; // New widgets according to @objectstack/spec export * from './widgets/ColorField.js'; diff --git a/ui/packages/react/src/context/index.ts b/ui/packages/react/src/context/index.ts index 31060ec35b7..232025518d2 100644 --- a/ui/packages/react/src/context/index.ts +++ b/ui/packages/react/src/context/index.ts @@ -1,8 +1,34 @@ export * from './SchemaRendererContext.js'; export * from './PreviewModeContext.js'; export * from './ActionContext.js'; -export * from './ThemeContext.js'; -export * from './NotificationContext.js'; +export { ThemeProvider, useTheme } from './ThemeContext.js'; +export type { ThemeContextValue, ThemeProviderProps } from './ThemeContext.js'; +// resolveNotificationPresentation and the three SUPPORTED_NOTIFICATION_* sets stay +// module-level for the provider and the spec-parity test; no host imports them. +export { + resolveNotificationConfig, + useNotifications, + useHasNotificationProvider, + visibleNotificationStack, + resolveNotificationPosition, + useNotificationsByPresentation, + NOTIFICATION_PRESENTATIONS, + NotificationProvider, +} from './NotificationContext.js'; +export type { + NotificationSeverityLevel, + NotificationPresentation, + NotificationDisplayType, + NotificationSurface, + NotificationPresentationBehavior, + NotificationPositionValue, + NotificationActionVariant, + NotificationActionButton, + NotificationItem, + NotificationSystemConfig, + ResolvedNotificationConfig, + NotificationProviderProps, +} from './NotificationContext.js'; export * from './DndContext.js'; export * from './AppShellContext.js'; export * from './RecordContext.js'; @@ -10,7 +36,8 @@ export * from './InlineEditContext.js'; export * from './DiscussionContext.js'; export * from './DrillNavigationContext.js'; export * from './HostNavigationContext.js'; -export * from './HostMapStyleContext.js'; -export * from './RecordPagePreferencesContext.js'; +export { useHostMapStyle, HostMapStyleProvider } from './HostMapStyleContext.js'; +export { useRecordPagePreferences, RecordPagePreferencesProvider } from './RecordPagePreferencesContext.js'; +export type { RecordPagePreference, RecordPagePreferencesStore } from './RecordPagePreferencesContext.js'; export * from './RelatedRecordActionsContext.js'; -export * from './PrintPageContext.js'; +export { PrintPageProvider, usePrintPage } from './PrintPageContext.js'; diff --git a/ui/packages/react/src/hooks/index.ts b/ui/packages/react/src/hooks/index.ts index 5203f55271f..20db89ede9a 100644 --- a/ui/packages/react/src/hooks/index.ts +++ b/ui/packages/react/src/hooks/index.ts @@ -23,14 +23,15 @@ export * from './useDynamicApp.js'; export * from './useDiscovery.js'; export * from './useKeyboardShortcuts.js'; export * from './useCrudShortcuts.js'; -export * from './useReducedMotion.js'; -export * from './useAnimation.js'; +// SUPPORTED_TRANSITION_PRESETS / SUPPORTED_EASING_FUNCTIONS stay module-level for +// the spec-parity test that imports them from the module; no host imports them. +export { useAnimation } from './useAnimation.js'; +export type { EasingPreset, TransitionPresetType, AnimationConfig, AnimationResult } from './useAnimation.js'; export * from './useDensityMode.js'; export * from './useViewSharing.js'; export * from './useOffline.js'; export * from './usePerformance.js'; export * from './usePerformanceBudget.js'; -export * from './useViewTransition.js'; export * from './useETagCache.js'; export * from './useGlobalUndo.js'; export * from './useDebugMode.js'; diff --git a/ui/packages/react/src/hooks/useAnimation.ts b/ui/packages/react/src/hooks/useAnimation.ts index 5dadbd08103..dfc7e64c86c 100644 --- a/ui/packages/react/src/hooks/useAnimation.ts +++ b/ui/packages/react/src/hooks/useAnimation.ts @@ -8,9 +8,6 @@ import { useMemo } from 'react'; -/** Animation trigger type */ -export type AnimationTriggerType = 'enter' | 'exit' | 'hover' | 'focus' | 'click'; - /** * Easing presets aligned with the spec `EasingFunctionSchema` * (`ui/animation.zod.ts` — underscore spellings). The hyphen spellings are diff --git a/ui/packages/react/src/hooks/useKeyboardShortcuts.ts b/ui/packages/react/src/hooks/useKeyboardShortcuts.ts index 29c965b7edd..57a2df8b81f 100644 --- a/ui/packages/react/src/hooks/useKeyboardShortcuts.ts +++ b/ui/packages/react/src/hooks/useKeyboardShortcuts.ts @@ -95,25 +95,3 @@ export function useKeyboardShortcuts( }; }, [enabled, handleKeyDown]); } - -/** - * Returns a list of all registered shortcut descriptions. - * Useful for building a help dialog (? key). - */ -export function getShortcutDescriptions( - shortcuts: KeyboardShortcutDefinition[] -): Array<{ keys: string; description: string }> { - return shortcuts - .filter((s) => s.description && s.enabled !== false) - .map((s) => { - const parts: string[] = []; - if (s.ctrlOrMeta) parts.push('⌘/Ctrl'); - if (s.shift) parts.push('Shift'); - if (s.alt) parts.push('Alt'); - parts.push(s.key.length === 1 ? s.key.toUpperCase() : s.key); - return { - keys: parts.join(' + '), - description: s.description!, - }; - }); -} diff --git a/ui/packages/react/src/hooks/usePageVariables.tsx b/ui/packages/react/src/hooks/usePageVariables.tsx index 70748fbdf47..9da9180df05 100644 --- a/ui/packages/react/src/hooks/usePageVariables.tsx +++ b/ui/packages/react/src/hooks/usePageVariables.tsx @@ -213,13 +213,6 @@ const OUTSIDE_PAGE: PageVariablesContextValue = Object.freeze({ resetVariables: () => {}, }); -/** - * Hook to check if a PageVariablesProvider is available. - */ -export function useHasPageVariables(): boolean { - return useContext(PageVariablesContext) !== null; -} - /** * A writer binding for a page variable, resolved from a component id. */ diff --git a/ui/packages/react/src/hooks/useReducedMotion.ts b/ui/packages/react/src/hooks/useReducedMotion.ts deleted file mode 100644 index 0fb4bc59d37..00000000000 --- a/ui/packages/react/src/hooks/useReducedMotion.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * ObjectUI - * Copyright (c) 2024-present ObjectStack Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { useState, useEffect } from 'react'; - -/** - * Hook that detects the user's motion preference. - * Implements MotionConfigSchema from @objectstack/spec v2.0.7. - * - * Respects the `prefers-reduced-motion` media query to provide - * accessible animation experiences. - * - * @example - * ```tsx - * function AnimatedCard() { - * const prefersReducedMotion = useReducedMotion(); - * - * return ( - *