import { type Accessor, createContext, useContext } from "solid-js"; import type { BaseUIChangeEventDetails, BaseUIGenericEventDetails, REASONS, } from "../../internals/change-event-details"; import type { ChangeEventCustomProperties, EventWithOptionalKeyState, IncrementValueParameters, } from "../utils/types.ts"; import type { NumberFieldRootState } from "./number-field-root.tsx"; export type InputMode = "numeric" | "decimal" | "text"; export type NumberFieldRootChangeEventReason = | typeof REASONS.inputChange | typeof REASONS.inputClear | typeof REASONS.inputBlur | typeof REASONS.inputPaste | typeof REASONS.keyboard | typeof REASONS.incrementPress | typeof REASONS.decrementPress | typeof REASONS.wheel | typeof REASONS.scrub | typeof REASONS.none; export type NumberFieldRootChangeEventDetails = BaseUIChangeEventDetails< NumberFieldRootChangeEventReason, ChangeEventCustomProperties >; export type NumberFieldRootCommitEventReason = | typeof REASONS.inputBlur | typeof REASONS.inputClear | typeof REASONS.keyboard | typeof REASONS.incrementPress | typeof REASONS.decrementPress | typeof REASONS.wheel | typeof REASONS.scrub | typeof REASONS.none; export type NumberFieldRootCommitEventDetails = BaseUIGenericEventDetails; /** * Root context shared across every `` part. Every reactive * entry is exposed as an `Accessor` so descendants can subscribe to the * pieces they care about without rereading the entire bag. * * Non-reactive slots (`inputRef`, `valueRef`, `hasPendingCommitRef`) are * plain mutable records — shared between root / input / buttons so each * part can read the latest committed state synchronously from event * handlers. */ export interface NumberFieldRootContextValue { inputRef: { current: HTMLInputElement | null }; inputValue: Accessor; value: Accessor; minWithDefault: Accessor; maxWithDefault: Accessor; disabled: Accessor; readOnly: Accessor; id: string; setValue: ( value: number | null, details: NumberFieldRootChangeEventDetails, ) => boolean; getStepAmount: (event?: EventWithOptionalKeyState) => number | undefined; incrementValue: (amount: number, params: IncrementValueParameters) => boolean; allowInputSyncRef: { current: boolean }; formatOptionsRef: { current: Intl.NumberFormatOptions | undefined }; valueRef: { current: number | null }; lastChangedValueRef: { current: number | null }; hasPendingCommitRef: { current: boolean }; name: Accessor; required: Accessor; invalid: Accessor; inputMode: Accessor; getAllowedNonNumericKeys: () => Set; min: Accessor; max: Accessor; setInputValue: (next: string) => void; locale: Accessor; isScrubbing: Accessor; setIsScrubbing: (next: boolean) => void; state: Accessor; onValueCommitted: ( value: number | null, eventDetails: NumberFieldRootCommitEventDetails, ) => void; } /** * `createContext(null)` + `== null` sentinel — * Solid 2's `useContext` throws `ContextNotFoundError` when the default is * `undefined`, which would shadow the intended Base UI error message below. */ export const NumberFieldRootContext = createContext(null); export function useNumberFieldRootContext(): NumberFieldRootContextValue { const context = useContext(NumberFieldRootContext); if (context == null) { throw new Error( "Base UI: NumberFieldRootContext is missing. NumberField parts must be placed within .", ); } return context; }