Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,25 @@
**React Datepicker components for [Fluent UI React](https://react.fluentui.dev/)**

These are not production-ready components and **should never be used in product**. This space is useful for testing new components whose APIs might change before final release.

DatePicker composes Input and Calendar Preview with controlled/uncontrolled date selection, optional
text editing, validation callbacks, popup positioning, and modal focus management. Use Field for labels
and validation presentation. See the [spec](./docs/Spec.md) for the API and parity requirements.

```tsx
<Field label="Start date">
<DatePicker placeholder="Select a date..." />
</Field>
```

`useDatePickerBase_unstable` shares date-input state, availability checks, and popup requests without
visual components, positioning, or Tabster. Custom integrations own their slots, focus, and dismissal
behavior. `useDatePicker_unstable` adds the standard Input/Calendar slots and popup integration.

For server rendering, wrap the application in Fluent UI's `SSRProvider`. An initially open portaled
popup mounts after hydration; an inline popup can be included in the server markup. Popup focus entry
and return use `preventScroll` so they do not trigger outside-scroll dismissal.

Automated interaction tests and example stories cover the supported API. Paired visual fixtures are
provided, but exact compat visual parity and manual screen-reader verification remain release gates;
this component is not yet certified as a production replacement for DatePicker Compat.
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
/** Jest test setup file. */

// Explicit IDs make the DatePicker snapshot stable across React versions.
process.env.RIT_SKIP_SNAPSHOTS = 'false';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { baseConfig } from '@fluentui/scripts-cypress';

export default baseConfig;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# @fluentui/react-datepicker-preview Spec

**Status:** Proposed. This document specifies the target component, not the current scaffold's implemented API.
**Status:** Implemented in preview. Exact compat visual parity and manual assistive-technology
verification remain release gates; see Acceptance Criteria and Verification.

## Background

Expand Down Expand Up @@ -38,7 +39,7 @@ compat prop comments alone.

## Sample Code

Examples use the proposed API; they are not examples of the current scaffold.
Examples use the preview API.

### Basic usage

Expand Down Expand Up @@ -119,7 +120,7 @@ There is no additional clear button, time picker, multiple-date selection, or st

## API

The implementation must replace the scaffold in
The public API is defined in
[DatePicker.types.ts](../src/components/DatePicker/DatePicker.types.ts) with this contract.

### Slots and ref
Expand Down Expand Up @@ -339,8 +340,8 @@ not an undocumented "v9 improvement".
### Compat-to-preview migration walkthrough

This walkthrough targets `@fluentui/react-datepicker-compat` consumers. The destination code uses
the **proposed** API in this spec and is not runnable against the current scaffold. Migrate only
after that API is implemented and parity is verified; keep production consumers on compat meanwhile.
the preview API in this spec. Migrate production consumers only after parity is verified;
keep production consumers on compat meanwhile.

#### 1. Replace imports and adapt controlled callbacks

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,99 @@

```ts

import type { Calendar } from '@fluentui/react-calendar-preview';
import type { CalendarProps } from '@fluentui/react-calendar-preview';
import type { ComponentProps } from '@fluentui/react-utilities';
import type { ComponentState } from '@fluentui/react-utilities';
import type { EventData } from '@fluentui/react-utilities';
import type { EventHandler } from '@fluentui/react-utilities';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import type { Input } from '@fluentui/react-input';
import type { JSXElement } from '@fluentui/react-utilities';
import type * as React_2 from 'react';
import type { PortalProps } from '@fluentui/react-portal';
import type { PositioningProps } from '@fluentui/react-positioning';
import * as React_2 from 'react';
import type { RefAttributes } from '@fluentui/react-utilities';
import type { Slot } from '@fluentui/react-utilities';
import type { SlotClassNames } from '@fluentui/react-utilities';

// @public
export const DatePicker: ForwardRefComponent<DatePickerProps>;

// @public
export type DatePickerBaseProps = Omit<DatePickerProps, 'appearance' | 'size'>;

// @public
export type DatePickerBaseState = DatePickerDateState & {
open: boolean;
today: Date;
required?: boolean;
requestOpen: (event: React_2.SyntheticEvent | Event, open: boolean, reason: DatePickerOpenChangeData['reason']) => void;
};

// @public (undocumented)
export const datePickerClassNames: SlotClassNames<DatePickerSlots>;

// @public (undocumented)
export type DatePickerDateChangeData = EventData<string, DatePickerEvent> & {
value: Date | null;
selectedDateRange: Date[];
reason: 'calendar' | 'input' | 'clear';
};

// @public (undocumented)
export type DatePickerErrorType = 'invalid-input' | 'out-of-bounds' | 'required-input';

// @public
export type DatePickerOpenChangeData = EventData<string, React_2.SyntheticEvent | Event> & {
open: boolean;
reason: 'input' | 'icon' | 'keyboard' | 'focus' | 'selection' | 'dismiss';
};

// @public
export type DatePickerProps = ComponentProps<DatePickerSlots> & {};
export type DatePickerProps = Omit<ComponentProps<Partial<DatePickerSlots>>, 'value' | 'defaultValue' | 'type' | 'readOnly' | 'calendar'> & Omit<DatePickerDateStateOptions, 'isDateUnavailable'> & {
calendar?: NonNullable<Slot<Omit<CalendarProps, 'value' | 'defaultValue' | 'today' | 'minDate' | 'maxDate'> & RefAttributes<HTMLDivElement>>>;
open?: boolean;
defaultOpen?: boolean;
onOpenChange?: EventHandler<DatePickerOpenChangeData>;
openOnClick?: boolean;
openOnFocus?: boolean;
today?: Date;
minDate?: Date;
maxDate?: Date;
inlinePopup?: boolean;
mountNode?: PortalProps['mountNode'];
positioning?: PositioningProps;
};

// @public (undocumented)
export type DatePickerSlots = {
root: NonNullable<Slot<typeof Input>>;
calendar: NonNullable<Slot<typeof Calendar>>;
popupSurface?: Slot<'div'>;
};

// @public
export type DatePickerState = ComponentState<DatePickerSlots>;
export type DatePickerState = ComponentState<DatePickerSlots> & Required<Pick<DatePickerProps, 'allowTextInput' | 'disabled' | 'inlinePopup'>> & Pick<DatePickerProps, 'mountNode'> & {
open: boolean;
};

// @public (undocumented)
export type DatePickerValidationResultData = EventData<string, DatePickerEvent> & {
error?: DatePickerErrorType;
};

// @public
export const defaultDatePickerErrorStrings: Record<DatePickerErrorType, string>;

// @public
export const renderDatePicker_unstable: (state: DatePickerState) => JSXElement;

// @public
export const useDatePicker_unstable: (props: DatePickerProps, ref: React_2.Ref<HTMLDivElement>) => DatePickerState;
export const useDatePicker_unstable: (props: DatePickerProps, ref: React_2.Ref<HTMLInputElement>) => DatePickerState;

// @public
export const useDatePickerBase_unstable: (props: DatePickerBaseProps) => DatePickerBaseState;

// @public
export const useDatePickerStyles_unstable: (state: DatePickerState) => DatePickerState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@fluentui/react-datepicker-preview",
"version": "0.0.0",
"private": true,
"description": "New fluentui react package",
"description": "DatePicker preview component for Fluent UI React",
"type": "module",
"main": "lib-commonjs/index.cjs",
"module": "lib/index.js",
Expand All @@ -21,8 +21,15 @@
},
"license": "MIT",
"dependencies": {
"@fluentui/react-calendar-preview": "workspace:^",
"@fluentui/react-field": "workspace:^",
"@fluentui/react-icons": "^2.0.339",
"@fluentui/react-input": "workspace:^",
"@fluentui/react-jsx-runtime": "^9.4.6",
"@fluentui/react-portal": "workspace:^",
"@fluentui/react-positioning": "workspace:^",
"@fluentui/react-shared-contexts": "^9.26.4",
"@fluentui/react-tabster": "workspace:^",
"@fluentui/react-theme": "^9.2.2",
"@fluentui/react-utilities": "^9.26.7",
"@griffel/react": "^1.5.32",
Expand Down Expand Up @@ -55,5 +62,9 @@
"major",
"prerelease"
]
},
"devDependencies": {
"@fluentui/react-provider": "*",
"@fluentui/scripts-cypress": "*"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,15 @@
"projectType": "library",
"sourceRoot": "packages/react-components/react-datepicker-preview/library/src",
"tags": ["platform:web", "vNext"],
"implicitDependencies": []
"implicitDependencies": [],
"targets": {
"e2e": {
"inputs": [
"default",
"{projectRoot}/cypress.config.ts",
"{projectRoot}/src/**/*.cy.tsx",
{ "externalDependencies": ["cypress", "@cypress/react"] }
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const runConfig = {
test: { configPath: 'jest.config.cjs', command: 'jest --runInBand' },
e2e: { configPath: 'cypress.config.ts', command: 'cypress run --component --browser chrome' },
};

export default {
react: {
17: { runConfig },
18: { runConfig },
},
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
export {
datePickerClassNames,
defaultDatePickerErrorStrings,
DatePicker,
renderDatePicker_unstable,
useDatePicker_unstable,
useDatePickerBase_unstable,
useDatePickerStyles_unstable,
} from './components/DatePicker/index';
export type { DatePickerProps, DatePickerState } from './components/DatePicker/index';
export type {
DatePickerBaseProps,
DatePickerBaseState,
DatePickerDateChangeData,
DatePickerErrorType,
DatePickerOpenChangeData,
DatePickerProps,
DatePickerSlots,
DatePickerState,
DatePickerValidationResultData,
} from './components/DatePicker/index';
Loading
Loading