diff --git a/package.json b/package.json index 7e4c459eb0d00..40db11eb88a59 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "@babel/plugin-transform-object-rest-spread": "7.29.7", "@babel/traverse": "catalog:", "@babel/types": "7.29.7", + "@base-ui/utils": "catalog:", "@emotion/cache": "catalog:", "@inquirer/prompts": "8.5.1", "@mui/internal-babel-plugin-display-name": "1.0.4-canary.20", diff --git a/packages/x-data-grid-premium/package.json b/packages/x-data-grid-premium/package.json index 19c73a18dba58..0a7e2b6423635 100644 --- a/packages/x-data-grid-premium/package.json +++ b/packages/x-data-grid-premium/package.json @@ -40,6 +40,7 @@ }, "dependencies": { "@babel/runtime": "catalog:", + "@base-ui/utils": "catalog:", "@mui/utils": "catalog:", "@mui/x-data-grid": "workspace:^", "@mui/x-data-grid-pro": "workspace:^", diff --git a/packages/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts b/packages/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts index 81719b7b71933..45566d7e36df8 100644 --- a/packages/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts +++ b/packages/x-data-grid-premium/src/hooks/features/cellSelection/useGridCellSelection.ts @@ -1,5 +1,6 @@ 'use client'; import * as React from 'react'; +import { platform } from '@base-ui/utils/platform'; import type { RefObject } from '@mui/x-internals/types'; import ownerDocument from '@mui/utils/ownerDocument'; import useEventCallback from '@mui/utils/useEventCallback'; @@ -302,8 +303,7 @@ export const useGridCellSelection = ( (params, event) => { // Skip if the click comes from the right-button or, only on macOS, Ctrl is pressed // Fix for https://github.com/mui/mui-x/pull/6567#issuecomment-1329155578 - const isMacOs = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0; - if (event.button !== 0 || (event.ctrlKey && isMacOs)) { + if (event.button !== 0 || (event.ctrlKey && platform.os.mac)) { return; } diff --git a/packages/x-data-grid-premium/src/tests/cellSelection.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/cellSelection.DataGridPremium.test.tsx index 566bb5127aef8..81560b6783dc4 100644 --- a/packages/x-data-grid-premium/src/tests/cellSelection.DataGridPremium.test.tsx +++ b/packages/x-data-grid-premium/src/tests/cellSelection.DataGridPremium.test.tsx @@ -13,7 +13,7 @@ import { gridClasses, } from '@mui/x-data-grid-premium'; import { getBasicGridData } from '@mui/x-data-grid-generator'; -import { isJSDOM } from 'test/utils/skipIf'; +import { isJSDOM, isOSX } from 'test/utils/skipIf'; describe(' - Cell selection', () => { const { render } = createRenderer(); @@ -416,9 +416,7 @@ describe(' - Cell selection', () => { ); // Add a new cell range to the selection - const isMac = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0; - - await user.keyboard(isMac ? '{Meta>}' : '{Control>}'); + await user.keyboard(isOSX ? '{Meta>}' : '{Control>}'); await user.pointer([ // touch the screen at element1 { keys: '[MouseLeft>]', target: getCell(2, 0) }, @@ -427,7 +425,7 @@ describe(' - Cell selection', () => { // release the touch pointer at the last position (element2) { keys: '[/MouseLeft]' }, ]); - await user.keyboard(isMac ? '{/Meta}' : '{/Control}'); + await user.keyboard(isOSX ? '{/Meta}' : '{/Control}'); expect(onCellSelectionModelChange.lastCall.args[0]).to.deep.equal({ '0': { id: true }, diff --git a/packages/x-data-grid/package.json b/packages/x-data-grid/package.json index ef683ee5d154c..8d95b83a5aff8 100644 --- a/packages/x-data-grid/package.json +++ b/packages/x-data-grid/package.json @@ -44,6 +44,7 @@ }, "dependencies": { "@babel/runtime": "catalog:", + "@base-ui/utils": "catalog:", "@mui/utils": "catalog:", "@mui/x-internals": "workspace:^", "@mui/x-virtualizer": "workspace:*", diff --git a/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts b/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts index 664cc191d8309..c34fc78147553 100644 --- a/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts +++ b/packages/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts @@ -1,5 +1,6 @@ 'use client'; import * as React from 'react'; +import { platform } from '@base-ui/utils/platform'; import type { RefObject } from '@mui/x-internals/types'; import { useStoreEffect } from '@mui/x-internals/store'; import type { GridEventListener } from '../../../models/events'; @@ -27,7 +28,6 @@ import { getTotalHeaderHeight } from '../columns/gridColumnsUtils'; import type { GridStateInitializer } from '../../utils/useGridInitializeState'; import { DATA_GRID_PROPS_DEFAULT_VALUES } from '../../../constants/dataGridPropsDefaultValues'; import { roundToDecimalPlaces } from '../../../utils/roundToDecimalPlaces'; -import { isJSDOM } from '../../../utils/isJSDOM'; type RootProps = Pick< DataGridProcessedProps, @@ -148,7 +148,7 @@ export function useGridDimensions(apiRef: RefObject, pr if (!getRootDimensions().isReady) { return; } - if (size.height === 0 && !errorShown.current && !props.autoHeight && !isJSDOM) { + if (size.height === 0 && !errorShown.current && !props.autoHeight && !platform.env.jsdom) { logger.error( [ 'The parent DOM element of the Data Grid has an empty height.', @@ -160,7 +160,7 @@ export function useGridDimensions(apiRef: RefObject, pr ); errorShown.current = true; } - if (size.width === 0 && !errorShown.current && !isJSDOM) { + if (size.width === 0 && !errorShown.current && !platform.env.jsdom) { logger.error( [ 'The parent DOM element of the Data Grid has an empty width.', diff --git a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualization.tsx b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualization.tsx index 3d6e695171ea5..c500f66860a1f 100644 --- a/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualization.tsx +++ b/packages/x-data-grid/src/hooks/features/virtualization/useGridVirtualization.tsx @@ -2,14 +2,14 @@ import * as React from 'react'; import type { RefObject } from '@mui/x-internals/types'; import { type Virtualization, type LayoutDataGrid, EMPTY_RENDER_CONTEXT } from '@mui/x-virtualizer'; -import { isJSDOM } from '../../../utils/isJSDOM'; +import { platform } from '@base-ui/utils/platform'; import type { GridPrivateApiCommunity } from '../../../models/api/gridApiCommunity'; import { useGridApiMethod } from '../../utils/useGridApiMethod'; import type { GridStateInitializer } from '../../utils/useGridInitializeState'; import { useGridEventPriority } from '../../utils'; import type { DataGridProcessedProps } from '../../../models/props/DataGridProps'; -const HAS_LAYOUT = !isJSDOM; +const HAS_LAYOUT = !platform.env.jsdom; type RootProps = DataGridProcessedProps; diff --git a/packages/x-data-grid/src/utils/formatNumber.test.ts b/packages/x-data-grid/src/utils/formatNumber.test.ts index 01c599a336abe..ef621cc00f111 100644 --- a/packages/x-data-grid/src/utils/formatNumber.test.ts +++ b/packages/x-data-grid/src/utils/formatNumber.test.ts @@ -1,5 +1,5 @@ +import { isJSDOM } from 'test/utils/skipIf'; import { formatNumber } from './getGridLocalization'; -import { isJSDOM } from './isJSDOM'; describe('formatNumber', () => { it('should format numbers with thousands separators', () => { diff --git a/packages/x-data-grid/src/utils/isJSDOM.ts b/packages/x-data-grid/src/utils/isJSDOM.ts deleted file mode 100644 index 635b110eb7758..0000000000000 --- a/packages/x-data-grid/src/utils/isJSDOM.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const isJSDOM = - typeof window !== 'undefined' && /jsdom|HappyDOM/.test(window.navigator.userAgent); diff --git a/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts b/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts index f22fb2b135852..55ba88be10337 100644 --- a/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts +++ b/packages/x-date-pickers/src/internals/hooks/useField/useField.utils.ts @@ -585,8 +585,6 @@ export const mergeDateIntoReferenceDate = ( return mergedDate; }, referenceDate); -export const isAndroid = () => navigator.userAgent.toLowerCase().includes('android'); - export const getSectionOrder = (sections: FieldSection[]): SectionOrdering => { const neighbors: SectionNeighbors = {}; sections.forEach((_, index) => { diff --git a/packages/x-date-pickers/src/internals/hooks/useReduceAnimations.ts b/packages/x-date-pickers/src/internals/hooks/useReduceAnimations.ts index 1c8a174c85908..bd7a4f008ab1b 100644 --- a/packages/x-date-pickers/src/internals/hooks/useReduceAnimations.ts +++ b/packages/x-date-pickers/src/internals/hooks/useReduceAnimations.ts @@ -2,13 +2,17 @@ import useMediaQuery from '@mui/material/useMediaQuery'; const PREFERS_REDUCED_MOTION = '@media (prefers-reduced-motion: reduce)'; -// detect if user agent has Android version < 10 or iOS version < 13 +// TODO(v10): Remove user-agent sniffing. The Android branch is dead and the iOS branch is becoming +// irrelevant. +// https://github.com/mui/mui-x/pull/22710#discussion_r3377072061 + const mobileVersionMatches = typeof navigator !== 'undefined' && navigator.userAgent.match(/android\s(\d+)|OS\s(\d+)/i); const androidVersion = mobileVersionMatches && mobileVersionMatches[1] ? parseInt(mobileVersionMatches[1], 10) : null; const iOSVersion = mobileVersionMatches && mobileVersionMatches[2] ? parseInt(mobileVersionMatches[2], 10) : null; + export const slowAnimationDevices = (androidVersion && androidVersion < 10) || (iOSVersion && iOSVersion < 13) || false; diff --git a/packages/x-internal-gestures/package.json b/packages/x-internal-gestures/package.json index a43f167956217..b27ed5fdb16e2 100644 --- a/packages/x-internal-gestures/package.json +++ b/packages/x-internal-gestures/package.json @@ -39,7 +39,8 @@ "prebuild": "rimraf build tsconfig.build.tsbuildinfo" }, "dependencies": { - "@babel/runtime": "catalog:" + "@babel/runtime": "catalog:", + "@base-ui/utils": "catalog:" }, "sideEffects": false, "exports": { diff --git a/packages/x-internal-gestures/src/core/KeyboardManager.ts b/packages/x-internal-gestures/src/core/KeyboardManager.ts index 90cc642e669b5..b02a28d8e024f 100644 --- a/packages/x-internal-gestures/src/core/KeyboardManager.ts +++ b/packages/x-internal-gestures/src/core/KeyboardManager.ts @@ -6,6 +6,8 @@ * 2. Providing methods to check if specific keys are pressed */ +import { platform } from '@base-ui/utils/platform'; + /** * Type definition for keyboard keys */ @@ -103,9 +105,8 @@ export class KeyboardManager { return keys.every((key) => { if (key === 'ControlOrMeta') { - // May be "deprecated" on types, but it is still the best option for cross-platform detection - // https://stackoverflow.com/a/71785253/24269134 - return navigator.platform.includes('Mac') + // Apple platforms (incl. iPadOS with a keyboard) use Cmd/Meta as the primary modifier. + return platform.os.apple ? this.pressedKeys.has('Meta') : this.pressedKeys.has('Control'); } diff --git a/packages/x-internals/src/platform/index.ts b/packages/x-internals/src/platform/index.ts deleted file mode 100644 index e2044e1d3a2e9..0000000000000 --- a/packages/x-internals/src/platform/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase() : 'empty'; - -export const isFirefox = userAgent.includes('firefox'); - -export const isJSDOM = - typeof window !== 'undefined' && /jsdom|HappyDOM/.test(window.navigator.userAgent); - -export default { - isFirefox, - isJSDOM, -}; diff --git a/packages/x-telemetry/src/runtime/config.test.ts b/packages/x-telemetry/src/runtime/config.test.ts index 6831cf435307c..10310868ada77 100644 --- a/packages/x-telemetry/src/runtime/config.test.ts +++ b/packages/x-telemetry/src/runtime/config.test.ts @@ -2,7 +2,7 @@ import { vi } from 'vitest'; import { muiXTelemetrySettings } from '@mui/x-telemetry'; -import { isJSDOM } from '@mui/x-internals/platform'; +import { isJSDOM } from 'test/utils/skipIf'; import { getTelemetryEnvConfig } from './config'; describe.runIf(isJSDOM)('Telemetry: getTelemetryConfig', () => { diff --git a/packages/x-telemetry/src/runtime/get-context.test.ts b/packages/x-telemetry/src/runtime/get-context.test.ts index d7719feafa329..bd576279a1e4a 100644 --- a/packages/x-telemetry/src/runtime/get-context.test.ts +++ b/packages/x-telemetry/src/runtime/get-context.test.ts @@ -1,6 +1,6 @@ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'; import { createHash } from 'crypto'; -import { isJSDOM } from '@mui/x-internals/platform'; +import { isJSDOM } from 'test/utils/skipIf'; import telemetryContext from '../context'; vi.mock('../context', () => ({ diff --git a/packages/x-telemetry/src/runtime/hash-string.test.ts b/packages/x-telemetry/src/runtime/hash-string.test.ts index fba7ba0e3126e..3c55d31b0ad69 100644 --- a/packages/x-telemetry/src/runtime/hash-string.test.ts +++ b/packages/x-telemetry/src/runtime/hash-string.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi } from 'vitest'; -import { isJSDOM } from '@mui/x-internals/platform'; +import { isJSDOM } from 'test/utils/skipIf'; async function nodeHash(input: string): Promise { const { createHash } = await import('crypto'); diff --git a/packages/x-telemetry/src/runtime/sender.test.ts b/packages/x-telemetry/src/runtime/sender.test.ts index 7f2ca905a3350..85343f0b5141d 100644 --- a/packages/x-telemetry/src/runtime/sender.test.ts +++ b/packages/x-telemetry/src/runtime/sender.test.ts @@ -1,6 +1,6 @@ import { vi } from 'vitest'; import { muiXTelemetrySettings } from '@mui/x-telemetry'; -import { isJSDOM } from '@mui/x-internals/platform'; +import { isJSDOM } from 'test/utils/skipIf'; import telemetryContext from '../context'; import { getTelemetryEnvConfig } from './config'; diff --git a/packages/x-tree-view-pro/src/internals/plugins/itemsReordering/itemPlugin.ts b/packages/x-tree-view-pro/src/internals/plugins/itemsReordering/itemPlugin.ts index b6a109a927e17..a461c00e58099 100644 --- a/packages/x-tree-view-pro/src/internals/plugins/itemsReordering/itemPlugin.ts +++ b/packages/x-tree-view-pro/src/internals/plugins/itemsReordering/itemPlugin.ts @@ -1,5 +1,6 @@ 'use client'; import * as React from 'react'; +import { platform } from '@base-ui/utils/platform'; import { useStore } from '@mui/x-internals/store'; import { TreeViewCancellableEvent, TreeViewCancellableEventHandler } from '@mui/x-tree-view/models'; import { @@ -12,8 +13,6 @@ import { TreeViewItemItemReorderingValidActions } from './types'; import { itemsReorderingSelectors } from './selectors'; import { RichTreeViewProStore } from '../../RichTreeViewProStore'; -export const isAndroid = () => navigator.userAgent.toLowerCase().includes('android'); - export const useTreeViewItemsReorderingItemPlugin: TreeViewItemPlugin = ({ props }) => { const { store } = useTreeViewContext>(); const { itemId } = props; @@ -53,7 +52,11 @@ export const useTreeViewItemsReorderingItemPlugin: TreeViewItemPlugin = ({ props event.dataTransfer.setDragImage(contentRefObject.current!, 0, 0); const { types } = event.dataTransfer; - if (isAndroid() && !types.includes('text/plain') && !types.includes('text/uri-list')) { + if ( + platform.os.android && + !types.includes('text/plain') && + !types.includes('text/uri-list') + ) { event.dataTransfer.setData('text/plain', 'android-fallback'); } diff --git a/packages/x-virtualizer/package.json b/packages/x-virtualizer/package.json index 8effb517e0544..f6c6b5667ca76 100644 --- a/packages/x-virtualizer/package.json +++ b/packages/x-virtualizer/package.json @@ -34,6 +34,7 @@ }, "dependencies": { "@babel/runtime": "catalog:", + "@base-ui/utils": "catalog:", "@mui/utils": "catalog:", "@mui/x-internals": "workspace:^" }, diff --git a/packages/x-virtualizer/src/features/virtualization/layout.ts b/packages/x-virtualizer/src/features/virtualization/layout.ts index 89d083e5ba0dc..028900bc3bd7d 100644 --- a/packages/x-virtualizer/src/features/virtualization/layout.ts +++ b/packages/x-virtualizer/src/features/virtualization/layout.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import useForkRef from '@mui/utils/useForkRef'; import useEventCallback from '@mui/utils/useEventCallback'; -import * as platform from '@mui/x-internals/platform'; +import { platform } from '@base-ui/utils/platform'; import { Store, createSelectorMemoized } from '@mui/x-internals/store'; import { Dimensions } from '../../features/dimensions'; import { Virtualization, type VirtualizationLayoutParams } from './virtualization'; @@ -106,7 +106,7 @@ export class LayoutDataGrid extends Layout { role: 'presentation', // `tabIndex` shouldn't be used along role=presentation, but it fixes a Firefox bug // https://github.com/mui/mui-x/pull/13891#discussion_r1683416024 - tabIndex: platform.isFirefox ? -1 : undefined, + tabIndex: platform.engine.gecko ? -1 : undefined, }), ), @@ -269,7 +269,7 @@ export class LayoutList extends Layout { role: 'presentation', // `tabIndex` shouldn't be used along role=presentation, but it fixes a Firefox bug // https://github.com/mui/mui-x/pull/13891#discussion_r1683416024 - tabIndex: platform.isFirefox ? -1 : undefined, + tabIndex: platform.engine.gecko ? -1 : undefined, }), ), diff --git a/packages/x-virtualizer/src/features/virtualization/virtualization.ts b/packages/x-virtualizer/src/features/virtualization/virtualization.ts index caf22288f88ea..61db9445231fd 100644 --- a/packages/x-virtualizer/src/features/virtualization/virtualization.ts +++ b/packages/x-virtualizer/src/features/virtualization/virtualization.ts @@ -6,7 +6,7 @@ import useTimeout from '@mui/utils/useTimeout'; import useEventCallback from '@mui/utils/useEventCallback'; import useEnhancedEffect from '@mui/utils/useEnhancedEffect'; import type { integer } from '@mui/x-internals/types'; -import * as platform from '@mui/x-internals/platform'; +import { platform } from '@base-ui/utils/platform'; import { useRunOnce } from '@mui/x-internals/useRunOnce'; import { createSelector, useStore, useStoreEffect, Store } from '@mui/x-internals/store'; import useRefCallback from '../../utils/useRefCallback'; @@ -155,9 +155,9 @@ function initializeState(params: ParamsWithDefaults) { const state: Virtualization.State = { virtualization: { - enabled: !platform.isJSDOM, - enabledForRows: !platform.isJSDOM, - enabledForColumns: !platform.isJSDOM, + enabled: !platform.env.jsdom, + enabledForRows: !platform.env.jsdom, + enabledForColumns: !platform.env.jsdom, renderContext, props: (params.layout.constructor as typeof Layout).elements.reduce( (acc, key) => (acc[key as string], acc), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf3732dbaf289..08ac6f92d5d95 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,8 +34,8 @@ catalogs: specifier: ^1.5.0 version: 1.5.0 '@base-ui/utils': - specifier: ^0.2.9 - version: 0.2.9 + specifier: ^0.3.0 + version: 0.3.0 '@date-fns/tz': specifier: ^1.5.0 version: 1.5.0 @@ -254,6 +254,9 @@ importers: '@babel/types': specifier: 7.29.7 version: 7.29.7 + '@base-ui/utils': + specifier: 'catalog:' + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/cache': specifier: 'catalog:' version: 11.14.0 @@ -1172,6 +1175,9 @@ importers: '@babel/runtime': specifier: 'catalog:' version: 7.29.7 + '@base-ui/utils': + specifier: 'catalog:' + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/react': specifier: ^11.9.0 version: 11.14.0(@types/react@19.2.15)(react@19.2.6) @@ -1287,6 +1293,9 @@ importers: '@babel/runtime': specifier: 'catalog:' version: 7.29.7 + '@base-ui/utils': + specifier: 'catalog:' + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/react': specifier: ^11.9.0 version: 11.14.0(@types/react@19.2.15)(react@19.2.6) @@ -1580,6 +1589,9 @@ importers: '@babel/runtime': specifier: 'catalog:' version: 7.29.7 + '@base-ui/utils': + specifier: 'catalog:' + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) publishDirectory: build packages/x-internals: @@ -1653,7 +1665,7 @@ importers: version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.15)(date-fns@4.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@base-ui/utils': specifier: 'catalog:' - version: 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/react': specifier: ^11.9.0 version: 11.14.0(@types/react@19.2.15)(react@19.2.6) @@ -1724,7 +1736,7 @@ importers: version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.15)(date-fns@4.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@base-ui/utils': specifier: 'catalog:' - version: 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@date-fns/tz': specifier: 'catalog:' version: 1.5.0 @@ -1780,7 +1792,7 @@ importers: version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.15)(date-fns@4.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@base-ui/utils': specifier: 'catalog:' - version: 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@mui/x-internals': specifier: workspace:^ version: link:../x-internals/build @@ -1827,7 +1839,7 @@ importers: version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.15)(date-fns@4.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@base-ui/utils': specifier: 'catalog:' - version: 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/react': specifier: ^11.9.0 version: 11.14.0(@types/react@19.2.15)(react@19.2.6) @@ -1927,7 +1939,7 @@ importers: version: 7.29.7 '@base-ui/utils': specifier: 'catalog:' - version: 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/react': specifier: ^11.9.0 version: 11.14.0(@types/react@19.2.15)(react@19.2.6) @@ -1983,7 +1995,7 @@ importers: version: 7.29.7 '@base-ui/utils': specifier: 'catalog:' - version: 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/react': specifier: ^11.9.0 version: 11.14.0(@types/react@19.2.15)(react@19.2.6) @@ -2055,6 +2067,9 @@ importers: '@babel/runtime': specifier: 'catalog:' version: 7.29.7 + '@base-ui/utils': + specifier: 'catalog:' + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@mui/utils': specifier: 'catalog:' version: 9.0.1(@types/react@19.2.15)(react@19.2.6) @@ -2086,7 +2101,7 @@ importers: version: 7.29.7 '@base-ui/utils': specifier: 'catalog:' - version: 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/cache': specifier: 'catalog:' version: 11.14.0 @@ -3220,6 +3235,16 @@ packages: '@types/react': optional: true + '@base-ui/utils@0.3.0': + resolution: {integrity: sha512-IbZYmvB99kna6u75q8SPCV5LU+bxRzuBHIsimMf1S2Iy10K7qUuZrS2FP3RFZ17ROzt0YXxxJd70QRcnAKWpcw==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} @@ -12407,6 +12432,17 @@ snapshots: optionalDependencies: '@types/react': 19.2.15 + '@base-ui/utils@0.3.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.11 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.15 + '@bcoe/v8-coverage@1.0.2': {} '@blazediff/core@1.9.1': {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b68bd57136fac..48b80078747d2 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -15,7 +15,7 @@ catalog: '@babel/runtime': ^7.29.7 '@babel/traverse': ^7.29.7 '@base-ui/react': ^1.5.0 - '@base-ui/utils': ^0.2.9 + '@base-ui/utils': ^0.3.0 '@date-fns/tz': ^1.5.0 '@emotion/cache': ^11.14.0 '@emotion/react': ^11.14.0 diff --git a/test/utils/skipIf.ts b/test/utils/skipIf.ts index dea5c0218ca30..94c2a8687b7f8 100644 --- a/test/utils/skipIf.ts +++ b/test/utils/skipIf.ts @@ -1,4 +1,6 @@ -export const isJSDOM = /jsdom/.test(window.navigator.userAgent); -export const isOSX = /macintosh/i.test(window.navigator.userAgent); +import { platform } from '@base-ui/utils/platform'; + +export const isJSDOM = platform.env.jsdom; +export const isOSX = platform.os.mac; export const hasTouchSupport = typeof window.Touch !== 'undefined' && typeof window.TouchEvent !== 'undefined';