diff --git a/docs/app/experiments/slider-marks.tsx b/docs/app/experiments/slider-marks.tsx index 3aca9f132..81cf3f6cd 100644 --- a/docs/app/experiments/slider-marks.tsx +++ b/docs/app/experiments/slider-marks.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import { Slider } from '@base_ui/react/Slider'; -import { useSliderContext } from '../../../packages/mui-base/src/Slider/Root/SliderContext'; +import { useSliderRootContext } from '../../../packages/mui-base/src/Slider/Root/SliderRootContext'; const STOPS = [ { @@ -33,7 +33,7 @@ function getSliderThumbAriaValueText(value: number) { // for "inverted track", the track/rail can be styled with CSS but a prop is needed to flip the "mark active" state function MarkWithLabel(props: { index: number; value: number; label: string; inverted?: boolean }) { const { index, value, label, inverted = false } = props; - const { direction, values } = useSliderContext(); + const { direction, values } = useSliderRootContext(); const isRtl = direction === 'rtl'; const isFilled = inverted ? value >= values[0] : values[0] >= value; return ( diff --git a/docs/app/experiments/slider-tooltip.tsx b/docs/app/experiments/slider-tooltip.tsx index 28d89d685..690be39d7 100644 --- a/docs/app/experiments/slider-tooltip.tsx +++ b/docs/app/experiments/slider-tooltip.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import { useTheme } from '@mui/system'; import { Slider } from '@base_ui/react/Slider'; import { Tooltip } from '@base_ui/react/Tooltip'; -import { useSliderContext } from '../../../packages/mui-base/src/Slider/Root/SliderContext'; +import { useSliderRootContext } from '../../../packages/mui-base/src/Slider/Root/SliderRootContext'; function useIsDarkMode() { const theme = useTheme(); @@ -74,7 +74,7 @@ export default function App() { const SliderMark = React.forwardRef(function SliderMark(props: any, ref: React.ForwardedRef) { const { index, style, ...otherProps } = props; - const { percentageValues } = useSliderContext(); + const { percentageValues } = useSliderRootContext(); const isFilled = percentageValues[0] >= index * 10; return ( .', + ); } + return context; } diff --git a/packages/mui-base/src/Checkbox/Root/CheckboxRootContext.ts b/packages/mui-base/src/Checkbox/Root/CheckboxRootContext.ts index 580c1816a..88bb016f5 100644 --- a/packages/mui-base/src/Checkbox/Root/CheckboxRootContext.ts +++ b/packages/mui-base/src/Checkbox/Root/CheckboxRootContext.ts @@ -4,14 +4,19 @@ import type { CheckboxRoot } from './CheckboxRoot'; export type CheckboxRootContext = CheckboxRoot.OwnerState; -export const CheckboxRootContext = React.createContext(null); +export const CheckboxRootContext = React.createContext(undefined); + +if (process.env.NODE_ENV !== 'production') { + CheckboxRootContext.displayName = 'CheckboxRootContext'; +} export function useCheckboxRootContext() { const context = React.useContext(CheckboxRootContext); - if (context === null) { + if (context === undefined) { throw new Error( - 'Base UI: Checkbox.Indicator must be placed inside the Checkbox.Root component.', + 'Base UI: CheckboxRootContext is missing. Checkbox parts must be placed within .', ); } + return context; } diff --git a/packages/mui-base/src/CheckboxGroup/Root/CheckboxGroupRootContext.ts b/packages/mui-base/src/CheckboxGroup/Root/CheckboxGroupRootContext.ts index 0c4b461c5..7e9295ace 100644 --- a/packages/mui-base/src/CheckboxGroup/Root/CheckboxGroupRootContext.ts +++ b/packages/mui-base/src/CheckboxGroup/Root/CheckboxGroupRootContext.ts @@ -9,12 +9,21 @@ export interface CheckboxGroupRootContext { parent: UseCheckboxGroupParent.ReturnValue; } -export const CheckboxGroupRootContext = React.createContext(null); +export const CheckboxGroupRootContext = React.createContext( + undefined, +); + +if (process.env.NODE_ENV !== 'production') { + CheckboxGroupRootContext.displayName = 'CheckboxGroupRootContext'; +} export function useCheckboxGroupRootContext(optional = true) { const context = React.useContext(CheckboxGroupRootContext); - if (context === null && !optional) { - throw new Error('Base UI: CheckboxGroupRootContext is not defined.'); + if (context === undefined && !optional) { + throw new Error( + 'Base UI: CheckboxGroupRootContext is missing. CheckboxGroup parts must be placed within .', + ); } + return context; } diff --git a/packages/mui-base/src/Collapsible/Panel/CollapsiblePanel.test.tsx b/packages/mui-base/src/Collapsible/Panel/CollapsiblePanel.test.tsx index 9302b381f..0bea82d66 100644 --- a/packages/mui-base/src/Collapsible/Panel/CollapsiblePanel.test.tsx +++ b/packages/mui-base/src/Collapsible/Panel/CollapsiblePanel.test.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { createRenderer } from '@mui/internal-test-utils'; import { Collapsible } from '@base_ui/react/Collapsible'; -import { CollapsibleRootContext } from '../Root/CollapsibleRootContext'; import { describeConformance } from '../../../test/describeConformance'; +import { CollapsibleRootContext } from '../Root/CollapsibleRootContext'; const contextValue: CollapsibleRootContext = { animated: false, diff --git a/packages/mui-base/src/Collapsible/Root/CollapsibleRootContext.ts b/packages/mui-base/src/Collapsible/Root/CollapsibleRootContext.ts index 98a7491ad..d19cffcb7 100644 --- a/packages/mui-base/src/Collapsible/Root/CollapsibleRootContext.ts +++ b/packages/mui-base/src/Collapsible/Root/CollapsibleRootContext.ts @@ -6,9 +6,7 @@ import type { CollapsibleRoot } from './CollapsibleRoot'; export interface CollapsibleRootContext extends useCollapsibleRoot.ReturnValue { ownerState: CollapsibleRoot.OwnerState; } -/** - * @ignore - internal component. - */ + export const CollapsibleRootContext = React.createContext( undefined, ); @@ -20,7 +18,10 @@ if (process.env.NODE_ENV !== 'production') { export function useCollapsibleRootContext() { const context = React.useContext(CollapsibleRootContext); if (context === undefined) { - throw new Error('useCollapsibleRootContext must be used inside a Collapsible component'); + throw new Error( + 'Base UI: CollapsibleRootContext is missing. Collapsible parts must be placed within .', + ); } + return context; } diff --git a/packages/mui-base/src/Collapsible/Trigger/CollapsibleTrigger.test.tsx b/packages/mui-base/src/Collapsible/Trigger/CollapsibleTrigger.test.tsx index 8f9ed3e74..289fc2969 100644 --- a/packages/mui-base/src/Collapsible/Trigger/CollapsibleTrigger.test.tsx +++ b/packages/mui-base/src/Collapsible/Trigger/CollapsibleTrigger.test.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { createRenderer } from '@mui/internal-test-utils'; import { Collapsible } from '@base_ui/react/Collapsible'; -import { CollapsibleRootContext } from '../Root/CollapsibleRootContext'; import { describeConformance } from '../../../test/describeConformance'; +import { CollapsibleRootContext } from '../Root/CollapsibleRootContext'; const contextValue: CollapsibleRootContext = { animated: false, diff --git a/packages/mui-base/src/Composite/List/CompositeListContext.ts b/packages/mui-base/src/Composite/List/CompositeListContext.ts index 07588d903..4f1358525 100644 --- a/packages/mui-base/src/Composite/List/CompositeListContext.ts +++ b/packages/mui-base/src/Composite/List/CompositeListContext.ts @@ -16,6 +16,10 @@ export const CompositeListContext = React.createContext ({ activeIndex, onActiveIndexChange }), [activeIndex, onActiveIndexChange], ); diff --git a/packages/mui-base/src/Composite/Root/CompositeRootContext.ts b/packages/mui-base/src/Composite/Root/CompositeRootContext.ts index 69648f910..f92f119c9 100644 --- a/packages/mui-base/src/Composite/Root/CompositeRootContext.ts +++ b/packages/mui-base/src/Composite/Root/CompositeRootContext.ts @@ -1,19 +1,26 @@ 'use client'; import * as React from 'react'; -export const CompositeRootContext = React.createContext(null); +export interface CompositeRootContext { + activeIndex: number; + onActiveIndexChange: (index: number) => void; +} + +export const CompositeRootContext = React.createContext( + undefined, +); + +if (process.env.NODE_ENV !== 'production') { + CompositeRootContext.displayName = 'CompositeRootContext'; +} export function useCompositeRootContext() { const context = React.useContext(CompositeRootContext); - if (context === null) { - throw new Error(' must be used within '); + if (context === undefined) { + throw new Error( + 'Base UI: CompositeRootContext is missing. Composite parts must be placed within .', + ); } - return context; -} -export namespace CompositeRootContext { - export interface Value { - activeIndex: number; - onActiveIndexChange: (index: number) => void; - } + return context; } diff --git a/packages/mui-base/src/Dialog/Root/DialogRootContext.ts b/packages/mui-base/src/Dialog/Root/DialogRootContext.ts index ade4da0cd..4514bc492 100644 --- a/packages/mui-base/src/Dialog/Root/DialogRootContext.ts +++ b/packages/mui-base/src/Dialog/Root/DialogRootContext.ts @@ -24,7 +24,10 @@ export const DialogRootContext = React.createContext.', + ); } + return context; } diff --git a/packages/mui-base/src/Field/Root/FieldRootContext.ts b/packages/mui-base/src/Field/Root/FieldRootContext.ts index d7966e262..9ea94220b 100644 --- a/packages/mui-base/src/Field/Root/FieldRootContext.ts +++ b/packages/mui-base/src/Field/Root/FieldRootContext.ts @@ -70,7 +70,9 @@ export function useFieldRootContext(optional = true) { const context = React.useContext(FieldRootContext); if (context.setControlId === NOOP && !optional) { - throw new Error('Base UI: Field components must be placed within .'); + throw new Error( + 'Base UI: FieldRootContext is missing. Field parts must be placed within .', + ); } return context; diff --git a/packages/mui-base/src/Form/Root/FormRootContext.ts b/packages/mui-base/src/Form/Root/FormRootContext.ts index 8eb9bf6da..35370255d 100644 --- a/packages/mui-base/src/Form/Root/FormRootContext.ts +++ b/packages/mui-base/src/Form/Root/FormRootContext.ts @@ -28,6 +28,10 @@ export const FormRootContext = React.createContext({ onClearErrors: () => {}, }); +if (process.env.NODE_ENV !== 'production') { + FormRootContext.displayName = 'FormRootContext'; +} + export function useFormRootContext() { return React.useContext(FormRootContext); } diff --git a/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItem.test.tsx b/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItem.test.tsx index c962d100d..9bfeb83b5 100644 --- a/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItem.test.tsx +++ b/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItem.test.tsx @@ -13,7 +13,7 @@ const testRootContext: MenuRootContext = { getPositionerProps: (p) => ({ ...p }), getTriggerProps: (p) => ({ ...p }), getItemProps: (p) => ({ ...p }), - parentContext: null, + parentContext: undefined, nested: false, triggerElement: null, setTriggerElement: () => {}, diff --git a/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItemContext.ts b/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItemContext.ts index beab8db3f..9d2f631fe 100644 --- a/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItemContext.ts +++ b/packages/mui-base/src/Menu/CheckboxItem/MenuCheckboxItemContext.ts @@ -13,7 +13,9 @@ export const MenuCheckboxItemContext = React.createContext.', + ); } return context; diff --git a/packages/mui-base/src/Menu/Group/MenuGroupContext.ts b/packages/mui-base/src/Menu/Group/MenuGroupContext.ts index b3c97d8a9..b4e46d8cc 100644 --- a/packages/mui-base/src/Menu/Group/MenuGroupContext.ts +++ b/packages/mui-base/src/Menu/Group/MenuGroupContext.ts @@ -12,7 +12,7 @@ if (process.env.NODE_ENV !== 'production') { export function useMenuGroupRootContext() { const context = React.useContext(MenuGroupContext); - if (context == null) { + if (context === undefined) { throw new Error('Base UI: Missing MenuGroupRootContext provider'); } diff --git a/packages/mui-base/src/Menu/Item/MenuItem.test.tsx b/packages/mui-base/src/Menu/Item/MenuItem.test.tsx index 1195d4f17..918d08d8f 100644 --- a/packages/mui-base/src/Menu/Item/MenuItem.test.tsx +++ b/packages/mui-base/src/Menu/Item/MenuItem.test.tsx @@ -13,7 +13,7 @@ const testRootContext: MenuRootContext = { getPositionerProps: (p) => ({ ...p }), getTriggerProps: (p) => ({ ...p }), getItemProps: (p) => ({ ...p }), - parentContext: null, + parentContext: undefined, nested: false, triggerElement: null, setTriggerElement: () => {}, diff --git a/packages/mui-base/src/Menu/Popup/MenuPopup.test.tsx b/packages/mui-base/src/Menu/Popup/MenuPopup.test.tsx index cf5904881..6c6542b65 100644 --- a/packages/mui-base/src/Menu/Popup/MenuPopup.test.tsx +++ b/packages/mui-base/src/Menu/Popup/MenuPopup.test.tsx @@ -10,7 +10,7 @@ const testRootContext: MenuRootContext = { getPositionerProps: (p) => ({ ...p }), getTriggerProps: (p) => ({ ...p }), getItemProps: (p) => ({ ...p }), - parentContext: null, + parentContext: undefined, nested: false, triggerElement: null, setTriggerElement: () => {}, diff --git a/packages/mui-base/src/Menu/Positioner/MenuPositioner.test.tsx b/packages/mui-base/src/Menu/Positioner/MenuPositioner.test.tsx index 70adbf142..2a89d5f0c 100644 --- a/packages/mui-base/src/Menu/Positioner/MenuPositioner.test.tsx +++ b/packages/mui-base/src/Menu/Positioner/MenuPositioner.test.tsx @@ -12,7 +12,7 @@ const testRootContext: MenuRootContext = { getPositionerProps: (p) => ({ ...p }), getTriggerProps: (p) => ({ ...p }), getItemProps: (p) => ({ ...p }), - parentContext: null, + parentContext: undefined, nested: false, triggerElement: null, setTriggerElement: () => {}, diff --git a/packages/mui-base/src/Menu/Positioner/MenuPositionerContext.ts b/packages/mui-base/src/Menu/Positioner/MenuPositionerContext.ts index 8e3ad8a1c..fa72df76e 100644 --- a/packages/mui-base/src/Menu/Positioner/MenuPositionerContext.ts +++ b/packages/mui-base/src/Menu/Positioner/MenuPositionerContext.ts @@ -16,7 +16,9 @@ export interface MenuPositionerContext { arrowStyles: React.CSSProperties; } -export const MenuPositionerContext = React.createContext(null); +export const MenuPositionerContext = React.createContext( + undefined, +); if (process.env.NODE_ENV !== 'production') { MenuPositionerContext.displayName = 'MenuPositionerContext'; @@ -24,8 +26,10 @@ if (process.env.NODE_ENV !== 'production') { export function useMenuPositionerContext() { const context = React.useContext(MenuPositionerContext); - if (context === null) { - throw new Error(' must be used within the component'); + if (context === undefined) { + throw new Error( + 'Base UI: MenuPositionerContext is missing. MenuPositioner parts must be placed within .', + ); } return context; } diff --git a/packages/mui-base/src/Menu/RadioGroup/MenuRadioGroupContext.ts b/packages/mui-base/src/Menu/RadioGroup/MenuRadioGroupContext.ts index 10ac8dc81..1b8332f8b 100644 --- a/packages/mui-base/src/Menu/RadioGroup/MenuRadioGroupContext.ts +++ b/packages/mui-base/src/Menu/RadioGroup/MenuRadioGroupContext.ts @@ -5,7 +5,9 @@ export interface MenuRadioGroupContext { setValue: (newValue: any, event: Event) => void; } -export const MenuRadioGroupContext = React.createContext(null); +export const MenuRadioGroupContext = React.createContext( + undefined, +); if (process.env.NODE_ENV !== 'production') { MenuRadioGroupContext.displayName = 'MenuRadioGroupContext'; @@ -13,8 +15,10 @@ if (process.env.NODE_ENV !== 'production') { export function useMenuRadioGroupContext() { const context = React.useContext(MenuRadioGroupContext); - if (context === null) { - throw new Error('useMenuRadioGroupContext must be used within a MenuRadioGroup'); + if (context === undefined) { + throw new Error( + 'Base UI: MenuRadioGroupContext is missing. MenuRadioGroup parts must be placed within .', + ); } return context; diff --git a/packages/mui-base/src/Menu/RadioItem/MenuRadioItem.test.tsx b/packages/mui-base/src/Menu/RadioItem/MenuRadioItem.test.tsx index ba44c1972..00f68560c 100644 --- a/packages/mui-base/src/Menu/RadioItem/MenuRadioItem.test.tsx +++ b/packages/mui-base/src/Menu/RadioItem/MenuRadioItem.test.tsx @@ -14,7 +14,7 @@ const testRootContext: MenuRootContext = { getPositionerProps: (p) => ({ ...p }), getTriggerProps: (p) => ({ ...p }), getItemProps: (p) => ({ ...p }), - parentContext: null, + parentContext: undefined, nested: false, triggerElement: null, setTriggerElement: () => {}, diff --git a/packages/mui-base/src/Menu/RadioItem/MenuRadioItemContext.ts b/packages/mui-base/src/Menu/RadioItem/MenuRadioItemContext.ts index 760b3618d..f40dc4894 100644 --- a/packages/mui-base/src/Menu/RadioItem/MenuRadioItemContext.ts +++ b/packages/mui-base/src/Menu/RadioItem/MenuRadioItemContext.ts @@ -10,10 +10,16 @@ export const MenuRadioItemContext = React.createContext.', + ); } return context; diff --git a/packages/mui-base/src/Menu/Root/MenuRootContext.ts b/packages/mui-base/src/Menu/Root/MenuRootContext.ts index a834e3da4..d00e0f939 100644 --- a/packages/mui-base/src/Menu/Root/MenuRootContext.ts +++ b/packages/mui-base/src/Menu/Root/MenuRootContext.ts @@ -6,23 +6,25 @@ export interface MenuRootContext extends useMenuRoot.ReturnValue { clickAndDragEnabled: boolean; disabled: boolean; nested: boolean; - parentContext: MenuRootContext | null; + parentContext: MenuRootContext | undefined; setClickAndDragEnabled: React.Dispatch>; typingRef: React.RefObject; } -export const MenuRootContext = React.createContext(null); +export const MenuRootContext = React.createContext(undefined); if (process.env.NODE_ENV !== 'production') { MenuRootContext.displayName = 'MenuRootContext'; } function useMenuRootContext(optional?: false): MenuRootContext; -function useMenuRootContext(optional: true): MenuRootContext | null; +function useMenuRootContext(optional: true): MenuRootContext | undefined; function useMenuRootContext(optional?: boolean) { const context = React.useContext(MenuRootContext); - if (context === null && !optional) { - throw new Error('Base UI: MenuRootContext is not defined.'); + if (context === undefined && !optional) { + throw new Error( + 'Base UI: MenuRootContext is missing. Menu parts must be placed within .', + ); } return context; diff --git a/packages/mui-base/src/Menu/SubmenuTrigger/SubmenuTrigger.tsx b/packages/mui-base/src/Menu/SubmenuTrigger/SubmenuTrigger.tsx index 4a32fdfde..9161e512f 100644 --- a/packages/mui-base/src/Menu/SubmenuTrigger/SubmenuTrigger.tsx +++ b/packages/mui-base/src/Menu/SubmenuTrigger/SubmenuTrigger.tsx @@ -36,7 +36,7 @@ const SubmenuTrigger = React.forwardRef(function SubmenuTriggerComponent( typingRef, } = useMenuRootContext(); - if (parentContext === null) { + if (parentContext === undefined) { throw new Error('Base UI: ItemTrigger must be placed in a nested Menu.'); } diff --git a/packages/mui-base/src/Menu/Trigger/MenuTrigger.test.tsx b/packages/mui-base/src/Menu/Trigger/MenuTrigger.test.tsx index 305d9ad81..48e67d7a0 100644 --- a/packages/mui-base/src/Menu/Trigger/MenuTrigger.test.tsx +++ b/packages/mui-base/src/Menu/Trigger/MenuTrigger.test.tsx @@ -12,7 +12,7 @@ const testRootContext: MenuRootContext = { getPositionerProps: (p) => ({ ...p }), getTriggerProps: (p) => ({ ...p }), getItemProps: (p) => ({ ...p }), - parentContext: null, + parentContext: undefined, nested: false, triggerElement: null, setTriggerElement: () => {}, diff --git a/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.test.tsx b/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.test.tsx index 2ca25b155..ad0800657 100644 --- a/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.test.tsx +++ b/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.test.tsx @@ -4,7 +4,7 @@ import { screen, fireEvent } from '@mui/internal-test-utils'; import { NumberField } from '@base_ui/react/NumberField'; import { createRenderer, describeConformance } from '#test-utils'; import { CHANGE_VALUE_TICK_DELAY, START_AUTO_CHANGE_DELAY } from '../utils/constants'; -import { NumberFieldContext } from '../Root/NumberFieldContext'; +import { NumberFieldRootContext } from '../Root/NumberFieldRootContext'; const testContext = { getDecrementButtonProps: (externalProps) => externalProps, @@ -15,7 +15,7 @@ const testContext = { invalid: false, readOnly: false, }, -} as NumberFieldContext; +} as NumberFieldRootContext; describe('', () => { const { render, clock } = createRenderer(); @@ -24,7 +24,9 @@ describe('', () => { refInstanceof: window.HTMLButtonElement, render(node) { return render( - {node}, + + {node} + , ); }, })); diff --git a/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.tsx b/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.tsx index 4d9c71cf1..049500f80 100644 --- a/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.tsx +++ b/packages/mui-base/src/NumberField/Decrement/NumberFieldDecrement.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { useNumberFieldContext } from '../Root/NumberFieldContext'; +import { useNumberFieldRootContext } from '../Root/NumberFieldRootContext'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; import type { NumberFieldRoot } from '../Root/NumberFieldRoot'; import { BaseUIComponentProps } from '../../utils/types'; @@ -23,7 +23,7 @@ const NumberFieldDecrement = React.forwardRef(function NumberFieldDecrement( ) { const { render, className, ...otherProps } = props; - const { getDecrementButtonProps, ownerState } = useNumberFieldContext('Decrement'); + const { getDecrementButtonProps, ownerState } = useNumberFieldRootContext(); const { renderElement } = useComponentRenderer({ propGetter: getDecrementButtonProps, diff --git a/packages/mui-base/src/NumberField/Group/NumberFieldGroup.test.tsx b/packages/mui-base/src/NumberField/Group/NumberFieldGroup.test.tsx index bda5d52f1..167d3c78b 100644 --- a/packages/mui-base/src/NumberField/Group/NumberFieldGroup.test.tsx +++ b/packages/mui-base/src/NumberField/Group/NumberFieldGroup.test.tsx @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { screen } from '@mui/internal-test-utils'; import { NumberField } from '@base_ui/react/NumberField'; import { createRenderer, describeConformance } from '#test-utils'; -import { NumberFieldContext } from '../Root/NumberFieldContext'; +import { NumberFieldRootContext } from '../Root/NumberFieldRootContext'; const testContext = { getGroupProps: (externalProps) => ({ role: 'group', ...externalProps }), @@ -14,7 +14,7 @@ const testContext = { invalid: false, readOnly: false, }, -} as NumberFieldContext; +} as NumberFieldRootContext; describe('', () => { const { render } = createRenderer(); @@ -23,7 +23,9 @@ describe('', () => { refInstanceof: window.HTMLDivElement, render(node) { return render( - {node}, + + {node} + , ); }, })); diff --git a/packages/mui-base/src/NumberField/Group/NumberFieldGroup.tsx b/packages/mui-base/src/NumberField/Group/NumberFieldGroup.tsx index e35913dd9..28d0f2589 100644 --- a/packages/mui-base/src/NumberField/Group/NumberFieldGroup.tsx +++ b/packages/mui-base/src/NumberField/Group/NumberFieldGroup.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { useNumberFieldContext } from '../Root/NumberFieldContext'; +import { useNumberFieldRootContext } from '../Root/NumberFieldRootContext'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; import type { NumberFieldRoot } from '../Root/NumberFieldRoot'; import type { BaseUIComponentProps } from '../../utils/types'; @@ -23,7 +23,7 @@ const NumberFieldGroup = React.forwardRef(function NumberFieldGroup( ) { const { render, className, ...otherProps } = props; - const { getGroupProps, ownerState } = useNumberFieldContext('Group'); + const { getGroupProps, ownerState } = useNumberFieldRootContext(); const { renderElement } = useComponentRenderer({ propGetter: getGroupProps, diff --git a/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.test.tsx b/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.test.tsx index dc90a6857..5b18c6963 100644 --- a/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.test.tsx +++ b/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.test.tsx @@ -4,7 +4,7 @@ import { screen, fireEvent } from '@mui/internal-test-utils'; import { NumberField } from '@base_ui/react/NumberField'; import { createRenderer, describeConformance } from '#test-utils'; import { CHANGE_VALUE_TICK_DELAY, START_AUTO_CHANGE_DELAY } from '../utils/constants'; -import { NumberFieldContext } from '../Root/NumberFieldContext'; +import { NumberFieldRootContext } from '../Root/NumberFieldRootContext'; const testContext = { getIncrementButtonProps: (externalProps) => externalProps, @@ -15,7 +15,7 @@ const testContext = { invalid: false, readOnly: false, }, -} as NumberFieldContext; +} as NumberFieldRootContext; describe('', () => { const { render, clock } = createRenderer(); @@ -24,7 +24,9 @@ describe('', () => { refInstanceof: window.HTMLButtonElement, render(node) { return render( - {node}, + + {node} + , ); }, })); diff --git a/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.tsx b/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.tsx index 6974a4860..addb79544 100644 --- a/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.tsx +++ b/packages/mui-base/src/NumberField/Increment/NumberFieldIncrement.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { useNumberFieldContext } from '../Root/NumberFieldContext'; +import { useNumberFieldRootContext } from '../Root/NumberFieldRootContext'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; import type { NumberFieldRoot } from '../Root/NumberFieldRoot'; import type { BaseUIComponentProps } from '../../utils/types'; @@ -23,7 +23,7 @@ const NumberFieldIncrement = React.forwardRef(function NumberFieldIncrement( ) { const { render, className, ...otherProps } = props; - const { getIncrementButtonProps, ownerState } = useNumberFieldContext('Increment'); + const { getIncrementButtonProps, ownerState } = useNumberFieldRootContext(); const { renderElement } = useComponentRenderer({ propGetter: getIncrementButtonProps, diff --git a/packages/mui-base/src/NumberField/Input/NumberFieldInput.test.tsx b/packages/mui-base/src/NumberField/Input/NumberFieldInput.test.tsx index 46ef5531e..ffa6e1348 100644 --- a/packages/mui-base/src/NumberField/Input/NumberFieldInput.test.tsx +++ b/packages/mui-base/src/NumberField/Input/NumberFieldInput.test.tsx @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { act, screen, fireEvent } from '@mui/internal-test-utils'; import { NumberField } from '@base_ui/react/NumberField'; import { createRenderer, describeConformance } from '#test-utils'; -import { NumberFieldContext } from '../Root/NumberFieldContext'; +import { NumberFieldRootContext } from '../Root/NumberFieldRootContext'; const testContext = { getInputProps: (externalProps) => externalProps, @@ -14,7 +14,7 @@ const testContext = { invalid: false, readOnly: false, }, -} as NumberFieldContext; +} as NumberFieldRootContext; describe('', () => { const { render } = createRenderer(); @@ -23,7 +23,9 @@ describe('', () => { refInstanceof: window.HTMLInputElement, render(node) { return render( - {node}, + + {node} + , ); }, })); diff --git a/packages/mui-base/src/NumberField/Input/NumberFieldInput.tsx b/packages/mui-base/src/NumberField/Input/NumberFieldInput.tsx index d714fcedb..8638b289b 100644 --- a/packages/mui-base/src/NumberField/Input/NumberFieldInput.tsx +++ b/packages/mui-base/src/NumberField/Input/NumberFieldInput.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { useNumberFieldContext } from '../Root/NumberFieldContext'; +import { useNumberFieldRootContext } from '../Root/NumberFieldRootContext'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; import { useForkRef } from '../../utils/useForkRef'; import type { NumberFieldRoot } from '../Root/NumberFieldRoot'; @@ -24,7 +24,7 @@ const NumberFieldInput = React.forwardRef(function NumberFieldInput( ) { const { render, className, ...otherProps } = props; - const { getInputProps, inputRef, ownerState } = useNumberFieldContext('Input'); + const { getInputProps, inputRef, ownerState } = useNumberFieldRootContext(); const mergedInputRef = useForkRef(forwardedRef, inputRef); diff --git a/packages/mui-base/src/NumberField/Root/NumberFieldContext.ts b/packages/mui-base/src/NumberField/Root/NumberFieldContext.ts deleted file mode 100644 index 3dbd2becb..000000000 --- a/packages/mui-base/src/NumberField/Root/NumberFieldContext.ts +++ /dev/null @@ -1,24 +0,0 @@ -'use client'; -import * as React from 'react'; -import type { UseNumberFieldRoot } from './useNumberFieldRoot'; -import type { NumberFieldRoot } from './NumberFieldRoot'; - -export interface NumberFieldContext extends UseNumberFieldRoot.ReturnValue { - ownerState: NumberFieldRoot.OwnerState; -} - -export const NumberFieldContext = React.createContext(null); - -if (process.env.NODE_ENV !== 'production') { - NumberFieldContext.displayName = 'NumberFieldContext'; -} - -type Part = 'Group' | 'Input' | 'Increment' | 'Decrement' | 'ScrubArea' | 'ScrubAreaCursor'; - -export function useNumberFieldContext(part: Part) { - const context = React.useContext(NumberFieldContext); - if (context === null) { - throw new Error(`Base UI: NumberField${part} is not placed inside the NumberField component.`); - } - return context; -} diff --git a/packages/mui-base/src/NumberField/Root/NumberFieldRoot.tsx b/packages/mui-base/src/NumberField/Root/NumberFieldRoot.tsx index fb5bce021..1e8132eca 100644 --- a/packages/mui-base/src/NumberField/Root/NumberFieldRoot.tsx +++ b/packages/mui-base/src/NumberField/Root/NumberFieldRoot.tsx @@ -1,7 +1,7 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { NumberFieldContext } from './NumberFieldContext'; +import { NumberFieldRootContext } from './NumberFieldRootContext'; import { UseNumberFieldRoot, useNumberFieldRoot } from './useNumberFieldRoot'; import { useFieldRootContext } from '../../Field/Root/FieldRootContext'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; @@ -91,9 +91,9 @@ const NumberFieldRoot = React.forwardRef(function NumberFieldRoot( }); return ( - + {renderElement()} - + ); }); diff --git a/packages/mui-base/src/NumberField/Root/NumberFieldRootContext.ts b/packages/mui-base/src/NumberField/Root/NumberFieldRootContext.ts new file mode 100644 index 000000000..2da27b527 --- /dev/null +++ b/packages/mui-base/src/NumberField/Root/NumberFieldRootContext.ts @@ -0,0 +1,27 @@ +'use client'; +import * as React from 'react'; +import type { UseNumberFieldRoot } from './useNumberFieldRoot'; +import type { NumberFieldRoot } from './NumberFieldRoot'; + +export interface NumberFieldRootContext extends UseNumberFieldRoot.ReturnValue { + ownerState: NumberFieldRoot.OwnerState; +} + +export const NumberFieldRootContext = React.createContext( + undefined, +); + +if (process.env.NODE_ENV !== 'production') { + NumberFieldRootContext.displayName = 'NumberFieldRootContext'; +} + +export function useNumberFieldRootContext() { + const context = React.useContext(NumberFieldRootContext); + if (context === undefined) { + throw new Error( + 'Base UI: NumberFieldRootContext is missing. NumberField parts must be placed within .', + ); + } + + return context; +} diff --git a/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.test.tsx b/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.test.tsx index 26a693730..05b9ba8da 100644 --- a/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.test.tsx +++ b/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.test.tsx @@ -4,7 +4,7 @@ import { screen, waitFor } from '@mui/internal-test-utils'; import { NumberField } from '@base_ui/react/NumberField'; import { createRenderer, describeConformance } from '#test-utils'; import { isWebKit } from '../../utils/detectBrowser'; -import { NumberFieldContext } from '../Root/NumberFieldContext'; +import { NumberFieldRootContext } from '../Root/NumberFieldRootContext'; function createPointerMoveEvent({ movementX = 0, movementY = 0 }) { return new PointerEvent('pointermove', { @@ -23,7 +23,7 @@ const testContext = { invalid: false, readOnly: false, }, -} as NumberFieldContext; +} as NumberFieldRootContext; describe('', () => { const { render } = createRenderer(); @@ -32,7 +32,9 @@ describe('', () => { refInstanceof: window.HTMLSpanElement, render(node) { return render( - {node}, + + {node} + , ); }, })); diff --git a/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.tsx b/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.tsx index e6823be8f..8ed06f68d 100644 --- a/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.tsx +++ b/packages/mui-base/src/NumberField/ScrubArea/NumberFieldScrubArea.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import type { BaseUIComponentProps } from '../../utils/types'; -import { useNumberFieldContext } from '../Root/NumberFieldContext'; +import { useNumberFieldRootContext } from '../Root/NumberFieldRootContext'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; import { useForkRef } from '../../utils/useForkRef'; import type { NumberFieldRoot } from '../Root/NumberFieldRoot'; @@ -32,7 +32,7 @@ const NumberFieldScrubArea = React.forwardRef(function NumberFieldScrubArea( } = props; const { getScrubAreaProps, scrubAreaRef, scrubHandleRef, ownerState } = - useNumberFieldContext('ScrubArea'); + useNumberFieldRootContext(); React.useImperativeHandle(scrubHandleRef, () => ({ direction, diff --git a/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.test.tsx b/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.test.tsx index de3ef46f0..72d956b20 100644 --- a/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.test.tsx +++ b/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.test.tsx @@ -4,7 +4,7 @@ import { screen } from '@mui/internal-test-utils'; import { NumberField } from '@base_ui/react/NumberField'; import { createRenderer, describeConformance } from '#test-utils'; import { isWebKit } from '../../utils/detectBrowser'; -import { NumberFieldContext } from '../Root/NumberFieldContext'; +import { NumberFieldRootContext } from '../Root/NumberFieldRootContext'; const testContext = { getScrubAreaCursorProps: (externalProps) => externalProps, @@ -16,7 +16,7 @@ const testContext = { invalid: false, readOnly: false, }, -} as NumberFieldContext; +} as NumberFieldRootContext; describe('', () => { const { render } = createRenderer(); @@ -30,7 +30,9 @@ describe('', () => { refInstanceof: window.HTMLSpanElement, render(node) { return render( - {node}, + + {node} + , ); }, })); diff --git a/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.tsx b/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.tsx index aea53c103..fcf17c3c3 100644 --- a/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.tsx +++ b/packages/mui-base/src/NumberField/ScrubAreaCursor/NumberFieldScrubAreaCursor.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; -import { useNumberFieldContext } from '../Root/NumberFieldContext'; +import { useNumberFieldRootContext } from '../Root/NumberFieldRootContext'; import { isWebKit } from '../../utils/detectBrowser'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; import { useForkRef } from '../../utils/useForkRef'; @@ -28,7 +28,7 @@ const NumberFieldScrubAreaCursor = React.forwardRef(function NumberFieldScrubAre const { render, className, ...otherProps } = props; const { isScrubbing, scrubAreaCursorRef, ownerState, getScrubAreaCursorProps } = - useNumberFieldContext('ScrubAreaCursor'); + useNumberFieldRootContext(); const [element, setElement] = React.useState(null); diff --git a/packages/mui-base/src/Popover/Positioner/PopoverPositionerContext.ts b/packages/mui-base/src/Popover/Positioner/PopoverPositionerContext.ts index 073694c62..ff3eaae71 100644 --- a/packages/mui-base/src/Popover/Positioner/PopoverPositionerContext.ts +++ b/packages/mui-base/src/Popover/Positioner/PopoverPositionerContext.ts @@ -10,14 +10,21 @@ export interface PopoverPositionerContext { arrowStyles: React.CSSProperties; } -export const PopoverPositionerContext = React.createContext(null); +export const PopoverPositionerContext = React.createContext( + undefined, +); + +if (process.env.NODE_ENV !== 'production') { + PopoverPositionerContext.displayName = 'PopoverPositionerContext'; +} export function usePopoverPositionerContext() { const context = React.useContext(PopoverPositionerContext); - if (context === null) { + if (context === undefined) { throw new Error( - ' and must be used within the component', + 'Base UI: PopoverPositionerContext is missing. PopoverPositioner parts must be placed within .', ); } + return context; } diff --git a/packages/mui-base/src/Popover/Root/PopoverRootContext.ts b/packages/mui-base/src/Popover/Root/PopoverRootContext.ts index a6f621d8a..666a129a9 100644 --- a/packages/mui-base/src/Popover/Root/PopoverRootContext.ts +++ b/packages/mui-base/src/Popover/Root/PopoverRootContext.ts @@ -28,12 +28,19 @@ export interface PopoverRootContext { getRootPopupProps: (externalProps?: GenericHTMLProps) => GenericHTMLProps; } -export const PopoverRootContext = React.createContext(null); +export const PopoverRootContext = React.createContext(undefined); + +if (process.env.NODE_ENV !== 'production') { + PopoverRootContext.displayName = 'PopoverRootContext'; +} export function usePopoverRootContext() { const context = React.useContext(PopoverRootContext); - if (context === null) { - throw new Error('Popover components must be used within the component'); + if (context === undefined) { + throw new Error( + 'Base UI: PopoverRootContext is missing. Popover parts must be placed within .', + ); } + return context; } diff --git a/packages/mui-base/src/PreviewCard/Positioner/PreviewCardPositionerContext.ts b/packages/mui-base/src/PreviewCard/Positioner/PreviewCardPositionerContext.ts index 842819d6e..3d096866a 100644 --- a/packages/mui-base/src/PreviewCard/Positioner/PreviewCardPositionerContext.ts +++ b/packages/mui-base/src/PreviewCard/Positioner/PreviewCardPositionerContext.ts @@ -10,15 +10,21 @@ export interface PreviewCardPositionerContext { arrowStyles: React.CSSProperties; } -export const PreviewCardPositionerContext = - React.createContext(null); +export const PreviewCardPositionerContext = React.createContext< + PreviewCardPositionerContext | undefined +>(undefined); + +if (process.env.NODE_ENV !== 'production') { + PreviewCardPositionerContext.displayName = 'PreviewCardPositionerContext'; +} export function usePreviewCardPositionerContext() { const context = React.useContext(PreviewCardPositionerContext); - if (context === null) { + if (context === undefined) { throw new Error( 'Base UI: and must be used within the component', ); } + return context; } diff --git a/packages/mui-base/src/PreviewCard/Root/PreviewCardContext.ts b/packages/mui-base/src/PreviewCard/Root/PreviewCardContext.ts index 4e87ed603..337c14021 100644 --- a/packages/mui-base/src/PreviewCard/Root/PreviewCardContext.ts +++ b/packages/mui-base/src/PreviewCard/Root/PreviewCardContext.ts @@ -22,12 +22,21 @@ export interface PreviewCardRootContext { popupRef: React.RefObject; } -export const PreviewCardRootContext = React.createContext(null); +export const PreviewCardRootContext = React.createContext( + undefined, +); + +if (process.env.NODE_ENV !== 'production') { + PreviewCardRootContext.displayName = 'PreviewCardRootContext'; +} export function usePreviewCardRootContext() { const context = React.useContext(PreviewCardRootContext); - if (context === null) { - throw new Error('PreviewCard components must be used within the component'); + if (context === undefined) { + throw new Error( + 'Base UI: PreviewCardRootContext is missing. PreviewCard parts must be placed within .', + ); } + return context; } diff --git a/packages/mui-base/src/Progress/Root/ProgressRootContext.tsx b/packages/mui-base/src/Progress/Root/ProgressRootContext.tsx index f48eb17bc..029373389 100644 --- a/packages/mui-base/src/Progress/Root/ProgressRootContext.tsx +++ b/packages/mui-base/src/Progress/Root/ProgressRootContext.tsx @@ -19,7 +19,10 @@ if (process.env.NODE_ENV !== 'production') { export function useProgressRootContext() { const context = React.useContext(ProgressRootContext); if (context === undefined) { - throw new Error('useProgressContext must be used inside a Progress component'); + throw new Error( + 'Base UI: ProgressRootContext is missing. Progress parts must be placed within .', + ); } + return context; } diff --git a/packages/mui-base/src/Radio/Root/RadioRootContext.ts b/packages/mui-base/src/Radio/Root/RadioRootContext.ts index 512fd2fed..b419b765d 100644 --- a/packages/mui-base/src/Radio/Root/RadioRootContext.ts +++ b/packages/mui-base/src/Radio/Root/RadioRootContext.ts @@ -8,12 +8,19 @@ export interface RadioRootContext { required: boolean; } -export const RadioRootContext = React.createContext(null); +export const RadioRootContext = React.createContext(undefined); + +if (process.env.NODE_ENV !== 'production') { + RadioRootContext.displayName = 'RadioRootContext'; +} export function useRadioRootContext() { const value = React.useContext(RadioRootContext); - if (value === null) { - throw new Error('Base UI: must be used within '); + if (value === undefined) { + throw new Error( + 'Base UI: RadioRootContext is missing. Radio parts must be placed within .', + ); } + return value; } diff --git a/packages/mui-base/src/RadioGroup/Root/RadioGroupRootContext.ts b/packages/mui-base/src/RadioGroup/Root/RadioGroupRootContext.ts index 2aef2556e..73fe30970 100644 --- a/packages/mui-base/src/RadioGroup/Root/RadioGroupRootContext.ts +++ b/packages/mui-base/src/RadioGroup/Root/RadioGroupRootContext.ts @@ -24,6 +24,10 @@ export const RadioGroupRootContext = React.createContext( setTouched: NOOP, }); +if (process.env.NODE_ENV !== 'production') { + RadioGroupRootContext.displayName = 'RadioGroupRootContext'; +} + export function useRadioGroupRootContext() { return React.useContext(RadioGroupRootContext); } diff --git a/packages/mui-base/src/Slider/Control/SliderControl.test.tsx b/packages/mui-base/src/Slider/Control/SliderControl.test.tsx index 6fd286664..14c3b7981 100644 --- a/packages/mui-base/src/Slider/Control/SliderControl.test.tsx +++ b/packages/mui-base/src/Slider/Control/SliderControl.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import { Slider } from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; -import type { SliderRoot } from '../Root/SliderRoot'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Control/SliderControl.tsx b/packages/mui-base/src/Slider/Control/SliderControl.tsx index 3622e1692..6d4cb09d8 100644 --- a/packages/mui-base/src/Slider/Control/SliderControl.tsx +++ b/packages/mui-base/src/Slider/Control/SliderControl.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import type { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { sliderStyleHookMapping } from '../Root/styleHooks'; import type { SliderRoot } from '../Root/SliderRoot'; import { useSliderControl } from './useSliderControl'; @@ -39,7 +39,7 @@ const SliderControl = React.forwardRef(function SliderControl( setValueState, step, thumbRefs, - } = useSliderContext(); + } = useSliderRootContext(); const { getRootProps } = useSliderControl({ areValuesEqual, diff --git a/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx b/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx index 658c9a54f..842d83fd7 100644 --- a/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx +++ b/packages/mui-base/src/Slider/Indicator/SliderIndicator.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import { Slider } from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; -import type { SliderRoot } from '../Root/SliderRoot'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx b/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx index e28914e3f..aec14a707 100644 --- a/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx +++ b/packages/mui-base/src/Slider/Indicator/SliderIndicator.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import type { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { sliderStyleHookMapping } from '../Root/styleHooks'; import type { SliderRoot } from '../Root/SliderRoot'; import { useSliderIndicator } from './useSliderIndicator'; @@ -24,7 +24,7 @@ const SliderIndicator = React.forwardRef(function SliderIndicator( const { render, className, ...otherProps } = props; const { axis, direction, disabled, orientation, ownerState, percentageValues } = - useSliderContext(); + useSliderRootContext(); const { getRootProps } = useSliderIndicator({ axis, diff --git a/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx b/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx index 500877d60..a223875a0 100644 --- a/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx +++ b/packages/mui-base/src/Slider/Output/SliderOutput.test.tsx @@ -2,11 +2,10 @@ import * as React from 'react'; import { expect } from 'chai'; import { Slider } from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -import type { SliderRoot } from '../Root/SliderRoot'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -60,7 +59,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLOutputElement, diff --git a/packages/mui-base/src/Slider/Output/SliderOutput.tsx b/packages/mui-base/src/Slider/Output/SliderOutput.tsx index a2d80a44e..e2a306cfc 100644 --- a/packages/mui-base/src/Slider/Output/SliderOutput.tsx +++ b/packages/mui-base/src/Slider/Output/SliderOutput.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import type { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { sliderStyleHookMapping } from '../Root/styleHooks'; import type { SliderRoot } from '../Root/SliderRoot'; import { useSliderOutput } from './useSliderOutput'; @@ -23,7 +23,7 @@ const SliderOutput = React.forwardRef(function SliderOutput( ) { const { render, className, ...otherProps } = props; - const { inputIdMap, ownerState, values } = useSliderContext(); + const { inputIdMap, ownerState, values } = useSliderRootContext(); const { getRootProps } = useSliderOutput({ inputIdMap, diff --git a/packages/mui-base/src/Slider/Root/SliderContext.tsx b/packages/mui-base/src/Slider/Root/SliderContext.tsx deleted file mode 100644 index 33cb14bfe..000000000 --- a/packages/mui-base/src/Slider/Root/SliderContext.tsx +++ /dev/null @@ -1,20 +0,0 @@ -'use client'; -import * as React from 'react'; -import type { SliderRoot } from './SliderRoot'; - -/** - * @ignore - internal component. - */ -export const SliderContext = React.createContext(undefined); - -if (process.env.NODE_ENV !== 'production') { - SliderContext.displayName = 'SliderContext'; -} - -export function useSliderContext() { - const context = React.useContext(SliderContext); - if (context === undefined) { - throw new Error('useSliderContext must be used inside a Slider component'); - } - return context; -} diff --git a/packages/mui-base/src/Slider/Root/SliderRoot.tsx b/packages/mui-base/src/Slider/Root/SliderRoot.tsx index 274855b2a..0346f83f6 100644 --- a/packages/mui-base/src/Slider/Root/SliderRoot.tsx +++ b/packages/mui-base/src/Slider/Root/SliderRoot.tsx @@ -7,8 +7,9 @@ import type { FieldRoot } from '../../Field/Root/FieldRoot'; import { CompositeList } from '../../Composite/List/CompositeList'; import { sliderStyleHookMapping } from './styleHooks'; import { useSliderRoot } from './useSliderRoot'; -import { SliderContext } from './SliderContext'; +import { SliderRootContext } from './SliderRootContext'; import { useFieldRootContext } from '../../Field/Root/FieldRootContext'; + /** * * Demos: @@ -104,18 +105,13 @@ const SliderRoot = React.forwardRef(function SliderRoot( }); return ( - + {renderElement()} - + ); }); export namespace SliderRoot { - export interface Context - extends Omit { - ownerState: OwnerState; - } - export interface OwnerState extends FieldRoot.OwnerState { /** * The index of the active thumb. diff --git a/packages/mui-base/src/Slider/Root/SliderRootContext.ts b/packages/mui-base/src/Slider/Root/SliderRootContext.ts new file mode 100644 index 000000000..60e7e613a --- /dev/null +++ b/packages/mui-base/src/Slider/Root/SliderRootContext.ts @@ -0,0 +1,24 @@ +'use client'; +import * as React from 'react'; +import type { SliderRoot } from './SliderRoot'; +import type { useSliderRoot } from './useSliderRoot'; + +export interface SliderRootContext extends Omit { + ownerState: SliderRoot.OwnerState; +} + +export const SliderRootContext = React.createContext(undefined); + +if (process.env.NODE_ENV !== 'production') { + SliderRootContext.displayName = 'SliderRootContext'; +} + +export function useSliderRootContext() { + const context = React.useContext(SliderRootContext); + if (context === undefined) { + throw new Error( + 'Base UI: SliderRootContext is missing. Slider parts must be placed within .', + ); + } + return context; +} diff --git a/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx b/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx index ac6512002..c6d8a78e3 100644 --- a/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx +++ b/packages/mui-base/src/Slider/Thumb/SliderThumb.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import { Slider } from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -import type { SliderRoot } from '../Root/SliderRoot'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx b/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx index c9dc22214..06d8600a8 100644 --- a/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx +++ b/packages/mui-base/src/Slider/Thumb/SliderThumb.tsx @@ -7,7 +7,7 @@ import { resolveClassName } from '../../utils/resolveClassName'; import { BaseUIComponentProps } from '../../utils/types'; import { useForkRef } from '../../utils/useForkRef'; import type { SliderRoot } from '../Root/SliderRoot'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import { useSliderThumb } from './useSliderThumb'; import { isReactVersionAtLeast } from '../../utils/reactVersion'; @@ -70,7 +70,7 @@ const SliderThumb = React.forwardRef(function SliderThumb( step, tabIndex, values, - } = useSliderContext(); + } = useSliderRootContext(); let renderPropRef = null; if (typeof render !== 'function') { diff --git a/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx b/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx index 88165fc91..bfbda1262 100644 --- a/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx +++ b/packages/mui-base/src/Slider/Track/SliderTrack.test.tsx @@ -1,11 +1,10 @@ import * as React from 'react'; import { Slider } from '@base_ui/react/Slider'; import { createRenderer, describeConformance } from '#test-utils'; -import { SliderContext } from '../Root/SliderContext'; +import { SliderRootContext } from '../Root/SliderRootContext'; import { NOOP } from '../../utils/noop'; -import type { SliderRoot } from '../Root/SliderRoot'; -const testRootContext: SliderRoot.Context = { +const testRootContext: SliderRootContext = { active: -1, areValuesEqual: () => true, axis: 'horizontal', @@ -59,7 +58,7 @@ describe('', () => { describeConformance(, () => ({ render: (node) => { return render( - {node}, + {node}, ); }, refInstanceof: window.HTMLSpanElement, diff --git a/packages/mui-base/src/Slider/Track/SliderTrack.tsx b/packages/mui-base/src/Slider/Track/SliderTrack.tsx index 7fa0de221..4f6c42655 100644 --- a/packages/mui-base/src/Slider/Track/SliderTrack.tsx +++ b/packages/mui-base/src/Slider/Track/SliderTrack.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { BaseUIComponentProps } from '../../utils/types'; import { useComponentRenderer } from '../../utils/useComponentRenderer'; -import { useSliderContext } from '../Root/SliderContext'; +import { useSliderRootContext } from '../Root/SliderRootContext'; import type { SliderRoot } from '../Root/SliderRoot'; import { sliderStyleHookMapping } from '../Root/styleHooks'; /** @@ -22,7 +22,7 @@ const SliderTrack = React.forwardRef(function SliderTrack( ) { const { render, className, ...otherProps } = props; - const { ownerState } = useSliderContext(); + const { ownerState } = useSliderRootContext(); const { renderElement } = useComponentRenderer({ render: render ?? 'span', diff --git a/packages/mui-base/src/Switch/Root/SwitchRootContext.ts b/packages/mui-base/src/Switch/Root/SwitchRootContext.ts index 3804b912d..ab61d0653 100644 --- a/packages/mui-base/src/Switch/Root/SwitchRootContext.ts +++ b/packages/mui-base/src/Switch/Root/SwitchRootContext.ts @@ -5,10 +5,16 @@ export type SwitchRootContext = SwitchRoot.OwnerState; export const SwitchRootContext = React.createContext(undefined); +if (process.env.NODE_ENV !== 'production') { + SwitchRootContext.displayName = 'SwitchRootContext'; +} + export function useSwitchRootContext() { const context = React.useContext(SwitchRootContext); if (context === undefined) { - throw new Error('useSwitchRootContext must be used within a SwitchRootProvider'); + throw new Error( + 'Base UI: SwitchRootContext is missing. Switch parts must be placed within .', + ); } return context; diff --git a/packages/mui-base/src/Tabs/Root/TabsRootContext.ts b/packages/mui-base/src/Tabs/Root/TabsRootContext.ts index ea4d9101c..ac011c009 100644 --- a/packages/mui-base/src/Tabs/Root/TabsRootContext.ts +++ b/packages/mui-base/src/Tabs/Root/TabsRootContext.ts @@ -46,7 +46,7 @@ export interface TabsRootContext { /** * @ignore - internal component. */ -const TabsRootContext = React.createContext(null); +const TabsRootContext = React.createContext(undefined); if (process.env.NODE_ENV !== 'production') { TabsRootContext.displayName = 'TabsRootContext'; @@ -54,8 +54,10 @@ if (process.env.NODE_ENV !== 'production') { export function useTabsRootContext() { const context = React.useContext(TabsRootContext); - if (context == null) { - throw new Error('Base UI: No TabsRootContext provided'); + if (context === undefined) { + throw new Error( + 'Base UI: TabsRootContext is missing. Tabs parts must be placed within .', + ); } return context; diff --git a/packages/mui-base/src/Tabs/TabsList/TabsListContext.ts b/packages/mui-base/src/Tabs/TabsList/TabsListContext.ts index 9b2833529..fa31ac8a9 100644 --- a/packages/mui-base/src/Tabs/TabsList/TabsListContext.ts +++ b/packages/mui-base/src/Tabs/TabsList/TabsListContext.ts @@ -9,10 +9,16 @@ export interface TabsListContext { export const TabsListContext = React.createContext(undefined); +if (process.env.NODE_ENV !== 'production') { + TabsListContext.displayName = 'TabsListContext'; +} + export function useTabsListContext() { const context = React.useContext(TabsListContext); if (context === undefined) { - throw new Error('useTabsListContext must be used within a TabsList component'); + throw new Error( + 'Base UI: TabsListContext is missing. TabsList parts must be placed within .', + ); } return context; diff --git a/packages/mui-base/src/Tooltip/Positioner/TooltipPositionerContext.ts b/packages/mui-base/src/Tooltip/Positioner/TooltipPositionerContext.ts index 6792c3cb5..f3b1dab4c 100644 --- a/packages/mui-base/src/Tooltip/Positioner/TooltipPositionerContext.ts +++ b/packages/mui-base/src/Tooltip/Positioner/TooltipPositionerContext.ts @@ -11,13 +11,19 @@ export interface TooltipPositionerContext { arrowStyles: React.CSSProperties; } -export const TooltipPositionerContext = React.createContext(null); +export const TooltipPositionerContext = React.createContext( + undefined, +); + +if (process.env.NODE_ENV !== 'production') { + TooltipPositionerContext.displayName = 'TooltipPositionerContext'; +} export function useTooltipPositionerContext() { const context = React.useContext(TooltipPositionerContext); - if (context === null) { + if (context === undefined) { throw new Error( - ' and must be used within the component', + 'Base UI: TooltipPositionerContext is missing. TooltipPositioner parts must be placed within .', ); } return context; diff --git a/packages/mui-base/src/Tooltip/Root/TooltipRootContext.ts b/packages/mui-base/src/Tooltip/Root/TooltipRootContext.ts index 05e581963..8daa11124 100644 --- a/packages/mui-base/src/Tooltip/Root/TooltipRootContext.ts +++ b/packages/mui-base/src/Tooltip/Root/TooltipRootContext.ts @@ -24,12 +24,15 @@ export interface TooltipRootContext { transitionStatus: TransitionStatus; } -export const TooltipRootContext = React.createContext(null); +export const TooltipRootContext = React.createContext(undefined); export function useTooltipRootContext() { const context = React.useContext(TooltipRootContext); - if (context === null) { - throw new Error('Tooltip components must be used within the component'); + if (context === undefined) { + throw new Error( + 'Base UI: TooltipRootContext is missing. Tooltip parts must be placed within .', + ); } + return context; }